@eifi1/ui-kit 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. package/README.md +53 -30
  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-parts.d.ts +8 -1
  5. package/dist/admin/admin-parts.js +1 -1
  6. package/dist/admin/admin-parts.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/auth/reset-password-form.d.ts +1 -1
  21. package/dist/auth/reset-password-form.js +2 -1
  22. package/dist/auth/reset-password-form.js.map +1 -1
  23. package/dist/auth/verify-email.d.ts +4 -0
  24. package/dist/auth/verify-email.js +3 -2
  25. package/dist/auth/verify-email.js.map +1 -1
  26. package/dist/billing/billing-banner.d.ts +184 -0
  27. package/dist/billing/billing-banner.js +98 -0
  28. package/dist/billing/billing-banner.js.map +1 -0
  29. package/dist/billing/billing-labels.d.ts +100 -0
  30. package/dist/billing/billing-labels.js +74 -0
  31. package/dist/billing/billing-labels.js.map +1 -0
  32. package/dist/billing/billing-lock.d.ts +158 -0
  33. package/dist/billing/billing-lock.js +17 -0
  34. package/dist/billing/billing-lock.js.map +1 -0
  35. package/dist/billing/billing-standing.d.ts +149 -0
  36. package/dist/billing/billing-standing.js +28 -0
  37. package/dist/billing/billing-standing.js.map +1 -0
  38. package/dist/billing/plan-card.d.ts +248 -0
  39. package/dist/billing/plan-card.js +248 -0
  40. package/dist/billing/plan-card.js.map +1 -0
  41. package/dist/billing/plan-limit-notice.d.ts +156 -0
  42. package/dist/billing/plan-limit-notice.js +76 -0
  43. package/dist/billing/plan-limit-notice.js.map +1 -0
  44. package/dist/billing/plan-limit.d.ts +34 -0
  45. package/dist/billing/plan-limit.js +20 -0
  46. package/dist/billing/plan-limit.js.map +1 -0
  47. package/dist/billing/plan-price.d.ts +61 -0
  48. package/dist/billing/plan-price.js +45 -0
  49. package/dist/billing/plan-price.js.map +1 -0
  50. package/dist/billing/subscription-actions.d.ts +133 -0
  51. package/dist/billing/subscription-actions.js +28 -0
  52. package/dist/billing/subscription-actions.js.map +1 -0
  53. package/dist/billing/subscription-status-chip.d.ts +149 -0
  54. package/dist/billing/subscription-status-chip.js +48 -0
  55. package/dist/billing/subscription-status-chip.js.map +1 -0
  56. package/dist/chart.d.ts +9 -3
  57. package/dist/components/account-chips.d.ts +16 -4
  58. package/dist/components/account-chips.js +21 -3
  59. package/dist/components/account-chips.js.map +1 -1
  60. package/dist/components/alert-banner.d.ts +6 -1
  61. package/dist/components/alert-banner.js +4 -3
  62. package/dist/components/alert-banner.js.map +1 -1
  63. package/dist/components/amount-input.d.ts +8 -3
  64. package/dist/components/amount-input.js +5 -5
  65. package/dist/components/amount-input.js.map +1 -1
  66. package/dist/components/appearance-labels.d.ts +32 -0
  67. package/dist/components/appearance-labels.js +18 -0
  68. package/dist/components/appearance-labels.js.map +1 -0
  69. package/dist/components/autocomplete.js +2 -2
  70. package/dist/components/autocomplete.js.map +1 -1
  71. package/dist/components/breadcrumbs.js +3 -2
  72. package/dist/components/breadcrumbs.js.map +1 -1
  73. package/dist/components/bulk-action-bar.d.ts +2 -2
  74. package/dist/components/bulk-action-bar.js +7 -12
  75. package/dist/components/bulk-action-bar.js.map +1 -1
  76. package/dist/components/button-group.d.ts +8 -3
  77. package/dist/components/calculator.d.ts +8 -3
  78. package/dist/components/calculator.js +4 -3
  79. package/dist/components/calculator.js.map +1 -1
  80. package/dist/components/calendar-heatmap.js +5 -5
  81. package/dist/components/calendar-heatmap.js.map +1 -1
  82. package/dist/components/chart-height.d.ts +23 -0
  83. package/dist/components/chart-height.js +15 -0
  84. package/dist/components/chart-height.js.map +1 -0
  85. package/dist/components/chart-zoom.js +6 -1
  86. package/dist/components/chart-zoom.js.map +1 -1
  87. package/dist/components/checkbox-group.js +2 -2
  88. package/dist/components/checkbox-group.js.map +1 -1
  89. package/dist/components/checkbox.d.ts +10 -0
  90. package/dist/components/checkbox.js +25 -10
  91. package/dist/components/checkbox.js.map +1 -1
  92. package/dist/components/chip.d.ts +19 -3
  93. package/dist/components/chip.js +47 -21
  94. package/dist/components/chip.js.map +1 -1
  95. package/dist/components/choice-card.d.ts +1 -1
  96. package/dist/components/choice-card.js +8 -7
  97. package/dist/components/choice-card.js.map +1 -1
  98. package/dist/components/column-mapper.js +1 -1
  99. package/dist/components/column-mapper.js.map +1 -1
  100. package/dist/components/combobox-core.js +8 -7
  101. package/dist/components/combobox-core.js.map +1 -1
  102. package/dist/components/combobox.js +8 -8
  103. package/dist/components/combobox.js.map +1 -1
  104. package/dist/components/confirm-dialog.d.ts +8 -3
  105. package/dist/components/confirm-dialog.js +7 -1
  106. package/dist/components/confirm-dialog.js.map +1 -1
  107. package/dist/components/copy-button.d.ts +10 -5
  108. package/dist/components/country-select.js +1 -1
  109. package/dist/components/country-select.js.map +1 -1
  110. package/dist/components/currency-select.js +3 -3
  111. package/dist/components/currency-select.js.map +1 -1
  112. package/dist/components/danger-confirm.d.ts +8 -3
  113. package/dist/components/data-table-cells.d.ts +1 -1
  114. package/dist/components/data-table-filter-popover.d.ts +1 -1
  115. package/dist/components/data-table-filter-popover.js +4 -1
  116. package/dist/components/data-table-filter-popover.js.map +1 -1
  117. package/dist/components/data-table-filters.d.ts +1 -1
  118. package/dist/components/data-table-labels.d.ts +1 -1
  119. package/dist/components/data-table-pagination.d.ts +1 -1
  120. package/dist/components/data-table.d.ts +1 -1
  121. package/dist/components/data-table.js +123 -52
  122. package/dist/components/data-table.js.map +1 -1
  123. package/dist/components/date-picker.d.ts +1 -1
  124. package/dist/components/date-picker.js +7 -5
  125. package/dist/components/date-picker.js.map +1 -1
  126. package/dist/components/description-list.js +2 -2
  127. package/dist/components/description-list.js.map +1 -1
  128. package/dist/components/dialog-frame.js +2 -1
  129. package/dist/components/dialog-frame.js.map +1 -1
  130. package/dist/components/disclosure.js +3 -2
  131. package/dist/components/disclosure.js.map +1 -1
  132. package/dist/components/dropdown.d.ts +1 -1
  133. package/dist/components/dropdown.js +7 -1
  134. package/dist/components/dropdown.js.map +1 -1
  135. package/dist/components/facing-pair.d.ts +19 -6
  136. package/dist/components/facing-pair.js +3 -2
  137. package/dist/components/facing-pair.js.map +1 -1
  138. package/dist/components/field-parts.d.ts +102 -6
  139. package/dist/components/field-parts.js +81 -6
  140. package/dist/components/field-parts.js.map +1 -1
  141. package/dist/components/field-sync.d.ts +4 -1
  142. package/dist/components/field-sync.js +12 -2
  143. package/dist/components/field-sync.js.map +1 -1
  144. package/dist/components/field.js +2 -2
  145. package/dist/components/field.js.map +1 -1
  146. package/dist/components/file-button.d.ts +8 -3
  147. package/dist/components/file-dropzone.d.ts +8 -3
  148. package/dist/components/floating-panel.js +7 -4
  149. package/dist/components/floating-panel.js.map +1 -1
  150. package/dist/components/focus-ring.d.ts +12 -0
  151. package/dist/components/focus-ring.js +8 -0
  152. package/dist/components/focus-ring.js.map +1 -0
  153. package/dist/components/form-actions.d.ts +8 -3
  154. package/dist/components/form-actions.js +33 -19
  155. package/dist/components/form-actions.js.map +1 -1
  156. package/dist/components/full-bleed-dialog.d.ts +11 -1
  157. package/dist/components/full-bleed-dialog.js +3 -1
  158. package/dist/components/full-bleed-dialog.js.map +1 -1
  159. package/dist/components/iban-input.d.ts +8 -3
  160. package/dist/components/image-grid.js +1 -1
  161. package/dist/components/image-grid.js.map +1 -1
  162. package/dist/components/inline-edit-field.js +6 -3
  163. package/dist/components/inline-edit-field.js.map +1 -1
  164. package/dist/components/language-select.d.ts +8 -3
  165. package/dist/components/legal-page.d.ts +26 -5
  166. package/dist/components/legal-page.js +3 -1
  167. package/dist/components/legal-page.js.map +1 -1
  168. package/dist/components/legal.d.ts +8 -3
  169. package/dist/components/legal.js +2 -1
  170. package/dist/components/legal.js.map +1 -1
  171. package/dist/components/lightbox.js +24 -2
  172. package/dist/components/lightbox.js.map +1 -1
  173. package/dist/components/line-items.js +2 -1
  174. package/dist/components/line-items.js.map +1 -1
  175. package/dist/components/list.d.ts +5 -0
  176. package/dist/components/list.js +13 -9
  177. package/dist/components/list.js.map +1 -1
  178. package/dist/components/measured-grid.d.ts +3 -1
  179. package/dist/components/measured-grid.js +38 -20
  180. package/dist/components/measured-grid.js.map +1 -1
  181. package/dist/components/menu-item.js +2 -1
  182. package/dist/components/menu-item.js.map +1 -1
  183. package/dist/components/mini-calendar.js +8 -4
  184. package/dist/components/mini-calendar.js.map +1 -1
  185. package/dist/components/money-field.d.ts +8 -3
  186. package/dist/components/month-picker.js +9 -5
  187. package/dist/components/month-picker.js.map +1 -1
  188. package/dist/components/nav-pills.js +1 -1
  189. package/dist/components/nav-pills.js.map +1 -1
  190. package/dist/components/number-field.d.ts +8 -3
  191. package/dist/components/number-input.d.ts +11 -4
  192. package/dist/components/number-input.js +8 -6
  193. package/dist/components/number-input.js.map +1 -1
  194. package/dist/components/numpad-sheet.d.ts +8 -3
  195. package/dist/components/numpad-sheet.js +2 -1
  196. package/dist/components/numpad-sheet.js.map +1 -1
  197. package/dist/components/one-time-code-input.js +2 -2
  198. package/dist/components/one-time-code-input.js.map +1 -1
  199. package/dist/components/page-contents.js +2 -2
  200. package/dist/components/page-contents.js.map +1 -1
  201. package/dist/components/phone-input.d.ts +8 -3
  202. package/dist/components/phone-input.js +2 -2
  203. package/dist/components/phone-input.js.map +1 -1
  204. package/dist/components/pie-chart.d.ts +8 -2
  205. package/dist/components/pie-chart.js +11 -7
  206. package/dist/components/pie-chart.js.map +1 -1
  207. package/dist/components/popover.d.ts +9 -1
  208. package/dist/components/popover.js +8 -4
  209. package/dist/components/popover.js.map +1 -1
  210. package/dist/components/row-actions.d.ts +100 -0
  211. package/dist/components/row-actions.js +165 -0
  212. package/dist/components/row-actions.js.map +1 -0
  213. package/dist/components/scroll-area.js +1 -1
  214. package/dist/components/scroll-area.js.map +1 -1
  215. package/dist/components/search-field.js +3 -2
  216. package/dist/components/search-field.js.map +1 -1
  217. package/dist/components/series-chart-budget.d.ts +30 -7
  218. package/dist/components/series-chart-budget.js +12 -4
  219. package/dist/components/series-chart-budget.js.map +1 -1
  220. package/dist/components/series-chart-ticks.d.ts +7 -1
  221. package/dist/components/series-chart-ticks.js +6 -0
  222. package/dist/components/series-chart-ticks.js.map +1 -1
  223. package/dist/components/series-chart.d.ts +58 -28
  224. package/dist/components/series-chart.js +42 -32
  225. package/dist/components/series-chart.js.map +1 -1
  226. package/dist/components/settings-fields.d.ts +51 -6
  227. package/dist/components/settings-fields.js +37 -0
  228. package/dist/components/settings-fields.js.map +1 -1
  229. package/dist/components/share-card.d.ts +11 -6
  230. package/dist/components/share-card.js +2 -0
  231. package/dist/components/share-card.js.map +1 -1
  232. package/dist/components/sign-chip.d.ts +4 -0
  233. package/dist/components/sign-chip.js +17 -4
  234. package/dist/components/sign-chip.js.map +1 -1
  235. package/dist/components/signature-pad.d.ts +3 -1
  236. package/dist/components/signature-pad.js +8 -5
  237. package/dist/components/signature-pad.js.map +1 -1
  238. package/dist/components/slider.js +7 -6
  239. package/dist/components/slider.js.map +1 -1
  240. package/dist/components/sparkline.d.ts +5 -1
  241. package/dist/components/sparkline.js +4 -2
  242. package/dist/components/sparkline.js.map +1 -1
  243. package/dist/components/stat-tile.d.ts +17 -1
  244. package/dist/components/stat-tile.js +48 -20
  245. package/dist/components/stat-tile.js.map +1 -1
  246. package/dist/components/status-dot.d.ts +4 -0
  247. package/dist/components/swipeable-row.js +2 -1
  248. package/dist/components/swipeable-row.js.map +1 -1
  249. package/dist/components/switch.d.ts +21 -7
  250. package/dist/components/switch.js +24 -11
  251. package/dist/components/switch.js.map +1 -1
  252. package/dist/components/table.js +2 -2
  253. package/dist/components/table.js.map +1 -1
  254. package/dist/components/text-link.d.ts +8 -3
  255. package/dist/components/text-link.js +1 -1
  256. package/dist/components/text-link.js.map +1 -1
  257. package/dist/components/text.d.ts +7 -2
  258. package/dist/components/text.js +5 -5
  259. package/dist/components/text.js.map +1 -1
  260. package/dist/components/tile-radio.js +2 -1
  261. package/dist/components/tile-radio.js.map +1 -1
  262. package/dist/components/time-input.d.ts +8 -3
  263. package/dist/components/toast.d.ts +18 -2
  264. package/dist/components/toast.js +8 -5
  265. package/dist/components/toast.js.map +1 -1
  266. package/dist/components/toggle-group.d.ts +16 -1
  267. package/dist/components/toggle-group.js +40 -11
  268. package/dist/components/toggle-group.js.map +1 -1
  269. package/dist/components/toggle-legend.d.ts +10 -1
  270. package/dist/components/toggle-legend.js +21 -7
  271. package/dist/components/toggle-legend.js.map +1 -1
  272. package/dist/components/translation-review-parts.d.ts +4 -0
  273. package/dist/components/translation-review.d.ts +4 -0
  274. package/dist/components/translation-review.js +3 -3
  275. package/dist/components/translation-review.js.map +1 -1
  276. package/dist/components/tree-view.js +3 -2
  277. package/dist/components/tree-view.js.map +1 -1
  278. package/dist/components/treemap.d.ts +5 -2
  279. package/dist/components/treemap.js +33 -16
  280. package/dist/components/treemap.js.map +1 -1
  281. package/dist/components/ui.d.ts +8 -3
  282. package/dist/components/ui.js +202 -114
  283. package/dist/components/ui.js.map +1 -1
  284. package/dist/components/use-table-state.d.ts +1 -1
  285. package/dist/components/user-avatar.d.ts +5 -1
  286. package/dist/components/user-avatar.js +1 -1
  287. package/dist/components/user-avatar.js.map +1 -1
  288. package/dist/{data-table-labels-DUELeXpa.d.ts → data-table-labels-kpAAVi6g.d.ts} +26 -2
  289. package/dist/data-table.d.ts +1 -1
  290. package/dist/{delete-account-setting-DCFS5Vof.d.ts → delete-account-setting-BvdQdbv3.d.ts} +613 -58
  291. package/dist/demo/demo-banner.js +1 -0
  292. package/dist/demo/demo-banner.js.map +1 -1
  293. package/dist/feedback/feedback-attachment.d.ts +8 -3
  294. package/dist/feedback/feedback-context.d.ts +8 -3
  295. package/dist/feedback/feedback-crash.d.ts +8 -3
  296. package/dist/feedback/feedback-dialog.d.ts +8 -3
  297. package/dist/feedback/feedback-dialog.js +3 -3
  298. package/dist/feedback/feedback-dialog.js.map +1 -1
  299. package/dist/feedback/feedback-inbox.d.ts +8 -3
  300. package/dist/feedback/feedback-inbox.js +2 -2
  301. package/dist/feedback/feedback-inbox.js.map +1 -1
  302. package/dist/feedback/feedback-labels.d.ts +8 -3
  303. package/dist/feedback/feedback-menu.d.ts +9 -4
  304. package/dist/feedback/feedback-record.d.ts +8 -3
  305. package/dist/feedback/feedback-row-detail.d.ts +8 -3
  306. package/dist/feedback/feedback-status-undo.d.ts +8 -3
  307. package/dist/feedback/feedback-submit.d.ts +8 -3
  308. package/dist/feedback/feedback-swipe.d.ts +8 -3
  309. package/dist/feedback/feedback-table.d.ts +8 -3
  310. package/dist/feedback/feedback-thread.d.ts +8 -3
  311. package/dist/feedback/feedback-thread.js +3 -3
  312. package/dist/feedback/feedback-thread.js.map +1 -1
  313. package/dist/feedback.d.ts +8 -3
  314. package/dist/hooks/use-anchored-panel.d.ts +32 -3
  315. package/dist/hooks/use-anchored-panel.js +21 -3
  316. package/dist/hooks/use-anchored-panel.js.map +1 -1
  317. package/dist/hooks/use-breakpoint.d.ts +77 -0
  318. package/dist/hooks/use-breakpoint.js +50 -0
  319. package/dist/hooks/use-breakpoint.js.map +1 -0
  320. package/dist/hooks/use-file-drop.d.ts +8 -3
  321. package/dist/hooks/use-large-text.d.ts +29 -0
  322. package/dist/hooks/use-large-text.js +20 -0
  323. package/dist/hooks/use-large-text.js.map +1 -0
  324. package/dist/hooks/use-windowed-rows.d.ts +52 -8
  325. package/dist/hooks/use-windowed-rows.js +94 -5
  326. package/dist/hooks/use-windowed-rows.js.map +1 -1
  327. package/dist/i18n/defaults.d.ts +8 -3
  328. package/dist/i18n/defaults.js +8 -0
  329. package/dist/i18n/defaults.js.map +1 -1
  330. package/dist/i18n/german.d.ts +8 -3
  331. package/dist/i18n/german.js +91 -3
  332. package/dist/i18n/german.js.map +1 -1
  333. package/dist/i18n/kit-labels.d.ts +8 -3
  334. package/dist/i18n/kit-labels.js.map +1 -1
  335. package/dist/i18n/languages.d.ts +10 -5
  336. package/dist/i18n/locales/de-CH.d.ts +8 -3
  337. package/dist/i18n/locales/en.d.ts +8 -3
  338. package/dist/i18n/locales/es.d.ts +8 -3
  339. package/dist/i18n/locales/es.js +86 -3
  340. package/dist/i18n/locales/es.js.map +1 -1
  341. package/dist/i18n/locales/fr.d.ts +8 -3
  342. package/dist/i18n/locales/fr.js +88 -3
  343. package/dist/i18n/locales/fr.js.map +1 -1
  344. package/dist/i18n/locales/hu.d.ts +8 -3
  345. package/dist/i18n/locales/hu.js +88 -3
  346. package/dist/i18n/locales/hu.js.map +1 -1
  347. package/dist/i18n/locales/it.d.ts +8 -3
  348. package/dist/i18n/locales/it.js +89 -3
  349. package/dist/i18n/locales/it.js.map +1 -1
  350. package/dist/i18n/locales/zh.d.ts +8 -3
  351. package/dist/i18n/locales/zh.js +86 -3
  352. package/dist/i18n/locales/zh.js.map +1 -1
  353. package/dist/i18n/review.d.ts +8 -3
  354. package/dist/i18n/review.js +16 -1
  355. package/dist/i18n/review.js.map +1 -1
  356. package/dist/index.d.ts +29 -13
  357. package/dist/index.js +77 -5
  358. package/dist/index.js.map +1 -1
  359. package/dist/landing/landing-actions.d.ts +12 -5
  360. package/dist/landing/landing-actions.js +1 -1
  361. package/dist/landing/landing-actions.js.map +1 -1
  362. package/dist/landing/landing-sections.d.ts +8 -3
  363. package/dist/landing/public-header.d.ts +9 -4
  364. package/dist/landing/public-header.js +3 -3
  365. package/dist/landing/public-header.js.map +1 -1
  366. package/dist/landing/routing.d.ts +27 -9
  367. package/dist/landing/routing.js +5 -2
  368. package/dist/landing/routing.js.map +1 -1
  369. package/dist/lib/cn.js +3 -2
  370. package/dist/lib/cn.js.map +1 -1
  371. package/dist/rhf/fields.d.ts +8 -3
  372. package/dist/rhf/fields.js +1 -1
  373. package/dist/rhf/fields.js.map +1 -1
  374. package/dist/rhf/form.d.ts +8 -3
  375. package/dist/rhf/form.js +2 -2
  376. package/dist/rhf/form.js.map +1 -1
  377. package/dist/rhf.d.ts +8 -3
  378. package/dist/search/command-palette.d.ts +1 -1
  379. package/dist/search/command-palette.js +9 -8
  380. package/dist/search/command-palette.js.map +1 -1
  381. package/dist/settings/settings-labels.d.ts +8 -1
  382. package/dist/settings/settings-labels.js +7 -2
  383. package/dist/settings/settings-labels.js.map +1 -1
  384. package/dist/settings/settings-layout.js +2 -1
  385. package/dist/settings/settings-layout.js.map +1 -1
  386. package/dist/settings/settings-section.d.ts +8 -3
  387. package/dist/settings/use-account-appearance.d.ts +92 -0
  388. package/dist/settings/use-account-appearance.js +63 -0
  389. package/dist/settings/use-account-appearance.js.map +1 -0
  390. package/dist/settings/use-settings-route.d.ts +1 -1
  391. package/dist/settings/use-settings-route.js +2 -3
  392. package/dist/settings/use-settings-route.js.map +1 -1
  393. package/dist/shell/app-shell.d.ts +12 -171
  394. package/dist/shell/app-shell.js +144 -28
  395. package/dist/shell/app-shell.js.map +1 -1
  396. package/dist/shell/auth-layout.js +1 -1
  397. package/dist/shell/auth-layout.js.map +1 -1
  398. package/dist/shell/option-switcher-menu.js +1 -1
  399. package/dist/shell/option-switcher-menu.js.map +1 -1
  400. package/dist/shell/top-bar-brand.d.ts +8 -3
  401. package/dist/shell/top-bar-brand.js +3 -1
  402. package/dist/shell/top-bar-brand.js.map +1 -1
  403. package/dist/shell/topbar-action-menu.d.ts +4 -0
  404. package/dist/shell/topbar-action-menu.js +3 -3
  405. package/dist/shell/topbar-action-menu.js.map +1 -1
  406. package/dist/shell/topbar-controls.js +4 -4
  407. package/dist/shell/topbar-controls.js.map +1 -1
  408. package/dist/shell.d.ts +10 -6
  409. package/dist/shell.js.map +1 -1
  410. package/dist/theme/contrast-tokens.d.ts +41 -0
  411. package/dist/theme/contrast-tokens.js +59 -0
  412. package/dist/theme/contrast-tokens.js.map +1 -0
  413. package/dist/theme/contrast.d.ts +109 -0
  414. package/dist/theme/contrast.js +128 -0
  415. package/dist/theme/contrast.js.map +1 -0
  416. package/dist/theme/palette-presets.d.ts +12 -1
  417. package/dist/theme/palette-presets.js +9 -4
  418. package/dist/theme/palette-presets.js.map +1 -1
  419. package/dist/theme/palette-store.js.map +1 -1
  420. package/dist/theme/text-size.d.ts +157 -0
  421. package/dist/theme/text-size.js +121 -0
  422. package/dist/theme/text-size.js.map +1 -0
  423. package/dist/wizard/stepper-nav.d.ts +8 -3
  424. package/dist/wizard.d.ts +8 -3
  425. package/package.json +1 -1
  426. package/src/admin/admin-parts.ts +9 -2
  427. package/src/admin/invitations-panel.tsx +36 -29
  428. package/src/admin/user-roster.tsx +17 -72
  429. package/src/auth/auth-errors.ts +68 -7
  430. package/src/auth/reset-password-form.tsx +6 -2
  431. package/src/auth/verify-email.tsx +14 -2
  432. package/src/billing/billing-banner.tsx +205 -0
  433. package/src/billing/billing-labels.ts +224 -0
  434. package/src/billing/billing-lock.ts +75 -0
  435. package/src/billing/billing-standing.ts +72 -0
  436. package/src/billing/plan-card.tsx +458 -0
  437. package/src/billing/plan-limit-notice.tsx +145 -0
  438. package/src/billing/plan-limit.ts +53 -0
  439. package/src/billing/plan-price.ts +101 -0
  440. package/src/billing/subscription-actions.tsx +76 -0
  441. package/src/billing/subscription-status-chip.tsx +95 -0
  442. package/src/components/account-chips.tsx +36 -10
  443. package/src/components/alert-banner.tsx +11 -6
  444. package/src/components/amount-input.tsx +5 -5
  445. package/src/components/appearance-labels.ts +40 -0
  446. package/src/components/autocomplete.tsx +2 -2
  447. package/src/components/breadcrumbs.tsx +3 -3
  448. package/src/components/bulk-action-bar.tsx +11 -14
  449. package/src/components/calculator.tsx +4 -3
  450. package/src/components/calendar-heatmap.tsx +5 -5
  451. package/src/components/chart-height.ts +30 -0
  452. package/src/components/chart-zoom.tsx +6 -1
  453. package/src/components/checkbox-group.tsx +2 -2
  454. package/src/components/checkbox.tsx +62 -20
  455. package/src/components/chip.tsx +105 -24
  456. package/src/components/choice-card.tsx +15 -10
  457. package/src/components/column-mapper.tsx +1 -1
  458. package/src/components/combobox-core.tsx +8 -7
  459. package/src/components/combobox.tsx +8 -8
  460. package/src/components/confirm-dialog.tsx +20 -1
  461. package/src/components/country-select.tsx +1 -1
  462. package/src/components/currency-select.tsx +3 -3
  463. package/src/components/data-table-filter-popover.tsx +7 -1
  464. package/src/components/data-table.tsx +160 -43
  465. package/src/components/date-picker.tsx +12 -9
  466. package/src/components/description-list.tsx +2 -2
  467. package/src/components/dialog-frame.tsx +2 -1
  468. package/src/components/disclosure.tsx +3 -2
  469. package/src/components/dropdown.tsx +10 -2
  470. package/src/components/facing-pair.ts +12 -5
  471. package/src/components/field-parts.tsx +190 -7
  472. package/src/components/field-sync.tsx +17 -3
  473. package/src/components/field.tsx +2 -2
  474. package/src/components/floating-panel.tsx +7 -4
  475. package/src/components/focus-ring.ts +12 -0
  476. package/src/components/form-actions.tsx +55 -18
  477. package/src/components/full-bleed-dialog.tsx +18 -4
  478. package/src/components/image-grid.tsx +1 -1
  479. package/src/components/inline-edit-field.tsx +6 -3
  480. package/src/components/legal-page.tsx +28 -2
  481. package/src/components/legal.tsx +19 -1
  482. package/src/components/lightbox.tsx +24 -2
  483. package/src/components/line-items.tsx +7 -1
  484. package/src/components/list.tsx +36 -10
  485. package/src/components/measured-grid.tsx +49 -24
  486. package/src/components/menu-item.tsx +2 -2
  487. package/src/components/mini-calendar.tsx +8 -4
  488. package/src/components/month-picker.tsx +9 -5
  489. package/src/components/nav-pills.tsx +1 -1
  490. package/src/components/number-input.tsx +14 -7
  491. package/src/components/numpad-sheet.tsx +2 -2
  492. package/src/components/one-time-code-input.tsx +2 -2
  493. package/src/components/page-contents.tsx +2 -2
  494. package/src/components/phone-input.tsx +2 -2
  495. package/src/components/pie-chart.tsx +19 -9
  496. package/src/components/popover.tsx +22 -5
  497. package/src/components/row-actions.tsx +344 -0
  498. package/src/components/scroll-area.tsx +1 -1
  499. package/src/components/search-field.tsx +4 -2
  500. package/src/components/series-chart-budget.ts +40 -8
  501. package/src/components/series-chart-ticks.ts +10 -0
  502. package/src/components/series-chart.tsx +123 -72
  503. package/src/components/settings-fields.tsx +81 -2
  504. package/src/components/share-card.tsx +10 -0
  505. package/src/components/sign-chip.tsx +28 -4
  506. package/src/components/signature-pad.tsx +13 -7
  507. package/src/components/slider.tsx +22 -9
  508. package/src/components/sparkline.tsx +11 -3
  509. package/src/components/stat-tile.tsx +70 -14
  510. package/src/components/swipeable-row.tsx +2 -1
  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 +99 -12
  518. package/src/components/toggle-legend.tsx +53 -8
  519. package/src/components/translation-review.tsx +10 -5
  520. package/src/components/tree-view.tsx +3 -2
  521. package/src/components/treemap.tsx +27 -10
  522. package/src/components/ui.tsx +331 -145
  523. package/src/components/user-avatar.tsx +1 -1
  524. package/src/demo/demo-banner.tsx +5 -0
  525. package/src/feedback/feedback-dialog.tsx +3 -3
  526. package/src/feedback/feedback-inbox.tsx +2 -2
  527. package/src/feedback/feedback-thread.tsx +3 -3
  528. package/src/hooks/use-anchored-panel.ts +67 -5
  529. package/src/hooks/use-breakpoint.ts +121 -0
  530. package/src/hooks/use-large-text.ts +41 -0
  531. package/src/hooks/use-windowed-rows.ts +168 -12
  532. package/src/i18n/defaults.ts +8 -0
  533. package/src/i18n/german.ts +105 -1
  534. package/src/i18n/kit-labels.tsx +12 -0
  535. package/src/i18n/locales/es.ts +96 -1
  536. package/src/i18n/locales/fr.ts +100 -1
  537. package/src/i18n/locales/hu.ts +98 -1
  538. package/src/i18n/locales/it.ts +101 -1
  539. package/src/i18n/locales/zh.ts +92 -1
  540. package/src/i18n/review.ts +15 -0
  541. package/src/index.ts +82 -8
  542. package/src/landing/landing-actions.tsx +9 -5
  543. package/src/landing/public-header.tsx +4 -4
  544. package/src/landing/routing.tsx +22 -5
  545. package/src/lib/cn.ts +13 -2
  546. package/src/rhf/fields.tsx +1 -1
  547. package/src/rhf/form.tsx +2 -2
  548. package/src/search/command-palette.tsx +10 -9
  549. package/src/settings/settings-labels.ts +13 -1
  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/shell.ts +7 -1
  560. package/src/theme/contrast-tokens.ts +112 -0
  561. package/src/theme/contrast.ts +224 -0
  562. package/src/theme/palette-presets.ts +24 -4
  563. package/src/theme/palette-store.ts +6 -1
  564. package/src/theme/text-size.ts +267 -0
  565. package/tokens.css +143 -1
@@ -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
+ }
@@ -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
  <>
@@ -376,7 +381,7 @@ export function AlertBanner({
376
381
  inlineRow || strip ? "items-center" : "items-start",
377
382
  "outline-none after:absolute after:inset-0 after:content-['']",
378
383
  strip ? "after:rounded-none" : "after:rounded-md",
379
- "focus-visible:after:ring-2 focus-visible:after:ring-[var(--brand)]",
384
+ "focus-visible:after:ring-[length:var(--focus-ring-width)] focus-visible:after:ring-[var(--brand)]",
380
385
  )
381
386
  : cn(row, !inlineRow && "w-full", frame, TONE_TEXT[tone], hover, focusRing, className);
382
387
  // 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,40 @@
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
+
27
+ export const DEFAULT_APPEARANCE_LABELS: AppearanceLabels = {
28
+ textSize: "Text size",
29
+ textSizeHelp: "Larger letters, and a layout that makes room for them.",
30
+ textSizes: { normal: "Normal", large: "Large", xlarge: "Extra large" },
31
+ contrast: "Contrast",
32
+ contrastHelp: "More contrast darkens quiet text and lines, and thickens focus frames. System follows this device.",
33
+ contrastModes: { system: "System", standard: "Standard", more: "More" },
34
+ };
35
+
36
+ /** The `appearance` namespace, resolved — English, then the provider, then `labels`. For
37
+ * an app's catalogue entries and quick switches, without restating the defaults. */
38
+ export function useAppearanceLabels(labels?: Partial<AppearanceLabels>): AppearanceLabels {
39
+ return useKitLabels("appearance", DEFAULT_APPEARANCE_LABELS, labels);
40
+ }
@@ -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
  }
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
2
2
  import { Calculator as CalculatorIcon, Delete } from "lucide-react";
3
3
  import { Popover } from "./popover";
4
4
  import { cn } from "../lib/cn";
5
+ import { FIELD_TOUCH_TEXT } from "./ui";
5
6
  import { evaluateExpression, formatResult, isBareAmount, splitLeadingSign } from "../lib/calc";
6
7
  import {
7
8
  DEFAULT_CALCULATOR_LABELS,
@@ -70,7 +71,7 @@ const KEYS: Key[] = [
70
71
  ];
71
72
 
72
73
  const KEY_BASE =
73
- "flex h-9 items-center justify-center rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--border-strong)]";
74
+ "flex h-9 items-center justify-center rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-[length:var(--focus-ring-width)] focus:ring-[var(--border-strong)]";
74
75
  // Two key families, two fills: digits sit on the inset surface and darken on
75
76
  // hover, operators sit a step down on `--border` and lift toward that surface —
76
77
  // the same split `NumberPadSheet` uses for this keypad on a phone. The tokens
@@ -151,7 +152,7 @@ function CalculatorPanel({
151
152
  // is right-aligned in every script too — so both stay physical, pinned
152
153
  // with `dir="ltr"` rather than mirrored in a right-to-left form.
153
154
  dir="ltr"
154
- className="block w-full rounded-md border border-[var(--border)] bg-[var(--bg-surface)] px-2 py-1.5 text-right font-mono text-sm text-[var(--text-primary)] focus:border-[var(--border-strong)] focus:ring-[var(--border-strong)]"
155
+ className={cn("block w-full rounded-md border border-[var(--border)] bg-[var(--bg-surface)] px-2 py-1.5 text-right font-mono text-sm text-[var(--text-primary)] focus:border-[var(--border-strong)] focus:ring-[var(--border-strong)]", FIELD_TOUCH_TEXT)}
155
156
  />
156
157
  <div dir="ltr" className="h-4 pr-1 text-right font-mono text-xs text-[var(--text-placeholder)]">
157
158
  {result !== null && formatResult(result) !== text.trim() ? `= ${formatResult(result)}` : ""}
@@ -231,7 +232,7 @@ export function CalculatorButton({
231
232
  const labels = useKitLabels("calculator", DEFAULT_CALCULATOR_LABELS, fromProps);
232
233
  return (
233
234
  <Popover
234
- width={224}
235
+ width="14rem"
235
236
  labels={{ panel: labels.panel }}
236
237
  trigger={({ open, toggle, ref }) => (
237
238
  <button