diff --git a/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property-data-type.element.ts b/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property-data-type.element.ts deleted file mode 100644 index 3007a3c4b3..0000000000 --- a/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property-data-type.element.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { css, html, LitElement, PropertyValueMap } from 'lit'; -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../core/context'; -import { UmbDataTypeStore } from '../../core/stores/data-type.store'; -import { Subscription, map, switchMap } from 'rxjs'; -import { DataTypeEntity } from '../../mocks/data/content.data'; -import { UmbExtensionManifest, UmbExtensionRegistry } from '../../core/extension'; -import { createExtensionElement } from '../../core/extension/create-extension-element.function'; - -@customElement('umb-node-property-data-type') -class UmbNodePropertyDataType extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - height: 100%; - } - `, - ]; - - @property() - private _dataTypeKey?: string | undefined; - public get dataTypeKey(): string | undefined { - return this._dataTypeKey; - } - public set dataTypeKey(key: string | undefined) { - //const oldValue = this._dataTypeKey; - this._dataTypeKey = key; - this._useDataType(); - } - - // TODO: make interface for UMBPropertyEditorElement - @state() - private _element?: { value?: string } & HTMLElement; // TODO: invent interface for propertyEditorUI. - - @property() - value?: string; - - @state() - _dataType?: DataTypeEntity; - - @state() - _propertyEditorUI?: UmbExtensionManifest; - - private _extensionRegistry?: UmbExtensionRegistry; - private _dataTypeStore?: UmbDataTypeStore; - private _dataTypeSubscription?: Subscription; - - constructor() { - super(); - this.consumeContext('umbDataTypeStore', (_instance: UmbDataTypeStore) => { - this._dataTypeStore = _instance; - this._useDataType(); - }); - this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { - this._extensionRegistry = _instance; - this._useDataType(); - }); - - // TODO: solution to know when both contexts are available - } - - // TODO: use subscribtion, rename to _useDataType: - private _useDataType() { - this._dataTypeSubscription?.unsubscribe(); - if (this._dataTypeKey && this._extensionRegistry && this._dataTypeStore) { - //this._dataTypeSubscription = this._dataTypeStore.getByKey(this._dataTypeKey).subscribe(this._gotDataType); - - this._dataTypeSubscription = this._dataTypeStore - .getByKey(this._dataTypeKey) - .pipe( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - map((dataTypeEntity: DataTypeEntity) => { - this._dataType = dataTypeEntity; - return dataTypeEntity.propertyEditorUIAlias; - }), - switchMap((alias: string) => this._extensionRegistry?.getByAlias(alias) as any) - ) - .subscribe((propertyEditorUI: any) => { - this._propertyEditorUI = propertyEditorUI; - this._gotData(this._dataType, this._propertyEditorUI); - }); - } - } - - private _gotData(_data?: DataTypeEntity, _propertyEditorUI?: UmbExtensionManifest) { - if (!_data || !_propertyEditorUI) { - // TODO: if dataTypeKey didn't exist in store, we should do some nice UI. - return; - } - - createExtensionElement(_propertyEditorUI) - .then((el) => { - const oldValue = this._element; - this._element = el; - - // TODO: Set/Parse Data-Type-UI-configuration - - if (oldValue) { - oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener); - } - - if (this._element) { - this._element.addEventListener( - 'property-editor-change', - this._onPropertyEditorChange as any as EventListener - ); - this._element.value = this.value; // Be aware its duplicated code - } - this.requestUpdate('element', oldValue); - }) - .catch(() => { - // TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.) - }); - } - - private _onPropertyEditorChange = (e: CustomEvent) => { - if (e.currentTarget === this._element) { - this.value = this._element.value; - // - this.dispatchEvent(new CustomEvent('property-data-type-value-change', { bubbles: true, composed: true })); - } - // make sure no event leave this scope. - e.stopPropagation(); - }; - - /** Lit does not currently handle dynamic tag names, therefor we are doing some manual rendering */ - // TODO: Refactor into a base class for dynamic-tag element? we will be using this a lot for extensions. - // This could potentially hook into Lit and parse all properties defined in the specific class on to the dynamic-element. (see static elementProperties: PropertyDeclarationMap;) - willUpdate(changedProperties: PropertyValueMap | Map) { - super.willUpdate(changedProperties); - - const hasChangedProps = changedProperties.has('value'); - if (hasChangedProps && this._element) { - this._element.value = this.value; // Be aware its duplicated code - } - } - - disconnectedCallback(): void { - super.disconnectedCallback(); - this._dataTypeSubscription?.unsubscribe(); - } - - render() { - return html`${this._element}`; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'umb-node-property-control': UmbNodePropertyDataType; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property.element.ts b/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property.element.ts index 14759737c9..42d6e21f44 100644 --- a/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/editors/node-editor/node-property.element.ts @@ -1,36 +1,143 @@ -import { css, html, LitElement } from 'lit'; +import { css, html, LitElement, PropertyValueMap } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; +import { createExtensionElement, UmbExtensionManifest, UmbExtensionRegistry } from '../../core/extension'; +import { Subscription, map, switchMap } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../core/context'; +import { DataTypeEntity } from '../../mocks/data/content.data'; +import { UmbDataTypeStore } from '../../core/stores/data-type.store'; @customElement('umb-node-property') -class UmbNodeProperty extends LitElement { +class UmbNodeProperty extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` :host { display: block; } - p { color: var(--uui-color-text-alt); } `, ]; + private _property: any; // TODO: property data model interface.. @property() - property: any; // TODO: property data model interface.. + public get property(): any { + return this._property; + } + public set property(value: any) { + this._property = value; + this._useDataType(); + } @property() value?: string; - // TODO: maybe a bit messy with all the event listeners on the different levels: - private _onPropertyDataTypeChange = (e: CustomEvent) => { + // TODO: make interface for UMBPropertyEditorElement + @state() + private _element?: { value?: string } & HTMLElement; // TODO: invent interface for propertyEditorUI. + + private _dataType?: DataTypeEntity; + private _extensionRegistry?: UmbExtensionRegistry; + private _dataTypeStore?: UmbDataTypeStore; + private _dataTypeSubscription?: Subscription; + + constructor() { + super(); + + /** TODO: Use DI for these types of services. */ + this.consumeContext('umbDataTypeStore', (_instance: UmbDataTypeStore) => { + this._dataTypeStore = _instance; + this._useDataType(); + }); + this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { + this._extensionRegistry = _instance; + this._useDataType(); + }); + + // TODO: solution to know when both contexts are available + } + + // TODO: use subscribtion, rename to _useDataType: + private _useDataType() { + this._dataTypeSubscription?.unsubscribe(); + if (this._property.dataTypeKey && this._extensionRegistry && this._dataTypeStore) { + + this._dataTypeSubscription = this._dataTypeStore + .getByKey(this._property.dataTypeKey) + .pipe( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + map((dataTypeEntity: DataTypeEntity) => { + this._dataType = dataTypeEntity; + return dataTypeEntity.propertyEditorUIAlias; + }), + switchMap((alias: string) => this._extensionRegistry?.getByAlias(alias) as any) + ) + .subscribe((propertyEditorUI: any) => { + this._gotData(propertyEditorUI); + }); + } + } + + private _gotData(_propertyEditorUI?: UmbExtensionManifest) { + + if (!this._dataType || !_propertyEditorUI) { + // TODO: if dataTypeKey didn't exist in store, we should do some nice UI. + return; + } + + createExtensionElement(_propertyEditorUI) + .then((el) => { + const oldValue = this._element; + this._element = el; + + // TODO: Set/Parse Data-Type-UI-configuration + + if (oldValue) { + oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener); + } + + /* NYT lav callback: */ + if (this._element) { + this._element.addEventListener( + 'property-editor-change', + this._onPropertyEditorChange as any as EventListener + ); + this._element.value = this.value; // Be aware its duplicated code + } + this.requestUpdate('element', oldValue); + }) + .catch(() => { + // TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.) + }); + } + + private _onPropertyEditorChange = (e: CustomEvent) => { this.value = (e.target as any).value; this.dispatchEvent(new CustomEvent('property-value-change', { bubbles: true, composed: true })); // No need for this event to leave scope. e.stopPropagation(); }; + /** Lit does not currently handle dynamic tag names, therefor we are doing some manual rendering */ + // TODO: Refactor into a base class for dynamic-tag element? we will be using this a lot for extensions. + // This could potentially hook into Lit and parse all properties defined in the specific class on to the dynamic-element. (see static elementProperties: PropertyDeclarationMap;) + willUpdate(changedProperties: PropertyValueMap | Map) { + super.willUpdate(changedProperties); + + const hasChangedProps = changedProperties.has('value'); + if (hasChangedProps && this._element) { + this._element.value = this.value; // Be aware its duplicated code + } + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + this._dataTypeSubscription?.unsubscribe(); + } + render() { return html` @@ -39,10 +146,7 @@ class UmbNodeProperty extends LitElement {

${this.property.description}

- + ${this._element}
`;