@eifi1/ui-kit 0.53.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (902) hide show
  1. package/README.md +96 -82
  2. package/dist/account/delete-account-setting.d.ts +3 -2
  3. package/dist/account/delete-account-setting.js.map +1 -1
  4. package/dist/admin/plan-change.js +2 -2
  5. package/dist/admin/plan-change.js.map +1 -1
  6. package/dist/admin/user-roster.d.ts +6 -0
  7. package/dist/admin/user-roster.js +4 -0
  8. package/dist/admin/user-roster.js.map +1 -1
  9. package/dist/auth/auth-errors.d.ts +36 -0
  10. package/dist/auth/auth-errors.js +20 -0
  11. package/dist/auth/auth-errors.js.map +1 -1
  12. package/dist/billing/billing-labels.d.ts +26 -0
  13. package/dist/billing/billing-labels.js +9 -0
  14. package/dist/billing/billing-labels.js.map +1 -1
  15. package/dist/billing/subscription-standing.d.ts +61 -0
  16. package/dist/billing/subscription-standing.js +51 -0
  17. package/dist/billing/subscription-standing.js.map +1 -0
  18. package/dist/billing/usage-meter.d.ts +52 -0
  19. package/dist/billing/usage-meter.js +52 -0
  20. package/dist/billing/usage-meter.js.map +1 -0
  21. package/dist/chart.d.ts +1 -0
  22. package/dist/chart.js +4 -0
  23. package/dist/chart.js.map +1 -1
  24. package/dist/components/alert-banner.js +2 -3
  25. package/dist/components/alert-banner.js.map +1 -1
  26. package/dist/components/amount-input.d.ts +2 -1
  27. package/dist/components/amount-input.js +3 -15
  28. package/dist/components/amount-input.js.map +1 -1
  29. package/dist/components/autocomplete.js +2 -2
  30. package/dist/components/autocomplete.js.map +1 -1
  31. package/dist/components/bulk-action-bar.js +2 -1
  32. package/dist/components/bulk-action-bar.js.map +1 -1
  33. package/dist/components/button.d.ts +35 -1
  34. package/dist/components/button.js +5 -9
  35. package/dist/components/button.js.map +1 -1
  36. package/dist/components/calendar-heatmap.js +6 -4
  37. package/dist/components/calendar-heatmap.js.map +1 -1
  38. package/dist/components/camera-button.d.ts +89 -0
  39. package/dist/components/camera-button.js +122 -0
  40. package/dist/components/camera-button.js.map +1 -0
  41. package/dist/components/camera-capture.d.ts +66 -0
  42. package/dist/components/camera-capture.js +190 -0
  43. package/dist/components/camera-capture.js.map +1 -0
  44. package/dist/components/camera-labels.d.ts +20 -0
  45. package/dist/components/camera-labels.js +15 -0
  46. package/dist/components/camera-labels.js.map +1 -0
  47. package/dist/components/chart-edge.d.ts +9 -0
  48. package/dist/components/chart-edge.js +14 -3
  49. package/dist/components/chart-edge.js.map +1 -1
  50. package/dist/components/chart-zoom-core.js +34 -29
  51. package/dist/components/chart-zoom-core.js.map +1 -1
  52. package/dist/components/checkbox-group.js +1 -1
  53. package/dist/components/checkbox-group.js.map +1 -1
  54. package/dist/components/combobox-core.js +3 -2
  55. package/dist/components/combobox-core.js.map +1 -1
  56. package/dist/components/combobox.js +2 -2
  57. package/dist/components/combobox.js.map +1 -1
  58. package/dist/components/consent-again-notice-labels.d.ts +25 -0
  59. package/dist/components/consent-again-notice-labels.js +15 -0
  60. package/dist/components/consent-again-notice-labels.js.map +1 -0
  61. package/dist/components/consent-again-notice.d.ts +85 -0
  62. package/dist/components/consent-again-notice.js +94 -0
  63. package/dist/components/consent-again-notice.js.map +1 -0
  64. package/dist/components/country-select.js +2 -7
  65. package/dist/components/country-select.js.map +1 -1
  66. package/dist/components/currency-option-list.d.ts +2 -1
  67. package/dist/components/currency-option-list.js +10 -3
  68. package/dist/components/currency-option-list.js.map +1 -1
  69. package/dist/components/currency-select.d.ts +3 -1
  70. package/dist/components/currency-select.js +2 -2
  71. package/dist/components/currency-select.js.map +1 -1
  72. package/dist/components/danger-confirm.d.ts +22 -1
  73. package/dist/components/danger-confirm.js +52 -30
  74. package/dist/components/danger-confirm.js.map +1 -1
  75. package/dist/components/data-table-column-settings.js +2 -2
  76. package/dist/components/data-table-column-settings.js.map +1 -1
  77. package/dist/components/data-table-filter-popover.d.ts +2 -1
  78. package/dist/components/data-table-filter-popover.js +3 -2
  79. package/dist/components/data-table-filter-popover.js.map +1 -1
  80. package/dist/components/data-table-filters.d.ts +33 -3
  81. package/dist/components/data-table-filters.js +6 -4
  82. package/dist/components/data-table-filters.js.map +1 -1
  83. package/dist/components/data-table-fit.js.map +1 -1
  84. package/dist/components/data-table-virtual.js +13 -3
  85. package/dist/components/data-table-virtual.js.map +1 -1
  86. package/dist/components/date-field.js +2 -2
  87. package/dist/components/date-field.js.map +1 -1
  88. package/dist/components/date-picker.js +2 -2
  89. package/dist/components/date-picker.js.map +1 -1
  90. package/dist/components/date-range-picker.js +2 -6
  91. package/dist/components/date-range-picker.js.map +1 -1
  92. package/dist/components/dialog-frame.d.ts +5 -1
  93. package/dist/components/dialog-frame.js +6 -2
  94. package/dist/components/dialog-frame.js.map +1 -1
  95. package/dist/components/dropdown.js +7 -3
  96. package/dist/components/dropdown.js.map +1 -1
  97. package/dist/components/entity-combobox.js +2 -2
  98. package/dist/components/entity-combobox.js.map +1 -1
  99. package/dist/components/field-parts.d.ts +108 -6
  100. package/dist/components/field-parts.js +59 -6
  101. package/dist/components/field-parts.js.map +1 -1
  102. package/dist/components/field-suggestion-labels.d.ts +2 -0
  103. package/dist/components/field-suggestion-labels.js +10 -0
  104. package/dist/components/field-suggestion-labels.js.map +1 -0
  105. package/dist/components/field.js +1 -1
  106. package/dist/components/field.js.map +1 -1
  107. package/dist/components/file-button.d.ts +1 -1
  108. package/dist/components/file-button.js.map +1 -1
  109. package/dist/components/floating-panel.d.ts +7 -6
  110. package/dist/components/floating-panel.js +3 -17
  111. package/dist/components/floating-panel.js.map +1 -1
  112. package/dist/components/form-actions.d.ts +3 -2
  113. package/dist/components/form-actions.js.map +1 -1
  114. package/dist/components/hover-menu.js +3 -2
  115. package/dist/components/hover-menu.js.map +1 -1
  116. package/dist/components/icon-button.d.ts +23 -5
  117. package/dist/components/icon-button.js +6 -8
  118. package/dist/components/icon-button.js.map +1 -1
  119. package/dist/components/inline-confirm.js +2 -1
  120. package/dist/components/inline-confirm.js.map +1 -1
  121. package/dist/components/inline-entity-combobox.js +2 -2
  122. package/dist/components/inline-entity-combobox.js.map +1 -1
  123. package/dist/components/input.js +2 -2
  124. package/dist/components/input.js.map +1 -1
  125. package/dist/components/jump-calendar.js +3 -3
  126. package/dist/components/jump-calendar.js.map +1 -1
  127. package/dist/components/legal.d.ts +13 -1
  128. package/dist/components/legal.js +12 -0
  129. package/dist/components/legal.js.map +1 -1
  130. package/dist/components/legended-series-chart.d.ts +80 -0
  131. package/dist/components/legended-series-chart.js +70 -0
  132. package/dist/components/legended-series-chart.js.map +1 -0
  133. package/dist/components/lightbox.js +2 -1
  134. package/dist/components/lightbox.js.map +1 -1
  135. package/dist/components/mini-calendar.js +16 -7
  136. package/dist/components/mini-calendar.js.map +1 -1
  137. package/dist/components/modal.d.ts +48 -0
  138. package/dist/components/modal.js +26 -6
  139. package/dist/components/modal.js.map +1 -1
  140. package/dist/components/month-picker.d.ts +1 -1
  141. package/dist/components/month-picker.js +6 -6
  142. package/dist/components/month-picker.js.map +1 -1
  143. package/dist/components/multi-entity-combobox.js +2 -2
  144. package/dist/components/multi-entity-combobox.js.map +1 -1
  145. package/dist/components/multi-select.js +2 -6
  146. package/dist/components/multi-select.js.map +1 -1
  147. package/dist/components/number-input.js +2 -2
  148. package/dist/components/number-input.js.map +1 -1
  149. package/dist/components/page-header-layout.d.ts +18 -0
  150. package/dist/components/page-header-layout.js +23 -0
  151. package/dist/components/page-header-layout.js.map +1 -0
  152. package/dist/components/page-header-skeleton.d.ts +41 -0
  153. package/dist/components/page-header-skeleton.js +52 -0
  154. package/dist/components/page-header-skeleton.js.map +1 -0
  155. package/dist/components/page-header.js +4 -17
  156. package/dist/components/page-header.js.map +1 -1
  157. package/dist/components/popover.js +7 -2
  158. package/dist/components/popover.js.map +1 -1
  159. package/dist/components/release-notes-labels.d.ts +16 -0
  160. package/dist/components/release-notes-labels.js +18 -0
  161. package/dist/components/release-notes-labels.js.map +1 -0
  162. package/dist/components/release-notes.d.ts +65 -0
  163. package/dist/components/release-notes.js +65 -0
  164. package/dist/components/release-notes.js.map +1 -0
  165. package/dist/components/select.js +2 -2
  166. package/dist/components/select.js.map +1 -1
  167. package/dist/components/series-chart-labels.d.ts +9 -0
  168. package/dist/components/series-chart-labels.js +3 -1
  169. package/dist/components/series-chart-labels.js.map +1 -1
  170. package/dist/components/series-chart.d.ts +5 -0
  171. package/dist/components/series-chart.js +89 -36
  172. package/dist/components/series-chart.js.map +1 -1
  173. package/dist/components/stat-tile.d.ts +21 -2
  174. package/dist/components/stat-tile.js +4 -2
  175. package/dist/components/stat-tile.js.map +1 -1
  176. package/dist/components/toggle-group.js +3 -2
  177. package/dist/components/toggle-group.js.map +1 -1
  178. package/dist/components/treemap-layout.js.map +1 -1
  179. package/dist/components/treemap.d.ts +17 -15
  180. package/dist/components/treemap.js +167 -85
  181. package/dist/components/treemap.js.map +1 -1
  182. package/dist/currencies.d.ts +16 -2
  183. package/dist/currencies.js +2 -1
  184. package/dist/currencies.js.map +1 -1
  185. package/dist/eslint/index.js +1 -1
  186. package/dist/eslint/role-utilities.d.ts +2 -2
  187. package/dist/eslint/role-utilities.js.map +1 -1
  188. package/dist/feedback/feedback-context-labels.js +2 -1
  189. package/dist/feedback/feedback-context-labels.js.map +1 -1
  190. package/dist/feedback/feedback-context.d.ts +19 -3
  191. package/dist/feedback/feedback-context.js +12 -1
  192. package/dist/feedback/feedback-context.js.map +1 -1
  193. package/dist/feedback/feedback-diagnostics.d.ts +17 -0
  194. package/dist/feedback/feedback-diagnostics.js +27 -0
  195. package/dist/feedback/feedback-diagnostics.js.map +1 -0
  196. package/dist/feedback/feedback-dialog.d.ts +10 -0
  197. package/dist/feedback/feedback-dialog.js +6 -4
  198. package/dist/feedback/feedback-dialog.js.map +1 -1
  199. package/dist/feedback/feedback-inbox-page.d.ts +260 -0
  200. package/dist/feedback/feedback-inbox-page.js +207 -0
  201. package/dist/feedback/feedback-inbox-page.js.map +1 -0
  202. package/dist/feedback/feedback-record.d.ts +5 -0
  203. package/dist/feedback/feedback-record.js.map +1 -1
  204. package/dist/feedback/feedback-row-detail-labels.js +1 -0
  205. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  206. package/dist/feedback/feedback-row-detail.d.ts +3 -0
  207. package/dist/feedback/feedback-row-detail.js +3 -0
  208. package/dist/feedback/feedback-row-detail.js.map +1 -1
  209. package/dist/feedback/feedback-submit-dialog.d.ts +5 -1
  210. package/dist/feedback/feedback-submit-dialog.js +15 -3
  211. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  212. package/dist/feedback/feedback-submit.d.ts +30 -2
  213. package/dist/feedback/feedback-submit.js +5 -2
  214. package/dist/feedback/feedback-submit.js.map +1 -1
  215. package/dist/feedback/feedback-vocabulary.js +2 -2
  216. package/dist/feedback/feedback-vocabulary.js.map +1 -1
  217. package/dist/feedback.d.ts +1 -0
  218. package/dist/feedback.js +6 -0
  219. package/dist/feedback.js.map +1 -1
  220. package/dist/hooks/use-debounce.d.ts +32 -5
  221. package/dist/hooks/use-debounce.js +6 -5
  222. package/dist/hooks/use-debounce.js.map +1 -1
  223. package/dist/hooks/use-file-picker.d.ts +3 -1
  224. package/dist/hooks/use-file-picker.js.map +1 -1
  225. package/dist/hooks/use-focus-trap.d.ts +19 -3
  226. package/dist/hooks/use-focus-trap.js +15 -5
  227. package/dist/hooks/use-focus-trap.js.map +1 -1
  228. package/dist/hooks/use-has-camera.d.ts +36 -0
  229. package/dist/hooks/use-has-camera.js +53 -0
  230. package/dist/hooks/use-has-camera.js.map +1 -0
  231. package/dist/hooks/use-hotkey.js +2 -1
  232. package/dist/hooks/use-hotkey.js.map +1 -1
  233. package/dist/hooks/use-overlay-history.d.ts +6 -1
  234. package/dist/hooks/use-overlay-history.js +10 -2
  235. package/dist/hooks/use-overlay-history.js.map +1 -1
  236. package/dist/i18n/defaults.js +11 -1
  237. package/dist/i18n/defaults.js.map +1 -1
  238. package/dist/i18n/german.js +78 -4
  239. package/dist/i18n/german.js.map +1 -1
  240. package/dist/i18n/kit-labels.d.ts +20 -0
  241. package/dist/i18n/kit-labels.js.map +1 -1
  242. package/dist/i18n/locales/en.js +95 -5
  243. package/dist/i18n/locales/en.js.map +3 -3
  244. package/dist/i18n/locales/es.js +74 -4
  245. package/dist/i18n/locales/es.js.map +1 -1
  246. package/dist/i18n/locales/fr.js +75 -3
  247. package/dist/i18n/locales/fr.js.map +1 -1
  248. package/dist/i18n/locales/hu.js +77 -4
  249. package/dist/i18n/locales/hu.js.map +1 -1
  250. package/dist/i18n/locales/it.js +77 -4
  251. package/dist/i18n/locales/it.js.map +1 -1
  252. package/dist/i18n/locales/zh.js +74 -4
  253. package/dist/i18n/locales/zh.js.map +1 -1
  254. package/dist/i18n/review.js +22 -1
  255. package/dist/i18n/review.js.map +1 -1
  256. package/dist/index.d.ts +27 -8
  257. package/dist/index.js +41 -2
  258. package/dist/index.js.map +1 -1
  259. package/dist/landing/landing-labels.d.ts +8 -0
  260. package/dist/landing/landing-labels.js +2 -1
  261. package/dist/landing/landing-labels.js.map +1 -1
  262. package/dist/lib/changelog.d.ts +130 -0
  263. package/dist/lib/changelog.js +137 -0
  264. package/dist/lib/changelog.js.map +1 -0
  265. package/dist/lib/clipboard-minus.js +2 -2
  266. package/dist/lib/clipboard-minus.js.map +1 -1
  267. package/dist/lib/dates.d.ts +36 -4
  268. package/dist/lib/dates.js +49 -13
  269. package/dist/lib/dates.js.map +1 -1
  270. package/dist/lib/editable-content.d.ts +33 -0
  271. package/dist/lib/editable-content.js +15 -0
  272. package/dist/lib/editable-content.js.map +1 -0
  273. package/dist/lib/focus-left.d.ts +47 -1
  274. package/dist/lib/focus-left.js +11 -2
  275. package/dist/lib/focus-left.js.map +1 -1
  276. package/dist/lib/format.d.ts +37 -2
  277. package/dist/lib/format.js +25 -1
  278. package/dist/lib/format.js.map +1 -1
  279. package/dist/lib/intl-cache.d.ts +4 -2
  280. package/dist/lib/intl-cache.js.map +1 -1
  281. package/dist/lib/server-wake.d.ts +49 -9
  282. package/dist/lib/server-wake.js +25 -14
  283. package/dist/lib/server-wake.js.map +1 -1
  284. package/dist/lib/session-refresh.d.ts +53 -0
  285. package/dist/lib/session-refresh.js +27 -1
  286. package/dist/lib/session-refresh.js.map +1 -1
  287. package/dist/lib/translation-review.d.ts +26 -0
  288. package/dist/lib/translation-review.js +14 -0
  289. package/dist/lib/translation-review.js.map +1 -1
  290. package/dist/rhf/fields.js +3 -3
  291. package/dist/rhf/fields.js.map +1 -1
  292. package/dist/shell/app-shell.d.ts +25 -1
  293. package/dist/shell/app-shell.js +3 -1
  294. package/dist/shell/app-shell.js.map +1 -1
  295. package/dist/shell/dev-menu.d.ts +3 -0
  296. package/dist/shell/dev-menu.js +4 -2
  297. package/dist/shell/dev-menu.js.map +1 -1
  298. package/dist/shell/held-changes-banner-labels.d.ts +23 -0
  299. package/dist/shell/held-changes-banner-labels.js +14 -0
  300. package/dist/shell/held-changes-banner-labels.js.map +1 -0
  301. package/dist/shell/held-changes-banner.d.ts +75 -0
  302. package/dist/shell/held-changes-banner.js +106 -0
  303. package/dist/shell/held-changes-banner.js.map +1 -0
  304. package/dist/shell/sync-status-indicator.d.ts +27 -12
  305. package/dist/shell/sync-status-indicator.js +13 -4
  306. package/dist/shell/sync-status-indicator.js.map +1 -1
  307. package/dist/shell/top-bar-parts-labels.d.ts +5 -0
  308. package/dist/shell/top-bar-parts-labels.js +3 -1
  309. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  310. package/dist/shell.d.ts +2 -0
  311. package/dist/shell.js +3 -0
  312. package/dist/shell.js.map +1 -1
  313. package/dist/sync/engine.d.ts +11 -2
  314. package/dist/sync/engine.js +13 -5
  315. package/dist/sync/engine.js.map +1 -1
  316. package/dist/sync/hooks.d.ts +3 -2
  317. package/dist/sync/hooks.js +4 -2
  318. package/dist/sync/hooks.js.map +1 -1
  319. package/dist/testing/css-variables.generated.d.ts +2 -2
  320. package/dist/testing/css-variables.generated.js +1 -1
  321. package/dist/testing/css-variables.generated.js.map +1 -1
  322. package/dist/theme/chart-palette.d.ts +18 -0
  323. package/dist/theme/chart-palette.js +17 -1
  324. package/dist/theme/chart-palette.js.map +1 -1
  325. package/dist/theme/contrast-tokens.d.ts +3 -3
  326. package/dist/theme/contrast-tokens.js.map +1 -1
  327. package/dist/theme/contrast.d.ts +4 -4
  328. package/dist/theme/contrast.js.map +1 -1
  329. package/dist/tour/tour-overlay.js +2 -1
  330. package/dist/tour/tour-overlay.js.map +1 -1
  331. package/package.json +5 -9
  332. package/tokens.css +19 -54
  333. package/src/account/account-parts.ts +0 -47
  334. package/src/account/account-settings-labels.ts +0 -240
  335. package/src/account/account-settings.tsx +0 -698
  336. package/src/account/data-export-setting-labels.ts +0 -20
  337. package/src/account/data-export-setting.tsx +0 -200
  338. package/src/account/delete-account-setting-labels.ts +0 -33
  339. package/src/account/delete-account-setting.tsx +0 -341
  340. package/src/account/email-change-setting-labels.ts +0 -31
  341. package/src/account/email-change-setting.tsx +0 -443
  342. package/src/account/passkeys-setting.tsx +0 -445
  343. package/src/account/sessions-setting-labels.ts +0 -24
  344. package/src/account/sessions-setting.tsx +0 -283
  345. package/src/admin/admin-action-confirm-labels.ts +0 -19
  346. package/src/admin/admin-action-confirm.tsx +0 -509
  347. package/src/admin/admin-action-log-labels.ts +0 -83
  348. package/src/admin/admin-action-log.tsx +0 -464
  349. package/src/admin/admin-area-labels.ts +0 -114
  350. package/src/admin/admin-forbidden.tsx +0 -75
  351. package/src/admin/admin-overview.tsx +0 -258
  352. package/src/admin/admin-parts.ts +0 -68
  353. package/src/admin/admin-sections.tsx +0 -208
  354. package/src/admin/admin-tool-links.tsx +0 -90
  355. package/src/admin/invitations-panel-labels.ts +0 -31
  356. package/src/admin/invitations-panel.tsx +0 -516
  357. package/src/admin/mail-test-card-labels.ts +0 -19
  358. package/src/admin/mail-test-card.tsx +0 -189
  359. package/src/admin/plan-change-labels.ts +0 -5
  360. package/src/admin/plan-change.tsx +0 -474
  361. package/src/admin/reviewer-scope-editor-labels.ts +0 -16
  362. package/src/admin/reviewer-scope-editor.tsx +0 -224
  363. package/src/admin/role-select-labels.ts +0 -16
  364. package/src/admin/role-select.tsx +0 -282
  365. package/src/admin/transfer-ownership-dialog-labels.ts +0 -20
  366. package/src/admin/transfer-ownership-dialog.tsx +0 -162
  367. package/src/admin/user-roster-labels.ts +0 -17
  368. package/src/admin/user-roster.tsx +0 -559
  369. package/src/auth/accept-invitation-labels.ts +0 -21
  370. package/src/auth/accept-invitation.tsx +0 -210
  371. package/src/auth/auth-errors-labels.ts +0 -23
  372. package/src/auth/auth-errors.ts +0 -370
  373. package/src/auth/complete-name-dialog-labels.ts +0 -16
  374. package/src/auth/complete-name-dialog.tsx +0 -253
  375. package/src/auth/email-tag.ts +0 -75
  376. package/src/auth/forgot-password-form-labels.ts +0 -20
  377. package/src/auth/forgot-password-form.tsx +0 -221
  378. package/src/auth/form-rules.ts +0 -40
  379. package/src/auth/new-password-fields.tsx +0 -85
  380. package/src/auth/not-found-page-labels.ts +0 -12
  381. package/src/auth/not-found-page.tsx +0 -95
  382. package/src/auth/register-form-labels.ts +0 -31
  383. package/src/auth/register-form.tsx +0 -456
  384. package/src/auth/reset-password-form-labels.ts +0 -27
  385. package/src/auth/reset-password-form.tsx +0 -341
  386. package/src/auth/sign-in-form-labels.ts +0 -44
  387. package/src/auth/sign-in-form.tsx +0 -858
  388. package/src/auth/status-parts.tsx +0 -132
  389. package/src/auth/verify-email-labels.ts +0 -26
  390. package/src/auth/verify-email.tsx +0 -445
  391. package/src/billing/billing-banner.tsx +0 -258
  392. package/src/billing/billing-labels.ts +0 -381
  393. package/src/billing/billing-lock.ts +0 -108
  394. package/src/billing/billing-overview.ts +0 -157
  395. package/src/billing/billing-standing.ts +0 -80
  396. package/src/billing/cancel-request.ts +0 -97
  397. package/src/billing/cancel-subscription.tsx +0 -98
  398. package/src/billing/checkout-processing.ts +0 -394
  399. package/src/billing/checkout-return.ts +0 -90
  400. package/src/billing/pay-page.ts +0 -330
  401. package/src/billing/plan-card.tsx +0 -562
  402. package/src/billing/plan-change-labels.ts +0 -66
  403. package/src/billing/plan-limit-notice.tsx +0 -148
  404. package/src/billing/plan-limit-toast.tsx +0 -90
  405. package/src/billing/plan-limit.ts +0 -52
  406. package/src/billing/plan-price.ts +0 -98
  407. package/src/billing/plan-switch.tsx +0 -216
  408. package/src/billing/provider-page.ts +0 -84
  409. package/src/billing/subscription-actions.tsx +0 -247
  410. package/src/billing/subscription-status-chip.tsx +0 -95
  411. package/src/chart.ts +0 -103
  412. package/src/components/account-chips-labels.ts +0 -16
  413. package/src/components/account-chips.tsx +0 -474
  414. package/src/components/alert-banner.tsx +0 -670
  415. package/src/components/amount-input.tsx +0 -815
  416. package/src/components/appearance-labels.ts +0 -63
  417. package/src/components/authed-image-labels.ts +0 -11
  418. package/src/components/authed-image.tsx +0 -209
  419. package/src/components/autocomplete.tsx +0 -645
  420. package/src/components/breadcrumbs-labels.ts +0 -10
  421. package/src/components/breadcrumbs.tsx +0 -205
  422. package/src/components/bulk-action-bar-labels.ts +0 -11
  423. package/src/components/bulk-action-bar.tsx +0 -443
  424. package/src/components/button-group.tsx +0 -223
  425. package/src/components/button-look.ts +0 -256
  426. package/src/components/button.tsx +0 -339
  427. package/src/components/calculator.tsx +0 -341
  428. package/src/components/calendar-heatmap-labels.ts +0 -15
  429. package/src/components/calendar-heatmap.tsx +0 -594
  430. package/src/components/card.tsx +0 -377
  431. package/src/components/chart-edge.ts +0 -106
  432. package/src/components/chart-figure.tsx +0 -35
  433. package/src/components/chart-height.ts +0 -30
  434. package/src/components/chart-zoom-core.tsx +0 -627
  435. package/src/components/chart-zoom.tsx +0 -22
  436. package/src/components/chart.tsx +0 -554
  437. package/src/components/checkbox-group.tsx +0 -247
  438. package/src/components/checkbox.tsx +0 -346
  439. package/src/components/chip-input.tsx +0 -370
  440. package/src/components/chip-labels.ts +0 -13
  441. package/src/components/chip.tsx +0 -843
  442. package/src/components/choice-card.tsx +0 -544
  443. package/src/components/column-mapper-labels.ts +0 -38
  444. package/src/components/column-mapper.tsx +0 -655
  445. package/src/components/combobox-core.tsx +0 -1321
  446. package/src/components/combobox-suggestions.tsx +0 -131
  447. package/src/components/combobox.tsx +0 -716
  448. package/src/components/confirm-context.ts +0 -7
  449. package/src/components/confirm-dialog-labels.ts +0 -13
  450. package/src/components/confirm-dialog.tsx +0 -341
  451. package/src/components/copy-button-labels.ts +0 -13
  452. package/src/components/copy-button.tsx +0 -192
  453. package/src/components/country-select-labels.ts +0 -11
  454. package/src/components/country-select.tsx +0 -539
  455. package/src/components/currency-option-list.tsx +0 -180
  456. package/src/components/currency-select.tsx +0 -341
  457. package/src/components/danger-confirm-labels.ts +0 -20
  458. package/src/components/danger-confirm.tsx +0 -934
  459. package/src/components/data-table-cells.tsx +0 -118
  460. package/src/components/data-table-column-settings.tsx +0 -198
  461. package/src/components/data-table-filter-popover.tsx +0 -281
  462. package/src/components/data-table-filters.ts +0 -287
  463. package/src/components/data-table-fit.ts +0 -301
  464. package/src/components/data-table-groups.tsx +0 -288
  465. package/src/components/data-table-head.tsx +0 -280
  466. package/src/components/data-table-labels.ts +0 -198
  467. package/src/components/data-table-leading-row.tsx +0 -58
  468. package/src/components/data-table-mobile.tsx +0 -1117
  469. package/src/components/data-table-pagination.tsx +0 -202
  470. package/src/components/data-table-resize.ts +0 -188
  471. package/src/components/data-table-row-actions.tsx +0 -302
  472. package/src/components/data-table-row.tsx +0 -496
  473. package/src/components/data-table-selection.ts +0 -71
  474. package/src/components/data-table-shared.tsx +0 -287
  475. package/src/components/data-table-sort.ts +0 -163
  476. package/src/components/data-table-virtual.ts +0 -576
  477. package/src/components/data-table.tsx +0 -2598
  478. package/src/components/date-field.tsx +0 -684
  479. package/src/components/date-format-setting.tsx +0 -64
  480. package/src/components/date-picker.tsx +0 -404
  481. package/src/components/date-range-picker.tsx +0 -518
  482. package/src/components/description-list-labels.ts +0 -9
  483. package/src/components/description-list.tsx +0 -386
  484. package/src/components/dialog-frame-labels.ts +0 -7
  485. package/src/components/dialog-frame.tsx +0 -276
  486. package/src/components/disclosure.tsx +0 -476
  487. package/src/components/dropdown.tsx +0 -461
  488. package/src/components/empty-state.tsx +0 -136
  489. package/src/components/entity-combobox.tsx +0 -422
  490. package/src/components/error-boundary-labels.ts +0 -20
  491. package/src/components/error-boundary.tsx +0 -675
  492. package/src/components/facing-pair.ts +0 -93
  493. package/src/components/field-base-labels.ts +0 -20
  494. package/src/components/field-base.tsx +0 -656
  495. package/src/components/field-parts.tsx +0 -825
  496. package/src/components/field-strip.tsx +0 -129
  497. package/src/components/field.tsx +0 -206
  498. package/src/components/file-button.tsx +0 -295
  499. package/src/components/file-dropzone.tsx +0 -559
  500. package/src/components/floating-panel-labels.ts +0 -10
  501. package/src/components/floating-panel.tsx +0 -828
  502. package/src/components/focus-ring.ts +0 -16
  503. package/src/components/form-actions-labels.ts +0 -11
  504. package/src/components/form-actions.tsx +0 -578
  505. package/src/components/full-bleed-dialog.tsx +0 -294
  506. package/src/components/grouped-picker.tsx +0 -184
  507. package/src/components/help-popover.tsx +0 -117
  508. package/src/components/hover-menu.tsx +0 -343
  509. package/src/components/iban-input-labels.ts +0 -14
  510. package/src/components/iban-input.tsx +0 -236
  511. package/src/components/icon-button.tsx +0 -959
  512. package/src/components/icon-picker-labels.ts +0 -13
  513. package/src/components/icon-picker.tsx +0 -232
  514. package/src/components/image-grid-labels.ts +0 -11
  515. package/src/components/image-grid.tsx +0 -202
  516. package/src/components/inline-confirm.tsx +0 -116
  517. package/src/components/inline-edit-field-labels.ts +0 -11
  518. package/src/components/inline-edit-field.tsx +0 -552
  519. package/src/components/inline-entity-combobox.tsx +0 -849
  520. package/src/components/input.tsx +0 -394
  521. package/src/components/jump-calendar.tsx +0 -265
  522. package/src/components/language-select.tsx +0 -93
  523. package/src/components/legal-labels.ts +0 -105
  524. package/src/components/legal-page.tsx +0 -711
  525. package/src/components/legal.tsx +0 -668
  526. package/src/components/lightbox-labels.ts +0 -18
  527. package/src/components/lightbox.tsx +0 -399
  528. package/src/components/line-items-labels.ts +0 -14
  529. package/src/components/line-items.tsx +0 -602
  530. package/src/components/list-labels.ts +0 -12
  531. package/src/components/list.tsx +0 -870
  532. package/src/components/loading-state.tsx +0 -78
  533. package/src/components/measured-grid-labels.ts +0 -25
  534. package/src/components/measured-grid.tsx +0 -837
  535. package/src/components/menu-item.tsx +0 -241
  536. package/src/components/mini-calendar-labels.ts +0 -17
  537. package/src/components/mini-calendar.tsx +0 -789
  538. package/src/components/modal.tsx +0 -505
  539. package/src/components/money-draft.ts +0 -83
  540. package/src/components/money-field.tsx +0 -76
  541. package/src/components/month-grid.tsx +0 -229
  542. package/src/components/month-picker-labels.ts +0 -22
  543. package/src/components/month-picker.tsx +0 -1087
  544. package/src/components/multi-entity-combobox.tsx +0 -369
  545. package/src/components/multi-select.tsx +0 -376
  546. package/src/components/nav-pills.tsx +0 -198
  547. package/src/components/number-field.tsx +0 -327
  548. package/src/components/number-input.tsx +0 -558
  549. package/src/components/numeric-field.ts +0 -169
  550. package/src/components/numpad-sheet.tsx +0 -285
  551. package/src/components/one-time-code-input.tsx +0 -270
  552. package/src/components/page-contents-labels.ts +0 -9
  553. package/src/components/page-contents.tsx +0 -282
  554. package/src/components/page-header-context.ts +0 -8
  555. package/src/components/page-header.tsx +0 -298
  556. package/src/components/password-strength-labels.ts +0 -22
  557. package/src/components/password-strength.tsx +0 -241
  558. package/src/components/phone-input-labels.ts +0 -10
  559. package/src/components/phone-input.tsx +0 -282
  560. package/src/components/picker-sheet.tsx +0 -330
  561. package/src/components/pie-chart-labels.ts +0 -40
  562. package/src/components/pie-chart.tsx +0 -480
  563. package/src/components/popover-labels.ts +0 -14
  564. package/src/components/popover.tsx +0 -268
  565. package/src/components/progress-bar-labels.ts +0 -10
  566. package/src/components/progress-bar.tsx +0 -479
  567. package/src/components/qr-code.tsx +0 -76
  568. package/src/components/reauth-dialog-labels.ts +0 -13
  569. package/src/components/reauth-dialog.tsx +0 -265
  570. package/src/components/row-actions-labels.ts +0 -12
  571. package/src/components/row-actions.tsx +0 -795
  572. package/src/components/scroll-area.tsx +0 -123
  573. package/src/components/search-field.tsx +0 -192
  574. package/src/components/select.tsx +0 -294
  575. package/src/components/separator.tsx +0 -33
  576. package/src/components/series-chart-axes.ts +0 -342
  577. package/src/components/series-chart-budget.ts +0 -150
  578. package/src/components/series-chart-labels.ts +0 -33
  579. package/src/components/series-chart-thin.ts +0 -180
  580. package/src/components/series-chart-ticks.ts +0 -194
  581. package/src/components/series-chart.tsx +0 -1906
  582. package/src/components/server-wake-labels.ts +0 -11
  583. package/src/components/server-wake.tsx +0 -129
  584. package/src/components/settings-fields.tsx +0 -237
  585. package/src/components/share-card-labels.ts +0 -30
  586. package/src/components/share-card.tsx +0 -675
  587. package/src/components/signature-pad-labels.ts +0 -24
  588. package/src/components/signature-pad.tsx +0 -747
  589. package/src/components/signed-amount-labels.ts +0 -10
  590. package/src/components/signed-amount.tsx +0 -336
  591. package/src/components/skeleton.tsx +0 -80
  592. package/src/components/slider.tsx +0 -338
  593. package/src/components/sparkline-labels.ts +0 -14
  594. package/src/components/sparkline.tsx +0 -322
  595. package/src/components/spinner.tsx +0 -81
  596. package/src/components/stat-tile-labels.ts +0 -15
  597. package/src/components/stat-tile.tsx +0 -725
  598. package/src/components/status-dot.tsx +0 -170
  599. package/src/components/swatch-picker-labels.ts +0 -10
  600. package/src/components/swatch-picker.tsx +0 -283
  601. package/src/components/swipeable-row.tsx +0 -386
  602. package/src/components/switch.tsx +0 -273
  603. package/src/components/table-skeleton.tsx +0 -136
  604. package/src/components/table.tsx +0 -647
  605. package/src/components/tabs-labels.ts +0 -13
  606. package/src/components/tabs.tsx +0 -693
  607. package/src/components/text-link.tsx +0 -359
  608. package/src/components/text.tsx +0 -150
  609. package/src/components/textarea.tsx +0 -330
  610. package/src/components/tile-radio.tsx +0 -332
  611. package/src/components/time-input.tsx +0 -121
  612. package/src/components/toast-labels.ts +0 -12
  613. package/src/components/toast.tsx +0 -519
  614. package/src/components/toggle-group.tsx +0 -752
  615. package/src/components/toggle-legend.tsx +0 -394
  616. package/src/components/tooltip.tsx +0 -1149
  617. package/src/components/translation-review-editor.tsx +0 -290
  618. package/src/components/translation-review-labels.ts +0 -181
  619. package/src/components/translation-review-parts.tsx +0 -272
  620. package/src/components/translation-review.tsx +0 -1240
  621. package/src/components/tree-view.tsx +0 -589
  622. package/src/components/treemap-labels.ts +0 -47
  623. package/src/components/treemap-layout.ts +0 -210
  624. package/src/components/treemap.tsx +0 -1184
  625. package/src/components/trigger-aria.ts +0 -44
  626. package/src/components/use-anchor-dir.ts +0 -20
  627. package/src/components/use-mobile-reveal.ts +0 -62
  628. package/src/components/use-table-state.ts +0 -753
  629. package/src/components/user-avatar.tsx +0 -116
  630. package/src/components/wizard-stepper.tsx +0 -42
  631. package/src/components/write-lock-labels.ts +0 -10
  632. package/src/components/write-lock.tsx +0 -253
  633. package/src/currencies.ts +0 -70
  634. package/src/data-table.ts +0 -42
  635. package/src/demo/demo-banner.tsx +0 -153
  636. package/src/demo/demo-countdown.ts +0 -136
  637. package/src/demo/demo-ended.tsx +0 -90
  638. package/src/demo/demo-labels.ts +0 -78
  639. package/src/demo/demo-session.ts +0 -32
  640. package/src/demo/demo-start.tsx +0 -156
  641. package/src/eslint/index.ts +0 -161
  642. package/src/eslint/role-utilities.generated.ts +0 -146
  643. package/src/eslint/role-utilities.ts +0 -233
  644. package/src/feedback/feedback-attachment-download.tsx +0 -77
  645. package/src/feedback/feedback-attachment-labels.ts +0 -37
  646. package/src/feedback/feedback-attachment.tsx +0 -1239
  647. package/src/feedback/feedback-capture.ts +0 -287
  648. package/src/feedback/feedback-comment-thread.tsx +0 -353
  649. package/src/feedback/feedback-context-labels.ts +0 -10
  650. package/src/feedback/feedback-context.tsx +0 -213
  651. package/src/feedback/feedback-crash.ts +0 -547
  652. package/src/feedback/feedback-dialog-labels.ts +0 -29
  653. package/src/feedback/feedback-dialog.tsx +0 -440
  654. package/src/feedback/feedback-entry-file.tsx +0 -150
  655. package/src/feedback/feedback-inbox.tsx +0 -552
  656. package/src/feedback/feedback-labels.ts +0 -144
  657. package/src/feedback/feedback-menu-labels.ts +0 -12
  658. package/src/feedback/feedback-menu.tsx +0 -177
  659. package/src/feedback/feedback-mutation.ts +0 -20
  660. package/src/feedback/feedback-page-link.ts +0 -90
  661. package/src/feedback/feedback-public-labels.ts +0 -81
  662. package/src/feedback/feedback-public-list.tsx +0 -524
  663. package/src/feedback/feedback-public-switch.tsx +0 -102
  664. package/src/feedback/feedback-public-types.ts +0 -101
  665. package/src/feedback/feedback-record.ts +0 -423
  666. package/src/feedback/feedback-replies-context.ts +0 -9
  667. package/src/feedback/feedback-replies.tsx +0 -343
  668. package/src/feedback/feedback-rework-entry-chip.tsx +0 -18
  669. package/src/feedback/feedback-row-detail-labels.ts +0 -30
  670. package/src/feedback/feedback-row-detail.tsx +0 -858
  671. package/src/feedback/feedback-status-undo.ts +0 -109
  672. package/src/feedback/feedback-submit-dialog.tsx +0 -118
  673. package/src/feedback/feedback-submit.tsx +0 -237
  674. package/src/feedback/feedback-swipe.tsx +0 -192
  675. package/src/feedback/feedback-table-labels.ts +0 -27
  676. package/src/feedback/feedback-table.tsx +0 -912
  677. package/src/feedback/feedback-thread-labels.ts +0 -22
  678. package/src/feedback/feedback-thread-parts-labels.ts +0 -41
  679. package/src/feedback/feedback-thread.tsx +0 -905
  680. package/src/feedback/feedback-vocabulary.ts +0 -263
  681. package/src/feedback/feedback-vote-button.tsx +0 -124
  682. package/src/feedback.ts +0 -116
  683. package/src/hooks/use-anchored-panel.ts +0 -396
  684. package/src/hooks/use-anchored-rect.ts +0 -77
  685. package/src/hooks/use-announce.ts +0 -85
  686. package/src/hooks/use-authed-src.ts +0 -167
  687. package/src/hooks/use-body-scroll-lock.ts +0 -119
  688. package/src/hooks/use-breakpoint.ts +0 -133
  689. package/src/hooks/use-close-transition.ts +0 -107
  690. package/src/hooks/use-copy-to-clipboard.ts +0 -122
  691. package/src/hooks/use-debounce.ts +0 -114
  692. package/src/hooks/use-dismiss.ts +0 -371
  693. package/src/hooks/use-document-title.ts +0 -33
  694. package/src/hooks/use-file-drop.ts +0 -121
  695. package/src/hooks/use-file-picker-labels.ts +0 -28
  696. package/src/hooks/use-file-picker.tsx +0 -359
  697. package/src/hooks/use-focus-trap.ts +0 -199
  698. package/src/hooks/use-hotkey.ts +0 -189
  699. package/src/hooks/use-large-text.ts +0 -41
  700. package/src/hooks/use-long-press.ts +0 -140
  701. package/src/hooks/use-media-query.ts +0 -39
  702. package/src/hooks/use-mounted.ts +0 -39
  703. package/src/hooks/use-noindex.ts +0 -37
  704. package/src/hooks/use-overlay-history.ts +0 -714
  705. package/src/hooks/use-row-swipe.ts +0 -207
  706. package/src/hooks/use-search-param-state.ts +0 -434
  707. package/src/hooks/use-windowed-rows.ts +0 -225
  708. package/src/i18n/defaults.ts +0 -267
  709. package/src/i18n/german.ts +0 -2057
  710. package/src/i18n/kit-labels.tsx +0 -1003
  711. package/src/i18n/languages.ts +0 -349
  712. package/src/i18n/locales/de-CH.ts +0 -24
  713. package/src/i18n/locales/en.ts +0 -267
  714. package/src/i18n/locales/es.ts +0 -1997
  715. package/src/i18n/locales/fr.ts +0 -2035
  716. package/src/i18n/locales/hu.ts +0 -2002
  717. package/src/i18n/locales/it.ts +0 -2012
  718. package/src/i18n/locales/zh.ts +0 -1910
  719. package/src/i18n/plurals.ts +0 -86
  720. package/src/i18n/review.ts +0 -475
  721. package/src/i18n/shared-labels.ts +0 -138
  722. package/src/i18n/swiss.ts +0 -29
  723. package/src/index.ts +0 -1179
  724. package/src/landing/access.ts +0 -93
  725. package/src/landing/landing-actions.tsx +0 -97
  726. package/src/landing/landing-labels.ts +0 -59
  727. package/src/landing/landing-sections.tsx +0 -341
  728. package/src/landing/page-seo.ts +0 -261
  729. package/src/landing/public-header.tsx +0 -121
  730. package/src/landing/public-page.tsx +0 -106
  731. package/src/landing/routing.tsx +0 -225
  732. package/src/lib/broadcast.ts +0 -52
  733. package/src/lib/calc.ts +0 -323
  734. package/src/lib/chip-edge-snap.ts +0 -212
  735. package/src/lib/clipboard-minus.ts +0 -107
  736. package/src/lib/clipping.ts +0 -34
  737. package/src/lib/cn.ts +0 -28
  738. package/src/lib/column-mapping.ts +0 -234
  739. package/src/lib/countries.ts +0 -91
  740. package/src/lib/data-attributes.ts +0 -14
  741. package/src/lib/date-format.ts +0 -227
  742. package/src/lib/dates.ts +0 -266
  743. package/src/lib/day-format.ts +0 -96
  744. package/src/lib/decimal-marks.ts +0 -108
  745. package/src/lib/describe-failure.ts +0 -18
  746. package/src/lib/device-settings.ts +0 -147
  747. package/src/lib/direction.ts +0 -74
  748. package/src/lib/document-navigation.ts +0 -17
  749. package/src/lib/document-title.ts +0 -41
  750. package/src/lib/download.ts +0 -172
  751. package/src/lib/float-clearance.ts +0 -70
  752. package/src/lib/floating-stack.ts +0 -70
  753. package/src/lib/focus-left.ts +0 -156
  754. package/src/lib/format.ts +0 -522
  755. package/src/lib/http-status.ts +0 -38
  756. package/src/lib/iban.ts +0 -251
  757. package/src/lib/ime.ts +0 -24
  758. package/src/lib/intl-cache.ts +0 -25
  759. package/src/lib/iso-day.ts +0 -13
  760. package/src/lib/lazy-with-fallback.ts +0 -82
  761. package/src/lib/logger.ts +0 -69
  762. package/src/lib/minus.ts +0 -50
  763. package/src/lib/path-pattern.ts +0 -55
  764. package/src/lib/person-name.ts +0 -155
  765. package/src/lib/phone.ts +0 -208
  766. package/src/lib/plain-text.ts +0 -22
  767. package/src/lib/presence.ts +0 -18
  768. package/src/lib/qr-encode.ts +0 -444
  769. package/src/lib/quiet-focus.ts +0 -32
  770. package/src/lib/reduced-motion.ts +0 -22
  771. package/src/lib/refs.ts +0 -22
  772. package/src/lib/round.ts +0 -43
  773. package/src/lib/safe-storage.ts +0 -119
  774. package/src/lib/server-wake.ts +0 -315
  775. package/src/lib/session-refresh.ts +0 -472
  776. package/src/lib/share-format.ts +0 -18
  777. package/src/lib/status-tone.ts +0 -43
  778. package/src/lib/strip-fade.ts +0 -287
  779. package/src/lib/table-text.ts +0 -554
  780. package/src/lib/text-case.ts +0 -19
  781. package/src/lib/text-match.ts +0 -169
  782. package/src/lib/thenable.ts +0 -19
  783. package/src/lib/translation-review.ts +0 -717
  784. package/src/notifications/device-zone-report.ts +0 -67
  785. package/src/notifications/feedback-notification-types-labels.ts +0 -33
  786. package/src/notifications/feedback-notification-types.ts +0 -71
  787. package/src/notifications/notification-bell.tsx +0 -119
  788. package/src/notifications/notification-inbox.tsx +0 -309
  789. package/src/notifications/notification-parts.tsx +0 -81
  790. package/src/notifications/notification-types-setting.tsx +0 -406
  791. package/src/notifications/notification-types.ts +0 -89
  792. package/src/notifications/notifications-labels.ts +0 -287
  793. package/src/notifications/push-device-setting.tsx +0 -230
  794. package/src/notifications/push-devices-setting.tsx +0 -374
  795. package/src/notifications/push-worker.ts +0 -168
  796. package/src/notifications/quiet-hours-setting.tsx +0 -238
  797. package/src/notifications/unsubscribe-panel.tsx +0 -200
  798. package/src/notifications/use-push-device.ts +0 -448
  799. package/src/offline/local-first.ts +0 -100
  800. package/src/offline/pwa-update-prompt-labels.ts +0 -9
  801. package/src/offline/pwa-update-prompt.tsx +0 -78
  802. package/src/offline/query-persistence.ts +0 -391
  803. package/src/offline/service-worker-updates.ts +0 -81
  804. package/src/offline/shared-computer-labels.ts +0 -8
  805. package/src/offline/shared-computer.tsx +0 -87
  806. package/src/offline/sign-out-pending-dialog-labels.ts +0 -21
  807. package/src/offline/sign-out-pending-dialog.tsx +0 -135
  808. package/src/offline.ts +0 -37
  809. package/src/push-worker.ts +0 -25
  810. package/src/rhf/fields.tsx +0 -2187
  811. package/src/rhf/form-core.tsx +0 -324
  812. package/src/rhf/form.tsx +0 -12
  813. package/src/rhf/line-items.tsx +0 -135
  814. package/src/rhf/use-rhf-wizard-step.ts +0 -104
  815. package/src/rhf.ts +0 -21
  816. package/src/search/command-palette-labels.ts +0 -16
  817. package/src/search/command-palette.tsx +0 -624
  818. package/src/search/global-search-labels.ts +0 -13
  819. package/src/search/global-search.tsx +0 -660
  820. package/src/search/search-index.ts +0 -283
  821. package/src/search/use-command-key.ts +0 -23
  822. package/src/search.ts +0 -14
  823. package/src/settings/device-reset-setting-labels.ts +0 -20
  824. package/src/settings/device-reset-setting.tsx +0 -116
  825. package/src/settings/settings-card-classes.ts +0 -11
  826. package/src/settings/settings-catalogue.ts +0 -150
  827. package/src/settings/settings-context.ts +0 -33
  828. package/src/settings/settings-heading.tsx +0 -67
  829. package/src/settings/settings-labels.ts +0 -87
  830. package/src/settings/settings-layout.tsx +0 -471
  831. package/src/settings/settings-section.tsx +0 -108
  832. package/src/settings/use-account-appearance.ts +0 -148
  833. package/src/settings/use-account-language.ts +0 -146
  834. package/src/settings/use-settings-focus.ts +0 -128
  835. package/src/settings/use-settings-route.ts +0 -258
  836. package/src/shell/account-menu-language.tsx +0 -130
  837. package/src/shell/account-menu-text-size.tsx +0 -80
  838. package/src/shell/admin-menu.tsx +0 -183
  839. package/src/shell/app-shell-labels.ts +0 -11
  840. package/src/shell/app-shell.tsx +0 -1560
  841. package/src/shell/auth-layout.tsx +0 -186
  842. package/src/shell/company-switcher-labels.ts +0 -13
  843. package/src/shell/company-switcher.tsx +0 -136
  844. package/src/shell/dev-menu.tsx +0 -257
  845. package/src/shell/fill-height.tsx +0 -45
  846. package/src/shell/language-code.ts +0 -5
  847. package/src/shell/option-switcher-menu.tsx +0 -84
  848. package/src/shell/sync-status-indicator.tsx +0 -303
  849. package/src/shell/top-bar-actions.tsx +0 -87
  850. package/src/shell/top-bar-brand.tsx +0 -78
  851. package/src/shell/top-bar-parts-labels.ts +0 -148
  852. package/src/shell/top-bar.tsx +0 -40
  853. package/src/shell/topbar-action-menu.tsx +0 -567
  854. package/src/shell/topbar-controls.tsx +0 -269
  855. package/src/shell/tour-menu.tsx +0 -187
  856. package/src/shell.ts +0 -108
  857. package/src/sync/db.ts +0 -129
  858. package/src/sync/engine.ts +0 -1011
  859. package/src/sync/hooks.ts +0 -98
  860. package/src/sync/testing.ts +0 -73
  861. package/src/sync/wire.ts +0 -61
  862. package/src/sync.ts +0 -37
  863. package/src/table-text.ts +0 -8
  864. package/src/testing/css-variables.generated.ts +0 -112
  865. package/src/testing/css-variables.ts +0 -189
  866. package/src/testing/index.ts +0 -29
  867. package/src/testing/react.ts +0 -58
  868. package/src/testing/tour.ts +0 -41
  869. package/src/testing/viewport.ts +0 -357
  870. package/src/theme/chart-palette.ts +0 -232
  871. package/src/theme/color.ts +0 -272
  872. package/src/theme/contrast-tokens.ts +0 -268
  873. package/src/theme/contrast.ts +0 -250
  874. package/src/theme/palette-derive.ts +0 -825
  875. package/src/theme/palette-presets.ts +0 -544
  876. package/src/theme/palette-store.ts +0 -108
  877. package/src/theme/text-size.ts +0 -289
  878. package/src/theme/theme-store.ts +0 -157
  879. package/src/tour/tour-catalogue-labels.ts +0 -75
  880. package/src/tour/tour-catalogue.tsx +0 -335
  881. package/src/tour/tour-dock.ts +0 -134
  882. package/src/tour/tour-engine.ts +0 -37
  883. package/src/tour/tour-gates.ts +0 -218
  884. package/src/tour/tour-guide-button.tsx +0 -64
  885. package/src/tour/tour-guide-labels.ts +0 -15
  886. package/src/tour/tour-info.ts +0 -144
  887. package/src/tour/tour-labels.ts +0 -23
  888. package/src/tour/tour-overlay.tsx +0 -1170
  889. package/src/tour/tour.tsx +0 -750
  890. package/src/tour/use-tour-progress.ts +0 -671
  891. package/src/tour/use-tour-url-sync.ts +0 -266
  892. package/src/tour.ts +0 -21
  893. package/src/vite-env.d.ts +0 -23
  894. package/src/wizard/stepper-nav.tsx +0 -360
  895. package/src/wizard/types.ts +0 -275
  896. package/src/wizard/use-wizard.ts +0 -560
  897. package/src/wizard/validation.ts +0 -39
  898. package/src/wizard/wizard-context.tsx +0 -74
  899. package/src/wizard/wizard-labels.ts +0 -29
  900. package/src/wizard/wizard-step.tsx +0 -76
  901. package/src/wizard/wizard-summary.tsx +0 -84
  902. package/src/wizard.ts +0 -15
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/chart-zoom-core.tsx"],"sourcesContent":["// Drag-to-zoom for cartesian charts — the HOC, the shared x window, and the arithmetic.\n// Lifted out of lenkbank, where every plot in the app is one `SeriesChart` and zoom is\n// therefore wired in exactly once.\n//\n// **Which axes a drag zooms is read off the drag itself.** A selection that is roughly\n// square is a box: the reader framed a REGION and means both axes. A long thin one is a\n// band, and its own direction says which: a wide flat drag means \"this stretch of the\n// abscissa\", a tall narrow one \"this range of values\". Asking with a modifier key\n// instead would be asking people to remember a convention for something they have\n// already drawn.\n//\n// Squareness is measured **in fractions of the plot**, not pixels. These charts are\n// three times wider than they are tall, so a pixel-square selection is a very wide\n// slice of the data and would read as a band to anybody looking at it.\n//\n// The zoom is VIEW state and lives here, never in a query or a store: it is where\n// somebody is looking, and a chart whose data reloads should not lose it. It is cleared\n// by the reset button, by a double click, and by nothing else.\n//\n// Everything with a decision in it is a pure exported function below (`zoomAxesFor`,\n// `selectionFromDrag`, `zoomAfter`, `zoomDomains`, `fitYToX`, `fitXToY`); the\n// components are plumbing between a pointer and those.\n//\n// The kit's own module (0.34, refactor audit 2026-10, API-6b): SeriesChart, its axes and\n// the facing pair import from here. ./chart-zoom is the public face — `SharedXZoom`, the\n// types, and until 0.35 the deprecated arithmetic and HOC, which no app imports.\nimport { createContext, useContext, useEffect, useRef, useState } from \"react\";\nimport type { ComponentType, Dispatch, ReactNode, SetStateAction } from \"react\";\nimport { usePlotArea, useXAxisInverseScale, useYAxisInverseScale, type InverseScaleFunction } from \"recharts\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { FOCUS_RING } from \"./focus-ring\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { DEFAULT_SERIES_CHART_LABELS, type SeriesChartLabels } from \"./series-chart-labels\";\n\n/** The y axis a series lands on when it names none — the single shared scale most\n * charts have. `SeriesChart` and the fit below agree on it by importing this. */\nexport const DEFAULT_Y_AXIS = \"y\";\n\n/* ── The arithmetic ─────────────────────────────────────────────────────── */\n\n/**\n * How square a selection has to be before it counts as a box: the shorter side\n * against the longer, both as fractions of the plot. At 0.5 a selection twice as wide\n * as it is tall is still a box and one three times as wide is a band.\n */\nexport const ZOOM_SQUARE_ENOUGH = 0.5;\n\n/** Below this a drag is a click that moved, not a selection. In fractions of the plot,\n * so it is the same gesture on a phone and on a wall display. */\nexport const ZOOM_MIN_DRAG = 0.02;\n\nexport type ZoomAxes = \"both\" | \"x\" | \"y\";\n\n/** Which axes a drag zooms — or `null` for a drag too small to mean one, or a plot\n * that has not been laid out yet. Direction does not matter; proportion does. */\nexport function zoomAxesFor(\n dx: number,\n dy: number,\n width: number,\n height: number,\n threshold: number = ZOOM_SQUARE_ENOUGH,\n /** A chart that zooms ONE axis only (see {@link ZoomTarget.zoomAxes}): every drag is\n * a band along it, however it was drawn, and a drag with no extent along it is\n * nothing — a tall narrow drag over a bar chart names no stretch of the abscissa. */\n only?: \"x\" | \"y\",\n): ZoomAxes | null {\n if (!(width > 0) || !(height > 0)) return null;\n const across = Math.abs(dx) / width;\n const down = Math.abs(dy) / height;\n if (only === \"x\") return across < ZOOM_MIN_DRAG ? null : \"x\";\n if (only === \"y\") return down < ZOOM_MIN_DRAG ? null : \"y\";\n if (across < ZOOM_MIN_DRAG && down < ZOOM_MIN_DRAG) return null;\n const longer = Math.max(across, down);\n const shorter = Math.min(across, down);\n if (shorter / longer >= threshold) return \"both\";\n return across > down ? \"x\" : \"y\";\n}\n\n/** What a drag chose, in DATA coordinates, and which axes it actually named — the\n * caller needs the second to know which of the two it may derive from the other. */\nexport interface ZoomSelection {\n which: ZoomAxes;\n x?: [number, number];\n /** One window per y axis, keyed by axis id: they are in different units. */\n y: Record<string, [number, number]>;\n}\n\n/** A drag, in the chart's own pixel coordinates. */\nexport interface ZoomDrag {\n fromX: number;\n fromY: number;\n toX: number;\n toY: number;\n}\n\n/** A pair as a domain, smallest first. Recharts wants an ascending domain whichever\n * way the drag went, and a y axis counts downward in pixels while its values count\n * upward — so both ends are read and sorted rather than one assumed to be low. */\nfunction ordered(a: number, b: number): [number, number] {\n return a <= b ? [a, b] : [b, a];\n}\n\n/**\n * A finished drag as a selection, or `null` when it selects nothing.\n *\n * `xInverse` and `yInverse(axisId)` are recharts' pixel→value functions; an axis whose\n * function is missing, or whose ends come back non-finite, is left out rather than\n * handed a NaN window.\n */\nexport function selectionFromDrag(\n drag: ZoomDrag,\n plot: { width: number; height: number },\n xInverse: InverseScaleFunction | undefined,\n yInverse: (axisId: string) => InverseScaleFunction | undefined,\n axisIds: readonly string[],\n only?: \"x\" | \"y\",\n): ZoomSelection | null {\n const which = zoomAxesFor(\n drag.toX - drag.fromX,\n drag.toY - drag.fromY,\n plot.width,\n plot.height,\n ZOOM_SQUARE_ENOUGH,\n only,\n );\n if (!which) return null;\n const next: ZoomSelection = { which, y: {} };\n if (which !== \"y\" && xInverse) {\n const from = Number(xInverse(drag.fromX));\n const to = Number(xInverse(drag.toX));\n if (Number.isFinite(from) && Number.isFinite(to)) next.x = ordered(from, to);\n }\n if (which !== \"x\") {\n for (const id of axisIds) {\n const inverse = yInverse(id);\n if (!inverse) continue;\n const from = Number(inverse(drag.fromY));\n const to = Number(inverse(drag.toY));\n if (Number.isFinite(from) && Number.isFinite(to)) next.y[id] = ordered(from, to);\n }\n }\n return next.x || Object.keys(next.y).length ? next : null;\n}\n\n/** One row of a zoomable chart. Loose on purpose: a row also carries what the chart\n * does not plot — keksdose's `rawPeriod` for a drilldown, a label for a category axis —\n * and only the finite NUMBERS in it are ever read as samples. */\nexport type ZoomRow = Readonly<Record<string, unknown>>;\n\n/** A series as the fit sees it. `stack` groups bars/areas drawn on top of each other\n * (recharts' `stackId`), whose extent is their SUM, not any one of them. */\nexport interface ZoomFitSeries {\n key: string;\n axis?: string;\n stack?: string;\n /** Only `\"line\"` matters here: recharts cannot stack a line, so a line's `stack` is\n * ignored rather than summed into a height nothing on the chart reaches. */\n type?: string;\n}\n\n/** What a band refit needs to know about the chart — a subset of `SeriesChart`'s own\n * props, so a chart hands its data straight over. */\nexport interface ZoomFitSource {\n rows: readonly ZoomRow[];\n series: readonly ZoomFitSeries[];\n axes: readonly { id: string }[];\n xKey: string;\n}\n\n/** How much of a refitted span to leave as air, top and bottom. Without it the\n * highest sample sits exactly on the frame, where a line is half drawn and reads as\n * clipped rather than as the maximum. */\nconst FIT_AIR = 0.05;\n\n/** A span with air around it — and a real span for a flat channel, which would\n * otherwise be a zero-height window recharts cannot scale. */\nfunction airy(low: number, high: number): [number, number] {\n const span = high - low;\n const air = span > 0 ? span * FIT_AIR : Math.max(Math.abs(high), 1) * FIT_AIR;\n return [low - air, high + air];\n}\n\n/** A running low/high pair. A pair rather than an array to take `Math.min(...)` of:\n * the spread passes one argument per sample, and V8 faults past ~125,000 of them. */\ntype Span = [number, number] | undefined;\n\n/** A pair widened by one value. A non-finite one is not a value — one NaN would\n * otherwise take the whole window with it. */\nfunction widen(span: Span, value: unknown): Span {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return span;\n if (!span) return [value, value];\n if (value < span[0]) span[0] = value;\n else if (value > span[1]) span[1] = value;\n return span;\n}\n\n/** Which series are measured on an axis. */\nfunction keysOn(source: ZoomFitSource, axisId: string): string[] {\n return source.series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axisId).map((entry) => entry.key);\n}\n\n/** A row's value as a sample, or 0 for a stack's missing layer — a stacked bar with no\n * value for one series draws the rest of the stack from where that one would end. */\nconst layer = (value: unknown) => (typeof value === \"number\" && Number.isFinite(value) ? value : 0);\n\n/**\n * The lowest and highest value an axis DRAWS over the rows whose abscissa is inside\n * `window` (every row when there is none) — `undefined` when it draws nothing finite.\n *\n * Stack-aware, and that is why it exists: a stack of three bars reaches the SUM of\n * them, and fitting the axis to the tallest single layer (what fitting on values did)\n * cuts the top two thirds of every stack off. Positive and negative layers are summed\n * apart, as recharts draws them under `stackOffset=\"sign\"` — a month with 900 income\n * and −300 expense stacks up to 900 and down to −300, not to 600. A stacked extent\n * therefore always contains the zero its layers stand on.\n *\n * `SeriesChart` fits its axes with this and the zoom refits them with it, so the two\n * cannot disagree about how tall a stack is.\n */\nexport function axisExtent(\n source: ZoomFitSource,\n axisId: string,\n window?: readonly [number, number],\n): [number, number] | undefined {\n const mine = source.series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axisId);\n const loose: string[] = [];\n const stacks = new Map<string, string[]>();\n for (const entry of mine) {\n if (entry.stack === undefined || entry.type === \"line\" || entry.type === undefined) {\n loose.push(entry.key);\n } else {\n stacks.set(entry.stack, [...(stacks.get(entry.stack) ?? []), entry.key]);\n }\n }\n let span: Span;\n for (const row of source.rows) {\n if (window) {\n const at = row[source.xKey];\n if (typeof at !== \"number\" || !(at >= window[0] && at <= window[1])) continue;\n }\n for (const key of loose) span = widen(span, row[key]);\n for (const keys of stacks.values()) {\n let up = 0;\n let down = 0;\n let any = false;\n for (const key of keys) {\n const value = layer(row[key]);\n any ||= typeof row[key] === \"number\" && Number.isFinite(row[key]);\n if (value >= 0) up += value;\n else down += value;\n }\n if (!any) continue;\n span = widen(widen(span, down), up);\n }\n }\n return span;\n}\n\n/**\n * Each y axis fitted to the samples inside an x window — what a band across x leaves\n * the axes nobody dragged showing. Zoom into a tenth of a sweep and a y axis still\n * scaled to the whole run draws that tenth as a flat line, which is the one thing the\n * zoom was for; so the unnamed axes are refitted, which is what \"zoom\" means everywhere\n * else.\n *\n * An axis with nothing inside the window is left OUT rather than collapsed: a window\n * between two samples is one where the chart should keep drawing the line across.\n */\nexport function fitYToX(source: ZoomFitSource, window: readonly [number, number]): Record<string, [number, number]> {\n const fitted: Record<string, [number, number]> = {};\n for (const axis of source.axes) {\n const span = axisExtent(source, axis.id, window);\n if (span) fitted[axis.id] = airy(span[0], span[1]);\n }\n return fitted;\n}\n\n/**\n * The x window that holds every sample inside a set of y windows — the other direction\n * of the same idea. A channel crossing its band once gives a tight window; one that\n * oscillates through it gives back most of the sweep, which is the truthful answer.\n * `undefined` when no sample qualifies, rather than a guess.\n */\nexport function fitXToY(\n source: ZoomFitSource,\n windows: Readonly<Record<string, readonly [number, number]>>,\n): [number, number] | undefined {\n let hits: Span;\n for (const [axisId, [low, high]] of Object.entries(windows)) {\n for (const key of keysOn(source, axisId)) {\n for (const row of source.rows) {\n const value = row[key];\n if (typeof value === \"number\" && Number.isFinite(value) && value >= low && value <= high) {\n hits = widen(hits, row[source.xKey]);\n }\n }\n }\n }\n return hits ? airy(hits[0], hits[1]) : undefined;\n}\n\n/**\n * What a chart remembers about its zoom: the x window, and the y windows the reader\n * DRAGGED. `y: null` means \"derive y from x\" — the split is the whole design: what was\n * dragged is kept, and what follows from it is recomputed on every render, so a band\n * across x refits y here and in every chart sharing the window.\n */\nexport interface ZoomState {\n x?: [number, number];\n y: Record<string, [number, number]> | null;\n}\n\nexport const NO_ZOOM: ZoomState = { x: undefined, y: null };\n\n/**\n * The state after a selection. Two band drags COMPOSE rather than the second undoing\n * the first: a band down y keeps the x window when the band holds no samples, and\n * otherwise pulls x in to where they are.\n */\nexport function zoomAfter(state: ZoomState, selection: ZoomSelection, source: ZoomFitSource): ZoomState {\n if (selection.which === \"both\") return { x: selection.x, y: selection.y };\n // Leave y derived, so it fits itself to what is inside the new window.\n if (selection.which === \"x\") return { x: selection.x, y: null };\n return { x: fitXToY(source, selection.y) ?? state.x, y: selection.y };\n}\n\n/** The domains a chart draws for a state: the x window as is, and each y axis either\n * as dragged or fitted to the x window. `{}` means \"fit your own data\". */\nexport function zoomDomains(\n state: ZoomState,\n source: ZoomFitSource,\n): { xDomain?: [number, number]; yDomains: Record<string, [number, number]> } {\n return {\n xDomain: state.x,\n yDomains: state.y ?? (state.x ? fitYToX(source, state.x) : {}),\n };\n}\n\n/* ── The components ─────────────────────────────────────────────────────── */\n\n/** What the wrapped chart is handed. It applies the domains to its own axes and renders\n * `layer` INSIDE the recharts chart, where recharts' hooks answer. */\nexport interface ZoomBinding {\n xDomain?: [number, number];\n yDomains: Record<string, [number, number]>;\n layer: ReactNode;\n}\n\n/**\n * Which axes a chart lets a drag zoom. `\"none\"` draws no drag layer and no reset.\n * A drag on a one-axis chart is always a band along that axis (see {@link zoomAxesFor}).\n */\nexport type ZoomAxesSetting = ZoomAxes | \"none\";\n\n/**\n * The zoom a chart gets when it does not say, read off what its series ARE.\n *\n * - Only lines: `\"both\"` — lenkbank's measurement plots, unchanged.\n * - Any area: `\"x\"`. An area's height is a length from zero, and a y window that cuts\n * the baseline off draws a band of 40 as three times one of 20 — so its y axis refits\n * to the x window (still from zero), and a drag never names a y range.\n * - Any bar: `\"none\"`. A bar chart is a handful of periods read one bar at a time, and\n * in keksdose every one of them is CLICKED — to drill into a payee, a month, a budget\n * line — which a drag layer over the plot would swallow. A chart of many bars opts\n * back in with `zoomAxes: \"x\"`; a click then reports the period, not the bar.\n */\nexport function defaultZoomAxes(series: readonly { type?: string }[] | undefined): ZoomAxesSetting {\n if (series?.some((entry) => entry.type === \"bar\")) return \"none\";\n if (series?.some((entry) => entry.type === \"area\")) return \"x\";\n return \"both\";\n}\n\n/** The props `withChartZoom` reads off the chart it wraps. */\nexport interface ZoomTarget {\n /** Default: the single axis {@link DEFAULT_Y_AXIS}. */\n axes?: readonly { id: string; hide?: boolean }[];\n /** The chart's own data, so a band can refit the axis it did not name. Optional: a\n * chart with nothing plotted has nothing to fit to. */\n rows?: readonly ZoomRow[];\n series?: readonly ZoomFitSeries[];\n x?: { key?: string };\n zoom?: ZoomBinding;\n labels?: LabelOverride<SeriesChartLabels>;\n /** Which axes a drag may zoom. Default: {@link defaultZoomAxes} of `series`. */\n zoomAxes?: ZoomAxesSetting;\n}\n\nconst SharedX = createContext<{\n window?: [number, number];\n set: Dispatch<SetStateAction<[number, number] | undefined>>;\n} | null>(null);\n\n/**\n * One x window for several charts.\n *\n * A column of charts over one abscissa is one picture, and zooming one of them and not\n * the rest turns it into several pictures of different things. Every zoomable chart\n * inside this shares the x window: any drag in any of them moves all of them.\n *\n * **Only x.** The y axes stay each chart's own — they are in different units — and\n * each refits its own y to what is inside the shared window.\n */\nexport function SharedXZoom({ children }: { children: ReactNode }) {\n const [window, set] = useState<[number, number] | undefined>(undefined);\n return <SharedX.Provider value={{ window, set }}>{children}</SharedX.Provider>;\n}\n\n/**\n * Wrap a chart in drag-to-zoom.\n *\n * The chart receives a `zoom` binding: it applies `xDomain`/`yDomains` to its axes\n * (with `allowDataOverflow`, so recharts clips to the window instead of widening it\n * back out) and renders `layer` as a child of its recharts chart. A reset button\n * appears over the chart's top end corner while it is zoomed — a real button, so the\n * keyboard can undo what the pointer did.\n */\nexport function withChartZoom<P extends ZoomTarget>(Chart: ComponentType<P>) {\n function Zoomable(props: P) {\n const labels = useKitLabels(\"seriesChart\", DEFAULT_SERIES_CHART_LABELS, props.labels);\n const group = useContext(SharedX);\n const [ownX, setOwnX] = useState<[number, number] | undefined>(undefined);\n const [ownY, setOwnY] = useState<Record<string, [number, number]> | null>(null);\n const xWindow = group ? group.window : ownX;\n const setXWindow = group ? group.set : setOwnX;\n const axes = props.axes ?? [{ id: DEFAULT_Y_AXIS }];\n const setting = props.zoomAxes ?? defaultZoomAxes(props.series);\n const only = setting === \"x\" || setting === \"y\" ? setting : undefined;\n\n // Every axis, hidden ones included: a hidden axis still scales its lines, and a\n // line whose axis did not refit is drawn as a flat streak inside the window.\n const source: ZoomFitSource = {\n rows: props.rows ?? [],\n series: [...(props.series ?? [])],\n axes: [...axes],\n xKey: props.x?.key ?? \"x\",\n };\n const state: ZoomState = { x: xWindow, y: ownY };\n const zoomed = xWindow !== undefined || ownY !== null;\n // A chart handed no rows or no series draws its empty state, not a plot — and a\n // \"Reset zoom\" floating over \"No data\" (every line toggled off while zoomed) offers\n // to undo something the reader cannot see. The zoom itself is KEPT: it is where they\n // were looking, and it applies again the moment a line comes back. Only an array\n // that is there and empty counts; a chart that does not pass its data is not known\n // to be empty.\n const empty = props.rows?.length === 0 || props.series?.length === 0;\n\n const clear = () => {\n setXWindow(undefined);\n setOwnY(null);\n };\n\n // Switched off, the chart still gets a binding — with no window and no layer — so a\n // chart whose series change type mid-life is not remounted by a different tree.\n if (setting === \"none\") {\n return (\n <div className=\"relative\">\n <Chart {...props} zoom={{ yDomains: {}, layer: null }} />\n </div>\n );\n }\n\n const binding: ZoomBinding = {\n ...zoomDomains(state, source),\n layer: (\n <ZoomLayer\n axisIds={axes.map((axis) => axis.id)}\n only={only}\n onZoom={(selection) => {\n const next = zoomAfter(state, selection, source);\n if (next.x !== xWindow) setXWindow(next.x);\n setOwnY(next.y);\n }}\n onReset={clear}\n />\n ),\n };\n\n return (\n <div className=\"relative\">\n <Chart {...props} zoom={binding} />\n {zoomed && !empty && (\n <button\n type=\"button\"\n onClick={clear}\n className={cn(\n \"absolute end-1 top-1 z-10 inline-flex items-center gap-1 rounded border border-subtle bg-surface/90 px-1.5 py-0.5 text-micro text-muted backdrop-blur transition-colors hover:text-primary\",\n FOCUS_RING,\n )}\n >\n <X aria-hidden className=\"size-3\" /> {labels.resetZoom}\n </button>\n )}\n </div>\n );\n }\n Zoomable.displayName = `withChartZoom(${Chart.displayName ?? Chart.name ?? \"Chart\"})`;\n return Zoomable;\n}\n\n/**\n * The part that lives INSIDE the recharts chart, where recharts will say where the plot\n * is and what value a pixel is.\n *\n * A transparent rectangle over the plot area that reads the drag. It does NOT stop the\n * event: recharts drives its tooltip from the same pointer move bubbling up to its own\n * wrapper, so swallowing it here would trade the tooltip for the zoom.\n *\n * Nothing to assistive technology (0.52, refactor audit 2026-10-30, DSP-5): it was a\n * `role=\"application\"` named by the drag hint, which could not take focus — the one name\n * on an otherwise unnamed chart. The hint is in the chart's description now\n * (`SeriesChart`'s figure), and `data-zoom-surface` is how a test finds the rect.\n */\nfunction ZoomLayer({\n axisIds,\n only,\n onZoom,\n onReset,\n}: {\n axisIds: string[];\n only?: \"x\" | \"y\";\n onZoom: (selection: ZoomSelection) => void;\n onReset: () => void;\n}) {\n const plot = usePlotArea();\n const xInverse = useXAxisInverseScale();\n // One probe COMPONENT per axis rather than a hook in a loop: the number of axes\n // changes as series are toggled, and a hook count that changes with the data is the\n // one thing React will not forgive.\n const [scales] = useState(() => new Map<string, InverseScaleFunction | undefined>());\n const [drag, setDrag] = useState<ZoomDrag | null>(null);\n // A finished drag is followed by a click on the same element, and a chart with an\n // `onClick` (keksdose opens a drilldown on one) would read the zoom as a pick.\n const draggedRef = useRef(false);\n\n if (!plot || plot.width <= 0 || plot.height <= 0) return null;\n\n const at = (event: { clientX: number; clientY: number; currentTarget: Element }) => {\n // Against the overlay's own screen box, so padding around the container cannot\n // shift every reading — plus the plot's offset, because the scales are in the\n // chart's coordinates rather than the plot's.\n const box = event.currentTarget.getBoundingClientRect();\n return { x: event.clientX - box.left + plot.x, y: event.clientY - box.top + plot.y };\n };\n\n const finish = () => {\n if (!drag) return;\n setDrag(null);\n const selection = selectionFromDrag(drag, plot, xInverse, (id) => scales.get(id), axisIds, only);\n draggedRef.current = selection !== null;\n if (selection) onZoom(selection);\n };\n\n // What the drag would do, shown while it is being made: a band paints the full width\n // or height, so the reader sees it is about to let the other axis refit.\n const which = drag\n ? zoomAxesFor(drag.toX - drag.fromX, drag.toY - drag.fromY, plot.width, plot.height, ZOOM_SQUARE_ENOUGH, only)\n : null;\n\n return (\n <g>\n {axisIds.map((id) => (\n <AxisProbe key={id} axisId={id} scales={scales} />\n ))}\n {drag && which && (\n <rect\n x={which === \"y\" ? plot.x : Math.min(drag.fromX, drag.toX)}\n y={which === \"x\" ? plot.y : Math.min(drag.fromY, drag.toY)}\n width={which === \"y\" ? plot.width : Math.abs(drag.toX - drag.fromX)}\n height={which === \"x\" ? plot.height : Math.abs(drag.toY - drag.fromY)}\n className=\"fill-[var(--brand)]/15 stroke-[var(--brand)]\"\n strokeDasharray=\"4 3\"\n pointerEvents=\"none\"\n />\n )}\n <rect\n x={plot.x}\n y={plot.y}\n width={plot.width}\n height={plot.height}\n // `transparent`, not `none`: an unpainted shape takes no pointer events.\n fill=\"transparent\"\n data-zoom-surface=\"\"\n style={{ cursor: \"crosshair\" }}\n onPointerDown={(event) => {\n if (event.button !== 0) return;\n draggedRef.current = false;\n const point = at(event);\n // Best effort: capture keeps a drag alive past the plot's edge, but a\n // pointer id the environment does not know throws — jsdom refuses them all —\n // and a zoom that threw on pointer-down would be a chart nobody could click.\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n /* the drag still works; it just stops at the edge of the plot */\n }\n setDrag({ fromX: point.x, fromY: point.y, toX: point.x, toY: point.y });\n }}\n onPointerMove={(event) => {\n if (!drag) return;\n const point = at(event);\n setDrag({ ...drag, toX: point.x, toY: point.y });\n }}\n onPointerUp={finish}\n onPointerCancel={() => setDrag(null)}\n onClick={(event) => {\n if (!draggedRef.current) return;\n draggedRef.current = false;\n event.stopPropagation();\n }}\n onDoubleClick={onReset}\n />\n </g>\n );\n}\n\n/** One axis's pixel→value function, parked where the pointer handler can reach it. */\nfunction AxisProbe({ axisId, scales }: { axisId: string; scales: Map<string, InverseScaleFunction | undefined> }) {\n const inverse = useYAxisInverseScale(axisId);\n useEffect(() => {\n scales.set(axisId, inverse);\n return () => {\n scales.delete(axisId);\n };\n }, [axisId, inverse, scales]);\n return null;\n}\n"],"mappings":";AAqZS,cA6EC,YA7ED;AA3XT,SAAS,eAAe,YAAY,WAAW,QAAQ,gBAAgB;AAEvE,SAAS,aAAa,sBAAsB,4BAAuD;AACnG,SAAS,SAAS;AAClB,SAAS,UAAU;AACnB,SAAS,kBAAkB;AAC3B,SAAS,oBAAwC;AACjD,SAAS,mCAA2D;AAI7D,MAAM,iBAAiB;AASvB,MAAM,qBAAqB;AAI3B,MAAM,gBAAgB;AAMtB,SAAS,YACd,IACA,IACA,OACA,QACA,YAAoB,oBAIpB,MACiB;AACjB,MAAI,EAAE,QAAQ,MAAM,EAAE,SAAS,GAAI,QAAO;AAC1C,QAAM,SAAS,KAAK,IAAI,EAAE,IAAI;AAC9B,QAAM,OAAO,KAAK,IAAI,EAAE,IAAI;AAC5B,MAAI,SAAS,IAAK,QAAO,SAAS,gBAAgB,OAAO;AACzD,MAAI,SAAS,IAAK,QAAO,OAAO,gBAAgB,OAAO;AACvD,MAAI,SAAS,iBAAiB,OAAO,cAAe,QAAO;AAC3D,QAAM,SAAS,KAAK,IAAI,QAAQ,IAAI;AACpC,QAAM,UAAU,KAAK,IAAI,QAAQ,IAAI;AACrC,MAAI,UAAU,UAAU,UAAW,QAAO;AAC1C,SAAO,SAAS,OAAO,MAAM;AAC/B;AAsBA,SAAS,QAAQ,GAAW,GAA6B;AACvD,SAAO,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAChC;AASO,SAAS,kBACd,MACA,MACA,UACA,UACA,SACA,MACsB;AACtB,QAAM,QAAQ;AAAA,IACZ,KAAK,MAAM,KAAK;AAAA,IAChB,KAAK,MAAM,KAAK;AAAA,IAChB,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAsB,EAAE,OAAO,GAAG,CAAC,EAAE;AAC3C,MAAI,UAAU,OAAO,UAAU;AAC7B,UAAM,OAAO,OAAO,SAAS,KAAK,KAAK,CAAC;AACxC,UAAM,KAAK,OAAO,SAAS,KAAK,GAAG,CAAC;AACpC,QAAI,OAAO,SAAS,IAAI,KAAK,OAAO,SAAS,EAAE,EAAG,MAAK,IAAI,QAAQ,MAAM,EAAE;AAAA,EAC7E;AACA,MAAI,UAAU,KAAK;AACjB,eAAW,MAAM,SAAS;AACxB,YAAM,UAAU,SAAS,EAAE;AAC3B,UAAI,CAAC,QAAS;AACd,YAAM,OAAO,OAAO,QAAQ,KAAK,KAAK,CAAC;AACvC,YAAM,KAAK,OAAO,QAAQ,KAAK,GAAG,CAAC;AACnC,UAAI,OAAO,SAAS,IAAI,KAAK,OAAO,SAAS,EAAE,EAAG,MAAK,EAAE,EAAE,IAAI,QAAQ,MAAM,EAAE;AAAA,IACjF;AAAA,EACF;AACA,SAAO,KAAK,KAAK,OAAO,KAAK,KAAK,CAAC,EAAE,SAAS,OAAO;AACvD;AA8BA,MAAM,UAAU;AAIhB,SAAS,KAAK,KAAa,MAAgC;AACzD,QAAM,OAAO,OAAO;AACpB,QAAM,MAAM,OAAO,IAAI,OAAO,UAAU,KAAK,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI;AACtE,SAAO,CAAC,MAAM,KAAK,OAAO,GAAG;AAC/B;AAQA,SAAS,MAAM,MAAY,OAAsB;AAC/C,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,MAAI,CAAC,KAAM,QAAO,CAAC,OAAO,KAAK;AAC/B,MAAI,QAAQ,KAAK,CAAC,EAAG,MAAK,CAAC,IAAI;AAAA,WACtB,QAAQ,KAAK,CAAC,EAAG,MAAK,CAAC,IAAI;AACpC,SAAO;AACT;AAGA,SAAS,OAAO,QAAuB,QAA0B;AAC/D,SAAO,OAAO,OAAO,OAAO,CAAC,WAAW,MAAM,QAAQ,oBAAoB,MAAM,EAAE,IAAI,CAAC,UAAU,MAAM,GAAG;AAC5G;AAIA,MAAM,QAAQ,CAAC,UAAoB,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AAgB1F,SAAS,WACd,QACA,QACA,QAC8B;AAC9B,QAAM,OAAO,OAAO,OAAO,OAAO,CAAC,WAAW,MAAM,QAAQ,oBAAoB,MAAM;AACtF,QAAM,QAAkB,CAAC;AACzB,QAAM,SAAS,oBAAI,IAAsB;AACzC,aAAW,SAAS,MAAM;AACxB,QAAI,MAAM,UAAU,UAAa,MAAM,SAAS,UAAU,MAAM,SAAS,QAAW;AAClF,YAAM,KAAK,MAAM,GAAG;AAAA,IACtB,OAAO;AACL,aAAO,IAAI,MAAM,OAAO,CAAC,GAAI,OAAO,IAAI,MAAM,KAAK,KAAK,CAAC,GAAI,MAAM,GAAG,CAAC;AAAA,IACzE;AAAA,EACF;AACA,MAAI;AACJ,aAAW,OAAO,OAAO,MAAM;AAC7B,QAAI,QAAQ;AACV,YAAM,KAAK,IAAI,OAAO,IAAI;AAC1B,UAAI,OAAO,OAAO,YAAY,EAAE,MAAM,OAAO,CAAC,KAAK,MAAM,OAAO,CAAC,GAAI;AAAA,IACvE;AACA,eAAW,OAAO,MAAO,QAAO,MAAM,MAAM,IAAI,GAAG,CAAC;AACpD,eAAW,QAAQ,OAAO,OAAO,GAAG;AAClC,UAAI,KAAK;AACT,UAAI,OAAO;AACX,UAAI,MAAM;AACV,iBAAW,OAAO,MAAM;AACtB,cAAM,QAAQ,MAAM,IAAI,GAAG,CAAC;AAC5B,gBAAQ,OAAO,IAAI,GAAG,MAAM,YAAY,OAAO,SAAS,IAAI,GAAG,CAAC;AAChE,YAAI,SAAS,EAAG,OAAM;AAAA,YACjB,SAAQ;AAAA,MACf;AACA,UAAI,CAAC,IAAK;AACV,aAAO,MAAM,MAAM,MAAM,IAAI,GAAG,EAAE;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAYO,SAAS,QAAQ,QAAuB,QAAqE;AAClH,QAAM,SAA2C,CAAC;AAClD,aAAW,QAAQ,OAAO,MAAM;AAC9B,UAAM,OAAO,WAAW,QAAQ,KAAK,IAAI,MAAM;AAC/C,QAAI,KAAM,QAAO,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,EACnD;AACA,SAAO;AACT;AAQO,SAAS,QACd,QACA,SAC8B;AAC9B,MAAI;AACJ,aAAW,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC3D,eAAW,OAAO,OAAO,QAAQ,MAAM,GAAG;AACxC,iBAAW,OAAO,OAAO,MAAM;AAC7B,cAAM,QAAQ,IAAI,GAAG;AACrB,YAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS,OAAO,SAAS,MAAM;AACxF,iBAAO,MAAM,MAAM,IAAI,OAAO,IAAI,CAAC;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI;AACzC;AAaO,MAAM,UAAqB,EAAE,GAAG,QAAW,GAAG,KAAK;AAOnD,SAAS,UAAU,OAAkB,WAA0B,QAAkC;AACtG,MAAI,UAAU,UAAU,OAAQ,QAAO,EAAE,GAAG,UAAU,GAAG,GAAG,UAAU,EAAE;AAExE,MAAI,UAAU,UAAU,IAAK,QAAO,EAAE,GAAG,UAAU,GAAG,GAAG,KAAK;AAC9D,SAAO,EAAE,GAAG,QAAQ,QAAQ,UAAU,CAAC,KAAK,MAAM,GAAG,GAAG,UAAU,EAAE;AACtE;AAIO,SAAS,YACd,OACA,QAC4E;AAC5E,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,UAAU,MAAM,MAAM,MAAM,IAAI,QAAQ,QAAQ,MAAM,CAAC,IAAI,CAAC;AAAA,EAC9D;AACF;AA8BO,SAAS,gBAAgB,QAAmE;AACjG,MAAI,QAAQ,KAAK,CAAC,UAAU,MAAM,SAAS,KAAK,EAAG,QAAO;AAC1D,MAAI,QAAQ,KAAK,CAAC,UAAU,MAAM,SAAS,MAAM,EAAG,QAAO;AAC3D,SAAO;AACT;AAiBA,MAAM,UAAU,cAGN,IAAI;AAYP,SAAS,YAAY,EAAE,SAAS,GAA4B;AACjE,QAAM,CAAC,QAAQ,GAAG,IAAI,SAAuC,MAAS;AACtE,SAAO,oBAAC,QAAQ,UAAR,EAAiB,OAAO,EAAE,QAAQ,IAAI,GAAI,UAAS;AAC7D;AAWO,SAAS,cAAoC,OAAyB;AAC3E,WAAS,SAAS,OAAU;AAC1B,UAAM,SAAS,aAAa,eAAe,6BAA6B,MAAM,MAAM;AACpF,UAAM,QAAQ,WAAW,OAAO;AAChC,UAAM,CAAC,MAAM,OAAO,IAAI,SAAuC,MAAS;AACxE,UAAM,CAAC,MAAM,OAAO,IAAI,SAAkD,IAAI;AAC9E,UAAM,UAAU,QAAQ,MAAM,SAAS;AACvC,UAAM,aAAa,QAAQ,MAAM,MAAM;AACvC,UAAM,OAAO,MAAM,QAAQ,CAAC,EAAE,IAAI,eAAe,CAAC;AAClD,UAAM,UAAU,MAAM,YAAY,gBAAgB,MAAM,MAAM;AAC9D,UAAM,OAAO,YAAY,OAAO,YAAY,MAAM,UAAU;AAI5D,UAAM,SAAwB;AAAA,MAC5B,MAAM,MAAM,QAAQ,CAAC;AAAA,MACrB,QAAQ,CAAC,GAAI,MAAM,UAAU,CAAC,CAAE;AAAA,MAChC,MAAM,CAAC,GAAG,IAAI;AAAA,MACd,MAAM,MAAM,GAAG,OAAO;AAAA,IACxB;AACA,UAAM,QAAmB,EAAE,GAAG,SAAS,GAAG,KAAK;AAC/C,UAAM,SAAS,YAAY,UAAa,SAAS;AAOjD,UAAM,QAAQ,MAAM,MAAM,WAAW,KAAK,MAAM,QAAQ,WAAW;AAEnE,UAAM,QAAQ,MAAM;AAClB,iBAAW,MAAS;AACpB,cAAQ,IAAI;AAAA,IACd;AAIA,QAAI,YAAY,QAAQ;AACtB,aACE,oBAAC,SAAI,WAAU,YACb,8BAAC,SAAO,GAAG,OAAO,MAAM,EAAE,UAAU,CAAC,GAAG,OAAO,KAAK,GAAG,GACzD;AAAA,IAEJ;AAEA,UAAM,UAAuB;AAAA,MAC3B,GAAG,YAAY,OAAO,MAAM;AAAA,MAC5B,OACE;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,KAAK,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,UACnC;AAAA,UACA,QAAQ,CAAC,cAAc;AACrB,kBAAM,OAAO,UAAU,OAAO,WAAW,MAAM;AAC/C,gBAAI,KAAK,MAAM,QAAS,YAAW,KAAK,CAAC;AACzC,oBAAQ,KAAK,CAAC;AAAA,UAChB;AAAA,UACA,SAAS;AAAA;AAAA,MACX;AAAA,IAEJ;AAEA,WACE,qBAAC,SAAI,WAAU,YACb;AAAA,0BAAC,SAAO,GAAG,OAAO,MAAM,SAAS;AAAA,MAChC,UAAU,CAAC,SACV;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAW;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,UAEA;AAAA,gCAAC,KAAE,eAAW,MAAC,WAAU,UAAS;AAAA,YAAE;AAAA,YAAE,OAAO;AAAA;AAAA;AAAA,MAC/C;AAAA,OAEJ;AAAA,EAEJ;AACA,WAAS,cAAc,iBAAiB,MAAM,eAAe,MAAM,QAAQ,OAAO;AAClF,SAAO;AACT;AAeA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,OAAO,YAAY;AACzB,QAAM,WAAW,qBAAqB;AAItC,QAAM,CAAC,MAAM,IAAI,SAAS,MAAM,oBAAI,IAA8C,CAAC;AACnF,QAAM,CAAC,MAAM,OAAO,IAAI,SAA0B,IAAI;AAGtD,QAAM,aAAa,OAAO,KAAK;AAE/B,MAAI,CAAC,QAAQ,KAAK,SAAS,KAAK,KAAK,UAAU,EAAG,QAAO;AAEzD,QAAM,KAAK,CAAC,UAAwE;AAIlF,UAAM,MAAM,MAAM,cAAc,sBAAsB;AACtD,WAAO,EAAE,GAAG,MAAM,UAAU,IAAI,OAAO,KAAK,GAAG,GAAG,MAAM,UAAU,IAAI,MAAM,KAAK,EAAE;AAAA,EACrF;AAEA,QAAM,SAAS,MAAM;AACnB,QAAI,CAAC,KAAM;AACX,YAAQ,IAAI;AACZ,UAAM,YAAY,kBAAkB,MAAM,MAAM,UAAU,CAAC,OAAO,OAAO,IAAI,EAAE,GAAG,SAAS,IAAI;AAC/F,eAAW,UAAU,cAAc;AACnC,QAAI,UAAW,QAAO,SAAS;AAAA,EACjC;AAIA,QAAM,QAAQ,OACV,YAAY,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,oBAAoB,IAAI,IAC3G;AAEJ,SACE,qBAAC,OACE;AAAA,YAAQ,IAAI,CAAC,OACZ,oBAAC,aAAmB,QAAQ,IAAI,UAAhB,EAAgC,CACjD;AAAA,IACA,QAAQ,SACP;AAAA,MAAC;AAAA;AAAA,QACC,GAAG,UAAU,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,OAAO,KAAK,GAAG;AAAA,QACzD,GAAG,UAAU,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,OAAO,KAAK,GAAG;AAAA,QACzD,OAAO,UAAU,MAAM,KAAK,QAAQ,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK;AAAA,QAClE,QAAQ,UAAU,MAAM,KAAK,SAAS,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK;AAAA,QACpE,WAAU;AAAA,QACV,iBAAgB;AAAA,QAChB,eAAc;AAAA;AAAA,IAChB;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,GAAG,KAAK;AAAA,QACR,GAAG,KAAK;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QAEb,MAAK;AAAA,QACL,qBAAkB;AAAA,QAClB,OAAO,EAAE,QAAQ,YAAY;AAAA,QAC7B,eAAe,CAAC,UAAU;AACxB,cAAI,MAAM,WAAW,EAAG;AACxB,qBAAW,UAAU;AACrB,gBAAM,QAAQ,GAAG,KAAK;AAItB,cAAI;AACF,kBAAM,cAAc,kBAAkB,MAAM,SAAS;AAAA,UACvD,QAAQ;AAAA,UAER;AACA,kBAAQ,EAAE,OAAO,MAAM,GAAG,OAAO,MAAM,GAAG,KAAK,MAAM,GAAG,KAAK,MAAM,EAAE,CAAC;AAAA,QACxE;AAAA,QACA,eAAe,CAAC,UAAU;AACxB,cAAI,CAAC,KAAM;AACX,gBAAM,QAAQ,GAAG,KAAK;AACtB,kBAAQ,EAAE,GAAG,MAAM,KAAK,MAAM,GAAG,KAAK,MAAM,EAAE,CAAC;AAAA,QACjD;AAAA,QACA,aAAa;AAAA,QACb,iBAAiB,MAAM,QAAQ,IAAI;AAAA,QACnC,SAAS,CAAC,UAAU;AAClB,cAAI,CAAC,WAAW,QAAS;AACzB,qBAAW,UAAU;AACrB,gBAAM,gBAAgB;AAAA,QACxB;AAAA,QACA,eAAe;AAAA;AAAA,IACjB;AAAA,KACF;AAEJ;AAGA,SAAS,UAAU,EAAE,QAAQ,OAAO,GAA8E;AAChH,QAAM,UAAU,qBAAqB,MAAM;AAC3C,YAAU,MAAM;AACd,WAAO,IAAI,QAAQ,OAAO;AAC1B,WAAO,MAAM;AACX,aAAO,OAAO,MAAM;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,MAAM,CAAC;AAC5B,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/components/chart-zoom-core.tsx"],"sourcesContent":["// Drag-to-zoom for cartesian charts — the HOC, the shared x window, and the arithmetic.\n// Lifted out of lenkbank, where every plot in the app is one `SeriesChart` and zoom is\n// therefore wired in exactly once.\n//\n// **Which axes a drag zooms is read off the drag itself.** A selection that is roughly\n// square is a box: the reader framed a REGION and means both axes. A long thin one is a\n// band, and its own direction says which: a wide flat drag means \"this stretch of the\n// abscissa\", a tall narrow one \"this range of values\". Asking with a modifier key\n// instead would be asking people to remember a convention for something they have\n// already drawn.\n//\n// Squareness is measured **in fractions of the plot**, not pixels. These charts are\n// three times wider than they are tall, so a pixel-square selection is a very wide\n// slice of the data and would read as a band to anybody looking at it.\n//\n// The zoom is VIEW state and lives here, never in a query or a store: it is where\n// somebody is looking, and a chart whose data reloads should not lose it. It is cleared\n// by the reset button, by a double click, and by nothing else.\n//\n// Everything with a decision in it is a pure exported function below (`zoomAxesFor`,\n// `selectionFromDrag`, `zoomAfter`, `zoomDomains`, `fitYToX`, `fitXToY`); the\n// components are plumbing between a pointer and those.\n//\n// The kit's own module (0.34, refactor audit 2026-10, API-6b): SeriesChart, its axes and\n// the facing pair import from here. ./chart-zoom is the public face — `SharedXZoom`, the\n// types, and until 0.35 the deprecated arithmetic and HOC, which no app imports.\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ComponentType, Dispatch, ReactNode, SetStateAction } from \"react\";\nimport { usePlotArea, useXAxisInverseScale, useYAxisInverseScale, type InverseScaleFunction } from \"recharts\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { FOCUS_RING } from \"./focus-ring\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { DEFAULT_SERIES_CHART_LABELS, type SeriesChartLabels } from \"./series-chart-labels\";\n\n/** The y axis a series lands on when it names none — the single shared scale most\n * charts have. `SeriesChart` and the fit below agree on it by importing this. */\nexport const DEFAULT_Y_AXIS = \"y\";\n\n/* ── The arithmetic ─────────────────────────────────────────────────────── */\n\n/**\n * How square a selection has to be before it counts as a box: the shorter side\n * against the longer, both as fractions of the plot. At 0.5 a selection twice as wide\n * as it is tall is still a box and one three times as wide is a band.\n */\nexport const ZOOM_SQUARE_ENOUGH = 0.5;\n\n/** Below this a drag is a click that moved, not a selection. In fractions of the plot,\n * so it is the same gesture on a phone and on a wall display. */\nexport const ZOOM_MIN_DRAG = 0.02;\n\nexport type ZoomAxes = \"both\" | \"x\" | \"y\";\n\n/** Which axes a drag zooms — or `null` for a drag too small to mean one, or a plot\n * that has not been laid out yet. Direction does not matter; proportion does. */\nexport function zoomAxesFor(\n dx: number,\n dy: number,\n width: number,\n height: number,\n threshold: number = ZOOM_SQUARE_ENOUGH,\n /** A chart that zooms ONE axis only (see {@link ZoomTarget.zoomAxes}): every drag is\n * a band along it, however it was drawn, and a drag with no extent along it is\n * nothing — a tall narrow drag over a bar chart names no stretch of the abscissa. */\n only?: \"x\" | \"y\",\n): ZoomAxes | null {\n if (!(width > 0) || !(height > 0)) return null;\n const across = Math.abs(dx) / width;\n const down = Math.abs(dy) / height;\n if (only === \"x\") return across < ZOOM_MIN_DRAG ? null : \"x\";\n if (only === \"y\") return down < ZOOM_MIN_DRAG ? null : \"y\";\n if (across < ZOOM_MIN_DRAG && down < ZOOM_MIN_DRAG) return null;\n const longer = Math.max(across, down);\n const shorter = Math.min(across, down);\n if (shorter / longer >= threshold) return \"both\";\n return across > down ? \"x\" : \"y\";\n}\n\n/** What a drag chose, in DATA coordinates, and which axes it actually named — the\n * caller needs the second to know which of the two it may derive from the other. */\nexport interface ZoomSelection {\n which: ZoomAxes;\n x?: [number, number];\n /** One window per y axis, keyed by axis id: they are in different units. */\n y: Record<string, [number, number]>;\n}\n\n/** A drag, in the chart's own pixel coordinates. */\nexport interface ZoomDrag {\n fromX: number;\n fromY: number;\n toX: number;\n toY: number;\n}\n\n/** A pair as a domain, smallest first. Recharts wants an ascending domain whichever\n * way the drag went, and a y axis counts downward in pixels while its values count\n * upward — so both ends are read and sorted rather than one assumed to be low. */\nfunction ordered(a: number, b: number): [number, number] {\n return a <= b ? [a, b] : [b, a];\n}\n\n/**\n * A finished drag as a selection, or `null` when it selects nothing.\n *\n * `xInverse` and `yInverse(axisId)` are recharts' pixel→value functions; an axis whose\n * function is missing, or whose ends come back non-finite, is left out rather than\n * handed a NaN window.\n */\nexport function selectionFromDrag(\n drag: ZoomDrag,\n plot: { width: number; height: number },\n xInverse: InverseScaleFunction | undefined,\n yInverse: (axisId: string) => InverseScaleFunction | undefined,\n axisIds: readonly string[],\n only?: \"x\" | \"y\",\n): ZoomSelection | null {\n const which = zoomAxesFor(\n drag.toX - drag.fromX,\n drag.toY - drag.fromY,\n plot.width,\n plot.height,\n ZOOM_SQUARE_ENOUGH,\n only,\n );\n if (!which) return null;\n const next: ZoomSelection = { which, y: {} };\n if (which !== \"y\" && xInverse) {\n const from = Number(xInverse(drag.fromX));\n const to = Number(xInverse(drag.toX));\n if (Number.isFinite(from) && Number.isFinite(to)) next.x = ordered(from, to);\n }\n if (which !== \"x\") {\n for (const id of axisIds) {\n const inverse = yInverse(id);\n if (!inverse) continue;\n const from = Number(inverse(drag.fromY));\n const to = Number(inverse(drag.toY));\n if (Number.isFinite(from) && Number.isFinite(to)) next.y[id] = ordered(from, to);\n }\n }\n return next.x || Object.keys(next.y).length ? next : null;\n}\n\n/** One row of a zoomable chart. Loose on purpose: a row also carries what the chart\n * does not plot — keksdose's `rawPeriod` for a drilldown, a label for a category axis —\n * and only the finite NUMBERS in it are ever read as samples. */\nexport type ZoomRow = Readonly<Record<string, unknown>>;\n\n/** A series as the fit sees it. `stack` groups bars/areas drawn on top of each other\n * (recharts' `stackId`), whose extent is their SUM, not any one of them. */\nexport interface ZoomFitSeries {\n key: string;\n axis?: string;\n stack?: string;\n /** Only `\"line\"` matters here: recharts cannot stack a line, so a line's `stack` is\n * ignored rather than summed into a height nothing on the chart reaches. */\n type?: string;\n}\n\n/** What a band refit needs to know about the chart — a subset of `SeriesChart`'s own\n * props, so a chart hands its data straight over. */\nexport interface ZoomFitSource {\n rows: readonly ZoomRow[];\n series: readonly ZoomFitSeries[];\n axes: readonly { id: string }[];\n xKey: string;\n}\n\n/** How much of a refitted span to leave as air, top and bottom. Without it the\n * highest sample sits exactly on the frame, where a line is half drawn and reads as\n * clipped rather than as the maximum. */\nconst FIT_AIR = 0.05;\n\n/** A span with air around it — and a real span for a flat channel, which would\n * otherwise be a zero-height window recharts cannot scale. */\nfunction airy(low: number, high: number): [number, number] {\n const span = high - low;\n const air = span > 0 ? span * FIT_AIR : Math.max(Math.abs(high), 1) * FIT_AIR;\n return [low - air, high + air];\n}\n\n/** A running low/high pair. A pair rather than an array to take `Math.min(...)` of:\n * the spread passes one argument per sample, and V8 faults past ~125,000 of them. */\ntype Span = [number, number] | undefined;\n\n/** A pair widened by one value. A non-finite one is not a value — one NaN would\n * otherwise take the whole window with it. */\nfunction widen(span: Span, value: unknown): Span {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return span;\n if (!span) return [value, value];\n if (value < span[0]) span[0] = value;\n else if (value > span[1]) span[1] = value;\n return span;\n}\n\n/** Which series are measured on an axis. */\nfunction keysOn(source: ZoomFitSource, axisId: string): string[] {\n return source.series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axisId).map((entry) => entry.key);\n}\n\n/** A row's value as a sample, or 0 for a stack's missing layer — a stacked bar with no\n * value for one series draws the rest of the stack from where that one would end. */\nconst layer = (value: unknown) => (typeof value === \"number\" && Number.isFinite(value) ? value : 0);\n\n/**\n * The lowest and highest value an axis DRAWS over the rows whose abscissa is inside\n * `window` (every row when there is none) — `undefined` when it draws nothing finite.\n *\n * Stack-aware, and that is why it exists: a stack of three bars reaches the SUM of\n * them, and fitting the axis to the tallest single layer (what fitting on values did)\n * cuts the top two thirds of every stack off. Positive and negative layers are summed\n * apart, as recharts draws them under `stackOffset=\"sign\"` — a month with 900 income\n * and −300 expense stacks up to 900 and down to −300, not to 600. A stacked extent\n * therefore always contains the zero its layers stand on.\n *\n * `SeriesChart` fits its axes with this and the zoom refits them with it, so the two\n * cannot disagree about how tall a stack is.\n */\nexport function axisExtent(\n source: ZoomFitSource,\n axisId: string,\n window?: readonly [number, number],\n): [number, number] | undefined {\n const mine = source.series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axisId);\n const loose: string[] = [];\n const stacks = new Map<string, string[]>();\n for (const entry of mine) {\n if (entry.stack === undefined || entry.type === \"line\" || entry.type === undefined) {\n loose.push(entry.key);\n } else {\n stacks.set(entry.stack, [...(stacks.get(entry.stack) ?? []), entry.key]);\n }\n }\n let span: Span;\n for (const row of source.rows) {\n if (window) {\n const at = row[source.xKey];\n if (typeof at !== \"number\" || !(at >= window[0] && at <= window[1])) continue;\n }\n for (const key of loose) span = widen(span, row[key]);\n for (const keys of stacks.values()) {\n let up = 0;\n let down = 0;\n let any = false;\n for (const key of keys) {\n const value = layer(row[key]);\n any ||= typeof row[key] === \"number\" && Number.isFinite(row[key]);\n if (value >= 0) up += value;\n else down += value;\n }\n if (!any) continue;\n span = widen(widen(span, down), up);\n }\n }\n return span;\n}\n\n/**\n * Each y axis fitted to the samples inside an x window — what a band across x leaves\n * the axes nobody dragged showing. Zoom into a tenth of a sweep and a y axis still\n * scaled to the whole run draws that tenth as a flat line, which is the one thing the\n * zoom was for; so the unnamed axes are refitted, which is what \"zoom\" means everywhere\n * else.\n *\n * An axis with nothing inside the window is left OUT rather than collapsed: a window\n * between two samples is one where the chart should keep drawing the line across.\n */\nexport function fitYToX(source: ZoomFitSource, window: readonly [number, number]): Record<string, [number, number]> {\n const fitted: Record<string, [number, number]> = {};\n for (const axis of source.axes) {\n const span = axisExtent(source, axis.id, window);\n if (span) fitted[axis.id] = airy(span[0], span[1]);\n }\n return fitted;\n}\n\n/**\n * The x window that holds every sample inside a set of y windows — the other direction\n * of the same idea. A channel crossing its band once gives a tight window; one that\n * oscillates through it gives back most of the sweep, which is the truthful answer.\n * `undefined` when no sample qualifies, rather than a guess.\n */\nexport function fitXToY(\n source: ZoomFitSource,\n windows: Readonly<Record<string, readonly [number, number]>>,\n): [number, number] | undefined {\n let hits: Span;\n for (const [axisId, [low, high]] of Object.entries(windows)) {\n for (const key of keysOn(source, axisId)) {\n for (const row of source.rows) {\n const value = row[key];\n if (typeof value === \"number\" && Number.isFinite(value) && value >= low && value <= high) {\n hits = widen(hits, row[source.xKey]);\n }\n }\n }\n }\n return hits ? airy(hits[0], hits[1]) : undefined;\n}\n\n/**\n * What a chart remembers about its zoom: the x window, and the y windows the reader\n * DRAGGED. `y: null` means \"derive y from x\" — the split is the whole design: what was\n * dragged is kept, and what follows from it is recomputed on every render, so a band\n * across x refits y here and in every chart sharing the window.\n */\nexport interface ZoomState {\n x?: [number, number];\n y: Record<string, [number, number]> | null;\n}\n\nexport const NO_ZOOM: ZoomState = { x: undefined, y: null };\n\n/**\n * The state after a selection. Two band drags COMPOSE rather than the second undoing\n * the first: a band down y keeps the x window when the band holds no samples, and\n * otherwise pulls x in to where they are.\n */\nexport function zoomAfter(state: ZoomState, selection: ZoomSelection, source: ZoomFitSource): ZoomState {\n if (selection.which === \"both\") return { x: selection.x, y: selection.y };\n // Leave y derived, so it fits itself to what is inside the new window.\n if (selection.which === \"x\") return { x: selection.x, y: null };\n return { x: fitXToY(source, selection.y) ?? state.x, y: selection.y };\n}\n\n/** The domains a chart draws for a state: the x window as is, and each y axis either\n * as dragged or fitted to the x window. `{}` means \"fit your own data\". */\nexport function zoomDomains(\n state: ZoomState,\n source: ZoomFitSource,\n): { xDomain?: [number, number]; yDomains: Record<string, [number, number]> } {\n return {\n xDomain: state.x,\n yDomains: state.y ?? (state.x ? fitYToX(source, state.x) : {}),\n };\n}\n\n/* ── The components ─────────────────────────────────────────────────────── */\n\n/** What the wrapped chart is handed. It applies the domains to its own axes and renders\n * `layer` INSIDE the recharts chart, where recharts' hooks answer. */\nexport interface ZoomBinding {\n xDomain?: [number, number];\n yDomains: Record<string, [number, number]>;\n layer: ReactNode;\n}\n\n/**\n * Which axes a chart lets a drag zoom. `\"none\"` draws no drag layer and no reset.\n * A drag on a one-axis chart is always a band along that axis (see {@link zoomAxesFor}).\n */\nexport type ZoomAxesSetting = ZoomAxes | \"none\";\n\n/**\n * The zoom a chart gets when it does not say, read off what its series ARE.\n *\n * - Only lines: `\"both\"` — lenkbank's measurement plots, unchanged.\n * - Any area: `\"x\"`. An area's height is a length from zero, and a y window that cuts\n * the baseline off draws a band of 40 as three times one of 20 — so its y axis refits\n * to the x window (still from zero), and a drag never names a y range.\n * - Any bar: `\"none\"`. A bar chart is a handful of periods read one bar at a time, and\n * in keksdose every one of them is CLICKED — to drill into a payee, a month, a budget\n * line — which a drag layer over the plot would swallow. A chart of many bars opts\n * back in with `zoomAxes: \"x\"`; a click then reports the period, not the bar.\n */\nexport function defaultZoomAxes(series: readonly { type?: string }[] | undefined): ZoomAxesSetting {\n if (series?.some((entry) => entry.type === \"bar\")) return \"none\";\n if (series?.some((entry) => entry.type === \"area\")) return \"x\";\n return \"both\";\n}\n\n/** The props `withChartZoom` reads off the chart it wraps. */\nexport interface ZoomTarget {\n /** Default: the single axis {@link DEFAULT_Y_AXIS}. */\n axes?: readonly { id: string; hide?: boolean }[];\n /** The chart's own data, so a band can refit the axis it did not name. Optional: a\n * chart with nothing plotted has nothing to fit to. */\n rows?: readonly ZoomRow[];\n series?: readonly ZoomFitSeries[];\n x?: { key?: string };\n zoom?: ZoomBinding;\n labels?: LabelOverride<SeriesChartLabels>;\n /** Which axes a drag may zoom. Default: {@link defaultZoomAxes} of `series`. */\n zoomAxes?: ZoomAxesSetting;\n}\n\nconst SharedX = createContext<{\n window?: [number, number];\n set: Dispatch<SetStateAction<[number, number] | undefined>>;\n} | null>(null);\n\n/**\n * One x window for several charts.\n *\n * A column of charts over one abscissa is one picture, and zooming one of them and not\n * the rest turns it into several pictures of different things. Every zoomable chart\n * inside this shares the x window: any drag in any of them moves all of them.\n *\n * **Only x.** The y axes stay each chart's own — they are in different units — and\n * each refits its own y to what is inside the shared window.\n */\nexport function SharedXZoom({ children }: { children: ReactNode }) {\n const [window, set] = useState<[number, number] | undefined>(undefined);\n return <SharedX.Provider value={{ window, set }}>{children}</SharedX.Provider>;\n}\n\n/** The axes a chart that names none zooms: the single shared scale, one array for all. */\nconst ONE_AXIS: readonly { id: string }[] = [{ id: DEFAULT_Y_AXIS }];\n\n/** The binding of a chart that does not zoom: no window, no layer, the same object always. */\nconst NO_BINDING: ZoomBinding = { yDomains: {}, layer: null };\n\n/**\n * Wrap a chart in drag-to-zoom.\n *\n * The chart receives a `zoom` binding: it applies `xDomain`/`yDomains` to its axes\n * (with `allowDataOverflow`, so recharts clips to the window instead of widening it\n * back out) and renders `layer` as a child of its recharts chart. A reset button\n * appears over the chart's top end corner while it is zoomed — a real button, so the\n * keyboard can undo what the pointer did.\n */\nexport function withChartZoom<P extends ZoomTarget>(Chart: ComponentType<P>) {\n function Zoomable(props: P) {\n const labels = useKitLabels(\"seriesChart\", DEFAULT_SERIES_CHART_LABELS, props.labels);\n const group = useContext(SharedX);\n const [ownX, setOwnX] = useState<[number, number] | undefined>(undefined);\n const [ownY, setOwnY] = useState<Record<string, [number, number]> | null>(null);\n const xWindow = group ? group.window : ownX;\n const setXWindow = group ? group.set : setOwnX;\n const axes = props.axes ?? ONE_AXIS;\n const setting = props.zoomAxes ?? defaultZoomAxes(props.series);\n const only = setting === \"x\" || setting === \"y\" ? setting : undefined;\n const { rows, series } = props;\n const xKey = props.x?.key ?? \"x\";\n\n // Every axis, hidden ones included: a hidden axis still scales its lines, and a\n // line whose axis did not refit is drawn as a flat streak inside the window.\n const source = useMemo<ZoomFitSource>(\n () => ({ rows: rows ?? [], series: [...(series ?? [])], axes: [...axes], xKey }),\n [rows, series, axes, xKey],\n );\n const zoomed = xWindow !== undefined || ownY !== null;\n // A chart handed no rows or no series draws its empty state, not a plot — and a\n // \"Reset zoom\" floating over \"No data\" (every line toggled off while zoomed) offers\n // to undo something the reader cannot see. The zoom itself is KEPT: it is where they\n // were looking, and it applies again the moment a line comes back. Only an array\n // that is there and empty counts; a chart that does not pass its data is not known\n // to be empty.\n const empty = rows?.length === 0 || series?.length === 0;\n\n const clear = useCallback(() => {\n setXWindow(undefined);\n setOwnY(null);\n }, [setXWindow]);\n\n // Memoised over what it reads (0.55, held back from 0.52's review): built afresh on every\n // render, the binding was a new prop — and its layer a new element — for the chart,\n // which then drew every series, axis and tick again for a render of the page that\n // changed nothing in it.\n //\n // Switched off, the chart still gets a binding — with no window and no layer — so a\n // chart whose series change type mid-life is not remounted by a different tree.\n const binding = useMemo<ZoomBinding>(() => {\n if (setting === \"none\") return NO_BINDING;\n const state: ZoomState = { x: xWindow, y: ownY };\n return {\n ...zoomDomains(state, source),\n layer: (\n <ZoomLayer\n axisIds={source.axes.map((axis) => axis.id)}\n only={only}\n onZoom={(selection) => {\n const next = zoomAfter(state, selection, source);\n if (next.x !== xWindow) setXWindow(next.x);\n setOwnY(next.y);\n }}\n onReset={clear}\n />\n ),\n };\n }, [setting, xWindow, ownY, source, only, setXWindow, clear]);\n\n if (setting === \"none\") {\n return (\n <div className=\"relative\">\n <Chart {...props} zoom={binding} />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n <Chart {...props} zoom={binding} />\n {zoomed && !empty && (\n <button\n type=\"button\"\n onClick={clear}\n className={cn(\n \"absolute end-1 top-1 z-10 inline-flex items-center gap-1 rounded border border-subtle bg-surface/90 px-1.5 py-0.5 text-micro text-muted backdrop-blur transition-colors hover:text-primary\",\n FOCUS_RING,\n )}\n >\n <X aria-hidden className=\"size-3\" /> {labels.resetZoom}\n </button>\n )}\n </div>\n );\n }\n Zoomable.displayName = `withChartZoom(${Chart.displayName ?? Chart.name ?? \"Chart\"})`;\n return Zoomable;\n}\n\n/**\n * The part that lives INSIDE the recharts chart, where recharts will say where the plot\n * is and what value a pixel is.\n *\n * A transparent rectangle over the plot area that reads the drag. It does NOT stop the\n * event: recharts drives its tooltip from the same pointer move bubbling up to its own\n * wrapper, so swallowing it here would trade the tooltip for the zoom.\n *\n * Nothing to assistive technology (0.52, refactor audit 2026-10-30, DSP-5): it was a\n * `role=\"application\"` named by the drag hint, which could not take focus — the one name\n * on an otherwise unnamed chart. The hint is in the chart's description now\n * (`SeriesChart`'s figure), and `data-zoom-surface` is how a test finds the rect.\n */\nfunction ZoomLayer({\n axisIds,\n only,\n onZoom,\n onReset,\n}: {\n axisIds: string[];\n only?: \"x\" | \"y\";\n onZoom: (selection: ZoomSelection) => void;\n onReset: () => void;\n}) {\n const plot = usePlotArea();\n const xInverse = useXAxisInverseScale();\n // One probe COMPONENT per axis rather than a hook in a loop: the number of axes\n // changes as series are toggled, and a hook count that changes with the data is the\n // one thing React will not forgive.\n const [scales] = useState(() => new Map<string, InverseScaleFunction | undefined>());\n const [drag, setDrag] = useState<ZoomDrag | null>(null);\n // A finished drag is followed by a click on the same element, and a chart with an\n // `onClick` (keksdose opens a drilldown on one) would read the zoom as a pick.\n const draggedRef = useRef(false);\n\n if (!plot || plot.width <= 0 || plot.height <= 0) return null;\n\n const at = (event: { clientX: number; clientY: number; currentTarget: Element }) => {\n // Against the overlay's own screen box, so padding around the container cannot\n // shift every reading — plus the plot's offset, because the scales are in the\n // chart's coordinates rather than the plot's.\n const box = event.currentTarget.getBoundingClientRect();\n return { x: event.clientX - box.left + plot.x, y: event.clientY - box.top + plot.y };\n };\n\n const finish = () => {\n if (!drag) return;\n setDrag(null);\n const selection = selectionFromDrag(drag, plot, xInverse, (id) => scales.get(id), axisIds, only);\n draggedRef.current = selection !== null;\n if (selection) onZoom(selection);\n };\n\n // What the drag would do, shown while it is being made: a band paints the full width\n // or height, so the reader sees it is about to let the other axis refit.\n const which = drag\n ? zoomAxesFor(drag.toX - drag.fromX, drag.toY - drag.fromY, plot.width, plot.height, ZOOM_SQUARE_ENOUGH, only)\n : null;\n\n return (\n <g>\n {axisIds.map((id) => (\n <AxisProbe key={id} axisId={id} scales={scales} />\n ))}\n {drag && which && (\n <rect\n x={which === \"y\" ? plot.x : Math.min(drag.fromX, drag.toX)}\n y={which === \"x\" ? plot.y : Math.min(drag.fromY, drag.toY)}\n width={which === \"y\" ? plot.width : Math.abs(drag.toX - drag.fromX)}\n height={which === \"x\" ? plot.height : Math.abs(drag.toY - drag.fromY)}\n className=\"fill-[var(--brand)]/15 stroke-[var(--brand)]\"\n strokeDasharray=\"4 3\"\n pointerEvents=\"none\"\n />\n )}\n <rect\n x={plot.x}\n y={plot.y}\n width={plot.width}\n height={plot.height}\n // `transparent`, not `none`: an unpainted shape takes no pointer events.\n fill=\"transparent\"\n data-zoom-surface=\"\"\n style={{ cursor: \"crosshair\" }}\n onPointerDown={(event) => {\n if (event.button !== 0) return;\n draggedRef.current = false;\n const point = at(event);\n // Best effort: capture keeps a drag alive past the plot's edge, but a\n // pointer id the environment does not know throws — jsdom refuses them all —\n // and a zoom that threw on pointer-down would be a chart nobody could click.\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n /* the drag still works; it just stops at the edge of the plot */\n }\n setDrag({ fromX: point.x, fromY: point.y, toX: point.x, toY: point.y });\n }}\n onPointerMove={(event) => {\n if (!drag) return;\n const point = at(event);\n setDrag({ ...drag, toX: point.x, toY: point.y });\n }}\n onPointerUp={finish}\n onPointerCancel={() => setDrag(null)}\n onClick={(event) => {\n if (!draggedRef.current) return;\n draggedRef.current = false;\n event.stopPropagation();\n }}\n onDoubleClick={onReset}\n />\n </g>\n );\n}\n\n/** One axis's pixel→value function, parked where the pointer handler can reach it. */\nfunction AxisProbe({ axisId, scales }: { axisId: string; scales: Map<string, InverseScaleFunction | undefined> }) {\n const inverse = useYAxisInverseScale(axisId);\n useEffect(() => {\n scales.set(axisId, inverse);\n return () => {\n scales.delete(axisId);\n };\n }, [axisId, inverse, scales]);\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -46,7 +46,7 @@ function CheckboxGroup({
46
46
  const errorId = `${generated}-error`;
47
47
  const helpMark = fieldHelpMark(legend !== void 0 && legendVisibility === "visible" ? help : void 0, legend);
48
48
  const legendTextId = `${generated}-legend`;
49
- const shownHint = useInlineHint(hint, helpMark !== void 0);
49
+ const shownHint = useInlineHint(hint, helpMark !== void 0, legend);
50
50
  const showHint = hasContent(shownHint);
51
51
  const showError = hasContent(error);
52
52
  const isInvalid = Boolean(invalid) || showError;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/checkbox-group.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { Checkbox } from \"./checkbox\";\nimport { hasContent } from \"../lib/presence\";\nimport { useCommitReason, type CommitScope } from \"./write-lock\";\nimport {\n FIELD_ERROR_CLASS,\n fieldHelpMark,\n mergeDescribedBy,\n RequiredStarOnLegend,\n useInlineHint,\n type FieldHelpProps,\n} from \"./field-parts\";\n\n/** One box of a {@link CheckboxGroup}. */\nexport interface CheckboxGroupOption<T extends string = string> {\n value: T;\n /** The words beside the box — its accessible name. */\n label: ReactNode;\n /** A line under the label (\"Imprint, Privacy Policy and Terms only\"), attached to the\n * box with `aria-describedby` — {@link Checkbox}'s `description`. */\n hint?: ReactNode;\n /** This box cannot be changed; the others can. */\n disabled?: boolean;\n}\n\n/** Whether the legend is drawn. `\"sr-only\"` keeps it as the group's name for a screen\n * reader where the dialog's title already says it to the eye. */\nexport type CheckboxGroupLegendVisibility = \"visible\" | \"sr-only\";\n\nexport interface CheckboxGroupProps<T extends string = string> extends FieldHelpProps {\n /** The question the boxes answer — the fieldset's `<legend>`, which names the group.\n * Without one, pass `aria-label`. */\n legend?: ReactNode;\n /** Default `\"visible\"`. */\n legendVisibility?: CheckboxGroupLegendVisibility;\n \"aria-label\"?: string;\n /** One box per option, in this order. */\n options: CheckboxGroupOption<T>[];\n /** The ticked values. Controlled. */\n value: T[];\n /**\n * The new set on every tick. In the ORDER OF `options`, not the order the boxes were\n * ticked, so a list saved from it does not change with the order someone clicked in\n * (ChoiceCardGroup's rule). A value in `value` that no option carries — a grant for a\n * locale the app no longer offers — is kept, after the known ones: a picker that\n * dropped what it could not show would delete it on the next unrelated tick.\n */\n onChange: (value: T[]) => void;\n /**\n * `\"vertical\"` (default): one box per line. `\"horizontal\"`: a wrapping row, for a few\n * short labels. With `columns`, vertical becomes a grid of that many columns from the\n * `sm` breakpoint up and stays one column on a phone — the reviewer dialog's shape.\n */\n layout?: \"vertical\" | \"horizontal\";\n /** Columns for a vertical group, from `sm` up (one on a phone). Default 1. */\n columns?: 1 | 2 | 3 | 4;\n /** Shared by every box — what a plain form submits the values under. */\n name?: string;\n /** Every box: the fieldset's own `disabled` (which disables them all natively), each\n * box faded as a disabled Checkbox is, and the legend with them. */\n disabled?: boolean;\n /**\n * At least one box must be ticked. Draws the required star after the legend, and puts\n * the native `required` on every box while NONE is ticked — so a form refuses an\n * empty set — and on none once one is (ChoiceCardGroup's rule: checkboxes cannot say\n * \"at least one\" natively).\n */\n required?: boolean;\n /**\n * Standing advice for the group, under the boxes, attached to the fieldset with\n * `aria-describedby` before the error — the field anatomy every kit field keeps.\n * A `help` beside it (0.36) is a \"?\" after the legend — with a visible legend only —\n * and names nothing: the fieldset is then named by the legend's words alone.\n */\n hint?: ReactNode;\n /** What is wrong with the set, in the caller's words. Under the boxes, on the\n * fieldset's `aria-describedby`, and paints every box invalid. */\n error?: ReactNode;\n /** Paints every box invalid without a message (the message lives elsewhere). */\n invalid?: boolean;\n /**\n * The group SAVES on change — each tick is written straight away (a reviewer's\n * per-locale grants). Under a locked {@link WriteLockProvider} every box is locked\n * the focusable way with the lock's reason. See {@link Checkbox}'s `commit`.\n */\n commit?: CommitScope;\n /** Why no box can be changed — every box gets it, and it wins over `disabled` (the\n * boxes stay focusable to say it). See {@link Checkbox}'s `disabledReason`. */\n disabledReason?: ReactNode;\n /** The fieldset's id. */\n id?: string;\n /** Classes for the fieldset — the outermost element, where layout belongs. */\n className?: string;\n /** Classes for the box list (the grid or the row). */\n listClassName?: string;\n /** Ids of something else on the page that describes the group; merged before the\n * group's own hint and error. */\n \"aria-describedby\"?: string;\n}\n\n// Literal class strings so Tailwind's scanner sees each one.\nconst COLUMNS: Record<NonNullable<CheckboxGroupProps[\"columns\"]>, string> = {\n 1: \"flex flex-col gap-2\",\n 2: \"grid grid-cols-1 gap-2 sm:grid-cols-2\",\n 3: \"grid grid-cols-1 gap-2 sm:grid-cols-3\",\n 4: \"grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-4\",\n};\n\n/**\n * A set of kit {@link Checkbox}es answering one question, in a `<fieldset>`.\n *\n * Kurvenschmiede's reviewer dialog (features/admin/reviewer-dialog.tsx) builds this by\n * hand — a fieldset, an `sr-only` legend, a grid of checkboxes, a `toggle(code, on)`\n * that adds or filters a `string[]` — and keksdose's and kastlan's reviewer grants build\n * the same picker for the same per-locale grant. The hand-built ones differ in the parts\n * that are easy to get wrong: whether the legend names the group, whether a hint or an\n * error is attached to anything, what order the saved list comes out in, and whether a\n * value the picker cannot show survives a tick.\n *\n * Every box is a kit {@link Checkbox}, so the native checkbox semantics stay (each box\n * submits under `name` in a plain form). The legend is the group's name; the hint and\n * error describe the fieldset. For a choice of ONE, use radios ({@link ChoiceCardGroup},\n * {@link ToggleGroup}).\n */\nexport function CheckboxGroup<T extends string = string>({\n legend,\n legendVisibility = \"visible\",\n \"aria-label\": ariaLabel,\n options,\n value,\n onChange,\n layout = \"vertical\",\n columns = 1,\n name,\n disabled,\n required,\n hint,\n help,\n error,\n invalid,\n commit,\n disabledReason,\n id,\n className,\n listClassName,\n \"aria-describedby\": ariaDescribedBy,\n}: CheckboxGroupProps<T>) {\n const generated = useId();\n const hintId = `${generated}-hint`;\n const errorId = `${generated}-error`;\n // §4: a FieldHint under the group is its words at Large and on a touch screen, not a\n // lone \"?\" (DUP-2, refactor audit 2026-10). A HelpPopover stays a \"?\".\n // A `help` \"?\" after a VISIBLE legend (0.36): the label line a group has. Its FieldHint\n // hint is then its words at every size, as everywhere a help stands beside one.\n const helpMark = fieldHelpMark(legend !== undefined && legendVisibility === \"visible\" ? help : undefined, legend);\n const legendTextId = `${generated}-legend`;\n const shownHint = useInlineHint(hint, helpMark !== undefined);\n const showHint = hasContent(shownHint);\n const showError = hasContent(error);\n const isInvalid = Boolean(invalid) || showError;\n const ticked = new Set(value);\n // Resolved here rather than per box: a reason has to keep the fieldset from being\n // natively `disabled` too, or it would take every box out of the tab order — the\n // thing a reason exists to prevent.\n const reason = useCommitReason(commit, disabledReason);\n const locked = hasContent(reason);\n\n const toggle = (v: T, on: boolean) => {\n const next = new Set(value);\n if (on) next.add(v);\n else next.delete(v);\n const known = new Set(options.map((o) => o.value));\n onChange([\n ...options.map((o) => o.value).filter((x) => next.has(x)),\n // Values no option carries, kept in their own order — see `onChange`.\n ...value.filter((x) => !known.has(x)),\n ]);\n };\n\n return (\n <fieldset\n id={id}\n aria-label={ariaLabel}\n // With a help \"?\" inside the legend, the legend's WORDS name the group: a legend\n // names its fieldset by its whole content, the \"?\"'s \"About …\" included.\n aria-labelledby={helpMark !== undefined && ariaLabel === undefined ? legendTextId : undefined}\n aria-describedby={mergeDescribedBy(ariaDescribedBy, showHint && hintId, showError && errorId)}\n disabled={disabled && !locked}\n // `relative` holds an `sr-only` legend (sr-only-containment.test); `min-w-0`\n // undoes a fieldset's `min-width: min-content`, which would otherwise push a long\n // label past a phone's edge instead of wrapping it.\n className={cn(\"relative m-0 min-w-0 border-0 p-0\", className)}\n >\n {legend !== undefined && (\n <legend\n className={\n legendVisibility === \"sr-only\"\n ? \"sr-only\"\n : cn(\"mb-2 p-0 text-sm font-medium text-primary\", (disabled || locked) && \"opacity-60\")\n }\n >\n {helpMark === undefined ? legend : <span id={legendTextId}>{legend}</span>}\n {required && (\n <span aria-hidden className=\"ms-0.5 text-danger\">\n *\n </span>\n )}\n {helpMark !== undefined && <span className=\"ms-1 inline-flex align-middle font-normal\">{helpMark}</span>}\n </legend>\n )}\n <RequiredStarOnLegend.Provider value={true}>\n <div\n className={cn(layout === \"horizontal\" ? \"flex flex-wrap gap-x-4 gap-y-2\" : COLUMNS[columns], listClassName)}\n >\n {options.map((o) => (\n <Checkbox\n key={o.value}\n name={name}\n value={o.value}\n label={o.label}\n description={o.hint}\n checked={ticked.has(o.value)}\n onCheckedChange={(on) => toggle(o.value, on)}\n disabled={disabled || o.disabled}\n invalid={isInvalid || undefined}\n required={required && value.length === 0 ? true : undefined}\n disabledReason={reason}\n />\n ))}\n </div>\n </RequiredStarOnLegend.Provider>\n {showHint && (\n // A `div`, not a `p`: a hint may be a node with a link in it.\n <div id={hintId} className=\"mt-1.5 text-caption leading-tight text-muted\">\n {shownHint}\n </div>\n )}\n {showError && (\n <p id={errorId} className={FIELD_ERROR_CLASS}>\n {error}\n </p>\n )}\n </fieldset>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/checkbox-group.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { Checkbox } from \"./checkbox\";\nimport { hasContent } from \"../lib/presence\";\nimport { useCommitReason, type CommitScope } from \"./write-lock\";\nimport {\n FIELD_ERROR_CLASS,\n fieldHelpMark,\n mergeDescribedBy,\n RequiredStarOnLegend,\n useInlineHint,\n type FieldHelpProps,\n} from \"./field-parts\";\n\n/** One box of a {@link CheckboxGroup}. */\nexport interface CheckboxGroupOption<T extends string = string> {\n value: T;\n /** The words beside the box — its accessible name. */\n label: ReactNode;\n /** A line under the label (\"Imprint, Privacy Policy and Terms only\"), attached to the\n * box with `aria-describedby` — {@link Checkbox}'s `description`. */\n hint?: ReactNode;\n /** This box cannot be changed; the others can. */\n disabled?: boolean;\n}\n\n/** Whether the legend is drawn. `\"sr-only\"` keeps it as the group's name for a screen\n * reader where the dialog's title already says it to the eye. */\nexport type CheckboxGroupLegendVisibility = \"visible\" | \"sr-only\";\n\nexport interface CheckboxGroupProps<T extends string = string> extends FieldHelpProps {\n /** The question the boxes answer — the fieldset's `<legend>`, which names the group.\n * Without one, pass `aria-label`. */\n legend?: ReactNode;\n /** Default `\"visible\"`. */\n legendVisibility?: CheckboxGroupLegendVisibility;\n \"aria-label\"?: string;\n /** One box per option, in this order. */\n options: CheckboxGroupOption<T>[];\n /** The ticked values. Controlled. */\n value: T[];\n /**\n * The new set on every tick. In the ORDER OF `options`, not the order the boxes were\n * ticked, so a list saved from it does not change with the order someone clicked in\n * (ChoiceCardGroup's rule). A value in `value` that no option carries — a grant for a\n * locale the app no longer offers — is kept, after the known ones: a picker that\n * dropped what it could not show would delete it on the next unrelated tick.\n */\n onChange: (value: T[]) => void;\n /**\n * `\"vertical\"` (default): one box per line. `\"horizontal\"`: a wrapping row, for a few\n * short labels. With `columns`, vertical becomes a grid of that many columns from the\n * `sm` breakpoint up and stays one column on a phone — the reviewer dialog's shape.\n */\n layout?: \"vertical\" | \"horizontal\";\n /** Columns for a vertical group, from `sm` up (one on a phone). Default 1. */\n columns?: 1 | 2 | 3 | 4;\n /** Shared by every box — what a plain form submits the values under. */\n name?: string;\n /** Every box: the fieldset's own `disabled` (which disables them all natively), each\n * box faded as a disabled Checkbox is, and the legend with them. */\n disabled?: boolean;\n /**\n * At least one box must be ticked. Draws the required star after the legend, and puts\n * the native `required` on every box while NONE is ticked — so a form refuses an\n * empty set — and on none once one is (ChoiceCardGroup's rule: checkboxes cannot say\n * \"at least one\" natively).\n */\n required?: boolean;\n /**\n * Standing advice for the group, under the boxes, attached to the fieldset with\n * `aria-describedby` before the error — the field anatomy every kit field keeps.\n * A `help` beside it (0.36) is a \"?\" after the legend — with a visible legend only —\n * and names nothing: the fieldset is then named by the legend's words alone.\n */\n hint?: ReactNode;\n /** What is wrong with the set, in the caller's words. Under the boxes, on the\n * fieldset's `aria-describedby`, and paints every box invalid. */\n error?: ReactNode;\n /** Paints every box invalid without a message (the message lives elsewhere). */\n invalid?: boolean;\n /**\n * The group SAVES on change — each tick is written straight away (a reviewer's\n * per-locale grants). Under a locked {@link WriteLockProvider} every box is locked\n * the focusable way with the lock's reason. See {@link Checkbox}'s `commit`.\n */\n commit?: CommitScope;\n /** Why no box can be changed — every box gets it, and it wins over `disabled` (the\n * boxes stay focusable to say it). See {@link Checkbox}'s `disabledReason`. */\n disabledReason?: ReactNode;\n /** The fieldset's id. */\n id?: string;\n /** Classes for the fieldset — the outermost element, where layout belongs. */\n className?: string;\n /** Classes for the box list (the grid or the row). */\n listClassName?: string;\n /** Ids of something else on the page that describes the group; merged before the\n * group's own hint and error. */\n \"aria-describedby\"?: string;\n}\n\n// Literal class strings so Tailwind's scanner sees each one.\nconst COLUMNS: Record<NonNullable<CheckboxGroupProps[\"columns\"]>, string> = {\n 1: \"flex flex-col gap-2\",\n 2: \"grid grid-cols-1 gap-2 sm:grid-cols-2\",\n 3: \"grid grid-cols-1 gap-2 sm:grid-cols-3\",\n 4: \"grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-4\",\n};\n\n/**\n * A set of kit {@link Checkbox}es answering one question, in a `<fieldset>`.\n *\n * Kurvenschmiede's reviewer dialog (features/admin/reviewer-dialog.tsx) builds this by\n * hand — a fieldset, an `sr-only` legend, a grid of checkboxes, a `toggle(code, on)`\n * that adds or filters a `string[]` — and keksdose's and kastlan's reviewer grants build\n * the same picker for the same per-locale grant. The hand-built ones differ in the parts\n * that are easy to get wrong: whether the legend names the group, whether a hint or an\n * error is attached to anything, what order the saved list comes out in, and whether a\n * value the picker cannot show survives a tick.\n *\n * Every box is a kit {@link Checkbox}, so the native checkbox semantics stay (each box\n * submits under `name` in a plain form). The legend is the group's name; the hint and\n * error describe the fieldset. For a choice of ONE, use radios ({@link ChoiceCardGroup},\n * {@link ToggleGroup}).\n */\nexport function CheckboxGroup<T extends string = string>({\n legend,\n legendVisibility = \"visible\",\n \"aria-label\": ariaLabel,\n options,\n value,\n onChange,\n layout = \"vertical\",\n columns = 1,\n name,\n disabled,\n required,\n hint,\n help,\n error,\n invalid,\n commit,\n disabledReason,\n id,\n className,\n listClassName,\n \"aria-describedby\": ariaDescribedBy,\n}: CheckboxGroupProps<T>) {\n const generated = useId();\n const hintId = `${generated}-hint`;\n const errorId = `${generated}-error`;\n // §4: a FieldHint under the group is its words at Large and on a touch screen, not a\n // lone \"?\" (DUP-2, refactor audit 2026-10). A HelpPopover stays a \"?\".\n // A `help` \"?\" after a VISIBLE legend (0.36): the label line a group has. Its FieldHint\n // hint is then its words at every size, as everywhere a help stands beside one.\n const helpMark = fieldHelpMark(legend !== undefined && legendVisibility === \"visible\" ? help : undefined, legend);\n const legendTextId = `${generated}-legend`;\n const shownHint = useInlineHint(hint, helpMark !== undefined, legend);\n const showHint = hasContent(shownHint);\n const showError = hasContent(error);\n const isInvalid = Boolean(invalid) || showError;\n const ticked = new Set(value);\n // Resolved here rather than per box: a reason has to keep the fieldset from being\n // natively `disabled` too, or it would take every box out of the tab order — the\n // thing a reason exists to prevent.\n const reason = useCommitReason(commit, disabledReason);\n const locked = hasContent(reason);\n\n const toggle = (v: T, on: boolean) => {\n const next = new Set(value);\n if (on) next.add(v);\n else next.delete(v);\n const known = new Set(options.map((o) => o.value));\n onChange([\n ...options.map((o) => o.value).filter((x) => next.has(x)),\n // Values no option carries, kept in their own order — see `onChange`.\n ...value.filter((x) => !known.has(x)),\n ]);\n };\n\n return (\n <fieldset\n id={id}\n aria-label={ariaLabel}\n // With a help \"?\" inside the legend, the legend's WORDS name the group: a legend\n // names its fieldset by its whole content, the \"?\"'s \"About …\" included.\n aria-labelledby={helpMark !== undefined && ariaLabel === undefined ? legendTextId : undefined}\n aria-describedby={mergeDescribedBy(ariaDescribedBy, showHint && hintId, showError && errorId)}\n disabled={disabled && !locked}\n // `relative` holds an `sr-only` legend (sr-only-containment.test); `min-w-0`\n // undoes a fieldset's `min-width: min-content`, which would otherwise push a long\n // label past a phone's edge instead of wrapping it.\n className={cn(\"relative m-0 min-w-0 border-0 p-0\", className)}\n >\n {legend !== undefined && (\n <legend\n className={\n legendVisibility === \"sr-only\"\n ? \"sr-only\"\n : cn(\"mb-2 p-0 text-sm font-medium text-primary\", (disabled || locked) && \"opacity-60\")\n }\n >\n {helpMark === undefined ? legend : <span id={legendTextId}>{legend}</span>}\n {required && (\n <span aria-hidden className=\"ms-0.5 text-danger\">\n *\n </span>\n )}\n {helpMark !== undefined && <span className=\"ms-1 inline-flex align-middle font-normal\">{helpMark}</span>}\n </legend>\n )}\n <RequiredStarOnLegend.Provider value={true}>\n <div\n className={cn(layout === \"horizontal\" ? \"flex flex-wrap gap-x-4 gap-y-2\" : COLUMNS[columns], listClassName)}\n >\n {options.map((o) => (\n <Checkbox\n key={o.value}\n name={name}\n value={o.value}\n label={o.label}\n description={o.hint}\n checked={ticked.has(o.value)}\n onCheckedChange={(on) => toggle(o.value, on)}\n disabled={disabled || o.disabled}\n invalid={isInvalid || undefined}\n required={required && value.length === 0 ? true : undefined}\n disabledReason={reason}\n />\n ))}\n </div>\n </RequiredStarOnLegend.Provider>\n {showHint && (\n // A `div`, not a `p`: a hint may be a node with a link in it.\n <div id={hintId} className=\"mt-1.5 text-caption leading-tight text-muted\">\n {shownHint}\n </div>\n )}\n {showError && (\n <p id={errorId} className={FIELD_ERROR_CLASS}>\n {error}\n </p>\n )}\n </fieldset>\n );\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import { createPortal } from "react-dom";
5
5
  import { Check, Plus } from "lucide-react";
6
6
  import { cn } from "../lib/cn.js";
7
7
  import { CLIPS_ATTRIBUTE } from "../lib/clipping.js";
8
- import { tabStops } from "../lib/focus-left.js";
8
+ import { returnFocus, tabStops } from "../lib/focus-left.js";
9
9
  import { DropdownSearchHeader } from "./dropdown.js";
10
10
  import { PickerSheet, SHEET_ROW_CLASS } from "./picker-sheet.js";
11
11
  import { usePhoneLayout, useRemPx } from "../hooks/use-breakpoint.js";
@@ -118,8 +118,8 @@ function useComboboxCore({
118
118
  const [active, setActive] = useState(0);
119
119
  const close = () => setOpen(false);
120
120
  const closeToTrigger = () => {
121
+ returnFocus({ opener: triggerRef.current, closing: panelRef.current });
121
122
  setOpen(false);
122
- triggerRef.current?.focus();
123
123
  };
124
124
  const placement = useAnchoredPanel(triggerRef, open);
125
125
  const rect = placement.rect;
@@ -562,6 +562,7 @@ function ComboboxPanel({
562
562
  PickerSheet,
563
563
  {
564
564
  ...rest,
565
+ ref: panelRef,
565
566
  className,
566
567
  style,
567
568
  open: true,