@eifi1/ui-kit 0.4.0 → 0.5.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 (410) hide show
  1. package/LICENSE +32 -0
  2. package/README.md +498 -57
  3. package/dist/chart.d.ts +10 -0
  4. package/dist/chart.js +10 -0
  5. package/dist/chart.js.map +1 -0
  6. package/dist/components/account-settings.d.ts +11 -0
  7. package/dist/components/account-settings.js +19 -12
  8. package/dist/components/account-settings.js.map +1 -1
  9. package/dist/components/alert-banner.d.ts +10 -6
  10. package/dist/components/alert-banner.js +20 -16
  11. package/dist/components/alert-banner.js.map +1 -1
  12. package/dist/components/amount-input.d.ts +30 -4
  13. package/dist/components/amount-input.js +36 -14
  14. package/dist/components/amount-input.js.map +1 -1
  15. package/dist/components/calculator.d.ts +24 -7
  16. package/dist/components/calculator.js +37 -20
  17. package/dist/components/calculator.js.map +1 -1
  18. package/dist/components/chart-zoom.d.ts +156 -0
  19. package/dist/components/chart-zoom.js +262 -0
  20. package/dist/components/chart-zoom.js.map +1 -0
  21. package/dist/components/chart.d.ts +28 -3
  22. package/dist/components/chart.js +71 -32
  23. package/dist/components/chart.js.map +1 -1
  24. package/dist/components/checkbox.d.ts +51 -0
  25. package/dist/components/checkbox.js +123 -0
  26. package/dist/components/checkbox.js.map +1 -0
  27. package/dist/components/chip.d.ts +128 -0
  28. package/dist/components/chip.js +357 -0
  29. package/dist/components/chip.js.map +1 -0
  30. package/dist/components/choice-parts.d.ts +24 -0
  31. package/dist/components/choice-parts.js +18 -0
  32. package/dist/components/choice-parts.js.map +1 -0
  33. package/dist/components/combobox-core.d.ts +52 -9
  34. package/dist/components/combobox-core.js +91 -20
  35. package/dist/components/combobox-core.js.map +1 -1
  36. package/dist/components/combobox.d.ts +43 -33
  37. package/dist/components/combobox.js +409 -340
  38. package/dist/components/combobox.js.map +1 -1
  39. package/dist/components/currency-select.d.ts +48 -8
  40. package/dist/components/currency-select.js +107 -65
  41. package/dist/components/currency-select.js.map +1 -1
  42. package/dist/components/data-table-filter-popover.d.ts +15 -3
  43. package/dist/components/data-table-filter-popover.js +23 -17
  44. package/dist/components/data-table-filter-popover.js.map +1 -1
  45. package/dist/components/data-table-filters.d.ts +1 -1
  46. package/dist/components/data-table-filters.js +3 -2
  47. package/dist/components/data-table-filters.js.map +1 -1
  48. package/dist/components/data-table-labels.d.ts +53 -2
  49. package/dist/components/data-table-labels.js +31 -2
  50. package/dist/components/data-table-labels.js.map +1 -1
  51. package/dist/components/data-table-pagination.d.ts +3 -1
  52. package/dist/components/data-table-pagination.js +16 -10
  53. package/dist/components/data-table-pagination.js.map +1 -1
  54. package/dist/components/data-table-sort.js +1 -0
  55. package/dist/components/data-table-sort.js.map +1 -1
  56. package/dist/components/data-table.d.ts +1 -1
  57. package/dist/components/data-table.js +201 -85
  58. package/dist/components/data-table.js.map +1 -1
  59. package/dist/components/date-picker.d.ts +25 -9
  60. package/dist/components/date-picker.js +232 -94
  61. package/dist/components/date-picker.js.map +1 -1
  62. package/dist/components/dropdown.d.ts +96 -20
  63. package/dist/components/dropdown.js +77 -33
  64. package/dist/components/dropdown.js.map +1 -1
  65. package/dist/components/entity-combobox.d.ts +5 -4
  66. package/dist/components/entity-combobox.js +107 -76
  67. package/dist/components/entity-combobox.js.map +1 -1
  68. package/dist/components/facing-pair.d.ts +36 -0
  69. package/dist/components/facing-pair.js +40 -0
  70. package/dist/components/facing-pair.js.map +1 -0
  71. package/dist/components/field-sync.d.ts +164 -0
  72. package/dist/components/field-sync.js +264 -0
  73. package/dist/components/field-sync.js.map +1 -0
  74. package/dist/components/file-dropzone.d.ts +38 -6
  75. package/dist/components/file-dropzone.js +34 -9
  76. package/dist/components/file-dropzone.js.map +1 -1
  77. package/dist/components/full-bleed-dialog.d.ts +37 -26
  78. package/dist/components/full-bleed-dialog.js +20 -5
  79. package/dist/components/full-bleed-dialog.js.map +1 -1
  80. package/dist/components/grouped-picker.d.ts +21 -10
  81. package/dist/components/grouped-picker.js +66 -52
  82. package/dist/components/grouped-picker.js.map +1 -1
  83. package/dist/components/hover-menu.d.ts +20 -4
  84. package/dist/components/hover-menu.js +15 -4
  85. package/dist/components/hover-menu.js.map +1 -1
  86. package/dist/components/mini-calendar.d.ts +102 -14
  87. package/dist/components/mini-calendar.js +256 -70
  88. package/dist/components/mini-calendar.js.map +1 -1
  89. package/dist/components/modal.d.ts +9 -3
  90. package/dist/components/modal.js +34 -45
  91. package/dist/components/modal.js.map +1 -1
  92. package/dist/components/month-picker.d.ts +79 -0
  93. package/dist/components/month-picker.js +342 -0
  94. package/dist/components/month-picker.js.map +1 -0
  95. package/dist/components/multi-entity-combobox.d.ts +7 -6
  96. package/dist/components/multi-entity-combobox.js +112 -72
  97. package/dist/components/multi-entity-combobox.js.map +1 -1
  98. package/dist/components/multi-select.d.ts +13 -11
  99. package/dist/components/multi-select.js +161 -84
  100. package/dist/components/multi-select.js.map +1 -1
  101. package/dist/components/number-field.d.ts +92 -0
  102. package/dist/components/number-field.js +111 -0
  103. package/dist/components/number-field.js.map +1 -0
  104. package/dist/components/number-input.d.ts +28 -2
  105. package/dist/components/number-input.js +12 -2
  106. package/dist/components/number-input.js.map +1 -1
  107. package/dist/components/numpad-sheet.d.ts +32 -4
  108. package/dist/components/numpad-sheet.js +30 -13
  109. package/dist/components/numpad-sheet.js.map +1 -1
  110. package/dist/components/page-contents.d.ts +90 -0
  111. package/dist/components/page-contents.js +170 -0
  112. package/dist/components/page-contents.js.map +1 -0
  113. package/dist/components/password-strength.d.ts +106 -0
  114. package/dist/components/password-strength.js +132 -0
  115. package/dist/components/password-strength.js.map +1 -0
  116. package/dist/components/picker-sheet.d.ts +23 -15
  117. package/dist/components/picker-sheet.js +34 -14
  118. package/dist/components/picker-sheet.js.map +1 -1
  119. package/dist/components/popover.d.ts +62 -4
  120. package/dist/components/popover.js +52 -2
  121. package/dist/components/popover.js.map +1 -1
  122. package/dist/components/search-field.d.ts +25 -7
  123. package/dist/components/search-field.js +7 -5
  124. package/dist/components/search-field.js.map +1 -1
  125. package/dist/components/series-chart-labels.d.ts +14 -0
  126. package/dist/components/series-chart-labels.js +11 -0
  127. package/dist/components/series-chart-labels.js.map +1 -0
  128. package/dist/components/series-chart.d.ts +207 -0
  129. package/dist/components/series-chart.js +223 -0
  130. package/dist/components/series-chart.js.map +1 -0
  131. package/dist/components/settings-fields.d.ts +14 -4
  132. package/dist/components/settings-fields.js +19 -8
  133. package/dist/components/settings-fields.js.map +1 -1
  134. package/dist/components/signature-pad.d.ts +119 -0
  135. package/dist/components/signature-pad.js +405 -0
  136. package/dist/components/signature-pad.js.map +1 -0
  137. package/dist/components/slider.d.ts +80 -0
  138. package/dist/components/slider.js +155 -0
  139. package/dist/components/slider.js.map +1 -0
  140. package/dist/components/sparkline.d.ts +93 -0
  141. package/dist/components/sparkline.js +205 -0
  142. package/dist/components/sparkline.js.map +1 -0
  143. package/dist/components/stat-tile.d.ts +151 -0
  144. package/dist/components/stat-tile.js +236 -0
  145. package/dist/components/stat-tile.js.map +1 -0
  146. package/dist/components/swipeable-row.d.ts +25 -2
  147. package/dist/components/swipeable-row.js +31 -0
  148. package/dist/components/swipeable-row.js.map +1 -1
  149. package/dist/components/switch.d.ts +60 -0
  150. package/dist/components/switch.js +81 -0
  151. package/dist/components/switch.js.map +1 -0
  152. package/dist/components/time-input.d.ts +58 -0
  153. package/dist/components/time-input.js +50 -0
  154. package/dist/components/time-input.js.map +1 -0
  155. package/dist/components/toggle-group.d.ts +18 -3
  156. package/dist/components/toggle-group.js +10 -6
  157. package/dist/components/toggle-group.js.map +1 -1
  158. package/dist/components/toggle-legend.d.ts +115 -0
  159. package/dist/components/toggle-legend.js +114 -0
  160. package/dist/components/toggle-legend.js.map +1 -0
  161. package/dist/components/tooltip.d.ts +40 -11
  162. package/dist/components/tooltip.js +77 -20
  163. package/dist/components/tooltip.js.map +1 -1
  164. package/dist/components/treemap.d.ts +132 -0
  165. package/dist/components/treemap.js +179 -0
  166. package/dist/components/treemap.js.map +1 -0
  167. package/dist/components/ui.d.ts +159 -46
  168. package/dist/components/ui.js +220 -115
  169. package/dist/components/ui.js.map +1 -1
  170. package/dist/components/use-mobile-reveal.js +1 -0
  171. package/dist/components/use-mobile-reveal.js.map +1 -1
  172. package/dist/components/use-table-state.d.ts +1 -1
  173. package/dist/components/use-table-state.js +38 -17
  174. package/dist/components/use-table-state.js.map +1 -1
  175. package/dist/components/user-avatar.d.ts +15 -4
  176. package/dist/components/user-avatar.js +5 -4
  177. package/dist/components/user-avatar.js.map +1 -1
  178. package/dist/components/wizard-stepper.js +3 -2
  179. package/dist/components/wizard-stepper.js.map +1 -1
  180. package/dist/{data-table-filters-aXyf0Xub.d.ts → data-table-filters-DM1auUfH.d.ts} +27 -5
  181. package/dist/data-table.d.ts +7 -0
  182. package/dist/data-table.js +12 -0
  183. package/dist/data-table.js.map +1 -0
  184. package/dist/feedback/feedback-attachment.js +12 -11
  185. package/dist/feedback/feedback-attachment.js.map +1 -1
  186. package/dist/feedback/feedback-dialog.js +2 -1
  187. package/dist/feedback/feedback-dialog.js.map +1 -1
  188. package/dist/feedback/feedback-inbox.d.ts +33 -7
  189. package/dist/feedback/feedback-inbox.js +49 -37
  190. package/dist/feedback/feedback-inbox.js.map +1 -1
  191. package/dist/feedback.d.ts +5 -0
  192. package/dist/feedback.js +5 -0
  193. package/dist/feedback.js.map +1 -0
  194. package/dist/hooks/use-anchored-panel.js +1 -0
  195. package/dist/hooks/use-anchored-panel.js.map +1 -1
  196. package/dist/hooks/use-anchored-rect.js +1 -0
  197. package/dist/hooks/use-anchored-rect.js.map +1 -1
  198. package/dist/hooks/use-announce.d.ts +46 -0
  199. package/dist/hooks/use-announce.js +37 -0
  200. package/dist/hooks/use-announce.js.map +1 -0
  201. package/dist/hooks/use-body-scroll-lock.js +1 -0
  202. package/dist/hooks/use-body-scroll-lock.js.map +1 -1
  203. package/dist/hooks/use-close-transition.js +1 -0
  204. package/dist/hooks/use-close-transition.js.map +1 -1
  205. package/dist/hooks/use-dismiss.js +1 -0
  206. package/dist/hooks/use-dismiss.js.map +1 -1
  207. package/dist/hooks/use-focus-trap.d.ts +16 -0
  208. package/dist/hooks/use-focus-trap.js +67 -0
  209. package/dist/hooks/use-focus-trap.js.map +1 -0
  210. package/dist/hooks/use-media-query.js +1 -0
  211. package/dist/hooks/use-media-query.js.map +1 -1
  212. package/dist/hooks/use-overlay-history.js +27 -1
  213. package/dist/hooks/use-overlay-history.js.map +1 -1
  214. package/dist/hooks/use-row-swipe.js +1 -0
  215. package/dist/hooks/use-row-swipe.js.map +1 -1
  216. package/dist/i18n/defaults.d.ts +31 -0
  217. package/dist/i18n/defaults.js +63 -0
  218. package/dist/i18n/defaults.js.map +1 -0
  219. package/dist/i18n/kit-labels.d.ts +250 -0
  220. package/dist/i18n/kit-labels.js +184 -0
  221. package/dist/i18n/kit-labels.js.map +1 -0
  222. package/dist/index.d.ts +47 -22
  223. package/dist/index.js +28 -0
  224. package/dist/index.js.map +1 -1
  225. package/dist/lib/calc.js +1 -0
  226. package/dist/lib/calc.js.map +1 -1
  227. package/dist/lib/cn.js +1 -0
  228. package/dist/lib/cn.js.map +1 -1
  229. package/dist/lib/dates.js +1 -0
  230. package/dist/lib/dates.js.map +1 -1
  231. package/dist/lib/logger.js +1 -0
  232. package/dist/lib/logger.js.map +1 -1
  233. package/dist/lib/safe-storage.js +1 -0
  234. package/dist/lib/safe-storage.js.map +1 -1
  235. package/dist/search/command-palette.d.ts +11 -1
  236. package/dist/search/command-palette.js +21 -15
  237. package/dist/search/command-palette.js.map +1 -1
  238. package/dist/search.d.ts +2 -0
  239. package/dist/search.js +3 -0
  240. package/dist/search.js.map +1 -0
  241. package/dist/shell/app-shell.d.ts +33 -4
  242. package/dist/shell/app-shell.js +275 -78
  243. package/dist/shell/app-shell.js.map +1 -1
  244. package/dist/shell/option-switcher-menu.js +3 -2
  245. package/dist/shell/option-switcher-menu.js.map +1 -1
  246. package/dist/shell/role-switcher.d.ts +6 -0
  247. package/dist/shell/role-switcher.js +7 -4
  248. package/dist/shell/role-switcher.js.map +1 -1
  249. package/dist/shell/top-bar.d.ts +15 -7
  250. package/dist/shell/top-bar.js +3 -5
  251. package/dist/shell/top-bar.js.map +1 -1
  252. package/dist/shell/topbar-action-menu.js +3 -2
  253. package/dist/shell/topbar-action-menu.js.map +1 -1
  254. package/dist/shell/topbar-controls.d.ts +5 -2
  255. package/dist/shell/topbar-controls.js +20 -15
  256. package/dist/shell/topbar-controls.js.map +1 -1
  257. package/dist/shell.d.ts +13 -0
  258. package/dist/shell.js +8 -0
  259. package/dist/shell.js.map +1 -0
  260. package/dist/theme/chart-palette.d.ts +19 -12
  261. package/dist/theme/chart-palette.js +24 -30
  262. package/dist/theme/chart-palette.js.map +1 -1
  263. package/dist/theme/color.d.ts +78 -0
  264. package/dist/theme/color.js +148 -0
  265. package/dist/theme/color.js.map +1 -0
  266. package/dist/theme/palette-derive.d.ts +140 -0
  267. package/dist/theme/palette-derive.js +376 -0
  268. package/dist/theme/palette-derive.js.map +1 -0
  269. package/dist/theme/palette-presets.d.ts +27 -5
  270. package/dist/theme/palette-presets.js +231 -33
  271. package/dist/theme/palette-presets.js.map +1 -1
  272. package/dist/theme/palette-store.js +1 -0
  273. package/dist/theme/palette-store.js.map +1 -1
  274. package/dist/theme/theme-store.js +1 -0
  275. package/dist/theme/theme-store.js.map +1 -1
  276. package/dist/tour/tour.d.ts +2 -1
  277. package/dist/tour/tour.js +15 -9
  278. package/dist/tour/tour.js.map +1 -1
  279. package/dist/tour.d.ts +2 -0
  280. package/dist/tour.js +3 -0
  281. package/dist/tour.js.map +1 -0
  282. package/dist/wizard/stepper-nav.js +10 -8
  283. package/dist/wizard/stepper-nav.js.map +1 -1
  284. package/dist/wizard/types.d.ts +18 -2
  285. package/dist/wizard/types.js +4 -1
  286. package/dist/wizard/types.js.map +1 -1
  287. package/dist/wizard/use-wizard.js +12 -4
  288. package/dist/wizard/use-wizard.js.map +1 -1
  289. package/dist/wizard/validation.js +1 -0
  290. package/dist/wizard/validation.js.map +1 -1
  291. package/dist/wizard/wizard-context.js +1 -0
  292. package/dist/wizard/wizard-context.js.map +1 -1
  293. package/dist/wizard/wizard-step.js +1 -0
  294. package/dist/wizard/wizard-step.js.map +1 -1
  295. package/dist/wizard/wizard-summary.js +5 -3
  296. package/dist/wizard/wizard-summary.js.map +1 -1
  297. package/dist/wizard.d.ts +8 -0
  298. package/dist/wizard.js +9 -0
  299. package/dist/wizard.js.map +1 -0
  300. package/package.json +67 -14
  301. package/src/chart.ts +22 -0
  302. package/src/components/account-settings.tsx +275 -0
  303. package/src/components/alert-banner.tsx +75 -0
  304. package/src/components/amount-input.tsx +471 -0
  305. package/src/components/calculator.tsx +252 -0
  306. package/src/components/chart-zoom.tsx +499 -0
  307. package/src/components/chart.tsx +363 -0
  308. package/src/components/checkbox.tsx +222 -0
  309. package/src/components/chip.tsx +570 -0
  310. package/src/components/choice-parts.ts +33 -0
  311. package/src/components/combobox-core.tsx +540 -0
  312. package/src/components/combobox.tsx +1026 -0
  313. package/src/components/currency-select.tsx +269 -0
  314. package/src/components/data-table-filter-popover.tsx +252 -0
  315. package/src/components/data-table-filters.ts +176 -0
  316. package/src/components/data-table-labels.ts +190 -0
  317. package/src/components/data-table-pagination.tsx +126 -0
  318. package/src/components/data-table-sort.ts +70 -0
  319. package/src/components/data-table.tsx +1740 -0
  320. package/src/components/date-picker.tsx +631 -0
  321. package/src/components/dropdown.tsx +341 -0
  322. package/src/components/entity-combobox.tsx +215 -0
  323. package/src/components/facing-pair.ts +86 -0
  324. package/src/components/field-sync.tsx +472 -0
  325. package/src/components/file-dropzone.tsx +181 -0
  326. package/src/components/full-bleed-dialog.tsx +179 -0
  327. package/src/components/grouped-picker.tsx +157 -0
  328. package/src/components/hover-menu.tsx +183 -0
  329. package/src/components/mini-calendar.tsx +554 -0
  330. package/src/components/modal.tsx +287 -0
  331. package/src/components/month-picker.tsx +549 -0
  332. package/src/components/multi-entity-combobox.tsx +226 -0
  333. package/src/components/multi-select.tsx +303 -0
  334. package/src/components/number-field.tsx +225 -0
  335. package/src/components/number-input.tsx +211 -0
  336. package/src/components/numpad-sheet.tsx +264 -0
  337. package/src/components/page-contents.tsx +289 -0
  338. package/src/components/password-strength.tsx +258 -0
  339. package/src/components/picker-sheet.tsx +251 -0
  340. package/src/components/popover.tsx +195 -0
  341. package/src/components/search-field.tsx +146 -0
  342. package/src/components/series-chart-labels.ts +26 -0
  343. package/src/components/series-chart.tsx +481 -0
  344. package/src/components/settings-fields.tsx +68 -0
  345. package/src/components/signature-pad.tsx +630 -0
  346. package/src/components/slider.tsx +313 -0
  347. package/src/components/sparkline.tsx +329 -0
  348. package/src/components/stat-tile.tsx +448 -0
  349. package/src/components/swipeable-row.tsx +271 -0
  350. package/src/components/switch.tsx +170 -0
  351. package/src/components/time-input.tsx +107 -0
  352. package/src/components/toggle-group.tsx +153 -0
  353. package/src/components/toggle-legend.tsx +229 -0
  354. package/src/components/tooltip.tsx +477 -0
  355. package/src/components/treemap.tsx +390 -0
  356. package/src/components/ui.tsx +1284 -0
  357. package/src/components/use-mobile-reveal.ts +54 -0
  358. package/src/components/use-table-state.ts +295 -0
  359. package/src/components/user-avatar.tsx +61 -0
  360. package/src/components/wizard-stepper.tsx +37 -0
  361. package/src/data-table.ts +19 -0
  362. package/src/feedback/feedback-attachment.tsx +246 -0
  363. package/src/feedback/feedback-dialog.tsx +209 -0
  364. package/src/feedback/feedback-inbox.tsx +615 -0
  365. package/src/feedback.ts +8 -0
  366. package/src/hooks/use-anchored-panel.ts +169 -0
  367. package/src/hooks/use-anchored-rect.ts +78 -0
  368. package/src/hooks/use-announce.ts +85 -0
  369. package/src/hooks/use-body-scroll-lock.ts +94 -0
  370. package/src/hooks/use-close-transition.ts +99 -0
  371. package/src/hooks/use-dismiss.ts +77 -0
  372. package/src/hooks/use-focus-trap.ts +160 -0
  373. package/src/hooks/use-media-query.ts +23 -0
  374. package/src/hooks/use-overlay-history.ts +345 -0
  375. package/src/hooks/use-row-swipe.ts +212 -0
  376. package/src/i18n/defaults.ts +68 -0
  377. package/src/i18n/kit-labels.tsx +447 -0
  378. package/src/index.ts +169 -0
  379. package/src/lib/calc.ts +309 -0
  380. package/src/lib/cn.ts +5 -0
  381. package/src/lib/dates.ts +187 -0
  382. package/src/lib/logger.ts +73 -0
  383. package/src/lib/safe-storage.ts +37 -0
  384. package/src/search/command-palette.tsx +342 -0
  385. package/src/search.ts +3 -0
  386. package/src/shell/app-shell.tsx +772 -0
  387. package/src/shell/option-switcher-menu.tsx +72 -0
  388. package/src/shell/role-switcher.tsx +46 -0
  389. package/src/shell/top-bar.tsx +39 -0
  390. package/src/shell/topbar-action-menu.tsx +91 -0
  391. package/src/shell/topbar-controls.tsx +229 -0
  392. package/src/shell.ts +10 -0
  393. package/src/theme/chart-palette.ts +145 -0
  394. package/src/theme/color.ts +266 -0
  395. package/src/theme/palette-derive.ts +681 -0
  396. package/src/theme/palette-presets.ts +760 -0
  397. package/src/theme/palette-store.ts +94 -0
  398. package/src/theme/theme-store.ts +145 -0
  399. package/src/tour/tour.tsx +586 -0
  400. package/src/tour.ts +3 -0
  401. package/src/vite-env.d.ts +26 -0
  402. package/src/wizard/stepper-nav.tsx +221 -0
  403. package/src/wizard/types.ts +178 -0
  404. package/src/wizard/use-wizard.ts +345 -0
  405. package/src/wizard/validation.ts +37 -0
  406. package/src/wizard/wizard-context.tsx +29 -0
  407. package/src/wizard/wizard-step.tsx +14 -0
  408. package/src/wizard/wizard-summary.tsx +69 -0
  409. package/src/wizard.ts +14 -0
  410. package/tokens.css +222 -20
@@ -1,26 +1,23 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
3
  import { forwardRef, useId, useState } from "react";
3
4
  import { ChevronDown, Eye, EyeOff, HelpCircle } from "lucide-react";
4
5
  import { cn } from "../lib/cn.js";
5
6
  import { useMediaQuery } from "../hooks/use-media-query.js";
6
7
  import { Tooltip } from "./tooltip.js";
8
+ import { DEFAULT_COMMON_LABELS, useKitLabels } from "../i18n/kit-labels.js";
7
9
  const BUTTON_BASE = "inline-flex items-center justify-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 disabled:opacity-50 disabled:cursor-not-allowed";
8
10
  const buttonVariantClasses = {
9
11
  primary: "border border-[var(--border)] bg-[var(--bg-surface-2)] text-[var(--text-primary)] hover:bg-[var(--border)] focus:ring-[var(--brand)]",
10
12
  secondary: "border border-[var(--border)] bg-transparent text-[var(--text-primary)] hover:bg-[var(--bg-surface-2)] focus:ring-[var(--brand)]",
11
13
  ghost: "bg-transparent text-[var(--text-primary)] hover:bg-[var(--bg-surface-2)] focus:ring-[var(--brand)]",
12
- danger: "bg-red-600 text-white hover:bg-red-500 focus:ring-red-300",
14
+ danger: "bg-[var(--danger)] text-[var(--danger-contrast)] hover:bg-[var(--danger-hover)] focus:ring-[var(--danger-border)]",
13
15
  brand: "bg-[var(--brand)] text-[var(--brand-contrast)] hover:bg-[var(--brand-hover)] focus:ring-[var(--brand)]"
14
16
  };
15
17
  function buttonClasses(variant = "primary", className) {
16
18
  return cn(BUTTON_BASE, buttonVariantClasses[variant], className);
17
19
  }
18
- function Button({
19
- variant = "primary",
20
- stretch,
21
- className,
22
- ...rest
23
- }) {
20
+ function Button({ variant = "primary", stretch, className, ...rest }) {
24
21
  return /* @__PURE__ */ jsx(
25
22
  "button",
26
23
  {
@@ -54,46 +51,45 @@ const IconButton = forwardRef(function IconButton2({ variant = "ghost", size = "
54
51
  );
55
52
  });
56
53
  IconButton.displayName = "IconButton";
57
- const FIELD_BASE = "block w-full rounded-md border border-[var(--border)] bg-white px-3 py-2 text-sm text-slate-900 shadow-sm placeholder:text-slate-400 focus:border-[var(--brand)] focus:ring-[var(--brand)] dark:bg-slate-900 dark:text-slate-100 dark:placeholder:text-slate-500 disabled:cursor-default disabled:bg-slate-50 disabled:text-slate-500 dark:disabled:bg-slate-800/60 dark:disabled:text-slate-400 [&[readonly]]:bg-slate-50 [&[readonly]]:text-slate-500 dark:[&[readonly]]:bg-slate-800/60 dark:[&[readonly]]:text-slate-400";
58
- const FIELD_WRITABLE_LOOK = "[&[readonly]]:bg-white [&[readonly]]:text-slate-900 dark:[&[readonly]]:bg-slate-900 dark:[&[readonly]]:text-slate-100";
54
+ const FIELD_BASE = "block w-full rounded-md border border-[var(--border)] bg-[var(--bg-surface)] px-3 py-2 text-sm text-[var(--text-primary)] shadow-sm placeholder:text-[var(--text-placeholder)] focus:border-[var(--brand)] focus:ring-[var(--brand)] disabled:cursor-default disabled:bg-[var(--bg-surface-2)] disabled:text-[var(--text-muted)] [&[readonly]]:bg-[var(--bg-surface-2)] [&[readonly]]:text-[var(--text-muted)]";
55
+ const FIELD_WRITABLE_LOOK = "[&[readonly]]:bg-[var(--bg-surface)] [&[readonly]]:text-[var(--text-primary)]";
59
56
  const FIELD_FLOATING_PAD = "pt-4 pb-1";
60
- const FIELD_INVALID = "border-rose-400 ring-1 ring-rose-400 focus:border-rose-500 focus:ring-rose-500 dark:border-rose-500/80 dark:ring-rose-500/80 dark:focus:border-rose-400";
57
+ const FIELD_INVALID = "border-[var(--danger-border)] ring-1 ring-[var(--danger-border)] focus:border-[var(--danger)] focus:ring-[var(--danger)]";
61
58
  const FLOATING_INPUT_CLASS = cn(FIELD_BASE, FIELD_FLOATING_PAD, "peer placeholder:text-transparent");
62
59
  const PHONE_QUERY = "(max-width: 767px)";
63
- const FIELD_DISPLAY = "block w-full border-x-0 border-t-0 border-b border-[var(--border)] bg-transparent px-0 pt-0 pb-1 text-[var(--text-primary)] shadow-none placeholder:text-slate-400 focus:border-[var(--brand)] focus:outline-none focus:ring-0 disabled:opacity-60 dark:placeholder:text-slate-500";
60
+ const FIELD_DISPLAY = "block w-full border-x-0 border-t-0 border-b border-[var(--border)] bg-transparent px-0 pt-0 pb-1 text-[var(--text-primary)] shadow-none placeholder:text-[var(--text-placeholder)] focus:border-[var(--brand)] focus:outline-none focus:ring-0 disabled:opacity-60";
64
61
  const FIELD_TRIGGER = cn(
65
62
  FIELD_BASE,
66
- "relative flex items-center justify-between gap-2 text-left hover:bg-slate-50 dark:hover:bg-slate-800"
63
+ "relative flex items-center justify-between gap-2 text-left hover:bg-[var(--bg-hover)]"
67
64
  );
68
- function FieldChevron({ className }) {
65
+ function FieldChevron({ className, ...rest }) {
69
66
  return /* @__PURE__ */ jsx(
70
67
  ChevronDown,
71
68
  {
69
+ ...rest,
72
70
  "aria-hidden": true,
73
71
  className: cn(
74
- "pointer-events-none absolute right-2.5 top-1/2 size-4 -translate-y-1/2 text-slate-400 dark:text-slate-500",
72
+ "pointer-events-none absolute right-2.5 top-1/2 size-4 -translate-y-1/2 text-[var(--text-placeholder)]",
75
73
  className
76
74
  )
77
75
  }
78
76
  );
79
77
  }
80
78
  const FLOATING_LABEL_CLASS = cn(
81
- "pointer-events-none absolute left-3 top-2.5 text-sm text-slate-400 transition-all",
79
+ "pointer-events-none absolute left-3 top-2.5 text-sm text-[var(--text-placeholder)] transition-all",
82
80
  "max-w-[calc(100%-1.5rem)] truncate",
83
- "peer-focus:top-1 peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-slate-600",
84
- "peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-[11px] peer-[:not(:placeholder-shown)]:leading-tight peer-[:not(:placeholder-shown)]:text-slate-600",
85
- "dark:text-slate-500 dark:peer-focus:text-slate-300 dark:peer-[:not(:placeholder-shown)]:text-slate-300",
81
+ "peer-focus:top-1 peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-[var(--text-secondary)]",
82
+ "peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-[11px] peer-[:not(:placeholder-shown)]:leading-tight peer-[:not(:placeholder-shown)]:text-[var(--text-secondary)]",
86
83
  "peer-disabled:opacity-50"
87
84
  );
88
85
  const FLOATING_ROW_CLASS = cn(
89
86
  "pointer-events-none absolute left-3 top-2.5 flex items-center gap-1 transition-all",
90
- "max-w-[calc(100%-3rem)] text-sm text-slate-400",
91
- "peer-focus:top-1 peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-slate-600",
92
- "peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-[11px] peer-[:not(:placeholder-shown)]:leading-tight peer-[:not(:placeholder-shown)]:text-slate-600",
93
- "dark:text-slate-500 dark:peer-focus:text-slate-300 dark:peer-[:not(:placeholder-shown)]:text-slate-300",
87
+ "max-w-[calc(100%-3rem)] text-sm text-[var(--text-placeholder)]",
88
+ "peer-focus:top-1 peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-[var(--text-secondary)]",
89
+ "peer-[:not(:placeholder-shown)]:top-1 peer-[:not(:placeholder-shown)]:text-[11px] peer-[:not(:placeholder-shown)]:leading-tight peer-[:not(:placeholder-shown)]:text-[var(--text-secondary)]",
94
90
  "peer-disabled:opacity-50"
95
91
  );
96
- const STATIC_LABEL_TYPE = "text-[11px] leading-tight text-slate-500 dark:text-slate-400 peer-disabled:opacity-50";
92
+ const STATIC_LABEL_TYPE = "text-[11px] leading-tight text-[var(--text-muted)] peer-disabled:opacity-50";
97
93
  const FLOATING_LABEL_STATIC = cn(
98
94
  "pointer-events-none absolute left-3 top-1",
99
95
  STATIC_LABEL_TYPE,
@@ -106,7 +102,8 @@ function FloatingField({
106
102
  staticLabel,
107
103
  srOnlyLabel,
108
104
  hint,
109
- children
105
+ children,
106
+ ...rest
110
107
  }) {
111
108
  const withHint = hint !== void 0 && !srOnlyLabel;
112
109
  const atEnd = withHint && staticLabel;
@@ -118,46 +115,105 @@ function FloatingField({
118
115
  children: label
119
116
  }
120
117
  );
121
- return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
122
- children,
123
- withHint ? (
124
- // Static: `inset-x-3` rather than `left-3`, so a long label truncates at
125
- // the field's own right padding instead of running under the chevron.
126
- // Animated: the row floats with the label and is only as wide as it needs
127
- // to be. Either way the hint keeps its width (`shrink-0`) and the label
128
- // is the one that gives way.
129
- /* @__PURE__ */ jsxs(
130
- "div",
131
- {
132
- className: atEnd ? "pointer-events-none absolute inset-x-3 top-1 flex items-center gap-1" : FLOATING_ROW_CLASS,
133
- children: [
134
- labelEl,
135
- /* @__PURE__ */ jsx("span", { className: "pointer-events-auto flex shrink-0 items-center", children: hint })
136
- ]
137
- }
138
- )
139
- ) : labelEl
140
- ] });
118
+ return (
119
+ // `relative` is the whole contract of this wrapper — the floating label and every
120
+ // control that hangs off it (a reveal toggle, a chevron) are positioned against
121
+ // this box — so it is merged through `cn` after the spread rather than left where
122
+ // a caller's stray `className` or `style` could unset it.
123
+ /* @__PURE__ */ jsxs("div", { ...rest, className: cn("relative", className), children: [
124
+ children,
125
+ withHint ? (
126
+ // Static: `inset-x-3` rather than `left-3`, so a long label truncates at
127
+ // the field's own right padding instead of running under the chevron.
128
+ // Animated: the row floats with the label and is only as wide as it needs
129
+ // to be. Either way the hint keeps its width (`shrink-0`) and the label
130
+ // is the one that gives way.
131
+ /* @__PURE__ */ jsxs(
132
+ "div",
133
+ {
134
+ className: atEnd ? "pointer-events-none absolute inset-x-3 top-1 flex items-center gap-1" : FLOATING_ROW_CLASS,
135
+ children: [
136
+ labelEl,
137
+ /* @__PURE__ */ jsx("span", { className: "pointer-events-auto flex shrink-0 items-center", children: hint })
138
+ ]
139
+ }
140
+ )
141
+ ) : labelEl
142
+ ] })
143
+ );
141
144
  }
142
- function FieldHint({ label, side = "left" }) {
145
+ function FieldHint({
146
+ label,
147
+ side = "left",
148
+ className,
149
+ "aria-label": ariaLabel,
150
+ ...rest
151
+ }) {
143
152
  return /* @__PURE__ */ jsx(Tooltip, { label, side, portal: true, children: /* @__PURE__ */ jsx(
144
153
  "button",
145
154
  {
155
+ ...rest,
146
156
  type: "button",
147
- "aria-label": label,
157
+ "aria-label": ariaLabel ?? label,
148
158
  onClick: (e) => e.preventDefault(),
149
- className: "flex text-slate-400 transition-colors hover:text-slate-600 dark:hover:text-slate-200",
159
+ className: cn(
160
+ "flex text-[var(--text-placeholder)] transition-colors hover:text-[var(--text-secondary)]",
161
+ className
162
+ ),
150
163
  children: /* @__PURE__ */ jsx(HelpCircle, { className: "size-3.5" })
151
164
  }
152
165
  ) });
153
166
  }
154
- function FieldLabel({ children, className }) {
155
- return /* @__PURE__ */ jsx("span", { className: cn(FLOATING_LABEL_STATIC, "z-10", className), children });
167
+ function FieldLabel({ children, className, ...rest }) {
168
+ return /* @__PURE__ */ jsx("span", { ...rest, className: cn(FLOATING_LABEL_STATIC, "z-10", className), children });
169
+ }
170
+ const FIELD_ERROR_CLASS = "mt-1 text-[11px] leading-tight text-[var(--danger)]";
171
+ function useFieldError(error, invalid, describedBy) {
172
+ const errorId = useId();
173
+ const hasError = error !== void 0 && error !== null && error !== false && error !== "";
174
+ return {
175
+ /** A field carrying a message that says what is wrong with it IS wrong. */
176
+ isInvalid: Boolean(invalid) || hasError,
177
+ describedBy: hasError ? describedBy ? `${describedBy} ${errorId}` : errorId : describedBy,
178
+ errorEl: hasError ? /* @__PURE__ */ jsx("p", { id: errorId, className: FIELD_ERROR_CLASS, children: error }) : null
179
+ };
180
+ }
181
+ function FieldGroup({ errorEl, children }) {
182
+ if (errorEl === null) return /* @__PURE__ */ jsx(Fragment, { children });
183
+ return /* @__PURE__ */ jsxs("div", { children: [
184
+ children,
185
+ errorEl
186
+ ] });
187
+ }
188
+ const DEFAULT_PASSWORD_REVEAL_LABELS = {
189
+ show: "Show password",
190
+ hide: "Hide password"
191
+ };
192
+ function resolvePasswordRevealLabels(partial) {
193
+ if (!partial) return DEFAULT_PASSWORD_REVEAL_LABELS;
194
+ return { ...DEFAULT_PASSWORD_REVEAL_LABELS, ...partial };
156
195
  }
157
196
  const PICKER_TYPES = /* @__PURE__ */ new Set(["date", "datetime-local", "month", "time", "week"]);
158
- const Input = forwardRef(function Input2({ className, inputClassName, label, id, placeholder, type, variant = "field", invalid, ...rest }, ref) {
197
+ const Input = forwardRef(function Input2({
198
+ className,
199
+ inputClassName,
200
+ label,
201
+ id,
202
+ placeholder,
203
+ type,
204
+ variant = "field",
205
+ invalid,
206
+ error,
207
+ passwordLabels,
208
+ ...rest
209
+ }, ref) {
159
210
  const generated = useId();
160
211
  const fieldId = id ?? generated;
212
+ const { isInvalid, describedBy, errorEl } = useFieldError(
213
+ error,
214
+ invalid,
215
+ rest["aria-describedby"]
216
+ );
161
217
  const asDisplay = useMediaQuery(PHONE_QUERY, false) && variant === "display";
162
218
  const isPassword = type === "password";
163
219
  const [revealed, setRevealed] = useState(false);
@@ -169,21 +225,22 @@ const Input = forwardRef(function Input2({ className, inputClassName, label, id,
169
225
  } catch {
170
226
  }
171
227
  } : rest.onClick;
228
+ const passwordText = useKitLabels("passwordReveal", DEFAULT_PASSWORD_REVEAL_LABELS, passwordLabels);
172
229
  const revealToggle = isPassword ? /* @__PURE__ */ jsx(
173
230
  "button",
174
231
  {
175
232
  type: "button",
176
- tabIndex: -1,
177
233
  onClick: () => setRevealed((v) => !v),
178
- "aria-label": revealed ? "Hide password" : "Show password",
234
+ disabled: rest.disabled,
235
+ "aria-label": revealed ? passwordText.hide : passwordText.show,
179
236
  "aria-pressed": revealed,
180
- className: "absolute inset-y-0 right-0 flex items-center px-2.5 text-slate-400 hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-300",
237
+ className: "absolute inset-y-0 right-0 flex items-center rounded-r-md px-2.5 text-[var(--text-placeholder)] transition-colors hover:text-[var(--text-secondary)] focus:outline-none focus:ring-2 focus:ring-[var(--brand)] disabled:cursor-default disabled:opacity-50",
181
238
  children: revealed ? /* @__PURE__ */ jsx(EyeOff, { className: "size-4" }) : /* @__PURE__ */ jsx(Eye, { className: "size-4" })
182
239
  }
183
240
  ) : null;
184
241
  if (label === void 0) {
185
242
  if (!isPassword) {
186
- return /* @__PURE__ */ jsx(
243
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsx(
187
244
  "input",
188
245
  {
189
246
  ref,
@@ -191,13 +248,14 @@ const Input = forwardRef(function Input2({ className, inputClassName, label, id,
191
248
  type,
192
249
  placeholder,
193
250
  ...rest,
194
- "aria-invalid": invalid || rest["aria-invalid"] || void 0,
251
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
252
+ "aria-describedby": describedBy,
195
253
  onClick: handleClick,
196
- className: cn(FIELD_BASE, className, inputClassName, invalid && FIELD_INVALID)
254
+ className: cn(FIELD_BASE, className, inputClassName, isInvalid && FIELD_INVALID)
197
255
  }
198
- );
256
+ ) });
199
257
  }
200
- return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
258
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
201
259
  /* @__PURE__ */ jsx(
202
260
  "input",
203
261
  {
@@ -206,14 +264,15 @@ const Input = forwardRef(function Input2({ className, inputClassName, label, id,
206
264
  type: effectiveType,
207
265
  placeholder,
208
266
  ...rest,
209
- "aria-invalid": invalid || rest["aria-invalid"] || void 0,
210
- className: cn(FIELD_BASE, "pr-9", inputClassName, invalid && FIELD_INVALID)
267
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
268
+ "aria-describedby": describedBy,
269
+ className: cn(FIELD_BASE, "pr-9", inputClassName, isInvalid && FIELD_INVALID)
211
270
  }
212
271
  ),
213
272
  revealToggle
214
- ] });
273
+ ] }) });
215
274
  }
216
- return /* @__PURE__ */ jsxs(FloatingField, { className, htmlFor: fieldId, label, srOnlyLabel: asDisplay, children: [
275
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsxs(FloatingField, { className, htmlFor: fieldId, label, srOnlyLabel: asDisplay, children: [
217
276
  /* @__PURE__ */ jsx(
218
277
  "input",
219
278
  {
@@ -222,97 +281,110 @@ const Input = forwardRef(function Input2({ className, inputClassName, label, id,
222
281
  type: effectiveType,
223
282
  placeholder: asDisplay ? placeholder ?? (typeof label === "string" ? label : " ") : " ",
224
283
  ...rest,
225
- "aria-invalid": invalid || rest["aria-invalid"] || void 0,
284
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
285
+ "aria-describedby": describedBy,
226
286
  onClick: handleClick,
227
287
  className: cn(
228
288
  asDisplay ? cn(FIELD_DISPLAY, "text-xl font-semibold leading-snug") : FLOATING_INPUT_CLASS,
229
289
  isPassword && "pr-9",
230
290
  inputClassName,
231
- invalid && FIELD_INVALID
291
+ isInvalid && FIELD_INVALID
232
292
  )
233
293
  }
234
294
  ),
235
295
  revealToggle
236
- ] });
296
+ ] }) });
237
297
  });
238
298
  Input.displayName = "Input";
239
- const Select = forwardRef(function Select2({ className, label, id, children, invalid, hint, ...rest }, ref) {
299
+ const Select = forwardRef(function Select2({ className, label, id, children, invalid, error, hint, ...rest }, ref) {
240
300
  const generated = useId();
241
301
  const fieldId = id ?? generated;
302
+ const { isInvalid, describedBy, errorEl } = useFieldError(
303
+ error,
304
+ invalid,
305
+ rest["aria-describedby"]
306
+ );
242
307
  const chevron = rest.disabled ? null : /* @__PURE__ */ jsx(FieldChevron, {});
243
308
  if (label === void 0) {
244
- return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
309
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
245
310
  /* @__PURE__ */ jsx(
246
311
  "select",
247
312
  {
248
313
  ref,
314
+ id,
249
315
  ...rest,
250
- "aria-invalid": invalid || void 0,
251
- className: cn(FIELD_BASE, "appearance-none pr-9", invalid && FIELD_INVALID),
316
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
317
+ "aria-describedby": describedBy,
318
+ className: cn(FIELD_BASE, "appearance-none pr-9", isInvalid && FIELD_INVALID),
252
319
  children
253
320
  }
254
321
  ),
255
322
  chevron
256
- ] });
323
+ ] }) });
257
324
  }
258
- return /* @__PURE__ */ jsxs(FloatingField, { className, htmlFor: fieldId, label, staticLabel: true, hint, children: [
325
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsxs(FloatingField, { className, htmlFor: fieldId, label, staticLabel: true, hint, children: [
259
326
  /* @__PURE__ */ jsx(
260
327
  "select",
261
328
  {
262
329
  ref,
263
330
  id: fieldId,
264
331
  ...rest,
265
- "aria-invalid": invalid || void 0,
332
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
333
+ "aria-describedby": describedBy,
266
334
  className: cn(
267
335
  FIELD_BASE,
268
336
  FIELD_FLOATING_PAD,
269
337
  "peer appearance-none pr-9",
270
- invalid && FIELD_INVALID
338
+ isInvalid && FIELD_INVALID
271
339
  ),
272
340
  children
273
341
  }
274
342
  ),
275
343
  chevron
276
- ] });
344
+ ] }) });
277
345
  });
278
346
  Select.displayName = "Select";
279
- const Textarea = forwardRef(function Textarea2({ className, label, id, placeholder, invalid, ...rest }, ref) {
347
+ const Textarea = forwardRef(function Textarea2({ className, label, id, placeholder, invalid, error, ...rest }, ref) {
280
348
  const generated = useId();
281
349
  const fieldId = id ?? generated;
350
+ const { isInvalid, describedBy, errorEl } = useFieldError(
351
+ error,
352
+ invalid,
353
+ rest["aria-describedby"]
354
+ );
282
355
  if (label === void 0) {
283
- return /* @__PURE__ */ jsx(
356
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsx(
284
357
  "textarea",
285
358
  {
286
359
  ref,
287
360
  id,
288
361
  placeholder,
289
362
  ...rest,
290
- "aria-invalid": invalid || rest["aria-invalid"] || void 0,
291
- className: cn(FIELD_BASE, className, invalid && FIELD_INVALID)
363
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
364
+ "aria-describedby": describedBy,
365
+ className: cn(FIELD_BASE, className, isInvalid && FIELD_INVALID)
292
366
  }
293
- );
367
+ ) });
294
368
  }
295
- return /* @__PURE__ */ jsx(FloatingField, { className, htmlFor: fieldId, label, children: /* @__PURE__ */ jsx(
369
+ return /* @__PURE__ */ jsx(FieldGroup, { errorEl, children: /* @__PURE__ */ jsx(FloatingField, { className, htmlFor: fieldId, label, children: /* @__PURE__ */ jsx(
296
370
  "textarea",
297
371
  {
298
372
  ref,
299
373
  id: fieldId,
300
374
  placeholder: " ",
301
375
  ...rest,
302
- "aria-invalid": invalid || rest["aria-invalid"] || void 0,
303
- className: cn(FLOATING_INPUT_CLASS, invalid && FIELD_INVALID)
376
+ "aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
377
+ "aria-describedby": describedBy,
378
+ className: cn(FLOATING_INPUT_CLASS, isInvalid && FIELD_INVALID)
304
379
  }
305
- ) });
380
+ ) }) });
306
381
  });
307
382
  Textarea.displayName = "Textarea";
308
- function Card({
309
- className,
310
- children,
311
- flush
312
- }) {
383
+ function Card({ className, children, flush, ...rest }) {
313
384
  return /* @__PURE__ */ jsx(
314
385
  "div",
315
386
  {
387
+ ...rest,
316
388
  className: cn(
317
389
  // Surface + border are theme tokens so the palette switcher (feedback
318
390
  // #307) can re-skin every card; a caller's own bg-*/border-* override
@@ -383,50 +455,63 @@ function CardFooter({ className, ...props }) {
383
455
  }
384
456
  );
385
457
  }
386
- function Spinner({ className }) {
458
+ function Spinner({ className, label, ...rest }) {
459
+ const common = useKitLabels("common", DEFAULT_COMMON_LABELS, { loading: label });
387
460
  return /* @__PURE__ */ jsx(
388
461
  "span",
389
462
  {
463
+ role: "status",
464
+ ...rest,
390
465
  className: cn(
391
- "inline-block h-5 w-5 animate-spin rounded-full border-2 border-slate-300 border-t-slate-700 dark:border-slate-700 dark:border-t-slate-200",
466
+ "relative inline-block h-5 w-5 animate-spin rounded-full border-2 border-[var(--border)] border-t-[var(--text-primary)]",
392
467
  className
393
- )
468
+ ),
469
+ children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: common.loading })
394
470
  }
395
471
  );
396
472
  }
397
- function EmptyState({
398
- title,
399
- hint,
400
- className
401
- }) {
473
+ function EmptyState({ title, hint, className, ...rest }) {
402
474
  return /* @__PURE__ */ jsxs(
403
475
  "div",
404
476
  {
477
+ ...rest,
405
478
  className: cn(
406
- "flex flex-col items-center justify-center rounded-lg border border-dashed border-slate-300 bg-slate-50/50 px-4 py-10 text-center text-sm text-slate-500 dark:border-slate-700 dark:bg-slate-900/40 dark:text-slate-400",
479
+ "flex flex-col items-center justify-center rounded-lg border border-dashed border-[var(--border-strong)] bg-[var(--bg-surface-2)] px-4 py-10 text-center text-sm text-[var(--text-muted)]",
407
480
  className
408
481
  ),
409
482
  children: [
410
- /* @__PURE__ */ jsx("div", { className: "font-medium text-slate-700 dark:text-slate-200", children: title }),
483
+ /* @__PURE__ */ jsx("div", { className: "font-medium text-[var(--text-secondary)]", children: title }),
411
484
  hint && /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs", children: hint })
412
485
  ]
413
486
  }
414
487
  );
415
488
  }
416
- const TABLIST_CLASSES = "flex gap-1 overflow-x-auto overflow-y-hidden border-b border-slate-200 dark:border-slate-800";
417
- const TABLIST_WRAP_CLASSES = "flex flex-wrap gap-1.5 md:flex-nowrap md:gap-1 md:overflow-x-auto md:overflow-y-hidden md:border-b md:border-slate-200 md:dark:border-slate-800";
418
- const TAB_CLASSES = "whitespace-nowrap px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px focus:outline-none focus:ring-2 focus:ring-slate-300";
419
- const TAB_ACTIVE_CLASSES = "border-slate-900 text-slate-900 dark:border-slate-100 dark:text-slate-100";
420
- const TAB_INACTIVE_CLASSES = "border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300 dark:text-slate-400 dark:hover:text-slate-200";
421
- const TAB_WRAP_CLASSES = "whitespace-nowrap rounded-md px-2.5 py-2 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-slate-300 md:rounded-none md:border-b-2 md:-mb-px md:bg-transparent md:px-3 md:py-2 md:text-sm";
422
- const TAB_WRAP_ACTIVE_CLASSES = "bg-[var(--brand)] text-[var(--brand-contrast)] md:border-slate-900 md:text-slate-900 md:dark:border-slate-100 md:dark:text-slate-100";
423
- const TAB_WRAP_INACTIVE_CLASSES = "bg-[var(--bg-surface)] text-[var(--text-primary)] md:border-transparent md:text-slate-500 md:hover:border-slate-300 md:hover:text-slate-700 md:dark:text-slate-400 md:dark:hover:text-slate-200";
424
- function Tabs({ tabs, active, onChange, className, wrap = false, label }) {
425
- const onListKeyDown = (e) => {
489
+ const TABLIST_CLASSES = "flex gap-1 overflow-x-auto overflow-y-hidden border-b border-[var(--border)]";
490
+ const TABLIST_WRAP_CLASSES = "flex flex-wrap gap-1.5 md:flex-nowrap md:gap-1 md:overflow-x-auto md:overflow-y-hidden md:border-b md:border-[var(--border)]";
491
+ const TAB_CLASSES = "whitespace-nowrap px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px focus:outline-none focus:ring-2 focus:ring-[var(--border-strong)]";
492
+ const TAB_ACTIVE_CLASSES = "border-[var(--text-primary)] text-[var(--text-primary)]";
493
+ const TAB_INACTIVE_CLASSES = "border-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:border-[var(--border-strong)]";
494
+ const TAB_WRAP_CLASSES = "whitespace-nowrap rounded-md px-2.5 py-2 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--border-strong)] md:rounded-none md:border-b-2 md:-mb-px md:bg-transparent md:px-3 md:py-2 md:text-sm";
495
+ const TAB_WRAP_ACTIVE_CLASSES = "bg-[var(--brand)] text-[var(--brand-contrast)] md:border-[var(--text-primary)] md:text-[var(--text-primary)]";
496
+ const TAB_WRAP_INACTIVE_CLASSES = "bg-[var(--bg-surface)] text-[var(--text-primary)] md:border-transparent md:text-[var(--text-muted)] md:hover:border-[var(--border-strong)] md:hover:text-[var(--text-secondary)]";
497
+ function Tabs({
498
+ tabs,
499
+ active,
500
+ onChange,
501
+ className,
502
+ wrap = false,
503
+ label,
504
+ panelId,
505
+ "aria-label": ariaLabel,
506
+ ...rest
507
+ }) {
508
+ const onTabKeyDown = (e) => {
426
509
  const step = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : 0;
427
510
  if (step === 0 && e.key !== "Home" && e.key !== "End") return;
428
- const items = Array.from(e.currentTarget.querySelectorAll('[role="tab"]'));
429
- const from = items.indexOf(document.activeElement);
511
+ const strip = e.currentTarget.closest('[role="tablist"]');
512
+ if (!strip) return;
513
+ const items = Array.from(strip.querySelectorAll('[role="tab"]'));
514
+ const from = items.indexOf(e.currentTarget);
430
515
  if (from === -1) return;
431
516
  e.preventDefault();
432
517
  const to = e.key === "Home" ? 0 : e.key === "End" ? items.length - 1 : (from + step + items.length) % items.length;
@@ -435,15 +520,32 @@ function Tabs({ tabs, active, onChange, className, wrap = false, label }) {
435
520
  return /* @__PURE__ */ jsx(
436
521
  "div",
437
522
  {
523
+ ...rest,
438
524
  role: "tablist",
439
- "aria-label": label,
440
- onKeyDown: onListKeyDown,
525
+ "aria-label": ariaLabel ?? label,
441
526
  className: cn(wrap ? TABLIST_WRAP_CLASSES : TABLIST_CLASSES, className),
442
527
  children: tabs.map((tab) => {
443
528
  const isActive = tab.id === active;
444
529
  const shared = {
445
530
  role: "tab",
446
531
  "aria-selected": isActive,
532
+ // Roving tabindex: the whole strip is ONE stop in the page's tab order, and
533
+ // it is the open tab. Ten report tabs otherwise cost ten Tab presses to step
534
+ // over on the way to the table below them (live #262's strip is the extreme
535
+ // case, but every strip in the app paid it).
536
+ //
537
+ // The stop follows the SELECTION, not the focus. Arrowing is a look around —
538
+ // activation here is manual, because a tab can be a real route — so re-
539
+ // pointing the stop at a report the user only arrowed past would hand the
540
+ // strip back on the next visit in a state they never chose. The cost is that
541
+ // Tab out and back returns to the open tab rather than to the last one
542
+ // looked at; the ARIA pattern allows either, and this one needs no second
543
+ // piece of state shadowing `active`.
544
+ tabIndex: isActive ? 0 : -1,
545
+ // Only the open tab: see `panelId`.
546
+ "aria-controls": isActive ? panelId : void 0,
547
+ id: isActive && panelId ? `${panelId}-tab` : void 0,
548
+ onKeyDown: onTabKeyDown,
447
549
  className: cn(
448
550
  wrap ? TAB_WRAP_CLASSES : TAB_CLASSES,
449
551
  wrap ? isActive ? TAB_WRAP_ACTIVE_CLASSES : TAB_WRAP_INACTIVE_CLASSES : isActive ? TAB_ACTIVE_CLASSES : TAB_INACTIVE_CLASSES
@@ -465,7 +567,8 @@ function Tabs({ tabs, active, onChange, className, wrap = false, label }) {
465
567
  onChange(tab.id);
466
568
  },
467
569
  onKeyDown: (e) => {
468
- if (e.key !== " ") return;
570
+ onTabKeyDown(e);
571
+ if (e.defaultPrevented || e.key !== " ") return;
469
572
  e.preventDefault();
470
573
  onChange(tab.id);
471
574
  },
@@ -486,6 +589,7 @@ export {
486
589
  CardFooter,
487
590
  CardHeader,
488
591
  CardTitle,
592
+ DEFAULT_PASSWORD_REVEAL_LABELS,
489
593
  EmptyState,
490
594
  FIELD_BASE,
491
595
  FIELD_DISPLAY,
@@ -507,6 +611,7 @@ export {
507
611
  Spinner,
508
612
  Tabs,
509
613
  Textarea,
510
- buttonClasses
614
+ buttonClasses,
615
+ resolvePasswordRevealLabels
511
616
  };
512
617
  //# sourceMappingURL=ui.js.map