@eifi1/ui-kit 0.54.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (847) hide show
  1. package/README.md +90 -76
  2. package/dist/admin/plan-change.js +2 -2
  3. package/dist/admin/plan-change.js.map +1 -1
  4. package/dist/admin/user-roster.d.ts +6 -0
  5. package/dist/admin/user-roster.js +4 -0
  6. package/dist/admin/user-roster.js.map +1 -1
  7. package/dist/billing/billing-labels.d.ts +26 -0
  8. package/dist/billing/billing-labels.js +9 -0
  9. package/dist/billing/billing-labels.js.map +1 -1
  10. package/dist/billing/subscription-standing.d.ts +61 -0
  11. package/dist/billing/subscription-standing.js +51 -0
  12. package/dist/billing/subscription-standing.js.map +1 -0
  13. package/dist/billing/usage-meter.d.ts +52 -0
  14. package/dist/billing/usage-meter.js +52 -0
  15. package/dist/billing/usage-meter.js.map +1 -0
  16. package/dist/chart.d.ts +1 -0
  17. package/dist/chart.js +4 -0
  18. package/dist/chart.js.map +1 -1
  19. package/dist/components/alert-banner.js +2 -3
  20. package/dist/components/alert-banner.js.map +1 -1
  21. package/dist/components/amount-input.js +3 -15
  22. package/dist/components/amount-input.js.map +1 -1
  23. package/dist/components/autocomplete.js +2 -2
  24. package/dist/components/autocomplete.js.map +1 -1
  25. package/dist/components/bulk-action-bar.js +2 -1
  26. package/dist/components/bulk-action-bar.js.map +1 -1
  27. package/dist/components/button.d.ts +35 -1
  28. package/dist/components/button.js +5 -9
  29. package/dist/components/button.js.map +1 -1
  30. package/dist/components/calendar-heatmap.js +2 -2
  31. package/dist/components/calendar-heatmap.js.map +1 -1
  32. package/dist/components/camera-button.d.ts +89 -0
  33. package/dist/components/camera-button.js +122 -0
  34. package/dist/components/camera-button.js.map +1 -0
  35. package/dist/components/camera-capture.d.ts +66 -0
  36. package/dist/components/camera-capture.js +190 -0
  37. package/dist/components/camera-capture.js.map +1 -0
  38. package/dist/components/camera-labels.d.ts +20 -0
  39. package/dist/components/camera-labels.js +15 -0
  40. package/dist/components/camera-labels.js.map +1 -0
  41. package/dist/components/chart-edge.d.ts +9 -0
  42. package/dist/components/chart-edge.js +14 -3
  43. package/dist/components/chart-edge.js.map +1 -1
  44. package/dist/components/chart-zoom-core.js +34 -29
  45. package/dist/components/chart-zoom-core.js.map +1 -1
  46. package/dist/components/checkbox-group.js +1 -1
  47. package/dist/components/checkbox-group.js.map +1 -1
  48. package/dist/components/combobox-core.js +3 -2
  49. package/dist/components/combobox-core.js.map +1 -1
  50. package/dist/components/combobox.js +2 -2
  51. package/dist/components/combobox.js.map +1 -1
  52. package/dist/components/consent-again-notice-labels.d.ts +25 -0
  53. package/dist/components/consent-again-notice-labels.js +15 -0
  54. package/dist/components/consent-again-notice-labels.js.map +1 -0
  55. package/dist/components/consent-again-notice.d.ts +85 -0
  56. package/dist/components/consent-again-notice.js +94 -0
  57. package/dist/components/consent-again-notice.js.map +1 -0
  58. package/dist/components/country-select.js +2 -7
  59. package/dist/components/country-select.js.map +1 -1
  60. package/dist/components/currency-select.js +2 -2
  61. package/dist/components/currency-select.js.map +1 -1
  62. package/dist/components/danger-confirm.js +2 -2
  63. package/dist/components/danger-confirm.js.map +1 -1
  64. package/dist/components/data-table-column-settings.js +2 -2
  65. package/dist/components/data-table-column-settings.js.map +1 -1
  66. package/dist/components/data-table-fit.js.map +1 -1
  67. package/dist/components/data-table-virtual.js +13 -3
  68. package/dist/components/data-table-virtual.js.map +1 -1
  69. package/dist/components/date-field.js +2 -2
  70. package/dist/components/date-field.js.map +1 -1
  71. package/dist/components/date-picker.js +2 -2
  72. package/dist/components/date-picker.js.map +1 -1
  73. package/dist/components/date-range-picker.js +2 -6
  74. package/dist/components/date-range-picker.js.map +1 -1
  75. package/dist/components/dialog-frame.d.ts +3 -1
  76. package/dist/components/dialog-frame.js.map +1 -1
  77. package/dist/components/dropdown.js +7 -3
  78. package/dist/components/dropdown.js.map +1 -1
  79. package/dist/components/entity-combobox.js +2 -2
  80. package/dist/components/entity-combobox.js.map +1 -1
  81. package/dist/components/field-parts.d.ts +108 -6
  82. package/dist/components/field-parts.js +59 -6
  83. package/dist/components/field-parts.js.map +1 -1
  84. package/dist/components/field-suggestion-labels.d.ts +2 -0
  85. package/dist/components/field-suggestion-labels.js +10 -0
  86. package/dist/components/field-suggestion-labels.js.map +1 -0
  87. package/dist/components/field.js +1 -1
  88. package/dist/components/field.js.map +1 -1
  89. package/dist/components/file-button.d.ts +1 -1
  90. package/dist/components/file-button.js.map +1 -1
  91. package/dist/components/floating-panel.d.ts +7 -6
  92. package/dist/components/floating-panel.js +3 -17
  93. package/dist/components/floating-panel.js.map +1 -1
  94. package/dist/components/form-actions.d.ts +3 -2
  95. package/dist/components/form-actions.js.map +1 -1
  96. package/dist/components/hover-menu.js +3 -2
  97. package/dist/components/hover-menu.js.map +1 -1
  98. package/dist/components/icon-button.d.ts +23 -5
  99. package/dist/components/icon-button.js +6 -8
  100. package/dist/components/icon-button.js.map +1 -1
  101. package/dist/components/inline-confirm.js +2 -1
  102. package/dist/components/inline-confirm.js.map +1 -1
  103. package/dist/components/inline-entity-combobox.js +2 -2
  104. package/dist/components/inline-entity-combobox.js.map +1 -1
  105. package/dist/components/input.js +2 -2
  106. package/dist/components/input.js.map +1 -1
  107. package/dist/components/jump-calendar.js +3 -3
  108. package/dist/components/jump-calendar.js.map +1 -1
  109. package/dist/components/legal.d.ts +13 -1
  110. package/dist/components/legal.js +12 -0
  111. package/dist/components/legal.js.map +1 -1
  112. package/dist/components/legended-series-chart.d.ts +80 -0
  113. package/dist/components/legended-series-chart.js +70 -0
  114. package/dist/components/legended-series-chart.js.map +1 -0
  115. package/dist/components/lightbox.js +2 -1
  116. package/dist/components/lightbox.js.map +1 -1
  117. package/dist/components/mini-calendar.js +13 -5
  118. package/dist/components/mini-calendar.js.map +1 -1
  119. package/dist/components/modal.d.ts +23 -2
  120. package/dist/components/modal.js +24 -6
  121. package/dist/components/modal.js.map +1 -1
  122. package/dist/components/month-picker.d.ts +1 -1
  123. package/dist/components/month-picker.js +6 -6
  124. package/dist/components/month-picker.js.map +1 -1
  125. package/dist/components/multi-entity-combobox.js +2 -2
  126. package/dist/components/multi-entity-combobox.js.map +1 -1
  127. package/dist/components/multi-select.js +2 -6
  128. package/dist/components/multi-select.js.map +1 -1
  129. package/dist/components/number-input.js +2 -2
  130. package/dist/components/number-input.js.map +1 -1
  131. package/dist/components/page-header-layout.d.ts +18 -0
  132. package/dist/components/page-header-layout.js +23 -0
  133. package/dist/components/page-header-layout.js.map +1 -0
  134. package/dist/components/page-header-skeleton.d.ts +41 -0
  135. package/dist/components/page-header-skeleton.js +52 -0
  136. package/dist/components/page-header-skeleton.js.map +1 -0
  137. package/dist/components/page-header.js +4 -17
  138. package/dist/components/page-header.js.map +1 -1
  139. package/dist/components/popover.js +7 -2
  140. package/dist/components/popover.js.map +1 -1
  141. package/dist/components/release-notes-labels.d.ts +16 -0
  142. package/dist/components/release-notes-labels.js +18 -0
  143. package/dist/components/release-notes-labels.js.map +1 -0
  144. package/dist/components/release-notes.d.ts +65 -0
  145. package/dist/components/release-notes.js +65 -0
  146. package/dist/components/release-notes.js.map +1 -0
  147. package/dist/components/select.js +2 -2
  148. package/dist/components/select.js.map +1 -1
  149. package/dist/components/series-chart-labels.d.ts +9 -0
  150. package/dist/components/series-chart-labels.js +3 -1
  151. package/dist/components/series-chart-labels.js.map +1 -1
  152. package/dist/components/series-chart.d.ts +5 -0
  153. package/dist/components/series-chart.js +89 -36
  154. package/dist/components/series-chart.js.map +1 -1
  155. package/dist/components/toggle-group.js +3 -2
  156. package/dist/components/toggle-group.js.map +1 -1
  157. package/dist/components/treemap-layout.js.map +1 -1
  158. package/dist/components/treemap.d.ts +17 -15
  159. package/dist/components/treemap.js +167 -85
  160. package/dist/components/treemap.js.map +1 -1
  161. package/dist/eslint/index.js +1 -1
  162. package/dist/eslint/role-utilities.d.ts +2 -2
  163. package/dist/eslint/role-utilities.js.map +1 -1
  164. package/dist/feedback/feedback-inbox-page.d.ts +260 -0
  165. package/dist/feedback/feedback-inbox-page.js +207 -0
  166. package/dist/feedback/feedback-inbox-page.js.map +1 -0
  167. package/dist/feedback/feedback-vocabulary.js +2 -2
  168. package/dist/feedback/feedback-vocabulary.js.map +1 -1
  169. package/dist/feedback.d.ts +1 -0
  170. package/dist/feedback.js +6 -0
  171. package/dist/feedback.js.map +1 -1
  172. package/dist/hooks/use-debounce.d.ts +32 -5
  173. package/dist/hooks/use-debounce.js +6 -5
  174. package/dist/hooks/use-debounce.js.map +1 -1
  175. package/dist/hooks/use-file-picker.d.ts +3 -1
  176. package/dist/hooks/use-file-picker.js.map +1 -1
  177. package/dist/hooks/use-focus-trap.d.ts +19 -3
  178. package/dist/hooks/use-focus-trap.js +15 -5
  179. package/dist/hooks/use-focus-trap.js.map +1 -1
  180. package/dist/hooks/use-has-camera.d.ts +36 -0
  181. package/dist/hooks/use-has-camera.js +53 -0
  182. package/dist/hooks/use-has-camera.js.map +1 -0
  183. package/dist/hooks/use-hotkey.js +1 -10
  184. package/dist/hooks/use-hotkey.js.map +1 -1
  185. package/dist/hooks/use-overlay-history.d.ts +6 -1
  186. package/dist/hooks/use-overlay-history.js +10 -2
  187. package/dist/hooks/use-overlay-history.js.map +1 -1
  188. package/dist/i18n/defaults.js +11 -1
  189. package/dist/i18n/defaults.js.map +1 -1
  190. package/dist/i18n/german.js +75 -3
  191. package/dist/i18n/german.js.map +1 -1
  192. package/dist/i18n/kit-labels.d.ts +20 -0
  193. package/dist/i18n/kit-labels.js.map +1 -1
  194. package/dist/i18n/locales/en.js +92 -4
  195. package/dist/i18n/locales/en.js.map +3 -3
  196. package/dist/i18n/locales/es.js +71 -3
  197. package/dist/i18n/locales/es.js.map +1 -1
  198. package/dist/i18n/locales/fr.js +72 -2
  199. package/dist/i18n/locales/fr.js.map +1 -1
  200. package/dist/i18n/locales/hu.js +74 -3
  201. package/dist/i18n/locales/hu.js.map +1 -1
  202. package/dist/i18n/locales/it.js +74 -3
  203. package/dist/i18n/locales/it.js.map +1 -1
  204. package/dist/i18n/locales/zh.js +71 -3
  205. package/dist/i18n/locales/zh.js.map +1 -1
  206. package/dist/i18n/review.js +22 -1
  207. package/dist/i18n/review.js.map +1 -1
  208. package/dist/index.d.ts +24 -5
  209. package/dist/index.js +35 -1
  210. package/dist/index.js.map +1 -1
  211. package/dist/landing/landing-labels.d.ts +8 -0
  212. package/dist/landing/landing-labels.js +2 -1
  213. package/dist/landing/landing-labels.js.map +1 -1
  214. package/dist/lib/changelog.d.ts +130 -0
  215. package/dist/lib/changelog.js +137 -0
  216. package/dist/lib/changelog.js.map +1 -0
  217. package/dist/lib/clipboard-minus.js +2 -2
  218. package/dist/lib/clipboard-minus.js.map +1 -1
  219. package/dist/lib/dates.d.ts +29 -3
  220. package/dist/lib/dates.js +41 -12
  221. package/dist/lib/dates.js.map +1 -1
  222. package/dist/lib/editable-content.d.ts +33 -0
  223. package/dist/lib/editable-content.js +15 -0
  224. package/dist/lib/editable-content.js.map +1 -0
  225. package/dist/lib/focus-left.d.ts +47 -1
  226. package/dist/lib/focus-left.js +11 -2
  227. package/dist/lib/focus-left.js.map +1 -1
  228. package/dist/lib/server-wake.d.ts +49 -9
  229. package/dist/lib/server-wake.js +25 -14
  230. package/dist/lib/server-wake.js.map +1 -1
  231. package/dist/lib/session-refresh.d.ts +53 -0
  232. package/dist/lib/session-refresh.js +27 -1
  233. package/dist/lib/session-refresh.js.map +1 -1
  234. package/dist/rhf/fields.js +3 -3
  235. package/dist/rhf/fields.js.map +1 -1
  236. package/dist/shell/app-shell.d.ts +25 -1
  237. package/dist/shell/app-shell.js +3 -1
  238. package/dist/shell/app-shell.js.map +1 -1
  239. package/dist/shell/dev-menu.d.ts +3 -0
  240. package/dist/shell/dev-menu.js +4 -2
  241. package/dist/shell/dev-menu.js.map +1 -1
  242. package/dist/shell/held-changes-banner-labels.d.ts +23 -0
  243. package/dist/shell/held-changes-banner-labels.js +14 -0
  244. package/dist/shell/held-changes-banner-labels.js.map +1 -0
  245. package/dist/shell/held-changes-banner.d.ts +75 -0
  246. package/dist/shell/held-changes-banner.js +106 -0
  247. package/dist/shell/held-changes-banner.js.map +1 -0
  248. package/dist/shell/sync-status-indicator.d.ts +27 -12
  249. package/dist/shell/sync-status-indicator.js +13 -4
  250. package/dist/shell/sync-status-indicator.js.map +1 -1
  251. package/dist/shell/top-bar-parts-labels.d.ts +5 -0
  252. package/dist/shell/top-bar-parts-labels.js +3 -1
  253. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  254. package/dist/shell.d.ts +2 -0
  255. package/dist/shell.js +3 -0
  256. package/dist/shell.js.map +1 -1
  257. package/dist/sync/engine.d.ts +11 -2
  258. package/dist/sync/engine.js +13 -5
  259. package/dist/sync/engine.js.map +1 -1
  260. package/dist/sync/hooks.d.ts +3 -2
  261. package/dist/sync/hooks.js +4 -2
  262. package/dist/sync/hooks.js.map +1 -1
  263. package/dist/testing/css-variables.generated.d.ts +2 -2
  264. package/dist/testing/css-variables.generated.js +1 -1
  265. package/dist/testing/css-variables.generated.js.map +1 -1
  266. package/dist/theme/chart-palette.d.ts +18 -0
  267. package/dist/theme/chart-palette.js +17 -1
  268. package/dist/theme/chart-palette.js.map +1 -1
  269. package/dist/theme/contrast-tokens.d.ts +3 -3
  270. package/dist/theme/contrast-tokens.js.map +1 -1
  271. package/dist/theme/contrast.d.ts +4 -4
  272. package/dist/theme/contrast.js.map +1 -1
  273. package/dist/tour/tour-overlay.js +2 -1
  274. package/dist/tour/tour-overlay.js.map +1 -1
  275. package/package.json +5 -9
  276. package/tokens.css +19 -54
  277. package/src/account/account-parts.ts +0 -47
  278. package/src/account/account-settings-labels.ts +0 -240
  279. package/src/account/account-settings.tsx +0 -698
  280. package/src/account/data-export-setting-labels.ts +0 -20
  281. package/src/account/data-export-setting.tsx +0 -200
  282. package/src/account/delete-account-setting-labels.ts +0 -33
  283. package/src/account/delete-account-setting.tsx +0 -342
  284. package/src/account/email-change-setting-labels.ts +0 -31
  285. package/src/account/email-change-setting.tsx +0 -443
  286. package/src/account/passkeys-setting.tsx +0 -445
  287. package/src/account/sessions-setting-labels.ts +0 -24
  288. package/src/account/sessions-setting.tsx +0 -283
  289. package/src/admin/admin-action-confirm-labels.ts +0 -19
  290. package/src/admin/admin-action-confirm.tsx +0 -509
  291. package/src/admin/admin-action-log-labels.ts +0 -83
  292. package/src/admin/admin-action-log.tsx +0 -464
  293. package/src/admin/admin-area-labels.ts +0 -114
  294. package/src/admin/admin-forbidden.tsx +0 -75
  295. package/src/admin/admin-overview.tsx +0 -258
  296. package/src/admin/admin-parts.ts +0 -68
  297. package/src/admin/admin-sections.tsx +0 -208
  298. package/src/admin/admin-tool-links.tsx +0 -90
  299. package/src/admin/invitations-panel-labels.ts +0 -31
  300. package/src/admin/invitations-panel.tsx +0 -516
  301. package/src/admin/mail-test-card-labels.ts +0 -19
  302. package/src/admin/mail-test-card.tsx +0 -189
  303. package/src/admin/plan-change-labels.ts +0 -5
  304. package/src/admin/plan-change.tsx +0 -474
  305. package/src/admin/reviewer-scope-editor-labels.ts +0 -16
  306. package/src/admin/reviewer-scope-editor.tsx +0 -224
  307. package/src/admin/role-select-labels.ts +0 -16
  308. package/src/admin/role-select.tsx +0 -282
  309. package/src/admin/transfer-ownership-dialog-labels.ts +0 -20
  310. package/src/admin/transfer-ownership-dialog.tsx +0 -162
  311. package/src/admin/user-roster-labels.ts +0 -17
  312. package/src/admin/user-roster.tsx +0 -559
  313. package/src/auth/accept-invitation-labels.ts +0 -21
  314. package/src/auth/accept-invitation.tsx +0 -210
  315. package/src/auth/auth-errors-labels.ts +0 -23
  316. package/src/auth/auth-errors.ts +0 -439
  317. package/src/auth/complete-name-dialog-labels.ts +0 -16
  318. package/src/auth/complete-name-dialog.tsx +0 -253
  319. package/src/auth/email-tag.ts +0 -75
  320. package/src/auth/forgot-password-form-labels.ts +0 -20
  321. package/src/auth/forgot-password-form.tsx +0 -221
  322. package/src/auth/form-rules.ts +0 -40
  323. package/src/auth/new-password-fields.tsx +0 -85
  324. package/src/auth/not-found-page-labels.ts +0 -12
  325. package/src/auth/not-found-page.tsx +0 -95
  326. package/src/auth/register-form-labels.ts +0 -31
  327. package/src/auth/register-form.tsx +0 -456
  328. package/src/auth/reset-password-form-labels.ts +0 -27
  329. package/src/auth/reset-password-form.tsx +0 -341
  330. package/src/auth/sign-in-form-labels.ts +0 -44
  331. package/src/auth/sign-in-form.tsx +0 -858
  332. package/src/auth/status-parts.tsx +0 -132
  333. package/src/auth/verify-email-labels.ts +0 -26
  334. package/src/auth/verify-email.tsx +0 -445
  335. package/src/billing/billing-banner.tsx +0 -258
  336. package/src/billing/billing-labels.ts +0 -381
  337. package/src/billing/billing-lock.ts +0 -108
  338. package/src/billing/billing-overview.ts +0 -157
  339. package/src/billing/billing-standing.ts +0 -80
  340. package/src/billing/cancel-request.ts +0 -97
  341. package/src/billing/cancel-subscription.tsx +0 -98
  342. package/src/billing/checkout-processing.ts +0 -394
  343. package/src/billing/checkout-return.ts +0 -90
  344. package/src/billing/pay-page.ts +0 -330
  345. package/src/billing/plan-card.tsx +0 -562
  346. package/src/billing/plan-change-labels.ts +0 -66
  347. package/src/billing/plan-limit-notice.tsx +0 -148
  348. package/src/billing/plan-limit-toast.tsx +0 -90
  349. package/src/billing/plan-limit.ts +0 -52
  350. package/src/billing/plan-price.ts +0 -98
  351. package/src/billing/plan-switch.tsx +0 -216
  352. package/src/billing/provider-page.ts +0 -84
  353. package/src/billing/subscription-actions.tsx +0 -247
  354. package/src/billing/subscription-status-chip.tsx +0 -95
  355. package/src/chart.ts +0 -103
  356. package/src/components/account-chips-labels.ts +0 -16
  357. package/src/components/account-chips.tsx +0 -474
  358. package/src/components/alert-banner.tsx +0 -670
  359. package/src/components/amount-input.tsx +0 -816
  360. package/src/components/appearance-labels.ts +0 -63
  361. package/src/components/authed-image-labels.ts +0 -11
  362. package/src/components/authed-image.tsx +0 -209
  363. package/src/components/autocomplete.tsx +0 -645
  364. package/src/components/breadcrumbs-labels.ts +0 -10
  365. package/src/components/breadcrumbs.tsx +0 -205
  366. package/src/components/bulk-action-bar-labels.ts +0 -11
  367. package/src/components/bulk-action-bar.tsx +0 -443
  368. package/src/components/button-group.tsx +0 -223
  369. package/src/components/button-look.ts +0 -256
  370. package/src/components/button.tsx +0 -339
  371. package/src/components/calculator.tsx +0 -341
  372. package/src/components/calendar-heatmap-labels.ts +0 -15
  373. package/src/components/calendar-heatmap.tsx +0 -600
  374. package/src/components/card.tsx +0 -377
  375. package/src/components/chart-edge.ts +0 -106
  376. package/src/components/chart-figure.tsx +0 -35
  377. package/src/components/chart-height.ts +0 -30
  378. package/src/components/chart-zoom-core.tsx +0 -627
  379. package/src/components/chart-zoom.tsx +0 -22
  380. package/src/components/chart.tsx +0 -554
  381. package/src/components/checkbox-group.tsx +0 -247
  382. package/src/components/checkbox.tsx +0 -346
  383. package/src/components/chip-input.tsx +0 -370
  384. package/src/components/chip-labels.ts +0 -13
  385. package/src/components/chip.tsx +0 -843
  386. package/src/components/choice-card.tsx +0 -544
  387. package/src/components/column-mapper-labels.ts +0 -38
  388. package/src/components/column-mapper.tsx +0 -655
  389. package/src/components/combobox-core.tsx +0 -1321
  390. package/src/components/combobox-suggestions.tsx +0 -131
  391. package/src/components/combobox.tsx +0 -716
  392. package/src/components/confirm-context.ts +0 -7
  393. package/src/components/confirm-dialog-labels.ts +0 -13
  394. package/src/components/confirm-dialog.tsx +0 -341
  395. package/src/components/copy-button-labels.ts +0 -13
  396. package/src/components/copy-button.tsx +0 -192
  397. package/src/components/country-select-labels.ts +0 -11
  398. package/src/components/country-select.tsx +0 -539
  399. package/src/components/currency-option-list.tsx +0 -188
  400. package/src/components/currency-select.tsx +0 -343
  401. package/src/components/danger-confirm-labels.ts +0 -20
  402. package/src/components/danger-confirm.tsx +0 -987
  403. package/src/components/data-table-cells.tsx +0 -118
  404. package/src/components/data-table-column-settings.tsx +0 -198
  405. package/src/components/data-table-filter-popover.tsx +0 -289
  406. package/src/components/data-table-filters.ts +0 -315
  407. package/src/components/data-table-fit.ts +0 -301
  408. package/src/components/data-table-groups.tsx +0 -288
  409. package/src/components/data-table-head.tsx +0 -280
  410. package/src/components/data-table-labels.ts +0 -198
  411. package/src/components/data-table-leading-row.tsx +0 -58
  412. package/src/components/data-table-mobile.tsx +0 -1117
  413. package/src/components/data-table-pagination.tsx +0 -202
  414. package/src/components/data-table-resize.ts +0 -188
  415. package/src/components/data-table-row-actions.tsx +0 -302
  416. package/src/components/data-table-row.tsx +0 -496
  417. package/src/components/data-table-selection.ts +0 -71
  418. package/src/components/data-table-shared.tsx +0 -287
  419. package/src/components/data-table-sort.ts +0 -163
  420. package/src/components/data-table-virtual.ts +0 -576
  421. package/src/components/data-table.tsx +0 -2598
  422. package/src/components/date-field.tsx +0 -684
  423. package/src/components/date-format-setting.tsx +0 -64
  424. package/src/components/date-picker.tsx +0 -404
  425. package/src/components/date-range-picker.tsx +0 -518
  426. package/src/components/description-list-labels.ts +0 -9
  427. package/src/components/description-list.tsx +0 -386
  428. package/src/components/dialog-frame-labels.ts +0 -7
  429. package/src/components/dialog-frame.tsx +0 -284
  430. package/src/components/disclosure.tsx +0 -476
  431. package/src/components/dropdown.tsx +0 -461
  432. package/src/components/empty-state.tsx +0 -136
  433. package/src/components/entity-combobox.tsx +0 -422
  434. package/src/components/error-boundary-labels.ts +0 -20
  435. package/src/components/error-boundary.tsx +0 -675
  436. package/src/components/facing-pair.ts +0 -93
  437. package/src/components/field-base-labels.ts +0 -20
  438. package/src/components/field-base.tsx +0 -656
  439. package/src/components/field-parts.tsx +0 -825
  440. package/src/components/field-strip.tsx +0 -129
  441. package/src/components/field.tsx +0 -206
  442. package/src/components/file-button.tsx +0 -295
  443. package/src/components/file-dropzone.tsx +0 -559
  444. package/src/components/floating-panel-labels.ts +0 -10
  445. package/src/components/floating-panel.tsx +0 -828
  446. package/src/components/focus-ring.ts +0 -16
  447. package/src/components/form-actions-labels.ts +0 -11
  448. package/src/components/form-actions.tsx +0 -578
  449. package/src/components/full-bleed-dialog.tsx +0 -294
  450. package/src/components/grouped-picker.tsx +0 -184
  451. package/src/components/help-popover.tsx +0 -117
  452. package/src/components/hover-menu.tsx +0 -343
  453. package/src/components/iban-input-labels.ts +0 -14
  454. package/src/components/iban-input.tsx +0 -236
  455. package/src/components/icon-button.tsx +0 -959
  456. package/src/components/icon-picker-labels.ts +0 -13
  457. package/src/components/icon-picker.tsx +0 -232
  458. package/src/components/image-grid-labels.ts +0 -11
  459. package/src/components/image-grid.tsx +0 -202
  460. package/src/components/inline-confirm.tsx +0 -116
  461. package/src/components/inline-edit-field-labels.ts +0 -11
  462. package/src/components/inline-edit-field.tsx +0 -552
  463. package/src/components/inline-entity-combobox.tsx +0 -849
  464. package/src/components/input.tsx +0 -394
  465. package/src/components/jump-calendar.tsx +0 -265
  466. package/src/components/language-select.tsx +0 -93
  467. package/src/components/legal-labels.ts +0 -105
  468. package/src/components/legal-page.tsx +0 -711
  469. package/src/components/legal.tsx +0 -668
  470. package/src/components/lightbox-labels.ts +0 -18
  471. package/src/components/lightbox.tsx +0 -399
  472. package/src/components/line-items-labels.ts +0 -14
  473. package/src/components/line-items.tsx +0 -602
  474. package/src/components/list-labels.ts +0 -12
  475. package/src/components/list.tsx +0 -870
  476. package/src/components/loading-state.tsx +0 -78
  477. package/src/components/measured-grid-labels.ts +0 -25
  478. package/src/components/measured-grid.tsx +0 -837
  479. package/src/components/menu-item.tsx +0 -241
  480. package/src/components/mini-calendar-labels.ts +0 -17
  481. package/src/components/mini-calendar.tsx +0 -792
  482. package/src/components/modal.tsx +0 -534
  483. package/src/components/money-draft.ts +0 -83
  484. package/src/components/money-field.tsx +0 -76
  485. package/src/components/month-grid.tsx +0 -229
  486. package/src/components/month-picker-labels.ts +0 -22
  487. package/src/components/month-picker.tsx +0 -1087
  488. package/src/components/multi-entity-combobox.tsx +0 -369
  489. package/src/components/multi-select.tsx +0 -376
  490. package/src/components/nav-pills.tsx +0 -198
  491. package/src/components/number-field.tsx +0 -327
  492. package/src/components/number-input.tsx +0 -559
  493. package/src/components/numeric-field.ts +0 -169
  494. package/src/components/numpad-sheet.tsx +0 -285
  495. package/src/components/one-time-code-input.tsx +0 -270
  496. package/src/components/page-contents-labels.ts +0 -9
  497. package/src/components/page-contents.tsx +0 -282
  498. package/src/components/page-header-context.ts +0 -8
  499. package/src/components/page-header.tsx +0 -298
  500. package/src/components/password-strength-labels.ts +0 -22
  501. package/src/components/password-strength.tsx +0 -241
  502. package/src/components/phone-input-labels.ts +0 -10
  503. package/src/components/phone-input.tsx +0 -282
  504. package/src/components/picker-sheet.tsx +0 -330
  505. package/src/components/pie-chart-labels.ts +0 -40
  506. package/src/components/pie-chart.tsx +0 -480
  507. package/src/components/popover-labels.ts +0 -14
  508. package/src/components/popover.tsx +0 -268
  509. package/src/components/progress-bar-labels.ts +0 -10
  510. package/src/components/progress-bar.tsx +0 -479
  511. package/src/components/qr-code.tsx +0 -76
  512. package/src/components/reauth-dialog-labels.ts +0 -13
  513. package/src/components/reauth-dialog.tsx +0 -265
  514. package/src/components/row-actions-labels.ts +0 -12
  515. package/src/components/row-actions.tsx +0 -795
  516. package/src/components/scroll-area.tsx +0 -123
  517. package/src/components/search-field.tsx +0 -192
  518. package/src/components/select.tsx +0 -294
  519. package/src/components/separator.tsx +0 -33
  520. package/src/components/series-chart-axes.ts +0 -342
  521. package/src/components/series-chart-budget.ts +0 -150
  522. package/src/components/series-chart-labels.ts +0 -33
  523. package/src/components/series-chart-thin.ts +0 -180
  524. package/src/components/series-chart-ticks.ts +0 -194
  525. package/src/components/series-chart.tsx +0 -1906
  526. package/src/components/server-wake-labels.ts +0 -11
  527. package/src/components/server-wake.tsx +0 -129
  528. package/src/components/settings-fields.tsx +0 -237
  529. package/src/components/share-card-labels.ts +0 -30
  530. package/src/components/share-card.tsx +0 -675
  531. package/src/components/signature-pad-labels.ts +0 -24
  532. package/src/components/signature-pad.tsx +0 -747
  533. package/src/components/signed-amount-labels.ts +0 -10
  534. package/src/components/signed-amount.tsx +0 -336
  535. package/src/components/skeleton.tsx +0 -80
  536. package/src/components/slider.tsx +0 -338
  537. package/src/components/sparkline-labels.ts +0 -14
  538. package/src/components/sparkline.tsx +0 -322
  539. package/src/components/spinner.tsx +0 -81
  540. package/src/components/stat-tile-labels.ts +0 -15
  541. package/src/components/stat-tile.tsx +0 -754
  542. package/src/components/status-dot.tsx +0 -170
  543. package/src/components/swatch-picker-labels.ts +0 -10
  544. package/src/components/swatch-picker.tsx +0 -283
  545. package/src/components/swipeable-row.tsx +0 -386
  546. package/src/components/switch.tsx +0 -273
  547. package/src/components/table-skeleton.tsx +0 -136
  548. package/src/components/table.tsx +0 -647
  549. package/src/components/tabs-labels.ts +0 -13
  550. package/src/components/tabs.tsx +0 -693
  551. package/src/components/text-link.tsx +0 -359
  552. package/src/components/text.tsx +0 -150
  553. package/src/components/textarea.tsx +0 -330
  554. package/src/components/tile-radio.tsx +0 -332
  555. package/src/components/time-input.tsx +0 -121
  556. package/src/components/toast-labels.ts +0 -12
  557. package/src/components/toast.tsx +0 -519
  558. package/src/components/toggle-group.tsx +0 -752
  559. package/src/components/toggle-legend.tsx +0 -394
  560. package/src/components/tooltip.tsx +0 -1149
  561. package/src/components/translation-review-editor.tsx +0 -290
  562. package/src/components/translation-review-labels.ts +0 -181
  563. package/src/components/translation-review-parts.tsx +0 -272
  564. package/src/components/translation-review.tsx +0 -1240
  565. package/src/components/tree-view.tsx +0 -589
  566. package/src/components/treemap-labels.ts +0 -47
  567. package/src/components/treemap-layout.ts +0 -210
  568. package/src/components/treemap.tsx +0 -1184
  569. package/src/components/trigger-aria.ts +0 -44
  570. package/src/components/use-anchor-dir.ts +0 -20
  571. package/src/components/use-mobile-reveal.ts +0 -62
  572. package/src/components/use-table-state.ts +0 -753
  573. package/src/components/user-avatar.tsx +0 -116
  574. package/src/components/wizard-stepper.tsx +0 -42
  575. package/src/components/write-lock-labels.ts +0 -10
  576. package/src/components/write-lock.tsx +0 -253
  577. package/src/currencies.ts +0 -90
  578. package/src/data-table.ts +0 -42
  579. package/src/demo/demo-banner.tsx +0 -153
  580. package/src/demo/demo-countdown.ts +0 -136
  581. package/src/demo/demo-ended.tsx +0 -90
  582. package/src/demo/demo-labels.ts +0 -78
  583. package/src/demo/demo-session.ts +0 -32
  584. package/src/demo/demo-start.tsx +0 -156
  585. package/src/eslint/index.ts +0 -161
  586. package/src/eslint/role-utilities.generated.ts +0 -146
  587. package/src/eslint/role-utilities.ts +0 -233
  588. package/src/feedback/feedback-attachment-download.tsx +0 -77
  589. package/src/feedback/feedback-attachment-labels.ts +0 -37
  590. package/src/feedback/feedback-attachment.tsx +0 -1239
  591. package/src/feedback/feedback-capture.ts +0 -287
  592. package/src/feedback/feedback-comment-thread.tsx +0 -353
  593. package/src/feedback/feedback-context-labels.ts +0 -11
  594. package/src/feedback/feedback-context.tsx +0 -245
  595. package/src/feedback/feedback-crash.ts +0 -547
  596. package/src/feedback/feedback-diagnostics.tsx +0 -41
  597. package/src/feedback/feedback-dialog-labels.ts +0 -29
  598. package/src/feedback/feedback-dialog.tsx +0 -452
  599. package/src/feedback/feedback-entry-file.tsx +0 -150
  600. package/src/feedback/feedback-inbox.tsx +0 -552
  601. package/src/feedback/feedback-labels.ts +0 -144
  602. package/src/feedback/feedback-menu-labels.ts +0 -12
  603. package/src/feedback/feedback-menu.tsx +0 -177
  604. package/src/feedback/feedback-mutation.ts +0 -20
  605. package/src/feedback/feedback-page-link.ts +0 -90
  606. package/src/feedback/feedback-public-labels.ts +0 -81
  607. package/src/feedback/feedback-public-list.tsx +0 -524
  608. package/src/feedback/feedback-public-switch.tsx +0 -102
  609. package/src/feedback/feedback-public-types.ts +0 -101
  610. package/src/feedback/feedback-record.ts +0 -428
  611. package/src/feedback/feedback-replies-context.ts +0 -9
  612. package/src/feedback/feedback-replies.tsx +0 -343
  613. package/src/feedback/feedback-rework-entry-chip.tsx +0 -18
  614. package/src/feedback/feedback-row-detail-labels.ts +0 -31
  615. package/src/feedback/feedback-row-detail.tsx +0 -871
  616. package/src/feedback/feedback-status-undo.ts +0 -109
  617. package/src/feedback/feedback-submit-dialog.tsx +0 -131
  618. package/src/feedback/feedback-submit.tsx +0 -270
  619. package/src/feedback/feedback-swipe.tsx +0 -192
  620. package/src/feedback/feedback-table-labels.ts +0 -27
  621. package/src/feedback/feedback-table.tsx +0 -912
  622. package/src/feedback/feedback-thread-labels.ts +0 -22
  623. package/src/feedback/feedback-thread-parts-labels.ts +0 -41
  624. package/src/feedback/feedback-thread.tsx +0 -905
  625. package/src/feedback/feedback-vocabulary.ts +0 -263
  626. package/src/feedback/feedback-vote-button.tsx +0 -124
  627. package/src/feedback.ts +0 -116
  628. package/src/hooks/use-anchored-panel.ts +0 -396
  629. package/src/hooks/use-anchored-rect.ts +0 -77
  630. package/src/hooks/use-announce.ts +0 -85
  631. package/src/hooks/use-authed-src.ts +0 -167
  632. package/src/hooks/use-body-scroll-lock.ts +0 -119
  633. package/src/hooks/use-breakpoint.ts +0 -133
  634. package/src/hooks/use-close-transition.ts +0 -107
  635. package/src/hooks/use-copy-to-clipboard.ts +0 -122
  636. package/src/hooks/use-debounce.ts +0 -114
  637. package/src/hooks/use-dismiss.ts +0 -371
  638. package/src/hooks/use-document-title.ts +0 -33
  639. package/src/hooks/use-file-drop.ts +0 -121
  640. package/src/hooks/use-file-picker-labels.ts +0 -28
  641. package/src/hooks/use-file-picker.tsx +0 -359
  642. package/src/hooks/use-focus-trap.ts +0 -199
  643. package/src/hooks/use-hotkey.ts +0 -212
  644. package/src/hooks/use-large-text.ts +0 -41
  645. package/src/hooks/use-long-press.ts +0 -140
  646. package/src/hooks/use-media-query.ts +0 -39
  647. package/src/hooks/use-mounted.ts +0 -39
  648. package/src/hooks/use-noindex.ts +0 -37
  649. package/src/hooks/use-overlay-history.ts +0 -714
  650. package/src/hooks/use-row-swipe.ts +0 -207
  651. package/src/hooks/use-search-param-state.ts +0 -434
  652. package/src/hooks/use-windowed-rows.ts +0 -225
  653. package/src/i18n/defaults.ts +0 -267
  654. package/src/i18n/german.ts +0 -2059
  655. package/src/i18n/kit-labels.tsx +0 -1003
  656. package/src/i18n/languages.ts +0 -349
  657. package/src/i18n/locales/de-CH.ts +0 -24
  658. package/src/i18n/locales/en.ts +0 -267
  659. package/src/i18n/locales/es.ts +0 -1999
  660. package/src/i18n/locales/fr.ts +0 -2037
  661. package/src/i18n/locales/hu.ts +0 -2004
  662. package/src/i18n/locales/it.ts +0 -2014
  663. package/src/i18n/locales/zh.ts +0 -1912
  664. package/src/i18n/plurals.ts +0 -86
  665. package/src/i18n/review.ts +0 -475
  666. package/src/i18n/shared-labels.ts +0 -138
  667. package/src/i18n/swiss.ts +0 -29
  668. package/src/index.ts +0 -1191
  669. package/src/landing/access.ts +0 -93
  670. package/src/landing/landing-actions.tsx +0 -97
  671. package/src/landing/landing-labels.ts +0 -59
  672. package/src/landing/landing-sections.tsx +0 -341
  673. package/src/landing/page-seo.ts +0 -261
  674. package/src/landing/public-header.tsx +0 -121
  675. package/src/landing/public-page.tsx +0 -106
  676. package/src/landing/routing.tsx +0 -225
  677. package/src/lib/broadcast.ts +0 -52
  678. package/src/lib/calc.ts +0 -323
  679. package/src/lib/chip-edge-snap.ts +0 -212
  680. package/src/lib/clipboard-minus.ts +0 -107
  681. package/src/lib/clipping.ts +0 -34
  682. package/src/lib/cn.ts +0 -28
  683. package/src/lib/column-mapping.ts +0 -234
  684. package/src/lib/countries.ts +0 -91
  685. package/src/lib/data-attributes.ts +0 -14
  686. package/src/lib/date-format.ts +0 -227
  687. package/src/lib/dates.ts +0 -288
  688. package/src/lib/day-format.ts +0 -96
  689. package/src/lib/decimal-marks.ts +0 -108
  690. package/src/lib/describe-failure.ts +0 -18
  691. package/src/lib/device-settings.ts +0 -147
  692. package/src/lib/direction.ts +0 -74
  693. package/src/lib/document-navigation.ts +0 -17
  694. package/src/lib/document-title.ts +0 -41
  695. package/src/lib/download.ts +0 -172
  696. package/src/lib/float-clearance.ts +0 -70
  697. package/src/lib/floating-stack.ts +0 -70
  698. package/src/lib/focus-left.ts +0 -156
  699. package/src/lib/format.ts +0 -585
  700. package/src/lib/http-status.ts +0 -38
  701. package/src/lib/iban.ts +0 -251
  702. package/src/lib/ime.ts +0 -24
  703. package/src/lib/intl-cache.ts +0 -27
  704. package/src/lib/iso-day.ts +0 -13
  705. package/src/lib/lazy-with-fallback.ts +0 -82
  706. package/src/lib/logger.ts +0 -69
  707. package/src/lib/minus.ts +0 -50
  708. package/src/lib/path-pattern.ts +0 -55
  709. package/src/lib/person-name.ts +0 -155
  710. package/src/lib/phone.ts +0 -208
  711. package/src/lib/plain-text.ts +0 -22
  712. package/src/lib/presence.ts +0 -18
  713. package/src/lib/qr-encode.ts +0 -444
  714. package/src/lib/quiet-focus.ts +0 -32
  715. package/src/lib/reduced-motion.ts +0 -22
  716. package/src/lib/refs.ts +0 -22
  717. package/src/lib/round.ts +0 -43
  718. package/src/lib/safe-storage.ts +0 -119
  719. package/src/lib/server-wake.ts +0 -315
  720. package/src/lib/session-refresh.ts +0 -472
  721. package/src/lib/share-format.ts +0 -18
  722. package/src/lib/status-tone.ts +0 -43
  723. package/src/lib/strip-fade.ts +0 -287
  724. package/src/lib/table-text.ts +0 -554
  725. package/src/lib/text-case.ts +0 -19
  726. package/src/lib/text-match.ts +0 -169
  727. package/src/lib/thenable.ts +0 -19
  728. package/src/lib/translation-review.ts +0 -769
  729. package/src/notifications/device-zone-report.ts +0 -67
  730. package/src/notifications/feedback-notification-types-labels.ts +0 -33
  731. package/src/notifications/feedback-notification-types.ts +0 -71
  732. package/src/notifications/notification-bell.tsx +0 -119
  733. package/src/notifications/notification-inbox.tsx +0 -309
  734. package/src/notifications/notification-parts.tsx +0 -81
  735. package/src/notifications/notification-types-setting.tsx +0 -406
  736. package/src/notifications/notification-types.ts +0 -89
  737. package/src/notifications/notifications-labels.ts +0 -287
  738. package/src/notifications/push-device-setting.tsx +0 -230
  739. package/src/notifications/push-devices-setting.tsx +0 -374
  740. package/src/notifications/push-worker.ts +0 -168
  741. package/src/notifications/quiet-hours-setting.tsx +0 -238
  742. package/src/notifications/unsubscribe-panel.tsx +0 -200
  743. package/src/notifications/use-push-device.ts +0 -448
  744. package/src/offline/local-first.ts +0 -100
  745. package/src/offline/pwa-update-prompt-labels.ts +0 -9
  746. package/src/offline/pwa-update-prompt.tsx +0 -78
  747. package/src/offline/query-persistence.ts +0 -391
  748. package/src/offline/service-worker-updates.ts +0 -81
  749. package/src/offline/shared-computer-labels.ts +0 -8
  750. package/src/offline/shared-computer.tsx +0 -87
  751. package/src/offline/sign-out-pending-dialog-labels.ts +0 -21
  752. package/src/offline/sign-out-pending-dialog.tsx +0 -135
  753. package/src/offline.ts +0 -37
  754. package/src/push-worker.ts +0 -25
  755. package/src/rhf/fields.tsx +0 -2187
  756. package/src/rhf/form-core.tsx +0 -324
  757. package/src/rhf/form.tsx +0 -12
  758. package/src/rhf/line-items.tsx +0 -135
  759. package/src/rhf/use-rhf-wizard-step.ts +0 -104
  760. package/src/rhf.ts +0 -21
  761. package/src/search/command-palette-labels.ts +0 -16
  762. package/src/search/command-palette.tsx +0 -624
  763. package/src/search/global-search-labels.ts +0 -13
  764. package/src/search/global-search.tsx +0 -660
  765. package/src/search/search-index.ts +0 -283
  766. package/src/search/use-command-key.ts +0 -23
  767. package/src/search.ts +0 -14
  768. package/src/settings/device-reset-setting-labels.ts +0 -20
  769. package/src/settings/device-reset-setting.tsx +0 -116
  770. package/src/settings/settings-card-classes.ts +0 -11
  771. package/src/settings/settings-catalogue.ts +0 -150
  772. package/src/settings/settings-context.ts +0 -33
  773. package/src/settings/settings-heading.tsx +0 -67
  774. package/src/settings/settings-labels.ts +0 -87
  775. package/src/settings/settings-layout.tsx +0 -471
  776. package/src/settings/settings-section.tsx +0 -108
  777. package/src/settings/use-account-appearance.ts +0 -148
  778. package/src/settings/use-account-language.ts +0 -146
  779. package/src/settings/use-settings-focus.ts +0 -128
  780. package/src/settings/use-settings-route.ts +0 -258
  781. package/src/shell/account-menu-language.tsx +0 -130
  782. package/src/shell/account-menu-text-size.tsx +0 -80
  783. package/src/shell/admin-menu.tsx +0 -183
  784. package/src/shell/app-shell-labels.ts +0 -11
  785. package/src/shell/app-shell.tsx +0 -1560
  786. package/src/shell/auth-layout.tsx +0 -186
  787. package/src/shell/company-switcher-labels.ts +0 -13
  788. package/src/shell/company-switcher.tsx +0 -136
  789. package/src/shell/dev-menu.tsx +0 -257
  790. package/src/shell/fill-height.tsx +0 -45
  791. package/src/shell/language-code.ts +0 -5
  792. package/src/shell/option-switcher-menu.tsx +0 -84
  793. package/src/shell/sync-status-indicator.tsx +0 -303
  794. package/src/shell/top-bar-actions.tsx +0 -87
  795. package/src/shell/top-bar-brand.tsx +0 -78
  796. package/src/shell/top-bar-parts-labels.ts +0 -148
  797. package/src/shell/top-bar.tsx +0 -40
  798. package/src/shell/topbar-action-menu.tsx +0 -567
  799. package/src/shell/topbar-controls.tsx +0 -269
  800. package/src/shell/tour-menu.tsx +0 -187
  801. package/src/shell.ts +0 -108
  802. package/src/sync/db.ts +0 -129
  803. package/src/sync/engine.ts +0 -1011
  804. package/src/sync/hooks.ts +0 -98
  805. package/src/sync/testing.ts +0 -73
  806. package/src/sync/wire.ts +0 -61
  807. package/src/sync.ts +0 -37
  808. package/src/table-text.ts +0 -8
  809. package/src/testing/css-variables.generated.ts +0 -112
  810. package/src/testing/css-variables.ts +0 -189
  811. package/src/testing/index.ts +0 -29
  812. package/src/testing/react.ts +0 -58
  813. package/src/testing/tour.ts +0 -41
  814. package/src/testing/viewport.ts +0 -357
  815. package/src/theme/chart-palette.ts +0 -232
  816. package/src/theme/color.ts +0 -272
  817. package/src/theme/contrast-tokens.ts +0 -268
  818. package/src/theme/contrast.ts +0 -250
  819. package/src/theme/palette-derive.ts +0 -825
  820. package/src/theme/palette-presets.ts +0 -544
  821. package/src/theme/palette-store.ts +0 -108
  822. package/src/theme/text-size.ts +0 -289
  823. package/src/theme/theme-store.ts +0 -157
  824. package/src/tour/tour-catalogue-labels.ts +0 -75
  825. package/src/tour/tour-catalogue.tsx +0 -335
  826. package/src/tour/tour-dock.ts +0 -134
  827. package/src/tour/tour-engine.ts +0 -37
  828. package/src/tour/tour-gates.ts +0 -218
  829. package/src/tour/tour-guide-button.tsx +0 -64
  830. package/src/tour/tour-guide-labels.ts +0 -15
  831. package/src/tour/tour-info.ts +0 -144
  832. package/src/tour/tour-labels.ts +0 -23
  833. package/src/tour/tour-overlay.tsx +0 -1170
  834. package/src/tour/tour.tsx +0 -750
  835. package/src/tour/use-tour-progress.ts +0 -671
  836. package/src/tour/use-tour-url-sync.ts +0 -266
  837. package/src/tour.ts +0 -21
  838. package/src/vite-env.d.ts +0 -23
  839. package/src/wizard/stepper-nav.tsx +0 -360
  840. package/src/wizard/types.ts +0 -275
  841. package/src/wizard/use-wizard.ts +0 -560
  842. package/src/wizard/validation.ts +0 -39
  843. package/src/wizard/wizard-context.tsx +0 -74
  844. package/src/wizard/wizard-labels.ts +0 -29
  845. package/src/wizard/wizard-step.tsx +0 -76
  846. package/src/wizard/wizard-summary.tsx +0 -84
  847. package/src/wizard.ts +0 -15
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/combobox.tsx"],"sourcesContent":["import { useId, useMemo, useRef, useState } from \"react\";\nimport type { ComponentPropsWithoutRef, KeyboardEvent, ReactNode, Ref } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { FIELD_BASE, FIELD_FLOATING_PAD, FIELD_INVALID } from \"./field-base\";\nimport { cn } from \"../lib/cn\";\nimport { useDropdown } from \"./dropdown\";\nimport { takeEscape, useDismissLayer } from \"../hooks/use-dismiss\";\nimport { isImeEnter } from \"../lib/ime\";\nimport { isQuietFocus } from \"../lib/quiet-focus\";\nimport { usePhoneLayout } from \"../hooks/use-breakpoint\";\nimport { PickerSheet, SHEET_ROW_CLASS } from \"./picker-sheet\";\nimport {\n anchoredHeadingClass,\n ComboboxFieldLabel,\n endHintRowProps,\n GroupedOptions,\n groupRuns,\n SHEET_HEADING_CLASS,\n useTypedListStatus,\n type GroupRun,\n} from \"./combobox-core\";\nimport { DEFAULT_COMBOBOX_LABELS, useKitLabels, useKitLocale } from \"../i18n/kit-labels\";\nimport { sameName, searchRanked } from \"../lib/text-match\";\nimport {\n EndHintRow,\n FieldCaption,\n LABEL_IN_ROW,\n LockedReason,\n mergeDescribedBy,\n StaticLabelRow,\n useFieldError,\n useFieldHint,\n useLockReason,\n type DisabledReasonDisplay,\n type FieldHelpProps,\n} from \"./field-parts\";\nimport type { CommitScope } from \"./write-lock\";\nimport { lockedKeyDown, rowClass, SuggestionList, usePrimaryPressOnly } from \"./combobox-suggestions\";\n// The id-keyed sibling lives in inline-entity-combobox.tsx (MOD-9), the list both share\n// in combobox-suggestions.tsx; its public names are still this module's.\nexport { InlineEntityCombobox } from \"./inline-entity-combobox\";\nexport type { InlineEntityComboboxProps } from \"./inline-entity-combobox\";\n\n/**\n * Four of the div's own attributes are omitted because this component already owns\n * the name, with a different meaning: `id` is the INPUT's (a caller labels or\n * automates the field, not the box around it), and `onChange`/`onBlur`/`onSubmit`\n * are the field's — a value, a departure, and \"I mean what I typed\" — rather than\n * the DOM events of the wrapper. Everything else a wrapper needs reaches the root.\n */\nexport interface ComboboxProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"id\" | \"onChange\" | \"onBlur\" | \"onSubmit\">, FieldHelpProps {\n value: string;\n onChange: (v: string) => void;\n /** Suggestion pool (e.g. existing payee names). */\n options: readonly string[];\n /** The visible label, a `<label for>` above the field: a ReactNode, as on every kit\n * field (a string until 0.34, refactor audit 2026-10, API-9). Without one, name the\n * field with `aria-label`. */\n label?: ReactNode;\n id?: string;\n placeholder?: string;\n className?: string;\n /** Required and unanswered — see {@link Input}'s `invalid`. Set on the `<input>`\n * itself rather than on the wrapper, which is what let Keksdose's account picker\n * delete the `[&_input]:…` copy of {@link FIELD_INVALID} it had been carrying\n * because this component had no `invalid` of its own. */\n invalid?: boolean;\n /** What is wrong with the value, as {@link Input}'s `error`: rendered under the\n * field, on the `<input>`'s `aria-describedby`, and implies `invalid` (lenkbank's\n * scope fields, which moved here off `<Input list>` + `<datalist>`). */\n error?: ReactNode;\n /**\n * Standing advice for the field — {@link Input}'s `hint`, so the combobox family\n * reads like every other field (keksdose K4: the family had `error` and no `hint`, so\n * the app's pickers carried their captions outside the component, attached to\n * nothing). Plain TEXT is a caption under the field on the input's\n * `aria-describedby`, before any error; a {@link FieldHint} \"?\" rides the label line,\n * or with no label sits at the field's end edge, outside the box.\n */\n hint?: ReactNode;\n /** As `<input disabled>`: no focus, no list, the field's settled look. The chevron\n * stops toggling with it — it is a mouse target the input's own `disabled` does\n * not reach. */\n disabled?: boolean;\n /**\n * Why the value cannot be changed — {@link Button}'s `disabledReason`, for a field\n * that SAVES itself (an inline editor whose blur writes). The input stays focusable\n * and `aria-disabled`, is `readOnly`, opens no list and calls neither `onChange` nor\n * `onSubmit`; the reason is in the kit {@link Tooltip} and on its `aria-describedby`.\n * Wins over `disabled`. The family's lock (keksdose G2) — see {@link InlineEntityCombobox}.\n */\n disabledReason?: ReactNode;\n /** This field COMMITS. Under a locked {@link WriteLockProvider} it is locked the\n * `disabledReason` way with the lock's reason; inside a form with its own Save, leave\n * it off and put `commit` on the Save. No provider, or an unlocked one: no effect. */\n commit?: CommitScope;\n /** Where the reason shows — {@link Button}'s `disabledReasonDisplay`: a line under the\n * field at Large and on a touch screen by default, the tooltip otherwise (DUP-3). */\n disabledReasonDisplay?: DisabledReasonDisplay;\n /** Heading an option belongs under. Supplying it makes this list read exactly\n * like {@link InlineEntityCombobox}'s — one heading per group with its rows\n * indented beneath — instead of a flat list (feedback #136 rework: the payee\n * field sat next to the newly-grouped category field and no longer matched).\n * Omit for a plain list. */\n groupBy?: (option: string) => string;\n /**\n * Something to show at the far end of an option's row — a badge saying what the\n * option IS, as distinct from what it is called.\n *\n * Keksdose's category-name field is the case: its proposals carry per-locale\n * names, so picking one stores a category that follows the UI language, and\n * picking a look-alike custom name does not. That difference is invisible in the\n * label and decides what the row DOES, so the row has to show it. Returning\n * `null` for an option renders nothing and costs no layout.\n *\n * Not rendered in the create row, which by definition names nothing in the pool.\n */\n optionAdornment?: (option: string) => ReactNode;\n /** Focus on mount, the way `<input autoFocus>` does — and, through `onFocus`, open\n * the list with it. A click-the-value inline editor needs it: the cell the user\n * clicked names the field the caret should land in. {@link InlineEntityCombobox}\n * has had it since live #218. */\n autoFocus?: boolean;\n /** Focus genuinely LEFT the field. Not fired by picking a row — the rows suppress\n * `mousedown`, so the input never blurs — which is what makes it usable as a\n * \"close the inline editor\" signal. */\n onBlur?: () => void;\n /** Enter pressed with no row highlighted, i.e. \"I mean what I typed\". The list\n * closes either way; this is for a caller whose Enter also submits a row editor. */\n onSubmit?: () => void;\n /** Rows to offer when the field is empty. 8 on a dropdown, where that is all\n * that fits; the phone sheet asks for more because it has a screen. */\n maxSuggestions?: number;\n searchPlaceholder?: string;\n closeLabel?: string;\n /**\n * The phone sheet's heading — and, as a string, the dialog's accessible name — for a\n * field whose label is drawn by someone else: a bound field's label above it,\n * which `RhfTextCombobox` hands over here (0.24). Default: `label`. Without either, the\n * full-screen sheet opened untitled and unnamed, the one screen on a phone that has to\n * say what it is asking for (live #200).\n */\n sheetTitle?: ReactNode;\n /**\n * Label for the row that COMMITS a value the list does not contain — e.g.\n * `(v) => \\`Add \"${v}\" as payee\\``. Supplying it turns the free text into\n * something you confirm rather than something you leave behind.\n *\n * Keksdose live #212: *\"For the payee input have an apply button, when input is\n * placed like 'add xxx as payee' to confirm. Now it can be put in and closed with\n * the right top X, which seems not intuitive.\"* On the phone sheet the search box\n * IS the value, so typing a brand-new name and dismissing the sheet did commit it —\n * but the only control on offer was the close X, which reads as \"discard\". A named\n * affordance says what the typing did.\n *\n * Omit and the row is not rendered, which is the right default for a list whose\n * values are all supposed to already exist.\n */\n createLabel?: (value: string) => string;\n /**\n * The `<input>` — the control a reader types in and the one focus belongs on — as a\n * React 19 ref prop, the way {@link CountrySelect} takes its trigger's (0.24, kastlan:\n * react-hook-form's focus-on-error calls `focus()` on whatever `field.ref` is handed,\n * and a combobox with no ref inside a hand-wired `RhfField` gave it nothing, so a\n * failed submit could not take the user to it). Not the wrapper: a ref is for focus,\n * measurement and selection, and all three are the input's. `RhfTextCombobox` passes it.\n */\n ref?: Ref<HTMLInputElement>;\n}\n\n/**\n * Free-text combobox that looks like the shared {@link Select} (same FIELD_BASE\n * styling, chevron and static floating label) but lets the user type a value\n * that isn't in the list — e.g. naming a brand-new payee. Picking from the\n * filtered suggestion list fills the value; typing keeps whatever was entered.\n *\n * Use this instead of an `<Input list=\"…\">` + `<datalist>` so the control is\n * visually and behaviourally consistent with the other dropdowns (feedback\n * #230 — the payee field looked/behaved differently from every other select).\n */\nexport function Combobox(props: ComboboxProps) {\n const {\n value,\n onChange,\n options,\n label,\n id,\n placeholder,\n className,\n groupBy,\n maxSuggestions,\n searchPlaceholder,\n closeLabel,\n sheetTitle,\n createLabel,\n invalid,\n error,\n hint,\n help,\n disabled,\n disabledReason,\n disabledReasonDisplay,\n commit,\n optionAdornment,\n autoFocus,\n onBlur,\n onSubmit,\n ref,\n \"aria-label\": ariaLabel,\n // Off `rest` and onto the <input>, which is the combobox a reader meets: `Field`'s\n // render-prop spreads `{ id, aria-describedby, aria-invalid, aria-required }`, and\n // on the wrapper div the hint and required state described nothing.\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n \"aria-required\": ariaRequired,\n ...rest\n } = props;\n const hintParts = useFieldHint(hint, ariaDescribedBy, { help, name: label ?? ariaLabel });\n const field = useFieldError(error, invalid, hintParts.describedBy, ariaInvalid);\n const generated = useId();\n const fieldId = id ?? generated;\n // Derived from the GENERATED id, never from `id`: a caller's id is theirs to\n // collide with, and `aria-controls` has to resolve.\n const listboxId = `${generated}-listbox`;\n const optionId = (index: number) => `${generated}-option-${index}`;\n // `backCloses` is the desktop half of live #309: the phone's list IS a\n // {@link PickerSheet}, which registers its own history entry, so registering a\n // second one here would cost two Back presses to dismiss one sheet. Its Escape\n // layer is this field's own, below — the list can be open with nothing to show.\n const isPhone = usePhoneLayout();\n const { open, setOpen, wrapperRef, panelRef } = useDropdown({ backCloses: !isPhone, escapeLayer: false });\n const primaryOnly = usePrimaryPressOnly();\n const [active, setActive] = useState(-1);\n // A closed list has no row the keyboard is on, however it closed — the sheet's X,\n // Escape or Back, a press outside — adjusted while rendering. The arrows' row outlived\n // it: the list reopens on the whole pool, so the row the arrows had put on \"Migros\"\n // showed \"Aldi\" highlighted, and Enter took it over the typed value (0.52 code review,\n // combobox.tsx). An ArrowDown that opens the list sets both at once, and keeps its row.\n if (!open && active !== -1) setActive(-1);\n // The lock (see `lockedKeyDown`): a lock arriving while the list is up closes it,\n // adjusted while rendering so no frame offers a row that can no longer be taken.\n const lock = useLockReason(commit, disabledReason);\n const locked = lock.locked;\n const inert = locked || Boolean(disabled);\n if (locked && open) setOpen(false);\n // A phone opens the list as a full-screen sheet with its own input, the way a\n // native <select> does — live #200: \"Paid as full screen dialog with input.\n // Similar to the account select that already appears as full screen.\" The\n // anchored list stays for pointer devices, where it is the better shape.\n const sheetInputRef = useRef<HTMLInputElement | null>(null);\n // The box the portalled list hangs off — the inner wrapper, which hugs the input,\n // not the outer one (a grid item that can be taller than the field).\n const fieldRef = useRef<HTMLDivElement>(null);\n\n /**\n * Is the text in the field a QUERY, or just what was picked last time?\n *\n * Keksdose dev#549, filed against the category-name field: *\"Currently it acts kind\n * of a filter and clicking again does not open anything since the previous text is\n * still there likely filtering all other options out.\"* A combobox whose filter is\n * its own value can only ever re-offer the answer it already has — after picking\n * \"REWE\" the list reopens holding one row, the one you are looking at, and changing\n * your mind means clearing the field by hand first.\n *\n * So the text filters only while it is being TYPED; opening the list, by focus or\n * by clicking the field again, puts the whole pool back. {@link InlineEntityCombobox}\n * below has had this since it was written (see its `typedQuery`) and the app's\n * category-name field grew its own copy to get it — this one, the payee field, was\n * the one left with the bug.\n *\n * Not derived from \"does the text exactly match an option\": a custom value that\n * happens to collide with one would then behave differently from every other, and\n * what is being tracked is what the user just did, which is not a property of the\n * string.\n */\n const [typing, setTyping] = useState(false);\n\n const query = typing ? value.trim() : \"\";\n // Folded as every kit list folds (DUP-5): \"zurich\" finds Zürich, by the locale's case.\n const locale = useKitLocale();\n // The live status's words (INP-6): the result count and \"No results\", as the panel\n // pickers say them.\n const labels = useKitLabels(\"combobox\", DEFAULT_COMBOBOX_LABELS);\n const matches = useMemo(() => {\n const seen = new Set<string>();\n const uniq = options.filter((o) => o && !seen.has(o) && seen.add(o));\n let ranked: string[];\n const cap = maxSuggestions ?? (isPhone ? 50 : 8);\n if (!query) {\n ranked = uniq.slice(0, cap);\n } else {\n // Every word of the query somewhere in the name (0.51.4's rule, which this list\n // was said to have and did not: refactor audit 2026-10-30, DUP-4), ranked by the\n // WHOLE query — the whole name, then prefix matches, then substring matches, then\n // the names that hold the words apart (`searchRanked`, each name folded once). A\n // stable sort keeps the pool's order within a rank.\n ranked = searchRanked(uniq, query, (o) => [o], { locale })\n .sort((a, b) => a.rank - b.rank)\n .map((x) => x.row)\n .slice(0, cap);\n }\n if (!groupBy) return ranked;\n // Keep each group contiguous so a heading appears once instead of every time\n // the ranking interleaves two groups — while preserving \"best match first\":\n // a Map keeps insertion order, so groups come out ordered by their best-ranked\n // member and members keep their rank order inside the group.\n const byGroup = new Map<string, string[]>();\n for (const o of ranked) {\n const key = groupBy(o);\n if (!byGroup.has(key)) byGroup.set(key, []);\n byGroup.get(key)!.push(o);\n }\n return [...byGroup.values()].flat();\n }, [options, query, groupBy, maxSuggestions, isPhone, locale]);\n\n /**\n * The rows cut into their groups — computed once for both lists, each run a\n * `role=\"group\"` its heading names (INP-8). Without `groupBy`, one bare run.\n *\n * The desktop list had the boundaries as `matches[i - 1]`, which is free; the sheet had\n * them as `matches[matches.indexOf(o) - 1]`, which is a scan of the list per row and\n * another per heading test. That is quadratic in the sheet's own cap of 50, on the\n * branch that runs on the slowest hardware we ship to — and it answers the wrong\n * question besides: `indexOf` finds the FIRST row with that string, so a duplicated\n * option would have compared against a neighbour it is not next to. (`matches`\n * de-duplicates today; that is a property of the memo above, not of the row being\n * rendered.)\n */\n const runs = useMemo<GroupRun<string>[]>(\n () => (groupBy ? groupRuns(matches, groupBy) : [{ group: null, start: 0, rows: matches }]),\n [matches, groupBy],\n );\n\n const take = (v: string) => {\n if (locked) return;\n onChange(v);\n setOpen(false);\n setActive(-1);\n // What is in the field is now an ANSWER, not a query — so reopening offers the\n // whole pool again rather than a one-row filter of the value just chosen.\n setTyping(false);\n };\n\n // While locked the field sits in the reason's Tooltip — in a fragment with a hidden\n // copy of the reason, Button's anatomy; `block` so a full-width field stays full width.\n const withLock = (box: ReactNode) =>\n locked ? (\n <LockedReason lock={lock} display={disabledReasonDisplay} className=\"block\">\n {box}\n </LockedReason>\n ) : (\n box\n );\n\n // Offered only when the typed text is genuinely NOT in the pool: an exact match —\n // folded as the list matches, so \"cafe\" is Café ({@link sameName}, DUP-5 in the\n // 2026-10-30 refactor audit) — is an existing entry the list is already showing, and a\n // second way to pick it would be noise. Compared against `options`, not `matches` —\n // `matches` is capped, so a pool of 300 payees would otherwise offer to \"add\" one\n // that exists but fell off the end of the list.\n const typed = value.trim();\n const createRow =\n createLabel && typed.length > 0 && !options.some((o) => sameName(o, typed, locale)) ? createLabel(typed) : null;\n\n // Whether a list shows, the row the keyboard is on — named by the field, or on a phone\n // by the sheet's own search box, which takes the same keys (INP-6, 0.34's BUG-5 for\n // this field) — and the live status: the family's one rule for a typed list.\n const { showing, expanded, activeOption, statusRegion } = useTypedListStatus({\n isPhone,\n open,\n inert,\n rowCount: matches.length,\n extraRow: Boolean(createRow),\n query,\n active: active < matches.length ? active : -1,\n optionId,\n labels,\n });\n // The list is a layer on the Escape stack while it SHOWS (Wave 2, DUP-1): an Escape\n // over an empty \"open\" list is the dialog's, as it always was. On a phone the sheet\n // is the layer.\n useDismissLayer(showing, () => {\n setOpen(false);\n setActive(-1);\n });\n\n /** The list's keys — in the field and, on a phone, in the sheet's search box. Enter\n * with no row highlighted is \"I mean what I typed\" in both. */\n const listKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setOpen(true);\n setActive((i) => Math.min(i + 1, matches.length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((i) => Math.max(i - 1, 0));\n } else if (e.key === \"Enter\") {\n // The Enter that confirms an IME composition is the IME's: it picks no row and\n // submits nothing (BUG-9).\n if (isImeEnter(e)) return;\n if (open && active >= 0 && active < matches.length) {\n e.preventDefault();\n take(matches[active]);\n } else {\n // No row highlighted: the typed text is the answer. `preventDefault` only when a\n // caller is taking Enter, so a plain form submit is otherwise left alone.\n if (onSubmit) e.preventDefault();\n setOpen(false);\n onSubmit?.();\n }\n }\n };\n\n /** The rows in their runs — each group a `role=\"group\"` its heading names (INP-8) —\n * for the sheet or the anchored list; `row` draws one option, `grouped` when it\n * stands under a heading. `matches` is group-contiguous, so the boundaries are a\n * property of the list rather than of the branch drawing it (see `runs`). */\n const groupedRows = (sheet: boolean, row: (o: string, i: number, grouped: boolean) => ReactNode) => (\n <GroupedOptions\n runs={runs}\n listboxId={listboxId}\n rowKey={(o) => o}\n row={row}\n // The list's first item sits closer to its top edge; the create row comes first\n // when there is one.\n headingClassName={(run) => (sheet ? SHEET_HEADING_CLASS : anchoredHeadingClass(run, !createRow))}\n />\n );\n\n return (\n // `rest` dresses the outer box — a `data-tour` anchor, a test id. Not the NAME,\n // description, invalid or required state: those belong on the <input> below,\n // which is the combobox a reader meets. Spread FIRST, so the field's ARIA and the\n // handlers carrying live #309 and dev#549 cannot be replaced from outside.\n <div {...rest} ref={wrapperRef} className={cn(\"relative\", className)}>\n {/* A real <label for> since lenkbank's tests met a field `getByLabelText` could\n not find: it used to be a <span>, with the text copied onto `aria-label`. The\n name a reader hears is the same words either way. With a \"?\" it moves into a\n row after the field, below. */}\n {label !== undefined && hintParts.labelHint === undefined && (\n <ComboboxFieldLabel htmlFor={fieldId} className={inert ? \"opacity-50\" : undefined}>\n {label}\n </ComboboxFieldLabel>\n )}\n <EndHintRow {...endHintRowProps(\"hint\" in props, label !== undefined, hintParts.labelHint)}>\n {withLock(\n /* The chevron centers against this inner wrapper, which hugs the input.\n The outer div can be taller than the input (as a grid item it\n stretches to the row height, e.g. next to the editor's category cell\n with its split button), which used to drag a top-1/2 chevron down to\n the input's bottom edge (feedback #248).\n Dimmed as a whole when disabled (or locked), the way EntityCombobox dims its\n trigger. FIELD_BASE's grey alone left a disabled picker looking like a\n filled-in one beside the pickers that do dim (the label is not the input's\n `peer`, so it is dimmed by hand above). */\n <div ref={fieldRef} className={cn(\"relative\", inert && \"cursor-not-allowed opacity-50\")}>\n <input\n ref={ref}\n id={fieldId}\n value={value}\n placeholder={placeholder}\n // The caller's name, over the <label for> above — which is what names the\n // field otherwise (dev#477: a field with neither announces only its text).\n aria-label={ariaLabel}\n role=\"combobox\"\n aria-expanded={expanded}\n // The list this field is the mouth of. Required by the role, and the half\n // that was missing: the field said it was expanded and never said what it\n // had expanded, so a reader had no way from the box to the options\n // (ESLint's `role-has-required-aria-props`, the audit's §a11y).\n aria-controls={listboxId}\n // Only on a pointer device: on a phone the sheet's own search box holds\n // focus and names the row, and the field behind it says nothing.\n aria-activedescendant={isPhone ? undefined : activeOption}\n aria-autocomplete=\"list\"\n aria-invalid={field.isInvalid || undefined}\n aria-describedby={mergeDescribedBy(field.describedBy, locked && lock.reasonId)}\n aria-required={ariaRequired}\n autoComplete=\"off\"\n // Locked: focusable, `readOnly`, `aria-disabled` — see `lockedKeyDown`.\n disabled={locked ? undefined : disabled}\n readOnly={locked || undefined}\n aria-disabled={locked || undefined}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- a documented prop the caller opts into (off by default); the field never takes focus on its own.\n autoFocus={autoFocus}\n onBlur={onBlur}\n onMouseDown={primaryOnly.onMouseDown}\n onFocus={(e) => {\n // A back/forward mouse button focuses this field on its way to\n // navigating; it is not a request to open anything (live #309 rework).\n // A locked field takes focus to say why, and opens nothing.\n if (primaryOnly.fromAuxButton() || locked) return;\n // The tour's focus on arrival (§11.8) opens nothing: the list would cover\n // its card (0.50.1). The click handler below still opens on a click.\n if (isQuietFocus(e.currentTarget)) return;\n setOpen(true);\n setTyping(false);\n setActive(-1);\n // The sheet carries its own input, so the field behind it must not also\n // pull up the keyboard and scroll the page under the dialog.\n if (isPhone) sheetInputRef.current?.focus();\n }}\n // A CLICK as well as focus — the other half of dev#549. Picking a suggestion\n // closes the list without moving focus (the rows suppress `mousedown` on\n // purpose, so the input never blurred), which means clicking the field again\n // fires no `focus` event at all and the list stayed shut. \"Does not open\n // anything\" was literally true.\n onClick={() => {\n if (locked) return;\n setOpen(true);\n // The whole pool again, so no row of the typed list is the keyboard's\n // (0.52 code review, combobox.tsx — see `active`).\n setTyping(false);\n setActive(-1);\n }}\n // `inputMode=\"none\"` rather than readOnly: the field must not look\n // uneditable (FIELD_BASE greys a read-only field since dev#468) and must\n // still take focus — it just has no keyboard of its own, the same trick\n // the amount field uses for the numpad.\n inputMode={isPhone ? \"none\" : undefined}\n onChange={(e) => {\n if (locked) return;\n onChange(e.target.value);\n setOpen(true);\n setActive(-1);\n setTyping(true);\n }}\n onKeyDown={(e) => {\n if (locked) return lockedKeyDown(e);\n listKeyDown(e);\n if (e.key === \"Escape\") {\n // A list that is SHOWING is the top of the Escape stack, and the key\n // closes it and stops here: a Modal or FullBleedDialog around the field\n // otherwise closed with it, form and all (round 0.34 BUG-1). With no\n // list on screen the key goes on to whoever wants it.\n if (showing && takeEscape(e)) return;\n setOpen(false);\n setActive(-1);\n } else if (e.key === \"Tab\") {\n // Closes, and lets the browser take the Tab: focus is in THIS input,\n // which is staying, so there is nothing to catch — unlike the pickers\n // whose focus sits inside a portalled panel.\n setOpen(false);\n setActive(-1);\n }\n // Home/End are deliberately absent. The APG gives them to the list only\n // where the combobox is not editable; here the text IS the value, a\n // payee name is long enough to want the caret moved to its start, and\n // the desktop list is capped at 8 rows — so jumping it would be worth\n // almost nothing and would cost the one gesture that field is used with.\n }}\n className={cn(\n FIELD_BASE,\n label !== undefined && FIELD_FLOATING_PAD,\n \"pe-9\",\n field.isInvalid && FIELD_INVALID,\n )}\n />\n <ChevronDown\n aria-hidden\n onMouseDown={(e) => {\n // Toggle on the chevron without stealing focus from the input.\n e.preventDefault();\n if (!inert) setOpen((o) => !o);\n }}\n className={cn(\n \"absolute end-2.5 top-1/2 size-4 -translate-y-1/2 text-placeholder\",\n // The box above does the dimming; dimming here too would halve it again.\n !inert && \"cursor-pointer\",\n )}\n />\n </div>,\n )}\n </EndHintRow>\n {/* The label and its \"?\" share the top strip — after the field in the DOM, so the\n \"?\" follows the control in the tab order, as it does on Input and Select. */}\n {label !== undefined && hintParts.labelHint !== undefined && (\n <StaticLabelRow hint={hintParts.labelHint}>\n <ComboboxFieldLabel htmlFor={fieldId} className={cn(LABEL_IN_ROW, inert && \"opacity-50\")}>\n {label}\n </ComboboxFieldLabel>\n </StaticLabelRow>\n )}\n <FieldCaption parts={hintParts} />\n {field.errorEl}\n {/* The live status — see `useTypedListStatus` for where it goes and why. */}\n {!isPhone && statusRegion}\n {isPhone && (\n <PickerSheet\n open={open && !inert}\n onClose={() => setOpen(false)}\n title={sheetTitle ?? label}\n // The sheet's input IS the field: this is a free-text control, so what is\n // typed here is the value (a brand-new payee is just a name nothing\n // matches), and the list below narrows as it changes.\n query={value}\n onQueryChange={(v) => {\n onChange(v);\n setActive(-1);\n setTyping(true);\n }}\n searchPlaceholder={searchPlaceholder ?? placeholder}\n inputRef={sheetInputRef}\n closeLabel={closeLabel}\n // The field's own keys, in the box focus is in while the sheet is up: arrows\n // and Enter there did nothing (INP-6, as BUG-5 gave the panel pickers).\n onSearchKeyDown={listKeyDown}\n listboxId={listboxId}\n activeId={activeOption}\n >\n <ul id={listboxId} role=\"listbox\">\n {createRow && (\n // `role=\"option\"` rides the BUTTON, not the <li> around it: an option\n // may not contain a separately focusable control, and the button is\n // what a pointer presses. Same shape `CommandPalette` has always had.\n <li role=\"presentation\">\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n onClick={() => take(typed)}\n className={cn(SHEET_ROW_CLASS, \"font-medium text-brand\")}\n >\n {createRow}\n </button>\n </li>\n )}\n {groupedRows(true, (o, i) => (\n <li role=\"presentation\">\n <button\n type=\"button\"\n id={optionId(i)}\n role=\"option\"\n aria-selected={o === value}\n onClick={() => take(o)}\n className={cn(\n SHEET_ROW_CLASS,\n // The row the sheet's arrows are on.\n i === active && \"bg-active\",\n optionAdornment && \"flex items-center justify-between gap-2\",\n )}\n >\n {optionAdornment ? <span className=\"truncate-until-large\">{o}</span> : o}\n {optionAdornment?.(o)}\n </button>\n </li>\n ))}\n </ul>\n {statusRegion}\n </PickerSheet>\n )}\n {showing && (\n <SuggestionList id={listboxId} anchorRef={fieldRef} panelRef={panelRef}>\n {createRow && (\n <li role=\"presentation\">\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n tabIndex={-1}\n onMouseDown={(e) => {\n // mousedown, like the rows below: the input's blur would otherwise\n // close the list before the click landed.\n e.preventDefault();\n take(typed);\n }}\n className={cn(rowClass(false), \"font-medium text-brand\")}\n >\n {createRow}\n </button>\n </li>\n )}\n {groupedRows(false, (o, i, grouped) => (\n <li role=\"presentation\">\n <button\n type=\"button\"\n id={optionId(i)}\n role=\"option\"\n // CHOSEN, not highlighted. The row the arrows are on is named by the\n // field's `aria-activedescendant`; saying \"selected\" for it would tell a\n // reader that the row they are passing over is already the answer.\n aria-selected={o === value}\n // Focus stays in the field — that is what `aria-activedescendant` is\n // for — so the rows are not tab stops.\n tabIndex={-1}\n onMouseDown={(e) => {\n // mousedown (not click) so the blur from the input firing first\n // doesn't close the list before the selection registers.\n e.preventDefault();\n take(o);\n }}\n onMouseEnter={() => setActive(i)}\n className={cn(\n rowClass(i === active),\n // Every row of a group indented under its heading — it was the first\n // row of each group only.\n grouped && \"ps-6\",\n // A row with a badge is a flex row so the label truncates and the\n // badge keeps its width; without one it stays the plain block the\n // other lists render, so nothing shifts for callers that pass none.\n // From Large up the label wraps instead (`truncate-until-large`,\n // text size §10.17, round 0.34 T1), as the badge-less row does.\n optionAdornment && \"flex items-center justify-between gap-2\",\n )}\n >\n {optionAdornment ? <span className=\"truncate-until-large\">{o}</span> : o}\n {optionAdornment?.(o)}\n </button>\n </li>\n ))}\n </SuggestionList>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/combobox.tsx"],"sourcesContent":["import { useId, useMemo, useRef, useState } from \"react\";\nimport type { ComponentPropsWithoutRef, KeyboardEvent, ReactNode, Ref } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { FIELD_BASE, FIELD_FLOATING_PAD, FIELD_INVALID } from \"./field-base\";\nimport { cn } from \"../lib/cn\";\nimport { useDropdown } from \"./dropdown\";\nimport { takeEscape, useDismissLayer } from \"../hooks/use-dismiss\";\nimport { isImeEnter } from \"../lib/ime\";\nimport { isQuietFocus } from \"../lib/quiet-focus\";\nimport { usePhoneLayout } from \"../hooks/use-breakpoint\";\nimport { PickerSheet, SHEET_ROW_CLASS } from \"./picker-sheet\";\nimport {\n anchoredHeadingClass,\n ComboboxFieldLabel,\n endHintRowProps,\n GroupedOptions,\n groupRuns,\n SHEET_HEADING_CLASS,\n useTypedListStatus,\n type GroupRun,\n} from \"./combobox-core\";\nimport { DEFAULT_COMBOBOX_LABELS, useKitLabels, useKitLocale } from \"../i18n/kit-labels\";\nimport { sameName, searchRanked } from \"../lib/text-match\";\nimport {\n EndHintRow,\n FieldCaption,\n LABEL_IN_ROW,\n LockFrame,\n mergeDescribedBy,\n StaticLabelRow,\n useFieldError,\n useFieldHint,\n useLockReason,\n type DisabledReasonDisplay,\n type FieldHelpProps,\n} from \"./field-parts\";\nimport type { CommitScope } from \"./write-lock\";\nimport { lockedKeyDown, rowClass, SuggestionList, usePrimaryPressOnly } from \"./combobox-suggestions\";\n// The id-keyed sibling lives in inline-entity-combobox.tsx (MOD-9), the list both share\n// in combobox-suggestions.tsx; its public names are still this module's.\nexport { InlineEntityCombobox } from \"./inline-entity-combobox\";\nexport type { InlineEntityComboboxProps } from \"./inline-entity-combobox\";\n\n/**\n * Four of the div's own attributes are omitted because this component already owns\n * the name, with a different meaning: `id` is the INPUT's (a caller labels or\n * automates the field, not the box around it), and `onChange`/`onBlur`/`onSubmit`\n * are the field's — a value, a departure, and \"I mean what I typed\" — rather than\n * the DOM events of the wrapper. Everything else a wrapper needs reaches the root.\n */\nexport interface ComboboxProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"id\" | \"onChange\" | \"onBlur\" | \"onSubmit\">, FieldHelpProps {\n value: string;\n onChange: (v: string) => void;\n /** Suggestion pool (e.g. existing payee names). */\n options: readonly string[];\n /** The visible label, a `<label for>` above the field: a ReactNode, as on every kit\n * field (a string until 0.34, refactor audit 2026-10, API-9). Without one, name the\n * field with `aria-label`. */\n label?: ReactNode;\n id?: string;\n placeholder?: string;\n className?: string;\n /** Required and unanswered — see {@link Input}'s `invalid`. Set on the `<input>`\n * itself rather than on the wrapper, which is what let Keksdose's account picker\n * delete the `[&_input]:…` copy of {@link FIELD_INVALID} it had been carrying\n * because this component had no `invalid` of its own. */\n invalid?: boolean;\n /** What is wrong with the value, as {@link Input}'s `error`: rendered under the\n * field, on the `<input>`'s `aria-describedby`, and implies `invalid` (lenkbank's\n * scope fields, which moved here off `<Input list>` + `<datalist>`). */\n error?: ReactNode;\n /**\n * Standing advice for the field — {@link Input}'s `hint`, so the combobox family\n * reads like every other field (keksdose K4: the family had `error` and no `hint`, so\n * the app's pickers carried their captions outside the component, attached to\n * nothing). Plain TEXT is a caption under the field on the input's\n * `aria-describedby`, before any error; a {@link FieldHint} \"?\" rides the label line,\n * or with no label sits at the field's end edge, outside the box.\n */\n hint?: ReactNode;\n /** As `<input disabled>`: no focus, no list, the field's settled look. The chevron\n * stops toggling with it — it is a mouse target the input's own `disabled` does\n * not reach. */\n disabled?: boolean;\n /**\n * Why the value cannot be changed — {@link Button}'s `disabledReason`, for a field\n * that SAVES itself (an inline editor whose blur writes). The input stays focusable\n * and `aria-disabled`, is `readOnly`, opens no list and calls neither `onChange` nor\n * `onSubmit`; the reason is in the kit {@link Tooltip} and on its `aria-describedby`.\n * Wins over `disabled`. The family's lock (keksdose G2) — see {@link InlineEntityCombobox}.\n */\n disabledReason?: ReactNode;\n /** This field COMMITS. Under a locked {@link WriteLockProvider} it is locked the\n * `disabledReason` way with the lock's reason; inside a form with its own Save, leave\n * it off and put `commit` on the Save. No provider, or an unlocked one: no effect. */\n commit?: CommitScope;\n /** Where the reason shows — {@link Button}'s `disabledReasonDisplay`: a line under the\n * field at Large and on a touch screen by default, the tooltip otherwise (DUP-3). */\n disabledReasonDisplay?: DisabledReasonDisplay;\n /** Heading an option belongs under. Supplying it makes this list read exactly\n * like {@link InlineEntityCombobox}'s — one heading per group with its rows\n * indented beneath — instead of a flat list (feedback #136 rework: the payee\n * field sat next to the newly-grouped category field and no longer matched).\n * Omit for a plain list. */\n groupBy?: (option: string) => string;\n /**\n * Something to show at the far end of an option's row — a badge saying what the\n * option IS, as distinct from what it is called.\n *\n * Keksdose's category-name field is the case: its proposals carry per-locale\n * names, so picking one stores a category that follows the UI language, and\n * picking a look-alike custom name does not. That difference is invisible in the\n * label and decides what the row DOES, so the row has to show it. Returning\n * `null` for an option renders nothing and costs no layout.\n *\n * Not rendered in the create row, which by definition names nothing in the pool.\n */\n optionAdornment?: (option: string) => ReactNode;\n /** Focus on mount, the way `<input autoFocus>` does — and, through `onFocus`, open\n * the list with it. A click-the-value inline editor needs it: the cell the user\n * clicked names the field the caret should land in. {@link InlineEntityCombobox}\n * has had it since live #218. */\n autoFocus?: boolean;\n /** Focus genuinely LEFT the field. Not fired by picking a row — the rows suppress\n * `mousedown`, so the input never blurs — which is what makes it usable as a\n * \"close the inline editor\" signal. */\n onBlur?: () => void;\n /** Enter pressed with no row highlighted, i.e. \"I mean what I typed\". The list\n * closes either way; this is for a caller whose Enter also submits a row editor. */\n onSubmit?: () => void;\n /** Rows to offer when the field is empty. 8 on a dropdown, where that is all\n * that fits; the phone sheet asks for more because it has a screen. */\n maxSuggestions?: number;\n searchPlaceholder?: string;\n closeLabel?: string;\n /**\n * The phone sheet's heading — and, as a string, the dialog's accessible name — for a\n * field whose label is drawn by someone else: a bound field's label above it,\n * which `RhfTextCombobox` hands over here (0.24). Default: `label`. Without either, the\n * full-screen sheet opened untitled and unnamed, the one screen on a phone that has to\n * say what it is asking for (live #200).\n */\n sheetTitle?: ReactNode;\n /**\n * Label for the row that COMMITS a value the list does not contain — e.g.\n * `(v) => \\`Add \"${v}\" as payee\\``. Supplying it turns the free text into\n * something you confirm rather than something you leave behind.\n *\n * Keksdose live #212: *\"For the payee input have an apply button, when input is\n * placed like 'add xxx as payee' to confirm. Now it can be put in and closed with\n * the right top X, which seems not intuitive.\"* On the phone sheet the search box\n * IS the value, so typing a brand-new name and dismissing the sheet did commit it —\n * but the only control on offer was the close X, which reads as \"discard\". A named\n * affordance says what the typing did.\n *\n * Omit and the row is not rendered, which is the right default for a list whose\n * values are all supposed to already exist.\n */\n createLabel?: (value: string) => string;\n /**\n * The `<input>` — the control a reader types in and the one focus belongs on — as a\n * React 19 ref prop, the way {@link CountrySelect} takes its trigger's (0.24, kastlan:\n * react-hook-form's focus-on-error calls `focus()` on whatever `field.ref` is handed,\n * and a combobox with no ref inside a hand-wired `RhfField` gave it nothing, so a\n * failed submit could not take the user to it). Not the wrapper: a ref is for focus,\n * measurement and selection, and all three are the input's. `RhfTextCombobox` passes it.\n */\n ref?: Ref<HTMLInputElement>;\n}\n\n/**\n * Free-text combobox that looks like the shared {@link Select} (same FIELD_BASE\n * styling, chevron and static floating label) but lets the user type a value\n * that isn't in the list — e.g. naming a brand-new payee. Picking from the\n * filtered suggestion list fills the value; typing keeps whatever was entered.\n *\n * Use this instead of an `<Input list=\"…\">` + `<datalist>` so the control is\n * visually and behaviourally consistent with the other dropdowns (feedback\n * #230 — the payee field looked/behaved differently from every other select).\n */\nexport function Combobox(props: ComboboxProps) {\n const {\n value,\n onChange,\n options,\n label,\n id,\n placeholder,\n className,\n groupBy,\n maxSuggestions,\n searchPlaceholder,\n closeLabel,\n sheetTitle,\n createLabel,\n invalid,\n error,\n hint,\n help,\n disabled,\n disabledReason,\n disabledReasonDisplay,\n commit,\n optionAdornment,\n autoFocus,\n onBlur,\n onSubmit,\n ref,\n \"aria-label\": ariaLabel,\n // Off `rest` and onto the <input>, which is the combobox a reader meets: `Field`'s\n // render-prop spreads `{ id, aria-describedby, aria-invalid, aria-required }`, and\n // on the wrapper div the hint and required state described nothing.\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n \"aria-required\": ariaRequired,\n ...rest\n } = props;\n const hintParts = useFieldHint(hint, ariaDescribedBy, { help, name: label ?? ariaLabel });\n const field = useFieldError(error, invalid, hintParts.describedBy, ariaInvalid);\n const generated = useId();\n const fieldId = id ?? generated;\n // Derived from the GENERATED id, never from `id`: a caller's id is theirs to\n // collide with, and `aria-controls` has to resolve.\n const listboxId = `${generated}-listbox`;\n const optionId = (index: number) => `${generated}-option-${index}`;\n // `backCloses` is the desktop half of live #309: the phone's list IS a\n // {@link PickerSheet}, which registers its own history entry, so registering a\n // second one here would cost two Back presses to dismiss one sheet. Its Escape\n // layer is this field's own, below — the list can be open with nothing to show.\n const isPhone = usePhoneLayout();\n const { open, setOpen, wrapperRef, panelRef } = useDropdown({ backCloses: !isPhone, escapeLayer: false });\n const primaryOnly = usePrimaryPressOnly();\n const [active, setActive] = useState(-1);\n // A closed list has no row the keyboard is on, however it closed — the sheet's X,\n // Escape or Back, a press outside — adjusted while rendering. The arrows' row outlived\n // it: the list reopens on the whole pool, so the row the arrows had put on \"Migros\"\n // showed \"Aldi\" highlighted, and Enter took it over the typed value (0.52 code review,\n // combobox.tsx). An ArrowDown that opens the list sets both at once, and keeps its row.\n if (!open && active !== -1) setActive(-1);\n // The lock (see `lockedKeyDown`): a lock arriving while the list is up closes it,\n // adjusted while rendering so no frame offers a row that can no longer be taken.\n const lock = useLockReason(commit, disabledReason);\n const locked = lock.locked;\n const inert = locked || Boolean(disabled);\n if (locked && open) setOpen(false);\n // A phone opens the list as a full-screen sheet with its own input, the way a\n // native <select> does — live #200: \"Paid as full screen dialog with input.\n // Similar to the account select that already appears as full screen.\" The\n // anchored list stays for pointer devices, where it is the better shape.\n const sheetInputRef = useRef<HTMLInputElement | null>(null);\n // The box the portalled list hangs off — the inner wrapper, which hugs the input,\n // not the outer one (a grid item that can be taller than the field).\n const fieldRef = useRef<HTMLDivElement>(null);\n\n /**\n * Is the text in the field a QUERY, or just what was picked last time?\n *\n * Keksdose dev#549, filed against the category-name field: *\"Currently it acts kind\n * of a filter and clicking again does not open anything since the previous text is\n * still there likely filtering all other options out.\"* A combobox whose filter is\n * its own value can only ever re-offer the answer it already has — after picking\n * \"REWE\" the list reopens holding one row, the one you are looking at, and changing\n * your mind means clearing the field by hand first.\n *\n * So the text filters only while it is being TYPED; opening the list, by focus or\n * by clicking the field again, puts the whole pool back. {@link InlineEntityCombobox}\n * below has had this since it was written (see its `typedQuery`) and the app's\n * category-name field grew its own copy to get it — this one, the payee field, was\n * the one left with the bug.\n *\n * Not derived from \"does the text exactly match an option\": a custom value that\n * happens to collide with one would then behave differently from every other, and\n * what is being tracked is what the user just did, which is not a property of the\n * string.\n */\n const [typing, setTyping] = useState(false);\n\n const query = typing ? value.trim() : \"\";\n // Folded as every kit list folds (DUP-5): \"zurich\" finds Zürich, by the locale's case.\n const locale = useKitLocale();\n // The live status's words (INP-6): the result count and \"No results\", as the panel\n // pickers say them.\n const labels = useKitLabels(\"combobox\", DEFAULT_COMBOBOX_LABELS);\n const matches = useMemo(() => {\n const seen = new Set<string>();\n const uniq = options.filter((o) => o && !seen.has(o) && seen.add(o));\n let ranked: string[];\n const cap = maxSuggestions ?? (isPhone ? 50 : 8);\n if (!query) {\n ranked = uniq.slice(0, cap);\n } else {\n // Every word of the query somewhere in the name (0.51.4's rule, which this list\n // was said to have and did not: refactor audit 2026-10-30, DUP-4), ranked by the\n // WHOLE query — the whole name, then prefix matches, then substring matches, then\n // the names that hold the words apart (`searchRanked`, each name folded once). A\n // stable sort keeps the pool's order within a rank.\n ranked = searchRanked(uniq, query, (o) => [o], { locale })\n .sort((a, b) => a.rank - b.rank)\n .map((x) => x.row)\n .slice(0, cap);\n }\n if (!groupBy) return ranked;\n // Keep each group contiguous so a heading appears once instead of every time\n // the ranking interleaves two groups — while preserving \"best match first\":\n // a Map keeps insertion order, so groups come out ordered by their best-ranked\n // member and members keep their rank order inside the group.\n const byGroup = new Map<string, string[]>();\n for (const o of ranked) {\n const key = groupBy(o);\n if (!byGroup.has(key)) byGroup.set(key, []);\n byGroup.get(key)!.push(o);\n }\n return [...byGroup.values()].flat();\n }, [options, query, groupBy, maxSuggestions, isPhone, locale]);\n\n /**\n * The rows cut into their groups — computed once for both lists, each run a\n * `role=\"group\"` its heading names (INP-8). Without `groupBy`, one bare run.\n *\n * The desktop list had the boundaries as `matches[i - 1]`, which is free; the sheet had\n * them as `matches[matches.indexOf(o) - 1]`, which is a scan of the list per row and\n * another per heading test. That is quadratic in the sheet's own cap of 50, on the\n * branch that runs on the slowest hardware we ship to — and it answers the wrong\n * question besides: `indexOf` finds the FIRST row with that string, so a duplicated\n * option would have compared against a neighbour it is not next to. (`matches`\n * de-duplicates today; that is a property of the memo above, not of the row being\n * rendered.)\n */\n const runs = useMemo<GroupRun<string>[]>(\n () => (groupBy ? groupRuns(matches, groupBy) : [{ group: null, start: 0, rows: matches }]),\n [matches, groupBy],\n );\n\n const take = (v: string) => {\n if (locked) return;\n onChange(v);\n setOpen(false);\n setActive(-1);\n // What is in the field is now an ANSWER, not a query — so reopening offers the\n // whole pool again rather than a one-row filter of the value just chosen.\n setTyping(false);\n };\n\n // While locked the field sits in the reason's Tooltip — in a fragment with a hidden\n // copy of the reason, Button's anatomy; `block` so a full-width field stays full width.\n const withLock = (box: ReactNode) => (\n <LockFrame lock={lock} display={disabledReasonDisplay}>\n {box}\n </LockFrame>\n );\n\n // Offered only when the typed text is genuinely NOT in the pool: an exact match —\n // folded as the list matches, so \"cafe\" is Café ({@link sameName}, DUP-5 in the\n // 2026-10-30 refactor audit) — is an existing entry the list is already showing, and a\n // second way to pick it would be noise. Compared against `options`, not `matches` —\n // `matches` is capped, so a pool of 300 payees would otherwise offer to \"add\" one\n // that exists but fell off the end of the list.\n const typed = value.trim();\n const createRow =\n createLabel && typed.length > 0 && !options.some((o) => sameName(o, typed, locale)) ? createLabel(typed) : null;\n\n // Whether a list shows, the row the keyboard is on — named by the field, or on a phone\n // by the sheet's own search box, which takes the same keys (INP-6, 0.34's BUG-5 for\n // this field) — and the live status: the family's one rule for a typed list.\n const { showing, expanded, activeOption, statusRegion } = useTypedListStatus({\n isPhone,\n open,\n inert,\n rowCount: matches.length,\n extraRow: Boolean(createRow),\n query,\n active: active < matches.length ? active : -1,\n optionId,\n labels,\n });\n // The list is a layer on the Escape stack while it SHOWS (Wave 2, DUP-1): an Escape\n // over an empty \"open\" list is the dialog's, as it always was. On a phone the sheet\n // is the layer.\n useDismissLayer(showing, () => {\n setOpen(false);\n setActive(-1);\n });\n\n /** The list's keys — in the field and, on a phone, in the sheet's search box. Enter\n * with no row highlighted is \"I mean what I typed\" in both. */\n const listKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setOpen(true);\n setActive((i) => Math.min(i + 1, matches.length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((i) => Math.max(i - 1, 0));\n } else if (e.key === \"Enter\") {\n // The Enter that confirms an IME composition is the IME's: it picks no row and\n // submits nothing (BUG-9).\n if (isImeEnter(e)) return;\n if (open && active >= 0 && active < matches.length) {\n e.preventDefault();\n take(matches[active]);\n } else {\n // No row highlighted: the typed text is the answer. `preventDefault` only when a\n // caller is taking Enter, so a plain form submit is otherwise left alone.\n if (onSubmit) e.preventDefault();\n setOpen(false);\n onSubmit?.();\n }\n }\n };\n\n /** The rows in their runs — each group a `role=\"group\"` its heading names (INP-8) —\n * for the sheet or the anchored list; `row` draws one option, `grouped` when it\n * stands under a heading. `matches` is group-contiguous, so the boundaries are a\n * property of the list rather than of the branch drawing it (see `runs`). */\n const groupedRows = (sheet: boolean, row: (o: string, i: number, grouped: boolean) => ReactNode) => (\n <GroupedOptions\n runs={runs}\n listboxId={listboxId}\n rowKey={(o) => o}\n row={row}\n // The list's first item sits closer to its top edge; the create row comes first\n // when there is one.\n headingClassName={(run) => (sheet ? SHEET_HEADING_CLASS : anchoredHeadingClass(run, !createRow))}\n />\n );\n\n return (\n // `rest` dresses the outer box — a `data-tour` anchor, a test id. Not the NAME,\n // description, invalid or required state: those belong on the <input> below,\n // which is the combobox a reader meets. Spread FIRST, so the field's ARIA and the\n // handlers carrying live #309 and dev#549 cannot be replaced from outside.\n <div {...rest} ref={wrapperRef} className={cn(\"relative\", className)}>\n {/* A real <label for> since lenkbank's tests met a field `getByLabelText` could\n not find: it used to be a <span>, with the text copied onto `aria-label`. The\n name a reader hears is the same words either way. With a \"?\" it moves into a\n row after the field, below. */}\n {label !== undefined && hintParts.labelHint === undefined && (\n <ComboboxFieldLabel htmlFor={fieldId} className={inert ? \"opacity-50\" : undefined}>\n {label}\n </ComboboxFieldLabel>\n )}\n <EndHintRow {...endHintRowProps(\"hint\" in props, label !== undefined, hintParts.labelHint)}>\n {withLock(\n /* The chevron centers against this inner wrapper, which hugs the input.\n The outer div can be taller than the input (as a grid item it\n stretches to the row height, e.g. next to the editor's category cell\n with its split button), which used to drag a top-1/2 chevron down to\n the input's bottom edge (feedback #248).\n Dimmed as a whole when disabled (or locked), the way EntityCombobox dims its\n trigger. FIELD_BASE's grey alone left a disabled picker looking like a\n filled-in one beside the pickers that do dim (the label is not the input's\n `peer`, so it is dimmed by hand above). */\n <div ref={fieldRef} className={cn(\"relative\", inert && \"cursor-not-allowed opacity-50\")}>\n <input\n ref={ref}\n id={fieldId}\n value={value}\n placeholder={placeholder}\n // The caller's name, over the <label for> above — which is what names the\n // field otherwise (dev#477: a field with neither announces only its text).\n aria-label={ariaLabel}\n role=\"combobox\"\n aria-expanded={expanded}\n // The list this field is the mouth of. Required by the role, and the half\n // that was missing: the field said it was expanded and never said what it\n // had expanded, so a reader had no way from the box to the options\n // (ESLint's `role-has-required-aria-props`, the audit's §a11y).\n aria-controls={listboxId}\n // Only on a pointer device: on a phone the sheet's own search box holds\n // focus and names the row, and the field behind it says nothing.\n aria-activedescendant={isPhone ? undefined : activeOption}\n aria-autocomplete=\"list\"\n aria-invalid={field.isInvalid || undefined}\n aria-describedby={mergeDescribedBy(field.describedBy, locked && lock.reasonId)}\n aria-required={ariaRequired}\n autoComplete=\"off\"\n // Locked: focusable, `readOnly`, `aria-disabled` — see `lockedKeyDown`.\n disabled={locked ? undefined : disabled}\n readOnly={locked || undefined}\n aria-disabled={locked || undefined}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- a documented prop the caller opts into (off by default); the field never takes focus on its own.\n autoFocus={autoFocus}\n onBlur={onBlur}\n onMouseDown={primaryOnly.onMouseDown}\n onFocus={(e) => {\n // A back/forward mouse button focuses this field on its way to\n // navigating; it is not a request to open anything (live #309 rework).\n // A locked field takes focus to say why, and opens nothing.\n if (primaryOnly.fromAuxButton() || locked) return;\n // The tour's focus on arrival (§11.8) opens nothing: the list would cover\n // its card (0.50.1). The click handler below still opens on a click.\n if (isQuietFocus(e.currentTarget)) return;\n setOpen(true);\n setTyping(false);\n setActive(-1);\n // The sheet carries its own input, so the field behind it must not also\n // pull up the keyboard and scroll the page under the dialog.\n if (isPhone) sheetInputRef.current?.focus();\n }}\n // A CLICK as well as focus — the other half of dev#549. Picking a suggestion\n // closes the list without moving focus (the rows suppress `mousedown` on\n // purpose, so the input never blurred), which means clicking the field again\n // fires no `focus` event at all and the list stayed shut. \"Does not open\n // anything\" was literally true.\n onClick={() => {\n if (locked) return;\n setOpen(true);\n // The whole pool again, so no row of the typed list is the keyboard's\n // (0.52 code review, combobox.tsx — see `active`).\n setTyping(false);\n setActive(-1);\n }}\n // `inputMode=\"none\"` rather than readOnly: the field must not look\n // uneditable (FIELD_BASE greys a read-only field since dev#468) and must\n // still take focus — it just has no keyboard of its own, the same trick\n // the amount field uses for the numpad.\n inputMode={isPhone ? \"none\" : undefined}\n onChange={(e) => {\n if (locked) return;\n onChange(e.target.value);\n setOpen(true);\n setActive(-1);\n setTyping(true);\n }}\n onKeyDown={(e) => {\n if (locked) return lockedKeyDown(e);\n listKeyDown(e);\n if (e.key === \"Escape\") {\n // A list that is SHOWING is the top of the Escape stack, and the key\n // closes it and stops here: a Modal or FullBleedDialog around the field\n // otherwise closed with it, form and all (round 0.34 BUG-1). With no\n // list on screen the key goes on to whoever wants it.\n if (showing && takeEscape(e)) return;\n setOpen(false);\n setActive(-1);\n } else if (e.key === \"Tab\") {\n // Closes, and lets the browser take the Tab: focus is in THIS input,\n // which is staying, so there is nothing to catch — unlike the pickers\n // whose focus sits inside a portalled panel.\n setOpen(false);\n setActive(-1);\n }\n // Home/End are deliberately absent. The APG gives them to the list only\n // where the combobox is not editable; here the text IS the value, a\n // payee name is long enough to want the caret moved to its start, and\n // the desktop list is capped at 8 rows — so jumping it would be worth\n // almost nothing and would cost the one gesture that field is used with.\n }}\n className={cn(\n FIELD_BASE,\n label !== undefined && FIELD_FLOATING_PAD,\n \"pe-9\",\n field.isInvalid && FIELD_INVALID,\n )}\n />\n <ChevronDown\n aria-hidden\n onMouseDown={(e) => {\n // Toggle on the chevron without stealing focus from the input.\n e.preventDefault();\n if (!inert) setOpen((o) => !o);\n }}\n className={cn(\n \"absolute end-2.5 top-1/2 size-4 -translate-y-1/2 text-placeholder\",\n // The box above does the dimming; dimming here too would halve it again.\n !inert && \"cursor-pointer\",\n )}\n />\n </div>,\n )}\n </EndHintRow>\n {/* The label and its \"?\" share the top strip — after the field in the DOM, so the\n \"?\" follows the control in the tab order, as it does on Input and Select. */}\n {label !== undefined && hintParts.labelHint !== undefined && (\n <StaticLabelRow hint={hintParts.labelHint}>\n <ComboboxFieldLabel htmlFor={fieldId} className={cn(LABEL_IN_ROW, inert && \"opacity-50\")}>\n {label}\n </ComboboxFieldLabel>\n </StaticLabelRow>\n )}\n <FieldCaption parts={hintParts} />\n {field.errorEl}\n {/* The live status — see `useTypedListStatus` for where it goes and why. */}\n {!isPhone && statusRegion}\n {isPhone && (\n <PickerSheet\n open={open && !inert}\n onClose={() => setOpen(false)}\n title={sheetTitle ?? label}\n // The sheet's input IS the field: this is a free-text control, so what is\n // typed here is the value (a brand-new payee is just a name nothing\n // matches), and the list below narrows as it changes.\n query={value}\n onQueryChange={(v) => {\n onChange(v);\n setActive(-1);\n setTyping(true);\n }}\n searchPlaceholder={searchPlaceholder ?? placeholder}\n inputRef={sheetInputRef}\n closeLabel={closeLabel}\n // The field's own keys, in the box focus is in while the sheet is up: arrows\n // and Enter there did nothing (INP-6, as BUG-5 gave the panel pickers).\n onSearchKeyDown={listKeyDown}\n listboxId={listboxId}\n activeId={activeOption}\n >\n <ul id={listboxId} role=\"listbox\">\n {createRow && (\n // `role=\"option\"` rides the BUTTON, not the <li> around it: an option\n // may not contain a separately focusable control, and the button is\n // what a pointer presses. Same shape `CommandPalette` has always had.\n <li role=\"presentation\">\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n onClick={() => take(typed)}\n className={cn(SHEET_ROW_CLASS, \"font-medium text-brand\")}\n >\n {createRow}\n </button>\n </li>\n )}\n {groupedRows(true, (o, i) => (\n <li role=\"presentation\">\n <button\n type=\"button\"\n id={optionId(i)}\n role=\"option\"\n aria-selected={o === value}\n onClick={() => take(o)}\n className={cn(\n SHEET_ROW_CLASS,\n // The row the sheet's arrows are on.\n i === active && \"bg-active\",\n optionAdornment && \"flex items-center justify-between gap-2\",\n )}\n >\n {optionAdornment ? <span className=\"truncate-until-large\">{o}</span> : o}\n {optionAdornment?.(o)}\n </button>\n </li>\n ))}\n </ul>\n {statusRegion}\n </PickerSheet>\n )}\n {showing && (\n <SuggestionList id={listboxId} anchorRef={fieldRef} panelRef={panelRef}>\n {createRow && (\n <li role=\"presentation\">\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={false}\n tabIndex={-1}\n onMouseDown={(e) => {\n // mousedown, like the rows below: the input's blur would otherwise\n // close the list before the click landed.\n e.preventDefault();\n take(typed);\n }}\n className={cn(rowClass(false), \"font-medium text-brand\")}\n >\n {createRow}\n </button>\n </li>\n )}\n {groupedRows(false, (o, i, grouped) => (\n <li role=\"presentation\">\n <button\n type=\"button\"\n id={optionId(i)}\n role=\"option\"\n // CHOSEN, not highlighted. The row the arrows are on is named by the\n // field's `aria-activedescendant`; saying \"selected\" for it would tell a\n // reader that the row they are passing over is already the answer.\n aria-selected={o === value}\n // Focus stays in the field — that is what `aria-activedescendant` is\n // for — so the rows are not tab stops.\n tabIndex={-1}\n onMouseDown={(e) => {\n // mousedown (not click) so the blur from the input firing first\n // doesn't close the list before the selection registers.\n e.preventDefault();\n take(o);\n }}\n onMouseEnter={() => setActive(i)}\n className={cn(\n rowClass(i === active),\n // Every row of a group indented under its heading — it was the first\n // row of each group only.\n grouped && \"ps-6\",\n // A row with a badge is a flex row so the label truncates and the\n // badge keeps its width; without one it stays the plain block the\n // other lists render, so nothing shifts for callers that pass none.\n // From Large up the label wraps instead (`truncate-until-large`,\n // text size §10.17, round 0.34 T1), as the badge-less row does.\n optionAdornment && \"flex items-center justify-between gap-2\",\n )}\n >\n {optionAdornment ? <span className=\"truncate-until-large\">{o}</span> : o}\n {optionAdornment?.(o)}\n </button>\n </li>\n ))}\n </SuggestionList>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `ConsentAgainNotice`'s words — the `consentAgain` namespace of `<UiKitProvider labels>`
3
+ * (0.55). The kit's chrome only: the title, the intro, the list of changes and the wording
4
+ * before and now are the app's, as they say what this consent is about.
5
+ */
6
+ export interface ConsentAgainLabels {
7
+ /** The button that gives the consent again. */
8
+ agree: string;
9
+ /** The banner's ×, its accessible name: not a refusal, the question comes back. */
10
+ notNow: string;
11
+ /** The banner's disclosure that unfolds the list of changes. */
12
+ changesToggle: string;
13
+ /** The card's disclosure that unfolds the full wording, before and now. */
14
+ wordingToggle: string;
15
+ /** Over the text agreed to before. */
16
+ beforeHeading: string;
17
+ /** Over the text asked for now. */
18
+ nowHeading: string;
19
+ /** Read before each paragraph of the old text, which is struck through: a line-through
20
+ * is not announced, and colour alone must not carry the meaning. */
21
+ removed: string;
22
+ /** Read before each paragraph of the new text. */
23
+ added: string;
24
+ }
25
+ export declare const DEFAULT_CONSENT_AGAIN_LABELS: ConsentAgainLabels;
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ const DEFAULT_CONSENT_AGAIN_LABELS = {
3
+ agree: "Agree",
4
+ notNow: "Not now",
5
+ changesToggle: "See what changed",
6
+ wordingToggle: "Show the full wording, before and now",
7
+ beforeHeading: "Until now",
8
+ nowHeading: "From now on",
9
+ removed: "Removed:",
10
+ added: "Added:"
11
+ };
12
+ export {
13
+ DEFAULT_CONSENT_AGAIN_LABELS
14
+ };
15
+ //# sourceMappingURL=consent-again-notice-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/consent-again-notice-labels.ts"],"sourcesContent":["// The English words of ./consent-again-notice, in a module with no component code: the\n// English catalogue (src/i18n/defaults.ts) imports them without the component (0.34, KS U8).\n// keksdose's reviewed words (price_pool.reconsent.*) are the canon, without its price pool:\n// the kit cannot know what was agreed to, only that the text changed and is asked again.\n\n/**\n * `ConsentAgainNotice`'s words — the `consentAgain` namespace of `<UiKitProvider labels>`\n * (0.55). The kit's chrome only: the title, the intro, the list of changes and the wording\n * before and now are the app's, as they say what this consent is about.\n */\nexport interface ConsentAgainLabels {\n /** The button that gives the consent again. */\n agree: string;\n /** The banner's ×, its accessible name: not a refusal, the question comes back. */\n notNow: string;\n /** The banner's disclosure that unfolds the list of changes. */\n changesToggle: string;\n /** The card's disclosure that unfolds the full wording, before and now. */\n wordingToggle: string;\n /** Over the text agreed to before. */\n beforeHeading: string;\n /** Over the text asked for now. */\n nowHeading: string;\n /** Read before each paragraph of the old text, which is struck through: a line-through\n * is not announced, and colour alone must not carry the meaning. */\n removed: string;\n /** Read before each paragraph of the new text. */\n added: string;\n}\n\nexport const DEFAULT_CONSENT_AGAIN_LABELS: ConsentAgainLabels = {\n agree: \"Agree\",\n notNow: \"Not now\",\n changesToggle: \"See what changed\",\n wordingToggle: \"Show the full wording, before and now\",\n beforeHeading: \"Until now\",\n nowHeading: \"From now on\",\n removed: \"Removed:\",\n added: \"Added:\",\n};\n"],"mappings":";AA8BO,MAAM,+BAAmD;AAAA,EAC9D,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,OAAO;AACT;","names":[]}
@@ -0,0 +1,85 @@
1
+ import type { ReactNode } from "react";
2
+ import type { LabelOverride } from "../i18n/kit-labels.js";
3
+ import type { CommitScope } from "./write-lock.js";
4
+ import { DEFAULT_CONSENT_AGAIN_LABELS, type ConsentAgainLabels } from "./consent-again-notice-labels.js";
5
+ export { DEFAULT_CONSENT_AGAIN_LABELS };
6
+ export type { ConsentAgainLabels };
7
+ interface ConsentAgainNoticeBase {
8
+ /** What changed, as a headline: "Price sharing has changed — please agree again". */
9
+ title: ReactNode;
10
+ /** What holds until the answer — what stops, what goes on. */
11
+ intro: ReactNode;
12
+ /** The "what's new" list, one entry per change, in the reader's terms. */
13
+ changes: readonly ReactNode[];
14
+ /** Agree is busy: the consent is on its way to the server. */
15
+ agreePending?: boolean;
16
+ /**
17
+ * Agree commits — under a locked `WriteLockProvider` it is disabled with the lock's
18
+ * reason, as every committing button is. Default `true`: an answer the server keeps is a
19
+ * write, and the demo, a lapsed plan or an offline device refuse it (keksdose's price
20
+ * pool). `false` for a consent that only this device keeps.
21
+ */
22
+ commit?: CommitScope;
23
+ labels?: LabelOverride<ConsentAgainLabels>;
24
+ className?: string;
25
+ }
26
+ /** `frame="card"`: everything, where the question stays until it is answered. */
27
+ export interface ConsentAgainCardProps extends ConsentAgainNoticeBase {
28
+ frame: "card";
29
+ /** The full text agreed to before and the one asked for now, one paragraph per entry,
30
+ * behind a disclosure. Left out, no disclosure. */
31
+ wording?: {
32
+ before: readonly ReactNode[];
33
+ now: readonly ReactNode[];
34
+ };
35
+ /** Left out for a reader who may not answer (a guest, a member who is not the owner):
36
+ * no Agree, and {@link note} says who can. */
37
+ onAgree?: () => void;
38
+ /** A quiet line under the list — why this reader cannot agree. */
39
+ note?: ReactNode;
40
+ /** The title's element. Default `h3`; the wording's two headings are one level below
41
+ * (a `div` title, `div` headings). */
42
+ headingAs?: "div" | "h2" | "h3" | "h4";
43
+ }
44
+ /** `frame="banner"`: the short form, where the reader is about to do what waits for it. */
45
+ export interface ConsentAgainBannerProps extends ConsentAgainNoticeBase {
46
+ frame: "banner";
47
+ /** Always there: the banner is only shown to a reader who may answer. */
48
+ onAgree: () => void;
49
+ /** The ×: the banner does not hide itself — the caller removes it and remembers that it
50
+ * did, and asks again later. "Not now" is not a refusal. */
51
+ onNotNow: () => void;
52
+ /** The quiet last line under the unfolded list: where the full wording is (a link to
53
+ * the card). */
54
+ wordingLink?: ReactNode;
55
+ }
56
+ export type ConsentAgainNoticeProps = ConsentAgainCardProps | ConsentAgainBannerProps;
57
+ /**
58
+ * "What you agreed to has changed — agree again?" (0.55): the question an app asks when the
59
+ * text a consent was given to has changed, and the consent is needed again before what it
60
+ * covers goes on. keksdose built it first (shared/components/consent-again-notice.tsx, for
61
+ * its price pool's second consent text, price pool v2 plan §6), display-only so it could be
62
+ * lifted as it is: every word of the subject and both choices are the app's, and nothing
63
+ * here knows a consent version or where "Not now" is remembered.
64
+ *
65
+ * Two frames, which do not hold the same parts:
66
+ *
67
+ * - `card` — everything, for the settings page where the question stays until it is
68
+ * answered: an info-toned card with the title, the intro, the "what's new" list in front
69
+ * and the full wording before and now behind a disclosure. No "Not now": there is nothing
70
+ * for it to do there. A reader who may not answer gets no Agree, and the app's `note`.
71
+ * - `banner` — the short form, where the reader is about to do what waits for the answer:
72
+ * one or two sentences, the same list one tap away in the banner (informed consent wants
73
+ * it beside Agree), Agree as the action and "Not now" as the ×. The old and new wording
74
+ * is not in it — two folding levels in a callout is too much, and on a 390px phone the
75
+ * banner with everything was ~600px — so the type takes none; `wordingLink` points to
76
+ * the card.
77
+ *
78
+ * Never a modal: the app stays usable without an answer, and "Not now" is not a refusal
79
+ * (Marcel, 2026-10-24: two choices only, Agree and Not now).
80
+ *
81
+ * On the card the old text is a `<del>` and the new an `<ins>`, each paragraph led by a
82
+ * visually hidden "Removed:" / "Added:": a line-through is not announced, and colour alone
83
+ * must not carry the meaning.
84
+ */
85
+ export declare function ConsentAgainNotice(props: ConsentAgainNoticeProps): import("react").JSX.Element;
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { cn } from "../lib/cn.js";
4
+ import { useKitLabels } from "../i18n/kit-labels.js";
5
+ import { AlertBanner } from "./alert-banner.js";
6
+ import { Button } from "./button.js";
7
+ import { Card, CardTitle } from "./card.js";
8
+ import { Disclosure } from "./disclosure.js";
9
+ import { DEFAULT_CONSENT_AGAIN_LABELS } from "./consent-again-notice-labels.js";
10
+ const SUB_HEADING = { div: "div", h2: "h3", h3: "h4", h4: "h5" };
11
+ function ChangeList({ changes }) {
12
+ return /* @__PURE__ */ jsx("ul", { className: "list-disc space-y-1 ps-5 text-sm text-secondary", "data-slot": "consent-changes", children: changes.map((change, i) => (
13
+ // The list is the caller's fixed copy, in a fixed order: the index is its key.
14
+ /* @__PURE__ */ jsx("li", { children: change }, i)
15
+ )) });
16
+ }
17
+ function ConsentAgainNotice(props) {
18
+ const { title, intro, changes, onAgree, agreePending = false, commit = true, className } = props;
19
+ const labels = useKitLabels("consentAgain", DEFAULT_CONSENT_AGAIN_LABELS, props.labels);
20
+ const agree = onAgree && /* @__PURE__ */ jsx(Button, { commit, pending: agreePending, onClick: onAgree, children: labels.agree });
21
+ if (props.frame === "banner") {
22
+ return /* @__PURE__ */ jsx(
23
+ AlertBanner,
24
+ {
25
+ tone: "info",
26
+ variant: "box",
27
+ action: agree,
28
+ onDismiss: props.onNotNow,
29
+ dismissLabel: labels.notNow,
30
+ className,
31
+ "data-consent-again": "banner",
32
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
33
+ /* @__PURE__ */ jsxs("p", { children: [
34
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: title }),
35
+ " ",
36
+ /* @__PURE__ */ jsx("span", { className: "text-secondary", children: intro })
37
+ ] }),
38
+ /* @__PURE__ */ jsxs(Disclosure, { variant: "bare", title: labels.changesToggle, children: [
39
+ /* @__PURE__ */ jsx(ChangeList, { changes }),
40
+ props.wordingLink != null && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs", children: props.wordingLink })
41
+ ] })
42
+ ] })
43
+ }
44
+ );
45
+ }
46
+ const { wording, note, headingAs = "h3" } = props;
47
+ const Sub = SUB_HEADING[headingAs];
48
+ return /* @__PURE__ */ jsxs(
49
+ Card,
50
+ {
51
+ tone: "info",
52
+ toneStrength: "strong",
53
+ toneFill: true,
54
+ density: "compact",
55
+ padding: "md",
56
+ className: cn("space-y-3", className),
57
+ "data-consent-again": "card",
58
+ children: [
59
+ /* @__PURE__ */ jsx(CardTitle, { as: headingAs, children: title }),
60
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-secondary", children: intro }),
61
+ /* @__PURE__ */ jsx(ChangeList, { changes }),
62
+ wording && /* @__PURE__ */ jsx(Disclosure, { variant: "bare", title: labels.wordingToggle, children: /* @__PURE__ */ jsxs("div", { className: "space-y-3 pt-2 text-sm text-secondary", children: [
63
+ /* @__PURE__ */ jsxs("section", { className: "space-y-1", children: [
64
+ /* @__PURE__ */ jsx(Sub, { className: "text-xs font-medium text-primary", children: labels.beforeHeading }),
65
+ wording.before.map((text, i) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsxs("del", { children: [
66
+ /* @__PURE__ */ jsxs("span", { className: "sr-only-fixed", children: [
67
+ labels.removed,
68
+ " "
69
+ ] }),
70
+ text
71
+ ] }) }, i))
72
+ ] }),
73
+ /* @__PURE__ */ jsxs("section", { className: "space-y-1", children: [
74
+ /* @__PURE__ */ jsx(Sub, { className: "text-xs font-medium text-primary", children: labels.nowHeading }),
75
+ wording.now.map((text, i) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsxs("ins", { className: "no-underline", children: [
76
+ /* @__PURE__ */ jsxs("span", { className: "sr-only-fixed", children: [
77
+ labels.added,
78
+ " "
79
+ ] }),
80
+ text
81
+ ] }) }, i))
82
+ ] })
83
+ ] }) }),
84
+ note != null && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted", children: note }),
85
+ agree && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: agree })
86
+ ]
87
+ }
88
+ );
89
+ }
90
+ export {
91
+ ConsentAgainNotice,
92
+ DEFAULT_CONSENT_AGAIN_LABELS
93
+ };
94
+ //# sourceMappingURL=consent-again-notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/consent-again-notice.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useKitLabels } from \"../i18n/kit-labels\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\nimport { AlertBanner } from \"./alert-banner\";\nimport { Button } from \"./button\";\nimport { Card, CardTitle } from \"./card\";\nimport { Disclosure } from \"./disclosure\";\nimport type { CommitScope } from \"./write-lock\";\nimport { DEFAULT_CONSENT_AGAIN_LABELS, type ConsentAgainLabels } from \"./consent-again-notice-labels\";\n\nexport { DEFAULT_CONSENT_AGAIN_LABELS };\nexport type { ConsentAgainLabels };\n\ninterface ConsentAgainNoticeBase {\n /** What changed, as a headline: \"Price sharing has changed — please agree again\". */\n title: ReactNode;\n /** What holds until the answer — what stops, what goes on. */\n intro: ReactNode;\n /** The \"what's new\" list, one entry per change, in the reader's terms. */\n changes: readonly ReactNode[];\n /** Agree is busy: the consent is on its way to the server. */\n agreePending?: boolean;\n /**\n * Agree commits — under a locked `WriteLockProvider` it is disabled with the lock's\n * reason, as every committing button is. Default `true`: an answer the server keeps is a\n * write, and the demo, a lapsed plan or an offline device refuse it (keksdose's price\n * pool). `false` for a consent that only this device keeps.\n */\n commit?: CommitScope;\n labels?: LabelOverride<ConsentAgainLabels>;\n className?: string;\n}\n\n/** `frame=\"card\"`: everything, where the question stays until it is answered. */\nexport interface ConsentAgainCardProps extends ConsentAgainNoticeBase {\n frame: \"card\";\n /** The full text agreed to before and the one asked for now, one paragraph per entry,\n * behind a disclosure. Left out, no disclosure. */\n wording?: {\n before: readonly ReactNode[];\n now: readonly ReactNode[];\n };\n /** Left out for a reader who may not answer (a guest, a member who is not the owner):\n * no Agree, and {@link note} says who can. */\n onAgree?: () => void;\n /** A quiet line under the list — why this reader cannot agree. */\n note?: ReactNode;\n /** The title's element. Default `h3`; the wording's two headings are one level below\n * (a `div` title, `div` headings). */\n headingAs?: \"div\" | \"h2\" | \"h3\" | \"h4\";\n}\n\n/** `frame=\"banner\"`: the short form, where the reader is about to do what waits for it. */\nexport interface ConsentAgainBannerProps extends ConsentAgainNoticeBase {\n frame: \"banner\";\n /** Always there: the banner is only shown to a reader who may answer. */\n onAgree: () => void;\n /** The ×: the banner does not hide itself — the caller removes it and remembers that it\n * did, and asks again later. \"Not now\" is not a refusal. */\n onNotNow: () => void;\n /** The quiet last line under the unfolded list: where the full wording is (a link to\n * the card). */\n wordingLink?: ReactNode;\n}\n\nexport type ConsentAgainNoticeProps = ConsentAgainCardProps | ConsentAgainBannerProps;\n\nconst SUB_HEADING = { div: \"div\", h2: \"h3\", h3: \"h4\", h4: \"h5\" } as const;\n\nfunction ChangeList({ changes }: { changes: readonly ReactNode[] }) {\n return (\n <ul className=\"list-disc space-y-1 ps-5 text-sm text-secondary\" data-slot=\"consent-changes\">\n {changes.map((change, i) => (\n // The list is the caller's fixed copy, in a fixed order: the index is its key.\n <li key={i}>{change}</li>\n ))}\n </ul>\n );\n}\n\n/**\n * \"What you agreed to has changed — agree again?\" (0.55): the question an app asks when the\n * text a consent was given to has changed, and the consent is needed again before what it\n * covers goes on. keksdose built it first (shared/components/consent-again-notice.tsx, for\n * its price pool's second consent text, price pool v2 plan §6), display-only so it could be\n * lifted as it is: every word of the subject and both choices are the app's, and nothing\n * here knows a consent version or where \"Not now\" is remembered.\n *\n * Two frames, which do not hold the same parts:\n *\n * - `card` — everything, for the settings page where the question stays until it is\n * answered: an info-toned card with the title, the intro, the \"what's new\" list in front\n * and the full wording before and now behind a disclosure. No \"Not now\": there is nothing\n * for it to do there. A reader who may not answer gets no Agree, and the app's `note`.\n * - `banner` — the short form, where the reader is about to do what waits for the answer:\n * one or two sentences, the same list one tap away in the banner (informed consent wants\n * it beside Agree), Agree as the action and \"Not now\" as the ×. The old and new wording\n * is not in it — two folding levels in a callout is too much, and on a 390px phone the\n * banner with everything was ~600px — so the type takes none; `wordingLink` points to\n * the card.\n *\n * Never a modal: the app stays usable without an answer, and \"Not now\" is not a refusal\n * (Marcel, 2026-10-24: two choices only, Agree and Not now).\n *\n * On the card the old text is a `<del>` and the new an `<ins>`, each paragraph led by a\n * visually hidden \"Removed:\" / \"Added:\": a line-through is not announced, and colour alone\n * must not carry the meaning.\n */\nexport function ConsentAgainNotice(props: ConsentAgainNoticeProps) {\n const { title, intro, changes, onAgree, agreePending = false, commit = true, className } = props;\n const labels = useKitLabels(\"consentAgain\", DEFAULT_CONSENT_AGAIN_LABELS, props.labels);\n const agree = onAgree && (\n <Button commit={commit} pending={agreePending} onClick={onAgree}>\n {labels.agree}\n </Button>\n );\n\n if (props.frame === \"banner\") {\n // `actionPlacement` stays at its default, `own-line`: on a phone Agree sits under the\n // text instead of squeezing it into a column beside the button.\n return (\n <AlertBanner\n tone=\"info\"\n variant=\"box\"\n action={agree}\n onDismiss={props.onNotNow}\n dismissLabel={labels.notNow}\n className={className}\n data-consent-again=\"banner\"\n >\n <div className=\"space-y-1\">\n <p>\n <span className=\"font-medium\">{title}</span> <span className=\"text-secondary\">{intro}</span>\n </p>\n <Disclosure variant=\"bare\" title={labels.changesToggle}>\n <ChangeList changes={changes} />\n {props.wordingLink != null && <p className=\"mt-1 text-xs\">{props.wordingLink}</p>}\n </Disclosure>\n </div>\n </AlertBanner>\n );\n }\n\n const { wording, note, headingAs = \"h3\" } = props;\n const Sub = SUB_HEADING[headingAs];\n return (\n <Card\n tone=\"info\"\n toneStrength=\"strong\"\n toneFill\n density=\"compact\"\n padding=\"md\"\n className={cn(\"space-y-3\", className)}\n data-consent-again=\"card\"\n >\n <CardTitle as={headingAs}>{title}</CardTitle>\n <p className=\"text-sm text-secondary\">{intro}</p>\n <ChangeList changes={changes} />\n {wording && (\n <Disclosure variant=\"bare\" title={labels.wordingToggle}>\n <div className=\"space-y-3 pt-2 text-sm text-secondary\">\n <section className=\"space-y-1\">\n <Sub className=\"text-xs font-medium text-primary\">{labels.beforeHeading}</Sub>\n {wording.before.map((text, i) => (\n <p key={i}>\n <del>\n <span className=\"sr-only-fixed\">{labels.removed} </span>\n {text}\n </del>\n </p>\n ))}\n </section>\n <section className=\"space-y-1\">\n <Sub className=\"text-xs font-medium text-primary\">{labels.nowHeading}</Sub>\n {wording.now.map((text, i) => (\n <p key={i}>\n <ins className=\"no-underline\">\n <span className=\"sr-only-fixed\">{labels.added} </span>\n {text}\n </ins>\n </p>\n ))}\n </section>\n </div>\n </Disclosure>\n )}\n {note != null && <p className=\"text-xs text-muted\">{note}</p>}\n {agree && <div className=\"flex flex-wrap gap-2\">{agree}</div>}\n </Card>\n );\n}\n"],"mappings":"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","names":[]}
@@ -9,7 +9,7 @@ import { FieldChevron, FIELD_FLOATING_PAD, FIELD_INVALID, FIELD_TRIGGER, Floatin
9
9
  import {
10
10
  assignRef,
11
11
  EndHintRow,
12
- LockedReason,
12
+ LockFrame,
13
13
  mergeDescribedBy,
14
14
  useFieldMessages,
15
15
  useLockReason
@@ -223,12 +223,7 @@ function CountrySelect({
223
223
  ]
224
224
  }
225
225
  );
226
- const control = locked ? (
227
- // Button's frame: the line under the trigger, or the Tooltip with a hidden copy for
228
- // `aria-describedby`. `items-stretch`: in the line's column the trigger keeps the
229
- // field's full width.
230
- /* @__PURE__ */ jsx(LockedReason, { lock, display: disabledReasonDisplay, className: "flex w-full items-stretch", children: trigger })
231
- ) : trigger;
226
+ const control = /* @__PURE__ */ jsx(LockFrame, { lock, display: disabledReasonDisplay, className: "flex w-full items-stretch", children: trigger });
232
227
  const box = label !== void 0 ? /* @__PURE__ */ jsx(FloatingField, { htmlFor: triggerId, label, staticLabel: true, hint: field.labelHint, children: control }) : (
233
228
  // No label line to ride: a "?" goes at the field's end, outside the box, as on an
234
229
  // unlabelled Select.