diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts index 8ab27986e1..7b0ec0e6a5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-editor/property-editor-ui-block-grid.element.ts @@ -19,7 +19,11 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import { jsonStringComparison, observeMultiple } from '@umbraco-cms/backoffice/observable-api'; import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; -import { UmbFormControlMixin, UmbValidationContext } from '@umbraco-cms/backoffice/validation'; +import { + UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, + UmbFormControlMixin, + UmbValidationContext, +} from '@umbraco-cms/backoffice/validation'; import type { UmbBlockTypeGroup } from '@umbraco-cms/backoffice/block-type'; import { debounceTime } from '@umbraco-cms/backoffice/external/rxjs'; @@ -77,6 +81,10 @@ export class UmbPropertyEditorUIBlockGridElement return this.#readonly; } #readonly = false; + @property({ type: Boolean }) + mandatory?: boolean; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() private _layoutColumns?: number; @@ -112,6 +120,16 @@ export class UmbPropertyEditorUIBlockGridElement constructor() { super(); + this.addValidator( + 'valueMissing', + () => this.mandatoryMessage, + () => { + if (!this.mandatory || this.readonly) return false; + const count = this.value?.layout?.[UMB_BLOCK_GRID_PROPERTY_EDITOR_SCHEMA_ALIAS]?.length ?? 0; + return count === 0; + }, + ); + this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (context) => { if (context) { this.observe( diff --git a/src/Umbraco.Web.UI.Client/src/packages/code-editor/property-editor/property-editor-ui-code-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/code-editor/property-editor/property-editor-ui-code-editor.element.ts index 7d004f5693..50b68ae048 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/code-editor/property-editor/property-editor-ui-code-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/code-editor/property-editor/property-editor-ui-code-editor.element.ts @@ -9,11 +9,15 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import '../components/code-editor.element.js'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; const elementName = 'umb-property-editor-ui-code-editor'; @customElement(elementName) -export class UmbPropertyEditorUICodeEditorElement extends UmbLitElement implements UmbPropertyEditorUiElement { +export class UmbPropertyEditorUICodeEditorElement + extends UmbFormControlMixin(UmbLitElement) + implements UmbPropertyEditorUiElement +{ #defaultLanguage: CodeEditorLanguage = 'javascript'; @state() @@ -31,8 +35,9 @@ export class UmbPropertyEditorUICodeEditorElement extends UmbLitElement implemen @state() private _wordWrap = false; - @property() - value = ''; + mandatory?: boolean; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @property({ attribute: false }) public set config(config: UmbPropertyEditorConfigCollection | undefined) { @@ -53,6 +58,16 @@ export class UmbPropertyEditorUICodeEditorElement extends UmbLitElement implemen this.dispatchEvent(new UmbChangeEvent()); } + constructor() { + super(); + + this.addValidator( + 'valueMissing', + () => this.mandatoryMessage, + () => !!this.mandatory && (!this.value || this.value.length === 0), + ); + } + override render() { return html` this.requiredMessage ?? UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, + () => !this.readonly && !!this.required && (this.value === undefined || this.value === null || this.value === ''), + ); + } + #onCodeEditorLoaded(event: UmbCodeEditorLoadedEvent) { if (event.type !== UmbCodeEditorLoadedEvent.TYPE) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/property-editors/markdown-editor/property-editor-ui-markdown-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/property-editors/markdown-editor/property-editor-ui-markdown-editor.element.ts index 2307159e45..ec4d19cdc7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/property-editors/markdown-editor/property-editor-ui-markdown-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/property-editors/markdown-editor/property-editor-ui-markdown-editor.element.ts @@ -9,15 +9,16 @@ import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import '../../components/input-markdown-editor/index.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; /** * @element umb-property-editor-ui-markdown-editor */ @customElement('umb-property-editor-ui-markdown-editor') -export class UmbPropertyEditorUIMarkdownEditorElement extends UmbLitElement implements UmbPropertyEditorUiElement { - @property() - value?: string; - +export class UmbPropertyEditorUIMarkdownEditorElement + 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} @@ -26,6 +27,14 @@ export class UmbPropertyEditorUIMarkdownEditorElement extends UmbLitElement impl */ @property({ type: Boolean, reflect: true }) readonly = false; + /** + * Sets the input to mandatory, meaning validation will fail if the value is empty. + * @type {boolean} + */ + @property({ type: Boolean }) + mandatory?: boolean; + @property({ type: String }) + mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY; @state() private _preview?: boolean; @@ -45,6 +54,10 @@ export class UmbPropertyEditorUIMarkdownEditorElement extends UmbLitElement impl this.dispatchEvent(new UmbChangeEvent()); } + protected override firstUpdated() { + this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-markdown')!); + } + override render() { return html` + ?readonly=${this.readonly} + ?required=${this.mandatory} + .requiredMessage=${this.mandatoryMessage}> `; } }