@raintonic/formaui 0.2.0

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 (240) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +145 -0
  3. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs +806 -0
  4. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs.map +1 -0
  5. package/fesm2022/raintonic-formaui-cdk-form-field.mjs +86 -0
  6. package/fesm2022/raintonic-formaui-cdk-form-field.mjs.map +1 -0
  7. package/fesm2022/raintonic-formaui-cdk-overlay.mjs +1757 -0
  8. package/fesm2022/raintonic-formaui-cdk-overlay.mjs.map +1 -0
  9. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs +287 -0
  10. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs.map +1 -0
  11. package/fesm2022/raintonic-formaui-components-accordion.mjs +217 -0
  12. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -0
  13. package/fesm2022/raintonic-formaui-components-alert.mjs +161 -0
  14. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -0
  15. package/fesm2022/raintonic-formaui-components-autocomplete.mjs +726 -0
  16. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -0
  17. package/fesm2022/raintonic-formaui-components-avatar.mjs +92 -0
  18. package/fesm2022/raintonic-formaui-components-avatar.mjs.map +1 -0
  19. package/fesm2022/raintonic-formaui-components-badge.mjs +107 -0
  20. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -0
  21. package/fesm2022/raintonic-formaui-components-big-menu.mjs +68 -0
  22. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +1 -0
  23. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +55 -0
  24. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -0
  25. package/fesm2022/raintonic-formaui-components-button-group.mjs +103 -0
  26. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -0
  27. package/fesm2022/raintonic-formaui-components-button.mjs +241 -0
  28. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -0
  29. package/fesm2022/raintonic-formaui-components-card.mjs +270 -0
  30. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -0
  31. package/fesm2022/raintonic-formaui-components-checkbox.mjs +295 -0
  32. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -0
  33. package/fesm2022/raintonic-formaui-components-data-table.mjs +631 -0
  34. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -0
  35. package/fesm2022/raintonic-formaui-components-date-picker.mjs +1331 -0
  36. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -0
  37. package/fesm2022/raintonic-formaui-components-divider.mjs +41 -0
  38. package/fesm2022/raintonic-formaui-components-divider.mjs.map +1 -0
  39. package/fesm2022/raintonic-formaui-components-drawer.mjs +190 -0
  40. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -0
  41. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs +266 -0
  42. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs.map +1 -0
  43. package/fesm2022/raintonic-formaui-components-empty-state.mjs +33 -0
  44. package/fesm2022/raintonic-formaui-components-empty-state.mjs.map +1 -0
  45. package/fesm2022/raintonic-formaui-components-file-upload.mjs +246 -0
  46. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -0
  47. package/fesm2022/raintonic-formaui-components-form-field.mjs +482 -0
  48. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -0
  49. package/fesm2022/raintonic-formaui-components-icon.mjs +117 -0
  50. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -0
  51. package/fesm2022/raintonic-formaui-components-input.mjs +327 -0
  52. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -0
  53. package/fesm2022/raintonic-formaui-components-list.mjs +149 -0
  54. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -0
  55. package/fesm2022/raintonic-formaui-components-menu.mjs +896 -0
  56. package/fesm2022/raintonic-formaui-components-menu.mjs.map +1 -0
  57. package/fesm2022/raintonic-formaui-components-number-input.mjs +345 -0
  58. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -0
  59. package/fesm2022/raintonic-formaui-components-paginator.mjs +139 -0
  60. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -0
  61. package/fesm2022/raintonic-formaui-components-password-input.mjs +306 -0
  62. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -0
  63. package/fesm2022/raintonic-formaui-components-popover.mjs +451 -0
  64. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -0
  65. package/fesm2022/raintonic-formaui-components-progressbar.mjs +148 -0
  66. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -0
  67. package/fesm2022/raintonic-formaui-components-radio.mjs +260 -0
  68. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -0
  69. package/fesm2022/raintonic-formaui-components-select.mjs +1011 -0
  70. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -0
  71. package/fesm2022/raintonic-formaui-components-side-panel.mjs +150 -0
  72. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -0
  73. package/fesm2022/raintonic-formaui-components-sidebar.mjs +257 -0
  74. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +1 -0
  75. package/fesm2022/raintonic-formaui-components-skeleton.mjs +50 -0
  76. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -0
  77. package/fesm2022/raintonic-formaui-components-slider.mjs +347 -0
  78. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -0
  79. package/fesm2022/raintonic-formaui-components-spinner.mjs +63 -0
  80. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -0
  81. package/fesm2022/raintonic-formaui-components-stepper.mjs +317 -0
  82. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -0
  83. package/fesm2022/raintonic-formaui-components-tab.mjs +197 -0
  84. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -0
  85. package/fesm2022/raintonic-formaui-components-tag.mjs +78 -0
  86. package/fesm2022/raintonic-formaui-components-tag.mjs.map +1 -0
  87. package/fesm2022/raintonic-formaui-components-time-picker.mjs +644 -0
  88. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -0
  89. package/fesm2022/raintonic-formaui-components-toggle.mjs +171 -0
  90. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -0
  91. package/fesm2022/raintonic-formaui-components-toolbar.mjs +140 -0
  92. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -0
  93. package/fesm2022/raintonic-formaui-components-tooltip.mjs +555 -0
  94. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -0
  95. package/fesm2022/raintonic-formaui-components-tree-select.mjs +314 -0
  96. package/fesm2022/raintonic-formaui-components-tree-select.mjs.map +1 -0
  97. package/fesm2022/raintonic-formaui-components-tree-table.mjs +103 -0
  98. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -0
  99. package/fesm2022/raintonic-formaui-components-tree.mjs +430 -0
  100. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -0
  101. package/fesm2022/raintonic-formaui-core.mjs +62 -0
  102. package/fesm2022/raintonic-formaui-core.mjs.map +1 -0
  103. package/fesm2022/raintonic-formaui-services-dialog.mjs +798 -0
  104. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -0
  105. package/fesm2022/raintonic-formaui-services-notification.mjs +391 -0
  106. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -0
  107. package/fesm2022/raintonic-formaui-services-theme.mjs +248 -0
  108. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -0
  109. package/fesm2022/raintonic-formaui-test-utils.mjs +66 -0
  110. package/fesm2022/raintonic-formaui-test-utils.mjs.map +1 -0
  111. package/fesm2022/raintonic-formaui.mjs +15 -0
  112. package/fesm2022/raintonic-formaui.mjs.map +1 -0
  113. package/llms-full.txt +1627 -0
  114. package/llms.txt +60 -0
  115. package/package.json +251 -0
  116. package/styles/_fonts-entry.scss +3 -0
  117. package/styles/fonts/dm-mono-400-latin.woff2 +0 -0
  118. package/styles/fonts/inter-tight-latin-italic.woff2 +0 -0
  119. package/styles/fonts/inter-tight-latin.woff2 +0 -0
  120. package/styles/index.scss +127 -0
  121. package/styles/partials/_constants.scss +29 -0
  122. package/styles/partials/_fonts.scss +36 -0
  123. package/styles/partials/_grid.scss +171 -0
  124. package/styles/partials/_mixins.scss +145 -0
  125. package/styles/partials/_motion.scss +252 -0
  126. package/styles/partials/_theme.scss +275 -0
  127. package/styles/partials/_typography.scss +112 -0
  128. package/styles/partials/_utilities.scss +480 -0
  129. package/styles/partials/themes/_dark.scss +254 -0
  130. package/styles/partials/themes/_light.scss +254 -0
  131. package/types/raintonic-formaui-cdk-drag-drop.d.ts +196 -0
  132. package/types/raintonic-formaui-cdk-drag-drop.d.ts.map +1 -0
  133. package/types/raintonic-formaui-cdk-form-field.d.ts +62 -0
  134. package/types/raintonic-formaui-cdk-form-field.d.ts.map +1 -0
  135. package/types/raintonic-formaui-cdk-overlay.d.ts +843 -0
  136. package/types/raintonic-formaui-cdk-overlay.d.ts.map +1 -0
  137. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts +112 -0
  138. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts.map +1 -0
  139. package/types/raintonic-formaui-components-accordion.d.ts +124 -0
  140. package/types/raintonic-formaui-components-accordion.d.ts.map +1 -0
  141. package/types/raintonic-formaui-components-alert.d.ts +143 -0
  142. package/types/raintonic-formaui-components-alert.d.ts.map +1 -0
  143. package/types/raintonic-formaui-components-autocomplete.d.ts +193 -0
  144. package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -0
  145. package/types/raintonic-formaui-components-avatar.d.ts +52 -0
  146. package/types/raintonic-formaui-components-avatar.d.ts.map +1 -0
  147. package/types/raintonic-formaui-components-badge.d.ts +47 -0
  148. package/types/raintonic-formaui-components-badge.d.ts.map +1 -0
  149. package/types/raintonic-formaui-components-big-menu.d.ts +62 -0
  150. package/types/raintonic-formaui-components-big-menu.d.ts.map +1 -0
  151. package/types/raintonic-formaui-components-breadcrumb.d.ts +26 -0
  152. package/types/raintonic-formaui-components-breadcrumb.d.ts.map +1 -0
  153. package/types/raintonic-formaui-components-button-group.d.ts +61 -0
  154. package/types/raintonic-formaui-components-button-group.d.ts.map +1 -0
  155. package/types/raintonic-formaui-components-button.d.ts +116 -0
  156. package/types/raintonic-formaui-components-button.d.ts.map +1 -0
  157. package/types/raintonic-formaui-components-card.d.ts +191 -0
  158. package/types/raintonic-formaui-components-card.d.ts.map +1 -0
  159. package/types/raintonic-formaui-components-checkbox.d.ts +132 -0
  160. package/types/raintonic-formaui-components-checkbox.d.ts.map +1 -0
  161. package/types/raintonic-formaui-components-data-table.d.ts +368 -0
  162. package/types/raintonic-formaui-components-data-table.d.ts.map +1 -0
  163. package/types/raintonic-formaui-components-date-picker.d.ts +341 -0
  164. package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -0
  165. package/types/raintonic-formaui-components-divider.d.ts +21 -0
  166. package/types/raintonic-formaui-components-divider.d.ts.map +1 -0
  167. package/types/raintonic-formaui-components-drawer.d.ts +48 -0
  168. package/types/raintonic-formaui-components-drawer.d.ts.map +1 -0
  169. package/types/raintonic-formaui-components-dynamic-form.d.ts +412 -0
  170. package/types/raintonic-formaui-components-dynamic-form.d.ts.map +1 -0
  171. package/types/raintonic-formaui-components-empty-state.d.ts +14 -0
  172. package/types/raintonic-formaui-components-empty-state.d.ts.map +1 -0
  173. package/types/raintonic-formaui-components-file-upload.d.ts +77 -0
  174. package/types/raintonic-formaui-components-file-upload.d.ts.map +1 -0
  175. package/types/raintonic-formaui-components-form-field.d.ts +271 -0
  176. package/types/raintonic-formaui-components-form-field.d.ts.map +1 -0
  177. package/types/raintonic-formaui-components-icon.d.ts +61 -0
  178. package/types/raintonic-formaui-components-icon.d.ts.map +1 -0
  179. package/types/raintonic-formaui-components-input.d.ts +149 -0
  180. package/types/raintonic-formaui-components-input.d.ts.map +1 -0
  181. package/types/raintonic-formaui-components-list.d.ts +48 -0
  182. package/types/raintonic-formaui-components-list.d.ts.map +1 -0
  183. package/types/raintonic-formaui-components-menu.d.ts +403 -0
  184. package/types/raintonic-formaui-components-menu.d.ts.map +1 -0
  185. package/types/raintonic-formaui-components-number-input.d.ts +127 -0
  186. package/types/raintonic-formaui-components-number-input.d.ts.map +1 -0
  187. package/types/raintonic-formaui-components-paginator.d.ts +37 -0
  188. package/types/raintonic-formaui-components-paginator.d.ts.map +1 -0
  189. package/types/raintonic-formaui-components-password-input.d.ts +111 -0
  190. package/types/raintonic-formaui-components-password-input.d.ts.map +1 -0
  191. package/types/raintonic-formaui-components-popover.d.ts +131 -0
  192. package/types/raintonic-formaui-components-popover.d.ts.map +1 -0
  193. package/types/raintonic-formaui-components-progressbar.d.ts +111 -0
  194. package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -0
  195. package/types/raintonic-formaui-components-radio.d.ts +95 -0
  196. package/types/raintonic-formaui-components-radio.d.ts.map +1 -0
  197. package/types/raintonic-formaui-components-select.d.ts +307 -0
  198. package/types/raintonic-formaui-components-select.d.ts.map +1 -0
  199. package/types/raintonic-formaui-components-side-panel.d.ts +51 -0
  200. package/types/raintonic-formaui-components-side-panel.d.ts.map +1 -0
  201. package/types/raintonic-formaui-components-sidebar.d.ts +174 -0
  202. package/types/raintonic-formaui-components-sidebar.d.ts.map +1 -0
  203. package/types/raintonic-formaui-components-skeleton.d.ts +20 -0
  204. package/types/raintonic-formaui-components-skeleton.d.ts.map +1 -0
  205. package/types/raintonic-formaui-components-slider.d.ts +108 -0
  206. package/types/raintonic-formaui-components-slider.d.ts.map +1 -0
  207. package/types/raintonic-formaui-components-spinner.d.ts +42 -0
  208. package/types/raintonic-formaui-components-spinner.d.ts.map +1 -0
  209. package/types/raintonic-formaui-components-stepper.d.ts +126 -0
  210. package/types/raintonic-formaui-components-stepper.d.ts.map +1 -0
  211. package/types/raintonic-formaui-components-tab.d.ts +96 -0
  212. package/types/raintonic-formaui-components-tab.d.ts.map +1 -0
  213. package/types/raintonic-formaui-components-tag.d.ts +34 -0
  214. package/types/raintonic-formaui-components-tag.d.ts.map +1 -0
  215. package/types/raintonic-formaui-components-time-picker.d.ts +172 -0
  216. package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -0
  217. package/types/raintonic-formaui-components-toggle.d.ts +70 -0
  218. package/types/raintonic-formaui-components-toggle.d.ts.map +1 -0
  219. package/types/raintonic-formaui-components-toolbar.d.ts +128 -0
  220. package/types/raintonic-formaui-components-toolbar.d.ts.map +1 -0
  221. package/types/raintonic-formaui-components-tooltip.d.ts +268 -0
  222. package/types/raintonic-formaui-components-tooltip.d.ts.map +1 -0
  223. package/types/raintonic-formaui-components-tree-select.d.ts +80 -0
  224. package/types/raintonic-formaui-components-tree-select.d.ts.map +1 -0
  225. package/types/raintonic-formaui-components-tree-table.d.ts +90 -0
  226. package/types/raintonic-formaui-components-tree-table.d.ts.map +1 -0
  227. package/types/raintonic-formaui-components-tree.d.ts +104 -0
  228. package/types/raintonic-formaui-components-tree.d.ts.map +1 -0
  229. package/types/raintonic-formaui-core.d.ts +115 -0
  230. package/types/raintonic-formaui-core.d.ts.map +1 -0
  231. package/types/raintonic-formaui-services-dialog.d.ts +451 -0
  232. package/types/raintonic-formaui-services-dialog.d.ts.map +1 -0
  233. package/types/raintonic-formaui-services-notification.d.ts +221 -0
  234. package/types/raintonic-formaui-services-notification.d.ts.map +1 -0
  235. package/types/raintonic-formaui-services-theme.d.ts +126 -0
  236. package/types/raintonic-formaui-services-theme.d.ts.map +1 -0
  237. package/types/raintonic-formaui-test-utils.d.ts +24 -0
  238. package/types/raintonic-formaui-test-utils.d.ts.map +1 -0
  239. package/types/raintonic-formaui.d.ts +4 -0
  240. package/types/raintonic-formaui.d.ts.map +1 -0
@@ -0,0 +1,726 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, input, output, signal, inject, computed, contentChildren, ElementRef, NgZone, effect, ViewChild, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { NgForm, FormGroupDirective, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
4
+ import { DOCUMENT } from '@angular/common';
5
+ import { Subject, Subscription, fromEvent } from 'rxjs';
6
+ import { filter } from 'rxjs/operators';
7
+ import { injectNgControl, updateErrorState, syncRequiredState, syncNgControlDisabled } from '@raintonic/formaui/cdk/form-field';
8
+ import { FuiIconComponent } from '@raintonic/formaui/components/icon';
9
+ import { FuiButtonDirective } from '@raintonic/formaui/components/button';
10
+ import { DefaultErrorStateMatcher, FUI_FORM_FIELD_CONTROL } from '@raintonic/formaui/core';
11
+ import { FuiOptionComponent } from '@raintonic/formaui/components/select';
12
+ import { FuiOverlayService } from '@raintonic/formaui/cdk/overlay';
13
+
14
+ /**
15
+ * Injection token used to provide the parent autocomplete to options
16
+ */
17
+ const FUI_AUTOCOMPLETE = new InjectionToken('FUI_AUTOCOMPLETE');
18
+ /**
19
+ * # fui-autocomplete Component
20
+ *
21
+ * An autocomplete component designed to work seamlessly with fui-form-field.
22
+ * Similar to Angular Material's mat-autocomplete integration with mat-form-field.
23
+ * Provides full Reactive Forms support with validation, filtering, and optional
24
+ * add/refresh actions.
25
+ *
26
+ * ## Features
27
+ * - Works inside fui-form-field like mat-autocomplete
28
+ * - Full Reactive Forms integration (ControlValueAccessor)
29
+ * - Options via projected content (fui-option)
30
+ * - Built-in search/filter input in the panel
31
+ * - Optional "Add New" and "Refresh" action buttons
32
+ * - Disabled and readonly states
33
+ * - Full accessibility support
34
+ * - Full keyboard navigation (Arrow keys, Enter, Escape, Home, End, PageUp, PageDown)
35
+ * - Uses overlay service for proper positioning
36
+ *
37
+ * ## Usage
38
+ *
39
+ * ### Basic Autocomplete with Form Field
40
+ * ```html
41
+ * <fui-form-field>
42
+ * <label>Country</label>
43
+ * <fui-autocomplete placeholder="Search countries...">
44
+ * <fui-option value="us">United States</fui-option>
45
+ * <fui-option value="ca">Canada</fui-option>
46
+ * <fui-option value="mx">Mexico</fui-option>
47
+ * </fui-autocomplete>
48
+ * </fui-form-field>
49
+ * ```
50
+ *
51
+ * ### With Reactive Forms and Validation
52
+ * ```html
53
+ * <form [formGroup]="form">
54
+ * <fui-form-field>
55
+ * <label>Country</label>
56
+ * <fui-autocomplete formControlName="country" placeholder="Select a country">
57
+ * <fui-option value="us">United States</fui-option>
58
+ * <fui-option value="ca">Canada</fui-option>
59
+ * </fui-autocomplete>
60
+ * <fui-error *ngIf="form.get('country')?.hasError('required')">
61
+ * Country is required
62
+ * </fui-error>
63
+ * </fui-form-field>
64
+ * </form>
65
+ * ```
66
+ *
67
+ * ### With Add/Refresh Buttons
68
+ * ```html
69
+ * <fui-form-field>
70
+ * <label>Category</label>
71
+ * <fui-autocomplete
72
+ * placeholder="Search categories..."
73
+ * [showAddButton]="true"
74
+ * [showRefreshButton]="true"
75
+ * (addNew)="openAddCategoryDialog()"
76
+ * (refresh)="refreshCategories()">
77
+ * @for (category of categories; track category.id) {
78
+ * <fui-option [value]="category.id">{{ category.name }}</fui-option>
79
+ * }
80
+ * </fui-autocomplete>
81
+ * </fui-form-field>
82
+ * ```
83
+ */
84
+ class FuiAutocompleteComponent {
85
+ // Static properties
86
+ static nextId = 0;
87
+ controlType = 'fui-autocomplete';
88
+ // Inputs using signal-based API
89
+ placeholderInput = input('', { ...(ngDevMode ? { debugName: "placeholderInput" } : /* istanbul ignore next */ {}), alias: 'placeholder' });
90
+ disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled' });
91
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
92
+ showAddButton = input(false, ...(ngDevMode ? [{ debugName: "showAddButton" }] : /* istanbul ignore next */ []));
93
+ showRefreshButton = input(false, ...(ngDevMode ? [{ debugName: "showRefreshButton" }] : /* istanbul ignore next */ []));
94
+ addButtonLabel = input('Add New', ...(ngDevMode ? [{ debugName: "addButtonLabel" }] : /* istanbul ignore next */ []));
95
+ refreshButtonLabel = input('Refresh', ...(ngDevMode ? [{ debugName: "refreshButtonLabel" }] : /* istanbul ignore next */ []));
96
+ noOptionsText = input('No options found', ...(ngDevMode ? [{ debugName: "noOptionsText" }] : /* istanbul ignore next */ []));
97
+ searchPlaceholder = input('Search...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
98
+ errorStateMatcher = input(null, ...(ngDevMode ? [{ debugName: "errorStateMatcher" }] : /* istanbul ignore next */ []));
99
+ /**
100
+ * Whether to compare option values using object identity or deep equality
101
+ */
102
+ compareWith = input((o1, o2) => o1 === o2, ...(ngDevMode ? [{ debugName: "compareWith" }] : /* istanbul ignore next */ []));
103
+ // Outputs
104
+ valueChange = output();
105
+ selectionChange = output();
106
+ openedChange = output();
107
+ addNew = output();
108
+ refresh = output();
109
+ searchChange = output();
110
+ // Internal state signals
111
+ _value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
112
+ _focused = signal(false, ...(ngDevMode ? [{ debugName: "_focused" }] : /* istanbul ignore next */ []));
113
+ _disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
114
+ _readOnly = signal(false, ...(ngDevMode ? [{ debugName: "_readOnly" }] : /* istanbul ignore next */ []));
115
+ // FuiFormFieldControl implementation
116
+ stateChanges = new Subject();
117
+ _uid = `fui-autocomplete-${FuiAutocompleteComponent.nextId++}`;
118
+ _ariaDescribedby = null;
119
+ // Error state
120
+ _errorState = signal(false, ...(ngDevMode ? [{ debugName: "_errorState" }] : /* istanbul ignore next */ []));
121
+ errorState = this._errorState;
122
+ // Form control references
123
+ _parentForm = inject(NgForm, { optional: true });
124
+ _parentFormGroup = inject(FormGroupDirective, { optional: true });
125
+ _defaultErrorStateMatcher = inject(DefaultErrorStateMatcher);
126
+ _ngControlRef = injectNgControl();
127
+ get ngControl() {
128
+ return this._ngControlRef.ngControl;
129
+ }
130
+ // Interface implementation
131
+ placeholder = computed(() => this.placeholderInput(), ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
132
+ _required = signal(false, ...(ngDevMode ? [{ debugName: "_required" }] : /* istanbul ignore next */ []));
133
+ required = this._required;
134
+ value = this._value;
135
+ focused = this._focused;
136
+ _ngControlDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_ngControlDisabled" }] : /* istanbul ignore next */ []));
137
+ disabled = computed(() => this._disabled() || this.disabledInput() || this._ngControlDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
138
+ empty = computed(() => {
139
+ const val = this._value();
140
+ return val === null || val === undefined;
141
+ }, ...(ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []));
142
+ id = this._uid;
143
+ // ViewChild for trigger and panel
144
+ trigger;
145
+ panel;
146
+ searchInput;
147
+ // ContentChildren for options
148
+ options = contentChildren(FuiOptionComponent, { ...(ngDevMode ? { debugName: "options" } : /* istanbul ignore next */ {}), descendants: true });
149
+ // Panel open/close state
150
+ panelOpen = signal(false, ...(ngDevMode ? [{ debugName: "panelOpen" }] : /* istanbul ignore next */ []));
151
+ // Search term for filtering
152
+ searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
153
+ // Active option index for keyboard navigation
154
+ activeOptionIndex = signal(-1, ...(ngDevMode ? [{ debugName: "activeOptionIndex" }] : /* istanbul ignore next */ []));
155
+ // Live announcement for screen readers
156
+ _liveAnnouncement = signal('', ...(ngDevMode ? [{ debugName: "_liveAnnouncement" }] : /* istanbul ignore next */ []));
157
+ _announce(message) {
158
+ this._liveAnnouncement.set('');
159
+ setTimeout(() => {
160
+ this._liveAnnouncement.set(message);
161
+ }, 50);
162
+ }
163
+ // Overlay reference
164
+ _overlayRef = null;
165
+ _overlaySubscriptions = new Subscription();
166
+ // Services
167
+ _overlayService = inject(FuiOverlayService);
168
+ _elementRef = inject(ElementRef);
169
+ _document = inject(DOCUMENT);
170
+ _ngZone = inject(NgZone);
171
+ _outsideClickSub;
172
+ // ControlValueAccessor callbacks
173
+ _onChange = () => {
174
+ // Intentionally empty: will be replaced by Angular forms
175
+ };
176
+ _onTouched = () => {
177
+ // Intentionally empty: will be replaced by Angular forms
178
+ };
179
+ // Computed properties
180
+ displayValue = computed(() => {
181
+ const currentValue = this.value();
182
+ const opts = this.options();
183
+ if (currentValue === null || currentValue === undefined) {
184
+ return '';
185
+ }
186
+ const selectedOption = opts.find((opt) => this.compareWith()(opt.value(), currentValue));
187
+ return selectedOption ? selectedOption.getLabel() : String(currentValue);
188
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
189
+ // Filtered options based on search term
190
+ filteredOptions = computed(() => {
191
+ const opts = this.options();
192
+ const term = this.searchTerm().toLowerCase().trim();
193
+ if (!term) {
194
+ return opts.filter((opt) => !opt.disabled());
195
+ }
196
+ return opts.filter((opt) => !opt.disabled() && opt.getLabel().toLowerCase().includes(term));
197
+ }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
198
+ hasFilteredOptions = computed(() => {
199
+ return this.filteredOptions().length > 0;
200
+ }, ...(ngDevMode ? [{ debugName: "hasFilteredOptions" }] : /* istanbul ignore next */ []));
201
+ constructor() {
202
+ // Set valueAccessor after NgControl is resolved
203
+ void Promise.resolve().then(() => {
204
+ if (this._ngControlRef.ngControl) {
205
+ this._ngControlRef.ngControl.valueAccessor = this;
206
+ }
207
+ });
208
+ // Effect to emit state changes
209
+ effect(() => {
210
+ // Track all reactive inputs and internal signals
211
+ this.placeholderInput();
212
+ this.readonly();
213
+ this.disabledInput();
214
+ this.errorStateMatcher();
215
+ this._focused();
216
+ this._disabled();
217
+ this._value();
218
+ this._ngControlDisabled();
219
+ this._required();
220
+ this._errorState();
221
+ // Emit state change
222
+ this.stateChanges.next();
223
+ });
224
+ // Effect to update options selected state when value changes
225
+ effect(() => {
226
+ const currentValue = this._value();
227
+ const opts = this.options();
228
+ const compareFn = this.compareWith();
229
+ opts.forEach((option) => {
230
+ const optValue = option.value();
231
+ const isSelected = compareFn(currentValue, optValue);
232
+ if (isSelected) {
233
+ option.select();
234
+ }
235
+ else {
236
+ option.deselect();
237
+ }
238
+ });
239
+ // Notify form-field that state may have changed
240
+ this.stateChanges.next();
241
+ });
242
+ }
243
+ ngDoCheck() {
244
+ if (this.ngControl) {
245
+ updateErrorState(this.ngControl, this._errorState, this.errorStateMatcher(), this._defaultErrorStateMatcher, this._parentForm, this._parentFormGroup, this.stateChanges);
246
+ syncRequiredState(this.ngControl, this._required, this.stateChanges);
247
+ syncNgControlDisabled(this.ngControl, this._ngControlDisabled, this.stateChanges);
248
+ }
249
+ }
250
+ ngOnDestroy() {
251
+ this.stateChanges.complete();
252
+ this._outsideClickSub?.unsubscribe();
253
+ this._disposeOverlay();
254
+ }
255
+ // ControlValueAccessor implementation
256
+ writeValue(value) {
257
+ this._value.set(value ?? null);
258
+ this.stateChanges.next();
259
+ }
260
+ registerOnChange(fn) {
261
+ this._onChange = fn;
262
+ }
263
+ registerOnTouched(fn) {
264
+ this._onTouched = fn;
265
+ }
266
+ setDisabledState(isDisabled) {
267
+ this._disabled.set(isDisabled);
268
+ this.stateChanges.next();
269
+ }
270
+ // FuiFormFieldControl implementation
271
+ onContainerClick(_event) {
272
+ if (!this.disabled()) {
273
+ this.toggle();
274
+ }
275
+ }
276
+ setDescribedByIds(ids) {
277
+ this._ariaDescribedby = ids.length ? ids.join(' ') : null;
278
+ }
279
+ setReadOnly(readOnly) {
280
+ this._readOnly.set(readOnly);
281
+ }
282
+ // Public methods
283
+ clear(event) {
284
+ event.stopPropagation();
285
+ this._value.set(null);
286
+ this._onChange(null);
287
+ this.valueChange.emit(null);
288
+ this.selectionChange.emit({ source: this, value: null });
289
+ this.stateChanges.next();
290
+ }
291
+ focus() {
292
+ this.trigger?.nativeElement.focus();
293
+ }
294
+ blur() {
295
+ this.trigger?.nativeElement.blur();
296
+ }
297
+ // Toggle panel open/close
298
+ toggle() {
299
+ if (this.disabled())
300
+ return;
301
+ if (this.panelOpen()) {
302
+ this.close();
303
+ }
304
+ else {
305
+ this.open();
306
+ }
307
+ }
308
+ // Open the dropdown panel
309
+ open() {
310
+ if (this.disabled() || this.readonly() || this.panelOpen())
311
+ return;
312
+ this.panelOpen.set(true);
313
+ this._focused.set(true);
314
+ this.searchTerm.set('');
315
+ this.openedChange.emit(true);
316
+ // Set active option to currently selected or first option
317
+ this._setInitialActiveOption();
318
+ // Create overlay after the view updates
319
+ setTimeout(() => {
320
+ this._createOverlay();
321
+ this._scrollToActiveOption();
322
+ this._listenForOutsideClicks();
323
+ // Focus the search input
324
+ this.searchInput?.nativeElement.focus();
325
+ }, 0);
326
+ }
327
+ // Close the dropdown panel
328
+ close() {
329
+ if (!this.panelOpen())
330
+ return;
331
+ this._outsideClickSub?.unsubscribe();
332
+ this.panelOpen.set(false);
333
+ this._focused.set(false);
334
+ this.activeOptionIndex.set(-1);
335
+ this.searchTerm.set('');
336
+ this._disposeOverlay();
337
+ this.openedChange.emit(false);
338
+ this._onTouched();
339
+ // Clear active state on all options
340
+ this.options().forEach((opt) => {
341
+ opt.setInactive();
342
+ });
343
+ // Return focus to trigger
344
+ setTimeout(() => {
345
+ this.trigger?.nativeElement.focus();
346
+ }, 0);
347
+ }
348
+ // Handle option selection (called by FuiOptionComponent or internally)
349
+ _onOptionSelected(option) {
350
+ const newValue = option.value();
351
+ // Deselect previous option
352
+ const opts = this.options();
353
+ opts.forEach((opt) => {
354
+ if (opt !== option) {
355
+ opt.deselect();
356
+ }
357
+ });
358
+ option.select();
359
+ this._value.set(newValue);
360
+ this._onChange(newValue);
361
+ this.valueChange.emit(newValue);
362
+ this.selectionChange.emit({ source: this, value: newValue });
363
+ this._announce(`${option.getLabel()} selected`);
364
+ this.close();
365
+ this.stateChanges.next();
366
+ }
367
+ // Handle search input
368
+ onSearchInput(event) {
369
+ const target = event.target;
370
+ const term = target.value;
371
+ this.searchTerm.set(term);
372
+ this.searchChange.emit(term);
373
+ // Reset active index when search changes
374
+ const filtered = this.filteredOptions();
375
+ if (filtered.length > 0) {
376
+ this._setActiveOptionIndex(0);
377
+ }
378
+ else {
379
+ this.activeOptionIndex.set(-1);
380
+ }
381
+ }
382
+ // Handle add new action
383
+ onAddNew() {
384
+ this.close();
385
+ this.addNew.emit();
386
+ }
387
+ // Handle refresh action
388
+ onRefresh() {
389
+ this.refresh.emit();
390
+ // Keep panel open and clear search
391
+ this.searchTerm.set('');
392
+ }
393
+ // Get display value for trigger
394
+ _getDisplayValue() {
395
+ return this.displayValue();
396
+ }
397
+ // Handle keyboard navigation
398
+ _handleKeydown(event) {
399
+ if (this.disabled())
400
+ return;
401
+ const isOpen = this.panelOpen();
402
+ if (!isOpen) {
403
+ this._handleClosedKeydown(event);
404
+ }
405
+ else {
406
+ this._handleOpenKeydown(event);
407
+ }
408
+ }
409
+ // Handle keydown when panel is closed
410
+ _handleClosedKeydown(event) {
411
+ const key = event.key;
412
+ switch (key) {
413
+ case 'Enter':
414
+ case ' ':
415
+ case 'ArrowDown':
416
+ case 'ArrowUp':
417
+ event.preventDefault();
418
+ this.open();
419
+ break;
420
+ }
421
+ }
422
+ // Handle keydown when panel is open (for search input)
423
+ _handlePanelKeydown(event) {
424
+ if (this.disabled())
425
+ return;
426
+ const key = event.key;
427
+ const opts = this.filteredOptions();
428
+ const activeIndex = this.activeOptionIndex();
429
+ switch (key) {
430
+ case 'ArrowDown':
431
+ event.preventDefault();
432
+ this._setNextActiveOption(1);
433
+ break;
434
+ case 'ArrowUp':
435
+ event.preventDefault();
436
+ this._setNextActiveOption(-1);
437
+ break;
438
+ case 'Home':
439
+ event.preventDefault();
440
+ if (opts.length > 0) {
441
+ this._setActiveOptionIndex(0);
442
+ }
443
+ break;
444
+ case 'End':
445
+ event.preventDefault();
446
+ if (opts.length > 0) {
447
+ this._setActiveOptionIndex(opts.length - 1);
448
+ }
449
+ break;
450
+ case 'PageDown':
451
+ event.preventDefault();
452
+ if (opts.length > 0) {
453
+ const pageSize = Math.min(10, opts.length);
454
+ const newIndex = Math.min(activeIndex + pageSize, opts.length - 1);
455
+ this._setActiveOptionIndex(newIndex);
456
+ }
457
+ break;
458
+ case 'PageUp':
459
+ event.preventDefault();
460
+ if (opts.length > 0) {
461
+ const pageSize = Math.min(10, opts.length);
462
+ const newIndex = Math.max(activeIndex - pageSize, 0);
463
+ this._setActiveOptionIndex(newIndex);
464
+ }
465
+ break;
466
+ case 'Enter':
467
+ event.preventDefault();
468
+ if (activeIndex >= 0 && activeIndex < opts.length) {
469
+ this._onOptionSelected(opts[activeIndex]);
470
+ }
471
+ break;
472
+ case 'Escape':
473
+ event.preventDefault();
474
+ this.close();
475
+ break;
476
+ case 'Tab':
477
+ // Allow tab to close and move to next element
478
+ this.close();
479
+ break;
480
+ }
481
+ }
482
+ // Handle keydown when panel is open (for trigger)
483
+ _handleOpenKeydown(event) {
484
+ // Delegate to panel keydown handler
485
+ this._handlePanelKeydown(event);
486
+ }
487
+ // Set the next active option based on delta
488
+ _setNextActiveOption(delta) {
489
+ const opts = this.filteredOptions();
490
+ if (opts.length === 0)
491
+ return;
492
+ let currentIndex = this.activeOptionIndex();
493
+ if (currentIndex < 0) {
494
+ currentIndex = delta > 0 ? -1 : opts.length;
495
+ }
496
+ let newIndex = currentIndex + delta;
497
+ // Wrap around
498
+ if (newIndex < 0) {
499
+ newIndex = opts.length - 1;
500
+ }
501
+ else if (newIndex >= opts.length) {
502
+ newIndex = 0;
503
+ }
504
+ this._setActiveOptionIndex(newIndex);
505
+ }
506
+ // Set the active option index
507
+ _setActiveOptionIndex(index) {
508
+ const opts = this.filteredOptions();
509
+ if (index < 0 || index >= opts.length)
510
+ return;
511
+ // Update active state on options
512
+ const allOpts = this.options();
513
+ allOpts.forEach((opt) => {
514
+ opt.setInactive();
515
+ });
516
+ const activeOption = opts[index];
517
+ activeOption.setActive();
518
+ this.activeOptionIndex.set(index);
519
+ this._scrollToActiveOption();
520
+ this._announce(`${activeOption.getLabel()}, ${index + 1} of ${opts.length}`);
521
+ }
522
+ // Set initial active option when opening
523
+ _setInitialActiveOption() {
524
+ const opts = this.filteredOptions();
525
+ if (opts.length === 0) {
526
+ this.activeOptionIndex.set(-1);
527
+ return;
528
+ }
529
+ const currentValue = this._value();
530
+ const compareFn = this.compareWith();
531
+ // Find the selected option
532
+ let selectedIndex = -1;
533
+ if (currentValue !== null && currentValue !== undefined) {
534
+ selectedIndex = opts.findIndex((opt) => compareFn(opt.value(), currentValue));
535
+ }
536
+ const initialIndex = selectedIndex >= 0 ? selectedIndex : 0;
537
+ this._setActiveOptionIndex(initialIndex);
538
+ }
539
+ // Scroll to active option
540
+ _scrollToActiveOption() {
541
+ const opts = this.filteredOptions();
542
+ const activeIndex = this.activeOptionIndex();
543
+ if (activeIndex < 0 || activeIndex >= opts.length)
544
+ return;
545
+ const activeOption = opts[activeIndex];
546
+ const element = activeOption._getHostElement();
547
+ const panelElement = this.panel?.nativeElement;
548
+ if (element && panelElement) {
549
+ const optionsContainer = panelElement.querySelector('.fui-autocomplete__options');
550
+ if (optionsContainer) {
551
+ const optionTop = element.offsetTop - optionsContainer.offsetTop;
552
+ const optionBottom = optionTop + element.offsetHeight;
553
+ const containerTop = optionsContainer.scrollTop;
554
+ const containerBottom = containerTop + optionsContainer.clientHeight;
555
+ if (optionTop < containerTop) {
556
+ optionsContainer.scrollTop = optionTop;
557
+ }
558
+ else if (optionBottom > containerBottom) {
559
+ optionsContainer.scrollTop = optionBottom - optionsContainer.clientHeight;
560
+ }
561
+ }
562
+ }
563
+ }
564
+ // Start listening for outside clicks when panel opens
565
+ _listenForOutsideClicks() {
566
+ this._outsideClickSub?.unsubscribe();
567
+ this._ngZone.runOutsideAngular(() => {
568
+ setTimeout(() => {
569
+ this._outsideClickSub = fromEvent(this._document, 'click')
570
+ .pipe(filter(() => this.panelOpen()), filter((event) => {
571
+ const target = event.target;
572
+ const triggerElement = this.trigger?.nativeElement;
573
+ const panelElement = this.panel?.nativeElement;
574
+ const overlayElement = this._overlayRef?.overlayElement;
575
+ return (!triggerElement?.contains(target) &&
576
+ !panelElement?.contains(target) &&
577
+ !overlayElement?.contains(target));
578
+ }))
579
+ .subscribe(() => {
580
+ this._ngZone.run(() => {
581
+ this.close();
582
+ });
583
+ });
584
+ });
585
+ });
586
+ }
587
+ // Create overlay for panel
588
+ _createOverlay() {
589
+ if (this._overlayRef || !this.panel || !this.trigger)
590
+ return;
591
+ const triggerElement = this.trigger.nativeElement;
592
+ const triggerWidth = triggerElement.getBoundingClientRect().width;
593
+ const positions = [
594
+ {
595
+ originX: 'start',
596
+ originY: 'bottom',
597
+ overlayX: 'start',
598
+ overlayY: 'top',
599
+ offsetY: 4,
600
+ },
601
+ {
602
+ originX: 'start',
603
+ originY: 'top',
604
+ overlayX: 'start',
605
+ overlayY: 'bottom',
606
+ offsetY: -4,
607
+ },
608
+ ];
609
+ const positionStrategy = this._overlayService
610
+ .position()
611
+ .connectedTo(triggerElement, positions)
612
+ .withPush(true)
613
+ .withViewportMargin(8);
614
+ this._overlayRef = this._overlayService.create({
615
+ positionStrategy,
616
+ scrollStrategy: this._overlayService.scrollStrategies.reposition(),
617
+ hasBackdrop: true,
618
+ backdropClass: 'fui-autocomplete-backdrop',
619
+ backdropClickBehavior: 'close',
620
+ panelClass: ['fui-autocomplete-overlay-panel'],
621
+ minWidth: triggerWidth,
622
+ });
623
+ // Track overlay subscriptions for proper cleanup
624
+ this._overlaySubscriptions.unsubscribe();
625
+ this._overlaySubscriptions = new Subscription();
626
+ this._overlaySubscriptions.add(this._overlayRef.backdropClick.subscribe(() => {
627
+ this.close();
628
+ }));
629
+ this._overlaySubscriptions.add(this._overlayRef.keydownEvents.subscribe((event) => {
630
+ if (event.key === 'Escape') {
631
+ this.close();
632
+ }
633
+ }));
634
+ // Attach panel to overlay
635
+ const panelElement = this.panel.nativeElement;
636
+ this._overlayRef.attach(panelElement);
637
+ }
638
+ // Dispose overlay
639
+ _disposeOverlay() {
640
+ this._overlaySubscriptions.unsubscribe();
641
+ if (this._overlayRef) {
642
+ this._overlayRef.dispose();
643
+ this._overlayRef = null;
644
+ }
645
+ }
646
+ // Get the active option's id for aria-activedescendant
647
+ _getActiveDescendant() {
648
+ const opts = this.filteredOptions();
649
+ const activeIndex = this.activeOptionIndex();
650
+ if (activeIndex >= 0 && activeIndex < opts.length) {
651
+ return opts[activeIndex].id;
652
+ }
653
+ return null;
654
+ }
655
+ // Set active option by index (for template use)
656
+ setActiveOption(index, option) {
657
+ const allOpts = this.options();
658
+ allOpts.forEach((opt) => {
659
+ opt.setInactive();
660
+ });
661
+ option.setActive();
662
+ this.activeOptionIndex.set(index);
663
+ }
664
+ // Mat-autocomplete compatibility methods
665
+ get selected() {
666
+ return this.value;
667
+ }
668
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiAutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
669
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiAutocompleteComponent, isStandalone: true, selector: "fui-autocomplete", inputs: { placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, showAddButton: { classPropertyName: "showAddButton", publicName: "showAddButton", isSignal: true, isRequired: false, transformFunction: null }, showRefreshButton: { classPropertyName: "showRefreshButton", publicName: "showRefreshButton", isSignal: true, isRequired: false, transformFunction: null }, addButtonLabel: { classPropertyName: "addButtonLabel", publicName: "addButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, refreshButtonLabel: { classPropertyName: "refreshButtonLabel", publicName: "refreshButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, noOptionsText: { classPropertyName: "noOptionsText", publicName: "noOptionsText", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", selectionChange: "selectionChange", openedChange: "openedChange", addNew: "addNew", refresh: "refresh", searchChange: "searchChange" }, host: { properties: { "attr.id": "id", "class.fui-autocomplete--open": "panelOpen()", "class.fui-autocomplete--disabled": "disabled()", "class.fui-autocomplete--focused": "focused()", "class.fui-autocomplete--error": "errorState()", "class.fui-autocomplete--readonly": "_readOnly()" }, classAttribute: "fui-autocomplete" }, providers: [
670
+ {
671
+ provide: NG_VALUE_ACCESSOR,
672
+ useExisting: FuiAutocompleteComponent,
673
+ multi: true,
674
+ },
675
+ {
676
+ provide: FUI_FORM_FIELD_CONTROL,
677
+ useExisting: FuiAutocompleteComponent,
678
+ },
679
+ {
680
+ provide: FUI_AUTOCOMPLETE,
681
+ useExisting: FuiAutocompleteComponent,
682
+ },
683
+ ], queries: [{ propertyName: "options", predicate: FuiOptionComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: "<!-- Autocomplete Trigger -->\r\n<div\r\n #trigger\r\n [id]=\"id\"\r\n class=\"fui-autocomplete__trigger\"\r\n [attr.tabindex]=\"disabled() ? -1 : 0\"\r\n [attr.role]=\"'combobox'\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n [attr.aria-describedby]=\"_ariaDescribedby\"\r\n [attr.aria-required]=\"required()\"\r\n aria-autocomplete=\"list\"\r\n [attr.aria-activedescendant]=\"panelOpen() ? _getActiveDescendant() : null\"\r\n [attr.aria-controls]=\"panelOpen() ? id + '-panel' : null\"\r\n (keydown)=\"_handleKeydown($event)\"\r\n>\r\n <span class=\"fui-autocomplete__value\">\r\n @if (empty()) {\r\n <span class=\"fui-autocomplete__placeholder\">{{ placeholder() }}</span>\r\n } @else {\r\n <span class=\"fui-autocomplete__value-text\">{{ _getDisplayValue() }}</span>\r\n }\r\n </span>\r\n\r\n @if (!_readOnly()) {\r\n <!-- Clear button \u2014 visible only when a value is selected and not disabled -->\r\n @if (!empty() && !disabled()) {\r\n <span class=\"fui-autocomplete__clear\" role=\"button\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\r\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\"\r\n />\r\n </svg>\r\n </span>\r\n }\r\n\r\n <!-- Dropdown arrow icon -->\r\n <svg\r\n class=\"fui-autocomplete__arrow\"\r\n [class.fui-autocomplete__arrow--open]=\"panelOpen()\"\r\n viewBox=\"0 0 16 16\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path d=\"M8 11L3 6l.7-.7L8 9.6l4.3-4.3L13 6z\" />\r\n </svg>\r\n }\r\n</div>\r\n\r\n<!-- Hidden container for projected options (used for data binding) -->\r\n<div class=\"fui-autocomplete__options-source\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!-- Dropdown Panel -->\r\n@if (panelOpen()) {\r\n <div #panel [id]=\"id + '-panel'\" class=\"fui-autocomplete__panel\" [attr.aria-label]=\"placeholder()\">\r\n <!-- Search Input -->\r\n <div class=\"fui-autocomplete__search\">\r\n <fui-icon name=\"magnifying-glass\" size=\"sm\" class=\"fui-autocomplete__search-icon\"> </fui-icon>\r\n <input\r\n #searchInput\r\n type=\"text\"\r\n class=\"fui-autocomplete__search-input\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n autocomplete=\"off\"\r\n role=\"searchbox\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [attr.aria-controls]=\"id + '-panel-listbox'\"\r\n [attr.aria-activedescendant]=\"_getActiveDescendant()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"_handlePanelKeydown($event)\"\r\n />\r\n </div>\r\n <!-- Live region for announcing result count to screen readers -->\r\n <div class=\"fui-visually-hidden\" aria-live=\"assertive\" aria-atomic=\"true\">\r\n @if (_liveAnnouncement()) {\r\n {{ _liveAnnouncement() }}\r\n } @else if (hasFilteredOptions()) {\r\n {{ filteredOptions().length }} results available.\r\n } @else {\r\n No results available.\r\n }\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n @if (showAddButton() || showRefreshButton()) {\r\n <div class=\"fui-autocomplete__actions\">\r\n @if (showAddButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onAddNew()\"\r\n >\r\n <fui-icon name=\"plus\" size=\"sm\"></fui-icon>\r\n {{ addButtonLabel() }}\r\n </button>\r\n }\r\n @if (showRefreshButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onRefresh()\"\r\n >\r\n <fui-icon name=\"refresh-cw\" size=\"sm\"></fui-icon>\r\n {{ refreshButtonLabel() }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Options List -->\r\n <div\r\n class=\"fui-autocomplete__options\"\r\n [id]=\"id + '-panel-listbox'\"\r\n role=\"listbox\"\r\n [attr.aria-label]=\"placeholder()\"\r\n >\r\n @if (hasFilteredOptions()) {\r\n @for (option of filteredOptions(); track option.id; let i = $index) {\r\n <div\r\n class=\"fui-autocomplete__option\"\r\n [class.fui-autocomplete__option--active]=\"activeOptionIndex() === i\"\r\n [class.fui-autocomplete__option--selected]=\"option._selected()\"\r\n role=\"option\"\r\n [attr.id]=\"option.id\"\r\n [attr.aria-selected]=\"option._selected()\"\r\n (click)=\"_onOptionSelected(option)\"\r\n (mouseenter)=\"setActiveOption(i, option)\"\r\n (mouseleave)=\"option.setInactive()\"\r\n >\r\n <span class=\"fui-autocomplete__option-text\">{{ option.getLabel() }}</span>\r\n @if (option._selected()) {\r\n <fui-icon name=\"check\" size=\"sm\" class=\"fui-autocomplete__option-check\"></fui-icon>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fui-autocomplete__no-options\">\r\n {{ noOptionsText() }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-autocomplete{--fui-autocomplete-font-size: var(--fui-font-size-02);--fui-autocomplete-panel-max-height: 24rem;--fui-autocomplete-panel-border-radius: var(--fui-border-radius-sm);--fui-autocomplete-panel-shadow: var(--fui-shadow-03);--fui-autocomplete-panel-bg: var(--fui-surface-00);--fui-autocomplete-option-padding: .5rem .75rem;--fui-autocomplete-search-padding: .75rem;position:relative;display:inline-block;width:100%}.fui-autocomplete__options-source{display:none}.fui-autocomplete__trigger{display:flex;align-items:center;width:100%;border:none;color:var(--fui-text-primary);font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);line-height:1.29;letter-spacing:.16px;cursor:pointer;outline:none;transition:border-color var(--fui-duration-fast-01) var(--fui-ease-standard),background-color var(--fui-duration-fast-01) var(--fui-ease-standard);gap:.25rem}.fui-autocomplete__trigger:hover:not([aria-disabled=true]){background-color:var(--fui-field-background-hover)}.fui-autocomplete__trigger[aria-disabled=true]{background-color:var(--fui-field-background-disabled);color:var(--fui-text-primary-disabled);cursor:not-allowed}.fui-autocomplete__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.fui-autocomplete__placeholder{color:var(--fui-text-secondary)}.fui-autocomplete__value-text{color:var(--fui-text-primary)}.fui-autocomplete__clear{display:flex;align-items:center;justify-content:center;width:1rem;height:1rem;cursor:pointer;color:var(--fui-icon-secondary);flex-shrink:0;border-radius:50%;transition:color var(--fui-duration-fast-01) var(--fui-ease-standard),background-color var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__clear svg{width:.75rem;height:.75rem}.fui-autocomplete__clear:hover{color:var(--fui-text-primary);background-color:var(--fui-background-hover)}.fui-autocomplete__arrow{width:1rem;height:1rem;flex-shrink:0;color:var(--fui-icon-primary);pointer-events:none;transition:transform var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__arrow--open{transform:rotate(180deg)}.fui-autocomplete__panel{position:absolute;width:100%;background-color:var(--fui-autocomplete-panel-bg);border:1px solid var(--fui-border-color);border-radius:var(--fui-autocomplete-panel-border-radius);box-shadow:var(--fui-autocomplete-panel-shadow);max-height:var(--fui-autocomplete-panel-max-height);overflow:hidden;display:flex;flex-direction:column}.fui-autocomplete__search{position:relative;padding:.75rem;border-bottom:1px solid var(--fui-border-color);background-color:var(--fui-field-background)}.fui-autocomplete__search-icon{position:absolute;left:1.5rem;top:50%;transform:translateY(-50%);color:var(--fui-icon-secondary);pointer-events:none}.fui-autocomplete__search-input{width:100%;padding:.5rem .75rem .5rem 2.5rem;border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);background-color:var(--fui-background-primary);color:var(--fui-text-primary);font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);line-height:1.29;letter-spacing:.16px;transition:border-color var(--fui-duration-fast-01) var(--fui-ease-standard),outline var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__search-input:focus{outline:2px solid var(--fui-primary);outline-offset:-2px;border-color:var(--fui-primary)}.fui-autocomplete__search-input::placeholder{color:var(--fui-text-secondary)}.fui-autocomplete__actions{display:flex;gap:.5rem;padding:.5rem .75rem;border-bottom:1px solid var(--fui-border-color);background-color:var(--fui-field-background)}.fui-autocomplete__action-button{display:flex;align-items:center;gap:.25rem;font-size:var(--fui-font-size-01)}.fui-autocomplete__action-button fui-icon{flex-shrink:0}.fui-autocomplete__options{max-height:16rem;overflow-y:auto;padding:.25rem 0;background-color:var(--fui-surface-01);scrollbar-width:thin;scrollbar-color:var(--fui-border-color) transparent}.fui-autocomplete__options::-webkit-scrollbar{width:6px}.fui-autocomplete__options::-webkit-scrollbar-track{background:transparent}.fui-autocomplete__options::-webkit-scrollbar-thumb{background-color:var(--fui-border-color);border-radius:3px}.fui-autocomplete__options::-webkit-scrollbar-thumb:hover{background-color:var(--fui-text-secondary)}.fui-autocomplete__option{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;cursor:pointer;color:var(--fui-text-primary);font-size:var(--fui-font-size-02);line-height:1.29;letter-spacing:.16px;transition:background-color var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__option:hover:not(.fui-autocomplete__option--disabled){background-color:var(--fui-background-hover)}.fui-autocomplete__option--active{background-color:var(--fui-surface-05)}.fui-autocomplete__option--selected{background-color:var(--fui-surface-05);font-weight:600}.fui-autocomplete__option--disabled{color:var(--fui-text-primary-disabled);cursor:not-allowed}.fui-autocomplete__option-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-autocomplete__option-check{color:var(--fui-icon-primary);flex-shrink:0;margin-left:.5rem}.fui-autocomplete__no-options{padding:1rem .75rem;text-align:center;color:var(--fui-text-secondary);font-size:var(--fui-font-size-02);font-style:italic}.fui-autocomplete--disabled .fui-autocomplete__trigger{background-color:var(--fui-field-background-disabled);color:var(--fui-text-primary-disabled);cursor:not-allowed}.fui-autocomplete--disabled .fui-autocomplete__arrow{color:var(--fui-text-primary-disabled)}.fui-autocomplete--readonly .fui-autocomplete__trigger{background-color:transparent;min-height:unset;cursor:default;color:var(--fui-text-primary)}.fui-autocomplete--readonly .fui-autocomplete__trigger[aria-disabled=true]{background-color:transparent;color:var(--fui-text-primary);cursor:default}.fui-autocomplete--readonly .fui-autocomplete__value-text{color:var(--fui-text-primary)}.fui-autocomplete--error .fui-autocomplete__trigger{border-bottom-color:var(--fui-error)}.fui-autocomplete--error .fui-autocomplete__trigger:focus{outline-color:var(--fui-error)}.fui-autocomplete-overlay-panel .fui-autocomplete__panel{border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);box-shadow:var(--fui-shadow-03)}.fui-autocomplete-backdrop{background:transparent}@media(prefers-contrast:high){.fui-autocomplete__trigger,.fui-autocomplete__panel{border-width:2px}.fui-autocomplete__trigger:focus,.fui-autocomplete__search-input:focus{outline-width:3px}.fui-autocomplete__option--active,.fui-autocomplete__option--selected{outline:2px solid var(--fui-primary);outline-offset:-2px}}@media(prefers-reduced-motion:reduce){.fui-autocomplete__trigger,.fui-autocomplete__arrow,.fui-autocomplete__option,.fui-autocomplete__search-input{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: FuiButtonDirective, selector: "button[fuiButton], a[fuiButton]", inputs: ["variant", "size", "disabled", "fullWidth", "loading", "iconOnly", "aria-label", "type"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
684
+ }
685
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiAutocompleteComponent, decorators: [{
686
+ type: Component,
687
+ args: [{ selector: 'fui-autocomplete', standalone: true, imports: [FuiIconComponent, ReactiveFormsModule, FuiButtonDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
688
+ class: 'fui-autocomplete',
689
+ '[attr.id]': 'id',
690
+ '[class.fui-autocomplete--open]': 'panelOpen()',
691
+ '[class.fui-autocomplete--disabled]': 'disabled()',
692
+ '[class.fui-autocomplete--focused]': 'focused()',
693
+ '[class.fui-autocomplete--error]': 'errorState()',
694
+ '[class.fui-autocomplete--readonly]': '_readOnly()',
695
+ }, providers: [
696
+ {
697
+ provide: NG_VALUE_ACCESSOR,
698
+ useExisting: FuiAutocompleteComponent,
699
+ multi: true,
700
+ },
701
+ {
702
+ provide: FUI_FORM_FIELD_CONTROL,
703
+ useExisting: FuiAutocompleteComponent,
704
+ },
705
+ {
706
+ provide: FUI_AUTOCOMPLETE,
707
+ useExisting: FuiAutocompleteComponent,
708
+ },
709
+ ], template: "<!-- Autocomplete Trigger -->\r\n<div\r\n #trigger\r\n [id]=\"id\"\r\n class=\"fui-autocomplete__trigger\"\r\n [attr.tabindex]=\"disabled() ? -1 : 0\"\r\n [attr.role]=\"'combobox'\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n [attr.aria-describedby]=\"_ariaDescribedby\"\r\n [attr.aria-required]=\"required()\"\r\n aria-autocomplete=\"list\"\r\n [attr.aria-activedescendant]=\"panelOpen() ? _getActiveDescendant() : null\"\r\n [attr.aria-controls]=\"panelOpen() ? id + '-panel' : null\"\r\n (keydown)=\"_handleKeydown($event)\"\r\n>\r\n <span class=\"fui-autocomplete__value\">\r\n @if (empty()) {\r\n <span class=\"fui-autocomplete__placeholder\">{{ placeholder() }}</span>\r\n } @else {\r\n <span class=\"fui-autocomplete__value-text\">{{ _getDisplayValue() }}</span>\r\n }\r\n </span>\r\n\r\n @if (!_readOnly()) {\r\n <!-- Clear button \u2014 visible only when a value is selected and not disabled -->\r\n @if (!empty() && !disabled()) {\r\n <span class=\"fui-autocomplete__clear\" role=\"button\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\r\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\"\r\n />\r\n </svg>\r\n </span>\r\n }\r\n\r\n <!-- Dropdown arrow icon -->\r\n <svg\r\n class=\"fui-autocomplete__arrow\"\r\n [class.fui-autocomplete__arrow--open]=\"panelOpen()\"\r\n viewBox=\"0 0 16 16\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path d=\"M8 11L3 6l.7-.7L8 9.6l4.3-4.3L13 6z\" />\r\n </svg>\r\n }\r\n</div>\r\n\r\n<!-- Hidden container for projected options (used for data binding) -->\r\n<div class=\"fui-autocomplete__options-source\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!-- Dropdown Panel -->\r\n@if (panelOpen()) {\r\n <div #panel [id]=\"id + '-panel'\" class=\"fui-autocomplete__panel\" [attr.aria-label]=\"placeholder()\">\r\n <!-- Search Input -->\r\n <div class=\"fui-autocomplete__search\">\r\n <fui-icon name=\"magnifying-glass\" size=\"sm\" class=\"fui-autocomplete__search-icon\"> </fui-icon>\r\n <input\r\n #searchInput\r\n type=\"text\"\r\n class=\"fui-autocomplete__search-input\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n autocomplete=\"off\"\r\n role=\"searchbox\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [attr.aria-controls]=\"id + '-panel-listbox'\"\r\n [attr.aria-activedescendant]=\"_getActiveDescendant()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"_handlePanelKeydown($event)\"\r\n />\r\n </div>\r\n <!-- Live region for announcing result count to screen readers -->\r\n <div class=\"fui-visually-hidden\" aria-live=\"assertive\" aria-atomic=\"true\">\r\n @if (_liveAnnouncement()) {\r\n {{ _liveAnnouncement() }}\r\n } @else if (hasFilteredOptions()) {\r\n {{ filteredOptions().length }} results available.\r\n } @else {\r\n No results available.\r\n }\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n @if (showAddButton() || showRefreshButton()) {\r\n <div class=\"fui-autocomplete__actions\">\r\n @if (showAddButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onAddNew()\"\r\n >\r\n <fui-icon name=\"plus\" size=\"sm\"></fui-icon>\r\n {{ addButtonLabel() }}\r\n </button>\r\n }\r\n @if (showRefreshButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onRefresh()\"\r\n >\r\n <fui-icon name=\"refresh-cw\" size=\"sm\"></fui-icon>\r\n {{ refreshButtonLabel() }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Options List -->\r\n <div\r\n class=\"fui-autocomplete__options\"\r\n [id]=\"id + '-panel-listbox'\"\r\n role=\"listbox\"\r\n [attr.aria-label]=\"placeholder()\"\r\n >\r\n @if (hasFilteredOptions()) {\r\n @for (option of filteredOptions(); track option.id; let i = $index) {\r\n <div\r\n class=\"fui-autocomplete__option\"\r\n [class.fui-autocomplete__option--active]=\"activeOptionIndex() === i\"\r\n [class.fui-autocomplete__option--selected]=\"option._selected()\"\r\n role=\"option\"\r\n [attr.id]=\"option.id\"\r\n [attr.aria-selected]=\"option._selected()\"\r\n (click)=\"_onOptionSelected(option)\"\r\n (mouseenter)=\"setActiveOption(i, option)\"\r\n (mouseleave)=\"option.setInactive()\"\r\n >\r\n <span class=\"fui-autocomplete__option-text\">{{ option.getLabel() }}</span>\r\n @if (option._selected()) {\r\n <fui-icon name=\"check\" size=\"sm\" class=\"fui-autocomplete__option-check\"></fui-icon>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fui-autocomplete__no-options\">\r\n {{ noOptionsText() }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}.fui-autocomplete{--fui-autocomplete-font-size: var(--fui-font-size-02);--fui-autocomplete-panel-max-height: 24rem;--fui-autocomplete-panel-border-radius: var(--fui-border-radius-sm);--fui-autocomplete-panel-shadow: var(--fui-shadow-03);--fui-autocomplete-panel-bg: var(--fui-surface-00);--fui-autocomplete-option-padding: .5rem .75rem;--fui-autocomplete-search-padding: .75rem;position:relative;display:inline-block;width:100%}.fui-autocomplete__options-source{display:none}.fui-autocomplete__trigger{display:flex;align-items:center;width:100%;border:none;color:var(--fui-text-primary);font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);line-height:1.29;letter-spacing:.16px;cursor:pointer;outline:none;transition:border-color var(--fui-duration-fast-01) var(--fui-ease-standard),background-color var(--fui-duration-fast-01) var(--fui-ease-standard);gap:.25rem}.fui-autocomplete__trigger:hover:not([aria-disabled=true]){background-color:var(--fui-field-background-hover)}.fui-autocomplete__trigger[aria-disabled=true]{background-color:var(--fui-field-background-disabled);color:var(--fui-text-primary-disabled);cursor:not-allowed}.fui-autocomplete__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.fui-autocomplete__placeholder{color:var(--fui-text-secondary)}.fui-autocomplete__value-text{color:var(--fui-text-primary)}.fui-autocomplete__clear{display:flex;align-items:center;justify-content:center;width:1rem;height:1rem;cursor:pointer;color:var(--fui-icon-secondary);flex-shrink:0;border-radius:50%;transition:color var(--fui-duration-fast-01) var(--fui-ease-standard),background-color var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__clear svg{width:.75rem;height:.75rem}.fui-autocomplete__clear:hover{color:var(--fui-text-primary);background-color:var(--fui-background-hover)}.fui-autocomplete__arrow{width:1rem;height:1rem;flex-shrink:0;color:var(--fui-icon-primary);pointer-events:none;transition:transform var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__arrow--open{transform:rotate(180deg)}.fui-autocomplete__panel{position:absolute;width:100%;background-color:var(--fui-autocomplete-panel-bg);border:1px solid var(--fui-border-color);border-radius:var(--fui-autocomplete-panel-border-radius);box-shadow:var(--fui-autocomplete-panel-shadow);max-height:var(--fui-autocomplete-panel-max-height);overflow:hidden;display:flex;flex-direction:column}.fui-autocomplete__search{position:relative;padding:.75rem;border-bottom:1px solid var(--fui-border-color);background-color:var(--fui-field-background)}.fui-autocomplete__search-icon{position:absolute;left:1.5rem;top:50%;transform:translateY(-50%);color:var(--fui-icon-secondary);pointer-events:none}.fui-autocomplete__search-input{width:100%;padding:.5rem .75rem .5rem 2.5rem;border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);background-color:var(--fui-background-primary);color:var(--fui-text-primary);font-family:var(--fui-font-family-sans);font-size:var(--fui-font-size-02);line-height:1.29;letter-spacing:.16px;transition:border-color var(--fui-duration-fast-01) var(--fui-ease-standard),outline var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__search-input:focus{outline:2px solid var(--fui-primary);outline-offset:-2px;border-color:var(--fui-primary)}.fui-autocomplete__search-input::placeholder{color:var(--fui-text-secondary)}.fui-autocomplete__actions{display:flex;gap:.5rem;padding:.5rem .75rem;border-bottom:1px solid var(--fui-border-color);background-color:var(--fui-field-background)}.fui-autocomplete__action-button{display:flex;align-items:center;gap:.25rem;font-size:var(--fui-font-size-01)}.fui-autocomplete__action-button fui-icon{flex-shrink:0}.fui-autocomplete__options{max-height:16rem;overflow-y:auto;padding:.25rem 0;background-color:var(--fui-surface-01);scrollbar-width:thin;scrollbar-color:var(--fui-border-color) transparent}.fui-autocomplete__options::-webkit-scrollbar{width:6px}.fui-autocomplete__options::-webkit-scrollbar-track{background:transparent}.fui-autocomplete__options::-webkit-scrollbar-thumb{background-color:var(--fui-border-color);border-radius:3px}.fui-autocomplete__options::-webkit-scrollbar-thumb:hover{background-color:var(--fui-text-secondary)}.fui-autocomplete__option{display:flex;align-items:center;justify-content:space-between;padding:.5rem .75rem;cursor:pointer;color:var(--fui-text-primary);font-size:var(--fui-font-size-02);line-height:1.29;letter-spacing:.16px;transition:background-color var(--fui-duration-fast-01) var(--fui-ease-standard)}.fui-autocomplete__option:hover:not(.fui-autocomplete__option--disabled){background-color:var(--fui-background-hover)}.fui-autocomplete__option--active{background-color:var(--fui-surface-05)}.fui-autocomplete__option--selected{background-color:var(--fui-surface-05);font-weight:600}.fui-autocomplete__option--disabled{color:var(--fui-text-primary-disabled);cursor:not-allowed}.fui-autocomplete__option-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-autocomplete__option-check{color:var(--fui-icon-primary);flex-shrink:0;margin-left:.5rem}.fui-autocomplete__no-options{padding:1rem .75rem;text-align:center;color:var(--fui-text-secondary);font-size:var(--fui-font-size-02);font-style:italic}.fui-autocomplete--disabled .fui-autocomplete__trigger{background-color:var(--fui-field-background-disabled);color:var(--fui-text-primary-disabled);cursor:not-allowed}.fui-autocomplete--disabled .fui-autocomplete__arrow{color:var(--fui-text-primary-disabled)}.fui-autocomplete--readonly .fui-autocomplete__trigger{background-color:transparent;min-height:unset;cursor:default;color:var(--fui-text-primary)}.fui-autocomplete--readonly .fui-autocomplete__trigger[aria-disabled=true]{background-color:transparent;color:var(--fui-text-primary);cursor:default}.fui-autocomplete--readonly .fui-autocomplete__value-text{color:var(--fui-text-primary)}.fui-autocomplete--error .fui-autocomplete__trigger{border-bottom-color:var(--fui-error)}.fui-autocomplete--error .fui-autocomplete__trigger:focus{outline-color:var(--fui-error)}.fui-autocomplete-overlay-panel .fui-autocomplete__panel{border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm);box-shadow:var(--fui-shadow-03)}.fui-autocomplete-backdrop{background:transparent}@media(prefers-contrast:high){.fui-autocomplete__trigger,.fui-autocomplete__panel{border-width:2px}.fui-autocomplete__trigger:focus,.fui-autocomplete__search-input:focus{outline-width:3px}.fui-autocomplete__option--active,.fui-autocomplete__option--selected{outline:2px solid var(--fui-primary);outline-offset:-2px}}@media(prefers-reduced-motion:reduce){.fui-autocomplete__trigger,.fui-autocomplete__arrow,.fui-autocomplete__option,.fui-autocomplete__search-input{transition:none}}\n"] }]
710
+ }], ctorParameters: () => [], propDecorators: { placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], showAddButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddButton", required: false }] }], showRefreshButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRefreshButton", required: false }] }], addButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addButtonLabel", required: false }] }], refreshButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshButtonLabel", required: false }] }], noOptionsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noOptionsText", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }], addNew: [{ type: i0.Output, args: ["addNew"] }], refresh: [{ type: i0.Output, args: ["refresh"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], trigger: [{
711
+ type: ViewChild,
712
+ args: ['trigger', { static: false }]
713
+ }], panel: [{
714
+ type: ViewChild,
715
+ args: ['panel', { static: false }]
716
+ }], searchInput: [{
717
+ type: ViewChild,
718
+ args: ['searchInput', { static: false }]
719
+ }], options: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FuiOptionComponent), { ...{ descendants: true }, isSignal: true }] }] } });
720
+
721
+ /**
722
+ * Generated bundle index. Do not edit.
723
+ */
724
+
725
+ export { FUI_AUTOCOMPLETE, FuiAutocompleteComponent };
726
+ //# sourceMappingURL=raintonic-formaui-components-autocomplete.mjs.map