@eifi1/ui-kit 0.31.1 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. package/README.md +51 -28
  2. package/dist/account/delete-account-setting.d.ts +8 -3
  3. package/dist/admin/admin-action-confirm.d.ts +8 -3
  4. package/dist/admin/admin-action-log.d.ts +1 -1
  5. package/dist/admin/admin-action-log.js +4 -2
  6. package/dist/admin/admin-action-log.js.map +1 -1
  7. package/dist/admin/invitations-panel.d.ts +8 -3
  8. package/dist/admin/invitations-panel.js +29 -26
  9. package/dist/admin/invitations-panel.js.map +1 -1
  10. package/dist/admin/reviewer-scope-editor.d.ts +8 -3
  11. package/dist/admin/role-select.d.ts +10 -5
  12. package/dist/admin/transfer-ownership-dialog.d.ts +8 -3
  13. package/dist/admin/user-roster.d.ts +10 -5
  14. package/dist/admin/user-roster.js +8 -47
  15. package/dist/admin/user-roster.js.map +1 -1
  16. package/dist/auth/auth-errors.d.ts +43 -8
  17. package/dist/auth/auth-errors.js +24 -1
  18. package/dist/auth/auth-errors.js.map +1 -1
  19. package/dist/auth/register-form.d.ts +8 -3
  20. package/dist/billing/billing-banner.d.ts +184 -0
  21. package/dist/billing/billing-banner.js +98 -0
  22. package/dist/billing/billing-banner.js.map +1 -0
  23. package/dist/billing/billing-labels.d.ts +100 -0
  24. package/dist/billing/billing-labels.js +76 -0
  25. package/dist/billing/billing-labels.js.map +1 -0
  26. package/dist/billing/billing-lock.d.ts +158 -0
  27. package/dist/billing/billing-lock.js +17 -0
  28. package/dist/billing/billing-lock.js.map +1 -0
  29. package/dist/billing/billing-standing.d.ts +149 -0
  30. package/dist/billing/billing-standing.js +28 -0
  31. package/dist/billing/billing-standing.js.map +1 -0
  32. package/dist/billing/plan-card.d.ts +248 -0
  33. package/dist/billing/plan-card.js +248 -0
  34. package/dist/billing/plan-card.js.map +1 -0
  35. package/dist/billing/plan-limit-notice.d.ts +156 -0
  36. package/dist/billing/plan-limit-notice.js +76 -0
  37. package/dist/billing/plan-limit-notice.js.map +1 -0
  38. package/dist/billing/plan-limit.d.ts +34 -0
  39. package/dist/billing/plan-limit.js +20 -0
  40. package/dist/billing/plan-limit.js.map +1 -0
  41. package/dist/billing/plan-price.d.ts +61 -0
  42. package/dist/billing/plan-price.js +45 -0
  43. package/dist/billing/plan-price.js.map +1 -0
  44. package/dist/billing/subscription-actions.d.ts +133 -0
  45. package/dist/billing/subscription-actions.js +28 -0
  46. package/dist/billing/subscription-actions.js.map +1 -0
  47. package/dist/billing/subscription-status-chip.d.ts +149 -0
  48. package/dist/billing/subscription-status-chip.js +48 -0
  49. package/dist/billing/subscription-status-chip.js.map +1 -0
  50. package/dist/chart.d.ts +9 -3
  51. package/dist/chart.js.map +1 -1
  52. package/dist/components/account-chips.d.ts +16 -4
  53. package/dist/components/account-chips.js +21 -3
  54. package/dist/components/account-chips.js.map +1 -1
  55. package/dist/components/alert-banner.d.ts +6 -1
  56. package/dist/components/alert-banner.js +5 -4
  57. package/dist/components/alert-banner.js.map +1 -1
  58. package/dist/components/amount-input.d.ts +8 -3
  59. package/dist/components/amount-input.js +5 -5
  60. package/dist/components/amount-input.js.map +1 -1
  61. package/dist/components/appearance-labels.d.ts +38 -0
  62. package/dist/components/appearance-labels.js +19 -0
  63. package/dist/components/appearance-labels.js.map +1 -0
  64. package/dist/components/autocomplete.js +2 -2
  65. package/dist/components/autocomplete.js.map +1 -1
  66. package/dist/components/breadcrumbs.js +3 -2
  67. package/dist/components/breadcrumbs.js.map +1 -1
  68. package/dist/components/bulk-action-bar.d.ts +2 -2
  69. package/dist/components/bulk-action-bar.js +7 -12
  70. package/dist/components/bulk-action-bar.js.map +1 -1
  71. package/dist/components/button-group.d.ts +8 -3
  72. package/dist/components/button-group.js +7 -1
  73. package/dist/components/button-group.js.map +1 -1
  74. package/dist/components/calculator.d.ts +8 -3
  75. package/dist/components/calculator.js +4 -3
  76. package/dist/components/calculator.js.map +1 -1
  77. package/dist/components/calendar-heatmap.js +5 -5
  78. package/dist/components/calendar-heatmap.js.map +1 -1
  79. package/dist/components/chart-height.d.ts +23 -0
  80. package/dist/components/chart-height.js +15 -0
  81. package/dist/components/chart-height.js.map +1 -0
  82. package/dist/components/chart-zoom.js +6 -1
  83. package/dist/components/chart-zoom.js.map +1 -1
  84. package/dist/components/checkbox-group.js +2 -2
  85. package/dist/components/checkbox-group.js.map +1 -1
  86. package/dist/components/checkbox.d.ts +10 -0
  87. package/dist/components/checkbox.js +25 -10
  88. package/dist/components/checkbox.js.map +1 -1
  89. package/dist/components/chip.d.ts +19 -3
  90. package/dist/components/chip.js +54 -23
  91. package/dist/components/chip.js.map +1 -1
  92. package/dist/components/choice-card.d.ts +1 -1
  93. package/dist/components/choice-card.js +9 -8
  94. package/dist/components/choice-card.js.map +1 -1
  95. package/dist/components/column-mapper.js +1 -1
  96. package/dist/components/column-mapper.js.map +1 -1
  97. package/dist/components/combobox-core.js +8 -7
  98. package/dist/components/combobox-core.js.map +1 -1
  99. package/dist/components/combobox.js +8 -8
  100. package/dist/components/combobox.js.map +1 -1
  101. package/dist/components/confirm-dialog.d.ts +8 -3
  102. package/dist/components/copy-button.d.ts +10 -5
  103. package/dist/components/country-select.js +1 -1
  104. package/dist/components/country-select.js.map +1 -1
  105. package/dist/components/currency-select.js +3 -3
  106. package/dist/components/currency-select.js.map +1 -1
  107. package/dist/components/danger-confirm.d.ts +8 -3
  108. package/dist/components/data-table-cells.d.ts +1 -1
  109. package/dist/components/data-table-filter-popover.d.ts +1 -1
  110. package/dist/components/data-table-filter-popover.js +4 -1
  111. package/dist/components/data-table-filter-popover.js.map +1 -1
  112. package/dist/components/data-table-filters.d.ts +1 -1
  113. package/dist/components/data-table-labels.d.ts +1 -1
  114. package/dist/components/data-table-pagination.d.ts +3 -2
  115. package/dist/components/data-table-pagination.js +15 -6
  116. package/dist/components/data-table-pagination.js.map +1 -1
  117. package/dist/components/data-table.d.ts +1 -1
  118. package/dist/components/data-table.js +123 -52
  119. package/dist/components/data-table.js.map +1 -1
  120. package/dist/components/date-picker.d.ts +1 -1
  121. package/dist/components/date-picker.js +18 -6
  122. package/dist/components/date-picker.js.map +1 -1
  123. package/dist/components/description-list.js +2 -2
  124. package/dist/components/description-list.js.map +1 -1
  125. package/dist/components/dialog-frame.js +2 -1
  126. package/dist/components/dialog-frame.js.map +1 -1
  127. package/dist/components/disclosure.js +3 -2
  128. package/dist/components/disclosure.js.map +1 -1
  129. package/dist/components/dropdown.d.ts +1 -1
  130. package/dist/components/dropdown.js +7 -1
  131. package/dist/components/dropdown.js.map +1 -1
  132. package/dist/components/facing-pair.d.ts +19 -6
  133. package/dist/components/facing-pair.js +3 -2
  134. package/dist/components/facing-pair.js.map +1 -1
  135. package/dist/components/field-parts.d.ts +102 -6
  136. package/dist/components/field-parts.js +81 -6
  137. package/dist/components/field-parts.js.map +1 -1
  138. package/dist/components/field-sync.d.ts +4 -1
  139. package/dist/components/field-sync.js +12 -2
  140. package/dist/components/field-sync.js.map +1 -1
  141. package/dist/components/field.js +2 -2
  142. package/dist/components/field.js.map +1 -1
  143. package/dist/components/file-button.d.ts +8 -3
  144. package/dist/components/file-dropzone.d.ts +8 -3
  145. package/dist/components/floating-panel.js +7 -4
  146. package/dist/components/floating-panel.js.map +1 -1
  147. package/dist/components/focus-ring.d.ts +12 -0
  148. package/dist/components/focus-ring.js +8 -0
  149. package/dist/components/focus-ring.js.map +1 -0
  150. package/dist/components/form-actions.d.ts +8 -3
  151. package/dist/components/form-actions.js +33 -19
  152. package/dist/components/form-actions.js.map +1 -1
  153. package/dist/components/full-bleed-dialog.d.ts +11 -1
  154. package/dist/components/full-bleed-dialog.js +3 -1
  155. package/dist/components/full-bleed-dialog.js.map +1 -1
  156. package/dist/components/iban-input.d.ts +8 -3
  157. package/dist/components/image-grid.js +1 -1
  158. package/dist/components/image-grid.js.map +1 -1
  159. package/dist/components/inline-edit-field.js +10 -4
  160. package/dist/components/inline-edit-field.js.map +1 -1
  161. package/dist/components/language-select.d.ts +8 -3
  162. package/dist/components/legal-page.d.ts +26 -5
  163. package/dist/components/legal-page.js +3 -1
  164. package/dist/components/legal-page.js.map +1 -1
  165. package/dist/components/legal.d.ts +8 -3
  166. package/dist/components/legal.js +2 -1
  167. package/dist/components/legal.js.map +1 -1
  168. package/dist/components/lightbox.js +24 -2
  169. package/dist/components/lightbox.js.map +1 -1
  170. package/dist/components/line-items.js +2 -1
  171. package/dist/components/line-items.js.map +1 -1
  172. package/dist/components/list.d.ts +5 -0
  173. package/dist/components/list.js +13 -9
  174. package/dist/components/list.js.map +1 -1
  175. package/dist/components/measured-grid.d.ts +3 -1
  176. package/dist/components/measured-grid.js +38 -20
  177. package/dist/components/measured-grid.js.map +1 -1
  178. package/dist/components/menu-item.js +2 -1
  179. package/dist/components/menu-item.js.map +1 -1
  180. package/dist/components/mini-calendar.js +8 -4
  181. package/dist/components/mini-calendar.js.map +1 -1
  182. package/dist/components/money-field.d.ts +8 -3
  183. package/dist/components/month-picker.js +50 -39
  184. package/dist/components/month-picker.js.map +1 -1
  185. package/dist/components/nav-pills.js +1 -1
  186. package/dist/components/nav-pills.js.map +1 -1
  187. package/dist/components/number-field.d.ts +8 -3
  188. package/dist/components/number-input.d.ts +11 -4
  189. package/dist/components/number-input.js +8 -6
  190. package/dist/components/number-input.js.map +1 -1
  191. package/dist/components/numpad-sheet.d.ts +8 -3
  192. package/dist/components/numpad-sheet.js +2 -1
  193. package/dist/components/numpad-sheet.js.map +1 -1
  194. package/dist/components/one-time-code-input.js +2 -2
  195. package/dist/components/one-time-code-input.js.map +1 -1
  196. package/dist/components/page-contents.js +2 -2
  197. package/dist/components/page-contents.js.map +1 -1
  198. package/dist/components/phone-input.d.ts +8 -3
  199. package/dist/components/phone-input.js +4 -4
  200. package/dist/components/phone-input.js.map +1 -1
  201. package/dist/components/pie-chart.d.ts +8 -2
  202. package/dist/components/pie-chart.js +11 -7
  203. package/dist/components/pie-chart.js.map +1 -1
  204. package/dist/components/popover.d.ts +9 -1
  205. package/dist/components/popover.js +8 -4
  206. package/dist/components/popover.js.map +1 -1
  207. package/dist/components/row-actions.d.ts +100 -0
  208. package/dist/components/row-actions.js +231 -0
  209. package/dist/components/row-actions.js.map +1 -0
  210. package/dist/components/scroll-area.js +1 -1
  211. package/dist/components/scroll-area.js.map +1 -1
  212. package/dist/components/search-field.js +3 -2
  213. package/dist/components/search-field.js.map +1 -1
  214. package/dist/components/series-chart-budget.d.ts +30 -7
  215. package/dist/components/series-chart-budget.js +12 -4
  216. package/dist/components/series-chart-budget.js.map +1 -1
  217. package/dist/components/series-chart-ticks.d.ts +7 -1
  218. package/dist/components/series-chart-ticks.js +6 -0
  219. package/dist/components/series-chart-ticks.js.map +1 -1
  220. package/dist/components/series-chart.d.ts +58 -28
  221. package/dist/components/series-chart.js +42 -32
  222. package/dist/components/series-chart.js.map +1 -1
  223. package/dist/components/settings-fields.d.ts +57 -8
  224. package/dist/components/settings-fields.js +39 -1
  225. package/dist/components/settings-fields.js.map +1 -1
  226. package/dist/components/share-card.d.ts +11 -6
  227. package/dist/components/share-card.js +8 -2
  228. package/dist/components/share-card.js.map +1 -1
  229. package/dist/components/sign-chip.d.ts +4 -0
  230. package/dist/components/sign-chip.js +17 -4
  231. package/dist/components/sign-chip.js.map +1 -1
  232. package/dist/components/signature-pad.d.ts +3 -1
  233. package/dist/components/signature-pad.js +8 -5
  234. package/dist/components/signature-pad.js.map +1 -1
  235. package/dist/components/slider.js +7 -6
  236. package/dist/components/slider.js.map +1 -1
  237. package/dist/components/sparkline.d.ts +5 -1
  238. package/dist/components/sparkline.js +4 -2
  239. package/dist/components/sparkline.js.map +1 -1
  240. package/dist/components/stat-tile.d.ts +17 -1
  241. package/dist/components/stat-tile.js +48 -20
  242. package/dist/components/stat-tile.js.map +1 -1
  243. package/dist/components/status-dot.d.ts +4 -0
  244. package/dist/components/status-dot.js +9 -2
  245. package/dist/components/status-dot.js.map +1 -1
  246. package/dist/components/swipeable-row.js +10 -2
  247. package/dist/components/swipeable-row.js.map +1 -1
  248. package/dist/components/switch.d.ts +21 -7
  249. package/dist/components/switch.js +24 -11
  250. package/dist/components/switch.js.map +1 -1
  251. package/dist/components/table.js +2 -2
  252. package/dist/components/table.js.map +1 -1
  253. package/dist/components/text-link.d.ts +8 -3
  254. package/dist/components/text-link.js +1 -1
  255. package/dist/components/text-link.js.map +1 -1
  256. package/dist/components/text.d.ts +7 -2
  257. package/dist/components/text.js +5 -5
  258. package/dist/components/text.js.map +1 -1
  259. package/dist/components/tile-radio.js +2 -1
  260. package/dist/components/tile-radio.js.map +1 -1
  261. package/dist/components/time-input.d.ts +8 -3
  262. package/dist/components/toast.d.ts +18 -2
  263. package/dist/components/toast.js +8 -5
  264. package/dist/components/toast.js.map +1 -1
  265. package/dist/components/toggle-group.d.ts +25 -3
  266. package/dist/components/toggle-group.js +40 -11
  267. package/dist/components/toggle-group.js.map +1 -1
  268. package/dist/components/toggle-legend.d.ts +10 -1
  269. package/dist/components/toggle-legend.js +21 -7
  270. package/dist/components/toggle-legend.js.map +1 -1
  271. package/dist/components/translation-review-editor.js +1 -1
  272. package/dist/components/translation-review-editor.js.map +1 -1
  273. package/dist/components/translation-review-parts.d.ts +4 -0
  274. package/dist/components/translation-review.d.ts +4 -0
  275. package/dist/components/translation-review.js +3 -3
  276. package/dist/components/translation-review.js.map +1 -1
  277. package/dist/components/tree-view.js +3 -2
  278. package/dist/components/tree-view.js.map +1 -1
  279. package/dist/components/treemap.d.ts +5 -2
  280. package/dist/components/treemap.js +33 -16
  281. package/dist/components/treemap.js.map +1 -1
  282. package/dist/components/ui.d.ts +8 -3
  283. package/dist/components/ui.js +207 -119
  284. package/dist/components/ui.js.map +1 -1
  285. package/dist/components/use-table-state.d.ts +1 -1
  286. package/dist/components/user-avatar.d.ts +5 -1
  287. package/dist/components/user-avatar.js +1 -1
  288. package/dist/components/user-avatar.js.map +1 -1
  289. package/dist/components/wizard-stepper.js +20 -14
  290. package/dist/components/wizard-stepper.js.map +1 -1
  291. package/dist/{data-table-labels-DUELeXpa.d.ts → data-table-labels-kpAAVi6g.d.ts} +26 -2
  292. package/dist/data-table.d.ts +1 -1
  293. package/dist/{delete-account-setting-CpIhzxxZ.d.ts → delete-account-setting-FLyJf-kZ.d.ts} +642 -60
  294. package/dist/demo/demo-banner.js +1 -0
  295. package/dist/demo/demo-banner.js.map +1 -1
  296. package/dist/feedback/feedback-attachment.d.ts +8 -3
  297. package/dist/feedback/feedback-context.d.ts +8 -3
  298. package/dist/feedback/feedback-crash.d.ts +8 -3
  299. package/dist/feedback/feedback-dialog.d.ts +8 -3
  300. package/dist/feedback/feedback-dialog.js +3 -3
  301. package/dist/feedback/feedback-dialog.js.map +1 -1
  302. package/dist/feedback/feedback-inbox.d.ts +8 -3
  303. package/dist/feedback/feedback-inbox.js +2 -2
  304. package/dist/feedback/feedback-inbox.js.map +1 -1
  305. package/dist/feedback/feedback-labels.d.ts +8 -3
  306. package/dist/feedback/feedback-menu.d.ts +9 -4
  307. package/dist/feedback/feedback-record.d.ts +8 -3
  308. package/dist/feedback/feedback-row-detail.d.ts +8 -3
  309. package/dist/feedback/feedback-status-undo.d.ts +8 -3
  310. package/dist/feedback/feedback-submit.d.ts +8 -3
  311. package/dist/feedback/feedback-swipe.d.ts +8 -3
  312. package/dist/feedback/feedback-table.d.ts +8 -3
  313. package/dist/feedback/feedback-thread.d.ts +8 -3
  314. package/dist/feedback/feedback-thread.js +3 -3
  315. package/dist/feedback/feedback-thread.js.map +1 -1
  316. package/dist/feedback.d.ts +8 -3
  317. package/dist/hooks/use-anchored-panel.d.ts +32 -3
  318. package/dist/hooks/use-anchored-panel.js +21 -3
  319. package/dist/hooks/use-anchored-panel.js.map +1 -1
  320. package/dist/hooks/use-breakpoint.d.ts +88 -0
  321. package/dist/hooks/use-breakpoint.js +50 -0
  322. package/dist/hooks/use-breakpoint.js.map +1 -0
  323. package/dist/hooks/use-file-drop.d.ts +8 -3
  324. package/dist/hooks/use-large-text.d.ts +29 -0
  325. package/dist/hooks/use-large-text.js +20 -0
  326. package/dist/hooks/use-large-text.js.map +1 -0
  327. package/dist/hooks/use-windowed-rows.d.ts +52 -8
  328. package/dist/hooks/use-windowed-rows.js +94 -5
  329. package/dist/hooks/use-windowed-rows.js.map +1 -1
  330. package/dist/i18n/defaults.d.ts +8 -3
  331. package/dist/i18n/defaults.js +8 -0
  332. package/dist/i18n/defaults.js.map +1 -1
  333. package/dist/i18n/german.d.ts +8 -3
  334. package/dist/i18n/german.js +94 -3
  335. package/dist/i18n/german.js.map +1 -1
  336. package/dist/i18n/kit-labels.d.ts +8 -3
  337. package/dist/i18n/kit-labels.js.map +1 -1
  338. package/dist/i18n/languages.d.ts +10 -5
  339. package/dist/i18n/locales/de-CH.d.ts +8 -3
  340. package/dist/i18n/locales/en.d.ts +8 -3
  341. package/dist/i18n/locales/es.d.ts +8 -3
  342. package/dist/i18n/locales/es.js +89 -3
  343. package/dist/i18n/locales/es.js.map +1 -1
  344. package/dist/i18n/locales/fr.d.ts +8 -3
  345. package/dist/i18n/locales/fr.js +91 -3
  346. package/dist/i18n/locales/fr.js.map +1 -1
  347. package/dist/i18n/locales/hu.d.ts +8 -3
  348. package/dist/i18n/locales/hu.js +91 -3
  349. package/dist/i18n/locales/hu.js.map +1 -1
  350. package/dist/i18n/locales/it.d.ts +8 -3
  351. package/dist/i18n/locales/it.js +92 -3
  352. package/dist/i18n/locales/it.js.map +1 -1
  353. package/dist/i18n/locales/zh.d.ts +8 -3
  354. package/dist/i18n/locales/zh.js +89 -3
  355. package/dist/i18n/locales/zh.js.map +1 -1
  356. package/dist/i18n/review.d.ts +8 -3
  357. package/dist/i18n/review.js +15 -1
  358. package/dist/i18n/review.js.map +1 -1
  359. package/dist/index.d.ts +27 -11
  360. package/dist/index.js +77 -4
  361. package/dist/index.js.map +1 -1
  362. package/dist/landing/landing-actions.d.ts +8 -3
  363. package/dist/landing/landing-sections.d.ts +8 -3
  364. package/dist/landing/landing-sections.js +7 -3
  365. package/dist/landing/landing-sections.js.map +1 -1
  366. package/dist/landing/public-header.d.ts +9 -4
  367. package/dist/landing/public-header.js +3 -3
  368. package/dist/landing/public-header.js.map +1 -1
  369. package/dist/landing/routing.d.ts +8 -3
  370. package/dist/lib/cn.js +3 -2
  371. package/dist/lib/cn.js.map +1 -1
  372. package/dist/rhf/fields.d.ts +8 -3
  373. package/dist/rhf/fields.js +1 -1
  374. package/dist/rhf/fields.js.map +1 -1
  375. package/dist/rhf/form.d.ts +8 -3
  376. package/dist/rhf/form.js +2 -2
  377. package/dist/rhf/form.js.map +1 -1
  378. package/dist/rhf.d.ts +8 -3
  379. package/dist/search/command-palette.d.ts +1 -1
  380. package/dist/search/command-palette.js +9 -8
  381. package/dist/search/command-palette.js.map +1 -1
  382. package/dist/settings/settings-layout.js +2 -1
  383. package/dist/settings/settings-layout.js.map +1 -1
  384. package/dist/settings/settings-section.d.ts +8 -3
  385. package/dist/settings/use-account-appearance.d.ts +92 -0
  386. package/dist/settings/use-account-appearance.js +63 -0
  387. package/dist/settings/use-account-appearance.js.map +1 -0
  388. package/dist/settings/use-settings-route.d.ts +1 -1
  389. package/dist/settings/use-settings-route.js +2 -3
  390. package/dist/settings/use-settings-route.js.map +1 -1
  391. package/dist/shell/app-shell.d.ts +12 -171
  392. package/dist/shell/app-shell.js +144 -28
  393. package/dist/shell/app-shell.js.map +1 -1
  394. package/dist/shell/auth-layout.js +1 -1
  395. package/dist/shell/auth-layout.js.map +1 -1
  396. package/dist/shell/option-switcher-menu.js +1 -1
  397. package/dist/shell/option-switcher-menu.js.map +1 -1
  398. package/dist/shell/top-bar-brand.d.ts +8 -3
  399. package/dist/shell/top-bar-brand.js +3 -1
  400. package/dist/shell/top-bar-brand.js.map +1 -1
  401. package/dist/shell/topbar-action-menu.d.ts +4 -0
  402. package/dist/shell/topbar-action-menu.js +3 -3
  403. package/dist/shell/topbar-action-menu.js.map +1 -1
  404. package/dist/shell/topbar-controls.js +4 -4
  405. package/dist/shell/topbar-controls.js.map +1 -1
  406. package/dist/shell.d.ts +9 -5
  407. package/dist/theme/contrast-tokens.d.ts +41 -0
  408. package/dist/theme/contrast-tokens.js +59 -0
  409. package/dist/theme/contrast-tokens.js.map +1 -0
  410. package/dist/theme/contrast.d.ts +110 -0
  411. package/dist/theme/contrast.js +128 -0
  412. package/dist/theme/contrast.js.map +1 -0
  413. package/dist/theme/palette-presets.d.ts +12 -1
  414. package/dist/theme/palette-presets.js +9 -4
  415. package/dist/theme/palette-presets.js.map +1 -1
  416. package/dist/theme/palette-store.js.map +1 -1
  417. package/dist/theme/text-size.d.ts +173 -0
  418. package/dist/theme/text-size.js +121 -0
  419. package/dist/theme/text-size.js.map +1 -0
  420. package/dist/wizard/stepper-nav.d.ts +8 -3
  421. package/dist/wizard/wizard-summary.js +1 -1
  422. package/dist/wizard/wizard-summary.js.map +1 -1
  423. package/dist/wizard.d.ts +8 -3
  424. package/package.json +1 -1
  425. package/src/admin/admin-action-log.tsx +6 -1
  426. package/src/admin/invitations-panel.tsx +36 -29
  427. package/src/admin/user-roster.tsx +17 -72
  428. package/src/auth/auth-errors.ts +68 -7
  429. package/src/billing/billing-banner.tsx +205 -0
  430. package/src/billing/billing-labels.ts +240 -0
  431. package/src/billing/billing-lock.ts +75 -0
  432. package/src/billing/billing-standing.ts +72 -0
  433. package/src/billing/plan-card.tsx +458 -0
  434. package/src/billing/plan-limit-notice.tsx +145 -0
  435. package/src/billing/plan-limit.ts +53 -0
  436. package/src/billing/plan-price.ts +101 -0
  437. package/src/billing/subscription-actions.tsx +76 -0
  438. package/src/billing/subscription-status-chip.tsx +95 -0
  439. package/src/chart.ts +2 -0
  440. package/src/components/account-chips.tsx +36 -10
  441. package/src/components/alert-banner.tsx +16 -7
  442. package/src/components/amount-input.tsx +5 -5
  443. package/src/components/appearance-labels.ts +47 -0
  444. package/src/components/autocomplete.tsx +2 -2
  445. package/src/components/breadcrumbs.tsx +3 -3
  446. package/src/components/bulk-action-bar.tsx +11 -14
  447. package/src/components/button-group.tsx +21 -0
  448. package/src/components/calculator.tsx +4 -3
  449. package/src/components/calendar-heatmap.tsx +5 -5
  450. package/src/components/chart-height.ts +30 -0
  451. package/src/components/chart-zoom.tsx +6 -1
  452. package/src/components/checkbox-group.tsx +2 -2
  453. package/src/components/checkbox.tsx +62 -20
  454. package/src/components/chip.tsx +139 -30
  455. package/src/components/choice-card.tsx +16 -11
  456. package/src/components/column-mapper.tsx +1 -1
  457. package/src/components/combobox-core.tsx +8 -7
  458. package/src/components/combobox.tsx +8 -8
  459. package/src/components/country-select.tsx +1 -1
  460. package/src/components/currency-select.tsx +3 -3
  461. package/src/components/data-table-filter-popover.tsx +7 -1
  462. package/src/components/data-table-pagination.tsx +60 -31
  463. package/src/components/data-table.tsx +164 -43
  464. package/src/components/date-picker.tsx +44 -10
  465. package/src/components/description-list.tsx +2 -2
  466. package/src/components/dialog-frame.tsx +2 -1
  467. package/src/components/disclosure.tsx +3 -2
  468. package/src/components/dropdown.tsx +10 -2
  469. package/src/components/facing-pair.ts +12 -5
  470. package/src/components/field-parts.tsx +190 -7
  471. package/src/components/field-sync.tsx +17 -3
  472. package/src/components/field.tsx +2 -2
  473. package/src/components/floating-panel.tsx +7 -4
  474. package/src/components/focus-ring.ts +12 -0
  475. package/src/components/form-actions.tsx +55 -18
  476. package/src/components/full-bleed-dialog.tsx +18 -4
  477. package/src/components/image-grid.tsx +1 -1
  478. package/src/components/inline-edit-field.tsx +26 -4
  479. package/src/components/legal-page.tsx +28 -2
  480. package/src/components/legal.tsx +19 -1
  481. package/src/components/lightbox.tsx +24 -2
  482. package/src/components/line-items.tsx +7 -1
  483. package/src/components/list.tsx +36 -10
  484. package/src/components/measured-grid.tsx +49 -24
  485. package/src/components/menu-item.tsx +2 -2
  486. package/src/components/mini-calendar.tsx +8 -4
  487. package/src/components/month-picker.tsx +15 -6
  488. package/src/components/nav-pills.tsx +1 -1
  489. package/src/components/number-input.tsx +14 -7
  490. package/src/components/numpad-sheet.tsx +2 -2
  491. package/src/components/one-time-code-input.tsx +2 -2
  492. package/src/components/page-contents.tsx +2 -2
  493. package/src/components/phone-input.tsx +9 -4
  494. package/src/components/pie-chart.tsx +19 -9
  495. package/src/components/popover.tsx +22 -5
  496. package/src/components/row-actions.tsx +450 -0
  497. package/src/components/scroll-area.tsx +1 -1
  498. package/src/components/search-field.tsx +4 -2
  499. package/src/components/series-chart-budget.ts +40 -8
  500. package/src/components/series-chart-ticks.ts +10 -0
  501. package/src/components/series-chart.tsx +123 -72
  502. package/src/components/settings-fields.tsx +89 -5
  503. package/src/components/share-card.tsx +31 -2
  504. package/src/components/sign-chip.tsx +28 -4
  505. package/src/components/signature-pad.tsx +13 -7
  506. package/src/components/slider.tsx +22 -9
  507. package/src/components/sparkline.tsx +11 -3
  508. package/src/components/stat-tile.tsx +70 -14
  509. package/src/components/status-dot.tsx +25 -2
  510. package/src/components/swipeable-row.tsx +10 -2
  511. package/src/components/switch.tsx +57 -23
  512. package/src/components/table.tsx +2 -2
  513. package/src/components/text-link.tsx +1 -1
  514. package/src/components/text.tsx +11 -6
  515. package/src/components/tile-radio.tsx +4 -1
  516. package/src/components/toast.tsx +27 -7
  517. package/src/components/toggle-group.tsx +115 -14
  518. package/src/components/toggle-legend.tsx +53 -8
  519. package/src/components/translation-review-editor.tsx +1 -1
  520. package/src/components/translation-review.tsx +11 -5
  521. package/src/components/tree-view.tsx +3 -2
  522. package/src/components/treemap.tsx +27 -10
  523. package/src/components/ui.tsx +353 -153
  524. package/src/components/user-avatar.tsx +1 -1
  525. package/src/components/wizard-stepper.tsx +5 -1
  526. package/src/demo/demo-banner.tsx +5 -0
  527. package/src/feedback/feedback-dialog.tsx +3 -3
  528. package/src/feedback/feedback-inbox.tsx +2 -2
  529. package/src/feedback/feedback-thread.tsx +3 -3
  530. package/src/hooks/use-anchored-panel.ts +67 -5
  531. package/src/hooks/use-breakpoint.ts +132 -0
  532. package/src/hooks/use-large-text.ts +41 -0
  533. package/src/hooks/use-windowed-rows.ts +168 -12
  534. package/src/i18n/defaults.ts +8 -0
  535. package/src/i18n/german.ts +107 -0
  536. package/src/i18n/kit-labels.tsx +12 -0
  537. package/src/i18n/locales/es.ts +98 -0
  538. package/src/i18n/locales/fr.ts +102 -0
  539. package/src/i18n/locales/hu.ts +100 -0
  540. package/src/i18n/locales/it.ts +103 -0
  541. package/src/i18n/locales/zh.ts +94 -0
  542. package/src/i18n/review.ts +14 -0
  543. package/src/index.ts +76 -6
  544. package/src/landing/landing-sections.tsx +7 -3
  545. package/src/landing/public-header.tsx +4 -4
  546. package/src/lib/cn.ts +13 -2
  547. package/src/rhf/fields.tsx +1 -1
  548. package/src/rhf/form.tsx +2 -2
  549. package/src/search/command-palette.tsx +10 -9
  550. package/src/settings/settings-layout.tsx +2 -1
  551. package/src/settings/use-account-appearance.ts +148 -0
  552. package/src/settings/use-settings-route.ts +3 -4
  553. package/src/shell/app-shell.tsx +278 -54
  554. package/src/shell/auth-layout.tsx +1 -1
  555. package/src/shell/option-switcher-menu.tsx +1 -1
  556. package/src/shell/top-bar-brand.tsx +3 -1
  557. package/src/shell/topbar-action-menu.tsx +3 -3
  558. package/src/shell/topbar-controls.tsx +4 -4
  559. package/src/theme/contrast-tokens.ts +112 -0
  560. package/src/theme/contrast.ts +225 -0
  561. package/src/theme/palette-presets.ts +24 -4
  562. package/src/theme/palette-store.ts +6 -1
  563. package/src/theme/text-size.ts +283 -0
  564. package/src/wizard/wizard-summary.tsx +4 -2
  565. package/tokens.css +158 -8
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/theme/text-size.ts"],"sourcesContent":["import { useEffect, useMemo, useSyncExternalStore } from \"react\";\nimport { create } from \"zustand\";\nimport { persist } from \"zustand/middleware\";\nimport { logger } from \"../lib/logger\";\nimport { readStored } from \"../lib/safe-storage\";\n\n/**\n * The text size (docs/text-size-harmonization.md §2.1, §3.1, §10.3, §10.6).\n *\n * ONE scale on `<html>`: `data-text-size=\"normal|large|xlarge\"`, and `tokens.css` turns\n * it into `font-size: 100% / 125% / 150%` — percent, never px, so \"Normal\" keeps\n * whatever size the person set in the browser. Tailwind's spacing and type are rem, so\n * about 90 % of every screen grows with that one declaration; the breakpoints follow too\n * (tokens.css redefines `sm:` … `3xl:` per size, {@link useBreakpoint} answers the same\n * in JS).\n *\n * The names below are the mechanism's public vocabulary and are FROZEN: an app's\n * storage, its `/auth/me` column (server-kit's `TEXT_SIZES`) and the inline boot snippet\n * all spell them this way.\n */\n\n/** The three steps, in order (§2.1, §10.6): server-kit's `TEXT_SIZES`, value for value. */\nexport const TEXT_SIZES = [\"normal\", \"large\", \"xlarge\"] as const;\n\nexport type TextSize = (typeof TEXT_SIZES)[number];\n\n/** The root font size each step sets, as a factor of the browser's own (tokens.css). For\n * what CSS cannot reach: a canvas or SVG chart's px constants, a windowed list's row\n * estimate, a popover width in px (§3.2). */\nexport const TEXT_SCALE: Readonly<Record<TextSize, number>> = { normal: 1, large: 1.25, xlarge: 1.5 };\n\n/** The attribute on `<html>` that carries the size. */\nconst TEXT_SIZE_ATTRIBUTE = \"data-text-size\";\n\nexport function isTextSize(value: unknown): value is TextSize {\n return value === \"normal\" || value === \"large\" || value === \"xlarge\";\n}\n\n/**\n * The size in force: **this device's own choice → the account's → Normal** (§2.2, §2.6).\n * Each is taken only when it is one of {@link TEXT_SIZES}; anything else (a stale value,\n * `null` = never chosen) falls through to the next. The one order the pre-paint call, the\n * apply hook and `useAccountAppearance` all use, so the three can never disagree.\n */\nexport function resolveTextSize(device: unknown, account?: unknown): TextSize {\n if (isTextSize(device)) return device;\n if (isTextSize(account)) return account;\n return \"normal\";\n}\n\n/* ── <html data-text-size> and the subscribers that read it ─────────────── */\n\nconst listeners = new Set<() => void>();\nlet observer: MutationObserver | null = null;\n\nfunction notify(): void {\n for (const listener of listeners) listener();\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n // Also catches writers that are not this module — the inline boot snippet, an app\n // setting the attribute by hand, a test.\n if (!observer && typeof MutationObserver !== \"undefined\" && typeof document !== \"undefined\") {\n observer = new MutationObserver(notify);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [TEXT_SIZE_ATTRIBUTE] });\n }\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) {\n observer?.disconnect();\n observer = null;\n }\n };\n}\n\n/** The size `<html>` carries now; Normal without one (or outside a browser). */\nexport function readTextSize(): TextSize {\n if (typeof document === \"undefined\") return \"normal\";\n const value = document.documentElement.getAttribute(TEXT_SIZE_ATTRIBUTE);\n return isTextSize(value) ? value : \"normal\";\n}\n\n/** Put `size` on `<html>`. Every {@link useTextSize} re-renders with it. */\nexport function applyTextSize(size: TextSize): void {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n if (root.getAttribute(TEXT_SIZE_ATTRIBUTE) === size) return;\n root.setAttribute(TEXT_SIZE_ATTRIBUTE, size);\n notify();\n}\n\nexport interface TextSizeInfo {\n size: TextSize;\n /** {@link TEXT_SCALE} for `size`: 1, 1.25 or 1.5. */\n scale: number;\n}\n\n/**\n * The size in force on this page, and its scale (§3.1) — read from `<html>`, so it needs\n * no store and works in every kit component: whoever applied the size (the app's store,\n * the pre-paint call, the inline snippet), this follows it.\n *\n * Only for what CSS cannot do. A class that should differ at Large is a `large:`\n * variant; a layout switch is a breakpoint, which already scales.\n */\nexport function useTextSize(): TextSizeInfo {\n const size = useSyncExternalStore(subscribe, readTextSize, () => \"normal\" as const);\n return useMemo(() => ({ size, scale: TEXT_SCALE[size] }), [size]);\n}\n\n/* ── Storage: the frozen format, the pre-paint call ─────────────────────── */\n\n/**\n * What a text-size store persists under its key — zustand's persist envelope, and FROZEN\n * (§10.3) because an app's inline `<head>` snippet reads it before any module loads:\n *\n * {\"state\":{\"size\":\"large\"},\"version\":1}\n *\n * `size` is one of {@link TEXT_SIZES}, or `null` / absent when this device never chose.\n * A future change adds a key; it never renames `state.size` or changes its values.\n *\n * A hand-written seed (a test, a screenshot script) must carry `\"version\":1`: the store\n * drops a stored state of another version as a migration it doesn't know, silently\n * (keksdose's 0.32 report). The inline snippet reads `state.size` whatever the version,\n * so the two would disagree. In the kit's showcase, `?text-size=` needs no seed.\n */\nexport interface PersistedTextSize {\n state?: { size?: TextSize | null };\n version?: number;\n}\n\n/** This device's own choice under `storageKey`, or `null` when it never chose (or the\n * storage is blocked, malformed, or holds a value that is not a size). */\nexport function readPersistedTextSize(storageKey: string): TextSize | null {\n try {\n const blob = JSON.parse(readStored(storageKey) ?? \"null\") as PersistedTextSize | null;\n const size = blob?.state?.size;\n return isTextSize(size) ? size : null;\n } catch {\n return null;\n }\n}\n\nexport interface PersistedAppearanceOptions {\n /**\n * The account's last known value, for a device without a choice of its own (§10.3):\n * what the app persisted with its user (keksdose keeps `/auth/me` in localStorage), so\n * a cold boot paints the account's size instead of Normal and then jumping — offline\n * too. Called once, guarded: a throw counts as \"no account value\".\n */\n account?: () => string | null | undefined;\n}\n\nfunction readAccount(account: PersistedAppearanceOptions[\"account\"]): unknown {\n if (!account) return undefined;\n try {\n return account();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Pre-paint (§3.1, §10.3): read this device's choice under `storageKey` — else the\n * account's last known value — and put it on `<html>` BEFORE `createRoot`, next to\n * `applyPersistedTheme`, so the first paint already has the right size. Returns the size\n * applied.\n *\n * ```ts\n * applyPersistedTextSize(\"keksdose-text-size\", {\n * account: () => readPersistedUser()?.text_size,\n * });\n * ```\n */\nexport function applyPersistedTextSize(storageKey: string, options: PersistedAppearanceOptions = {}): TextSize {\n const size = resolveTextSize(readPersistedTextSize(storageKey), readAccount(options.account));\n applyTextSize(size);\n return size;\n}\n\n/**\n * The same pre-paint as {@link applyPersistedTextSize}, as an inline `<head>` script for\n * a boot splash painted from `index.html` before any module runs (§10.3). A function\n * EXPRESSION: call it with the storage key and, optionally, a function returning the\n * account's last known value.\n *\n * ```html\n * <script>\n * (function(k,a){…})(\"keksdose-text-size\", function () {\n * return JSON.parse(localStorage.getItem(\"keksdose-auth\")).state.user.text_size;\n * });\n * </script>\n * ```\n *\n * Paste the constant's value in place of `(function(k,a){…})`. It reads the frozen\n * {@link PersistedTextSize} format, never throws, and sets only `data-text-size`.\n *\n * The splash sizes in rem, and needs the root rules inline beside it, since the app's\n * stylesheet is a separate request and arrives after the splash paints (0.32.1,\n * keksdose's 0.32 report: that is every app, not an edge case):\n *\n * ```html\n * <style>html[data-text-size=large]{font-size:125%}html[data-text-size=xlarge]{font-size:150%}</style>\n * ```\n *\n * Under a hash-based Content Security Policy (`script-src 'sha256-…'`) this is a second\n * inline script with its own hash: add it to the policy, and recompute it whenever the\n * storage key or the account function in the call changes (keksdose added it to both\n * its Caddyfiles, and its guard test hashes every inline script).\n */\nexport const TEXT_SIZE_INLINE_SCRIPT =\n \"(function(k,a){function ok(v){return v==='normal'||v==='large'||v==='xlarge'}\" +\n \"var v=null;try{var s=JSON.parse(localStorage.getItem(k)||'null');v=s&&s.state&&s.state.size}catch(e){}\" +\n \"if(!ok(v)){v=null;try{v=a?a():null}catch(e){}}\" +\n \"try{document.documentElement.setAttribute('data-text-size',ok(v)?v:'normal')}catch(e){}})\";\n\n/* ── The store ──────────────────────────────────────────────────────────── */\n\nexport interface TextSizeState {\n /** This device's own choice (persisted), or `null` when it never chose — then the\n * account's value applies (§2.2). */\n size: TextSize | null;\n /** Store this device's choice; `null` forgets it, so the account's applies again. */\n setSize: (size: TextSize | null) => void;\n}\n\nexport interface ApplyTextSizeOptions {\n /** The account's value (`/auth/me`'s `text_size`): it applies while this device has no\n * choice of its own. Leave it out where there is no account. */\n account?: string | null;\n}\n\n/**\n * Build a text-size store bound to a consumer-supplied localStorage key, shaped like\n * `createThemeStore` (§6). It holds the DEVICE's choice only; the account's value comes\n * in through `useApplyTextSize({ account })` and `useAccountAppearance`, and the size in\n * force is always {@link resolveTextSize} of the two.\n *\n * - `useTextSizeStore` — the zustand hook: `size` (device choice or null) and `setSize`.\n * - `useApplyTextSize({ account })` — the effect that puts the size in force on `<html>`.\n * Mount it once near the root, beside `useApplyTheme`.\n *\n * The persisted format is {@link PersistedTextSize}, and frozen.\n */\nexport function createTextSizeStore(storageKey: string) {\n const useTextSizeStore = create<TextSizeState>()(\n logger(\n persist(\n (set) => ({\n size: null,\n setSize: (size) => set({ size: isTextSize(size) ? size : null }),\n }),\n {\n name: storageKey,\n version: 1,\n partialize: (s) => ({ size: s.size }),\n // A hand-edited or future value must not reach <html> as an unknown size.\n merge: (persisted, current) => ({\n ...current,\n size: isTextSize((persisted as { size?: unknown } | null)?.size)\n ? ((persisted as { size: TextSize }).size)\n : null,\n }),\n },\n ),\n \"text-size\",\n ),\n );\n\n function useApplyTextSize({ account }: ApplyTextSizeOptions = {}): TextSize {\n const device = useTextSizeStore((s) => s.size);\n const size = resolveTextSize(device, account);\n useEffect(() => {\n applyTextSize(size);\n }, [size]);\n return size;\n }\n\n return { useTextSizeStore, useApplyTextSize };\n}\n\nexport type TextSizeStore = ReturnType<typeof createTextSizeStore>;\n"],"mappings":";AAAA,SAAS,WAAW,SAAS,4BAA4B;AACzD,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAkBpB,MAAM,aAAa,CAAC,UAAU,SAAS,QAAQ;AAO/C,MAAM,aAAiD,EAAE,QAAQ,GAAG,OAAO,MAAM,QAAQ,IAAI;AAGpG,MAAM,sBAAsB;AAErB,SAAS,WAAW,OAAmC;AAC5D,SAAO,UAAU,YAAY,UAAU,WAAW,UAAU;AAC9D;AAQO,SAAS,gBAAgB,QAAiB,SAA6B;AAC5E,MAAI,WAAW,MAAM,EAAG,QAAO;AAC/B,MAAI,WAAW,OAAO,EAAG,QAAO;AAChC,SAAO;AACT;AAIA,MAAM,YAAY,oBAAI,IAAgB;AACtC,IAAI,WAAoC;AAExC,SAAS,SAAe;AACtB,aAAW,YAAY,UAAW,UAAS;AAC7C;AAEA,SAAS,UAAU,UAAkC;AACnD,YAAU,IAAI,QAAQ;AAGtB,MAAI,CAAC,YAAY,OAAO,qBAAqB,eAAe,OAAO,aAAa,aAAa;AAC3F,eAAW,IAAI,iBAAiB,MAAM;AACtC,aAAS,QAAQ,SAAS,iBAAiB,EAAE,YAAY,MAAM,iBAAiB,CAAC,mBAAmB,EAAE,CAAC;AAAA,EACzG;AACA,SAAO,MAAM;AACX,cAAU,OAAO,QAAQ;AACzB,QAAI,UAAU,SAAS,GAAG;AACxB,gBAAU,WAAW;AACrB,iBAAW;AAAA,IACb;AAAA,EACF;AACF;AAGO,SAAS,eAAyB;AACvC,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAM,QAAQ,SAAS,gBAAgB,aAAa,mBAAmB;AACvE,SAAO,WAAW,KAAK,IAAI,QAAQ;AACrC;AAGO,SAAS,cAAc,MAAsB;AAClD,MAAI,OAAO,aAAa,YAAa;AACrC,QAAM,OAAO,SAAS;AACtB,MAAI,KAAK,aAAa,mBAAmB,MAAM,KAAM;AACrD,OAAK,aAAa,qBAAqB,IAAI;AAC3C,SAAO;AACT;AAgBO,SAAS,cAA4B;AAC1C,QAAM,OAAO,qBAAqB,WAAW,cAAc,MAAM,QAAiB;AAClF,SAAO,QAAQ,OAAO,EAAE,MAAM,OAAO,WAAW,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;AAClE;AAyBO,SAAS,sBAAsB,YAAqC;AACzE,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,WAAW,UAAU,KAAK,MAAM;AACxD,UAAM,OAAO,MAAM,OAAO;AAC1B,WAAO,WAAW,IAAI,IAAI,OAAO;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,SAAS,YAAY,SAAyD;AAC5E,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,WAAO,QAAQ;AAAA,EACjB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAcO,SAAS,uBAAuB,YAAoB,UAAsC,CAAC,GAAa;AAC7G,QAAM,OAAO,gBAAgB,sBAAsB,UAAU,GAAG,YAAY,QAAQ,OAAO,CAAC;AAC5F,gBAAc,IAAI;AAClB,SAAO;AACT;AAgCO,MAAM,0BACX;AAiCK,SAAS,oBAAoB,YAAoB;AACtD,QAAM,mBAAmB,OAAsB;AAAA,IAC7C;AAAA,MACE;AAAA,QACE,CAAC,SAAS;AAAA,UACR,MAAM;AAAA,UACN,SAAS,CAAC,SAAS,IAAI,EAAE,MAAM,WAAW,IAAI,IAAI,OAAO,KAAK,CAAC;AAAA,QACjE;AAAA,QACA;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,UACT,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK;AAAA;AAAA,UAEnC,OAAO,CAAC,WAAW,aAAa;AAAA,YAC9B,GAAG;AAAA,YACH,MAAM,WAAY,WAAyC,IAAI,IACzD,UAAiC,OACnC;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,WAAS,iBAAiB,EAAE,QAAQ,IAA0B,CAAC,GAAa;AAC1E,UAAM,SAAS,iBAAiB,CAAC,MAAM,EAAE,IAAI;AAC7C,UAAM,OAAO,gBAAgB,QAAQ,OAAO;AAC5C,cAAU,MAAM;AACd,oBAAc,IAAI;AAAA,IACpB,GAAG,CAAC,IAAI,CAAC;AACT,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,kBAAkB,iBAAiB;AAC9C;","names":[]}
@@ -1,18 +1,20 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ReactElement } from 'react';
3
- import { bH as ButtonVariant } from '../delete-account-setting-CpIhzxxZ.js';
3
+ import { bO as ButtonVariant } from '../delete-account-setting-FLyJf-kZ.js';
4
4
  import { UseWizardReturn, WizardLabels } from './types.js';
5
5
  import '../components/tooltip.js';
6
6
  import '../hooks/use-anchored-rect.js';
7
7
  import '../lib/clipping.js';
8
- import '../data-table-labels-DUELeXpa.js';
8
+ import '../data-table-labels-kpAAVi6g.js';
9
9
  import '../components/data-table-sort.js';
10
10
  import '../components/swipeable-row.js';
11
11
  import '../components/mini-calendar.js';
12
12
  import '../components/calendar-heatmap.js';
13
13
  import '../components/popover.js';
14
+ import '../hooks/use-breakpoint.js';
14
15
  import '../components/chip.js';
15
16
  import 'lucide-react';
17
+ import '../components/field-parts.js';
16
18
  import '../components/field-sync.js';
17
19
  import '../tour/tour.js';
18
20
  import '../search/command-palette.js';
@@ -80,6 +82,9 @@ import '../admin/admin-parts.js';
80
82
  import '../admin/admin-action-log.js';
81
83
  import '../settings/settings-labels.js';
82
84
  import '../demo/demo-labels.js';
85
+ import '../components/appearance-labels.js';
86
+ import '../theme/contrast.js';
87
+ import '../theme/text-size.js';
83
88
  import '../components/reauth-dialog.js';
84
89
  import '../components/server-wake.js';
85
90
  import '../lib/server-wake.js';
@@ -93,7 +98,7 @@ import '../components/sign-chip.js';
93
98
  import '../components/column-mapper.js';
94
99
  import '../lib/column-mapping.js';
95
100
  import '../lib/table-text.js';
96
- import '../components/field-parts.js';
101
+ import '../components/focus-ring.js';
97
102
 
98
103
  /**
99
104
  * The chrome around a wizard: the step indicator, the step content, and the
@@ -15,7 +15,7 @@ function WizardSummary({
15
15
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
16
16
  /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-[var(--text-primary)]", children: l.reviewTitle }),
17
17
  sections.map((section, sIdx) => /* @__PURE__ */ jsxs(Card, { children: [
18
- /* @__PURE__ */ jsxs(CardHeader, { className: "pb-2", children: [
18
+ /* @__PURE__ */ jsxs(CardHeader, { className: "pb-2", stackAction: false, children: [
19
19
  /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: section.label }),
20
20
  section.stepIndex !== void 0 && onEditStep && /* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Tooltip, { label: l.edit, children: /* @__PURE__ */ jsx(
21
21
  IconButton,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/wizard/wizard-summary.tsx"],"sourcesContent":["import { Pencil } from \"lucide-react\";\nimport { Card, CardAction, CardContent, CardHeader, CardTitle, IconButton } from \"../components/ui\";\nimport { Tooltip } from \"../components/tooltip\";\nimport type { SummarySection, WizardLabels } from \"./types\";\nimport { DEFAULT_WIZARD_LABELS } from \"./types\";\nimport { useKitLabels } from \"../i18n/kit-labels\";\n\n/**\n * The review step: one card per section, each row a label/value pair, each card\n * carrying an edit button back to the step it came from.\n *\n * Sections are data, not children, because \"jump back to step N\" is the whole\n * point of the component and a caller assembling its own cards invariably drops\n * it. Labels and values are `ReactNode`, so a value can be a badge or a link.\n *\n * A section with no `stepIndex` (file-level counts, a total) is a card without an\n * edit button. `disabled` greys every edit button at once — while the commit runs,\n * when jumping back would show a step whose edits can no longer reach the request.\n */\nexport function WizardSummary({\n sections,\n onEditStep,\n disabled = false,\n labels,\n}: {\n sections: SummarySection[];\n /** Called with the section's `stepIndex`. Optional only for a summary whose\n * sections name no step at all. */\n onEditStep?: (stepIndex: number) => void;\n /** Disable every edit button (e.g. `wizard.isSubmitting`). */\n disabled?: boolean;\n labels?: Partial<WizardLabels>;\n}) {\n const l = useKitLabels(\"wizard\", DEFAULT_WIZARD_LABELS, labels);\n\n return (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">{l.reviewTitle}</h2>\n {sections.map((section, sIdx) => (\n <Card key={sIdx}>\n {/* CardHeader is a grid, and CardAction is the top-right column it\n reserves — the edit button has to go through it or it stacks under\n the title instead of sitting beside it. */}\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-base\">{section.label}</CardTitle>\n {section.stepIndex !== undefined && onEditStep && (\n <CardAction>\n {/* The kit Tooltip, not a native `title`: it shows on keyboard focus too,\n and an app with a one-tooltip rule (keksdose dev#523) sees one. */}\n <Tooltip label={l.edit}>\n <IconButton\n size=\"sm\"\n variant=\"ghost\"\n aria-label={l.edit}\n disabled={disabled}\n onClick={() => onEditStep(section.stepIndex as number)}\n >\n <Pencil />\n </IconButton>\n </Tooltip>\n </CardAction>\n )}\n </CardHeader>\n <CardContent>\n <dl className=\"grid gap-2 text-sm\">\n {section.items.map((item, iIdx) => (\n <div key={iIdx}>\n {iIdx > 0 && (\n <div className=\"mb-2 border-t border-[var(--border)]\" role=\"presentation\" />\n )}\n <div className=\"flex items-start justify-between gap-4\">\n <dt className=\"text-[var(--text-muted)]\">{item.label}</dt>\n <dd className=\"text-end font-medium text-[var(--text-primary)]\">\n {item.value}\n </dd>\n </div>\n </div>\n ))}\n </dl>\n </CardContent>\n </Card>\n ))}\n </div>\n );\n}\n"],"mappings":";AAqCM,cAMI,YANJ;AArCN,SAAS,cAAc;AACvB,SAAS,MAAM,YAAY,aAAa,YAAY,WAAW,kBAAkB;AACjF,SAAS,eAAe;AAExB,SAAS,6BAA6B;AACtC,SAAS,oBAAoB;AActB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,GAQG;AACD,QAAM,IAAI,aAAa,UAAU,uBAAuB,MAAM;AAE9D,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,QAAG,WAAU,oDAAoD,YAAE,aAAY;AAAA,IAC/E,SAAS,IAAI,CAAC,SAAS,SACtB,qBAAC,QAIC;AAAA,2BAAC,cAAW,WAAU,QACpB;AAAA,4BAAC,aAAU,WAAU,aAAa,kBAAQ,OAAM;AAAA,QAC/C,QAAQ,cAAc,UAAa,cAClC,oBAAC,cAGC,8BAAC,WAAQ,OAAO,EAAE,MAChB;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,cAAY,EAAE;AAAA,YACd;AAAA,YACA,SAAS,MAAM,WAAW,QAAQ,SAAmB;AAAA,YAErD,8BAAC,UAAO;AAAA;AAAA,QACV,GACF,GACF;AAAA,SAEJ;AAAA,MACA,oBAAC,eACC,8BAAC,QAAG,WAAU,sBACX,kBAAQ,MAAM,IAAI,CAAC,MAAM,SACxB,qBAAC,SACE;AAAA,eAAO,KACN,oBAAC,SAAI,WAAU,wCAAuC,MAAK,gBAAe;AAAA,QAE5E,qBAAC,SAAI,WAAU,0CACb;AAAA,8BAAC,QAAG,WAAU,4BAA4B,eAAK,OAAM;AAAA,UACrD,oBAAC,QAAG,WAAU,mDACX,eAAK,OACR;AAAA,WACF;AAAA,WATQ,IAUV,CACD,GACH,GACF;AAAA,SAxCS,IAyCX,CACD;AAAA,KACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/wizard/wizard-summary.tsx"],"sourcesContent":["import { Pencil } from \"lucide-react\";\nimport { Card, CardAction, CardContent, CardHeader, CardTitle, IconButton } from \"../components/ui\";\nimport { Tooltip } from \"../components/tooltip\";\nimport type { SummarySection, WizardLabels } from \"./types\";\nimport { DEFAULT_WIZARD_LABELS } from \"./types\";\nimport { useKitLabels } from \"../i18n/kit-labels\";\n\n/**\n * The review step: one card per section, each row a label/value pair, each card\n * carrying an edit button back to the step it came from.\n *\n * Sections are data, not children, because \"jump back to step N\" is the whole\n * point of the component and a caller assembling its own cards invariably drops\n * it. Labels and values are `ReactNode`, so a value can be a badge or a link.\n *\n * A section with no `stepIndex` (file-level counts, a total) is a card without an\n * edit button. `disabled` greys every edit button at once — while the commit runs,\n * when jumping back would show a step whose edits can no longer reach the request.\n */\nexport function WizardSummary({\n sections,\n onEditStep,\n disabled = false,\n labels,\n}: {\n sections: SummarySection[];\n /** Called with the section's `stepIndex`. Optional only for a summary whose\n * sections name no step at all. */\n onEditStep?: (stepIndex: number) => void;\n /** Disable every edit button (e.g. `wizard.isSubmitting`). */\n disabled?: boolean;\n labels?: Partial<WizardLabels>;\n}) {\n const l = useKitLabels(\"wizard\", DEFAULT_WIZARD_LABELS, labels);\n\n return (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">{l.reviewTitle}</h2>\n {sections.map((section, sIdx) => (\n <Card key={sIdx}>\n {/* CardHeader is a grid, and CardAction is the top-right column it\n reserves — the edit button has to go through it or it stacks under\n the title instead of sitting beside it. `stackAction={false}`: the pencil\n is named by `aria-label` and stays an icon at Large, so it keeps its\n place beside the title there too (0.32.1). */}\n <CardHeader className=\"pb-2\" stackAction={false}>\n <CardTitle className=\"text-base\">{section.label}</CardTitle>\n {section.stepIndex !== undefined && onEditStep && (\n <CardAction>\n {/* The kit Tooltip, not a native `title`: it shows on keyboard focus too,\n and an app with a one-tooltip rule (keksdose dev#523) sees one. */}\n <Tooltip label={l.edit}>\n <IconButton\n size=\"sm\"\n variant=\"ghost\"\n aria-label={l.edit}\n disabled={disabled}\n onClick={() => onEditStep(section.stepIndex as number)}\n >\n <Pencil />\n </IconButton>\n </Tooltip>\n </CardAction>\n )}\n </CardHeader>\n <CardContent>\n <dl className=\"grid gap-2 text-sm\">\n {section.items.map((item, iIdx) => (\n <div key={iIdx}>\n {iIdx > 0 && (\n <div className=\"mb-2 border-t border-[var(--border)]\" role=\"presentation\" />\n )}\n <div className=\"flex items-start justify-between gap-4\">\n <dt className=\"text-[var(--text-muted)]\">{item.label}</dt>\n <dd className=\"text-end font-medium text-[var(--text-primary)]\">\n {item.value}\n </dd>\n </div>\n </div>\n ))}\n </dl>\n </CardContent>\n </Card>\n ))}\n </div>\n );\n}\n"],"mappings":";AAqCM,cAQI,YARJ;AArCN,SAAS,cAAc;AACvB,SAAS,MAAM,YAAY,aAAa,YAAY,WAAW,kBAAkB;AACjF,SAAS,eAAe;AAExB,SAAS,6BAA6B;AACtC,SAAS,oBAAoB;AActB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,GAQG;AACD,QAAM,IAAI,aAAa,UAAU,uBAAuB,MAAM;AAE9D,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,QAAG,WAAU,oDAAoD,YAAE,aAAY;AAAA,IAC/E,SAAS,IAAI,CAAC,SAAS,SACtB,qBAAC,QAMC;AAAA,2BAAC,cAAW,WAAU,QAAO,aAAa,OACxC;AAAA,4BAAC,aAAU,WAAU,aAAa,kBAAQ,OAAM;AAAA,QAC/C,QAAQ,cAAc,UAAa,cAClC,oBAAC,cAGC,8BAAC,WAAQ,OAAO,EAAE,MAChB;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,cAAY,EAAE;AAAA,YACd;AAAA,YACA,SAAS,MAAM,WAAW,QAAQ,SAAmB;AAAA,YAErD,8BAAC,UAAO;AAAA;AAAA,QACV,GACF,GACF;AAAA,SAEJ;AAAA,MACA,oBAAC,eACC,8BAAC,QAAG,WAAU,sBACX,kBAAQ,MAAM,IAAI,CAAC,MAAM,SACxB,qBAAC,SACE;AAAA,eAAO,KACN,oBAAC,SAAI,WAAU,wCAAuC,MAAK,gBAAe;AAAA,QAE5E,qBAAC,SAAI,WAAU,0CACb;AAAA,8BAAC,QAAG,WAAU,4BAA4B,eAAK,OAAM;AAAA,UACrD,oBAAC,QAAG,WAAU,mDACX,eAAK,OACR;AAAA,WACF;AAAA,WATQ,IAUV,CACD,GACH,GACF;AAAA,SA1CS,IA2CX,CACD;AAAA,KACH;AAEJ;","names":[]}
package/dist/wizard.d.ts CHANGED
@@ -6,18 +6,20 @@ export { WizardStep, WizardStepProps } from './wizard/wizard-step.js';
6
6
  export { WizardSummary } from './wizard/wizard-summary.js';
7
7
  export { StepperNav } from './wizard/stepper-nav.js';
8
8
  import 'react';
9
- import './delete-account-setting-CpIhzxxZ.js';
9
+ import './delete-account-setting-FLyJf-kZ.js';
10
10
  import './components/tooltip.js';
11
11
  import './hooks/use-anchored-rect.js';
12
12
  import './lib/clipping.js';
13
- import './data-table-labels-DUELeXpa.js';
13
+ import './data-table-labels-kpAAVi6g.js';
14
14
  import './components/data-table-sort.js';
15
15
  import './components/swipeable-row.js';
16
16
  import './components/mini-calendar.js';
17
17
  import './components/calendar-heatmap.js';
18
18
  import './components/popover.js';
19
+ import './hooks/use-breakpoint.js';
19
20
  import './components/chip.js';
20
21
  import 'lucide-react';
22
+ import './components/field-parts.js';
21
23
  import './components/field-sync.js';
22
24
  import './tour/tour.js';
23
25
  import './search/command-palette.js';
@@ -85,6 +87,9 @@ import './admin/admin-parts.js';
85
87
  import './admin/admin-action-log.js';
86
88
  import './settings/settings-labels.js';
87
89
  import './demo/demo-labels.js';
90
+ import './components/appearance-labels.js';
91
+ import './theme/contrast.js';
92
+ import './theme/text-size.js';
88
93
  import './components/reauth-dialog.js';
89
94
  import './components/server-wake.js';
90
95
  import './lib/server-wake.js';
@@ -98,4 +103,4 @@ import './components/sign-chip.js';
98
103
  import './components/column-mapper.js';
99
104
  import './lib/column-mapping.js';
100
105
  import './lib/table-text.js';
101
- import './components/field-parts.js';
106
+ import './components/focus-ring.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eifi1/ui-kit",
3
- "version": "0.31.1",
3
+ "version": "0.32.1",
4
4
  "type": "module",
5
5
  "description": "App-agnostic shared design system: domain-free React components, theme and tokens.",
6
6
  "_sideEffects": "The barrel (src/index.ts) re-exports EVERY component, including components/chart, which statically imports recharts. Without this field a bundler must assume each of those modules has side effects, so it cannot drop the unused ones: importing a Button from '@eifi1/ui-kit' dragged all 433KB of recharts into the consumer's ENTRY chunk, and Keksdose was preloading it on every page load, login included. Nothing in src/ imports for side effects (no bare imports, no CSS imports from JS, no module-level global writes) — the token stylesheet is its own './tokens.css' export — so this is safe. CSS is still listed so any future stylesheet survives. Re-checked when `flag-icons` left `dependencies` and tsup started emitting a `\"use client\"` banner: neither touches this. The flag stylesheet was never imported from JS in the first place (that was the finding), and a directive prologue is a string literal every bundler lifts out before it decides whether a module is inert.",
@@ -47,7 +47,10 @@ export type AdminActionKind =
47
47
  | "transfer"
48
48
  | "deletion_request"
49
49
  | "deletion_cancel"
50
- | "erase";
50
+ | "erase"
51
+ // 0.32.1 (keksdose's 0.32 report): server-kit 0.6's `AdminAction.PLAN`, an operator's
52
+ // plan change or grant (docs/billing-harmonization.md §6).
53
+ | "plan";
51
54
 
52
55
  /** Every {@link AdminActionKind}, in the contract's order. */
53
56
  export const ADMIN_ACTION_KINDS: readonly AdminActionKind[] = [
@@ -67,6 +70,7 @@ export const ADMIN_ACTION_KINDS: readonly AdminActionKind[] = [
67
70
  "deletion_request",
68
71
  "deletion_cancel",
69
72
  "erase",
73
+ "plan",
70
74
  ];
71
75
 
72
76
  /** One logged action — the app's `admin_actions` row with the people joined in. */
@@ -142,6 +146,7 @@ export const DEFAULT_ADMIN_ACTION_LOG_LABELS: AdminActionLogLabels = {
142
146
  deletion_request: "Deletion requested",
143
147
  deletion_cancel: "Deletion cancelled",
144
148
  erase: "Account erased",
149
+ plan: "Plan changed",
145
150
  },
146
151
  };
147
152
 
@@ -14,7 +14,8 @@ import type { ChipTone } from "../components/chip";
14
14
  import { CopyButton } from "../components/copy-button";
15
15
  import { LanguageSelect } from "../components/language-select";
16
16
  import { SectionLabel, Caption } from "../components/text";
17
- import { Button, IconButton, Input, Select, Spinner } from "../components/ui";
17
+ import { RowActions } from "../components/row-actions";
18
+ import { Button, Input, Select, Spinner } from "../components/ui";
18
19
  import { useWriteLock } from "../components/write-lock";
19
20
  import { hasMessage, settle, useDayText, usePersonLabel } from "./admin-parts";
20
21
  import type { AdminPerson, MaybePromise } from "./admin-parts";
@@ -480,35 +481,41 @@ export function InvitationsPanel<R extends string = string>({
480
481
  </div>
481
482
  {(link || resendable || revocable) && (
482
483
  <div className="ms-auto flex shrink-0 items-center gap-1">
484
+ {/* The copy stays its own icon: it says "Copied" where it was
485
+ pressed, which a menu entry that closes cannot. */}
483
486
  {link && open && <CopyButton size="xs" tone="muted" text={link} label={labels.copyLink} />}
484
- {resendable && (
485
- <IconButton
486
- size="xs"
487
- commit
488
- label={labels.resend(invitation.email)}
489
- pending={busy === `resend:${key}`}
490
- disabled={busy !== null}
491
- onClick={async () => {
492
- const answer = await run(`resend:${key}`, () => onResend(invitation));
493
- if (answer !== FAILED) took(answer, invitation.email, invitation.id);
494
- }}
495
- >
496
- <RefreshCw />
497
- </IconButton>
498
- )}
499
- {revocable && (
500
- <IconButton
501
- size="xs"
502
- tone="danger"
503
- commit
504
- label={labels.revoke(invitation.email)}
505
- pending={busy === `revoke:${key}`}
506
- disabled={busy !== null}
507
- onClick={() => void run(`revoke:${key}`, () => onRevoke(invitation))}
508
- >
509
- <Trash2 />
510
- </IconButton>
511
- )}
487
+ {/* Resend and revoke are the row's actions (docs/text-size-
488
+ harmonization.md §10.8): two icons at Normal, one "⋯" menu at
489
+ Large, where both names as text ("Send … a new link") would
490
+ not fit a phone's row beside the copy icon. */}
491
+ <RowActions
492
+ name={invitation.email}
493
+ actions={[
494
+ resendable && {
495
+ key: "resend",
496
+ label: labels.resend(invitation.email),
497
+ icon: RefreshCw,
498
+ commit: true,
499
+ pending: busy === `resend:${key}`,
500
+ disabled: busy !== null,
501
+ onSelect: () =>
502
+ void (async () => {
503
+ const answer = await run(`resend:${key}`, () => onResend(invitation));
504
+ if (answer !== FAILED) took(answer, invitation.email, invitation.id);
505
+ })(),
506
+ },
507
+ revocable && {
508
+ key: "revoke",
509
+ label: labels.revoke(invitation.email),
510
+ icon: Trash2,
511
+ tone: "danger",
512
+ commit: true,
513
+ pending: busy === `revoke:${key}`,
514
+ disabled: busy !== null,
515
+ onSelect: () => void run(`revoke:${key}`, () => onRevoke(invitation)),
516
+ },
517
+ ]}
518
+ />
512
519
  </div>
513
520
  )}
514
521
  </div>
@@ -1,7 +1,5 @@
1
1
  import { useMemo } from "react";
2
2
  import type { ReactNode } from "react";
3
- import { MoreHorizontal } from "lucide-react";
4
- import type { LucideIcon } from "lucide-react";
5
3
  import { cn } from "../lib/cn";
6
4
  import type { DateInput } from "../lib/format";
7
5
  import type { PersonName } from "../lib/person-name";
@@ -12,8 +10,8 @@ import type { ChipTone } from "../components/chip";
12
10
  import type { DataTableColumn } from "../components/data-table";
13
11
  import { encodeSorts } from "../components/data-table-sort";
14
12
  import type { SortState } from "../components/data-table-sort";
15
- import { Popover } from "../components/popover";
16
- import { Button, IconButton } from "../components/ui";
13
+ import { RowActions } from "../components/row-actions";
14
+ import type { RowAction, RowActionList } from "../components/row-actions";
17
15
  import { UserAvatar } from "../components/user-avatar";
18
16
  import { personLabel } from "./admin-parts";
19
17
  import { RoleSelect } from "./role-select";
@@ -213,27 +211,13 @@ export function UserIdentityCell({
213
211
 
214
212
  /* ── The row's actions ──────────────────────────────────────────────────────── */
215
213
 
216
- /** One entry of a row's action menu (§4). */
217
- export interface UserRowAction {
218
- /** React key. Default: the label. */
219
- key?: string;
220
- label: string;
221
- /** Runs it — usually opens `AdminActionConfirm` with the level the server states. */
222
- onSelect: () => void;
223
- icon?: LucideIcon;
224
- /** `danger` for deactivate, transfer, erase. */
225
- tone?: "default" | "danger";
226
- /** Why it is not available for this row ("You can’t deactivate yourself"). The entry
227
- * stays in the menu, focusable, and says so — an action that silently vanished
228
- * would leave the admin looking for it. */
229
- disabledReason?: ReactNode;
230
- /** Leave it out for this row. */
231
- hidden?: boolean;
232
- }
214
+ /** One entry of a row's action menu (§4) — the kit's {@link RowAction} since 0.32,
215
+ * which generalised it for every dense row (docs/text-size-harmonization.md §10.8). */
216
+ export type UserRowAction = RowAction;
233
217
 
234
218
  /** What `actions(row)` may return: entries, and `false` / `null` for the ones a
235
219
  * condition left out (`row.is_active && {…}`). */
236
- export type UserRowActionList = readonly (UserRowAction | false | null | undefined)[];
220
+ export type UserRowActionList = RowActionList;
237
221
 
238
222
  export interface UserRowActionsProps {
239
223
  actions: UserRowActionList;
@@ -248,59 +232,19 @@ export interface UserRowActionsProps {
248
232
  * a phone card, and both grow with every action §2.4 adds. The menu is portalled, so a
249
233
  * table's scroller cannot clip it; Escape and an outside press close it, and focus goes
250
234
  * back to the button, which is where a confirmation dialog then returns it.
235
+ *
236
+ * Since 0.32 this is {@link RowActions} with `collapse="menu"` — the menu at every size —
237
+ * named by the roster's own `actionsFor`.
251
238
  */
252
239
  export function UserRowActions({ actions, name, labels: labelsProp }: UserRowActionsProps) {
253
240
  const labels = useKitLabels("userRoster", DEFAULT_USER_ROSTER_LABELS, labelsProp);
254
- const entries = actions.filter((a): a is UserRowAction => Boolean(a) && !(a as UserRowAction).hidden);
255
- if (entries.length === 0) return null;
256
- const title = labels.actionsFor(name);
257
241
  return (
258
- <Popover
259
- width={240}
260
- aria-label={title}
261
- className="p-1"
262
- trigger={({ open, toggle, ref }) => (
263
- <IconButton
264
- ref={ref}
265
- size="xs"
266
- label={title}
267
- aria-haspopup="dialog"
268
- aria-expanded={open}
269
- stopPropagation
270
- onClick={toggle}
271
- >
272
- <MoreHorizontal />
273
- </IconButton>
274
- )}
275
- >
276
- {(close) => (
277
- <ul className="space-y-0.5">
278
- {entries.map((action) => {
279
- const Icon = action.icon;
280
- return (
281
- <li key={action.key ?? action.label}>
282
- <Button
283
- type="button"
284
- variant="ghost"
285
- size="sm"
286
- stretch
287
- tone={action.tone === "danger" ? "danger" : undefined}
288
- disabledReason={action.disabledReason}
289
- className="justify-start"
290
- onClick={() => {
291
- close();
292
- action.onSelect();
293
- }}
294
- >
295
- {Icon && <Icon className="size-4 shrink-0" aria-hidden />}
296
- {action.label}
297
- </Button>
298
- </li>
299
- );
300
- })}
301
- </ul>
302
- )}
303
- </Popover>
242
+ <RowActions
243
+ actions={actions}
244
+ name={name}
245
+ collapse="menu"
246
+ labels={{ actionsFor: labels.actionsFor }}
247
+ />
304
248
  );
305
249
  }
306
250
 
@@ -507,7 +451,8 @@ export function userRosterColumns<T extends UserRosterRow, R extends string = st
507
451
  column: { mobileHidden: true },
508
452
  }),
509
453
  // How long ago rather than a date — the question is "recently?" — with the exact
510
- // time in a tooltip (keksdose's last-seen column, Kurvenschmiede's).
454
+ // time beside it (keksdose's last-seen column, Kurvenschmiede's; 0.32 §4: never only
455
+ // in a tooltip).
511
456
  dateColumn<T>({
512
457
  key: "last_login",
513
458
  header: labels.lastLogin,
@@ -86,9 +86,35 @@ export type DemoErrorCode =
86
86
  | "demo_read_only"
87
87
  | "demo_refused";
88
88
 
89
- /** Every code the kit reads: the sign-in refusals, the account ones (0.30.0) and the
90
- * demo's (0.31.0). */
91
- export type KitErrorCode = AuthErrorCode | AccountErrorCode | DemoErrorCode;
89
+ /**
90
+ * 0.32.0: billing's coded refusals (docs/billing-harmonization.md §3.3, §3.4, §4, §12.3) —
91
+ * server-kit 0.6's `BillingError` and `PlanLimitError`, value for value, answered as
92
+ * `{detail, code}` like the others and read by the same {@link authErrorCode}.
93
+ *
94
+ * - `billing_disabled` — `404`: the billing switch is off (§2.9), so every billing route
95
+ * but `GET /billing/status` is "not there", as a switched-off demo is.
96
+ * - `billing_read_only` — `402`: a write by (or into the data of) a payer out of good
97
+ * standing (§3.3, §12.1). Inside a sync reply it marks the changes that were refused
98
+ * and not applied (§12.5). The app's write lock and banner already say why, so — like
99
+ * `demo_read_only` — it needs no toast of its own.
100
+ * - `plan_limit` — `402`: a create past the plan's limit (§3.4), with the extra fields
101
+ * `dimension`, `plan`, `limit` and `used` — read them with `isPlanLimit`. A lapsed payer
102
+ * creating gets `billing_read_only` instead, never this (§12.3).
103
+ * - `billing_not_configured` — billing is switched on but the provider's settings are
104
+ * missing (the secrets, a price id): the operator's mistake, not the payer's.
105
+ */
106
+ export type BillingErrorCode = "billing_disabled" | "billing_read_only" | "plan_limit" | "billing_not_configured";
107
+
108
+ /** Every code the kit reads: the sign-in refusals, the account ones (0.30.0), the demo's
109
+ * (0.31.0) and billing's (0.32.0). */
110
+ export type KitErrorCode = AuthErrorCode | AccountErrorCode | DemoErrorCode | BillingErrorCode;
111
+
112
+ const BILLING_CODES: ReadonlySet<BillingErrorCode> = new Set<BillingErrorCode>([
113
+ "billing_disabled",
114
+ "billing_read_only",
115
+ "plan_limit",
116
+ "billing_not_configured",
117
+ ]);
92
118
 
93
119
  const CODES: ReadonlySet<string> = new Set<KitErrorCode>([
94
120
  "invalid_credentials",
@@ -112,6 +138,7 @@ const CODES: ReadonlySet<string> = new Set<KitErrorCode>([
112
138
  "demo_not_ready",
113
139
  "demo_read_only",
114
140
  "demo_refused",
141
+ ...BILLING_CODES,
115
142
  ]);
116
143
 
117
144
  type Bag = Record<string, unknown>;
@@ -132,8 +159,8 @@ function codeOfBody(body: unknown): KitErrorCode | undefined {
132
159
 
133
160
  /**
134
161
  * The code an error carries — an {@link AuthErrorCode}, since 0.30.0 an
135
- * {@link AccountErrorCode}, since 0.31.0 a {@link DemoErrorCode} — or `undefined` when it
136
- * carries none.
162
+ * {@link AccountErrorCode}, since 0.31.0 a {@link DemoErrorCode}, since 0.32.0 a
163
+ * {@link BillingErrorCode} — or `undefined` when it carries none.
137
164
  *
138
165
  * Reads the parsed response body wherever the apps' HTTP clients put it, without
139
166
  * depending on any of them:
@@ -148,7 +175,7 @@ function codeOfBody(body: unknown): KitErrorCode | undefined {
148
175
  * it is one of the codes above: axios writes its OWN codes there (`ERR_NETWORK`,
149
176
  * `ECONNABORTED`, `ERR_BAD_REQUEST`), and so does Node, so an unknown value is never
150
177
  * read as a refusal. The HTTP status is not checked: the code is the contract, and the
151
- * status differs per refusal (401, 403, 409, 410).
178
+ * status differs per refusal (401, 402, 403, 404, 409, 410).
152
179
  */
153
180
  export function authErrorCode(err: unknown): KitErrorCode | undefined {
154
181
  if (!isBag(err)) return undefined;
@@ -173,13 +200,47 @@ export function authErrorCode(err: unknown): KitErrorCode | undefined {
173
200
  * with, so an app's `onSubmit` can simply let its client's error through. See
174
201
  * {@link authErrorCode} for the shapes it reads. Since 0.30.0 it knows the account codes
175
202
  * too: `isAuthError(err, "last_admin")`; since 0.31.0 the demo's:
176
- * `isAuthError(err, "demo_read_only")`.
203
+ * `isAuthError(err, "demo_read_only")`; since 0.32.0 billing's:
204
+ * `isAuthError(err, "billing_read_only")` (or {@link isBillingError}).
177
205
  */
178
206
  export function isAuthError(err: unknown, code?: KitErrorCode): boolean {
179
207
  const found = authErrorCode(err);
180
208
  return found !== undefined && (code === undefined || found === code);
181
209
  }
182
210
 
211
+ /**
212
+ * Whether `err` is one of billing's coded refusals (0.32.0, docs/billing-harmonization.md
213
+ * §10) — any of the four, or the one named. {@link isAuthError} answers the same for a
214
+ * named code; this one also answers "is it billing's at all", which an app's error
215
+ * handler asks before it decides between the write lock, a `PlanLimitNotice` and a toast.
216
+ */
217
+ export function isBillingError(err: unknown, code?: BillingErrorCode): boolean {
218
+ const found = authErrorCode(err);
219
+ return found !== undefined && BILLING_CODES.has(found as BillingErrorCode) && (code === undefined || found === code);
220
+ }
221
+
222
+ /**
223
+ * The parsed body that carries a code, wherever {@link authErrorCode} would find it (in
224
+ * the same order) — the object with the `code`, so FastAPI's nested `detail` when the code
225
+ * is there. For a reader of a refusal's EXTRA fields (`isPlanLimit`: `dimension`, `limit`,
226
+ * `used` sit beside the code). `accept` decides which codes count; default, the known ones.
227
+ *
228
+ * @internal Not part of the barrel.
229
+ */
230
+ export function errorBodyWithCode(
231
+ err: unknown,
232
+ accept: (code: unknown) => boolean = (code) => known(code) !== undefined,
233
+ ): Record<string, unknown> | undefined {
234
+ if (!isBag(err)) return undefined;
235
+ const response = err.response;
236
+ for (const body of [isBag(response) ? response.data : undefined, err.data, err.body, err]) {
237
+ if (!isBag(body)) continue;
238
+ if (accept(body.code)) return body;
239
+ if (isBag(body.detail) && accept(body.detail.code)) return body.detail;
240
+ }
241
+ return undefined;
242
+ }
243
+
183
244
  /** An HTTP status as a number, or undefined. */
184
245
  function statusOf(value: unknown): number | undefined {
185
246
  return typeof value === "number" && Number.isInteger(value) ? value : undefined;