diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-checkbox-list/input-checkbox-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-checkbox-list/input-checkbox-list.element.ts index 98d3dbdc59..9555158e76 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-checkbox-list/input-checkbox-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-checkbox-list/input-checkbox-list.element.ts @@ -1,6 +1,6 @@ import { css, html, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; +import { customElement, property } from 'lit/decorators.js'; import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; import { repeat } from 'lit/directives/repeat.js'; import { UUIBooleanInputEvent } from '@umbraco-ui/uui'; @@ -21,21 +21,21 @@ export class UmbInputCheckboxListElement extends FormControlMixin(UmbLitElement) * List of items. */ @property() - list?: []; + public list: Array<{ key: string; checked: boolean; value: string }> = []; - private _selectedKeys: Array = []; - public get selectedKeys(): Array { - return this._selectedKeys; + #selected: Array = []; + public get selected(): Array { + return this.#selected; } - public set selectedKeys(keys: Array) { - this._selectedKeys = keys; + public set selected(keys: Array) { + this.#selected = keys; super.value = keys.join(','); } @property() public set value(keysString: string) { if (keysString !== this._value) { - this.selectedKeys = keysString.split(/[ ,]+/); + this.selected = keysString.split(/[ ,]+/); } } @@ -43,32 +43,32 @@ export class UmbInputCheckboxListElement extends FormControlMixin(UmbLitElement) return undefined; } - private _setSelection(e: UUIBooleanInputEvent) { + #setSelection(e: UUIBooleanInputEvent) { e.stopPropagation(); - if (e.target.checked) this.selectedKeys = [...this.selectedKeys, e.target.value]; - else this._removeFromSelection(this.selectedKeys.findIndex((key) => e.target.value === key)); + if (e.target.checked) this.selected = [...this.selected, e.target.value]; + else this.#removeFromSelection(this.selected.findIndex((key) => e.target.value === key)); this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true })); } - private _removeFromSelection(index: number) { + #removeFromSelection(index: number) { if (index == -1) return; - const keys = [...this.selectedKeys]; + const keys = [...this.selected]; keys.splice(index, 1); - this.selectedKeys = keys; + this.selected = keys; } render() { if (!this.list) return nothing; return html`
- + ${repeat(this.list, (item) => item.key, this.renderCheckbox)} `; } - renderCheckbox(item: any) { - return html``; + renderCheckbox(item: { key: string; checked: boolean; value: string }) { + return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-radio-button-list/input-radio-button-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-radio-button-list/input-radio-button-list.element.ts new file mode 100644 index 0000000000..e68110dabc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-radio-button-list/input-radio-button-list.element.ts @@ -0,0 +1,71 @@ +import { css, html, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property } from 'lit/decorators.js'; +import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; +import { repeat } from 'lit/directives/repeat.js'; +import { UUIBooleanInputEvent } from '@umbraco-ui/uui'; +import { UmbLitElement } from '@umbraco-cms/element'; + +@customElement('umb-input-radio-button-list') +export class UmbInputRadioButtonListElement extends FormControlMixin(UmbLitElement) { + static styles = [ + UUITextStyles, + css` + :host { + display: block; + } + `, + ]; + + /** + * List of items. + */ + @property() + public list: Array<{ key: string; sortOrder: number; value: string }> = []; + + #selected = ''; + public get selected(): string { + return this.#selected; + } + public set selected(key: string) { + this.#selected = key; + super.value = key; + } + + @property() + public set value(key: string) { + if (key !== this._value) { + this.selected = key; + } + } + + protected getFormElement() { + return undefined; + } + + #setSelection(e: UUIBooleanInputEvent) { + e.stopPropagation(); + if (e.target.value) this.selected = e.target.value; + this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true })); + } + + render() { + if (!this.list) return nothing; + + return html` + ${repeat(this.list, (item) => item, this.renderRadioButton)} + `; + } + + renderRadioButton(item: { key: string; sortOrder: number; value: string }) { + return html``; + } +} + +export default UmbInputRadioButtonListElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-input-radio-button-list': UmbInputRadioButtonListElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/checkbox-list/property-editor-ui-checkbox-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/checkbox-list/property-editor-ui-checkbox-list.element.ts index 552f25fb94..0dda2b82d8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/checkbox-list/property-editor-ui-checkbox-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/checkbox-list/property-editor-ui-checkbox-list.element.ts @@ -12,35 +12,48 @@ import type { DataTypePropertyModel } from '@umbraco-cms/backend-api'; export class UmbPropertyEditorUICheckboxListElement extends UmbLitElement { static styles = [UUITextStyles]; - private _value: Array = []; + #value: Array = []; @property({ type: Array }) public get value(): Array { - return this._value; + return this.#value; } public set value(value: Array) { - this._value = value || []; + this.#value = value || []; } @property({ type: Array, attribute: false }) public set config(config: Array) { - const listData = config.find((x) => x.alias === 'itemList'); + const listData = config.find((x) => x.alias === 'items'); if (!listData) return; - this._list = listData.value; + + // formatting the items in the dictionary into an array + const sortedItems = []; + const values = Object.values<{ value: string; sortOrder: number }>(listData.value); + const keys = Object.keys(listData.value); + for (let i = 0; i < values.length; i++) { + sortedItems.push({ key: keys[i], sortOrder: values[i].sortOrder, value: values[i].value }); + } + // ensure the items are sorted by the provided sort order + sortedItems.sort((a, b) => { + return a.sortOrder > b.sortOrder ? 1 : b.sortOrder > a.sortOrder ? -1 : 0; + }); + + this._list = sortedItems.map((x) => ({ key: x.key, checked: this.#value.includes(x.value), value: x.value })); } @state() - private _list: [] = []; + private _list: Array<{ key: string; checked: boolean; value: string }> = []; - private _onChange(event: CustomEvent) { - this.value = (event.target as UmbInputCheckboxListElement).selectedKeys; + #onChange(event: CustomEvent) { + this.value = (event.target as UmbInputCheckboxListElement).selected; this.dispatchEvent(new CustomEvent('property-value-change')); } render() { return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/radio-button-list/property-editor-ui-radio-button-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/radio-button-list/property-editor-ui-radio-button-list.element.ts index 2718c7cc9a..1730df37a9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/radio-button-list/property-editor-ui-radio-button-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/uis/radio-button-list/property-editor-ui-radio-button-list.element.ts @@ -1,7 +1,10 @@ import { html } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property } from 'lit/decorators.js'; +import '../../../components/input-radio-button-list/input-radio-button-list.element'; +import type { UmbInputRadioButtonListElement } from '../../../components/input-radio-button-list/input-radio-button-list.element'; import { UmbLitElement } from '@umbraco-cms/element'; +import type { DataTypePropertyModel } from '@umbraco-cms/backend-api'; /** * @element umb-property-editor-ui-radio-button-list @@ -10,14 +13,50 @@ import { UmbLitElement } from '@umbraco-cms/element'; export class UmbPropertyEditorUIRadioButtonListElement extends UmbLitElement { static styles = [UUITextStyles]; - @property() - value = ''; + #value = ''; + @property({ type: String }) + public get value(): string { + return this.#value; + } + public set value(value: string) { + this.#value = value || ''; + } @property({ type: Array, attribute: false }) - public config = []; + public set config(config: Array) { + const listData = config.find((x) => x.alias === 'items'); + + if (!listData) return; + + // formatting the items in the dictionary into an array + const sortedItems = []; + const values = Object.values<{ value: string; sortOrder: number }>(listData.value); + const keys = Object.keys(listData.value); + for (let i = 0; i < values.length; i++) { + sortedItems.push({ key: keys[i], sortOrder: values[i].sortOrder, value: values[i].value }); + } + + // ensure the items are sorted by the provided sort order + sortedItems.sort((a, b) => { + return a.sortOrder > b.sortOrder ? 1 : b.sortOrder > a.sortOrder ? -1 : 0; + }); + + this._list = sortedItems; + } + + @state() + private _list: Array<{ key: string; sortOrder: number; value: string }> = []; + + #onChange(event: CustomEvent) { + this.value = (event.target as UmbInputRadioButtonListElement).selected; + this.dispatchEvent(new CustomEvent('property-value-change')); + } render() { - return html`
umb-property-editor-ui-radio-button-list
`; + return html``; } } 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 13397b5334..2e60cf6417 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 @@ -239,7 +239,16 @@ export const data: Array = [ parentKey: null, propertyEditorAlias: 'Umbraco.RadioButtonList', propertyEditorUiAlias: 'Umb.PropertyEditorUI.RadioButtonList', - data: [], + data: [ + { + alias: 'items', + value: { + 0: { sortOrder: 1, value: 'First Option' }, + 1: { sortOrder: 2, value: 'Second Option' }, + 2: { sortOrder: 3, value: 'I Am the third Option' }, + }, + }, + ], }, { type: 'data-type', @@ -250,11 +259,12 @@ export const data: Array = [ propertyEditorUiAlias: 'Umb.PropertyEditorUI.CheckboxList', data: [ { - alias: 'itemList', - value: [ - { label: 'Label 1', key: '123' }, - { label: 'Label 2', key: '456' }, - ], + alias: 'items', + value: { + 0: { sortOrder: 1, value: 'First Option' }, + 1: { sortOrder: 2, value: 'Second Option' }, + 2: { sortOrder: 3, value: 'I Am the third Option' }, + }, }, ], },