@nexterajs/ui 0.0.1 → 0.0.2
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.
- package/fesm2022/nexterajs-ui-core.mjs +189 -5
- package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-dropdowns.mjs +314 -50
- package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-file-uploader.mjs +6 -3
- package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-forms.mjs +729 -370
- package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-grid.mjs +1188 -208
- package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-intl.mjs +15 -5
- package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-notify.mjs +351 -0
- package/fesm2022/nexterajs-ui-notify.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-pivot.mjs +146 -116
- package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-styling.mjs +568 -3
- package/fesm2022/nexterajs-ui-styling.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-tree-view.mjs +147 -18
- package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-validation.mjs +247 -92
- package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
- package/fesm2022/nexterajs-ui.mjs +1 -0
- package/fesm2022/nexterajs-ui.mjs.map +1 -1
- package/package.json +5 -1
- package/styles/_dropdown.scss +149 -0
- package/styles/_editor.scss +23 -4
- package/styles/_icons.scss +92 -0
- package/styles/_mixins.scss +104 -1
- package/styles/_scrollbar.scss +134 -0
- package/styles/_toast.scss +243 -0
- package/styles/_tokens.scss +48 -0
- package/styles/index.scss +4 -0
- package/types/nexterajs-ui-core.d.ts +142 -22
- package/types/nexterajs-ui-dropdowns.d.ts +145 -27
- package/types/nexterajs-ui-file-uploader.d.ts +4 -1
- package/types/nexterajs-ui-forms.d.ts +103 -19
- package/types/nexterajs-ui-grid.d.ts +445 -57
- package/types/nexterajs-ui-notify.d.ts +147 -0
- package/types/nexterajs-ui-pivot.d.ts +35 -22
- package/types/nexterajs-ui-styling.d.ts +163 -3
- package/types/nexterajs-ui-tree-view.d.ts +50 -1
- package/types/nexterajs-ui-validation.d.ts +94 -15
- package/types/nexterajs-ui.d.ts +1 -0
|
@@ -5,7 +5,7 @@ import * as i0 from '@angular/core';
|
|
|
5
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';
|
|
6
6
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
7
7
|
import { merge, filter, distinctUntilChanged, Subject } from 'rxjs';
|
|
8
|
-
import { NxeFormControlBase, NxeTemplateDirective, nxeOptionalBoolean, NXE_VALIDATION_TARGET } from '@nexterajs/ui/core';
|
|
8
|
+
import { NxeFormControlBase, NxeTemplateDirective, nxeOptionalBoolean, nxeResolveText, nxeResolveExpr, NXE_VALIDATION_TARGET } from '@nexterajs/ui/core';
|
|
9
9
|
import { nxePane, trackPaneFlip } from '@nexterajs/ui/styling';
|
|
10
10
|
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
11
11
|
|
|
@@ -14,10 +14,11 @@ import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
|
14
14
|
*
|
|
15
15
|
* A signal-CVA single-select dropdown over a plain array (`[dataSource]`). It bakes in the app's
|
|
16
16
|
* global `dxSelectBox.defaultOptions` (`displayExpr='lovName'`, `valueExpr='lovCode'`,
|
|
17
|
-
* `searchEnabled
|
|
18
|
-
*
|
|
19
|
-
* an in-field search filter. Emits `(valueChange)` (the code) and
|
|
20
|
-
* (`{selectedItem}`). Hosts a projected `nxe-validator` via
|
|
17
|
+
* `searchEnabled`), so the bound control value is the `valueExpr` field (a string code) and the
|
|
18
|
+
* field shows the `displayExpr` field. The clear button follows dx and is off unless asked for.
|
|
19
|
+
* Dropdown is a CDK overlay with an in-field search filter. Emits `(valueChange)` (the code) and
|
|
20
|
+
* `(onSelectionChanged)` (`{selectedItem}`). Hosts a projected `nxe-validator` via
|
|
21
|
+
* {@link NXE_VALIDATION_TARGET}.
|
|
21
22
|
*/
|
|
22
23
|
class NxeSelectBoxComponent extends NxeFormControlBase {
|
|
23
24
|
overlay = inject(Overlay);
|
|
@@ -41,13 +42,24 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
|
|
|
41
42
|
...(ngDevMode ? [{ debugName: "valueExpr" }] : /* istanbul ignore next */ []));
|
|
42
43
|
/** Field matched while searching (DevExtreme default `lovName`). */
|
|
43
44
|
searchExprInput = input(undefined, { ...(ngDevMode ? { debugName: "searchExprInput" } : /* istanbul ignore next */ {}), alias: 'searchExpr' });
|
|
44
|
-
|
|
45
|
+
/**
|
|
46
|
+
* dx searches by `displayExpr` when `searchExpr` is not given. Defaulting to the literal
|
|
47
|
+
* 'lovName' instead meant that any picker with a custom displayExpr searched a field its
|
|
48
|
+
* items do not have, and found nothing - silently, because an empty result looks like no
|
|
49
|
+
* match. Where displayExpr is the default this resolves to 'lovName' exactly as before.
|
|
50
|
+
*/
|
|
51
|
+
searchExpr = computed(() => this.searchExprInput() ?? this.nxeDefaults.selectBox?.searchExpr ?? this.displayExpr(), /* @ts-ignore */
|
|
45
52
|
...(ngDevMode ? [{ debugName: "searchExpr" }] : /* istanbul ignore next */ []));
|
|
46
53
|
searchEnabledInput = input(undefined, { ...(ngDevMode ? { debugName: "searchEnabledInput" } : /* istanbul ignore next */ {}), alias: 'searchEnabled', transform: nxeOptionalBoolean });
|
|
47
54
|
searchEnabled = computed(() => this.searchEnabledInput() ?? this.nxeDefaults.selectBox?.searchEnabled ?? true, /* @ts-ignore */
|
|
48
55
|
...(ngDevMode ? [{ debugName: "searchEnabled" }] : /* istanbul ignore next */ []));
|
|
49
56
|
showClearButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showClearButtonInput" } : /* istanbul ignore next */ {}), alias: 'showClearButton', transform: nxeOptionalBoolean });
|
|
50
|
-
|
|
57
|
+
/**
|
|
58
|
+
* dx defaults `showClearButton` to false (m_text_editor.base.js). The library used to default it
|
|
59
|
+
* on, which gave every host that never asked for one a clear button dx would not show. An app
|
|
60
|
+
* that wants it everywhere says so once through `NXE_DEFAULT_OPTIONS.selectBox.showClearButton`.
|
|
61
|
+
*/
|
|
62
|
+
showClearButton = computed(() => this.showClearButtonInput() ?? this.nxeDefaults.selectBox?.showClearButton ?? false, /* @ts-ignore */
|
|
51
63
|
...(ngDevMode ? [{ debugName: "showClearButton" }] : /* istanbul ignore next */ []));
|
|
52
64
|
/** dx parity: dx-select-box shows its drop-down arrow unless showDropDownButton=false. */
|
|
53
65
|
showDropDownButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showDropDownButtonInput" } : /* istanbul ignore next */ {}), alias: 'showDropDownButton', transform: nxeOptionalBoolean });
|
|
@@ -86,15 +98,10 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
|
|
|
86
98
|
items = computed(() => this.dataSource() ?? [], /* @ts-ignore */
|
|
87
99
|
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
88
100
|
display(item) {
|
|
89
|
-
|
|
90
|
-
if (!expr) {
|
|
91
|
-
return item == null ? '' : String(item);
|
|
92
|
-
}
|
|
93
|
-
return item?.[expr] ?? '';
|
|
101
|
+
return nxeResolveText(this.displayExpr(), item);
|
|
94
102
|
}
|
|
95
103
|
extractValue(item) {
|
|
96
|
-
|
|
97
|
-
return expr ? item?.[expr] : item;
|
|
104
|
+
return nxeResolveExpr(this.valueExpr(), item);
|
|
98
105
|
}
|
|
99
106
|
selectedItem = computed(() => {
|
|
100
107
|
const v = this.value();
|
|
@@ -124,12 +131,9 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
|
|
|
124
131
|
if (!this.searchEnabled() || !search) {
|
|
125
132
|
return items;
|
|
126
133
|
}
|
|
127
|
-
const expr = this.searchExpr()
|
|
134
|
+
const expr = this.searchExpr();
|
|
128
135
|
const needle = search.toLowerCase();
|
|
129
|
-
return items.filter((it) =>
|
|
130
|
-
const hay = (expr ? it?.[expr] : it) ?? '';
|
|
131
|
-
return String(hay).toLowerCase().includes(needle);
|
|
132
|
-
});
|
|
136
|
+
return items.filter((it) => nxeResolveText(expr, it).toLowerCase().includes(needle));
|
|
133
137
|
}, /* @ts-ignore */
|
|
134
138
|
...(ngDevMode ? [{ debugName: "filteredItems" }] : /* istanbul ignore next */ []));
|
|
135
139
|
itemTemplateRef = computed(() => this.templates().find((t) => t.name() === this.itemTemplate())?.templateRef ?? null, /* @ts-ignore */
|
|
@@ -267,7 +271,7 @@ class NxeSelectBoxComponent extends NxeFormControlBase {
|
|
|
267
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: [
|
|
268
272
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeSelectBoxComponent), multi: true },
|
|
269
273
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeSelectBoxComponent) },
|
|
270
|
-
], 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 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 <svg viewBox=\"0 0
|
|
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 });
|
|
271
275
|
}
|
|
272
276
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeSelectBoxComponent, decorators: [{
|
|
273
277
|
type: Component,
|
|
@@ -280,15 +284,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
280
284
|
}, providers: [
|
|
281
285
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeSelectBoxComponent), multi: true },
|
|
282
286
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeSelectBoxComponent) },
|
|
283
|
-
], 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 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 <svg viewBox=\"0 0
|
|
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"] }]
|
|
284
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"] }] } });
|
|
285
289
|
|
|
286
290
|
/**
|
|
287
291
|
* `nxe-tag-box` — drop-in replacement for DevExtreme `dx-tag-box` (multi-select sibling of
|
|
288
292
|
* `nxe-select-box`). The bound value is an **array of `valueExpr` keys** (`lovCode` strings).
|
|
289
293
|
* Bakes in the app's global `dxTagBox.defaultOptions` (display/search `lovName`, value `lovCode`,
|
|
290
|
-
* search +
|
|
291
|
-
*
|
|
294
|
+
* search + selection-controls on); the clear button follows dx and is off unless asked for.
|
|
295
|
+
* Selected items render as removable chips; with selection controls the dropdown shows a checkbox
|
|
296
|
+
* per row under a tri-state "Select All". Provides {@link NXE_VALIDATION_TARGET} for a projected
|
|
297
|
+
* `nxe-validator`.
|
|
292
298
|
*/
|
|
293
299
|
class NxeTagBoxComponent extends NxeFormControlBase {
|
|
294
300
|
overlay = inject(Overlay);
|
|
@@ -306,14 +312,37 @@ class NxeTagBoxComponent extends NxeFormControlBase {
|
|
|
306
312
|
valueExpr = computed(() => this.valueExprInput() ?? this.nxeDefaults.tagBox?.valueExpr ?? 'lovCode', /* @ts-ignore */
|
|
307
313
|
...(ngDevMode ? [{ debugName: "valueExpr" }] : /* istanbul ignore next */ []));
|
|
308
314
|
searchExprInput = input(undefined, { ...(ngDevMode ? { debugName: "searchExprInput" } : /* istanbul ignore next */ {}), alias: 'searchExpr' });
|
|
309
|
-
|
|
315
|
+
/**
|
|
316
|
+
* dx searches by `displayExpr` when `searchExpr` is not given. Defaulting to the literal
|
|
317
|
+
* 'lovName' instead meant that any picker with a custom displayExpr searched a field its
|
|
318
|
+
* items do not have, and found nothing - silently, because an empty result looks like no
|
|
319
|
+
* match. Where displayExpr is the default this resolves to 'lovName' exactly as before.
|
|
320
|
+
*/
|
|
321
|
+
searchExpr = computed(() => this.searchExprInput() ?? this.nxeDefaults.tagBox?.searchExpr ?? this.displayExpr(), /* @ts-ignore */
|
|
310
322
|
...(ngDevMode ? [{ debugName: "searchExpr" }] : /* istanbul ignore next */ []));
|
|
311
323
|
searchEnabledInput = input(undefined, { ...(ngDevMode ? { debugName: "searchEnabledInput" } : /* istanbul ignore next */ {}), alias: 'searchEnabled', transform: nxeOptionalBoolean });
|
|
312
324
|
searchEnabled = computed(() => this.searchEnabledInput() ?? this.nxeDefaults.tagBox?.searchEnabled ?? true, /* @ts-ignore */
|
|
313
325
|
...(ngDevMode ? [{ debugName: "searchEnabled" }] : /* istanbul ignore next */ []));
|
|
314
326
|
showClearButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showClearButtonInput" } : /* istanbul ignore next */ {}), alias: 'showClearButton', transform: nxeOptionalBoolean });
|
|
315
|
-
|
|
327
|
+
/**
|
|
328
|
+
* dx defaults `showClearButton` to false (m_text_editor.base.js). The library used to default it
|
|
329
|
+
* on, which gave every host that never asked for one a clear button dx would not show. An app
|
|
330
|
+
* that wants it everywhere says so once through `NXE_DEFAULT_OPTIONS.tagBox.showClearButton`.
|
|
331
|
+
*/
|
|
332
|
+
showClearButton = computed(() => this.showClearButtonInput() ?? this.nxeDefaults.tagBox?.showClearButton ?? false, /* @ts-ignore */
|
|
316
333
|
...(ngDevMode ? [{ debugName: "showClearButton" }] : /* istanbul ignore next */ []));
|
|
334
|
+
showSelectionControlsInput = input(undefined, { ...(ngDevMode ? { debugName: "showSelectionControlsInput" } : /* istanbul ignore next */ {}), alias: 'showSelectionControls', transform: nxeOptionalBoolean });
|
|
335
|
+
/**
|
|
336
|
+
* dx `showSelectionControls`. On (the literal, and what every consumer site passes): a checkbox
|
|
337
|
+
* per row and a tri-state "Select All" row — dx switches its list to `selectionMode: 'all'`
|
|
338
|
+
* (m_tag_box.js `_listConfig`). Off: plain rows whose fill marks the selection
|
|
339
|
+
* (`selectionMode: 'multiple'`).
|
|
340
|
+
*/
|
|
341
|
+
showSelectionControls = computed(() => this.showSelectionControlsInput() ?? this.nxeDefaults.tagBox?.showSelectionControls ?? true, /* @ts-ignore */
|
|
342
|
+
...(ngDevMode ? [{ debugName: "showSelectionControls" }] : /* istanbul ignore next */ []));
|
|
343
|
+
/** dx `selectAllText` — the label of the "Select All" row (dx: `dxList-selectAll`). */
|
|
344
|
+
selectAllText = input('Select All', /* @ts-ignore */
|
|
345
|
+
...(ngDevMode ? [{ debugName: "selectAllText" }] : /* istanbul ignore next */ []));
|
|
317
346
|
/** dx parity: dx-tag-box does NOT show a drop-down arrow unless showDropDownButton is set. */
|
|
318
347
|
showDropDownButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showDropDownButtonInput" } : /* istanbul ignore next */ {}), alias: 'showDropDownButton', transform: nxeOptionalBoolean });
|
|
319
348
|
showDropDownButton = computed(() => this.showDropDownButtonInput() ?? this.nxeDefaults.tagBox?.showDropDownButton ?? false, /* @ts-ignore */
|
|
@@ -341,15 +370,10 @@ class NxeTagBoxComponent extends NxeFormControlBase {
|
|
|
341
370
|
}, /* @ts-ignore */
|
|
342
371
|
...(ngDevMode ? [{ debugName: "selectedKeys" }] : /* istanbul ignore next */ []));
|
|
343
372
|
display(item) {
|
|
344
|
-
|
|
345
|
-
if (!expr) {
|
|
346
|
-
return item == null ? '' : String(item);
|
|
347
|
-
}
|
|
348
|
-
return item?.[expr] ?? '';
|
|
373
|
+
return nxeResolveText(this.displayExpr(), item);
|
|
349
374
|
}
|
|
350
375
|
extractValue(item) {
|
|
351
|
-
|
|
352
|
-
return expr ? item?.[expr] : item;
|
|
376
|
+
return nxeResolveExpr(this.valueExpr(), item);
|
|
353
377
|
}
|
|
354
378
|
/** Selected items resolved from the value keys (for chip rendering). */
|
|
355
379
|
selectedItems = computed(() => {
|
|
@@ -365,17 +389,29 @@ class NxeTagBoxComponent extends NxeFormControlBase {
|
|
|
365
389
|
if (!this.searchEnabled() || !search) {
|
|
366
390
|
return items;
|
|
367
391
|
}
|
|
368
|
-
const expr = this.searchExpr()
|
|
392
|
+
const expr = this.searchExpr();
|
|
369
393
|
const needle = search.toLowerCase();
|
|
370
|
-
return items.filter((it) =>
|
|
371
|
-
const hay = (expr ? it?.[expr] : it) ?? '';
|
|
372
|
-
return String(hay).toLowerCase().includes(needle);
|
|
373
|
-
});
|
|
394
|
+
return items.filter((it) => nxeResolveText(expr, it).toLowerCase().includes(needle));
|
|
374
395
|
}, /* @ts-ignore */
|
|
375
396
|
...(ngDevMode ? [{ debugName: "filteredItems" }] : /* istanbul ignore next */ []));
|
|
376
397
|
isSelected(item) {
|
|
377
398
|
return this.selectedKeys().includes(this.extractValue(item));
|
|
378
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* The "Select All" checkbox value over the rows currently listed — dx `selectAllMode: 'page'`,
|
|
402
|
+
* so a search narrows what it counts: `true` when every listed row is selected, `false` when
|
|
403
|
+
* none is, and `undefined` (indeterminate) in between.
|
|
404
|
+
*/
|
|
405
|
+
selectAllState = computed(() => {
|
|
406
|
+
const items = this.filteredItems();
|
|
407
|
+
const keys = this.selectedKeys();
|
|
408
|
+
const selected = items.filter((it) => keys.includes(this.extractValue(it))).length;
|
|
409
|
+
if (selected === 0) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
return selected === items.length ? true : undefined;
|
|
413
|
+
}, /* @ts-ignore */
|
|
414
|
+
...(ngDevMode ? [{ debugName: "selectAllState" }] : /* istanbul ignore next */ []));
|
|
379
415
|
onFieldMousedown(event) {
|
|
380
416
|
if (this.readOnly() || this.disabled()) {
|
|
381
417
|
return;
|
|
@@ -411,7 +447,24 @@ class NxeTagBoxComponent extends NxeFormControlBase {
|
|
|
411
447
|
input.value = '';
|
|
412
448
|
}
|
|
413
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* dx `_selectAllHandler`: anything short of all-selected selects every listed row (keeping
|
|
452
|
+
* selections the search hides); all-selected deselects the listed rows only.
|
|
453
|
+
*/
|
|
454
|
+
toggleAll(event) {
|
|
455
|
+
event.preventDefault();
|
|
456
|
+
const listed = this.filteredItems().map((it) => this.extractValue(it));
|
|
457
|
+
const keys = this.selectedKeys();
|
|
458
|
+
const next = this.selectAllState() === true
|
|
459
|
+
? keys.filter((k) => !listed.includes(k))
|
|
460
|
+
: [...keys, ...listed.filter((k) => !keys.includes(k))];
|
|
461
|
+
this.commitValue(next, event);
|
|
462
|
+
}
|
|
414
463
|
removeTag(item, event) {
|
|
464
|
+
// The × stays rendered in readOnly/disabled, as dx's does; its action is what is withheld.
|
|
465
|
+
if (this.readOnly() || this.disabled()) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
415
468
|
event.preventDefault();
|
|
416
469
|
event.stopPropagation();
|
|
417
470
|
const key = this.extractValue(item);
|
|
@@ -469,10 +522,10 @@ class NxeTagBoxComponent extends NxeFormControlBase {
|
|
|
469
522
|
this.overlayRef?.dispose();
|
|
470
523
|
}
|
|
471
524
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTagBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
472
|
-
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 }, 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: [
|
|
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: [
|
|
473
526
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeTagBoxComponent), multi: true },
|
|
474
527
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeTagBoxComponent) },
|
|
475
|
-
], 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 nxe-tag-container\" (mousedown)=\"onFieldMousedown($event)\">\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 @if (!readOnly() && !disabled()) {\r\n <span class=\"nxe-tag-remove\" (mousedown)=\"removeTag(item, $event)\" aria-hidden=\"true\"></span>\r\n }\r\n </span>\r\n }\r\n\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-tag-input\"\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\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <svg viewBox=\"0 0 24 24\"><path d=\"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" /></svg>\r\n </span>\r\n }\r\n @if (showDropDownButton() && !readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <svg viewBox=\"0 0 24 24\"><path d=\"M7 10l5 5 5-5z\" /></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 @for (item of filteredItems(); track $index) {\r\n <div\r\n class=\"nxe-list-item nxe-tag-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 </div>\r\n</ng-template>\r\n", styles: ["nxe-tag-box{cursor:pointer}nxe-tag-box .nxe-tag-container{flex-wrap:wrap;align-items:center;gap:4px;padding:3px 4px;min-height:36px}nxe-tag-box .nxe-tag-input{flex:1 1 60px;min-width:60px;width:auto;min-height:26px;padding:0 4px}nxe-tag-box .nxe-tag{position:relative;display:inline-flex;align-items:center;max-width:calc(100% - 1px);min-width:40px;padding:3px 25px 4px 6px;background-color:#dcdcdc;border-radius:2px;color:#333;line-height:1.2}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:#a9a9aa}nxe-tag-box .nxe-tag-remove:after{inset-inline-end:5px;margin-top:-1px;width:11px;height:3px}nxe-tag-box .nxe-select-clear,nxe-tag-box .nxe-select-arrow{flex:0 0 auto;align-self:center;display:inline-flex;align-items:center;justify-content:center;color:#333}nxe-tag-box .nxe-select-clear svg,nxe-tag-box .nxe-select-arrow svg{width:16px;height:16px;fill:currentColor}nxe-tag-box .nxe-select-clear{width:22px;color:#999}nxe-tag-box .nxe-select-clear:hover{color:#333}nxe-tag-box .nxe-select-arrow{width:28px}nxe-tag-box .nxe-select-arrow svg{width:18px;height:18px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 32px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear){--nxe-invalid-badge-inset: 26px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow):has(>.nxe-select-clear){--nxe-invalid-badge-inset: 54px}.nxe-tag-item{display:flex;align-items:center;gap:8px}.nxe-tag-check{box-sizing:border-box;position:relative;flex-shrink:0;width:18px;height:18px;border:1px solid #ddd;border-radius:2px;background:#fff}.nxe-tag-check.nxe-tag-checked{border-color:#337ab7}.nxe-tag-check.nxe-tag-checked:after{content:\"\";position:absolute;top:1px;inset-inline-start:5px;width:5px;height:9px;border:solid #337ab7;border-width:0 2px 2px 0;transform:rotate(45deg)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
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 });
|
|
476
529
|
}
|
|
477
530
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTagBoxComponent, decorators: [{
|
|
478
531
|
type: Component,
|
|
@@ -485,8 +538,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
485
538
|
}, providers: [
|
|
486
539
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeTagBoxComponent), multi: true },
|
|
487
540
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeTagBoxComponent) },
|
|
488
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nxe-editor-container nxe-tag-container\" (mousedown)=\"onFieldMousedown($event)\">\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 @if (!readOnly() && !disabled()) {\r\n <span class=\"nxe-tag-remove\" (mousedown)=\"removeTag(item, $event)\" aria-hidden=\"true\"></span>\r\n }\r\n </span>\r\n }\r\n\r\n <input\r\n #input\r\n class=\"nxe-editor-input nxe-tag-input\"\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\r\n @if (showClearButton() && hasValue() && !readOnly() && !disabled()) {\r\n <span class=\"nxe-select-clear\" (mousedown)=\"onClear($event)\" aria-hidden=\"true\">\r\n <svg viewBox=\"0 0 24 24\"><path d=\"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\" /></svg>\r\n </span>\r\n }\r\n @if (showDropDownButton() && !readOnly()) {\r\n <span class=\"nxe-select-arrow\" aria-hidden=\"true\">\r\n <svg viewBox=\"0 0 24 24\"><path d=\"M7 10l5 5 5-5z\" /></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 @for (item of filteredItems(); track $index) {\r\n <div\r\n class=\"nxe-list-item nxe-tag-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 </div>\r\n</ng-template>\r\n", styles: ["nxe-tag-box{cursor:pointer}nxe-tag-box .nxe-tag-container{flex-wrap:wrap;align-items:center;gap:4px;padding:3px 4px;min-height:36px}nxe-tag-box .nxe-tag-input{flex:1 1 60px;min-width:60px;width:auto;min-height:26px;padding:0 4px}nxe-tag-box .nxe-tag{position:relative;display:inline-flex;align-items:center;max-width:calc(100% - 1px);min-width:40px;padding:3px 25px 4px 6px;background-color:#dcdcdc;border-radius:2px;color:#333;line-height:1.2}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:#a9a9aa}nxe-tag-box .nxe-tag-remove:after{inset-inline-end:5px;margin-top:-1px;width:11px;height:3px}nxe-tag-box .nxe-select-clear,nxe-tag-box .nxe-select-arrow{flex:0 0 auto;align-self:center;display:inline-flex;align-items:center;justify-content:center;color:#333}nxe-tag-box .nxe-select-clear svg,nxe-tag-box .nxe-select-arrow svg{width:16px;height:16px;fill:currentColor}nxe-tag-box .nxe-select-clear{width:22px;color:#999}nxe-tag-box .nxe-select-clear:hover{color:#333}nxe-tag-box .nxe-select-arrow{width:28px}nxe-tag-box .nxe-select-arrow svg{width:18px;height:18px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow){--nxe-invalid-badge-inset: 32px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-clear){--nxe-invalid-badge-inset: 26px}nxe-tag-box .nxe-editor-container:has(>.nxe-select-arrow):has(>.nxe-select-clear){--nxe-invalid-badge-inset: 54px}.nxe-tag-item{display:flex;align-items:center;gap:8px}.nxe-tag-check{box-sizing:border-box;position:relative;flex-shrink:0;width:18px;height:18px;border:1px solid #ddd;border-radius:2px;background:#fff}.nxe-tag-check.nxe-tag-checked{border-color:#337ab7}.nxe-tag-check.nxe-tag-checked:after{content:\"\";position:absolute;top:1px;inset-inline-start:5px;width:5px;height:9px;border:solid #337ab7;border-width:0 2px 2px 0;transform:rotate(45deg)}\n"] }]
|
|
489
|
-
}], 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 }] }], showDropDownButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropDownButton", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }] } });
|
|
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 }] }] } });
|
|
490
543
|
|
|
491
544
|
/**
|
|
492
545
|
* `nxe-drop-down-options` — drop-in for DevExtreme `dxo-drop-down-options`, a no-template config
|
|
@@ -621,8 +674,8 @@ class NxeDropDownBoxComponent extends NxeFormControlBase {
|
|
|
621
674
|
}
|
|
622
675
|
// The bound value is the code; match it against valueExpr (default the implicit `lovCode`).
|
|
623
676
|
const ve = this.valueExpr() || 'lovCode';
|
|
624
|
-
const item = (this.dataSource() ?? []).find((it) =>
|
|
625
|
-
return item ?
|
|
677
|
+
const item = (this.dataSource() ?? []).find((it) => nxeResolveExpr(ve, it) === v);
|
|
678
|
+
return item ? nxeResolveText(de, item) : String(v);
|
|
626
679
|
}, /* @ts-ignore */
|
|
627
680
|
...(ngDevMode ? [{ debugName: "displayText" }] : /* istanbul ignore next */ []));
|
|
628
681
|
hasValue = computed(() => {
|
|
@@ -694,7 +747,7 @@ class NxeDropDownBoxComponent extends NxeFormControlBase {
|
|
|
694
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: [
|
|
695
748
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeDropDownBoxComponent), multi: true },
|
|
696
749
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeDropDownBoxComponent) },
|
|
697
|
-
], 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 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 <svg viewBox=\"0 0
|
|
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 });
|
|
698
751
|
}
|
|
699
752
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeDropDownBoxComponent, decorators: [{
|
|
700
753
|
type: Component,
|
|
@@ -706,7 +759,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
706
759
|
}, providers: [
|
|
707
760
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeDropDownBoxComponent), multi: true },
|
|
708
761
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeDropDownBoxComponent) },
|
|
709
|
-
], 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 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 <svg viewBox=\"0 0
|
|
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"] }]
|
|
710
763
|
}], 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"] }] } });
|
|
711
764
|
|
|
712
765
|
/** DI token the menu provides so projected `nxe-menu-item`s can close it on click. */
|
|
@@ -731,6 +784,20 @@ class NxeListComponent {
|
|
|
731
784
|
/** DevExtreme `[elementAttr]` — `{ id, class }` applied to the host. */
|
|
732
785
|
elementAttr = input(/* @ts-ignore */
|
|
733
786
|
...(ngDevMode ? [undefined, { debugName: "elementAttr" }] : /* istanbul ignore next */ []));
|
|
787
|
+
/**
|
|
788
|
+
* dx `keyExpr` — the field identifying an item. Used for `@for` tracking, so a list whose
|
|
789
|
+
* items are replaced by equal-but-not-identical objects keeps its DOM instead of rebuilding
|
|
790
|
+
* every row. Falls back to the index when unset, which is the previous behaviour.
|
|
791
|
+
*/
|
|
792
|
+
keyExpr = input(undefined, /* @ts-ignore */
|
|
793
|
+
...(ngDevMode ? [{ debugName: "keyExpr" }] : /* istanbul ignore next */ []));
|
|
794
|
+
trackItem(item, index) {
|
|
795
|
+
const key = this.keyExpr();
|
|
796
|
+
if (!key || item == null || typeof item !== 'object') {
|
|
797
|
+
return index;
|
|
798
|
+
}
|
|
799
|
+
return item[key] ?? index;
|
|
800
|
+
}
|
|
734
801
|
onItemClick = output();
|
|
735
802
|
items = computed(() => this.dataSource() ?? [], /* @ts-ignore */
|
|
736
803
|
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
@@ -751,8 +818,8 @@ class NxeListComponent {
|
|
|
751
818
|
this.menu?.closeMenu();
|
|
752
819
|
}
|
|
753
820
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
754
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeListComponent, isStandalone: true, selector: "nxe-list", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, elementAttr: { classPropertyName: "elementAttr", publicName: "elementAttr", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick" }, host: { properties: { "class": "'nxe-widget nxe-list ' + (elementAttr()?.class ?? '')", "attr.id": "elementAttr()?.id ?? null" } }, queries: [{ propertyName: "templates", predicate: NxeTemplateDirective, isSignal: true }], ngImport: i0, template: `
|
|
755
|
-
@for (item of items(); track $index; let last = $last) {
|
|
821
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeListComponent, isStandalone: true, selector: "nxe-list", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, elementAttr: { classPropertyName: "elementAttr", publicName: "elementAttr", isSignal: true, isRequired: false, transformFunction: null }, keyExpr: { classPropertyName: "keyExpr", publicName: "keyExpr", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick" }, host: { properties: { "class": "'nxe-widget nxe-list ' + (elementAttr()?.class ?? '')", "attr.id": "elementAttr()?.id ?? null" } }, queries: [{ propertyName: "templates", predicate: NxeTemplateDirective, isSignal: true }], ngImport: i0, template: `
|
|
822
|
+
@for (item of items(); track trackItem(item, $index); let last = $last) {
|
|
756
823
|
<div
|
|
757
824
|
class="nxe-list-item-row"
|
|
758
825
|
[class.nxe-state-disabled]="isDisabled(item)"
|
|
@@ -772,7 +839,7 @@ class NxeListComponent {
|
|
|
772
839
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeListComponent, decorators: [{
|
|
773
840
|
type: Component,
|
|
774
841
|
args: [{ selector: 'nxe-list', standalone: true, imports: [NgTemplateOutlet], template: `
|
|
775
|
-
@for (item of items(); track $index; let last = $last) {
|
|
842
|
+
@for (item of items(); track trackItem(item, $index); let last = $last) {
|
|
776
843
|
<div
|
|
777
844
|
class="nxe-list-item-row"
|
|
778
845
|
[class.nxe-state-disabled]="isDisabled(item)"
|
|
@@ -791,7 +858,204 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
791
858
|
'[class]': "'nxe-widget nxe-list ' + (elementAttr()?.class ?? '')",
|
|
792
859
|
'[attr.id]': 'elementAttr()?.id ?? null',
|
|
793
860
|
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-list{display:block}nxe-list .nxe-list-item-row{display:block;cursor:pointer}nxe-list .nxe-list-item-row.nxe-state-disabled{opacity:.5;cursor:default;-webkit-user-select:none;user-select:none}nxe-list .nxe-list-item-content{display:block}\n"] }]
|
|
794
|
-
}], propDecorators: { templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeTemplateDirective), { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], elementAttr: [{ type: i0.Input, args: [{ isSignal: true, alias: "elementAttr", required: false }] }], onItemClick: [{ type: i0.Output, args: ["onItemClick"] }] } });
|
|
861
|
+
}], propDecorators: { templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeTemplateDirective), { isSignal: true }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], elementAttr: [{ type: i0.Input, args: [{ isSignal: true, alias: "elementAttr", required: false }] }], keyExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyExpr", required: false }] }], onItemClick: [{ type: i0.Output, args: ["onItemClick"] }] } });
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* `nxe-auto-complete` — drop-in replacement for DevExtreme `dx-autocomplete`.
|
|
865
|
+
*
|
|
866
|
+
* The distinction from `nxe-select-box` is the value contract, and it is the whole reason this
|
|
867
|
+
* is a separate component: here the control value is the TEXT the user typed. A suggestion is a
|
|
868
|
+
* shortcut for typing, not a constraint on what may be entered, so free text survives and
|
|
869
|
+
* `valueExpr` only says which field of a picked item becomes that text.
|
|
870
|
+
*
|
|
871
|
+
* Deliberately not merged into the existing Material-shaped `nxe-autocomplete`: that one takes
|
|
872
|
+
* projected `nxe-option` children rather than a `[dataSource]`, so the two have incompatible
|
|
873
|
+
* content models and merging them would make every future change to one a risk to the other.
|
|
874
|
+
*/
|
|
875
|
+
class NxeAutoCompleteComponent extends NxeFormControlBase {
|
|
876
|
+
overlay = inject(Overlay);
|
|
877
|
+
viewContainerRef = inject(ViewContainerRef);
|
|
878
|
+
dropdownTemplate = viewChild.required('dropdown', /* @ts-ignore */
|
|
879
|
+
...(ngDevMode ? [{ debugName: "dropdownTemplate" }] : /* istanbul ignore next */ []));
|
|
880
|
+
inputEl = viewChild('input', /* @ts-ignore */
|
|
881
|
+
...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
|
|
882
|
+
dataSource = input([], /* @ts-ignore */
|
|
883
|
+
...(ngDevMode ? [{ debugName: "dataSource" }] : /* istanbul ignore next */ []));
|
|
884
|
+
/** Field of a picked item that becomes the value (dx default `lovName`). */
|
|
885
|
+
valueExpr = input('lovName', /* @ts-ignore */
|
|
886
|
+
...(ngDevMode ? [{ debugName: "valueExpr" }] : /* istanbul ignore next */ []));
|
|
887
|
+
/** Field matched against the query; defaults to {@link valueExpr}, as dx does. */
|
|
888
|
+
searchExprInput = input(undefined, { ...(ngDevMode ? { debugName: "searchExprInput" } : /* istanbul ignore next */ {}), alias: 'searchExpr' });
|
|
889
|
+
searchExpr = computed(() => this.searchExprInput() ?? this.valueExpr(), /* @ts-ignore */
|
|
890
|
+
...(ngDevMode ? [{ debugName: "searchExpr" }] : /* istanbul ignore next */ []));
|
|
891
|
+
searchMode = input('contains', /* @ts-ignore */
|
|
892
|
+
...(ngDevMode ? [{ debugName: "searchMode" }] : /* istanbul ignore next */ []));
|
|
893
|
+
/** Characters required before suggestions appear. dx defaults to 1; 0 shows all on focus. */
|
|
894
|
+
minSearchLength = input(1, /* @ts-ignore */
|
|
895
|
+
...(ngDevMode ? [{ debugName: "minSearchLength" }] : /* istanbul ignore next */ []));
|
|
896
|
+
/** dx caps the suggestion list; beyond this the user is expected to keep typing. */
|
|
897
|
+
maxItemCount = input(10, /* @ts-ignore */
|
|
898
|
+
...(ngDevMode ? [{ debugName: "maxItemCount" }] : /* istanbul ignore next */ []));
|
|
899
|
+
placeholder = input('', /* @ts-ignore */
|
|
900
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
901
|
+
showClearButton = input(false, { ...(ngDevMode ? { debugName: "showClearButton" } : /* istanbul ignore next */ {}), transform: nxeOptionalBoolean });
|
|
902
|
+
onSelectionChanged = output();
|
|
903
|
+
focused = signal(false, /* @ts-ignore */
|
|
904
|
+
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
|
|
905
|
+
open = signal(false, /* @ts-ignore */
|
|
906
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
907
|
+
activeIndex = signal(-1, /* @ts-ignore */
|
|
908
|
+
...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
909
|
+
panelWidth = signal(0, /* @ts-ignore */
|
|
910
|
+
...(ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []));
|
|
911
|
+
/** dx `.instance` facade — `focus()` is what the autofocus directive calls. */
|
|
912
|
+
get instance() {
|
|
913
|
+
return this;
|
|
914
|
+
}
|
|
915
|
+
overlayRef;
|
|
916
|
+
closeSub;
|
|
917
|
+
flipSub;
|
|
918
|
+
text = computed(() => this.value() ?? '', /* @ts-ignore */
|
|
919
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
920
|
+
itemText(item) {
|
|
921
|
+
return nxeResolveText(this.valueExpr(), item);
|
|
922
|
+
}
|
|
923
|
+
searchText(item) {
|
|
924
|
+
return nxeResolveText(this.searchExpr(), item);
|
|
925
|
+
}
|
|
926
|
+
suggestions = computed(() => {
|
|
927
|
+
const query = (this.value() ?? '').toLowerCase();
|
|
928
|
+
if (query.length < this.minSearchLength()) {
|
|
929
|
+
return [];
|
|
930
|
+
}
|
|
931
|
+
const mode = this.searchMode();
|
|
932
|
+
const matches = (this.dataSource() ?? []).filter((item) => {
|
|
933
|
+
const candidate = this.searchText(item).toLowerCase();
|
|
934
|
+
if (mode === 'startswith') {
|
|
935
|
+
return candidate.startsWith(query);
|
|
936
|
+
}
|
|
937
|
+
if (mode === 'equals') {
|
|
938
|
+
return candidate === query;
|
|
939
|
+
}
|
|
940
|
+
return candidate.includes(query);
|
|
941
|
+
});
|
|
942
|
+
return matches.slice(0, this.maxItemCount());
|
|
943
|
+
}, /* @ts-ignore */
|
|
944
|
+
...(ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []));
|
|
945
|
+
onFieldInput(event) {
|
|
946
|
+
// The typed text IS the value: an autocomplete constrains nothing.
|
|
947
|
+
this.commitValue(event.target.value, event);
|
|
948
|
+
this.activeIndex.set(-1);
|
|
949
|
+
this.openPanel();
|
|
950
|
+
}
|
|
951
|
+
onFocus() {
|
|
952
|
+
this.focused.set(true);
|
|
953
|
+
this.openPanel();
|
|
954
|
+
}
|
|
955
|
+
onBlur() {
|
|
956
|
+
this.focused.set(false);
|
|
957
|
+
this.markAsTouched();
|
|
958
|
+
this.closePanel();
|
|
959
|
+
}
|
|
960
|
+
pick(item, event) {
|
|
961
|
+
event.preventDefault();
|
|
962
|
+
this.commitValue(this.itemText(item), event);
|
|
963
|
+
this.onSelectionChanged.emit({ selectedItem: item, value: this.value() });
|
|
964
|
+
this.closePanel();
|
|
965
|
+
}
|
|
966
|
+
onKeydown(event) {
|
|
967
|
+
if (event.key === 'Escape') {
|
|
968
|
+
this.closePanel();
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const items = this.suggestions();
|
|
972
|
+
if (!items.length) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
if (event.key === 'ArrowDown') {
|
|
976
|
+
event.preventDefault();
|
|
977
|
+
this.openPanel();
|
|
978
|
+
this.activeIndex.update((i) => Math.min(i + 1, items.length - 1));
|
|
979
|
+
}
|
|
980
|
+
else if (event.key === 'ArrowUp') {
|
|
981
|
+
event.preventDefault();
|
|
982
|
+
this.activeIndex.update((i) => Math.max(i - 1, 0));
|
|
983
|
+
}
|
|
984
|
+
else if (event.key === 'Enter' && this.activeIndex() >= 0) {
|
|
985
|
+
this.pick(items[this.activeIndex()], event);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
onClear(event) {
|
|
989
|
+
event.preventDefault();
|
|
990
|
+
this.commitValue('', event);
|
|
991
|
+
this.closePanel();
|
|
992
|
+
}
|
|
993
|
+
focus() {
|
|
994
|
+
this.inputEl()?.nativeElement.focus();
|
|
995
|
+
}
|
|
996
|
+
openPanel() {
|
|
997
|
+
if (this.readOnly() || this.disabled() || !this.suggestions().length) {
|
|
998
|
+
this.closePanel();
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
if (this.overlayRef) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const host = this.element;
|
|
1005
|
+
this.panelWidth.set(host.getBoundingClientRect().width);
|
|
1006
|
+
this.overlayRef = this.overlay.create({
|
|
1007
|
+
positionStrategy: this.overlay
|
|
1008
|
+
.position()
|
|
1009
|
+
.flexibleConnectedTo(host)
|
|
1010
|
+
.withPositions([
|
|
1011
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },
|
|
1012
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },
|
|
1013
|
+
]),
|
|
1014
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
1015
|
+
panelClass: nxePane('nxe-autocomplete-box-pane'),
|
|
1016
|
+
});
|
|
1017
|
+
this.overlayRef.attach(new TemplatePortal(this.dropdownTemplate(), this.viewContainerRef));
|
|
1018
|
+
this.flipSub = trackPaneFlip(this.overlayRef);
|
|
1019
|
+
this.open.set(true);
|
|
1020
|
+
}
|
|
1021
|
+
closePanel() {
|
|
1022
|
+
this.overlayRef?.dispose();
|
|
1023
|
+
this.overlayRef = undefined;
|
|
1024
|
+
this.closeSub?.unsubscribe();
|
|
1025
|
+
this.flipSub?.unsubscribe();
|
|
1026
|
+
this.open.set(false);
|
|
1027
|
+
this.activeIndex.set(-1);
|
|
1028
|
+
}
|
|
1029
|
+
ngOnDestroy() {
|
|
1030
|
+
this.closePanel();
|
|
1031
|
+
}
|
|
1032
|
+
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: [
|
|
1034
|
+
{
|
|
1035
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1036
|
+
useExisting: forwardRef(() => NxeAutoCompleteComponent),
|
|
1037
|
+
multi: true,
|
|
1038
|
+
},
|
|
1039
|
+
{ 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 });
|
|
1041
|
+
}
|
|
1042
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeAutoCompleteComponent, decorators: [{
|
|
1043
|
+
type: Component,
|
|
1044
|
+
args: [{ selector: 'nxe-auto-complete', standalone: true, host: {
|
|
1045
|
+
class: 'nxe-widget nxe-editor nxe-autocomplete-box',
|
|
1046
|
+
'[class.nxe-focused]': 'focused()',
|
|
1047
|
+
'[class.nxe-invalid]': '!!validationError()',
|
|
1048
|
+
'[class.nxe-open]': 'open()',
|
|
1049
|
+
'(keydown)': 'onKeydown($event)',
|
|
1050
|
+
}, providers: [
|
|
1051
|
+
{
|
|
1052
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1053
|
+
useExisting: forwardRef(() => NxeAutoCompleteComponent),
|
|
1054
|
+
multi: true,
|
|
1055
|
+
},
|
|
1056
|
+
{ 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"] }]
|
|
1058
|
+
}], 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"] }] } });
|
|
795
1059
|
|
|
796
1060
|
/** DI token the autocomplete provides so projected `nxe-option`s can close it on click. */
|
|
797
1061
|
const NXE_AUTOCOMPLETE = new InjectionToken('NXE_AUTOCOMPLETE');
|
|
@@ -949,5 +1213,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
949
1213
|
* Generated bundle index. Do not edit.
|
|
950
1214
|
*/
|
|
951
1215
|
|
|
952
|
-
export { NXE_AUTOCOMPLETE, NxeAutocompleteComponent, NxeAutocompleteTriggerDirective, NxeDropDownBoxComponent, NxeDropDownOptionsComponent, NxeListComponent, NxeOptionComponent, NxeSelectBoxComponent, NxeTagBoxComponent };
|
|
1216
|
+
export { NXE_AUTOCOMPLETE, NxeAutoCompleteComponent, NxeAutocompleteComponent, NxeAutocompleteTriggerDirective, NxeDropDownBoxComponent, NxeDropDownOptionsComponent, NxeListComponent, NxeOptionComponent, NxeSelectBoxComponent, NxeTagBoxComponent };
|
|
953
1217
|
//# sourceMappingURL=nexterajs-ui-dropdowns.mjs.map
|