@nexterajs/ui 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +279 -34
  2. package/fesm2022/nexterajs-ui-charts.mjs +1096 -0
  3. package/fesm2022/nexterajs-ui-charts.mjs.map +1 -0
  4. package/fesm2022/nexterajs-ui-core.mjs +652 -12
  5. package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
  6. package/fesm2022/nexterajs-ui-display.mjs +1142 -0
  7. package/fesm2022/nexterajs-ui-display.mjs.map +1 -0
  8. package/fesm2022/nexterajs-ui-dropdowns.mjs +321 -33
  9. package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
  10. package/fesm2022/nexterajs-ui-file-uploader.mjs +572 -10
  11. package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
  12. package/fesm2022/nexterajs-ui-forms.mjs +2027 -136
  13. package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
  14. package/fesm2022/nexterajs-ui-grid.mjs +1222 -188
  15. package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
  16. package/fesm2022/nexterajs-ui-intl.mjs +103 -11
  17. package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
  18. package/fesm2022/nexterajs-ui-navigation.mjs +1054 -0
  19. package/fesm2022/nexterajs-ui-navigation.mjs.map +1 -0
  20. package/fesm2022/nexterajs-ui-notify.mjs +46 -44
  21. package/fesm2022/nexterajs-ui-notify.mjs.map +1 -1
  22. package/fesm2022/nexterajs-ui-overlay.mjs +1671 -0
  23. package/fesm2022/nexterajs-ui-overlay.mjs.map +1 -0
  24. package/fesm2022/nexterajs-ui-pivot.mjs +51 -26
  25. package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
  26. package/fesm2022/nexterajs-ui-shell.mjs +542 -0
  27. package/fesm2022/nexterajs-ui-shell.mjs.map +1 -0
  28. package/fesm2022/nexterajs-ui-tree-view.mjs +5 -2
  29. package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
  30. package/fesm2022/nexterajs-ui-validation.mjs +42 -11
  31. package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
  32. package/fesm2022/nexterajs-ui.mjs +5 -0
  33. package/fesm2022/nexterajs-ui.mjs.map +1 -1
  34. package/package.json +33 -2
  35. package/styles/_dropdown.scss +5 -5
  36. package/styles/_editor.scss +52 -17
  37. package/styles/_mixins.scss +1 -1
  38. package/styles/_scrollbar.scss +5 -5
  39. package/styles/_status.scss +21 -0
  40. package/styles/_toast.scss +14 -14
  41. package/styles/_tokens.scss +420 -3
  42. package/styles/_widget.scss +14 -3
  43. package/styles/index.scss +6 -4
  44. package/types/nexterajs-ui-charts.d.ts +446 -0
  45. package/types/nexterajs-ui-core.d.ts +387 -22
  46. package/types/nexterajs-ui-display.d.ts +720 -0
  47. package/types/nexterajs-ui-dropdowns.d.ts +191 -48
  48. package/types/nexterajs-ui-file-uploader.d.ts +236 -7
  49. package/types/nexterajs-ui-forms.d.ts +675 -30
  50. package/types/nexterajs-ui-grid.d.ts +448 -93
  51. package/types/nexterajs-ui-intl.d.ts +39 -4
  52. package/types/nexterajs-ui-navigation.d.ts +531 -0
  53. package/types/nexterajs-ui-notify.d.ts +4 -2
  54. package/types/nexterajs-ui-overlay.d.ts +703 -0
  55. package/types/nexterajs-ui-pivot.d.ts +56 -48
  56. package/types/nexterajs-ui-shell.d.ts +294 -0
  57. package/types/nexterajs-ui-tree-view.d.ts +6 -3
  58. package/types/nexterajs-ui-validation.d.ts +20 -11
  59. package/types/nexterajs-ui.d.ts +5 -0
@@ -2,12 +2,156 @@ import { Overlay } from '@angular/cdk/overlay';
2
2
  import { TemplatePortal } from '@angular/cdk/portal';
3
3
  import { NgTemplateOutlet } from '@angular/common';
4
4
  import * as i0 from '@angular/core';
5
- import { inject, ViewContainerRef, viewChild, contentChildren, input, computed, booleanAttribute, output, signal, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component, contentChild, model, Injector, InjectionToken, ElementRef, TemplateRef, Directive } from '@angular/core';
5
+ import { signal, inject, DestroyRef, ViewContainerRef, viewChild, contentChildren, input, computed, numberAttribute, booleanAttribute, output, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component, contentChild, model, Injector, InjectionToken, ElementRef, TemplateRef, Directive } from '@angular/core';
6
6
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
7
- import { merge, filter, distinctUntilChanged, Subject } from 'rxjs';
7
+ import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
8
+ import { Subject, switchMap, timer, map, firstValueFrom, from, filter, catchError, EMPTY, merge, mergeMap, distinctUntilChanged } from 'rxjs';
8
9
  import { NxeFormControlBase, NxeTemplateDirective, nxeOptionalBoolean, nxeResolveText, nxeResolveExpr, NXE_VALIDATION_TARGET } from '@nexterajs/ui/core';
9
10
  import { nxePane, trackPaneFlip } from '@nexterajs/ui/styling';
10
- import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
11
+
12
+ /** True for a store object (anything with a `load` function that is not an array). */
13
+ function nxeIsPickerStore(value) {
14
+ return (!!value &&
15
+ typeof value === 'object' &&
16
+ !Array.isArray(value) &&
17
+ typeof value.load === 'function');
18
+ }
19
+ /**
20
+ * The search plumbing shared by the pickers: debounces typing by `searchTimeout`, emits
21
+ * `searchChange` once the text reaches `minSearchLength` (or is cleared), and, when the
22
+ * `dataSource` is a {@link NxePickerStore}, queries it and keeps only the newest response.
23
+ * Must be created in an injection context. It uses no `effect()`: it reacts only to the explicit
24
+ * {@link typed}, {@link open} and {@link loadMore} calls.
25
+ */
26
+ class NxePickerSearch {
27
+ cfg;
28
+ /** Rows of the store loaded so far (all pages of the current query). */
29
+ items = signal([], /* @ts-ignore */
30
+ ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
31
+ loading = signal(false, /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
33
+ error = signal(null, /* @ts-ignore */
34
+ ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
35
+ hasMore = signal(false, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "hasMore" }] : /* istanbul ignore next */ []));
37
+ typedText = new Subject();
38
+ loadedFor = null;
39
+ seq = 0;
40
+ controller = null;
41
+ constructor(cfg) {
42
+ this.cfg = cfg;
43
+ const destroyRef = inject(DestroyRef);
44
+ this.typedText
45
+ .pipe(switchMap((text) => timer(Math.max(0, cfg.searchTimeout())).pipe(map(() => text))), takeUntilDestroyed(destroyRef))
46
+ .subscribe((text) => this.settled(text));
47
+ destroyRef.onDestroy(() => this.controller?.abort());
48
+ }
49
+ get hasStore() {
50
+ return this.cfg.store() !== null;
51
+ }
52
+ /** True when `text` is long enough to be searched. */
53
+ reachesMinimum(text) {
54
+ return text.length >= this.cfg.minSearchLength();
55
+ }
56
+ /** The user typed; the search settles after `searchTimeout`. */
57
+ typed(text) {
58
+ this.typedText.next(text);
59
+ }
60
+ /** The panel opened with `text` in the field: load the first page unless that query is current. */
61
+ open(text) {
62
+ if (this.hasStore && this.loadedFor !== this.effective(text)) {
63
+ this.query(text);
64
+ }
65
+ }
66
+ /** Loads the next page of the current query (a scroll-to-bottom handler calls this). */
67
+ loadMore() {
68
+ if (this.hasStore && this.hasMore() && !this.loading()) {
69
+ void this.run(this.loadedFor ?? '', true);
70
+ }
71
+ }
72
+ /** Fetches one row by key through `byKey`; `null` when the store cannot or does not know it. */
73
+ async lookup(key) {
74
+ const store = this.cfg.store();
75
+ if (!store?.byKey) {
76
+ return null;
77
+ }
78
+ const controller = new AbortController();
79
+ try {
80
+ return (await firstValueFrom(from(store.byKey(key, { signal: controller.signal })))) ?? null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ settled(text) {
87
+ if (text === '' || this.reachesMinimum(text)) {
88
+ this.cfg.searchChange({ searchValue: text });
89
+ }
90
+ if (this.hasStore) {
91
+ this.query(text);
92
+ }
93
+ }
94
+ /** The text actually sent to the store: below the minimum nothing is searched. */
95
+ effective(text) {
96
+ if (this.reachesMinimum(text)) {
97
+ return text;
98
+ }
99
+ return this.cfg.showDataBeforeSearch() ? '' : null;
100
+ }
101
+ query(text) {
102
+ const effective = this.effective(text);
103
+ if (effective === null) {
104
+ this.cancel();
105
+ this.items.set([]);
106
+ this.hasMore.set(false);
107
+ this.loadedFor = null;
108
+ this.cfg.loaded?.();
109
+ return;
110
+ }
111
+ void this.run(effective, false);
112
+ }
113
+ cancel() {
114
+ this.seq++;
115
+ this.controller?.abort();
116
+ this.controller = null;
117
+ this.loading.set(false);
118
+ }
119
+ async run(text, append) {
120
+ const store = this.cfg.store();
121
+ if (!store) {
122
+ return;
123
+ }
124
+ this.cancel();
125
+ const seq = this.seq;
126
+ const controller = new AbortController();
127
+ this.controller = controller;
128
+ this.loading.set(true);
129
+ this.error.set(null);
130
+ const take = Math.max(1, this.cfg.pageSize());
131
+ const skip = append ? this.items().length : 0;
132
+ try {
133
+ const raw = await firstValueFrom(from(store.load({ searchValue: text, searchExpr: this.cfg.searchExpr(), searchOperation: 'contains', skip, take }, { signal: controller.signal })));
134
+ if (seq !== this.seq) {
135
+ return;
136
+ }
137
+ const data = Array.isArray(raw) ? raw : (raw.data ?? []);
138
+ const total = Array.isArray(raw) ? undefined : raw.totalCount;
139
+ const next = append ? [...this.items(), ...data] : data;
140
+ this.items.set(next);
141
+ this.hasMore.set(total !== undefined ? next.length < total : data.length >= take);
142
+ this.loadedFor = text;
143
+ this.loading.set(false);
144
+ this.cfg.loaded?.();
145
+ }
146
+ catch (error) {
147
+ if (seq !== this.seq) {
148
+ return;
149
+ }
150
+ this.error.set(error);
151
+ this.loading.set(false);
152
+ }
153
+ }
154
+ }
11
155
 
12
156
  /**
13
157
  * `nxe-select-box` — drop-in replacement for DevExtreme `dx-select-box`.
@@ -29,7 +173,10 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
29
173
  ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
30
174
  templates = contentChildren(NxeTemplateDirective, /* @ts-ignore */
31
175
  ...(ngDevMode ? [{ debugName: "templates" }] : /* istanbul ignore next */ []));
32
- /** The source array (plain JS array of `Lov`-shaped objects, or primitives). */
176
+ /**
177
+ * The source: a plain array of `Lov`-shaped objects (or primitives), or an {@link NxePickerStore}
178
+ * whose `load({searchValue, skip, take})` the box calls itself (server-side search).
179
+ */
33
180
  dataSource = input([], /* @ts-ignore */
34
181
  ...(ngDevMode ? [{ debugName: "dataSource" }] : /* istanbul ignore next */ []));
35
182
  /** Field shown in the box/list (DevExtreme default `lovName`). Empty => the item itself. */
@@ -74,9 +221,29 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
74
221
  /** Named template ('inputField') for the closed field; `$implicit` = the selected item. */
75
222
  fieldTemplate = input(/* @ts-ignore */
76
223
  ...(ngDevMode ? [undefined, { debugName: "fieldTemplate" }] : /* istanbul ignore next */ []));
224
+ /** dx `searchTimeout`: ms of typing pause before `(searchChange)` fires or a store is queried. */
225
+ searchTimeout = input(500, { ...(ngDevMode ? { debugName: "searchTimeout" } : /* istanbul ignore next */ {}), transform: numberAttribute });
226
+ /** dx `minSearchLength`: characters needed before a search is emitted, applied or sent. */
227
+ minSearchLength = input(0, { ...(ngDevMode ? { debugName: "minSearchLength" } : /* istanbul ignore next */ {}), transform: numberAttribute });
228
+ /** dx `showDataBeforeSearch`: list rows while the text is shorter than `minSearchLength`. */
229
+ showDataBeforeSearch = input(false, { ...(ngDevMode ? { debugName: "showDataBeforeSearch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
230
+ /** Rows requested per page from a store `dataSource` (`take`); more load on scroll to the end. */
231
+ pageSize = input(20, { ...(ngDevMode ? { debugName: "pageSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
232
+ /**
233
+ * dx `displayValue`: the text shown for the current value while its row is not among the loaded
234
+ * ones (a store `dataSource` with the selection outside the current page, and no `byKey`).
235
+ */
236
+ displayValue = input(undefined, /* @ts-ignore */
237
+ ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
77
238
  /** DevExtreme parity, cosmetic. */
78
239
  hoverStateEnabled = input(true, { ...(ngDevMode ? { debugName: "hoverStateEnabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
79
240
  onSelectionChanged = output();
241
+ /**
242
+ * The search text settled: fires `searchTimeout` ms after the last keystroke, once the text has
243
+ * `minSearchLength` characters (or was cleared). Use it to query a server and replace
244
+ * `[dataSource]`, or pass a {@link NxePickerStore} and let the box query for you.
245
+ */
246
+ searchChange = output();
80
247
  focused = signal(false, /* @ts-ignore */
81
248
  ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
82
249
  open = signal(false, /* @ts-ignore */
@@ -95,8 +262,39 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
95
262
  overlayRef;
96
263
  closeSub;
97
264
  flipSub;
98
- items = computed(() => this.dataSource() ?? [], /* @ts-ignore */
265
+ store = computed(() => {
266
+ const ds = this.dataSource();
267
+ return nxeIsPickerStore(ds) ? ds : null;
268
+ }, /* @ts-ignore */
269
+ ...(ngDevMode ? [{ debugName: "store" }] : /* istanbul ignore next */ []));
270
+ search = new NxePickerSearch({
271
+ store: this.store,
272
+ searchExpr: this.searchExpr,
273
+ searchTimeout: this.searchTimeout,
274
+ minSearchLength: this.minSearchLength,
275
+ showDataBeforeSearch: this.showDataBeforeSearch,
276
+ pageSize: this.pageSize,
277
+ searchChange: (event) => this.searchChange.emit(event),
278
+ loaded: () => this.activeIndex.set(this.filteredItems().length ? 0 : -1),
279
+ });
280
+ /** Rows picked or fetched by key from a store, so the label outlives the page that held them. */
281
+ resolved = signal(new Map(), /* @ts-ignore */
282
+ ...(ngDevMode ? [{ debugName: "resolved" }] : /* istanbul ignore next */ []));
283
+ items = computed(() => {
284
+ const ds = this.dataSource();
285
+ return nxeIsPickerStore(ds) ? this.search.items() : (ds ?? []);
286
+ }, /* @ts-ignore */
99
287
  ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
288
+ /** Fetches the row of an externally set value through `byKey` when no loaded row has it. */
289
+ keyLookup = toObservable(this.value)
290
+ .pipe(filter((v) => v != null && v !== '' && this.search.hasStore && this.findRow(v) === undefined), switchMap((v) => from(this.search.lookup(v)).pipe(catchError(() => EMPTY), filter((row) => row != null), map((row) => [v, row]))), takeUntilDestroyed())
291
+ .subscribe(([key, row]) => this.remember(key, row));
292
+ findRow(key) {
293
+ return this.items().find((it) => this.extractValue(it) === key) ?? this.resolved().get(key);
294
+ }
295
+ remember(key, row) {
296
+ this.resolved.update((m) => new Map(m).set(key, row));
297
+ }
100
298
  display(item) {
101
299
  return nxeResolveText(this.displayExpr(), item);
102
300
  }
@@ -108,7 +306,7 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
108
306
  if (v == null) {
109
307
  return null;
110
308
  }
111
- return this.items().find((it) => this.extractValue(it) === v) ?? null;
309
+ return this.findRow(v) ?? null;
112
310
  }, /* @ts-ignore */
113
311
  ...(ngDevMode ? [{ debugName: "selectedItem" }] : /* istanbul ignore next */ []));
114
312
  hasValue = computed(() => this.value() != null && this.value() !== '', /* @ts-ignore */
@@ -116,7 +314,10 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
116
314
  /** Display text when the field is not being searched. */
117
315
  displayText = computed(() => {
118
316
  const sel = this.selectedItem();
119
- return sel ? this.display(sel) : '';
317
+ if (sel) {
318
+ return this.display(sel);
319
+ }
320
+ return this.hasValue() ? (this.displayValue() ?? '') : '';
120
321
  }, /* @ts-ignore */
121
322
  ...(ngDevMode ? [{ debugName: "displayText" }] : /* istanbul ignore next */ []));
122
323
  /** Value bound to the input element. */
@@ -128,9 +329,15 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
128
329
  filteredItems = computed(() => {
129
330
  const items = this.items();
130
331
  const search = this.searchText();
131
- if (!this.searchEnabled() || !search) {
332
+ if (this.search.hasStore) {
132
333
  return items;
133
334
  }
335
+ if (!this.searchEnabled() || !search) {
336
+ return this.minSearchLength() > 0 && !this.showDataBeforeSearch() ? [] : items;
337
+ }
338
+ if (!this.search.reachesMinimum(search)) {
339
+ return this.showDataBeforeSearch() ? items : [];
340
+ }
134
341
  const expr = this.searchExpr();
135
342
  const needle = search.toLowerCase();
136
343
  return items.filter((it) => nxeResolveText(expr, it).toLowerCase().includes(needle));
@@ -163,12 +370,21 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
163
370
  this.openPanel();
164
371
  }
165
372
  onSearchInput(event) {
166
- this.searchText.set(event.target.value);
373
+ const text = event.target.value;
374
+ this.searchText.set(text);
375
+ this.search.typed(text);
167
376
  this.activeIndex.set(0);
168
377
  if (!this.open()) {
169
378
  this.openPanel();
170
379
  }
171
380
  }
381
+ /** Loads the next page of a store `dataSource` when the list is scrolled to its end. */
382
+ onPanelScroll(event) {
383
+ const el = event.target;
384
+ if (el.scrollTop + el.clientHeight >= el.scrollHeight - 8) {
385
+ this.search.loadMore();
386
+ }
387
+ }
172
388
  onBlur() {
173
389
  this.focused.set(false);
174
390
  this.markAsTouched();
@@ -179,6 +395,9 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
179
395
  event.preventDefault();
180
396
  const previousValue = this.value();
181
397
  const next = this.extractValue(item);
398
+ if (this.search.hasStore) {
399
+ this.remember(next, item);
400
+ }
182
401
  this.commitValue(next, event);
183
402
  this.onSelectionChanged.emit({ selectedItem: item, previousValue, value: next });
184
403
  this.searchText.set(null);
@@ -230,6 +449,7 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
230
449
  this.panelWidth.set(this.elementRef.nativeElement.offsetWidth);
231
450
  const idx = this.items().findIndex((it) => this.extractValue(it) === this.value());
232
451
  this.activeIndex.set(idx >= 0 ? idx : 0);
452
+ this.search.open(this.searchText() ?? '');
233
453
  if (!this.overlayRef) {
234
454
  this.overlayRef = this.overlay.create({
235
455
  positionStrategy: this.overlay
@@ -268,24 +488,24 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
268
488
  this.overlayRef?.dispose();
269
489
  }
270
490
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeSelectBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
271
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeSelectBoxComponent, isStandalone: true, selector: "nxe-select-box", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, displayExprInput: { classPropertyName: "displayExprInput", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, valueExprInput: { classPropertyName: "valueExprInput", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, searchExprInput: { classPropertyName: "searchExprInput", publicName: "searchExpr", isSignal: true, isRequired: false, transformFunction: null }, searchEnabledInput: { classPropertyName: "searchEnabledInput", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showDropDownButtonInput: { classPropertyName: "showDropDownButtonInput", publicName: "showDropDownButton", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, fieldTemplate: { classPropertyName: "fieldTemplate", publicName: "fieldTemplate", isSignal: true, isRequired: false, transformFunction: null }, hoverStateEnabled: { classPropertyName: "hoverStateEnabled", publicName: "hoverStateEnabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChanged: "onSelectionChanged" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-selectbox" }, providers: [
491
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeSelectBoxComponent, isStandalone: true, selector: "nxe-select-box", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, displayExprInput: { classPropertyName: "displayExprInput", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, valueExprInput: { classPropertyName: "valueExprInput", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, searchExprInput: { classPropertyName: "searchExprInput", publicName: "searchExpr", isSignal: true, isRequired: false, transformFunction: null }, searchEnabledInput: { classPropertyName: "searchEnabledInput", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showDropDownButtonInput: { classPropertyName: "showDropDownButtonInput", publicName: "showDropDownButton", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, fieldTemplate: { classPropertyName: "fieldTemplate", publicName: "fieldTemplate", isSignal: true, isRequired: false, transformFunction: null }, searchTimeout: { classPropertyName: "searchTimeout", publicName: "searchTimeout", isSignal: true, isRequired: false, transformFunction: null }, minSearchLength: { classPropertyName: "minSearchLength", publicName: "minSearchLength", isSignal: true, isRequired: false, transformFunction: null }, showDataBeforeSearch: { classPropertyName: "showDataBeforeSearch", publicName: "showDataBeforeSearch", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, displayValue: { classPropertyName: "displayValue", publicName: "displayValue", isSignal: true, isRequired: false, transformFunction: null }, hoverStateEnabled: { classPropertyName: "hoverStateEnabled", publicName: "hoverStateEnabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChanged: "onSelectionChanged", searchChange: "searchChange" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "invalidState()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-selectbox" }, providers: [
272
492
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeSelectBoxComponent), multi: true },
273
493
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeSelectBoxComponent) },
274
- ], queries: [{ propertyName: "templates", predicate: NxeTemplateDirective, isSignal: true }], viewQueries: [{ propertyName: "dropdownTemplate", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }, { propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\r\n @if (fieldTemplateRef(); as tpl) {\r\n <div class=\"nxe-select-field\">\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: selectedItem() }\" />\r\n </div>\r\n } @else {\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-select-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"open()\"\r\n [attr.aria-controls]=\"open() ? panelId() : null\"\r\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n [value]=\"inputDisplay()\"\r\n [readOnly]=\"readOnly() || !searchEnabled()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"placeholder() || null\"\r\n autocomplete=\"off\"\r\n (input)=\"onSearchInput($event)\"\r\n (focus)=\"focused.set(true)\"\r\n (blur)=\"onBlur()\" />\r\n }\r\n\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n\r\n @if (showDropDownButton() && !readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <!-- An 8x4 triangle centred in the 18px box. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #dropdown>\r\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\r\n [id]=\"panelId()\"\r\n role=\"listbox\">\r\n @for (item of filteredItems(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-active]=\"i === activeIndex()\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n @if (itemTemplateRef(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\r\n } @else {\r\n {{ display(item) }}\r\n }\r\n </div>\r\n } @empty {\r\n <div class=\"nxe-list-empty\">No data to display</div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-select-box{cursor:pointer}nxe-select-box .nxe-select-input{cursor:pointer}nxe-select-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-select-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-select-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-select-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-select-box.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear),nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
494
+ ], queries: [{ propertyName: "templates", predicate: NxeTemplateDirective, isSignal: true }], viewQueries: [{ propertyName: "dropdownTemplate", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }, { propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\n @if (fieldTemplateRef(); as tpl) {\n <div class=\"nxe-select-field\">\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: selectedItem() }\" />\n </div>\n } @else {\n <input\n #input\n class=\"nxe-editor-input nxe-select-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId() : null\"\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n [value]=\"inputDisplay()\"\n [readOnly]=\"readOnly() || !searchEnabled()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || null\"\n autocomplete=\"off\"\n (input)=\"onSearchInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\" />\n }\n\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n\n @if (showDropDownButton() && !readOnly()) {\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\n <!-- An 8x4 triangle centred in the 18px box. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #dropdown>\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\n [id]=\"panelId()\"\n role=\"listbox\"\n (scroll)=\"onPanelScroll($event)\">\n @for (item of filteredItems(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(item)\"\n [class.nxe-list-item-selected]=\"isSelected(item)\"\n [class.nxe-list-item-active]=\"i === activeIndex()\"\n (mousedown)=\"selectItem(item, $event)\">\n @if (itemTemplateRef(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\n } @else {\n {{ display(item) }}\n }\n </div>\n } @empty {\n <div class=\"nxe-list-empty\">{{ nxeMessages.t('dropdown.noData') }}</div>\n }\n </div>\n</ng-template>\n", styles: ["nxe-select-box{cursor:pointer}nxe-select-box .nxe-select-input{cursor:pointer}nxe-select-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-select-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-select-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-select-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-select-box.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear),nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
275
495
  }
276
496
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeSelectBoxComponent, decorators: [{
277
497
  type: Component,
278
498
  args: [{ selector: 'nxe-select-box', standalone: true, imports: [NgTemplateOutlet], host: {
279
499
  class: 'nxe-widget nxe-editor nxe-selectbox',
280
500
  '[class.nxe-focused]': 'focused()',
281
- '[class.nxe-invalid]': '!!validationError()',
501
+ '[class.nxe-invalid]': 'invalidState()',
282
502
  '[class.nxe-open]': 'open()',
283
503
  '(keydown)': 'onKeydown($event)',
284
504
  }, providers: [
285
505
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeSelectBoxComponent), multi: true },
286
506
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeSelectBoxComponent) },
287
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\r\n @if (fieldTemplateRef(); as tpl) {\r\n <div class=\"nxe-select-field\">\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: selectedItem() }\" />\r\n </div>\r\n } @else {\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-select-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"open()\"\r\n [attr.aria-controls]=\"open() ? panelId() : null\"\r\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n [value]=\"inputDisplay()\"\r\n [readOnly]=\"readOnly() || !searchEnabled()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"placeholder() || null\"\r\n autocomplete=\"off\"\r\n (input)=\"onSearchInput($event)\"\r\n (focus)=\"focused.set(true)\"\r\n (blur)=\"onBlur()\" />\r\n }\r\n\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n\r\n @if (showDropDownButton() && !readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <!-- An 8x4 triangle centred in the 18px box. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #dropdown>\r\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\r\n [id]=\"panelId()\"\r\n role=\"listbox\">\r\n @for (item of filteredItems(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-active]=\"i === activeIndex()\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n @if (itemTemplateRef(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\r\n } @else {\r\n {{ display(item) }}\r\n }\r\n </div>\r\n } @empty {\r\n <div class=\"nxe-list-empty\">No data to display</div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-select-box{cursor:pointer}nxe-select-box .nxe-select-input{cursor:pointer}nxe-select-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-select-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-select-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-select-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-select-box.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear),nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}\n"] }]
288
- }], propDecorators: { dropdownTemplate: [{ type: i0.ViewChild, args: ['dropdown', { isSignal: true }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeTemplateDirective), { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], displayExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], valueExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueExpr", required: false }] }], searchExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchExpr", required: false }] }], searchEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showDropDownButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropDownButton", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], fieldTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldTemplate", required: false }] }], hoverStateEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverStateEnabled", required: false }] }], onSelectionChanged: [{ type: i0.Output, args: ["onSelectionChanged"] }] } });
507
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\n @if (fieldTemplateRef(); as tpl) {\n <div class=\"nxe-select-field\">\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: selectedItem() }\" />\n </div>\n } @else {\n <input\n #input\n class=\"nxe-editor-input nxe-select-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId() : null\"\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n [value]=\"inputDisplay()\"\n [readOnly]=\"readOnly() || !searchEnabled()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || null\"\n autocomplete=\"off\"\n (input)=\"onSearchInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\" />\n }\n\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n\n @if (showDropDownButton() && !readOnly()) {\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\n <!-- An 8x4 triangle centred in the 18px box. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #dropdown>\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\n [id]=\"panelId()\"\n role=\"listbox\"\n (scroll)=\"onPanelScroll($event)\">\n @for (item of filteredItems(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(item)\"\n [class.nxe-list-item-selected]=\"isSelected(item)\"\n [class.nxe-list-item-active]=\"i === activeIndex()\"\n (mousedown)=\"selectItem(item, $event)\">\n @if (itemTemplateRef(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\n } @else {\n {{ display(item) }}\n }\n </div>\n } @empty {\n <div class=\"nxe-list-empty\">{{ nxeMessages.t('dropdown.noData') }}</div>\n }\n </div>\n</ng-template>\n", styles: ["nxe-select-box{cursor:pointer}nxe-select-box .nxe-select-input{cursor:pointer}nxe-select-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-select-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-select-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-select-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-select-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-select-box.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear),nxe-select-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-select-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}\n"] }]
508
+ }], propDecorators: { dropdownTemplate: [{ type: i0.ViewChild, args: ['dropdown', { isSignal: true }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeTemplateDirective), { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], displayExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], valueExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueExpr", required: false }] }], searchExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchExpr", required: false }] }], searchEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showDropDownButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropDownButton", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], fieldTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldTemplate", required: false }] }], searchTimeout: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTimeout", required: false }] }], minSearchLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSearchLength", required: false }] }], showDataBeforeSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDataBeforeSearch", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], displayValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayValue", required: false }] }], hoverStateEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverStateEnabled", required: false }] }], onSelectionChanged: [{ type: i0.Output, args: ["onSelectionChanged"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }] } });
289
509
 
290
510
  /**
291
511
  * `nxe-tag-box` — drop-in replacement for DevExtreme `dx-tag-box` (multi-select sibling of
@@ -303,6 +523,7 @@ class NxeTagBoxComponent extends NxeFormControlBase {
303
523
  ...(ngDevMode ? [{ debugName: "dropdownTemplate" }] : /* istanbul ignore next */ []));
304
524
  inputEl = viewChild('input', /* @ts-ignore */
305
525
  ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
526
+ /** A plain array, or an {@link NxePickerStore} the box queries itself (server-side search). */
306
527
  dataSource = input([], /* @ts-ignore */
307
528
  ...(ngDevMode ? [{ debugName: "dataSource" }] : /* istanbul ignore next */ []));
308
529
  displayExprInput = input(undefined, { ...(ngDevMode ? { debugName: "displayExprInput" } : /* istanbul ignore next */ {}), alias: 'displayExpr' });
@@ -341,7 +562,7 @@ class NxeTagBoxComponent extends NxeFormControlBase {
341
562
  showSelectionControls = computed(() => this.showSelectionControlsInput() ?? this.nxeDefaults.tagBox?.showSelectionControls ?? true, /* @ts-ignore */
342
563
  ...(ngDevMode ? [{ debugName: "showSelectionControls" }] : /* istanbul ignore next */ []));
343
564
  /** dx `selectAllText` — the label of the "Select All" row (dx: `dxList-selectAll`). */
344
- selectAllText = input('Select All', /* @ts-ignore */
565
+ selectAllText = input(undefined, /* @ts-ignore */
345
566
  ...(ngDevMode ? [{ debugName: "selectAllText" }] : /* istanbul ignore next */ []));
346
567
  /** dx parity: dx-tag-box does NOT show a drop-down arrow unless showDropDownButton is set. */
347
568
  showDropDownButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showDropDownButtonInput" } : /* istanbul ignore next */ {}), alias: 'showDropDownButton', transform: nxeOptionalBoolean });
@@ -350,6 +571,16 @@ class NxeTagBoxComponent extends NxeFormControlBase {
350
571
  placeholderInput = input(undefined, { ...(ngDevMode ? { debugName: "placeholderInput" } : /* istanbul ignore next */ {}), alias: 'placeholder' });
351
572
  placeholder = computed(() => this.placeholderInput() ?? this.nxeDefaults.tagBox?.placeholder ?? '', /* @ts-ignore */
352
573
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
574
+ /** dx `searchTimeout`: ms of typing pause before `(searchChange)` fires or a store is queried. */
575
+ searchTimeout = input(500, { ...(ngDevMode ? { debugName: "searchTimeout" } : /* istanbul ignore next */ {}), transform: numberAttribute });
576
+ /** dx `minSearchLength`: characters needed before a search is emitted, applied or sent. */
577
+ minSearchLength = input(0, { ...(ngDevMode ? { debugName: "minSearchLength" } : /* istanbul ignore next */ {}), transform: numberAttribute });
578
+ /** dx `showDataBeforeSearch`: list rows while the text is shorter than `minSearchLength`. */
579
+ showDataBeforeSearch = input(false, { ...(ngDevMode ? { debugName: "showDataBeforeSearch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
580
+ /** Rows requested per page from a store `dataSource` (`take`); more load on scroll to the end. */
581
+ pageSize = input(20, { ...(ngDevMode ? { debugName: "pageSize" } : /* istanbul ignore next */ {}), transform: numberAttribute });
582
+ /** The search text settled (after `searchTimeout`, once it has `minSearchLength` characters or was cleared). */
583
+ searchChange = output();
353
584
  focused = signal(false, /* @ts-ignore */
354
585
  ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
355
586
  open = signal(false, /* @ts-ignore */
@@ -361,8 +592,38 @@ class NxeTagBoxComponent extends NxeFormControlBase {
361
592
  overlayRef;
362
593
  closeSub;
363
594
  flipSub;
364
- items = computed(() => this.dataSource() ?? [], /* @ts-ignore */
595
+ store = computed(() => {
596
+ const ds = this.dataSource();
597
+ return nxeIsPickerStore(ds) ? ds : null;
598
+ }, /* @ts-ignore */
599
+ ...(ngDevMode ? [{ debugName: "store" }] : /* istanbul ignore next */ []));
600
+ search = new NxePickerSearch({
601
+ store: this.store,
602
+ searchExpr: this.searchExpr,
603
+ searchTimeout: this.searchTimeout,
604
+ minSearchLength: this.minSearchLength,
605
+ showDataBeforeSearch: this.showDataBeforeSearch,
606
+ pageSize: this.pageSize,
607
+ searchChange: (event) => this.searchChange.emit(event),
608
+ });
609
+ /** Rows picked or fetched by key from a store, so a chip keeps its label off the loaded page. */
610
+ resolved = signal(new Map(), /* @ts-ignore */
611
+ ...(ngDevMode ? [{ debugName: "resolved" }] : /* istanbul ignore next */ []));
612
+ items = computed(() => {
613
+ const ds = this.dataSource();
614
+ return nxeIsPickerStore(ds) ? this.search.items() : (ds ?? []);
615
+ }, /* @ts-ignore */
365
616
  ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
617
+ /** Fetches, through `byKey`, the rows of externally set keys that no loaded row has. */
618
+ keyLookup = toObservable(this.value)
619
+ .pipe(mergeMap((v) => (Array.isArray(v) && this.search.hasStore ? v : [])), filter((key) => this.findRow(key) === undefined), mergeMap((key) => from(this.search.lookup(key)).pipe(catchError(() => EMPTY), filter((row) => row != null), map((row) => [key, row]))), takeUntilDestroyed())
620
+ .subscribe(([key, row]) => this.remember(key, row));
621
+ findRow(key) {
622
+ return this.items().find((it) => this.extractValue(it) === key) ?? this.resolved().get(key);
623
+ }
624
+ remember(key, row) {
625
+ this.resolved.update((m) => new Map(m).set(key, row));
626
+ }
366
627
  /** The selected keys (always an array). */
367
628
  selectedKeys = computed(() => {
368
629
  const v = this.value();
@@ -378,7 +639,7 @@ class NxeTagBoxComponent extends NxeFormControlBase {
378
639
  /** Selected items resolved from the value keys (for chip rendering). */
379
640
  selectedItems = computed(() => {
380
641
  const keys = this.selectedKeys();
381
- return keys.map((k) => this.items().find((it) => this.extractValue(it) === k) ?? k);
642
+ return keys.map((k) => this.findRow(k) ?? k);
382
643
  }, /* @ts-ignore */
383
644
  ...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
384
645
  hasValue = computed(() => this.selectedKeys().length > 0, /* @ts-ignore */
@@ -386,9 +647,15 @@ class NxeTagBoxComponent extends NxeFormControlBase {
386
647
  filteredItems = computed(() => {
387
648
  const items = this.items();
388
649
  const search = this.searchText();
389
- if (!this.searchEnabled() || !search) {
650
+ if (this.search.hasStore) {
390
651
  return items;
391
652
  }
653
+ if (!this.searchEnabled() || !search) {
654
+ return this.minSearchLength() > 0 && !this.showDataBeforeSearch() ? [] : items;
655
+ }
656
+ if (!this.search.reachesMinimum(search)) {
657
+ return this.showDataBeforeSearch() ? items : [];
658
+ }
392
659
  const expr = this.searchExpr();
393
660
  const needle = search.toLowerCase();
394
661
  return items.filter((it) => nxeResolveText(expr, it).toLowerCase().includes(needle));
@@ -426,11 +693,20 @@ class NxeTagBoxComponent extends NxeFormControlBase {
426
693
  this.inputEl()?.nativeElement?.focus();
427
694
  }
428
695
  onSearchInput(event) {
429
- this.searchText.set(event.target.value);
696
+ const text = event.target.value;
697
+ this.searchText.set(text);
698
+ this.search.typed(text);
430
699
  if (!this.open()) {
431
700
  this.openPanel();
432
701
  }
433
702
  }
703
+ /** Loads the next page of a store `dataSource` when the list is scrolled to its end. */
704
+ onPanelScroll(event) {
705
+ const el = event.target;
706
+ if (el.scrollTop + el.clientHeight >= el.scrollHeight - 8) {
707
+ this.search.loadMore();
708
+ }
709
+ }
434
710
  onBlur() {
435
711
  this.focused.set(false);
436
712
  this.markAsTouched();
@@ -440,7 +716,13 @@ class NxeTagBoxComponent extends NxeFormControlBase {
440
716
  const key = this.extractValue(item);
441
717
  const keys = this.selectedKeys();
442
718
  const next = keys.includes(key) ? keys.filter((k) => k !== key) : [...keys, key];
719
+ if (this.search.hasStore) {
720
+ this.remember(key, item);
721
+ }
443
722
  this.commitValue(next, event);
723
+ if (this.searchText()) {
724
+ this.search.typed('');
725
+ }
444
726
  this.searchText.set('');
445
727
  const input = this.inputEl()?.nativeElement;
446
728
  if (input) {
@@ -454,6 +736,11 @@ class NxeTagBoxComponent extends NxeFormControlBase {
454
736
  toggleAll(event) {
455
737
  event.preventDefault();
456
738
  const listed = this.filteredItems().map((it) => this.extractValue(it));
739
+ if (this.search.hasStore) {
740
+ for (const it of this.filteredItems()) {
741
+ this.remember(this.extractValue(it), it);
742
+ }
743
+ }
457
744
  const keys = this.selectedKeys();
458
745
  const next = this.selectAllState() === true
459
746
  ? keys.filter((k) => !listed.includes(k))
@@ -502,6 +789,7 @@ class NxeTagBoxComponent extends NxeFormControlBase {
502
789
  if (this.overlayRef.hasAttached()) {
503
790
  return;
504
791
  }
792
+ this.search.open(this.searchText());
505
793
  this.overlayRef.attach(new TemplatePortal(this.dropdownTemplate(), this.viewContainerRef));
506
794
  this.closeSub = merge(this.overlayRef.backdropClick(), this.overlayRef.keydownEvents().pipe(filter((e) => e.key === 'Escape'))).subscribe(() => this.close());
507
795
  this.open.set(true);
@@ -522,24 +810,24 @@ class NxeTagBoxComponent extends NxeFormControlBase {
522
810
  this.overlayRef?.dispose();
523
811
  }
524
812
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTagBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
525
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeTagBoxComponent, isStandalone: true, selector: "nxe-tag-box", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, displayExprInput: { classPropertyName: "displayExprInput", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, valueExprInput: { classPropertyName: "valueExprInput", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, searchExprInput: { classPropertyName: "searchExprInput", publicName: "searchExpr", isSignal: true, isRequired: false, transformFunction: null }, searchEnabledInput: { classPropertyName: "searchEnabledInput", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showSelectionControlsInput: { classPropertyName: "showSelectionControlsInput", publicName: "showSelectionControls", isSignal: true, isRequired: false, transformFunction: null }, selectAllText: { classPropertyName: "selectAllText", publicName: "selectAllText", isSignal: true, isRequired: false, transformFunction: null }, showDropDownButtonInput: { classPropertyName: "showDropDownButtonInput", publicName: "showDropDownButton", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-tagbox" }, providers: [
813
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeTagBoxComponent, isStandalone: true, selector: "nxe-tag-box", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, displayExprInput: { classPropertyName: "displayExprInput", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, valueExprInput: { classPropertyName: "valueExprInput", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, searchExprInput: { classPropertyName: "searchExprInput", publicName: "searchExpr", isSignal: true, isRequired: false, transformFunction: null }, searchEnabledInput: { classPropertyName: "searchEnabledInput", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showSelectionControlsInput: { classPropertyName: "showSelectionControlsInput", publicName: "showSelectionControls", isSignal: true, isRequired: false, transformFunction: null }, selectAllText: { classPropertyName: "selectAllText", publicName: "selectAllText", isSignal: true, isRequired: false, transformFunction: null }, showDropDownButtonInput: { classPropertyName: "showDropDownButtonInput", publicName: "showDropDownButton", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, searchTimeout: { classPropertyName: "searchTimeout", publicName: "searchTimeout", isSignal: true, isRequired: false, transformFunction: null }, minSearchLength: { classPropertyName: "minSearchLength", publicName: "minSearchLength", isSignal: true, isRequired: false, transformFunction: null }, showDataBeforeSearch: { classPropertyName: "showDataBeforeSearch", publicName: "showDataBeforeSearch", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChange: "searchChange" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "invalidState()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-tagbox" }, providers: [
526
814
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeTagBoxComponent), multi: true },
527
815
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeTagBoxComponent) },
528
- ], viewQueries: [{ propertyName: "dropdownTemplate", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }, { propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!--\r\n Two columns, as dx-tag-box renders them: the wrapping tag container (dx turns\r\n `.dx-texteditor-input-container` into `.dx-tag-container`) and, beside it, the buttons \u2014 never\r\n inside it, so they cannot wrap onto a tag row and they centre on the whole editor height.\r\n-->\r\n<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\r\n <div class=\"nxe-tag-container\">\r\n @for (item of selectedItems(); track $index) {\r\n <span class=\"nxe-tag\">\r\n <span class=\"nxe-tag-text\">{{ display(item) }}</span>\r\n <!-- Rendered in every state, as dx does (m_tag_box.js appends it unconditionally);\r\n readOnly/disabled make it inert rather than removing it. -->\r\n <span class=\"nxe-tag-remove\" (mousedown)=\"removeTag(item, $event)\" aria-hidden=\"true\"></span>\r\n </span>\r\n }\r\n\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-tag-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"open()\"\r\n [attr.aria-controls]=\"open() ? panelId() : null\"\r\n\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n [readOnly]=\"readOnly() || !searchEnabled()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"selectedItems().length ? null : (placeholder() || null)\"\r\n autocomplete=\"off\"\r\n (input)=\"onSearchInput($event)\"\r\n (focus)=\"focused.set(true)\"\r\n (blur)=\"onBlur()\" />\r\n </div>\r\n\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n @if (showDropDownButton() && !readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <!-- An 8x4 triangle centred in the 18px box. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #dropdown>\r\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\r\n [id]=\"panelId()\"\r\n role=\"listbox\"\r\n aria-multiselectable=\"true\">\r\n @if (showSelectionControls()) {\r\n <!-- dx `selectionMode: 'all'`, which showSelectionControls switches on\r\n (m_tag_box.js _listConfig): a tri-state \"Select All\" over the rows shown. Hidden\r\n while the list is empty, as `.dx-empty-collection .dx-list-select-all` is. -->\r\n @if (filteredItems().length) {\r\n <div\r\n class=\"nxe-tag-select-all\"\r\n [id]=\"panelId() + '-select-all'\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"selectAllState() === true\"\r\n [attr.aria-checked]=\"selectAllState() === undefined ? 'mixed' : selectAllState()\"\r\n (mousedown)=\"toggleAll($event)\">\r\n <span\r\n class=\"nxe-tag-check\"\r\n [class.nxe-tag-checked]=\"selectAllState() === true\"\r\n [class.nxe-tag-indeterminate]=\"selectAllState() === undefined\"\r\n aria-hidden=\"true\"></span>\r\n <span class=\"nxe-tag-select-all-label\">{{ selectAllText() }}</span>\r\n </div>\r\n }\r\n @for (item of filteredItems(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item nxe-tag-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-selected]=\"isSelected(item)\"\r\n (mousedown)=\"toggle(item, $event)\">\r\n <span class=\"nxe-tag-check\" [class.nxe-tag-checked]=\"isSelected(item)\" aria-hidden=\"true\"></span>\r\n <span class=\"nxe-tag-item-text\">{{ display(item) }}</span>\r\n </div>\r\n } @empty {\r\n <div class=\"nxe-list-empty\">No data to display</div>\r\n }\r\n } @else {\r\n <!-- dx `selectionMode: 'multiple'`: plain rows, selection shown by the row fill. -->\r\n @for (item of filteredItems(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-selected]=\"isSelected(item)\"\r\n (mousedown)=\"toggle(item, $event)\">\r\n {{ display(item) }}\r\n </div>\r\n } @empty {\r\n <div class=\"nxe-list-empty\">No data to display</div>\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-tag-box{cursor:pointer}nxe-tag-box .nxe-tag-container{box-sizing:border-box;position:relative;display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:stretch;align-self:stretch;min-width:0;padding-bottom:4px}nxe-tag-box .nxe-tag-input{flex:1 1 60px;min-width:60px;width:auto;height:auto;min-height:30px;padding-bottom:4px}nxe-tag-box .nxe-tag-container:has(>.nxe-tag)>.nxe-tag-input{padding-inline-start:0;margin-inline-start:5px}nxe-tag-box.nxe-invalid>.nxe-editor-container:not(:has(>.nxe-select-clear,>.nxe-select-arrow))>.nxe-tag-container:not(:has(>.nxe-tag))>.nxe-tag-input{padding-inline-end:34px}nxe-tag-box .nxe-tag{box-sizing:border-box;position:relative;display:inline-flex;align-self:flex-start;justify-content:center;max-width:calc(100% - 5px);min-width:40px;margin-top:4px;margin-inline-start:4px;padding-block:3px 4px;padding-inline:6px 25px;background-color:#ddd;border-radius:2px;color:#333}nxe-tag-box .nxe-tag-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tag-box .nxe-tag-remove{position:absolute;inset-inline-end:0;top:0;width:25px;height:100%;cursor:pointer}nxe-tag-box .nxe-tag-remove:before,nxe-tag-box .nxe-tag-remove:after{position:absolute;top:50%;content:\"\";transform:rotate(45deg);inset-inline-end:9px;margin-top:-5px;width:3px;height:11px;background:#aaa}nxe-tag-box .nxe-tag-remove:after{inset-inline-end:5px;margin-top:-1px;width:11px;height:3px}nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:before,nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:after{background:#ddd}nxe-tag-box.nxe-disabled .nxe-tag,nxe-tag-box.nxe-disabled .nxe-tag-remove{cursor:default}nxe-tag-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-tag-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-tag-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-tag-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-tag-box.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear),nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-select-panel .nxe-list-item.nxe-tag-item{display:block;position:relative;padding-block:10px;padding-inline:41px 10px}.nxe-select-panel .nxe-list-item.nxe-tag-item:hover,.nxe-select-panel .nxe-list-item.nxe-tag-item:active,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected:hover:not(.nxe-list-item-active){background-color:transparent;color:var(--nxe-ui-text)}.nxe-tag-check{box-sizing:border-box;position:relative;display:block;width:22px;height:22px;border:1px solid var(--nxe-ui-border);border-radius:2px;background:var(--nxe-ui-surface)}.nxe-tag-check.nxe-tag-checked:after{content:\"\";position:absolute;box-sizing:border-box;top:5px;inset-inline-start:2.5px;width:15px;height:11px;background-color:var(--nxe-ui-accent);clip-path:polygon(0 5.586px,5.414px 11px,15px 1.414px,13.586px 0,5.414px 8.172px,1.414px 4.172px)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-checked:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-check.nxe-tag-indeterminate:after{content:\"\";position:absolute;box-sizing:border-box;top:50%;inset-inline-start:50%;width:12px;height:12px;margin-top:-6px;margin-inline-start:-6px;border-radius:2px;background-color:var(--nxe-ui-accent)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-indeterminate:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-item .nxe-tag-check{position:absolute;top:50%;inset-inline-start:10px;margin-top:-10px}.nxe-tag-item:hover .nxe-tag-check,.nxe-tag-select-all:hover .nxe-tag-check{border-color:var(--nxe-ui-checkbox-hover-border, #265a87)}.nxe-tag-select-all{box-sizing:border-box;padding-block:12px 11px;padding-inline:0;border-bottom:1px solid var(--nxe-ui-border);margin-bottom:3px;white-space:nowrap;cursor:pointer}.nxe-tag-select-all .nxe-tag-check{float:inline-start;margin-top:-1px;margin-bottom:-3px;margin-inline-start:10px}.nxe-tag-select-all-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:17px;padding:0 10px;margin-top:1px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
816
+ ], viewQueries: [{ propertyName: "dropdownTemplate", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }, { propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!--\n Two columns, as dx-tag-box renders them: the wrapping tag container (dx turns\n `.dx-texteditor-input-container` into `.dx-tag-container`) and, beside it, the buttons \u2014 never\n inside it, so they cannot wrap onto a tag row and they centre on the whole editor height.\n-->\n<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\n <div class=\"nxe-tag-container\">\n @for (item of selectedItems(); track $index) {\n <span class=\"nxe-tag\">\n <span class=\"nxe-tag-text\">{{ display(item) }}</span>\n <!-- Rendered in every state, as dx does (m_tag_box.js appends it unconditionally);\n readOnly/disabled make it inert rather than removing it. -->\n <span class=\"nxe-tag-remove\" (mousedown)=\"removeTag(item, $event)\" aria-hidden=\"true\"></span>\n </span>\n }\n\n <input\n #input\n class=\"nxe-editor-input nxe-tag-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId() : null\"\n\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n [readOnly]=\"readOnly() || !searchEnabled()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"selectedItems().length ? null : (placeholder() || null)\"\n autocomplete=\"off\"\n (input)=\"onSearchInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\" />\n </div>\n\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n @if (showDropDownButton() && !readOnly()) {\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\n <!-- An 8x4 triangle centred in the 18px box. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #dropdown>\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\n [id]=\"panelId()\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n (scroll)=\"onPanelScroll($event)\">\n @if (showSelectionControls()) {\n <!-- dx `selectionMode: 'all'`, which showSelectionControls switches on\n (m_tag_box.js _listConfig): a tri-state \"Select All\" over the rows shown. Hidden\n while the list is empty, as `.dx-empty-collection .dx-list-select-all` is. -->\n @if (filteredItems().length) {\n <div\n class=\"nxe-tag-select-all\"\n [id]=\"panelId() + '-select-all'\"\n role=\"option\"\n [attr.aria-selected]=\"selectAllState() === true\"\n [attr.aria-checked]=\"selectAllState() === undefined ? 'mixed' : selectAllState()\"\n (mousedown)=\"toggleAll($event)\">\n <span\n class=\"nxe-tag-check\"\n [class.nxe-tag-checked]=\"selectAllState() === true\"\n [class.nxe-tag-indeterminate]=\"selectAllState() === undefined\"\n aria-hidden=\"true\"></span>\n <span class=\"nxe-tag-select-all-label\">{{ selectAllText() ?? nxeMessages.t('dropdown.selectAll') }}</span>\n </div>\n }\n @for (item of filteredItems(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item nxe-tag-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(item)\"\n [class.nxe-list-item-selected]=\"isSelected(item)\"\n (mousedown)=\"toggle(item, $event)\">\n <span class=\"nxe-tag-check\" [class.nxe-tag-checked]=\"isSelected(item)\" aria-hidden=\"true\"></span>\n <span class=\"nxe-tag-item-text\">{{ display(item) }}</span>\n </div>\n } @empty {\n <div class=\"nxe-list-empty\">{{ nxeMessages.t('dropdown.noData') }}</div>\n }\n } @else {\n <!-- dx `selectionMode: 'multiple'`: plain rows, selection shown by the row fill. -->\n @for (item of filteredItems(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(item)\"\n [class.nxe-list-item-selected]=\"isSelected(item)\"\n (mousedown)=\"toggle(item, $event)\">\n {{ display(item) }}\n </div>\n } @empty {\n <div class=\"nxe-list-empty\">{{ nxeMessages.t('dropdown.noData') }}</div>\n }\n }\n </div>\n</ng-template>\n", styles: ["nxe-tag-box{cursor:pointer}nxe-tag-box .nxe-tag-container{box-sizing:border-box;position:relative;display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:stretch;align-self:stretch;min-width:0;padding-bottom:4px}nxe-tag-box .nxe-tag-input{flex:1 1 60px;min-width:60px;width:auto;height:auto;min-height:30px;padding-bottom:4px}nxe-tag-box .nxe-tag-container:has(>.nxe-tag)>.nxe-tag-input{padding-inline-start:0;margin-inline-start:5px}nxe-tag-box.nxe-invalid>.nxe-editor-container:not(:has(>.nxe-select-clear,>.nxe-select-arrow))>.nxe-tag-container:not(:has(>.nxe-tag))>.nxe-tag-input{padding-inline-end:34px}nxe-tag-box .nxe-tag{box-sizing:border-box;position:relative;display:inline-flex;align-self:flex-start;justify-content:center;max-width:calc(100% - 5px);min-width:40px;margin-top:4px;margin-inline-start:4px;padding-block:3px 4px;padding-inline:6px 25px;background-color:var(--nxe-ui-border, #ddd);border-radius:2px;color:var(--nxe-ui-text, #333)}nxe-tag-box .nxe-tag-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tag-box .nxe-tag-remove{position:absolute;inset-inline-end:0;top:0;width:25px;height:100%;cursor:pointer}nxe-tag-box .nxe-tag-remove:before,nxe-tag-box .nxe-tag-remove:after{position:absolute;top:50%;content:\"\";transform:rotate(45deg);inset-inline-end:9px;margin-top:-5px;width:3px;height:11px;background:var(--nxe-ui-neutral-400, #aaa)}nxe-tag-box .nxe-tag-remove:after{inset-inline-end:5px;margin-top:-1px;width:11px;height:3px}nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:before,nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:after{background:var(--nxe-ui-border, #ddd)}nxe-tag-box.nxe-disabled .nxe-tag,nxe-tag-box.nxe-disabled .nxe-tag-remove{cursor:default}nxe-tag-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-tag-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-tag-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-tag-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-tag-box.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear),nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-select-panel .nxe-list-item.nxe-tag-item{display:block;position:relative;padding-block:10px;padding-inline:41px 10px}.nxe-select-panel .nxe-list-item.nxe-tag-item:hover,.nxe-select-panel .nxe-list-item.nxe-tag-item:active,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected:hover:not(.nxe-list-item-active){background-color:transparent;color:var(--nxe-ui-text)}.nxe-tag-check{box-sizing:border-box;position:relative;display:block;width:22px;height:22px;border:1px solid var(--nxe-ui-border);border-radius:2px;background:var(--nxe-ui-surface)}.nxe-tag-check.nxe-tag-checked:after{content:\"\";position:absolute;box-sizing:border-box;top:5px;inset-inline-start:2.5px;width:15px;height:11px;background-color:var(--nxe-ui-accent);clip-path:polygon(0 5.586px,5.414px 11px,15px 1.414px,13.586px 0,5.414px 8.172px,1.414px 4.172px)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-checked:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-check.nxe-tag-indeterminate:after{content:\"\";position:absolute;box-sizing:border-box;top:50%;inset-inline-start:50%;width:12px;height:12px;margin-top:-6px;margin-inline-start:-6px;border-radius:2px;background-color:var(--nxe-ui-accent)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-indeterminate:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-item .nxe-tag-check{position:absolute;top:50%;inset-inline-start:10px;margin-top:-10px}.nxe-tag-item:hover .nxe-tag-check,.nxe-tag-select-all:hover .nxe-tag-check{border-color:var(--nxe-ui-checkbox-hover-border, #265a87)}.nxe-tag-select-all{box-sizing:border-box;padding-block:12px 11px;padding-inline:0;border-bottom:1px solid var(--nxe-ui-border);margin-bottom:3px;white-space:nowrap;cursor:pointer}.nxe-tag-select-all .nxe-tag-check{float:inline-start;margin-top:-1px;margin-bottom:-3px;margin-inline-start:10px}.nxe-tag-select-all-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:17px;padding:0 10px;margin-top:1px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
529
817
  }
530
818
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTagBoxComponent, decorators: [{
531
819
  type: Component,
532
820
  args: [{ selector: 'nxe-tag-box', standalone: true, host: {
533
821
  class: 'nxe-widget nxe-editor nxe-tagbox',
534
822
  '[class.nxe-focused]': 'focused()',
535
- '[class.nxe-invalid]': '!!validationError()',
823
+ '[class.nxe-invalid]': 'invalidState()',
536
824
  '[class.nxe-open]': 'open()',
537
825
  '(keydown)': 'onKeydown($event)',
538
826
  }, providers: [
539
827
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeTagBoxComponent), multi: true },
540
828
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeTagBoxComponent) },
541
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!--\r\n Two columns, as dx-tag-box renders them: the wrapping tag container (dx turns\r\n `.dx-texteditor-input-container` into `.dx-tag-container`) and, beside it, the buttons \u2014 never\r\n inside it, so they cannot wrap onto a tag row and they centre on the whole editor height.\r\n-->\r\n<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\r\n <div class=\"nxe-tag-container\">\r\n @for (item of selectedItems(); track $index) {\r\n <span class=\"nxe-tag\">\r\n <span class=\"nxe-tag-text\">{{ display(item) }}</span>\r\n <!-- Rendered in every state, as dx does (m_tag_box.js appends it unconditionally);\r\n readOnly/disabled make it inert rather than removing it. -->\r\n <span class=\"nxe-tag-remove\" (mousedown)=\"removeTag(item, $event)\" aria-hidden=\"true\"></span>\r\n </span>\r\n }\r\n\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-tag-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"open()\"\r\n [attr.aria-controls]=\"open() ? panelId() : null\"\r\n\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n [readOnly]=\"readOnly() || !searchEnabled()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"selectedItems().length ? null : (placeholder() || null)\"\r\n autocomplete=\"off\"\r\n (input)=\"onSearchInput($event)\"\r\n (focus)=\"focused.set(true)\"\r\n (blur)=\"onBlur()\" />\r\n </div>\r\n\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n @if (showDropDownButton() && !readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <!-- An 8x4 triangle centred in the 18px box. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #dropdown>\r\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\r\n [id]=\"panelId()\"\r\n role=\"listbox\"\r\n aria-multiselectable=\"true\">\r\n @if (showSelectionControls()) {\r\n <!-- dx `selectionMode: 'all'`, which showSelectionControls switches on\r\n (m_tag_box.js _listConfig): a tri-state \"Select All\" over the rows shown. Hidden\r\n while the list is empty, as `.dx-empty-collection .dx-list-select-all` is. -->\r\n @if (filteredItems().length) {\r\n <div\r\n class=\"nxe-tag-select-all\"\r\n [id]=\"panelId() + '-select-all'\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"selectAllState() === true\"\r\n [attr.aria-checked]=\"selectAllState() === undefined ? 'mixed' : selectAllState()\"\r\n (mousedown)=\"toggleAll($event)\">\r\n <span\r\n class=\"nxe-tag-check\"\r\n [class.nxe-tag-checked]=\"selectAllState() === true\"\r\n [class.nxe-tag-indeterminate]=\"selectAllState() === undefined\"\r\n aria-hidden=\"true\"></span>\r\n <span class=\"nxe-tag-select-all-label\">{{ selectAllText() }}</span>\r\n </div>\r\n }\r\n @for (item of filteredItems(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item nxe-tag-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-selected]=\"isSelected(item)\"\r\n (mousedown)=\"toggle(item, $event)\">\r\n <span class=\"nxe-tag-check\" [class.nxe-tag-checked]=\"isSelected(item)\" aria-hidden=\"true\"></span>\r\n <span class=\"nxe-tag-item-text\">{{ display(item) }}</span>\r\n </div>\r\n } @empty {\r\n <div class=\"nxe-list-empty\">No data to display</div>\r\n }\r\n } @else {\r\n <!-- dx `selectionMode: 'multiple'`: plain rows, selection shown by the row fill. -->\r\n @for (item of filteredItems(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"isSelected(item)\"\r\n [class.nxe-list-item-selected]=\"isSelected(item)\"\r\n (mousedown)=\"toggle(item, $event)\">\r\n {{ display(item) }}\r\n </div>\r\n } @empty {\r\n <div class=\"nxe-list-empty\">No data to display</div>\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-tag-box{cursor:pointer}nxe-tag-box .nxe-tag-container{box-sizing:border-box;position:relative;display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:stretch;align-self:stretch;min-width:0;padding-bottom:4px}nxe-tag-box .nxe-tag-input{flex:1 1 60px;min-width:60px;width:auto;height:auto;min-height:30px;padding-bottom:4px}nxe-tag-box .nxe-tag-container:has(>.nxe-tag)>.nxe-tag-input{padding-inline-start:0;margin-inline-start:5px}nxe-tag-box.nxe-invalid>.nxe-editor-container:not(:has(>.nxe-select-clear,>.nxe-select-arrow))>.nxe-tag-container:not(:has(>.nxe-tag))>.nxe-tag-input{padding-inline-end:34px}nxe-tag-box .nxe-tag{box-sizing:border-box;position:relative;display:inline-flex;align-self:flex-start;justify-content:center;max-width:calc(100% - 5px);min-width:40px;margin-top:4px;margin-inline-start:4px;padding-block:3px 4px;padding-inline:6px 25px;background-color:#ddd;border-radius:2px;color:#333}nxe-tag-box .nxe-tag-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tag-box .nxe-tag-remove{position:absolute;inset-inline-end:0;top:0;width:25px;height:100%;cursor:pointer}nxe-tag-box .nxe-tag-remove:before,nxe-tag-box .nxe-tag-remove:after{position:absolute;top:50%;content:\"\";transform:rotate(45deg);inset-inline-end:9px;margin-top:-5px;width:3px;height:11px;background:#aaa}nxe-tag-box .nxe-tag-remove:after{inset-inline-end:5px;margin-top:-1px;width:11px;height:3px}nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:before,nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:after{background:#ddd}nxe-tag-box.nxe-disabled .nxe-tag,nxe-tag-box.nxe-disabled .nxe-tag-remove{cursor:default}nxe-tag-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-tag-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-tag-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-tag-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-tag-box.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear),nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-select-panel .nxe-list-item.nxe-tag-item{display:block;position:relative;padding-block:10px;padding-inline:41px 10px}.nxe-select-panel .nxe-list-item.nxe-tag-item:hover,.nxe-select-panel .nxe-list-item.nxe-tag-item:active,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected:hover:not(.nxe-list-item-active){background-color:transparent;color:var(--nxe-ui-text)}.nxe-tag-check{box-sizing:border-box;position:relative;display:block;width:22px;height:22px;border:1px solid var(--nxe-ui-border);border-radius:2px;background:var(--nxe-ui-surface)}.nxe-tag-check.nxe-tag-checked:after{content:\"\";position:absolute;box-sizing:border-box;top:5px;inset-inline-start:2.5px;width:15px;height:11px;background-color:var(--nxe-ui-accent);clip-path:polygon(0 5.586px,5.414px 11px,15px 1.414px,13.586px 0,5.414px 8.172px,1.414px 4.172px)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-checked:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-check.nxe-tag-indeterminate:after{content:\"\";position:absolute;box-sizing:border-box;top:50%;inset-inline-start:50%;width:12px;height:12px;margin-top:-6px;margin-inline-start:-6px;border-radius:2px;background-color:var(--nxe-ui-accent)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-indeterminate:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-item .nxe-tag-check{position:absolute;top:50%;inset-inline-start:10px;margin-top:-10px}.nxe-tag-item:hover .nxe-tag-check,.nxe-tag-select-all:hover .nxe-tag-check{border-color:var(--nxe-ui-checkbox-hover-border, #265a87)}.nxe-tag-select-all{box-sizing:border-box;padding-block:12px 11px;padding-inline:0;border-bottom:1px solid var(--nxe-ui-border);margin-bottom:3px;white-space:nowrap;cursor:pointer}.nxe-tag-select-all .nxe-tag-check{float:inline-start;margin-top:-1px;margin-bottom:-3px;margin-inline-start:10px}.nxe-tag-select-all-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:17px;padding:0 10px;margin-top:1px}\n"] }]
542
- }], propDecorators: { dropdownTemplate: [{ type: i0.ViewChild, args: ['dropdown', { isSignal: true }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], displayExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], valueExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueExpr", required: false }] }], searchExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchExpr", required: false }] }], searchEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showSelectionControlsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSelectionControls", required: false }] }], selectAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllText", required: false }] }], showDropDownButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropDownButton", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }] } });
829
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!--\n Two columns, as dx-tag-box renders them: the wrapping tag container (dx turns\n `.dx-texteditor-input-container` into `.dx-tag-container`) and, beside it, the buttons \u2014 never\n inside it, so they cannot wrap onto a tag row and they centre on the whole editor height.\n-->\n<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\n <div class=\"nxe-tag-container\">\n @for (item of selectedItems(); track $index) {\n <span class=\"nxe-tag\">\n <span class=\"nxe-tag-text\">{{ display(item) }}</span>\n <!-- Rendered in every state, as dx does (m_tag_box.js appends it unconditionally);\n readOnly/disabled make it inert rather than removing it. -->\n <span class=\"nxe-tag-remove\" (mousedown)=\"removeTag(item, $event)\" aria-hidden=\"true\"></span>\n </span>\n }\n\n <input\n #input\n class=\"nxe-editor-input nxe-tag-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId() : null\"\n\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n [readOnly]=\"readOnly() || !searchEnabled()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"selectedItems().length ? null : (placeholder() || null)\"\n autocomplete=\"off\"\n (input)=\"onSearchInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\" />\n </div>\n\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n @if (showDropDownButton() && !readOnly()) {\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\n <!-- An 8x4 triangle centred in the 18px box. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #dropdown>\n <div class=\"nxe-select-panel\" [style.width.px]=\"panelWidth()\"\n [id]=\"panelId()\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n (scroll)=\"onPanelScroll($event)\">\n @if (showSelectionControls()) {\n <!-- dx `selectionMode: 'all'`, which showSelectionControls switches on\n (m_tag_box.js _listConfig): a tri-state \"Select All\" over the rows shown. Hidden\n while the list is empty, as `.dx-empty-collection .dx-list-select-all` is. -->\n @if (filteredItems().length) {\n <div\n class=\"nxe-tag-select-all\"\n [id]=\"panelId() + '-select-all'\"\n role=\"option\"\n [attr.aria-selected]=\"selectAllState() === true\"\n [attr.aria-checked]=\"selectAllState() === undefined ? 'mixed' : selectAllState()\"\n (mousedown)=\"toggleAll($event)\">\n <span\n class=\"nxe-tag-check\"\n [class.nxe-tag-checked]=\"selectAllState() === true\"\n [class.nxe-tag-indeterminate]=\"selectAllState() === undefined\"\n aria-hidden=\"true\"></span>\n <span class=\"nxe-tag-select-all-label\">{{ selectAllText() ?? nxeMessages.t('dropdown.selectAll') }}</span>\n </div>\n }\n @for (item of filteredItems(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item nxe-tag-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(item)\"\n [class.nxe-list-item-selected]=\"isSelected(item)\"\n (mousedown)=\"toggle(item, $event)\">\n <span class=\"nxe-tag-check\" [class.nxe-tag-checked]=\"isSelected(item)\" aria-hidden=\"true\"></span>\n <span class=\"nxe-tag-item-text\">{{ display(item) }}</span>\n </div>\n } @empty {\n <div class=\"nxe-list-empty\">{{ nxeMessages.t('dropdown.noData') }}</div>\n }\n } @else {\n <!-- dx `selectionMode: 'multiple'`: plain rows, selection shown by the row fill. -->\n @for (item of filteredItems(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(item)\"\n [class.nxe-list-item-selected]=\"isSelected(item)\"\n (mousedown)=\"toggle(item, $event)\">\n {{ display(item) }}\n </div>\n } @empty {\n <div class=\"nxe-list-empty\">{{ nxeMessages.t('dropdown.noData') }}</div>\n }\n }\n </div>\n</ng-template>\n", styles: ["nxe-tag-box{cursor:pointer}nxe-tag-box .nxe-tag-container{box-sizing:border-box;position:relative;display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:stretch;align-self:stretch;min-width:0;padding-bottom:4px}nxe-tag-box .nxe-tag-input{flex:1 1 60px;min-width:60px;width:auto;height:auto;min-height:30px;padding-bottom:4px}nxe-tag-box .nxe-tag-container:has(>.nxe-tag)>.nxe-tag-input{padding-inline-start:0;margin-inline-start:5px}nxe-tag-box.nxe-invalid>.nxe-editor-container:not(:has(>.nxe-select-clear,>.nxe-select-arrow))>.nxe-tag-container:not(:has(>.nxe-tag))>.nxe-tag-input{padding-inline-end:34px}nxe-tag-box .nxe-tag{box-sizing:border-box;position:relative;display:inline-flex;align-self:flex-start;justify-content:center;max-width:calc(100% - 5px);min-width:40px;margin-top:4px;margin-inline-start:4px;padding-block:3px 4px;padding-inline:6px 25px;background-color:var(--nxe-ui-border, #ddd);border-radius:2px;color:var(--nxe-ui-text, #333)}nxe-tag-box .nxe-tag-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tag-box .nxe-tag-remove{position:absolute;inset-inline-end:0;top:0;width:25px;height:100%;cursor:pointer}nxe-tag-box .nxe-tag-remove:before,nxe-tag-box .nxe-tag-remove:after{position:absolute;top:50%;content:\"\";transform:rotate(45deg);inset-inline-end:9px;margin-top:-5px;width:3px;height:11px;background:var(--nxe-ui-neutral-400, #aaa)}nxe-tag-box .nxe-tag-remove:after{inset-inline-end:5px;margin-top:-1px;width:11px;height:3px}nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:before,nxe-tag-box:not(.nxe-disabled) .nxe-tag-remove:active:after{background:var(--nxe-ui-border, #ddd)}nxe-tag-box.nxe-disabled .nxe-tag,nxe-tag-box.nxe-disabled .nxe-tag-remove{cursor:default}nxe-tag-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-tag-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-tag-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-tag-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-tag-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-tag-box.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear),nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-select-panel .nxe-list-item.nxe-tag-item{display:block;position:relative;padding-block:10px;padding-inline:41px 10px}.nxe-select-panel .nxe-list-item.nxe-tag-item:hover,.nxe-select-panel .nxe-list-item.nxe-tag-item:active,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected,.nxe-select-panel .nxe-list-item.nxe-tag-item.nxe-list-item-selected:hover:not(.nxe-list-item-active){background-color:transparent;color:var(--nxe-ui-text)}.nxe-tag-check{box-sizing:border-box;position:relative;display:block;width:22px;height:22px;border:1px solid var(--nxe-ui-border);border-radius:2px;background:var(--nxe-ui-surface)}.nxe-tag-check.nxe-tag-checked:after{content:\"\";position:absolute;box-sizing:border-box;top:5px;inset-inline-start:2.5px;width:15px;height:11px;background-color:var(--nxe-ui-accent);clip-path:polygon(0 5.586px,5.414px 11px,15px 1.414px,13.586px 0,5.414px 8.172px,1.414px 4.172px)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-checked:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-check.nxe-tag-indeterminate:after{content:\"\";position:absolute;box-sizing:border-box;top:50%;inset-inline-start:50%;width:12px;height:12px;margin-top:-6px;margin-inline-start:-6px;border-radius:2px;background-color:var(--nxe-ui-accent)}@media(forced-colors:active){.nxe-tag-check.nxe-tag-indeterminate:after{forced-color-adjust:none;background-color:CanvasText}}.nxe-tag-item .nxe-tag-check{position:absolute;top:50%;inset-inline-start:10px;margin-top:-10px}.nxe-tag-item:hover .nxe-tag-check,.nxe-tag-select-all:hover .nxe-tag-check{border-color:var(--nxe-ui-checkbox-hover-border, #265a87)}.nxe-tag-select-all{box-sizing:border-box;padding-block:12px 11px;padding-inline:0;border-bottom:1px solid var(--nxe-ui-border);margin-bottom:3px;white-space:nowrap;cursor:pointer}.nxe-tag-select-all .nxe-tag-check{float:inline-start;margin-top:-1px;margin-bottom:-3px;margin-inline-start:10px}.nxe-tag-select-all-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:17px;padding:0 10px;margin-top:1px}\n"] }]
830
+ }], propDecorators: { dropdownTemplate: [{ type: i0.ViewChild, args: ['dropdown', { isSignal: true }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], displayExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], valueExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueExpr", required: false }] }], searchExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchExpr", required: false }] }], searchEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showSelectionControlsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSelectionControls", required: false }] }], selectAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllText", required: false }] }], showDropDownButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropDownButton", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], searchTimeout: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTimeout", required: false }] }], minSearchLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSearchLength", required: false }] }], showDataBeforeSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDataBeforeSearch", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }] } });
543
831
 
544
832
  /**
545
833
  * `nxe-drop-down-options` — drop-in for DevExtreme `dxo-drop-down-options`, a no-template config
@@ -744,22 +1032,22 @@ class NxeDropDownBoxComponent extends NxeFormControlBase {
744
1032
  this.overlayRef?.dispose();
745
1033
  }
746
1034
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeDropDownBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
747
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeDropDownBoxComponent, isStandalone: true, selector: "nxe-drop-down-box", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, displayExprInput: { classPropertyName: "displayExprInput", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, valueExprInput: { classPropertyName: "valueExprInput", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, dropDownOptions: { classPropertyName: "dropDownOptions", publicName: "dropDownOptions", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "openedChange", onClosed: "onClosed" }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-dropdownbox" }, providers: [
1035
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeDropDownBoxComponent, isStandalone: true, selector: "nxe-drop-down-box", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, displayExprInput: { classPropertyName: "displayExprInput", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, valueExprInput: { classPropertyName: "valueExprInput", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, dropDownOptions: { classPropertyName: "dropDownOptions", publicName: "dropDownOptions", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "openedChange", onClosed: "onClosed" }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "invalidState()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-dropdownbox" }, providers: [
748
1036
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeDropDownBoxComponent), multi: true },
749
1037
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeDropDownBoxComponent) },
750
- ], queries: [{ propertyName: "templates", predicate: NxeTemplateDirective, isSignal: true }, { propertyName: "options", first: true, predicate: NxeDropDownOptionsComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "panelTemplate", first: true, predicate: ["panel"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\r\n <input\r\n class=\"nxe-editor-input nxe-dropdownbox-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"dialog\"\r\n [attr.aria-expanded]=\"opened()\"\r\n [attr.aria-controls]=\"opened() ? panelId() : null\"\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n readonly\r\n [value]=\"displayText()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"placeholder() || null\"\r\n (focus)=\"focused.set(true)\"\r\n (blur)=\"onBlur()\" />\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n\r\n @if (!readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <!-- An 8x4 triangle centred in the 18px box. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #panel>\r\n <div class=\"nxe-dropdownbox-panel\" [id]=\"panelId()\" role=\"dialog\" [style.width]=\"panelStyleWidth()\">\r\n @if (contentTemplateRef(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: value() }\" />\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-drop-down-box{cursor:pointer}nxe-drop-down-box .nxe-dropdownbox-input{cursor:pointer}nxe-drop-down-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-drop-down-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-drop-down-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-drop-down-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-drop-down-box.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear),nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-dropdownbox-panel{box-sizing:border-box;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 6px 12px #0000002d;overflow:auto;max-height:420px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1038
+ ], queries: [{ propertyName: "templates", predicate: NxeTemplateDirective, isSignal: true }, { propertyName: "options", first: true, predicate: NxeDropDownOptionsComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "panelTemplate", first: true, predicate: ["panel"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\n <input\n class=\"nxe-editor-input nxe-dropdownbox-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"opened()\"\n [attr.aria-controls]=\"opened() ? panelId() : null\"\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n readonly\n [value]=\"displayText()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || null\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\" />\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n\n @if (!readOnly()) {\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\n <!-- An 8x4 triangle centred in the 18px box. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #panel>\n <div class=\"nxe-dropdownbox-panel\" [id]=\"panelId()\" role=\"dialog\" [style.width]=\"panelStyleWidth()\">\n @if (contentTemplateRef(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: value() }\" />\n }\n </div>\n</ng-template>\n", styles: ["nxe-drop-down-box{cursor:pointer}nxe-drop-down-box .nxe-dropdownbox-input{cursor:pointer}nxe-drop-down-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-drop-down-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-drop-down-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-drop-down-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-drop-down-box.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear),nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-dropdownbox-panel{box-sizing:border-box;background:var(--nxe-ui-surface, #fff);border:1px solid var(--nxe-ui-border, #ddd);border-radius:6px;box-shadow:var(--nxe-ui-popup-shadow, 0 6px 12px rgba(0, 0, 0, .175));overflow:auto;max-height:420px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
751
1039
  }
752
1040
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeDropDownBoxComponent, decorators: [{
753
1041
  type: Component,
754
1042
  args: [{ selector: 'nxe-drop-down-box', standalone: true, imports: [NgTemplateOutlet], host: {
755
1043
  class: 'nxe-widget nxe-editor nxe-dropdownbox',
756
1044
  '[class.nxe-focused]': 'focused()',
757
- '[class.nxe-invalid]': '!!validationError()',
1045
+ '[class.nxe-invalid]': 'invalidState()',
758
1046
  '[class.nxe-open]': 'open()',
759
1047
  }, providers: [
760
1048
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeDropDownBoxComponent), multi: true },
761
1049
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeDropDownBoxComponent) },
762
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\r\n <input\r\n class=\"nxe-editor-input nxe-dropdownbox-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"dialog\"\r\n [attr.aria-expanded]=\"opened()\"\r\n [attr.aria-controls]=\"opened() ? panelId() : null\"\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n readonly\r\n [value]=\"displayText()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"placeholder() || null\"\r\n (focus)=\"focused.set(true)\"\r\n (blur)=\"onBlur()\" />\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n\r\n @if (!readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <!-- An 8x4 triangle centred in the 18px box. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #panel>\r\n <div class=\"nxe-dropdownbox-panel\" [id]=\"panelId()\" role=\"dialog\" [style.width]=\"panelStyleWidth()\">\r\n @if (contentTemplateRef(); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: value() }\" />\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-drop-down-box{cursor:pointer}nxe-drop-down-box .nxe-dropdownbox-input{cursor:pointer}nxe-drop-down-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-drop-down-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-drop-down-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-drop-down-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-drop-down-box.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear),nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-dropdownbox-panel{box-sizing:border-box;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 6px 12px #0000002d;overflow:auto;max-height:420px}\n"] }]
1050
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container\" (mousedown)=\"onFieldMousedown($event)\">\n <input\n class=\"nxe-editor-input nxe-dropdownbox-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"opened()\"\n [attr.aria-controls]=\"opened() ? panelId() : null\"\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n readonly\n [value]=\"displayText()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || null\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\" />\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n\n @if (!readOnly()) {\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\n <!-- An 8x4 triangle centred in the 18px box. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\"><path d=\"M5 7h8l-4 4z\" /></svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #panel>\n <div class=\"nxe-dropdownbox-panel\" [id]=\"panelId()\" role=\"dialog\" [style.width]=\"panelStyleWidth()\">\n @if (contentTemplateRef(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: value() }\" />\n }\n </div>\n</ng-template>\n", styles: ["nxe-drop-down-box{cursor:pointer}nxe-drop-down-box .nxe-dropdownbox-input{cursor:pointer}nxe-drop-down-box .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-drop-down-box .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-drop-down-box .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-drop-down-box:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-drop-down-box:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-drop-down-box.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear),nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-drop-down-box .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-dropdownbox-panel{box-sizing:border-box;background:var(--nxe-ui-surface, #fff);border:1px solid var(--nxe-ui-border, #ddd);border-radius:6px;box-shadow:var(--nxe-ui-popup-shadow, 0 6px 12px rgba(0, 0, 0, .175));overflow:auto;max-height:420px}\n"] }]
763
1051
  }], ctorParameters: () => [], propDecorators: { panelTemplate: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeTemplateDirective), { isSignal: true }] }], options: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NxeDropDownOptionsComponent), { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], displayExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], valueExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueExpr", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], dropDownOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropDownOptions", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], opened: [{ type: i0.Input, args: [{ isSignal: true, alias: "opened", required: false }] }, { type: i0.Output, args: ["openedChange"] }], onClosed: [{ type: i0.Output, args: ["onClosed"] }] } });
764
1052
 
765
1053
  /** DI token the menu provides so projected `nxe-menu-item`s can close it on click. */
@@ -1030,21 +1318,21 @@ class NxeAutoCompleteComponent extends NxeFormControlBase {
1030
1318
  this.closePanel();
1031
1319
  }
1032
1320
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeAutoCompleteComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1033
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeAutoCompleteComponent, isStandalone: true, selector: "nxe-auto-complete", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, valueExpr: { classPropertyName: "valueExpr", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, searchExprInput: { classPropertyName: "searchExprInput", publicName: "searchExpr", isSignal: true, isRequired: false, transformFunction: null }, searchMode: { classPropertyName: "searchMode", publicName: "searchMode", isSignal: true, isRequired: false, transformFunction: null }, minSearchLength: { classPropertyName: "minSearchLength", publicName: "minSearchLength", isSignal: true, isRequired: false, transformFunction: null }, maxItemCount: { classPropertyName: "maxItemCount", publicName: "maxItemCount", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChanged: "onSelectionChanged" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-autocomplete-box" }, providers: [
1321
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeAutoCompleteComponent, isStandalone: true, selector: "nxe-auto-complete", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, valueExpr: { classPropertyName: "valueExpr", publicName: "valueExpr", isSignal: true, isRequired: false, transformFunction: null }, searchExprInput: { classPropertyName: "searchExprInput", publicName: "searchExpr", isSignal: true, isRequired: false, transformFunction: null }, searchMode: { classPropertyName: "searchMode", publicName: "searchMode", isSignal: true, isRequired: false, transformFunction: null }, minSearchLength: { classPropertyName: "minSearchLength", publicName: "minSearchLength", isSignal: true, isRequired: false, transformFunction: null }, maxItemCount: { classPropertyName: "maxItemCount", publicName: "maxItemCount", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChanged: "onSelectionChanged" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "invalidState()", "class.nxe-open": "open()" }, classAttribute: "nxe-widget nxe-editor nxe-autocomplete-box" }, providers: [
1034
1322
  {
1035
1323
  provide: NG_VALUE_ACCESSOR,
1036
1324
  useExisting: forwardRef(() => NxeAutoCompleteComponent),
1037
1325
  multi: true,
1038
1326
  },
1039
1327
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeAutoCompleteComponent) },
1040
- ], viewQueries: [{ propertyName: "dropdownTemplate", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }, { propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"nxe-editor-container\">\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-autocomplete-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"open()\"\r\n [attr.aria-controls]=\"open() ? panelId() : null\"\r\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n [value]=\"text()\"\r\n [readOnly]=\"readOnly()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"placeholder() || null\"\r\n autocomplete=\"off\"\r\n (input)=\"onFieldInput($event)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\" />\r\n\r\n @if (showClearButton() && text() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #dropdown>\r\n <div class=\"nxe-autocomplete-box-panel\" [style.width.px]=\"panelWidth()\"\r\n [id]=\"panelId()\"\r\n role=\"listbox\">\r\n @for (item of suggestions(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === activeIndex()\"\r\n [class.nxe-list-item-active]=\"i === activeIndex()\"\r\n (mousedown)=\"pick(item, $event)\">\r\n {{ itemText(item) }}\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-auto-complete .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-auto-complete .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-auto-complete .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-auto-complete:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-auto-complete.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear),nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-autocomplete-box-panel{max-height:300px;overflow-y:auto;background:var(--nxe-ui-surface, #fff);border:1px solid var(--nxe-ui-border, #ddd);box-sizing:border-box}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1328
+ ], viewQueries: [{ propertyName: "dropdownTemplate", first: true, predicate: ["dropdown"], descendants: true, isSignal: true }, { propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"nxe-editor-container\">\n <input\n #input\n class=\"nxe-editor-input nxe-autocomplete-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId() : null\"\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n [value]=\"text()\"\n [readOnly]=\"readOnly()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || null\"\n autocomplete=\"off\"\n (input)=\"onFieldInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\" />\n\n @if (showClearButton() && text() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #dropdown>\n <div class=\"nxe-autocomplete-box-panel\" [style.width.px]=\"panelWidth()\"\n [id]=\"panelId()\"\n role=\"listbox\">\n @for (item of suggestions(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"i === activeIndex()\"\n [class.nxe-list-item-active]=\"i === activeIndex()\"\n (mousedown)=\"pick(item, $event)\">\n {{ itemText(item) }}\n </div>\n }\n </div>\n</ng-template>\n", styles: ["nxe-auto-complete .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-auto-complete .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-auto-complete .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-auto-complete:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-auto-complete.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear),nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-autocomplete-box-panel{max-height:300px;overflow-y:auto;background:var(--nxe-ui-surface, #fff);border:1px solid var(--nxe-ui-border, #ddd);box-sizing:border-box}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1041
1329
  }
1042
1330
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeAutoCompleteComponent, decorators: [{
1043
1331
  type: Component,
1044
1332
  args: [{ selector: 'nxe-auto-complete', standalone: true, host: {
1045
1333
  class: 'nxe-widget nxe-editor nxe-autocomplete-box',
1046
1334
  '[class.nxe-focused]': 'focused()',
1047
- '[class.nxe-invalid]': '!!validationError()',
1335
+ '[class.nxe-invalid]': 'invalidState()',
1048
1336
  '[class.nxe-open]': 'open()',
1049
1337
  '(keydown)': 'onKeydown($event)',
1050
1338
  }, providers: [
@@ -1054,7 +1342,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
1054
1342
  multi: true,
1055
1343
  },
1056
1344
  { provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeAutoCompleteComponent) },
1057
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container\">\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-autocomplete-input\"\r\n [attr.tabindex]=\"tabIndex()\"\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n [attr.aria-expanded]=\"open()\"\r\n [attr.aria-controls]=\"open() ? panelId() : null\"\r\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\r\n [id]=\"controlId()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\r\n [attr.aria-invalid]=\"validationError() ? true : null\"\r\n [attr.aria-required]=\"required() ? true : null\"\r\n type=\"text\"\r\n [value]=\"text()\"\r\n [readOnly]=\"readOnly()\"\r\n [disabled]=\"disabled()\"\r\n [attr.placeholder]=\"placeholder() || null\"\r\n autocomplete=\"off\"\r\n (input)=\"onFieldInput($event)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\" />\r\n\r\n @if (showClearButton() && text() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\r\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\r\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\r\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </span>\r\n }\r\n</div>\r\n\r\n<ng-content />\r\n\r\n@if (validationError(); as error) {\r\n @if (focused()) {\r\n <div class=\"nxe-invalid-message\">{{ error }}</div>\r\n }\r\n}\r\n\r\n<ng-template #dropdown>\r\n <div class=\"nxe-autocomplete-box-panel\" [style.width.px]=\"panelWidth()\"\r\n [id]=\"panelId()\"\r\n role=\"listbox\">\r\n @for (item of suggestions(); track $index; let i = $index) {\r\n <div\r\n class=\"nxe-list-item\"\r\n [id]=\"optionId(i)\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === activeIndex()\"\r\n [class.nxe-list-item-active]=\"i === activeIndex()\"\r\n (mousedown)=\"pick(item, $event)\">\r\n {{ itemText(item) }}\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["nxe-auto-complete .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:#999;cursor:pointer}nxe-auto-complete .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-auto-complete .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-auto-complete:active:not(.nxe-disabled) .nxe-select-arrow{background-color:#e6e6e6}nxe-auto-complete.nxe-open .nxe-select-arrow{background-color:#b3b3b3}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear),nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-autocomplete-box-panel{max-height:300px;overflow-y:auto;background:var(--nxe-ui-surface, #fff);border:1px solid var(--nxe-ui-border, #ddd);box-sizing:border-box}\n"] }]
1345
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container\">\n <input\n #input\n class=\"nxe-editor-input nxe-autocomplete-input\"\n [attr.tabindex]=\"tabIndex()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? panelId() : null\"\n [attr.aria-activedescendant]=\"open() && activeIndex() >= 0 ? optionId(activeIndex()) : null\"\n [id]=\"controlId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n [attr.aria-invalid]=\"invalidState() ? true : null\"\n [attr.aria-required]=\"required() ? true : null\"\n type=\"text\"\n [value]=\"text()\"\n [readOnly]=\"readOnly()\"\n [disabled]=\"disabled()\"\n [attr.placeholder]=\"placeholder() || null\"\n autocomplete=\"off\"\n (input)=\"onFieldInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\" />\n\n @if (showClearButton() && text() && !readOnly() && !disabled()) {\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\n <!-- A \u00D816 disc with a 2px \u00D7 cut out: two 2px bars, each running corner to corner of the\n 8px square centred on the disc, drawn as a plus and turned 45\u00B0. -->\n <svg viewBox=\"0 0 18 18\" focusable=\"false\">\n <path fill-rule=\"evenodd\" transform=\"rotate(45 9 9)\"\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\n </svg>\n </span>\n }\n</div>\n\n<ng-content />\n\n@if (validationError(); as error) {\n @if (focused()) {\n <div class=\"nxe-invalid-message\">{{ error }}</div>\n }\n}\n\n<ng-template #dropdown>\n <div class=\"nxe-autocomplete-box-panel\" [style.width.px]=\"panelWidth()\"\n [id]=\"panelId()\"\n role=\"listbox\">\n @for (item of suggestions(); track $index; let i = $index) {\n <div\n class=\"nxe-list-item\"\n [id]=\"optionId(i)\"\n role=\"option\"\n [attr.aria-selected]=\"i === activeIndex()\"\n [class.nxe-list-item-active]=\"i === activeIndex()\"\n (mousedown)=\"pick(item, $event)\">\n {{ itemText(item) }}\n </div>\n }\n </div>\n</ng-template>\n", styles: ["nxe-auto-complete .nxe-select-clear{box-sizing:border-box;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:0;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-auto-complete .nxe-select-clear svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete .nxe-select-arrow{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-auto-complete .nxe-select-arrow svg{display:block;width:18px;height:18px;fill:currentColor}nxe-auto-complete:hover:not(.nxe-disabled) .nxe-select-arrow,nxe-auto-complete:active:not(.nxe-disabled) .nxe-select-arrow{background-color:var(--nxe-ui-neutral-150, #e6e6e6)}nxe-auto-complete.nxe-open .nxe-select-arrow{background-color:var(--nxe-ui-neutral-350, #b3b3b3)}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow) .nxe-editor-input{padding-inline-end:0}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear),nxe-auto-complete .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 38px}nxe-auto-complete .nxe-editor-container:has(>.nxe-select-clear):has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 72px}.nxe-autocomplete-box-panel{max-height:300px;overflow-y:auto;background:var(--nxe-ui-surface, #fff);border:1px solid var(--nxe-ui-border, #ddd);box-sizing:border-box}\n"] }]
1058
1346
  }], propDecorators: { dropdownTemplate: [{ type: i0.ViewChild, args: ['dropdown', { isSignal: true }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], valueExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueExpr", required: false }] }], searchExprInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchExpr", required: false }] }], searchMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchMode", required: false }] }], minSearchLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSearchLength", required: false }] }], maxItemCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxItemCount", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], onSelectionChanged: [{ type: i0.Output, args: ["onSelectionChanged"] }] } });
1059
1347
 
1060
1348
  /** DI token the autocomplete provides so projected `nxe-option`s can close it on click. */
@@ -1213,5 +1501,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
1213
1501
  * Generated bundle index. Do not edit.
1214
1502
  */
1215
1503
 
1216
- export { NXE_AUTOCOMPLETE, NxeAutoCompleteComponent, NxeAutocompleteComponent, NxeAutocompleteTriggerDirective, NxeDropDownBoxComponent, NxeDropDownOptionsComponent, NxeListComponent, NxeOptionComponent, NxeSelectBoxComponent, NxeTagBoxComponent };
1504
+ export { NXE_AUTOCOMPLETE, NXE_MENU, NxeAutoCompleteComponent, NxeAutocompleteComponent, NxeAutocompleteTriggerDirective, NxeDropDownBoxComponent, NxeDropDownOptionsComponent, NxeListComponent, NxeOptionComponent, NxePickerSearch, NxeSelectBoxComponent, NxeTagBoxComponent, nxeIsPickerStore };
1217
1505
  //# sourceMappingURL=nexterajs-ui-dropdowns.mjs.map