@eifi1/ui-kit 0.54.0 → 0.55.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 (847) hide show
  1. package/README.md +90 -76
  2. package/dist/admin/plan-change.js +2 -2
  3. package/dist/admin/plan-change.js.map +1 -1
  4. package/dist/admin/user-roster.d.ts +6 -0
  5. package/dist/admin/user-roster.js +4 -0
  6. package/dist/admin/user-roster.js.map +1 -1
  7. package/dist/billing/billing-labels.d.ts +26 -0
  8. package/dist/billing/billing-labels.js +9 -0
  9. package/dist/billing/billing-labels.js.map +1 -1
  10. package/dist/billing/subscription-standing.d.ts +61 -0
  11. package/dist/billing/subscription-standing.js +51 -0
  12. package/dist/billing/subscription-standing.js.map +1 -0
  13. package/dist/billing/usage-meter.d.ts +52 -0
  14. package/dist/billing/usage-meter.js +52 -0
  15. package/dist/billing/usage-meter.js.map +1 -0
  16. package/dist/chart.d.ts +1 -0
  17. package/dist/chart.js +4 -0
  18. package/dist/chart.js.map +1 -1
  19. package/dist/components/alert-banner.js +2 -3
  20. package/dist/components/alert-banner.js.map +1 -1
  21. package/dist/components/amount-input.js +3 -15
  22. package/dist/components/amount-input.js.map +1 -1
  23. package/dist/components/autocomplete.js +2 -2
  24. package/dist/components/autocomplete.js.map +1 -1
  25. package/dist/components/bulk-action-bar.js +2 -1
  26. package/dist/components/bulk-action-bar.js.map +1 -1
  27. package/dist/components/button.d.ts +35 -1
  28. package/dist/components/button.js +5 -9
  29. package/dist/components/button.js.map +1 -1
  30. package/dist/components/calendar-heatmap.js +2 -2
  31. package/dist/components/calendar-heatmap.js.map +1 -1
  32. package/dist/components/camera-button.d.ts +89 -0
  33. package/dist/components/camera-button.js +122 -0
  34. package/dist/components/camera-button.js.map +1 -0
  35. package/dist/components/camera-capture.d.ts +66 -0
  36. package/dist/components/camera-capture.js +190 -0
  37. package/dist/components/camera-capture.js.map +1 -0
  38. package/dist/components/camera-labels.d.ts +20 -0
  39. package/dist/components/camera-labels.js +15 -0
  40. package/dist/components/camera-labels.js.map +1 -0
  41. package/dist/components/chart-edge.d.ts +9 -0
  42. package/dist/components/chart-edge.js +14 -3
  43. package/dist/components/chart-edge.js.map +1 -1
  44. package/dist/components/chart-zoom-core.js +34 -29
  45. package/dist/components/chart-zoom-core.js.map +1 -1
  46. package/dist/components/checkbox-group.js +1 -1
  47. package/dist/components/checkbox-group.js.map +1 -1
  48. package/dist/components/combobox-core.js +3 -2
  49. package/dist/components/combobox-core.js.map +1 -1
  50. package/dist/components/combobox.js +2 -2
  51. package/dist/components/combobox.js.map +1 -1
  52. package/dist/components/consent-again-notice-labels.d.ts +25 -0
  53. package/dist/components/consent-again-notice-labels.js +15 -0
  54. package/dist/components/consent-again-notice-labels.js.map +1 -0
  55. package/dist/components/consent-again-notice.d.ts +85 -0
  56. package/dist/components/consent-again-notice.js +94 -0
  57. package/dist/components/consent-again-notice.js.map +1 -0
  58. package/dist/components/country-select.js +2 -7
  59. package/dist/components/country-select.js.map +1 -1
  60. package/dist/components/currency-select.js +2 -2
  61. package/dist/components/currency-select.js.map +1 -1
  62. package/dist/components/danger-confirm.js +2 -2
  63. package/dist/components/danger-confirm.js.map +1 -1
  64. package/dist/components/data-table-column-settings.js +2 -2
  65. package/dist/components/data-table-column-settings.js.map +1 -1
  66. package/dist/components/data-table-fit.js.map +1 -1
  67. package/dist/components/data-table-virtual.js +13 -3
  68. package/dist/components/data-table-virtual.js.map +1 -1
  69. package/dist/components/date-field.js +2 -2
  70. package/dist/components/date-field.js.map +1 -1
  71. package/dist/components/date-picker.js +2 -2
  72. package/dist/components/date-picker.js.map +1 -1
  73. package/dist/components/date-range-picker.js +2 -6
  74. package/dist/components/date-range-picker.js.map +1 -1
  75. package/dist/components/dialog-frame.d.ts +3 -1
  76. package/dist/components/dialog-frame.js.map +1 -1
  77. package/dist/components/dropdown.js +7 -3
  78. package/dist/components/dropdown.js.map +1 -1
  79. package/dist/components/entity-combobox.js +2 -2
  80. package/dist/components/entity-combobox.js.map +1 -1
  81. package/dist/components/field-parts.d.ts +108 -6
  82. package/dist/components/field-parts.js +59 -6
  83. package/dist/components/field-parts.js.map +1 -1
  84. package/dist/components/field-suggestion-labels.d.ts +2 -0
  85. package/dist/components/field-suggestion-labels.js +10 -0
  86. package/dist/components/field-suggestion-labels.js.map +1 -0
  87. package/dist/components/field.js +1 -1
  88. package/dist/components/field.js.map +1 -1
  89. package/dist/components/file-button.d.ts +1 -1
  90. package/dist/components/file-button.js.map +1 -1
  91. package/dist/components/floating-panel.d.ts +7 -6
  92. package/dist/components/floating-panel.js +3 -17
  93. package/dist/components/floating-panel.js.map +1 -1
  94. package/dist/components/form-actions.d.ts +3 -2
  95. package/dist/components/form-actions.js.map +1 -1
  96. package/dist/components/hover-menu.js +3 -2
  97. package/dist/components/hover-menu.js.map +1 -1
  98. package/dist/components/icon-button.d.ts +23 -5
  99. package/dist/components/icon-button.js +6 -8
  100. package/dist/components/icon-button.js.map +1 -1
  101. package/dist/components/inline-confirm.js +2 -1
  102. package/dist/components/inline-confirm.js.map +1 -1
  103. package/dist/components/inline-entity-combobox.js +2 -2
  104. package/dist/components/inline-entity-combobox.js.map +1 -1
  105. package/dist/components/input.js +2 -2
  106. package/dist/components/input.js.map +1 -1
  107. package/dist/components/jump-calendar.js +3 -3
  108. package/dist/components/jump-calendar.js.map +1 -1
  109. package/dist/components/legal.d.ts +13 -1
  110. package/dist/components/legal.js +12 -0
  111. package/dist/components/legal.js.map +1 -1
  112. package/dist/components/legended-series-chart.d.ts +80 -0
  113. package/dist/components/legended-series-chart.js +70 -0
  114. package/dist/components/legended-series-chart.js.map +1 -0
  115. package/dist/components/lightbox.js +2 -1
  116. package/dist/components/lightbox.js.map +1 -1
  117. package/dist/components/mini-calendar.js +13 -5
  118. package/dist/components/mini-calendar.js.map +1 -1
  119. package/dist/components/modal.d.ts +23 -2
  120. package/dist/components/modal.js +24 -6
  121. package/dist/components/modal.js.map +1 -1
  122. package/dist/components/month-picker.d.ts +1 -1
  123. package/dist/components/month-picker.js +6 -6
  124. package/dist/components/month-picker.js.map +1 -1
  125. package/dist/components/multi-entity-combobox.js +2 -2
  126. package/dist/components/multi-entity-combobox.js.map +1 -1
  127. package/dist/components/multi-select.js +2 -6
  128. package/dist/components/multi-select.js.map +1 -1
  129. package/dist/components/number-input.js +2 -2
  130. package/dist/components/number-input.js.map +1 -1
  131. package/dist/components/page-header-layout.d.ts +18 -0
  132. package/dist/components/page-header-layout.js +23 -0
  133. package/dist/components/page-header-layout.js.map +1 -0
  134. package/dist/components/page-header-skeleton.d.ts +41 -0
  135. package/dist/components/page-header-skeleton.js +52 -0
  136. package/dist/components/page-header-skeleton.js.map +1 -0
  137. package/dist/components/page-header.js +4 -17
  138. package/dist/components/page-header.js.map +1 -1
  139. package/dist/components/popover.js +7 -2
  140. package/dist/components/popover.js.map +1 -1
  141. package/dist/components/release-notes-labels.d.ts +16 -0
  142. package/dist/components/release-notes-labels.js +18 -0
  143. package/dist/components/release-notes-labels.js.map +1 -0
  144. package/dist/components/release-notes.d.ts +65 -0
  145. package/dist/components/release-notes.js +65 -0
  146. package/dist/components/release-notes.js.map +1 -0
  147. package/dist/components/select.js +2 -2
  148. package/dist/components/select.js.map +1 -1
  149. package/dist/components/series-chart-labels.d.ts +9 -0
  150. package/dist/components/series-chart-labels.js +3 -1
  151. package/dist/components/series-chart-labels.js.map +1 -1
  152. package/dist/components/series-chart.d.ts +5 -0
  153. package/dist/components/series-chart.js +89 -36
  154. package/dist/components/series-chart.js.map +1 -1
  155. package/dist/components/toggle-group.js +3 -2
  156. package/dist/components/toggle-group.js.map +1 -1
  157. package/dist/components/treemap-layout.js.map +1 -1
  158. package/dist/components/treemap.d.ts +17 -15
  159. package/dist/components/treemap.js +167 -85
  160. package/dist/components/treemap.js.map +1 -1
  161. package/dist/eslint/index.js +1 -1
  162. package/dist/eslint/role-utilities.d.ts +2 -2
  163. package/dist/eslint/role-utilities.js.map +1 -1
  164. package/dist/feedback/feedback-inbox-page.d.ts +260 -0
  165. package/dist/feedback/feedback-inbox-page.js +207 -0
  166. package/dist/feedback/feedback-inbox-page.js.map +1 -0
  167. package/dist/feedback/feedback-vocabulary.js +2 -2
  168. package/dist/feedback/feedback-vocabulary.js.map +1 -1
  169. package/dist/feedback.d.ts +1 -0
  170. package/dist/feedback.js +6 -0
  171. package/dist/feedback.js.map +1 -1
  172. package/dist/hooks/use-debounce.d.ts +32 -5
  173. package/dist/hooks/use-debounce.js +6 -5
  174. package/dist/hooks/use-debounce.js.map +1 -1
  175. package/dist/hooks/use-file-picker.d.ts +3 -1
  176. package/dist/hooks/use-file-picker.js.map +1 -1
  177. package/dist/hooks/use-focus-trap.d.ts +19 -3
  178. package/dist/hooks/use-focus-trap.js +15 -5
  179. package/dist/hooks/use-focus-trap.js.map +1 -1
  180. package/dist/hooks/use-has-camera.d.ts +36 -0
  181. package/dist/hooks/use-has-camera.js +53 -0
  182. package/dist/hooks/use-has-camera.js.map +1 -0
  183. package/dist/hooks/use-hotkey.js +1 -10
  184. package/dist/hooks/use-hotkey.js.map +1 -1
  185. package/dist/hooks/use-overlay-history.d.ts +6 -1
  186. package/dist/hooks/use-overlay-history.js +10 -2
  187. package/dist/hooks/use-overlay-history.js.map +1 -1
  188. package/dist/i18n/defaults.js +11 -1
  189. package/dist/i18n/defaults.js.map +1 -1
  190. package/dist/i18n/german.js +75 -3
  191. package/dist/i18n/german.js.map +1 -1
  192. package/dist/i18n/kit-labels.d.ts +20 -0
  193. package/dist/i18n/kit-labels.js.map +1 -1
  194. package/dist/i18n/locales/en.js +92 -4
  195. package/dist/i18n/locales/en.js.map +3 -3
  196. package/dist/i18n/locales/es.js +71 -3
  197. package/dist/i18n/locales/es.js.map +1 -1
  198. package/dist/i18n/locales/fr.js +72 -2
  199. package/dist/i18n/locales/fr.js.map +1 -1
  200. package/dist/i18n/locales/hu.js +74 -3
  201. package/dist/i18n/locales/hu.js.map +1 -1
  202. package/dist/i18n/locales/it.js +74 -3
  203. package/dist/i18n/locales/it.js.map +1 -1
  204. package/dist/i18n/locales/zh.js +71 -3
  205. package/dist/i18n/locales/zh.js.map +1 -1
  206. package/dist/i18n/review.js +22 -1
  207. package/dist/i18n/review.js.map +1 -1
  208. package/dist/index.d.ts +24 -5
  209. package/dist/index.js +35 -1
  210. package/dist/index.js.map +1 -1
  211. package/dist/landing/landing-labels.d.ts +8 -0
  212. package/dist/landing/landing-labels.js +2 -1
  213. package/dist/landing/landing-labels.js.map +1 -1
  214. package/dist/lib/changelog.d.ts +130 -0
  215. package/dist/lib/changelog.js +137 -0
  216. package/dist/lib/changelog.js.map +1 -0
  217. package/dist/lib/clipboard-minus.js +2 -2
  218. package/dist/lib/clipboard-minus.js.map +1 -1
  219. package/dist/lib/dates.d.ts +29 -3
  220. package/dist/lib/dates.js +41 -12
  221. package/dist/lib/dates.js.map +1 -1
  222. package/dist/lib/editable-content.d.ts +33 -0
  223. package/dist/lib/editable-content.js +15 -0
  224. package/dist/lib/editable-content.js.map +1 -0
  225. package/dist/lib/focus-left.d.ts +47 -1
  226. package/dist/lib/focus-left.js +11 -2
  227. package/dist/lib/focus-left.js.map +1 -1
  228. package/dist/lib/server-wake.d.ts +49 -9
  229. package/dist/lib/server-wake.js +25 -14
  230. package/dist/lib/server-wake.js.map +1 -1
  231. package/dist/lib/session-refresh.d.ts +53 -0
  232. package/dist/lib/session-refresh.js +27 -1
  233. package/dist/lib/session-refresh.js.map +1 -1
  234. package/dist/rhf/fields.js +3 -3
  235. package/dist/rhf/fields.js.map +1 -1
  236. package/dist/shell/app-shell.d.ts +25 -1
  237. package/dist/shell/app-shell.js +3 -1
  238. package/dist/shell/app-shell.js.map +1 -1
  239. package/dist/shell/dev-menu.d.ts +3 -0
  240. package/dist/shell/dev-menu.js +4 -2
  241. package/dist/shell/dev-menu.js.map +1 -1
  242. package/dist/shell/held-changes-banner-labels.d.ts +23 -0
  243. package/dist/shell/held-changes-banner-labels.js +14 -0
  244. package/dist/shell/held-changes-banner-labels.js.map +1 -0
  245. package/dist/shell/held-changes-banner.d.ts +75 -0
  246. package/dist/shell/held-changes-banner.js +106 -0
  247. package/dist/shell/held-changes-banner.js.map +1 -0
  248. package/dist/shell/sync-status-indicator.d.ts +27 -12
  249. package/dist/shell/sync-status-indicator.js +13 -4
  250. package/dist/shell/sync-status-indicator.js.map +1 -1
  251. package/dist/shell/top-bar-parts-labels.d.ts +5 -0
  252. package/dist/shell/top-bar-parts-labels.js +3 -1
  253. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  254. package/dist/shell.d.ts +2 -0
  255. package/dist/shell.js +3 -0
  256. package/dist/shell.js.map +1 -1
  257. package/dist/sync/engine.d.ts +11 -2
  258. package/dist/sync/engine.js +13 -5
  259. package/dist/sync/engine.js.map +1 -1
  260. package/dist/sync/hooks.d.ts +3 -2
  261. package/dist/sync/hooks.js +4 -2
  262. package/dist/sync/hooks.js.map +1 -1
  263. package/dist/testing/css-variables.generated.d.ts +2 -2
  264. package/dist/testing/css-variables.generated.js +1 -1
  265. package/dist/testing/css-variables.generated.js.map +1 -1
  266. package/dist/theme/chart-palette.d.ts +18 -0
  267. package/dist/theme/chart-palette.js +17 -1
  268. package/dist/theme/chart-palette.js.map +1 -1
  269. package/dist/theme/contrast-tokens.d.ts +3 -3
  270. package/dist/theme/contrast-tokens.js.map +1 -1
  271. package/dist/theme/contrast.d.ts +4 -4
  272. package/dist/theme/contrast.js.map +1 -1
  273. package/dist/tour/tour-overlay.js +2 -1
  274. package/dist/tour/tour-overlay.js.map +1 -1
  275. package/package.json +5 -9
  276. package/tokens.css +19 -54
  277. package/src/account/account-parts.ts +0 -47
  278. package/src/account/account-settings-labels.ts +0 -240
  279. package/src/account/account-settings.tsx +0 -698
  280. package/src/account/data-export-setting-labels.ts +0 -20
  281. package/src/account/data-export-setting.tsx +0 -200
  282. package/src/account/delete-account-setting-labels.ts +0 -33
  283. package/src/account/delete-account-setting.tsx +0 -342
  284. package/src/account/email-change-setting-labels.ts +0 -31
  285. package/src/account/email-change-setting.tsx +0 -443
  286. package/src/account/passkeys-setting.tsx +0 -445
  287. package/src/account/sessions-setting-labels.ts +0 -24
  288. package/src/account/sessions-setting.tsx +0 -283
  289. package/src/admin/admin-action-confirm-labels.ts +0 -19
  290. package/src/admin/admin-action-confirm.tsx +0 -509
  291. package/src/admin/admin-action-log-labels.ts +0 -83
  292. package/src/admin/admin-action-log.tsx +0 -464
  293. package/src/admin/admin-area-labels.ts +0 -114
  294. package/src/admin/admin-forbidden.tsx +0 -75
  295. package/src/admin/admin-overview.tsx +0 -258
  296. package/src/admin/admin-parts.ts +0 -68
  297. package/src/admin/admin-sections.tsx +0 -208
  298. package/src/admin/admin-tool-links.tsx +0 -90
  299. package/src/admin/invitations-panel-labels.ts +0 -31
  300. package/src/admin/invitations-panel.tsx +0 -516
  301. package/src/admin/mail-test-card-labels.ts +0 -19
  302. package/src/admin/mail-test-card.tsx +0 -189
  303. package/src/admin/plan-change-labels.ts +0 -5
  304. package/src/admin/plan-change.tsx +0 -474
  305. package/src/admin/reviewer-scope-editor-labels.ts +0 -16
  306. package/src/admin/reviewer-scope-editor.tsx +0 -224
  307. package/src/admin/role-select-labels.ts +0 -16
  308. package/src/admin/role-select.tsx +0 -282
  309. package/src/admin/transfer-ownership-dialog-labels.ts +0 -20
  310. package/src/admin/transfer-ownership-dialog.tsx +0 -162
  311. package/src/admin/user-roster-labels.ts +0 -17
  312. package/src/admin/user-roster.tsx +0 -559
  313. package/src/auth/accept-invitation-labels.ts +0 -21
  314. package/src/auth/accept-invitation.tsx +0 -210
  315. package/src/auth/auth-errors-labels.ts +0 -23
  316. package/src/auth/auth-errors.ts +0 -439
  317. package/src/auth/complete-name-dialog-labels.ts +0 -16
  318. package/src/auth/complete-name-dialog.tsx +0 -253
  319. package/src/auth/email-tag.ts +0 -75
  320. package/src/auth/forgot-password-form-labels.ts +0 -20
  321. package/src/auth/forgot-password-form.tsx +0 -221
  322. package/src/auth/form-rules.ts +0 -40
  323. package/src/auth/new-password-fields.tsx +0 -85
  324. package/src/auth/not-found-page-labels.ts +0 -12
  325. package/src/auth/not-found-page.tsx +0 -95
  326. package/src/auth/register-form-labels.ts +0 -31
  327. package/src/auth/register-form.tsx +0 -456
  328. package/src/auth/reset-password-form-labels.ts +0 -27
  329. package/src/auth/reset-password-form.tsx +0 -341
  330. package/src/auth/sign-in-form-labels.ts +0 -44
  331. package/src/auth/sign-in-form.tsx +0 -858
  332. package/src/auth/status-parts.tsx +0 -132
  333. package/src/auth/verify-email-labels.ts +0 -26
  334. package/src/auth/verify-email.tsx +0 -445
  335. package/src/billing/billing-banner.tsx +0 -258
  336. package/src/billing/billing-labels.ts +0 -381
  337. package/src/billing/billing-lock.ts +0 -108
  338. package/src/billing/billing-overview.ts +0 -157
  339. package/src/billing/billing-standing.ts +0 -80
  340. package/src/billing/cancel-request.ts +0 -97
  341. package/src/billing/cancel-subscription.tsx +0 -98
  342. package/src/billing/checkout-processing.ts +0 -394
  343. package/src/billing/checkout-return.ts +0 -90
  344. package/src/billing/pay-page.ts +0 -330
  345. package/src/billing/plan-card.tsx +0 -562
  346. package/src/billing/plan-change-labels.ts +0 -66
  347. package/src/billing/plan-limit-notice.tsx +0 -148
  348. package/src/billing/plan-limit-toast.tsx +0 -90
  349. package/src/billing/plan-limit.ts +0 -52
  350. package/src/billing/plan-price.ts +0 -98
  351. package/src/billing/plan-switch.tsx +0 -216
  352. package/src/billing/provider-page.ts +0 -84
  353. package/src/billing/subscription-actions.tsx +0 -247
  354. package/src/billing/subscription-status-chip.tsx +0 -95
  355. package/src/chart.ts +0 -103
  356. package/src/components/account-chips-labels.ts +0 -16
  357. package/src/components/account-chips.tsx +0 -474
  358. package/src/components/alert-banner.tsx +0 -670
  359. package/src/components/amount-input.tsx +0 -816
  360. package/src/components/appearance-labels.ts +0 -63
  361. package/src/components/authed-image-labels.ts +0 -11
  362. package/src/components/authed-image.tsx +0 -209
  363. package/src/components/autocomplete.tsx +0 -645
  364. package/src/components/breadcrumbs-labels.ts +0 -10
  365. package/src/components/breadcrumbs.tsx +0 -205
  366. package/src/components/bulk-action-bar-labels.ts +0 -11
  367. package/src/components/bulk-action-bar.tsx +0 -443
  368. package/src/components/button-group.tsx +0 -223
  369. package/src/components/button-look.ts +0 -256
  370. package/src/components/button.tsx +0 -339
  371. package/src/components/calculator.tsx +0 -341
  372. package/src/components/calendar-heatmap-labels.ts +0 -15
  373. package/src/components/calendar-heatmap.tsx +0 -600
  374. package/src/components/card.tsx +0 -377
  375. package/src/components/chart-edge.ts +0 -106
  376. package/src/components/chart-figure.tsx +0 -35
  377. package/src/components/chart-height.ts +0 -30
  378. package/src/components/chart-zoom-core.tsx +0 -627
  379. package/src/components/chart-zoom.tsx +0 -22
  380. package/src/components/chart.tsx +0 -554
  381. package/src/components/checkbox-group.tsx +0 -247
  382. package/src/components/checkbox.tsx +0 -346
  383. package/src/components/chip-input.tsx +0 -370
  384. package/src/components/chip-labels.ts +0 -13
  385. package/src/components/chip.tsx +0 -843
  386. package/src/components/choice-card.tsx +0 -544
  387. package/src/components/column-mapper-labels.ts +0 -38
  388. package/src/components/column-mapper.tsx +0 -655
  389. package/src/components/combobox-core.tsx +0 -1321
  390. package/src/components/combobox-suggestions.tsx +0 -131
  391. package/src/components/combobox.tsx +0 -716
  392. package/src/components/confirm-context.ts +0 -7
  393. package/src/components/confirm-dialog-labels.ts +0 -13
  394. package/src/components/confirm-dialog.tsx +0 -341
  395. package/src/components/copy-button-labels.ts +0 -13
  396. package/src/components/copy-button.tsx +0 -192
  397. package/src/components/country-select-labels.ts +0 -11
  398. package/src/components/country-select.tsx +0 -539
  399. package/src/components/currency-option-list.tsx +0 -188
  400. package/src/components/currency-select.tsx +0 -343
  401. package/src/components/danger-confirm-labels.ts +0 -20
  402. package/src/components/danger-confirm.tsx +0 -987
  403. package/src/components/data-table-cells.tsx +0 -118
  404. package/src/components/data-table-column-settings.tsx +0 -198
  405. package/src/components/data-table-filter-popover.tsx +0 -289
  406. package/src/components/data-table-filters.ts +0 -315
  407. package/src/components/data-table-fit.ts +0 -301
  408. package/src/components/data-table-groups.tsx +0 -288
  409. package/src/components/data-table-head.tsx +0 -280
  410. package/src/components/data-table-labels.ts +0 -198
  411. package/src/components/data-table-leading-row.tsx +0 -58
  412. package/src/components/data-table-mobile.tsx +0 -1117
  413. package/src/components/data-table-pagination.tsx +0 -202
  414. package/src/components/data-table-resize.ts +0 -188
  415. package/src/components/data-table-row-actions.tsx +0 -302
  416. package/src/components/data-table-row.tsx +0 -496
  417. package/src/components/data-table-selection.ts +0 -71
  418. package/src/components/data-table-shared.tsx +0 -287
  419. package/src/components/data-table-sort.ts +0 -163
  420. package/src/components/data-table-virtual.ts +0 -576
  421. package/src/components/data-table.tsx +0 -2598
  422. package/src/components/date-field.tsx +0 -684
  423. package/src/components/date-format-setting.tsx +0 -64
  424. package/src/components/date-picker.tsx +0 -404
  425. package/src/components/date-range-picker.tsx +0 -518
  426. package/src/components/description-list-labels.ts +0 -9
  427. package/src/components/description-list.tsx +0 -386
  428. package/src/components/dialog-frame-labels.ts +0 -7
  429. package/src/components/dialog-frame.tsx +0 -284
  430. package/src/components/disclosure.tsx +0 -476
  431. package/src/components/dropdown.tsx +0 -461
  432. package/src/components/empty-state.tsx +0 -136
  433. package/src/components/entity-combobox.tsx +0 -422
  434. package/src/components/error-boundary-labels.ts +0 -20
  435. package/src/components/error-boundary.tsx +0 -675
  436. package/src/components/facing-pair.ts +0 -93
  437. package/src/components/field-base-labels.ts +0 -20
  438. package/src/components/field-base.tsx +0 -656
  439. package/src/components/field-parts.tsx +0 -825
  440. package/src/components/field-strip.tsx +0 -129
  441. package/src/components/field.tsx +0 -206
  442. package/src/components/file-button.tsx +0 -295
  443. package/src/components/file-dropzone.tsx +0 -559
  444. package/src/components/floating-panel-labels.ts +0 -10
  445. package/src/components/floating-panel.tsx +0 -828
  446. package/src/components/focus-ring.ts +0 -16
  447. package/src/components/form-actions-labels.ts +0 -11
  448. package/src/components/form-actions.tsx +0 -578
  449. package/src/components/full-bleed-dialog.tsx +0 -294
  450. package/src/components/grouped-picker.tsx +0 -184
  451. package/src/components/help-popover.tsx +0 -117
  452. package/src/components/hover-menu.tsx +0 -343
  453. package/src/components/iban-input-labels.ts +0 -14
  454. package/src/components/iban-input.tsx +0 -236
  455. package/src/components/icon-button.tsx +0 -959
  456. package/src/components/icon-picker-labels.ts +0 -13
  457. package/src/components/icon-picker.tsx +0 -232
  458. package/src/components/image-grid-labels.ts +0 -11
  459. package/src/components/image-grid.tsx +0 -202
  460. package/src/components/inline-confirm.tsx +0 -116
  461. package/src/components/inline-edit-field-labels.ts +0 -11
  462. package/src/components/inline-edit-field.tsx +0 -552
  463. package/src/components/inline-entity-combobox.tsx +0 -849
  464. package/src/components/input.tsx +0 -394
  465. package/src/components/jump-calendar.tsx +0 -265
  466. package/src/components/language-select.tsx +0 -93
  467. package/src/components/legal-labels.ts +0 -105
  468. package/src/components/legal-page.tsx +0 -711
  469. package/src/components/legal.tsx +0 -668
  470. package/src/components/lightbox-labels.ts +0 -18
  471. package/src/components/lightbox.tsx +0 -399
  472. package/src/components/line-items-labels.ts +0 -14
  473. package/src/components/line-items.tsx +0 -602
  474. package/src/components/list-labels.ts +0 -12
  475. package/src/components/list.tsx +0 -870
  476. package/src/components/loading-state.tsx +0 -78
  477. package/src/components/measured-grid-labels.ts +0 -25
  478. package/src/components/measured-grid.tsx +0 -837
  479. package/src/components/menu-item.tsx +0 -241
  480. package/src/components/mini-calendar-labels.ts +0 -17
  481. package/src/components/mini-calendar.tsx +0 -792
  482. package/src/components/modal.tsx +0 -534
  483. package/src/components/money-draft.ts +0 -83
  484. package/src/components/money-field.tsx +0 -76
  485. package/src/components/month-grid.tsx +0 -229
  486. package/src/components/month-picker-labels.ts +0 -22
  487. package/src/components/month-picker.tsx +0 -1087
  488. package/src/components/multi-entity-combobox.tsx +0 -369
  489. package/src/components/multi-select.tsx +0 -376
  490. package/src/components/nav-pills.tsx +0 -198
  491. package/src/components/number-field.tsx +0 -327
  492. package/src/components/number-input.tsx +0 -559
  493. package/src/components/numeric-field.ts +0 -169
  494. package/src/components/numpad-sheet.tsx +0 -285
  495. package/src/components/one-time-code-input.tsx +0 -270
  496. package/src/components/page-contents-labels.ts +0 -9
  497. package/src/components/page-contents.tsx +0 -282
  498. package/src/components/page-header-context.ts +0 -8
  499. package/src/components/page-header.tsx +0 -298
  500. package/src/components/password-strength-labels.ts +0 -22
  501. package/src/components/password-strength.tsx +0 -241
  502. package/src/components/phone-input-labels.ts +0 -10
  503. package/src/components/phone-input.tsx +0 -282
  504. package/src/components/picker-sheet.tsx +0 -330
  505. package/src/components/pie-chart-labels.ts +0 -40
  506. package/src/components/pie-chart.tsx +0 -480
  507. package/src/components/popover-labels.ts +0 -14
  508. package/src/components/popover.tsx +0 -268
  509. package/src/components/progress-bar-labels.ts +0 -10
  510. package/src/components/progress-bar.tsx +0 -479
  511. package/src/components/qr-code.tsx +0 -76
  512. package/src/components/reauth-dialog-labels.ts +0 -13
  513. package/src/components/reauth-dialog.tsx +0 -265
  514. package/src/components/row-actions-labels.ts +0 -12
  515. package/src/components/row-actions.tsx +0 -795
  516. package/src/components/scroll-area.tsx +0 -123
  517. package/src/components/search-field.tsx +0 -192
  518. package/src/components/select.tsx +0 -294
  519. package/src/components/separator.tsx +0 -33
  520. package/src/components/series-chart-axes.ts +0 -342
  521. package/src/components/series-chart-budget.ts +0 -150
  522. package/src/components/series-chart-labels.ts +0 -33
  523. package/src/components/series-chart-thin.ts +0 -180
  524. package/src/components/series-chart-ticks.ts +0 -194
  525. package/src/components/series-chart.tsx +0 -1906
  526. package/src/components/server-wake-labels.ts +0 -11
  527. package/src/components/server-wake.tsx +0 -129
  528. package/src/components/settings-fields.tsx +0 -237
  529. package/src/components/share-card-labels.ts +0 -30
  530. package/src/components/share-card.tsx +0 -675
  531. package/src/components/signature-pad-labels.ts +0 -24
  532. package/src/components/signature-pad.tsx +0 -747
  533. package/src/components/signed-amount-labels.ts +0 -10
  534. package/src/components/signed-amount.tsx +0 -336
  535. package/src/components/skeleton.tsx +0 -80
  536. package/src/components/slider.tsx +0 -338
  537. package/src/components/sparkline-labels.ts +0 -14
  538. package/src/components/sparkline.tsx +0 -322
  539. package/src/components/spinner.tsx +0 -81
  540. package/src/components/stat-tile-labels.ts +0 -15
  541. package/src/components/stat-tile.tsx +0 -754
  542. package/src/components/status-dot.tsx +0 -170
  543. package/src/components/swatch-picker-labels.ts +0 -10
  544. package/src/components/swatch-picker.tsx +0 -283
  545. package/src/components/swipeable-row.tsx +0 -386
  546. package/src/components/switch.tsx +0 -273
  547. package/src/components/table-skeleton.tsx +0 -136
  548. package/src/components/table.tsx +0 -647
  549. package/src/components/tabs-labels.ts +0 -13
  550. package/src/components/tabs.tsx +0 -693
  551. package/src/components/text-link.tsx +0 -359
  552. package/src/components/text.tsx +0 -150
  553. package/src/components/textarea.tsx +0 -330
  554. package/src/components/tile-radio.tsx +0 -332
  555. package/src/components/time-input.tsx +0 -121
  556. package/src/components/toast-labels.ts +0 -12
  557. package/src/components/toast.tsx +0 -519
  558. package/src/components/toggle-group.tsx +0 -752
  559. package/src/components/toggle-legend.tsx +0 -394
  560. package/src/components/tooltip.tsx +0 -1149
  561. package/src/components/translation-review-editor.tsx +0 -290
  562. package/src/components/translation-review-labels.ts +0 -181
  563. package/src/components/translation-review-parts.tsx +0 -272
  564. package/src/components/translation-review.tsx +0 -1240
  565. package/src/components/tree-view.tsx +0 -589
  566. package/src/components/treemap-labels.ts +0 -47
  567. package/src/components/treemap-layout.ts +0 -210
  568. package/src/components/treemap.tsx +0 -1184
  569. package/src/components/trigger-aria.ts +0 -44
  570. package/src/components/use-anchor-dir.ts +0 -20
  571. package/src/components/use-mobile-reveal.ts +0 -62
  572. package/src/components/use-table-state.ts +0 -753
  573. package/src/components/user-avatar.tsx +0 -116
  574. package/src/components/wizard-stepper.tsx +0 -42
  575. package/src/components/write-lock-labels.ts +0 -10
  576. package/src/components/write-lock.tsx +0 -253
  577. package/src/currencies.ts +0 -90
  578. package/src/data-table.ts +0 -42
  579. package/src/demo/demo-banner.tsx +0 -153
  580. package/src/demo/demo-countdown.ts +0 -136
  581. package/src/demo/demo-ended.tsx +0 -90
  582. package/src/demo/demo-labels.ts +0 -78
  583. package/src/demo/demo-session.ts +0 -32
  584. package/src/demo/demo-start.tsx +0 -156
  585. package/src/eslint/index.ts +0 -161
  586. package/src/eslint/role-utilities.generated.ts +0 -146
  587. package/src/eslint/role-utilities.ts +0 -233
  588. package/src/feedback/feedback-attachment-download.tsx +0 -77
  589. package/src/feedback/feedback-attachment-labels.ts +0 -37
  590. package/src/feedback/feedback-attachment.tsx +0 -1239
  591. package/src/feedback/feedback-capture.ts +0 -287
  592. package/src/feedback/feedback-comment-thread.tsx +0 -353
  593. package/src/feedback/feedback-context-labels.ts +0 -11
  594. package/src/feedback/feedback-context.tsx +0 -245
  595. package/src/feedback/feedback-crash.ts +0 -547
  596. package/src/feedback/feedback-diagnostics.tsx +0 -41
  597. package/src/feedback/feedback-dialog-labels.ts +0 -29
  598. package/src/feedback/feedback-dialog.tsx +0 -452
  599. package/src/feedback/feedback-entry-file.tsx +0 -150
  600. package/src/feedback/feedback-inbox.tsx +0 -552
  601. package/src/feedback/feedback-labels.ts +0 -144
  602. package/src/feedback/feedback-menu-labels.ts +0 -12
  603. package/src/feedback/feedback-menu.tsx +0 -177
  604. package/src/feedback/feedback-mutation.ts +0 -20
  605. package/src/feedback/feedback-page-link.ts +0 -90
  606. package/src/feedback/feedback-public-labels.ts +0 -81
  607. package/src/feedback/feedback-public-list.tsx +0 -524
  608. package/src/feedback/feedback-public-switch.tsx +0 -102
  609. package/src/feedback/feedback-public-types.ts +0 -101
  610. package/src/feedback/feedback-record.ts +0 -428
  611. package/src/feedback/feedback-replies-context.ts +0 -9
  612. package/src/feedback/feedback-replies.tsx +0 -343
  613. package/src/feedback/feedback-rework-entry-chip.tsx +0 -18
  614. package/src/feedback/feedback-row-detail-labels.ts +0 -31
  615. package/src/feedback/feedback-row-detail.tsx +0 -871
  616. package/src/feedback/feedback-status-undo.ts +0 -109
  617. package/src/feedback/feedback-submit-dialog.tsx +0 -131
  618. package/src/feedback/feedback-submit.tsx +0 -270
  619. package/src/feedback/feedback-swipe.tsx +0 -192
  620. package/src/feedback/feedback-table-labels.ts +0 -27
  621. package/src/feedback/feedback-table.tsx +0 -912
  622. package/src/feedback/feedback-thread-labels.ts +0 -22
  623. package/src/feedback/feedback-thread-parts-labels.ts +0 -41
  624. package/src/feedback/feedback-thread.tsx +0 -905
  625. package/src/feedback/feedback-vocabulary.ts +0 -263
  626. package/src/feedback/feedback-vote-button.tsx +0 -124
  627. package/src/feedback.ts +0 -116
  628. package/src/hooks/use-anchored-panel.ts +0 -396
  629. package/src/hooks/use-anchored-rect.ts +0 -77
  630. package/src/hooks/use-announce.ts +0 -85
  631. package/src/hooks/use-authed-src.ts +0 -167
  632. package/src/hooks/use-body-scroll-lock.ts +0 -119
  633. package/src/hooks/use-breakpoint.ts +0 -133
  634. package/src/hooks/use-close-transition.ts +0 -107
  635. package/src/hooks/use-copy-to-clipboard.ts +0 -122
  636. package/src/hooks/use-debounce.ts +0 -114
  637. package/src/hooks/use-dismiss.ts +0 -371
  638. package/src/hooks/use-document-title.ts +0 -33
  639. package/src/hooks/use-file-drop.ts +0 -121
  640. package/src/hooks/use-file-picker-labels.ts +0 -28
  641. package/src/hooks/use-file-picker.tsx +0 -359
  642. package/src/hooks/use-focus-trap.ts +0 -199
  643. package/src/hooks/use-hotkey.ts +0 -212
  644. package/src/hooks/use-large-text.ts +0 -41
  645. package/src/hooks/use-long-press.ts +0 -140
  646. package/src/hooks/use-media-query.ts +0 -39
  647. package/src/hooks/use-mounted.ts +0 -39
  648. package/src/hooks/use-noindex.ts +0 -37
  649. package/src/hooks/use-overlay-history.ts +0 -714
  650. package/src/hooks/use-row-swipe.ts +0 -207
  651. package/src/hooks/use-search-param-state.ts +0 -434
  652. package/src/hooks/use-windowed-rows.ts +0 -225
  653. package/src/i18n/defaults.ts +0 -267
  654. package/src/i18n/german.ts +0 -2059
  655. package/src/i18n/kit-labels.tsx +0 -1003
  656. package/src/i18n/languages.ts +0 -349
  657. package/src/i18n/locales/de-CH.ts +0 -24
  658. package/src/i18n/locales/en.ts +0 -267
  659. package/src/i18n/locales/es.ts +0 -1999
  660. package/src/i18n/locales/fr.ts +0 -2037
  661. package/src/i18n/locales/hu.ts +0 -2004
  662. package/src/i18n/locales/it.ts +0 -2014
  663. package/src/i18n/locales/zh.ts +0 -1912
  664. package/src/i18n/plurals.ts +0 -86
  665. package/src/i18n/review.ts +0 -475
  666. package/src/i18n/shared-labels.ts +0 -138
  667. package/src/i18n/swiss.ts +0 -29
  668. package/src/index.ts +0 -1191
  669. package/src/landing/access.ts +0 -93
  670. package/src/landing/landing-actions.tsx +0 -97
  671. package/src/landing/landing-labels.ts +0 -59
  672. package/src/landing/landing-sections.tsx +0 -341
  673. package/src/landing/page-seo.ts +0 -261
  674. package/src/landing/public-header.tsx +0 -121
  675. package/src/landing/public-page.tsx +0 -106
  676. package/src/landing/routing.tsx +0 -225
  677. package/src/lib/broadcast.ts +0 -52
  678. package/src/lib/calc.ts +0 -323
  679. package/src/lib/chip-edge-snap.ts +0 -212
  680. package/src/lib/clipboard-minus.ts +0 -107
  681. package/src/lib/clipping.ts +0 -34
  682. package/src/lib/cn.ts +0 -28
  683. package/src/lib/column-mapping.ts +0 -234
  684. package/src/lib/countries.ts +0 -91
  685. package/src/lib/data-attributes.ts +0 -14
  686. package/src/lib/date-format.ts +0 -227
  687. package/src/lib/dates.ts +0 -288
  688. package/src/lib/day-format.ts +0 -96
  689. package/src/lib/decimal-marks.ts +0 -108
  690. package/src/lib/describe-failure.ts +0 -18
  691. package/src/lib/device-settings.ts +0 -147
  692. package/src/lib/direction.ts +0 -74
  693. package/src/lib/document-navigation.ts +0 -17
  694. package/src/lib/document-title.ts +0 -41
  695. package/src/lib/download.ts +0 -172
  696. package/src/lib/float-clearance.ts +0 -70
  697. package/src/lib/floating-stack.ts +0 -70
  698. package/src/lib/focus-left.ts +0 -156
  699. package/src/lib/format.ts +0 -585
  700. package/src/lib/http-status.ts +0 -38
  701. package/src/lib/iban.ts +0 -251
  702. package/src/lib/ime.ts +0 -24
  703. package/src/lib/intl-cache.ts +0 -27
  704. package/src/lib/iso-day.ts +0 -13
  705. package/src/lib/lazy-with-fallback.ts +0 -82
  706. package/src/lib/logger.ts +0 -69
  707. package/src/lib/minus.ts +0 -50
  708. package/src/lib/path-pattern.ts +0 -55
  709. package/src/lib/person-name.ts +0 -155
  710. package/src/lib/phone.ts +0 -208
  711. package/src/lib/plain-text.ts +0 -22
  712. package/src/lib/presence.ts +0 -18
  713. package/src/lib/qr-encode.ts +0 -444
  714. package/src/lib/quiet-focus.ts +0 -32
  715. package/src/lib/reduced-motion.ts +0 -22
  716. package/src/lib/refs.ts +0 -22
  717. package/src/lib/round.ts +0 -43
  718. package/src/lib/safe-storage.ts +0 -119
  719. package/src/lib/server-wake.ts +0 -315
  720. package/src/lib/session-refresh.ts +0 -472
  721. package/src/lib/share-format.ts +0 -18
  722. package/src/lib/status-tone.ts +0 -43
  723. package/src/lib/strip-fade.ts +0 -287
  724. package/src/lib/table-text.ts +0 -554
  725. package/src/lib/text-case.ts +0 -19
  726. package/src/lib/text-match.ts +0 -169
  727. package/src/lib/thenable.ts +0 -19
  728. package/src/lib/translation-review.ts +0 -769
  729. package/src/notifications/device-zone-report.ts +0 -67
  730. package/src/notifications/feedback-notification-types-labels.ts +0 -33
  731. package/src/notifications/feedback-notification-types.ts +0 -71
  732. package/src/notifications/notification-bell.tsx +0 -119
  733. package/src/notifications/notification-inbox.tsx +0 -309
  734. package/src/notifications/notification-parts.tsx +0 -81
  735. package/src/notifications/notification-types-setting.tsx +0 -406
  736. package/src/notifications/notification-types.ts +0 -89
  737. package/src/notifications/notifications-labels.ts +0 -287
  738. package/src/notifications/push-device-setting.tsx +0 -230
  739. package/src/notifications/push-devices-setting.tsx +0 -374
  740. package/src/notifications/push-worker.ts +0 -168
  741. package/src/notifications/quiet-hours-setting.tsx +0 -238
  742. package/src/notifications/unsubscribe-panel.tsx +0 -200
  743. package/src/notifications/use-push-device.ts +0 -448
  744. package/src/offline/local-first.ts +0 -100
  745. package/src/offline/pwa-update-prompt-labels.ts +0 -9
  746. package/src/offline/pwa-update-prompt.tsx +0 -78
  747. package/src/offline/query-persistence.ts +0 -391
  748. package/src/offline/service-worker-updates.ts +0 -81
  749. package/src/offline/shared-computer-labels.ts +0 -8
  750. package/src/offline/shared-computer.tsx +0 -87
  751. package/src/offline/sign-out-pending-dialog-labels.ts +0 -21
  752. package/src/offline/sign-out-pending-dialog.tsx +0 -135
  753. package/src/offline.ts +0 -37
  754. package/src/push-worker.ts +0 -25
  755. package/src/rhf/fields.tsx +0 -2187
  756. package/src/rhf/form-core.tsx +0 -324
  757. package/src/rhf/form.tsx +0 -12
  758. package/src/rhf/line-items.tsx +0 -135
  759. package/src/rhf/use-rhf-wizard-step.ts +0 -104
  760. package/src/rhf.ts +0 -21
  761. package/src/search/command-palette-labels.ts +0 -16
  762. package/src/search/command-palette.tsx +0 -624
  763. package/src/search/global-search-labels.ts +0 -13
  764. package/src/search/global-search.tsx +0 -660
  765. package/src/search/search-index.ts +0 -283
  766. package/src/search/use-command-key.ts +0 -23
  767. package/src/search.ts +0 -14
  768. package/src/settings/device-reset-setting-labels.ts +0 -20
  769. package/src/settings/device-reset-setting.tsx +0 -116
  770. package/src/settings/settings-card-classes.ts +0 -11
  771. package/src/settings/settings-catalogue.ts +0 -150
  772. package/src/settings/settings-context.ts +0 -33
  773. package/src/settings/settings-heading.tsx +0 -67
  774. package/src/settings/settings-labels.ts +0 -87
  775. package/src/settings/settings-layout.tsx +0 -471
  776. package/src/settings/settings-section.tsx +0 -108
  777. package/src/settings/use-account-appearance.ts +0 -148
  778. package/src/settings/use-account-language.ts +0 -146
  779. package/src/settings/use-settings-focus.ts +0 -128
  780. package/src/settings/use-settings-route.ts +0 -258
  781. package/src/shell/account-menu-language.tsx +0 -130
  782. package/src/shell/account-menu-text-size.tsx +0 -80
  783. package/src/shell/admin-menu.tsx +0 -183
  784. package/src/shell/app-shell-labels.ts +0 -11
  785. package/src/shell/app-shell.tsx +0 -1560
  786. package/src/shell/auth-layout.tsx +0 -186
  787. package/src/shell/company-switcher-labels.ts +0 -13
  788. package/src/shell/company-switcher.tsx +0 -136
  789. package/src/shell/dev-menu.tsx +0 -257
  790. package/src/shell/fill-height.tsx +0 -45
  791. package/src/shell/language-code.ts +0 -5
  792. package/src/shell/option-switcher-menu.tsx +0 -84
  793. package/src/shell/sync-status-indicator.tsx +0 -303
  794. package/src/shell/top-bar-actions.tsx +0 -87
  795. package/src/shell/top-bar-brand.tsx +0 -78
  796. package/src/shell/top-bar-parts-labels.ts +0 -148
  797. package/src/shell/top-bar.tsx +0 -40
  798. package/src/shell/topbar-action-menu.tsx +0 -567
  799. package/src/shell/topbar-controls.tsx +0 -269
  800. package/src/shell/tour-menu.tsx +0 -187
  801. package/src/shell.ts +0 -108
  802. package/src/sync/db.ts +0 -129
  803. package/src/sync/engine.ts +0 -1011
  804. package/src/sync/hooks.ts +0 -98
  805. package/src/sync/testing.ts +0 -73
  806. package/src/sync/wire.ts +0 -61
  807. package/src/sync.ts +0 -37
  808. package/src/table-text.ts +0 -8
  809. package/src/testing/css-variables.generated.ts +0 -112
  810. package/src/testing/css-variables.ts +0 -189
  811. package/src/testing/index.ts +0 -29
  812. package/src/testing/react.ts +0 -58
  813. package/src/testing/tour.ts +0 -41
  814. package/src/testing/viewport.ts +0 -357
  815. package/src/theme/chart-palette.ts +0 -232
  816. package/src/theme/color.ts +0 -272
  817. package/src/theme/contrast-tokens.ts +0 -268
  818. package/src/theme/contrast.ts +0 -250
  819. package/src/theme/palette-derive.ts +0 -825
  820. package/src/theme/palette-presets.ts +0 -544
  821. package/src/theme/palette-store.ts +0 -108
  822. package/src/theme/text-size.ts +0 -289
  823. package/src/theme/theme-store.ts +0 -157
  824. package/src/tour/tour-catalogue-labels.ts +0 -75
  825. package/src/tour/tour-catalogue.tsx +0 -335
  826. package/src/tour/tour-dock.ts +0 -134
  827. package/src/tour/tour-engine.ts +0 -37
  828. package/src/tour/tour-gates.ts +0 -218
  829. package/src/tour/tour-guide-button.tsx +0 -64
  830. package/src/tour/tour-guide-labels.ts +0 -15
  831. package/src/tour/tour-info.ts +0 -144
  832. package/src/tour/tour-labels.ts +0 -23
  833. package/src/tour/tour-overlay.tsx +0 -1170
  834. package/src/tour/tour.tsx +0 -750
  835. package/src/tour/use-tour-progress.ts +0 -671
  836. package/src/tour/use-tour-url-sync.ts +0 -266
  837. package/src/tour.ts +0 -21
  838. package/src/vite-env.d.ts +0 -23
  839. package/src/wizard/stepper-nav.tsx +0 -360
  840. package/src/wizard/types.ts +0 -275
  841. package/src/wizard/use-wizard.ts +0 -560
  842. package/src/wizard/validation.ts +0 -39
  843. package/src/wizard/wizard-context.tsx +0 -74
  844. package/src/wizard/wizard-labels.ts +0 -29
  845. package/src/wizard/wizard-step.tsx +0 -76
  846. package/src/wizard/wizard-summary.tsx +0 -84
  847. package/src/wizard.ts +0 -15
@@ -1,987 +0,0 @@
1
- import { Children, useCallback, useEffect, useId, useRef, useState } from "react";
2
- import type { ChangeEvent, ComponentPropsWithRef, FormEvent, ReactNode } from "react";
3
- import { cn } from "../lib/cn";
4
- import { hasContent } from "../lib/presence";
5
- import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
6
- import { Button } from "./button";
7
- import { Input } from "./input";
8
- import { Label } from "./field-base";
9
- import { FIELD_ERROR_CLASS } from "./field-parts";
10
- import { Spinner } from "./spinner";
11
- import type { ButtonVariant } from "./button-look";
12
- import type { InputProps } from "./input";
13
- import { Checkbox } from "./checkbox";
14
- import { Tooltip } from "./tooltip";
15
- import { useCommitReason, type CommitScope } from "./write-lock";
16
- import { DEFAULT_DANGER_CONFIRM_LABELS } from "./danger-confirm-labels";
17
-
18
- /**
19
- * How typed text is compared with the text it has to repeat — shared by
20
- * `DangerConfirm`'s `phraseMatch` and `useConfirm`'s `typedMatch`.
21
- *
22
- * - `"trim"` ignores spaces around the typed text — a phone keyboard's autocomplete
23
- * likes to add one. Case counts: "delete" is not "DELETE".
24
- * - `"exact"` compares character for character, spaces included.
25
- * - `"caseless"` trims AND ignores case: for an e-mail address, whose domain is
26
- * case-insensitive and whose local part every real mail server treats so. Both apps'
27
- * "type the account's address" rules (keksdose's `TYPE_EMAIL`, Kurvenschmiede's
28
- * `TypedConfirm`) compared `trim().toLowerCase()`, and a capital the user's keyboard
29
- * put at the start must not make the right row look like the wrong one.
30
- */
31
- export type TypedMatch = "trim" | "exact" | "caseless";
32
-
33
- /** Whether `typed` repeats `target` under `mode` — see {@link TypedMatch}. Exported for
34
- * a caller that draws its own field (a dialog that also picks a recipient) and wants
35
- * the same rule as the kit's. */
36
- export function typedMatches(typed: string, target: string, mode: TypedMatch = "trim"): boolean {
37
- if (mode === "exact") return typed === target;
38
- if (mode === "trim") return typed.trim() === target;
39
- // `toLowerCase`, not `toLocaleLowerCase`: the comparison must not change with the
40
- // reader's locale (a Turkish dotless i would otherwise fail an ASCII address).
41
- return typed.trim().toLowerCase() === target.trim().toLowerCase();
42
- }
43
-
44
- /**
45
- * Busy-while-a-promise-runs, for an action that MAY return one: `run(result, onResolved)`
46
- * marks the caller pending until `result` settles, calls `onResolved` if it fulfilled,
47
- * and only clears the flag if it rejected — the caller shows why and the user retries.
48
- * Nothing runs after unmount. Shared by `DangerConfirm` and `ReauthDialog`, whose
49
- * contract is the same: resolve = done, reject = stay put.
50
- *
51
- * @internal
52
- */
53
- export function usePromisePending() {
54
- const [pending, setPending] = useState(false);
55
- const mounted = useRef(true);
56
- useEffect(() => {
57
- mounted.current = true;
58
- return () => {
59
- mounted.current = false;
60
- };
61
- }, []);
62
- const run = useCallback((result: unknown, onResolved: () => void): boolean => {
63
- if (!result || typeof (result as Promise<unknown>).then !== "function") return false;
64
- setPending(true);
65
- (result as Promise<unknown>).then(
66
- () => {
67
- if (!mounted.current) return;
68
- setPending(false);
69
- onResolved();
70
- },
71
- () => {
72
- if (mounted.current) setPending(false);
73
- },
74
- );
75
- return true;
76
- }, []);
77
- return { pending, run };
78
- }
79
-
80
- /** The one word {@link CurrentPasswordInput} says on its own behalf — the
81
- * `dangerConfirm.password` label, shared with DangerConfirm's password field, so an
82
- * app translates "Password" once. */
83
- export type CurrentPasswordInputLabels = Pick<DangerConfirmLabels, "password">;
84
-
85
- /**
86
- * Everything {@link Input} takes except what makes this field what it is: `type` is
87
- * always `"password"` and `autoComplete` always `"current-password"`.
88
- */
89
- export interface CurrentPasswordInputProps extends Omit<InputProps, "type" | "autoComplete" | "label"> {
90
- /**
91
- * The visible label. Default `dangerConfirm.password` ("Password") — unless the field
92
- * is named another way (`aria-label` / `aria-labelledby`), which then stays the only
93
- * name. Pass the app's own word on a sign-in form ("Password", "Your password"), or
94
- * `null` for a field whose `<label htmlFor>` is drawn elsewhere (a form library's
95
- * label), which would otherwise be labelled twice.
96
- */
97
- label?: ReactNode;
98
- /** The value as a string — the `(next) => …` shape, so a caller holding it in
99
- * `useState` need not unwrap `event.target.value`. Fires alongside `onChange`,
100
- * never instead of it, so a form library's `onChange` keeps working. */
101
- onValueChange?: (value: string) => void;
102
- /**
103
- * A check is running (the sign-in request, the re-auth). The field turns `readOnly`,
104
- * NOT `disabled`: the field being submitted is usually the focused one (Enter was
105
- * pressed in it), and disabling a focused field drops focus to `<body>` — the user
106
- * lands nowhere when the "wrong password" answer comes back.
107
- */
108
- busy?: boolean;
109
- /** Per-instance override of `dangerConfirm.password`. */
110
- labels?: LabelOverride<CurrentPasswordInputLabels>;
111
- }
112
-
113
- /**
114
- * The "prove it is you" field: a password input that a password manager fills with
115
- * the CURRENT password and never offers to generate a new one for.
116
- *
117
- * It is the field of a sign-in form, a re-auth step ({@link ReauthDialog} draws the same
118
- * field), and {@link DangerConfirm}'s `requirePassword`. Public since 0.22 for kastlan's
119
- * sign-in and re-auth (kastlan 1), which wrote `type="password"` +
120
- * `autoComplete="current-password"` by hand — and a sign-in field that forgets the
121
- * second half gets the browser's "suggest a strong password" offer on the one form where
122
- * a NEW password is never what is wanted. The reverse matters as much: a field that sets
123
- * a NEW password (a passphrase, a sign-up) must NOT be this one — keksdose #170 keeps
124
- * its passphrase doors on `new-password` / `off` for that reason.
125
- *
126
- * Everything else is {@link Input}: the reveal toggle, `error` (under the field,
127
- * `aria-describedby`, `aria-invalid`), `invalid`, `name`, `id`, `autoFocus`, `required`.
128
- * The ref is the `<input>`, so it works with `@eifi1/ui-kit/rhf`'s `RhfField` / a
129
- * `register()` spread, and controlled or uncontrolled.
130
- *
131
- * ```tsx
132
- * <CurrentPasswordInput name="password" label={t("password")} error={errors.password?.message}
133
- * busy={isSubmitting} {...register("password")} />
134
- * ```
135
- */
136
- export function CurrentPasswordInput({
137
- label,
138
- onValueChange,
139
- onChange,
140
- busy,
141
- readOnly,
142
- labels: labelsProp,
143
- ...rest
144
- }: CurrentPasswordInputProps) {
145
- const labels = useKitLabels("dangerConfirm", DEFAULT_DANGER_CONFIRM_LABELS, labelsProp);
146
- const namedOtherwise = rest["aria-label"] !== undefined || rest["aria-labelledby"] !== undefined;
147
- return (
148
- <Input
149
- // `ref` (the `<input>`) rides along: a React 19 ref prop since 0.34 (MOD-4, refactor
150
- // audit 2026-10), where this was `forwardRef`.
151
- {...rest}
152
- // After the spread: a props object spread at the field must not turn it into a
153
- // text field, or into one the password manager offers a new password for.
154
- type="password"
155
- autoComplete="current-password"
156
- label={
157
- label === undefined ? (namedOtherwise ? undefined : labels.password) : hasContent(label) ? label : undefined
158
- }
159
- readOnly={Boolean(busy) || readOnly}
160
- onChange={(e) => {
161
- onChange?.(e);
162
- onValueChange?.(e.target.value);
163
- }}
164
- />
165
- );
166
- }
167
-
168
- /** The words {@link TypedConfirmField} says on its own behalf — the `dangerConfirm`
169
- * namespace's `phrase` and `phrasePlaceholder`, shared with DangerConfirm's own field,
170
- * so the sentence "Type “X” to confirm" is translated once. */
171
- export type TypedConfirmFieldLabels = Pick<DangerConfirmLabels, "phrase" | "phrasePlaceholder">;
172
-
173
- export interface TypedConfirmFieldProps extends Omit<
174
- InputProps,
175
- "type" | "value" | "defaultValue" | "label" | "placeholder"
176
- > {
177
- /** The text to repeat — a word ("DELETE"), a name, an e-mail address. */
178
- target: string;
179
- /** How the typed text is compared with `target` — {@link TypedMatch}. Default
180
- * `"trim"`, as {@link typedMatches}; `"caseless"` for an address or an
181
- * acknowledgement word a user may type in any case. */
182
- match?: TypedMatch;
183
- /** Controlled value. Left out, the field keeps its own (start: `defaultValue`). */
184
- value?: string;
185
- defaultValue?: string;
186
- /** The typed text as a string, on every keystroke. Fires alongside `onChange`. */
187
- onValueChange?: (value: string) => void;
188
- /**
189
- * The typed text started or stopped matching `target` — fired from the keystroke
190
- * that flipped it, so an uncontrolled field can still drive the button it guards. A
191
- * controlled caller that resets the value itself (on a close) knows the answer
192
- * already, and gets no call for that; it can also compute it with {@link typedMatches}.
193
- */
194
- onMatchedChange?: (matched: boolean) => void;
195
- /** The label. Default `dangerConfirm.phrase(target)` — "Type “DELETE” to confirm". */
196
- label?: ReactNode;
197
- /** Text inside the empty field. Default `dangerConfirm.phrasePlaceholder` (unset).
198
- * Given, the label moves ABOVE the field: a floating label occupies the empty
199
- * field, which is exactly where a placeholder shows. `""` means none. */
200
- placeholder?: string;
201
- /** The guarded action is running: the field turns `readOnly` (not `disabled`, which
202
- * would drop the focus Enter left in it). */
203
- busy?: boolean;
204
- labels?: LabelOverride<TypedConfirmFieldLabels>;
205
- }
206
-
207
- /**
208
- * The "type this to confirm" field — {@link DangerConfirm}'s `phrase` field and
209
- * `useConfirm({ requireTyped })`'s, on its own (keksdose K7).
210
- *
211
- * keksdose writes it by hand four times: the privacy enrol, upgrade and sweep dialogs
212
- * (type the acknowledgement word, then the key doors appear) and the admin's "type the
213
- * user's address" (`UserActionConfirm`), each an `Input` plus its own
214
- * `trim().toUpperCase()` / `toLowerCase()` comparison. None of those places is an
215
- * arm → confirm tile or a modal confirm — what is guarded is a whole form, or the
216
- * next step of a dialog — so the field had to stand alone. What it brings over a plain
217
- * `Input`: one match rule ({@link typedMatches}, which lower-cases locale-independently
218
- * on purpose), the label worded from the target in the app's language, and the
219
- * attributes a phone keyboard needs to leave the text alone (no autocomplete, no
220
- * auto-capital, no autocorrect, no spellcheck — a keyboard that "corrects" an e-mail
221
- * address makes the guard unpassable).
222
- *
223
- * The field reports whether it matches (`onMatchedChange`, and `data-matched` on the
224
- * `<input>` for styling); what the match unlocks is the caller's. The ref is the
225
- * `<input>`.
226
- *
227
- * ```tsx
228
- * const [ok, setOk] = useState(false);
229
- * <TypedConfirmField target={t("privacy.enroll_ack_word")} match="caseless" onMatchedChange={setOk} />
230
- * {ok && <KeyDoorsForm … />}
231
- * ```
232
- */
233
- export function TypedConfirmField({
234
- ref,
235
- target,
236
- match = "trim",
237
- value: valueProp,
238
- defaultValue = "",
239
- onValueChange,
240
- onMatchedChange,
241
- onChange,
242
- label: labelProp,
243
- placeholder: placeholderProp,
244
- busy,
245
- readOnly,
246
- labels: labelsProp,
247
- id,
248
- className,
249
- ...rest
250
- }: TypedConfirmFieldProps) {
251
- const labels = useKitLabels("dangerConfirm", DEFAULT_DANGER_CONFIRM_LABELS, labelsProp);
252
- const [own, setOwn] = useState(defaultValue);
253
- const value = valueProp ?? own;
254
- const matched = typedMatches(value, target, match);
255
- const generated = useId();
256
- const fieldId = id ?? generated;
257
- const label =
258
- labelProp !== undefined ? labelProp : typeof labels.phrase === "function" ? labels.phrase(target) : labels.phrase;
259
- const fromLabels =
260
- labels.phrasePlaceholder === undefined
261
- ? undefined
262
- : typeof labels.phrasePlaceholder === "function"
263
- ? labels.phrasePlaceholder(target)
264
- : labels.phrasePlaceholder;
265
- const placeholder = placeholderProp ?? fromLabels;
266
-
267
- const fieldProps = {
268
- ...rest,
269
- ref,
270
- id: fieldId,
271
- value,
272
- autoComplete: "off",
273
- autoCapitalize: "off",
274
- autoCorrect: "off",
275
- spellCheck: false,
276
- readOnly: Boolean(busy) || readOnly,
277
- "data-matched": matched || undefined,
278
- onChange: (e: ChangeEvent<HTMLInputElement>) => {
279
- onChange?.(e);
280
- const next = e.target.value;
281
- if (valueProp === undefined) setOwn(next);
282
- onValueChange?.(next);
283
- const nextMatched = typedMatches(next, target, match);
284
- if (nextMatched !== matched) onMatchedChange?.(nextMatched);
285
- },
286
- };
287
-
288
- if (placeholder) {
289
- return (
290
- // A static label above, so the placeholder has the empty field to itself.
291
- <div className={cn("space-y-1.5", className)}>
292
- <Label htmlFor={fieldId}>{label}</Label>
293
- <Input {...fieldProps} placeholder={placeholder} />
294
- </div>
295
- );
296
- }
297
- return <Input {...fieldProps} label={label} className={className} />;
298
- }
299
-
300
- /**
301
- * Every string the tile renders — the `dangerConfirm` namespace of
302
- * `<UiKitProvider labels>`, overridable per instance through `labels`. The arm and
303
- * confirm buttons are usually worded per action ("Delete budget"), which is what the
304
- * `armLabel` / `confirmLabel` props are for; these are the fallbacks.
305
- */
306
- export interface DangerConfirmLabels {
307
- /** The button that arms the tile. */
308
- arm: string;
309
- /** The button that runs the action once the guards are satisfied. */
310
- confirm: string;
311
- cancel: string;
312
- /** The warning above the fields, when no `prompt` is given. */
313
- prompt: string;
314
- /** Label of the password field (`requirePassword`). */
315
- password: string;
316
- /** Label of the type-to-confirm field. A FUNCTION of the phrase by default, like
317
- * every message that carries a value: where the phrase sits in the sentence moves
318
- * with the language. A plain STRING is taken as the finished label — for an app
319
- * whose catalogue already words it ("Type DELETE to confirm") and would otherwise
320
- * wrap it as `() => label`. */
321
- phrase: string | ((phrase: string) => string);
322
- /** Placeholder of the type-to-confirm field — a string, or a function of the
323
- * phrase (`(p) => p` echoes it). Optional and unset by default: the field keeps its
324
- * floating label, as before. Given, the label moves ABOVE the field (a floating
325
- * label occupies the empty field, which is exactly where a placeholder shows) and
326
- * the placeholder fills the field. An empty string means none. */
327
- phrasePlaceholder?: string | ((phrase: string) => string);
328
- /** 0.22: the checkbox `requireAcknowledge={true}` shows — "I have read what this does
329
- * and want to continue" (keksdose's `admin.users.confirm_ack`). */
330
- acknowledge: string;
331
- /**
332
- * 0.23: why the armed confirm is held while the typed phrase does not match yet — in
333
- * the confirm's tooltip and its description (keksdose G4a). A FUNCTION of the phrase
334
- * by default ("Type “DELETE” to confirm"), or a finished STRING, as `phrase`.
335
- */
336
- needsPhrase: string | ((phrase: string) => string);
337
- /** 0.23: why the armed confirm is held while the `requireAcknowledge` box is unticked
338
- * — "Tick the box to confirm". */
339
- needsAcknowledge: string;
340
- /** 0.23: why the armed confirm is held while the `requirePassword` field is empty —
341
- * "Enter your password to confirm". */
342
- needsPassword: string;
343
- }
344
-
345
- // Defined in ./danger-confirm-labels, which holds no component code (0.34, KS U8).
346
- export { DEFAULT_DANGER_CONFIRM_LABELS };
347
-
348
- /**
349
- * What the guards were answered with — the second argument of
350
- * {@link DangerConfirmProps.onConfirm} (0.23, keksdose G4b). A key is there only when its
351
- * guard was asked for, so the object can go into a request body as it is.
352
- */
353
- export interface DangerConfirmValues {
354
- /**
355
- * The text typed into the `phrase` field — as the match rule compared it: trimmed
356
- * under `phraseMatch` `"trim"` and `"caseless"` (the spaces a phone keyboard adds are
357
- * not part of it), exactly as typed under `"exact"`. The case is the user's, even
358
- * under `"caseless"`: a server that re-checks applies its own rule to it. Absent
359
- * without a `phrase`.
360
- */
361
- typed?: string;
362
- /** The entered password — the same value as the first argument. Absent without
363
- * `requirePassword`. */
364
- password?: string;
365
- /** `true` when the `requireAcknowledge` box was shown — it was ticked, since the
366
- * confirm is held until it is. Absent without one. */
367
- acknowledged?: true;
368
- }
369
-
370
- /**
371
- * One line of {@link DangerConfirmProps.consequences}: what the action will do. A plain
372
- * string, or this, for a key of its own and the `severe` mark.
373
- */
374
- export interface DangerConsequence {
375
- /** React key — keksdose keys its lines by what they say ("api_tokens", "only_door").
376
- * Default: the text when it is a string, else the position. */
377
- key?: string;
378
- text: ReactNode;
379
- /** "There is no way back" — painted in the danger colour rather than the list's
380
- * muted one. keksdose reserves it for the one line that loses something for good. */
381
- severe?: boolean;
382
- }
383
-
384
- export interface DangerConfirmProps extends Omit<ComponentPropsWithRef<"div">, "onChange"> {
385
- /**
386
- * Runs the action, with the entered password when `requirePassword` is on.
387
- *
388
- * Return a promise and the tile manages itself: busy until it settles, disarmed
389
- * (fields wiped) when it resolves, still armed when it rejects — so the user can
390
- * correct a wrong password and retry. The rejection is not swallowed for you to
391
- * miss: handle it (and show why) in the caller, as with any mutation.
392
- *
393
- * 0.23: the second argument is what every guard was answered with — the typed phrase,
394
- * the password, the tick ({@link DangerConfirmValues}). keksdose G4b: its admin
395
- * actions send the address the admin TYPED, and the server re-checks it against the
396
- * account (`assert_confirmed`), so a client that put the wrong row's id in the request
397
- * is refused rather than obeyed; the tile kept the text to itself.
398
- *
399
- * onConfirm={(_password, { typed }) =>
400
- * reset.mutateAsync({ id, confirm: { acknowledged: true, confirm_email: typed ?? null } })}
401
- *
402
- * A second argument rather than one object in place of the password: every
403
- * `(password) => …` and `() => …` handler, and a `mutation.mutate` passed as it is,
404
- * keeps working unchanged, and a handler that needs one guard's answer names it.
405
- */
406
- onConfirm: (password: string | undefined, values: DangerConfirmValues) => void | Promise<unknown>;
407
- /** Show a password field; confirm is held until it is filled. */
408
- requirePassword?: boolean;
409
- /**
410
- * Show an "I understand" checkbox; confirm is held until it is ticked
411
- * (keksdose K7). `true` words it with `labels.acknowledge`; any other node IS the
412
- * checkbox's label ("I understand Anna will be signed out everywhere").
413
- *
414
- * The guard for an action whose risk is MIS-TARGETING less than carelessness:
415
- * keksdose's admin password reset asks for a typed address when the account has an
416
- * encrypted door to lose, and a tick otherwise (`UserActionConfirm`), and its plan
417
- * editor asks for the tick alone (`UserPlanEditor`). Both were hand-built beside this
418
- * tile because it had no tick. It combines with `phrase` and `requirePassword`: every
419
- * guard given must be satisfied.
420
- */
421
- requireAcknowledge?: ReactNode;
422
- /**
423
- * What the action will do, said before it happens — a list under the prompt, shown
424
- * once armed (keksdose K7, `UserActionConfirm`'s consequences). Strings, or
425
- * {@link DangerConsequence}s for a `severe` line in the danger colour.
426
- *
427
- * Derive them from the row's own facts rather than reciting the worst case: an admin
428
- * who reads the same paragraph on every row stops reading it (keksdose dev#488).
429
- */
430
- consequences?: readonly (string | DangerConsequence)[];
431
- /** Show a "type <phrase> to confirm" field; confirm is held until the field matches
432
- * (case-sensitive; surrounding spaces ignored unless `phraseMatch="exact"`). */
433
- phrase?: string;
434
- /**
435
- * How the typed text is compared with `phrase`. `"trim"` (default) ignores spaces
436
- * around it — a phone keyboard's autocomplete likes to add one. `"exact"` compares
437
- * character for character, spaces included, for an app whose contract is "type
438
- * exactly this". `"caseless"` (0.18) also ignores case — for a phrase that is an
439
- * e-mail address (keksdose's "type the user's address" admin rule). See
440
- * {@link TypedMatch}.
441
- */
442
- phraseMatch?: TypedMatch;
443
- /** The warning above the fields. Defaults to `labels.prompt`. */
444
- prompt?: ReactNode;
445
- /** `"danger"` (default) for what cannot be undone; `"warning"` for what can, at a
446
- * cost (loading demo data over your own). Colours the prompt, and picks the arm
447
- * button's variant and — unless {@link DangerConfirmProps.confirmVariant} is
448
- * given — the confirm's. */
449
- tone?: "danger" | "warning";
450
- /**
451
- * The confirm button's variant, apart from `tone` (0.24, keksdose). Default: what
452
- * `tone` picks, as before — `"danger"` for `"danger"`, `"default"` for `"warning"`.
453
- *
454
- * `tone` says how bad the outcome is; this says how loud the last press is, and the two
455
- * need not agree. keksdose's `UserActionConfirm` (an admin resets somebody else's
456
- * password) asks an AMBER question — what it guards against is mis-targeting, not data
457
- * loss, so the danger colour stays its one `severe` consequence's — and ends in a RED
458
- * Go, as its hand-built panel did before it moved onto this tile in 0.23; with only
459
- * `tone`, the amber question made Go the neutral `default` fill. `tone="warning"
460
- * confirmVariant="danger"` is that panel again.
461
- */
462
- confirmVariant?: ButtonVariant;
463
- /**
464
- * Hold the armed confirm for a reason of the CALLER's own (0.24, keksdose) — the
465
- * tile's counterpart of FormActions' `submitDisabledReason`. While it has content the
466
- * confirm is held exactly as by the built-in guards: `aria-disabled` but focusable,
467
- * the reason in the kit {@link Tooltip} and its description, a press — or Enter in a
468
- * field — does nothing. Nothing else changes: the arm button stays usable, and no
469
- * line is printed under the buttons.
470
- *
471
- * keksdose's `UserPlanEditor` ("move this account onto another plan") must not confirm
472
- * the plan the account already holds — the request would only write FREE → FREE into
473
- * the audit trail. With no guard of its own to give, it passed "Pick a different plan"
474
- * as `lockedReason`, which is a LOCK: documented as "the action is not available",
475
- * spelled out under the buttons as well as in the tooltip, and meant for a write the
476
- * user cannot make land. A guard the user lifts by changing a field is this prop.
477
- *
478
- * Which reason the held confirm names: a write lock's first (`lockedReason`, `commit`
479
- * — nothing in the tile lifts it), then this one, then the built-in guards in the
480
- * order they are drawn (the tick, the phrase, the password). This one before the
481
- * built-ins because it is usually about a field in
482
- * {@link DangerConfirmProps.children}, which is drawn ABOVE them — the rule since 0.23
483
- * is "the first open guard in the order the user meets it" — and because it is about
484
- * WHAT is being confirmed (which plan), which has to be settled before acknowledging
485
- * it means anything. It is also the order keksdose's plan editor had, its
486
- * `lockedReason` winning over the tick.
487
- */
488
- confirmDisabledReason?: ReactNode;
489
- /**
490
- * Fields of the caller's own, drawn INSIDE the armed tile (0.24, keksdose): after the
491
- * prompt and the consequences, before the tick, the typed phrase and the password —
492
- * the order is "what this does, what to do it with, then prove you mean it". Nothing
493
- * is drawn for them while the tile is disarmed, and nothing at all without them, so a
494
- * tile without children is laid out exactly as before.
495
- *
496
- * keksdose's `UserPlanEditor` asks WHICH plan before it asks for the tick; with no
497
- * place inside the tile for the picker, the `Select` sat above it, and the tile's
498
- * prompt — the panel's title by rights — became the "FREE → PRO" line under the
499
- * picker. With the picker here, the prompt is the title again.
500
- *
501
- * The fields are the caller's: their values are not wiped on disarm (an uncontrolled
502
- * field starts over anyway — the slot unmounts), not passed to `onConfirm`, and a
503
- * guard on them is {@link DangerConfirmProps.confirmDisabledReason}. Arming moves
504
- * focus to their first form field (an input, a select, a combobox, a radio…), else to
505
- * the tile's own first field as before; Tab then goes on through the tick, the phrase
506
- * and the password to Cancel and the confirm. They sit inside the tile's `<form>`:
507
- * Enter in a text field confirms once every guard allows, and a {@link Button} among
508
- * them needs `type="button"` — without one it SUBMITS the form, as a native button
509
- * does.
510
- */
511
- children?: ReactNode;
512
- /** Visible text of the arm button; defaults to `labels.arm`. */
513
- armLabel?: ReactNode;
514
- /** Visible text of the confirm button; defaults to `labels.confirm`. */
515
- confirmLabel?: ReactNode;
516
- /**
517
- * The action is running: confirm shows a spinner and nothing can be pressed — Cancel
518
- * included. For a caller that tracks the mutation itself (a `useMutation`'s
519
- * `isPending`); a promise returned from `onConfirm` does the same on its own.
520
- *
521
- * Cancel stays disabled ON PURPOSE, unlike FormActions' (keksdose asked in 0.24 why the
522
- * two differ). Once the request has left, nothing on the client can call it back —
523
- * not even an `AbortSignal`, which only stops the waiting, not the server — so a usable
524
- * Cancel could only collapse the tile while the action went on: "Cancel" pressed, and
525
- * the account reset anyway. Every way of settling what comes back is wrong somewhere: a
526
- * resolve after the Cancel did what the user called off; a reject finds the fields
527
- * wiped (a collapsed tile holds no password), so the 0.23 "stay armed and retry" is
528
- * gone; and re-arming while the first request runs is either a busy tile with empty
529
- * fields or — if the busy state went with the Cancel — a second destructive request
530
- * beside the first. FormActions' Cancel leaves an editor whose save is the user's own
531
- * edit landing, and a form can be edited again; the tile's action is the one that
532
- * cannot be undone, so it says nothing it cannot keep and waits — the wait is one
533
- * request long.
534
- *
535
- * When the action settles still armed (it failed) and the press on the confirm had
536
- * dropped the focus — a natively disabled button loses it — focus comes back to the
537
- * confirm, so a keyboard user can retry or Shift+Tab to the field to correct (0.24).
538
- */
539
- busy?: boolean;
540
- /**
541
- * Why the last confirm failed ("Wrong password"), in the tile beside the field it is
542
- * about rather than in a toast away from it (keksdose audit follow-up, 2026-11-01:
543
- * PasswordDangerCard toasted its `password_incorrect` for want of this). The app sets
544
- * it from the failure and words it — a 400 is a wrong password, a 500 is not.
545
- *
546
- * Drawn as the field's own `error`, as {@link ReauthDialog} draws its own: under the
547
- * password with `requirePassword`, else under the typed phrase — the field painted,
548
- * `aria-invalid`, the message its `aria-describedby` — and in a tile with neither, as
549
- * a line above the buttons. Announced as it appears (`role="alert"`): it arrives
550
- * after the press, with focus on the confirm, where a field's description alone is
551
- * not heard. Passed at all — even as `undefined` — the field keeps its box, as with
552
- * Input's `error`, so the message going away does not rebuild the field mid-edit.
553
- *
554
- * Hidden while the next attempt runs, once the user edits the tick, the phrase or the
555
- * password (it is about what was submitted), and when the tile arms or disarms, until
556
- * the next confirm; shown again when a confirm fails with it still set. So a
557
- * mutation's error can be handed over as it is:
558
- * `error={mut.error ? message(mut.error) : undefined}`.
559
- */
560
- error?: ReactNode;
561
- /** The arm button is disabled. */
562
- disabled?: boolean;
563
- /**
564
- * Why the action is not available — a read-only demo, a write lock, a missing
565
- * permission. Disables the arm button like `disabled`, and SAYS so: the sentence is
566
- * shown under the button and attached to it with `aria-describedby`, and the button
567
- * stays focusable (`aria-disabled`) so a keyboard user can land on it and hear why.
568
- *
569
- * On the ARM button rather than the confirm: arming asks for a password, and asking
570
- * for a password for a write that can never land is the worse of the two. A tile that
571
- * is ALREADY armed when the reason arrives (controlled `armed`, or a lock that landed
572
- * while it was open) keeps its fields but its confirm takes the reason the same way
573
- * — focusable, `aria-disabled`, the reason in its tooltip — and Enter does nothing.
574
- */
575
- lockedReason?: ReactNode;
576
- /**
577
- * This tile COMMITS — the 0.18 write-lock opt-in that {@link Button} has (keksdose
578
- * K3). Under a locked {@link WriteLockProvider} the lock's reason becomes
579
- * `lockedReason` (and wins over one of the tile's own), so a page that mounts the
580
- * provider no longer threads `lockedReason={lock.locked ? lock.reason : undefined}`
581
- * into every tile. No provider, or an unlocked one: no effect.
582
- */
583
- commit?: CommitScope;
584
- /** Controlled armed state. The parent can then collapse the tile from a mutation's
585
- * own `onSuccess` without returning a promise. */
586
- armed?: boolean;
587
- /** Called with the next armed state — on arm, cancel, and a resolved `onConfirm`. */
588
- onArmedChange?: (armed: boolean) => void;
589
- /** User-facing strings; see {@link DangerConfirmLabels}. */
590
- labels?: LabelOverride<DangerConfirmLabels>;
591
- }
592
-
593
- /** What counts as a FIELD among the caller's `children` — what arming focuses. Not
594
- * any tabbable element: a "see the plans" link or a disclosure button before the
595
- * picker is not where the user starts. `[tabindex="-1"]` is a roving radio group's
596
- * unselected option; the selected one (`0`) is the group's stop. */
597
- const SLOT_FIELD = [
598
- 'input:not([type="hidden"])',
599
- "select",
600
- "textarea",
601
- ...["combobox", "listbox", "radio", "checkbox", "switch", "slider", "spinbutton", "textbox"].map(
602
- (role) => `[role="${role}"]`,
603
- ),
604
- ]
605
- .map((selector) => `${selector}:not(:disabled):not([tabindex="-1"]):not([aria-hidden="true"])`)
606
- .join(", ");
607
-
608
- /** The first field among the caller's `children`, skipping a native radio that is not
609
- * the checked one of its group (Tab lands on the checked one). */
610
- function firstSlotField(slot: HTMLElement | null): HTMLElement | null {
611
- if (!slot) return null;
612
- for (const el of slot.querySelectorAll<HTMLElement>(SLOT_FIELD)) {
613
- if (el.closest("[hidden], [inert]")) continue;
614
- if (el instanceof HTMLInputElement && el.type === "radio" && !el.checked && el.name) {
615
- const group = el.form?.elements.namedItem(el.name);
616
- const checked =
617
- group instanceof RadioNodeList && Array.from(group).some((r) => r instanceof HTMLInputElement && r.checked);
618
- if (checked) continue;
619
- }
620
- return el;
621
- }
622
- return null;
623
- }
624
-
625
- /**
626
- * An "arm → confirm" tile for destructive actions: one button, which expands into a
627
- * warning, an optional list of consequences, optional fields of the caller's own
628
- * (`children`, 0.24), an optional "I understand" tick, an optional type-to-confirm
629
- * field, an optional password field and a confirm that is held until every guard is
630
- * satisfied — the built-in ones, and the caller's `confirmDisabledReason` (0.24).
631
- *
632
- * A held confirm SAYS which guard is still open (0.23, keksdose G4a): it is
633
- * `aria-disabled` rather than `disabled` — still focusable, so a keyboard user can land
634
- * on it — with the reason in the kit {@link Tooltip} and its description ("Type
635
- * “DELETE” to confirm", "Tick the box to confirm", "Enter your password to confirm";
636
- * `labels.needs*`), the first open guard in the order they are drawn. FormActions'
637
- * `submitDisabledReason` does the same for a form's Save. Pressing it, or Enter in a
638
- * field, does nothing. A lock's reason wins over a guard's, the caller's guard over the
639
- * built-in ones; while the action runs the confirm is plainly disabled, its spinner
640
- * saying why — and so is Cancel, which cannot call back a request that has left (see
641
- * `busy`).
642
- *
643
- * Keksdose hand-rolled it three times (load demo data, wipe everything, reset a
644
- * budget) and then as `shared/components/danger-confirm.tsx`; the only app-specific
645
- * part was its write-lock hook, which is `lockedReason` here.
646
- *
647
- * The fields are a `<form>`, so Enter confirms once the guards allow it. They are
648
- * wiped every time the tile disarms — a password must not sit in a collapsed tile.
649
- * Arming moves focus to the first field (or Cancel, when there is none — never to the
650
- * destructive button itself), and disarming moves it back to the arm button, so the
651
- * keyboard user is never left on an element that just vanished.
652
- */
653
- export function DangerConfirm(props: DangerConfirmProps) {
654
- const {
655
- onConfirm,
656
- requirePassword,
657
- requireAcknowledge,
658
- consequences,
659
- phrase,
660
- phraseMatch = "trim",
661
- prompt,
662
- tone = "danger",
663
- confirmVariant,
664
- confirmDisabledReason,
665
- children,
666
- armLabel,
667
- confirmLabel,
668
- busy: busyProp,
669
- error,
670
- disabled,
671
- lockedReason: ownLockedReason,
672
- commit,
673
- armed: armedProp,
674
- onArmedChange,
675
- labels: labelsProp,
676
- className,
677
- ...rest
678
- } = props;
679
- const labels = useKitLabels("dangerConfirm", DEFAULT_DANGER_CONFIRM_LABELS, labelsProp);
680
- const lockedReason = useCommitReason(commit, ownLockedReason);
681
- const [armedState, setArmedState] = useState(false);
682
- const armed = armedProp ?? armedState;
683
- const [password, setPassword] = useState("");
684
- const [typed, setTyped] = useState("");
685
- const [acknowledged, setAcknowledged] = useState(false);
686
- // The `error` describes what was submitted: an edit, an arm or a disarm leaves it
687
- // describing nothing on screen. Cleared by the next confirm — ReauthDialog's `edited`.
688
- const [errorStale, setErrorStale] = useState(false);
689
- const { pending, run } = usePromisePending();
690
- const busy = Boolean(busyProp) || pending;
691
- // `readOnly` rather than `disabled` on the fields while busy: disabling the field
692
- // that has focus (Enter was pressed in it) drops focus to <body>.
693
- const promptId = useId();
694
- const consequencesId = useId();
695
- const reasonId = useId();
696
-
697
- // The buttons focus is moved to are found by id.
698
- const armId = useId();
699
- const cancelId = useId();
700
- const confirmId = useId();
701
- const firstFieldRef = useRef<HTMLInputElement>(null);
702
- // The caller's fields (`children`), searched for their first form field on arm.
703
- const slotRef = useRef<HTMLDivElement>(null);
704
- // Focus moves only after a transition — never on mount, so a tile that renders armed
705
- // (controlled) does not take the page's focus merely by existing.
706
- const moveFocus = useRef(false);
707
- // A confirm from this tile is under way — see the focus return after a failure below.
708
- const confirmed = useRef(false);
709
-
710
- // A disarm from anywhere (cancel, a resolved confirm, the parent) wipes the fields.
711
- // During render, like NumberField's draft, so no frame shows a collapsed tile that
712
- // still holds a password.
713
- const [wasArmed, setWasArmed] = useState(armed);
714
- if (wasArmed !== armed) {
715
- setWasArmed(armed);
716
- // An `error` still passed is about the attempt before: not shown until a confirm.
717
- setErrorStale(true);
718
- if (!armed) {
719
- setPassword("");
720
- setTyped("");
721
- setAcknowledged(false);
722
- }
723
- }
724
-
725
- const prevArmed = useRef(armed);
726
- useEffect(() => {
727
- const changed = prevArmed.current !== armed;
728
- prevArmed.current = armed;
729
- const byUser = moveFocus.current;
730
- moveFocus.current = false;
731
- if (!changed) return;
732
- if (armed) {
733
- if (byUser) {
734
- // The caller's fields come first on the page, so first in focus too.
735
- (firstSlotField(slotRef.current) ?? firstFieldRef.current ?? document.getElementById(cancelId))?.focus();
736
- }
737
- return;
738
- }
739
- confirmed.current = false;
740
- // A controlled parent collapsing the tile from its own `onSuccess` did not go
741
- // through `setArmed`; if focus went down with the form, bring it back too.
742
- const lost = document.activeElement === null || document.activeElement === document.body;
743
- if (byUser || lost) document.getElementById(armId)?.focus();
744
- }, [armed, armId, cancelId]);
745
-
746
- // The action settled and the tile is still armed — it failed, and the user retries.
747
- // The confirm was natively disabled while it ran, and a focused button that turns
748
- // disabled drops the focus to <body>: bring it back to the button that was pressed.
749
- // Only after a confirm from THIS tile (`confirmed`), so a `busy` that comes and goes
750
- // on its own never pulls the page's focus in. (A resolve disarms, and the effect
751
- // above takes the focus to the arm button.)
752
- const wasBusy = useRef(busy);
753
- useEffect(() => {
754
- const settled = wasBusy.current && !busy;
755
- wasBusy.current = busy;
756
- if (!settled) return;
757
- const ours = confirmed.current;
758
- confirmed.current = false;
759
- if (!ours || !armed) return;
760
- if (document.activeElement === null || document.activeElement === document.body) {
761
- document.getElementById(confirmId)?.focus();
762
- }
763
- }, [busy, armed, confirmId]);
764
-
765
- const setArmed = (next: boolean) => {
766
- moveFocus.current = true;
767
- if (armedProp === undefined) setArmedState(next);
768
- onArmedChange?.(next);
769
- };
770
-
771
- const locked = hasContent(lockedReason);
772
- // `true` words the tick with the namespace; any other node is its label; `false`,
773
- // `null` and `""` are no tick at all.
774
- const acknowledgeLabel: ReactNode =
775
- requireAcknowledge === true ? labels.acknowledge : hasContent(requireAcknowledge) ? requireAcknowledge : null;
776
- const asksAcknowledge = acknowledgeLabel !== null;
777
- const passwordOk = !requirePassword || password !== "";
778
- const phraseOk = phrase === undefined || typedMatches(typed, phrase, phraseMatch);
779
- const acknowledgeOk = !asksAcknowledge || acknowledged;
780
- const callerHeld = hasContent(confirmDisabledReason);
781
- // `{cond && <Select />}` and `[null, false]` are no fields: no wrapper, no gap.
782
- const hasFields = Children.toArray(children).some(hasContent);
783
- const canConfirm = passwordOk && phraseOk && acknowledgeOk && !callerHeld && !busy;
784
- // The first guard still open, in the order the fields are drawn — the one the user
785
- // meets next, so the sentence points at it.
786
- const guardReason: string | undefined = !acknowledgeOk
787
- ? labels.needsAcknowledge
788
- : !phraseOk
789
- ? typeof labels.needsPhrase === "function"
790
- ? labels.needsPhrase(phrase ?? "")
791
- : labels.needsPhrase
792
- : !passwordOk
793
- ? labels.needsPassword
794
- : undefined;
795
- // The lock first (no guard can lift it); none while busy, when the guards were met and
796
- // the spinner is the state; then the caller's guard — about the fields drawn above the
797
- // built-in ones, and about WHAT is confirmed — then the first built-in guard still open.
798
- const confirmReason: ReactNode = locked
799
- ? lockedReason
800
- : busy
801
- ? undefined
802
- : callerHeld
803
- ? confirmDisabledReason
804
- : guardReason;
805
-
806
- const submit = (e: FormEvent) => {
807
- e.preventDefault();
808
- // `locked` too: Enter in a field submits the form without the button's say (and
809
- // `canConfirm` holds the caller's guard the same way).
810
- if (!canConfirm || locked) return;
811
- const values: DangerConfirmValues = {
812
- ...(phrase !== undefined && { typed: phraseMatch === "exact" ? typed : typed.trim() }),
813
- ...(requirePassword && { password }),
814
- ...(asksAcknowledge && { acknowledged: true as const }),
815
- };
816
- confirmed.current = true;
817
- setErrorStale(false);
818
- // Disarms when it resolves; a rejection leaves it armed, fields kept: the caller
819
- // shows why, the user retries.
820
- run(onConfirm(values.password, values), () => setArmed(false));
821
- };
822
-
823
- // The failure's message, under the field it is about: the password, else the phrase,
824
- // else (a tile with neither) a line of its own. Not while the next attempt runs.
825
- const shownError = errorStale || busy ? undefined : error;
826
- const errorAlert = hasContent(shownError) ? <span role="alert">{shownError}</span> : undefined;
827
- const errorOn = requirePassword ? "password" : phrase !== undefined ? "phrase" : "line";
828
- // Passed at all, the carrying field keeps its box (Input's `error` rule): only then.
829
- const fieldError = (field: "password" | "phrase") =>
830
- "error" in props && errorOn === field ? { error: errorAlert } : {};
831
- const edited = () => setErrorStale(true);
832
-
833
- // The first field takes focus on arm: the tick, then the phrase, then the password —
834
- // the order they are drawn in.
835
- const firstField = asksAcknowledge ? "acknowledge" : phrase !== undefined ? "phrase" : "password";
836
- const lines = (consequences ?? []).map((item, index) =>
837
- typeof item === "string"
838
- ? { key: item, text: item as ReactNode, severe: false }
839
- : { key: item.key ?? String(index), text: item.text, severe: Boolean(item.severe) },
840
- );
841
-
842
- const toneText = tone === "warning" ? "text-warning" : "text-danger";
843
-
844
- if (!armed) {
845
- const arm = (
846
- <Button
847
- id={armId}
848
- type="button"
849
- variant={tone === "warning" ? "secondary" : "danger"}
850
- disabled={disabled}
851
- aria-disabled={locked || undefined}
852
- aria-describedby={locked ? reasonId : undefined}
853
- onClick={() => {
854
- if (!locked) setArmed(true);
855
- }}
856
- className="aria-disabled:cursor-not-allowed aria-disabled:opacity-50"
857
- >
858
- {armLabel ?? labels.arm}
859
- </Button>
860
- );
861
- return (
862
- <div {...rest} className={cn("space-y-1", className)}>
863
- {locked ? (
864
- // The reason on the button itself too, where the pointer that tried it is —
865
- // the line below can sit out of view in a long settings card. Portalled, so
866
- // a card that scrolls neither clips it nor grows by it.
867
- //
868
- // The button in a FRAGMENT on purpose: Tooltip clones an element child to
869
- // add the bubble to its `aria-describedby`, and the button is already
870
- // described by the visible line below — the same sentence twice, read out
871
- // on every focus. A fragment is left as it is, so the bubble stays visual.
872
- <Tooltip label={lockedReason} portal>
873
- <>{arm}</>
874
- </Tooltip>
875
- ) : (
876
- arm
877
- )}
878
- {locked && (
879
- <p id={reasonId} className="text-xs text-muted">
880
- {lockedReason}
881
- </p>
882
- )}
883
- </div>
884
- );
885
- }
886
-
887
- return (
888
- <div {...rest} className={cn("space-y-2", className)}>
889
- <form
890
- className="space-y-2"
891
- aria-describedby={lines.length > 0 ? `${promptId} ${consequencesId}` : promptId}
892
- aria-busy={busy || undefined}
893
- onSubmit={submit}
894
- noValidate
895
- >
896
- <p id={promptId} className={cn("text-xs font-medium", toneText)}>
897
- {prompt ?? labels.prompt}
898
- </p>
899
- {lines.length > 0 && (
900
- <ul id={consequencesId} className="list-disc space-y-1 ps-5 text-xs text-secondary">
901
- {lines.map((line) => (
902
- <li key={line.key} className={line.severe ? "text-danger" : undefined}>
903
- {line.text}
904
- </li>
905
- ))}
906
- </ul>
907
- )}
908
- {/* The caller's fields: after what the action does, before the proof that it is
909
- meant. No wrapper without them — a 0.23 tile's markup is unchanged. */}
910
- {hasFields && (
911
- <div ref={slotRef} className="space-y-2">
912
- {children}
913
- </div>
914
- )}
915
- {asksAcknowledge && (
916
- <Checkbox
917
- ref={firstField === "acknowledge" ? firstFieldRef : undefined}
918
- label={acknowledgeLabel}
919
- checked={acknowledged}
920
- // Not `disabled` while busy, for the same reason the fields are readOnly:
921
- // the box may hold the focus. A change while busy is simply not taken.
922
- onCheckedChange={(next) => {
923
- if (busy) return;
924
- setAcknowledged(next);
925
- edited();
926
- }}
927
- />
928
- )}
929
- {phrase !== undefined && (
930
- <TypedConfirmField
931
- ref={firstField === "phrase" ? firstFieldRef : undefined}
932
- target={phrase}
933
- match={phraseMatch}
934
- value={typed}
935
- onValueChange={(next) => {
936
- setTyped(next);
937
- edited();
938
- }}
939
- busy={busy}
940
- // Already resolved through this tile's own `labels` prop; handed on so a
941
- // per-instance phrase wording reaches the field.
942
- labels={{ phrase: labels.phrase, phrasePlaceholder: labels.phrasePlaceholder }}
943
- {...fieldError("phrase")}
944
- />
945
- )}
946
- {requirePassword && (
947
- <CurrentPasswordInput
948
- ref={firstField === "password" ? firstFieldRef : undefined}
949
- label={labels.password}
950
- value={password}
951
- busy={busy}
952
- onValueChange={(next) => {
953
- setPassword(next);
954
- edited();
955
- }}
956
- {...fieldError("password")}
957
- />
958
- )}
959
- {errorOn === "line" && errorAlert !== undefined && (
960
- <p className={cn(FIELD_ERROR_CLASS, "mt-0")}>{errorAlert}</p>
961
- )}
962
- <div className="flex flex-wrap gap-2">
963
- <Button id={cancelId} type="button" variant="ghost" disabled={busy} onClick={() => setArmed(false)}>
964
- {labels.cancel}
965
- </Button>
966
- <Button
967
- id={confirmId}
968
- type="submit"
969
- variant={confirmVariant ?? (tone === "warning" ? "default" : "danger")}
970
- disabled={!canConfirm}
971
- // Held by a guard (the caller's or a built-in one), or armed and then locked
972
- // (or rendered armed under a lock): the confirm says why the way Button
973
- // does — focusable, `aria-disabled`, the reason in its tooltip and
974
- // description, a press swallowed (the submit with it) — and the fields stay
975
- // as typed. Only busy is the native `disabled`.
976
- disabledReason={confirmReason}
977
- aria-busy={busy || undefined}
978
- >
979
- {busy && <Spinner label={null} className="h-4 w-4" />}
980
- {confirmLabel ?? labels.confirm}
981
- </Button>
982
- </div>
983
- {locked && <p className="text-xs text-muted">{lockedReason}</p>}
984
- </form>
985
- </div>
986
- );
987
- }