@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
@@ -25,7 +25,7 @@ export function avatarInitials(name?: string | null, email?: string | null): str
25
25
  }
26
26
 
27
27
  const AVATAR_SIZES = {
28
- sm: "size-7 text-[11px]",
28
+ sm: "size-7 text-caption",
29
29
  md: "size-8 text-xs",
30
30
  lg: "size-12 text-base",
31
31
  } as const;
@@ -13,7 +13,11 @@ export function WizardStepper({
13
13
  }) {
14
14
  const currentIndex = steps.findIndex((s) => s.key === current);
15
15
  return (
16
- <ol className="flex items-center gap-1 text-xs" aria-label={ariaLabel}>
16
+ // `flex-wrap`: the steps flow onto a second line rather than past the screen
17
+ // (0.32.1, the 360 px Extra-large sweep; docs/text-size-harmonization.md §4).
18
+ // "Upload — Map columns — Confirm" ran 22 px past a 360 px phone at Extra large.
19
+ // Where the steps fit, they stay one row.
20
+ <ol className="flex flex-wrap items-center gap-1 text-xs" aria-label={ariaLabel}>
17
21
  {steps.map((step, i) => (
18
22
  <li key={step.key} className="flex items-center gap-1">
19
23
  {i > 0 && <span className="w-4 border-t border-[var(--border)]" />}
@@ -139,6 +139,11 @@ export function DemoBanner({
139
139
  size="2xs"
140
140
  variant="ghost"
141
141
  label={labels.details}
142
+ // The icon alone at every text size (docs/text-size-harmonization.md §10.8):
143
+ // a strip's one disclosure chevron beside its two links, whose state the
144
+ // chevron and `aria-expanded` say; "Details" as text at Large would push the
145
+ // links onto another line of a strip that is meant to stay one.
146
+ labelVisible={false}
142
147
  aria-expanded={!collapsed}
143
148
  onClick={toggle}
144
149
  >
@@ -1,10 +1,10 @@
1
1
  import { useState } from "react";
2
2
  import type { ReactNode } from "react";
3
- import { Button, Input, PHONE_QUERY, Select, Textarea } from "../components/ui";
3
+ import { Button, Input, Select, Textarea } from "../components/ui";
4
4
  import type { ButtonSize, ButtonVariant } from "../components/ui";
5
5
  import { Modal } from "../components/modal";
6
6
  import { isApplePlatform } from "../hooks/use-hotkey";
7
- import { useMediaQuery } from "../hooks/use-media-query";
7
+ import { usePhoneLayout } from "../hooks/use-breakpoint";
8
8
  import { useKitLabels } from "../i18n/kit-labels";
9
9
  import {
10
10
  DEFAULT_ATTACHMENT_ACCEPT,
@@ -262,7 +262,7 @@ export function FeedbackDialog(props: FeedbackDialogProps) {
262
262
  // `attachments="multiple"` only: the capture, apart from the picked/pasted files.
263
263
  const [screenshot, setScreenshot] = useState<File | null>(null);
264
264
  const [files, setFiles] = useState<File[]>([]);
265
- const isMobile = useMediaQuery(PHONE_QUERY, false);
265
+ const isMobile = usePhoneLayout();
266
266
  const labels = useKitLabels("feedbackDialog", DEFAULT_FEEDBACK_DIALOG_LABELS, labelsProp);
267
267
  const attachmentText = useKitLabels("feedbackAttachment", DEFAULT_FEEDBACK_ATTACHMENT_LABELS, labelsProp);
268
268
  // Under `multiple` the heading is `attachmentList` — a screenshot AND photos — which
@@ -313,7 +313,7 @@ export function FeedbackCategoryBadge({
313
313
  <span
314
314
  className={cn(
315
315
  "inline-flex items-center gap-1 rounded font-medium",
316
- compact ? "px-1.5 py-0.5 text-[11px]" : "px-2 py-0.5 text-xs",
316
+ compact ? "px-1.5 py-0.5 text-caption" : "px-2 py-0.5 text-xs",
317
317
  meta.badgeBg,
318
318
  meta.badgeText,
319
319
  className,
@@ -346,7 +346,7 @@ export function FeedbackStatusBadge({
346
346
  return (
347
347
  <span
348
348
  className={cn(
349
- "inline-flex items-center gap-1 whitespace-nowrap rounded px-1.5 py-0.5 text-[11px] font-medium",
349
+ "inline-flex items-center gap-1 whitespace-nowrap rounded px-1.5 py-0.5 text-caption font-medium",
350
350
  meta.activeBg,
351
351
  meta.activeText,
352
352
  className,
@@ -265,7 +265,7 @@ export function FeedbackThread({
265
265
  className="flex flex-wrap items-baseline justify-center gap-x-2 px-4 text-center text-xs text-[var(--text-muted)]"
266
266
  >
267
267
  <span>{message.body}</span>
268
- {time && <span className="text-[11px]">{time}</span>}
268
+ {time && <span className="text-caption">{time}</span>}
269
269
  </li>,
270
270
  );
271
271
  return rows;
@@ -286,14 +286,14 @@ export function FeedbackThread({
286
286
  : "rounded-es-sm bg-[var(--bg-surface-2)]",
287
287
  )}
288
288
  >
289
- <header className="mb-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-[var(--text-muted)]">
289
+ <header className="mb-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-caption text-[var(--text-muted)]">
290
290
  {author != null && (
291
291
  <span data-private={priv} className="font-medium text-[var(--text-secondary)]">
292
292
  {author}
293
293
  </span>
294
294
  )}
295
295
  {message.staff && (
296
- <span className="rounded border border-[var(--border)] bg-[var(--bg-surface)] px-1 text-[10px] font-medium uppercase tracking-wide text-[var(--text-secondary)]">
296
+ <span className="rounded border border-[var(--border)] bg-[var(--bg-surface)] px-1 text-micro font-medium uppercase tracking-wide text-[var(--text-secondary)]">
297
297
  {labels.staff}
298
298
  </span>
299
299
  )}
@@ -1,6 +1,7 @@
1
1
  import { useLayoutEffect, useState } from "react";
2
2
  import type { RefObject } from "react";
3
3
  import { useAnchoredRect, type AnchorRect } from "./use-anchored-rect";
4
+ import { useTextSize } from "../theme/text-size";
4
5
 
5
6
  /**
6
7
  * Vertical placement for a portalled, `position: fixed` panel anchored to a trigger.
@@ -22,6 +23,51 @@ export interface ViewportBox {
22
23
  height: number;
23
24
  }
24
25
 
26
+ /**
27
+ * Whether the page is pinch-zoomed (docs/text-size-harmonization.md §10.2). A zoom
28
+ * shrinks `visualViewport.height` exactly like an on-screen keyboard does, so every
29
+ * reader below must tell the two apart — and while zoomed, the answer is "no keyboard":
30
+ * following a zoomed viewport would drag a pinned row on every pan, magnified, and the
31
+ * browser already scrolls a focused field into view. The epsilon absorbs a scale of
32
+ * 1.0000001 that some engines report at rest.
33
+ */
34
+ function isZoomed(vv: VisualViewport): boolean {
35
+ return vv.scale > 1.001;
36
+ }
37
+
38
+ /** Below this the "keyboard" is rounding noise or a browser UI strip — `innerHeight` and
39
+ * `visualViewport.height` routinely disagree by a pixel or two — and nothing should move
40
+ * (keksdose's `MIN_KEYBOARD_PX`). */
41
+ const MIN_KEYBOARD_PX = 100;
42
+
43
+ export interface KeyboardInsetOptions {
44
+ /** The smallest inset that counts as a keyboard. Default 100 px. */
45
+ minimum?: number;
46
+ }
47
+
48
+ /**
49
+ * How many CSS px at the bottom of the LAYOUT viewport the on-screen keyboard covers, now
50
+ * — the one guarded reader (§10.2), so the apps' copies go (keksdose's
51
+ * `use-keyboard-inset.ts`):
52
+ *
53
+ * - 0 while the page is pinch-zoomed (`visualViewport.scale > 1`), where a smaller visual
54
+ * viewport is the zoom, not a keyboard;
55
+ * - 0 below `minimum` (100 px), which is noise;
56
+ * - 0 without `visualViewport` (SSR, jsdom, an old browser) and under
57
+ * `interactive-widget=resizes-content`, where `bottom: 0` already lands above the
58
+ * keyboard.
59
+ *
60
+ * Read it on `visualViewport`'s `resize` and `scroll` events (window `resize` as the
61
+ * fallback); a bottom-anchored control lifts itself by the result.
62
+ */
63
+ export function readKeyboardInset({ minimum = MIN_KEYBOARD_PX }: KeyboardInsetOptions = {}): number {
64
+ if (typeof window === "undefined") return 0;
65
+ const vv = window.visualViewport;
66
+ if (!vv || isZoomed(vv)) return 0;
67
+ const inset = Math.round(window.innerHeight - vv.height - vv.offsetTop);
68
+ return inset >= minimum ? inset : 0;
69
+ }
70
+
25
71
  function readViewport(): ViewportBox {
26
72
  if (typeof window === "undefined") return { top: 0, height: 0 };
27
73
  const vv = window.visualViewport;
@@ -35,9 +81,12 @@ export interface AnchoredPanelOptions {
35
81
  gap?: number;
36
82
  /** Space kept clear at the viewport edges. */
37
83
  margin?: number;
38
- /** The height the panel would like, when there is room. */
84
+ /** The height the panel would like, when there is room. In px at Normal text size:
85
+ * {@link useAnchoredPanel} multiplies it by the size's scale, since what a panel
86
+ * holds is rows of text (0.32, docs/text-size-harmonization.md §3.2). */
39
87
  preferredHeight?: number;
40
- /** Below this, the space under the trigger counts as unusable and a flip is considered. */
88
+ /** Below this, the space under the trigger counts as unusable and a flip is considered.
89
+ * In px at Normal, scaled likewise. */
41
90
  minHeight?: number;
42
91
  }
43
92
 
@@ -118,6 +167,12 @@ export function anchoredPanelPlacement(
118
167
  * older browsers) or no keyboard taking a bite out of it. A caller then keeps its
119
168
  * static layout, which is right at every width where this does not apply — and is why
120
169
  * the desktop and the test suite see exactly the markup they saw before.
170
+ *
171
+ * Also `null` while the page is pinch-zoomed (0.32, §10.2), with the guard
172
+ * {@link readKeyboardInset} uses. A zoom shrinks the visual viewport like a keyboard,
173
+ * and following it gave PickerSheet the zoomed region's top and height but the page's
174
+ * full width — its close button sat off screen (kastlan, Kurvenschmiede). Zoomed, the
175
+ * sheet keeps its static full-screen box, which the reader can pan to like the page.
121
176
  */
122
177
  export function useVisualViewport(active: boolean): ViewportBox | null {
123
178
  const [box, setBox] = useState<ViewportBox | null>(null);
@@ -130,7 +185,9 @@ export function useVisualViewport(active: boolean): ViewportBox | null {
130
185
  // device-pixel-ratio that is not an integer (his phone reports 1.25), so a
131
186
  // strict comparison would report a "keyboard" of 0.4px on every phone and pin
132
187
  // a height where none was needed.
133
- setBox(vv && vv.height < window.innerHeight - 1 ? { top: vv.offsetTop, height: vv.height } : null);
188
+ setBox(
189
+ vv && !isZoomed(vv) && vv.height < window.innerHeight - 1 ? { top: vv.offsetTop, height: vv.height } : null,
190
+ );
134
191
  };
135
192
  update();
136
193
  const vv = window.visualViewport;
@@ -154,6 +211,11 @@ export function useAnchoredPanel<T extends HTMLElement>(
154
211
  ): AnchoredPanel {
155
212
  const rect = useAnchoredRect(ref, open);
156
213
  const [viewport, setViewport] = useState<ViewportBox>(readViewport);
214
+ // A panel of rows wants room for the same number of rows at every text size; the gap
215
+ // and the edge margin are not text and stay px.
216
+ const { scale } = useTextSize();
217
+ const preferredHeight = (options.preferredHeight ?? 320) * scale;
218
+ const minHeight = (options.minHeight ?? 160) * scale;
157
219
 
158
220
  useLayoutEffect(() => {
159
221
  if (!open) return;
@@ -174,7 +236,7 @@ export function useAnchoredPanel<T extends HTMLElement>(
174
236
  }, [open]);
175
237
 
176
238
  if (!rect) {
177
- return { rect: null, top: 0, maxHeight: options.preferredHeight ?? 320, above: false };
239
+ return { rect: null, top: 0, maxHeight: preferredHeight, above: false };
178
240
  }
179
- return { rect, ...anchoredPanelPlacement(rect, viewport, options) };
241
+ return { rect, ...anchoredPanelPlacement(rect, viewport, { ...options, preferredHeight, minHeight }) };
180
242
  }
@@ -0,0 +1,132 @@
1
+ import { useMediaQuery } from "./use-media-query";
2
+ import { useTextSize } from "../theme/text-size";
3
+
4
+ /**
5
+ * Breakpoints that follow the text size, in JS (docs/text-size-harmonization.md §3.3,
6
+ * §10.4).
7
+ *
8
+ * A media query's rem resolves against the browser's default font size, not `<html>`'s,
9
+ * so Tailwind's `md:` would stay at 48rem when the root grows. tokens.css therefore
10
+ * redefines every breakpoint variant per text size — `md:` is 48rem at Normal, 60rem at
11
+ * Large, 72rem at Extra large — and these hooks ask the same question with the same
12
+ * numbers, so the CSS and the JS answer always agree: AppShell's `md:hidden` and its
13
+ * `isMdUp`, DataTable's cards and its full-screen dialog, an app's sticky footer
14
+ * (keksdose's must be the SAME `usePhoneLayout()` the dialog uses, §10.4).
15
+ *
16
+ * Width queries only. Pointer and display-mode queries stay `useMediaQuery` (§10.4).
17
+ */
18
+
19
+ /** The breakpoints at Normal, in rem: Tailwind's five, and `3xl` (keksdose's
20
+ * `min-[2400px]`, §10.4). tokens.css multiplies each by the text size. */
21
+ export const BREAKPOINT_REM = { sm: 40, md: 48, lg: 64, xl: 80, "2xl": 96, "3xl": 150 } as const;
22
+
23
+ export type Breakpoint = keyof typeof BREAKPOINT_REM;
24
+
25
+ /** A breakpoint variant, spelled as in a class: `"md"` is `md:` (at least md), `"max-md"`
26
+ * is `max-md:` (below md). */
27
+ export type BreakpointVariant = Breakpoint | `max-${Breakpoint}`;
28
+
29
+ /**
30
+ * The browser's own default font size in px — what a media query's rem means (the
31
+ * initial `font-size: medium`, never `<html>`'s). 16 unless the person changed it, and 16
32
+ * outside a browser. Read once: changing it takes a browser setting, after which the
33
+ * page is reloaded in practice.
34
+ */
35
+ let browserRemPx: number | null = null;
36
+ function readBrowserRemPx(): number {
37
+ if (browserRemPx !== null) return browserRemPx;
38
+ // Outside a browser (SSR): 16, uncached, so the client's first real read still counts.
39
+ if (typeof document === "undefined" || !document.body) return 16;
40
+ const probe = document.createElement("div");
41
+ probe.style.cssText = "position:absolute;visibility:hidden;font-size:medium";
42
+ document.body.appendChild(probe);
43
+ const px = Number.parseFloat(getComputedStyle(probe).fontSize);
44
+ probe.remove();
45
+ // jsdom computes no font size ("medium" or nothing): the default it stands for.
46
+ browserRemPx = px > 0 ? px : 16;
47
+ return browserRemPx;
48
+ }
49
+
50
+ /**
51
+ * How many CSS px one `rem` is at `scale` (`TEXT_SCALE` of the size in force): the
52
+ * browser's own default font size times the text size — what `<html>`'s computed font
53
+ * size is, by tokens.css. For the few lengths JS has to do arithmetic with: a popover's
54
+ * width against the viewport edge, a chart constant (§3.1, §3.2). 16 × `scale` outside a
55
+ * browser and in jsdom, which computes no default font size.
56
+ */
57
+ export function remPx(scale = 1): number {
58
+ return readBrowserRemPx() * scale;
59
+ }
60
+
61
+ /** {@link remPx} at the text size in force, re-rendering when it changes. */
62
+ export function useRemPx(): number {
63
+ const { scale } = useTextSize();
64
+ return remPx(scale);
65
+ }
66
+
67
+ /** A length in rem as the kit spells one in JS — `"18rem"` — where a prop also takes px
68
+ * as a plain number. */
69
+ export type RemLength = `${number}rem`;
70
+
71
+ /**
72
+ * A `number | RemLength` in CSS px now: a number is px as given, `"18rem"` is 18 ×
73
+ * `rootRemPx` (see {@link remPx}). `undefined` stays `undefined`.
74
+ */
75
+ export function lengthPx(length: number | RemLength, rootRemPx: number): number;
76
+ export function lengthPx(length: number | RemLength | undefined, rootRemPx: number): number | undefined;
77
+ export function lengthPx(length: number | RemLength | undefined, rootRemPx: number): number | undefined {
78
+ if (length === undefined) return undefined;
79
+ return typeof length === "number" ? length : Number.parseFloat(length) * rootRemPx;
80
+ }
81
+
82
+ /**
83
+ * The media query a breakpoint variant means at `scale` (`TEXT_SCALE` of the size in
84
+ * force). `"md"` → `(min-width: 768px)` at Normal, `(min-width: 960px)` at Large;
85
+ * `"max-md"` → `(width < 768px)` at Normal. In px, scaled by the browser's own default
86
+ * font size as well, so a person who set 20 px in the browser gets 960 px for `md` at
87
+ * Normal — as the CSS does.
88
+ *
89
+ * `max-*` is written in range syntax, `(width < N)`, against the same `N` its `min-*`
90
+ * twin starts at, so the two are exact complements at EVERY width: exactly one of
91
+ * `md` and `max-md` matches, as with tokens.css's `width >= 48rem` / `width < 48rem`
92
+ * (and Tailwind's own `max-*`). Until 0.32.1 it was `(max-width: 767px)`, which left a
93
+ * gap: on a fractional viewport width (767.5 px under zoom or at some Android
94
+ * device-pixel ratios) neither query matched, so DataTable, asking `!md`, said phone
95
+ * while `usePhoneLayout()`, asking `max-md`, said not (0.32.1, keksdose's 0.32 report;
96
+ * docs/text-size-harmonization.md §3.3: "the CSS and JS answers always agree").
97
+ *
98
+ * Range syntax in media queries is Chrome / Edge 104, Firefox 63, Safari 16.4. That is
99
+ * inside the floor the kit already sets: tokens.css's breakpoint variants are written in
100
+ * it, and Tailwind v4 itself needs Safari 16.4, Chrome 111 and Firefox 128.
101
+ *
102
+ * A test's `matchMedia` stub that keyed on the old string (`"max-width: 767px"`, the
103
+ * deprecated `PHONE_QUERY`) has to answer `(width < 768px)` now. `min-*` is unchanged,
104
+ * character for character.
105
+ */
106
+ export function breakpointQuery(variant: BreakpointVariant, scale = 1, remPx: number = readBrowserRemPx()): string {
107
+ const max = variant.startsWith("max-");
108
+ const name = (max ? variant.slice(4) : variant) as Breakpoint;
109
+ const px = Math.round(BREAKPOINT_REM[name] * remPx * scale);
110
+ return max ? `(width < ${px}px)` : `(min-width: ${px}px)`;
111
+ }
112
+
113
+ /**
114
+ * Whether the viewport matches a breakpoint variant at the text size in force — the JS
115
+ * twin of the class: `useBreakpoint("md")` is true exactly where `md:` applies,
116
+ * `useBreakpoint("max-sm")` where `max-sm:` does. `fallback` answers where there is no
117
+ * `matchMedia` (SSR, jsdom).
118
+ */
119
+ export function useBreakpoint(variant: BreakpointVariant, fallback = false): boolean {
120
+ const { scale } = useTextSize();
121
+ return useMediaQuery(breakpointQuery(variant, scale), fallback);
122
+ }
123
+
124
+ /**
125
+ * The phone layout: below `md` at the text size in force — `max-md:` in CSS. The single
126
+ * answer for "is this the phone layout" (§10.4): the kit's own sheets and cards use it,
127
+ * and an app's phone checks must too, so a tablet at 150 % gets every phone treatment
128
+ * at once or none of them. Replaces `useMediaQuery(PHONE_QUERY)`.
129
+ */
130
+ export function usePhoneLayout(fallback = false): boolean {
131
+ return useBreakpoint("max-md", fallback);
132
+ }
@@ -0,0 +1,41 @@
1
+ import { useTextSize } from "../theme/text-size";
2
+ import { useMediaQuery } from "./use-media-query";
3
+
4
+ /**
5
+ * The two questions the kit's 0.32 behaviours ask (docs/text-size-harmonization.md §4,
6
+ * §10.7–10.9), answered in one place so every part draws the line where the others do.
7
+ *
8
+ * Prefer CSS where it can: a class that differs at Large is a `large:` variant
9
+ * (tokens.css), and a layout switch is a breakpoint, which already scales. These hooks
10
+ * are for what CSS cannot decide — whether a tooltip is rendered at all, whether a label
11
+ * becomes text, whether a row's actions collapse into a menu.
12
+ */
13
+
14
+ /** Large or Extra large is in force (`<html data-text-size>`) — the JS twin of the
15
+ * `large:` variant. */
16
+ export function useLargeText(): boolean {
17
+ return useTextSize().size !== "normal";
18
+ }
19
+
20
+ /**
21
+ * The primary pointer is a finger (`pointer: coarse`): a hover never happens, so a
22
+ * tooltip opens only on the taps that do nothing else. A pointer query, so it stays
23
+ * `useMediaQuery` (§10.4). `false` without `matchMedia` (SSR, jsdom).
24
+ */
25
+ export function useCoarsePointer(): boolean {
26
+ return useMediaQuery("(pointer: coarse)", false);
27
+ }
28
+
29
+ /**
30
+ * Whether a fact may NOT live only in a tooltip here (§4 "No fact only in a tooltip"):
31
+ * at Large and Extra large, where the reader is the one who asked for bigger type, and
32
+ * on a touch screen at every size, where a tooltip cannot be hovered open. Where this
33
+ * is true the kit draws the fact in the layout — a `disabledReason` as a line under its
34
+ * control, a FieldHint as the field's caption, a StatTile hint as text — and keeps the
35
+ * bubble only where there is no room (a top bar, a dense row's inline actions).
36
+ */
37
+ export function useInlineFacts(): boolean {
38
+ const large = useLargeText();
39
+ const coarse = useCoarsePointer();
40
+ return large || coarse;
41
+ }
@@ -1,27 +1,104 @@
1
- import { useEffect, useState } from "react";
1
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
2
  import type { RefObject } from "react";
3
+ import { useTextSize } from "../theme/text-size";
3
4
 
4
5
  /** Rows kept mounted beyond each edge, so a flick-scroll has something to show
5
6
  * before the next render lands. */
6
7
  const OVERSCAN = 6;
7
8
 
9
+ /** The attribute a measured row carries so {@link WindowedRows.measureRef} knows which
10
+ * row it is looking at: `data-row-index={index}`. */
11
+ export const WINDOWED_ROW_INDEX = "data-row-index";
12
+
8
13
  /** What {@link useWindowedRows} answers: render rows `first` up to (not including)
9
14
  * `last`, inside a scroll body `totalHeight` pixels tall. */
10
15
  export interface WindowedRows {
11
16
  first: number;
12
17
  last: number;
13
18
  totalHeight: number;
19
+ /**
20
+ * The top of row `index`, in px from the top of the list: the rows above it at their
21
+ * MEASURED heights where they have been rendered, at {@link estimate} where not.
22
+ * Position each row at this (`style={{ top: offsetOf(index) }}`) rather than at
23
+ * `index × rowHeight`, which is right only while every row is the estimate.
24
+ */
25
+ offsetOf: (index: number) => number;
26
+ /** The height of row `index`: measured, else {@link estimate}. */
27
+ heightOf: (index: number) => number;
28
+ /**
29
+ * The height assumed for a row not measured yet: `rowHeight × scale`, the text
30
+ * size's factor (`useTextSize`). Give a row this as its `minHeight`, not its
31
+ * `height`: a row that wraps must be allowed to grow, and is then measured.
32
+ */
33
+ estimate: number;
34
+ /**
35
+ * Put on every rendered row, with `data-row-index={index}` beside it: the row is
36
+ * observed while it is mounted, and its height replaces the estimate. Stable for the
37
+ * life of the list. A row without it keeps the estimate, which is the pre-0.32
38
+ * fixed-height list exactly.
39
+ */
40
+ measureRef: (element: HTMLElement | null) => (() => void) | undefined;
41
+ }
42
+
43
+ type Heights = ReadonlyMap<number, number>;
44
+ const NO_HEIGHTS: Heights = new Map();
45
+
46
+ /** The box height of an observed row: the border box where the browser reports one,
47
+ * else its laid-out rectangle. `0` means "not laid out" (hidden, jsdom) and is ignored. */
48
+ function rowHeightOf(entry: ResizeObserverEntry): number {
49
+ const box = entry.borderBoxSize?.[0];
50
+ if (box && box.blockSize > 0) return box.blockSize;
51
+ return entry.target.getBoundingClientRect().height;
52
+ }
53
+
54
+ /** The row index an element was given with {@link WINDOWED_ROW_INDEX}, or `null`. */
55
+ function indexOf(element: Element): number | null {
56
+ const raw = element.getAttribute(WINDOWED_ROW_INDEX);
57
+ if (raw === null) return null;
58
+ const index = Number(raw);
59
+ return Number.isInteger(index) && index >= 0 ? index : null;
60
+ }
61
+
62
+ /** The last index `i` with `offsets[i] <= y` (0 when none): the row whose box holds `y`. */
63
+ function rowAt(offsets: Float64Array, count: number, y: number): number {
64
+ let lo = 0;
65
+ let hi = count;
66
+ while (lo < hi) {
67
+ const mid = (lo + hi + 1) >> 1;
68
+ if (offsets[mid] <= y) lo = mid;
69
+ else hi = mid - 1;
70
+ }
71
+ return Math.min(lo, Math.max(0, count - 1));
14
72
  }
15
73
 
16
74
  /**
17
- * Which rows of a fixed-height list are worth rendering.
75
+ * Which rows of a long list are worth rendering — and, since 0.32, where each one goes.
18
76
  *
19
- * Hand-rolled rather than pulled from a virtualization library, for two reasons. With
20
- * a fixed row height the whole problem is two divisions — a library earns its keep on
21
- * measured, variable-height rows, and there are none here. And the obvious library for
22
- * it (`@tanstack/react-virtual`) returns functions that cannot be memoized safely, so
23
- * the React Compiler skips optimising any component that calls it: a list that exists
24
- * to stay fast would opt out of the consumer's main source of speed.
77
+ * Hand-rolled rather than pulled from a virtualization library: the obvious one
78
+ * (`@tanstack/react-virtual`) returns functions that cannot be memoized safely, so the
79
+ * React Compiler skips optimising any component that calls it — a list that exists to
80
+ * stay fast would opt out of the consumer's main source of speed.
81
+ *
82
+ * **Measured rows (docs/text-size-harmonization.md §10.9).** Until 0.32 every row was
83
+ * `rowHeight` px and the window was two divisions. "Nothing truncates" at Large and
84
+ * Extra large needs rows that grow with their text — Kurvenschmiede's segment list
85
+ * wraps a long name at 150 %, and a fixed 68 px row cut it off. So the rows are
86
+ * measured: put {@link WindowedRows.measureRef} and `data-row-index` on each rendered
87
+ * row, and one `ResizeObserver` watches every row while it is mounted (one observer for
88
+ * all of them, which the browser batches into one callback per frame). A measured
89
+ * height replaces the estimate; a row never rendered keeps `rowHeight × scale`, the
90
+ * text size's factor, so the scroll body is about right before anything is measured
91
+ * and exactly right for everything that has been. Offsets are a prefix sum over both,
92
+ * rebuilt only when a height changes — scrolling is a binary search.
93
+ *
94
+ * Measurements are dropped when the text size changes (every row is a different height
95
+ * then, and the rendered ones measure again at once) and ignored past `count` (a row
96
+ * removed at the end). Removing a row in the MIDDLE shifts the indices below it; they
97
+ * keep the old row's height until they are rendered again, which costs a few pixels of
98
+ * scrollbar, never a row out of place on screen.
99
+ *
100
+ * Without a `ResizeObserver` (jsdom, an old webview) the estimate holds for every row,
101
+ * which is the fixed-height list of before.
25
102
  *
26
103
  * `scrollRef` is the element that scrolls. The rows are assumed to start at its top;
27
104
  * a sticky header above them costs a row or two of the overscan, not correctness.
@@ -35,8 +112,21 @@ export function useWindowedRows(
35
112
  rowHeight: number,
36
113
  scrollRef: RefObject<HTMLElement | null>,
37
114
  ): WindowedRows {
115
+ const { scale } = useTextSize();
116
+ const estimate = rowHeight * scale;
38
117
  const [scrollTop, setScrollTop] = useState(0);
39
118
  const [viewport, setViewport] = useState(0);
119
+ // The heights are keyed to the scale they were measured at: a text size switch makes
120
+ // every one of them stale at once, and the derivation below drops them on read.
121
+ const [measured, setMeasured] = useState<{ scale: number; heights: Heights }>({ scale, heights: NO_HEIGHTS });
122
+ const heights = measured.scale === scale ? measured.heights : NO_HEIGHTS;
123
+ // The observer's callback runs outside render and needs the scale in force then. A
124
+ // LAYOUT effect: the rows' new heights after a size switch are reported before the
125
+ // browser paints, which can be before a passive effect has run.
126
+ const scaleRef = useRef(scale);
127
+ useLayoutEffect(() => {
128
+ scaleRef.current = scale;
129
+ }, [scale]);
40
130
 
41
131
  useEffect(() => {
42
132
  const element = scrollRef.current;
@@ -59,11 +149,77 @@ export function useWindowedRows(
59
149
  };
60
150
  }, [scrollRef]);
61
151
 
62
- const first = Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN);
152
+ // ONE observer for every row, made on the first row that asks for it.
153
+ const rowObserver = useRef<ResizeObserver | null>(null);
154
+ useEffect(
155
+ () => () => {
156
+ rowObserver.current?.disconnect();
157
+ rowObserver.current = null;
158
+ },
159
+ [],
160
+ );
161
+
162
+ const measureRef = useCallback((element: HTMLElement | null) => {
163
+ if (!element || typeof ResizeObserver === "undefined") return undefined;
164
+ if (!rowObserver.current) {
165
+ rowObserver.current = new ResizeObserver((entries) => {
166
+ const updates: [number, number][] = [];
167
+ for (const entry of entries) {
168
+ const index = indexOf(entry.target);
169
+ const height = rowHeightOf(entry);
170
+ if (index !== null && height > 0) updates.push([index, height]);
171
+ }
172
+ if (!updates.length) return;
173
+ const at = scaleRef.current;
174
+ setMeasured((previous) => {
175
+ const base = previous.scale === at ? previous.heights : NO_HEIGHTS;
176
+ // Unchanged heights are the common case (a row re-observed after a re-render):
177
+ // the same map back means no render.
178
+ if (updates.every(([index, height]) => base.get(index) === height)) {
179
+ return previous.scale === at ? previous : { scale: at, heights: base };
180
+ }
181
+ const next = new Map(base);
182
+ for (const [index, height] of updates) next.set(index, height);
183
+ return { scale: at, heights: next };
184
+ });
185
+ });
186
+ }
187
+ const observer = rowObserver.current;
188
+ observer.observe(element);
189
+ // React 19 calls this when the row unmounts (or the ref moves to another element).
190
+ return () => observer.unobserve(element);
191
+ }, []);
192
+
193
+ // The prefix sum: offsets[i] is the top of row i, offsets[count] the whole height.
194
+ // Skipped while nothing is measured, when the arithmetic is exact without it.
195
+ const offsets = useMemo(() => {
196
+ if (heights.size === 0) return null;
197
+ const table = new Float64Array(count + 1);
198
+ for (let index = 0; index < count; index += 1) {
199
+ table[index + 1] = table[index] + (heights.get(index) ?? estimate);
200
+ }
201
+ return table;
202
+ }, [count, estimate, heights]);
203
+
204
+ const offsetOf = useCallback(
205
+ (index: number) => (offsets ? offsets[Math.max(0, Math.min(index, count))] : index * estimate),
206
+ [offsets, count, estimate],
207
+ );
208
+ const heightOf = useCallback((index: number) => heights.get(index) ?? estimate, [heights, estimate]);
209
+
63
210
  // A viewport of 0 is the first render, before the pane has been laid out (and every
64
211
  // render under jsdom). Rendering nothing then would leave the list blank until
65
212
  // something scrolled it, so fall back to a screenful.
66
- const visible = Math.ceil((viewport || 600) / rowHeight) + OVERSCAN * 2;
67
- const last = Math.min(count, first + visible);
68
- return { first, last, totalHeight: count * rowHeight };
213
+ const room = viewport || 600;
214
+ let first: number;
215
+ let last: number;
216
+ if (offsets) {
217
+ first = Math.max(0, rowAt(offsets, count, scrollTop) - OVERSCAN);
218
+ last = Math.min(count, rowAt(offsets, count, scrollTop + room) + 1 + OVERSCAN);
219
+ } else {
220
+ first = Math.max(0, Math.floor(scrollTop / estimate) - OVERSCAN);
221
+ last = Math.min(count, first + Math.ceil(room / estimate) + OVERSCAN * 2);
222
+ }
223
+ const totalHeight = offsets ? offsets[count] : count * estimate;
224
+ return { first, last, totalHeight, offsetOf, heightOf, estimate, measureRef };
69
225
  }
@@ -84,6 +84,10 @@ import { DEFAULT_INVITATIONS_LABELS } from "../admin/invitations-panel";
84
84
  import { DEFAULT_SETTINGS_LABELS } from "../settings/settings-labels";
85
85
  import { DEFAULT_LANDING_LABELS } from "../landing/landing-labels";
86
86
  import { DEFAULT_DEMO_LABELS } from "../demo/demo-labels";
87
+ import { DEFAULT_BILLING_LABELS } from "../billing/billing-labels";
88
+ import { DEFAULT_APPEARANCE_LABELS } from "../components/appearance-labels";
89
+ import { DEFAULT_ROW_ACTIONS_LABELS } from "../components/row-actions";
90
+ import { DEFAULT_APP_SHELL_MORE_LABELS } from "../shell/app-shell";
87
91
  import { DEFAULT_ACCOUNT_STATE_LABELS } from "../components/account-chips";
88
92
  import { DEFAULT_SHARE_CARD_LABELS } from "../components/share-card";
89
93
  import { DEFAULT_REAUTH_DIALOG_LABELS } from "../components/reauth-dialog";
@@ -214,6 +218,10 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
214
218
  settings: DEFAULT_SETTINGS_LABELS,
215
219
  landing: DEFAULT_LANDING_LABELS,
216
220
  demo: DEFAULT_DEMO_LABELS,
221
+ billing: DEFAULT_BILLING_LABELS,
222
+ appearance: DEFAULT_APPEARANCE_LABELS,
223
+ rowActions: DEFAULT_ROW_ACTIONS_LABELS,
224
+ appShellMore: DEFAULT_APP_SHELL_MORE_LABELS,
217
225
  characterCount: DEFAULT_CHARACTER_COUNT_LABELS,
218
226
  countrySelect: DEFAULT_COUNTRY_SELECT_LABELS,
219
227
  inlineEdit: DEFAULT_INLINE_EDIT_LABELS,