From 5d682929d7c9a8cf773b594532eb23f6c02b9c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 12 Jan 2024 13:27:13 +0100 Subject: [PATCH] move into web components --- .../sorter-dashboard.ts | 92 +-------------- .../sorter-group.ts | 107 ++++++++++++++++++ .../sorter-with-two-containers/sorter-item.ts | 46 ++++++++ .../packages/core/sorter/sorter.controller.ts | 26 +++-- 4 files changed, 175 insertions(+), 96 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-group.ts create mode 100644 src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-item.ts diff --git a/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-dashboard.ts b/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-dashboard.ts index 9f8737a08e..a1a799fbc5 100644 --- a/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-dashboard.ts +++ b/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-dashboard.ts @@ -1,87 +1,13 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, customElement, LitElement, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; -import { UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter'; - -type ModelEntryType = { - name: string; -}; - -const SORTER_CONFIG: UmbSorterConfig = { - compareElementToModel: (element: HTMLElement, model: ModelEntryType) => { - return element.getAttribute('data-name') === model.name; - }, - querySelectModelToElement: (container: HTMLElement, modelEntry: ModelEntryType) => { - return container.querySelector('data-name[' + modelEntry.name + ']'); - }, - identifier: 'string-that-identifies-all-example-sorters', - itemSelector: '.sorter-item', - containerSelector: '.sorter-container', - placeholderClass: 'sorter-placeholder', -}; - +import './sorter-group.js'; @customElement('example-sorter-dashboard') export class ExampleSorterDashboard extends UmbElementMixin(LitElement) { - @state() - _items: ModelEntryType[] = [ - { - name: 'Apple', - }, - { - name: 'Banana', - }, - { - name: 'Pear', - }, - { - name: 'Pineapple', - }, - { - name: 'Lemon', - }, - ]; - - #sorter = new UmbSorterController(this, { - ...SORTER_CONFIG, - performItemInsert: ({ item, newIndex }) => { - this._items.splice(newIndex, 0, item); - console.log('inserted', item.name, 'at', newIndex, ' ', this._items.map((x) => x.name).join(', ')); - this.requestUpdate('_items'); - return true; - }, - performItemRemove: ({ item }) => { - const indexToMove = this._items.findIndex((x) => x.name === item.name); - this._items.splice(indexToMove, 1); - console.log('removed', item.name, 'at', indexToMove, ' ', this._items.map((x) => x.name).join(', ')); - this.requestUpdate('_items'); - return true; - }, - }); - - constructor() { - super(); - this.#sorter.setModel(this._items); - } - - removeItem = (item: ModelEntryType) => { - this._items = this._items.filter((r) => r.name !== item.name); - this.#sorter.setModel(this._items); - }; - render() { return html` - -
- ${repeat( - this._items, - (item) => item.name, - (item) => - html`
- ${item.name} - -
`, - )} -
+ + `; } @@ -94,17 +20,9 @@ export class ExampleSorterDashboard extends UmbElementMixin(LitElement) { padding: var(--uui-size-layout-1); } - .sorter-item { + .outer-wrapper { display: flex; - align-items: center; - justify-content: space-between; - padding: var(--uui-size-layout-1); - border: 1px solid var(--uui-color-border); - border-radius: var(--uui-border-radius); - margin-bottom: 3px; - } - .sorter-placeholder { - opacity: 0.2; + flex-direction: row; } `, ]; diff --git a/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-group.ts b/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-group.ts new file mode 100644 index 0000000000..04d64ee479 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-group.ts @@ -0,0 +1,107 @@ +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { css, html, customElement, LitElement, state, repeat } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; +import { UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter'; + +import './sorter-item.js'; + +type ModelEntryType = { + name: string; +}; + +const SORTER_CONFIG: UmbSorterConfig = { + compareElementToModel: (element: HTMLElement, model: ModelEntryType) => { + return element.getAttribute('name') === model.name; + }, + querySelectModelToElement: (container: HTMLElement, modelEntry: ModelEntryType) => { + return container.querySelector('name[' + modelEntry.name + ']'); + }, + identifier: 'string-that-identifies-all-example-sorters', + itemSelector: 'example-sorter-item', + containerSelector: '.sorter-container', +}; + +@customElement('example-sorter-group') +export class ExampleSorterGroup extends UmbElementMixin(LitElement) { + @state() + _items: ModelEntryType[] = [ + { + name: 'Apple', + }, + { + name: 'Banana', + }, + { + name: 'Pear', + }, + { + name: 'Pineapple', + }, + { + name: 'Lemon', + }, + ]; + + #sorter = new UmbSorterController(this, { + ...SORTER_CONFIG, + performItemInsert: ({ item, newIndex }) => { + this._items.splice(newIndex, 0, item); + console.log('inserted', item.name, 'at', newIndex, ' ', this._items.map((x) => x.name).join(', ')); + this.requestUpdate('_items'); + return true; + }, + performItemRemove: ({ item }) => { + const indexToMove = this._items.findIndex((x) => x.name === item.name); + this._items.splice(indexToMove, 1); + console.log('removed', item.name, 'at', indexToMove, ' ', this._items.map((x) => x.name).join(', ')); + this.requestUpdate('_items'); + return true; + }, + }); + + constructor() { + super(); + this.#sorter.setModel(this._items); + } + + removeItem = (item: ModelEntryType) => { + this._items = this._items.filter((r) => r.name !== item.name); + this.#sorter.setModel(this._items); + }; + + render() { + return html` +
+ ${repeat( + this._items, + (item) => item.name, + (item) => + html` + + `, + )} +
+ `; + } + + static styles = [ + UmbTextStyles, + css` + :host { + display: block; + } + + .sorter-placeholder { + opacity: 0.2; + } + `, + ]; +} + +export default ExampleSorterGroup; + +declare global { + interface HTMLElementTagNameMap { + 'example-sorter-group': ExampleSorterGroup; + } +} diff --git a/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-item.ts b/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-item.ts new file mode 100644 index 0000000000..d9d9c81aa7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/examples/sorter-with-two-containers/sorter-item.ts @@ -0,0 +1,46 @@ +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { css, html, customElement, LitElement, state, repeat, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; +import { UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter'; + +@customElement('example-sorter-item') +export class ExampleSorterItem extends UmbElementMixin(LitElement) { + @property({ type: String, reflect: true }) + name: string = ''; + + @property({ type: Boolean, reflect: true, attribute: 'drag-placeholder' }) + umbDragPlaceholder = false; + + render() { + return html` + ${this.name} + + `; + } + + static styles = [ + UmbTextStyles, + css` + :host { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--uui-size-layout-1); + border: 1px solid var(--uui-color-border); + border-radius: var(--uui-border-radius); + margin-bottom: 3px; + } + :host[drag-placeholder] { + opacity: 0.2; + } + `, + ]; +} + +export default ExampleSorterItem; + +declare global { + interface HTMLElementTagNameMap { + 'example-sorter-item': ExampleSorterItem; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts index 598ce08d76..5fcc94a136 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts @@ -69,7 +69,8 @@ type INTERNAL_UmbSorterConfig = { disabledItemSelector?: string; containerSelector: string; ignorerSelector: string; - placeholderClass: string; + placeholderClass?: string; + placeholderAttr?: string; draggableSelector?: string; boundarySelector?: string; dataTransferResolver?: (dataTransfer: DataTransfer | null, currentItem: T) => void; @@ -102,11 +103,8 @@ type INTERNAL_UmbSorterConfig = { }; // External type with some properties optional, as they have defaults: -export type UmbSorterConfig = Omit< - INTERNAL_UmbSorterConfig, - 'placeholderClass' | 'ignorerSelector' | 'containerSelector' -> & - Partial, 'placeholderClass' | 'ignorerSelector' | 'containerSelector'>>; +export type UmbSorterConfig = Omit, 'ignorerSelector' | 'containerSelector'> & + Partial, 'ignorerSelector' | 'containerSelector'>>; /** * @export @@ -149,7 +147,7 @@ export class UmbSorterController implements UmbController { // Set defaults: config.ignorerSelector ??= 'a, img, iframe'; - config.placeholderClass ??= '--umb-sorter-placeholder'; + config.placeholderAttr ??= 'drag-placeholder'; this.#config = config as INTERNAL_UmbSorterConfig; host.addController(this); @@ -308,7 +306,12 @@ export class UmbSorterController implements UmbController { this.#rqaId = undefined; if (this.#currentElement) { this.#currentElement.style.transform = ''; - this.#currentElement.classList.add(this.#config.placeholderClass); + if (this.#config.placeholderClass) { + this.#currentElement.classList.add(this.#config.placeholderClass); + } + if (this.#config.placeholderAttr) { + this.#currentElement.setAttribute(this.#config.placeholderAttr, ''); + } } }); }; @@ -321,7 +324,12 @@ export class UmbSorterController implements UmbController { window.removeEventListener('dragover', this.#handleDragMove); window.removeEventListener('dragend', this.#handleDragEnd); this.#currentElement.style.transform = ''; - this.#currentElement.classList.remove(this.#config.placeholderClass); + if (this.#config.placeholderClass) { + this.#currentElement.classList.remove(this.#config.placeholderClass); + } + if (this.#config.placeholderAttr) { + this.#currentElement.removeAttribute(this.#config.placeholderAttr); + } this.#stopAutoScroll(); this.removeAllowIndication();