Skip to content

Commit 8434c7d

Browse files
Icon Picker: Fix empty selection allowed on mandatory fields and add validation. (#20536)
* Not show the empty tile when filtering is active. * Added mandatory property to the icon picker. * Avoid deselecting the icon on second click when not showing the empty option. * Extends the form control mixin to the icon picker. * Used super.value. * Support mandatory from settings config. * Removed mandatoryConf. * remove requestUpdate --------- Co-authored-by: Niels Lyngsø <[email protected]>
1 parent 3854b2b commit 8434c7d

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-picker-modal/icon-picker-modal.element.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
3030
@state()
3131
private _colorList = umbracoColors.filter((color) => !color.legacy);
3232

33+
@state()
34+
private _isSearching = false;
35+
3336
constructor() {
3437
super();
3538
this.consumeContext(UMB_ICON_REGISTRY_CONTEXT, (context) => {
@@ -44,8 +47,10 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
4447
if (!this.#icons) return;
4548
const value = this._searchInput?.value;
4649
if (value) {
50+
this._isSearching = value.length > 0;
4751
this._iconsFiltered = this.#icons.filter((icon) => icon.name.toLowerCase().includes(value.toLowerCase()));
4852
} else {
53+
this._isSearching = false;
4954
this._iconsFiltered = this.#icons;
5055
}
5156
}
@@ -54,8 +59,12 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
5459
const isActivate = e.type === 'click' || (e.type === 'keyup' && (e as KeyboardEvent).key === 'Enter');
5560
if (!isActivate) return;
5661

57-
const nextIcon = this.value.icon === iconName ? '' : iconName;
58-
this.modalContext?.updateValue({ icon: nextIcon });
62+
if (this.data?.showEmptyOption) {
63+
const nextIcon = this.value.icon === iconName ? '' : iconName;
64+
this.modalContext?.updateValue({ icon: nextIcon });
65+
} else {
66+
this.modalContext?.updateValue({ icon: iconName });
67+
}
5968
}
6069

6170
#onColorChange(e: UUIColorSwatchesEvent) {
@@ -93,16 +102,21 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
93102
</uui-color-swatches>
94103
<hr />
95104
<uui-scroll-container id="icons">
96-
<uui-button
97-
class=${!this.value.icon ? 'selected' : ''}
98-
label=${this.localize.term('defaultdialogs_noIcon')}
99-
title=${this.localize.term('defaultdialogs_noIcon')}
100-
@click=${this.#clearIcon}
101-
@keyup=${(e: KeyboardEvent) => {
102-
if (e.key === 'Enter' || e.key === ' ') this.#clearIcon();
103-
}}>
104-
<uui-icon style="opacity:.35" name=${ifDefined(this.data?.placeholder)}></uui-icon> </uui-button
105-
>${this.renderIcons()}</uui-scroll-container
105+
${this.data?.showEmptyOption && !this._isSearching
106+
? html`
107+
<uui-button
108+
class=${!this.value.icon ? 'selected' : ''}
109+
label=${this.localize.term('defaultdialogs_noIcon')}
110+
title=${this.localize.term('defaultdialogs_noIcon')}
111+
@click=${this.#clearIcon}
112+
@keyup=${(e: KeyboardEvent) => {
113+
if (e.key === 'Enter' || e.key === ' ') this.#clearIcon();
114+
}}>
115+
<uui-icon style="opacity:.35" name=${ifDefined(this.data?.placeholder)}></uui-icon>
116+
</uui-button>
117+
`
118+
: nothing}
119+
${this.renderIcons()}</uui-scroll-container
106120
>
107121
</div>
108122
<uui-button

src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-picker-modal/icon-picker-modal.token.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
22

33
export interface UmbIconPickerModalData {
44
placeholder?: string;
5+
showEmptyOption?: boolean;
56
}
67

78
export interface UmbIconPickerModalValue {

src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/property-editor-ui-icon-picker.element.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,45 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
99
import { extractUmbColorVariable } from '@umbraco-cms/backoffice/resources';
1010
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
1111

12+
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
13+
1214
/**
1315
* @element umb-property-editor-ui-icon-picker
1416
*/
1517
@customElement('umb-property-editor-ui-icon-picker')
16-
export class UmbPropertyEditorUIIconPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
17-
//
18+
export class UmbPropertyEditorUIIconPickerElement
19+
extends UmbFormControlMixin<string, typeof UmbLitElement, undefined>(UmbLitElement, undefined)
20+
implements UmbPropertyEditorUiElement
21+
{
22+
@property({ type: Boolean })
23+
mandatory = false;
24+
25+
protected override firstUpdated(): void {
26+
this.addValidator(
27+
'valueMissing',
28+
() => 'Icon is required',
29+
() => this.mandatory && !this._icon,
30+
);
31+
}
32+
1833
@property()
19-
public set value(v: string) {
20-
this._value = v ?? '';
21-
const parts = this._value.split(' ');
34+
public override set value(v: string) {
35+
const val = v ?? '';
36+
super.value = val;
37+
38+
const parts = val.split(' ');
2239
if (parts.length === 2) {
2340
this._icon = parts[0];
2441
this._color = parts[1].replace('color-', '');
2542
} else {
26-
this._icon = this._value;
43+
this._icon = val;
2744
this._color = '';
2845
}
2946
}
30-
public get value() {
31-
return this._value;
47+
48+
public override get value() {
49+
return (super.value as string) ?? '';
3250
}
33-
private _value = '';
3451

3552
@state()
3653
private _icon = '';
@@ -53,7 +70,7 @@ export class UmbPropertyEditorUIIconPickerElement extends UmbLitElement implemen
5370
icon: this._icon,
5471
color: this._color,
5572
},
56-
data: { placeholder: this._placeholderIcon },
73+
data: { placeholder: this._placeholderIcon, showEmptyOption: !this.mandatory },
5774
}).catch(() => undefined);
5875

5976
if (!data) return;

0 commit comments

Comments
 (0)