diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts index 47f48626e0..018ea55c34 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts @@ -1,16 +1,16 @@ import { html, customElement, property, map, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; import type { UmbSwatchDetails } from '@umbraco-cms/backoffice/models'; import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /* * This wraps the UUI library uui-color-swatches component * @element umb-input-color */ @customElement('umb-input-color') -export class UmbInputColorElement extends UUIFormControlMixin(UmbLitElement, '') { +export class UmbInputColorElement extends UmbFormControlMixin(UmbLitElement) { protected override getFormElement() { return undefined; } @@ -22,6 +22,10 @@ export class UmbInputColorElement extends UUIFormControlMixin(UmbLitElement, '') */ @property({ type: Boolean, reflect: true }) readonly = false; + @property({ type: Boolean }) + required = false; + @property({ type: String }) + requiredMessage: string = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @property({ type: Boolean }) showLabels = false; @@ -29,6 +33,15 @@ export class UmbInputColorElement extends UUIFormControlMixin(UmbLitElement, '') @property({ type: Array }) swatches?: Array; + constructor() { + super(); + this.addValidator( + 'valueMissing', + () => this.requiredMessage ?? UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, + () => !!this.required && !this.value && !this.readonly, + ); + } + #onChange(event: UUIColorSwatchesEvent) { this.value = event.target.value; this.dispatchEvent(new UmbChangeEvent()); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-eye-dropper/input-eye-dropper.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-eye-dropper/input-eye-dropper.element.ts index 1d45f6230c..73b8b26bed 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-eye-dropper/input-eye-dropper.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-eye-dropper/input-eye-dropper.element.ts @@ -1,11 +1,13 @@ import { customElement, html, property, when } from '@umbraco-cms/backoffice/external/lit'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external/uui'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; @customElement('umb-input-eye-dropper') -export class UmbInputEyeDropperElement extends UUIFormControlMixin(UmbLitElement, '') { +export class UmbInputEyeDropperElement extends UmbFormControlMixin( + UmbLitElement, +) { protected override getFormElement() { return undefined; } @@ -16,12 +18,26 @@ export class UmbInputEyeDropperElement extends UUIFormControlMixin(UmbLitElement this.dispatchEvent(new UmbChangeEvent()); } + @property({ type: Boolean, reflect: true }) + readonly = false; + @property({ type: Boolean }) + required = false; + @property({ type: String }) + requiredMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; + + constructor() { + super(); + this.addValidator( + 'valueMissing', + () => this.requiredMessage, + () => !this.readonly && this.required && (!this.value || this.value === ''), + ); + } + @property({ type: Boolean }) opacity = false; - @property({ type: Boolean }) showPalette = false; - @property({ type: Array }) swatches?: string[]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 302d9594c7..c93de3b058 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -4,7 +4,7 @@ import { css, customElement, html, nothing, property, repeat, state, when } from import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbInteractionMemoriesChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @@ -14,7 +14,7 @@ import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interact import type { UmbRepositoryItemsStatus } from '@umbraco-cms/backoffice/repository'; @customElement('umb-input-document') -export class UmbInputDocumentElement extends UmbFormControlMixin( +export class UmbInputDocumentElement extends UmbFormControlMixin( UmbLitElement, ) { #sorter = new UmbSorterController(this, { @@ -54,7 +54,7 @@ export class UmbInputDocumentElement extends UmbFormControlMixin | undefined { @@ -148,16 +152,22 @@ export class UmbInputDocumentElement extends UmbFormControlMixin this.requiredMessage, + () => !this.readonly && this.required && this.selection.length === 0, + ); + this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this.selection.length < this.min, + () => !this.readonly && !!this.min && this.selection.length < this.min, ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this.selection.length > this.max, + () => !this.readonly && !!this.max && this.selection.length > this.max, ); this.observe( diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index b5ebbff03d..5360295429 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -11,12 +11,13 @@ import type { UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; @customElement('umb-property-editor-ui-document-picker') -export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { - @property() - public value?: string; - +export class UmbPropertyEditorUIDocumentPickerElement + extends UmbFormControlMixin(UmbLitElement) + implements UmbPropertyEditorUiElement +{ public set config(config: UmbPropertyEditorConfigCollection | undefined) { this.#interactionMemoryManager.setPropertyEditorConfig(config); @@ -39,6 +40,10 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl */ @property({ type: Boolean, reflect: true }) readonly = false; + @property({ type: Boolean }) + mandatory = false; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() private _min = 0; @@ -66,6 +71,10 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl }); } + override firstUpdated() { + this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-document')!); + } + #onChange(event: CustomEvent & { target: UmbInputDocumentElement }) { this.value = event.target.value; this.dispatchEvent(new UmbChangeEvent()); @@ -95,6 +104,8 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl .value=${this.value} @change=${this.#onChange} ?readonly=${this.readonly} + ?required=${this.mandatory} + .requiredMessage=${this.mandatoryMessage} .interactionMemories=${this._interactionMemories} @interaction-memories-change=${this.#onInputInteractionMemoriesChange}> diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index 177fd5e022..619c7505d0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -206,12 +206,12 @@ export class UmbInputMediaElement extends UmbFormControlMixin this.minMessage, - () => !!this.min && this.selection.length < this.min, + () => !this.readonly && !!this.min && this.selection.length < this.min, ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this.selection.length > this.max, + () => !this.readonly && !!this.max && this.selection.length > this.max, ); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts index 8ddf6e6068..198a6a7097 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts @@ -133,13 +133,13 @@ export class UmbInputMemberElement extends UmbFormControlMixin this.minMessage, - () => !!this.min && this.selection.length < this.min, + () => !this.readonly && !!this.min && this.selection.length < this.min, ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this.selection.length > this.max, + () => !this.readonly && !!this.max && this.selection.length > this.max, ); this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts index 21c98a9aed..1608d03339 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts @@ -23,9 +23,9 @@ import { import { UmbMediaItemRepository, UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; -import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router'; import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /** * @element umb-input-multi-url @@ -34,7 +34,9 @@ import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; * @fires focus - when the input gains focus */ @customElement('umb-input-multi-url') -export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, '') { +export class UmbInputMultiUrlElement extends UmbFormControlMixin( + UmbLitElement, +) { #sorter = new UmbSorterController(this, { getUniqueOfElement: (element) => { return element.id; @@ -88,7 +90,7 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, * @attr * @default */ - @property({ type: String, attribute: 'min-message' }) + @property({ type: String, attribute: 'max-message' }) maxMessage = 'This field exceeds the allowed amount of items'; /** @@ -150,6 +152,10 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, } } #readonly = false; + @property({ type: Boolean }) + required = false; + @property({ type: String }) + requiredMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() private _modalRoute?: UmbModalRouteBuilder; @@ -165,6 +171,12 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, constructor() { super(); + this.addValidator( + 'valueMissing', + () => this.requiredMessage, + () => !this.readonly && this.required && (!this.value || this.value === ''), + ); + this.addValidator( 'rangeUnderflow', () => this.minMessage, diff --git a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.ts index d49b268abf..8c22e654d1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.ts @@ -11,7 +11,7 @@ import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import '../components/input-multi-url/index.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /** * @element umb-property-editor-ui-multi-url-picker @@ -38,6 +38,10 @@ export class UmbPropertyEditorUIMultiUrlPickerElement */ @property({ type: Boolean, reflect: true }) readonly = false; + @property({ type: Boolean }) + mandatory = false; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; #parseInt(value: unknown, fallback: number): number { const num = Number(value); @@ -101,6 +105,8 @@ export class UmbPropertyEditorUIMultiUrlPickerElement .variantId=${this._variantId} ?hide-anchor=${this._hideAnchor} ?readonly=${this.readonly} + ?required=${this.mandatory} + .requiredMessage=${this.mandatoryMessage} @change=${this.#onChange}> `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts index 3b0519ed92..f5c1642c2a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.element.ts @@ -7,22 +7,23 @@ import type { import type { UmbSwatchDetails } from '@umbraco-cms/backoffice/models'; import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /** * @element umb-property-editor-ui-color-picker */ @customElement('umb-property-editor-ui-color-picker') -export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { - #defaultShowLabels = false; - +export class UmbPropertyEditorUIColorPickerElement + extends UmbFormControlMixin(UmbLitElement) + implements UmbPropertyEditorUiElement +{ @property({ type: Object }) - public set value(value: UmbSwatchDetails | undefined) { - this.#value = value ? this.#ensureHashPrefix(value) : undefined; + public override set value(value: UmbSwatchDetails | undefined) { + super.value = value ? this.#ensureHashPrefix(value) : undefined; } - public get value(): UmbSwatchDetails | undefined { - return this.#value; + public override get value(): UmbSwatchDetails | undefined { + return super.value; } - #value?: UmbSwatchDetails | undefined; /** * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. @@ -32,9 +33,11 @@ export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement impleme */ @property({ type: Boolean, reflect: true }) readonly = false; + @property({ type: Boolean }) mandatory = false; + @property({ type: String }) mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() - private _showLabels = this.#defaultShowLabels; + private _showLabels = false; @state() private _swatches: Array = []; @@ -42,7 +45,7 @@ export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement impleme public set config(config: UmbPropertyEditorConfigCollection | undefined) { if (!config) return; - this._showLabels = config?.getValueByAlias('useLabel') ?? this.#defaultShowLabels; + this._showLabels = config?.getValueByAlias('useLabel') ?? false; const swatches = config?.getValueByAlias>('items') ?? []; this._swatches = swatches.map((swatch) => this.#ensureHashPrefix(swatch)); @@ -62,12 +65,18 @@ export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement impleme this.dispatchEvent(new UmbChangeEvent()); } + override firstUpdated() { + this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-color')!); + } + override render() { return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index a557488c1e..97cd3ef16e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -2,7 +2,7 @@ import type { UmbContentPickerSource } from '../../types.js'; import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbInteractionMemoriesChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; @@ -75,6 +75,20 @@ export class UmbInputContentElement extends UmbFormControlMixin this.requiredMessage, + () => !this.readonly && (this.required || this.min > 0) && this.selection.length === 0, + ); + } @property({ type: Array, attribute: false }) public get interactionMemories(): Array | undefined { diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index a805823960..59c459217d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -5,7 +5,7 @@ import { css, customElement, html, nothing, property, repeat, state } from '@umb import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UMB_ANCESTORS_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; import { UMB_DOCUMENT_ENTITY_TYPE } from '@umbraco-cms/backoffice/document'; import { UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; @@ -39,6 +39,10 @@ export class UmbPropertyEditorUIContentPickerElement */ @property({ type: Boolean, reflect: true }) readonly = false; + @property({ type: Boolean }) + mandatory = false; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() private _type: UmbContentPickerSource['type'] = 'content'; @@ -117,11 +121,6 @@ export class UmbPropertyEditorUIContentPickerElement this._minMessage = `${this.localize.term('validation_minCount')} ${this._min} ${this.localize.term('validation_items')}`; this._maxMessage = `${this.localize.term('validation_maxCount')} ${this._max} ${this.localize.term('validation_itemsSelected')}`; - - // NOTE: Run validation immediately, to notify if the value is outside of min/max range. [LK] - if (this._min > 0 || this._max < Infinity) { - this.checkValidity(); - } } #parseInt(value: unknown, fallback: number): number { @@ -207,6 +206,8 @@ export class UmbPropertyEditorUIContentPickerElement .startNode=${startNode} .allowedContentTypeIds=${this._allowedContentTypeUniques ?? ''} ?readonly=${this.readonly} + ?required=${this.mandatory} + .requiredMessage=${this.mandatoryMessage} @change=${this.#onChange} .interactionMemories=${this._interactionMemories} @interaction-memories-change=${this.#onInputInteractionMemoriesChange}> diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts index df32f6f115..3f88d38568 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/date-picker/property-editor-ui-date-picker.element.ts @@ -6,6 +6,7 @@ import { html, customElement, property, state } from '@umbraco-cms/backoffice/ex import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbInputDateElement } from '@umbraco-cms/backoffice/components'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /** * This property editor allows the user to pick a date, datetime-local, or time. @@ -27,7 +28,10 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; * @element umb-property-editor-ui-date-picker */ @customElement('umb-property-editor-ui-date-picker') -export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { +export class UmbPropertyEditorUIDatePickerElement + extends UmbFormControlMixin(UmbLitElement) + implements UmbPropertyEditorUiElement +{ /** * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. * @type {boolean} @@ -36,6 +40,17 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen */ @property({ type: Boolean, reflect: true }) readonly: boolean = false; + @property({ type: Boolean }) + mandatory = false; + + @property({ type: String }) + override get value(): string | undefined { + return super.value; + } + override set value(value: string | undefined) { + super.value = value; + this.#formatValue(value ?? ''); + } @state() private _inputType: UmbInputDateElement['type'] = 'datetime-local'; @@ -49,9 +64,6 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen @state() private _step?: number; - @property() - value?: string; - @state() private _inputValue?: string; @@ -144,16 +156,21 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen } } + override firstUpdated() { + this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-date')!); + } + override render() { return html` `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/eye-dropper/property-editor-ui-eye-dropper.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/eye-dropper/property-editor-ui-eye-dropper.element.ts index 6f1f271f10..a1ac4b6784 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/eye-dropper/property-editor-ui-eye-dropper.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/eye-dropper/property-editor-ui-eye-dropper.element.ts @@ -6,18 +6,25 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external/uui'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /** * @element umb-property-editor-ui-eye-dropper */ @customElement('umb-property-editor-ui-eye-dropper') -export class UmbPropertyEditorUIEyeDropperElement extends UmbLitElement implements UmbPropertyEditorUiElement { - @property() - value = ''; +export class UmbPropertyEditorUIEyeDropperElement + extends UmbFormControlMixin(UmbLitElement) + implements UmbPropertyEditorUiElement +{ + @property({ type: Boolean, reflect: true }) + readonly = false; + @property({ type: Boolean }) + mandatory = false; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() private _opacity = false; - @state() private _showPalette = false; @@ -33,12 +40,19 @@ export class UmbPropertyEditorUIEyeDropperElement extends UmbLitElement implemen this.dispatchEvent(new UmbChangeEvent()); } + protected override firstUpdated() { + this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-eye-dropper')!); + } + override render() { return html` `; }