@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
@@ -1,13 +1,17 @@
1
- import { useEffect, useRef, useState } from "react";
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
2
  import type { KeyboardEvent, ReactNode } from "react";
3
3
  import { KeyRound } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
5
- import { useKitLocale, type LabelOverride } from "../i18n/kit-labels";
5
+ import { useDayFormatter } from "../lib/day-format";
6
+ import { toDate } from "../lib/format";
7
+ import type { LabelOverride } from "../i18n/kit-labels";
6
8
  import { Button } from "../components/button";
7
9
  import { Card } from "../components/card";
8
10
  import { EmptyState } from "../components/empty-state";
11
+ import { InlineConfirm } from "../components/inline-confirm";
9
12
  import { Input } from "../components/input";
10
13
  import { Skeleton } from "../components/skeleton";
14
+ import { COMMIT_EXCEPT_BILLING, useWriteLock } from "../components/write-lock";
11
15
  import { useAccountSettingsLabels } from "./account-settings-labels";
12
16
  import { SettingsCardTitle } from "../settings/settings-heading";
13
17
  import type { PasskeysSettingLabels } from "./account-settings-labels";
@@ -88,7 +92,9 @@ export interface PasskeysSettingProps<Id extends PasskeyId = PasskeyId> extends
88
92
  * app knows which of those it detected.
89
93
  */
90
94
  unavailable?: ReactNode;
91
- /** A date for the "Added …" / "Last used …" lines. Default: the locale's medium date. */
95
+ /** A date for the "Added …" / "Last used …" lines. Default: the provider's `formatDate`
96
+ * (the app's date preference), else a medium date in the provider's locale and
97
+ * `timeZone`. */
92
98
  formatDate?: (date: Date) => string;
93
99
  /** Overrides the provider's locale for the default date format. */
94
100
  locale?: string;
@@ -117,6 +123,11 @@ export interface PasskeysSettingProps<Id extends PasskeyId = PasskeyId> extends
117
123
  * must work in an app without a `ConfirmProvider`, and the question belongs next to
118
124
  * the passkey it names. Focus moves to Cancel, as in every destructive confirm in the
119
125
  * kit, so the Enter that pressed Delete cannot also answer it.
126
+ *
127
+ * **Under a write lock** (0.52) Add, Rename, Delete and the confirm are `commit` controls
128
+ * exempt from billing — a lapsed plan still lets the account manage how it signs in, the
129
+ * demo does not. Until 0.52 the passkeys' confirm was the one inline confirm without it,
130
+ * so the demo could delete, rename and add (refactor audit 2026-10-30, DUP-10).
120
131
  */
121
132
  export function PasskeysSetting<Id extends PasskeyId = PasskeyId>({
122
133
  passkeys,
@@ -138,7 +149,21 @@ export function PasskeysSetting<Id extends PasskeyId = PasskeyId>({
138
149
  ...rest
139
150
  }: PasskeysSettingProps<Id>) {
140
151
  const labels = useAccountSettingsLabels("passkeys", labelsProp);
141
- const locale = useKitLocale(localeProp);
152
+ // The prop, else the provider's `formatDate`, else the kit's in the provider's locale and
153
+ // `timeZone`; a bare "YYYY-MM-DD" is read on its calendar (refactor audit 2026-10-30,
154
+ // DUP-2: this card parsed with `new Date` and built its own `Intl` formatter).
155
+ // The raw value goes in, so a bare day keeps its calendar; the prop still gets a Date.
156
+ const own = useMemo(
157
+ () =>
158
+ formatDate &&
159
+ ((value: PasskeyItem["createdAt"]) => {
160
+ const date = toDate(value);
161
+ return date ? formatDate(date) : "";
162
+ }),
163
+ [formatDate],
164
+ );
165
+ const day = useDayFormatter(own, localeProp);
166
+ const lock = useWriteLock(COMMIT_EXCEPT_BILLING);
142
167
  const [name, setName] = useState("");
143
168
  // `beforeAdd` is running. State for the button, and a ref for the guard: two clicks
144
169
  // in one frame both read the state from before either set it.
@@ -146,14 +171,12 @@ export function PasskeysSetting<Id extends PasskeyId = PasskeyId>({
146
171
  const checkingRef = useRef(false);
147
172
 
148
173
  const date = (value: PasskeyItem["createdAt"]): string | null => {
149
- if (value === null || value === undefined || value === "") return null;
150
- const d = value instanceof Date ? value : new Date(value);
151
- if (Number.isNaN(d.getTime())) return null;
152
- return formatDate ? formatDate(d) : new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(d);
174
+ return toDate(value) ? day(value) : null;
153
175
  };
154
176
 
155
177
  const add = () => {
156
- if (adding || checkingRef.current) return;
178
+ // The name field's Enter reaches here too, past the locked button.
179
+ if (adding || checkingRef.current || lock.locked) return;
157
180
  const typed = name;
158
181
  const value = typed.trim();
159
182
  const send = () =>
@@ -211,6 +234,7 @@ export function PasskeysSetting<Id extends PasskeyId = PasskeyId>({
211
234
  lastUsed={date(item.lastUsedAt)}
212
235
  attributes={rowProps?.(item)}
213
236
  busy={busyId !== undefined && busyId !== null && busyId === item.id}
237
+ locked={lock.locked}
214
238
  onRename={onRename}
215
239
  onDelete={onDelete}
216
240
  labels={labels}
@@ -234,7 +258,7 @@ export function PasskeysSetting<Id extends PasskeyId = PasskeyId>({
234
258
  }}
235
259
  />
236
260
  )}
237
- <Button onClick={add} disabled={busy} aria-busy={busy || undefined}>
261
+ <Button onClick={add} commit={COMMIT_EXCEPT_BILLING} disabled={busy} aria-busy={busy || undefined}>
238
262
  <KeyRound className="size-4" aria-hidden />
239
263
  {adding ? labels.adding : labels.add}
240
264
  </Button>
@@ -265,6 +289,7 @@ function PasskeyRow<Id extends PasskeyId>({
265
289
  lastUsed,
266
290
  attributes,
267
291
  busy,
292
+ locked,
268
293
  onRename,
269
294
  onDelete,
270
295
  labels,
@@ -274,24 +299,26 @@ function PasskeyRow<Id extends PasskeyId>({
274
299
  lastUsed: string | null;
275
300
  attributes?: { id?: string } & PasskeyDataAttributes;
276
301
  busy: boolean;
302
+ /** A write lock holds: the rename field's Enter saves nothing. */
303
+ locked: boolean;
277
304
  onRename?: PasskeysSettingProps<Id>["onRename"];
278
305
  onDelete?: PasskeysSettingProps<Id>["onDelete"];
279
306
  labels: PasskeysSettingLabels;
280
307
  }) {
281
308
  const [mode, setMode] = useState<RowMode>("view");
282
309
  const [draft, setDraft] = useState(item.name);
283
- // Which button opened the sub-mode, so leaving it puts focus back there — the
284
- // confirm or the field unmounts under the focus, which otherwise falls to <body>.
310
+ // Which button opened the sub-mode, so leaving it puts focus back there — the field or
311
+ // the confirm unmounts under the focus, which otherwise falls to <body>. InlineConfirm
312
+ // returns it on Cancel and Escape; this also covers a delete that succeeded while the
313
+ // row stayed (the list not refreshed yet) and a rename.
285
314
  const [returnTo, setReturnTo] = useState<"rename" | "delete" | null>(null);
286
- const cancelDeleteRef = useRef<HTMLButtonElement>(null);
287
315
  const renameRef = useRef<HTMLInputElement>(null);
288
316
  const renameButtonRef = useRef<HTMLButtonElement>(null);
289
317
  const deleteButtonRef = useRef<HTMLButtonElement>(null);
290
318
 
291
319
  useEffect(() => {
292
- if (mode === "delete") cancelDeleteRef.current?.focus();
293
- else if (mode === "rename") renameRef.current?.select();
294
- else if (returnTo) (returnTo === "rename" ? renameButtonRef : deleteButtonRef).current?.focus();
320
+ if (mode === "rename") renameRef.current?.select();
321
+ else if (mode === "view" && returnTo) (returnTo === "rename" ? renameButtonRef : deleteButtonRef).current?.focus();
295
322
  }, [mode, returnTo]);
296
323
 
297
324
  const open = (next: "rename" | "delete") => {
@@ -300,17 +327,10 @@ function PasskeyRow<Id extends PasskeyId>({
300
327
  setMode(next);
301
328
  };
302
329
  const leave = () => setMode("view");
303
- const escapeLeaves = (e: KeyboardEvent<HTMLButtonElement>) => {
304
- if (e.key === "Escape") {
305
- e.preventDefault();
306
- e.stopPropagation();
307
- leave();
308
- }
309
- };
310
330
 
311
331
  const saveRename = () => {
312
332
  const next = draft.trim();
313
- if (!onRename || !next || busy) return;
333
+ if (!onRename || !next || busy || locked) return;
314
334
  if (next === item.name) {
315
335
  leave();
316
336
  return;
@@ -356,7 +376,7 @@ function PasskeyRow<Id extends PasskeyId>({
356
376
  }
357
377
  }}
358
378
  />
359
- <Button size="sm" onClick={saveRename} disabled={busy || !draft.trim()}>
379
+ <Button size="sm" onClick={saveRename} commit={COMMIT_EXCEPT_BILLING} disabled={busy || !draft.trim()}>
360
380
  {labels.save}
361
381
  </Button>
362
382
  <Button size="sm" variant="ghost" onClick={leave}>
@@ -368,19 +388,19 @@ function PasskeyRow<Id extends PasskeyId>({
368
388
 
369
389
  if (mode === "delete") {
370
390
  return (
371
- <li {...li} className="space-y-2 py-2">
372
- <p role="alert" className="text-sm">
373
- {labels.deleteConfirm(item.name)}
374
- </p>
375
- <div className="flex flex-wrap gap-2">
376
- <Button size="sm" variant="danger" onClick={confirmDelete} onKeyDown={escapeLeaves} disabled={busy}>
377
- {labels.confirmDelete}
378
- </Button>
379
- <Button ref={cancelDeleteRef} size="sm" variant="ghost" onClick={leave} onKeyDown={escapeLeaves}>
380
- {labels.cancel}
381
- </Button>
382
- </div>
383
- </li>
391
+ <InlineConfirm
392
+ as="li"
393
+ {...li}
394
+ className="py-2"
395
+ prompt={labels.deleteConfirm(item.name)}
396
+ confirmLabel={labels.confirmDelete}
397
+ cancelLabel={labels.cancel}
398
+ onConfirm={confirmDelete}
399
+ onLeave={leave}
400
+ busy={busy}
401
+ commit={COMMIT_EXCEPT_BILLING}
402
+ returnFocusRef={deleteButtonRef}
403
+ />
384
404
  );
385
405
  }
386
406
 
@@ -398,6 +418,7 @@ function PasskeyRow<Id extends PasskeyId>({
398
418
  ref={renameButtonRef}
399
419
  size="sm"
400
420
  variant="ghost"
421
+ commit={COMMIT_EXCEPT_BILLING}
401
422
  disabled={busy}
402
423
  onClick={() => open("rename")}
403
424
  aria-label={labels.renameItem(item.name)}
@@ -411,6 +432,7 @@ function PasskeyRow<Id extends PasskeyId>({
411
432
  size="sm"
412
433
  variant="ghost"
413
434
  tone="danger"
435
+ commit={COMMIT_EXCEPT_BILLING}
414
436
  disabled={busy}
415
437
  onClick={() => open("delete")}
416
438
  aria-label={labels.deleteItem(item.name)}
@@ -2,9 +2,11 @@ import { useState } from "react";
2
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 { cn } from "../lib/cn";
7
- import { formatRelativeTime, toDate } from "../lib/format";
7
+ import { useDayFormatter } from "../lib/day-format";
8
+ import { describeFailure } from "../lib/describe-failure";
9
+ import { toDate, useKitFormat } from "../lib/format";
8
10
  import type { DateInput } from "../lib/format";
9
11
  import { AlertBanner } from "../components/alert-banner";
10
12
  import { Chip } from "../components/chip";
@@ -107,8 +109,9 @@ export interface SessionsSettingProps<Id extends SessionId = SessionId> extends
107
109
  onRevoke?: (id: Id) => Promise<unknown> | void;
108
110
  /** The app's own words for a failure, or `undefined` for the kit's `failed`. */
109
111
  describeError?: (error: unknown, action: SessionsAction) => ReactNode | undefined;
110
- /** The "Last active" text. Default: how long ago, in the provider's locale, and the
111
- * date once it is more than a week back. */
112
+ /** The "Last active" text. Default: how long ago, in the provider's locale and
113
+ * `timeZone`, and the date once it is more than a week back — through the provider's
114
+ * `formatDate` (the app's date preference) when it has one. */
112
115
  formatLastActive?: (date: Date) => string;
113
116
  /** Overrides the provider's locale for the default format. */
114
117
  locale?: string;
@@ -152,22 +155,25 @@ export function SessionsSetting<Id extends SessionId = SessionId>({
152
155
  ...rest
153
156
  }: SessionsSettingProps<Id>) {
154
157
  const labels = useKitLabels("sessions", DEFAULT_SESSIONS_LABELS, labelsProp);
155
- const locale = useKitLocale(localeProp);
158
+ // The provider's locale and `timeZone`; past a week the words are a date, and a date
159
+ // that names a day follows the app's preference (refactor audit 2026-10-30, DUP-2).
160
+ const { formatDate, formatRelativeTime } = useKitFormat(localeProp);
161
+ const day = useDayFormatter(null, localeProp);
156
162
  const [busyId, setBusyId] = useState<Id | null>(null);
157
163
  const [failure, setFailure] = useState<ReactNode>(null);
158
164
  const mounted = useMounted();
159
165
 
160
- const describe = (error: unknown, action: SessionsAction): ReactNode => {
161
- const own = describeError?.(error, action);
162
- return hasContent(own) ? own : labels.failed;
163
- };
166
+ const describe = (error: unknown, action: SessionsAction): ReactNode =>
167
+ describeFailure(describeError?.(error, action), labels.failed);
164
168
 
165
169
  const lastActive = (value: DateInput): string | null => {
166
170
  const date = toDate(value);
167
171
  if (!date) return null;
168
- return formatLastActive
169
- ? formatLastActive(date)
170
- : formatRelativeTime(date, { locale, absoluteAfterDays: 7, absoluteStyle: "medium" });
172
+ if (formatLastActive) return formatLastActive(date);
173
+ const words = formatRelativeTime(date, { absoluteAfterDays: 7, absoluteStyle: "medium" });
174
+ // Past a week the words ARE the medium date ("5 weeks ago" makes a reader do sums);
175
+ // then the day as the app's preference writes it.
176
+ return words === formatDate(date, "medium") ? day(date) : words;
171
177
  };
172
178
 
173
179
  const signOutEverywhere = () => {
@@ -12,6 +12,7 @@ import { authErrorCode } from "../auth/auth-errors";
12
12
  import type { KitErrorCode } from "../auth/auth-errors";
13
13
  import { usePersonLabel } from "./admin-parts";
14
14
  import { hasContent } from "../lib/presence";
15
+ import { isThenable } from "../lib/thenable";
15
16
  import type { AdminPerson, MaybePromise } from "./admin-parts";
16
17
  import { isGroupTarget } from "./admin-action-log";
17
18
  import type { AdminGroupTarget } from "./admin-action-log";
@@ -176,11 +177,6 @@ interface AdminActionConfirmCommonProps {
176
177
  * and `acknowledge`. */
177
178
  export type AdminActionConfirmProps = AdminActionConfirmCommonProps & AdminActionConfirmTarget;
178
179
 
179
- /** Whether a callback answered a promise. */
180
- function isThenable(value: unknown): value is PromiseLike<unknown> {
181
- return typeof value === "object" && value !== null && typeof (value as PromiseLike<unknown>).then === "function";
182
- }
183
-
184
180
  /** The refusal's words and code. */
185
181
  function refusalOf(
186
182
  error: unknown,
@@ -1,8 +1,8 @@
1
1
  import { useCallback } from "react";
2
- import { useKitDateFormatter, useKitLocale } from "../i18n/kit-labels";
3
- import { formatDate, toDate } from "../lib/format";
2
+ import { useKitLocale } from "../i18n/kit-labels";
3
+ import { useDayFormatter } from "../lib/day-format";
4
+ import { toDate } from "../lib/format";
4
5
  import type { DateInput } from "../lib/format";
5
- import { toLocalIso } from "../lib/dates";
6
6
  import { formatPersonName } from "../lib/person-name";
7
7
 
8
8
  /**
@@ -54,29 +54,15 @@ export function usePersonLabel(localeProp?: string): (person: AdminPerson | null
54
54
  /**
55
55
  * A day as words in a sentence ("6 Nov 2026"): the provider's `formatDate` when the app
56
56
  * set one (keksdose K12), asked for no weekday — a date in a sentence carries none — else
57
- * `Intl`'s medium date. `""` for no date.
57
+ * `Intl`'s medium date, in the provider's locale and `timeZone` (0.52: the kit's one day
58
+ * ladder, `useDayFormatter` — refactor audit 2026-10-30, DUP-2). `""` for no date or one
59
+ * that does not parse: the caller leaves the sentence out.
58
60
  */
59
61
  export function useDayText(localeProp?: string): (value: DateInput) => string {
60
- const locale = useKitLocale(localeProp);
61
- const fromProvider = useKitDateFormatter();
62
- return useCallback(
63
- (value) => {
64
- const date = toDate(value);
65
- if (!date) return "";
66
- const own = fromProvider
67
- ? fromProvider(toLocalIso(date), { unit: "day", source: "dateMark", locale, weekday: false })
68
- : "";
69
- return own || formatDate(date, "medium", { locale });
70
- },
71
- [fromProvider, locale],
72
- );
62
+ const day = useDayFormatter(undefined, localeProp);
63
+ return useCallback((value) => (toDate(value) ? day(value) : ""), [day]);
73
64
  }
74
65
 
75
- /** Call a callback that may throw or answer a promise, as a promise. */
76
- export function settle<T>(call: () => MaybePromise<T>): Promise<T | void> {
77
- try {
78
- return Promise.resolve(call());
79
- } catch (error) {
80
- return Promise.reject(error);
81
- }
82
- }
66
+ /** Call a callback that may throw or answer a promise, as a promise — the kit's one
67
+ * (hooks/use-mounted), not a copy of it (0.52 code review, this file). */
68
+ export { settle } from "../hooks/use-mounted";
@@ -2,7 +2,7 @@
2
2
  // catalogue (src/i18n/defaults.ts) imports them without the component, so `en` loads as one
3
3
  // chunk like the other languages (0.34, KS U8). ./mail-test-card re-exports them.
4
4
 
5
- import { englishRateLimited } from "../auth/auth-errors";
5
+ import { englishRateLimited } from "../auth/auth-errors-labels";
6
6
  import type { MailTestCardLabels } from "./mail-test-card";
7
7
 
8
8
  /** docs/admin-harmonization.md §9.2.4, word for word. */
@@ -1,23 +1,5 @@
1
- // The English words of ./plan-change, in a module with no component code: the English
2
- // catalogue (src/i18n/defaults.ts) imports them without the component, so `en` loads as one
3
- // chunk like the other languages (0.34, KS U8). ./plan-change re-exports them.
4
-
5
- import type { PlanChangeLabels } from "./plan-change";
6
-
7
- export const DEFAULT_PLAN_CHANGE_LABELS: PlanChangeLabels = {
8
- column: "Plan",
9
- title: "Change plan",
10
- confirm: "Change plan",
11
- plan: "Plan",
12
- current: (plan) => `Current plan: ${plan}`,
13
- keepsItems: "A smaller plan only blocks creating more; nothing is deleted.",
14
- until: "Free until",
15
- untilHint: "Leave empty for no end. A running beta keeps its own end.",
16
- needsChange: "Pick another plan or an end date.",
17
- changed: (from, to) => `Plan changed from ${from} to ${to}.`,
18
- set: (to) => `Plan set to ${to}.`,
19
- keptBeta: "The beta keeps its end; only the plan changed.",
20
- untilDone: (date) => `Free until ${date}.`,
21
- overLimit: "Above the new plan’s limit: nothing is removed, new items are blocked.",
22
- usageOf: (used, limit, dimension) => `${used} of ${limit} ${dimension}`,
23
- };
1
+ // Moved to billing/plan-change-labels in 0.52 (refactor audit 2026-10-30, MOD-6): the
2
+ // billing and admin folders imported each other through it. Kept so the old path still
3
+ // answers; nothing in the kit imports it any more but the English catalogue.
4
+ export { DEFAULT_PLAN_CHANGE_LABELS } from "../billing/plan-change-labels";
5
+ export type { PlanChangeLabels } from "../billing/plan-change-labels";
@@ -18,7 +18,8 @@ import { AdminActionConfirm } from "./admin-action-confirm";
18
18
  import type { AdminActionConfirmValues } from "./admin-action-confirm";
19
19
  import { personLabel, useDayText } from "./admin-parts";
20
20
  import type { AdminPerson, MaybePromise } from "./admin-parts";
21
- import { DEFAULT_PLAN_CHANGE_LABELS } from "./plan-change-labels";
21
+ import { DEFAULT_PLAN_CHANGE_LABELS } from "../billing/plan-change-labels";
22
+ import type { PlanChangeLabels } from "../billing/plan-change-labels";
22
23
 
23
24
  /**
24
25
  * The operator's plan parts (docs/billing-harmonization.md §14.12, decision 27):
@@ -34,49 +35,11 @@ import { DEFAULT_PLAN_CHANGE_LABELS } from "./plan-change-labels";
34
35
  * whatever the billing switch says.
35
36
  */
36
37
 
37
- /** The `planChange` namespace: the column, the grant dialog and the result's lines. */
38
- export interface PlanChangeLabels {
39
- /** The column's header: "Plan". */
40
- column: string;
41
- /** The dialog's title: "Change plan". */
42
- title: string;
43
- /** Its confirm button: "Change plan". */
44
- confirm: string;
45
- /** The plan select's label: "Plan". */
46
- plan: string;
47
- /** The line over the select: "Current plan: Free". */
48
- current: (plan: string) => string;
49
- /** Under the select — the fact that is not on the button. */
50
- keepsItems: string;
51
- /** The end of a free grant's field: "Free until". */
52
- until: string;
53
- /** Under it. */
54
- untilHint: string;
55
- /** Why the confirm is held while nothing would change. */
56
- needsChange: string;
57
- /** The result: the plan moved from one to another. */
58
- changed: (from: string, to: string) => string;
59
- /** The result: an account with no plan before, or the same plan again. */
60
- set: (to: string) => string;
61
- /** The result: a running beta kept its own end (§12.34); only the plan moved. */
62
- keptBeta: string;
63
- /** The result: the grant runs until `date` (formatted). */
64
- untilDone: (date: string) => string;
65
- /** The result: the account owns more than the new plan allows. */
66
- overLimit: string;
67
- /**
68
- * The column's usage, spelled out (its tooltip): "1 of 5 budgets". Figures arrive
69
- * formatted; `dimension` is the app's word, as `usage.label` gives it — since 0.33.1
70
- * in the form the LIMIT takes when the label gives its plural forms ("1 of 1 budget",
71
- * "1 of 5 budgets"): in every shipped language the word follows the limit, or heads
72
- * the line in German, whose `von` would want a dative plural no app form carries
73
- * ("Budgets: 1 von 5"). An override of yours gets the same word. Since 0.34 the grant
74
- * dialog's usage line too, when `usage` comes as the column's shape.
75
- */
76
- usageOf: (used: string, limit: string, dimension: string) => string;
77
- }
78
-
79
- // Defined in ./plan-change-labels, which holds no component code (0.34, KS U8).
38
+ // The words and their type live in billing/plan-change-labels, which holds no component
39
+ // code (0.34, KS U8): PlanSwitchConfirm reads them too, and billing importing admin while
40
+ // this module imports billing made the two folders import each other (refactor audit
41
+ // 2026-10-30, MOD-6).
42
+ export type { PlanChangeLabels };
80
43
  export { DEFAULT_PLAN_CHANGE_LABELS };
81
44
 
82
45
  /** A plan code as the parts compare it: lowercase (§12.16 — an older row's "FREE" is
@@ -8,6 +8,7 @@ import { CheckboxGroup } from "../components/checkbox-group";
8
8
  import type { CheckboxGroupOption } from "../components/checkbox-group";
9
9
  import { FormActions } from "../components/form-actions";
10
10
  import { Caption } from "../components/text";
11
+ import { describeFailure } from "../lib/describe-failure";
11
12
  import { hasContent } from "../lib/presence";
12
13
  import type { MaybePromise } from "./admin-parts";
13
14
  import type { CommitScope } from "../components/write-lock";
@@ -165,7 +166,7 @@ export function ReviewerScopeEditor({
165
166
  try {
166
167
  result = onSave(scope);
167
168
  } catch (error) {
168
- setFailure(describeError?.(error) ?? labels.failed);
169
+ setFailure(describeFailure(describeError?.(error), labels.failed));
169
170
  return;
170
171
  }
171
172
  if (!result || typeof result.then !== "function") return;
@@ -174,8 +175,7 @@ export function ReviewerScopeEditor({
174
175
  () => setPending(false),
175
176
  (error: unknown) => {
176
177
  setPending(false);
177
- const own = describeError?.(error);
178
- setFailure(hasContent(own) ? own : labels.failed);
178
+ setFailure(describeFailure(describeError?.(error), labels.failed));
179
179
  },
180
180
  );
181
181
  };
@@ -0,0 +1,23 @@
1
+ // The English of every `rateLimited` label, in a module with no component code and no
2
+ // error probing: the English catalogue (src/i18n/defaults.ts) reaches it through nine
3
+ // `*-labels.ts` modules, and until 0.52 that pulled `auth/auth-errors` — and since MOD-6
4
+ // its `lib/http-status` — into the `en` chunk (refactor audit 2026-10-30, MOD-6).
5
+ // auth/auth-errors re-exports both.
6
+
7
+ /**
8
+ * The English of every `rateLimited` label (0.30.0): "Too many attempts. Try again in
9
+ * 30 s." with a wait under a minute, in whole minutes from one minute up (keksdose's
10
+ * reset throttle answers in hours, and "3600 s" is a number nobody reads), and "Wait a
11
+ * moment and try again." without one — or with a `0`.
12
+ *
13
+ * @internal The namespaces' English; not part of the barrel.
14
+ */
15
+ export function englishRateLimited(seconds?: number): string {
16
+ if (!seconds || seconds <= 0) return "Too many attempts. Wait a moment and try again.";
17
+ return `Too many attempts. Try again in ${englishWait(seconds)}.`;
18
+ }
19
+
20
+ /** "30 s", "2 min" — a wait in English, rounded up. @internal */
21
+ export function englishWait(seconds: number): string {
22
+ return seconds < 60 ? `${Math.ceil(seconds)} s` : `${Math.ceil(seconds / 60)} min`;
23
+ }
@@ -1,3 +1,5 @@
1
+ import { httpStatusOf } from "../lib/http-status";
2
+
1
3
  /**
2
4
  * The coded refusals of sign-in and sign-up (docs/auth-harmonization.md §5.2): every
3
5
  * refusal the auth routes answer carries a machine-readable `code`, and the pages
@@ -274,29 +276,13 @@ export function errorBodyWithCode(
274
276
  return undefined;
275
277
  }
276
278
 
277
- /** An HTTP status as a number, or undefined. */
278
- function statusOf(value: unknown): number | undefined {
279
- return typeof value === "number" && Number.isInteger(value) ? value : undefined;
280
- }
281
-
282
279
  /**
283
- * The HTTP status a thrown error carries, wherever the apps' HTTP clients put it —
284
- * without depending on any of them:
285
- *
286
- * 1. `err.response.status` — axios (all three apps' clients);
287
- * 2. `err.status` — ofetch's `FetchError`, the generated OpenAPI clients' `ApiError`, and
288
- * a `Response` thrown as it came;
289
- * 3. `err.statusCode` — ofetch's alias, and Node-style errors.
290
- *
291
- * `undefined` when none is a whole number. Package-private — not re-exported from the
292
- * barrel; {@link isRateLimited} and the session refresh's classifier read it (DUP-11,
293
- * refactor audit 2026-10: the refresh carried its own copy of this probe).
280
+ * The HTTP status a thrown error carries ({@link httpStatusOf}): axios'
281
+ * `response.status`, then `status`, then `statusCode`. Lives in `lib/http-status.ts`
282
+ * since 0.52 (refactor audit 2026-10-30, MOD-6); re-exported here for the modules that
283
+ * import it from auth. Package-private — not re-exported from the barrel.
294
284
  */
295
- export function httpStatusOf(err: unknown): number | undefined {
296
- if (!isBag(err)) return undefined;
297
- const response = err.response;
298
- return (isBag(response) ? statusOf(response.status) : undefined) ?? statusOf(err.status) ?? statusOf(err.statusCode);
299
- }
285
+ export { httpStatusOf };
300
286
 
301
287
  /**
302
288
  * Whether `err` is a throttled request — HTTP `429 Too Many Requests` (0.30.0, from the
@@ -378,20 +364,7 @@ export function retryAfterSeconds(err: unknown, now: number | Date = Date.now())
378
364
  return value === undefined ? undefined : parseRetryAfter(value, at);
379
365
  }
380
366
 
381
- /**
382
- * The English of every `rateLimited` label (0.30.0): "Too many attempts. Try again in
383
- * 30 s." with a wait under a minute, in whole minutes from one minute up (keksdose's
384
- * reset throttle answers in hours, and "3600 s" is a number nobody reads), and "Wait a
385
- * moment and try again." without one — or with a `0`.
386
- *
387
- * @internal The namespaces' English; not part of the barrel.
388
- */
389
- export function englishRateLimited(seconds?: number): string {
390
- if (!seconds || seconds <= 0) return "Too many attempts. Wait a moment and try again.";
391
- return `Too many attempts. Try again in ${englishWait(seconds)}.`;
392
- }
393
-
394
- /** "30 s", "2 min" — a wait in English, rounded up. @internal */
395
- export function englishWait(seconds: number): string {
396
- return seconds < 60 ? `${Math.ceil(seconds)} s` : `${Math.ceil(seconds / 60)} min`;
397
- }
367
+ // The English of the `rateLimited` labels, in auth-errors-labels since 0.52: the English
368
+ // catalogue reached this module for them, and with it `lib/http-status` (refactor audit
369
+ // 2026-10-30, MOD-6). Re-exported for the modules that import them from here.
370
+ export { englishRateLimited, englishWait } from "./auth-errors-labels";
@@ -2,6 +2,7 @@ import { useContext, useEffect, useId, useRef, useState } from "react";
2
2
  import type { ReactNode } from "react";
3
3
 
4
4
  import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
5
+ import { describeFailure } from "../lib/describe-failure";
5
6
  import { usePromisePending } from "../components/danger-confirm";
6
7
  import { DialogFrame } from "../components/dialog-frame";
7
8
  import { ModalCloseContext } from "../components/modal";
@@ -153,7 +154,9 @@ export function CompleteNameDialog({
153
154
  setFailed(false);
154
155
  };
155
156
 
156
- const message = failed ? (error ?? labels.failed) : undefined;
157
+ // An app's `failed && words` before it has words is `false`, which `??` kept (refactor
158
+ // audit 2026-10-30, DUP-14): the kit's sentence unless the app's says something.
159
+ const message = failed ? describeFailure(error, labels.failed) : undefined;
157
160
 
158
161
  return (
159
162
  <DialogFrame
@@ -3,7 +3,7 @@
3
3
  // loads as one chunk like the other languages (0.34, KS U8). ./forgot-password-form
4
4
  // re-exports them.
5
5
 
6
- import { englishRateLimited } from "./auth-errors";
6
+ import { englishRateLimited } from "./auth-errors-labels";
7
7
  import type { ForgotPasswordLabels } from "./forgot-password-form";
8
8
 
9
9
  /** `Required`: every key, the 0.30 one included, has its English here. */
@@ -2,13 +2,15 @@ import { useId, useRef, useState } from "react";
2
2
  import type { ComponentPropsWithRef, FormEvent, ReactNode } from "react";
3
3
  import { MailCheck } from "lucide-react";
4
4
  import { cn } from "../lib/cn";
5
+ import { describeFailure } from "../lib/describe-failure";
5
6
  import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
6
7
  import { AlertBanner } from "../components/alert-banner";
7
8
  import { TextLink } from "../components/text-link";
8
9
  import { Button } from "../components/button";
9
10
  import { Input } from "../components/input";
10
11
  import { isRateLimited, retryAfterSeconds } from "./auth-errors";
11
- import { FORM_HEADING_CLASS, INTRO_CLASS, OutcomeMessage, isThenable, useFocusWhen } from "./status-parts";
12
+ import { isThenable } from "../lib/thenable";
13
+ import { FORM_HEADING_CLASS, INTRO_CLASS, OutcomeMessage, useFocusWhen } from "./status-parts";
12
14
  import type { AuthHeadingLevel } from "./status-parts";
13
15
  import { DEFAULT_FORGOT_PASSWORD_LABELS } from "./forgot-password-form-labels";
14
16
 
@@ -146,12 +148,15 @@ export function ForgotPasswordForm({
146
148
  );
147
149
  }
148
150
 
149
- // The app's words first, then the throttle's, then the kit's catch-all.
151
+ // The app's words first, then the throttle's, then the kit's catch-all — an app's ""
152
+ // is no words (refactor audit 2026-10-30, DUP-14: `??` drew an empty alert).
150
153
  const failureFor = (error: unknown): ReactNode =>
151
- describeError?.(error) ??
152
- (isRateLimited(error)
153
- ? (labels.rateLimited ?? DEFAULT_FORGOT_PASSWORD_LABELS.rateLimited)(retryAfterSeconds(error))
154
- : labels.error);
154
+ describeFailure(
155
+ describeError?.(error),
156
+ isRateLimited(error)
157
+ ? (labels.rateLimited ?? DEFAULT_FORGOT_PASSWORD_LABELS.rateLimited)(retryAfterSeconds(error))
158
+ : labels.error,
159
+ );
155
160
 
156
161
  const submit = (e: FormEvent) => {
157
162
  e.preventDefault();