@eifi1/ui-kit 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) 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 +142 -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 +89 -19
  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 +115 -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 +244 -94
  61. package/dist/components/date-picker.js.map +1 -1
  62. package/dist/components/dropdown.d.ts +74 -19
  63. package/dist/components/dropdown.js +72 -22
  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 +21 -7
  75. package/dist/components/file-dropzone.js +28 -7
  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 +353 -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 +21 -2
  105. package/dist/components/number-input.js +2 -1
  106. package/dist/components/number-input.js.map +1 -1
  107. package/dist/components/numpad-sheet.d.ts +25 -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 +55 -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/trigger-aria.d.ts +18 -0
  168. package/dist/components/trigger-aria.js +25 -0
  169. package/dist/components/trigger-aria.js.map +1 -0
  170. package/dist/components/ui.d.ts +167 -46
  171. package/dist/components/ui.js +225 -121
  172. package/dist/components/ui.js.map +1 -1
  173. package/dist/components/use-mobile-reveal.js +1 -0
  174. package/dist/components/use-mobile-reveal.js.map +1 -1
  175. package/dist/components/use-table-state.d.ts +1 -1
  176. package/dist/components/use-table-state.js +38 -17
  177. package/dist/components/use-table-state.js.map +1 -1
  178. package/dist/components/user-avatar.d.ts +5 -3
  179. package/dist/components/user-avatar.js +4 -2
  180. package/dist/components/user-avatar.js.map +1 -1
  181. package/dist/components/wizard-stepper.js +3 -2
  182. package/dist/components/wizard-stepper.js.map +1 -1
  183. package/dist/{data-table-filters-aXyf0Xub.d.ts → data-table-filters-DM1auUfH.d.ts} +27 -5
  184. package/dist/data-table.d.ts +7 -0
  185. package/dist/data-table.js +12 -0
  186. package/dist/data-table.js.map +1 -0
  187. package/dist/feedback/feedback-attachment.js +12 -11
  188. package/dist/feedback/feedback-attachment.js.map +1 -1
  189. package/dist/feedback/feedback-dialog.js +2 -1
  190. package/dist/feedback/feedback-dialog.js.map +1 -1
  191. package/dist/feedback/feedback-inbox.d.ts +33 -7
  192. package/dist/feedback/feedback-inbox.js +49 -37
  193. package/dist/feedback/feedback-inbox.js.map +1 -1
  194. package/dist/feedback.d.ts +5 -0
  195. package/dist/feedback.js +5 -0
  196. package/dist/feedback.js.map +1 -0
  197. package/dist/hooks/use-anchored-panel.js +1 -0
  198. package/dist/hooks/use-anchored-panel.js.map +1 -1
  199. package/dist/hooks/use-anchored-rect.js +1 -0
  200. package/dist/hooks/use-anchored-rect.js.map +1 -1
  201. package/dist/hooks/use-announce.d.ts +46 -0
  202. package/dist/hooks/use-announce.js +37 -0
  203. package/dist/hooks/use-announce.js.map +1 -0
  204. package/dist/hooks/use-body-scroll-lock.js +1 -0
  205. package/dist/hooks/use-body-scroll-lock.js.map +1 -1
  206. package/dist/hooks/use-close-transition.js +1 -0
  207. package/dist/hooks/use-close-transition.js.map +1 -1
  208. package/dist/hooks/use-dismiss.js +1 -0
  209. package/dist/hooks/use-dismiss.js.map +1 -1
  210. package/dist/hooks/use-focus-trap.d.ts +16 -0
  211. package/dist/hooks/use-focus-trap.js +67 -0
  212. package/dist/hooks/use-focus-trap.js.map +1 -0
  213. package/dist/hooks/use-media-query.js +1 -0
  214. package/dist/hooks/use-media-query.js.map +1 -1
  215. package/dist/hooks/use-overlay-history.js +27 -1
  216. package/dist/hooks/use-overlay-history.js.map +1 -1
  217. package/dist/hooks/use-row-swipe.js +1 -0
  218. package/dist/hooks/use-row-swipe.js.map +1 -1
  219. package/dist/i18n/defaults.d.ts +31 -0
  220. package/dist/i18n/defaults.js +63 -0
  221. package/dist/i18n/defaults.js.map +1 -0
  222. package/dist/i18n/kit-labels.d.ts +250 -0
  223. package/dist/i18n/kit-labels.js +184 -0
  224. package/dist/i18n/kit-labels.js.map +1 -0
  225. package/dist/index.d.ts +47 -22
  226. package/dist/index.js +28 -0
  227. package/dist/index.js.map +1 -1
  228. package/dist/lib/calc.js +1 -0
  229. package/dist/lib/calc.js.map +1 -1
  230. package/dist/lib/cn.js +1 -0
  231. package/dist/lib/cn.js.map +1 -1
  232. package/dist/lib/dates.js +1 -0
  233. package/dist/lib/dates.js.map +1 -1
  234. package/dist/lib/logger.js +1 -0
  235. package/dist/lib/logger.js.map +1 -1
  236. package/dist/lib/safe-storage.js +1 -0
  237. package/dist/lib/safe-storage.js.map +1 -1
  238. package/dist/search/command-palette.d.ts +11 -1
  239. package/dist/search/command-palette.js +21 -15
  240. package/dist/search/command-palette.js.map +1 -1
  241. package/dist/search.d.ts +2 -0
  242. package/dist/search.js +3 -0
  243. package/dist/search.js.map +1 -0
  244. package/dist/shell/app-shell.d.ts +33 -4
  245. package/dist/shell/app-shell.js +275 -78
  246. package/dist/shell/app-shell.js.map +1 -1
  247. package/dist/shell/option-switcher-menu.js +3 -2
  248. package/dist/shell/option-switcher-menu.js.map +1 -1
  249. package/dist/shell/role-switcher.d.ts +6 -0
  250. package/dist/shell/role-switcher.js +7 -4
  251. package/dist/shell/role-switcher.js.map +1 -1
  252. package/dist/shell/top-bar.d.ts +15 -7
  253. package/dist/shell/top-bar.js +3 -5
  254. package/dist/shell/top-bar.js.map +1 -1
  255. package/dist/shell/topbar-action-menu.js +3 -2
  256. package/dist/shell/topbar-action-menu.js.map +1 -1
  257. package/dist/shell/topbar-controls.d.ts +5 -2
  258. package/dist/shell/topbar-controls.js +20 -15
  259. package/dist/shell/topbar-controls.js.map +1 -1
  260. package/dist/shell.d.ts +13 -0
  261. package/dist/shell.js +8 -0
  262. package/dist/shell.js.map +1 -0
  263. package/dist/theme/chart-palette.d.ts +19 -12
  264. package/dist/theme/chart-palette.js +24 -30
  265. package/dist/theme/chart-palette.js.map +1 -1
  266. package/dist/theme/color.d.ts +78 -0
  267. package/dist/theme/color.js +148 -0
  268. package/dist/theme/color.js.map +1 -0
  269. package/dist/theme/palette-derive.d.ts +140 -0
  270. package/dist/theme/palette-derive.js +376 -0
  271. package/dist/theme/palette-derive.js.map +1 -0
  272. package/dist/theme/palette-presets.d.ts +14 -1
  273. package/dist/theme/palette-presets.js +231 -3
  274. package/dist/theme/palette-presets.js.map +1 -1
  275. package/dist/theme/palette-store.js +1 -0
  276. package/dist/theme/palette-store.js.map +1 -1
  277. package/dist/theme/theme-store.js +1 -0
  278. package/dist/theme/theme-store.js.map +1 -1
  279. package/dist/tour/tour.d.ts +2 -1
  280. package/dist/tour/tour.js +15 -9
  281. package/dist/tour/tour.js.map +1 -1
  282. package/dist/tour.d.ts +2 -0
  283. package/dist/tour.js +3 -0
  284. package/dist/tour.js.map +1 -0
  285. package/dist/wizard/stepper-nav.js +10 -8
  286. package/dist/wizard/stepper-nav.js.map +1 -1
  287. package/dist/wizard/types.d.ts +18 -2
  288. package/dist/wizard/types.js +4 -1
  289. package/dist/wizard/types.js.map +1 -1
  290. package/dist/wizard/use-wizard.js +12 -4
  291. package/dist/wizard/use-wizard.js.map +1 -1
  292. package/dist/wizard/validation.js +1 -0
  293. package/dist/wizard/validation.js.map +1 -1
  294. package/dist/wizard/wizard-context.js +1 -0
  295. package/dist/wizard/wizard-context.js.map +1 -1
  296. package/dist/wizard/wizard-step.js +1 -0
  297. package/dist/wizard/wizard-step.js.map +1 -1
  298. package/dist/wizard/wizard-summary.js +5 -3
  299. package/dist/wizard/wizard-summary.js.map +1 -1
  300. package/dist/wizard.d.ts +8 -0
  301. package/dist/wizard.js +9 -0
  302. package/dist/wizard.js.map +1 -0
  303. package/package.json +66 -13
  304. package/src/chart.ts +22 -0
  305. package/src/components/account-settings.tsx +275 -0
  306. package/src/components/alert-banner.tsx +75 -0
  307. package/src/components/amount-input.tsx +471 -0
  308. package/src/components/calculator.tsx +252 -0
  309. package/src/components/chart-zoom.tsx +499 -0
  310. package/src/components/chart.tsx +363 -0
  311. package/src/components/checkbox.tsx +222 -0
  312. package/src/components/chip.tsx +584 -0
  313. package/src/components/choice-parts.ts +33 -0
  314. package/src/components/combobox-core.tsx +540 -0
  315. package/src/components/combobox.tsx +1026 -0
  316. package/src/components/currency-select.tsx +283 -0
  317. package/src/components/data-table-filter-popover.tsx +252 -0
  318. package/src/components/data-table-filters.ts +176 -0
  319. package/src/components/data-table-labels.ts +190 -0
  320. package/src/components/data-table-pagination.tsx +126 -0
  321. package/src/components/data-table-sort.ts +70 -0
  322. package/src/components/data-table.tsx +1740 -0
  323. package/src/components/date-picker.tsx +656 -0
  324. package/src/components/dropdown.tsx +341 -0
  325. package/src/components/entity-combobox.tsx +215 -0
  326. package/src/components/facing-pair.ts +86 -0
  327. package/src/components/field-sync.tsx +472 -0
  328. package/src/components/file-dropzone.tsx +181 -0
  329. package/src/components/full-bleed-dialog.tsx +179 -0
  330. package/src/components/grouped-picker.tsx +157 -0
  331. package/src/components/hover-menu.tsx +183 -0
  332. package/src/components/mini-calendar.tsx +554 -0
  333. package/src/components/modal.tsx +287 -0
  334. package/src/components/month-picker.tsx +567 -0
  335. package/src/components/multi-entity-combobox.tsx +226 -0
  336. package/src/components/multi-select.tsx +303 -0
  337. package/src/components/number-field.tsx +225 -0
  338. package/src/components/number-input.tsx +211 -0
  339. package/src/components/numpad-sheet.tsx +264 -0
  340. package/src/components/page-contents.tsx +289 -0
  341. package/src/components/password-strength.tsx +258 -0
  342. package/src/components/picker-sheet.tsx +251 -0
  343. package/src/components/popover.tsx +198 -0
  344. package/src/components/search-field.tsx +146 -0
  345. package/src/components/series-chart-labels.ts +26 -0
  346. package/src/components/series-chart.tsx +481 -0
  347. package/src/components/settings-fields.tsx +68 -0
  348. package/src/components/signature-pad.tsx +630 -0
  349. package/src/components/slider.tsx +313 -0
  350. package/src/components/sparkline.tsx +329 -0
  351. package/src/components/stat-tile.tsx +448 -0
  352. package/src/components/swipeable-row.tsx +271 -0
  353. package/src/components/switch.tsx +170 -0
  354. package/src/components/time-input.tsx +107 -0
  355. package/src/components/toggle-group.tsx +153 -0
  356. package/src/components/toggle-legend.tsx +229 -0
  357. package/src/components/tooltip.tsx +477 -0
  358. package/src/components/treemap.tsx +390 -0
  359. package/src/components/trigger-aria.ts +42 -0
  360. package/src/components/ui.tsx +1295 -0
  361. package/src/components/use-mobile-reveal.ts +54 -0
  362. package/src/components/use-table-state.ts +295 -0
  363. package/src/components/user-avatar.tsx +61 -0
  364. package/src/components/wizard-stepper.tsx +37 -0
  365. package/src/data-table.ts +19 -0
  366. package/src/feedback/feedback-attachment.tsx +246 -0
  367. package/src/feedback/feedback-dialog.tsx +209 -0
  368. package/src/feedback/feedback-inbox.tsx +615 -0
  369. package/src/feedback.ts +8 -0
  370. package/src/hooks/use-anchored-panel.ts +169 -0
  371. package/src/hooks/use-anchored-rect.ts +78 -0
  372. package/src/hooks/use-announce.ts +85 -0
  373. package/src/hooks/use-body-scroll-lock.ts +94 -0
  374. package/src/hooks/use-close-transition.ts +99 -0
  375. package/src/hooks/use-dismiss.ts +77 -0
  376. package/src/hooks/use-focus-trap.ts +160 -0
  377. package/src/hooks/use-media-query.ts +23 -0
  378. package/src/hooks/use-overlay-history.ts +345 -0
  379. package/src/hooks/use-row-swipe.ts +212 -0
  380. package/src/i18n/defaults.ts +68 -0
  381. package/src/i18n/kit-labels.tsx +447 -0
  382. package/src/index.ts +169 -0
  383. package/src/lib/calc.ts +309 -0
  384. package/src/lib/cn.ts +5 -0
  385. package/src/lib/dates.ts +187 -0
  386. package/src/lib/logger.ts +73 -0
  387. package/src/lib/safe-storage.ts +37 -0
  388. package/src/search/command-palette.tsx +342 -0
  389. package/src/search.ts +3 -0
  390. package/src/shell/app-shell.tsx +772 -0
  391. package/src/shell/option-switcher-menu.tsx +72 -0
  392. package/src/shell/role-switcher.tsx +46 -0
  393. package/src/shell/top-bar.tsx +39 -0
  394. package/src/shell/topbar-action-menu.tsx +91 -0
  395. package/src/shell/topbar-controls.tsx +229 -0
  396. package/src/shell.ts +10 -0
  397. package/src/theme/chart-palette.ts +145 -0
  398. package/src/theme/color.ts +266 -0
  399. package/src/theme/palette-derive.ts +681 -0
  400. package/src/theme/palette-presets.ts +760 -0
  401. package/src/theme/palette-store.ts +94 -0
  402. package/src/theme/theme-store.ts +145 -0
  403. package/src/tour/tour.tsx +586 -0
  404. package/src/tour.ts +3 -0
  405. package/src/vite-env.d.ts +26 -0
  406. package/src/wizard/stepper-nav.tsx +221 -0
  407. package/src/wizard/types.ts +178 -0
  408. package/src/wizard/use-wizard.ts +345 -0
  409. package/src/wizard/validation.ts +37 -0
  410. package/src/wizard/wizard-context.tsx +29 -0
  411. package/src/wizard/wizard-step.tsx +14 -0
  412. package/src/wizard/wizard-summary.tsx +69 -0
  413. package/src/wizard.ts +14 -0
  414. package/tokens.css +222 -20
package/LICENSE ADDED
@@ -0,0 +1,32 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marcel Eifert
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ THIRD-PARTY NOTICES
26
+
27
+ src/components/chart.tsx is adapted from the shadcn/ui chart kit
28
+ (https://ui.shadcn.com), Copyright (c) 2023 shadcn, MIT licensed. The structure
29
+ — config-driven series colours injected as CSS custom properties, the muted
30
+ axis/grid treatment, and the tooltip/legend content components — is retained;
31
+ it has been ported to Recharts 3 and re-skinned onto this package's own tokens
32
+ rather than shadcn's.
package/README.md CHANGED
@@ -25,6 +25,25 @@ module so consumers can still tree-shake it (see the `sideEffects` note in
25
25
  entry chunk). Tailwind classes are emitted as-is; each app still compiles them
26
26
  with its own Tailwind config.
27
27
 
28
+ ## Documentation
29
+
30
+ | | |
31
+ |---|---|
32
+ | [ADOPTING.md](https://github.com/Eifi1/ui-kit/blob/main/ADOPTING.md) | The brief for a new consuming app — hand it to that repo's agent |
33
+ | [MIGRATING.md](https://github.com/Eifi1/ui-kit/blob/main/MIGRATING.md) | Moving an app off the old `@hb/ui` submodule onto the npm package |
34
+ | [CHANGELOG.md](https://github.com/Eifi1/ui-kit/blob/main/CHANGELOG.md) | Every release, and the semver contract this package keeps below 1.0 |
35
+ | [CONTRIBUTING.md](https://github.com/Eifi1/ui-kit/blob/main/CONTRIBUTING.md) | Repo layout, the house rules, the gates, how to cut a release |
36
+ | [Issues](https://github.com/Eifi1/ui-kit/issues) | Bugs and requests |
37
+
38
+ The links are absolute because only this README is in the npm tarball — `files` ships
39
+ `dist`, `src`, `tokens.css` and `LICENSE`, so a reader who arrived from npmjs.com has none
40
+ of the others on disk and a relative link would be a 404.
41
+
42
+ A rendered catalogue of every component, with the theme, palette and language switchers
43
+ live, deploys to <https://eifi1.github.io/ui-kit/> on every push to `main`. It needs one
44
+ manual repo setting to go live, named at the top of `.github/workflows/pages.yml`; until
45
+ then, `npm run dev:showcase` from a checkout is the same page.
46
+
28
47
  ## Install
29
48
 
30
49
  ```bash
@@ -35,10 +54,43 @@ Versions are pinned in your lockfile like any dependency, so each app upgrades
35
54
  when it chooses. To work on the design system and an app together, use
36
55
  `npm link` or a workspace override rather than a `file:` path.
37
56
 
38
- `@eifi1/ui-kit` needs these installed in the consuming app: `react`, `react-dom` (required
39
- peers) and — only if you use the pieces that need them — `recharts` (the `chart`
40
- kit), `sonner` (`FileDropzone`), `react-router` (`DataTable` URL-sync + `AppShell`).
41
- It also pulls `clsx`, `tailwind-merge`, `lucide-react`, `zustand`, `flag-icons`.
57
+ ### What you install alongside it
58
+
59
+ | Package | Declared as | Why |
60
+ |---|---|---|
61
+ | `react`, `react-dom` | peer, `>=19` | The kit is components and hooks; two copies of React break hooks and context. |
62
+ | `react-router` | peer, `>=7` | Imported unconditionally by `DataTable`, `useTableState`, `AppShell` and `useWizard`. A Router has to be mounted even with `urlSync` off. |
63
+ | `recharts` | peer, `>=3` | `@eifi1/ui-kit/chart` imports it statically. Only that subpath needs it — the main barrel no longer reaches it. |
64
+ | `lucide-react` | peer, `>=0.400.0 <2` | Icons, in 33 modules. **Yours to version.** |
65
+ | `sonner` | peer, `>=2`, **optional** | `FileDropzone` and the wizard's "fill in the required fields" toast, reached only through `await import()`. Pass `onValidationFailed` to route it elsewhere. |
66
+ | `clsx`, `tailwind-merge`, `zustand` | dependency | Small, imported directly, and the kit owns the version. Add `zustand` to Vite's `dedupe` (below) — the theme and palette stores are singletons. |
67
+ | `flag-icons` | **nothing — you supply the stylesheet** | See below. |
68
+
69
+ **`lucide-react` is a peer from 0.5.0, not a dependency.** All three consumers already
70
+ declared it themselves, so a hard dependency here bought each of them a second copy of the
71
+ icon set — and `^0.511.0` on a 0.x package is a *patch* pin, which held them on 0.511.x
72
+ while the line moved to 1.x. The range is wide on purpose: the kit imports named icon
73
+ components and nothing else, and that has been stable across the whole span. *Migration:*
74
+ none if you already depend on it; otherwise `npm install lucide-react`.
75
+
76
+ **`flag-icons` is a host contract, not a dependency.** `CurrencyFlag`, `CurrencySelect`
77
+ (and `AmountInput`'s currency picker, which uses it) and `LanguageMenu` render flags as
78
+ class names — `<span class="fi fi-ch">` — and nothing in the package imports a stylesheet.
79
+ The app provides it:
80
+
81
+ ```bash
82
+ npm install flag-icons
83
+ ```
84
+
85
+ ```ts
86
+ // main.tsx, once, next to your other global CSS
87
+ import "flag-icons/css/flag-icons.min.css";
88
+ ```
89
+
90
+ Without it those flags are empty boxes: no error, no warning, just missing glyphs in the
91
+ currency picker and the language menu. It was a 5.6 MB hard dependency through 0.4.x —
92
+ installed into every consumer and imported by nothing — so it may still be in your tree
93
+ transitively after upgrading. Depend on it explicitly if you render any of the three.
42
94
 
43
95
  ## Wiring
44
96
 
@@ -59,10 +111,28 @@ resolve: {
59
111
  ```css
60
112
  /* app.css */
61
113
  @import "tailwindcss";
62
- @import "@eifi1/ui-kit/tokens.css"; /* design tokens, semantic utilities, chrome */
63
- @source "../../node_modules/@eifi1/ui-kit/src"; /* keep the class names @eifi1/ui-kit uses */
114
+ @import "@eifi1/ui-kit/tokens.css"; /* design tokens, semantic utilities, chrome */
115
+ @source "../../node_modules/@eifi1/ui-kit/dist"; /* keep the class names @eifi1/ui-kit uses */
64
116
  ```
65
117
 
118
+ **Get this path right, and check it.** Tailwind never scans `node_modules`, so without
119
+ `@source` none of the kit's class names are generated and the components render
120
+ *unstyled* — laid out, interactive, and completely unpainted. Nothing errors, so it
121
+ looks like a broken design system rather than a missing line. The path is relative to
122
+ **the CSS file it is written in**, not to the project root; count the `../` from there.
123
+
124
+ To verify in ten seconds: build, then grep the emitted CSS for a class only this
125
+ package uses.
126
+
127
+ ```bash
128
+ npm run build && grep -c 'pointer-events-auto' dist/assets/*.css # 0 means the scan missed
129
+ ```
130
+
131
+ Scanning `dist` is the recommended path: it is published by every version. From
132
+ v0.5.0 the tarball also ships `src`, so `@source ".../@eifi1/ui-kit/src"` works too and
133
+ scans the original TSX rather than transpiled output — but it is not present in
134
+ v0.4.x, and an `@source` pointing at a directory that does not exist fails silently.
135
+
66
136
  ### 3. Theme + palette stores (own persistence keys)
67
137
 
68
138
  The stores are factories so each app namespaces its own `localStorage`:
@@ -75,8 +145,201 @@ export const { usePalette, useApplyPalette, useActiveTokenSet, useChartHex, useH
75
145
  ```
76
146
 
77
147
  Call `useApplyTheme()` + `useApplyPalette()` once near the root. For a no-flash
78
- first paint, apply the persisted theme class + token set before hydration (see
79
- Keksdose's `main.tsx` for the pattern, using `applyTokenSet`/`presetById`).
148
+ first paint, apply the persisted theme class + token set **before** hydration —
149
+ `applyPersistedTheme(key)` resolves the stored preference, toggles `.dark` and
150
+ returns the mode, which `applyPersistedPalette(key, mode)` then uses:
151
+
152
+ ```ts
153
+ // main.tsx, at module scope, before createRoot
154
+ const mode = applyPersistedTheme("myapp-theme");
155
+ applyPersistedPalette("myapp-palette", mode);
156
+ ```
157
+
158
+ Worked example: [`showcase/src/main.tsx`](showcase/src/main.tsx).
159
+
160
+ ## Tokens
161
+
162
+ Everything the components paint with comes from `tokens.css`, so a consuming app
163
+ re-skins the kit by changing values rather than by forking components. Three layers:
164
+
165
+ | Layer | Tokens | Set by |
166
+ |---|---|---|
167
+ | **Palette** | `--bg-page` `--bg-surface` `--bg-surface-2` `--border` `--text-primary` `--text-secondary` `--text-muted` `--brand` `--brand-hover` `--brand-contrast` `--money-income` `--money-expense` `--money-net` `--money-neutral` `--chart-1…9` | `applyTokenSet()`, written inline on `<html>` from the active `PalettePreset` |
168
+ | **Derived** | `--text-placeholder` `--bg-hover` `--bg-active` `--bg-inverse` `--text-inverse` `--border-strong` `--brand-bg` `--brand-bg-hover` `--brand-muted` | `color-mix()` in `tokens.css`, from the layer above — so they follow the preset with no preset having to list them |
169
+ | **Semantic** | `--danger*` `--warning*` `--info*`, and `--status-synced/-pending/-edited/-error` | literals in `tokens.css`, per theme |
170
+
171
+ The semantic layer is deliberately **not** part of `TokenSet`: a destructive action and a
172
+ failed save are fixed meanings, and they should not change because somebody picked a
173
+ different appearance preset. Everything else does follow the preset.
174
+
175
+ To re-skin, override the tokens after importing the stylesheet:
176
+
177
+ ```css
178
+ @import "@eifi1/ui-kit/tokens.css";
179
+
180
+ :root { --brand: #0f766e; --brand-hover: #115e59; --brand-contrast: #fff; }
181
+ .dark { --brand: #5eead4; --brand-hover: #99f6e4; --brand-contrast: #042f2e; }
182
+ ```
183
+
184
+ `--brand-bg`, `--brand-bg-hover` and `--brand-muted` are derived from `--brand`, so the
185
+ soft brand chips (an active filter, a selected day) follow that override automatically.
186
+
187
+ `npm run check:tokens` fails if a component reaches for a raw Tailwind palette colour
188
+ instead of a token. It is a ratchet: when the count drops, lower the budget in the same
189
+ commit.
190
+
191
+ ## Colour
192
+
193
+ ### Three systems, deliberately separate
194
+
195
+ A colour in this kit belongs to exactly one of three systems, and they are kept apart
196
+ because they answer different questions.
197
+
198
+ | System | Tokens | The question it answers |
199
+ |---|---|---|
200
+ | **Semantic UI** | `--danger*` `--warning*` `--info*` `--success*`, `--status-*` | *What does this mean?* Danger is red because every other interface the reader has used made it red. Fixed meanings, so they live in `tokens.css` and are **not** part of `TokenSet` — a destructive action must not change colour because somebody picked a different preset. |
201
+ | **Semantic data** | `--money-income` `--money-expense` `--money-net` `--money-neutral` | *Which direction is this number?* Never red/green: that pair is exactly the axis dichromacy collapses. Always paired with a `+`/`−` or an arrow at the call site, so colour is never the only signal. |
202
+ | **Categorical chart** | `--chart-1` … `--chart-9` | *Which series is this?* No meaning and no order — nine hues that must stay separable from each other. Paul Tol's "Muted" set, CVD-safe across protan/deutan/tritan. `paletteFor(i)` returns the CSS var, so a Recharts series is theme-aware for free. |
203
+
204
+ Optimising a set for one of these makes it worse at the others. A UI colour needs contrast
205
+ against one known surface and carries a fixed meaning; a chart colour needs to stay
206
+ separable from eight unknown siblings at roughly equal salience with no implied order.
207
+ That is why `derivePalette` leaves the chart ramp alone unless you ask for
208
+ `deriveChartRamp` explicitly.
209
+
210
+ One consequence to know about: the `chart` array it returns is **empty, not absent**. A
211
+ caller who hands the result straight to `applyTokenSet` keeps whatever `--chart-1…9` were
212
+ already on the element — deliberate, because clearing them would leave charts unpainted,
213
+ but it means a derived palette applied over another preset is a *mix* until you supply a
214
+ ramp of your own.
215
+
216
+ ### Deriving a palette
217
+
218
+ ```ts
219
+ import { derivePalette, auditPalette, auditChartRamp } from "@eifi1/ui-kit";
220
+
221
+ const { tokens, semantic, audit, warnings } = derivePalette({
222
+ anchors: { brand: "#4f46e5", danger: "#b91c1c" }, // brand required; the rest optional
223
+ mode: "light",
224
+ });
225
+ ```
226
+
227
+ `brand` is required and `accent`, `danger`, `warning`, `success` and `info` are optional
228
+ hard points. Pinned hues are honoured exactly; the rest are placed away from the brand and
229
+ from each other, each within its own narrow licence to move — enough to get out of the
230
+ brand's way, not enough to stop meaning what it means. If a role cannot get far enough,
231
+ that is a `warnings` entry, not a silent compromise.
232
+
233
+ Everything is **solved to a target and then measured**. Text is solved against the *worst*
234
+ of the three surfaces (`--bg-page`, `--bg-surface`, `--bg-surface-2`) — 10:1 primary, 7:1
235
+ secondary, 4.6:1 muted by default — because solving against `--bg-surface` alone is the
236
+ mistake that makes a muted label fail on the page background it also sits on. The brand
237
+ keeps the hue and chroma you asked for and moves only in lightness, and only as far as the
238
+ 3:1 that WCAG 1.4.11 asks of a control boundary.
239
+
240
+ It exists because the presets this package shipped were assembled by eye and annotated with
241
+ the ratios they were *believed* to hold — `tokens.css` recorded "7.0:1 and 4.8:1",
242
+ `palette-presets.ts` recorded "2.67:1 … lifted they clear it at 3.30:1" — and nothing
243
+ computed any of them. A comment is not a test. The audit found four of the nine default
244
+ light chart hues below 3:1.
245
+
246
+ `auditPalette(tokens, semantic)` and `auditChartRamp(colors, surfaces)` measure a palette
247
+ instead of trusting it, and run in CI over everything the package ships. The ramp report
248
+ gives pairwise collisions under normal vision *and* each of the three dichromacies, every
249
+ series below 3:1 against a surface it may be drawn on, and the worst of each.
250
+
251
+ The colour maths (`src/theme/color.ts`: sRGB ↔ OKLab ↔ OKLCH, WCAG contrast, gamut
252
+ clipping, dichromat simulation, OKLab ΔE) is dependency-free, and OKLCH rather than HSL
253
+ because HSL's "lightness" is not lightness — `hsl(60 100% 50%)` and `hsl(240 100% 50%)`
254
+ claim the same 50% and differ about twelvefold in apparent brightness.
255
+
256
+ ### The categorical trade-off, measured
257
+
258
+ **At a single lightness, the most categorical series that can satisfy both the 3:1 fill
259
+ contrast of WCAG 1.4.11 and the dichromat separation floor is four.** Searched exhaustively
260
+ over starting hue and lightness:
261
+
262
+ | Series | Best separation | Both satisfiable |
263
+ |---|---|---|
264
+ | 4 | 0.065 | yes |
265
+ | 5 | 0.041 | no |
266
+ | 9 | 0.015 | no |
267
+
268
+ The floor is 0.05 in OKLab, calibrated rather than chosen: Paul Tol's "Muted" set — known
269
+ to work — bottoms out at 0.059 light and 0.032 in the lightened dark variant, and a
270
+ threshold above that would fail a palette that is known good, which is worse than no check
271
+ at all.
272
+
273
+ The reason is structural. Dichromacy collapses the red-green axis, so hue alone stops
274
+ distinguishing colours past a handful, and the only channel left is **lightness** — the
275
+ very thing a uniform-contrast ramp holds constant. Tol's set varies lightness deliberately
276
+ and pays for it in contrast; that is not an oversight in their palette, it is the only
277
+ currency left. Above four series `deriveChartRamp` varies lightness too, in a three-step
278
+ cycle so adjacent series differ in lightness as well as hue, and reports what it gave up.
279
+
280
+ Two honest caveats. That bound describes the **problem**, not a guarantee about
281
+ `deriveChartRamp`: it fixes lightness and starts the hue wheel at the brand's own hue
282
+ rather than searching for the best start, so it reaches the bound only where the brand
283
+ happens to sit well — sweeping 72 brand hues against the default light surfaces, **7 of 72
284
+ produced a passing 4-series ramp** (12 of 72 on dark), and none passed at 5 or 9. Read the
285
+ report it returns; do not assume a pass. And `deriveChartRamp` is offered, not used by
286
+ default: evenly spaced hues at one lightness are a reasonable generic answer, and Tol's set
287
+ is a better specific one, because it was optimised against real confusion lines rather than
288
+ derived from a formula.
289
+
290
+ ## Showcase
291
+
292
+ Every component in the package, rendered on one page, with the theme and palette
293
+ switchers live:
294
+
295
+ ```bash
296
+ npm run dev:showcase
297
+ ```
298
+
299
+ and open **http://localhost:4170**.
300
+
301
+ The port is harmonised with the sibling apps rather than left on Vite's default, so the
302
+ showcase can run next to whatever you are testing it against:
303
+
304
+ | Port | What |
305
+ |---|---|
306
+ | **4170** | **this showcase** (`dev:showcase`) |
307
+ | **4171** | this showcase, built (`preview:showcase`) |
308
+ | 4173 | keksdose frontend (backend 8000) |
309
+ | 4175 | lenkbank frontend (backend 8001) |
310
+ | 5173 | kastlan frontend (Vite's default) |
311
+
312
+ `strictPort` is on: a collision fails loudly instead of silently moving to another port
313
+ and printing a URL that is not the one documented here. For a throwaway instance that
314
+ must not take the port your editor's build task wants:
315
+
316
+ ```bash
317
+ SHOWCASE_PORT=4199 npm run dev:showcase
318
+ ```
319
+
320
+ It renders **`src/`, not `dist/`** — no build step first, and an edit to a component
321
+ is on screen on save. It is also the package's broadest test: `npm test` mounts the
322
+ whole page under jsdom, so a component that throws on mount fails CI, and `tsc`
323
+ covers it, so an export renamed out of the barrel is a compile error rather than a
324
+ demo that quietly disappears.
325
+
326
+ ```
327
+ showcase/
328
+ index.html
329
+ vite.config.ts # root; aliases @eifi1/ui-kit → ../src
330
+ alias.ts # that alias, shared with the root vitest.config.ts
331
+ src/
332
+ main.tsx # the pre-hydration no-flash boot, as a worked example
333
+ app.css # tailwind + tokens.css + the @source scan
334
+ stores.ts # createThemeStore / createPaletteStore, showcase keys
335
+ showcase.tsx # the AppShell frame + the SECTIONS registry
336
+ sections/*.tsx # one file per section
337
+ ```
338
+
339
+ Adding a component to the kit means adding it to a section — that is how the page
340
+ stays true. `npm run build:showcase` produces a static site; CI builds it on every
341
+ push and asserts the emitted CSS actually contains the kit's utility classes, which
342
+ is the only automated check that the documented Tailwind `@source` step works.
80
343
 
81
344
  ## Tests
82
345
 
@@ -99,42 +362,159 @@ a test written after the fix proves only that the fix is self-consistent.
99
362
 
100
363
  ## What's exported
101
364
 
102
- - **Primitives / fields:** `cn`, `Button`, `Input`, `Select`, `Textarea`,
103
- `FloatingField`, `FieldLabel`, `Card`, `Spinner`, `EmptyState`, `Tabs`, plus the
104
- field-class constants (`FIELD_BASE`, `FIELD_TRIGGER`, `FLOATING_*`, …).
105
- - **Inputs / dropdowns:** `NumberInput`, `AmountInput`, `Combobox`, `MultiSelect`,
106
- `CurrencySelect` (+ `CURRENCIES`, `getCurrency`, `CurrencyFlag`), dropdown
107
- primitives (`useDropdown`, `useDropdownSearch`, `DropdownPanel`,
108
- `DropdownSearchHeader`), `CalculatorButton`, the calc engine.
109
- - **Overlays / misc:** `Modal` (+ `useBackdropClose`), `Popover`, `HoverMenu`,
110
- `Tooltip`, `AlertBanner`, `ToggleGroup`, `FileDropzone`, `GroupedPicker`,
111
- `MiniCalendar`, `WizardStepper` (a bare two-step indicator — not the wizard
112
- engine below), the `chart` kit.
113
- - **Data table:** `DataTable` (+ `DataTableColumn`, `FilterState`, `SortState`,
114
- `ServerPagination`), `Pagination`, filter/sort helpers, `DataTableLabels`.
115
- - **Theme:** `TokenSet`, `PalettePreset`, `DEFAULT_PRESET`, `ALTERNATIVE_PRESETS`,
116
- `PALETTES`, `presetById`, `applyTokenSet`,
117
- `PALETTE_HEX`, chart-colour helpers, and the store factories.
118
- - **Shell:** `TopBar`, `AppShell` (+ `AppShellNavItem`), `ThemeToggle`,
119
- `PaletteMenu`, `LanguageMenu`, `TOPBAR_TRIGGER_CLASS`, `TOPBAR_MENU_ITEM_CLASS`.
120
- - **Feedback:** `FeedbackDialog` (the compose form) and the inbox parts —
121
- `FeedbackStatus`/`FeedbackCategory` and their `*_META`/`*_ORDER` tables,
122
- `nextFeedbackStatus`, `visibleFeedbackStatuses`, `selectableFeedbackStatuses`,
123
- `feedbackCategoryRank`, `FeedbackStatusBadge`, `FeedbackStatusTransitions`,
124
- `FeedbackCategoryBadge`, `FeedbackNoteEditor`, `FeedbackDetail`,
125
- `FeedbackDetailSection`, `FeedbackProse`. The vocabulary, the transition policy
126
- and the look; each app still wires its own API, columns, strings and
127
- permissions — see the note at the top of `src/feedback/feedback-inbox.tsx`.
128
- - **Wizard:** the multi-step engine (`useWizard`, `WizardContextProvider`,
129
- `useWizardContext`, `useRhfWizardStep`, `useWizardStepValidate`,
130
- `useWizardNextGate`, `requiredFieldsValidator`), the chrome around it
131
- (`StepperNav`, `WizardSummary`) and the parts its steps are built from
132
- (`WizardStep`, `WizardField`, `WizardSelectField`) — plus the types
133
- (`WizardStepConfig`, `UseWizardOptions`, `UseWizardReturn`, `StepStatus`,
134
- `ValidateResult`, `FieldErrors`, `SummarySection`, `SummaryItem`,
135
- `RequiredFieldSpec`) and the label table (`WizardLabels`,
136
- `DEFAULT_WIZARD_LABELS`, `resolveWizardLabels`). See [Wizard](#wizard) below.
137
- - **Subpath:** date helpers at `@eifi1/ui-kit/dates`; stylesheet at `@eifi1/ui-kit/tokens.css`.
365
+ The full inventory, generated from the build rather than maintained by hand — the
366
+ hand-written version named 93 of 263 and had been advertising five deleted wizard exports
367
+ since 0.4.0. Regenerate it with `node scripts/gen-export-inventory.mjs` after a build.
368
+
369
+ Two names that read as something they are not: `WizardStepper` is a bare two-step
370
+ indicator and has nothing to do with the wizard engine below, and the feedback exports are
371
+ the vocabulary, the transition policy and the look only — each app still wires its own API,
372
+ columns, strings and permissions (see the note at the top of `src/feedback/feedback-inbox.tsx`).
373
+
374
+ <!-- BEGIN GENERATED: exports — node scripts/gen-export-inventory.mjs -->
375
+
376
+ **324 names from 76 modules** — 212 values and 112 types. _Italic_ is a type-only export.
377
+
378
+ Generated from `dist/index.d.ts` by `node scripts/gen-export-inventory.mjs`; the count
379
+ is pinned by `src/__tests__/public-surface.test.ts`. Do not edit between the markers.
380
+
381
+ | Entry point | Names |
382
+ |---|---|
383
+ | `@eifi1/ui-kit` | 324 |
384
+ | `@eifi1/ui-kit/chart` | 15 |
385
+ | `@eifi1/ui-kit/shell` | 16 |
386
+ | `@eifi1/ui-kit/data-table` | 27 |
387
+ | `@eifi1/ui-kit/wizard` | 20 |
388
+ | `@eifi1/ui-kit/tour` | 6 |
389
+ | `@eifi1/ui-kit/feedback` | 27 |
390
+ | `@eifi1/ui-kit/search` | 4 |
391
+ | `@eifi1/ui-kit/dates` | 16 |
392
+
393
+ Everything below is reachable from the main `@eifi1/ui-kit` barrel. The subpaths are a
394
+ re-slicing of it, never a second API.
395
+
396
+ ### lib — pure helpers
397
+
398
+ | Module | Exports |
399
+ |---|---|
400
+ | `lib/calc` | `commitExpression`, `evaluateExpression`, `formatResult`, `isBareAmount`, `looksLikeExpression`, `sanitizeLive`, `splitLeadingSign` |
401
+ | `lib/cn` | `cn` |
402
+ | `lib/logger` | `logger`, `setStoreLog` |
403
+
404
+ ### hooks
405
+
406
+ | Module | Exports |
407
+ |---|---|
408
+ | `hooks/use-media-query` | `useMediaQuery` |
409
+ | `hooks/use-body-scroll-lock` | `useBodyScrollLock` |
410
+ | `hooks/use-anchored-rect` | `useAnchoredRect`, _`AnchorRect`_ |
411
+ | `hooks/use-anchored-panel` | `anchoredPanelPlacement`, `useAnchoredPanel`, `useVisualViewport`, _`AnchoredPanel`_, _`AnchoredPanelOptions`_, _`ViewportBox`_ |
412
+ | `hooks/use-dismiss` | `useEscapeKey`, `useOutsideClick` |
413
+ | `hooks/use-focus-trap` | `useFocusTrap`, _`FocusTrapOptions`_ |
414
+ | `hooks/use-announce` | `useAnnounce`, _`AnnounceRegionProps`_, _`UseAnnounceOptions`_, _`UseAnnounceReturn`_ |
415
+ | `hooks/use-overlay-history` | `useOverlayHistory` |
416
+ | `hooks/use-close-transition` | `OVERLAY_EXIT_MS`, `useCloseTransition` |
417
+ | `hooks/use-row-swipe` | `useRowSwipe`, _`RowSwipeOptions`_, _`RowSwipeReturn`_, _`SwipeStage`_ |
418
+
419
+ ### theme, palettes, colour
420
+
421
+ | Module | Exports |
422
+ |---|---|
423
+ | `theme/chart-palette` | `CHART_COLORS`, `HEATMAP_HEX`, `lerpHex`, `PALETTE_HEX`, `paletteFor`, `textOn`, _`HeatStops`_ |
424
+ | `theme/color` | `contrast`, `deltaE`, `hexToOklch`, `luminance`, `oklchToHex`, `oklchToRgb`, `parseHex`, `rgbToOklch`, `simulateCvd`, `solveLightness`, `toHex`, _`CvdType`_, _`Oklch`_, _`Rgb`_ |
425
+ | `theme/palette-derive` | `auditChartRamp`, `auditPalette`, `deriveChartRamp`, `derivePalette`, `describe`, _`AnchorRole`_, _`ChartRampReport`_, _`ContrastCheck`_, _`ContrastReport`_, _`DerivedPalette`_, _`DeriveOptions`_, _`PaletteAnchors`_, _`SemanticTokens`_ |
426
+ | `theme/palette-presets` | `ALTERNATIVE_PRESETS`, `applyTokenSet`, `DEFAULT_PRESET`, `DERIVED_PRESETS`, `IMPRINT_PRESET`, `PALETTES`, `presetById`, _`PalettePreset`_, _`TokenSet`_ |
427
+ | `theme/theme-store` | `applyPersistedTheme`, `createThemeStore`, _`ThemeMode`_, _`ThemePreference`_, _`ThemeState`_, _`ThemeStore`_ |
428
+ | `theme/palette-store` | `applyPersistedPalette`, `createPaletteStore`, _`PaletteStore`_ |
429
+
430
+ ### components
431
+
432
+ | Module | Exports |
433
+ |---|---|
434
+ | `components/ui` | `Button`, `buttonClasses`, `Card`, `CardAction`, `CardContent`, `CardDescription`, `CardFooter`, `CardHeader`, `CardTitle`, `DEFAULT_PASSWORD_REVEAL_LABELS`, `EmptyState`, `FIELD_BASE`, `FIELD_DISPLAY`, `FIELD_FLOATING_PAD`, `FIELD_INVALID`, `FIELD_TRIGGER`, `FIELD_WRITABLE_LOOK`, `FieldChevron`, `FieldHint`, `FieldLabel`, `FLOATING_INPUT_CLASS`, `FLOATING_LABEL_CLASS`, `FLOATING_LABEL_STATIC`, `FloatingField`, `IconButton`, `Input`, `PHONE_QUERY`, `resolvePasswordRevealLabels`, `Select`, `Spinner`, `Tabs`, `Textarea`, _`ButtonVariant`_, _`PasswordRevealLabels`_, _`TabsProps`_ |
435
+ | `components/search-field` | `SearchField`, _`SearchFieldProps`_ |
436
+ | `components/dropdown` | `DropdownPanel`, `DropdownSearchHeader`, `useDropdown`, `useDropdownSearch` |
437
+ | `components/popover` | `Popover`, _`PopoverLabels`_ |
438
+ | `components/swipeable-row` | `SwipeableRow`, _`SwipeableRowProps`_, _`SwipeAction`_ |
439
+ | `components/calculator` | `CalculatorButton`, _`CalculatorButtonLabels`_ |
440
+ | `components/numpad-sheet` | `NumberPadSheet`, _`NumberPadSheetLabels`_ |
441
+ | `components/number-input` | `NumberInput` |
442
+ | `components/currency-select` | `CURRENCIES`, `CurrencyFlag`, `currencyName`, `CurrencySelect`, `getCurrency`, _`CurrencyOption`_ |
443
+ | `components/amount-input` | `AmountInput` |
444
+ | `components/combobox` | `Combobox`, `InlineEntityCombobox` |
445
+ | `components/picker-sheet` | `PickerSheet`, `SHEET_ROW_CLASS` |
446
+ | `components/entity-combobox` | `EntityCombobox`, _`EntityComboboxProps`_ |
447
+ | `components/multi-entity-combobox` | `MultiEntityCombobox`, _`MultiEntityComboboxProps`_ |
448
+ | `components/multi-select` | `MultiSelect`, _`MultiSelectOption`_ |
449
+ | `components/tooltip` | `placeTooltip`, `Tooltip`, _`TooltipPlacement`_, _`TooltipSize`_, _`TooltipViewport`_ |
450
+ | `components/user-avatar` | `avatarInitials`, `UserAvatar`, _`UserAvatarProps`_ |
451
+ | `components/settings-fields` | `LanguageSetting`, `ThemeSetting`, _`LanguageSettingProps`_, _`ThemeSettingProps`_ |
452
+ | `components/field-sync` | `DEFAULT_FIELD_SYNC_LABELS`, `FieldSyncIndicator`, `FieldSyncRow`, `resolveFieldSyncLabels`, `useFieldSync`, _`FieldSyncIndicatorProps`_, _`FieldSyncLabels`_, _`FieldSyncRowProps`_, _`FieldSyncState`_, _`UseFieldSyncOptions`_, _`UseFieldSyncReturn`_ |
453
+ | `components/account-settings` | `PasswordSetting`, `ProfileSetting`, `TwoFactorSetting`, _`PasswordSettingLabels`_, _`ProfileSettingLabels`_, _`TwoFactorSettingLabels`_ |
454
+ | `components/alert-banner` | `AlertBanner`, `alertFrameClass`, `toneFrameClass`, _`AlertTone`_ |
455
+ | `components/toggle-group` | `ToggleGroup` |
456
+ | `components/chip` | `Chip`, `ChipInput`, `DEFAULT_CHIP_INPUT_LABELS`, `resolveChipInputLabels`, _`ChipInputLabels`_, _`ChipInputProps`_, _`ChipProps`_, _`ChipSize`_, _`ChipTone`_ |
457
+ | `components/wizard-stepper` | `WizardStepper` |
458
+ | `components/hover-menu` | `HoverMenu` |
459
+ | `components/modal` | `Modal`, `useBackdropClose`, _`ModalProps`_ |
460
+ | `components/full-bleed-dialog` | `FullBleedDialog` |
461
+ | `components/grouped-picker` | `GroupedPicker`, _`PickerGroup`_ |
462
+ | `components/file-dropzone` | `FileDropzone` |
463
+ | `components/mini-calendar` | `MiniCalendar`, _`MiniCalendarLabels`_, _`MiniCalendarProps`_ |
464
+ | `components/date-picker` | `DatePicker`, `DateRangePicker`, _`DatePickerProps`_, _`DateRangePickerPreset`_, _`DateRangePickerProps`_ |
465
+ | `components/chart` | `ChartContainer`, `ChartLegend`, `ChartLegendContent`, `ChartTooltip`, `ChartTooltipContent`, `useChart`, _`ChartConfig`_, _`ChartSeriesConfig`_ |
466
+ | `components/data-table-labels` | `DEFAULT_DATA_TABLE_LABELS`, `missingDataTableLabels`, `resolveDataTableLabels`, _`DataTableLabels`_ |
467
+ | `components/data-table-sort` | `decodeSorts`, `encodeSorts`, `nextSorts`, `normalizeSorts`, _`SortDir`_, _`SortState`_ |
468
+ | `components/data-table-filters` | `decodeFilterValue`, `decodeFilterValueOfType`, `defaultFilterState`, `encodeFilterValue`, `isFilterActive`, `resolveFilter`, `rowMatches`, _`ColumnFilter`_, _`FilterValue`_ |
469
+ | `components/data-table` | `DataTable`, _`DataTableColumn`_, _`DataTableProps`_, _`FilterState`_, _`ServerPagination`_ |
470
+ | `components/data-table-pagination` | `PAGE_SIZE_OPTIONS`, `Pagination` |
471
+ | `components/data-table-filter-popover` | `FilterPopover` |
472
+ | `components/combobox-core` | _`ComboOption`_ |
473
+
474
+ ### shell
475
+
476
+ | Module | Exports |
477
+ |---|---|
478
+ | `shell/topbar-controls` | `LanguageMenu`, `PaletteMenu`, `ThemeToggle`, `TOPBAR_MENU_ITEM_CLASS`, `TOPBAR_TRIGGER_CLASS`, _`LanguageOption`_ |
479
+ | `shell/top-bar` | `TopBar` |
480
+ | `shell/app-shell` | `AppShell`, _`AppShellNavItem`_, _`AppShellSubItem`_ |
481
+ | `shell/option-switcher-menu` | `OptionSwitcherMenu`, _`OptionSwitcherOption`_ |
482
+ | `shell/role-switcher` | `RoleSwitcher`, _`RoleSwitcherProps`_ |
483
+ | `shell/topbar-action-menu` | `TopBarActionMenu`, _`TopBarMenuEntry`_ |
484
+
485
+ ### feedback
486
+
487
+ | Module | Exports |
488
+ |---|---|
489
+ | `feedback/feedback-attachment` | `DEFAULT_ATTACHMENT_ACCEPT`, `DEFAULT_MAX_ATTACHMENT_BYTES`, `FeedbackAttachmentField`, `pastedName` |
490
+ | `feedback/feedback-dialog` | `FeedbackDialog`, _`FeedbackAttachmentLabels`_, _`FeedbackCategoryOption`_, _`FeedbackDialogLabels`_, _`FeedbackSubmission`_ |
491
+ | `feedback/feedback-inbox` | `FEEDBACK_CATEGORY_META`, `FEEDBACK_CATEGORY_ORDER`, `FEEDBACK_STATUS_META`, `FEEDBACK_STATUS_ORDER`, `FeedbackCategoryBadge`, `feedbackCategoryRank`, `FeedbackDetail`, `FeedbackDetailSection`, `FeedbackNoteEditor`, `FeedbackProse`, `FeedbackStatusBadge`, `FeedbackStatusTransitions`, `nextFeedbackStatus`, `selectableFeedbackStatuses`, `visibleFeedbackStatuses`, _`FeedbackCategory`_, _`FeedbackNoteAttachment`_, _`FeedbackStatus`_ |
492
+
493
+ ### wizard
494
+
495
+ | Module | Exports |
496
+ |---|---|
497
+ | `wizard/types` | `DEFAULT_WIZARD_LABELS`, `resolveWizardLabels`, _`FieldErrors`_, _`StepStatus`_, _`SummaryItem`_, _`SummarySection`_, _`UseWizardOptions`_, _`UseWizardReturn`_, _`ValidateResult`_, _`WizardLabels`_, _`WizardStepConfig`_ |
498
+ | `wizard/use-wizard` | `useWizard` |
499
+ | `wizard/wizard-context` | `useWizardContext`, `WizardContextProvider`, _`WizardContextValue`_ |
500
+ | `wizard/validation` | `requiredFieldsValidator`, _`RequiredFieldSpec`_ |
501
+ | `wizard/wizard-step` | `WizardStep` |
502
+ | `wizard/wizard-summary` | `WizardSummary` |
503
+ | `wizard/stepper-nav` | `StepperNav` |
504
+
505
+ ### tour
506
+
507
+ | Module | Exports |
508
+ |---|---|
509
+ | `tour/tour` | `TourProvider`, `useTour`, `useTourOptional`, _`TourLabels`_, _`TourPlacement`_, _`TourStep`_ |
510
+
511
+ ### search
512
+
513
+ | Module | Exports |
514
+ |---|---|
515
+ | `search/command-palette` | `CommandPalette`, `useCommandKey`, _`CommandItem`_, _`CommandPaletteLabels`_ |
516
+
517
+ <!-- END GENERATED: exports -->
138
518
 
139
519
  ## Forms / refs
140
520
 
@@ -145,14 +525,76 @@ focus-and-scroll-to-error for free.
145
525
 
146
526
  ## i18n
147
527
 
148
- The package carries no translation catalog. Components with user-facing text take
149
- **label props with English defaults** — pass your own translated strings:
528
+ **The kit resolves no strings.** It carries no translation catalogue, no locale detection
529
+ and no `t()`. Every string it renders is a key in one typed tree, `UiKitLabels`, with an
530
+ English default — and the app hands its translation to every component at once:
150
531
 
151
532
  ```tsx
152
- <MultiSelect allLabel={t("all")} searchLabel={t("search")} … />
153
- <DataTable labels={{ columns: t("table.columns"), presets: { today: t("today") }, … }} … />
533
+ import { UiKitProvider } from "@eifi1/ui-kit";
534
+
535
+ <UiKitProvider labels={de} locale="de-DE"> {/* de: UiKitLabels, or any part of it */}
536
+ <App />
537
+ </UiKitProvider>
538
+ ```
539
+
540
+ Precedence is fixed: **a component's own prop > the provider > the English default.** So
541
+ one table can still say `labels={{ table: "Transactions" }}` inside a German app, and a
542
+ component outside any provider behaves exactly as it always did.
543
+
544
+ The tree is namespaced by component and addressed by dot path — `dataTable.pageSize`,
545
+ `miniCalendar.previousMonth`, `datePicker.today`, `appShell.collapse`,
546
+ `common.fieldValue` — and `DEFAULT_UI_KIT_LABELS` is the whole English reference in one
547
+ object. Write the translation against its type and `tsc` refuses a missing key; for a
548
+ translation built at runtime, assert in the app's own test:
549
+
550
+ ```ts
551
+ expect(missingKitLabels(de, DEFAULT_UI_KIT_LABELS)).toEqual([]);
154
552
  ```
155
553
 
554
+ The provider's `locale` reaches every `Intl` formatter in the kit that is not handed a
555
+ `locale` prop of its own: calendar month and weekday names, day numbers, the data table's
556
+ counts, file sizes.
557
+
558
+ **Why a provider, when every component already took a `labels` prop.** Because a prop has
559
+ to be passed at every call site, under a different name per component (`labels`,
560
+ `calendarLabels`, `passwordLabels`, `clearLabel`, `ariaLabel` …), and one forgotten prop is
561
+ one English word in a German UI that nothing reports. Worse, a component NESTED inside
562
+ another — the calendar inside the data table's date filter, the popover inside the date
563
+ picker — could not be reached from the outer call site at all. The per-component props
564
+ still work and still win; they are now the exception rather than the mechanism.
565
+
566
+ **A label that interpolates a value is a function of that value, never a template.** Word
567
+ order, pluralisation and where the number goes are the translator's business, and a string
568
+ with a `{count}` hole in it decides all three on their behalf:
569
+
570
+ ```ts
571
+ // UiKitLabels["dataTable"]
572
+ pageChanged: (page: number, totalPages: number) => string;
573
+ // UiKitLabels["common"] — even "Label: value" is not universal punctuation
574
+ fieldValue: (field: string, value: string) => string;
575
+ ```
576
+
577
+ ### The worked example
578
+
579
+ `showcase/src/i18n/` runs the whole showcase in seven locales — English, German, French,
580
+ Italian, Spanish, Hungarian and Chinese — and it is deliberately **not** an i18n library: a
581
+ dictionary in context, a hook to read it, and ONE `<UiKitProvider labels={dict.kit}
582
+ locale={dict.tag}>` at the root. Each dictionary's `kit` is typed as the full
583
+ `UiKitLabels`, so a translation with a hole does not compile; the Localisation page shows
584
+ the tree and the per-language completeness live. The long explanatory prose on each page is
585
+ *not* translated: it is developer documentation about the kit's internals. The chrome, the
586
+ navigation and every component label are.
587
+
588
+ ### Right-to-left is partial
589
+
590
+ Newer components (the sidebar's inline groups, the date range band, the month picker, the
591
+ checkbox, switch and slider) use logical properties (`ms-*`, `pe-*`, `text-start`) and
592
+ flip correctly under `dir="rtl"`. The older ones still carry roughly 130 physical-direction
593
+ utilities plus pointer maths (column resize, row swipe) that assume left-to-right —
594
+ `docs/module-audit-2026-09-22.md` §10 has the site-by-site detail. None of the showcase's
595
+ seven locales is right-to-left, so nothing exercises it today; plan around that before
596
+ shipping Arabic or Hebrew.
597
+
156
598
  ## Wizard
157
599
 
158
600
  A multi-step form engine: a step machine with per-step validation gates, collected
@@ -182,11 +624,9 @@ const wizard = useWizard<LeaseDraft>({
182
624
  </WizardContextProvider>
183
625
  ```
184
626
 
185
- A step gates forward navigation three ways, and `goNext` runs all of them:
186
- its `validate` in the config above, `useWizardStepValidate(fn)` for a step that
187
- checks by hand, and `useRhfWizardStep(form, onValid)` for a react-hook-form step
188
- (which also reports its own inline messages). `useWizardNextGate(blocked)`
189
- disables Next/Skip outright.
627
+ A step gates forward navigation two ways, and `goNext` runs both: its `validate`
628
+ in the config above, and `useWizardStepValidate(fn)` for a step that checks by
629
+ hand. `useWizardNextGate(blocked)` disables Next/Skip outright.
190
630
 
191
631
  Like the rest of the package it resolves **no strings**: a step carries a `label`
192
632
  node, and the chrome takes a `labels` object (`WizardLabels`, every key optional
@@ -194,10 +634,11 @@ over an English default) — the same split `DataTable` and `TourProvider` use.
194
634
  app with i18n wraps `useWizard`/`StepperNav`/`WizardSummary` once and maps its
195
635
  own keys; see Kastlan's `shared/components/wizard/app-wizard.tsx`.
196
636
 
197
- **Optional peers.** `react-hook-form` is needed only by `useRhfWizardStep`, and
198
- only as a type. `react-router` backs the `?step=` sync in `useWizard`. `sonner`
199
- carries the "fill in the required fields" toast and is imported dynamically, on
200
- that failure path only — pass `onValidationFailed` to route it elsewhere.
637
+ **Peers.** `react-router` backs the `?step=` sync in `useWizard` — and is imported
638
+ unconditionally, so a wizard needs a Router mounted even if you never read the
639
+ step from the URL. `sonner` carries the "fill in the required fields" toast and is
640
+ imported dynamically, on that failure path only — pass `onValidationFailed` to
641
+ route it elsewhere.
201
642
 
202
643
  ## Shell
203
644