@neural-ui/core 1.7.1 → 1.7.3

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 (129) hide show
  1. package/bottom-sheet/package.json +4 -0
  2. package/confirm-popup/package.json +4 -0
  3. package/data-view/package.json +4 -0
  4. package/fesm2022/neural-ui-core-alert.mjs +48 -21
  5. package/fesm2022/neural-ui-core-alert.mjs.map +1 -1
  6. package/fesm2022/neural-ui-core-autocomplete.mjs +153 -71
  7. package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -1
  8. package/fesm2022/neural-ui-core-block-ui.mjs +2 -2
  9. package/fesm2022/neural-ui-core-block-ui.mjs.map +1 -1
  10. package/fesm2022/neural-ui-core-bottom-sheet.mjs +121 -0
  11. package/fesm2022/neural-ui-core-bottom-sheet.mjs.map +1 -0
  12. package/fesm2022/neural-ui-core-breadcrumb.mjs +2 -2
  13. package/fesm2022/neural-ui-core-breadcrumb.mjs.map +1 -1
  14. package/fesm2022/neural-ui-core-button.mjs +2 -2
  15. package/fesm2022/neural-ui-core-button.mjs.map +1 -1
  16. package/fesm2022/neural-ui-core-calendar.mjs +2 -2
  17. package/fesm2022/neural-ui-core-calendar.mjs.map +1 -1
  18. package/fesm2022/neural-ui-core-checkbox.mjs +69 -39
  19. package/fesm2022/neural-ui-core-checkbox.mjs.map +1 -1
  20. package/fesm2022/neural-ui-core-chip.mjs +2 -2
  21. package/fesm2022/neural-ui-core-chip.mjs.map +1 -1
  22. package/fesm2022/neural-ui-core-code-block.mjs +2 -2
  23. package/fesm2022/neural-ui-core-code-block.mjs.map +1 -1
  24. package/fesm2022/neural-ui-core-confirm-popup.mjs +105 -0
  25. package/fesm2022/neural-ui-core-confirm-popup.mjs.map +1 -0
  26. package/fesm2022/neural-ui-core-dashboard-grid.mjs +9 -3
  27. package/fesm2022/neural-ui-core-dashboard-grid.mjs.map +1 -1
  28. package/fesm2022/neural-ui-core-data-view.mjs +386 -0
  29. package/fesm2022/neural-ui-core-data-view.mjs.map +1 -0
  30. package/fesm2022/neural-ui-core-date-input.mjs +185 -10
  31. package/fesm2022/neural-ui-core-date-input.mjs.map +1 -1
  32. package/fesm2022/neural-ui-core-empty-state.mjs +19 -5
  33. package/fesm2022/neural-ui-core-empty-state.mjs.map +1 -1
  34. package/fesm2022/neural-ui-core-form-field.mjs +81 -0
  35. package/fesm2022/neural-ui-core-form-field.mjs.map +1 -0
  36. package/fesm2022/neural-ui-core-inline-editor.mjs +428 -0
  37. package/fesm2022/neural-ui-core-inline-editor.mjs.map +1 -0
  38. package/fesm2022/neural-ui-core-input-mask.mjs +110 -0
  39. package/fesm2022/neural-ui-core-input-mask.mjs.map +1 -0
  40. package/fesm2022/neural-ui-core-input.mjs +2 -2
  41. package/fesm2022/neural-ui-core-input.mjs.map +1 -1
  42. package/fesm2022/neural-ui-core-listbox.mjs +219 -0
  43. package/fesm2022/neural-ui-core-listbox.mjs.map +1 -0
  44. package/fesm2022/neural-ui-core-menu.mjs +229 -0
  45. package/fesm2022/neural-ui-core-menu.mjs.map +1 -0
  46. package/fesm2022/neural-ui-core-modal.mjs +34 -10
  47. package/fesm2022/neural-ui-core-modal.mjs.map +1 -1
  48. package/fesm2022/neural-ui-core-multiselect.mjs +170 -179
  49. package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -1
  50. package/fesm2022/neural-ui-core-number-input.mjs +2 -2
  51. package/fesm2022/neural-ui-core-number-input.mjs.map +1 -1
  52. package/fesm2022/neural-ui-core-panel.mjs +92 -0
  53. package/fesm2022/neural-ui-core-panel.mjs.map +1 -0
  54. package/fesm2022/neural-ui-core-password.mjs +106 -0
  55. package/fesm2022/neural-ui-core-password.mjs.map +1 -0
  56. package/fesm2022/neural-ui-core-pick-list.mjs +133 -0
  57. package/fesm2022/neural-ui-core-pick-list.mjs.map +1 -0
  58. package/fesm2022/neural-ui-core-select.mjs +128 -166
  59. package/fesm2022/neural-ui-core-select.mjs.map +1 -1
  60. package/fesm2022/neural-ui-core-sidebar.mjs +14 -3
  61. package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -1
  62. package/fesm2022/neural-ui-core-slider.mjs +2 -2
  63. package/fesm2022/neural-ui-core-slider.mjs.map +1 -1
  64. package/fesm2022/neural-ui-core-spinner.mjs +19 -9
  65. package/fesm2022/neural-ui-core-spinner.mjs.map +1 -1
  66. package/fesm2022/neural-ui-core-split-button.mjs +2 -2
  67. package/fesm2022/neural-ui-core-split-button.mjs.map +1 -1
  68. package/fesm2022/neural-ui-core-table.mjs +503 -62
  69. package/fesm2022/neural-ui-core-table.mjs.map +1 -1
  70. package/fesm2022/neural-ui-core-tabs.mjs +11 -4
  71. package/fesm2022/neural-ui-core-tabs.mjs.map +1 -1
  72. package/fesm2022/neural-ui-core-tags.mjs +134 -0
  73. package/fesm2022/neural-ui-core-tags.mjs.map +1 -0
  74. package/fesm2022/neural-ui-core-textarea.mjs +2 -2
  75. package/fesm2022/neural-ui-core-textarea.mjs.map +1 -1
  76. package/fesm2022/neural-ui-core-toggle-button-group.mjs +2 -2
  77. package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -1
  78. package/fesm2022/neural-ui-core-toolbar.mjs +16 -4
  79. package/fesm2022/neural-ui-core-toolbar.mjs.map +1 -1
  80. package/fesm2022/neural-ui-core-tree-select.mjs +259 -0
  81. package/fesm2022/neural-ui-core-tree-select.mjs.map +1 -0
  82. package/fesm2022/neural-ui-core-tree-table.mjs +267 -8
  83. package/fesm2022/neural-ui-core-tree-table.mjs.map +1 -1
  84. package/fesm2022/neural-ui-core-tree.mjs +15 -14
  85. package/fesm2022/neural-ui-core-tree.mjs.map +1 -1
  86. package/fesm2022/neural-ui-core-uploader.mjs +103 -12
  87. package/fesm2022/neural-ui-core-uploader.mjs.map +1 -1
  88. package/form-field/package.json +4 -0
  89. package/inline-editor/package.json +4 -0
  90. package/input-mask/package.json +4 -0
  91. package/listbox/package.json +4 -0
  92. package/menu/package.json +4 -0
  93. package/package.json +53 -1
  94. package/panel/package.json +4 -0
  95. package/password/package.json +4 -0
  96. package/pick-list/package.json +4 -0
  97. package/styles/_tokens.scss +33 -17
  98. package/tags/package.json +4 -0
  99. package/tree-select/package.json +4 -0
  100. package/types/neural-ui-core-alert.d.ts +2 -1
  101. package/types/neural-ui-core-autocomplete.d.ts +22 -2
  102. package/types/neural-ui-core-bottom-sheet.d.ts +20 -0
  103. package/types/neural-ui-core-checkbox.d.ts +6 -1
  104. package/types/neural-ui-core-confirm-popup.d.ts +38 -0
  105. package/types/neural-ui-core-dashboard-grid.d.ts +1 -0
  106. package/types/neural-ui-core-data-view.d.ts +95 -0
  107. package/types/neural-ui-core-date-input.d.ts +35 -5
  108. package/types/neural-ui-core-empty-state.d.ts +11 -1
  109. package/types/neural-ui-core-form-field.d.ts +33 -0
  110. package/types/neural-ui-core-inline-editor.d.ts +66 -0
  111. package/types/neural-ui-core-input-mask.d.ts +26 -0
  112. package/types/neural-ui-core-listbox.d.ts +54 -0
  113. package/types/neural-ui-core-menu.d.ts +49 -0
  114. package/types/neural-ui-core-modal.d.ts +10 -2
  115. package/types/neural-ui-core-multiselect.d.ts +10 -1
  116. package/types/neural-ui-core-panel.d.ts +25 -0
  117. package/types/neural-ui-core-password.d.ts +29 -0
  118. package/types/neural-ui-core-pick-list.d.ts +40 -0
  119. package/types/neural-ui-core-select.d.ts +7 -1
  120. package/types/neural-ui-core-sidebar.d.ts +5 -1
  121. package/types/neural-ui-core-spinner.d.ts +4 -2
  122. package/types/neural-ui-core-table.d.ts +89 -5
  123. package/types/neural-ui-core-tabs.d.ts +2 -0
  124. package/types/neural-ui-core-tags.d.ts +32 -0
  125. package/types/neural-ui-core-toolbar.d.ts +8 -2
  126. package/types/neural-ui-core-tree-select.d.ts +57 -0
  127. package/types/neural-ui-core-tree-table.d.ts +111 -4
  128. package/types/neural-ui-core-tree.d.ts +1 -1
  129. package/types/neural-ui-core-uploader.d.ts +26 -3
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, TemplateRef, Directive, ElementRef, viewChild, effect, untracked, contentChild, input, output, signal, computed, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
2
+ import { inject, TemplateRef, Directive, ElementRef, PLATFORM_ID, viewChild, effect, untracked, contentChild, input, output, signal, computed, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
3
  import { NeuUrlStateService } from '@neural-ui/core/url-state';
4
- import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
4
+ import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
5
5
  import * as i1 from '@angular/cdk/overlay';
6
6
  import { Overlay, OverlayModule } from '@angular/cdk/overlay';
7
7
  import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
@@ -47,6 +47,7 @@ function arraysEqual(left, right) {
47
47
  class NeuMultiselectComponent {
48
48
  elementRef = inject(ElementRef);
49
49
  _document = inject(DOCUMENT);
50
+ _platformId = inject(PLATFORM_ID);
50
51
  _overlay = inject(Overlay);
51
52
  _urlState = inject(NeuUrlStateService);
52
53
  _viewportMargin = 16;
@@ -102,6 +103,11 @@ class NeuMultiselectComponent {
102
103
  searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
103
104
  /** Placeholder del input de búsqueda / Search input placeholder */
104
105
  searchPlaceholder = input('Buscar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
106
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
107
+ loadingLabel = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingLabel" }] : /* istanbul ignore next */ []));
108
+ selectAll = input(false, ...(ngDevMode ? [{ debugName: "selectAll" }] : /* istanbul ignore next */ []));
109
+ selectAllLabel = input('Select all', ...(ngDevMode ? [{ debugName: "selectAllLabel" }] : /* istanbul ignore next */ []));
110
+ unselectAllLabel = input('Unselect all', ...(ngDevMode ? [{ debugName: "unselectAllLabel" }] : /* istanbul ignore next */ []));
105
111
  /** Texto cuando no hay opciones tras filtrar / Text when no options remain after filtering */
106
112
  noResultsMessage = input('Sin resultados', ...(ngDevMode ? [{ debugName: "noResultsMessage" }] : /* istanbul ignore next */ []));
107
113
  /** Texto del botón de limpiar todas las selecciones / Button text to clear all selections */
@@ -186,6 +192,10 @@ class NeuMultiselectComponent {
186
192
  return this.options();
187
193
  return this.options().filter((o) => o.label.toLowerCase().includes(q));
188
194
  }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
195
+ allFilteredSelected = computed(() => {
196
+ const enabled = this.filteredOptions().filter((option) => !option.disabled);
197
+ return enabled.length > 0 && enabled.every((option) => this._values().includes(option.value));
198
+ }, ...(ngDevMode ? [{ debugName: "allFilteredSelected" }] : /* istanbul ignore next */ []));
189
199
  resultsAnnouncement = computed(() => {
190
200
  if (!this.isOpen()) {
191
201
  return '';
@@ -337,6 +347,26 @@ class NeuMultiselectComponent {
337
347
  this._urlState.setParam(param, null);
338
348
  this.refreshVirtualViewport();
339
349
  }
350
+ toggleAllFiltered(event) {
351
+ event.stopPropagation();
352
+ const enabled = this.filteredOptions().filter((option) => !option.disabled);
353
+ const current = new Set(this._values());
354
+ if (this.allFilteredSelected()) {
355
+ enabled.forEach((option) => current.delete(option.value));
356
+ }
357
+ else {
358
+ enabled.forEach((option) => current.add(option.value));
359
+ }
360
+ const next = [...current];
361
+ this._values.set(next);
362
+ this._onChange(next);
363
+ this._onTouched();
364
+ this.selectionChange.emit(this.options().filter((option) => next.includes(option.value)));
365
+ const param = this.urlParam();
366
+ if (param)
367
+ this._urlState.setParam(param, next.length ? next.join(',') : null);
368
+ this.refreshVirtualViewport();
369
+ }
340
370
  toggleChipMode(event) {
341
371
  event.stopPropagation();
342
372
  this._chipMode.set(this._chipMode() === 'chips' ? 'count' : 'chips');
@@ -379,7 +409,7 @@ class NeuMultiselectComponent {
379
409
  maxHeight: `${maxHeight}px`,
380
410
  });
381
411
  if (this.virtualScroll()) {
382
- requestAnimationFrame(() => this._viewport()?.checkViewportSize());
412
+ this._requestFrame(() => this._viewport()?.checkViewportSize());
383
413
  }
384
414
  }
385
415
  focusFirstOption() {
@@ -396,7 +426,7 @@ class NeuMultiselectComponent {
396
426
  this._viewport()?.scrollToIndex(optionIndex, 'auto');
397
427
  this._viewport()?.checkViewportSize();
398
428
  }
399
- requestAnimationFrame(() => {
429
+ this._requestFrame(() => {
400
430
  const optionElement = this.elementRef.nativeElement.querySelector(`#neu-ms-opt-${value}`) ?? this._document.getElementById(`neu-ms-opt-${value}`);
401
431
  optionElement?.focus();
402
432
  });
@@ -419,12 +449,17 @@ class NeuMultiselectComponent {
419
449
  if (!this.isOpen() || !this.virtualScroll()) {
420
450
  return;
421
451
  }
422
- requestAnimationFrame(() => {
452
+ this._requestFrame(() => {
423
453
  this._viewport()?.checkViewportSize();
424
454
  });
425
455
  }
456
+ _requestFrame(callback) {
457
+ if (isPlatformBrowser(this._platformId)) {
458
+ requestAnimationFrame(callback);
459
+ }
460
+ }
426
461
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuMultiselectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
427
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: NeuMultiselectComponent, isStandalone: true, selector: "neu-multiselect", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessage: { classPropertyName: "noResultsMessage", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, clearAllLabel: { classPropertyName: "clearAllLabel", publicName: "clearAllLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollVisibleItems: { classPropertyName: "virtualScrollVisibleItems", publicName: "virtualScrollVisibleItems", isSignal: true, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "keydown.escape": "close()", "window:resize": "onWindowResize()" } }, providers: [
462
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: NeuMultiselectComponent, isStandalone: true, selector: "neu-multiselect", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, selectAll: { classPropertyName: "selectAll", publicName: "selectAll", isSignal: true, isRequired: false, transformFunction: null }, selectAllLabel: { classPropertyName: "selectAllLabel", publicName: "selectAllLabel", isSignal: true, isRequired: false, transformFunction: null }, unselectAllLabel: { classPropertyName: "unselectAllLabel", publicName: "unselectAllLabel", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessage: { classPropertyName: "noResultsMessage", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, clearAllLabel: { classPropertyName: "clearAllLabel", publicName: "clearAllLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollVisibleItems: { classPropertyName: "virtualScrollVisibleItems", publicName: "virtualScrollVisibleItems", isSignal: true, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "keydown.escape": "close()", "window:resize": "onWindowResize()" } }, providers: [
428
463
  {
429
464
  provide: NG_VALUE_ACCESSOR,
430
465
  useExisting: forwardRef(() => NeuMultiselectComponent),
@@ -585,105 +620,83 @@ class NeuMultiselectComponent {
585
620
  />
586
621
  </div>
587
622
  }
623
+ @if (selectAll()) {
624
+ <button type="button" class="neu-multiselect__select-all" (click)="toggleAllFiltered($event)">
625
+ {{ allFilteredSelected() ? unselectAllLabel() : selectAllLabel() }}
626
+ </button>
627
+ }
588
628
 
589
629
  <!-- Opciones -->
590
630
  <div class="neu-multiselect__options">
591
- @if (virtualScroll()) {
631
+ <ng-template #multiselectOptionTpl let-option>
632
+ <div
633
+ class="neu-multiselect__option"
634
+ [class.neu-multiselect__option--selected]="isSelected(option.value)"
635
+ [class.neu-multiselect__option--disabled]="option.disabled"
636
+ role="option"
637
+ [id]="'neu-ms-opt-' + option.value"
638
+ [attr.aria-selected]="isSelected(option.value)"
639
+ [attr.aria-disabled]="option.disabled"
640
+ [attr.tabindex]="option.disabled ? null : '-1'"
641
+ (click)="toggleOption(option)"
642
+ (keydown.enter)="toggleOption(option)"
643
+ (keydown.space)="toggleOption(option)"
644
+ (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
645
+ (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
646
+ >
647
+ <span
648
+ class="neu-multiselect__checkbox"
649
+ [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
650
+ >
651
+ <svg
652
+ class="neu-multiselect__checkbox-check"
653
+ viewBox="0 0 12 10"
654
+ fill="none"
655
+ stroke="currentColor"
656
+ stroke-width="2"
657
+ stroke-linecap="round"
658
+ stroke-linejoin="round"
659
+ aria-hidden="true"
660
+ >
661
+ <polyline points="1 5 4.5 9 11 1" />
662
+ </svg>
663
+ </span>
664
+ @if (itemTpl()) {
665
+ <ng-container
666
+ [ngTemplateOutlet]="itemTpl()!.templateRef"
667
+ [ngTemplateOutletContext]="{ $implicit: option }"
668
+ />
669
+ } @else {
670
+ {{ option.label }}
671
+ }
672
+ </div>
673
+ </ng-template>
674
+
675
+ @if (loading()) {
676
+ <div class="neu-multiselect__empty" role="status">{{ loadingLabel() }}</div>
677
+ } @else if (virtualScroll()) {
592
678
  <cdk-virtual-scroll-viewport
593
679
  class="neu-multiselect__viewport"
594
680
  [itemSize]="virtualScrollItemSize()"
595
681
  [style.height]="virtualViewportHeight()"
596
682
  >
597
- <div
598
- *cdkVirtualFor="let option of filteredOptions(); trackBy: trackByOptionValue"
599
- class="neu-multiselect__option"
600
- [class.neu-multiselect__option--selected]="isSelected(option.value)"
601
- [class.neu-multiselect__option--disabled]="option.disabled"
602
- role="option"
603
- [id]="'neu-ms-opt-' + option.value"
604
- [attr.aria-selected]="isSelected(option.value)"
605
- [attr.aria-disabled]="option.disabled"
606
- [attr.tabindex]="option.disabled ? null : '-1'"
607
- (click)="toggleOption(option)"
608
- (keydown.enter)="toggleOption(option)"
609
- (keydown.space)="toggleOption(option)"
610
- (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
611
- (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
612
- >
613
- <span
614
- class="neu-multiselect__checkbox"
615
- [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
616
- >
617
- <svg
618
- class="neu-multiselect__checkbox-check"
619
- viewBox="0 0 12 10"
620
- fill="none"
621
- stroke="currentColor"
622
- stroke-width="2"
623
- stroke-linecap="round"
624
- stroke-linejoin="round"
625
- aria-hidden="true"
626
- >
627
- <polyline points="1 5 4.5 9 11 1" />
628
- </svg>
629
- </span>
630
- @if (itemTpl()) {
631
- <ng-container
632
- [ngTemplateOutlet]="itemTpl()!.templateRef"
633
- [ngTemplateOutletContext]="{ $implicit: option }"
634
- />
635
- } @else {
636
- {{ option.label }}
637
- }
638
- </div>
683
+ <ng-container *cdkVirtualFor="let option of filteredOptions(); trackBy: trackByOptionValue">
684
+ <ng-container
685
+ [ngTemplateOutlet]="multiselectOptionTpl"
686
+ [ngTemplateOutletContext]="{ $implicit: option }"
687
+ />
688
+ </ng-container>
639
689
  </cdk-virtual-scroll-viewport>
640
690
  } @else {
641
691
  @for (option of filteredOptions(); track option.value) {
642
- <div
643
- class="neu-multiselect__option"
644
- [class.neu-multiselect__option--selected]="isSelected(option.value)"
645
- [class.neu-multiselect__option--disabled]="option.disabled"
646
- role="option"
647
- [id]="'neu-ms-opt-' + option.value"
648
- [attr.aria-selected]="isSelected(option.value)"
649
- [attr.aria-disabled]="option.disabled"
650
- [attr.tabindex]="option.disabled ? null : '-1'"
651
- (click)="toggleOption(option)"
652
- (keydown.enter)="toggleOption(option)"
653
- (keydown.space)="toggleOption(option)"
654
- (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
655
- (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
656
- >
657
- <span
658
- class="neu-multiselect__checkbox"
659
- [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
660
- >
661
- <svg
662
- class="neu-multiselect__checkbox-check"
663
- viewBox="0 0 12 10"
664
- fill="none"
665
- stroke="currentColor"
666
- stroke-width="2"
667
- stroke-linecap="round"
668
- stroke-linejoin="round"
669
- aria-hidden="true"
670
- >
671
- <polyline points="1 5 4.5 9 11 1" />
672
- </svg>
673
- </span>
674
- @if (itemTpl()) {
675
- <ng-container
676
- [ngTemplateOutlet]="itemTpl()!.templateRef"
677
- [ngTemplateOutletContext]="{ $implicit: option }"
678
- />
679
- } @else {
680
- {{ option.label }}
681
- }
682
- </div>
692
+ <ng-container
693
+ [ngTemplateOutlet]="multiselectOptionTpl"
694
+ [ngTemplateOutletContext]="{ $implicit: option }"
695
+ />
683
696
  }
684
697
  }
685
698
 
686
- @if (filteredOptions().length === 0) {
699
+ @if (!loading() && filteredOptions().length === 0) {
687
700
  <div class="neu-multiselect__empty">{{ noResultsMessage() }}</div>
688
701
  }
689
702
  </div>
@@ -728,7 +741,7 @@ class NeuMultiselectComponent {
728
741
  } @else if (hint()) {
729
742
  <p class="neu-multiselect__hint" [id]="_triggerId + '-hint'">{{ hint() }}</p>
730
743
  }
731
- `, isInline: true, styles: [".neu-multiselect__static-label{display:block;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);margin-bottom:var(--neu-space-2)}.neu-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));transition:top var(--neu-transition),font-size var(--neu-transition),color var(--neu-transition),transform var(--neu-transition),padding var(--neu-transition),background var(--neu-transition)}.neu-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__label{top:0;transform:translateY(-50%);font-size:12px;font-weight:600;letter-spacing:.01em;background:var(--neu-surface);padding:0 4px;left:calc(var(--neu-space-3) - 4px)}.neu-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect--sm .neu-multiselect__trigger{min-height:36px;font-size:var(--neu-text-sm);padding:var(--neu-space-1) var(--neu-space-2);padding-right:36px}.neu-multiselect--lg .neu-multiselect__trigger{min-height:56px}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not([aria-disabled=true]){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:focus-visible{outline:none;border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect__trigger[aria-disabled=true]{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect--error .neu-multiselect__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__clear{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:2px;padding:0;border:none;background:transparent;color:var(--neu-text-muted);cursor:pointer;border-radius:var(--neu-radius-sm);flex-shrink:0;transition:color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:relative;z-index:200;box-sizing:border-box;width:100%;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}.neu-multiselect__panel--virtual{overflow:visible}@media(max-width:600px){.neu-multiselect__panel{left:auto;right:0;width:min(max(100%,240px),100vw - 2rem);max-width:calc(100vw - 2rem)}}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__search-input{width:100%;height:34px;padding:0 var(--neu-space-3);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius-sm);background:var(--neu-bg);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);outline:none;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__panel--virtual .neu-multiselect__options{overflow:hidden}.neu-multiselect__viewport{width:100%}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);min-height:var(--neu-multiselect-option-height, 44px);box-sizing:border-box;cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__empty{padding:var(--neu-space-4);text-align:center;font-size:var(--neu-text-sm);color:var(--neu-text-disabled);font-family:var(--neu-font-sans)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-mode:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__footer-clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px;border-radius:var(--neu-radius-sm)}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary-dark, var(--neu-primary));border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}.neu-multiselect__hint{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-text-muted);font-family:var(--neu-font-sans)}.neu-multiselect__sr-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.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", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: i1.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: ScrollingModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
744
+ `, isInline: true, styles: [".neu-multiselect__static-label{display:block;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);margin-bottom:var(--neu-space-2)}.neu-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));transition:top var(--neu-transition),font-size var(--neu-transition),color var(--neu-transition),transform var(--neu-transition),padding var(--neu-transition),background var(--neu-transition)}.neu-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__label{top:0;transform:translateY(-50%);font-size:12px;font-weight:600;letter-spacing:.01em;background:var(--neu-surface);padding:0 4px;left:calc(var(--neu-space-3) - 4px)}.neu-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect--sm .neu-multiselect__trigger{min-height:36px;font-size:var(--neu-text-sm);padding:var(--neu-space-1) var(--neu-space-2);padding-right:36px}.neu-multiselect--lg .neu-multiselect__trigger{min-height:56px}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not([aria-disabled=true]){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:focus-visible{outline:none;border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect__trigger[aria-disabled=true]{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect--error .neu-multiselect__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__clear{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:2px;padding:0;border:none;background:transparent;color:var(--neu-text-muted);cursor:pointer;border-radius:var(--neu-radius-sm);flex-shrink:0;transition:color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:relative;z-index:200;box-sizing:border-box;width:100%;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}.neu-multiselect__panel--virtual{overflow:visible}@media(max-width:600px){.neu-multiselect__panel{left:auto;right:0;width:min(max(100%,240px),100vw - 2rem);max-width:calc(100vw - 2rem)}}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__search-input{width:100%;height:34px;padding:0 var(--neu-space-3);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius-sm);background:var(--neu-bg);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);outline:none;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__panel--virtual .neu-multiselect__options{overflow:hidden}.neu-multiselect__viewport{width:100%}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);min-height:var(--neu-multiselect-option-height, 44px);box-sizing:border-box;cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__empty{padding:var(--neu-space-4);text-align:center;font-size:var(--neu-text-sm);color:var(--neu-text-disabled);font-family:var(--neu-font-sans)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-mode:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__footer-clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px;border-radius:var(--neu-radius-sm)}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary-dark, var(--neu-primary));border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}html[data-theme=dark] .neu-multiselect__count-badge{background:#0b66d4;color:#fff}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}.neu-multiselect__hint{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-text-muted);font-family:var(--neu-font-sans)}.neu-multiselect__sr-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.neu-multiselect__select-all{width:calc(100% - 16px);margin:8px;border:1px solid var(--neu-border);border-radius:var(--neu-radius-md);background:var(--neu-surface-2);color:var(--neu-text);padding:8px 10px;text-align:left;cursor:pointer}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.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", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: i1.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: ScrollingModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
732
745
  }
733
746
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuMultiselectComponent, decorators: [{
734
747
  type: Component,
@@ -896,105 +909,83 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
896
909
  />
897
910
  </div>
898
911
  }
912
+ @if (selectAll()) {
913
+ <button type="button" class="neu-multiselect__select-all" (click)="toggleAllFiltered($event)">
914
+ {{ allFilteredSelected() ? unselectAllLabel() : selectAllLabel() }}
915
+ </button>
916
+ }
899
917
 
900
918
  <!-- Opciones -->
901
919
  <div class="neu-multiselect__options">
902
- @if (virtualScroll()) {
920
+ <ng-template #multiselectOptionTpl let-option>
921
+ <div
922
+ class="neu-multiselect__option"
923
+ [class.neu-multiselect__option--selected]="isSelected(option.value)"
924
+ [class.neu-multiselect__option--disabled]="option.disabled"
925
+ role="option"
926
+ [id]="'neu-ms-opt-' + option.value"
927
+ [attr.aria-selected]="isSelected(option.value)"
928
+ [attr.aria-disabled]="option.disabled"
929
+ [attr.tabindex]="option.disabled ? null : '-1'"
930
+ (click)="toggleOption(option)"
931
+ (keydown.enter)="toggleOption(option)"
932
+ (keydown.space)="toggleOption(option)"
933
+ (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
934
+ (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
935
+ >
936
+ <span
937
+ class="neu-multiselect__checkbox"
938
+ [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
939
+ >
940
+ <svg
941
+ class="neu-multiselect__checkbox-check"
942
+ viewBox="0 0 12 10"
943
+ fill="none"
944
+ stroke="currentColor"
945
+ stroke-width="2"
946
+ stroke-linecap="round"
947
+ stroke-linejoin="round"
948
+ aria-hidden="true"
949
+ >
950
+ <polyline points="1 5 4.5 9 11 1" />
951
+ </svg>
952
+ </span>
953
+ @if (itemTpl()) {
954
+ <ng-container
955
+ [ngTemplateOutlet]="itemTpl()!.templateRef"
956
+ [ngTemplateOutletContext]="{ $implicit: option }"
957
+ />
958
+ } @else {
959
+ {{ option.label }}
960
+ }
961
+ </div>
962
+ </ng-template>
963
+
964
+ @if (loading()) {
965
+ <div class="neu-multiselect__empty" role="status">{{ loadingLabel() }}</div>
966
+ } @else if (virtualScroll()) {
903
967
  <cdk-virtual-scroll-viewport
904
968
  class="neu-multiselect__viewport"
905
969
  [itemSize]="virtualScrollItemSize()"
906
970
  [style.height]="virtualViewportHeight()"
907
971
  >
908
- <div
909
- *cdkVirtualFor="let option of filteredOptions(); trackBy: trackByOptionValue"
910
- class="neu-multiselect__option"
911
- [class.neu-multiselect__option--selected]="isSelected(option.value)"
912
- [class.neu-multiselect__option--disabled]="option.disabled"
913
- role="option"
914
- [id]="'neu-ms-opt-' + option.value"
915
- [attr.aria-selected]="isSelected(option.value)"
916
- [attr.aria-disabled]="option.disabled"
917
- [attr.tabindex]="option.disabled ? null : '-1'"
918
- (click)="toggleOption(option)"
919
- (keydown.enter)="toggleOption(option)"
920
- (keydown.space)="toggleOption(option)"
921
- (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
922
- (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
923
- >
924
- <span
925
- class="neu-multiselect__checkbox"
926
- [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
927
- >
928
- <svg
929
- class="neu-multiselect__checkbox-check"
930
- viewBox="0 0 12 10"
931
- fill="none"
932
- stroke="currentColor"
933
- stroke-width="2"
934
- stroke-linecap="round"
935
- stroke-linejoin="round"
936
- aria-hidden="true"
937
- >
938
- <polyline points="1 5 4.5 9 11 1" />
939
- </svg>
940
- </span>
941
- @if (itemTpl()) {
942
- <ng-container
943
- [ngTemplateOutlet]="itemTpl()!.templateRef"
944
- [ngTemplateOutletContext]="{ $implicit: option }"
945
- />
946
- } @else {
947
- {{ option.label }}
948
- }
949
- </div>
972
+ <ng-container *cdkVirtualFor="let option of filteredOptions(); trackBy: trackByOptionValue">
973
+ <ng-container
974
+ [ngTemplateOutlet]="multiselectOptionTpl"
975
+ [ngTemplateOutletContext]="{ $implicit: option }"
976
+ />
977
+ </ng-container>
950
978
  </cdk-virtual-scroll-viewport>
951
979
  } @else {
952
980
  @for (option of filteredOptions(); track option.value) {
953
- <div
954
- class="neu-multiselect__option"
955
- [class.neu-multiselect__option--selected]="isSelected(option.value)"
956
- [class.neu-multiselect__option--disabled]="option.disabled"
957
- role="option"
958
- [id]="'neu-ms-opt-' + option.value"
959
- [attr.aria-selected]="isSelected(option.value)"
960
- [attr.aria-disabled]="option.disabled"
961
- [attr.tabindex]="option.disabled ? null : '-1'"
962
- (click)="toggleOption(option)"
963
- (keydown.enter)="toggleOption(option)"
964
- (keydown.space)="toggleOption(option)"
965
- (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
966
- (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
967
- >
968
- <span
969
- class="neu-multiselect__checkbox"
970
- [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
971
- >
972
- <svg
973
- class="neu-multiselect__checkbox-check"
974
- viewBox="0 0 12 10"
975
- fill="none"
976
- stroke="currentColor"
977
- stroke-width="2"
978
- stroke-linecap="round"
979
- stroke-linejoin="round"
980
- aria-hidden="true"
981
- >
982
- <polyline points="1 5 4.5 9 11 1" />
983
- </svg>
984
- </span>
985
- @if (itemTpl()) {
986
- <ng-container
987
- [ngTemplateOutlet]="itemTpl()!.templateRef"
988
- [ngTemplateOutletContext]="{ $implicit: option }"
989
- />
990
- } @else {
991
- {{ option.label }}
992
- }
993
- </div>
981
+ <ng-container
982
+ [ngTemplateOutlet]="multiselectOptionTpl"
983
+ [ngTemplateOutletContext]="{ $implicit: option }"
984
+ />
994
985
  }
995
986
  }
996
987
 
997
- @if (filteredOptions().length === 0) {
988
+ @if (!loading() && filteredOptions().length === 0) {
998
989
  <div class="neu-multiselect__empty">{{ noResultsMessage() }}</div>
999
990
  }
1000
991
  </div>
@@ -1039,8 +1030,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
1039
1030
  } @else if (hint()) {
1040
1031
  <p class="neu-multiselect__hint" [id]="_triggerId + '-hint'">{{ hint() }}</p>
1041
1032
  }
1042
- `, styles: [".neu-multiselect__static-label{display:block;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);margin-bottom:var(--neu-space-2)}.neu-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));transition:top var(--neu-transition),font-size var(--neu-transition),color var(--neu-transition),transform var(--neu-transition),padding var(--neu-transition),background var(--neu-transition)}.neu-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__label{top:0;transform:translateY(-50%);font-size:12px;font-weight:600;letter-spacing:.01em;background:var(--neu-surface);padding:0 4px;left:calc(var(--neu-space-3) - 4px)}.neu-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect--sm .neu-multiselect__trigger{min-height:36px;font-size:var(--neu-text-sm);padding:var(--neu-space-1) var(--neu-space-2);padding-right:36px}.neu-multiselect--lg .neu-multiselect__trigger{min-height:56px}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not([aria-disabled=true]){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:focus-visible{outline:none;border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect__trigger[aria-disabled=true]{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect--error .neu-multiselect__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__clear{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:2px;padding:0;border:none;background:transparent;color:var(--neu-text-muted);cursor:pointer;border-radius:var(--neu-radius-sm);flex-shrink:0;transition:color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:relative;z-index:200;box-sizing:border-box;width:100%;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}.neu-multiselect__panel--virtual{overflow:visible}@media(max-width:600px){.neu-multiselect__panel{left:auto;right:0;width:min(max(100%,240px),100vw - 2rem);max-width:calc(100vw - 2rem)}}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__search-input{width:100%;height:34px;padding:0 var(--neu-space-3);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius-sm);background:var(--neu-bg);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);outline:none;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__panel--virtual .neu-multiselect__options{overflow:hidden}.neu-multiselect__viewport{width:100%}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);min-height:var(--neu-multiselect-option-height, 44px);box-sizing:border-box;cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__empty{padding:var(--neu-space-4);text-align:center;font-size:var(--neu-text-sm);color:var(--neu-text-disabled);font-family:var(--neu-font-sans)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-mode:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__footer-clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px;border-radius:var(--neu-radius-sm)}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary-dark, var(--neu-primary));border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}.neu-multiselect__hint{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-text-muted);font-family:var(--neu-font-sans)}.neu-multiselect__sr-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
1043
- }], ctorParameters: () => [], propDecorators: { _viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuMultiselectItemDirective), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollVisibleItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollVisibleItems", required: false }] }], clearAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAriaLabel", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
1033
+ `, styles: [".neu-multiselect__static-label{display:block;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);margin-bottom:var(--neu-space-2)}.neu-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));transition:top var(--neu-transition),font-size var(--neu-transition),color var(--neu-transition),transform var(--neu-transition),padding var(--neu-transition),background var(--neu-transition)}.neu-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__label{top:0;transform:translateY(-50%);font-size:12px;font-weight:600;letter-spacing:.01em;background:var(--neu-surface);padding:0 4px;left:calc(var(--neu-space-3) - 4px)}.neu-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect--sm .neu-multiselect__trigger{min-height:36px;font-size:var(--neu-text-sm);padding:var(--neu-space-1) var(--neu-space-2);padding-right:36px}.neu-multiselect--lg .neu-multiselect__trigger{min-height:56px}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not([aria-disabled=true]){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:focus-visible{outline:none;border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect__trigger[aria-disabled=true]{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect--error .neu-multiselect__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__clear{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:2px;padding:0;border:none;background:transparent;color:var(--neu-text-muted);cursor:pointer;border-radius:var(--neu-radius-sm);flex-shrink:0;transition:color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:relative;z-index:200;box-sizing:border-box;width:100%;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}.neu-multiselect__panel--virtual{overflow:visible}@media(max-width:600px){.neu-multiselect__panel{left:auto;right:0;width:min(max(100%,240px),100vw - 2rem);max-width:calc(100vw - 2rem)}}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__search-input{width:100%;height:34px;padding:0 var(--neu-space-3);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius-sm);background:var(--neu-bg);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);outline:none;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__panel--virtual .neu-multiselect__options{overflow:hidden}.neu-multiselect__viewport{width:100%}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);min-height:var(--neu-multiselect-option-height, 44px);box-sizing:border-box;cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__empty{padding:var(--neu-space-4);text-align:center;font-size:var(--neu-text-sm);color:var(--neu-text-disabled);font-family:var(--neu-font-sans)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-mode:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__footer-clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px;border-radius:var(--neu-radius-sm)}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary-dark, var(--neu-primary));border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}html[data-theme=dark] .neu-multiselect__count-badge{background:#0b66d4;color:#fff}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}.neu-multiselect__hint{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-text-muted);font-family:var(--neu-font-sans)}.neu-multiselect__sr-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.neu-multiselect__select-all{width:calc(100% - 16px);margin:8px;border:1px solid var(--neu-border);border-radius:var(--neu-radius-md);background:var(--neu-surface-2);color:var(--neu-text);padding:8px 10px;text-align:left;cursor:pointer}\n"] }]
1034
+ }], ctorParameters: () => [], propDecorators: { _viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuMultiselectItemDirective), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], selectAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAll", required: false }] }], selectAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllLabel", required: false }] }], unselectAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "unselectAllLabel", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollVisibleItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollVisibleItems", required: false }] }], clearAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAriaLabel", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
1044
1035
 
1045
1036
  /**
1046
1037
  * Generated bundle index. Do not edit.