diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-toggle/input-toggle.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-toggle/input-toggle.element.ts index 4a0eadee2a..58249d3659 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-toggle/input-toggle.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-toggle/input-toggle.element.ts @@ -26,6 +26,15 @@ export class UmbInputToggleElement extends UUIFormControlMixin(UmbLitElement, '' @property({ type: String }) labelOff?: string; + /** + * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. + * @type {boolean} + * @attr + * @default false + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + @state() _currentLabel?: string; @@ -52,7 +61,8 @@ export class UmbInputToggleElement extends UUIFormControlMixin(UmbLitElement, '' return html``; + @change=${this.#onChange} + ?readonly=${this.readonly}>`; } static override styles = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts index 522b6733d0..c6e010236a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/document-create-options-modal.element.ts @@ -119,7 +119,7 @@ export class UmbDocumentCreateOptionsModalElement extends UmbModalBaseElement< return html` ${when( - this._availableBlueprints.length === 0 && this.#documentTypeUnique, + this._availableBlueprints.length && this.#documentTypeUnique, () => this.#renderBlueprints(), () => this.#renderDocumentTypes(), )} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-field.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-field.element.ts index 7ca51a65f9..c330b50c43 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-field.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-field.element.ts @@ -15,9 +15,6 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @customElement('umb-image-cropper-field') export class UmbInputImageCropperFieldElement extends UmbLitElement { @property({ attribute: false }) - get value() { - return this.#value; - } set value(value) { if (!value) { this.crops = []; @@ -34,6 +31,9 @@ export class UmbInputImageCropperFieldElement extends UmbLitElement { this.requestUpdate(); } + get value() { + return this.#value; + } #value?: UmbImageCropperPropertyEditorValue; @state() diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-preview.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-preview.element.ts index 35f20b490d..a092f0868c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-preview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/image-cropper-preview.element.ts @@ -1,9 +1,10 @@ import type { UmbImageCropperCrop, UmbImageCropperFocalPoint } from './index.js'; import { calculateExtrapolatedValue, clamp } from '@umbraco-cms/backoffice/utils'; -import { LitElement, css, html, nothing, customElement, property, query } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, nothing, customElement, property, query } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @customElement('umb-image-cropper-preview') -export class UmbImageCropperPreviewElement extends LitElement { +export class UmbImageCropperPreviewElement extends UmbLitElement { @query('#image') imageElement!: HTMLImageElement; @query('#container') imageContainerElement!: HTMLImageElement; @@ -150,7 +151,9 @@ export class UmbImageCropperPreviewElement extends LitElement {
- ${this.label ?? this.crop.alias} + + ${this.crop.label !== undefined ? this.localize.string(this.crop.label) : (this.label ?? this.crop.alias)} + ${this.crop.width} x ${this.crop.height} ${this.crop.coordinates ? html`User defined` diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/types.ts index 649368b8a7..1def05fbb3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/types.ts @@ -1,17 +1,9 @@ +import type { UmbCropModel, UmbFocalPointModel } from '../../types.js'; + export type UmbImageCropperPropertyEditorValue = { temporaryFileId?: string | null; - crops: Array<{ - alias: string; - coordinates?: { - x1: number; - x2: number; - y1: number; - y2: number; - }; - height: number; - width: number; - }>; - focalPoint: { left: number; top: number }; + crops: Array; + focalPoint: UmbFocalPointModel; src: string; }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts index 43d8a51bc7..725d1502f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts @@ -1,7 +1,7 @@ import { UmbInputMediaElement } from '../input-media/index.js'; import { UmbMediaItemRepository } from '../../repository/index.js'; import { UMB_IMAGE_CROPPER_EDITOR_MODAL, UMB_MEDIA_PICKER_MODAL } from '../../modals/index.js'; -import type { UmbCropModel, UmbMediaPickerPropertyValue } from '../../property-editors/index.js'; +import type { UmbCropModel, UmbMediaPickerPropertyValue } from '../../types.js'; import type { UmbMediaItemModel } from '../../repository/index.js'; import type { UmbUploadableFileModel } from '../../dropzone/index.js'; import { customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit'; @@ -122,13 +122,7 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement, } @property({ type: Array }) - public set preselectedCrops(value: Array) { - this.#preselectedCrops = value; - } - public get preselectedCrops(): Array { - return this.#preselectedCrops; - } - #preselectedCrops: Array = []; + public preselectedCrops?: Array; @property({ type: Boolean }) public set focalPointEnabled(value: boolean) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts index ef56a68fe6..8ee054676a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts @@ -14,3 +14,5 @@ export { UMB_MEDIA_PICKER_MODAL } from './modals/media-picker/index.js'; export type { UmbMediaTreeItemModel } from './tree/index.js'; export { UmbMediaAuditLogRepository } from './audit-log/index.js'; + +export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts index 0641fbe118..846e26822c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts @@ -1,6 +1,6 @@ import { UmbMediaUrlRepository } from '../../repository/index.js'; import { UMB_MEDIA_PICKER_MODAL } from '../media-picker/media-picker-modal.token.js'; -import type { UmbCropModel } from '../../property-editors/index.js'; +import type { UmbCropModel } from '../../types.js'; import type { UmbInputImageCropperFieldElement } from '../../components/input-image-cropper/image-cropper-field.element.js'; import type { UmbImageCropperPropertyEditorValue } from '../../components/index.js'; import type { @@ -79,10 +79,21 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement< const item = data?.[0]; if (!item?.url) return; + + /** + * Combine the crops from the property editor with the stored crops and ignore any invalid crops + * (e.g. crops that have been removed from the property editor) + * @remark If a crop is removed from the property editor, it will be ignored and not saved + */ + const crops: Array = this._crops.map((crop) => { + const existingCrop = this.value.crops?.find((c) => c.alias === crop.alias); + return existingCrop ? { ...crop, ...existingCrop } : crop; + }); + const value: UmbImageCropperPropertyEditorValue = { ...this.value, src: item.url, - crops: this.value.crops?.length ? this.value.crops : this._crops, + crops, focalPoint: this.value.focalPoint ?? { left: 0.5, top: 0.5 }, }; this._imageCropperValue = value; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.token.ts index e5b4f47c0b..6371e4c56d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.token.ts @@ -1,5 +1,5 @@ import type { UmbImageCropperCrop } from '../../components/index.js'; -import type { UmbCropModel } from '../../property-editors/index.js'; +import type { UmbCropModel } from '../../property-editors/types.js'; import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; export interface UmbImageCropperEditorModalData { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts index b246c984b2..7eddcc7572 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/index.ts @@ -1,33 +1 @@ export * from './property-editor-ui-media-picker.element.js'; - -export type UmbMediaPickerPropertyValue = { - key: string; - mediaKey: string; - mediaTypeAlias: string; - focalPoint: UmbFocalPointModel | null; - crops: Array; -}; - -export type UmbCropModel = { - alias: string; - height: number; - width: number; - coordinates?: { - x1: number; - x2: number; - y1: number; - y2: number; - }; -}; - -export interface UmbConfiguredCropModel { - label: string; - alias: string; - width: number; - height: number; -} - -export interface UmbFocalPointModel { - left: number; - top: number; -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index d80f7f33f7..4a1eff1fc9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -1,5 +1,5 @@ import type { UmbInputRichMediaElement } from '../../components/input-rich-media/input-rich-media.element.js'; -import type { UmbCropModel, UmbMediaPickerPropertyValue } from './index.js'; +import type { UmbCropModel, UmbMediaPickerPropertyValue } from '../types.js'; import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/types.ts new file mode 100644 index 0000000000..0baa97364e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/types.ts @@ -0,0 +1,25 @@ +export type UmbMediaPickerPropertyValue = { + key: string; + mediaKey: string; + mediaTypeAlias: string; + focalPoint: UmbFocalPointModel | null; + crops: Array; +}; + +export type UmbCropModel = { + label?: string; + alias: string; + height: number; + width: number; + coordinates?: { + x1: number; + x2: number; + y1: number; + y2: number; + }; +}; + +export interface UmbFocalPointModel { + left: number; + top: number; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts index 65dfefdd6c..a350ead8dd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts @@ -30,3 +30,5 @@ export interface UmbMediaValueModel { } export interface UmbMediaVariantOptionModel extends UmbVariantOptionModel {} + +export type * from './property-editors/types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/toggle/property-editor-ui-toggle.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/toggle/property-editor-ui-toggle.element.ts index ae1bb7f9a4..e2a2333e23 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/toggle/property-editor-ui-toggle.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/toggle/property-editor-ui-toggle.element.ts @@ -13,6 +13,15 @@ export class UmbPropertyEditorUIToggleElement extends UmbLitElement implements U @property({ type: Boolean }) value: undefined | boolean = undefined; + /** + * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. + * @type {boolean} + * @attr + * @default false + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + @state() _labelOff?: string; @@ -42,7 +51,8 @@ export class UmbPropertyEditorUIToggleElement extends UmbLitElement implements U .labelOff=${this._labelOff} ?checked=${this.value} ?showLabels=${this._showLabels} - @change=${this.#onChange}> + @change=${this.#onChange} + ?readonly=${this.readonly}> `; }