@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
@@ -2,7 +2,14 @@ import { forwardRef, useId } from "react";
2
2
  import type { ChangeEvent, InputHTMLAttributes, ReactNode } from "react";
3
3
  import { cn } from "../lib/cn";
4
4
  import { hasMessage, mergeDescribedBy } from "./choice-parts";
5
- import { LockedReason, useLockReason } from "./field-parts";
5
+ import {
6
+ DISABLED_REASON_LINE_CLASS,
7
+ LockedReason,
8
+ useDisabledReasonLine,
9
+ useLockReason,
10
+ type DisabledReasonDisplay,
11
+ } from "./field-parts";
12
+ import { FOCUS_RING } from "./focus-ring";
6
13
 
7
14
  /**
8
15
  * An on/off switch that is still `<input type="checkbox">`, with `role="switch"`.
@@ -14,16 +21,20 @@ import { LockedReason, useLockReason } from "./field-parts";
14
21
  * the moment it is flipped; a choice that waits for a Save button is a checkbox.
15
22
  */
16
23
 
17
- /** Geometry per size. The thumb sits `2px` in from each end of the track, so its
18
- * checked offset is `track width − thumb − 2px`. `start-*`, never `left-*` or a
19
- * `translate-x`: an inline-start offset follows the writing direction, so in a
20
- * right-to-left form the thumb travels right-to-left with no `rtl:` override to
21
- * keep in step. */
24
+ /** Geometry per size. The thumb sits `start-0.5` (0.125rem, 2 px at Normal) in from
25
+ * each end of the track, so its checked offset is `track width − thumb − 0.125rem`.
26
+ * All of it in rem since 0.32 (docs/text-size-harmonization.md §3.2, §4): the track
27
+ * and thumb already grew with the text, and a checked offset left in px (14 / 18) put
28
+ * the thumb short of the end at 125 % and in the middle at 150 %. `start-*`, never
29
+ * `left-*` or a `translate-x`: an inline-start offset follows the writing direction,
30
+ * so in a right-to-left form the thumb travels right-to-left with no `rtl:` override
31
+ * to keep in step. */
22
32
  const SIZES = {
23
- // 28×16 track, 12px thumb: the dense setting rows in Kastlan's tables.
24
- sm: { track: "h-4 w-7", thumb: "size-3 peer-checked:start-[14px]" },
25
- // 36×20 track, 16px thumb.
26
- md: { track: "h-5 w-9", thumb: "size-4 peer-checked:start-[18px]" },
33
+ // 1.75 × 1rem track, 0.75rem thumb (28×16 / 12 at Normal): the dense setting rows in
34
+ // Kastlan's tables. Checked: 1.75 − 0.75 − 0.125 = 0.875rem.
35
+ sm: { track: "h-4 w-7", thumb: "size-3 peer-checked:start-3.5" },
36
+ // 2.25 × 1.25rem track, 1rem thumb (36×20 / 16). Checked: 2.25 − 1 − 0.125 = 1.125rem.
37
+ md: { track: "h-5 w-9", thumb: "size-4 peer-checked:start-4.5" },
27
38
  } as const;
28
39
 
29
40
  export type SwitchSize = keyof typeof SIZES;
@@ -38,7 +49,8 @@ export type SwitchSize = keyof typeof SIZES;
38
49
  const TRACK =
39
50
  "peer block shrink-0 cursor-pointer appearance-none rounded-full bg-[var(--border-strong)] transition-colors " +
40
51
  "checked:bg-[var(--brand)] " +
41
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-surface)] " +
52
+ // The kit's focus frame (§5), stood off the track so it never merges with the fill.
53
+ `focus:outline-none ${FOCUS_RING} focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-surface)] ` +
42
54
  "disabled:cursor-not-allowed";
43
55
 
44
56
  // The thumb, laid over the input and ignoring the pointer so every click still reaches
@@ -93,6 +105,13 @@ export interface SwitchProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
93
105
  * switch anew (it moves in or out of the Tooltip), as a locked Button is.
94
106
  */
95
107
  disabledReason?: ReactNode;
108
+ /**
109
+ * Where `disabledReason` shows (0.32, §4 "No fact only in a tooltip"): by default, at
110
+ * Large and on a touch screen, as a line in the words column under the description (a
111
+ * bare switch: under the track), and in the tooltip otherwise. See
112
+ * {@link DisabledReasonDisplay}.
113
+ */
114
+ disabledReasonDisplay?: DisabledReasonDisplay;
96
115
  /**
97
116
  * This switch COMMITS — flipping it saves. Under a locked {@link WriteLockProvider} it
98
117
  * is locked the `disabledReason` way with the lock's reason (which wins over its
@@ -122,6 +141,7 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
122
141
  disabled,
123
142
  required,
124
143
  disabledReason,
144
+ disabledReasonDisplay,
125
145
  commit,
126
146
  onClick,
127
147
  ...rest
@@ -132,6 +152,7 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
132
152
  const inputId = id ?? generated;
133
153
  const lock = useLockReason(commit, disabledReason);
134
154
  const locked = lock.locked;
155
+ const reasonLine = useDisabledReasonLine(disabledReasonDisplay);
135
156
  // Locked is disabled the focusable way — the row fades and the words stop inviting a
136
157
  // click, as for `disabled`.
137
158
  const looksDisabled = Boolean(disabled) || locked;
@@ -177,21 +198,28 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
177
198
  </span>
178
199
  );
179
200
  // The Tooltip goes round the track, not the row — the row is the caller's layout. A
180
- // bare switch hands its `className` to the wrapper, then the outermost element.
181
- const control = locked ? (
182
- <LockedReason lock={lock} className={cn("shrink-0", bare && className)}>
183
- {track}
184
- </LockedReason>
185
- ) : (
186
- track
187
- );
201
+ // bare switch hands its `className` to the wrapper, then the outermost element. With
202
+ // words beside it, the reason LINE goes under them instead (below), so the track
203
+ // stays where the row puts it.
204
+ const lineInWords = locked && reasonLine && !bare;
205
+ const control =
206
+ locked && !lineInWords ? (
207
+ <LockedReason lock={lock} line={reasonLine} className={cn("shrink-0", bare && className)}>
208
+ {track}
209
+ </LockedReason>
210
+ ) : (
211
+ track
212
+ );
188
213
 
189
214
  if (bare) return control;
190
215
 
191
- // The switch's cell is one label line tall (text-sm, 20px) so it centres on the
216
+ // The switch's cell is one label line tall (text-sm, 1.25rem) so it centres on the
192
217
  // FIRST line of a label that wraps, and a description underneath does not drag it
193
218
  // down to the middle of the paragraph.
194
- const cell = <span className="flex h-5 shrink-0 items-center">{control}</span>;
219
+ // With the reason line in the words, the row's fade moves onto its parts: the line is
220
+ // the one thing on the row still to be read, and at 60 % it would not be.
221
+ const dimParts = lineInWords;
222
+ const cell = <span className={cn("flex h-5 shrink-0 items-center", dimParts && "opacity-60")}>{control}</span>;
195
223
  const words = (
196
224
  <span className="min-w-0 flex-1">
197
225
  {label !== undefined && (
@@ -200,6 +228,7 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
200
228
  className={cn(
201
229
  "block text-sm leading-5 text-[var(--text-primary)]",
202
230
  looksDisabled ? "cursor-not-allowed" : "cursor-pointer select-none",
231
+ dimParts && "opacity-60",
203
232
  )}
204
233
  >
205
234
  {label}
@@ -211,15 +240,20 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
211
240
  </label>
212
241
  )}
213
242
  {showDescription && (
214
- <span id={descriptionId} className="mt-0.5 block text-xs text-[var(--text-muted)]">
243
+ <span id={descriptionId} className={cn("mt-0.5 block text-xs text-[var(--text-muted)]", dimParts && "opacity-60")}>
215
244
  {description}
216
245
  </span>
217
246
  )}
247
+ {lineInWords && (
248
+ <span id={lock.reasonId} className={DISABLED_REASON_LINE_CLASS}>
249
+ {lock.reason}
250
+ </span>
251
+ )}
218
252
  </span>
219
253
  );
220
254
 
221
255
  return (
222
- <div className={cn("flex items-start gap-3", looksDisabled && "opacity-60", className)}>
256
+ <div className={cn("flex items-start gap-3", looksDisabled && !dimParts && "opacity-60", className)}>
223
257
  {switchPosition === "end" ? (
224
258
  <>
225
259
  {words}
@@ -242,7 +242,7 @@ const STACK_PHONE_CLASSES = cn(
242
242
  "max-sm:[&_tbody_td]:block max-sm:[&_tbody_td]:px-0 max-sm:[&_tbody_td]:py-0.5 max-sm:[&_tbody_td]:text-start",
243
243
  "max-sm:[&_tfoot_td]:block max-sm:[&_tfoot_td]:px-0 max-sm:[&_tfoot_td]:py-0.5",
244
244
  "max-sm:[&_tbody_td:first-child]:font-medium",
245
- "max-sm:[&_td[data-label]]:before:block max-sm:[&_td[data-label]]:before:text-[11px] max-sm:[&_td[data-label]]:before:font-medium max-sm:[&_td[data-label]]:before:text-[var(--text-muted)] max-sm:[&_td[data-label]]:before:content-[attr(data-label)]",
245
+ "max-sm:[&_td[data-label]]:before:block max-sm:[&_td[data-label]]:before:text-caption max-sm:[&_td[data-label]]:before:font-medium max-sm:[&_td[data-label]]:before:text-[var(--text-muted)] max-sm:[&_td[data-label]]:before:content-[attr(data-label)]",
246
246
  );
247
247
 
248
248
  /**
@@ -353,7 +353,7 @@ export function Table({
353
353
  // rounded corners.
354
354
  framed && "rounded-md border border-[var(--border)]",
355
355
  THIN_SCROLLBAR_CLASS,
356
- "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--brand)]",
356
+ "focus-visible:outline-[length:var(--focus-ring-width)] focus-visible:-outline-offset-2 focus-visible:outline-[var(--brand)]",
357
357
  wrapperClassName,
358
358
  )}
359
359
  >
@@ -288,7 +288,7 @@ export function TextLink({
288
288
 
289
289
  const look = cn(
290
290
  "rounded-sm underline-offset-2 transition-colors",
291
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--brand)]",
291
+ "focus-visible:outline-[length:var(--focus-ring-width)] focus-visible:outline-offset-2 focus-visible:outline-[var(--brand)]",
292
292
  TONE[tone],
293
293
  UNDERLINE[underline],
294
294
  ariaCurrent && "font-semibold",
@@ -35,10 +35,14 @@ export type SectionLabelSize = "xs" | "md" | "sm";
35
35
  * reached as a string than wrapped in a component that only takes a `className`. The
36
36
  * uppercase is CSS, so a screen reader reads the text as written: write it in normal
37
37
  * case.
38
+ *
39
+ * The sizes are the kit's named rem steps since 0.32 (`text-micro` 0.625rem,
40
+ * `text-caption` 0.6875rem — 10 and 11 px at Normal), so a label grows with the text
41
+ * size like everything around it (docs/text-size-harmonization.md §3.2).
38
42
  */
39
43
  export const SECTION_LABEL_CLASS: Record<SectionLabelSize, string> = {
40
- xs: "text-[10px] font-semibold uppercase tracking-wide text-[var(--text-muted)]",
41
- md: "text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)]",
44
+ xs: "text-micro font-semibold uppercase tracking-wide text-[var(--text-muted)]",
45
+ md: "text-caption font-semibold uppercase tracking-wide text-[var(--text-muted)]",
42
46
  sm: "text-xs font-semibold uppercase tracking-wide text-[var(--text-muted)]",
43
47
  };
44
48
 
@@ -61,8 +65,8 @@ export type SectionLabelVariant = "plain" | "band";
61
65
  * a font-size arbitrary `text-` value from a colour one. (Not spelt out as class
62
66
  * names here: Tailwind scans comments, and a literal one broke the showcase CSS.) */
63
67
  const SECTION_LABEL_BAND_CLASS: Record<SectionLabelSize, string> = {
64
- xs: "text-[10px]",
65
- md: "text-[11px]",
68
+ xs: "text-micro",
69
+ md: "text-caption",
66
70
  sm: "text-xs",
67
71
  };
68
72
  const BAND =
@@ -112,14 +116,15 @@ export function SectionLabel({
112
116
  /* ── Caption ──────────────────────────────────────────────────────────────── */
113
117
 
114
118
  /**
115
- * The caption type as a class string: 11px, snug, muted. lenkbank's `CAPTION`
119
+ * The caption type as a class string: `text-caption` (0.6875rem, 11 px at Normal, §3.2),
120
+ * snug, muted. lenkbank's `CAPTION`
116
121
  * (shared/ui/caption.ts:23) — written out 31 times before it was a constant — as a
117
122
  * token colour rather than `slate-500 dark:slate-400`, so it follows the palette.
118
123
  * Exported for the same reason lenkbank's is a string: every caller positions it
119
124
  * differently (`mt-1`, `self-end pb-2`, `border-t`), and what must be one thing is the
120
125
  * type, not the box.
121
126
  */
122
- export const CAPTION_CLASS = "text-[11px] leading-snug text-[var(--text-muted)]";
127
+ export const CAPTION_CLASS = "text-caption leading-snug text-[var(--text-muted)]";
123
128
 
124
129
  export interface CaptionProps extends ComponentPropsWithoutRef<"p"> {
125
130
  /** Default `p`; `span` for a caption inside a line of other content. */
@@ -2,6 +2,7 @@ import { useId, useRef } from "react";
2
2
  import type { KeyboardEvent, ReactNode } from "react";
3
3
  import { Ban, Check } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
5
+ import { FOCUS_RING } from "./focus-ring";
5
6
  import { horizontalStep } from "../lib/direction";
6
7
  import { Tooltip } from "./tooltip";
7
8
 
@@ -133,7 +134,9 @@ export interface TileRadioGroupProps<T extends string> {
133
134
  */
134
135
  const TILE_BASE =
135
136
  "relative inline-flex shrink-0 items-center justify-center rounded-md border transition-colors " +
136
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-surface)] " +
137
+ "focus:outline-none " +
138
+ FOCUS_RING +
139
+ " focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-surface)] " +
137
140
  "disabled:cursor-not-allowed disabled:opacity-50";
138
141
  const TILE_IDLE =
139
142
  "border-[var(--border)] bg-[var(--bg-surface)] hover:border-[var(--border-strong)] hover:bg-[var(--bg-hover)]";
@@ -1,8 +1,7 @@
1
1
  import { useEffect, useState, useSyncExternalStore } from "react";
2
2
  import type { CSSProperties, MouseEvent, ReactElement, ReactNode } from "react";
3
3
  import { useKitLabels } from "../i18n/kit-labels";
4
- import { useMediaQuery } from "../hooks/use-media-query";
5
- import { PHONE_QUERY } from "./ui";
4
+ import { usePhoneLayout } from "../hooks/use-breakpoint";
6
5
 
7
6
  /**
8
7
  * The kit's toast layer: a `toast` API and a `<Toaster>`, over sonner.
@@ -298,7 +297,9 @@ export type ToastPosition =
298
297
 
299
298
  export type ToastSwipeDirection = "top" | "right" | "bottom" | "left";
300
299
 
301
- /** sonner's offset: one value for every edge, or per edge. Numbers are px. */
300
+ /** sonner's offset: one value for every edge, or per edge. Numbers are px, which do not
301
+ * follow the text size — prefer a CSS length (rem, or a `calc()` on
302
+ * {@link TOASTER_OFFSET_TOP} / {@link TOASTER_OFFSET_BOTTOM}). */
302
303
  export type ToasterOffset =
303
304
  | string
304
305
  | number
@@ -397,6 +398,22 @@ function subscribeDocumentTheme(onChange: () => void): () => void {
397
398
 
398
399
  const px = (v: string | number) => (typeof v === "number" ? `${v}px` : v);
399
400
 
401
+ /**
402
+ * The Toaster's default distance from the top edge (desktop), as a CSS length (0.32,
403
+ * docs/text-size-harmonization.md §10.11): below a 3rem top bar with 1rem to spare, and
404
+ * the safe area. In rem, so it moves with the text size along with the top bar — an
405
+ * app's `offset={{ top: 64 }}` (keksdose) did not. Pass it, or a `calc()` built on it,
406
+ * instead of a px number.
407
+ */
408
+ export const TOASTER_OFFSET_TOP = "calc(env(safe-area-inset-top, 0px) + 4rem)";
409
+
410
+ /**
411
+ * The Toaster's default distance from the bottom edge (phone), as a CSS length: above
412
+ * AppShell's measured bottom nav (`--app-nav-h`) or the home indicator, whichever is
413
+ * taller, with 0.75rem to spare.
414
+ */
415
+ export const TOASTER_OFFSET_BOTTOM = "calc(max(var(--app-nav-h, 0px), env(safe-area-inset-bottom, 0px)) + 0.75rem)";
416
+
400
417
  /**
401
418
  * Where the toasts appear, with the kit's defaults — mount ONE, near the root and
402
419
  * inside `<UiKitProvider>` (it reads the `toast` labels) and inside the router if a
@@ -480,14 +497,17 @@ export function Toaster({
480
497
  }, [dismissOnMiddleClick, mod]);
481
498
 
482
499
  const documentTheme = useSyncExternalStore(subscribeDocumentTheme, readDocumentTheme, () => "light" as const);
483
- const phone = useMediaQuery(PHONE_QUERY, false);
500
+ const phone = usePhoneLayout();
484
501
  const resolved: ToastPosition = position ?? (phone ? "bottom-center" : "top-center");
485
502
 
486
503
  // Above the bottom nav and the home indicator: whichever is taller, since the nav
487
504
  // already pads itself by the safe area (the same sum BulkActionBar floats on).
488
- const bottom = `calc(max(${navOffset === undefined ? "var(--app-nav-h, 0px)" : px(navOffset)}, env(safe-area-inset-bottom, 0px)) + 0.75rem)`;
489
- // Below a 48px TopBar with the same 1rem clearance.
490
- const top = "calc(env(safe-area-inset-top, 0px) + 4rem)";
505
+ const bottom =
506
+ navOffset === undefined
507
+ ? TOASTER_OFFSET_BOTTOM
508
+ : `calc(max(${px(navOffset)}, env(safe-area-inset-bottom, 0px)) + 0.75rem)`;
509
+ // Below a 3rem TopBar with the same 1rem clearance.
510
+ const top = TOASTER_OFFSET_TOP;
491
511
  const computed = resolved.startsWith("bottom") ? { bottom } : { top };
492
512
 
493
513
  if (!mod) return null;
@@ -5,7 +5,17 @@ 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
+ isTextHint,
13
+ LabelStrip,
14
+ useDisabledReasonLine,
15
+ useInlineHint,
16
+ type DisabledReasonDisplay,
17
+ } from "./field-parts";
18
+ import { FOCUS_RING_WIDTH } from "./focus-ring";
9
19
 
10
20
  export interface ToggleOption<T extends string> {
11
21
  value: T;
@@ -36,6 +46,11 @@ export interface ToggleGroupBaseProps<T extends string>
36
46
  * whole ("Bewegung", not "Beweg…"), at the price of a taller group on a narrow
37
47
  * screen (lenkbank L4: five signal types on a 390px control page). From the width
38
48
  * where they fit, both look the same.
49
+ *
50
+ * Since 0.32 a group in the field chrome (`label`, the default placement) with four or
51
+ * more options wraps at Large and Extra large under `"truncate"` too, inside its frame:
52
+ * the type is bigger there and the field would otherwise run past a phone's edge
53
+ * (docs/text-size-harmonization.md §4). The keyboard is the same either way.
39
54
  */
40
55
  overflow?: "truncate" | "wrap";
41
56
  /**
@@ -116,8 +131,15 @@ export interface ToggleGroupBaseProps<T extends string>
116
131
  * two stack and both keep their corners.
117
132
  */
118
133
  chromeClassName?: string;
119
- /** A {@link FieldHint} on the label line, as on a labelled {@link Select}. Only with
120
- * `label`. */
134
+ /**
135
+ * As on a labelled {@link Select}: a {@link FieldHint} "?" on the label line, and plain
136
+ * text (a string) as a caption under the group. Only with `label`.
137
+ *
138
+ * 0.32.1 (keksdose's 0.32 report): text went on the label line in every placement, so
139
+ * `TextSizeSetting`'s hint with `labelPlacement="above"` sat beside the label in body
140
+ * type, and at Extra large became a column one word wide — on the setting a reader who
141
+ * needs large text opens first. The label line holds the "?" only (`isTextHint`).
142
+ */
121
143
  hint?: ReactNode;
122
144
  /** The message under the field when it is wrong: paints the field's border with
123
145
  * `--danger`, marks the group `aria-invalid` and describes it with the message, as
@@ -136,6 +158,12 @@ export interface ToggleGroupBaseProps<T extends string>
136
158
  * Wins over `disabled`, as on Button: passing both keeps the group reachable.
137
159
  */
138
160
  disabledReason?: ReactNode;
161
+ /**
162
+ * Where `disabledReason` shows (0.32, §4 "No fact only in a tooltip"): by default, at
163
+ * Large and on a touch screen, as a line under the group (where its caption goes), and
164
+ * in the tooltip over the segments otherwise. See {@link DisabledReasonDisplay}.
165
+ */
166
+ disabledReasonDisplay?: DisabledReasonDisplay;
139
167
  /**
140
168
  * This group COMMITS — choosing an option saves it. Under a locked
141
169
  * {@link WriteLockProvider} it takes the `disabledReason` path with the lock's
@@ -151,6 +179,11 @@ export interface ToggleGroupBaseProps<T extends string>
151
179
  * The field chrome's vertical geometry — keksdose K1, the kit reintroducing feedback
152
180
  * #117 that keksdose's hand-built chrome had fixed.
153
181
  *
182
+ * In px at Normal, as measured; since 0.32 every term but the two borders is rem
183
+ * (§3.2), so the sum stays a labelled Select's at 125 and 150 % too — the Select's own
184
+ * `pt-4 pb-1` and 1.25rem line grow by the same factor (52 px at Large, 62 at Extra
185
+ * large). The md line was `leading-[18px]` and is `leading-[1.125rem]`.
186
+ *
154
187
  * The label is the field's static label: `top-1` and 11px in a `leading-tight` line, so
155
188
  * its line box runs from 4px to 17.75px. Until 0.22 the chrome was `pt-4` over a 20px
156
189
  * (`leading-5`) segment, so the ACTIVE segment's fill — painted from the top of the
@@ -168,7 +201,35 @@ export interface ToggleGroupBaseProps<T extends string>
168
201
  * md: 1 + 20 + 18 + 2 + 1 = 42 sm: 1 + 20 + 16 + 4 + 1 = 42
169
202
  */
170
203
  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" };
204
+ const CHROME_SEGMENT: Record<"sm" | "md", string> = { md: "py-0 leading-[1.125rem]", sm: "py-0 leading-4" };
205
+
206
+ /**
207
+ * A group at Large and Extra large (0.32,
208
+ * docs/text-size-harmonization.md §4 "nothing truncates", §3.3): the segments flow onto a
209
+ * second row inside the group's frame instead of overflowing it. At 125 % a 390 px phone
210
+ * is 312 px of Normal type, and "Month / Quarter / Half-year / Year" in one row of the
211
+ * field ran 7 px past it: a one-row flex group is as wide as all its labels end to end
212
+ * when a grid or a stretched column asks how small it can get, however its segments
213
+ * truncate. Wrapped, it is as wide as its longest label.
214
+ *
215
+ * Wrap, not a stacked select-like list: a wrapped radio group is the same radio group —
216
+ * one Tab stop, and the arrow keys walk the options in reading order whichever row
217
+ * they are on (←/↑ back, →/↓ on, Home/End) — so nothing about the keyboard changes with
218
+ * the text size. A list in its place would be a second widget with its own keys.
219
+ *
220
+ * Only where it has to: `flex-wrap` breaks a row only when the segments do not fit, so
221
+ * a wide field at Large stays one row, and a segment shares out what its row leaves
222
+ * (`flex-1`); a label wider than the whole row still truncates as the last resort.
223
+ * A `large:` class, so it costs no render and is right on the first paint.
224
+ * `overflow="wrap"` wraps at every size already.
225
+ *
226
+ * 0.32.1 (Kurvenschmiede's 0.32 report): every count and every placement but the
227
+ * strip, not only a field of four or more. Since a row breaks only where its labels do
228
+ * not fit, a wrap only ever replaces a truncation — and three options in a card at
229
+ * Extra large on a 360 px phone read "Syst… Li… D…". The strip keeps one row: its
230
+ * 26 px group is what lines it up with the 42 px fields beside it (`STRIP_SEGMENT`).
231
+ */
232
+ const WRAP_AT_LARGE = "large:flex-wrap";
172
233
 
173
234
  /**
174
235
  * The strip placement's segments: a 26px group (1 + 2 + 20 + 2 + 1) under the 16px
@@ -185,7 +246,7 @@ const STRIP_SEGMENT: Record<"sm" | "md", string> = { md: "py-0", sm: "py-0.5" };
185
246
  * region, because a description is read when the group is entered and not again when
186
247
  * an arrow key changes the choice underneath it.
187
248
  *
188
- * In muted 11px text under the field (or the bare group), above an `error`.
249
+ * In muted caption-size text under the field (or the bare group), above an `error`.
189
250
  */
190
251
  type ToggleGroupCaption<V> = ReactNode | ((value: V) => ReactNode);
191
252
 
@@ -272,6 +333,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
272
333
  hint,
273
334
  error,
274
335
  disabledReason: ownDisabledReason,
336
+ disabledReasonDisplay,
275
337
  commit,
276
338
  "aria-label": ariaLabelAttr,
277
339
  ...restWithMode
@@ -279,9 +341,17 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
279
341
  const labelId = useId();
280
342
  const errorId = useId();
281
343
  const reasonId = useId();
344
+ const hintCaptionId = useId();
282
345
  // The lock's reason under a locked provider (with `commit`), else the group's own.
283
346
  const disabledReason = useCommitReason(commit, ownDisabledReason);
284
347
  const locked = hasContent(disabledReason);
348
+ // §4: at Large and on touch the reason is a line under the group, not a bubble.
349
+ const reasonLine = useDisabledReasonLine(disabledReasonDisplay) && locked;
350
+ // §4: likewise a FieldHint "?" on the label line becomes a caption under the group at
351
+ // Large and on touch; text is a caption at every size, as Select's (see `hint`).
352
+ const inlineHint = useInlineHint(hint);
353
+ const hintAsCaption = isTextHint(hint) ? hint : inlineHint !== hint ? inlineHint : undefined;
354
+ const labelHint = hintAsCaption === undefined ? hint : undefined;
285
355
  // Locked looks disabled — the dimmed group, the not-allowed cursor, no hover offer —
286
356
  // but stays focusable; `disabled` alone also takes the segments out of the tab order.
287
357
  const dimmed = disabled || locked;
@@ -291,6 +361,9 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
291
361
  const field = labelled && labelPlacement === "field";
292
362
  const above = labelled && labelPlacement === "above";
293
363
  const strip = labelled && labelPlacement === "strip";
364
+ // At Large and Extra large a truncating group wraps instead, the strip excepted (see
365
+ // WRAP_AT_LARGE).
366
+ const wrapAtLarge = overflow === "truncate" && !strip;
294
367
  const hasError = labelled && hasContent(error);
295
368
  // Taken off the rest so neither reaches the DOM; `props` keeps them paired, which is
296
369
  // what lets the `onChange` below be called with `null` only in the mode that allows it.
@@ -377,8 +450,11 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
377
450
  // overlaying the selected segment's boundary. Inset keeps the ring
378
451
  // inside the segment it belongs to; focus-visible keeps it for the
379
452
  // keyboard, which is the only input that needs it.
453
+ //
454
+ // The ring is the kit's focus frame (0.32, §5): `--focus-ring-width` wide.
380
455
  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)]",
456
+ "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)]",
457
+ FOCUS_RING_WIDTH,
382
458
  size === "sm" && "px-2 py-1 text-xs",
383
459
  // In the field chrome: no vertical padding, and the line that makes the
384
460
  // field 42px under a strip that clears the label — see CHROME_PAD. `sm`
@@ -423,7 +499,9 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
423
499
  aria-labelledby={labelled && ariaLabelAttr === undefined && ariaLabel === undefined ? labelId : rest["aria-labelledby"]}
424
500
  aria-invalid={hasError || rest["aria-invalid"] || undefined}
425
501
  aria-describedby={
426
- [rest["aria-describedby"], hasCaption && captionId, hasError && errorId].filter(Boolean).join(" ") || undefined
502
+ [rest["aria-describedby"], hintAsCaption !== undefined && hintCaptionId, hasCaption && captionId, hasError && errorId]
503
+ .filter(Boolean)
504
+ .join(" ") || undefined
427
505
  }
428
506
  // `aria-disabled` on the group as well as on (or `disabled` on) each button: a
429
507
  // radio group is what the user is being refused, and a screen reader announcing
@@ -444,6 +522,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
444
522
  // phone does see is the focus ring — see the segment's own note below.)
445
523
  "inline-flex w-full gap-0.5 rounded-md border border-[var(--border-strong)] bg-[var(--bg-surface)] p-0.5 shadow-sm",
446
524
  overflow === "wrap" && "flex-wrap",
525
+ wrapAtLarge && WRAP_AT_LARGE,
447
526
  // The whole group fades, the way every other disabled control in this
448
527
  // package does; `cursor-not-allowed` is on the buttons, which is what a
449
528
  // pointer is actually over.
@@ -456,7 +535,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
456
535
  !labelled && className,
457
536
  )}
458
537
  >
459
- {locked ? (
538
+ {locked && !reasonLine ? (
460
539
  // The reason's bubble wraps the SEGMENTS, inside the group, not the group: a
461
540
  // wrapper outside it would become the flex or grid item in the caller's row in
462
541
  // the group's place, and a `w-full` / `md:w-auto` on the group would size the
@@ -487,16 +566,34 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
487
566
  <p
488
567
  id={captionId}
489
568
  aria-live={captionIsLive ? "polite" : undefined}
490
- className={cn("text-[11px] leading-snug text-[var(--text-muted)]", hasCaption && "mt-1")}
569
+ className={cn("text-caption leading-snug text-[var(--text-muted)]", hasCaption && "mt-1")}
491
570
  >
492
571
  {hasCaption ? captionNode : null}
493
572
  </p>
494
573
  ) : null;
495
574
  const errorEl = hasError ? (
496
- <p id={errorId} className="mt-1 text-[11px] leading-tight text-[var(--danger)]">
575
+ <p id={errorId} className="mt-1 text-caption leading-tight text-[var(--danger)]">
497
576
  {error}
498
577
  </p>
499
578
  ) : null;
579
+ // §4: the FieldHint's words and the lock's reason, under the group, before the caption
580
+ // (standing advice first) and the error (the news). The reason line IS what each
581
+ // segment's `aria-describedby` names.
582
+ const belowEl =
583
+ hintAsCaption !== undefined || reasonLine ? (
584
+ <>
585
+ {hintAsCaption !== undefined && (
586
+ <p id={hintCaptionId} className={FIELD_CAPTION_CLASS}>
587
+ {hintAsCaption}
588
+ </p>
589
+ )}
590
+ {reasonLine && (
591
+ <p id={reasonId} className={DISABLED_REASON_LINE_CLASS}>
592
+ {disabledReason}
593
+ </p>
594
+ )}
595
+ </>
596
+ ) : null;
500
597
  if (above) {
501
598
  // `relative` so a caller's `sr-only` label cannot escape (sr-only-containment).
502
599
  return (
@@ -512,10 +609,11 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
512
609
  >
513
610
  {label}
514
611
  </Label>
515
- {hint}
612
+ {labelHint}
516
613
  </div>
517
614
  <div className="min-w-0">
518
615
  {group}
616
+ {belowEl}
519
617
  {captionEl}
520
618
  {errorEl}
521
619
  </div>
@@ -524,19 +622,21 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
524
622
  }
525
623
  if (strip) {
526
624
  return (
527
- <LabelStrip labelId={labelId} label={label} hint={hint} disabled={dimmed} pad="field" className={className}>
625
+ <LabelStrip labelId={labelId} label={label} hint={labelHint} disabled={dimmed} pad="field" className={className}>
528
626
  {group}
627
+ {belowEl}
529
628
  {captionEl}
530
629
  {errorEl}
531
630
  </LabelStrip>
532
631
  );
533
632
  }
534
633
  if (!field) {
535
- if (!captionEl) return group;
634
+ if (!captionEl && !belowEl) return group;
536
635
  // The group keeps its `className`, as without a caption; the wrapper only stacks.
537
636
  return (
538
637
  <div className="min-w-0">
539
638
  {group}
639
+ {belowEl}
540
640
  {captionEl}
541
641
  </div>
542
642
  );
@@ -549,7 +649,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
549
649
  className="flex flex-1 flex-col"
550
650
  label={<span id={labelId}>{label}</span>}
551
651
  staticLabel
552
- hint={hint}
652
+ hint={labelHint}
553
653
  >
554
654
  <div
555
655
  className={cn(
@@ -563,6 +663,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
563
663
  {group}
564
664
  </div>
565
665
  </FloatingField>
666
+ {belowEl}
566
667
  {captionEl}
567
668
  {errorEl}
568
669
  </div>