@seniorsistemas/angular-components 17.27.1-feature-sds-110-35ee9b4f → 17.27.1-fix-interactive-content-46e38731

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 (61) hide show
  1. package/button/lib/button/button.component.d.ts +1 -1
  2. package/checkbox/lib/checkbox/checkbox.component.d.ts +11 -13
  3. package/checkbox/public-api.d.ts +1 -4
  4. package/checkbox-list/index.d.ts +5 -0
  5. package/checkbox-list/lib/checkbox-list/checkbox-list.component.d.ts +21 -0
  6. package/checkbox-list/lib/checkbox-list/checkbox-list.module.d.ts +9 -0
  7. package/checkbox-list/lib/checkbox-list/models/checkbox-list-data.d.ts +5 -0
  8. package/checkbox-list/lib/checkbox-list/models/checkbox-list-state.d.ts +7 -0
  9. package/checkbox-list/package.json +3 -0
  10. package/checkbox-list/public-api.d.ts +4 -0
  11. package/dynamic-form/lib/dynamic-form/dynamic-form.module.d.ts +35 -36
  12. package/dynamic-form/lib/dynamic-form/form-field/configurations/fields/checkbox-field.d.ts +3 -3
  13. package/dynamic-form/lib/dynamic-form/form-field/configurations/fields/select-field.d.ts +2 -0
  14. package/fesm2022/seniorsistemas-angular-components-button.mjs +4 -2
  15. package/fesm2022/seniorsistemas-angular-components-button.mjs.map +1 -1
  16. package/fesm2022/seniorsistemas-angular-components-checkbox-list.mjs +151 -0
  17. package/fesm2022/seniorsistemas-angular-components-checkbox-list.mjs.map +1 -0
  18. package/fesm2022/seniorsistemas-angular-components-checkbox.mjs +33 -110
  19. package/fesm2022/seniorsistemas-angular-components-checkbox.mjs.map +1 -1
  20. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +19 -22
  21. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
  22. package/fesm2022/seniorsistemas-angular-components-fieldset.mjs +7 -7
  23. package/fesm2022/seniorsistemas-angular-components-fieldset.mjs.map +1 -1
  24. package/fesm2022/seniorsistemas-angular-components-interactive-content.mjs +65 -0
  25. package/fesm2022/seniorsistemas-angular-components-interactive-content.mjs.map +1 -0
  26. package/fesm2022/seniorsistemas-angular-components-paginator.mjs +145 -0
  27. package/fesm2022/seniorsistemas-angular-components-paginator.mjs.map +1 -0
  28. package/fesm2022/seniorsistemas-angular-components-select.mjs +741 -0
  29. package/fesm2022/seniorsistemas-angular-components-select.mjs.map +1 -0
  30. package/fesm2022/seniorsistemas-angular-components-star-rating.mjs +4 -5
  31. package/fesm2022/seniorsistemas-angular-components-star-rating.mjs.map +1 -1
  32. package/fesm2022/seniorsistemas-angular-components-table-header.mjs +8 -8
  33. package/fesm2022/seniorsistemas-angular-components-table-header.mjs.map +1 -1
  34. package/fesm2022/seniorsistemas-angular-components-thumbnails.mjs +7 -7
  35. package/fesm2022/seniorsistemas-angular-components-thumbnails.mjs.map +1 -1
  36. package/fieldset/lib/fieldset/fieldset.component.d.ts +1 -1
  37. package/fieldset/lib/fieldset/fieldset.module.d.ts +2 -2
  38. package/interactive-content/index.d.ts +5 -0
  39. package/interactive-content/lib/interactive-content/interactive-content.directive.d.ts +17 -0
  40. package/interactive-content/package.json +3 -0
  41. package/interactive-content/public-api.d.ts +1 -0
  42. package/package.json +35 -15
  43. package/paginator/index.d.ts +5 -0
  44. package/paginator/lib/models/paginator.models.d.ts +14 -0
  45. package/paginator/lib/paginator/paginator.component.d.ts +30 -0
  46. package/paginator/package.json +3 -0
  47. package/paginator/public-api.d.ts +2 -0
  48. package/table-header/lib/table-header/table-header-checkbox.component.d.ts +3 -3
  49. package/table-header/lib/table-header/table-header-checkox.module.d.ts +2 -2
  50. package/tailwind.css +263 -0
  51. package/thumbnails/lib/thumbnails/thumbnails.module.d.ts +2 -2
  52. package/accessibility-events/index.d.ts +0 -5
  53. package/accessibility-events/lib/accessibility-events/accessibility-events.module.d.ts +0 -8
  54. package/accessibility-events/lib/accessibility-events/directives/accessibility-event.directive.d.ts +0 -15
  55. package/accessibility-events/package.json +0 -3
  56. package/accessibility-events/public-api.d.ts +0 -2
  57. package/checkbox/lib/checkbox/checkbox.module.d.ts +0 -9
  58. package/checkbox/lib/checkbox/models/checkbox-data.d.ts +0 -5
  59. package/checkbox/lib/checkbox/models/checkbox-state.d.ts +0 -7
  60. package/fesm2022/seniorsistemas-angular-components-accessibility-events.mjs +0 -77
  61. package/fesm2022/seniorsistemas-angular-components-accessibility-events.mjs.map +0 -1
@@ -0,0 +1,741 @@
1
+ import { DomPortalOutlet, TemplatePortal } from '@angular/cdk/portal';
2
+ import * as i3 from '@angular/cdk/scrolling';
3
+ import { ScrollingModule } from '@angular/cdk/scrolling';
4
+ import * as i1 from '@angular/common';
5
+ import { CommonModule, isPlatformBrowser } from '@angular/common';
6
+ import * as i0 from '@angular/core';
7
+ import { input, model, output, Component, signal, computed, inject, ElementRef, viewChild, PLATFORM_ID, ViewContainerRef, forwardRef } from '@angular/core';
8
+ import * as i2 from '@angular/forms';
9
+ import { FormGroup, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
10
+ import * as i4 from '@ngx-translate/core';
11
+ import { TranslateService, TranslateModule } from '@ngx-translate/core';
12
+ import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
13
+ import { CheckboxComponent } from '@seniorsistemas/angular-components/checkbox';
14
+ import { Subject } from 'rxjs';
15
+
16
+ class SelectOptionComponent {
17
+ id = input.required();
18
+ label = input.required();
19
+ multiple = input.required();
20
+ checkmark = input.required();
21
+ isGrouper = input.required();
22
+ isFocused = input.required();
23
+ isSelected = model.required();
24
+ selected = output();
25
+ onClick() {
26
+ if (this.isGrouper()) {
27
+ return;
28
+ }
29
+ this.selected.emit();
30
+ }
31
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectOptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
32
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", 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", "indeterminateChange"] }] });
33
+ }
34
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectOptionComponent, decorators: [{
35
+ type: Component,
36
+ 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
+ }] });
38
+
39
+ class SelectComponent {
40
+ placeholder = input('');
41
+ multiple = input(false);
42
+ options = input.required();
43
+ optionLabel = input();
44
+ optionValue = input();
45
+ showClear = input(false);
46
+ filter = input(false);
47
+ checkmark = input(false);
48
+ filterBy = input();
49
+ group = input(false);
50
+ virtualScroll = input(false);
51
+ virtualScrollItemSize = input(37);
52
+ emptyMessage = input(null);
53
+ useRawValue = input(false);
54
+ dataKey = input();
55
+ disabled = model(false);
56
+ showOptions = signal(false);
57
+ value = signal(null);
58
+ values = signal([]);
59
+ filterValue = signal('');
60
+ focusedIndex = signal(-1);
61
+ dropTop = 0;
62
+ dropLeft = 0;
63
+ dropWidth = 0;
64
+ _portalHost = null;
65
+ /**
66
+ * Verifica se todas as opções visíveis (filtradas e não agrupadoras) estão selecionadas.
67
+ *
68
+ * - Retorna `true` se todas as opções filtradas estiverem presentes em `values()`.
69
+ * - Ignora opções marcadas como `grouper`.
70
+ * - Usa `_getCompareValueExtractor()` para comparar os valores de forma consistente.
71
+ *
72
+ * Esse estado é usado para controlar o checkbox de "Selecionar todos" quando todas as opções visíveis estão marcadas.
73
+ */
74
+ allSelected = computed(() => {
75
+ const selected = this.values();
76
+ const options = this.filteredOptions().filter((o) => !o.grouper);
77
+ return (options.length > 0 &&
78
+ options.every((option) => selected.some((s) => this._getCompareValueExtractor()(s) === this._getCompareValueExtractor()(option))));
79
+ });
80
+ focusedItem = computed(() => this.filteredOptions().at(this.focusedIndex())?.data ?? null);
81
+ /**
82
+ * Converte as opções externas (`options()`) em uma estrutura interna padronizada (`InternalDropdownOption<T>`).
83
+ *
84
+ * - Se os dados forem primitivos (string, number, etc.), gera opções com IDs baseados no índice.
85
+ * - Se os dados forem objetos, delega a criação das opções para `_addIdToOptions()`, que adiciona IDs e marca agrupadores.
86
+ * - Se o modo agrupado estiver ativo (`group()`), transforma as opções em uma lista achatada com agrupadores via `_grouperToFlat()`.
87
+ *
88
+ * Essa estrutura é usada internamente para renderização, filtragem e controle de seleção.
89
+ */
90
+ internalOptions = computed(() => {
91
+ const opts = this.options();
92
+ const optionsWithId = this.TIsPrimitive()
93
+ ? opts.map((value, index) => ({
94
+ id: `id_primitive_${index}`,
95
+ grouper: false,
96
+ data: value,
97
+ }))
98
+ : this._addIdToOptions(opts);
99
+ return this.group() ? this._grouperToFlat(optionsWithId) : optionsWithId;
100
+ });
101
+ /**
102
+ * Retorna o texto que deve ser exibido no componente com base nos valores selecionados.
103
+ *
104
+ * - No modo múltiplo:
105
+ * - Se houver mais de um item selecionado, exibe uma mensagem traduzida com o total de registros.
106
+ * - Se houver apenas um item selecionado, exibe o label correspondente.
107
+ * - No modo simples:
108
+ * - Exibe o label do valor selecionado. *
109
+ * - Se nenhum valor estiver selecionado, retorna uma string vazia.
110
+ *
111
+ * Essa lógica é usada para mostrar o conteúdo atual do campo de seleção.
112
+ */
113
+ print = computed(() => {
114
+ if (this.multiple()) {
115
+ const selected = this.values();
116
+ if (selected.length > 1) {
117
+ return this._translateService.instant(`platform.angular_components.total_records_selected`, {
118
+ count: selected.length,
119
+ });
120
+ }
121
+ else if (selected.length === 1) {
122
+ return this._getLabelFromOption(selected[0]);
123
+ }
124
+ }
125
+ else if (this.value()) {
126
+ return this._getLabelFromOption(this.value());
127
+ }
128
+ return '';
129
+ });
130
+ isClean = computed(() => {
131
+ return this.multiple() ? !this.values().length : !this.value();
132
+ });
133
+ TIsPrimitive = computed(() => {
134
+ const opts = this.options();
135
+ if (!opts.length)
136
+ return false;
137
+ return ['string', 'number', 'boolean'].includes(typeof opts[0]);
138
+ });
139
+ /**
140
+ * Indica se o estado de seleção está indeterminado.
141
+ *
142
+ * - Retorna `true` quando **algumas**, mas não todas, opções visíveis estão selecionadas.
143
+ * - Retorna `false` quando **todas** ou **nenhuma** das opções visíveis estão selecionadas.
144
+ * - Ignora opções marcadas como `grouper`.
145
+ *
146
+ * Esse estado é usado, por exemplo, para exibir o checkbox de "Selecionar todos" em modo indeterminado.
147
+ */
148
+ selectAllIsIndeterminate = computed(() => {
149
+ const selected = this.values();
150
+ const options = this.filteredOptions().filter((o) => !o.grouper);
151
+ const all = options.length > 0 && options.every((o) => selected.includes(o.data));
152
+ const none = options.every((o) => !selected.includes(o.data));
153
+ return !all && !none;
154
+ });
155
+ /**
156
+ * Retorna a lista de opções filtradas com base no valor digitado pelo usuário.
157
+ *
158
+ * - Se o filtro estiver desativado ou vazio, retorna todas as opções.
159
+ * - Caso contrário, aplica o filtro usando o(s) campo(s) definidos em `filterBy`.
160
+ * - Ignora opções marcadas como `grouper`.
161
+ * - Usa o extrator de label para comparar os valores com o texto buscado.
162
+ */
163
+ filteredOptions = computed(() => {
164
+ const allOptions = this.internalOptions();
165
+ const search = this.filterValue().toLowerCase().trim();
166
+ if (!this.filter() || !search) {
167
+ return allOptions;
168
+ }
169
+ const filterBy = this.filterBy();
170
+ return allOptions.filter((option) => {
171
+ if (option.grouper) {
172
+ return false;
173
+ }
174
+ const labelExtractor = this._getLabelExtractor();
175
+ let label = '';
176
+ if (!filterBy) {
177
+ label = labelExtractor(option.data);
178
+ }
179
+ else if (Array.isArray(filterBy)) {
180
+ label = filterBy.map((by) => String(option.data[by] ?? '')).join(' ');
181
+ }
182
+ else {
183
+ label = String(option.data[filterBy] ?? '');
184
+ }
185
+ return label.toLowerCase().includes(search);
186
+ });
187
+ });
188
+ filterForm = new FormGroup({
189
+ filter: new FormControl('', { nonNullable: true }),
190
+ });
191
+ _elementRef = inject((ElementRef));
192
+ _dropdownTemplate = viewChild('dropdownTemplate');
193
+ _containerDiv = viewChild('containerDiv');
194
+ _onChange = () => { };
195
+ _onTouched = () => { };
196
+ platformId = inject(PLATFORM_ID);
197
+ _viewContainerRef = inject(ViewContainerRef);
198
+ _translateService = inject(TranslateService);
199
+ destroy$ = new Subject();
200
+ /**
201
+ * Inicializa o componente, validando os inputs e configurando o filtro com debounce.
202
+ */
203
+ ngOnInit() {
204
+ this._validateInputs();
205
+ this.filterForm
206
+ .get('filter')
207
+ .valueChanges.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$))
208
+ .subscribe((value) => {
209
+ this.filterValue.set(value);
210
+ });
211
+ }
212
+ /**
213
+ * Executa limpeza de recursos ao destruir o componente.
214
+ */
215
+ ngOnDestroy() {
216
+ this._destroyDropdownPortal();
217
+ if (this._portalHost) {
218
+ this._portalHost.dispose();
219
+ this._portalHost = null;
220
+ }
221
+ this.destroy$.next();
222
+ this.destroy$.complete();
223
+ }
224
+ /**
225
+ * Define o valor no componente vindo do formulário externo.
226
+ * @param value Valor atribuído pelo Angular forms.
227
+ */
228
+ writeValue(value) {
229
+ if (this.multiple()) {
230
+ if (Array.isArray(value)) {
231
+ const items = this.TIsPrimitive()
232
+ ? value.map((v) => this._findOptionByPrimitiveValue(v)).filter(Boolean)
233
+ : this.useRawValue()
234
+ ? value
235
+ : value.map((v) => this._findOptionByValue(v)).filter(Boolean);
236
+ this.values.set(items);
237
+ }
238
+ else {
239
+ this.values.set([]);
240
+ }
241
+ }
242
+ else {
243
+ const item = this.TIsPrimitive()
244
+ ? this._findOptionByPrimitiveValue(value)
245
+ : this.useRawValue()
246
+ ? value
247
+ : this._findOptionByValue(value);
248
+ this.value.set(item ?? null);
249
+ }
250
+ }
251
+ /**
252
+ * Registra a função que será chamada quando o valor mudar.
253
+ * @param onChange Função callback.
254
+ */
255
+ registerOnChange(onChange) {
256
+ this._onChange = onChange;
257
+ }
258
+ /**
259
+ * Registra a função que será chamada quando o componente for "tocado".
260
+ * @param onTouched Função callback.
261
+ */
262
+ registerOnTouched(onTouched) {
263
+ this._onTouched = onTouched;
264
+ }
265
+ /**
266
+ * Define o estado de desabilitado do componente.
267
+ * @param disabled Indica se o componente está desabilitado.
268
+ */
269
+ setDisabledState(disabled) {
270
+ this.disabled.set(disabled);
271
+ }
272
+ /**
273
+ * Alterna a exibição da lista de opções (dropdown).
274
+ */
275
+ toggle() {
276
+ if (this.disabled()) {
277
+ return;
278
+ }
279
+ const shouldOpen = !this.showOptions();
280
+ this.showOptions.set(shouldOpen);
281
+ if (shouldOpen) {
282
+ setTimeout(() => {
283
+ this._createDropdownPortal();
284
+ });
285
+ }
286
+ else {
287
+ this._destroyDropdownPortal();
288
+ }
289
+ }
290
+ /**
291
+ * Seleciona ou desseleciona um item na lista.
292
+ * @param item Item a ser selecionado ou desmarcado.
293
+ */
294
+ selectItem(item) {
295
+ if (this.disabled()) {
296
+ return;
297
+ }
298
+ const getCompareValue = this._getCompareValueExtractor();
299
+ if (this.multiple()) {
300
+ const store = [...this.values()];
301
+ const itemValue = getCompareValue(item);
302
+ const index = store.findIndex((selectedItem) => {
303
+ return getCompareValue(selectedItem) === itemValue;
304
+ });
305
+ if (index !== -1) {
306
+ store.splice(index, 1);
307
+ }
308
+ else {
309
+ store.push(item);
310
+ }
311
+ this.values.set(store);
312
+ const result = this.useRawValue() ? store : store.map((i) => this._getValueExtractor()(i));
313
+ this._onChange(result);
314
+ }
315
+ else {
316
+ this.value.set(item);
317
+ const result = this.useRawValue() ? item : this._getValueExtractor()(item);
318
+ this._onChange(result);
319
+ this._closeDropdown();
320
+ }
321
+ this._onTouched();
322
+ }
323
+ /**
324
+ * Limpa a seleção atual.
325
+ * @param event Evento do clique.
326
+ */
327
+ clear(event) {
328
+ if (this.disabled()) {
329
+ return;
330
+ }
331
+ if (this.multiple()) {
332
+ this.values.set([]);
333
+ this._onChange(this._removeInternalProperties(this.values()));
334
+ }
335
+ else {
336
+ this.value.set(null);
337
+ this._onChange(this.value());
338
+ }
339
+ this._closeDropdown();
340
+ this._onTouched();
341
+ event.stopPropagation();
342
+ }
343
+ /**
344
+ * Limpa o filtro aplicado à lista de opções.
345
+ */
346
+ clearFilter() {
347
+ this.filterForm.get('filter')?.reset();
348
+ }
349
+ /**
350
+ * Fecha o dropdown se o clique ocorrer fora do componente.
351
+ * @param event Evento do clique.
352
+ */
353
+ onDocumentClick(event) {
354
+ const clickTarget = event.target;
355
+ const clickedInsideComponent = this._elementRef.nativeElement.contains(clickTarget);
356
+ const dropdownInBody = document.querySelector('.dropdown-body-class')?.contains(clickTarget);
357
+ if (!clickedInsideComponent && !dropdownInBody) {
358
+ this._closeDropdown();
359
+ }
360
+ }
361
+ /**
362
+ * Fecha o dropdown em eventos de redimensionamento de janela.
363
+ */
364
+ onWindowResize(_) {
365
+ if (this.showOptions()) {
366
+ this._closeDropdown();
367
+ }
368
+ }
369
+ /**
370
+ * Dispara a abertura/fechamento do dropdown ao clicar no container.
371
+ */
372
+ onContainerDivClick() {
373
+ this.toggle();
374
+ this._containerDiv()?.nativeElement.focus();
375
+ }
376
+ /**
377
+ * Trata eventos de teclado para navegação e seleção.
378
+ * @param event Evento do teclado.
379
+ */
380
+ onKeyDown(event) {
381
+ const options = this.filteredOptions();
382
+ if (!options.length) {
383
+ return;
384
+ }
385
+ const _selectOption = () => {
386
+ if (this.focusedIndex() >= 0 && this.focusedIndex() < options.length) {
387
+ event.preventDefault();
388
+ this.selectItem(options[this.focusedIndex()].data);
389
+ }
390
+ };
391
+ switch (event.key) {
392
+ case 'ArrowDown':
393
+ event.preventDefault();
394
+ this._focusNextOption(options);
395
+ break;
396
+ case 'ArrowUp':
397
+ event.preventDefault();
398
+ this._focusPreviousOption(options);
399
+ break;
400
+ case 'Tab':
401
+ _selectOption();
402
+ this._closeDropdown();
403
+ break;
404
+ case 'Enter':
405
+ if (this.showOptions()) {
406
+ _selectOption();
407
+ }
408
+ else {
409
+ this.toggle();
410
+ }
411
+ break;
412
+ case 'Escape':
413
+ this._closeDropdown();
414
+ break;
415
+ case ' ':
416
+ _selectOption();
417
+ break;
418
+ }
419
+ }
420
+ /**
421
+ * Retorna o rótulo de exibição de uma opção.
422
+ * @param option Item da lista de opções.
423
+ * @returns Texto que será exibido no dropdown.
424
+ */
425
+ getOptionLabel(option) {
426
+ return this._getLabelFromOption(option);
427
+ }
428
+ /**
429
+ * Função usada para o trackBy no for do template.
430
+ * @param _ Índice do item.
431
+ * @param item Item da lista.
432
+ * @returns ID único da opção.
433
+ */
434
+ trackById(_, item) {
435
+ return item.id;
436
+ }
437
+ /**
438
+ * Verifica se uma opção está selecionada.
439
+ * @param option Opção a ser verificada.
440
+ * @returns Verdadeiro se a opção estiver selecionada.
441
+ */
442
+ isOptionSelected(option) {
443
+ const getCompareValue = this._getCompareValueExtractor();
444
+ if (this.multiple()) {
445
+ const selectedValues = this.values().map(getCompareValue);
446
+ return selectedValues.includes(getCompareValue(option));
447
+ }
448
+ else {
449
+ const currentValue = this.value();
450
+ return currentValue !== null && getCompareValue(currentValue) === getCompareValue(option);
451
+ }
452
+ }
453
+ /**
454
+ * Alterna a seleção de todos os itens filtrados.
455
+ */
456
+ toggleSelectAll() {
457
+ if (!this.multiple()) {
458
+ return;
459
+ }
460
+ const options = this.filteredOptions().filter((o) => !o.grouper);
461
+ if (this.allSelected()) {
462
+ this.values.set([]);
463
+ }
464
+ else {
465
+ this.values.set(options.map((o) => o.data));
466
+ }
467
+ this._onChange(this._removeInternalProperties(this.values()));
468
+ }
469
+ /**
470
+ * Procura e retorna uma opção com valor primitivo igual ao informado.
471
+ *
472
+ * @param value Valor primitivo (string, number ou boolean).
473
+ * @returns A opção correspondente, ou `null` se não encontrada.
474
+ */
475
+ _findOptionByPrimitiveValue(value) {
476
+ return this.internalOptions().find((opt) => opt.data === value)?.data ?? null;
477
+ }
478
+ /**
479
+ * Remove propriedades internas adicionadas pelo componente, retornando apenas os dados crus.
480
+ *
481
+ * Usado para garantir que apenas os objetos de dados reais sejam emitidos ao formulário,
482
+ * especialmente no modo múltiplo.
483
+ *
484
+ * @param value Valor armazenado internamente (com ou sem `InternalDropdownOption`).
485
+ * @returns Os dados "puros", sem propriedades adicionais.
486
+ */
487
+ _removeInternalProperties(value) {
488
+ if (this.TIsPrimitive()) {
489
+ return value;
490
+ }
491
+ return Array.isArray(value)
492
+ ? value.map((opt) => opt.data)
493
+ : value.data;
494
+ }
495
+ /**
496
+ * Retorna o texto (label) correspondente a uma determinada opção.
497
+ * Usa a propriedade definida em `optionLabel`, ou tenta usar uma propriedade padrão (`label`).
498
+ *
499
+ * @param option A opção a ser exibida.
500
+ * @returns O texto legível da opção para exibição no componente.
501
+ */
502
+ _getLabelFromOption(option) {
503
+ if (['string', 'number', 'boolean'].includes(typeof option)) {
504
+ return String(option);
505
+ }
506
+ const labelKey = this.optionLabel();
507
+ if (!labelKey) {
508
+ return String(option.label ?? '');
509
+ }
510
+ return String(option[labelKey]);
511
+ }
512
+ /**
513
+ * Valida os inputs obrigatórios do componente.
514
+ */
515
+ _validateInputs() {
516
+ if (!this.useRawValue() && !this.TIsPrimitive() && !this.optionValue()) {
517
+ throw new Error(`The 'optionValue' input must be provided for non-primitive options when useRawValue is false.`);
518
+ }
519
+ if (!this.TIsPrimitive() && !this.optionValue() && !this.dataKey()) {
520
+ throw new Error('Either the optionValue or dataKey input must be provided for non-primitive options.');
521
+ }
522
+ if (!this.TIsPrimitive() && !this.optionLabel()) {
523
+ throw new Error(`The 'optionLabel' input must be provided for non-primitive options.`);
524
+ }
525
+ }
526
+ _findOptionByValue(value) {
527
+ if (this.useRawValue()) {
528
+ return this.options().find((option) => option === value) ?? null;
529
+ }
530
+ const getValue = this._getValueExtractor();
531
+ return this.options().find((option) => getValue(option) === value) ?? null;
532
+ }
533
+ /**
534
+ * Extrai o valor final de uma opção, com base em `optionValue`.
535
+ * @returns Função que retorna o valor da opção.
536
+ */
537
+ _getValueExtractor() {
538
+ if (this.TIsPrimitive()) {
539
+ return (option) => option;
540
+ }
541
+ if (this.useRawValue()) {
542
+ return (option) => option;
543
+ }
544
+ const valueInput = this.optionValue();
545
+ if (valueInput) {
546
+ return (option) => option[valueInput];
547
+ }
548
+ throw new Error(`optionValue is required for non-primitive options.`);
549
+ }
550
+ /**
551
+ * Extrai o valor comparável de uma opção.
552
+ * @returns Função que retorna a chave de comparação.
553
+ */
554
+ _getCompareValueExtractor() {
555
+ if (this.TIsPrimitive()) {
556
+ return (option) => option;
557
+ }
558
+ if (this.dataKey()) {
559
+ const key = this.dataKey();
560
+ return (option) => option[key];
561
+ }
562
+ return this._getValueExtractor();
563
+ }
564
+ /**
565
+ * Fecha o dropdown e redefine o foco.
566
+ */
567
+ _closeDropdown() {
568
+ this.showOptions.set(false);
569
+ this._destroyDropdownPortal();
570
+ this.focusedIndex.set(-1);
571
+ }
572
+ /**
573
+ * Adiciona identificadores únicos às opções.
574
+ * @param options Lista original de opções.
575
+ * @returns Lista com IDs adicionados.
576
+ */
577
+ _addIdToOptions(options) {
578
+ const timestamp = Date.now();
579
+ return options.map((option, index) => {
580
+ if (this.group() && Array.isArray(option.items)) {
581
+ return {
582
+ data: option,
583
+ id: `id_${timestamp}_${index++}`,
584
+ grouper: true,
585
+ };
586
+ }
587
+ return {
588
+ data: option,
589
+ id: `id_${timestamp}_${index++}`,
590
+ };
591
+ });
592
+ }
593
+ /**
594
+ * Converte uma estrutura agrupada em uma lista achatada.
595
+ * @param options Lista de opções com agrupadores.
596
+ * @returns Lista achatada de opções e grupos.
597
+ */
598
+ _grouperToFlat(options) {
599
+ const result = [];
600
+ options.forEach((option) => {
601
+ if (option.grouper && Array.isArray(option.data.items)) {
602
+ result.push(option);
603
+ const groupItems = option.data.items.map((item, index) => ({
604
+ data: item,
605
+ id: `${option.id}_item_${index}`,
606
+ }));
607
+ result.push(...groupItems);
608
+ }
609
+ else {
610
+ result.push(option);
611
+ }
612
+ });
613
+ return result;
614
+ }
615
+ /**
616
+ * Move o foco para a próxima opção.
617
+ * @param options Lista de opções visíveis.
618
+ */
619
+ _focusNextOption(options) {
620
+ let nextIndex = this.focusedIndex() + 1;
621
+ while (nextIndex < options.length && options[nextIndex].grouper) {
622
+ nextIndex++;
623
+ }
624
+ if (nextIndex < options.length) {
625
+ this.focusedIndex.set(nextIndex);
626
+ this._scrollToFocusedOption();
627
+ }
628
+ }
629
+ /**
630
+ * Move o foco para a opção anterior.
631
+ * @param options Lista de opções visíveis.
632
+ */
633
+ _focusPreviousOption(options) {
634
+ let prevIndex = this.focusedIndex() - 1;
635
+ while (prevIndex >= 0 && options[prevIndex].grouper) {
636
+ prevIndex--;
637
+ }
638
+ if (prevIndex >= 0) {
639
+ this.focusedIndex.set(prevIndex);
640
+ this._scrollToFocusedOption();
641
+ }
642
+ }
643
+ /**
644
+ * Rola o dropdown até a opção atualmente focada.
645
+ */
646
+ _scrollToFocusedOption() {
647
+ const id = this.filteredOptions()[this.focusedIndex()]?.id;
648
+ if (!id) {
649
+ return;
650
+ }
651
+ const el = document.getElementById(id);
652
+ el?.scrollIntoView({ block: 'nearest' });
653
+ }
654
+ /**
655
+ * Extrai o texto de uma opção, com base em `optionLabel`.
656
+ * @returns Função que retorna o label da opção.
657
+ */
658
+ _getLabelExtractor() {
659
+ if (this.TIsPrimitive()) {
660
+ return (option) => String(option);
661
+ }
662
+ const labelInput = this.optionLabel();
663
+ if (labelInput) {
664
+ return (option) => String(option[labelInput] ?? '');
665
+ }
666
+ else {
667
+ throw new Error(`optionLabel is required for non-primitive options.`);
668
+ }
669
+ }
670
+ /**
671
+ * Cria e posiciona dinamicamente o dropdown como portal.
672
+ */
673
+ _createDropdownPortal() {
674
+ if (!isPlatformBrowser(this.platformId)) {
675
+ return;
676
+ }
677
+ const container = this._containerDiv();
678
+ const template = this._dropdownTemplate();
679
+ if (!container || !template) {
680
+ return;
681
+ }
682
+ const dropElementRect = container.nativeElement.getBoundingClientRect();
683
+ this.dropTop = dropElementRect.bottom + window.scrollY;
684
+ this.dropLeft = dropElementRect.left + window.scrollX;
685
+ this.dropWidth = dropElementRect.width;
686
+ this._destroyDropdownPortal();
687
+ this._portalHost = new DomPortalOutlet(document.body);
688
+ const portal = new TemplatePortal(template, this._viewContainerRef);
689
+ this._portalHost.attach(portal);
690
+ const dropdownEl = document.querySelector('.dropdown-body-class');
691
+ if (dropdownEl) {
692
+ dropdownEl.style.position = 'absolute';
693
+ dropdownEl.style.top = `${this.dropTop + 4}px`;
694
+ dropdownEl.style.left = `${this.dropLeft}px`;
695
+ dropdownEl.style.width = `${this.dropWidth}px`;
696
+ }
697
+ }
698
+ /**
699
+ * Remove o portal do dropdown do DOM.
700
+ */
701
+ _destroyDropdownPortal() {
702
+ if (this._portalHost?.hasAttached()) {
703
+ this._portalHost.detach();
704
+ }
705
+ }
706
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
707
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", 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 }, useRawValue: { classPropertyName: "useRawValue", publicName: "useRawValue", isSignal: true, isRequired: false, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "window:resize": "onWindowResize($event)" } }, providers: [
708
+ {
709
+ provide: NG_VALUE_ACCESSOR,
710
+ useExisting: forwardRef(() => SelectComponent),
711
+ multi: true,
712
+ },
713
+ ], viewQueries: [{ propertyName: "_dropdownTemplate", first: true, predicate: ["dropdownTemplate"], descendants: true, isSignal: true }, { propertyName: "_containerDiv", first: true, predicate: ["containerDiv"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #portalAnchor></ng-template>\n\n<div\n #containerDiv\n class=\"group flex 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 (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=\"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 #dropdownTemplate>\n <div\n class=\"dropdown-body-class z-[999] rounded-[3px] bg-grayscale-0 py-1 shadow-md\"\n [style.position]=\"'absolute'\"\n [style.top.px]=\"dropTop\"\n [style.left.px]=\"dropLeft\"\n (click)=\"$event.stopPropagation()\"\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.data)\"\n (selected)=\"selectItem(option.data)\"\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.data)\"\n (selected)=\"selectItem(option.data)\"\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", 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", "indeterminateChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] });
714
+ }
715
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SelectComponent, decorators: [{
716
+ type: Component,
717
+ args: [{ selector: 's-select', standalone: true, imports: [
718
+ CommonModule,
719
+ ReactiveFormsModule,
720
+ ScrollingModule,
721
+ SelectOptionComponent,
722
+ CheckboxComponent,
723
+ TranslateModule,
724
+ ], host: {
725
+ '(document:click)': 'onDocumentClick($event)',
726
+ '(window:resize)': 'onWindowResize($event)',
727
+ }, providers: [
728
+ {
729
+ provide: NG_VALUE_ACCESSOR,
730
+ useExisting: forwardRef(() => SelectComponent),
731
+ multi: true,
732
+ },
733
+ ], template: "<ng-template #portalAnchor></ng-template>\n\n<div\n #containerDiv\n class=\"group flex 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 (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=\"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 #dropdownTemplate>\n <div\n class=\"dropdown-body-class z-[999] rounded-[3px] bg-grayscale-0 py-1 shadow-md\"\n [style.position]=\"'absolute'\"\n [style.top.px]=\"dropTop\"\n [style.left.px]=\"dropLeft\"\n (click)=\"$event.stopPropagation()\"\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.data)\"\n (selected)=\"selectItem(option.data)\"\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.data)\"\n (selected)=\"selectItem(option.data)\"\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" }]
734
+ }] });
735
+
736
+ /**
737
+ * Generated bundle index. Do not edit.
738
+ */
739
+
740
+ export { SelectComponent };
741
+ //# sourceMappingURL=seniorsistemas-angular-components-select.mjs.map