@acorex/components 22.0.0-next.24 → 22.0.0-next.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/combo-box/README.md +24 -1
  2. package/fesm2022/acorex-components-calendar.mjs +2 -2
  3. package/fesm2022/acorex-components-calendar.mjs.map +1 -1
  4. package/fesm2022/acorex-components-color-palette.mjs +2 -2
  5. package/fesm2022/acorex-components-color-palette.mjs.map +1 -1
  6. package/fesm2022/acorex-components-combo-box.mjs +177 -609
  7. package/fesm2022/acorex-components-combo-box.mjs.map +1 -1
  8. package/fesm2022/acorex-components-conversation.mjs +937 -670
  9. package/fesm2022/acorex-components-conversation.mjs.map +1 -1
  10. package/fesm2022/acorex-components-cron-job.mjs +12 -12
  11. package/fesm2022/acorex-components-cron-job.mjs.map +1 -1
  12. package/fesm2022/acorex-components-data-table.mjs +42 -36
  13. package/fesm2022/acorex-components-data-table.mjs.map +1 -1
  14. package/fesm2022/acorex-components-datetime-box.mjs +2 -2
  15. package/fesm2022/acorex-components-datetime-box.mjs.map +1 -1
  16. package/fesm2022/acorex-components-dialog.mjs +3 -2
  17. package/fesm2022/acorex-components-dialog.mjs.map +1 -1
  18. package/fesm2022/acorex-components-form.mjs +3 -4
  19. package/fesm2022/acorex-components-form.mjs.map +1 -1
  20. package/fesm2022/acorex-components-list.mjs +19 -265
  21. package/fesm2022/acorex-components-list.mjs.map +1 -1
  22. package/fesm2022/acorex-components-number-box.mjs +30 -29
  23. package/fesm2022/acorex-components-number-box.mjs.map +1 -1
  24. package/fesm2022/acorex-components-phone-box.mjs +6 -6
  25. package/fesm2022/acorex-components-phone-box.mjs.map +1 -1
  26. package/fesm2022/acorex-components-query-builder.mjs +2 -6
  27. package/fesm2022/acorex-components-query-builder.mjs.map +1 -1
  28. package/fesm2022/acorex-components-rest-api-generator.mjs +2 -2
  29. package/fesm2022/acorex-components-rest-api-generator.mjs.map +1 -1
  30. package/fesm2022/acorex-components-rrule.mjs +2 -2
  31. package/fesm2022/acorex-components-rrule.mjs.map +1 -1
  32. package/fesm2022/acorex-components-scheduler-picker.mjs +16 -16
  33. package/fesm2022/acorex-components-scheduler-picker.mjs.map +1 -1
  34. package/fesm2022/acorex-components-scheduler.mjs +2 -2
  35. package/fesm2022/acorex-components-scheduler.mjs.map +1 -1
  36. package/fesm2022/acorex-components-select-box.mjs +451 -176
  37. package/fesm2022/acorex-components-select-box.mjs.map +1 -1
  38. package/fesm2022/acorex-components-selection-list.mjs +4 -0
  39. package/fesm2022/acorex-components-selection-list.mjs.map +1 -1
  40. package/package.json +3 -3
  41. package/select-box/README.md +0 -2
  42. package/types/acorex-components-combo-box.d.ts +74 -162
  43. package/types/acorex-components-conversation.d.ts +126 -32
  44. package/types/acorex-components-list.d.ts +3 -65
  45. package/types/acorex-components-number-box.d.ts +3 -1
  46. package/types/acorex-components-phone-box.d.ts +2 -2
  47. package/types/acorex-components-query-builder.d.ts +9 -10
  48. package/types/acorex-components-select-box.d.ts +147 -36
  49. package/types/acorex-components-selection-list.d.ts +2 -1
@@ -1,663 +1,231 @@
1
- import { MXSelectionValueComponent, MXLookComponent, AXHotkeysService, convertArrayToDataSource, AX_SELECTION_DATA_TOKEN, AXDataSource, AXComponent, AXFocusableComponent, AXValuableComponent, AXClearableComponent, AXClosableComponent, AXSearchableComponent, MXSelectionBridgeService, AXCommonModule } from '@acorex/cdk/common';
2
- import { AXDecoratorGenericComponent, AXDecoratorCloseButtonComponent, AXDecoratorModule } from '@acorex/components/decorators';
3
- import { MXDropdownBoxBaseComponent, AXDropdownBoxComponent, AXDropdownModule } from '@acorex/components/dropdown';
4
- import { AXListComponent, AXListModule } from '@acorex/components/list';
5
- import { AXLoadingSpinnerComponent, AXLoadingModule } from '@acorex/components/loading';
6
- import { AXSearchBoxComponent } from '@acorex/components/search-box';
7
- import { AXTagComponent } from '@acorex/components/tag';
8
- import { AXTranslatorPipe, AXTranslationModule } from '@acorex/core/translation';
9
- import { AXUnsubscriber } from '@acorex/core/utils';
10
- import { NgTemplateOutlet, NgClass, AsyncPipe, CommonModule } from '@angular/common';
1
+ import { NXComponent, AXComponent } from '@acorex/cdk/common';
2
+ import { AXPopoverComponent } from '@acorex/components/popover';
3
+ import { AXTranslatorPipe } from '@acorex/core/translation';
4
+ import { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';
5
+ import { Listbox, Option } from '@angular/aria/listbox';
6
+ import { AsyncPipe } from '@angular/common';
11
7
  import * as i0 from '@angular/core';
12
- import { input, inject, signal, linkedSignal, afterNextRender, forwardRef, HostListener, ViewChild, ContentChild, Input, ViewEncapsulation, Component, NgModule } from '@angular/core';
13
- import * as i1 from '@angular/forms';
14
- import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
15
- import { isEqual, get, last, findLastIndex, nth } from 'lodash-es';
16
- import { classes } from 'polytype';
17
- import { AXBadgeModule } from '@acorex/components/badge';
18
- import { AXCheckBoxModule } from '@acorex/components/check-box';
19
- import { AXPopoverModule } from '@acorex/components/popover';
20
- import { A11yModule } from '@angular/cdk/a11y';
21
- import { AXTextBoxModule } from '@acorex/components/text-box';
8
+ import { input, model, output, signal, computed, linkedSignal, viewChild, effect, untracked, afterRenderEffect, ChangeDetectionStrategy, ViewEncapsulation, Component, NgModule } from '@angular/core';
22
9
 
23
10
  /**
24
- * The ComboBox is a component which supports static arrays and advanced AXDataSource with lazy loading.
25
- * @category
11
+ * A minimal combo box for selecting a single value from a list of items.
12
+ *
13
+ * Built on top of the `@angular/aria/combobox` directives, it supports two behaviors:
14
+ * - `editable="true"` (default): an editable input with typeahead filtering (matches `id`).
15
+ * - `editable="false"`: a non-editable, select-like trigger (same input, read-only).
16
+ *
17
+ * Items use `text` for display, `id` for search/identity, and `value` as the submitted model value.
18
+ *
19
+ * @category Components
26
20
  */
27
- class AXComboBoxComponent extends classes(MXDropdownBoxBaseComponent, MXSelectionValueComponent, MXLookComponent) {
21
+ class AXComboBoxComponent extends NXComponent {
22
+ #isUserInteraction;
23
+ #lastValue;
24
+ #lastExpanded;
28
25
  constructor() {
29
- super(...arguments);
26
+ super();
30
27
  /**
31
- * Determines if an item is truncated.
32
- *
33
- * @defaultValue true
28
+ * The list of items the user can select from.
29
+ * Each item has `id` (search/identity), `text` (display), and `value` (submitted).
34
30
  */
35
- this.isItemTruncated = input(true, /* @ts-ignore */
36
- ...(ngDevMode ? [{ debugName: "isItemTruncated" }] : /* istanbul ignore next */ []));
31
+ this.items = input([], /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
37
33
  /**
38
- * Determines if a tooltip is shown for an item.
39
- *
40
- * @defaultValue false
34
+ * Whether the combo box renders an editable input with typeahead filtering (`true`)
35
+ * or a non-editable, select-like trigger (`false`).
41
36
  */
42
- this.showItemTooltip = input(false, /* @ts-ignore */
43
- ...(ngDevMode ? [{ debugName: "showItemTooltip" }] : /* istanbul ignore next */ []));
44
- /** Height of each list item in pixels, or 'auto' to let list measure. */
45
- this.itemHeight = input(40, /* @ts-ignore */
46
- ...(ngDevMode ? [{ debugName: "itemHeight" }] : /* istanbul ignore next */ []));
47
- /** Maximum number of visible items before scrolling. */
48
- this.maxVisibleItems = input(5, /* @ts-ignore */
49
- ...(ngDevMode ? [{ debugName: "maxVisibleItems" }] : /* istanbul ignore next */ []));
50
- /** @ignore */
51
- this.hotKeyService = inject(AXHotkeysService);
52
- /** @ignore */
53
- this.isLoading = signal(false, /* @ts-ignore */
54
- ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
55
- /** @ignore */
56
- this.searchValue = signal('', /* @ts-ignore */
57
- ...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
58
- /** @ignore */
59
- this.renderList = signal(false, /* @ts-ignore */
60
- ...(ngDevMode ? [{ debugName: "renderList" }] : /* istanbul ignore next */ []));
61
- /** @ignore */
62
- this._dropdownWidth = linkedSignal(() => this.dropdownWidth(), /* @ts-ignore */
63
- ...(ngDevMode ? [{ debugName: "_dropdownWidth" }] : /* istanbul ignore next */ []));
64
- /** @ignore */
65
- this._dropdownHeight = signal('auto', /* @ts-ignore */
66
- ...(ngDevMode ? [{ debugName: "_dropdownHeight" }] : /* istanbul ignore next */ []));
67
- /** @ignore */
68
- this._listDataSource = convertArrayToDataSource([], {
69
- key: this.valueField,
70
- pageSize: 10,
71
- });
72
- this.#init = afterNextRender(() => {
73
- const formField = this.getHostElement().closest('ax-form-field');
74
- if (formField?.classList.contains('ax-state-floating-label')) {
75
- this.getHostElement().classList.add('ax-float-label');
76
- }
77
- });
37
+ this.editable = input(true, /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "editable" }] : /* istanbul ignore next */ []));
78
39
  /**
79
- * The width of the dropdown in pixels.
80
- * @defaultValue null
40
+ * The placeholder text shown when no value is selected.
81
41
  */
82
- this.dropdownWidth = input(null, /* @ts-ignore */
83
- ...(ngDevMode ? [{ debugName: "dropdownWidth" }] : /* istanbul ignore next */ []));
84
- this.searchBoxAutoFocus = input(true, /* @ts-ignore */
85
- ...(ngDevMode ? [{ debugName: "searchBoxAutoFocus" }] : /* istanbul ignore next */ []));
42
+ this.placeholder = input('', /* @ts-ignore */
43
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
86
44
  /**
87
- * Service for managing selection data, injected via `AX_SELECTION_DATA_TOKEN`.
45
+ * Whether the combo box is disabled.
88
46
  */
89
- this.selectionService = inject(AX_SELECTION_DATA_TOKEN);
90
- /** @ignore */
91
- this._unsubscriber = inject(AXUnsubscriber);
92
- }
93
- #init;
94
- /**
95
- * Gets the data source for the component, which can be either an `AXDataSource` or an array of items.
96
- * @returns {AXDataSource<any> | any[]}
97
- */
98
- get dataSource() {
99
- return this._originalDataSource;
100
- }
101
- /**
102
- * Sets the data source, either as an `AXDataSource` or an array.
103
- * @param {AXDataSource<any> | any[]} v
104
- */
105
- set dataSource(v) {
106
- // check if the data source is the same
107
- if (Array.isArray(v) && Array.isArray(this._originalDataSource) && isEqual(v, this._originalDataSource)) {
108
- return;
109
- }
110
- if (v instanceof AXDataSource && v == this._originalDataSource) {
111
- return;
112
- }
113
- //
114
- this._originalDataSource = v;
115
- if (Array.isArray(v)) {
116
- this._listDataSource = convertArrayToDataSource(v, {
117
- key: this.valueField,
118
- pageSize: v.length || 10,
119
- });
120
- }
121
- else {
122
- this._listDataSource = this.dataSource;
123
- }
124
- //
125
- this.onChangedSubscription?.unsubscribe();
126
- this.onChangedSubscription = this._listDataSource.onChanged
127
- .pipe(this._unsubscriber.takeUntilDestroy)
128
- .subscribe(() => {
129
- this.updateDropdownSize();
130
- // Force refresh of selected items when data source changes
131
- this.forceRefreshSelectedItems();
132
- if (this.isOpen) {
133
- this.scheduleRevealSelected();
47
+ this.disabled = model(false, /* @ts-ignore */
48
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
49
+ /**
50
+ * Whether the combo box is readonly.
51
+ */
52
+ this.readonly = model(false, /* @ts-ignore */
53
+ ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
54
+ /**
55
+ * Predefined look scheme of the editor container. Same looks as other editor components like ax-text-box.
56
+ */
57
+ this.look = model('solid', /* @ts-ignore */
58
+ ...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
59
+ /**
60
+ * The selected item's `value`. Supports two-way binding.
61
+ */
62
+ this.value = model(null, /* @ts-ignore */
63
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
64
+ /**
65
+ * Emitted when the selected value changes.
66
+ */
67
+ this.onValueChanged = output();
68
+ /**
69
+ * Emitted when the popup list opens.
70
+ */
71
+ this.onOpened = output();
72
+ /**
73
+ * Emitted when the popup list closes.
74
+ */
75
+ this.onClosed = output();
76
+ /** Whether the popup is expanded. */
77
+ this.expanded = signal(false, /* @ts-ignore */
78
+ ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
79
+ /** The item whose `value` matches the current model value. */
80
+ this.selectedItem = computed(() => {
81
+ const value = this.value();
82
+ if (value == null) {
83
+ return null;
134
84
  }
135
- });
136
- //
137
- this.onLoadingChangedSubscription?.unsubscribe();
138
- this.onLoadingChangedSubscription = this._listDataSource.onLoadingChanged
139
- .pipe(this._unsubscriber.takeUntilDestroy)
140
- .subscribe((loading) => {
141
- this.isLoading.set(loading);
142
- // After async load completes while open, scroll/focus the selected item.
143
- if (!loading && this.isOpen) {
144
- this.scheduleRevealSelected();
85
+ return this.items().find((item) => item.value === value) ?? null;
86
+ }, /* @ts-ignore */
87
+ ...(ngDevMode ? [{ debugName: "selectedItem" }] : /* istanbul ignore next */ []));
88
+ /** Display text shown in the trigger / used as the editable input baseline. */
89
+ this.displayText = computed(() => this.selectedItem()?.text ?? '', /* @ts-ignore */
90
+ ...(ngDevMode ? [{ debugName: "displayText" }] : /* istanbul ignore next */ []));
91
+ /** The text typed in the editable input. Resets to the selected item's text. */
92
+ this.searchText = linkedSignal(() => this.displayText(), /* @ts-ignore */
93
+ ...(ngDevMode ? [{ debugName: "searchText" }] : /* istanbul ignore next */ []));
94
+ /** The listbox selection (item ids), kept in sync with the selected value. */
95
+ this.selection = linkedSignal(() => {
96
+ const id = this.selectedItem()?.id;
97
+ return id != null ? [id] : [];
98
+ }, /* @ts-ignore */
99
+ ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
100
+ /** Items filtered by typed query against `id` when the combo box is editable. */
101
+ this.filteredItems = computed(() => {
102
+ const items = this.items();
103
+ if (!this.editable()) {
104
+ return items;
145
105
  }
146
- });
147
- // After setting data source, try to fetch item data if needed
148
- setTimeout(() => this.fetchItemDataIfNeeded(), 0);
149
- }
150
- /** @ignore */
151
- ngOnInit() {
152
- super.ngOnInit();
153
- //
154
- this.registerValidation();
155
- // Proactively fetch item data if we have a value but no corresponding item
156
- this.fetchItemDataIfNeeded();
157
- }
158
- /**
159
- * Proactively fetches item data if the component has a value but no corresponding item data.
160
- * This prevents showing "loading..." when the component has a value.
161
- */
162
- async fetchItemDataIfNeeded() {
163
- const isEmptyValue = this.value == null || (Array.isArray(this.value) && this.value.length === 0);
164
- if (!isEmptyValue && this._listDataSource && !this.selectedItems?.length) {
165
- try {
166
- const item = await this.getItemByKey(this.value);
167
- if (item) {
168
- // Force refresh to update the display
169
- this.forceRefreshSelectedItems();
170
- }
106
+ const query = this.searchText().trim().toLowerCase();
107
+ const selectedId = (this.selectedItem()?.id ?? '').toLowerCase();
108
+ if (!query || query === selectedId || query === this.displayText().trim().toLowerCase()) {
109
+ return items;
171
110
  }
172
- catch (error) {
173
- console.warn('Failed to fetch item data:', error);
111
+ return items.filter((item) => item.id.toLowerCase().includes(query));
112
+ }, /* @ts-ignore */
113
+ ...(ngDevMode ? [{ debugName: "filteredItems" }] : /* istanbul ignore next */ []));
114
+ this.comboboxRef = viewChild(Combobox, /* @ts-ignore */
115
+ ...(ngDevMode ? [{ debugName: "comboboxRef" }] : /* istanbul ignore next */ []));
116
+ this.listboxRef = viewChild(Listbox, /* @ts-ignore */
117
+ ...(ngDevMode ? [{ debugName: "listboxRef" }] : /* istanbul ignore next */ []));
118
+ this.popoverRef = viewChild(AXPopoverComponent, /* @ts-ignore */
119
+ ...(ngDevMode ? [{ debugName: "popoverRef" }] : /* istanbul ignore next */ []));
120
+ this.#isUserInteraction = false;
121
+ this.#lastValue = undefined;
122
+ this.#lastExpanded = undefined;
123
+ effect(() => this.#emitValueChanged(this.value()));
124
+ effect(() => this.#emitOpenedOrClosed(this.expanded()));
125
+ // Open during CD (before render) so the overlay exists before Aria DeferredContent
126
+ // creates the list in its after-render hook.
127
+ effect(() => {
128
+ const expanded = this.expanded();
129
+ const popover = this.popoverRef();
130
+ if (!popover) {
131
+ return;
174
132
  }
175
- }
176
- }
177
- /** @ignore */
178
- ngOnDestroy() {
179
- this.searchBox?.onKeyDown.unsubscribe();
180
- this.onChangedSubscription?.unsubscribe();
181
- this.onLoadingChangedSubscription?.unsubscribe();
182
- }
183
- /**
184
- * Retrieves an item by its key.
185
- * @param {any} key
186
- */
187
- getItemByKey(key) {
188
- // Static array data sources resolve synchronously to avoid a false loading state
189
- // for primitive values (e.g. color format "hex" / "rgba").
190
- if (Array.isArray(this._originalDataSource)) {
191
- for (const candidate of this._originalDataSource) {
192
- if (candidate != null && typeof candidate === 'object') {
193
- if (get(candidate, this.valueField) == key || get(candidate, this.textField) == key) {
194
- return candidate;
195
- }
133
+ untracked(() => {
134
+ if (expanded && !popover.isOpen) {
135
+ void popover.open();
196
136
  }
197
- else if (candidate == key) {
198
- return { [this.valueField]: candidate, [this.textField]: String(candidate ?? '') };
137
+ else if (!expanded && popover.isOpen) {
138
+ popover.close();
199
139
  }
200
- }
201
- return null;
202
- }
203
- if (this._listDataSource && typeof this._listDataSource.find === 'function') {
204
- return this._listDataSource.find(key);
205
- }
206
- // If neither method is available, return null
207
- console.warn('No find method available on data source');
208
- return null;
209
- }
210
- /** @ignore */
211
- _handleOnOpenedEvent(e) {
212
- if (!this.renderList()) {
213
- this.renderList.set(true);
214
- }
215
- else if (!this._listDataSource.totalCount || this._listDataSource.totalCount == 0) {
216
- this.list?.refresh(false);
217
- }
218
- this._handleFocus();
219
- //
220
- this.onOpened.emit({
221
- component: this,
222
- isUserInteraction: e.isUserInteraction,
223
- });
224
- this.updateDropdownSize();
225
- // Force refresh of selected items when opening to show updated text
226
- this.forceRefreshSelectedItems();
227
- // Keep retrying until async pages arrive and the viewport has a real size.
228
- this.scheduleRevealSelected();
229
- }
230
- /** @ignore */
231
- _handleOnClosedEvent(e) {
232
- this.list?.cancelRevealSelected();
233
- this.onClosed.emit({
234
- component: this,
235
- isUserInteraction: e.isUserInteraction,
140
+ });
236
141
  });
237
- this._unsubscriber.unsubscribe();
238
- }
239
- /** @ignore */
240
- _handleFocus() {
241
- // Wait a tick so the list is created (first open) and dropdown height is applied.
242
- setTimeout(() => {
243
- if (this.searchBox) {
244
- this.searchBox.look = 'flat';
245
- if (this.searchBoxAutoFocus()) {
246
- this.searchBox.focus();
247
- }
248
- //TODO: unsubscribe
249
- this.hotKeyService
250
- .addShortcut({ keys: 'Control.f', element: this.panel.nativeElement })
251
- .pipe(this._unsubscriber.takeUntilDestroy)
252
- .subscribe(() => {
253
- this.searchBox.focus();
254
- });
255
- this.searchBox.onKeyDown.pipe(this._unsubscriber.takeUntilDestroy).subscribe((e) => {
256
- if (e.nativeEvent.code === 'ArrowDown' || e.nativeEvent.key === 'ArrowDown') {
257
- this.list?.focus();
258
- e.nativeEvent.preventDefault();
259
- }
260
- });
261
- }
262
- else {
263
- this.list?.focus();
142
+ afterRenderEffect(() => {
143
+ if (this.expanded()) {
144
+ this.listboxRef()?.scrollActiveItemIntoView();
264
145
  }
265
146
  });
266
147
  }
267
- /**
268
- * Scroll (and focus when there is no search autofocus) to the selected item once the list is ready.
269
- * @ignore
270
- */
271
- scheduleRevealSelected() {
272
- const focusList = !this.searchBox || !this.searchBoxAutoFocus();
273
- setTimeout(() => {
274
- this.list?.revealSelected({ focus: focusList });
275
- });
276
- }
277
- /** @ignore */
278
- _handleBadgeRemove(e, item) {
279
- this.unselectItems(item);
280
- e.stopPropagation();
281
- }
282
- /** @ignore */
283
- _handleValueChanged(e) {
284
- if (e.isUserInteraction) {
285
- if (!this.multiple) {
286
- this.close();
287
- }
288
- this.commitValue(e.component.selectedItems, true);
289
- }
290
- }
291
- /** @ignore */
292
- _handleItemClick(e) {
293
- this.onItemClick.emit(e);
294
- if (!this.multiple) {
295
- this.close();
296
- }
297
- }
298
- /** @ignore */
299
- _handleItemSelected(e) {
300
- this.onItemSelected.emit(e);
301
- this.resetSearchAfterSelection();
302
- if (!this.multiple) {
303
- this.close();
148
+ /** Emits onValueChanged when the value actually changes (skips the initial value). */
149
+ #emitValueChanged(value) {
150
+ const previous = this.#lastValue;
151
+ this.#lastValue = value;
152
+ if (previous === undefined || previous === value) {
153
+ return;
304
154
  }
155
+ this.onValueChanged.emit({
156
+ component: this,
157
+ htmlElement: this.nativeElement,
158
+ name: 'value',
159
+ value,
160
+ oldValue: previous,
161
+ isUserInteraction: this.#isUserInteraction,
162
+ });
163
+ this.#isUserInteraction = false;
305
164
  }
306
- resetSearchAfterSelection() {
307
- if (!this.searchBox && !this.searchBox?.value)
165
+ /** Emits onOpened/onClosed when the expanded state actually changes (skips the initial state). */
166
+ #emitOpenedOrClosed(expanded) {
167
+ const previous = this.#lastExpanded;
168
+ this.#lastExpanded = expanded;
169
+ if (previous === undefined || previous === expanded) {
308
170
  return;
309
- if (this.searchBox && this.searchBox?.value)
310
- this.searchBox.commitValue('', false);
311
- }
312
- /** @ignore */
313
- setDropdownSize(count = 0) {
314
- const itemPx = typeof this.itemHeight() === 'number' ? this.itemHeight() : 40;
315
- const isActionsheet = this.dropdown.isActionsheetStyle;
316
- if (isActionsheet) {
317
- this._dropdownWidth.set('100%');
318
- // Prefer maxVisibleItems on actionsheet too; still clamp to the pane afterwards.
319
- const maxItems = Math.max(Number(this.maxVisibleItems()) || 5, 1);
320
- this._dropdownHeight.set(`${Math.min(maxItems, Math.max(count, 1)) * itemPx}px`);
321
- }
322
- else {
323
- const hostWidth = Math.max(this.getHostElement().offsetWidth, Number(this.dropdownWidth()) || 0);
324
- const maxItems = Number(this.maxVisibleItems());
325
- this._dropdownWidth.set(`${hostWidth}px`);
326
- this._dropdownHeight.set(count == 0 ? 'auto' : `${Math.min(maxItems, count) * itemPx}px`);
327
171
  }
328
- setTimeout(() => {
329
- this._fitListHeightToAvailableSpace(itemPx);
330
- this.dropdown.updatePosition();
331
- this.list?.render();
332
- // Second pass after the overlay pane applies max-height / overflow constraints.
333
- // Height changes invalidate the previous scroll offset — scroll again after fit.
334
- requestAnimationFrame(() => {
335
- setTimeout(() => {
336
- this._fitListHeightToAvailableSpace(itemPx);
337
- this.list?.render();
338
- requestAnimationFrame(() => this.scheduleRevealSelected());
339
- }, 0);
340
- });
341
- });
172
+ const event = {
173
+ component: this,
174
+ htmlElement: this.nativeElement,
175
+ isUserInteraction: true,
176
+ };
177
+ expanded ? this.onOpened.emit(event) : this.onClosed.emit(event);
342
178
  }
343
179
  /**
344
- * Shrinks list height to the visible overlay area so virtual scroll ends on fully
345
- * visible rows instead of inside an overflow:hidden clipped region.
346
- * @ignore
180
+ * Opens (editable) or toggles (non-editable) the popup on trigger click.
347
181
  */
348
- _fitListHeightToAvailableSpace(itemPx) {
349
- if (itemPx <= 0 || this._dropdownHeight() === 'auto') {
350
- return;
351
- }
352
- const panel = this.panel?.nativeElement;
353
- const listEl = this.list?.getHostElement?.();
354
- if (!panel || !listEl) {
355
- return;
356
- }
357
- const pane = panel.closest('.ax-overlay-pane');
358
- if (!pane) {
359
- return;
360
- }
361
- const listRect = listEl.getBoundingClientRect();
362
- const paneRect = pane.getBoundingClientRect();
363
- const paneOverflow = listRect.bottom - paneRect.bottom;
364
- const viewportOverflow = listRect.bottom - window.innerHeight;
365
- const overflow = Math.max(paneOverflow, viewportOverflow);
366
- let nextHeight = listEl.clientHeight || parseFloat(this._dropdownHeight());
367
- if (!Number.isFinite(nextHeight) || nextHeight <= 0) {
182
+ onTriggerClick() {
183
+ if (this.disabled() || this.readonly()) {
368
184
  return;
369
185
  }
370
- // When the list extends past the overlay pane or screen, shrink it to the visible area.
371
- if (overflow > 1) {
372
- nextHeight = Math.max(itemPx, nextHeight - overflow);
373
- }
374
- // Keep height as whole rows so the last item is never permanently cropped.
375
- nextHeight = Math.max(itemPx, Math.floor(nextHeight / itemPx) * itemPx);
376
- const current = parseFloat(this._dropdownHeight());
377
- if (!Number.isFinite(current) || nextHeight !== current) {
378
- this._dropdownHeight.set(`${nextHeight}px`);
379
- }
380
- }
381
- updateDropdownPosition() {
382
- setTimeout(() => {
383
- this.dropdown.updatePosition();
384
- });
385
- }
386
- updateDropdownSize() {
387
- setTimeout(() => {
388
- this.setDropdownSize(this._listDataSource.totalCount);
389
- this.updateDropdownPosition();
390
- this.list?.render();
391
- if (!this.isItemTruncated()) {
392
- setTimeout(() => {
393
- this._fitDropdownToContent();
394
- setTimeout(() => this._fitDropdownToContent(), 100);
395
- });
396
- }
397
- });
398
- }
399
- _fitDropdownToContent() {
400
- const panel = this.panel?.nativeElement;
401
- if (!panel)
186
+ if (this.editable()) {
187
+ this.expanded.set(true);
402
188
  return;
403
- const hostWidth = Math.max(this.getHostElement().offsetWidth, Number(this.dropdownWidth()) || 0);
404
- let contentWidth = hostWidth;
405
- panel.querySelectorAll('li.list-item').forEach((item) => {
406
- const label = item.querySelector('.ax-label-container span');
407
- if (label) {
408
- const labelContainer = label.parentElement;
409
- const horizontalPadding = labelContainer ? item.offsetWidth - labelContainer.clientWidth : 0;
410
- contentWidth = Math.max(contentWidth, label.scrollWidth + horizontalPadding);
411
- }
412
- else {
413
- contentWidth = Math.max(contentWidth, item.scrollWidth);
414
- }
415
- });
416
- const nextWidth = `${Math.max(hostWidth, contentWidth)}px`;
417
- if (this._dropdownWidth() !== nextWidth) {
418
- this._dropdownWidth.set(nextWidth);
419
- this.dropdown.updatePosition();
420
- }
421
- }
422
- internalValueChanged(value) {
423
- super.internalValueChanged(value);
424
- this.updateDropdownPosition();
425
- // Try to fetch item data when value changes
426
- setTimeout(() => this.fetchItemDataIfNeeded(), 0);
427
- }
428
- /** @ignore */
429
- _handleKeydown(e) {
430
- if (e.code === 'ArrowDown' || e.code === 'ArrowUp') {
431
- this.selectItemByNav(e.code === 'ArrowDown' ? 1 : -1);
432
- e.preventDefault();
433
- }
434
- else if (e.code === 'Backspace') {
435
- this.unselectItems(this.selectedItems.pop());
436
- e.preventDefault();
437
- }
438
- }
439
- /** @ignore */
440
- selectItemByNav(sign) {
441
- if (Array.isArray(this.dataSource) && !this.multiple) {
442
- const items = this.normalizeItemsList(this.dataSource);
443
- const _last = last(this.selectedItems);
444
- let i = -1;
445
- if (_last) {
446
- i = findLastIndex(items, [this.valueField, get(_last, this.valueField)]);
447
- }
448
- i += sign;
449
- if (i < 0 || i >= items.length)
450
- return;
451
- const next = nth(items, i);
452
- if (next) {
453
- this.selectItems(next);
454
- }
455
- }
456
- else {
457
- this.open();
458
189
  }
190
+ this.expanded.update((open) => !open);
459
191
  }
460
192
  /**
461
- * Filters the data source based on the provided search term.
462
- * @param {string} term
193
+ * Keeps the combobox expanded state in sync when the popover closes (e.g. click outside).
463
194
  */
464
- search(term) {
465
- this.searchValue.set(term);
466
- if (term) {
467
- this._listDataSource.filter({
468
- field: this.textField,
469
- value: term,
470
- operator: { type: 'contains' },
471
- });
472
- }
473
- else {
474
- this._listDataSource.clearFilter();
475
- }
476
- this._listDataSource.refresh();
195
+ onPopoverClosed() {
196
+ this.expanded.set(false);
477
197
  }
478
198
  /**
479
- * Refreshes the component by resetting state, clearing selection cache, refreshing the list, and closing the component.
199
+ * Commits the current listbox selection as the component value and closes the popup.
480
200
  */
481
- refresh() {
482
- this.reset(false);
483
- this.clearSelectionCache();
484
- this.list?.refresh();
485
- this.close();
486
- }
487
- hostClickListener() {
488
- this.toggle();
489
- }
490
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
491
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXComboBoxComponent, isStandalone: true, selector: "ax-combo-box", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: false, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: false, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: false, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: false, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: false, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: false, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: false, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: false, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: false, isRequired: false, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: false, isRequired: false, transformFunction: null }, disabledField: { classPropertyName: "disabledField", publicName: "disabledField", isSignal: false, isRequired: false, transformFunction: null }, textTemplate: { classPropertyName: "textTemplate", publicName: "textTemplate", isSignal: false, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: false, isRequired: false, transformFunction: null }, isItemTruncated: { classPropertyName: "isItemTruncated", publicName: "isItemTruncated", isSignal: true, isRequired: false, transformFunction: null }, showItemTooltip: { classPropertyName: "showItemTooltip", publicName: "showItemTooltip", isSignal: true, isRequired: false, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleItems: { classPropertyName: "maxVisibleItems", publicName: "maxVisibleItems", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: false, isRequired: false, transformFunction: null }, minRecordsForSearch: { classPropertyName: "minRecordsForSearch", publicName: "minRecordsForSearch", isSignal: false, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: false, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: false, isRequired: false, transformFunction: null }, selectedTemplate: { classPropertyName: "selectedTemplate", publicName: "selectedTemplate", isSignal: false, isRequired: false, transformFunction: null }, emptyTemplate: { classPropertyName: "emptyTemplate", publicName: "emptyTemplate", isSignal: false, isRequired: false, transformFunction: null }, loadingTemplate: { classPropertyName: "loadingTemplate", publicName: "loadingTemplate", isSignal: false, isRequired: false, transformFunction: null }, dropdownWidth: { classPropertyName: "dropdownWidth", publicName: "dropdownWidth", isSignal: true, isRequired: false, transformFunction: null }, searchBoxAutoFocus: { classPropertyName: "searchBoxAutoFocus", publicName: "searchBoxAutoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", stateChange: "stateChange", onValueChanged: "onValueChanged", onBlur: "onBlur", onFocus: "onFocus", readonlyChange: "readonlyChange", disabledChange: "disabledChange", onOpened: "onOpened", onClosed: "onClosed", onItemSelected: "onItemSelected", onItemClick: "onItemClick" }, host: { attributes: { "ngSkipHydration": "true" }, listeners: { "keydown": "_handleKeydown($event)", "click": "hostClickListener()" } }, providers: [
492
- { provide: AXComponent, useExisting: AXComboBoxComponent },
493
- { provide: AXFocusableComponent, useExisting: AXComboBoxComponent },
494
- { provide: AXValuableComponent, useExisting: AXComboBoxComponent },
495
- { provide: AXClearableComponent, useExisting: AXComboBoxComponent },
496
- { provide: AXClosableComponent, useExisting: AXComboBoxComponent },
497
- { provide: AXSearchableComponent, useExisting: AXComboBoxComponent },
498
- {
499
- provide: NG_VALUE_ACCESSOR,
500
- useExisting: forwardRef(() => AXComboBoxComponent),
501
- multi: true,
502
- },
503
- {
504
- provide: AX_SELECTION_DATA_TOKEN,
505
- useClass: MXSelectionBridgeService,
506
- },
507
- AXUnsubscriber,
508
- ], queries: [{ propertyName: "searchBox", first: true, predicate: AXSearchBoxComponent, descendants: true }], viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true }, { propertyName: "list", first: true, predicate: AXListComponent, descendants: true }, { propertyName: "dropdown", first: true, predicate: AXDropdownBoxComponent, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ax-dropdown-box\n [class.ax-state-multiple]=\"multiple\"\n (onOpened)=\"_handleOnOpenedEvent($event)\"\n (onClosed)=\"_handleOnClosedEvent($event)\"\n (focus)=\"emitOnFocusEvent($event)\"\n (blur)=\"emitOnBlurEvent($event)\"\n [disabled]=\"disabled\"\n [look]=\"look\"\n [popoverWidth]=\"dropdownWidth()\"\n>\n <ng-container input>\n <ng-content select=\"ax-prefix\"> </ng-content>\n <div\n class=\"ax-editor ax-chips-container ax-content ax-input\"\n [class.ax-state-multiple]=\"multiple\"\n [tabindex]=\"tabIndex\"\n >\n @if (selectedItems.length === 0) {\n <div class=\"ax-placeholder\" role=\"textbox\" area-readonly=\"true\">\n {{ placeholder | translate | async }}\n </div>\n }\n @for (item of selectedItems; track $index) {\n @if (selectedTemplate) {\n <ng-template\n [ngTemplateOutlet]=\"selectedTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { data: item } }\"\n ></ng-template>\n } @else {\n @if (multiple) {\n <ax-tag [text]=\"getDisplayText(item) | translate | async\" look=\"twotone\">\n @if (!disabled && !readonly && multiple) {\n <ax-suffix>\n <span class=\"ax-icon ax-icon-close\" (click)=\"_handleBadgeRemove($event, item)\"></span>\n </ax-suffix>\n }\n </ax-tag>\n } @else {\n {{ getDisplayText(item) | translate | async }}\n }\n }\n }\n </div>\n @if (selectedItems?.length && !disabled && !readonly) {\n <ng-content select=\"ax-clear-button\"></ng-content>\n }\n <button type=\"button\" [disabled]=\"disabled\" [tabIndex]=\"-1\" class=\"ax-general-button-icon\">\n @if (isLoading()) {\n <ax-loading-spinner [size]=\"16\" [stroke]=\"1\"></ax-loading-spinner>\n } @else {\n <span\n class=\"ax-icon\"\n [ngClass]=\"{\n 'ax-icon-chevron-down': !isOpen,\n 'ax-icon-chevron-up': isOpen,\n }\"\n ></span>\n }\n </button>\n <ng-content select=\"ax-suffix\"> </ng-content>\n <ng-template #search>\n <ng-content select=\"ax-search-box\"> </ng-content>\n </ng-template>\n </ng-container>\n <ng-container panel>\n <div\n #panel\n class=\"ax-combo-box-panel\"\n [class.ax-no-truncate]=\"!isItemTruncated()\"\n [style.min-width]=\"_dropdownWidth()\"\n >\n @if (dropdown.isActionsheetStyle) {\n <ax-header class=\"ax-solid\">\n <ax-title>{{ caption || placeholder || '@acorex:selectbox.popover.title' | translate | async }}</ax-title>\n <ax-close-button [icon]=\"multiple ? 'ax-icon ax-icon-check' : 'ax-icon ax-icon-close'\"></ax-close-button>\n </ax-header>\n }\n @if (searchBox && (!minRecordsForSearch || _listDataSource.totalCount >= minRecordsForSearch || searchValue())) {\n <div class=\"ax-search-container\">\n <ng-template [ngTemplateOutlet]=\"search\"></ng-template>\n </div>\n }\n @if (renderList()) {\n <ax-list\n [name]=\"name\"\n [ngModel]=\"value\"\n [readonly]=\"readonly\"\n [multiple]=\"multiple\"\n [textField]=\"textField\"\n [selectionMode]=\"'item'\"\n [valueField]=\"valueField\"\n [itemHeight]=\"itemHeight()\"\n [itemTemplate]=\"itemTemplate\"\n [textTemplate]=\"textTemplate\"\n [dataSource]=\"_listDataSource\"\n [style.height]=\"_dropdownHeight()\"\n [loadingTemplate]=\"loadingTemplate\"\n [isItemTruncated]=\"isItemTruncated()\"\n [showItemTooltip]=\"showItemTooltip()\"\n (onItemClick)=\"_handleItemClick($event)\"\n [emptyTemplate]=\"emptyTemplate ?? empty\"\n (onValueChanged)=\"_handleValueChanged($event)\"\n (onItemSelected)=\"_handleItemSelected($event)\"\n >\n </ax-list>\n <ng-template #empty>\n {{ '@acorex:common.general.no-result-found' | translate | async }}\n </ng-template>\n }\n\n @if (isLoading()) {\n @if (loadingTemplate) {\n <ng-template [ngTemplateOutlet]=\"loadingTemplate\"></ng-template>\n }\n }\n\n <ng-content select=\"ax-footer\"> </ng-content>\n </div>\n </ng-container>\n</ax-dropdown-box>\n<ng-content select=\"ax-validation-rule\"> </ng-content>\n", styles: ["@layer properties;@layer components{ax-combo-box .ax-editor-container{padding-block:calc(var(--spacing, .25rem) * 0)}ax-combo-box .ax-editor-container.ax-state-multiple{padding-inline:calc(var(--spacing, .25rem) * 1)}ax-combo-box .ax-editor-container.ax-state-multiple .ax-placeholder{padding-inline-start:calc(var(--spacing, .25rem) * 2)}ax-combo-box .ax-editor-container .ax-input,ax-combo-box .ax-editor-container .ax-editor{padding-block:calc(var(--spacing, .25rem) * 1)}ax-combo-box ax-dropdown-box.ax-state-multiple{height:auto!important;min-height:var(--ax-comp-editor-height);--ax-comp-editor-space-start-size: 0}ax-combo-box .ax-chips-container{display:flex;min-height:var(--ax-sys-size-base);min-width:calc(var(--spacing, .25rem) * 0);flex:1;cursor:pointer!important;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:var(--ax-comp-combo-box-chips-gap,.25rem);outline-style:var(--tw-outline-style);outline-width:0px;outline-color:transparent;-webkit-user-select:none;user-select:none}ax-combo-box .ax-chips-container .ax-selectbox-input{width:calc(var(--spacing, .25rem) * 0);opacity:0%}ax-combo-box .ax-chips-container.ax-state-multiple:has(.ax-chips){padding:var(--ax-comp-combo-box-chips-container-padding, .25rem)}ax-combo-box .ax-chips-container ax-tag ax-prefix,ax-combo-box .ax-chips-container ax-tag ax-suffix{padding:calc(var(--spacing, .25rem) * 0)!important}.ax-combo-box-panel{display:flex;height:fit-content;max-height:100%;flex-direction:column;overflow:hidden}.ax-combo-box-panel.ax-no-truncate .ax-label-container span:not(.ax-truncated){white-space:nowrap}.ax-combo-box-panel .ax-combo-box-loading-container{display:flex;align-items:center;justify-content:center;padding:calc(var(--spacing, .25rem) * 4)}.ax-combo-box-panel ax-list{min-height:calc(var(--spacing, .25rem) * 0);flex:1 1 auto}.ax-combo-box-panel>ax-header .ax-icon-check{color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-panel>ax-header.ax-solid{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-border-lightest-surface))}.ax-combo-box-panel>ax-header.ax-solid ax-title{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));--tw-leading: calc(var(--spacing, .25rem) * 6);line-height:calc(var(--spacing, .25rem) * 6);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}@media(max-width:40rem){.ax-combo-box-panel .list-item{padding-inline:1rem}}}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-outline-style: solid;--tw-border-style: solid;--tw-leading: initial;--tw-font-weight: initial}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: AXDropdownBoxComponent, selector: "ax-dropdown-box", inputs: ["disabled", "look", "hasInput", "popoverWidth"], outputs: ["disabledChange", "onBlur", "onFocus", "onClick", "onOpened", "onClosed"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "component", type: AXDecoratorCloseButtonComponent, selector: "ax-close-button", inputs: ["closeAll", "icon"] }, { kind: "component", type: AXListComponent, selector: "ax-list", inputs: ["id", "name", "disabled", "readonly", "valueField", "textField", "textTemplate", "disabledField", "multiple", "selectionMode", "isItemTruncated", "showItemTooltip", "dataSource", "itemHeight", "itemTemplate", "emptyTemplate", "loadingTemplate", "checkbox"], outputs: ["onValueChanged", "disabledChange", "readonlyChange", "onBlur", "onFocus", "onItemClick", "onItemSelected", "onScrolledIndexChanged"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXTagComponent, selector: "ax-tag", inputs: ["color", "look", "text"], outputs: ["onClick", "onDblClick", "onContextMenu"] }, { kind: "component", type: AXLoadingSpinnerComponent, selector: "ax-loading-spinner", inputs: ["text", "color", "size", "stroke"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); }
201
+ commit() {
202
+ const selectedId = this.selection()[0];
203
+ const item = selectedId != null ? this.items().find((i) => i.id === selectedId) : undefined;
204
+ if (item != null && item.value !== this.value()) {
205
+ this.#isUserInteraction = true;
206
+ this.value.set(item.value);
207
+ }
208
+ this.expanded.set(false);
209
+ this.comboboxRef()?.element.focus();
210
+ }
211
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
212
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXComboBoxComponent, isStandalone: true, selector: "ax-combo-box", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", readonly: "readonlyChange", look: "lookChange", value: "valueChange", onValueChanged: "onValueChanged", onOpened: "onOpened", onClosed: "onClosed" }, providers: [{ provide: AXComponent, useExisting: AXComboBoxComponent }], viewQueries: [{ propertyName: "comboboxRef", first: true, predicate: Combobox, descendants: true, isSignal: true }, { propertyName: "listboxRef", first: true, predicate: Listbox, descendants: true, isSignal: true }, { propertyName: "popoverRef", first: true, predicate: AXPopoverComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n #origin\n class=\"ax-editor-container ax-{{ look() }} ax-default\"\n [class.ax-combo-box-trigger]=\"!editable()\"\n [class.ax-state-disabled]=\"disabled()\"\n [class.ax-state-readonly]=\"readonly()\"\n>\n <ng-content select=\"ax-prefix\"></ng-content>\n\n <input\n ngCombobox\n #combobox=\"ngCombobox\"\n type=\"text\"\n class=\"ax-input\"\n [class.ax-combo-box-select-input]=\"!editable()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly() || !editable()\"\n [(value)]=\"searchText\"\n [(expanded)]=\"expanded\"\n (click)=\"onTriggerClick()\"\n />\n\n <button\n type=\"button\"\n class=\"ax-general-button-icon\"\n tabindex=\"-1\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"onTriggerClick()\"\n >\n <span\n class=\"ax-icon\"\n [class.ax-icon-chevron-down]=\"!expanded()\"\n [class.ax-icon-chevron-up]=\"expanded()\"\n ></span>\n </button>\n <ng-content select=\"ax-suffix\"></ng-content>\n</div>\n\n<ax-popover\n [target]=\"origin\"\n [openOn]=\"'manual'\"\n [closeOn]=\"'clickOut'\"\n [placement]=\"'bottom-start'\"\n [width]=\"origin.offsetWidth + 'px'\"\n [disabled]=\"disabled() || readonly()\"\n (onClosed)=\"onPopoverClosed()\"\n>\n <ng-template ngComboboxPopup [combobox]=\"combobox\">\n <div class=\"ax-combo-box-popup\" [class.ax-is-empty]=\"filteredItems().length === 0\">\n @if (filteredItems().length === 0) {\n <div class=\"ax-combo-box-empty\">{{ '@acorex:common.general.no-result-found' | translate | async }}</div>\n }\n <div\n ngListbox\n ngComboboxWidget\n #listbox=\"ngListbox\"\n class=\"ax-combo-box-listbox\"\n [class.ax-hidden]=\"filteredItems().length === 0\"\n focusMode=\"activedescendant\"\n selectionMode=\"explicit\"\n [tabindex]=\"-1\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n [(value)]=\"selection\"\n (click)=\"commit()\"\n (keydown.enter)=\"commit()\"\n >\n @for (item of filteredItems(); track item.id) {\n <div ngOption class=\"ax-combo-box-option\" [value]=\"item.id\" [label]=\"item.text\">\n <span class=\"ax-combo-box-option-label\">{{ item.text }}</span>\n <span class=\"ax-combo-box-option-check\" aria-hidden=\"true\"></span>\n </div>\n }\n </div>\n </div>\n </ng-template>\n</ax-popover>\n", styles: ["@layer properties;@layer components{ax-combo-box{display:block;width:100%}ax-combo-box .ax-editor-container{justify-content:flex-start;gap:calc(var(--spacing, .25rem) * 1)}ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix{display:flex;width:calc(var(--spacing, .25rem) * 6);height:calc(var(--spacing, .25rem) * 6);flex-shrink:0;align-items:center;justify-content:center;gap:calc(var(--spacing, .25rem) * 0);align-self:center;padding:calc(var(--spacing, .25rem) * 0);padding-inline-end:calc(var(--spacing, .25rem) * 0)}:is(ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix)>ax-icon,:is(ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix)>ax-text{display:inline-flex;max-height:100%;max-width:100%;align-items:center;justify-content:center;--tw-leading: 1;line-height:1}:is(ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix)>ax-icon{width:calc(var(--spacing, .25rem) * 4);height:calc(var(--spacing, .25rem) * 4);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}ax-combo-box .ax-editor-container.ax-state-disabled{cursor:not-allowed;opacity:50%}ax-combo-box .ax-editor-container.ax-state-disabled .ax-input,ax-combo-box .ax-editor-container.ax-state-disabled .ax-editor{cursor:not-allowed}ax-combo-box .ax-editor-container.ax-state-readonly{opacity:75%}ax-combo-box .ax-combo-box-trigger{cursor:pointer;--tw-outline-style: none;outline-style:none;-webkit-user-select:none;user-select:none}ax-combo-box .ax-combo-box-select-input{cursor:pointer;caret-color:transparent;-webkit-user-select:none;user-select:none}.ax-combo-box-popup{--ax-comp-combo-box-popup-max-height: 15rem;box-sizing:border-box;width:100%;overflow:hidden;border-radius:var(--ax-sys-border-radius);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-border-surface));background-color:rgba(var(--ax-sys-color-lightest-surface));--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ax-combo-box-popup:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:rgba(var(--ax-sys-color-darkest-surface))}.ax-combo-box-popup.ax-is-empty{display:flex;min-height:calc(var(--spacing, .25rem) * 12);align-items:center;justify-content:center}.ax-combo-box-listbox{display:flex;max-height:var(--ax-comp-combo-box-popup-max-height);flex-direction:column;gap:calc(var(--spacing, .25rem) * .5);overflow:auto;padding:calc(var(--spacing, .25rem) * 1);--tw-outline-style: none;outline-style:none}.ax-combo-box-listbox.ax-hidden{display:none}.ax-combo-box-empty{width:100%;padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 3);text-align:center;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-on-surface))}@supports (color: color-mix(in lab,red,red)){.ax-combo-box-empty{color:color-mix(in oklab,rgba(var(--ax-sys-color-on-surface)) 60%,transparent)}}.ax-combo-box-option{display:flex;cursor:pointer;align-items:center;justify-content:space-between;border-radius:var(--ax-sys-border-radius);border-style:var(--tw-border-style);border-width:1px;border-color:transparent;padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-on-surface));--tw-outline-style: none;outline-style:none}.ax-combo-box-option:hover{background-color:rgba(var(--ax-sys-color-on-surface))}@supports (color: color-mix(in lab,red,red)){.ax-combo-box-option:hover{background-color:color-mix(in oklab,rgba(var(--ax-sys-color-on-surface)) 5%,transparent)}}.ax-combo-box-option[data-active=true]{border-color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-option[aria-selected=true]{border-color:rgba(var(--ax-sys-color-primary-surface));background-color:rgba(var(--ax-sys-color-primary-lightest-surface));color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-option[aria-selected=true]:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:rgba(var(--ax-sys-color-primary-darkest-surface))}@supports (color: color-mix(in lab,red,red)){.ax-combo-box-option[aria-selected=true]:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:color-mix(in oklab,rgba(var(--ax-sys-color-primary-darkest-surface)) 25%,transparent)}}.ax-combo-box-option[aria-selected=true] .ax-combo-box-option-check{display:block;width:calc(var(--spacing, .25rem) * 2);height:calc(var(--spacing, .25rem) * 2);rotate:45deg;border-right-style:var(--tw-border-style);border-right-width:2px;border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-option .ax-combo-box-option-check{display:none}}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: Combobox, selector: "[ngCombobox]", inputs: ["disabled", "readonly", "softDisabled", "alwaysExpanded", "tabindex", "expanded", "value", "inlineSuggestion"], outputs: ["expandedChange", "valueChange"], exportAs: ["ngCombobox"] }, { kind: "directive", type: ComboboxPopup, selector: "ng-template[ngComboboxPopup]", inputs: ["combobox", "popupType"], exportAs: ["ngComboboxPopup"] }, { kind: "directive", type: ComboboxWidget, selector: "[ngComboboxWidget]", inputs: ["activeDescendant"], exportAs: ["ngComboboxWidget"] }, { kind: "directive", type: Listbox, selector: "[ngListbox]", inputs: ["id", "orientation", "multi", "wrap", "softDisabled", "focusMode", "selectionMode", "typeaheadDelay", "disabled", "readonly", "tabindex", "value"], outputs: ["valueChange"], exportAs: ["ngListbox"] }, { kind: "directive", type: Option, selector: "[ngOption]", inputs: ["id", "value", "disabled", "label"], exportAs: ["ngOption"] }, { kind: "component", type: AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
509
213
  }
510
214
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxComponent, decorators: [{
511
215
  type: Component,
512
- args: [{ selector: 'ax-combo-box', inputs: [
513
- 'disabled',
514
- 'readonly',
515
- 'tabIndex',
516
- 'placeholder',
517
- 'minValue',
518
- 'maxValue',
519
- 'value',
520
- 'state',
521
- 'name',
522
- 'id',
523
- 'type',
524
- 'look',
525
- 'multiple',
526
- 'valueField',
527
- 'textField',
528
- 'disabledField',
529
- 'textTemplate',
530
- 'selectedItems',
531
- ], outputs: [
532
- 'valueChange',
533
- 'stateChange',
534
- 'onValueChanged',
535
- 'onBlur',
536
- 'onFocus',
537
- 'readonlyChange',
538
- 'disabledChange',
539
- 'onOpened',
540
- 'onClosed',
541
- 'onItemSelected',
542
- 'onItemClick',
543
- ], encapsulation: ViewEncapsulation.None, providers: [
544
- { provide: AXComponent, useExisting: AXComboBoxComponent },
545
- { provide: AXFocusableComponent, useExisting: AXComboBoxComponent },
546
- { provide: AXValuableComponent, useExisting: AXComboBoxComponent },
547
- { provide: AXClearableComponent, useExisting: AXComboBoxComponent },
548
- { provide: AXClosableComponent, useExisting: AXComboBoxComponent },
549
- { provide: AXSearchableComponent, useExisting: AXComboBoxComponent },
550
- {
551
- provide: NG_VALUE_ACCESSOR,
552
- useExisting: forwardRef(() => AXComboBoxComponent),
553
- multi: true,
554
- },
555
- {
556
- provide: AX_SELECTION_DATA_TOKEN,
557
- useClass: MXSelectionBridgeService,
558
- },
559
- AXUnsubscriber,
560
- ], host: { ngSkipHydration: 'true' }, imports: [
561
- AXDropdownBoxComponent,
562
- NgTemplateOutlet,
563
- NgClass,
564
- AXDecoratorGenericComponent,
565
- AXDecoratorCloseButtonComponent,
566
- AXListComponent,
567
- FormsModule,
568
- AsyncPipe,
569
- AXTranslatorPipe,
570
- AXTagComponent,
571
- AXLoadingSpinnerComponent,
572
- ], template: "<ax-dropdown-box\n [class.ax-state-multiple]=\"multiple\"\n (onOpened)=\"_handleOnOpenedEvent($event)\"\n (onClosed)=\"_handleOnClosedEvent($event)\"\n (focus)=\"emitOnFocusEvent($event)\"\n (blur)=\"emitOnBlurEvent($event)\"\n [disabled]=\"disabled\"\n [look]=\"look\"\n [popoverWidth]=\"dropdownWidth()\"\n>\n <ng-container input>\n <ng-content select=\"ax-prefix\"> </ng-content>\n <div\n class=\"ax-editor ax-chips-container ax-content ax-input\"\n [class.ax-state-multiple]=\"multiple\"\n [tabindex]=\"tabIndex\"\n >\n @if (selectedItems.length === 0) {\n <div class=\"ax-placeholder\" role=\"textbox\" area-readonly=\"true\">\n {{ placeholder | translate | async }}\n </div>\n }\n @for (item of selectedItems; track $index) {\n @if (selectedTemplate) {\n <ng-template\n [ngTemplateOutlet]=\"selectedTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { data: item } }\"\n ></ng-template>\n } @else {\n @if (multiple) {\n <ax-tag [text]=\"getDisplayText(item) | translate | async\" look=\"twotone\">\n @if (!disabled && !readonly && multiple) {\n <ax-suffix>\n <span class=\"ax-icon ax-icon-close\" (click)=\"_handleBadgeRemove($event, item)\"></span>\n </ax-suffix>\n }\n </ax-tag>\n } @else {\n {{ getDisplayText(item) | translate | async }}\n }\n }\n }\n </div>\n @if (selectedItems?.length && !disabled && !readonly) {\n <ng-content select=\"ax-clear-button\"></ng-content>\n }\n <button type=\"button\" [disabled]=\"disabled\" [tabIndex]=\"-1\" class=\"ax-general-button-icon\">\n @if (isLoading()) {\n <ax-loading-spinner [size]=\"16\" [stroke]=\"1\"></ax-loading-spinner>\n } @else {\n <span\n class=\"ax-icon\"\n [ngClass]=\"{\n 'ax-icon-chevron-down': !isOpen,\n 'ax-icon-chevron-up': isOpen,\n }\"\n ></span>\n }\n </button>\n <ng-content select=\"ax-suffix\"> </ng-content>\n <ng-template #search>\n <ng-content select=\"ax-search-box\"> </ng-content>\n </ng-template>\n </ng-container>\n <ng-container panel>\n <div\n #panel\n class=\"ax-combo-box-panel\"\n [class.ax-no-truncate]=\"!isItemTruncated()\"\n [style.min-width]=\"_dropdownWidth()\"\n >\n @if (dropdown.isActionsheetStyle) {\n <ax-header class=\"ax-solid\">\n <ax-title>{{ caption || placeholder || '@acorex:selectbox.popover.title' | translate | async }}</ax-title>\n <ax-close-button [icon]=\"multiple ? 'ax-icon ax-icon-check' : 'ax-icon ax-icon-close'\"></ax-close-button>\n </ax-header>\n }\n @if (searchBox && (!minRecordsForSearch || _listDataSource.totalCount >= minRecordsForSearch || searchValue())) {\n <div class=\"ax-search-container\">\n <ng-template [ngTemplateOutlet]=\"search\"></ng-template>\n </div>\n }\n @if (renderList()) {\n <ax-list\n [name]=\"name\"\n [ngModel]=\"value\"\n [readonly]=\"readonly\"\n [multiple]=\"multiple\"\n [textField]=\"textField\"\n [selectionMode]=\"'item'\"\n [valueField]=\"valueField\"\n [itemHeight]=\"itemHeight()\"\n [itemTemplate]=\"itemTemplate\"\n [textTemplate]=\"textTemplate\"\n [dataSource]=\"_listDataSource\"\n [style.height]=\"_dropdownHeight()\"\n [loadingTemplate]=\"loadingTemplate\"\n [isItemTruncated]=\"isItemTruncated()\"\n [showItemTooltip]=\"showItemTooltip()\"\n (onItemClick)=\"_handleItemClick($event)\"\n [emptyTemplate]=\"emptyTemplate ?? empty\"\n (onValueChanged)=\"_handleValueChanged($event)\"\n (onItemSelected)=\"_handleItemSelected($event)\"\n >\n </ax-list>\n <ng-template #empty>\n {{ '@acorex:common.general.no-result-found' | translate | async }}\n </ng-template>\n }\n\n @if (isLoading()) {\n @if (loadingTemplate) {\n <ng-template [ngTemplateOutlet]=\"loadingTemplate\"></ng-template>\n }\n }\n\n <ng-content select=\"ax-footer\"> </ng-content>\n </div>\n </ng-container>\n</ax-dropdown-box>\n<ng-content select=\"ax-validation-rule\"> </ng-content>\n", styles: ["@layer properties;@layer components{ax-combo-box .ax-editor-container{padding-block:calc(var(--spacing, .25rem) * 0)}ax-combo-box .ax-editor-container.ax-state-multiple{padding-inline:calc(var(--spacing, .25rem) * 1)}ax-combo-box .ax-editor-container.ax-state-multiple .ax-placeholder{padding-inline-start:calc(var(--spacing, .25rem) * 2)}ax-combo-box .ax-editor-container .ax-input,ax-combo-box .ax-editor-container .ax-editor{padding-block:calc(var(--spacing, .25rem) * 1)}ax-combo-box ax-dropdown-box.ax-state-multiple{height:auto!important;min-height:var(--ax-comp-editor-height);--ax-comp-editor-space-start-size: 0}ax-combo-box .ax-chips-container{display:flex;min-height:var(--ax-sys-size-base);min-width:calc(var(--spacing, .25rem) * 0);flex:1;cursor:pointer!important;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:var(--ax-comp-combo-box-chips-gap,.25rem);outline-style:var(--tw-outline-style);outline-width:0px;outline-color:transparent;-webkit-user-select:none;user-select:none}ax-combo-box .ax-chips-container .ax-selectbox-input{width:calc(var(--spacing, .25rem) * 0);opacity:0%}ax-combo-box .ax-chips-container.ax-state-multiple:has(.ax-chips){padding:var(--ax-comp-combo-box-chips-container-padding, .25rem)}ax-combo-box .ax-chips-container ax-tag ax-prefix,ax-combo-box .ax-chips-container ax-tag ax-suffix{padding:calc(var(--spacing, .25rem) * 0)!important}.ax-combo-box-panel{display:flex;height:fit-content;max-height:100%;flex-direction:column;overflow:hidden}.ax-combo-box-panel.ax-no-truncate .ax-label-container span:not(.ax-truncated){white-space:nowrap}.ax-combo-box-panel .ax-combo-box-loading-container{display:flex;align-items:center;justify-content:center;padding:calc(var(--spacing, .25rem) * 4)}.ax-combo-box-panel ax-list{min-height:calc(var(--spacing, .25rem) * 0);flex:1 1 auto}.ax-combo-box-panel>ax-header .ax-icon-check{color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-panel>ax-header.ax-solid{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:rgba(var(--ax-sys-color-border-lightest-surface))}.ax-combo-box-panel>ax-header.ax-solid ax-title{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));--tw-leading: calc(var(--spacing, .25rem) * 6);line-height:calc(var(--spacing, .25rem) * 6);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}@media(max-width:40rem){.ax-combo-box-panel .list-item{padding-inline:1rem}}}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-outline-style: solid;--tw-border-style: solid;--tw-leading: initial;--tw-font-weight: initial}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
573
- }], propDecorators: { isItemTruncated: [{ type: i0.Input, args: [{ isSignal: true, alias: "isItemTruncated", required: false }] }], showItemTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "showItemTooltip", required: false }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: false }] }], maxVisibleItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleItems", required: false }] }], dataSource: [{
574
- type: Input
575
- }], placeholder: [{
576
- type: Input
577
- }], minRecordsForSearch: [{
578
- type: Input
579
- }], caption: [{
580
- type: Input
581
- }], itemTemplate: [{
582
- type: Input
583
- }], selectedTemplate: [{
584
- type: Input
585
- }], emptyTemplate: [{
586
- type: Input
587
- }], loadingTemplate: [{
588
- type: Input
589
- }], dropdownWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownWidth", required: false }] }], panel: [{
590
- type: ViewChild,
591
- args: ['panel']
592
- }], list: [{
593
- type: ViewChild,
594
- args: [AXListComponent]
595
- }], searchBox: [{
596
- type: ContentChild,
597
- args: [AXSearchBoxComponent]
598
- }], searchBoxAutoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchBoxAutoFocus", required: false }] }], dropdown: [{
599
- type: ViewChild,
600
- args: [AXDropdownBoxComponent, { static: true }]
601
- }], _handleKeydown: [{
602
- type: HostListener,
603
- args: ['keydown', ['$event']]
604
- }], hostClickListener: [{
605
- type: HostListener,
606
- args: ['click']
607
- }] } });
216
+ args: [{ selector: 'ax-combo-box', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option, AXPopoverComponent, AXTranslatorPipe, AsyncPipe], providers: [{ provide: AXComponent, useExisting: AXComboBoxComponent }], template: "<div\n #origin\n class=\"ax-editor-container ax-{{ look() }} ax-default\"\n [class.ax-combo-box-trigger]=\"!editable()\"\n [class.ax-state-disabled]=\"disabled()\"\n [class.ax-state-readonly]=\"readonly()\"\n>\n <ng-content select=\"ax-prefix\"></ng-content>\n\n <input\n ngCombobox\n #combobox=\"ngCombobox\"\n type=\"text\"\n class=\"ax-input\"\n [class.ax-combo-box-select-input]=\"!editable()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly() || !editable()\"\n [(value)]=\"searchText\"\n [(expanded)]=\"expanded\"\n (click)=\"onTriggerClick()\"\n />\n\n <button\n type=\"button\"\n class=\"ax-general-button-icon\"\n tabindex=\"-1\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"onTriggerClick()\"\n >\n <span\n class=\"ax-icon\"\n [class.ax-icon-chevron-down]=\"!expanded()\"\n [class.ax-icon-chevron-up]=\"expanded()\"\n ></span>\n </button>\n <ng-content select=\"ax-suffix\"></ng-content>\n</div>\n\n<ax-popover\n [target]=\"origin\"\n [openOn]=\"'manual'\"\n [closeOn]=\"'clickOut'\"\n [placement]=\"'bottom-start'\"\n [width]=\"origin.offsetWidth + 'px'\"\n [disabled]=\"disabled() || readonly()\"\n (onClosed)=\"onPopoverClosed()\"\n>\n <ng-template ngComboboxPopup [combobox]=\"combobox\">\n <div class=\"ax-combo-box-popup\" [class.ax-is-empty]=\"filteredItems().length === 0\">\n @if (filteredItems().length === 0) {\n <div class=\"ax-combo-box-empty\">{{ '@acorex:common.general.no-result-found' | translate | async }}</div>\n }\n <div\n ngListbox\n ngComboboxWidget\n #listbox=\"ngListbox\"\n class=\"ax-combo-box-listbox\"\n [class.ax-hidden]=\"filteredItems().length === 0\"\n focusMode=\"activedescendant\"\n selectionMode=\"explicit\"\n [tabindex]=\"-1\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n [(value)]=\"selection\"\n (click)=\"commit()\"\n (keydown.enter)=\"commit()\"\n >\n @for (item of filteredItems(); track item.id) {\n <div ngOption class=\"ax-combo-box-option\" [value]=\"item.id\" [label]=\"item.text\">\n <span class=\"ax-combo-box-option-label\">{{ item.text }}</span>\n <span class=\"ax-combo-box-option-check\" aria-hidden=\"true\"></span>\n </div>\n }\n </div>\n </div>\n </ng-template>\n</ax-popover>\n", styles: ["@layer properties;@layer components{ax-combo-box{display:block;width:100%}ax-combo-box .ax-editor-container{justify-content:flex-start;gap:calc(var(--spacing, .25rem) * 1)}ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix{display:flex;width:calc(var(--spacing, .25rem) * 6);height:calc(var(--spacing, .25rem) * 6);flex-shrink:0;align-items:center;justify-content:center;gap:calc(var(--spacing, .25rem) * 0);align-self:center;padding:calc(var(--spacing, .25rem) * 0);padding-inline-end:calc(var(--spacing, .25rem) * 0)}:is(ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix)>ax-icon,:is(ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix)>ax-text{display:inline-flex;max-height:100%;max-width:100%;align-items:center;justify-content:center;--tw-leading: 1;line-height:1}:is(ax-combo-box .ax-editor-container ax-prefix,ax-combo-box .ax-editor-container ax-suffix)>ax-icon{width:calc(var(--spacing, .25rem) * 4);height:calc(var(--spacing, .25rem) * 4);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}ax-combo-box .ax-editor-container.ax-state-disabled{cursor:not-allowed;opacity:50%}ax-combo-box .ax-editor-container.ax-state-disabled .ax-input,ax-combo-box .ax-editor-container.ax-state-disabled .ax-editor{cursor:not-allowed}ax-combo-box .ax-editor-container.ax-state-readonly{opacity:75%}ax-combo-box .ax-combo-box-trigger{cursor:pointer;--tw-outline-style: none;outline-style:none;-webkit-user-select:none;user-select:none}ax-combo-box .ax-combo-box-select-input{cursor:pointer;caret-color:transparent;-webkit-user-select:none;user-select:none}.ax-combo-box-popup{--ax-comp-combo-box-popup-max-height: 15rem;box-sizing:border-box;width:100%;overflow:hidden;border-radius:var(--ax-sys-border-radius);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-border-surface));background-color:rgba(var(--ax-sys-color-lightest-surface));--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ax-combo-box-popup:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:rgba(var(--ax-sys-color-darkest-surface))}.ax-combo-box-popup.ax-is-empty{display:flex;min-height:calc(var(--spacing, .25rem) * 12);align-items:center;justify-content:center}.ax-combo-box-listbox{display:flex;max-height:var(--ax-comp-combo-box-popup-max-height);flex-direction:column;gap:calc(var(--spacing, .25rem) * .5);overflow:auto;padding:calc(var(--spacing, .25rem) * 1);--tw-outline-style: none;outline-style:none}.ax-combo-box-listbox.ax-hidden{display:none}.ax-combo-box-empty{width:100%;padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 3);text-align:center;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-on-surface))}@supports (color: color-mix(in lab,red,red)){.ax-combo-box-empty{color:color-mix(in oklab,rgba(var(--ax-sys-color-on-surface)) 60%,transparent)}}.ax-combo-box-option{display:flex;cursor:pointer;align-items:center;justify-content:space-between;border-radius:var(--ax-sys-border-radius);border-style:var(--tw-border-style);border-width:1px;border-color:transparent;padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:calc(var(--spacing, .25rem) * 2);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:rgba(var(--ax-sys-color-on-surface));--tw-outline-style: none;outline-style:none}.ax-combo-box-option:hover{background-color:rgba(var(--ax-sys-color-on-surface))}@supports (color: color-mix(in lab,red,red)){.ax-combo-box-option:hover{background-color:color-mix(in oklab,rgba(var(--ax-sys-color-on-surface)) 5%,transparent)}}.ax-combo-box-option[data-active=true]{border-color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-option[aria-selected=true]{border-color:rgba(var(--ax-sys-color-primary-surface));background-color:rgba(var(--ax-sys-color-primary-lightest-surface));color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-option[aria-selected=true]:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:rgba(var(--ax-sys-color-primary-darkest-surface))}@supports (color: color-mix(in lab,red,red)){.ax-combo-box-option[aria-selected=true]:where(.ax-dark,.ax-dark *):not(:where(.ax-light,.ax-light *)){background-color:color-mix(in oklab,rgba(var(--ax-sys-color-primary-darkest-surface)) 25%,transparent)}}.ax-combo-box-option[aria-selected=true] .ax-combo-box-option-check{display:block;width:calc(var(--spacing, .25rem) * 2);height:calc(var(--spacing, .25rem) * 2);rotate:45deg;border-right-style:var(--tw-border-style);border-right-width:2px;border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:rgba(var(--ax-sys-color-primary-surface))}.ax-combo-box-option .ax-combo-box-option-check{display:none}}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-leading: initial;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
217
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }, { type: i0.Output, args: ["readonlyChange"] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }, { type: i0.Output, args: ["lookChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onValueChanged: [{ type: i0.Output, args: ["onValueChanged"] }], onOpened: [{ type: i0.Output, args: ["onOpened"] }], onClosed: [{ type: i0.Output, args: ["onClosed"] }], comboboxRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Combobox), { isSignal: true }] }], listboxRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Listbox), { isSignal: true }] }], popoverRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPopoverComponent), { isSignal: true }] }] } });
608
218
 
609
219
  class AXComboBoxModule {
610
220
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
611
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxModule, imports: [CommonModule,
612
- AXCommonModule,
613
- FormsModule,
614
- AXCheckBoxModule,
615
- AXBadgeModule,
616
- AXDecoratorModule,
617
- AXTranslationModule,
618
- AXPopoverModule,
619
- AXLoadingModule,
620
- A11yModule,
621
- AXTextBoxModule,
622
- AXDropdownModule,
623
- AXListModule,
624
- AXComboBoxComponent], exports: [AXComboBoxComponent] }); }
625
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxModule, imports: [CommonModule,
626
- AXCommonModule,
627
- FormsModule,
628
- AXCheckBoxModule,
629
- AXBadgeModule,
630
- AXDecoratorModule,
631
- AXTranslationModule,
632
- AXPopoverModule,
633
- AXLoadingModule,
634
- A11yModule,
635
- AXTextBoxModule,
636
- AXDropdownModule,
637
- AXListModule,
638
- AXComboBoxComponent] }); }
221
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxModule, imports: [AXComboBoxComponent], exports: [AXComboBoxComponent] }); }
222
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxModule, imports: [AXComboBoxComponent] }); }
639
223
  }
640
224
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXComboBoxModule, decorators: [{
641
225
  type: NgModule,
642
226
  args: [{
643
- imports: [
644
- CommonModule,
645
- AXCommonModule,
646
- FormsModule,
647
- AXCheckBoxModule,
648
- AXBadgeModule,
649
- AXDecoratorModule,
650
- AXTranslationModule,
651
- AXPopoverModule,
652
- AXLoadingModule,
653
- A11yModule,
654
- AXTextBoxModule,
655
- AXDropdownModule,
656
- AXListModule,
657
- AXComboBoxComponent,
658
- ],
227
+ imports: [AXComboBoxComponent],
659
228
  exports: [AXComboBoxComponent],
660
- providers: [],
661
229
  }]
662
230
  }] });
663
231