@eifi1/ui-kit 0.51.7 → 0.52.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 (746) hide show
  1. package/README.md +141 -23
  2. package/dist/account/account-parts.d.ts +10 -8
  3. package/dist/account/account-parts.js +1 -18
  4. package/dist/account/account-parts.js.map +1 -1
  5. package/dist/account/data-export-setting-labels.js +1 -1
  6. package/dist/account/data-export-setting-labels.js.map +1 -1
  7. package/dist/account/delete-account-setting-labels.js +1 -1
  8. package/dist/account/delete-account-setting-labels.js.map +1 -1
  9. package/dist/account/email-change-setting-labels.js +1 -1
  10. package/dist/account/email-change-setting-labels.js.map +1 -1
  11. package/dist/account/passkeys-setting.d.ts +9 -2
  12. package/dist/account/passkeys-setting.js +41 -29
  13. package/dist/account/passkeys-setting.js.map +1 -1
  14. package/dist/account/sessions-setting.d.ts +3 -2
  15. package/dist/account/sessions-setting.js +10 -8
  16. package/dist/account/sessions-setting.js.map +1 -1
  17. package/dist/admin/admin-action-confirm.js +1 -3
  18. package/dist/admin/admin-action-confirm.js.map +1 -1
  19. package/dist/admin/admin-parts.d.ts +6 -3
  20. package/dist/admin/admin-parts.js +6 -21
  21. package/dist/admin/admin-parts.js.map +1 -1
  22. package/dist/admin/mail-test-card-labels.js +1 -1
  23. package/dist/admin/mail-test-card-labels.js.map +1 -1
  24. package/dist/admin/plan-change-labels.d.ts +2 -2
  25. package/dist/admin/plan-change-labels.js +1 -17
  26. package/dist/admin/plan-change-labels.js.map +1 -1
  27. package/dist/admin/plan-change.d.ts +3 -42
  28. package/dist/admin/plan-change.js +1 -1
  29. package/dist/admin/plan-change.js.map +1 -1
  30. package/dist/admin/reviewer-scope-editor.js +3 -3
  31. package/dist/admin/reviewer-scope-editor.js.map +1 -1
  32. package/dist/auth/auth-errors-labels.d.ts +11 -0
  33. package/dist/auth/auth-errors-labels.js +13 -0
  34. package/dist/auth/auth-errors-labels.js.map +1 -0
  35. package/dist/auth/auth-errors.d.ts +7 -23
  36. package/dist/auth/auth-errors.js +2 -15
  37. package/dist/auth/auth-errors.js.map +1 -1
  38. package/dist/auth/complete-name-dialog.js +2 -1
  39. package/dist/auth/complete-name-dialog.js.map +1 -1
  40. package/dist/auth/forgot-password-form-labels.js +1 -1
  41. package/dist/auth/forgot-password-form-labels.js.map +1 -1
  42. package/dist/auth/forgot-password-form.js +7 -2
  43. package/dist/auth/forgot-password-form.js.map +1 -1
  44. package/dist/auth/register-form-labels.js +1 -1
  45. package/dist/auth/register-form-labels.js.map +1 -1
  46. package/dist/auth/reset-password-form-labels.js +1 -1
  47. package/dist/auth/reset-password-form-labels.js.map +1 -1
  48. package/dist/auth/reset-password-form.js +5 -1
  49. package/dist/auth/reset-password-form.js.map +1 -1
  50. package/dist/auth/sign-in-form-labels.js +1 -1
  51. package/dist/auth/sign-in-form-labels.js.map +1 -1
  52. package/dist/auth/status-parts.d.ts +0 -3
  53. package/dist/auth/status-parts.js +0 -4
  54. package/dist/auth/status-parts.js.map +1 -1
  55. package/dist/auth/verify-email-labels.js +1 -1
  56. package/dist/auth/verify-email-labels.js.map +1 -1
  57. package/dist/auth/verify-email.js +7 -2
  58. package/dist/auth/verify-email.js.map +1 -1
  59. package/dist/billing/cancel-subscription.d.ts +20 -8
  60. package/dist/billing/cancel-subscription.js +7 -5
  61. package/dist/billing/cancel-subscription.js.map +1 -1
  62. package/dist/billing/dialog-close.d.ts +29 -0
  63. package/dist/billing/dialog-close.js +8 -0
  64. package/dist/billing/dialog-close.js.map +1 -0
  65. package/dist/billing/plan-card.d.ts +14 -4
  66. package/dist/billing/plan-card.js +15 -8
  67. package/dist/billing/plan-card.js.map +1 -1
  68. package/dist/billing/plan-change-labels.d.ts +42 -0
  69. package/dist/billing/plan-change-labels.js +22 -0
  70. package/dist/billing/plan-change-labels.js.map +1 -0
  71. package/dist/billing/plan-switch.d.ts +19 -7
  72. package/dist/billing/plan-switch.js +8 -4
  73. package/dist/billing/plan-switch.js.map +1 -1
  74. package/dist/chart.d.ts +12 -0
  75. package/dist/chart.js +16 -1
  76. package/dist/chart.js.map +1 -1
  77. package/dist/components/account-chips.d.ts +5 -5
  78. package/dist/components/account-chips.js +11 -13
  79. package/dist/components/account-chips.js.map +1 -1
  80. package/dist/components/alert-banner.d.ts +16 -5
  81. package/dist/components/alert-banner.js +46 -1
  82. package/dist/components/alert-banner.js.map +1 -1
  83. package/dist/components/amount-input.d.ts +13 -0
  84. package/dist/components/amount-input.js +1 -0
  85. package/dist/components/amount-input.js.map +1 -1
  86. package/dist/components/autocomplete.js +57 -65
  87. package/dist/components/autocomplete.js.map +1 -1
  88. package/dist/components/bulk-action-bar.d.ts +12 -2
  89. package/dist/components/bulk-action-bar.js +65 -21
  90. package/dist/components/bulk-action-bar.js.map +1 -1
  91. package/dist/components/button-look.d.ts +5 -5
  92. package/dist/components/button-look.js.map +1 -1
  93. package/dist/components/button.d.ts +2 -2
  94. package/dist/components/button.js.map +1 -1
  95. package/dist/components/chart-edge.d.ts +16 -0
  96. package/dist/components/chart-edge.js +14 -1
  97. package/dist/components/chart-edge.js.map +1 -1
  98. package/dist/components/chart-figure.d.ts +13 -0
  99. package/dist/components/chart-figure.js +15 -0
  100. package/dist/components/chart-figure.js.map +1 -0
  101. package/dist/components/chart-zoom-core.js +1 -4
  102. package/dist/components/chart-zoom-core.js.map +1 -1
  103. package/dist/components/chart.d.ts +8 -1
  104. package/dist/components/chart.js +19 -10
  105. package/dist/components/chart.js.map +1 -1
  106. package/dist/components/combobox-core.d.ts +111 -2
  107. package/dist/components/combobox-core.js +148 -42
  108. package/dist/components/combobox-core.js.map +1 -1
  109. package/dist/components/combobox.d.ts +1 -1
  110. package/dist/components/combobox.js +141 -130
  111. package/dist/components/combobox.js.map +1 -1
  112. package/dist/components/copy-button.d.ts +6 -5
  113. package/dist/components/copy-button.js +5 -3
  114. package/dist/components/copy-button.js.map +1 -1
  115. package/dist/components/country-select.js +2 -2
  116. package/dist/components/country-select.js.map +1 -1
  117. package/dist/components/data-table-column-settings.d.ts +1 -1
  118. package/dist/components/data-table-column-settings.js +33 -7
  119. package/dist/components/data-table-column-settings.js.map +1 -1
  120. package/dist/components/data-table-filters.d.ts +4 -2
  121. package/dist/components/data-table-filters.js +2 -2
  122. package/dist/components/data-table-filters.js.map +1 -1
  123. package/dist/components/data-table-fit.d.ts +6 -4
  124. package/dist/components/data-table-fit.js +4 -1
  125. package/dist/components/data-table-fit.js.map +1 -1
  126. package/dist/components/data-table-groups.d.ts +1 -1
  127. package/dist/components/data-table-groups.js.map +1 -1
  128. package/dist/components/data-table-head.d.ts +1 -1
  129. package/dist/components/data-table-head.js +15 -12
  130. package/dist/components/data-table-head.js.map +1 -1
  131. package/dist/components/data-table-mobile.d.ts +12 -7
  132. package/dist/components/data-table-mobile.js +43 -30
  133. package/dist/components/data-table-mobile.js.map +1 -1
  134. package/dist/components/data-table-pagination.js +11 -6
  135. package/dist/components/data-table-pagination.js.map +1 -1
  136. package/dist/components/data-table-resize.d.ts +1 -1
  137. package/dist/components/data-table-resize.js.map +1 -1
  138. package/dist/components/data-table-row-actions.d.ts +2 -2
  139. package/dist/components/data-table-row-actions.js.map +1 -1
  140. package/dist/components/data-table-row.d.ts +6 -2
  141. package/dist/components/data-table-row.js +17 -10
  142. package/dist/components/data-table-row.js.map +1 -1
  143. package/dist/components/data-table-selection.d.ts +1 -1
  144. package/dist/components/data-table-selection.js.map +1 -1
  145. package/dist/components/data-table-shared.d.ts +10 -2
  146. package/dist/components/data-table-shared.js +18 -0
  147. package/dist/components/data-table-shared.js.map +1 -1
  148. package/dist/components/data-table-sort.d.ts +21 -2
  149. package/dist/components/data-table-sort.js +24 -0
  150. package/dist/components/data-table-sort.js.map +1 -1
  151. package/dist/components/data-table-virtual.d.ts +1 -1
  152. package/dist/components/data-table-virtual.js +18 -6
  153. package/dist/components/data-table-virtual.js.map +1 -1
  154. package/dist/components/data-table.d.ts +13 -4
  155. package/dist/components/data-table.js +139 -36
  156. package/dist/components/data-table.js.map +1 -1
  157. package/dist/components/date-field.d.ts +24 -2
  158. package/dist/components/date-field.js +33 -8
  159. package/dist/components/date-field.js.map +1 -1
  160. package/dist/components/date-picker.d.ts +15 -2
  161. package/dist/components/date-picker.js +55 -26
  162. package/dist/components/date-picker.js.map +1 -1
  163. package/dist/components/date-range-picker.d.ts +47 -20
  164. package/dist/components/date-range-picker.js +23 -7
  165. package/dist/components/date-range-picker.js.map +1 -1
  166. package/dist/components/error-boundary.js +37 -30
  167. package/dist/components/error-boundary.js.map +1 -1
  168. package/dist/components/{ui-labels.d.ts → field-base-labels.d.ts} +0 -2
  169. package/dist/components/{ui-labels.js → field-base-labels.js} +2 -9
  170. package/dist/components/field-base-labels.js.map +1 -0
  171. package/dist/components/field-base.d.ts +4 -3
  172. package/dist/components/field-base.js +3 -3
  173. package/dist/components/field-base.js.map +1 -1
  174. package/dist/components/field-sync-labels.d.ts +1 -0
  175. package/dist/components/field-sync-labels.js.map +1 -1
  176. package/dist/components/field-sync.d.ts +23 -1
  177. package/dist/components/field-sync.js.map +1 -1
  178. package/dist/components/form-actions.js +11 -5
  179. package/dist/components/form-actions.js.map +1 -1
  180. package/dist/components/hover-menu.d.ts +3 -0
  181. package/dist/components/hover-menu.js +5 -3
  182. package/dist/components/hover-menu.js.map +1 -1
  183. package/dist/components/icon-button.js +14 -9
  184. package/dist/components/icon-button.js.map +1 -1
  185. package/dist/components/inline-confirm.d.ts +43 -0
  186. package/dist/components/inline-confirm.js +67 -0
  187. package/dist/components/inline-confirm.js.map +1 -0
  188. package/dist/components/inline-entity-combobox.d.ts +4 -3
  189. package/dist/components/inline-entity-combobox.js +148 -140
  190. package/dist/components/inline-entity-combobox.js.map +1 -1
  191. package/dist/components/input.js +1 -1
  192. package/dist/components/input.js.map +1 -1
  193. package/dist/components/jump-calendar.js +28 -112
  194. package/dist/components/jump-calendar.js.map +1 -1
  195. package/dist/components/legal-page.d.ts +3 -1
  196. package/dist/components/legal-page.js +3 -2
  197. package/dist/components/legal-page.js.map +1 -1
  198. package/dist/components/legal.d.ts +4 -2
  199. package/dist/components/legal.js.map +1 -1
  200. package/dist/components/lightbox.d.ts +2 -2
  201. package/dist/components/lightbox.js +17 -6
  202. package/dist/components/lightbox.js.map +1 -1
  203. package/dist/components/list.d.ts +6 -2
  204. package/dist/components/list.js +3 -2
  205. package/dist/components/list.js.map +1 -1
  206. package/dist/components/measured-grid.d.ts +1 -1
  207. package/dist/components/measured-grid.js +2 -1
  208. package/dist/components/measured-grid.js.map +1 -1
  209. package/dist/components/mini-calendar.js +3 -5
  210. package/dist/components/mini-calendar.js.map +1 -1
  211. package/dist/components/modal.js +3 -1
  212. package/dist/components/modal.js.map +1 -1
  213. package/dist/components/month-grid.d.ts +55 -0
  214. package/dist/components/month-grid.js +148 -0
  215. package/dist/components/month-grid.js.map +1 -0
  216. package/dist/components/month-picker.d.ts +36 -4
  217. package/dist/components/month-picker.js +123 -146
  218. package/dist/components/month-picker.js.map +1 -1
  219. package/dist/components/multi-select.d.ts +2 -2
  220. package/dist/components/multi-select.js +11 -6
  221. package/dist/components/multi-select.js.map +1 -1
  222. package/dist/components/picker-sheet.js +2 -1
  223. package/dist/components/picker-sheet.js.map +1 -1
  224. package/dist/components/pie-chart-labels.d.ts +7 -0
  225. package/dist/components/pie-chart-labels.js +1 -0
  226. package/dist/components/pie-chart-labels.js.map +1 -1
  227. package/dist/components/pie-chart.d.ts +5 -3
  228. package/dist/components/pie-chart.js +7 -22
  229. package/dist/components/pie-chart.js.map +1 -1
  230. package/dist/components/popover.d.ts +3 -0
  231. package/dist/components/popover.js +7 -1
  232. package/dist/components/popover.js.map +1 -1
  233. package/dist/components/row-actions.js +2 -1
  234. package/dist/components/row-actions.js.map +1 -1
  235. package/dist/components/section-nav.d.ts +7 -0
  236. package/dist/components/section-nav.js.map +1 -1
  237. package/dist/components/series-chart-axes.d.ts +3 -3
  238. package/dist/components/series-chart-axes.js.map +1 -1
  239. package/dist/components/series-chart-labels.d.ts +7 -4
  240. package/dist/components/series-chart-labels.js.map +1 -1
  241. package/dist/components/series-chart.d.ts +31 -7
  242. package/dist/components/series-chart.js +72 -29
  243. package/dist/components/series-chart.js.map +1 -1
  244. package/dist/components/share-card.js +3 -3
  245. package/dist/components/share-card.js.map +1 -1
  246. package/dist/components/sign-chip-labels.d.ts +1 -0
  247. package/dist/components/sign-chip-labels.js.map +1 -1
  248. package/dist/components/sign-chip.d.ts +10 -1
  249. package/dist/components/sign-chip.js.map +1 -1
  250. package/dist/components/tabs-labels.d.ts +2 -0
  251. package/dist/components/tabs-labels.js +11 -0
  252. package/dist/components/tabs-labels.js.map +1 -0
  253. package/dist/components/tabs.d.ts +1 -1
  254. package/dist/components/tabs.js +1 -1
  255. package/dist/components/tabs.js.map +1 -1
  256. package/dist/components/toggle-legend.d.ts +2 -2
  257. package/dist/components/toggle-legend.js +6 -6
  258. package/dist/components/toggle-legend.js.map +1 -1
  259. package/dist/components/translation-review-editor.d.ts +4 -2
  260. package/dist/components/translation-review-editor.js +2 -3
  261. package/dist/components/translation-review-editor.js.map +1 -1
  262. package/dist/components/translation-review.d.ts +2 -1
  263. package/dist/components/translation-review.js +2 -2
  264. package/dist/components/translation-review.js.map +1 -1
  265. package/dist/components/treemap-labels.d.ts +26 -0
  266. package/dist/components/treemap-labels.js +10 -0
  267. package/dist/components/treemap-labels.js.map +1 -0
  268. package/dist/components/treemap-layout.d.ts +62 -0
  269. package/dist/components/treemap-layout.js +126 -0
  270. package/dist/components/treemap-layout.js.map +1 -0
  271. package/dist/components/treemap.d.ts +140 -17
  272. package/dist/components/treemap.js +324 -97
  273. package/dist/components/treemap.js.map +1 -1
  274. package/dist/components/use-table-state.d.ts +5 -5
  275. package/dist/components/use-table-state.js +4 -1
  276. package/dist/components/use-table-state.js.map +1 -1
  277. package/dist/data-table.d.ts +6 -2
  278. package/dist/data-table.js +7 -2
  279. package/dist/data-table.js.map +1 -1
  280. package/dist/eslint/index.js +1 -1
  281. package/dist/eslint/role-utilities.d.ts +36 -7
  282. package/dist/eslint/role-utilities.js +42 -9
  283. package/dist/eslint/role-utilities.js.map +1 -1
  284. package/dist/feedback/feedback-dialog.d.ts +25 -16
  285. package/dist/feedback/feedback-dialog.js +6 -2
  286. package/dist/feedback/feedback-dialog.js.map +1 -1
  287. package/dist/feedback/feedback-mutation.d.ts +30 -0
  288. package/dist/feedback/feedback-mutation.js +16 -0
  289. package/dist/feedback/feedback-mutation.js.map +1 -0
  290. package/dist/feedback/feedback-page-link.d.ts +53 -0
  291. package/dist/feedback/feedback-page-link.js +37 -0
  292. package/dist/feedback/feedback-page-link.js.map +1 -0
  293. package/dist/feedback/feedback-public-list.d.ts +12 -3
  294. package/dist/feedback/feedback-public-list.js +2 -1
  295. package/dist/feedback/feedback-public-list.js.map +1 -1
  296. package/dist/feedback/feedback-replies.d.ts +3 -1
  297. package/dist/feedback/feedback-replies.js +5 -4
  298. package/dist/feedback/feedback-replies.js.map +1 -1
  299. package/dist/feedback/feedback-row-detail-labels.js +5 -0
  300. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  301. package/dist/feedback/feedback-row-detail.d.ts +64 -28
  302. package/dist/feedback/feedback-row-detail.js +30 -28
  303. package/dist/feedback/feedback-row-detail.js.map +1 -1
  304. package/dist/feedback/feedback-status-undo.d.ts +30 -11
  305. package/dist/feedback/feedback-status-undo.js +10 -15
  306. package/dist/feedback/feedback-status-undo.js.map +1 -1
  307. package/dist/feedback/feedback-submit-dialog.d.ts +1 -1
  308. package/dist/feedback/feedback-submit-dialog.js +1 -1
  309. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  310. package/dist/feedback/feedback-submit.js +9 -3
  311. package/dist/feedback/feedback-submit.js.map +1 -1
  312. package/dist/feedback/feedback-swipe.d.ts +1 -1
  313. package/dist/feedback/feedback-swipe.js.map +1 -1
  314. package/dist/feedback/feedback-table.d.ts +21 -9
  315. package/dist/feedback/feedback-table.js +45 -25
  316. package/dist/feedback/feedback-table.js.map +1 -1
  317. package/dist/feedback/feedback-thread-labels.d.ts +2 -2
  318. package/dist/feedback/feedback-thread-labels.js.map +1 -1
  319. package/dist/feedback/feedback-thread.d.ts +24 -23
  320. package/dist/feedback/feedback-thread.js +2 -1
  321. package/dist/feedback/feedback-thread.js.map +1 -1
  322. package/dist/feedback.d.ts +34 -0
  323. package/dist/feedback.js +42 -0
  324. package/dist/feedback.js.map +1 -1
  325. package/dist/hooks/use-focus-trap.d.ts +35 -0
  326. package/dist/hooks/use-focus-trap.js +6 -4
  327. package/dist/hooks/use-focus-trap.js.map +1 -1
  328. package/dist/hooks/use-hotkey.d.ts +5 -2
  329. package/dist/hooks/use-hotkey.js +5 -4
  330. package/dist/hooks/use-hotkey.js.map +1 -1
  331. package/dist/hooks/use-long-press.d.ts +7 -4
  332. package/dist/hooks/use-long-press.js +3 -0
  333. package/dist/hooks/use-long-press.js.map +1 -1
  334. package/dist/hooks/use-media-query.js +12 -4
  335. package/dist/hooks/use-media-query.js.map +1 -1
  336. package/dist/hooks/use-mounted.d.ts +22 -0
  337. package/dist/hooks/use-mounted.js +24 -0
  338. package/dist/hooks/use-mounted.js.map +1 -0
  339. package/dist/hooks/use-overlay-history.js +19 -3
  340. package/dist/hooks/use-overlay-history.js.map +1 -1
  341. package/dist/i18n/defaults.js +4 -5
  342. package/dist/i18n/defaults.js.map +1 -1
  343. package/dist/i18n/german.js +7 -1
  344. package/dist/i18n/german.js.map +1 -1
  345. package/dist/i18n/kit-labels.d.ts +9 -2
  346. package/dist/i18n/kit-labels.js.map +1 -1
  347. package/dist/i18n/locales/en.js +20 -41
  348. package/dist/i18n/locales/en.js.map +3 -3
  349. package/dist/i18n/locales/es.js +7 -1
  350. package/dist/i18n/locales/es.js.map +1 -1
  351. package/dist/i18n/locales/fr.js +20 -10
  352. package/dist/i18n/locales/fr.js.map +1 -1
  353. package/dist/i18n/locales/hu.js +9 -1
  354. package/dist/i18n/locales/hu.js.map +1 -1
  355. package/dist/i18n/locales/it.js +7 -1
  356. package/dist/i18n/locales/it.js.map +1 -1
  357. package/dist/i18n/locales/zh.js +8 -1
  358. package/dist/i18n/locales/zh.js.map +1 -1
  359. package/dist/i18n/review.js +5 -0
  360. package/dist/i18n/review.js.map +1 -1
  361. package/dist/index.d.ts +64 -17
  362. package/dist/index.js +77 -12
  363. package/dist/index.js.map +1 -1
  364. package/dist/landing/routing.d.ts +3 -1
  365. package/dist/landing/routing.js +4 -7
  366. package/dist/landing/routing.js.map +1 -1
  367. package/dist/lib/broadcast.d.ts +17 -0
  368. package/dist/lib/broadcast.js +30 -0
  369. package/dist/lib/broadcast.js.map +1 -0
  370. package/dist/lib/date-format.d.ts +37 -2
  371. package/dist/lib/date-format.js +34 -8
  372. package/dist/lib/date-format.js.map +1 -1
  373. package/dist/lib/day-format.d.ts +46 -0
  374. package/dist/lib/day-format.js +46 -0
  375. package/dist/lib/day-format.js.map +1 -0
  376. package/dist/lib/describe-failure.d.ts +14 -0
  377. package/dist/lib/describe-failure.js +9 -0
  378. package/dist/lib/describe-failure.js.map +1 -0
  379. package/dist/lib/direction.d.ts +16 -0
  380. package/dist/lib/direction.js +9 -1
  381. package/dist/lib/direction.js.map +1 -1
  382. package/dist/lib/focus-left.d.ts +63 -0
  383. package/dist/lib/focus-left.js +67 -0
  384. package/dist/lib/focus-left.js.map +1 -0
  385. package/dist/lib/format.js +5 -14
  386. package/dist/lib/format.js.map +1 -1
  387. package/dist/lib/http-status.d.ts +24 -0
  388. package/dist/lib/http-status.js +14 -0
  389. package/dist/lib/http-status.js.map +1 -0
  390. package/dist/lib/intl-cache.d.ts +14 -0
  391. package/dist/lib/intl-cache.js +15 -0
  392. package/dist/lib/intl-cache.js.map +1 -0
  393. package/dist/lib/isin.d.ts +10 -0
  394. package/dist/lib/isin.js.map +1 -1
  395. package/dist/lib/iso-day.d.ts +11 -0
  396. package/dist/lib/iso-day.js +8 -0
  397. package/dist/lib/iso-day.js.map +1 -0
  398. package/dist/lib/lazy-with-fallback.d.ts +31 -0
  399. package/dist/lib/lazy-with-fallback.js +40 -0
  400. package/dist/lib/lazy-with-fallback.js.map +1 -0
  401. package/dist/lib/path-pattern.d.ts +34 -0
  402. package/dist/lib/path-pattern.js +24 -0
  403. package/dist/lib/path-pattern.js.map +1 -0
  404. package/dist/lib/reduced-motion.d.ts +2 -1
  405. package/dist/lib/reduced-motion.js.map +1 -1
  406. package/dist/lib/round.d.ts +2 -1
  407. package/dist/lib/round.js +2 -1
  408. package/dist/lib/round.js.map +1 -1
  409. package/dist/lib/safe-storage.d.ts +24 -5
  410. package/dist/lib/safe-storage.js +27 -2
  411. package/dist/lib/safe-storage.js.map +1 -1
  412. package/dist/lib/session-refresh.js +1 -1
  413. package/dist/lib/session-refresh.js.map +1 -1
  414. package/dist/lib/share-format.d.ts +13 -0
  415. package/dist/lib/share-format.js +10 -0
  416. package/dist/lib/share-format.js.map +1 -0
  417. package/dist/lib/text-case.d.ts +17 -0
  418. package/dist/lib/text-case.js +8 -0
  419. package/dist/lib/text-case.js.map +1 -0
  420. package/dist/lib/text-match.d.ts +29 -0
  421. package/dist/lib/text-match.js +20 -2
  422. package/dist/lib/text-match.js.map +1 -1
  423. package/dist/lib/thenable.d.ts +13 -0
  424. package/dist/lib/thenable.js +8 -0
  425. package/dist/lib/thenable.js.map +1 -0
  426. package/dist/lib/translation-review.d.ts +7 -2
  427. package/dist/lib/translation-review.js +4 -4
  428. package/dist/lib/translation-review.js.map +1 -1
  429. package/dist/notifications/device-zone-report.js +1 -1
  430. package/dist/notifications/device-zone-report.js.map +1 -1
  431. package/dist/notifications/notification-bell.d.ts +2 -1
  432. package/dist/notifications/notification-bell.js +3 -3
  433. package/dist/notifications/notification-bell.js.map +1 -1
  434. package/dist/notifications/notification-inbox.d.ts +10 -6
  435. package/dist/notifications/notification-inbox.js +26 -48
  436. package/dist/notifications/notification-inbox.js.map +1 -1
  437. package/dist/notifications/notification-parts.d.ts +3 -2
  438. package/dist/notifications/notification-parts.js +1 -3
  439. package/dist/notifications/notification-parts.js.map +1 -1
  440. package/dist/notifications/notification-types-setting.js +1 -1
  441. package/dist/notifications/notification-types-setting.js.map +1 -1
  442. package/dist/notifications/notifications-labels.d.ts +6 -0
  443. package/dist/notifications/notifications-labels.js +1 -0
  444. package/dist/notifications/notifications-labels.js.map +1 -1
  445. package/dist/notifications/push-device-setting.js +1 -1
  446. package/dist/notifications/push-device-setting.js.map +1 -1
  447. package/dist/notifications/push-devices-setting.d.ts +2 -1
  448. package/dist/notifications/push-devices-setting.js +27 -49
  449. package/dist/notifications/push-devices-setting.js.map +1 -1
  450. package/dist/notifications/quiet-hours-setting.d.ts +10 -3
  451. package/dist/notifications/quiet-hours-setting.js +65 -26
  452. package/dist/notifications/quiet-hours-setting.js.map +1 -1
  453. package/dist/notifications/unsubscribe-panel.js +4 -7
  454. package/dist/notifications/unsubscribe-panel.js.map +1 -1
  455. package/dist/notifications/use-push-device.d.ts +39 -1
  456. package/dist/notifications/use-push-device.js +28 -7
  457. package/dist/notifications/use-push-device.js.map +1 -1
  458. package/dist/offline/query-persistence.d.ts +3 -1
  459. package/dist/offline/query-persistence.js +19 -2
  460. package/dist/offline/query-persistence.js.map +1 -1
  461. package/dist/rhf/fields.d.ts +11 -4
  462. package/dist/rhf/fields.js.map +1 -1
  463. package/dist/search/command-palette.js +1 -1
  464. package/dist/search/command-palette.js.map +1 -1
  465. package/dist/search/global-search.js +19 -9
  466. package/dist/search/global-search.js.map +1 -1
  467. package/dist/search/use-command-key.d.ts +12 -1
  468. package/dist/search/use-command-key.js +3 -12
  469. package/dist/search/use-command-key.js.map +1 -1
  470. package/dist/search.d.ts +7 -0
  471. package/dist/search.js +10 -0
  472. package/dist/search.js.map +1 -1
  473. package/dist/settings/use-settings-focus.js +1 -0
  474. package/dist/settings/use-settings-focus.js.map +1 -1
  475. package/dist/shell/account-menu-language.d.ts +21 -5
  476. package/dist/shell/account-menu-language.js +3 -1
  477. package/dist/shell/account-menu-language.js.map +1 -1
  478. package/dist/shell/account-menu-text-size.d.ts +26 -9
  479. package/dist/shell/account-menu-text-size.js +3 -2
  480. package/dist/shell/account-menu-text-size.js.map +1 -1
  481. package/dist/shell/dev-menu.js +5 -18
  482. package/dist/shell/dev-menu.js.map +1 -1
  483. package/dist/shell/role-switcher.d.ts +7 -0
  484. package/dist/shell/role-switcher.js.map +1 -1
  485. package/dist/shell/top-bar-actions.d.ts +1 -1
  486. package/dist/shell/top-bar-actions.js.map +1 -1
  487. package/dist/shell/top-bar-parts-labels.d.ts +0 -2
  488. package/dist/shell/top-bar-parts-labels.js +0 -1
  489. package/dist/shell/top-bar-parts-labels.js.map +1 -1
  490. package/dist/shell.d.ts +27 -8
  491. package/dist/shell.js +28 -7
  492. package/dist/shell.js.map +1 -1
  493. package/dist/sync/engine.d.ts +30 -4
  494. package/dist/sync/engine.js +172 -52
  495. package/dist/sync/engine.js.map +1 -1
  496. package/dist/sync.d.ts +6 -2
  497. package/dist/sync.js +6 -1
  498. package/dist/sync.js.map +1 -1
  499. package/dist/testing/css-variables.js +3 -8
  500. package/dist/testing/css-variables.js.map +1 -1
  501. package/dist/theme/contrast.d.ts +2 -1
  502. package/dist/theme/contrast.js +3 -8
  503. package/dist/theme/contrast.js.map +1 -1
  504. package/dist/theme/palette-store.js +6 -6
  505. package/dist/theme/palette-store.js.map +1 -1
  506. package/dist/theme/text-size.js +3 -8
  507. package/dist/theme/text-size.js.map +1 -1
  508. package/dist/theme/theme-store.js +3 -6
  509. package/dist/theme/theme-store.js.map +1 -1
  510. package/dist/tour/tour-catalogue.d.ts +7 -4
  511. package/dist/tour/tour-catalogue.js +12 -10
  512. package/dist/tour/tour-catalogue.js.map +1 -1
  513. package/dist/tour/tour-dock.d.ts +0 -2
  514. package/dist/tour/tour-dock.js +0 -2
  515. package/dist/tour/tour-dock.js.map +1 -1
  516. package/dist/tour/tour-gates.d.ts +4 -0
  517. package/dist/tour/tour-gates.js +14 -0
  518. package/dist/tour/tour-gates.js.map +1 -1
  519. package/dist/tour/tour-overlay.d.ts +27 -0
  520. package/dist/tour/tour-overlay.js +741 -0
  521. package/dist/tour/tour-overlay.js.map +1 -0
  522. package/dist/tour/tour.d.ts +13 -3
  523. package/dist/tour/tour.js +59 -781
  524. package/dist/tour/tour.js.map +1 -1
  525. package/dist/tour/use-tour-progress.js +1 -1
  526. package/dist/tour/use-tour-progress.js.map +1 -1
  527. package/dist/wizard/stepper-nav.d.ts +5 -1
  528. package/dist/wizard/stepper-nav.js.map +1 -1
  529. package/dist/wizard/types.d.ts +6 -2
  530. package/dist/wizard/types.js.map +1 -1
  531. package/dist/wizard/use-wizard.d.ts +3 -1
  532. package/dist/wizard/use-wizard.js.map +1 -1
  533. package/dist/wizard/validation.d.ts +3 -1
  534. package/dist/wizard/validation.js.map +1 -1
  535. package/package.json +10 -6
  536. package/src/account/account-parts.ts +5 -25
  537. package/src/account/data-export-setting-labels.ts +1 -1
  538. package/src/account/delete-account-setting-labels.ts +1 -1
  539. package/src/account/email-change-setting-labels.ts +1 -1
  540. package/src/account/passkeys-setting.tsx +60 -38
  541. package/src/account/sessions-setting.tsx +18 -12
  542. package/src/admin/admin-action-confirm.tsx +1 -5
  543. package/src/admin/admin-parts.ts +11 -25
  544. package/src/admin/mail-test-card-labels.ts +1 -1
  545. package/src/admin/plan-change-labels.ts +5 -23
  546. package/src/admin/plan-change.tsx +7 -44
  547. package/src/admin/reviewer-scope-editor.tsx +3 -3
  548. package/src/auth/auth-errors-labels.ts +23 -0
  549. package/src/auth/auth-errors.ts +11 -38
  550. package/src/auth/complete-name-dialog.tsx +4 -1
  551. package/src/auth/forgot-password-form-labels.ts +1 -1
  552. package/src/auth/forgot-password-form.tsx +11 -6
  553. package/src/auth/register-form-labels.ts +1 -1
  554. package/src/auth/reset-password-form-labels.ts +1 -1
  555. package/src/auth/reset-password-form.tsx +8 -4
  556. package/src/auth/sign-in-form-labels.ts +1 -1
  557. package/src/auth/status-parts.tsx +0 -6
  558. package/src/auth/verify-email-labels.ts +1 -1
  559. package/src/auth/verify-email.tsx +11 -6
  560. package/src/billing/cancel-subscription.tsx +26 -12
  561. package/src/billing/dialog-close.ts +34 -0
  562. package/src/billing/plan-card.tsx +36 -11
  563. package/src/billing/plan-change-labels.ts +66 -0
  564. package/src/billing/plan-switch.tsx +26 -12
  565. package/src/chart.ts +21 -3
  566. package/src/components/account-chips.tsx +20 -23
  567. package/src/components/alert-banner.tsx +82 -5
  568. package/src/components/amount-input.tsx +18 -7
  569. package/src/components/autocomplete.tsx +64 -70
  570. package/src/components/bulk-action-bar.tsx +70 -2
  571. package/src/components/button-look.ts +5 -5
  572. package/src/components/button.tsx +2 -2
  573. package/src/components/chart-edge.ts +34 -1
  574. package/src/components/chart-figure.tsx +35 -0
  575. package/src/components/chart-zoom-core.tsx +6 -5
  576. package/src/components/chart.tsx +26 -5
  577. package/src/components/combobox-core.tsx +293 -62
  578. package/src/components/combobox.tsx +183 -153
  579. package/src/components/copy-button.tsx +34 -23
  580. package/src/components/country-select.tsx +16 -11
  581. package/src/components/data-table-column-settings.tsx +52 -10
  582. package/src/components/data-table-filters.ts +6 -4
  583. package/src/components/data-table-fit.ts +19 -5
  584. package/src/components/data-table-groups.tsx +1 -1
  585. package/src/components/data-table-head.tsx +32 -22
  586. package/src/components/data-table-mobile.tsx +61 -26
  587. package/src/components/data-table-pagination.tsx +21 -6
  588. package/src/components/data-table-resize.ts +1 -1
  589. package/src/components/data-table-row-actions.tsx +3 -3
  590. package/src/components/data-table-row.tsx +25 -14
  591. package/src/components/data-table-selection.ts +1 -1
  592. package/src/components/data-table-shared.tsx +33 -1
  593. package/src/components/data-table-sort.ts +57 -2
  594. package/src/components/data-table-virtual.ts +32 -8
  595. package/src/components/data-table.tsx +239 -68
  596. package/src/components/date-field.tsx +65 -8
  597. package/src/components/date-picker.tsx +125 -48
  598. package/src/components/date-range-picker.tsx +82 -31
  599. package/src/components/error-boundary.tsx +53 -39
  600. package/src/components/field-base-labels.ts +20 -0
  601. package/src/components/field-base.tsx +13 -7
  602. package/src/components/field-sync-labels.ts +1 -0
  603. package/src/components/field-sync.tsx +23 -1
  604. package/src/components/form-actions.tsx +20 -5
  605. package/src/components/hover-menu.tsx +18 -8
  606. package/src/components/icon-button.tsx +14 -9
  607. package/src/components/inline-confirm.tsx +116 -0
  608. package/src/components/inline-entity-combobox.tsx +197 -153
  609. package/src/components/input.tsx +1 -1
  610. package/src/components/jump-calendar.tsx +30 -146
  611. package/src/components/legal-page.tsx +10 -7
  612. package/src/components/legal.tsx +4 -2
  613. package/src/components/lightbox.tsx +21 -8
  614. package/src/components/list.tsx +10 -4
  615. package/src/components/measured-grid.tsx +8 -4
  616. package/src/components/mini-calendar.tsx +6 -5
  617. package/src/components/modal.tsx +6 -1
  618. package/src/components/month-grid.tsx +229 -0
  619. package/src/components/month-picker.tsx +192 -200
  620. package/src/components/multi-select.tsx +21 -9
  621. package/src/components/picker-sheet.tsx +12 -9
  622. package/src/components/pie-chart-labels.ts +8 -0
  623. package/src/components/pie-chart.tsx +22 -28
  624. package/src/components/popover.tsx +18 -1
  625. package/src/components/row-actions.tsx +2 -1
  626. package/src/components/section-nav.tsx +7 -0
  627. package/src/components/series-chart-axes.ts +3 -3
  628. package/src/components/series-chart-labels.ts +7 -4
  629. package/src/components/series-chart.tsx +178 -69
  630. package/src/components/share-card.tsx +6 -6
  631. package/src/components/sign-chip-labels.ts +1 -0
  632. package/src/components/sign-chip.tsx +10 -1
  633. package/src/components/tabs-labels.ts +13 -0
  634. package/src/components/tabs.tsx +2 -2
  635. package/src/components/toggle-legend.tsx +16 -11
  636. package/src/components/translation-review-editor.tsx +6 -5
  637. package/src/components/translation-review.tsx +4 -3
  638. package/src/components/treemap-labels.ts +39 -0
  639. package/src/components/treemap-layout.ts +210 -0
  640. package/src/components/treemap.tsx +722 -133
  641. package/src/components/use-table-state.ts +12 -9
  642. package/src/data-table.ts +9 -2
  643. package/src/eslint/role-utilities.ts +97 -19
  644. package/src/feedback/feedback-dialog.tsx +30 -19
  645. package/src/feedback/feedback-mutation.ts +41 -0
  646. package/src/feedback/feedback-page-link.ts +90 -0
  647. package/src/feedback/feedback-public-list.tsx +17 -5
  648. package/src/feedback/feedback-replies.tsx +13 -6
  649. package/src/feedback/feedback-row-detail-labels.ts +5 -0
  650. package/src/feedback/feedback-row-detail.tsx +103 -67
  651. package/src/feedback/feedback-status-undo.ts +41 -27
  652. package/src/feedback/feedback-submit-dialog.tsx +2 -2
  653. package/src/feedback/feedback-submit.tsx +21 -7
  654. package/src/feedback/feedback-swipe.tsx +1 -1
  655. package/src/feedback/feedback-table.tsx +86 -38
  656. package/src/feedback/feedback-thread-labels.ts +2 -2
  657. package/src/feedback/feedback-thread.tsx +27 -25
  658. package/src/feedback.ts +42 -0
  659. package/src/hooks/use-focus-trap.ts +8 -24
  660. package/src/hooks/use-hotkey.ts +24 -7
  661. package/src/hooks/use-long-press.ts +16 -2
  662. package/src/hooks/use-media-query.ts +20 -4
  663. package/src/hooks/use-mounted.ts +39 -0
  664. package/src/hooks/use-overlay-history.ts +32 -3
  665. package/src/i18n/defaults.ts +4 -5
  666. package/src/i18n/german.ts +8 -2
  667. package/src/i18n/kit-labels.tsx +9 -2
  668. package/src/i18n/locales/es.ts +8 -2
  669. package/src/i18n/locales/fr.ts +21 -13
  670. package/src/i18n/locales/hu.ts +10 -2
  671. package/src/i18n/locales/it.ts +8 -2
  672. package/src/i18n/locales/zh.ts +9 -2
  673. package/src/i18n/review.ts +5 -0
  674. package/src/index.ts +103 -13
  675. package/src/landing/routing.tsx +14 -10
  676. package/src/lib/broadcast.ts +52 -0
  677. package/src/lib/date-format.ts +89 -13
  678. package/src/lib/day-format.ts +96 -0
  679. package/src/lib/describe-failure.ts +18 -0
  680. package/src/lib/direction.ts +39 -0
  681. package/src/lib/focus-left.ts +156 -0
  682. package/src/lib/format.ts +5 -17
  683. package/src/lib/http-status.ts +38 -0
  684. package/src/lib/intl-cache.ts +25 -0
  685. package/src/lib/isin.ts +10 -0
  686. package/src/lib/iso-day.ts +13 -0
  687. package/src/lib/lazy-with-fallback.ts +82 -0
  688. package/src/lib/path-pattern.ts +55 -0
  689. package/src/lib/reduced-motion.ts +2 -1
  690. package/src/lib/round.ts +7 -2
  691. package/src/lib/safe-storage.ts +48 -6
  692. package/src/lib/session-refresh.ts +1 -1
  693. package/src/lib/share-format.ts +18 -0
  694. package/src/lib/text-case.ts +19 -0
  695. package/src/lib/text-match.ts +57 -2
  696. package/src/lib/thenable.ts +19 -0
  697. package/src/lib/translation-review.ts +13 -5
  698. package/src/notifications/device-zone-report.ts +1 -1
  699. package/src/notifications/notification-bell.tsx +7 -4
  700. package/src/notifications/notification-inbox.tsx +40 -58
  701. package/src/notifications/notification-parts.tsx +3 -4
  702. package/src/notifications/notification-types-setting.tsx +1 -1
  703. package/src/notifications/notifications-labels.ts +7 -0
  704. package/src/notifications/push-device-setting.tsx +1 -1
  705. package/src/notifications/push-devices-setting.tsx +30 -55
  706. package/src/notifications/quiet-hours-setting.tsx +93 -31
  707. package/src/notifications/unsubscribe-panel.tsx +4 -7
  708. package/src/notifications/use-push-device.ts +76 -10
  709. package/src/offline/query-persistence.ts +35 -3
  710. package/src/rhf/fields.tsx +11 -4
  711. package/src/search/command-palette.tsx +2 -4
  712. package/src/search/global-search.tsx +36 -15
  713. package/src/search/use-command-key.ts +13 -12
  714. package/src/search.ts +9 -0
  715. package/src/settings/use-settings-focus.ts +3 -0
  716. package/src/shell/account-menu-language.tsx +27 -5
  717. package/src/shell/account-menu-text-size.tsx +32 -10
  718. package/src/shell/dev-menu.tsx +7 -21
  719. package/src/shell/role-switcher.tsx +7 -0
  720. package/src/shell/top-bar-actions.tsx +1 -1
  721. package/src/shell/top-bar-parts-labels.ts +0 -3
  722. package/src/shell.ts +40 -9
  723. package/src/sync/engine.ts +339 -61
  724. package/src/sync.ts +8 -1
  725. package/src/testing/css-variables.ts +8 -9
  726. package/src/theme/contrast.ts +8 -9
  727. package/src/theme/palette-store.ts +9 -9
  728. package/src/theme/text-size.ts +6 -8
  729. package/src/theme/theme-store.ts +7 -9
  730. package/src/tour/tour-catalogue.tsx +26 -15
  731. package/src/tour/tour-dock.ts +0 -2
  732. package/src/tour/tour-gates.ts +23 -0
  733. package/src/tour/tour-overlay.tsx +1170 -0
  734. package/src/tour/tour.tsx +108 -1202
  735. package/src/tour/use-tour-progress.ts +1 -1
  736. package/src/wizard/stepper-nav.tsx +3 -1
  737. package/src/wizard/types.ts +11 -2
  738. package/src/wizard/use-wizard.ts +2 -1
  739. package/src/wizard/validation.ts +8 -2
  740. package/tokens.css +2 -1
  741. package/dist/components/ui-labels.js.map +0 -1
  742. package/dist/shell/dev-switchers.d.ts +0 -6
  743. package/dist/shell/dev-switchers.js +0 -12
  744. package/dist/shell/dev-switchers.js.map +0 -1
  745. package/src/components/ui-labels.ts +0 -24
  746. package/src/shell/dev-switchers.tsx +0 -18
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/date-picker.tsx"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport { CalendarClock, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { addDaysIso } from \"../lib/dates\";\nimport { useKitLocale } from \"../i18n/kit-labels\";\nimport { splitTriggerAria } from \"./trigger-aria\";\nimport { FIELD_BASE } from \"./field-base\";\nimport { FieldBox, useFieldMessages } from \"./field-parts\";\nimport { Tooltip } from \"./tooltip\";\nimport { DateField, useDatePickerLabels, useTriggerFormat, withEndHint, type DatePickerBaseProps } from \"./date-field\";\nimport { PanelCalendar } from \"./jump-calendar\";\n// The shared field, the month-jump calendar and the range picker live in date-field.tsx,\n// jump-calendar.tsx and date-range-picker.tsx (MOD-9); their public names are still this\n// module's, so the barrel exports them as before.\nexport type { DateTriggerAttributes } from \"./date-field\";\nexport { DateRangePicker } from \"./date-range-picker\";\nexport type {\n DateRangeCommit,\n DateRangeDraftSummary,\n DateRangePickerPreset,\n DateRangePickerProps,\n DateRangeTriggerRenderProps,\n} from \"./date-range-picker\";\n\n/**\n * The ‹ date › (today) row on a phone at Large and Extra large (0.32.1, the 360 px\n * Extra-large sweep; docs/text-size-harmonization.md §4): the field takes the first line\n * on its own, whole and with all four corners, and the buttons share the line under it\n * as one joined strip. Three 2.5rem buttons are 180 px at 150 %, and on a 360 px phone\n * they left the field 84 px — \"Book… 0\" for \"Booking date 07/09/2026\" — where a 360 px\n * row would hold the date only by cutting it. `large:max-sm:`, the scaled phone width,\n * so a tablet or a desktop at Large keeps the one row, and Normal is unchanged.\n */\nconst STEP_ROW_STACK_AT_LARGE = cn(\n \"large:max-sm:flex-wrap large:max-sm:gap-y-2\",\n \"large:max-sm:[&>[data-slot=date-step-field]]:order-first large:max-sm:[&>[data-slot=date-step-field]]:basis-full\",\n \"large:max-sm:[&>[data-slot=date-step-field]]:ms-0 large:max-sm:[&_[role=combobox]]:rounded-md\",\n // The buttons (each in its tooltip's wrapper) share the line under the field.\n \"large:max-sm:[&>span]:flex-1 large:max-sm:[&>span>button]:w-full\",\n);\n\n// The focused part of the ‹ date › (today) row framed 2px wide, not 1 (keksdose live\n// #394, fourth round; kk K5). The row raises the focused part over the neighbour it\n// overlaps (`[&>*:focus-within]:z-20`), so all four of its sides are its own brand\n// border — but at a fractional device-pixel ratio a 1px line covers 1.25 device pixels\n// (at 125 %), and on whichever sides fall across a pixel boundary it is spread over two\n// pixels at partial strength: ‹'s left side and the date field's right read grey beside\n// the crisp ones (dark theme, measured: 82,87,146 against 139,147,248).\n//\n// A 1px INSET ring in the focus colour beside the 1px border doubles the line inward, so\n// every side keeps at least one fully covered device pixel at any scale — FIELD_INVALID's\n// border-plus-ring, for the same reason (live #295). A box-shadow, and inset: nothing\n// outside the part moves or is covered. `focus`, not `focus-visible`, as the row's\n// raise: a tap focuses too.\n//\n// 0.34 drew it here, on the parts — `focus:ring-1 focus:ring-inset` on each step and\n// `[&_[role=combobox]:focus]:…` from the row — and the K5 follow-up then moved that very\n// ring into FIELD_BASE for every field (keksdose run 78). Each part of this row is\n// FIELD_BASE, the steps directly and the trigger through FIELD_TRIGGER, so the copies went\n// (round 0.34 Wave 2). Not on every button in the row: keksdose's local fix\n// (`[&_button:focus]:ring-1 [&_button:focus]:ring-inset` on the row) also reached the\n// label's \"?\" and thinned its 2px focus frame to 1.\n\n/** One ‹ / › day-step button, sized to sit flush beside the field. */\nfunction StepButton({\n icon: Icon,\n label,\n disabled,\n onClick,\n mirror,\n className,\n}: {\n icon: ComponentType<{ className?: string }>;\n label: string;\n disabled: boolean;\n onClick: () => void;\n /** Flip the icon in RTL — for the ‹ › day steps, whose \"previous\" points to the\n * reading start. Not for the today icon, which has no direction. */\n mirror?: boolean;\n /** The button's corners in the joined group (see DatePicker). */\n className?: string;\n}) {\n return (\n <Tooltip label={label} portal>\n <button\n type=\"button\"\n aria-label={label}\n disabled={disabled}\n onClick={onClick}\n className={cn(\n FIELD_BASE,\n // FIELD_BASE is `block w-full` for text inputs; a step button is neither, and\n // px-3 would make it wider than it needs to be. twMerge lets these win.\n \"relative flex h-full w-10 shrink-0 items-center justify-center px-0 text-muted\",\n \"hover:bg-hover hover:text-secondary\",\n // Dimmed ICON, not a dimmed box: at 40% opacity the whole button — border\n // included — faded out of the group and read as a broken, detached control.\n \"disabled:cursor-not-allowed disabled:text-placeholder disabled:opacity-60 disabled:hover:bg-surface\",\n // A part of a joined row: FIELD_BASE's 2px focus line, whole at 125 % (K5, the\n // note above this function).\n className,\n )}\n >\n <Icon className={cn(\"size-4\", mirror && \"rtl:-scale-x-100\")} />\n </button>\n </Tooltip>\n );\n}\n\nexport interface DatePickerProps extends DatePickerBaseProps {\n /** ISO \"YYYY-MM-DD\", or \"\" for empty. */\n value: string;\n onChange: (iso: string) => void;\n /**\n * Flank the field with ‹ › buttons that move the value one day. For fields whose\n * typical edit is a day or two — opening a calendar to go \"yesterday\" is three\n * interactions for what should be one.\n *\n * Off by default: on a filter or a far-away date the buttons are dead weight, and\n * they cost ~5rem of width that a narrow layout may not have.\n */\n step?: boolean;\n /** Accessible names for the step buttons. Optional: they resolve from\n * `datePicker.previousDay` / `nextDay` in `<UiKitProvider labels>`, then from the\n * English defaults. This prop wins over both, for the one field that says it\n * differently. */\n stepLabels?: { prev: string; next: string };\n /**\n * Today's date as ISO \"YYYY-MM-DD\". Adds a jump-to-today button beside the field,\n * disabled once the value already is that day.\n *\n * Passed in rather than read from a clock here: a component that decides what \"today\"\n * is cannot be tested at a fixed date, and the consumer already has one definition of\n * it. The button is always RENDERED — going flat instead of disappearing — because a\n * control that comes and goes with the value reflows whatever sits beside it, which\n * is the report this exists to answer.\n */\n today?: string;\n /** Accessible name for the today button; wins over `datePicker.today`. */\n todayLabel?: string;\n}\n\n/** Single-date picker: a field showing the formatted date, opening a calendar. */\nexport function DatePicker(props: DatePickerProps) {\n const {\n value,\n onChange,\n locale: localeProp,\n placeholder,\n min,\n max,\n formatOptions,\n formatValue,\n step,\n stepLabels,\n today,\n todayLabel,\n className,\n calendarLabels,\n monthJump,\n label,\n clearable,\n clearLabel,\n disabled,\n invalid,\n hint,\n help,\n error,\n // Named so it reaches the field (and so its trigger) when a step/today row is the\n // root and takes the rest of the caller's props.\n \"aria-required\": ariaRequired,\n // The trigger's, wherever the rest go (API-3).\n ref,\n ...rest\n } = props;\n const locale = useKitLocale(localeProp);\n const text = useDatePickerLabels(clearLabel, stepLabels, todayLabel);\n const render = useTriggerFormat(\"datePicker\", locale, formatOptions, formatValue);\n // keksdose K4: the caption and the error under the field, attached to the TRIGGER\n // (the element a screen reader is on) after any description of the caller's own.\n const messages = useFieldMessages({\n hint,\n help,\n name: label ?? rest[\"aria-label\"],\n error,\n invalid,\n describedBy: rest[\"aria-describedby\"],\n ariaInvalid: rest[\"aria-invalid\"],\n });\n // With a step or a today button beside it the field is no longer the outermost\n // element — the flex row at the bottom is, and a caller's attributes belong on\n // whichever of the two is actually the root. Naming the shared props rather than\n // letting `...rest` carry them is what makes that choice possible.\n const wrapped = Boolean(step || today);\n const [triggerAria, wrapperRest] = splitTriggerAria(rest);\n const field = (\n <DateField\n // With step/today buttons the flex row is the root and takes the caller's props —\n // except the ones that name the field, which still belong on its trigger.\n {...(wrapped ? triggerAria : rest)}\n fieldRef={ref}\n aria-describedby={messages.describedBy}\n aria-required={ariaRequired}\n label={label}\n labelHint={messages.labelHint}\n clearable={clearable}\n clearLabel={text.clear}\n panelLabel={text.panel}\n disabled={disabled}\n invalid={messages.isInvalid}\n className={step ? \"min-w-0 flex-1\" : className}\n // Named for STEP_ROW_STACK_AT_LARGE; only in the row, so a caller's own\n // `data-slot` on a bare field is left alone.\n {...(wrapped ? { \"data-slot\": \"date-step-field\" } : {})}\n hasValue={Boolean(value)}\n triggerText={value ? render(value) : (placeholder ?? \"\")}\n onClear={() => onChange(\"\")}\n >\n {(close) => (\n <PanelCalendar\n monthJump={monthJump}\n mode=\"single\"\n focusOnOpen\n from={value}\n to={value}\n locale={locale}\n min={min}\n max={max}\n labels={calendarLabels}\n onSelect={(iso) => {\n onChange(iso);\n close();\n }}\n />\n )}\n </DateField>\n );\n // Passed at all — even as `undefined` — the field keeps its box; see FieldBox.\n const reserve = \"error\" in props || \"hint\" in props;\n const endHint = label === undefined ? messages.labelHint : undefined;\n if (!wrapped) {\n return (\n <FieldBox below={messages.below} reserve={reserve}>\n {withEndHint(field, endHint)}\n </FieldBox>\n );\n }\n\n // An empty field has nothing to step from, so both buttons are dead until a date\n // is picked. Bounds are compared as strings: \"YYYY-MM-DD\" sorts chronologically.\n const target = (days: number) => (value ? addDaysIso(value, days) : \"\");\n const outOfBounds = (iso: string) => Boolean((min && iso < min) || (max && iso > max));\n const blocked = (days: number) => {\n const next = target(days);\n if (!next || disabled) return true;\n return outOfBounds(next);\n };\n const row = (\n // ONE joined control, not three boxes in a row: the buttons and the field share\n // their borders (each piece overlaps the previous by a pixel) and only the outer\n // ends are rounded — the button-group shape, so ‹ date › reads as one field with\n // controls rather than a field with loose buttons parked beside it, which is what\n // the `gap-1` version looked like.\n //\n // items-stretch, not items-center: the buttons match the field's height, which\n // varies with whether it carries a floating label. The field's trigger is nested\n // inside DateField, so its inner corners are squared from here.\n <div\n {...wrapperRest}\n className={cn(\n \"flex items-stretch [&>*:not(:first-child)]:-ms-px\",\n step && \"[&_[role=combobox]]:rounded-s-none\",\n (step || today) && \"[&_[role=combobox]]:rounded-e-none\",\n // The PART that is focused, pressed or invalid is raised over the neighbour it\n // overlaps by a pixel, so its blue (or red) border shows on all four sides\n // (keksdose live #394). `:focus-within`, not `:focus-visible`: a tap focuses\n // without it, as does the sheet handing focus back, and the next part — later in\n // the DOM — painted its grey left edge over the tapped one's right. Raising the\n // whole part (each is `relative`) keeps the floating label and the icon above\n // the trigger, which raising the trigger alone covered. Hover raises nothing: it\n // changes no border, and would let a hovered › cover a focused field's edge.\n \"[&>*:focus-within]:z-20 [&>*:active]:z-20 [&>*:has([aria-invalid=true])]:z-10\",\n // …and its line is 2px, so no side of it reads half-strength at 125 % (live #394,\n // fourth round): FIELD_BASE's inset ring, which every part of the row carries.\n STEP_ROW_STACK_AT_LARGE,\n className,\n )}\n >\n {step && (\n <StepButton\n icon={ChevronLeft}\n mirror\n label={text.previousDay}\n disabled={blocked(-1)}\n onClick={() => onChange(target(-1))}\n className=\"rounded-e-none\"\n />\n )}\n {field}\n {step && (\n <StepButton\n icon={ChevronRight}\n mirror\n label={text.nextDay}\n disabled={blocked(1)}\n onClick={() => onChange(target(1))}\n className={cn(\"rounded-s-none\", today && \"rounded-e-none\")}\n />\n )}\n {today && (\n <StepButton\n icon={CalendarClock}\n label={text.today}\n disabled={Boolean(disabled) || value === today || outOfBounds(today)}\n onClick={() => onChange(today)}\n className=\"rounded-s-none\"\n />\n )}\n </div>\n );\n // Under the whole row, not under the field between the buttons: the message is about\n // the date, and the steppers are part of how it is entered.\n return (\n <FieldBox below={messages.below} reserve={reserve}>\n {withEndHint(row, endHint)}\n </FieldBox>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/date-picker.tsx"],"sourcesContent":["import type { ComponentType, ReactNode } from \"react\";\nimport { CalendarClock, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { addDaysIso } from \"../lib/dates\";\nimport { useKitLocale } from \"../i18n/kit-labels\";\nimport { splitTriggerAria } from \"./trigger-aria\";\nimport { FIELD_BASE } from \"./field-base\";\nimport { FieldBox, LockedReason, useFieldMessages, useLockReason } from \"./field-parts\";\nimport { Tooltip } from \"./tooltip\";\nimport type { CommitScope } from \"./write-lock\";\nimport { DateField, useDatePickerLabels, useTriggerFormat, withEndHint, type DatePickerBaseProps } from \"./date-field\";\nimport { PanelCalendar } from \"./jump-calendar\";\n// The shared field, the month-jump calendar and the range picker live in date-field.tsx,\n// jump-calendar.tsx and date-range-picker.tsx (MOD-9); their public names are still this\n// module's, so the barrel exports them as before.\nexport type { DateTriggerAttributes } from \"./date-field\";\nexport { DateRangePicker } from \"./date-range-picker\";\nexport type {\n DateRangeCommit,\n DateRangeDraftSummary,\n DateRangePickerPreset,\n DateRangePickerProps,\n DateRangeTriggerRenderProps,\n} from \"./date-range-picker\";\n\n/**\n * The ‹ date › (today) row on a phone at Large and Extra large (0.32.1, the 360 px\n * Extra-large sweep; docs/text-size-harmonization.md §4): the field takes the first line\n * on its own, whole and with all four corners, and the buttons share the line under it\n * as one joined strip. Three 2.5rem buttons are 180 px at 150 %, and on a 360 px phone\n * they left the field 84 px — \"Book… 0\" for \"Booking date 07/09/2026\" — where a 360 px\n * row would hold the date only by cutting it. `large:max-sm:`, the scaled phone width,\n * so a tablet or a desktop at Large keeps the one row, and Normal is unchanged.\n */\nconst STEP_ROW_STACK_AT_LARGE = cn(\n \"large:max-sm:flex-wrap large:max-sm:gap-y-2\",\n \"large:max-sm:[&>[data-slot=date-step-field]]:order-first large:max-sm:[&>[data-slot=date-step-field]]:basis-full\",\n \"large:max-sm:[&>[data-slot=date-step-field]]:ms-0 large:max-sm:[&_[role=combobox]]:rounded-md\",\n // The buttons (each in its tooltip's wrapper) share the line under the field.\n \"large:max-sm:[&>span]:flex-1 large:max-sm:[&>span>button]:w-full\",\n);\n\n// The focused part of the ‹ date › (today) row framed 2px wide, not 1 (keksdose live\n// #394, fourth round; kk K5). The row raises the focused part over the neighbour it\n// overlaps (`[&>*:focus-within]:z-20`), so all four of its sides are its own brand\n// border — but at a fractional device-pixel ratio a 1px line covers 1.25 device pixels\n// (at 125 %), and on whichever sides fall across a pixel boundary it is spread over two\n// pixels at partial strength: ‹'s left side and the date field's right read grey beside\n// the crisp ones (dark theme, measured: 82,87,146 against 139,147,248).\n//\n// A 1px INSET ring in the focus colour beside the 1px border doubles the line inward, so\n// every side keeps at least one fully covered device pixel at any scale — FIELD_INVALID's\n// border-plus-ring, for the same reason (live #295). A box-shadow, and inset: nothing\n// outside the part moves or is covered. `focus`, not `focus-visible`, as the row's\n// raise: a tap focuses too.\n//\n// 0.34 drew it here, on the parts — `focus:ring-1 focus:ring-inset` on each step and\n// `[&_[role=combobox]:focus]:…` from the row — and the K5 follow-up then moved that very\n// ring into FIELD_BASE for every field (keksdose run 78). Each part of this row is\n// FIELD_BASE, the steps directly and the trigger through FIELD_TRIGGER, so the copies went\n// (round 0.34 Wave 2). Not on every button in the row: keksdose's local fix\n// (`[&_button:focus]:ring-1 [&_button:focus]:ring-inset` on the row) also reached the\n// label's \"?\" and thinned its 2px focus frame to 1.\n\n/**\n * One ‹ / › day-step (or today) button, sized to sit flush beside the field.\n *\n * Two kinds of \"cannot\" (refactor audit 2026-10-30, INP-4). `off` is natively `disabled`,\n * out of the tab order: the field is `disabled`, or empty with nothing to step from — no\n * press of these buttons gets there, so the focus is never on one as it turns. `refused`\n * is `aria-disabled` with a click that does nothing, JumpCalendar's rule: › pressed onto\n * `max`, ‹ onto `min` and Today onto today are refused by the very press the focus is on,\n * and a focused button that turns `disabled` drops the focus to <body>, mid-form\n * (keksdose's shared date field passes `step` and `today` in 14 files). A lock refuses\n * too, and the lock's reason describes the button.\n */\nfunction StepButton({\n icon: Icon,\n label,\n off,\n refused,\n reasonId,\n onClick,\n mirror,\n className,\n}: {\n icon: ComponentType<{ className?: string }>;\n label: string;\n off: boolean;\n refused: boolean;\n /** While locked: the id of the lock's reason, which the row's frame shows. */\n reasonId?: string;\n onClick: () => void;\n /** Flip the icon in RTL — for the ‹ › day steps, whose \"previous\" points to the\n * reading start. Not for the today icon, which has no direction. */\n mirror?: boolean;\n /** The button's corners in the joined group (see DatePicker). */\n className?: string;\n}) {\n const button = (\n <button\n type=\"button\"\n aria-label={label}\n disabled={off}\n aria-disabled={(!off && refused) || undefined}\n aria-describedby={reasonId}\n onClick={() => {\n if (!refused) onClick();\n }}\n className={cn(\n FIELD_BASE,\n // FIELD_BASE is `block w-full` for text inputs; a step button is neither, and\n // px-3 would make it wider than it needs to be. twMerge lets these win.\n \"relative flex h-full w-10 shrink-0 items-center justify-center px-0 text-muted\",\n \"hover:bg-hover hover:text-secondary\",\n // Dimmed ICON, not a dimmed box: at 40% opacity the whole button — border\n // included — faded out of the group and read as a broken, detached control. The\n // same look for the focusable kind (INP-4).\n \"disabled:cursor-not-allowed disabled:text-placeholder disabled:opacity-60 disabled:hover:bg-surface\",\n \"aria-disabled:cursor-not-allowed aria-disabled:text-placeholder aria-disabled:opacity-60 aria-disabled:hover:bg-surface\",\n // A part of a joined row: FIELD_BASE's 2px focus line, whole at 125 % (K5, the\n // note above this function).\n className,\n )}\n >\n <Icon className={cn(\"size-4\", mirror && \"rtl:-scale-x-100\")} />\n </button>\n );\n // Locked, the row's frame holds the reason's bubble; a name bubble of its own as well\n // would be two on one hover (IconButton drops its own the same way). The wrapper stays\n // — STEP_ROW_STACK_AT_LARGE lays the buttons out by it.\n if (reasonId) return <span className=\"relative inline-flex\">{button}</span>;\n return (\n <Tooltip label={label} portal>\n {button}\n </Tooltip>\n );\n}\n\nexport interface DatePickerProps extends DatePickerBaseProps {\n /** ISO \"YYYY-MM-DD\", or \"\" for empty. */\n value: string;\n onChange: (iso: string) => void;\n /**\n * Flank the field with ‹ › buttons that move the value one day. For fields whose\n * typical edit is a day or two — opening a calendar to go \"yesterday\" is three\n * interactions for what should be one. A button whose day is outside `min` / `max` is\n * refused (`aria-disabled`, still focusable — 0.52); with no value both are disabled.\n *\n * Off by default: on a filter or a far-away date the buttons are dead weight, and\n * they cost ~5rem of width that a narrow layout may not have.\n */\n step?: boolean;\n /** Accessible names for the step buttons. Optional: they resolve from\n * `datePicker.previousDay` / `nextDay` in `<UiKitProvider labels>`, then from the\n * English defaults. This prop wins over both, for the one field that says it\n * differently. */\n stepLabels?: { prev: string; next: string };\n /**\n * Today's date as ISO \"YYYY-MM-DD\". Adds a jump-to-today button beside the field,\n * refused once the value already is that day — `aria-disabled`, so the focus stays on\n * the button that was just pressed (0.52) — and disabled while that day is outside\n * `min` / `max`.\n *\n * Passed in rather than read from a clock here: a component that decides what \"today\"\n * is cannot be tested at a fixed date, and the consumer already has one definition of\n * it. The button is always RENDERED — going flat instead of disappearing — because a\n * control that comes and goes with the value reflows whatever sits beside it, which\n * is the report this exists to answer.\n */\n today?: string;\n /** Accessible name for the today button; wins over `datePicker.today`. */\n todayLabel?: string;\n /**\n * This picker COMMITS — picking a date saves it (a row's date edited in place, a\n * filter kept as it moves). Under a locked {@link WriteLockProvider} it is locked the\n * `disabledReason` way, with the lock's reason; a {@link CommitScope}, as on every kit\n * control. A date field inside a form with its own Save stays editable under the lock —\n * leave this off there, and put `commit` on the Save. 0.52 (refactor audit 2026-10-30,\n * API-3).\n */\n commit?: CommitScope;\n}\n\n/** Single-date picker: a field showing the formatted date, opening a calendar. */\nexport function DatePicker(props: DatePickerProps) {\n const {\n value,\n onChange,\n locale: localeProp,\n placeholder,\n min,\n max,\n formatOptions,\n formatValue,\n step,\n stepLabels,\n today,\n todayLabel,\n className,\n calendarLabels,\n monthJump,\n label,\n clearable,\n clearLabel,\n disabled,\n disabledReason,\n disabledReasonDisplay,\n commit,\n invalid,\n hint,\n help,\n error,\n // Named so it reaches the field (and so its trigger) when a step/today row is the\n // root and takes the rest of the caller's props.\n \"aria-required\": ariaRequired,\n // The trigger's, wherever the rest go (API-3).\n ref,\n ...rest\n } = props;\n const locale = useKitLocale(localeProp);\n const text = useDatePickerLabels(clearLabel, stepLabels, todayLabel);\n const render = useTriggerFormat(\"datePicker\", locale, formatOptions, formatValue);\n // The write lock (API-3): Select's — the trigger stays reachable and says why.\n const lock = useLockReason(commit, disabledReason);\n const locked = lock.locked;\n const change = (iso: string) => {\n if (!locked) onChange(iso);\n };\n // keksdose K4: the caption and the error under the field, attached to the TRIGGER\n // (the element a screen reader is on) after any description of the caller's own; a\n // lock's reason between the two, as on Select.\n const messages = useFieldMessages({\n hint,\n help,\n name: label ?? rest[\"aria-label\"],\n error,\n invalid,\n describedBy: rest[\"aria-describedby\"],\n ariaInvalid: rest[\"aria-invalid\"],\n reasonId: locked && lock.reasonId,\n });\n // With a step or a today button beside it the field is no longer the outermost\n // element — the flex row at the bottom is, and a caller's attributes belong on\n // whichever of the two is actually the root. Naming the shared props rather than\n // letting `...rest` carry them is what makes that choice possible.\n const wrapped = Boolean(step || today);\n const [triggerAria, wrapperRest] = splitTriggerAria(rest);\n const field = (\n <DateField\n // With step/today buttons the flex row is the root and takes the caller's props —\n // except the ones that name the field, which still belong on its trigger.\n {...(wrapped ? triggerAria : rest)}\n fieldRef={ref}\n aria-describedby={messages.describedBy}\n aria-required={ariaRequired}\n label={label}\n labelHint={messages.labelHint}\n clearable={clearable}\n clearLabel={text.clear}\n panelLabel={text.panel}\n disabled={disabled}\n locked={locked}\n invalid={messages.isInvalid}\n // In the row, the field fills what the buttons leave and the caller's classes are\n // the row's — with `today` alone too: dressed on `step` alone, a today-only row put\n // them on both (refactor audit 2026-10-30, INP-13). Locked, they are the frame's.\n className={wrapped ? \"min-w-0 flex-1\" : locked ? undefined : className}\n // Named for STEP_ROW_STACK_AT_LARGE; only in the row, so a caller's own\n // `data-slot` on a bare field is left alone.\n {...(wrapped ? { \"data-slot\": \"date-step-field\" } : {})}\n hasValue={Boolean(value)}\n triggerText={value ? render(value) : (placeholder ?? \"\")}\n onClear={() => change(\"\")}\n >\n {(close) => (\n <PanelCalendar\n monthJump={monthJump}\n mode=\"single\"\n focusOnOpen\n from={value}\n to={value}\n locale={locale}\n min={min}\n max={max}\n labels={calendarLabels}\n onSelect={(iso) => {\n change(iso);\n close();\n }}\n />\n )}\n </DateField>\n );\n // Passed at all — even as `undefined` — the field keeps its box; see FieldBox.\n const reserve = \"error\" in props || \"hint\" in props;\n const endHint = label === undefined ? messages.labelHint : undefined;\n // Locked, the field — or the whole row, whose buttons change the value too — sits in\n // the reason's frame (the line, or the Tooltip), which becomes the outermost box: the\n // caller's classes move onto it, as on Select, so a lock does not reflow the form.\n const withReason = (box: ReactNode) =>\n locked ? (\n <LockedReason lock={lock} display={disabledReasonDisplay} className={cn(\"block\", className)}>\n {box}\n </LockedReason>\n ) : (\n box\n );\n if (!wrapped) {\n return (\n <FieldBox below={messages.below} reserve={reserve}>\n {withReason(withEndHint(field, endHint))}\n </FieldBox>\n );\n }\n\n // An empty field has nothing to step from, so both buttons are off until a date is\n // picked. Bounds are compared as strings: \"YYYY-MM-DD\" sorts chronologically.\n const target = (days: number) => (value ? addDaysIso(value, days) : \"\");\n const outOfBounds = (iso: string) => Boolean((min && iso < min) || (max && iso > max));\n // A lock's reason wins over `disabled`, as on Select: the buttons stay focusable then.\n const fieldOff = Boolean(disabled) && !locked;\n const reasonId = locked ? lock.reasonId : undefined;\n const row = (\n // ONE joined control, not three boxes in a row: the buttons and the field share\n // their borders (each piece overlaps the previous by a pixel) and only the outer\n // ends are rounded — the button-group shape, so ‹ date › reads as one field with\n // controls rather than a field with loose buttons parked beside it, which is what\n // the `gap-1` version looked like.\n //\n // items-stretch, not items-center: the buttons match the field's height, which\n // varies with whether it carries a floating label. The field's trigger is nested\n // inside DateField, so its inner corners are squared from here.\n <div\n {...wrapperRest}\n className={cn(\n \"flex items-stretch [&>*:not(:first-child)]:-ms-px\",\n step && \"[&_[role=combobox]]:rounded-s-none\",\n (step || today) && \"[&_[role=combobox]]:rounded-e-none\",\n // The PART that is focused, pressed or invalid is raised over the neighbour it\n // overlaps by a pixel, so its blue (or red) border shows on all four sides\n // (keksdose live #394). `:focus-within`, not `:focus-visible`: a tap focuses\n // without it, as does the sheet handing focus back, and the next part — later in\n // the DOM — painted its grey left edge over the tapped one's right. Raising the\n // whole part (each is `relative`) keeps the floating label and the icon above\n // the trigger, which raising the trigger alone covered. Hover raises nothing: it\n // changes no border, and would let a hovered › cover a focused field's edge.\n \"[&>*:focus-within]:z-20 [&>*:active]:z-20 [&>*:has([aria-invalid=true])]:z-10\",\n // …and its line is 2px, so no side of it reads half-strength at 125 % (live #394,\n // fourth round): FIELD_BASE's inset ring, which every part of the row carries.\n STEP_ROW_STACK_AT_LARGE,\n !locked && className,\n )}\n >\n {step && (\n <StepButton\n icon={ChevronLeft}\n mirror\n label={text.previousDay}\n off={fieldOff || !value}\n refused={locked || outOfBounds(target(-1))}\n reasonId={reasonId}\n onClick={() => change(target(-1))}\n className=\"rounded-e-none\"\n />\n )}\n {field}\n {step && (\n <StepButton\n icon={ChevronRight}\n mirror\n label={text.nextDay}\n off={fieldOff || !value}\n refused={locked || outOfBounds(target(1))}\n reasonId={reasonId}\n onClick={() => change(target(1))}\n className={cn(\"rounded-s-none\", today && \"rounded-e-none\")}\n />\n )}\n {today && (\n // Refused once the value is today: pressable as a no-op would keep the focus too\n // (INP-4), and this also says there is nothing to jump to. Today outside the\n // bounds is `off`: no press here gets there, as MonthPicker's stepper has it — it\n // was refused, a tab stop that could never do anything (0.52 code review,\n // date-picker.tsx). A lock wins, focusable, to say why.\n <StepButton\n icon={CalendarClock}\n label={text.today}\n off={fieldOff || (!locked && outOfBounds(today))}\n refused={locked || value === today}\n reasonId={reasonId}\n onClick={() => change(today)}\n className=\"rounded-s-none\"\n />\n )}\n </div>\n );\n // Under the whole row, not under the field between the buttons: the message is about\n // the date, and the steppers are part of how it is entered.\n return (\n <FieldBox below={messages.below} reserve={reserve}>\n {withReason(withEndHint(row, endHint))}\n </FieldBox>\n );\n}\n"],"mappings":";AA6HM,cAgNF,YAhNE;AA5HN,SAAS,eAAe,aAAa,oBAAoB;AACzD,SAAS,UAAU;AACnB,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAC3B,SAAS,UAAU,cAAc,kBAAkB,qBAAqB;AACxE,SAAS,eAAe;AAExB,SAAS,WAAW,qBAAqB,kBAAkB,mBAA6C;AACxG,SAAS,qBAAqB;AAK9B,SAAS,uBAAuB;AAkBhC,MAAM,0BAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF;AAoCA,SAAS,WAAW;AAAA,EAClB,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAaG;AACD,QAAM,SACJ;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,UAAU;AAAA,MACV,iBAAgB,CAAC,OAAO,WAAY;AAAA,MACpC,oBAAkB;AAAA,MAClB,SAAS,MAAM;AACb,YAAI,CAAC,QAAS,SAAQ;AAAA,MACxB;AAAA,MACA,WAAW;AAAA,QACT;AAAA;AAAA;AAAA,QAGA;AAAA,QACA;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,QACA;AAAA;AAAA;AAAA,QAGA;AAAA,MACF;AAAA,MAEA,8BAAC,QAAK,WAAW,GAAG,UAAU,UAAU,kBAAkB,GAAG;AAAA;AAAA,EAC/D;AAKF,MAAI,SAAU,QAAO,oBAAC,UAAK,WAAU,wBAAwB,kBAAO;AACpE,SACE,oBAAC,WAAQ,OAAc,QAAM,MAC1B,kBACH;AAEJ;AAgDO,SAAS,WAAW,OAAwB;AACjD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,iBAAiB;AAAA;AAAA,IAEjB;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,SAAS,aAAa,UAAU;AACtC,QAAM,OAAO,oBAAoB,YAAY,YAAY,UAAU;AACnE,QAAM,SAAS,iBAAiB,cAAc,QAAQ,eAAe,WAAW;AAEhF,QAAM,OAAO,cAAc,QAAQ,cAAc;AACjD,QAAM,SAAS,KAAK;AACpB,QAAM,SAAS,CAAC,QAAgB;AAC9B,QAAI,CAAC,OAAQ,UAAS,GAAG;AAAA,EAC3B;AAIA,QAAM,WAAW,iBAAiB;AAAA,IAChC;AAAA,IACA;AAAA,IACA,MAAM,SAAS,KAAK,YAAY;AAAA,IAChC;AAAA,IACA;AAAA,IACA,aAAa,KAAK,kBAAkB;AAAA,IACpC,aAAa,KAAK,cAAc;AAAA,IAChC,UAAU,UAAU,KAAK;AAAA,EAC3B,CAAC;AAKD,QAAM,UAAU,QAAQ,QAAQ,KAAK;AACrC,QAAM,CAAC,aAAa,WAAW,IAAI,iBAAiB,IAAI;AACxD,QAAM,QACJ;AAAA,IAAC;AAAA;AAAA,MAGE,GAAI,UAAU,cAAc;AAAA,MAC7B,UAAU;AAAA,MACV,oBAAkB,SAAS;AAAA,MAC3B,iBAAe;AAAA,MACf;AAAA,MACA,WAAW,SAAS;AAAA,MACpB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK;AAAA,MACjB;AAAA,MACA;AAAA,MACA,SAAS,SAAS;AAAA,MAIlB,WAAW,UAAU,mBAAmB,SAAS,SAAY;AAAA,MAG5D,GAAI,UAAU,EAAE,aAAa,kBAAkB,IAAI,CAAC;AAAA,MACrD,UAAU,QAAQ,KAAK;AAAA,MACvB,aAAa,QAAQ,OAAO,KAAK,IAAK,eAAe;AAAA,MACrD,SAAS,MAAM,OAAO,EAAE;AAAA,MAEvB,WAAC,UACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,MAAK;AAAA,UACL,aAAW;AAAA,UACX,MAAM;AAAA,UACN,IAAI;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,UAAU,CAAC,QAAQ;AACjB,mBAAO,GAAG;AACV,kBAAM;AAAA,UACR;AAAA;AAAA,MACF;AAAA;AAAA,EAEJ;AAGF,QAAM,UAAU,WAAW,SAAS,UAAU;AAC9C,QAAM,UAAU,UAAU,SAAY,SAAS,YAAY;AAI3D,QAAM,aAAa,CAAC,QAClB,SACE,oBAAC,gBAAa,MAAY,SAAS,uBAAuB,WAAW,GAAG,SAAS,SAAS,GACvF,eACH,IAEA;AAEJ,MAAI,CAAC,SAAS;AACZ,WACE,oBAAC,YAAS,OAAO,SAAS,OAAO,SAC9B,qBAAW,YAAY,OAAO,OAAO,CAAC,GACzC;AAAA,EAEJ;AAIA,QAAM,SAAS,CAAC,SAAkB,QAAQ,WAAW,OAAO,IAAI,IAAI;AACpE,QAAM,cAAc,CAAC,QAAgB,QAAS,OAAO,MAAM,OAAS,OAAO,MAAM,GAAI;AAErF,QAAM,WAAW,QAAQ,QAAQ,KAAK,CAAC;AACvC,QAAM,WAAW,SAAS,KAAK,WAAW;AAC1C,QAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUJ;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW;AAAA,UACT;AAAA,UACA,QAAQ;AAAA,WACP,QAAQ,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UASnB;AAAA;AAAA;AAAA,UAGA;AAAA,UACA,CAAC,UAAU;AAAA,QACb;AAAA,QAEC;AAAA,kBACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,QAAM;AAAA,cACN,OAAO,KAAK;AAAA,cACZ,KAAK,YAAY,CAAC;AAAA,cAClB,SAAS,UAAU,YAAY,OAAO,EAAE,CAAC;AAAA,cACzC;AAAA,cACA,SAAS,MAAM,OAAO,OAAO,EAAE,CAAC;AAAA,cAChC,WAAU;AAAA;AAAA,UACZ;AAAA,UAED;AAAA,UACA,QACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,QAAM;AAAA,cACN,OAAO,KAAK;AAAA,cACZ,KAAK,YAAY,CAAC;AAAA,cAClB,SAAS,UAAU,YAAY,OAAO,CAAC,CAAC;AAAA,cACxC;AAAA,cACA,SAAS,MAAM,OAAO,OAAO,CAAC,CAAC;AAAA,cAC/B,WAAW,GAAG,kBAAkB,SAAS,gBAAgB;AAAA;AAAA,UAC3D;AAAA,UAED;AAAA;AAAA;AAAA;AAAA;AAAA,UAMC;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,OAAO,KAAK;AAAA,cACZ,KAAK,YAAa,CAAC,UAAU,YAAY,KAAK;AAAA,cAC9C,SAAS,UAAU,UAAU;AAAA,cAC7B;AAAA,cACA,SAAS,MAAM,OAAO,KAAK;AAAA,cAC3B,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,IAEJ;AAAA;AAIF,SACE,oBAAC,YAAS,OAAO,SAAS,OAAO,SAC9B,qBAAW,YAAY,KAAK,OAAO,CAAC,GACvC;AAEJ;","names":[]}
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
+ import type { CommitScope } from "./write-lock.js";
2
3
  import { type DatePickerBaseProps, type DateTriggerAttributes } from "./date-field.js";
3
4
  export interface DateRangePickerPreset {
4
5
  /**
@@ -20,19 +21,13 @@ export interface DateRangePickerPreset {
20
21
  to: string;
21
22
  }
22
23
  /**
23
- * When the picker hands its range to `onChange`.
24
+ * The 0.x values of DateRangePicker's `commit`, when it was the panel's mode:
25
+ * `"immediate"` is `apply` left out, `"apply"` is `apply`. See
26
+ * {@link DateRangePickerProps.apply}.
24
27
  *
25
- * - `"immediate"` (the default, and all of 0.7): a preset click commits and closes,
26
- * and each calendar click is reported as it happens — the half-made `(from, "")`
27
- * included. The right shape for quick ranges on a filter, where one click is one
28
- * answer.
29
- * - `"apply"`: the panel works on a DRAFT. A preset ARMS the calendar instead of
30
- * committing, days can then be nudged ("last 3 months, but end it last Friday"),
31
- * and nothing reaches `onChange` until Apply — which stays disabled until both ends
32
- * exist. Cancel, Escape and an outside click discard the draft, and every open
33
- * starts again from the committed value. keksdose's report range asked for exactly
34
- * this: each commit there re-runs a whole page of charts, so an intermediate state
35
- * must never escape the panel.
28
+ * @deprecated 0.52 — DateRangePicker's `apply` (`commit="apply"` → `apply`, `"immediate"`
29
+ * → nothing); removed in 0.53. `commit` is the write lock's opt-in on every other kit
30
+ * control, and since 0.52 on this one too (refactor audit 2026-10-30, API-3).
36
31
  */
37
32
  export type DateRangeCommit = "immediate" | "apply";
38
33
  export interface DateRangePickerProps extends DatePickerBaseProps {
@@ -44,8 +39,9 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
44
39
  onChange: (from: string, to: string, presetId?: string) => void;
45
40
  /** Separator between the two formatted dates in the trigger (default " – "). */
46
41
  separator?: string;
47
- /** Optional named ranges rendered as a start-side column (last month / YTD / …). */
48
- presets?: DateRangePickerPreset[];
42
+ /** Optional named ranges rendered as a start-side column (last month / YTD / …).
43
+ * `readonly` since 0.52 (API-7): the picker never changes the list. */
44
+ presets?: readonly DateRangePickerPreset[];
49
45
  /**
50
46
  * The active preset's `id`, controlled — e.g. straight from keksdose's `?preset=`.
51
47
  * `null` (or an id no preset has, such as `"custom"`) says "no preset": nothing in
@@ -56,8 +52,39 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
56
52
  * itself; with no memory at all it falls back to the first preset whose dates match.
57
53
  */
58
54
  preset?: string | null;
59
- /** See {@link DateRangeCommit}. Default `"immediate"`. */
60
- commit?: DateRangeCommit;
55
+ /**
56
+ * When the picker hands its range to `onChange`.
57
+ *
58
+ * - Left out (the default, and all of 0.7): a preset click commits and closes, and
59
+ * each calendar click is reported as it happens — the half-made `(from, "")`
60
+ * included. The right shape for quick ranges on a filter, where one click is one
61
+ * answer.
62
+ * - `apply`: the panel works on a DRAFT. A preset ARMS the calendar instead of
63
+ * committing, days can then be nudged ("last 3 months, but end it last Friday"),
64
+ * and nothing reaches `onChange` until Apply — which stays disabled until both ends
65
+ * exist. Cancel, Escape and an outside click discard the draft, and every open
66
+ * starts again from the committed value. keksdose's report range asked for exactly
67
+ * this: each commit there re-runs a whole page of charts, so an intermediate state
68
+ * must never escape the panel.
69
+ *
70
+ * `commit="apply"` until 0.52 (refactor audit 2026-10-30, API-3): `commit` is the write
71
+ * lock's prop on every other kit control. The old spelling still works for 0.52 and
72
+ * goes in 0.53 ({@link DateRangeCommit}); `apply` wins where both are given.
73
+ */
74
+ apply?: boolean;
75
+ /**
76
+ * This picker COMMITS — picking a range saves it (a report's period kept per user, a
77
+ * filter persisted as it moves). Under a locked {@link WriteLockProvider} it is locked
78
+ * the `disabledReason` way, with the lock's reason; a {@link CommitScope}, as on every
79
+ * kit control since 0.33, and on this one since 0.52 (API-3). A range inside a form with
80
+ * its own Save stays editable under the lock — leave this off there.
81
+ *
82
+ * The strings `"immediate"` and `"apply"` are the panel's mode, the 0.x meaning of this
83
+ * prop: deprecated, read as `apply` for one minor, removed in 0.53 — see
84
+ * {@link DateRangeCommit}. They cannot be taken for a scope, which is a boolean or an
85
+ * object.
86
+ */
87
+ commit?: CommitScope | DateRangeCommit;
61
88
  /**
62
89
  * Draw the trigger yourself. keksdose's report range field
63
90
  * (reports/report-range-field.tsx, "Why this is app-level") is why: its trigger
@@ -82,7 +109,7 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
82
109
  */
83
110
  sheetBackCloses?: boolean;
84
111
  /**
85
- * With `commit="apply"`: a line above the calendar saying what Apply would commit —
112
+ * With `apply`: a line above the calendar saying what Apply would commit —
86
113
  * keksdose's report range writes "Custom · 1 Mar 2026 – …" there
87
114
  * (report-range-field.tsx), the one place a preset armed and then nudged by a day is
88
115
  * seen to have become "Custom", and a half-made range to still lack its end. Called
@@ -91,7 +118,7 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
91
118
  * `""` until the second click. The line is a polite live region, so a screen reader
92
119
  * hears the draft change as the calendar is used.
93
120
  *
94
- * Ignored in `"immediate"` mode, where there is no draft: every click is the value.
121
+ * Ignored without `apply`, where there is no draft: every click is the value.
95
122
  */
96
123
  renderDraftSummary?: (draft: DateRangeDraftSummary) => ReactNode;
97
124
  }
@@ -120,6 +147,6 @@ export interface DateRangeTriggerRenderProps {
120
147
  text: string;
121
148
  }
122
149
  /** Two-date range picker: click a start then an end; closes once both are set.
123
- * With `presets`, a column of named ranges is shown beside the calendar; with
124
- * `commit="apply"` the panel drafts and commits on Apply (see {@link DateRangeCommit}). */
150
+ * With `presets`, a column of named ranges is shown beside the calendar; with `apply`
151
+ * the panel drafts and commits on Apply (see {@link DateRangePickerProps.apply}). */
125
152
  export declare function DateRangePicker(props: DateRangePickerProps): import("react").JSX.Element;
@@ -4,7 +4,7 @@ import { useState } from "react";
4
4
  import { cn } from "../lib/cn.js";
5
5
  import { useKitLocale } from "../i18n/kit-labels.js";
6
6
  import { Button } from "./button.js";
7
- import { FieldBox, useFieldMessages } from "./field-parts.js";
7
+ import { FieldBox, LockedReason, useFieldMessages, useLockReason } from "./field-parts.js";
8
8
  import { usePhoneLayout } from "../hooks/use-breakpoint.js";
9
9
  import {
10
10
  DateField,
@@ -69,7 +69,7 @@ function RangePanel({
69
69
  presets,
70
70
  activeId,
71
71
  controlled,
72
- commit,
72
+ drafting,
73
73
  close,
74
74
  frame,
75
75
  sheet,
@@ -78,7 +78,6 @@ function RangePanel({
78
78
  labels,
79
79
  renderDraftSummary
80
80
  }) {
81
- const drafting = commit === "apply";
82
81
  const [draft, setDraft] = useState({
83
82
  from,
84
83
  to,
@@ -165,7 +164,8 @@ function DateRangePicker(props) {
165
164
  separator = " \u2013 ",
166
165
  presets,
167
166
  preset,
168
- commit = "immediate",
167
+ apply,
168
+ commit,
169
169
  renderTrigger,
170
170
  sheetBackCloses,
171
171
  renderDraftSummary,
@@ -175,10 +175,13 @@ function DateRangePicker(props) {
175
175
  clearable,
176
176
  clearLabel,
177
177
  disabled,
178
+ disabledReason,
179
+ disabledReasonDisplay,
178
180
  invalid,
179
181
  hint,
180
182
  help,
181
183
  error,
184
+ className,
182
185
  // The trigger's (API-3).
183
186
  ref,
184
187
  ...rest
@@ -186,6 +189,9 @@ function DateRangePicker(props) {
186
189
  const locale = useKitLocale(localeProp);
187
190
  const text = useDatePickerLabels(clearLabel, void 0, void 0);
188
191
  const render = useTriggerFormat("dateRangePicker", locale, formatOptions, formatValue);
192
+ const drafting = apply ?? commit === "apply";
193
+ const lock = useLockReason(typeof commit === "string" ? void 0 : commit, disabledReason);
194
+ const locked = lock.locked;
189
195
  const messages = useFieldMessages({
190
196
  hint,
191
197
  help,
@@ -193,7 +199,9 @@ function DateRangePicker(props) {
193
199
  error,
194
200
  invalid,
195
201
  describedBy: rest["aria-describedby"],
196
- ariaInvalid: rest["aria-invalid"]
202
+ ariaInvalid: rest["aria-invalid"],
203
+ // A lock's reason between the caption and the error, as on Select.
204
+ reasonId: locked && lock.reasonId
197
205
  });
198
206
  const [ownPreset, setOwnPreset] = useState(void 0);
199
207
  const controlled = preset !== void 0;
@@ -204,6 +212,7 @@ function DateRangePicker(props) {
204
212
  const hasPresets = Boolean(presets && presets.length > 0);
205
213
  const sheet = usePhoneLayout();
206
214
  const commitRange = (f, t, presetId) => {
215
+ if (locked) return;
207
216
  setOwnPreset(presetId);
208
217
  if (presetId === void 0) onChange(f, t);
209
218
  else onChange(f, t, presetId);
@@ -220,6 +229,8 @@ function DateRangePicker(props) {
220
229
  clearLabel: text.clear,
221
230
  panelLabel: text.rangePanel,
222
231
  disabled,
232
+ locked,
233
+ className: locked ? void 0 : className,
223
234
  invalid: messages.isInvalid,
224
235
  width: hasPresets ? "27.5rem" : void 0,
225
236
  hasValue: Boolean(from || to),
@@ -244,7 +255,7 @@ function DateRangePicker(props) {
244
255
  presets,
245
256
  activeId,
246
257
  controlled,
247
- commit,
258
+ drafting,
248
259
  close,
249
260
  frame,
250
261
  sheet,
@@ -256,7 +267,12 @@ function DateRangePicker(props) {
256
267
  )
257
268
  }
258
269
  );
259
- return /* @__PURE__ */ jsx(FieldBox, { below: messages.below, reserve: "error" in props || "hint" in props, children: withEndHint(field, label === void 0 ? messages.labelHint : void 0) });
270
+ const box = withEndHint(field, label === void 0 ? messages.labelHint : void 0);
271
+ return /* @__PURE__ */ jsx(FieldBox, { below: messages.below, reserve: "error" in props || "hint" in props, children: locked ? (
272
+ // DatePicker's frame: the line under the field, or the Tooltip with a hidden copy
273
+ // for `aria-describedby`; the outermost box, so it takes the caller's classes.
274
+ /* @__PURE__ */ jsx(LockedReason, { lock, display: disabledReasonDisplay, className: cn("block", className), children: box })
275
+ ) : box });
260
276
  }
261
277
  export {
262
278
  DateRangePicker
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/date-range-picker.tsx"],"sourcesContent":["// The two-date range picker: presets beside the calendar, `commit=\"apply\"` drafts, a\n// custom trigger. Moved out of date-picker.tsx as it was (MOD-9, refactor audit\n// 2026-10); date-picker still exports every public name here.\nimport { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useKitLocale, type DatePickerLabels } from \"../i18n/kit-labels\";\nimport { Button } from \"./button\";\nimport { FieldBox, useFieldMessages } from \"./field-parts\";\nimport { usePhoneLayout } from \"../hooks/use-breakpoint\";\nimport {\n DateField,\n useDatePickerLabels,\n useTriggerFormat,\n withEndHint,\n type DatePickerBaseProps,\n type DateTriggerAttributes,\n type PanelFrame,\n} from \"./date-field\";\nimport { PanelCalendar, type PanelCalendarProps } from \"./jump-calendar\";\n\nexport interface DateRangePickerPreset {\n /**\n * The preset's identity, independent of its dates — `\"last_3_months\"`, not two ISO\n * strings. Optional for the 0.x callers that pass anonymous pairs.\n *\n * keksdose's report range field (report-range-field.tsx, \"Why this is app-level\")\n * is why it exists: its URL stores `?preset=last_3_months` and recomputes the dates\n * from today on every read, so a preset that is only its dates froze \"last 3 months\"\n * at whatever day the panel rendered, and two presets that happen to cover the same\n * days (this week and today, on a Monday) could not be told apart. With an `id` the\n * choice is reported to `onChange` and shown as selected for as long as the range\n * still matches it. Recompute `from`/`to` on every render (`calendarMonthPresets()`,\n * `dateRangePresets()`) and pass the key as the id.\n */\n id?: string;\n label: ReactNode;\n from: string;\n to: string;\n}\n\n/**\n * When the picker hands its range to `onChange`.\n *\n * - `\"immediate\"` (the default, and all of 0.7): a preset click commits and closes,\n * and each calendar click is reported as it happens — the half-made `(from, \"\")`\n * included. The right shape for quick ranges on a filter, where one click is one\n * answer.\n * - `\"apply\"`: the panel works on a DRAFT. A preset ARMS the calendar instead of\n * committing, days can then be nudged (\"last 3 months, but end it last Friday\"),\n * and nothing reaches `onChange` until Apply — which stays disabled until both ends\n * exist. Cancel, Escape and an outside click discard the draft, and every open\n * starts again from the committed value. keksdose's report range asked for exactly\n * this: each commit there re-runs a whole page of charts, so an intermediate state\n * must never escape the panel.\n */\nexport type DateRangeCommit = \"immediate\" | \"apply\";\n\nexport interface DateRangePickerProps extends DatePickerBaseProps {\n from: string;\n to: string;\n /** The committed range. `presetId` is the chosen preset's `id` when a preset\n * produced it (and the range was not nudged since), `undefined` for days picked by\n * hand. A 0.x two-argument handler simply ignores it. */\n onChange: (from: string, to: string, presetId?: string) => void;\n /** Separator between the two formatted dates in the trigger (default \" – \"). */\n separator?: string;\n /** Optional named ranges rendered as a start-side column (last month / YTD / …). */\n presets?: DateRangePickerPreset[];\n /**\n * The active preset's `id`, controlled — e.g. straight from keksdose's `?preset=`.\n * `null` (or an id no preset has, such as `\"custom\"`) says \"no preset\": nothing in\n * the column is marked even if a preset happens to cover the same days. A preset is\n * marked only while its dates still equal `from`/`to`.\n *\n * Leave it `undefined` and the picker remembers the last preset it committed\n * itself; with no memory at all it falls back to the first preset whose dates match.\n */\n preset?: string | null;\n /** See {@link DateRangeCommit}. Default `\"immediate\"`. */\n commit?: DateRangeCommit;\n /**\n * Draw the trigger yourself. keksdose's report range field\n * (reports/report-range-field.tsx, \"Why this is app-level\") is why: its trigger\n * NAMES the active preset (\"Last 3 months\", the window as a muted suffix) where the\n * kit's shows two dates, sits inside a Tooltip, and is squared off on one side so the\n * granularity control can join it flush at the field's 42px.\n *\n * Spread `props.triggerProps` onto a `<button>` whole and put `props.valueProps` on\n * the element that shows the value — see {@link DateTriggerAttributes} for what each\n * part is for. The field around it (label, hidden name twin, clear/calendar glyph,\n * popover or phone sheet) is unchanged.\n */\n renderTrigger?: (props: DateRangeTriggerRenderProps) => ReactNode;\n /**\n * In the phone layout (`usePhoneLayout()`) the panel opens as a full-screen sheet (`FullBleedDialog`)\n * with presets in a grid above the calendar and Apply pinned in the footer, instead\n * of the 440px popover that hung off a 360px screen (keksdose's report range field,\n * which hand-rolled exactly this). This is its `backCloses`: on by default, so Back\n * dismisses the sheet; off for a caller whose commit rewrites the URL with\n * `replaceState` in the same tick — keksdose's `?preset/from/to` — where the router\n * would overwrite the sheet's history marker.\n */\n sheetBackCloses?: boolean;\n /**\n * With `commit=\"apply\"`: a line above the calendar saying what Apply would commit —\n * keksdose's report range writes \"Custom · 1 Mar 2026 – …\" there\n * (report-range-field.tsx), the one place a preset armed and then nudged by a day is\n * seen to have become \"Custom\", and a half-made range to still lack its end. Called\n * with the DRAFT on every change, in the popover and the phone sheet alike; `preset`\n * is the preset the column marks for it (none once a day was picked by hand), `to` is\n * `\"\"` until the second click. The line is a polite live region, so a screen reader\n * hears the draft change as the calendar is used.\n *\n * Ignored in `\"immediate\"` mode, where there is no draft: every click is the value.\n */\n renderDraftSummary?: (draft: DateRangeDraftSummary) => ReactNode;\n}\n\n/** What {@link DateRangePickerProps.renderDraftSummary} is called with. */\nexport interface DateRangeDraftSummary {\n from: string;\n to: string;\n /** The preset the column marks for the draft, if any. */\n preset: DateRangePickerPreset | undefined;\n}\n\n/** What {@link DateRangePickerProps.renderTrigger} is called with. */\nexport interface DateRangeTriggerRenderProps {\n /** Spread onto the `<button>`, whole. Merge your class after `triggerProps.className`. */\n triggerProps: DateTriggerAttributes;\n /** Put on the element showing the value: the trigger is named \"label, value\" by\n * reference to this id. Without it the name is the label alone. */\n valueProps: { id: string };\n open: boolean;\n from: string;\n to: string;\n /** The preset the column marks for the committed range, if any — the one to name. */\n preset: DateRangePickerPreset | undefined;\n /** What the kit's own trigger would show: the formatted range, or the placeholder. */\n text: string;\n}\n\ninterface RangeDraft {\n from: string;\n to: string;\n presetId: string | undefined;\n}\n\n/** Which preset (by index) the column marks, or -1. See `DateRangePickerProps.preset`. */\nfunction markedPreset(\n presets: readonly DateRangePickerPreset[],\n from: string,\n to: string,\n activeId: string | null | undefined,\n controlled: boolean,\n): number {\n const matches = (p: DateRangePickerPreset) => p.from === from && p.to === to;\n if (activeId != null) {\n const byId = presets.findIndex((p) => p.id === activeId && matches(p));\n if (byId !== -1 || controlled) return byId;\n } else if (controlled) {\n return -1;\n }\n return presets.findIndex(matches);\n}\n\n/**\n * The preset column: a named group of toggle buttons, `aria-pressed` on the marked one.\n * Pressed-state rather than colour alone, because \"which range is this\" is the one\n * thing a screen-reader user opening the panel needs to hear.\n */\nfunction PresetColumn({\n presets,\n marked,\n label,\n onPick,\n sheet,\n}: {\n presets: readonly DateRangePickerPreset[];\n marked: number;\n label: string;\n onPick: (p: DateRangePickerPreset) => void;\n /** The phone sheet's shape: a two-column grid ABOVE the calendar with 44px rows —\n * a 128px column beside a month grid leaves the grid ~200px on a 360px screen. */\n sheet?: boolean;\n}) {\n return (\n // `border-e`/`pe`, not `-r`: the preset column is on the START side, and the rule\n // between it and the calendar has to follow it in a right-to-left UI.\n <div\n role=\"group\"\n aria-label={label}\n className={sheet ? \"grid grid-cols-2 gap-0.5\" : \"flex w-32 shrink-0 flex-col gap-0.5 border-e border-subtle pe-2\"}\n >\n {presets.map((p, i) => {\n const selected = i === marked;\n return (\n <button\n key={p.id ?? i}\n type=\"button\"\n aria-pressed={selected}\n data-preset={p.id}\n onClick={() => onPick(p)}\n className={cn(\n \"rounded px-2 text-start\",\n // 44px on a phone: the kit's touch-target size (`SHEET_ROW_CLASS`).\n sheet ? \"min-h-11 py-2 text-sm\" : \"py-1.5 text-xs\",\n selected ? \"bg-active font-medium text-primary\" : \"text-secondary hover:bg-hover\",\n )}\n >\n {p.label}\n </button>\n );\n })}\n </div>\n );\n}\n\n/**\n * The panel's body. A component of its own so `commit=\"apply\"` can keep its draft in\n * state that is born when the panel opens: `Popover` unmounts its children on close,\n * so the draft is re-seeded from the committed value on every open, and an abandoned\n * half-selection cannot survive into the next one.\n */\nfunction RangePanel({\n from,\n to,\n presets,\n activeId,\n controlled,\n commit,\n close,\n frame,\n sheet,\n commitRange,\n calendarProps,\n labels,\n renderDraftSummary,\n}: {\n from: string;\n to: string;\n presets: readonly DateRangePickerPreset[] | undefined;\n activeId: string | null | undefined;\n controlled: boolean;\n commit: DateRangeCommit;\n close: () => void;\n /** Where the body and the Apply row go — see `PanelFrame`. */\n frame: PanelFrame;\n sheet: boolean;\n commitRange: (from: string, to: string, presetId: string | undefined) => void;\n calendarProps: Pick<PanelCalendarProps, \"locale\" | \"min\" | \"max\" | \"labels\" | \"monthJump\">;\n labels: DatePickerLabels;\n renderDraftSummary?: DateRangePickerProps[\"renderDraftSummary\"];\n}) {\n const drafting = commit === \"apply\";\n const [draft, setDraft] = useState<RangeDraft>({\n from,\n to,\n presetId: activeId ?? undefined,\n });\n // What the panel SHOWS: the draft while drafting, the committed value otherwise.\n const shown = drafting ? draft : { from, to, presetId: activeId ?? undefined };\n const marked = presets\n ? markedPreset(presets, shown.from, shown.to, drafting ? draft.presetId : activeId, drafting || controlled)\n : -1;\n const complete = Boolean(draft.from && draft.to);\n\n const summary =\n drafting && renderDraftSummary\n ? renderDraftSummary({ from: draft.from, to: draft.to, preset: presets?.[marked] })\n : null;\n\n const picker = (\n <PanelCalendar\n {...calendarProps}\n focusOnOpen\n from={shown.from}\n to={shown.to}\n onSelect={(f, t) => {\n if (drafting) {\n setDraft({ from: f, to: t, presetId: undefined });\n return;\n }\n commitRange(f, t, undefined);\n // Two-click range: only dismiss once both ends are chosen.\n if (f && t) close();\n }}\n />\n );\n // The summary heads the CALENDAR's column, not the panel: beside a preset column it\n // reads as the calendar's caption, and in the sheet it sits between the presets and\n // the month it describes. `null` renders no line — a caller may opt out per draft —\n // but keeps the wrapper, so the calendar is not remounted (and its month and focus\n // lost) when a line comes or goes.\n const calendar =\n drafting && renderDraftSummary ? (\n <div className=\"flex flex-col gap-2\">\n {summary != null && (\n <div aria-live=\"polite\" data-draft-summary=\"\" className=\"text-xs text-muted\">\n {summary}\n </div>\n )}\n {picker}\n </div>\n ) : (\n picker\n );\n\n const body =\n presets && presets.length > 0 ? (\n <div className={sheet ? \"flex flex-col gap-3\" : \"flex gap-3\"}>\n <PresetColumn\n sheet={sheet}\n presets={presets}\n marked={marked}\n label={labels.presets}\n onPick={(p) => {\n if (drafting) {\n setDraft({ from: p.from, to: p.to, presetId: p.id });\n return;\n }\n commitRange(p.from, p.to, p.id);\n close();\n }}\n />\n {/* `flex-1`: the calendar takes the rest of the panel. Content-sized it was\n seven tiny cells beside a wide preset column. */}\n <div className=\"min-w-0 flex-1\">{calendar}</div>\n </div>\n ) : (\n calendar\n );\n\n if (!drafting) return frame(body);\n return frame(\n body,\n <>\n {/* `flex-1` in the sheet: two thumb-wide halves of the footer, not two small\n buttons in its corner. */}\n <Button type=\"button\" variant=\"ghost\" className={sheet ? \"flex-1\" : undefined} onClick={close}>\n {labels.cancel}\n </Button>\n <Button\n type=\"button\"\n className={sheet ? \"flex-1\" : undefined}\n // A half-made `(from, \"\")` would commit a window with no end — a blank\n // report, one click into a two-click gesture.\n disabled={!complete}\n onClick={() => {\n if (!complete) return;\n commitRange(draft.from, draft.to, draft.presetId);\n close();\n }}\n >\n {labels.apply}\n </Button>\n </>,\n );\n}\n\n/** Two-date range picker: click a start then an end; closes once both are set.\n * With `presets`, a column of named ranges is shown beside the calendar; with\n * `commit=\"apply\"` the panel drafts and commits on Apply (see {@link DateRangeCommit}). */\nexport function DateRangePicker(props: DateRangePickerProps) {\n const {\n from,\n to,\n onChange,\n locale: localeProp,\n placeholder,\n min,\n max,\n formatOptions,\n formatValue,\n separator = \" – \",\n presets,\n preset,\n commit = \"immediate\",\n renderTrigger,\n sheetBackCloses,\n renderDraftSummary,\n calendarLabels,\n monthJump,\n label,\n clearable,\n clearLabel,\n disabled,\n invalid,\n hint,\n help,\n error,\n // The trigger's (API-3).\n ref,\n ...rest\n } = props;\n const locale = useKitLocale(localeProp);\n const text = useDatePickerLabels(clearLabel, undefined, undefined);\n const render = useTriggerFormat(\"dateRangePicker\", locale, formatOptions, formatValue);\n const messages = useFieldMessages({\n hint,\n help,\n name: label ?? rest[\"aria-label\"],\n error,\n invalid,\n describedBy: rest[\"aria-describedby\"],\n ariaInvalid: rest[\"aria-invalid\"],\n });\n // The preset this picker committed itself, for a caller that does not control\n // `preset`. Cleared by a hand-picked range or a clear.\n const [ownPreset, setOwnPreset] = useState<string | undefined>(undefined);\n const controlled = preset !== undefined;\n const activeId = controlled ? preset : ownPreset;\n const a = from ? render(from) : \"\";\n const b = to ? render(to) : \"\";\n const triggerText = from ? (to ? `${a}${separator}${b}` : `${a}${separator}…`) : (placeholder ?? \"\");\n const hasPresets = Boolean(presets && presets.length > 0);\n const sheet = usePhoneLayout();\n const commitRange = (f: string, t: string, presetId: string | undefined) => {\n setOwnPreset(presetId);\n // Two arguments when no preset is involved — exactly the 0.7 call, so a caller's\n // `toHaveBeenCalledWith(from, to)` and a variadic handler see no difference.\n if (presetId === undefined) onChange(f, t);\n else onChange(f, t, presetId);\n };\n const field = (\n <DateField\n {...rest}\n fieldRef={ref}\n aria-describedby={messages.describedBy}\n label={label}\n labelHint={messages.labelHint}\n clearable={clearable}\n clearLabel={text.clear}\n panelLabel={text.rangePanel}\n disabled={disabled}\n invalid={messages.isInvalid}\n // Widen so the preset column sits beside the calendar (default otherwise).\n width={hasPresets ? \"27.5rem\" : undefined}\n hasValue={Boolean(from || to)}\n triggerText={triggerText}\n onClear={() => commitRange(\"\", \"\", undefined)}\n sheet={sheet}\n sheetBackCloses={sheetBackCloses}\n renderTrigger={\n renderTrigger &&\n ((triggerProps, valueId) =>\n renderTrigger({\n triggerProps,\n valueProps: { id: valueId },\n open: triggerProps[\"aria-expanded\"],\n from,\n to,\n preset: presets?.[markedPreset(presets, from, to, activeId, controlled)],\n text: triggerText,\n }))\n }\n >\n {(close, frame) => (\n <RangePanel\n from={from}\n to={to}\n presets={presets}\n activeId={activeId}\n controlled={controlled}\n commit={commit}\n close={close}\n frame={frame}\n sheet={sheet}\n commitRange={commitRange}\n calendarProps={{ locale, min, max, labels: calendarLabels, monthJump }}\n labels={text}\n renderDraftSummary={renderDraftSummary}\n />\n )}\n </DateField>\n );\n return (\n <FieldBox below={messages.below} reserve={\"error\" in props || \"hint\" in props}>\n {withEndHint(field, label === undefined ? messages.labelHint : undefined)}\n </FieldBox>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/date-range-picker.tsx"],"sourcesContent":["// The two-date range picker: presets beside the calendar, `apply` drafts, a custom\n// trigger. Moved out of date-picker.tsx as it was (MOD-9, refactor audit\n// 2026-10); date-picker still exports every public name here.\nimport { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useKitLocale, type DatePickerLabels } from \"../i18n/kit-labels\";\nimport { Button } from \"./button\";\nimport { FieldBox, LockedReason, useFieldMessages, useLockReason } from \"./field-parts\";\nimport type { CommitScope } from \"./write-lock\";\nimport { usePhoneLayout } from \"../hooks/use-breakpoint\";\nimport {\n DateField,\n useDatePickerLabels,\n useTriggerFormat,\n withEndHint,\n type DatePickerBaseProps,\n type DateTriggerAttributes,\n type PanelFrame,\n} from \"./date-field\";\nimport { PanelCalendar, type PanelCalendarProps } from \"./jump-calendar\";\n\nexport interface DateRangePickerPreset {\n /**\n * The preset's identity, independent of its dates — `\"last_3_months\"`, not two ISO\n * strings. Optional for the 0.x callers that pass anonymous pairs.\n *\n * keksdose's report range field (report-range-field.tsx, \"Why this is app-level\")\n * is why it exists: its URL stores `?preset=last_3_months` and recomputes the dates\n * from today on every read, so a preset that is only its dates froze \"last 3 months\"\n * at whatever day the panel rendered, and two presets that happen to cover the same\n * days (this week and today, on a Monday) could not be told apart. With an `id` the\n * choice is reported to `onChange` and shown as selected for as long as the range\n * still matches it. Recompute `from`/`to` on every render (`calendarMonthPresets()`,\n * `dateRangePresets()`) and pass the key as the id.\n */\n id?: string;\n label: ReactNode;\n from: string;\n to: string;\n}\n\n/**\n * The 0.x values of DateRangePicker's `commit`, when it was the panel's mode:\n * `\"immediate\"` is `apply` left out, `\"apply\"` is `apply`. See\n * {@link DateRangePickerProps.apply}.\n *\n * @deprecated 0.52 — DateRangePicker's `apply` (`commit=\"apply\"` → `apply`, `\"immediate\"`\n * → nothing); removed in 0.53. `commit` is the write lock's opt-in on every other kit\n * control, and since 0.52 on this one too (refactor audit 2026-10-30, API-3).\n */\nexport type DateRangeCommit = \"immediate\" | \"apply\";\n\nexport interface DateRangePickerProps extends DatePickerBaseProps {\n from: string;\n to: string;\n /** The committed range. `presetId` is the chosen preset's `id` when a preset\n * produced it (and the range was not nudged since), `undefined` for days picked by\n * hand. A 0.x two-argument handler simply ignores it. */\n onChange: (from: string, to: string, presetId?: string) => void;\n /** Separator between the two formatted dates in the trigger (default \" – \"). */\n separator?: string;\n /** Optional named ranges rendered as a start-side column (last month / YTD / …).\n * `readonly` since 0.52 (API-7): the picker never changes the list. */\n presets?: readonly DateRangePickerPreset[];\n /**\n * The active preset's `id`, controlled — e.g. straight from keksdose's `?preset=`.\n * `null` (or an id no preset has, such as `\"custom\"`) says \"no preset\": nothing in\n * the column is marked even if a preset happens to cover the same days. A preset is\n * marked only while its dates still equal `from`/`to`.\n *\n * Leave it `undefined` and the picker remembers the last preset it committed\n * itself; with no memory at all it falls back to the first preset whose dates match.\n */\n preset?: string | null;\n /**\n * When the picker hands its range to `onChange`.\n *\n * - Left out (the default, and all of 0.7): a preset click commits and closes, and\n * each calendar click is reported as it happens — the half-made `(from, \"\")`\n * included. The right shape for quick ranges on a filter, where one click is one\n * answer.\n * - `apply`: the panel works on a DRAFT. A preset ARMS the calendar instead of\n * committing, days can then be nudged (\"last 3 months, but end it last Friday\"),\n * and nothing reaches `onChange` until Apply — which stays disabled until both ends\n * exist. Cancel, Escape and an outside click discard the draft, and every open\n * starts again from the committed value. keksdose's report range asked for exactly\n * this: each commit there re-runs a whole page of charts, so an intermediate state\n * must never escape the panel.\n *\n * `commit=\"apply\"` until 0.52 (refactor audit 2026-10-30, API-3): `commit` is the write\n * lock's prop on every other kit control. The old spelling still works for 0.52 and\n * goes in 0.53 ({@link DateRangeCommit}); `apply` wins where both are given.\n */\n apply?: boolean;\n /**\n * This picker COMMITS — picking a range saves it (a report's period kept per user, a\n * filter persisted as it moves). Under a locked {@link WriteLockProvider} it is locked\n * the `disabledReason` way, with the lock's reason; a {@link CommitScope}, as on every\n * kit control since 0.33, and on this one since 0.52 (API-3). A range inside a form with\n * its own Save stays editable under the lock — leave this off there.\n *\n * The strings `\"immediate\"` and `\"apply\"` are the panel's mode, the 0.x meaning of this\n * prop: deprecated, read as `apply` for one minor, removed in 0.53 — see\n * {@link DateRangeCommit}. They cannot be taken for a scope, which is a boolean or an\n * object.\n */\n commit?: CommitScope | DateRangeCommit;\n /**\n * Draw the trigger yourself. keksdose's report range field\n * (reports/report-range-field.tsx, \"Why this is app-level\") is why: its trigger\n * NAMES the active preset (\"Last 3 months\", the window as a muted suffix) where the\n * kit's shows two dates, sits inside a Tooltip, and is squared off on one side so the\n * granularity control can join it flush at the field's 42px.\n *\n * Spread `props.triggerProps` onto a `<button>` whole and put `props.valueProps` on\n * the element that shows the value — see {@link DateTriggerAttributes} for what each\n * part is for. The field around it (label, hidden name twin, clear/calendar glyph,\n * popover or phone sheet) is unchanged.\n */\n renderTrigger?: (props: DateRangeTriggerRenderProps) => ReactNode;\n /**\n * In the phone layout (`usePhoneLayout()`) the panel opens as a full-screen sheet (`FullBleedDialog`)\n * with presets in a grid above the calendar and Apply pinned in the footer, instead\n * of the 440px popover that hung off a 360px screen (keksdose's report range field,\n * which hand-rolled exactly this). This is its `backCloses`: on by default, so Back\n * dismisses the sheet; off for a caller whose commit rewrites the URL with\n * `replaceState` in the same tick — keksdose's `?preset/from/to` — where the router\n * would overwrite the sheet's history marker.\n */\n sheetBackCloses?: boolean;\n /**\n * With `apply`: a line above the calendar saying what Apply would commit —\n * keksdose's report range writes \"Custom · 1 Mar 2026 – …\" there\n * (report-range-field.tsx), the one place a preset armed and then nudged by a day is\n * seen to have become \"Custom\", and a half-made range to still lack its end. Called\n * with the DRAFT on every change, in the popover and the phone sheet alike; `preset`\n * is the preset the column marks for it (none once a day was picked by hand), `to` is\n * `\"\"` until the second click. The line is a polite live region, so a screen reader\n * hears the draft change as the calendar is used.\n *\n * Ignored without `apply`, where there is no draft: every click is the value.\n */\n renderDraftSummary?: (draft: DateRangeDraftSummary) => ReactNode;\n}\n\n/** What {@link DateRangePickerProps.renderDraftSummary} is called with. */\nexport interface DateRangeDraftSummary {\n from: string;\n to: string;\n /** The preset the column marks for the draft, if any. */\n preset: DateRangePickerPreset | undefined;\n}\n\n/** What {@link DateRangePickerProps.renderTrigger} is called with. */\nexport interface DateRangeTriggerRenderProps {\n /** Spread onto the `<button>`, whole. Merge your class after `triggerProps.className`. */\n triggerProps: DateTriggerAttributes;\n /** Put on the element showing the value: the trigger is named \"label, value\" by\n * reference to this id. Without it the name is the label alone. */\n valueProps: { id: string };\n open: boolean;\n from: string;\n to: string;\n /** The preset the column marks for the committed range, if any — the one to name. */\n preset: DateRangePickerPreset | undefined;\n /** What the kit's own trigger would show: the formatted range, or the placeholder. */\n text: string;\n}\n\ninterface RangeDraft {\n from: string;\n to: string;\n presetId: string | undefined;\n}\n\n/** Which preset (by index) the column marks, or -1. See `DateRangePickerProps.preset`. */\nfunction markedPreset(\n presets: readonly DateRangePickerPreset[],\n from: string,\n to: string,\n activeId: string | null | undefined,\n controlled: boolean,\n): number {\n const matches = (p: DateRangePickerPreset) => p.from === from && p.to === to;\n if (activeId != null) {\n const byId = presets.findIndex((p) => p.id === activeId && matches(p));\n if (byId !== -1 || controlled) return byId;\n } else if (controlled) {\n return -1;\n }\n return presets.findIndex(matches);\n}\n\n/**\n * The preset column: a named group of toggle buttons, `aria-pressed` on the marked one.\n * Pressed-state rather than colour alone, because \"which range is this\" is the one\n * thing a screen-reader user opening the panel needs to hear.\n */\nfunction PresetColumn({\n presets,\n marked,\n label,\n onPick,\n sheet,\n}: {\n presets: readonly DateRangePickerPreset[];\n marked: number;\n label: string;\n onPick: (p: DateRangePickerPreset) => void;\n /** The phone sheet's shape: a two-column grid ABOVE the calendar with 44px rows —\n * a 128px column beside a month grid leaves the grid ~200px on a 360px screen. */\n sheet?: boolean;\n}) {\n return (\n // `border-e`/`pe`, not `-r`: the preset column is on the START side, and the rule\n // between it and the calendar has to follow it in a right-to-left UI.\n <div\n role=\"group\"\n aria-label={label}\n className={sheet ? \"grid grid-cols-2 gap-0.5\" : \"flex w-32 shrink-0 flex-col gap-0.5 border-e border-subtle pe-2\"}\n >\n {presets.map((p, i) => {\n const selected = i === marked;\n return (\n <button\n key={p.id ?? i}\n type=\"button\"\n aria-pressed={selected}\n data-preset={p.id}\n onClick={() => onPick(p)}\n className={cn(\n \"rounded px-2 text-start\",\n // 44px on a phone: the kit's touch-target size (`SHEET_ROW_CLASS`).\n sheet ? \"min-h-11 py-2 text-sm\" : \"py-1.5 text-xs\",\n selected ? \"bg-active font-medium text-primary\" : \"text-secondary hover:bg-hover\",\n )}\n >\n {p.label}\n </button>\n );\n })}\n </div>\n );\n}\n\n/**\n * The panel's body. A component of its own so `apply` can keep its draft in state that\n * is born when the panel opens: `Popover` unmounts its children on close,\n * so the draft is re-seeded from the committed value on every open, and an abandoned\n * half-selection cannot survive into the next one.\n */\nfunction RangePanel({\n from,\n to,\n presets,\n activeId,\n controlled,\n drafting,\n close,\n frame,\n sheet,\n commitRange,\n calendarProps,\n labels,\n renderDraftSummary,\n}: {\n from: string;\n to: string;\n presets: readonly DateRangePickerPreset[] | undefined;\n activeId: string | null | undefined;\n controlled: boolean;\n /** `apply`: the panel works on a draft. */\n drafting: boolean;\n close: () => void;\n /** Where the body and the Apply row go — see `PanelFrame`. */\n frame: PanelFrame;\n sheet: boolean;\n commitRange: (from: string, to: string, presetId: string | undefined) => void;\n calendarProps: Pick<PanelCalendarProps, \"locale\" | \"min\" | \"max\" | \"labels\" | \"monthJump\">;\n labels: DatePickerLabels;\n renderDraftSummary?: DateRangePickerProps[\"renderDraftSummary\"];\n}) {\n const [draft, setDraft] = useState<RangeDraft>({\n from,\n to,\n presetId: activeId ?? undefined,\n });\n // What the panel SHOWS: the draft while drafting, the committed value otherwise.\n const shown = drafting ? draft : { from, to, presetId: activeId ?? undefined };\n const marked = presets\n ? markedPreset(presets, shown.from, shown.to, drafting ? draft.presetId : activeId, drafting || controlled)\n : -1;\n const complete = Boolean(draft.from && draft.to);\n\n const summary =\n drafting && renderDraftSummary\n ? renderDraftSummary({ from: draft.from, to: draft.to, preset: presets?.[marked] })\n : null;\n\n const picker = (\n <PanelCalendar\n {...calendarProps}\n focusOnOpen\n from={shown.from}\n to={shown.to}\n onSelect={(f, t) => {\n if (drafting) {\n setDraft({ from: f, to: t, presetId: undefined });\n return;\n }\n commitRange(f, t, undefined);\n // Two-click range: only dismiss once both ends are chosen.\n if (f && t) close();\n }}\n />\n );\n // The summary heads the CALENDAR's column, not the panel: beside a preset column it\n // reads as the calendar's caption, and in the sheet it sits between the presets and\n // the month it describes. `null` renders no line — a caller may opt out per draft —\n // but keeps the wrapper, so the calendar is not remounted (and its month and focus\n // lost) when a line comes or goes.\n const calendar =\n drafting && renderDraftSummary ? (\n <div className=\"flex flex-col gap-2\">\n {summary != null && (\n <div aria-live=\"polite\" data-draft-summary=\"\" className=\"text-xs text-muted\">\n {summary}\n </div>\n )}\n {picker}\n </div>\n ) : (\n picker\n );\n\n const body =\n presets && presets.length > 0 ? (\n <div className={sheet ? \"flex flex-col gap-3\" : \"flex gap-3\"}>\n <PresetColumn\n sheet={sheet}\n presets={presets}\n marked={marked}\n label={labels.presets}\n onPick={(p) => {\n if (drafting) {\n setDraft({ from: p.from, to: p.to, presetId: p.id });\n return;\n }\n commitRange(p.from, p.to, p.id);\n close();\n }}\n />\n {/* `flex-1`: the calendar takes the rest of the panel. Content-sized it was\n seven tiny cells beside a wide preset column. */}\n <div className=\"min-w-0 flex-1\">{calendar}</div>\n </div>\n ) : (\n calendar\n );\n\n if (!drafting) return frame(body);\n return frame(\n body,\n <>\n {/* `flex-1` in the sheet: two thumb-wide halves of the footer, not two small\n buttons in its corner. */}\n <Button type=\"button\" variant=\"ghost\" className={sheet ? \"flex-1\" : undefined} onClick={close}>\n {labels.cancel}\n </Button>\n <Button\n type=\"button\"\n className={sheet ? \"flex-1\" : undefined}\n // A half-made `(from, \"\")` would commit a window with no end — a blank\n // report, one click into a two-click gesture.\n disabled={!complete}\n onClick={() => {\n if (!complete) return;\n commitRange(draft.from, draft.to, draft.presetId);\n close();\n }}\n >\n {labels.apply}\n </Button>\n </>,\n );\n}\n\n/** Two-date range picker: click a start then an end; closes once both are set.\n * With `presets`, a column of named ranges is shown beside the calendar; with `apply`\n * the panel drafts and commits on Apply (see {@link DateRangePickerProps.apply}). */\nexport function DateRangePicker(props: DateRangePickerProps) {\n const {\n from,\n to,\n onChange,\n locale: localeProp,\n placeholder,\n min,\n max,\n formatOptions,\n formatValue,\n separator = \" – \",\n presets,\n preset,\n apply,\n commit,\n renderTrigger,\n sheetBackCloses,\n renderDraftSummary,\n calendarLabels,\n monthJump,\n label,\n clearable,\n clearLabel,\n disabled,\n disabledReason,\n disabledReasonDisplay,\n invalid,\n hint,\n help,\n error,\n className,\n // The trigger's (API-3).\n ref,\n ...rest\n } = props;\n const locale = useKitLocale(localeProp);\n const text = useDatePickerLabels(clearLabel, undefined, undefined);\n const render = useTriggerFormat(\"dateRangePicker\", locale, formatOptions, formatValue);\n // `commit` is two props until 0.53: a string is the deprecated mode, anything else\n // the write lock's scope (API-3).\n const drafting = apply ?? commit === \"apply\";\n const lock = useLockReason(typeof commit === \"string\" ? undefined : commit, disabledReason);\n const locked = lock.locked;\n const messages = useFieldMessages({\n hint,\n help,\n name: label ?? rest[\"aria-label\"],\n error,\n invalid,\n describedBy: rest[\"aria-describedby\"],\n ariaInvalid: rest[\"aria-invalid\"],\n // A lock's reason between the caption and the error, as on Select.\n reasonId: locked && lock.reasonId,\n });\n // The preset this picker committed itself, for a caller that does not control\n // `preset`. Cleared by a hand-picked range or a clear.\n const [ownPreset, setOwnPreset] = useState<string | undefined>(undefined);\n const controlled = preset !== undefined;\n const activeId = controlled ? preset : ownPreset;\n const a = from ? render(from) : \"\";\n const b = to ? render(to) : \"\";\n const triggerText = from ? (to ? `${a}${separator}${b}` : `${a}${separator}…`) : (placeholder ?? \"\");\n const hasPresets = Boolean(presets && presets.length > 0);\n const sheet = usePhoneLayout();\n const commitRange = (f: string, t: string, presetId: string | undefined) => {\n if (locked) return;\n setOwnPreset(presetId);\n // Two arguments when no preset is involved — exactly the 0.7 call, so a caller's\n // `toHaveBeenCalledWith(from, to)` and a variadic handler see no difference.\n if (presetId === undefined) onChange(f, t);\n else onChange(f, t, presetId);\n };\n const field = (\n <DateField\n {...rest}\n fieldRef={ref}\n aria-describedby={messages.describedBy}\n label={label}\n labelHint={messages.labelHint}\n clearable={clearable}\n clearLabel={text.clear}\n panelLabel={text.rangePanel}\n disabled={disabled}\n locked={locked}\n // Locked, the caller's classes are the reason's frame's (below).\n className={locked ? undefined : className}\n invalid={messages.isInvalid}\n // Widen so the preset column sits beside the calendar (default otherwise).\n width={hasPresets ? \"27.5rem\" : undefined}\n hasValue={Boolean(from || to)}\n triggerText={triggerText}\n onClear={() => commitRange(\"\", \"\", undefined)}\n sheet={sheet}\n sheetBackCloses={sheetBackCloses}\n renderTrigger={\n renderTrigger &&\n ((triggerProps, valueId) =>\n renderTrigger({\n triggerProps,\n valueProps: { id: valueId },\n open: triggerProps[\"aria-expanded\"],\n from,\n to,\n preset: presets?.[markedPreset(presets, from, to, activeId, controlled)],\n text: triggerText,\n }))\n }\n >\n {(close, frame) => (\n <RangePanel\n from={from}\n to={to}\n presets={presets}\n activeId={activeId}\n controlled={controlled}\n drafting={drafting}\n close={close}\n frame={frame}\n sheet={sheet}\n commitRange={commitRange}\n calendarProps={{ locale, min, max, labels: calendarLabels, monthJump }}\n labels={text}\n renderDraftSummary={renderDraftSummary}\n />\n )}\n </DateField>\n );\n const box = withEndHint(field, label === undefined ? messages.labelHint : undefined);\n return (\n <FieldBox below={messages.below} reserve={\"error\" in props || \"hint\" in props}>\n {locked ? (\n // DatePicker's frame: the line under the field, or the Tooltip with a hidden copy\n // for `aria-describedby`; the outermost box, so it takes the caller's classes.\n <LockedReason lock={lock} display={disabledReasonDisplay} className={cn(\"block\", className)}>\n {box}\n </LockedReason>\n ) : (\n box\n )}\n </FieldBox>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { Component } from "react";
3
+ import { Component, useEffect } from "react";
4
4
  import { AlertTriangle, RefreshCw, WifiOff } from "lucide-react";
5
5
  import { useKitLabels } from "../i18n/kit-labels.js";
6
6
  import { Button } from "./button.js";
@@ -8,6 +8,7 @@ import { EmptyState } from "./empty-state.js";
8
8
  import { CopyButton } from "./copy-button.js";
9
9
  import { Disclosure } from "./disclosure.js";
10
10
  import { documentNavigation } from "../lib/document-navigation.js";
11
+ import { useAnnounce } from "../hooks/use-announce.js";
11
12
  import { DEFAULT_ERROR_BOUNDARY_LABELS } from "./error-boundary-labels.js";
12
13
  function read(get) {
13
14
  try {
@@ -264,37 +265,43 @@ function ErrorFallback({
264
265
  const Icon = mode === "offline" ? WifiOff : mode === "update" ? RefreshCw : AlertTriangle;
265
266
  const reportText = report ? formatCrashReport(report) : null;
266
267
  const errorLine = details.message ? `${details.name}: ${details.message}` : details.name;
268
+ const alert = useAnnounce({ politeness: "assertive" });
269
+ const { announce } = alert;
270
+ const spoken = `${title}. ${hint}`;
271
+ useEffect(() => announce(spoken), [announce, spoken]);
267
272
  const reloadButton = /* @__PURE__ */ jsx(Button, { variant: mode === "error" ? "secondary" : "default", onClick: reloadPage, children: text.reload }, "reload");
268
273
  const retryButton = chunk ? null : /* @__PURE__ */ jsx(Button, { variant: mode === "error" ? "default" : "secondary", onClick: reset, children: text.retry }, "retry");
269
- return /* @__PURE__ */ jsx(
270
- EmptyState,
271
- {
272
- role: "alert",
273
- tone: mode === "error" ? "danger" : void 0,
274
- headingAs,
275
- className,
276
- icon: /* @__PURE__ */ jsx(Icon, {}),
277
- title,
278
- hint,
279
- action: /* @__PURE__ */ jsxs(Fragment, { children: [
280
- showMessage && mode === "error" && // A quotation, not prose: left-aligned and monospaced, so it reads as the
281
- // program's words and can be read out or screenshotted verbatim.
282
- /* @__PURE__ */ jsx(
283
- "p",
284
- {
285
- "data-error-message": "",
286
- className: "-mt-1 mb-1 basis-full whitespace-pre-wrap break-words rounded-md border border-danger-strong bg-danger-soft px-3 py-2 text-start font-mono text-xs text-primary",
287
- children: errorLine
288
- }
289
- ),
290
- filing === "filed" && /* @__PURE__ */ jsx("p", { className: "-mt-1 mb-1 basis-full text-xs", children: reference ? text.reportedAs(reference) : text.reported }),
291
- mode === "error" ? [retryButton, reloadButton] : [reloadButton, retryButton],
292
- copyReport && reportText !== null && filing !== "filed" && /* @__PURE__ */ jsx(CopyButton, { variant: "label", buttonVariant: "ghost", label: text.copyReport, text: reportText }),
293
- actions,
294
- showDetails && reportText !== null && /* @__PURE__ */ jsx(Disclosure, { variant: "bare", title: text.details, className: "basis-full text-start", children: /* @__PURE__ */ jsx("pre", { className: "max-h-60 overflow-auto whitespace-pre-wrap break-words text-xs text-secondary", children: reportText }) })
295
- ] })
296
- }
297
- );
274
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
275
+ /* @__PURE__ */ jsx("span", { ...alert.regionProps }),
276
+ /* @__PURE__ */ jsx(
277
+ EmptyState,
278
+ {
279
+ tone: mode === "error" ? "danger" : void 0,
280
+ headingAs,
281
+ className,
282
+ icon: /* @__PURE__ */ jsx(Icon, {}),
283
+ title,
284
+ hint,
285
+ action: /* @__PURE__ */ jsxs(Fragment, { children: [
286
+ showMessage && mode === "error" && // A quotation, not prose: left-aligned and monospaced, so it reads as the
287
+ // program's words and can be read out or screenshotted verbatim.
288
+ /* @__PURE__ */ jsx(
289
+ "p",
290
+ {
291
+ "data-error-message": "",
292
+ className: "-mt-1 mb-1 basis-full whitespace-pre-wrap break-words rounded-md border border-danger-strong bg-danger-soft px-3 py-2 text-start font-mono text-xs text-primary",
293
+ children: errorLine
294
+ }
295
+ ),
296
+ filing === "filed" && /* @__PURE__ */ jsx("p", { className: "-mt-1 mb-1 basis-full text-xs", children: reference ? text.reportedAs(reference) : text.reported }),
297
+ mode === "error" ? [retryButton, reloadButton] : [reloadButton, retryButton],
298
+ copyReport && reportText !== null && filing !== "filed" && /* @__PURE__ */ jsx(CopyButton, { variant: "label", buttonVariant: "ghost", label: text.copyReport, text: reportText }),
299
+ actions,
300
+ showDetails && reportText !== null && /* @__PURE__ */ jsx(Disclosure, { variant: "bare", title: text.details, className: "basis-full text-start", children: /* @__PURE__ */ jsx("pre", { className: "max-h-60 overflow-auto whitespace-pre-wrap break-words text-xs text-secondary", children: reportText }) })
301
+ ] })
302
+ }
303
+ )
304
+ ] });
298
305
  }
299
306
  export {
300
307
  DEFAULT_ERROR_BOUNDARY_LABELS,