@eifi1/ui-kit 0.34.0 → 0.36.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 (446) hide show
  1. package/README.md +115 -41
  2. package/dist/admin/role-select.d.ts +3 -2
  3. package/dist/admin/role-select.js +2 -0
  4. package/dist/admin/role-select.js.map +1 -1
  5. package/dist/billing/billing-banner.d.ts +5 -2
  6. package/dist/billing/billing-banner.js.map +1 -1
  7. package/dist/billing/plan-limit-notice.d.ts +5 -2
  8. package/dist/billing/plan-limit-notice.js.map +1 -1
  9. package/dist/chart.js.map +1 -1
  10. package/dist/components/amount-input.d.ts +2 -5
  11. package/dist/components/amount-input.js +2 -2
  12. package/dist/components/amount-input.js.map +1 -1
  13. package/dist/components/autocomplete.d.ts +2 -2
  14. package/dist/components/autocomplete.js +2 -1
  15. package/dist/components/autocomplete.js.map +1 -1
  16. package/dist/components/button-look.d.ts +1 -1
  17. package/dist/components/button-look.js +9 -4
  18. package/dist/components/button-look.js.map +1 -1
  19. package/dist/components/calculator.d.ts +1 -4
  20. package/dist/components/calculator.js +1 -3
  21. package/dist/components/calculator.js.map +1 -1
  22. package/dist/components/chart-zoom.d.ts +0 -37
  23. package/dist/components/chart-zoom.js +1 -28
  24. package/dist/components/chart-zoom.js.map +1 -1
  25. package/dist/components/checkbox-group.d.ts +5 -2
  26. package/dist/components/checkbox-group.js +15 -4
  27. package/dist/components/checkbox-group.js.map +1 -1
  28. package/dist/components/chip-input.d.ts +0 -4
  29. package/dist/components/chip-input.js +1 -5
  30. package/dist/components/chip-input.js.map +1 -1
  31. package/dist/components/column-mapper.d.ts +5 -3
  32. package/dist/components/column-mapper.js +2 -0
  33. package/dist/components/column-mapper.js.map +1 -1
  34. package/dist/components/combobox.d.ts +3 -3
  35. package/dist/components/combobox.js +2 -1
  36. package/dist/components/combobox.js.map +1 -1
  37. package/dist/components/copy-button.d.ts +5 -1
  38. package/dist/components/copy-button.js.map +1 -1
  39. package/dist/components/country-select.d.ts +3 -3
  40. package/dist/components/country-select.js +3 -0
  41. package/dist/components/country-select.js.map +1 -1
  42. package/dist/components/currency-option-list.d.ts +3 -8
  43. package/dist/components/currency-option-list.js +1 -29
  44. package/dist/components/currency-option-list.js.map +1 -1
  45. package/dist/components/currency-select.d.ts +3 -2
  46. package/dist/components/currency-select.js +10 -1
  47. package/dist/components/currency-select.js.map +1 -1
  48. package/dist/components/danger-confirm.d.ts +3 -3
  49. package/dist/components/danger-confirm.js.map +1 -1
  50. package/dist/components/data-table-filter-popover.d.ts +1 -1
  51. package/dist/components/data-table-filter-popover.js +1 -1
  52. package/dist/components/data-table-filter-popover.js.map +1 -1
  53. package/dist/components/data-table-labels.d.ts +1 -42
  54. package/dist/components/data-table-labels.js +2 -31
  55. package/dist/components/data-table-labels.js.map +1 -1
  56. package/dist/components/data-table-shared.d.ts +17 -1
  57. package/dist/components/data-table-shared.js +22 -0
  58. package/dist/components/data-table-shared.js.map +1 -1
  59. package/dist/components/data-table.d.ts +12 -2
  60. package/dist/components/data-table.js +18 -14
  61. package/dist/components/data-table.js.map +1 -1
  62. package/dist/components/date-field.d.ts +2 -1
  63. package/dist/components/date-field.js.map +1 -1
  64. package/dist/components/date-picker.js +3 -0
  65. package/dist/components/date-picker.js.map +1 -1
  66. package/dist/components/date-range-picker.js +3 -0
  67. package/dist/components/date-range-picker.js.map +1 -1
  68. package/dist/components/dialog-frame.d.ts +3 -1
  69. package/dist/components/dialog-frame.js.map +1 -1
  70. package/dist/components/dropdown.d.ts +18 -15
  71. package/dist/components/dropdown.js +11 -3
  72. package/dist/components/dropdown.js.map +1 -1
  73. package/dist/components/entity-combobox.d.ts +3 -3
  74. package/dist/components/entity-combobox.js +2 -1
  75. package/dist/components/entity-combobox.js.map +1 -1
  76. package/dist/components/field-base.d.ts +0 -5
  77. package/dist/components/field-base.js +0 -5
  78. package/dist/components/field-base.js.map +1 -1
  79. package/dist/components/field-parts.d.ts +69 -22
  80. package/dist/components/field-parts.js +33 -19
  81. package/dist/components/field-parts.js.map +1 -1
  82. package/dist/components/field-strip.d.ts +9 -23
  83. package/dist/components/field-strip.js +26 -23
  84. package/dist/components/field-strip.js.map +1 -1
  85. package/dist/components/field-sync.d.ts +0 -4
  86. package/dist/components/field-sync.js +0 -4
  87. package/dist/components/field-sync.js.map +1 -1
  88. package/dist/components/field.d.ts +7 -6
  89. package/dist/components/field.js +24 -15
  90. package/dist/components/field.js.map +1 -1
  91. package/dist/components/full-bleed-dialog.js +2 -2
  92. package/dist/components/full-bleed-dialog.js.map +1 -1
  93. package/dist/components/help-popover.d.ts +9 -7
  94. package/dist/components/help-popover.js.map +1 -1
  95. package/dist/components/hover-menu.d.ts +6 -13
  96. package/dist/components/hover-menu.js +3 -3
  97. package/dist/components/hover-menu.js.map +1 -1
  98. package/dist/components/icon-picker.d.ts +3 -2
  99. package/dist/components/icon-picker.js +3 -0
  100. package/dist/components/icon-picker.js.map +1 -1
  101. package/dist/components/inline-entity-combobox.d.ts +3 -3
  102. package/dist/components/inline-entity-combobox.js +2 -1
  103. package/dist/components/inline-entity-combobox.js.map +1 -1
  104. package/dist/components/input.d.ts +2 -2
  105. package/dist/components/input.js +2 -1
  106. package/dist/components/input.js.map +1 -1
  107. package/dist/components/modal.d.ts +9 -1
  108. package/dist/components/modal.js +7 -4
  109. package/dist/components/modal.js.map +1 -1
  110. package/dist/components/month-picker.d.ts +2 -1
  111. package/dist/components/month-picker.js +8 -1
  112. package/dist/components/month-picker.js.map +1 -1
  113. package/dist/components/multi-entity-combobox.d.ts +2 -2
  114. package/dist/components/multi-entity-combobox.js +2 -1
  115. package/dist/components/multi-entity-combobox.js.map +1 -1
  116. package/dist/components/multi-select.d.ts +7 -18
  117. package/dist/components/multi-select.js +8 -10
  118. package/dist/components/multi-select.js.map +1 -1
  119. package/dist/components/number-input.d.ts +2 -5
  120. package/dist/components/number-input.js +2 -4
  121. package/dist/components/number-input.js.map +1 -1
  122. package/dist/components/numeric-field.d.ts +5 -2
  123. package/dist/components/numeric-field.js +4 -1
  124. package/dist/components/numeric-field.js.map +1 -1
  125. package/dist/components/one-time-code-input.d.ts +2 -1
  126. package/dist/components/one-time-code-input.js +2 -1
  127. package/dist/components/one-time-code-input.js.map +1 -1
  128. package/dist/components/phone-input.d.ts +1 -1
  129. package/dist/components/phone-input.js +4 -0
  130. package/dist/components/phone-input.js.map +1 -1
  131. package/dist/components/popover.js +3 -3
  132. package/dist/components/popover.js.map +1 -1
  133. package/dist/components/select.d.ts +4 -3
  134. package/dist/components/select.js +2 -1
  135. package/dist/components/select.js.map +1 -1
  136. package/dist/components/series-chart.js.map +1 -1
  137. package/dist/components/server-wake.d.ts +0 -6
  138. package/dist/components/server-wake.js.map +1 -1
  139. package/dist/components/settings-fields.d.ts +4 -2
  140. package/dist/components/settings-fields.js.map +1 -1
  141. package/dist/components/slider.d.ts +3 -2
  142. package/dist/components/slider.js +7 -1
  143. package/dist/components/slider.js.map +1 -1
  144. package/dist/components/stat-tile.d.ts +8 -2
  145. package/dist/components/stat-tile.js +2 -11
  146. package/dist/components/stat-tile.js.map +1 -1
  147. package/dist/components/swatch-picker.d.ts +3 -2
  148. package/dist/components/swatch-picker.js +3 -0
  149. package/dist/components/swatch-picker.js.map +1 -1
  150. package/dist/components/swipeable-row.d.ts +2 -17
  151. package/dist/components/swipeable-row.js +11 -16
  152. package/dist/components/swipeable-row.js.map +1 -1
  153. package/dist/components/text-link.js +3 -1
  154. package/dist/components/text-link.js.map +1 -1
  155. package/dist/components/textarea.d.ts +2 -1
  156. package/dist/components/textarea.js +9 -3
  157. package/dist/components/textarea.js.map +1 -1
  158. package/dist/components/toggle-group.d.ts +2 -2
  159. package/dist/components/toggle-group.js +7 -3
  160. package/dist/components/toggle-group.js.map +1 -1
  161. package/dist/components/tooltip.d.ts +9 -1
  162. package/dist/components/tooltip.js +20 -5
  163. package/dist/components/tooltip.js.map +1 -1
  164. package/dist/components/translation-review.d.ts +10 -2
  165. package/dist/components/translation-review.js +11 -3
  166. package/dist/components/translation-review.js.map +1 -1
  167. package/dist/components/use-table-state.d.ts +31 -3
  168. package/dist/components/use-table-state.js +53 -8
  169. package/dist/components/use-table-state.js.map +1 -1
  170. package/dist/components/user-avatar.d.ts +2 -2
  171. package/dist/components/user-avatar.js.map +1 -1
  172. package/dist/components/wizard-stepper.d.ts +1 -4
  173. package/dist/components/wizard-stepper.js +2 -3
  174. package/dist/components/wizard-stepper.js.map +1 -1
  175. package/dist/currencies.d.ts +23 -0
  176. package/dist/currencies.js +38 -0
  177. package/dist/currencies.js.map +1 -0
  178. package/dist/demo/demo-banner.d.ts +7 -2
  179. package/dist/demo/demo-banner.js.map +1 -1
  180. package/dist/eslint/index.d.ts +83 -0
  181. package/dist/eslint/index.js +69 -0
  182. package/dist/eslint/index.js.map +1 -0
  183. package/dist/eslint/role-utilities.d.ts +48 -0
  184. package/dist/eslint/role-utilities.generated.d.ts +2 -0
  185. package/dist/eslint/role-utilities.generated.js +143 -0
  186. package/dist/eslint/role-utilities.generated.js.map +1 -0
  187. package/dist/eslint/role-utilities.js +43 -0
  188. package/dist/eslint/role-utilities.js.map +1 -0
  189. package/dist/feedback/feedback-menu.d.ts +2 -2
  190. package/dist/feedback/feedback-menu.js.map +1 -1
  191. package/dist/feedback/feedback-thread.d.ts +3 -8
  192. package/dist/feedback/feedback-thread.js +0 -2
  193. package/dist/feedback/feedback-thread.js.map +1 -1
  194. package/dist/hooks/use-dismiss.d.ts +16 -3
  195. package/dist/hooks/use-dismiss.js +14 -2
  196. package/dist/hooks/use-dismiss.js.map +1 -1
  197. package/dist/i18n/defaults.js +5 -1
  198. package/dist/i18n/defaults.js.map +1 -1
  199. package/dist/i18n/german.js +97 -1
  200. package/dist/i18n/german.js.map +1 -1
  201. package/dist/i18n/kit-labels.d.ts +29 -4
  202. package/dist/i18n/kit-labels.js +21 -1
  203. package/dist/i18n/kit-labels.js.map +1 -1
  204. package/dist/i18n/locales/en.js +104 -3
  205. package/dist/i18n/locales/en.js.map +3 -3
  206. package/dist/i18n/locales/es.js +95 -1
  207. package/dist/i18n/locales/es.js.map +1 -1
  208. package/dist/i18n/locales/fr.js +99 -3
  209. package/dist/i18n/locales/fr.js.map +1 -1
  210. package/dist/i18n/locales/hu.js +95 -1
  211. package/dist/i18n/locales/hu.js.map +1 -1
  212. package/dist/i18n/locales/it.js +99 -3
  213. package/dist/i18n/locales/it.js.map +1 -1
  214. package/dist/i18n/locales/zh.js +95 -1
  215. package/dist/i18n/locales/zh.js.map +1 -1
  216. package/dist/i18n/review.js +13 -0
  217. package/dist/i18n/review.js.map +1 -1
  218. package/dist/i18n/shared-labels.js +3 -1
  219. package/dist/i18n/shared-labels.js.map +1 -1
  220. package/dist/index.d.ts +23 -1
  221. package/dist/index.js +40 -2
  222. package/dist/index.js.map +1 -1
  223. package/dist/lib/device-settings.d.ts +72 -0
  224. package/dist/lib/device-settings.js +64 -0
  225. package/dist/lib/device-settings.js.map +1 -0
  226. package/dist/lib/plain-text.d.ts +11 -0
  227. package/dist/lib/plain-text.js +16 -0
  228. package/dist/lib/plain-text.js.map +1 -0
  229. package/dist/lib/refs.d.ts +13 -0
  230. package/dist/lib/refs.js +15 -0
  231. package/dist/lib/refs.js.map +1 -0
  232. package/dist/lib/safe-storage.d.ts +6 -0
  233. package/dist/lib/safe-storage.js +11 -0
  234. package/dist/lib/safe-storage.js.map +1 -1
  235. package/dist/notifications/notification-parts.d.ts +39 -0
  236. package/dist/notifications/notification-parts.js +47 -0
  237. package/dist/notifications/notification-parts.js.map +1 -0
  238. package/dist/notifications/notification-types-setting.d.ts +62 -0
  239. package/dist/notifications/notification-types-setting.js +192 -0
  240. package/dist/notifications/notification-types-setting.js.map +1 -0
  241. package/dist/notifications/notification-types.d.ts +75 -0
  242. package/dist/notifications/notification-types.js +2 -0
  243. package/dist/notifications/notification-types.js.map +1 -0
  244. package/dist/notifications/notifications-labels.d.ts +131 -0
  245. package/dist/notifications/notifications-labels.js +83 -0
  246. package/dist/notifications/notifications-labels.js.map +1 -0
  247. package/dist/notifications/push-device-setting.d.ts +37 -0
  248. package/dist/notifications/push-device-setting.js +164 -0
  249. package/dist/notifications/push-device-setting.js.map +1 -0
  250. package/dist/notifications/push-devices-setting.d.ts +44 -0
  251. package/dist/notifications/push-devices-setting.js +203 -0
  252. package/dist/notifications/push-devices-setting.js.map +1 -0
  253. package/dist/notifications/quiet-hours-setting.d.ts +47 -0
  254. package/dist/notifications/quiet-hours-setting.js +131 -0
  255. package/dist/notifications/quiet-hours-setting.js.map +1 -0
  256. package/dist/notifications/time-zone-select.d.ts +50 -0
  257. package/dist/notifications/time-zone-select.js +76 -0
  258. package/dist/notifications/time-zone-select.js.map +1 -0
  259. package/dist/notifications/unsubscribe-panel.d.ts +53 -0
  260. package/dist/notifications/unsubscribe-panel.js +139 -0
  261. package/dist/notifications/unsubscribe-panel.js.map +1 -0
  262. package/dist/notifications/use-push-device.d.ts +122 -0
  263. package/dist/notifications/use-push-device.js +230 -0
  264. package/dist/notifications/use-push-device.js.map +1 -0
  265. package/dist/rhf/fields.d.ts +36 -29
  266. package/dist/rhf/fields.js +51 -22
  267. package/dist/rhf/fields.js.map +1 -1
  268. package/dist/rhf/form-core.d.ts +5 -4
  269. package/dist/rhf/form-core.js.map +1 -1
  270. package/dist/rhf/form.d.ts +7 -36
  271. package/dist/rhf/form.js +1 -16
  272. package/dist/rhf/form.js.map +1 -1
  273. package/dist/rhf/line-items.d.ts +1 -1
  274. package/dist/rhf/line-items.js.map +1 -1
  275. package/dist/rhf/use-rhf-wizard-step.js.map +1 -1
  276. package/dist/rhf.js.map +1 -1
  277. package/dist/settings/device-reset-setting-labels.d.ts +3 -0
  278. package/dist/settings/device-reset-setting-labels.js +15 -0
  279. package/dist/settings/device-reset-setting-labels.js.map +1 -0
  280. package/dist/settings/device-reset-setting.d.ts +58 -0
  281. package/dist/settings/device-reset-setting.js +51 -0
  282. package/dist/settings/device-reset-setting.js.map +1 -0
  283. package/dist/shell/app-shell.js +5 -0
  284. package/dist/shell/app-shell.js.map +1 -1
  285. package/dist/shell/option-switcher-menu.d.ts +5 -17
  286. package/dist/shell/option-switcher-menu.js +1 -3
  287. package/dist/shell/option-switcher-menu.js.map +1 -1
  288. package/dist/shell/role-switcher.d.ts +1 -4
  289. package/dist/shell/role-switcher.js +2 -3
  290. package/dist/shell/role-switcher.js.map +1 -1
  291. package/dist/shell/topbar-action-menu.d.ts +7 -19
  292. package/dist/shell/topbar-action-menu.js +1 -3
  293. package/dist/shell/topbar-action-menu.js.map +1 -1
  294. package/dist/shell/topbar-controls.d.ts +3 -12
  295. package/dist/shell/topbar-controls.js +6 -9
  296. package/dist/shell/topbar-controls.js.map +1 -1
  297. package/dist/testing/index.d.ts +1 -1
  298. package/dist/testing/index.js +2 -0
  299. package/dist/testing/index.js.map +1 -1
  300. package/dist/testing/viewport.d.ts +25 -2
  301. package/dist/testing/viewport.js +61 -10
  302. package/dist/testing/viewport.js.map +1 -1
  303. package/dist/theme/contrast-tokens.d.ts +42 -4
  304. package/dist/theme/contrast-tokens.js +56 -9
  305. package/dist/theme/contrast-tokens.js.map +1 -1
  306. package/dist/theme/contrast.d.ts +4 -2
  307. package/dist/theme/contrast.js +13 -0
  308. package/dist/theme/contrast.js.map +1 -1
  309. package/dist/theme/palette-derive.d.ts +15 -1
  310. package/dist/theme/palette-derive.js +37 -8
  311. package/dist/theme/palette-derive.js.map +1 -1
  312. package/dist/theme/palette-presets.d.ts +2 -8
  313. package/dist/theme/palette-presets.js +5 -284
  314. package/dist/theme/palette-presets.js.map +1 -1
  315. package/dist/theme/palette-store.js +6 -0
  316. package/dist/theme/palette-store.js.map +1 -1
  317. package/dist/theme/text-size.js +6 -0
  318. package/dist/theme/text-size.js.map +1 -1
  319. package/dist/theme/theme-store.js +6 -0
  320. package/dist/theme/theme-store.js.map +1 -1
  321. package/dist/wizard/types.d.ts +0 -5
  322. package/dist/wizard/types.js +1 -5
  323. package/dist/wizard/types.js.map +1 -1
  324. package/package.json +9 -1
  325. package/src/admin/role-select.tsx +4 -1
  326. package/src/billing/billing-banner.tsx +5 -2
  327. package/src/billing/plan-limit-notice.tsx +5 -2
  328. package/src/chart.ts +5 -3
  329. package/src/components/amount-input.tsx +4 -7
  330. package/src/components/autocomplete.tsx +5 -2
  331. package/src/components/button-look.ts +15 -5
  332. package/src/components/calculator.tsx +2 -7
  333. package/src/components/chart-zoom.tsx +4 -47
  334. package/src/components/checkbox-group.tsx +22 -4
  335. package/src/components/chip-input.tsx +0 -7
  336. package/src/components/column-mapper.tsx +6 -2
  337. package/src/components/combobox.tsx +6 -3
  338. package/src/components/copy-button.tsx +5 -1
  339. package/src/components/country-select.tsx +6 -1
  340. package/src/components/currency-option-list.tsx +8 -42
  341. package/src/components/currency-select.tsx +12 -3
  342. package/src/components/danger-confirm.tsx +3 -3
  343. package/src/components/data-table-filter-popover.tsx +2 -1
  344. package/src/components/data-table-labels.ts +2 -84
  345. package/src/components/data-table-shared.tsx +55 -2
  346. package/src/components/data-table.tsx +29 -17
  347. package/src/components/date-field.tsx +2 -2
  348. package/src/components/date-picker.tsx +3 -0
  349. package/src/components/date-range-picker.tsx +3 -0
  350. package/src/components/dialog-frame.tsx +3 -1
  351. package/src/components/dropdown.tsx +42 -18
  352. package/src/components/entity-combobox.tsx +6 -3
  353. package/src/components/field-base.tsx +0 -11
  354. package/src/components/field-parts.tsx +112 -38
  355. package/src/components/field-strip.tsx +12 -27
  356. package/src/components/field-sync.tsx +0 -7
  357. package/src/components/field.tsx +32 -19
  358. package/src/components/full-bleed-dialog.tsx +4 -3
  359. package/src/components/help-popover.tsx +9 -7
  360. package/src/components/hover-menu.tsx +12 -16
  361. package/src/components/icon-picker.tsx +8 -3
  362. package/src/components/inline-entity-combobox.tsx +6 -3
  363. package/src/components/input.tsx +4 -2
  364. package/src/components/modal.tsx +20 -4
  365. package/src/components/month-picker.tsx +10 -3
  366. package/src/components/multi-entity-combobox.tsx +5 -2
  367. package/src/components/multi-select.tsx +19 -31
  368. package/src/components/number-input.tsx +5 -10
  369. package/src/components/numeric-field.ts +10 -2
  370. package/src/components/one-time-code-input.tsx +5 -3
  371. package/src/components/phone-input.tsx +4 -0
  372. package/src/components/popover.tsx +8 -4
  373. package/src/components/select.tsx +6 -3
  374. package/src/components/series-chart.tsx +1 -1
  375. package/src/components/server-wake.tsx +0 -6
  376. package/src/components/settings-fields.tsx +4 -2
  377. package/src/components/slider.tsx +10 -3
  378. package/src/components/stat-tile.tsx +11 -20
  379. package/src/components/swatch-picker.tsx +9 -4
  380. package/src/components/swipeable-row.tsx +15 -37
  381. package/src/components/text-link.tsx +3 -1
  382. package/src/components/textarea.tsx +11 -4
  383. package/src/components/toggle-group.tsx +21 -5
  384. package/src/components/tooltip.tsx +37 -6
  385. package/src/components/translation-review.tsx +25 -7
  386. package/src/components/use-table-state.ts +91 -10
  387. package/src/components/user-avatar.tsx +2 -2
  388. package/src/components/wizard-stepper.tsx +2 -6
  389. package/src/currencies.ts +70 -0
  390. package/src/demo/demo-banner.tsx +7 -2
  391. package/src/eslint/index.ts +161 -0
  392. package/src/eslint/role-utilities.generated.ts +146 -0
  393. package/src/eslint/role-utilities.ts +99 -0
  394. package/src/feedback/feedback-menu.tsx +2 -2
  395. package/src/feedback/feedback-thread.tsx +3 -8
  396. package/src/hooks/use-dismiss.ts +39 -4
  397. package/src/i18n/defaults.ts +4 -0
  398. package/src/i18n/german.ts +113 -0
  399. package/src/i18n/kit-labels.tsx +66 -6
  400. package/src/i18n/locales/en.ts +6 -0
  401. package/src/i18n/locales/es.ts +106 -0
  402. package/src/i18n/locales/fr.ts +109 -2
  403. package/src/i18n/locales/hu.ts +104 -0
  404. package/src/i18n/locales/it.ts +108 -2
  405. package/src/i18n/locales/zh.ts +96 -0
  406. package/src/i18n/review.ts +13 -0
  407. package/src/i18n/shared-labels.ts +2 -0
  408. package/src/index.ts +53 -1
  409. package/src/lib/device-settings.ts +146 -0
  410. package/src/lib/plain-text.ts +22 -0
  411. package/src/lib/refs.ts +22 -0
  412. package/src/lib/safe-storage.ts +16 -0
  413. package/src/notifications/notification-parts.tsx +83 -0
  414. package/src/notifications/notification-types-setting.tsx +309 -0
  415. package/src/notifications/notification-types.ts +80 -0
  416. package/src/notifications/notifications-labels.ts +238 -0
  417. package/src/notifications/push-device-setting.tsx +224 -0
  418. package/src/notifications/push-devices-setting.tsx +306 -0
  419. package/src/notifications/quiet-hours-setting.tsx +185 -0
  420. package/src/notifications/time-zone-select.tsx +126 -0
  421. package/src/notifications/unsubscribe-panel.tsx +203 -0
  422. package/src/notifications/use-push-device.ts +392 -0
  423. package/src/rhf/fields.tsx +87 -39
  424. package/src/rhf/form-core.tsx +5 -4
  425. package/src/rhf/form.tsx +7 -43
  426. package/src/rhf/line-items.tsx +1 -1
  427. package/src/rhf/use-rhf-wizard-step.ts +4 -4
  428. package/src/rhf.ts +3 -2
  429. package/src/settings/device-reset-setting-labels.ts +20 -0
  430. package/src/settings/device-reset-setting.tsx +119 -0
  431. package/src/shell/app-shell.tsx +8 -0
  432. package/src/shell/option-switcher-menu.tsx +5 -22
  433. package/src/shell/role-switcher.tsx +2 -6
  434. package/src/shell/topbar-action-menu.tsx +7 -24
  435. package/src/shell/topbar-controls.tsx +6 -18
  436. package/src/testing/index.ts +3 -1
  437. package/src/testing/viewport.ts +125 -19
  438. package/src/theme/contrast-tokens.ts +106 -12
  439. package/src/theme/contrast.ts +30 -4
  440. package/src/theme/palette-derive.ts +68 -7
  441. package/src/theme/palette-presets.ts +16 -299
  442. package/src/theme/palette-store.ts +12 -0
  443. package/src/theme/text-size.ts +8 -0
  444. package/src/theme/theme-store.ts +10 -0
  445. package/src/wizard/types.ts +0 -8
  446. package/tokens.css +38 -4
package/README.md CHANGED
@@ -94,6 +94,12 @@ currency picker and the language menu. It was a 5.6 MB hard dependency through 0
94
94
  installed into every consumer and imported by nothing — so it may still be in your tree
95
95
  transitively after upgrading. Depend on it explicitly if you render any of the three.
96
96
 
97
+ **Shipping only the flags you render.** `@eifi1/ui-kit/currencies` (0.34.1) is the
98
+ currency list as plain data — `CURRENCIES`, and `CURRENCY_COUNTRIES` (code → the lowercase
99
+ country flag-icons names the flag by: `CHF` → `"ch"`, `EUR` → `"eu"`). It imports nothing,
100
+ so a build script or a Vite plugin can import it in Node to generate a flag subset. Read
101
+ it there, never out of a file under `dist/`: those move between versions.
102
+
97
103
  ## Wiring
98
104
 
99
105
  ### 1. Vite — dedupe shared singletons
@@ -169,6 +175,16 @@ module runs needs the text size even earlier: see "Before the first paint" under
169
175
  [Styling](#styling). Worked example:
170
176
  [`showcase/src/main.tsx`](https://github.com/Eifi1/ui-kit/blob/main/showcase/src/main.tsx).
171
177
 
178
+ **Reset this device's settings** (0.36, `docs/settings-harmonization.md` §11): the four
179
+ stores, `AppShell`'s sidebar key and `UiKitProvider`'s table prefix join a registry by
180
+ themselves; `DeviceResetSetting` (the last card of the appearance group) clears them all and
181
+ puts each back live. An app adds its own device keys, each with a reset that goes through its
182
+ own store:
183
+
184
+ ```ts
185
+ registerDeviceSetting({ key: "myapp-lang", kind: "appearance", reset: () => setDeviceLanguage(null) });
186
+ ```
187
+
172
188
  ### 4. Labels — one provider, the shipped catalogues
173
189
 
174
190
  Load the kit's words with `await loadUiKitLabels(code)` before the first render and hand
@@ -182,9 +198,9 @@ re-skins the kit by changing values rather than by forking components. The famil
182
198
 
183
199
  | Family | Tokens | Set by |
184
200
  |---|---|---|
185
- | **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` (More contrast steps four of them) |
201
+ | **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` (More contrast steps four of them; in light also the well and the four money colours) |
186
202
  | **Derived** | `--text-placeholder` `--bg-hover` `--bg-active` `--bg-inverse` `--text-inverse` `--border-strong` `--brand-bg` `--brand-bg-hover` `--brand-muted`, and `--neutral` (`--text-muted` as a fill) | `color-mix()` or `var()` in `tokens.css`, from the layer above — so they follow the preset with no preset having to list them |
187
- | **Semantic** | `--danger*` `--warning*` `--info*` `--success*` — each the colour, `-contrast`, `-border` and `-bg`; danger and warning also `-border-strong`, danger `-hover` — and `--status-synced/-pending/-edited/-error` | literals in `tokens.css`, per theme |
203
+ | **Semantic** | `--danger*` `--warning*` `--info*` `--success*` — each the colour, `-contrast`, `-border` and `-bg`; danger and warning also `-border-strong`, danger `-hover` — and `--status-synced/-pending/-edited/-error` | literals in `tokens.css`, per theme; in light under More contrast the four colours and `--status-edited` deepen for the darker well |
188
204
  | **Categorical hues** | `--hue-blue` `--hue-indigo` `--hue-purple` `--hue-teal` `--hue-orange`, each with `-contrast`, `-border` and `-bg` | literals in `tokens.css`, per theme — values that mean only "a different value" (a status enum), at the semantic family's weight |
189
205
  | **Fill foregrounds** | `<fill>-contrast`: the text ON a fill — `--brand-contrast`, `--money-income-contrast` … `--money-neutral-contrast`, `--neutral-contrast`, and each tone's and hue's `-contrast` | with their family; money is white in light and the page in dark |
190
206
  | **Media** | `--media-ink` `--media-scrim` `--media-scrim-hover` | literals, the SAME in both themes: controls drawn on a photo or a camera picture, whose background is the picture, not the page |
@@ -226,8 +242,10 @@ name with the property's own prefix dropped (`--bg-surface` → `bg-surface`,
226
242
  The names are **property-scoped**: a text role makes a `text-*` utility and nothing else,
227
243
  so `bg-muted` does not exist and a role cannot land on the wrong property by accident. An
228
244
  app's own `--color-*` names (shadcn-style) do not collide with them. Keep `[var(--…)]` for a
229
- role with no utility: the chart colours, `--status-*`, a ring offset, and a money colour
230
- that needs a variant (the money classes below are plain and take none). The kit's own
245
+ role with no utility: the chart colours and `--status-*`. The ring offsets
246
+ (`ring-offset-surface`, `ring-offset-page`) and the money colours (`text-money-income`,
247
+ `bg-money-expense` …, the table below) are utilities since 0.34 and take variants, unlike
248
+ the plain money classes further down. The kit's own
231
249
  markup follows this rule with no exceptions: `check:tokens` allows no `[var(--role)]` where
232
250
  a utility exists.
233
251
 
@@ -329,13 +347,46 @@ Theme values: `text-micro` (font size 0.625rem), `text-caption` (font size 0.687
329
347
 
330
348
  <!-- END GENERATED: styling -->
331
349
 
350
+ ### Lint: the role utilities in an app
351
+
352
+ `@eifi1/ui-kit/eslint` (0.35) is `check:tokens`' role rule for an app's own markup: an ESLint
353
+ flat-config plugin whose `role-utilities` rule reports a `[var(--role)]` class wherever that
354
+ property has a utility for the role, and names it. It reads every string literal and
355
+ template-literal part, so a JSX `className`, a `cn()` / `clsx()` argument and a class constant
356
+ alike. Where one utility fits, `eslint --fix` writes it and keeps the variants and the opacity:
357
+ `hover:text-[var(--text-muted)]/70` → `hover:text-muted/70`. A token with no utility on that
358
+ property is left alone (`text-[var(--chart-1)]`, `--status-*`, `bg-[var(--border)]` as a
359
+ divider), and so are comments. The rule reads the table above, so a role that gains a utility is
360
+ flagged from the release that adds it.
361
+
362
+ ```js
363
+ // eslint.config.js
364
+ import uiKit from "@eifi1/ui-kit/eslint";
365
+
366
+ export default defineConfig([ // or tseslint.config(…): either takes it
367
+ // … the app's own entries, which say which files are linted …
368
+ uiKit.configs.recommended,
369
+ ]);
370
+ ```
371
+
372
+ `configs.recommended` registers the plugin as `@eifi1/ui-kit` and turns
373
+ `@eifi1/ui-kit/role-utilities` on as an error for every linted file except tests
374
+ (`**/__tests__/**`, `*.test.*`, `*.spec.*`), which may name an old class to assert it is gone.
375
+ To scope it yourself, register the plugin and set the rule:
376
+ `{ files: ["src/**/*.tsx"], plugins: { "@eifi1/ui-kit": uiKit }, rules: { "@eifi1/ui-kit/role-utilities": "error" } }`.
377
+ It runs on ESLint 9 and 10 and imports no package of its own.
378
+
332
379
  ### Text size and More contrast
333
380
 
334
381
  ONE scale on `<html>`: `data-text-size="normal" | "large" | "xlarge"` is 100 / 125 / 150 %
335
382
  of the browser's own font size, so Normal keeps whatever the reader set in the browser,
336
383
  and everything sized in rem (Tailwind's spacing and type) grows with it.
337
384
  `data-contrast="more"` is More contrast, from the setting or from `prefers-contrast: more`
338
- on "System"; it steps the colour tokens in JavaScript and widens `--focus-ring-width`. The
385
+ on "System"; it steps the colour tokens in JavaScript and widens `--focus-ring-width`. In
386
+ light it also darkens the well (`--bg-surface-2`, 10 % ink into the card) and deepens the
387
+ money, status, teal, orange and `--status-edited` colours and `--bg-active` so they keep
388
+ their contrast on it; dark keeps its well. A link button's and TextLink's brand reads
389
+ `--brand-muted` (the brand as text) under it, in both modes. The
339
390
  stores in [Wiring](#wiring) put both attributes there; the attribute names are frozen.
340
391
 
341
392
  - **`large:`** applies at Large AND Extra large, **`xlarge:`** only at Extra large, and
@@ -505,25 +556,27 @@ columns, strings and permissions (see the note at the top of `src/feedback/feedb
505
556
 
506
557
  <!-- BEGIN GENERATED: exports — node scripts/gen-export-inventory.mjs -->
507
558
 
508
- **1899 names from 302 modules** — 888 values and 1011 types. _Italic_ is a type-only export.
559
+ **1925 names from 313 modules** — 890 values and 1035 types. _Italic_ is a type-only export.
509
560
 
510
561
  Generated from `dist/index.d.ts` by `node scripts/gen-export-inventory.mjs`; the count
511
562
  is pinned by `src/__tests__/public-surface.test.ts`. Do not edit between the markers.
512
563
 
513
564
  | Entry point | Names |
514
565
  |---|---|
515
- | `@eifi1/ui-kit` | 1899 |
516
- | `@eifi1/ui-kit/chart` | 105 |
566
+ | `@eifi1/ui-kit` | 1925 |
567
+ | `@eifi1/ui-kit/chart` | 92 |
517
568
  | `@eifi1/ui-kit/shell` | 77 |
518
- | `@eifi1/ui-kit/data-table` | 53 |
519
- | `@eifi1/ui-kit/wizard` | 25 |
569
+ | `@eifi1/ui-kit/data-table` | 51 |
570
+ | `@eifi1/ui-kit/wizard` | 24 |
520
571
  | `@eifi1/ui-kit/tour` | 7 |
521
- | `@eifi1/ui-kit/feedback` | 165 |
572
+ | `@eifi1/ui-kit/feedback` | 164 |
522
573
  | `@eifi1/ui-kit/search` | 23 |
523
574
  | `@eifi1/ui-kit/dates` | 22 |
524
575
  | `@eifi1/ui-kit/table-text` | 14 |
525
- | `@eifi1/ui-kit/testing` | 10 |
526
- | `@eifi1/ui-kit/rhf` | 60 |
576
+ | `@eifi1/ui-kit/currencies` | 3 |
577
+ | `@eifi1/ui-kit/eslint` | 1 |
578
+ | `@eifi1/ui-kit/testing` | 11 |
579
+ | `@eifi1/ui-kit/rhf` | 48 |
527
580
 
528
581
  Everything below is reachable from the main `@eifi1/ui-kit` barrel. The subpaths are a
529
582
  re-slicing of it, never a second API.
@@ -549,6 +602,7 @@ re-slicing of it, never a second API.
549
602
  | `lib/isin` | `formatIsin`, `isinCheckDigit`, `isValidIsin` |
550
603
  | `lib/phone` | `formatNationalPhone`, `formatPhone`, `isE164`, `parsePhone`, `PHONE_COUNTRIES`, `PHONE_DIAL_CODES`, _`ParsedPhone`_, _`PhoneCountry`_, _`PhoneCountryCode`_ |
551
604
  | `lib/column-mapping` | `assignColumnRole`, `guessMapping`, `missingRoles`, `readMappedTable`, `readTextFile`, `roleOfColumn`, _`ColumnMapperResult`_, _`ColumnMapping`_, _`ColumnRole`_ |
605
+ | `lib/device-settings` | `deviceSettings`, `registerDeviceSetting`, `resetDeviceSettings`, _`DeviceSetting`_, _`DeviceSettingKind`_ |
552
606
  | `lib/clipping` | `CLIPS_ATTRIBUTE` |
553
607
  | `lib/chip-edge-snap` | `refreshChipEdges` |
554
608
 
@@ -584,7 +638,7 @@ re-slicing of it, never a second API.
584
638
  |---|---|
585
639
  | `theme/color` | `contrast`, `deltaE`, `hexToOklch`, `luminance`, `oklchToHex`, `oklchToRgb`, `parseHex`, `rgbToOklch`, `simulateCvd`, `solveLightness`, `toHex`, _`CvdType`_, _`Oklch`_, _`Rgb`_ |
586
640
  | `theme/palette-derive` | `auditChartRamp`, `auditPalette`, `deriveChartRamp`, `derivePalette`, `describe`, _`AnchorRole`_, _`ChartRampReport`_, _`ContrastCheck`_, _`ContrastReport`_, _`DerivedPalette`_, _`DeriveOptions`_, _`PaletteAnchors`_, _`SemanticTokens`_ |
587
- | `theme/palette-presets` | `ALTERNATIVE_PRESETS`, `applyTokenSet`, `DEFAULT_PRESET`, `DERIVED_PRESETS`, `IMPRINT_PRESET`, `PALETTES`, `presetById`, _`PalettePreset`_, _`TokenSet`_ |
641
+ | `theme/palette-presets` | `applyTokenSet`, `DEFAULT_PRESET`, `DERIVED_PRESETS`, `IMPRINT_PRESET`, `PALETTES`, `presetById`, _`PalettePreset`_, _`TokenSet`_ |
588
642
  | `theme/theme-store` | `applyPersistedTheme`, `createThemeStore`, _`ThemeMode`_, _`ThemePreference`_, _`ThemeState`_, _`ThemeStore`_ |
589
643
  | `theme/palette-store` | `applyPersistedPalette`, `createPaletteStore`, _`PaletteStore`_ |
590
644
  | `theme/text-size` | `applyPersistedTextSize`, `applyTextSize`, `createTextSizeStore`, `isTextSize`, `readPersistedTextSize`, `readTextSize`, `resolveTextSize`, `TEXT_SCALE`, `TEXT_SIZE_INLINE_SCRIPT`, `TEXT_SIZES`, `useTextSize`, _`ApplyTextSizeOptions`_, _`PersistedAppearanceOptions`_, _`PersistedTextSize`_, _`TextSize`_, _`TextSizeInfo`_, _`TextSizeState`_, _`TextSizeStore`_ |
@@ -608,7 +662,7 @@ re-slicing of it, never a second API.
608
662
  | `components/button` | `Button`, _`ButtonLinkProps`_, _`ButtonProps`_ |
609
663
  | `components/button-look` | `buttonClasses`, `TOUCH_TARGET_LARGE`, _`ButtonClassesOptions`_, _`ButtonSize`_, _`ButtonTone`_, _`ButtonVariant`_ |
610
664
  | `components/icon-button` | `IconButton`, _`IconButtonGlyphSize`_, _`IconButtonLinkProps`_, _`IconButtonProps`_, _`IconButtonSize`_, _`IconButtonTone`_, _`IconButtonToneColor`_, _`IconButtonVariant`_ |
611
- | `components/field-base` | `DEFAULT_CHARACTER_COUNT_LABELS`, `DEFAULT_PASSWORD_REVEAL_LABELS`, `FIELD_BASE`, `FIELD_DISPLAY`, `FIELD_FLOATING_PAD`, `FIELD_INVALID`, `FIELD_TOUCH_TEXT`, `FIELD_TRIGGER`, `FIELD_WRITABLE_LOOK`, `FieldChevron`, `FLOATING_INPUT_CLASS`, `FLOATING_LABEL_CLASS`, `FloatingField`, `Label`, `resolvePasswordRevealLabels`, _`CharacterCountLabels`_, _`FieldChevronProps`_, _`FloatingFieldProps`_, _`LabelProps`_, _`PasswordRevealLabels`_ |
665
+ | `components/field-base` | `DEFAULT_CHARACTER_COUNT_LABELS`, `DEFAULT_PASSWORD_REVEAL_LABELS`, `FIELD_BASE`, `FIELD_DISPLAY`, `FIELD_FLOATING_PAD`, `FIELD_INVALID`, `FIELD_TOUCH_TEXT`, `FIELD_TRIGGER`, `FIELD_WRITABLE_LOOK`, `FieldChevron`, `FLOATING_INPUT_CLASS`, `FLOATING_LABEL_CLASS`, `FloatingField`, `Label`, _`CharacterCountLabels`_, _`FieldChevronProps`_, _`FloatingFieldProps`_, _`LabelProps`_, _`PasswordRevealLabels`_ |
612
666
  | `components/input` | `Input`, _`InputProps`_ |
613
667
  | `components/select` | `Select`, _`SelectProps`_ |
614
668
  | `components/textarea` | `Textarea`, _`TextareaProps`_ |
@@ -638,7 +692,7 @@ re-slicing of it, never a second API.
638
692
  | `components/tooltip` | `placeTooltip`, `Tooltip`, _`TooltipPlacement`_, _`TooltipProps`_, _`TooltipSide`_, _`TooltipSize`_, _`TooltipTap`_, _`TooltipViewport`_ |
639
693
  | `components/user-avatar` | `avatarInitials`, `UserAvatar`, _`UserAvatarBadge`_, _`UserAvatarProps`_ |
640
694
  | `components/settings-fields` | `ContrastSetting`, `LanguageSetting`, `TextSizeSetting`, `ThemeSetting`, _`ContrastSettingProps`_, _`LanguageSettingProps`_, _`TextSizeSettingProps`_, _`ThemeSettingProps`_, _`ThemeSettingSelectProps`_, _`ThemeSettingToggleProps`_ |
641
- | `components/field-sync` | `DEFAULT_FIELD_SYNC_LABELS`, `FIELD_SYNC_FRAME`, `FIELD_SYNC_SAVED_MS`, `FieldSyncIndicator`, `FieldSyncRow`, `resolveFieldSyncLabels`, `useFieldSync`, _`FieldSyncIndicatorProps`_, _`FieldSyncLabels`_, _`FieldSyncRowProps`_, _`FieldSyncState`_, _`UseFieldSyncOptions`_, _`UseFieldSyncReturn`_ |
695
+ | `components/field-sync` | `DEFAULT_FIELD_SYNC_LABELS`, `FIELD_SYNC_FRAME`, `FIELD_SYNC_SAVED_MS`, `FieldSyncIndicator`, `FieldSyncRow`, `useFieldSync`, _`FieldSyncIndicatorProps`_, _`FieldSyncLabels`_, _`FieldSyncRowProps`_, _`FieldSyncState`_, _`UseFieldSyncOptions`_, _`UseFieldSyncReturn`_ |
642
696
  | `components/month-picker` | `DEFAULT_MONTH_PICKER_LABELS`, `MonthPicker`, _`MonthPickerLabels`_, _`MonthPickerProps`_ |
643
697
  | `components/checkbox` | `Checkbox`, _`CheckboxProps`_ |
644
698
  | `components/switch` | `Switch`, _`SwitchProps`_, _`SwitchSize`_ |
@@ -667,7 +721,6 @@ re-slicing of it, never a second API.
667
721
  | `components/treemap` | `fitLabel`, `Treemap`, `TreemapCell`, _`TreemapCellProps`_, _`TreemapNode`_, _`TreemapProps`_ |
668
722
  | `components/series-chart` | `resolveTooltipPlacement`, `SeriesChart`, `seriesLegendEntries`, `StaticSeriesChart`, _`SeriesChartAxis`_, _`SeriesChartHit`_, _`SeriesChartMarker`_, _`SeriesChartPoint`_, _`SeriesChartProps`_, _`SeriesChartReference`_, _`SeriesChartRow`_, _`SeriesChartSeries`_, _`SeriesChartSpan`_, _`SeriesChartTickValues`_, _`SeriesChartTone`_, _`SeriesChartTooltip`_, _`SeriesChartTooltipPlacement`_, _`SeriesChartType`_, _`SeriesChartX`_, _`SeriesChartXTick`_, _`SeriesChartXValue`_, _`SeriesLegendAxes`_ |
669
723
  | `components/chart-height` | _`ChartHeight`_ |
670
- | `components/chart-zoom` | `axisExtent`, `DEFAULT_Y_AXIS`, `defaultZoomAxes`, `fitXToY`, `fitYToX`, `NO_ZOOM`, `selectionFromDrag`, `withChartZoom`, `ZOOM_MIN_DRAG`, `ZOOM_SQUARE_ENOUGH`, `zoomAfter`, `zoomAxesFor`, `zoomDomains` |
671
724
  | `components/chart-zoom-core` | `SharedXZoom`, _`ZoomAxes`_, _`ZoomAxesSetting`_, _`ZoomBinding`_, _`ZoomDrag`_, _`ZoomFitSeries`_, _`ZoomFitSource`_, _`ZoomRow`_, _`ZoomSelection`_, _`ZoomState`_, _`ZoomTarget`_ |
672
725
  | `components/toggle-legend` | `LegendColumn`, `LegendGroup`, `StaticLegend`, `STEP_DASH`, `STROKE_PATTERNS`, `strokeDash`, `toggleHidden`, `ToggleLegend`, _`LegendEntry`_, _`StaticLegendProps`_, _`ToggleLegendProps`_ |
673
726
  | `components/facing-pair` | `FACING_SIDES`, `facingAxes`, `facingBand`, `facingHeadingPad`, _`FacingSide`_ |
@@ -679,7 +732,7 @@ re-slicing of it, never a second API.
679
732
  | `components/toggle-group` | `ToggleGroup`, _`ToggleGroupBaseProps`_, _`ToggleGroupClearableProps`_, _`ToggleGroupProps`_, _`ToggleGroupRequiredProps`_, _`ToggleOption`_ |
680
733
  | `components/nav-pills` | `NavPills`, _`NavPillItem`_, _`NavPillLinkProps`_, _`NavPillsCurrent`_, _`NavPillsProps`_ |
681
734
  | `components/chip` | `Chip`, _`ChipHue`_, _`ChipLinkProps`_, _`ChipProps`_, _`ChipShape`_, _`ChipSize`_, _`ChipTone`_, _`ChipVariant`_ |
682
- | `components/chip-input` | `ChipInput`, `DEFAULT_CHIP_INPUT_LABELS`, `resolveChipInputLabels`, _`ChipInputLabels`_, _`ChipInputProps`_ |
735
+ | `components/chip-input` | `ChipInput`, `DEFAULT_CHIP_INPUT_LABELS`, _`ChipInputLabels`_, _`ChipInputProps`_ |
683
736
  | `components/wizard-stepper` | `WizardStepper` |
684
737
  | `components/hover-menu` | `HoverMenu`, _`HoverMenuProps`_ |
685
738
  | `components/modal` | `Modal`, `ModalCloseContext`, `useBackdropClose`, _`ModalProps`_ |
@@ -732,9 +785,9 @@ re-slicing of it, never a second API.
732
785
  | `components/country-select` | `CountrySelect`, `DEFAULT_COUNTRY_SELECT_LABELS`, _`CountrySelectLabels`_, _`CountrySelectProps`_ |
733
786
  | `components/iban-input` | `DEFAULT_IBAN_INPUT_LABELS`, `IbanInput`, _`IbanInputLabels`_, _`IbanInputProps`_ |
734
787
  | `components/phone-input` | `DEFAULT_PHONE_INPUT_LABELS`, `PhoneInput`, _`PhoneInputLabels`_, _`PhoneInputProps`_ |
735
- | `components/field-strip` | `FieldStrip`, _`FieldStripIds`_, _`FieldStripPad`_, _`FieldStripProps`_ |
788
+ | `components/field-strip` | `FieldStrip`, _`FieldStripIds`_, _`FieldStripProps`_ |
736
789
  | `components/column-mapper` | `ColumnMapper`, `ColumnRoleTable`, `DEFAULT_COLUMN_MAPPER_LABELS`, _`ColumnMapperLabels`_, _`ColumnMapperProps`_, _`ColumnRoleTableBodyProps`_, _`ColumnRoleTableProps`_, _`ColumnRoleTableRowProps`_ |
737
- | `components/data-table-labels` | `DEFAULT_DATA_TABLE_LABELS`, `missingDataTableLabels`, `resolveDataTableLabels`, _`DataTableLabels`_ |
790
+ | `components/data-table-labels` | `DEFAULT_DATA_TABLE_LABELS`, _`DataTableLabels`_ |
738
791
  | `components/data-table-sort` | `decodeSorts`, `encodeSorts`, `nextSorts`, `normalizeSorts`, _`SortCycle`_, _`SortDir`_, _`SortState`_, _`SortStepOptions`_ |
739
792
  | `components/data-table-filters` | `dateFilter`, `decodeFilterValue`, `decodeFilterValueOfType`, `defaultFilterState`, `encodeFilterValue`, `filterHref`, `isFilterActive`, `numberFilter`, `resolveFilter`, `rowMatches`, `selectFilter`, `textFilter`, _`ColumnFilter`_, _`FilterValue`_ |
740
793
  | `components/data-table-pagination` | `PAGE_SIZE_OPTIONS`, `Pagination` |
@@ -779,6 +832,7 @@ re-slicing of it, never a second API.
779
832
  | `settings/settings-heading` | `SettingsHeadingLevel`, `useSettingsHeadingLevel`, _`SettingsHeadingLevelProps`_, _`SettingsHeadingTag`_ |
780
833
  | `settings/settings-catalogue` | `settingsHref`, `settingsSearchEntries`, `visibleSettingsEntries`, `visibleSettingsGroups`, _`SettingsEntry`_, _`SettingsGroup`_, _`SettingsSearchEntriesOptions`_ |
781
834
  | `settings/settings-labels` | `DEFAULT_SETTINGS_LABELS`, `useSettingsLabels`, _`SettingsCoreGroup`_, _`SettingsGroupLabels`_, _`SettingsLabels`_ |
835
+ | `settings/device-reset-setting` | `DEFAULT_DEVICE_RESET_LABELS`, `DEVICE_RESET_ANCHOR`, `DeviceResetSetting`, _`DeviceResetLabels`_, _`DeviceResetSettingProps`_ |
782
836
  | `settings/use-account-language` | `matchOfferedLanguage`, `resolveAccountLanguage`, `useAccountLanguage`, _`AccountLanguage`_, _`AccountLanguageSource`_, _`ResolveAccountLanguageInput`_, _`ResolvedAccountLanguage`_, _`UseAccountLanguageOptions`_ |
783
837
  | `settings/use-account-appearance` | `resolveAccountAppearance`, `useAccountAppearance`, _`AccountAppearance`_, _`AccountAppearanceFields`_, _`AccountAppearancePatch`_, _`AppearanceSource`_, _`DeviceAppearance`_, _`ResolvedAccountAppearance`_, _`UseAccountAppearanceOptions`_ |
784
838
 
@@ -801,7 +855,7 @@ re-slicing of it, never a second API.
801
855
  | `feedback/feedback-attachment` | `DEFAULT_ATTACHMENT_ACCEPT`, `DEFAULT_FEEDBACK_ATTACHMENT_LABELS`, `DEFAULT_MAX_ATTACHMENT_BYTES`, `DEFAULT_MAX_ATTACHMENTS`, `FeedbackAttachmentField`, `pastedName`, _`FeedbackAttachmentError`_, _`FeedbackAttachmentErrorInfo`_, _`FeedbackAttachmentFieldLabels`_, _`FeedbackAttachmentFieldMultipleProps`_, _`FeedbackAttachmentFieldProps`_, _`FeedbackAttachmentFieldRefsProps`_, _`FeedbackAttachmentFieldSingleProps`_, _`FeedbackAttachmentRef`_, _`FeedbackAttachmentRefsError`_ |
802
856
  | `feedback/feedback-dialog` | `DEFAULT_FEEDBACK_DIALOG_LABELS`, `FeedbackDialog`, _`FeedbackAttachmentLabels`_, _`FeedbackCategoryOption`_, _`FeedbackDialogLabels`_, _`FeedbackDialogMultipleProps`_, _`FeedbackDialogProps`_, _`FeedbackDialogSingleProps`_, _`FeedbackDialogTextLabels`_, _`FeedbackMultipleSubmission`_, _`FeedbackSubmission`_, _`FeedbackSubmitHint`_ |
803
857
  | `feedback/feedback-inbox` | `FeedbackCategoryBadge`, `FeedbackDetail`, `FeedbackDetailSection`, `FeedbackNoteEditor`, `FeedbackProse`, `FeedbackStatusBadge`, `FeedbackStatusTransitions`, _`FeedbackNoteAttachment`_ |
804
- | `feedback/feedback-thread` | `ChatComposer`, `DEFAULT_FEEDBACK_COMPOSER_LABELS`, `DEFAULT_FEEDBACK_THREAD_LABELS`, `FeedbackComposer`, `FeedbackThread`, _`ChatComposerHandle`_, _`ChatComposerLabels`_, _`ChatComposerProps`_, _`ChatComposerSlotContext`_, _`FeedbackComposerAttachment`_, _`FeedbackComposerHandle`_, _`FeedbackComposerLabels`_, _`FeedbackComposerProps`_, _`FeedbackComposerSlotContext`_, _`FeedbackThreadAttachment`_, _`FeedbackThreadEvent`_, _`FeedbackThreadItem`_, _`FeedbackThreadLabels`_, _`FeedbackThreadMessage`_, _`FeedbackThreadProps`_ |
858
+ | `feedback/feedback-thread` | `ChatComposer`, `DEFAULT_FEEDBACK_COMPOSER_LABELS`, `DEFAULT_FEEDBACK_THREAD_LABELS`, `FeedbackThread`, _`ChatComposerHandle`_, _`ChatComposerLabels`_, _`ChatComposerProps`_, _`ChatComposerSlotContext`_, _`FeedbackComposerAttachment`_, _`FeedbackComposerHandle`_, _`FeedbackComposerLabels`_, _`FeedbackComposerProps`_, _`FeedbackComposerSlotContext`_, _`FeedbackThreadAttachment`_, _`FeedbackThreadEvent`_, _`FeedbackThreadItem`_, _`FeedbackThreadLabels`_, _`FeedbackThreadMessage`_, _`FeedbackThreadProps`_ |
805
859
  | `feedback/feedback-record` | `appendRework`, `attachmentName`, `FEEDBACK_ATTACHMENT_ACCEPT`, `FEEDBACK_AUTHOR_EDITABLE_STATUSES`, `FEEDBACK_AWAITING_STATUSES`, `FEEDBACK_PICKABLE_CATEGORIES`, `FEEDBACK_REWORKABLE_STATUSES`, `feedbackAttachmentLine`, `isImageAttachment`, `replaceDescription`, `reworkCount`, `splitBodyAttachments`, `splitDescription`, _`FeedbackContext`_, _`FeedbackEnvironment`_, _`FeedbackRecord`_ |
806
860
  | `feedback/feedback-labels` | `DEFAULT_FEEDBACK_CATEGORY_LABELS`, `DEFAULT_FEEDBACK_STATUS_LABELS`, `DEFAULT_FEEDBACK_TOAST_LABELS`, `useFeedbackCategoryLabels`, `useFeedbackStatusLabels`, `useFeedbackToastLabels`, _`FeedbackCategoryLabels`_, _`FeedbackStatusLabels`_, _`FeedbackToastLabels`_ |
807
861
  | `feedback/feedback-status-undo` | `FEEDBACK_UNDO_DURATION`, `useFeedbackStatusUndo`, _`FeedbackStatusChange`_, _`FeedbackStatusMutate`_, _`FeedbackStatusPatch`_, _`FeedbackStatusRow`_, _`FeedbackStatusUndoOptions`_ |
@@ -819,7 +873,7 @@ re-slicing of it, never a second API.
819
873
 
820
874
  | Module | Exports |
821
875
  |---|---|
822
- | `wizard/types` | `DEFAULT_WIZARD_LABELS`, `resolveWizardLabels`, _`FieldErrors`_, _`StepStatus`_, _`SummaryItem`_, _`SummarySection`_, _`UseWizardOptions`_, _`UseWizardReturn`_, _`ValidateResult`_, _`WizardLabels`_, _`WizardStepConfig`_, _`WizardUrlSync`_ |
876
+ | `wizard/types` | `DEFAULT_WIZARD_LABELS`, _`FieldErrors`_, _`StepStatus`_, _`SummaryItem`_, _`SummarySection`_, _`UseWizardOptions`_, _`UseWizardReturn`_, _`ValidateResult`_, _`WizardLabels`_, _`WizardStepConfig`_, _`WizardUrlSync`_ |
823
877
  | `wizard/use-wizard` | `useWizard` |
824
878
  | `wizard/wizard-context` | `useOptionalWizardContext`, `useWizardContext`, `useWizardNextGate`, `useWizardStepValidate`, `WizardContextProvider`, _`WizardContextValue`_ |
825
879
  | `wizard/validation` | `requiredFieldsValidator`, _`RequiredFieldSpec`_ |
@@ -904,6 +958,20 @@ re-slicing of it, never a second API.
904
958
  | `billing/billing-overview` | _`BillingOverview`_, _`PortalRequest`_, _`PortalTarget`_, _`SubscriptionSource`_ |
905
959
  | `billing/plan-limit-toast` | `usePlanLimitToast`, _`PlanLimitToastOptions`_ |
906
960
 
961
+ ### notifications
962
+
963
+ | Module | Exports |
964
+ |---|---|
965
+ | `notifications/notifications-labels` | `DEFAULT_NOTIFICATIONS_LABELS`, _`NotificationRegionLabels`_, _`NotificationsLabels`_ |
966
+ | `notifications/notification-types` | _`DigestCadence`_, _`NotificationSettingsPatch`_, _`NotificationSwitches`_, _`NotificationTypeEntry`_, _`NotificationTypeGroup`_, _`NotificationTypesValue`_, _`PushDeviceItem`_ |
967
+ | `notifications/notification-types-setting` | `NotificationTypesSetting`, _`NotificationTypesSettingProps`_ |
968
+ | `notifications/quiet-hours-setting` | `QuietHoursSetting`, _`QuietHoursSettingProps`_ |
969
+ | `notifications/time-zone-select` | `deviceTimeZone`, `timeZoneOptions`, `TimeZoneSelect`, _`TimeZoneSelectProps`_ |
970
+ | `notifications/use-push-device` | `notifyPushSubscriptionChanged`, `PUSH_SUBSCRIPTION_CHANGED`, `PushDeviceError`, `pushSupported`, `usePushDevice`, _`PushDevice`_, _`PushDeviceErrorCode`_, _`PushPermission`_, _`PushSubscriptionInput`_, _`UsePushDeviceOptions`_ |
971
+ | `notifications/push-device-setting` | `PushDeviceSetting`, _`PushDeviceAction`_, _`PushDeviceSettingProps`_ |
972
+ | `notifications/push-devices-setting` | `describeUserAgent`, `PushDevicesSetting`, _`PushDevicesSettingProps`_ |
973
+ | `notifications/unsubscribe-panel` | `UnsubscribePanel`, `unsubscribeTokenType`, _`UnsubscribePanelProps`_ |
974
+
907
975
  ### demo
908
976
 
909
977
  | Module | Exports |
@@ -915,6 +983,12 @@ re-slicing of it, never a second API.
915
983
  | `demo/demo-banner` | `DemoBanner`, _`DemoBannerProps`_ |
916
984
  | `demo/demo-ended` | `DemoEnded`, _`DemoEndedProps`_ |
917
985
 
986
+ ### root
987
+
988
+ | Module | Exports |
989
+ |---|---|
990
+ | `currencies` | `CURRENCY_COUNTRIES` |
991
+
918
992
  <!-- END GENERATED: exports -->
919
993
 
920
994
  ## Forms / refs
@@ -926,36 +1000,36 @@ element that takes focus: the `<input>` of `Input`, `NumberField`, `AmountInput`
926
1000
  on its checked option. So they work directly with react-hook-form:
927
1001
  `<Input {...field} />` (from `Controller`/`register`) attaches RHF's ref, giving
928
1002
  focus-and-scroll-to-error for free. A component that spreads its props onto an element
929
- (`Card`, `EmptyState`, `PageHeader`, …) takes that element's `ref` too. For the full
930
- `FormField`/`FormControl` scaffolding, see `@eifi1/ui-kit/rhf` below.
1003
+ (`Card`, `EmptyState`, `PageHeader`, …) takes that element's `ref` too. For fields bound
1004
+ to a react-hook-form form in one line each, see `@eifi1/ui-kit/rhf` below.
931
1005
 
932
1006
  ### react-hook-form — `@eifi1/ui-kit/rhf` (optional)
933
1007
 
934
- A thin adapter in shadcn's `form.tsx` shape, and the only entry that needs
935
- `react-hook-form` (an **optional** peer, `^7.55.0`). The main barrel does not import it,
936
- so apps without a form library install nothing.
1008
+ The react-hook-form adapter: `Form`, the bound fields (`RhfTextField`, `RhfNumberField`,
1009
+ `RhfMoneyField`, `RhfDateField`, `RhfSelect`, `RhfCombobox`, `RhfCheckbox`, …) and
1010
+ `RhfField` for a control of your own, and the only entry that needs `react-hook-form` (an
1011
+ **optional** peer, `^7.55.0`). The main barrel does not import it, so apps without a form
1012
+ library install nothing.
937
1013
 
938
1014
  ```tsx
939
- import { Form, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage } from "@eifi1/ui-kit/rhf";
1015
+ import { Form, RhfField, RhfNumberField, RhfTextField } from "@eifi1/ui-kit/rhf";
940
1016
 
941
1017
  <Form {...form}>
942
- <FormField control={form.control} name="amount" render={({ field }) => (
943
- <FormItem>
944
- <FormLabel required>Amount</FormLabel>
945
- <FormControl>
946
- <NumberField value={field.value} onCommit={field.onChange} />
947
- </FormControl>
948
- <FormMessage />
949
- </FormItem>
1018
+ <RhfTextField name="title" label="Title" required rules={{ required: "Give it a title." }} />
1019
+ <RhfNumberField name="amount" label="Amount" unit="EUR" hint="Net of VAT." />
1020
+ <RhfField name="street" label="Street" render={({ field, invalid }) => (
1021
+ <AddressAutocomplete {...field} invalid={invalid} />
950
1022
  )} />
951
1023
  </Form>
952
1024
  ```
953
1025
 
954
- `FormControl` gives its one child `id`, `aria-describedby` (only the description and
955
- message actually rendered, merged after the child's own) and `aria-invalid` — which every
956
- kit field now also PAINTS from, so no extra `invalid` prop is needed. `FormMessage` shows
957
- the form's own message; the kit adds no text. `useFormField()` exposes the ids and field
958
- state for custom parts.
1026
+ Each bound field is a label, the control, a hint and the form's message wired to each
1027
+ other: the control's `aria-describedby` names only the hint and message actually rendered
1028
+ (merged after the control's own), `aria-invalid` and `invalid` come from the field state,
1029
+ and `field.ref` reaches the focusable element, so a failed submit focuses the first field
1030
+ in error. The message is the form's own; the kit adds no text. The shadcn scaffold the
1031
+ adapter started as (`FormField`, `FormItem`, `FormLabel`, `FormControl`,
1032
+ `FormDescription`, `FormMessage`, `useFormField`) left the public surface in 0.35.
959
1033
 
960
1034
  ### Pasted and imported tables — `@eifi1/ui-kit/table-text`
961
1035
 
@@ -3,6 +3,7 @@ import { type LabelOverride } from "../i18n/kit-labels.js";
3
3
  import type { RoleVocabulary } from "../components/account-chips.js";
4
4
  import type { SelectProps } from "../components/select.js";
5
5
  import type { CommitScope } from "../components/write-lock.js";
6
+ import type { FieldHelpProps } from "../components/field-parts.js";
6
7
  import { DEFAULT_ROLE_SELECT_LABELS } from "./role-select-labels.js";
7
8
  /**
8
9
  * The role of an account, chosen by an admin (docs/user-admin-harmonization.md §3.3,
@@ -94,7 +95,7 @@ export interface RoleSelectProps<R extends string = string> extends Omit<SelectP
94
95
  * (`size`, `commit`, `hint`, `error`, `data-*`).
95
96
  */
96
97
  export declare function RoleSelect<R extends string = string>({ value, roles, onChange, offered, disabledReason, optionDisabledReason, name, labels: labelsProp, label, ...rest }: RoleSelectProps<R>): import("react").JSX.Element;
97
- export interface RolesEditorProps<R extends string = string> {
98
+ export interface RolesEditorProps<R extends string = string> extends FieldHelpProps {
98
99
  /** The roles ticked — the draft the app holds while its dialog is open. */
99
100
  value: readonly R[];
100
101
  roles: RoleVocabulary<R>;
@@ -133,4 +134,4 @@ export interface RolesEditorProps<R extends string = string> {
133
134
  * `AdminActionConfirm` (`acknowledge`, §4.2) — which can draw this editor as its
134
135
  * `children`, so the roles and the tick are one dialog.
135
136
  */
136
- export declare function RolesEditor<R extends string = string>({ value, roles, onChange, offered, disabledReason, optionDisabledReason, legend, legendVisibility, required, hint, error, columns, commit, className, labels: labelsProp, }: RolesEditorProps<R>): import("react").JSX.Element;
137
+ export declare function RolesEditor<R extends string = string>({ value, roles, onChange, offered, disabledReason, optionDisabledReason, legend, legendVisibility, required, hint, help, error, columns, commit, className, labels: labelsProp, }: RolesEditorProps<R>): import("react").JSX.Element;
@@ -71,6 +71,7 @@ function RolesEditor({
71
71
  legendVisibility,
72
72
  required,
73
73
  hint,
74
+ help,
74
75
  error,
75
76
  columns,
76
77
  commit,
@@ -101,6 +102,7 @@ function RolesEditor({
101
102
  onChange,
102
103
  required,
103
104
  hint,
105
+ help,
104
106
  error,
105
107
  columns,
106
108
  commit,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/role-select.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { hasContent } from \"../lib/presence\";\nimport type { RoleVocabulary } from \"../components/account-chips\";\nimport { CheckboxGroup } from \"../components/checkbox-group\";\nimport type { CheckboxGroupOption } from \"../components/checkbox-group\";\nimport { Select } from \"../components/select\";\nimport type { SelectProps } from \"../components/select\";\nimport type { CommitScope } from \"../components/write-lock\";\nimport { DEFAULT_ROLE_SELECT_LABELS } from \"./role-select-labels\";\n\n/**\n * The role of an account, chosen by an admin (docs/user-admin-harmonization.md §3.3,\n * §4.1, §7): {@link RoleSelect} for the apps where an account has ONE role (keksdose,\n * Kurvenschmiede) and {@link RolesEditor} for kastlan, where an account has several per\n * company.\n *\n * Both take the app's {@link RoleVocabulary} — the one `RoleChip` reads — so a role is\n * called the same in the chip, the select and the editor. Neither sends a request: a role\n * change is an `acknowledge` action (§4.2), so the app opens `AdminActionConfirm` from\n * `onChange` and the value stays where the server has it until the server says otherwise.\n *\n * WHY THE REASONS. The server refuses the last active admin's demotion (`last_admin`),\n * your own admin role (`self`), Kurvenschmiede's CUSTOMER for an account that owns work,\n * kastlan's TENANT until a tenant portal exists (§4.1, §9.6). A choice the server will\n * refuse is shown as unavailable, with why, rather than offered and answered with an\n * error after a confirmation dialog — the 0.18 write-lock rule: a control that cannot\n * act says so where it is. `\"last_admin\"` and `\"self\"` are the kit's words in every\n * language; anything else is the app's own sentence.\n */\n\n/** A reason the kit words itself. `self_action` is the server's code for `self` (the\n * account error codes), so a refusal's code can be handed on as it came. */\nexport type RoleLockCode = \"last_admin\" | \"self\" | \"self_action\";\n\n/**\n * Why a role (or the whole control) cannot be changed: one of the kit's\n * {@link RoleLockCode}s, or the app's own words.\n */\nexport type RoleLock = RoleLockCode | (string & {}) | ReactNode;\n\n/** The `roleSelect` namespace — RoleSelect's and RolesEditor's words. */\nexport interface RoleSelectLabels {\n /** The select's name where no `label` is drawn, and RolesEditor's legend. \"Role\". */\n label: string;\n /** RolesEditor's legend. \"Roles\". */\n rolesLegend: string;\n /** The select's accessible name in a roster row — \"Role of Ada Example\". */\n roleOf: (name: string) => string;\n /** The whole control is locked: the account is the last active administrator. */\n lockedLastAdmin: string;\n /** The whole control is locked: it is the admin's own account. */\n lockedSelf: string;\n /** One option is unavailable for the last active administrator — said after the\n * role's name, inside the option. */\n notForLastAdmin: string;\n /** One option is unavailable on the admin's own account. */\n notForSelf: string;\n /** An unavailable option's text: the role's name and why. */\n unavailable: (role: string, reason: string) => string;\n}\n\n// Defined in ./role-select-labels, which holds no component code (0.34, KS U8).\nexport { DEFAULT_ROLE_SELECT_LABELS };\n\n/** The whole-control reason, the kit's codes in the kit's words. */\nfunction lockText(reason: RoleLock, labels: RoleSelectLabels): ReactNode {\n if (reason === \"last_admin\") return labels.lockedLastAdmin;\n if (reason === \"self\" || reason === \"self_action\") return labels.lockedSelf;\n return reason;\n}\n\n/** An option's reason as the text a native `<option>` can hold. */\nfunction optionReasonText(reason: string, labels: RoleSelectLabels): string {\n if (reason === \"last_admin\") return labels.notForLastAdmin;\n if (reason === \"self\" || reason === \"self_action\") return labels.notForSelf;\n return reason;\n}\n\n/** The vocabulary's keys, in its own order. */\nfunction keysOf<R extends string>(roles: RoleVocabulary<R>): R[] {\n return Object.keys(roles) as R[];\n}\n\n/* ── RoleSelect ─────────────────────────────────────────────────────────────── */\n\nexport interface RoleSelectProps<R extends string = string>\n extends Omit<SelectProps, \"value\" | \"defaultValue\" | \"onChange\" | \"children\" | \"multiple\" | \"disabledReason\"> {\n /** The role the server has. Controlled: a pick does not move the select until the\n * app's request lands and the row comes back with the new role. */\n value: R | null | undefined;\n /** The app's roles — what `RoleChip` reads. Their order is the list's. */\n roles: RoleVocabulary<R>;\n /** A role other than `value` was picked. The app asks `AdminActionConfirm` (an\n * `acknowledge` action, §4.2) and sends the change. */\n onChange: (role: R) => void;\n /**\n * The roles that may be CHOSEN here, in the vocabulary's order whatever order this is\n * in. Default: all of them. A role the account holds that is not offered (Kurvenschmiede's\n * REVIEWER, given only through the reviewer scope, §9.6) is still shown, unavailable:\n * a select that dropped it would show the account as something it is not.\n */\n offered?: readonly R[];\n /**\n * Why the whole choice is locked for this account: `\"last_admin\"`, `\"self\"`, or the\n * app's own words. The select stays focusable and says so (Select's `disabledReason`).\n */\n disabledReason?: RoleLock;\n /**\n * Why ONE role cannot be chosen for this account: `\"last_admin\"`, `\"self\"`, or the\n * app's own words (Kurvenschmiede: \"owns work\", for CUSTOMER) — a STRING, because a\n * native option holds text only. The option is disabled and reads \"Member (not for the\n * last administrator)\". `undefined` for an available role.\n */\n optionDisabledReason?: (role: R) => string | undefined;\n /** The account's name, for the select's accessible name in a roster row (\"Role of\n * Ada Example\") where no `label` is drawn. */\n name?: string;\n labels?: LabelOverride<RoleSelectLabels>;\n}\n\n/**\n * One role, picked from the app's vocabulary — Kurvenschmiede's roster `Select`\n * (users-panel.tsx), with the reasons it left to the server's toast drawn in place.\n *\n * Unlabelled by default, for a table cell: named \"Role of Ada Example\" (`name`) or\n * \"Role\". Pass `label` for a form field. Every {@link Select} prop passes through\n * (`size`, `commit`, `hint`, `error`, `data-*`).\n */\nexport function RoleSelect<R extends string = string>({\n value,\n roles,\n onChange,\n offered,\n disabledReason,\n optionDisabledReason,\n name,\n labels: labelsProp,\n label,\n ...rest\n}: RoleSelectProps<R>) {\n const labels = useKitLabels(\"roleSelect\", DEFAULT_ROLE_SELECT_LABELS, labelsProp);\n const all = keysOf(roles);\n const choosable = new Set<R>(offered ?? all);\n const held = value ?? null;\n // A cell has no room for a visible label: the select is named for the account it\n // belongs to, so fifty of them in a roster are not fifty \"Role\"s.\n const ariaLabel =\n label === undefined ? (rest[\"aria-label\"] ?? (name ? labels.roleOf(name) : labels.label)) : rest[\"aria-label\"];\n return (\n <Select\n {...rest}\n label={label}\n aria-label={ariaLabel}\n value={held ?? \"\"}\n disabledReason={hasContent(disabledReason) ? lockText(disabledReason, labels) : undefined}\n onChange={(event) => {\n const next = event.target.value as R;\n if (next && next !== held) onChange(next);\n }}\n >\n {held === null && <option value=\"\" disabled />}\n {all\n .filter((role) => choosable.has(role) || role === held)\n .map((role) => {\n const word = roles[role].label;\n const reason = role === held ? undefined : optionDisabledReason?.(role);\n const unavailable = !choosable.has(role) || hasContent(reason);\n return (\n <option key={role} value={role} disabled={unavailable && role !== held}>\n {reason ? labels.unavailable(word, optionReasonText(reason, labels)) : word}\n </option>\n );\n })}\n {/* A role the vocabulary does not know (an older client against a newer API) is\n still the account's role: shown as its key, as RoleChip shows it. */}\n {held !== null && !all.includes(held) && (\n <option value={held} disabled>\n {held}\n </option>\n )}\n </Select>\n );\n}\n\n/* ── RolesEditor ────────────────────────────────────────────────────────────── */\n\nexport interface RolesEditorProps<R extends string = string> {\n /** The roles ticked — the draft the app holds while its dialog is open. */\n value: readonly R[];\n roles: RoleVocabulary<R>;\n /** The new set, in the vocabulary's order (a role the editor does not offer, but the\n * account holds, is kept after the rest — CheckboxGroup's rule). */\n onChange: (roles: R[]) => void;\n /** The roles that may be ticked or unticked here. Default: all. kastlan leaves TENANT\n * out until a tenant portal exists (§4.1). */\n offered?: readonly R[];\n /** Why nothing can be changed: `\"last_admin\"`, `\"self\"` or the app's words. */\n disabledReason?: RoleLock;\n /** Why one role cannot be changed — shown under it, and the box keeps its state:\n * `\"last_admin\"` on the last administrator's ADMIN, say. */\n optionDisabledReason?: (role: R) => RoleLock | undefined;\n /** Default `roleSelect.rolesLegend` — \"Roles\". kastlan names the company: \"Roles in\n * Example Ltd\". */\n legend?: ReactNode;\n legendVisibility?: \"visible\" | \"sr-only\";\n /** At least one role (kastlan's dialog saves none). Draws the required star. */\n required?: boolean;\n hint?: ReactNode;\n error?: ReactNode;\n columns?: 1 | 2 | 3 | 4;\n /** The editor SAVES on change — the write lock's opt-in (CheckboxGroup's `commit`). */\n commit?: CommitScope;\n className?: string;\n labels?: LabelOverride<RoleSelectLabels>;\n}\n\n/**\n * Several roles at once — kastlan's manage-roles dialog (`ChoiceCardGroup multiple`),\n * which holds an account's roles in the CURRENT company (§4.1: `PUT /admin/users/{id}/roles`).\n * A kit {@link CheckboxGroup} of the vocabulary, with the reasons of {@link RoleSelect}:\n * a role that cannot change keeps its box as it is and says why under it.\n *\n * A field, not a form: the app's dialog holds the draft, and its Save goes through\n * `AdminActionConfirm` (`acknowledge`, §4.2) — which can draw this editor as its\n * `children`, so the roles and the tick are one dialog.\n */\nexport function RolesEditor<R extends string = string>({\n value,\n roles,\n onChange,\n offered,\n disabledReason,\n optionDisabledReason,\n legend,\n legendVisibility,\n required,\n hint,\n error,\n columns,\n commit,\n className,\n labels: labelsProp,\n}: RolesEditorProps<R>) {\n const labels = useKitLabels(\"roleSelect\", DEFAULT_ROLE_SELECT_LABELS, labelsProp);\n const all = keysOf(roles);\n const choosable = new Set<R>(offered ?? all);\n const held = new Set<R>(value);\n const options: CheckboxGroupOption<R>[] = all\n .filter((role) => choosable.has(role) || held.has(role))\n .map((role) => {\n const reason = optionDisabledReason?.(role);\n const locked = hasContent(reason);\n return {\n value: role,\n label: roles[role].label,\n hint: locked ? lockText(reason, labels) : undefined,\n disabled: locked || !choosable.has(role),\n };\n });\n return (\n <CheckboxGroup<R>\n legend={legend ?? labels.rolesLegend}\n legendVisibility={legendVisibility}\n options={options}\n value={[...value]}\n onChange={onChange}\n required={required}\n hint={hint}\n error={error}\n columns={columns}\n commit={commit}\n disabledReason={hasContent(disabledReason) ? lockText(disabledReason, labels) : undefined}\n className={className}\n />\n );\n}\n"],"mappings":";AAsJI,SAWoB,KAXpB;AArJJ,SAAS,oBAAwC;AACjD,SAAS,kBAAkB;AAE3B,SAAS,qBAAqB;AAE9B,SAAS,cAAc;AAGvB,SAAS,kCAAkC;AAyD3C,SAAS,SAAS,QAAkB,QAAqC;AACvE,MAAI,WAAW,aAAc,QAAO,OAAO;AAC3C,MAAI,WAAW,UAAU,WAAW,cAAe,QAAO,OAAO;AACjE,SAAO;AACT;AAGA,SAAS,iBAAiB,QAAgB,QAAkC;AAC1E,MAAI,WAAW,aAAc,QAAO,OAAO;AAC3C,MAAI,WAAW,UAAU,WAAW,cAAe,QAAO,OAAO;AACjE,SAAO;AACT;AAGA,SAAS,OAAyB,OAA+B;AAC/D,SAAO,OAAO,KAAK,KAAK;AAC1B;AA+CO,SAAS,WAAsC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,QAAM,SAAS,aAAa,cAAc,4BAA4B,UAAU;AAChF,QAAM,MAAM,OAAO,KAAK;AACxB,QAAM,YAAY,IAAI,IAAO,WAAW,GAAG;AAC3C,QAAM,OAAO,SAAS;AAGtB,QAAM,YACJ,UAAU,SAAa,KAAK,YAAY,MAAM,OAAO,OAAO,OAAO,IAAI,IAAI,OAAO,SAAU,KAAK,YAAY;AAC/G,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,cAAY;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,gBAAgB,WAAW,cAAc,IAAI,SAAS,gBAAgB,MAAM,IAAI;AAAA,MAChF,UAAU,CAAC,UAAU;AACnB,cAAM,OAAO,MAAM,OAAO;AAC1B,YAAI,QAAQ,SAAS,KAAM,UAAS,IAAI;AAAA,MAC1C;AAAA,MAEC;AAAA,iBAAS,QAAQ,oBAAC,YAAO,OAAM,IAAG,UAAQ,MAAC;AAAA,QAC3C,IACE,OAAO,CAAC,SAAS,UAAU,IAAI,IAAI,KAAK,SAAS,IAAI,EACrD,IAAI,CAAC,SAAS;AACb,gBAAM,OAAO,MAAM,IAAI,EAAE;AACzB,gBAAM,SAAS,SAAS,OAAO,SAAY,uBAAuB,IAAI;AACtE,gBAAM,cAAc,CAAC,UAAU,IAAI,IAAI,KAAK,WAAW,MAAM;AAC7D,iBACE,oBAAC,YAAkB,OAAO,MAAM,UAAU,eAAe,SAAS,MAC/D,mBAAS,OAAO,YAAY,MAAM,iBAAiB,QAAQ,MAAM,CAAC,IAAI,QAD5D,IAEb;AAAA,QAEJ,CAAC;AAAA,QAGF,SAAS,QAAQ,CAAC,IAAI,SAAS,IAAI,KAClC,oBAAC,YAAO,OAAO,MAAM,UAAQ,MAC1B,gBACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;AA4CO,SAAS,YAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AACV,GAAwB;AACtB,QAAM,SAAS,aAAa,cAAc,4BAA4B,UAAU;AAChF,QAAM,MAAM,OAAO,KAAK;AACxB,QAAM,YAAY,IAAI,IAAO,WAAW,GAAG;AAC3C,QAAM,OAAO,IAAI,IAAO,KAAK;AAC7B,QAAM,UAAoC,IACvC,OAAO,CAAC,SAAS,UAAU,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,EACtD,IAAI,CAAC,SAAS;AACb,UAAM,SAAS,uBAAuB,IAAI;AAC1C,UAAM,SAAS,WAAW,MAAM;AAChC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,MAAM,IAAI,EAAE;AAAA,MACnB,MAAM,SAAS,SAAS,QAAQ,MAAM,IAAI;AAAA,MAC1C,UAAU,UAAU,CAAC,UAAU,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AACH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ,UAAU,OAAO;AAAA,MACzB;AAAA,MACA;AAAA,MACA,OAAO,CAAC,GAAG,KAAK;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,WAAW,cAAc,IAAI,SAAS,gBAAgB,MAAM,IAAI;AAAA,MAChF;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/admin/role-select.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { hasContent } from \"../lib/presence\";\nimport type { RoleVocabulary } from \"../components/account-chips\";\nimport { CheckboxGroup } from \"../components/checkbox-group\";\nimport type { CheckboxGroupOption } from \"../components/checkbox-group\";\nimport { Select } from \"../components/select\";\nimport type { SelectProps } from \"../components/select\";\nimport type { CommitScope } from \"../components/write-lock\";\nimport type { FieldHelpProps } from \"../components/field-parts\";\nimport { DEFAULT_ROLE_SELECT_LABELS } from \"./role-select-labels\";\n\n/**\n * The role of an account, chosen by an admin (docs/user-admin-harmonization.md §3.3,\n * §4.1, §7): {@link RoleSelect} for the apps where an account has ONE role (keksdose,\n * Kurvenschmiede) and {@link RolesEditor} for kastlan, where an account has several per\n * company.\n *\n * Both take the app's {@link RoleVocabulary} — the one `RoleChip` reads — so a role is\n * called the same in the chip, the select and the editor. Neither sends a request: a role\n * change is an `acknowledge` action (§4.2), so the app opens `AdminActionConfirm` from\n * `onChange` and the value stays where the server has it until the server says otherwise.\n *\n * WHY THE REASONS. The server refuses the last active admin's demotion (`last_admin`),\n * your own admin role (`self`), Kurvenschmiede's CUSTOMER for an account that owns work,\n * kastlan's TENANT until a tenant portal exists (§4.1, §9.6). A choice the server will\n * refuse is shown as unavailable, with why, rather than offered and answered with an\n * error after a confirmation dialog — the 0.18 write-lock rule: a control that cannot\n * act says so where it is. `\"last_admin\"` and `\"self\"` are the kit's words in every\n * language; anything else is the app's own sentence.\n */\n\n/** A reason the kit words itself. `self_action` is the server's code for `self` (the\n * account error codes), so a refusal's code can be handed on as it came. */\nexport type RoleLockCode = \"last_admin\" | \"self\" | \"self_action\";\n\n/**\n * Why a role (or the whole control) cannot be changed: one of the kit's\n * {@link RoleLockCode}s, or the app's own words.\n */\nexport type RoleLock = RoleLockCode | (string & {}) | ReactNode;\n\n/** The `roleSelect` namespace — RoleSelect's and RolesEditor's words. */\nexport interface RoleSelectLabels {\n /** The select's name where no `label` is drawn, and RolesEditor's legend. \"Role\". */\n label: string;\n /** RolesEditor's legend. \"Roles\". */\n rolesLegend: string;\n /** The select's accessible name in a roster row — \"Role of Ada Example\". */\n roleOf: (name: string) => string;\n /** The whole control is locked: the account is the last active administrator. */\n lockedLastAdmin: string;\n /** The whole control is locked: it is the admin's own account. */\n lockedSelf: string;\n /** One option is unavailable for the last active administrator — said after the\n * role's name, inside the option. */\n notForLastAdmin: string;\n /** One option is unavailable on the admin's own account. */\n notForSelf: string;\n /** An unavailable option's text: the role's name and why. */\n unavailable: (role: string, reason: string) => string;\n}\n\n// Defined in ./role-select-labels, which holds no component code (0.34, KS U8).\nexport { DEFAULT_ROLE_SELECT_LABELS };\n\n/** The whole-control reason, the kit's codes in the kit's words. */\nfunction lockText(reason: RoleLock, labels: RoleSelectLabels): ReactNode {\n if (reason === \"last_admin\") return labels.lockedLastAdmin;\n if (reason === \"self\" || reason === \"self_action\") return labels.lockedSelf;\n return reason;\n}\n\n/** An option's reason as the text a native `<option>` can hold. */\nfunction optionReasonText(reason: string, labels: RoleSelectLabels): string {\n if (reason === \"last_admin\") return labels.notForLastAdmin;\n if (reason === \"self\" || reason === \"self_action\") return labels.notForSelf;\n return reason;\n}\n\n/** The vocabulary's keys, in its own order. */\nfunction keysOf<R extends string>(roles: RoleVocabulary<R>): R[] {\n return Object.keys(roles) as R[];\n}\n\n/* ── RoleSelect ─────────────────────────────────────────────────────────────── */\n\nexport interface RoleSelectProps<R extends string = string>\n extends Omit<SelectProps, \"value\" | \"defaultValue\" | \"onChange\" | \"children\" | \"multiple\" | \"disabledReason\"> {\n /** The role the server has. Controlled: a pick does not move the select until the\n * app's request lands and the row comes back with the new role. */\n value: R | null | undefined;\n /** The app's roles — what `RoleChip` reads. Their order is the list's. */\n roles: RoleVocabulary<R>;\n /** A role other than `value` was picked. The app asks `AdminActionConfirm` (an\n * `acknowledge` action, §4.2) and sends the change. */\n onChange: (role: R) => void;\n /**\n * The roles that may be CHOSEN here, in the vocabulary's order whatever order this is\n * in. Default: all of them. A role the account holds that is not offered (Kurvenschmiede's\n * REVIEWER, given only through the reviewer scope, §9.6) is still shown, unavailable:\n * a select that dropped it would show the account as something it is not.\n */\n offered?: readonly R[];\n /**\n * Why the whole choice is locked for this account: `\"last_admin\"`, `\"self\"`, or the\n * app's own words. The select stays focusable and says so (Select's `disabledReason`).\n */\n disabledReason?: RoleLock;\n /**\n * Why ONE role cannot be chosen for this account: `\"last_admin\"`, `\"self\"`, or the\n * app's own words (Kurvenschmiede: \"owns work\", for CUSTOMER) — a STRING, because a\n * native option holds text only. The option is disabled and reads \"Member (not for the\n * last administrator)\". `undefined` for an available role.\n */\n optionDisabledReason?: (role: R) => string | undefined;\n /** The account's name, for the select's accessible name in a roster row (\"Role of\n * Ada Example\") where no `label` is drawn. */\n name?: string;\n labels?: LabelOverride<RoleSelectLabels>;\n}\n\n/**\n * One role, picked from the app's vocabulary — Kurvenschmiede's roster `Select`\n * (users-panel.tsx), with the reasons it left to the server's toast drawn in place.\n *\n * Unlabelled by default, for a table cell: named \"Role of Ada Example\" (`name`) or\n * \"Role\". Pass `label` for a form field. Every {@link Select} prop passes through\n * (`size`, `commit`, `hint`, `error`, `data-*`).\n */\nexport function RoleSelect<R extends string = string>({\n value,\n roles,\n onChange,\n offered,\n disabledReason,\n optionDisabledReason,\n name,\n labels: labelsProp,\n label,\n ...rest\n}: RoleSelectProps<R>) {\n const labels = useKitLabels(\"roleSelect\", DEFAULT_ROLE_SELECT_LABELS, labelsProp);\n const all = keysOf(roles);\n const choosable = new Set<R>(offered ?? all);\n const held = value ?? null;\n // A cell has no room for a visible label: the select is named for the account it\n // belongs to, so fifty of them in a roster are not fifty \"Role\"s.\n const ariaLabel =\n label === undefined ? (rest[\"aria-label\"] ?? (name ? labels.roleOf(name) : labels.label)) : rest[\"aria-label\"];\n return (\n <Select\n {...rest}\n label={label}\n aria-label={ariaLabel}\n value={held ?? \"\"}\n disabledReason={hasContent(disabledReason) ? lockText(disabledReason, labels) : undefined}\n onChange={(event) => {\n const next = event.target.value as R;\n if (next && next !== held) onChange(next);\n }}\n >\n {held === null && <option value=\"\" disabled />}\n {all\n .filter((role) => choosable.has(role) || role === held)\n .map((role) => {\n const word = roles[role].label;\n const reason = role === held ? undefined : optionDisabledReason?.(role);\n const unavailable = !choosable.has(role) || hasContent(reason);\n return (\n <option key={role} value={role} disabled={unavailable && role !== held}>\n {reason ? labels.unavailable(word, optionReasonText(reason, labels)) : word}\n </option>\n );\n })}\n {/* A role the vocabulary does not know (an older client against a newer API) is\n still the account's role: shown as its key, as RoleChip shows it. */}\n {held !== null && !all.includes(held) && (\n <option value={held} disabled>\n {held}\n </option>\n )}\n </Select>\n );\n}\n\n/* ── RolesEditor ────────────────────────────────────────────────────────────── */\n\nexport interface RolesEditorProps<R extends string = string> extends FieldHelpProps {\n /** The roles ticked — the draft the app holds while its dialog is open. */\n value: readonly R[];\n roles: RoleVocabulary<R>;\n /** The new set, in the vocabulary's order (a role the editor does not offer, but the\n * account holds, is kept after the rest — CheckboxGroup's rule). */\n onChange: (roles: R[]) => void;\n /** The roles that may be ticked or unticked here. Default: all. kastlan leaves TENANT\n * out until a tenant portal exists (§4.1). */\n offered?: readonly R[];\n /** Why nothing can be changed: `\"last_admin\"`, `\"self\"` or the app's words. */\n disabledReason?: RoleLock;\n /** Why one role cannot be changed — shown under it, and the box keeps its state:\n * `\"last_admin\"` on the last administrator's ADMIN, say. */\n optionDisabledReason?: (role: R) => RoleLock | undefined;\n /** Default `roleSelect.rolesLegend` — \"Roles\". kastlan names the company: \"Roles in\n * Example Ltd\". */\n legend?: ReactNode;\n legendVisibility?: \"visible\" | \"sr-only\";\n /** At least one role (kastlan's dialog saves none). Draws the required star. */\n required?: boolean;\n hint?: ReactNode;\n error?: ReactNode;\n columns?: 1 | 2 | 3 | 4;\n /** The editor SAVES on change — the write lock's opt-in (CheckboxGroup's `commit`). */\n commit?: CommitScope;\n className?: string;\n labels?: LabelOverride<RoleSelectLabels>;\n}\n\n/**\n * Several roles at once — kastlan's manage-roles dialog (`ChoiceCardGroup multiple`),\n * which holds an account's roles in the CURRENT company (§4.1: `PUT /admin/users/{id}/roles`).\n * A kit {@link CheckboxGroup} of the vocabulary, with the reasons of {@link RoleSelect}:\n * a role that cannot change keeps its box as it is and says why under it.\n *\n * A field, not a form: the app's dialog holds the draft, and its Save goes through\n * `AdminActionConfirm` (`acknowledge`, §4.2) — which can draw this editor as its\n * `children`, so the roles and the tick are one dialog.\n */\nexport function RolesEditor<R extends string = string>({\n value,\n roles,\n onChange,\n offered,\n disabledReason,\n optionDisabledReason,\n legend,\n legendVisibility,\n required,\n hint,\n help,\n error,\n columns,\n commit,\n className,\n labels: labelsProp,\n}: RolesEditorProps<R>) {\n const labels = useKitLabels(\"roleSelect\", DEFAULT_ROLE_SELECT_LABELS, labelsProp);\n const all = keysOf(roles);\n const choosable = new Set<R>(offered ?? all);\n const held = new Set<R>(value);\n const options: CheckboxGroupOption<R>[] = all\n .filter((role) => choosable.has(role) || held.has(role))\n .map((role) => {\n const reason = optionDisabledReason?.(role);\n const locked = hasContent(reason);\n return {\n value: role,\n label: roles[role].label,\n hint: locked ? lockText(reason, labels) : undefined,\n disabled: locked || !choosable.has(role),\n };\n });\n return (\n <CheckboxGroup<R>\n legend={legend ?? labels.rolesLegend}\n legendVisibility={legendVisibility}\n options={options}\n value={[...value]}\n onChange={onChange}\n required={required}\n hint={hint}\n help={help}\n error={error}\n columns={columns}\n commit={commit}\n disabledReason={hasContent(disabledReason) ? lockText(disabledReason, labels) : undefined}\n className={className}\n />\n );\n}\n"],"mappings":";AAuJI,SAWoB,KAXpB;AAtJJ,SAAS,oBAAwC;AACjD,SAAS,kBAAkB;AAE3B,SAAS,qBAAqB;AAE9B,SAAS,cAAc;AAIvB,SAAS,kCAAkC;AAyD3C,SAAS,SAAS,QAAkB,QAAqC;AACvE,MAAI,WAAW,aAAc,QAAO,OAAO;AAC3C,MAAI,WAAW,UAAU,WAAW,cAAe,QAAO,OAAO;AACjE,SAAO;AACT;AAGA,SAAS,iBAAiB,QAAgB,QAAkC;AAC1E,MAAI,WAAW,aAAc,QAAO,OAAO;AAC3C,MAAI,WAAW,UAAU,WAAW,cAAe,QAAO,OAAO;AACjE,SAAO;AACT;AAGA,SAAS,OAAyB,OAA+B;AAC/D,SAAO,OAAO,KAAK,KAAK;AAC1B;AA+CO,SAAS,WAAsC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,QAAM,SAAS,aAAa,cAAc,4BAA4B,UAAU;AAChF,QAAM,MAAM,OAAO,KAAK;AACxB,QAAM,YAAY,IAAI,IAAO,WAAW,GAAG;AAC3C,QAAM,OAAO,SAAS;AAGtB,QAAM,YACJ,UAAU,SAAa,KAAK,YAAY,MAAM,OAAO,OAAO,OAAO,IAAI,IAAI,OAAO,SAAU,KAAK,YAAY;AAC/G,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,cAAY;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,gBAAgB,WAAW,cAAc,IAAI,SAAS,gBAAgB,MAAM,IAAI;AAAA,MAChF,UAAU,CAAC,UAAU;AACnB,cAAM,OAAO,MAAM,OAAO;AAC1B,YAAI,QAAQ,SAAS,KAAM,UAAS,IAAI;AAAA,MAC1C;AAAA,MAEC;AAAA,iBAAS,QAAQ,oBAAC,YAAO,OAAM,IAAG,UAAQ,MAAC;AAAA,QAC3C,IACE,OAAO,CAAC,SAAS,UAAU,IAAI,IAAI,KAAK,SAAS,IAAI,EACrD,IAAI,CAAC,SAAS;AACb,gBAAM,OAAO,MAAM,IAAI,EAAE;AACzB,gBAAM,SAAS,SAAS,OAAO,SAAY,uBAAuB,IAAI;AACtE,gBAAM,cAAc,CAAC,UAAU,IAAI,IAAI,KAAK,WAAW,MAAM;AAC7D,iBACE,oBAAC,YAAkB,OAAO,MAAM,UAAU,eAAe,SAAS,MAC/D,mBAAS,OAAO,YAAY,MAAM,iBAAiB,QAAQ,MAAM,CAAC,IAAI,QAD5D,IAEb;AAAA,QAEJ,CAAC;AAAA,QAGF,SAAS,QAAQ,CAAC,IAAI,SAAS,IAAI,KAClC,oBAAC,YAAO,OAAO,MAAM,UAAQ,MAC1B,gBACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;AA4CO,SAAS,YAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AACV,GAAwB;AACtB,QAAM,SAAS,aAAa,cAAc,4BAA4B,UAAU;AAChF,QAAM,MAAM,OAAO,KAAK;AACxB,QAAM,YAAY,IAAI,IAAO,WAAW,GAAG;AAC3C,QAAM,OAAO,IAAI,IAAO,KAAK;AAC7B,QAAM,UAAoC,IACvC,OAAO,CAAC,SAAS,UAAU,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,EACtD,IAAI,CAAC,SAAS;AACb,UAAM,SAAS,uBAAuB,IAAI;AAC1C,UAAM,SAAS,WAAW,MAAM;AAChC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,MAAM,IAAI,EAAE;AAAA,MACnB,MAAM,SAAS,SAAS,QAAQ,MAAM,IAAI;AAAA,MAC1C,UAAU,UAAU,CAAC,UAAU,IAAI,IAAI;AAAA,IACzC;AAAA,EACF,CAAC;AACH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ,UAAU,OAAO;AAAA,MACzB;AAAA,MACA;AAAA,MACA,OAAO,CAAC,GAAG,KAAK;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,WAAW,cAAc,IAAI,SAAS,gBAAgB,MAAM,IAAI;AAAA,MAChF;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,4 +1,4 @@
1
- import type { ComponentPropsWithoutRef } from "react";
1
+ import type { ComponentPropsWithRef } from "react";
2
2
  import type { LabelOverride } from "../i18n/kit-labels.js";
3
3
  import type { AlertSize, AlertTone } from "../components/alert-banner.js";
4
4
  import type { BillingLabels } from "./billing-labels.js";
@@ -15,7 +15,10 @@ import type { BillingLabels } from "./billing-labels.js";
15
15
  * - `processing` — back from checkout before the webhook landed (§12.21).
16
16
  */
17
17
  export type BillingBannerKind = "trial-ending" | "grant-ending" | "payment-failed" | "plan-ended" | "guest" | "processing";
18
- interface BillingBannerBaseProps extends Omit<ComponentPropsWithoutRef<"div">, "children" | "onClick"> {
18
+ /** A `div`'s props, `ref` included since 0.35 (round 0.35 R4, the follow-up to API-2): they
19
+ * go on to the {@link AlertBanner}, so the ref is the banner's `<div>` — with an × too,
20
+ * since the banner has no `href` or `onClick` that would make its row a link or a button. */
21
+ interface BillingBannerBaseProps extends Omit<ComponentPropsWithRef<"div">, "children" | "onClick"> {
19
22
  /**
20
23
  * Over the kind's tone: `trial-ending` and `grant-ending` are `info` until the last
21
24
  * three days and `warning` in them; `payment-failed` is `danger` (money did not
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/billing/billing-banner.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ReactNode } from \"react\";\nimport { CreditCard, Hourglass, PencilOff } from \"lucide-react\";\n\nimport type { LabelOverride } from \"../i18n/kit-labels\";\nimport { AlertBanner } from \"../components/alert-banner\";\nimport type { AlertSize, AlertTone } from \"../components/alert-banner\";\nimport { Button } from \"../components/button\";\nimport { Spinner } from \"../components/spinner\";\nimport { useBillingLabels } from \"./billing-labels\";\nimport type { BillingLabels } from \"./billing-labels\";\n\n/**\n * The billing banners (docs/billing-harmonization.md §3.3, §7, §12.6, §12.21):\n *\n * - `trial-ending` — from 7 days before `trial_ends_at` (§3.3);\n * - `grant-ending` — from 7 days before `comped_until`: a beta user's 12 months, an\n * operator's grant;\n * - `payment-failed` — from the first failed payment (`past_due`), while the provider\n * retries;\n * - `plan-ended` — out of good standing: read-only, never locked (§2.3);\n * - `guest` — a guest in someone else's read-only item (§12.6);\n * - `processing` — back from checkout before the webhook landed (§12.21).\n */\nexport type BillingBannerKind =\n | \"trial-ending\"\n | \"grant-ending\"\n | \"payment-failed\"\n | \"plan-ended\"\n | \"guest\"\n | \"processing\";\n\ninterface BillingBannerBaseProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\" | \"onClick\"> {\n /**\n * Over the kind's tone: `trial-ending` and `grant-ending` are `info` until the last\n * three days and `warning` in them; `payment-failed` is `danger` (money did not\n * arrive — kastlan's past-due strip was red); `plan-ended` is `warning`, a state with\n * everything still there rather than an error; `guest` and `processing` are `info`.\n */\n tone?: AlertTone;\n /** `strip` (default): the band under the top bar, on every page. `box`: the same\n * message on the subscription page itself. */\n variant?: \"strip\" | \"box\";\n /** Default `sm` for a strip (the demo's banner), `md` for a box. */\n size?: AlertSize;\n /**\n * Where the action goes — the subscription page, say. The app's action, as an `href`\n * or as {@link onAction}; without either there is no button. Never a write-locked\n * commit: billing itself always works (§3.3).\n */\n actionHref?: string;\n /** What the action does — the app's portal call (`POST /billing/portal`, then off to\n * its `url`): for `payment-failed` with `{target: \"payment_method\"}`, the portal's\n * page for the card (§14.5); for `processing`, `useCheckoutProcessing`'s\n * `checkAgain`. The kit sends no request. */\n onAction?: () => void;\n /**\n * Over the kind's action words: \"Choose a plan\" (trial, grant, plan ended), \"Update\n * payment method\" (payment failed), \"Check again\" (processing). The guest banner has\n * none of its own: an action there needs this.\n */\n actionLabel?: string;\n /** The action is under way: the button's spinner, no second press. */\n actionPending?: boolean;\n /** An × that calls this; the app removes the banner and remembers that it did. */\n onDismiss?: () => void;\n dismissLabel?: string;\n /** Prop > `<UiKitProvider labels={{ billing }}>` > English. */\n labels?: LabelOverride<BillingLabels>;\n}\n\nexport type BillingBannerProps = BillingBannerBaseProps &\n (\n | {\n kind: \"trial-ending\" | \"grant-ending\";\n /** Calendar days left — `billingDaysLeft(trial_ends_at)`. 0 is today. */\n daysLeft: number;\n item?: never;\n }\n | {\n kind: \"guest\";\n /** The item's own name (\"Household 2026\"), or nothing. NEVER the owner's status:\n * the banner says \"for now\" and nothing more (§12.6). */\n item?: string;\n daysLeft?: never;\n }\n | {\n kind: \"payment-failed\" | \"plan-ended\" | \"processing\";\n daysLeft?: never;\n item?: never;\n }\n );\n\n/** The last days, in which an ending trial or grant turns from news into a warning. */\nconst LAST_DAYS = 3;\n\nfunction defaultTone(kind: BillingBannerKind, daysLeft: number | undefined): AlertTone {\n switch (kind) {\n case \"trial-ending\":\n case \"grant-ending\":\n return (daysLeft ?? 0) > LAST_DAYS ? \"info\" : \"warning\";\n case \"payment-failed\":\n return \"danger\";\n case \"plan-ended\":\n return \"warning\";\n default:\n return \"info\";\n }\n}\n\n/**\n * One of the billing banners, as a kit `AlertBanner` strip (§7): the kind's sentence, its\n * glyph and tone, and the app's action. Carries `data-billing-banner` with the kind.\n *\n * The app decides WHICH banner shows, from `GET /billing/overview` (and hides all of them\n * while billing is off, §4); the kit only says it. A guest's banner takes no status at\n * all — the type does not let one in — so the owner's payment state cannot leak into it\n * by a wrong prop (§12.6).\n *\n * `processing` is a live region (`role=\"status\"`): it appears when the person comes back\n * from checkout and goes when the overview catches up (§12.21), and a screen reader\n * should hear both. The others are page furniture, role-less as the strip is.\n */\nexport function BillingBanner(props: BillingBannerProps) {\n const {\n kind,\n daysLeft,\n item,\n tone,\n variant = \"strip\",\n size,\n actionHref,\n onAction,\n actionLabel,\n actionPending,\n onDismiss,\n dismissLabel,\n labels: labelsProp,\n role,\n ...rest\n } = props;\n const labels = useBillingLabels(labelsProp);\n const days = Math.max(0, Math.floor(daysLeft ?? 0));\n\n let text: string;\n let icon: ReactNode;\n let ownAction: string | undefined;\n switch (kind) {\n case \"trial-ending\":\n text = labels.trialEnding(days);\n icon = <Hourglass />;\n ownAction = labels.choosePlan;\n break;\n case \"grant-ending\":\n text = labels.grantEnding(days);\n icon = <Hourglass />;\n ownAction = labels.choosePlan;\n break;\n case \"payment-failed\":\n text = labels.paymentFailed;\n icon = <CreditCard />;\n ownAction = labels.updatePayment;\n break;\n case \"plan-ended\":\n text = labels.planEnded;\n icon = <PencilOff />;\n ownAction = labels.choosePlan;\n break;\n case \"guest\":\n text = labels.guestReadOnly(item);\n icon = <PencilOff />;\n ownAction = undefined;\n break;\n case \"processing\":\n text = labels.processing;\n icon = <Spinner label={null} />;\n ownAction = labels.checkAgain;\n break;\n }\n\n const words = actionLabel ?? ownAction;\n const action =\n words === undefined || (actionHref === undefined && onAction === undefined) ? undefined : actionHref !== undefined ? (\n <Button href={actionHref} variant=\"secondary\" size=\"sm\">\n {words}\n </Button>\n ) : (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={onAction} pending={actionPending}>\n {words}\n </Button>\n );\n\n return (\n <AlertBanner\n {...rest}\n role={role ?? (kind === \"processing\" ? \"status\" : undefined)}\n variant={variant}\n size={size ?? (variant === \"strip\" ? \"sm\" : \"md\")}\n tone={tone ?? defaultTone(kind, days)}\n icon={icon}\n action={action}\n onDismiss={onDismiss}\n dismissLabel={dismissLabel}\n data-billing-banner={kind}\n >\n {text}\n </AlertBanner>\n );\n}\n"],"mappings":";AAqJa;AApJb,SAAS,YAAY,WAAW,iBAAiB;AAGjD,SAAS,mBAAmB;AAE5B,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,wBAAwB;AAqFjC,MAAM,YAAY;AAElB,SAAS,YAAY,MAAyB,UAAyC;AACrF,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AACH,cAAQ,YAAY,KAAK,YAAY,SAAS;AAAA,IAChD,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAeO,SAAS,cAAc,OAA2B;AACvD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,SAAS,iBAAiB,UAAU;AAC1C,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,CAAC,CAAC;AAElD,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO,YAAY,IAAI;AAC9B,aAAO,oBAAC,aAAU;AAClB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO,YAAY,IAAI;AAC9B,aAAO,oBAAC,aAAU;AAClB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO;AACd,aAAO,oBAAC,cAAW;AACnB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO;AACd,aAAO,oBAAC,aAAU;AAClB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO,cAAc,IAAI;AAChC,aAAO,oBAAC,aAAU;AAClB,kBAAY;AACZ;AAAA,IACF,KAAK;AACH,aAAO,OAAO;AACd,aAAO,oBAAC,WAAQ,OAAO,MAAM;AAC7B,kBAAY,OAAO;AACnB;AAAA,EACJ;AAEA,QAAM,QAAQ,eAAe;AAC7B,QAAM,SACJ,UAAU,UAAc,eAAe,UAAa,aAAa,SAAa,SAAY,eAAe,SACvG,oBAAC,UAAO,MAAM,YAAY,SAAQ,aAAY,MAAK,MAChD,iBACH,IAEA,oBAAC,UAAO,MAAK,UAAS,SAAQ,aAAY,MAAK,MAAK,SAAS,UAAU,SAAS,eAC7E,iBACH;AAGJ,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,MAAM,SAAS,SAAS,eAAe,WAAW;AAAA,MAClD;AAAA,MACA,MAAM,SAAS,YAAY,UAAU,OAAO;AAAA,MAC5C,MAAM,QAAQ,YAAY,MAAM,IAAI;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uBAAqB;AAAA,MAEpB;AAAA;AAAA,EACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/billing/billing-banner.tsx"],"sourcesContent":["import type { ComponentPropsWithRef, ReactNode } from \"react\";\nimport { CreditCard, Hourglass, PencilOff } from \"lucide-react\";\n\nimport type { LabelOverride } from \"../i18n/kit-labels\";\nimport { AlertBanner } from \"../components/alert-banner\";\nimport type { AlertSize, AlertTone } from \"../components/alert-banner\";\nimport { Button } from \"../components/button\";\nimport { Spinner } from \"../components/spinner\";\nimport { useBillingLabels } from \"./billing-labels\";\nimport type { BillingLabels } from \"./billing-labels\";\n\n/**\n * The billing banners (docs/billing-harmonization.md §3.3, §7, §12.6, §12.21):\n *\n * - `trial-ending` — from 7 days before `trial_ends_at` (§3.3);\n * - `grant-ending` — from 7 days before `comped_until`: a beta user's 12 months, an\n * operator's grant;\n * - `payment-failed` — from the first failed payment (`past_due`), while the provider\n * retries;\n * - `plan-ended` — out of good standing: read-only, never locked (§2.3);\n * - `guest` — a guest in someone else's read-only item (§12.6);\n * - `processing` — back from checkout before the webhook landed (§12.21).\n */\nexport type BillingBannerKind =\n | \"trial-ending\"\n | \"grant-ending\"\n | \"payment-failed\"\n | \"plan-ended\"\n | \"guest\"\n | \"processing\";\n\n/** A `div`'s props, `ref` included since 0.35 (round 0.35 R4, the follow-up to API-2): they\n * go on to the {@link AlertBanner}, so the ref is the banner's `<div>` — with an × too,\n * since the banner has no `href` or `onClick` that would make its row a link or a button. */\ninterface BillingBannerBaseProps extends Omit<ComponentPropsWithRef<\"div\">, \"children\" | \"onClick\"> {\n /**\n * Over the kind's tone: `trial-ending` and `grant-ending` are `info` until the last\n * three days and `warning` in them; `payment-failed` is `danger` (money did not\n * arrive — kastlan's past-due strip was red); `plan-ended` is `warning`, a state with\n * everything still there rather than an error; `guest` and `processing` are `info`.\n */\n tone?: AlertTone;\n /** `strip` (default): the band under the top bar, on every page. `box`: the same\n * message on the subscription page itself. */\n variant?: \"strip\" | \"box\";\n /** Default `sm` for a strip (the demo's banner), `md` for a box. */\n size?: AlertSize;\n /**\n * Where the action goes — the subscription page, say. The app's action, as an `href`\n * or as {@link onAction}; without either there is no button. Never a write-locked\n * commit: billing itself always works (§3.3).\n */\n actionHref?: string;\n /** What the action does — the app's portal call (`POST /billing/portal`, then off to\n * its `url`): for `payment-failed` with `{target: \"payment_method\"}`, the portal's\n * page for the card (§14.5); for `processing`, `useCheckoutProcessing`'s\n * `checkAgain`. The kit sends no request. */\n onAction?: () => void;\n /**\n * Over the kind's action words: \"Choose a plan\" (trial, grant, plan ended), \"Update\n * payment method\" (payment failed), \"Check again\" (processing). The guest banner has\n * none of its own: an action there needs this.\n */\n actionLabel?: string;\n /** The action is under way: the button's spinner, no second press. */\n actionPending?: boolean;\n /** An × that calls this; the app removes the banner and remembers that it did. */\n onDismiss?: () => void;\n dismissLabel?: string;\n /** Prop > `<UiKitProvider labels={{ billing }}>` > English. */\n labels?: LabelOverride<BillingLabels>;\n}\n\nexport type BillingBannerProps = BillingBannerBaseProps &\n (\n | {\n kind: \"trial-ending\" | \"grant-ending\";\n /** Calendar days left — `billingDaysLeft(trial_ends_at)`. 0 is today. */\n daysLeft: number;\n item?: never;\n }\n | {\n kind: \"guest\";\n /** The item's own name (\"Household 2026\"), or nothing. NEVER the owner's status:\n * the banner says \"for now\" and nothing more (§12.6). */\n item?: string;\n daysLeft?: never;\n }\n | {\n kind: \"payment-failed\" | \"plan-ended\" | \"processing\";\n daysLeft?: never;\n item?: never;\n }\n );\n\n/** The last days, in which an ending trial or grant turns from news into a warning. */\nconst LAST_DAYS = 3;\n\nfunction defaultTone(kind: BillingBannerKind, daysLeft: number | undefined): AlertTone {\n switch (kind) {\n case \"trial-ending\":\n case \"grant-ending\":\n return (daysLeft ?? 0) > LAST_DAYS ? \"info\" : \"warning\";\n case \"payment-failed\":\n return \"danger\";\n case \"plan-ended\":\n return \"warning\";\n default:\n return \"info\";\n }\n}\n\n/**\n * One of the billing banners, as a kit `AlertBanner` strip (§7): the kind's sentence, its\n * glyph and tone, and the app's action. Carries `data-billing-banner` with the kind.\n *\n * The app decides WHICH banner shows, from `GET /billing/overview` (and hides all of them\n * while billing is off, §4); the kit only says it. A guest's banner takes no status at\n * all — the type does not let one in — so the owner's payment state cannot leak into it\n * by a wrong prop (§12.6).\n *\n * `processing` is a live region (`role=\"status\"`): it appears when the person comes back\n * from checkout and goes when the overview catches up (§12.21), and a screen reader\n * should hear both. The others are page furniture, role-less as the strip is.\n */\nexport function BillingBanner(props: BillingBannerProps) {\n const {\n kind,\n daysLeft,\n item,\n tone,\n variant = \"strip\",\n size,\n actionHref,\n onAction,\n actionLabel,\n actionPending,\n onDismiss,\n dismissLabel,\n labels: labelsProp,\n role,\n ...rest\n } = props;\n const labels = useBillingLabels(labelsProp);\n const days = Math.max(0, Math.floor(daysLeft ?? 0));\n\n let text: string;\n let icon: ReactNode;\n let ownAction: string | undefined;\n switch (kind) {\n case \"trial-ending\":\n text = labels.trialEnding(days);\n icon = <Hourglass />;\n ownAction = labels.choosePlan;\n break;\n case \"grant-ending\":\n text = labels.grantEnding(days);\n icon = <Hourglass />;\n ownAction = labels.choosePlan;\n break;\n case \"payment-failed\":\n text = labels.paymentFailed;\n icon = <CreditCard />;\n ownAction = labels.updatePayment;\n break;\n case \"plan-ended\":\n text = labels.planEnded;\n icon = <PencilOff />;\n ownAction = labels.choosePlan;\n break;\n case \"guest\":\n text = labels.guestReadOnly(item);\n icon = <PencilOff />;\n ownAction = undefined;\n break;\n case \"processing\":\n text = labels.processing;\n icon = <Spinner label={null} />;\n ownAction = labels.checkAgain;\n break;\n }\n\n const words = actionLabel ?? ownAction;\n const action =\n words === undefined || (actionHref === undefined && onAction === undefined) ? undefined : actionHref !== undefined ? (\n <Button href={actionHref} variant=\"secondary\" size=\"sm\">\n {words}\n </Button>\n ) : (\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={onAction} pending={actionPending}>\n {words}\n </Button>\n );\n\n return (\n <AlertBanner\n {...rest}\n role={role ?? (kind === \"processing\" ? \"status\" : undefined)}\n variant={variant}\n size={size ?? (variant === \"strip\" ? \"sm\" : \"md\")}\n tone={tone ?? defaultTone(kind, days)}\n icon={icon}\n action={action}\n onDismiss={onDismiss}\n dismissLabel={dismissLabel}\n data-billing-banner={kind}\n >\n {text}\n </AlertBanner>\n );\n}\n"],"mappings":";AAwJa;AAvJb,SAAS,YAAY,WAAW,iBAAiB;AAGjD,SAAS,mBAAmB;AAE5B,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,wBAAwB;AAwFjC,MAAM,YAAY;AAElB,SAAS,YAAY,MAAyB,UAAyC;AACrF,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AACH,cAAQ,YAAY,KAAK,YAAY,SAAS;AAAA,IAChD,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAeO,SAAS,cAAc,OAA2B;AACvD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,SAAS,iBAAiB,UAAU;AAC1C,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,CAAC,CAAC;AAElD,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO,YAAY,IAAI;AAC9B,aAAO,oBAAC,aAAU;AAClB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO,YAAY,IAAI;AAC9B,aAAO,oBAAC,aAAU;AAClB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO;AACd,aAAO,oBAAC,cAAW;AACnB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO;AACd,aAAO,oBAAC,aAAU;AAClB,kBAAY,OAAO;AACnB;AAAA,IACF,KAAK;AACH,aAAO,OAAO,cAAc,IAAI;AAChC,aAAO,oBAAC,aAAU;AAClB,kBAAY;AACZ;AAAA,IACF,KAAK;AACH,aAAO,OAAO;AACd,aAAO,oBAAC,WAAQ,OAAO,MAAM;AAC7B,kBAAY,OAAO;AACnB;AAAA,EACJ;AAEA,QAAM,QAAQ,eAAe;AAC7B,QAAM,SACJ,UAAU,UAAc,eAAe,UAAa,aAAa,SAAa,SAAY,eAAe,SACvG,oBAAC,UAAO,MAAM,YAAY,SAAQ,aAAY,MAAK,MAChD,iBACH,IAEA,oBAAC,UAAO,MAAK,UAAS,SAAQ,aAAY,MAAK,MAAK,SAAS,UAAU,SAAS,eAC7E,iBACH;AAGJ,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,MAAM,SAAS,SAAS,eAAe,WAAW;AAAA,MAClD;AAAA,MACA,MAAM,SAAS,YAAY,UAAU,OAAO;AAAA,MAC5C,MAAM,QAAQ,YAAY,MAAM,IAAI;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uBAAqB;AAAA,MAEpB;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -1,10 +1,13 @@
1
- import type { ComponentPropsWithoutRef } from "react";
1
+ import type { ComponentPropsWithRef } from "react";
2
2
  import type { LabelOverride } from "../i18n/kit-labels.js";
3
3
  import type { AlertTone } from "../components/alert-banner.js";
4
4
  import type { BillingLabels } from "./billing-labels.js";
5
5
  /** The `contact` mode's mail: to support, its subject naming the dimension. */
6
6
  export declare function planLimitMailto(email: string, subject: string): string;
7
- interface PlanLimitNoticeBaseProps extends Omit<ComponentPropsWithoutRef<"div">, "children" | "onClick"> {
7
+ /** A `div`'s props, `ref` included since 0.35 (round 0.35 R4, the follow-up to API-2): they
8
+ * go on to the {@link AlertBanner}, so the ref is the notice's `<div>` — its `href` is the
9
+ * action button's, never the banner's, so the frame is never a link. */
10
+ interface PlanLimitNoticeBaseProps extends Omit<ComponentPropsWithRef<"div">, "children" | "onClick"> {
8
11
  /** The dimension as the refusal names it (`"budgets"`, `"seats"`) — `isPlanLimit(err)`'s
9
12
  * `dimension`. Carried as `data-dimension`. */
10
13
  dimension: string;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/billing/plan-limit-notice.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef } from \"react\";\n\nimport { useKitLocale } from \"../i18n/kit-labels\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\nimport { formatNumber } from \"../lib/format\";\nimport { AlertBanner } from \"../components/alert-banner\";\nimport type { AlertTone } from \"../components/alert-banner\";\nimport { ProgressBar } from \"../components/progress-bar\";\nimport { Button } from \"../components/button\";\nimport { useBillingLabels } from \"./billing-labels\";\nimport type { BillingLabels } from \"./billing-labels\";\n\n/** RFC 3986 percent-encoding, `!'()*` too — a mail client that splits on `'` is the one\n * that breaks \"Plan limit: Ada's plots\" (landing/access.ts keeps the same rule). */\nfunction encodeStrict(value: string): string {\n return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);\n}\n\n/** The `contact` mode's mail: to support, its subject naming the dimension. */\nexport function planLimitMailto(email: string, subject: string): string {\n const to = encodeStrict(email).replace(/%40/g, \"@\");\n return `mailto:${to}?subject=${encodeStrict(subject)}`;\n}\n\ninterface PlanLimitNoticeBaseProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\" | \"onClick\"> {\n /** The dimension as the refusal names it (`\"budgets\"`, `\"seats\"`) — `isPlanLimit(err)`'s\n * `dimension`. Carried as `data-dimension`. */\n dimension: string;\n /** The app's name for it, in the reader's language: \"Budgets\". Default: the key. */\n dimensionLabel?: string;\n /** How many there are. Left out (keksdose's legacy `plan_budget_limit` body has no\n * `used`), it is read as `limit`: the create was refused for being at it. */\n used?: number;\n /** The plan's limit for the dimension. Left out — a body without one — the notice says\n * its words and draws no meter. */\n limit?: number;\n /** The payer's plan code, as `isPlanLimit` reads it — carried as `data-plan`, so the\n * refusal can be spread in whole: `<PlanLimitNotice {...isPlanLimit(err)} …/>`. */\n plan?: string;\n /** How a figure is written — kastlan's storage limit is bytes (`formatFileSize`).\n * Default: a number in the kit's locale. */\n formatValue?: (value: number) => string;\n /** Over the provider's locale, for the default figures. */\n locale?: string;\n /** Default `warning`. */\n tone?: AlertTone;\n /** Prop > `<UiKitProvider labels={{ billing }}>` > English. */\n labels?: LabelOverride<BillingLabels>;\n}\n\nexport type PlanLimitNoticeProps = PlanLimitNoticeBaseProps &\n (\n | {\n /** Plans are bought: \"Choose a plan\" → the app's subscription page. */\n mode: \"upgrade\";\n /** The subscription page. */\n href: string;\n email?: never;\n }\n | {\n /** The operator grants plans by hand (keksdose's today): \"Ask for more\" → a mail. */\n mode: \"contact\";\n /** The support address: `support@` the app's domain. */\n email: string;\n href?: never;\n }\n );\n\n/**\n * A create refused at the plan's limit (docs/billing-harmonization.md §3.4): \"Plan limit\n * reached\", what to do, the dimension's meter (\"Budgets — 3 of 3\") and the app's way to\n * more — `upgrade`, a link to the subscription page, or `contact`, a mail to support.\n *\n * A limit gates CREATION only: a downgrade never deletes or hides what is over the new\n * limit (§3.4), so `used` may be past `limit`; the meter then fills and turns red. Feed it\n * the refusal: `const hit = isPlanLimit(err); hit && <PlanLimitNotice {...hit} …/>`. The\n * kit sends nothing — the mail opens the reader's own client.\n */\nexport function PlanLimitNotice(props: PlanLimitNoticeProps) {\n const {\n dimension,\n dimensionLabel,\n used: usedProp,\n limit,\n plan,\n formatValue,\n locale: localeProp,\n tone = \"warning\",\n labels: labelsProp,\n mode,\n href,\n email,\n className,\n ...rest\n } = props;\n const labels = useBillingLabels(labelsProp);\n const locale = useKitLocale(localeProp);\n const used = usedProp ?? limit ?? 0;\n const name = dimensionLabel ?? dimension;\n const figure = (value: number) => (formatValue ? formatValue(value) : formatNumber(value, { locale }));\n\n const action =\n mode === \"upgrade\" ? (\n <Button href={href} variant=\"secondary\" size=\"sm\">\n {labels.choosePlan}\n </Button>\n ) : (\n <Button href={planLimitMailto(email, labels.contactSubject(name))} variant=\"secondary\" size=\"sm\">\n {labels.askForMore}\n </Button>\n );\n\n return (\n <AlertBanner\n {...rest}\n tone={tone}\n action={action}\n data-plan-limit-mode={mode}\n data-dimension={dimension}\n data-plan={plan}\n className={className}\n >\n <span className=\"block font-medium\">{labels.limitReached}</span>\n <span className=\"block\">{mode === \"upgrade\" ? labels.limitUpgrade : labels.limitContact}</span>\n {limit !== undefined && (\n <ProgressBar\n as=\"span\"\n variant=\"meter\"\n size=\"slim\"\n value={used}\n max={limit}\n label={name}\n showValue\n // The bar is clamped at `max` and hands its formatter the clamped value; the\n // figures are the real ones, so \"5 of 3\" after a downgrade says what the bar\n // cannot draw.\n formatValue={() => labels.usage(figure(used), figure(limit))}\n tone={used > limit ? \"danger\" : \"warning\"}\n className=\"mt-2\"\n locale={locale}\n />\n )}\n </AlertBanner>\n );\n}\n"],"mappings":";AAuGM,cAUF,YAVE;AArGN,SAAS,oBAAoB;AAE7B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAE5B,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB,SAAS,wBAAwB;AAKjC,SAAS,aAAa,OAAuB;AAC3C,SAAO,mBAAmB,KAAK,EAAE,QAAQ,YAAY,CAAC,MAAM,IAAI,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAY,CAAC,EAAE;AAC9G;AAGO,SAAS,gBAAgB,OAAe,SAAyB;AACtE,QAAM,KAAK,aAAa,KAAK,EAAE,QAAQ,QAAQ,GAAG;AAClD,SAAO,UAAU,EAAE,YAAY,aAAa,OAAO,CAAC;AACtD;AAwDO,SAAS,gBAAgB,OAA6B;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,SAAS,iBAAiB,UAAU;AAC1C,QAAM,SAAS,aAAa,UAAU;AACtC,QAAM,OAAO,YAAY,SAAS;AAClC,QAAM,OAAO,kBAAkB;AAC/B,QAAM,SAAS,CAAC,UAAmB,cAAc,YAAY,KAAK,IAAI,aAAa,OAAO,EAAE,OAAO,CAAC;AAEpG,QAAM,SACJ,SAAS,YACP,oBAAC,UAAO,MAAY,SAAQ,aAAY,MAAK,MAC1C,iBAAO,YACV,IAEA,oBAAC,UAAO,MAAM,gBAAgB,OAAO,OAAO,eAAe,IAAI,CAAC,GAAG,SAAQ,aAAY,MAAK,MACzF,iBAAO,YACV;AAGJ,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,MACA,wBAAsB;AAAA,MACtB,kBAAgB;AAAA,MAChB,aAAW;AAAA,MACX;AAAA,MAEA;AAAA,4BAAC,UAAK,WAAU,qBAAqB,iBAAO,cAAa;AAAA,QACzD,oBAAC,UAAK,WAAU,SAAS,mBAAS,YAAY,OAAO,eAAe,OAAO,cAAa;AAAA,QACvF,UAAU,UACT;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,OAAO;AAAA,YACP,KAAK;AAAA,YACL,OAAO;AAAA,YACP,WAAS;AAAA,YAIT,aAAa,MAAM,OAAO,MAAM,OAAO,IAAI,GAAG,OAAO,KAAK,CAAC;AAAA,YAC3D,MAAM,OAAO,QAAQ,WAAW;AAAA,YAChC,WAAU;AAAA,YACV;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/billing/plan-limit-notice.tsx"],"sourcesContent":["import type { ComponentPropsWithRef } from \"react\";\n\nimport { useKitLocale } from \"../i18n/kit-labels\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\nimport { formatNumber } from \"../lib/format\";\nimport { AlertBanner } from \"../components/alert-banner\";\nimport type { AlertTone } from \"../components/alert-banner\";\nimport { ProgressBar } from \"../components/progress-bar\";\nimport { Button } from \"../components/button\";\nimport { useBillingLabels } from \"./billing-labels\";\nimport type { BillingLabels } from \"./billing-labels\";\n\n/** RFC 3986 percent-encoding, `!'()*` too — a mail client that splits on `'` is the one\n * that breaks \"Plan limit: Ada's plots\" (landing/access.ts keeps the same rule). */\nfunction encodeStrict(value: string): string {\n return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);\n}\n\n/** The `contact` mode's mail: to support, its subject naming the dimension. */\nexport function planLimitMailto(email: string, subject: string): string {\n const to = encodeStrict(email).replace(/%40/g, \"@\");\n return `mailto:${to}?subject=${encodeStrict(subject)}`;\n}\n\n/** A `div`'s props, `ref` included since 0.35 (round 0.35 R4, the follow-up to API-2): they\n * go on to the {@link AlertBanner}, so the ref is the notice's `<div>` — its `href` is the\n * action button's, never the banner's, so the frame is never a link. */\ninterface PlanLimitNoticeBaseProps extends Omit<ComponentPropsWithRef<\"div\">, \"children\" | \"onClick\"> {\n /** The dimension as the refusal names it (`\"budgets\"`, `\"seats\"`) — `isPlanLimit(err)`'s\n * `dimension`. Carried as `data-dimension`. */\n dimension: string;\n /** The app's name for it, in the reader's language: \"Budgets\". Default: the key. */\n dimensionLabel?: string;\n /** How many there are. Left out (keksdose's legacy `plan_budget_limit` body has no\n * `used`), it is read as `limit`: the create was refused for being at it. */\n used?: number;\n /** The plan's limit for the dimension. Left out — a body without one — the notice says\n * its words and draws no meter. */\n limit?: number;\n /** The payer's plan code, as `isPlanLimit` reads it — carried as `data-plan`, so the\n * refusal can be spread in whole: `<PlanLimitNotice {...isPlanLimit(err)} …/>`. */\n plan?: string;\n /** How a figure is written — kastlan's storage limit is bytes (`formatFileSize`).\n * Default: a number in the kit's locale. */\n formatValue?: (value: number) => string;\n /** Over the provider's locale, for the default figures. */\n locale?: string;\n /** Default `warning`. */\n tone?: AlertTone;\n /** Prop > `<UiKitProvider labels={{ billing }}>` > English. */\n labels?: LabelOverride<BillingLabels>;\n}\n\nexport type PlanLimitNoticeProps = PlanLimitNoticeBaseProps &\n (\n | {\n /** Plans are bought: \"Choose a plan\" → the app's subscription page. */\n mode: \"upgrade\";\n /** The subscription page. */\n href: string;\n email?: never;\n }\n | {\n /** The operator grants plans by hand (keksdose's today): \"Ask for more\" → a mail. */\n mode: \"contact\";\n /** The support address: `support@` the app's domain. */\n email: string;\n href?: never;\n }\n );\n\n/**\n * A create refused at the plan's limit (docs/billing-harmonization.md §3.4): \"Plan limit\n * reached\", what to do, the dimension's meter (\"Budgets — 3 of 3\") and the app's way to\n * more — `upgrade`, a link to the subscription page, or `contact`, a mail to support.\n *\n * A limit gates CREATION only: a downgrade never deletes or hides what is over the new\n * limit (§3.4), so `used` may be past `limit`; the meter then fills and turns red. Feed it\n * the refusal: `const hit = isPlanLimit(err); hit && <PlanLimitNotice {...hit} …/>`. The\n * kit sends nothing — the mail opens the reader's own client.\n */\nexport function PlanLimitNotice(props: PlanLimitNoticeProps) {\n const {\n dimension,\n dimensionLabel,\n used: usedProp,\n limit,\n plan,\n formatValue,\n locale: localeProp,\n tone = \"warning\",\n labels: labelsProp,\n mode,\n href,\n email,\n className,\n ...rest\n } = props;\n const labels = useBillingLabels(labelsProp);\n const locale = useKitLocale(localeProp);\n const used = usedProp ?? limit ?? 0;\n const name = dimensionLabel ?? dimension;\n const figure = (value: number) => (formatValue ? formatValue(value) : formatNumber(value, { locale }));\n\n const action =\n mode === \"upgrade\" ? (\n <Button href={href} variant=\"secondary\" size=\"sm\">\n {labels.choosePlan}\n </Button>\n ) : (\n <Button href={planLimitMailto(email, labels.contactSubject(name))} variant=\"secondary\" size=\"sm\">\n {labels.askForMore}\n </Button>\n );\n\n return (\n <AlertBanner\n {...rest}\n tone={tone}\n action={action}\n data-plan-limit-mode={mode}\n data-dimension={dimension}\n data-plan={plan}\n className={className}\n >\n <span className=\"block font-medium\">{labels.limitReached}</span>\n <span className=\"block\">{mode === \"upgrade\" ? labels.limitUpgrade : labels.limitContact}</span>\n {limit !== undefined && (\n <ProgressBar\n as=\"span\"\n variant=\"meter\"\n size=\"slim\"\n value={used}\n max={limit}\n label={name}\n showValue\n // The bar is clamped at `max` and hands its formatter the clamped value; the\n // figures are the real ones, so \"5 of 3\" after a downgrade says what the bar\n // cannot draw.\n formatValue={() => labels.usage(figure(used), figure(limit))}\n tone={used > limit ? \"danger\" : \"warning\"}\n className=\"mt-2\"\n locale={locale}\n />\n )}\n </AlertBanner>\n );\n}\n"],"mappings":";AA0GM,cAUF,YAVE;AAxGN,SAAS,oBAAoB;AAE7B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAE5B,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB,SAAS,wBAAwB;AAKjC,SAAS,aAAa,OAAuB;AAC3C,SAAO,mBAAmB,KAAK,EAAE,QAAQ,YAAY,CAAC,MAAM,IAAI,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAY,CAAC,EAAE;AAC9G;AAGO,SAAS,gBAAgB,OAAe,SAAyB;AACtE,QAAM,KAAK,aAAa,KAAK,EAAE,QAAQ,QAAQ,GAAG;AAClD,SAAO,UAAU,EAAE,YAAY,aAAa,OAAO,CAAC;AACtD;AA2DO,SAAS,gBAAgB,OAA6B;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,SAAS,iBAAiB,UAAU;AAC1C,QAAM,SAAS,aAAa,UAAU;AACtC,QAAM,OAAO,YAAY,SAAS;AAClC,QAAM,OAAO,kBAAkB;AAC/B,QAAM,SAAS,CAAC,UAAmB,cAAc,YAAY,KAAK,IAAI,aAAa,OAAO,EAAE,OAAO,CAAC;AAEpG,QAAM,SACJ,SAAS,YACP,oBAAC,UAAO,MAAY,SAAQ,aAAY,MAAK,MAC1C,iBAAO,YACV,IAEA,oBAAC,UAAO,MAAM,gBAAgB,OAAO,OAAO,eAAe,IAAI,CAAC,GAAG,SAAQ,aAAY,MAAK,MACzF,iBAAO,YACV;AAGJ,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,MACA,wBAAsB;AAAA,MACtB,kBAAgB;AAAA,MAChB,aAAW;AAAA,MACX;AAAA,MAEA;AAAA,4BAAC,UAAK,WAAU,qBAAqB,iBAAO,cAAa;AAAA,QACzD,oBAAC,UAAK,WAAU,SAAS,mBAAS,YAAY,OAAO,eAAe,OAAO,cAAa;AAAA,QACvF,UAAU,UACT;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,OAAO;AAAA,YACP,KAAK;AAAA,YACL,OAAO;AAAA,YACP,WAAS;AAAA,YAIT,aAAa,MAAM,OAAO,MAAM,OAAO,IAAI,GAAG,OAAO,KAAK,CAAC;AAAA,YAC3D,MAAM,OAAO,QAAQ,WAAW;AAAA,YAChC,WAAU;AAAA,YACV;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
package/dist/chart.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chart.ts"],"sourcesContent":["// `@eifi1/ui-kit/chart` — the chart shell and its colour system.\n//\n// A re-slicing of what the main barrel already exports, not a new API. It exists so a\n// consumer can reach the chart kit WITHOUT the barrel: `import(\"@eifi1/ui-kit/chart\")`\n// is a 31KB chunk, where the same lazy import through the barrel pulls 221KB, because\n// a dynamic import of the barrel cannot be tree-shaken down to one of its members.\n//\n// It is about chunk size, not about the peer: `recharts` is a REQUIRED peer (since 0.5.0),\n// because the main barrel re-exports everything here too, so `import { Button } from\n// \"@eifi1/ui-kit\"` reaches recharts as well (packaging-contract.test.ts asserts it).\nexport * from \"./components/chart\";\nexport * from \"./theme/chart-palette\";\n\n// The tile chart (treemap) the apps share — moved here from keksdose so every consumer\n// derives it from the package rather than from a copy.\nexport * from \"./components/treemap\";\n\n// lenkbank's zoomable series chart, its synced x-zoom, the toggle legend and the\n// mirrored-pair axis geometry — moved here so the apps derive them from the package.\nexport * from \"./components/series-chart\";\n// 0.32.1 (keksdose's 0.32 report): the height every chart takes, for an app's wrappers.\nexport type { ChartHeight } from \"./components/chart-height\";\nexport * from \"./components/chart-zoom\";\n// The zoom's own module since 0.34: SharedXZoom and the drag layer (recharts) live here,\n// ./chart-zoom is their public face. Named, so the arithmetic it also holds stays the\n// kit's (refactor audit 2026-10, API-6b) — the same binding the line above re-exports.\nexport { SharedXZoom } from \"./components/chart-zoom-core\";\nexport * from \"./components/toggle-legend\";\nexport * from \"./components/facing-pair\";\nexport * from \"./components/series-chart-labels\";\n\n// The part-to-whole chart (donut / pie) — moved here from kastlan's dashboard and reports.\nexport * from \"./components/pie-chart\";\nexport * from \"./components/pie-chart-labels\";\n"],"mappings":";AAUA,cAAc;AACd,cAAc;AAId,cAAc;AAId,cAAc;AAGd,cAAc;AAId,SAAS,mBAAmB;AAC5B,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/chart.ts"],"sourcesContent":["// `@eifi1/ui-kit/chart` — the chart shell and its colour system.\n//\n// A re-slicing of what the main barrel already exports, not a new API. It exists so a\n// consumer can reach the chart kit WITHOUT the barrel: `import(\"@eifi1/ui-kit/chart\")`\n// is a 31KB chunk, where the same lazy import through the barrel pulls 221KB, because\n// a dynamic import of the barrel cannot be tree-shaken down to one of its members.\n//\n// It is about chunk size, not about the peer: `recharts` is a REQUIRED peer (since 0.5.0),\n// because the main barrel re-exports everything here too, so `import { Button } from\n// \"@eifi1/ui-kit\"` reaches recharts as well (packaging-contract.test.ts asserts it).\nexport * from \"./components/chart\";\nexport * from \"./theme/chart-palette\";\n\n// The tile chart (treemap) the apps share — moved here from keksdose so every consumer\n// derives it from the package rather than from a copy.\nexport * from \"./components/treemap\";\n\n// lenkbank's zoomable series chart, its synced x-zoom, the toggle legend and the\n// mirrored-pair axis geometry — moved here so the apps derive them from the package.\nexport * from \"./components/series-chart\";\n// 0.32.1 (keksdose's 0.32 report): the height every chart takes, for an app's wrappers.\nexport type { ChartHeight } from \"./components/chart-height\";\n// SharedXZoom and the zoom's types: the public face of ./chart-zoom-core, whose arithmetic\n// stays the kit's (refactor audit 2026-10, API-6b; off the surface in 0.35).\nexport * from \"./components/chart-zoom\";\n// The same binding, named from the module that holds it and the drag layer (recharts): the\n// packaging contract reads this entry's own imports to know which modules may import\n// recharts, so chart-zoom-core has to be one of them (MOD-6).\nexport { SharedXZoom } from \"./components/chart-zoom-core\";\nexport * from \"./components/toggle-legend\";\nexport * from \"./components/facing-pair\";\nexport * from \"./components/series-chart-labels\";\n\n// The part-to-whole chart (donut / pie) — moved here from kastlan's dashboard and reports.\nexport * from \"./components/pie-chart\";\nexport * from \"./components/pie-chart-labels\";\n"],"mappings":";AAUA,cAAc;AACd,cAAc;AAId,cAAc;AAId,cAAc;AAKd,cAAc;AAId,SAAS,mBAAmB;AAC5B,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;","names":[]}