ngx-tethys 20.0.0 → 20.0.1

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.
@@ -1,23 +1,23 @@
1
1
  import { Overlay, CdkConnectedOverlay, CdkOverlayOrigin, OverlayModule } from '@angular/cdk/overlay';
2
2
  import { isPlatformBrowser, NgClass, NgTemplateOutlet, CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, inject, NgZone, ElementRef, ChangeDetectorRef, PLATFORM_ID, input, viewChild, output, contentChild, numberAttribute, contentChildren, viewChildren, effect, untracked, forwardRef, HostListener, ViewChildren, ContentChildren, ViewChild, Input, ChangeDetectionStrategy, Component, model, signal, NgModule } from '@angular/core';
5
- import * as i1 from '@angular/forms';
4
+ import { InjectionToken, inject, NgZone, ElementRef, ChangeDetectorRef, PLATFORM_ID, computed, input, signal, DestroyRef, viewChild, output, contentChild, numberAttribute, contentChildren, linkedSignal, afterRenderEffect, untracked, forwardRef, HostListener, ViewChildren, ViewChild, Input, ChangeDetectionStrategy, Component, model, NgModule } from '@angular/core';
5
+ import * as i1$1 from '@angular/forms';
6
6
  import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
7
7
  import { ThyEmpty, ThyEmptyModule } from 'ngx-tethys/empty';
8
8
  import { ThyIcon, ThyIconModule } from 'ngx-tethys/icon';
9
9
  import { ThyInputDirective, ThyInputModule } from 'ngx-tethys/input';
10
10
  import { ThyLoading, ThyLoadingModule } from 'ngx-tethys/loading';
11
- import { ThySelectOptionGroup, ThySelectControl, ThyStopPropagationDirective, ThyScrollDirective, ThyOptionsContainer, ThyOption, THY_OPTION_PARENT_COMPONENT, ThyOptionModule, ThySharedModule, ThySelectCommonModule } from 'ngx-tethys/shared';
12
- import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
11
+ import { ThyOption, ThySelectOptionGroup, ThySelectControl, ThyStopPropagationDirective, ThyOptionRender, ThyOptionGroupRender, ThyOptionModule, ThySharedModule, ThySelectCommonModule } from 'ngx-tethys/shared';
12
+ import { TabIndexDisabledControlValueAccessorMixin, ThyClickDispatcher, injectPanelEmptyIcon, getFlexiblePositions, scaleXMotion, scaleYMotion, scaleMotion } from 'ngx-tethys/core';
13
+ import { ENTER, isFunction, coerceBooleanProperty, helpers, elementMatchClosest, SPACE, DOWN_ARROW, UP_ARROW, hasModifierKey, HOME, END, A, TAB } from 'ngx-tethys/util';
14
+ import { timer, Observable } from 'rxjs';
15
+ import { map, filter, startWith, take, distinctUntilChanged } from 'rxjs/operators';
13
16
  import { coerceElement } from '@angular/cdk/coercion';
14
- import { SelectionModel } from '@angular/cdk/collections';
15
- import { TabIndexDisabledControlValueAccessorMixin, ThyClickDispatcher, injectPanelEmptyIcon, ScrollToService, getFlexiblePositions, scaleXMotion, scaleYMotion, scaleMotion } from 'ngx-tethys/core';
16
- import { ENTER, isFunction, coerceBooleanProperty, elementMatchClosest, DOWN_ARROW, UP_ARROW, LEFT_ARROW, RIGHT_ARROW, SPACE, hasModifierKey, HOME, END, A, helpers, isArray } from 'ngx-tethys/util';
17
- import { Subject, defer, merge, timer, Observable } from 'rxjs';
18
- import { map, filter, take, switchMap, takeUntil, startWith, distinctUntilChanged } from 'rxjs/operators';
19
- import { outputToObservable } from '@angular/core/rxjs-interop';
20
17
  import { injectLocale } from 'ngx-tethys/i18n';
18
+ import * as i1 from '@angular/cdk/scrolling';
19
+ import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
20
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
21
21
  import { useHostRenderer } from '@tethys/cdk/dom';
22
22
 
23
23
  const THY_SELECT_SCROLL_STRATEGY = new InjectionToken('thy-select-scroll-strategy');
@@ -41,10 +41,9 @@ const THY_SELECT_CONFIG_PROVIDER = {
41
41
 
42
42
  const SELECT_PANEL_MAX_HEIGHT = 300;
43
43
  const SELECT_OPTION_MAX_HEIGHT = 40;
44
- const SELECT_OPTION_GROUP_MAX_HEIGHT = 30;
45
- const SELECT_PANEL_PADDING_TOP = 10;
44
+ const SELECT_PANEL_PADDING_TOP = 12;
45
+ const SELECT_PANEL_PADDING_BOTTOM = 12;
46
46
  const THY_SELECT_PANEL_MIN_WIDTH = 200;
47
- const noop$1 = () => { };
48
47
  /**
49
48
  * 下拉选择组件
50
49
  * @name thy-select,thy-custom-select
@@ -61,19 +60,19 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
61
60
  get thyDisabled() {
62
61
  return this.disabled;
63
62
  }
64
- handleKeydown(event) {
65
- if (!this.disabled) {
66
- if (event.keyCode === ENTER) {
67
- event.stopPropagation();
68
- }
69
- this.panelOpen ? this.handleOpenKeydown(event) : this.handleClosedKeydown(event);
63
+ keydown(event) {
64
+ if (this.disabled) {
65
+ return;
70
66
  }
67
+ if (event.keyCode === ENTER) {
68
+ event.stopPropagation();
69
+ }
70
+ this.handleKeydown(event);
71
71
  }
72
72
  get optionsChanges$() {
73
- this.options = this.isReactiveDriven ? this.viewOptions : this.contentOptions;
74
- let previousOptions = this.options.toArray();
75
- return this.options.changes.pipe(map(data => {
76
- return this.options.toArray();
73
+ let previousOptions = this.optionRenders.toArray();
74
+ return this.optionRenders.changes.pipe(map(data => {
75
+ return this.optionRenders.toArray();
77
76
  }), filter(data => {
78
77
  const res = previousOptions.length !== data.length || previousOptions.some((op, index) => op !== data[index]);
79
78
  previousOptions = data;
@@ -88,9 +87,6 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
88
87
  this.scrollStrategy = this.overlay.scrollStrategies.reposition();
89
88
  }
90
89
  }
91
- get placement() {
92
- return this.thyPlacement() || this.config.placement;
93
- }
94
90
  constructor() {
95
91
  super();
96
92
  this.ngZone = inject(NgZone);
@@ -106,25 +102,55 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
106
102
  this.disabled = false;
107
103
  this.mode = '';
108
104
  this.scrollTop = 0;
109
- this.modalValue = null;
110
105
  this.defaultOffset = 4;
111
- this.dropDownMinWidth = null;
106
+ this.dropDownClass = computed(() => {
107
+ const modeClass = `thy-select-dropdown-${this.isMultiple() ? 'multiple' : 'single'}`;
108
+ return {
109
+ [`thy-select-dropdown`]: true,
110
+ [modeClass]: true
111
+ };
112
+ }, ...(ngDevMode ? [{ debugName: "dropDownClass" }] : []));
113
+ this.dropDownMinWidth = computed(() => {
114
+ const mode = this.thyDropdownWidthMode() || this.config.dropdownWidthMode;
115
+ let dropdownMinWidth = null;
116
+ if (mode?.minWidth) {
117
+ dropdownMinWidth = mode.minWidth;
118
+ }
119
+ else if (mode === 'min-width') {
120
+ dropdownMinWidth = THY_SELECT_PANEL_MIN_WIDTH;
121
+ }
122
+ else {
123
+ dropdownMinWidth = null;
124
+ }
125
+ return dropdownMinWidth;
126
+ }, ...(ngDevMode ? [{ debugName: "dropDownMinWidth" }] : []));
112
127
  /**
113
128
  * 设置下拉框的最小宽度,默认值 `match-select`,表示与输入框的宽度一致;`min-width` 表示最小宽度为200px;支持自定义最小宽度,比如传 `{minWidth: 150}` 表示最小宽度为150px
114
129
  * @default match-select
115
130
  */
116
131
  this.thyDropdownWidthMode = input(...(ngDevMode ? [undefined, { debugName: "thyDropdownWidthMode" }] : []));
132
+ this.placement = computed(() => {
133
+ return this.thyPlacement() || this.config.placement;
134
+ }, ...(ngDevMode ? [{ debugName: "placement" }] : []));
135
+ this.dropDownPositions = computed(() => {
136
+ return getFlexiblePositions(this.placement(), this.defaultOffset);
137
+ }, ...(ngDevMode ? [{ debugName: "dropDownPositions" }] : []));
138
+ this.itemSize = SELECT_OPTION_MAX_HEIGHT;
139
+ this.virtualHeight = computed(() => {
140
+ const maxVirtualHeight = SELECT_PANEL_MAX_HEIGHT - SELECT_PANEL_PADDING_TOP - SELECT_PANEL_PADDING_BOTTOM;
141
+ const height = this.filteredGroupsAndOptions().length * this.itemSize;
142
+ return Math.min(height, maxVirtualHeight);
143
+ }, ...(ngDevMode ? [{ debugName: "virtualHeight" }] : []));
144
+ /**
145
+ * 视觉上能看到的最大选项个数
146
+ */
147
+ this.maxItemLength = 7;
148
+ this.triggerRectWidth = signal(undefined, ...(ngDevMode ? [{ debugName: "triggerRectWidth" }] : []));
117
149
  /**
118
150
  * 手动聚焦中的标识
119
151
  */
120
152
  this.manualFocusing = false;
121
- this.destroy$ = new Subject();
122
- this.optionSelectionChanges = defer(() => {
123
- if (this.options) {
124
- return merge(...this.options.map(option => outputToObservable(option.selectionChange)));
125
- }
126
- return this.ngZone.onStable.asObservable().pipe(take(1), switchMap(() => this.optionSelectionChanges));
127
- });
153
+ this.destroyRef = inject(DestroyRef);
128
154
  this.cdkConnectedOverlay = viewChild(CdkConnectedOverlay, ...(ngDevMode ? [{ debugName: "cdkConnectedOverlay" }] : []));
129
155
  this.panelOpen = false;
130
156
  /**
@@ -237,70 +263,119 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
237
263
  * 是否隐藏选择框边框
238
264
  */
239
265
  this.thyBorderless = input(false, ...(ngDevMode ? [{ debugName: "thyBorderless", transform: coerceBooleanProperty }] : [{ transform: coerceBooleanProperty }]));
240
- this.isReactiveDriven = false;
241
- this.optionGroups = [];
266
+ this.scrolledIndex = 0;
267
+ this.cdkVirtualScrollViewport = viewChild(CdkVirtualScrollViewport, ...(ngDevMode ? [{ debugName: "cdkVirtualScrollViewport" }] : []));
268
+ this.shouldActivateOption = false;
242
269
  /**
243
270
  * option 列表
244
271
  */
245
272
  this.thyOptions = input(undefined, ...(ngDevMode ? [{ debugName: "thyOptions", transform: (value) => {
246
- if (value === null) {
273
+ if (helpers.isUndefinedOrNull(value)) {
247
274
  value = [];
248
275
  }
249
- this.innerOptions = value;
250
- this.isReactiveDriven = true;
251
- this.buildReactiveOptions();
252
276
  return value;
253
277
  } }] : [{
254
278
  transform: (value) => {
255
- if (value === null) {
279
+ if (helpers.isUndefinedOrNull(value)) {
256
280
  value = [];
257
281
  }
258
- this.innerOptions = value;
259
- this.isReactiveDriven = true;
260
- this.buildReactiveOptions();
261
282
  return value;
262
283
  }
263
284
  }]));
285
+ this.keywords = signal('', ...(ngDevMode ? [{ debugName: "keywords" }] : []));
264
286
  /**
265
287
  * 目前只支持多选选中项的展示,默认为空,渲染文字模板,传入tag,渲染展示模板,
266
288
  * @default ''|tag
267
289
  */
268
290
  this.thyPreset = input('', ...(ngDevMode ? [{ debugName: "thyPreset" }] : []));
269
- this.panel = viewChild('panel', ...(ngDevMode ? [{ debugName: "panel" }] : []));
291
+ this.options = contentChildren(ThyOption, ...(ngDevMode ? [{ debugName: "options", descendants: true }] : [{ descendants: true }]));
292
+ this.groups = contentChildren(ThySelectOptionGroup, ...(ngDevMode ? [{ debugName: "groups", descendants: true }] : [{ descendants: true }]));
270
293
  /**
271
- * @private
294
+ * 所有分组和选项
295
+ */
296
+ this.allGroupsAndOptions = signal([], ...(ngDevMode ? [{ debugName: "allGroupsAndOptions" }] : []));
297
+ /**
298
+ * 渲染的分组和选项,基于 keywords 过滤后
299
+ */
300
+ this.filteredGroupsAndOptions = computed(() => {
301
+ return this.buildFilteredGroupsAndOptions();
302
+ }, ...(ngDevMode ? [{ debugName: "filteredGroupsAndOptions" }] : []));
303
+ /**
304
+ * 渲染的选项
305
+ */
306
+ this.filteredOptions = computed(() => {
307
+ return this.filteredGroupsAndOptions().filter(item => item.type === 'option');
308
+ }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
309
+ this.filteredOptionsMap = computed(() => {
310
+ return helpers.keyBy(this.filteredOptions(), 'value');
311
+ }, ...(ngDevMode ? [{ debugName: "filteredOptionsMap" }] : []));
312
+ /**
313
+ * 当前选中的值
314
+ */
315
+ this.selectedValues = linkedSignal(...(ngDevMode ? [{ debugName: "selectedValues", source: () => this.thyMode(),
316
+ computation: () => {
317
+ return [];
318
+ } }] : [{
319
+ source: () => this.thyMode(),
320
+ computation: () => {
321
+ return [];
322
+ }
323
+ }]));
324
+ this.selectedValuesMap = computed(() => {
325
+ return new Map(this.selectedValues().map(value => [value, true]));
326
+ }, ...(ngDevMode ? [{ debugName: "selectedValuesMap" }] : []));
327
+ /**
328
+ * 传给 selectControl 指令的选中值
272
329
  */
273
- this.contentGroups = contentChildren(ThySelectOptionGroup, ...(ngDevMode ? [{ debugName: "contentGroups" }] : []));
274
- this.viewGroups = viewChildren(ThySelectOptionGroup, ...(ngDevMode ? [{ debugName: "viewGroups" }] : []));
275
- this.isSearching = false;
276
- this.groupBy = (item) => item.groupLabel;
330
+ this.selectedOptions = linkedSignal(...(ngDevMode ? [{ debugName: "selectedOptions", source: () => this.thyMode(),
331
+ computation: () => {
332
+ return this.thyMode() === 'multiple' ? [] : null;
333
+ } }] : [{
334
+ source: () => this.thyMode(),
335
+ computation: () => {
336
+ return this.thyMode() === 'multiple' ? [] : null;
337
+ }
338
+ }]));
339
+ this.isMultiple = computed(() => {
340
+ return this.thyMode() === 'multiple';
341
+ }, ...(ngDevMode ? [{ debugName: "isMultiple" }] : []));
342
+ this.empty = computed(() => {
343
+ return !this.selectedValues().length;
344
+ }, ...(ngDevMode ? [{ debugName: "empty" }] : []));
345
+ this.activatedValue = signal(null, ...(ngDevMode ? [{ debugName: "activatedValue" }] : []));
277
346
  const selectConfig = this.selectConfig;
278
347
  this.config = { ...DEFAULT_SELECT_CONFIG, ...selectConfig };
279
348
  this.buildScrollStrategy();
280
- effect(() => {
281
- this.mode = this.thyMode();
349
+ afterRenderEffect(() => {
350
+ const options = this.options();
351
+ const groups = this.groups();
352
+ const reactiveOptions = this.thyOptions();
282
353
  untracked(() => {
283
- this.instanceSelectionModel();
284
- this.getPositions();
285
- this.setDropDownClass();
354
+ this.buildAllGroupsAndOptions();
286
355
  });
287
356
  });
357
+ afterRenderEffect(() => {
358
+ this.updateSelectedOptions();
359
+ });
288
360
  }
289
361
  writeValue(value) {
290
- this.modalValue = value;
291
- this.setSelectionByModelValue(this.modalValue);
362
+ let selectedValues;
363
+ if (helpers.isUndefinedOrNull(value)) {
364
+ selectedValues = [];
365
+ }
366
+ else if (this.isMultiple()) {
367
+ selectedValues = value;
368
+ }
369
+ else {
370
+ selectedValues = [value];
371
+ }
372
+ this.selectedValues.set(selectedValues);
292
373
  }
293
374
  ngOnInit() {
294
- this.getPositions();
295
- this.dropDownMinWidth = this.getDropdownMinWidth();
296
- if (!this.selectionModel) {
297
- this.instanceSelectionModel();
298
- }
299
- this.setDropDownClass();
300
375
  if (isPlatformBrowser(this.platformId)) {
301
376
  this.thyClickDispatcher
302
377
  .clicked(0)
303
- .pipe(takeUntil(this.destroy$))
378
+ .pipe(takeUntilDestroyed(this.destroyRef))
304
379
  .subscribe(event => {
305
380
  if (!this.elementRef.nativeElement.contains(event.target) && this.panelOpen) {
306
381
  this.ngZone.run(() => {
@@ -311,74 +386,16 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
311
386
  });
312
387
  }
313
388
  }
314
- buildOptionGroups(options) {
315
- const optionGroups = [];
316
- const groups = [...new Set(options.filter(item => this.groupBy(item)).map(sub => this.groupBy(sub)))];
317
- const groupMap = new Map();
318
- groups.forEach(group => {
319
- const children = options.filter(item => this.groupBy(item) === group);
320
- const groupOption = {
321
- groupLabel: group,
322
- children: children
323
- };
324
- groupMap.set(group, groupOption);
325
- });
326
- options.forEach(option => {
327
- if (this.groupBy(option)) {
328
- const currentIndex = optionGroups.findIndex(item => item.groupLabel === this.groupBy(option));
329
- if (currentIndex === -1) {
330
- const item = groupMap.get(this.groupBy(option));
331
- optionGroups.push(item);
332
- }
333
- }
334
- else {
335
- optionGroups.push(option);
336
- }
337
- });
338
- return optionGroups;
339
- }
340
- buildReactiveOptions() {
341
- if (this.innerOptions.filter(item => this.groupBy(item)).length > 0) {
342
- this.optionGroups = this.buildOptionGroups(this.innerOptions);
343
- }
344
- else {
345
- this.optionGroups = this.innerOptions;
346
- }
347
- }
348
- getDropdownMinWidth() {
349
- const mode = this.thyDropdownWidthMode() || this.config.dropdownWidthMode;
350
- let dropdownMinWidth = null;
351
- if (mode?.minWidth) {
352
- dropdownMinWidth = mode.minWidth;
353
- }
354
- else if (mode === 'min-width') {
355
- dropdownMinWidth = THY_SELECT_PANEL_MIN_WIDTH;
356
- }
357
- else {
358
- dropdownMinWidth = null;
359
- }
360
- return dropdownMinWidth;
361
- }
362
389
  ngAfterViewInit() {
363
- if (this.isReactiveDriven) {
364
- this.setup();
365
- }
366
- }
367
- ngAfterContentInit() {
368
- if (!this.isReactiveDriven) {
369
- this.setup();
370
- }
390
+ this.setup();
371
391
  }
372
392
  setup() {
373
- this.optionsChanges$.pipe(startWith(null), takeUntil(this.destroy$)).subscribe(data => {
374
- this.resetOptions();
375
- this.initializeSelection();
376
- this.initKeyManager();
377
- if (this.isSearching) {
378
- this.highlightCorrectOption(false);
379
- this.isSearching = false;
393
+ this.optionsChanges$.pipe(startWith(null), takeUntilDestroyed(this.destroyRef)).subscribe(() => {
394
+ // Don't scroll to default highlighted option when scroll load more options
395
+ if (this.shouldActivateOption) {
396
+ this.shouldActivateOption = false;
397
+ this.scrollToActivatedOption();
380
398
  }
381
- this.changeDetectorRef.markForCheck();
382
399
  this.ngZone.onStable
383
400
  .asObservable()
384
401
  .pipe(take(1))
@@ -396,57 +413,185 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
396
413
  });
397
414
  }
398
415
  }
399
- get isHiddenOptions() {
400
- return this.options.toArray().every(option => option.hidden());
416
+ buildAllGroupsAndOptions() {
417
+ let allGroupsAndOptions;
418
+ const isReactiveDriven = this.thyOptions()?.length > 0;
419
+ if (isReactiveDriven) {
420
+ allGroupsAndOptions = this.allGroupsAndOptionsByReactive();
421
+ }
422
+ else {
423
+ allGroupsAndOptions = this.allGroupsAndOptionsByTemplate();
424
+ }
425
+ this.allGroupsAndOptions.set(allGroupsAndOptions);
401
426
  }
402
- onAttached() {
403
- this.cdkConnectedOverlay()
404
- .positionChange.pipe(take(1))
405
- .subscribe(() => {
406
- if (this.panel()) {
407
- if (this.keyManager.activeItem) {
408
- ScrollToService.scrollToElement(this.keyManager.activeItem.element.nativeElement, this.panel().nativeElement);
409
- this.changeDetectorRef.detectChanges();
427
+ allGroupsAndOptionsByReactive() {
428
+ const options = this.thyOptions();
429
+ const groupMap = new Map();
430
+ const ungroupedOptions = [];
431
+ let groupsAndOptions = [];
432
+ for (const option of options) {
433
+ if (option.groupLabel) {
434
+ if (!groupMap.has(option.groupLabel)) {
435
+ groupMap.set(option.groupLabel, []);
410
436
  }
411
- else {
412
- if (!this.empty) {
413
- ScrollToService.scrollToElement(this.selectionModel.selected[0].element.nativeElement, this.panel().nativeElement);
414
- this.changeDetectorRef.detectChanges();
437
+ groupMap.get(option.groupLabel).push(option);
438
+ }
439
+ else {
440
+ ungroupedOptions.push(option);
441
+ }
442
+ }
443
+ for (const [groupLabel, groupOptions] of groupMap) {
444
+ groupsAndOptions.push({
445
+ type: 'group',
446
+ label: groupLabel
447
+ });
448
+ for (const option of groupOptions) {
449
+ groupsAndOptions.push({
450
+ type: 'option',
451
+ value: option.value,
452
+ label: option.label,
453
+ rawValue: option,
454
+ showOptionCustom: false,
455
+ disabled: !!option.disabled,
456
+ groupLabel: option.groupLabel
457
+ });
458
+ }
459
+ }
460
+ for (const option of ungroupedOptions) {
461
+ groupsAndOptions.push({
462
+ type: 'option',
463
+ value: option.value,
464
+ label: option.label,
465
+ rawValue: option,
466
+ showOptionCustom: false,
467
+ disabled: !!option.disabled
468
+ });
469
+ }
470
+ return groupsAndOptions;
471
+ }
472
+ allGroupsAndOptionsByTemplate() {
473
+ const options = this.options();
474
+ const groups = this.groups();
475
+ let groupsAndOptions = [];
476
+ if (options && options.length > 0) {
477
+ groupsAndOptions = options.map((option) => {
478
+ const { thyValue, thyRawValue, thyLabelText, thyShowOptionCustom, thyDisabled, template, thySearchKey, groupLabel } = option;
479
+ return {
480
+ type: 'option',
481
+ value: thyValue(),
482
+ rawValue: thyRawValue(),
483
+ label: thyLabelText(),
484
+ showOptionCustom: thyShowOptionCustom(),
485
+ disabled: thyDisabled(),
486
+ template: template(),
487
+ searchKey: thySearchKey(),
488
+ groupLabel: groupLabel
489
+ };
490
+ });
491
+ }
492
+ if (groups && groups.length > 0) {
493
+ for (const group of groups) {
494
+ const groupIndex = groupsAndOptions.findIndex(option => option.groupLabel === group.thyGroupLabel());
495
+ if (groupIndex > -1) {
496
+ const groupItem = {
497
+ type: 'group',
498
+ label: group.thyGroupLabel(),
499
+ disabled: group.thyDisabled()
500
+ };
501
+ groupsAndOptions.splice(groupIndex, 0, groupItem);
502
+ }
503
+ }
504
+ }
505
+ return groupsAndOptions;
506
+ }
507
+ buildFilteredGroupsAndOptions() {
508
+ const keywords = this.keywords();
509
+ const isServerSearch = this.thyServerSearch();
510
+ const allGroupsAndOptions = this.allGroupsAndOptions();
511
+ let filteredGroupsAndOptions = [];
512
+ if (keywords && !isServerSearch) {
513
+ const lowerKeywords = keywords.toLowerCase();
514
+ const matchedOptions = new Set();
515
+ const matchedGroupLabels = new Set();
516
+ for (const item of allGroupsAndOptions) {
517
+ if (item.type === 'option') {
518
+ const isMatch = (item.searchKey || item.label).toLowerCase().indexOf(lowerKeywords) > -1;
519
+ if (isMatch) {
520
+ matchedOptions.add(item.value);
521
+ if (item.groupLabel) {
522
+ matchedGroupLabels.add(item.groupLabel);
523
+ }
415
524
  }
416
525
  }
417
526
  }
418
- });
527
+ for (const item of allGroupsAndOptions) {
528
+ if (item.type === 'group' && matchedGroupLabels.has(item.label)) {
529
+ filteredGroupsAndOptions.push(item);
530
+ }
531
+ else if (item.type === 'option' && matchedOptions.has(item.value)) {
532
+ filteredGroupsAndOptions.push(item);
533
+ }
534
+ }
535
+ return filteredGroupsAndOptions;
536
+ }
537
+ return allGroupsAndOptions;
419
538
  }
420
- dropDownMouseMove(event) {
421
- if (this.keyManager.activeItem) {
422
- this.keyManager.setActiveItem(-1);
539
+ updateSelectedOptions() {
540
+ const selectedValues = this.selectedValues();
541
+ const isMultiple = untracked(() => this.isMultiple());
542
+ let newOptions = [];
543
+ if (selectedValues.length) {
544
+ const filteredOptionsMap = this.filteredOptionsMap();
545
+ const oldSelectedOptionsMap = untracked(() => {
546
+ const selected = this.selectedOptions();
547
+ let oldSelectedOptions;
548
+ if (helpers.isArray(selected)) {
549
+ oldSelectedOptions = selected;
550
+ }
551
+ else if (selected) {
552
+ oldSelectedOptions = [selected];
553
+ }
554
+ else {
555
+ oldSelectedOptions = [];
556
+ }
557
+ return helpers.keyBy(oldSelectedOptions, 'thyValue');
558
+ });
559
+ selectedValues.forEach(value => {
560
+ let option = filteredOptionsMap[value];
561
+ if (option) {
562
+ newOptions.push({
563
+ thyLabelText: option.label,
564
+ thyValue: option.value,
565
+ thyRawValue: option.rawValue
566
+ });
567
+ }
568
+ else if (oldSelectedOptionsMap[value]) {
569
+ newOptions.push(oldSelectedOptionsMap[value]);
570
+ }
571
+ });
572
+ this.selectedOptions.set(isMultiple ? newOptions : newOptions.length ? newOptions[0] : null);
573
+ }
574
+ else {
575
+ this.selectedOptions.set(isMultiple ? [] : null);
423
576
  }
424
577
  }
425
- onOptionsScrolled(elementRef) {
426
- const scroll = elementRef.nativeElement.scrollTop, height = elementRef.nativeElement.clientHeight, scrollHeight = elementRef.nativeElement.scrollHeight;
427
- if (scroll + height + 10 >= scrollHeight) {
428
- this.ngZone.run(() => {
578
+ optionsScrolled(index) {
579
+ this.scrolledIndex = index;
580
+ if (this.thyEnableScrollLoad()) {
581
+ const isScrollToBottom = index + this.maxItemLength >= this.filteredGroupsAndOptions().length;
582
+ if (isScrollToBottom) {
429
583
  this.thyOnScrollToBottom.emit();
430
- });
584
+ }
431
585
  }
432
586
  }
433
- onSearchFilter(searchText) {
434
- searchText = searchText.trim();
587
+ search(keywords) {
588
+ this.shouldActivateOption = true;
589
+ this.activatedValue.set(null);
590
+ this.keywords.set(keywords.trim());
435
591
  if (this.thyServerSearch()) {
436
- this.isSearching = true;
437
- this.thyOnSearch.emit(searchText);
592
+ this.thyOnSearch.emit(keywords);
438
593
  }
439
594
  else {
440
- const options = this.options.toArray();
441
- options.forEach(option => {
442
- if (option.matchSearchText(searchText)) {
443
- option.showOption();
444
- }
445
- else {
446
- option.hideOption();
447
- }
448
- });
449
- this.highlightCorrectOption(false);
450
595
  this.updateCdkConnectedOverlayPositions();
451
596
  }
452
597
  }
@@ -478,14 +623,12 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
478
623
  if (this.disabled) {
479
624
  return;
480
625
  }
481
- if (!this.options.find(option => option === $event.item)) {
482
- $event.item.deselect();
483
- // fix option unselect can not emit changes;
484
- this.onSelect($event.item, true);
485
- }
486
- else {
487
- $event.item.deselect();
626
+ const selectedValue = this.selectedValues();
627
+ const index = selectedValue.indexOf($event.item.thyValue);
628
+ if (index > -1) {
629
+ this.selectedValues.set([...selectedValue.slice(0, index), ...selectedValue.slice(index + 1)]);
488
630
  }
631
+ this.emitModelValueChange();
489
632
  }
490
633
  clearSelectValue(event) {
491
634
  if (event) {
@@ -494,8 +637,7 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
494
637
  if (this.disabled) {
495
638
  return;
496
639
  }
497
- this.selectionModel.clear();
498
- this.changeDetectorRef.markForCheck();
640
+ this.selectedValues.set([]);
499
641
  this.emitModelValueChange();
500
642
  }
501
643
  updateCdkConnectedOverlayPositions() {
@@ -505,19 +647,6 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
505
647
  }
506
648
  });
507
649
  }
508
- get selected() {
509
- return this.isMultiple ? this.selectionModel.selected : this.selectionModel.selected[0];
510
- }
511
- get isMultiple() {
512
- return this.mode === 'multiple';
513
- }
514
- get empty() {
515
- return !this.selectionModel || this.selectionModel.isEmpty();
516
- }
517
- getItemCount() {
518
- const group = this.isReactiveDriven ? this.viewGroups() : this.contentGroups();
519
- return this.options.length + group.length;
520
- }
521
650
  toggle(event) {
522
651
  if (this.panelOpen) {
523
652
  if (!this.thyShowSearch()) {
@@ -529,19 +658,20 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
529
658
  }
530
659
  }
531
660
  open() {
532
- if (this.disabled || !this.options || this.panelOpen) {
661
+ if (this.disabled || this.panelOpen) {
533
662
  return;
534
663
  }
535
- this.triggerRectWidth = this.getOriginRectWidth();
664
+ this.triggerRectWidth.set(this.getOriginRectWidth());
536
665
  this.subscribeTriggerResize();
537
666
  this.panelOpen = true;
538
- this.highlightCorrectOption();
667
+ this.shouldActivateOption = true;
539
668
  this.thyOnExpandStatusChange.emit(this.panelOpen);
540
669
  this.changeDetectorRef.markForCheck();
541
670
  }
542
671
  close() {
543
672
  if (this.panelOpen) {
544
673
  this.panelOpen = false;
674
+ this.scrolledIndex = 0;
545
675
  this.unsubscribeTriggerResize();
546
676
  this.thyOnExpandStatusChange.emit(this.panelOpen);
547
677
  this.changeDetectorRef.markForCheck();
@@ -549,252 +679,190 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
549
679
  }
550
680
  }
551
681
  emitModelValueChange() {
552
- const selectedValues = this.selectionModel.selected;
553
- const changeValue = selectedValues.map((option) => {
554
- return option.thyValue;
555
- });
556
- if (this.isMultiple) {
557
- this.modalValue = changeValue;
682
+ let modelValue;
683
+ const selectedValues = this.selectedValues();
684
+ if (this.isMultiple()) {
685
+ modelValue = selectedValues;
558
686
  }
559
687
  else {
560
- if (changeValue.length === 0) {
561
- this.modalValue = null;
688
+ if (selectedValues.length === 0) {
689
+ modelValue = null;
562
690
  }
563
691
  else {
564
- this.modalValue = changeValue[0];
692
+ modelValue = selectedValues[0];
565
693
  }
566
694
  }
567
- this.onChangeFn(this.modalValue);
695
+ this.onChangeFn(modelValue);
568
696
  this.updateCdkConnectedOverlayPositions();
569
697
  }
570
- highlightCorrectOption(fromOpenPanel = true) {
571
- if (this.keyManager && this.panelOpen) {
572
- if (fromOpenPanel) {
573
- if (this.keyManager.activeItem) {
574
- return;
575
- }
576
- if (this.empty) {
577
- if (!this.thyAutoActiveFirstItem()) {
578
- return;
579
- }
580
- this.keyManager.setFirstItemActive();
581
- }
582
- else {
583
- this.keyManager.setActiveItem(this.selectionModel.selected[0]);
584
- }
698
+ scrollToActivatedOption(needSelect = false) {
699
+ if (!this.panelOpen) {
700
+ return;
701
+ }
702
+ const filteredOptions = this.filteredOptions();
703
+ if (!filteredOptions.length) {
704
+ return;
705
+ }
706
+ let toActivatedValue = this.activatedValue();
707
+ if (!toActivatedValue || !this.filteredOptionsMap()[toActivatedValue]) {
708
+ if (this.selectedValues().length > 0) {
709
+ toActivatedValue = this.selectedValues()[0];
585
710
  }
586
711
  else {
587
- if (!this.thyAutoActiveFirstItem()) {
588
- return;
712
+ if (this.thyAutoActiveFirstItem()) {
713
+ toActivatedValue = filteredOptions[0].value || null;
589
714
  }
590
- // always set first option active
591
- this.keyManager.setFirstItemActive();
592
715
  }
716
+ if (!toActivatedValue) {
717
+ return;
718
+ }
719
+ this.activatedValue.set(toActivatedValue);
593
720
  }
594
- }
595
- initKeyManager() {
596
- if (this.keyManager && this.keyManager.activeItem) {
597
- this.keyManager.activeItem.setInactiveStyles();
721
+ const targetIndex = this.filteredGroupsAndOptions().findIndex(item => item.value === toActivatedValue);
722
+ if (targetIndex === -1) {
723
+ return;
598
724
  }
599
- this.keyManager = new ActiveDescendantKeyManager(this.options)
600
- .withTypeAhead()
601
- .withWrap()
602
- .withVerticalOrientation()
603
- .withAllowedModifierKeys(['shiftKey']);
604
- this.keyManager.tabOut.pipe(takeUntil(this.destroy$)).subscribe(() => {
605
- this.focus();
606
- this.close();
607
- });
608
- this.keyManager.change.pipe(takeUntil(this.destroy$)).subscribe(() => {
609
- if (this.panelOpen && this.panel()) {
610
- if (this.keyManager.activeItem) {
611
- ScrollToService.scrollToElement(this.keyManager.activeItem.element.nativeElement, this.panel().nativeElement);
612
- }
613
- }
614
- else if (!this.panelOpen && !this.isMultiple && this.keyManager.activeItem) {
615
- this.keyManager.activeItem.selectViaInteraction();
616
- }
617
- });
618
- }
619
- handleClosedKeydown(event) {
620
- const keyCode = event.keyCode;
621
- const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW || keyCode === LEFT_ARROW || keyCode === RIGHT_ARROW;
622
- const isOpenKey = keyCode === ENTER || keyCode === SPACE;
623
- const manager = this.keyManager;
624
- // Open the select on ALT + arrow key to match the native <select>
625
- if ((isOpenKey && !hasModifierKey(event)) || ((this.isMultiple || event.altKey) && isArrowKey)) {
626
- event.preventDefault(); // prevents the page from scrolling down when pressing space
627
- this.open();
725
+ if (targetIndex < this.scrolledIndex || targetIndex >= this.scrolledIndex + this.maxItemLength) {
726
+ this.cdkVirtualScrollViewport()?.scrollToIndex(targetIndex || 0);
628
727
  }
629
- else if (!this.isMultiple) {
630
- if (keyCode === HOME || keyCode === END) {
631
- keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
632
- event.preventDefault();
633
- }
634
- else {
635
- manager.onKeydown(event);
636
- }
728
+ if (needSelect) {
729
+ this.optionRenders.find(option => option.thyValue() === toActivatedValue)?.selectViaInteraction();
637
730
  }
638
731
  }
639
- handleOpenKeydown(event) {
732
+ handleKeydown(event) {
640
733
  const keyCode = event.keyCode;
734
+ const isOpenKey = keyCode === ENTER || keyCode === SPACE;
641
735
  const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW;
642
- const manager = this.keyManager;
643
- if (keyCode === HOME || keyCode === END) {
644
- event.preventDefault();
645
- keyCode === HOME ? manager.setFirstItemActive() : manager.setLastItemActive();
736
+ if (event.altKey) {
737
+ if (this.panelOpen && isArrowKey) {
738
+ event.preventDefault();
739
+ this.close();
740
+ return;
741
+ }
646
742
  }
647
- else if (isArrowKey && event.altKey) {
648
- // Close the select on ALT + arrow key to match the native <select>
649
- event.preventDefault();
650
- this.close();
743
+ if (!this.panelOpen) {
744
+ this.open();
745
+ if (isOpenKey) {
746
+ event.preventDefault();
747
+ return;
748
+ }
651
749
  }
652
- else if ((keyCode === ENTER || keyCode === SPACE) && (manager.activeItem || !this.empty) && !hasModifierKey(event)) {
750
+ const filteredOptions = this.filteredOptions();
751
+ if (keyCode === DOWN_ARROW || keyCode === UP_ARROW) {
653
752
  event.preventDefault();
654
- if (!manager.activeItem) {
655
- if (manager.activeItemIndex === -1 && !this.empty) {
656
- manager.setActiveItem(this.selectionModel.selected[0]);
753
+ const activatedValue = this.activatedValue();
754
+ const currentOption = this.filteredOptionsMap()[activatedValue];
755
+ if (!currentOption) {
756
+ return;
757
+ }
758
+ const currentIndex = filteredOptions.indexOf(currentOption);
759
+ let targetIndex;
760
+ if (keyCode === DOWN_ARROW) {
761
+ targetIndex = currentIndex + 1;
762
+ if (targetIndex > filteredOptions.length - 1) {
763
+ targetIndex = 0;
764
+ }
765
+ let attempts = 0;
766
+ while (filteredOptions[targetIndex]?.disabled && attempts < filteredOptions.length) {
767
+ targetIndex++;
768
+ if (targetIndex > filteredOptions.length - 1) {
769
+ targetIndex = 0;
770
+ }
771
+ attempts++;
657
772
  }
658
773
  }
659
- manager.activeItem.selectViaInteraction();
660
- }
661
- else if (this.isMultiple && keyCode === A && event.ctrlKey) {
662
- event.preventDefault();
663
- const hasDeselectedOptions = this.options.some(opt => !opt.disabled && !opt.selected());
664
- this.options.forEach(option => {
665
- if (!option.disabled) {
666
- hasDeselectedOptions ? option.select() : option.deselect();
774
+ else {
775
+ targetIndex = currentIndex - 1;
776
+ if (targetIndex < 0) {
777
+ targetIndex = filteredOptions.length - 1;
667
778
  }
668
- });
669
- }
670
- else {
671
- if (manager.activeItemIndex === -1 && !this.empty) {
672
- manager.setActiveItem(this.selectionModel.selected[0]);
779
+ let attempts = 0;
780
+ while (filteredOptions[targetIndex]?.disabled && attempts < filteredOptions.length) {
781
+ targetIndex--;
782
+ if (targetIndex < 0) {
783
+ targetIndex = filteredOptions.length - 1;
784
+ }
785
+ attempts++;
786
+ }
787
+ }
788
+ const targetOption = filteredOptions[targetIndex];
789
+ if (targetOption?.disabled) {
790
+ return;
791
+ }
792
+ this.activatedValue.set(targetOption.value);
793
+ if (!hasModifierKey(event)) {
794
+ this.scrollToActivatedOption();
673
795
  }
674
- const previouslyFocusedIndex = manager.activeItemIndex;
675
- manager.onKeydown(event);
676
- if (this.isMultiple &&
677
- isArrowKey &&
678
- event.shiftKey &&
679
- manager.activeItem &&
680
- manager.activeItemIndex !== previouslyFocusedIndex) {
681
- manager.activeItem.selectViaInteraction();
796
+ else if (this.isMultiple() && event.shiftKey) {
797
+ this.scrollToActivatedOption(true);
682
798
  }
683
799
  }
684
- }
685
- getPositions() {
686
- this.dropDownPositions = getFlexiblePositions(this.thyPlacement() || this.config.placement, this.defaultOffset);
687
- }
688
- instanceSelectionModel() {
689
- if (this.selectionModel) {
690
- this.selectionModel.clear();
800
+ else if (keyCode === HOME || keyCode === END) {
801
+ event.preventDefault();
802
+ const targetOption = keyCode === HOME ? filteredOptions[0] : filteredOptions[filteredOptions.length - 1];
803
+ this.activatedValue.set(targetOption.value);
804
+ this.scrollToActivatedOption();
691
805
  }
692
- this.selectionModel = new SelectionModel(this.isMultiple);
693
- if (this.selectionModelSubscription) {
694
- this.selectionModelSubscription.unsubscribe();
695
- this.selectionModelSubscription = null;
806
+ else if ((keyCode === ENTER || keyCode === SPACE) && (this.activatedValue() || !this.empty()) && !hasModifierKey(event)) {
807
+ event.preventDefault();
808
+ this.scrollToActivatedOption(true);
696
809
  }
697
- this.selectionModelSubscription = this.selectionModel.changed.pipe(takeUntil(this.destroy$)).subscribe(event => {
698
- event.added.forEach(option => option.select());
699
- event.removed.forEach(option => option.deselect());
700
- });
701
- }
702
- resetOptions() {
703
- const changedOrDestroyed$ = merge(this.optionsChanges$, this.destroy$);
704
- this.optionSelectionChanges.pipe(takeUntil(changedOrDestroyed$)).subscribe((event) => {
705
- this.onSelect(event.option, event.isUserInput);
706
- if (event.isUserInput && !this.isMultiple && this.panelOpen) {
707
- this.close();
708
- this.focus();
810
+ else if (this.isMultiple() && keyCode === A && event.ctrlKey) {
811
+ event.preventDefault();
812
+ const hasDeselectedOptions = filteredOptions.some(opt => !opt.disabled && !this.selectedValues().includes(opt.value));
813
+ let selectedValues = [];
814
+ if (hasDeselectedOptions) {
815
+ selectedValues = filteredOptions.filter(option => !option.disabled).map(option => option.value);
709
816
  }
710
- });
711
- }
712
- initializeSelection() {
713
- Promise.resolve().then(() => {
714
- this.setSelectionByModelValue(this.modalValue);
715
- });
716
- }
717
- setDropDownClass() {
718
- let modeClass = '';
719
- if (this.isMultiple) {
720
- modeClass = `thy-select-dropdown-${this.mode}`;
817
+ this.selectedValues.set(selectedValues);
818
+ this.emitModelValueChange();
721
819
  }
722
- else {
723
- modeClass = `thy-select-dropdown-single`;
820
+ else if (keyCode === TAB) {
821
+ this.focus();
822
+ this.close();
724
823
  }
725
- this.dropDownClass = {
726
- [`thy-select-dropdown`]: true,
727
- [modeClass]: true
728
- };
729
824
  }
730
- setSelectionByModelValue(modalValue) {
731
- if (helpers.isUndefinedOrNull(modalValue)) {
732
- if (this.selectionModel.selected.length > 0) {
733
- this.selectionModel.clear();
734
- this.changeDetectorRef.markForCheck();
825
+ optionClick(event) {
826
+ const { value, isUserInput } = event;
827
+ const options = this.options();
828
+ if (this.isMultiple()) {
829
+ const selectedValues = this.selectedValues() || [];
830
+ const index = selectedValues.indexOf(value);
831
+ if (index > -1) {
832
+ selectedValues.splice(index, 1);
735
833
  }
736
- return;
737
- }
738
- if (this.isMultiple) {
739
- if (isArray(modalValue)) {
740
- const selected = [...this.selectionModel.selected];
741
- this.selectionModel.clear();
742
- modalValue.forEach(itemValue => {
743
- const option = this.options.find(_option => _option.thyValue === itemValue) ||
744
- selected.find(_option => _option.thyValue === itemValue);
745
- if (option) {
746
- this.selectionModel.select(option);
747
- }
748
- });
834
+ else {
835
+ selectedValues.push(value);
749
836
  }
750
- }
751
- else {
752
- const selectedOption = this.options?.find(option => {
753
- return option.thyValue === modalValue;
754
- });
755
- if (selectedOption) {
756
- this.selectionModel.select(selectedOption);
837
+ if (this.thySortComparator()) {
838
+ selectedValues.sort((a, b) => {
839
+ const aOption = options.find(option => option.thyValue() === a);
840
+ const bOption = options.find(option => option.thyValue() === b);
841
+ return this.thySortComparator()(aOption, bOption, [...options]);
842
+ });
757
843
  }
758
- }
759
- this.changeDetectorRef.markForCheck();
760
- }
761
- onSelect(option, isUserInput) {
762
- const wasSelected = this.selectionModel.isSelected(option);
763
- if (option.thyValue == null && !this.isMultiple) {
764
- option.deselect();
765
- this.selectionModel.clear();
844
+ this.selectedValues.set([...selectedValues]);
766
845
  }
767
846
  else {
768
- if (wasSelected !== option.selected()) {
769
- option.selected() ? this.selectionModel.select(option) : this.selectionModel.deselect(option);
770
- }
771
- if (isUserInput) {
772
- this.keyManager.setActiveItem(option);
773
- }
774
- if (this.isMultiple) {
775
- this.sortValues();
776
- if (isUserInput) {
777
- this.focus();
778
- }
779
- }
847
+ this.selectedValues.set([value]);
848
+ this.close();
780
849
  }
781
- if (wasSelected !== this.selectionModel.isSelected(option)) {
782
- this.emitModelValueChange();
850
+ const option = options.find(option => option.thyValue() === value);
851
+ if (option) {
852
+ const selected = this.selectedValues().includes(value);
853
+ option.selected.set(selected);
854
+ option.selectionChange.emit({ option, isUserInput });
783
855
  }
784
- if (!this.isMultiple) {
856
+ this.emitModelValueChange();
857
+ if (!this.isMultiple()) {
785
858
  this.onTouchedFn();
786
859
  }
787
- this.changeDetectorRef.markForCheck();
788
860
  }
789
- sortValues() {
790
- if (this.isMultiple) {
791
- const options = this.options.toArray();
792
- if (this.thySortComparator()) {
793
- this.selectionModel.sort((a, b) => {
794
- return this.thySortComparator()(a, b, options);
795
- });
796
- }
797
- }
861
+ optionHover(value) {
862
+ this.activatedValue.set(value);
863
+ }
864
+ mouseLeaveOptions() {
865
+ this.activatedValue.set(null);
798
866
  }
799
867
  getOriginRectWidth() {
800
868
  return this.thyOrigin() ? coerceElement(this.thyOrigin()).offsetWidth : this.trigger.nativeElement.offsetWidth;
@@ -813,7 +881,7 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
813
881
  }), distinctUntilChanged())
814
882
  .subscribe((width) => {
815
883
  this.ngZone.run(() => {
816
- this.triggerRectWidth = width;
884
+ this.triggerRectWidth.set(width);
817
885
  this.updateCdkConnectedOverlayPositions();
818
886
  this.changeDetectorRef.markForCheck();
819
887
  });
@@ -826,31 +894,29 @@ class ThySelect extends TabIndexDisabledControlValueAccessorMixin {
826
894
  this.resizeSubscription = null;
827
895
  }
828
896
  }
897
+ trackByFn(index, item) {
898
+ if (item.type === 'group') {
899
+ return item.label || index;
900
+ }
901
+ if (item.type === 'option') {
902
+ return item.value || index;
903
+ }
904
+ }
829
905
  ngOnDestroy() {
830
906
  this.unsubscribeTriggerResize();
831
- this.destroy$.next();
832
- this.destroy$.complete();
833
907
  }
834
908
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ThySelect, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
835
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: ThySelect, isStandalone: true, selector: "thy-select,thy-custom-select", inputs: { thyDropdownWidthMode: { classPropertyName: "thyDropdownWidthMode", publicName: "thyDropdownWidthMode", isSignal: true, isRequired: false, transformFunction: null }, thyShowSearch: { classPropertyName: "thyShowSearch", publicName: "thyShowSearch", isSignal: true, isRequired: false, transformFunction: null }, thyPlaceHolder: { classPropertyName: "thyPlaceHolder", publicName: "thyPlaceHolder", isSignal: true, isRequired: false, transformFunction: null }, thyServerSearch: { classPropertyName: "thyServerSearch", publicName: "thyServerSearch", isSignal: true, isRequired: false, transformFunction: null }, thyLoadState: { classPropertyName: "thyLoadState", publicName: "thyLoadState", isSignal: true, isRequired: false, transformFunction: null }, thyAutoActiveFirstItem: { classPropertyName: "thyAutoActiveFirstItem", publicName: "thyAutoActiveFirstItem", isSignal: true, isRequired: false, transformFunction: null }, thyMode: { classPropertyName: "thyMode", publicName: "thyMode", isSignal: true, isRequired: false, transformFunction: null }, thySize: { classPropertyName: "thySize", publicName: "thySize", isSignal: true, isRequired: false, transformFunction: null }, thyEmptyStateText: { classPropertyName: "thyEmptyStateText", publicName: "thyEmptyStateText", isSignal: true, isRequired: false, transformFunction: null }, thyEmptySearchMessageText: { classPropertyName: "thyEmptySearchMessageText", publicName: "thyEmptySearchMessageText", isSignal: true, isRequired: false, transformFunction: null }, thyEnableScrollLoad: { classPropertyName: "thyEnableScrollLoad", publicName: "thyEnableScrollLoad", isSignal: true, isRequired: false, transformFunction: null }, thyAllowClear: { classPropertyName: "thyAllowClear", publicName: "thyAllowClear", isSignal: true, isRequired: false, transformFunction: null }, thyDisabled: { classPropertyName: "thyDisabled", publicName: "thyDisabled", isSignal: false, isRequired: false, transformFunction: coerceBooleanProperty }, thySortComparator: { classPropertyName: "thySortComparator", publicName: "thySortComparator", isSignal: true, isRequired: false, transformFunction: null }, thyFooterTemplate: { classPropertyName: "thyFooterTemplate", publicName: "thyFooterTemplate", isSignal: true, isRequired: false, transformFunction: null }, thyPlacement: { classPropertyName: "thyPlacement", publicName: "thyPlacement", isSignal: true, isRequired: false, transformFunction: null }, thyOrigin: { classPropertyName: "thyOrigin", publicName: "thyOrigin", isSignal: true, isRequired: false, transformFunction: null }, thyFooterClass: { classPropertyName: "thyFooterClass", publicName: "thyFooterClass", isSignal: true, isRequired: false, transformFunction: null }, thyAutoExpand: { classPropertyName: "thyAutoExpand", publicName: "thyAutoExpand", isSignal: true, isRequired: false, transformFunction: null }, thyHasBackdrop: { classPropertyName: "thyHasBackdrop", publicName: "thyHasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, thyMaxTagCount: { classPropertyName: "thyMaxTagCount", publicName: "thyMaxTagCount", isSignal: true, isRequired: false, transformFunction: null }, thyBorderless: { classPropertyName: "thyBorderless", publicName: "thyBorderless", isSignal: true, isRequired: false, transformFunction: null }, thyOptions: { classPropertyName: "thyOptions", publicName: "thyOptions", isSignal: true, isRequired: false, transformFunction: null }, thyPreset: { classPropertyName: "thyPreset", publicName: "thyPreset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { thyOnSearch: "thyOnSearch", thyOnScrollToBottom: "thyOnScrollToBottom", thyOnExpandStatusChange: "thyOnExpandStatusChange" }, host: { listeners: { "focus": "onFocus($event)", "blur": "onBlur($event)", "keydown": "handleKeydown($event)" }, properties: { "class.thy-select-custom": "true", "class.thy-select": "true", "class.menu-is-opened": "panelOpen", "attr.tabindex": "tabIndex" } }, providers: [
836
- {
837
- provide: THY_OPTION_PARENT_COMPONENT,
838
- useExisting: ThySelect
839
- },
909
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: ThySelect, isStandalone: true, selector: "thy-select,thy-custom-select", inputs: { thyDropdownWidthMode: { classPropertyName: "thyDropdownWidthMode", publicName: "thyDropdownWidthMode", isSignal: true, isRequired: false, transformFunction: null }, thyShowSearch: { classPropertyName: "thyShowSearch", publicName: "thyShowSearch", isSignal: true, isRequired: false, transformFunction: null }, thyPlaceHolder: { classPropertyName: "thyPlaceHolder", publicName: "thyPlaceHolder", isSignal: true, isRequired: false, transformFunction: null }, thyServerSearch: { classPropertyName: "thyServerSearch", publicName: "thyServerSearch", isSignal: true, isRequired: false, transformFunction: null }, thyLoadState: { classPropertyName: "thyLoadState", publicName: "thyLoadState", isSignal: true, isRequired: false, transformFunction: null }, thyAutoActiveFirstItem: { classPropertyName: "thyAutoActiveFirstItem", publicName: "thyAutoActiveFirstItem", isSignal: true, isRequired: false, transformFunction: null }, thyMode: { classPropertyName: "thyMode", publicName: "thyMode", isSignal: true, isRequired: false, transformFunction: null }, thySize: { classPropertyName: "thySize", publicName: "thySize", isSignal: true, isRequired: false, transformFunction: null }, thyEmptyStateText: { classPropertyName: "thyEmptyStateText", publicName: "thyEmptyStateText", isSignal: true, isRequired: false, transformFunction: null }, thyEmptySearchMessageText: { classPropertyName: "thyEmptySearchMessageText", publicName: "thyEmptySearchMessageText", isSignal: true, isRequired: false, transformFunction: null }, thyEnableScrollLoad: { classPropertyName: "thyEnableScrollLoad", publicName: "thyEnableScrollLoad", isSignal: true, isRequired: false, transformFunction: null }, thyAllowClear: { classPropertyName: "thyAllowClear", publicName: "thyAllowClear", isSignal: true, isRequired: false, transformFunction: null }, thyDisabled: { classPropertyName: "thyDisabled", publicName: "thyDisabled", isSignal: false, isRequired: false, transformFunction: coerceBooleanProperty }, thySortComparator: { classPropertyName: "thySortComparator", publicName: "thySortComparator", isSignal: true, isRequired: false, transformFunction: null }, thyFooterTemplate: { classPropertyName: "thyFooterTemplate", publicName: "thyFooterTemplate", isSignal: true, isRequired: false, transformFunction: null }, thyPlacement: { classPropertyName: "thyPlacement", publicName: "thyPlacement", isSignal: true, isRequired: false, transformFunction: null }, thyOrigin: { classPropertyName: "thyOrigin", publicName: "thyOrigin", isSignal: true, isRequired: false, transformFunction: null }, thyFooterClass: { classPropertyName: "thyFooterClass", publicName: "thyFooterClass", isSignal: true, isRequired: false, transformFunction: null }, thyAutoExpand: { classPropertyName: "thyAutoExpand", publicName: "thyAutoExpand", isSignal: true, isRequired: false, transformFunction: null }, thyHasBackdrop: { classPropertyName: "thyHasBackdrop", publicName: "thyHasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, thyMaxTagCount: { classPropertyName: "thyMaxTagCount", publicName: "thyMaxTagCount", isSignal: true, isRequired: false, transformFunction: null }, thyBorderless: { classPropertyName: "thyBorderless", publicName: "thyBorderless", isSignal: true, isRequired: false, transformFunction: null }, thyOptions: { classPropertyName: "thyOptions", publicName: "thyOptions", isSignal: true, isRequired: false, transformFunction: null }, thyPreset: { classPropertyName: "thyPreset", publicName: "thyPreset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { thyOnSearch: "thyOnSearch", thyOnScrollToBottom: "thyOnScrollToBottom", thyOnExpandStatusChange: "thyOnExpandStatusChange" }, host: { listeners: { "focus": "onFocus($event)", "blur": "onBlur($event)", "keydown": "keydown($event)" }, properties: { "class.thy-select-custom": "true", "class.thy-select": "true", "class.menu-is-opened": "panelOpen", "attr.tabindex": "tabIndex" } }, providers: [
840
910
  {
841
911
  provide: NG_VALUE_ACCESSOR,
842
912
  useExisting: forwardRef(() => ThySelect),
843
913
  multi: true
844
914
  }
845
- ], queries: [{ propertyName: "selectedValueDisplayRef", first: true, predicate: ["selectedDisplay"], descendants: true, isSignal: true }, { propertyName: "contentGroups", predicate: ThySelectOptionGroup, isSignal: true }, { propertyName: "contentOptions", predicate: ThyOption, descendants: true }], viewQueries: [{ propertyName: "cdkConnectedOverlay", first: true, predicate: CdkConnectedOverlay, descendants: true, isSignal: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }, { propertyName: "viewGroups", predicate: ThySelectOptionGroup, descendants: true, isSignal: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, read: ElementRef, static: true }, { propertyName: "viewOptions", predicate: ThyOption, descendants: true }], exportAs: ["thySelect"], usesInheritance: true, ngImport: i0, template: "<div\n cdk-overlay-origin\n thySelectControl\n (click)=\"toggle($event)\"\n #origin=\"cdkOverlayOrigin\"\n #trigger\n [thyPanelOpened]=\"panelOpen\"\n [thySelectedOptions]=\"selected\"\n [thyIsMultiple]=\"isMultiple\"\n [thyShowSearch]=\"thyShowSearch()\"\n [thyAllowClear]=\"thyAllowClear()\"\n [thySize]=\"thySize()\"\n [thyPlaceholder]=\"thyPlaceHolder()\"\n [customDisplayTemplate]=\"selectedValueDisplayRef()\"\n [thyDisabled]=\"disabled\"\n [thyBorderless]=\"thyBorderless()\"\n (thyOnClear)=\"clearSelectValue($event)\"\n (thyOnRemove)=\"remove($event)\"\n (thyOnSearch)=\"onSearchFilter($event)\"\n (thyOnBlur)=\"onBlur($event)\"\n [thyMaxTagCount]=\"thyMaxTagCount()\"\n [thyPreset]=\"thyPreset()\"></div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayHasBackdrop]=\"thyHasBackdrop()\"\n [cdkConnectedOverlayPositions]=\"dropDownPositions\"\n [cdkConnectedOverlayOrigin]=\"thyOrigin() || origin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayWidth]=\"triggerRectWidth\"\n [cdkConnectedOverlayMinWidth]=\"dropDownMinWidth\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n cdkConnectedOverlayTransformOriginOn=\".thy-select-dropdown\"\n (attach)=\"onAttached()\"\n (detach)=\"close()\">\n <div\n thyStopPropagation\n [attr.tabindex]=\"-1\"\n [ngClass]=\"dropDownClass\"\n [@scaleYMotion]=\"placement === 'top' || placement === 'bottom' ? 'enter' : 'void'\"\n [@scaleXMotion]=\"placement === 'left' || placement === 'right' ? 'enter' : 'void'\"\n [@scaleMotion]=\"placement !== 'top' && placement !== 'bottom' && placement !== 'left' && placement !== 'right' ? 'enter' : 'void'\"\n (mousemove)=\"dropDownMouseMove($event)\">\n @if (contentOptions?.length > 0 || contentGroups?.length > 0 || innerOptions?.length > 0) {\n <div\n #panel\n class=\"thy-select-dropdown-options thy-select-dropdown-options-{{ thySize() }}\"\n thyScroll\n (thyOnScrolled)=\"onOptionsScrolled($event)\"\n [thyEnable]=\"thyEnableScrollLoad()\">\n @if (isReactiveDriven) {\n <ng-template [ngTemplateOutlet]=\"optionsContainer.optionsTemplate()\"></ng-template>\n }\n <ng-content></ng-content>\n @if (isHiddenOptions) {\n <thy-loading [thyDone]=\"thyLoadState()\" thySize=\"sm\"></thy-loading>\n <div class=\"thy-select-empty-content\">\n @if (thyLoadState()) {\n <thy-empty [thyMessage]=\"thyEmptySearchMessageText()\" thySize=\"sm\" [thyIconName]=\"emptyIcon()\"></thy-empty>\n }\n </div>\n }\n </div>\n } @else {\n <thy-loading [thyDone]=\"thyLoadState()\" thySize=\"sm\"></thy-loading>\n <div class=\"thy-select-empty-content\">\n @if (thyLoadState()) {\n <thy-empty [thyMessage]=\"thyEmptyStateText()\" thySize=\"sm\" [thyIconName]=\"emptyIcon()\"></thy-empty>\n }\n </div>\n }\n @if (thyFooterTemplate()) {\n <div [class]=\"thyFooterClass() ? thyFooterClass() : 'thy-custom-select-footer'\">\n @if (thyFooterTemplate()) {\n <ng-template [ngTemplateOutlet]=\"thyFooterTemplate()\"></ng-template>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<thy-options-container #optionsContainer>\n @for (option of optionGroups; track $index) {\n @if (!option.children) {\n <thy-option\n [thyDisabled]=\"option.disabled\"\n [thyLabelText]=\"option.label\"\n [thyValue]=\"option.value\"\n [thyRawValue]=\"option\"></thy-option>\n } @else {\n <thy-option-group [thyGroupLabel]=\"option.groupLabel\">\n @for (sub of option.children; track sub.value) {\n <thy-option [thyDisabled]=\"sub.disabled\" [thyLabelText]=\"sub.label\" [thyValue]=\"sub.value\" [thyRawValue]=\"sub\"></thy-option>\n }\n </thy-option-group>\n }\n }\n</thy-options-container>\n", dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: ThySelectControl, selector: "thy-select-control,[thySelectControl]", inputs: ["inputValue", "thyPanelOpened", "thyIsMultiple", "thyShowSearch", "thySelectedOptions", "thyDisabled", "customDisplayTemplate", "thyAllowClear", "thyPlaceholder", "thySize", "thyMaxTagCount", "thyBorderless", "thyPreset"], outputs: ["inputValueChange", "thyOnSearch", "thyOnRemove", "thyOnClear", "thyOnBlur"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: ThyStopPropagationDirective, selector: "[thyStopPropagation]", inputs: ["thyStopPropagation"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: ThyScrollDirective, selector: "[thyScroll]", inputs: ["thyEnable"], outputs: ["thyOnScrolled"] }, { kind: "component", type: ThyLoading, selector: "thy-loading", inputs: ["thyDone", "thyTip", "thyIsMask"] }, { kind: "component", type: ThyEmpty, selector: "thy-empty", inputs: ["thyMessage", "thyTranslationKey", "thyTranslationValues", "thyEntityName", "thyEntityNameTranslateKey", "thyIconName", "thySize", "thyMarginTop", "thyTopAuto", "thyContainer", "thyImageUrl", "thyImageLoading", "thyImageFetchPriority", "thyDescription"] }, { kind: "component", type: ThyOptionsContainer, selector: "thy-options-container" }, { kind: "component", type: ThyOption, selector: "thy-option", inputs: ["thyValue", "thyRawValue", "thyLabelText", "thyShowOptionCustom", "thySearchKey", "thyDisabled"], outputs: ["selectionChange", "visibleChange"] }, { kind: "component", type: ThySelectOptionGroup, selector: "thy-option-group", inputs: ["thyDisabled", "thyGroupLabel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], animations: [scaleXMotion, scaleYMotion, scaleMotion], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
915
+ ], queries: [{ propertyName: "selectedValueDisplayRef", first: true, predicate: ["selectedDisplay"], descendants: true, isSignal: true }, { propertyName: "options", predicate: ThyOption, descendants: true, isSignal: true }, { propertyName: "groups", predicate: ThySelectOptionGroup, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "cdkConnectedOverlay", first: true, predicate: CdkConnectedOverlay, descendants: true, isSignal: true }, { propertyName: "cdkVirtualScrollViewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, read: ElementRef, static: true }, { propertyName: "optionRenders", predicate: ThyOptionRender, descendants: true }], exportAs: ["thySelect"], usesInheritance: true, ngImport: i0, template: "<div\n cdk-overlay-origin\n thySelectControl\n (click)=\"toggle($event)\"\n #origin=\"cdkOverlayOrigin\"\n #trigger\n [thyPanelOpened]=\"panelOpen\"\n [thySelectedOptions]=\"selectedOptions()\"\n [thyIsMultiple]=\"isMultiple()\"\n [thyShowSearch]=\"thyShowSearch()\"\n [thyAllowClear]=\"thyAllowClear()\"\n [thySize]=\"thySize()\"\n [thyPlaceholder]=\"thyPlaceHolder()\"\n [customDisplayTemplate]=\"selectedValueDisplayRef()\"\n [thyDisabled]=\"disabled\"\n [thyBorderless]=\"thyBorderless()\"\n (thyOnClear)=\"clearSelectValue($event)\"\n (thyOnRemove)=\"remove($event)\"\n (thyOnSearch)=\"search($event)\"\n (thyOnBlur)=\"onBlur($event)\"\n [thyMaxTagCount]=\"thyMaxTagCount()\"\n [thyPreset]=\"thyPreset()\"></div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayHasBackdrop]=\"thyHasBackdrop()\"\n [cdkConnectedOverlayPositions]=\"dropDownPositions()\"\n [cdkConnectedOverlayOrigin]=\"thyOrigin() || origin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayWidth]=\"triggerRectWidth()\"\n [cdkConnectedOverlayMinWidth]=\"dropDownMinWidth()\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n cdkConnectedOverlayTransformOriginOn=\".thy-select-dropdown\"\n (detach)=\"close()\">\n <div\n thyStopPropagation\n [attr.tabindex]=\"-1\"\n [ngClass]=\"dropDownClass()\"\n [@scaleYMotion]=\"placement() === 'top' || placement() === 'bottom' ? 'enter' : 'void'\"\n [@scaleXMotion]=\"placement() === 'left' || placement() === 'right' ? 'enter' : 'void'\"\n [@scaleMotion]=\"\n placement() !== 'top' && placement() !== 'bottom' && placement() !== 'left' && placement() !== 'right' ? 'enter' : 'void'\n \">\n @if (filteredGroupsAndOptions()?.length > 0) {\n <div\n #panel\n class=\"thy-select-dropdown-options thy-select-dropdown-options-{{ thySize() }} thy-select-dropdown-options-with-virtual-scroll\">\n <cdk-virtual-scroll-viewport\n class=\"thy-select-scroll-viewport\"\n [itemSize]=\"itemSize\"\n [style.height.px]=\"virtualHeight()\"\n (scrolledIndexChange)=\"optionsScrolled($event)\"\n (mouseleave)=\"mouseLeaveOptions()\">\n <ng-template cdkVirtualFor [cdkVirtualForOf]=\"filteredGroupsAndOptions()\" [cdkVirtualForTrackBy]=\"trackByFn\" let-item>\n @if (item.type === 'group') {\n <thy-option-group-render [thyGroupLabel]=\"item.label\"></thy-option-group-render>\n } @else {\n <thy-option-render\n [thyValue]=\"item.value\"\n [thyRawValue]=\"item.rawValue\"\n [thyLabelText]=\"item.label\"\n [thyShowOptionCustom]=\"item.showOptionCustom\"\n [thySearchKey]=\"item.searchKey\"\n [thyDisabled]=\"item.disabled\"\n [thyTemplate]=\"item.template\"\n [thyShowCheckedIcon]=\"isMultiple()\"\n [thySelectedValuesMap]=\"selectedValuesMap()\"\n [thyActivatedValue]=\"activatedValue()\"\n (optionHover)=\"optionHover($event)\"\n (optionClick)=\"optionClick($event)\">\n </thy-option-render>\n }\n </ng-template>\n </cdk-virtual-scroll-viewport>\n <ng-content></ng-content>\n </div>\n } @else {\n <thy-loading [thyDone]=\"thyLoadState()\" thySize=\"sm\"></thy-loading>\n <div class=\"thy-select-empty-content\">\n @if (thyLoadState()) {\n @let isSearching = keywords();\n <thy-empty\n [thyMessage]=\"isSearching ? thyEmptySearchMessageText() : thyEmptyStateText()\"\n thySize=\"sm\"\n [thyIconName]=\"emptyIcon()\"></thy-empty>\n }\n </div>\n }\n @if (thyFooterTemplate()) {\n <div [class]=\"thyFooterClass() ? thyFooterClass() : 'thy-custom-select-footer'\">\n @if (thyFooterTemplate()) {\n <ng-template [ngTemplateOutlet]=\"thyFooterTemplate()\"></ng-template>\n }\n </div>\n }\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: ThySelectControl, selector: "thy-select-control,[thySelectControl]", inputs: ["inputValue", "thyPanelOpened", "thyIsMultiple", "thyShowSearch", "thySelectedOptions", "thyDisabled", "customDisplayTemplate", "thyAllowClear", "thyPlaceholder", "thySize", "thyMaxTagCount", "thyBorderless", "thyPreset"], outputs: ["inputValueChange", "thyOnSearch", "thyOnRemove", "thyOnClear", "thyOnBlur"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: ThyStopPropagationDirective, selector: "[thyStopPropagation]", inputs: ["thyStopPropagation"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ThyLoading, selector: "thy-loading", inputs: ["thyDone", "thyTip", "thyIsMask"] }, { kind: "component", type: ThyEmpty, selector: "thy-empty", inputs: ["thyMessage", "thyTranslationKey", "thyTranslationValues", "thyEntityName", "thyEntityNameTranslateKey", "thyIconName", "thySize", "thyMarginTop", "thyTopAuto", "thyContainer", "thyImageUrl", "thyImageLoading", "thyImageFetchPriority", "thyDescription"] }, { kind: "component", type: ThyOptionRender, selector: "thy-option-render", inputs: ["thyValue", "thyRawValue", "thyLabelText", "thySearchKey", "thyDisabled", "thyShowOptionCustom", "thyTemplate", "thyTemplateContext", "thyShowCheckedIcon", "thySelectedValuesMap", "thyActivatedValue"], outputs: ["optionClick", "optionHover"] }, { kind: "component", type: ThyOptionGroupRender, selector: "thy-option-group-render", inputs: ["thyGroupLabel", "thyDisabled"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }], animations: [scaleXMotion, scaleYMotion, scaleMotion], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
846
916
  }
847
917
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ThySelect, decorators: [{
848
918
  type: Component,
849
919
  args: [{ selector: 'thy-select,thy-custom-select', exportAs: 'thySelect', providers: [
850
- {
851
- provide: THY_OPTION_PARENT_COMPONENT,
852
- useExisting: ThySelect
853
- },
854
920
  {
855
921
  provide: NG_VALUE_ACCESSOR,
856
922
  useExisting: forwardRef(() => ThySelect),
@@ -862,13 +928,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
862
928
  CdkConnectedOverlay,
863
929
  ThyStopPropagationDirective,
864
930
  NgClass,
865
- ThyScrollDirective,
866
931
  ThyLoading,
867
932
  ThyEmpty,
868
- ThyOptionsContainer,
869
- ThyOption,
870
- ThySelectOptionGroup,
871
- NgTemplateOutlet
933
+ ThyOptionRender,
934
+ ThyOptionGroupRender,
935
+ NgTemplateOutlet,
936
+ ScrollingModule
872
937
  ], host: {
873
938
  '[class.thy-select-custom]': 'true',
874
939
  '[class.thy-select]': 'true',
@@ -876,20 +941,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
876
941
  '[attr.tabindex]': 'tabIndex',
877
942
  '(focus)': 'onFocus($event)',
878
943
  '(blur)': 'onBlur($event)'
879
- }, animations: [scaleXMotion, scaleYMotion, scaleMotion], template: "<div\n cdk-overlay-origin\n thySelectControl\n (click)=\"toggle($event)\"\n #origin=\"cdkOverlayOrigin\"\n #trigger\n [thyPanelOpened]=\"panelOpen\"\n [thySelectedOptions]=\"selected\"\n [thyIsMultiple]=\"isMultiple\"\n [thyShowSearch]=\"thyShowSearch()\"\n [thyAllowClear]=\"thyAllowClear()\"\n [thySize]=\"thySize()\"\n [thyPlaceholder]=\"thyPlaceHolder()\"\n [customDisplayTemplate]=\"selectedValueDisplayRef()\"\n [thyDisabled]=\"disabled\"\n [thyBorderless]=\"thyBorderless()\"\n (thyOnClear)=\"clearSelectValue($event)\"\n (thyOnRemove)=\"remove($event)\"\n (thyOnSearch)=\"onSearchFilter($event)\"\n (thyOnBlur)=\"onBlur($event)\"\n [thyMaxTagCount]=\"thyMaxTagCount()\"\n [thyPreset]=\"thyPreset()\"></div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayHasBackdrop]=\"thyHasBackdrop()\"\n [cdkConnectedOverlayPositions]=\"dropDownPositions\"\n [cdkConnectedOverlayOrigin]=\"thyOrigin() || origin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayWidth]=\"triggerRectWidth\"\n [cdkConnectedOverlayMinWidth]=\"dropDownMinWidth\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n cdkConnectedOverlayTransformOriginOn=\".thy-select-dropdown\"\n (attach)=\"onAttached()\"\n (detach)=\"close()\">\n <div\n thyStopPropagation\n [attr.tabindex]=\"-1\"\n [ngClass]=\"dropDownClass\"\n [@scaleYMotion]=\"placement === 'top' || placement === 'bottom' ? 'enter' : 'void'\"\n [@scaleXMotion]=\"placement === 'left' || placement === 'right' ? 'enter' : 'void'\"\n [@scaleMotion]=\"placement !== 'top' && placement !== 'bottom' && placement !== 'left' && placement !== 'right' ? 'enter' : 'void'\"\n (mousemove)=\"dropDownMouseMove($event)\">\n @if (contentOptions?.length > 0 || contentGroups?.length > 0 || innerOptions?.length > 0) {\n <div\n #panel\n class=\"thy-select-dropdown-options thy-select-dropdown-options-{{ thySize() }}\"\n thyScroll\n (thyOnScrolled)=\"onOptionsScrolled($event)\"\n [thyEnable]=\"thyEnableScrollLoad()\">\n @if (isReactiveDriven) {\n <ng-template [ngTemplateOutlet]=\"optionsContainer.optionsTemplate()\"></ng-template>\n }\n <ng-content></ng-content>\n @if (isHiddenOptions) {\n <thy-loading [thyDone]=\"thyLoadState()\" thySize=\"sm\"></thy-loading>\n <div class=\"thy-select-empty-content\">\n @if (thyLoadState()) {\n <thy-empty [thyMessage]=\"thyEmptySearchMessageText()\" thySize=\"sm\" [thyIconName]=\"emptyIcon()\"></thy-empty>\n }\n </div>\n }\n </div>\n } @else {\n <thy-loading [thyDone]=\"thyLoadState()\" thySize=\"sm\"></thy-loading>\n <div class=\"thy-select-empty-content\">\n @if (thyLoadState()) {\n <thy-empty [thyMessage]=\"thyEmptyStateText()\" thySize=\"sm\" [thyIconName]=\"emptyIcon()\"></thy-empty>\n }\n </div>\n }\n @if (thyFooterTemplate()) {\n <div [class]=\"thyFooterClass() ? thyFooterClass() : 'thy-custom-select-footer'\">\n @if (thyFooterTemplate()) {\n <ng-template [ngTemplateOutlet]=\"thyFooterTemplate()\"></ng-template>\n }\n </div>\n }\n </div>\n</ng-template>\n\n<thy-options-container #optionsContainer>\n @for (option of optionGroups; track $index) {\n @if (!option.children) {\n <thy-option\n [thyDisabled]=\"option.disabled\"\n [thyLabelText]=\"option.label\"\n [thyValue]=\"option.value\"\n [thyRawValue]=\"option\"></thy-option>\n } @else {\n <thy-option-group [thyGroupLabel]=\"option.groupLabel\">\n @for (sub of option.children; track sub.value) {\n <thy-option [thyDisabled]=\"sub.disabled\" [thyLabelText]=\"sub.label\" [thyValue]=\"sub.value\" [thyRawValue]=\"sub\"></thy-option>\n }\n </thy-option-group>\n }\n }\n</thy-options-container>\n" }]
944
+ }, animations: [scaleXMotion, scaleYMotion, scaleMotion], template: "<div\n cdk-overlay-origin\n thySelectControl\n (click)=\"toggle($event)\"\n #origin=\"cdkOverlayOrigin\"\n #trigger\n [thyPanelOpened]=\"panelOpen\"\n [thySelectedOptions]=\"selectedOptions()\"\n [thyIsMultiple]=\"isMultiple()\"\n [thyShowSearch]=\"thyShowSearch()\"\n [thyAllowClear]=\"thyAllowClear()\"\n [thySize]=\"thySize()\"\n [thyPlaceholder]=\"thyPlaceHolder()\"\n [customDisplayTemplate]=\"selectedValueDisplayRef()\"\n [thyDisabled]=\"disabled\"\n [thyBorderless]=\"thyBorderless()\"\n (thyOnClear)=\"clearSelectValue($event)\"\n (thyOnRemove)=\"remove($event)\"\n (thyOnSearch)=\"search($event)\"\n (thyOnBlur)=\"onBlur($event)\"\n [thyMaxTagCount]=\"thyMaxTagCount()\"\n [thyPreset]=\"thyPreset()\"></div>\n\n<ng-template\n cdk-connected-overlay\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayHasBackdrop]=\"thyHasBackdrop()\"\n [cdkConnectedOverlayPositions]=\"dropDownPositions()\"\n [cdkConnectedOverlayOrigin]=\"thyOrigin() || origin\"\n [cdkConnectedOverlayOpen]=\"panelOpen\"\n [cdkConnectedOverlayWidth]=\"triggerRectWidth()\"\n [cdkConnectedOverlayMinWidth]=\"dropDownMinWidth()\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n cdkConnectedOverlayTransformOriginOn=\".thy-select-dropdown\"\n (detach)=\"close()\">\n <div\n thyStopPropagation\n [attr.tabindex]=\"-1\"\n [ngClass]=\"dropDownClass()\"\n [@scaleYMotion]=\"placement() === 'top' || placement() === 'bottom' ? 'enter' : 'void'\"\n [@scaleXMotion]=\"placement() === 'left' || placement() === 'right' ? 'enter' : 'void'\"\n [@scaleMotion]=\"\n placement() !== 'top' && placement() !== 'bottom' && placement() !== 'left' && placement() !== 'right' ? 'enter' : 'void'\n \">\n @if (filteredGroupsAndOptions()?.length > 0) {\n <div\n #panel\n class=\"thy-select-dropdown-options thy-select-dropdown-options-{{ thySize() }} thy-select-dropdown-options-with-virtual-scroll\">\n <cdk-virtual-scroll-viewport\n class=\"thy-select-scroll-viewport\"\n [itemSize]=\"itemSize\"\n [style.height.px]=\"virtualHeight()\"\n (scrolledIndexChange)=\"optionsScrolled($event)\"\n (mouseleave)=\"mouseLeaveOptions()\">\n <ng-template cdkVirtualFor [cdkVirtualForOf]=\"filteredGroupsAndOptions()\" [cdkVirtualForTrackBy]=\"trackByFn\" let-item>\n @if (item.type === 'group') {\n <thy-option-group-render [thyGroupLabel]=\"item.label\"></thy-option-group-render>\n } @else {\n <thy-option-render\n [thyValue]=\"item.value\"\n [thyRawValue]=\"item.rawValue\"\n [thyLabelText]=\"item.label\"\n [thyShowOptionCustom]=\"item.showOptionCustom\"\n [thySearchKey]=\"item.searchKey\"\n [thyDisabled]=\"item.disabled\"\n [thyTemplate]=\"item.template\"\n [thyShowCheckedIcon]=\"isMultiple()\"\n [thySelectedValuesMap]=\"selectedValuesMap()\"\n [thyActivatedValue]=\"activatedValue()\"\n (optionHover)=\"optionHover($event)\"\n (optionClick)=\"optionClick($event)\">\n </thy-option-render>\n }\n </ng-template>\n </cdk-virtual-scroll-viewport>\n <ng-content></ng-content>\n </div>\n } @else {\n <thy-loading [thyDone]=\"thyLoadState()\" thySize=\"sm\"></thy-loading>\n <div class=\"thy-select-empty-content\">\n @if (thyLoadState()) {\n @let isSearching = keywords();\n <thy-empty\n [thyMessage]=\"isSearching ? thyEmptySearchMessageText() : thyEmptyStateText()\"\n thySize=\"sm\"\n [thyIconName]=\"emptyIcon()\"></thy-empty>\n }\n </div>\n }\n @if (thyFooterTemplate()) {\n <div [class]=\"thyFooterClass() ? thyFooterClass() : 'thy-custom-select-footer'\">\n @if (thyFooterTemplate()) {\n <ng-template [ngTemplateOutlet]=\"thyFooterTemplate()\"></ng-template>\n }\n </div>\n }\n </div>\n</ng-template>\n" }]
880
945
  }], ctorParameters: () => [], propDecorators: { thyDropdownWidthMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyDropdownWidthMode", required: false }] }], cdkConnectedOverlay: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkConnectedOverlay), { isSignal: true }] }], thyOnSearch: [{ type: i0.Output, args: ["thyOnSearch"] }], thyOnScrollToBottom: [{ type: i0.Output, args: ["thyOnScrollToBottom"] }], thyOnExpandStatusChange: [{ type: i0.Output, args: ["thyOnExpandStatusChange"] }], thyShowSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyShowSearch", required: false }] }], thyPlaceHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyPlaceHolder", required: false }] }], thyServerSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyServerSearch", required: false }] }], thyLoadState: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyLoadState", required: false }] }], thyAutoActiveFirstItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyAutoActiveFirstItem", required: false }] }], thyMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyMode", required: false }] }], thySize: [{ type: i0.Input, args: [{ isSignal: true, alias: "thySize", required: false }] }], thyEmptyStateText: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyEmptyStateText", required: false }] }], thyEmptySearchMessageText: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyEmptySearchMessageText", required: false }] }], thyEnableScrollLoad: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyEnableScrollLoad", required: false }] }], thyAllowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyAllowClear", required: false }] }], thyDisabled: [{
881
946
  type: Input,
882
947
  args: [{ transform: coerceBooleanProperty }]
883
- }], thySortComparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "thySortComparator", required: false }] }], thyFooterTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyFooterTemplate", required: false }] }], thyPlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyPlacement", required: false }] }], thyOrigin: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyOrigin", required: false }] }], thyFooterClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyFooterClass", required: false }] }], selectedValueDisplayRef: [{ type: i0.ContentChild, args: ['selectedDisplay', { isSignal: true }] }], thyAutoExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyAutoExpand", required: false }] }], thyHasBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyHasBackdrop", required: false }] }], thyMaxTagCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyMaxTagCount", required: false }] }], thyBorderless: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyBorderless", required: false }] }], thyOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyOptions", required: false }] }], thyPreset: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyPreset", required: false }] }], trigger: [{
948
+ }], thySortComparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "thySortComparator", required: false }] }], thyFooterTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyFooterTemplate", required: false }] }], thyPlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyPlacement", required: false }] }], thyOrigin: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyOrigin", required: false }] }], thyFooterClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyFooterClass", required: false }] }], selectedValueDisplayRef: [{ type: i0.ContentChild, args: ['selectedDisplay', { isSignal: true }] }], thyAutoExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyAutoExpand", required: false }] }], thyHasBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyHasBackdrop", required: false }] }], thyMaxTagCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyMaxTagCount", required: false }] }], thyBorderless: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyBorderless", required: false }] }], cdkVirtualScrollViewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], thyOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyOptions", required: false }] }], thyPreset: [{ type: i0.Input, args: [{ isSignal: true, alias: "thyPreset", required: false }] }], trigger: [{
884
949
  type: ViewChild,
885
950
  args: ['trigger', { read: ElementRef, static: true }]
886
- }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], contentOptions: [{
887
- type: ContentChildren,
888
- args: [ThyOption, { descendants: true }]
889
- }], viewOptions: [{
951
+ }], options: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => ThyOption), { ...{ descendants: true }, isSignal: true }] }], groups: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => ThySelectOptionGroup), { ...{ descendants: true }, isSignal: true }] }], optionRenders: [{
890
952
  type: ViewChildren,
891
- args: [ThyOption]
892
- }], contentGroups: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => ThySelectOptionGroup), { isSignal: true }] }], viewGroups: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => ThySelectOptionGroup), { isSignal: true }] }], handleKeydown: [{
953
+ args: [ThyOptionRender]
954
+ }], keydown: [{
893
955
  type: HostListener,
894
956
  args: ['keydown', ['$event']]
895
957
  }] } });
@@ -949,7 +1011,7 @@ class ThyNativeSelect extends TabIndexDisabledControlValueAccessorMixin {
949
1011
  useExisting: forwardRef(() => ThyNativeSelect),
950
1012
  multi: true
951
1013
  }
952
- ], viewQueries: [{ propertyName: "selectElement", first: true, predicate: ["select"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<select\n #select\n thyInput\n [tabindex]=\"-1\"\n [thySize]=\"thySize()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"innerValue\"\n (ngModelChange)=\"ngModelChange()\"\n (blur)=\"onBlur($event)\"\n [class.thy-select-selection-allow-clear]=\"thyAllowClear()\">\n <ng-content></ng-content>\n</select>\n<thy-icon thyIconName=\"angle-down\"></thy-icon>\n@if (thyAllowClear() && innerValue()) {\n <a class=\"thy-select-remove remove-link\" href=\"javascript:;\" (click)=\"clearSelectValue($event)\">\n <thy-icon class=\"remove-link-icon\" thyIconName=\"close-circle-bold-fill\"></thy-icon>\n </a>\n}\n", dependencies: [{ kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }] }); }
1014
+ ], viewQueries: [{ propertyName: "selectElement", first: true, predicate: ["select"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<select\n #select\n thyInput\n [tabindex]=\"-1\"\n [thySize]=\"thySize()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"innerValue\"\n (ngModelChange)=\"ngModelChange()\"\n (blur)=\"onBlur($event)\"\n [class.thy-select-selection-allow-clear]=\"thyAllowClear()\">\n <ng-content></ng-content>\n</select>\n<thy-icon thyIconName=\"angle-down\"></thy-icon>\n@if (thyAllowClear() && innerValue()) {\n <a class=\"thy-select-remove remove-link\" href=\"javascript:;\" (click)=\"clearSelectValue($event)\">\n <thy-icon class=\"remove-link-icon\" thyIconName=\"close-circle-bold-fill\"></thy-icon>\n </a>\n}\n", dependencies: [{ kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }] }); }
953
1015
  }
954
1016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ThyNativeSelect, decorators: [{
955
1017
  type: Component,