diff --git a/src/Umbraco.Web.UI.Client/src/packages/elements/item/index.ts b/src/Umbraco.Web.UI.Client/src/packages/elements/item/index.ts index fd536b101113..ee85c07b7286 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/elements/item/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/elements/item/index.ts @@ -1 +1,2 @@ export { UmbElementItemRepository } from './repository/index.js'; +export * from './data-resolver/element-item-data-resolver.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.component.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.component.ts new file mode 100644 index 000000000000..4fa51bf7c612 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.component.ts @@ -0,0 +1,14 @@ +import type { UfmToken } from '../../plugins/types.js'; +import { UmbUfmComponentBase } from '../ufm-component-base.js'; + +import './element-name.element.js'; + +export class UmbUfmElementNameComponent extends UmbUfmComponentBase { + render(token: UfmToken) { + if (!token.text) return; + const attributes = super.getAttributes(token.text); + return ``; + } +} + +export { UmbUfmElementNameComponent as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.element.ts new file mode 100644 index 000000000000..23f253c70942 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.element.ts @@ -0,0 +1,73 @@ +import { UmbUfmElementBase } from '../ufm-element-base.js'; +import { UMB_UFM_RENDER_CONTEXT } from '../ufm-render/ufm-render.context.js'; +import { customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementItemDataResolver, UmbElementItemRepository } from '@umbraco-cms/backoffice/element'; +import { UmbId } from '@umbraco-cms/backoffice/id'; + +@customElement('ufm-element-name') +export class UmbUfmElementNameElement extends UmbUfmElementBase { + #repository?: UmbElementItemRepository; + + @property() + alias?: string; + + constructor() { + super(); + + this.consumeContext(UMB_UFM_RENDER_CONTEXT, (context) => { + this.observe( + context?.value, + async (value) => { + const temp = + this.alias && typeof value === 'object' + ? (value as Record)[this.alias] + : (value as unknown); + + if (!temp) { + this.value = ''; + return; + } + + const uniques = this.#getUniques(temp); + this.value = await this.#getNames(uniques); + }, + 'observeValue', + ); + }); + } + + #getUniques(value: unknown) { + if (Array.isArray(value)) { + return value.map((x) => x.unique ?? x).filter((x) => UmbId.validate(x)); + } + return typeof value === 'string' && UmbId.validate(value) ? [value] : []; + } + + async #getNames(uniques?: Array) { + if (uniques?.length) { + if (!this.#repository) this.#repository = new UmbElementItemRepository(this); + const { data } = await this.#repository.requestItems(uniques); + + if (Array.isArray(data) && data.length > 0) { + const namePromises = data.map(async (item) => { + const resolver = new UmbElementItemDataResolver(this); + resolver.setData(item); + const name = await resolver.getName(); + resolver.destroy(); + return name; + }); + const names = await Promise.all(namePromises); + return names.filter(Boolean).join(', '); + } + } + return ''; + } +} + +export { UmbUfmElementNameElement as element }; + +declare global { + interface HTMLElementTagNameMap { + 'ufm-element-name': UmbUfmElementNameElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/manifests.ts new file mode 100644 index 000000000000..77f1c9b3effe --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/manifests.ts @@ -0,0 +1,11 @@ +import type { ManifestUfmComponent } from '../../extensions/ufm-component.extension.js'; + +export const manifests: Array = [ + { + type: 'ufmComponent', + alias: 'Umb.Markdown.ElementName', + name: 'Element Name UFM Component', + api: () => import('./element-name.component.js'), + meta: { alias: 'umbElementName' }, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/manifests.ts index fc4dae305161..54c53d22791b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/manifests.ts @@ -1,4 +1,5 @@ import type { ManifestUfmComponent } from '../extensions/ufm-component.extension.js'; +import { manifests as elementNameManifests } from './element-name/manifests.js'; export const manifests: Array = [ { @@ -22,6 +23,7 @@ export const manifests: Array = [ api: () => import('./content-name/content-name.component.js'), meta: { alias: 'umbContentName' }, }, + ...elementNameManifests, { type: 'ufmComponent', alias: 'Umb.Markdown.Link', diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts index ae9be9452b2e..7239496f0c58 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts @@ -2,6 +2,7 @@ import { expect } from '@open-wc/testing'; import { ufm } from './marked-ufm.plugin.js'; import { UmbMarked } from '../contexts/ufm.context.js'; import { UmbUfmContentNameComponent } from '../components/content-name/content-name.component.js'; +import { UmbUfmElementNameComponent } from '../components/element-name/element-name.component.js'; import { UmbUfmLabelValueComponent } from '../components/label-value/label-value.component.js'; import { UmbUfmLocalizeComponent } from '../components/localize/localize.component.js'; import { UmbUfmMemberNameComponent } from '../components/member-name/member-name.component.js'; @@ -27,7 +28,7 @@ describe('UmbMarkedUfm', () => { ufm: '{umbContentName: contentPicker}', expected: '', }, - { ufm: '{umbMemberName:memberPicker}', expected: '' }, + { ufm: '{umbElementName:elementPicker}', expected: '' }, { ufm: '{umbMemberName: memberPicker}', expected: '', @@ -38,6 +39,7 @@ describe('UmbMarkedUfm', () => { UmbMarked.use( ufm([ { alias: 'umbContentName', marker: '~', render: new UmbUfmContentNameComponent().render }, + { alias: 'umbElementName', render: new UmbUfmElementNameComponent().render }, { alias: 'umbValue', marker: '=', render: new UmbUfmLabelValueComponent().render }, { alias: 'umbLocalize', marker: '#', render: new UmbUfmLocalizeComponent().render }, { alias: 'umbMemberName', render: new UmbUfmMemberNameComponent().render },