@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,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useEffect, useRef, useState } from 'react';
3
4
  import { cn } from "../internal/cn.js";
@@ -5,33 +6,36 @@ import { KptOverlay } from "../internal/overlay.js";
5
6
  import { nextRovingIndex, rovingStop } from "../internal/roving.js";
6
7
  import { useKptId } from "../internal/use-id.js";
7
8
  import { KptIcon } from "../icon/icon.js";
9
+ import { kptIsPlainClick } from "../shared/types.js";
8
10
  import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
9
11
  /**
10
12
  * Pozioma belka menu z rozwijanymi pod-menu. Pozycja bez `items` działa jak akcja lub link.
11
13
  *
12
- * Pod-menu renderuje się w portalu, więc rodzic z `overflow: hidden` go nie przycina — to ta sama
14
+ * Pod-menu renderuje się w portalu, więc rodzic z `overflow: hidden` go nie przycina - to ta sama
13
15
  * korzyść, dla której port Angulara sięga po CDK Overlay, tylko bez CDK.
14
16
  *
15
- * Klawiatura według wzorca WAI-ARIA „menubar”: belka to jeden przystanek Tab, strzałki w lewo/prawo
17
+ * Klawiatura według wzorca WAI-ARIA "menubar": belka to jeden przystanek Tab, strzałki w lewo/prawo
16
18
  * i `Home`/`End` chodzą po pozycjach górnych, strzałka w dół (albo `Enter`/spacja) otwiera
17
- * pod-menu z fokusem na pierwszej pozycji, w górę — na ostatniej. W otwartym pod-menu strzałki
19
+ * pod-menu z fokusem na pierwszej pozycji, w górę - na ostatniej. W otwartym pod-menu strzałki
18
20
  * w lewo/prawo przechodzą do sąsiedniego, a `Escape` zamyka je i oddaje fokus belce.
19
21
  *
20
22
  * @example
21
23
  * <KptMenubar items={items} onSelect={onSelect} />
22
24
  */
23
- export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest }) {
25
+ export function KptMenubar({ items = [], onSelect, onNavigate, ariaLabel, className, ...rest }) {
24
26
  const [openIndex, setOpenIndex] = useState(null);
25
- // Ostatnio skupiona pozycja górna — ona jest przystankiem Tab belki.
27
+ /** Przycisk otwartego pod-menu - w stanie, bo render podaje go nakładce jako kotwicę. */
28
+ const [anchorEl, setAnchorEl] = useState(null);
29
+ // Ostatnio skupiona pozycja górna - ona jest przystankiem Tab belki.
26
30
  const [focusIndex, setFocusIndex] = useState(0);
27
31
  const buttonsRef = useRef([]);
28
32
  const panelRef = useRef(null);
29
- // Którą pozycję pod-menu skupić po otwarciu — strzałka w górę otwiera „od końca”.
33
+ // Którą pozycję pod-menu skupić po otwarciu - strzałka w górę otwiera "od końca".
30
34
  const focusEdge = useRef('first');
31
35
  const baseId = useKptId(undefined, 'kpt-menubar');
32
36
  const panelId = (index) => `${baseId}-menu-${index}`;
33
37
  const disabled = items.map((item) => !!item.disabled);
34
- // Pozycja z `url` (bez pod-menu, niewyłączona) to `<a href>` — nawigację robi przeglądarka,
38
+ // Pozycja z `url` (bez pod-menu, niewyłączona) to `<a href>` - nawigację robi przeglądarka,
35
39
  // więc działa nowa karta i podgląd adresu. `onSelect` i tak jest wołane.
36
40
  const isLink = (item) => !!item.url && !item.items?.length && !item.disabled;
37
41
  const tabStop = rovingStop(disabled, focusIndex);
@@ -59,6 +63,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
59
63
  focusMenuEdge(panelRef.current, edge);
60
64
  return;
61
65
  }
66
+ setAnchorEl(buttonsRef.current[index] ?? null);
62
67
  setOpenIndex(hasMenu ? index : null);
63
68
  focusTop(index);
64
69
  };
@@ -67,6 +72,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
67
72
  return;
68
73
  if (item.items?.length) {
69
74
  focusEdge.current = 'first';
75
+ setAnchorEl(buttonsRef.current[index] ?? null);
70
76
  setOpenIndex((current) => (current === index ? null : index));
71
77
  }
72
78
  else {
@@ -79,7 +85,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
79
85
  return;
80
86
  onSelect?.(item);
81
87
  closeAll();
82
- // Fokus wraca na pozycję górną — inaczej po zniknięciu pod-menu spadłby na `<body>`.
88
+ // Fokus wraca na pozycję górną - inaczej po zniknięciu pod-menu spadłby na `<body>`.
83
89
  focusTop(index);
84
90
  };
85
91
  const onTopKeyDown = (event, index) => {
@@ -94,7 +100,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
94
100
  if (next === null)
95
101
  return;
96
102
  event.preventDefault();
97
- // Przy otwartym pod-menu przejście w bok otwiera pod-menu sąsiada — jak w menu aplikacji.
103
+ // Przy otwartym pod-menu przejście w bok otwiera pod-menu sąsiada - jak w menu aplikacji.
98
104
  if (openIndex === null)
99
105
  focusTop(next);
100
106
  else
@@ -114,12 +120,18 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
114
120
  focusTop(index);
115
121
  }
116
122
  };
123
+ /** Zwykły klik w odnośnik -> `onNavigate` (Ctrl/Cmd/Shift, środkowy przycisk i `_blank` zostają natywne). */
124
+ const linkClick = (event, item) => {
125
+ if (item.url && onNavigate && kptIsPlainClick(event, event.currentTarget.target)) {
126
+ onNavigate({ item, url: item.url, event: event.nativeEvent });
127
+ }
128
+ };
117
129
  return (_jsx("div", { className: cn('kpt-menubar-host', className), ...rest, children: _jsx("div", { className: "kpt-menubar", role: "menubar", "aria-orientation": "horizontal", "aria-label": ariaLabel || undefined, children: items.map((item, index) => {
118
130
  const hasMenu = !!item.items?.length;
119
131
  return (_jsxs("div", { className: "kpt-menubar__group", role: "none", children: [isLink(item) ? (_jsxs("a", { ref: (el) => {
120
132
  buttonsRef.current[index] = el;
121
- }, className: "kpt-menubar__top", role: "menuitem", href: item.url, tabIndex: index === tabStop ? 0 : -1, onClick: () => pick(item, index), onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label })] })) : (_jsxs("button", { ref: (el) => {
133
+ }, className: "kpt-menubar__top", role: "menuitem", href: item.url, tabIndex: index === tabStop ? 0 : -1, onClick: (event) => { linkClick(event, item); pick(item, index); }, onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label })] })) : (_jsxs("button", { ref: (el) => {
122
134
  buttonsRef.current[index] = el;
123
- }, type: "button", className: cn('kpt-menubar__top', openIndex === index && 'is-open'), role: "menuitem", disabled: item.disabled, tabIndex: index === tabStop ? 0 : -1, "aria-haspopup": hasMenu ? 'menu' : undefined, "aria-expanded": hasMenu ? openIndex === index : undefined, "aria-controls": openIndex === index ? panelId(index) : undefined, onClick: () => toggle(index, item), onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label }), hasMenu ? _jsx(KptIcon, { name: "chevron-down", className: "kpt-menubar__caret" }) : null] })), _jsx(KptOverlay, { open: openIndex === index && hasMenu, anchor: buttonsRef.current[index] ?? null, onClose: closeAll, children: _jsx("div", { ref: panelRef, className: "kpt-menubar__dropdown", role: "menu", id: panelId(index), "aria-label": item.label, onKeyDown: (event) => onPanelKeyDown(event, index), children: (item.items ?? []).map((sub, subIndex) => sub.separator ? (_jsx("div", { className: "kpt-menubar__separator", role: "separator" }, subIndex)) : isLink(sub) ? (_jsxs("a", { className: cn('kpt-menubar__item', sub.danger && 'kpt-menubar__item--danger'), role: "menuitem", tabIndex: -1, href: sub.url, onClick: () => pick(sub, index), children: [sub.icon ? _jsx(KptIcon, { name: sub.icon }) : null, _jsx("span", { children: sub.label })] }, subIndex)) : (_jsxs("button", { type: "button", className: cn('kpt-menubar__item', sub.danger && 'kpt-menubar__item--danger'), role: "menuitem", tabIndex: -1, disabled: sub.disabled, onClick: () => pick(sub, index), children: [sub.icon ? _jsx(KptIcon, { name: sub.icon }) : null, _jsx("span", { children: sub.label })] }, subIndex))) }) })] }, index));
135
+ }, type: "button", className: cn('kpt-menubar__top', openIndex === index && 'is-open'), role: "menuitem", disabled: item.disabled, tabIndex: index === tabStop ? 0 : -1, "aria-haspopup": hasMenu ? 'menu' : undefined, "aria-expanded": hasMenu ? openIndex === index : undefined, "aria-controls": openIndex === index ? panelId(index) : undefined, onClick: () => toggle(index, item), onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label }), hasMenu ? _jsx(KptIcon, { name: "chevron-down", className: "kpt-menubar__caret" }) : null] })), _jsx(KptOverlay, { open: openIndex === index && hasMenu, anchor: openIndex === index ? anchorEl : null, onClose: closeAll, children: _jsx("div", { ref: panelRef, className: "kpt-menubar__dropdown", role: "menu", tabIndex: -1, id: panelId(index), "aria-label": item.label, onKeyDown: (event) => onPanelKeyDown(event, index), children: (item.items ?? []).map((sub, subIndex) => sub.separator ? (_jsx("div", { className: "kpt-menubar__separator", role: "separator" }, subIndex)) : isLink(sub) ? (_jsxs("a", { className: cn('kpt-menubar__item', sub.danger && 'kpt-menubar__item--danger'), role: "menuitem", tabIndex: -1, href: sub.url, onClick: (event) => { linkClick(event, sub); pick(sub, index); }, children: [sub.icon ? _jsx(KptIcon, { name: sub.icon }) : null, _jsx("span", { children: sub.label })] }, subIndex)) : (_jsxs("button", { type: "button", className: cn('kpt-menubar__item', sub.danger && 'kpt-menubar__item--danger'), role: "menuitem", tabIndex: -1, disabled: sub.disabled, onClick: () => pick(sub, index), children: [sub.icon ? _jsx(KptIcon, { name: sub.icon }) : null, _jsx("span", { children: sub.label })] }, subIndex))) }) })] }, index));
124
136
  }) }) }));
125
137
  }
@@ -7,35 +7,35 @@ Import: `import { KptMeterGroup } from '@konce-pt/react';`
7
7
  <div class="kpt-meter-group-host">
8
8
  <div class="kpt-meter-group">
9
9
  <div class="kpt-meter-group__track" role="meter" aria-label="Usage" aria-valuemin="0"
10
- aria-valuenow="100" aria-valuemax="100" aria-valuetext="Documents 45, …">
11
- <span class="kpt-meter-group__segment" style="width:45%" title="Documents"></span>…
10
+ aria-valuenow="100" aria-valuemax="100" aria-valuetext="Documents 45, ...">
11
+ <span class="kpt-meter-group__segment" style="width:45%" title="Documents"></span>...
12
12
  </div>
13
13
  <ul class="kpt-meter-group__legend">
14
14
  <li class="kpt-meter-group__legend-item">
15
15
  <span class="kpt-meter-group__dot"></span><span>Documents</span>
16
16
  <span class="kpt-meter-group__val">45%</span>
17
- </li>…
17
+ </li>...
18
18
  </ul>
19
19
  </div>
20
20
  </div>
21
21
 
22
22
  ## Props
23
- - `values`: `KptMeterItem[]` — `{ label, value, color? }`
24
- - `max`: number — the reference total; without it the values' sum is 100%
23
+ - `values`: `KptMeterItem[]` - `{ label, value, color? }`
24
+ - `max`: number - the reference total; without it the values' sum is 100%
25
25
  - `showLegend`: boolean (default true)
26
- - `label`: string — the meter's name; empty = `meterGroup.label`
27
- - `legendValue`: 'percent' | 'value' (default 'percent') — what the legend shows next to each label
28
- - `unit`: string — appended to the values in the legend and in `aria-valuetext` (e.g. 'GB')
26
+ - `label`: string - the meter's name; empty = `meterGroup.label`
27
+ - `legendValue`: 'percent' | 'value' (default 'percent') - what the legend shows next to each label
28
+ - `unit`: string - appended to the values in the legend and in `aria-valuetext` (e.g. 'GB')
29
29
  - `className`, `ref` and every other `<div>` prop go to the host
30
30
 
31
31
  ## Percentages come from the sum, not from 100
32
32
  Without `max` the reference is the sum of the values, so `[45, 25, 15, 15]` and `[9, 5, 3, 3]`
33
- draw the same picture. Pass `max` when the segments are meant to leave a gap — a quota that is
33
+ draw the same picture. Pass `max` when the segments are meant to leave a gap - a quota that is
34
34
  not full yet. All-zero values fall back to a divisor of 1 instead of producing `NaN%`.
35
35
 
36
36
  ## Colours
37
37
  `color` per item, otherwise the next one from the semantic palette
38
- (`primary → info → success → warning → danger`, cycled), so a group of any length stays readable
38
+ (`primary -> info -> success -> warning -> danger`, cycled), so a group of any length stays readable
39
39
  without picking colours by hand.
40
40
 
41
41
  ## Examples
@@ -48,7 +48,7 @@ The palette `--kpt-color-{primary,info,success,warning,danger}`, the track
48
48
 
49
49
  ## Accessibility
50
50
  The track is `role="meter"` named by `label` (or `meterGroup.label`), with `aria-valuemin="0"`,
51
- `aria-valuenow` set to the sum and `aria-valuemax` set to the real total — `max`, or the sum without
52
- it. `aria-valuetext` spells out the split (“Photos 42 GB, Videos 28 GB, …”), so the segments reach
51
+ `aria-valuenow` set to the sum and `aria-valuemax` set to the real total - `max`, or the sum without
52
+ it. `aria-valuetext` spells out the split ("Photos 42 GB, Videos 28 GB, ..."), so the segments reach
53
53
  the screen reader even with the legend hidden. Keep the legend visible anyway: it is the text
54
54
  alternative to the colours.
@@ -11,11 +11,11 @@ export interface KptMeterGroupProps extends ComponentPropsWithRef<'div'>, KptI18
11
11
  /** Suma odniesienia; domyślnie suma wartości, czyli segmenty wypełniają całość. */
12
12
  max?: number;
13
13
  showLegend?: boolean;
14
- /** Nazwa paska dla czytników ekranu, np. „Miejsce na dysku”; domyślnie `meterGroup.label`. */
14
+ /** Nazwa paska dla czytników ekranu, np. "Miejsce na dysku"; domyślnie `meterGroup.label`. */
15
15
  label?: string;
16
16
  /** Co pokazuje legenda przy etykiecie: udział procentowy albo samą wartość (z `unit`). */
17
17
  legendValue?: 'percent' | 'value';
18
- /** Jednostka dopisywana do wartości — w legendzie (`legendValue="value"`) i w `aria-valuetext`. */
18
+ /** Jednostka dopisywana do wartości - w legendzie (`legendValue="value"`) i w `aria-valuetext`. */
19
19
  unit?: string;
20
20
  }
21
21
  /**
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { cn } from "../internal/cn.js";
3
4
  import { useKptMessages } from "../i18n/i18n-context.js";
@@ -24,7 +25,7 @@ export function KptMeterGroup({ values = [], max, showLegend = true, label = '',
24
25
  const color = (item, index) => item.color || PALETTE[index % PALETTE.length];
25
26
  const withUnit = (value) => (unit ? `${value} ${unit}` : String(value));
26
27
  const legendText = (item) => legendValue === 'value' ? withUnit(item.value) : `${Math.round(percent(item))}%`;
27
- // Podział dla czytnika („Zdjęcia 42 GB, Filmy 28 GB…”) — sam `aria-valuenow` mówi tylko sumę.
28
+ // Podział dla czytnika ("Zdjęcia 42 GB, Filmy 28 GB...") - sam `aria-valuenow` mówi tylko sumę.
28
29
  const valueText = values.map((item) => `${item.label} ${withUnit(item.value)}`).join(', ');
29
30
  return (_jsx("div", { className: cn('kpt-meter-group-host', className), ...rest, children: _jsxs("div", { className: "kpt-meter-group", children: [_jsx("div", { className: "kpt-meter-group__track", role: "meter", "aria-valuemin": 0, "aria-valuenow": sum, "aria-valuemax": total, "aria-valuetext": valueText, "aria-label": label || t('meterGroup.label'), children: values.map((item, index) => (_jsx("span", { className: "kpt-meter-group__segment", style: { width: `${percent(item)}%`, backgroundColor: color(item, index) }, title: item.label }, index))) }), showLegend ? (_jsx("ul", { className: "kpt-meter-group__legend", children: values.map((item, index) => (_jsxs("li", { className: "kpt-meter-group__legend-item", children: [_jsx("span", { className: "kpt-meter-group__dot", style: { backgroundColor: color(item, index) } }), _jsx("span", { children: item.label }), _jsx("span", { className: "kpt-meter-group__val", children: legendText(item) })] }, index))) })) : null] }) }));
30
31
  }
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type KptLayoutMotion, type KptMotionConfig } from '@konce-pt/motion';
3
+ export interface KptMotionProviderProps extends KptMotionConfig {
4
+ children?: ReactNode;
5
+ }
6
+ /**
7
+ * Globalne ustawienie ruchu Koncept UI: czy ruch jest włączony i jaki rodzaj ruchu dostają
8
+ * komponenty, które pozwalają go wybrać. Bez providera ruch jest włączony z domyślnymi
9
+ * wartościami; systemowe "ogranicz ruch" jest respektowane zawsze.
10
+ *
11
+ * `enabled={false}` gasi przejścia CSS wszystkich komponentów (atrybut `data-kpt-motion="off"`
12
+ * i zmienne na `:root` - nakładki w portalach też) oraz ruch sterowany z kodu; wskaźniki
13
+ * ładowania zwalniają zamiast stanąć.
14
+ *
15
+ * @example
16
+ * <KptMotionProvider layout="arc" collapse="fade"><App /></KptMotionProvider>
17
+ * <KptMotionProvider enabled={false}><App /></KptMotionProvider>
18
+ */
19
+ export declare function KptMotionProvider({ enabled, layout, collapse, enter, toggle, children }: Readonly<KptMotionProviderProps>): import("react").JSX.Element;
20
+ /** Konfiguracja ruchu z najbliższego providera; poza providerem `null` (wartości domyślne). */
21
+ export declare function useKptMotion(): KptMotionConfig | null;
22
+ export type { KptLayoutMotion, KptMotionConfig };
@@ -0,0 +1,28 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useLayoutEffect, useMemo } from 'react';
4
+ import { applyMotionConfig } from '@konce-pt/motion';
5
+ const KptMotionContext = createContext(null);
6
+ /**
7
+ * Globalne ustawienie ruchu Koncept UI: czy ruch jest włączony i jaki rodzaj ruchu dostają
8
+ * komponenty, które pozwalają go wybrać. Bez providera ruch jest włączony z domyślnymi
9
+ * wartościami; systemowe "ogranicz ruch" jest respektowane zawsze.
10
+ *
11
+ * `enabled={false}` gasi przejścia CSS wszystkich komponentów (atrybut `data-kpt-motion="off"`
12
+ * i zmienne na `:root` - nakładki w portalach też) oraz ruch sterowany z kodu; wskaźniki
13
+ * ładowania zwalniają zamiast stanąć.
14
+ *
15
+ * @example
16
+ * <KptMotionProvider layout="arc" collapse="fade"><App /></KptMotionProvider>
17
+ * <KptMotionProvider enabled={false}><App /></KptMotionProvider>
18
+ */
19
+ export function KptMotionProvider({ enabled, layout, collapse, enter, toggle, children }) {
20
+ const config = useMemo(() => ({ enabled, layout, collapse, enter, toggle }), [enabled, layout, collapse, enter, toggle]);
21
+ // Korzeń dokumentu, nie wrapper: przejścia w portalach (dialog, drawer) też muszą zgasnąć.
22
+ useLayoutEffect(() => applyMotionConfig(document.documentElement, config), [config]);
23
+ return _jsx(KptMotionContext.Provider, { value: config, children: children });
24
+ }
25
+ /** Konfiguracja ruchu z najbliższego providera; poza providerem `null` (wartości domyślne). */
26
+ export function useKptMotion() {
27
+ return useContext(KptMotionContext);
28
+ }
@@ -7,26 +7,27 @@ Import: `import { KptOrderList } from '@konce-pt/react';`
7
7
  ## DOM
8
8
  <div class="kpt-order-list-host">
9
9
  <div class="kpt-order-list">
10
- <div class="kpt-order-list__controls">…up, down…</div>
10
+ <div class="kpt-order-list__controls">...up, down...</div>
11
11
  <div class="kpt-order-list__panel">
12
12
  <div class="kpt-order-list__header">Order</div>
13
13
  <ul class="kpt-order-list__items">
14
- <li class="kpt-order-list__item is-selected">…</li>…
14
+ <li class="kpt-order-list__item is-selected">...</li>...
15
15
  </ul>
16
16
  </div>
17
17
  </div>
18
18
  </div>
19
19
 
20
20
  ## Props
21
- - `items` / `defaultItems` / `onItemsChange` — the list; the callback receives the new order
21
+ - `items` / `defaultItems` / `onItemsChange` - the list; the callback receives the new order
22
22
  - `header`: string
23
- - `dragdrop` — `false` by default; enables dragging (opt-in, nothing changes without it)
24
- - `renderItem(item, index)` — required; the equivalent of `<ng-template let-item>`
23
+ - `dragdrop` - `false` by default; enables dragging (opt-in, nothing changes without it)
24
+ - `layoutMotion` - `'spring' | 'arc' | 'morph' | 'none'` (default from `KptMotionProvider`, else `spring`) - see below
25
+ - `renderItem(item, index)` - required; the equivalent of `<ng-template let-item>`
25
26
  - `className`, `ref` and every other `<div>` prop go to the host
26
27
 
27
28
  ## The selection follows the item
28
29
  After a move the selection jumps to the new index, so pressing the button again moves the same
29
- entry — with the selection pinned to a position, the second press would move its neighbour. A drop
30
+ entry - with the selection pinned to a position, the second press would move its neighbour. A drop
30
31
  does the same.
31
32
 
32
33
  ## Where a dragged item lands
@@ -43,18 +44,32 @@ dragged one `is-dragging`.
43
44
  The buttons use `orderList.up` and `orderList.down`. Dragging carries no visible label, so it adds
44
45
  no dictionary keys.
45
46
 
47
+ ## Reorder motion
48
+ `layoutMotion` animates a reorder made by the user (buttons, `Alt`+ArrowUp/ArrowDown, dragging):
49
+ - `spring` - the moved item glides to its new place on a spring;
50
+ - `arc` - the moved item lifts (shadow) and lands, above its neighbours;
51
+ - `morph` - the browser's own morph (View Transitions); without support the change is instant;
52
+ - `none` - no motion.
53
+
54
+ Neighbours always make room with a calm spring, and the list scrolls to keep the moved item in
55
+ view. With no value it takes `layout` from `KptMotionProvider` (default `spring`); `enabled: false` and the
56
+ system "reduce motion" setting always win. A list replaced from outside (`items`) switches instantly.
57
+
46
58
  ## Tokens
47
59
  The selection `--kpt-color-primary`, the buttons `--kpt-color-surface-raised`.
48
60
 
49
61
  ## Keyboard
50
62
  The list is a `listbox` with a single Tab stop (roving tabindex), and the selection follows focus:
51
- - `↓` / `↑` select the next / previous item (wrapping), `Home` / `End` the first / last;
52
- - `Alt`+`↑` / `Alt`+`↓` move the selected item one place up / down — focus travels with it, so
63
+ - `ArrowDown` / `ArrowUp` select the next / previous item (wrapping), `Home` / `End` the first / last;
64
+ - `Alt`+`ArrowUp` / `Alt`+`ArrowDown` move the selected item one place up / down - focus travels with it, so
53
65
  repeated presses keep moving the same entry.
54
66
  The up / down buttons stay and act on the same selection.
55
67
 
56
68
  ## Accessibility
57
69
  The list is named after `header` (`aria-label`) and the selected item carries `aria-selected`.
58
70
  Both buttons are labelled from the dictionary and go disabled while nothing is selected. Native
59
- HTML5 drag and drop has no keyboard equivalent — `Alt`+arrows and the buttons cover it, and
71
+ HTML5 drag and drop has no keyboard equivalent - `Alt`+arrows and the buttons cover it, and
60
72
  `dragdrop` adds to them, it never replaces them.
73
+
74
+ ## Announcements
75
+ Every reorder (buttons, Alt+ArrowUp/ArrowDown, drag and drop) is announced in a polite live region: `orderList.moved` with `{position}` and `{total}` - focus does not move, so a screen reader would not hear the new place otherwise.
@@ -1,4 +1,5 @@
1
1
  import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
+ import { type KptLayoutMotion } from '@konce-pt/motion';
2
3
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
4
  export interface KptOrderListProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'children'>, KptI18nOverrides {
4
5
  items?: T[];
@@ -7,18 +8,25 @@ export interface KptOrderListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
7
8
  header?: string;
8
9
  /** Włącza przestawianie pozycji metodą przeciągnij-i-upuść. */
9
10
  dragdrop?: boolean;
10
- /** Szablon elementu — odpowiednik `<ng-template let-item>` z Angulara. */
11
+ /**
12
+ * Ruch przestawiania: `spring` - pozycja płynie na nowe miejsce na sprężynie, `arc` - unosi się
13
+ * z cieniem i ląduje, `morph` - natywny morf przeglądarki (View Transitions), `none` - bez ruchu.
14
+ * Sąsiedzi zawsze robią miejsce spokojną sprężyną. Bez wartości bierze `layout` z `KptMotionProvider`
15
+ * (domyślnie `spring`); `enabled={false}` i systemowe "ogranicz ruch" wyłączają go zawsze.
16
+ */
17
+ layoutMotion?: KptLayoutMotion;
18
+ /** Szablon elementu - odpowiednik `<ng-template let-item>` z Angulara. */
11
19
  renderItem: (item: T, index: number) => ReactNode;
12
20
  }
13
21
  /**
14
- * OrderList — lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
22
+ * OrderList - lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
15
23
  * w górę i w dół. Z `dragdrop` pozycje przestawia się także przeciąganiem.
16
24
  *
17
25
  * Lista to `listbox` z jednym przystankiem Tab (roving tabindex), w którym zaznaczenie idzie
18
- * za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt`+↑/↓ przestawia ją o jedno
26
+ * za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt`+ArrowUp/ArrowDown przestawia ją o jedno
19
27
  * miejsce (fokus jedzie razem z nią).
20
28
  *
21
29
  * @example
22
30
  * <KptOrderList items={tasks} onItemsChange={setTasks} header="Kolejność" dragdrop renderItem={(t) => t.name} />
23
31
  */
24
- export declare function KptOrderList<T>({ items, defaultItems, onItemsChange, header, dragdrop, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptOrderListProps<T>>): import("react").JSX.Element;
32
+ export declare function KptOrderList<T>({ items, defaultItems, onItemsChange, header, dragdrop, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptOrderListProps<T>>): import("react").JSX.Element;
@@ -1,24 +1,40 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
3
+ import { useEffect, useEffectEvent, useId, useLayoutEffect, useRef, useState, } from 'react';
4
+ import { flushSync } from 'react-dom';
5
+ import { isVisibleInScroller, layoutMotionAllowed, morphKeyed, playKeyedMotion, resolveLayoutMotion, revealInScroller, snapshotKeyed, stopKeyedMotion, } from '@konce-pt/motion';
3
6
  import { cn } from "../internal/cn.js";
4
7
  import { composeRefs } from "../internal/compose-refs.js";
5
8
  import { useControllableState } from "../internal/use-controllable-state.js";
6
9
  import { useKptMessages } from "../i18n/i18n-context.js";
7
10
  import { KptIcon } from "../icon/icon.js";
8
11
  import { nextMenuIndex } from "../menu/menu-keys.js";
12
+ import { useKptMotion } from "../motion/motion-context.js";
13
+ /** Klasy ruchu przestawiania - reguły we wspólnym CSS komponentu (duchów tu nie ma: jedna lista). */
14
+ const MOTION_CLASSES = {
15
+ ghostClass: 'kpt-order-list__ghost',
16
+ hiddenClass: 'kpt-order-list__item--waiting',
17
+ movingClass: 'kpt-order-list__item--moving',
18
+ };
19
+ /** Klasa View Transitions dla morfu. */
20
+ const MORPH_CLASS = 'kpt-order-list-morph';
21
+ /** Przewijany pojemnik wiersza. */
22
+ function scrollerOf(element) {
23
+ return element.closest('.kpt-order-list__items');
24
+ }
9
25
  const EMPTY = [];
10
26
  /**
11
- * OrderList — lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
27
+ * OrderList - lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
12
28
  * w górę i w dół. Z `dragdrop` pozycje przestawia się także przeciąganiem.
13
29
  *
14
30
  * Lista to `listbox` z jednym przystankiem Tab (roving tabindex), w którym zaznaczenie idzie
15
- * za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt`+↑/↓ przestawia ją o jedno
31
+ * za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt`+ArrowUp/ArrowDown przestawia ją o jedno
16
32
  * miejsce (fokus jedzie razem z nią).
17
33
  *
18
34
  * @example
19
35
  * <KptOrderList items={tasks} onItemsChange={setTasks} header="Kolejność" dragdrop renderItem={(t) => t.name} />
20
36
  */
21
- export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, header = '', dragdrop = false, renderItem, locale, dictionary, className, ref, ...rest }) {
37
+ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, header = '', dragdrop = false, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }) {
22
38
  const { t } = useKptMessages({ locale, dictionary });
23
39
  const [list, setList] = useControllableState({
24
40
  value: items,
@@ -28,46 +44,119 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
28
44
  const [selected, setSelected] = useState(null);
29
45
  /** Indeks przeciąganej pozycji; `null` gdy nic nie jest przeciągane. */
30
46
  const [dragIndex, setDragIndex] = useState(null);
31
- /** Indeks pozycji pod kursorem — rysuje wskaźnik miejsca upuszczenia. */
47
+ /** Indeks pozycji pod kursorem - rysuje wskaźnik miejsca upuszczenia. */
32
48
  const [overIndex, setOverIndex] = useState(null);
33
- /** Kursor nad pustym obszarem listy — upuszczenie tam dopina na koniec. */
49
+ /** Kursor nad pustym obszarem listy - upuszczenie tam dopina na koniec. */
34
50
  const [listOver, setListOver] = useState(false);
35
51
  /** Pozycja, na którą po renderze trzeba przenieść fokus DOM (klawiatura). */
36
52
  const [focusRequest, setFocusRequest] = useState(null);
37
53
  const rootRef = useRef(null);
54
+ const motionConfig = useKptMotion();
55
+ // `view-transition-name` musi być poprawnym identyfikatorem CSS - `useId` daje dwukropki.
56
+ const morphPrefix = `kpt-order-list-${useId().replaceAll(/[^a-zA-Z0-9-]/g, '')}`;
57
+ /** Który element danych pokazuje każdy wiersz - wiersze mają klucz po indeksie, więc go zmieniają. */
58
+ const keyOf = useRef(new WeakMap());
59
+ /** Stan sprzed zmiany, czekający na commit nowej kolejności. */
60
+ const pending = useRef(null);
61
+ /** Indeks przestawionej pozycji - lista przewija się do niej po zmianie. */
62
+ const revealIndex = useRef(null);
63
+ const stage = () => rootRef.current?.querySelector('.kpt-order-list') ?? null;
64
+ const nodes = () => {
65
+ const root = stage();
66
+ if (!root)
67
+ return [];
68
+ return Array.from(root.querySelectorAll('.kpt-order-list__items > .kpt-order-list__item')).flatMap((element) => keyOf.current.has(element) ? [{ key: keyOf.current.get(element), element }] : []);
69
+ };
70
+ const reveal = () => {
71
+ const row = revealIndex.current === null ? undefined : nodes()[revealIndex.current];
72
+ if (row)
73
+ revealInScroller(row.element, scrollerOf(row.element));
74
+ };
75
+ /**
76
+ * Przestawienie z ruchem. Stan sprzed zmiany mierzymy, zanim React zmieni DOM - dlatego animujemy
77
+ * zmiany z interakcji (przyciski, `Alt`+strzałki, przeciąganie), a lista podmieniona z zewnątrz
78
+ * przełącza się od razu.
79
+ */
80
+ const withMotion = (apply, lead, target, origin) => {
81
+ const motion = resolveLayoutMotion(layoutMotion, motionConfig);
82
+ revealIndex.current = target;
83
+ const root = stage();
84
+ if (motion === 'none' || !root || !layoutMotionAllowed()) {
85
+ apply();
86
+ return;
87
+ }
88
+ if (motion === 'morph') {
89
+ morphKeyed(nodes(), nodes, morphPrefix, MORPH_CLASS, () => {
90
+ flushSync(apply);
91
+ reveal();
92
+ }, (el) => isVisibleInScroller(el, scrollerOf(el)));
93
+ return;
94
+ }
95
+ pending.current = { first: snapshotKeyed(root, nodes(), scrollerOf), motion, lead, origin };
96
+ stopKeyedMotion(root, MOTION_CLASSES);
97
+ apply();
98
+ };
99
+ // Nowa kolejność jest już w DOM (a `keyOf` zaktualizowany refami) - gramy loty od zapamiętanego stanu.
100
+ const playPending = useEffectEvent(() => {
101
+ const job = pending.current;
102
+ pending.current = null;
103
+ const root = stage();
104
+ if (!job || !root)
105
+ return;
106
+ reveal();
107
+ playKeyedMotion(root, job.first, nodes(), { motion: job.motion, scrollerOf, ...MOTION_CLASSES, lead: new Set([job.lead]) }, job.origin);
108
+ });
109
+ useLayoutEffect(() => {
110
+ playPending();
111
+ }, [list]);
112
+ // Żądanie nie jest zerowane w efekcie (setState w efekcie = dodatkowy przebieg renderu): każde jest
113
+ // nowym obiektem, więc efekt rusza raz na żądanie, także o ten sam indeks.
38
114
  useEffect(() => {
39
- if (focusRequest === null)
115
+ if (!focusRequest)
40
116
  return;
41
- rootRef.current?.querySelectorAll('[role="option"]')[focusRequest]?.focus();
42
- setFocusRequest(null);
117
+ rootRef.current?.querySelectorAll('[role="option"]')[focusRequest.index]?.focus();
43
118
  }, [focusRequest]);
44
119
  /**
45
120
  * Przesuwa pozycję spod `index` o jedno miejsce i zwraca jej nowy indeks. Jawny indeks zamiast
46
121
  * `selected`: klawiatura zaznacza i przesuwa w jednym zdarzeniu, a stan z domknięcia byłby stary.
47
122
  */
48
- const moveFrom = (index, dir) => {
123
+ /** Treść regionu `aria-live` po przestawieniu. */
124
+ const [announcement, setAnnouncement] = useState('');
125
+ /**
126
+ * Ogłasza nową pozycję. Ten sam tekst drugi raz pod rząd nie zostałby przeczytany (region reaguje
127
+ * na zmianę), więc naprzemiennie dokładamy niewidoczną spację.
128
+ */
129
+ const announce = (index, total) => {
130
+ const text = t('orderList.moved', { position: index + 1, total });
131
+ setAnnouncement((current) => (current === text ? text + '\u00a0' : text));
132
+ };
133
+ const moveFrom = (index, dir, origin) => {
49
134
  const target = index + dir;
50
135
  if (target < 0 || target >= list.length)
51
136
  return index;
52
137
  const next = [...list];
138
+ const moved = next[index];
53
139
  [next[index], next[target]] = [next[target], next[index]];
54
- setList(next);
55
- // Zaznaczenie wędruje za elementem, nie zostaje na pozycji — inaczej kolejne kliknięcie
56
- // przesuwałoby sąsiada zamiast tego samego wpisu.
57
- setSelected(target);
140
+ withMotion(() => {
141
+ setList(next);
142
+ // Zaznaczenie wędruje za elementem, nie zostaje na pozycji - inaczej kolejne kliknięcie
143
+ // przesuwałoby sąsiada zamiast tego samego wpisu.
144
+ setSelected(target);
145
+ }, moved, target, origin);
146
+ announce(target, next.length);
58
147
  return target;
59
148
  };
60
- const move = (dir) => {
149
+ const move = (dir, origin) => {
61
150
  if (selected !== null)
62
- moveFrom(selected, dir);
151
+ moveFrom(selected, dir, origin);
63
152
  };
64
153
  /** Przystanek Tab: zaznaczona pozycja albo pierwsza. */
65
154
  const tabStop = selected !== null && selected < list.length ? selected : 0;
66
- // Strzałki wybierają pozycję (zaznaczenie idzie za fokusem), `Alt`+↑/↓ ją przestawia.
155
+ // Strzałki wybierają pozycję (zaznaczenie idzie za fokusem), `Alt`+ArrowUp/ArrowDown ją przestawia.
67
156
  const onItemKeyDown = (index, event) => {
68
157
  if (event.altKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {
69
158
  event.preventDefault();
70
- setFocusRequest(moveFrom(index, event.key === 'ArrowUp' ? -1 : 1));
159
+ setFocusRequest({ index: moveFrom(index, event.key === 'ArrowUp' ? -1 : 1, event.currentTarget) });
71
160
  return;
72
161
  }
73
162
  const next = nextMenuIndex(list.length, index, event.key);
@@ -75,7 +164,7 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
75
164
  return;
76
165
  event.preventDefault();
77
166
  setSelected(next);
78
- setFocusRequest(next);
167
+ setFocusRequest({ index: next });
79
168
  };
80
169
  const clearDrag = () => {
81
170
  setDragIndex(null);
@@ -105,15 +194,18 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
105
194
  clearDrag();
106
195
  if (from === null || from === index)
107
196
  return;
108
- // Indeks celu liczony na tablicy sprzed usunięcia — element ląduje na pozycji tego,
197
+ // Indeks celu liczony na tablicy sprzed usunięcia - element ląduje na pozycji tego,
109
198
  // na który go upuszczono (ten sam wzór co przestawianie kolumn w KptDataTable).
110
199
  const next = [...list];
111
200
  const [moved] = next.splice(from, 1);
112
201
  if (moved === undefined)
113
202
  return;
114
203
  next.splice(index, 0, moved);
115
- setList(next);
116
- setSelected(index);
204
+ withMotion(() => {
205
+ setList(next);
206
+ setSelected(index);
207
+ }, moved, index, event.currentTarget);
208
+ announce(index, next.length);
117
209
  };
118
210
  const onListDragOver = (event) => {
119
211
  if (dragIndex === null)
@@ -133,8 +225,14 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
133
225
  if (moved === undefined)
134
226
  return;
135
227
  next.push(moved);
136
- setList(next);
137
- setSelected(next.length - 1);
228
+ withMotion(() => {
229
+ setList(next);
230
+ setSelected(next.length - 1);
231
+ }, moved, next.length - 1, event.currentTarget);
232
+ announce(next.length - 1, next.length);
138
233
  };
139
- return (_jsx("div", { ref: composeRefs(rootRef, ref), className: cn('kpt-order-list-host', className), ...rest, children: _jsxs("div", { className: "kpt-order-list", children: [_jsxs("div", { className: "kpt-order-list__controls", children: [_jsx("button", { type: "button", disabled: selected === null, "aria-label": t('orderList.up'), onClick: () => move(-1), children: _jsx(KptIcon, { name: "arrow-up" }) }), _jsx("button", { type: "button", disabled: selected === null, "aria-label": t('orderList.down'), onClick: () => move(1), children: _jsx(KptIcon, { name: "arrow-down" }) })] }), _jsxs("div", { className: "kpt-order-list__panel", children: [header ? _jsx("div", { className: "kpt-order-list__header", children: header }) : null, _jsx("ul", { className: cn('kpt-order-list__items', listOver && 'is-dragover'), role: "listbox", "aria-label": header || undefined, onDragOver: onListDragOver, onDragLeave: () => setListOver(false), onDrop: onListDrop, children: list.map((item, index) => (_jsx("li", { className: cn('kpt-order-list__item', selected === index && 'is-selected', dragIndex === index && 'is-dragging', dragdrop && 'kpt-order-list__item--draggable', overIndex === index && dragIndex !== index && 'kpt-order-list__item--dragover'), role: "option", "aria-selected": selected === index, tabIndex: index === tabStop ? 0 : -1, onFocus: () => setSelected(index), onKeyDown: (event) => onItemKeyDown(index, event), draggable: dragdrop || undefined, onClick: () => setSelected(index), onDragStart: (event) => onDragStart(index, event), onDragOver: (event) => onDragOver(index, event), onDragLeave: () => setOverIndex(null), onDrop: (event) => onDrop(index, event), onDragEnd: clearDrag, children: renderItem(item, index) }, index))) })] })] }) }));
234
+ return (_jsxs("div", { ref: composeRefs(rootRef, ref), className: cn('kpt-order-list-host', className), ...rest, children: [_jsxs("div", { className: "kpt-order-list", children: [_jsxs("div", { className: "kpt-order-list__controls", children: [_jsx("button", { type: "button", disabled: selected === null, "aria-label": t('orderList.up'), onClick: (event) => move(-1, event.currentTarget), children: _jsx(KptIcon, { name: "arrow-up" }) }), _jsx("button", { type: "button", disabled: selected === null, "aria-label": t('orderList.down'), onClick: (event) => move(1, event.currentTarget), children: _jsx(KptIcon, { name: "arrow-down" }) })] }), _jsxs("div", { className: "kpt-order-list__panel", children: [header ? _jsx("div", { className: "kpt-order-list__header", children: header }) : null, _jsx("ul", { className: cn('kpt-order-list__items', listOver && 'is-dragover'), role: "listbox", "aria-label": header || undefined, onDragOver: onListDragOver, onDragLeave: () => setListOver(false), onDrop: onListDrop, children: list.map((item, index) => (_jsx("li", { ref: (element) => {
235
+ if (element)
236
+ keyOf.current.set(element, item);
237
+ }, className: cn('kpt-order-list__item', selected === index && 'is-selected', dragIndex === index && 'is-dragging', dragdrop && 'kpt-order-list__item--draggable', overIndex === index && dragIndex !== index && 'kpt-order-list__item--dragover'), role: "option", "aria-selected": selected === index, tabIndex: index === tabStop ? 0 : -1, onFocus: () => setSelected(index), onKeyDown: (event) => onItemKeyDown(index, event), draggable: dragdrop || undefined, onClick: () => setSelected(index), onDragStart: (event) => onDragStart(index, event), onDragOver: (event) => onDragOver(index, event), onDragLeave: () => setOverIndex(null), onDrop: (event) => onDrop(index, event), onDragEnd: clearDrag, children: renderItem(item, index) }, index))) })] })] }), _jsx("p", { className: "kpt-visually-hidden", "aria-live": "polite", children: announcement })] }));
140
238
  }
@@ -5,22 +5,22 @@ Import: `import { KptPaginator } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-paginator">
8
- <div class="kpt-paginator__size"><label>Rows: <select class="kpt-paginator__select">…</select></label></div>
9
- <span class="kpt-paginator__range">1–10 of 120</span>
10
- <div class="kpt-paginator__nav">…two KptButton…</div>
8
+ <div class="kpt-paginator__size"><label>Rows: <select class="kpt-paginator__select">...</select></label></div>
9
+ <span class="kpt-paginator__range">1-10 of 120</span>
10
+ <div class="kpt-paginator__nav">...two KptButton...</div>
11
11
  </div>
12
12
 
13
13
  ## Props
14
- - `length`: number — the total number of items (required)
15
- - `pageIndex` / `defaultPageIndex` / `onPageIndexChange` — the 0-based page
16
- - `pageSize` / `defaultPageSize` / `onPageSizeChange` — the page size (default 10)
14
+ - `length`: number - the total number of items (required)
15
+ - `pageIndex` / `defaultPageIndex` / `onPageIndexChange` - the 0-based page
16
+ - `pageSize` / `defaultPageSize` / `onPageSizeChange` - the page size (default 10)
17
17
  - `pageSizeOptions`: readonly number[] (default [5, 10, 20, 50])
18
18
 
19
19
  The select always offers the current `pageSize` even when it is absent from this list: without
20
20
  that, `pageSize={8}` against the defaults left no matching option, so the control displayed the
21
21
  first entry while the table paged by eight.
22
- - `prevIcon`, `nextIcon`: ReactNode — the navigation button content
23
- - `locale`, `dictionary` — i18n overrides for this component only
22
+ - `prevIcon`, `nextIcon`: ReactNode - the navigation button content
23
+ - `locale`, `dictionary` - i18n overrides for this component only
24
24
  - `className`, `ref` and every other `<div>` prop go to the paginator root
25
25
 
26
26
  ## Behaviour