@eifi1/ui-kit 0.31.1 → 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 (538) 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/invitations-panel.d.ts +8 -3
  5. package/dist/admin/invitations-panel.js +29 -26
  6. package/dist/admin/invitations-panel.js.map +1 -1
  7. package/dist/admin/reviewer-scope-editor.d.ts +8 -3
  8. package/dist/admin/role-select.d.ts +10 -5
  9. package/dist/admin/transfer-ownership-dialog.d.ts +8 -3
  10. package/dist/admin/user-roster.d.ts +10 -5
  11. package/dist/admin/user-roster.js +8 -47
  12. package/dist/admin/user-roster.js.map +1 -1
  13. package/dist/auth/auth-errors.d.ts +43 -8
  14. package/dist/auth/auth-errors.js +24 -1
  15. package/dist/auth/auth-errors.js.map +1 -1
  16. package/dist/auth/register-form.d.ts +8 -3
  17. package/dist/billing/billing-banner.d.ts +184 -0
  18. package/dist/billing/billing-banner.js +98 -0
  19. package/dist/billing/billing-banner.js.map +1 -0
  20. package/dist/billing/billing-labels.d.ts +100 -0
  21. package/dist/billing/billing-labels.js +74 -0
  22. package/dist/billing/billing-labels.js.map +1 -0
  23. package/dist/billing/billing-lock.d.ts +158 -0
  24. package/dist/billing/billing-lock.js +17 -0
  25. package/dist/billing/billing-lock.js.map +1 -0
  26. package/dist/billing/billing-standing.d.ts +149 -0
  27. package/dist/billing/billing-standing.js +28 -0
  28. package/dist/billing/billing-standing.js.map +1 -0
  29. package/dist/billing/plan-card.d.ts +248 -0
  30. package/dist/billing/plan-card.js +248 -0
  31. package/dist/billing/plan-card.js.map +1 -0
  32. package/dist/billing/plan-limit-notice.d.ts +156 -0
  33. package/dist/billing/plan-limit-notice.js +76 -0
  34. package/dist/billing/plan-limit-notice.js.map +1 -0
  35. package/dist/billing/plan-limit.d.ts +34 -0
  36. package/dist/billing/plan-limit.js +20 -0
  37. package/dist/billing/plan-limit.js.map +1 -0
  38. package/dist/billing/plan-price.d.ts +61 -0
  39. package/dist/billing/plan-price.js +45 -0
  40. package/dist/billing/plan-price.js.map +1 -0
  41. package/dist/billing/subscription-actions.d.ts +133 -0
  42. package/dist/billing/subscription-actions.js +28 -0
  43. package/dist/billing/subscription-actions.js.map +1 -0
  44. package/dist/billing/subscription-status-chip.d.ts +149 -0
  45. package/dist/billing/subscription-status-chip.js +48 -0
  46. package/dist/billing/subscription-status-chip.js.map +1 -0
  47. package/dist/chart.d.ts +9 -3
  48. package/dist/components/account-chips.d.ts +16 -4
  49. package/dist/components/account-chips.js +21 -3
  50. package/dist/components/account-chips.js.map +1 -1
  51. package/dist/components/alert-banner.d.ts +6 -1
  52. package/dist/components/alert-banner.js +4 -3
  53. package/dist/components/alert-banner.js.map +1 -1
  54. package/dist/components/amount-input.d.ts +8 -3
  55. package/dist/components/amount-input.js +5 -5
  56. package/dist/components/amount-input.js.map +1 -1
  57. package/dist/components/appearance-labels.d.ts +32 -0
  58. package/dist/components/appearance-labels.js +18 -0
  59. package/dist/components/appearance-labels.js.map +1 -0
  60. package/dist/components/autocomplete.js +2 -2
  61. package/dist/components/autocomplete.js.map +1 -1
  62. package/dist/components/breadcrumbs.js +3 -2
  63. package/dist/components/breadcrumbs.js.map +1 -1
  64. package/dist/components/bulk-action-bar.d.ts +2 -2
  65. package/dist/components/bulk-action-bar.js +7 -12
  66. package/dist/components/bulk-action-bar.js.map +1 -1
  67. package/dist/components/button-group.d.ts +8 -3
  68. package/dist/components/calculator.d.ts +8 -3
  69. package/dist/components/calculator.js +4 -3
  70. package/dist/components/calculator.js.map +1 -1
  71. package/dist/components/calendar-heatmap.js +5 -5
  72. package/dist/components/calendar-heatmap.js.map +1 -1
  73. package/dist/components/chart-height.d.ts +23 -0
  74. package/dist/components/chart-height.js +15 -0
  75. package/dist/components/chart-height.js.map +1 -0
  76. package/dist/components/chart-zoom.js +6 -1
  77. package/dist/components/chart-zoom.js.map +1 -1
  78. package/dist/components/checkbox-group.js +2 -2
  79. package/dist/components/checkbox-group.js.map +1 -1
  80. package/dist/components/checkbox.d.ts +10 -0
  81. package/dist/components/checkbox.js +25 -10
  82. package/dist/components/checkbox.js.map +1 -1
  83. package/dist/components/chip.d.ts +19 -3
  84. package/dist/components/chip.js +47 -21
  85. package/dist/components/chip.js.map +1 -1
  86. package/dist/components/choice-card.d.ts +1 -1
  87. package/dist/components/choice-card.js +8 -7
  88. package/dist/components/choice-card.js.map +1 -1
  89. package/dist/components/column-mapper.js +1 -1
  90. package/dist/components/column-mapper.js.map +1 -1
  91. package/dist/components/combobox-core.js +8 -7
  92. package/dist/components/combobox-core.js.map +1 -1
  93. package/dist/components/combobox.js +8 -8
  94. package/dist/components/combobox.js.map +1 -1
  95. package/dist/components/confirm-dialog.d.ts +8 -3
  96. package/dist/components/copy-button.d.ts +10 -5
  97. package/dist/components/country-select.js +1 -1
  98. package/dist/components/country-select.js.map +1 -1
  99. package/dist/components/currency-select.js +3 -3
  100. package/dist/components/currency-select.js.map +1 -1
  101. package/dist/components/danger-confirm.d.ts +8 -3
  102. package/dist/components/data-table-cells.d.ts +1 -1
  103. package/dist/components/data-table-filter-popover.d.ts +1 -1
  104. package/dist/components/data-table-filter-popover.js +4 -1
  105. package/dist/components/data-table-filter-popover.js.map +1 -1
  106. package/dist/components/data-table-filters.d.ts +1 -1
  107. package/dist/components/data-table-labels.d.ts +1 -1
  108. package/dist/components/data-table-pagination.d.ts +1 -1
  109. package/dist/components/data-table.d.ts +1 -1
  110. package/dist/components/data-table.js +123 -52
  111. package/dist/components/data-table.js.map +1 -1
  112. package/dist/components/date-picker.d.ts +1 -1
  113. package/dist/components/date-picker.js +7 -5
  114. package/dist/components/date-picker.js.map +1 -1
  115. package/dist/components/description-list.js +2 -2
  116. package/dist/components/description-list.js.map +1 -1
  117. package/dist/components/dialog-frame.js +2 -1
  118. package/dist/components/dialog-frame.js.map +1 -1
  119. package/dist/components/disclosure.js +3 -2
  120. package/dist/components/disclosure.js.map +1 -1
  121. package/dist/components/dropdown.d.ts +1 -1
  122. package/dist/components/dropdown.js +7 -1
  123. package/dist/components/dropdown.js.map +1 -1
  124. package/dist/components/facing-pair.d.ts +19 -6
  125. package/dist/components/facing-pair.js +3 -2
  126. package/dist/components/facing-pair.js.map +1 -1
  127. package/dist/components/field-parts.d.ts +102 -6
  128. package/dist/components/field-parts.js +81 -6
  129. package/dist/components/field-parts.js.map +1 -1
  130. package/dist/components/field-sync.d.ts +4 -1
  131. package/dist/components/field-sync.js +12 -2
  132. package/dist/components/field-sync.js.map +1 -1
  133. package/dist/components/field.js +2 -2
  134. package/dist/components/field.js.map +1 -1
  135. package/dist/components/file-button.d.ts +8 -3
  136. package/dist/components/file-dropzone.d.ts +8 -3
  137. package/dist/components/floating-panel.js +7 -4
  138. package/dist/components/floating-panel.js.map +1 -1
  139. package/dist/components/focus-ring.d.ts +12 -0
  140. package/dist/components/focus-ring.js +8 -0
  141. package/dist/components/focus-ring.js.map +1 -0
  142. package/dist/components/form-actions.d.ts +8 -3
  143. package/dist/components/form-actions.js +33 -19
  144. package/dist/components/form-actions.js.map +1 -1
  145. package/dist/components/full-bleed-dialog.d.ts +11 -1
  146. package/dist/components/full-bleed-dialog.js +3 -1
  147. package/dist/components/full-bleed-dialog.js.map +1 -1
  148. package/dist/components/iban-input.d.ts +8 -3
  149. package/dist/components/image-grid.js +1 -1
  150. package/dist/components/image-grid.js.map +1 -1
  151. package/dist/components/inline-edit-field.js +6 -3
  152. package/dist/components/inline-edit-field.js.map +1 -1
  153. package/dist/components/language-select.d.ts +8 -3
  154. package/dist/components/legal-page.d.ts +26 -5
  155. package/dist/components/legal-page.js +3 -1
  156. package/dist/components/legal-page.js.map +1 -1
  157. package/dist/components/legal.d.ts +8 -3
  158. package/dist/components/legal.js +2 -1
  159. package/dist/components/legal.js.map +1 -1
  160. package/dist/components/lightbox.js +24 -2
  161. package/dist/components/lightbox.js.map +1 -1
  162. package/dist/components/line-items.js +2 -1
  163. package/dist/components/line-items.js.map +1 -1
  164. package/dist/components/list.d.ts +5 -0
  165. package/dist/components/list.js +13 -9
  166. package/dist/components/list.js.map +1 -1
  167. package/dist/components/measured-grid.d.ts +3 -1
  168. package/dist/components/measured-grid.js +38 -20
  169. package/dist/components/measured-grid.js.map +1 -1
  170. package/dist/components/menu-item.js +2 -1
  171. package/dist/components/menu-item.js.map +1 -1
  172. package/dist/components/mini-calendar.js +8 -4
  173. package/dist/components/mini-calendar.js.map +1 -1
  174. package/dist/components/money-field.d.ts +8 -3
  175. package/dist/components/month-picker.js +9 -5
  176. package/dist/components/month-picker.js.map +1 -1
  177. package/dist/components/nav-pills.js +1 -1
  178. package/dist/components/nav-pills.js.map +1 -1
  179. package/dist/components/number-field.d.ts +8 -3
  180. package/dist/components/number-input.d.ts +11 -4
  181. package/dist/components/number-input.js +8 -6
  182. package/dist/components/number-input.js.map +1 -1
  183. package/dist/components/numpad-sheet.d.ts +8 -3
  184. package/dist/components/numpad-sheet.js +2 -1
  185. package/dist/components/numpad-sheet.js.map +1 -1
  186. package/dist/components/one-time-code-input.js +2 -2
  187. package/dist/components/one-time-code-input.js.map +1 -1
  188. package/dist/components/page-contents.js +2 -2
  189. package/dist/components/page-contents.js.map +1 -1
  190. package/dist/components/phone-input.d.ts +8 -3
  191. package/dist/components/phone-input.js +2 -2
  192. package/dist/components/phone-input.js.map +1 -1
  193. package/dist/components/pie-chart.d.ts +8 -2
  194. package/dist/components/pie-chart.js +11 -7
  195. package/dist/components/pie-chart.js.map +1 -1
  196. package/dist/components/popover.d.ts +9 -1
  197. package/dist/components/popover.js +8 -4
  198. package/dist/components/popover.js.map +1 -1
  199. package/dist/components/row-actions.d.ts +100 -0
  200. package/dist/components/row-actions.js +165 -0
  201. package/dist/components/row-actions.js.map +1 -0
  202. package/dist/components/scroll-area.js +1 -1
  203. package/dist/components/scroll-area.js.map +1 -1
  204. package/dist/components/search-field.js +3 -2
  205. package/dist/components/search-field.js.map +1 -1
  206. package/dist/components/series-chart-budget.d.ts +30 -7
  207. package/dist/components/series-chart-budget.js +12 -4
  208. package/dist/components/series-chart-budget.js.map +1 -1
  209. package/dist/components/series-chart-ticks.d.ts +7 -1
  210. package/dist/components/series-chart-ticks.js +6 -0
  211. package/dist/components/series-chart-ticks.js.map +1 -1
  212. package/dist/components/series-chart.d.ts +58 -28
  213. package/dist/components/series-chart.js +42 -32
  214. package/dist/components/series-chart.js.map +1 -1
  215. package/dist/components/settings-fields.d.ts +51 -6
  216. package/dist/components/settings-fields.js +37 -0
  217. package/dist/components/settings-fields.js.map +1 -1
  218. package/dist/components/share-card.d.ts +11 -6
  219. package/dist/components/share-card.js +2 -0
  220. package/dist/components/share-card.js.map +1 -1
  221. package/dist/components/sign-chip.d.ts +4 -0
  222. package/dist/components/sign-chip.js +17 -4
  223. package/dist/components/sign-chip.js.map +1 -1
  224. package/dist/components/signature-pad.d.ts +3 -1
  225. package/dist/components/signature-pad.js +8 -5
  226. package/dist/components/signature-pad.js.map +1 -1
  227. package/dist/components/slider.js +7 -6
  228. package/dist/components/slider.js.map +1 -1
  229. package/dist/components/sparkline.d.ts +5 -1
  230. package/dist/components/sparkline.js +4 -2
  231. package/dist/components/sparkline.js.map +1 -1
  232. package/dist/components/stat-tile.d.ts +17 -1
  233. package/dist/components/stat-tile.js +48 -20
  234. package/dist/components/stat-tile.js.map +1 -1
  235. package/dist/components/status-dot.d.ts +4 -0
  236. package/dist/components/swipeable-row.js +2 -1
  237. package/dist/components/swipeable-row.js.map +1 -1
  238. package/dist/components/switch.d.ts +21 -7
  239. package/dist/components/switch.js +24 -11
  240. package/dist/components/switch.js.map +1 -1
  241. package/dist/components/table.js +2 -2
  242. package/dist/components/table.js.map +1 -1
  243. package/dist/components/text-link.d.ts +8 -3
  244. package/dist/components/text-link.js +1 -1
  245. package/dist/components/text-link.js.map +1 -1
  246. package/dist/components/text.d.ts +7 -2
  247. package/dist/components/text.js +5 -5
  248. package/dist/components/text.js.map +1 -1
  249. package/dist/components/tile-radio.js +2 -1
  250. package/dist/components/tile-radio.js.map +1 -1
  251. package/dist/components/time-input.d.ts +8 -3
  252. package/dist/components/toast.d.ts +18 -2
  253. package/dist/components/toast.js +8 -5
  254. package/dist/components/toast.js.map +1 -1
  255. package/dist/components/toggle-group.d.ts +16 -1
  256. package/dist/components/toggle-group.js +40 -11
  257. package/dist/components/toggle-group.js.map +1 -1
  258. package/dist/components/toggle-legend.d.ts +10 -1
  259. package/dist/components/toggle-legend.js +21 -7
  260. package/dist/components/toggle-legend.js.map +1 -1
  261. package/dist/components/translation-review-parts.d.ts +4 -0
  262. package/dist/components/translation-review.d.ts +4 -0
  263. package/dist/components/translation-review.js +3 -3
  264. package/dist/components/translation-review.js.map +1 -1
  265. package/dist/components/tree-view.js +3 -2
  266. package/dist/components/tree-view.js.map +1 -1
  267. package/dist/components/treemap.d.ts +5 -2
  268. package/dist/components/treemap.js +33 -16
  269. package/dist/components/treemap.js.map +1 -1
  270. package/dist/components/ui.d.ts +8 -3
  271. package/dist/components/ui.js +202 -114
  272. package/dist/components/ui.js.map +1 -1
  273. package/dist/components/use-table-state.d.ts +1 -1
  274. package/dist/components/user-avatar.d.ts +5 -1
  275. package/dist/components/user-avatar.js +1 -1
  276. package/dist/components/user-avatar.js.map +1 -1
  277. package/dist/{data-table-labels-DUELeXpa.d.ts → data-table-labels-kpAAVi6g.d.ts} +26 -2
  278. package/dist/data-table.d.ts +1 -1
  279. package/dist/{delete-account-setting-CpIhzxxZ.d.ts → delete-account-setting-BvdQdbv3.d.ts} +605 -58
  280. package/dist/demo/demo-banner.js +1 -0
  281. package/dist/demo/demo-banner.js.map +1 -1
  282. package/dist/feedback/feedback-attachment.d.ts +8 -3
  283. package/dist/feedback/feedback-context.d.ts +8 -3
  284. package/dist/feedback/feedback-crash.d.ts +8 -3
  285. package/dist/feedback/feedback-dialog.d.ts +8 -3
  286. package/dist/feedback/feedback-dialog.js +3 -3
  287. package/dist/feedback/feedback-dialog.js.map +1 -1
  288. package/dist/feedback/feedback-inbox.d.ts +8 -3
  289. package/dist/feedback/feedback-inbox.js +2 -2
  290. package/dist/feedback/feedback-inbox.js.map +1 -1
  291. package/dist/feedback/feedback-labels.d.ts +8 -3
  292. package/dist/feedback/feedback-menu.d.ts +9 -4
  293. package/dist/feedback/feedback-record.d.ts +8 -3
  294. package/dist/feedback/feedback-row-detail.d.ts +8 -3
  295. package/dist/feedback/feedback-status-undo.d.ts +8 -3
  296. package/dist/feedback/feedback-submit.d.ts +8 -3
  297. package/dist/feedback/feedback-swipe.d.ts +8 -3
  298. package/dist/feedback/feedback-table.d.ts +8 -3
  299. package/dist/feedback/feedback-thread.d.ts +8 -3
  300. package/dist/feedback/feedback-thread.js +3 -3
  301. package/dist/feedback/feedback-thread.js.map +1 -1
  302. package/dist/feedback.d.ts +8 -3
  303. package/dist/hooks/use-anchored-panel.d.ts +32 -3
  304. package/dist/hooks/use-anchored-panel.js +21 -3
  305. package/dist/hooks/use-anchored-panel.js.map +1 -1
  306. package/dist/hooks/use-breakpoint.d.ts +77 -0
  307. package/dist/hooks/use-breakpoint.js +50 -0
  308. package/dist/hooks/use-breakpoint.js.map +1 -0
  309. package/dist/hooks/use-file-drop.d.ts +8 -3
  310. package/dist/hooks/use-large-text.d.ts +29 -0
  311. package/dist/hooks/use-large-text.js +20 -0
  312. package/dist/hooks/use-large-text.js.map +1 -0
  313. package/dist/hooks/use-windowed-rows.d.ts +52 -8
  314. package/dist/hooks/use-windowed-rows.js +94 -5
  315. package/dist/hooks/use-windowed-rows.js.map +1 -1
  316. package/dist/i18n/defaults.d.ts +8 -3
  317. package/dist/i18n/defaults.js +8 -0
  318. package/dist/i18n/defaults.js.map +1 -1
  319. package/dist/i18n/german.d.ts +8 -3
  320. package/dist/i18n/german.js +89 -2
  321. package/dist/i18n/german.js.map +1 -1
  322. package/dist/i18n/kit-labels.d.ts +8 -3
  323. package/dist/i18n/kit-labels.js.map +1 -1
  324. package/dist/i18n/languages.d.ts +10 -5
  325. package/dist/i18n/locales/de-CH.d.ts +8 -3
  326. package/dist/i18n/locales/en.d.ts +8 -3
  327. package/dist/i18n/locales/es.d.ts +8 -3
  328. package/dist/i18n/locales/es.js +84 -2
  329. package/dist/i18n/locales/es.js.map +1 -1
  330. package/dist/i18n/locales/fr.d.ts +8 -3
  331. package/dist/i18n/locales/fr.js +86 -2
  332. package/dist/i18n/locales/fr.js.map +1 -1
  333. package/dist/i18n/locales/hu.d.ts +8 -3
  334. package/dist/i18n/locales/hu.js +86 -2
  335. package/dist/i18n/locales/hu.js.map +1 -1
  336. package/dist/i18n/locales/it.d.ts +8 -3
  337. package/dist/i18n/locales/it.js +87 -2
  338. package/dist/i18n/locales/it.js.map +1 -1
  339. package/dist/i18n/locales/zh.d.ts +8 -3
  340. package/dist/i18n/locales/zh.js +84 -2
  341. package/dist/i18n/locales/zh.js.map +1 -1
  342. package/dist/i18n/review.d.ts +8 -3
  343. package/dist/i18n/review.js +15 -1
  344. package/dist/i18n/review.js.map +1 -1
  345. package/dist/index.d.ts +27 -11
  346. package/dist/index.js +75 -4
  347. package/dist/index.js.map +1 -1
  348. package/dist/landing/landing-actions.d.ts +8 -3
  349. package/dist/landing/landing-sections.d.ts +8 -3
  350. package/dist/landing/public-header.d.ts +9 -4
  351. package/dist/landing/public-header.js +3 -3
  352. package/dist/landing/public-header.js.map +1 -1
  353. package/dist/landing/routing.d.ts +8 -3
  354. package/dist/lib/cn.js +3 -2
  355. package/dist/lib/cn.js.map +1 -1
  356. package/dist/rhf/fields.d.ts +8 -3
  357. package/dist/rhf/fields.js +1 -1
  358. package/dist/rhf/fields.js.map +1 -1
  359. package/dist/rhf/form.d.ts +8 -3
  360. package/dist/rhf/form.js +2 -2
  361. package/dist/rhf/form.js.map +1 -1
  362. package/dist/rhf.d.ts +8 -3
  363. package/dist/search/command-palette.d.ts +1 -1
  364. package/dist/search/command-palette.js +9 -8
  365. package/dist/search/command-palette.js.map +1 -1
  366. package/dist/settings/settings-layout.js +2 -1
  367. package/dist/settings/settings-layout.js.map +1 -1
  368. package/dist/settings/settings-section.d.ts +8 -3
  369. package/dist/settings/use-account-appearance.d.ts +92 -0
  370. package/dist/settings/use-account-appearance.js +63 -0
  371. package/dist/settings/use-account-appearance.js.map +1 -0
  372. package/dist/settings/use-settings-route.d.ts +1 -1
  373. package/dist/settings/use-settings-route.js +2 -3
  374. package/dist/settings/use-settings-route.js.map +1 -1
  375. package/dist/shell/app-shell.d.ts +12 -171
  376. package/dist/shell/app-shell.js +144 -28
  377. package/dist/shell/app-shell.js.map +1 -1
  378. package/dist/shell/auth-layout.js +1 -1
  379. package/dist/shell/auth-layout.js.map +1 -1
  380. package/dist/shell/option-switcher-menu.js +1 -1
  381. package/dist/shell/option-switcher-menu.js.map +1 -1
  382. package/dist/shell/top-bar-brand.d.ts +8 -3
  383. package/dist/shell/top-bar-brand.js +3 -1
  384. package/dist/shell/top-bar-brand.js.map +1 -1
  385. package/dist/shell/topbar-action-menu.d.ts +4 -0
  386. package/dist/shell/topbar-action-menu.js +3 -3
  387. package/dist/shell/topbar-action-menu.js.map +1 -1
  388. package/dist/shell/topbar-controls.js +4 -4
  389. package/dist/shell/topbar-controls.js.map +1 -1
  390. package/dist/shell.d.ts +9 -5
  391. package/dist/theme/contrast-tokens.d.ts +41 -0
  392. package/dist/theme/contrast-tokens.js +59 -0
  393. package/dist/theme/contrast-tokens.js.map +1 -0
  394. package/dist/theme/contrast.d.ts +109 -0
  395. package/dist/theme/contrast.js +128 -0
  396. package/dist/theme/contrast.js.map +1 -0
  397. package/dist/theme/palette-presets.d.ts +12 -1
  398. package/dist/theme/palette-presets.js +9 -4
  399. package/dist/theme/palette-presets.js.map +1 -1
  400. package/dist/theme/palette-store.js.map +1 -1
  401. package/dist/theme/text-size.d.ts +157 -0
  402. package/dist/theme/text-size.js +121 -0
  403. package/dist/theme/text-size.js.map +1 -0
  404. package/dist/wizard/stepper-nav.d.ts +8 -3
  405. package/dist/wizard.d.ts +8 -3
  406. package/package.json +1 -1
  407. package/src/admin/invitations-panel.tsx +36 -29
  408. package/src/admin/user-roster.tsx +17 -72
  409. package/src/auth/auth-errors.ts +68 -7
  410. package/src/billing/billing-banner.tsx +205 -0
  411. package/src/billing/billing-labels.ts +224 -0
  412. package/src/billing/billing-lock.ts +75 -0
  413. package/src/billing/billing-standing.ts +72 -0
  414. package/src/billing/plan-card.tsx +458 -0
  415. package/src/billing/plan-limit-notice.tsx +145 -0
  416. package/src/billing/plan-limit.ts +53 -0
  417. package/src/billing/plan-price.ts +101 -0
  418. package/src/billing/subscription-actions.tsx +76 -0
  419. package/src/billing/subscription-status-chip.tsx +95 -0
  420. package/src/components/account-chips.tsx +36 -10
  421. package/src/components/alert-banner.tsx +11 -6
  422. package/src/components/amount-input.tsx +5 -5
  423. package/src/components/appearance-labels.ts +40 -0
  424. package/src/components/autocomplete.tsx +2 -2
  425. package/src/components/breadcrumbs.tsx +3 -3
  426. package/src/components/bulk-action-bar.tsx +11 -14
  427. package/src/components/calculator.tsx +4 -3
  428. package/src/components/calendar-heatmap.tsx +5 -5
  429. package/src/components/chart-height.ts +30 -0
  430. package/src/components/chart-zoom.tsx +6 -1
  431. package/src/components/checkbox-group.tsx +2 -2
  432. package/src/components/checkbox.tsx +62 -20
  433. package/src/components/chip.tsx +105 -24
  434. package/src/components/choice-card.tsx +15 -10
  435. package/src/components/column-mapper.tsx +1 -1
  436. package/src/components/combobox-core.tsx +8 -7
  437. package/src/components/combobox.tsx +8 -8
  438. package/src/components/country-select.tsx +1 -1
  439. package/src/components/currency-select.tsx +3 -3
  440. package/src/components/data-table-filter-popover.tsx +7 -1
  441. package/src/components/data-table.tsx +160 -43
  442. package/src/components/date-picker.tsx +12 -9
  443. package/src/components/description-list.tsx +2 -2
  444. package/src/components/dialog-frame.tsx +2 -1
  445. package/src/components/disclosure.tsx +3 -2
  446. package/src/components/dropdown.tsx +10 -2
  447. package/src/components/facing-pair.ts +12 -5
  448. package/src/components/field-parts.tsx +190 -7
  449. package/src/components/field-sync.tsx +17 -3
  450. package/src/components/field.tsx +2 -2
  451. package/src/components/floating-panel.tsx +7 -4
  452. package/src/components/focus-ring.ts +12 -0
  453. package/src/components/form-actions.tsx +55 -18
  454. package/src/components/full-bleed-dialog.tsx +18 -4
  455. package/src/components/image-grid.tsx +1 -1
  456. package/src/components/inline-edit-field.tsx +6 -3
  457. package/src/components/legal-page.tsx +28 -2
  458. package/src/components/legal.tsx +19 -1
  459. package/src/components/lightbox.tsx +24 -2
  460. package/src/components/line-items.tsx +7 -1
  461. package/src/components/list.tsx +36 -10
  462. package/src/components/measured-grid.tsx +49 -24
  463. package/src/components/menu-item.tsx +2 -2
  464. package/src/components/mini-calendar.tsx +8 -4
  465. package/src/components/month-picker.tsx +9 -5
  466. package/src/components/nav-pills.tsx +1 -1
  467. package/src/components/number-input.tsx +14 -7
  468. package/src/components/numpad-sheet.tsx +2 -2
  469. package/src/components/one-time-code-input.tsx +2 -2
  470. package/src/components/page-contents.tsx +2 -2
  471. package/src/components/phone-input.tsx +2 -2
  472. package/src/components/pie-chart.tsx +19 -9
  473. package/src/components/popover.tsx +22 -5
  474. package/src/components/row-actions.tsx +344 -0
  475. package/src/components/scroll-area.tsx +1 -1
  476. package/src/components/search-field.tsx +4 -2
  477. package/src/components/series-chart-budget.ts +40 -8
  478. package/src/components/series-chart-ticks.ts +10 -0
  479. package/src/components/series-chart.tsx +123 -72
  480. package/src/components/settings-fields.tsx +81 -2
  481. package/src/components/share-card.tsx +10 -0
  482. package/src/components/sign-chip.tsx +28 -4
  483. package/src/components/signature-pad.tsx +13 -7
  484. package/src/components/slider.tsx +22 -9
  485. package/src/components/sparkline.tsx +11 -3
  486. package/src/components/stat-tile.tsx +70 -14
  487. package/src/components/swipeable-row.tsx +2 -1
  488. package/src/components/switch.tsx +57 -23
  489. package/src/components/table.tsx +2 -2
  490. package/src/components/text-link.tsx +1 -1
  491. package/src/components/text.tsx +11 -6
  492. package/src/components/tile-radio.tsx +4 -1
  493. package/src/components/toast.tsx +27 -7
  494. package/src/components/toggle-group.tsx +99 -12
  495. package/src/components/toggle-legend.tsx +53 -8
  496. package/src/components/translation-review.tsx +10 -5
  497. package/src/components/tree-view.tsx +3 -2
  498. package/src/components/treemap.tsx +27 -10
  499. package/src/components/ui.tsx +331 -145
  500. package/src/components/user-avatar.tsx +1 -1
  501. package/src/demo/demo-banner.tsx +5 -0
  502. package/src/feedback/feedback-dialog.tsx +3 -3
  503. package/src/feedback/feedback-inbox.tsx +2 -2
  504. package/src/feedback/feedback-thread.tsx +3 -3
  505. package/src/hooks/use-anchored-panel.ts +67 -5
  506. package/src/hooks/use-breakpoint.ts +121 -0
  507. package/src/hooks/use-large-text.ts +41 -0
  508. package/src/hooks/use-windowed-rows.ts +168 -12
  509. package/src/i18n/defaults.ts +8 -0
  510. package/src/i18n/german.ts +103 -0
  511. package/src/i18n/kit-labels.tsx +12 -0
  512. package/src/i18n/locales/es.ts +94 -0
  513. package/src/i18n/locales/fr.ts +98 -0
  514. package/src/i18n/locales/hu.ts +96 -0
  515. package/src/i18n/locales/it.ts +99 -0
  516. package/src/i18n/locales/zh.ts +90 -0
  517. package/src/i18n/review.ts +14 -0
  518. package/src/index.ts +74 -6
  519. package/src/landing/public-header.tsx +4 -4
  520. package/src/lib/cn.ts +13 -2
  521. package/src/rhf/fields.tsx +1 -1
  522. package/src/rhf/form.tsx +2 -2
  523. package/src/search/command-palette.tsx +10 -9
  524. package/src/settings/settings-layout.tsx +2 -1
  525. package/src/settings/use-account-appearance.ts +148 -0
  526. package/src/settings/use-settings-route.ts +3 -4
  527. package/src/shell/app-shell.tsx +278 -54
  528. package/src/shell/auth-layout.tsx +1 -1
  529. package/src/shell/option-switcher-menu.tsx +1 -1
  530. package/src/shell/top-bar-brand.tsx +3 -1
  531. package/src/shell/topbar-action-menu.tsx +3 -3
  532. package/src/shell/topbar-controls.tsx +4 -4
  533. package/src/theme/contrast-tokens.ts +112 -0
  534. package/src/theme/contrast.ts +224 -0
  535. package/src/theme/palette-presets.ts +24 -4
  536. package/src/theme/palette-store.ts +6 -1
  537. package/src/theme/text-size.ts +267 -0
  538. package/tokens.css +143 -1
@@ -5,7 +5,16 @@ import { horizontalStep } from "../lib/direction";
5
5
  import { FIELD_INVALID, FloatingField, Label } from "./ui";
6
6
  import { Tooltip } from "./tooltip";
7
7
  import { useCommitReason } from "./write-lock";
8
- import { hasContent, LabelStrip } from "./field-parts";
8
+ import {
9
+ DISABLED_REASON_LINE_CLASS,
10
+ FIELD_CAPTION_CLASS,
11
+ hasContent,
12
+ LabelStrip,
13
+ useDisabledReasonLine,
14
+ useInlineHint,
15
+ type DisabledReasonDisplay,
16
+ } from "./field-parts";
17
+ import { FOCUS_RING_WIDTH } from "./focus-ring";
9
18
 
10
19
  export interface ToggleOption<T extends string> {
11
20
  value: T;
@@ -36,6 +45,11 @@ export interface ToggleGroupBaseProps<T extends string>
36
45
  * whole ("Bewegung", not "Beweg…"), at the price of a taller group on a narrow
37
46
  * screen (lenkbank L4: five signal types on a 390px control page). From the width
38
47
  * where they fit, both look the same.
48
+ *
49
+ * Since 0.32 a group in the field chrome (`label`, the default placement) with four or
50
+ * more options wraps at Large and Extra large under `"truncate"` too, inside its frame:
51
+ * the type is bigger there and the field would otherwise run past a phone's edge
52
+ * (docs/text-size-harmonization.md §4). The keyboard is the same either way.
39
53
  */
40
54
  overflow?: "truncate" | "wrap";
41
55
  /**
@@ -136,6 +150,12 @@ export interface ToggleGroupBaseProps<T extends string>
136
150
  * Wins over `disabled`, as on Button: passing both keeps the group reachable.
137
151
  */
138
152
  disabledReason?: ReactNode;
153
+ /**
154
+ * Where `disabledReason` shows (0.32, §4 "No fact only in a tooltip"): by default, at
155
+ * Large and on a touch screen, as a line under the group (where its caption goes), and
156
+ * in the tooltip over the segments otherwise. See {@link DisabledReasonDisplay}.
157
+ */
158
+ disabledReasonDisplay?: DisabledReasonDisplay;
139
159
  /**
140
160
  * This group COMMITS — choosing an option saves it. Under a locked
141
161
  * {@link WriteLockProvider} it takes the `disabledReason` path with the lock's
@@ -151,6 +171,11 @@ export interface ToggleGroupBaseProps<T extends string>
151
171
  * The field chrome's vertical geometry — keksdose K1, the kit reintroducing feedback
152
172
  * #117 that keksdose's hand-built chrome had fixed.
153
173
  *
174
+ * In px at Normal, as measured; since 0.32 every term but the two borders is rem
175
+ * (§3.2), so the sum stays a labelled Select's at 125 and 150 % too — the Select's own
176
+ * `pt-4 pb-1` and 1.25rem line grow by the same factor (52 px at Large, 62 at Extra
177
+ * large). The md line was `leading-[18px]` and is `leading-[1.125rem]`.
178
+ *
154
179
  * The label is the field's static label: `top-1` and 11px in a `leading-tight` line, so
155
180
  * its line box runs from 4px to 17.75px. Until 0.22 the chrome was `pt-4` over a 20px
156
181
  * (`leading-5`) segment, so the ACTIVE segment's fill — painted from the top of the
@@ -168,7 +193,31 @@ export interface ToggleGroupBaseProps<T extends string>
168
193
  * md: 1 + 20 + 18 + 2 + 1 = 42 sm: 1 + 20 + 16 + 4 + 1 = 42
169
194
  */
170
195
  const CHROME_PAD: Record<"sm" | "md", string> = { md: "pt-5 pb-0.5", sm: "pt-5 pb-1" };
171
- const CHROME_SEGMENT: Record<"sm" | "md", string> = { md: "py-0 leading-[18px]", sm: "py-0 leading-4" };
196
+ const CHROME_SEGMENT: Record<"sm" | "md", string> = { md: "py-0 leading-[1.125rem]", sm: "py-0 leading-4" };
197
+
198
+ /**
199
+ * A field of four or more options at Large and Extra large (0.32,
200
+ * docs/text-size-harmonization.md §4 "nothing truncates", §3.3): the segments flow onto a
201
+ * second row inside the field's frame instead of overflowing it. At 125 % a 390 px phone
202
+ * is 312 px of Normal type, and "Month / Quarter / Half-year / Year" in one row of the
203
+ * field ran 7 px past it: a one-row flex group is as wide as all its labels end to end
204
+ * when a grid or a stretched column asks how small it can get, however its segments
205
+ * truncate. Wrapped, it is as wide as its longest label.
206
+ *
207
+ * Wrap, not a stacked select-like list: a wrapped radio group is the same radio group —
208
+ * one Tab stop, and the arrow keys walk the options in reading order whichever row
209
+ * they are on (←/↑ back, →/↓ on, Home/End) — so nothing about the keyboard changes with
210
+ * the text size. A list in its place would be a second widget with its own keys.
211
+ *
212
+ * Only where it has to: `flex-wrap` breaks a row only when the segments do not fit, so
213
+ * a wide field at Large stays one row, and a segment shares out what its row leaves
214
+ * (`flex-1`); a label wider than the whole row still truncates as the last resort.
215
+ * Three or fewer options keep one row: each holds a third of the field. A `large:`
216
+ * class, so it costs no render and is right on the first paint. `overflow="wrap"` wraps
217
+ * at every size already; outside the field the group keeps its `overflow`.
218
+ */
219
+ const WRAP_AT_LARGE = "large:flex-wrap";
220
+ const WRAP_AT_LARGE_FROM = 4;
172
221
 
173
222
  /**
174
223
  * The strip placement's segments: a 26px group (1 + 2 + 20 + 2 + 1) under the 16px
@@ -185,7 +234,7 @@ const STRIP_SEGMENT: Record<"sm" | "md", string> = { md: "py-0", sm: "py-0.5" };
185
234
  * region, because a description is read when the group is entered and not again when
186
235
  * an arrow key changes the choice underneath it.
187
236
  *
188
- * In muted 11px text under the field (or the bare group), above an `error`.
237
+ * In muted caption-size text under the field (or the bare group), above an `error`.
189
238
  */
190
239
  type ToggleGroupCaption<V> = ReactNode | ((value: V) => ReactNode);
191
240
 
@@ -272,6 +321,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
272
321
  hint,
273
322
  error,
274
323
  disabledReason: ownDisabledReason,
324
+ disabledReasonDisplay,
275
325
  commit,
276
326
  "aria-label": ariaLabelAttr,
277
327
  ...restWithMode
@@ -279,9 +329,16 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
279
329
  const labelId = useId();
280
330
  const errorId = useId();
281
331
  const reasonId = useId();
332
+ const hintCaptionId = useId();
282
333
  // The lock's reason under a locked provider (with `commit`), else the group's own.
283
334
  const disabledReason = useCommitReason(commit, ownDisabledReason);
284
335
  const locked = hasContent(disabledReason);
336
+ // §4: at Large and on touch the reason is a line under the group, not a bubble.
337
+ const reasonLine = useDisabledReasonLine(disabledReasonDisplay) && locked;
338
+ // §4: likewise a FieldHint "?" on the label line becomes a caption under the group.
339
+ const inlineHint = useInlineHint(hint);
340
+ const hintAsCaption = inlineHint !== hint ? inlineHint : undefined;
341
+ const labelHint = hintAsCaption === undefined ? hint : undefined;
285
342
  // Locked looks disabled — the dimmed group, the not-allowed cursor, no hover offer —
286
343
  // but stays focusable; `disabled` alone also takes the segments out of the tab order.
287
344
  const dimmed = disabled || locked;
@@ -289,6 +346,8 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
289
346
  // `field` is the chrome; a label placed above or in a strip keeps the bare group's
290
347
  // own box.
291
348
  const field = labelled && labelPlacement === "field";
349
+ // At Large and Extra large a FIELD of four or more options wraps (see WRAP_AT_LARGE).
350
+ const wrapAtLarge = field && overflow === "truncate" && options.length >= WRAP_AT_LARGE_FROM;
292
351
  const above = labelled && labelPlacement === "above";
293
352
  const strip = labelled && labelPlacement === "strip";
294
353
  const hasError = labelled && hasContent(error);
@@ -377,8 +436,11 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
377
436
  // overlaying the selected segment's boundary. Inset keeps the ring
378
437
  // inside the segment it belongs to; focus-visible keeps it for the
379
438
  // keyboard, which is the only input that needs it.
439
+ //
440
+ // The ring is the kit's focus frame (0.32, §5): `--focus-ring-width` wide.
380
441
  overflow === "wrap" ? "whitespace-nowrap" : "min-w-0 truncate",
381
- "flex-1 basis-auto rounded px-3 py-1.5 text-sm font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--border-strong)]",
442
+ "flex-1 basis-auto rounded px-3 py-1.5 text-sm font-medium transition-colors focus:outline-none focus-visible:ring-inset focus-visible:ring-[var(--border-strong)]",
443
+ FOCUS_RING_WIDTH,
382
444
  size === "sm" && "px-2 py-1 text-xs",
383
445
  // In the field chrome: no vertical padding, and the line that makes the
384
446
  // field 42px under a strip that clears the label — see CHROME_PAD. `sm`
@@ -423,7 +485,9 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
423
485
  aria-labelledby={labelled && ariaLabelAttr === undefined && ariaLabel === undefined ? labelId : rest["aria-labelledby"]}
424
486
  aria-invalid={hasError || rest["aria-invalid"] || undefined}
425
487
  aria-describedby={
426
- [rest["aria-describedby"], hasCaption && captionId, hasError && errorId].filter(Boolean).join(" ") || undefined
488
+ [rest["aria-describedby"], hintAsCaption !== undefined && hintCaptionId, hasCaption && captionId, hasError && errorId]
489
+ .filter(Boolean)
490
+ .join(" ") || undefined
427
491
  }
428
492
  // `aria-disabled` on the group as well as on (or `disabled` on) each button: a
429
493
  // radio group is what the user is being refused, and a screen reader announcing
@@ -444,6 +508,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
444
508
  // phone does see is the focus ring — see the segment's own note below.)
445
509
  "inline-flex w-full gap-0.5 rounded-md border border-[var(--border-strong)] bg-[var(--bg-surface)] p-0.5 shadow-sm",
446
510
  overflow === "wrap" && "flex-wrap",
511
+ wrapAtLarge && WRAP_AT_LARGE,
447
512
  // The whole group fades, the way every other disabled control in this
448
513
  // package does; `cursor-not-allowed` is on the buttons, which is what a
449
514
  // pointer is actually over.
@@ -456,7 +521,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
456
521
  !labelled && className,
457
522
  )}
458
523
  >
459
- {locked ? (
524
+ {locked && !reasonLine ? (
460
525
  // The reason's bubble wraps the SEGMENTS, inside the group, not the group: a
461
526
  // wrapper outside it would become the flex or grid item in the caller's row in
462
527
  // the group's place, and a `w-full` / `md:w-auto` on the group would size the
@@ -487,16 +552,34 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
487
552
  <p
488
553
  id={captionId}
489
554
  aria-live={captionIsLive ? "polite" : undefined}
490
- className={cn("text-[11px] leading-snug text-[var(--text-muted)]", hasCaption && "mt-1")}
555
+ className={cn("text-caption leading-snug text-[var(--text-muted)]", hasCaption && "mt-1")}
491
556
  >
492
557
  {hasCaption ? captionNode : null}
493
558
  </p>
494
559
  ) : null;
495
560
  const errorEl = hasError ? (
496
- <p id={errorId} className="mt-1 text-[11px] leading-tight text-[var(--danger)]">
561
+ <p id={errorId} className="mt-1 text-caption leading-tight text-[var(--danger)]">
497
562
  {error}
498
563
  </p>
499
564
  ) : null;
565
+ // §4: the FieldHint's words and the lock's reason, under the group, before the caption
566
+ // (standing advice first) and the error (the news). The reason line IS what each
567
+ // segment's `aria-describedby` names.
568
+ const belowEl =
569
+ hintAsCaption !== undefined || reasonLine ? (
570
+ <>
571
+ {hintAsCaption !== undefined && (
572
+ <p id={hintCaptionId} className={FIELD_CAPTION_CLASS}>
573
+ {hintAsCaption}
574
+ </p>
575
+ )}
576
+ {reasonLine && (
577
+ <p id={reasonId} className={DISABLED_REASON_LINE_CLASS}>
578
+ {disabledReason}
579
+ </p>
580
+ )}
581
+ </>
582
+ ) : null;
500
583
  if (above) {
501
584
  // `relative` so a caller's `sr-only` label cannot escape (sr-only-containment).
502
585
  return (
@@ -512,10 +595,11 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
512
595
  >
513
596
  {label}
514
597
  </Label>
515
- {hint}
598
+ {labelHint}
516
599
  </div>
517
600
  <div className="min-w-0">
518
601
  {group}
602
+ {belowEl}
519
603
  {captionEl}
520
604
  {errorEl}
521
605
  </div>
@@ -524,19 +608,21 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
524
608
  }
525
609
  if (strip) {
526
610
  return (
527
- <LabelStrip labelId={labelId} label={label} hint={hint} disabled={dimmed} pad="field" className={className}>
611
+ <LabelStrip labelId={labelId} label={label} hint={labelHint} disabled={dimmed} pad="field" className={className}>
528
612
  {group}
613
+ {belowEl}
529
614
  {captionEl}
530
615
  {errorEl}
531
616
  </LabelStrip>
532
617
  );
533
618
  }
534
619
  if (!field) {
535
- if (!captionEl) return group;
620
+ if (!captionEl && !belowEl) return group;
536
621
  // The group keeps its `className`, as without a caption; the wrapper only stacks.
537
622
  return (
538
623
  <div className="min-w-0">
539
624
  {group}
625
+ {belowEl}
540
626
  {captionEl}
541
627
  </div>
542
628
  );
@@ -549,7 +635,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
549
635
  className="flex flex-1 flex-col"
550
636
  label={<span id={labelId}>{label}</span>}
551
637
  staticLabel
552
- hint={hint}
638
+ hint={labelHint}
553
639
  >
554
640
  <div
555
641
  className={cn(
@@ -563,6 +649,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
563
649
  {group}
564
650
  </div>
565
651
  </FloatingField>
652
+ {belowEl}
566
653
  {captionEl}
567
654
  {errorEl}
568
655
  </div>
@@ -6,6 +6,7 @@
6
6
  // useful under a chart the consumer drew by hand as under `SeriesChart`.
7
7
  import type { ReactNode } from "react";
8
8
  import { cn } from "../lib/cn";
9
+ import { FOCUS_RING } from "./focus-ring";
9
10
  import { useKitLabels } from "../i18n/kit-labels";
10
11
  import { DEFAULT_SERIES_CHART_LABELS, type SeriesChartLabels } from "./series-chart-labels";
11
12
 
@@ -60,6 +61,32 @@ export function toggleHidden(hidden: ReadonlySet<string>, key: string): Readonly
60
61
  return next;
61
62
  }
62
63
 
64
+ /**
65
+ * Where a legend that stands BESIDE a chart goes from Large up: UNDER it
66
+ * (docs/text-size-harmonization.md §4). Beside a chart, a legend column takes a third of
67
+ * a row whose plot needs all of it once the text is 25–50 % larger; under it, the row
68
+ * is the plot's and the legend wraps across the width.
69
+ *
70
+ * Pure CSS (`large:`), so a legend moves with the text size alone, whatever drew the
71
+ * row around it:
72
+ * - in a GRID it spans a row of its own (`col-span-full`) after the charts
73
+ * (`order-last`) — Kurvenschmiede's facing pairs;
74
+ * - in a FLEX row it takes a line of its own (`basis-full`), and its row is allowed to
75
+ * wrap for it (`[*:has(>&)]:flex-wrap` sets `flex-wrap` on the PARENT — the one rule
76
+ * here that reaches outside the legend, because a row that may not wrap would squeeze
77
+ * the chart to nothing beside a full-width legend) — Kurvenschmiede's chart rows.
78
+ *
79
+ * A caller that places its legend itself and wants it kept beside the chart at every
80
+ * size overrides with `large:col-auto large:basis-auto`.
81
+ */
82
+ const UNDER_THE_CHART_AT_LARGE =
83
+ "large:order-last large:col-span-full large:basis-full large:[*:has(>&)]:flex-wrap";
84
+
85
+ /** A vertical legend's entries from Large up: across, wrapping — it is under the chart
86
+ * now (see {@link UNDER_THE_CHART_AT_LARGE}), where a column of entries would be a
87
+ * screenful of one-word lines. */
88
+ const VERTICAL_AT_LARGE = "large:flex-row large:flex-wrap large:items-center large:justify-start";
89
+
63
90
  export interface LegendEntry {
64
91
  key: string;
65
92
  label: ReactNode;
@@ -109,7 +136,10 @@ export interface ToggleLegendProps {
109
136
  onToggle: (key: string) => void;
110
137
  /** `vertical` is for a legend standing BESIDE the charts rather than under them —
111
138
  * what a row of charts sharing one legend wants, since under two charts there is
112
- * no "under", and putting it under one says it belongs to that one. */
139
+ * no "under", and putting it under one says it belongs to that one.
140
+ *
141
+ * From Large up a vertical legend moves under the charts and lays its entries
142
+ * across (0.32, docs/text-size-harmonization.md §4) — see {@link LegendColumn}. */
113
143
  orientation?: "horizontal" | "vertical";
114
144
  /**
115
145
  * Draw a legend of ONE entry rather than nothing.
@@ -157,7 +187,7 @@ export function ToggleLegend({
157
187
  className={cn(
158
188
  "flex gap-x-3 gap-y-1",
159
189
  orientation === "vertical"
160
- ? "flex-col items-start justify-center"
190
+ ? cn("flex-col items-start justify-center", VERTICAL_AT_LARGE, UNDER_THE_CHART_AT_LARGE)
161
191
  : "mt-2 flex-wrap items-center",
162
192
  className,
163
193
  )}
@@ -173,8 +203,8 @@ export function ToggleLegend({
173
203
  aria-pressed={!off}
174
204
  onClick={() => onToggle(entry.key)}
175
205
  className={cn(
176
- "flex items-center gap-1.5 rounded text-start text-[11px] text-[var(--text-secondary)] transition-opacity hover:opacity-80",
177
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)]",
206
+ "flex items-center gap-1.5 rounded text-start text-caption text-[var(--text-secondary)] transition-opacity hover:opacity-80",
207
+ FOCUS_RING,
178
208
  off && "opacity-35",
179
209
  entry.align === "end" && "ms-auto",
180
210
  )}
@@ -246,7 +276,7 @@ export function StaticLegend({
246
276
  className={cn(
247
277
  "m-0 flex list-none gap-x-3 gap-y-1 p-0",
248
278
  orientation === "vertical"
249
- ? "flex-col items-start justify-center"
279
+ ? cn("flex-col items-start justify-center", VERTICAL_AT_LARGE, UNDER_THE_CHART_AT_LARGE)
250
280
  : "mt-2 flex-wrap items-center",
251
281
  className,
252
282
  )}
@@ -255,7 +285,7 @@ export function StaticLegend({
255
285
  <Item
256
286
  key={entry.key}
257
287
  className={cn(
258
- "flex items-center gap-1.5 text-[11px] text-[var(--text-secondary)]",
288
+ "flex items-center gap-1.5 text-caption text-[var(--text-secondary)]",
259
289
  entry.align === "end" && "ms-auto",
260
290
  )}
261
291
  >
@@ -273,10 +303,25 @@ export function StaticLegend({
273
303
  * that stretches it — and stacks whatever it is given, which is what a panel showing
274
304
  * two legends at once needs. The width is the caller's: how wide a legend column is
275
305
  * is a fact about that screen's layout.
306
+ *
307
+ * **From Large up it goes UNDER the charts** (0.32, docs/text-size-harmonization.md
308
+ * §4): a row of its own in a grid, a line of its own in a flex row (see
309
+ * `UNDER_THE_CHART_AT_LARGE`), with what it holds laid across and wrapping. A
310
+ * caller's own `max-sm:flex-row …` for the phone keeps working; the caller's width
311
+ * (`sm:w-40`) gives way to the full row, because a size wins over a breakpoint.
276
312
  */
277
313
  export function LegendColumn({ children, className }: { children: ReactNode; className?: string }) {
278
314
  return (
279
- <div className={cn("flex h-full flex-col justify-center gap-3", className)}>{children}</div>
315
+ <div
316
+ className={cn(
317
+ "flex h-full flex-col justify-center gap-3",
318
+ UNDER_THE_CHART_AT_LARGE,
319
+ "large:h-auto large:flex-row large:flex-wrap large:items-start large:justify-start large:gap-x-6",
320
+ className,
321
+ )}
322
+ >
323
+ {children}
324
+ </div>
280
325
  );
281
326
  }
282
327
 
@@ -290,7 +335,7 @@ export function LegendColumn({ children, className }: { children: ReactNode; cla
290
335
  export function LegendGroup({ title, children }: { title: ReactNode; children: ReactNode }) {
291
336
  return (
292
337
  <div className="flex min-w-0 flex-col items-start gap-1">
293
- <span className="text-[10px] font-semibold uppercase tracking-wide text-[var(--text-muted)]">
338
+ <span className="text-micro font-semibold uppercase tracking-wide text-[var(--text-muted)]">
294
339
  {title}
295
340
  </span>
296
341
  <div className="flex flex-col items-start gap-y-0.5">{children}</div>
@@ -2,7 +2,7 @@ import { useEffect, useId, useMemo, useRef, useState } from "react";
2
2
  import type { ReactNode } from "react";
3
3
  import { Check, ListChecks, PencilLine, RotateCcw } from "lucide-react";
4
4
 
5
- import { useMediaQuery } from "../hooks/use-media-query";
5
+ import { useBreakpoint } from "../hooks/use-breakpoint";
6
6
  import { useKitLabels, useKitLocale } from "../i18n/kit-labels";
7
7
  import { cn } from "../lib/cn";
8
8
  import {
@@ -293,9 +293,6 @@ export interface TranslationReviewPanelProps {
293
293
  labels?: Partial<TranslationReviewLabels>;
294
294
  }
295
295
 
296
- /** The wide screen's query — the same one DataTable switches its layout on, so "a phone"
297
- * means the same here as in the table. */
298
- const MD_UP = "(min-width: 768px)";
299
296
 
300
297
  /**
301
298
  * How many rows the groups may render at once on a wide screen before they start folded
@@ -461,7 +458,9 @@ export function TranslationReviewPanel({
461
458
  const labels = useKitLabels("translationReview", DEFAULT_TRANSLATION_REVIEW_LABELS, labelsProp);
462
459
  const locale = useKitLocale();
463
460
  const lock = useWriteLock();
464
- const phone = !useMediaQuery(MD_UP, true);
461
+ // The wide screen's breakpoint — the one DataTable switches its layout on, so "a phone"
462
+ // means the same here as in the table, at every text size.
463
+ const phone = !useBreakpoint("md", true);
465
464
  const baseId = useId();
466
465
  const rootRef = useRef<HTMLDivElement>(null);
467
466
  const editable = !readOnly && onSave !== undefined;
@@ -744,6 +743,12 @@ export function TranslationReviewPanel({
744
743
  tone="muted"
745
744
  commit
746
745
  label={labels.approve}
746
+ // The icon alone at every text size (docs/text-size-harmonization.md §10.8):
747
+ // the row's one action, in a hugging column of a dense table beside the
748
+ // string under review, which "Approve" as text at Large would squeeze. A
749
+ // single action stays inline in `RowActions` too, so the menu would not help;
750
+ // the swipe and the editor say it in words.
751
+ labelVisible={false}
747
752
  pending={isQueued(`row:${r.id}`)}
748
753
  disabled={busy}
749
754
  onClick={(event) => {
@@ -4,6 +4,7 @@ import { ChevronRight } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
5
5
  import { horizontalStep } from "../lib/direction";
6
6
  import { Spinner } from "./ui";
7
+ import { FOCUS_RING } from "./focus-ring";
7
8
 
8
9
  /**
9
10
  * A hierarchy you walk with the keyboard: kastlan's chart of accounts (Assets › Current
@@ -182,7 +183,7 @@ export function TreeRow({
182
183
  e.stopPropagation();
183
184
  onToggle();
184
185
  }}
185
- className="flex size-4 shrink-0 items-center justify-center rounded text-[var(--text-muted)] outline-none hover:text-[var(--text-primary)] focus-visible:ring-2 focus-visible:ring-[var(--brand)]"
186
+ className={cn("flex size-4 shrink-0 items-center justify-center rounded text-[var(--text-muted)] outline-none hover:text-[var(--text-primary)]", FOCUS_RING)}
186
187
  >
187
188
  {chevron}
188
189
  </button>
@@ -543,7 +544,7 @@ export function TreeView<T = unknown>({
543
544
  }}
544
545
  // The ring goes on this row's own box, not the <li>: the <li> contains the
545
546
  // whole open branch below it, and ringing that would outline a subtree.
546
- className="outline-none [&:focus-visible>[data-tree-row]]:ring-2 [&:focus-visible>[data-tree-row]]:ring-[var(--brand)]"
547
+ className="outline-none [&:focus-visible>[data-tree-row]]:ring-[length:var(--focus-ring-width)] [&:focus-visible>[data-tree-row]]:ring-[var(--brand)]"
547
548
  >
548
549
  <TreeRow
549
550
  id={rowId}
@@ -15,6 +15,9 @@ import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } f
15
15
  import { PALETTE_HEX, textOn } from "../theme/chart-palette";
16
16
  import { parseHex } from "../theme/color";
17
17
  import { dirOf, type Direction } from "../lib/direction";
18
+ import { cn } from "../lib/cn";
19
+ import { useTextSize } from "../theme/text-size";
20
+ import { chartHeightProps, type ChartHeight } from "./chart-height";
18
21
 
19
22
  /**
20
23
  * One tile.
@@ -63,8 +66,10 @@ export interface TreemapProps extends Omit<ComponentPropsWithoutRef<"div">, "chi
63
66
  * host that has a currency or a locale passes this — the kit knows neither.
64
67
  */
65
68
  valueFormatter?: (value: number, share: number | undefined) => ReactNode;
66
- /** Chart height in px. Default 320. */
67
- height?: number;
69
+ /** Chart height: a CSS length (`"20rem"`, `"min(20rem, 50dvh)"`), a Tailwind class,
70
+ * or px. Default `"20rem"` — 320 px at Normal, growing with the text size like the
71
+ * labels in the tiles (0.32, docs/text-size-harmonization.md §10.10). */
72
+ height?: ChartHeight;
68
73
  /** A tile was activated — by click, or by Enter/Space on a focused tile. Setting
69
74
  * this makes every tile a focusable `role="button"` named by its node name. */
70
75
  onNodeClick?: (id: string, name: string) => void;
@@ -165,6 +170,8 @@ function measurableFill(fill: string, tokens: readonly string[]): string | null
165
170
 
166
171
  // ── Tile ──────────────────────────────────────────────────────────────────
167
172
 
173
+ /** The name's size in px at Normal; a tile draws it × the text size's scale (§10.10), and
174
+ * every distance below that is measured in lines grows with it. */
168
175
  const LABEL_FONT_SIZE = 12;
169
176
  /** The optional second line, a step down from the name so the tile reads name-first. */
170
177
  const NOTE_FONT_SIZE = 11;
@@ -233,6 +240,7 @@ export function TreemapCell({
233
240
  }: TreemapCellProps) {
234
241
  // Before the early return: a hook has to run on every render of the cell.
235
242
  const tokenHex = useChartTokenHex();
243
+ const { scale } = useTextSize();
236
244
  // Depth 0 is recharts' synthetic root, which spans the whole chart.
237
245
  if (!depth) return null;
238
246
  // Whole pixels: a rect on a half pixel renders its edge across two half-lit
@@ -251,14 +259,16 @@ export function TreemapCell({
251
259
  const halo = measured ? tileFill : "none";
252
260
  // Below ~44x20 there is no room for a readable word, so no label at all rather than
253
261
  // a one-letter stub bleeding over the tile edge.
254
- const label = pw >= 44 && ph >= 20 ? fitLabel(name ?? "", pw, LABEL_FONT_SIZE) : null;
262
+ const labelSize = LABEL_FONT_SIZE * scale;
263
+ const noteSize = NOTE_FONT_SIZE * scale;
264
+ const label = pw >= 44 * scale && ph >= 20 * scale ? fitLabel(name ?? "", pw, labelSize) : null;
255
265
  // Only under a label that is itself drawn — a stray "+12%" on an unnamed rectangle
256
266
  // names nothing — and only where a second baseline fits: the note's baseline sits
257
267
  // 29px down and an 11px glyph hangs ~2px below it, so 36 leaves the same ~5px under
258
268
  // the note that the label keeps under itself at the 20px floor.
259
269
  const rawNote = id != null && nodeNote ? nodeNote(id) : undefined;
260
270
  const note =
261
- label != null && rawNote != null && ph >= 36 ? fitLabel(rawNote, pw, NOTE_FONT_SIZE) : null;
271
+ label != null && rawNote != null && ph >= 36 * scale ? fitLabel(rawNote, pw, noteSize) : null;
262
272
  // The label's START edge, 6px in from the tile's. The tiles themselves are laid out
263
273
  // physically (the plot is not mirrored, see `ChartContainer`) and the chart's SVG is
264
274
  // pinned `ltr`, so the direction is set on each <text> explicitly: `start` is then
@@ -306,14 +316,14 @@ export function TreemapCell({
306
316
  // <text> exactly as it reaches a table cell.
307
317
  data-private={redactNames ? "" : undefined}
308
318
  x={textX}
309
- y={py + 15}
319
+ y={py + 15 * scale}
310
320
  direction={dir}
311
321
  fill={ink}
312
322
  stroke={halo}
313
323
  strokeWidth={2.5}
314
324
  strokeLinejoin="round"
315
325
  paintOrder="stroke"
316
- fontSize={LABEL_FONT_SIZE}
326
+ fontSize={labelSize}
317
327
  fontWeight={600}
318
328
  style={{ pointerEvents: "none" }}
319
329
  >
@@ -323,7 +333,7 @@ export function TreemapCell({
323
333
  {note != null && (
324
334
  <text
325
335
  x={textX}
326
- y={py + 29}
336
+ y={py + 29 * scale}
327
337
  direction={dir}
328
338
  fill={ink}
329
339
  fillOpacity={0.85}
@@ -331,7 +341,7 @@ export function TreemapCell({
331
341
  strokeWidth={2.5}
332
342
  strokeLinejoin="round"
333
343
  paintOrder="stroke"
334
- fontSize={NOTE_FONT_SIZE}
344
+ fontSize={noteSize}
335
345
  fontWeight={500}
336
346
  style={{ pointerEvents: "none" }}
337
347
  >
@@ -386,7 +396,7 @@ const DEFAULT_NUMBER = new Intl.NumberFormat();
386
396
  export function Treemap({
387
397
  data,
388
398
  valueFormatter,
389
- height = 320,
399
+ height = "20rem",
390
400
  onNodeClick,
391
401
  redactNames = false,
392
402
  nodeNote,
@@ -421,6 +431,7 @@ export function Treemap({
421
431
  .filter((n) => Number.isFinite(n.size) && n.size > 0)
422
432
  .slice(0, maxTiles ?? undefined);
423
433
  if (nodes.length === 0) return null;
434
+ const box = chartHeightProps(height);
424
435
 
425
436
  // The share is of what is DRAWN, so it always reads as "of this picture".
426
437
  const total = nodes.reduce((acc, n) => acc + n.size, 0);
@@ -430,7 +441,13 @@ export function Treemap({
430
441
  };
431
442
  const Content = redactNames ? RedactedTooltipContent : ChartTooltipContent;
432
443
  return (
433
- <ChartContainer {...rest} ref={rootRef} config={TREEMAP_CONFIG} style={{ ...style, height }}>
444
+ <ChartContainer
445
+ {...rest}
446
+ ref={rootRef}
447
+ config={TREEMAP_CONFIG}
448
+ className={cn(box.className, rest.className)}
449
+ style={{ ...style, ...box.style }}
450
+ >
434
451
  {/* No chart-level `stroke`: recharts spreads it onto the <svg> root, from where
435
452
  it inherits into every label (see TreemapCell). Each cell strokes its own rect. */}
436
453
  <RechartsTreemap