diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/input-multiple-text-string/input-multiple-text-string.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/input-multiple-text-string/input-multiple-text-string.element.ts new file mode 100644 index 0000000000..8c076836c0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/input-multiple-text-string/input-multiple-text-string.element.ts @@ -0,0 +1,143 @@ +import { css, html } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; +import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui-input'; +import { UmbLitElement } from '@umbraco-cms/element'; +import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from 'src/core/modal'; + +export type MultipleTextStringValue = Array; + +export interface MultipleTextStringValueItem { + value: string; +} + +/** + * @element umb-input-multiple-text-string + */ +@customElement('umb-input-multiple-text-string') +export class UmbInputMultipleTextStringElement extends UmbLitElement { + static styles = [ + UUITextStyles, + css` + .item { + display: flex; + align-items: center; + margin-bottom: var(--uui-size-space-3); + gap: var(--uui-size-space-3); + } + + .item #text-field { + flex: 1; + } + + #action { + display: block; + } + `, + ]; + + @state() + private _value: MultipleTextStringValue = []; + + @property({ type: Array }) + public get value(): MultipleTextStringValue { + return this._value; + } + public set value(value: MultipleTextStringValue) { + this._value = value || []; + } + + private _modalService?: UmbModalService; + + constructor() { + super(); + + this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => { + this._modalService = modalService; + }); + } + + #onAdd() { + this._value = [...this._value, { value: '' }]; + this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: false, cancelable: false })); + this.#focusNewItem(); + } + + #onDelete(index: number) { + const item = this._value[index]; + + const modalHandler = this._modalService?.confirm({ + headline: `Delete ${item.value || 'item'}`, + content: 'Are you sure you want to delete this item?', + color: 'danger', + confirmLabel: 'Delete', + }); + + modalHandler?.onClose().then(({ confirmed }: any) => { + if (confirmed) this.#deleteItem(index); + }); + } + + #onInput(event: UUIInputEvent, currentIndex: number) { + const target = event.currentTarget as UUIInputElement; + const value = target.value as string; + this._value = this._value.map((item, index) => (index === currentIndex ? { value } : item)); + this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: false, cancelable: false })); + } + + async #focusNewItem() { + await this.updateComplete; + const inputs = this.shadowRoot?.querySelectorAll('uui-input') as NodeListOf; + const lastInput = inputs[inputs.length - 1]; + lastInput.focus(); + } + + #deleteItem(itemIndex: number) { + this._value = this._value.filter((item, index) => index !== itemIndex); + this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: false, cancelable: false })); + } + + render() { + return html` + ${this._renderItems()} + + `; + } + + private _renderItems() { + return html` + ${repeat( + this._value, + (item, index) => index, + (item, index) => html`${this._renderItem(item, index)}` + )} + `; + } + + private _renderItem(item: MultipleTextStringValueItem, index: number) { + return html`
+ + + + + +
`; + } +} + +export default UmbInputMultipleTextStringElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-input-multiple-text-string': UmbInputMultipleTextStringElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/property-editor-ui-multiple-text-string.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/property-editor-ui-multiple-text-string.element.ts index 45f5142048..5d203c28f3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/property-editor-ui-multiple-text-string.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/multiple-text-string/property-editor-ui-multiple-text-string.element.ts @@ -1,58 +1,29 @@ -import { css, html } from 'lit'; -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { repeat } from 'lit/directives/repeat.js'; -import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui-input'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; +import { UmbChangeEvent } from 'src/core/events/change.event'; import { UmbPropertyValueChangeEvent } from '../..'; +import UmbInputMultipleTextStringElement, { + MultipleTextStringValue, +} from './input-multiple-text-string/input-multiple-text-string.element'; import { UmbLitElement } from '@umbraco-cms/element'; -import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from 'src/core/modal'; + +import './input-multiple-text-string/input-multiple-text-string.element'; export type MultipleTextStringConfigData = Array<{ alias: 'minNumber' | 'maxNumber'; value: number; }>; -export type MultipleTextStringValue = Array; - -export interface MultipleTextStringValueItem { - value: string; -} - /** * @element umb-property-editor-ui-multiple-text-string */ @customElement('umb-property-editor-ui-multiple-text-string') export class UmbPropertyEditorUIMultipleTextStringElement extends UmbLitElement { - static styles = [ - UUITextStyles, - css` - .item { - display: flex; - align-items: center; - margin-bottom: var(--uui-size-space-3); - gap: var(--uui-size-space-3); - } - - .item #text-field { - flex: 1; - } - - #action { - display: block; - } - `, - ]; - - @state() - private _value: MultipleTextStringValue = []; + static styles = []; @property({ type: Array }) - public get value(): MultipleTextStringValue { - return this._value; - } - public set value(value: MultipleTextStringValue) { - this._value = value || []; - } + public value: MultipleTextStringValue = []; @property({ type: Array, attribute: false }) public set config(config: MultipleTextStringConfigData) { @@ -66,87 +37,19 @@ export class UmbPropertyEditorUIMultipleTextStringElement extends UmbLitElement @state() private _limitMax?: number; - private _modalService?: UmbModalService; - - constructor() { - super(); - - this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => { - this._modalService = modalService; - }); - } - - private _onAdd() { - this._value = [...this._value, { value: '' }]; - this.dispatchEvent(new UmbPropertyValueChangeEvent()); - this.#focusNewItem(); - } - - #onDelete(index: number) { - const item = this._value[index]; - - const modalHandler = this._modalService?.confirm({ - headline: `Delete ${item.value || 'item'}`, - content: 'Are you sure you want to delete this item?', - color: 'danger', - confirmLabel: 'Delete', - }); - - modalHandler?.onClose().then(({ confirmed }: any) => { - if (confirmed) this.#deleteItem(index); - }); - } - - #onInput(event: UUIInputEvent, currentIndex: number) { - const target = event.currentTarget as UUIInputElement; - const value = target.value as string; - this._value = this._value.map((item, index) => (index === currentIndex ? { value } : item)); - this.dispatchEvent(new UmbPropertyValueChangeEvent()); - } - - async #focusNewItem() { - await this.updateComplete; - const inputs = this.shadowRoot?.querySelectorAll('uui-input') as NodeListOf; - const lastInput = inputs[inputs.length - 1]; - lastInput.focus(); - } - - #deleteItem(itemIndex: number) { - this._value = this._value.filter((item, index) => index !== itemIndex); + #onChange(event: UmbChangeEvent) { + event.stopPropagation(); + const target = event.currentTarget as UmbInputMultipleTextStringElement; + this.value = target.value; this.dispatchEvent(new UmbPropertyValueChangeEvent()); } render() { - return html` - ${this._renderItems()} - - `; - } - - private _renderItems() { - return html` ${repeat( - this._value, - (item, index) => index, - (item, index) => html`${this._renderItem(item, index)}` - )}`; - } - - private _renderItem(item: MultipleTextStringValueItem, index: number) { - return html`
- - - - - -
`; + return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/core/events/change.event.ts b/src/Umbraco.Web.UI.Client/src/core/events/change.event.ts new file mode 100644 index 0000000000..61ccc0f296 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/events/change.event.ts @@ -0,0 +1,6 @@ +export class UmbChangeEvent extends Event { + public constructor() { + // mimics the native change event + super('change', { bubbles: true, composed: false, cancelable: false }); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts index 051036493d..47da89b6a0 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts @@ -155,7 +155,16 @@ export const data: Array = [ isFolder: false, propertyEditorModelAlias: 'Umbraco.MultipleTextString', propertyEditorUIAlias: 'Umb.PropertyEditorUI.MultipleTextString', - data: [], + data: [ + { + alias: 'minNumber', + value: 2, + }, + { + alias: 'maxNumber', + value: 4, + }, + ], }, { name: 'Dropdown',