concat node-property-data-type.element.ts to node-property

This commit is contained in:
Niels Lyngsø
2022-06-02 15:17:42 +02:00
parent 18faafb57b
commit ec2314d855
2 changed files with 115 additions and 168 deletions

View File

@@ -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<any> | Map<PropertyKey, unknown>) {
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;
}
}

View File

@@ -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<any> | Map<PropertyKey, unknown>) {
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`
<umb-editor-property-layout>
@@ -39,10 +146,7 @@ class UmbNodeProperty extends LitElement {
<p>${this.property.description}</p>
</div>
<div slot="editor">
<umb-node-property-data-type
.dataTypeKey=${this.property.dataTypeKey}
.value=${this.value}
@property-data-type-value-change=${this._onPropertyDataTypeChange}></umb-node-property-data-type>
${this._element}
</div>
</umb-editor-property-layout>
`;