@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 { KPT_CALENDAR_LEVELS, buildDayGrid, buildDecadeCells, buildMonthCells, buildYearCells, canPageBack, canPageForward, centuryStart, commitLevelFor, decadeStart, formatDate, formatTime, initialFocusDate, initialPage, moveCellIndex, moveFocusDate, pad, pageBy, parseDate, parseDateTime, parseTime, resolveStartView, selectedYearMonth, toIso, } from '@konce-pt/datetime';
3
+ import { useEffect, useEffectEvent, useRef, useState, } from 'react';
4
+ import { KPT_CALENDAR_LEVELS, buildDayGrid, buildDecadeCells, buildMonthCells, buildYearCells, canPageBack, canPageForward, centuryStart, commitLevelFor, datePlaceholder, dayPeriodLabels, decadeStart, displayDate, displayMonthYear, formatTime, initialFocusDate, kptFirstDayOfWeek, orderWeekdays, initialPage, moveCellIndex, moveFocusDate, pad, pageBy, parseDate, parseDateTime, parseTime, resolveStartView, selectedYearMonth, 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";
@@ -14,52 +15,74 @@ import { useKptId } from "../internal/use-id.js";
14
15
  import { focusCalendarActive, trapTab } from "../internal/calendar-focus.js";
15
16
  /**
16
17
  * Wybór daty i godziny z własnym kalendarzem. Panel jest stosem widoków
17
- * dekady → lata → miesiące → dni: klik w komórkę schodzi poziom niżej, klik w tytuł wchodzi wyżej.
18
+ * dekady -> lata -> miesiące -> dni: klik w komórkę schodzi poziom niżej, klik w tytuł wchodzi wyżej.
18
19
  *
19
- * Klawiatura według wzorca WAI-ARIA „date picker dialog”: `Enter`/`Spacja`/`↓` na polu otwierają
20
+ * Klawiatura według wzorca WAI-ARIA "date picker dialog": `Enter`/`Spacja`/`ArrowDown` na polu otwierają
20
21
  * kalendarz i przenoszą fokus na wybrany (albo dzisiejszy) dzień. W siatce dni strzałki chodzą
21
22
  * o dzień i tydzień, `Home`/`End` na początek i koniec tygodnia, `PageUp`/`PageDown` o miesiąc
22
- * (z `Shift` — o rok); w siatkach miesięcy, lat i dekad strzałki chodzą po komórkach. `Tab` krąży
23
+ * (z `Shift` - o rok); w siatkach miesięcy, lat i dekad strzałki chodzą po komórkach. `Tab` krąży
23
24
  * w panelu, `Escape` zamyka go, a wybór i zamknięcie oddają fokus polu. `Delete`/`Backspace` na polu
24
25
  * czyści wartość.
25
26
  *
27
+ * Pole to `role="combobox"` z `aria-haspopup="dialog"`, więc niesie `aria-required`,
28
+ * `aria-readonly` i `aria-invalid`. Tydzień zaczyna się wg aktywnego języka, chyba że podano
29
+ * `firstDayOfWeek`; przewinięcie strony strzałką < > jest ogłaszane.
30
+ *
26
31
  * @example
27
32
  * <KptDatepicker value={date} onValueChange={setDate} startView="decade" minDate="1920-01-01" />
28
33
  * <KptDatepicker selectionMode="datetime" hourFormat={12} value={at} onValueChange={setAt} />
29
34
  */
30
- export function KptDatepicker({ value, defaultValue = '', onValueChange, selectionMode = 'date', startView = null, minDate = null, maxDate = null, placeholder = '', monthDisplay = 'long', displayFormat = 'pl', hourFormat = 24, minuteStep = 1, open, onOpenChange, ariaLabel = null, id, disabled = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
35
+ export function KptDatepicker({ value, defaultValue = '', onValueChange, selectionMode = 'date', startView = null, minDate = null, maxDate = null, placeholder = '', monthDisplay = 'long', displayFormat = 'pl', firstDayOfWeek = null, hourFormat = 24, minuteStep = 1, open, onOpenChange, ariaLabel = null, id, disabled = false, readOnly = false, required = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
31
36
  const { t, locale: activeLocale } = useKptMessages({ locale, dictionary });
32
- /** `div` z rolą nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
37
+ /** `div` z rolą nie dostaje nazwy z `label[for]` - stąd `aria-labelledby` na etykietę wrappera. */
33
38
  const field = useKptFieldA11y(id, 'kpt-datepicker');
34
39
  const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
35
40
  const [isOpen, setOpen] = useControllableState({ value: open, defaultValue: false, onChange: onOpenChange });
36
41
  const [anchor, setAnchor] = useState(null);
37
42
  const triggerRef = useRef(null);
38
- const today = useRef(new Date()).current;
43
+ /** "Dziś" liczone przy każdym otwarciu - panel otwarty po północy nie pokazuje wczorajszego dnia. */
44
+ const [today, setToday] = useState(() => new Date());
39
45
  const todayIso = toIso(today);
46
+ const firstDay = firstDayOfWeek ?? kptFirstDayOfWeek(activeLocale);
47
+ const periods = dayPeriodLabels(activeLocale);
48
+ /** Ogłoszenie strony kalendarza po przewinięciu strzałką < >. */
49
+ const [pageAnnouncement, setPageAnnouncement] = useState('');
40
50
  const showInvalid = invalid && (touched ?? true);
41
51
  const [page, setPage] = useState(() => initialPage(current, selectionMode, today));
42
52
  const [panelView, setPanelView] = useState(() => resolveStartView(selectionMode, startView));
43
53
  const [timeStr, setTimeStr] = useState('');
44
54
  const [pendingDate, setPendingDate] = useState('');
45
55
  const [dtView, setDtView] = useState('calendar');
46
- /** Dzień z fokusem w siatce dni — jedyny przystanek Tab siatki (roving tabindex). */
56
+ /** Dzień z fokusem w siatce dni - jedyny przystanek Tab siatki (roving tabindex). */
47
57
  const [focusIso, setFocusIso] = useState('');
48
58
  /** Komórka z fokusem w siatkach miesięcy, lat i dekad. */
49
59
  const [focusCell, setFocusCell] = useState(0);
50
60
  const panelId = useKptId(undefined, 'kpt-datepicker-panel');
51
61
  const panelRef = useRef(null);
52
- /** Prośba o przeniesienie fokusu po najbliższym renderze (otwarcie, ruch klawiszem, zmiana poziomu). */
53
- const wantFocus = useRef(false);
62
+ /**
63
+ * Prośba o przeniesienie fokusu po najbliższym renderze (otwarcie, ruch klawiszem, zmiana
64
+ * poziomu) - licznik w stanie, nie ref zapisywany w renderze.
65
+ */
66
+ const [focusRequest, setFocusRequest] = useState(0);
67
+ const requestFocus = () => setFocusRequest((n) => n + 1);
54
68
  const months = monthNames(activeLocale);
55
- const weekdays = weekdayNames(activeLocale);
69
+ const weekdays = orderWeekdays(weekdayNames(activeLocale), firstDay);
56
70
  const commitLevel = commitLevelFor(selectionMode);
57
- // Panel można otworzyć także z zewnątrz (`open`), nie tylko klikiem w trigger — widok
58
- // i bufor czasu ustawiamy więc przy każdym otwarciu, a nie w obsłudze kliknięcia.
59
- useEffect(() => {
60
- if (!isOpen)
61
- return;
62
- setPage(initialPage(current, selectionMode, today));
71
+ // Panel można otworzyć także z zewnątrz (`open`), nie tylko klikiem w trigger - widok i bufor
72
+ // czasu ustawiamy więc przy każdym przejściu w stan otwarty. Wzorzec "poprzednia wartość
73
+ // w stanie" z react.dev: stan liczy się w tym samym renderze, bez efektu i bez klatki ze starym
74
+ // widokiem. Późniejsze zmiany wartości w otwartym panelu go nie resetują.
75
+ const [wasOpen, setWasOpen] = useState(isOpen);
76
+ if (wasOpen !== isOpen) {
77
+ setWasOpen(isOpen);
78
+ if (isOpen)
79
+ prepareOpen();
80
+ }
81
+ function prepareOpen() {
82
+ const now = new Date();
83
+ setToday(now);
84
+ setPageAnnouncement('');
85
+ setPage(initialPage(current, selectionMode, now));
63
86
  setPanelView(resolveStartView(selectionMode, startView));
64
87
  setDtView(selectionMode === 'time' ? 'clock' : 'calendar');
65
88
  if (selectionMode === 'time') {
@@ -73,18 +96,15 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
73
96
  }
74
97
  const startLevel = resolveStartView(selectionMode, startView);
75
98
  const selected = selectionMode === 'datetime' ? (parseDateTime(current)?.date ?? '') : current;
76
- const focus = initialFocusDate(selected, todayIso, minDate, maxDate);
99
+ const focus = initialFocusDate(selected, toIso(now), minDate, maxDate);
77
100
  setFocusIso(focus);
78
101
  if (startLevel === 'day' && selectionMode !== 'time') {
79
102
  const date = parseDate(focus);
80
103
  setPage({ y: date.getFullYear(), m: date.getMonth() });
81
104
  }
82
105
  setFocusCell(-1); // -1 = domyślna komórka nowej siatki, wyliczana przy renderze
83
- wantFocus.current = true;
84
- // Zależność wyłącznie od `isOpen`: to otwarcie ma ustawić stan początkowy, a późniejsze
85
- // zmiany wartości w otwartym panelu nie mogą go zresetować pod palcami użytkownika.
86
- // eslint-disable-next-line react-hooks/exhaustive-deps
87
- }, [isOpen]);
106
+ requestFocus();
107
+ }
88
108
  const showClock = selectionMode === 'time' || (selectionMode === 'datetime' && dtView === 'clock');
89
109
  const hasFooter = selectionMode === 'time' || selectionMode === 'datetime';
90
110
  const hasNav = selectionMode !== 'month';
@@ -94,54 +114,48 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
94
114
  setOpen(false);
95
115
  onTouch?.();
96
116
  };
97
- /** Zamknięcie z powrotem fokusu na pole — po wyborze z klawiatury, `Escape`. */
117
+ /** Zamknięcie z powrotem fokusu na pole - po wyborze z klawiatury, `Escape`. */
98
118
  const closeAndFocus = () => {
99
119
  close();
100
120
  triggerRef.current?.focus();
101
121
  };
102
- // Fokus po renderze. Panel w nakładce jest niewidoczny do pierwszego pomiaru — stąd rAF.
122
+ // Fokus po renderze. Panel w nakładce jest niewidoczny do pierwszego pomiaru - stąd rAF.
123
+ // `focusIso` czytamy przez zdarzenie efektu: liczy się prośba, nie każda zmiana dnia.
124
+ const focusActive = useEffectEvent(() => focusCalendarActive(panelRef.current, focusIso));
103
125
  useEffect(() => {
104
- if (!isOpen || !wantFocus.current)
126
+ if (!isOpen || focusRequest === 0)
105
127
  return;
106
- const frame = requestAnimationFrame(() => {
107
- wantFocus.current = false;
108
- focusCalendarActive(panelRef.current, focusIso);
109
- });
128
+ const frame = requestAnimationFrame(() => focusActive());
110
129
  return () => cancelAnimationFrame(frame);
111
- });
112
- // ── Prezentacja w triggerze ──
130
+ }, [focusRequest, isOpen]);
131
+ // -- Prezentacja w triggerze --
113
132
  const effectivePlaceholder = (() => {
114
133
  if (placeholder)
115
134
  return placeholder;
116
- const iso = displayFormat === 'iso';
135
+ const tokens = { year: t('datepicker.yearToken'), month: t('datepicker.monthToken'), day: t('datepicker.dayToken') };
117
136
  const time = hourFormat === 12 ? '--:-- --' : '--:--';
118
137
  switch (selectionMode) {
119
138
  case 'monthYear':
120
- return iso ? 'RRRR-MM' : 'MM.RRRR';
139
+ return datePlaceholder(displayFormat, tokens, 'monthYear', activeLocale);
121
140
  case 'year':
122
- return 'RRRR';
141
+ return tokens.year;
123
142
  case 'month':
124
- return monthDisplay === 'number' ? 'MM' : t('datepicker.month');
143
+ return monthDisplay === 'number' ? tokens.month : t('datepicker.month');
125
144
  case 'time':
126
145
  return time;
127
146
  case 'datetime':
128
- return `${iso ? 'RRRR-MM-DD' : 'DD.MM.RRRR'} ${time}`;
147
+ return `${datePlaceholder(displayFormat, tokens, 'date', activeLocale)} ${time}`;
129
148
  default:
130
- return iso ? 'RRRR-MM-DD' : 'DD.MM.RRRR';
149
+ return datePlaceholder(displayFormat, tokens, 'date', activeLocale);
131
150
  }
132
151
  })();
133
- /** Wartość niepasująca do formatu trybu daje pusty tekst — trigger nie pokazuje śmieci. */
152
+ /** Wartość niepasująca do formatu trybu daje pusty tekst - trigger nie pokazuje śmieci. */
134
153
  const display = (() => {
135
154
  if (!current)
136
155
  return '';
137
- const iso = displayFormat === 'iso';
138
156
  switch (selectionMode) {
139
- case 'monthYear': {
140
- const match = /^(\d{4})-(\d{2})$/.exec(current);
141
- if (!match)
142
- return '';
143
- return iso ? current : `${match[2]}.${match[1]}`;
144
- }
157
+ case 'monthYear':
158
+ return displayMonthYear(current, displayFormat, activeLocale);
145
159
  case 'year':
146
160
  return /^\d{4}$/.test(current) ? current : '';
147
161
  case 'month': {
@@ -152,22 +166,22 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
152
166
  }
153
167
  case 'time': {
154
168
  const parsed = parseTime(current);
155
- return parsed ? formatTime(parsed.h, parsed.m, hourFormat) : '';
169
+ return parsed ? formatTime(parsed.h, parsed.m, hourFormat, periods) : '';
156
170
  }
157
171
  case 'datetime': {
158
172
  const parsed = parseDateTime(current);
159
173
  if (!parsed)
160
174
  return '';
161
- const sep = iso ? 'T' : ' ';
162
- return `${formatDate(parsed.date, displayFormat)}${sep}${formatTime(parsed.h, parsed.m, hourFormat)}`;
175
+ const sep = displayFormat === 'iso' ? 'T' : ' ';
176
+ return `${displayDate(parsed.date, displayFormat, activeLocale)}${sep}${formatTime(parsed.h, parsed.m, hourFormat, periods)}`;
163
177
  }
164
178
  default:
165
- return formatDate(current, displayFormat);
179
+ return displayDate(current, displayFormat, activeLocale);
166
180
  }
167
181
  })();
168
- // ── Siatki ──
182
+ // -- Siatki --
169
183
  const selectedDateIso = selectionMode === 'datetime' ? pendingDate : current;
170
- const weeks = buildDayGrid({ page, selectedIso: selectedDateIso, todayIso, minDate, maxDate });
184
+ const weeks = buildDayGrid({ page, selectedIso: selectedDateIso, todayIso, minDate, maxDate, firstDay });
171
185
  const selectedYM = selectedYearMonth(selectionMode === 'datetime' ? pendingDate : current, selectionMode);
172
186
  const levelCells = panelView === 'year'
173
187
  ? buildYearCells({ year: page.y, selected: selectedYM, today, minDate, maxDate })
@@ -191,7 +205,7 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
191
205
  return now >= 0 ? now : Math.max(0, levelCells.findIndex((c) => !c.disabled));
192
206
  })();
193
207
  const activeCell = focusCell >= 0 && focusCell < levelCells.length ? focusCell : defaultCell;
194
- /** Pełna nazwa dnia dla czytnika („czwartek, 8 października 2026”) — sama liczba nic nie mówi. */
208
+ /** Pełna nazwa dnia dla czytnika ("czwartek, 8 października 2026") - sama liczba nic nie mówi. */
195
209
  const dayFormat = new Intl.DateTimeFormat(activeLocale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
196
210
  const dayName = (iso) => {
197
211
  const date = parseDate(iso);
@@ -199,7 +213,7 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
199
213
  };
200
214
  const isRtl = () => !!panelRef.current && getComputedStyle(panelRef.current).direction === 'rtl';
201
215
  const onDayKeyDown = (event) => {
202
- const next = moveFocusDate(focusIso, event.key, { shift: event.shiftKey, rtl: isRtl(), minDate, maxDate });
216
+ const next = moveFocusDate(focusIso, event.key, { shift: event.shiftKey, rtl: isRtl(), minDate, maxDate, firstDay });
203
217
  if (next === null)
204
218
  return;
205
219
  event.preventDefault();
@@ -207,7 +221,7 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
207
221
  const date = parseDate(next);
208
222
  if (date.getFullYear() !== page.y || date.getMonth() !== page.m)
209
223
  setPage({ y: date.getFullYear(), m: date.getMonth() });
210
- wantFocus.current = true;
224
+ requestFocus();
211
225
  };
212
226
  const onCellKeyDown = (event) => {
213
227
  const next = moveCellIndex(levelCells.map((c) => c.disabled), activeCell, event.key, 3, isRtl());
@@ -215,23 +229,24 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
215
229
  return;
216
230
  event.preventDefault();
217
231
  setFocusCell(next);
218
- wantFocus.current = true;
232
+ requestFocus();
219
233
  };
220
- /** Tytuł, który kliknięto, znika razem z poziomem — fokus idzie do nowej siatki. */
234
+ /** Tytuł, który kliknięto, znika razem z poziomem - fokus idzie do nowej siatki. */
221
235
  const goTo = (level) => {
222
236
  setPanelView(level);
223
237
  setFocusCell(-1);
224
- wantFocus.current = true;
238
+ requestFocus();
225
239
  };
226
- /** Strzałki ‹ ›: fokus zostaje na strzałce, ale przystanek siatki dni idzie za stroną. */
240
+ /** Strzałki < >: fokus zostaje na strzałce, ale przystanek siatki dni idzie za stroną. */
227
241
  const turnPage = (dir) => {
228
242
  const next = pageBy(page, panelView, dir);
229
243
  setPage(next);
244
+ setPageAnnouncement(pageTitle(next));
230
245
  if (panelView === 'day') {
231
- const moved = moveFocusDate(focusIso, dir === 1 ? 'PageDown' : 'PageUp', { minDate, maxDate });
232
- // Dzień przycięty do granicy może leżeć poza nową stroną — wtedy pierwszy dozwolony dzień miesiąca.
246
+ const moved = moveFocusDate(focusIso, dir === 1 ? 'PageDown' : 'PageUp', { minDate, maxDate, firstDay });
247
+ // Dzień przycięty do granicy może leżeć poza nową stroną - wtedy pierwszy dozwolony dzień miesiąca.
233
248
  const inPage = moved?.startsWith(`${next.y}-${pad(next.m + 1)}`);
234
- const fallback = buildDayGrid({ page: next, selectedIso: selectedDateIso, todayIso, minDate, maxDate })
249
+ const fallback = buildDayGrid({ page: next, selectedIso: selectedDateIso, todayIso, minDate, maxDate, firstDay })
235
250
  .flat()
236
251
  .find((c) => c.inMonth && !c.disabled)?.iso;
237
252
  const target = inPage ? moved : fallback;
@@ -242,6 +257,19 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
242
257
  setFocusCell(-1);
243
258
  }
244
259
  };
260
+ /** Tytuł strony do ogłoszenia - miesiąc z rokiem, rok albo zakres lat. */
261
+ const pageTitle = (target) => {
262
+ switch (panelView) {
263
+ case 'day':
264
+ return `${months[target.m]} ${target.y}`;
265
+ case 'month':
266
+ return String(target.y);
267
+ case 'year':
268
+ return `${decadeStart(target.y)} - ${decadeStart(target.y) + 9}`;
269
+ default:
270
+ return `${centuryStart(target.y)} - ${centuryStart(target.y) + 119}`;
271
+ }
272
+ };
245
273
  const navLabel = (dir) => {
246
274
  switch (panelView) {
247
275
  case 'month':
@@ -254,12 +282,12 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
254
282
  return t(dir === 'prev' ? 'datepicker.prevMonth' : 'datepicker.nextMonth');
255
283
  }
256
284
  };
257
- // ── Wybór ──
285
+ // -- Wybór --
258
286
  const selectDay = (iso, cellDisabled) => {
259
287
  if (cellDisabled)
260
288
  return;
261
289
  if (selectionMode === 'datetime') {
262
- setPendingDate(iso); // czas jeszcze do wyboru — zamyka dopiero „Gotowe"
290
+ setPendingDate(iso); // czas jeszcze do wyboru - zamyka dopiero "Gotowe"
263
291
  return;
264
292
  }
265
293
  setCurrent(iso);
@@ -286,7 +314,7 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
286
314
  else {
287
315
  setFocusCell(-1);
288
316
  }
289
- wantFocus.current = true;
317
+ requestFocus();
290
318
  };
291
319
  const commit = () => {
292
320
  const time = timeStr || '00:00';
@@ -301,15 +329,19 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
301
329
  };
302
330
  const clear = (event) => {
303
331
  event.stopPropagation();
332
+ if (readOnly)
333
+ return;
304
334
  setCurrent('');
305
335
  setPendingDate('');
336
+ // Wyczyszczenie to interakcja z polem - błąd "wymagane" ma się pokazać od razu.
337
+ onTouch?.();
306
338
  };
307
339
  const timeParts = parseTime(timeStr);
308
340
  return (_jsxs("div", { className: cn('kpt-datepicker-host', className), ...rest, children: [_jsxs("div", { ref: (el) => {
309
341
  triggerRef.current = el;
310
342
  setAnchor(el);
311
- }, className: cn('kpt-datepicker', isOpen && 'kpt-datepicker--open', disabled && 'kpt-datepicker--disabled', showInvalid && 'kpt-datepicker--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-label": ariaLabel ?? undefined, onClick: () => !disabled && setOpen(!isOpen), onKeyDown: (event) => {
312
- if (disabled)
343
+ }, className: cn('kpt-datepicker', isOpen && 'kpt-datepicker--open', disabled && 'kpt-datepicker--disabled', readOnly && 'kpt-datepicker--readonly', showInvalid && 'kpt-datepicker--invalid'), role: "combobox", tabIndex: 0, "aria-haspopup": "dialog", "aria-keyshortcuts": "Delete Backspace", "aria-required": required || undefined, "aria-readonly": readOnly || undefined, "aria-invalid": showInvalid || undefined, "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-label": ariaLabel ?? undefined, onClick: () => !disabled && !readOnly && setOpen(!isOpen), onKeyDown: (event) => {
344
+ if (disabled || readOnly)
313
345
  return;
314
346
  if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
315
347
  event.preventDefault();
@@ -321,8 +353,8 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
321
353
  clear(event);
322
354
  }
323
355
  },
324
- // Przy otwartym panelu fokus idzie do kalendarza — „dotknięcie” wyśle dopiero zamknięcie.
325
- onBlur: () => !isOpen && onTouch?.(), children: [display ? (_jsx("span", { className: "kpt-datepicker__value", children: display })) : (_jsx("span", { className: "kpt-datepicker__placeholder", children: effectivePlaceholder })), _jsx("span", { className: "kpt-datepicker__spacer" }), display ? (_jsx("button", { type: "button", className: "kpt-datepicker__clear", tabIndex: -1, onClick: clear, "aria-label": t('common.clear'), children: _jsx(KptIcon, { name: "x" }) })) : null, _jsx(KptIcon, { className: "kpt-datepicker__icon", name: selectionMode === 'time' ? 'clock' : 'calendar' })] }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, offset: 4, children: _jsxs("div", { ref: panelRef, id: panelId, role: "dialog", "aria-label": t('datepicker.dialog'), className: cn('kpt-calendar', showClock && 'kpt-calendar--clock'), onKeyDown: (event) => {
356
+ // Przy otwartym panelu fokus idzie do kalendarza - "dotknięcie" wyśle dopiero zamknięcie.
357
+ onBlur: () => !isOpen && onTouch?.(), children: [display ? (_jsx("span", { className: "kpt-datepicker__value", children: display })) : (_jsx("span", { className: "kpt-datepicker__placeholder", children: effectivePlaceholder })), _jsx("span", { className: "kpt-datepicker__spacer" }), display && !readOnly ? (_jsx("button", { type: "button", className: "kpt-datepicker__clear", tabIndex: -1, onClick: clear, "aria-label": t('common.clear'), children: _jsx(KptIcon, { name: "x" }) })) : null, _jsx(KptIcon, { className: "kpt-datepicker__icon", name: selectionMode === 'time' ? 'clock' : 'calendar' })] }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, offset: 4, children: _jsxs("div", { ref: panelRef, id: panelId, role: "dialog", "aria-label": t('datepicker.dialog'), className: cn('kpt-calendar', showClock && 'kpt-calendar--clock'), onKeyDown: (event) => {
326
358
  if (event.key === 'Escape') {
327
359
  event.preventDefault();
328
360
  event.stopPropagation();
@@ -331,5 +363,5 @@ export function KptDatepicker({ value, defaultValue = '', onValueChange, selecti
331
363
  else if (event.key === 'Tab') {
332
364
  trapTab(event.currentTarget, event.nativeEvent);
333
365
  }
334
- }, children: [showClock ? (_jsxs(_Fragment, { children: [selectionMode === 'datetime' ? (_jsxs("div", { className: "kpt-calendar__header", children: [_jsx("button", { type: "button", className: "kpt-calendar__nav", onClick: () => setDtView('calendar'), "aria-label": t('datepicker.calendar'), children: _jsx(KptIcon, { name: "chevron-left" }) }), _jsx("span", { className: "kpt-calendar__title", children: t('datepicker.time') })] })) : null, _jsx(KptClock, { value: timeStr, onValueChange: setTimeStr, hourFormat: hourFormat, minuteStep: minuteStep })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "kpt-calendar__header", children: [hasNav ? (_jsx("button", { type: "button", className: "kpt-calendar__nav", disabled: !canPageBack(page, panelView, minDate), onClick: () => turnPage(-1), "aria-label": navLabel('prev'), children: _jsx(KptIcon, { name: "chevron-left" }) })) : null, _jsxs("span", { className: "kpt-calendar__titles", children: [panelView === 'day' ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('month'), "aria-label": t('datepicker.chooseMonth'), children: months[page.m] }), _jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('year'), "aria-label": t('datepicker.chooseYear'), children: page.y })] })) : null, panelView === 'month' ? (selectionMode === 'month' ? (_jsx("span", { className: "kpt-calendar__title", children: t('datepicker.month') })) : (_jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('year'), "aria-label": t('datepicker.chooseYear'), children: page.y }))) : null, panelView === 'year' ? (_jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('decade'), "aria-label": t('datepicker.chooseDecade'), children: `${decadeStart(page.y)} – ${decadeStart(page.y) + 9}` })) : null, panelView === 'decade' ? (_jsx("span", { className: "kpt-calendar__title", children: `${centuryStart(page.y)} – ${centuryStart(page.y) + 119}` })) : null] }), hasNav ? (_jsx("button", { type: "button", className: "kpt-calendar__nav", disabled: !canPageForward(page, panelView, maxDate), onClick: () => turnPage(1), "aria-label": navLabel('next'), children: _jsx(KptIcon, { name: "chevron-right" }) })) : null] }), panelView === 'day' ? (_jsxs(_Fragment, { children: [_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: weeks.flat().map((cell) => (_jsx("button", { type: "button", className: cn('kpt-calendar__day', !cell.inMonth && 'kpt-calendar__day--muted', cell.today && 'kpt-calendar__day--today', cell.selected && 'kpt-calendar__day--selected'), "data-iso": cell.iso, tabIndex: cell.iso === focusIso ? 0 : -1, "aria-label": dayName(cell.iso), "aria-current": cell.today ? 'date' : undefined, disabled: cell.disabled, "aria-pressed": cell.selected, onClick: () => selectDay(cell.iso, cell.disabled), children: cell.day }, cell.iso))) })] })) : (_jsx("div", { className: cn('kpt-calendar__grid kpt-calendar__grid--cells', panelView === 'decade' && 'kpt-calendar__grid--decades'), onKeyDown: onCellKeyDown, children: levelCells.map((cell, index) => (_jsx("button", { type: "button", className: cn('kpt-calendar__cell', cell.selected && 'kpt-calendar__cell--selected', cell.current && 'kpt-calendar__cell--current'), tabIndex: index === activeCell ? 0 : -1, disabled: cell.disabled, "aria-pressed": cell.selected, onClick: () => selectCell(cell), children: cell.label }, cell.label))) })), selectionMode === 'datetime' ? (_jsxs("button", { type: "button", className: "kpt-calendar__timebar", onClick: () => setDtView('clock'), children: [_jsx(KptIcon, { name: "clock" }), _jsx("span", { children: formatTime(timeParts?.h ?? 0, timeParts?.m ?? 0, hourFormat) })] })) : null] })), hasFooter ? (_jsx("div", { className: "kpt-calendar__footer", children: _jsx(KptButton, { size: "sm", onClick: commit, children: t('common.done') }) })) : null] }) })] }));
366
+ }, children: [showClock ? (_jsxs(_Fragment, { children: [selectionMode === 'datetime' ? (_jsxs("div", { className: "kpt-calendar__header", children: [_jsx("button", { type: "button", className: "kpt-calendar__nav", onClick: () => setDtView('calendar'), "aria-label": t('datepicker.calendar'), children: _jsx(KptIcon, { name: "chevron-left" }) }), _jsx("span", { className: "kpt-calendar__title", children: t('datepicker.time') })] })) : null, _jsx(KptClock, { value: timeStr, onValueChange: setTimeStr, hourFormat: hourFormat, minuteStep: minuteStep })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "kpt-calendar__live", "aria-live": "polite", children: pageAnnouncement }), _jsxs("div", { className: "kpt-calendar__header", children: [hasNav ? (_jsx("button", { type: "button", className: "kpt-calendar__nav", disabled: !canPageBack(page, panelView, minDate), onClick: () => turnPage(-1), "aria-label": navLabel('prev'), children: _jsx(KptIcon, { name: "chevron-left" }) })) : null, _jsxs("span", { className: "kpt-calendar__titles", children: [panelView === 'day' ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('month'), "aria-label": `${months[page.m]}, ${t('datepicker.chooseMonth')}`, children: months[page.m] }), _jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('year'), "aria-label": `${page.y}, ${t('datepicker.chooseYear')}`, children: page.y })] })) : null, panelView === 'month' ? (selectionMode === 'month' ? (_jsx("span", { className: "kpt-calendar__title", children: t('datepicker.month') })) : (_jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('year'), "aria-label": `${page.y}, ${t('datepicker.chooseYear')}`, children: page.y }))) : null, panelView === 'year' ? (_jsx("button", { type: "button", className: "kpt-calendar__title-btn", onClick: () => goTo('decade'), "aria-label": `${decadeStart(page.y)} - ${decadeStart(page.y) + 9}, ${t('datepicker.chooseDecade')}`, children: `${decadeStart(page.y)} - ${decadeStart(page.y) + 9}` })) : null, panelView === 'decade' ? (_jsx("span", { className: "kpt-calendar__title", children: `${centuryStart(page.y)} - ${centuryStart(page.y) + 119}` })) : null] }), hasNav ? (_jsx("button", { type: "button", className: "kpt-calendar__nav", disabled: !canPageForward(page, panelView, maxDate), onClick: () => turnPage(1), "aria-label": navLabel('next'), children: _jsx(KptIcon, { name: "chevron-right" }) })) : null] }), panelView === 'day' ? (_jsxs(_Fragment, { children: [_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: weeks.flat().map((cell) => (_jsx("button", { type: "button", className: cn('kpt-calendar__day', !cell.inMonth && 'kpt-calendar__day--muted', cell.today && 'kpt-calendar__day--today', cell.selected && 'kpt-calendar__day--selected'), "data-iso": cell.iso, tabIndex: cell.iso === focusIso ? 0 : -1, "aria-label": dayName(cell.iso), "aria-current": cell.today ? 'date' : undefined, disabled: cell.disabled, "aria-pressed": cell.selected, onClick: () => selectDay(cell.iso, cell.disabled), children: cell.day }, cell.iso))) })] })) : (_jsx("div", { className: cn('kpt-calendar__grid kpt-calendar__grid--cells', panelView === 'decade' && 'kpt-calendar__grid--decades'), onKeyDown: onCellKeyDown, children: levelCells.map((cell, index) => (_jsx("button", { type: "button", className: cn('kpt-calendar__cell', cell.selected && 'kpt-calendar__cell--selected', cell.current && 'kpt-calendar__cell--current'), tabIndex: index === activeCell ? 0 : -1, disabled: cell.disabled, "aria-pressed": cell.selected, onClick: () => selectCell(cell), children: cell.label }, cell.label))) })), selectionMode === 'datetime' ? (_jsxs("button", { type: "button", className: "kpt-calendar__timebar", onClick: () => setDtView('clock'), children: [_jsx(KptIcon, { name: "clock" }), _jsx("span", { children: formatTime(timeParts?.h ?? 0, timeParts?.m ?? 0, hourFormat, periods) })] })) : null] })), hasFooter ? (_jsx("div", { className: "kpt-calendar__footer", children: _jsx(KptButton, { size: "sm", onClick: commit, children: t('common.done') }) })) : null] }) })] }));
335
367
  }
@@ -5,36 +5,36 @@ Import: `import { KptDatepicker } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-datepicker-host">
8
- <div class="kpt-datepicker" role="button" tabindex="0">
8
+ <div class="kpt-datepicker" role="combobox" tabindex="0" aria-haspopup="dialog">
9
9
  <span class="kpt-datepicker__value">06.09.2026</span>
10
10
  <span class="kpt-datepicker__spacer"></span>
11
- <button class="kpt-datepicker__clear">…</button>
12
- <span class="kpt-icon-host kpt-datepicker__icon">…</span>
11
+ <button class="kpt-datepicker__clear">...</button>
12
+ <span class="kpt-icon-host kpt-datepicker__icon">...</span>
13
13
  </div>
14
14
  </div>
15
- <!-- in a portal: <div class="kpt-calendar">…</div> -->
15
+ <!-- in a portal: <div class="kpt-calendar">...</div> -->
16
16
 
17
17
  ## Props
18
- - `value` / `defaultValue` / `onValueChange` — the value as a string; its format follows the mode:
18
+ - `value` / `defaultValue` / `onValueChange` - the value as a string; its format follows the mode:
19
19
  'YYYY-MM-DD' / 'YYYY-MM' / 'YYYY' / 'MM' / 'YYYY-MM-DDTHH:mm' / 'HH:mm'
20
20
  - `selectionMode`: `'date'` (default) | `'monthYear'` | `'year'` | `'month'` | `'datetime'` | `'time'`
21
- - `startView`: `'day' | 'month' | 'year' | 'decade' | null` — the level the panel opens at; `null`
21
+ - `startView`: `'day' | 'month' | 'year' | 'decade' | null` - the level the panel opens at; `null`
22
22
  means the level where the mode commits. It is never lowered below that level, so
23
23
  `startView="day"` in 'year' mode is raised to 'year'.
24
24
  - `minDate`, `maxDate`: 'YYYY-MM-DD' strings
25
- - `monthDisplay`: `'long'` (default) | `'number'`; `displayFormat`: `'pl'` (default) | `'iso'`
26
- - `hourFormat`: 12 | 24 (default 24) — the dial; the stored value is always 24h
27
- - `minuteStep`: number (default 1) — minute snapping on the dial
28
- - `open` / `onOpenChange` — the panel state, so it can be opened from outside
25
+ - `monthDisplay`: `'long'` (default) | `'number'`; `displayFormat`: `'pl'` (default) | `'iso'` | `'locale'`
26
+ - `hourFormat`: 12 | 24 (default 24) - the dial; the stored value is always 24h
27
+ - `minuteStep`: number (default 1) - minute snapping on the dial
28
+ - `open` / `onOpenChange` - the panel state, so it can be opened from outside
29
29
  - `placeholder`, `ariaLabel`, `disabled`, `invalid`, `touched`
30
- - `onTouch()` — fires when the panel closes or focus leaves the closed trigger
30
+ - `onTouch()` - fires when the panel closes or focus leaves the closed trigger
31
31
  - `className`, `ref` and every other `<div>` prop go to the host
32
32
 
33
33
  ## Keyboard
34
34
  The date picker dialog pattern. The trigger has `aria-haspopup="dialog"` and `aria-expanded`;
35
- `Enter`, `Space` and `↓` open the panel — a `role="dialog"` named "Choose a date" — and move focus to
35
+ `Enter`, `Space` and `ArrowDown` open the panel - a `role="dialog"` named "Choose a date" - and move focus to
36
36
  the selected day, or today, clamped to `minDate`/`maxDate`.
37
- - Day grid: `←`/`→` one day, `↑`/`↓` one week, `Home`/`End` Monday and Sunday of the week,
37
+ - Day grid: `ArrowLeft`/`ArrowRight` one day, `ArrowUp`/`ArrowDown` one week, `Home`/`End` Monday and Sunday of the week,
38
38
  `PageUp`/`PageDown` one month, with `Shift` one year (the day is clamped to the month length).
39
39
  Crossing a month edge turns the page. Each day is named with the full date from `Intl`
40
40
  ("Thursday, October 8, 2026"), today has `aria-current="date"`, and only the focused day is
@@ -42,22 +42,22 @@ the selected day, or today, clamped to `minDate`/`maxDate`.
42
42
  - Month, year and decade grids: the arrows move between cells (three columns), `Home`/`End` to the ends.
43
43
  Clicking a title moves focus to the new grid.
44
44
  - `Tab` cycles inside the panel; `Escape` closes it. Picking a value (or "Done") closes the panel
45
- and returns focus to the trigger. `Delete`/`Backspace` on the trigger clears the value; the "×" button
45
+ and returns focus to the trigger. `Delete`/`Backspace` on the trigger clears the value; the "x" button
46
46
  sits outside the Tab order.
47
47
 
48
48
  ## The view stack
49
- The header is always `‹ title ›`: the arrows page the current level, the title goes one level up.
49
+ The header is always `< title >`: the arrows page the current level, the title goes one level up.
50
50
 
51
- day ‹ [June] [1979] › arrows ±1 month; the chips → months / years
52
- month ‹ [1979] › arrows ±1 year; the chip → years
53
- year ‹ [1970 – 1979] › arrows ±10 years; the chip → decades
54
- decade ‹ 1920 – 2039 › arrows ±120 years; the top of the stack
51
+ day < [June] [1979] > arrows +/-1 month; the chips -> months / years
52
+ month < [1979] > arrows +/-1 year; the chip -> years
53
+ year < [1970 - 1979] > arrows +/-10 years; the chip -> decades
54
+ decade < 1920 - 2039 > arrows +/-120 years; the top of the stack
55
55
 
56
56
  Clicking a cell above the committing level drills down; on that level it sets the value and closes
57
57
  the panel. An arrow dims when the whole neighbouring page falls outside `minDate`/`maxDate`.
58
58
 
59
59
  ## The logic lives in a package, the component only renders
60
- Every grid, bound and format comes from `@konce-pt/datetime` — pure functions with their own tests.
60
+ Every grid, bound and format comes from `@konce-pt/datetime` - pure functions with their own tests.
61
61
  The component holds nothing but React state: the page, the level, the time buffer.
62
62
 
63
63
  ## The panel is set up on open, not on click
@@ -66,7 +66,7 @@ outside through the `open` prop. The effect deliberately depends on `open` alone
66
66
  while the panel is open must not reset the view under the user's fingers.
67
67
 
68
68
  ## Requires
69
- `@konce-pt/styles/components` for the calendar styles. No CDK — the panel rides the internal
69
+ `@konce-pt/styles/components` for the calendar styles. No CDK - the panel rides the internal
70
70
  overlay primitive.
71
71
 
72
72
  ## Examples
@@ -81,6 +81,20 @@ Weekday and month names come from `Intl` for the active locale, not from the dic
81
81
  navigation labels and "Done" come from the `datepicker` and `common` namespaces; `locale` and
82
82
  `dictionary` override them per instance.
83
83
 
84
+ ## Week start, display format and field state
85
+ - The week starts by the active language (`Intl.Locale#getWeekInfo`, with a fallback list of regions):
86
+ en / en-US on Sunday, pl, de, en-GB on Monday. `firstDayOfWeek` (1 = Monday ... 7 = Sunday) overrides it;
87
+ the headers, the grid and `Home`/`End` follow it.
88
+ - `displayFormat`: `'pl'` (DD.MM.YYYY, default), `'iso'` (YYYY-MM-DD) or `'locale'` - order and separators
89
+ from `Intl` (en-US: MM/DD/YYYY). The placeholder follows the format and its letters follow the language
90
+ (EN `YYYY`, PL `RRRR`, the `datepicker.yearToken`/`monthToken`/`dayToken` keys). AM/PM come from `Intl`.
91
+ - The field is `role="combobox"` with `aria-haspopup="dialog"` (the APG select-only combobox), so it carries
92
+ `aria-required` (`required`), `aria-readonly` (`readOnly` - the value shows, the panel does not open,
93
+ there is no clear button) and `aria-invalid`.
94
+ - Turning the page with < > is announced (`aria-live="polite"`); the title buttons are named
95
+ "October, Choose month" - the visible text first (WCAG 2.5.3). Clearing the value counts as a touch.
96
+ - "Today" is computed on every open, so a panel opened after midnight marks the right day.
97
+
84
98
  ## Label and description
85
99
  `id` goes to the focusable element, not the host; without one it comes from `KptFormField` or is
86
100
  generated. A `div` with a role is not named by `label[for]`, so inside `KptFormField` it gets
@@ -92,7 +106,7 @@ is added to `aria-describedby`. New: `id`; the trigger is the element that carri
92
106
  `--kpt-color-surface-raised`, the selection `--kpt-color-primary`.
93
107
 
94
108
  ## Accessibility
95
- The trigger is `role="button"` with `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`;
109
+ The trigger is `role="combobox"` with `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`;
96
110
  the panel is a named `role="dialog"`; every cell is a real `<button>` with `aria-pressed`, days carry
97
111
  the full date and `aria-current="date"`; `ariaLabel` names the field when no `<label for>` describes
98
112
  it. The keyboard is described above.
@@ -7,22 +7,22 @@ export interface KptDialogProps extends Omit<ComponentPropsWithRef<'dialog'>, 'o
7
7
  onOpenChange: (open: boolean) => void;
8
8
  header?: string;
9
9
  /**
10
- * Szerokość okna: `sm` 24rem, `md` 32rem (domyślna), `lg` 48rem — zawsze przycięta do szerokości
10
+ * Szerokość okna: `sm` 24rem, `md` 32rem (domyślna), `lg` 48rem - zawsze przycięta do szerokości
11
11
  * okna przeglądarki. `lg` jest dla treści, której nie da się sensownie zwęzić: kodu, tabeli,
12
12
  * porównania dwóch kolumn.
13
13
  */
14
14
  size?: KptDialogSize;
15
- /** Pozwala zamknąć klawiszem Esc i przyciskiem ×. */
15
+ /** Pozwala zamknąć klawiszem Esc i przyciskiem x. */
16
16
  dismissible?: boolean;
17
17
  children?: ReactNode;
18
18
  }
19
19
  /**
20
- * Okno modalne na natywnym `<dialog>` — pułapka fokusu, Escape i backdrop pochodzą z platformy,
20
+ * Okno modalne na natywnym `<dialog>` - pułapka fokusu, Escape i backdrop pochodzą z platformy,
21
21
  * nie z naszego kodu. Stopkę wstaw przez `<KptDialog.Footer>`.
22
22
  *
23
23
  * Z `header` okno bierze nazwę z nagłówka (`aria-labelledby`); bez niego podaj `aria-label`.
24
24
  * Okno wymagające odpowiedzi dostaje `role="alertdialog"` i `aria-describedby` wprost z propsów
25
- * `<dialog>` — tak robi `KptConfirmContainer`.
25
+ * `<dialog>` - tak robi `KptConfirmContainer`.
26
26
  *
27
27
  * @example
28
28
  * <KptDialog open={open} onOpenChange={setOpen} header="Usunąć?">
@@ -1,18 +1,21 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Children, isValidElement, useEffect, useRef, useState, } from 'react';
3
+ import { isValidElement, useEffect, useRef, useState, } from 'react';
3
4
  import { cn } from "../internal/cn.js";
5
+ import { slotChildren } from "../internal/slot-children.js";
6
+ import { kptLockScroll } from "../internal/scroll-lock.js";
4
7
  import { composeRefs } from "../internal/compose-refs.js";
5
8
  import { useKptId } from "../internal/use-id.js";
6
9
  import { KptOverlayContainerContext } from "../internal/overlay-container.js";
7
10
  import { useKptMessages } from "../i18n/i18n-context.js";
8
11
  import { KptIcon } from "../icon/icon.js";
9
12
  /**
10
- * Okno modalne na natywnym `<dialog>` — pułapka fokusu, Escape i backdrop pochodzą z platformy,
13
+ * Okno modalne na natywnym `<dialog>` - pułapka fokusu, Escape i backdrop pochodzą z platformy,
11
14
  * nie z naszego kodu. Stopkę wstaw przez `<KptDialog.Footer>`.
12
15
  *
13
16
  * Z `header` okno bierze nazwę z nagłówka (`aria-labelledby`); bez niego podaj `aria-label`.
14
17
  * Okno wymagające odpowiedzi dostaje `role="alertdialog"` i `aria-describedby` wprost z propsów
15
- * `<dialog>` — tak robi `KptConfirmContainer`.
18
+ * `<dialog>` - tak robi `KptConfirmContainer`.
16
19
  *
17
20
  * @example
18
21
  * <KptDialog open={open} onOpenChange={setOpen} header="Usunąć?">
@@ -27,23 +30,41 @@ export function KptDialog({ open, onOpenChange, header = '', size = 'md', dismis
27
30
  const { t } = useKptMessages({ locale, dictionary });
28
31
  const dialogRef = useRef(null);
29
32
  const titleId = useKptId(undefined, 'kpt-dialog-title');
30
- // Element trafia do kontekstu, więc musi wywołać render — sam `ref` by nie wystarczył.
33
+ // Element trafia do kontekstu, więc musi wywołać render - sam `ref` by nie wystarczył.
31
34
  const [dialogEl, setDialogEl] = useState(null);
32
35
  useEffect(() => {
33
36
  const el = dialogRef.current;
34
- if (!el)
37
+ if (!el || !open)
35
38
  return;
36
- if (open && !el.open)
39
+ if (!el.open)
37
40
  el.showModal();
38
- else if (!open && el.open)
39
- el.close();
41
+ // `showModal()` blokuje interakcję z tłem, ale nie jego przewijanie kółkiem.
42
+ const releaseScroll = kptLockScroll();
43
+ return () => {
44
+ releaseScroll();
45
+ if (el.open)
46
+ el.close();
47
+ };
40
48
  }, [open]);
49
+ /**
50
+ * `close` przychodzi z każdej drogi. Przy `dismissible=false` zamknąć wolno tylko z kodu:
51
+ * Chromium z CloseWatcherem pozwala anulować `cancel` jedynie po aktywacji użytkownika, więc drugi
52
+ * Escape z rzędu zamyka okno mimo `preventDefault` - wtedy otwieramy je z powrotem.
53
+ */
54
+ const onClose = () => {
55
+ const el = dialogRef.current;
56
+ if (!dismissible && open && el && !el.open) {
57
+ el.showModal();
58
+ return;
59
+ }
60
+ onOpenChange(false);
61
+ };
41
62
  const footers = [];
42
63
  const body = [];
43
- Children.forEach(children, (child) => {
64
+ for (const child of slotChildren(children)) {
44
65
  const isFooter = isValidElement(child) && child.type?.kptDialogSlot === 'footer';
45
66
  (isFooter ? footers : body).push(child);
46
- });
67
+ }
47
68
  const onCancel = (event) => {
48
69
  // Esc idzie przez `cancel`; blokujemy go, gdy okna nie wolno zamknąć.
49
70
  if (!dismissible) {
@@ -52,7 +73,7 @@ export function KptDialog({ open, onOpenChange, header = '', size = 'md', dismis
52
73
  }
53
74
  onOpenChange(false);
54
75
  };
55
- return (_jsx(KptOverlayContainerContext.Provider, { value: open ? dialogEl : null, children: _jsxs("dialog", { ref: composeRefs(dialogRef, setDialogEl, ref), className: cn('kpt-dialog', className), "data-size": size, "aria-labelledby": header ? titleId : undefined, onClose: () => onOpenChange(false), onCancel: onCancel, ...rest, children: [header ? (_jsxs("div", { className: "kpt-dialog__header", children: [_jsx("h2", { className: "kpt-dialog__title", id: titleId, children: header }), dismissible ? (_jsx("button", { className: "kpt-dialog__close", type: "button", onClick: () => onOpenChange(false), "aria-label": t('common.close'), children: _jsx(KptIcon, { name: "x" }) })) : null] })) : null, _jsx("div", { className: "kpt-dialog__body", children: body }), footers] }) }));
76
+ return (_jsx(KptOverlayContainerContext.Provider, { value: open ? dialogEl : null, children: _jsxs("dialog", { ref: composeRefs(dialogRef, setDialogEl, ref), className: cn('kpt-dialog', className), "data-size": size, "aria-labelledby": header ? titleId : undefined, closedby: dismissible ? undefined : 'none', onClose: onClose, onCancel: onCancel, ...rest, children: [header ? (_jsxs("div", { className: "kpt-dialog__header", children: [_jsx("h2", { className: "kpt-dialog__title", id: titleId, children: header }), dismissible ? (_jsx("button", { className: "kpt-dialog__close", type: "button", onClick: () => onOpenChange(false), "aria-label": t('common.close'), children: _jsx(KptIcon, { name: "x" }) })) : null] })) : null, _jsx("div", { className: "kpt-dialog__body", children: body }), footers] }) }));
56
77
  }
57
78
  /**
58
79
  * Stopka okna. Nosi atrybut `kptdialogfooter`, w który celuje wspólny SCSS (nazwy atrybutów