@eifi1/ui-kit 0.51.7 → 0.53.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 (775) hide show
  1. package/README.md +178 -67
  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 +1 -3
  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.js +2 -1
  39. package/dist/auth/complete-name-dialog.js.map +1 -1
  40. package/dist/auth/forgot-password-form-labels.js +1 -1
  41. package/dist/auth/forgot-password-form-labels.js.map +1 -1
  42. package/dist/auth/forgot-password-form.js +7 -2
  43. package/dist/auth/forgot-password-form.js.map +1 -1
  44. package/dist/auth/register-form-labels.js +1 -1
  45. package/dist/auth/register-form-labels.js.map +1 -1
  46. package/dist/auth/reset-password-form-labels.js +1 -1
  47. package/dist/auth/reset-password-form-labels.js.map +1 -1
  48. package/dist/auth/reset-password-form.js +5 -1
  49. package/dist/auth/reset-password-form.js.map +1 -1
  50. package/dist/auth/sign-in-form-labels.js +1 -1
  51. package/dist/auth/sign-in-form-labels.js.map +1 -1
  52. package/dist/auth/status-parts.d.ts +0 -3
  53. package/dist/auth/status-parts.js +0 -4
  54. package/dist/auth/status-parts.js.map +1 -1
  55. package/dist/auth/verify-email-labels.js +1 -1
  56. package/dist/auth/verify-email-labels.js.map +1 -1
  57. package/dist/auth/verify-email.js +7 -2
  58. package/dist/auth/verify-email.js.map +1 -1
  59. package/dist/billing/cancel-subscription.d.ts +10 -7
  60. package/dist/billing/cancel-subscription.js +6 -6
  61. package/dist/billing/cancel-subscription.js.map +1 -1
  62. package/dist/billing/plan-card.d.ts +5 -3
  63. package/dist/billing/plan-card.js +7 -8
  64. package/dist/billing/plan-card.js.map +1 -1
  65. package/dist/billing/plan-change-labels.d.ts +42 -0
  66. package/dist/billing/plan-change-labels.js +22 -0
  67. package/dist/billing/plan-change-labels.js.map +1 -0
  68. package/dist/billing/plan-switch.d.ts +9 -6
  69. package/dist/billing/plan-switch.js +7 -5
  70. package/dist/billing/plan-switch.js.map +1 -1
  71. package/dist/chart.d.ts +4 -3
  72. package/dist/chart.js +72 -4
  73. package/dist/chart.js.map +1 -1
  74. package/dist/components/account-chips.d.ts +5 -5
  75. package/dist/components/account-chips.js +11 -13
  76. package/dist/components/account-chips.js.map +1 -1
  77. package/dist/components/alert-banner.d.ts +16 -5
  78. package/dist/components/alert-banner.js +46 -1
  79. package/dist/components/alert-banner.js.map +1 -1
  80. package/dist/components/amount-input.d.ts +13 -0
  81. package/dist/components/amount-input.js +1 -0
  82. package/dist/components/amount-input.js.map +1 -1
  83. package/dist/components/autocomplete.js +57 -65
  84. package/dist/components/autocomplete.js.map +1 -1
  85. package/dist/components/bulk-action-bar.d.ts +12 -2
  86. package/dist/components/bulk-action-bar.js +65 -21
  87. package/dist/components/bulk-action-bar.js.map +1 -1
  88. package/dist/components/button-look.d.ts +5 -5
  89. package/dist/components/button-look.js.map +1 -1
  90. package/dist/components/button.d.ts +2 -2
  91. package/dist/components/button.js.map +1 -1
  92. package/dist/components/chart-edge.d.ts +16 -0
  93. package/dist/components/chart-edge.js +14 -1
  94. package/dist/components/chart-edge.js.map +1 -1
  95. package/dist/components/chart-figure.d.ts +13 -0
  96. package/dist/components/chart-figure.js +15 -0
  97. package/dist/components/chart-figure.js.map +1 -0
  98. package/dist/components/chart-zoom-core.js +1 -4
  99. package/dist/components/chart-zoom-core.js.map +1 -1
  100. package/dist/components/chart.d.ts +8 -1
  101. package/dist/components/chart.js +19 -10
  102. package/dist/components/chart.js.map +1 -1
  103. package/dist/components/combobox-core.d.ts +111 -2
  104. package/dist/components/combobox-core.js +148 -42
  105. package/dist/components/combobox-core.js.map +1 -1
  106. package/dist/components/combobox.d.ts +1 -1
  107. package/dist/components/combobox.js +141 -130
  108. package/dist/components/combobox.js.map +1 -1
  109. package/dist/components/copy-button.d.ts +6 -5
  110. package/dist/components/copy-button.js +5 -3
  111. package/dist/components/copy-button.js.map +1 -1
  112. package/dist/components/country-select.js +2 -2
  113. package/dist/components/country-select.js.map +1 -1
  114. package/dist/components/data-table-column-settings.d.ts +1 -1
  115. package/dist/components/data-table-column-settings.js +33 -7
  116. package/dist/components/data-table-column-settings.js.map +1 -1
  117. package/dist/components/data-table-filters.d.ts +4 -2
  118. package/dist/components/data-table-filters.js +2 -2
  119. package/dist/components/data-table-filters.js.map +1 -1
  120. package/dist/components/data-table-fit.d.ts +6 -4
  121. package/dist/components/data-table-fit.js +4 -1
  122. package/dist/components/data-table-fit.js.map +1 -1
  123. package/dist/components/data-table-groups.d.ts +1 -1
  124. package/dist/components/data-table-groups.js.map +1 -1
  125. package/dist/components/data-table-head.d.ts +1 -1
  126. package/dist/components/data-table-head.js +15 -12
  127. package/dist/components/data-table-head.js.map +1 -1
  128. package/dist/components/data-table-mobile.d.ts +12 -7
  129. package/dist/components/data-table-mobile.js +43 -30
  130. package/dist/components/data-table-mobile.js.map +1 -1
  131. package/dist/components/data-table-pagination.js +11 -6
  132. package/dist/components/data-table-pagination.js.map +1 -1
  133. package/dist/components/data-table-resize.d.ts +1 -1
  134. package/dist/components/data-table-resize.js.map +1 -1
  135. package/dist/components/data-table-row-actions.d.ts +2 -2
  136. package/dist/components/data-table-row-actions.js.map +1 -1
  137. package/dist/components/data-table-row.d.ts +6 -2
  138. package/dist/components/data-table-row.js +17 -10
  139. package/dist/components/data-table-row.js.map +1 -1
  140. package/dist/components/data-table-selection.d.ts +1 -1
  141. package/dist/components/data-table-selection.js.map +1 -1
  142. package/dist/components/data-table-shared.d.ts +10 -2
  143. package/dist/components/data-table-shared.js +18 -0
  144. package/dist/components/data-table-shared.js.map +1 -1
  145. package/dist/components/data-table-sort.d.ts +21 -2
  146. package/dist/components/data-table-sort.js +24 -0
  147. package/dist/components/data-table-sort.js.map +1 -1
  148. package/dist/components/data-table-virtual.d.ts +1 -1
  149. package/dist/components/data-table-virtual.js +18 -6
  150. package/dist/components/data-table-virtual.js.map +1 -1
  151. package/dist/components/data-table.d.ts +13 -4
  152. package/dist/components/data-table.js +139 -36
  153. package/dist/components/data-table.js.map +1 -1
  154. package/dist/components/date-field.d.ts +25 -3
  155. package/dist/components/date-field.js +33 -8
  156. package/dist/components/date-field.js.map +1 -1
  157. package/dist/components/date-picker.d.ts +16 -3
  158. package/dist/components/date-picker.js +55 -26
  159. package/dist/components/date-picker.js.map +1 -1
  160. package/dist/components/date-range-picker.d.ts +38 -24
  161. package/dist/components/date-range-picker.js +23 -7
  162. package/dist/components/date-range-picker.js.map +1 -1
  163. package/dist/components/error-boundary.js +37 -30
  164. package/dist/components/error-boundary.js.map +1 -1
  165. package/dist/components/{ui-labels.d.ts → field-base-labels.d.ts} +0 -2
  166. package/dist/components/{ui-labels.js → field-base-labels.js} +2 -9
  167. package/dist/components/field-base-labels.js.map +1 -0
  168. package/dist/components/field-base.d.ts +4 -3
  169. package/dist/components/field-base.js +3 -3
  170. package/dist/components/field-base.js.map +1 -1
  171. package/dist/components/form-actions.js +11 -5
  172. package/dist/components/form-actions.js.map +1 -1
  173. package/dist/components/hover-menu.d.ts +3 -0
  174. package/dist/components/hover-menu.js +5 -3
  175. package/dist/components/hover-menu.js.map +1 -1
  176. package/dist/components/icon-button.js +14 -9
  177. package/dist/components/icon-button.js.map +1 -1
  178. package/dist/components/inline-confirm.d.ts +43 -0
  179. package/dist/components/inline-confirm.js +67 -0
  180. package/dist/components/inline-confirm.js.map +1 -0
  181. package/dist/components/inline-entity-combobox.d.ts +4 -3
  182. package/dist/components/inline-entity-combobox.js +148 -140
  183. package/dist/components/inline-entity-combobox.js.map +1 -1
  184. package/dist/components/input.js +1 -1
  185. package/dist/components/input.js.map +1 -1
  186. package/dist/components/jump-calendar.js +28 -112
  187. package/dist/components/jump-calendar.js.map +1 -1
  188. package/dist/components/legal-page.d.ts +3 -1
  189. package/dist/components/legal-page.js +3 -2
  190. package/dist/components/legal-page.js.map +1 -1
  191. package/dist/components/legal.d.ts +4 -2
  192. package/dist/components/legal.js.map +1 -1
  193. package/dist/components/lightbox.d.ts +2 -2
  194. package/dist/components/lightbox.js +17 -6
  195. package/dist/components/lightbox.js.map +1 -1
  196. package/dist/components/list.d.ts +6 -2
  197. package/dist/components/list.js +3 -2
  198. package/dist/components/list.js.map +1 -1
  199. package/dist/components/measured-grid.d.ts +1 -1
  200. package/dist/components/measured-grid.js +2 -1
  201. package/dist/components/measured-grid.js.map +1 -1
  202. package/dist/components/mini-calendar.js +3 -5
  203. package/dist/components/mini-calendar.js.map +1 -1
  204. package/dist/components/modal.js +3 -1
  205. package/dist/components/modal.js.map +1 -1
  206. package/dist/components/month-grid.d.ts +55 -0
  207. package/dist/components/month-grid.js +148 -0
  208. package/dist/components/month-grid.js.map +1 -0
  209. package/dist/components/month-picker.d.ts +36 -4
  210. package/dist/components/month-picker.js +123 -146
  211. package/dist/components/month-picker.js.map +1 -1
  212. package/dist/components/multi-select.d.ts +2 -2
  213. package/dist/components/multi-select.js +11 -6
  214. package/dist/components/multi-select.js.map +1 -1
  215. package/dist/components/nav-pills.d.ts +1 -1
  216. package/dist/components/nav-pills.js.map +1 -1
  217. package/dist/components/picker-sheet.js +2 -1
  218. package/dist/components/picker-sheet.js.map +1 -1
  219. package/dist/components/pie-chart-labels.d.ts +7 -0
  220. package/dist/components/pie-chart-labels.js +1 -0
  221. package/dist/components/pie-chart-labels.js.map +1 -1
  222. package/dist/components/pie-chart.d.ts +5 -3
  223. package/dist/components/pie-chart.js +7 -22
  224. package/dist/components/pie-chart.js.map +1 -1
  225. package/dist/components/popover.d.ts +3 -0
  226. package/dist/components/popover.js +7 -1
  227. package/dist/components/popover.js.map +1 -1
  228. package/dist/components/row-actions.js +2 -1
  229. package/dist/components/row-actions.js.map +1 -1
  230. package/dist/components/series-chart-axes.d.ts +4 -4
  231. package/dist/components/series-chart-axes.js.map +1 -1
  232. package/dist/components/series-chart-labels.d.ts +7 -4
  233. package/dist/components/series-chart-labels.js.map +1 -1
  234. package/dist/components/series-chart.d.ts +92 -23
  235. package/dist/components/series-chart.js +74 -30
  236. package/dist/components/series-chart.js.map +1 -1
  237. package/dist/components/share-card.js +3 -3
  238. package/dist/components/share-card.js.map +1 -1
  239. package/dist/components/tabs-labels.d.ts +2 -0
  240. package/dist/components/tabs-labels.js +11 -0
  241. package/dist/components/tabs-labels.js.map +1 -0
  242. package/dist/components/tabs.d.ts +1 -1
  243. package/dist/components/tabs.js +1 -1
  244. package/dist/components/tabs.js.map +1 -1
  245. package/dist/components/toggle-legend.d.ts +2 -2
  246. package/dist/components/toggle-legend.js +6 -6
  247. package/dist/components/toggle-legend.js.map +1 -1
  248. package/dist/components/translation-review-editor.d.ts +4 -2
  249. package/dist/components/translation-review-editor.js +2 -3
  250. package/dist/components/translation-review-editor.js.map +1 -1
  251. package/dist/components/translation-review.d.ts +2 -1
  252. package/dist/components/translation-review.js +2 -2
  253. package/dist/components/translation-review.js.map +1 -1
  254. package/dist/components/treemap-labels.d.ts +31 -0
  255. package/dist/components/treemap-labels.js +10 -0
  256. package/dist/components/treemap-labels.js.map +1 -0
  257. package/dist/components/treemap-layout.d.ts +62 -0
  258. package/dist/components/treemap-layout.js +126 -0
  259. package/dist/components/treemap-layout.js.map +1 -0
  260. package/dist/components/treemap.d.ts +167 -19
  261. package/dist/components/treemap.js +340 -100
  262. package/dist/components/treemap.js.map +1 -1
  263. package/dist/components/use-table-state.d.ts +5 -5
  264. package/dist/components/use-table-state.js +4 -1
  265. package/dist/components/use-table-state.js.map +1 -1
  266. package/dist/data-table.d.ts +1 -2
  267. package/dist/data-table.js +1 -4
  268. package/dist/data-table.js.map +1 -1
  269. package/dist/demo/demo-countdown.d.ts +0 -5
  270. package/dist/demo/demo-countdown.js +0 -4
  271. package/dist/demo/demo-countdown.js.map +1 -1
  272. package/dist/eslint/index.js +1 -1
  273. package/dist/eslint/role-utilities.d.ts +36 -7
  274. package/dist/eslint/role-utilities.js +42 -9
  275. package/dist/eslint/role-utilities.js.map +1 -1
  276. package/dist/feedback/feedback-dialog.d.ts +25 -16
  277. package/dist/feedback/feedback-dialog.js +6 -2
  278. package/dist/feedback/feedback-dialog.js.map +1 -1
  279. package/dist/feedback/feedback-mutation.d.ts +18 -0
  280. package/dist/feedback/feedback-mutation.js +8 -0
  281. package/dist/feedback/feedback-mutation.js.map +1 -0
  282. package/dist/feedback/feedback-page-link.d.ts +53 -0
  283. package/dist/feedback/feedback-page-link.js +37 -0
  284. package/dist/feedback/feedback-page-link.js.map +1 -0
  285. package/dist/feedback/feedback-public-list.d.ts +8 -4
  286. package/dist/feedback/feedback-public-list.js +2 -2
  287. package/dist/feedback/feedback-public-list.js.map +1 -1
  288. package/dist/feedback/feedback-replies.d.ts +3 -1
  289. package/dist/feedback/feedback-replies.js +5 -4
  290. package/dist/feedback/feedback-replies.js.map +1 -1
  291. package/dist/feedback/feedback-row-detail-labels.js +0 -3
  292. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  293. package/dist/feedback/feedback-row-detail.d.ts +33 -44
  294. package/dist/feedback/feedback-row-detail.js +28 -34
  295. package/dist/feedback/feedback-row-detail.js.map +1 -1
  296. package/dist/feedback/feedback-status-undo.d.ts +17 -14
  297. package/dist/feedback/feedback-status-undo.js +10 -15
  298. package/dist/feedback/feedback-status-undo.js.map +1 -1
  299. package/dist/feedback/feedback-submit-dialog.d.ts +1 -1
  300. package/dist/feedback/feedback-submit-dialog.js +1 -1
  301. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  302. package/dist/feedback/feedback-submit.js +9 -3
  303. package/dist/feedback/feedback-submit.js.map +1 -1
  304. package/dist/feedback/feedback-swipe.d.ts +1 -1
  305. package/dist/feedback/feedback-swipe.js.map +1 -1
  306. package/dist/feedback/feedback-table.d.ts +21 -9
  307. package/dist/feedback/feedback-table.js +45 -25
  308. package/dist/feedback/feedback-table.js.map +1 -1
  309. package/dist/feedback/feedback-thread-labels.d.ts +2 -2
  310. package/dist/feedback/feedback-thread-labels.js.map +1 -1
  311. package/dist/feedback/feedback-thread.d.ts +15 -23
  312. package/dist/feedback/feedback-thread.js +2 -1
  313. package/dist/feedback/feedback-thread.js.map +1 -1
  314. package/dist/feedback.d.ts +6 -6
  315. package/dist/feedback.js +90 -6
  316. package/dist/feedback.js.map +1 -1
  317. package/dist/hooks/use-focus-trap.d.ts +35 -0
  318. package/dist/hooks/use-focus-trap.js +6 -4
  319. package/dist/hooks/use-focus-trap.js.map +1 -1
  320. package/dist/hooks/use-hotkey.d.ts +5 -2
  321. package/dist/hooks/use-hotkey.js +5 -4
  322. package/dist/hooks/use-hotkey.js.map +1 -1
  323. package/dist/hooks/use-long-press.d.ts +7 -4
  324. package/dist/hooks/use-long-press.js +3 -0
  325. package/dist/hooks/use-long-press.js.map +1 -1
  326. package/dist/hooks/use-media-query.js +12 -4
  327. package/dist/hooks/use-media-query.js.map +1 -1
  328. package/dist/hooks/use-mounted.d.ts +22 -0
  329. package/dist/hooks/use-mounted.js +24 -0
  330. package/dist/hooks/use-mounted.js.map +1 -0
  331. package/dist/hooks/use-overlay-history.js +19 -3
  332. package/dist/hooks/use-overlay-history.js.map +1 -1
  333. package/dist/i18n/defaults.js +4 -9
  334. package/dist/i18n/defaults.js.map +1 -1
  335. package/dist/i18n/german.js +7 -18
  336. package/dist/i18n/german.js.map +1 -1
  337. package/dist/i18n/kit-labels.d.ts +9 -11
  338. package/dist/i18n/kit-labels.js.map +1 -1
  339. package/dist/i18n/locales/en.js +15 -64
  340. package/dist/i18n/locales/en.js.map +3 -3
  341. package/dist/i18n/locales/es.js +7 -18
  342. package/dist/i18n/locales/es.js.map +1 -1
  343. package/dist/i18n/locales/fr.js +20 -27
  344. package/dist/i18n/locales/fr.js.map +1 -1
  345. package/dist/i18n/locales/hu.js +9 -18
  346. package/dist/i18n/locales/hu.js.map +1 -1
  347. package/dist/i18n/locales/it.js +7 -19
  348. package/dist/i18n/locales/it.js.map +1 -1
  349. package/dist/i18n/locales/zh.js +8 -18
  350. package/dist/i18n/locales/zh.js.map +1 -1
  351. package/dist/i18n/review.js +12 -2
  352. package/dist/i18n/review.js.map +1 -1
  353. package/dist/i18n/shared-labels.js +0 -1
  354. package/dist/i18n/shared-labels.js.map +1 -1
  355. package/dist/index.d.ts +21 -23
  356. package/dist/index.js +50 -65
  357. package/dist/index.js.map +1 -1
  358. package/dist/landing/routing.d.ts +3 -1
  359. package/dist/landing/routing.js +4 -7
  360. package/dist/landing/routing.js.map +1 -1
  361. package/dist/lib/broadcast.d.ts +17 -0
  362. package/dist/lib/broadcast.js +30 -0
  363. package/dist/lib/broadcast.js.map +1 -0
  364. package/dist/lib/date-format.d.ts +37 -2
  365. package/dist/lib/date-format.js +34 -8
  366. package/dist/lib/date-format.js.map +1 -1
  367. package/dist/lib/day-format.d.ts +46 -0
  368. package/dist/lib/day-format.js +46 -0
  369. package/dist/lib/day-format.js.map +1 -0
  370. package/dist/lib/describe-failure.d.ts +14 -0
  371. package/dist/lib/describe-failure.js +9 -0
  372. package/dist/lib/describe-failure.js.map +1 -0
  373. package/dist/lib/direction.d.ts +16 -0
  374. package/dist/lib/direction.js +9 -1
  375. package/dist/lib/direction.js.map +1 -1
  376. package/dist/lib/focus-left.d.ts +63 -0
  377. package/dist/lib/focus-left.js +67 -0
  378. package/dist/lib/focus-left.js.map +1 -0
  379. package/dist/lib/format.js +5 -14
  380. package/dist/lib/format.js.map +1 -1
  381. package/dist/lib/http-status.d.ts +24 -0
  382. package/dist/lib/http-status.js +14 -0
  383. package/dist/lib/http-status.js.map +1 -0
  384. package/dist/lib/intl-cache.d.ts +14 -0
  385. package/dist/lib/intl-cache.js +15 -0
  386. package/dist/lib/intl-cache.js.map +1 -0
  387. package/dist/lib/iso-day.d.ts +11 -0
  388. package/dist/lib/iso-day.js +8 -0
  389. package/dist/lib/iso-day.js.map +1 -0
  390. package/dist/lib/lazy-with-fallback.d.ts +31 -0
  391. package/dist/lib/lazy-with-fallback.js +40 -0
  392. package/dist/lib/lazy-with-fallback.js.map +1 -0
  393. package/dist/lib/path-pattern.d.ts +34 -0
  394. package/dist/lib/path-pattern.js +24 -0
  395. package/dist/lib/path-pattern.js.map +1 -0
  396. package/dist/lib/reduced-motion.d.ts +2 -1
  397. package/dist/lib/reduced-motion.js.map +1 -1
  398. package/dist/lib/round.d.ts +2 -1
  399. package/dist/lib/round.js +2 -1
  400. package/dist/lib/round.js.map +1 -1
  401. package/dist/lib/safe-storage.d.ts +24 -5
  402. package/dist/lib/safe-storage.js +27 -2
  403. package/dist/lib/safe-storage.js.map +1 -1
  404. package/dist/lib/session-refresh.js +1 -1
  405. package/dist/lib/session-refresh.js.map +1 -1
  406. package/dist/lib/share-format.d.ts +13 -0
  407. package/dist/lib/share-format.js +10 -0
  408. package/dist/lib/share-format.js.map +1 -0
  409. package/dist/lib/text-case.d.ts +17 -0
  410. package/dist/lib/text-case.js +8 -0
  411. package/dist/lib/text-case.js.map +1 -0
  412. package/dist/lib/text-match.d.ts +29 -0
  413. package/dist/lib/text-match.js +20 -2
  414. package/dist/lib/text-match.js.map +1 -1
  415. package/dist/lib/thenable.d.ts +13 -0
  416. package/dist/lib/thenable.js +8 -0
  417. package/dist/lib/thenable.js.map +1 -0
  418. package/dist/lib/translation-review.d.ts +7 -2
  419. package/dist/lib/translation-review.js +4 -4
  420. package/dist/lib/translation-review.js.map +1 -1
  421. package/dist/notifications/device-zone-report.js +1 -1
  422. package/dist/notifications/device-zone-report.js.map +1 -1
  423. package/dist/notifications/notification-bell.d.ts +2 -1
  424. package/dist/notifications/notification-bell.js +3 -3
  425. package/dist/notifications/notification-bell.js.map +1 -1
  426. package/dist/notifications/notification-inbox.d.ts +10 -6
  427. package/dist/notifications/notification-inbox.js +26 -48
  428. package/dist/notifications/notification-inbox.js.map +1 -1
  429. package/dist/notifications/notification-parts.d.ts +3 -2
  430. package/dist/notifications/notification-parts.js +1 -3
  431. package/dist/notifications/notification-parts.js.map +1 -1
  432. package/dist/notifications/notification-types-setting.js +1 -1
  433. package/dist/notifications/notification-types-setting.js.map +1 -1
  434. package/dist/notifications/notifications-labels.d.ts +6 -0
  435. package/dist/notifications/notifications-labels.js +1 -0
  436. package/dist/notifications/notifications-labels.js.map +1 -1
  437. package/dist/notifications/push-device-setting.js +1 -1
  438. package/dist/notifications/push-device-setting.js.map +1 -1
  439. package/dist/notifications/push-devices-setting.d.ts +2 -1
  440. package/dist/notifications/push-devices-setting.js +27 -49
  441. package/dist/notifications/push-devices-setting.js.map +1 -1
  442. package/dist/notifications/quiet-hours-setting.d.ts +10 -3
  443. package/dist/notifications/quiet-hours-setting.js +65 -26
  444. package/dist/notifications/quiet-hours-setting.js.map +1 -1
  445. package/dist/notifications/unsubscribe-panel.js +4 -7
  446. package/dist/notifications/unsubscribe-panel.js.map +1 -1
  447. package/dist/notifications/use-push-device.d.ts +39 -1
  448. package/dist/notifications/use-push-device.js +28 -7
  449. package/dist/notifications/use-push-device.js.map +1 -1
  450. package/dist/offline/query-persistence.d.ts +3 -1
  451. package/dist/offline/query-persistence.js +19 -2
  452. package/dist/offline/query-persistence.js.map +1 -1
  453. package/dist/rhf/fields.d.ts +11 -4
  454. package/dist/rhf/fields.js.map +1 -1
  455. package/dist/search/command-palette.js +1 -1
  456. package/dist/search/command-palette.js.map +1 -1
  457. package/dist/search/global-search.js +19 -9
  458. package/dist/search/global-search.js.map +1 -1
  459. package/dist/search/search-index.d.ts +0 -6
  460. package/dist/search/search-index.js +0 -4
  461. package/dist/search/search-index.js.map +1 -1
  462. package/dist/search/use-command-key.d.ts +12 -1
  463. package/dist/search/use-command-key.js +3 -12
  464. package/dist/search/use-command-key.js.map +1 -1
  465. package/dist/search.d.ts +1 -1
  466. package/dist/search.js +6 -1
  467. package/dist/search.js.map +1 -1
  468. package/dist/settings/use-settings-focus.js +1 -0
  469. package/dist/settings/use-settings-focus.js.map +1 -1
  470. package/dist/shell/account-menu-language.d.ts +5 -3
  471. package/dist/shell/account-menu-language.js +2 -2
  472. package/dist/shell/account-menu-language.js.map +1 -1
  473. package/dist/shell/account-menu-text-size.d.ts +9 -6
  474. package/dist/shell/account-menu-text-size.js +2 -2
  475. package/dist/shell/account-menu-text-size.js.map +1 -1
  476. package/dist/shell/app-shell.d.ts +0 -10
  477. package/dist/shell/app-shell.js +1 -7
  478. package/dist/shell/app-shell.js.map +1 -1
  479. package/dist/shell/company-switcher.d.ts +1 -1
  480. package/dist/shell/company-switcher.js.map +1 -1
  481. package/dist/shell/dev-menu.d.ts +1 -1
  482. package/dist/shell/dev-menu.js +5 -18
  483. package/dist/shell/dev-menu.js.map +1 -1
  484. package/dist/shell/top-bar-actions.d.ts +1 -1
  485. package/dist/shell/top-bar-actions.js.map +1 -1
  486. package/dist/shell/top-bar-parts-labels.d.ts +1 -3
  487. package/dist/shell/top-bar-parts-labels.js +0 -1
  488. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  489. package/dist/shell.d.ts +7 -10
  490. package/dist/shell.js +14 -23
  491. package/dist/shell.js.map +1 -1
  492. package/dist/sync/engine.d.ts +30 -4
  493. package/dist/sync/engine.js +172 -52
  494. package/dist/sync/engine.js.map +1 -1
  495. package/dist/sync.d.ts +2 -2
  496. package/dist/sync.js +2 -10
  497. package/dist/sync.js.map +1 -1
  498. package/dist/testing/css-variables.js +3 -8
  499. package/dist/testing/css-variables.js.map +1 -1
  500. package/dist/theme/chart-palette.d.ts +0 -5
  501. package/dist/theme/chart-palette.js +0 -2
  502. package/dist/theme/chart-palette.js.map +1 -1
  503. package/dist/theme/contrast.d.ts +2 -1
  504. package/dist/theme/contrast.js +3 -8
  505. package/dist/theme/contrast.js.map +1 -1
  506. package/dist/theme/palette-store.js +6 -6
  507. package/dist/theme/palette-store.js.map +1 -1
  508. package/dist/theme/text-size.js +3 -8
  509. package/dist/theme/text-size.js.map +1 -1
  510. package/dist/theme/theme-store.js +3 -6
  511. package/dist/theme/theme-store.js.map +1 -1
  512. package/dist/tour/tour-catalogue.d.ts +7 -4
  513. package/dist/tour/tour-catalogue.js +12 -10
  514. package/dist/tour/tour-catalogue.js.map +1 -1
  515. package/dist/tour/tour-dock.d.ts +0 -2
  516. package/dist/tour/tour-dock.js +0 -2
  517. package/dist/tour/tour-dock.js.map +1 -1
  518. package/dist/tour/tour-gates.d.ts +4 -0
  519. package/dist/tour/tour-gates.js +14 -0
  520. package/dist/tour/tour-gates.js.map +1 -1
  521. package/dist/tour/tour-overlay.d.ts +27 -0
  522. package/dist/tour/tour-overlay.js +741 -0
  523. package/dist/tour/tour-overlay.js.map +1 -0
  524. package/dist/tour/tour.d.ts +13 -3
  525. package/dist/tour/tour.js +59 -781
  526. package/dist/tour/tour.js.map +1 -1
  527. package/dist/tour/use-tour-progress.js +1 -1
  528. package/dist/tour/use-tour-progress.js.map +1 -1
  529. package/dist/wizard/stepper-nav.d.ts +5 -1
  530. package/dist/wizard/stepper-nav.js.map +1 -1
  531. package/dist/wizard/types.d.ts +6 -2
  532. package/dist/wizard/types.js.map +1 -1
  533. package/dist/wizard/use-wizard.d.ts +3 -1
  534. package/dist/wizard/use-wizard.js.map +1 -1
  535. package/dist/wizard/validation.d.ts +3 -1
  536. package/dist/wizard/validation.js.map +1 -1
  537. package/package.json +10 -6
  538. package/src/account/account-parts.ts +5 -25
  539. package/src/account/data-export-setting-labels.ts +1 -1
  540. package/src/account/delete-account-setting-labels.ts +1 -1
  541. package/src/account/email-change-setting-labels.ts +1 -1
  542. package/src/account/passkeys-setting.tsx +60 -38
  543. package/src/account/sessions-setting.tsx +18 -12
  544. package/src/admin/admin-action-confirm.tsx +1 -5
  545. package/src/admin/admin-parts.ts +11 -25
  546. package/src/admin/mail-test-card-labels.ts +1 -1
  547. package/src/admin/plan-change-labels.ts +5 -23
  548. package/src/admin/plan-change.tsx +7 -44
  549. package/src/admin/reviewer-scope-editor.tsx +3 -3
  550. package/src/auth/auth-errors-labels.ts +23 -0
  551. package/src/auth/auth-errors.ts +11 -38
  552. package/src/auth/complete-name-dialog.tsx +4 -1
  553. package/src/auth/forgot-password-form-labels.ts +1 -1
  554. package/src/auth/forgot-password-form.tsx +11 -6
  555. package/src/auth/register-form-labels.ts +1 -1
  556. package/src/auth/reset-password-form-labels.ts +1 -1
  557. package/src/auth/reset-password-form.tsx +8 -4
  558. package/src/auth/sign-in-form-labels.ts +1 -1
  559. package/src/auth/status-parts.tsx +0 -6
  560. package/src/auth/verify-email-labels.ts +1 -1
  561. package/src/auth/verify-email.tsx +11 -6
  562. package/src/billing/cancel-subscription.tsx +15 -12
  563. package/src/billing/plan-card.tsx +18 -10
  564. package/src/billing/plan-change-labels.ts +66 -0
  565. package/src/billing/plan-switch.tsx +15 -12
  566. package/src/chart.ts +73 -6
  567. package/src/components/account-chips.tsx +20 -23
  568. package/src/components/alert-banner.tsx +82 -5
  569. package/src/components/amount-input.tsx +18 -7
  570. package/src/components/autocomplete.tsx +64 -70
  571. package/src/components/bulk-action-bar.tsx +70 -2
  572. package/src/components/button-look.ts +5 -5
  573. package/src/components/button.tsx +2 -2
  574. package/src/components/chart-edge.ts +34 -1
  575. package/src/components/chart-figure.tsx +35 -0
  576. package/src/components/chart-zoom-core.tsx +6 -5
  577. package/src/components/chart.tsx +26 -5
  578. package/src/components/combobox-core.tsx +293 -62
  579. package/src/components/combobox.tsx +183 -153
  580. package/src/components/copy-button.tsx +34 -23
  581. package/src/components/country-select.tsx +16 -11
  582. package/src/components/data-table-column-settings.tsx +52 -10
  583. package/src/components/data-table-filters.ts +6 -4
  584. package/src/components/data-table-fit.ts +19 -5
  585. package/src/components/data-table-groups.tsx +1 -1
  586. package/src/components/data-table-head.tsx +32 -22
  587. package/src/components/data-table-mobile.tsx +61 -26
  588. package/src/components/data-table-pagination.tsx +21 -6
  589. package/src/components/data-table-resize.ts +1 -1
  590. package/src/components/data-table-row-actions.tsx +3 -3
  591. package/src/components/data-table-row.tsx +25 -14
  592. package/src/components/data-table-selection.ts +1 -1
  593. package/src/components/data-table-shared.tsx +33 -1
  594. package/src/components/data-table-sort.ts +57 -2
  595. package/src/components/data-table-virtual.ts +32 -8
  596. package/src/components/data-table.tsx +239 -68
  597. package/src/components/date-field.tsx +66 -9
  598. package/src/components/date-picker.tsx +125 -49
  599. package/src/components/date-range-picker.tsx +71 -36
  600. package/src/components/error-boundary.tsx +53 -39
  601. package/src/components/field-base-labels.ts +20 -0
  602. package/src/components/field-base.tsx +13 -7
  603. package/src/components/form-actions.tsx +20 -5
  604. package/src/components/hover-menu.tsx +18 -8
  605. package/src/components/icon-button.tsx +14 -9
  606. package/src/components/inline-confirm.tsx +116 -0
  607. package/src/components/inline-entity-combobox.tsx +197 -153
  608. package/src/components/input.tsx +1 -1
  609. package/src/components/jump-calendar.tsx +30 -146
  610. package/src/components/legal-page.tsx +10 -7
  611. package/src/components/legal.tsx +4 -2
  612. package/src/components/lightbox.tsx +21 -8
  613. package/src/components/list.tsx +10 -4
  614. package/src/components/measured-grid.tsx +8 -4
  615. package/src/components/mini-calendar.tsx +6 -5
  616. package/src/components/modal.tsx +6 -1
  617. package/src/components/month-grid.tsx +229 -0
  618. package/src/components/month-picker.tsx +192 -200
  619. package/src/components/multi-select.tsx +21 -9
  620. package/src/components/nav-pills.tsx +1 -1
  621. package/src/components/picker-sheet.tsx +12 -9
  622. package/src/components/pie-chart-labels.ts +8 -0
  623. package/src/components/pie-chart.tsx +22 -28
  624. package/src/components/popover.tsx +18 -1
  625. package/src/components/row-actions.tsx +2 -1
  626. package/src/components/series-chart-axes.ts +9 -4
  627. package/src/components/series-chart-labels.ts +7 -4
  628. package/src/components/series-chart.tsx +253 -87
  629. package/src/components/share-card.tsx +6 -6
  630. package/src/components/tabs-labels.ts +13 -0
  631. package/src/components/tabs.tsx +2 -2
  632. package/src/components/toggle-legend.tsx +16 -11
  633. package/src/components/translation-review-editor.tsx +6 -5
  634. package/src/components/translation-review.tsx +4 -3
  635. package/src/components/treemap-labels.ts +47 -0
  636. package/src/components/treemap-layout.ts +210 -0
  637. package/src/components/treemap.tsx +780 -138
  638. package/src/components/use-table-state.ts +12 -9
  639. package/src/data-table.ts +1 -4
  640. package/src/demo/demo-countdown.ts +3 -8
  641. package/src/eslint/role-utilities.ts +97 -19
  642. package/src/feedback/feedback-dialog.tsx +30 -19
  643. package/src/feedback/feedback-mutation.ts +20 -0
  644. package/src/feedback/feedback-page-link.ts +90 -0
  645. package/src/feedback/feedback-public-list.tsx +13 -7
  646. package/src/feedback/feedback-replies.tsx +13 -6
  647. package/src/feedback/feedback-row-detail-labels.ts +0 -3
  648. package/src/feedback/feedback-row-detail.tsx +70 -84
  649. package/src/feedback/feedback-status-undo.ts +28 -28
  650. package/src/feedback/feedback-submit-dialog.tsx +2 -2
  651. package/src/feedback/feedback-submit.tsx +21 -7
  652. package/src/feedback/feedback-swipe.tsx +1 -1
  653. package/src/feedback/feedback-table.tsx +86 -38
  654. package/src/feedback/feedback-thread-labels.ts +2 -2
  655. package/src/feedback/feedback-thread.tsx +18 -26
  656. package/src/feedback.ts +89 -6
  657. package/src/hooks/use-focus-trap.ts +8 -24
  658. package/src/hooks/use-hotkey.ts +24 -7
  659. package/src/hooks/use-long-press.ts +16 -2
  660. package/src/hooks/use-media-query.ts +20 -4
  661. package/src/hooks/use-mounted.ts +39 -0
  662. package/src/hooks/use-overlay-history.ts +32 -3
  663. package/src/i18n/defaults.ts +4 -9
  664. package/src/i18n/german.ts +8 -19
  665. package/src/i18n/kit-labels.tsx +9 -11
  666. package/src/i18n/locales/es.ts +8 -19
  667. package/src/i18n/locales/fr.ts +21 -30
  668. package/src/i18n/locales/hu.ts +10 -19
  669. package/src/i18n/locales/it.ts +8 -20
  670. package/src/i18n/locales/zh.ts +9 -19
  671. package/src/i18n/review.ts +12 -2
  672. package/src/i18n/shared-labels.ts +0 -1
  673. package/src/index.ts +57 -49
  674. package/src/landing/routing.tsx +14 -10
  675. package/src/lib/broadcast.ts +52 -0
  676. package/src/lib/date-format.ts +89 -13
  677. package/src/lib/day-format.ts +96 -0
  678. package/src/lib/describe-failure.ts +18 -0
  679. package/src/lib/direction.ts +39 -0
  680. package/src/lib/focus-left.ts +156 -0
  681. package/src/lib/format.ts +5 -17
  682. package/src/lib/http-status.ts +38 -0
  683. package/src/lib/intl-cache.ts +25 -0
  684. package/src/lib/iso-day.ts +13 -0
  685. package/src/lib/lazy-with-fallback.ts +82 -0
  686. package/src/lib/path-pattern.ts +55 -0
  687. package/src/lib/reduced-motion.ts +2 -1
  688. package/src/lib/round.ts +7 -2
  689. package/src/lib/safe-storage.ts +48 -6
  690. package/src/lib/session-refresh.ts +1 -1
  691. package/src/lib/share-format.ts +18 -0
  692. package/src/lib/text-case.ts +19 -0
  693. package/src/lib/text-match.ts +57 -2
  694. package/src/lib/thenable.ts +19 -0
  695. package/src/lib/translation-review.ts +13 -5
  696. package/src/notifications/device-zone-report.ts +1 -1
  697. package/src/notifications/notification-bell.tsx +7 -4
  698. package/src/notifications/notification-inbox.tsx +40 -58
  699. package/src/notifications/notification-parts.tsx +3 -4
  700. package/src/notifications/notification-types-setting.tsx +1 -1
  701. package/src/notifications/notifications-labels.ts +7 -0
  702. package/src/notifications/push-device-setting.tsx +1 -1
  703. package/src/notifications/push-devices-setting.tsx +30 -55
  704. package/src/notifications/quiet-hours-setting.tsx +93 -31
  705. package/src/notifications/unsubscribe-panel.tsx +4 -7
  706. package/src/notifications/use-push-device.ts +76 -10
  707. package/src/offline/query-persistence.ts +35 -3
  708. package/src/rhf/fields.tsx +11 -4
  709. package/src/search/command-palette.tsx +2 -4
  710. package/src/search/global-search.tsx +36 -15
  711. package/src/search/search-index.ts +0 -15
  712. package/src/search/use-command-key.ts +13 -12
  713. package/src/search.ts +10 -1
  714. package/src/settings/use-settings-focus.ts +3 -0
  715. package/src/shell/account-menu-language.tsx +6 -4
  716. package/src/shell/account-menu-text-size.tsx +10 -7
  717. package/src/shell/app-shell.tsx +0 -13
  718. package/src/shell/company-switcher.tsx +1 -1
  719. package/src/shell/dev-menu.tsx +8 -22
  720. package/src/shell/top-bar-actions.tsx +1 -1
  721. package/src/shell/top-bar-parts-labels.ts +1 -4
  722. package/src/shell.ts +21 -17
  723. package/src/sync/engine.ts +339 -61
  724. package/src/sync.ts +2 -8
  725. package/src/testing/css-variables.ts +8 -9
  726. package/src/theme/chart-palette.ts +0 -2
  727. package/src/theme/contrast.ts +8 -9
  728. package/src/theme/palette-store.ts +9 -9
  729. package/src/theme/text-size.ts +6 -8
  730. package/src/theme/theme-store.ts +7 -9
  731. package/src/tour/tour-catalogue.tsx +26 -15
  732. package/src/tour/tour-dock.ts +0 -2
  733. package/src/tour/tour-gates.ts +23 -0
  734. package/src/tour/tour-overlay.tsx +1170 -0
  735. package/src/tour/tour.tsx +108 -1202
  736. package/src/tour/use-tour-progress.ts +1 -1
  737. package/src/wizard/stepper-nav.tsx +3 -1
  738. package/src/wizard/types.ts +11 -2
  739. package/src/wizard/use-wizard.ts +2 -1
  740. package/src/wizard/validation.ts +8 -2
  741. package/tokens.css +6 -5
  742. package/dist/components/field-sync-labels.d.ts +0 -2
  743. package/dist/components/field-sync-labels.js +0 -12
  744. package/dist/components/field-sync-labels.js.map +0 -1
  745. package/dist/components/field-sync.d.ts +0 -164
  746. package/dist/components/field-sync.js +0 -269
  747. package/dist/components/field-sync.js.map +0 -1
  748. package/dist/components/section-nav.d.ts +0 -37
  749. package/dist/components/section-nav.js +0 -33
  750. package/dist/components/section-nav.js.map +0 -1
  751. package/dist/components/sign-chip-labels.d.ts +0 -2
  752. package/dist/components/sign-chip-labels.js +0 -11
  753. package/dist/components/sign-chip-labels.js.map +0 -1
  754. package/dist/components/sign-chip.d.ts +0 -68
  755. package/dist/components/sign-chip.js +0 -47
  756. package/dist/components/sign-chip.js.map +0 -1
  757. package/dist/components/ui-labels.js.map +0 -1
  758. package/dist/lib/isin.d.ts +0 -28
  759. package/dist/lib/isin.js +0 -36
  760. package/dist/lib/isin.js.map +0 -1
  761. package/dist/shell/dev-switchers.d.ts +0 -6
  762. package/dist/shell/dev-switchers.js +0 -12
  763. package/dist/shell/dev-switchers.js.map +0 -1
  764. package/dist/shell/role-switcher.d.ts +0 -21
  765. package/dist/shell/role-switcher.js +0 -31
  766. package/dist/shell/role-switcher.js.map +0 -1
  767. package/src/components/field-sync-labels.ts +0 -13
  768. package/src/components/field-sync.tsx +0 -482
  769. package/src/components/section-nav.tsx +0 -65
  770. package/src/components/sign-chip-labels.ts +0 -12
  771. package/src/components/sign-chip.tsx +0 -124
  772. package/src/components/ui-labels.ts +0 -24
  773. package/src/lib/isin.ts +0 -62
  774. package/src/shell/dev-switchers.tsx +0 -18
  775. package/src/shell/role-switcher.tsx +0 -46
@@ -107,8 +107,63 @@ export function rankMatch(
107
107
  ): MatchRank {
108
108
  const q = foldForSearch(query.trim(), locale);
109
109
  if (!q) return 0;
110
- const text = foldForSearch(label, locale);
111
- if (text === q || (code !== undefined && foldForSearch(code, locale) === q)) return 0;
110
+ return rankFolded(foldForSearch(label, locale), q, code === undefined ? undefined : foldForSearch(code, locale));
111
+ }
112
+
113
+ /** {@link rankMatch} on a text, a non-empty query and a code all folded already. */
114
+ function rankFolded(text: string, q: string, code: string | undefined): MatchRank {
115
+ if (text === q || code === q) return 0;
112
116
  if (text.startsWith(q)) return 1;
113
117
  return text.includes(q) ? 2 : -1;
114
118
  }
119
+
120
+ /** A row {@link searchRanked} kept, and how well it answers the WHOLE query:
121
+ * {@link rankMatch}'s rank, or `3` for a row that holds the query's words apart
122
+ * ("Zürich Migros" for "migros zürich"). */
123
+ export interface RankedHit<T> {
124
+ row: T;
125
+ rank: Exclude<MatchRank, -1> | 3;
126
+ }
127
+
128
+ /**
129
+ * The rows that hold every word of `query`, each ranked for the WHOLE query — for the
130
+ * lists that FILTER by words ({@link matchesSearch}) and RANK by the whole query
131
+ * ({@link rankMatch}): Combobox, CountrySelect and InlineEntityCombobox (refactor audit
132
+ * 2026-10-30, DUP-4). In the order given; sort by `rank` with a stable sort, and the rows
133
+ * of one rank keep it. No words keep every row, at `0`.
134
+ *
135
+ * Each row's texts are folded ONCE, and the query once. The lists asked `matchesSearch`
136
+ * and then `rankMatch` of each row they kept, which folded the row three times and the
137
+ * query once per row, per keystroke — InlineEntityCombobox asked `rankMatch` twice of
138
+ * most rows (0.52 code review, combobox.tsx).
139
+ *
140
+ * `texts(row)`: where a word may stand; the FIRST is the label the rank is for.
141
+ * `code(row)`: a key that answers only WHOLE — a word that IS the code matches the row,
142
+ * and the code as the whole query ranks `0` ("ch" is Switzerland before it is Chad) —
143
+ * never a letter of it ("w" is not Aruba, AW: 0.52 code review, country-select.tsx).
144
+ * Internal: not in the barrel.
145
+ */
146
+ export function searchRanked<T>(
147
+ rows: readonly T[],
148
+ query: string,
149
+ texts: (row: T) => readonly (string | undefined)[],
150
+ { code, locale }: { code?: (row: T) => string; locale?: string } = {},
151
+ ): RankedHit<T>[] {
152
+ const q = foldForSearch(query.trim(), locale);
153
+ const words = q.split(/\s+/).filter((word) => word !== "");
154
+ if (words.length === 0) return rows.map((row) => ({ row, rank: 0 }));
155
+ const hits: RankedHit<T>[] = [];
156
+ for (const row of rows) {
157
+ const folded = texts(row)
158
+ .filter((t): t is string => t !== undefined)
159
+ .map((t) => foldForSearch(t, locale));
160
+ const key = code === undefined ? undefined : foldForSearch(code(row), locale);
161
+ // One haystack, as `matchesSearch` has it: a word holds no whitespace, so it cannot
162
+ // match across the newline between two texts.
163
+ const hay = folded.join("\n");
164
+ if (!words.every((word) => word === key || hay.includes(word))) continue;
165
+ const rank = rankFolded(folded[0] ?? "", q, key);
166
+ hits.push({ row, rank: rank === -1 ? 3 : rank });
167
+ }
168
+ return hits;
169
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Whether a callback's answer is a promise to wait for — an object or a function with a
3
+ * `then` (Promises/A+ "thenable"). A callback that answers nothing is done when it
4
+ * returns.
5
+ *
6
+ * The auth forms (`auth/status-parts`), the admin confirm and the feedback mutation each
7
+ * wrote their own, three spellings of one check — and the admin's turned a thenable
8
+ * FUNCTION away (0.52 code review, feedback/feedback-mutation.ts; the refactor audit's
9
+ * DUP findings).
10
+ *
11
+ * @internal Package-private — not re-exported from the barrel.
12
+ */
13
+ export function isThenable(value: unknown): value is PromiseLike<unknown> {
14
+ return (
15
+ (typeof value === "object" || typeof value === "function") &&
16
+ value !== null &&
17
+ typeof (value as { then?: unknown }).then === "function"
18
+ );
19
+ }
@@ -22,7 +22,7 @@
22
22
  * the same contract, so the mapping is written once, here.
23
23
  */
24
24
 
25
- import { foldForSearch } from "./text-match";
25
+ import { matchesSearch, searchWords } from "./text-match";
26
26
 
27
27
  // ── Shapes ──────────────────────────────────────────────────────────────────────
28
28
 
@@ -407,7 +407,8 @@ export interface TranslationReviewFilter {
407
407
  source: string;
408
408
  namespace: string;
409
409
  /** Searched in the key, the text and the reference, folded as every kit list's search
410
- * is (`foldForSearch`): no case, no accents — "uberweisung" finds "Überweisung". */
410
+ * is (`foldForSearch`): no case, no accents — "uberweisung" finds "Überweisung". Every
411
+ * word on its own (0.52): "budget assign" finds `budget.rta`, "Ready to Assign". */
411
412
  query: string;
412
413
  placeholdersOnly: boolean;
413
414
  }
@@ -420,20 +421,27 @@ export const DEFAULT_TRANSLATION_REVIEW_FILTER: TranslationReviewFilter = {
420
421
  placeholdersOnly: false,
421
422
  };
422
423
 
424
+ /**
425
+ * The rows the filters leave. `locale` (0.52) folds the query and the texts as the kit's
426
+ * other lists do — the panel passes the provider's; left out, the runtime's default.
427
+ */
423
428
  export function filterTranslationRows(
424
429
  rows: readonly TranslationRow[],
425
430
  filter: Partial<TranslationReviewFilter>,
431
+ locale?: string,
426
432
  ): TranslationRow[] {
427
433
  const f = { ...DEFAULT_TRANSLATION_REVIEW_FILTER, ...filter };
428
- // Folded as every kit list's search is (DUP-5, refactor audit 2026-10).
429
- const q = foldForSearch(f.query.trim());
434
+ // Folded as every kit list's search is (DUP-5, refactor audit 2026-10), and since 0.52
435
+ // word by word, each anywhere in the key, the text or the reference (0.51.4's rule;
436
+ // refactor audit 2026-10-30, DUP-4: the whole query had to be one substring of one).
437
+ const words = searchWords(f.query, locale);
430
438
  return rows.filter(
431
439
  (row) =>
432
440
  (f.status === "all" || row.status === f.status) &&
433
441
  (f.source === "all" || row.source === f.source) &&
434
442
  (f.namespace === "all" || row.namespace === f.namespace) &&
435
443
  (!f.placeholdersOnly || row.placeholderMismatch) &&
436
- (!q || [row.key, row.text, row.reference].some((s) => foldForSearch(s).includes(q))),
444
+ matchesSearch(words, [row.key, row.text, row.reference], locale),
437
445
  );
438
446
  }
439
447
 
@@ -1,6 +1,6 @@
1
1
  import { useEffect } from "react";
2
2
 
3
- import { settle } from "../account/account-parts";
3
+ import { settle } from "../hooks/use-mounted";
4
4
 
5
5
  export interface DeviceZoneReportOptions {
6
6
  /** The account's `device_timezone` from `/auth/me`; `undefined` while it loads (no
@@ -2,7 +2,7 @@ import { Bell } from "lucide-react";
2
2
  import type { LucideIcon } from "lucide-react";
3
3
 
4
4
  import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
5
- import { useKitFormat } from "../lib/format";
5
+ import { useDayFormatter } from "../lib/day-format";
6
6
  import { DEFAULT_LIST_LABELS } from "../components/list-labels";
7
7
  import { StatusDot } from "../components/status-dot";
8
8
  import { TopBarActionMenu } from "../shell/topbar-action-menu";
@@ -26,7 +26,8 @@ export interface NotificationBellProps<Id extends string | number = string | num
26
26
  href: string;
27
27
  /** The row's glyph for a type, as {@link NotificationInbox}'s; `Bell` by default. */
28
28
  icon?: (type: string) => LucideIcon | undefined;
29
- /** A row's time. Default: the provider's locale and `timeZone`, date and time. */
29
+ /** A row's time. Default: the provider's `formatDate` (the app's date preference) with
30
+ * the language's clock, else date and time in the provider's locale and `timeZone`. */
30
31
  formatDate?: (iso: string) => string;
31
32
  labels?: LabelOverride<NotificationsLabels>;
32
33
  }
@@ -57,8 +58,10 @@ export function NotificationBell<Id extends string | number = string | number>({
57
58
  }: NotificationBellProps<Id>) {
58
59
  const labels = useNotificationsLabels(labelsProp);
59
60
  const list = useKitLabels("list", DEFAULT_LIST_LABELS);
60
- const { formatDate } = useKitFormat();
61
- const timeOf = (iso: string) => (formatDateProp ? formatDateProp(iso) : formatDate(iso, "dateTime"));
61
+ // As the inbox's rows: the prop, else the provider's `formatDate` with the language's
62
+ // clock, else the kit's in the provider's locale and `timeZone` (refactor audit 2026-10-30, DUP-2).
63
+ const day = useDayFormatter(formatDateProp);
64
+ const timeOf = (iso: string) => day(iso, { time: true });
62
65
  const unread = unreadCount > 0;
63
66
  const shown = (items ?? []).slice(0, BELL_ROWS);
64
67
 
@@ -1,21 +1,23 @@
1
- import { useEffect, useId, useRef, useState } from "react";
2
- import type { ComponentPropsWithRef, KeyboardEvent, ReactNode } from "react";
1
+ import { useId, useRef, useState } from "react";
2
+ import type { ComponentPropsWithRef, ReactNode } from "react";
3
3
  import { Bell, CheckCheck, Trash2 } from "lucide-react";
4
4
  import type { LucideIcon } from "lucide-react";
5
5
 
6
6
  import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
7
7
  import { DEFAULT_COMMON_LABELS } from "../i18n/shared-labels";
8
8
  import { cn } from "../lib/cn";
9
- import { useKitFormat } from "../lib/format";
9
+ import { useDayFormatter } from "../lib/day-format";
10
10
  import { Button } from "../components/button";
11
11
  import { Card } from "../components/card";
12
12
  import { EmptyState } from "../components/empty-state";
13
13
  import { IconButton } from "../components/icon-button";
14
+ import { InlineConfirm } from "../components/inline-confirm";
14
15
  import { List, ListItem } from "../components/list";
15
16
  import { Skeleton } from "../components/skeleton";
16
17
  import { COMMIT_EXCEPT_BILLING } from "../components/write-lock";
17
18
  import { SettingsCardTitle } from "../settings/settings-heading";
18
- import { settle, useMounted } from "../account/account-parts";
19
+ import { safeNextPath } from "../landing/routing";
20
+ import { settle, useMounted } from "../hooks/use-mounted";
19
21
  import { describeFailure, FailureLine, useNotificationsLabels } from "./notification-parts";
20
22
  import type { NotificationsLabels } from "./notifications-labels";
21
23
 
@@ -29,7 +31,8 @@ export interface NotificationInboxItem<Id extends string | number = string | num
29
31
  notification_type: string;
30
32
  title: string;
31
33
  body: string;
32
- /** A path in the app, an absolute URL, or `null` (nothing to open). */
34
+ /** A path in the app, or `null` (nothing to open). Never `//` or a scheme (§3.7): a url
35
+ * that does not resolve to this origin is drawn as a row with nothing to open. */
33
36
  url: string | null;
34
37
  /** ISO date-time. */
35
38
  created_at: string;
@@ -62,10 +65,12 @@ export interface NotificationInboxProps<Id extends string | number = string | nu
62
65
  onClear: () => Promise<unknown> | void;
63
66
  /**
64
67
  * Open a row: the kit marks it read first, then calls this, and the app routes to
65
- * `item.url` (kastlan switches the acting company, `item.company_id`, first). Every row is a button then.
66
- * Left out, a row with a `url` is a real link — an in-app path through the provider's
67
- * router link, an absolute URL in a new tab — that marks itself read on a click or a
68
- * middle click (keksdose #451), and a row without one marks itself read.
68
+ * `item.url` (kastlan switches the acting company, `item.company_id`, first) — through
69
+ * `safeNextPath`, as the kit does. Every row is a button then.
70
+ * Left out, a row with a `url` is a real link through the provider's router link — the
71
+ * url as a same-origin path (`safeNextPath`) — that marks itself read on a click or a
72
+ * middle click (keksdose #451). A row without one, or with one that leaves the origin
73
+ * (`//host`, a scheme), marks itself read and opens nothing.
69
74
  */
70
75
  onOpen?: (item: NotificationInboxItem<Id>) => void;
71
76
  /** The row's glyph for a type — the app's map (keksdose's `TYPE_ICONS`). `undefined`,
@@ -77,7 +82,8 @@ export interface NotificationInboxProps<Id extends string | number = string | nu
77
82
  onLoadMore?: () => void;
78
83
  /** The next page is loading. */
79
84
  loadingMore?: boolean;
80
- /** A row's time. Default: the provider's locale and `timeZone`, date and time. */
85
+ /** A row's time. Default: the provider's `formatDate` (the app's date preference) with
86
+ * the language's clock, else date and time in the provider's locale and `timeZone`. */
81
87
  formatDate?: (iso: string) => string;
82
88
  /** The heading. Default `labels.inboxTitle` ("Inbox"). */
83
89
  title?: ReactNode;
@@ -124,21 +130,18 @@ export function NotificationInbox<Id extends string | number = string | number>(
124
130
  }: NotificationInboxProps<Id>) {
125
131
  const labels = useNotificationsLabels(labelsProp);
126
132
  const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
127
- const { formatDate } = useKitFormat();
133
+ // The prop, else the provider's `formatDate` with the language's clock, else the kit's
134
+ // date and time in the provider's locale and `timeZone` (refactor audit 2026-10-30, DUP-2).
135
+ const day = useDayFormatter(formatDateProp);
128
136
  const [asking, setAsking] = useState(false);
129
137
  const [busy, setBusy] = useState<"read" | "clear" | null>(null);
130
138
  const [failure, setFailure] = useState<ReactNode>(null);
131
139
  const mounted = useMounted();
132
140
  const headingId = useId();
133
- const cancelRef = useRef<HTMLButtonElement>(null);
141
+ // Back to "Clear all" when the confirm leaves, so focus does not fall to <body>.
134
142
  const clearRef = useRef<HTMLButtonElement>(null);
135
- const [returning, setReturning] = useState(false);
136
- useEffect(() => {
137
- if (asking) cancelRef.current?.focus();
138
- else if (returning) clearRef.current?.focus();
139
- }, [asking, returning]);
140
143
 
141
- const timeOf = (iso: string) => (formatDateProp ? formatDateProp(iso) : formatDate(iso, "dateTime"));
144
+ const timeOf = (iso: string) => day(iso, { time: true });
142
145
  const iconOf = (type: string): LucideIcon => icon?.(type) ?? Bell;
143
146
 
144
147
  const run = (which: "read" | "clear", call: () => unknown, after?: () => void) => {
@@ -166,42 +169,21 @@ export function NotificationInbox<Id extends string | number = string | number>(
166
169
  });
167
170
  };
168
171
 
169
- const leave = () => {
170
- setReturning(true);
171
- setAsking(false);
172
- };
173
- const escapeLeaves = (event: KeyboardEvent<HTMLButtonElement>) => {
174
- if (event.key === "Escape") {
175
- event.preventDefault();
176
- event.stopPropagation();
177
- leave();
178
- }
179
- };
180
-
181
172
  const count = items?.length ?? 0;
182
173
 
183
174
  const header = asking ? (
184
- <div className="space-y-2 border-b border-subtle px-3 py-2" data-inbox-confirm="">
185
- <p role="alert" className="text-sm">
186
- {labels.clearPrompt}
187
- </p>
188
- <div className="flex flex-wrap gap-2">
189
- <Button
190
- type="button"
191
- size="sm"
192
- variant="danger"
193
- commit={COMMIT_EXCEPT_BILLING}
194
- pending={busy === "clear"}
195
- onClick={() => run("clear", onClear, () => setAsking(false))}
196
- onKeyDown={escapeLeaves}
197
- >
198
- {labels.clearAll}
199
- </Button>
200
- <Button ref={cancelRef} type="button" size="sm" variant="ghost" onClick={leave} onKeyDown={escapeLeaves}>
201
- {common.cancel}
202
- </Button>
203
- </div>
204
- </div>
175
+ <InlineConfirm
176
+ className="border-b border-subtle px-3 py-2"
177
+ data-inbox-confirm=""
178
+ prompt={labels.clearPrompt}
179
+ confirmLabel={labels.clearAll}
180
+ cancelLabel={common.cancel}
181
+ onConfirm={() => run("clear", onClear, () => setAsking(false))}
182
+ onLeave={() => setAsking(false)}
183
+ busy={busy === "clear"}
184
+ commit={COMMIT_EXCEPT_BILLING}
185
+ returnFocusRef={clearRef}
186
+ />
205
187
  ) : (
206
188
  <div className="flex items-center justify-between gap-2 border-b border-subtle px-3 py-2">
207
189
  <SettingsCardTitle id={headingId}>{title ?? labels.inboxTitle}</SettingsCardTitle>
@@ -223,10 +205,7 @@ export function NotificationInbox<Id extends string | number = string | number>(
223
205
  size="xs"
224
206
  tone="danger"
225
207
  commit={COMMIT_EXCEPT_BILLING}
226
- onClick={() => {
227
- setReturning(false);
228
- setAsking(true);
229
- }}
208
+ onClick={() => setAsking(true)}
230
209
  disabled={count === 0 || busy !== null}
231
210
  label={labels.clearAll}
232
211
  >
@@ -273,7 +252,11 @@ export function NotificationInbox<Id extends string | number = string | number>(
273
252
  />
274
253
  );
275
254
  }
276
- if (!item.url) {
255
+ // A same-origin path or nothing (refactor audit 2026-10-30, FLW-8): `//host` starts
256
+ // with "/" and went through the router link off the origin, and any scheme opened
257
+ // as an external link. The urls are server-written; this is defence in depth.
258
+ const path = safeNextPath(item.url);
259
+ if (!path) {
277
260
  return <ListItem key={item.id} {...row} data-inbox-item={String(item.id)} onClick={() => markOne(item)} />;
278
261
  }
279
262
  // A real link, so a middle click opens a background tab; a middle click fires no
@@ -283,8 +266,7 @@ export function NotificationInbox<Id extends string | number = string | number>(
283
266
  key={item.id}
284
267
  {...row}
285
268
  data-inbox-item={String(item.id)}
286
- href={item.url}
287
- external={!item.url.startsWith("/")}
269
+ href={path}
288
270
  onClick={() => markOne(item)}
289
271
  onAuxClick={(event) => {
290
272
  if (event.button === 1) markOne(item);
@@ -19,10 +19,9 @@ export function useNotificationsLabels(prop?: LabelOverride<NotificationsLabels>
19
19
  return useKitLabels("notifications", DEFAULT_NOTIFICATIONS_LABELS, prop);
20
20
  }
21
21
 
22
- /** The app's words for a failure, else `fallback`. */
23
- export function describeFailure(own: ReactNode | undefined, fallback: ReactNode): ReactNode {
24
- return hasContent(own) ? own : fallback;
25
- }
22
+ /** The app's words for a failure, else `fallback` — in lib/ since 0.52, for the auth forms
23
+ * too (refactor audit 2026-10-30, DUP-14). */
24
+ export { describeFailure } from "../lib/describe-failure";
26
25
 
27
26
  /** A failure, said under the card's controls — nothing toasts (§4.2). */
28
27
  export function FailureLine({ children }: { children: ReactNode }) {
@@ -13,7 +13,7 @@ import { COMMIT_EXCEPT_BILLING } from "../components/write-lock";
13
13
  import { usePhoneLayout } from "../hooks/use-breakpoint";
14
14
  import { CARD_DESCRIPTION_CLASS } from "../settings/settings-card-classes";
15
15
  import { SettingsCardTitle } from "../settings/settings-heading";
16
- import { settle, useMounted } from "../account/account-parts";
16
+ import { settle, useMounted } from "../hooks/use-mounted";
17
17
  import { describeFailure, FailureLine, useNotificationsLabels, useWriteOverlay } from "./notification-parts";
18
18
  import type { WriteOverlay } from "./notification-parts";
19
19
  import type { NotificationsLabels } from "./notifications-labels";
@@ -162,6 +162,12 @@ export interface NotificationsLabels {
162
162
  /** Account mail is not a notification, and keeps coming. */
163
163
  accountMail: string;
164
164
  turnBackOn: string;
165
+ /**
166
+ * 0.52: the line under the outcome, {@link accountMail} and {@link turnBackOn} as one
167
+ * text — joined by the catalogue, not by the panel: the panel glued them with an ASCII
168
+ * space, which Chinese does not put between sentences (refactor audit 2026-10-30, DOC-11).
169
+ */
170
+ stoppedHint: (accountMail: string, turnBackOn: string) => string;
165
171
  openSettings: string;
166
172
  /** A token the server refused, or one that does not parse. */
167
173
  invalidLink: string;
@@ -273,6 +279,7 @@ export const DEFAULT_NOTIFICATIONS_LABELS: NotificationsLabels = {
273
279
  stoppedAll: (app) => `Done. You won’t get notification e-mails from ${app} any more.`,
274
280
  accountMail: "E-mails about your account still come.",
275
281
  turnBackOn: "You can turn them back on at any time in Settings.",
282
+ stoppedHint: (accountMail, turnBackOn) => `${accountMail} ${turnBackOn}`,
276
283
  openSettings: "Open Settings",
277
284
  invalidLink: "This link doesn’t work any more. You can turn e-mails off in Settings instead.",
278
285
 
@@ -11,7 +11,7 @@ import { DialogFrame } from "../components/dialog-frame";
11
11
  import { COMMIT_EXCEPT_BILLING } from "../components/write-lock";
12
12
  import { CARD_DESCRIPTION_CLASS } from "../settings/settings-card-classes";
13
13
  import { SettingsCardTitle } from "../settings/settings-heading";
14
- import { useMounted } from "../account/account-parts";
14
+ import { useMounted } from "../hooks/use-mounted";
15
15
  import { describeFailure, FailureLine, useNotificationsLabels } from "./notification-parts";
16
16
  import type { NotificationsLabels } from "./notifications-labels";
17
17
  import { PushDeviceError } from "./use-push-device";
@@ -1,21 +1,23 @@
1
- import { useEffect, useRef, useState } from "react";
2
- import type { ComponentPropsWithRef, KeyboardEvent, ReactNode } from "react";
1
+ import { useRef, useState } from "react";
2
+ import type { ComponentPropsWithRef, ReactNode } from "react";
3
3
  import { MonitorSmartphone } from "lucide-react";
4
4
 
5
- import { useKitLabels, useKitLocale, type LabelOverride } from "../i18n/kit-labels";
5
+ import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
6
6
  import { DEFAULT_COMMON_LABELS } from "../i18n/shared-labels";
7
7
  import { cn } from "../lib/cn";
8
- import { formatDate } from "../lib/format";
8
+ import { useDayFormatter } from "../lib/day-format";
9
+ import { toDate } from "../lib/format";
9
10
  import { Button } from "../components/button";
10
11
  import { Card } from "../components/card";
11
12
  import { Chip } from "../components/chip";
12
13
  import { Disclosure } from "../components/disclosure";
14
+ import { InlineConfirm } from "../components/inline-confirm";
13
15
  import { Skeleton } from "../components/skeleton";
14
16
  import { Switch } from "../components/switch";
15
17
  import { COMMIT_EXCEPT_BILLING } from "../components/write-lock";
16
18
  import { CARD_DESCRIPTION_CLASS } from "../settings/settings-card-classes";
17
19
  import { SettingsCardTitle } from "../settings/settings-heading";
18
- import { settle, useMounted } from "../account/account-parts";
20
+ import { settle, useMounted } from "../hooks/use-mounted";
19
21
  import { describeFailure, FailureLine, useNotificationsLabels, useWriteOverlay } from "./notification-parts";
20
22
  import type { NotificationsLabels } from "./notifications-labels";
21
23
  import type { NotificationTypeEntry, NotificationTypesValue, PushDeviceItem } from "./notification-types";
@@ -68,7 +70,8 @@ export interface PushDevicesSettingProps<Id extends string | number = string> ex
68
70
  /** `DELETE /notifications/devices/{id}`. Asked first; refresh `devices` once it
69
71
  * resolves. */
70
72
  onRemove: (id: Id) => Promise<unknown> | void;
71
- /** The dates' text. Default: the provider's locale, medium date. */
73
+ /** The dates' text. Default: the provider's `formatDate` (the app's date preference),
74
+ * else a medium date in the provider's locale and `timeZone`. */
72
75
  formatDate?: (date: Date) => string;
73
76
  /** Overrides the provider's locale for the default format. */
74
77
  locale?: string;
@@ -140,16 +143,17 @@ export function PushDevicesSetting<Id extends string | number = string>({
140
143
  const labels = useNotificationsLabels(labelsProp);
141
144
  const mutedOverlay = useWriteOverlay<string[]>(devices);
142
145
  const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
143
- const locale = useKitLocale(localeProp);
146
+ // The prop, else the provider's `formatDate` (the app's date preference), else the kit's
147
+ // in the provider's locale and `timeZone` (refactor audit 2026-10-30, DUP-2).
148
+ const day = useDayFormatter(formatDateProp, localeProp);
144
149
  const [asking, setAsking] = useState<Id | null>(null);
145
150
  const [busyId, setBusyId] = useState<Id | null>(null);
146
151
  const [failure, setFailure] = useState<ReactNode>(null);
147
152
  const mounted = useMounted();
148
153
 
149
154
  const dateText = (iso: string): string => {
150
- const date = new Date(iso);
151
- if (Number.isNaN(date.getTime())) return iso;
152
- return formatDateProp ? formatDateProp(date) : formatDate(date, "medium", { locale });
155
+ const date = toDate(iso);
156
+ return date ? day(date) : iso;
153
157
  };
154
158
 
155
159
  const remove = (device: PushDeviceItem<Id>) => {
@@ -305,53 +309,27 @@ function DeviceRow<Id extends string | number>({
305
309
  /** "Types on this device", under the row (0.46). */
306
310
  types: ReactNode;
307
311
  }) {
308
- const cancelRef = useRef<HTMLButtonElement>(null);
312
+ // Back to Remove when the confirm leaves, so focus does not fall to <body>.
309
313
  const removeRef = useRef<HTMLButtonElement>(null);
310
- // Which way the confirm closed: back to Remove, so focus does not fall to <body>.
311
- const [returning, setReturning] = useState(false);
312
- useEffect(() => {
313
- if (asking) cancelRef.current?.focus();
314
- else if (returning) removeRef.current?.focus();
315
- }, [asking, returning]);
316
-
317
- const leave = () => {
318
- setReturning(true);
319
- onCancel();
320
- };
321
- const escapeLeaves = (event: KeyboardEvent<HTMLButtonElement>) => {
322
- if (event.key === "Escape") {
323
- event.preventDefault();
324
- event.stopPropagation();
325
- leave();
326
- }
327
- };
328
314
 
329
315
  const row = { "data-push-device-id": String(device.id), "data-current": current || undefined };
330
316
 
331
317
  if (asking) {
332
318
  return (
333
- <li {...row} className="space-y-2 py-2">
334
- <p role="alert" className="text-sm">
335
- {labels.removePrompt}
336
- </p>
337
- <div className="flex flex-wrap gap-2">
338
- <Button
339
- type="button"
340
- size="sm"
341
- variant="danger"
342
- commit={COMMIT_EXCEPT_BILLING}
343
- pending={busy}
344
- aria-label={labels.removeItem(name)}
345
- onClick={onConfirm}
346
- onKeyDown={escapeLeaves}
347
- >
348
- {labels.remove}
349
- </Button>
350
- <Button ref={cancelRef} type="button" size="sm" variant="ghost" onClick={leave} onKeyDown={escapeLeaves}>
351
- {cancelLabel}
352
- </Button>
353
- </div>
354
- </li>
319
+ <InlineConfirm
320
+ as="li"
321
+ {...row}
322
+ className="py-2"
323
+ prompt={labels.removePrompt}
324
+ confirmLabel={labels.remove}
325
+ confirmName={labels.removeItem(name)}
326
+ cancelLabel={cancelLabel}
327
+ onConfirm={onConfirm}
328
+ onLeave={onCancel}
329
+ busy={busy}
330
+ commit={COMMIT_EXCEPT_BILLING}
331
+ returnFocusRef={removeRef}
332
+ />
355
333
  );
356
334
  }
357
335
 
@@ -385,10 +363,7 @@ function DeviceRow<Id extends string | number>({
385
363
  commit={COMMIT_EXCEPT_BILLING}
386
364
  disabled={blocked}
387
365
  aria-label={labels.removeItem(name)}
388
- onClick={() => {
389
- setReturning(false);
390
- onAsk();
391
- }}
366
+ onClick={onAsk}
392
367
  >
393
368
  {labels.remove}
394
369
  </Button>