diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-cropper/Umbraco.ImageCropper.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-cropper/Umbraco.ImageCropper.ts index e00276f2d794..f3f41f277c9a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-cropper/Umbraco.ImageCropper.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-cropper/Umbraco.ImageCropper.ts @@ -10,7 +10,7 @@ export const manifest: ManifestPropertyEditorSchema = { properties: [ { alias: 'crops', - label: 'Define Crops', + label: 'Crop options', propertyEditorUiAlias: 'Umb.PropertyEditorUi.ImageCropsConfiguration', }, ], diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-crops/property-editor-ui-image-crops.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-crops/property-editor-ui-image-crops.element.ts index 8a4252228206..a5428232cb07 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-crops/property-editor-ui-image-crops.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/image-crops/property-editor-ui-image-crops.element.ts @@ -13,9 +13,6 @@ export type UmbCrop = { height: number; }; -/** - * @element umb-property-editor-ui-image-crops - */ @customElement('umb-property-editor-ui-image-crops') export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implements UmbPropertyEditorUiElement { @query('#label') @@ -24,6 +21,9 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen @state() private _value: Array = []; + @state() + private _isCreating = false; + @property({ type: Array }) public set value(value: Array) { this._value = value ?? []; @@ -39,13 +39,8 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen #oldInputValue = ''; #sorter = new UmbSorterController(this, { - getUniqueOfElement: (element: HTMLElement) => { - const unique = element.dataset['alias']; - return unique; - }, - getUniqueOfModel: (modelEntry: UmbCrop) => { - return modelEntry.alias; - }, + getUniqueOfElement: (element: HTMLElement) => element.dataset['alias'], + getUniqueOfModel: (modelEntry: UmbCrop) => modelEntry.alias, identifier: 'Umb.SorterIdentifier.ImageCrops', itemSelector: '.crop', containerSelector: '.crops', @@ -64,45 +59,28 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen #onEdit(crop: UmbCrop) { this.editCropAlias = crop.alias; - - const form = this.shadowRoot?.querySelector('form') as HTMLFormElement; - if (!form) return; - - const label = form.querySelector('#label') as HTMLInputElement; - const alias = form.querySelector('#alias') as HTMLInputElement; - const width = form.querySelector('#width') as HTMLInputElement; - const height = form.querySelector('#height') as HTMLInputElement; - - if (!alias || !width || !height) return; - - label.value = crop.label; - alias.value = crop.alias; - width.value = crop.width.toString(); - height.value = crop.height.toString(); + this._isCreating = false; } #onEditCancel() { this.editCropAlias = ''; + this._isCreating = false; } #onSubmit(event: Event) { event.preventDefault(); const form = event.target as HTMLFormElement; - if (!form) return; - - if (!form.checkValidity()) return; + if (!form || !form.checkValidity()) return; const formData = new FormData(form); - const label = formData.get('label') as string; const alias = formData.get('alias') as string; const width = formData.get('width') as string; const height = formData.get('height') as string; if (!label || !alias || !width || !height) return; - if (!this.value) this.value = []; - const newCrop = { + const newCrop: UmbCrop = { label, alias, width: parseInt(width), @@ -112,7 +90,6 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen if (this.editCropAlias) { const index = this.value.findIndex((item) => item.alias === this.editCropAlias); if (index === -1) return; - const temp = [...this.value]; temp[index] = newCrop; this.value = [...temp]; @@ -120,40 +97,14 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen } else { this.value = [...this.value, newCrop]; } - this.dispatchEvent(new UmbChangeEvent()); + this.dispatchEvent(new UmbChangeEvent()); form.reset(); - this._labelInput.focus(); - } - - #renderActions() { - return this.editCropAlias - ? html`Cancel - ` - : html``; - } - - #onLabelInput() { - const value = this._labelInput.value ?? ''; - - const aliasValue = generateAlias(value); - - const alias = this.shadowRoot?.querySelector('#alias') as HTMLInputElement; - - if (!alias) return; - - const oldAliasValue = generateAlias(this.#oldInputValue); - - if (alias.value === oldAliasValue || !alias.value) { - alias.value = aliasValue; - } - - this.#oldInputValue = value; + this._labelInput?.focus(); + this._isCreating = false; } - override render() { - if (!this.value) this.value = []; - + #renderForm(initial?: UmbCrop) { return html`
@@ -165,54 +116,118 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen id="label" name="label" type="text" - autocomplete="false" - value=""> + required + .value=${initial?.label ?? ''}>
Alias - +
Width - + px
Height - + px
-
${this.#renderActions()}
+
+ ${this.editCropAlias + ? html`Cancel + ` + : html``} +
-
+ `; + } + + #onLabelInput() { + const value = this._labelInput.value ?? ''; + const aliasValue = generateAlias(value); + const alias = this.shadowRoot?.querySelector('#alias') as HTMLInputElement; + if (!alias) return; + + const oldAliasValue = generateAlias(this.#oldInputValue); + if (alias.value === oldAliasValue || !alias.value) { + alias.value = aliasValue; + } + + this.#oldInputValue = value; + } + + override render() { + return html` + ${repeat( this.value, (item) => item.alias, (item) => html` -
- - ${item.label} (${item.alias}) - (${item.width} x ${item.height}px) -
- this.#onEdit(item)}> - this.#onRemove(item.alias)}> -
-
+ ${this.editCropAlias === item.alias + ? html`
${this.#renderForm(item)}
` + : html` + + + + this.#onEdit(item)}> + this.#onRemove(item.alias)}> + + + `} `, )} -
+ + ${!this._isCreating && !this.editCropAlias + ? html` (this._isCreating = true)} + label=${this.localize.term('general_create')}>` + : ''} + ${this._isCreating ? this.#renderForm() : ''} `; } - static override readonly styles = [ UmbTextStyles, css` @@ -228,34 +243,16 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen .crop { display: flex; align-items: center; - background: var(--uui-color-background); - } - .crop-drag { - cursor: grab; - padding-inline: var(--uui-size-space-4); - color: var(--uui-color-disabled-contrast); - font-weight: bold; - } - - .crop-drag:active { - cursor: grabbing; - } - - .crop-size { - font-size: 0.9em; - padding-inline: var(--uui-size-space-4); - } - .crop-actions { - display: flex; - margin-left: auto; } form { display: flex; gap: var(--uui-size-space-2); + flex-wrap: wrap; } .input { display: flex; flex-direction: column; + flex: 1 1 200px; } uui-input[type='number'] { text-align: right; @@ -273,6 +270,9 @@ export class UmbPropertyEditorUIImageCropsElement extends UmbLitElement implemen display: flex; align-items: flex-end; } + #create { + width: 100%; + } `, ]; }