@konce-pt/react 0.11.2 → 0.14.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 (382) hide show
  1. package/README.md +128 -64
  2. package/dist/accordion/accordion.d.ts +14 -6
  3. package/dist/accordion/accordion.js +25 -17
  4. package/dist/accordion/llms.txt +22 -10
  5. package/dist/alert/alert.d.ts +2 -2
  6. package/dist/alert/alert.js +3 -2
  7. package/dist/alert/llms.txt +10 -9
  8. package/dist/app-shell/app-shell.d.ts +14 -14
  9. package/dist/app-shell/app-shell.js +22 -15
  10. package/dist/app-shell/llms.txt +16 -15
  11. package/dist/auth/auth-types.d.ts +6 -6
  12. package/dist/auth/auth.d.ts +2 -2
  13. package/dist/auth/auth.js +24 -15
  14. package/dist/auth/llms.txt +12 -11
  15. package/dist/autocomplete/autocomplete.d.ts +19 -6
  16. package/dist/autocomplete/autocomplete.js +32 -11
  17. package/dist/autocomplete/llms.txt +19 -5
  18. package/dist/avatar/avatar.d.ts +6 -6
  19. package/dist/avatar/avatar.js +6 -5
  20. package/dist/avatar/llms.txt +10 -10
  21. package/dist/avatar-group/avatar-group.d.ts +4 -4
  22. package/dist/avatar-group/avatar-group.js +4 -3
  23. package/dist/avatar-group/llms.txt +8 -8
  24. package/dist/backdrop/backdrop.d.ts +7 -26
  25. package/dist/backdrop/backdrop.js +32 -27
  26. package/dist/backdrop/llms.txt +27 -27
  27. package/dist/badge/badge.d.ts +3 -3
  28. package/dist/badge/badge.js +1 -1
  29. package/dist/badge/llms.txt +11 -11
  30. package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
  31. package/dist/bottom-sheet/bottom-sheet.js +5 -4
  32. package/dist/bottom-sheet/llms.txt +11 -8
  33. package/dist/breadcrumb/breadcrumb.d.ts +8 -2
  34. package/dist/breadcrumb/breadcrumb.js +11 -3
  35. package/dist/breadcrumb/llms.txt +10 -2
  36. package/dist/button/button.d.ts +3 -3
  37. package/dist/button/button.js +10 -9
  38. package/dist/button/llms.txt +27 -19
  39. package/dist/button-group/button-group.d.ts +18 -5
  40. package/dist/button-group/button-group.js +54 -6
  41. package/dist/button-group/llms.txt +27 -18
  42. package/dist/card/card.d.ts +8 -8
  43. package/dist/card/card.js +10 -9
  44. package/dist/card/llms.txt +20 -20
  45. package/dist/carousel/carousel.d.ts +6 -6
  46. package/dist/carousel/carousel.js +8 -5
  47. package/dist/carousel/llms.txt +10 -10
  48. package/dist/charts/chart-legend.d.ts +3 -3
  49. package/dist/charts/chart-legend.js +2 -1
  50. package/dist/charts/chart-tooltip.d.ts +3 -3
  51. package/dist/charts/chart-tooltip.js +1 -1
  52. package/dist/charts/chart.d.ts +4 -3
  53. package/dist/charts/chart.js +18 -10
  54. package/dist/charts/llms.txt +10 -7
  55. package/dist/charts-entry/public-api.js +2 -2
  56. package/dist/chat/chat.d.ts +17 -10
  57. package/dist/chat/chat.js +77 -23
  58. package/dist/chat/llms.txt +39 -15
  59. package/dist/chat-composer/chat-composer.d.ts +20 -7
  60. package/dist/chat-composer/chat-composer.js +29 -7
  61. package/dist/chat-composer/llms.txt +20 -11
  62. package/dist/chat-dock/chat-dock.d.ts +11 -4
  63. package/dist/chat-dock/chat-dock.js +10 -6
  64. package/dist/chat-dock/llms.txt +15 -14
  65. package/dist/chat-entry/public-api.js +1 -1
  66. package/dist/chat-message/chat-message.d.ts +12 -5
  67. package/dist/chat-message/chat-message.js +19 -8
  68. package/dist/chat-message/llms.txt +16 -15
  69. package/dist/chat-typing/chat-typing.d.ts +2 -2
  70. package/dist/chat-typing/chat-typing.js +4 -3
  71. package/dist/chat-typing/llms.txt +6 -6
  72. package/dist/checkbox/checkbox.d.ts +13 -6
  73. package/dist/checkbox/checkbox.js +31 -5
  74. package/dist/checkbox/llms.txt +26 -11
  75. package/dist/chip/chip.d.ts +4 -4
  76. package/dist/chip/chip.js +3 -2
  77. package/dist/chip/llms.txt +11 -11
  78. package/dist/chips-input/chips-input.d.ts +6 -4
  79. package/dist/chips-input/chips-input.js +47 -12
  80. package/dist/chips-input/llms.txt +18 -8
  81. package/dist/clock/clock.d.ts +11 -6
  82. package/dist/clock/clock.js +38 -8
  83. package/dist/clock/llms.txt +12 -8
  84. package/dist/color-picker/color-picker.d.ts +9 -5
  85. package/dist/color-picker/color-picker.js +37 -18
  86. package/dist/color-picker/llms.txt +8 -5
  87. package/dist/confirm/confirm-container.d.ts +3 -3
  88. package/dist/confirm/confirm-container.js +6 -5
  89. package/dist/confirm/confirm-store.d.ts +4 -4
  90. package/dist/confirm/confirm-store.js +11 -5
  91. package/dist/confirm/llms.txt +8 -7
  92. package/dist/context-menu/context-menu.d.ts +1 -1
  93. package/dist/context-menu/context-menu.js +37 -14
  94. package/dist/context-menu/llms.txt +10 -7
  95. package/dist/data-table/data-table-types.d.ts +5 -5
  96. package/dist/data-table/data-table.d.ts +37 -5
  97. package/dist/data-table/data-table.js +426 -119
  98. package/dist/data-table/export-csv.d.ts +3 -3
  99. package/dist/data-table/export-csv.js +8 -10
  100. package/dist/data-table/llms.txt +127 -79
  101. package/dist/data-view/data-view.d.ts +13 -5
  102. package/dist/data-view/data-view.js +68 -6
  103. package/dist/data-view/llms.txt +29 -10
  104. package/dist/date-range/date-range.d.ts +20 -8
  105. package/dist/date-range/date-range.js +86 -63
  106. package/dist/date-range/llms.txt +32 -18
  107. package/dist/datepicker/datepicker.d.ts +22 -8
  108. package/dist/datepicker/datepicker.js +103 -71
  109. package/dist/datepicker/llms.txt +36 -22
  110. package/dist/dialog/dialog.d.ts +4 -4
  111. package/dist/dialog/dialog.js +32 -11
  112. package/dist/dialog/llms.txt +13 -10
  113. package/dist/divider/divider.d.ts +7 -1
  114. package/dist/divider/divider.js +3 -2
  115. package/dist/divider/llms.txt +4 -3
  116. package/dist/drawer/drawer.d.ts +9 -4
  117. package/dist/drawer/drawer.js +5 -4
  118. package/dist/drawer/llms.txt +13 -10
  119. package/dist/empty/empty.d.ts +2 -2
  120. package/dist/empty/empty.js +1 -1
  121. package/dist/empty/llms.txt +9 -9
  122. package/dist/fab/fab.d.ts +1 -1
  123. package/dist/fab/fab.js +1 -1
  124. package/dist/fab/llms.txt +10 -6
  125. package/dist/fieldset/fieldset.d.ts +18 -4
  126. package/dist/fieldset/fieldset.js +12 -6
  127. package/dist/fieldset/llms.txt +26 -9
  128. package/dist/file-upload/file-upload.d.ts +8 -2
  129. package/dist/file-upload/file-upload.js +22 -11
  130. package/dist/file-upload/llms.txt +12 -9
  131. package/dist/form-field/form-field-context.d.ts +4 -4
  132. package/dist/form-field/form-field.d.ts +12 -4
  133. package/dist/form-field/form-field.js +27 -6
  134. package/dist/form-field/llms.txt +25 -11
  135. package/dist/galleria/galleria.d.ts +3 -3
  136. package/dist/galleria/galleria.js +9 -6
  137. package/dist/galleria/llms.txt +7 -7
  138. package/dist/grid/col.d.ts +4 -4
  139. package/dist/grid/col.js +2 -2
  140. package/dist/grid/flex.d.ts +3 -3
  141. package/dist/grid/flex.js +1 -1
  142. package/dist/grid/grid.d.ts +7 -7
  143. package/dist/grid/grid.js +3 -3
  144. package/dist/grid/layout.d.ts +2 -2
  145. package/dist/grid/layout.js +2 -2
  146. package/dist/grid/llms.txt +15 -15
  147. package/dist/grid-entry/public-api.js +1 -1
  148. package/dist/i18n/i18n-context.d.ts +6 -6
  149. package/dist/i18n/i18n-context.js +27 -5
  150. package/dist/icon/icon-registry.d.ts +3 -3
  151. package/dist/icon/icon-registry.js +3 -3
  152. package/dist/icon/icon.d.ts +4 -4
  153. package/dist/icon/icon.js +10 -7
  154. package/dist/icon/llms.txt +13 -13
  155. package/dist/icon-button/icon-button.d.ts +2 -2
  156. package/dist/icon-button/icon-button.js +1 -1
  157. package/dist/icon-button/llms.txt +9 -5
  158. package/dist/icons-entry/public-api.d.ts +2 -2
  159. package/dist/icons-entry/public-api.js +3 -3
  160. package/dist/image/image.js +5 -5
  161. package/dist/image/llms.txt +13 -13
  162. package/dist/input/input.d.ts +18 -5
  163. package/dist/input/input.js +22 -6
  164. package/dist/input/llms.txt +25 -11
  165. package/dist/input-mask/input-mask.d.ts +7 -2
  166. package/dist/input-mask/input-mask.js +17 -43
  167. package/dist/input-mask/llms.txt +8 -5
  168. package/dist/input-number/input-number.d.ts +11 -9
  169. package/dist/input-number/input-number.js +25 -21
  170. package/dist/input-number/llms.txt +17 -14
  171. package/dist/input-otp/input-otp.d.ts +18 -5
  172. package/dist/input-otp/input-otp.js +48 -24
  173. package/dist/input-otp/llms.txt +18 -7
  174. package/dist/internal/calendar-focus.d.ts +1 -1
  175. package/dist/internal/calendar-focus.js +3 -3
  176. package/dist/internal/cn.d.ts +1 -1
  177. package/dist/internal/mask.d.ts +14 -0
  178. package/dist/internal/mask.js +62 -0
  179. package/dist/internal/number-group.d.ts +22 -0
  180. package/dist/internal/number-group.js +53 -0
  181. package/dist/internal/option-key.d.ts +6 -0
  182. package/dist/internal/option-key.js +8 -0
  183. package/dist/internal/option-nav.d.ts +4 -4
  184. package/dist/internal/option-nav.js +5 -5
  185. package/dist/internal/overlay-container.js +1 -1
  186. package/dist/internal/overlay.d.ts +3 -3
  187. package/dist/internal/overlay.js +40 -10
  188. package/dist/internal/password-strength.d.ts +6 -0
  189. package/dist/internal/password-strength.js +74 -0
  190. package/dist/internal/roving.d.ts +2 -2
  191. package/dist/internal/roving.js +3 -3
  192. package/dist/internal/scroll-lock.d.ts +6 -0
  193. package/dist/internal/scroll-lock.js +35 -0
  194. package/dist/internal/slot-children.d.ts +13 -0
  195. package/dist/internal/slot-children.js +31 -0
  196. package/dist/internal/slot.d.ts +3 -3
  197. package/dist/internal/slot.js +2 -2
  198. package/dist/internal/step.d.ts +12 -0
  199. package/dist/internal/step.js +31 -0
  200. package/dist/internal/tween.d.ts +5 -5
  201. package/dist/internal/tween.js +7 -8
  202. package/dist/internal/types.d.ts +2 -2
  203. package/dist/internal/use-breakpoint.d.ts +2 -2
  204. package/dist/internal/use-breakpoint.js +4 -4
  205. package/dist/internal/use-controllable-state.d.ts +5 -0
  206. package/dist/internal/use-controllable-state.js +25 -4
  207. package/dist/internal/use-id.d.ts +2 -2
  208. package/dist/internal/use-id.js +2 -2
  209. package/dist/internal/use-modal-focus.d.ts +2 -1
  210. package/dist/internal/use-modal-focus.js +14 -3
  211. package/dist/knob/knob.d.ts +7 -4
  212. package/dist/knob/knob.js +27 -22
  213. package/dist/knob/llms.txt +18 -11
  214. package/dist/listbox/listbox.d.ts +8 -6
  215. package/dist/listbox/listbox.js +37 -17
  216. package/dist/listbox/llms.txt +12 -9
  217. package/dist/loader/llms.txt +56 -0
  218. package/dist/loader/loader.d.ts +49 -0
  219. package/dist/loader/loader.js +68 -0
  220. package/dist/map/llms.txt +30 -23
  221. package/dist/map/map-create-dialog.d.ts +4 -4
  222. package/dist/map/map-create-dialog.js +36 -28
  223. package/dist/map/map-hours-field.d.ts +4 -4
  224. package/dist/map/map-hours-field.js +8 -7
  225. package/dist/map/map-image-field.d.ts +2 -2
  226. package/dist/map/map-image-field.js +6 -5
  227. package/dist/map/map-legend.d.ts +4 -4
  228. package/dist/map/map-legend.js +3 -2
  229. package/dist/map/map-poi-card.d.ts +3 -3
  230. package/dist/map/map-poi-card.js +10 -9
  231. package/dist/map/map-search.d.ts +17 -6
  232. package/dist/map/map-search.js +70 -43
  233. package/dist/map/map.d.ts +25 -13
  234. package/dist/map/map.js +86 -57
  235. package/dist/map/ports.d.ts +9 -9
  236. package/dist/map/ports.js +6 -6
  237. package/dist/map-entry/public-api.js +2 -2
  238. package/dist/megamenu/llms.txt +18 -7
  239. package/dist/megamenu/megamenu.d.ts +12 -6
  240. package/dist/megamenu/megamenu.js +23 -14
  241. package/dist/mention/llms.txt +15 -15
  242. package/dist/mention/mention.d.ts +5 -5
  243. package/dist/mention/mention.js +2 -2
  244. package/dist/mention/mentions.d.ts +1 -1
  245. package/dist/mention/mentions.js +1 -1
  246. package/dist/menu/llms.txt +12 -12
  247. package/dist/menu/menu-item.d.ts +4 -4
  248. package/dist/menu/menu-keys.d.ts +2 -2
  249. package/dist/menu/menu-keys.js +5 -5
  250. package/dist/menu/menu-rows.js +1 -0
  251. package/dist/menu/menu.d.ts +2 -2
  252. package/dist/menu/menu.js +15 -8
  253. package/dist/menubar/llms.txt +19 -8
  254. package/dist/menubar/menubar.d.ts +11 -5
  255. package/dist/menubar/menubar.js +23 -11
  256. package/dist/meter-group/llms.txt +12 -12
  257. package/dist/meter-group/meter-group.d.ts +2 -2
  258. package/dist/meter-group/meter-group.js +2 -1
  259. package/dist/motion/motion-context.d.ts +22 -0
  260. package/dist/motion/motion-context.js +28 -0
  261. package/dist/order-list/llms.txt +24 -9
  262. package/dist/order-list/order-list.d.ts +12 -4
  263. package/dist/order-list/order-list.js +123 -25
  264. package/dist/paginator/llms.txt +8 -8
  265. package/dist/paginator/paginator.js +7 -4
  266. package/dist/panel/llms.txt +25 -13
  267. package/dist/panel/panel.d.ts +11 -3
  268. package/dist/panel/panel.js +12 -7
  269. package/dist/password/llms.txt +19 -7
  270. package/dist/password/password.d.ts +2 -2
  271. package/dist/password/password.js +27 -16
  272. package/dist/peek/llms.txt +11 -11
  273. package/dist/peek/peek.d.ts +6 -6
  274. package/dist/peek/peek.js +41 -19
  275. package/dist/pick-list/llms.txt +35 -12
  276. package/dist/pick-list/pick-list.d.ts +12 -4
  277. package/dist/pick-list/pick-list.js +128 -24
  278. package/dist/popover/llms.txt +13 -10
  279. package/dist/popover/popover.d.ts +6 -4
  280. package/dist/popover/popover.js +14 -7
  281. package/dist/progress/llms.txt +17 -17
  282. package/dist/progress/progress.d.ts +7 -7
  283. package/dist/progress/progress.js +7 -6
  284. package/dist/public-api.d.ts +16 -4
  285. package/dist/public-api.js +13 -7
  286. package/dist/radio-group/llms.txt +16 -6
  287. package/dist/radio-group/radio-group.d.ts +12 -3
  288. package/dist/radio-group/radio-group.js +23 -4
  289. package/dist/rating/llms.txt +20 -13
  290. package/dist/rating/rating-pointer.d.ts +16 -0
  291. package/dist/rating/rating-pointer.js +26 -0
  292. package/dist/rating/rating.d.ts +6 -6
  293. package/dist/rating/rating.js +77 -12
  294. package/dist/rich-text/lists.d.ts +2 -2
  295. package/dist/rich-text/lists.js +7 -7
  296. package/dist/rich-text/llms.txt +35 -12
  297. package/dist/rich-text/rich-text.d.ts +13 -14
  298. package/dist/rich-text/rich-text.js +311 -142
  299. package/dist/rich-text/sanitize.d.ts +11 -2
  300. package/dist/rich-text/sanitize.js +80 -32
  301. package/dist/rich-text/tables.d.ts +3 -3
  302. package/dist/rich-text/tables.js +3 -3
  303. package/dist/roadmap/llms.txt +23 -17
  304. package/dist/roadmap/roadmap.d.ts +6 -6
  305. package/dist/roadmap/roadmap.js +102 -25
  306. package/dist/roadmap-entry/public-api.js +2 -2
  307. package/dist/scroll-top/llms.txt +6 -6
  308. package/dist/scroll-top/scroll-top.d.ts +1 -1
  309. package/dist/scroll-top/scroll-top.js +2 -1
  310. package/dist/select/llms.txt +22 -12
  311. package/dist/select/select.d.ts +10 -8
  312. package/dist/select/select.js +87 -47
  313. package/dist/shared/types.d.ts +22 -1
  314. package/dist/shared/types.js +9 -1
  315. package/dist/sidenav/llms.txt +9 -9
  316. package/dist/sidenav/sidenav.d.ts +2 -3
  317. package/dist/sidenav/sidenav.js +5 -4
  318. package/dist/skeleton/llms.txt +3 -3
  319. package/dist/skeleton/skeleton.d.ts +1 -1
  320. package/dist/skeleton/skeleton.js +1 -1
  321. package/dist/slider/llms.txt +34 -12
  322. package/dist/slider/slider-drag.d.ts +26 -0
  323. package/dist/slider/slider-drag.js +79 -0
  324. package/dist/slider/slider.d.ts +8 -5
  325. package/dist/slider/slider.js +38 -8
  326. package/dist/speech/llms.txt +97 -0
  327. package/dist/speech/speech-button.d.ts +44 -0
  328. package/dist/speech/speech-button.js +86 -0
  329. package/dist/speech/speech-wave.d.ts +19 -0
  330. package/dist/speech/speech-wave.js +16 -0
  331. package/dist/speech/use-speech-recognition.d.ts +81 -0
  332. package/dist/speech/use-speech-recognition.js +179 -0
  333. package/dist/speed-dial/llms.txt +14 -8
  334. package/dist/speed-dial/speed-dial.d.ts +1 -1
  335. package/dist/speed-dial/speed-dial.js +3 -2
  336. package/dist/spinner/llms.txt +7 -7
  337. package/dist/spinner/spinner.d.ts +1 -1
  338. package/dist/spinner/spinner.js +2 -1
  339. package/dist/split-button/llms.txt +21 -15
  340. package/dist/split-button/split-button.d.ts +2 -2
  341. package/dist/split-button/split-button.js +13 -6
  342. package/dist/splitter/llms.txt +11 -11
  343. package/dist/splitter/splitter.d.ts +3 -3
  344. package/dist/splitter/splitter.js +25 -10
  345. package/dist/stepper/llms.txt +35 -13
  346. package/dist/stepper/stepper.d.ts +6 -6
  347. package/dist/stepper/stepper.js +60 -13
  348. package/dist/switch/llms.txt +15 -5
  349. package/dist/switch/switch.d.ts +10 -3
  350. package/dist/switch/switch.js +18 -4
  351. package/dist/switch-group/llms.txt +11 -8
  352. package/dist/switch-group/switch-group.d.ts +6 -4
  353. package/dist/switch-group/switch-group.js +9 -7
  354. package/dist/tabs/llms.txt +12 -9
  355. package/dist/tabs/tabs.d.ts +5 -5
  356. package/dist/tabs/tabs.js +36 -20
  357. package/dist/textarea/llms.txt +23 -12
  358. package/dist/textarea/textarea.d.ts +19 -6
  359. package/dist/textarea/textarea.js +22 -7
  360. package/dist/timeline/llms.txt +4 -4
  361. package/dist/timeline/timeline.d.ts +1 -1
  362. package/dist/timeline/timeline.js +1 -1
  363. package/dist/toast/llms.txt +50 -17
  364. package/dist/toast/toast-container.d.ts +9 -3
  365. package/dist/toast/toast-container.js +18 -9
  366. package/dist/toast/toast-store.d.ts +42 -2
  367. package/dist/toast/toast-store.js +36 -1
  368. package/dist/toolbar/llms.txt +7 -7
  369. package/dist/toolbar/toolbar.d.ts +3 -3
  370. package/dist/toolbar/toolbar.js +2 -2
  371. package/dist/tooltip/llms.txt +14 -12
  372. package/dist/tooltip/tooltip.d.ts +5 -4
  373. package/dist/tooltip/tooltip.js +100 -41
  374. package/dist/tree/llms.txt +25 -11
  375. package/dist/tree/tree-keys.d.ts +5 -5
  376. package/dist/tree/tree-keys.js +7 -7
  377. package/dist/tree/tree.d.ts +17 -5
  378. package/dist/tree/tree.js +62 -20
  379. package/dist/update/llms.txt +54 -0
  380. package/dist/update/update.d.ts +49 -0
  381. package/dist/update/update.js +82 -0
  382. package/package.json +18 -15
@@ -1,6 +1,7 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
3
- import { buildRangeGrid, clampVisibleMonths, datePart, formatDate, formatTime, initialFocusDate, moveFocusDate, pad, parseDate, parseTime, pickRangeDay, timePart, toIso, } from '@konce-pt/datetime';
3
+ import { useEffect, useEffectEvent, useRef, useState, } from 'react';
4
+ import { buildRangeGrid, clampVisibleMonths, datePart, dayPeriodLabels, displayDate, formatTime, kptFirstDayOfWeek, orderWeekdays, initialFocusDate, moveFocusDate, pad, parseDate, parseTime, pickRangeDay, timePart, toIso, } from '@konce-pt/datetime';
4
5
  import { monthNames, weekdayNames } from '@konce-pt/i18n';
5
6
  import { cn } from "../internal/cn.js";
6
7
  import { useControllableState } from "../internal/use-controllable-state.js";
@@ -18,43 +19,49 @@ const EMPTY_RANGE = { start: '', end: '' };
18
19
  * `visibleMonths` pokazuje kilka miesięcy obok siebie, a zakres podświetla się ciągłym pasmem
19
20
  * przez wszystkie panele.
20
21
  *
21
- * Klawiatura jak w `KptDatepicker`: `Enter`/`Spacja`/`↓` otwierają panel z fokusem na początku
22
- * zakresu (albo dziś), strzałki, `Home`/`End` i `PageUp`/`PageDown` (z `Shift` — rok) chodzą po
22
+ * Klawiatura jak w `KptDatepicker`: `Enter`/`Spacja`/`ArrowDown` otwierają panel z fokusem na początku
23
+ * zakresu (albo dziś), strzałki, `Home`/`End` i `PageUp`/`PageDown` (z `Shift` - rok) chodzą po
23
24
  * dniach przez wszystkie panele, `Tab` krąży w panelu, `Escape` i wybór końca oddają fokus polu.
24
- * Krańce i środek zakresu są w nazwie dnia („…, początek zakresu”), a wybór ogłasza region `polite`.
25
+ * Krańce i środek zakresu są w nazwie dnia ("..., początek zakresu"), a wybór i przewinięcie miesiąca
26
+ * ogłasza region `polite`. Pole to `role="combobox"` z `aria-haspopup="dialog"`, więc niesie
27
+ * `aria-required`, `aria-readonly` i `aria-invalid`. Tydzień zaczyna się wg aktywnego języka.
25
28
  *
26
29
  * @example
27
30
  * <KptDateRange value={period} onValueChange={setPeriod} visibleMonths={2} />
28
31
  * <KptDateRange mode="datetime" hourFormat={12} value={span} onValueChange={setSpan} />
29
32
  */
30
- export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange, mode = 'date', visibleMonths = 1, hourFormat = 24, minuteStep = 1, placeholder, displayFormat = 'pl', minDate = null, maxDate = null, ariaLabel = null, id, disabled = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
33
+ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange, mode = 'date', visibleMonths = 1, hourFormat = 24, minuteStep = 1, placeholder, displayFormat = 'pl', firstDayOfWeek = null, open, onOpenChange, minDate = null, maxDate = null, ariaLabel = null, id, disabled = false, readOnly = false, required = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
31
34
  const { t, locale: activeLocale } = useKptMessages({ locale, dictionary });
32
- /** `div` z rolą nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
35
+ /** `div` z rolą nie dostaje nazwy z `label[for]` - stąd `aria-labelledby` na etykietę wrappera. */
33
36
  const field = useKptFieldA11y(id, 'kpt-date-range');
34
37
  const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
35
- const [isOpen, setOpen] = useState(false);
38
+ const [isOpen, setOpen] = useControllableState({ value: open, defaultValue: false, onChange: onOpenChange });
36
39
  const [anchor, setAnchor] = useState(null);
37
40
  const triggerRef = useRef(null);
38
41
  const panelRef = useRef(null);
39
42
  const panelId = useKptId(undefined, 'kpt-date-range-panel');
40
- /** Dzień z fokusem — jedyny przystanek Tab siatek dni (roving tabindex przez wszystkie panele). */
43
+ /** Dzień z fokusem - jedyny przystanek Tab siatek dni (roving tabindex przez wszystkie panele). */
41
44
  const [focusIso, setFocusIso] = useState('');
42
45
  /** Komunikat regionu `polite` po wyborze początku i całego zakresu. */
43
46
  const [announcement, setAnnouncement] = useState('');
44
- /** Prośba o przeniesienie fokusu po najbliższym renderze (otwarcie, ruch klawiszem). */
45
- const wantFocus = useRef(false);
46
- const today = useRef(new Date()).current;
47
+ /** Prośba o przeniesienie fokusu po najbliższym renderze (otwarcie, ruch klawiszem) - licznik w stanie. */
48
+ const [focusRequest, setFocusRequest] = useState(0);
49
+ const requestFocus = () => setFocusRequest((n) => n + 1);
50
+ /** "Dziś" liczone przy każdym otwarciu - panel otwarty po północy nie pokazuje wczorajszego dnia. */
51
+ const [today, setToday] = useState(() => new Date());
47
52
  const todayIso = toIso(today);
53
+ const firstDay = firstDayOfWeek ?? kptFirstDayOfWeek(activeLocale);
54
+ const periods = dayPeriodLabels(activeLocale);
48
55
  const showInvalid = invalid && (touched ?? true);
49
56
  const [page, setPage] = useState(() => ({ y: today.getFullYear(), m: today.getMonth() }));
50
57
  const [startTime, setStartTime] = useState('');
51
58
  const [endTime, setEndTime] = useState('');
52
59
  const [timeEnd, setTimeEnd] = useState('start');
53
- // Część kalendarzowa zakresu w trybie datetime — wartość powstaje dopiero przy „Gotowe".
60
+ // Część kalendarzowa zakresu w trybie datetime - wartość powstaje dopiero przy "Gotowe".
54
61
  const [startDate, setStartDate] = useState('');
55
62
  const [endDate, setEndDate] = useState('');
56
63
  const months = monthNames(activeLocale);
57
- const weekdays = weekdayNames(activeLocale);
64
+ const weekdays = orderWeekdays(weekdayNames(activeLocale), firstDay);
58
65
  const panelCount = mode === 'time' ? 1 : clampVisibleMonths(visibleMonths);
59
66
  const multi = panelCount > 1;
60
67
  const dayFormat = new Intl.DateTimeFormat(activeLocale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
@@ -62,7 +69,7 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
62
69
  const date = parseDate(iso);
63
70
  return date ? dayFormat.format(date) : iso;
64
71
  };
65
- /** Pełna nazwa dnia z rolą w zakresie — kolor pasma nie jest jedynym nośnikiem informacji. */
72
+ /** Pełna nazwa dnia z rolą w zakresie - kolor pasma nie jest jedynym nośnikiem informacji. */
66
73
  const dayLabel = (cell) => {
67
74
  const name = dayName(cell.iso);
68
75
  if (cell.isStart)
@@ -75,49 +82,58 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
75
82
  };
76
83
  const fmtTime = (hhmm) => {
77
84
  const parsed = parseTime(hhmm);
78
- return parsed ? formatTime(parsed.h, parsed.m, hourFormat) : '';
85
+ return parsed ? formatTime(parsed.h, parsed.m, hourFormat, periods) : '';
79
86
  };
80
87
  const display = (() => {
81
88
  const { start, end } = current;
82
89
  if (!start)
83
90
  return '';
84
91
  if (mode === 'time') {
85
- return end ? `${fmtTime(start)} – ${fmtTime(end)}` : `${fmtTime(start)} – …`;
92
+ return end ? `${fmtTime(start)} - ${fmtTime(end)}` : `${fmtTime(start)} - ...`;
86
93
  }
87
94
  if (mode === 'datetime') {
88
95
  const one = (v) => {
89
- const date = formatDate(datePart(v), displayFormat);
96
+ const date = displayDate(datePart(v), displayFormat, activeLocale);
90
97
  const time = fmtTime(timePart(v));
91
98
  return time ? `${date} ${time}` : date;
92
99
  };
93
- return end ? `${one(start)} – ${one(end)}` : `${one(start)} – …`;
100
+ return end ? `${one(start)} - ${one(end)}` : `${one(start)} - ...`;
94
101
  }
95
- return end
96
- ? `${formatDate(start, displayFormat)} – ${formatDate(end, displayFormat)}`
97
- : `${formatDate(start, displayFormat)} – …`;
102
+ const fmt = (iso) => displayDate(iso, displayFormat, activeLocale);
103
+ return end ? `${fmt(start)} - ${fmt(end)}` : `${fmt(start)} - ...`;
98
104
  })();
105
+ // Panel otwiera też `open` z zewnątrz - stan początkowy liczymy przy każdym przejściu w stan
106
+ // otwarty, wzorcem "poprzednia wartość w stanie" (bez efektu i klatki ze starym widokiem).
107
+ const [wasOpen, setWasOpen] = useState(isOpen);
108
+ if (wasOpen !== isOpen) {
109
+ setWasOpen(isOpen);
110
+ if (isOpen)
111
+ prepareOpen();
112
+ }
113
+ function prepareOpen() {
114
+ const now = new Date();
115
+ setToday(now);
116
+ const { start, end } = current;
117
+ const focus = initialFocusDate(datePart(start), toIso(now), minDate, maxDate);
118
+ setFocusIso(focus);
119
+ setAnnouncement('');
120
+ setPage({ y: +focus.slice(0, 4), m: +focus.slice(5, 7) - 1 });
121
+ requestFocus();
122
+ if (mode === 'datetime') {
123
+ setStartDate(datePart(start));
124
+ setEndDate(datePart(end));
125
+ setStartTime(timePart(start) || '00:00');
126
+ setEndTime(timePart(end) || '00:00');
127
+ }
128
+ else if (mode === 'time') {
129
+ setStartTime(/^\d{2}:\d{2}$/.test(start) ? start : '00:00');
130
+ setEndTime(/^\d{2}:\d{2}$/.test(end) ? end : '00:00');
131
+ }
132
+ setTimeEnd('start');
133
+ }
99
134
  const toggleOpen = () => {
100
- if (disabled)
135
+ if (disabled || readOnly)
101
136
  return;
102
- if (!isOpen) {
103
- const { start, end } = current;
104
- const focus = initialFocusDate(datePart(start), todayIso, minDate, maxDate);
105
- setFocusIso(focus);
106
- setAnnouncement('');
107
- setPage({ y: +focus.slice(0, 4), m: +focus.slice(5, 7) - 1 });
108
- wantFocus.current = true;
109
- if (mode === 'datetime') {
110
- setStartDate(datePart(start));
111
- setEndDate(datePart(end));
112
- setStartTime(timePart(start) || '00:00');
113
- setEndTime(timePart(end) || '00:00');
114
- }
115
- else if (mode === 'time') {
116
- setStartTime(/^\d{2}:\d{2}$/.test(start) ? start : '00:00');
117
- setEndTime(/^\d{2}:\d{2}$/.test(end) ? end : '00:00');
118
- }
119
- setTimeEnd('start');
120
- }
121
137
  setOpen(!isOpen);
122
138
  };
123
139
  const close = () => {
@@ -126,22 +142,20 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
126
142
  setOpen(false);
127
143
  onTouch?.();
128
144
  };
129
- /** Zamknięcie z powrotem fokusu na pole — po wyborze z klawiatury, `Escape`. */
145
+ /** Zamknięcie z powrotem fokusu na pole - po wyborze z klawiatury, `Escape`. */
130
146
  const closeAndFocus = () => {
131
147
  close();
132
148
  triggerRef.current?.focus();
133
149
  };
134
- // Fokus po renderze. Panel w nakładce jest niewidoczny do pierwszego pomiaru — stąd rAF.
150
+ // Fokus po renderze. Panel w nakładce jest niewidoczny do pierwszego pomiaru - stąd rAF.
151
+ const focusActive = useEffectEvent(() => focusCalendarActive(panelRef.current, focusIso));
135
152
  useEffect(() => {
136
- if (!isOpen || !wantFocus.current)
153
+ if (!isOpen || focusRequest === 0)
137
154
  return;
138
- const frame = requestAnimationFrame(() => {
139
- wantFocus.current = false;
140
- focusCalendarActive(panelRef.current, focusIso);
141
- });
155
+ const frame = requestAnimationFrame(() => focusActive());
142
156
  return () => cancelAnimationFrame(frame);
143
- });
144
- /** Przesuwa okno paneli tak, żeby miesiąc dnia `iso` był widoczny — z najmniejszym skokiem. */
157
+ }, [focusRequest, isOpen]);
158
+ /** Przesuwa okno paneli tak, żeby miesiąc dnia `iso` był widoczny - z najmniejszym skokiem. */
145
159
  const revealMonth = (iso) => {
146
160
  const target = +iso.slice(0, 4) * 12 + (+iso.slice(5, 7) - 1);
147
161
  const first = page.y * 12 + page.m;
@@ -154,22 +168,27 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
154
168
  };
155
169
  const onDayKeyDown = (event) => {
156
170
  const rtl = !!panelRef.current && getComputedStyle(panelRef.current).direction === 'rtl';
157
- const next = moveFocusDate(focusIso, event.key, { shift: event.shiftKey, rtl, minDate, maxDate });
171
+ const next = moveFocusDate(focusIso, event.key, { shift: event.shiftKey, rtl, minDate, maxDate, firstDay });
158
172
  if (next === null)
159
173
  return;
160
174
  event.preventDefault();
161
175
  setFocusIso(next);
162
176
  revealMonth(next);
163
- wantFocus.current = true;
177
+ requestFocus();
164
178
  };
165
- /** Strzałki ‹ ›: fokus zostaje na strzałce, ale przystanek siatki idzie za stroną. */
179
+ /** Strzałki < >: fokus zostaje na strzałce, ale przystanek siatki idzie za stroną. */
166
180
  const turnPage = (dir) => {
167
181
  const first = page.y * 12 + page.m + dir;
168
182
  setPage({ y: Math.floor(first / 12), m: ((first % 12) + 12) % 12 });
169
- const moved = moveFocusDate(focusIso, dir === 1 ? 'PageDown' : 'PageUp', { minDate, maxDate });
183
+ // Przewinięcie ogłasza widoczne miesiące (APG: `aria-live` na nagłówku).
184
+ setAnnouncement(Array.from({ length: panelCount }, (_, i) => {
185
+ const month = first + i;
186
+ return `${months[((month % 12) + 12) % 12]} ${Math.floor(month / 12)}`;
187
+ }).join(' - '));
188
+ const moved = moveFocusDate(focusIso, dir === 1 ? 'PageDown' : 'PageUp', { minDate, maxDate, firstDay });
170
189
  if (moved) {
171
190
  const target = +moved.slice(0, 4) * 12 + (+moved.slice(5, 7) - 1);
172
- // Nowe okno zaczyna się od `first` — dzień spoza niego nie dostałby przystanku Tab.
191
+ // Nowe okno zaczyna się od `first` - dzień spoza niego nie dostałby przystanku Tab.
173
192
  if (target >= first && target < first + panelCount)
174
193
  setFocusIso(moved);
175
194
  }
@@ -194,6 +213,7 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
194
213
  hideOutside: multi,
195
214
  minDate,
196
215
  maxDate,
216
+ firstDay,
197
217
  }),
198
218
  };
199
219
  });
@@ -204,12 +224,12 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
204
224
  setStartDate(next.start);
205
225
  setEndDate(next.end);
206
226
  announce(next.start, next.end);
207
- return; // czas do wyboru → zamknięcie przez „Gotowe"
227
+ return; // czas do wyboru -> zamknięcie przez "Gotowe"
208
228
  }
209
229
  const next = pickRangeDay(current, iso);
210
230
  setCurrent(next);
211
231
  announce(next.start, next.end);
212
- // Panel zostaje otwarty do czasu domknięcia zakresu — inaczej drugi klik nie miałby gdzie paść.
232
+ // Panel zostaje otwarty do czasu domknięcia zakresu - inaczej drugi klik nie miałby gdzie paść.
213
233
  if (next.end)
214
234
  closeAndFocus();
215
235
  };
@@ -232,17 +252,20 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
232
252
  };
233
253
  const clear = (event) => {
234
254
  event.stopPropagation();
255
+ if (readOnly)
256
+ return;
235
257
  setCurrent(EMPTY_RANGE);
236
258
  setStartDate('');
237
259
  setEndDate('');
260
+ onTouch?.();
238
261
  };
239
262
  const clockValue = timeEnd === 'start' ? startTime : endTime;
240
263
  const setClockValue = timeEnd === 'start' ? setStartTime : setEndTime;
241
264
  return (_jsxs("div", { className: cn('kpt-date-range-host', className), ...rest, children: [_jsxs("div", { ref: (el) => {
242
265
  triggerRef.current = el;
243
266
  setAnchor(el);
244
- }, className: cn('kpt-date-range', isOpen && 'kpt-date-range--open', disabled && 'kpt-date-range--disabled', showInvalid && 'kpt-date-range--invalid'), role: "button", tabIndex: 0, "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, id: field.id, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, "aria-disabled": disabled || undefined, "aria-invalid": showInvalid || undefined, "aria-label": ariaLabel ?? undefined, onClick: toggleOpen, onKeyDown: (event) => {
245
- if (disabled)
267
+ }, className: cn('kpt-date-range', isOpen && 'kpt-date-range--open', disabled && 'kpt-date-range--disabled', readOnly && 'kpt-date-range--readonly', showInvalid && 'kpt-date-range--invalid'), role: "combobox", tabIndex: 0, "aria-keyshortcuts": "Delete Backspace", "aria-required": required || undefined, "aria-readonly": readOnly || undefined, "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, id: field.id, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, "aria-disabled": disabled || undefined, "aria-invalid": showInvalid || undefined, "aria-label": ariaLabel ?? undefined, onClick: toggleOpen, onKeyDown: (event) => {
268
+ if (disabled || readOnly)
246
269
  return;
247
270
  if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
248
271
  event.preventDefault();
@@ -254,8 +277,8 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
254
277
  clear(event);
255
278
  }
256
279
  },
257
- // Przy otwartym panelu fokus idzie do kalendarza — „dotknięcie” wyśle dopiero zamknięcie.
258
- onBlur: () => !isOpen && onTouch?.(), children: [display ? (_jsx("span", { className: "kpt-date-range__value", children: display })) : (_jsx("span", { className: "kpt-date-range__placeholder", children: placeholder ?? t('dateRange.placeholder') })), _jsx("span", { className: "kpt-date-range__spacer" }), display ? (_jsx("button", { type: "button", className: "kpt-date-range__clear", tabIndex: -1, onClick: clear, "aria-label": t('common.clear'), children: _jsx(KptIcon, { name: "x" }) })) : null, _jsx(KptIcon, { className: "kpt-date-range__icon", name: "calendar" })] }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, offset: 4, children: _jsxs("div", { ref: panelRef, id: panelId, role: "dialog", "aria-label": t('dateRange.dialog'), className: cn('kpt-calendar', mode === 'time' && 'kpt-calendar--clock', mode !== 'time' && 'kpt-calendar--range', multi && mode !== 'time' && 'kpt-calendar--multi'), onKeyDown: (event) => {
280
+ // Przy otwartym panelu fokus idzie do kalendarza - "dotknięcie" wyśle dopiero zamknięcie.
281
+ onBlur: () => !isOpen && onTouch?.(), children: [display ? (_jsx("span", { className: "kpt-date-range__value", children: display })) : (_jsx("span", { className: "kpt-date-range__placeholder", children: placeholder ?? t('dateRange.placeholder') })), _jsx("span", { className: "kpt-date-range__spacer" }), display && !readOnly ? (_jsx("button", { type: "button", className: "kpt-date-range__clear", tabIndex: -1, onClick: clear, "aria-label": t('common.clear'), children: _jsx(KptIcon, { name: "x" }) })) : null, _jsx(KptIcon, { className: "kpt-date-range__icon", name: "calendar" })] }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, offset: 4, children: _jsxs("div", { ref: panelRef, id: panelId, role: "dialog", "aria-label": t('dateRange.dialog'), className: cn('kpt-calendar', mode === 'time' && 'kpt-calendar--clock', mode !== 'time' && 'kpt-calendar--range', multi && mode !== 'time' && 'kpt-calendar--multi'), onKeyDown: (event) => {
259
282
  if (event.key === 'Escape') {
260
283
  event.preventDefault();
261
284
  event.stopPropagation();
@@ -265,7 +288,7 @@ export function KptDateRange({ value, defaultValue = EMPTY_RANGE, onValueChange,
265
288
  trapTab(event.currentTarget, event.nativeEvent);
266
289
  }
267
290
  }, children: [_jsx("span", { className: "kpt-calendar__live", "aria-live": "polite", children: announcement }), mode === 'time' ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "kpt-range-tabs", children: [_jsx("button", { type: "button", className: cn(timeEnd === 'start' && 'is-active'), onClick: () => setTimeEnd('start'), children: t('dateRange.from') }), _jsx("button", { type: "button", className: cn(timeEnd === 'end' && 'is-active'), onClick: () => setTimeEnd('end'), children: t('dateRange.to') })] }), _jsx(KptClock
268
- // Klucz na edytowanym końcu wymusza remount przy przełączeniu Od/Koniec — tarcza ma
291
+ // Klucz na edytowanym końcu wymusza remount przy przełączeniu Od/Koniec - tarcza ma
269
292
  // wtedy wrócić do etapu godzin, tak jak dwie osobne instancje w porcie Angulara.
270
293
  , { value: clockValue, onValueChange: setClockValue, hourFormat: hourFormat, minuteStep: minuteStep }, timeEnd), _jsx("div", { className: "kpt-calendar__footer", children: _jsx(KptButton, { size: "sm", onClick: commit, children: t('common.done') }) })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "kpt-calendar__panels", children: panels.map((panel, index) => (_jsxs("div", { className: "kpt-calendar__panel", children: [_jsxs("div", { className: "kpt-calendar__header", children: [index === 0 ? (_jsx("button", { type: "button", className: "kpt-calendar__nav", onClick: () => turnPage(-1), "aria-label": t('datepicker.prevMonth'), children: _jsx(KptIcon, { name: "chevron-left" }) })) : (_jsx("span", { className: "kpt-calendar__nav-slot" })), _jsx("span", { className: "kpt-calendar__title", children: panel.label }), index === panels.length - 1 ? (_jsx("button", { type: "button", className: "kpt-calendar__nav", onClick: () => turnPage(1), "aria-label": t('datepicker.nextMonth'), children: _jsx(KptIcon, { name: "chevron-right" }) })) : (_jsx("span", { className: "kpt-calendar__nav-slot" }))] }), _jsx("div", { className: "kpt-calendar__weekdays", children: weekdays.map((weekday) => (_jsx("span", { className: "kpt-calendar__weekday", children: weekday }, weekday))) }), _jsx("div", { className: "kpt-calendar__grid", onKeyDown: onDayKeyDown, children: panel.weeks.flat().map((cell) => cell.blank ? (_jsx("span", { className: "kpt-calendar__day kpt-calendar__day--blank" }, cell.iso)) : (_jsx("button", { type: "button", className: cn('kpt-calendar__day', !cell.inMonth && 'kpt-calendar__day--muted', cell.today && 'kpt-calendar__day--today', cell.inRange && 'kpt-calendar__day--range', cell.rangeStart && 'kpt-calendar__day--range-start', cell.rangeEnd && 'kpt-calendar__day--range-end', (cell.isStart || cell.isEnd) && 'kpt-calendar__day--selected'), "data-iso": cell.iso, tabIndex: cell.iso === focusIso ? 0 : -1, "aria-label": dayLabel(cell), "aria-current": cell.today ? 'date' : undefined, "aria-pressed": cell.isStart || cell.isEnd, disabled: cell.disabled, onClick: () => selectDay(cell.iso), children: cell.day }, cell.iso))) })] }, panel.key))) }), mode === 'datetime' ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "kpt-range-tabs", children: [_jsx("button", { type: "button", className: cn(timeEnd === 'start' && 'is-active'), onClick: () => setTimeEnd('start'), children: t('dateRange.fromTime') }), _jsx("button", { type: "button", className: cn(timeEnd === 'end' && 'is-active'), onClick: () => setTimeEnd('end'), children: t('dateRange.toTime') })] }), _jsx(KptClock, { value: clockValue, onValueChange: setClockValue, hourFormat: hourFormat, minuteStep: minuteStep }, timeEnd), _jsx("div", { className: "kpt-calendar__footer", children: _jsx(KptButton, { size: "sm", onClick: commit, children: t('common.done') }) })] })) : null] }))] }) })] }));
271
294
  }
@@ -5,49 +5,49 @@ Import: `import { KptDateRange, type KptDateRangeValue } from '@konce-pt/react';
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-date-range-host">
8
- <div class="kpt-date-range" role="button" tabindex="0">
9
- <span class="kpt-date-range__value">08.09.2026 – 14.09.2026</span>
10
- …clear, icon…
8
+ <div class="kpt-date-range" role="combobox" tabindex="0" aria-haspopup="dialog">
9
+ <span class="kpt-date-range__value">08.09.2026 - 14.09.2026</span>
10
+ ...clear, icon...
11
11
  </div>
12
12
  </div>
13
- <!-- in a portal: <div class="kpt-calendar kpt-calendar--range kpt-calendar--multi">…</div> -->
13
+ <!-- in a portal: <div class="kpt-calendar kpt-calendar--range kpt-calendar--multi">...</div> -->
14
14
 
15
15
  ## Props
16
- - `value` / `defaultValue` / `onValueChange` — `{ start, end }`: dates 'YYYY-MM-DD',
16
+ - `value` / `defaultValue` / `onValueChange` - `{ start, end }`: dates 'YYYY-MM-DD',
17
17
  datetime 'YYYY-MM-DDTHH:mm', times 'HH:mm'
18
18
  - `mode`: `'date'` (default) | `'datetime'` | `'time'`
19
- - `visibleMonths`: number (default 1, clamped to 1–3) — months side by side; ignored in 'time' mode
19
+ - `visibleMonths`: number (default 1, clamped to 1-3) - months side by side; ignored in 'time' mode
20
20
  - `hourFormat`: 12 | 24 (default 24); `minuteStep`: number (default 1)
21
- - `placeholder` — without one it falls back to `dateRange.placeholder`
22
- - `displayFormat`: `'pl'` (default) | `'iso'`
21
+ - `placeholder` - without one it falls back to `dateRange.placeholder`
22
+ - `displayFormat`: `'pl'` (default) | `'iso'` | `'locale'`
23
23
  - `minDate`, `maxDate`: 'YYYY-MM-DD' bounds (inclusive); days outside are disabled
24
- - `ariaLabel` — the accessible name when no `<label for>` describes the field
24
+ - `ariaLabel` - the accessible name when no `<label for>` describes the field
25
25
  - `disabled`, `invalid`, `touched`
26
- - `onTouch()` — fires when the panel closes or focus leaves the closed trigger
26
+ - `onTouch()` - fires when the panel closes or focus leaves the closed trigger
27
27
  - `className`, `ref` and every other `<div>` prop go to the host
28
28
 
29
29
  ## Two clicks, one band
30
30
  The first click sets `start`, the second `end`, a third starts over; clicking before the start
31
31
  normalizes the order rather than producing a reversed range (`pickRangeDay` in `@konce-pt/datetime`).
32
- The panel stays open until the range closes — the second click needs somewhere to land.
32
+ The panel stays open until the range closes - the second click needs somewhere to land.
33
33
 
34
34
  With several panels the adjacent-month days become blank slots: otherwise the same date would be
35
35
  clickable twice, and the band would paint in both places.
36
36
 
37
37
  ## Keyboard
38
38
  As in the date picker: the trigger has `aria-haspopup="dialog"` and `aria-expanded`; `Enter`, `Space`
39
- and `↓` open the panel (a `role="dialog"` named "Choose a date range") with focus on the range start,
40
- or today. The arrows, `Home`/`End` and `PageUp`/`PageDown` (with `Shift` — a year) walk the days across
39
+ and `ArrowDown` open the panel (a `role="dialog"` named "Choose a date range") with focus on the range start,
40
+ or today. The arrows, `Home`/`End` and `PageUp`/`PageDown` (with `Shift` - a year) walk the days across
41
41
  every panel, shifting the set of months when focus leaves it. `Tab` cycles inside the panel, `Escape`
42
42
  closes it, and picking the end (or "Done") returns focus to the trigger. `Delete`/`Backspace` on the
43
43
  trigger clears the range.
44
44
 
45
- Each day is named with the full date and its role in the range ("…, start of range", "…, end of range",
46
- "…, in range") — the band colour is not the only carrier. The ends have `aria-pressed`, today has
47
- `aria-current="date"`. After the first pick a polite live region says "Start: … Choose the end date.".
45
+ Each day is named with the full date and its role in the range ("..., start of range", "..., end of range",
46
+ "..., in range") - the band colour is not the only carrier. The ends have `aria-pressed`, today has
47
+ `aria-current="date"`. After the first pick a polite live region says "Start: ... Choose the end date.".
48
48
 
49
49
  ## The clock remounts when the end switches
50
- `key={timeEnd}` on `KptClock`, so the dial returns to the hours stage after the From/To toggle —
50
+ `key={timeEnd}` on `KptClock`, so the dial returns to the hours stage after the From/To toggle -
51
51
  in Angular that came for free from two separate template branches.
52
52
 
53
53
  ## Examples
@@ -60,6 +60,20 @@ in Angular that came for free from two separate template branches.
60
60
  Day and month names come from `Intl`; "From/To", the navigation, "Done" and the placeholder come
61
61
  from the `dateRange`, `datepicker` and `common` namespaces.
62
62
 
63
+ ## Week start, display format and field state
64
+ - The week starts by the active language (`Intl.Locale#getWeekInfo`, with a fallback list of regions):
65
+ en / en-US on Sunday, pl, de, en-GB on Monday. `firstDayOfWeek` (1 = Monday ... 7 = Sunday) overrides it;
66
+ the headers, the grid and `Home`/`End` follow it.
67
+ - `displayFormat`: `'pl'` (DD.MM.YYYY, default), `'iso'` (YYYY-MM-DD) or `'locale'` - order and separators
68
+ from `Intl` (en-US: MM/DD/YYYY). The placeholder follows the format and its letters follow the language
69
+ (EN `YYYY`, PL `RRRR`, the `datepicker.yearToken`/`monthToken`/`dayToken` keys). AM/PM come from `Intl`.
70
+ - The field is `role="combobox"` with `aria-haspopup="dialog"` (the APG select-only combobox), so it carries
71
+ `aria-required` (`required`), `aria-readonly` (`readOnly` - the value shows, the panel does not open,
72
+ there is no clear button) and `aria-invalid`.
73
+ - Turning the page with < > is announced (`aria-live="polite"`); the title buttons are named
74
+ "October, Choose month" - the visible text first (WCAG 2.5.3). Clearing the value counts as a touch.
75
+ - "Today" is computed on every open, so a panel opened after midnight marks the right day.
76
+
63
77
  ## Label and description
64
78
  `id` goes to the focusable element, not the host; without one it comes from `KptFormField` or is
65
79
  generated. A `div` with a role is not named by `label[for]`, so inside `KptFormField` it gets
@@ -71,7 +85,7 @@ The field `--kpt-form-field-*`; the calendar `--kpt-color-surface-raised`, the r
71
85
  `--kpt-color-primary`.
72
86
 
73
87
  ## Accessibility
74
- The trigger is `role="button"` with `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`;
88
+ The trigger is `role="combobox"` with `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`;
75
89
  the panel is a named `role="dialog"`; the days are real buttons named with the date and their range
76
90
  role, and the time ends are switched with a two-button toggle rather than a custom control. The
77
91
  keyboard is described above.
@@ -1,5 +1,5 @@
1
1
  import { type ComponentPropsWithRef } from 'react';
2
- import { type KptCalendarView, type KptDateSelectionMode } from '@konce-pt/datetime';
2
+ import { type KptCalendarView, type KptDateDisplayFormat, type KptDateSelectionMode, type KptFirstDayOfWeek } from '@konce-pt/datetime';
3
3
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
4
4
  export type { KptDateSelectionMode as KptDatepickerMode, KptCalendarView as KptDatepickerView };
5
5
  export interface KptDatepickerProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'>, KptI18nOverrides {
@@ -15,34 +15,48 @@ export interface KptDatepickerProps extends Omit<ComponentPropsWithRef<'div'>, '
15
15
  placeholder?: string;
16
16
  /** Prezentacja miesiąca w trybie 'month' i w etykietach: słownie czy liczbą. */
17
17
  monthDisplay?: 'long' | 'number';
18
- displayFormat?: 'pl' | 'iso';
18
+ /**
19
+ * Zapis daty: `'pl'` (DD.MM.RRRR, domyślnie), `'iso'` albo `'locale'` - kolejność i separatory
20
+ * z `Intl` dla aktywnego języka. Placeholder idzie za formatem, a jego litery za językiem.
21
+ */
22
+ displayFormat?: KptDateDisplayFormat;
23
+ /** Pierwszy dzień tygodnia (1 = poniedziałek ... 7 = niedziela); `null` = wg aktywnego języka. */
24
+ firstDayOfWeek?: KptFirstDayOfWeek | null;
19
25
  hourFormat?: 12 | 24;
20
26
  minuteStep?: number;
21
- /** Stan panelu — pozwala otworzyć kalendarz z zewnątrz i wiedzieć, kiedy wybór się skończył. */
27
+ /** Stan panelu - pozwala otworzyć kalendarz z zewnątrz i wiedzieć, kiedy wybór się skończył. */
22
28
  open?: boolean;
23
29
  onOpenChange?: (open: boolean) => void;
24
30
  /** Nazwa dostępna, gdy pola nie opisuje `<label for>`. */
25
31
  ariaLabel?: string | null;
26
- /** Id pola (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
32
+ /** Id pola (nie hosta); bez niego generowane, w `KptFormField` - z wrappera. */
27
33
  id?: string;
28
34
  disabled?: boolean;
35
+ /** Tylko do odczytu - wartość widać, panel się nie otwiera (`aria-readonly`). */
36
+ readOnly?: boolean;
37
+ /** Pole wymagane - `aria-required`. */
38
+ required?: boolean;
29
39
  invalid?: boolean;
30
40
  touched?: boolean;
31
41
  onTouch?: () => void;
32
42
  }
33
43
  /**
34
44
  * Wybór daty i godziny z własnym kalendarzem. Panel jest stosem widoków
35
- * dekady → lata → miesiące → dni: klik w komórkę schodzi poziom niżej, klik w tytuł wchodzi wyżej.
45
+ * dekady -> lata -> miesiące -> dni: klik w komórkę schodzi poziom niżej, klik w tytuł wchodzi wyżej.
36
46
  *
37
- * Klawiatura według wzorca WAI-ARIA „date picker dialog”: `Enter`/`Spacja`/`↓` na polu otwierają
47
+ * Klawiatura według wzorca WAI-ARIA "date picker dialog": `Enter`/`Spacja`/`ArrowDown` na polu otwierają
38
48
  * kalendarz i przenoszą fokus na wybrany (albo dzisiejszy) dzień. W siatce dni strzałki chodzą
39
49
  * o dzień i tydzień, `Home`/`End` na początek i koniec tygodnia, `PageUp`/`PageDown` o miesiąc
40
- * (z `Shift` — o rok); w siatkach miesięcy, lat i dekad strzałki chodzą po komórkach. `Tab` krąży
50
+ * (z `Shift` - o rok); w siatkach miesięcy, lat i dekad strzałki chodzą po komórkach. `Tab` krąży
41
51
  * w panelu, `Escape` zamyka go, a wybór i zamknięcie oddają fokus polu. `Delete`/`Backspace` na polu
42
52
  * czyści wartość.
43
53
  *
54
+ * Pole to `role="combobox"` z `aria-haspopup="dialog"`, więc niesie `aria-required`,
55
+ * `aria-readonly` i `aria-invalid`. Tydzień zaczyna się wg aktywnego języka, chyba że podano
56
+ * `firstDayOfWeek`; przewinięcie strony strzałką < > jest ogłaszane.
57
+ *
44
58
  * @example
45
59
  * <KptDatepicker value={date} onValueChange={setDate} startView="decade" minDate="1920-01-01" />
46
60
  * <KptDatepicker selectionMode="datetime" hourFormat={12} value={at} onValueChange={setAt} />
47
61
  */
48
- export declare function KptDatepicker({ value, defaultValue, onValueChange, selectionMode, startView, minDate, maxDate, placeholder, monthDisplay, displayFormat, hourFormat, minuteStep, open, onOpenChange, ariaLabel, id, disabled, invalid, touched, onTouch, locale, dictionary, className, ...rest }: Readonly<KptDatepickerProps>): import("react").JSX.Element;
62
+ export declare function KptDatepicker({ value, defaultValue, onValueChange, selectionMode, startView, minDate, maxDate, placeholder, monthDisplay, displayFormat, firstDayOfWeek, hourFormat, minuteStep, open, onOpenChange, ariaLabel, id, disabled, readOnly, required, invalid, touched, onTouch, locale, dictionary, className, ...rest }: Readonly<KptDatepickerProps>): import("react").JSX.Element;