@eifi1/ui-kit 0.51.6 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (805) hide show
  1. package/README.md +146 -26
  2. package/dist/account/account-parts.d.ts +10 -8
  3. package/dist/account/account-parts.js +1 -18
  4. package/dist/account/account-parts.js.map +1 -1
  5. package/dist/account/data-export-setting-labels.js +1 -1
  6. package/dist/account/data-export-setting-labels.js.map +1 -1
  7. package/dist/account/delete-account-setting-labels.js +1 -1
  8. package/dist/account/delete-account-setting-labels.js.map +1 -1
  9. package/dist/account/email-change-setting-labels.js +1 -1
  10. package/dist/account/email-change-setting-labels.js.map +1 -1
  11. package/dist/account/passkeys-setting.d.ts +9 -2
  12. package/dist/account/passkeys-setting.js +41 -29
  13. package/dist/account/passkeys-setting.js.map +1 -1
  14. package/dist/account/sessions-setting.d.ts +3 -2
  15. package/dist/account/sessions-setting.js +10 -8
  16. package/dist/account/sessions-setting.js.map +1 -1
  17. package/dist/admin/admin-action-confirm.js +3 -7
  18. package/dist/admin/admin-action-confirm.js.map +1 -1
  19. package/dist/admin/admin-parts.d.ts +6 -3
  20. package/dist/admin/admin-parts.js +6 -21
  21. package/dist/admin/admin-parts.js.map +1 -1
  22. package/dist/admin/mail-test-card-labels.js +1 -1
  23. package/dist/admin/mail-test-card-labels.js.map +1 -1
  24. package/dist/admin/plan-change-labels.d.ts +2 -2
  25. package/dist/admin/plan-change-labels.js +1 -17
  26. package/dist/admin/plan-change-labels.js.map +1 -1
  27. package/dist/admin/plan-change.d.ts +3 -42
  28. package/dist/admin/plan-change.js +1 -1
  29. package/dist/admin/plan-change.js.map +1 -1
  30. package/dist/admin/reviewer-scope-editor.js +3 -3
  31. package/dist/admin/reviewer-scope-editor.js.map +1 -1
  32. package/dist/auth/auth-errors-labels.d.ts +11 -0
  33. package/dist/auth/auth-errors-labels.js +13 -0
  34. package/dist/auth/auth-errors-labels.js.map +1 -0
  35. package/dist/auth/auth-errors.d.ts +7 -23
  36. package/dist/auth/auth-errors.js +2 -15
  37. package/dist/auth/auth-errors.js.map +1 -1
  38. package/dist/auth/complete-name-dialog.d.ts +3 -2
  39. package/dist/auth/complete-name-dialog.js +3 -5
  40. package/dist/auth/complete-name-dialog.js.map +1 -1
  41. package/dist/auth/forgot-password-form-labels.js +1 -1
  42. package/dist/auth/forgot-password-form-labels.js.map +1 -1
  43. package/dist/auth/forgot-password-form.js +7 -2
  44. package/dist/auth/forgot-password-form.js.map +1 -1
  45. package/dist/auth/register-form-labels.js +1 -1
  46. package/dist/auth/register-form-labels.js.map +1 -1
  47. package/dist/auth/reset-password-form-labels.js +1 -1
  48. package/dist/auth/reset-password-form-labels.js.map +1 -1
  49. package/dist/auth/reset-password-form.js +5 -1
  50. package/dist/auth/reset-password-form.js.map +1 -1
  51. package/dist/auth/sign-in-form-labels.js +1 -1
  52. package/dist/auth/sign-in-form-labels.js.map +1 -1
  53. package/dist/auth/status-parts.d.ts +0 -3
  54. package/dist/auth/status-parts.js +0 -4
  55. package/dist/auth/status-parts.js.map +1 -1
  56. package/dist/auth/verify-email-labels.js +1 -1
  57. package/dist/auth/verify-email-labels.js.map +1 -1
  58. package/dist/auth/verify-email.js +7 -2
  59. package/dist/auth/verify-email.js.map +1 -1
  60. package/dist/billing/cancel-request.d.ts +11 -2
  61. package/dist/billing/cancel-request.js +15 -3
  62. package/dist/billing/cancel-request.js.map +1 -1
  63. package/dist/billing/cancel-subscription.d.ts +22 -10
  64. package/dist/billing/cancel-subscription.js +8 -11
  65. package/dist/billing/cancel-subscription.js.map +1 -1
  66. package/dist/billing/dialog-close.d.ts +29 -0
  67. package/dist/billing/dialog-close.js +8 -0
  68. package/dist/billing/dialog-close.js.map +1 -0
  69. package/dist/billing/plan-card.d.ts +14 -4
  70. package/dist/billing/plan-card.js +15 -8
  71. package/dist/billing/plan-card.js.map +1 -1
  72. package/dist/billing/plan-change-labels.d.ts +42 -0
  73. package/dist/billing/plan-change-labels.js +22 -0
  74. package/dist/billing/plan-change-labels.js.map +1 -0
  75. package/dist/billing/plan-switch.d.ts +21 -9
  76. package/dist/billing/plan-switch.js +10 -8
  77. package/dist/billing/plan-switch.js.map +1 -1
  78. package/dist/chart.d.ts +12 -0
  79. package/dist/chart.js +16 -1
  80. package/dist/chart.js.map +1 -1
  81. package/dist/components/account-chips.d.ts +5 -5
  82. package/dist/components/account-chips.js +11 -13
  83. package/dist/components/account-chips.js.map +1 -1
  84. package/dist/components/alert-banner.d.ts +16 -5
  85. package/dist/components/alert-banner.js +46 -1
  86. package/dist/components/alert-banner.js.map +1 -1
  87. package/dist/components/amount-input.d.ts +22 -4
  88. package/dist/components/amount-input.js +3 -3
  89. package/dist/components/amount-input.js.map +1 -1
  90. package/dist/components/autocomplete.js +57 -65
  91. package/dist/components/autocomplete.js.map +1 -1
  92. package/dist/components/bulk-action-bar.d.ts +12 -2
  93. package/dist/components/bulk-action-bar.js +65 -21
  94. package/dist/components/bulk-action-bar.js.map +1 -1
  95. package/dist/components/button-look.d.ts +5 -5
  96. package/dist/components/button-look.js.map +1 -1
  97. package/dist/components/button.d.ts +2 -2
  98. package/dist/components/button.js.map +1 -1
  99. package/dist/components/calculator.d.ts +21 -2
  100. package/dist/components/calculator.js +53 -14
  101. package/dist/components/calculator.js.map +1 -1
  102. package/dist/components/chart-edge.d.ts +16 -0
  103. package/dist/components/chart-edge.js +14 -1
  104. package/dist/components/chart-edge.js.map +1 -1
  105. package/dist/components/chart-figure.d.ts +13 -0
  106. package/dist/components/chart-figure.js +15 -0
  107. package/dist/components/chart-figure.js.map +1 -0
  108. package/dist/components/chart-zoom-core.js +1 -4
  109. package/dist/components/chart-zoom-core.js.map +1 -1
  110. package/dist/components/chart.d.ts +8 -1
  111. package/dist/components/chart.js +19 -10
  112. package/dist/components/chart.js.map +1 -1
  113. package/dist/components/combobox-core.d.ts +119 -7
  114. package/dist/components/combobox-core.js +151 -46
  115. package/dist/components/combobox-core.js.map +1 -1
  116. package/dist/components/combobox.d.ts +1 -1
  117. package/dist/components/combobox.js +142 -131
  118. package/dist/components/combobox.js.map +1 -1
  119. package/dist/components/copy-button.d.ts +6 -5
  120. package/dist/components/copy-button.js +5 -3
  121. package/dist/components/copy-button.js.map +1 -1
  122. package/dist/components/country-select.js +2 -2
  123. package/dist/components/country-select.js.map +1 -1
  124. package/dist/components/data-table-column-settings.d.ts +1 -1
  125. package/dist/components/data-table-column-settings.js +33 -7
  126. package/dist/components/data-table-column-settings.js.map +1 -1
  127. package/dist/components/data-table-filters.d.ts +4 -2
  128. package/dist/components/data-table-filters.js +2 -2
  129. package/dist/components/data-table-filters.js.map +1 -1
  130. package/dist/components/data-table-fit.d.ts +6 -4
  131. package/dist/components/data-table-fit.js +4 -1
  132. package/dist/components/data-table-fit.js.map +1 -1
  133. package/dist/components/data-table-groups.d.ts +1 -1
  134. package/dist/components/data-table-groups.js.map +1 -1
  135. package/dist/components/data-table-head.d.ts +1 -1
  136. package/dist/components/data-table-head.js +15 -12
  137. package/dist/components/data-table-head.js.map +1 -1
  138. package/dist/components/data-table-mobile.d.ts +36 -7
  139. package/dist/components/data-table-mobile.js +63 -31
  140. package/dist/components/data-table-mobile.js.map +1 -1
  141. package/dist/components/data-table-pagination.js +11 -6
  142. package/dist/components/data-table-pagination.js.map +1 -1
  143. package/dist/components/data-table-resize.d.ts +1 -1
  144. package/dist/components/data-table-resize.js.map +1 -1
  145. package/dist/components/data-table-row-actions.d.ts +2 -2
  146. package/dist/components/data-table-row-actions.js.map +1 -1
  147. package/dist/components/data-table-row.d.ts +6 -2
  148. package/dist/components/data-table-row.js +17 -10
  149. package/dist/components/data-table-row.js.map +1 -1
  150. package/dist/components/data-table-selection.d.ts +1 -1
  151. package/dist/components/data-table-selection.js.map +1 -1
  152. package/dist/components/data-table-shared.d.ts +10 -2
  153. package/dist/components/data-table-shared.js +18 -0
  154. package/dist/components/data-table-shared.js.map +1 -1
  155. package/dist/components/data-table-sort.d.ts +21 -2
  156. package/dist/components/data-table-sort.js +24 -0
  157. package/dist/components/data-table-sort.js.map +1 -1
  158. package/dist/components/data-table-virtual.d.ts +1 -1
  159. package/dist/components/data-table-virtual.js +18 -6
  160. package/dist/components/data-table-virtual.js.map +1 -1
  161. package/dist/components/data-table.d.ts +25 -8
  162. package/dist/components/data-table.js +154 -25
  163. package/dist/components/data-table.js.map +1 -1
  164. package/dist/components/date-field.d.ts +24 -2
  165. package/dist/components/date-field.js +33 -8
  166. package/dist/components/date-field.js.map +1 -1
  167. package/dist/components/date-picker.d.ts +15 -2
  168. package/dist/components/date-picker.js +55 -26
  169. package/dist/components/date-picker.js.map +1 -1
  170. package/dist/components/date-range-picker.d.ts +47 -20
  171. package/dist/components/date-range-picker.js +23 -7
  172. package/dist/components/date-range-picker.js.map +1 -1
  173. package/dist/components/dialog-frame.d.ts +2 -1
  174. package/dist/components/dialog-frame.js.map +1 -1
  175. package/dist/components/entity-combobox.js +4 -2
  176. package/dist/components/entity-combobox.js.map +1 -1
  177. package/dist/components/error-boundary.js +37 -30
  178. package/dist/components/error-boundary.js.map +1 -1
  179. package/dist/components/{ui-labels.d.ts → field-base-labels.d.ts} +0 -2
  180. package/dist/components/{ui-labels.js → field-base-labels.js} +2 -9
  181. package/dist/components/field-base-labels.js.map +1 -0
  182. package/dist/components/field-base.d.ts +4 -3
  183. package/dist/components/field-base.js +3 -3
  184. package/dist/components/field-base.js.map +1 -1
  185. package/dist/components/field-sync-labels.d.ts +1 -0
  186. package/dist/components/field-sync-labels.js.map +1 -1
  187. package/dist/components/field-sync.d.ts +23 -1
  188. package/dist/components/field-sync.js.map +1 -1
  189. package/dist/components/form-actions.js +11 -5
  190. package/dist/components/form-actions.js.map +1 -1
  191. package/dist/components/hover-menu.d.ts +3 -0
  192. package/dist/components/hover-menu.js +5 -3
  193. package/dist/components/hover-menu.js.map +1 -1
  194. package/dist/components/icon-button.js +14 -9
  195. package/dist/components/icon-button.js.map +1 -1
  196. package/dist/components/inline-confirm.d.ts +43 -0
  197. package/dist/components/inline-confirm.js +67 -0
  198. package/dist/components/inline-confirm.js.map +1 -0
  199. package/dist/components/inline-entity-combobox.d.ts +4 -3
  200. package/dist/components/inline-entity-combobox.js +150 -141
  201. package/dist/components/inline-entity-combobox.js.map +1 -1
  202. package/dist/components/input.js +1 -1
  203. package/dist/components/input.js.map +1 -1
  204. package/dist/components/jump-calendar.js +28 -112
  205. package/dist/components/jump-calendar.js.map +1 -1
  206. package/dist/components/legal-page.d.ts +3 -1
  207. package/dist/components/legal-page.js +3 -2
  208. package/dist/components/legal-page.js.map +1 -1
  209. package/dist/components/legal.d.ts +4 -2
  210. package/dist/components/legal.js.map +1 -1
  211. package/dist/components/lightbox.d.ts +2 -2
  212. package/dist/components/lightbox.js +17 -6
  213. package/dist/components/lightbox.js.map +1 -1
  214. package/dist/components/list.d.ts +6 -2
  215. package/dist/components/list.js +4 -3
  216. package/dist/components/list.js.map +1 -1
  217. package/dist/components/measured-grid.d.ts +1 -1
  218. package/dist/components/measured-grid.js +2 -1
  219. package/dist/components/measured-grid.js.map +1 -1
  220. package/dist/components/mini-calendar.js +3 -5
  221. package/dist/components/mini-calendar.js.map +1 -1
  222. package/dist/components/modal.d.ts +24 -0
  223. package/dist/components/modal.js +12 -4
  224. package/dist/components/modal.js.map +1 -1
  225. package/dist/components/money-draft.js +7 -5
  226. package/dist/components/money-draft.js.map +1 -1
  227. package/dist/components/money-field.d.ts +2 -2
  228. package/dist/components/money-field.js.map +1 -1
  229. package/dist/components/month-grid.d.ts +55 -0
  230. package/dist/components/month-grid.js +148 -0
  231. package/dist/components/month-grid.js.map +1 -0
  232. package/dist/components/month-picker.d.ts +36 -4
  233. package/dist/components/month-picker.js +123 -146
  234. package/dist/components/month-picker.js.map +1 -1
  235. package/dist/components/multi-entity-combobox.js +2 -1
  236. package/dist/components/multi-entity-combobox.js.map +1 -1
  237. package/dist/components/multi-select.d.ts +2 -2
  238. package/dist/components/multi-select.js +11 -6
  239. package/dist/components/multi-select.js.map +1 -1
  240. package/dist/components/number-field.d.ts +6 -4
  241. package/dist/components/number-field.js +3 -2
  242. package/dist/components/number-field.js.map +1 -1
  243. package/dist/components/number-input.d.ts +4 -1
  244. package/dist/components/number-input.js +3 -2
  245. package/dist/components/number-input.js.map +1 -1
  246. package/dist/components/numpad-sheet.js.map +1 -1
  247. package/dist/components/picker-sheet.js +2 -1
  248. package/dist/components/picker-sheet.js.map +1 -1
  249. package/dist/components/pie-chart-labels.d.ts +7 -0
  250. package/dist/components/pie-chart-labels.js +1 -0
  251. package/dist/components/pie-chart-labels.js.map +1 -1
  252. package/dist/components/pie-chart.d.ts +5 -3
  253. package/dist/components/pie-chart.js +7 -22
  254. package/dist/components/pie-chart.js.map +1 -1
  255. package/dist/components/popover.d.ts +3 -0
  256. package/dist/components/popover.js +7 -1
  257. package/dist/components/popover.js.map +1 -1
  258. package/dist/components/reauth-dialog.d.ts +4 -5
  259. package/dist/components/reauth-dialog.js +1 -4
  260. package/dist/components/reauth-dialog.js.map +1 -1
  261. package/dist/components/row-actions.js +2 -1
  262. package/dist/components/row-actions.js.map +1 -1
  263. package/dist/components/section-nav.d.ts +7 -0
  264. package/dist/components/section-nav.js.map +1 -1
  265. package/dist/components/series-chart-axes.d.ts +10 -3
  266. package/dist/components/series-chart-axes.js +1 -0
  267. package/dist/components/series-chart-axes.js.map +1 -1
  268. package/dist/components/series-chart-labels.d.ts +7 -4
  269. package/dist/components/series-chart-labels.js.map +1 -1
  270. package/dist/components/series-chart.d.ts +31 -7
  271. package/dist/components/series-chart.js +72 -29
  272. package/dist/components/series-chart.js.map +1 -1
  273. package/dist/components/share-card.js +3 -3
  274. package/dist/components/share-card.js.map +1 -1
  275. package/dist/components/sign-chip-labels.d.ts +1 -0
  276. package/dist/components/sign-chip-labels.js.map +1 -1
  277. package/dist/components/sign-chip.d.ts +10 -1
  278. package/dist/components/sign-chip.js.map +1 -1
  279. package/dist/components/tabs-labels.d.ts +2 -0
  280. package/dist/components/tabs-labels.js +11 -0
  281. package/dist/components/tabs-labels.js.map +1 -0
  282. package/dist/components/tabs.d.ts +1 -1
  283. package/dist/components/tabs.js +13 -11
  284. package/dist/components/tabs.js.map +1 -1
  285. package/dist/components/toggle-legend.d.ts +2 -2
  286. package/dist/components/toggle-legend.js +6 -6
  287. package/dist/components/toggle-legend.js.map +1 -1
  288. package/dist/components/translation-review-editor.d.ts +4 -2
  289. package/dist/components/translation-review-editor.js +2 -3
  290. package/dist/components/translation-review-editor.js.map +1 -1
  291. package/dist/components/translation-review.d.ts +2 -1
  292. package/dist/components/translation-review.js +2 -2
  293. package/dist/components/translation-review.js.map +1 -1
  294. package/dist/components/treemap-labels.d.ts +26 -0
  295. package/dist/components/treemap-labels.js +10 -0
  296. package/dist/components/treemap-labels.js.map +1 -0
  297. package/dist/components/treemap-layout.d.ts +62 -0
  298. package/dist/components/treemap-layout.js +126 -0
  299. package/dist/components/treemap-layout.js.map +1 -0
  300. package/dist/components/treemap.d.ts +140 -17
  301. package/dist/components/treemap.js +324 -97
  302. package/dist/components/treemap.js.map +1 -1
  303. package/dist/components/use-table-state.d.ts +5 -5
  304. package/dist/components/use-table-state.js +4 -1
  305. package/dist/components/use-table-state.js.map +1 -1
  306. package/dist/data-table.d.ts +6 -2
  307. package/dist/data-table.js +7 -2
  308. package/dist/data-table.js.map +1 -1
  309. package/dist/eslint/index.js +1 -1
  310. package/dist/eslint/role-utilities.d.ts +36 -7
  311. package/dist/eslint/role-utilities.js +42 -9
  312. package/dist/eslint/role-utilities.js.map +1 -1
  313. package/dist/feedback/feedback-dialog.d.ts +25 -16
  314. package/dist/feedback/feedback-dialog.js +6 -2
  315. package/dist/feedback/feedback-dialog.js.map +1 -1
  316. package/dist/feedback/feedback-mutation.d.ts +30 -0
  317. package/dist/feedback/feedback-mutation.js +16 -0
  318. package/dist/feedback/feedback-mutation.js.map +1 -0
  319. package/dist/feedback/feedback-page-link.d.ts +53 -0
  320. package/dist/feedback/feedback-page-link.js +37 -0
  321. package/dist/feedback/feedback-page-link.js.map +1 -0
  322. package/dist/feedback/feedback-public-list.d.ts +12 -3
  323. package/dist/feedback/feedback-public-list.js +2 -1
  324. package/dist/feedback/feedback-public-list.js.map +1 -1
  325. package/dist/feedback/feedback-replies.d.ts +3 -1
  326. package/dist/feedback/feedback-replies.js +5 -4
  327. package/dist/feedback/feedback-replies.js.map +1 -1
  328. package/dist/feedback/feedback-row-detail-labels.js +5 -0
  329. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  330. package/dist/feedback/feedback-row-detail.d.ts +64 -28
  331. package/dist/feedback/feedback-row-detail.js +30 -28
  332. package/dist/feedback/feedback-row-detail.js.map +1 -1
  333. package/dist/feedback/feedback-status-undo.d.ts +30 -11
  334. package/dist/feedback/feedback-status-undo.js +10 -15
  335. package/dist/feedback/feedback-status-undo.js.map +1 -1
  336. package/dist/feedback/feedback-submit-dialog.d.ts +1 -1
  337. package/dist/feedback/feedback-submit-dialog.js +1 -1
  338. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  339. package/dist/feedback/feedback-submit.js +9 -3
  340. package/dist/feedback/feedback-submit.js.map +1 -1
  341. package/dist/feedback/feedback-swipe.d.ts +1 -1
  342. package/dist/feedback/feedback-swipe.js.map +1 -1
  343. package/dist/feedback/feedback-table.d.ts +21 -9
  344. package/dist/feedback/feedback-table.js +45 -25
  345. package/dist/feedback/feedback-table.js.map +1 -1
  346. package/dist/feedback/feedback-thread-labels.d.ts +2 -2
  347. package/dist/feedback/feedback-thread-labels.js.map +1 -1
  348. package/dist/feedback/feedback-thread.d.ts +24 -23
  349. package/dist/feedback/feedback-thread.js +2 -1
  350. package/dist/feedback/feedback-thread.js.map +1 -1
  351. package/dist/feedback.d.ts +34 -0
  352. package/dist/feedback.js +42 -0
  353. package/dist/feedback.js.map +1 -1
  354. package/dist/hooks/use-dismiss.js.map +1 -1
  355. package/dist/hooks/use-focus-trap.d.ts +35 -0
  356. package/dist/hooks/use-focus-trap.js +6 -4
  357. package/dist/hooks/use-focus-trap.js.map +1 -1
  358. package/dist/hooks/use-hotkey.d.ts +5 -2
  359. package/dist/hooks/use-hotkey.js +5 -4
  360. package/dist/hooks/use-hotkey.js.map +1 -1
  361. package/dist/hooks/use-long-press.d.ts +7 -4
  362. package/dist/hooks/use-long-press.js +3 -0
  363. package/dist/hooks/use-long-press.js.map +1 -1
  364. package/dist/hooks/use-media-query.js +12 -4
  365. package/dist/hooks/use-media-query.js.map +1 -1
  366. package/dist/hooks/use-mounted.d.ts +22 -0
  367. package/dist/hooks/use-mounted.js +24 -0
  368. package/dist/hooks/use-mounted.js.map +1 -0
  369. package/dist/hooks/use-overlay-history.d.ts +7 -1
  370. package/dist/hooks/use-overlay-history.js +35 -5
  371. package/dist/hooks/use-overlay-history.js.map +1 -1
  372. package/dist/i18n/defaults.js +4 -5
  373. package/dist/i18n/defaults.js.map +1 -1
  374. package/dist/i18n/german.js +7 -1
  375. package/dist/i18n/german.js.map +1 -1
  376. package/dist/i18n/kit-labels.d.ts +9 -2
  377. package/dist/i18n/kit-labels.js.map +1 -1
  378. package/dist/i18n/locales/en.js +20 -41
  379. package/dist/i18n/locales/en.js.map +3 -3
  380. package/dist/i18n/locales/es.js +7 -1
  381. package/dist/i18n/locales/es.js.map +1 -1
  382. package/dist/i18n/locales/fr.js +20 -10
  383. package/dist/i18n/locales/fr.js.map +1 -1
  384. package/dist/i18n/locales/hu.js +9 -1
  385. package/dist/i18n/locales/hu.js.map +1 -1
  386. package/dist/i18n/locales/it.js +7 -1
  387. package/dist/i18n/locales/it.js.map +1 -1
  388. package/dist/i18n/locales/zh.js +8 -1
  389. package/dist/i18n/locales/zh.js.map +1 -1
  390. package/dist/i18n/review.js +5 -0
  391. package/dist/i18n/review.js.map +1 -1
  392. package/dist/index.d.ts +64 -17
  393. package/dist/index.js +77 -12
  394. package/dist/index.js.map +1 -1
  395. package/dist/landing/routing.d.ts +3 -1
  396. package/dist/landing/routing.js +4 -7
  397. package/dist/landing/routing.js.map +1 -1
  398. package/dist/lib/broadcast.d.ts +17 -0
  399. package/dist/lib/broadcast.js +30 -0
  400. package/dist/lib/broadcast.js.map +1 -0
  401. package/dist/lib/calc.d.ts +7 -1
  402. package/dist/lib/calc.js +3 -1
  403. package/dist/lib/calc.js.map +1 -1
  404. package/dist/lib/clipboard-minus.d.ts +2 -2
  405. package/dist/lib/clipboard-minus.js +1 -1
  406. package/dist/lib/clipboard-minus.js.map +1 -1
  407. package/dist/lib/date-format.d.ts +37 -2
  408. package/dist/lib/date-format.js +34 -8
  409. package/dist/lib/date-format.js.map +1 -1
  410. package/dist/lib/day-format.d.ts +46 -0
  411. package/dist/lib/day-format.js +46 -0
  412. package/dist/lib/day-format.js.map +1 -0
  413. package/dist/lib/decimal-marks.d.ts +7 -1
  414. package/dist/lib/decimal-marks.js +5 -2
  415. package/dist/lib/decimal-marks.js.map +1 -1
  416. package/dist/lib/describe-failure.d.ts +14 -0
  417. package/dist/lib/describe-failure.js +9 -0
  418. package/dist/lib/describe-failure.js.map +1 -0
  419. package/dist/lib/direction.d.ts +16 -0
  420. package/dist/lib/direction.js +9 -1
  421. package/dist/lib/direction.js.map +1 -1
  422. package/dist/lib/focus-left.d.ts +63 -0
  423. package/dist/lib/focus-left.js +67 -0
  424. package/dist/lib/focus-left.js.map +1 -0
  425. package/dist/lib/format.d.ts +5 -3
  426. package/dist/lib/format.js +16 -13
  427. package/dist/lib/format.js.map +1 -1
  428. package/dist/lib/http-status.d.ts +24 -0
  429. package/dist/lib/http-status.js +14 -0
  430. package/dist/lib/http-status.js.map +1 -0
  431. package/dist/lib/intl-cache.d.ts +14 -0
  432. package/dist/lib/intl-cache.js +15 -0
  433. package/dist/lib/intl-cache.js.map +1 -0
  434. package/dist/lib/isin.d.ts +10 -0
  435. package/dist/lib/isin.js.map +1 -1
  436. package/dist/lib/iso-day.d.ts +11 -0
  437. package/dist/lib/iso-day.js +8 -0
  438. package/dist/lib/iso-day.js.map +1 -0
  439. package/dist/lib/lazy-with-fallback.d.ts +31 -0
  440. package/dist/lib/lazy-with-fallback.js +40 -0
  441. package/dist/lib/lazy-with-fallback.js.map +1 -0
  442. package/dist/lib/path-pattern.d.ts +34 -0
  443. package/dist/lib/path-pattern.js +24 -0
  444. package/dist/lib/path-pattern.js.map +1 -0
  445. package/dist/lib/reduced-motion.d.ts +2 -1
  446. package/dist/lib/reduced-motion.js.map +1 -1
  447. package/dist/lib/round.d.ts +2 -1
  448. package/dist/lib/round.js +2 -1
  449. package/dist/lib/round.js.map +1 -1
  450. package/dist/lib/safe-storage.d.ts +24 -5
  451. package/dist/lib/safe-storage.js +27 -2
  452. package/dist/lib/safe-storage.js.map +1 -1
  453. package/dist/lib/session-refresh.js +1 -1
  454. package/dist/lib/session-refresh.js.map +1 -1
  455. package/dist/lib/share-format.d.ts +13 -0
  456. package/dist/lib/share-format.js +10 -0
  457. package/dist/lib/share-format.js.map +1 -0
  458. package/dist/lib/text-case.d.ts +17 -0
  459. package/dist/lib/text-case.js +8 -0
  460. package/dist/lib/text-case.js.map +1 -0
  461. package/dist/lib/text-match.d.ts +38 -0
  462. package/dist/lib/text-match.js +24 -2
  463. package/dist/lib/text-match.js.map +1 -1
  464. package/dist/lib/thenable.d.ts +13 -0
  465. package/dist/lib/thenable.js +8 -0
  466. package/dist/lib/thenable.js.map +1 -0
  467. package/dist/lib/translation-review.d.ts +7 -2
  468. package/dist/lib/translation-review.js +4 -4
  469. package/dist/lib/translation-review.js.map +1 -1
  470. package/dist/notifications/device-zone-report.js +1 -1
  471. package/dist/notifications/device-zone-report.js.map +1 -1
  472. package/dist/notifications/notification-bell.d.ts +2 -1
  473. package/dist/notifications/notification-bell.js +3 -3
  474. package/dist/notifications/notification-bell.js.map +1 -1
  475. package/dist/notifications/notification-inbox.d.ts +10 -6
  476. package/dist/notifications/notification-inbox.js +26 -48
  477. package/dist/notifications/notification-inbox.js.map +1 -1
  478. package/dist/notifications/notification-parts.d.ts +3 -2
  479. package/dist/notifications/notification-parts.js +1 -3
  480. package/dist/notifications/notification-parts.js.map +1 -1
  481. package/dist/notifications/notification-types-setting.js +1 -1
  482. package/dist/notifications/notification-types-setting.js.map +1 -1
  483. package/dist/notifications/notifications-labels.d.ts +6 -0
  484. package/dist/notifications/notifications-labels.js +1 -0
  485. package/dist/notifications/notifications-labels.js.map +1 -1
  486. package/dist/notifications/push-device-setting.js +1 -1
  487. package/dist/notifications/push-device-setting.js.map +1 -1
  488. package/dist/notifications/push-devices-setting.d.ts +2 -1
  489. package/dist/notifications/push-devices-setting.js +27 -49
  490. package/dist/notifications/push-devices-setting.js.map +1 -1
  491. package/dist/notifications/quiet-hours-setting.d.ts +10 -3
  492. package/dist/notifications/quiet-hours-setting.js +65 -26
  493. package/dist/notifications/quiet-hours-setting.js.map +1 -1
  494. package/dist/notifications/unsubscribe-panel.js +4 -7
  495. package/dist/notifications/unsubscribe-panel.js.map +1 -1
  496. package/dist/notifications/use-push-device.d.ts +39 -1
  497. package/dist/notifications/use-push-device.js +28 -7
  498. package/dist/notifications/use-push-device.js.map +1 -1
  499. package/dist/offline/query-persistence.d.ts +3 -1
  500. package/dist/offline/query-persistence.js +19 -2
  501. package/dist/offline/query-persistence.js.map +1 -1
  502. package/dist/rhf/fields.d.ts +11 -4
  503. package/dist/rhf/fields.js.map +1 -1
  504. package/dist/search/command-palette.js +1 -1
  505. package/dist/search/command-palette.js.map +1 -1
  506. package/dist/search/global-search.js +19 -9
  507. package/dist/search/global-search.js.map +1 -1
  508. package/dist/search/use-command-key.d.ts +12 -1
  509. package/dist/search/use-command-key.js +3 -12
  510. package/dist/search/use-command-key.js.map +1 -1
  511. package/dist/search.d.ts +7 -0
  512. package/dist/search.js +10 -0
  513. package/dist/search.js.map +1 -1
  514. package/dist/settings/use-settings-focus.js +1 -0
  515. package/dist/settings/use-settings-focus.js.map +1 -1
  516. package/dist/shell/account-menu-language.d.ts +21 -5
  517. package/dist/shell/account-menu-language.js +3 -1
  518. package/dist/shell/account-menu-language.js.map +1 -1
  519. package/dist/shell/account-menu-text-size.d.ts +26 -9
  520. package/dist/shell/account-menu-text-size.js +3 -2
  521. package/dist/shell/account-menu-text-size.js.map +1 -1
  522. package/dist/shell/dev-menu.js +5 -18
  523. package/dist/shell/dev-menu.js.map +1 -1
  524. package/dist/shell/role-switcher.d.ts +7 -0
  525. package/dist/shell/role-switcher.js.map +1 -1
  526. package/dist/shell/top-bar-actions.d.ts +1 -1
  527. package/dist/shell/top-bar-actions.js.map +1 -1
  528. package/dist/shell/top-bar-parts-labels.d.ts +0 -2
  529. package/dist/shell/top-bar-parts-labels.js +0 -1
  530. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  531. package/dist/shell.d.ts +27 -8
  532. package/dist/shell.js +28 -7
  533. package/dist/shell.js.map +1 -1
  534. package/dist/sync/engine.d.ts +30 -4
  535. package/dist/sync/engine.js +172 -52
  536. package/dist/sync/engine.js.map +1 -1
  537. package/dist/sync.d.ts +6 -2
  538. package/dist/sync.js +6 -1
  539. package/dist/sync.js.map +1 -1
  540. package/dist/testing/css-variables.js +3 -8
  541. package/dist/testing/css-variables.js.map +1 -1
  542. package/dist/theme/contrast.d.ts +2 -1
  543. package/dist/theme/contrast.js +3 -8
  544. package/dist/theme/contrast.js.map +1 -1
  545. package/dist/theme/palette-store.js +6 -6
  546. package/dist/theme/palette-store.js.map +1 -1
  547. package/dist/theme/text-size.js +3 -8
  548. package/dist/theme/text-size.js.map +1 -1
  549. package/dist/theme/theme-store.js +3 -6
  550. package/dist/theme/theme-store.js.map +1 -1
  551. package/dist/tour/tour-catalogue.d.ts +7 -4
  552. package/dist/tour/tour-catalogue.js +12 -10
  553. package/dist/tour/tour-catalogue.js.map +1 -1
  554. package/dist/tour/tour-dock.d.ts +0 -2
  555. package/dist/tour/tour-dock.js +0 -2
  556. package/dist/tour/tour-dock.js.map +1 -1
  557. package/dist/tour/tour-gates.d.ts +4 -0
  558. package/dist/tour/tour-gates.js +14 -0
  559. package/dist/tour/tour-gates.js.map +1 -1
  560. package/dist/tour/tour-overlay.d.ts +27 -0
  561. package/dist/tour/tour-overlay.js +741 -0
  562. package/dist/tour/tour-overlay.js.map +1 -0
  563. package/dist/tour/tour.d.ts +16 -4
  564. package/dist/tour/tour.js +62 -778
  565. package/dist/tour/tour.js.map +1 -1
  566. package/dist/tour/use-tour-progress.js +1 -1
  567. package/dist/tour/use-tour-progress.js.map +1 -1
  568. package/dist/tour/use-tour-url-sync.js +2 -2
  569. package/dist/tour/use-tour-url-sync.js.map +1 -1
  570. package/dist/wizard/stepper-nav.d.ts +5 -1
  571. package/dist/wizard/stepper-nav.js.map +1 -1
  572. package/dist/wizard/types.d.ts +6 -2
  573. package/dist/wizard/types.js.map +1 -1
  574. package/dist/wizard/use-wizard.d.ts +3 -1
  575. package/dist/wizard/use-wizard.js.map +1 -1
  576. package/dist/wizard/validation.d.ts +3 -1
  577. package/dist/wizard/validation.js.map +1 -1
  578. package/package.json +12 -8
  579. package/src/account/account-parts.ts +5 -25
  580. package/src/account/data-export-setting-labels.ts +1 -1
  581. package/src/account/delete-account-setting-labels.ts +1 -1
  582. package/src/account/email-change-setting-labels.ts +1 -1
  583. package/src/account/passkeys-setting.tsx +60 -38
  584. package/src/account/sessions-setting.tsx +18 -12
  585. package/src/admin/admin-action-confirm.tsx +5 -10
  586. package/src/admin/admin-parts.ts +11 -25
  587. package/src/admin/mail-test-card-labels.ts +1 -1
  588. package/src/admin/plan-change-labels.ts +5 -23
  589. package/src/admin/plan-change.tsx +7 -44
  590. package/src/admin/reviewer-scope-editor.tsx +3 -3
  591. package/src/auth/auth-errors-labels.ts +23 -0
  592. package/src/auth/auth-errors.ts +11 -38
  593. package/src/auth/complete-name-dialog.tsx +9 -8
  594. package/src/auth/forgot-password-form-labels.ts +1 -1
  595. package/src/auth/forgot-password-form.tsx +11 -6
  596. package/src/auth/register-form-labels.ts +1 -1
  597. package/src/auth/reset-password-form-labels.ts +1 -1
  598. package/src/auth/reset-password-form.tsx +8 -4
  599. package/src/auth/sign-in-form-labels.ts +1 -1
  600. package/src/auth/status-parts.tsx +0 -6
  601. package/src/auth/verify-email-labels.ts +1 -1
  602. package/src/auth/verify-email.tsx +11 -6
  603. package/src/billing/cancel-request.ts +28 -6
  604. package/src/billing/cancel-subscription.tsx +29 -22
  605. package/src/billing/dialog-close.ts +34 -0
  606. package/src/billing/plan-card.tsx +36 -11
  607. package/src/billing/plan-change-labels.ts +66 -0
  608. package/src/billing/plan-switch.tsx +31 -20
  609. package/src/chart.ts +21 -3
  610. package/src/components/account-chips.tsx +20 -23
  611. package/src/components/alert-banner.tsx +82 -5
  612. package/src/components/amount-input.tsx +32 -14
  613. package/src/components/autocomplete.tsx +64 -70
  614. package/src/components/bulk-action-bar.tsx +70 -2
  615. package/src/components/button-look.ts +5 -5
  616. package/src/components/button.tsx +2 -2
  617. package/src/components/calculator.tsx +98 -17
  618. package/src/components/chart-edge.ts +34 -1
  619. package/src/components/chart-figure.tsx +35 -0
  620. package/src/components/chart-zoom-core.tsx +6 -5
  621. package/src/components/chart.tsx +26 -5
  622. package/src/components/combobox-core.tsx +303 -69
  623. package/src/components/combobox.tsx +184 -155
  624. package/src/components/copy-button.tsx +34 -23
  625. package/src/components/country-select.tsx +16 -11
  626. package/src/components/data-table-column-settings.tsx +52 -10
  627. package/src/components/data-table-filters.ts +6 -4
  628. package/src/components/data-table-fit.ts +19 -5
  629. package/src/components/data-table-groups.tsx +1 -1
  630. package/src/components/data-table-head.tsx +32 -22
  631. package/src/components/data-table-mobile.tsx +110 -27
  632. package/src/components/data-table-pagination.tsx +21 -6
  633. package/src/components/data-table-resize.ts +1 -1
  634. package/src/components/data-table-row-actions.tsx +3 -3
  635. package/src/components/data-table-row.tsx +25 -14
  636. package/src/components/data-table-selection.ts +1 -1
  637. package/src/components/data-table-shared.tsx +33 -1
  638. package/src/components/data-table-sort.ts +57 -2
  639. package/src/components/data-table-virtual.ts +32 -8
  640. package/src/components/data-table.tsx +267 -41
  641. package/src/components/date-field.tsx +65 -8
  642. package/src/components/date-picker.tsx +125 -48
  643. package/src/components/date-range-picker.tsx +82 -31
  644. package/src/components/dialog-frame.tsx +2 -1
  645. package/src/components/entity-combobox.tsx +4 -1
  646. package/src/components/error-boundary.tsx +53 -39
  647. package/src/components/field-base-labels.ts +20 -0
  648. package/src/components/field-base.tsx +13 -7
  649. package/src/components/field-sync-labels.ts +1 -0
  650. package/src/components/field-sync.tsx +23 -1
  651. package/src/components/form-actions.tsx +20 -5
  652. package/src/components/hover-menu.tsx +18 -8
  653. package/src/components/icon-button.tsx +14 -9
  654. package/src/components/inline-confirm.tsx +116 -0
  655. package/src/components/inline-entity-combobox.tsx +198 -152
  656. package/src/components/input.tsx +1 -1
  657. package/src/components/jump-calendar.tsx +30 -146
  658. package/src/components/legal-page.tsx +10 -7
  659. package/src/components/legal.tsx +4 -2
  660. package/src/components/lightbox.tsx +21 -8
  661. package/src/components/list.tsx +14 -5
  662. package/src/components/measured-grid.tsx +8 -4
  663. package/src/components/mini-calendar.tsx +6 -5
  664. package/src/components/modal.tsx +45 -4
  665. package/src/components/money-draft.ts +16 -5
  666. package/src/components/money-field.tsx +2 -2
  667. package/src/components/month-grid.tsx +229 -0
  668. package/src/components/month-picker.tsx +192 -200
  669. package/src/components/multi-entity-combobox.tsx +1 -0
  670. package/src/components/multi-select.tsx +21 -9
  671. package/src/components/number-field.tsx +14 -7
  672. package/src/components/number-input.tsx +9 -3
  673. package/src/components/numpad-sheet.tsx +4 -3
  674. package/src/components/picker-sheet.tsx +12 -9
  675. package/src/components/pie-chart-labels.ts +8 -0
  676. package/src/components/pie-chart.tsx +22 -28
  677. package/src/components/popover.tsx +18 -1
  678. package/src/components/reauth-dialog.tsx +6 -10
  679. package/src/components/row-actions.tsx +2 -1
  680. package/src/components/section-nav.tsx +7 -0
  681. package/src/components/series-chart-axes.ts +11 -3
  682. package/src/components/series-chart-labels.ts +7 -4
  683. package/src/components/series-chart.tsx +178 -69
  684. package/src/components/share-card.tsx +6 -6
  685. package/src/components/sign-chip-labels.ts +1 -0
  686. package/src/components/sign-chip.tsx +10 -1
  687. package/src/components/tabs-labels.ts +13 -0
  688. package/src/components/tabs.tsx +35 -19
  689. package/src/components/toggle-legend.tsx +16 -11
  690. package/src/components/translation-review-editor.tsx +6 -5
  691. package/src/components/translation-review.tsx +4 -3
  692. package/src/components/treemap-labels.ts +39 -0
  693. package/src/components/treemap-layout.ts +210 -0
  694. package/src/components/treemap.tsx +722 -133
  695. package/src/components/use-table-state.ts +12 -9
  696. package/src/data-table.ts +9 -2
  697. package/src/eslint/role-utilities.ts +97 -19
  698. package/src/feedback/feedback-dialog.tsx +30 -19
  699. package/src/feedback/feedback-mutation.ts +41 -0
  700. package/src/feedback/feedback-page-link.ts +90 -0
  701. package/src/feedback/feedback-public-list.tsx +17 -5
  702. package/src/feedback/feedback-replies.tsx +13 -6
  703. package/src/feedback/feedback-row-detail-labels.ts +5 -0
  704. package/src/feedback/feedback-row-detail.tsx +103 -67
  705. package/src/feedback/feedback-status-undo.ts +41 -27
  706. package/src/feedback/feedback-submit-dialog.tsx +2 -2
  707. package/src/feedback/feedback-submit.tsx +21 -7
  708. package/src/feedback/feedback-swipe.tsx +1 -1
  709. package/src/feedback/feedback-table.tsx +86 -38
  710. package/src/feedback/feedback-thread-labels.ts +2 -2
  711. package/src/feedback/feedback-thread.tsx +27 -25
  712. package/src/feedback.ts +42 -0
  713. package/src/hooks/use-dismiss.ts +3 -2
  714. package/src/hooks/use-focus-trap.ts +8 -24
  715. package/src/hooks/use-hotkey.ts +24 -7
  716. package/src/hooks/use-long-press.ts +16 -2
  717. package/src/hooks/use-media-query.ts +20 -4
  718. package/src/hooks/use-mounted.ts +39 -0
  719. package/src/hooks/use-overlay-history.ts +70 -5
  720. package/src/i18n/defaults.ts +4 -5
  721. package/src/i18n/german.ts +8 -2
  722. package/src/i18n/kit-labels.tsx +9 -2
  723. package/src/i18n/locales/es.ts +8 -2
  724. package/src/i18n/locales/fr.ts +21 -13
  725. package/src/i18n/locales/hu.ts +10 -2
  726. package/src/i18n/locales/it.ts +8 -2
  727. package/src/i18n/locales/zh.ts +9 -2
  728. package/src/i18n/review.ts +5 -0
  729. package/src/index.ts +103 -13
  730. package/src/landing/routing.tsx +14 -10
  731. package/src/lib/broadcast.ts +52 -0
  732. package/src/lib/calc.ts +13 -2
  733. package/src/lib/clipboard-minus.ts +14 -4
  734. package/src/lib/date-format.ts +89 -13
  735. package/src/lib/day-format.ts +96 -0
  736. package/src/lib/decimal-marks.ts +12 -3
  737. package/src/lib/describe-failure.ts +18 -0
  738. package/src/lib/direction.ts +39 -0
  739. package/src/lib/focus-left.ts +156 -0
  740. package/src/lib/format.ts +34 -19
  741. package/src/lib/http-status.ts +38 -0
  742. package/src/lib/intl-cache.ts +25 -0
  743. package/src/lib/isin.ts +10 -0
  744. package/src/lib/iso-day.ts +13 -0
  745. package/src/lib/lazy-with-fallback.ts +82 -0
  746. package/src/lib/path-pattern.ts +55 -0
  747. package/src/lib/reduced-motion.ts +2 -1
  748. package/src/lib/round.ts +7 -2
  749. package/src/lib/safe-storage.ts +48 -6
  750. package/src/lib/session-refresh.ts +1 -1
  751. package/src/lib/share-format.ts +18 -0
  752. package/src/lib/text-case.ts +19 -0
  753. package/src/lib/text-match.ts +69 -2
  754. package/src/lib/thenable.ts +19 -0
  755. package/src/lib/translation-review.ts +13 -5
  756. package/src/notifications/device-zone-report.ts +1 -1
  757. package/src/notifications/notification-bell.tsx +7 -4
  758. package/src/notifications/notification-inbox.tsx +40 -58
  759. package/src/notifications/notification-parts.tsx +3 -4
  760. package/src/notifications/notification-types-setting.tsx +1 -1
  761. package/src/notifications/notifications-labels.ts +7 -0
  762. package/src/notifications/push-device-setting.tsx +1 -1
  763. package/src/notifications/push-devices-setting.tsx +30 -55
  764. package/src/notifications/quiet-hours-setting.tsx +93 -31
  765. package/src/notifications/unsubscribe-panel.tsx +4 -7
  766. package/src/notifications/use-push-device.ts +76 -10
  767. package/src/offline/query-persistence.ts +35 -3
  768. package/src/rhf/fields.tsx +11 -4
  769. package/src/search/command-palette.tsx +2 -4
  770. package/src/search/global-search.tsx +36 -15
  771. package/src/search/use-command-key.ts +13 -12
  772. package/src/search.ts +9 -0
  773. package/src/settings/use-settings-focus.ts +3 -0
  774. package/src/shell/account-menu-language.tsx +27 -5
  775. package/src/shell/account-menu-text-size.tsx +32 -10
  776. package/src/shell/dev-menu.tsx +7 -21
  777. package/src/shell/role-switcher.tsx +7 -0
  778. package/src/shell/top-bar-actions.tsx +1 -1
  779. package/src/shell/top-bar-parts-labels.ts +0 -3
  780. package/src/shell.ts +40 -9
  781. package/src/sync/engine.ts +339 -61
  782. package/src/sync.ts +8 -1
  783. package/src/testing/css-variables.ts +8 -9
  784. package/src/theme/contrast.ts +8 -9
  785. package/src/theme/palette-store.ts +9 -9
  786. package/src/theme/text-size.ts +6 -8
  787. package/src/theme/theme-store.ts +7 -9
  788. package/src/tour/tour-catalogue.tsx +26 -15
  789. package/src/tour/tour-dock.ts +0 -2
  790. package/src/tour/tour-gates.ts +23 -0
  791. package/src/tour/tour-overlay.tsx +1170 -0
  792. package/src/tour/tour.tsx +116 -1193
  793. package/src/tour/use-tour-progress.ts +1 -1
  794. package/src/tour/use-tour-url-sync.ts +7 -3
  795. package/src/wizard/stepper-nav.tsx +3 -1
  796. package/src/wizard/types.ts +11 -2
  797. package/src/wizard/use-wizard.ts +2 -1
  798. package/src/wizard/validation.ts +8 -2
  799. package/tokens.css +2 -1
  800. package/dist/components/ui-labels.js.map +0 -1
  801. package/dist/shell/dev-switchers.d.ts +0 -6
  802. package/dist/shell/dev-switchers.js +0 -12
  803. package/dist/shell/dev-switchers.js.map +0 -1
  804. package/src/components/ui-labels.ts +0 -24
  805. package/src/shell/dev-switchers.tsx +0 -18
@@ -8,6 +8,7 @@ import { useRangeSelection } from "./data-table-selection";
8
8
  import { columnLabel, logicalAlign, resolveDataTableLabels } from "./data-table-shared";
9
9
  import {
10
10
  MobileFilters,
11
+ MobileLeadingRow,
11
12
  MobileSelectBar,
12
13
  MobileSort,
13
14
  StackedFields,
@@ -41,8 +42,9 @@ import { ColumnSettingsPanel } from "./data-table-column-settings";
41
42
  import { useLargeText } from "../hooks/use-large-text";
42
43
  import { cn } from "../lib/cn";
43
44
  import { isFilterActive, resolveFilter, rowMatches } from "./data-table-filters";
45
+ import { matchesSearch, searchWords } from "../lib/text-match";
44
46
  import type { ColumnFilter, FilterValue } from "./data-table-filters";
45
- import { nextSorts } from "./data-table-sort";
47
+ import { compareSortValues, nextSorts } from "./data-table-sort";
46
48
  import type { SortCycle, SortDir, SortState } from "./data-table-sort";
47
49
  import { Pagination } from "./data-table-pagination";
48
50
  import type { SwipeAction } from "./swipeable-row";
@@ -60,6 +62,7 @@ import {
60
62
  } from "../i18n/kit-labels";
61
63
  import { useEdgeFade } from "../lib/strip-fade";
62
64
  import { dirOf, type Direction } from "../lib/direction";
65
+ import { focusContainer, focusFirst, focusIsLost, tabStops, whenFocusLeftForNothing } from "../lib/focus-left";
63
66
 
64
67
  // ---------- Types ----------
65
68
 
@@ -67,6 +70,11 @@ export interface DataTableColumn<T> {
67
70
  key: string;
68
71
  header: ReactNode;
69
72
  cell: (row: T) => ReactNode;
73
+ /** What a client sort orders the column by. Strings collate in the table's `locale`
74
+ * (digits as numbers, case and accents left out; 0.51.7, audit 2026-10-30 DSP-3),
75
+ * numbers compare as numbers and sort before strings, `null` and `undefined` sort
76
+ * last in either direction. The order is `compareSortValues`, exported for an app's
77
+ * own list beside the table (0.52). */
70
78
  sortBy?: (row: T) => string | number | null | undefined;
71
79
  filter?: ColumnFilter<T>;
72
80
  filterBy?: (row: T) => string;
@@ -261,8 +269,11 @@ export interface ServerPagination {
261
269
  }
262
270
 
263
271
  export interface DataTableProps<T> {
264
- rows: T[];
265
- columns: DataTableColumn<T>[];
272
+ /** `readonly` since 0.52 (refactor audit 2026-10-30, API-7): the table never changes the
273
+ * arrays it is handed, so a caller's `as const` list or a query's frozen result needs no
274
+ * copy. Only widens: a mutable array is still one. The same for `columns` and `sorts`. */
275
+ rows: readonly T[];
276
+ columns: readonly DataTableColumn<T>[];
266
277
  rowKey: (row: T) => string | number;
267
278
  defaultPageSize?: number;
268
279
  onRowClick?: (row: T) => void;
@@ -284,6 +295,11 @@ export interface DataTableProps<T> {
284
295
  * not wrap table cells, and the absolutely-positioned row overlay that is the
285
296
  * usual workaround would sit on top of the per-cell controls these rows carry
286
297
  * (status toggles, the selection checkbox, nested links) and swallow them.
298
+ *
299
+ * With `onRowClick` a plain click opens the row through it, in place. Without one
300
+ * (0.52, refactor audit 2026-10-30, DSP-23 b) the click follows the link — through the
301
+ * provider's `linkComponent` for an in-app path, as every kit link — and the phone
302
+ * card is that link too; before, the click was cancelled and opened nothing.
287
303
  */
288
304
  rowHref?: (row: T) => string | undefined;
289
305
  expandedRow?: (row: T) => ReactNode | null;
@@ -437,7 +453,7 @@ export interface DataTableProps<T> {
437
453
  */
438
454
  filters?: FilterState;
439
455
  onFiltersChange?: (next: FilterState) => void;
440
- sorts?: SortState[];
456
+ sorts?: readonly SortState[];
441
457
  onSortsChange?: (next: SortState[]) => void;
442
458
  /**
443
459
  * Controlled page size, as `sorts` above: the table pages by it and hands its pager's
@@ -618,8 +634,10 @@ export interface DataTableProps<T> {
618
634
  */
619
635
  desktopSwipeActions?: boolean | DataTableDesktopSwipeActions<T>;
620
636
  /**
621
- * Renders as a full-width row above the data rows in the desktop table
622
- * (mobile has no equivalent list-row slot, so it's desktop-only). For a
637
+ * Renders as a full-width row above the data rows in the desktop table, and since
638
+ * 0.51.7 as the first item of the phone's card list (audit 2026-10-30 DSP-2: the card
639
+ * list dropped it, and kastlan's inline "Add meter" editor never appeared on a phone).
640
+ * On the phone it is no card: no row link, swipe or selection toggle. For a
623
641
  * toggle that shows/hides a slice of rows, style it as an expand/collapse
624
642
  * disclosure (chevron + label) so it reads as part of the table rather
625
643
  * than a floating control above it. See feedback #10/#11 (transactions'
@@ -629,9 +647,11 @@ export interface DataTableProps<T> {
629
647
  /**
630
648
  * 0.48 (keksdose dev #603: "it should rather be sticky, so the user can show hide them
631
649
  * everywhere on click"): pin the {@link leadingRow} under the sticky header while the
632
- * rows scroll beneath both — its `top` is the header's measured height. Desktop only,
633
- * as `leadingRow` is; it sticks within the table's own scroller (a bounded body:
634
- * `fillHeight` or `maxBodyHeight`). Default: it scrolls with the rows.
650
+ * rows scroll beneath both — its `top` is the header's measured height. It sticks
651
+ * within the table's own scroller (a bounded body: `fillHeight` or `maxBodyHeight`).
652
+ * On a phone (0.51.7) it is pinned at the top of the card list's scroller (the list
653
+ * under a bounded `fillHeight`, else the page), with `mobileGroupBy`'s section headers
654
+ * under it. Default: it scrolls with the rows.
635
655
  */
636
656
  leadingRowSticky?: boolean;
637
657
  /**
@@ -922,6 +942,28 @@ export interface DataTableDesktopSwipeActions<T> {
922
942
  */
923
943
  const FOOTER_CELL = "sticky bottom-0 z-10 bg-surface-2 shadow-[inset_0_2px_0_var(--border-strong)]";
924
944
 
945
+ /** Where focus that leaves a row is still the row's (DSP-4): an overlay — a confirm, a
946
+ * menu, a sheet — hands it back or closes with the row it was about. The kit marks its
947
+ * own (`data-kit-layer`); an app's dialog says what it is. */
948
+ const OVERLAY_SELECTOR = '[data-kit-layer],[role="dialog"],[role="alertdialog"],[aria-modal="true"],[role="menu"]';
949
+
950
+ /** `rows`' places by `rowKey`, the first row of a key winning as a `findIndex`'s did; the
951
+ * map built at the first lookup (0.52 code review, data-table.tsx). */
952
+ function keyIndex<T>(rows: readonly T[], rowKey: (row: T) => string | number): (key: string | number) => number {
953
+ let at: Map<string | number, number> | null = null;
954
+ return (key) => {
955
+ if (!at) {
956
+ at = new Map();
957
+ for (let i = rows.length - 1; i >= 0; i--) at.set(rowKey(rows[i]), i);
958
+ }
959
+ return at.get(key) ?? -1;
960
+ };
961
+ }
962
+
963
+ /** How long a filter's "n of m rows" waits for the typing to pause (DSP-23 d): longer than
964
+ * the gap between two keystrokes, short enough to answer the word just typed. */
965
+ const FILTER_ANNOUNCE_DELAY_MS = 500;
966
+
925
967
  // ---------- Phone sort control (keksdose K10) ----------
926
968
 
927
969
  /**
@@ -968,6 +1010,21 @@ import { DEFAULT_PERSIST_PREFIX, useTableState, type TableUrlSync } from "./use-
968
1010
  import { useMobileReveal } from "./use-mobile-reveal";
969
1011
  import { GROW_CELL_CLASS, GROW_PEER_CELL_CLASS, useColumnFit } from "./data-table-fit";
970
1012
 
1013
+ /**
1014
+ * rowMatches for one column's filter state, the text filter's query folded once (0.52
1015
+ * code review, data-table-filters.ts): folded again for every row it tested, a 5000-row
1016
+ * table folded the same query 5000 times per keystroke. Module-private: data-table-filters
1017
+ * is re-exported whole by @eifi1/ui-kit/data-table, and this is no public API.
1018
+ */
1019
+ function rowMatcher<T>(col: DataTableColumn<T>, state: FilterValue, locale?: string): (row: T) => boolean {
1020
+ const filter = resolveFilter(col);
1021
+ if (filter?.type === "text" && state.type === "text" && state.q.trim()) {
1022
+ const words = searchWords(state.q, locale);
1023
+ return (row) => matchesSearch(words, [filter.getValue(row)], locale);
1024
+ }
1025
+ return (row) => rowMatches(col, row, state, locale);
1026
+ }
1027
+
971
1028
  export function DataTable<T>({
972
1029
  rows,
973
1030
  columns: columnsProp,
@@ -1108,13 +1165,15 @@ export function DataTable<T>({
1108
1165
  // (a drag or "Auto-size columns" before it grew, KS N2) is ignored, and it has no
1109
1166
  // handle, so it can never pin it again. Ignored rather than deleted from storage, as
1110
1167
  // the widths above; the next resize or auto-size writes a blob without it.
1168
+ // Keyed on the `grow` column's key, not the columns array: an inline `columns={…}`
1169
+ // gave every render new widths, and the fit measured the table for it (DSP-19).
1170
+ const growKey = columns.find((c) => c.grow)?.key;
1111
1171
  const widths = useMemo(() => {
1112
1172
  if (!resizable) return {};
1113
- const grow = columns.find((c) => c.grow)?.key;
1114
- if (!grow || !(grow in storedWidths)) return storedWidths;
1115
- const { [grow]: _ignored, ...rest } = storedWidths;
1173
+ if (!growKey || !(growKey in storedWidths)) return storedWidths;
1174
+ const { [growKey]: _ignored, ...rest } = storedWidths;
1116
1175
  return rest;
1117
- }, [resizable, storedWidths, columns]);
1176
+ }, [resizable, storedWidths, growKey]);
1118
1177
  const hiddenCols = useMemo(
1119
1178
  () => (columnSettings ? storedHiddenCols : new Set<string>()),
1120
1179
  [columnSettings, storedHiddenCols],
@@ -1159,13 +1218,13 @@ export function DataTable<T>({
1159
1218
  if (v && !seen.has(v)) seen.add(v);
1160
1219
  }
1161
1220
  map[col.key] = Array.from(seen)
1162
- .sort()
1221
+ .sort((a, b) => compareSortValues(a, b, locale))
1163
1222
  .map((v) => ({ value: v, label: v }));
1164
1223
  }
1165
1224
  return map;
1166
1225
  // `columns` by signature — see the note above the signatures.
1167
1226
  // eslint-disable-next-line react-hooks/exhaustive-deps
1168
- }, [columnSig, selectOptionsSig, rows]);
1227
+ }, [columnSig, selectOptionsSig, rows, locale]);
1169
1228
 
1170
1229
  const filtered = useMemo(() => {
1171
1230
  if (serverRows) return rows;
@@ -1173,7 +1232,8 @@ export function DataTable<T>({
1173
1232
  for (const col of columns) {
1174
1233
  const state = filters[col.key];
1175
1234
  if (!state || !isFilterActive(state)) continue;
1176
- result = result.filter((row) => rowMatches(col, row, state, locale));
1235
+ // One matcher per filter, its query folded once (0.52 code review, data-table-filters.ts).
1236
+ result = result.filter(rowMatcher(col, state, locale));
1177
1237
  }
1178
1238
  return result;
1179
1239
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1198,14 +1258,16 @@ export function DataTable<T>({
1198
1258
  if (av == null && bv == null) continue;
1199
1259
  if (av == null) return 1;
1200
1260
  if (bv == null) return -1;
1201
- if (av < bv) return dir === "asc" ? -1 : 1;
1202
- if (av > bv) return dir === "asc" ? 1 : -1;
1261
+ // The order `compareSortValues` exports (0.52): one rule, here and in an app's
1262
+ // own list beside the table. Nulls are last above, in either direction.
1263
+ const order = compareSortValues(av, bv, locale);
1264
+ if (order !== 0) return dir === "asc" ? order : -order;
1203
1265
  }
1204
1266
  return 0;
1205
1267
  });
1206
1268
  return copy;
1207
1269
  // eslint-disable-next-line react-hooks/exhaustive-deps
1208
- }, [filtered, sorts, columnSig, serverRows]);
1270
+ }, [filtered, sorts, columnSig, serverRows, locale]);
1209
1271
 
1210
1272
  // `paginated={false}` is expressed as "page size = everything" rather than as a
1211
1273
  // second code path, so slicing, the page clamp and the range summary all keep
@@ -1224,10 +1286,16 @@ export function DataTable<T>({
1224
1286
  const safePage = isServer
1225
1287
  ? Math.min(Math.max(0, serverPagination!.page), totalPages - 1)
1226
1288
  : Math.min(page, totalPages - 1);
1227
- const slice =
1228
- isServer || unpaged || pageSize === Infinity
1229
- ? sorted
1230
- : sorted.slice(safePage * effectivePageSize, safePage * effectivePageSize + effectivePageSize);
1289
+ // Memoised (refactor audit 2026-10-30, DSP-19): the fit, the rows' window and the
1290
+ // range selection compare the page's rows by identity, and a fresh `slice(…)` on every
1291
+ // render of a paginated table — the default — had the fit lay the whole table out on a
1292
+ // ticked box, a keystroke, any parent render.
1293
+ const wholeList = isServer || unpaged || pageSize === Infinity;
1294
+ const slice = useMemo(
1295
+ () =>
1296
+ wholeList ? sorted : sorted.slice(safePage * effectivePageSize, safePage * effectivePageSize + effectivePageSize),
1297
+ [wholeList, sorted, safePage, effectivePageSize],
1298
+ );
1231
1299
 
1232
1300
  const toggleSort = (key: string, shiftKey: boolean) => {
1233
1301
  const col = columns.find((c) => c.key === key);
@@ -1320,6 +1388,16 @@ export function DataTable<T>({
1320
1388
  // Seeded with the mount value: a live region that speaks on first paint talks over
1321
1389
  // the page the user has just opened, and every table on that page does it at once.
1322
1390
  const announcedFilterKey = useRef(filterKey);
1391
+ // Spoken once the typing pauses (refactor audit 2026-10-30, DSP-23 d): every keystroke
1392
+ // in a text filter is a new filter, and "12 of 137 rows" on each one — through the live
1393
+ // region's 50 ms reset — talked over the very letters being typed. The count is read
1394
+ // when the sentence goes out, so it is the rows the pause left on screen.
1395
+ const filterSpeech = useRef({ shown: filtered.length, total: rows.length, labels });
1396
+ useLayoutEffect(() => {
1397
+ filterSpeech.current = { shown: filtered.length, total: rows.length, labels };
1398
+ });
1399
+ const filterTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
1400
+ useEffect(() => () => clearTimeout(filterTimer.current), []);
1323
1401
  useEffect(() => {
1324
1402
  if (announcedFilterKey.current === filterKey) return;
1325
1403
  announcedFilterKey.current = filterKey;
@@ -1328,8 +1406,12 @@ export function DataTable<T>({
1328
1406
  // filtered total — so the "n of m" sentence has no second number to give here.
1329
1407
  // Saying nothing is better than announcing the page size as a result count.
1330
1408
  if (serverRows) return;
1331
- announce(labels.filterResults(filtered.length, rows.length));
1332
- }, [filterKey, filtered.length, rows.length, serverRows, announce, labels]);
1409
+ clearTimeout(filterTimer.current);
1410
+ filterTimer.current = setTimeout(() => {
1411
+ const { shown, total, labels: words } = filterSpeech.current;
1412
+ announce(words.filterResults(shown, total));
1413
+ }, FILTER_ANNOUNCE_DELAY_MS);
1414
+ }, [filterKey, serverRows, announce]);
1333
1415
 
1334
1416
  // 1-based, because that is what the page strip shows and what a person says.
1335
1417
  const goToPage = (p: number) => {
@@ -1348,8 +1430,11 @@ export function DataTable<T>({
1348
1430
  headRefs,
1349
1431
  scroller: () => desktopScroller.current,
1350
1432
  enabled: !usePhoneLayout(),
1351
- // Measured only when one of these changed (0.48.2): not on a ticked box.
1352
- content: [slice, columns, hiddenCols, widths, density, large],
1433
+ // Measured only when one of these changed (0.48.2): not on a ticked box. The columns
1434
+ // by their keys (DSP-19): an inline `columns={…}` is a new array every render. The
1435
+ // locale (0.52 code review, data-table.tsx): the cells' dates, numbers and the kit's
1436
+ // words follow it under the same rows and keys; the fit adds the headers' drawn text.
1437
+ content: [slice, columnSig, hiddenCols, widths, density, large, locale],
1353
1438
  });
1354
1439
  const visibleColumns = useMemo(
1355
1440
  () => columns.filter((c) => !hiddenCols.has(c.key) && !autoHidden.has(c.key)),
@@ -1404,7 +1489,10 @@ export function DataTable<T>({
1404
1489
  const footerLabelCol = showFooter
1405
1490
  ? (visibleColumns.find((c) => !c.footer && !isTableOwnColumn(c.key)) ?? visibleColumns[0])
1406
1491
  : undefined;
1407
- const footerValue = (col: DataTableColumn<T>) => col.footer?.(sorted, slice);
1492
+ // `footer` keeps its `T[]` parameters: narrowed to `readonly`, a caller's footer typed
1493
+ // `(rows: Row[]) => …` would no longer fit (API-7 only widens). The table hands over the
1494
+ // arrays it holds, as before, and changes neither.
1495
+ const footerValue = (col: DataTableColumn<T>) => col.footer?.(sorted as T[], slice as T[]);
1408
1496
  const footerHeadingId = useId();
1409
1497
  // Each open row's detail row, for its disclosure button's `aria-controls`.
1410
1498
  const detailIdBase = useId();
@@ -1541,10 +1629,14 @@ export function DataTable<T>({
1541
1629
  if (el.parentElement) ro.observe(el.parentElement);
1542
1630
  return () => ro.disconnect();
1543
1631
  }, [phoneFill]);
1632
+ // A sticky `leadingRow`'s height on a phone (audit 2026-10-30 DSP-2): the section
1633
+ // headers stick under it, as the desktop's group bands stick under the desktop row.
1634
+ const [phoneLeadHeight, setPhoneLeadHeight] = useState(0);
1544
1635
 
1545
1636
  const { mobileSlice, canRevealMoreMobile, loadMoreRef } = useMobileReveal({
1546
- rows: sorted,
1547
- slice,
1637
+ // Read only there; its `T[]` widens to `readonly T[]` with its owner (API-7).
1638
+ rows: sorted as T[],
1639
+ slice: slice as T[],
1548
1640
  isServer,
1549
1641
  isMdUp,
1550
1642
  unpaged,
@@ -1594,12 +1686,18 @@ export function DataTable<T>({
1594
1686
  // the pager.
1595
1687
  const rowsFocusable = !!onRowClick;
1596
1688
  const [focusRowKey, setFocusRowKey] = useState<string | number | null>(null);
1689
+ // The rows' places by key (0.52 code review, data-table.tsx): the tab stop's check
1690
+ // below, the focus note and its recovery each walked the rows calling `rowKey` — on
1691
+ // every render, at each focus, in every commit while a row was noted: under
1692
+ // `virtualize`, 3000 rows, ~15000 calls per arrow step at the table's end. Built at the
1693
+ // first lookup, once per array, so a table nobody focuses builds none. Keyed on the
1694
+ // rows alone: `rowKey` is a pure function of its row, and a call site writes it inline.
1695
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1696
+ const sliceIndex = useMemo(() => keyIndex(slice, rowKey), [slice]);
1697
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1698
+ const mobileIndex = useMemo(() => keyIndex(mobileSlice, rowKey), [mobileSlice]);
1597
1699
  const tabRowKey =
1598
- focusRowKey !== null && slice.some((r) => rowKey(r) === focusRowKey)
1599
- ? focusRowKey
1600
- : slice.length
1601
- ? rowKey(slice[0])
1602
- : null;
1700
+ focusRowKey !== null && sliceIndex(focusRowKey) !== -1 ? focusRowKey : slice.length ? rowKey(slice[0]) : null;
1603
1701
 
1604
1702
  // What the memoised rows' handlers read at event time (0.48.2, K-052-2): the latest
1605
1703
  // props, refreshed every commit, so a row that bailed out of a render still toggles
@@ -1608,7 +1706,38 @@ export function DataTable<T>({
1608
1706
  // move over every row, rendered or not: the target is rendered, then focused.
1609
1707
  const virtualOn = !!virtualize && isMdUp && slice.length > 0;
1610
1708
  const focusRowRef = useRef<((index: number) => void) | undefined>(undefined);
1709
+ // ---- When the focused row leaves (refactor audit 2026-10-30, DSP-4) ----
1710
+ // The row holding the focus — its key, and where it stood — noted as the focus comes
1711
+ // into it (the rows report it, through React, so a menu or a dialog a row opened in a
1712
+ // portal is the row's too). A delete, a status change that filters the row out, an
1713
+ // approval: the row's DOM goes, the focus with it to <body>, and the commit that took it
1714
+ // puts the focus on the row now in its place (below).
1715
+ const heldRow = useRef<{ key: string | number; index: number } | null>(null);
1716
+ const noteRowFocus = (key: string | number) => {
1717
+ heldRow.current = { key, index: (isMdUp ? sliceIndex : mobileIndex)(key) };
1718
+ };
1719
+ // A gone row's note waiting for the overlay that holds the focus (below): watched as
1720
+ // a node until it leaves the page, since its close need not render the table.
1721
+ const overlayWatch = useRef<{ layer: Element; stop: () => void } | null>(null);
1722
+ const settleRef = useRef<() => void>(() => {});
1723
+ const watchOverlay = (layer: Element) => {
1724
+ if (overlayWatch.current?.layer === layer) return;
1725
+ overlayWatch.current?.stop();
1726
+ const observer = new MutationObserver(() => {
1727
+ if (layer.isConnected) return;
1728
+ stop();
1729
+ settleRef.current();
1730
+ });
1731
+ const stop = () => {
1732
+ observer.disconnect();
1733
+ if (overlayWatch.current?.layer === layer) overlayWatch.current = null;
1734
+ };
1735
+ observer.observe(layer.ownerDocument.body, { childList: true, subtree: true });
1736
+ overlayWatch.current = { layer, stop };
1737
+ };
1738
+ useEffect(() => () => overlayWatch.current?.stop(), []);
1611
1739
  const latestRowCtx: DataTableRowCtx<T> = {
1740
+ noteFocus: noteRowFocus,
1612
1741
  moveFocus: virtualOn
1613
1742
  ? (from, key) => {
1614
1743
  const target = rowNavTarget(from, key, slice.length);
@@ -1653,7 +1782,7 @@ export function DataTable<T>({
1653
1782
 
1654
1783
  // One mobile card (`MobileRow`, data-table-mobile.tsx). A function so the flat list
1655
1784
  // and the grouped list (below) share identical row markup.
1656
- const renderMobileRow = (row: T) => {
1785
+ const renderMobileRow = (row: T, index: number) => {
1657
1786
  const key = rowKey(row);
1658
1787
  const expanded = isExpanded?.(row) ?? false;
1659
1788
  return (
@@ -1661,6 +1790,7 @@ export function DataTable<T>({
1661
1790
  key={key}
1662
1791
  ctx={rowCtx}
1663
1792
  rowKey={key}
1793
+ rowIndex={index}
1664
1794
  row={row}
1665
1795
  expanded={expanded}
1666
1796
  expansion={expanded ? openedRowContent(row) : null}
@@ -1756,15 +1886,72 @@ export function DataTable<T>({
1756
1886
  focusRowRef.current = focusRowAt;
1757
1887
  }, [focusRowAt]);
1758
1888
 
1889
+ // The commit that took the focused row (DSP-4): if the focus fell with it — to <body>,
1890
+ // not into a dialog or a field the app chose — it goes to the row now at that index,
1891
+ // else the last row, else the table itself (`tabIndex=-1` while empty, named by
1892
+ // `labels.table`); the card on a phone. A focusable row (`onRowClick`) takes it itself,
1893
+ // any other its first control. The remaining count is said, as a filter's is: the
1894
+ // focus moved without the user moving it. translation-review's `keepFocusAt` is the
1895
+ // kit's earlier copy of the rule, for its groups.
1896
+ //
1897
+ // Every commit while a row is noted, a lookup by its key. A focus the user took
1898
+ // elsewhere drops the note (`onBlur` on the root, below), and since the 0.52 code review
1899
+ // so does one that went to nothing — a click on the page's background: kept, it was the
1900
+ // one case where a later removal (a refetch, a sync) pulled the focus back in.
1901
+ const settleFocus = () => {
1902
+ const held = heldRow.current;
1903
+ if (!held) return;
1904
+ const now = (isMdUp ? sliceIndex : mobileIndex)(held.key);
1905
+ if (now !== -1) {
1906
+ held.index = now;
1907
+ return;
1908
+ }
1909
+ const list = isMdUp ? tableRef.current : phoneListRef.current;
1910
+ // In an overlay — a confirm, an edit drawer — the focus is not lost yet: the overlay
1911
+ // hands it back to its opener as it closes, and the opener was in the row (0.52 code
1912
+ // review, data-table.tsx: an optimistic delete with its confirm still open dropped the
1913
+ // note, and the confirm's close dropped the focus to <body>). The note waits for the
1914
+ // overlay to leave the page, watched as a node: the table need not render when it does
1915
+ // (`useConfirm`'s provider, a Modal's exit). Not an overlay the table itself is in.
1916
+ const layer = focusIsLost() ? null : document.activeElement?.closest(OVERLAY_SELECTOR);
1917
+ if (layer && !(list && layer.contains(list))) {
1918
+ watchOverlay(layer);
1919
+ return;
1920
+ }
1921
+ heldRow.current = null;
1922
+ overlayWatch.current?.stop();
1923
+ if (!list || !focusIsLost()) return;
1924
+ const shown = isMdUp ? slice : mobileSlice;
1925
+ const at = shown.length === 0 ? -1 : Math.min(Math.max(held.index, 0), shown.length - 1);
1926
+ if (at === -1) list.focus();
1927
+ else if (isMdUp && virtualOn && rowsFocusable) focusRowRef.current?.(at);
1928
+ else {
1929
+ const row = list.querySelector<HTMLElement>(
1930
+ isMdUp ? `:scope > tbody > tr[data-row-index="${at}"]` : `:scope > li[data-row-index="${at}"]`,
1931
+ );
1932
+ // Each of the row's stops in turn, then the table (0.52 code review): `focus()` on
1933
+ // one that cannot hold it — `display: none`, in a closed <details>, a hidden input —
1934
+ // does nothing, and the focus stayed on <body>.
1935
+ const stops = !row ? [] : isMdUp && rowsFocusable ? [row] : tabStops(row, { includeSelf: false });
1936
+ if (!focusFirst(stops)) focusContainer(list);
1937
+ }
1938
+ announce(labels.filterResults(paginationTotal, isServer ? paginationTotal : rows.length));
1939
+ };
1940
+ useLayoutEffect(() => {
1941
+ settleRef.current = settleFocus;
1942
+ settleFocus();
1943
+ });
1944
+
1759
1945
  // `mobileGroupBy` may be a desktop `groupBy` level (0.48), its label and end slot too.
1760
1946
  const mobileLevel = typeof mobileGroupBy === "function" ? null : (mobileGroupBy ?? null);
1761
1947
  const mobileKey = typeof mobileGroupBy === "function" ? mobileGroupBy : mobileGroupBy?.key;
1762
- const mobileGroups: { key: string; rows: T[] }[] | null = mobileKey
1763
- ? mobileSlice.reduce<{ key: string; rows: T[] }[]>((acc, row) => {
1948
+ // `start`: the section's first card's place in the list (its `data-row-index`, DSP-4).
1949
+ const mobileGroups: { key: string; rows: T[]; start: number }[] | null = mobileKey
1950
+ ? mobileSlice.reduce<{ key: string; rows: T[]; start: number }[]>((acc, row, i) => {
1764
1951
  const key = mobileKey(row);
1765
1952
  const last = acc[acc.length - 1];
1766
1953
  if (last && last.key === key) last.rows.push(row);
1767
- else acc.push({ key, rows: [row] });
1954
+ else acc.push({ key, rows: [row], start: i });
1768
1955
  return acc;
1769
1956
  }, [])
1770
1957
  : null;
@@ -1788,6 +1975,24 @@ export function DataTable<T>({
1788
1975
  // `<main>` and every `FillHeight` between it and this table key off it with
1789
1976
  // `has-[[data-fill-height]]`, so a page asks for the fill by passing the prop.
1790
1977
  data-fill-height={fillHeight ? "" : undefined}
1978
+ // The focused row's note (DSP-4): cleared on the way down to whatever takes the
1979
+ // focus, and set again on the way up by the row that holds it. Focus leaving for
1980
+ // something real outside the table drops it — unless that is an overlay (a confirm,
1981
+ // a menu), which hands the focus back, or closes with the row it asked about.
1982
+ onFocusCapture={() => {
1983
+ heldRow.current = null;
1984
+ overlayWatch.current?.stop();
1985
+ }}
1986
+ onBlur={(e) => {
1987
+ const to = e.relatedTarget;
1988
+ if (to instanceof Element && !to.closest(OVERLAY_SELECTOR)) heldRow.current = null;
1989
+ // Focus that left for nothing — a click on the page (0.52 code review): no
1990
+ // element to say where, and a later removal of the row is no longer the user's.
1991
+ const held = heldRow.current;
1992
+ whenFocusLeftForNothing(e, () => {
1993
+ if (heldRow.current === held) heldRow.current = null;
1994
+ });
1995
+ }}
1791
1996
  className={cn(
1792
1997
  "group/table",
1793
1998
  frame ? "overflow-clip" : "min-w-0",
@@ -1879,6 +2084,10 @@ export function DataTable<T>({
1879
2084
  )}
1880
2085
  <ul
1881
2086
  ref={phoneListRef}
2087
+ // Named as the table is, and focusable while empty: where the focus goes when
2088
+ // the last card leaves (DSP-4).
2089
+ aria-label={labels.table}
2090
+ tabIndex={mobileSlice.length === 0 ? -1 : undefined}
1882
2091
  className={cn(
1883
2092
  "divide-y divide-subtle",
1884
2093
  // Under `fillHeight` the list takes the room its parent gives it, and in a
@@ -1894,10 +2103,20 @@ export function DataTable<T>({
1894
2103
  )}
1895
2104
  aria-busy={isLoading || undefined}
1896
2105
  >
2106
+ {/* The desktop's leading row, as the list's first item (0.51.7, audit
2107
+ 2026-10-30 DSP-2; MobileLeadingRow says what it is and is not). */}
2108
+ {leadingRow ? (
2109
+ <MobileLeadingRow sticky={leadingRowSticky} onHeight={setPhoneLeadHeight}>
2110
+ {leadingRow}
2111
+ </MobileLeadingRow>
2112
+ ) : null}
1897
2113
  {mobileGroups
1898
2114
  ? mobileGroups.map((g) => (
1899
2115
  <Fragment key={`hb-group:${g.key}`}>
1900
- <li className="sticky top-0 z-10 flex flex-wrap items-baseline justify-between gap-x-3 bg-surface-2 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted backdrop-blur">
2116
+ <li
2117
+ className="sticky top-0 z-10 flex flex-wrap items-baseline justify-between gap-x-3 bg-surface-2 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted backdrop-blur"
2118
+ style={leadingRow && leadingRowSticky ? { top: phoneLeadHeight } : undefined}
2119
+ >
1901
2120
  <span className="min-w-0">
1902
2121
  {mobileGroupLabel
1903
2122
  ? mobileGroupLabel(g.key)
@@ -1909,7 +2128,7 @@ export function DataTable<T>({
1909
2128
  <span className="ms-auto tabular-nums">{mobileLevel.end(g.key, g.rows)}</span>
1910
2129
  )}
1911
2130
  </li>
1912
- {g.rows.map(renderMobileRow)}
2131
+ {g.rows.map((r, i) => renderMobileRow(r, g.start + i))}
1913
2132
  </Fragment>
1914
2133
  ))
1915
2134
  : mobileSlice.map(renderMobileRow)}
@@ -1992,6 +2211,11 @@ export function DataTable<T>({
1992
2211
  behind it shows, so the panel names the row it opened from. */}
1993
2212
  <FullBleedDialog
1994
2213
  open={dialogOpen}
2214
+ // The open row's editor is the row's focus too: a Delete in it takes the row,
2215
+ // and the dialog with it (DSP-4).
2216
+ onFocus={() => {
2217
+ if (mobileDialogRow) noteRowFocus(rowKey(mobileDialogRow));
2218
+ }}
1995
2219
  onClose={closeDialog}
1996
2220
  closeLabel={labels.close}
1997
2221
  header={mobileDialogRow ? mobilePrimaryCol?.cell(mobileDialogRow) : null}
@@ -2036,6 +2260,8 @@ export function DataTable<T>({
2036
2260
  className={cn("w-full", compact ? "text-xs" : "text-sm")}
2037
2261
  data-fit-grow={growDrawn ? "" : undefined}
2038
2262
  aria-label={labels.table}
2263
+ // Focusable while empty: where the focus goes when the last row leaves (DSP-4).
2264
+ tabIndex={slice.length === 0 ? -1 : undefined}
2039
2265
  aria-busy={isLoading || undefined}
2040
2266
  // `virtualize` (0.48.2): every row counted, rendered or not.
2041
2267
  aria-rowcount={rowWindow?.rowCount}