@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,101 @@
1
+ import { currencyMinorDigits, formatMoney } from "../lib/format";
2
+
3
+ /**
4
+ * Money and periods of the plan catalogue (docs/billing-harmonization.md §3.1, §4, §12.17).
5
+ *
6
+ * Money crosses the wire as INTEGER MINOR UNITS plus an ISO currency, never as a float
7
+ * (§4): 4900 CHF is CHF 49.00. The kit turns it into the reader's notation with
8
+ * `formatMoney`, so no app divides by 100 by hand.
9
+ */
10
+
11
+ /** A billing period: the provider charges per month or per year. */
12
+ export type BillingInterval = "month" | "year";
13
+
14
+ /** The two currencies every app sells in (§2.6). */
15
+ export type BillingCurrency = "CHF" | "EUR";
16
+
17
+ /**
18
+ * The periods in the order the picker offers them — YEARLY FIRST (§12.17): a Merchant of
19
+ * Record takes about 5 % + 0.50 per transaction, so a small monthly price loses a fifth
20
+ * of itself (CHF 3 a month loses about 22 %). The page leads with the yearly price.
21
+ */
22
+ export const BILLING_INTERVALS: readonly BillingInterval[] = Object.freeze(["year", "month"]);
23
+
24
+ /** One currency's prices, in minor units, per period. A period left out is not offered. */
25
+ export type PlanIntervalPrices = Partial<Record<BillingInterval, number>>;
26
+
27
+ /** A plan's prices as server-kit's `PlanSpec.prices` sends them: currency → period →
28
+ * minor units, GROSS (§12.17). */
29
+ export type PlanPrices = Partial<Record<BillingCurrency, PlanIntervalPrices>>;
30
+
31
+ /**
32
+ * What one plan costs in one currency and period:
33
+ * - `price` — a gross amount in minor units;
34
+ * - `free` — a plan with no prices at all (keksdose's free plan), or a price of 0;
35
+ * - `not-offered` — a plan with prices, but none for this currency and period.
36
+ */
37
+ export type PlanPriceAnswer =
38
+ | { kind: "price"; minor: number }
39
+ | { kind: "free" }
40
+ | { kind: "not-offered" };
41
+
42
+ /** Whether a price table holds any figure at all. */
43
+ function hasAnyPrice(prices: PlanPrices | null | undefined): boolean {
44
+ if (!prices) return false;
45
+ return Object.values(prices).some(
46
+ (byInterval) => byInterval && Object.values(byInterval).some((v) => typeof v === "number"),
47
+ );
48
+ }
49
+
50
+ /** What `prices` says for `currency` and `interval` — see {@link PlanPriceAnswer}. */
51
+ export function planPrice(
52
+ prices: PlanPrices | null | undefined,
53
+ currency: BillingCurrency,
54
+ interval: BillingInterval,
55
+ ): PlanPriceAnswer {
56
+ const minor = prices?.[currency]?.[interval];
57
+ if (typeof minor === "number" && Number.isFinite(minor)) {
58
+ return minor === 0 ? { kind: "free" } : { kind: "price", minor };
59
+ }
60
+ return hasAnyPrice(prices) ? { kind: "not-offered" } : { kind: "free" };
61
+ }
62
+
63
+ /** Minor units as the amount: 4900 CHF → 49, 1250 EUR → 12.5. The currency's minor unit
64
+ * comes from `Intl` (CHF and EUR have 2); a code `Intl` cannot read counts as 2. */
65
+ export function minorToMajor(minor: number, currency: string): number {
66
+ const digits = currencyMinorDigits(currency) ?? 2;
67
+ return minor / 10 ** digits;
68
+ }
69
+
70
+ /**
71
+ * A price in minor units, in the reader's notation: "CHF 49", "CHF 4.90", "49 €",
72
+ * "4,90 €". A whole amount drops its decimals — a price list reads "CHF 49" — and any
73
+ * other keeps all of them ("CHF 4.90", never "CHF 4.9").
74
+ */
75
+ export function formatPlanPrice(minor: number, currency: string, options: { locale?: string } = {}): string {
76
+ const digits = currencyMinorDigits(currency) ?? 2;
77
+ const whole = Number.isInteger(minor) && minor % 10 ** digits === 0;
78
+ return formatMoney(minorToMajor(minor, currency), currency, {
79
+ locale: options.locale,
80
+ digits: whole ? 0 : digits,
81
+ });
82
+ }
83
+
84
+ /**
85
+ * The currency a payer starts with when the app stores none (§12.18): francs where the
86
+ * locale's region is Switzerland or Liechtenstein, euros everywhere else — "de-CH" and
87
+ * "fr-CH" CHF, "de" (Germany, once `Intl` fills the region in) and "it" EUR.
88
+ *
89
+ * Only the fallback: an account's stored currency comes first (keksdose's
90
+ * `reporting_currency` — a de-CH speaker living in Germany pays in euros), and the payer
91
+ * may switch in the picker either way; checkout takes the one they leave it on (§4).
92
+ */
93
+ export function billingCurrencyFor(locale?: string): BillingCurrency {
94
+ if (!locale) return "EUR";
95
+ try {
96
+ const region = new Intl.Locale(locale).maximize().region;
97
+ return region === "CH" || region === "LI" ? "CHF" : "EUR";
98
+ } catch {
99
+ return "EUR";
100
+ }
101
+ }
@@ -0,0 +1,76 @@
1
+ import type { ComponentPropsWithoutRef } from "react";
2
+
3
+ import type { LabelOverride } from "../i18n/kit-labels";
4
+ import { cn } from "../lib/cn";
5
+ import { Button } from "../components/ui";
6
+ import { useBillingLabels } from "./billing-labels";
7
+ import type { BillingLabels } from "./billing-labels";
8
+
9
+ export interface SubscriptionActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
10
+ /** "Payment and invoices", as a link — or {@link onManage}. Without either, none. */
11
+ manageHref?: string;
12
+ /** "Payment and invoices", as the app's call: `POST /billing/portal`, then off to its
13
+ * `url` (§4). The kit sends no request. */
14
+ onManage?: () => void;
15
+ /** "Cancel subscription", as a link — or {@link onCancel}. Without either, none. */
16
+ cancelHref?: string;
17
+ /** "Cancel subscription", as the app's call — usually the portal again, where the
18
+ * provider's cancel and withdrawal functions are (§12.26). */
19
+ onCancel?: () => void;
20
+ /** Which of the two is under way: its spinner, no second press. */
21
+ pending?: "manage" | "cancel" | null;
22
+ /** Prop > `<UiKitProvider labels={{ billing }}>` > English. */
23
+ labels?: LabelOverride<BillingLabels>;
24
+ }
25
+
26
+ /**
27
+ * The two ways to the provider's hosted portal on the subscription page
28
+ * (docs/billing-harmonization.md §2.8, §7, §12.26): "Payment and invoices" — the payment
29
+ * method and the invoices live there, never in the app — and a VISIBLE "Cancel
30
+ * subscription". Consumer law wants the second in plain sight: Germany's cancellation
31
+ * button (§312k BGB) and the EU withdrawal function (Directive (EU) 2023/2673, from
32
+ * 19 June 2026) are in the portal, and the app's page must not hide the way there behind
33
+ * "manage".
34
+ *
35
+ * Neither takes the write lock: a read-only payer must be able to pay, leave or cancel
36
+ * (§3.3).
37
+ */
38
+ export function SubscriptionActions({
39
+ manageHref,
40
+ onManage,
41
+ cancelHref,
42
+ onCancel,
43
+ pending,
44
+ labels: labelsProp,
45
+ className,
46
+ ...rest
47
+ }: SubscriptionActionsProps) {
48
+ const labels = useBillingLabels(labelsProp);
49
+ const manage =
50
+ manageHref !== undefined ? (
51
+ <Button href={manageHref} variant="secondary">
52
+ {labels.manage}
53
+ </Button>
54
+ ) : onManage !== undefined ? (
55
+ <Button type="button" variant="secondary" onClick={onManage} pending={pending === "manage"}>
56
+ {labels.manage}
57
+ </Button>
58
+ ) : null;
59
+ const cancel =
60
+ cancelHref !== undefined ? (
61
+ <Button href={cancelHref} variant="link" tone="danger">
62
+ {labels.cancel}
63
+ </Button>
64
+ ) : onCancel !== undefined ? (
65
+ <Button type="button" variant="link" tone="danger" onClick={onCancel} pending={pending === "cancel"}>
66
+ {labels.cancel}
67
+ </Button>
68
+ ) : null;
69
+ if (!manage && !cancel) return null;
70
+ return (
71
+ <div {...rest} className={cn("flex flex-wrap items-center gap-x-4 gap-y-2", className)}>
72
+ {manage}
73
+ {cancel}
74
+ </div>
75
+ );
76
+ }
@@ -0,0 +1,95 @@
1
+ import type { ReactNode } from "react";
2
+
3
+ import type { LabelOverride } from "../i18n/kit-labels";
4
+ import { Chip } from "../components/chip";
5
+ import type { ChipShape, ChipSize, ChipTone, ChipVariant } from "../components/chip";
6
+ import { useBillingLabels } from "./billing-labels";
7
+ import type { BillingLabels, SubscriptionStatus } from "./billing-labels";
8
+
9
+ /**
10
+ * The tone of each status (docs/billing-harmonization.md §3.2, §3.3). The tone follows
11
+ * the STANDING, so a roster reads at a glance who can write:
12
+ *
13
+ * - `active` green: paid, in good standing;
14
+ * - `trialing` blue (info): in good standing until `trial_ends_at`, nothing wrong;
15
+ * - `past_due` amber: a payment failed, still in good standing while the provider retries;
16
+ * - `expired` red: out of good standing — read-only until a plan is chosen;
17
+ * - `canceled` grey: the payer's own choice, nothing to warn about;
18
+ * - `comped` purple, a hue rather than a tone: free by grant — neither paid nor in trouble,
19
+ * only different from both.
20
+ */
21
+ export const SUBSCRIPTION_STATUS_TONES: Readonly<Record<SubscriptionStatus, ChipTone>> = Object.freeze({
22
+ trialing: "info",
23
+ active: "success",
24
+ past_due: "warning",
25
+ canceled: "neutral",
26
+ expired: "danger",
27
+ comped: "purple",
28
+ });
29
+
30
+ export interface SubscriptionStatusChipProps {
31
+ /**
32
+ * The row's `status` as the API sends it (§3.2). A value the kit does not know yet is
33
+ * shown as itself, in `neutral` — an unknown status is still a fact an operator should
34
+ * see. `null` / `undefined` renders nothing.
35
+ */
36
+ status: SubscriptionStatus | (string & {}) | null | undefined;
37
+ /** Over {@link SUBSCRIPTION_STATUS_TONES}. */
38
+ tone?: ChipTone;
39
+ /** Over the status's word, for an app whose word is its own. */
40
+ children?: ReactNode;
41
+ /** Default `sm` (a roster's `extra` column, §6). */
42
+ size?: ChipSize;
43
+ /** Default `soft`. */
44
+ variant?: ChipVariant;
45
+ /** Default `square`, the status tag of `AccountStateChip`. */
46
+ shape?: ChipShape;
47
+ /** Default true, as `AccountStateChip`. */
48
+ caps?: boolean;
49
+ className?: string;
50
+ /** Prop > `<UiKitProvider labels={{ billing: { status } }}>` > English. */
51
+ labels?: LabelOverride<BillingLabels>;
52
+ [key: `data-${string}`]: string | number | boolean | undefined;
53
+ }
54
+
55
+ // Own keys only: `"toString" in {}` is true.
56
+ const isKnown = (value: string): value is SubscriptionStatus =>
57
+ Object.prototype.hasOwnProperty.call(SUBSCRIPTION_STATUS_TONES, value);
58
+
59
+ /**
60
+ * A subscription's status as a chip, in the kit's words and tones (§6: the operator's
61
+ * roster shows the plan and the standing; §7: the subscription page). ALWAYS A WORD, never
62
+ * colour alone: "Trial", "Active", "Payment overdue", "Cancelled", "Expired",
63
+ * "Complimentary" — the tone repeats what the word says. Carries `data-status` with the
64
+ * key, for a test or a style hook.
65
+ */
66
+ export function SubscriptionStatusChip({
67
+ status,
68
+ tone,
69
+ children,
70
+ size = "sm",
71
+ variant,
72
+ shape = "square",
73
+ caps = true,
74
+ className,
75
+ labels: labelsProp,
76
+ ...rest
77
+ }: SubscriptionStatusChipProps) {
78
+ const labels = useBillingLabels(labelsProp);
79
+ if (status === null || status === undefined || status === "") return null;
80
+ const known = isKnown(status);
81
+ return (
82
+ <Chip
83
+ {...rest}
84
+ data-status={status}
85
+ tone={tone ?? (known ? SUBSCRIPTION_STATUS_TONES[status] : "neutral")}
86
+ size={size}
87
+ variant={variant}
88
+ shape={shape}
89
+ caps={caps}
90
+ className={className}
91
+ >
92
+ {children ?? (known ? labels.status[status] : status)}
93
+ </Chip>
94
+ );
95
+ }
package/src/chart.ts CHANGED
@@ -16,6 +16,8 @@ export * from "./components/treemap";
16
16
  // lenkbank's zoomable series chart, its synced x-zoom, the toggle legend and the
17
17
  // mirrored-pair axis geometry — moved here so the apps derive them from the package.
18
18
  export * from "./components/series-chart";
19
+ // 0.32.1 (keksdose's 0.32 report): the height every chart takes, for an app's wrappers.
20
+ export type { ChartHeight } from "./components/chart-height";
19
21
  export * from "./components/chart-zoom";
20
22
  export * from "./components/toggle-legend";
21
23
  export * from "./components/facing-pair";
@@ -7,7 +7,6 @@ import { useKitDateFormatter, useKitLabels, useKitLocale } from "../i18n/kit-lab
7
7
  import { toLocalIso } from "../lib/dates";
8
8
  import { Chip } from "./chip";
9
9
  import type { ChipShape, ChipSize, ChipTone, ChipVariant } from "./chip";
10
- import { Tooltip } from "./tooltip";
11
10
  import type { DataTableColumn } from "./data-table";
12
11
 
13
12
  /**
@@ -255,10 +254,18 @@ export interface DateMarkProps {
255
254
  /**
256
255
  * `"date"` (default): the date in `dateStyle` — "Created". `"relative"`: how long
257
256
  * ago — "Last login", where the question is "recently?" — with the full date and
258
- * time in a tooltip (keksdose's last-seen column).
257
+ * time beside it (keksdose's last-seen column; see `absolute`).
259
258
  */
260
259
  display?: "date" | "relative";
261
- /** Default `medium`. Under `"relative"`, the style of the tooltip's date (default
260
+ /**
261
+ * Where a `"relative"` mark puts the exact date and time (0.32,
262
+ * docs/text-size-harmonization.md §4: "relative dates show the absolute one beside
263
+ * them", at every size — a touch screen never opens the tooltip it used to live in):
264
+ * `"below"` (default), a muted second line under the words, so a table column keeps
265
+ * its width; `"inline"`, after them on the same line, for a sentence or a wide cell.
266
+ */
267
+ absolute?: "below" | "inline";
268
+ /** Default `medium`. Under `"relative"`, the style of the exact date beside it (default
262
269
  * `dateTime`) and of the date `relative.absoluteAfterDays` switches to. Given, it wins
263
270
  * over the provider's `formatDate`. */
264
271
  dateStyle?: FormatDateStyle | Intl.DateTimeFormatOptions;
@@ -288,6 +295,7 @@ export function DateMark({
288
295
  display = "date",
289
296
  dateStyle,
290
297
  relative,
298
+ absolute = "below",
291
299
  empty = EMPTY_FORMATTED_VALUE,
292
300
  locale: localeProp,
293
301
  className,
@@ -309,14 +317,32 @@ export function DateMark({
309
317
  );
310
318
  }
311
319
  const text = formatRelativeTime(date, { ...relative, locale, absoluteStyle: dateStyle ?? "medium" });
312
- return (
313
- <Tooltip label={formatDate(date, dateStyle ?? "dateTime", { locale })} lazy>
314
- {/* Not a tab stop: a roster of fifty rows would be fifty more of them, and the
315
- relative words already answer the column's question; the exact time is extra. */}
316
- <time dateTime={date.toISOString()} className={cls}>
317
- {text}
320
+ const exact = formatDate(date, dateStyle ?? "dateTime", { locale });
321
+ // Past `absoluteAfterDays` the relative words already ARE the date; then the exact
322
+ // line alone, rather than the same day twice.
323
+ const sameDay = text === formatDate(date, dateStyle ?? "medium", { locale });
324
+ const iso = date.toISOString();
325
+ if (sameDay) {
326
+ return (
327
+ <time dateTime={iso} className={cls}>
328
+ {exact}
318
329
  </time>
319
- </Tooltip>
330
+ );
331
+ }
332
+ // The exact date and time in the layout, never only in a tooltip (§4). Still no tab
333
+ // stop: a roster of fifty rows would be fifty more of them.
334
+ return (
335
+ <time
336
+ dateTime={iso}
337
+ data-slot="date-mark"
338
+ className={cn(absolute === "below" ? "inline-flex flex-col leading-tight" : "inline", className)}
339
+ >
340
+ <span className="whitespace-nowrap tabular-nums">{text}</span>
341
+ {absolute === "inline" && " · "}
342
+ <span className={cn("whitespace-nowrap tabular-nums text-[var(--text-muted)]", absolute === "below" && "text-xs")}>
343
+ {exact}
344
+ </span>
345
+ </time>
320
346
  );
321
347
  }
322
348
 
@@ -1,6 +1,7 @@
1
1
  import type { ComponentPropsWithoutRef, MouseEvent, ReactNode } from "react";
2
2
  import { AlertTriangle, CheckCircle2, ChevronRight, Info, X } from "lucide-react";
3
3
  import { cn } from "../lib/cn";
4
+ import { FOCUS_RING } from "./focus-ring";
4
5
  import { DEFAULT_COMMON_LABELS, useKitLabels } from "../i18n/kit-labels";
5
6
 
6
7
  /** `info` (0.8.0) is the sky family, for news that is neither good nor bad: keksdose's
@@ -60,16 +61,21 @@ export function toneFrameClass(tone: AlertTone): string {
60
61
 
61
62
  /** Single source for the warning-callout frame (feedback #277): the tone's border
62
63
  * and surface plus this component's own radius and padding, the latter
63
- * compensating the 2px colored border so toggling tones never shifts layout. */
64
+ * compensating the 2px colored border so toggling tones never shifts layout.
65
+ *
66
+ * The compensation is `calc(<the neutral padding in rem> - 1px)`, not a px figure
67
+ * (0.32, docs/text-size-harmonization.md §3.2): the padding grows with the text size,
68
+ * the 1px it gives back to the border does not — an 11 px padding stopped matching `p-3`
69
+ * at 125 %, and toggling the tone shifted the layout again. */
64
70
  export function alertFrameClass(tone: AlertTone, size: AlertSize = "md"): string {
65
71
  const box =
66
72
  size === "sm"
67
73
  ? tone === "neutral"
68
74
  ? "rounded-md px-2.5 py-1.5"
69
- : "rounded-md px-[9px] py-[5px]"
75
+ : "rounded-md px-[calc(0.625rem-1px)] py-[calc(0.375rem-1px)]"
70
76
  : tone === "neutral"
71
77
  ? "rounded-md p-3"
72
- : "rounded-md p-[11px]";
78
+ : "rounded-md p-[calc(0.75rem-1px)]";
73
79
  return `${box} ${TONE_FRAME[tone]}`;
74
80
  }
75
81
 
@@ -293,8 +299,7 @@ export function AlertBanner({
293
299
  strip ? stripFrameClass(tone, size) : alertFrameClass(tone, size),
294
300
  elevated && cn(ELEVATED, TONE_ELEVATED[tone]),
295
301
  );
296
- const focusRing =
297
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)] focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-surface)]";
302
+ const focusRing = cn(FOCUS_RING, "focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-surface)]");
298
303
 
299
304
  const content = (
300
305
  <>
@@ -331,11 +336,15 @@ export function AlertBanner({
331
336
  ) : null;
332
337
 
333
338
  // `relative z-10` so it stays clickable over a whole-row banner's stretched target.
339
+ // `max-w-full flex-wrap`: on a line of its own, two actions side by side ran 57 px
340
+ // past a 360 px phone at Extra large (the demo strip's "Request access" and "Sign in",
341
+ // 0.32.1); held to the line, they wrap there instead. Where they fit in one row,
342
+ // nothing changes.
334
343
  const trailing =
335
344
  action !== undefined && action !== null ? (
336
345
  <div
337
346
  className={cn(
338
- "relative z-10 flex shrink-0 items-center gap-2",
347
+ "relative z-10 flex max-w-full shrink-0 flex-wrap items-center gap-2",
339
348
  !strip && !inlineRow && "self-center",
340
349
  strip && "ms-auto",
341
350
  // Last, on a line of its own, lined up with the message (past the glyph).
@@ -376,7 +385,7 @@ export function AlertBanner({
376
385
  inlineRow || strip ? "items-center" : "items-start",
377
386
  "outline-none after:absolute after:inset-0 after:content-['']",
378
387
  strip ? "after:rounded-none" : "after:rounded-md",
379
- "focus-visible:after:ring-2 focus-visible:after:ring-[var(--brand)]",
388
+ "focus-visible:after:ring-[length:var(--focus-ring-width)] focus-visible:after:ring-[var(--brand)]",
380
389
  )
381
390
  : cn(row, !inlineRow && "w-full", frame, TONE_TEXT[tone], hover, focusRing, className);
382
391
  // The div's attributes are the row element's: an `id`, a test id or an
@@ -2,10 +2,10 @@ import { forwardRef, useCallback, useId, useMemo, useRef, useState } from "react
2
2
  import { ChevronDown } from "lucide-react";
3
3
  import type { ReactNode } from "react";
4
4
  import { CURRENCIES, CurrencyFlag, currencyName, getCurrency } from "./currency-select";
5
- import { FIELD_BASE, FIELD_DISPLAY, FIELD_INVALID, FLOATING_INPUT_CLASS, FloatingField, PHONE_QUERY } from "./ui";
5
+ import { FIELD_BASE, FIELD_DISPLAY, FIELD_INVALID, FLOATING_INPUT_CLASS, FloatingField } from "./ui";
6
6
  import { cn } from "../lib/cn";
7
7
  import { currencyMinorDigits } from "../lib/format";
8
- import { useMediaQuery } from "../hooks/use-media-query";
8
+ import { usePhoneLayout } from "../hooks/use-breakpoint";
9
9
  import { CalculatorButton, type CalculatorButtonLabels } from "./calculator";
10
10
  import { NumberPadSheet, type NumberPadSheetLabels } from "./numpad-sheet";
11
11
  import { DropdownPanel, DropdownSearchHeader, useDropdownSearch } from "./dropdown";
@@ -274,7 +274,7 @@ function settleAmount(text: string, digits: number | undefined, min?: number, ma
274
274
 
275
275
  // The error line under a field — the type of `ui.tsx`'s (module-private) one, so an
276
276
  // AmountInput's message is indistinguishable from an Input's.
277
- const FIELD_ERROR_CLASS = "mt-1 text-[11px] leading-tight text-[var(--danger)]";
277
+ const FIELD_ERROR_CLASS = "mt-1 text-caption leading-tight text-[var(--danger)]";
278
278
 
279
279
  // The consuming app's ONE money palette (`--money-expense` / `--money-income`),
280
280
  // not a bespoke rose/emerald pairing: a figure being typed has to wear the same
@@ -332,7 +332,7 @@ export const AmountInput = forwardRef<HTMLInputElement, AmountInputProps>(
332
332
  // On phones we suppress the OS keyboard (inputMode="none" below) and show our
333
333
  // own calculator numpad, so the desktop popover trigger is hidden. The
334
334
  // end padding keys off showCalc, so it tightens up automatically.
335
- const isMobile = useMediaQuery(PHONE_QUERY, false);
335
+ const isMobile = usePhoneLayout();
336
336
  const showCalc = calculator && !disabled && !isMobile;
337
337
  const [focused, setFocused] = useState(false);
338
338
  // On mobile, focusing the field opens the numpad bottom sheet in place of the
@@ -678,7 +678,7 @@ export const AmountInput = forwardRef<HTMLInputElement, AmountInputProps>(
678
678
  {/* Outside the relative box, as NumberInput's caption is: the trailing
679
679
  controls are `inset-y-1` in it and would stretch down over a second line. */}
680
680
  {textHint && (
681
- <p id={hintId} className="mt-1 text-[11px] leading-tight text-[var(--text-muted)]">
681
+ <p id={hintId} className="mt-1 text-caption leading-tight text-[var(--text-muted)]">
682
682
  {hint}
683
683
  </p>
684
684
  )}
@@ -0,0 +1,47 @@
1
+ import { useKitLabels } from "../i18n/kit-labels";
2
+ import type { ContrastMode } from "../theme/contrast";
3
+ import type { TextSize } from "../theme/text-size";
4
+
5
+ /**
6
+ * The `appearance` namespace (0.32, docs/text-size-harmonization.md §6): the words of the
7
+ * two new settings in the core `appearance` group — `TextSizeSetting` and
8
+ * `ContrastSetting` — and of any quick switch an app builds from the same vocabulary (the
9
+ * showcase's top bar). Like every kit label: prop > `<UiKitProvider labels={{ appearance
10
+ * }}>` > English.
11
+ */
12
+ export interface AppearanceLabels {
13
+ /** The text-size setting's name. */
14
+ textSize: string;
15
+ /** One line under it: what changes, so "Large" is not mistaken for zoom. */
16
+ textSizeHelp: string;
17
+ /** The three steps, in {@link TEXT_SIZES} order. */
18
+ textSizes: Record<TextSize, string>;
19
+ /** The contrast setting's name. */
20
+ contrast: string;
21
+ /** One line under it. */
22
+ contrastHelp: string;
23
+ /** The three choices, in {@link CONTRAST_MODES} order. */
24
+ contrastModes: Record<ContrastMode, string>;
25
+ /**
26
+ * The account could not keep the pick (`useAccountAppearance`'s `pickTextSize` /
27
+ * `pickContrast` rejected): this device keeps it, the account doesn't. For the app's
28
+ * toast or the line under the setting (0.32.1, keksdose's 0.32 report).
29
+ */
30
+ saveFailed: string;
31
+ }
32
+
33
+ export const DEFAULT_APPEARANCE_LABELS: AppearanceLabels = {
34
+ textSize: "Text size",
35
+ textSizeHelp: "Larger letters, and a layout that makes room for them.",
36
+ textSizes: { normal: "Normal", large: "Large", xlarge: "Extra large" },
37
+ contrast: "Contrast",
38
+ contrastHelp: "More contrast darkens quiet text and lines, and thickens focus frames. System follows this device.",
39
+ contrastModes: { system: "System", standard: "Standard", more: "More" },
40
+ saveFailed: "Couldn't save this to your account. It still applies on this device.",
41
+ };
42
+
43
+ /** The `appearance` namespace, resolved — English, then the provider, then `labels`. For
44
+ * an app's catalogue entries and quick switches, without restating the defaults. */
45
+ export function useAppearanceLabels(labels?: Partial<AppearanceLabels>): AppearanceLabels {
46
+ return useKitLabels("appearance", DEFAULT_APPEARANCE_LABELS, labels);
47
+ }
@@ -500,7 +500,7 @@ function AutocompleteInner<V extends string | number = string>(
500
500
  {startsGroup && (
501
501
  <li
502
502
  role="presentation"
503
- className="px-3 pb-0.5 pt-2 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1"
503
+ className="px-3 pb-0.5 pt-2 text-caption font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1"
504
504
  >
505
505
  {o.group}
506
506
  </li>
@@ -546,7 +546,7 @@ function AutocompleteInner<V extends string | number = string>(
546
546
  <span
547
547
  className={cn(
548
548
  "block truncate text-[var(--text-placeholder)]",
549
- small ? "text-[11px]" : "text-xs",
549
+ small ? "text-caption" : "text-xs",
550
550
  )}
551
551
  >
552
552
  {o.sublabel}
@@ -2,6 +2,7 @@ import { Fragment, useEffect, useRef, useState } from "react";
2
2
  import type { ComponentPropsWithoutRef, ReactElement, ReactNode } from "react";
3
3
  import { ChevronRight, MoreHorizontal } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
5
+ import { FOCUS_RING } from "./focus-ring";
5
6
  import { useKitLabels, useKitLink } from "../i18n/kit-labels";
6
7
  import { pickLinkRenderer, RenderedKitLink } from "./text-link";
7
8
 
@@ -106,8 +107,7 @@ export function Breadcrumbs({
106
107
  {separator ?? <ChevronRight className="size-3.5 rtl:-scale-x-100" />}
107
108
  </span>
108
109
  );
109
- const linkClass =
110
- "block max-w-[14rem] truncate rounded-sm hover:text-[var(--text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)]";
110
+ const linkClass = cn("block max-w-[14rem] truncate rounded-sm hover:text-[var(--text-primary)]", FOCUS_RING);
111
111
 
112
112
  return (
113
113
  <nav {...rest} aria-label={ariaLabel ?? labels.label} className={cn("min-w-0 text-sm", className)}>
@@ -150,7 +150,7 @@ export function Breadcrumbs({
150
150
  }}
151
151
  aria-label={labels.showAll}
152
152
  aria-expanded={false}
153
- className="flex items-center rounded-sm px-0.5 hover:text-[var(--text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)]"
153
+ className={cn("flex items-center rounded-sm px-0.5 hover:text-[var(--text-primary)]", FOCUS_RING)}
154
154
  >
155
155
  <MoreHorizontal className="size-4" aria-hidden />
156
156
  </button>
@@ -6,7 +6,7 @@ import { cn } from "../lib/cn";
6
6
  import { horizontalStep } from "../lib/direction";
7
7
  import { useKitLabels } from "../i18n/kit-labels";
8
8
  import { useAnnounce } from "../hooks/use-announce";
9
- import { useMediaQuery } from "../hooks/use-media-query";
9
+ import { useBreakpoint } from "../hooks/use-breakpoint";
10
10
  import { OVERLAY_EXIT_MS, prefersReducedMotion } from "../hooks/use-close-transition";
11
11
  import { Button, IconButton } from "./ui";
12
12
 
@@ -38,8 +38,8 @@ export type BulkActionBarVariant = "floating" | "sticky" | "inline";
38
38
  /**
39
39
  * A variant per breakpoint, mobile first — `{ base: "floating", md: "sticky" }` is the
40
40
  * phone's floating card below 768px and the desktop's sticky bar from there up. The
41
- * breakpoints are Tailwind's (sm 640, md 768, lg 1024, xl 1280px), the ones the kit's
42
- * classes already use. keksdose's payees selection bar (payees-selection-bar.tsx)
41
+ * breakpoints are the ones the kit's classes use (sm 640, md 768, lg 1024, xl 1280px
42
+ * at Normal text size; since 0.32 they move with the text size, as `md:` does). keksdose's payees selection bar (payees-selection-bar.tsx)
43
43
  * computes exactly this with its own `useMediaQuery("(min-width: 768px)")`; every bar
44
44
  * that is a card on a phone and a strip on a desktop would repeat it.
45
45
  *
@@ -55,12 +55,9 @@ export interface ResponsiveBulkActionBarVariant {
55
55
  xl?: BulkActionBarVariant;
56
56
  }
57
57
 
58
- const BREAKPOINTS = [
59
- ["xl", "(min-width: 1280px)"],
60
- ["lg", "(min-width: 1024px)"],
61
- ["md", "(min-width: 768px)"],
62
- ["sm", "(min-width: 640px)"],
63
- ] as const;
58
+ /** Widest first: the first that matches and names a value wins. Each is the class's own
59
+ * breakpoint at the text size in force (`useBreakpoint`), so `md` here is `md:` there. */
60
+ const BREAKPOINTS = ["xl", "lg", "md", "sm"] as const;
64
61
 
65
62
  /** The variant in force: the widest breakpoint that matches AND names one, else
66
63
  * `base`. The four queries are subscribed unconditionally — hooks cannot be skipped —
@@ -68,13 +65,13 @@ const BREAKPOINTS = [
68
65
  * every query is false, so the bar renders its `base`, the phone's, first. */
69
66
  function useResolvedVariant(variant: BulkActionBarVariant | ResponsiveBulkActionBarVariant): BulkActionBarVariant {
70
67
  const matches = {
71
- xl: useMediaQuery(BREAKPOINTS[0][1], false),
72
- lg: useMediaQuery(BREAKPOINTS[1][1], false),
73
- md: useMediaQuery(BREAKPOINTS[2][1], false),
74
- sm: useMediaQuery(BREAKPOINTS[3][1], false),
68
+ xl: useBreakpoint("xl"),
69
+ lg: useBreakpoint("lg"),
70
+ md: useBreakpoint("md"),
71
+ sm: useBreakpoint("sm"),
75
72
  };
76
73
  if (typeof variant === "string") return variant;
77
- for (const [key] of BREAKPOINTS) {
74
+ for (const key of BREAKPOINTS) {
78
75
  const v = variant[key];
79
76
  if (matches[key] && v !== undefined) return v;
80
77
  }
@@ -26,6 +26,26 @@ const JOINED_COMMON = cn(
26
26
  "[&>*]:relative [&>*:focus-within]:z-10",
27
27
  );
28
28
 
29
+ /**
30
+ * A joined row at Large and Extra large wraps rather than run past its container (0.32.1,
31
+ * the 360 px Extra-large sweep; docs/text-size-harmonization.md §4 "nothing
32
+ * overflows"): "Buttons | Chips | Feedback" was 329 px at 150 %, 67 px past a 360 px
33
+ * phone's card. A wrapped row cannot keep one frame with dividers between members — the
34
+ * second line's first member would carry a divider against the frame and no line would
35
+ * part the rows — so at Large the frame is drawn by the members: each its own 1px
36
+ * border, overlapping its neighbours by a pixel on both axes (the container's `ps-px
37
+ * pt-px` takes the overlap back at the edges). On one row that draws the same frame and
38
+ * dividers as Normal; wrapped, every line and every member is parted by one hairline,
39
+ * and the members share out each line (`grow`), so the lines make one block. A group
40
+ * that fits is only as wide as its members, so nothing grows there. A `large:` class,
41
+ * so Normal keeps the frame it has, and it costs no render.
42
+ */
43
+ const JOINED_WRAP_AT_LARGE = cn(
44
+ "large:max-w-full large:flex-wrap large:border-0 large:ps-px large:pt-px",
45
+ "large:[&>*]:border large:[&>*]:-ms-px large:[&>*]:-mt-px",
46
+ "large:[&>*]:grow large:[&>*>button]:grow large:[&>*>a]:grow",
47
+ );
48
+
29
49
  const JOINED: Record<"horizontal" | "vertical", string> = {
30
50
  // Logical edges and corners throughout (`border-s`, `rounded-s-*`), so in RTL the
31
51
  // first member sits on the right with the right-hand corners rounded — the physical
@@ -37,6 +57,7 @@ const JOINED: Record<"horizontal" | "vertical", string> = {
37
57
  "[&>:first-child]:rounded-s-md [&>:last-child]:rounded-e-md",
38
58
  "[&>:first-child>button]:rounded-s-md [&>:last-child>button]:rounded-e-md",
39
59
  "[&>:first-child>a]:rounded-s-md [&>:last-child>a]:rounded-e-md",
60
+ JOINED_WRAP_AT_LARGE,
40
61
  ),
41
62
  // The block axis is top-to-bottom in both reading directions, so top/bottom are
42
63
  // already the logical edges here.