@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
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Whether a pathname is one a `PathPattern` names — the rule `useLastVisitedPage`'s
3
+ * `exclude` reads (landing/routing.tsx) and the feedback guard's one-shot routes
4
+ * (refactor audit 2026-10-30, FLW-7), here without the router: `landing/routing` imports
5
+ * react-router, which `/feedback` must not drag in. The one copy: routing kept a private
6
+ * one, and the two had drifted within the round (0.52 code review, this file).
7
+ *
8
+ * A string is that path and everything under it (`/join` is `/join` and `/join/abc`, not
9
+ * `/joined`; `/` is only `/`); a RegExp is tested on the pathname (a `g` flag dropped, so
10
+ * `lastIndex` never carries over between calls).
11
+ *
12
+ * Case-INSENSITIVE, as React Router matches a route unless it sets `caseSensitive` (0.52
13
+ * code review, feedback/feedback-page-link.ts): the FLW-7 guard compared case-sensitively,
14
+ * and `/Join?token=` went out as a link the router still rendered as `/join`. A RegExp
15
+ * gets the `i` flag for the same reason. Matching more than a case-sensitive route would
16
+ * only turns a link into text, or leaves a page unrecorded as a resume target: both
17
+ * callers' safe side.
18
+ *
19
+ * @internal Package-private — not re-exported from the barrel.
20
+ */
21
+ export function matchesPathPattern(pathname: string, pattern: string | RegExp): boolean {
22
+ if (typeof pattern !== "string") {
23
+ return new RegExp(pattern.source, `${pattern.flags.replace(/[gi]/g, "")}i`).test(pathname);
24
+ }
25
+ const path = pathname.toLowerCase();
26
+ if (pattern === "/") return path === "/";
27
+ const base = (pattern.endsWith("/") ? pattern.slice(0, -1) : pattern).toLowerCase();
28
+ return path === base || path.startsWith(`${base}/`);
29
+ }
30
+
31
+ /**
32
+ * The pathname of `href` (a path with its query and hash) as React Router matches it:
33
+ * each segment percent-decoded, an encoded `/` kept as `%2F` so it never splits a segment
34
+ * (react-router 8, `decodePath` in `matchRoutesImpl`). The 0.52 code review
35
+ * (feedback/feedback-page-link.ts) found `/j%6Fin?token=` passing the FLW-7 guard as a
36
+ * link that the router decoded to `/join`.
37
+ *
38
+ * A malformed escape leaves its own segment as written, where the router gives up on the
39
+ * whole path: the rest still decodes, so the answer is never less than the router's.
40
+ *
41
+ * @internal Package-private — not re-exported from the barrel.
42
+ */
43
+ export function routerPathname(href: string): string {
44
+ return href
45
+ .replace(/[?#].*$/, "")
46
+ .split("/")
47
+ .map((segment) => {
48
+ try {
49
+ return decodeURIComponent(segment).replace(/\//g, "%2F");
50
+ } catch {
51
+ return segment;
52
+ }
53
+ })
54
+ .join("/");
55
+ }
@@ -13,7 +13,8 @@
13
13
  * screen only delays its `onClose` — every test suite, the kit's and the apps', reads a
14
14
  * closed overlay as gone at once.
15
15
  *
16
- * Package-private — not re-exported from the barrel.
16
+ * Public since 0.52 (DUP-8, refactor audit 2026-10-30): Kurvenschmiede's chain animation
17
+ * carried a copy of its own.
17
18
  */
18
19
  export function prefersReducedMotion(whereUnknown = false): boolean {
19
20
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return whereUnknown;
package/src/lib/round.ts CHANGED
@@ -25,14 +25,19 @@ function shiftDecimal(value: number, by: number): number {
25
25
  * `n` rounded to `digits` decimals, half away from zero, in decimal arithmetic:
26
26
  * 1.005 → 1.01, -2.5 at 0 → -3. Never NaN for a finite `n`, and never -0 — `formatMoney`
27
27
  * prints -0 as "-0,00 €", so a negative that rounds away comes back as 0. A non-finite
28
- * `n` comes back unchanged.
28
+ * `n` comes back unchanged. `digits` counts in whole decimals, as `toFixed` takes it: 2.5
29
+ * is 2, and NaN is 0.
29
30
  */
30
31
  export function roundHalfAway(n: number, digits: number): number {
31
32
  if (!Number.isFinite(n)) return n;
33
+ // "1.2345e2.5" is NaN, and `|| 0` below made it 0: MeasuredGrid's `digits`, which went to
34
+ // `toFixed` before DUP-14 brought it here, wrote every computed cell of a table with a
35
+ // fractional one as "0" (0.52 code review, deep, charts, finding 5).
36
+ const places = Math.trunc(digits) || 0;
32
37
  const abs = Math.abs(n);
33
38
  // Every double from 2^53 up is a whole number already, and scaling one near
34
39
  // Number.MAX_VALUE up would overflow to Infinity.
35
- const magnitude = abs >= 2 ** 53 ? abs : shiftDecimal(Math.round(shiftDecimal(abs, digits)), -digits);
40
+ const magnitude = abs >= 2 ** 53 ? abs : shiftDecimal(Math.round(shiftDecimal(abs, places)), -places);
36
41
  // The sign goes back on after rounding, so `|| 0` must see the signed result.
37
42
  return (n < 0 ? -magnitude : magnitude) || 0;
38
43
  }
@@ -16,8 +16,13 @@
16
16
  *
17
17
  * Since 0.34 (DUP-11, refactor audit 2026-10) it also removes, and guards
18
18
  * `sessionStorage` the same way: `landing/routing`, `billing/checkout-processing` and
19
- * the demo banner each wrote that guard again by hand. `removeStored` and the session
20
- * pair are package-private — the barrel exports `readStored` / `writeStored` only.
19
+ * the demo banner each wrote that guard again by hand.
20
+ *
21
+ * Since 0.52 all of it but {@link storedKeys} is public, with a JSON pair beside it
22
+ * (DUP-8, refactor audit 2026-10-30). Kept package-private, the guard was written again
23
+ * four times in the kit's showcase and in 16 files across the three apps, some of them
24
+ * without it: a token read that throws where storage is blocked takes every request
25
+ * down with it. (The kit's own DevMenu, 0.51, wrote the session pair a second time too.)
21
26
  */
22
27
 
23
28
  /** `access` on the storage area, or `fallback` where there is none (SSR) or it throws. */
@@ -37,9 +42,13 @@ export function readStored(key: string): string | null {
37
42
  }
38
43
 
39
44
  /** Store `value` under `key`, silently doing nothing when storage is unavailable
40
- * or full. A preference that cannot be persisted is not worth an exception. */
41
- export function writeStored(key: string, value: string): void {
42
- guarded("localStorage", undefined, (storage) => storage.setItem(key, value));
45
+ * or full. A preference that cannot be persisted is not worth an exception. `null`
46
+ * removes the key, as {@link writeSessionStored}'s does (0.52; the two pairs wrote
47
+ * differently, and `null` past the types stored the string "null" — 0.52 code review). */
48
+ export function writeStored(key: string, value: string | null): void {
49
+ guarded("localStorage", undefined, (storage) =>
50
+ value === null ? storage.removeItem(key) : storage.setItem(key, value),
51
+ );
43
52
  }
44
53
 
45
54
  /** Forget `key`, silently doing nothing when storage is blocked — there is nothing to
@@ -60,10 +69,43 @@ export function writeSessionStored(key: string, value: string | null): void {
60
69
  );
61
70
  }
62
71
 
72
+ /**
73
+ * The JSON stored under `key`, when it parses and `isShape` accepts it; else `null`. Absent,
74
+ * blocked, malformed and another shape all read as "never set" — the caller's default —
75
+ * which is what the six hand-written `JSON.parse(readStored(key))` reads in the kit each
76
+ * answered in their own try/catch (DUP-8). `isShape` gets the parsed value as `unknown`:
77
+ * the shape check is the one part that is the caller's. A shape check that throws reads
78
+ * as another shape: null.
79
+ */
80
+ export function readStoredJson<T>(key: string, isShape: (value: unknown) => value is T): T | null {
81
+ const text = readStored(key);
82
+ if (text === null) return null;
83
+ try {
84
+ const value: unknown = JSON.parse(text);
85
+ return isShape(value) ? value : null;
86
+ } catch {
87
+ // not JSON, or a shape check that read past what is there
88
+ return null;
89
+ }
90
+ }
91
+
92
+ /** Store `value` as JSON under `key`, silently doing nothing when storage is unavailable
93
+ * or full, or the value has no JSON form (a cycle, a BigInt) — {@link writeStored}'s rule. */
94
+ export function writeStoredJson(key: string, value: unknown): void {
95
+ let text: string | undefined;
96
+ try {
97
+ text = JSON.stringify(value);
98
+ } catch {
99
+ return;
100
+ }
101
+ // `undefined` (and a function) has no JSON form either: stringify answers undefined.
102
+ if (text !== undefined) writeStored(key, text);
103
+ }
104
+
63
105
  /**
64
106
  * Every key in `area` that starts with `prefix`, or `[]` where storage refuses — for the
65
107
  * reset of this device's settings, which removes a table's views by their prefix
66
- * (docs/settings-harmonization.md §11.4). Package-private, like {@link removeStored}.
108
+ * (docs/settings-harmonization.md §11.4). Package-private: the reset's alone.
67
109
  */
68
110
  export function storedKeys(prefix: string, area: "local" | "session" = "local"): string[] {
69
111
  return guarded(area === "session" ? "sessionStorage" : "localStorage", [], (storage) => {
@@ -36,7 +36,7 @@
36
36
  */
37
37
 
38
38
  import type { AxiosLikeInstance, ServerWakeAxiosConfig } from "./server-wake";
39
- import { httpStatusOf } from "../auth/auth-errors";
39
+ import { httpStatusOf } from "./http-status";
40
40
 
41
41
  /** What the app's `refresh` resolves: the new access token, plus whatever its `store`
42
42
  * needs (its refresh token, the user). */
@@ -0,0 +1,18 @@
1
+ /**
2
+ * How a chart says a share of its whole — PieChart's slices and centre, Treemap's tiles
3
+ * and groups. Internal, not exported from the barrel.
4
+ *
5
+ * Each chart held a copy of the same two `Intl` formats and the same switch between them
6
+ * (0.52 code review of treemap.tsx, finding 9); one copy is the rule both say.
7
+ */
8
+
9
+ /**
10
+ * A formatter for shares (0–1) in `locale`, as a percent: one decimal under 10 %, where
11
+ * rounding to whole percents starts to lie — a slice of 0.4 % said as "0%" says it is not
12
+ * there — and whole percents above. Make it once per locale (it builds two `Intl` formats).
13
+ */
14
+ export function shareFormat(locale: string | undefined): (share: number) => string {
15
+ const whole = new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: 0 });
16
+ const fine = new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: 1 });
17
+ return (share) => (share < 0.1 ? fine : whole).format(share);
18
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Upper-case the first letter only, in `locale` — the one copy of the rule (refactor audit
3
+ * 2026-10-30, DUP-11: MonthPicker and JumpCalendar each had it, and MiniCalendar's caption
4
+ * still used the CSS `capitalize` it was written against).
5
+ *
6
+ * Several locales (fr, es, it, pt, …) write month names in lower case, which at the head
7
+ * of a field or a panel reads as a typo. But only the FIRST letter is ours to change:
8
+ * `capitalize` upper-cases every word, so Spanish read "Septiembre De 2026", and a
9
+ * caption that does not start with the month kept its wrong capital — Hungarian read
10
+ * "2026. Szeptember". This gives "Septiembre de 2026" and "2026. szeptember".
11
+ *
12
+ * In `locale` because the case mapping is the language's: Turkish upper-cases "i" to "İ".
13
+ * `undefined` is the runtime's default, as everywhere `Intl` takes one.
14
+ *
15
+ * Package-private — not re-exported from the barrel.
16
+ */
17
+ export function upperFirst(text: string, locale: string | undefined): string {
18
+ return text.charAt(0).toLocaleUpperCase(locale) + text.slice(1);
19
+ }
@@ -32,6 +32,18 @@ export function foldForSearch(text: string, locale?: string): string {
32
32
  .replace(/ß/g, "ss");
33
33
  }
34
34
 
35
+ /**
36
+ * Whether two names are one name as a picker's search reads them: folded
37
+ * ({@link foldForSearch}) and trimmed — "cafe" is Café, " MIGROS " is Migros. For "does
38
+ * the typed text name a record that exists" (a create row, InlineEntityCombobox's blur
39
+ * commit), which compared with plain `toLowerCase` while the list beside it folded, so
40
+ * "cafe" listed Café as a hit and offered "Create “cafe”" too — a duplicate payee or shop
41
+ * chain one Enter away (refactor audit 2026-10-30, DUP-5). Internal: not in the barrel.
42
+ */
43
+ export function sameName(a: string, b: string, locale?: string): boolean {
44
+ return foldForSearch(a.trim(), locale) === foldForSearch(b.trim(), locale);
45
+ }
46
+
35
47
  /**
36
48
  * A picker's query as its words, each folded (0.51.4, keksdose's /prices shop picker):
37
49
  * "Migros Zürich" → `["migros", "zurich"]`. An empty or blank query has no words.
@@ -95,8 +107,63 @@ export function rankMatch(
95
107
  ): MatchRank {
96
108
  const q = foldForSearch(query.trim(), locale);
97
109
  if (!q) return 0;
98
- const text = foldForSearch(label, locale);
99
- 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;
100
116
  if (text.startsWith(q)) return 1;
101
117
  return text.includes(q) ? 2 : -1;
102
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