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