@eifi1/ui-kit 0.31.1 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. package/README.md +51 -28
  2. package/dist/account/delete-account-setting.d.ts +8 -3
  3. package/dist/admin/admin-action-confirm.d.ts +8 -3
  4. package/dist/admin/admin-action-log.d.ts +1 -1
  5. package/dist/admin/admin-action-log.js +4 -2
  6. package/dist/admin/admin-action-log.js.map +1 -1
  7. package/dist/admin/invitations-panel.d.ts +8 -3
  8. package/dist/admin/invitations-panel.js +29 -26
  9. package/dist/admin/invitations-panel.js.map +1 -1
  10. package/dist/admin/reviewer-scope-editor.d.ts +8 -3
  11. package/dist/admin/role-select.d.ts +10 -5
  12. package/dist/admin/transfer-ownership-dialog.d.ts +8 -3
  13. package/dist/admin/user-roster.d.ts +10 -5
  14. package/dist/admin/user-roster.js +8 -47
  15. package/dist/admin/user-roster.js.map +1 -1
  16. package/dist/auth/auth-errors.d.ts +43 -8
  17. package/dist/auth/auth-errors.js +24 -1
  18. package/dist/auth/auth-errors.js.map +1 -1
  19. package/dist/auth/register-form.d.ts +8 -3
  20. package/dist/billing/billing-banner.d.ts +184 -0
  21. package/dist/billing/billing-banner.js +98 -0
  22. package/dist/billing/billing-banner.js.map +1 -0
  23. package/dist/billing/billing-labels.d.ts +100 -0
  24. package/dist/billing/billing-labels.js +76 -0
  25. package/dist/billing/billing-labels.js.map +1 -0
  26. package/dist/billing/billing-lock.d.ts +158 -0
  27. package/dist/billing/billing-lock.js +17 -0
  28. package/dist/billing/billing-lock.js.map +1 -0
  29. package/dist/billing/billing-standing.d.ts +149 -0
  30. package/dist/billing/billing-standing.js +28 -0
  31. package/dist/billing/billing-standing.js.map +1 -0
  32. package/dist/billing/plan-card.d.ts +248 -0
  33. package/dist/billing/plan-card.js +248 -0
  34. package/dist/billing/plan-card.js.map +1 -0
  35. package/dist/billing/plan-limit-notice.d.ts +156 -0
  36. package/dist/billing/plan-limit-notice.js +76 -0
  37. package/dist/billing/plan-limit-notice.js.map +1 -0
  38. package/dist/billing/plan-limit.d.ts +34 -0
  39. package/dist/billing/plan-limit.js +20 -0
  40. package/dist/billing/plan-limit.js.map +1 -0
  41. package/dist/billing/plan-price.d.ts +61 -0
  42. package/dist/billing/plan-price.js +45 -0
  43. package/dist/billing/plan-price.js.map +1 -0
  44. package/dist/billing/subscription-actions.d.ts +133 -0
  45. package/dist/billing/subscription-actions.js +28 -0
  46. package/dist/billing/subscription-actions.js.map +1 -0
  47. package/dist/billing/subscription-status-chip.d.ts +149 -0
  48. package/dist/billing/subscription-status-chip.js +48 -0
  49. package/dist/billing/subscription-status-chip.js.map +1 -0
  50. package/dist/chart.d.ts +9 -3
  51. package/dist/chart.js.map +1 -1
  52. package/dist/components/account-chips.d.ts +16 -4
  53. package/dist/components/account-chips.js +21 -3
  54. package/dist/components/account-chips.js.map +1 -1
  55. package/dist/components/alert-banner.d.ts +6 -1
  56. package/dist/components/alert-banner.js +5 -4
  57. package/dist/components/alert-banner.js.map +1 -1
  58. package/dist/components/amount-input.d.ts +8 -3
  59. package/dist/components/amount-input.js +5 -5
  60. package/dist/components/amount-input.js.map +1 -1
  61. package/dist/components/appearance-labels.d.ts +38 -0
  62. package/dist/components/appearance-labels.js +19 -0
  63. package/dist/components/appearance-labels.js.map +1 -0
  64. package/dist/components/autocomplete.js +2 -2
  65. package/dist/components/autocomplete.js.map +1 -1
  66. package/dist/components/breadcrumbs.js +3 -2
  67. package/dist/components/breadcrumbs.js.map +1 -1
  68. package/dist/components/bulk-action-bar.d.ts +2 -2
  69. package/dist/components/bulk-action-bar.js +7 -12
  70. package/dist/components/bulk-action-bar.js.map +1 -1
  71. package/dist/components/button-group.d.ts +8 -3
  72. package/dist/components/button-group.js +7 -1
  73. package/dist/components/button-group.js.map +1 -1
  74. package/dist/components/calculator.d.ts +8 -3
  75. package/dist/components/calculator.js +4 -3
  76. package/dist/components/calculator.js.map +1 -1
  77. package/dist/components/calendar-heatmap.js +5 -5
  78. package/dist/components/calendar-heatmap.js.map +1 -1
  79. package/dist/components/chart-height.d.ts +23 -0
  80. package/dist/components/chart-height.js +15 -0
  81. package/dist/components/chart-height.js.map +1 -0
  82. package/dist/components/chart-zoom.js +6 -1
  83. package/dist/components/chart-zoom.js.map +1 -1
  84. package/dist/components/checkbox-group.js +2 -2
  85. package/dist/components/checkbox-group.js.map +1 -1
  86. package/dist/components/checkbox.d.ts +10 -0
  87. package/dist/components/checkbox.js +25 -10
  88. package/dist/components/checkbox.js.map +1 -1
  89. package/dist/components/chip.d.ts +19 -3
  90. package/dist/components/chip.js +54 -23
  91. package/dist/components/chip.js.map +1 -1
  92. package/dist/components/choice-card.d.ts +1 -1
  93. package/dist/components/choice-card.js +9 -8
  94. package/dist/components/choice-card.js.map +1 -1
  95. package/dist/components/column-mapper.js +1 -1
  96. package/dist/components/column-mapper.js.map +1 -1
  97. package/dist/components/combobox-core.js +8 -7
  98. package/dist/components/combobox-core.js.map +1 -1
  99. package/dist/components/combobox.js +8 -8
  100. package/dist/components/combobox.js.map +1 -1
  101. package/dist/components/confirm-dialog.d.ts +8 -3
  102. package/dist/components/copy-button.d.ts +10 -5
  103. package/dist/components/country-select.js +1 -1
  104. package/dist/components/country-select.js.map +1 -1
  105. package/dist/components/currency-select.js +3 -3
  106. package/dist/components/currency-select.js.map +1 -1
  107. package/dist/components/danger-confirm.d.ts +8 -3
  108. package/dist/components/data-table-cells.d.ts +1 -1
  109. package/dist/components/data-table-filter-popover.d.ts +1 -1
  110. package/dist/components/data-table-filter-popover.js +4 -1
  111. package/dist/components/data-table-filter-popover.js.map +1 -1
  112. package/dist/components/data-table-filters.d.ts +1 -1
  113. package/dist/components/data-table-labels.d.ts +1 -1
  114. package/dist/components/data-table-pagination.d.ts +3 -2
  115. package/dist/components/data-table-pagination.js +15 -6
  116. package/dist/components/data-table-pagination.js.map +1 -1
  117. package/dist/components/data-table.d.ts +1 -1
  118. package/dist/components/data-table.js +123 -52
  119. package/dist/components/data-table.js.map +1 -1
  120. package/dist/components/date-picker.d.ts +1 -1
  121. package/dist/components/date-picker.js +18 -6
  122. package/dist/components/date-picker.js.map +1 -1
  123. package/dist/components/description-list.js +2 -2
  124. package/dist/components/description-list.js.map +1 -1
  125. package/dist/components/dialog-frame.js +2 -1
  126. package/dist/components/dialog-frame.js.map +1 -1
  127. package/dist/components/disclosure.js +3 -2
  128. package/dist/components/disclosure.js.map +1 -1
  129. package/dist/components/dropdown.d.ts +1 -1
  130. package/dist/components/dropdown.js +7 -1
  131. package/dist/components/dropdown.js.map +1 -1
  132. package/dist/components/facing-pair.d.ts +19 -6
  133. package/dist/components/facing-pair.js +3 -2
  134. package/dist/components/facing-pair.js.map +1 -1
  135. package/dist/components/field-parts.d.ts +102 -6
  136. package/dist/components/field-parts.js +81 -6
  137. package/dist/components/field-parts.js.map +1 -1
  138. package/dist/components/field-sync.d.ts +4 -1
  139. package/dist/components/field-sync.js +12 -2
  140. package/dist/components/field-sync.js.map +1 -1
  141. package/dist/components/field.js +2 -2
  142. package/dist/components/field.js.map +1 -1
  143. package/dist/components/file-button.d.ts +8 -3
  144. package/dist/components/file-dropzone.d.ts +8 -3
  145. package/dist/components/floating-panel.js +7 -4
  146. package/dist/components/floating-panel.js.map +1 -1
  147. package/dist/components/focus-ring.d.ts +12 -0
  148. package/dist/components/focus-ring.js +8 -0
  149. package/dist/components/focus-ring.js.map +1 -0
  150. package/dist/components/form-actions.d.ts +8 -3
  151. package/dist/components/form-actions.js +33 -19
  152. package/dist/components/form-actions.js.map +1 -1
  153. package/dist/components/full-bleed-dialog.d.ts +11 -1
  154. package/dist/components/full-bleed-dialog.js +3 -1
  155. package/dist/components/full-bleed-dialog.js.map +1 -1
  156. package/dist/components/iban-input.d.ts +8 -3
  157. package/dist/components/image-grid.js +1 -1
  158. package/dist/components/image-grid.js.map +1 -1
  159. package/dist/components/inline-edit-field.js +10 -4
  160. package/dist/components/inline-edit-field.js.map +1 -1
  161. package/dist/components/language-select.d.ts +8 -3
  162. package/dist/components/legal-page.d.ts +26 -5
  163. package/dist/components/legal-page.js +3 -1
  164. package/dist/components/legal-page.js.map +1 -1
  165. package/dist/components/legal.d.ts +8 -3
  166. package/dist/components/legal.js +2 -1
  167. package/dist/components/legal.js.map +1 -1
  168. package/dist/components/lightbox.js +24 -2
  169. package/dist/components/lightbox.js.map +1 -1
  170. package/dist/components/line-items.js +2 -1
  171. package/dist/components/line-items.js.map +1 -1
  172. package/dist/components/list.d.ts +5 -0
  173. package/dist/components/list.js +13 -9
  174. package/dist/components/list.js.map +1 -1
  175. package/dist/components/measured-grid.d.ts +3 -1
  176. package/dist/components/measured-grid.js +38 -20
  177. package/dist/components/measured-grid.js.map +1 -1
  178. package/dist/components/menu-item.js +2 -1
  179. package/dist/components/menu-item.js.map +1 -1
  180. package/dist/components/mini-calendar.js +8 -4
  181. package/dist/components/mini-calendar.js.map +1 -1
  182. package/dist/components/money-field.d.ts +8 -3
  183. package/dist/components/month-picker.js +50 -39
  184. package/dist/components/month-picker.js.map +1 -1
  185. package/dist/components/nav-pills.js +1 -1
  186. package/dist/components/nav-pills.js.map +1 -1
  187. package/dist/components/number-field.d.ts +8 -3
  188. package/dist/components/number-input.d.ts +11 -4
  189. package/dist/components/number-input.js +8 -6
  190. package/dist/components/number-input.js.map +1 -1
  191. package/dist/components/numpad-sheet.d.ts +8 -3
  192. package/dist/components/numpad-sheet.js +2 -1
  193. package/dist/components/numpad-sheet.js.map +1 -1
  194. package/dist/components/one-time-code-input.js +2 -2
  195. package/dist/components/one-time-code-input.js.map +1 -1
  196. package/dist/components/page-contents.js +2 -2
  197. package/dist/components/page-contents.js.map +1 -1
  198. package/dist/components/phone-input.d.ts +8 -3
  199. package/dist/components/phone-input.js +4 -4
  200. package/dist/components/phone-input.js.map +1 -1
  201. package/dist/components/pie-chart.d.ts +8 -2
  202. package/dist/components/pie-chart.js +11 -7
  203. package/dist/components/pie-chart.js.map +1 -1
  204. package/dist/components/popover.d.ts +9 -1
  205. package/dist/components/popover.js +8 -4
  206. package/dist/components/popover.js.map +1 -1
  207. package/dist/components/row-actions.d.ts +100 -0
  208. package/dist/components/row-actions.js +231 -0
  209. package/dist/components/row-actions.js.map +1 -0
  210. package/dist/components/scroll-area.js +1 -1
  211. package/dist/components/scroll-area.js.map +1 -1
  212. package/dist/components/search-field.js +3 -2
  213. package/dist/components/search-field.js.map +1 -1
  214. package/dist/components/series-chart-budget.d.ts +30 -7
  215. package/dist/components/series-chart-budget.js +12 -4
  216. package/dist/components/series-chart-budget.js.map +1 -1
  217. package/dist/components/series-chart-ticks.d.ts +7 -1
  218. package/dist/components/series-chart-ticks.js +6 -0
  219. package/dist/components/series-chart-ticks.js.map +1 -1
  220. package/dist/components/series-chart.d.ts +58 -28
  221. package/dist/components/series-chart.js +42 -32
  222. package/dist/components/series-chart.js.map +1 -1
  223. package/dist/components/settings-fields.d.ts +57 -8
  224. package/dist/components/settings-fields.js +39 -1
  225. package/dist/components/settings-fields.js.map +1 -1
  226. package/dist/components/share-card.d.ts +11 -6
  227. package/dist/components/share-card.js +8 -2
  228. package/dist/components/share-card.js.map +1 -1
  229. package/dist/components/sign-chip.d.ts +4 -0
  230. package/dist/components/sign-chip.js +17 -4
  231. package/dist/components/sign-chip.js.map +1 -1
  232. package/dist/components/signature-pad.d.ts +3 -1
  233. package/dist/components/signature-pad.js +8 -5
  234. package/dist/components/signature-pad.js.map +1 -1
  235. package/dist/components/slider.js +7 -6
  236. package/dist/components/slider.js.map +1 -1
  237. package/dist/components/sparkline.d.ts +5 -1
  238. package/dist/components/sparkline.js +4 -2
  239. package/dist/components/sparkline.js.map +1 -1
  240. package/dist/components/stat-tile.d.ts +17 -1
  241. package/dist/components/stat-tile.js +48 -20
  242. package/dist/components/stat-tile.js.map +1 -1
  243. package/dist/components/status-dot.d.ts +4 -0
  244. package/dist/components/status-dot.js +9 -2
  245. package/dist/components/status-dot.js.map +1 -1
  246. package/dist/components/swipeable-row.js +10 -2
  247. package/dist/components/swipeable-row.js.map +1 -1
  248. package/dist/components/switch.d.ts +21 -7
  249. package/dist/components/switch.js +24 -11
  250. package/dist/components/switch.js.map +1 -1
  251. package/dist/components/table.js +2 -2
  252. package/dist/components/table.js.map +1 -1
  253. package/dist/components/text-link.d.ts +8 -3
  254. package/dist/components/text-link.js +1 -1
  255. package/dist/components/text-link.js.map +1 -1
  256. package/dist/components/text.d.ts +7 -2
  257. package/dist/components/text.js +5 -5
  258. package/dist/components/text.js.map +1 -1
  259. package/dist/components/tile-radio.js +2 -1
  260. package/dist/components/tile-radio.js.map +1 -1
  261. package/dist/components/time-input.d.ts +8 -3
  262. package/dist/components/toast.d.ts +18 -2
  263. package/dist/components/toast.js +8 -5
  264. package/dist/components/toast.js.map +1 -1
  265. package/dist/components/toggle-group.d.ts +25 -3
  266. package/dist/components/toggle-group.js +40 -11
  267. package/dist/components/toggle-group.js.map +1 -1
  268. package/dist/components/toggle-legend.d.ts +10 -1
  269. package/dist/components/toggle-legend.js +21 -7
  270. package/dist/components/toggle-legend.js.map +1 -1
  271. package/dist/components/translation-review-editor.js +1 -1
  272. package/dist/components/translation-review-editor.js.map +1 -1
  273. package/dist/components/translation-review-parts.d.ts +4 -0
  274. package/dist/components/translation-review.d.ts +4 -0
  275. package/dist/components/translation-review.js +3 -3
  276. package/dist/components/translation-review.js.map +1 -1
  277. package/dist/components/tree-view.js +3 -2
  278. package/dist/components/tree-view.js.map +1 -1
  279. package/dist/components/treemap.d.ts +5 -2
  280. package/dist/components/treemap.js +33 -16
  281. package/dist/components/treemap.js.map +1 -1
  282. package/dist/components/ui.d.ts +8 -3
  283. package/dist/components/ui.js +207 -119
  284. package/dist/components/ui.js.map +1 -1
  285. package/dist/components/use-table-state.d.ts +1 -1
  286. package/dist/components/user-avatar.d.ts +5 -1
  287. package/dist/components/user-avatar.js +1 -1
  288. package/dist/components/user-avatar.js.map +1 -1
  289. package/dist/components/wizard-stepper.js +20 -14
  290. package/dist/components/wizard-stepper.js.map +1 -1
  291. package/dist/{data-table-labels-DUELeXpa.d.ts → data-table-labels-kpAAVi6g.d.ts} +26 -2
  292. package/dist/data-table.d.ts +1 -1
  293. package/dist/{delete-account-setting-CpIhzxxZ.d.ts → delete-account-setting-FLyJf-kZ.d.ts} +642 -60
  294. package/dist/demo/demo-banner.js +1 -0
  295. package/dist/demo/demo-banner.js.map +1 -1
  296. package/dist/feedback/feedback-attachment.d.ts +8 -3
  297. package/dist/feedback/feedback-context.d.ts +8 -3
  298. package/dist/feedback/feedback-crash.d.ts +8 -3
  299. package/dist/feedback/feedback-dialog.d.ts +8 -3
  300. package/dist/feedback/feedback-dialog.js +3 -3
  301. package/dist/feedback/feedback-dialog.js.map +1 -1
  302. package/dist/feedback/feedback-inbox.d.ts +8 -3
  303. package/dist/feedback/feedback-inbox.js +2 -2
  304. package/dist/feedback/feedback-inbox.js.map +1 -1
  305. package/dist/feedback/feedback-labels.d.ts +8 -3
  306. package/dist/feedback/feedback-menu.d.ts +9 -4
  307. package/dist/feedback/feedback-record.d.ts +8 -3
  308. package/dist/feedback/feedback-row-detail.d.ts +8 -3
  309. package/dist/feedback/feedback-status-undo.d.ts +8 -3
  310. package/dist/feedback/feedback-submit.d.ts +8 -3
  311. package/dist/feedback/feedback-swipe.d.ts +8 -3
  312. package/dist/feedback/feedback-table.d.ts +8 -3
  313. package/dist/feedback/feedback-thread.d.ts +8 -3
  314. package/dist/feedback/feedback-thread.js +3 -3
  315. package/dist/feedback/feedback-thread.js.map +1 -1
  316. package/dist/feedback.d.ts +8 -3
  317. package/dist/hooks/use-anchored-panel.d.ts +32 -3
  318. package/dist/hooks/use-anchored-panel.js +21 -3
  319. package/dist/hooks/use-anchored-panel.js.map +1 -1
  320. package/dist/hooks/use-breakpoint.d.ts +88 -0
  321. package/dist/hooks/use-breakpoint.js +50 -0
  322. package/dist/hooks/use-breakpoint.js.map +1 -0
  323. package/dist/hooks/use-file-drop.d.ts +8 -3
  324. package/dist/hooks/use-large-text.d.ts +29 -0
  325. package/dist/hooks/use-large-text.js +20 -0
  326. package/dist/hooks/use-large-text.js.map +1 -0
  327. package/dist/hooks/use-windowed-rows.d.ts +52 -8
  328. package/dist/hooks/use-windowed-rows.js +94 -5
  329. package/dist/hooks/use-windowed-rows.js.map +1 -1
  330. package/dist/i18n/defaults.d.ts +8 -3
  331. package/dist/i18n/defaults.js +8 -0
  332. package/dist/i18n/defaults.js.map +1 -1
  333. package/dist/i18n/german.d.ts +8 -3
  334. package/dist/i18n/german.js +94 -3
  335. package/dist/i18n/german.js.map +1 -1
  336. package/dist/i18n/kit-labels.d.ts +8 -3
  337. package/dist/i18n/kit-labels.js.map +1 -1
  338. package/dist/i18n/languages.d.ts +10 -5
  339. package/dist/i18n/locales/de-CH.d.ts +8 -3
  340. package/dist/i18n/locales/en.d.ts +8 -3
  341. package/dist/i18n/locales/es.d.ts +8 -3
  342. package/dist/i18n/locales/es.js +89 -3
  343. package/dist/i18n/locales/es.js.map +1 -1
  344. package/dist/i18n/locales/fr.d.ts +8 -3
  345. package/dist/i18n/locales/fr.js +91 -3
  346. package/dist/i18n/locales/fr.js.map +1 -1
  347. package/dist/i18n/locales/hu.d.ts +8 -3
  348. package/dist/i18n/locales/hu.js +91 -3
  349. package/dist/i18n/locales/hu.js.map +1 -1
  350. package/dist/i18n/locales/it.d.ts +8 -3
  351. package/dist/i18n/locales/it.js +92 -3
  352. package/dist/i18n/locales/it.js.map +1 -1
  353. package/dist/i18n/locales/zh.d.ts +8 -3
  354. package/dist/i18n/locales/zh.js +89 -3
  355. package/dist/i18n/locales/zh.js.map +1 -1
  356. package/dist/i18n/review.d.ts +8 -3
  357. package/dist/i18n/review.js +15 -1
  358. package/dist/i18n/review.js.map +1 -1
  359. package/dist/index.d.ts +27 -11
  360. package/dist/index.js +77 -4
  361. package/dist/index.js.map +1 -1
  362. package/dist/landing/landing-actions.d.ts +8 -3
  363. package/dist/landing/landing-sections.d.ts +8 -3
  364. package/dist/landing/landing-sections.js +7 -3
  365. package/dist/landing/landing-sections.js.map +1 -1
  366. package/dist/landing/public-header.d.ts +9 -4
  367. package/dist/landing/public-header.js +3 -3
  368. package/dist/landing/public-header.js.map +1 -1
  369. package/dist/landing/routing.d.ts +8 -3
  370. package/dist/lib/cn.js +3 -2
  371. package/dist/lib/cn.js.map +1 -1
  372. package/dist/rhf/fields.d.ts +8 -3
  373. package/dist/rhf/fields.js +1 -1
  374. package/dist/rhf/fields.js.map +1 -1
  375. package/dist/rhf/form.d.ts +8 -3
  376. package/dist/rhf/form.js +2 -2
  377. package/dist/rhf/form.js.map +1 -1
  378. package/dist/rhf.d.ts +8 -3
  379. package/dist/search/command-palette.d.ts +1 -1
  380. package/dist/search/command-palette.js +9 -8
  381. package/dist/search/command-palette.js.map +1 -1
  382. package/dist/settings/settings-layout.js +2 -1
  383. package/dist/settings/settings-layout.js.map +1 -1
  384. package/dist/settings/settings-section.d.ts +8 -3
  385. package/dist/settings/use-account-appearance.d.ts +92 -0
  386. package/dist/settings/use-account-appearance.js +63 -0
  387. package/dist/settings/use-account-appearance.js.map +1 -0
  388. package/dist/settings/use-settings-route.d.ts +1 -1
  389. package/dist/settings/use-settings-route.js +2 -3
  390. package/dist/settings/use-settings-route.js.map +1 -1
  391. package/dist/shell/app-shell.d.ts +12 -171
  392. package/dist/shell/app-shell.js +144 -28
  393. package/dist/shell/app-shell.js.map +1 -1
  394. package/dist/shell/auth-layout.js +1 -1
  395. package/dist/shell/auth-layout.js.map +1 -1
  396. package/dist/shell/option-switcher-menu.js +1 -1
  397. package/dist/shell/option-switcher-menu.js.map +1 -1
  398. package/dist/shell/top-bar-brand.d.ts +8 -3
  399. package/dist/shell/top-bar-brand.js +3 -1
  400. package/dist/shell/top-bar-brand.js.map +1 -1
  401. package/dist/shell/topbar-action-menu.d.ts +4 -0
  402. package/dist/shell/topbar-action-menu.js +3 -3
  403. package/dist/shell/topbar-action-menu.js.map +1 -1
  404. package/dist/shell/topbar-controls.js +4 -4
  405. package/dist/shell/topbar-controls.js.map +1 -1
  406. package/dist/shell.d.ts +9 -5
  407. package/dist/theme/contrast-tokens.d.ts +41 -0
  408. package/dist/theme/contrast-tokens.js +59 -0
  409. package/dist/theme/contrast-tokens.js.map +1 -0
  410. package/dist/theme/contrast.d.ts +110 -0
  411. package/dist/theme/contrast.js +128 -0
  412. package/dist/theme/contrast.js.map +1 -0
  413. package/dist/theme/palette-presets.d.ts +12 -1
  414. package/dist/theme/palette-presets.js +9 -4
  415. package/dist/theme/palette-presets.js.map +1 -1
  416. package/dist/theme/palette-store.js.map +1 -1
  417. package/dist/theme/text-size.d.ts +173 -0
  418. package/dist/theme/text-size.js +121 -0
  419. package/dist/theme/text-size.js.map +1 -0
  420. package/dist/wizard/stepper-nav.d.ts +8 -3
  421. package/dist/wizard/wizard-summary.js +1 -1
  422. package/dist/wizard/wizard-summary.js.map +1 -1
  423. package/dist/wizard.d.ts +8 -3
  424. package/package.json +1 -1
  425. package/src/admin/admin-action-log.tsx +6 -1
  426. package/src/admin/invitations-panel.tsx +36 -29
  427. package/src/admin/user-roster.tsx +17 -72
  428. package/src/auth/auth-errors.ts +68 -7
  429. package/src/billing/billing-banner.tsx +205 -0
  430. package/src/billing/billing-labels.ts +240 -0
  431. package/src/billing/billing-lock.ts +75 -0
  432. package/src/billing/billing-standing.ts +72 -0
  433. package/src/billing/plan-card.tsx +458 -0
  434. package/src/billing/plan-limit-notice.tsx +145 -0
  435. package/src/billing/plan-limit.ts +53 -0
  436. package/src/billing/plan-price.ts +101 -0
  437. package/src/billing/subscription-actions.tsx +76 -0
  438. package/src/billing/subscription-status-chip.tsx +95 -0
  439. package/src/chart.ts +2 -0
  440. package/src/components/account-chips.tsx +36 -10
  441. package/src/components/alert-banner.tsx +16 -7
  442. package/src/components/amount-input.tsx +5 -5
  443. package/src/components/appearance-labels.ts +47 -0
  444. package/src/components/autocomplete.tsx +2 -2
  445. package/src/components/breadcrumbs.tsx +3 -3
  446. package/src/components/bulk-action-bar.tsx +11 -14
  447. package/src/components/button-group.tsx +21 -0
  448. package/src/components/calculator.tsx +4 -3
  449. package/src/components/calendar-heatmap.tsx +5 -5
  450. package/src/components/chart-height.ts +30 -0
  451. package/src/components/chart-zoom.tsx +6 -1
  452. package/src/components/checkbox-group.tsx +2 -2
  453. package/src/components/checkbox.tsx +62 -20
  454. package/src/components/chip.tsx +139 -30
  455. package/src/components/choice-card.tsx +16 -11
  456. package/src/components/column-mapper.tsx +1 -1
  457. package/src/components/combobox-core.tsx +8 -7
  458. package/src/components/combobox.tsx +8 -8
  459. package/src/components/country-select.tsx +1 -1
  460. package/src/components/currency-select.tsx +3 -3
  461. package/src/components/data-table-filter-popover.tsx +7 -1
  462. package/src/components/data-table-pagination.tsx +60 -31
  463. package/src/components/data-table.tsx +164 -43
  464. package/src/components/date-picker.tsx +44 -10
  465. package/src/components/description-list.tsx +2 -2
  466. package/src/components/dialog-frame.tsx +2 -1
  467. package/src/components/disclosure.tsx +3 -2
  468. package/src/components/dropdown.tsx +10 -2
  469. package/src/components/facing-pair.ts +12 -5
  470. package/src/components/field-parts.tsx +190 -7
  471. package/src/components/field-sync.tsx +17 -3
  472. package/src/components/field.tsx +2 -2
  473. package/src/components/floating-panel.tsx +7 -4
  474. package/src/components/focus-ring.ts +12 -0
  475. package/src/components/form-actions.tsx +55 -18
  476. package/src/components/full-bleed-dialog.tsx +18 -4
  477. package/src/components/image-grid.tsx +1 -1
  478. package/src/components/inline-edit-field.tsx +26 -4
  479. package/src/components/legal-page.tsx +28 -2
  480. package/src/components/legal.tsx +19 -1
  481. package/src/components/lightbox.tsx +24 -2
  482. package/src/components/line-items.tsx +7 -1
  483. package/src/components/list.tsx +36 -10
  484. package/src/components/measured-grid.tsx +49 -24
  485. package/src/components/menu-item.tsx +2 -2
  486. package/src/components/mini-calendar.tsx +8 -4
  487. package/src/components/month-picker.tsx +15 -6
  488. package/src/components/nav-pills.tsx +1 -1
  489. package/src/components/number-input.tsx +14 -7
  490. package/src/components/numpad-sheet.tsx +2 -2
  491. package/src/components/one-time-code-input.tsx +2 -2
  492. package/src/components/page-contents.tsx +2 -2
  493. package/src/components/phone-input.tsx +9 -4
  494. package/src/components/pie-chart.tsx +19 -9
  495. package/src/components/popover.tsx +22 -5
  496. package/src/components/row-actions.tsx +450 -0
  497. package/src/components/scroll-area.tsx +1 -1
  498. package/src/components/search-field.tsx +4 -2
  499. package/src/components/series-chart-budget.ts +40 -8
  500. package/src/components/series-chart-ticks.ts +10 -0
  501. package/src/components/series-chart.tsx +123 -72
  502. package/src/components/settings-fields.tsx +89 -5
  503. package/src/components/share-card.tsx +31 -2
  504. package/src/components/sign-chip.tsx +28 -4
  505. package/src/components/signature-pad.tsx +13 -7
  506. package/src/components/slider.tsx +22 -9
  507. package/src/components/sparkline.tsx +11 -3
  508. package/src/components/stat-tile.tsx +70 -14
  509. package/src/components/status-dot.tsx +25 -2
  510. package/src/components/swipeable-row.tsx +10 -2
  511. package/src/components/switch.tsx +57 -23
  512. package/src/components/table.tsx +2 -2
  513. package/src/components/text-link.tsx +1 -1
  514. package/src/components/text.tsx +11 -6
  515. package/src/components/tile-radio.tsx +4 -1
  516. package/src/components/toast.tsx +27 -7
  517. package/src/components/toggle-group.tsx +115 -14
  518. package/src/components/toggle-legend.tsx +53 -8
  519. package/src/components/translation-review-editor.tsx +1 -1
  520. package/src/components/translation-review.tsx +11 -5
  521. package/src/components/tree-view.tsx +3 -2
  522. package/src/components/treemap.tsx +27 -10
  523. package/src/components/ui.tsx +353 -153
  524. package/src/components/user-avatar.tsx +1 -1
  525. package/src/components/wizard-stepper.tsx +5 -1
  526. package/src/demo/demo-banner.tsx +5 -0
  527. package/src/feedback/feedback-dialog.tsx +3 -3
  528. package/src/feedback/feedback-inbox.tsx +2 -2
  529. package/src/feedback/feedback-thread.tsx +3 -3
  530. package/src/hooks/use-anchored-panel.ts +67 -5
  531. package/src/hooks/use-breakpoint.ts +132 -0
  532. package/src/hooks/use-large-text.ts +41 -0
  533. package/src/hooks/use-windowed-rows.ts +168 -12
  534. package/src/i18n/defaults.ts +8 -0
  535. package/src/i18n/german.ts +107 -0
  536. package/src/i18n/kit-labels.tsx +12 -0
  537. package/src/i18n/locales/es.ts +98 -0
  538. package/src/i18n/locales/fr.ts +102 -0
  539. package/src/i18n/locales/hu.ts +100 -0
  540. package/src/i18n/locales/it.ts +103 -0
  541. package/src/i18n/locales/zh.ts +94 -0
  542. package/src/i18n/review.ts +14 -0
  543. package/src/index.ts +76 -6
  544. package/src/landing/landing-sections.tsx +7 -3
  545. package/src/landing/public-header.tsx +4 -4
  546. package/src/lib/cn.ts +13 -2
  547. package/src/rhf/fields.tsx +1 -1
  548. package/src/rhf/form.tsx +2 -2
  549. package/src/search/command-palette.tsx +10 -9
  550. package/src/settings/settings-layout.tsx +2 -1
  551. package/src/settings/use-account-appearance.ts +148 -0
  552. package/src/settings/use-settings-route.ts +3 -4
  553. package/src/shell/app-shell.tsx +278 -54
  554. package/src/shell/auth-layout.tsx +1 -1
  555. package/src/shell/option-switcher-menu.tsx +1 -1
  556. package/src/shell/top-bar-brand.tsx +3 -1
  557. package/src/shell/topbar-action-menu.tsx +3 -3
  558. package/src/shell/topbar-controls.tsx +4 -4
  559. package/src/theme/contrast-tokens.ts +112 -0
  560. package/src/theme/contrast.ts +225 -0
  561. package/src/theme/palette-presets.ts +24 -4
  562. package/src/theme/palette-store.ts +6 -1
  563. package/src/theme/text-size.ts +283 -0
  564. package/src/wizard/wizard-summary.tsx +4 -2
  565. package/tokens.css +158 -8
@@ -1,4 +1,4 @@
1
- import { Fragment, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
1
+ import { Fragment, isValidElement, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
2
2
  import type { CSSProperties, ReactNode, TdHTMLAttributes, ThHTMLAttributes } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  import {
@@ -14,7 +14,9 @@ import {
14
14
  Trash2,
15
15
  X,
16
16
  } from "lucide-react";
17
- import { Card, IconButton, Select, Spinner } from "./ui";
17
+ import { Card, FOCUS_RING, IconButton, Select, Spinner } from "./ui";
18
+ import { RowActions, type RowAction } from "./row-actions";
19
+ import { useLargeText } from "../hooks/use-large-text";
18
20
  import { cn } from "../lib/cn";
19
21
  import {
20
22
  defaultFilterState,
@@ -33,7 +35,7 @@ import { useBodyScrollLock } from "../hooks/use-body-scroll-lock";
33
35
  import { useOverlayHistory } from "../hooks/use-overlay-history";
34
36
  import { FullBleedDialog } from "./full-bleed-dialog";
35
37
  import { Popover } from "./popover";
36
- import { useMediaQuery } from "../hooks/use-media-query";
38
+ import { usePhoneLayout } from "../hooks/use-breakpoint";
37
39
  import { useAnnounce } from "../hooks/use-announce";
38
40
  import { DEFAULT_DATA_TABLE_LABELS, resolveDataTableLabels, type DataTableLabels } from "./data-table-labels";
39
41
  import { useKitLabelOverrides, useKitLocale } from "../i18n/kit-labels";
@@ -366,6 +368,27 @@ export interface DataTableProps<T> {
366
368
  * of unfolding it inline (feedback #204). Desktop always uses inline expansion.
367
369
  */
368
370
  mobileExpandAsDialog?: boolean;
371
+ /**
372
+ * Show the `mobileHidden` columns in the OPENED row on the phone layout — inline
373
+ * under the card, or in the `mobileExpandAsDialog` dialog — so a column dropped from
374
+ * the card to keep it short is not lost (0.32, docs/text-size-harmonization.md §4:
375
+ * "a new `mobileDetailsInRow` puts the `mobileHidden` columns into the opened row, so
376
+ * nothing is lost"). At Large a card holds fewer facts per screen, and dropping one
377
+ * from the card must not drop it from the phone.
378
+ *
379
+ * Each column is a label above its value, BEFORE what `expandedRow` renders: the
380
+ * row's own facts first, then the app's detail or editor. A row opens as it always
381
+ * does (`onRowClick` toggling `isExpanded`); with this set it may open without an
382
+ * `expandedRow` at all. `rowActions`' column is one of them — the actions, which the
383
+ * card otherwise offers only as swipes, reachable by a tap. Desktop is unaffected.
384
+ */
385
+ mobileDetailsInRow?: boolean;
386
+ /**
387
+ * The row's name, as plain text — for the "⋯" menu its `rowActions` collapse into at
388
+ * Large ("Actions for Ada Example", §10.8). Without it every row's menu button is
389
+ * named "Actions", which a screen reader cannot tell apart down the list.
390
+ */
391
+ rowName?: (row: T) => string | undefined;
369
392
  /**
370
393
  * The phone row dialog's `backCloses` ({@link FullBleedDialog}): whether it pushes
371
394
  * its own history entry so Back dismisses it. On by default — right for a row whose
@@ -526,7 +549,10 @@ export interface DataTableProps<T> {
526
549
  /**
527
550
  * Per-row actions: an actions column of icon buttons at the row's end on desktop,
528
551
  * and the same actions as swipe actions on a phone card (where the column is not
529
- * shown). kastlan's `ResourceListPage` appended this column by hand to every CRUD
552
+ * shown; with `mobileDetailsInRow` also as buttons in the opened row). At Large and
553
+ * Extra large two or more collapse into one "⋯" menu with each action's words
554
+ * (0.32, §10.8, `RowActions`) — name the rows with `rowName` so each menu button is
555
+ * "Actions for …". kastlan's `ResourceListPage` appended this column by hand to every CRUD
530
556
  * list — the edit pencil, the delete bin, a `useConfirm` before the delete, and a
531
557
  * `stopPropagation` on each so a press did not also open the row.
532
558
  *
@@ -637,6 +663,19 @@ async function runRowAction<T>(action: DataTableRowAction<T>, row: T): Promise<v
637
663
  action.onAction(row);
638
664
  }
639
665
 
666
+ /** A resolved row action as {@link RowActions} takes it. Its `icon` is any node; a
667
+ * non-element one (a string glyph) is wrapped, since RowAction wants an element. */
668
+ function toRowAction<T>(a: ResolvedRowAction<T>, row: T): RowAction {
669
+ return {
670
+ key: a.key,
671
+ label: a.label,
672
+ icon: isValidElement(a.icon) ? a.icon : a.icon != null && a.icon !== false ? <>{a.icon}</> : undefined,
673
+ tone: a.tone,
674
+ disabledReason: a.action.disabledReason?.(row),
675
+ onSelect: () => void runRowAction(a.action, row),
676
+ };
677
+ }
678
+
640
679
  /** See {@link DataTableProps.chrome}. */
641
680
  export type DataTableChrome = "full" | "minimal";
642
681
 
@@ -734,6 +773,46 @@ function columnLabel<T>(col: DataTableColumn<T>, labels?: DataTableLabels): stri
734
773
  return col.headerText ?? (typeof col.header === "string" ? col.header : col.key);
735
774
  }
736
775
 
776
+ // ---------- Phone card at Large (0.32) ----------
777
+
778
+ /**
779
+ * §4 "nothing truncates" in a phone card at Large and Extra large: a cell's own
780
+ * `truncate` (a kit cell, a chip, the app's span) wraps instead — and breaks inside a
781
+ * word too long for the card rather than running out of it. A descendant rule, so it
782
+ * reaches the cells without the table knowing what they render; `large:`, so Normal
783
+ * keeps every ellipsis it had.
784
+ */
785
+ const CARD_NO_TRUNCATE =
786
+ "large:[&_.truncate]:whitespace-normal large:[&_.truncate]:[overflow-wrap:anywhere]";
787
+
788
+ /**
789
+ * Columns as label-above-value pairs: the phone card's fields at Large (§4), and the
790
+ * opened row's `mobileDetailsInRow` at every size. Each pair is a `<div>` in the
791
+ * `<dl>` — the grouping HTML allows — so a pair keeps together and the gap falls
792
+ * BETWEEN facts rather than between a label and its own value. `relative` holds a
793
+ * header's `sr-only` text (an actions column's), as every kit container must.
794
+ */
795
+ function StackedFields<T>({ columns, row, compact }: { columns: DataTableColumn<T>[]; row: T; compact: boolean }) {
796
+ return (
797
+ <dl
798
+ data-card-fields="stacked"
799
+ className={cn("relative flex min-w-0 flex-col", compact ? "gap-1.5 text-xs" : "gap-2.5 text-sm", CARD_NO_TRUNCATE)}
800
+ >
801
+ {columns.map((col) => (
802
+ <div key={col.key} className="min-w-0">
803
+ <dt className="text-xs uppercase tracking-wide text-[var(--text-muted)]">{col.header}</dt>
804
+ <dd
805
+ {...dataAttrsOf(col.cellProps?.(row))}
806
+ className="mt-0.5 min-w-0 break-words text-[var(--text-secondary)]"
807
+ >
808
+ {col.cell(row)}
809
+ </dd>
810
+ </div>
811
+ ))}
812
+ </dl>
813
+ );
814
+ }
815
+
737
816
  // ---------- Phone sort control (keksdose K10) ----------
738
817
 
739
818
  /**
@@ -813,7 +892,9 @@ function MobileSort<T>({
813
892
  <div
814
893
  data-table-mobile-sort=""
815
894
  className={cn(
816
- "flex items-center gap-2 border-b border-[var(--border)]",
895
+ // At Large the direction button shows its words (IconButton's label, §4); the
896
+ // row wraps so the select keeps a usable width on a 240 px card.
897
+ "flex flex-wrap items-center gap-2 border-b border-[var(--border)]",
817
898
  compact ? "px-3 py-1.5" : "px-4 py-2",
818
899
  )}
819
900
  >
@@ -823,7 +904,7 @@ function MobileSort<T>({
823
904
  <Select
824
905
  id={selectId}
825
906
  size={compact ? "sm" : "md"}
826
- className="min-w-0 flex-1"
907
+ className="min-w-0 flex-1 large:basis-40"
827
908
  value={primary?.key ?? ""}
828
909
  onChange={(e) => onPick(e.target.value || null)}
829
910
  >
@@ -1014,6 +1095,8 @@ export function DataTable<T>({
1014
1095
  locale: localeProp,
1015
1096
  storageKeyPrefix = DEFAULT_PERSIST_PREFIX,
1016
1097
  mobileExpandAsDialog = false,
1098
+ mobileDetailsInRow = false,
1099
+ rowName,
1017
1100
  mobileDialogBackCloses = true,
1018
1101
  mobileGroupBy,
1019
1102
  mobileGroupLabel,
@@ -1085,24 +1168,19 @@ export function DataTable<T>({
1085
1168
  {
1086
1169
  key: ROW_ACTIONS_KEY,
1087
1170
  header: <span className="sr-only">{labels.actions}</span>,
1171
+ // Through RowActions (0.32, §10.8): the icons inline at Normal, one "⋯"
1172
+ // menu at Large once there are two — every label at once does not fit a
1173
+ // row. Each control stops its own click: the row's handler already skips
1174
+ // its controls, and this is for the caller who wraps the table in a
1175
+ // clickable element of their own.
1088
1176
  cell: (row) => (
1089
- <div className="flex items-center justify-end gap-0.5">
1090
- {rowActionsFor(row).map((a) => (
1091
- <IconButton
1092
- key={a.key}
1093
- size={density === "compact" ? "2xs" : "xs"}
1094
- label={a.label}
1095
- tone={a.tone === "danger" ? "danger" : undefined}
1096
- disabledReason={a.action.disabledReason?.(row)}
1097
- // The row's click handler already skips its own controls; this is for
1098
- // the caller who wraps the table in a clickable element of their own.
1099
- stopPropagation
1100
- onClick={() => void runRowAction(a.action, row)}
1101
- >
1102
- {a.icon}
1103
- </IconButton>
1104
- ))}
1105
- </div>
1177
+ <RowActions
1178
+ actions={rowActionsFor(row).map((a) => toRowAction(a, row))}
1179
+ name={rowName?.(row)}
1180
+ size={density === "compact" ? "2xs" : "xs"}
1181
+ labels={{ actions: labels.actions }}
1182
+ className="justify-end"
1183
+ />
1106
1184
  ),
1107
1185
  className: "w-px whitespace-nowrap text-end",
1108
1186
  headClassName: "w-px",
@@ -1112,7 +1190,7 @@ export function DataTable<T>({
1112
1190
  },
1113
1191
  ]
1114
1192
  : columnsProp,
1115
- [columnsProp, rowActions, rowActionsFor, labels.actions, density],
1193
+ [columnsProp, rowActions, rowActionsFor, rowName, labels.actions, density],
1116
1194
  );
1117
1195
  const swipesFromActions = (row: T): MobileSwipeActions | null => {
1118
1196
  const swipes = rowActionsFor(row).filter((a) => a.swipe && !a.action.disabledReason?.(row));
@@ -1575,10 +1653,15 @@ export function DataTable<T>({
1575
1653
  const columnsCountLabel = rowActions
1576
1654
  ? labels.columnsCount(visibleCount - 1, totalCount - 1)
1577
1655
  : labels.columnsCount(visibleCount, totalCount);
1578
- // Match Tailwind's `md` breakpoint: we render either the table or the card
1579
- // list — never both — so we don't double up DOM nodes that screen readers and
1580
- // integration tests would have to disambiguate.
1581
- const isMdUp = useMediaQuery("(min-width: 768px)", true);
1656
+ // Match the `md:` breakpoint at the text size in force: we render either the table or
1657
+ // the card list — never both — so we don't double up DOM nodes that screen readers and
1658
+ // integration tests would have to disambiguate. `usePhoneLayout()` itself, not its twin
1659
+ // `useBreakpoint("md")`: the same query an app's own phone checks ask (keksdose's
1660
+ // sticky editor footer), so the card list and the full-screen row dialog switch with
1661
+ // them and never a frame apart (§10.4 "usePhoneLayout() is the single answer"; 0.32.1,
1662
+ // keksdose's 0.32 report, where `md` and `max-md` both missed at 767.5 px). Without
1663
+ // `matchMedia` (SSR, jsdom) it is the table, as before.
1664
+ const isMdUp = !usePhoneLayout();
1582
1665
  // `edgeFade` (0.25) on the desktop scroller; the phone list never scrolls sideways.
1583
1666
  const desktopScroller = useRef<HTMLDivElement | null>(null);
1584
1667
  const edgeFadeProps = useEdgeFade(desktopScroller, edgeFade && isMdUp);
@@ -1592,6 +1675,26 @@ export function DataTable<T>({
1592
1675
  const mobilePrimaryCol =
1593
1676
  mobileColumns.find((c) => c.mobilePrimary) ?? mobileColumns[0] ?? null;
1594
1677
  const mobileSecondaryColumns = mobileColumns.filter((c) => c !== mobilePrimaryCol);
1678
+ // The columns the card leaves out, for the opened row (`mobileDetailsInRow`).
1679
+ const mobileDetailColumns = mobileDetailsInRow ? visibleColumns.filter((c) => c.mobileHidden) : [];
1680
+ // Large and Extra large (§4 "DataTable phone card"): the card's labels go ABOVE their
1681
+ // values, nothing in it truncates, and the rows get more room. Most of it is a
1682
+ // `large:` class; the label/value grid needs a different STRUCTURE (each pair in a
1683
+ // box of its own), which a class cannot write.
1684
+ const large = useLargeText();
1685
+ // What an opened phone row shows: the card's left-out columns first (when asked
1686
+ // for), then the app's own `expandedRow`. Desktop keeps `expandedRow` alone.
1687
+ const opensRow = !!expandedRow || mobileDetailColumns.length > 0;
1688
+ const openedRowContent = (row: T): ReactNode => {
1689
+ const detail = expandedRow?.(row) ?? null;
1690
+ if (mobileDetailColumns.length === 0) return detail;
1691
+ return (
1692
+ <div data-row-details="" className={cn("flex flex-col", compact ? "gap-2" : "gap-3")}>
1693
+ <StackedFields columns={mobileDetailColumns} row={row} compact={compact} />
1694
+ {detail}
1695
+ </div>
1696
+ );
1697
+ };
1595
1698
  // The phone card IS the anchor, so unlike the desktop table there is no other
1596
1699
  // cell to move the row link into: if any cell the card renders owns a link, the
1597
1700
  // card itself cannot be one (feedback #451 — same nesting rule as `linkColumn`
@@ -1679,7 +1782,7 @@ export function DataTable<T>({
1679
1782
  // When dialog-mode is on, the expanded row's detail goes into a bottom-sheet
1680
1783
  // modal instead of unfolding inline. Only one row is ever expanded at a time.
1681
1784
  const mobileDialogRow = mobileExpandAsDialog && !isMdUp ? mobileSlice.find((r) => isExpanded?.(r)) : undefined;
1682
- const mobileDialogContent = mobileDialogRow ? expandedRow?.(mobileDialogRow) : null;
1785
+ const mobileDialogContent = mobileDialogRow ? openedRowContent(mobileDialogRow) : null;
1683
1786
  // The full-screen row dialog. Its panel, header, scroll lock and Back handling all
1684
1787
  // live in {@link FullBleedDialog} now — this was the only copy of that shell until
1685
1788
  // the transactions create card needed the same one (Keksdose live #307's follow-up),
@@ -1694,7 +1797,7 @@ export function DataTable<T>({
1694
1797
  // share identical row markup.
1695
1798
  const renderMobileRow = (row: T) => {
1696
1799
  const expanded = isExpanded?.(row) ?? false;
1697
- const expansion = expanded ? expandedRow?.(row) : null;
1800
+ const expansion = expanded ? openedRowContent(row) : null;
1698
1801
  const tint = rowClassName?.(row);
1699
1802
  // Use div+role="button" rather than a real <button> so cells that
1700
1803
  // contain their own interactive controls (status toggles, action
@@ -1706,7 +1809,7 @@ export function DataTable<T>({
1706
1809
  // values are not editable". A chevron is the affordance every list on a phone
1707
1810
  // uses for exactly this, and it points the way the row actually opens: right into
1708
1811
  // a sheet, or down into an inline panel that flips it when expanded.
1709
- const opensDetail = interactive && !!expandedRow;
1812
+ const opensDetail = interactive && opensRow;
1710
1813
  const swipeActions = swipeActionsFor?.(row);
1711
1814
  const swipe = swipeActions ? physicalSwipe(swipeActions, mobileDir) : null;
1712
1815
  // An expanded row never swipes: the editor below it owns the horizontal space,
@@ -1715,7 +1818,8 @@ export function DataTable<T>({
1715
1818
  const href = mobileCardLinkable ? rowHref?.(row) : undefined;
1716
1819
  const cardClass = cn(
1717
1820
  "w-full text-start flex items-center",
1718
- compact ? "px-3 py-2 gap-2 text-sm" : "px-4 py-3 gap-3",
1821
+ // §4: more room per row at Large — a taller row is a bigger tap target too.
1822
+ compact ? "px-3 py-2 gap-2 text-sm large:py-3" : "px-4 py-3 gap-3 large:py-4",
1719
1823
  // Live #320's other half: the card acknowledges the touch before the sheet
1720
1824
  // arrives. On a cold route the data can take a beat, and an unacknowledged tap
1721
1825
  // reads as "did that register?" — which is most of what "abrupt" means here.
@@ -1731,8 +1835,7 @@ export function DataTable<T>({
1731
1835
  // AppShell main's `overflow-x-clip` — so the frame went missing on one side. A press
1732
1836
  // keeps the fill and the squeeze above; an outline on every tap of a long list would
1733
1837
  // be louder than the acknowledgement it replaces.
1734
- interactive &&
1735
- "[-webkit-tap-highlight-color:transparent] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--brand)]",
1838
+ interactive && cn("[-webkit-tap-highlight-color:transparent] focus-visible:ring-inset", FOCUS_RING),
1736
1839
  );
1737
1840
  // The card's content is written once and worn by either tag below. Note that
1738
1841
  // the primary cell is rendered RAW here, never through `linkColumn` — the card
@@ -1743,18 +1846,31 @@ export function DataTable<T>({
1743
1846
  <>
1744
1847
  {/* The card's own content keeps the column it always had; the chevron sits
1745
1848
  beside it rather than inside, so a caller's `mobileCard` is untouched. */}
1746
- <div className={cn("flex min-w-0 flex-1 flex-col", compact ? "gap-1" : "gap-2")}>
1849
+ <div
1850
+ className={cn(
1851
+ "flex min-w-0 flex-1 flex-col",
1852
+ compact ? "gap-1 large:gap-2" : "gap-2 large:gap-3",
1853
+ // §4 "nothing truncates": at Large a cell's own `truncate` wraps instead —
1854
+ // the reader who chose bigger type is the one an ellipsis fails. A caller's
1855
+ // `mobileCard` is its own layout and keeps what it chose.
1856
+ !mobileCard && CARD_NO_TRUNCATE,
1857
+ )}
1858
+ >
1747
1859
  {mobileCard ? (
1748
1860
  mobileCard(row)
1749
1861
  ) : (
1750
1862
  <>
1751
1863
  {/* Only the `data-*` half of `cellProps` — see its note. */}
1752
1864
  {mobilePrimaryCol && (
1753
- <div {...dataAttrsOf(mobilePrimaryCol.cellProps?.(row))} className="font-medium">
1865
+ <div {...dataAttrsOf(mobilePrimaryCol.cellProps?.(row))} className="min-w-0 break-words font-medium">
1754
1866
  {mobilePrimaryCol.cell(row)}
1755
1867
  </div>
1756
1868
  )}
1757
- {mobileSecondaryColumns.length > 0 && (
1869
+ {mobileSecondaryColumns.length > 0 && large ? (
1870
+ // §4: each label ABOVE its value at Large. Side by side, a label column
1871
+ // sized to the widest label leaves a value a sliver of a 240 px card.
1872
+ <StackedFields columns={mobileSecondaryColumns} row={row} compact={compact} />
1873
+ ) : mobileSecondaryColumns.length > 0 && (
1758
1874
  <dl
1759
1875
  className={cn(
1760
1876
  "grid grid-cols-[auto_1fr] gap-x-3",
@@ -1807,7 +1923,7 @@ export function DataTable<T>({
1807
1923
  <RowLink
1808
1924
  href={href}
1809
1925
  onActivate={() => onRowClick!(row)}
1810
- aria-expanded={expandedRow ? expanded : undefined}
1926
+ aria-expanded={opensRow ? expanded : undefined}
1811
1927
  className={cardClass}
1812
1928
  // Enter already activates a link natively, and that routes through
1813
1929
  // RowLink's own onClick — handling it here too would open the row twice.
@@ -1848,7 +1964,7 @@ export function DataTable<T>({
1848
1964
  }
1849
1965
  : undefined
1850
1966
  }
1851
- aria-expanded={expandedRow ? expanded : undefined}
1967
+ aria-expanded={opensRow ? expanded : undefined}
1852
1968
  className={cardClass}
1853
1969
  >
1854
1970
  {cardInner}
@@ -2238,7 +2354,7 @@ export function DataTable<T>({
2238
2354
  )}
2239
2355
  {/* Priority badge, only meaningful with 2+ sort keys */}
2240
2356
  {active && sorts.length > 1 && (
2241
- <span className="text-[9px] font-semibold leading-none text-brand">
2357
+ <span className="text-micro font-semibold leading-none text-brand">
2242
2358
  {sortIdx + 1}
2243
2359
  </span>
2244
2360
  )}
@@ -2246,7 +2362,9 @@ export function DataTable<T>({
2246
2362
  </Tooltip>
2247
2363
  {filter && (
2248
2364
  <Popover
2249
- width={filter.type === "date" ? 420 : undefined}
2365
+ // 420 px at Normal, in rem so the calendar grows with its
2366
+ // text (§3.2); Popover caps it at the viewport.
2367
+ width={filter.type === "date" ? "26.25rem" : undefined}
2250
2368
  // The panel is the column's filter, and says so. Unnamed it
2251
2369
  // was announced as the kit-wide fallback, "Popover".
2252
2370
  labels={{ panel: labels.filter }}
@@ -2364,8 +2482,11 @@ export function DataTable<T>({
2364
2482
  className={cn(
2365
2483
  "border-t border-[var(--border)]",
2366
2484
  rowInteractive && "cursor-pointer hover:bg-[var(--bg-hover)]",
2485
+ // The kit's focus frame width (§5, `--focus-ring-width`), drawn as an
2486
+ // OUTLINE rather than FOCUS_RING's box-shadow: a shadow on a `<tr>`
2487
+ // is not painted by every engine, an outline is.
2367
2488
  rowsFocusable &&
2368
- "focus-visible:bg-[var(--bg-hover)] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--brand)]",
2489
+ "focus-visible:bg-[var(--bg-hover)] focus-visible:outline-[length:var(--focus-ring-width)] focus-visible:-outline-offset-2 focus-visible:outline-[var(--brand)]",
2369
2490
  rowClassName?.(row),
2370
2491
  )}
2371
2492
  onClick={
@@ -2787,7 +2908,7 @@ function MobileFilters<T>({
2787
2908
  <Filter className="size-4" />
2788
2909
  <span>{labels.filters}</span>
2789
2910
  {activeCount > 0 && (
2790
- <span className="inline-flex min-w-4 items-center justify-center rounded-full bg-[var(--info-bg)] px-1 text-[11px] font-semibold text-[var(--info)]">
2911
+ <span className="inline-flex min-w-4 items-center justify-center rounded-full bg-[var(--info-bg)] px-1 text-caption font-semibold text-[var(--info)]">
2791
2912
  {activeCount}
2792
2913
  </span>
2793
2914
  )}
@@ -15,10 +15,11 @@ import {
15
15
  } from "../i18n/kit-labels";
16
16
  import { splitTriggerAria } from "./trigger-aria";
17
17
  import type { TriggerAria } from "./trigger-aria";
18
- import { Button, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID, PHONE_QUERY } from "./ui";
18
+ import { Button, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from "./ui";
19
+ import { FOCUS_RING_WIDTH } from "./focus-ring";
19
20
  import { FieldBox, FieldLabelLine, useFieldMessages } from "./field-parts";
20
21
  import { FullBleedDialog } from "./full-bleed-dialog";
21
- import { useMediaQuery } from "../hooks/use-media-query";
22
+ import { usePhoneLayout, type RemLength } from "../hooks/use-breakpoint";
22
23
  import { DEFAULT_MINI_CALENDAR_LABELS, MiniCalendar, type MiniCalendarProps } from "./mini-calendar";
23
24
  import { DEFAULT_MONTH_PICKER_LABELS } from "./month-picker";
24
25
  import { Popover } from "./popover";
@@ -205,6 +206,16 @@ function CustomTrigger({
205
206
  return render(attrs, valueId);
206
207
  }
207
208
 
209
+ /**
210
+ * The trigger's value wraps instead of truncating at Large and Extra large (0.32.1, the
211
+ * 360 px Extra-large sweep; docs/text-size-harmonization.md §4 "nothing truncates"). A
212
+ * range ("01/09/2026 – 30/09/2026") is 312 px at 150 %, and on a 360 px phone it read
213
+ * "01/09/2026 – 30/…" — its end, the half a reader needs, was the half cut off. It breaks
214
+ * at its spaces; a single date breaks only where it cannot fit at all. A `large:` class,
215
+ * so Normal keeps its one-line field.
216
+ */
217
+ const VALUE_WRAP_AT_LARGE = "large:whitespace-normal large:break-words";
218
+
208
219
  /**
209
220
  * The field-shaped button that opens the calendar.
210
221
  *
@@ -319,7 +330,7 @@ function DateFieldTrigger({
319
330
 
320
331
  return (
321
332
  <button {...attrs}>
322
- <span id={valueId} className={cn("truncate", !hasValue && "text-[var(--text-placeholder)]")}>
333
+ <span id={valueId} className={cn("truncate", VALUE_WRAP_AT_LARGE, !hasValue && "text-[var(--text-placeholder)]")}>
323
334
  {/* `|| " "` (a NON-BREAKING space) — triggerText is "" when there is no value and no
324
335
  placeholder was passed. An empty span has no line box, so the
325
336
  trigger collapses to its padding and sits shorter than every
@@ -395,11 +406,12 @@ function DateField({
395
406
  panelLabel: string;
396
407
  invalid?: boolean;
397
408
  className?: string;
398
- /** Popover panel width; omit for the default (a bare calendar). */
399
- width?: number;
409
+ /** Popover panel width; omit for the default (a bare calendar). In rem so it grows
410
+ * with the text size, like the Popover's own default (§3.2). */
411
+ width?: number | RemLength;
400
412
  onClear: () => void;
401
413
  /** Open as a full-screen sheet instead of the popover — the picker decides when
402
- * (below {@link PHONE_QUERY}). */
414
+ * (in the phone layout, `usePhoneLayout()`). */
403
415
  sheet?: boolean;
404
416
  /** The sheet's `FullBleedDialog backCloses`. */
405
417
  sheetBackCloses?: boolean;
@@ -556,6 +568,23 @@ function DateField({
556
568
  );
557
569
  }
558
570
 
571
+ /**
572
+ * The ‹ date › (today) row on a phone at Large and Extra large (0.32.1, the 360 px
573
+ * Extra-large sweep; docs/text-size-harmonization.md §4): the field takes the first line
574
+ * on its own, whole and with all four corners, and the buttons share the line under it
575
+ * as one joined strip. Three 2.5rem buttons are 180 px at 150 %, and on a 360 px phone
576
+ * they left the field 84 px — "Book… 0" for "Booking date 07/09/2026" — where a 360 px
577
+ * row would hold the date only by cutting it. `large:max-sm:`, the scaled phone width,
578
+ * so a tablet or a desktop at Large keeps the one row, and Normal is unchanged.
579
+ */
580
+ const STEP_ROW_STACK_AT_LARGE = cn(
581
+ "large:max-sm:flex-wrap large:max-sm:gap-y-2",
582
+ "large:max-sm:[&>[data-slot=date-step-field]]:order-first large:max-sm:[&>[data-slot=date-step-field]]:basis-full",
583
+ "large:max-sm:[&>[data-slot=date-step-field]]:ms-0 large:max-sm:[&_[role=combobox]]:rounded-md",
584
+ // The buttons (each in its tooltip's wrapper) share the line under the field.
585
+ "large:max-sm:[&>span]:flex-1 large:max-sm:[&>span>button]:w-full",
586
+ );
587
+
559
588
  /** One ‹ / › day-step button, sized to sit flush beside the field. */
560
589
  function StepButton({
561
590
  icon: Icon,
@@ -943,7 +972,8 @@ function JumpCalendar({
943
972
  // 44px rows: the touch-target size, and four of them stand as tall
944
973
  // as a month of days, so the panel does not jump as the views swap.
945
974
  "h-11 rounded px-1 text-sm tabular-nums transition-colors",
946
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset",
975
+ FOCUS_RING_WIDTH,
976
+ "focus-visible:outline-none focus-visible:ring-inset",
947
977
  // A --brand ring on a --brand fill exists only in the DOM.
948
978
  end && !disabled ? "focus-visible:ring-[var(--brand-contrast)]" : "focus-visible:ring-[var(--brand)]",
949
979
  disabled
@@ -1102,6 +1132,9 @@ export function DatePicker(props: DatePickerProps) {
1102
1132
  disabled={disabled}
1103
1133
  invalid={messages.isInvalid}
1104
1134
  className={step ? "min-w-0 flex-1" : className}
1135
+ // Named for STEP_ROW_STACK_AT_LARGE; only in the row, so a caller's own
1136
+ // `data-slot` on a bare field is left alone.
1137
+ {...(wrapped ? { "data-slot": "date-step-field" } : {})}
1105
1138
  hasValue={Boolean(value)}
1106
1139
  triggerText={value ? render(value) : (placeholder ?? "")}
1107
1140
  onClear={() => onChange("")}
@@ -1170,6 +1203,7 @@ export function DatePicker(props: DatePickerProps) {
1170
1203
  // the trigger, which raising the trigger alone covered. Hover raises nothing: it
1171
1204
  // changes no border, and would let a hovered › cover a focused field's edge.
1172
1205
  "[&>*:focus-within]:z-20 [&>*:active]:z-20 [&>*:has([aria-invalid=true])]:z-10",
1206
+ STEP_ROW_STACK_AT_LARGE,
1173
1207
  className,
1174
1208
  )}
1175
1209
  >
@@ -1288,7 +1322,7 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
1288
1322
  */
1289
1323
  renderTrigger?: (props: DateRangeTriggerRenderProps) => ReactNode;
1290
1324
  /**
1291
- * Below {@link PHONE_QUERY} the panel opens as a full-screen sheet (`FullBleedDialog`)
1325
+ * In the phone layout (`usePhoneLayout()`) the panel opens as a full-screen sheet (`FullBleedDialog`)
1292
1326
  * with presets in a grid above the calendar and Apply pinned in the footer, instead
1293
1327
  * of the 440px popover that hung off a 360px screen (keksdose's report range field,
1294
1328
  * which hand-rolled exactly this). This is its `backCloses`: on by default, so Back
@@ -1615,7 +1649,7 @@ export function DateRangePicker(props: DateRangePickerProps) {
1615
1649
  : `${a}${separator}…`
1616
1650
  : (placeholder ?? "");
1617
1651
  const hasPresets = Boolean(presets && presets.length > 0);
1618
- const sheet = useMediaQuery(PHONE_QUERY, false);
1652
+ const sheet = usePhoneLayout();
1619
1653
  const commitRange = (f: string, t: string, presetId: string | undefined) => {
1620
1654
  setOwnPreset(presetId);
1621
1655
  // Two arguments when no preset is involved — exactly the 0.7 call, so a caller's
@@ -1635,7 +1669,7 @@ export function DateRangePicker(props: DateRangePickerProps) {
1635
1669
  disabled={disabled}
1636
1670
  invalid={messages.isInvalid}
1637
1671
  // Widen so the preset column sits beside the calendar (default otherwise).
1638
- width={hasPresets ? 440 : undefined}
1672
+ width={hasPresets ? "27.5rem" : undefined}
1639
1673
  hasValue={Boolean(from || to)}
1640
1674
  triggerText={triggerText}
1641
1675
  onClear={() => commitRange("", "", undefined)}
@@ -165,7 +165,7 @@ export function DescriptionList({
165
165
  ? { gridTemplateColumns: `repeat(auto-fill, minmax(min(100%, ${track}), 1fr))` }
166
166
  : undefined;
167
167
  const ctx: ListContextValue = { layout, numeric, prose, density, columns: columns ?? 2, placeholder };
168
- const text = density === "tight" ? "text-[11px] leading-4" : density === "compact" ? "text-xs" : "text-sm";
168
+ const text = density === "tight" ? "text-caption leading-4" : density === "compact" ? "text-xs" : "text-sm";
169
169
 
170
170
  if (stacked) {
171
171
  return (
@@ -299,7 +299,7 @@ export function DescriptionItem({
299
299
  <dt
300
300
  className={cn(
301
301
  "flex min-w-0 items-center gap-1 text-[var(--text-muted)]",
302
- cards && (density === "tight" ? "text-[10px] uppercase tracking-wide" : "text-xs uppercase tracking-wide"),
302
+ cards && (density === "tight" ? "text-micro uppercase tracking-wide" : "text-xs uppercase tracking-wide"),
303
303
  // Stacked terms are a step smaller than the detail, as kastlan's dialogs set
304
304
  // them; in a list that is already small they stay the list's own size.
305
305
  stacked && density === "comfortable" && "text-xs",
@@ -3,6 +3,7 @@ import type { ReactNode } from "react";
3
3
  import { X } from "lucide-react";
4
4
 
5
5
  import { cn } from "../lib/cn";
6
+ import { FOCUS_RING } from "./focus-ring";
6
7
  import { Modal, ModalCloseContext } from "./modal";
7
8
  import type { ModalProps } from "./modal";
8
9
  import { useKitLabels } from "../i18n/kit-labels";
@@ -211,7 +212,7 @@ function FrameClose({ label, onClose }: { label?: string; onClose: () => void })
211
212
  type="button"
212
213
  onClick={close}
213
214
  aria-label={labels.close}
214
- className="-me-1.5 -mt-1 shrink-0 rounded p-1.5 text-[var(--text-muted)] outline-none hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)] focus-visible:ring-2 focus-visible:ring-[var(--brand)]"
215
+ className={cn("-me-1.5 -mt-1 shrink-0 rounded p-1.5 text-[var(--text-muted)] outline-none hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)]", FOCUS_RING)}
215
216
  >
216
217
  <X aria-hidden className="size-5" />
217
218
  </button>
@@ -3,6 +3,7 @@ import type { ComponentPropsWithoutRef, ReactNode } from "react";
3
3
  import { ChevronDown } from "lucide-react";
4
4
 
5
5
  import { cn } from "../lib/cn";
6
+ import { FOCUS_RING } from "./focus-ring";
6
7
  // Read at the moment of closing, as `useCloseTransition` does: the setting can change
7
8
  // under a long-lived page.
8
9
  import { prefersReducedMotion } from "../hooks/use-close-transition";
@@ -345,10 +346,10 @@ export function Disclosure({
345
346
  // card's hover paint on the stretched area / the row, not the text box.
346
347
  cn(
347
348
  "min-w-0 flex-1 after:absolute after:inset-0 after:content-['']",
348
- "focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-[var(--brand)]",
349
+ "focus-visible:after:ring-[length:var(--focus-ring-width)] focus-visible:after:ring-inset focus-visible:after:ring-[var(--brand)]",
349
350
  card ? cn("after:rounded-lg", joined && "after:rounded-b-none") : !menu && "after:rounded-sm",
350
351
  )
351
- : "focus-visible:ring-2 focus-visible:ring-[var(--brand)]",
352
+ : FOCUS_RING,
352
353
  card
353
354
  ? cn(
354
355
  "items-center justify-between rounded-lg p-4",
@@ -11,6 +11,8 @@ import { useAnchoredPanel } from "../hooks/use-anchored-panel";
11
11
  import { useEscapeKey, useOutsideClick } from "../hooks/use-dismiss";
12
12
  import { useOverlayHistory } from "../hooks/use-overlay-history";
13
13
  import { cn } from "../lib/cn";
14
+ import { FIELD_TOUCH_TEXT } from "./ui";
15
+ import { FOCUS_RING } from "./focus-ring";
14
16
  import { useAnchorDir } from "./use-anchor-dir";
15
17
 
16
18
  /**
@@ -34,7 +36,7 @@ import { useAnchorDir } from "./use-anchor-dir";
34
36
  * while it is up, so the rule is the hook's rather than each caller's. `backCloses`
35
37
  * is for the ONE case where a second entry would be wrong: a caller whose panel is
36
38
  * itself a `PickerSheet`, which already registers one — both comboboxes swap shape at
37
- * {@link PHONE_QUERY}, and two entries would cost two Back presses to close one sheet.
39
+ * the phone layout (`usePhoneLayout()`), and two entries would cost two Back presses to close one sheet.
38
40
  *
39
41
  * ## One outside-click rule for the whole package
40
42
  *
@@ -206,7 +208,13 @@ export function DropdownSearchHeader({
206
208
  aria-controls={listboxId}
207
209
  aria-activedescendant={activeId}
208
210
  aria-autocomplete={listboxId ? "list" : undefined}
209
- className="w-full rounded-sm bg-transparent text-sm outline-none placeholder:text-[var(--text-placeholder)] text-[var(--text-primary)] focus-visible:ring-2 focus-visible:ring-[var(--brand)]"
211
+ // FIELD_TOUCH_TEXT: a search box is a field — at least 16 px on touch, or iOS zooms
212
+ // the page the moment a picker opens and focuses it (§10.1).
213
+ className={cn(
214
+ "w-full rounded-sm bg-transparent text-sm outline-none placeholder:text-[var(--text-placeholder)] text-[var(--text-primary)]",
215
+ FOCUS_RING,
216
+ FIELD_TOUCH_TEXT,
217
+ )}
210
218
  />
211
219
  </div>
212
220
  );
@@ -28,7 +28,9 @@ export type FacingSide = "left" | "right";
28
28
  export const FACING_SIDES: readonly FacingSide[] = ["left", "right"];
29
29
 
30
30
  /** The whole band a facing y axis occupies: its ticks, and the strip the rotated title
31
- * is drawn in — whether or not this chart is the one that spends it. */
31
+ * is drawn in — whether or not this chart is the one that spends it. In px at Normal:
32
+ * it is also the right axis' declared `width`, which the chart scales with the text
33
+ * (see {@link facingHeadingPad} for a heading's). */
32
34
  export function facingBand(tickWidth: number = AXIS_TICK_WIDTH): number {
33
35
  return axisBandWidth(tickWidth, true);
34
36
  }
@@ -75,12 +77,17 @@ export function facingAxes({
75
77
 
76
78
  /** What a column heading is padded by to sit over the PLOT rather than the column: the
77
79
  * axis band, on the side that column's axis stands on. Physical padding on purpose —
78
- * the chart under it does not flip in RTL, so neither may the heading's offset. */
80
+ * the chart under it does not flip in RTL, so neither may the heading's offset.
81
+ *
82
+ * `scale` is the text size's (`useTextSize().scale`): the chart draws its bands that
83
+ * many times wider from Large up (docs/text-size-harmonization.md §10.10), so a heading
84
+ * passes the same factor to stay over its plot. Both sides by the same factor, as the
85
+ * chart does. */
79
86
  export function facingHeadingPad(
80
87
  side: FacingSide,
81
88
  tickWidth: number = AXIS_TICK_WIDTH,
89
+ scale = 1,
82
90
  ): Pick<CSSProperties, "paddingLeft" | "paddingRight"> {
83
- return side === "left"
84
- ? { paddingLeft: facingBand(tickWidth) }
85
- : { paddingRight: facingBand(tickWidth) };
91
+ const band = axisBandWidth(tickWidth, true, scale);
92
+ return side === "left" ? { paddingLeft: band } : { paddingRight: band };
86
93
  }