@atomng/ui 1.0.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 (299) hide show
  1. package/README.md +401 -0
  2. package/atomng-ui.d.ts.map +1 -0
  3. package/atoms/atomng-ui-atoms.d.ts.map +1 -0
  4. package/atoms/avatar/avatar.component.d.ts +24 -0
  5. package/atoms/avatar/avatar.component.d.ts.map +1 -0
  6. package/atoms/avatar/index.d.ts +3 -0
  7. package/atoms/avatar/index.d.ts.map +1 -0
  8. package/atoms/badge/badge.component.d.ts +23 -0
  9. package/atoms/badge/badge.component.d.ts.map +1 -0
  10. package/atoms/badge/index.d.ts +3 -0
  11. package/atoms/badge/index.d.ts.map +1 -0
  12. package/atoms/button/button.component.d.ts +47 -0
  13. package/atoms/button/button.component.d.ts.map +1 -0
  14. package/atoms/button/index.d.ts +3 -0
  15. package/atoms/button/index.d.ts.map +1 -0
  16. package/atoms/checkbox/checkbox.component.d.ts +28 -0
  17. package/atoms/checkbox/checkbox.component.d.ts.map +1 -0
  18. package/atoms/checkbox/index.d.ts +2 -0
  19. package/atoms/checkbox/index.d.ts.map +1 -0
  20. package/atoms/chip/chip.component.d.ts +17 -0
  21. package/atoms/chip/chip.component.d.ts.map +1 -0
  22. package/atoms/chip/index.d.ts +2 -0
  23. package/atoms/chip/index.d.ts.map +1 -0
  24. package/atoms/index.d.ts +14 -0
  25. package/atoms/index.d.ts.map +1 -0
  26. package/atoms/kbd/index.d.ts +2 -0
  27. package/atoms/kbd/index.d.ts.map +1 -0
  28. package/atoms/kbd/kbd.component.d.ts +14 -0
  29. package/atoms/kbd/kbd.component.d.ts.map +1 -0
  30. package/atoms/link/index.d.ts +2 -0
  31. package/atoms/link/index.d.ts.map +1 -0
  32. package/atoms/link/link.component.d.ts +15 -0
  33. package/atoms/link/link.component.d.ts.map +1 -0
  34. package/atoms/progress/index.d.ts +3 -0
  35. package/atoms/progress/index.d.ts.map +1 -0
  36. package/atoms/progress/progress.component.d.ts +20 -0
  37. package/atoms/progress/progress.component.d.ts.map +1 -0
  38. package/atoms/separator/index.d.ts +2 -0
  39. package/atoms/separator/index.d.ts.map +1 -0
  40. package/atoms/separator/separator.component.d.ts +13 -0
  41. package/atoms/separator/separator.component.d.ts.map +1 -0
  42. package/atoms/skeleton/index.d.ts +2 -0
  43. package/atoms/skeleton/index.d.ts.map +1 -0
  44. package/atoms/skeleton/skeleton.component.d.ts +13 -0
  45. package/atoms/skeleton/skeleton.component.d.ts.map +1 -0
  46. package/atoms/slider/index.d.ts +2 -0
  47. package/atoms/slider/index.d.ts.map +1 -0
  48. package/atoms/slider/slider.component.d.ts +27 -0
  49. package/atoms/slider/slider.component.d.ts.map +1 -0
  50. package/atoms/switch/index.d.ts +2 -0
  51. package/atoms/switch/index.d.ts.map +1 -0
  52. package/atoms/switch/switch.component.d.ts +25 -0
  53. package/atoms/switch/switch.component.d.ts.map +1 -0
  54. package/atoms/tooltip/index.d.ts +2 -0
  55. package/atoms/tooltip/index.d.ts.map +1 -0
  56. package/atoms/tooltip/tooltip.component.d.ts +15 -0
  57. package/atoms/tooltip/tooltip.component.d.ts.map +1 -0
  58. package/fesm2022/atomng-ui-atoms.mjs +778 -0
  59. package/fesm2022/atomng-ui-atoms.mjs.map +1 -0
  60. package/fesm2022/atomng-ui-molecules.mjs +1590 -0
  61. package/fesm2022/atomng-ui-molecules.mjs.map +1 -0
  62. package/fesm2022/atomng-ui-organisms.mjs +1346 -0
  63. package/fesm2022/atomng-ui-organisms.mjs.map +1 -0
  64. package/fesm2022/atomng-ui-tokens.mjs +499 -0
  65. package/fesm2022/atomng-ui-tokens.mjs.map +1 -0
  66. package/fesm2022/atomng-ui.mjs +4184 -0
  67. package/fesm2022/atomng-ui.mjs.map +1 -0
  68. package/index.d.ts +5 -0
  69. package/index.d.ts.map +1 -0
  70. package/lib/atoms/avatar/avatar.component.d.ts +24 -0
  71. package/lib/atoms/avatar/avatar.component.d.ts.map +1 -0
  72. package/lib/atoms/avatar/index.d.ts +3 -0
  73. package/lib/atoms/avatar/index.d.ts.map +1 -0
  74. package/lib/atoms/badge/badge.component.d.ts +23 -0
  75. package/lib/atoms/badge/badge.component.d.ts.map +1 -0
  76. package/lib/atoms/badge/index.d.ts +3 -0
  77. package/lib/atoms/badge/index.d.ts.map +1 -0
  78. package/lib/atoms/button/button.component.d.ts +47 -0
  79. package/lib/atoms/button/button.component.d.ts.map +1 -0
  80. package/lib/atoms/button/index.d.ts +3 -0
  81. package/lib/atoms/button/index.d.ts.map +1 -0
  82. package/lib/atoms/checkbox/checkbox.component.d.ts +28 -0
  83. package/lib/atoms/checkbox/checkbox.component.d.ts.map +1 -0
  84. package/lib/atoms/checkbox/index.d.ts +2 -0
  85. package/lib/atoms/checkbox/index.d.ts.map +1 -0
  86. package/lib/atoms/chip/chip.component.d.ts +17 -0
  87. package/lib/atoms/chip/chip.component.d.ts.map +1 -0
  88. package/lib/atoms/chip/index.d.ts +2 -0
  89. package/lib/atoms/chip/index.d.ts.map +1 -0
  90. package/lib/atoms/index.d.ts +14 -0
  91. package/lib/atoms/index.d.ts.map +1 -0
  92. package/lib/atoms/kbd/index.d.ts +2 -0
  93. package/lib/atoms/kbd/index.d.ts.map +1 -0
  94. package/lib/atoms/kbd/kbd.component.d.ts +14 -0
  95. package/lib/atoms/kbd/kbd.component.d.ts.map +1 -0
  96. package/lib/atoms/link/index.d.ts +2 -0
  97. package/lib/atoms/link/index.d.ts.map +1 -0
  98. package/lib/atoms/link/link.component.d.ts +15 -0
  99. package/lib/atoms/link/link.component.d.ts.map +1 -0
  100. package/lib/atoms/progress/index.d.ts +3 -0
  101. package/lib/atoms/progress/index.d.ts.map +1 -0
  102. package/lib/atoms/progress/progress.component.d.ts +20 -0
  103. package/lib/atoms/progress/progress.component.d.ts.map +1 -0
  104. package/lib/atoms/separator/index.d.ts +2 -0
  105. package/lib/atoms/separator/index.d.ts.map +1 -0
  106. package/lib/atoms/separator/separator.component.d.ts +13 -0
  107. package/lib/atoms/separator/separator.component.d.ts.map +1 -0
  108. package/lib/atoms/skeleton/index.d.ts +2 -0
  109. package/lib/atoms/skeleton/index.d.ts.map +1 -0
  110. package/lib/atoms/skeleton/skeleton.component.d.ts +13 -0
  111. package/lib/atoms/skeleton/skeleton.component.d.ts.map +1 -0
  112. package/lib/atoms/slider/index.d.ts +2 -0
  113. package/lib/atoms/slider/index.d.ts.map +1 -0
  114. package/lib/atoms/slider/slider.component.d.ts +27 -0
  115. package/lib/atoms/slider/slider.component.d.ts.map +1 -0
  116. package/lib/atoms/switch/index.d.ts +2 -0
  117. package/lib/atoms/switch/index.d.ts.map +1 -0
  118. package/lib/atoms/switch/switch.component.d.ts +25 -0
  119. package/lib/atoms/switch/switch.component.d.ts.map +1 -0
  120. package/lib/atoms/tooltip/index.d.ts +2 -0
  121. package/lib/atoms/tooltip/index.d.ts.map +1 -0
  122. package/lib/atoms/tooltip/tooltip.component.d.ts +15 -0
  123. package/lib/atoms/tooltip/tooltip.component.d.ts.map +1 -0
  124. package/lib/molecules/alert/alert.component.d.ts +22 -0
  125. package/lib/molecules/alert/alert.component.d.ts.map +1 -0
  126. package/lib/molecules/alert/index.d.ts +2 -0
  127. package/lib/molecules/alert/index.d.ts.map +1 -0
  128. package/lib/molecules/avatar-group/avatar-group.component.d.ts +22 -0
  129. package/lib/molecules/avatar-group/avatar-group.component.d.ts.map +1 -0
  130. package/lib/molecules/avatar-group/index.d.ts +2 -0
  131. package/lib/molecules/avatar-group/index.d.ts.map +1 -0
  132. package/lib/molecules/breadcrumb/breadcrumb.component.d.ts +17 -0
  133. package/lib/molecules/breadcrumb/breadcrumb.component.d.ts.map +1 -0
  134. package/lib/molecules/breadcrumb/index.d.ts +2 -0
  135. package/lib/molecules/breadcrumb/index.d.ts.map +1 -0
  136. package/lib/molecules/button-group/button-group.component.d.ts +11 -0
  137. package/lib/molecules/button-group/button-group.component.d.ts.map +1 -0
  138. package/lib/molecules/button-group/index.d.ts +2 -0
  139. package/lib/molecules/button-group/index.d.ts.map +1 -0
  140. package/lib/molecules/form-field/form-field.component.d.ts +18 -0
  141. package/lib/molecules/form-field/form-field.component.d.ts.map +1 -0
  142. package/lib/molecules/form-field/index.d.ts +2 -0
  143. package/lib/molecules/form-field/index.d.ts.map +1 -0
  144. package/lib/molecules/index.d.ts +13 -0
  145. package/lib/molecules/index.d.ts.map +1 -0
  146. package/lib/molecules/input/index.d.ts +2 -0
  147. package/lib/molecules/input/index.d.ts.map +1 -0
  148. package/lib/molecules/input/input.component.d.ts +50 -0
  149. package/lib/molecules/input/input.component.d.ts.map +1 -0
  150. package/lib/molecules/pagination/index.d.ts +2 -0
  151. package/lib/molecules/pagination/index.d.ts.map +1 -0
  152. package/lib/molecules/pagination/pagination.component.d.ts +18 -0
  153. package/lib/molecules/pagination/pagination.component.d.ts.map +1 -0
  154. package/lib/molecules/select/index.d.ts +3 -0
  155. package/lib/molecules/select/index.d.ts.map +1 -0
  156. package/lib/molecules/select/select.component.d.ts +56 -0
  157. package/lib/molecules/select/select.component.d.ts.map +1 -0
  158. package/lib/molecules/select-search/index.d.ts +2 -0
  159. package/lib/molecules/select-search/index.d.ts.map +1 -0
  160. package/lib/molecules/select-search/select-search.component.d.ts +63 -0
  161. package/lib/molecules/select-search/select-search.component.d.ts.map +1 -0
  162. package/lib/molecules/tabs/index.d.ts +2 -0
  163. package/lib/molecules/tabs/index.d.ts.map +1 -0
  164. package/lib/molecules/tabs/tabs.component.d.ts +23 -0
  165. package/lib/molecules/tabs/tabs.component.d.ts.map +1 -0
  166. package/lib/molecules/textarea/index.d.ts +2 -0
  167. package/lib/molecules/textarea/index.d.ts.map +1 -0
  168. package/lib/molecules/textarea/textarea.component.d.ts +27 -0
  169. package/lib/molecules/textarea/textarea.component.d.ts.map +1 -0
  170. package/lib/molecules/toast/index.d.ts +2 -0
  171. package/lib/molecules/toast/index.d.ts.map +1 -0
  172. package/lib/molecules/toast/toast.component.d.ts +19 -0
  173. package/lib/molecules/toast/toast.component.d.ts.map +1 -0
  174. package/lib/organisms/accordion/accordion.component.d.ts +25 -0
  175. package/lib/organisms/accordion/accordion.component.d.ts.map +1 -0
  176. package/lib/organisms/card/card.component.d.ts +14 -0
  177. package/lib/organisms/card/card.component.d.ts.map +1 -0
  178. package/lib/organisms/dropdown-menu/dropdown-menu.component.d.ts +29 -0
  179. package/lib/organisms/dropdown-menu/dropdown-menu.component.d.ts.map +1 -0
  180. package/lib/organisms/index.d.ts +8 -0
  181. package/lib/organisms/index.d.ts.map +1 -0
  182. package/lib/organisms/modal/modal.component.d.ts +19 -0
  183. package/lib/organisms/modal/modal.component.d.ts.map +1 -0
  184. package/lib/organisms/navigation-menu/navigation-menu.component.d.ts +24 -0
  185. package/lib/organisms/navigation-menu/navigation-menu.component.d.ts.map +1 -0
  186. package/lib/organisms/sidebar/sidebar.component.d.ts +68 -0
  187. package/lib/organisms/sidebar/sidebar.component.d.ts.map +1 -0
  188. package/lib/organisms/table/index.d.ts +3 -0
  189. package/lib/organisms/table/index.d.ts.map +1 -0
  190. package/lib/organisms/table/table-cell.directive.d.ts +17 -0
  191. package/lib/organisms/table/table-cell.directive.d.ts.map +1 -0
  192. package/lib/organisms/table/table.component.d.ts +50 -0
  193. package/lib/organisms/table/table.component.d.ts.map +1 -0
  194. package/lib/tokens/index.d.ts +2 -0
  195. package/lib/tokens/index.d.ts.map +1 -0
  196. package/lib/tokens/theme/color-presets.d.ts +24 -0
  197. package/lib/tokens/theme/color-presets.d.ts.map +1 -0
  198. package/lib/tokens/theme/index.d.ts +6 -0
  199. package/lib/tokens/theme/index.d.ts.map +1 -0
  200. package/lib/tokens/theme/theme-picker.component.d.ts +11 -0
  201. package/lib/tokens/theme/theme-picker.component.d.ts.map +1 -0
  202. package/lib/tokens/theme/theme-toggle.component.d.ts +15 -0
  203. package/lib/tokens/theme/theme-toggle.component.d.ts.map +1 -0
  204. package/lib/tokens/theme/theme.provider.d.ts +4 -0
  205. package/lib/tokens/theme/theme.provider.d.ts.map +1 -0
  206. package/lib/tokens/theme/theme.service.d.ts +48 -0
  207. package/lib/tokens/theme/theme.service.d.ts.map +1 -0
  208. package/molecules/alert/alert.component.d.ts +22 -0
  209. package/molecules/alert/alert.component.d.ts.map +1 -0
  210. package/molecules/alert/index.d.ts +2 -0
  211. package/molecules/alert/index.d.ts.map +1 -0
  212. package/molecules/atomng-ui-molecules.d.ts.map +1 -0
  213. package/molecules/avatar-group/avatar-group.component.d.ts +22 -0
  214. package/molecules/avatar-group/avatar-group.component.d.ts.map +1 -0
  215. package/molecules/avatar-group/index.d.ts +2 -0
  216. package/molecules/avatar-group/index.d.ts.map +1 -0
  217. package/molecules/breadcrumb/breadcrumb.component.d.ts +17 -0
  218. package/molecules/breadcrumb/breadcrumb.component.d.ts.map +1 -0
  219. package/molecules/breadcrumb/index.d.ts +2 -0
  220. package/molecules/breadcrumb/index.d.ts.map +1 -0
  221. package/molecules/button-group/button-group.component.d.ts +11 -0
  222. package/molecules/button-group/button-group.component.d.ts.map +1 -0
  223. package/molecules/button-group/index.d.ts +2 -0
  224. package/molecules/button-group/index.d.ts.map +1 -0
  225. package/molecules/form-field/form-field.component.d.ts +18 -0
  226. package/molecules/form-field/form-field.component.d.ts.map +1 -0
  227. package/molecules/form-field/index.d.ts +2 -0
  228. package/molecules/form-field/index.d.ts.map +1 -0
  229. package/molecules/index.d.ts +13 -0
  230. package/molecules/index.d.ts.map +1 -0
  231. package/molecules/input/index.d.ts +2 -0
  232. package/molecules/input/index.d.ts.map +1 -0
  233. package/molecules/input/input.component.d.ts +50 -0
  234. package/molecules/input/input.component.d.ts.map +1 -0
  235. package/molecules/pagination/index.d.ts +2 -0
  236. package/molecules/pagination/index.d.ts.map +1 -0
  237. package/molecules/pagination/pagination.component.d.ts +18 -0
  238. package/molecules/pagination/pagination.component.d.ts.map +1 -0
  239. package/molecules/select/index.d.ts +3 -0
  240. package/molecules/select/index.d.ts.map +1 -0
  241. package/molecules/select/select.component.d.ts +56 -0
  242. package/molecules/select/select.component.d.ts.map +1 -0
  243. package/molecules/select-search/index.d.ts +2 -0
  244. package/molecules/select-search/index.d.ts.map +1 -0
  245. package/molecules/select-search/select-search.component.d.ts +63 -0
  246. package/molecules/select-search/select-search.component.d.ts.map +1 -0
  247. package/molecules/tabs/index.d.ts +2 -0
  248. package/molecules/tabs/index.d.ts.map +1 -0
  249. package/molecules/tabs/tabs.component.d.ts +23 -0
  250. package/molecules/tabs/tabs.component.d.ts.map +1 -0
  251. package/molecules/textarea/index.d.ts +2 -0
  252. package/molecules/textarea/index.d.ts.map +1 -0
  253. package/molecules/textarea/textarea.component.d.ts +27 -0
  254. package/molecules/textarea/textarea.component.d.ts.map +1 -0
  255. package/molecules/toast/index.d.ts +2 -0
  256. package/molecules/toast/index.d.ts.map +1 -0
  257. package/molecules/toast/toast.component.d.ts +19 -0
  258. package/molecules/toast/toast.component.d.ts.map +1 -0
  259. package/organisms/accordion/accordion.component.d.ts +25 -0
  260. package/organisms/accordion/accordion.component.d.ts.map +1 -0
  261. package/organisms/atomng-ui-organisms.d.ts.map +1 -0
  262. package/organisms/card/card.component.d.ts +14 -0
  263. package/organisms/card/card.component.d.ts.map +1 -0
  264. package/organisms/dropdown-menu/dropdown-menu.component.d.ts +29 -0
  265. package/organisms/dropdown-menu/dropdown-menu.component.d.ts.map +1 -0
  266. package/organisms/index.d.ts +8 -0
  267. package/organisms/index.d.ts.map +1 -0
  268. package/organisms/modal/modal.component.d.ts +19 -0
  269. package/organisms/modal/modal.component.d.ts.map +1 -0
  270. package/organisms/navigation-menu/navigation-menu.component.d.ts +24 -0
  271. package/organisms/navigation-menu/navigation-menu.component.d.ts.map +1 -0
  272. package/organisms/sidebar/sidebar.component.d.ts +68 -0
  273. package/organisms/sidebar/sidebar.component.d.ts.map +1 -0
  274. package/organisms/table/index.d.ts +3 -0
  275. package/organisms/table/index.d.ts.map +1 -0
  276. package/organisms/table/table-cell.directive.d.ts +17 -0
  277. package/organisms/table/table-cell.directive.d.ts.map +1 -0
  278. package/organisms/table/table.component.d.ts +50 -0
  279. package/organisms/table/table.component.d.ts.map +1 -0
  280. package/package.json +81 -0
  281. package/tokens/_colors.scss +150 -0
  282. package/tokens/_spacing.scss +98 -0
  283. package/tokens/_typography.scss +59 -0
  284. package/tokens/atomng-ui-tokens.d.ts.map +1 -0
  285. package/tokens/index.d.ts +2 -0
  286. package/tokens/index.d.ts.map +1 -0
  287. package/tokens/index.scss +8 -0
  288. package/tokens/theme/color-presets.d.ts +24 -0
  289. package/tokens/theme/color-presets.d.ts.map +1 -0
  290. package/tokens/theme/index.d.ts +6 -0
  291. package/tokens/theme/index.d.ts.map +1 -0
  292. package/tokens/theme/theme-picker.component.d.ts +11 -0
  293. package/tokens/theme/theme-picker.component.d.ts.map +1 -0
  294. package/tokens/theme/theme-toggle.component.d.ts +15 -0
  295. package/tokens/theme/theme-toggle.component.d.ts.map +1 -0
  296. package/tokens/theme/theme.provider.d.ts +4 -0
  297. package/tokens/theme/theme.provider.d.ts.map +1 -0
  298. package/tokens/theme/theme.service.d.ts +48 -0
  299. package/tokens/theme/theme.service.d.ts.map +1 -0
@@ -0,0 +1,4184 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, PLATFORM_ID, signal, computed, effect, Injectable, makeEnvironmentProviders, APP_INITIALIZER, output, ChangeDetectionStrategy, Component, input, model, forwardRef, HostListener, ViewChild, Input, Directive, ContentChildren } from '@angular/core';
3
+ import * as i1$2 from '@angular/common';
4
+ import { isPlatformBrowser, CommonModule, NgTemplateOutlet } from '@angular/common';
5
+ import * as i1$1 from '@angular/forms';
6
+ import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
7
+ import * as i1 from '@angular/router';
8
+ import { RouterModule, Router, NavigationEnd, RouterLink, RouterLinkActive } from '@angular/router';
9
+ import { AvatarComponent as AvatarComponent$1 } from '@atomng/ui/atoms';
10
+ import { trigger, transition, style, animate, state } from '@angular/animations';
11
+ import { toSignal } from '@angular/core/rxjs-interop';
12
+ import { filter, map, startWith } from 'rxjs';
13
+ import * as i1$3 from 'lucide-angular';
14
+ import { MessageSquare, Contact, LogOut, CircleQuestionMark, LayoutDashboard, House, icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS } from 'lucide-angular';
15
+
16
+ // ── Color presets ─────────────────────────────────────────────────────────────
17
+ // Full 11-step palettes (50→950).
18
+ // Colors sourced from Tailwind CSS v3 palette — production-grade, accessible.
19
+ // Each palette is keyed by a human-readable preset name.
20
+ // ── Palette definitions ───────────────────────────────────────────────────────
21
+ const COLOR_PRESETS = {
22
+ green: {
23
+ name: 'green', label: 'Green', swatch: '#22c55e',
24
+ palette: {
25
+ 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac',
26
+ 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d',
27
+ 800: '#166534', 900: '#14532d', 950: '#052e16',
28
+ },
29
+ },
30
+ emerald: {
31
+ name: 'emerald', label: 'Emerald', swatch: '#10b981',
32
+ palette: {
33
+ 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7',
34
+ 400: '#34d399', 500: '#10b981', 600: '#059669', 700: '#047857',
35
+ 800: '#065f46', 900: '#064e3b', 950: '#022c22',
36
+ },
37
+ },
38
+ teal: {
39
+ name: 'teal', label: 'Teal', swatch: '#14b8a6',
40
+ palette: {
41
+ 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4',
42
+ 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e',
43
+ 800: '#115e59', 900: '#134e4a', 950: '#042f2e',
44
+ },
45
+ },
46
+ cyan: {
47
+ name: 'cyan', label: 'Cyan', swatch: '#06b6d4',
48
+ palette: {
49
+ 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9',
50
+ 400: '#22d3ee', 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490',
51
+ 800: '#155e75', 900: '#164e63', 950: '#083344',
52
+ },
53
+ },
54
+ sky: {
55
+ name: 'sky', label: 'Sky', swatch: '#0ea5e9',
56
+ palette: {
57
+ 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc',
58
+ 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1',
59
+ 800: '#075985', 900: '#0c4a6e', 950: '#082f49',
60
+ },
61
+ },
62
+ blue: {
63
+ name: 'blue', label: 'Blue', swatch: '#3b82f6',
64
+ palette: {
65
+ 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd',
66
+ 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8',
67
+ 800: '#1e40af', 900: '#1e3a8a', 950: '#172554',
68
+ },
69
+ },
70
+ indigo: {
71
+ name: 'indigo', label: 'Indigo', swatch: '#6366f1',
72
+ palette: {
73
+ 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc',
74
+ 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca',
75
+ 800: '#3730a3', 900: '#312e81', 950: '#1e1b4b',
76
+ },
77
+ },
78
+ violet: {
79
+ name: 'violet', label: 'Violet', swatch: '#8b5cf6',
80
+ palette: {
81
+ 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd',
82
+ 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9',
83
+ 800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065',
84
+ },
85
+ },
86
+ purple: {
87
+ name: 'purple', label: 'Purple', swatch: '#a855f7',
88
+ palette: {
89
+ 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe',
90
+ 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce',
91
+ 800: '#6b21a8', 900: '#581c87', 950: '#3b0764',
92
+ },
93
+ },
94
+ fuchsia: {
95
+ name: 'fuchsia', label: 'Fuchsia', swatch: '#d946ef',
96
+ palette: {
97
+ 50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc',
98
+ 400: '#e879f9', 500: '#d946ef', 600: '#c026d3', 700: '#a21caf',
99
+ 800: '#86198f', 900: '#701a75', 950: '#4a044e',
100
+ },
101
+ },
102
+ pink: {
103
+ name: 'pink', label: 'Pink', swatch: '#ec4899',
104
+ palette: {
105
+ 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4',
106
+ 400: '#f472b6', 500: '#ec4899', 600: '#db2777', 700: '#be185d',
107
+ 800: '#9d174d', 900: '#831843', 950: '#500724',
108
+ },
109
+ },
110
+ rose: {
111
+ name: 'rose', label: 'Rose', swatch: '#f43f5e',
112
+ palette: {
113
+ 50: '#fff1f2', 100: '#ffe4e6', 200: '#fecdd3', 300: '#fda4af',
114
+ 400: '#fb7185', 500: '#f43f5e', 600: '#e11d48', 700: '#be123c',
115
+ 800: '#9f1239', 900: '#881337', 950: '#4c0519',
116
+ },
117
+ },
118
+ red: {
119
+ name: 'red', label: 'Red', swatch: '#ef4444',
120
+ palette: {
121
+ 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5',
122
+ 400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c',
123
+ 800: '#991b1b', 900: '#7f1d1d', 950: '#450a0a',
124
+ },
125
+ },
126
+ orange: {
127
+ name: 'orange', label: 'Orange', swatch: '#f97316',
128
+ palette: {
129
+ 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74',
130
+ 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c',
131
+ 800: '#9a3412', 900: '#7c2d12', 950: '#431407',
132
+ },
133
+ },
134
+ amber: {
135
+ name: 'amber', label: 'Amber', swatch: '#f59e0b',
136
+ palette: {
137
+ 50: '#fffbeb', 100: '#fef3c7', 200: '#fde68a', 300: '#fcd34d',
138
+ 400: '#fbbf24', 500: '#f59e0b', 600: '#d97706', 700: '#b45309',
139
+ 800: '#92400e', 900: '#78350f', 950: '#451a03',
140
+ },
141
+ },
142
+ lime: {
143
+ name: 'lime', label: 'Lime', swatch: '#84cc16',
144
+ palette: {
145
+ 50: '#f7fee7', 100: '#ecfccb', 200: '#d9f99d', 300: '#bef264',
146
+ 400: '#a3e635', 500: '#84cc16', 600: '#65a30d', 700: '#4d7c0f',
147
+ 800: '#3f6212', 900: '#365314', 950: '#1a2e05',
148
+ },
149
+ },
150
+ slate: {
151
+ name: 'slate', label: 'Slate', swatch: '#64748b',
152
+ palette: {
153
+ 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1',
154
+ 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155',
155
+ 800: '#1e293b', 900: '#0f172a', 950: '#020617',
156
+ },
157
+ },
158
+ zinc: {
159
+ name: 'zinc', label: 'Zinc', swatch: '#71717a',
160
+ palette: {
161
+ 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8',
162
+ 400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46',
163
+ 800: '#27272a', 900: '#18181b', 950: '#09090b',
164
+ },
165
+ },
166
+ };
167
+ /** Returns all preset metas sorted for display */
168
+ function getAllPresets() {
169
+ return Object.values(COLOR_PRESETS);
170
+ }
171
+
172
+ const STORAGE_KEY_MODE = 'ui-theme-mode';
173
+ const STORAGE_KEY_PRESET = 'ui-theme-preset';
174
+ // ── ThemeService ──────────────────────────────────────────────────────────────
175
+ // Single source of truth for:
176
+ // · Primary color palette → overrides --color-primary-* CSS vars on :root
177
+ // · Theme mode (light / dark / system) → sets data-theme attribute
178
+ //
179
+ // State is persisted to localStorage and restored on next page load.
180
+ //
181
+ // Usage (anywhere in the app):
182
+ // theme = inject(ThemeService);
183
+ // theme.setPrimary('violet');
184
+ // theme.setMode('dark');
185
+ class ThemeService {
186
+ // ── Constructor — restore from localStorage ───────────────────────────────
187
+ constructor() {
188
+ this.platformId = inject(PLATFORM_ID);
189
+ // ── Private state ─────────────────────────────────────────────────────────
190
+ this._preset = signal(null);
191
+ this._palette = signal(null);
192
+ this._mode = signal('light');
193
+ // ── Public read-only signals ──────────────────────────────────────────────
194
+ /** Currently active preset name (null when a custom palette was set) */
195
+ this.activePreset = this._preset.asReadonly();
196
+ /** Resolved full palette */
197
+ this.activePalette = computed(() => {
198
+ const custom = this._palette();
199
+ if (custom)
200
+ return custom;
201
+ const preset = this._preset();
202
+ return preset ? (COLOR_PRESETS[preset]?.palette ?? null) : null;
203
+ });
204
+ /** Currently active mode */
205
+ this.activeMode = this._mode.asReadonly();
206
+ /** Derived boolean — true when dark is currently active (including system→dark) */
207
+ this.isDark = computed(() => {
208
+ if (this._mode() === 'dark')
209
+ return true;
210
+ if (this._mode() === 'system' && isPlatformBrowser(this.platformId)) {
211
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
212
+ }
213
+ return false;
214
+ });
215
+ /** All available presets for rendering a picker */
216
+ this.presets = Object.values(COLOR_PRESETS);
217
+ if (!isPlatformBrowser(this.platformId))
218
+ return;
219
+ // Restore mode
220
+ const savedMode = localStorage.getItem(STORAGE_KEY_MODE);
221
+ const initialMode = (savedMode === 'light' || savedMode === 'dark' || savedMode === 'system')
222
+ ? savedMode : 'light';
223
+ this._mode.set(initialMode);
224
+ this.applyMode(initialMode);
225
+ // Restore preset
226
+ const savedPreset = localStorage.getItem(STORAGE_KEY_PRESET);
227
+ if (savedPreset && COLOR_PRESETS[savedPreset]) {
228
+ this._preset.set(savedPreset);
229
+ this.applyPalette(COLOR_PRESETS[savedPreset].palette);
230
+ }
231
+ // Persist mode changes to localStorage
232
+ effect(() => {
233
+ localStorage.setItem(STORAGE_KEY_MODE, this._mode());
234
+ });
235
+ // Persist preset changes to localStorage
236
+ effect(() => {
237
+ const p = this._preset();
238
+ if (p)
239
+ localStorage.setItem(STORAGE_KEY_PRESET, p);
240
+ else
241
+ localStorage.removeItem(STORAGE_KEY_PRESET);
242
+ });
243
+ }
244
+ // ── Public API ─────────────────────────────────────────────────────────────
245
+ /**
246
+ * Set the primary color using a preset name or a full custom palette.
247
+ * Immediately applies CSS custom properties to :root and persists to localStorage.
248
+ */
249
+ setPrimary(color) {
250
+ if (typeof color === 'string') {
251
+ if (!COLOR_PRESETS[color])
252
+ return;
253
+ this._preset.set(color);
254
+ this._palette.set(null);
255
+ this.applyPalette(COLOR_PRESETS[color].palette);
256
+ }
257
+ else {
258
+ this._preset.set(null);
259
+ this._palette.set(color);
260
+ this.applyPalette(color);
261
+ }
262
+ }
263
+ /**
264
+ * Switch between light, dark, and system modes.
265
+ * Persisted to localStorage automatically.
266
+ */
267
+ setMode(mode) {
268
+ this._mode.set(mode);
269
+ this.applyMode(mode);
270
+ }
271
+ /** Toggle between light ↔ dark (ignores system). */
272
+ toggleMode() {
273
+ this.setMode(this._mode() === 'dark' ? 'light' : 'dark');
274
+ }
275
+ /**
276
+ * Apply a full ThemeConfig at once (used by provideSharedUiTheme).
277
+ * Does NOT override values already restored from localStorage unless
278
+ * the config explicitly provides them.
279
+ */
280
+ applyConfig(config) {
281
+ // Only apply if nothing was already restored from localStorage
282
+ if (config.primaryColor !== undefined && this._preset() === null && this._palette() === null) {
283
+ this.setPrimary(config.primaryColor);
284
+ }
285
+ if (config.mode !== undefined) {
286
+ const saved = isPlatformBrowser(this.platformId)
287
+ ? localStorage.getItem(STORAGE_KEY_MODE)
288
+ : null;
289
+ // Don't override a user's saved preference with the default config
290
+ if (!saved)
291
+ this.setMode(config.mode);
292
+ }
293
+ }
294
+ // ── Internal helpers ──────────────────────────────────────────────────────
295
+ applyPalette(palette) {
296
+ if (!isPlatformBrowser(this.platformId))
297
+ return;
298
+ const root = document.documentElement;
299
+ Object.entries(palette).forEach(([shade, value]) => {
300
+ root.style.setProperty(`--color-primary-${shade}`, value);
301
+ });
302
+ }
303
+ applyMode(mode) {
304
+ if (!isPlatformBrowser(this.platformId))
305
+ return;
306
+ const applyDark = (dark) => document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
307
+ // Remove any previous media-query listener
308
+ if (this._mqListener) {
309
+ window.matchMedia('(prefers-color-scheme: dark)')
310
+ .removeEventListener('change', this._mqListener);
311
+ this._mqListener = undefined;
312
+ }
313
+ if (mode === 'system') {
314
+ const mq = window.matchMedia('(prefers-color-scheme: dark)');
315
+ applyDark(mq.matches);
316
+ this._mqListener = (e) => { if (this._mode() === 'system')
317
+ applyDark(e.matches); };
318
+ mq.addEventListener('change', this._mqListener);
319
+ }
320
+ else {
321
+ applyDark(mode === 'dark');
322
+ }
323
+ }
324
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
325
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemeService, providedIn: 'root' }); }
326
+ }
327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemeService, decorators: [{
328
+ type: Injectable,
329
+ args: [{ providedIn: 'root' }]
330
+ }], ctorParameters: () => [] });
331
+
332
+ // ── provideSharedUiTheme ──────────────────────────────────────────────────────
333
+ // Call in app.config.ts to configure the design system theme at bootstrap time.
334
+ //
335
+ // Usage:
336
+ // export const appConfig: ApplicationConfig = {
337
+ // providers: [
338
+ // provideSharedUiTheme({ primaryColor: 'indigo', mode: 'light' }),
339
+ // ],
340
+ // };
341
+ function provideSharedUiTheme(config = {}) {
342
+ return makeEnvironmentProviders([
343
+ {
344
+ provide: APP_INITIALIZER,
345
+ useFactory: (theme) => () => theme.applyConfig(config),
346
+ deps: [ThemeService],
347
+ multi: true,
348
+ },
349
+ ]);
350
+ }
351
+
352
+ // ── ThemePickerComponent ──────────────────────────────────────────────────────
353
+ // Grid of color swatches — clicking one applies the preset immediately.
354
+ // Emits (change) for the host to react if needed.
355
+ //
356
+ // Usage:
357
+ // <ui-theme-picker />
358
+ // <ui-theme-picker (change)="onColorChange($event)" />
359
+ class ThemePickerComponent {
360
+ constructor() {
361
+ this.theme = inject(ThemeService);
362
+ this.change = output();
363
+ }
364
+ select(preset) {
365
+ this.theme.setPrimary(preset.name);
366
+ this.change.emit(preset.name);
367
+ }
368
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
369
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ThemePickerComponent, isStandalone: true, selector: "ui-theme-picker", outputs: { change: "change" }, ngImport: i0, template: `
370
+ <div class="tp" role="radiogroup" aria-label="Primary color">
371
+ @for (preset of theme.presets; track preset.name) {
372
+ <button
373
+ class="tp__swatch"
374
+ type="button"
375
+ role="radio"
376
+ [attr.aria-label]="preset.label"
377
+ [attr.aria-checked]="theme.activePreset() === preset.name"
378
+ [class.tp__swatch--active]="theme.activePreset() === preset.name"
379
+ [style.background]="preset.swatch"
380
+ [title]="preset.label"
381
+ (click)="select(preset)"
382
+ >
383
+ @if (theme.activePreset() === preset.name) {
384
+ <svg class="tp__check" viewBox="0 0 12 12" fill="none" aria-hidden="true">
385
+ <path d="M2 6l3 3 5-5" stroke="#fff" stroke-width="1.8"
386
+ stroke-linecap="round" stroke-linejoin="round"/>
387
+ </svg>
388
+ }
389
+ </button>
390
+ }
391
+ </div>
392
+ `, isInline: true, styles: [".tp{display:grid;grid-template-columns:repeat(6,28px);gap:8px;padding:4px}.tp__swatch{width:28px;height:28px;border-radius:50%;border:2px solid transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform .15s,border-color .15s;padding:0;&:hover{transform:scale(1.15)}}.tp__swatch--active{border-color:var(--color-border);box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px currentColor}.tp__check{width:12px;height:12px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
393
+ }
394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemePickerComponent, decorators: [{
395
+ type: Component,
396
+ args: [{ selector: 'ui-theme-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
397
+ <div class="tp" role="radiogroup" aria-label="Primary color">
398
+ @for (preset of theme.presets; track preset.name) {
399
+ <button
400
+ class="tp__swatch"
401
+ type="button"
402
+ role="radio"
403
+ [attr.aria-label]="preset.label"
404
+ [attr.aria-checked]="theme.activePreset() === preset.name"
405
+ [class.tp__swatch--active]="theme.activePreset() === preset.name"
406
+ [style.background]="preset.swatch"
407
+ [title]="preset.label"
408
+ (click)="select(preset)"
409
+ >
410
+ @if (theme.activePreset() === preset.name) {
411
+ <svg class="tp__check" viewBox="0 0 12 12" fill="none" aria-hidden="true">
412
+ <path d="M2 6l3 3 5-5" stroke="#fff" stroke-width="1.8"
413
+ stroke-linecap="round" stroke-linejoin="round"/>
414
+ </svg>
415
+ }
416
+ </button>
417
+ }
418
+ </div>
419
+ `, styles: [".tp{display:grid;grid-template-columns:repeat(6,28px);gap:8px;padding:4px}.tp__swatch{width:28px;height:28px;border-radius:50%;border:2px solid transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform .15s,border-color .15s;padding:0;&:hover{transform:scale(1.15)}}.tp__swatch--active{border-color:var(--color-border);box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px currentColor}.tp__check{width:12px;height:12px}\n"] }]
420
+ }] });
421
+
422
+ class ThemeToggleComponent {
423
+ constructor() {
424
+ this.theme = inject(ThemeService);
425
+ this.options = [
426
+ {
427
+ value: 'light',
428
+ label: 'Clair',
429
+ icon: `<circle cx="12" cy="12" r="4"/>
430
+ <path d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32 1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>`,
431
+ },
432
+ {
433
+ value: 'system',
434
+ label: 'Auto',
435
+ icon: `<rect x="2" y="3" width="20" height="14" rx="2"/>
436
+ <path d="M8 21h8m-4-4v4"/>`,
437
+ },
438
+ {
439
+ value: 'dark',
440
+ label: 'Sombre',
441
+ icon: `<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>`,
442
+ },
443
+ ];
444
+ }
445
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemeToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
446
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ThemeToggleComponent, isStandalone: true, selector: "ui-theme-toggle", ngImport: i0, template: `
447
+ <div class="toggle" role="group" aria-label="Mode d'affichage">
448
+ @for (opt of options; track opt.value) {
449
+ <button
450
+ class="toggle__btn"
451
+ [class.toggle__btn--active]="theme.activeMode() === opt.value"
452
+ type="button"
453
+ [attr.aria-label]="opt.label"
454
+ [attr.title]="opt.label"
455
+ [attr.aria-pressed]="theme.activeMode() === opt.value"
456
+ (click)="theme.setMode(opt.value)"
457
+ >
458
+ <svg
459
+ width="15" height="15"
460
+ viewBox="0 0 24 24" fill="none"
461
+ stroke="currentColor" stroke-width="2"
462
+ stroke-linecap="round" stroke-linejoin="round"
463
+ aria-hidden="true"
464
+ [innerHTML]="opt.icon"
465
+ ></svg>
466
+ <span class="toggle__label">{{ opt.label }}</span>
467
+ </button>
468
+ }
469
+ </div>
470
+ `, isInline: true, styles: [".toggle{display:inline-flex;align-items:center;background:var(--color-bg-subtle);border:1px solid var(--color-border);border-radius:var(--radius-lg, 10px);padding:3px;gap:2px}.toggle__btn{display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:var(--radius-md, 8px);background:transparent;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-xs, 11px);font-weight:var(--font-medium, 500);cursor:pointer;transition:background .15s,color .15s,box-shadow .15s;white-space:nowrap}.toggle__label{line-height:1}.toggle__btn:hover:not(.toggle__btn--active){background:var(--color-bg);color:var(--color-text)}.toggle__btn--active{background:var(--color-bg);color:var(--color-text);box-shadow:0 1px 3px #0000001a,0 0 0 1px var(--color-border)}:host-context([data-theme=\"dark\"]) .toggle__btn:hover:not(.toggle__btn--active){background:var(--color-neutral-700);color:var(--color-text)}:host-context([data-theme=\"dark\"]) .toggle__btn--active{background:var(--color-neutral-600);color:var(--color-text);box-shadow:0 1px 3px #00000059,0 0 0 1px var(--color-neutral-600)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
471
+ }
472
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ThemeToggleComponent, decorators: [{
473
+ type: Component,
474
+ args: [{ selector: 'ui-theme-toggle', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
475
+ <div class="toggle" role="group" aria-label="Mode d'affichage">
476
+ @for (opt of options; track opt.value) {
477
+ <button
478
+ class="toggle__btn"
479
+ [class.toggle__btn--active]="theme.activeMode() === opt.value"
480
+ type="button"
481
+ [attr.aria-label]="opt.label"
482
+ [attr.title]="opt.label"
483
+ [attr.aria-pressed]="theme.activeMode() === opt.value"
484
+ (click)="theme.setMode(opt.value)"
485
+ >
486
+ <svg
487
+ width="15" height="15"
488
+ viewBox="0 0 24 24" fill="none"
489
+ stroke="currentColor" stroke-width="2"
490
+ stroke-linecap="round" stroke-linejoin="round"
491
+ aria-hidden="true"
492
+ [innerHTML]="opt.icon"
493
+ ></svg>
494
+ <span class="toggle__label">{{ opt.label }}</span>
495
+ </button>
496
+ }
497
+ </div>
498
+ `, styles: [".toggle{display:inline-flex;align-items:center;background:var(--color-bg-subtle);border:1px solid var(--color-border);border-radius:var(--radius-lg, 10px);padding:3px;gap:2px}.toggle__btn{display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:var(--radius-md, 8px);background:transparent;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-xs, 11px);font-weight:var(--font-medium, 500);cursor:pointer;transition:background .15s,color .15s,box-shadow .15s;white-space:nowrap}.toggle__label{line-height:1}.toggle__btn:hover:not(.toggle__btn--active){background:var(--color-bg);color:var(--color-text)}.toggle__btn--active{background:var(--color-bg);color:var(--color-text);box-shadow:0 1px 3px #0000001a,0 0 0 1px var(--color-border)}:host-context([data-theme=\"dark\"]) .toggle__btn:hover:not(.toggle__btn--active){background:var(--color-neutral-700);color:var(--color-text)}:host-context([data-theme=\"dark\"]) .toggle__btn--active{background:var(--color-neutral-600);color:var(--color-text);box-shadow:0 1px 3px #00000059,0 0 0 1px var(--color-neutral-600)}\n"] }]
499
+ }] });
500
+
501
+ // ── Tokens public API ─────────────────────────────────────────────────────────
502
+ // Re-exports all TypeScript theme utilities.
503
+ // SCSS tokens are imported separately via @use in your global styles.scss
504
+
505
+ /**
506
+ * Avatar Atom
507
+ * Source: Nuxt UI v3 — ❖ Avatar
508
+ * Shows: image → initials → icon fallback
509
+ * Sizes: xs(20) sm(24) md(32) lg(40) xl(48) 2xl(64) 3xl(80)
510
+ */
511
+ class AvatarComponent {
512
+ constructor() {
513
+ this.src = input(null);
514
+ this.alt = input(null);
515
+ this.size = input('md');
516
+ this.initials = input(null);
517
+ this.chip = input(false);
518
+ this.chipColor = input('success');
519
+ this.chipAlt = input(null);
520
+ this.rounded = input(true);
521
+ this.imgError = signal(false);
522
+ this.classes = computed(() => {
523
+ const cls = ['ui-avatar', `ui-avatar--${this.size()}`];
524
+ if (!this.rounded())
525
+ cls.push('ui-avatar--square');
526
+ return cls.join(' ');
527
+ });
528
+ }
529
+ onImgError() { this.imgError.set(true); }
530
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
531
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: AvatarComponent, isStandalone: true, selector: "ui-avatar", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, chip: { classPropertyName: "chip", publicName: "chip", isSignal: true, isRequired: false, transformFunction: null }, chipColor: { classPropertyName: "chipColor", publicName: "chipColor", isSignal: true, isRequired: false, transformFunction: null }, chipAlt: { classPropertyName: "chipAlt", publicName: "chipAlt", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
532
+ <span [class]="classes()" [attr.aria-label]="alt() ?? null">
533
+ @if (src() && !imgError()) {
534
+ <img
535
+ [src]="src()"
536
+ [alt]="alt() ?? ''"
537
+ (error)="onImgError()"
538
+ class="ui-avatar__img"
539
+ />
540
+ } @else if (initials()) {
541
+ <span class="ui-avatar__initials" aria-hidden="true">{{ initials() }}</span>
542
+ } @else {
543
+ <span class="ui-avatar__icon" aria-hidden="true">
544
+ <ng-content />
545
+ </span>
546
+ }
547
+
548
+ @if (chip()) {
549
+ <span
550
+ class="ui-avatar__chip"
551
+ [class]="'ui-avatar__chip--' + chipColor()"
552
+ [attr.aria-label]="chipAlt()"
553
+ ></span>
554
+ }
555
+ </span>
556
+ `, isInline: true, styles: [".ui-avatar{position:relative;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--radius-full);background:var(--color-neutral-100);color:var(--color-neutral-500);overflow:hidden;flex-shrink:0;font-family:var(--font-sans);font-weight:var(--font-medium)}.ui-avatar--square{border-radius:var(--radius-md)}.ui-avatar--xs{width:20px;height:20px;font-size:10px}.ui-avatar--sm{width:24px;height:24px;font-size:11px}.ui-avatar--md{width:32px;height:32px;font-size:13px}.ui-avatar--lg{width:40px;height:40px;font-size:15px}.ui-avatar--xl{width:48px;height:48px;font-size:18px}.ui-avatar--2xl{width:64px;height:64px;font-size:22px}.ui-avatar--3xl{width:80px;height:80px;font-size:28px}.ui-avatar__img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.ui-avatar__initials{line-height:1;letter-spacing:var(--tracking-wide);text-transform:uppercase;-webkit-user-select:none;user-select:none}.ui-avatar__icon{display:flex;align-items:center;justify-content:center;width:60%;height:60%}.ui-avatar__chip{position:absolute;bottom:0;right:0;width:30%;height:30%;min-width:8px;min-height:8px;border-radius:50%;border:2px solid var(--color-bg)}.ui-avatar__chip--online{background:var(--color-success-500)}.ui-avatar__chip--idle{background:var(--color-warning-500)}.ui-avatar__chip--busy{background:var(--color-error-500)}.ui-avatar__chip--offline{background:var(--color-neutral-400)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
557
+ }
558
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AvatarComponent, decorators: [{
559
+ type: Component,
560
+ args: [{ selector: 'ui-avatar', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
561
+ <span [class]="classes()" [attr.aria-label]="alt() ?? null">
562
+ @if (src() && !imgError()) {
563
+ <img
564
+ [src]="src()"
565
+ [alt]="alt() ?? ''"
566
+ (error)="onImgError()"
567
+ class="ui-avatar__img"
568
+ />
569
+ } @else if (initials()) {
570
+ <span class="ui-avatar__initials" aria-hidden="true">{{ initials() }}</span>
571
+ } @else {
572
+ <span class="ui-avatar__icon" aria-hidden="true">
573
+ <ng-content />
574
+ </span>
575
+ }
576
+
577
+ @if (chip()) {
578
+ <span
579
+ class="ui-avatar__chip"
580
+ [class]="'ui-avatar__chip--' + chipColor()"
581
+ [attr.aria-label]="chipAlt()"
582
+ ></span>
583
+ }
584
+ </span>
585
+ `, styles: [".ui-avatar{position:relative;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--radius-full);background:var(--color-neutral-100);color:var(--color-neutral-500);overflow:hidden;flex-shrink:0;font-family:var(--font-sans);font-weight:var(--font-medium)}.ui-avatar--square{border-radius:var(--radius-md)}.ui-avatar--xs{width:20px;height:20px;font-size:10px}.ui-avatar--sm{width:24px;height:24px;font-size:11px}.ui-avatar--md{width:32px;height:32px;font-size:13px}.ui-avatar--lg{width:40px;height:40px;font-size:15px}.ui-avatar--xl{width:48px;height:48px;font-size:18px}.ui-avatar--2xl{width:64px;height:64px;font-size:22px}.ui-avatar--3xl{width:80px;height:80px;font-size:28px}.ui-avatar__img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.ui-avatar__initials{line-height:1;letter-spacing:var(--tracking-wide);text-transform:uppercase;-webkit-user-select:none;user-select:none}.ui-avatar__icon{display:flex;align-items:center;justify-content:center;width:60%;height:60%}.ui-avatar__chip{position:absolute;bottom:0;right:0;width:30%;height:30%;min-width:8px;min-height:8px;border-radius:50%;border:2px solid var(--color-bg)}.ui-avatar__chip--online{background:var(--color-success-500)}.ui-avatar__chip--idle{background:var(--color-warning-500)}.ui-avatar__chip--busy{background:var(--color-error-500)}.ui-avatar__chip--offline{background:var(--color-neutral-400)}\n"] }]
586
+ }] });
587
+
588
+ /**
589
+ * Badge Atom
590
+ * Source: Nuxt UI v3 — ❖ Badge
591
+ * Colors: Neutral | Primary | Secondary | Success | Info | Warning | Error
592
+ * Variants: Outline | Soft | Solid | Subtle
593
+ * Sizes: xs | sm | md | lg | xl
594
+ * RoundedFull: True | False
595
+ */
596
+ class BadgeComponent {
597
+ constructor() {
598
+ this.variant = input('soft');
599
+ this.color = input('neutral');
600
+ this.size = input('md');
601
+ this.rounded = input(false);
602
+ this.dot = input(false);
603
+ this.classes = computed(() => {
604
+ const cls = ['ui-badge', `ui-badge--${this.variant()}`, `ui-badge--${this.color()}`, `ui-badge--${this.size()}`];
605
+ if (this.rounded())
606
+ cls.push('ui-badge--rounded');
607
+ return cls.join(' ');
608
+ });
609
+ }
610
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
611
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: BadgeComponent, isStandalone: true, selector: "ui-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, dot: { classPropertyName: "dot", publicName: "dot", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
612
+ <span [class]="classes()">
613
+ @if (dot()) {
614
+ <span class="ui-badge__dot" aria-hidden="true"></span>
615
+ }
616
+ <ng-content />
617
+ </span>
618
+ `, isInline: true, styles: [".ui-badge{display:inline-flex;align-items:center;gap:.25rem;font-family:var(--font-sans);font-weight:var(--font-medium);white-space:nowrap;border:1px solid transparent;border-radius:var(--radius-md)}.ui-badge--rounded{border-radius:var(--radius-full)}.ui-badge__dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0}.ui-badge--xs{padding:0 6px;font-size:var(--text-xs);height:18px}.ui-badge--sm{padding:0 8px;font-size:var(--text-xs);height:20px}.ui-badge--md{padding:0 10px;font-size:var(--text-sm);height:22px}.ui-badge--lg{padding:0 10px;font-size:var(--text-sm);height:24px}.ui-badge--xl{padding:0 12px;font-size:var(--text-md);height:28px}.ui-badge--primary.ui-badge--solid{background:var(--color-primary-500);color:#fff}.ui-badge--primary.ui-badge--outline{color:var(--color-primary-500);border-color:var(--color-primary-500);background:transparent}.ui-badge--primary.ui-badge--soft{background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-700)}.ui-badge--primary.ui-badge--subtle{background:color-mix(in srgb,var(--color-primary-500) 10%,transparent);color:var(--color-primary-600)}.ui-badge--neutral.ui-badge--solid{background:var(--color-neutral-800);color:#fff}.ui-badge--neutral.ui-badge--outline{color:var(--color-neutral-600);border-color:var(--color-neutral-300);background:transparent}.ui-badge--neutral.ui-badge--soft{background:var(--color-neutral-100);color:var(--color-neutral-700)}.ui-badge--neutral.ui-badge--subtle{background:var(--color-neutral-50);color:var(--color-neutral-600)}.ui-badge--success.ui-badge--solid{background:var(--color-success-500);color:#fff}.ui-badge--success.ui-badge--outline{color:var(--color-success-600);border-color:var(--color-success-500);background:transparent}.ui-badge--success.ui-badge--soft{background:color-mix(in srgb,var(--color-success-500) 15%,transparent);color:var(--color-success-700)}.ui-badge--success.ui-badge--subtle{background:color-mix(in srgb,var(--color-success-500) 10%,transparent);color:var(--color-success-600)}.ui-badge--warning.ui-badge--solid{background:var(--color-warning-500);color:#fff}.ui-badge--warning.ui-badge--outline{color:var(--color-warning-600);border-color:var(--color-warning-500);background:transparent}.ui-badge--warning.ui-badge--soft{background:color-mix(in srgb,var(--color-warning-500) 15%,transparent);color:var(--color-warning-700)}.ui-badge--warning.ui-badge--subtle{background:color-mix(in srgb,var(--color-warning-500) 10%,transparent);color:var(--color-warning-600)}.ui-badge--error.ui-badge--solid{background:var(--color-error-500);color:#fff}.ui-badge--error.ui-badge--outline{color:var(--color-error-600);border-color:var(--color-error-500);background:transparent}.ui-badge--error.ui-badge--soft{background:color-mix(in srgb,var(--color-error-500) 15%,transparent);color:var(--color-error-700)}.ui-badge--error.ui-badge--subtle{background:color-mix(in srgb,var(--color-error-500) 10%,transparent);color:var(--color-error-600)}.ui-badge--info.ui-badge--solid{background:var(--color-info-500);color:#fff}.ui-badge--info.ui-badge--outline{color:var(--color-info-600);border-color:var(--color-info-500);background:transparent}.ui-badge--info.ui-badge--soft{background:color-mix(in srgb,var(--color-info-500) 15%,transparent);color:var(--color-info-700)}.ui-badge--info.ui-badge--subtle{background:color-mix(in srgb,var(--color-info-500) 10%,transparent);color:var(--color-info-600)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
619
+ }
620
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BadgeComponent, decorators: [{
621
+ type: Component,
622
+ args: [{ selector: 'ui-badge', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
623
+ <span [class]="classes()">
624
+ @if (dot()) {
625
+ <span class="ui-badge__dot" aria-hidden="true"></span>
626
+ }
627
+ <ng-content />
628
+ </span>
629
+ `, styles: [".ui-badge{display:inline-flex;align-items:center;gap:.25rem;font-family:var(--font-sans);font-weight:var(--font-medium);white-space:nowrap;border:1px solid transparent;border-radius:var(--radius-md)}.ui-badge--rounded{border-radius:var(--radius-full)}.ui-badge__dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0}.ui-badge--xs{padding:0 6px;font-size:var(--text-xs);height:18px}.ui-badge--sm{padding:0 8px;font-size:var(--text-xs);height:20px}.ui-badge--md{padding:0 10px;font-size:var(--text-sm);height:22px}.ui-badge--lg{padding:0 10px;font-size:var(--text-sm);height:24px}.ui-badge--xl{padding:0 12px;font-size:var(--text-md);height:28px}.ui-badge--primary.ui-badge--solid{background:var(--color-primary-500);color:#fff}.ui-badge--primary.ui-badge--outline{color:var(--color-primary-500);border-color:var(--color-primary-500);background:transparent}.ui-badge--primary.ui-badge--soft{background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-700)}.ui-badge--primary.ui-badge--subtle{background:color-mix(in srgb,var(--color-primary-500) 10%,transparent);color:var(--color-primary-600)}.ui-badge--neutral.ui-badge--solid{background:var(--color-neutral-800);color:#fff}.ui-badge--neutral.ui-badge--outline{color:var(--color-neutral-600);border-color:var(--color-neutral-300);background:transparent}.ui-badge--neutral.ui-badge--soft{background:var(--color-neutral-100);color:var(--color-neutral-700)}.ui-badge--neutral.ui-badge--subtle{background:var(--color-neutral-50);color:var(--color-neutral-600)}.ui-badge--success.ui-badge--solid{background:var(--color-success-500);color:#fff}.ui-badge--success.ui-badge--outline{color:var(--color-success-600);border-color:var(--color-success-500);background:transparent}.ui-badge--success.ui-badge--soft{background:color-mix(in srgb,var(--color-success-500) 15%,transparent);color:var(--color-success-700)}.ui-badge--success.ui-badge--subtle{background:color-mix(in srgb,var(--color-success-500) 10%,transparent);color:var(--color-success-600)}.ui-badge--warning.ui-badge--solid{background:var(--color-warning-500);color:#fff}.ui-badge--warning.ui-badge--outline{color:var(--color-warning-600);border-color:var(--color-warning-500);background:transparent}.ui-badge--warning.ui-badge--soft{background:color-mix(in srgb,var(--color-warning-500) 15%,transparent);color:var(--color-warning-700)}.ui-badge--warning.ui-badge--subtle{background:color-mix(in srgb,var(--color-warning-500) 10%,transparent);color:var(--color-warning-600)}.ui-badge--error.ui-badge--solid{background:var(--color-error-500);color:#fff}.ui-badge--error.ui-badge--outline{color:var(--color-error-600);border-color:var(--color-error-500);background:transparent}.ui-badge--error.ui-badge--soft{background:color-mix(in srgb,var(--color-error-500) 15%,transparent);color:var(--color-error-700)}.ui-badge--error.ui-badge--subtle{background:color-mix(in srgb,var(--color-error-500) 10%,transparent);color:var(--color-error-600)}.ui-badge--info.ui-badge--solid{background:var(--color-info-500);color:#fff}.ui-badge--info.ui-badge--outline{color:var(--color-info-600);border-color:var(--color-info-500);background:transparent}.ui-badge--info.ui-badge--soft{background:color-mix(in srgb,var(--color-info-500) 15%,transparent);color:var(--color-info-700)}.ui-badge--info.ui-badge--subtle{background:color-mix(in srgb,var(--color-info-500) 10%,transparent);color:var(--color-info-600)}\n"] }]
630
+ }] });
631
+
632
+ /**
633
+ * Button Atom
634
+ * Source: Nuxt UI v3 Design Kit — ❖ Button
635
+ *
636
+ * Variants: solid | outline | soft | subtle | ghost | link
637
+ * Sizes: xs (h:24px) | sm (h:28px) | md (h:32px) | lg (h:36px) | xl (h:40px)
638
+ * States: default | hover | focus | disabled | loading
639
+ *
640
+ * @example
641
+ * <ui-button variant="solid" color="primary" size="md">Click me</ui-button>
642
+ * <ui-button variant="outline" [loading]="true">Loading</ui-button>
643
+ * <ui-button [square]="true" leadingIcon="plus" />
644
+ */
645
+ class ButtonComponent {
646
+ constructor() {
647
+ /** Visual variant — from Figma: Solid | Outline | Soft | Subtle | Ghost | Link */
648
+ this.variant = input('solid');
649
+ /** Color theme */
650
+ this.color = input('primary');
651
+ /** Size — from Figma: xs(h:24) sm(h:28) md(h:32) lg(h:36) xl(h:40) */
652
+ this.size = input('md');
653
+ /** Disabled state */
654
+ this.disabled = input(false);
655
+ /** Loading state — shows spinner */
656
+ this.loading = input(false);
657
+ /** Position of the spinner */
658
+ this.loadingPosition = input('leading');
659
+ /** Square/icon-only mode */
660
+ this.square = input(false);
661
+ /** Full width */
662
+ this.block = input(false);
663
+ /** Leading icon name (for aria/slot reference) */
664
+ this.leadingIcon = input(null);
665
+ /** Trailing icon name */
666
+ this.trailingIcon = input(null);
667
+ /** HTML button type */
668
+ this.type = input('button');
669
+ /** Accessible label for icon-only buttons */
670
+ this.ariaLabel = input(null);
671
+ this.hostClasses = computed(() => {
672
+ const classes = [
673
+ 'ui-btn',
674
+ `ui-btn--${this.variant()}`,
675
+ `ui-btn--${this.color()}`,
676
+ `ui-btn--${this.size()}`,
677
+ ];
678
+ if (this.square())
679
+ classes.push('ui-btn--square');
680
+ if (this.block())
681
+ classes.push('ui-btn--block');
682
+ if (this.loading())
683
+ classes.push('ui-btn--loading');
684
+ if (this.disabled())
685
+ classes.push('ui-btn--disabled');
686
+ return classes.join(' ');
687
+ });
688
+ }
689
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
690
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ButtonComponent, isStandalone: true, selector: "ui-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingPosition: { classPropertyName: "loadingPosition", publicName: "loadingPosition", isSignal: true, isRequired: false, transformFunction: null }, square: { classPropertyName: "square", publicName: "square", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null }, leadingIcon: { classPropertyName: "leadingIcon", publicName: "leadingIcon", isSignal: true, isRequired: false, transformFunction: null }, trailingIcon: { classPropertyName: "trailingIcon", publicName: "trailingIcon", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
691
+ <button
692
+ [type]="type()"
693
+ [disabled]="disabled() || loading()"
694
+ [class]="hostClasses()"
695
+ [attr.aria-disabled]="disabled() || loading()"
696
+ [attr.aria-label]="ariaLabel() ?? null"
697
+ [attr.aria-busy]="loading()"
698
+ >
699
+ <!-- Leading icon -->
700
+ @if (loading() && loadingPosition() === 'leading') {
701
+ <span class="ui-btn__spinner" aria-hidden="true">
702
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
703
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
704
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
705
+ </svg>
706
+ </span>
707
+ } @else if (leadingIcon() && !square()) {
708
+ <span class="ui-btn__icon ui-btn__icon--leading" aria-hidden="true">
709
+ <ng-content select="[slot=leading-icon]" />
710
+ </span>
711
+ }
712
+
713
+ <!-- Label -->
714
+ @if (!square()) {
715
+ <span class="ui-btn__label">
716
+ <ng-content />
717
+ </span>
718
+ }
719
+
720
+ <!-- Trailing icon or square icon -->
721
+ @if (loading() && loadingPosition() === 'trailing') {
722
+ <span class="ui-btn__spinner" aria-hidden="true">
723
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
724
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
725
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
726
+ </svg>
727
+ </span>
728
+ } @else if (trailingIcon() && !square()) {
729
+ <span class="ui-btn__icon ui-btn__icon--trailing" aria-hidden="true">
730
+ <ng-content select="[slot=trailing-icon]" />
731
+ </span>
732
+ }
733
+
734
+ <!-- Square/icon-only mode -->
735
+ @if (square()) {
736
+ <span class="ui-btn__icon" aria-hidden="true">
737
+ <ng-content select="[slot=icon]" />
738
+ </span>
739
+ }
740
+ </button>
741
+ `, isInline: true, styles: [".ui-btn{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;white-space:nowrap;cursor:pointer;border:1px solid transparent;border-radius:var(--radius-md);font-family:var(--font-sans);font-weight:var(--font-medium);text-decoration:none;outline:none;transition:var(--transition-colors);-webkit-user-select:none;user-select:none;position:relative;overflow:hidden}.ui-btn:focus-visible{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-btn--xs{height:var(--size-xs);padding:4px 8px;font-size:var(--text-xs)}.ui-btn--xs .ui-btn__icon{width:var(--icon-xs);height:var(--icon-xs)}.ui-btn--xs.ui-btn--square{width:var(--size-xs);padding:0}.ui-btn--sm{height:var(--size-sm);padding:6px 10px;font-size:var(--text-xs)}.ui-btn--sm .ui-btn__icon{width:var(--icon-sm);height:var(--icon-sm)}.ui-btn--sm.ui-btn--square{width:var(--size-sm);padding:0}.ui-btn--md{height:var(--size-md);padding:6px 10px;font-size:var(--text-sm)}.ui-btn--md .ui-btn__icon{width:var(--icon-md);height:var(--icon-md)}.ui-btn--md.ui-btn--square{width:var(--size-md);padding:0}.ui-btn--lg{height:var(--size-lg);padding:8px 12px;font-size:var(--text-sm)}.ui-btn--lg .ui-btn__icon{width:var(--icon-md);height:var(--icon-md)}.ui-btn--lg.ui-btn--square{width:var(--size-lg);padding:0}.ui-btn--xl{height:var(--size-xl);padding:8px 12px;font-size:var(--text-md)}.ui-btn--xl .ui-btn__icon{width:var(--icon-lg);height:var(--icon-lg)}.ui-btn--xl.ui-btn--square{width:var(--size-xl);padding:0}.ui-btn--block{width:100%}.ui-btn__icon{display:flex;align-items:center;justify-content:center;flex-shrink:0}.ui-btn__spinner{display:flex;align-items:center;width:1em;height:1em;flex-shrink:0}.ui-btn__spinner svg{width:100%;height:100%;animation:ui-spin .75s linear infinite}.ui-btn[disabled],.ui-btn--disabled{cursor:not-allowed;opacity:.5}.ui-btn--loading{cursor:wait}.ui-btn--primary.ui-btn--solid{background:var(--color-primary-500);color:var(--color-neutral-0)}.ui-btn--primary.ui-btn--solid:hover:not([disabled]){background:var(--color-primary-600)}.ui-btn--primary.ui-btn--solid:active:not([disabled]){background:var(--color-primary-700)}.ui-btn--primary.ui-btn--outline{background:transparent;color:var(--color-primary-500);border-color:var(--color-primary-500)}.ui-btn--primary.ui-btn--outline:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-btn--primary.ui-btn--soft{background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-700)}.ui-btn--primary.ui-btn--soft:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.ui-btn--primary.ui-btn--subtle{background:transparent;color:var(--color-primary-500)}.ui-btn--primary.ui-btn--subtle:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-btn--primary.ui-btn--ghost{background:transparent;color:var(--color-primary-500)}.ui-btn--primary.ui-btn--ghost:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 8%,transparent)}.ui-btn--primary.ui-btn--link{background:transparent;color:var(--color-primary-500);text-decoration:underline;padding-left:0;padding-right:0;height:auto}.ui-btn--primary.ui-btn--link:hover:not([disabled]){color:var(--color-primary-600)}.ui-btn--neutral.ui-btn--solid{background:var(--color-neutral-900);color:var(--color-neutral-0)}.ui-btn--neutral.ui-btn--solid:hover:not([disabled]){background:var(--color-neutral-800)}.ui-btn--neutral.ui-btn--outline{background:transparent;color:var(--color-neutral-700);border-color:var(--color-neutral-300)}.ui-btn--neutral.ui-btn--outline:hover:not([disabled]){background:var(--color-neutral-50)}.ui-btn--neutral.ui-btn--soft{background:var(--color-neutral-100);color:var(--color-neutral-700)}.ui-btn--neutral.ui-btn--soft:hover:not([disabled]){background:var(--color-neutral-200)}.ui-btn--neutral.ui-btn--subtle{background:transparent;color:var(--color-neutral-600)}.ui-btn--neutral.ui-btn--subtle:hover:not([disabled]){background:var(--color-neutral-100)}.ui-btn--neutral.ui-btn--ghost{background:transparent;color:var(--color-neutral-600)}.ui-btn--neutral.ui-btn--ghost:hover:not([disabled]){background:var(--color-neutral-100)}.ui-btn--neutral.ui-btn--link{background:transparent;color:var(--color-neutral-600);text-decoration:underline;padding-left:0;padding-right:0;height:auto}.ui-btn--success.ui-btn--solid{background:var(--color-success-500);color:var(--color-neutral-0)}.ui-btn--success.ui-btn--solid:hover:not([disabled]){background:var(--color-success-600)}.ui-btn--success.ui-btn--outline{background:transparent;color:var(--color-success-600);border-color:var(--color-success-500)}.ui-btn--success.ui-btn--soft{background:color-mix(in srgb,var(--color-success-500) 15%,transparent);color:var(--color-success-700)}.ui-btn--success.ui-btn--subtle,.ui-btn--success.ui-btn--ghost{background:transparent;color:var(--color-success-600)}.ui-btn--warning.ui-btn--solid{background:var(--color-warning-500);color:var(--color-neutral-0)}.ui-btn--warning.ui-btn--solid:hover:not([disabled]){background:var(--color-warning-600)}.ui-btn--warning.ui-btn--outline{background:transparent;color:var(--color-warning-600);border-color:var(--color-warning-500)}.ui-btn--warning.ui-btn--soft{background:color-mix(in srgb,var(--color-warning-500) 15%,transparent);color:var(--color-warning-700)}.ui-btn--warning.ui-btn--subtle,.ui-btn--warning.ui-btn--ghost{background:transparent;color:var(--color-warning-600)}.ui-btn--error.ui-btn--solid{background:var(--color-error-500);color:var(--color-neutral-0)}.ui-btn--error.ui-btn--solid:hover:not([disabled]){background:var(--color-error-600)}.ui-btn--error.ui-btn--outline{background:transparent;color:var(--color-error-600);border-color:var(--color-error-500)}.ui-btn--error.ui-btn--soft{background:color-mix(in srgb,var(--color-error-500) 15%,transparent);color:var(--color-error-700)}.ui-btn--error.ui-btn--subtle,.ui-btn--error.ui-btn--ghost{background:transparent;color:var(--color-error-600)}.ui-btn--info.ui-btn--solid{background:var(--color-info-500);color:var(--color-neutral-0)}.ui-btn--info.ui-btn--solid:hover:not([disabled]){background:var(--color-info-600)}.ui-btn--info.ui-btn--outline{background:transparent;color:var(--color-info-600);border-color:var(--color-info-500)}.ui-btn--info.ui-btn--soft{background:color-mix(in srgb,var(--color-info-500) 15%,transparent);color:var(--color-info-700)}.ui-btn--info.ui-btn--subtle,.ui-btn--info.ui-btn--ghost{background:transparent;color:var(--color-info-600)}@keyframes ui-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
742
+ }
743
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ButtonComponent, decorators: [{
744
+ type: Component,
745
+ args: [{ selector: 'ui-button', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
746
+ <button
747
+ [type]="type()"
748
+ [disabled]="disabled() || loading()"
749
+ [class]="hostClasses()"
750
+ [attr.aria-disabled]="disabled() || loading()"
751
+ [attr.aria-label]="ariaLabel() ?? null"
752
+ [attr.aria-busy]="loading()"
753
+ >
754
+ <!-- Leading icon -->
755
+ @if (loading() && loadingPosition() === 'leading') {
756
+ <span class="ui-btn__spinner" aria-hidden="true">
757
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
758
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
759
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
760
+ </svg>
761
+ </span>
762
+ } @else if (leadingIcon() && !square()) {
763
+ <span class="ui-btn__icon ui-btn__icon--leading" aria-hidden="true">
764
+ <ng-content select="[slot=leading-icon]" />
765
+ </span>
766
+ }
767
+
768
+ <!-- Label -->
769
+ @if (!square()) {
770
+ <span class="ui-btn__label">
771
+ <ng-content />
772
+ </span>
773
+ }
774
+
775
+ <!-- Trailing icon or square icon -->
776
+ @if (loading() && loadingPosition() === 'trailing') {
777
+ <span class="ui-btn__spinner" aria-hidden="true">
778
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
779
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
780
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
781
+ </svg>
782
+ </span>
783
+ } @else if (trailingIcon() && !square()) {
784
+ <span class="ui-btn__icon ui-btn__icon--trailing" aria-hidden="true">
785
+ <ng-content select="[slot=trailing-icon]" />
786
+ </span>
787
+ }
788
+
789
+ <!-- Square/icon-only mode -->
790
+ @if (square()) {
791
+ <span class="ui-btn__icon" aria-hidden="true">
792
+ <ng-content select="[slot=icon]" />
793
+ </span>
794
+ }
795
+ </button>
796
+ `, styles: [".ui-btn{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;white-space:nowrap;cursor:pointer;border:1px solid transparent;border-radius:var(--radius-md);font-family:var(--font-sans);font-weight:var(--font-medium);text-decoration:none;outline:none;transition:var(--transition-colors);-webkit-user-select:none;user-select:none;position:relative;overflow:hidden}.ui-btn:focus-visible{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-btn--xs{height:var(--size-xs);padding:4px 8px;font-size:var(--text-xs)}.ui-btn--xs .ui-btn__icon{width:var(--icon-xs);height:var(--icon-xs)}.ui-btn--xs.ui-btn--square{width:var(--size-xs);padding:0}.ui-btn--sm{height:var(--size-sm);padding:6px 10px;font-size:var(--text-xs)}.ui-btn--sm .ui-btn__icon{width:var(--icon-sm);height:var(--icon-sm)}.ui-btn--sm.ui-btn--square{width:var(--size-sm);padding:0}.ui-btn--md{height:var(--size-md);padding:6px 10px;font-size:var(--text-sm)}.ui-btn--md .ui-btn__icon{width:var(--icon-md);height:var(--icon-md)}.ui-btn--md.ui-btn--square{width:var(--size-md);padding:0}.ui-btn--lg{height:var(--size-lg);padding:8px 12px;font-size:var(--text-sm)}.ui-btn--lg .ui-btn__icon{width:var(--icon-md);height:var(--icon-md)}.ui-btn--lg.ui-btn--square{width:var(--size-lg);padding:0}.ui-btn--xl{height:var(--size-xl);padding:8px 12px;font-size:var(--text-md)}.ui-btn--xl .ui-btn__icon{width:var(--icon-lg);height:var(--icon-lg)}.ui-btn--xl.ui-btn--square{width:var(--size-xl);padding:0}.ui-btn--block{width:100%}.ui-btn__icon{display:flex;align-items:center;justify-content:center;flex-shrink:0}.ui-btn__spinner{display:flex;align-items:center;width:1em;height:1em;flex-shrink:0}.ui-btn__spinner svg{width:100%;height:100%;animation:ui-spin .75s linear infinite}.ui-btn[disabled],.ui-btn--disabled{cursor:not-allowed;opacity:.5}.ui-btn--loading{cursor:wait}.ui-btn--primary.ui-btn--solid{background:var(--color-primary-500);color:var(--color-neutral-0)}.ui-btn--primary.ui-btn--solid:hover:not([disabled]){background:var(--color-primary-600)}.ui-btn--primary.ui-btn--solid:active:not([disabled]){background:var(--color-primary-700)}.ui-btn--primary.ui-btn--outline{background:transparent;color:var(--color-primary-500);border-color:var(--color-primary-500)}.ui-btn--primary.ui-btn--outline:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-btn--primary.ui-btn--soft{background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-700)}.ui-btn--primary.ui-btn--soft:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.ui-btn--primary.ui-btn--subtle{background:transparent;color:var(--color-primary-500)}.ui-btn--primary.ui-btn--subtle:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-btn--primary.ui-btn--ghost{background:transparent;color:var(--color-primary-500)}.ui-btn--primary.ui-btn--ghost:hover:not([disabled]){background:color-mix(in srgb,var(--color-primary-500) 8%,transparent)}.ui-btn--primary.ui-btn--link{background:transparent;color:var(--color-primary-500);text-decoration:underline;padding-left:0;padding-right:0;height:auto}.ui-btn--primary.ui-btn--link:hover:not([disabled]){color:var(--color-primary-600)}.ui-btn--neutral.ui-btn--solid{background:var(--color-neutral-900);color:var(--color-neutral-0)}.ui-btn--neutral.ui-btn--solid:hover:not([disabled]){background:var(--color-neutral-800)}.ui-btn--neutral.ui-btn--outline{background:transparent;color:var(--color-neutral-700);border-color:var(--color-neutral-300)}.ui-btn--neutral.ui-btn--outline:hover:not([disabled]){background:var(--color-neutral-50)}.ui-btn--neutral.ui-btn--soft{background:var(--color-neutral-100);color:var(--color-neutral-700)}.ui-btn--neutral.ui-btn--soft:hover:not([disabled]){background:var(--color-neutral-200)}.ui-btn--neutral.ui-btn--subtle{background:transparent;color:var(--color-neutral-600)}.ui-btn--neutral.ui-btn--subtle:hover:not([disabled]){background:var(--color-neutral-100)}.ui-btn--neutral.ui-btn--ghost{background:transparent;color:var(--color-neutral-600)}.ui-btn--neutral.ui-btn--ghost:hover:not([disabled]){background:var(--color-neutral-100)}.ui-btn--neutral.ui-btn--link{background:transparent;color:var(--color-neutral-600);text-decoration:underline;padding-left:0;padding-right:0;height:auto}.ui-btn--success.ui-btn--solid{background:var(--color-success-500);color:var(--color-neutral-0)}.ui-btn--success.ui-btn--solid:hover:not([disabled]){background:var(--color-success-600)}.ui-btn--success.ui-btn--outline{background:transparent;color:var(--color-success-600);border-color:var(--color-success-500)}.ui-btn--success.ui-btn--soft{background:color-mix(in srgb,var(--color-success-500) 15%,transparent);color:var(--color-success-700)}.ui-btn--success.ui-btn--subtle,.ui-btn--success.ui-btn--ghost{background:transparent;color:var(--color-success-600)}.ui-btn--warning.ui-btn--solid{background:var(--color-warning-500);color:var(--color-neutral-0)}.ui-btn--warning.ui-btn--solid:hover:not([disabled]){background:var(--color-warning-600)}.ui-btn--warning.ui-btn--outline{background:transparent;color:var(--color-warning-600);border-color:var(--color-warning-500)}.ui-btn--warning.ui-btn--soft{background:color-mix(in srgb,var(--color-warning-500) 15%,transparent);color:var(--color-warning-700)}.ui-btn--warning.ui-btn--subtle,.ui-btn--warning.ui-btn--ghost{background:transparent;color:var(--color-warning-600)}.ui-btn--error.ui-btn--solid{background:var(--color-error-500);color:var(--color-neutral-0)}.ui-btn--error.ui-btn--solid:hover:not([disabled]){background:var(--color-error-600)}.ui-btn--error.ui-btn--outline{background:transparent;color:var(--color-error-600);border-color:var(--color-error-500)}.ui-btn--error.ui-btn--soft{background:color-mix(in srgb,var(--color-error-500) 15%,transparent);color:var(--color-error-700)}.ui-btn--error.ui-btn--subtle,.ui-btn--error.ui-btn--ghost{background:transparent;color:var(--color-error-600)}.ui-btn--info.ui-btn--solid{background:var(--color-info-500);color:var(--color-neutral-0)}.ui-btn--info.ui-btn--solid:hover:not([disabled]){background:var(--color-info-600)}.ui-btn--info.ui-btn--outline{background:transparent;color:var(--color-info-600);border-color:var(--color-info-500)}.ui-btn--info.ui-btn--soft{background:color-mix(in srgb,var(--color-info-500) 15%,transparent);color:var(--color-info-700)}.ui-btn--info.ui-btn--subtle,.ui-btn--info.ui-btn--ghost{background:transparent;color:var(--color-info-600)}@keyframes ui-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
797
+ }] });
798
+
799
+ /**
800
+ * Checkbox Atom — Source: Nuxt UI v3 ❖ Checkbox
801
+ * CVA-compatible, accessible (ARIA), indeterminate state
802
+ */
803
+ class CheckboxComponent {
804
+ constructor() {
805
+ this.size = input('md');
806
+ this.color = input('primary');
807
+ this.label = input(null);
808
+ this.disabled = input(false);
809
+ this.indeterminate = input(false);
810
+ this.required = input(false);
811
+ this.ariaLabel = input(null);
812
+ this.checked = model(false);
813
+ this._onChange = () => { };
814
+ this._onTouched = () => { };
815
+ }
816
+ writeValue(v) { this.checked.set(v); }
817
+ registerOnChange(fn) { this._onChange = fn; }
818
+ registerOnTouched(fn) { this._onTouched = fn; }
819
+ setDisabledState(_) { }
820
+ onChange(e) {
821
+ const checked = e.target.checked;
822
+ this.checked.set(checked);
823
+ this._onChange(checked);
824
+ this._onTouched();
825
+ }
826
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
827
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: CheckboxComponent, isStandalone: true, selector: "ui-checkbox", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CheckboxComponent), multi: true }], ngImport: i0, template: `
828
+ <label class="ui-checkbox" [class.ui-checkbox--disabled]="disabled()">
829
+ <span class="ui-checkbox__control ui-checkbox__control--{{ size() }} ui-checkbox__control--{{ color() }}"
830
+ [class.ui-checkbox__control--checked]="checked()"
831
+ [class.ui-checkbox__control--indeterminate]="indeterminate()">
832
+ <input
833
+ type="checkbox"
834
+ class="ui-checkbox__input"
835
+ [checked]="checked()"
836
+ [disabled]="disabled()"
837
+ [indeterminate]="indeterminate()"
838
+ [attr.aria-label]="ariaLabel() ?? null"
839
+ (change)="onChange($event)"
840
+ />
841
+ @if (indeterminate()) {
842
+ <span class="ui-checkbox__icon ui-checkbox__icon--indeterminate" aria-hidden="true">—</span>
843
+ } @else if (checked()) {
844
+ <span class="ui-checkbox__icon" aria-hidden="true">✓</span>
845
+ }
846
+ </span>
847
+ @if (label()) {
848
+ <span class="ui-checkbox__label ui-checkbox__label--{{ size() }}">
849
+ {{ label() }}
850
+ @if (required()) { <span class="ui-checkbox__required" aria-hidden="true">*</span> }
851
+ </span>
852
+ }
853
+ </label>
854
+ `, isInline: true, styles: [".ui-checkbox{display:inline-flex;align-items:flex-start;gap:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none}.ui-checkbox--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ui-checkbox__input{position:absolute;opacity:0;width:0;height:0}.ui-checkbox__control{position:relative;display:flex;align-items:center;justify-content:center;flex-shrink:0;border:1.5px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg);transition:var(--transition-colors)}.ui-checkbox__control--xs{width:14px;height:14px}.ui-checkbox__control--sm{width:16px;height:16px}.ui-checkbox__control--md{width:18px;height:18px}.ui-checkbox__control--lg{width:20px;height:20px}.ui-checkbox__control--xl{width:22px;height:22px}.ui-checkbox__control--checked.ui-checkbox__control--primary,.ui-checkbox__control--indeterminate.ui-checkbox__control--primary{background:var(--color-primary-500);border-color:var(--color-primary-500);color:#fff}.ui-checkbox__control--checked.ui-checkbox__control--neutral,.ui-checkbox__control--indeterminate.ui-checkbox__control--neutral{background:var(--color-neutral-800);border-color:var(--color-neutral-800);color:#fff}.ui-checkbox__control--checked.ui-checkbox__control--success,.ui-checkbox__control--indeterminate.ui-checkbox__control--success{background:var(--color-success-500);border-color:var(--color-success-500);color:#fff}.ui-checkbox__control--checked.ui-checkbox__control--error,.ui-checkbox__control--indeterminate.ui-checkbox__control--error{background:var(--color-error-500);border-color:var(--color-error-500);color:#fff}.ui-checkbox__control:focus-within{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-checkbox__icon{font-size:11px;font-weight:700;line-height:1}.ui-checkbox__label{font-family:var(--font-sans);color:var(--color-text)}.ui-checkbox__label--xs,.ui-checkbox__label--sm{font-size:var(--text-xs)}.ui-checkbox__label--md{font-size:var(--text-sm)}.ui-checkbox__label--lg{font-size:var(--text-md)}.ui-checkbox__label--xl{font-size:var(--text-lg)}.ui-checkbox__required{color:var(--color-error-500);margin-left:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
855
+ }
856
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CheckboxComponent, decorators: [{
857
+ type: Component,
858
+ args: [{ selector: 'ui-checkbox', standalone: true, imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CheckboxComponent), multi: true }], template: `
859
+ <label class="ui-checkbox" [class.ui-checkbox--disabled]="disabled()">
860
+ <span class="ui-checkbox__control ui-checkbox__control--{{ size() }} ui-checkbox__control--{{ color() }}"
861
+ [class.ui-checkbox__control--checked]="checked()"
862
+ [class.ui-checkbox__control--indeterminate]="indeterminate()">
863
+ <input
864
+ type="checkbox"
865
+ class="ui-checkbox__input"
866
+ [checked]="checked()"
867
+ [disabled]="disabled()"
868
+ [indeterminate]="indeterminate()"
869
+ [attr.aria-label]="ariaLabel() ?? null"
870
+ (change)="onChange($event)"
871
+ />
872
+ @if (indeterminate()) {
873
+ <span class="ui-checkbox__icon ui-checkbox__icon--indeterminate" aria-hidden="true">—</span>
874
+ } @else if (checked()) {
875
+ <span class="ui-checkbox__icon" aria-hidden="true">✓</span>
876
+ }
877
+ </span>
878
+ @if (label()) {
879
+ <span class="ui-checkbox__label ui-checkbox__label--{{ size() }}">
880
+ {{ label() }}
881
+ @if (required()) { <span class="ui-checkbox__required" aria-hidden="true">*</span> }
882
+ </span>
883
+ }
884
+ </label>
885
+ `, styles: [".ui-checkbox{display:inline-flex;align-items:flex-start;gap:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none}.ui-checkbox--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ui-checkbox__input{position:absolute;opacity:0;width:0;height:0}.ui-checkbox__control{position:relative;display:flex;align-items:center;justify-content:center;flex-shrink:0;border:1.5px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg);transition:var(--transition-colors)}.ui-checkbox__control--xs{width:14px;height:14px}.ui-checkbox__control--sm{width:16px;height:16px}.ui-checkbox__control--md{width:18px;height:18px}.ui-checkbox__control--lg{width:20px;height:20px}.ui-checkbox__control--xl{width:22px;height:22px}.ui-checkbox__control--checked.ui-checkbox__control--primary,.ui-checkbox__control--indeterminate.ui-checkbox__control--primary{background:var(--color-primary-500);border-color:var(--color-primary-500);color:#fff}.ui-checkbox__control--checked.ui-checkbox__control--neutral,.ui-checkbox__control--indeterminate.ui-checkbox__control--neutral{background:var(--color-neutral-800);border-color:var(--color-neutral-800);color:#fff}.ui-checkbox__control--checked.ui-checkbox__control--success,.ui-checkbox__control--indeterminate.ui-checkbox__control--success{background:var(--color-success-500);border-color:var(--color-success-500);color:#fff}.ui-checkbox__control--checked.ui-checkbox__control--error,.ui-checkbox__control--indeterminate.ui-checkbox__control--error{background:var(--color-error-500);border-color:var(--color-error-500);color:#fff}.ui-checkbox__control:focus-within{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-checkbox__icon{font-size:11px;font-weight:700;line-height:1}.ui-checkbox__label{font-family:var(--font-sans);color:var(--color-text)}.ui-checkbox__label--xs,.ui-checkbox__label--sm{font-size:var(--text-xs)}.ui-checkbox__label--md{font-size:var(--text-sm)}.ui-checkbox__label--lg{font-size:var(--text-md)}.ui-checkbox__label--xl{font-size:var(--text-lg)}.ui-checkbox__required{color:var(--color-error-500);margin-left:2px}\n"] }]
886
+ }] });
887
+
888
+ /**
889
+ * Chip Atom — Source: Nuxt UI v3 ❖ Chip
890
+ * Small indicator overlaid on another element (e.g., notification dot)
891
+ */
892
+ class ChipComponent {
893
+ constructor() {
894
+ this.color = input('primary');
895
+ this.size = input('md');
896
+ this.position = input('top-right');
897
+ this.text = input(null);
898
+ }
899
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
900
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ChipComponent, isStandalone: true, selector: "ui-chip", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
901
+ <span class="ui-chip-wrap">
902
+ <ng-content />
903
+ <span [class]="'ui-chip ui-chip--' + color() + ' ui-chip--' + size() + ' ui-chip--' + position()">
904
+ @if (text()) { {{ text() }} }
905
+ </span>
906
+ </span>
907
+ `, isInline: true, styles: [".ui-chip-wrap{position:relative;display:inline-flex}.ui-chip{position:absolute;border:2px solid var(--color-bg);border-radius:var(--radius-full);font-family:var(--font-sans);font-weight:var(--font-medium);font-size:10px;display:flex;align-items:center;justify-content:center;z-index:var(--z-raised)}.ui-chip--xs{min-width:8px;height:8px;padding:0}.ui-chip--sm{min-width:10px;height:10px;padding:0}.ui-chip--md{min-width:16px;height:16px;padding:0 4px}.ui-chip--lg{min-width:18px;height:18px;padding:0 5px}.ui-chip--xl{min-width:20px;height:20px;padding:0 6px}.ui-chip--top-right{top:0;right:0;transform:translate(30%,-30%)}.ui-chip--top-left{top:0;left:0;transform:translate(-30%,-30%)}.ui-chip--bottom-right{bottom:0;right:0;transform:translate(30%,30%)}.ui-chip--bottom-left{bottom:0;left:0;transform:translate(-30%,30%)}.ui-chip--primary{background:var(--color-primary-500);color:#fff}.ui-chip--secondary{background:var(--color-secondary-500);color:#fff}.ui-chip--neutral{background:var(--color-neutral-500);color:#fff}.ui-chip--success{background:var(--color-success-500);color:#fff}.ui-chip--warning{background:var(--color-warning-500);color:#fff}.ui-chip--error{background:var(--color-error-500);color:#fff}.ui-chip--info{background:var(--color-info-500);color:#fff}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
908
+ }
909
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChipComponent, decorators: [{
910
+ type: Component,
911
+ args: [{ selector: 'ui-chip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
912
+ <span class="ui-chip-wrap">
913
+ <ng-content />
914
+ <span [class]="'ui-chip ui-chip--' + color() + ' ui-chip--' + size() + ' ui-chip--' + position()">
915
+ @if (text()) { {{ text() }} }
916
+ </span>
917
+ </span>
918
+ `, styles: [".ui-chip-wrap{position:relative;display:inline-flex}.ui-chip{position:absolute;border:2px solid var(--color-bg);border-radius:var(--radius-full);font-family:var(--font-sans);font-weight:var(--font-medium);font-size:10px;display:flex;align-items:center;justify-content:center;z-index:var(--z-raised)}.ui-chip--xs{min-width:8px;height:8px;padding:0}.ui-chip--sm{min-width:10px;height:10px;padding:0}.ui-chip--md{min-width:16px;height:16px;padding:0 4px}.ui-chip--lg{min-width:18px;height:18px;padding:0 5px}.ui-chip--xl{min-width:20px;height:20px;padding:0 6px}.ui-chip--top-right{top:0;right:0;transform:translate(30%,-30%)}.ui-chip--top-left{top:0;left:0;transform:translate(-30%,-30%)}.ui-chip--bottom-right{bottom:0;right:0;transform:translate(30%,30%)}.ui-chip--bottom-left{bottom:0;left:0;transform:translate(-30%,30%)}.ui-chip--primary{background:var(--color-primary-500);color:#fff}.ui-chip--secondary{background:var(--color-secondary-500);color:#fff}.ui-chip--neutral{background:var(--color-neutral-500);color:#fff}.ui-chip--success{background:var(--color-success-500);color:#fff}.ui-chip--warning{background:var(--color-warning-500);color:#fff}.ui-chip--error{background:var(--color-error-500);color:#fff}.ui-chip--info{background:var(--color-info-500);color:#fff}\n"] }]
919
+ }] });
920
+
921
+ /**
922
+ * Kbd Atom — Source: Nuxt UI v3 ❖ Kbd
923
+ * Keyboard key indicator
924
+ */
925
+ class KbdComponent {
926
+ constructor() {
927
+ this.size = input('md');
928
+ this.variant = input('outline');
929
+ }
930
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: KbdComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
931
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.20", type: KbdComponent, isStandalone: true, selector: "ui-kbd", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<kbd [class]="'ui-kbd ui-kbd--' + size() + ' ui-kbd--' + variant()"><ng-content /></kbd>`, isInline: true, styles: [".ui-kbd{display:inline-flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:var(--font-medium);border-radius:var(--radius-md);white-space:nowrap}.ui-kbd--xs{padding:1px 4px;font-size:10px}.ui-kbd--sm{padding:2px 6px;font-size:11px}.ui-kbd--md{padding:2px 8px;font-size:12px}.ui-kbd--lg{padding:3px 10px;font-size:13px}.ui-kbd--xl{padding:4px 12px;font-size:14px}.ui-kbd--solid{background:var(--color-neutral-800);color:#fff}.ui-kbd--outline{background:var(--color-bg);color:var(--color-text);border:1px solid var(--color-border);box-shadow:0 1px 0 var(--color-border)}.ui-kbd--subtle{background:var(--color-neutral-100);color:var(--color-neutral-700)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
932
+ }
933
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: KbdComponent, decorators: [{
934
+ type: Component,
935
+ args: [{ selector: 'ui-kbd', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<kbd [class]="'ui-kbd ui-kbd--' + size() + ' ui-kbd--' + variant()"><ng-content /></kbd>`, styles: [".ui-kbd{display:inline-flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:var(--font-medium);border-radius:var(--radius-md);white-space:nowrap}.ui-kbd--xs{padding:1px 4px;font-size:10px}.ui-kbd--sm{padding:2px 6px;font-size:11px}.ui-kbd--md{padding:2px 8px;font-size:12px}.ui-kbd--lg{padding:3px 10px;font-size:13px}.ui-kbd--xl{padding:4px 12px;font-size:14px}.ui-kbd--solid{background:var(--color-neutral-800);color:#fff}.ui-kbd--outline{background:var(--color-bg);color:var(--color-text);border:1px solid var(--color-border);box-shadow:0 1px 0 var(--color-border)}.ui-kbd--subtle{background:var(--color-neutral-100);color:var(--color-neutral-700)}\n"] }]
936
+ }] });
937
+
938
+ /**
939
+ * Link Atom — Source: Nuxt UI v3 ❖ Link
940
+ * Router-aware link with external support
941
+ */
942
+ class LinkComponent {
943
+ constructor() {
944
+ this.href = input(null);
945
+ this.to = input(null);
946
+ this.external = input(false);
947
+ this.inactive = input(false);
948
+ this.classes = input('ui-link');
949
+ }
950
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: LinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
951
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: LinkComponent, isStandalone: true, selector: "ui-link", inputs: { href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, to: { classPropertyName: "to", publicName: "to", isSignal: true, isRequired: false, transformFunction: null }, external: { classPropertyName: "external", publicName: "external", isSignal: true, isRequired: false, transformFunction: null }, inactive: { classPropertyName: "inactive", publicName: "inactive", isSignal: true, isRequired: false, transformFunction: null }, classes: { classPropertyName: "classes", publicName: "classes", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
952
+ @if (external()) {
953
+ <a [href]="href()" [class]="classes()" target="_blank" rel="noopener noreferrer">
954
+ <ng-content />
955
+ </a>
956
+ } @else if (href()) {
957
+ <a [href]="href()" [class]="classes()"><ng-content /></a>
958
+ } @else {
959
+ <a [routerLink]="to()" [class]="classes()"><ng-content /></a>
960
+ }
961
+ `, isInline: true, styles: [".ui-link{color:var(--color-primary-500);text-decoration:none;font-family:var(--font-sans);transition:color var(--transition-fast);cursor:pointer}.ui-link:hover{color:var(--color-primary-600);text-decoration:underline}.ui-link:visited{color:var(--color-primary-700)}.ui-link:focus-visible{outline:2px solid var(--color-ring);outline-offset:2px;border-radius:var(--radius-sm)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
962
+ }
963
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: LinkComponent, decorators: [{
964
+ type: Component,
965
+ args: [{ selector: 'ui-link', standalone: true, imports: [CommonModule, RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
966
+ @if (external()) {
967
+ <a [href]="href()" [class]="classes()" target="_blank" rel="noopener noreferrer">
968
+ <ng-content />
969
+ </a>
970
+ } @else if (href()) {
971
+ <a [href]="href()" [class]="classes()"><ng-content /></a>
972
+ } @else {
973
+ <a [routerLink]="to()" [class]="classes()"><ng-content /></a>
974
+ }
975
+ `, styles: [".ui-link{color:var(--color-primary-500);text-decoration:none;font-family:var(--font-sans);transition:color var(--transition-fast);cursor:pointer}.ui-link:hover{color:var(--color-primary-600);text-decoration:underline}.ui-link:visited{color:var(--color-primary-700)}.ui-link:focus-visible{outline:2px solid var(--color-ring);outline-offset:2px;border-radius:var(--radius-sm)}\n"] }]
976
+ }] });
977
+
978
+ /**
979
+ * Progress Atom — Source: Nuxt UI v3 ❖ Progress
980
+ * Linear progress bar with indeterminate support
981
+ */
982
+ class ProgressComponent {
983
+ constructor() {
984
+ this.value = input(0);
985
+ this.max = input(100);
986
+ this.size = input('md');
987
+ this.color = input('primary');
988
+ this.indeterminate = input(false);
989
+ this.label = input(null);
990
+ this.showValue = input(false);
991
+ this.percentage = computed(() => Math.min(100, Math.max(0, Math.round((this.value() / this.max()) * 100))));
992
+ }
993
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ProgressComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
994
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ProgressComponent, isStandalone: true, selector: "ui-progress", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
995
+ <div class="ui-progress" [class]="'ui-progress--' + size()">
996
+ @if (label()) {
997
+ <div class="ui-progress__label">{{ label() }}</div>
998
+ }
999
+ <div
1000
+ class="ui-progress__track"
1001
+ role="progressbar"
1002
+ [attr.aria-valuenow]="indeterminate() ? null : value()"
1003
+ [attr.aria-valuemin]="0"
1004
+ [attr.aria-valuemax]="max()"
1005
+ [attr.aria-label]="label() ?? 'Progress'"
1006
+ >
1007
+ <div
1008
+ class="ui-progress__bar"
1009
+ [class]="'ui-progress__bar--' + color() + (indeterminate() ? ' ui-progress__bar--indeterminate' : '')"
1010
+ [style.width]="indeterminate() ? null : percentage() + '%'"
1011
+ ></div>
1012
+ </div>
1013
+ @if (showValue() && !indeterminate()) {
1014
+ <span class="ui-progress__value">{{ percentage() }}%</span>
1015
+ }
1016
+ </div>
1017
+ `, isInline: true, styles: [".ui-progress{display:flex;flex-direction:column;gap:var(--spacing-1)}.ui-progress--xs .ui-progress__track{height:4px;border-radius:var(--radius-full)}.ui-progress--sm .ui-progress__track{height:6px;border-radius:var(--radius-full)}.ui-progress--md .ui-progress__track{height:8px;border-radius:var(--radius-full)}.ui-progress--lg .ui-progress__track{height:10px;border-radius:var(--radius-full)}.ui-progress--xl .ui-progress__track{height:12px;border-radius:var(--radius-full)}.ui-progress__track{width:100%;background:var(--color-neutral-100);overflow:hidden}.ui-progress__bar{height:100%;border-radius:inherit;transition:width var(--transition-slow)}.ui-progress__bar--primary{background:var(--color-primary-500)}.ui-progress__bar--neutral{background:var(--color-neutral-600)}.ui-progress__bar--success{background:var(--color-success-500)}.ui-progress__bar--warning{background:var(--color-warning-500)}.ui-progress__bar--error{background:var(--color-error-500)}.ui-progress__bar--info{background:var(--color-info-500)}.ui-progress__bar--indeterminate{width:40%!important;animation:ui-progress-slide 1.5s ease-in-out infinite}.ui-progress__label{font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text)}.ui-progress__value{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-text-muted);text-align:right}@keyframes ui-progress-slide{0%{transform:translate(-150%)}to{transform:translate(350%)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1018
+ }
1019
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ProgressComponent, decorators: [{
1020
+ type: Component,
1021
+ args: [{ selector: 'ui-progress', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1022
+ <div class="ui-progress" [class]="'ui-progress--' + size()">
1023
+ @if (label()) {
1024
+ <div class="ui-progress__label">{{ label() }}</div>
1025
+ }
1026
+ <div
1027
+ class="ui-progress__track"
1028
+ role="progressbar"
1029
+ [attr.aria-valuenow]="indeterminate() ? null : value()"
1030
+ [attr.aria-valuemin]="0"
1031
+ [attr.aria-valuemax]="max()"
1032
+ [attr.aria-label]="label() ?? 'Progress'"
1033
+ >
1034
+ <div
1035
+ class="ui-progress__bar"
1036
+ [class]="'ui-progress__bar--' + color() + (indeterminate() ? ' ui-progress__bar--indeterminate' : '')"
1037
+ [style.width]="indeterminate() ? null : percentage() + '%'"
1038
+ ></div>
1039
+ </div>
1040
+ @if (showValue() && !indeterminate()) {
1041
+ <span class="ui-progress__value">{{ percentage() }}%</span>
1042
+ }
1043
+ </div>
1044
+ `, styles: [".ui-progress{display:flex;flex-direction:column;gap:var(--spacing-1)}.ui-progress--xs .ui-progress__track{height:4px;border-radius:var(--radius-full)}.ui-progress--sm .ui-progress__track{height:6px;border-radius:var(--radius-full)}.ui-progress--md .ui-progress__track{height:8px;border-radius:var(--radius-full)}.ui-progress--lg .ui-progress__track{height:10px;border-radius:var(--radius-full)}.ui-progress--xl .ui-progress__track{height:12px;border-radius:var(--radius-full)}.ui-progress__track{width:100%;background:var(--color-neutral-100);overflow:hidden}.ui-progress__bar{height:100%;border-radius:inherit;transition:width var(--transition-slow)}.ui-progress__bar--primary{background:var(--color-primary-500)}.ui-progress__bar--neutral{background:var(--color-neutral-600)}.ui-progress__bar--success{background:var(--color-success-500)}.ui-progress__bar--warning{background:var(--color-warning-500)}.ui-progress__bar--error{background:var(--color-error-500)}.ui-progress__bar--info{background:var(--color-info-500)}.ui-progress__bar--indeterminate{width:40%!important;animation:ui-progress-slide 1.5s ease-in-out infinite}.ui-progress__label{font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text)}.ui-progress__value{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-text-muted);text-align:right}@keyframes ui-progress-slide{0%{transform:translate(-150%)}to{transform:translate(350%)}}\n"] }]
1045
+ }] });
1046
+
1047
+ /**
1048
+ * Separator Atom — Source: Nuxt UI v3 ❖ Separator
1049
+ * Horizontal or vertical divider, optionally with label
1050
+ */
1051
+ class SeparatorComponent {
1052
+ constructor() {
1053
+ this.orientation = input('horizontal');
1054
+ this.label = input(null);
1055
+ this.type = input('solid');
1056
+ }
1057
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1058
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SeparatorComponent, isStandalone: true, selector: "ui-separator", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1059
+ <div [class]="'ui-separator ui-separator--' + orientation() + (label() ? ' ui-separator--labeled' : '')"
1060
+ role="separator"
1061
+ [attr.aria-orientation]="orientation()">
1062
+ @if (label()) {
1063
+ <span class="ui-separator__label">{{ label() }}</span>
1064
+ }
1065
+ </div>
1066
+ `, isInline: true, styles: [".ui-separator{--sep-color: var(--color-border);flex-shrink:0}.ui-separator--horizontal{width:100%;height:1px;background:var(--sep-color);margin:var(--spacing-4) 0}.ui-separator--vertical{width:1px;height:100%;min-height:1em;background:var(--sep-color);margin:0 var(--spacing-4)}.ui-separator--labeled{display:flex;align-items:center;gap:var(--spacing-3);background:none;height:auto}.ui-separator--labeled:before,.ui-separator--labeled:after{content:\"\";flex:1;height:1px;background:var(--sep-color)}.ui-separator__label{font-family:var(--font-sans);font-size:var(--text-xs);font-weight:var(--font-medium);color:var(--color-text-muted);white-space:nowrap;padding:0 var(--spacing-2)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1067
+ }
1068
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SeparatorComponent, decorators: [{
1069
+ type: Component,
1070
+ args: [{ selector: 'ui-separator', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1071
+ <div [class]="'ui-separator ui-separator--' + orientation() + (label() ? ' ui-separator--labeled' : '')"
1072
+ role="separator"
1073
+ [attr.aria-orientation]="orientation()">
1074
+ @if (label()) {
1075
+ <span class="ui-separator__label">{{ label() }}</span>
1076
+ }
1077
+ </div>
1078
+ `, styles: [".ui-separator{--sep-color: var(--color-border);flex-shrink:0}.ui-separator--horizontal{width:100%;height:1px;background:var(--sep-color);margin:var(--spacing-4) 0}.ui-separator--vertical{width:1px;height:100%;min-height:1em;background:var(--sep-color);margin:0 var(--spacing-4)}.ui-separator--labeled{display:flex;align-items:center;gap:var(--spacing-3);background:none;height:auto}.ui-separator--labeled:before,.ui-separator--labeled:after{content:\"\";flex:1;height:1px;background:var(--sep-color)}.ui-separator__label{font-family:var(--font-sans);font-size:var(--text-xs);font-weight:var(--font-medium);color:var(--color-text-muted);white-space:nowrap;padding:0 var(--spacing-2)}\n"] }]
1079
+ }] });
1080
+
1081
+ /**
1082
+ * Skeleton Atom — Source: Nuxt UI v3 ❖ Skeleton
1083
+ * Loading placeholder with shimmer animation
1084
+ */
1085
+ class SkeletonComponent {
1086
+ constructor() {
1087
+ this.width = input('100%');
1088
+ this.height = input('1rem');
1089
+ this.rounded = input(false);
1090
+ }
1091
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SkeletonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1092
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.20", type: SkeletonComponent, isStandalone: true, selector: "ui-skeleton", inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<div [class]="'ui-skeleton' + (rounded() ? ' ui-skeleton--rounded' : '')"
1093
+ [style.width]="width()" [style.height]="height()" role="status" aria-label="Loading..."></div>`, isInline: true, styles: [".ui-skeleton{background:linear-gradient(90deg,var(--color-neutral-100) 25%,var(--color-neutral-200) 50%,var(--color-neutral-100) 75%);background-size:200% 100%;animation:ui-shimmer 1.5s ease-in-out infinite;border-radius:var(--radius-md);display:block}.ui-skeleton--rounded{border-radius:var(--radius-full)}@keyframes ui-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1094
+ }
1095
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SkeletonComponent, decorators: [{
1096
+ type: Component,
1097
+ args: [{ selector: 'ui-skeleton', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<div [class]="'ui-skeleton' + (rounded() ? ' ui-skeleton--rounded' : '')"
1098
+ [style.width]="width()" [style.height]="height()" role="status" aria-label="Loading..."></div>`, styles: [".ui-skeleton{background:linear-gradient(90deg,var(--color-neutral-100) 25%,var(--color-neutral-200) 50%,var(--color-neutral-100) 75%);background-size:200% 100%;animation:ui-shimmer 1.5s ease-in-out infinite;border-radius:var(--radius-md);display:block}.ui-skeleton--rounded{border-radius:var(--radius-full)}@keyframes ui-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"] }]
1099
+ }] });
1100
+
1101
+ /**
1102
+ * Slider Atom — Source: Nuxt UI v3 ❖ Slider
1103
+ * Range input with custom styling
1104
+ */
1105
+ class SliderComponent {
1106
+ constructor() {
1107
+ this.min = input(0);
1108
+ this.max = input(100);
1109
+ this.step = input(1);
1110
+ this.size = input('md');
1111
+ this.color = input('primary');
1112
+ this.disabled = input(false);
1113
+ this.value = model(0);
1114
+ this._onChange = () => { };
1115
+ this._onTouched = () => { };
1116
+ }
1117
+ onInput(e) {
1118
+ const val = Number(e.target.value);
1119
+ this.value.set(val);
1120
+ this._onChange(val);
1121
+ this._onTouched();
1122
+ }
1123
+ writeValue(v) { this.value.set(v); }
1124
+ registerOnChange(fn) { this._onChange = fn; }
1125
+ registerOnTouched(fn) { this._onTouched = fn; }
1126
+ setDisabledState(_) { }
1127
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1128
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.20", type: SliderComponent, isStandalone: true, selector: "ui-slider", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SliderComponent), multi: true }], ngImport: i0, template: `
1129
+ <div class="ui-slider ui-slider--{{ size() }}">
1130
+ <input
1131
+ type="range"
1132
+ class="ui-slider__input ui-slider__input--{{ color() }}"
1133
+ [min]="min()"
1134
+ [max]="max()"
1135
+ [step]="step()"
1136
+ [value]="value()"
1137
+ [disabled]="disabled()"
1138
+ (input)="onInput($event)"
1139
+ />
1140
+ </div>
1141
+ `, isInline: true, styles: [".ui-slider{display:flex;align-items:center;width:100%}.ui-slider--xs{height:var(--size-xs)}.ui-slider--sm{height:var(--size-sm)}.ui-slider--md{height:var(--size-md)}.ui-slider--lg{height:var(--size-lg)}.ui-slider--xl{height:var(--size-xl)}.ui-slider__input{-webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:var(--radius-full);background:var(--color-neutral-200);cursor:pointer;outline:none}.ui-slider__input::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;border:2px solid white;box-shadow:var(--shadow-sm);transition:transform var(--transition-fast)}.ui-slider__input:focus-visible{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-slider__input--primary::-webkit-slider-thumb{background:var(--color-primary-500)}.ui-slider__input--neutral::-webkit-slider-thumb{background:var(--color-neutral-600)}.ui-slider__input--success::-webkit-slider-thumb{background:var(--color-success-500)}.ui-slider__input--warning::-webkit-slider-thumb{background:var(--color-warning-500)}.ui-slider__input--error::-webkit-slider-thumb{background:var(--color-error-500)}.ui-slider__input:disabled{opacity:.5;cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1142
+ }
1143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SliderComponent, decorators: [{
1144
+ type: Component,
1145
+ args: [{ selector: 'ui-slider', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SliderComponent), multi: true }], template: `
1146
+ <div class="ui-slider ui-slider--{{ size() }}">
1147
+ <input
1148
+ type="range"
1149
+ class="ui-slider__input ui-slider__input--{{ color() }}"
1150
+ [min]="min()"
1151
+ [max]="max()"
1152
+ [step]="step()"
1153
+ [value]="value()"
1154
+ [disabled]="disabled()"
1155
+ (input)="onInput($event)"
1156
+ />
1157
+ </div>
1158
+ `, styles: [".ui-slider{display:flex;align-items:center;width:100%}.ui-slider--xs{height:var(--size-xs)}.ui-slider--sm{height:var(--size-sm)}.ui-slider--md{height:var(--size-md)}.ui-slider--lg{height:var(--size-lg)}.ui-slider--xl{height:var(--size-xl)}.ui-slider__input{-webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:var(--radius-full);background:var(--color-neutral-200);cursor:pointer;outline:none}.ui-slider__input::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;border:2px solid white;box-shadow:var(--shadow-sm);transition:transform var(--transition-fast)}.ui-slider__input:focus-visible{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-slider__input--primary::-webkit-slider-thumb{background:var(--color-primary-500)}.ui-slider__input--neutral::-webkit-slider-thumb{background:var(--color-neutral-600)}.ui-slider__input--success::-webkit-slider-thumb{background:var(--color-success-500)}.ui-slider__input--warning::-webkit-slider-thumb{background:var(--color-warning-500)}.ui-slider__input--error::-webkit-slider-thumb{background:var(--color-error-500)}.ui-slider__input:disabled{opacity:.5;cursor:not-allowed}\n"] }]
1159
+ }] });
1160
+
1161
+ /**
1162
+ * Switch Atom — Source: Nuxt UI v3 ❖ Switch
1163
+ * Toggle control with label support and CVA
1164
+ */
1165
+ class SwitchComponent {
1166
+ constructor() {
1167
+ this.size = input('md');
1168
+ this.color = input('primary');
1169
+ this.label = input(null);
1170
+ this.disabled = input(false);
1171
+ this.checked = model(false);
1172
+ this._onChange = () => { };
1173
+ this._onTouched = () => { };
1174
+ }
1175
+ toggle() {
1176
+ if (this.disabled())
1177
+ return;
1178
+ this.checked.update(v => !v);
1179
+ this._onChange(this.checked());
1180
+ this._onTouched();
1181
+ }
1182
+ writeValue(v) { this.checked.set(v); }
1183
+ registerOnChange(fn) { this._onChange = fn; }
1184
+ registerOnTouched(fn) { this._onTouched = fn; }
1185
+ setDisabledState(_) { }
1186
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1187
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SwitchComponent, isStandalone: true, selector: "ui-switch", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SwitchComponent), multi: true }], ngImport: i0, template: `
1188
+ <label class="ui-switch" [class.ui-switch--disabled]="disabled()">
1189
+ <button
1190
+ type="button"
1191
+ role="switch"
1192
+ [class]="'ui-switch__track ui-switch__track--' + size() + ' ui-switch__track--' + color() + (checked() ? ' ui-switch__track--on' : '')"
1193
+ [attr.aria-checked]="checked()"
1194
+ [disabled]="disabled()"
1195
+ (click)="toggle()"
1196
+ >
1197
+ <span class="ui-switch__thumb" [class.ui-switch__thumb--on]="checked()"></span>
1198
+ </button>
1199
+ @if (label()) {
1200
+ <span class="ui-switch__label">{{ label() }}</span>
1201
+ }
1202
+ </label>
1203
+ `, isInline: true, styles: [".ui-switch{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer}.ui-switch--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ui-switch__track{position:relative;display:inline-flex;align-items:center;border:none;border-radius:var(--radius-full);background:var(--color-neutral-300);cursor:pointer;transition:background var(--transition-base);padding:2px}.ui-switch__track--xs{width:28px;height:16px}.ui-switch__track--sm{width:32px;height:18px}.ui-switch__track--md{width:40px;height:22px}.ui-switch__track--lg{width:48px;height:26px}.ui-switch__track--xl{width:56px;height:30px}.ui-switch__track--on.ui-switch__track--primary{background:var(--color-primary-500)}.ui-switch__track--on.ui-switch__track--neutral{background:var(--color-neutral-800)}.ui-switch__track--on.ui-switch__track--success{background:var(--color-success-500)}.ui-switch__track--on.ui-switch__track--warning{background:var(--color-warning-500)}.ui-switch__track--on.ui-switch__track--error{background:var(--color-error-500)}.ui-switch__track:focus-visible{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-switch__thumb{width:calc(50% - 2px);height:calc(100% - 4px);border-radius:50%;background:#fff;box-shadow:var(--shadow-xs);transition:transform var(--transition-base);transform:translate(0)}.ui-switch__thumb--on{transform:translate(100%)}.ui-switch__label{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1204
+ }
1205
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SwitchComponent, decorators: [{
1206
+ type: Component,
1207
+ args: [{ selector: 'ui-switch', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SwitchComponent), multi: true }], template: `
1208
+ <label class="ui-switch" [class.ui-switch--disabled]="disabled()">
1209
+ <button
1210
+ type="button"
1211
+ role="switch"
1212
+ [class]="'ui-switch__track ui-switch__track--' + size() + ' ui-switch__track--' + color() + (checked() ? ' ui-switch__track--on' : '')"
1213
+ [attr.aria-checked]="checked()"
1214
+ [disabled]="disabled()"
1215
+ (click)="toggle()"
1216
+ >
1217
+ <span class="ui-switch__thumb" [class.ui-switch__thumb--on]="checked()"></span>
1218
+ </button>
1219
+ @if (label()) {
1220
+ <span class="ui-switch__label">{{ label() }}</span>
1221
+ }
1222
+ </label>
1223
+ `, styles: [".ui-switch{display:inline-flex;align-items:center;gap:.5rem;cursor:pointer}.ui-switch--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ui-switch__track{position:relative;display:inline-flex;align-items:center;border:none;border-radius:var(--radius-full);background:var(--color-neutral-300);cursor:pointer;transition:background var(--transition-base);padding:2px}.ui-switch__track--xs{width:28px;height:16px}.ui-switch__track--sm{width:32px;height:18px}.ui-switch__track--md{width:40px;height:22px}.ui-switch__track--lg{width:48px;height:26px}.ui-switch__track--xl{width:56px;height:30px}.ui-switch__track--on.ui-switch__track--primary{background:var(--color-primary-500)}.ui-switch__track--on.ui-switch__track--neutral{background:var(--color-neutral-800)}.ui-switch__track--on.ui-switch__track--success{background:var(--color-success-500)}.ui-switch__track--on.ui-switch__track--warning{background:var(--color-warning-500)}.ui-switch__track--on.ui-switch__track--error{background:var(--color-error-500)}.ui-switch__track:focus-visible{box-shadow:0 0 0 2px var(--color-bg),0 0 0 4px var(--color-ring)}.ui-switch__thumb{width:calc(50% - 2px);height:calc(100% - 4px);border-radius:50%;background:#fff;box-shadow:var(--shadow-xs);transition:transform var(--transition-base);transform:translate(0)}.ui-switch__thumb--on{transform:translate(100%)}.ui-switch__label{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text)}\n"] }]
1224
+ }] });
1225
+
1226
+ /**
1227
+ * Tooltip Atom — Source: Nuxt UI v3 ❖ Tooltip
1228
+ * CSS-only hover tooltip with positioning
1229
+ */
1230
+ class TooltipComponent {
1231
+ constructor() {
1232
+ this.text = input.required();
1233
+ this.position = input('top');
1234
+ this.shortcut = input(null);
1235
+ this.delay = input(500);
1236
+ }
1237
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1238
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: TooltipComponent, isStandalone: true, selector: "ui-tooltip", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1239
+ <span class="ui-tooltip-wrap">
1240
+ <ng-content />
1241
+ <span class="ui-tooltip ui-tooltip--{{ position() }}" role="tooltip">
1242
+ {{ text() }}
1243
+ @if (shortcut()) {
1244
+ <kbd class="ui-tooltip__kbd">{{ shortcut() }}</kbd>
1245
+ }
1246
+ </span>
1247
+ </span>
1248
+ `, isInline: true, styles: [".ui-tooltip-wrap{position:relative;display:inline-flex;align-items:center}.ui-tooltip-wrap:hover .ui-tooltip,.ui-tooltip-wrap:focus-within .ui-tooltip{opacity:1;pointer-events:auto}.ui-tooltip{position:absolute;z-index:var(--z-tooltip);padding:5px 10px;background:var(--color-neutral-900);color:var(--color-neutral-0);font-family:var(--font-sans);font-size:var(--text-xs);font-weight:var(--font-medium);border-radius:var(--radius-md);white-space:nowrap;pointer-events:none;opacity:0;transition:opacity var(--transition-fast);box-shadow:var(--shadow-md)}.ui-tooltip--top{bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.ui-tooltip--bottom{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.ui-tooltip--left{right:calc(100% + 6px);top:50%;transform:translateY(-50%)}.ui-tooltip--right{left:calc(100% + 6px);top:50%;transform:translateY(-50%)}.ui-tooltip__kbd{display:inline-flex;align-items:center;justify-content:center;padding:1px 4px;margin-left:4px;background:var(--color-neutral-700);border-radius:var(--radius-sm);font-family:var(--font-mono);font-size:.7em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1249
+ }
1250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TooltipComponent, decorators: [{
1251
+ type: Component,
1252
+ args: [{ selector: 'ui-tooltip', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1253
+ <span class="ui-tooltip-wrap">
1254
+ <ng-content />
1255
+ <span class="ui-tooltip ui-tooltip--{{ position() }}" role="tooltip">
1256
+ {{ text() }}
1257
+ @if (shortcut()) {
1258
+ <kbd class="ui-tooltip__kbd">{{ shortcut() }}</kbd>
1259
+ }
1260
+ </span>
1261
+ </span>
1262
+ `, styles: [".ui-tooltip-wrap{position:relative;display:inline-flex;align-items:center}.ui-tooltip-wrap:hover .ui-tooltip,.ui-tooltip-wrap:focus-within .ui-tooltip{opacity:1;pointer-events:auto}.ui-tooltip{position:absolute;z-index:var(--z-tooltip);padding:5px 10px;background:var(--color-neutral-900);color:var(--color-neutral-0);font-family:var(--font-sans);font-size:var(--text-xs);font-weight:var(--font-medium);border-radius:var(--radius-md);white-space:nowrap;pointer-events:none;opacity:0;transition:opacity var(--transition-fast);box-shadow:var(--shadow-md)}.ui-tooltip--top{bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.ui-tooltip--bottom{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.ui-tooltip--left{right:calc(100% + 6px);top:50%;transform:translateY(-50%)}.ui-tooltip--right{left:calc(100% + 6px);top:50%;transform:translateY(-50%)}.ui-tooltip__kbd{display:inline-flex;align-items:center;justify-content:center;padding:1px 4px;margin-left:4px;background:var(--color-neutral-700);border-radius:var(--radius-sm);font-family:var(--font-mono);font-size:.7em}\n"] }]
1263
+ }] });
1264
+
1265
+ // ============================================================
1266
+ // ATOMS — Nuxt UI v3 Design Kit → Angular 19 + NX
1267
+ // Basic building blocks (no component dependencies)
1268
+ // ============================================================
1269
+
1270
+ /**
1271
+ * Alert Molecule — Source: Nuxt UI v3 ❖ Alert
1272
+ * Contextual messages with icon, title, description, actions
1273
+ * Built from: icon (atom) + content + optional close button
1274
+ */
1275
+ class AlertComponent {
1276
+ constructor() {
1277
+ this.variant = input('soft');
1278
+ this.color = input('info');
1279
+ this.title = input(null);
1280
+ this.description = input(null);
1281
+ this.icon = input(true);
1282
+ this.closable = input(false);
1283
+ this.actions = input(false);
1284
+ this.live = input('polite');
1285
+ this.close = output();
1286
+ }
1287
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1288
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: AlertComponent, isStandalone: true, selector: "ui-alert", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close" }, ngImport: i0, template: `
1289
+ <div [class]="'ui-alert ui-alert--' + variant() + ' ui-alert--' + color()"
1290
+ role="alert" [attr.aria-live]="live()">
1291
+ @if (icon()) {
1292
+ <span class="ui-alert__icon" aria-hidden="true">
1293
+ <ng-content select="[slot=icon]" />
1294
+ </span>
1295
+ }
1296
+ <div class="ui-alert__body">
1297
+ @if (title()) {
1298
+ <p class="ui-alert__title">{{ title() }}</p>
1299
+ }
1300
+ @if (description()) {
1301
+ <p class="ui-alert__description">{{ description() }}</p>
1302
+ }
1303
+ <ng-content />
1304
+ @if (actions()) {
1305
+ <div class="ui-alert__actions">
1306
+ <ng-content select="[slot=actions]" />
1307
+ </div>
1308
+ }
1309
+ </div>
1310
+ @if (closable()) {
1311
+ <button type="button" class="ui-alert__close" aria-label="Close" (click)="close.emit()">
1312
+ <span aria-hidden="true">×</span>
1313
+ </button>
1314
+ }
1315
+ </div>
1316
+ `, isInline: true, styles: [".ui-alert{display:flex;align-items:flex-start;gap:var(--spacing-3);padding:var(--spacing-4);border-radius:var(--radius-lg);border:1px solid transparent}.ui-alert__icon{flex-shrink:0;width:1.25rem;height:1.25rem;margin-top:1px}.ui-alert__body{flex:1;min-width:0}.ui-alert__title{font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);margin:0 0 var(--spacing-1)}.ui-alert__description{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);margin:0}.ui-alert__actions{display:flex;gap:var(--spacing-2);margin-top:var(--spacing-3)}.ui-alert__close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border:none;background:transparent;cursor:pointer;border-radius:var(--radius-md);color:currentColor;opacity:.6;font-size:1.25rem;line-height:1}.ui-alert__close:hover{opacity:1}.ui-alert--primary.ui-alert--soft{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-primary-500) 20%,transparent);color:var(--color-primary-700)}.ui-alert--primary.ui-alert--outline{background:transparent;border-color:var(--color-primary-500);color:var(--color-primary-700)}.ui-alert--primary.ui-alert--solid{background:var(--color-primary-500);color:#fff}.ui-alert--primary.ui-alert--subtle{background:color-mix(in srgb,var(--color-primary-500) 8%,transparent);border-color:transparent;color:var(--color-primary-700)}.ui-alert--success.ui-alert--soft{background:color-mix(in srgb,var(--color-success-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-success-500) 20%,transparent);color:var(--color-success-700)}.ui-alert--success.ui-alert--outline{background:transparent;border-color:var(--color-success-500);color:var(--color-success-700)}.ui-alert--success.ui-alert--solid{background:var(--color-success-500);color:#fff}.ui-alert--success.ui-alert--subtle{background:color-mix(in srgb,var(--color-success-500) 8%,transparent);border-color:transparent;color:var(--color-success-700)}.ui-alert--warning.ui-alert--soft{background:color-mix(in srgb,var(--color-warning-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-warning-500) 20%,transparent);color:var(--color-warning-700)}.ui-alert--warning.ui-alert--outline{background:transparent;border-color:var(--color-warning-500);color:var(--color-warning-700)}.ui-alert--warning.ui-alert--solid{background:var(--color-warning-500);color:#fff}.ui-alert--warning.ui-alert--subtle{background:color-mix(in srgb,var(--color-warning-500) 8%,transparent);border-color:transparent;color:var(--color-warning-700)}.ui-alert--error.ui-alert--soft{background:color-mix(in srgb,var(--color-error-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-error-500) 20%,transparent);color:var(--color-error-700)}.ui-alert--error.ui-alert--outline{background:transparent;border-color:var(--color-error-500);color:var(--color-error-700)}.ui-alert--error.ui-alert--solid{background:var(--color-error-500);color:#fff}.ui-alert--error.ui-alert--subtle{background:color-mix(in srgb,var(--color-error-500) 8%,transparent);border-color:transparent;color:var(--color-error-700)}.ui-alert--info.ui-alert--soft{background:color-mix(in srgb,var(--color-info-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-info-500) 20%,transparent);color:var(--color-info-700)}.ui-alert--info.ui-alert--outline{background:transparent;border-color:var(--color-info-500);color:var(--color-info-700)}.ui-alert--info.ui-alert--solid{background:var(--color-info-500);color:#fff}.ui-alert--info.ui-alert--subtle{background:color-mix(in srgb,var(--color-info-500) 8%,transparent);border-color:transparent;color:var(--color-info-700)}.ui-alert--neutral.ui-alert--soft{background:color-mix(in srgb,var(--color-neutral-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-neutral-500) 20%,transparent);color:var(--color-neutral-700)}.ui-alert--neutral.ui-alert--outline{background:transparent;border-color:var(--color-neutral-500);color:var(--color-neutral-700)}.ui-alert--neutral.ui-alert--solid{background:var(--color-neutral-500);color:#fff}.ui-alert--neutral.ui-alert--subtle{background:color-mix(in srgb,var(--color-neutral-500) 8%,transparent);border-color:transparent;color:var(--color-neutral-700)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1317
+ }
1318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AlertComponent, decorators: [{
1319
+ type: Component,
1320
+ args: [{ selector: 'ui-alert', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1321
+ <div [class]="'ui-alert ui-alert--' + variant() + ' ui-alert--' + color()"
1322
+ role="alert" [attr.aria-live]="live()">
1323
+ @if (icon()) {
1324
+ <span class="ui-alert__icon" aria-hidden="true">
1325
+ <ng-content select="[slot=icon]" />
1326
+ </span>
1327
+ }
1328
+ <div class="ui-alert__body">
1329
+ @if (title()) {
1330
+ <p class="ui-alert__title">{{ title() }}</p>
1331
+ }
1332
+ @if (description()) {
1333
+ <p class="ui-alert__description">{{ description() }}</p>
1334
+ }
1335
+ <ng-content />
1336
+ @if (actions()) {
1337
+ <div class="ui-alert__actions">
1338
+ <ng-content select="[slot=actions]" />
1339
+ </div>
1340
+ }
1341
+ </div>
1342
+ @if (closable()) {
1343
+ <button type="button" class="ui-alert__close" aria-label="Close" (click)="close.emit()">
1344
+ <span aria-hidden="true">×</span>
1345
+ </button>
1346
+ }
1347
+ </div>
1348
+ `, styles: [".ui-alert{display:flex;align-items:flex-start;gap:var(--spacing-3);padding:var(--spacing-4);border-radius:var(--radius-lg);border:1px solid transparent}.ui-alert__icon{flex-shrink:0;width:1.25rem;height:1.25rem;margin-top:1px}.ui-alert__body{flex:1;min-width:0}.ui-alert__title{font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);margin:0 0 var(--spacing-1)}.ui-alert__description{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);margin:0}.ui-alert__actions{display:flex;gap:var(--spacing-2);margin-top:var(--spacing-3)}.ui-alert__close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border:none;background:transparent;cursor:pointer;border-radius:var(--radius-md);color:currentColor;opacity:.6;font-size:1.25rem;line-height:1}.ui-alert__close:hover{opacity:1}.ui-alert--primary.ui-alert--soft{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-primary-500) 20%,transparent);color:var(--color-primary-700)}.ui-alert--primary.ui-alert--outline{background:transparent;border-color:var(--color-primary-500);color:var(--color-primary-700)}.ui-alert--primary.ui-alert--solid{background:var(--color-primary-500);color:#fff}.ui-alert--primary.ui-alert--subtle{background:color-mix(in srgb,var(--color-primary-500) 8%,transparent);border-color:transparent;color:var(--color-primary-700)}.ui-alert--success.ui-alert--soft{background:color-mix(in srgb,var(--color-success-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-success-500) 20%,transparent);color:var(--color-success-700)}.ui-alert--success.ui-alert--outline{background:transparent;border-color:var(--color-success-500);color:var(--color-success-700)}.ui-alert--success.ui-alert--solid{background:var(--color-success-500);color:#fff}.ui-alert--success.ui-alert--subtle{background:color-mix(in srgb,var(--color-success-500) 8%,transparent);border-color:transparent;color:var(--color-success-700)}.ui-alert--warning.ui-alert--soft{background:color-mix(in srgb,var(--color-warning-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-warning-500) 20%,transparent);color:var(--color-warning-700)}.ui-alert--warning.ui-alert--outline{background:transparent;border-color:var(--color-warning-500);color:var(--color-warning-700)}.ui-alert--warning.ui-alert--solid{background:var(--color-warning-500);color:#fff}.ui-alert--warning.ui-alert--subtle{background:color-mix(in srgb,var(--color-warning-500) 8%,transparent);border-color:transparent;color:var(--color-warning-700)}.ui-alert--error.ui-alert--soft{background:color-mix(in srgb,var(--color-error-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-error-500) 20%,transparent);color:var(--color-error-700)}.ui-alert--error.ui-alert--outline{background:transparent;border-color:var(--color-error-500);color:var(--color-error-700)}.ui-alert--error.ui-alert--solid{background:var(--color-error-500);color:#fff}.ui-alert--error.ui-alert--subtle{background:color-mix(in srgb,var(--color-error-500) 8%,transparent);border-color:transparent;color:var(--color-error-700)}.ui-alert--info.ui-alert--soft{background:color-mix(in srgb,var(--color-info-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-info-500) 20%,transparent);color:var(--color-info-700)}.ui-alert--info.ui-alert--outline{background:transparent;border-color:var(--color-info-500);color:var(--color-info-700)}.ui-alert--info.ui-alert--solid{background:var(--color-info-500);color:#fff}.ui-alert--info.ui-alert--subtle{background:color-mix(in srgb,var(--color-info-500) 8%,transparent);border-color:transparent;color:var(--color-info-700)}.ui-alert--neutral.ui-alert--soft{background:color-mix(in srgb,var(--color-neutral-500) 12%,transparent);border-color:color-mix(in srgb,var(--color-neutral-500) 20%,transparent);color:var(--color-neutral-700)}.ui-alert--neutral.ui-alert--outline{background:transparent;border-color:var(--color-neutral-500);color:var(--color-neutral-700)}.ui-alert--neutral.ui-alert--solid{background:var(--color-neutral-500);color:#fff}.ui-alert--neutral.ui-alert--subtle{background:color-mix(in srgb,var(--color-neutral-500) 8%,transparent);border-color:transparent;color:var(--color-neutral-700)}\n"] }]
1349
+ }] });
1350
+
1351
+ /**
1352
+ * AvatarGroup Molecule — Source: Nuxt UI v3 ❖ AvatarGroup
1353
+ * Stacked avatar list with overflow count
1354
+ * Depends on: AvatarComponent (atom)
1355
+ */
1356
+ class AvatarGroupComponent {
1357
+ constructor() {
1358
+ this.items = input.required();
1359
+ this.max = input(5);
1360
+ this.size = input('md');
1361
+ }
1362
+ get visibleItems() { return () => this.items().slice(0, this.max()); }
1363
+ get overflow() { return () => Math.max(0, this.items().length - this.max()); }
1364
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AvatarGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1365
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: AvatarGroupComponent, isStandalone: true, selector: "ui-avatar-group", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1366
+ <div class="ui-avatar-group" [attr.aria-label]="'Group of ' + items().length + ' avatars'">
1367
+ @for (item of visibleItems(); track item.alt) {
1368
+ <ui-avatar
1369
+ [src]="item.src ?? null"
1370
+ [alt]="item.alt ?? null"
1371
+ [initials]="item.initials ?? null"
1372
+ [size]="size()"
1373
+ class="ui-avatar-group__item"
1374
+ />
1375
+ }
1376
+ @if (overflow() > 0) {
1377
+ <span class="ui-avatar-group__overflow ui-avatar-group__overflow--{{ size() }}"
1378
+ [attr.aria-label]="overflow() + ' more'">
1379
+ +{{ overflow() }}
1380
+ </span>
1381
+ }
1382
+ </div>
1383
+ `, isInline: true, styles: [".ui-avatar-group{display:flex;align-items:center}.ui-avatar-group .ui-avatar-group__item,.ui-avatar-group ui-avatar{margin-left:-8px}.ui-avatar-group .ui-avatar-group__item:first-child,.ui-avatar-group ui-avatar:first-child{margin-left:0}.ui-avatar-group ui-avatar,.ui-avatar-group .ui-avatar-group__item{border:2px solid var(--color-bg);border-radius:50%}.ui-avatar-group__overflow{display:inline-flex;align-items:center;justify-content:center;margin-left:-8px;border:2px solid var(--color-bg);border-radius:50%;background:var(--color-neutral-100);color:var(--color-neutral-600);font-family:var(--font-sans);font-weight:var(--font-medium);flex-shrink:0}.ui-avatar-group__overflow--xs{width:20px;height:20px;font-size:10px}.ui-avatar-group__overflow--sm{width:24px;height:24px;font-size:11px}.ui-avatar-group__overflow--md{width:32px;height:32px;font-size:13px}.ui-avatar-group__overflow--lg{width:40px;height:40px;font-size:15px}.ui-avatar-group__overflow--xl{width:48px;height:48px;font-size:17px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AvatarComponent$1, selector: "ui-avatar", inputs: ["src", "alt", "size", "initials", "chip", "chipColor", "chipAlt", "rounded"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1384
+ }
1385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AvatarGroupComponent, decorators: [{
1386
+ type: Component,
1387
+ args: [{ selector: 'ui-avatar-group', standalone: true, imports: [CommonModule, AvatarComponent$1], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1388
+ <div class="ui-avatar-group" [attr.aria-label]="'Group of ' + items().length + ' avatars'">
1389
+ @for (item of visibleItems(); track item.alt) {
1390
+ <ui-avatar
1391
+ [src]="item.src ?? null"
1392
+ [alt]="item.alt ?? null"
1393
+ [initials]="item.initials ?? null"
1394
+ [size]="size()"
1395
+ class="ui-avatar-group__item"
1396
+ />
1397
+ }
1398
+ @if (overflow() > 0) {
1399
+ <span class="ui-avatar-group__overflow ui-avatar-group__overflow--{{ size() }}"
1400
+ [attr.aria-label]="overflow() + ' more'">
1401
+ +{{ overflow() }}
1402
+ </span>
1403
+ }
1404
+ </div>
1405
+ `, styles: [".ui-avatar-group{display:flex;align-items:center}.ui-avatar-group .ui-avatar-group__item,.ui-avatar-group ui-avatar{margin-left:-8px}.ui-avatar-group .ui-avatar-group__item:first-child,.ui-avatar-group ui-avatar:first-child{margin-left:0}.ui-avatar-group ui-avatar,.ui-avatar-group .ui-avatar-group__item{border:2px solid var(--color-bg);border-radius:50%}.ui-avatar-group__overflow{display:inline-flex;align-items:center;justify-content:center;margin-left:-8px;border:2px solid var(--color-bg);border-radius:50%;background:var(--color-neutral-100);color:var(--color-neutral-600);font-family:var(--font-sans);font-weight:var(--font-medium);flex-shrink:0}.ui-avatar-group__overflow--xs{width:20px;height:20px;font-size:10px}.ui-avatar-group__overflow--sm{width:24px;height:24px;font-size:11px}.ui-avatar-group__overflow--md{width:32px;height:32px;font-size:13px}.ui-avatar-group__overflow--lg{width:40px;height:40px;font-size:15px}.ui-avatar-group__overflow--xl{width:48px;height:48px;font-size:17px}\n"] }]
1406
+ }] });
1407
+
1408
+ /**
1409
+ * Breadcrumb Molecule — Source: Nuxt UI v3 ❖ Breadcrumb
1410
+ * Navigation trail with router support
1411
+ */
1412
+ class BreadcrumbComponent {
1413
+ constructor() {
1414
+ this.items = input.required();
1415
+ this.separator = input('/');
1416
+ }
1417
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1418
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: BreadcrumbComponent, isStandalone: true, selector: "ui-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1419
+ <nav aria-label="Breadcrumb">
1420
+ <ol class="ui-breadcrumb">
1421
+ @for (item of items(); track item.label; let last = $last) {
1422
+ <li class="ui-breadcrumb__item" [class.ui-breadcrumb__item--current]="last">
1423
+ @if (!last && item.to) {
1424
+ <a [routerLink]="item.to" class="ui-breadcrumb__link">{{ item.label }}</a>
1425
+ } @else if (!last && item.href) {
1426
+ <a [href]="item.href" class="ui-breadcrumb__link">{{ item.label }}</a>
1427
+ } @else {
1428
+ <span class="ui-breadcrumb__current" [attr.aria-current]="last ? 'page' : null">{{ item.label }}</span>
1429
+ }
1430
+ @if (!last) {
1431
+ <span class="ui-breadcrumb__separator" aria-hidden="true">{{ separator() }}</span>
1432
+ }
1433
+ </li>
1434
+ }
1435
+ </ol>
1436
+ </nav>
1437
+ `, isInline: true, styles: [".ui-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacing-1);list-style:none;padding:0;margin:0}.ui-breadcrumb__item{display:flex;align-items:center;gap:var(--spacing-1)}.ui-breadcrumb__link{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);text-decoration:none;transition:color var(--transition-fast)}.ui-breadcrumb__link:hover{color:var(--color-primary-500);text-decoration:underline}.ui-breadcrumb__current{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text);font-weight:var(--font-medium)}.ui-breadcrumb__separator{font-size:var(--text-xs);color:var(--color-text-subtle);-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1438
+ }
1439
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BreadcrumbComponent, decorators: [{
1440
+ type: Component,
1441
+ args: [{ selector: 'ui-breadcrumb', standalone: true, imports: [CommonModule, RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1442
+ <nav aria-label="Breadcrumb">
1443
+ <ol class="ui-breadcrumb">
1444
+ @for (item of items(); track item.label; let last = $last) {
1445
+ <li class="ui-breadcrumb__item" [class.ui-breadcrumb__item--current]="last">
1446
+ @if (!last && item.to) {
1447
+ <a [routerLink]="item.to" class="ui-breadcrumb__link">{{ item.label }}</a>
1448
+ } @else if (!last && item.href) {
1449
+ <a [href]="item.href" class="ui-breadcrumb__link">{{ item.label }}</a>
1450
+ } @else {
1451
+ <span class="ui-breadcrumb__current" [attr.aria-current]="last ? 'page' : null">{{ item.label }}</span>
1452
+ }
1453
+ @if (!last) {
1454
+ <span class="ui-breadcrumb__separator" aria-hidden="true">{{ separator() }}</span>
1455
+ }
1456
+ </li>
1457
+ }
1458
+ </ol>
1459
+ </nav>
1460
+ `, styles: [".ui-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacing-1);list-style:none;padding:0;margin:0}.ui-breadcrumb__item{display:flex;align-items:center;gap:var(--spacing-1)}.ui-breadcrumb__link{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);text-decoration:none;transition:color var(--transition-fast)}.ui-breadcrumb__link:hover{color:var(--color-primary-500);text-decoration:underline}.ui-breadcrumb__current{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text);font-weight:var(--font-medium)}.ui-breadcrumb__separator{font-size:var(--text-xs);color:var(--color-text-subtle);-webkit-user-select:none;user-select:none}\n"] }]
1461
+ }] });
1462
+
1463
+ /**
1464
+ * ButtonGroup Molecule — Source: Nuxt UI v3 ❖ ButtonGroup
1465
+ * Groups buttons in a visual row (joined borders)
1466
+ */
1467
+ class ButtonGroupComponent {
1468
+ constructor() {
1469
+ this.vertical = input(false);
1470
+ }
1471
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ButtonGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1472
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.20", type: ButtonGroupComponent, isStandalone: true, selector: "ui-button-group", inputs: { vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1473
+ <div class="ui-button-group" [class.ui-button-group--vertical]="vertical()" role="group">
1474
+ <ng-content />
1475
+ </div>
1476
+ `, isInline: true, styles: [".ui-button-group{display:inline-flex;align-items:stretch}.ui-button-group ::ng-deep ui-button button,.ui-button-group ::ng-deep .ui-btn{border-radius:0;border-right-width:0}.ui-button-group ::ng-deep ui-button button:first-child,.ui-button-group ::ng-deep .ui-btn:first-child{border-radius:var(--radius-md) 0 0 var(--radius-md)}.ui-button-group ::ng-deep ui-button button:last-child,.ui-button-group ::ng-deep .ui-btn:last-child{border-radius:0 var(--radius-md) var(--radius-md) 0;border-right-width:1px}.ui-button-group--vertical{flex-direction:column}.ui-button-group--vertical ::ng-deep ui-button button,.ui-button-group--vertical ::ng-deep .ui-btn{border-bottom-width:0;border-radius:0}.ui-button-group--vertical ::ng-deep ui-button button:first-child,.ui-button-group--vertical ::ng-deep .ui-btn:first-child{border-radius:var(--radius-md) var(--radius-md) 0 0}.ui-button-group--vertical ::ng-deep ui-button button:last-child,.ui-button-group--vertical ::ng-deep .ui-btn:last-child{border-radius:0 0 var(--radius-md) var(--radius-md);border-bottom-width:1px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1477
+ }
1478
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ButtonGroupComponent, decorators: [{
1479
+ type: Component,
1480
+ args: [{ selector: 'ui-button-group', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1481
+ <div class="ui-button-group" [class.ui-button-group--vertical]="vertical()" role="group">
1482
+ <ng-content />
1483
+ </div>
1484
+ `, styles: [".ui-button-group{display:inline-flex;align-items:stretch}.ui-button-group ::ng-deep ui-button button,.ui-button-group ::ng-deep .ui-btn{border-radius:0;border-right-width:0}.ui-button-group ::ng-deep ui-button button:first-child,.ui-button-group ::ng-deep .ui-btn:first-child{border-radius:var(--radius-md) 0 0 var(--radius-md)}.ui-button-group ::ng-deep ui-button button:last-child,.ui-button-group ::ng-deep .ui-btn:last-child{border-radius:0 var(--radius-md) var(--radius-md) 0;border-right-width:1px}.ui-button-group--vertical{flex-direction:column}.ui-button-group--vertical ::ng-deep ui-button button,.ui-button-group--vertical ::ng-deep .ui-btn{border-bottom-width:0;border-radius:0}.ui-button-group--vertical ::ng-deep ui-button button:first-child,.ui-button-group--vertical ::ng-deep .ui-btn:first-child{border-radius:var(--radius-md) var(--radius-md) 0 0}.ui-button-group--vertical ::ng-deep ui-button button:last-child,.ui-button-group--vertical ::ng-deep .ui-btn:last-child{border-radius:0 0 var(--radius-md) var(--radius-md);border-bottom-width:1px}\n"] }]
1485
+ }] });
1486
+
1487
+ /**
1488
+ * FormField Molecule — Source: Nuxt UI v3 ❖ FormField
1489
+ * Wrapper for form controls: label + control + hint + error
1490
+ * Used with: Input, Textarea, Select, Checkbox, Radio...
1491
+ */
1492
+ class FormFieldComponent {
1493
+ constructor() {
1494
+ this.label = input(null);
1495
+ this.name = input('');
1496
+ this.hint = input(null);
1497
+ this.errorMessage = input(null);
1498
+ this.required = input(false);
1499
+ this.size = input('md');
1500
+ }
1501
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1502
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: FormFieldComponent, isStandalone: true, selector: "ui-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1503
+ <div class="ui-form-field" [class.ui-form-field--error]="!!errorMessage()" [class.ui-form-field--required]="required()">
1504
+ @if (label()) {
1505
+ <label class="ui-form-field__label ui-form-field__label--{{ size() }}" [for]="name()">
1506
+ {{ label() }}
1507
+ @if (required()) {
1508
+ <span class="ui-form-field__required" aria-hidden="true"> *</span>
1509
+ }
1510
+ </label>
1511
+ }
1512
+
1513
+ <div class="ui-form-field__control">
1514
+ <ng-content />
1515
+ </div>
1516
+
1517
+ @if (hint() && !errorMessage()) {
1518
+ <p class="ui-form-field__hint" [id]="name() + '-hint'">{{ hint() }}</p>
1519
+ }
1520
+
1521
+ @if (errorMessage()) {
1522
+ <p class="ui-form-field__error" role="alert" [id]="name() + '-error'">
1523
+ {{ errorMessage() }}
1524
+ </p>
1525
+ }
1526
+ </div>
1527
+ `, isInline: true, styles: [".ui-form-field{display:flex;flex-direction:column;gap:var(--spacing-1-5);width:100%}.ui-form-field__label{font-family:var(--font-sans);font-weight:var(--font-medium);color:var(--color-text);cursor:pointer}.ui-form-field__label--xs,.ui-form-field__label--sm{font-size:var(--text-xs)}.ui-form-field__label--md{font-size:var(--text-sm)}.ui-form-field__label--lg{font-size:var(--text-md)}.ui-form-field__label--xl{font-size:var(--text-lg)}.ui-form-field__required{color:var(--color-error-500)}.ui-form-field__control{position:relative}.ui-form-field__hint{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-text-muted);margin:0}.ui-form-field__error{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-error-600);margin:0;font-weight:var(--font-medium)}.ui-form-field--error .ui-form-field__label{color:var(--color-error-600)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1528
+ }
1529
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FormFieldComponent, decorators: [{
1530
+ type: Component,
1531
+ args: [{ selector: 'ui-form-field', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1532
+ <div class="ui-form-field" [class.ui-form-field--error]="!!errorMessage()" [class.ui-form-field--required]="required()">
1533
+ @if (label()) {
1534
+ <label class="ui-form-field__label ui-form-field__label--{{ size() }}" [for]="name()">
1535
+ {{ label() }}
1536
+ @if (required()) {
1537
+ <span class="ui-form-field__required" aria-hidden="true"> *</span>
1538
+ }
1539
+ </label>
1540
+ }
1541
+
1542
+ <div class="ui-form-field__control">
1543
+ <ng-content />
1544
+ </div>
1545
+
1546
+ @if (hint() && !errorMessage()) {
1547
+ <p class="ui-form-field__hint" [id]="name() + '-hint'">{{ hint() }}</p>
1548
+ }
1549
+
1550
+ @if (errorMessage()) {
1551
+ <p class="ui-form-field__error" role="alert" [id]="name() + '-error'">
1552
+ {{ errorMessage() }}
1553
+ </p>
1554
+ }
1555
+ </div>
1556
+ `, styles: [".ui-form-field{display:flex;flex-direction:column;gap:var(--spacing-1-5);width:100%}.ui-form-field__label{font-family:var(--font-sans);font-weight:var(--font-medium);color:var(--color-text);cursor:pointer}.ui-form-field__label--xs,.ui-form-field__label--sm{font-size:var(--text-xs)}.ui-form-field__label--md{font-size:var(--text-sm)}.ui-form-field__label--lg{font-size:var(--text-md)}.ui-form-field__label--xl{font-size:var(--text-lg)}.ui-form-field__required{color:var(--color-error-500)}.ui-form-field__control{position:relative}.ui-form-field__hint{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-text-muted);margin:0}.ui-form-field__error{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-error-600);margin:0;font-weight:var(--font-medium)}.ui-form-field--error .ui-form-field__label{color:var(--color-error-600)}\n"] }]
1557
+ }] });
1558
+
1559
+ /**
1560
+ * Input Molecule — Source: Nuxt UI v3 ❖ Input
1561
+ *
1562
+ * Slots :
1563
+ * [slot=leading] — icône / contenu à gauche
1564
+ * [slot=trailing] — icône / contenu à droite
1565
+ *
1566
+ * Pour rendre un slot cliquable (ex: toggle password) :
1567
+ * [trailingClickable]="true" → rend le slot trailing en <button> et émet (trailingClick)
1568
+ * [leadingClickable]="true" → rend le slot leading en <button> et émet (leadingClick)
1569
+ */
1570
+ class InputComponent {
1571
+ constructor() {
1572
+ // ── Inputs ───────────────────────────────────────────────
1573
+ this.type = input('text');
1574
+ this.placeholder = input('');
1575
+ this.size = input('md');
1576
+ this.variant = input('outline');
1577
+ this.color = input('primary');
1578
+ this.disabled = input(false);
1579
+ this.readonly = input(false);
1580
+ this.required = input(false);
1581
+ this.ariaLabel = input(null);
1582
+ this.leading = input(false);
1583
+ this.leadingClickable = input(false);
1584
+ /** aria-label du bouton leading quand leadingClickable=true */
1585
+ this.leadingLabel = input('');
1586
+ this.trailing = input(false);
1587
+ this.trailingClickable = input(false);
1588
+ /** aria-label du bouton trailing quand trailingClickable=true */
1589
+ this.trailingLabel = input('');
1590
+ // ── Two-way ──────────────────────────────────────────────
1591
+ this.value = model('');
1592
+ // ── Outputs ──────────────────────────────────────────────
1593
+ this.leadingClick = output();
1594
+ this.trailingClick = output();
1595
+ // ── CVA ──────────────────────────────────────────────────
1596
+ this._onChange = () => { };
1597
+ this.onTouched = () => { };
1598
+ }
1599
+ // ── Classes computed ─────────────────────────────────────
1600
+ wrapClass() {
1601
+ return [
1602
+ 'ui-input-wrap',
1603
+ `ui-input-wrap--${this.size()}`,
1604
+ this.leading() ? 'ui-input-wrap--has-leading' : '',
1605
+ this.trailing() ? 'ui-input-wrap--has-trailing' : '',
1606
+ ].filter(Boolean).join(' ');
1607
+ }
1608
+ inputClass() {
1609
+ return `ui-input ui-input--${this.variant()} ui-input--${this.color()} ui-input--${this.size()}`;
1610
+ }
1611
+ onInput(e) {
1612
+ const val = e.target.value;
1613
+ this.value.set(val);
1614
+ this._onChange(val);
1615
+ }
1616
+ writeValue(v) { this.value.set(v ?? ''); }
1617
+ registerOnChange(fn) { this._onChange = fn; }
1618
+ registerOnTouched(fn) { this.onTouched = fn; }
1619
+ setDisabledState(_) { }
1620
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: InputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1621
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: InputComponent, isStandalone: true, selector: "ui-input", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", 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 }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, leading: { classPropertyName: "leading", publicName: "leading", isSignal: true, isRequired: false, transformFunction: null }, leadingClickable: { classPropertyName: "leadingClickable", publicName: "leadingClickable", isSignal: true, isRequired: false, transformFunction: null }, leadingLabel: { classPropertyName: "leadingLabel", publicName: "leadingLabel", isSignal: true, isRequired: false, transformFunction: null }, trailing: { classPropertyName: "trailing", publicName: "trailing", isSignal: true, isRequired: false, transformFunction: null }, trailingClickable: { classPropertyName: "trailingClickable", publicName: "trailingClickable", isSignal: true, isRequired: false, transformFunction: null }, trailingLabel: { classPropertyName: "trailingLabel", publicName: "trailingLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", leadingClick: "leadingClick", trailingClick: "trailingClick" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputComponent), multi: true }], ngImport: i0, template: `
1622
+ <div [class]="wrapClass()">
1623
+
1624
+ <!-- Leading slot -->
1625
+ @if (leading()) {
1626
+ <span
1627
+ class="ui-input__leading"
1628
+ [class.ui-input__slot--clickable]="leadingClickable()"
1629
+ [attr.role]="leadingClickable() ? 'button' : null"
1630
+ [attr.tabindex]="leadingClickable() ? 0 : null"
1631
+ [attr.aria-label]="leadingClickable() ? leadingLabel() : null"
1632
+ (click)="leadingClickable() && leadingClick.emit()"
1633
+ (keydown.enter)="leadingClickable() && leadingClick.emit()"
1634
+ (keydown.space)="leadingClickable() && leadingClick.emit()"
1635
+ >
1636
+ <ng-content select="[slot=leading]" />
1637
+ </span>
1638
+ }
1639
+
1640
+ <!-- Native input -->
1641
+ <input
1642
+ [class]="inputClass()"
1643
+ [type]="type()"
1644
+ [placeholder]="placeholder()"
1645
+ [disabled]="disabled()"
1646
+ [readonly]="readonly()"
1647
+ [required]="required()"
1648
+ [attr.aria-label]="ariaLabel() ?? null"
1649
+ [attr.aria-invalid]="color() === 'error'"
1650
+ [value]="value()"
1651
+ (input)="onInput($event)"
1652
+ (blur)="onTouched()"
1653
+ />
1654
+
1655
+ <!-- Trailing slot -->
1656
+ @if (trailing()) {
1657
+ <span
1658
+ class="ui-input__trailing"
1659
+ [class.ui-input__slot--clickable]="trailingClickable()"
1660
+ [attr.role]="trailingClickable() ? 'button' : null"
1661
+ [attr.tabindex]="trailingClickable() ? 0 : null"
1662
+ [attr.aria-label]="trailingClickable() ? trailingLabel() : null"
1663
+ (click)="trailingClickable() && trailingClick.emit()"
1664
+ (keydown.enter)="trailingClickable() && trailingClick.emit()"
1665
+ (keydown.space)="trailingClickable() && trailingClick.emit()"
1666
+ >
1667
+ <ng-content select="[slot=trailing]" />
1668
+ </span>
1669
+ }
1670
+
1671
+ </div>
1672
+ `, isInline: true, styles: [".ui-input-wrap{position:relative;display:flex;align-items:stretch;width:100%}.ui-input-wrap--has-leading .ui-input{padding-left:2.5rem}.ui-input-wrap--has-trailing .ui-input{padding-right:2.5rem}.ui-input{width:100%;font-family:var(--font-sans);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);outline:none;transition:var(--transition-colors)}.ui-input::placeholder{color:var(--color-text-subtle)}.ui-input:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-input:disabled{opacity:.5;cursor:not-allowed;background:var(--color-neutral-50)}.ui-input--xs{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-input--sm{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-input--md{height:var(--size-md);padding:0 10px;font-size:var(--text-sm)}.ui-input--lg{height:var(--size-lg);padding:0 12px;font-size:var(--text-sm)}.ui-input--xl{height:var(--size-xl);padding:0 12px;font-size:var(--text-md)}.ui-input--outline{border-color:var(--color-border)}.ui-input--soft{background:var(--color-neutral-50);border-color:transparent}.ui-input--subtle{background:transparent;border-color:transparent;border-bottom-color:var(--color-border);border-radius:0}.ui-input--none{border:none;background:transparent;box-shadow:none!important}.ui-input--error{border-color:var(--color-error-500)}.ui-input--error:focus{box-shadow:0 0 0 1px var(--color-error-500)}.ui-input--success{border-color:var(--color-success-500)}.ui-input--success:focus{box-shadow:0 0 0 1px var(--color-success-500)}.ui-input--warning{border-color:var(--color-warning-500)}.ui-input--warning:focus{box-shadow:0 0 0 1px var(--color-warning-500)}.ui-input__leading,.ui-input__trailing{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;color:var(--color-text-muted);width:2.25rem;height:100%;pointer-events:none}.ui-input__leading{left:0}.ui-input__trailing{right:0}.ui-input__slot--clickable{pointer-events:auto;cursor:pointer;border-radius:var(--radius-sm);color:var(--color-text-muted);transition:color var(--transition-colors)}.ui-input__slot--clickable:hover{color:var(--color-text)}.ui-input__slot--clickable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1673
+ }
1674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: InputComponent, decorators: [{
1675
+ type: Component,
1676
+ args: [{ selector: 'ui-input', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputComponent), multi: true }], template: `
1677
+ <div [class]="wrapClass()">
1678
+
1679
+ <!-- Leading slot -->
1680
+ @if (leading()) {
1681
+ <span
1682
+ class="ui-input__leading"
1683
+ [class.ui-input__slot--clickable]="leadingClickable()"
1684
+ [attr.role]="leadingClickable() ? 'button' : null"
1685
+ [attr.tabindex]="leadingClickable() ? 0 : null"
1686
+ [attr.aria-label]="leadingClickable() ? leadingLabel() : null"
1687
+ (click)="leadingClickable() && leadingClick.emit()"
1688
+ (keydown.enter)="leadingClickable() && leadingClick.emit()"
1689
+ (keydown.space)="leadingClickable() && leadingClick.emit()"
1690
+ >
1691
+ <ng-content select="[slot=leading]" />
1692
+ </span>
1693
+ }
1694
+
1695
+ <!-- Native input -->
1696
+ <input
1697
+ [class]="inputClass()"
1698
+ [type]="type()"
1699
+ [placeholder]="placeholder()"
1700
+ [disabled]="disabled()"
1701
+ [readonly]="readonly()"
1702
+ [required]="required()"
1703
+ [attr.aria-label]="ariaLabel() ?? null"
1704
+ [attr.aria-invalid]="color() === 'error'"
1705
+ [value]="value()"
1706
+ (input)="onInput($event)"
1707
+ (blur)="onTouched()"
1708
+ />
1709
+
1710
+ <!-- Trailing slot -->
1711
+ @if (trailing()) {
1712
+ <span
1713
+ class="ui-input__trailing"
1714
+ [class.ui-input__slot--clickable]="trailingClickable()"
1715
+ [attr.role]="trailingClickable() ? 'button' : null"
1716
+ [attr.tabindex]="trailingClickable() ? 0 : null"
1717
+ [attr.aria-label]="trailingClickable() ? trailingLabel() : null"
1718
+ (click)="trailingClickable() && trailingClick.emit()"
1719
+ (keydown.enter)="trailingClickable() && trailingClick.emit()"
1720
+ (keydown.space)="trailingClickable() && trailingClick.emit()"
1721
+ >
1722
+ <ng-content select="[slot=trailing]" />
1723
+ </span>
1724
+ }
1725
+
1726
+ </div>
1727
+ `, styles: [".ui-input-wrap{position:relative;display:flex;align-items:stretch;width:100%}.ui-input-wrap--has-leading .ui-input{padding-left:2.5rem}.ui-input-wrap--has-trailing .ui-input{padding-right:2.5rem}.ui-input{width:100%;font-family:var(--font-sans);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);outline:none;transition:var(--transition-colors)}.ui-input::placeholder{color:var(--color-text-subtle)}.ui-input:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-input:disabled{opacity:.5;cursor:not-allowed;background:var(--color-neutral-50)}.ui-input--xs{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-input--sm{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-input--md{height:var(--size-md);padding:0 10px;font-size:var(--text-sm)}.ui-input--lg{height:var(--size-lg);padding:0 12px;font-size:var(--text-sm)}.ui-input--xl{height:var(--size-xl);padding:0 12px;font-size:var(--text-md)}.ui-input--outline{border-color:var(--color-border)}.ui-input--soft{background:var(--color-neutral-50);border-color:transparent}.ui-input--subtle{background:transparent;border-color:transparent;border-bottom-color:var(--color-border);border-radius:0}.ui-input--none{border:none;background:transparent;box-shadow:none!important}.ui-input--error{border-color:var(--color-error-500)}.ui-input--error:focus{box-shadow:0 0 0 1px var(--color-error-500)}.ui-input--success{border-color:var(--color-success-500)}.ui-input--success:focus{box-shadow:0 0 0 1px var(--color-success-500)}.ui-input--warning{border-color:var(--color-warning-500)}.ui-input--warning:focus{box-shadow:0 0 0 1px var(--color-warning-500)}.ui-input__leading,.ui-input__trailing{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;color:var(--color-text-muted);width:2.25rem;height:100%;pointer-events:none}.ui-input__leading{left:0}.ui-input__trailing{right:0}.ui-input__slot--clickable{pointer-events:auto;cursor:pointer;border-radius:var(--radius-sm);color:var(--color-text-muted);transition:color var(--transition-colors)}.ui-input__slot--clickable:hover{color:var(--color-text)}.ui-input__slot--clickable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}\n"] }]
1728
+ }] });
1729
+
1730
+ /**
1731
+ * Pagination Molecule — Source: Nuxt UI v3 ❖ Pagination
1732
+ * Page navigation with page numbers, prev/next controls
1733
+ */
1734
+ class PaginationComponent {
1735
+ constructor() {
1736
+ this.total = input.required();
1737
+ this.size = input('md');
1738
+ this.page = model(1);
1739
+ this.pages = computed(() => {
1740
+ const current = this.page();
1741
+ const last = this.total();
1742
+ if (last <= 7)
1743
+ return Array.from({ length: last }, (_, i) => i + 1);
1744
+ const items = [1];
1745
+ if (current > 3)
1746
+ items.push('...');
1747
+ const start = Math.max(2, current - 1);
1748
+ const end = Math.min(last - 1, current + 1);
1749
+ for (let i = start; i <= end; i++)
1750
+ items.push(i);
1751
+ if (current < last - 2)
1752
+ items.push('...');
1753
+ items.push(last);
1754
+ return items;
1755
+ });
1756
+ }
1757
+ prev() { if (this.page() > 1)
1758
+ this.page.update(p => p - 1); }
1759
+ next() { if (this.page() < this.total())
1760
+ this.page.update(p => p + 1); }
1761
+ goTo(p) { this.page.set(p); }
1762
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1763
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: PaginationComponent, isStandalone: true, selector: "ui-pagination", inputs: { total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange" }, ngImport: i0, template: `
1764
+ <nav class="ui-pagination ui-pagination--{{ size() }}" aria-label="Pagination">
1765
+ <button
1766
+ class="ui-pagination__btn"
1767
+ [disabled]="page() <= 1"
1768
+ (click)="prev()"
1769
+ aria-label="Previous page"
1770
+ >‹</button>
1771
+
1772
+ @for (p of pages(); track p) {
1773
+ @if (p === '...') {
1774
+ <span class="ui-pagination__ellipsis" aria-hidden="true">…</span>
1775
+ } @else {
1776
+ <button
1777
+ class="ui-pagination__btn"
1778
+ [class.ui-pagination__btn--active]="p === page()"
1779
+ [attr.aria-current]="p === page() ? 'page' : null"
1780
+ (click)="goTo(+p)"
1781
+ >{{ p }}</button>
1782
+ }
1783
+ }
1784
+
1785
+ <button
1786
+ class="ui-pagination__btn"
1787
+ [disabled]="page() >= total()"
1788
+ (click)="next()"
1789
+ aria-label="Next page"
1790
+ >›</button>
1791
+ </nav>
1792
+ `, isInline: true, styles: [".ui-pagination{display:flex;align-items:center;gap:var(--spacing-1)}.ui-pagination--xs .ui-pagination__btn{height:var(--size-xs);min-width:var(--size-xs);font-size:var(--text-xs)}.ui-pagination--sm .ui-pagination__btn{height:var(--size-sm);min-width:var(--size-sm);font-size:var(--text-xs)}.ui-pagination--md .ui-pagination__btn{height:var(--size-md);min-width:var(--size-md);font-size:var(--text-sm)}.ui-pagination--lg .ui-pagination__btn{height:var(--size-lg);min-width:var(--size-lg);font-size:var(--text-sm)}.ui-pagination--xl .ui-pagination__btn{height:var(--size-xl);min-width:var(--size-xl);font-size:var(--text-md)}.ui-pagination__btn{display:inline-flex;align-items:center;justify-content:center;padding:0 var(--spacing-2);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);font-weight:var(--font-medium);cursor:pointer;transition:var(--transition-colors)}.ui-pagination__btn:hover:not([disabled]){background:var(--color-neutral-100);border-color:var(--color-neutral-300)}.ui-pagination__btn--active{background:var(--color-primary-500);border-color:var(--color-primary-500);color:#fff}.ui-pagination__btn[disabled]{opacity:.4;cursor:not-allowed}.ui-pagination__ellipsis{display:inline-flex;align-items:center;padding:0 var(--spacing-1);color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1793
+ }
1794
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PaginationComponent, decorators: [{
1795
+ type: Component,
1796
+ args: [{ selector: 'ui-pagination', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
1797
+ <nav class="ui-pagination ui-pagination--{{ size() }}" aria-label="Pagination">
1798
+ <button
1799
+ class="ui-pagination__btn"
1800
+ [disabled]="page() <= 1"
1801
+ (click)="prev()"
1802
+ aria-label="Previous page"
1803
+ >‹</button>
1804
+
1805
+ @for (p of pages(); track p) {
1806
+ @if (p === '...') {
1807
+ <span class="ui-pagination__ellipsis" aria-hidden="true">…</span>
1808
+ } @else {
1809
+ <button
1810
+ class="ui-pagination__btn"
1811
+ [class.ui-pagination__btn--active]="p === page()"
1812
+ [attr.aria-current]="p === page() ? 'page' : null"
1813
+ (click)="goTo(+p)"
1814
+ >{{ p }}</button>
1815
+ }
1816
+ }
1817
+
1818
+ <button
1819
+ class="ui-pagination__btn"
1820
+ [disabled]="page() >= total()"
1821
+ (click)="next()"
1822
+ aria-label="Next page"
1823
+ >›</button>
1824
+ </nav>
1825
+ `, styles: [".ui-pagination{display:flex;align-items:center;gap:var(--spacing-1)}.ui-pagination--xs .ui-pagination__btn{height:var(--size-xs);min-width:var(--size-xs);font-size:var(--text-xs)}.ui-pagination--sm .ui-pagination__btn{height:var(--size-sm);min-width:var(--size-sm);font-size:var(--text-xs)}.ui-pagination--md .ui-pagination__btn{height:var(--size-md);min-width:var(--size-md);font-size:var(--text-sm)}.ui-pagination--lg .ui-pagination__btn{height:var(--size-lg);min-width:var(--size-lg);font-size:var(--text-sm)}.ui-pagination--xl .ui-pagination__btn{height:var(--size-xl);min-width:var(--size-xl);font-size:var(--text-md)}.ui-pagination__btn{display:inline-flex;align-items:center;justify-content:center;padding:0 var(--spacing-2);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);font-weight:var(--font-medium);cursor:pointer;transition:var(--transition-colors)}.ui-pagination__btn:hover:not([disabled]){background:var(--color-neutral-100);border-color:var(--color-neutral-300)}.ui-pagination__btn--active{background:var(--color-primary-500);border-color:var(--color-primary-500);color:#fff}.ui-pagination__btn[disabled]{opacity:.4;cursor:not-allowed}.ui-pagination__ellipsis{display:inline-flex;align-items:center;padding:0 var(--spacing-1);color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm)}\n"] }]
1826
+ }] });
1827
+
1828
+ /**
1829
+ * Select Molecule — Source: Nuxt UI v3 ❖ Select
1830
+ *
1831
+ * Dropdown custom (non natif) :
1832
+ * - Trigger stylisé comme un Input (variants, couleurs, tailles Figma)
1833
+ * - Panel dropdown animé (scale + fade, 100ms ease-out)
1834
+ * - Navigation clavier : ArrowUp/Down, Enter, Space, Escape, Tab
1835
+ * - ClickOutside pour fermer
1836
+ * - Slot leading icon dans le trigger
1837
+ * - Icône + checkmark par option
1838
+ * - Compatible ControlValueAccessor
1839
+ */
1840
+ class SelectComponent {
1841
+ constructor() {
1842
+ this.options = input.required();
1843
+ this.placeholder = input(null);
1844
+ this.size = input('md');
1845
+ this.variant = input('outline');
1846
+ this.color = input('neutral');
1847
+ this.disabled = input(false);
1848
+ this.loading = input(false);
1849
+ this.leadingIcon = input(false);
1850
+ this.ariaLabel = input(null);
1851
+ this.value = model('');
1852
+ this.change = output();
1853
+ this.isOpen = signal(false);
1854
+ this.activeIndex = signal(-1);
1855
+ this.selectedOption = computed(() => this.options().find(o => String(o.value) === String(this.value())));
1856
+ this.triggerClasses = computed(() => ['ui-select__trigger',
1857
+ `ui-select__trigger--${this.size()}`,
1858
+ `ui-select__trigger--${this.variant()}`,
1859
+ `ui-select__trigger--${this.color()}`
1860
+ ].join(' '));
1861
+ // CVA
1862
+ this._onChange = () => { };
1863
+ this._onTouched = () => { };
1864
+ }
1865
+ isSelected(opt) {
1866
+ return String(opt.value) === String(this.value());
1867
+ }
1868
+ writeValue(v) { this.value.set(v ?? ''); }
1869
+ registerOnChange(fn) { this._onChange = fn; }
1870
+ registerOnTouched(fn) { this._onTouched = fn; }
1871
+ setDisabledState(_) { }
1872
+ toggleOpen() {
1873
+ if (this.disabled() || this.loading())
1874
+ return;
1875
+ this.isOpen.update(v => !v);
1876
+ if (this.isOpen()) {
1877
+ const idx = this.options().findIndex(o => this.isSelected(o));
1878
+ this.activeIndex.set(idx >= 0 ? idx : 0);
1879
+ }
1880
+ }
1881
+ selectOption(opt) {
1882
+ if (opt.disabled)
1883
+ return;
1884
+ const val = String(opt.value);
1885
+ this.value.set(val);
1886
+ this._onChange(val);
1887
+ this._onTouched();
1888
+ this.change.emit(opt);
1889
+ this.isOpen.set(false);
1890
+ this.triggerEl?.nativeElement.focus();
1891
+ }
1892
+ onTriggerKeydown(event) {
1893
+ switch (event.key) {
1894
+ case 'Enter':
1895
+ case ' ':
1896
+ event.preventDefault();
1897
+ if (!this.isOpen()) {
1898
+ this.toggleOpen();
1899
+ }
1900
+ else {
1901
+ const opt = this.options()[this.activeIndex()];
1902
+ if (opt && !opt.disabled)
1903
+ this.selectOption(opt);
1904
+ }
1905
+ break;
1906
+ case 'ArrowDown':
1907
+ event.preventDefault();
1908
+ if (!this.isOpen()) {
1909
+ this.toggleOpen();
1910
+ return;
1911
+ }
1912
+ this.activeIndex.update(i => {
1913
+ let n = i + 1;
1914
+ while (n < this.options().length && this.options()[n]?.disabled)
1915
+ n++;
1916
+ return Math.min(n, this.options().length - 1);
1917
+ });
1918
+ break;
1919
+ case 'ArrowUp':
1920
+ event.preventDefault();
1921
+ this.activeIndex.update(i => {
1922
+ let n = i - 1;
1923
+ while (n >= 0 && this.options()[n]?.disabled)
1924
+ n--;
1925
+ return Math.max(n, 0);
1926
+ });
1927
+ break;
1928
+ case 'Escape':
1929
+ case 'Tab':
1930
+ this.isOpen.set(false);
1931
+ break;
1932
+ }
1933
+ }
1934
+ onDocumentClick(event) {
1935
+ if (this.isOpen() && !event.target.closest('ui-select')) {
1936
+ this.isOpen.set(false);
1937
+ }
1938
+ }
1939
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1940
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SelectComponent, isStandalone: true, selector: "ui-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", 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 }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, leadingIcon: { classPropertyName: "leadingIcon", publicName: "leadingIcon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", change: "change" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [{
1941
+ provide: NG_VALUE_ACCESSOR,
1942
+ useExisting: forwardRef(() => SelectComponent),
1943
+ multi: true,
1944
+ }], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true }], ngImport: i0, template: `
1945
+ <div
1946
+ class="ui-select"
1947
+ [class.ui-select--open]="isOpen()"
1948
+ [class.ui-select--disabled]="disabled()"
1949
+ >
1950
+ <!-- Trigger -->
1951
+ <button
1952
+ #triggerEl
1953
+ type="button"
1954
+ [class]="triggerClasses()"
1955
+ [disabled]="disabled() || loading()"
1956
+ [attr.aria-haspopup]="'listbox'"
1957
+ [attr.aria-expanded]="isOpen()"
1958
+ [attr.aria-label]="ariaLabel() ?? null"
1959
+ (click)="toggleOpen(); $event.stopPropagation()"
1960
+ (keydown)="onTriggerKeydown($event)"
1961
+ >
1962
+ @if (leadingIcon()) {
1963
+ <span class="ui-select__leading" aria-hidden="true">
1964
+ <ng-content select="[slot=leading]" />
1965
+ </span>
1966
+ }
1967
+
1968
+ <span class="ui-select__value" [class.ui-select__value--placeholder]="!selectedOption()">
1969
+ @if (loading()) {
1970
+ <span class="ui-select__spinner" aria-hidden="true">
1971
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1972
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
1973
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
1974
+ </svg>
1975
+ </span>
1976
+ } @else {
1977
+ {{ selectedOption()?.label ?? placeholder() ?? 'Sélectionner...' }}
1978
+ }
1979
+ </span>
1980
+
1981
+ <span class="ui-select__chevron" [class.ui-select__chevron--open]="isOpen()" aria-hidden="true">
1982
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75"
1983
+ stroke-linecap="round" stroke-linejoin="round">
1984
+ <path d="M4 6l4 4 4-4"/>
1985
+ </svg>
1986
+ </span>
1987
+ </button>
1988
+
1989
+ <!-- Dropdown panel -->
1990
+ @if (isOpen()) {
1991
+ <div
1992
+ [@dropdown]
1993
+ class="ui-select__panel"
1994
+ role="listbox"
1995
+ [attr.aria-label]="ariaLabel() ?? 'Options'"
1996
+ (click)="$event.stopPropagation()"
1997
+ >
1998
+ @for (opt of options(); track opt.value; let i = $index) {
1999
+ <button
2000
+ type="button"
2001
+ class="ui-select__option"
2002
+ role="option"
2003
+ [class.ui-select__option--selected]="isSelected(opt)"
2004
+ [class.ui-select__option--highlighted]="activeIndex() === i"
2005
+ [class.ui-select__option--disabled]="opt.disabled"
2006
+ [attr.aria-selected]="isSelected(opt)"
2007
+ [disabled]="opt.disabled"
2008
+ (click)="selectOption(opt)"
2009
+ (mouseenter)="activeIndex.set(i)"
2010
+ >
2011
+ @if (opt.icon) {
2012
+ <span class="ui-select__option-icon" aria-hidden="true">{{ opt.icon }}</span>
2013
+ }
2014
+ <span class="ui-select__option-label">{{ opt.label }}</span>
2015
+ @if (isSelected(opt)) {
2016
+ <span class="ui-select__option-check" aria-hidden="true">
2017
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.25"
2018
+ stroke-linecap="round" stroke-linejoin="round">
2019
+ <path d="M3 8l3.5 3.5L13 5"/>
2020
+ </svg>
2021
+ </span>
2022
+ }
2023
+ </button>
2024
+ }
2025
+ @if (options().length === 0) {
2026
+ <div class="ui-select__empty">Aucune option disponible</div>
2027
+ }
2028
+ </div>
2029
+ }
2030
+ </div>
2031
+ `, isInline: true, styles: [".ui-select{position:relative;display:inline-block;width:100%}.ui-select--disabled{opacity:.5;cursor:not-allowed}.ui-select__trigger{display:inline-flex;align-items:center;gap:.375rem;width:100%;border-radius:var(--radius-md);font-family:var(--font-sans);font-weight:var(--font-medium);cursor:pointer;outline:none;transition:background-color var(--transition-colors),border-color var(--transition-colors),box-shadow var(--transition-colors);text-align:left;white-space:nowrap;overflow:hidden}.ui-select__trigger--xs{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-select__trigger--sm{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-select__trigger--md{height:var(--size-md);padding:0 10px;font-size:var(--text-sm)}.ui-select__trigger--lg{height:var(--size-lg);padding:0 12px;font-size:var(--text-sm)}.ui-select__trigger--xl{height:var(--size-xl);padding:0 12px;font-size:var(--text-md)}.ui-select__trigger--outline.ui-select__trigger--neutral{background:var(--color-bg);border:1px solid var(--color-border);color:var(--color-text)}.ui-select__trigger--outline.ui-select__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-400)}.ui-select__trigger--outline.ui-select__trigger--neutral:focus-visible{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-select__trigger--soft.ui-select__trigger--neutral{background:var(--color-neutral-100);border:1px solid transparent;color:var(--color-text)}.ui-select__trigger--soft.ui-select__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-200)}.ui-select__trigger--soft.ui-select__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select__trigger--subtle.ui-select__trigger--neutral{background:transparent;border:1px solid transparent;color:var(--color-text)}.ui-select__trigger--subtle.ui-select__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-100)}.ui-select__trigger--subtle.ui-select__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select__trigger--ghost.ui-select__trigger--neutral{background:transparent;border:1px solid transparent;color:var(--color-text)}.ui-select__trigger--ghost.ui-select__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-100)}.ui-select__trigger--ghost.ui-select__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select__trigger--none.ui-select__trigger--neutral{background:transparent;border:none;color:var(--color-text)}.ui-select__trigger--outline.ui-select__trigger--primary{background:var(--color-bg);border:1px solid var(--color-primary-500);color:var(--color-primary-600)}.ui-select__trigger--outline.ui-select__trigger--primary:hover:not(:disabled){border-color:var(--color-primary-600);background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--primary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--primary{background:color-mix(in srgb,var(--color-primary-500) 10%,transparent);border:1px solid transparent;color:var(--color-primary-600)}.ui-select__trigger--soft.ui-select__trigger--primary:hover:not(:disabled){background:color-mix(in srgb,var(--color-primary-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--primary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--error{background:var(--color-bg);border:1px solid var(--color-error-500);color:var(--color-error-600)}.ui-select__trigger--outline.ui-select__trigger--error:hover:not(:disabled){background:color-mix(in srgb,var(--color-error-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--error:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-error-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--error{background:color-mix(in srgb,var(--color-error-500) 10%,transparent);border:1px solid transparent;color:var(--color-error-700)}.ui-select__trigger--soft.ui-select__trigger--error:hover:not(:disabled){background:color-mix(in srgb,var(--color-error-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--error:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-error-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--warning{background:var(--color-bg);border:1px solid var(--color-warning-500);color:var(--color-warning-600)}.ui-select__trigger--outline.ui-select__trigger--warning:hover:not(:disabled){background:color-mix(in srgb,var(--color-warning-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--warning:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-warning-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--warning{background:color-mix(in srgb,var(--color-warning-500) 10%,transparent);border:1px solid transparent;color:var(--color-warning-700)}.ui-select__trigger--soft.ui-select__trigger--warning:hover:not(:disabled){background:color-mix(in srgb,var(--color-warning-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--warning:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-warning-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--success{background:var(--color-bg);border:1px solid var(--color-success-500);color:var(--color-success-600)}.ui-select__trigger--outline.ui-select__trigger--success:hover:not(:disabled){background:color-mix(in srgb,var(--color-success-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--success:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-success-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--success{background:color-mix(in srgb,var(--color-success-500) 10%,transparent);border:1px solid transparent;color:var(--color-success-700)}.ui-select__trigger--soft.ui-select__trigger--success:hover:not(:disabled){background:color-mix(in srgb,var(--color-success-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--success:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-success-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--info{background:var(--color-bg);border:1px solid var(--color-info-500);color:var(--color-info-600)}.ui-select__trigger--outline.ui-select__trigger--info:hover:not(:disabled){background:color-mix(in srgb,var(--color-info-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--info:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-info-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--info{background:color-mix(in srgb,var(--color-info-500) 10%,transparent);border:1px solid transparent;color:var(--color-info-700)}.ui-select__trigger--soft.ui-select__trigger--info:hover:not(:disabled){background:color-mix(in srgb,var(--color-info-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--info:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-info-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--secondary{background:var(--color-bg);border:1px solid var(--color-secondary-500);color:var(--color-secondary-600)}.ui-select__trigger--outline.ui-select__trigger--secondary:hover:not(:disabled){background:color-mix(in srgb,var(--color-secondary-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--secondary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-secondary-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--secondary{background:color-mix(in srgb,var(--color-secondary-500) 10%,transparent);border:1px solid transparent;color:var(--color-secondary-700)}.ui-select__trigger--soft.ui-select__trigger--secondary:hover:not(:disabled){background:color-mix(in srgb,var(--color-secondary-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--secondary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-secondary-500) 40%,transparent)}.ui-select--open .ui-select__trigger--outline{border-color:var(--color-primary-500)}.ui-select__trigger:disabled{cursor:not-allowed}.ui-select__leading{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem}.ui-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__value--placeholder{color:var(--color-text-muted)}.ui-select__chevron{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem;transition:transform .15s ease}.ui-select__chevron svg{width:100%;height:100%}.ui-select__chevron--open{transform:rotate(180deg)}.ui-select__spinner{display:inline-flex;align-items:center}.ui-select__spinner svg{width:1em;height:1em;animation:ui-spin .75s linear infinite}@keyframes ui-spin{to{transform:rotate(360deg)}}.ui-select__panel{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:var(--z-dropdown, 50);min-width:100%;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1));padding:4px;overflow:hidden;overflow-y:auto;max-height:240px;transform-origin:top center}.ui-select__option{display:flex;align-items:center;gap:.5rem;width:100%;padding:6px 8px;border-radius:calc(var(--radius-md) - 2px);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-normal);color:var(--color-text);background:transparent;border:none;cursor:pointer;text-align:left;transition:background-color .1s ease}.ui-select__option:hover:not(:disabled),.ui-select__option--highlighted:not(:disabled){background:var(--color-neutral-100)}.ui-select__option--selected{color:var(--color-primary-600);font-weight:var(--font-medium);background:color-mix(in srgb,var(--color-primary-500) 8%,transparent)}.ui-select__option--selected:hover,.ui-select__option--selected.ui-select__option--highlighted{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}.ui-select__option--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-select__option-icon{flex-shrink:0;font-size:1rem;line-height:1}.ui-select__option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__option-check{flex-shrink:0;width:1rem;height:1rem;color:var(--color-primary-500);display:flex;align-items:center}.ui-select__option-check svg{width:100%;height:100%}.ui-select__empty{padding:12px 8px;text-align:center;font-size:var(--text-sm);color:var(--color-text-muted)}[data-theme=dark] .ui-select__trigger--outline.ui-select__trigger--neutral{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select__trigger--outline.ui-select__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-500)}[data-theme=dark] .ui-select__trigger--soft.ui-select__trigger--neutral{background:var(--color-neutral-800)}[data-theme=dark] .ui-select__panel{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select__option:hover:not(:disabled),[data-theme=dark] .ui-select__option--highlighted:not(:disabled){background:var(--color-neutral-800)}[data-theme=dark] .ui-select__option--selected{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
2032
+ trigger('dropdown', [
2033
+ transition(':enter', [
2034
+ style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' }),
2035
+ animate('100ms ease-out', style({ opacity: 1, transform: 'scale(1) translateY(0)' })),
2036
+ ]),
2037
+ transition(':leave', [
2038
+ animate('80ms ease-in', style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' })),
2039
+ ]),
2040
+ ]),
2041
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2042
+ }
2043
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SelectComponent, decorators: [{
2044
+ type: Component,
2045
+ args: [{ selector: 'ui-select', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{
2046
+ provide: NG_VALUE_ACCESSOR,
2047
+ useExisting: forwardRef(() => SelectComponent),
2048
+ multi: true,
2049
+ }], animations: [
2050
+ trigger('dropdown', [
2051
+ transition(':enter', [
2052
+ style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' }),
2053
+ animate('100ms ease-out', style({ opacity: 1, transform: 'scale(1) translateY(0)' })),
2054
+ ]),
2055
+ transition(':leave', [
2056
+ animate('80ms ease-in', style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' })),
2057
+ ]),
2058
+ ]),
2059
+ ], template: `
2060
+ <div
2061
+ class="ui-select"
2062
+ [class.ui-select--open]="isOpen()"
2063
+ [class.ui-select--disabled]="disabled()"
2064
+ >
2065
+ <!-- Trigger -->
2066
+ <button
2067
+ #triggerEl
2068
+ type="button"
2069
+ [class]="triggerClasses()"
2070
+ [disabled]="disabled() || loading()"
2071
+ [attr.aria-haspopup]="'listbox'"
2072
+ [attr.aria-expanded]="isOpen()"
2073
+ [attr.aria-label]="ariaLabel() ?? null"
2074
+ (click)="toggleOpen(); $event.stopPropagation()"
2075
+ (keydown)="onTriggerKeydown($event)"
2076
+ >
2077
+ @if (leadingIcon()) {
2078
+ <span class="ui-select__leading" aria-hidden="true">
2079
+ <ng-content select="[slot=leading]" />
2080
+ </span>
2081
+ }
2082
+
2083
+ <span class="ui-select__value" [class.ui-select__value--placeholder]="!selectedOption()">
2084
+ @if (loading()) {
2085
+ <span class="ui-select__spinner" aria-hidden="true">
2086
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2087
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
2088
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
2089
+ </svg>
2090
+ </span>
2091
+ } @else {
2092
+ {{ selectedOption()?.label ?? placeholder() ?? 'Sélectionner...' }}
2093
+ }
2094
+ </span>
2095
+
2096
+ <span class="ui-select__chevron" [class.ui-select__chevron--open]="isOpen()" aria-hidden="true">
2097
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.75"
2098
+ stroke-linecap="round" stroke-linejoin="round">
2099
+ <path d="M4 6l4 4 4-4"/>
2100
+ </svg>
2101
+ </span>
2102
+ </button>
2103
+
2104
+ <!-- Dropdown panel -->
2105
+ @if (isOpen()) {
2106
+ <div
2107
+ [@dropdown]
2108
+ class="ui-select__panel"
2109
+ role="listbox"
2110
+ [attr.aria-label]="ariaLabel() ?? 'Options'"
2111
+ (click)="$event.stopPropagation()"
2112
+ >
2113
+ @for (opt of options(); track opt.value; let i = $index) {
2114
+ <button
2115
+ type="button"
2116
+ class="ui-select__option"
2117
+ role="option"
2118
+ [class.ui-select__option--selected]="isSelected(opt)"
2119
+ [class.ui-select__option--highlighted]="activeIndex() === i"
2120
+ [class.ui-select__option--disabled]="opt.disabled"
2121
+ [attr.aria-selected]="isSelected(opt)"
2122
+ [disabled]="opt.disabled"
2123
+ (click)="selectOption(opt)"
2124
+ (mouseenter)="activeIndex.set(i)"
2125
+ >
2126
+ @if (opt.icon) {
2127
+ <span class="ui-select__option-icon" aria-hidden="true">{{ opt.icon }}</span>
2128
+ }
2129
+ <span class="ui-select__option-label">{{ opt.label }}</span>
2130
+ @if (isSelected(opt)) {
2131
+ <span class="ui-select__option-check" aria-hidden="true">
2132
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.25"
2133
+ stroke-linecap="round" stroke-linejoin="round">
2134
+ <path d="M3 8l3.5 3.5L13 5"/>
2135
+ </svg>
2136
+ </span>
2137
+ }
2138
+ </button>
2139
+ }
2140
+ @if (options().length === 0) {
2141
+ <div class="ui-select__empty">Aucune option disponible</div>
2142
+ }
2143
+ </div>
2144
+ }
2145
+ </div>
2146
+ `, styles: [".ui-select{position:relative;display:inline-block;width:100%}.ui-select--disabled{opacity:.5;cursor:not-allowed}.ui-select__trigger{display:inline-flex;align-items:center;gap:.375rem;width:100%;border-radius:var(--radius-md);font-family:var(--font-sans);font-weight:var(--font-medium);cursor:pointer;outline:none;transition:background-color var(--transition-colors),border-color var(--transition-colors),box-shadow var(--transition-colors);text-align:left;white-space:nowrap;overflow:hidden}.ui-select__trigger--xs{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-select__trigger--sm{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-select__trigger--md{height:var(--size-md);padding:0 10px;font-size:var(--text-sm)}.ui-select__trigger--lg{height:var(--size-lg);padding:0 12px;font-size:var(--text-sm)}.ui-select__trigger--xl{height:var(--size-xl);padding:0 12px;font-size:var(--text-md)}.ui-select__trigger--outline.ui-select__trigger--neutral{background:var(--color-bg);border:1px solid var(--color-border);color:var(--color-text)}.ui-select__trigger--outline.ui-select__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-400)}.ui-select__trigger--outline.ui-select__trigger--neutral:focus-visible{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-select__trigger--soft.ui-select__trigger--neutral{background:var(--color-neutral-100);border:1px solid transparent;color:var(--color-text)}.ui-select__trigger--soft.ui-select__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-200)}.ui-select__trigger--soft.ui-select__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select__trigger--subtle.ui-select__trigger--neutral{background:transparent;border:1px solid transparent;color:var(--color-text)}.ui-select__trigger--subtle.ui-select__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-100)}.ui-select__trigger--subtle.ui-select__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select__trigger--ghost.ui-select__trigger--neutral{background:transparent;border:1px solid transparent;color:var(--color-text)}.ui-select__trigger--ghost.ui-select__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-100)}.ui-select__trigger--ghost.ui-select__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select__trigger--none.ui-select__trigger--neutral{background:transparent;border:none;color:var(--color-text)}.ui-select__trigger--outline.ui-select__trigger--primary{background:var(--color-bg);border:1px solid var(--color-primary-500);color:var(--color-primary-600)}.ui-select__trigger--outline.ui-select__trigger--primary:hover:not(:disabled){border-color:var(--color-primary-600);background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--primary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--primary{background:color-mix(in srgb,var(--color-primary-500) 10%,transparent);border:1px solid transparent;color:var(--color-primary-600)}.ui-select__trigger--soft.ui-select__trigger--primary:hover:not(:disabled){background:color-mix(in srgb,var(--color-primary-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--primary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--error{background:var(--color-bg);border:1px solid var(--color-error-500);color:var(--color-error-600)}.ui-select__trigger--outline.ui-select__trigger--error:hover:not(:disabled){background:color-mix(in srgb,var(--color-error-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--error:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-error-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--error{background:color-mix(in srgb,var(--color-error-500) 10%,transparent);border:1px solid transparent;color:var(--color-error-700)}.ui-select__trigger--soft.ui-select__trigger--error:hover:not(:disabled){background:color-mix(in srgb,var(--color-error-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--error:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-error-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--warning{background:var(--color-bg);border:1px solid var(--color-warning-500);color:var(--color-warning-600)}.ui-select__trigger--outline.ui-select__trigger--warning:hover:not(:disabled){background:color-mix(in srgb,var(--color-warning-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--warning:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-warning-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--warning{background:color-mix(in srgb,var(--color-warning-500) 10%,transparent);border:1px solid transparent;color:var(--color-warning-700)}.ui-select__trigger--soft.ui-select__trigger--warning:hover:not(:disabled){background:color-mix(in srgb,var(--color-warning-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--warning:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-warning-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--success{background:var(--color-bg);border:1px solid var(--color-success-500);color:var(--color-success-600)}.ui-select__trigger--outline.ui-select__trigger--success:hover:not(:disabled){background:color-mix(in srgb,var(--color-success-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--success:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-success-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--success{background:color-mix(in srgb,var(--color-success-500) 10%,transparent);border:1px solid transparent;color:var(--color-success-700)}.ui-select__trigger--soft.ui-select__trigger--success:hover:not(:disabled){background:color-mix(in srgb,var(--color-success-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--success:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-success-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--info{background:var(--color-bg);border:1px solid var(--color-info-500);color:var(--color-info-600)}.ui-select__trigger--outline.ui-select__trigger--info:hover:not(:disabled){background:color-mix(in srgb,var(--color-info-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--info:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-info-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--info{background:color-mix(in srgb,var(--color-info-500) 10%,transparent);border:1px solid transparent;color:var(--color-info-700)}.ui-select__trigger--soft.ui-select__trigger--info:hover:not(:disabled){background:color-mix(in srgb,var(--color-info-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--info:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-info-500) 40%,transparent)}.ui-select__trigger--outline.ui-select__trigger--secondary{background:var(--color-bg);border:1px solid var(--color-secondary-500);color:var(--color-secondary-600)}.ui-select__trigger--outline.ui-select__trigger--secondary:hover:not(:disabled){background:color-mix(in srgb,var(--color-secondary-500) 5%,transparent)}.ui-select__trigger--outline.ui-select__trigger--secondary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-secondary-500) 30%,transparent)}.ui-select__trigger--soft.ui-select__trigger--secondary{background:color-mix(in srgb,var(--color-secondary-500) 10%,transparent);border:1px solid transparent;color:var(--color-secondary-700)}.ui-select__trigger--soft.ui-select__trigger--secondary:hover:not(:disabled){background:color-mix(in srgb,var(--color-secondary-500) 15%,transparent)}.ui-select__trigger--soft.ui-select__trigger--secondary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-secondary-500) 40%,transparent)}.ui-select--open .ui-select__trigger--outline{border-color:var(--color-primary-500)}.ui-select__trigger:disabled{cursor:not-allowed}.ui-select__leading{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem}.ui-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__value--placeholder{color:var(--color-text-muted)}.ui-select__chevron{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem;transition:transform .15s ease}.ui-select__chevron svg{width:100%;height:100%}.ui-select__chevron--open{transform:rotate(180deg)}.ui-select__spinner{display:inline-flex;align-items:center}.ui-select__spinner svg{width:1em;height:1em;animation:ui-spin .75s linear infinite}@keyframes ui-spin{to{transform:rotate(360deg)}}.ui-select__panel{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:var(--z-dropdown, 50);min-width:100%;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1));padding:4px;overflow:hidden;overflow-y:auto;max-height:240px;transform-origin:top center}.ui-select__option{display:flex;align-items:center;gap:.5rem;width:100%;padding:6px 8px;border-radius:calc(var(--radius-md) - 2px);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-normal);color:var(--color-text);background:transparent;border:none;cursor:pointer;text-align:left;transition:background-color .1s ease}.ui-select__option:hover:not(:disabled),.ui-select__option--highlighted:not(:disabled){background:var(--color-neutral-100)}.ui-select__option--selected{color:var(--color-primary-600);font-weight:var(--font-medium);background:color-mix(in srgb,var(--color-primary-500) 8%,transparent)}.ui-select__option--selected:hover,.ui-select__option--selected.ui-select__option--highlighted{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}.ui-select__option--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-select__option-icon{flex-shrink:0;font-size:1rem;line-height:1}.ui-select__option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__option-check{flex-shrink:0;width:1rem;height:1rem;color:var(--color-primary-500);display:flex;align-items:center}.ui-select__option-check svg{width:100%;height:100%}.ui-select__empty{padding:12px 8px;text-align:center;font-size:var(--text-sm);color:var(--color-text-muted)}[data-theme=dark] .ui-select__trigger--outline.ui-select__trigger--neutral{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select__trigger--outline.ui-select__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-500)}[data-theme=dark] .ui-select__trigger--soft.ui-select__trigger--neutral{background:var(--color-neutral-800)}[data-theme=dark] .ui-select__panel{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select__option:hover:not(:disabled),[data-theme=dark] .ui-select__option--highlighted:not(:disabled){background:var(--color-neutral-800)}[data-theme=dark] .ui-select__option--selected{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}\n"] }]
2147
+ }], propDecorators: { triggerEl: [{
2148
+ type: ViewChild,
2149
+ args: ['triggerEl']
2150
+ }], onDocumentClick: [{
2151
+ type: HostListener,
2152
+ args: ['document:click', ['$event']]
2153
+ }] } });
2154
+
2155
+ /**
2156
+ * Tabs Molecule — Source: Nuxt UI v3 ❖ Tabs
2157
+ * Tabbed navigation with pill, link and underline variants
2158
+ */
2159
+ class TabsComponent {
2160
+ constructor() {
2161
+ this.items = input.required();
2162
+ this.variant = input('pill');
2163
+ this.size = input('md');
2164
+ this.activeId = model('');
2165
+ }
2166
+ select(id) { this.activeId.set(id); }
2167
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2168
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: TabsComponent, isStandalone: true, selector: "ui-tabs", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, activeId: { classPropertyName: "activeId", publicName: "activeId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeId: "activeIdChange" }, ngImport: i0, template: `
2169
+ <div class="ui-tabs ui-tabs--{{ variant() }} ui-tabs--{{ size() }}" role="tablist">
2170
+ @for (tab of items(); track tab.id) {
2171
+ <button
2172
+ role="tab"
2173
+ type="button"
2174
+ [class]="'ui-tabs__tab' + (activeId() === tab.id ? ' ui-tabs__tab--active' : '') + (tab.disabled ? ' ui-tabs__tab--disabled' : '')"
2175
+ [attr.aria-selected]="activeId() === tab.id"
2176
+ [attr.aria-controls]="'panel-' + tab.id"
2177
+ [disabled]="tab.disabled"
2178
+ (click)="select(tab.id)"
2179
+ >
2180
+ {{ tab.label }}
2181
+ @if (tab.count !== undefined) {
2182
+ <span class="ui-tabs__count">{{ tab.count }}</span>
2183
+ }
2184
+ </button>
2185
+ }
2186
+ </div>
2187
+ <div class="ui-tabs__panels">
2188
+ <ng-content />
2189
+ </div>
2190
+ `, isInline: true, styles: [".ui-tabs{display:flex;align-items:center;gap:var(--spacing-1);overflow-x:auto}.ui-tabs--xs .ui-tabs__tab{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-tabs--sm .ui-tabs__tab{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-tabs--md .ui-tabs__tab{height:var(--size-md);padding:0 12px;font-size:var(--text-sm)}.ui-tabs--lg .ui-tabs__tab{height:var(--size-lg);padding:0 14px;font-size:var(--text-sm)}.ui-tabs--xl .ui-tabs__tab{height:var(--size-xl);padding:0 16px;font-size:var(--text-md)}.ui-tabs__tab{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);cursor:pointer;border:none;background:transparent;font-family:var(--font-sans);font-weight:var(--font-medium);color:var(--color-text-muted);border-radius:var(--radius-md);white-space:nowrap;transition:var(--transition-colors)}.ui-tabs__tab:hover:not(.ui-tabs__tab--disabled){color:var(--color-text)}.ui-tabs__tab--disabled{opacity:.5;cursor:not-allowed}.ui-tabs__count{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;border-radius:var(--radius-full);font-size:.75em;background:var(--color-neutral-100);color:var(--color-text-muted)}.ui-tabs--pill .ui-tabs__tab--active{background:var(--color-primary-500);color:#fff}.ui-tabs--pill .ui-tabs__tab--active .ui-tabs__count{background:#ffffff4d;color:#fff}.ui-tabs--link .ui-tabs__tab--active{color:var(--color-primary-500);font-weight:var(--font-semibold)}.ui-tabs--underline{border-bottom:1px solid var(--color-border);border-radius:0;gap:0}.ui-tabs--underline .ui-tabs__tab{border-radius:0;border-bottom:2px solid transparent;margin-bottom:-1px}.ui-tabs--underline .ui-tabs__tab--active{color:var(--color-primary-500);border-bottom-color:var(--color-primary-500)}.ui-tabs__panels{margin-top:var(--spacing-4)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2191
+ }
2192
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TabsComponent, decorators: [{
2193
+ type: Component,
2194
+ args: [{ selector: 'ui-tabs', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2195
+ <div class="ui-tabs ui-tabs--{{ variant() }} ui-tabs--{{ size() }}" role="tablist">
2196
+ @for (tab of items(); track tab.id) {
2197
+ <button
2198
+ role="tab"
2199
+ type="button"
2200
+ [class]="'ui-tabs__tab' + (activeId() === tab.id ? ' ui-tabs__tab--active' : '') + (tab.disabled ? ' ui-tabs__tab--disabled' : '')"
2201
+ [attr.aria-selected]="activeId() === tab.id"
2202
+ [attr.aria-controls]="'panel-' + tab.id"
2203
+ [disabled]="tab.disabled"
2204
+ (click)="select(tab.id)"
2205
+ >
2206
+ {{ tab.label }}
2207
+ @if (tab.count !== undefined) {
2208
+ <span class="ui-tabs__count">{{ tab.count }}</span>
2209
+ }
2210
+ </button>
2211
+ }
2212
+ </div>
2213
+ <div class="ui-tabs__panels">
2214
+ <ng-content />
2215
+ </div>
2216
+ `, styles: [".ui-tabs{display:flex;align-items:center;gap:var(--spacing-1);overflow-x:auto}.ui-tabs--xs .ui-tabs__tab{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-tabs--sm .ui-tabs__tab{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-tabs--md .ui-tabs__tab{height:var(--size-md);padding:0 12px;font-size:var(--text-sm)}.ui-tabs--lg .ui-tabs__tab{height:var(--size-lg);padding:0 14px;font-size:var(--text-sm)}.ui-tabs--xl .ui-tabs__tab{height:var(--size-xl);padding:0 16px;font-size:var(--text-md)}.ui-tabs__tab{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);cursor:pointer;border:none;background:transparent;font-family:var(--font-sans);font-weight:var(--font-medium);color:var(--color-text-muted);border-radius:var(--radius-md);white-space:nowrap;transition:var(--transition-colors)}.ui-tabs__tab:hover:not(.ui-tabs__tab--disabled){color:var(--color-text)}.ui-tabs__tab--disabled{opacity:.5;cursor:not-allowed}.ui-tabs__count{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;border-radius:var(--radius-full);font-size:.75em;background:var(--color-neutral-100);color:var(--color-text-muted)}.ui-tabs--pill .ui-tabs__tab--active{background:var(--color-primary-500);color:#fff}.ui-tabs--pill .ui-tabs__tab--active .ui-tabs__count{background:#ffffff4d;color:#fff}.ui-tabs--link .ui-tabs__tab--active{color:var(--color-primary-500);font-weight:var(--font-semibold)}.ui-tabs--underline{border-bottom:1px solid var(--color-border);border-radius:0;gap:0}.ui-tabs--underline .ui-tabs__tab{border-radius:0;border-bottom:2px solid transparent;margin-bottom:-1px}.ui-tabs--underline .ui-tabs__tab--active{color:var(--color-primary-500);border-bottom-color:var(--color-primary-500)}.ui-tabs__panels{margin-top:var(--spacing-4)}\n"] }]
2217
+ }] });
2218
+
2219
+ /**
2220
+ * Textarea Molecule — Source: Nuxt UI v3 ❖ Textarea
2221
+ * Multi-line text input with auto-resize support
2222
+ */
2223
+ class TextareaComponent {
2224
+ constructor() {
2225
+ this.placeholder = input('');
2226
+ this.size = input('md');
2227
+ this.rows = input(4);
2228
+ this.disabled = input(false);
2229
+ this.readonly = input(false);
2230
+ this.autoResize = input(false);
2231
+ this.ariaLabel = input(null);
2232
+ this.value = model('');
2233
+ this._onChange = () => { };
2234
+ this.onTouched = () => { };
2235
+ }
2236
+ onInput(e) {
2237
+ const el = e.target;
2238
+ this.value.set(el.value);
2239
+ this._onChange(el.value);
2240
+ }
2241
+ writeValue(v) { this.value.set(v ?? ''); }
2242
+ registerOnChange(fn) { this._onChange = fn; }
2243
+ registerOnTouched(fn) { this.onTouched = fn; }
2244
+ setDisabledState(_) { }
2245
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TextareaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2246
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.20", type: TextareaComponent, isStandalone: true, selector: "ui-textarea", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, autoResize: { classPropertyName: "autoResize", publicName: "autoResize", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextareaComponent), multi: true }], ngImport: i0, template: `
2247
+ <textarea
2248
+ [class]="'ui-textarea ui-textarea--' + size()"
2249
+ [placeholder]="placeholder()"
2250
+ [disabled]="disabled()"
2251
+ [readonly]="readonly()"
2252
+ [rows]="rows()"
2253
+ [attr.aria-label]="ariaLabel() ?? null"
2254
+ (input)="onInput($event)"
2255
+ (blur)="onTouched()"
2256
+ >{{ value() }}</textarea>
2257
+ `, isInline: true, styles: [".ui-textarea{width:100%;display:block;font-family:var(--font-sans);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);resize:vertical;outline:none;transition:var(--transition-colors)}.ui-textarea::placeholder{color:var(--color-text-subtle)}.ui-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-textarea:disabled{opacity:.5;cursor:not-allowed;resize:none}.ui-textarea--xs{padding:6px 8px;font-size:var(--text-xs)}.ui-textarea--sm{padding:8px 10px;font-size:var(--text-xs)}.ui-textarea--md{padding:8px 10px;font-size:var(--text-sm)}.ui-textarea--lg{padding:10px 12px;font-size:var(--text-sm)}.ui-textarea--xl{padding:10px 12px;font-size:var(--text-md)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2258
+ }
2259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TextareaComponent, decorators: [{
2260
+ type: Component,
2261
+ args: [{ selector: 'ui-textarea', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextareaComponent), multi: true }], template: `
2262
+ <textarea
2263
+ [class]="'ui-textarea ui-textarea--' + size()"
2264
+ [placeholder]="placeholder()"
2265
+ [disabled]="disabled()"
2266
+ [readonly]="readonly()"
2267
+ [rows]="rows()"
2268
+ [attr.aria-label]="ariaLabel() ?? null"
2269
+ (input)="onInput($event)"
2270
+ (blur)="onTouched()"
2271
+ >{{ value() }}</textarea>
2272
+ `, styles: [".ui-textarea{width:100%;display:block;font-family:var(--font-sans);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);resize:vertical;outline:none;transition:var(--transition-colors)}.ui-textarea::placeholder{color:var(--color-text-subtle)}.ui-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-textarea:disabled{opacity:.5;cursor:not-allowed;resize:none}.ui-textarea--xs{padding:6px 8px;font-size:var(--text-xs)}.ui-textarea--sm{padding:8px 10px;font-size:var(--text-xs)}.ui-textarea--md{padding:8px 10px;font-size:var(--text-sm)}.ui-textarea--lg{padding:10px 12px;font-size:var(--text-sm)}.ui-textarea--xl{padding:10px 12px;font-size:var(--text-md)}\n"] }]
2273
+ }] });
2274
+
2275
+ /**
2276
+ * Toast Molecule — Source: Nuxt UI v3 ❖ Toast
2277
+ * Transient notification with auto-close
2278
+ */
2279
+ class ToastComponent {
2280
+ constructor() {
2281
+ this.variant = input('soft');
2282
+ this.color = input('neutral');
2283
+ this.title = input(null);
2284
+ this.description = input(null);
2285
+ this.icon = input(false);
2286
+ this.closable = input(true);
2287
+ this.close = output();
2288
+ }
2289
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2290
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ToastComponent, isStandalone: true, selector: "ui-toast", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close" }, ngImport: i0, template: `
2291
+ <div
2292
+ [class]="'ui-toast ui-toast--' + variant() + ' ui-toast--' + color()"
2293
+ role="status"
2294
+ aria-live="polite"
2295
+ aria-atomic="true"
2296
+ >
2297
+ @if (icon()) {
2298
+ <span class="ui-toast__icon" aria-hidden="true">
2299
+ <ng-content select="[slot=icon]" />
2300
+ </span>
2301
+ }
2302
+ <div class="ui-toast__body">
2303
+ @if (title()) {
2304
+ <p class="ui-toast__title">{{ title() }}</p>
2305
+ }
2306
+ @if (description()) {
2307
+ <p class="ui-toast__description">{{ description() }}</p>
2308
+ }
2309
+ <ng-content />
2310
+ </div>
2311
+ @if (closable()) {
2312
+ <button type="button" class="ui-toast__close" aria-label="Dismiss" (click)="close.emit()">×</button>
2313
+ }
2314
+ </div>
2315
+ `, isInline: true, styles: [".ui-toast{display:flex;align-items:flex-start;gap:var(--spacing-3);padding:var(--spacing-3) var(--spacing-4);border-radius:var(--radius-lg);border:1px solid transparent;box-shadow:var(--shadow-lg);min-width:280px;max-width:480px;background:var(--color-bg);pointer-events:auto}.ui-toast__icon{flex-shrink:0;width:1.25rem;height:1.25rem}.ui-toast__body{flex:1;min-width:0}.ui-toast__title{font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);margin:0}.ui-toast__description{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-text-muted);margin:var(--spacing-0-5) 0 0}.ui-toast__close{flex-shrink:0;cursor:pointer;border:none;background:transparent;font-size:1.25rem;color:var(--color-text-muted);line-height:1;padding:0}.ui-toast__close:hover{color:var(--color-text)}.ui-toast--success{border-color:var(--color-success-200)}.ui-toast--error{border-color:var(--color-error-200)}.ui-toast--warning{border-color:var(--color-warning-200)}.ui-toast--info{border-color:var(--color-info-200)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2316
+ }
2317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ToastComponent, decorators: [{
2318
+ type: Component,
2319
+ args: [{ selector: 'ui-toast', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2320
+ <div
2321
+ [class]="'ui-toast ui-toast--' + variant() + ' ui-toast--' + color()"
2322
+ role="status"
2323
+ aria-live="polite"
2324
+ aria-atomic="true"
2325
+ >
2326
+ @if (icon()) {
2327
+ <span class="ui-toast__icon" aria-hidden="true">
2328
+ <ng-content select="[slot=icon]" />
2329
+ </span>
2330
+ }
2331
+ <div class="ui-toast__body">
2332
+ @if (title()) {
2333
+ <p class="ui-toast__title">{{ title() }}</p>
2334
+ }
2335
+ @if (description()) {
2336
+ <p class="ui-toast__description">{{ description() }}</p>
2337
+ }
2338
+ <ng-content />
2339
+ </div>
2340
+ @if (closable()) {
2341
+ <button type="button" class="ui-toast__close" aria-label="Dismiss" (click)="close.emit()">×</button>
2342
+ }
2343
+ </div>
2344
+ `, styles: [".ui-toast{display:flex;align-items:flex-start;gap:var(--spacing-3);padding:var(--spacing-3) var(--spacing-4);border-radius:var(--radius-lg);border:1px solid transparent;box-shadow:var(--shadow-lg);min-width:280px;max-width:480px;background:var(--color-bg);pointer-events:auto}.ui-toast__icon{flex-shrink:0;width:1.25rem;height:1.25rem}.ui-toast__body{flex:1;min-width:0}.ui-toast__title{font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);margin:0}.ui-toast__description{font-family:var(--font-sans);font-size:var(--text-xs);color:var(--color-text-muted);margin:var(--spacing-0-5) 0 0}.ui-toast__close{flex-shrink:0;cursor:pointer;border:none;background:transparent;font-size:1.25rem;color:var(--color-text-muted);line-height:1;padding:0}.ui-toast__close:hover{color:var(--color-text)}.ui-toast--success{border-color:var(--color-success-200)}.ui-toast--error{border-color:var(--color-error-200)}.ui-toast--warning{border-color:var(--color-warning-200)}.ui-toast--info{border-color:var(--color-info-200)}\n"] }]
2345
+ }] });
2346
+
2347
+ /**
2348
+ * SelectSearch Molecule — Source: Nuxt UI v3 ❖ SelectMenu / Combobox
2349
+ *
2350
+ * Extension du Select avec un input de recherche intégré dans le panel :
2351
+ * - Filtre les options en temps réel (case-insensitive)
2352
+ * - Highlight du terme recherché dans les labels
2353
+ * - "Aucun résultat" si aucune option trouvée
2354
+ * - Clavier : ↑↓ navigue, Enter sélectionne, Escape ferme, Tab ferme
2355
+ * - Focus automatique sur l'input à l'ouverture
2356
+ * - Même API / variants / couleurs / tailles que SelectComponent
2357
+ * - Compatible ControlValueAccessor
2358
+ *
2359
+ * @example
2360
+ * <ui-select-search [options]="pays" placeholder="Rechercher un pays..." />
2361
+ * <ui-select-search [(value)]="val" variant="soft" color="primary" />
2362
+ */
2363
+ class SelectSearchComponent {
2364
+ constructor() {
2365
+ // ── Inputs ───────────────────────────────────────────────
2366
+ this.options = input.required();
2367
+ this.placeholder = input(null);
2368
+ this.searchPlaceholder = input('Rechercher...');
2369
+ this.emptyLabel = input('Aucun résultat');
2370
+ this.size = input('md');
2371
+ this.variant = input('outline');
2372
+ this.color = input('neutral');
2373
+ this.disabled = input(false);
2374
+ this.loading = input(false);
2375
+ this.leadingIcon = input(false);
2376
+ this.ariaLabel = input(null);
2377
+ // ── Two-way binding ──────────────────────────────────────
2378
+ this.value = model('');
2379
+ this.change = output();
2380
+ // ── Internal state ───────────────────────────────────────
2381
+ this.isOpen = signal(false);
2382
+ this.activeIndex = signal(-1);
2383
+ this.query = signal('');
2384
+ this.selectedOption = computed(() => this.options().find(o => String(o.value) === String(this.value())));
2385
+ this.filteredOptions = computed(() => {
2386
+ const q = this.query().trim().toLowerCase();
2387
+ if (!q)
2388
+ return this.options();
2389
+ return this.options().filter(o => o.label.toLowerCase().includes(q));
2390
+ });
2391
+ this.triggerClasses = computed(() => ['ui-select-search__trigger',
2392
+ `ui-select-search__trigger--${this.size()}`,
2393
+ `ui-select-search__trigger--${this.variant()}`,
2394
+ `ui-select-search__trigger--${this.color()}`
2395
+ ].join(' '));
2396
+ // ── CVA ──────────────────────────────────────────────────
2397
+ this._onChange = () => { };
2398
+ this._onTouched = () => { };
2399
+ }
2400
+ isSelected(opt) {
2401
+ return String(opt.value) === String(this.value());
2402
+ }
2403
+ /** Entoure le terme recherché dans le label avec <mark> */
2404
+ highlight(label) {
2405
+ const q = this.query().trim();
2406
+ if (!q)
2407
+ return label;
2408
+ const escaped = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2409
+ return label.replace(new RegExp(`(${escaped})`, 'gi'), '<mark class="ui-select-search__highlight">$1</mark>');
2410
+ }
2411
+ writeValue(v) { this.value.set(v ?? ''); }
2412
+ registerOnChange(fn) { this._onChange = fn; }
2413
+ registerOnTouched(fn) { this._onTouched = fn; }
2414
+ setDisabledState(_) { }
2415
+ ngAfterViewInit() { }
2416
+ // ── Actions ──────────────────────────────────────────────
2417
+ toggleOpen() {
2418
+ if (this.disabled() || this.loading())
2419
+ return;
2420
+ this.isOpen.update(v => !v);
2421
+ if (this.isOpen()) {
2422
+ this.query.set('');
2423
+ const idx = this.filteredOptions().findIndex(o => this.isSelected(o));
2424
+ this.activeIndex.set(idx >= 0 ? idx : 0);
2425
+ // Focus search input after animation
2426
+ setTimeout(() => this.searchInput?.nativeElement.focus(), 60);
2427
+ }
2428
+ }
2429
+ selectOption(opt) {
2430
+ if (opt.disabled)
2431
+ return;
2432
+ const val = String(opt.value);
2433
+ this.value.set(val);
2434
+ this._onChange(val);
2435
+ this._onTouched();
2436
+ this.change.emit(opt);
2437
+ this.isOpen.set(false);
2438
+ this.query.set('');
2439
+ this.triggerEl?.nativeElement.focus();
2440
+ }
2441
+ clearQuery() {
2442
+ this.query.set('');
2443
+ this.activeIndex.set(0);
2444
+ this.searchInput?.nativeElement.focus();
2445
+ }
2446
+ // ── Keyboard — trigger ───────────────────────────────────
2447
+ onTriggerKeydown(event) {
2448
+ switch (event.key) {
2449
+ case 'Enter':
2450
+ case ' ':
2451
+ event.preventDefault();
2452
+ this.toggleOpen();
2453
+ break;
2454
+ case 'ArrowDown':
2455
+ event.preventDefault();
2456
+ this.toggleOpen();
2457
+ break;
2458
+ case 'Escape':
2459
+ this.isOpen.set(false);
2460
+ break;
2461
+ }
2462
+ }
2463
+ // ── Keyboard — search input ──────────────────────────────
2464
+ onSearchKeydown(event) {
2465
+ const opts = this.filteredOptions();
2466
+ switch (event.key) {
2467
+ case 'ArrowDown':
2468
+ event.preventDefault();
2469
+ this.activeIndex.update(i => {
2470
+ let n = i + 1;
2471
+ while (n < opts.length && opts[n]?.disabled)
2472
+ n++;
2473
+ return Math.min(n, opts.length - 1);
2474
+ });
2475
+ break;
2476
+ case 'ArrowUp':
2477
+ event.preventDefault();
2478
+ this.activeIndex.update(i => {
2479
+ let n = i - 1;
2480
+ while (n >= 0 && opts[n]?.disabled)
2481
+ n--;
2482
+ return Math.max(n, 0);
2483
+ });
2484
+ break;
2485
+ case 'Enter':
2486
+ event.preventDefault();
2487
+ const opt = opts[this.activeIndex()];
2488
+ if (opt && !opt.disabled)
2489
+ this.selectOption(opt);
2490
+ break;
2491
+ case 'Escape':
2492
+ case 'Tab':
2493
+ this.isOpen.set(false);
2494
+ this.triggerEl?.nativeElement.focus();
2495
+ break;
2496
+ }
2497
+ }
2498
+ // ── Close on outside click ───────────────────────────────
2499
+ onDocumentClick(event) {
2500
+ if (this.isOpen() && !event.target.closest('ui-select-search')) {
2501
+ this.isOpen.set(false);
2502
+ }
2503
+ }
2504
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SelectSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2505
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SelectSearchComponent, isStandalone: true, selector: "ui-select-search", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", 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 }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, leadingIcon: { classPropertyName: "leadingIcon", publicName: "leadingIcon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", change: "change" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [{
2506
+ provide: NG_VALUE_ACCESSOR,
2507
+ useExisting: forwardRef(() => SelectSearchComponent),
2508
+ multi: true,
2509
+ }], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: `
2510
+ <div
2511
+ class="ui-select-search"
2512
+ [class.ui-select-search--open]="isOpen()"
2513
+ [class.ui-select-search--disabled]="disabled()"
2514
+ >
2515
+ <!-- ── Trigger ──────────────────────────────────────── -->
2516
+ <button
2517
+ #triggerEl
2518
+ type="button"
2519
+ [class]="triggerClasses()"
2520
+ [disabled]="disabled() || loading()"
2521
+ [attr.aria-haspopup]="'listbox'"
2522
+ [attr.aria-expanded]="isOpen()"
2523
+ [attr.aria-label]="ariaLabel() ?? null"
2524
+ (click)="toggleOpen(); $event.stopPropagation()"
2525
+ (keydown)="onTriggerKeydown($event)"
2526
+ >
2527
+ @if (leadingIcon()) {
2528
+ <span class="ui-select-search__leading" aria-hidden="true">
2529
+ <ng-content select="[slot=leading]" />
2530
+ </span>
2531
+ }
2532
+
2533
+ <span
2534
+ class="ui-select-search__value"
2535
+ [class.ui-select-search__value--placeholder]="!selectedOption()"
2536
+ >
2537
+ @if (loading()) {
2538
+ <span class="ui-select-search__spinner" aria-hidden="true">
2539
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2540
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
2541
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
2542
+ </svg>
2543
+ </span>
2544
+ } @else {
2545
+ {{ selectedOption()?.label ?? placeholder() ?? 'Sélectionner...' }}
2546
+ }
2547
+ </span>
2548
+
2549
+ <span
2550
+ class="ui-select-search__chevron"
2551
+ [class.ui-select-search__chevron--open]="isOpen()"
2552
+ aria-hidden="true"
2553
+ >
2554
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2555
+ stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
2556
+ <path d="M4 6l4 4 4-4"/>
2557
+ </svg>
2558
+ </span>
2559
+ </button>
2560
+
2561
+ <!-- ── Dropdown panel ───────────────────────────────── -->
2562
+ @if (isOpen()) {
2563
+ <div [@dropdown] class="ui-select-search__panel" (click)="$event.stopPropagation()">
2564
+
2565
+ <!-- Search input -->
2566
+ <div class="ui-select-search__search-wrap">
2567
+ <span class="ui-select-search__search-icon" aria-hidden="true">
2568
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2569
+ stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
2570
+ <circle cx="6.5" cy="6.5" r="4"/>
2571
+ <path d="M10 10l3 3"/>
2572
+ </svg>
2573
+ </span>
2574
+ <input
2575
+ #searchInput
2576
+ type="text"
2577
+ class="ui-select-search__input"
2578
+ [placeholder]="searchPlaceholder()"
2579
+ [ngModel]="query()"
2580
+ (ngModelChange)="query.set($event); activeIndex.set(0)"
2581
+ (keydown)="onSearchKeydown($event)"
2582
+ aria-label="Rechercher"
2583
+ autocomplete="off"
2584
+ spellcheck="false"
2585
+ />
2586
+ @if (query()) {
2587
+ <button
2588
+ type="button"
2589
+ class="ui-select-search__clear"
2590
+ (click)="clearQuery()"
2591
+ aria-label="Effacer la recherche"
2592
+ >
2593
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2594
+ stroke-width="2" stroke-linecap="round">
2595
+ <path d="M4 4l8 8M12 4l-8 8"/>
2596
+ </svg>
2597
+ </button>
2598
+ }
2599
+ </div>
2600
+
2601
+ <!-- Options list -->
2602
+ <div
2603
+ class="ui-select-search__options"
2604
+ role="listbox"
2605
+ [attr.aria-label]="ariaLabel() ?? 'Options'"
2606
+ >
2607
+ @for (opt of filteredOptions(); track opt.value; let i = $index) {
2608
+ <button
2609
+ type="button"
2610
+ class="ui-select-search__option"
2611
+ role="option"
2612
+ [class.ui-select-search__option--selected]="isSelected(opt)"
2613
+ [class.ui-select-search__option--highlighted]="activeIndex() === i"
2614
+ [class.ui-select-search__option--disabled]="opt.disabled"
2615
+ [attr.aria-selected]="isSelected(opt)"
2616
+ [disabled]="opt.disabled"
2617
+ (click)="selectOption(opt)"
2618
+ (mouseenter)="activeIndex.set(i)"
2619
+ >
2620
+ @if (opt.icon) {
2621
+ <span class="ui-select-search__option-icon" aria-hidden="true">{{ opt.icon }}</span>
2622
+ }
2623
+ <!-- Highlighted label -->
2624
+ <span
2625
+ class="ui-select-search__option-label"
2626
+ [innerHTML]="highlight(opt.label)"
2627
+ ></span>
2628
+
2629
+ @if (isSelected(opt)) {
2630
+ <span class="ui-select-search__option-check" aria-hidden="true">
2631
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2632
+ stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
2633
+ <path d="M3 8l3.5 3.5L13 5"/>
2634
+ </svg>
2635
+ </span>
2636
+ }
2637
+ </button>
2638
+ }
2639
+
2640
+ @if (filteredOptions().length === 0) {
2641
+ <div class="ui-select-search__empty">
2642
+ <svg viewBox="0 0 20 20" fill="none" stroke="currentColor"
2643
+ stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2644
+ <circle cx="10" cy="10" r="8"/>
2645
+ <path d="M10 6v5M10 14h.01"/>
2646
+ </svg>
2647
+ <span>{{ emptyLabel() }}</span>
2648
+ </div>
2649
+ }
2650
+ </div>
2651
+ </div>
2652
+ }
2653
+ </div>
2654
+ `, isInline: true, styles: [".ui-select-search{position:relative;display:inline-block;width:100%}.ui-select-search--disabled{opacity:.5;cursor:not-allowed}.ui-select-search__trigger{display:inline-flex;align-items:center;gap:.375rem;width:100%;border-radius:var(--radius-md);font-family:var(--font-sans);font-weight:var(--font-medium);cursor:pointer;outline:none;transition:background-color var(--transition-colors),border-color var(--transition-colors),box-shadow var(--transition-colors);text-align:left;white-space:nowrap;overflow:hidden}.ui-select-search__trigger--xs{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-select-search__trigger--sm{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-select-search__trigger--md{height:var(--size-md);padding:0 10px;font-size:var(--text-sm)}.ui-select-search__trigger--lg{height:var(--size-lg);padding:0 12px;font-size:var(--text-sm)}.ui-select-search__trigger--xl{height:var(--size-xl);padding:0 12px;font-size:var(--text-md)}.ui-select-search__trigger--outline.ui-select-search__trigger--neutral{background:var(--color-bg);border:1px solid var(--color-border);color:var(--color-text)}.ui-select-search__trigger--outline.ui-select-search__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-400)}.ui-select-search__trigger--outline.ui-select-search__trigger--neutral:focus-visible{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-select-search__trigger--soft.ui-select-search__trigger--neutral{background:var(--color-neutral-100);border:1px solid transparent;color:var(--color-text)}.ui-select-search__trigger--soft.ui-select-search__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-200)}.ui-select-search__trigger--soft.ui-select-search__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select-search__trigger--subtle.ui-select-search__trigger--neutral,.ui-select-search__trigger--ghost.ui-select-search__trigger--neutral{background:transparent;border:1px solid transparent;color:var(--color-text)}.ui-select-search__trigger--subtle.ui-select-search__trigger--neutral:hover:not(:disabled),.ui-select-search__trigger--ghost.ui-select-search__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-100)}.ui-select-search__trigger--subtle.ui-select-search__trigger--neutral:focus-visible,.ui-select-search__trigger--ghost.ui-select-search__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select-search__trigger--none.ui-select-search__trigger--neutral{background:transparent;border:none;color:var(--color-text)}.ui-select-search__trigger--outline.ui-select-search__trigger--primary{background:var(--color-bg);border:1px solid var(--color-primary-500);color:var(--color-primary-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--primary:hover:not(:disabled){background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-select-search__trigger--outline.ui-select-search__trigger--primary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--primary{background:color-mix(in srgb,var(--color-primary-500) 10%,transparent);border:1px solid transparent;color:var(--color-primary-600)}.ui-select-search__trigger--soft.ui-select-search__trigger--primary:hover:not(:disabled){background:color-mix(in srgb,var(--color-primary-500) 15%,transparent)}.ui-select-search__trigger--outline.ui-select-search__trigger--error{background:var(--color-bg);border:1px solid var(--color-error-500);color:var(--color-error-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--error:hover:not(:disabled){background:color-mix(in srgb,var(--color-error-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--error{background:color-mix(in srgb,var(--color-error-500) 10%,transparent);border:1px solid transparent;color:var(--color-error-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--warning{background:var(--color-bg);border:1px solid var(--color-warning-500);color:var(--color-warning-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--warning:hover:not(:disabled){background:color-mix(in srgb,var(--color-warning-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--warning{background:color-mix(in srgb,var(--color-warning-500) 10%,transparent);border:1px solid transparent;color:var(--color-warning-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--success{background:var(--color-bg);border:1px solid var(--color-success-500);color:var(--color-success-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--success:hover:not(:disabled){background:color-mix(in srgb,var(--color-success-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--success{background:color-mix(in srgb,var(--color-success-500) 10%,transparent);border:1px solid transparent;color:var(--color-success-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--info{background:var(--color-bg);border:1px solid var(--color-info-500);color:var(--color-info-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--info:hover:not(:disabled){background:color-mix(in srgb,var(--color-info-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--info{background:color-mix(in srgb,var(--color-info-500) 10%,transparent);border:1px solid transparent;color:var(--color-info-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--secondary{background:var(--color-bg);border:1px solid var(--color-secondary-500);color:var(--color-secondary-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--secondary:hover:not(:disabled){background:color-mix(in srgb,var(--color-secondary-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--secondary{background:color-mix(in srgb,var(--color-secondary-500) 10%,transparent);border:1px solid transparent;color:var(--color-secondary-700)}.ui-select-search--open .ui-select-search__trigger--outline{border-color:var(--color-primary-500)}.ui-select-search__trigger:disabled{cursor:not-allowed}.ui-select-search__leading{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem}.ui-select-search__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select-search__value--placeholder{color:var(--color-text-muted)}.ui-select-search__chevron{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem;transition:transform .15s ease}.ui-select-search__chevron svg{width:100%;height:100%}.ui-select-search__chevron--open{transform:rotate(180deg)}.ui-select-search__spinner{display:inline-flex;align-items:center}.ui-select-search__spinner svg{width:1em;height:1em;animation:ui-spin .75s linear infinite}@keyframes ui-spin{to{transform:rotate(360deg)}}.ui-select-search__panel{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:var(--z-dropdown, 50);min-width:100%;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;overflow:hidden;transform-origin:top center}.ui-select-search__search-wrap{display:flex;align-items:center;gap:.375rem;padding:6px 8px;border-bottom:1px solid var(--color-border);background:var(--color-bg-muted, var(--color-neutral-50))}.ui-select-search__search-icon{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:14px;height:14px}.ui-select-search__search-icon svg{width:100%;height:100%}.ui-select-search__input{flex:1;border:none;background:transparent;outline:none;font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text);min-width:0}.ui-select-search__input::placeholder{color:var(--color-text-muted)}.ui-select-search__clear{display:flex;align-items:center;flex-shrink:0;width:16px;height:16px;color:var(--color-text-muted);background:transparent;border:none;cursor:pointer;padding:0;border-radius:3px;transition:color .1s ease}.ui-select-search__clear svg{width:100%;height:100%}.ui-select-search__clear:hover{color:var(--color-text)}.ui-select-search__options{padding:4px;overflow-y:auto;max-height:200px}.ui-select-search__option{display:flex;align-items:center;gap:.5rem;width:100%;padding:6px 8px;border-radius:calc(var(--radius-md) - 2px);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-normal);color:var(--color-text);background:transparent;border:none;cursor:pointer;text-align:left;transition:background-color .1s ease}.ui-select-search__option:hover:not(:disabled),.ui-select-search__option--highlighted:not(:disabled){background:var(--color-neutral-100)}.ui-select-search__option--selected{color:var(--color-primary-600);font-weight:var(--font-medium);background:color-mix(in srgb,var(--color-primary-500) 8%,transparent)}.ui-select-search__option--selected:hover,.ui-select-search__option--selected.ui-select-search__option--highlighted{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}.ui-select-search__option--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-select-search__option-icon{flex-shrink:0;font-size:1rem;line-height:1}.ui-select-search__option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select-search__option-check{flex-shrink:0;width:1rem;height:1rem;color:var(--color-primary-500);display:flex;align-items:center}.ui-select-search__option-check svg{width:100%;height:100%}:host ::ng-deep .ui-select-search__highlight{background:color-mix(in srgb,var(--color-primary-500) 20%,transparent);color:var(--color-primary-700);border-radius:2px;padding:0 1px;font-weight:var(--font-medium);font-style:normal}.ui-select-search__empty{display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 16px;color:var(--color-text-muted);font-size:var(--text-sm);text-align:center}.ui-select-search__empty svg{width:20px;height:20px;opacity:.5}[data-theme=dark] .ui-select-search__trigger--outline.ui-select-search__trigger--neutral{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select-search__trigger--outline.ui-select-search__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-500)}[data-theme=dark] .ui-select-search__trigger--soft.ui-select-search__trigger--neutral{background:var(--color-neutral-800)}[data-theme=dark] .ui-select-search__panel{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select-search__search-wrap{background:var(--color-neutral-800);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select-search__option:hover:not(:disabled),[data-theme=dark] .ui-select-search__option--highlighted:not(:disabled){background:var(--color-neutral-800)}[data-theme=dark] .ui-select-search__option--selected{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], animations: [
2655
+ trigger('dropdown', [
2656
+ transition(':enter', [
2657
+ style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' }),
2658
+ animate('100ms ease-out', style({ opacity: 1, transform: 'scale(1) translateY(0)' })),
2659
+ ]),
2660
+ transition(':leave', [
2661
+ animate('80ms ease-in', style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' })),
2662
+ ]),
2663
+ ]),
2664
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2665
+ }
2666
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SelectSearchComponent, decorators: [{
2667
+ type: Component,
2668
+ args: [{ selector: 'ui-select-search', standalone: true, imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{
2669
+ provide: NG_VALUE_ACCESSOR,
2670
+ useExisting: forwardRef(() => SelectSearchComponent),
2671
+ multi: true,
2672
+ }], animations: [
2673
+ trigger('dropdown', [
2674
+ transition(':enter', [
2675
+ style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' }),
2676
+ animate('100ms ease-out', style({ opacity: 1, transform: 'scale(1) translateY(0)' })),
2677
+ ]),
2678
+ transition(':leave', [
2679
+ animate('80ms ease-in', style({ opacity: 0, transform: 'scale(0.96) translateY(-4px)' })),
2680
+ ]),
2681
+ ]),
2682
+ ], template: `
2683
+ <div
2684
+ class="ui-select-search"
2685
+ [class.ui-select-search--open]="isOpen()"
2686
+ [class.ui-select-search--disabled]="disabled()"
2687
+ >
2688
+ <!-- ── Trigger ──────────────────────────────────────── -->
2689
+ <button
2690
+ #triggerEl
2691
+ type="button"
2692
+ [class]="triggerClasses()"
2693
+ [disabled]="disabled() || loading()"
2694
+ [attr.aria-haspopup]="'listbox'"
2695
+ [attr.aria-expanded]="isOpen()"
2696
+ [attr.aria-label]="ariaLabel() ?? null"
2697
+ (click)="toggleOpen(); $event.stopPropagation()"
2698
+ (keydown)="onTriggerKeydown($event)"
2699
+ >
2700
+ @if (leadingIcon()) {
2701
+ <span class="ui-select-search__leading" aria-hidden="true">
2702
+ <ng-content select="[slot=leading]" />
2703
+ </span>
2704
+ }
2705
+
2706
+ <span
2707
+ class="ui-select-search__value"
2708
+ [class.ui-select-search__value--placeholder]="!selectedOption()"
2709
+ >
2710
+ @if (loading()) {
2711
+ <span class="ui-select-search__spinner" aria-hidden="true">
2712
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2713
+ <circle cx="12" cy="12" r="10" stroke-opacity="0.25"/>
2714
+ <path d="M12 2a10 10 0 0 1 10 10" stroke-linecap="round"/>
2715
+ </svg>
2716
+ </span>
2717
+ } @else {
2718
+ {{ selectedOption()?.label ?? placeholder() ?? 'Sélectionner...' }}
2719
+ }
2720
+ </span>
2721
+
2722
+ <span
2723
+ class="ui-select-search__chevron"
2724
+ [class.ui-select-search__chevron--open]="isOpen()"
2725
+ aria-hidden="true"
2726
+ >
2727
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2728
+ stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
2729
+ <path d="M4 6l4 4 4-4"/>
2730
+ </svg>
2731
+ </span>
2732
+ </button>
2733
+
2734
+ <!-- ── Dropdown panel ───────────────────────────────── -->
2735
+ @if (isOpen()) {
2736
+ <div [@dropdown] class="ui-select-search__panel" (click)="$event.stopPropagation()">
2737
+
2738
+ <!-- Search input -->
2739
+ <div class="ui-select-search__search-wrap">
2740
+ <span class="ui-select-search__search-icon" aria-hidden="true">
2741
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2742
+ stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
2743
+ <circle cx="6.5" cy="6.5" r="4"/>
2744
+ <path d="M10 10l3 3"/>
2745
+ </svg>
2746
+ </span>
2747
+ <input
2748
+ #searchInput
2749
+ type="text"
2750
+ class="ui-select-search__input"
2751
+ [placeholder]="searchPlaceholder()"
2752
+ [ngModel]="query()"
2753
+ (ngModelChange)="query.set($event); activeIndex.set(0)"
2754
+ (keydown)="onSearchKeydown($event)"
2755
+ aria-label="Rechercher"
2756
+ autocomplete="off"
2757
+ spellcheck="false"
2758
+ />
2759
+ @if (query()) {
2760
+ <button
2761
+ type="button"
2762
+ class="ui-select-search__clear"
2763
+ (click)="clearQuery()"
2764
+ aria-label="Effacer la recherche"
2765
+ >
2766
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2767
+ stroke-width="2" stroke-linecap="round">
2768
+ <path d="M4 4l8 8M12 4l-8 8"/>
2769
+ </svg>
2770
+ </button>
2771
+ }
2772
+ </div>
2773
+
2774
+ <!-- Options list -->
2775
+ <div
2776
+ class="ui-select-search__options"
2777
+ role="listbox"
2778
+ [attr.aria-label]="ariaLabel() ?? 'Options'"
2779
+ >
2780
+ @for (opt of filteredOptions(); track opt.value; let i = $index) {
2781
+ <button
2782
+ type="button"
2783
+ class="ui-select-search__option"
2784
+ role="option"
2785
+ [class.ui-select-search__option--selected]="isSelected(opt)"
2786
+ [class.ui-select-search__option--highlighted]="activeIndex() === i"
2787
+ [class.ui-select-search__option--disabled]="opt.disabled"
2788
+ [attr.aria-selected]="isSelected(opt)"
2789
+ [disabled]="opt.disabled"
2790
+ (click)="selectOption(opt)"
2791
+ (mouseenter)="activeIndex.set(i)"
2792
+ >
2793
+ @if (opt.icon) {
2794
+ <span class="ui-select-search__option-icon" aria-hidden="true">{{ opt.icon }}</span>
2795
+ }
2796
+ <!-- Highlighted label -->
2797
+ <span
2798
+ class="ui-select-search__option-label"
2799
+ [innerHTML]="highlight(opt.label)"
2800
+ ></span>
2801
+
2802
+ @if (isSelected(opt)) {
2803
+ <span class="ui-select-search__option-check" aria-hidden="true">
2804
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
2805
+ stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
2806
+ <path d="M3 8l3.5 3.5L13 5"/>
2807
+ </svg>
2808
+ </span>
2809
+ }
2810
+ </button>
2811
+ }
2812
+
2813
+ @if (filteredOptions().length === 0) {
2814
+ <div class="ui-select-search__empty">
2815
+ <svg viewBox="0 0 20 20" fill="none" stroke="currentColor"
2816
+ stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2817
+ <circle cx="10" cy="10" r="8"/>
2818
+ <path d="M10 6v5M10 14h.01"/>
2819
+ </svg>
2820
+ <span>{{ emptyLabel() }}</span>
2821
+ </div>
2822
+ }
2823
+ </div>
2824
+ </div>
2825
+ }
2826
+ </div>
2827
+ `, styles: [".ui-select-search{position:relative;display:inline-block;width:100%}.ui-select-search--disabled{opacity:.5;cursor:not-allowed}.ui-select-search__trigger{display:inline-flex;align-items:center;gap:.375rem;width:100%;border-radius:var(--radius-md);font-family:var(--font-sans);font-weight:var(--font-medium);cursor:pointer;outline:none;transition:background-color var(--transition-colors),border-color var(--transition-colors),box-shadow var(--transition-colors);text-align:left;white-space:nowrap;overflow:hidden}.ui-select-search__trigger--xs{height:var(--size-xs);padding:0 8px;font-size:var(--text-xs)}.ui-select-search__trigger--sm{height:var(--size-sm);padding:0 10px;font-size:var(--text-xs)}.ui-select-search__trigger--md{height:var(--size-md);padding:0 10px;font-size:var(--text-sm)}.ui-select-search__trigger--lg{height:var(--size-lg);padding:0 12px;font-size:var(--text-sm)}.ui-select-search__trigger--xl{height:var(--size-xl);padding:0 12px;font-size:var(--text-md)}.ui-select-search__trigger--outline.ui-select-search__trigger--neutral{background:var(--color-bg);border:1px solid var(--color-border);color:var(--color-text)}.ui-select-search__trigger--outline.ui-select-search__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-400)}.ui-select-search__trigger--outline.ui-select-search__trigger--neutral:focus-visible{border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-select-search__trigger--soft.ui-select-search__trigger--neutral{background:var(--color-neutral-100);border:1px solid transparent;color:var(--color-text)}.ui-select-search__trigger--soft.ui-select-search__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-200)}.ui-select-search__trigger--soft.ui-select-search__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select-search__trigger--subtle.ui-select-search__trigger--neutral,.ui-select-search__trigger--ghost.ui-select-search__trigger--neutral{background:transparent;border:1px solid transparent;color:var(--color-text)}.ui-select-search__trigger--subtle.ui-select-search__trigger--neutral:hover:not(:disabled),.ui-select-search__trigger--ghost.ui-select-search__trigger--neutral:hover:not(:disabled){background:var(--color-neutral-100)}.ui-select-search__trigger--subtle.ui-select-search__trigger--neutral:focus-visible,.ui-select-search__trigger--ghost.ui-select-search__trigger--neutral:focus-visible{box-shadow:0 0 0 2px var(--color-primary-500)}.ui-select-search__trigger--none.ui-select-search__trigger--neutral{background:transparent;border:none;color:var(--color-text)}.ui-select-search__trigger--outline.ui-select-search__trigger--primary{background:var(--color-bg);border:1px solid var(--color-primary-500);color:var(--color-primary-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--primary:hover:not(:disabled){background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-select-search__trigger--outline.ui-select-search__trigger--primary:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--primary{background:color-mix(in srgb,var(--color-primary-500) 10%,transparent);border:1px solid transparent;color:var(--color-primary-600)}.ui-select-search__trigger--soft.ui-select-search__trigger--primary:hover:not(:disabled){background:color-mix(in srgb,var(--color-primary-500) 15%,transparent)}.ui-select-search__trigger--outline.ui-select-search__trigger--error{background:var(--color-bg);border:1px solid var(--color-error-500);color:var(--color-error-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--error:hover:not(:disabled){background:color-mix(in srgb,var(--color-error-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--error{background:color-mix(in srgb,var(--color-error-500) 10%,transparent);border:1px solid transparent;color:var(--color-error-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--warning{background:var(--color-bg);border:1px solid var(--color-warning-500);color:var(--color-warning-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--warning:hover:not(:disabled){background:color-mix(in srgb,var(--color-warning-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--warning{background:color-mix(in srgb,var(--color-warning-500) 10%,transparent);border:1px solid transparent;color:var(--color-warning-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--success{background:var(--color-bg);border:1px solid var(--color-success-500);color:var(--color-success-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--success:hover:not(:disabled){background:color-mix(in srgb,var(--color-success-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--success{background:color-mix(in srgb,var(--color-success-500) 10%,transparent);border:1px solid transparent;color:var(--color-success-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--info{background:var(--color-bg);border:1px solid var(--color-info-500);color:var(--color-info-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--info:hover:not(:disabled){background:color-mix(in srgb,var(--color-info-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--info{background:color-mix(in srgb,var(--color-info-500) 10%,transparent);border:1px solid transparent;color:var(--color-info-700)}.ui-select-search__trigger--outline.ui-select-search__trigger--secondary{background:var(--color-bg);border:1px solid var(--color-secondary-500);color:var(--color-secondary-600)}.ui-select-search__trigger--outline.ui-select-search__trigger--secondary:hover:not(:disabled){background:color-mix(in srgb,var(--color-secondary-500) 5%,transparent)}.ui-select-search__trigger--soft.ui-select-search__trigger--secondary{background:color-mix(in srgb,var(--color-secondary-500) 10%,transparent);border:1px solid transparent;color:var(--color-secondary-700)}.ui-select-search--open .ui-select-search__trigger--outline{border-color:var(--color-primary-500)}.ui-select-search__trigger:disabled{cursor:not-allowed}.ui-select-search__leading{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem}.ui-select-search__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select-search__value--placeholder{color:var(--color-text-muted)}.ui-select-search__chevron{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:1rem;height:1rem;transition:transform .15s ease}.ui-select-search__chevron svg{width:100%;height:100%}.ui-select-search__chevron--open{transform:rotate(180deg)}.ui-select-search__spinner{display:inline-flex;align-items:center}.ui-select-search__spinner svg{width:1em;height:1em;animation:ui-spin .75s linear infinite}@keyframes ui-spin{to{transform:rotate(360deg)}}.ui-select-search__panel{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:var(--z-dropdown, 50);min-width:100%;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;overflow:hidden;transform-origin:top center}.ui-select-search__search-wrap{display:flex;align-items:center;gap:.375rem;padding:6px 8px;border-bottom:1px solid var(--color-border);background:var(--color-bg-muted, var(--color-neutral-50))}.ui-select-search__search-icon{display:flex;align-items:center;flex-shrink:0;color:var(--color-text-muted);width:14px;height:14px}.ui-select-search__search-icon svg{width:100%;height:100%}.ui-select-search__input{flex:1;border:none;background:transparent;outline:none;font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text);min-width:0}.ui-select-search__input::placeholder{color:var(--color-text-muted)}.ui-select-search__clear{display:flex;align-items:center;flex-shrink:0;width:16px;height:16px;color:var(--color-text-muted);background:transparent;border:none;cursor:pointer;padding:0;border-radius:3px;transition:color .1s ease}.ui-select-search__clear svg{width:100%;height:100%}.ui-select-search__clear:hover{color:var(--color-text)}.ui-select-search__options{padding:4px;overflow-y:auto;max-height:200px}.ui-select-search__option{display:flex;align-items:center;gap:.5rem;width:100%;padding:6px 8px;border-radius:calc(var(--radius-md) - 2px);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-normal);color:var(--color-text);background:transparent;border:none;cursor:pointer;text-align:left;transition:background-color .1s ease}.ui-select-search__option:hover:not(:disabled),.ui-select-search__option--highlighted:not(:disabled){background:var(--color-neutral-100)}.ui-select-search__option--selected{color:var(--color-primary-600);font-weight:var(--font-medium);background:color-mix(in srgb,var(--color-primary-500) 8%,transparent)}.ui-select-search__option--selected:hover,.ui-select-search__option--selected.ui-select-search__option--highlighted{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}.ui-select-search__option--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-select-search__option-icon{flex-shrink:0;font-size:1rem;line-height:1}.ui-select-search__option-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select-search__option-check{flex-shrink:0;width:1rem;height:1rem;color:var(--color-primary-500);display:flex;align-items:center}.ui-select-search__option-check svg{width:100%;height:100%}:host ::ng-deep .ui-select-search__highlight{background:color-mix(in srgb,var(--color-primary-500) 20%,transparent);color:var(--color-primary-700);border-radius:2px;padding:0 1px;font-weight:var(--font-medium);font-style:normal}.ui-select-search__empty{display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 16px;color:var(--color-text-muted);font-size:var(--text-sm);text-align:center}.ui-select-search__empty svg{width:20px;height:20px;opacity:.5}[data-theme=dark] .ui-select-search__trigger--outline.ui-select-search__trigger--neutral{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select-search__trigger--outline.ui-select-search__trigger--neutral:hover:not(:disabled){border-color:var(--color-neutral-500)}[data-theme=dark] .ui-select-search__trigger--soft.ui-select-search__trigger--neutral{background:var(--color-neutral-800)}[data-theme=dark] .ui-select-search__panel{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select-search__search-wrap{background:var(--color-neutral-800);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-select-search__option:hover:not(:disabled),[data-theme=dark] .ui-select-search__option--highlighted:not(:disabled){background:var(--color-neutral-800)}[data-theme=dark] .ui-select-search__option--selected{background:color-mix(in srgb,var(--color-primary-500) 12%,transparent)}\n"] }]
2828
+ }], propDecorators: { triggerEl: [{
2829
+ type: ViewChild,
2830
+ args: ['triggerEl']
2831
+ }], searchInput: [{
2832
+ type: ViewChild,
2833
+ args: ['searchInput']
2834
+ }], onDocumentClick: [{
2835
+ type: HostListener,
2836
+ args: ['document:click', ['$event']]
2837
+ }] } });
2838
+
2839
+ // ============================================================
2840
+ // MOLECULES — Nuxt UI v3 Design Kit → Angular 19 + NX
2841
+ // Combinations of atoms with focused single responsibility
2842
+ // ============================================================
2843
+
2844
+ /**
2845
+ * Accordion Organism — Source: Nuxt UI v3 ❖ Accordion
2846
+ * Collapsible content sections with animation
2847
+ * Single or multiple open panels supported
2848
+ */
2849
+ class AccordionComponent {
2850
+ constructor() {
2851
+ this.items = input.required();
2852
+ this.variant = input('default');
2853
+ this.multiple = input(true);
2854
+ this.openIds = model([]);
2855
+ }
2856
+ isOpen(id) { return this.openIds().includes(id); }
2857
+ toggle(id) {
2858
+ this.openIds.update(ids => {
2859
+ if (ids.includes(id)) {
2860
+ return ids.filter(i => i !== id);
2861
+ }
2862
+ return this.multiple() ? [...ids, id] : [id];
2863
+ });
2864
+ }
2865
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2866
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: AccordionComponent, isStandalone: true, selector: "ui-accordion", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, openIds: { classPropertyName: "openIds", publicName: "openIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openIds: "openIdsChange" }, ngImport: i0, template: `
2867
+ <div class="ui-accordion ui-accordion--{{ variant() }}" role="list">
2868
+ @for (item of items(); track item.id) {
2869
+ <div
2870
+ class="ui-accordion__item"
2871
+ [class.ui-accordion__item--open]="isOpen(item.id)"
2872
+ [class.ui-accordion__item--disabled]="item.disabled"
2873
+ role="listitem"
2874
+ >
2875
+ <button
2876
+ type="button"
2877
+ class="ui-accordion__trigger"
2878
+ [attr.aria-expanded]="isOpen(item.id)"
2879
+ [attr.aria-controls]="'panel-' + item.id"
2880
+ [disabled]="item.disabled"
2881
+ (click)="toggle(item.id)"
2882
+ >
2883
+ <span class="ui-accordion__label">{{ item.label }}</span>
2884
+ <span class="ui-accordion__icon" [class.ui-accordion__icon--open]="isOpen(item.id)" aria-hidden="true">
2885
+
2886
+ </span>
2887
+ </button>
2888
+
2889
+ @if (isOpen(item.id)) {
2890
+ <div
2891
+ [@expand]
2892
+ class="ui-accordion__panel"
2893
+ [id]="'panel-' + item.id"
2894
+ role="region"
2895
+ [attr.aria-labelledby]="'trigger-' + item.id"
2896
+ >
2897
+ <div class="ui-accordion__content">{{ item.content }}</div>
2898
+ </div>
2899
+ }
2900
+ </div>
2901
+ }
2902
+ </div>
2903
+ `, isInline: true, styles: [".ui-accordion{width:100%}.ui-accordion__item{border-bottom:1px solid var(--color-border)}.ui-accordion__item:first-child{border-top:1px solid var(--color-border)}.ui-accordion__item--disabled{opacity:.5;pointer-events:none}.ui-accordion__trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--spacing-4) 0;border:none;background:transparent;cursor:pointer;font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);text-align:left;transition:color var(--transition-fast)}.ui-accordion__trigger:hover{color:var(--color-primary-500)}.ui-accordion__trigger:focus-visible{outline:2px solid var(--color-ring);outline-offset:2px;border-radius:var(--radius-sm)}.ui-accordion__icon{flex-shrink:0;font-size:.75rem;transition:transform var(--transition-base);color:var(--color-text-muted)}.ui-accordion__icon--open{transform:rotate(180deg)}.ui-accordion__panel{overflow:hidden}.ui-accordion__content{padding:0 0 var(--spacing-4);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);line-height:var(--leading-relaxed)}.ui-accordion--ghost .ui-accordion__item{border-bottom:none;border-radius:var(--radius-lg);margin-bottom:var(--spacing-1);background:var(--color-neutral-50)}.ui-accordion--ghost .ui-accordion__item:first-child{border-top:none}.ui-accordion--ghost .ui-accordion__item .ui-accordion__trigger{padding:var(--spacing-3) var(--spacing-4)}.ui-accordion--ghost .ui-accordion__item .ui-accordion__content{padding:0 var(--spacing-4) var(--spacing-3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
2904
+ trigger('expand', [
2905
+ state('void', style({ height: '0', opacity: 0, overflow: 'hidden' })),
2906
+ state('*', style({ height: '*', opacity: 1, overflow: 'hidden' })),
2907
+ transition('void <=> *', animate('200ms ease')),
2908
+ ])
2909
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2910
+ }
2911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccordionComponent, decorators: [{
2912
+ type: Component,
2913
+ args: [{ selector: 'ui-accordion', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
2914
+ trigger('expand', [
2915
+ state('void', style({ height: '0', opacity: 0, overflow: 'hidden' })),
2916
+ state('*', style({ height: '*', opacity: 1, overflow: 'hidden' })),
2917
+ transition('void <=> *', animate('200ms ease')),
2918
+ ])
2919
+ ], template: `
2920
+ <div class="ui-accordion ui-accordion--{{ variant() }}" role="list">
2921
+ @for (item of items(); track item.id) {
2922
+ <div
2923
+ class="ui-accordion__item"
2924
+ [class.ui-accordion__item--open]="isOpen(item.id)"
2925
+ [class.ui-accordion__item--disabled]="item.disabled"
2926
+ role="listitem"
2927
+ >
2928
+ <button
2929
+ type="button"
2930
+ class="ui-accordion__trigger"
2931
+ [attr.aria-expanded]="isOpen(item.id)"
2932
+ [attr.aria-controls]="'panel-' + item.id"
2933
+ [disabled]="item.disabled"
2934
+ (click)="toggle(item.id)"
2935
+ >
2936
+ <span class="ui-accordion__label">{{ item.label }}</span>
2937
+ <span class="ui-accordion__icon" [class.ui-accordion__icon--open]="isOpen(item.id)" aria-hidden="true">
2938
+
2939
+ </span>
2940
+ </button>
2941
+
2942
+ @if (isOpen(item.id)) {
2943
+ <div
2944
+ [@expand]
2945
+ class="ui-accordion__panel"
2946
+ [id]="'panel-' + item.id"
2947
+ role="region"
2948
+ [attr.aria-labelledby]="'trigger-' + item.id"
2949
+ >
2950
+ <div class="ui-accordion__content">{{ item.content }}</div>
2951
+ </div>
2952
+ }
2953
+ </div>
2954
+ }
2955
+ </div>
2956
+ `, styles: [".ui-accordion{width:100%}.ui-accordion__item{border-bottom:1px solid var(--color-border)}.ui-accordion__item:first-child{border-top:1px solid var(--color-border)}.ui-accordion__item--disabled{opacity:.5;pointer-events:none}.ui-accordion__trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--spacing-4) 0;border:none;background:transparent;cursor:pointer;font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);text-align:left;transition:color var(--transition-fast)}.ui-accordion__trigger:hover{color:var(--color-primary-500)}.ui-accordion__trigger:focus-visible{outline:2px solid var(--color-ring);outline-offset:2px;border-radius:var(--radius-sm)}.ui-accordion__icon{flex-shrink:0;font-size:.75rem;transition:transform var(--transition-base);color:var(--color-text-muted)}.ui-accordion__icon--open{transform:rotate(180deg)}.ui-accordion__panel{overflow:hidden}.ui-accordion__content{padding:0 0 var(--spacing-4);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);line-height:var(--leading-relaxed)}.ui-accordion--ghost .ui-accordion__item{border-bottom:none;border-radius:var(--radius-lg);margin-bottom:var(--spacing-1);background:var(--color-neutral-50)}.ui-accordion--ghost .ui-accordion__item:first-child{border-top:none}.ui-accordion--ghost .ui-accordion__item .ui-accordion__trigger{padding:var(--spacing-3) var(--spacing-4)}.ui-accordion--ghost .ui-accordion__item .ui-accordion__content{padding:0 var(--spacing-4) var(--spacing-3)}\n"] }]
2957
+ }] });
2958
+
2959
+ /**
2960
+ * Card Organism — Source: Nuxt UI v3 ❖ Card
2961
+ * Content container with header, body, footer slots
2962
+ */
2963
+ class CardComponent {
2964
+ constructor() {
2965
+ this.title = input(null);
2966
+ this.description = input(null);
2967
+ this.variant = input('outline');
2968
+ }
2969
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2970
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: CardComponent, isStandalone: true, selector: "ui-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
2971
+ <div [class]="'ui-card ui-card--' + variant()">
2972
+ @if (title() || description()) {
2973
+ <div class="ui-card__header">
2974
+ @if (title()) {
2975
+ <h3 class="ui-card__title">{{ title() }}</h3>
2976
+ }
2977
+ @if (description()) {
2978
+ <p class="ui-card__description">{{ description() }}</p>
2979
+ }
2980
+ <ng-content select="[slot=header]" />
2981
+ </div>
2982
+ }
2983
+ <div class="ui-card__body">
2984
+ <ng-content />
2985
+ </div>
2986
+ <ng-content select="[slot=footer]" />
2987
+ </div>
2988
+ `, isInline: true, styles: [".ui-card{border-radius:var(--radius-xl);overflow:hidden}.ui-card--outline{border:1px solid var(--color-border);background:var(--color-bg);box-shadow:var(--shadow-xs)}.ui-card--soft{background:var(--color-neutral-50);border:1px solid transparent}.ui-card--subtle{background:var(--color-bg-muted)}.ui-card--ghost{background:transparent}.ui-card--none{background:transparent;border:none}.ui-card__header{padding:var(--spacing-4);border-bottom:1px solid var(--color-border)}.ui-card__title{font-family:var(--font-sans);font-size:var(--text-lg);font-weight:var(--font-semibold);color:var(--color-text);margin:0 0 var(--spacing-1)}.ui-card__description{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);margin:0}.ui-card__body{padding:var(--spacing-4)}.ui-card__footer{padding:var(--spacing-4);border-top:1px solid var(--color-border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2989
+ }
2990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CardComponent, decorators: [{
2991
+ type: Component,
2992
+ args: [{ selector: 'ui-card', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2993
+ <div [class]="'ui-card ui-card--' + variant()">
2994
+ @if (title() || description()) {
2995
+ <div class="ui-card__header">
2996
+ @if (title()) {
2997
+ <h3 class="ui-card__title">{{ title() }}</h3>
2998
+ }
2999
+ @if (description()) {
3000
+ <p class="ui-card__description">{{ description() }}</p>
3001
+ }
3002
+ <ng-content select="[slot=header]" />
3003
+ </div>
3004
+ }
3005
+ <div class="ui-card__body">
3006
+ <ng-content />
3007
+ </div>
3008
+ <ng-content select="[slot=footer]" />
3009
+ </div>
3010
+ `, styles: [".ui-card{border-radius:var(--radius-xl);overflow:hidden}.ui-card--outline{border:1px solid var(--color-border);background:var(--color-bg);box-shadow:var(--shadow-xs)}.ui-card--soft{background:var(--color-neutral-50);border:1px solid transparent}.ui-card--subtle{background:var(--color-bg-muted)}.ui-card--ghost{background:transparent}.ui-card--none{background:transparent;border:none}.ui-card__header{padding:var(--spacing-4);border-bottom:1px solid var(--color-border)}.ui-card__title{font-family:var(--font-sans);font-size:var(--text-lg);font-weight:var(--font-semibold);color:var(--color-text);margin:0 0 var(--spacing-1)}.ui-card__description{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);margin:0}.ui-card__body{padding:var(--spacing-4)}.ui-card__footer{padding:var(--spacing-4);border-top:1px solid var(--color-border)}\n"] }]
3011
+ }] });
3012
+
3013
+ /**
3014
+ * DropdownMenu Organism — Source: Nuxt UI v3 ❖ DropdownMenu
3015
+ * Contextual action menu triggered by a slot
3016
+ */
3017
+ class DropdownMenuComponent {
3018
+ constructor(el) {
3019
+ this.el = el;
3020
+ this.items = input.required();
3021
+ this.align = input('left');
3022
+ this.open = model(false);
3023
+ this.itemClick = output();
3024
+ }
3025
+ toggle() { this.open.update(v => !v); }
3026
+ select(item) {
3027
+ if (item.disabled)
3028
+ return;
3029
+ this.itemClick.emit(item);
3030
+ this.open.set(false);
3031
+ }
3032
+ onDocumentClick(e) {
3033
+ if (!this.el.nativeElement.contains(e.target)) {
3034
+ this.open.set(false);
3035
+ }
3036
+ }
3037
+ onEscape() { this.open.set(false); }
3038
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DropdownMenuComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
3039
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: DropdownMenuComponent, isStandalone: true, selector: "ui-dropdown-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" } }, ngImport: i0, template: `
3040
+ <div class="ui-dropdown" [class.ui-dropdown--open]="open()">
3041
+ <div class="ui-dropdown__trigger" (click)="toggle()">
3042
+ <ng-content />
3043
+ </div>
3044
+
3045
+ @if (open()) {
3046
+ <div
3047
+ [@menu]
3048
+ class="ui-dropdown__menu ui-dropdown__menu--{{ align() }}"
3049
+ role="menu"
3050
+ aria-orientation="vertical"
3051
+ >
3052
+ @for (item of items(); track item.id) {
3053
+ @if (item.separator) {
3054
+ <hr class="ui-dropdown__separator" role="separator" />
3055
+ } @else {
3056
+ <button
3057
+ type="button"
3058
+ role="menuitem"
3059
+ [class]="'ui-dropdown__item' + (item.disabled ? ' ui-dropdown__item--disabled' : '') + (item.color === 'error' ? ' ui-dropdown__item--error' : '')"
3060
+ [disabled]="item.disabled"
3061
+ (click)="select(item)"
3062
+ >
3063
+ @if (item.icon) {
3064
+ <span class="ui-dropdown__icon" aria-hidden="true">{{ item.icon }}</span>
3065
+ }
3066
+ {{ item.label }}
3067
+ </button>
3068
+ }
3069
+ }
3070
+ </div>
3071
+ }
3072
+ </div>
3073
+ `, isInline: true, styles: [".ui-dropdown{position:relative;display:inline-flex}.ui-dropdown__trigger{cursor:pointer}.ui-dropdown__menu{position:absolute;top:calc(100% + 4px);z-index:var(--z-dropdown);min-width:160px;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-xl);box-shadow:var(--shadow-lg);padding:var(--spacing-1);outline:none}.ui-dropdown__menu--left{left:0}.ui-dropdown__menu--right{right:0}.ui-dropdown__item{display:flex;align-items:center;gap:var(--spacing-2);width:100%;padding:var(--spacing-2) var(--spacing-3);border:none;background:transparent;border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);cursor:pointer;text-align:left;transition:var(--transition-colors)}.ui-dropdown__item:hover:not(.ui-dropdown__item--disabled){background:var(--color-neutral-100)}.ui-dropdown__item--error{color:var(--color-error-600)}.ui-dropdown__item--error:hover{background:color-mix(in srgb,var(--color-error-500) 10%,transparent)}.ui-dropdown__item--disabled{opacity:.4;cursor:not-allowed}.ui-dropdown__icon{flex-shrink:0;width:1rem;height:1rem;display:flex;align-items:center;justify-content:center}.ui-dropdown__separator{margin:var(--spacing-1) 0;border:none;border-top:1px solid var(--color-border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
3074
+ trigger('menu', [
3075
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }), animate('150ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
3076
+ transition(':leave', [animate('100ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }))]),
3077
+ ])
3078
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3079
+ }
3080
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DropdownMenuComponent, decorators: [{
3081
+ type: Component,
3082
+ args: [{ selector: 'ui-dropdown-menu', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
3083
+ trigger('menu', [
3084
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }), animate('150ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
3085
+ transition(':leave', [animate('100ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }))]),
3086
+ ])
3087
+ ], template: `
3088
+ <div class="ui-dropdown" [class.ui-dropdown--open]="open()">
3089
+ <div class="ui-dropdown__trigger" (click)="toggle()">
3090
+ <ng-content />
3091
+ </div>
3092
+
3093
+ @if (open()) {
3094
+ <div
3095
+ [@menu]
3096
+ class="ui-dropdown__menu ui-dropdown__menu--{{ align() }}"
3097
+ role="menu"
3098
+ aria-orientation="vertical"
3099
+ >
3100
+ @for (item of items(); track item.id) {
3101
+ @if (item.separator) {
3102
+ <hr class="ui-dropdown__separator" role="separator" />
3103
+ } @else {
3104
+ <button
3105
+ type="button"
3106
+ role="menuitem"
3107
+ [class]="'ui-dropdown__item' + (item.disabled ? ' ui-dropdown__item--disabled' : '') + (item.color === 'error' ? ' ui-dropdown__item--error' : '')"
3108
+ [disabled]="item.disabled"
3109
+ (click)="select(item)"
3110
+ >
3111
+ @if (item.icon) {
3112
+ <span class="ui-dropdown__icon" aria-hidden="true">{{ item.icon }}</span>
3113
+ }
3114
+ {{ item.label }}
3115
+ </button>
3116
+ }
3117
+ }
3118
+ </div>
3119
+ }
3120
+ </div>
3121
+ `, styles: [".ui-dropdown{position:relative;display:inline-flex}.ui-dropdown__trigger{cursor:pointer}.ui-dropdown__menu{position:absolute;top:calc(100% + 4px);z-index:var(--z-dropdown);min-width:160px;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-xl);box-shadow:var(--shadow-lg);padding:var(--spacing-1);outline:none}.ui-dropdown__menu--left{left:0}.ui-dropdown__menu--right{right:0}.ui-dropdown__item{display:flex;align-items:center;gap:var(--spacing-2);width:100%;padding:var(--spacing-2) var(--spacing-3);border:none;background:transparent;border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);cursor:pointer;text-align:left;transition:var(--transition-colors)}.ui-dropdown__item:hover:not(.ui-dropdown__item--disabled){background:var(--color-neutral-100)}.ui-dropdown__item--error{color:var(--color-error-600)}.ui-dropdown__item--error:hover{background:color-mix(in srgb,var(--color-error-500) 10%,transparent)}.ui-dropdown__item--disabled{opacity:.4;cursor:not-allowed}.ui-dropdown__icon{flex-shrink:0;width:1rem;height:1rem;display:flex;align-items:center;justify-content:center}.ui-dropdown__separator{margin:var(--spacing-1) 0;border:none;border-top:1px solid var(--color-border)}\n"] }]
3122
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { onDocumentClick: [{
3123
+ type: HostListener,
3124
+ args: ['document:click', ['$event']]
3125
+ }], onEscape: [{
3126
+ type: HostListener,
3127
+ args: ['keydown.escape']
3128
+ }] } });
3129
+
3130
+ /**
3131
+ * Modal Organism — Source: Nuxt UI v3 ❖ Modal
3132
+ * Dialog overlay with backdrop, header, body, footer
3133
+ */
3134
+ class ModalComponent {
3135
+ constructor() {
3136
+ this.open = model(false);
3137
+ this.title = input(null);
3138
+ this.size = input('md');
3139
+ this.hideHeader = input(false);
3140
+ this.hideClose = input(false);
3141
+ this.dismissible = input(true);
3142
+ this.close = output();
3143
+ }
3144
+ onOverlayClick() {
3145
+ if (this.dismissible()) {
3146
+ this.open.set(false);
3147
+ this.close.emit();
3148
+ }
3149
+ }
3150
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3151
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ModalComponent, isStandalone: true, selector: "ui-modal", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, hideHeader: { classPropertyName: "hideHeader", publicName: "hideHeader", isSignal: true, isRequired: false, transformFunction: null }, hideClose: { classPropertyName: "hideClose", publicName: "hideClose", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", close: "close" }, ngImport: i0, template: `
3152
+ @if (open()) {
3153
+ <div class="ui-modal-overlay" [@overlay] (click)="onOverlayClick()" role="presentation">
3154
+ <div
3155
+ [@dialog]
3156
+ class="ui-modal ui-modal--{{ size() }}"
3157
+ role="dialog"
3158
+ [attr.aria-modal]="true"
3159
+ [attr.aria-label]="title() ?? 'Dialog'"
3160
+ (click)="$event.stopPropagation()"
3161
+ >
3162
+ @if (title() || !hideHeader()) {
3163
+ <div class="ui-modal__header">
3164
+ <h2 class="ui-modal__title">{{ title() }}</h2>
3165
+ @if (!hideClose()) {
3166
+ <button type="button" class="ui-modal__close" aria-label="Close" (click)="close.emit()">×</button>
3167
+ }
3168
+ </div>
3169
+ }
3170
+ <div class="ui-modal__body">
3171
+ <ng-content />
3172
+ </div>
3173
+ <ng-content select="[slot=footer]" />
3174
+ </div>
3175
+ </div>
3176
+ }
3177
+ `, isInline: true, styles: [".ui-modal-overlay{position:fixed;inset:0;z-index:var(--z-modal);display:flex;align-items:center;justify-content:center;background:#00000080;padding:var(--spacing-4);backdrop-filter:blur(2px)}.ui-modal{position:relative;background:var(--color-bg);border-radius:var(--radius-2xl);box-shadow:var(--shadow-xl);display:flex;flex-direction:column;max-height:90vh;width:100%;overflow:hidden}.ui-modal--xs{max-width:320px}.ui-modal--sm{max-width:384px}.ui-modal--md{max-width:512px}.ui-modal--lg{max-width:640px}.ui-modal--xl{max-width:768px}.ui-modal--2xl{max-width:896px}.ui-modal--3xl{max-width:1024px}.ui-modal--4xl{max-width:1280px}.ui-modal--full{max-width:calc(100vw - 2rem);max-height:calc(100vh - 2rem)}.ui-modal__header{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-6) var(--spacing-6) var(--spacing-4);border-bottom:1px solid var(--color-border);flex-shrink:0}.ui-modal__title{font-family:var(--font-sans);font-size:var(--text-xl);font-weight:var(--font-semibold);color:var(--color-text);margin:0}.ui-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;cursor:pointer;font-size:1.5rem;color:var(--color-text-muted);border-radius:var(--radius-md);transition:var(--transition-colors)}.ui-modal__close:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-modal__body{flex:1;overflow-y:auto;padding:var(--spacing-6);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted)}.ui-modal__footer{flex-shrink:0;padding:var(--spacing-4) var(--spacing-6);border-top:1px solid var(--color-border);display:flex;justify-content:flex-end;gap:var(--spacing-3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
3178
+ trigger('overlay', [
3179
+ transition(':enter', [style({ opacity: 0 }), animate('150ms ease', style({ opacity: 1 }))]),
3180
+ transition(':leave', [animate('150ms ease', style({ opacity: 0 }))]),
3181
+ ]),
3182
+ trigger('dialog', [
3183
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }), animate('200ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
3184
+ transition(':leave', [animate('150ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }))]),
3185
+ ]),
3186
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3187
+ }
3188
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ModalComponent, decorators: [{
3189
+ type: Component,
3190
+ args: [{ selector: 'ui-modal', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
3191
+ trigger('overlay', [
3192
+ transition(':enter', [style({ opacity: 0 }), animate('150ms ease', style({ opacity: 1 }))]),
3193
+ transition(':leave', [animate('150ms ease', style({ opacity: 0 }))]),
3194
+ ]),
3195
+ trigger('dialog', [
3196
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }), animate('200ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
3197
+ transition(':leave', [animate('150ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }))]),
3198
+ ]),
3199
+ ], template: `
3200
+ @if (open()) {
3201
+ <div class="ui-modal-overlay" [@overlay] (click)="onOverlayClick()" role="presentation">
3202
+ <div
3203
+ [@dialog]
3204
+ class="ui-modal ui-modal--{{ size() }}"
3205
+ role="dialog"
3206
+ [attr.aria-modal]="true"
3207
+ [attr.aria-label]="title() ?? 'Dialog'"
3208
+ (click)="$event.stopPropagation()"
3209
+ >
3210
+ @if (title() || !hideHeader()) {
3211
+ <div class="ui-modal__header">
3212
+ <h2 class="ui-modal__title">{{ title() }}</h2>
3213
+ @if (!hideClose()) {
3214
+ <button type="button" class="ui-modal__close" aria-label="Close" (click)="close.emit()">×</button>
3215
+ }
3216
+ </div>
3217
+ }
3218
+ <div class="ui-modal__body">
3219
+ <ng-content />
3220
+ </div>
3221
+ <ng-content select="[slot=footer]" />
3222
+ </div>
3223
+ </div>
3224
+ }
3225
+ `, styles: [".ui-modal-overlay{position:fixed;inset:0;z-index:var(--z-modal);display:flex;align-items:center;justify-content:center;background:#00000080;padding:var(--spacing-4);backdrop-filter:blur(2px)}.ui-modal{position:relative;background:var(--color-bg);border-radius:var(--radius-2xl);box-shadow:var(--shadow-xl);display:flex;flex-direction:column;max-height:90vh;width:100%;overflow:hidden}.ui-modal--xs{max-width:320px}.ui-modal--sm{max-width:384px}.ui-modal--md{max-width:512px}.ui-modal--lg{max-width:640px}.ui-modal--xl{max-width:768px}.ui-modal--2xl{max-width:896px}.ui-modal--3xl{max-width:1024px}.ui-modal--4xl{max-width:1280px}.ui-modal--full{max-width:calc(100vw - 2rem);max-height:calc(100vh - 2rem)}.ui-modal__header{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-6) var(--spacing-6) var(--spacing-4);border-bottom:1px solid var(--color-border);flex-shrink:0}.ui-modal__title{font-family:var(--font-sans);font-size:var(--text-xl);font-weight:var(--font-semibold);color:var(--color-text);margin:0}.ui-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;cursor:pointer;font-size:1.5rem;color:var(--color-text-muted);border-radius:var(--radius-md);transition:var(--transition-colors)}.ui-modal__close:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-modal__body{flex:1;overflow-y:auto;padding:var(--spacing-6);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted)}.ui-modal__footer{flex-shrink:0;padding:var(--spacing-4) var(--spacing-6);border-top:1px solid var(--color-border);display:flex;justify-content:flex-end;gap:var(--spacing-3)}\n"] }]
3226
+ }] });
3227
+
3228
+ /**
3229
+ * NavigationMenu Organism — Source: Nuxt UI v3 ❖ NavigationMenu
3230
+ * Primary site navigation with active link detection
3231
+ */
3232
+ class NavigationMenuComponent {
3233
+ constructor() {
3234
+ this.items = input.required();
3235
+ this.orientation = input('horizontal');
3236
+ this.ariaLabel = input('Main navigation');
3237
+ }
3238
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: NavigationMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3239
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: NavigationMenuComponent, isStandalone: true, selector: "ui-navigation-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
3240
+ <nav
3241
+ class="ui-nav ui-nav--{{ orientation() }}"
3242
+ [attr.aria-label]="ariaLabel()"
3243
+ >
3244
+ @for (item of items(); track item.id) {
3245
+ @if (item.to) {
3246
+ <a
3247
+ [routerLink]="item.to"
3248
+ routerLinkActive="ui-nav__item--active"
3249
+ class="ui-nav__item"
3250
+ [class.ui-nav__item--disabled]="item.disabled"
3251
+ >
3252
+ @if (item.icon) {
3253
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
3254
+ }
3255
+ <span class="ui-nav__label">{{ item.label }}</span>
3256
+ @if (item.badge) {
3257
+ <span class="ui-nav__badge" [attr.aria-label]="item.badge + ' notifications'">{{ item.badge }}</span>
3258
+ }
3259
+ </a>
3260
+ } @else {
3261
+ <a
3262
+ [href]="item.href ?? '#'"
3263
+ class="ui-nav__item"
3264
+ [class.ui-nav__item--disabled]="item.disabled"
3265
+ >
3266
+ @if (item.icon) {
3267
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
3268
+ }
3269
+ <span class="ui-nav__label">{{ item.label }}</span>
3270
+ </a>
3271
+ }
3272
+ }
3273
+ </nav>
3274
+ `, isInline: true, styles: [".ui-nav{display:flex;align-items:center}.ui-nav--horizontal{flex-direction:row;gap:var(--spacing-1)}.ui-nav--vertical{flex-direction:column;align-items:stretch;gap:var(--spacing-0-5)}.ui-nav__item{display:flex;align-items:center;gap:var(--spacing-2);padding:var(--spacing-2) var(--spacing-3);border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text-muted);text-decoration:none;transition:var(--transition-colors);cursor:pointer}.ui-nav__item:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-nav__item--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-nav__item--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-nav--vertical .ui-nav__item{justify-content:flex-start}.ui-nav__icon{flex-shrink:0;width:1.25rem;height:1.25rem;display:flex;align-items:center;justify-content:center}.ui-nav__label{flex:1}.ui-nav__badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:.7rem;font-weight:var(--font-bold)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3275
+ }
3276
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: NavigationMenuComponent, decorators: [{
3277
+ type: Component,
3278
+ args: [{ selector: 'ui-navigation-menu', standalone: true, imports: [CommonModule, RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
3279
+ <nav
3280
+ class="ui-nav ui-nav--{{ orientation() }}"
3281
+ [attr.aria-label]="ariaLabel()"
3282
+ >
3283
+ @for (item of items(); track item.id) {
3284
+ @if (item.to) {
3285
+ <a
3286
+ [routerLink]="item.to"
3287
+ routerLinkActive="ui-nav__item--active"
3288
+ class="ui-nav__item"
3289
+ [class.ui-nav__item--disabled]="item.disabled"
3290
+ >
3291
+ @if (item.icon) {
3292
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
3293
+ }
3294
+ <span class="ui-nav__label">{{ item.label }}</span>
3295
+ @if (item.badge) {
3296
+ <span class="ui-nav__badge" [attr.aria-label]="item.badge + ' notifications'">{{ item.badge }}</span>
3297
+ }
3298
+ </a>
3299
+ } @else {
3300
+ <a
3301
+ [href]="item.href ?? '#'"
3302
+ class="ui-nav__item"
3303
+ [class.ui-nav__item--disabled]="item.disabled"
3304
+ >
3305
+ @if (item.icon) {
3306
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
3307
+ }
3308
+ <span class="ui-nav__label">{{ item.label }}</span>
3309
+ </a>
3310
+ }
3311
+ }
3312
+ </nav>
3313
+ `, styles: [".ui-nav{display:flex;align-items:center}.ui-nav--horizontal{flex-direction:row;gap:var(--spacing-1)}.ui-nav--vertical{flex-direction:column;align-items:stretch;gap:var(--spacing-0-5)}.ui-nav__item{display:flex;align-items:center;gap:var(--spacing-2);padding:var(--spacing-2) var(--spacing-3);border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text-muted);text-decoration:none;transition:var(--transition-colors);cursor:pointer}.ui-nav__item:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-nav__item--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-nav__item--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-nav--vertical .ui-nav__item{justify-content:flex-start}.ui-nav__icon{flex-shrink:0;width:1.25rem;height:1.25rem;display:flex;align-items:center;justify-content:center}.ui-nav__label{flex:1}.ui-nav__badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:.7rem;font-weight:var(--font-bold)}\n"] }]
3314
+ }] });
3315
+
3316
+ class UiTableCellDirective {
3317
+ constructor(tpl) {
3318
+ this.tpl = tpl;
3319
+ }
3320
+ /** Type-safe static context guard for `let-row`. */
3321
+ static ngTemplateContextGuard(_dir, ctx) {
3322
+ return true;
3323
+ }
3324
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UiTableCellDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
3325
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.20", type: UiTableCellDirective, isStandalone: true, selector: "ng-template[uiCell]", inputs: { columnKey: ["uiCell", "columnKey"] }, ngImport: i0 }); }
3326
+ }
3327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UiTableCellDirective, decorators: [{
3328
+ type: Directive,
3329
+ args: [{
3330
+ selector: 'ng-template[uiCell]',
3331
+ standalone: true,
3332
+ }]
3333
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { columnKey: [{
3334
+ type: Input,
3335
+ args: [{ required: true, alias: 'uiCell' }]
3336
+ }] } });
3337
+
3338
+ /**
3339
+ * Table Organism — Source: Nuxt UI v3 ❖ Table
3340
+ * Data table with sorting, selection, loading state.
3341
+ *
3342
+ * Custom cell templates via UiTableCellDirective:
3343
+ * <ng-template uiCell="columnKey" let-row>
3344
+ * <ui-badge>{{ row['field'] }}</ui-badge>
3345
+ * </ng-template>
3346
+ */
3347
+ class TableComponent {
3348
+ constructor() {
3349
+ this.columns = input.required();
3350
+ this.rows = input([]);
3351
+ this.loading = input(false);
3352
+ this.selectable = input(false);
3353
+ this.caption = input(null);
3354
+ this.emptyLabel = input('No data available.');
3355
+ this.rowIdKey = input('id');
3356
+ this.sortState = model(null);
3357
+ this.selectedIds = model([]);
3358
+ this.rowClick = output();
3359
+ // ── Computed ───────────────────────────────────────────────────────────────
3360
+ this.loadingRows = computed(() => Array.from({ length: 5 }, (_, i) => i));
3361
+ this.allSelected = computed(() => this.rows().length > 0 && this.rows().every(r => this.isSelected(this.rowId(r))));
3362
+ }
3363
+ /** Returns the TemplateRef for a column key if a custom template was provided. */
3364
+ getCellTpl(key) {
3365
+ return this.cellDirs?.find(d => d.columnKey === key)?.tpl ?? null;
3366
+ }
3367
+ // ── Helpers ────────────────────────────────────────────────────────────────
3368
+ rowId(row) {
3369
+ return row[this.rowIdKey()];
3370
+ }
3371
+ isSelected(id) {
3372
+ return this.selectedIds().includes(id);
3373
+ }
3374
+ toggleRow(id) {
3375
+ this.selectedIds.update(ids => ids.includes(id) ? ids.filter(i => i !== id) : [...ids, id]);
3376
+ }
3377
+ toggleAll() {
3378
+ if (this.allSelected()) {
3379
+ this.selectedIds.set([]);
3380
+ }
3381
+ else {
3382
+ this.selectedIds.set(this.rows().map(r => this.rowId(r)));
3383
+ }
3384
+ }
3385
+ sort(key) {
3386
+ this.sortState.update(state => {
3387
+ if (state?.column === key) {
3388
+ return state.direction === 'asc'
3389
+ ? { column: key, direction: 'desc' }
3390
+ : null;
3391
+ }
3392
+ return { column: key, direction: 'asc' };
3393
+ });
3394
+ }
3395
+ getSortIcon(key) {
3396
+ const s = this.sortState();
3397
+ if (!s || s.column !== key)
3398
+ return '↕';
3399
+ return s.direction === 'asc' ? '↑' : '↓';
3400
+ }
3401
+ getSortAriaLabel(key) {
3402
+ const s = this.sortState();
3403
+ if (!s || s.column !== key)
3404
+ return 'none';
3405
+ return s.direction === 'asc' ? 'ascending' : 'descending';
3406
+ }
3407
+ onRowClick(row) {
3408
+ this.rowClick.emit(row);
3409
+ }
3410
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3411
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: TableComponent, isStandalone: true, selector: "ui-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", isSignal: true, isRequired: false, transformFunction: null }, rowIdKey: { classPropertyName: "rowIdKey", publicName: "rowIdKey", isSignal: true, isRequired: false, transformFunction: null }, sortState: { classPropertyName: "sortState", publicName: "sortState", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortState: "sortStateChange", selectedIds: "selectedIdsChange", rowClick: "rowClick" }, queries: [{ propertyName: "cellDirs", predicate: UiTableCellDirective }], ngImport: i0, template: `
3412
+ <div class="ui-table-wrap">
3413
+ <table class="ui-table" [attr.aria-label]="caption()">
3414
+ @if (caption()) {
3415
+ <caption class="ui-table__caption">{{ caption() }}</caption>
3416
+ }
3417
+ <thead class="ui-table__head">
3418
+ <tr>
3419
+ @if (selectable()) {
3420
+ <th class="ui-table__th ui-table__th--checkbox" scope="col">
3421
+ <input type="checkbox" [checked]="allSelected()" (change)="toggleAll()" aria-label="Select all" />
3422
+ </th>
3423
+ }
3424
+ @for (col of columns(); track col.key) {
3425
+ <th
3426
+ [class]="'ui-table__th' + (col.sortable ? ' ui-table__th--sortable' : '') + ' ui-table__th--' + (col.align ?? 'left')"
3427
+ scope="col"
3428
+ [attr.aria-sort]="getSortAriaLabel(col.key)"
3429
+ [style.width]="col.width ?? null"
3430
+ (click)="col.sortable ? sort(col.key) : null"
3431
+ >
3432
+ <span class="ui-table__th-inner">
3433
+ {{ col.label }}
3434
+ @if (col.sortable) {
3435
+ <span class="ui-table__sort-icon" aria-hidden="true">
3436
+ {{ getSortIcon(col.key) }}
3437
+ </span>
3438
+ }
3439
+ </span>
3440
+ </th>
3441
+ }
3442
+ </tr>
3443
+ </thead>
3444
+ <tbody class="ui-table__body">
3445
+ @if (loading()) {
3446
+ @for (i of loadingRows(); track i) {
3447
+ <tr class="ui-table__row ui-table__row--loading">
3448
+ @if (selectable()) {
3449
+ <td><div class="ui-skeleton" style="width:18px;height:18px;border-radius:4px"></div></td>
3450
+ }
3451
+ @for (col of columns(); track col.key) {
3452
+ <td class="ui-table__td">
3453
+ <div class="ui-skeleton" style="height:16px;border-radius:4px"></div>
3454
+ </td>
3455
+ }
3456
+ </tr>
3457
+ }
3458
+ } @else if (rows().length === 0) {
3459
+ <tr>
3460
+ <td [attr.colspan]="columns().length + (selectable() ? 1 : 0)" class="ui-table__empty">
3461
+ <ng-content select="[slot=empty]" />
3462
+ {{ emptyLabel() }}
3463
+ </td>
3464
+ </tr>
3465
+ } @else {
3466
+ @for (row of rows(); track rowId(row)) {
3467
+ <tr
3468
+ class="ui-table__row"
3469
+ [class.ui-table__row--selected]="isSelected(rowId(row))"
3470
+ (click)="onRowClick(row)"
3471
+ >
3472
+ @if (selectable()) {
3473
+ <td class="ui-table__td ui-table__td--checkbox">
3474
+ <input type="checkbox" [checked]="isSelected(rowId(row))"
3475
+ (change)="toggleRow(rowId(row))" [attr.aria-label]="'Select row'" />
3476
+ </td>
3477
+ }
3478
+ @for (col of columns(); track col.key) {
3479
+ <td [class]="'ui-table__td ui-table__td--' + (col.align ?? 'left')">
3480
+ @if (getCellTpl(col.key); as tpl) {
3481
+ <ng-container
3482
+ [ngTemplateOutlet]="tpl"
3483
+ [ngTemplateOutletContext]="{ $implicit: row, row: row }"
3484
+ />
3485
+ } @else {
3486
+ {{ row[col.key] }}
3487
+ }
3488
+ </td>
3489
+ }
3490
+ </tr>
3491
+ }
3492
+ }
3493
+ </tbody>
3494
+ </table>
3495
+ </div>
3496
+
3497
+ <!-- Custom cell template slots (projected, not rendered directly) -->
3498
+ <ng-content />
3499
+ `, isInline: true, styles: [".ui-table-wrap{width:100%;overflow-x:auto;border:1px solid var(--color-border);border-radius:var(--radius-xl)}.ui-table{width:100%;border-collapse:collapse;font-family:var(--font-sans)}.ui-table__caption{font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);padding:var(--spacing-3) var(--spacing-4);text-align:left;caption-side:top}.ui-table__head{background:var(--color-neutral-50)}.ui-table__th{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-wide);border-bottom:1px solid var(--color-border);white-space:nowrap}.ui-table__th--left{text-align:left}.ui-table__th--center{text-align:center}.ui-table__th--right{text-align:right}.ui-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.ui-table__th--sortable:hover{color:var(--color-text)}.ui-table__th--checkbox{width:40px}.ui-table__th-inner{display:inline-flex;align-items:center;gap:var(--spacing-1)}.ui-table__sort-icon{font-size:.75em;opacity:.6}.ui-table__body{background:var(--color-bg)}.ui-table__row{border-bottom:1px solid var(--color-border);transition:background var(--transition-fast)}.ui-table__row:last-child{border-bottom:none}.ui-table__row:hover{background:var(--color-neutral-50)}.ui-table__row--selected{background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-table__row--loading{pointer-events:none}.ui-table__td{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-sm);color:var(--color-text);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-table__td--left{text-align:left}.ui-table__td--center{text-align:center}.ui-table__td--right{text-align:right}.ui-table__td--checkbox{width:40px}.ui-table__empty{padding:var(--spacing-12) var(--spacing-4);text-align:center;color:var(--color-text-muted);font-size:var(--text-sm)}.ui-skeleton{background:linear-gradient(90deg,var(--color-neutral-100) 25%,var(--color-neutral-200) 50%,var(--color-neutral-100) 75%);background-size:200% 100%;animation:ui-shimmer 1.5s ease-in-out infinite}@keyframes ui-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3500
+ }
3501
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TableComponent, decorators: [{
3502
+ type: Component,
3503
+ args: [{ selector: 'ui-table', standalone: true, imports: [CommonModule, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: `
3504
+ <div class="ui-table-wrap">
3505
+ <table class="ui-table" [attr.aria-label]="caption()">
3506
+ @if (caption()) {
3507
+ <caption class="ui-table__caption">{{ caption() }}</caption>
3508
+ }
3509
+ <thead class="ui-table__head">
3510
+ <tr>
3511
+ @if (selectable()) {
3512
+ <th class="ui-table__th ui-table__th--checkbox" scope="col">
3513
+ <input type="checkbox" [checked]="allSelected()" (change)="toggleAll()" aria-label="Select all" />
3514
+ </th>
3515
+ }
3516
+ @for (col of columns(); track col.key) {
3517
+ <th
3518
+ [class]="'ui-table__th' + (col.sortable ? ' ui-table__th--sortable' : '') + ' ui-table__th--' + (col.align ?? 'left')"
3519
+ scope="col"
3520
+ [attr.aria-sort]="getSortAriaLabel(col.key)"
3521
+ [style.width]="col.width ?? null"
3522
+ (click)="col.sortable ? sort(col.key) : null"
3523
+ >
3524
+ <span class="ui-table__th-inner">
3525
+ {{ col.label }}
3526
+ @if (col.sortable) {
3527
+ <span class="ui-table__sort-icon" aria-hidden="true">
3528
+ {{ getSortIcon(col.key) }}
3529
+ </span>
3530
+ }
3531
+ </span>
3532
+ </th>
3533
+ }
3534
+ </tr>
3535
+ </thead>
3536
+ <tbody class="ui-table__body">
3537
+ @if (loading()) {
3538
+ @for (i of loadingRows(); track i) {
3539
+ <tr class="ui-table__row ui-table__row--loading">
3540
+ @if (selectable()) {
3541
+ <td><div class="ui-skeleton" style="width:18px;height:18px;border-radius:4px"></div></td>
3542
+ }
3543
+ @for (col of columns(); track col.key) {
3544
+ <td class="ui-table__td">
3545
+ <div class="ui-skeleton" style="height:16px;border-radius:4px"></div>
3546
+ </td>
3547
+ }
3548
+ </tr>
3549
+ }
3550
+ } @else if (rows().length === 0) {
3551
+ <tr>
3552
+ <td [attr.colspan]="columns().length + (selectable() ? 1 : 0)" class="ui-table__empty">
3553
+ <ng-content select="[slot=empty]" />
3554
+ {{ emptyLabel() }}
3555
+ </td>
3556
+ </tr>
3557
+ } @else {
3558
+ @for (row of rows(); track rowId(row)) {
3559
+ <tr
3560
+ class="ui-table__row"
3561
+ [class.ui-table__row--selected]="isSelected(rowId(row))"
3562
+ (click)="onRowClick(row)"
3563
+ >
3564
+ @if (selectable()) {
3565
+ <td class="ui-table__td ui-table__td--checkbox">
3566
+ <input type="checkbox" [checked]="isSelected(rowId(row))"
3567
+ (change)="toggleRow(rowId(row))" [attr.aria-label]="'Select row'" />
3568
+ </td>
3569
+ }
3570
+ @for (col of columns(); track col.key) {
3571
+ <td [class]="'ui-table__td ui-table__td--' + (col.align ?? 'left')">
3572
+ @if (getCellTpl(col.key); as tpl) {
3573
+ <ng-container
3574
+ [ngTemplateOutlet]="tpl"
3575
+ [ngTemplateOutletContext]="{ $implicit: row, row: row }"
3576
+ />
3577
+ } @else {
3578
+ {{ row[col.key] }}
3579
+ }
3580
+ </td>
3581
+ }
3582
+ </tr>
3583
+ }
3584
+ }
3585
+ </tbody>
3586
+ </table>
3587
+ </div>
3588
+
3589
+ <!-- Custom cell template slots (projected, not rendered directly) -->
3590
+ <ng-content />
3591
+ `, styles: [".ui-table-wrap{width:100%;overflow-x:auto;border:1px solid var(--color-border);border-radius:var(--radius-xl)}.ui-table{width:100%;border-collapse:collapse;font-family:var(--font-sans)}.ui-table__caption{font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);padding:var(--spacing-3) var(--spacing-4);text-align:left;caption-side:top}.ui-table__head{background:var(--color-neutral-50)}.ui-table__th{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-wide);border-bottom:1px solid var(--color-border);white-space:nowrap}.ui-table__th--left{text-align:left}.ui-table__th--center{text-align:center}.ui-table__th--right{text-align:right}.ui-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.ui-table__th--sortable:hover{color:var(--color-text)}.ui-table__th--checkbox{width:40px}.ui-table__th-inner{display:inline-flex;align-items:center;gap:var(--spacing-1)}.ui-table__sort-icon{font-size:.75em;opacity:.6}.ui-table__body{background:var(--color-bg)}.ui-table__row{border-bottom:1px solid var(--color-border);transition:background var(--transition-fast)}.ui-table__row:last-child{border-bottom:none}.ui-table__row:hover{background:var(--color-neutral-50)}.ui-table__row--selected{background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-table__row--loading{pointer-events:none}.ui-table__td{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-sm);color:var(--color-text);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-table__td--left{text-align:left}.ui-table__td--center{text-align:center}.ui-table__td--right{text-align:right}.ui-table__td--checkbox{width:40px}.ui-table__empty{padding:var(--spacing-12) var(--spacing-4);text-align:center;color:var(--color-text-muted);font-size:var(--text-sm)}.ui-skeleton{background:linear-gradient(90deg,var(--color-neutral-100) 25%,var(--color-neutral-200) 50%,var(--color-neutral-100) 75%);background-size:200% 100%;animation:ui-shimmer 1.5s ease-in-out infinite}@keyframes ui-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"] }]
3592
+ }], propDecorators: { cellDirs: [{
3593
+ type: ContentChildren,
3594
+ args: [UiTableCellDirective]
3595
+ }] } });
3596
+
3597
+ // ── Catalogue complet des icônes Lucide + aliases pratiques ──
3598
+ // `icons` contient les 1 700+ icônes en clés PascalCase.
3599
+ // Les aliases couvrent les noms courants qui n'existent pas dans Lucide.
3600
+ // LucideAngularComponent convertit kebab-case → PascalCase avant la recherche.
3601
+ // Ex : name="home" → cherche "Home" → House
3602
+ const SIDEBAR_ICONS = {
3603
+ ...icons,
3604
+ // Aliases courants absents du catalogue Lucide officiel
3605
+ Home: House, // name="home"
3606
+ Dashboard: LayoutDashboard, // name="dashboard"
3607
+ Help: CircleQuestionMark, // name="help"
3608
+ Logout: LogOut, // name="logout"
3609
+ Contacts: Contact, // name="contacts"
3610
+ Feedback: MessageSquare, // name="feedback"
3611
+ };
3612
+ /**
3613
+ * Sidebar Organism — Source: Nuxt UI v4 ❖ DashboardSidebar
3614
+ *
3615
+ * Sidebar de dashboard avec :
3616
+ * - Mode expanded (254px) ↔ collapsed (64px) avec animation CSS
3617
+ * - Header : logo ou slot personnalisé
3618
+ * - Navigation : groupes d'items avec icônes, badges, sous-menus, liens externes
3619
+ * - Search button avec shortcut clavier (⌘ K)
3620
+ * - Footer : utilisateur courant (avatar + nom)
3621
+ * - Compatible dark mode via `[data-theme="dark"]`
3622
+ *
3623
+ * @example
3624
+ * <ui-sidebar [navGroups]="groups" [user]="currentUser" />
3625
+ * <ui-sidebar [(collapsed)]="sidebarCollapsed" [navGroups]="groups" />
3626
+ */
3627
+ class SidebarComponent {
3628
+ constructor() {
3629
+ this.router = inject(Router);
3630
+ // ── Inputs ────────────────────────────────────────────────
3631
+ this.navGroups = input([]);
3632
+ this.footerGroups = input([]);
3633
+ this.user = input(null);
3634
+ this.logoSrc = input(null);
3635
+ this.logoAlt = input('Logo');
3636
+ this.collapsible = input(true);
3637
+ this.showSearch = input(true);
3638
+ this.searchPlaceholder = input('Search...');
3639
+ // ── Two-way binding ───────────────────────────────────────
3640
+ this.collapsed = model(false);
3641
+ // ── Outputs ───────────────────────────────────────────────
3642
+ this.searchClick = output();
3643
+ this.itemClick = output();
3644
+ this.userClick = output();
3645
+ // ── URL courante (réactive) ───────────────────────────────
3646
+ this.currentUrl = toSignal(this.router.events.pipe(filter(e => e instanceof NavigationEnd), map(() => this.router.url), startWith(this.router.url)), { initialValue: this.router.url });
3647
+ // ── Internal state (open sub-menus) ───────────────────────
3648
+ this.openItems = signal(new Set());
3649
+ // Auto-ouvre les sous-menus dont un enfant correspond à la route active
3650
+ effect(() => {
3651
+ const url = this.currentUrl();
3652
+ const allGroups = [...this.navGroups(), ...this.footerGroups()];
3653
+ allGroups.forEach(group => group.items.forEach(item => {
3654
+ const hasActiveChild = item.children?.some(child => child.href && url.startsWith(child.href)) ?? false;
3655
+ if (hasActiveChild) {
3656
+ this.openItems.update(set => new Set(set).add(item.id));
3657
+ }
3658
+ }));
3659
+ });
3660
+ }
3661
+ isItemOpen(id) {
3662
+ return this.openItems().has(id);
3663
+ }
3664
+ /**
3665
+ * Un item parent (button) est actif si au moins un de ses enfants
3666
+ * correspond à l'URL courante.
3667
+ */
3668
+ isParentActive(item) {
3669
+ const url = this.currentUrl();
3670
+ return item.children?.some(child => child.href ? url.startsWith(child.href) : false) ?? false;
3671
+ }
3672
+ toggleItem(id) {
3673
+ this.openItems.update(set => {
3674
+ const next = new Set(set);
3675
+ next.has(id) ? next.delete(id) : next.add(id);
3676
+ return next;
3677
+ });
3678
+ }
3679
+ toggleCollapse() {
3680
+ this.collapsed.update(v => !v);
3681
+ }
3682
+ navigate(item) {
3683
+ this.itemClick.emit(item);
3684
+ if (!item.href || item.disabled)
3685
+ return;
3686
+ if (item.external) {
3687
+ window.open(item.href, '_blank', 'noopener,noreferrer');
3688
+ }
3689
+ else {
3690
+ this.router.navigate([item.href]);
3691
+ }
3692
+ }
3693
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3694
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SidebarComponent, isStandalone: true, selector: "ui-sidebar", inputs: { navGroups: { classPropertyName: "navGroups", publicName: "navGroups", isSignal: true, isRequired: false, transformFunction: null }, footerGroups: { classPropertyName: "footerGroups", publicName: "footerGroups", isSignal: true, isRequired: false, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null }, logoSrc: { classPropertyName: "logoSrc", publicName: "logoSrc", isSignal: true, isRequired: false, transformFunction: null }, logoAlt: { classPropertyName: "logoAlt", publicName: "logoAlt", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", searchClick: "searchClick", itemClick: "itemClick", userClick: "userClick" }, providers: [
3695
+ { provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(SIDEBAR_ICONS) },
3696
+ ], ngImport: i0, template: `
3697
+ <aside
3698
+ class="ui-sidebar"
3699
+ [class.ui-sidebar--collapsed]="collapsed()"
3700
+ [class.ui-sidebar--collapsible]="collapsible()"
3701
+ [attr.aria-label]="'Sidebar navigation'"
3702
+ >
3703
+
3704
+ <!-- ── Header ─────────────────────────────────────────────── -->
3705
+ <div class="ui-sidebar__header">
3706
+ <div class="ui-sidebar__logo">
3707
+ @if (logoSrc()) {
3708
+ <img [src]="logoSrc()" [alt]="logoAlt()" class="ui-sidebar__logo-img" />
3709
+ } @else {
3710
+ <span class="ui-sidebar__logo-text">{{ logoAlt() }}</span>
3711
+ }
3712
+ </div>
3713
+
3714
+ @if (collapsible()) {
3715
+ <!-- Figma: toggle uses i-lucide-chevrons-up-down, consistent in expanded & collapsed states -->
3716
+ <button
3717
+ type="button"
3718
+ class="ui-sidebar__toggle"
3719
+ [attr.aria-label]="collapsed() ? 'Expand sidebar' : 'Collapse sidebar'"
3720
+ (click)="toggleCollapse()"
3721
+ >
3722
+ <lucide-icon name="chevrons-up-down" [size]="16" aria-hidden="true" />
3723
+ </button>
3724
+ }
3725
+ </div>
3726
+
3727
+ <!-- ── Body ───────────────────────────────────────────────── -->
3728
+ <div class="ui-sidebar__body">
3729
+
3730
+ <!-- Top section: search + primary nav groups -->
3731
+ <div class="ui-sidebar__top">
3732
+
3733
+ <!-- Search button -->
3734
+ @if (showSearch()) {
3735
+ <button
3736
+ type="button"
3737
+ class="ui-sidebar__search"
3738
+ [attr.aria-label]="searchPlaceholder()"
3739
+ (click)="searchClick.emit()"
3740
+ >
3741
+ <lucide-icon name="search" [size]="20" aria-hidden="true" class="ui-sidebar__search-icon" />
3742
+ <span class="ui-sidebar__search-label">{{ searchPlaceholder() }}</span>
3743
+ <span class="ui-sidebar__search-kbd" aria-hidden="true">
3744
+ <kbd class="ui-sidebar__kbd">⌘</kbd>
3745
+ <kbd class="ui-sidebar__kbd">K</kbd>
3746
+ </span>
3747
+ </button>
3748
+ }
3749
+
3750
+ <!-- Primary nav groups -->
3751
+ @for (group of navGroups(); track $index) {
3752
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Navigation'">
3753
+ @if (group.label && !collapsed()) {
3754
+ <p class="ui-sidebar__group-label">{{ group.label }}</p>
3755
+ }
3756
+ @for (item of group.items; track item.id) {
3757
+ <div class="ui-sidebar__nav-item-wrap">
3758
+
3759
+ @if (item.children?.length) {
3760
+ <!-- ── Collapsible parent item ── -->
3761
+ <button
3762
+ type="button"
3763
+ class="ui-sidebar__item"
3764
+ [class.ui-sidebar__item--active]="isParentActive(item)"
3765
+ [class.ui-sidebar__item--disabled]="item.disabled"
3766
+ [attr.aria-expanded]="isItemOpen(item.id)"
3767
+ [disabled]="item.disabled ?? null"
3768
+ (click)="toggleItem(item.id)"
3769
+ >
3770
+ @if (item.icon) {
3771
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
3772
+ }
3773
+ <span class="ui-sidebar__item-label">{{ item.label }}</span>
3774
+ @if (item.badge != null && !collapsed()) {
3775
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
3776
+ {{ item.badge }}
3777
+ </span>
3778
+ }
3779
+ @if (!collapsed()) {
3780
+ <span class="ui-sidebar__chevron"
3781
+ [class.ui-sidebar__chevron--open]="isItemOpen(item.id)"
3782
+ aria-hidden="true">
3783
+ <lucide-icon name="chevron-down" [size]="20" />
3784
+ </span>
3785
+ }
3786
+ </button>
3787
+
3788
+ <!-- Sub-items (only in expanded mode) -->
3789
+ @if (isItemOpen(item.id) && !collapsed()) {
3790
+ <div class="ui-sidebar__children" [@expand]>
3791
+ @for (child of item.children; track child.id) {
3792
+ <!-- Figma: NavigationMenuItem child has border-l + px-[6px] on outer wrapper -->
3793
+ <div class="ui-sidebar__child-wrap"
3794
+ [class.ui-sidebar__child-wrap--active]="childRla.isActive">
3795
+ <button
3796
+ type="button"
3797
+ #childRla="routerLinkActive"
3798
+ routerLinkActive
3799
+ [routerLink]="!child.external ? (child.href ?? null) : null"
3800
+ [routerLinkActiveOptions]="{ exact: true }"
3801
+ class="ui-sidebar__child"
3802
+ [class.ui-sidebar__child--active]="child.external ? !!child.active : childRla.isActive"
3803
+ [class.ui-sidebar__child--disabled]="child.disabled"
3804
+ [disabled]="child.disabled ?? null"
3805
+ (click)="navigate(child)"
3806
+ >
3807
+ @if (child.icon) {
3808
+ <lucide-icon [name]="child.icon" [size]="16" aria-hidden="true" class="ui-sidebar__child-icon" />
3809
+ }
3810
+ <span class="ui-sidebar__child-label">{{ child.label }}</span>
3811
+ </button>
3812
+ </div>
3813
+ }
3814
+ </div>
3815
+ }
3816
+
3817
+ } @else {
3818
+ <!-- ── Simple item ── -->
3819
+ <button
3820
+ type="button"
3821
+ #navRla="routerLinkActive"
3822
+ routerLinkActive
3823
+ [routerLink]="!item.external ? (item.href ?? null) : null"
3824
+ [routerLinkActiveOptions]="{ exact: false }"
3825
+ class="ui-sidebar__item"
3826
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : navRla.isActive"
3827
+ [class.ui-sidebar__item--disabled]="item.disabled"
3828
+ [disabled]="item.disabled ?? null"
3829
+ (click)="navigate(item)"
3830
+ >
3831
+ @if (item.icon) {
3832
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
3833
+ }
3834
+ <span class="ui-sidebar__item-label">
3835
+ {{ item.label }}
3836
+ @if (item.external) {
3837
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
3838
+ }
3839
+ </span>
3840
+ @if (item.badge != null && !collapsed()) {
3841
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
3842
+ {{ item.badge }}
3843
+ </span>
3844
+ }
3845
+ </button>
3846
+ }
3847
+
3848
+ </div>
3849
+ }
3850
+ </nav>
3851
+ }
3852
+ </div>
3853
+
3854
+ <!-- Bottom section: secondary / footer nav groups -->
3855
+ @if (footerGroups().length) {
3856
+ <div class="ui-sidebar__bottom">
3857
+ @for (group of footerGroups(); track $index) {
3858
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Footer navigation'">
3859
+ @for (item of group.items; track item.id) {
3860
+ <button
3861
+ type="button"
3862
+ #footerRla="routerLinkActive"
3863
+ routerLinkActive
3864
+ [routerLink]="!item.external ? (item.href ?? null) : null"
3865
+ [routerLinkActiveOptions]="{ exact: false }"
3866
+ class="ui-sidebar__item"
3867
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : footerRla.isActive"
3868
+ [class.ui-sidebar__item--disabled]="item.disabled"
3869
+ [disabled]="item.disabled ?? null"
3870
+ (click)="navigate(item)"
3871
+ >
3872
+ @if (item.icon) {
3873
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
3874
+ }
3875
+ <span class="ui-sidebar__item-label">
3876
+ {{ item.label }}
3877
+ @if (item.external) {
3878
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
3879
+ }
3880
+ </span>
3881
+ </button>
3882
+ }
3883
+ </nav>
3884
+ }
3885
+ </div>
3886
+ }
3887
+
3888
+ </div>
3889
+
3890
+ <!-- ── Footer ─────────────────────────────────────────────── -->
3891
+ @if (user()) {
3892
+ <div class="ui-sidebar__footer">
3893
+ <button
3894
+ type="button"
3895
+ class="ui-sidebar__user"
3896
+ [attr.aria-label]="'Account: ' + user()!.name"
3897
+ (click)="userClick.emit(user()!)"
3898
+ >
3899
+ @if (user()!.avatar) {
3900
+ <img
3901
+ class="ui-sidebar__avatar"
3902
+ [src]="user()!.avatar"
3903
+ [alt]="user()!.name"
3904
+ />
3905
+ } @else {
3906
+ <span class="ui-sidebar__avatar-fallback" aria-hidden="true">
3907
+ {{ user()!.name.charAt(0).toUpperCase() }}
3908
+ </span>
3909
+ }
3910
+ <span class="ui-sidebar__user-name">{{ user()!.name }}</span>
3911
+ </button>
3912
+ </div>
3913
+ }
3914
+
3915
+ </aside>
3916
+ `, isInline: true, styles: [".ui-sidebar{--sidebar-border-accented: #cad5e2;position:relative;display:flex;flex-direction:column;width:254px;height:100%;min-height:0;background:var(--color-bg);border-right:1px solid var(--color-border);overflow:hidden;transition:width var(--transition-slow)}.ui-sidebar--collapsed{width:64px}.ui-sidebar__header{position:relative;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;height:64px;padding:0 var(--spacing-4);border-bottom:1px solid var(--color-border);z-index:3}.ui-sidebar--collapsed .ui-sidebar__header{justify-content:center;padding:0 var(--spacing-2)}.ui-sidebar__logo{display:flex;align-items:center;overflow:hidden;white-space:nowrap;min-width:0}.ui-sidebar__logo-img{display:block;height:20px;width:auto;max-width:130px;object-fit:contain;flex-shrink:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-img{max-width:32px;height:32px;object-fit:cover;border-radius:var(--radius-md)}.ui-sidebar__logo-text{font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-text{opacity:0;width:0}.ui-sidebar__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;border:1px solid var(--color-border);border-radius:var(--radius-md);background:transparent;color:var(--color-text-subtle);cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors),border-color var(--transition-colors);padding:0}.ui-sidebar__toggle:hover{background:var(--color-bg-subtle);color:var(--color-text);border-color:var(--color-border-accent, var(--color-border))}.ui-sidebar__toggle:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__toggle{width:32px;height:32px}.ui-sidebar__toggle lucide-icon{display:flex}.ui-sidebar__body{display:flex;flex-direction:column;flex:1 0 0;justify-content:space-between;overflow-y:auto;overflow-x:hidden;min-height:0;padding:var(--spacing-2) var(--spacing-4) var(--spacing-4-5, 18px);scrollbar-width:thin;scrollbar-color:var(--color-border) transparent;z-index:2}.ui-sidebar--collapsed .ui-sidebar__body{padding:var(--spacing-2)}.ui-sidebar__body::-webkit-scrollbar{width:4px}.ui-sidebar__body::-webkit-scrollbar-track{background:transparent}.ui-sidebar__body::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.ui-sidebar__top{display:flex;flex-direction:column;gap:var(--spacing-4)}.ui-sidebar__bottom{display:flex;flex-direction:column;margin-top:var(--spacing-4)}.ui-sidebar__search{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;height:32px;padding:0 var(--spacing-2-5);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);cursor:pointer;transition:background-color var(--transition-colors),border-color var(--transition-colors);text-align:left;flex-shrink:0}.ui-sidebar__search:hover{background:var(--color-bg-subtle);border-color:var(--sidebar-border-accented);color:var(--color-text)}.ui-sidebar__search:focus-visible{outline:none;border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-sidebar--collapsed .ui-sidebar__search{width:100%;height:36px;padding:0;border:1px solid var(--sidebar-border-accented);justify-content:center;border-radius:var(--radius-md)}lucide-icon.ui-sidebar__search-icon{display:flex;align-items:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__search-icon svg{width:100%;height:100%}.ui-sidebar__search-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity var(--transition-fast),width var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__search-label{display:none}.ui-sidebar__search-kbd{display:flex;align-items:center;gap:2px;flex-shrink:0;margin-left:auto}.ui-sidebar--collapsed .ui-sidebar__search-kbd{display:none}.ui-sidebar__kbd{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0 var(--spacing-1);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-sm, 4px);background:var(--color-bg);font-size:10px;font-family:var(--font-mono, monospace);color:var(--color-text);line-height:1}.ui-sidebar__group{display:flex;flex-direction:column}.ui-sidebar__group-label{padding:var(--spacing-1) var(--spacing-2-5);font-size:var(--text-xs, 11px);font-weight:var(--font-medium, 500);color:var(--color-text-subtle);text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:var(--spacing-1)}.ui-sidebar__nav-item-wrap{display:flex;flex-direction:column;padding-right:6px}.ui-sidebar__nav-item-wrap:has(.ui-sidebar__item--active){padding-right:0}.ui-sidebar--collapsed .ui-sidebar__nav-item-wrap{padding-right:0}.ui-sidebar__item{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border-radius:var(--radius-md);background:transparent;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-decoration:none;cursor:pointer;white-space:nowrap;overflow:hidden;text-align:left;transition:background-color var(--transition-colors),color var(--transition-colors);min-height:32px}.ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__item:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__item--active{background:var(--color-bg-muted);color:var(--color-primary-500);font-weight:var(--font-semibold, 600)}.ui-sidebar__item--active:hover{background:color-mix(in srgb,var(--color-primary-500) 8%,var(--color-bg))}.ui-sidebar__item--active .ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ui-sidebar--collapsed .ui-sidebar__item{justify-content:center;padding:var(--spacing-1-5);min-height:36px}lucide-icon.ui-sidebar__item-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__item-icon svg{width:100%;height:100%;flex-shrink:0}.ui-sidebar__item--active lucide-icon.ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item-label{display:flex;align-items:center;gap:var(--spacing-1);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__item-label{display:none}lucide-icon.ui-sidebar__external{display:inline-flex;align-items:center;width:12px;height:12px;flex-shrink:0;opacity:.5}lucide-icon.ui-sidebar__external svg{width:100%;height:100%}.ui-sidebar__badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 var(--spacing-1-5);border-radius:var(--radius-md);background:var(--color-bg);border:1px solid var(--sidebar-border-accented);color:var(--color-text);font-size:10px;font-weight:var(--font-medium, 500);line-height:1;flex-shrink:0;margin-left:auto}.ui-sidebar__chevron{display:flex;align-items:center;flex-shrink:0;margin-left:auto;color:var(--color-text-subtle);transition:transform var(--transition-fast)}.ui-sidebar__chevron svg{width:20px;height:20px}.ui-sidebar__chevron--open{transform:rotate(180deg)}.ui-sidebar__children{display:flex;flex-direction:column;padding-left:var(--spacing-5);margin-top:var(--spacing-2);overflow:hidden}.ui-sidebar__child-wrap{display:flex;align-items:center;padding:0 var(--spacing-1-5);border-left:1px solid var(--color-border);width:100%}.ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}.ui-sidebar__child{display:flex;align-items:center;gap:var(--spacing-1-5);flex:1 0 0;width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-align:left;text-decoration:none;cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors);white-space:nowrap;overflow:hidden;min-width:0}.ui-sidebar__child:hover:not(.ui-sidebar__child--disabled):not(.ui-sidebar__child--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__child:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__child--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 6%,transparent)}.ui-sidebar__child--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}lucide-icon.ui-sidebar__child-icon{display:flex;align-items:center;flex-shrink:0;width:16px;height:16px;opacity:.6}lucide-icon.ui-sidebar__child-icon svg{width:100%;height:100%}.ui-sidebar__child-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-sidebar__footer{flex-shrink:0;padding:var(--spacing-2) var(--spacing-4);border-top:1px solid var(--color-border);z-index:1}.ui-sidebar--collapsed .ui-sidebar__footer{padding:var(--spacing-2)}.ui-sidebar__user{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);cursor:pointer;text-align:left;white-space:nowrap;overflow:hidden;transition:background-color var(--transition-colors)}.ui-sidebar__user:hover{background:var(--color-bg-subtle)}.ui-sidebar__user:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__user{justify-content:center;padding:var(--spacing-1-5)}.ui-sidebar__avatar{width:20px;height:20px;border-radius:var(--radius-full);object-fit:cover;flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar{width:24px;height:24px}.ui-sidebar__avatar-fallback{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:10px;font-weight:var(--font-semibold, 600);flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar-fallback{width:24px;height:24px;font-size:11px}.ui-sidebar__user-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__user-name{display:none}[data-theme=dark] .ui-sidebar{background:var(--color-neutral-950);border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__header{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__toggle{border-color:var(--color-neutral-700);color:var(--color-neutral-400)}[data-theme=dark] .ui-sidebar__toggle:hover{background:var(--color-neutral-800);color:var(--color-neutral-100);border-color:var(--color-neutral-600)}[data-theme=dark] .ui-sidebar__search{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__search:hover{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__kbd{background:var(--color-neutral-800);border-color:var(--color-neutral-600);color:var(--color-neutral-300)}[data-theme=dark] .ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__item--active{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__badge{background:var(--color-neutral-800);border-color:var(--color-neutral-700);color:var(--color-neutral-200)}[data-theme=dark] .ui-sidebar__child-wrap{border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}[data-theme=dark] .ui-sidebar__child:hover:not(.ui-sidebar__child--disabled){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__footer{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__user:hover{background:var(--color-neutral-800)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1$3.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], animations: [
3917
+ trigger('expand', [
3918
+ transition(':enter', [
3919
+ style({ height: '0', opacity: 0, overflow: 'hidden' }),
3920
+ animate('180ms ease', style({ height: '*', opacity: 1, overflow: 'hidden' })),
3921
+ ]),
3922
+ transition(':leave', [
3923
+ style({ overflow: 'hidden' }),
3924
+ animate('150ms ease', style({ height: '0', opacity: 0 })),
3925
+ ]),
3926
+ ]),
3927
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3928
+ }
3929
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SidebarComponent, decorators: [{
3930
+ type: Component,
3931
+ args: [{ selector: 'ui-sidebar', standalone: true, imports: [RouterLink, RouterLinkActive, LucideAngularModule], providers: [
3932
+ { provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(SIDEBAR_ICONS) },
3933
+ ], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
3934
+ trigger('expand', [
3935
+ transition(':enter', [
3936
+ style({ height: '0', opacity: 0, overflow: 'hidden' }),
3937
+ animate('180ms ease', style({ height: '*', opacity: 1, overflow: 'hidden' })),
3938
+ ]),
3939
+ transition(':leave', [
3940
+ style({ overflow: 'hidden' }),
3941
+ animate('150ms ease', style({ height: '0', opacity: 0 })),
3942
+ ]),
3943
+ ]),
3944
+ ], template: `
3945
+ <aside
3946
+ class="ui-sidebar"
3947
+ [class.ui-sidebar--collapsed]="collapsed()"
3948
+ [class.ui-sidebar--collapsible]="collapsible()"
3949
+ [attr.aria-label]="'Sidebar navigation'"
3950
+ >
3951
+
3952
+ <!-- ── Header ─────────────────────────────────────────────── -->
3953
+ <div class="ui-sidebar__header">
3954
+ <div class="ui-sidebar__logo">
3955
+ @if (logoSrc()) {
3956
+ <img [src]="logoSrc()" [alt]="logoAlt()" class="ui-sidebar__logo-img" />
3957
+ } @else {
3958
+ <span class="ui-sidebar__logo-text">{{ logoAlt() }}</span>
3959
+ }
3960
+ </div>
3961
+
3962
+ @if (collapsible()) {
3963
+ <!-- Figma: toggle uses i-lucide-chevrons-up-down, consistent in expanded & collapsed states -->
3964
+ <button
3965
+ type="button"
3966
+ class="ui-sidebar__toggle"
3967
+ [attr.aria-label]="collapsed() ? 'Expand sidebar' : 'Collapse sidebar'"
3968
+ (click)="toggleCollapse()"
3969
+ >
3970
+ <lucide-icon name="chevrons-up-down" [size]="16" aria-hidden="true" />
3971
+ </button>
3972
+ }
3973
+ </div>
3974
+
3975
+ <!-- ── Body ───────────────────────────────────────────────── -->
3976
+ <div class="ui-sidebar__body">
3977
+
3978
+ <!-- Top section: search + primary nav groups -->
3979
+ <div class="ui-sidebar__top">
3980
+
3981
+ <!-- Search button -->
3982
+ @if (showSearch()) {
3983
+ <button
3984
+ type="button"
3985
+ class="ui-sidebar__search"
3986
+ [attr.aria-label]="searchPlaceholder()"
3987
+ (click)="searchClick.emit()"
3988
+ >
3989
+ <lucide-icon name="search" [size]="20" aria-hidden="true" class="ui-sidebar__search-icon" />
3990
+ <span class="ui-sidebar__search-label">{{ searchPlaceholder() }}</span>
3991
+ <span class="ui-sidebar__search-kbd" aria-hidden="true">
3992
+ <kbd class="ui-sidebar__kbd">⌘</kbd>
3993
+ <kbd class="ui-sidebar__kbd">K</kbd>
3994
+ </span>
3995
+ </button>
3996
+ }
3997
+
3998
+ <!-- Primary nav groups -->
3999
+ @for (group of navGroups(); track $index) {
4000
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Navigation'">
4001
+ @if (group.label && !collapsed()) {
4002
+ <p class="ui-sidebar__group-label">{{ group.label }}</p>
4003
+ }
4004
+ @for (item of group.items; track item.id) {
4005
+ <div class="ui-sidebar__nav-item-wrap">
4006
+
4007
+ @if (item.children?.length) {
4008
+ <!-- ── Collapsible parent item ── -->
4009
+ <button
4010
+ type="button"
4011
+ class="ui-sidebar__item"
4012
+ [class.ui-sidebar__item--active]="isParentActive(item)"
4013
+ [class.ui-sidebar__item--disabled]="item.disabled"
4014
+ [attr.aria-expanded]="isItemOpen(item.id)"
4015
+ [disabled]="item.disabled ?? null"
4016
+ (click)="toggleItem(item.id)"
4017
+ >
4018
+ @if (item.icon) {
4019
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
4020
+ }
4021
+ <span class="ui-sidebar__item-label">{{ item.label }}</span>
4022
+ @if (item.badge != null && !collapsed()) {
4023
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
4024
+ {{ item.badge }}
4025
+ </span>
4026
+ }
4027
+ @if (!collapsed()) {
4028
+ <span class="ui-sidebar__chevron"
4029
+ [class.ui-sidebar__chevron--open]="isItemOpen(item.id)"
4030
+ aria-hidden="true">
4031
+ <lucide-icon name="chevron-down" [size]="20" />
4032
+ </span>
4033
+ }
4034
+ </button>
4035
+
4036
+ <!-- Sub-items (only in expanded mode) -->
4037
+ @if (isItemOpen(item.id) && !collapsed()) {
4038
+ <div class="ui-sidebar__children" [@expand]>
4039
+ @for (child of item.children; track child.id) {
4040
+ <!-- Figma: NavigationMenuItem child has border-l + px-[6px] on outer wrapper -->
4041
+ <div class="ui-sidebar__child-wrap"
4042
+ [class.ui-sidebar__child-wrap--active]="childRla.isActive">
4043
+ <button
4044
+ type="button"
4045
+ #childRla="routerLinkActive"
4046
+ routerLinkActive
4047
+ [routerLink]="!child.external ? (child.href ?? null) : null"
4048
+ [routerLinkActiveOptions]="{ exact: true }"
4049
+ class="ui-sidebar__child"
4050
+ [class.ui-sidebar__child--active]="child.external ? !!child.active : childRla.isActive"
4051
+ [class.ui-sidebar__child--disabled]="child.disabled"
4052
+ [disabled]="child.disabled ?? null"
4053
+ (click)="navigate(child)"
4054
+ >
4055
+ @if (child.icon) {
4056
+ <lucide-icon [name]="child.icon" [size]="16" aria-hidden="true" class="ui-sidebar__child-icon" />
4057
+ }
4058
+ <span class="ui-sidebar__child-label">{{ child.label }}</span>
4059
+ </button>
4060
+ </div>
4061
+ }
4062
+ </div>
4063
+ }
4064
+
4065
+ } @else {
4066
+ <!-- ── Simple item ── -->
4067
+ <button
4068
+ type="button"
4069
+ #navRla="routerLinkActive"
4070
+ routerLinkActive
4071
+ [routerLink]="!item.external ? (item.href ?? null) : null"
4072
+ [routerLinkActiveOptions]="{ exact: false }"
4073
+ class="ui-sidebar__item"
4074
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : navRla.isActive"
4075
+ [class.ui-sidebar__item--disabled]="item.disabled"
4076
+ [disabled]="item.disabled ?? null"
4077
+ (click)="navigate(item)"
4078
+ >
4079
+ @if (item.icon) {
4080
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
4081
+ }
4082
+ <span class="ui-sidebar__item-label">
4083
+ {{ item.label }}
4084
+ @if (item.external) {
4085
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
4086
+ }
4087
+ </span>
4088
+ @if (item.badge != null && !collapsed()) {
4089
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
4090
+ {{ item.badge }}
4091
+ </span>
4092
+ }
4093
+ </button>
4094
+ }
4095
+
4096
+ </div>
4097
+ }
4098
+ </nav>
4099
+ }
4100
+ </div>
4101
+
4102
+ <!-- Bottom section: secondary / footer nav groups -->
4103
+ @if (footerGroups().length) {
4104
+ <div class="ui-sidebar__bottom">
4105
+ @for (group of footerGroups(); track $index) {
4106
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Footer navigation'">
4107
+ @for (item of group.items; track item.id) {
4108
+ <button
4109
+ type="button"
4110
+ #footerRla="routerLinkActive"
4111
+ routerLinkActive
4112
+ [routerLink]="!item.external ? (item.href ?? null) : null"
4113
+ [routerLinkActiveOptions]="{ exact: false }"
4114
+ class="ui-sidebar__item"
4115
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : footerRla.isActive"
4116
+ [class.ui-sidebar__item--disabled]="item.disabled"
4117
+ [disabled]="item.disabled ?? null"
4118
+ (click)="navigate(item)"
4119
+ >
4120
+ @if (item.icon) {
4121
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
4122
+ }
4123
+ <span class="ui-sidebar__item-label">
4124
+ {{ item.label }}
4125
+ @if (item.external) {
4126
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
4127
+ }
4128
+ </span>
4129
+ </button>
4130
+ }
4131
+ </nav>
4132
+ }
4133
+ </div>
4134
+ }
4135
+
4136
+ </div>
4137
+
4138
+ <!-- ── Footer ─────────────────────────────────────────────── -->
4139
+ @if (user()) {
4140
+ <div class="ui-sidebar__footer">
4141
+ <button
4142
+ type="button"
4143
+ class="ui-sidebar__user"
4144
+ [attr.aria-label]="'Account: ' + user()!.name"
4145
+ (click)="userClick.emit(user()!)"
4146
+ >
4147
+ @if (user()!.avatar) {
4148
+ <img
4149
+ class="ui-sidebar__avatar"
4150
+ [src]="user()!.avatar"
4151
+ [alt]="user()!.name"
4152
+ />
4153
+ } @else {
4154
+ <span class="ui-sidebar__avatar-fallback" aria-hidden="true">
4155
+ {{ user()!.name.charAt(0).toUpperCase() }}
4156
+ </span>
4157
+ }
4158
+ <span class="ui-sidebar__user-name">{{ user()!.name }}</span>
4159
+ </button>
4160
+ </div>
4161
+ }
4162
+
4163
+ </aside>
4164
+ `, styles: [".ui-sidebar{--sidebar-border-accented: #cad5e2;position:relative;display:flex;flex-direction:column;width:254px;height:100%;min-height:0;background:var(--color-bg);border-right:1px solid var(--color-border);overflow:hidden;transition:width var(--transition-slow)}.ui-sidebar--collapsed{width:64px}.ui-sidebar__header{position:relative;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;height:64px;padding:0 var(--spacing-4);border-bottom:1px solid var(--color-border);z-index:3}.ui-sidebar--collapsed .ui-sidebar__header{justify-content:center;padding:0 var(--spacing-2)}.ui-sidebar__logo{display:flex;align-items:center;overflow:hidden;white-space:nowrap;min-width:0}.ui-sidebar__logo-img{display:block;height:20px;width:auto;max-width:130px;object-fit:contain;flex-shrink:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-img{max-width:32px;height:32px;object-fit:cover;border-radius:var(--radius-md)}.ui-sidebar__logo-text{font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-text{opacity:0;width:0}.ui-sidebar__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;border:1px solid var(--color-border);border-radius:var(--radius-md);background:transparent;color:var(--color-text-subtle);cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors),border-color var(--transition-colors);padding:0}.ui-sidebar__toggle:hover{background:var(--color-bg-subtle);color:var(--color-text);border-color:var(--color-border-accent, var(--color-border))}.ui-sidebar__toggle:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__toggle{width:32px;height:32px}.ui-sidebar__toggle lucide-icon{display:flex}.ui-sidebar__body{display:flex;flex-direction:column;flex:1 0 0;justify-content:space-between;overflow-y:auto;overflow-x:hidden;min-height:0;padding:var(--spacing-2) var(--spacing-4) var(--spacing-4-5, 18px);scrollbar-width:thin;scrollbar-color:var(--color-border) transparent;z-index:2}.ui-sidebar--collapsed .ui-sidebar__body{padding:var(--spacing-2)}.ui-sidebar__body::-webkit-scrollbar{width:4px}.ui-sidebar__body::-webkit-scrollbar-track{background:transparent}.ui-sidebar__body::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.ui-sidebar__top{display:flex;flex-direction:column;gap:var(--spacing-4)}.ui-sidebar__bottom{display:flex;flex-direction:column;margin-top:var(--spacing-4)}.ui-sidebar__search{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;height:32px;padding:0 var(--spacing-2-5);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);cursor:pointer;transition:background-color var(--transition-colors),border-color var(--transition-colors);text-align:left;flex-shrink:0}.ui-sidebar__search:hover{background:var(--color-bg-subtle);border-color:var(--sidebar-border-accented);color:var(--color-text)}.ui-sidebar__search:focus-visible{outline:none;border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-sidebar--collapsed .ui-sidebar__search{width:100%;height:36px;padding:0;border:1px solid var(--sidebar-border-accented);justify-content:center;border-radius:var(--radius-md)}lucide-icon.ui-sidebar__search-icon{display:flex;align-items:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__search-icon svg{width:100%;height:100%}.ui-sidebar__search-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity var(--transition-fast),width var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__search-label{display:none}.ui-sidebar__search-kbd{display:flex;align-items:center;gap:2px;flex-shrink:0;margin-left:auto}.ui-sidebar--collapsed .ui-sidebar__search-kbd{display:none}.ui-sidebar__kbd{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0 var(--spacing-1);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-sm, 4px);background:var(--color-bg);font-size:10px;font-family:var(--font-mono, monospace);color:var(--color-text);line-height:1}.ui-sidebar__group{display:flex;flex-direction:column}.ui-sidebar__group-label{padding:var(--spacing-1) var(--spacing-2-5);font-size:var(--text-xs, 11px);font-weight:var(--font-medium, 500);color:var(--color-text-subtle);text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:var(--spacing-1)}.ui-sidebar__nav-item-wrap{display:flex;flex-direction:column;padding-right:6px}.ui-sidebar__nav-item-wrap:has(.ui-sidebar__item--active){padding-right:0}.ui-sidebar--collapsed .ui-sidebar__nav-item-wrap{padding-right:0}.ui-sidebar__item{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border-radius:var(--radius-md);background:transparent;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-decoration:none;cursor:pointer;white-space:nowrap;overflow:hidden;text-align:left;transition:background-color var(--transition-colors),color var(--transition-colors);min-height:32px}.ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__item:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__item--active{background:var(--color-bg-muted);color:var(--color-primary-500);font-weight:var(--font-semibold, 600)}.ui-sidebar__item--active:hover{background:color-mix(in srgb,var(--color-primary-500) 8%,var(--color-bg))}.ui-sidebar__item--active .ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ui-sidebar--collapsed .ui-sidebar__item{justify-content:center;padding:var(--spacing-1-5);min-height:36px}lucide-icon.ui-sidebar__item-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__item-icon svg{width:100%;height:100%;flex-shrink:0}.ui-sidebar__item--active lucide-icon.ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item-label{display:flex;align-items:center;gap:var(--spacing-1);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__item-label{display:none}lucide-icon.ui-sidebar__external{display:inline-flex;align-items:center;width:12px;height:12px;flex-shrink:0;opacity:.5}lucide-icon.ui-sidebar__external svg{width:100%;height:100%}.ui-sidebar__badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 var(--spacing-1-5);border-radius:var(--radius-md);background:var(--color-bg);border:1px solid var(--sidebar-border-accented);color:var(--color-text);font-size:10px;font-weight:var(--font-medium, 500);line-height:1;flex-shrink:0;margin-left:auto}.ui-sidebar__chevron{display:flex;align-items:center;flex-shrink:0;margin-left:auto;color:var(--color-text-subtle);transition:transform var(--transition-fast)}.ui-sidebar__chevron svg{width:20px;height:20px}.ui-sidebar__chevron--open{transform:rotate(180deg)}.ui-sidebar__children{display:flex;flex-direction:column;padding-left:var(--spacing-5);margin-top:var(--spacing-2);overflow:hidden}.ui-sidebar__child-wrap{display:flex;align-items:center;padding:0 var(--spacing-1-5);border-left:1px solid var(--color-border);width:100%}.ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}.ui-sidebar__child{display:flex;align-items:center;gap:var(--spacing-1-5);flex:1 0 0;width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-align:left;text-decoration:none;cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors);white-space:nowrap;overflow:hidden;min-width:0}.ui-sidebar__child:hover:not(.ui-sidebar__child--disabled):not(.ui-sidebar__child--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__child:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__child--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 6%,transparent)}.ui-sidebar__child--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}lucide-icon.ui-sidebar__child-icon{display:flex;align-items:center;flex-shrink:0;width:16px;height:16px;opacity:.6}lucide-icon.ui-sidebar__child-icon svg{width:100%;height:100%}.ui-sidebar__child-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-sidebar__footer{flex-shrink:0;padding:var(--spacing-2) var(--spacing-4);border-top:1px solid var(--color-border);z-index:1}.ui-sidebar--collapsed .ui-sidebar__footer{padding:var(--spacing-2)}.ui-sidebar__user{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);cursor:pointer;text-align:left;white-space:nowrap;overflow:hidden;transition:background-color var(--transition-colors)}.ui-sidebar__user:hover{background:var(--color-bg-subtle)}.ui-sidebar__user:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__user{justify-content:center;padding:var(--spacing-1-5)}.ui-sidebar__avatar{width:20px;height:20px;border-radius:var(--radius-full);object-fit:cover;flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar{width:24px;height:24px}.ui-sidebar__avatar-fallback{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:10px;font-weight:var(--font-semibold, 600);flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar-fallback{width:24px;height:24px;font-size:11px}.ui-sidebar__user-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__user-name{display:none}[data-theme=dark] .ui-sidebar{background:var(--color-neutral-950);border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__header{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__toggle{border-color:var(--color-neutral-700);color:var(--color-neutral-400)}[data-theme=dark] .ui-sidebar__toggle:hover{background:var(--color-neutral-800);color:var(--color-neutral-100);border-color:var(--color-neutral-600)}[data-theme=dark] .ui-sidebar__search{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__search:hover{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__kbd{background:var(--color-neutral-800);border-color:var(--color-neutral-600);color:var(--color-neutral-300)}[data-theme=dark] .ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__item--active{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__badge{background:var(--color-neutral-800);border-color:var(--color-neutral-700);color:var(--color-neutral-200)}[data-theme=dark] .ui-sidebar__child-wrap{border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}[data-theme=dark] .ui-sidebar__child:hover:not(.ui-sidebar__child--disabled){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__footer{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__user:hover{background:var(--color-neutral-800)}\n"] }]
4165
+ }], ctorParameters: () => [] });
4166
+
4167
+ // ============================================================
4168
+ // ORGANISMS — Nuxt UI v3 Design Kit → Angular 19 + NX
4169
+ // Complex components composed of atoms + molecules
4170
+ // ============================================================
4171
+
4172
+ // ============================================================
4173
+ // SHARED-UI PUBLIC API
4174
+ // NX Angular Library — Nuxt UI v3 Design Kit
4175
+ // Atomic Design: Atoms → Molecules → Organisms
4176
+ // ============================================================
4177
+ // ── Theme (ThemeService, provideSharedUiTheme, ThemePickerComponent, presets) ─
4178
+
4179
+ /**
4180
+ * Generated bundle index. Do not edit.
4181
+ */
4182
+
4183
+ export { AccordionComponent, AlertComponent, AvatarComponent, AvatarGroupComponent, BadgeComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COLOR_PRESETS, CardComponent, CheckboxComponent, ChipComponent, DropdownMenuComponent, FormFieldComponent, InputComponent, KbdComponent, LinkComponent, ModalComponent, NavigationMenuComponent, PaginationComponent, ProgressComponent, SelectComponent, SelectSearchComponent, SeparatorComponent, SidebarComponent, SkeletonComponent, SliderComponent, SwitchComponent, TableComponent, TabsComponent, TextareaComponent, ThemePickerComponent, ThemeService, ThemeToggleComponent, ToastComponent, TooltipComponent, UiTableCellDirective, getAllPresets, provideSharedUiTheme };
4184
+ //# sourceMappingURL=atomng-ui.mjs.map