Property Editors: Added form control and mandatory support to editors in common group(Number, Tags, Slider). (#20659)
* Added mandatory support to property-editor-ui-number. * Added form control to property-editor-ui-tags * Added validator to the slider when value is missing and support for mandatory and mandatory message. * Removed unnecessary ternary. * Removed white space lit error. * Fix tags input to handle undefined items array --------- Co-authored-by: Mads Rasmussen <madsr@hey.com>
This commit is contained in:
@@ -3,13 +3,23 @@ import { customElement, html, property } from '@umbraco-cms/backoffice/external/
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UUISliderEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY } from '@umbraco-cms/backoffice/validation';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
function splitString(value: string | undefined): Partial<[number | undefined, number | undefined]> {
|
||||
const [from, to] = (value ?? ',').split(',');
|
||||
const fromNumber = makeNumberOrUndefined(from);
|
||||
return [fromNumber, makeNumberOrUndefined(to, fromNumber)];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @param fallback
|
||||
*/
|
||||
function makeNumberOrUndefined(value: string | undefined, fallback?: undefined | number) {
|
||||
if (value === undefined) {
|
||||
return fallback;
|
||||
@@ -21,6 +31,11 @@ function makeNumberOrUndefined(value: string | undefined, fallback?: undefined |
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @param fallback
|
||||
*/
|
||||
function undefinedFallbackToString(value: number | undefined, fallback: number): string {
|
||||
return (value === undefined ? fallback : value).toString();
|
||||
}
|
||||
@@ -48,6 +63,15 @@ export class UmbInputSliderElement extends UmbFormControlMixin<string, typeof Um
|
||||
|
||||
@property({ type: Number })
|
||||
step = 1;
|
||||
/**
|
||||
* Sets the input to required, meaning validation will fail if the value is empty.
|
||||
* @type {boolean}
|
||||
*/
|
||||
@property({ type: Boolean })
|
||||
required?: boolean;
|
||||
|
||||
@property({ type: String })
|
||||
requiredMessage?: string;
|
||||
|
||||
@property({ type: Number })
|
||||
public get valueLow(): number | undefined {
|
||||
@@ -92,6 +116,12 @@ export class UmbInputSliderElement extends UmbFormControlMixin<string, typeof Um
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.addValidator(
|
||||
'valueMissing',
|
||||
() => this.requiredMessage ?? UMB_VALIDATION_EMPTY_LOCALIZATION_KEY,
|
||||
() => !this.readonly && !!this.required && (this.value === undefined || this.value === null || this.value === ''),
|
||||
);
|
||||
|
||||
this.addValidator(
|
||||
'rangeUnderflow',
|
||||
() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { css, customElement, html, ifDefined, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import type {
|
||||
@@ -10,7 +10,7 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
@customElement('umb-property-editor-ui-number')
|
||||
export class UmbPropertyEditorUINumberElement
|
||||
extends UmbFormControlMixin<number | undefined, typeof UmbLitElement, undefined>(UmbLitElement)
|
||||
extends UmbFormControlMixin<number, typeof UmbLitElement, undefined>(UmbLitElement, undefined)
|
||||
implements UmbPropertyEditorUiElement
|
||||
{
|
||||
/**
|
||||
@@ -22,6 +22,15 @@ export class UmbPropertyEditorUINumberElement
|
||||
@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 _label?: string;
|
||||
|
||||
@@ -78,6 +87,7 @@ export class UmbPropertyEditorUINumberElement
|
||||
this,
|
||||
);
|
||||
}
|
||||
this.addFormControlElement(this.shadowRoot!.querySelector('uui-input')!);
|
||||
}
|
||||
|
||||
#parseNumber(input: unknown): number | undefined {
|
||||
@@ -103,6 +113,8 @@ export class UmbPropertyEditorUINumberElement
|
||||
placeholder=${ifDefined(this._placeholder)}
|
||||
value=${this.value?.toString() ?? ''}
|
||||
@change=${this.#onChange}
|
||||
?required=${this.mandatory}
|
||||
.requiredMessage=${this.mandatoryMessage}
|
||||
?readonly=${this.readonly}>
|
||||
</uui-input>
|
||||
`;
|
||||
|
||||
@@ -8,14 +8,23 @@ import type {
|
||||
UmbPropertyEditorConfigCollection,
|
||||
UmbPropertyEditorUiElement,
|
||||
} from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
function stringToValueObject(value: string | undefined): Partial<UmbSliderPropertyEditorUiValueObject> {
|
||||
const [from, to] = (value ?? ',').split(',');
|
||||
const fromNumber = makeNumberOrUndefined(from);
|
||||
return { from: fromNumber, to: makeNumberOrUndefined(to, fromNumber) };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @param fallback
|
||||
*/
|
||||
function makeNumberOrUndefined(value: string | undefined, fallback?: undefined | number) {
|
||||
if (value === undefined) {
|
||||
return fallback;
|
||||
@@ -27,6 +36,11 @@ function makeNumberOrUndefined(value: string | undefined, fallback?: undefined |
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @param fallback
|
||||
*/
|
||||
function undefinedFallback(value: number | undefined, fallback: number) {
|
||||
return value === undefined ? fallback : value;
|
||||
}
|
||||
@@ -48,6 +62,16 @@ export class UmbPropertyEditorUISliderElement
|
||||
@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 _enableRange = false;
|
||||
|
||||
@@ -139,7 +163,9 @@ export class UmbPropertyEditorUISliderElement
|
||||
.max=${this._max}
|
||||
?enable-range=${this._enableRange}
|
||||
@change=${this.#onChange}
|
||||
?readonly=${this.readonly}>
|
||||
?readonly=${this.readonly}
|
||||
?required=${this.mandatory}
|
||||
.requiredMessage=${this.mandatoryMessage}>
|
||||
</umb-input-slider>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ export class UmbPropertyEditorUIToggleElement
|
||||
}
|
||||
|
||||
#onChange(event: CustomEvent & { target: UmbInputToggleElement }) {
|
||||
const checked = event.target.checked;
|
||||
this.value = this.mandatory ? (checked ?? null) : checked;
|
||||
//checked is never null/undefined
|
||||
this.value = event.target.checked;
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,14 @@ export class UmbTagsInputElement extends UUIFormControlMixin(UmbLitElement, '')
|
||||
|
||||
@property({ type: String })
|
||||
culture?: string | null;
|
||||
@property({ type: Boolean })
|
||||
override required = false;
|
||||
@property({ type: String })
|
||||
override requiredMessage = 'This field is required';
|
||||
|
||||
@property({ type: Array })
|
||||
public set items(newTags: string[]) {
|
||||
const newItems = newTags.filter((x) => x !== '');
|
||||
const newItems = newTags?.filter((x) => x !== '') || [];
|
||||
this.#items = newItems;
|
||||
super.value = this.#items.join(',');
|
||||
}
|
||||
|
||||
@@ -9,20 +9,22 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
import '../../components/tags-input/tags-input.element.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-tags
|
||||
*/
|
||||
@customElement('umb-property-editor-ui-tags')
|
||||
export class UmbPropertyEditorUITagsElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||
private _value: Array<string> = [];
|
||||
|
||||
export class UmbPropertyEditorUITagsElement
|
||||
extends UmbFormControlMixin<Array<string>, typeof UmbLitElement, undefined>(UmbLitElement, undefined)
|
||||
implements UmbPropertyEditorUiElement
|
||||
{
|
||||
@property({ type: Array })
|
||||
public set value(value: Array<string>) {
|
||||
this._value = value || [];
|
||||
public override set value(value: Array<string>) {
|
||||
super.value = value || [];
|
||||
}
|
||||
public get value(): Array<string> {
|
||||
return this._value;
|
||||
public override get value(): Array<string> {
|
||||
return super.value as string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,6 +35,10 @@ export class UmbPropertyEditorUITagsElement extends UmbLitElement implements Umb
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
readonly = false;
|
||||
@property({ type: Boolean })
|
||||
mandatory?: boolean;
|
||||
@property({ type: String })
|
||||
mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY;
|
||||
|
||||
@state()
|
||||
private _group?: string;
|
||||
@@ -61,6 +67,10 @@ export class UmbPropertyEditorUITagsElement extends UmbLitElement implements Umb
|
||||
});
|
||||
}
|
||||
|
||||
protected override firstUpdated() {
|
||||
this.addFormControlElement(this.shadowRoot!.querySelector('umb-tags-input')!);
|
||||
}
|
||||
|
||||
#onChange(event: CustomEvent) {
|
||||
this.value = ((event.target as UmbTagsInputElement).value as string).split(',');
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
@@ -72,6 +82,8 @@ export class UmbPropertyEditorUITagsElement extends UmbLitElement implements Umb
|
||||
.culture=${this._culture}
|
||||
.items=${this.value}
|
||||
@change=${this.#onChange}
|
||||
?required=${!!this.mandatory}
|
||||
.requiredMessage=${this.mandatoryMessage}
|
||||
?readonly=${this.readonly}></umb-tags-input>`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user