@eifi1/ui-kit 0.4.1 → 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 +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 +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 +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 +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 +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 +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 +5 -3
  176. package/dist/components/user-avatar.js +4 -2
  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 +14 -1
  270. package/dist/theme/palette-presets.js +231 -3
  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 +66 -13
  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
@@ -0,0 +1,221 @@
1
+ import { useId, useMemo } from "react";
2
+ import type { ReactNode } from "react";
3
+ import { Check } from "lucide-react";
4
+ import { cn } from "../lib/cn";
5
+ import { Button } from "../components/ui";
6
+ import { Modal } from "../components/modal";
7
+ import { alertFrameClass } from "../components/alert-banner";
8
+ import { WizardContextProvider } from "./wizard-context";
9
+ import { DEFAULT_WIZARD_LABELS } from "./types";
10
+ import { useKitLabels } from "../i18n/kit-labels";
11
+ import type { UseWizardReturn, WizardLabels } from "./types";
12
+
13
+ /**
14
+ * The chrome around a wizard: the step indicator, the step content, and the
15
+ * Cancel / Back / Skip / Next / Finish bar — plus the cancel-confirmation
16
+ * dialog, because "are you sure you want to lose this" is part of the wizard's
17
+ * contract rather than something each app should re-decide.
18
+ *
19
+ * It is a component and not a set of parts for one reason: which button shows,
20
+ * and whether it is enabled, is a function of `wizard` state that was getting
21
+ * re-derived (and re-derived slightly differently) at every call site. Finish is
22
+ * gated on `canFinish`, Next and Skip on `nextBlocked`, and Skip only appears on
23
+ * an `optional` step that is not the last — that policy lives here now.
24
+ *
25
+ * The `<StepperNav>` is also what publishes {@link WizardContextProvider}, which
26
+ * is how a mounted step registers its own validator. A step's
27
+ * `useRhfWizardStep` / `useWizardStepValidate` therefore only works inside one.
28
+ */
29
+ export function StepperNav<TData extends Record<string, unknown>>({
30
+ wizard,
31
+ children,
32
+ title,
33
+ description,
34
+ className,
35
+ labels,
36
+ }: {
37
+ wizard: UseWizardReturn<TData>;
38
+ children: ReactNode;
39
+ title?: ReactNode;
40
+ description?: ReactNode;
41
+ className?: string;
42
+ labels?: Partial<WizardLabels>;
43
+ }) {
44
+ const l = useKitLabels("wizard", DEFAULT_WIZARD_LABELS, labels);
45
+ const cancelTitleId = useId();
46
+
47
+ const contextValue = useMemo(
48
+ () => ({
49
+ registerStepValidate: wizard.registerStepValidate,
50
+ setNextBlocked: wizard.setNextBlocked,
51
+ }),
52
+ [wizard.registerStepValidate, wizard.setNextBlocked],
53
+ );
54
+
55
+ // Finish is only valid once every step before the last has been completed or
56
+ // skipped (derived once in useWizard). Prevents a restored last-step index
57
+ // (empty data after a reload) from firing an empty submit.
58
+ const canFinish = wizard.canFinish;
59
+
60
+ return (
61
+ <div className={cn("flex flex-col gap-6", className)}>
62
+ {(title || description) && (
63
+ <div>
64
+ {title && (
65
+ <h1 className="text-2xl font-bold tracking-tight text-[var(--text-primary)]">
66
+ {title}
67
+ </h1>
68
+ )}
69
+ {description && (
70
+ <p className="mt-1 text-sm text-[var(--text-muted)]">{description}</p>
71
+ )}
72
+ </div>
73
+ )}
74
+
75
+ {/* Step indicator */}
76
+ <nav aria-label={l.steps}>
77
+ <ol className="flex w-full items-center">
78
+ {wizard.steps.map((step, index) => {
79
+ const status = wizard.stepStatus(index);
80
+ const isLast = index === wizard.steps.length - 1;
81
+
82
+ return (
83
+ <li key={step.id} className={cn("flex items-center", !isLast && "flex-1")}>
84
+ <button
85
+ type="button"
86
+ onClick={() => wizard.goToStep(index)}
87
+ disabled={status === "upcoming"}
88
+ aria-current={status === "active" ? "step" : undefined}
89
+ className={cn(
90
+ "group flex flex-col items-center gap-1.5",
91
+ status === "upcoming" ? "cursor-default" : "cursor-pointer",
92
+ )}
93
+ >
94
+ {/* Circle */}
95
+ <span
96
+ className={cn(
97
+ "flex size-8 shrink-0 items-center justify-center rounded-full border-2 text-xs font-semibold transition-colors",
98
+ status === "completed" &&
99
+ "border-[var(--brand)] bg-[var(--brand)] text-[var(--brand-contrast)]",
100
+ status === "active" &&
101
+ "border-[var(--brand)] bg-[var(--bg-surface)] text-[var(--brand)]",
102
+ status === "upcoming" &&
103
+ "border-[var(--border)] bg-[var(--bg-surface)] text-[var(--text-placeholder)]",
104
+ status === "skipped" &&
105
+ "border-[var(--border)] bg-[var(--bg-surface-2)] text-[var(--text-muted)]",
106
+ )}
107
+ >
108
+ {status === "completed" ? <Check className="size-4" /> : index + 1}
109
+ </span>
110
+ {/* Label — hidden on mobile, where the line below carries it */}
111
+ <span
112
+ className={cn(
113
+ "hidden text-xs font-medium md:block",
114
+ status === "active" || status === "completed"
115
+ ? "text-[var(--text-primary)]"
116
+ : "text-[var(--text-muted)]",
117
+ )}
118
+ >
119
+ {step.label}
120
+ </span>
121
+ </button>
122
+
123
+ {/* Connector line */}
124
+ {!isLast && (
125
+ <div
126
+ className={cn(
127
+ "mx-2 h-0.5 flex-1",
128
+ status === "completed" ? "bg-[var(--brand)]" : "bg-[var(--border)]",
129
+ )}
130
+ />
131
+ )}
132
+ </li>
133
+ );
134
+ })}
135
+ </ol>
136
+ {/* Mobile: the labels above are hidden, so name the current step here */}
137
+ <p className="mt-2 text-center text-sm font-medium text-[var(--text-primary)] md:hidden">
138
+ {l.step(wizard.currentStepIndex + 1, wizard.steps.length)}
139
+ {" — "}
140
+ {wizard.currentStep.label}
141
+ </p>
142
+ </nav>
143
+
144
+ {/* Step content */}
145
+ <WizardContextProvider value={contextValue}>
146
+ <div className="min-h-[300px]">{children}</div>
147
+ </WizardContextProvider>
148
+
149
+ {/* Submit error */}
150
+ {wizard.error && (
151
+ <div
152
+ role="alert"
153
+ className={cn(
154
+ "text-sm text-[var(--danger)]",
155
+ alertFrameClass("danger"),
156
+ )}
157
+ >
158
+ {wizard.error}
159
+ </div>
160
+ )}
161
+
162
+ {/* Navigation bar */}
163
+ <div className="flex items-center justify-between border-t border-[var(--border)] pt-4">
164
+ <Button variant="secondary" onClick={wizard.cancel}>
165
+ {l.cancel}
166
+ </Button>
167
+ <div className="flex items-center gap-2">
168
+ {!wizard.isFirstStep && (
169
+ <Button variant="secondary" onClick={wizard.goBack}>
170
+ {l.back}
171
+ </Button>
172
+ )}
173
+ {wizard.currentStep.optional && !wizard.isLastStep && (
174
+ <Button variant="ghost" onClick={wizard.skip} disabled={wizard.nextBlocked}>
175
+ {l.skip}
176
+ </Button>
177
+ )}
178
+ {wizard.isLastStep ? (
179
+ <Button
180
+ variant="brand"
181
+ data-tour="wizard-finish"
182
+ onClick={wizard.finish}
183
+ disabled={wizard.isSubmitting || !canFinish}
184
+ >
185
+ {wizard.isSubmitting ? l.submitting : l.finish}
186
+ </Button>
187
+ ) : (
188
+ <Button
189
+ variant="brand"
190
+ data-tour="wizard-next"
191
+ onClick={wizard.goNext}
192
+ disabled={wizard.nextBlocked}
193
+ >
194
+ {l.next}
195
+ </Button>
196
+ )}
197
+ </div>
198
+ </div>
199
+
200
+ {/* Cancel confirmation */}
201
+ {wizard.showCancelDialog && (
202
+ <Modal onClose={wizard.dismissCancel} labelledBy={cancelTitleId} className="space-y-4">
203
+ <div className="space-y-1.5">
204
+ <h2 id={cancelTitleId} className="text-lg font-semibold text-[var(--text-primary)]">
205
+ {l.cancelTitle}
206
+ </h2>
207
+ <p className="text-sm text-[var(--text-muted)]">{l.confirmCancel}</p>
208
+ </div>
209
+ <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
210
+ <Button variant="secondary" onClick={wizard.dismissCancel}>
211
+ {l.cancelDismissLabel}
212
+ </Button>
213
+ <Button variant="danger" onClick={wizard.confirmCancel}>
214
+ {l.cancelConfirmLabel}
215
+ </Button>
216
+ </div>
217
+ </Modal>
218
+ )}
219
+ </div>
220
+ );
221
+ }
@@ -0,0 +1,178 @@
1
+ import type { ReactNode } from "react";
2
+
3
+ export type FieldErrors = Record<string, string>;
4
+
5
+ export type ValidateResult = boolean | { ok: boolean; errors?: FieldErrors };
6
+
7
+ export interface WizardStepConfig {
8
+ /** Unique step identifier. */
9
+ id: string;
10
+ /**
11
+ * What the step is called in the indicator.
12
+ *
13
+ * A `ReactNode`, not a translation key: the engine never resolves strings.
14
+ * An app with i18n maps its own keys at the `useWizard` call — the same split
15
+ * `TourStep` and `DataTableLabels` already use.
16
+ */
17
+ label: ReactNode;
18
+ /** Whether the step can be skipped. */
19
+ optional?: boolean;
20
+ /**
21
+ * Validation gate before advancing.
22
+ * - Return `true` / `false` to just block.
23
+ * - Return `{ ok: false, errors: { fieldName: "message" } }` to also surface
24
+ * per-field error messages via `wizard.fieldErrors`.
25
+ */
26
+ validate?: () => ValidateResult | Promise<ValidateResult>;
27
+ }
28
+
29
+ export interface UseWizardOptions<TData extends Record<string, unknown>> {
30
+ steps: WizardStepConfig[];
31
+ initialData?: Partial<TData>;
32
+ onComplete?: (data: TData) => void | Promise<void>;
33
+ onCancel?: () => void;
34
+ /**
35
+ * Shown when a step blocks with no per-field detail — an RHF step surfacing
36
+ * its own inline messages, say — so the user learns why the wizard did not
37
+ * advance. Falls back to `wizard.missingRequired` from the {@link UiKitProvider},
38
+ * then to English.
39
+ */
40
+ missingRequiredMessage?: string;
41
+ /**
42
+ * How to surface {@link missingRequiredMessage}. Defaults to a `sonner` toast
43
+ * (an optional peer, imported only when this actually fires). Pass your own to
44
+ * route it somewhere else, or to a no-op to silence it.
45
+ */
46
+ onValidationFailed?: (message: string) => void;
47
+ }
48
+
49
+ export type StepStatus = "upcoming" | "active" | "completed" | "skipped";
50
+
51
+ export interface UseWizardReturn<TData extends Record<string, unknown>> {
52
+ // Navigation
53
+ currentStepIndex: number;
54
+ currentStep: WizardStepConfig;
55
+ steps: WizardStepConfig[];
56
+ isFirstStep: boolean;
57
+ isLastStep: boolean;
58
+ /** True once every step before the last has been completed or skipped. */
59
+ canFinish: boolean;
60
+ goNext: () => Promise<void>;
61
+ goBack: () => void;
62
+ goToStep: (index: number) => void;
63
+ skip: () => void;
64
+ cancel: () => void;
65
+ finish: () => Promise<void>;
66
+ /** Register a validator for the mounted step (used by useRhfWizardStep). */
67
+ registerStepValidate: (
68
+ fn: () => ValidateResult | Promise<ValidateResult>,
69
+ ) => () => void;
70
+ /** True when the mounted step has blocked forward navigation (Next/Skip disabled). */
71
+ nextBlocked: boolean;
72
+ /** Set by the active step (via useWizardNextGate) to disable/enable Next+Skip. */
73
+ setNextBlocked: (blocked: boolean) => void;
74
+
75
+ // Step state
76
+ stepStatus: (index: number) => StepStatus;
77
+ completedSteps: Set<number>;
78
+
79
+ // Data
80
+ data: TData;
81
+ updateData: (partial: Partial<TData>) => void;
82
+
83
+ // Loading / error
84
+ isSubmitting: boolean;
85
+ error: string | null;
86
+ clearError: () => void;
87
+
88
+ // Per-field validation errors (populated by the last failed goNext)
89
+ fieldErrors: FieldErrors;
90
+ clearFieldErrors: () => void;
91
+
92
+ // Cancel dialog
93
+ showCancelDialog: boolean;
94
+ confirmCancel: () => void;
95
+ dismissCancel: () => void;
96
+ }
97
+
98
+ export interface SummaryItem {
99
+ label: ReactNode;
100
+ value: ReactNode;
101
+ }
102
+
103
+ export interface SummarySection {
104
+ label: ReactNode;
105
+ /** Which step the section's edit button jumps back to. */
106
+ stepIndex: number;
107
+ items: SummaryItem[];
108
+ }
109
+
110
+ /**
111
+ * Every string the wizard chrome shows. All optional with English defaults, so a
112
+ * monolingual app can mount `StepperNav` bare; a translated app passes the whole
113
+ * object once (typically from a thin app-side wrapper).
114
+ */
115
+ export interface WizardLabels {
116
+ cancel: string;
117
+ back: string;
118
+ next: string;
119
+ skip: string;
120
+ finish: string;
121
+ /** Shown on Finish while `isSubmitting`. */
122
+ submitting: string;
123
+ /** `aria-label` for the step indicator's `<nav>`. */
124
+ steps: string;
125
+ /** The mobile "Step 2 of 5" line. */
126
+ step: (current: number, total: number) => string;
127
+ /** Heading of the cancel-confirmation dialog. */
128
+ cancelTitle: string;
129
+ /** Body of the cancel-confirmation dialog. */
130
+ confirmCancel: string;
131
+ /** Confirm button in the cancel dialog. */
132
+ cancelConfirmLabel: string;
133
+ /** Dismiss button in the cancel dialog ("keep editing"). */
134
+ cancelDismissLabel: string;
135
+ /** Heading above a {@link WizardSummary}. */
136
+ reviewTitle: string;
137
+ /** `aria-label` on a summary section's edit button. */
138
+ edit: string;
139
+ /**
140
+ * Toasted (or handed to `onValidationFailed`) when a step blocks Next without
141
+ * saying which field is at fault. `useWizard`'s `missingRequiredMessage` wins.
142
+ *
143
+ * This and `genericError` are OPTIONAL, unlike every key above, for the reason
144
+ * `TwoFactorSettingLabels.qrAlt` is: apps annotate a full translation as
145
+ * `const DE: WizardLabels = {…}`, and a new required key would be a compile error
146
+ * in each of them on the next update. The defaults below always carry both.
147
+ */
148
+ missingRequired?: string;
149
+ /** `wizard.error` when `onComplete` rejects with nothing readable — a thrown
150
+ * non-Error, or an Error whose message is empty. Optional: see above. */
151
+ genericError?: string;
152
+ }
153
+
154
+ /** Typed with the two optional keys made required, so code reading the defaults
155
+ * directly (the fallback in `useWizard`) needs no `!`. */
156
+ export const DEFAULT_WIZARD_LABELS: WizardLabels &
157
+ Required<Pick<WizardLabels, "missingRequired" | "genericError">> = {
158
+ cancel: "Cancel",
159
+ back: "Back",
160
+ next: "Next",
161
+ skip: "Skip",
162
+ finish: "Finish",
163
+ submitting: "Creating…",
164
+ steps: "Steps",
165
+ step: (current, total) => `Step ${current} of ${total}`,
166
+ cancelTitle: "Discard this form?",
167
+ confirmCancel: "Your entries will be lost.",
168
+ cancelConfirmLabel: "Discard",
169
+ cancelDismissLabel: "Keep editing",
170
+ reviewTitle: "Review",
171
+ edit: "Edit",
172
+ missingRequired: "Please fill in all required fields.",
173
+ genericError: "An error occurred",
174
+ };
175
+
176
+ export function resolveWizardLabels(labels?: Partial<WizardLabels>): WizardLabels {
177
+ return labels ? { ...DEFAULT_WIZARD_LABELS, ...labels } : DEFAULT_WIZARD_LABELS;
178
+ }