@neural-ui/core 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +56 -88
  2. package/accordion/package.json +4 -0
  3. package/alert/package.json +4 -0
  4. package/autocomplete/package.json +4 -0
  5. package/avatar/package.json +4 -0
  6. package/badge/package.json +4 -0
  7. package/block-ui/package.json +4 -0
  8. package/breadcrumb/package.json +4 -0
  9. package/button/package.json +4 -0
  10. package/card/package.json +4 -0
  11. package/chart/package.json +4 -0
  12. package/checkbox/package.json +4 -0
  13. package/chip/package.json +4 -0
  14. package/code-block/package.json +4 -0
  15. package/color-picker/package.json +4 -0
  16. package/command-palette/package.json +4 -0
  17. package/confirm-dialog/package.json +4 -0
  18. package/context-menu/package.json +4 -0
  19. package/dashboard-grid/package.json +4 -0
  20. package/date-input/package.json +4 -0
  21. package/divider/package.json +4 -0
  22. package/empty-state/package.json +4 -0
  23. package/fesm2022/neural-ui-core-accordion.mjs +162 -0
  24. package/fesm2022/neural-ui-core-accordion.mjs.map +1 -0
  25. package/fesm2022/neural-ui-core-alert.mjs +116 -0
  26. package/fesm2022/neural-ui-core-alert.mjs.map +1 -0
  27. package/fesm2022/neural-ui-core-autocomplete.mjs +406 -0
  28. package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -0
  29. package/fesm2022/neural-ui-core-avatar.mjs +109 -0
  30. package/fesm2022/neural-ui-core-avatar.mjs.map +1 -0
  31. package/fesm2022/neural-ui-core-badge.mjs +54 -0
  32. package/fesm2022/neural-ui-core-badge.mjs.map +1 -0
  33. package/fesm2022/neural-ui-core-block-ui.mjs +95 -0
  34. package/fesm2022/neural-ui-core-block-ui.mjs.map +1 -0
  35. package/fesm2022/neural-ui-core-breadcrumb.mjs +84 -0
  36. package/fesm2022/neural-ui-core-breadcrumb.mjs.map +1 -0
  37. package/fesm2022/neural-ui-core-button.mjs +125 -0
  38. package/fesm2022/neural-ui-core-button.mjs.map +1 -0
  39. package/fesm2022/neural-ui-core-card.mjs +69 -0
  40. package/fesm2022/neural-ui-core-card.mjs.map +1 -0
  41. package/fesm2022/neural-ui-core-chart.mjs +287 -0
  42. package/fesm2022/neural-ui-core-chart.mjs.map +1 -0
  43. package/fesm2022/neural-ui-core-checkbox.mjs +138 -0
  44. package/fesm2022/neural-ui-core-checkbox.mjs.map +1 -0
  45. package/fesm2022/neural-ui-core-chip.mjs +130 -0
  46. package/fesm2022/neural-ui-core-chip.mjs.map +1 -0
  47. package/fesm2022/neural-ui-core-code-block.mjs +250 -0
  48. package/fesm2022/neural-ui-core-code-block.mjs.map +1 -0
  49. package/fesm2022/neural-ui-core-color-picker.mjs +435 -0
  50. package/fesm2022/neural-ui-core-color-picker.mjs.map +1 -0
  51. package/fesm2022/neural-ui-core-command-palette.mjs +235 -0
  52. package/fesm2022/neural-ui-core-command-palette.mjs.map +1 -0
  53. package/fesm2022/neural-ui-core-confirm-dialog.mjs +118 -0
  54. package/fesm2022/neural-ui-core-confirm-dialog.mjs.map +1 -0
  55. package/fesm2022/neural-ui-core-context-menu.mjs +158 -0
  56. package/fesm2022/neural-ui-core-context-menu.mjs.map +1 -0
  57. package/fesm2022/neural-ui-core-dashboard-grid.mjs +144 -0
  58. package/fesm2022/neural-ui-core-dashboard-grid.mjs.map +1 -0
  59. package/fesm2022/neural-ui-core-date-input.mjs +1332 -0
  60. package/fesm2022/neural-ui-core-date-input.mjs.map +1 -0
  61. package/fesm2022/neural-ui-core-divider.mjs +54 -0
  62. package/fesm2022/neural-ui-core-divider.mjs.map +1 -0
  63. package/fesm2022/neural-ui-core-empty-state.mjs +84 -0
  64. package/fesm2022/neural-ui-core-empty-state.mjs.map +1 -0
  65. package/fesm2022/neural-ui-core-filter-bar.mjs +118 -0
  66. package/fesm2022/neural-ui-core-filter-bar.mjs.map +1 -0
  67. package/fesm2022/neural-ui-core-icon.mjs +50 -0
  68. package/fesm2022/neural-ui-core-icon.mjs.map +1 -0
  69. package/fesm2022/neural-ui-core-image-viewer.mjs +309 -0
  70. package/fesm2022/neural-ui-core-image-viewer.mjs.map +1 -0
  71. package/fesm2022/neural-ui-core-input-otp.mjs +192 -0
  72. package/fesm2022/neural-ui-core-input-otp.mjs.map +1 -0
  73. package/fesm2022/neural-ui-core-input.mjs +320 -0
  74. package/fesm2022/neural-ui-core-input.mjs.map +1 -0
  75. package/fesm2022/neural-ui-core-knob.mjs +323 -0
  76. package/fesm2022/neural-ui-core-knob.mjs.map +1 -0
  77. package/fesm2022/neural-ui-core-meter-group.mjs +122 -0
  78. package/fesm2022/neural-ui-core-meter-group.mjs.map +1 -0
  79. package/fesm2022/neural-ui-core-modal.mjs +156 -0
  80. package/fesm2022/neural-ui-core-modal.mjs.map +1 -0
  81. package/fesm2022/neural-ui-core-multiselect.mjs +825 -0
  82. package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -0
  83. package/fesm2022/neural-ui-core-nav.mjs +952 -0
  84. package/fesm2022/neural-ui-core-nav.mjs.map +1 -0
  85. package/fesm2022/neural-ui-core-notification-center.mjs +264 -0
  86. package/fesm2022/neural-ui-core-notification-center.mjs.map +1 -0
  87. package/fesm2022/neural-ui-core-number-input.mjs +331 -0
  88. package/fesm2022/neural-ui-core-number-input.mjs.map +1 -0
  89. package/fesm2022/neural-ui-core-pagination.mjs +198 -0
  90. package/fesm2022/neural-ui-core-pagination.mjs.map +1 -0
  91. package/fesm2022/neural-ui-core-popover.mjs +207 -0
  92. package/fesm2022/neural-ui-core-popover.mjs.map +1 -0
  93. package/fesm2022/neural-ui-core-progress-bar.mjs +105 -0
  94. package/fesm2022/neural-ui-core-progress-bar.mjs.map +1 -0
  95. package/fesm2022/neural-ui-core-radio.mjs +171 -0
  96. package/fesm2022/neural-ui-core-radio.mjs.map +1 -0
  97. package/fesm2022/neural-ui-core-rating.mjs +151 -0
  98. package/fesm2022/neural-ui-core-rating.mjs.map +1 -0
  99. package/fesm2022/neural-ui-core-select.mjs +710 -0
  100. package/fesm2022/neural-ui-core-select.mjs.map +1 -0
  101. package/fesm2022/neural-ui-core-sidebar.mjs +214 -0
  102. package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -0
  103. package/fesm2022/neural-ui-core-skeleton.mjs +40 -0
  104. package/fesm2022/neural-ui-core-skeleton.mjs.map +1 -0
  105. package/fesm2022/neural-ui-core-slider.mjs +146 -0
  106. package/fesm2022/neural-ui-core-slider.mjs.map +1 -0
  107. package/fesm2022/neural-ui-core-spinner.mjs +113 -0
  108. package/fesm2022/neural-ui-core-spinner.mjs.map +1 -0
  109. package/fesm2022/neural-ui-core-split-button.mjs +252 -0
  110. package/fesm2022/neural-ui-core-split-button.mjs.map +1 -0
  111. package/fesm2022/neural-ui-core-splitter.mjs +174 -0
  112. package/fesm2022/neural-ui-core-splitter.mjs.map +1 -0
  113. package/fesm2022/neural-ui-core-stats-card.mjs +163 -0
  114. package/fesm2022/neural-ui-core-stats-card.mjs.map +1 -0
  115. package/fesm2022/neural-ui-core-stepper.mjs +204 -0
  116. package/fesm2022/neural-ui-core-stepper.mjs.map +1 -0
  117. package/fesm2022/neural-ui-core-switch.mjs +111 -0
  118. package/fesm2022/neural-ui-core-switch.mjs.map +1 -0
  119. package/fesm2022/neural-ui-core-table.mjs +1872 -0
  120. package/fesm2022/neural-ui-core-table.mjs.map +1 -0
  121. package/fesm2022/neural-ui-core-tabs.mjs +338 -0
  122. package/fesm2022/neural-ui-core-tabs.mjs.map +1 -0
  123. package/fesm2022/neural-ui-core-textarea.mjs +188 -0
  124. package/fesm2022/neural-ui-core-textarea.mjs.map +1 -0
  125. package/fesm2022/neural-ui-core-timeline.mjs +117 -0
  126. package/fesm2022/neural-ui-core-timeline.mjs.map +1 -0
  127. package/fesm2022/neural-ui-core-toast.mjs +171 -0
  128. package/fesm2022/neural-ui-core-toast.mjs.map +1 -0
  129. package/fesm2022/neural-ui-core-toggle-button-group.mjs +162 -0
  130. package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -0
  131. package/fesm2022/neural-ui-core-toolbar.mjs +67 -0
  132. package/fesm2022/neural-ui-core-toolbar.mjs.map +1 -0
  133. package/fesm2022/neural-ui-core-tooltip.mjs +151 -0
  134. package/fesm2022/neural-ui-core-tooltip.mjs.map +1 -0
  135. package/fesm2022/neural-ui-core-url-state.mjs +96 -0
  136. package/fesm2022/neural-ui-core-url-state.mjs.map +1 -0
  137. package/fesm2022/neural-ui-core-virtual-list.mjs +126 -0
  138. package/fesm2022/neural-ui-core-virtual-list.mjs.map +1 -0
  139. package/fesm2022/neural-ui-core.mjs +11 -8544
  140. package/fesm2022/neural-ui-core.mjs.map +1 -1
  141. package/filter-bar/package.json +4 -0
  142. package/icon/package.json +4 -0
  143. package/image-viewer/package.json +4 -0
  144. package/input/package.json +4 -0
  145. package/input-otp/package.json +4 -0
  146. package/knob/package.json +4 -0
  147. package/meter-group/package.json +4 -0
  148. package/modal/package.json +4 -0
  149. package/multiselect/package.json +4 -0
  150. package/nav/package.json +4 -0
  151. package/notification-center/package.json +4 -0
  152. package/number-input/package.json +4 -0
  153. package/package.json +252 -5
  154. package/pagination/package.json +4 -0
  155. package/popover/package.json +4 -0
  156. package/progress-bar/package.json +4 -0
  157. package/radio/package.json +4 -0
  158. package/rating/package.json +4 -0
  159. package/select/package.json +4 -0
  160. package/sidebar/package.json +4 -0
  161. package/skeleton/package.json +4 -0
  162. package/slider/package.json +4 -0
  163. package/spinner/package.json +4 -0
  164. package/split-button/package.json +4 -0
  165. package/splitter/package.json +4 -0
  166. package/stats-card/package.json +4 -0
  167. package/stepper/package.json +4 -0
  168. package/styles/_tokens.scss +202 -0
  169. package/styles.scss +1 -0
  170. package/switch/package.json +4 -0
  171. package/table/package.json +4 -0
  172. package/tabs/package.json +4 -0
  173. package/textarea/package.json +4 -0
  174. package/timeline/package.json +4 -0
  175. package/toast/package.json +4 -0
  176. package/toggle-button-group/package.json +4 -0
  177. package/toolbar/package.json +4 -0
  178. package/tooltip/package.json +4 -0
  179. package/types/neural-ui-core-accordion.d.ts +55 -0
  180. package/types/neural-ui-core-alert.d.ts +47 -0
  181. package/types/neural-ui-core-autocomplete.d.ts +75 -0
  182. package/types/neural-ui-core-avatar.d.ts +39 -0
  183. package/types/neural-ui-core-badge.d.ts +36 -0
  184. package/types/neural-ui-core-block-ui.d.ts +46 -0
  185. package/types/neural-ui-core-breadcrumb.d.ts +38 -0
  186. package/types/neural-ui-core-button.d.ts +55 -0
  187. package/types/neural-ui-core-card.d.ts +37 -0
  188. package/types/neural-ui-core-chart.d.ts +236 -0
  189. package/types/neural-ui-core-checkbox.d.ts +33 -0
  190. package/types/neural-ui-core-chip.d.ts +53 -0
  191. package/types/neural-ui-core-code-block.d.ts +55 -0
  192. package/types/neural-ui-core-color-picker.d.ts +55 -0
  193. package/types/neural-ui-core-command-palette.d.ts +56 -0
  194. package/types/neural-ui-core-confirm-dialog.d.ts +50 -0
  195. package/types/neural-ui-core-context-menu.d.ts +66 -0
  196. package/types/neural-ui-core-dashboard-grid.d.ts +41 -0
  197. package/types/neural-ui-core-date-input.d.ts +178 -0
  198. package/types/neural-ui-core-divider.d.ts +20 -0
  199. package/types/neural-ui-core-empty-state.d.ts +32 -0
  200. package/types/neural-ui-core-filter-bar.d.ts +49 -0
  201. package/types/neural-ui-core-icon.d.ts +33 -0
  202. package/types/neural-ui-core-image-viewer.d.ts +67 -0
  203. package/types/neural-ui-core-input-otp.d.ts +49 -0
  204. package/types/neural-ui-core-input.d.ts +86 -0
  205. package/types/neural-ui-core-knob.d.ts +68 -0
  206. package/types/neural-ui-core-meter-group.d.ts +52 -0
  207. package/types/neural-ui-core-modal.d.ts +54 -0
  208. package/types/neural-ui-core-multiselect.d.ts +138 -0
  209. package/types/neural-ui-core-nav.d.ts +69 -0
  210. package/types/neural-ui-core-notification-center.d.ts +60 -0
  211. package/types/neural-ui-core-number-input.d.ts +63 -0
  212. package/types/neural-ui-core-pagination.d.ts +30 -0
  213. package/types/neural-ui-core-popover.d.ts +73 -0
  214. package/types/neural-ui-core-progress-bar.d.ts +35 -0
  215. package/types/neural-ui-core-radio.d.ts +51 -0
  216. package/types/neural-ui-core-rating.d.ts +34 -0
  217. package/types/neural-ui-core-select.d.ts +170 -0
  218. package/types/neural-ui-core-sidebar.d.ts +57 -0
  219. package/types/neural-ui-core-skeleton.d.ts +22 -0
  220. package/types/neural-ui-core-slider.d.ts +42 -0
  221. package/types/neural-ui-core-spinner.d.ts +38 -0
  222. package/types/neural-ui-core-split-button.d.ts +65 -0
  223. package/types/neural-ui-core-splitter.d.ts +28 -0
  224. package/types/neural-ui-core-stats-card.d.ts +39 -0
  225. package/types/neural-ui-core-stepper.d.ts +51 -0
  226. package/types/neural-ui-core-switch.d.ts +34 -0
  227. package/types/neural-ui-core-table.d.ts +285 -0
  228. package/types/neural-ui-core-tabs.d.ts +88 -0
  229. package/types/neural-ui-core-textarea.d.ts +52 -0
  230. package/types/neural-ui-core-timeline.d.ts +33 -0
  231. package/types/neural-ui-core-toast.d.ts +70 -0
  232. package/types/neural-ui-core-toggle-button-group.d.ts +63 -0
  233. package/types/neural-ui-core-toolbar.d.ts +36 -0
  234. package/types/neural-ui-core-tooltip.d.ts +48 -0
  235. package/types/neural-ui-core-url-state.d.ts +58 -0
  236. package/types/neural-ui-core-virtual-list.d.ts +60 -0
  237. package/types/neural-ui-core.d.ts +3 -2105
  238. package/url-state/package.json +4 -0
  239. package/virtual-list/package.json +4 -0
@@ -0,0 +1,825 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, TemplateRef, Directive, ElementRef, effect, untracked, contentChild, input, output, signal, computed, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import { NeuUrlStateService } from '@neural-ui/core/url-state';
4
+ import { NgTemplateOutlet } from '@angular/common';
5
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
+
7
+ /**
8
+ * Directiva para personalizar el template de cada ítem del dropdown de Multiselect. / Directive to customize the template of each Multiselect dropdown item.
9
+ *
10
+ * Uso:
11
+ * ```html
12
+ * <neu-multiselect [options]="opts" [formControl]="valuesCtrl">
13
+ * <ng-template neuMultiselectItem let-item>
14
+ * <span class="flag flag-{{ item.value }}"></span>
15
+ * {{ item.label }}
16
+ * </ng-template>
17
+ * </neu-multiselect>
18
+ * ```
19
+ */
20
+ class NeuMultiselectItemDirective {
21
+ templateRef = inject(TemplateRef);
22
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuMultiselectItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
23
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: NeuMultiselectItemDirective, isStandalone: true, selector: "[neuMultiselectItem]", ngImport: i0 });
24
+ }
25
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuMultiselectItemDirective, decorators: [{
26
+ type: Directive,
27
+ args: [{ selector: '[neuMultiselectItem]', standalone: true }]
28
+ }] });
29
+
30
+ let _neuMultiselectIdSeq = 0;
31
+ function arraysEqual(left, right) {
32
+ return left.length === right.length && left.every((value, index) => value === right[index]);
33
+ }
34
+ /**
35
+ * NeuralUI Multiselect Component
36
+ *
37
+ * Dropdown de selección múltiple con chips, búsqueda integrada y soporte / Multiple selection dropdown with chips, integrated search and support
38
+ * para ControlValueAccessor y Reactive Forms. Puede usarse dentro de un FormGroup o con un FormControl standalone. / for ControlValueAccessor and Reactive Forms. It can be used inside a FormGroup or with a standalone FormControl.
39
+ *
40
+ * Uso:
41
+ * readonly technologiesCtrl = new FormControl<string[]>([], { nonNullable: true });
42
+ * <neu-multiselect label="Tecnologías" [options]="opts" [formControl]="technologiesCtrl" />
43
+ */
44
+ class NeuMultiselectComponent {
45
+ elementRef = inject(ElementRef);
46
+ _urlState = inject(NeuUrlStateService);
47
+ _mobileViewportMax = 768;
48
+ _viewportMargin = 16;
49
+ _urlParamSignals = new Map();
50
+ _getUrlParamSignal(key) {
51
+ let paramSignal = this._urlParamSignals.get(key);
52
+ if (!paramSignal) {
53
+ paramSignal = this._urlState.getParam(key);
54
+ this._urlParamSignals.set(key, paramSignal);
55
+ }
56
+ return paramSignal;
57
+ }
58
+ constructor() {
59
+ effect(() => {
60
+ const param = this.urlParam();
61
+ if (!param)
62
+ return;
63
+ const urlRaw = this._getUrlParamSignal(param)();
64
+ const urlVals = urlRaw ? urlRaw.split(',').filter(Boolean) : [];
65
+ const current = untracked(() => this._values());
66
+ if (!arraysEqual(urlVals, current)) {
67
+ this._values.set(urlVals);
68
+ this._onChange(urlVals);
69
+ }
70
+ });
71
+ }
72
+ /** @internal */
73
+ _triggerId = `neu-multiselect-trigger-${_neuMultiselectIdSeq++}`;
74
+ _panelId = `${this._triggerId}-panel`;
75
+ /** Template personalizado para cada opción del dropdown / Custom template for each dropdown option */
76
+ itemTpl = contentChild(NeuMultiselectItemDirective, ...(ngDevMode ? [{ debugName: "itemTpl" }] : /* istanbul ignore next */ []));
77
+ /** Opciones del dropdown / Dropdown options */
78
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
79
+ /** Etiqueta del componente / Component label */
80
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
81
+ /** Muestra el label como flotante dentro del campo (true) o estático encima (false) / Shows the label as floating inside the field (true) or static above (false) */
82
+ floatingLabel = input(false, ...(ngDevMode ? [{ debugName: "floatingLabel" }] : /* istanbul ignore next */ []));
83
+ /** Tamaño del campo: 'sm' = 36px | 'md' = 48px | 'lg' = 56px / Field size */
84
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
85
+ /** Placeholder cuando no hay selección / Placeholder when there is no selection */
86
+ placeholder = input('Seleccionar...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
87
+ /** Mensaje de error / Error message */
88
+ errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
89
+ /** Texto de ayuda bajo el campo / Helper text below the field */
90
+ hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
91
+ /** Deshabilita el componente / Disables the component */
92
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
93
+ /** Activa input de búsqueda/filtro en el panel / Activates the search/filter input in the panel */
94
+ searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
95
+ /** Placeholder del input de búsqueda / Search input placeholder */
96
+ searchPlaceholder = input('Buscar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
97
+ /** Texto cuando no hay opciones tras filtrar / Text when no options remain after filtering */
98
+ noResultsMessage = input('Sin resultados', ...(ngDevMode ? [{ debugName: "noResultsMessage" }] : /* istanbul ignore next */ []));
99
+ /** Texto del botón de limpiar todas las selecciones / Button text to clear all selections */
100
+ clearAllLabel = input('Limpiar todo', ...(ngDevMode ? [{ debugName: "clearAllLabel" }] : /* istanbul ignore next */ []));
101
+ /** Muestra un botón × en el trigger para limpiar la selección de una vez / Shows a × button in the trigger to clear the selection at once */
102
+ clearable = input(false, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
103
+ /** Aria-label del botón clear que aparece en el trigger / Aria-label for the clear button shown in the trigger */
104
+ clearAriaLabel = input('Limpiar selección', ...(ngDevMode ? [{ debugName: "clearAriaLabel" }] : /* istanbul ignore next */ []));
105
+ /**
106
+ * Sincroniza los valores seleccionados con este query param de la URL.
107
+ * Los valores se codifican como lista separada por comas: `?{urlParam}=a,b,c`.
108
+ * Pasar `null` (default) deshabilita la sincronización.
109
+ */
110
+ urlParam = input(null, ...(ngDevMode ? [{ debugName: "urlParam" }] : /* istanbul ignore next */ []));
111
+ /**
112
+ * Emite el array de NeuSelectOption completo (incluyendo data) al cambiar la selección.
113
+ * Emite [] al limpiar toda la selección.
114
+ * Los valores del formControl siguen siendo string[].
115
+ */
116
+ selectionChange = output();
117
+ // --- Estado interno ---
118
+ _values = signal([], ...(ngDevMode ? [{ debugName: "_values" }] : /* istanbul ignore next */ []));
119
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
120
+ searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
121
+ _chipMode = signal('count', ...(ngDevMode ? [{ debugName: "_chipMode" }] : /* istanbul ignore next */ []));
122
+ panelPosition = signal({
123
+ position: null,
124
+ top: null,
125
+ left: null,
126
+ width: null,
127
+ maxHeight: null,
128
+ }, ...(ngDevMode ? [{ debugName: "panelPosition" }] : /* istanbul ignore next */ []));
129
+ _visibleChips = computed(() => this._values().slice(0, 3), ...(ngDevMode ? [{ debugName: "_visibleChips" }] : /* istanbul ignore next */ []));
130
+ hasError = computed(() => !!this.errorMessage(), ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
131
+ describedBy = computed(() => {
132
+ if (this.hasError()) {
133
+ return `${this._triggerId}-error`;
134
+ }
135
+ if (this.hint()) {
136
+ return `${this._triggerId}-hint`;
137
+ }
138
+ return null;
139
+ }, ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
140
+ filteredOptions = computed(() => {
141
+ const q = this.searchQuery().toLowerCase().trim();
142
+ if (!q)
143
+ return this.options();
144
+ return this.options().filter((o) => o.label.toLowerCase().includes(q));
145
+ }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
146
+ resultsAnnouncement = computed(() => {
147
+ if (!this.isOpen()) {
148
+ return '';
149
+ }
150
+ const total = this.filteredOptions().length;
151
+ if (!total) {
152
+ return this.noResultsMessage();
153
+ }
154
+ return total === 1 ? '1 opción disponible' : `${total} opciones disponibles`;
155
+ }, ...(ngDevMode ? [{ debugName: "resultsAnnouncement" }] : /* istanbul ignore next */ []));
156
+ // --- CVA ---
157
+ _onChange = () => { };
158
+ _onTouched = () => { };
159
+ writeValue(value) {
160
+ this._values.set(Array.isArray(value) ? value : []);
161
+ }
162
+ registerOnChange(fn) {
163
+ this._onChange = fn;
164
+ }
165
+ registerOnTouched(fn) {
166
+ this._onTouched = fn;
167
+ }
168
+ _cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
169
+ setDisabledState(isDisabled) {
170
+ this._cvaDisabled.set(isDisabled);
171
+ }
172
+ isDisabledFinal = computed(() => this.disabled() || this._cvaDisabled(), ...(ngDevMode ? [{ debugName: "isDisabledFinal" }] : /* istanbul ignore next */ []));
173
+ // --- Helpers ---
174
+ labelFor(value) {
175
+ return this.options().find((o) => o.value === value)?.label ?? value;
176
+ }
177
+ isSelected(value) {
178
+ return this._values().includes(value);
179
+ }
180
+ toggle() {
181
+ if (this.isDisabledFinal())
182
+ return;
183
+ this.isOpen.update((v) => !v);
184
+ if (!this.isOpen()) {
185
+ this.searchQuery.set('');
186
+ this.resetPanelPosition();
187
+ this._onTouched();
188
+ }
189
+ else {
190
+ this.syncPanelPosition();
191
+ requestAnimationFrame(() => {
192
+ const first = this.elementRef.nativeElement.querySelector('.neu-multiselect__option:not([aria-disabled="true"])');
193
+ first?.focus();
194
+ });
195
+ }
196
+ }
197
+ /** Abre el panel y mueve el foco al primer item / Opens the panel and moves focus to the first item */
198
+ onTriggerKey(event) {
199
+ if (event.target !== event.currentTarget) {
200
+ return;
201
+ }
202
+ event.preventDefault();
203
+ if (!this.isOpen()) {
204
+ this.isOpen.set(true);
205
+ this.syncPanelPosition();
206
+ requestAnimationFrame(() => {
207
+ const first = this.elementRef.nativeElement.querySelector('.neu-multiselect__option:not([aria-disabled="true"])');
208
+ first?.focus();
209
+ });
210
+ }
211
+ }
212
+ onTriggerActionKey(event) {
213
+ if (event.target !== event.currentTarget) {
214
+ return;
215
+ }
216
+ event.preventDefault();
217
+ this.toggle();
218
+ }
219
+ focusTrigger() {
220
+ this.elementRef.nativeElement.querySelector('.neu-multiselect__trigger')?.focus();
221
+ }
222
+ /** Navega entre opciones con flechas / Navigates between options with arrows */
223
+ focusOptionByIndex(event, current, dir) {
224
+ event.preventDefault();
225
+ const opts = this.filteredOptions().filter((o) => !o.disabled);
226
+ const idx = opts.findIndex((o) => o.value === current.value);
227
+ const next = opts[(idx + dir + opts.length) % opts.length];
228
+ if (next) {
229
+ const el = this.elementRef.nativeElement.querySelector(`#neu-ms-opt-${next.value}`);
230
+ el?.focus();
231
+ }
232
+ }
233
+ close() {
234
+ this.isOpen.set(false);
235
+ this.searchQuery.set('');
236
+ this.resetPanelPosition();
237
+ this._onTouched();
238
+ }
239
+ toggleOption(option) {
240
+ if (option.disabled)
241
+ return;
242
+ const current = this._values();
243
+ const next = current.includes(option.value)
244
+ ? current.filter((v) => v !== option.value)
245
+ : [...current, option.value];
246
+ this._values.set(next);
247
+ this._onChange(next);
248
+ this.selectionChange.emit(this.options().filter((o) => next.includes(o.value)));
249
+ const param = this.urlParam();
250
+ if (param)
251
+ this._urlState.setParam(param, next.length ? next.join(',') : null);
252
+ }
253
+ removeValue(value, event) {
254
+ event.stopPropagation();
255
+ const next = this._values().filter((v) => v !== value);
256
+ this._values.set(next);
257
+ this._onChange(next);
258
+ this._onTouched();
259
+ this.selectionChange.emit(this.options().filter((o) => next.includes(o.value)));
260
+ const param = this.urlParam();
261
+ if (param)
262
+ this._urlState.setParam(param, next.length ? next.join(',') : null);
263
+ }
264
+ clearAll(event) {
265
+ event.stopPropagation();
266
+ this._values.set([]);
267
+ this._onChange([]);
268
+ this._onTouched();
269
+ this.selectionChange.emit([]);
270
+ const param = this.urlParam();
271
+ if (param)
272
+ this._urlState.setParam(param, null);
273
+ }
274
+ toggleChipMode(event) {
275
+ event.stopPropagation();
276
+ this._chipMode.set(this._chipMode() === 'chips' ? 'count' : 'chips');
277
+ }
278
+ onDocumentClick(event) {
279
+ if (!this.elementRef.nativeElement.contains(event.target)) {
280
+ this.close();
281
+ }
282
+ }
283
+ onWindowResize() {
284
+ if (this.isOpen()) {
285
+ this.syncPanelPosition();
286
+ }
287
+ }
288
+ onWindowScroll() {
289
+ if (this.isOpen()) {
290
+ this.syncPanelPosition();
291
+ }
292
+ }
293
+ syncPanelPosition() {
294
+ requestAnimationFrame(() => {
295
+ const trigger = this.elementRef.nativeElement.querySelector('.neu-multiselect__trigger');
296
+ if (!trigger)
297
+ return;
298
+ if (window.innerWidth > this._mobileViewportMax) {
299
+ this.resetPanelPosition();
300
+ return;
301
+ }
302
+ const triggerRect = trigger.getBoundingClientRect();
303
+ const viewportWidth = window.innerWidth;
304
+ const viewportHeight = window.innerHeight;
305
+ const width = Math.min(triggerRect.width, viewportWidth - this._viewportMargin * 2);
306
+ const left = Math.min(Math.max(triggerRect.left, this._viewportMargin), viewportWidth - this._viewportMargin - width);
307
+ const top = triggerRect.bottom + 6;
308
+ const maxHeight = Math.max(180, viewportHeight - top - this._viewportMargin);
309
+ this.panelPosition.set({
310
+ position: 'fixed',
311
+ top: `${top}px`,
312
+ left: `${left}px`,
313
+ width: `${width}px`,
314
+ maxHeight: `${maxHeight}px`,
315
+ });
316
+ });
317
+ }
318
+ resetPanelPosition() {
319
+ this.panelPosition.set({
320
+ position: null,
321
+ top: null,
322
+ left: null,
323
+ width: null,
324
+ maxHeight: null,
325
+ });
326
+ }
327
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuMultiselectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
328
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", 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 }, 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: { "document:click": "onDocumentClick($event)", "keydown.escape": "close()", "window:resize": "onWindowResize()", "window:scroll": "onWindowScroll()" } }, providers: [
329
+ {
330
+ provide: NG_VALUE_ACCESSOR,
331
+ useExisting: forwardRef(() => NeuMultiselectComponent),
332
+ multi: true,
333
+ },
334
+ ], queries: [{ propertyName: "itemTpl", first: true, predicate: NeuMultiselectItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
335
+ @if (!floatingLabel() && label()) {
336
+ <label class="neu-multiselect__static-label" [for]="_triggerId" (click)="focusTrigger()">{{
337
+ label()
338
+ }}</label>
339
+ }
340
+ <div
341
+ class="neu-multiselect"
342
+ [class.neu-multiselect--open]="isOpen()"
343
+ [class.neu-multiselect--disabled]="isDisabledFinal()"
344
+ [class.neu-multiselect--error]="hasError()"
345
+ [class.neu-multiselect--has-value]="_values().length > 0"
346
+ [class.neu-multiselect--no-float]="!floatingLabel()"
347
+ [class.neu-multiselect--sm]="size() === 'sm'"
348
+ [class.neu-multiselect--lg]="size() === 'lg'"
349
+ >
350
+ <!-- Trigger -->
351
+ <div
352
+ class="neu-multiselect__trigger"
353
+ [id]="_triggerId"
354
+ [attr.tabindex]="isDisabledFinal() ? '-1' : '0'"
355
+ [attr.role]="'combobox'"
356
+ [attr.aria-haspopup]="'listbox'"
357
+ [attr.aria-expanded]="isOpen() ? 'true' : 'false'"
358
+ [attr.aria-controls]="_panelId"
359
+ [attr.aria-disabled]="isDisabledFinal() ? 'true' : null"
360
+ [attr.aria-invalid]="hasError() ? 'true' : null"
361
+ [attr.aria-describedby]="describedBy()"
362
+ [attr.aria-label]="label() || null"
363
+ (click)="toggle()"
364
+ (keydown.arrowDown)="onTriggerKey($any($event))"
365
+ (keydown.arrowUp)="onTriggerKey($any($event))"
366
+ (keydown.enter)="onTriggerActionKey($any($event))"
367
+ (keydown.space)="onTriggerActionKey($any($event))"
368
+ >
369
+ <!-- Floating label -->
370
+ @if (floatingLabel() && label()) {
371
+ <span class="neu-multiselect__label">{{ label() }}</span>
372
+ }
373
+ <span class="neu-multiselect__chips">
374
+ @if (_values().length === 0) {
375
+ <span class="neu-multiselect__placeholder">{{ placeholder() }}</span>
376
+ } @else if (_chipMode() === 'count') {
377
+ <span class="neu-multiselect__count-badge">{{ _values().length }} seleccionados</span>
378
+ } @else {
379
+ @for (val of _visibleChips(); track val) {
380
+ <span class="neu-multiselect__chip">
381
+ {{ labelFor(val) }}
382
+ <button
383
+ class="neu-multiselect__chip-remove"
384
+ type="button"
385
+ [attr.aria-label]="'Eliminar ' + labelFor(val)"
386
+ (click)="removeValue(val, $event)"
387
+ >
388
+ <svg
389
+ viewBox="0 0 24 24"
390
+ fill="none"
391
+ stroke="currentColor"
392
+ stroke-width="2.5"
393
+ stroke-linecap="round"
394
+ aria-hidden="true"
395
+ >
396
+ <line x1="18" y1="6" x2="6" y2="18" />
397
+ <line x1="6" y1="6" x2="18" y2="18" />
398
+ </svg>
399
+ </button>
400
+ </span>
401
+ }
402
+ @if (_values().length > 3) {
403
+ <span class="neu-multiselect__chip neu-multiselect__chip--overflow"
404
+ >+{{ _values().length - 3 }}</span
405
+ >
406
+ }
407
+ }
408
+ </span>
409
+
410
+ <!-- Clear button -->
411
+ @if (clearable() && _values().length > 0 && !isDisabledFinal()) {
412
+ <button
413
+ class="neu-multiselect__clear"
414
+ type="button"
415
+ [attr.aria-label]="clearAriaLabel()"
416
+ (click)="clearAll($event)"
417
+ >
418
+ <svg
419
+ viewBox="0 0 24 24"
420
+ fill="none"
421
+ stroke="currentColor"
422
+ stroke-width="2.5"
423
+ stroke-linecap="round"
424
+ aria-hidden="true"
425
+ >
426
+ <line x1="18" y1="6" x2="6" y2="18" />
427
+ <line x1="6" y1="6" x2="18" y2="18" />
428
+ </svg>
429
+ </button>
430
+ }
431
+
432
+ <!-- Chevron -->
433
+ <svg
434
+ class="neu-multiselect__chevron"
435
+ viewBox="0 0 24 24"
436
+ fill="none"
437
+ stroke="currentColor"
438
+ stroke-width="2"
439
+ stroke-linecap="round"
440
+ stroke-linejoin="round"
441
+ aria-hidden="true"
442
+ >
443
+ <polyline points="6 9 12 15 18 9" />
444
+ </svg>
445
+ </div>
446
+
447
+ <!-- Panel -->
448
+ @if (isOpen()) {
449
+ <div
450
+ class="neu-multiselect__panel"
451
+ role="listbox"
452
+ [id]="_panelId"
453
+ [attr.aria-multiselectable]="true"
454
+ [attr.aria-label]="label() || null"
455
+ [style.position]="panelPosition().position"
456
+ [style.top]="panelPosition().top"
457
+ [style.left]="panelPosition().left"
458
+ [style.width]="panelPosition().width"
459
+ [style.max-height]="panelPosition().maxHeight"
460
+ >
461
+ <!-- Search -->
462
+ @if (searchable()) {
463
+ <div class="neu-multiselect__search">
464
+ <input
465
+ class="neu-multiselect__search-input"
466
+ type="text"
467
+ [attr.aria-label]="'Search ' + label()"
468
+ [placeholder]="searchPlaceholder()"
469
+ [value]="searchQuery()"
470
+ (input)="searchQuery.set($any($event.target).value)"
471
+ (click)="$event.stopPropagation()"
472
+ />
473
+ </div>
474
+ }
475
+
476
+ <!-- Opciones -->
477
+ <div class="neu-multiselect__options">
478
+ @for (option of filteredOptions(); track option.value) {
479
+ <div
480
+ class="neu-multiselect__option"
481
+ [class.neu-multiselect__option--selected]="isSelected(option.value)"
482
+ [class.neu-multiselect__option--disabled]="option.disabled"
483
+ role="option"
484
+ [id]="'neu-ms-opt-' + option.value"
485
+ [attr.aria-selected]="isSelected(option.value)"
486
+ [attr.aria-disabled]="option.disabled"
487
+ [attr.tabindex]="option.disabled ? null : '-1'"
488
+ (click)="toggleOption(option)"
489
+ (keydown.enter)="toggleOption(option)"
490
+ (keydown.space)="toggleOption(option)"
491
+ (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
492
+ (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
493
+ >
494
+ <!-- Checkbox visual -->
495
+ <span
496
+ class="neu-multiselect__checkbox"
497
+ [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
498
+ >
499
+ <svg
500
+ class="neu-multiselect__checkbox-check"
501
+ viewBox="0 0 12 10"
502
+ fill="none"
503
+ stroke="currentColor"
504
+ stroke-width="2"
505
+ stroke-linecap="round"
506
+ stroke-linejoin="round"
507
+ aria-hidden="true"
508
+ >
509
+ <polyline points="1 5 4.5 9 11 1" />
510
+ </svg>
511
+ </span>
512
+ @if (itemTpl()) {
513
+ <ng-container
514
+ [ngTemplateOutlet]="itemTpl()!.templateRef"
515
+ [ngTemplateOutletContext]="{ $implicit: option }"
516
+ />
517
+ } @else {
518
+ {{ option.label }}
519
+ }
520
+ </div>
521
+ }
522
+
523
+ @if (filteredOptions().length === 0) {
524
+ <div class="neu-multiselect__empty">{{ noResultsMessage() }}</div>
525
+ }
526
+ </div>
527
+
528
+ <!-- Footer: resumen + limpiar + toggle modo -->
529
+ @if (_values().length > 0) {
530
+ <div class="neu-multiselect__footer">
531
+ <span class="neu-multiselect__footer-count"
532
+ >{{ _values().length }} seleccionados</span
533
+ >
534
+ <div class="neu-multiselect__footer-actions">
535
+ <button
536
+ class="neu-multiselect__footer-mode"
537
+ type="button"
538
+ [attr.aria-label]="_chipMode() === 'chips' ? 'Mostrar contador' : 'Mostrar chips'"
539
+ (click)="toggleChipMode($event)"
540
+ >
541
+ {{ _chipMode() === 'chips' ? '#' : '☰' }}
542
+ </button>
543
+ <button
544
+ class="neu-multiselect__footer-clear"
545
+ type="button"
546
+ (click)="clearAll($event)"
547
+ >
548
+ {{ clearAllLabel() }}
549
+ </button>
550
+ </div>
551
+ </div>
552
+ }
553
+ </div>
554
+ }
555
+
556
+ <div class="neu-multiselect__sr-status" aria-live="polite" aria-atomic="true">
557
+ {{ resultsAnnouncement() }}
558
+ </div>
559
+ </div>
560
+
561
+ @if (hasError()) {
562
+ <p class="neu-multiselect__error" [id]="_triggerId + '-error'" role="alert">
563
+ {{ errorMessage() }}
564
+ </p>
565
+ } @else if (hint()) {
566
+ <p class="neu-multiselect__hint" [id]="_triggerId + '-hint'">{{ hint() }}</p>
567
+ }
568
+ `, 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__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:absolute;top:calc(100% + 6px);left:0;right:0;z-index:200;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}@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__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);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);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}.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}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
569
+ }
570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuMultiselectComponent, decorators: [{
571
+ type: Component,
572
+ args: [{ selector: 'neu-multiselect', imports: [NgTemplateOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
573
+ {
574
+ provide: NG_VALUE_ACCESSOR,
575
+ useExisting: forwardRef(() => NeuMultiselectComponent),
576
+ multi: true,
577
+ },
578
+ ], host: {
579
+ '(document:click)': 'onDocumentClick($event)',
580
+ '(keydown.escape)': 'close()',
581
+ '(window:resize)': 'onWindowResize()',
582
+ '(window:scroll)': 'onWindowScroll()',
583
+ }, template: `
584
+ @if (!floatingLabel() && label()) {
585
+ <label class="neu-multiselect__static-label" [for]="_triggerId" (click)="focusTrigger()">{{
586
+ label()
587
+ }}</label>
588
+ }
589
+ <div
590
+ class="neu-multiselect"
591
+ [class.neu-multiselect--open]="isOpen()"
592
+ [class.neu-multiselect--disabled]="isDisabledFinal()"
593
+ [class.neu-multiselect--error]="hasError()"
594
+ [class.neu-multiselect--has-value]="_values().length > 0"
595
+ [class.neu-multiselect--no-float]="!floatingLabel()"
596
+ [class.neu-multiselect--sm]="size() === 'sm'"
597
+ [class.neu-multiselect--lg]="size() === 'lg'"
598
+ >
599
+ <!-- Trigger -->
600
+ <div
601
+ class="neu-multiselect__trigger"
602
+ [id]="_triggerId"
603
+ [attr.tabindex]="isDisabledFinal() ? '-1' : '0'"
604
+ [attr.role]="'combobox'"
605
+ [attr.aria-haspopup]="'listbox'"
606
+ [attr.aria-expanded]="isOpen() ? 'true' : 'false'"
607
+ [attr.aria-controls]="_panelId"
608
+ [attr.aria-disabled]="isDisabledFinal() ? 'true' : null"
609
+ [attr.aria-invalid]="hasError() ? 'true' : null"
610
+ [attr.aria-describedby]="describedBy()"
611
+ [attr.aria-label]="label() || null"
612
+ (click)="toggle()"
613
+ (keydown.arrowDown)="onTriggerKey($any($event))"
614
+ (keydown.arrowUp)="onTriggerKey($any($event))"
615
+ (keydown.enter)="onTriggerActionKey($any($event))"
616
+ (keydown.space)="onTriggerActionKey($any($event))"
617
+ >
618
+ <!-- Floating label -->
619
+ @if (floatingLabel() && label()) {
620
+ <span class="neu-multiselect__label">{{ label() }}</span>
621
+ }
622
+ <span class="neu-multiselect__chips">
623
+ @if (_values().length === 0) {
624
+ <span class="neu-multiselect__placeholder">{{ placeholder() }}</span>
625
+ } @else if (_chipMode() === 'count') {
626
+ <span class="neu-multiselect__count-badge">{{ _values().length }} seleccionados</span>
627
+ } @else {
628
+ @for (val of _visibleChips(); track val) {
629
+ <span class="neu-multiselect__chip">
630
+ {{ labelFor(val) }}
631
+ <button
632
+ class="neu-multiselect__chip-remove"
633
+ type="button"
634
+ [attr.aria-label]="'Eliminar ' + labelFor(val)"
635
+ (click)="removeValue(val, $event)"
636
+ >
637
+ <svg
638
+ viewBox="0 0 24 24"
639
+ fill="none"
640
+ stroke="currentColor"
641
+ stroke-width="2.5"
642
+ stroke-linecap="round"
643
+ aria-hidden="true"
644
+ >
645
+ <line x1="18" y1="6" x2="6" y2="18" />
646
+ <line x1="6" y1="6" x2="18" y2="18" />
647
+ </svg>
648
+ </button>
649
+ </span>
650
+ }
651
+ @if (_values().length > 3) {
652
+ <span class="neu-multiselect__chip neu-multiselect__chip--overflow"
653
+ >+{{ _values().length - 3 }}</span
654
+ >
655
+ }
656
+ }
657
+ </span>
658
+
659
+ <!-- Clear button -->
660
+ @if (clearable() && _values().length > 0 && !isDisabledFinal()) {
661
+ <button
662
+ class="neu-multiselect__clear"
663
+ type="button"
664
+ [attr.aria-label]="clearAriaLabel()"
665
+ (click)="clearAll($event)"
666
+ >
667
+ <svg
668
+ viewBox="0 0 24 24"
669
+ fill="none"
670
+ stroke="currentColor"
671
+ stroke-width="2.5"
672
+ stroke-linecap="round"
673
+ aria-hidden="true"
674
+ >
675
+ <line x1="18" y1="6" x2="6" y2="18" />
676
+ <line x1="6" y1="6" x2="18" y2="18" />
677
+ </svg>
678
+ </button>
679
+ }
680
+
681
+ <!-- Chevron -->
682
+ <svg
683
+ class="neu-multiselect__chevron"
684
+ viewBox="0 0 24 24"
685
+ fill="none"
686
+ stroke="currentColor"
687
+ stroke-width="2"
688
+ stroke-linecap="round"
689
+ stroke-linejoin="round"
690
+ aria-hidden="true"
691
+ >
692
+ <polyline points="6 9 12 15 18 9" />
693
+ </svg>
694
+ </div>
695
+
696
+ <!-- Panel -->
697
+ @if (isOpen()) {
698
+ <div
699
+ class="neu-multiselect__panel"
700
+ role="listbox"
701
+ [id]="_panelId"
702
+ [attr.aria-multiselectable]="true"
703
+ [attr.aria-label]="label() || null"
704
+ [style.position]="panelPosition().position"
705
+ [style.top]="panelPosition().top"
706
+ [style.left]="panelPosition().left"
707
+ [style.width]="panelPosition().width"
708
+ [style.max-height]="panelPosition().maxHeight"
709
+ >
710
+ <!-- Search -->
711
+ @if (searchable()) {
712
+ <div class="neu-multiselect__search">
713
+ <input
714
+ class="neu-multiselect__search-input"
715
+ type="text"
716
+ [attr.aria-label]="'Search ' + label()"
717
+ [placeholder]="searchPlaceholder()"
718
+ [value]="searchQuery()"
719
+ (input)="searchQuery.set($any($event.target).value)"
720
+ (click)="$event.stopPropagation()"
721
+ />
722
+ </div>
723
+ }
724
+
725
+ <!-- Opciones -->
726
+ <div class="neu-multiselect__options">
727
+ @for (option of filteredOptions(); track option.value) {
728
+ <div
729
+ class="neu-multiselect__option"
730
+ [class.neu-multiselect__option--selected]="isSelected(option.value)"
731
+ [class.neu-multiselect__option--disabled]="option.disabled"
732
+ role="option"
733
+ [id]="'neu-ms-opt-' + option.value"
734
+ [attr.aria-selected]="isSelected(option.value)"
735
+ [attr.aria-disabled]="option.disabled"
736
+ [attr.tabindex]="option.disabled ? null : '-1'"
737
+ (click)="toggleOption(option)"
738
+ (keydown.enter)="toggleOption(option)"
739
+ (keydown.space)="toggleOption(option)"
740
+ (keydown.arrowDown)="focusOptionByIndex($any($event), option, 1)"
741
+ (keydown.arrowUp)="focusOptionByIndex($any($event), option, -1)"
742
+ >
743
+ <!-- Checkbox visual -->
744
+ <span
745
+ class="neu-multiselect__checkbox"
746
+ [class.neu-multiselect__checkbox--checked]="isSelected(option.value)"
747
+ >
748
+ <svg
749
+ class="neu-multiselect__checkbox-check"
750
+ viewBox="0 0 12 10"
751
+ fill="none"
752
+ stroke="currentColor"
753
+ stroke-width="2"
754
+ stroke-linecap="round"
755
+ stroke-linejoin="round"
756
+ aria-hidden="true"
757
+ >
758
+ <polyline points="1 5 4.5 9 11 1" />
759
+ </svg>
760
+ </span>
761
+ @if (itemTpl()) {
762
+ <ng-container
763
+ [ngTemplateOutlet]="itemTpl()!.templateRef"
764
+ [ngTemplateOutletContext]="{ $implicit: option }"
765
+ />
766
+ } @else {
767
+ {{ option.label }}
768
+ }
769
+ </div>
770
+ }
771
+
772
+ @if (filteredOptions().length === 0) {
773
+ <div class="neu-multiselect__empty">{{ noResultsMessage() }}</div>
774
+ }
775
+ </div>
776
+
777
+ <!-- Footer: resumen + limpiar + toggle modo -->
778
+ @if (_values().length > 0) {
779
+ <div class="neu-multiselect__footer">
780
+ <span class="neu-multiselect__footer-count"
781
+ >{{ _values().length }} seleccionados</span
782
+ >
783
+ <div class="neu-multiselect__footer-actions">
784
+ <button
785
+ class="neu-multiselect__footer-mode"
786
+ type="button"
787
+ [attr.aria-label]="_chipMode() === 'chips' ? 'Mostrar contador' : 'Mostrar chips'"
788
+ (click)="toggleChipMode($event)"
789
+ >
790
+ {{ _chipMode() === 'chips' ? '#' : '☰' }}
791
+ </button>
792
+ <button
793
+ class="neu-multiselect__footer-clear"
794
+ type="button"
795
+ (click)="clearAll($event)"
796
+ >
797
+ {{ clearAllLabel() }}
798
+ </button>
799
+ </div>
800
+ </div>
801
+ }
802
+ </div>
803
+ }
804
+
805
+ <div class="neu-multiselect__sr-status" aria-live="polite" aria-atomic="true">
806
+ {{ resultsAnnouncement() }}
807
+ </div>
808
+ </div>
809
+
810
+ @if (hasError()) {
811
+ <p class="neu-multiselect__error" [id]="_triggerId + '-error'" role="alert">
812
+ {{ errorMessage() }}
813
+ </p>
814
+ } @else if (hint()) {
815
+ <p class="neu-multiselect__hint" [id]="_triggerId + '-hint'">{{ hint() }}</p>
816
+ }
817
+ `, 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__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:absolute;top:calc(100% + 6px);left:0;right:0;z-index:200;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}@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__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);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);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}.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}\n"] }]
818
+ }], ctorParameters: () => [], propDecorators: { 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 }] }], 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"] }] } });
819
+
820
+ /**
821
+ * Generated bundle index. Do not edit.
822
+ */
823
+
824
+ export { NeuMultiselectComponent, NeuMultiselectItemDirective };
825
+ //# sourceMappingURL=neural-ui-core-multiselect.mjs.map