@mathstack/ui 0.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/fesm2022/mathstack-ui.mjs +2175 -0
  4. package/fesm2022/mathstack-ui.mjs.map +1 -0
  5. package/index.d.ts +5 -0
  6. package/lib/combobox/combobox-label/combobox-label.component.d.ts +11 -0
  7. package/lib/combobox/combobox.component.d.ts +20 -0
  8. package/lib/combobox/combobox.module.d.ts +15 -0
  9. package/lib/combobox/combobox.service.d.ts +124 -0
  10. package/lib/combobox/editable-textbox/editable-textbox.component.d.ts +39 -0
  11. package/lib/combobox/index.d.ts +11 -0
  12. package/lib/combobox/listbox/active-index.service.d.ts +32 -0
  13. package/lib/combobox/listbox/listbox-filtering.service.d.ts +12 -0
  14. package/lib/combobox/listbox/listbox-scroll.service.d.ts +11 -0
  15. package/lib/combobox/listbox/listbox.component.d.ts +58 -0
  16. package/lib/combobox/listbox-group/listbox-group.component.d.ts +16 -0
  17. package/lib/combobox/listbox-label/listbox-label.component.d.ts +12 -0
  18. package/lib/combobox/listbox-option/listbox-option.component.d.ts +52 -0
  19. package/lib/combobox/select-all-listbox-option/select-all-listbox-option.component.d.ts +24 -0
  20. package/lib/combobox/textbox/textbox.component.d.ts +41 -0
  21. package/lib/directory/directory.component.d.ts +44 -0
  22. package/lib/directory/index.d.ts +1 -0
  23. package/lib/table/index.d.ts +4 -0
  24. package/lib/table/single-sort-header/single-sort-header.component.d.ts +9 -0
  25. package/lib/table/table-column.d.ts +53 -0
  26. package/lib/table/table.component.d.ts +27 -0
  27. package/lib/table/table.config.d.ts +5 -0
  28. package/lib/table/table.module.d.ts +11 -0
  29. package/lib/tabs/index.d.ts +6 -0
  30. package/lib/tabs/tab-body.component.d.ts +8 -0
  31. package/lib/tabs/tab-content.directive.d.ts +15 -0
  32. package/lib/tabs/tab-item.component.d.ts +16 -0
  33. package/lib/tabs/tab-label.component.d.ts +10 -0
  34. package/lib/tabs/tabs.component.d.ts +24 -0
  35. package/lib/tabs/tabs.module.d.ts +11 -0
  36. package/lib/tabs/tabs.service.d.ts +9 -0
  37. package/package.json +35 -0
  38. package/public-api.d.ts +4 -0
@@ -0,0 +1,2175 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Input, ViewChild, Component, ContentChildren, ContentChild, Injectable, Inject, EventEmitter, Output, forwardRef, TemplateRef, ViewEncapsulation, inject, DestroyRef, NgZone, NgModule, ChangeDetectionStrategy, InjectionToken, Directive } from '@angular/core';
3
+ import { BehaviorSubject, startWith, map, distinctUntilChanged, withLatestFrom, take, delay, skip, combineLatest, filter, pairwise, switchMap, merge, mergeAll, debounceTime, Subject, of, shareReplay, fromEvent, scan } from 'rxjs';
4
+ import * as i1 from '@angular/common';
5
+ import { CommonModule, DOCUMENT, AsyncPipe } from '@angular/common';
6
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
+ import * as i1$1 from '@angular/cdk/platform';
8
+ import { Platform } from '@angular/cdk/platform';
9
+ import * as i2 from '@angular/forms';
10
+ import { FormsModule } from '@angular/forms';
11
+ import { runNgChangeDetectionThen, NgOnChangesUtilities, safeAssign } from '@mathstack/app-kit';
12
+ import { MatIconModule } from '@angular/material/icon';
13
+ import { ascending, min } from 'd3';
14
+ import { isEqual } from 'lodash-es';
15
+ import * as i2$1 from '@angular/cdk/table';
16
+ import { CdkTableModule } from '@angular/cdk/table';
17
+
18
+ let nextUniqueId$3 = 0;
19
+ class ListboxOptionComponent {
20
+ constructor(service) {
21
+ this.service = service;
22
+ /** Whether the option is selected.
23
+ * If this property is changed during this component's lifecycle, no new value will be emitted from the listbox.
24
+ * Box label and select all button will respond to changes.
25
+ * @default false
26
+ */
27
+ this.selected = false;
28
+ /** Whether the option is selected.
29
+ * If this property is changed during this component's lifecycle, no new value will be emitted from the listbox.
30
+ * Box label and select all button will respond to changes.
31
+ * @default false
32
+ */
33
+ this.disabled = false;
34
+ this.id = nextUniqueId$3++;
35
+ // Only used for to update styles on change in listbox.component.html
36
+ this._selected = new BehaviorSubject(false);
37
+ this.selected$ = this._selected.asObservable();
38
+ this._disabled = new BehaviorSubject(false);
39
+ this.disabled$ = this._disabled.asObservable();
40
+ this.externalPropertyChanges = new BehaviorSubject(null);
41
+ this.externalPropertyChanges$ = this.externalPropertyChanges.asObservable();
42
+ }
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ get valueToEmit() {
45
+ return this.value || this.label?.nativeElement?.innerText.trim();
46
+ }
47
+ ngOnChanges(changes) {
48
+ if (changes['disabled']) {
49
+ this.updateDisabled(this.disabled);
50
+ if (!this.isFirstChangeAndValueIsFalse(changes, 'disabled')) {
51
+ this.externalPropertyChanges.next(this.getPropertyChange('disabled'));
52
+ }
53
+ }
54
+ if (changes['selected']) {
55
+ if (changes['selected'].isFirstChange()) {
56
+ this.updateSelected(this.selected);
57
+ if (this.selected) {
58
+ this.externalPropertyChanges.next(this.getPropertyChange('selected'));
59
+ }
60
+ }
61
+ else if (!this.disabled && this.selected !== this._selected.value) {
62
+ this.updateSelected(this.selected);
63
+ this.externalPropertyChanges.next(this.getPropertyChange('selected'));
64
+ }
65
+ }
66
+ }
67
+ isFirstChangeAndValueIsFalse(change, property) {
68
+ return change[property].isFirstChange() && !this[property];
69
+ }
70
+ getPropertyChange(property) {
71
+ return {
72
+ property,
73
+ value: this[property],
74
+ comboboxId: this.service.id,
75
+ id: this.id,
76
+ optionValue: this.valueToEmit,
77
+ };
78
+ }
79
+ updateSelected(selected) {
80
+ this._selected.next(selected);
81
+ }
82
+ updateDisabled(disabled) {
83
+ this._disabled.next(disabled);
84
+ }
85
+ select() {
86
+ if (!this._disabled.value) {
87
+ this.updateSelected(true);
88
+ }
89
+ }
90
+ deselect() {
91
+ if (!this._disabled.value) {
92
+ this.updateSelected(false);
93
+ }
94
+ }
95
+ toggleSelected() {
96
+ this.updateSelected(!this._selected.value);
97
+ }
98
+ isSelected() {
99
+ return this._selected.value;
100
+ }
101
+ isDisabled() {
102
+ return this._disabled.value;
103
+ }
104
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxOptionComponent, deps: [{ token: ComboboxService }], target: i0.ɵɵFactoryTarget.Component }); }
105
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: ListboxOptionComponent, isStandalone: true, selector: "hsi-ui-listbox-option", inputs: { boxDisplayLabel: "boxDisplayLabel", value: "value", selected: "selected", disabled: "disabled", ariaLabel: "ariaLabel" }, viewQueries: [{ propertyName: "label", first: true, predicate: ["label"], descendants: true }, { propertyName: "template", first: true, predicate: ["option"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #option>\n <div class=\"hsi-ui-listbox-option-container\">\n @if (isSelected()) {\n <ng-container *ngTemplateOutlet=\"selectedIcon\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"unselectedIcon\"></ng-container>\n }\n <div\n #label\n class=\"hsi-ui-listbox-option-label\"\n [attr.aria-label]=\"ariaLabel\"\n ><ng-content></ng-content\n ></div>\n </div>\n</ng-template>\n\n<ng-template #selectedIcon\n ><ng-content select=\"[selectedIcon]\"></ng-content>\n</ng-template>\n<ng-template #unselectedIcon\n ><ng-content select=\"[unselectedIcon]\"></ng-content>\n</ng-template>\n", styles: [".hsi-ui-listbox-option-container{display:var(--hsi-ui-listbox-option-container-display);flex-direction:var(--hsi-ui-listbox-option-container-flex-direction);align-items:var(--hsi-ui-listbox-option-container-align-items);cursor:var(--hsi-ui-listbox-option-cursor);padding:var(--hsi-ui-listbox-option-container-padding);gap:var(--hsi-ui-listbox-option-container-gap)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
106
+ }
107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxOptionComponent, decorators: [{
108
+ type: Component,
109
+ args: [{ selector: 'hsi-ui-listbox-option', imports: [CommonModule], template: "<ng-template #option>\n <div class=\"hsi-ui-listbox-option-container\">\n @if (isSelected()) {\n <ng-container *ngTemplateOutlet=\"selectedIcon\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"unselectedIcon\"></ng-container>\n }\n <div\n #label\n class=\"hsi-ui-listbox-option-label\"\n [attr.aria-label]=\"ariaLabel\"\n ><ng-content></ng-content\n ></div>\n </div>\n</ng-template>\n\n<ng-template #selectedIcon\n ><ng-content select=\"[selectedIcon]\"></ng-content>\n</ng-template>\n<ng-template #unselectedIcon\n ><ng-content select=\"[unselectedIcon]\"></ng-content>\n</ng-template>\n", styles: [".hsi-ui-listbox-option-container{display:var(--hsi-ui-listbox-option-container-display);flex-direction:var(--hsi-ui-listbox-option-container-flex-direction);align-items:var(--hsi-ui-listbox-option-container-align-items);cursor:var(--hsi-ui-listbox-option-cursor);padding:var(--hsi-ui-listbox-option-container-padding);gap:var(--hsi-ui-listbox-option-container-gap)}\n"] }]
110
+ }], ctorParameters: () => [{ type: ComboboxService }], propDecorators: { label: [{
111
+ type: ViewChild,
112
+ args: ['label']
113
+ }], template: [{
114
+ type: ViewChild,
115
+ args: ['option']
116
+ }], boxDisplayLabel: [{
117
+ type: Input
118
+ }], value: [{
119
+ type: Input
120
+ }], selected: [{
121
+ type: Input
122
+ }], disabled: [{
123
+ type: Input
124
+ }], ariaLabel: [{
125
+ type: Input
126
+ }] } });
127
+
128
+ let nextUniqueId$2 = 0;
129
+ class ListboxLabelComponent {
130
+ constructor(service) {
131
+ this.service = service;
132
+ this.id = `${this.service.id}-listbox-label-${nextUniqueId$2++}`;
133
+ }
134
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxLabelComponent, deps: [{ token: ComboboxService }], target: i0.ɵɵFactoryTarget.Component }); }
135
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: ListboxLabelComponent, isStandalone: true, selector: "hsi-ui-listbox-label", host: { classAttribute: "hsi-ui-listbox-label" }, viewQueries: [{ propertyName: "labelContent", first: true, predicate: ["label"], descendants: true }, { propertyName: "label", first: true, predicate: ["text"], descendants: true }], ngImport: i0, template: "<ng-template #label>\n <p class=\"hsi-ui-listbox-label\" [id]=\"id\" role=\"presentation\" #text\n ><ng-content></ng-content\n ></p>\n</ng-template>\n", styles: [".hsi-ui-listbox-label{padding:var(--hsi-ui-listbox-label-padding);font-size:var(--hsi-ui-listbox-label-font-size);font-weight:var(--hsi-ui-listbox-label-font-weight);text-transform:var(--hsi-ui-listbox-label-text-transform);margin-right:var(--hsi-ui-listbox-label-margin-right)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
136
+ }
137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxLabelComponent, decorators: [{
138
+ type: Component,
139
+ args: [{ selector: 'hsi-ui-listbox-label', imports: [CommonModule], host: {
140
+ class: 'hsi-ui-listbox-label',
141
+ }, template: "<ng-template #label>\n <p class=\"hsi-ui-listbox-label\" [id]=\"id\" role=\"presentation\" #text\n ><ng-content></ng-content\n ></p>\n</ng-template>\n", styles: [".hsi-ui-listbox-label{padding:var(--hsi-ui-listbox-label-padding);font-size:var(--hsi-ui-listbox-label-font-size);font-weight:var(--hsi-ui-listbox-label-font-weight);text-transform:var(--hsi-ui-listbox-label-text-transform);margin-right:var(--hsi-ui-listbox-label-margin-right)}\n"] }]
142
+ }], ctorParameters: () => [{ type: ComboboxService }], propDecorators: { labelContent: [{
143
+ type: ViewChild,
144
+ args: ['label']
145
+ }], label: [{
146
+ type: ViewChild,
147
+ args: ['text']
148
+ }] } });
149
+
150
+ class ListboxGroupComponent {
151
+ constructor(service) {
152
+ this.service = service;
153
+ }
154
+ ngAfterContentInit() {
155
+ this.options$ = this.options.changes.pipe(startWith(''), map(() => this.options.toArray()));
156
+ }
157
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxGroupComponent, deps: [{ token: ComboboxService }], target: i0.ɵɵFactoryTarget.Component }); }
158
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: ListboxGroupComponent, isStandalone: true, selector: "hsi-ui-listbox-group", host: { classAttribute: "hsi-ui-listbox-group" }, queries: [{ propertyName: "label", first: true, predicate: ListboxLabelComponent, descendants: true }, { propertyName: "options", predicate: ListboxOptionComponent }], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true }); }
159
+ }
160
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxGroupComponent, decorators: [{
161
+ type: Component,
162
+ args: [{
163
+ selector: 'hsi-ui-listbox-group',
164
+ template: `<ng-content></ng-content>`,
165
+ host: {
166
+ class: 'hsi-ui-listbox-group',
167
+ },
168
+ }]
169
+ }], ctorParameters: () => [{ type: ComboboxService }], propDecorators: { label: [{
170
+ type: ContentChild,
171
+ args: [ListboxLabelComponent]
172
+ }], options: [{
173
+ type: ContentChildren,
174
+ args: [ListboxOptionComponent]
175
+ }] } });
176
+
177
+ class ListboxFilteringService {
178
+ updateSearchString(char) {
179
+ if (typeof this.searchTimeout === 'number') {
180
+ clearTimeout(this.searchTimeout);
181
+ }
182
+ this.searchTimeout = setTimeout(() => {
183
+ this.searchString = '';
184
+ }, 500);
185
+ this.searchString += char;
186
+ }
187
+ resetSearch() {
188
+ clearTimeout(this.searchTimeout);
189
+ this.searchString = '';
190
+ }
191
+ getIndexByLetter(options, searchString, startIndex) {
192
+ const orderedOptions = [
193
+ ...options.slice(startIndex),
194
+ ...options.slice(0, startIndex),
195
+ ];
196
+ const firstMatch = this.filterOptionsBySearchString(orderedOptions, searchString)[0];
197
+ const allSameLetter = (array) => array.every((letter) => letter === array[0]);
198
+ if (firstMatch) {
199
+ return options.indexOf(firstMatch);
200
+ }
201
+ else if (allSameLetter(searchString.split(''))) {
202
+ const matches = this.filterOptionsBySearchString(orderedOptions, searchString[0]);
203
+ return options.indexOf(matches[0]);
204
+ }
205
+ else {
206
+ return -1;
207
+ }
208
+ }
209
+ filterOptionsBySearchString(options = [], searchString, exclude = []) {
210
+ return options.filter((option) => {
211
+ const matches = option.label?.nativeElement.innerText
212
+ .toLowerCase()
213
+ .indexOf(searchString.toLowerCase()) === 0;
214
+ return (matches &&
215
+ exclude
216
+ .map((x) => x.label?.nativeElement.innerText)
217
+ .indexOf(option.label?.nativeElement.innerText) < 0);
218
+ });
219
+ }
220
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxFilteringService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
221
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxFilteringService }); }
222
+ }
223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxFilteringService, decorators: [{
224
+ type: Injectable
225
+ }] });
226
+
227
+ class ListboxScrollService {
228
+ constructor(document) {
229
+ this.document = document;
230
+ }
231
+ isElementInView(element) {
232
+ const bounding = element.getBoundingClientRect();
233
+ return (bounding.top >= 0 &&
234
+ bounding.left >= 0 &&
235
+ bounding.bottom <=
236
+ (window.innerHeight || this.document.documentElement.clientHeight) &&
237
+ bounding.right <=
238
+ (window.innerWidth || this.document.documentElement.clientWidth));
239
+ }
240
+ isScrollable(element) {
241
+ return element && element.parentElement.clientHeight < element.scrollHeight;
242
+ }
243
+ maintainElementVisibility(activeElement, scrollParent) {
244
+ const { offsetHeight, offsetTop } = activeElement;
245
+ const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;
246
+ const isAbove = offsetTop < scrollTop;
247
+ const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
248
+ if (isAbove) {
249
+ scrollParent.scrollTo(0, offsetTop);
250
+ }
251
+ else if (isBelow) {
252
+ scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight);
253
+ }
254
+ }
255
+ scrollToTop(scrollParent) {
256
+ scrollParent.scrollTo(0, 0);
257
+ }
258
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxScrollService, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
259
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxScrollService }); }
260
+ }
261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxScrollService, decorators: [{
262
+ type: Injectable
263
+ }], ctorParameters: () => [{ type: Document, decorators: [{
264
+ type: Inject,
265
+ args: [DOCUMENT]
266
+ }] }] });
267
+
268
+ class ActiveIndexService {
269
+ constructor(service, filtering, scrolling) {
270
+ this.service = service;
271
+ this.filtering = filtering;
272
+ this.scrolling = scrolling;
273
+ this.activeIndex = new BehaviorSubject(null);
274
+ this.activeIndex$ = this.activeIndex.asObservable().pipe(distinctUntilChanged());
275
+ }
276
+ init(allOptions$, destroyRef) {
277
+ this.listenToActions(allOptions$, destroyRef);
278
+ this.initActiveId();
279
+ this.setActiveDescendant();
280
+ }
281
+ setScrollContentRef(scrollContentRef) {
282
+ this.scrollContentRef = scrollContentRef;
283
+ }
284
+ initActiveId() {
285
+ if (!this.service.nullActiveIdOnClose) {
286
+ this.activeIndex.next(0);
287
+ }
288
+ }
289
+ listenToActions(allOptions$, destroyRef) {
290
+ this.service.optionAction$
291
+ .pipe(takeUntilDestroyed(destroyRef), withLatestFrom(this.activeIndex$, allOptions$))
292
+ .subscribe(([action, activeIndex, options]) => {
293
+ if (!this.actionIsTypingChar(action)) {
294
+ if (action === OptionAction.last ||
295
+ action === OptionAction.next ||
296
+ action === OptionAction.pageDown) {
297
+ this.setNextActiveIndex(action, activeIndex, options);
298
+ }
299
+ else if (action === OptionAction.first ||
300
+ action === OptionAction.pageUp ||
301
+ action === OptionAction.previous) {
302
+ this.setPrevActiveIndex(action, activeIndex, options);
303
+ }
304
+ else if (action === OptionAction.zeroActiveIndex) {
305
+ this.setActiveIndex(0, OptionAction.next, options);
306
+ }
307
+ else if (action === OptionAction.nullActiveIndex) {
308
+ // should only be emitted from editable textboxes
309
+ if (this.service.nullActiveIdOnClose) {
310
+ this.setActiveIndex(null, OptionAction.next, options);
311
+ }
312
+ }
313
+ }
314
+ else if (action.length === 1) {
315
+ this.updateActiveIndexFromKeyChar(action, options);
316
+ }
317
+ });
318
+ }
319
+ setNextActiveIndex(action, activeIndex, options) {
320
+ const maxIndex = options.length - 1;
321
+ if (activeIndex === null && action === OptionAction.next) {
322
+ this.setActiveIndex(0, OptionAction.next, options);
323
+ }
324
+ else {
325
+ this.setActiveIndex(this.getIndexForAction(activeIndex, maxIndex, action), OptionAction.next, options);
326
+ }
327
+ }
328
+ setPrevActiveIndex(action, activeIndex, options) {
329
+ const maxIndex = options.length - 1;
330
+ this.setActiveIndex(this.getIndexForAction(activeIndex, maxIndex, action), OptionAction.previous, options);
331
+ }
332
+ setActiveIndex(index, actionIfDisabled, options, scrollToIndex = true) {
333
+ if (index === this.activeIndex.value)
334
+ return;
335
+ if (index === null || options.every((x) => x.isDisabled())) {
336
+ this.handleActiveIndexWhenCannotBeSet();
337
+ }
338
+ else {
339
+ let attempt = index;
340
+ while (actionIfDisabled && options[attempt]?.isDisabled()) {
341
+ if (actionIfDisabled === OptionAction.next) {
342
+ if (attempt === options.length - 1) {
343
+ attempt = 0;
344
+ }
345
+ else {
346
+ attempt++;
347
+ }
348
+ }
349
+ else if (actionIfDisabled === OptionAction.previous) {
350
+ if (attempt === 0) {
351
+ attempt = options.length - 1;
352
+ }
353
+ else {
354
+ attempt--;
355
+ }
356
+ }
357
+ }
358
+ if (attempt >= 0 &&
359
+ attempt < options.length &&
360
+ !options[attempt]?.isDisabled()) {
361
+ if (scrollToIndex) {
362
+ this.handleScrollingForNewIndex(attempt, options);
363
+ }
364
+ this.activeIndex.next(attempt);
365
+ }
366
+ else {
367
+ this.handleActiveIndexWhenCannotBeSet();
368
+ }
369
+ }
370
+ }
371
+ handleActiveIndexWhenCannotBeSet() {
372
+ this.service.emitTextboxFocus(FocusTextbox.includeMobile);
373
+ if (this.service.autoComplete !== AutoComplete.none) {
374
+ this.activeIndex.next(null);
375
+ }
376
+ }
377
+ handleScrollingForNewIndex(index, options) {
378
+ const indexEl = options[index].label?.nativeElement.parentElement;
379
+ if (indexEl && this.scrollContentRef.nativeElement) {
380
+ if (this.scrolling.isScrollable(this.scrollContentRef.nativeElement)) {
381
+ this.scrolling.maintainElementVisibility(indexEl, this.scrollContentRef.nativeElement);
382
+ }
383
+ if (!this.scrolling.isElementInView(indexEl)) {
384
+ indexEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
385
+ }
386
+ }
387
+ }
388
+ getIndexForAction(currentIndex, maxIndex, action) {
389
+ const pageSize = 10; // used for pageup/pagedown
390
+ const loop = this.service.autoComplete !== AutoComplete.none;
391
+ const validIndex = currentIndex ?? 0;
392
+ const previous = () => {
393
+ if (loop) {
394
+ return validIndex === 0 ? maxIndex : validIndex - 1;
395
+ }
396
+ else {
397
+ return Math.max(0, validIndex - 1);
398
+ }
399
+ };
400
+ const next = () => {
401
+ if (loop) {
402
+ return validIndex === maxIndex ? 0 : validIndex + 1;
403
+ }
404
+ else {
405
+ return Math.min(maxIndex, validIndex + 1);
406
+ }
407
+ };
408
+ switch (action) {
409
+ case OptionAction.first:
410
+ return 0;
411
+ case OptionAction.last:
412
+ return maxIndex;
413
+ case OptionAction.previous:
414
+ return previous();
415
+ case OptionAction.next:
416
+ return next();
417
+ case OptionAction.pageUp:
418
+ return Math.max(0, validIndex - pageSize);
419
+ case OptionAction.pageDown:
420
+ return Math.min(maxIndex, validIndex + pageSize);
421
+ default:
422
+ return validIndex;
423
+ }
424
+ }
425
+ actionIsTypingChar(action) {
426
+ return !Object.values(OptionAction).includes(action);
427
+ }
428
+ updateActiveIndexFromKeyChar(char, options) {
429
+ this.filtering.updateSearchString(char);
430
+ const searchIndex = this.filtering.getIndexByLetter(options, this.filtering.searchString, this.activeIndex.value + 1);
431
+ if (searchIndex >= 0) {
432
+ this.setActiveIndex(searchIndex, OptionAction.next, options);
433
+ }
434
+ else {
435
+ this.filtering.resetSearch();
436
+ }
437
+ }
438
+ setActiveDescendant() {
439
+ const activeDescendant$ = this.activeIndex$.pipe(map((i) => {
440
+ if (i === null || i < 0) {
441
+ return null;
442
+ }
443
+ else {
444
+ return `${this.service.id}-listbox-option-${i}`;
445
+ }
446
+ }));
447
+ this.service.initActiveDescendant(activeDescendant$);
448
+ }
449
+ setActiveIndexToFirstSelectedOrDefault(options) {
450
+ let firstSelected = options.findIndex((x) => x.isSelected());
451
+ if (firstSelected === -1) {
452
+ if (this.service.shouldAutoSelectOnListboxClose) {
453
+ firstSelected = 0;
454
+ }
455
+ else {
456
+ firstSelected = this.service.nullActiveIdOnClose ? null : 0;
457
+ }
458
+ }
459
+ if (firstSelected > -1) {
460
+ this.setActiveIndex(firstSelected, OptionAction.next, options);
461
+ }
462
+ if (firstSelected === null) {
463
+ this.activeIndex.next(null);
464
+ }
465
+ }
466
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ActiveIndexService, deps: [{ token: ComboboxService }, { token: ListboxFilteringService }, { token: ListboxScrollService }], target: i0.ɵɵFactoryTarget.Injectable }); }
467
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ActiveIndexService }); }
468
+ }
469
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ActiveIndexService, decorators: [{
470
+ type: Injectable
471
+ }], ctorParameters: () => [{ type: ComboboxService }, { type: ListboxFilteringService }, { type: ListboxScrollService }] });
472
+
473
+ class ListboxComponent {
474
+ constructor(service, activeIndex, filtering, scrolling, destroyRef) {
475
+ this.service = service;
476
+ this.activeIndex = activeIndex;
477
+ this.filtering = filtering;
478
+ this.scrolling = scrolling;
479
+ this.destroyRef = destroyRef;
480
+ this.findsOptionOnTyping = true;
481
+ this.isMultiSelect = false;
482
+ this.maxHeight = 300;
483
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
484
+ this.valueChanges = new EventEmitter();
485
+ }
486
+ ngOnChanges(changes) {
487
+ if (changes['isMultiSelect']) {
488
+ this.service.isMultiSelect = this.isMultiSelect;
489
+ }
490
+ }
491
+ ngAfterContentInit() {
492
+ this.service.setProjectedContent(this.groups, this.options);
493
+ this.options
494
+ .toArray()
495
+ .concat(this.groups.toArray().flatMap((group) => group.options?.toArray() ?? []))
496
+ .filter((option) => option instanceof SelectAllListboxOptionComponent)
497
+ .forEach((option) => {
498
+ option.setControlledOptions();
499
+ option.listenForOptionSelections();
500
+ });
501
+ this.activeIndex.init(this.service.allOptions$, this.destroyRef);
502
+ this.setSelectedEmitting();
503
+ this.setOnBlurEvent();
504
+ this.setOptionAction();
505
+ setTimeout(() => {
506
+ this.updateActiveIndexOnExternalChanges();
507
+ }, 0);
508
+ }
509
+ ngAfterViewInit() {
510
+ this.activeIndex.setScrollContentRef(this.scrollableContentRef);
511
+ this.setResetOnClose();
512
+ this.setOnOptionChanges();
513
+ }
514
+ setOnOptionChanges() {
515
+ this.service.allOptions$.pipe(take(1), delay(0)).subscribe(() => {
516
+ this.service.setProjectedContentIsInDOM();
517
+ });
518
+ // cannot pass allOptions$ to handleOptionClick through template because @if (allOptions | async; as allOptions) will delay rendering of option.template and option.label will not be defined when setBoxLabel is called. Thus subscribe and set allOptions in here.
519
+ this.service.allOptions$
520
+ .pipe(takeUntilDestroyed(this.destroyRef))
521
+ .subscribe((options) => {
522
+ this.service.allOptions = options;
523
+ });
524
+ }
525
+ setSelectedEmitting() {
526
+ this.service.selectedOptionsToEmit$
527
+ .pipe(takeUntilDestroyed(this.destroyRef), skip(1), map((options) => {
528
+ const selections = [];
529
+ for (const option of options) {
530
+ const value = option.valueToEmit;
531
+ selections.push(value);
532
+ }
533
+ return selections;
534
+ }))
535
+ .subscribe((value) => {
536
+ this.emitValue(value);
537
+ });
538
+ }
539
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
540
+ emitValue(selections) {
541
+ const value = this.isMultiSelect ? selections : selections[0];
542
+ if (this.ngFormControl) {
543
+ this.ngFormControl.setValue(value);
544
+ }
545
+ else {
546
+ this.valueChanges.emit(value);
547
+ }
548
+ }
549
+ setOnBlurEvent() {
550
+ this.service.textboxBlur$
551
+ .pipe(takeUntilDestroyed(this.destroyRef), withLatestFrom(combineLatest([this.service.isOpen$, this.activeIndex.activeIndex$]), this.service.allOptions$), filter(([, [isOpen]]) => isOpen))
552
+ .subscribe(([, [isOpen, activeIndex], options]) => {
553
+ if (isOpen) {
554
+ if (this.shouldAutoSelectOptionOnBlur(activeIndex, options)) {
555
+ const index = activeIndex ?? 0;
556
+ this.selectOptionFromIndex(index, options);
557
+ }
558
+ this.service.closeListbox();
559
+ }
560
+ });
561
+ }
562
+ shouldAutoSelectOptionOnBlur(activeIndex, options) {
563
+ const activeIndexOptionIsSelected = options[activeIndex]?.isSelected();
564
+ return (this.service.shouldAutoSelectOnListboxClose &&
565
+ !activeIndexOptionIsSelected);
566
+ }
567
+ setOptionAction() {
568
+ this.service.optionAction$
569
+ .pipe(takeUntilDestroyed(this.destroyRef), withLatestFrom(this.activeIndex.activeIndex$, this.service.allOptions$))
570
+ .subscribe(([action, activeIndex, options]) => {
571
+ if (options.length === 0) {
572
+ this.service.emitTextboxFocus();
573
+ return;
574
+ }
575
+ if (!this.actionIsTypingChar(action)) {
576
+ if (action === OptionAction.select) {
577
+ this.selectOptionFromIndex(activeIndex, options);
578
+ }
579
+ //double check because typesafety on this kind of sucks, could add && str.match(/\S| /)
580
+ }
581
+ else if (action.length === 1) {
582
+ this.activeIndex.updateActiveIndexFromKeyChar(action, options);
583
+ }
584
+ else {
585
+ throw new Error(`Invalid action: ${action}`);
586
+ }
587
+ });
588
+ }
589
+ actionIsTypingChar(action) {
590
+ return !Object.values(OptionAction).includes(action);
591
+ }
592
+ setResetOnClose() {
593
+ this.service.isOpen$
594
+ .pipe(takeUntilDestroyed(this.destroyRef), skip(1), filter((isOpen) => !isOpen), withLatestFrom(this.service.allOptions$))
595
+ .subscribe(([, options]) => {
596
+ this.activeIndex.setActiveIndexToFirstSelectedOrDefault(options);
597
+ this.resetScroll();
598
+ this.service.emitTextboxFocus(FocusTextbox.includeMobile);
599
+ });
600
+ }
601
+ resetScroll() {
602
+ if (this.scrolling.isScrollable(this.scrollableContentRef.nativeElement)) {
603
+ this.scrolling.scrollToTop(this.scrollableContentRef.nativeElement.parentElement);
604
+ }
605
+ }
606
+ getListboxLabelAsBoxPlaceholder() {
607
+ return this.label?.label?.nativeElement.innerText || '';
608
+ }
609
+ selectOptionFromIndex(index, options) {
610
+ this.handleOptionSelect(index, options);
611
+ }
612
+ handleOptionClick(event, optionIndex, groupIndex) {
613
+ event.stopPropagation();
614
+ this.service.setIsKeyboardEvent(false);
615
+ this.handleOptionSelect(optionIndex, this.service.allOptions, groupIndex);
616
+ if (!this.isMultiSelect) {
617
+ this.service.closeListbox();
618
+ }
619
+ this.service.emitTextboxFocus();
620
+ }
621
+ handleOptionSelect(optionIndex, options, groupIndex) {
622
+ const index = groupIndex
623
+ ? this.getOptionIndexFromGroups(groupIndex, optionIndex)
624
+ : optionIndex;
625
+ const option = options[index];
626
+ if (!option || option.isDisabled())
627
+ return;
628
+ this.toggleOptionSelected(option, options);
629
+ if (options[optionIndex].isSelected()) {
630
+ this.activeIndex.setActiveIndex(index, null, options);
631
+ }
632
+ else {
633
+ let nextSelectedIndex = options.findIndex((o, i) => i > optionIndex && o.isSelected());
634
+ if (nextSelectedIndex === -1) {
635
+ nextSelectedIndex = options.findIndex((o) => o.isSelected());
636
+ }
637
+ this.activeIndex.setActiveIndex(nextSelectedIndex, null, options);
638
+ }
639
+ }
640
+ toggleOptionSelected(option, options) {
641
+ if (!option || option.isDisabled()) {
642
+ this.service.emitTextboxFocus();
643
+ return;
644
+ }
645
+ if (this.isMultiSelect) {
646
+ option.toggleSelected();
647
+ this.updateSelectedOptionsToEmit(options);
648
+ }
649
+ else {
650
+ this.selectSingleSelectOption(option, options);
651
+ }
652
+ }
653
+ updateSelectedOptionsToEmit(options) {
654
+ const selected = this.getSelectedOptions(options);
655
+ this.service.setSelectedOptionsToEmit(selected);
656
+ }
657
+ selectSingleSelectOption(option, options) {
658
+ if (option.isSelected())
659
+ return;
660
+ options.forEach((o) => {
661
+ if (o !== option) {
662
+ o.deselect();
663
+ }
664
+ });
665
+ option.select();
666
+ this.updateSelectedOptionsToEmit(options);
667
+ }
668
+ isSelectAllListboxOption(option) {
669
+ return option instanceof SelectAllListboxOptionComponent;
670
+ }
671
+ getOptionIndexFromGroups(groupIndex, optionIndex) {
672
+ return (this.groups
673
+ .toArray()
674
+ .slice(0, groupIndex)
675
+ .reduce((acc, curr) => acc + curr.options.toArray().length, 0) +
676
+ optionIndex);
677
+ }
678
+ getSelectedOptions(options) {
679
+ return options?.filter((option) => !this.isSelectAllListboxOption(option) && option.isSelected());
680
+ }
681
+ updateActiveIndexOnExternalChanges() {
682
+ this.service.optionPropertyChanges$
683
+ .pipe(takeUntilDestroyed(this.destroyRef), pairwise(), filter(([prev, curr]) => {
684
+ return !!prev && !!curr && prev.optionValue !== curr.optionValue;
685
+ }), withLatestFrom(this.service.allOptions$, this.activeIndex.activeIndex$))
686
+ .subscribe(([, options]) => {
687
+ this.activeIndex.setActiveIndexToFirstSelectedOrDefault(options);
688
+ });
689
+ }
690
+ handleOptionMousedown() {
691
+ this.service.ignoreBlur = true;
692
+ }
693
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxComponent, deps: [{ token: ComboboxService }, { token: ActiveIndexService }, { token: ListboxFilteringService }, { token: ListboxScrollService }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
694
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: ListboxComponent, isStandalone: true, selector: "hsi-ui-listbox", inputs: { ngFormControl: "ngFormControl", findsOptionOnTyping: "findsOptionOnTyping", isMultiSelect: "isMultiSelect", maxHeight: "maxHeight" }, outputs: { valueChanges: "valueChanges" }, host: { classAttribute: "hsi-ui-listbox-component" }, providers: [
695
+ ListboxFilteringService,
696
+ ListboxScrollService,
697
+ ActiveIndexService,
698
+ ], queries: [{ propertyName: "label", first: true, predicate: ListboxLabelComponent }, { propertyName: "options", predicate: ListboxOptionComponent }, { propertyName: "groups", predicate: ListboxGroupComponent }], viewQueries: [{ propertyName: "scrollableContentRef", first: true, predicate: ["scrollableContent"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #scrollableContent\n role=\"listbox\"\n tabindex=\"-1\"\n [id]=\"service.id + '-listbox'\"\n class=\"hsi-ui-listbox\"\n [class.open]=\"service.isOpen$ | async\"\n [style.--hsi-ui-listbox-max-height.px]=\"maxHeight\"\n [attr.aria-labelledby]=\"\n (service.label$ | async) ? service.comboboxLabelId : label?.id\n \"\n [attr.aria-multiselectable]=\"isMultiSelect\"\n>\n <ng-container\n *ngTemplateOutlet=\"label?.labelContent || nullContent\"\n ></ng-container>\n @if ((service.groups$ | async)?.length > 0) {\n <ng-container *ngTemplateOutlet=\"groupedOptions\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"options\"></ng-container>\n }\n</div>\n\n<ng-template #options>\n @for (\n option of service.allOptions$ | async;\n track option.id;\n let i = $index\n ) {\n <ng-container\n *ngTemplateOutlet=\"\n optionTemplate;\n context: {\n $implicit: option,\n index: i,\n groupIndex: null,\n }\n \"\n ></ng-container>\n }\n</ng-template>\n\n<ng-template #groupedOptions>\n @for (group of service.groups$ | async; track $index; let i = $index) {\n <div class=\"hsi-ui-listbox-group-container\">\n <div\n role=\"group\"\n tabIndex=\"-1\"\n class=\"hsi-ui-listbox-group\"\n [ngClass]=\"'listbox-group-' + i\"\n [attr.aria-labelledby]=\"group.label?.id\"\n >\n @if (group.label) {\n <div\n role=\"presentation\"\n [id]=\"group.label?.id\"\n class=\"hsi-ui-listbox-group-label\"\n [ngClass]=\"'hsi-ui-listbox-group-' + i + '-label'\"\n >\n <ng-container\n *ngTemplateOutlet=\"group.label?.labelContent || nullContent\"\n ></ng-container>\n </div>\n }\n @for (\n option of group.options$ | async;\n track option.id;\n let j = $index\n ) {\n <ng-container\n *ngTemplateOutlet=\"\n optionTemplate;\n context: {\n $implicit: option,\n index: j,\n groupIndex: i,\n }\n \"\n ></ng-container>\n }\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template\n #optionTemplate\n let-option\n let-index=\"index\"\n let-groupIndex=\"groupIndex\"\n>\n <div\n role=\"option\"\n tabindex=\"-1\"\n [id]=\"\n service.id +\n '-listbox-option-' +\n (groupIndex !== null\n ? getOptionIndexFromGroups(groupIndex, index)\n : index)\n \"\n class=\"hsi-ui-listbox-option\"\n [class.grouped-option]=\"groupIndex !== null\"\n [ngClass]=\"\n groupIndex !== null\n ? 'hsi-ui-listbox-option-' + getOptionIndexFromGroups(groupIndex, index)\n : 'hsi-ui-listbox-option-' + index\n \"\n [class.current]=\"\n (activeIndex.activeIndex$ | async) ===\n (groupIndex !== null\n ? getOptionIndexFromGroups(groupIndex, index)\n : index) && (option.disabled$ | async) !== true\n \"\n [class.disabled]=\"option.disabled$ | async\"\n [class.keyboard-current]=\"\n (service.isKeyboardEvent$ | async) &&\n (activeIndex.activeIndex$ | async) ===\n (groupIndex !== null\n ? getOptionIndexFromGroups(groupIndex, index)\n : index) &&\n (option.disabled$ | async) !== true\n \"\n [class.multi]=\"isMultiSelect\"\n [class.selected]=\"option.selected$ | async\"\n [attr.aria-checked]=\"isMultiSelect ? (option.selected$ | async) : null\"\n [attr.aria-selected]=\"!isMultiSelect ? (option.selected$ | async) : null\"\n [attr.aria-disabled]=\"option.disabled$ | async\"\n data-cy=\"listbox-option\"\n (click)=\"handleOptionClick($event, index, groupIndex)\"\n (mousedown)=\"handleOptionMousedown()\"\n >\n <ng-container *ngTemplateOutlet=\"option.template\"></ng-container>\n </div>\n</ng-template>\n\n<ng-template #nullContent></ng-template>\n", styles: [":host{position:absolute;top:100%;left:0;width:100%;z-index:var(--hsi-ui-listbox-z-index);background:var(--hsi-ui-listbox-background);border-bottom-left-radius:var(--hsi-ui-combobox-border-radius);border-bottom-right-radius:var(--hsi-ui-combobox-border-radius)}:host ::-webkit-scrollbar-track{background:transparent}.hsi-ui-listbox{padding-top:var(--hsi-ui-listbox-padding-top);background:var(--hsi-ui-listbox-background);border-left:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);border-right:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);border-bottom:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);border-bottom-left-radius:var(--hsi-ui-combobox-border-radius);border-bottom-right-radius:var(--hsi-ui-combobox-border-radius);max-height:var(--hsi-ui-listbox-max-height);overflow-y:auto}.hsi-ui-listbox:not(.open){display:none}.hsi-ui-listbox-option{display:block;cursor:pointer;margin-left:var(--hsi-ui-listbox-padding-left);margin-right:var(--hsi-ui-listbox-padding-right)}.hsi-ui-listbox-option:not(.grouped-option):last-child,.hsi-ui-listbox-group-container:last-child .hsi-ui-listbox-option:last-child,.hsi-ui-listbox-option.current.keyboard-current:not(.grouped-option):last-child,.hsi-ui-listbox-group-container:last-child .hsi-ui-listbox-option.current.keyboard-current:last-child{margin-bottom:var(--hsi-ui-listbox-padding-bottom);border-bottom-left-radius:var(--hsi-ui-combobox-border-radius);border-bottom-right-radius:var(--hsi-ui-combobox-border-radius)}.hsi-ui-listbox-option:hover{background:var(--hsi-ui-listbox-option-hover-background);border-radius:var(--hsi-ui-listbox-option-hover-border-radius)}.hsi-ui-listbox-option.selected{background:var(--hsi-ui-listbox-option-selected-background);border-radius:var(--hsi-ui-listbox-option-selected-border-radius)}.hsi-ui-listbox-option.disabled{color:var(--hsi-ui-listbox-option-disabled-color)}.hsi-ui-listbox-option.current.keyboard-current{background:var(--hsi-ui-listbox-option-current-background);color:var(--hsi-ui-listbox-option-current-color);border-radius:var(--hsi-ui-listbox-option-current-border-radius)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] }); }
699
+ }
700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ListboxComponent, decorators: [{
701
+ type: Component,
702
+ args: [{ selector: 'hsi-ui-listbox', imports: [CommonModule], providers: [
703
+ ListboxFilteringService,
704
+ ListboxScrollService,
705
+ ActiveIndexService,
706
+ ], host: {
707
+ class: 'hsi-ui-listbox-component',
708
+ }, template: "<div\n #scrollableContent\n role=\"listbox\"\n tabindex=\"-1\"\n [id]=\"service.id + '-listbox'\"\n class=\"hsi-ui-listbox\"\n [class.open]=\"service.isOpen$ | async\"\n [style.--hsi-ui-listbox-max-height.px]=\"maxHeight\"\n [attr.aria-labelledby]=\"\n (service.label$ | async) ? service.comboboxLabelId : label?.id\n \"\n [attr.aria-multiselectable]=\"isMultiSelect\"\n>\n <ng-container\n *ngTemplateOutlet=\"label?.labelContent || nullContent\"\n ></ng-container>\n @if ((service.groups$ | async)?.length > 0) {\n <ng-container *ngTemplateOutlet=\"groupedOptions\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"options\"></ng-container>\n }\n</div>\n\n<ng-template #options>\n @for (\n option of service.allOptions$ | async;\n track option.id;\n let i = $index\n ) {\n <ng-container\n *ngTemplateOutlet=\"\n optionTemplate;\n context: {\n $implicit: option,\n index: i,\n groupIndex: null,\n }\n \"\n ></ng-container>\n }\n</ng-template>\n\n<ng-template #groupedOptions>\n @for (group of service.groups$ | async; track $index; let i = $index) {\n <div class=\"hsi-ui-listbox-group-container\">\n <div\n role=\"group\"\n tabIndex=\"-1\"\n class=\"hsi-ui-listbox-group\"\n [ngClass]=\"'listbox-group-' + i\"\n [attr.aria-labelledby]=\"group.label?.id\"\n >\n @if (group.label) {\n <div\n role=\"presentation\"\n [id]=\"group.label?.id\"\n class=\"hsi-ui-listbox-group-label\"\n [ngClass]=\"'hsi-ui-listbox-group-' + i + '-label'\"\n >\n <ng-container\n *ngTemplateOutlet=\"group.label?.labelContent || nullContent\"\n ></ng-container>\n </div>\n }\n @for (\n option of group.options$ | async;\n track option.id;\n let j = $index\n ) {\n <ng-container\n *ngTemplateOutlet=\"\n optionTemplate;\n context: {\n $implicit: option,\n index: j,\n groupIndex: i,\n }\n \"\n ></ng-container>\n }\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template\n #optionTemplate\n let-option\n let-index=\"index\"\n let-groupIndex=\"groupIndex\"\n>\n <div\n role=\"option\"\n tabindex=\"-1\"\n [id]=\"\n service.id +\n '-listbox-option-' +\n (groupIndex !== null\n ? getOptionIndexFromGroups(groupIndex, index)\n : index)\n \"\n class=\"hsi-ui-listbox-option\"\n [class.grouped-option]=\"groupIndex !== null\"\n [ngClass]=\"\n groupIndex !== null\n ? 'hsi-ui-listbox-option-' + getOptionIndexFromGroups(groupIndex, index)\n : 'hsi-ui-listbox-option-' + index\n \"\n [class.current]=\"\n (activeIndex.activeIndex$ | async) ===\n (groupIndex !== null\n ? getOptionIndexFromGroups(groupIndex, index)\n : index) && (option.disabled$ | async) !== true\n \"\n [class.disabled]=\"option.disabled$ | async\"\n [class.keyboard-current]=\"\n (service.isKeyboardEvent$ | async) &&\n (activeIndex.activeIndex$ | async) ===\n (groupIndex !== null\n ? getOptionIndexFromGroups(groupIndex, index)\n : index) &&\n (option.disabled$ | async) !== true\n \"\n [class.multi]=\"isMultiSelect\"\n [class.selected]=\"option.selected$ | async\"\n [attr.aria-checked]=\"isMultiSelect ? (option.selected$ | async) : null\"\n [attr.aria-selected]=\"!isMultiSelect ? (option.selected$ | async) : null\"\n [attr.aria-disabled]=\"option.disabled$ | async\"\n data-cy=\"listbox-option\"\n (click)=\"handleOptionClick($event, index, groupIndex)\"\n (mousedown)=\"handleOptionMousedown()\"\n >\n <ng-container *ngTemplateOutlet=\"option.template\"></ng-container>\n </div>\n</ng-template>\n\n<ng-template #nullContent></ng-template>\n", styles: [":host{position:absolute;top:100%;left:0;width:100%;z-index:var(--hsi-ui-listbox-z-index);background:var(--hsi-ui-listbox-background);border-bottom-left-radius:var(--hsi-ui-combobox-border-radius);border-bottom-right-radius:var(--hsi-ui-combobox-border-radius)}:host ::-webkit-scrollbar-track{background:transparent}.hsi-ui-listbox{padding-top:var(--hsi-ui-listbox-padding-top);background:var(--hsi-ui-listbox-background);border-left:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);border-right:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);border-bottom:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);border-bottom-left-radius:var(--hsi-ui-combobox-border-radius);border-bottom-right-radius:var(--hsi-ui-combobox-border-radius);max-height:var(--hsi-ui-listbox-max-height);overflow-y:auto}.hsi-ui-listbox:not(.open){display:none}.hsi-ui-listbox-option{display:block;cursor:pointer;margin-left:var(--hsi-ui-listbox-padding-left);margin-right:var(--hsi-ui-listbox-padding-right)}.hsi-ui-listbox-option:not(.grouped-option):last-child,.hsi-ui-listbox-group-container:last-child .hsi-ui-listbox-option:last-child,.hsi-ui-listbox-option.current.keyboard-current:not(.grouped-option):last-child,.hsi-ui-listbox-group-container:last-child .hsi-ui-listbox-option.current.keyboard-current:last-child{margin-bottom:var(--hsi-ui-listbox-padding-bottom);border-bottom-left-radius:var(--hsi-ui-combobox-border-radius);border-bottom-right-radius:var(--hsi-ui-combobox-border-radius)}.hsi-ui-listbox-option:hover{background:var(--hsi-ui-listbox-option-hover-background);border-radius:var(--hsi-ui-listbox-option-hover-border-radius)}.hsi-ui-listbox-option.selected{background:var(--hsi-ui-listbox-option-selected-background);border-radius:var(--hsi-ui-listbox-option-selected-border-radius)}.hsi-ui-listbox-option.disabled{color:var(--hsi-ui-listbox-option-disabled-color)}.hsi-ui-listbox-option.current.keyboard-current{background:var(--hsi-ui-listbox-option-current-background);color:var(--hsi-ui-listbox-option-current-color);border-radius:var(--hsi-ui-listbox-option-current-border-radius)}\n"] }]
709
+ }], ctorParameters: () => [{ type: ComboboxService }, { type: ActiveIndexService }, { type: ListboxFilteringService }, { type: ListboxScrollService }, { type: i0.DestroyRef }], propDecorators: { ngFormControl: [{
710
+ type: Input
711
+ }], findsOptionOnTyping: [{
712
+ type: Input
713
+ }], isMultiSelect: [{
714
+ type: Input
715
+ }], maxHeight: [{
716
+ type: Input
717
+ }], valueChanges: [{
718
+ type: Output
719
+ }], scrollableContentRef: [{
720
+ type: ViewChild,
721
+ args: ['scrollableContent']
722
+ }], label: [{
723
+ type: ContentChild,
724
+ args: [ListboxLabelComponent, { descendants: false }]
725
+ }], options: [{
726
+ type: ContentChildren,
727
+ args: [ListboxOptionComponent, { descendants: false }]
728
+ }], groups: [{
729
+ type: ContentChildren,
730
+ args: [ListboxGroupComponent]
731
+ }] } });
732
+
733
+ class SelectAllListboxOptionComponent extends ListboxOptionComponent {
734
+ constructor(service, listboxComponent, destroyRef) {
735
+ super(service);
736
+ this.listboxComponent = listboxComponent;
737
+ this.destroyRef = destroyRef;
738
+ this.boxDisplayLabel = 'Select all';
739
+ }
740
+ // select all will not respond to changes in selected or disabled properties
741
+ // users should not attempt to change these properties
742
+ // TODO: better architecture for this
743
+ ngOnChanges() {
744
+ return;
745
+ }
746
+ updateSelected(selected) {
747
+ this._selected.next(selected);
748
+ }
749
+ setControlledOptions() {
750
+ this.controlledOptions$ = this.service.groups$.pipe(map((groups) => this.getControlledOptionsFromGroups(groups)));
751
+ this.controlledOptions$
752
+ .pipe(takeUntilDestroyed(this.destroyRef))
753
+ .subscribe((controlledOptions) => {
754
+ this.controlledOptions = controlledOptions;
755
+ });
756
+ }
757
+ getControlledOptionsFromGroups(groups) {
758
+ let controlledOptions = [];
759
+ if (groups.length > 0) {
760
+ const groupId = groups.findIndex((group) => {
761
+ return group.options.some((option) => option.id === this.id);
762
+ });
763
+ if (groupId > -1) {
764
+ controlledOptions = groups[groupId].options.filter((o) => o !== this);
765
+ }
766
+ }
767
+ else {
768
+ controlledOptions = this.listboxComponent.options.filter((option) => option !== this);
769
+ }
770
+ return controlledOptions;
771
+ }
772
+ listenForOptionSelections() {
773
+ const optionSelectionChanges$ = this.controlledOptions$.pipe(switchMap((options) => merge(options.map((o) => o.selected$))), mergeAll());
774
+ optionSelectionChanges$
775
+ .pipe(takeUntilDestroyed(this.destroyRef), debounceTime(0), withLatestFrom(this.controlledOptions$))
776
+ .subscribe(([, controlledOptions]) => {
777
+ this.updateSelectAllSelected(controlledOptions);
778
+ });
779
+ }
780
+ updateSelectAllSelected(controlledOptions) {
781
+ const allControlledOptionsSelected = controlledOptions.every((option) => option.isSelected());
782
+ this.updateSelected(allControlledOptionsSelected);
783
+ }
784
+ toggleSelected() {
785
+ this.updateSelected(!this._selected.value);
786
+ if (this._selected.value) {
787
+ this.controlledOptions.forEach((option) => option.select());
788
+ }
789
+ else {
790
+ this.controlledOptions.forEach((option) => option.deselect());
791
+ }
792
+ }
793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: SelectAllListboxOptionComponent, deps: [{ token: ComboboxService }, { token: ListboxComponent }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
794
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: SelectAllListboxOptionComponent, isStandalone: true, selector: "hsi-ui-select-all-listbox-option", inputs: { boxDisplayLabel: "boxDisplayLabel" }, providers: [
795
+ {
796
+ provide: ListboxOptionComponent,
797
+ useExisting: forwardRef(() => SelectAllListboxOptionComponent),
798
+ },
799
+ ], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ng-template #option>\n <div class=\"hsi-ui-listbox-option-container\">\n @if (isSelected()) {\n <ng-container *ngTemplateOutlet=\"selectedIcon\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"unselectedIcon\"></ng-container>\n }\n <div\n #label\n class=\"hsi-ui-listbox-option-label\"\n [attr.aria-label]=\"ariaLabel\"\n ><ng-content></ng-content\n ></div>\n </div>\n</ng-template>\n\n<ng-template #selectedIcon\n ><ng-content select=\"[selectedIcon]\"></ng-content>\n</ng-template>\n<ng-template #unselectedIcon\n ><ng-content select=\"[unselectedIcon]\"></ng-content>\n</ng-template>\n", styles: [".hsi-ui-listbox-option-container{display:var(--hsi-ui-listbox-option-container-display);flex-direction:var(--hsi-ui-listbox-option-container-flex-direction);align-items:var(--hsi-ui-listbox-option-container-align-items);cursor:var(--hsi-ui-listbox-option-cursor);padding:var(--hsi-ui-listbox-option-container-padding);gap:var(--hsi-ui-listbox-option-container-gap)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
800
+ }
801
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: SelectAllListboxOptionComponent, decorators: [{
802
+ type: Component,
803
+ args: [{ selector: 'hsi-ui-select-all-listbox-option', imports: [CommonModule], providers: [
804
+ {
805
+ provide: ListboxOptionComponent,
806
+ useExisting: forwardRef(() => SelectAllListboxOptionComponent),
807
+ },
808
+ ], template: "<ng-template #option>\n <div class=\"hsi-ui-listbox-option-container\">\n @if (isSelected()) {\n <ng-container *ngTemplateOutlet=\"selectedIcon\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"unselectedIcon\"></ng-container>\n }\n <div\n #label\n class=\"hsi-ui-listbox-option-label\"\n [attr.aria-label]=\"ariaLabel\"\n ><ng-content></ng-content\n ></div>\n </div>\n</ng-template>\n\n<ng-template #selectedIcon\n ><ng-content select=\"[selectedIcon]\"></ng-content>\n</ng-template>\n<ng-template #unselectedIcon\n ><ng-content select=\"[unselectedIcon]\"></ng-content>\n</ng-template>\n", styles: [".hsi-ui-listbox-option-container{display:var(--hsi-ui-listbox-option-container-display);flex-direction:var(--hsi-ui-listbox-option-container-flex-direction);align-items:var(--hsi-ui-listbox-option-container-align-items);cursor:var(--hsi-ui-listbox-option-cursor);padding:var(--hsi-ui-listbox-option-container-padding);gap:var(--hsi-ui-listbox-option-container-gap)}\n"] }]
809
+ }], ctorParameters: () => [{ type: ComboboxService }, { type: ListboxComponent }, { type: i0.DestroyRef }], propDecorators: { boxDisplayLabel: [{
810
+ type: Input
811
+ }] } });
812
+
813
+ let nextUniqueId$1 = 0;
814
+ var FocusTextbox;
815
+ (function (FocusTextbox) {
816
+ FocusTextbox["default"] = "default";
817
+ FocusTextbox["includeMobile"] = "includeMobile";
818
+ })(FocusTextbox || (FocusTextbox = {}));
819
+ var Key;
820
+ (function (Key) {
821
+ Key["ArrowDown"] = "ArrowDown";
822
+ Key["ArrowUp"] = "ArrowUp";
823
+ Key["End"] = "End";
824
+ Key["Enter"] = "Enter";
825
+ Key["Escape"] = "Escape";
826
+ Key["Home"] = "Home";
827
+ Key["LeftArrow"] = "ArrowLeft";
828
+ Key["PageDown"] = "PageDown";
829
+ Key["PageUp"] = "PageUp";
830
+ Key["RightArrow"] = "ArrowRight";
831
+ Key["Space"] = " ";
832
+ Key["Tab"] = "Tab";
833
+ })(Key || (Key = {}));
834
+ var OptionAction;
835
+ (function (OptionAction) {
836
+ OptionAction["first"] = "first";
837
+ OptionAction["last"] = "last";
838
+ OptionAction["next"] = "next";
839
+ OptionAction["nullActiveIndex"] = "nullActiveIndex";
840
+ OptionAction["pageDown"] = "pageDown";
841
+ OptionAction["pageUp"] = "pageUp";
842
+ OptionAction["previous"] = "previous";
843
+ OptionAction["select"] = "select";
844
+ OptionAction["zeroActiveIndex"] = "zeroActiveIndex";
845
+ })(OptionAction || (OptionAction = {}));
846
+ var ListboxAction;
847
+ (function (ListboxAction) {
848
+ ListboxAction["close"] = "close";
849
+ ListboxAction["open"] = "open";
850
+ ListboxAction["closeSelect"] = "closeSelect";
851
+ })(ListboxAction || (ListboxAction = {}));
852
+ var TextboxAction;
853
+ (function (TextboxAction) {
854
+ TextboxAction["focus"] = "focus";
855
+ TextboxAction["setTextToValue"] = "setTextToValue";
856
+ TextboxAction["cursorRight"] = "cursorRight";
857
+ TextboxAction["cursorLeft"] = "cursorLeft";
858
+ TextboxAction["cursorFirst"] = "cursorFirst";
859
+ TextboxAction["cursorLast"] = "cursorLast";
860
+ TextboxAction["addChar"] = "addChar";
861
+ TextboxAction["type"] = "type";
862
+ })(TextboxAction || (TextboxAction = {}));
863
+ var AutoComplete;
864
+ (function (AutoComplete) {
865
+ AutoComplete["none"] = "none";
866
+ AutoComplete["list"] = "list";
867
+ AutoComplete["both"] = "both";
868
+ AutoComplete["inline"] = "inline";
869
+ })(AutoComplete || (AutoComplete = {}));
870
+ class ComboboxService {
871
+ constructor(platform) {
872
+ this.platform = platform;
873
+ this.id = `combobox-${nextUniqueId$1++}`;
874
+ this.scrollContainerId = `${this.id}-scroll-container`;
875
+ this.comboboxLabelId = `${this.id}-label`;
876
+ this.autoComplete = AutoComplete.none;
877
+ this.hasEditableTextbox = false;
878
+ this.ignoreBlur = false;
879
+ this.isMultiSelect = false;
880
+ this.nullActiveIdOnClose = false;
881
+ this.scrollWhenOpened = false;
882
+ this.shouldAutoSelectOnListboxClose = false;
883
+ this.destroy$ = new Subject();
884
+ this.focusTextbox = new Subject();
885
+ this.focusTextbox$ = this.focusTextbox.asObservable();
886
+ this.isKeyboardEvent = new BehaviorSubject(false);
887
+ this.isKeyboardEvent$ = this.isKeyboardEvent.asObservable();
888
+ this._isOpen = new BehaviorSubject(false);
889
+ this.isOpen$ = this._isOpen.asObservable().pipe(distinctUntilChanged());
890
+ this.label = new BehaviorSubject(null);
891
+ this.label$ = this.label.asObservable();
892
+ this.optionAction = new Subject();
893
+ this.optionAction$ = this.optionAction.asObservable();
894
+ this.projectedContentIsInDOM = new BehaviorSubject(false);
895
+ this.projectedContentIsInDOM$ = this.projectedContentIsInDOM.asObservable();
896
+ this.selectedOptionsToEmit = new BehaviorSubject([]);
897
+ this.selectedOptionsToEmit$ = this.selectedOptionsToEmit.asObservable();
898
+ this.textboxBlur = new Subject();
899
+ this.textboxBlur$ = this.textboxBlur.asObservable();
900
+ this.touched = new BehaviorSubject(false);
901
+ this.touched$ = this.touched.asObservable();
902
+ }
903
+ get isOpen() {
904
+ return this._isOpen.value;
905
+ }
906
+ initActiveDescendant(source$) {
907
+ if (source$) {
908
+ this.activeDescendant$ = source$;
909
+ }
910
+ else {
911
+ this.activeDescendant$ = of(null);
912
+ }
913
+ }
914
+ setLabel(label) {
915
+ this.label.next(label);
916
+ }
917
+ openListbox() {
918
+ this._isOpen.next(true);
919
+ }
920
+ closeListbox() {
921
+ this._isOpen.next(false);
922
+ }
923
+ toggleListbox() {
924
+ this._isOpen.next(!this._isOpen.value);
925
+ }
926
+ setProjectedContentIsInDOM() {
927
+ this.projectedContentIsInDOM.next(true);
928
+ }
929
+ emitTextboxBlur() {
930
+ this.textboxBlur.next();
931
+ }
932
+ setTouched() {
933
+ this.touched.next(true);
934
+ }
935
+ emitTextboxFocus(focus = FocusTextbox.default) {
936
+ this.focusTextbox.next(focus);
937
+ }
938
+ emitOptionAction(action) {
939
+ this.optionAction.next(action);
940
+ }
941
+ isMobile() {
942
+ return this.platform.ANDROID || this.platform.IOS;
943
+ }
944
+ setProjectedContent(groups, options) {
945
+ this.setGroups(groups);
946
+ this.setAllOptions(groups, options);
947
+ this.optionPropertyChanges$ = this.allOptions$.pipe(switchMap((options) => merge(options.map((o) => o.externalPropertyChanges$))), mergeAll());
948
+ }
949
+ setGroups(groups) {
950
+ this.groups$ = groups.changes.pipe(startWith(''), map(() => groups.toArray()));
951
+ }
952
+ setAllOptions(groups, options) {
953
+ // will not track changes to properties, just if the list of options changes
954
+ if (groups.length > 0) {
955
+ this.allOptions$ = this.groups$.pipe(switchMap((groups) => combineLatest(groups.map((group) => group.options$))), map((optionArrays) => optionArrays.flat()), shareReplay(1));
956
+ }
957
+ else {
958
+ this.allOptions$ = options.changes.pipe(startWith(''), map(() => options.toArray()), shareReplay(1));
959
+ }
960
+ }
961
+ setSelectedOptionsToEmit(selected) {
962
+ this.selectedOptionsToEmit.next(selected);
963
+ }
964
+ getSelectedOptions(options) {
965
+ return options?.filter((option) => !this.isSelectAllListboxOption(option) && option.isSelected());
966
+ }
967
+ isSelectAllListboxOption(option) {
968
+ return option instanceof SelectAllListboxOptionComponent;
969
+ }
970
+ setIsKeyboardEvent(isKeyboardEvent) {
971
+ this.isKeyboardEvent.next(isKeyboardEvent);
972
+ }
973
+ destroy() {
974
+ this.destroy$.next();
975
+ this.destroy$.complete();
976
+ this.focusTextbox.complete();
977
+ this.isKeyboardEvent.complete();
978
+ this._isOpen.complete();
979
+ this.label.complete();
980
+ this.optionAction.complete();
981
+ this.projectedContentIsInDOM.complete();
982
+ this.selectedOptionsToEmit.complete();
983
+ this.textboxBlur.complete();
984
+ this.touched.complete();
985
+ }
986
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxService, deps: [{ token: i1$1.Platform }], target: i0.ɵɵFactoryTarget.Injectable }); }
987
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxService }); }
988
+ }
989
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxService, decorators: [{
990
+ type: Injectable
991
+ }], ctorParameters: () => [{ type: i1$1.Platform }] });
992
+
993
+ class ComboboxLabelComponent {
994
+ constructor(service) {
995
+ this.service = service;
996
+ }
997
+ ngAfterViewInit() {
998
+ setTimeout(() => {
999
+ this.service.setLabel(this);
1000
+ }, 0);
1001
+ }
1002
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxLabelComponent, deps: [{ token: ComboboxService }], target: i0.ɵɵFactoryTarget.Component }); }
1003
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: ComboboxLabelComponent, isStandalone: true, selector: "hsi-ui-combobox-label", viewQueries: [{ propertyName: "labelContent", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: `<ng-template
1004
+ ><p class="combobox-label" [id]="service.comboboxLabelId"
1005
+ ><ng-content></ng-content></p
1006
+ ></ng-template>`, isInline: true }); }
1007
+ }
1008
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxLabelComponent, decorators: [{
1009
+ type: Component,
1010
+ args: [{
1011
+ selector: 'hsi-ui-combobox-label',
1012
+ template: `<ng-template
1013
+ ><p class="combobox-label" [id]="service.comboboxLabelId"
1014
+ ><ng-content></ng-content></p
1015
+ ></ng-template>`,
1016
+ }]
1017
+ }], ctorParameters: () => [{ type: ComboboxService }], propDecorators: { labelContent: [{
1018
+ type: ViewChild,
1019
+ args: [TemplateRef]
1020
+ }] } });
1021
+
1022
+ class ComboboxComponent {
1023
+ constructor(service, platform, zone, document, elRef, destroyRef) {
1024
+ this.service = service;
1025
+ this.platform = platform;
1026
+ this.zone = zone;
1027
+ this.document = document;
1028
+ this.elRef = elRef;
1029
+ this.destroyRef = destroyRef;
1030
+ }
1031
+ ngOnInit() {
1032
+ this.handleOutsideClick();
1033
+ }
1034
+ ngOnDestroy() {
1035
+ this.service.destroy();
1036
+ }
1037
+ handleOutsideClick() {
1038
+ if (!this.document) {
1039
+ return;
1040
+ }
1041
+ this.zone.runOutsideAngular(() => {
1042
+ merge(fromEvent(this.document, 'touchstart', { capture: true }), fromEvent(this.document, 'mousedown', { capture: true }))
1043
+ .pipe(takeUntilDestroyed(this.destroyRef), withLatestFrom(this.service.isOpen$), filter(([event, isOpen]) => isOpen && !event.composedPath().includes(this.elRef.nativeElement)))
1044
+ .subscribe(() => {
1045
+ if (this.platform.IOS || this.platform.ANDROID) {
1046
+ this.service.emitTextboxFocus(FocusTextbox.includeMobile);
1047
+ }
1048
+ this.service.emitTextboxBlur();
1049
+ });
1050
+ });
1051
+ }
1052
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxComponent, deps: [{ token: ComboboxService }, { token: i1$1.Platform }, { token: i0.NgZone }, { token: DOCUMENT }, { token: i0.ElementRef }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
1053
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: ComboboxComponent, isStandalone: true, selector: "hsi-ui-combobox", host: { classAttribute: "hsi-ui-combobox" }, providers: [ComboboxService], queries: [{ propertyName: "labelComponent", first: true, predicate: ComboboxLabelComponent, descendants: true }], ngImport: i0, template: "@if (service.label$ | async; as label) {\n <ng-template [ngTemplateOutlet]=\"label.labelContent\"></ng-template>\n}\n<ng-content></ng-content>\n", styles: ["html{--hsi-ui-combobox-background: var(--hsi-adk-color-primary-100, white);--hsi-ui-combobox-border-color: var(--hsi-adk-color-muted-primary-40, gray);--hsi-ui-combobox-border-style: solid;--hsi-ui-combobox-border-width: 1px;--hsi-ui-combobox-hover-border-color: var(--hsi-adk-color-muted-primary-20, darkgray);--hsi-ui-combobox-hover-cursor: pointer;--hsi-ui-combobox-max-width: none;--hsi-ui-textbox-display: flex;--hsi-ui-textbox-justify-content: space-between;--hsi-ui-textbox-align-items: center;--hsi-ui-textbox-background: var(--hsi-adk-color-primary-100, white);--hsi-ui-textbox-border-bottom-open: 1px solid var(--hsi-adk-color-muted-primary-80, gray);--hsi-ui-textbox-padding: .75rem;--hsi-ui-textbox-label-text-overflow: ellipsis;--hsi-ui-textbox-label-white-space: nowrap;--hsi-ui-textbox-label-overflow: hidden;--hsi-ui-textbox-label-max-width: calc(var(--hsi-ui-combobox-max-width) - 1rem);--hsi-ui-textbox-icon-display: flex;--hsi-ui-textbox-icon-flex-direction: column;--hsi-ui-textbox-icon-justify-content: center;--hsi-ui-textbox-transition-duration: .15s;--hsi-ui-editable-textbox-padding: .5rem;--hsi-ui-editable-textbox-input-border: none;--hsi-ui-editable-textbox-input-border-bottom: 1px solid transparent;--hsi-ui-editable-textbox-input-border-radius: 0;--hsi-ui-editable-textbox-input-width: 100%;--hsi-ui-editable-textbox-input-padding: .25rem .5rem;--hsi-ui-editable-textbox-input-hover-border: 0;--hsi-ui-editable-textbox-input-hover-border-bottom: 1px solid var(--hsi-adk-color-muted-primary-70, gray);--hsi-ui-editable-textbox-input-hover-background: var(--hsi-adk-color-muted-primary-98, #f2f2f2);--hsi-ui-editable-textbox-input-hover-outline: none;--hsi-ui-listbox-z-index: 100;--hsi-ui-listbox-max-height: 300px;--hsi-ui-listbox-background: var(--hsi-adk-color-primary-100, white);--hsi-ui-listbox-padding-top: .25rem;--hsi-ui-listbox-padding-right: .25rem;--hsi-ui-listbox-padding-bottom: .25rem;--hsi-ui-listbox-padding-left: .25rem;--hsi-ui-listbox-label-font-size: .9em;--hsi-ui-listbox-label-font-weight: var(--hsi-adk-font-weight-semibold, 600);--hsi-ui-listbox-label-text-transform: uppercase;--hsi-ui-listbox-label-padding: .25rem var(--hsi-ui-listbox-option-container-padding);--hsi-ui-listbox-label-margin-right: var(--hsi-ui-listbox-option-margin-right);--hsi-ui-listbox-option-hover-background: var(--hsi-adk-color-muted-primary-95, #f2f2f2);--hsi-ui-listbox-option-hover-border-radius: 0;--hsi-ui-listbox-option-selected-background: var(--hsi-adk-color-muted-primary-90, lightgray);--hsi-ui-listbox-option-selected-border-radius: 0;--hsi-ui-listbox-option-disabled-color: var(--hsi-adk-color-muted-primary-80, lightgray);--hsi-ui-listbox-option-current-background: var(--hsi-adk-color-muted-primary-40, darkgray);--hsi-ui-listbox-option-current-color: var(--hsi-adk-color-primary-100, white);--hsi-ui-listbox-option-current-border-radius: 0;--hsi-ui-listbox-option-label-padding: .75rem;--hsi-ui-listbox-option-cursor: pointer;--hsi-ui-listbox-option-margin-right: .25rem;--hsi-ui-listbox-option-container-display: flex;--hsi-ui-listbox-option-container-flex-direction: row;--hsi-ui-listbox-option-container-align-items: center;--hsi-ui-listbox-option-container-padding: .5rem;--hsi-ui-listbox-option-container-gap: .5rem}.hsi-ui-combobox{display:block;position:relative;max-width:var(--hsi-ui-combobox-max-width)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None }); }
1054
+ }
1055
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: ComboboxComponent, decorators: [{
1056
+ type: Component,
1057
+ args: [{ selector: 'hsi-ui-combobox', imports: [CommonModule, AsyncPipe], providers: [ComboboxService], encapsulation: ViewEncapsulation.None, host: { class: 'hsi-ui-combobox' }, template: "@if (service.label$ | async; as label) {\n <ng-template [ngTemplateOutlet]=\"label.labelContent\"></ng-template>\n}\n<ng-content></ng-content>\n", styles: ["html{--hsi-ui-combobox-background: var(--hsi-adk-color-primary-100, white);--hsi-ui-combobox-border-color: var(--hsi-adk-color-muted-primary-40, gray);--hsi-ui-combobox-border-style: solid;--hsi-ui-combobox-border-width: 1px;--hsi-ui-combobox-hover-border-color: var(--hsi-adk-color-muted-primary-20, darkgray);--hsi-ui-combobox-hover-cursor: pointer;--hsi-ui-combobox-max-width: none;--hsi-ui-textbox-display: flex;--hsi-ui-textbox-justify-content: space-between;--hsi-ui-textbox-align-items: center;--hsi-ui-textbox-background: var(--hsi-adk-color-primary-100, white);--hsi-ui-textbox-border-bottom-open: 1px solid var(--hsi-adk-color-muted-primary-80, gray);--hsi-ui-textbox-padding: .75rem;--hsi-ui-textbox-label-text-overflow: ellipsis;--hsi-ui-textbox-label-white-space: nowrap;--hsi-ui-textbox-label-overflow: hidden;--hsi-ui-textbox-label-max-width: calc(var(--hsi-ui-combobox-max-width) - 1rem);--hsi-ui-textbox-icon-display: flex;--hsi-ui-textbox-icon-flex-direction: column;--hsi-ui-textbox-icon-justify-content: center;--hsi-ui-textbox-transition-duration: .15s;--hsi-ui-editable-textbox-padding: .5rem;--hsi-ui-editable-textbox-input-border: none;--hsi-ui-editable-textbox-input-border-bottom: 1px solid transparent;--hsi-ui-editable-textbox-input-border-radius: 0;--hsi-ui-editable-textbox-input-width: 100%;--hsi-ui-editable-textbox-input-padding: .25rem .5rem;--hsi-ui-editable-textbox-input-hover-border: 0;--hsi-ui-editable-textbox-input-hover-border-bottom: 1px solid var(--hsi-adk-color-muted-primary-70, gray);--hsi-ui-editable-textbox-input-hover-background: var(--hsi-adk-color-muted-primary-98, #f2f2f2);--hsi-ui-editable-textbox-input-hover-outline: none;--hsi-ui-listbox-z-index: 100;--hsi-ui-listbox-max-height: 300px;--hsi-ui-listbox-background: var(--hsi-adk-color-primary-100, white);--hsi-ui-listbox-padding-top: .25rem;--hsi-ui-listbox-padding-right: .25rem;--hsi-ui-listbox-padding-bottom: .25rem;--hsi-ui-listbox-padding-left: .25rem;--hsi-ui-listbox-label-font-size: .9em;--hsi-ui-listbox-label-font-weight: var(--hsi-adk-font-weight-semibold, 600);--hsi-ui-listbox-label-text-transform: uppercase;--hsi-ui-listbox-label-padding: .25rem var(--hsi-ui-listbox-option-container-padding);--hsi-ui-listbox-label-margin-right: var(--hsi-ui-listbox-option-margin-right);--hsi-ui-listbox-option-hover-background: var(--hsi-adk-color-muted-primary-95, #f2f2f2);--hsi-ui-listbox-option-hover-border-radius: 0;--hsi-ui-listbox-option-selected-background: var(--hsi-adk-color-muted-primary-90, lightgray);--hsi-ui-listbox-option-selected-border-radius: 0;--hsi-ui-listbox-option-disabled-color: var(--hsi-adk-color-muted-primary-80, lightgray);--hsi-ui-listbox-option-current-background: var(--hsi-adk-color-muted-primary-40, darkgray);--hsi-ui-listbox-option-current-color: var(--hsi-adk-color-primary-100, white);--hsi-ui-listbox-option-current-border-radius: 0;--hsi-ui-listbox-option-label-padding: .75rem;--hsi-ui-listbox-option-cursor: pointer;--hsi-ui-listbox-option-margin-right: .25rem;--hsi-ui-listbox-option-container-display: flex;--hsi-ui-listbox-option-container-flex-direction: row;--hsi-ui-listbox-option-container-align-items: center;--hsi-ui-listbox-option-container-padding: .5rem;--hsi-ui-listbox-option-container-gap: .5rem}.hsi-ui-combobox{display:block;position:relative;max-width:var(--hsi-ui-combobox-max-width)}\n"] }]
1058
+ }], ctorParameters: () => [{ type: ComboboxService }, { type: i1$1.Platform }, { type: i0.NgZone }, { type: Document, decorators: [{
1059
+ type: Inject,
1060
+ args: [DOCUMENT]
1061
+ }] }, { type: i0.ElementRef }, { type: i0.DestroyRef }], propDecorators: { labelComponent: [{
1062
+ type: ContentChild,
1063
+ args: [ComboboxLabelComponent]
1064
+ }] } });
1065
+
1066
+ class TextboxComponent {
1067
+ constructor() {
1068
+ /*
1069
+ * Whether the textbox label responds to selections in any way.
1070
+ *
1071
+ * If true, the textbox label will display the selected option(s) if no other label properties are provided.
1072
+ *
1073
+ * @default true
1074
+ */
1075
+ this.dynamicLabel = true;
1076
+ this.findsOptionOnTyping = true;
1077
+ this.openKeys = ['ArrowDown', 'ArrowUp', 'Enter', ' '];
1078
+ this.label = new BehaviorSubject('');
1079
+ this.label$ = this.label.asObservable();
1080
+ this.destroyRef = inject(DestroyRef);
1081
+ this.service = inject(ComboboxService);
1082
+ this.platform = inject(Platform);
1083
+ this.zone = inject(NgZone);
1084
+ }
1085
+ ngOnInit() {
1086
+ this.service.projectedContentIsInDOM$
1087
+ .pipe(takeUntilDestroyed(this.destroyRef), filter((x) => !!x),
1088
+ // Required because the label is projected into the ListboxOption via <ng-content>, and the
1089
+ // listbox options are <ng-template>s that are projected into the listbox via ngTemplateOutlet.
1090
+ // We need this to ensure that the option labels are in the DOM to read from before we set the box label.
1091
+ runNgChangeDetectionThen(this.zone))
1092
+ .subscribe(() => {
1093
+ this.setLabel();
1094
+ });
1095
+ }
1096
+ ngAfterViewInit() {
1097
+ this.setFocusListener();
1098
+ }
1099
+ setFocusListener() {
1100
+ this.service.focusTextbox$
1101
+ .pipe(takeUntilDestroyed(this.destroyRef))
1102
+ .subscribe((focusType) => {
1103
+ if (!this.isMobile() || focusType === FocusTextbox.includeMobile) {
1104
+ this.focusBox();
1105
+ }
1106
+ });
1107
+ }
1108
+ focusBox() {
1109
+ this.box.nativeElement.focus();
1110
+ }
1111
+ handleBlur(event) {
1112
+ // DESCRIPTION OF HOW VARIOUS DEVICES/ASSISTIVE TECHNOLOGIES DO/NOT TRIGGER ANY BLUR EVENT (FocusEvent)
1113
+ // clicking (desktop) will trigger a blur event (item is focused, user clicks away, blur event fires)
1114
+ // keyboard navigation (desktop) will not trigger a blur event (item is focused, user navigates to another item, blur event does not fire)
1115
+ // tapping (mobile) will trigger a blur event (item is focused, user taps away, blur event fires)
1116
+ // swiping (VoiceOver) will trigger a blur event (item is focused, user swipes away, blur event fires)
1117
+ // The code below (lines 106 - 116) will refocus the textbox when the textbox receives blur event, and the
1118
+ // source of the blue event (related target) is something in the listbox.
1119
+ // We keep the focus on the textbox so that we can continue to listen for keyboard events to provide
1120
+ // keyboard navigation/interaction with the listbox options. The refocusing does not affect keyboard navigation,
1121
+ // and is unnoticable to the user.
1122
+ // However, VoiceOver (iOS assistive tech) will move the navigation back to the textbox when the textbox is focused,
1123
+ // which means the user will need to strt navigating the options from the top of the listbox every time they select
1124
+ // an option. (If we throw the focus). For this reason, we have decided that we will not support keyboard navigation
1125
+ // (which would need to happen on a connected external keybord) on mobile devices, as keyboard nav requires that the
1126
+ // focus stays on the textbox. Ostensibly it is standard practice to not support keyboard navigation on mobile devices.
1127
+ if (!this.isMobile()) {
1128
+ if (event.relatedTarget && this.isHtmlElement(event.relatedTarget)) {
1129
+ // when the blur happens because a listbox option was focused
1130
+ if (event.relatedTarget.id.includes('listbox') ||
1131
+ event.relatedTarget.classList.contains('listbox-group') ||
1132
+ event.relatedTarget.classList.contains('listbox-group-label')) {
1133
+ this.service.emitTextboxFocus();
1134
+ return;
1135
+ }
1136
+ }
1137
+ this.service.emitTextboxBlur();
1138
+ }
1139
+ }
1140
+ isHtmlElement(target) {
1141
+ return 'id' in target;
1142
+ }
1143
+ isMobile() {
1144
+ return this.platform.IOS || this.platform.ANDROID;
1145
+ }
1146
+ handleClick() {
1147
+ this.service.setIsKeyboardEvent(false);
1148
+ if (this.service.isOpen) {
1149
+ this.service.closeListbox();
1150
+ }
1151
+ else {
1152
+ this.service.setTouched();
1153
+ this.service.openListbox();
1154
+ }
1155
+ this.focusBox();
1156
+ }
1157
+ handleKeydown(event) {
1158
+ if (event.key === 'Escape') {
1159
+ this.onEscape();
1160
+ }
1161
+ else {
1162
+ this.service.setTouched();
1163
+ const action = this.getActionFromKeydownEvent(event);
1164
+ if (action) {
1165
+ this.service.setIsKeyboardEvent(true);
1166
+ }
1167
+ this.handleKeyboardAction(action, event);
1168
+ }
1169
+ }
1170
+ onEscape() {
1171
+ this.service.closeListbox();
1172
+ this.service.emitTextboxFocus();
1173
+ }
1174
+ getActionFromKeydownEvent(event) {
1175
+ if (!this.service.isOpen && this.openKeys.includes(event.key)) {
1176
+ return ListboxAction.open;
1177
+ }
1178
+ if (event.key === Key.Home) {
1179
+ return OptionAction.first;
1180
+ }
1181
+ if (event.key === Key.End) {
1182
+ return OptionAction.last;
1183
+ }
1184
+ if (this.findsOptionOnTyping && this.isTypingCharacter(event)) {
1185
+ return TextboxAction.type;
1186
+ }
1187
+ if (this.service.isOpen) {
1188
+ return this.getActionFromKeyEventWhenOpen(event);
1189
+ }
1190
+ else {
1191
+ return null;
1192
+ }
1193
+ }
1194
+ isTypingCharacter(event) {
1195
+ const { key, altKey, ctrlKey, metaKey } = event;
1196
+ return (key === 'Backspace' ||
1197
+ key === 'Clear' ||
1198
+ (key.length === 1 && key !== ' ' && !altKey && !ctrlKey && !metaKey));
1199
+ }
1200
+ getActionFromKeyEventWhenOpen(event) {
1201
+ const { key, altKey } = event;
1202
+ if (key === Key.ArrowUp && altKey) {
1203
+ return ListboxAction.closeSelect;
1204
+ }
1205
+ else if (key === Key.ArrowDown && !altKey) {
1206
+ return OptionAction.next;
1207
+ }
1208
+ else if (key === Key.ArrowUp) {
1209
+ return OptionAction.previous;
1210
+ }
1211
+ else if (key === Key.PageUp) {
1212
+ return OptionAction.pageUp;
1213
+ }
1214
+ else if (key === Key.PageDown) {
1215
+ return OptionAction.pageDown;
1216
+ }
1217
+ else if (key === Key.Enter || key === Key.Space) {
1218
+ return this.service.isMultiSelect
1219
+ ? OptionAction.select
1220
+ : ListboxAction.closeSelect;
1221
+ }
1222
+ else {
1223
+ return null;
1224
+ }
1225
+ }
1226
+ handleKeyboardAction(action, event) {
1227
+ switch (action) {
1228
+ case OptionAction.first:
1229
+ case OptionAction.last:
1230
+ this.service.openListbox();
1231
+ this.focusBox();
1232
+ event.preventDefault();
1233
+ this.service.emitOptionAction(action);
1234
+ break;
1235
+ case OptionAction.next:
1236
+ case OptionAction.pageDown:
1237
+ case OptionAction.previous:
1238
+ case OptionAction.pageUp:
1239
+ case OptionAction.select:
1240
+ event.preventDefault();
1241
+ this.service.emitOptionAction(action);
1242
+ break;
1243
+ case ListboxAction.closeSelect:
1244
+ event.preventDefault();
1245
+ this.service.emitOptionAction(OptionAction.select);
1246
+ this.service.closeListbox();
1247
+ this.focusBox();
1248
+ break;
1249
+ case ListboxAction.close:
1250
+ event.preventDefault();
1251
+ this.service.closeListbox();
1252
+ this.focusBox();
1253
+ break;
1254
+ case TextboxAction.type:
1255
+ this.service.openListbox();
1256
+ this.focusBox();
1257
+ this.service.emitOptionAction(event.key);
1258
+ break;
1259
+ case ListboxAction.open:
1260
+ event.preventDefault();
1261
+ this.service.openListbox();
1262
+ this.focusBox();
1263
+ }
1264
+ }
1265
+ setLabel() {
1266
+ if (this.dynamicLabel) {
1267
+ combineLatest([
1268
+ this.service.touched$,
1269
+ this.service.allOptions$, // when options (not properties) change
1270
+ this.service.selectedOptionsToEmit$, // when a user clicks
1271
+ this.service.optionPropertyChanges$.pipe(filter((x) => !!x), startWith(null)), // on an outside change,
1272
+ ])
1273
+ .pipe(takeUntilDestroyed(this.destroyRef))
1274
+ .subscribe(([touched, options]) => {
1275
+ const label = this.getComputedLabel(touched, options);
1276
+ this.label.next(label);
1277
+ });
1278
+ }
1279
+ }
1280
+ getComputedLabel(touched, options) {
1281
+ const selectedOptions = this.service.getSelectedOptions(options);
1282
+ let label = '';
1283
+ const numSelected = selectedOptions?.length;
1284
+ if (touched || numSelected || this.customLabel || this.selectedCountLabel) {
1285
+ if (this.customLabel && !this.service.hasEditableTextbox) {
1286
+ label = this.customLabel(selectedOptions);
1287
+ }
1288
+ else if (this.selectedCountLabel && !this.service.hasEditableTextbox) {
1289
+ if (numSelected === 1) {
1290
+ label = `${numSelected} ${this.selectedCountLabel.singular} selected`;
1291
+ }
1292
+ else {
1293
+ label = `${numSelected} ${this.selectedCountLabel.plural} selected`;
1294
+ }
1295
+ }
1296
+ else {
1297
+ label = this.getDefaultLabel(selectedOptions);
1298
+ }
1299
+ }
1300
+ return label;
1301
+ }
1302
+ getDefaultLabel(selectedOptions) {
1303
+ let label = '';
1304
+ if (selectedOptions) {
1305
+ label = selectedOptions
1306
+ .reduce((acc, option) => {
1307
+ const value = option.boxDisplayLabel ??
1308
+ option.label?.nativeElement.innerText.trim();
1309
+ if (value) {
1310
+ acc.push(value);
1311
+ }
1312
+ return acc;
1313
+ }, [])
1314
+ .join(', ');
1315
+ }
1316
+ return label;
1317
+ }
1318
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TextboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1319
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: TextboxComponent, isStandalone: true, selector: "hsi-ui-textbox", inputs: { ariaLabel: "ariaLabel", selectedCountLabel: "selectedCountLabel", customLabel: "customLabel", dynamicLabel: "dynamicLabel", findsOptionOnTyping: "findsOptionOnTyping" }, host: { classAttribute: "hsi-ui-textbox" }, viewQueries: [{ propertyName: "box", first: true, predicate: ["box"], descendants: true }, { propertyName: "boxIcon", first: true, predicate: ["boxIcon"], descendants: true }], ngImport: i0, template: "<div\n #box\n class=\"hsi-ui-textbox-container\"\n role=\"combobox\"\n tabindex=\"0\"\n [id]=\"service.id + '-textbox'\"\n data-cy=\"combobox-textbox\"\n (click)=\"handleClick()\"\n (blur)=\"handleBlur($event)\"\n (keydown)=\"handleKeydown($event)\"\n [attr.aria-label]=\"\n (service.label$ | async) === null\n ? ariaLabel || service.isMultiSelect\n ? 'Select options'\n : 'Select an option'\n : null\n \"\n [attr.aria-labelledby]=\"\n (service.label$ | async) !== null ? service.comboboxLabelId : null\n \"\n [attr.aria-activedescendant]=\"service.activeDescendant$ | async\"\n [attr.aria-expanded]=\"service.isOpen$ | async\"\n [attr.aria-controls]=\"service.id + '-listbox'\"\n aria-haspopup=\"listbox\"\n [class.open]=\"service.isOpen$ | async\"\n ><div\n *ngIf=\"dynamicLabel && !!(label$ | async); else staticLabel\"\n class=\"hsi-ui-textbox-label\"\n data-cy=\"textbox-label\"\n >{{ label$ | async }}</div\n ><div\n #boxIcon\n class=\"hsi-ui-textbox-icon\"\n [class.open]=\"service.isOpen$ | async\"\n ><ng-content select=\"[boxIcon]\"></ng-content></div\n></div>\n<ng-template #staticLabel\n ><div class=\"hsi-ui-textbox-label\" data-cy=\"textbox-label\"\n ><ng-content select=\"[boxLabel]\"></ng-content></div\n></ng-template>\n", styles: [".hsi-ui-textbox-container{display:var(--hsi-ui-textbox-display);justify-content:var(--hsi-ui-textbox-justify-content);align-items:var(--hsi-ui-textbox-align-items);background:var(--hsi-ui-textbox-background);border:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);padding:var(--hsi-ui-textbox-padding);border-radius:var(--hsi-ui-combobox-border-radius);transition:border var(--hsi-ui-textbox-transition-duration) ease-in-out}.hsi-ui-textbox-container:hover{border:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-hover-border-color);cursor:var(--hsi-ui-combobox-hover-cursor)}.hsi-ui-textbox-container.open{border-bottom:var(--hsi-ui-textbox-border-bottom-open);border-bottom-left-radius:0;border-bottom-right-radius:0}.hsi-ui-textbox-label{text-overflow:var(--hsi-ui-textbox-label-text-overflow);white-space:var(--hsi-ui-textbox-label-white-space);overflow:var(--hsi-ui-textbox-label-overflow);max-width:var(--hsi-ui-textbox-label-max-width)}.hsi-ui-textbox-icon{display:var(--hsi-ui-textbox-icon-display);flex-direction:var(--hsi-ui-textbox-icon-flex-direction);justify-content:var(--hsi-ui-textbox-icon-justify-content)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] }); }
1320
+ }
1321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TextboxComponent, decorators: [{
1322
+ type: Component,
1323
+ args: [{ selector: 'hsi-ui-textbox', imports: [CommonModule], host: {
1324
+ class: 'hsi-ui-textbox',
1325
+ }, template: "<div\n #box\n class=\"hsi-ui-textbox-container\"\n role=\"combobox\"\n tabindex=\"0\"\n [id]=\"service.id + '-textbox'\"\n data-cy=\"combobox-textbox\"\n (click)=\"handleClick()\"\n (blur)=\"handleBlur($event)\"\n (keydown)=\"handleKeydown($event)\"\n [attr.aria-label]=\"\n (service.label$ | async) === null\n ? ariaLabel || service.isMultiSelect\n ? 'Select options'\n : 'Select an option'\n : null\n \"\n [attr.aria-labelledby]=\"\n (service.label$ | async) !== null ? service.comboboxLabelId : null\n \"\n [attr.aria-activedescendant]=\"service.activeDescendant$ | async\"\n [attr.aria-expanded]=\"service.isOpen$ | async\"\n [attr.aria-controls]=\"service.id + '-listbox'\"\n aria-haspopup=\"listbox\"\n [class.open]=\"service.isOpen$ | async\"\n ><div\n *ngIf=\"dynamicLabel && !!(label$ | async); else staticLabel\"\n class=\"hsi-ui-textbox-label\"\n data-cy=\"textbox-label\"\n >{{ label$ | async }}</div\n ><div\n #boxIcon\n class=\"hsi-ui-textbox-icon\"\n [class.open]=\"service.isOpen$ | async\"\n ><ng-content select=\"[boxIcon]\"></ng-content></div\n></div>\n<ng-template #staticLabel\n ><div class=\"hsi-ui-textbox-label\" data-cy=\"textbox-label\"\n ><ng-content select=\"[boxLabel]\"></ng-content></div\n></ng-template>\n", styles: [".hsi-ui-textbox-container{display:var(--hsi-ui-textbox-display);justify-content:var(--hsi-ui-textbox-justify-content);align-items:var(--hsi-ui-textbox-align-items);background:var(--hsi-ui-textbox-background);border:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);padding:var(--hsi-ui-textbox-padding);border-radius:var(--hsi-ui-combobox-border-radius);transition:border var(--hsi-ui-textbox-transition-duration) ease-in-out}.hsi-ui-textbox-container:hover{border:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-hover-border-color);cursor:var(--hsi-ui-combobox-hover-cursor)}.hsi-ui-textbox-container.open{border-bottom:var(--hsi-ui-textbox-border-bottom-open);border-bottom-left-radius:0;border-bottom-right-radius:0}.hsi-ui-textbox-label{text-overflow:var(--hsi-ui-textbox-label-text-overflow);white-space:var(--hsi-ui-textbox-label-white-space);overflow:var(--hsi-ui-textbox-label-overflow);max-width:var(--hsi-ui-textbox-label-max-width)}.hsi-ui-textbox-icon{display:var(--hsi-ui-textbox-icon-display);flex-direction:var(--hsi-ui-textbox-icon-flex-direction);justify-content:var(--hsi-ui-textbox-icon-justify-content)}\n"] }]
1326
+ }], propDecorators: { ariaLabel: [{
1327
+ type: Input
1328
+ }], selectedCountLabel: [{
1329
+ type: Input
1330
+ }], customLabel: [{
1331
+ type: Input
1332
+ }], dynamicLabel: [{
1333
+ type: Input
1334
+ }], findsOptionOnTyping: [{
1335
+ type: Input
1336
+ }], box: [{
1337
+ type: ViewChild,
1338
+ args: ['box']
1339
+ }], boxIcon: [{
1340
+ type: ViewChild,
1341
+ args: ['boxIcon']
1342
+ }] } });
1343
+
1344
+ class EditableTextboxComponent extends TextboxComponent {
1345
+ constructor() {
1346
+ super(...arguments);
1347
+ this.autoSelect = false;
1348
+ this.autoSelectTrigger = 'character';
1349
+ this.displaySelected = true;
1350
+ this.initialValue = '';
1351
+ this.inputType = 'text';
1352
+ this.placeholder = '';
1353
+ this.valueChanges = new EventEmitter();
1354
+ this.moveFocusToTextboxKeys = ['RightArrow', 'LeftArrow', 'Home', 'End'];
1355
+ this.value = new BehaviorSubject('');
1356
+ this.value$ = this.value.asObservable();
1357
+ this.openKeys = ['ArrowDown', 'ArrowUp'];
1358
+ }
1359
+ ngOnInit() {
1360
+ this.service.autoComplete = this.displaySelected
1361
+ ? AutoComplete.list
1362
+ : AutoComplete.none;
1363
+ this.service.shouldAutoSelectOnListboxClose =
1364
+ this.autoSelect && this.autoSelectTrigger === 'any';
1365
+ this.service.nullActiveIdOnClose = true;
1366
+ this.service.hasEditableTextbox = true;
1367
+ super.ngOnInit();
1368
+ }
1369
+ ngAfterViewInit() {
1370
+ super.ngAfterViewInit();
1371
+ if (this.initialValue || this.ngFormControl?.value) {
1372
+ this.value.next(this.initialValue || this.ngFormControl.value);
1373
+ }
1374
+ }
1375
+ setLabel() {
1376
+ this.service.selectedOptionsToEmit$ // when a user clicks
1377
+ .pipe(skip(1))
1378
+ .subscribe((selectedOptions) => this.onSelectionChange(selectedOptions));
1379
+ }
1380
+ onSelectionChange(selectedOptions) {
1381
+ if (this.service.isMultiSelect) {
1382
+ this.setAndEmitValue('');
1383
+ }
1384
+ else {
1385
+ const label = selectedOptions.length
1386
+ ? selectedOptions[0].label?.nativeElement.innerText.trim()
1387
+ : '';
1388
+ this.setAndEmitValue(label);
1389
+ }
1390
+ }
1391
+ onInputChange(value) {
1392
+ if (value === '') {
1393
+ this.setAutoSelectWhenInputIsEmpty();
1394
+ }
1395
+ else {
1396
+ this.service.shouldAutoSelectOnListboxClose = this.autoSelect;
1397
+ }
1398
+ this.setAndEmitValue(value);
1399
+ }
1400
+ setAndEmitValue(value) {
1401
+ this.setValue(value);
1402
+ this.emitValue(value);
1403
+ }
1404
+ setValue(value) {
1405
+ this.value.next(value);
1406
+ }
1407
+ emitValue(value) {
1408
+ if (this.ngFormControl) {
1409
+ this.ngFormControl.setValue(value);
1410
+ }
1411
+ else {
1412
+ this.valueChanges.emit(value);
1413
+ }
1414
+ }
1415
+ handleClick() {
1416
+ this.service.setIsKeyboardEvent(false);
1417
+ if (this.service.isOpen) {
1418
+ this.service.closeListbox();
1419
+ }
1420
+ else {
1421
+ this.service.openListbox();
1422
+ if (this.autoSelect) {
1423
+ const inputValue = this.inputElRef.nativeElement.value;
1424
+ if (inputValue === '') {
1425
+ this.setAutoSelectWhenInputIsEmpty();
1426
+ }
1427
+ else {
1428
+ this.service.shouldAutoSelectOnListboxClose = this.autoSelect;
1429
+ }
1430
+ }
1431
+ }
1432
+ this.service.emitTextboxFocus();
1433
+ }
1434
+ setAutoSelectWhenInputIsEmpty() {
1435
+ this.service.shouldAutoSelectOnListboxClose = this.autoSelect
1436
+ ? this.autoSelectTrigger === 'any'
1437
+ : false;
1438
+ }
1439
+ onEscape() {
1440
+ if (!this.service.isOpen) {
1441
+ this.setAndEmitValue('');
1442
+ this.service.emitOptionAction(OptionAction.nullActiveIndex);
1443
+ }
1444
+ else {
1445
+ this.service.closeListbox();
1446
+ this.service.emitTextboxFocus();
1447
+ }
1448
+ }
1449
+ getActionFromKeydownEvent(event) {
1450
+ if (event.ctrlKey || event.key === 'Shift') {
1451
+ return null;
1452
+ }
1453
+ if (!this.service.isOpen && this.openKeys.includes(event.key)) {
1454
+ return ListboxAction.open;
1455
+ }
1456
+ else if (!this.service.isOpen && event.key === Key.Tab) {
1457
+ return null;
1458
+ }
1459
+ else if (event.key === Key.Enter &&
1460
+ (this.service.shouldAutoSelectOnListboxClose
1461
+ ? !this.service.isOpen
1462
+ : true)) {
1463
+ return ListboxAction.close;
1464
+ }
1465
+ else {
1466
+ if (event.key === Key.RightArrow ||
1467
+ event.key === Key.LeftArrow ||
1468
+ event.key === Key.Space) {
1469
+ this.service.emitTextboxFocus();
1470
+ return null;
1471
+ }
1472
+ else {
1473
+ return this.getActionFromKeydownEventWhenOpen(event);
1474
+ }
1475
+ }
1476
+ }
1477
+ getActionFromKeydownEventWhenOpen(event) {
1478
+ const { key } = event;
1479
+ if (key === Key.ArrowDown || key === 'Down') {
1480
+ return OptionAction.next;
1481
+ }
1482
+ else if (key === Key.ArrowUp) {
1483
+ return OptionAction.previous;
1484
+ }
1485
+ else if (key === Key.Enter || key === Key.Space) {
1486
+ return this.service.isMultiSelect
1487
+ ? OptionAction.select
1488
+ : ListboxAction.closeSelect;
1489
+ }
1490
+ else if (key === Key.Home) {
1491
+ return TextboxAction.cursorFirst;
1492
+ }
1493
+ else if (key === Key.End) {
1494
+ return TextboxAction.cursorLast;
1495
+ }
1496
+ else if (this.isPrintableCharacter(key) || key === 'Backspace') {
1497
+ return TextboxAction.addChar;
1498
+ }
1499
+ else if (key === Key.Tab) {
1500
+ return ListboxAction.closeSelect;
1501
+ }
1502
+ else {
1503
+ return null;
1504
+ }
1505
+ }
1506
+ handleKeyboardAction(action, event) {
1507
+ if (action === ListboxAction.closeSelect) {
1508
+ event.stopPropagation();
1509
+ event.preventDefault();
1510
+ this.service.emitOptionAction(OptionAction.select);
1511
+ this.service.closeListbox();
1512
+ if (event.key !== Key.Tab) {
1513
+ this.service.emitTextboxFocus();
1514
+ }
1515
+ this.service.emitOptionAction(OptionAction.nullActiveIndex);
1516
+ }
1517
+ else if (action === OptionAction.next ||
1518
+ action === OptionAction.previous ||
1519
+ action === OptionAction.select) {
1520
+ event.stopPropagation();
1521
+ event.preventDefault();
1522
+ this.service.emitOptionAction(action);
1523
+ }
1524
+ else if (action === ListboxAction.open) {
1525
+ event.stopPropagation();
1526
+ event.preventDefault();
1527
+ this.service.emitOptionAction(OptionAction.zeroActiveIndex);
1528
+ this.service.openListbox();
1529
+ this.service.emitTextboxFocus();
1530
+ }
1531
+ else if (action === ListboxAction.close) {
1532
+ event.stopPropagation();
1533
+ event.preventDefault();
1534
+ this.service.closeListbox();
1535
+ this.service.emitTextboxFocus();
1536
+ this.service.emitOptionAction(OptionAction.nullActiveIndex);
1537
+ }
1538
+ else if (action === TextboxAction.cursorFirst ||
1539
+ action === TextboxAction.cursorLast ||
1540
+ action === TextboxAction.addChar) {
1541
+ this.service.emitTextboxFocus();
1542
+ if (!this.service.isOpen) {
1543
+ this.service.openListbox();
1544
+ }
1545
+ if (action === TextboxAction.cursorFirst) {
1546
+ this.inputElRef.nativeElement.setSelectionRange(0, 0);
1547
+ }
1548
+ else if (action === TextboxAction.cursorLast) {
1549
+ this.inputElRef.nativeElement.setSelectionRange(this.inputElRef.nativeElement.value.length, this.inputElRef.nativeElement.value.length);
1550
+ }
1551
+ if (this.autoSelect && action === TextboxAction.addChar) {
1552
+ this.service.emitOptionAction(OptionAction.zeroActiveIndex);
1553
+ }
1554
+ else {
1555
+ this.service.emitOptionAction(OptionAction.nullActiveIndex);
1556
+ }
1557
+ }
1558
+ }
1559
+ isPrintableCharacter(str) {
1560
+ return str.length === 1 && str.match(/\S| /);
1561
+ }
1562
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: EditableTextboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1563
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: EditableTextboxComponent, isStandalone: true, selector: "hsi-ui-editable-textbox", inputs: { autoSelect: "autoSelect", autoSelectTrigger: "autoSelectTrigger", displaySelected: "displaySelected", initialValue: "initialValue", inputType: "inputType", ngFormControl: "ngFormControl", placeholder: "placeholder" }, outputs: { valueChanges: "valueChanges" }, host: { classAttribute: "hsi-ui-editable-textbox" }, viewQueries: [{ propertyName: "inputElRef", first: true, predicate: ["box"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"hsi-ui-editable-textbox-container\"\n [class.open]=\"service.isOpen$ | async\"\n #textInputTemplate\n>\n <input\n #box\n class=\"hsi-ui-editable-textbox-input\"\n [attr.type]=\"inputType\"\n role=\"combobox\"\n tabindex=\"0\"\n [id]=\"service.id + '-textbox'\"\n (click)=\"handleClick()\"\n (blur)=\"handleBlur($event)\"\n (keydown)=\"handleKeydown($event)\"\n autocomplete=\"off\"\n [attr.aria-label]=\"\n (service.label$ | async) === null\n ? ariaLabel || placeholder || service.isMultiSelect\n ? 'Search and select options'\n : 'Search and select an option'\n : null\n \"\n [attr.aria-labelledby]=\"\n (service.label$ | async) !== null ? service.comboboxLabelId : null\n \"\n [attr.aria-activedescendant]=\"service.activeDescendant$ | async\"\n [attr.aria-expanded]=\"service.isOpen$ | async\"\n [attr.aria-autocomplete]=\"service.autoComplete\"\n [attr.aria-controls]=\"service.id + '-listbox'\"\n aria-haspopup=\"listbox\"\n data-cy=\"editable-textbox-input\"\n [placeholder]=\"placeholder\"\n [ngModel]=\"value$ | async\"\n (ngModelChange)=\"onInputChange($event)\"\n />\n <div\n class=\"hsi-ui-textbox-icon hsi-ui-editable-textbox-icon\"\n [class.open]=\"service.isOpen$ | async\"\n >\n <ng-content select=\"[boxIcon]\"></ng-content\n ></div>\n</div>\n", styles: [".hsi-ui-editable-textbox-container{display:var(--hsi-ui-textbox-display);justify-content:var(--hsi-ui-textbox-justify-content);align-items:var(--hsi-ui-textbox-align-items);background:var(--hsi-ui-textbox-background);border:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);padding:var(--hsi-ui-editable-textbox-padding);border-radius:var(--hsi-ui-combobox-border-radius);transition:border var(--hsi-ui-textbox-transition-duration) ease-in-out}.hsi-ui-editable-textbox-container.open{border-bottom:var(--hsi-ui-textbox-border-bottom-open);border-bottom-left-radius:0;border-bottom-right-radius:0}.hsi-ui-editable-textbox-input{border:var(--hsi-ui-editable-textbox-input-border);border-bottom:var(--hsi-ui-editable-textbox-input-border-bottom);width:var(--hsi-ui-editable-textbox-input-width);padding:var(--hsi-ui-editable-textbox-input-padding);border-radius:var(--hsi-ui-editable-textbox-input-border-radius)}.hsi-ui-editable-textbox-input:hover,.hsi-ui-editable-textbox-input:focus{border:var(--hsi-ui-editable-textbox-input-hover-border);border-bottom:var(--hsi-ui-editable-textbox-input-hover-border-bottom);background:var(--hsi-ui-editable-textbox-input-hover-background);outline:var(--hsi-ui-editable-textbox-input-hover-outline)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
1564
+ }
1565
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: EditableTextboxComponent, decorators: [{
1566
+ type: Component,
1567
+ args: [{ selector: 'hsi-ui-editable-textbox', imports: [CommonModule, FormsModule], host: {
1568
+ class: 'hsi-ui-editable-textbox',
1569
+ }, template: "<div\n class=\"hsi-ui-editable-textbox-container\"\n [class.open]=\"service.isOpen$ | async\"\n #textInputTemplate\n>\n <input\n #box\n class=\"hsi-ui-editable-textbox-input\"\n [attr.type]=\"inputType\"\n role=\"combobox\"\n tabindex=\"0\"\n [id]=\"service.id + '-textbox'\"\n (click)=\"handleClick()\"\n (blur)=\"handleBlur($event)\"\n (keydown)=\"handleKeydown($event)\"\n autocomplete=\"off\"\n [attr.aria-label]=\"\n (service.label$ | async) === null\n ? ariaLabel || placeholder || service.isMultiSelect\n ? 'Search and select options'\n : 'Search and select an option'\n : null\n \"\n [attr.aria-labelledby]=\"\n (service.label$ | async) !== null ? service.comboboxLabelId : null\n \"\n [attr.aria-activedescendant]=\"service.activeDescendant$ | async\"\n [attr.aria-expanded]=\"service.isOpen$ | async\"\n [attr.aria-autocomplete]=\"service.autoComplete\"\n [attr.aria-controls]=\"service.id + '-listbox'\"\n aria-haspopup=\"listbox\"\n data-cy=\"editable-textbox-input\"\n [placeholder]=\"placeholder\"\n [ngModel]=\"value$ | async\"\n (ngModelChange)=\"onInputChange($event)\"\n />\n <div\n class=\"hsi-ui-textbox-icon hsi-ui-editable-textbox-icon\"\n [class.open]=\"service.isOpen$ | async\"\n >\n <ng-content select=\"[boxIcon]\"></ng-content\n ></div>\n</div>\n", styles: [".hsi-ui-editable-textbox-container{display:var(--hsi-ui-textbox-display);justify-content:var(--hsi-ui-textbox-justify-content);align-items:var(--hsi-ui-textbox-align-items);background:var(--hsi-ui-textbox-background);border:var(--hsi-ui-combobox-border-width) solid var(--hsi-ui-combobox-border-color);padding:var(--hsi-ui-editable-textbox-padding);border-radius:var(--hsi-ui-combobox-border-radius);transition:border var(--hsi-ui-textbox-transition-duration) ease-in-out}.hsi-ui-editable-textbox-container.open{border-bottom:var(--hsi-ui-textbox-border-bottom-open);border-bottom-left-radius:0;border-bottom-right-radius:0}.hsi-ui-editable-textbox-input{border:var(--hsi-ui-editable-textbox-input-border);border-bottom:var(--hsi-ui-editable-textbox-input-border-bottom);width:var(--hsi-ui-editable-textbox-input-width);padding:var(--hsi-ui-editable-textbox-input-padding);border-radius:var(--hsi-ui-editable-textbox-input-border-radius)}.hsi-ui-editable-textbox-input:hover,.hsi-ui-editable-textbox-input:focus{border:var(--hsi-ui-editable-textbox-input-hover-border);border-bottom:var(--hsi-ui-editable-textbox-input-hover-border-bottom);background:var(--hsi-ui-editable-textbox-input-hover-background);outline:var(--hsi-ui-editable-textbox-input-hover-outline)}\n"] }]
1570
+ }], propDecorators: { inputElRef: [{
1571
+ type: ViewChild,
1572
+ args: ['box']
1573
+ }], autoSelect: [{
1574
+ type: Input
1575
+ }], autoSelectTrigger: [{
1576
+ type: Input
1577
+ }], displaySelected: [{
1578
+ type: Input
1579
+ }], initialValue: [{
1580
+ type: Input
1581
+ }], inputType: [{
1582
+ type: Input
1583
+ }], ngFormControl: [{
1584
+ type: Input
1585
+ }], placeholder: [{
1586
+ type: Input
1587
+ }], valueChanges: [{
1588
+ type: Output
1589
+ }] } });
1590
+
1591
+ class HsiUiComboboxModule {
1592
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: HsiUiComboboxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1593
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.2", ngImport: i0, type: HsiUiComboboxModule, imports: [ComboboxComponent,
1594
+ ComboboxLabelComponent,
1595
+ TextboxComponent,
1596
+ ListboxComponent,
1597
+ ListboxGroupComponent,
1598
+ ListboxOptionComponent,
1599
+ ListboxLabelComponent,
1600
+ EditableTextboxComponent,
1601
+ SelectAllListboxOptionComponent], exports: [ComboboxComponent,
1602
+ ComboboxLabelComponent,
1603
+ TextboxComponent,
1604
+ ListboxComponent,
1605
+ ListboxGroupComponent,
1606
+ ListboxLabelComponent,
1607
+ ListboxOptionComponent,
1608
+ EditableTextboxComponent,
1609
+ SelectAllListboxOptionComponent] }); }
1610
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: HsiUiComboboxModule, imports: [ComboboxComponent,
1611
+ TextboxComponent,
1612
+ ListboxComponent,
1613
+ ListboxOptionComponent,
1614
+ ListboxLabelComponent,
1615
+ EditableTextboxComponent,
1616
+ SelectAllListboxOptionComponent] }); }
1617
+ }
1618
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: HsiUiComboboxModule, decorators: [{
1619
+ type: NgModule,
1620
+ args: [{
1621
+ imports: [
1622
+ ComboboxComponent,
1623
+ ComboboxLabelComponent,
1624
+ TextboxComponent,
1625
+ ListboxComponent,
1626
+ ListboxGroupComponent,
1627
+ ListboxOptionComponent,
1628
+ ListboxLabelComponent,
1629
+ EditableTextboxComponent,
1630
+ SelectAllListboxOptionComponent,
1631
+ ],
1632
+ exports: [
1633
+ ComboboxComponent,
1634
+ ComboboxLabelComponent,
1635
+ TextboxComponent,
1636
+ ListboxComponent,
1637
+ ListboxGroupComponent,
1638
+ ListboxLabelComponent,
1639
+ ListboxOptionComponent,
1640
+ EditableTextboxComponent,
1641
+ SelectAllListboxOptionComponent,
1642
+ ],
1643
+ }]
1644
+ }] });
1645
+
1646
+ class HsiUiDirectoryComponent {
1647
+ constructor() {
1648
+ this.level = 0;
1649
+ this.path = '';
1650
+ this.terminalItemsAreSelectable = true;
1651
+ this.selectionElementRole = 'button';
1652
+ /**
1653
+ * Emits the activePath and selectedItem when a leaf item is selected.
1654
+ *
1655
+ * Constructed from the `value` of each item if provided, otherwise uses `name`.
1656
+ */
1657
+ this.selectionChanges = new EventEmitter();
1658
+ /**
1659
+ * @internal
1660
+ *
1661
+ * Internal, will have no effect if provided at root level.
1662
+ */
1663
+ this.stateChanges = new EventEmitter();
1664
+ this.state = new BehaviorSubject({
1665
+ activePath: '',
1666
+ selectedItem: '',
1667
+ });
1668
+ this.state$ = this.state.asObservable();
1669
+ this.open = {};
1670
+ }
1671
+ ngOnChanges(changes) {
1672
+ if (NgOnChangesUtilities.inputObjectChanged(changes, 'selection')) {
1673
+ this.state.next(this.selection);
1674
+ }
1675
+ }
1676
+ toggleOpen(key) {
1677
+ if (this.open[key] === undefined) {
1678
+ this.open[key] = true;
1679
+ }
1680
+ else {
1681
+ this.open[key] = !this.open[key];
1682
+ }
1683
+ }
1684
+ // public events are emitted on leaf selection
1685
+ selectItem(item) {
1686
+ const itemValue = item.value || item.name;
1687
+ const activePath = this.path ? `${this.path}/${itemValue}` : itemValue;
1688
+ if (this.level === 0) {
1689
+ this.selectionChanges.emit({
1690
+ activePath: activePath,
1691
+ selectedItem: itemValue,
1692
+ });
1693
+ }
1694
+ else {
1695
+ this.stateChanges.emit({ activePath, selectedItem: itemValue });
1696
+ }
1697
+ }
1698
+ // called when child emits new _activePath value
1699
+ setState(state) {
1700
+ if (this.level === 0) {
1701
+ this.state.next(state);
1702
+ this.selectionChanges.emit({
1703
+ activePath: state.activePath,
1704
+ selectedItem: state.selectedItem,
1705
+ });
1706
+ }
1707
+ else {
1708
+ this.stateChanges.emit(state);
1709
+ }
1710
+ }
1711
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: HsiUiDirectoryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1712
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: HsiUiDirectoryComponent, isStandalone: true, selector: "hsi-ui-directory", inputs: { items: "items", level: "level", path: "path", terminalItemsAreSelectable: "terminalItemsAreSelectable", selectionElementRole: "selectionElementRole", selection: "selection" }, outputs: { selectionChanges: "selectionChanges", stateChanges: "stateChanges" }, usesOnChanges: true, ngImport: i0, template: "@for (item of items; track $index) {\n @if (!!item.children && item.children.length > 0) {\n <!-- This is the template for expandable nodes -->\n <div [style.--level]=\"level\">\n <div\n class=\"item expandable\"\n [ngClass]=\"'level-' + level\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"toggleOpen(item.name)\"\n (enter)=\"toggleOpen(item.name)\"\n >\n <p class=\"name\">{{ item.name }}</p>\n @if (open[item.name]) {\n <span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >expand_more</span\n >\n } @else {\n <span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >chevron_right</span\n >\n }\n </div>\n <hsi-ui-directory\n [items]=\"item.children\"\n [level]=\"level + 1\"\n [terminalItemsAreSelectable]=\"terminalItemsAreSelectable\"\n [path]=\"\n path.concat(\n level !== 0\n ? '/' + (item.value || item.name)\n : item.value || item.name\n )\n \"\n [class.invisible]=\"!open[item.name]\"\n (stateChanges)=\"setState($event)\"\n [selection]=\"state$ | async\"\n ></hsi-ui-directory>\n </div>\n } @else {\n <!-- This is the template for leaf nodes -->\n @if (terminalItemsAreSelectable) {\n <div\n class=\"item selectable\"\n [ngClass]=\"'level-' + level\"\n [attr.role]=\"selectionElementRole\"\n tabindex=\"0\"\n [style.--level]=\"level\"\n [class.active]=\"\n (state$ | async).activePath ===\n (level > 0 ? path + '/' : '') + (item.value || item.name)\n \"\n (click)=\"selectItem(item)\"\n (enter)=\"selectItem(item)\"\n >\n <p class=\"name\">{{ item.name }}</p>\n </div>\n } @else {\n <div class=\"item\" [style.--level]=\"level\">\n <p class=\"name\">{{ item.name }}</p>\n </div>\n }\n }\n}\n", styles: [".invisible{display:none}.item{display:flex;align-items:center;justify-content:space-between;margin:1px 0;margin-left:calc(var(--level) * .5rem);padding-right:.5rem;padding-top:.25rem;padding-bottom:.25rem}.item.expandable:hover,.item.selectable:hover{cursor:pointer;background-color:var(--hsi-adk-color-muted-primary-95);transition:all .2s}.item.active{background-color:var(--hsi-adk-color-muted-primary-95);color:var(--hsi-adk-color-primary-40)}.arrow{color:var(--hsi-adk-color-muted-primary-40);width:16px}\n"], dependencies: [{ kind: "component", type: HsiUiDirectoryComponent, selector: "hsi-ui-directory", inputs: ["items", "level", "path", "terminalItemsAreSelectable", "selectionElementRole", "selection"], outputs: ["selectionChanges", "stateChanges"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatIconModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1713
+ }
1714
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: HsiUiDirectoryComponent, decorators: [{
1715
+ type: Component,
1716
+ args: [{ selector: 'hsi-ui-directory', imports: [CommonModule, MatIconModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (item of items; track $index) {\n @if (!!item.children && item.children.length > 0) {\n <!-- This is the template for expandable nodes -->\n <div [style.--level]=\"level\">\n <div\n class=\"item expandable\"\n [ngClass]=\"'level-' + level\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"toggleOpen(item.name)\"\n (enter)=\"toggleOpen(item.name)\"\n >\n <p class=\"name\">{{ item.name }}</p>\n @if (open[item.name]) {\n <span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >expand_more</span\n >\n } @else {\n <span aria-hidden=\"true\" class=\"material-symbols-outlined arrow\"\n >chevron_right</span\n >\n }\n </div>\n <hsi-ui-directory\n [items]=\"item.children\"\n [level]=\"level + 1\"\n [terminalItemsAreSelectable]=\"terminalItemsAreSelectable\"\n [path]=\"\n path.concat(\n level !== 0\n ? '/' + (item.value || item.name)\n : item.value || item.name\n )\n \"\n [class.invisible]=\"!open[item.name]\"\n (stateChanges)=\"setState($event)\"\n [selection]=\"state$ | async\"\n ></hsi-ui-directory>\n </div>\n } @else {\n <!-- This is the template for leaf nodes -->\n @if (terminalItemsAreSelectable) {\n <div\n class=\"item selectable\"\n [ngClass]=\"'level-' + level\"\n [attr.role]=\"selectionElementRole\"\n tabindex=\"0\"\n [style.--level]=\"level\"\n [class.active]=\"\n (state$ | async).activePath ===\n (level > 0 ? path + '/' : '') + (item.value || item.name)\n \"\n (click)=\"selectItem(item)\"\n (enter)=\"selectItem(item)\"\n >\n <p class=\"name\">{{ item.name }}</p>\n </div>\n } @else {\n <div class=\"item\" [style.--level]=\"level\">\n <p class=\"name\">{{ item.name }}</p>\n </div>\n }\n }\n}\n", styles: [".invisible{display:none}.item{display:flex;align-items:center;justify-content:space-between;margin:1px 0;margin-left:calc(var(--level) * .5rem);padding-right:.5rem;padding-top:.25rem;padding-bottom:.25rem}.item.expandable:hover,.item.selectable:hover{cursor:pointer;background-color:var(--hsi-adk-color-muted-primary-95);transition:all .2s}.item.active{background-color:var(--hsi-adk-color-muted-primary-95);color:var(--hsi-adk-color-primary-40)}.arrow{color:var(--hsi-adk-color-muted-primary-40);width:16px}\n"] }]
1717
+ }], propDecorators: { items: [{
1718
+ type: Input
1719
+ }], level: [{
1720
+ type: Input
1721
+ }], path: [{
1722
+ type: Input
1723
+ }], terminalItemsAreSelectable: [{
1724
+ type: Input
1725
+ }], selectionElementRole: [{
1726
+ type: Input
1727
+ }], selection: [{
1728
+ type: Input
1729
+ }], selectionChanges: [{
1730
+ type: Output
1731
+ }], stateChanges: [{
1732
+ type: Output
1733
+ }] } });
1734
+
1735
+ var SortDirection;
1736
+ (function (SortDirection) {
1737
+ SortDirection["asc"] = "asc";
1738
+ SortDirection["desc"] = "desc";
1739
+ })(SortDirection || (SortDirection = {}));
1740
+ class TableColumn {
1741
+ constructor(init) {
1742
+ /**
1743
+ * Whether the column is sortable.
1744
+ */
1745
+ this.sortable = false;
1746
+ /**
1747
+ * The sort order of the column. Used to determine the order of sorting when multiple columns are sorted.
1748
+ * Sorting tiebreaks are determined by increasing sortOrder number.
1749
+ **/
1750
+ this.sortOrder = Number.MAX_SAFE_INTEGER;
1751
+ /**
1752
+ * Whether the column is a row header.
1753
+ */
1754
+ this.isRowHeader = false;
1755
+ this.sortDirection = SortDirection.asc;
1756
+ this.getAlignment = () => 'left';
1757
+ safeAssign(this, init);
1758
+ this.initialSortDirection = this.sortDirection;
1759
+ if (this.ascendingSortFunction === undefined) {
1760
+ this.ascendingSortFunction = this.defaultSort;
1761
+ }
1762
+ }
1763
+ defaultSort(a, b) {
1764
+ const accessor = this.getSortValue || this.getFormattedValue;
1765
+ return ascending(accessor(a), accessor(b));
1766
+ }
1767
+ }
1768
+
1769
+ /* eslint-disable @angular-eslint/prefer-standalone */
1770
+ class SingleSortHeaderComponent {
1771
+ getColumnSortClasses() {
1772
+ const baseClasses = [
1773
+ 'material-symbols-outlined',
1774
+ this.column.sortDirection,
1775
+ ];
1776
+ return this.column.activelySorted
1777
+ ? baseClasses.concat('actively-sorted')
1778
+ : baseClasses;
1779
+ }
1780
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: SingleSortHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1781
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: SingleSortHeaderComponent, isStandalone: false, selector: "[hsi-ui-single-sort-header]", inputs: { column: "column", sortIcon: "sortIcon" }, ngImport: i0, template: "<div class=\"header-cell-sort\">\n <span>{{ column.label }}</span>\n <span\n aria-hidden=\"true\"\n class=\"material-symbols-outlined\"\n [ngClass]=\"getColumnSortClasses()\"\n >{{ sortIcon }}</span\n >\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
1782
+ }
1783
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: SingleSortHeaderComponent, decorators: [{
1784
+ type: Component,
1785
+ args: [{ selector: '[hsi-ui-single-sort-header]', standalone: false, template: "<div class=\"header-cell-sort\">\n <span>{{ column.label }}</span>\n <span\n aria-hidden=\"true\"\n class=\"material-symbols-outlined\"\n [ngClass]=\"getColumnSortClasses()\"\n >{{ sortIcon }}</span\n >\n</div>\n" }]
1786
+ }], propDecorators: { column: [{
1787
+ type: Input
1788
+ }], sortIcon: [{
1789
+ type: Input
1790
+ }] } });
1791
+
1792
+ class TableComponent {
1793
+ constructor(destroyRef) {
1794
+ this.destroyRef = destroyRef;
1795
+ this.sortIcon = 'arrow_upward';
1796
+ this.sort = new BehaviorSubject(null);
1797
+ this.sort$ = this.sort.asObservable();
1798
+ }
1799
+ ngOnInit() {
1800
+ this.setTableData();
1801
+ this.setTableHeaders();
1802
+ this.validateRowHeaders();
1803
+ }
1804
+ setTableData() {
1805
+ const config$ = this.config$.pipe(withLatestFrom(this.sort$), map(([config, sort]) => () => {
1806
+ const activeSortColumn = sort || this.getMinSortOrderColumn(config.columns);
1807
+ const columns = this.getColumnsWithNewSortApplied(activeSortColumn, config.columns, false);
1808
+ return {
1809
+ data: this.sortData(config.data, activeSortColumn, columns),
1810
+ columns,
1811
+ };
1812
+ }));
1813
+ const sort$ = this.sort$.pipe(filter((sort) => sort !== null), map((sort) => (sortedConfig) => {
1814
+ const columns = this.getColumnsWithNewSortApplied(sort, sortedConfig.columns);
1815
+ return {
1816
+ data: this.sortData(sortedConfig.data, sort, columns),
1817
+ columns,
1818
+ };
1819
+ }));
1820
+ const sortedConfig$ = merge(config$, sort$).pipe(scan((sortedConfig, changeFn) => changeFn(sortedConfig), {
1821
+ data: [],
1822
+ columns: [],
1823
+ }), shareReplay(1) // do not remove sort toggle will be called twice
1824
+ );
1825
+ this.data$ = sortedConfig$.pipe(map((x) => x.data), shareReplay(1));
1826
+ this.columns$ = sortedConfig$.pipe(map((x) => x.columns), shareReplay(1));
1827
+ }
1828
+ getMinSortOrderColumn(columns) {
1829
+ const minSortOrder = min(columns, (x) => x.sortOrder);
1830
+ return columns.find((x) => x.sortOrder === minSortOrder);
1831
+ }
1832
+ getColumnsWithNewSortApplied(activeSortColumn, columns, toggleSortDirection = true) {
1833
+ const columnsWithSortDir = columns.map((x) => {
1834
+ if (x.label === activeSortColumn.label) {
1835
+ if (toggleSortDirection) {
1836
+ x.sortDirection =
1837
+ x.sortDirection === SortDirection.asc
1838
+ ? SortDirection.desc
1839
+ : SortDirection.asc;
1840
+ }
1841
+ x.activelySorted = true;
1842
+ }
1843
+ else {
1844
+ if (toggleSortDirection) {
1845
+ x.sortDirection = x.initialSortDirection;
1846
+ }
1847
+ x.activelySorted = false;
1848
+ }
1849
+ return x;
1850
+ });
1851
+ return columnsWithSortDir;
1852
+ }
1853
+ setTableHeaders() {
1854
+ this.tableHeaders$ = this.columns$.pipe(map((columns) => columns.map((x) => x.label)), distinctUntilChanged((a, b) => isEqual(a, b)), shareReplay(1));
1855
+ }
1856
+ validateRowHeaders() {
1857
+ this.columns$
1858
+ .pipe(takeUntilDestroyed(this.destroyRef))
1859
+ .subscribe((columns) => {
1860
+ const rowHeaders = columns.filter((x) => x.isRowHeader);
1861
+ if (rowHeaders.length > 1) {
1862
+ throw new Error('Table can only have one row header column. Please update your column config.');
1863
+ }
1864
+ });
1865
+ }
1866
+ sortTableByColumn(column) {
1867
+ this.sort.next(column);
1868
+ }
1869
+ sortData(data, primaryColumnSort, columns) {
1870
+ const sortedColumns = columns.slice().sort((columnA, columnB) => {
1871
+ return columnA.label === primaryColumnSort.label
1872
+ ? -1
1873
+ : columnB.label === primaryColumnSort.label
1874
+ ? 1
1875
+ : columnA.sortOrder - columnB.sortOrder;
1876
+ });
1877
+ const sortedData = data.slice().sort((a, b) => {
1878
+ for (const column of sortedColumns) {
1879
+ let returnValue = column.ascendingSortFunction(a, b);
1880
+ if (column.sortDirection === SortDirection.desc) {
1881
+ returnValue *= -1;
1882
+ }
1883
+ if (returnValue !== 0)
1884
+ return returnValue;
1885
+ }
1886
+ return 0;
1887
+ });
1888
+ return sortedData;
1889
+ }
1890
+ columnTrackingFunction(_, column) {
1891
+ return column.label;
1892
+ }
1893
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TableComponent, deps: [{ token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
1894
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: TableComponent, isStandalone: false, selector: "hsi-ui-table", inputs: { config$: "config$", sortIcon: "sortIcon" }, ngImport: i0, template: "<table class=\"table-container\" cdk-table [dataSource]=\"data$\">\n <col\n *ngFor=\"let column of columns$ | async; trackBy: columnTrackingFunction\"\n span=\"1\"\n [style]=\"'width:' + column.width\"\n />\n\n <ng-container\n *ngFor=\"let column of columns$ | async; trackBy: columnTrackingFunction\"\n [cdkColumnDef]=\"column.label\"\n >\n <ng-container\n *ngIf=\"column.sortable; then sortIconCells; else basicCells\"\n ></ng-container>\n <ng-template #sortIconCells>\n <th\n hsi-ui-single-sort-header\n scope=\"col\"\n cdk-header-cell\n *cdkHeaderCellDef=\"let element\"\n [ngClass]=\"[column.getAlignment(element), 'sorted-header']\"\n [column]=\"column\"\n [sortIcon]=\"sortIcon\"\n (click)=\"sortTableByColumn(column)\"\n ></th>\n <td\n cdk-cell\n [ngClass]=\"[column.getAlignment(element), 'sorted-header']\"\n *cdkCellDef=\"let element\"\n [attr.scope]=\"column.isRowHeader ? 'row' : null\"\n data-cy=\"table-cell\"\n >\n {{ column.getFormattedValue(element) }}\n </td>\n </ng-template>\n <ng-template #basicCells>\n <th\n cdk-header-cell\n *cdkHeaderCellDef=\"let element\"\n [class]=\"column.getAlignment(element)\"\n scope=\"col\"\n >\n {{ column.label }}\n </th>\n <td\n cdk-cell\n [ngClass]=\"[column.getAlignment(element), 'sorted-cell']\"\n *cdkCellDef=\"let element\"\n [attr.scope]=\"column.isRowHeader ? 'row' : null\"\n data-cy=\"table-cell\"\n >\n {{ column.getFormattedValue(element) }}\n </td>\n </ng-template>\n </ng-container>\n\n <tr\n cdk-header-row\n class=\"header\"\n *cdkHeaderRowDef=\"tableHeaders$ | async\"\n ></tr>\n <tr\n cdk-row\n class=\"row\"\n data-cy=\"table-row\"\n *cdkRowDef=\"let row; columns: tableHeaders$ | async\"\n ></tr>\n <ng-template></ng-template>\n</table>\n", styles: [".table-container{border-spacing:0}.table-container td:last-child.left{padding-right:0}.table-container th:last-child.left{padding-right:0}.table-container th{vertical-align:bottom}.table-container th.sorted-header{padding-right:0}.table-container .header-cell-sort{display:flex;align-items:flex-end}.table-container .header-cell-sort:hover{cursor:pointer}.table-container .material-symbols-outlined{display:flex;justify-content:center;width:.9rem;height:1.2rem;font-size:1.25rem;margin-left:.2rem;margin-right:.4rem;opacity:.25;transition:all .15s ease-in-out}.table-container .material-symbols-outlined:hover{opacity:.75}.table-container .material-symbols-outlined.actively-sorted{opacity:1}.table-container .desc{transform:rotate(180deg)}.table-container .left{text-align:left}.table-container .right{text-align:right}.table-container .right .header-cell-sort{justify-content:flex-end}.table-container .right.sorted-cell{padding-right:1.5rem}.table-container .center{text-align:center}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.CdkTable, selector: "cdk-table, table[cdk-table]", inputs: ["trackBy", "dataSource", "multiTemplateDataRows", "fixedLayout"], outputs: ["contentChanged"], exportAs: ["cdkTable"] }, { kind: "directive", type: i2$1.CdkRowDef, selector: "[cdkRowDef]", inputs: ["cdkRowDefColumns", "cdkRowDefWhen"] }, { kind: "directive", type: i2$1.CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: i2$1.CdkHeaderCellDef, selector: "[cdkHeaderCellDef]" }, { kind: "directive", type: i2$1.CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "directive", type: i2$1.CdkCell, selector: "cdk-cell, td[cdk-cell]" }, { kind: "component", type: i2$1.CdkRow, selector: "cdk-row, tr[cdk-row]" }, { kind: "directive", type: i2$1.CdkHeaderCell, selector: "cdk-header-cell, th[cdk-header-cell]" }, { kind: "component", type: i2$1.CdkHeaderRow, selector: "cdk-header-row, tr[cdk-header-row]" }, { kind: "directive", type: i2$1.CdkHeaderRowDef, selector: "[cdkHeaderRowDef]", inputs: ["cdkHeaderRowDef", "cdkHeaderRowDefSticky"] }, { kind: "component", type: SingleSortHeaderComponent, selector: "[hsi-ui-single-sort-header]", inputs: ["column", "sortIcon"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1895
+ }
1896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TableComponent, decorators: [{
1897
+ type: Component,
1898
+ args: [{ selector: 'hsi-ui-table', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<table class=\"table-container\" cdk-table [dataSource]=\"data$\">\n <col\n *ngFor=\"let column of columns$ | async; trackBy: columnTrackingFunction\"\n span=\"1\"\n [style]=\"'width:' + column.width\"\n />\n\n <ng-container\n *ngFor=\"let column of columns$ | async; trackBy: columnTrackingFunction\"\n [cdkColumnDef]=\"column.label\"\n >\n <ng-container\n *ngIf=\"column.sortable; then sortIconCells; else basicCells\"\n ></ng-container>\n <ng-template #sortIconCells>\n <th\n hsi-ui-single-sort-header\n scope=\"col\"\n cdk-header-cell\n *cdkHeaderCellDef=\"let element\"\n [ngClass]=\"[column.getAlignment(element), 'sorted-header']\"\n [column]=\"column\"\n [sortIcon]=\"sortIcon\"\n (click)=\"sortTableByColumn(column)\"\n ></th>\n <td\n cdk-cell\n [ngClass]=\"[column.getAlignment(element), 'sorted-header']\"\n *cdkCellDef=\"let element\"\n [attr.scope]=\"column.isRowHeader ? 'row' : null\"\n data-cy=\"table-cell\"\n >\n {{ column.getFormattedValue(element) }}\n </td>\n </ng-template>\n <ng-template #basicCells>\n <th\n cdk-header-cell\n *cdkHeaderCellDef=\"let element\"\n [class]=\"column.getAlignment(element)\"\n scope=\"col\"\n >\n {{ column.label }}\n </th>\n <td\n cdk-cell\n [ngClass]=\"[column.getAlignment(element), 'sorted-cell']\"\n *cdkCellDef=\"let element\"\n [attr.scope]=\"column.isRowHeader ? 'row' : null\"\n data-cy=\"table-cell\"\n >\n {{ column.getFormattedValue(element) }}\n </td>\n </ng-template>\n </ng-container>\n\n <tr\n cdk-header-row\n class=\"header\"\n *cdkHeaderRowDef=\"tableHeaders$ | async\"\n ></tr>\n <tr\n cdk-row\n class=\"row\"\n data-cy=\"table-row\"\n *cdkRowDef=\"let row; columns: tableHeaders$ | async\"\n ></tr>\n <ng-template></ng-template>\n</table>\n", styles: [".table-container{border-spacing:0}.table-container td:last-child.left{padding-right:0}.table-container th:last-child.left{padding-right:0}.table-container th{vertical-align:bottom}.table-container th.sorted-header{padding-right:0}.table-container .header-cell-sort{display:flex;align-items:flex-end}.table-container .header-cell-sort:hover{cursor:pointer}.table-container .material-symbols-outlined{display:flex;justify-content:center;width:.9rem;height:1.2rem;font-size:1.25rem;margin-left:.2rem;margin-right:.4rem;opacity:.25;transition:all .15s ease-in-out}.table-container .material-symbols-outlined:hover{opacity:.75}.table-container .material-symbols-outlined.actively-sorted{opacity:1}.table-container .desc{transform:rotate(180deg)}.table-container .left{text-align:left}.table-container .right{text-align:right}.table-container .right .header-cell-sort{justify-content:flex-end}.table-container .right.sorted-cell{padding-right:1.5rem}.table-container .center{text-align:center}\n"] }]
1899
+ }], ctorParameters: () => [{ type: i0.DestroyRef }], propDecorators: { config$: [{
1900
+ type: Input
1901
+ }], sortIcon: [{
1902
+ type: Input
1903
+ }] } });
1904
+
1905
+ class HsiUiTableConfig {
1906
+ }
1907
+
1908
+ class TableModule {
1909
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1910
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.2", ngImport: i0, type: TableModule, declarations: [TableComponent, SingleSortHeaderComponent], imports: [CommonModule, CdkTableModule, MatIconModule], exports: [TableComponent] }); }
1911
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TableModule, imports: [CommonModule, CdkTableModule, MatIconModule] }); }
1912
+ }
1913
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TableModule, decorators: [{
1914
+ type: NgModule,
1915
+ args: [{
1916
+ declarations: [TableComponent, SingleSortHeaderComponent],
1917
+ imports: [CommonModule, CdkTableModule, MatIconModule],
1918
+ exports: [TableComponent],
1919
+ }]
1920
+ }] });
1921
+
1922
+ const HSI_UI_TAB_CONTENT = new InjectionToken('TabContent');
1923
+ /**
1924
+ * Allows a tab to be lazy-loaded when it is activated when used as a directive on an ng-template. It is recommended that this be used when the content of the tab requires calculations.
1925
+ *
1926
+ * Has the same functionality as https://material.angular.io/components/tabs/overview#lazy-loading
1927
+ */
1928
+ class TabContentDirective {
1929
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1930
+ constructor(/** Content for the tab. */ template) {
1931
+ this.template = template;
1932
+ }
1933
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabContentDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1934
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.2", type: TabContentDirective, isStandalone: true, selector: "[hsiUiTabContent]", providers: [
1935
+ { provide: HSI_UI_TAB_CONTENT, useExisting: TabContentDirective },
1936
+ ], ngImport: i0 }); }
1937
+ }
1938
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabContentDirective, decorators: [{
1939
+ type: Directive,
1940
+ args: [{
1941
+ selector: '[hsiUiTabContent]',
1942
+ providers: [
1943
+ { provide: HSI_UI_TAB_CONTENT, useExisting: TabContentDirective },
1944
+ ],
1945
+ }]
1946
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
1947
+
1948
+ class TabBodyComponent {
1949
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabBodyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1950
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: TabBodyComponent, isStandalone: true, selector: "hsi-ui-tab-body", queries: [{ propertyName: "lazyLoadedContent", first: true, predicate: TabContentDirective, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "bodyContent", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: '<ng-template><ng-content></ng-content></ng-template>', isInline: true }); }
1951
+ }
1952
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabBodyComponent, decorators: [{
1953
+ type: Component,
1954
+ args: [{
1955
+ selector: 'hsi-ui-tab-body',
1956
+ template: '<ng-template><ng-content></ng-content></ng-template>',
1957
+ }]
1958
+ }], propDecorators: { bodyContent: [{
1959
+ type: ViewChild,
1960
+ args: [TemplateRef]
1961
+ }],
1962
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1963
+ lazyLoadedContent: [{
1964
+ type: ContentChild,
1965
+ args: [TabContentDirective, { read: TemplateRef, static: true }]
1966
+ }] } });
1967
+
1968
+ let nextUniqueId = 0;
1969
+ class TabLabelComponent {
1970
+ constructor() {
1971
+ this.id = `tab-label-${nextUniqueId++}`;
1972
+ }
1973
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1974
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: TabLabelComponent, isStandalone: true, selector: "hsi-ui-tab-label", inputs: { value: "value" }, viewQueries: [{ propertyName: "labelElement", first: true, predicate: ["label"], descendants: true }, { propertyName: "labelContent", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: `<ng-template
1975
+ ><div #label class="tab-label" [id]="id"><ng-content></ng-content></div
1976
+ ></ng-template>`, isInline: true }); }
1977
+ }
1978
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabLabelComponent, decorators: [{
1979
+ type: Component,
1980
+ args: [{
1981
+ selector: 'hsi-ui-tab-label',
1982
+ template: `<ng-template
1983
+ ><div #label class="tab-label" [id]="id"><ng-content></ng-content></div
1984
+ ></ng-template>`,
1985
+ }]
1986
+ }], propDecorators: { value: [{
1987
+ type: Input
1988
+ }], labelElement: [{
1989
+ type: ViewChild,
1990
+ args: ['label']
1991
+ }], labelContent: [{
1992
+ type: ViewChild,
1993
+ args: [TemplateRef]
1994
+ }] } });
1995
+
1996
+ class TabsService {
1997
+ constructor() {
1998
+ this.activeTab = new BehaviorSubject(null);
1999
+ this.activeTab$ = this.activeTab.asObservable();
2000
+ }
2001
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2002
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsService }); }
2003
+ }
2004
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsService, decorators: [{
2005
+ type: Injectable
2006
+ }] });
2007
+
2008
+ class TabItemComponent {
2009
+ constructor(service) {
2010
+ this.service = service;
2011
+ this.isActive = false;
2012
+ }
2013
+ ngOnChanges() {
2014
+ if (this.isActive) {
2015
+ this.service.activeTab.next(this);
2016
+ }
2017
+ }
2018
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabItemComponent, deps: [{ token: TabsService }], target: i0.ɵɵFactoryTarget.Component }); }
2019
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: TabItemComponent, isStandalone: true, selector: "hsi-ui-tab-item", inputs: { isActive: "isActive", value: "value" }, queries: [{ propertyName: "bodyComponent", first: true, predicate: TabBodyComponent, descendants: true }, { propertyName: "labelComponent", first: true, predicate: TabLabelComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true }); }
2020
+ }
2021
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabItemComponent, decorators: [{
2022
+ type: Component,
2023
+ args: [{
2024
+ selector: 'hsi-ui-tab-item',
2025
+ template: '<ng-content></ng-content>',
2026
+ }]
2027
+ }], ctorParameters: () => [{ type: TabsService }], propDecorators: { isActive: [{
2028
+ type: Input
2029
+ }], value: [{
2030
+ type: Input
2031
+ }], bodyComponent: [{
2032
+ type: ContentChild,
2033
+ args: [TabBodyComponent]
2034
+ }], labelComponent: [{
2035
+ type: ContentChild,
2036
+ args: [TabLabelComponent]
2037
+ }] } });
2038
+
2039
+ class TabsComponent {
2040
+ constructor(service, destroyRef) {
2041
+ this.service = service;
2042
+ this.destroyRef = destroyRef;
2043
+ this.tabChange = new EventEmitter();
2044
+ }
2045
+ ngAfterContentInit() {
2046
+ this.tabItems$ = this.tabs.changes.pipe(takeUntilDestroyed(this.destroyRef), startWith(''), map(() => this.tabs.toArray()));
2047
+ this.initializeActiveTab();
2048
+ }
2049
+ initializeActiveTab() {
2050
+ if (!this.service.activeTab.value) {
2051
+ this.service.activeTab.next(this.tabs.first);
2052
+ }
2053
+ }
2054
+ selectTab(tabItem) {
2055
+ if (this.service.activeTab.value !== tabItem) {
2056
+ this.service.activeTab.next(tabItem);
2057
+ this.emitNewActiveTab(tabItem);
2058
+ }
2059
+ }
2060
+ emitNewActiveTab(tabItem) {
2061
+ const value = tabItem.value ??
2062
+ tabItem.labelComponent.labelElement.nativeElement.innerText;
2063
+ this.tabChange.emit(value);
2064
+ }
2065
+ handleKeydown(event, tabItem) {
2066
+ const tabIndex = this.tabs.toArray().indexOf(tabItem);
2067
+ let cancelOtherActions = false;
2068
+ switch (event.key) {
2069
+ case 'Enter':
2070
+ case ' ':
2071
+ this.selectTab(tabItem);
2072
+ cancelOtherActions = true;
2073
+ break;
2074
+ case 'ArrowRight':
2075
+ case 'Right':
2076
+ this.focusNextTab(tabIndex);
2077
+ cancelOtherActions = true;
2078
+ break;
2079
+ case 'ArrowLeft':
2080
+ case 'Left':
2081
+ this.focusPreviousTab(tabIndex);
2082
+ cancelOtherActions = true;
2083
+ break;
2084
+ case 'Home':
2085
+ this.focusTab(this.tabs.first);
2086
+ cancelOtherActions = true;
2087
+ break;
2088
+ case 'End':
2089
+ this.focusTab(this.tabs.last);
2090
+ cancelOtherActions = true;
2091
+ break;
2092
+ default:
2093
+ break;
2094
+ }
2095
+ if (cancelOtherActions) {
2096
+ event.preventDefault();
2097
+ event.stopPropagation();
2098
+ }
2099
+ }
2100
+ focusTab(tabItem) {
2101
+ tabItem.labelComponent.labelElement.nativeElement.parentElement?.focus();
2102
+ }
2103
+ focusNextTab(tabIndex) {
2104
+ if (tabIndex < this.tabs.length - 1) {
2105
+ this.focusTab(this.tabs.toArray()[tabIndex + 1]);
2106
+ }
2107
+ else {
2108
+ this.focusTab(this.tabs.first);
2109
+ }
2110
+ }
2111
+ focusPreviousTab(tabIndex) {
2112
+ if (tabIndex > 0) {
2113
+ this.focusTab(this.tabs.toArray()[tabIndex - 1]);
2114
+ }
2115
+ else {
2116
+ this.focusTab(this.tabs.last);
2117
+ }
2118
+ }
2119
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsComponent, deps: [{ token: TabsService }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
2120
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: TabsComponent, isStandalone: true, selector: "hsi-ui-tabs", outputs: { tabChange: "tabChange" }, providers: [TabsService], queries: [{ propertyName: "tabs", predicate: TabItemComponent }], ngImport: i0, template: "<ng-container *ngIf=\"service.activeTab$ | async as activeTab\">\n <div class=\"tab-list\" role=\"tablist\">\n <div\n *ngFor=\"let item of tabItems$ | async\"\n role=\"tab\"\n [tabindex]=\"activeTab === item ? 0 : -1\"\n class=\"tab-label-container\"\n (click)=\"selectTab(item)\"\n (keydown)=\"handleKeydown($event, item)\"\n [attr.aria-selected]=\"activeTab === item\"\n [class.active]=\"activeTab === item\"\n aria-controls=\"tabs-component-body\"\n data-cy=\"level\"\n >\n <ng-container *ngIf=\"item.labelComponent\">\n <ng-container *ngTemplateOutlet=\"item.labelComponent.labelContent\">\n </ng-container>\n </ng-container>\n </div>\n </div>\n <div\n class=\"tabs-body\"\n id=\"tabs-component-body\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"activeTab?.labelComponent?.id\"\n >\n @if (activeTab.bodyComponent) {\n @if (activeTab.bodyComponent?.lazyLoadedContent) {\n <ng-container\n *ngTemplateOutlet=\"activeTab.bodyComponent.lazyLoadedContent\"\n >\n </ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"activeTab.bodyComponent.bodyContent\">\n </ng-container>\n }\n }\n </div>\n</ng-container>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] }); }
2121
+ }
2122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsComponent, decorators: [{
2123
+ type: Component,
2124
+ args: [{ selector: 'hsi-ui-tabs', imports: [CommonModule], providers: [TabsService], template: "<ng-container *ngIf=\"service.activeTab$ | async as activeTab\">\n <div class=\"tab-list\" role=\"tablist\">\n <div\n *ngFor=\"let item of tabItems$ | async\"\n role=\"tab\"\n [tabindex]=\"activeTab === item ? 0 : -1\"\n class=\"tab-label-container\"\n (click)=\"selectTab(item)\"\n (keydown)=\"handleKeydown($event, item)\"\n [attr.aria-selected]=\"activeTab === item\"\n [class.active]=\"activeTab === item\"\n aria-controls=\"tabs-component-body\"\n data-cy=\"level\"\n >\n <ng-container *ngIf=\"item.labelComponent\">\n <ng-container *ngTemplateOutlet=\"item.labelComponent.labelContent\">\n </ng-container>\n </ng-container>\n </div>\n </div>\n <div\n class=\"tabs-body\"\n id=\"tabs-component-body\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"activeTab?.labelComponent?.id\"\n >\n @if (activeTab.bodyComponent) {\n @if (activeTab.bodyComponent?.lazyLoadedContent) {\n <ng-container\n *ngTemplateOutlet=\"activeTab.bodyComponent.lazyLoadedContent\"\n >\n </ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"activeTab.bodyComponent.bodyContent\">\n </ng-container>\n }\n }\n </div>\n</ng-container>\n" }]
2125
+ }], ctorParameters: () => [{ type: TabsService }, { type: i0.DestroyRef }], propDecorators: { tabs: [{
2126
+ type: ContentChildren,
2127
+ args: [TabItemComponent]
2128
+ }], tabChange: [{
2129
+ type: Output
2130
+ }] } });
2131
+
2132
+ class TabsModule {
2133
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2134
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.2", ngImport: i0, type: TabsModule, imports: [TabsComponent,
2135
+ TabLabelComponent,
2136
+ TabItemComponent,
2137
+ TabBodyComponent,
2138
+ TabContentDirective], exports: [TabsComponent,
2139
+ TabLabelComponent,
2140
+ TabItemComponent,
2141
+ TabBodyComponent,
2142
+ TabContentDirective] }); }
2143
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsModule, imports: [TabsComponent] }); }
2144
+ }
2145
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: TabsModule, decorators: [{
2146
+ type: NgModule,
2147
+ args: [{
2148
+ declarations: [],
2149
+ imports: [
2150
+ TabsComponent,
2151
+ TabLabelComponent,
2152
+ TabItemComponent,
2153
+ TabBodyComponent,
2154
+ TabContentDirective,
2155
+ ],
2156
+ exports: [
2157
+ TabsComponent,
2158
+ TabLabelComponent,
2159
+ TabItemComponent,
2160
+ TabBodyComponent,
2161
+ TabContentDirective,
2162
+ ],
2163
+ }]
2164
+ }] });
2165
+
2166
+ /*
2167
+ * Public API Surface of ui
2168
+ */
2169
+
2170
+ /**
2171
+ * Generated bundle index. Do not edit.
2172
+ */
2173
+
2174
+ export { AutoComplete, ComboboxComponent, ComboboxLabelComponent, ComboboxService, EditableTextboxComponent, FocusTextbox, HSI_UI_TAB_CONTENT, HsiUiComboboxModule, HsiUiDirectoryComponent, HsiUiTableConfig, Key, ListboxAction, ListboxComponent, ListboxGroupComponent, ListboxLabelComponent, ListboxOptionComponent, OptionAction, SelectAllListboxOptionComponent, SortDirection, TabBodyComponent, TabContentDirective, TabItemComponent, TabLabelComponent, TableColumn, TableComponent, TableModule, TabsComponent, TabsModule, TextboxAction, TextboxComponent };
2175
+ //# sourceMappingURL=mathstack-ui.mjs.map