@seniorsistemas/angular-components 19.0.9 → 19.1.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.
Files changed (125) hide show
  1. package/breadcrumb/lib/breadcrumb/breadcrumb-models.d.ts +2 -0
  2. package/button/lib/button/button.component.d.ts +8 -2
  3. package/checkbox/lib/checkbox/checkbox.component.d.ts +5 -1
  4. package/dialog/lib/src/dialog/dialog.component.d.ts +7 -1
  5. package/esm2022/accordion/lib/accordion/components/accordion-panel/accordion-panel.component.mjs +2 -2
  6. package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-models.mjs +1 -1
  7. package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.component.mjs +3 -3
  8. package/esm2022/breadcrumb/lib/dynamic-breadcrumb/dynamic-breadcrumb.component.mjs +8 -6
  9. package/esm2022/button/lib/button/button.component.mjs +20 -8
  10. package/esm2022/checkbox/lib/checkbox/checkbox.component.mjs +8 -5
  11. package/esm2022/confirm-dialog/lib/popup-confirm-dialog/popup-confirm-dialog.component.mjs +2 -2
  12. package/esm2022/content-generator/lib/content-generator/content-generator.component.mjs +1 -1
  13. package/esm2022/dialog/lib/src/dialog/dialog.component.mjs +9 -3
  14. package/esm2022/dynamic-form/dynamic-form/components/grid/row/row.component.mjs +1 -1
  15. package/esm2022/dynamic-form/dynamic-form/components/lookup/lookup.component.mjs +2 -2
  16. package/esm2022/dynamic-form/dynamic-form/form-field/fields/bignumber/bignumber-field.component.mjs +1 -1
  17. package/esm2022/dynamic-form/dynamic-form/form-field/fields/boolean/boolean-radio-field/boolean-field.component.mjs +1 -1
  18. package/esm2022/dynamic-form/dynamic-form/form-field/fields/boolean/boolean-switch-field/boolean-switch-field.component.mjs +2 -2
  19. package/esm2022/dynamic-form/dynamic-form/form-field/fields/button-field/button-field.component.mjs +1 -1
  20. package/esm2022/dynamic-form/dynamic-form/form-field/fields/number/number-field.component.mjs +1 -1
  21. package/esm2022/dynamic-form/dynamic-form/form-field/fields/password/password-field.component.mjs +1 -1
  22. package/esm2022/dynamic-form/dynamic-form/form-field/fields/radio-button/radio-button-field.component.mjs +1 -1
  23. package/esm2022/dynamic-form/dynamic-form/form-field/fields/select/select-field.component.mjs +2 -2
  24. package/esm2022/dynamic-form/dynamic-form/form-field/fields/text/text-field.component.mjs +1 -1
  25. package/esm2022/empty-state/lib/empty-state/empty-state.component.mjs +1 -1
  26. package/esm2022/file-picker/lib/file-picker/file-picker.component.mjs +1 -1
  27. package/esm2022/global-search/lib/global-search/components/dropdown/global-search-dropdown-item.component.mjs +1 -1
  28. package/esm2022/global-search/lib/global-search/global-search.component.mjs +1 -1
  29. package/esm2022/help-popover/lib/help-popover/help-popover/help-popover.component.mjs +1 -1
  30. package/esm2022/image-cropper/lib/image-cropper/image-cropper.component.mjs +1 -1
  31. package/esm2022/inline-edit/lib/inline-edit/components/fields/inline-edit-number/inline-edit-number.component.mjs +1 -1
  32. package/esm2022/inline-edit/lib/inline-edit/components/inline-edit-item/inline-edit-item.component.mjs +1 -1
  33. package/esm2022/kanban/lib/kanban/components/kanban-column/kanban-column.component.mjs +1 -1
  34. package/esm2022/kanban/lib/kanban/components/kanban-item/kanban-item.component.mjs +1 -1
  35. package/esm2022/lib/locale/fallback.mjs +13 -2
  36. package/esm2022/navigation-button/lib/navigation-button/navigation-button.component.mjs +1 -1
  37. package/esm2022/object-card/lib/object-card/elements/field/object-card-field.component.mjs +1 -1
  38. package/esm2022/object-card/lib/object-card/elements/main/object-card-main.component.mjs +1 -1
  39. package/esm2022/paginator/lib/paginator/paginator.component.mjs +2 -2
  40. package/esm2022/picklist/lib/picklist/picklist.component.mjs +1 -1
  41. package/esm2022/profile-picture-picker/lib/profile-picture-picker/profile-picture-picker.component.mjs +1 -1
  42. package/esm2022/select/lib/select/components/select-option/select-option.component.mjs +3 -3
  43. package/esm2022/select/lib/select/select.component.mjs +132 -20
  44. package/esm2022/shared/lib/accessibility/paginator-accessibility.directive.mjs +182 -0
  45. package/esm2022/shared/lib/accessibility/table-checkbox-accessibility.directive.mjs +174 -0
  46. package/esm2022/shared/public-api.mjs +6 -4
  47. package/esm2022/switch/lib/switch/switch.component.mjs +19 -8
  48. package/esm2022/table/lib/table/table-paging/table-paging.component.mjs +1 -1
  49. package/esm2022/table/public-api.mjs +2 -1
  50. package/esm2022/tiered-menu/lib/tiered-menu/components/tiered-menu/tiered-menu.component.mjs +18 -8
  51. package/esm2022/tiered-menu/lib/tiered-menu/components/tiered-menu-item/tiered-menu-item.component.mjs +1 -1
  52. package/esm2022/tiered-menu/lib/tiered-menu/services/tiered-menu.service.mjs +1 -1
  53. package/esm2022/tiered-menu/lib/tiered-menu/tiered-menu.directive.mjs +11 -3
  54. package/esm2022/tooltip/lib/tooltip/tooltip.component.mjs +17 -11
  55. package/esm2022/tooltip/lib/tooltip/tooltip.directive.mjs +108 -241
  56. package/esm2022/tooltip/lib/tooltip/tooltip.module.mjs +4 -6
  57. package/esm2022/topbar/lib/topbar/topbar.component.mjs +2 -2
  58. package/fesm2022/seniorsistemas-angular-components-accordion.mjs +1 -1
  59. package/fesm2022/seniorsistemas-angular-components-accordion.mjs.map +1 -1
  60. package/fesm2022/seniorsistemas-angular-components-breadcrumb.mjs +9 -7
  61. package/fesm2022/seniorsistemas-angular-components-breadcrumb.mjs.map +1 -1
  62. package/fesm2022/seniorsistemas-angular-components-button.mjs +19 -7
  63. package/fesm2022/seniorsistemas-angular-components-button.mjs.map +1 -1
  64. package/fesm2022/seniorsistemas-angular-components-checkbox.mjs +7 -4
  65. package/fesm2022/seniorsistemas-angular-components-checkbox.mjs.map +1 -1
  66. package/fesm2022/seniorsistemas-angular-components-confirm-dialog.mjs +1 -1
  67. package/fesm2022/seniorsistemas-angular-components-confirm-dialog.mjs.map +1 -1
  68. package/fesm2022/seniorsistemas-angular-components-content-generator.mjs +1 -1
  69. package/fesm2022/seniorsistemas-angular-components-content-generator.mjs.map +1 -1
  70. package/fesm2022/seniorsistemas-angular-components-dialog.mjs +8 -2
  71. package/fesm2022/seniorsistemas-angular-components-dialog.mjs.map +1 -1
  72. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +11 -11
  73. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
  74. package/fesm2022/seniorsistemas-angular-components-empty-state.mjs +1 -1
  75. package/fesm2022/seniorsistemas-angular-components-empty-state.mjs.map +1 -1
  76. package/fesm2022/seniorsistemas-angular-components-file-picker.mjs +1 -1
  77. package/fesm2022/seniorsistemas-angular-components-file-picker.mjs.map +1 -1
  78. package/fesm2022/seniorsistemas-angular-components-global-search.mjs +2 -2
  79. package/fesm2022/seniorsistemas-angular-components-global-search.mjs.map +1 -1
  80. package/fesm2022/seniorsistemas-angular-components-help-popover.mjs +1 -1
  81. package/fesm2022/seniorsistemas-angular-components-help-popover.mjs.map +1 -1
  82. package/fesm2022/seniorsistemas-angular-components-image-cropper.mjs +1 -1
  83. package/fesm2022/seniorsistemas-angular-components-image-cropper.mjs.map +1 -1
  84. package/fesm2022/seniorsistemas-angular-components-inline-edit.mjs +2 -2
  85. package/fesm2022/seniorsistemas-angular-components-inline-edit.mjs.map +1 -1
  86. package/fesm2022/seniorsistemas-angular-components-kanban.mjs +2 -2
  87. package/fesm2022/seniorsistemas-angular-components-kanban.mjs.map +1 -1
  88. package/fesm2022/seniorsistemas-angular-components-navigation-button.mjs +1 -1
  89. package/fesm2022/seniorsistemas-angular-components-navigation-button.mjs.map +1 -1
  90. package/fesm2022/seniorsistemas-angular-components-object-card.mjs +2 -2
  91. package/fesm2022/seniorsistemas-angular-components-object-card.mjs.map +1 -1
  92. package/fesm2022/seniorsistemas-angular-components-paginator.mjs +1 -1
  93. package/fesm2022/seniorsistemas-angular-components-paginator.mjs.map +1 -1
  94. package/fesm2022/seniorsistemas-angular-components-picklist.mjs +1 -1
  95. package/fesm2022/seniorsistemas-angular-components-picklist.mjs.map +1 -1
  96. package/fesm2022/seniorsistemas-angular-components-profile-picture-picker.mjs +1 -1
  97. package/fesm2022/seniorsistemas-angular-components-profile-picture-picker.mjs.map +1 -1
  98. package/fesm2022/seniorsistemas-angular-components-select.mjs +133 -21
  99. package/fesm2022/seniorsistemas-angular-components-select.mjs.map +1 -1
  100. package/fesm2022/seniorsistemas-angular-components-shared.mjs +354 -2
  101. package/fesm2022/seniorsistemas-angular-components-shared.mjs.map +1 -1
  102. package/fesm2022/seniorsistemas-angular-components-switch.mjs +18 -7
  103. package/fesm2022/seniorsistemas-angular-components-switch.mjs.map +1 -1
  104. package/fesm2022/seniorsistemas-angular-components-table.mjs +2 -2
  105. package/fesm2022/seniorsistemas-angular-components-table.mjs.map +1 -1
  106. package/fesm2022/seniorsistemas-angular-components-tiered-menu.mjs +26 -8
  107. package/fesm2022/seniorsistemas-angular-components-tiered-menu.mjs.map +1 -1
  108. package/fesm2022/seniorsistemas-angular-components-tooltip.mjs +125 -254
  109. package/fesm2022/seniorsistemas-angular-components-tooltip.mjs.map +1 -1
  110. package/fesm2022/seniorsistemas-angular-components-topbar.mjs +2 -2
  111. package/fesm2022/seniorsistemas-angular-components-topbar.mjs.map +1 -1
  112. package/fesm2022/seniorsistemas-angular-components.mjs +12 -1
  113. package/fesm2022/seniorsistemas-angular-components.mjs.map +1 -1
  114. package/package.json +1 -1
  115. package/select/lib/select/select.component.d.ts +23 -2
  116. package/shared/lib/accessibility/paginator-accessibility.directive.d.ts +30 -0
  117. package/shared/lib/accessibility/table-checkbox-accessibility.directive.d.ts +46 -0
  118. package/shared/public-api.d.ts +7 -5
  119. package/switch/lib/switch/switch.component.d.ts +9 -5
  120. package/table/public-api.d.ts +1 -0
  121. package/tiered-menu/lib/tiered-menu/components/tiered-menu/tiered-menu.component.d.ts +1 -0
  122. package/tiered-menu/lib/tiered-menu/tiered-menu.directive.d.ts +4 -2
  123. package/tooltip/lib/tooltip/tooltip.component.d.ts +13 -7
  124. package/tooltip/lib/tooltip/tooltip.directive.d.ts +27 -40
  125. package/tooltip/lib/tooltip/tooltip.module.d.ts +3 -4
@@ -1,18 +1,18 @@
1
- import * as i5 from '@angular/cdk/overlay';
1
+ import * as i4 from '@angular/cdk/overlay';
2
2
  import { OverlayModule } from '@angular/cdk/overlay';
3
- import * as i3 from '@angular/cdk/scrolling';
3
+ import * as i2 from '@angular/cdk/scrolling';
4
4
  import { ScrollingModule } from '@angular/cdk/scrolling';
5
- import * as i1 from '@angular/common';
6
5
  import { CommonModule } from '@angular/common';
7
6
  import * as i0 from '@angular/core';
8
7
  import { input, model, output, Component, signal, computed, viewChild, inject, effect, forwardRef } from '@angular/core';
9
8
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
- import * as i2 from '@angular/forms';
9
+ import * as i1 from '@angular/forms';
11
10
  import { FormGroup, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
12
- import * as i4 from '@ngx-translate/core';
11
+ import * as i3 from '@ngx-translate/core';
13
12
  import { TranslateService, TranslateModule } from '@ngx-translate/core';
14
13
  import { CheckboxComponent } from '@seniorsistemas/angular-components/checkbox';
15
14
  import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
15
+ import { trigger, state, style, transition, animate } from '@angular/animations';
16
16
 
17
17
  class SelectOptionComponent {
18
18
  id = input.required();
@@ -30,11 +30,11 @@ class SelectOptionComponent {
30
30
  this.selected.emit();
31
31
  }
32
32
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectOptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SelectOptionComponent, isStandalone: true, selector: "s-select-option", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: true, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: true, transformFunction: null }, isGrouper: { classPropertyName: "isGrouper", publicName: "isGrouper", isSignal: true, isRequired: true, transformFunction: null }, isFocused: { classPropertyName: "isFocused", publicName: "isFocused", isSignal: true, isRequired: true, transformFunction: null }, isSelected: { classPropertyName: "isSelected", publicName: "isSelected", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { isSelected: "isSelectedChange", selected: "selected" }, ngImport: i0, template: "<li\n [attr.id]=\"id()\"\n class=\"flex select-none items-center gap-3 px-3 py-2\"\n [class.hover:bg-grayscale-10]=\"!isGrouper()\"\n [class.bg-grayscale-10]=\"!isGrouper() && isFocused()\"\n (click)=\"onClick()\"\n>\n @if (!isGrouper() && checkmark() && !multiple() && isSelected()) {\n <i class=\"far fa-check text-grayscale-60\"></i>\n }\n\n @if (!isGrouper() && multiple()) {\n <s-checkbox [checked]=\"isSelected()\"></s-checkbox>\n }\n <span\n class=\"text-grayscale-90\"\n [class.font-bold]=\"isGrouper()\"\n >\n {{ label() }}\n </span>\n</li>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CheckboxComponent, selector: "s-checkbox", inputs: ["disabled", "checked", "indeterminate", "label"], outputs: ["disabledChange", "checkedChange"] }] });
33
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SelectOptionComponent, isStandalone: true, selector: "s-select-option", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: true, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: true, transformFunction: null }, isGrouper: { classPropertyName: "isGrouper", publicName: "isGrouper", isSignal: true, isRequired: true, transformFunction: null }, isFocused: { classPropertyName: "isFocused", publicName: "isFocused", isSignal: true, isRequired: true, transformFunction: null }, isSelected: { classPropertyName: "isSelected", publicName: "isSelected", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { isSelected: "isSelectedChange", selected: "selected" }, ngImport: i0, template: "<div\n [attr.id]=\"id()\"\n [attr.role]=\"isGrouper() ? 'presentation' : 'option'\"\n [attr.aria-selected]=\"isGrouper() ? null : isSelected()\"\n class=\"flex select-none items-center gap-3 px-3 py-2\"\n [class.hover:bg-grayscale-10]=\"!isGrouper()\"\n [class.bg-grayscale-10]=\"!isGrouper() && isFocused()\"\n (click)=\"onClick()\"\n (keydown.enter)=\"onClick()\"\n (keydown.space)=\"onClick(); $event.preventDefault()\"\n>\n @if (!isGrouper() && checkmark() && !multiple() && isSelected()) {\n <i\n class=\"far fa-check text-grayscale-60\"\n aria-hidden=\"true\"\n ></i>\n }\n\n @if (!isGrouper() && multiple()) {\n <s-checkbox [checked]=\"isSelected()\"></s-checkbox>\n }\n <span\n [class]=\"isSelected() ? 'text-[#428BCA]' : 'text-grayscale-90'\"\n [class.font-bold]=\"isGrouper()\"\n >\n {{ label() }}\n </span>\n</div>\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CheckboxComponent, selector: "s-checkbox", inputs: ["disabled", "checked", "indeterminate", "label", "ariaLabel", "ariaLabelledBy"], outputs: ["disabledChange", "checkedChange"] }] });
34
34
  }
35
35
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectOptionComponent, decorators: [{
36
36
  type: Component,
37
- args: [{ selector: 's-select-option', standalone: true, imports: [CommonModule, CheckboxComponent], template: "<li\n [attr.id]=\"id()\"\n class=\"flex select-none items-center gap-3 px-3 py-2\"\n [class.hover:bg-grayscale-10]=\"!isGrouper()\"\n [class.bg-grayscale-10]=\"!isGrouper() && isFocused()\"\n (click)=\"onClick()\"\n>\n @if (!isGrouper() && checkmark() && !multiple() && isSelected()) {\n <i class=\"far fa-check text-grayscale-60\"></i>\n }\n\n @if (!isGrouper() && multiple()) {\n <s-checkbox [checked]=\"isSelected()\"></s-checkbox>\n }\n <span\n class=\"text-grayscale-90\"\n [class.font-bold]=\"isGrouper()\"\n >\n {{ label() }}\n </span>\n</li>\n" }]
37
+ args: [{ selector: 's-select-option', standalone: true, imports: [CommonModule, CheckboxComponent], template: "<div\n [attr.id]=\"id()\"\n [attr.role]=\"isGrouper() ? 'presentation' : 'option'\"\n [attr.aria-selected]=\"isGrouper() ? null : isSelected()\"\n class=\"flex select-none items-center gap-3 px-3 py-2\"\n [class.hover:bg-grayscale-10]=\"!isGrouper()\"\n [class.bg-grayscale-10]=\"!isGrouper() && isFocused()\"\n (click)=\"onClick()\"\n (keydown.enter)=\"onClick()\"\n (keydown.space)=\"onClick(); $event.preventDefault()\"\n>\n @if (!isGrouper() && checkmark() && !multiple() && isSelected()) {\n <i\n class=\"far fa-check text-grayscale-60\"\n aria-hidden=\"true\"\n ></i>\n }\n\n @if (!isGrouper() && multiple()) {\n <s-checkbox [checked]=\"isSelected()\"></s-checkbox>\n }\n <span\n [class]=\"isSelected() ? 'text-[#428BCA]' : 'text-grayscale-90'\"\n [class.font-bold]=\"isGrouper()\"\n >\n {{ label() }}\n </span>\n</div>\n\n" }]
38
38
  }] });
39
39
 
40
40
  /**
@@ -88,11 +88,16 @@ class SelectComponent {
88
88
  disabled = model(false);
89
89
  /** @description Controla a visibilidade do painel de opções via two-way binding. @default false */
90
90
  showOptions = model(false);
91
+ /** @description Label de acessibilidade do componente. @default '' */
92
+ ariaLabel = input('');
93
+ /** @description ID do elemento externo que descreve o componente (aria-labelledby). @default '' */
94
+ ariaLabelledBy = input('');
91
95
  value = signal(null);
92
96
  values = signal([]);
93
97
  filterValue = signal('');
94
98
  focusedIndex = signal(-1);
95
99
  _pendingValue = null;
100
+ isOpen = false;
96
101
  componentId = `select${SelectComponent.nextId++}`;
97
102
  /**
98
103
  * Computed que indica se todas as opções filtradas estão selecionadas.
@@ -116,6 +121,16 @@ class SelectComponent {
116
121
  return null;
117
122
  return this.filteredOptions()[index]?.data ?? null;
118
123
  });
124
+ /**
125
+ * Retorna o item atualmente focado na lista de opções filtradas.
126
+ * @returns O dado do item focado ou `null` caso nenhum item esteja focado.
127
+ */
128
+ focusedOptionId = computed(() => {
129
+ const index = this.focusedIndex();
130
+ if (index < 0)
131
+ return null;
132
+ return this.filteredOptions()[index]?.id ?? null;
133
+ });
119
134
  /**
120
135
  * Computa e retorna a lista interna de opções do dropdown.
121
136
  * - Se as opções estiverem agrupadas (`group()` retorna verdadeiro),
@@ -214,6 +229,8 @@ class SelectComponent {
214
229
  filter: new FormControl('', { nonNullable: true }),
215
230
  });
216
231
  _containerDiv = viewChild('containerDiv');
232
+ _filterInput = viewChild('filterInput');
233
+ _selectAllCheckbox = viewChild('selectAllCheckbox');
217
234
  _onChange = () => { };
218
235
  _onTouched = () => { };
219
236
  _translateService = inject(TranslateService);
@@ -322,9 +339,27 @@ class SelectComponent {
322
339
  return;
323
340
  }
324
341
  const shouldOpen = !this.showOptions();
342
+ this.isOpen = shouldOpen;
325
343
  this.showOptions.set(shouldOpen);
326
344
  if (shouldOpen) {
327
- this._focusSelectedOption();
345
+ if (this.filter()) {
346
+ // Quando há filtro com múltipla seleção, foco vai para o checkbox primeiro;
347
+ // caso contrário, vai direto para o input de filtro.
348
+ // O foco é movido após a renderização do overlay.
349
+ setTimeout(() => {
350
+ if (this.multiple()) {
351
+ const checkboxHost = this._selectAllCheckbox()?.nativeElement;
352
+ const focusable = checkboxHost?.querySelector('[tabindex]');
353
+ focusable?.focus();
354
+ }
355
+ else {
356
+ this._filterInput()?.nativeElement.focus();
357
+ }
358
+ });
359
+ }
360
+ else {
361
+ this._focusSelectedOption();
362
+ }
328
363
  }
329
364
  }
330
365
  /**
@@ -360,6 +395,7 @@ class SelectComponent {
360
395
  const result = optionValue ? item.data[optionValue] : item.data;
361
396
  this._onChange(result);
362
397
  this._closeDropdown();
398
+ this._containerDiv()?.nativeElement.focus();
363
399
  }
364
400
  this._onTouched();
365
401
  }
@@ -415,6 +451,54 @@ class SelectComponent {
415
451
  this.toggle();
416
452
  this._containerDiv()?.nativeElement.focus();
417
453
  }
454
+ /**
455
+ * Manipula eventos de teclado no input de filtro do overlay.
456
+ * - 'ArrowDown': Move o foco para a primeira opção da lista.
457
+ * - 'ArrowUp': Move o foco para a última opção da lista.
458
+ * - 'Escape': Fecha o dropdown e retorna o foco ao combobox.
459
+ * - 'Enter': Seleciona a opção focada, se houver.
460
+ * @param event O evento de teclado disparado no input de filtro.
461
+ */
462
+ onFilterKeyDown(event) {
463
+ const options = this.filteredOptions();
464
+ switch (event.key) {
465
+ case 'ArrowDown':
466
+ event.preventDefault();
467
+ this._focusNextOption(options);
468
+ break;
469
+ case 'ArrowUp':
470
+ event.preventDefault();
471
+ if (options.length > 0) {
472
+ if (this.focusedIndex() < 0) {
473
+ // Nenhum item focado: foca o último disponível
474
+ let lastIndex = options.length - 1;
475
+ while (lastIndex >= 0 && options[lastIndex].grouper) {
476
+ lastIndex--;
477
+ }
478
+ if (lastIndex >= 0) {
479
+ this.focusedIndex.set(lastIndex);
480
+ this._scrollToFocusedOption();
481
+ }
482
+ }
483
+ else {
484
+ this._focusPreviousOption(options);
485
+ }
486
+ }
487
+ break;
488
+ case 'Escape':
489
+ event.preventDefault();
490
+ event.stopPropagation();
491
+ this._closeDropdown();
492
+ this._containerDiv()?.nativeElement.focus();
493
+ break;
494
+ case 'Enter':
495
+ if (this.focusedIndex() >= 0 && this.focusedIndex() < options.length) {
496
+ event.preventDefault();
497
+ this.selectItem(options[this.focusedIndex()]);
498
+ }
499
+ break;
500
+ }
501
+ }
418
502
  /**
419
503
  * Manipula eventos de teclado para navegação e seleção de opções no componente select.
420
504
  * - 'ArrowDown': Move o foco para a próxima opção disponível.
@@ -428,7 +512,7 @@ class SelectComponent {
428
512
  */
429
513
  onKeyDown(event) {
430
514
  const options = this.filteredOptions();
431
- if (!options.length) {
515
+ if (!options.length && event.key !== 'Escape' && event.key !== 'Enter' && event.key !== ' ') {
432
516
  return;
433
517
  }
434
518
  const _selectOption = () => {
@@ -440,13 +524,24 @@ class SelectComponent {
440
524
  switch (event.key) {
441
525
  case 'ArrowDown':
442
526
  event.preventDefault();
443
- this._focusNextOption(options);
527
+ if (!this.showOptions()) {
528
+ this.toggle();
529
+ }
530
+ else {
531
+ this._focusNextOption(options);
532
+ }
444
533
  break;
445
534
  case 'ArrowUp':
446
535
  event.preventDefault();
447
- this._focusPreviousOption(options);
536
+ if (this.showOptions()) {
537
+ this._focusPreviousOption(options);
538
+ }
448
539
  break;
449
540
  case 'Tab':
541
+ // Quando há filtro aberto, Tab deve navegar para dentro do overlay (não fechar)
542
+ if (this.showOptions() && this.filter()) {
543
+ return;
544
+ }
450
545
  _selectOption();
451
546
  this._closeDropdown();
452
547
  break;
@@ -459,6 +554,10 @@ class SelectComponent {
459
554
  }
460
555
  break;
461
556
  case 'Escape':
557
+ if (this.showOptions()) {
558
+ event.preventDefault();
559
+ event.stopPropagation();
560
+ }
462
561
  this._closeDropdown();
463
562
  break;
464
563
  case ' ':
@@ -685,13 +784,23 @@ class SelectComponent {
685
784
  }
686
785
  }
687
786
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
688
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SelectComponent, isStandalone: true, selector: "s-select", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: false, transformFunction: null }, filterBy: { classPropertyName: "filterBy", publicName: "filterBy", isSignal: true, isRequired: false, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showOptions: { classPropertyName: "showOptions", publicName: "showOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", showOptions: "showOptionsChange" }, host: { attributes: { "role": "combobox" }, listeners: { "window:resize": "onWindowResize($event)" }, properties: { "attr.aria-expanded": "showOptions()", "attr.aria-haspopup": "\"listbox\"", "attr.aria-owns": "showOptions() ? componentId + \"-listbox\" : null", "attr.aria-activedescendant": "focusedIndex() >= 0 ? filteredOptions()[focusedIndex()]?.id : null", "attr.aria-label": "placeholder() || \"Select option\"", "attr.aria-disabled": "disabled()" } }, providers: [
787
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SelectComponent, isStandalone: true, selector: "s-select", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: false, transformFunction: null }, filterBy: { classPropertyName: "filterBy", publicName: "filterBy", isSignal: true, isRequired: false, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showOptions: { classPropertyName: "showOptions", publicName: "showOptions", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", showOptions: "showOptionsChange" }, host: { listeners: { "window:resize": "onWindowResize($event)" } }, providers: [
689
788
  {
690
789
  provide: NG_VALUE_ACCESSOR,
691
790
  useExisting: forwardRef(() => SelectComponent),
692
791
  multi: true,
693
792
  },
694
- ], viewQueries: [{ propertyName: "_containerDiv", first: true, predicate: ["containerDiv"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #containerDiv\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"select-container group flex h-[35px] w-full overflow-hidden rounded-[3px] border outline-1 outline-primary focus:outline\"\n [ngClass]=\"{\n 'pointer-events-none border-grayscale-20 bg-grayscale-5': disabled(),\n 'pointer-events-auto border-grayscale-30 bg-grayscale-0': !disabled(),\n }\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"showOptions()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-owns]=\"'dropdown-container-' + componentId\"\n [attr.aria-labelledby]=\"componentId + '-label'\"\n role=\"combobox\"\n (click)=\"onContainerDivClick()\"\n (keydown)=\"onKeyDown($event)\"\n tabindex=\"0\"\n>\n <span\n class=\"flex flex-grow select-none px-3 py-[7px]\"\n [ngClass]=\"{\n 'text-grayscale-90': !disabled() && !isClean(),\n 'text-grayscale-60': !disabled() && isClean(),\n 'text-grayscale-30': disabled(),\n }\"\n >\n {{ print() || placeholder() }}\n </span>\n\n @if (!disabled() && showClear() && !isClean()) {\n <button\n class=\"mx-3\"\n (click)=\"clear($event)\"\n >\n <i class=\"fas fa-times flex items-center\"></i>\n </button>\n }\n\n <div\n class=\"dropdown-container flex items-center border-l px-3 group-hover:bg-grayscale-10 group-focus:border-primary\"\n [ngClass]=\"{ 'border-grayscale-20': disabled(), 'border-grayscale-30': !disabled() }\"\n >\n <i\n class=\"fas\"\n [ngClass]=\"{\n 'text-grayscale-30': disabled(),\n 'text-grayscale-90': !disabled(),\n 'fa-caret-down': !showOptions(),\n 'fa-caret-up': showOptions(),\n }\"\n ></i>\n </div>\n</div>\n\n<ng-template\n #dropdownTemplate\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"showOptions()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n (backdropClick)=\"showOptions.set(false)\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (detach)=\"showOptions.set(false)\"\n>\n <div\n [id]=\"'dropdown-container-' + componentId\"\n class=\"dropdown-body-class z-[1000] rounded-[3px] bg-grayscale-0 py-1 shadow-md\"\n (click)=\"$event.stopPropagation()\"\n [style.width.px]=\"containerDiv.offsetWidth\"\n >\n @if (filter()) {\n <div class=\"flex w-full items-center gap-3 px-3 py-1.5\">\n @if (multiple()) {\n <s-checkbox\n #selectAllCheckbox\n [checked]=\"allSelected()\"\n [indeterminate]=\"selectAllIsIndeterminate()\"\n (checkedChange)=\"toggleSelectAll()\"\n ></s-checkbox>\n }\n\n <div class=\"relative flex h-[35px] grow\">\n <form\n class=\"flex grow\"\n [formGroup]=\"filterForm\"\n >\n <input\n class=\"w-full grow rounded-[3px] border border-grayscale-30 pl-2.5 pr-7 outline-1 outline-primary\"\n type=\"text\"\n formControlName=\"filter\"\n (click)=\"$event.stopPropagation()\"\n />\n </form>\n <i class=\"fas fa-search absolute right-2.5 top-2.5 text-grayscale-90\"></i>\n </div>\n <button (click)=\"clearFilter()\">\n <i class=\"fas fa-times flex items-center\"></i>\n </button>\n </div>\n }\n\n <!-- Virtual scroll -->\n @if (virtualScroll() && filteredOptions().length > 10) {\n <cdk-virtual-scroll-viewport\n [itemSize]=\"virtualScrollItemSize()\"\n class=\"h-52 overflow-auto\"\n >\n <ng-container *cdkVirtualFor=\"let option of filteredOptions(); trackBy: trackById\">\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Normal list -->\n @if (!virtualScroll() || filteredOptions().length <= 10) {\n <ul class=\"max-h-52 overflow-auto\">\n @for (option of filteredOptions(); track option.id) {\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper ?? false\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n }\n </ul>\n }\n\n @if (filteredOptions().length === 0) {\n <span class=\"m-3 text-grayscale-60\">{{\n emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n }}</span>\n }\n </div>\n</ng-template>\n\n", styles: [":host.ng-dirty.ng-invalid{.dropdown-container,.select-container{border-color:#c13018;outline:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: SelectOptionComponent, selector: "s-select-option", inputs: ["id", "label", "multiple", "checkmark", "isGrouper", "isFocused", "isSelected"], outputs: ["isSelectedChange", "selected"] }, { kind: "component", type: CheckboxComponent, selector: "s-checkbox", inputs: ["disabled", "checked", "indeterminate", "label"], outputs: ["disabledChange", "checkedChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5.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: i5.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
793
+ ], viewQueries: [{ propertyName: "_containerDiv", first: true, predicate: ["containerDiv"], descendants: true, isSignal: true }, { propertyName: "_filterInput", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }, { propertyName: "_selectAllCheckbox", first: true, predicate: ["selectAllCheckbox"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #containerDiv\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"select-container group flex h-[35px] w-full overflow-hidden rounded-[3px] border outline-1 outline-primary focus:outline\"\n [class.pointer-events-none]=\"disabled()\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.bg-grayscale-5]=\"disabled()\"\n [class.pointer-events-auto]=\"!disabled()\"\n [class.border-grayscale-30]=\"!disabled()\"\n [class.bg-grayscale-0]=\"!disabled()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"showOptions()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"componentId + '-listbox'\"\n [attr.aria-owns]=\"showOptions() ? componentId + '-listbox' : null\"\n [attr.aria-activedescendant]=\"showOptions() ? focusedOptionId() : null\"\n role=\"combobox\"\n (click)=\"onContainerDivClick()\"\n (keydown)=\"onKeyDown($event)\"\n tabindex=\"0\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n>\n <span\n class=\"flex flex-grow select-none px-3 py-[7px]\"\n [class.text-grayscale-90]=\"!disabled() && !isClean()\"\n [class.text-grayscale-60]=\"!disabled() && isClean()\"\n [class.text-grayscale-30]=\"disabled()\"\n >\n {{ print() || placeholder() }}\n </span>\n\n @if (!disabled() && showClear() && !isClean()) {\n <button\n class=\"mx-3\"\n (click)=\"clear($event)\"\n [attr.aria-label]=\"'platform.angular_components.aria_clear_selection' | translate\"\n >\n <i\n class=\"fas fa-times flex items-center\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n <div\n class=\"dropdown-container flex items-center border-l px-3 group-hover:bg-grayscale-10 group-focus:border-primary\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.border-grayscale-30]=\"!disabled()\"\n >\n <i\n class=\"fas\"\n aria-hidden=\"true\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.fa-caret-down]=\"!showOptions()\"\n [class.fa-caret-up]=\"showOptions()\"\n ></i>\n </div>\n</div>\n\n<ng-template\n #dropdownTemplate\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"showOptions()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n (backdropClick)=\"showOptions.set(false)\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (detach)=\"showOptions.set(false)\"\n>\n <div\n [id]=\"componentId + '-listbox'\"\n class=\"dropdown-body-class z-[1000] rounded-[3px] bg-grayscale-0 py-1 shadow-md\"\n (click)=\"$event.stopPropagation()\"\n [style.width.px]=\"containerDiv.offsetWidth\"\n [attr.aria-multiselectable]=\"multiple() ? true : null\"\n [@visibilityChanged]\n role=\"listbox\"\n >\n @if (filter()) {\n <div class=\"flex w-full items-center gap-3 px-3 py-1.5\">\n @if (multiple()) {\n <s-checkbox\n #selectAllCheckbox\n [checked]=\"allSelected()\"\n [indeterminate]=\"selectAllIsIndeterminate()\"\n (checkedChange)=\"toggleSelectAll()\"\n ></s-checkbox>\n }\n\n <div class=\"relative flex h-[35px] grow\">\n <form\n class=\"flex w-full grow\"\n [formGroup]=\"filterForm\"\n >\n <input\n #filterInput\n class=\"w-full grow rounded-[3px] border border-grayscale-30 pl-2.5 pr-7 outline-1 outline-primary\"\n type=\"text\"\n formControlName=\"filter\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"onFilterKeyDown($event)\"\n [attr.aria-label]=\"'platform.angular_components.filter_options' | translate\"\n [attr.aria-controls]=\"componentId + '-listbox'\"\n [attr.aria-activedescendant]=\"focusedOptionId()\"\n autocomplete=\"off\"\n />\n </form>\n <i\n class=\"fas fa-search absolute right-2.5 top-2.5 text-grayscale-90\"\n aria-hidden=\"true\"\n ></i>\n </div>\n <button\n (click)=\"clearFilter()\"\n [attr.aria-label]=\"'platform.angular_components.clear_filter' | translate\"\n >\n <i\n class=\"fas fa-times flex items-center\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n }\n\n <!-- Virtual scroll -->\n @if (virtualScroll() && filteredOptions().length > 10) {\n <cdk-virtual-scroll-viewport\n [itemSize]=\"virtualScrollItemSize()\"\n class=\"h-52 overflow-auto\"\n >\n <ng-container *cdkVirtualFor=\"let option of filteredOptions(); trackBy: trackById\">\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper ?? false\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Normal list -->\n @if (!virtualScroll() || filteredOptions().length <= 10) {\n <ul class=\"max-h-52 overflow-auto\">\n @for (option of filteredOptions(); track option.id) {\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper ?? false\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n }\n </ul>\n }\n\n @if (filteredOptions().length === 0) {\n <span class=\"m-3 text-grayscale-60\">{{\n emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n }}</span>\n }\n </div>\n</ng-template>\n\n", styles: [":host.ng-dirty.ng-invalid{.dropdown-container,.select-container{border-color:#c13018;outline:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: SelectOptionComponent, selector: "s-select-option", inputs: ["id", "label", "multiple", "checkmark", "isGrouper", "isFocused", "isSelected"], outputs: ["isSelectedChange", "selected"] }, { kind: "component", type: CheckboxComponent, selector: "s-checkbox", inputs: ["disabled", "checked", "indeterminate", "label", "ariaLabel", "ariaLabelledBy"], outputs: ["disabledChange", "checkedChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i4.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: i4.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], animations: [
794
+ trigger('visibilityChanged', [
795
+ state('void', style({ opacity: 0, transform: 'scale(0.95)' })),
796
+ transition(':enter', [
797
+ animate('500ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 1, transform: 'scale(1)' })),
798
+ ]),
799
+ transition(':leave', [
800
+ animate('500ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'scale(0.95)' })),
801
+ ]),
802
+ ]),
803
+ ] });
695
804
  }
696
805
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectComponent, decorators: [{
697
806
  type: Component,
@@ -705,20 +814,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
705
814
  OverlayModule,
706
815
  ], host: {
707
816
  '(window:resize)': 'onWindowResize($event)',
708
- '[attr.aria-expanded]': 'showOptions()',
709
- '[attr.aria-haspopup]': '"listbox"',
710
- '[attr.aria-owns]': 'showOptions() ? componentId + "-listbox" : null',
711
- '[attr.aria-activedescendant]': 'focusedIndex() >= 0 ? filteredOptions()[focusedIndex()]?.id : null',
712
- '[attr.aria-label]': 'placeholder() || "Select option"',
713
- '[attr.aria-disabled]': 'disabled()',
714
- role: 'combobox',
715
817
  }, providers: [
716
818
  {
717
819
  provide: NG_VALUE_ACCESSOR,
718
820
  useExisting: forwardRef(() => SelectComponent),
719
821
  multi: true,
720
822
  },
721
- ], template: "<div\n #containerDiv\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"select-container group flex h-[35px] w-full overflow-hidden rounded-[3px] border outline-1 outline-primary focus:outline\"\n [ngClass]=\"{\n 'pointer-events-none border-grayscale-20 bg-grayscale-5': disabled(),\n 'pointer-events-auto border-grayscale-30 bg-grayscale-0': !disabled(),\n }\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"showOptions()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-owns]=\"'dropdown-container-' + componentId\"\n [attr.aria-labelledby]=\"componentId + '-label'\"\n role=\"combobox\"\n (click)=\"onContainerDivClick()\"\n (keydown)=\"onKeyDown($event)\"\n tabindex=\"0\"\n>\n <span\n class=\"flex flex-grow select-none px-3 py-[7px]\"\n [ngClass]=\"{\n 'text-grayscale-90': !disabled() && !isClean(),\n 'text-grayscale-60': !disabled() && isClean(),\n 'text-grayscale-30': disabled(),\n }\"\n >\n {{ print() || placeholder() }}\n </span>\n\n @if (!disabled() && showClear() && !isClean()) {\n <button\n class=\"mx-3\"\n (click)=\"clear($event)\"\n >\n <i class=\"fas fa-times flex items-center\"></i>\n </button>\n }\n\n <div\n class=\"dropdown-container flex items-center border-l px-3 group-hover:bg-grayscale-10 group-focus:border-primary\"\n [ngClass]=\"{ 'border-grayscale-20': disabled(), 'border-grayscale-30': !disabled() }\"\n >\n <i\n class=\"fas\"\n [ngClass]=\"{\n 'text-grayscale-30': disabled(),\n 'text-grayscale-90': !disabled(),\n 'fa-caret-down': !showOptions(),\n 'fa-caret-up': showOptions(),\n }\"\n ></i>\n </div>\n</div>\n\n<ng-template\n #dropdownTemplate\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"showOptions()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n (backdropClick)=\"showOptions.set(false)\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (detach)=\"showOptions.set(false)\"\n>\n <div\n [id]=\"'dropdown-container-' + componentId\"\n class=\"dropdown-body-class z-[1000] rounded-[3px] bg-grayscale-0 py-1 shadow-md\"\n (click)=\"$event.stopPropagation()\"\n [style.width.px]=\"containerDiv.offsetWidth\"\n >\n @if (filter()) {\n <div class=\"flex w-full items-center gap-3 px-3 py-1.5\">\n @if (multiple()) {\n <s-checkbox\n #selectAllCheckbox\n [checked]=\"allSelected()\"\n [indeterminate]=\"selectAllIsIndeterminate()\"\n (checkedChange)=\"toggleSelectAll()\"\n ></s-checkbox>\n }\n\n <div class=\"relative flex h-[35px] grow\">\n <form\n class=\"flex grow\"\n [formGroup]=\"filterForm\"\n >\n <input\n class=\"w-full grow rounded-[3px] border border-grayscale-30 pl-2.5 pr-7 outline-1 outline-primary\"\n type=\"text\"\n formControlName=\"filter\"\n (click)=\"$event.stopPropagation()\"\n />\n </form>\n <i class=\"fas fa-search absolute right-2.5 top-2.5 text-grayscale-90\"></i>\n </div>\n <button (click)=\"clearFilter()\">\n <i class=\"fas fa-times flex items-center\"></i>\n </button>\n </div>\n }\n\n <!-- Virtual scroll -->\n @if (virtualScroll() && filteredOptions().length > 10) {\n <cdk-virtual-scroll-viewport\n [itemSize]=\"virtualScrollItemSize()\"\n class=\"h-52 overflow-auto\"\n >\n <ng-container *cdkVirtualFor=\"let option of filteredOptions(); trackBy: trackById\">\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Normal list -->\n @if (!virtualScroll() || filteredOptions().length <= 10) {\n <ul class=\"max-h-52 overflow-auto\">\n @for (option of filteredOptions(); track option.id) {\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper ?? false\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n }\n </ul>\n }\n\n @if (filteredOptions().length === 0) {\n <span class=\"m-3 text-grayscale-60\">{{\n emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n }}</span>\n }\n </div>\n</ng-template>\n\n", styles: [":host.ng-dirty.ng-invalid{.dropdown-container,.select-container{border-color:#c13018;outline:none}}\n"] }]
823
+ ], animations: [
824
+ trigger('visibilityChanged', [
825
+ state('void', style({ opacity: 0, transform: 'scale(0.95)' })),
826
+ transition(':enter', [
827
+ animate('500ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 1, transform: 'scale(1)' })),
828
+ ]),
829
+ transition(':leave', [
830
+ animate('500ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'scale(0.95)' })),
831
+ ]),
832
+ ]),
833
+ ], template: "<div\n #containerDiv\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"select-container group flex h-[35px] w-full overflow-hidden rounded-[3px] border outline-1 outline-primary focus:outline\"\n [class.pointer-events-none]=\"disabled()\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.bg-grayscale-5]=\"disabled()\"\n [class.pointer-events-auto]=\"!disabled()\"\n [class.border-grayscale-30]=\"!disabled()\"\n [class.bg-grayscale-0]=\"!disabled()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-expanded]=\"showOptions()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"componentId + '-listbox'\"\n [attr.aria-owns]=\"showOptions() ? componentId + '-listbox' : null\"\n [attr.aria-activedescendant]=\"showOptions() ? focusedOptionId() : null\"\n role=\"combobox\"\n (click)=\"onContainerDivClick()\"\n (keydown)=\"onKeyDown($event)\"\n tabindex=\"0\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy() || null\"\n>\n <span\n class=\"flex flex-grow select-none px-3 py-[7px]\"\n [class.text-grayscale-90]=\"!disabled() && !isClean()\"\n [class.text-grayscale-60]=\"!disabled() && isClean()\"\n [class.text-grayscale-30]=\"disabled()\"\n >\n {{ print() || placeholder() }}\n </span>\n\n @if (!disabled() && showClear() && !isClean()) {\n <button\n class=\"mx-3\"\n (click)=\"clear($event)\"\n [attr.aria-label]=\"'platform.angular_components.aria_clear_selection' | translate\"\n >\n <i\n class=\"fas fa-times flex items-center\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n <div\n class=\"dropdown-container flex items-center border-l px-3 group-hover:bg-grayscale-10 group-focus:border-primary\"\n [class.border-grayscale-20]=\"disabled()\"\n [class.border-grayscale-30]=\"!disabled()\"\n >\n <i\n class=\"fas\"\n aria-hidden=\"true\"\n [class.text-grayscale-30]=\"disabled()\"\n [class.text-grayscale-90]=\"!disabled()\"\n [class.fa-caret-down]=\"!showOptions()\"\n [class.fa-caret-up]=\"showOptions()\"\n ></i>\n </div>\n</div>\n\n<ng-template\n #dropdownTemplate\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"showOptions()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n (backdropClick)=\"showOptions.set(false)\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (detach)=\"showOptions.set(false)\"\n>\n <div\n [id]=\"componentId + '-listbox'\"\n class=\"dropdown-body-class z-[1000] rounded-[3px] bg-grayscale-0 py-1 shadow-md\"\n (click)=\"$event.stopPropagation()\"\n [style.width.px]=\"containerDiv.offsetWidth\"\n [attr.aria-multiselectable]=\"multiple() ? true : null\"\n [@visibilityChanged]\n role=\"listbox\"\n >\n @if (filter()) {\n <div class=\"flex w-full items-center gap-3 px-3 py-1.5\">\n @if (multiple()) {\n <s-checkbox\n #selectAllCheckbox\n [checked]=\"allSelected()\"\n [indeterminate]=\"selectAllIsIndeterminate()\"\n (checkedChange)=\"toggleSelectAll()\"\n ></s-checkbox>\n }\n\n <div class=\"relative flex h-[35px] grow\">\n <form\n class=\"flex w-full grow\"\n [formGroup]=\"filterForm\"\n >\n <input\n #filterInput\n class=\"w-full grow rounded-[3px] border border-grayscale-30 pl-2.5 pr-7 outline-1 outline-primary\"\n type=\"text\"\n formControlName=\"filter\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"onFilterKeyDown($event)\"\n [attr.aria-label]=\"'platform.angular_components.filter_options' | translate\"\n [attr.aria-controls]=\"componentId + '-listbox'\"\n [attr.aria-activedescendant]=\"focusedOptionId()\"\n autocomplete=\"off\"\n />\n </form>\n <i\n class=\"fas fa-search absolute right-2.5 top-2.5 text-grayscale-90\"\n aria-hidden=\"true\"\n ></i>\n </div>\n <button\n (click)=\"clearFilter()\"\n [attr.aria-label]=\"'platform.angular_components.clear_filter' | translate\"\n >\n <i\n class=\"fas fa-times flex items-center\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n }\n\n <!-- Virtual scroll -->\n @if (virtualScroll() && filteredOptions().length > 10) {\n <cdk-virtual-scroll-viewport\n [itemSize]=\"virtualScrollItemSize()\"\n class=\"h-52 overflow-auto\"\n >\n <ng-container *cdkVirtualFor=\"let option of filteredOptions(); trackBy: trackById\">\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper ?? false\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Normal list -->\n @if (!virtualScroll() || filteredOptions().length <= 10) {\n <ul class=\"max-h-52 overflow-auto\">\n @for (option of filteredOptions(); track option.id) {\n <s-select-option\n [id]=\"option.id\"\n [label]=\"getOptionLabel(option.data)\"\n [multiple]=\"multiple()\"\n [checkmark]=\"checkmark()\"\n [isSelected]=\"isOptionSelected(option)\"\n (selected)=\"selectItem(option)\"\n [isGrouper]=\"option.grouper ?? false\"\n [isFocused]=\"option.data === focusedItem()\"\n ></s-select-option>\n }\n </ul>\n }\n\n @if (filteredOptions().length === 0) {\n <span class=\"m-3 text-grayscale-60\">{{\n emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n }}</span>\n }\n </div>\n</ng-template>\n\n", styles: [":host.ng-dirty.ng-invalid{.dropdown-container,.select-container{border-color:#c13018;outline:none}}\n"] }]
722
834
  }], ctorParameters: () => [] });
723
835
 
724
836
  /**