@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 @@
1
+ {"version":3,"file":"raintonic-formaui-components-autocomplete.mjs","sources":["../../../lib/components/autocomplete/autocomplete.component.ts","../../../lib/components/autocomplete/autocomplete.component.html","../../../lib/components/autocomplete/raintonic-formaui-components-autocomplete.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChildren,\n DoCheck,\n effect,\n ElementRef,\n inject,\n InjectionToken,\n NgZone,\n input,\n InputSignal,\n OnDestroy,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n ViewChild,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport {\n ControlValueAccessor,\n FormGroupDirective,\n NG_VALUE_ACCESSOR,\n NgControl,\n NgForm,\n ReactiveFormsModule,\n} from '@angular/forms';\nimport { DOCUMENT } from '@angular/common';\nimport { fromEvent, Subject, Subscription } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { injectNgControl, updateErrorState, syncRequiredState, syncNgControlDisabled } from '@raintonic/formaui/cdk/form-field';\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\nimport { FuiButtonDirective } from '@raintonic/formaui/components/button';\nimport { FUI_FORM_FIELD_CONTROL, FuiFormFieldControl } from '@raintonic/formaui/core';\nimport { DefaultErrorStateMatcher, ErrorStateMatcher } from '@raintonic/formaui/core';\nimport { FuiOptionComponent } from '@raintonic/formaui/components/select';\nimport { FuiOverlayService, FuiOverlayRef, FuiConnectedPosition } from '@raintonic/formaui/cdk/overlay';\n\n/**\n * Injection token used to provide the parent autocomplete to options\n */\nexport const FUI_AUTOCOMPLETE = new InjectionToken<FuiAutocompleteComponent>('FUI_AUTOCOMPLETE');\n\n/**\n * Selection change event object emitted when the autocomplete's selection changes\n */\nexport interface FuiAutocompleteChange {\n source: FuiAutocompleteComponent;\n value: unknown;\n}\n\n/**\n * # fui-autocomplete Component\n *\n * An autocomplete component designed to work seamlessly with fui-form-field.\n * Similar to Angular Material's mat-autocomplete integration with mat-form-field.\n * Provides full Reactive Forms support with validation, filtering, and optional\n * add/refresh actions.\n *\n * ## Features\n * - Works inside fui-form-field like mat-autocomplete\n * - Full Reactive Forms integration (ControlValueAccessor)\n * - Options via projected content (fui-option)\n * - Built-in search/filter input in the panel\n * - Optional \"Add New\" and \"Refresh\" action buttons\n * - Disabled and readonly states\n * - Full accessibility support\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Home, End, PageUp, PageDown)\n * - Uses overlay service for proper positioning\n *\n * ## Usage\n *\n * ### Basic Autocomplete with Form Field\n * ```html\n * <fui-form-field>\n * <label>Country</label>\n * <fui-autocomplete placeholder=\"Search countries...\">\n * <fui-option value=\"us\">United States</fui-option>\n * <fui-option value=\"ca\">Canada</fui-option>\n * <fui-option value=\"mx\">Mexico</fui-option>\n * </fui-autocomplete>\n * </fui-form-field>\n * ```\n *\n * ### With Reactive Forms and Validation\n * ```html\n * <form [formGroup]=\"form\">\n * <fui-form-field>\n * <label>Country</label>\n * <fui-autocomplete formControlName=\"country\" placeholder=\"Select a country\">\n * <fui-option value=\"us\">United States</fui-option>\n * <fui-option value=\"ca\">Canada</fui-option>\n * </fui-autocomplete>\n * <fui-error *ngIf=\"form.get('country')?.hasError('required')\">\n * Country is required\n * </fui-error>\n * </fui-form-field>\n * </form>\n * ```\n *\n * ### With Add/Refresh Buttons\n * ```html\n * <fui-form-field>\n * <label>Category</label>\n * <fui-autocomplete\n * placeholder=\"Search categories...\"\n * [showAddButton]=\"true\"\n * [showRefreshButton]=\"true\"\n * (addNew)=\"openAddCategoryDialog()\"\n * (refresh)=\"refreshCategories()\">\n * @for (category of categories; track category.id) {\n * <fui-option [value]=\"category.id\">{{ category.name }}</fui-option>\n * }\n * </fui-autocomplete>\n * </fui-form-field>\n * ```\n */\n@Component({\n selector: 'fui-autocomplete',\n standalone: true,\n imports: [FuiIconComponent, ReactiveFormsModule, FuiButtonDirective],\n templateUrl: './autocomplete.component.html',\n styleUrls: ['./autocomplete.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'fui-autocomplete',\n '[attr.id]': 'id',\n '[class.fui-autocomplete--open]': 'panelOpen()',\n '[class.fui-autocomplete--disabled]': 'disabled()',\n '[class.fui-autocomplete--focused]': 'focused()',\n '[class.fui-autocomplete--error]': 'errorState()',\n '[class.fui-autocomplete--readonly]': '_readOnly()',\n },\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: FuiAutocompleteComponent,\n multi: true,\n },\n {\n provide: FUI_FORM_FIELD_CONTROL,\n useExisting: FuiAutocompleteComponent,\n },\n {\n provide: FUI_AUTOCOMPLETE,\n useExisting: FuiAutocompleteComponent,\n },\n ],\n})\nexport class FuiAutocompleteComponent implements ControlValueAccessor, FuiFormFieldControl, DoCheck, OnDestroy {\n // Static properties\n static nextId = 0;\n readonly controlType = 'fui-autocomplete';\n\n // Inputs using signal-based API\n readonly placeholderInput: InputSignal<string> = input('', {\n alias: 'placeholder',\n });\n readonly disabledInput: InputSignal<boolean> = input(false, {\n alias: 'disabled',\n });\n readonly readonly: InputSignal<boolean> = input(false);\n readonly showAddButton: InputSignal<boolean> = input(false);\n readonly showRefreshButton: InputSignal<boolean> = input(false);\n readonly addButtonLabel: InputSignal<string> = input('Add New');\n readonly refreshButtonLabel: InputSignal<string> = input('Refresh');\n readonly noOptionsText: InputSignal<string> = input('No options found');\n readonly searchPlaceholder: InputSignal<string> = input('Search...');\n readonly errorStateMatcher: InputSignal<ErrorStateMatcher | null> = input<ErrorStateMatcher | null>(null);\n\n /**\n * Whether to compare option values using object identity or deep equality\n */\n readonly compareWith: InputSignal<(o1: unknown, o2: unknown) => boolean> = input<\n (o1: unknown, o2: unknown) => boolean\n >((o1, o2) => o1 === o2);\n\n // Outputs\n readonly valueChange: OutputEmitterRef<unknown> = output<unknown>();\n readonly selectionChange: OutputEmitterRef<FuiAutocompleteChange> = output<FuiAutocompleteChange>();\n readonly openedChange: OutputEmitterRef<boolean> = output<boolean>();\n readonly addNew: OutputEmitterRef<void> = output();\n readonly refresh: OutputEmitterRef<void> = output();\n readonly searchChange: OutputEmitterRef<string> = output<string>();\n\n // Internal state signals\n private readonly _value: WritableSignal<unknown> = signal(null);\n private readonly _focused: WritableSignal<boolean> = signal(false);\n private readonly _disabled: WritableSignal<boolean> = signal(false);\n readonly _readOnly: WritableSignal<boolean> = signal(false);\n\n // FuiFormFieldControl implementation\n readonly stateChanges = new Subject<void>();\n private _uid = `fui-autocomplete-${FuiAutocompleteComponent.nextId++}`;\n _ariaDescribedby: string | null = null;\n\n // Error state\n private readonly _errorState: WritableSignal<boolean> = signal(false);\n readonly errorState = this._errorState;\n\n // Form control references\n private _parentForm = inject(NgForm, { optional: true });\n private _parentFormGroup = inject(FormGroupDirective, { optional: true });\n private _defaultErrorStateMatcher = inject(DefaultErrorStateMatcher);\n private readonly _ngControlRef = injectNgControl();\n get ngControl(): NgControl | null {\n return this._ngControlRef.ngControl;\n }\n\n // Interface implementation\n readonly placeholder = computed(() => this.placeholderInput());\n private readonly _required: WritableSignal<boolean> = signal(false);\n readonly required = this._required;\n\n readonly value = this._value;\n readonly focused = this._focused;\n\n private readonly _ngControlDisabled: WritableSignal<boolean> = signal(false);\n readonly disabled = computed(() => this._disabled() || this.disabledInput() || this._ngControlDisabled());\n\n readonly empty = computed(() => {\n const val = this._value();\n return val === null || val === undefined;\n });\n\n readonly id = this._uid;\n\n // ViewChild for trigger and panel\n @ViewChild('trigger', { static: false }) trigger?: ElementRef<HTMLDivElement>;\n @ViewChild('panel', { static: false }) panel?: ElementRef<HTMLDivElement>;\n @ViewChild('searchInput', { static: false })\n searchInput?: ElementRef<HTMLInputElement>;\n\n // ContentChildren for options\n readonly options = contentChildren(FuiOptionComponent, { descendants: true });\n\n // Panel open/close state\n readonly panelOpen = signal(false);\n\n // Search term for filtering\n readonly searchTerm: WritableSignal<string> = signal('');\n\n // Active option index for keyboard navigation\n readonly activeOptionIndex: WritableSignal<number> = signal(-1);\n\n // Live announcement for screen readers\n readonly _liveAnnouncement = signal('');\n\n _announce(message: string): void {\n this._liveAnnouncement.set('');\n setTimeout(() => {\n this._liveAnnouncement.set(message);\n }, 50);\n }\n\n // Overlay reference\n private _overlayRef: FuiOverlayRef | null = null;\n private _overlaySubscriptions = new Subscription();\n\n // Services\n private readonly _overlayService = inject(FuiOverlayService);\n private readonly _elementRef = inject(ElementRef);\n private readonly _document = inject(DOCUMENT);\n private readonly _ngZone = inject(NgZone);\n private _outsideClickSub?: Subscription;\n\n // ControlValueAccessor callbacks\n private _onChange: (value: unknown) => void = () => {\n // Intentionally empty: will be replaced by Angular forms\n };\n private _onTouched: () => void = () => {\n // Intentionally empty: will be replaced by Angular forms\n };\n\n // Computed properties\n readonly displayValue: Signal<string> = computed(() => {\n const currentValue = this.value();\n const opts = this.options();\n\n if (currentValue === null || currentValue === undefined) {\n return '';\n }\n\n const selectedOption = opts.find((opt) => this.compareWith()(opt.value(), currentValue));\n return selectedOption ? selectedOption.getLabel() : String(currentValue);\n });\n\n // Filtered options based on search term\n readonly filteredOptions: Signal<FuiOptionComponent[]> = computed(() => {\n const opts = this.options();\n const term = this.searchTerm().toLowerCase().trim();\n\n if (!term) {\n return opts.filter((opt) => !opt.disabled());\n }\n\n return opts.filter((opt) => !opt.disabled() && opt.getLabel().toLowerCase().includes(term));\n });\n\n readonly hasFilteredOptions: Signal<boolean> = computed(() => {\n return this.filteredOptions().length > 0;\n });\n\n constructor() {\n // Set valueAccessor after NgControl is resolved\n void Promise.resolve().then(() => {\n if (this._ngControlRef.ngControl) {\n this._ngControlRef.ngControl.valueAccessor = this;\n }\n });\n\n // Effect to emit state changes\n effect(() => {\n // Track all reactive inputs and internal signals\n this.placeholderInput();\n this.readonly();\n this.disabledInput();\n this.errorStateMatcher();\n this._focused();\n this._disabled();\n this._value();\n this._ngControlDisabled();\n this._required();\n this._errorState();\n\n // Emit state change\n this.stateChanges.next();\n });\n\n // Effect to update options selected state when value changes\n effect(() => {\n const currentValue = this._value();\n const opts = this.options();\n const compareFn = this.compareWith();\n\n opts.forEach((option) => {\n const optValue = option.value();\n const isSelected = compareFn(currentValue, optValue);\n\n if (isSelected) {\n option.select();\n } else {\n option.deselect();\n }\n });\n\n // Notify form-field that state may have changed\n this.stateChanges.next();\n });\n }\n\n ngDoCheck(): void {\n if (this.ngControl) {\n updateErrorState(\n this.ngControl,\n this._errorState,\n this.errorStateMatcher(),\n this._defaultErrorStateMatcher,\n this._parentForm,\n this._parentFormGroup,\n this.stateChanges,\n );\n syncRequiredState(this.ngControl, this._required, this.stateChanges);\n syncNgControlDisabled(this.ngControl, this._ngControlDisabled, this.stateChanges);\n }\n }\n\n ngOnDestroy(): void {\n this.stateChanges.complete();\n this._outsideClickSub?.unsubscribe();\n this._disposeOverlay();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: unknown): void {\n this._value.set(value ?? null);\n this.stateChanges.next();\n }\n\n registerOnChange(fn: (value: unknown) => void): void {\n this._onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._disabled.set(isDisabled);\n this.stateChanges.next();\n }\n\n // FuiFormFieldControl implementation\n onContainerClick(_event: MouseEvent): void {\n if (!this.disabled()) {\n this.toggle();\n }\n }\n\n setDescribedByIds(ids: string[]): void {\n this._ariaDescribedby = ids.length ? ids.join(' ') : null;\n }\n\n setReadOnly(readOnly: boolean): void {\n this._readOnly.set(readOnly);\n }\n\n // Public methods\n clear(event: Event): void {\n event.stopPropagation();\n this._value.set(null);\n this._onChange(null);\n this.valueChange.emit(null);\n this.selectionChange.emit({ source: this, value: null });\n this.stateChanges.next();\n }\n\n focus(): void {\n this.trigger?.nativeElement.focus();\n }\n\n blur(): void {\n this.trigger?.nativeElement.blur();\n }\n\n // Toggle panel open/close\n toggle(): void {\n if (this.disabled()) return;\n if (this.panelOpen()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n // Open the dropdown panel\n open(): void {\n if (this.disabled() || this.readonly() || this.panelOpen()) return;\n\n this.panelOpen.set(true);\n this._focused.set(true);\n this.searchTerm.set('');\n this.openedChange.emit(true);\n\n // Set active option to currently selected or first option\n this._setInitialActiveOption();\n\n // Create overlay after the view updates\n setTimeout(() => {\n this._createOverlay();\n this._scrollToActiveOption();\n this._listenForOutsideClicks();\n // Focus the search input\n this.searchInput?.nativeElement.focus();\n }, 0);\n }\n\n // Close the dropdown panel\n close(): void {\n if (!this.panelOpen()) return;\n this._outsideClickSub?.unsubscribe();\n\n this.panelOpen.set(false);\n this._focused.set(false);\n this.activeOptionIndex.set(-1);\n this.searchTerm.set('');\n this._disposeOverlay();\n this.openedChange.emit(false);\n this._onTouched();\n\n // Clear active state on all options\n this.options().forEach((opt) => {\n opt.setInactive();\n });\n\n // Return focus to trigger\n setTimeout(() => {\n this.trigger?.nativeElement.focus();\n }, 0);\n }\n\n // Handle option selection (called by FuiOptionComponent or internally)\n _onOptionSelected(option: FuiOptionComponent): void {\n const newValue = option.value();\n\n // Deselect previous option\n const opts = this.options();\n opts.forEach((opt) => {\n if (opt !== option) {\n opt.deselect();\n }\n });\n\n option.select();\n this._value.set(newValue);\n this._onChange(newValue);\n this.valueChange.emit(newValue);\n this.selectionChange.emit({ source: this, value: newValue });\n this._announce(`${option.getLabel()} selected`);\n this.close();\n\n this.stateChanges.next();\n }\n\n // Handle search input\n onSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n const term = target.value;\n this.searchTerm.set(term);\n this.searchChange.emit(term);\n\n // Reset active index when search changes\n const filtered = this.filteredOptions();\n if (filtered.length > 0) {\n this._setActiveOptionIndex(0);\n } else {\n this.activeOptionIndex.set(-1);\n }\n }\n\n // Handle add new action\n onAddNew(): void {\n this.close();\n this.addNew.emit();\n }\n\n // Handle refresh action\n onRefresh(): void {\n this.refresh.emit();\n // Keep panel open and clear search\n this.searchTerm.set('');\n }\n\n // Get display value for trigger\n _getDisplayValue(): string {\n return this.displayValue();\n }\n\n // Handle keyboard navigation\n _handleKeydown(event: KeyboardEvent): void {\n if (this.disabled()) return;\n\n const isOpen = this.panelOpen();\n\n if (!isOpen) {\n this._handleClosedKeydown(event);\n } else {\n this._handleOpenKeydown(event);\n }\n }\n\n // Handle keydown when panel is closed\n private _handleClosedKeydown(event: KeyboardEvent): void {\n const key = event.key;\n\n switch (key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n case 'ArrowUp':\n event.preventDefault();\n this.open();\n break;\n }\n }\n\n // Handle keydown when panel is open (for search input)\n _handlePanelKeydown(event: KeyboardEvent): void {\n if (this.disabled()) return;\n\n const key = event.key;\n const opts = this.filteredOptions();\n const activeIndex = this.activeOptionIndex();\n\n switch (key) {\n case 'ArrowDown':\n event.preventDefault();\n this._setNextActiveOption(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this._setNextActiveOption(-1);\n break;\n case 'Home':\n event.preventDefault();\n if (opts.length > 0) {\n this._setActiveOptionIndex(0);\n }\n break;\n case 'End':\n event.preventDefault();\n if (opts.length > 0) {\n this._setActiveOptionIndex(opts.length - 1);\n }\n break;\n case 'PageDown':\n event.preventDefault();\n if (opts.length > 0) {\n const pageSize = Math.min(10, opts.length);\n const newIndex = Math.min(activeIndex + pageSize, opts.length - 1);\n this._setActiveOptionIndex(newIndex);\n }\n break;\n case 'PageUp':\n event.preventDefault();\n if (opts.length > 0) {\n const pageSize = Math.min(10, opts.length);\n const newIndex = Math.max(activeIndex - pageSize, 0);\n this._setActiveOptionIndex(newIndex);\n }\n break;\n case 'Enter':\n event.preventDefault();\n if (activeIndex >= 0 && activeIndex < opts.length) {\n this._onOptionSelected(opts[activeIndex]);\n }\n break;\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n case 'Tab':\n // Allow tab to close and move to next element\n this.close();\n break;\n }\n }\n\n // Handle keydown when panel is open (for trigger)\n private _handleOpenKeydown(event: KeyboardEvent): void {\n // Delegate to panel keydown handler\n this._handlePanelKeydown(event);\n }\n\n // Set the next active option based on delta\n private _setNextActiveOption(delta: number): void {\n const opts = this.filteredOptions();\n if (opts.length === 0) return;\n\n let currentIndex = this.activeOptionIndex();\n if (currentIndex < 0) {\n currentIndex = delta > 0 ? -1 : opts.length;\n }\n\n let newIndex = currentIndex + delta;\n\n // Wrap around\n if (newIndex < 0) {\n newIndex = opts.length - 1;\n } else if (newIndex >= opts.length) {\n newIndex = 0;\n }\n\n this._setActiveOptionIndex(newIndex);\n }\n\n // Set the active option index\n private _setActiveOptionIndex(index: number): void {\n const opts = this.filteredOptions();\n if (index < 0 || index >= opts.length) return;\n\n // Update active state on options\n const allOpts = this.options();\n allOpts.forEach((opt) => {\n opt.setInactive();\n });\n\n const activeOption = opts[index];\n activeOption.setActive();\n this.activeOptionIndex.set(index);\n this._scrollToActiveOption();\n this._announce(`${activeOption.getLabel()}, ${index + 1} of ${opts.length}`);\n }\n\n // Set initial active option when opening\n private _setInitialActiveOption(): void {\n const opts = this.filteredOptions();\n if (opts.length === 0) {\n this.activeOptionIndex.set(-1);\n return;\n }\n\n const currentValue = this._value();\n const compareFn = this.compareWith();\n\n // Find the selected option\n let selectedIndex = -1;\n if (currentValue !== null && currentValue !== undefined) {\n selectedIndex = opts.findIndex((opt) => compareFn(opt.value(), currentValue));\n }\n\n const initialIndex = selectedIndex >= 0 ? selectedIndex : 0;\n this._setActiveOptionIndex(initialIndex);\n }\n\n // Scroll to active option\n private _scrollToActiveOption(): void {\n const opts = this.filteredOptions();\n const activeIndex = this.activeOptionIndex();\n\n if (activeIndex < 0 || activeIndex >= opts.length) return;\n\n const activeOption = opts[activeIndex];\n const element = activeOption._getHostElement();\n const panelElement = this.panel?.nativeElement;\n\n if (element && panelElement) {\n const optionsContainer = panelElement.querySelector('.fui-autocomplete__options');\n if (optionsContainer) {\n const optionTop = element.offsetTop - (optionsContainer as HTMLElement).offsetTop;\n const optionBottom = optionTop + element.offsetHeight;\n const containerTop = optionsContainer.scrollTop;\n const containerBottom = containerTop + optionsContainer.clientHeight;\n\n if (optionTop < containerTop) {\n optionsContainer.scrollTop = optionTop;\n } else if (optionBottom > containerBottom) {\n optionsContainer.scrollTop = optionBottom - optionsContainer.clientHeight;\n }\n }\n }\n }\n\n // Start listening for outside clicks when panel opens\n private _listenForOutsideClicks(): void {\n this._outsideClickSub?.unsubscribe();\n\n this._ngZone.runOutsideAngular(() => {\n setTimeout(() => {\n this._outsideClickSub = fromEvent<MouseEvent>(this._document, 'click')\n .pipe(\n filter(() => this.panelOpen()),\n filter((event) => {\n const target = event.target as HTMLElement;\n const triggerElement = this.trigger?.nativeElement;\n const panelElement = this.panel?.nativeElement;\n const overlayElement = this._overlayRef?.overlayElement;\n return (\n !triggerElement?.contains(target) &&\n !panelElement?.contains(target) &&\n !overlayElement?.contains(target)\n );\n }),\n )\n .subscribe(() => {\n this._ngZone.run(() => {\n this.close();\n });\n });\n });\n });\n }\n\n // Create overlay for panel\n private _createOverlay(): void {\n if (this._overlayRef || !this.panel || !this.trigger) return;\n\n const triggerElement = this.trigger.nativeElement;\n const triggerWidth = triggerElement.getBoundingClientRect().width;\n\n const positions: FuiConnectedPosition[] = [\n {\n originX: 'start',\n originY: 'bottom',\n overlayX: 'start',\n overlayY: 'top',\n offsetY: 4,\n },\n {\n originX: 'start',\n originY: 'top',\n overlayX: 'start',\n overlayY: 'bottom',\n offsetY: -4,\n },\n ];\n\n const positionStrategy = this._overlayService\n .position()\n .connectedTo(triggerElement, positions)\n .withPush(true)\n .withViewportMargin(8);\n\n this._overlayRef = this._overlayService.create({\n positionStrategy,\n scrollStrategy: this._overlayService.scrollStrategies.reposition(),\n hasBackdrop: true,\n backdropClass: 'fui-autocomplete-backdrop',\n backdropClickBehavior: 'close',\n panelClass: ['fui-autocomplete-overlay-panel'],\n minWidth: triggerWidth,\n });\n\n // Track overlay subscriptions for proper cleanup\n this._overlaySubscriptions.unsubscribe();\n this._overlaySubscriptions = new Subscription();\n\n this._overlaySubscriptions.add(\n this._overlayRef.backdropClick.subscribe(() => {\n this.close();\n }),\n );\n\n this._overlaySubscriptions.add(\n this._overlayRef.keydownEvents.subscribe((event) => {\n if (event.key === 'Escape') {\n this.close();\n }\n }),\n );\n\n // Attach panel to overlay\n const panelElement = this.panel.nativeElement;\n this._overlayRef.attach(panelElement);\n }\n\n // Dispose overlay\n private _disposeOverlay(): void {\n this._overlaySubscriptions.unsubscribe();\n if (this._overlayRef) {\n this._overlayRef.dispose();\n this._overlayRef = null;\n }\n }\n\n // Get the active option's id for aria-activedescendant\n _getActiveDescendant(): string | null {\n const opts = this.filteredOptions();\n const activeIndex = this.activeOptionIndex();\n if (activeIndex >= 0 && activeIndex < opts.length) {\n return opts[activeIndex].id;\n }\n return null;\n }\n\n // Set active option by index (for template use)\n setActiveOption(index: number, option: FuiOptionComponent): void {\n const allOpts = this.options();\n allOpts.forEach((opt) => {\n opt.setInactive();\n });\n option.setActive();\n this.activeOptionIndex.set(index);\n }\n\n // Mat-autocomplete compatibility methods\n get selected(): unknown {\n return this.value;\n }\n}\n","<!-- 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 — 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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+
4
+ /**
5
+ * @component FuiAvatarComponent
6
+ * @selector fui-avatar
7
+ * @description Displays a user avatar with image, initials fallback, and configurable shape/size.
8
+ * Automatically computes initials from name fields and generates a background color from an identity key.
9
+ *
10
+ * @input size - Avatar size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' or a numeric pixel value. Default 'md'.
11
+ * @input shape - Avatar shape: 'circle' | 'rounded' | 'square'. Default 'circle'.
12
+ * @input src - Image URL or data URI for the avatar.
13
+ * @input avatarUrl - Backward-compatible alias for src.
14
+ * @input srcSet - HTML srcset attribute for responsive images.
15
+ * @input sizesAttr - HTML sizes attribute for responsive images.
16
+ * @input name - First name used to compute initials.
17
+ * @input surname - Last name used to compute initials.
18
+ * @input fullName - Full name (overrides name + surname for initials).
19
+ * @input alt - Alt text for the image element.
20
+ * @input identityKey - Key (e.g. email) used to deterministically pick a background color.
21
+ *
22
+ * @example
23
+ * <fui-avatar [src]="user.photoUrl" [fullName]="user.displayName" size="lg"></fui-avatar>
24
+ */
25
+ class FuiAvatarComponent {
26
+ // Inputs (signals)
27
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
28
+ shape = input('circle', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
29
+ src = input(null, ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ [])); // URL or data URI
30
+ // Backward compatibility with previous API
31
+ avatarUrl = input(null, ...(ngDevMode ? [{ debugName: "avatarUrl" }] : /* istanbul ignore next */ []));
32
+ srcSet = input(null, ...(ngDevMode ? [{ debugName: "srcSet" }] : /* istanbul ignore next */ []));
33
+ sizesAttr = input(null, ...(ngDevMode ? [{ debugName: "sizesAttr" }] : /* istanbul ignore next */ []));
34
+ name = input(null, ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
35
+ surname = input(null, ...(ngDevMode ? [{ debugName: "surname" }] : /* istanbul ignore next */ []));
36
+ fullName = input(null, ...(ngDevMode ? [{ debugName: "fullName" }] : /* istanbul ignore next */ []));
37
+ alt = input(null, ...(ngDevMode ? [{ debugName: "alt" }] : /* istanbul ignore next */ []));
38
+ identityKey = input(null, ...(ngDevMode ? [{ debugName: "identityKey" }] : /* istanbul ignore next */ [])); // e.g., email for color hashing
39
+ // Local state
40
+ imageFailed = signal(false, ...(ngDevMode ? [{ debugName: "imageFailed" }] : /* istanbul ignore next */ []));
41
+ // Derived values
42
+ normalizedName = computed(() => {
43
+ const fn = (this.fullName() ?? `${this.name() ?? ''} ${this.surname() ?? ''}`).trim();
44
+ return fn.replace(/\s+/g, ' ');
45
+ }, ...(ngDevMode ? [{ debugName: "normalizedName" }] : /* istanbul ignore next */ []));
46
+ initials = computed(() => {
47
+ const parts = this.normalizedName().split(' ').filter(Boolean);
48
+ if (parts.length === 0)
49
+ return '?';
50
+ if (parts.length === 1)
51
+ return parts[0].slice(0, 2).toUpperCase();
52
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
53
+ }, ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
54
+ pixelSize = computed(() => {
55
+ const s = this.size();
56
+ if (typeof s === 'number')
57
+ return s;
58
+ return { xs: 16, sm: 24, md: 32, lg: 40, xl: 48 }[s] ?? 32;
59
+ }, ...(ngDevMode ? [{ debugName: "pixelSize" }] : /* istanbul ignore next */ []));
60
+ displayImage = computed(() => {
61
+ if (this.imageFailed())
62
+ return null;
63
+ return this.src() ?? this.avatarUrl();
64
+ }, ...(ngDevMode ? [{ debugName: "displayImage" }] : /* istanbul ignore next */ []));
65
+ bgColor = computed(() => {
66
+ const key = this.identityKey() ?? this.normalizedName() ?? this.initials();
67
+ const palette = ['var(--fui-primary)'];
68
+ let h = 0;
69
+ for (let i = 0; i < key.length; i++)
70
+ h = ((h << 5) - h + key.charCodeAt(i)) | 0;
71
+ return palette[Math.abs(h) % palette.length];
72
+ }, ...(ngDevMode ? [{ debugName: "bgColor" }] : /* istanbul ignore next */ []));
73
+ ariaLabel = computed(() => {
74
+ return this.alt() ?? (this.normalizedName() ? `Avatar for ${this.normalizedName()}` : 'User avatar');
75
+ }, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
76
+ onImgError() {
77
+ this.imageFailed.set(true);
78
+ }
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiAvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiAvatarComponent, isStandalone: true, selector: "fui-avatar", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, avatarUrl: { classPropertyName: "avatarUrl", publicName: "avatarUrl", isSignal: true, isRequired: false, transformFunction: null }, srcSet: { classPropertyName: "srcSet", publicName: "srcSet", isSignal: true, isRequired: false, transformFunction: null }, sizesAttr: { classPropertyName: "sizesAttr", publicName: "sizesAttr", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, surname: { classPropertyName: "surname", publicName: "surname", isSignal: true, isRequired: false, transformFunction: null }, fullName: { classPropertyName: "fullName", publicName: "fullName", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, identityKey: { classPropertyName: "identityKey", publicName: "identityKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\r\n class=\"fui-avatar\"\r\n [style.--fui-avatar-size.px]=\"pixelSize()\"\r\n [class.fui-avatar--rounded]=\"shape() === 'rounded'\"\r\n [class.fui-avatar--square]=\"shape() === 'square'\"\r\n>\r\n @if (displayImage(); as img) {\r\n <img\r\n class=\"fui-avatar__img\"\r\n [src]=\"img\"\r\n [srcset]=\"srcSet() || null\"\r\n [sizes]=\"sizesAttr() || null\"\r\n [attr.alt]=\"ariaLabel()\"\r\n loading=\"lazy\"\r\n decoding=\"async\"\r\n referrerpolicy=\"no-referrer\"\r\n (error)=\"onImgError()\"\r\n />\r\n } @else {\r\n <div class=\"fui-avatar__initials\" role=\"img\" [attr.aria-label]=\"ariaLabel()\" [style.background-color]=\"bgColor()\">\r\n {{ initials() }}\r\n </div>\r\n }\r\n\r\n <ng-content select=\"[avatar-badge]\"></ng-content>\r\n</div>\r\n", styles: [".fui-avatar{--fui-avatar-size: 32px;--fui-avatar-border-radius: var(--fui-border-radius-pill);--fui-avatar-border-color: var(--fui-border-color);--fui-avatar-font-size: var(--fui-font-size-02);--fui-avatar-font-weight: var(--fui-font-weight-semibold);contain:content;inline-size:var(--fui-avatar-size);block-size:var(--fui-avatar-size);position:relative;display:inline-flex;align-items:center;justify-content:center;border:var(--fui-border-width-sm) solid var(--fui-avatar-border-color);border-radius:var(--fui-avatar-border-radius);overflow:hidden;flex-shrink:0}.fui-avatar--rounded{border-radius:var(--fui-border-radius-sm)}.fui-avatar--square{border-radius:var(--fui-border-radius-none)}.fui-avatar__img{inline-size:100%;block-size:100%;object-fit:cover;border:var(--fui-border-width-sm) solid var(--fui-border-color)}.fui-avatar__initials{inline-size:100%;block-size:100%;display:grid;place-items:center;color:var(--fui-text-primary);font:var(--fui-avatar-font-weight) var(--fui-avatar-font-size)/1 var(--fui-font-family-sans);text-transform:uppercase}.fui-avatar ::ng-deep [avatar-badge]{position:absolute;inset-inline-end:-2px;inset-block-end:-2px;transform:translate(0)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiAvatarComponent, decorators: [{
83
+ type: Component,
84
+ args: [{ selector: 'fui-avatar', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"fui-avatar\"\r\n [style.--fui-avatar-size.px]=\"pixelSize()\"\r\n [class.fui-avatar--rounded]=\"shape() === 'rounded'\"\r\n [class.fui-avatar--square]=\"shape() === 'square'\"\r\n>\r\n @if (displayImage(); as img) {\r\n <img\r\n class=\"fui-avatar__img\"\r\n [src]=\"img\"\r\n [srcset]=\"srcSet() || null\"\r\n [sizes]=\"sizesAttr() || null\"\r\n [attr.alt]=\"ariaLabel()\"\r\n loading=\"lazy\"\r\n decoding=\"async\"\r\n referrerpolicy=\"no-referrer\"\r\n (error)=\"onImgError()\"\r\n />\r\n } @else {\r\n <div class=\"fui-avatar__initials\" role=\"img\" [attr.aria-label]=\"ariaLabel()\" [style.background-color]=\"bgColor()\">\r\n {{ initials() }}\r\n </div>\r\n }\r\n\r\n <ng-content select=\"[avatar-badge]\"></ng-content>\r\n</div>\r\n", styles: [".fui-avatar{--fui-avatar-size: 32px;--fui-avatar-border-radius: var(--fui-border-radius-pill);--fui-avatar-border-color: var(--fui-border-color);--fui-avatar-font-size: var(--fui-font-size-02);--fui-avatar-font-weight: var(--fui-font-weight-semibold);contain:content;inline-size:var(--fui-avatar-size);block-size:var(--fui-avatar-size);position:relative;display:inline-flex;align-items:center;justify-content:center;border:var(--fui-border-width-sm) solid var(--fui-avatar-border-color);border-radius:var(--fui-avatar-border-radius);overflow:hidden;flex-shrink:0}.fui-avatar--rounded{border-radius:var(--fui-border-radius-sm)}.fui-avatar--square{border-radius:var(--fui-border-radius-none)}.fui-avatar__img{inline-size:100%;block-size:100%;object-fit:cover;border:var(--fui-border-width-sm) solid var(--fui-border-color)}.fui-avatar__initials{inline-size:100%;block-size:100%;display:grid;place-items:center;color:var(--fui-text-primary);font:var(--fui-avatar-font-weight) var(--fui-avatar-font-size)/1 var(--fui-font-family-sans);text-transform:uppercase}.fui-avatar ::ng-deep [avatar-badge]{position:absolute;inset-inline-end:-2px;inset-block-end:-2px;transform:translate(0)}\n"] }]
85
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], avatarUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarUrl", required: false }] }], srcSet: [{ type: i0.Input, args: [{ isSignal: true, alias: "srcSet", required: false }] }], sizesAttr: [{ type: i0.Input, args: [{ isSignal: true, alias: "sizesAttr", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], surname: [{ type: i0.Input, args: [{ isSignal: true, alias: "surname", required: false }] }], fullName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullName", required: false }] }], alt: [{ type: i0.Input, args: [{ isSignal: true, alias: "alt", required: false }] }], identityKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "identityKey", required: false }] }] } });
86
+
87
+ /**
88
+ * Generated bundle index. Do not edit.
89
+ */
90
+
91
+ export { FuiAvatarComponent };
92
+ //# sourceMappingURL=raintonic-formaui-components-avatar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raintonic-formaui-components-avatar.mjs","sources":["../../../lib/components/avatar/avatar.component.ts","../../../lib/components/avatar/avatar.component.html","../../../lib/components/avatar/raintonic-formaui-components-avatar.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, Signal, signal } from '@angular/core';\n\nexport type FuiAvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\n/**\n * @component FuiAvatarComponent\n * @selector fui-avatar\n * @description Displays a user avatar with image, initials fallback, and configurable shape/size.\n * Automatically computes initials from name fields and generates a background color from an identity key.\n *\n * @input size - Avatar size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' or a numeric pixel value. Default 'md'.\n * @input shape - Avatar shape: 'circle' | 'rounded' | 'square'. Default 'circle'.\n * @input src - Image URL or data URI for the avatar.\n * @input avatarUrl - Backward-compatible alias for src.\n * @input srcSet - HTML srcset attribute for responsive images.\n * @input sizesAttr - HTML sizes attribute for responsive images.\n * @input name - First name used to compute initials.\n * @input surname - Last name used to compute initials.\n * @input fullName - Full name (overrides name + surname for initials).\n * @input alt - Alt text for the image element.\n * @input identityKey - Key (e.g. email) used to deterministically pick a background color.\n *\n * @example\n * <fui-avatar [src]=\"user.photoUrl\" [fullName]=\"user.displayName\" size=\"lg\"></fui-avatar>\n */\n@Component({\n selector: 'fui-avatar',\n standalone: true,\n imports: [],\n templateUrl: './avatar.component.html',\n styleUrls: ['./avatar.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class FuiAvatarComponent {\n // Inputs (signals)\n readonly size = input<FuiAvatarSize | number>('md');\n readonly shape = input<'circle' | 'rounded' | 'square'>('circle');\n readonly src = input<string | null>(null); // URL or data URI\n // Backward compatibility with previous API\n readonly avatarUrl = input<string | null>(null);\n readonly srcSet = input<string | null>(null);\n readonly sizesAttr = input<string | null>(null);\n readonly name = input<string | null>(null);\n readonly surname = input<string | null>(null);\n readonly fullName = input<string | null>(null);\n readonly alt = input<string | null>(null);\n readonly identityKey = input<string | null>(null); // e.g., email for color hashing\n\n // Local state\n private readonly imageFailed = signal(false);\n\n // Derived values\n readonly normalizedName: Signal<string> = computed(() => {\n const fn = (this.fullName() ?? `${this.name() ?? ''} ${this.surname() ?? ''}`).trim();\n return fn.replace(/\\s+/g, ' ');\n });\n\n readonly initials: Signal<string> = computed(() => {\n const parts = this.normalizedName().split(' ').filter(Boolean);\n if (parts.length === 0) return '?';\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n });\n\n readonly pixelSize: Signal<number> = computed(() => {\n const s = this.size();\n if (typeof s === 'number') return s;\n return { xs: 16, sm: 24, md: 32, lg: 40, xl: 48 }[s] ?? 32;\n });\n\n readonly displayImage: Signal<string | null> = computed(() => {\n if (this.imageFailed()) return null;\n return this.src() ?? this.avatarUrl();\n });\n\n readonly bgColor: Signal<string> = computed(() => {\n const key = this.identityKey() ?? this.normalizedName() ?? this.initials();\n const palette = ['var(--fui-primary)'];\n let h = 0;\n for (let i = 0; i < key.length; i++) h = ((h << 5) - h + key.charCodeAt(i)) | 0;\n return palette[Math.abs(h) % palette.length];\n });\n\n readonly ariaLabel: Signal<string> = computed(() => {\n return this.alt() ?? (this.normalizedName() ? `Avatar for ${this.normalizedName()}` : 'User avatar');\n });\n\n onImgError(): void {\n this.imageFailed.set(true);\n }\n}\n","<div\r\n class=\"fui-avatar\"\r\n [style.--fui-avatar-size.px]=\"pixelSize()\"\r\n [class.fui-avatar--rounded]=\"shape() === 'rounded'\"\r\n [class.fui-avatar--square]=\"shape() === 'square'\"\r\n>\r\n @if (displayImage(); as img) {\r\n <img\r\n class=\"fui-avatar__img\"\r\n [src]=\"img\"\r\n [srcset]=\"srcSet() || null\"\r\n [sizes]=\"sizesAttr() || null\"\r\n [attr.alt]=\"ariaLabel()\"\r\n loading=\"lazy\"\r\n decoding=\"async\"\r\n referrerpolicy=\"no-referrer\"\r\n (error)=\"onImgError()\"\r\n />\r\n } @else {\r\n <div class=\"fui-avatar__initials\" role=\"img\" [attr.aria-label]=\"ariaLabel()\" [style.background-color]=\"bgColor()\">\r\n {{ initials() }}\r\n </div>\r\n }\r\n\r\n <ng-content select=\"[avatar-badge]\"></ng-content>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { FuiIconComponent } from '@raintonic/formaui/components/icon';
4
+
5
+ const FUI_BADGE_SIZES = ['sm', 'md', 'lg'];
6
+ const FUI_BADGE_VARIANTS = [
7
+ 'primary',
8
+ 'secondary',
9
+ 'success',
10
+ 'info',
11
+ 'warning',
12
+ 'error',
13
+ 'custom',
14
+ ];
15
+
16
+ /**
17
+ * @component FuiBadgeComponent
18
+ * @selector fui-badge
19
+ * @description Displays a small label badge with optional icon and color variants.
20
+ * Supports custom colors with automatic text contrast calculation.
21
+ *
22
+ * @input label - (required) Text content of the badge.
23
+ * @input icon - Optional Phosphor icon name displayed before the label.
24
+ * @input customColor - Optional hex color that overrides the variant palette.
25
+ * @input size - Badge size: 'sm' | 'md' | 'lg'. Default 'md'.
26
+ * @input variant - Color variant: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'. Default 'primary'.
27
+ * @input ariaLabel - Accessible label override for screen readers.
28
+ *
29
+ * @example
30
+ * <fui-badge label="Active" variant="success" icon="check-circle"></fui-badge>
31
+ */
32
+ class FuiBadgeComponent {
33
+ /** Pattern allowing hex, rgb/rgba, hsl/hsla, and CSS named colors */
34
+ static _SAFE_COLOR_PATTERN = /^(#[0-9a-fA-F]{3,8}|(?:rgb|hsl)a?\([^)]+\)|[a-zA-Z]+)$/;
35
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
36
+ icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
37
+ customColor = input(null, ...(ngDevMode ? [{ debugName: "customColor" }] : /* istanbul ignore next */ []));
38
+ size = input('md', { ...(ngDevMode ? { debugName: "size" } : /* istanbul ignore next */ {}), transform: (v) => (FUI_BADGE_SIZES.includes(v) ? v : 'md') });
39
+ variant = input('primary', { ...(ngDevMode ? { debugName: "variant" } : /* istanbul ignore next */ {}), transform: (v) => (FUI_BADGE_VARIANTS.includes(v) ? v : 'primary') });
40
+ ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
41
+ /** Validated custom color - returns null for invalid values to prevent CSS injection */
42
+ sanitizedColor = computed(() => {
43
+ const color = this.customColor();
44
+ if (!color)
45
+ return null;
46
+ if (!FuiBadgeComponent._SAFE_COLOR_PATTERN.test(color)) {
47
+ console.warn(`[FormaUI] Invalid badge color: "${color}"`);
48
+ return null;
49
+ }
50
+ return color;
51
+ }, ...(ngDevMode ? [{ debugName: "sanitizedColor" }] : /* istanbul ignore next */ []));
52
+ computedTextColor = computed(() => {
53
+ const color = this.sanitizedColor();
54
+ if (!color)
55
+ return null;
56
+ const luminance = this.getRelativeLuminance(color);
57
+ return luminance < 0.5 ? '#ffffff' : '#000000';
58
+ }, ...(ngDevMode ? [{ debugName: "computedTextColor" }] : /* istanbul ignore next */ []));
59
+ computedStyles = computed(() => {
60
+ const color = this.sanitizedColor();
61
+ if (!color)
62
+ return {};
63
+ return {
64
+ 'background-color': color,
65
+ color: this.computedTextColor() ?? '#000000',
66
+ };
67
+ }, ...(ngDevMode ? [{ debugName: "computedStyles" }] : /* istanbul ignore next */ []));
68
+ computedClasses = computed(() => {
69
+ const effectiveVariant = this.sanitizedColor() ? 'custom' : this.variant();
70
+ const classes = ['fui-badge', `fui-badge--${effectiveVariant}`, `fui-badge--${this.size()}`];
71
+ if (this.icon()) {
72
+ classes.push('fui-badge--with-icon');
73
+ }
74
+ return classes.join(' ');
75
+ }, ...(ngDevMode ? [{ debugName: "computedClasses" }] : /* istanbul ignore next */ []));
76
+ iconSize = computed(() => {
77
+ const size = this.size();
78
+ if (size === 'lg')
79
+ return 'md';
80
+ return 'sm';
81
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
82
+ getRelativeLuminance(hex) {
83
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
84
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
85
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
86
+ const linearize = (channel) => channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
87
+ return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);
88
+ }
89
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
90
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiBadgeComponent, isStandalone: true, selector: "fui-badge", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, customColor: { classPropertyName: "customColor", publicName: "customColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class": "computedClasses()", "style": "computedStyles()", "attr.aria-label": "ariaLabel() || null" } }, ngImport: i0, template: "<div class=\"fui-badge__content\">\n @if (icon()) {\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\n }\n <span class=\"fui-badge__label\">{{ label() }}</span>\n</div>\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)}:host.fui-badge{--fui-badge-bg: transparent;--fui-badge-color: inherit;--fui-badge-font-size: var(--fui-font-size-01);--fui-badge-font-weight: var(--fui-font-weight-medium);--fui-badge-border-radius: var(--fui-border-radius-pill);--fui-badge-gap: var(--fui-spacing-02);--fui-badge-height-sm: 1.25rem;--fui-badge-height-md: 1.5rem;--fui-badge-height-lg: 2rem;contain:content;display:inline-flex;align-items:center;justify-content:center;font-family:var(--fui-font-family-sans);font-size:var(--fui-badge-font-size);font-weight:var(--fui-badge-font-weight);border-radius:var(--fui-badge-border-radius);background-color:var(--fui-badge-bg);color:var(--fui-badge-color);white-space:nowrap;transition:all var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}:host.fui-badge .fui-badge__content{display:flex;align-items:center;gap:var(--fui-badge-gap)}:host.fui-badge .fui-badge__label{line-height:1}:host.fui-badge .fui-badge__icon{display:inline-flex;align-items:center;justify-content:center}:host.fui-badge--sm{height:var(--fui-badge-height-sm);padding:0 var(--fui-spacing-03);font-size:var(--fui-font-size-01)}:host.fui-badge--md{height:var(--fui-badge-height-md);padding:0 var(--fui-spacing-04);font-size:var(--fui-font-size-02)}:host.fui-badge--lg{height:var(--fui-badge-height-lg);padding:0 var(--fui-spacing-05);font-size:var(--fui-font-size-03)}:host.fui-badge--primary{--fui-badge-bg: var(--fui-primary-20);--fui-badge-color: var(--fui-primary)}:host.fui-badge--secondary{--fui-badge-bg: var(--fui-secondary-20);--fui-badge-color: var(--fui-secondary-80)}:host.fui-badge--success{--fui-badge-bg: var(--fui-success-20);--fui-badge-color: var(--fui-success-80)}:host.fui-badge--info{--fui-badge-bg: var(--fui-info-20);--fui-badge-color: var(--fui-info-80)}:host.fui-badge--warning{--fui-badge-bg: var(--fui-warning-20);--fui-badge-color: var(--fui-warning-80)}:host.fui-badge--error{--fui-badge-bg: var(--fui-danger-20);--fui-badge-color: var(--fui-danger-80)}:host.fui-badge--custom{--fui-badge-bg: transparent;--fui-badge-color: inherit}@media(prefers-reduced-motion:reduce){:host.fui-badge{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
91
+ }
92
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBadgeComponent, decorators: [{
93
+ type: Component,
94
+ args: [{ selector: 'fui-badge', standalone: true, imports: [FuiIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
95
+ '[class]': 'computedClasses()',
96
+ '[style]': 'computedStyles()',
97
+ role: 'status',
98
+ '[attr.aria-label]': 'ariaLabel() || null',
99
+ }, template: "<div class=\"fui-badge__content\">\n @if (icon()) {\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\n }\n <span class=\"fui-badge__label\">{{ label() }}</span>\n</div>\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)}:host.fui-badge{--fui-badge-bg: transparent;--fui-badge-color: inherit;--fui-badge-font-size: var(--fui-font-size-01);--fui-badge-font-weight: var(--fui-font-weight-medium);--fui-badge-border-radius: var(--fui-border-radius-pill);--fui-badge-gap: var(--fui-spacing-02);--fui-badge-height-sm: 1.25rem;--fui-badge-height-md: 1.5rem;--fui-badge-height-lg: 2rem;contain:content;display:inline-flex;align-items:center;justify-content:center;font-family:var(--fui-font-family-sans);font-size:var(--fui-badge-font-size);font-weight:var(--fui-badge-font-weight);border-radius:var(--fui-badge-border-radius);background-color:var(--fui-badge-bg);color:var(--fui-badge-color);white-space:nowrap;transition:all var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}:host.fui-badge .fui-badge__content{display:flex;align-items:center;gap:var(--fui-badge-gap)}:host.fui-badge .fui-badge__label{line-height:1}:host.fui-badge .fui-badge__icon{display:inline-flex;align-items:center;justify-content:center}:host.fui-badge--sm{height:var(--fui-badge-height-sm);padding:0 var(--fui-spacing-03);font-size:var(--fui-font-size-01)}:host.fui-badge--md{height:var(--fui-badge-height-md);padding:0 var(--fui-spacing-04);font-size:var(--fui-font-size-02)}:host.fui-badge--lg{height:var(--fui-badge-height-lg);padding:0 var(--fui-spacing-05);font-size:var(--fui-font-size-03)}:host.fui-badge--primary{--fui-badge-bg: var(--fui-primary-20);--fui-badge-color: var(--fui-primary)}:host.fui-badge--secondary{--fui-badge-bg: var(--fui-secondary-20);--fui-badge-color: var(--fui-secondary-80)}:host.fui-badge--success{--fui-badge-bg: var(--fui-success-20);--fui-badge-color: var(--fui-success-80)}:host.fui-badge--info{--fui-badge-bg: var(--fui-info-20);--fui-badge-color: var(--fui-info-80)}:host.fui-badge--warning{--fui-badge-bg: var(--fui-warning-20);--fui-badge-color: var(--fui-warning-80)}:host.fui-badge--error{--fui-badge-bg: var(--fui-danger-20);--fui-badge-color: var(--fui-danger-80)}:host.fui-badge--custom{--fui-badge-bg: transparent;--fui-badge-color: inherit}@media(prefers-reduced-motion:reduce){:host.fui-badge{transition:none}}\n"] }]
100
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], customColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "customColor", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
101
+
102
+ /**
103
+ * Generated bundle index. Do not edit.
104
+ */
105
+
106
+ export { FUI_BADGE_SIZES, FUI_BADGE_VARIANTS, FuiBadgeComponent };
107
+ //# sourceMappingURL=raintonic-formaui-components-badge.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raintonic-formaui-components-badge.mjs","sources":["../../../lib/components/badge/badge.types.ts","../../../lib/components/badge/badge.component.ts","../../../lib/components/badge/badge.component.html","../../../lib/components/badge/raintonic-formaui-components-badge.ts"],"sourcesContent":["export type FuiBadgeSize = 'sm' | 'md' | 'lg';\n\nexport type FuiBadgeVariant = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'custom';\n\nexport const FUI_BADGE_SIZES: readonly FuiBadgeSize[] = ['sm', 'md', 'lg'] as const;\n\nexport const FUI_BADGE_VARIANTS: readonly FuiBadgeVariant[] = [\n 'primary',\n 'secondary',\n 'success',\n 'info',\n 'warning',\n 'error',\n 'custom',\n] as const;\n","import { ChangeDetectionStrategy, Component, computed, input, Signal } from '@angular/core';\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\nimport { FuiBadgeSize, FuiBadgeVariant, FUI_BADGE_SIZES, FUI_BADGE_VARIANTS } from './badge.types';\n\n/**\n * @component FuiBadgeComponent\n * @selector fui-badge\n * @description Displays a small label badge with optional icon and color variants.\n * Supports custom colors with automatic text contrast calculation.\n *\n * @input label - (required) Text content of the badge.\n * @input icon - Optional Phosphor icon name displayed before the label.\n * @input customColor - Optional hex color that overrides the variant palette.\n * @input size - Badge size: 'sm' | 'md' | 'lg'. Default 'md'.\n * @input variant - Color variant: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'. Default 'primary'.\n * @input ariaLabel - Accessible label override for screen readers.\n *\n * @example\n * <fui-badge label=\"Active\" variant=\"success\" icon=\"check-circle\"></fui-badge>\n */\n@Component({\n selector: 'fui-badge',\n standalone: true,\n imports: [FuiIconComponent],\n templateUrl: './badge.component.html',\n styleUrls: ['./badge.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'computedClasses()',\n '[style]': 'computedStyles()',\n role: 'status',\n '[attr.aria-label]': 'ariaLabel() || null',\n },\n})\nexport class FuiBadgeComponent {\n /** Pattern allowing hex, rgb/rgba, hsl/hsla, and CSS named colors */\n private static readonly _SAFE_COLOR_PATTERN = /^(#[0-9a-fA-F]{3,8}|(?:rgb|hsl)a?\\([^)]+\\)|[a-zA-Z]+)$/;\n\n readonly label = input.required<string>();\n\n readonly icon = input<string | null>(null);\n\n readonly customColor = input<string | null>(null);\n\n readonly size = input<FuiBadgeSize, FuiBadgeSize | string>('md', {\n transform: (v) => ((FUI_BADGE_SIZES as readonly string[]).includes(v) ? (v as FuiBadgeSize) : 'md'),\n });\n\n readonly variant = input<FuiBadgeVariant, FuiBadgeVariant | string>('primary', {\n transform: (v) => ((FUI_BADGE_VARIANTS as readonly string[]).includes(v) ? (v as FuiBadgeVariant) : 'primary'),\n });\n\n readonly ariaLabel = input<string | null>(null);\n\n /** Validated custom color - returns null for invalid values to prevent CSS injection */\n readonly sanitizedColor: Signal<string | null> = computed(() => {\n const color = this.customColor();\n if (!color) return null;\n if (!FuiBadgeComponent._SAFE_COLOR_PATTERN.test(color)) {\n console.warn(`[FormaUI] Invalid badge color: \"${color}\"`);\n return null;\n }\n return color;\n });\n\n readonly computedTextColor: Signal<string | null> = computed(() => {\n const color = this.sanitizedColor();\n if (!color) return null;\n const luminance = this.getRelativeLuminance(color);\n return luminance < 0.5 ? '#ffffff' : '#000000';\n });\n\n readonly computedStyles = computed(() => {\n const color = this.sanitizedColor();\n if (!color) return {} as Record<string, string>;\n return {\n 'background-color': color,\n color: this.computedTextColor() ?? '#000000',\n } as Record<string, string>;\n });\n\n readonly computedClasses: Signal<string> = computed(() => {\n const effectiveVariant = this.sanitizedColor() ? 'custom' : this.variant();\n const classes: string[] = ['fui-badge', `fui-badge--${effectiveVariant}`, `fui-badge--${this.size()}`];\n\n if (this.icon()) {\n classes.push('fui-badge--with-icon');\n }\n\n return classes.join(' ');\n });\n\n readonly iconSize: Signal<'sm' | 'md' | 'lg'> = computed(() => {\n const size = this.size();\n if (size === 'lg') return 'md';\n return 'sm';\n });\n\n private getRelativeLuminance(hex: string): number {\n const r = parseInt(hex.slice(1, 3), 16) / 255;\n const g = parseInt(hex.slice(3, 5), 16) / 255;\n const b = parseInt(hex.slice(5, 7), 16) / 255;\n\n const linearize = (channel: number): number =>\n channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\n\n return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);\n }\n}\n","<div class=\"fui-badge__content\">\n @if (icon()) {\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\n }\n <span class=\"fui-badge__label\">{{ label() }}</span>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, signal, computed, HostListener, Component } from '@angular/core';
3
+ import { FuiIconComponent } from '@raintonic/formaui/components/icon';
4
+ import { FuiTooltipDirective } from '@raintonic/formaui/components/tooltip';
5
+
6
+ /**
7
+ * @component FuiBigMenuComponent
8
+ * @selector fui-big-menu
9
+ * @description A two-level navigation mega-menu. The primary column displays icon-based
10
+ * main menu items; hovering over or selecting a main item reveals a secondary flyout
11
+ * panel listing its children. Designed for application-level navigation alongside
12
+ * `fui-toolbar` and `fui-sidebar`.
13
+ *
14
+ * @input menu - (required) Array of `BigMenuItem` objects defining the menu structure
15
+ *
16
+ * @output itemMenuClick - Emits `{ item: BigMenuChild; event: MouseEvent }` when a child item is clicked
17
+ *
18
+ * @cssvar --fui-big-menu-width - Width of the primary icon column (default: 90px)
19
+ * @cssvar --fui-big-menu-bg - Background color of both menu panels
20
+ * @cssvar --fui-big-menu-border-color - Border color between panels and edge
21
+ * @cssvar --fui-big-menu-item-size - Width and height of primary menu item icons
22
+ * @cssvar --fui-big-menu-item-border-radius - Border radius of primary item icons
23
+ * @cssvar --fui-big-menu-secondary-width - Width of the secondary flyout panel (default: 228px)
24
+ * @cssvar --fui-big-menu-secondary-item-height - Height of each child item row
25
+ *
26
+ * @example
27
+ * <fui-big-menu [menu]="menuItems" (itemMenuClick)="onItemClick($event)"></fui-big-menu>
28
+ */
29
+ class FuiBigMenuComponent {
30
+ menu = input.required(...(ngDevMode ? [{ debugName: "menu" }] : /* istanbul ignore next */ []));
31
+ itemMenuClick = output();
32
+ selectedMainVoice = signal(null, ...(ngDevMode ? [{ debugName: "selectedMainVoice" }] : /* istanbul ignore next */ []));
33
+ selectedMainVoiceId = computed(() => this.selectedMainVoice()?.id, ...(ngDevMode ? [{ debugName: "selectedMainVoiceId" }] : /* istanbul ignore next */ []));
34
+ showSecondaryMenu = signal(false, ...(ngDevMode ? [{ debugName: "showSecondaryMenu" }] : /* istanbul ignore next */ []));
35
+ ngOnInit() {
36
+ this.selectedMainVoice.set(this.menu()[0] ?? null);
37
+ }
38
+ selectMainVoice(voice) {
39
+ if (voice.id !== this.selectedMainVoiceId()) {
40
+ this.selectedMainVoice.set(voice);
41
+ }
42
+ }
43
+ onMouseOver() {
44
+ this.showSecondaryMenu.set(true);
45
+ }
46
+ onMouseLeave() {
47
+ this.showSecondaryMenu.set(false);
48
+ }
49
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBigMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
50
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiBigMenuComponent, isStandalone: true, selector: "fui-big-menu", inputs: { menu: { classPropertyName: "menu", publicName: "menu", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { itemMenuClick: "itemMenuClick" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseleave": "onMouseLeave()" } }, ngImport: i0, template: "<nav class=\"fui-big-menu\" role=\"navigation\" aria-label=\"Main menu\">\n <ng-content select=\"[top-content]\"></ng-content>\n\n <ul class=\"fui-big-menu__list\" role=\"menubar\" aria-label=\"Menu categories\">\n @for (item of menu(); track $index) {\n <li role=\"none\">\n <button\n role=\"menuitem\"\n type=\"button\"\n (click)=\"selectMainVoice(item)\"\n [class.fui-big-menu__item--active]=\"item.id === selectedMainVoiceId()\"\n [attr.aria-label]=\"item.label\"\n [attr.aria-current]=\"item.id === selectedMainVoiceId() ? 'true' : null\"\n [fuiTooltip]=\"item.label\"\n fuiTooltipTrigger=\"hover\"\n fuiTooltipPosition=\"right\"\n fuiTooltipSize=\"sm\"\n >\n <fui-icon [name]=\"item.icon\" size=\"md\" aria-hidden=\"true\"></fui-icon>\n </button>\n </li>\n }\n </ul>\n\n <div class=\"fui-grow\"></div>\n <ng-content select=\"[bottom-content]\"></ng-content>\n</nav>\n\n<div\n class=\"fui-big-menu__secondary-menu\"\n [class.fui-big-menu__secondary-menu__active]=\"showSecondaryMenu()\"\n role=\"menu\"\n [attr.aria-label]=\"selectedMainVoice()?.label\"\n>\n <h2 class=\"fui-text-md fui-font-medium fui-text-color-primary\" id=\"fui-big-menu-secondary-heading\">\n {{ selectedMainVoice()?.label }}\n </h2>\n\n <ul class=\"fui-big-menu__secondary-menu-list\" role=\"menu\" aria-labelledby=\"fui-big-menu-secondary-heading\">\n @for (item of selectedMainVoice()?.children; track $index) {\n <li role=\"none\">\n <button\n role=\"menuitem\"\n type=\"button\"\n class=\"fui-big-menu__secondary-menu-item\"\n (click)=\"itemMenuClick.emit({ item, event: $event })\"\n [class.fui-big-menu__secondary-menu-item--active]=\"item.isActive ?? false\"\n [attr.aria-current]=\"item.isActive ? 'page' : null\"\n >\n <fui-icon [name]=\"item.icon\" size=\"sm\" aria-hidden=\"true\"></fui-icon>\n <span class=\"fui-text-sm\">{{ item.label }}</span>\n <span class=\"fui-grow\"></span>\n </button>\n </li>\n }\n </ul>\n</div>\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)}:host{--fui-big-menu-width: 90px;--fui-big-menu-bg: var(--fui-surface-00);--fui-big-menu-border-color: var(--fui-border-color);--fui-big-menu-item-size: 48px;--fui-big-menu-item-border-radius: var(--fui-border-radius-sm);--fui-big-menu-secondary-width: 228px;--fui-big-menu-secondary-item-height: 32px;display:flex;width:var(--fui-big-menu-width);background-color:var(--fui-big-menu-bg);border-right:1px solid var(--fui-big-menu-border-color);position:fixed;top:0;left:0;height:100vh;padding:var(--fui-spacing-04);align-items:center;flex-direction:column;z-index:var(--fui-z-fixed)}.fui-big-menu__list{display:flex;flex-direction:column;gap:var(--fui-spacing-04)}.fui-big-menu__list li{list-style:none}.fui-big-menu__list li button{width:var(--fui-big-menu-item-size);height:var(--fui-big-menu-item-size);display:flex;align-items:center;justify-content:center;border-radius:var(--fui-big-menu-item-border-radius);color:var(--fui-text-secondary);transition:all var(--fui-duration-moderate-01) var(--fui-ease-standard) 0ms}.fui-big-menu__list li button:hover{color:var(--fui-primary);background-color:var(--fui-primary-20)}.fui-big-menu__list li button.fui-big-menu__item--active{background-color:var(--fui-primary);color:var(--fui-primary-text-color);box-shadow:0 2px 14px 0 var(--fui-primary)}.fui-big-menu__secondary-menu{width:var(--fui-big-menu-secondary-width);height:100vh;position:fixed;top:0;left:var(--fui-big-menu-width);z-index:-1;background-color:var(--fui-big-menu-bg);display:block;border-right:1px solid var(--fui-big-menu-border-color);transform:translate(-100%);padding:var(--fui-spacing-04);transition:all var(--fui-duration-moderate-01) var(--fui-ease-standard) 0ms}.fui-big-menu__secondary-menu h2{padding:var(--fui-spacing-04)}.fui-big-menu__secondary-menu__active{transform:translate(0)}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list{display:flex;flex-direction:column;gap:var(--fui-spacing-02);margin-top:var(--fui-spacing-04)}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li{list-style:none}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item{display:flex;align-items:center;gap:var(--fui-spacing-04);width:100%;border-radius:var(--fui-border-radius-sm);padding:var(--fui-spacing-04);height:var(--fui-big-menu-secondary-item-height);color:var(--fui-text-secondary);transition:all var(--fui-duration-moderate-01) var(--fui-ease-standard) 0ms}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item:hover:not(.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item--active){color:var(--fui-text-primary);background-color:var(--fui-surface-02)}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item--active{color:var(--fui-primary);background-color:var(--fui-primary-20)}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "directive", type: FuiTooltipDirective, selector: "[fuiTooltip]", inputs: ["fuiTooltip", "fuiTooltipPosition", "fuiTooltipSize", "fuiTooltipTrigger", "fuiTooltipShowDelay", "fuiTooltipHideDelay", "fuiTooltipDisabled", "fuiTooltipMaxWidth", "fuiTooltipOffset", "fuiTooltipArrow", "fuiTooltipShow"] }] });
51
+ }
52
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBigMenuComponent, decorators: [{
53
+ type: Component,
54
+ args: [{ selector: 'fui-big-menu', imports: [FuiIconComponent, FuiTooltipDirective], template: "<nav class=\"fui-big-menu\" role=\"navigation\" aria-label=\"Main menu\">\n <ng-content select=\"[top-content]\"></ng-content>\n\n <ul class=\"fui-big-menu__list\" role=\"menubar\" aria-label=\"Menu categories\">\n @for (item of menu(); track $index) {\n <li role=\"none\">\n <button\n role=\"menuitem\"\n type=\"button\"\n (click)=\"selectMainVoice(item)\"\n [class.fui-big-menu__item--active]=\"item.id === selectedMainVoiceId()\"\n [attr.aria-label]=\"item.label\"\n [attr.aria-current]=\"item.id === selectedMainVoiceId() ? 'true' : null\"\n [fuiTooltip]=\"item.label\"\n fuiTooltipTrigger=\"hover\"\n fuiTooltipPosition=\"right\"\n fuiTooltipSize=\"sm\"\n >\n <fui-icon [name]=\"item.icon\" size=\"md\" aria-hidden=\"true\"></fui-icon>\n </button>\n </li>\n }\n </ul>\n\n <div class=\"fui-grow\"></div>\n <ng-content select=\"[bottom-content]\"></ng-content>\n</nav>\n\n<div\n class=\"fui-big-menu__secondary-menu\"\n [class.fui-big-menu__secondary-menu__active]=\"showSecondaryMenu()\"\n role=\"menu\"\n [attr.aria-label]=\"selectedMainVoice()?.label\"\n>\n <h2 class=\"fui-text-md fui-font-medium fui-text-color-primary\" id=\"fui-big-menu-secondary-heading\">\n {{ selectedMainVoice()?.label }}\n </h2>\n\n <ul class=\"fui-big-menu__secondary-menu-list\" role=\"menu\" aria-labelledby=\"fui-big-menu-secondary-heading\">\n @for (item of selectedMainVoice()?.children; track $index) {\n <li role=\"none\">\n <button\n role=\"menuitem\"\n type=\"button\"\n class=\"fui-big-menu__secondary-menu-item\"\n (click)=\"itemMenuClick.emit({ item, event: $event })\"\n [class.fui-big-menu__secondary-menu-item--active]=\"item.isActive ?? false\"\n [attr.aria-current]=\"item.isActive ? 'page' : null\"\n >\n <fui-icon [name]=\"item.icon\" size=\"sm\" aria-hidden=\"true\"></fui-icon>\n <span class=\"fui-text-sm\">{{ item.label }}</span>\n <span class=\"fui-grow\"></span>\n </button>\n </li>\n }\n </ul>\n</div>\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)}:host{--fui-big-menu-width: 90px;--fui-big-menu-bg: var(--fui-surface-00);--fui-big-menu-border-color: var(--fui-border-color);--fui-big-menu-item-size: 48px;--fui-big-menu-item-border-radius: var(--fui-border-radius-sm);--fui-big-menu-secondary-width: 228px;--fui-big-menu-secondary-item-height: 32px;display:flex;width:var(--fui-big-menu-width);background-color:var(--fui-big-menu-bg);border-right:1px solid var(--fui-big-menu-border-color);position:fixed;top:0;left:0;height:100vh;padding:var(--fui-spacing-04);align-items:center;flex-direction:column;z-index:var(--fui-z-fixed)}.fui-big-menu__list{display:flex;flex-direction:column;gap:var(--fui-spacing-04)}.fui-big-menu__list li{list-style:none}.fui-big-menu__list li button{width:var(--fui-big-menu-item-size);height:var(--fui-big-menu-item-size);display:flex;align-items:center;justify-content:center;border-radius:var(--fui-big-menu-item-border-radius);color:var(--fui-text-secondary);transition:all var(--fui-duration-moderate-01) var(--fui-ease-standard) 0ms}.fui-big-menu__list li button:hover{color:var(--fui-primary);background-color:var(--fui-primary-20)}.fui-big-menu__list li button.fui-big-menu__item--active{background-color:var(--fui-primary);color:var(--fui-primary-text-color);box-shadow:0 2px 14px 0 var(--fui-primary)}.fui-big-menu__secondary-menu{width:var(--fui-big-menu-secondary-width);height:100vh;position:fixed;top:0;left:var(--fui-big-menu-width);z-index:-1;background-color:var(--fui-big-menu-bg);display:block;border-right:1px solid var(--fui-big-menu-border-color);transform:translate(-100%);padding:var(--fui-spacing-04);transition:all var(--fui-duration-moderate-01) var(--fui-ease-standard) 0ms}.fui-big-menu__secondary-menu h2{padding:var(--fui-spacing-04)}.fui-big-menu__secondary-menu__active{transform:translate(0)}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list{display:flex;flex-direction:column;gap:var(--fui-spacing-02);margin-top:var(--fui-spacing-04)}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li{list-style:none}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item{display:flex;align-items:center;gap:var(--fui-spacing-04);width:100%;border-radius:var(--fui-border-radius-sm);padding:var(--fui-spacing-04);height:var(--fui-big-menu-secondary-item-height);color:var(--fui-text-secondary);transition:all var(--fui-duration-moderate-01) var(--fui-ease-standard) 0ms}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item:hover:not(.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item--active){color:var(--fui-text-primary);background-color:var(--fui-surface-02)}.fui-big-menu__secondary-menu .fui-big-menu__secondary-menu-list li .fui-big-menu__secondary-menu-item--active{color:var(--fui-primary);background-color:var(--fui-primary-20)}\n"] }]
55
+ }], propDecorators: { menu: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu", required: true }] }], itemMenuClick: [{ type: i0.Output, args: ["itemMenuClick"] }], onMouseOver: [{
56
+ type: HostListener,
57
+ args: ['mouseover']
58
+ }], onMouseLeave: [{
59
+ type: HostListener,
60
+ args: ['mouseleave']
61
+ }] } });
62
+
63
+ /**
64
+ * Generated bundle index. Do not edit.
65
+ */
66
+
67
+ export { FuiBigMenuComponent };
68
+ //# sourceMappingURL=raintonic-formaui-components-big-menu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raintonic-formaui-components-big-menu.mjs","sources":["../../../lib/components/big-menu/big-menu.component.ts","../../../lib/components/big-menu/big-menu.component.html","../../../lib/components/big-menu/raintonic-formaui-components-big-menu.ts"],"sourcesContent":["import { Component, computed, HostListener, input, OnInit, output, signal } from '@angular/core';\nimport { BigMenuChild, BigMenuItem } from './big-menu-item.interface';\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\nimport { FuiTooltipDirective } from '@raintonic/formaui/components/tooltip';\n\n/**\n * @component FuiBigMenuComponent\n * @selector fui-big-menu\n * @description A two-level navigation mega-menu. The primary column displays icon-based\n * main menu items; hovering over or selecting a main item reveals a secondary flyout\n * panel listing its children. Designed for application-level navigation alongside\n * `fui-toolbar` and `fui-sidebar`.\n *\n * @input menu - (required) Array of `BigMenuItem` objects defining the menu structure\n *\n * @output itemMenuClick - Emits `{ item: BigMenuChild; event: MouseEvent }` when a child item is clicked\n *\n * @cssvar --fui-big-menu-width - Width of the primary icon column (default: 90px)\n * @cssvar --fui-big-menu-bg - Background color of both menu panels\n * @cssvar --fui-big-menu-border-color - Border color between panels and edge\n * @cssvar --fui-big-menu-item-size - Width and height of primary menu item icons\n * @cssvar --fui-big-menu-item-border-radius - Border radius of primary item icons\n * @cssvar --fui-big-menu-secondary-width - Width of the secondary flyout panel (default: 228px)\n * @cssvar --fui-big-menu-secondary-item-height - Height of each child item row\n *\n * @example\n * <fui-big-menu [menu]=\"menuItems\" (itemMenuClick)=\"onItemClick($event)\"></fui-big-menu>\n */\n@Component({\n selector: 'fui-big-menu',\n imports: [FuiIconComponent, FuiTooltipDirective],\n templateUrl: './big-menu.component.html',\n styleUrl: './big-menu.component.scss',\n})\nexport class FuiBigMenuComponent implements OnInit {\n menu = input.required<BigMenuItem[]>();\n\n itemMenuClick = output<{ item: BigMenuChild; event: MouseEvent }>();\n selectedMainVoice = signal<BigMenuItem | null>(null);\n selectedMainVoiceId = computed(() => this.selectedMainVoice()?.id);\n showSecondaryMenu = signal(false);\n\n ngOnInit(): void {\n this.selectedMainVoice.set(this.menu()[0] ?? null);\n }\n\n selectMainVoice(voice: BigMenuItem): void {\n if (voice.id !== this.selectedMainVoiceId()) {\n this.selectedMainVoice.set(voice);\n }\n }\n\n @HostListener('mouseover')\n onMouseOver(): void {\n this.showSecondaryMenu.set(true);\n }\n\n @HostListener('mouseleave')\n onMouseLeave(): void {\n this.showSecondaryMenu.set(false);\n }\n}\n","<nav class=\"fui-big-menu\" role=\"navigation\" aria-label=\"Main menu\">\n <ng-content select=\"[top-content]\"></ng-content>\n\n <ul class=\"fui-big-menu__list\" role=\"menubar\" aria-label=\"Menu categories\">\n @for (item of menu(); track $index) {\n <li role=\"none\">\n <button\n role=\"menuitem\"\n type=\"button\"\n (click)=\"selectMainVoice(item)\"\n [class.fui-big-menu__item--active]=\"item.id === selectedMainVoiceId()\"\n [attr.aria-label]=\"item.label\"\n [attr.aria-current]=\"item.id === selectedMainVoiceId() ? 'true' : null\"\n [fuiTooltip]=\"item.label\"\n fuiTooltipTrigger=\"hover\"\n fuiTooltipPosition=\"right\"\n fuiTooltipSize=\"sm\"\n >\n <fui-icon [name]=\"item.icon\" size=\"md\" aria-hidden=\"true\"></fui-icon>\n </button>\n </li>\n }\n </ul>\n\n <div class=\"fui-grow\"></div>\n <ng-content select=\"[bottom-content]\"></ng-content>\n</nav>\n\n<div\n class=\"fui-big-menu__secondary-menu\"\n [class.fui-big-menu__secondary-menu__active]=\"showSecondaryMenu()\"\n role=\"menu\"\n [attr.aria-label]=\"selectedMainVoice()?.label\"\n>\n <h2 class=\"fui-text-md fui-font-medium fui-text-color-primary\" id=\"fui-big-menu-secondary-heading\">\n {{ selectedMainVoice()?.label }}\n </h2>\n\n <ul class=\"fui-big-menu__secondary-menu-list\" role=\"menu\" aria-labelledby=\"fui-big-menu-secondary-heading\">\n @for (item of selectedMainVoice()?.children; track $index) {\n <li role=\"none\">\n <button\n role=\"menuitem\"\n type=\"button\"\n class=\"fui-big-menu__secondary-menu-item\"\n (click)=\"itemMenuClick.emit({ item, event: $event })\"\n [class.fui-big-menu__secondary-menu-item--active]=\"item.isActive ?? false\"\n [attr.aria-current]=\"item.isActive ? 'page' : null\"\n >\n <fui-icon [name]=\"item.icon\" size=\"sm\" aria-hidden=\"true\"></fui-icon>\n <span class=\"fui-text-sm\">{{ item.label }}</span>\n <span class=\"fui-grow\"></span>\n </button>\n </li>\n }\n </ul>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;AAsBG;MAOU,mBAAmB,CAAA;AAC9B,IAAA,IAAI,GAAG,KAAK,CAAC,QAAQ,0EAAiB;IAEtC,aAAa,GAAG,MAAM,EAA6C;AACnE,IAAA,iBAAiB,GAAG,MAAM,CAAqB,IAAI,wFAAC;AACpD,IAAA,mBAAmB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,EAAE,EAAE,0FAAC;AAClE,IAAA,iBAAiB,GAAG,MAAM,CAAC,KAAK,wFAAC;IAEjC,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACpD;AAEA,IAAA,eAAe,CAAC,KAAkB,EAAA;QAChC,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,mBAAmB,EAAE,EAAE;AAC3C,YAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC;QACnC;IACF;IAGA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;IAClC;IAGA,YAAY,GAAA;AACV,QAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC;IACnC;uGA1BW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,WAAA,EAAA,eAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EClChC,woEAyDA,EAAA,MAAA,EAAA,CAAA,q6IAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED3BY,gBAAgB,gIAAE,mBAAmB,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,oBAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,qBAAA,EAAA,oBAAA,EAAA,oBAAA,EAAA,kBAAA,EAAA,iBAAA,EAAA,gBAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAIpC,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAN/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,EAAA,OAAA,EACf,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,EAAA,QAAA,EAAA,woEAAA,EAAA,MAAA,EAAA,CAAA,q6IAAA,CAAA,EAAA;;sBAsB/C,YAAY;uBAAC,WAAW;;sBAKxB,YAAY;uBAAC,YAAY;;;AEzD5B;;AAEG;;;;"}