@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,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 KptPickListProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'children'>, KptI18nOverrides {
4
5
  source?: T[];
@@ -13,13 +14,20 @@ export interface KptPickListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
13
14
  targetHeader?: string;
14
15
  /** Włącza porządkowanie i przenoszenie elementów metodą przeciągnij-i-upuść. */
15
16
  dragdrop?: boolean;
16
- /** Szablon elementu — odpowiednik `<ng-template let-item>` z Angulara. */
17
+ /**
18
+ * Ruch przy przenoszeniu i przestawianiu elementów: `spring` - element płynie na sprężynie,
19
+ * `arc` - unosi się i leci po łuku, `morph` - natywny morf przeglądarki (View Transitions),
20
+ * `none` - bez ruchu. Bez wartości bierze `layout` z `KptMotionProvider` (domyślnie `spring`);
21
+ * `<KptMotionProvider enabled={false}>` i systemowe "ogranicz ruch" wyłączają go zawsze.
22
+ */
23
+ layoutMotion?: KptLayoutMotion;
24
+ /** Szablon elementu - odpowiednik `<ng-template let-item>` z Angulara. */
17
25
  renderItem: (item: T, index: number) => ReactNode;
18
26
  }
19
27
  /**
20
- * PickList — transfer elementów między dwiema listami. Klik zaznacza, przyciski pośrodku
28
+ * PickList - transfer elementów między dwiema listami. Klik zaznacza, przyciski pośrodku
21
29
  * przenoszą zaznaczone albo wszystko, dwuklik przerzuca pojedynczy element na drugą stronę.
22
- * Z `dragdrop` dochodzi przeciąganie — porządkowanie wewnątrz panelu i przenoszenie na
30
+ * Z `dragdrop` dochodzi przeciąganie - porządkowanie wewnątrz panelu i przenoszenie na
23
31
  * konkretną pozycję drugiego panelu.
24
32
  *
25
33
  * Każda lista to `listbox` z wielokrotnym wyborem i jednym przystankiem Tab (roving tabindex):
@@ -34,4 +42,4 @@ export interface KptPickListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
34
42
  * renderItem={(item) => item.name}
35
43
  * />
36
44
  */
37
- export declare function KptPickList<T>({ source, defaultSource, onSourceChange, target, defaultTarget, onTargetChange, sourceHeader, targetHeader, dragdrop, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptPickListProps<T>>): import("react").JSX.Element;
45
+ export declare function KptPickList<T>({ source, defaultSource, onSourceChange, target, defaultTarget, onTargetChange, sourceHeader, targetHeader, dragdrop, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptPickListProps<T>>): import("react").JSX.Element;
@@ -1,16 +1,32 @@
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";
9
13
  const EMPTY = [];
14
+ /** Klasy ruchu przenoszenia - reguły we wspólnym CSS komponentu. */
15
+ const MOTION_CLASSES = {
16
+ ghostClass: 'kpt-pick-list__ghost',
17
+ hiddenClass: 'kpt-pick-list__item--waiting',
18
+ movingClass: 'kpt-pick-list__item--moving',
19
+ };
20
+ /** Klasa View Transitions dla morfu. */
21
+ const MORPH_CLASS = 'kpt-pick-list-morph';
22
+ /** Przewijany pojemnik wiersza - lista panelu. */
23
+ function scrollerOf(element) {
24
+ return element.closest('.kpt-pick-list__items');
25
+ }
10
26
  /**
11
- * PickList — transfer elementów między dwiema listami. Klik zaznacza, przyciski pośrodku
27
+ * PickList - transfer elementów między dwiema listami. Klik zaznacza, przyciski pośrodku
12
28
  * przenoszą zaznaczone albo wszystko, dwuklik przerzuca pojedynczy element na drugą stronę.
13
- * Z `dragdrop` dochodzi przeciąganie — porządkowanie wewnątrz panelu i przenoszenie na
29
+ * Z `dragdrop` dochodzi przeciąganie - porządkowanie wewnątrz panelu i przenoszenie na
14
30
  * konkretną pozycję drugiego panelu.
15
31
  *
16
32
  * Każda lista to `listbox` z wielokrotnym wyborem i jednym przystankiem Tab (roving tabindex):
@@ -25,7 +41,7 @@ const EMPTY = [];
25
41
  * renderItem={(item) => item.name}
26
42
  * />
27
43
  */
28
- export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, target, defaultTarget = EMPTY, onTargetChange, sourceHeader, targetHeader, dragdrop = false, renderItem, locale, dictionary, className, ref, ...rest }) {
44
+ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, target, defaultTarget = EMPTY, onTargetChange, sourceHeader, targetHeader, dragdrop = false, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }) {
29
45
  const { t } = useKptMessages({ locale, dictionary });
30
46
  const [left, setLeft] = useControllableState({
31
47
  value: source,
@@ -41,18 +57,80 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
41
57
  // po obu stronach się przesuwają, a referencja zostaje ta sama.
42
58
  const [selLeft, setSelLeft] = useState(new Set());
43
59
  const [selRight, setSelRight] = useState(new Set());
44
- /** Przeciągany element — strona i pozycja w jej tablicy. */
60
+ /** Przeciągany element - strona i pozycja w jej tablicy. */
45
61
  const [drag, setDrag] = useState(null);
46
- /** Element pod kursorem — rysuje wskaźnik miejsca upuszczenia. */
62
+ /** Element pod kursorem - rysuje wskaźnik miejsca upuszczenia. */
47
63
  const [over, setOver] = useState(null);
48
- /** Panel, nad którego pustym obszarem jest kursor — upuszczenie tam dopina na koniec. */
64
+ /** Panel, nad którego pustym obszarem jest kursor - upuszczenie tam dopina na koniec. */
49
65
  const [listOver, setListOver] = useState(null);
50
- /** Pozycja, która ostatnio miała fokus w każdej liście — ona jest przystankiem Tab. */
66
+ /** Pozycja, która ostatnio miała fokus w każdej liście - ona jest przystankiem Tab. */
51
67
  const [focusLeft, setFocusLeft] = useState(0);
52
68
  const [focusRight, setFocusRight] = useState(0);
53
69
  /** Pozycja, na którą po renderze trzeba przenieść fokus DOM (klawiatura). */
54
70
  const [focusRequest, setFocusRequest] = useState(null);
55
71
  const rootRef = useRef(null);
72
+ const motionConfig = useKptMotion();
73
+ // `view-transition-name` musi być poprawnym identyfikatorem CSS - `useId` daje dwukropki.
74
+ const morphPrefix = `kpt-pick-list-${useId().replaceAll(/[^a-zA-Z0-9-]/g, '')}`;
75
+ /** Który element danych pokazuje każdy wiersz - wiersze mają klucz po indeksie, więc go zmieniają. */
76
+ const keyOf = useRef(new WeakMap());
77
+ /** Stan sprzed zmiany, czekający na commit nowego układu. */
78
+ const pending = useRef(null);
79
+ /** Elementy, które przy ostatniej zmianie przeszły na drugą stronę - lista przewija się do nich. */
80
+ const crossed = useRef([]);
81
+ const stage = () => rootRef.current?.querySelector('.kpt-pick-list') ?? null;
82
+ const nodes = () => {
83
+ const root = stage();
84
+ if (!root)
85
+ return [];
86
+ return Array.from(root.querySelectorAll('.kpt-pick-list__items > .kpt-pick-list__item')).flatMap((element) => keyOf.current.has(element) ? [{ key: keyOf.current.get(element), element }] : []);
87
+ };
88
+ /** Przewija listę docelową do ostatniego przeniesionego elementu - ląduje tam, gdzie go widać. */
89
+ const revealCrossed = () => {
90
+ const last = crossed.current.at(-1);
91
+ if (last === undefined)
92
+ return;
93
+ const node = nodes().find((n) => n.key === last);
94
+ if (node)
95
+ revealInScroller(node.element, scrollerOf(node.element));
96
+ };
97
+ /**
98
+ * Zmiana list z ruchem. Stan sprzed zmiany mierzymy, zanim React zmieni DOM - dlatego animujemy
99
+ * zmiany z interakcji (przyciski, dwuklik, Enter, przeciąganie), a listy podmienione z zewnątrz
100
+ * przełączają się od razu.
101
+ */
102
+ const withMotion = (apply, origin) => {
103
+ const motion = resolveLayoutMotion(layoutMotion, motionConfig);
104
+ crossed.current = [];
105
+ const root = stage();
106
+ if (motion === 'none' || !root || !layoutMotionAllowed()) {
107
+ apply();
108
+ return;
109
+ }
110
+ if (motion === 'morph') {
111
+ morphKeyed(nodes(), nodes, morphPrefix, MORPH_CLASS, () => {
112
+ flushSync(apply);
113
+ revealCrossed();
114
+ }, (el) => isVisibleInScroller(el, scrollerOf(el)));
115
+ return;
116
+ }
117
+ pending.current = { first: snapshotKeyed(root, nodes(), scrollerOf), motion, origin };
118
+ stopKeyedMotion(root, MOTION_CLASSES);
119
+ apply();
120
+ };
121
+ // Nowy układ jest już w DOM (a `keyOf` zaktualizowany refami) - gramy loty od zapamiętanego stanu.
122
+ const playPending = useEffectEvent(() => {
123
+ const job = pending.current;
124
+ pending.current = null;
125
+ const root = stage();
126
+ if (!job || !root)
127
+ return;
128
+ revealCrossed();
129
+ playKeyedMotion(root, job.first, nodes(), { motion: job.motion, scrollerOf, ...MOTION_CLASSES }, job.origin);
130
+ });
131
+ useLayoutEffect(() => {
132
+ playPending();
133
+ }, [left, right]);
56
134
  const listOf = (side) => (side === 'source' ? left : right);
57
135
  const setListOf = (side) => (side === 'source' ? setLeft : setRight);
58
136
  const selectionOf = (side) => (side === 'source' ? selLeft : selRight);
@@ -60,15 +138,16 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
60
138
  const other = (side) => (side === 'source' ? 'target' : 'source');
61
139
  const focusOf = (side) => (side === 'source' ? focusLeft : focusRight);
62
140
  const setFocusOf = (side) => (side === 'source' ? setFocusLeft : setFocusRight);
63
- /** Przystanek Tab listy — ostatnio skupiona pozycja, przycięta do długości listy. */
141
+ /** Przystanek Tab listy - ostatnio skupiona pozycja, przycięta do długości listy. */
64
142
  const tabIndexOf = (side) => Math.min(focusOf(side), listOf(side).length - 1);
143
+ // Żądanie nie jest zerowane w efekcie (setState w efekcie = dodatkowy przebieg renderu): każde jest
144
+ // nowym obiektem, więc efekt rusza raz na żądanie, także o ten sam indeks.
65
145
  useEffect(() => {
66
146
  if (!focusRequest)
67
147
  return;
68
148
  const list = rootRef.current?.querySelectorAll('.kpt-pick-list__items')[focusRequest.side === 'source' ? 0 : 1];
69
149
  const options = list?.querySelectorAll('[role="option"]') ?? [];
70
150
  options[Math.min(focusRequest.index, options.length - 1)]?.focus();
71
- setFocusRequest(null);
72
151
  }, [focusRequest]);
73
152
  const focusItem = (side, index) => {
74
153
  setFocusOf(side)(index);
@@ -82,7 +161,21 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
82
161
  next.add(item);
83
162
  setSelectionOf(side)(next);
84
163
  };
85
- const move = (from, all) => {
164
+ const headerOf = (side) => side === 'source' ? (sourceHeader ?? t('pickList.available')) : (targetHeader ?? t('pickList.selected'));
165
+ /** Treść regionu `aria-live` po przeniesieniu. */
166
+ const [announcement, setAnnouncement] = useState('');
167
+ /**
168
+ * Ogłasza przeniesienie. Ten sam tekst drugi raz pod rząd nie zostałby przeczytany (region
169
+ * reaguje na zmianę), więc naprzemiennie dokładamy niewidoczną spację.
170
+ */
171
+ const announce = (count, to) => {
172
+ const text = t('pickList.moved', { count, list: headerOf(to) });
173
+ setAnnouncement((current) => (current === text ? text + '\u00a0' : text));
174
+ };
175
+ const move = (from, all, origin) => {
176
+ withMotion(() => moveNow(from, all), origin);
177
+ };
178
+ const moveNow = (from, all) => {
86
179
  const to = other(from);
87
180
  const fromItems = listOf(from);
88
181
  const selection = selectionOf(from);
@@ -91,7 +184,9 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
91
184
  return;
92
185
  setListOf(from)(fromItems.filter((item) => !moving.includes(item)));
93
186
  setListOf(to)([...listOf(to), ...moving]);
187
+ crossed.current = moving;
94
188
  setSelectionOf(from)(new Set());
189
+ announce(moving.length, to);
95
190
  };
96
191
  /** Przenosi jeden element między panelami, wstawiając go pod wskazanym indeksem. */
97
192
  const transfer = (fromSide, fromIndex, toSide, toIndex) => {
@@ -103,7 +198,11 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
103
198
  toItems.splice(toIndex, 0, moved);
104
199
  setListOf(fromSide)(fromItems);
105
200
  setListOf(toSide)(toItems);
106
- // Element opuszcza panel — jego zaznaczenie po tamtej stronie przestaje cokolwiek znaczyć.
201
+ if (fromSide !== toSide) {
202
+ crossed.current = [moved];
203
+ announce(1, toSide);
204
+ }
205
+ // Element opuszcza panel - jego zaznaczenie po tamtej stronie przestaje cokolwiek znaczyć.
107
206
  const selection = selectionOf(fromSide);
108
207
  if (selection.has(moved)) {
109
208
  const next = new Set(selection);
@@ -112,12 +211,12 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
112
211
  }
113
212
  };
114
213
  /** Dwuklik: przenosi wyłącznie klikniętą pozycję, niezależnie od zaznaczenia. */
115
- const moveOne = (from, item) => {
214
+ const moveOne = (from, item, origin) => {
116
215
  const index = listOf(from).indexOf(item);
117
216
  if (index === -1)
118
217
  return;
119
218
  const to = other(from);
120
- transfer(from, index, to, listOf(to).length);
219
+ withMotion(() => transfer(from, index, to, listOf(to).length), origin);
121
220
  };
122
221
  const onItemKeyDown = (side, index, item, event) => {
123
222
  if (event.key === ' ') {
@@ -127,8 +226,8 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
127
226
  }
128
227
  if (event.key === 'Enter') {
129
228
  event.preventDefault();
130
- moveOne(side, item);
131
- // Pozycja zniknęła z listy — fokus zostaje w tym samym miejscu listy, na następnej.
229
+ moveOne(side, item, event.currentTarget);
230
+ // Pozycja zniknęła z listy - fokus zostaje w tym samym miejscu listy, na następnej.
132
231
  focusItem(side, index);
133
232
  return;
134
233
  }
@@ -166,20 +265,21 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
166
265
  clearDrag();
167
266
  if (from === null)
168
267
  return;
268
+ const origin = event.currentTarget;
169
269
  if (from.side !== side) {
170
- transfer(from.side, from.index, side, index);
270
+ withMotion(() => transfer(from.side, from.index, side, index), origin);
171
271
  return;
172
272
  }
173
273
  if (from.index === index)
174
274
  return;
175
- // Indeks celu liczony na tablicy sprzed usunięcia — element ląduje na pozycji tego,
275
+ // Indeks celu liczony na tablicy sprzed usunięcia - element ląduje na pozycji tego,
176
276
  // na który go upuszczono (ten sam wzór co przestawianie kolumn w KptDataTable).
177
277
  const next = [...listOf(side)];
178
278
  const [moved] = next.splice(from.index, 1);
179
279
  if (moved === undefined)
180
280
  return;
181
281
  next.splice(index, 0, moved);
182
- setListOf(side)(next);
282
+ withMotion(() => setListOf(side)(next), origin);
183
283
  };
184
284
  const onListDragOver = (side, event) => {
185
285
  if (drag === null)
@@ -194,8 +294,9 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
194
294
  clearDrag();
195
295
  if (from === null)
196
296
  return;
297
+ const origin = event.currentTarget;
197
298
  if (from.side !== side) {
198
- transfer(from.side, from.index, side, listOf(side).length);
299
+ withMotion(() => transfer(from.side, from.index, side, listOf(side).length), origin);
199
300
  return;
200
301
  }
201
302
  const next = [...listOf(side)];
@@ -203,16 +304,19 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
203
304
  if (moved === undefined)
204
305
  return;
205
306
  next.push(moved);
206
- setListOf(side)(next);
307
+ withMotion(() => setListOf(side)(next), origin);
207
308
  };
208
309
  const column = (side) => {
209
310
  const items = listOf(side);
210
311
  const selection = selectionOf(side);
211
- const header = side === 'source' ? (sourceHeader ?? t('pickList.available')) : (targetHeader ?? t('pickList.selected'));
312
+ const header = headerOf(side);
212
313
  return (_jsxs("div", { className: "kpt-pick-list__col", children: [_jsx("div", { className: "kpt-pick-list__header", children: header }), _jsx("ul", { className: cn('kpt-pick-list__items', listOver === side && 'is-dragover'), role: "listbox", "aria-multiselectable": "true", "aria-label": header, onDragOver: (event) => onListDragOver(side, event), onDragLeave: () => setListOver(null), onDrop: (event) => onListDrop(side, event), children: items.map((item, index) => {
213
314
  const dragging = drag?.side === side && drag.index === index;
214
- return (_jsx("li", { className: cn('kpt-pick-list__item', selection.has(item) && 'is-selected', dragging && 'is-dragging', dragdrop && 'kpt-pick-list__item--draggable', over?.side === side && over.index === index && !dragging && 'kpt-pick-list__item--dragover'), role: "option", "aria-selected": selection.has(item), tabIndex: index === tabIndexOf(side) ? 0 : -1, onFocus: () => setFocusOf(side)(index), onKeyDown: (event) => onItemKeyDown(side, index, item, event), draggable: dragdrop || undefined, onClick: () => toggle(side, item), onDoubleClick: () => moveOne(side, item), onDragStart: (event) => onDragStart(side, index, event), onDragOver: (event) => onDragOver(side, index, event), onDragLeave: () => setOver(null), onDrop: (event) => onDrop(side, index, event), onDragEnd: clearDrag, children: renderItem(item, index) }, index));
315
+ return (_jsx("li", { ref: (element) => {
316
+ if (element)
317
+ keyOf.current.set(element, item);
318
+ }, className: cn('kpt-pick-list__item', selection.has(item) && 'is-selected', dragging && 'is-dragging', dragdrop && 'kpt-pick-list__item--draggable', over?.side === side && over.index === index && !dragging && 'kpt-pick-list__item--dragover'), role: "option", "aria-selected": selection.has(item), tabIndex: index === tabIndexOf(side) ? 0 : -1, onFocus: () => setFocusOf(side)(index), onKeyDown: (event) => onItemKeyDown(side, index, item, event), draggable: dragdrop || undefined, onClick: () => toggle(side, item), onDoubleClick: (event) => moveOne(side, item, event.currentTarget), onDragStart: (event) => onDragStart(side, index, event), onDragOver: (event) => onDragOver(side, index, event), onDragLeave: () => setOver(null), onDrop: (event) => onDrop(side, index, event), onDragEnd: clearDrag, children: renderItem(item, index) }, index));
215
319
  }) })] }));
216
320
  };
217
- return (_jsx("div", { ref: composeRefs(rootRef, ref), className: cn('kpt-pick-list-host', className), ...rest, children: _jsxs("div", { className: "kpt-pick-list", children: [column('source'), _jsxs("div", { className: "kpt-pick-list__controls", children: [_jsxs("button", { type: "button", "aria-label": t('pickList.moveAllRight'), onClick: () => move('source', true), children: [_jsx(KptIcon, { name: "chevron-right" }), _jsx(KptIcon, { name: "chevron-right" })] }), _jsx("button", { type: "button", "aria-label": t('pickList.moveRight'), onClick: () => move('source', false), children: _jsx(KptIcon, { name: "chevron-right" }) }), _jsx("button", { type: "button", "aria-label": t('pickList.moveLeft'), onClick: () => move('target', false), children: _jsx(KptIcon, { name: "chevron-left" }) }), _jsxs("button", { type: "button", "aria-label": t('pickList.moveAllLeft'), onClick: () => move('target', true), children: [_jsx(KptIcon, { name: "chevron-left" }), _jsx(KptIcon, { name: "chevron-left" })] })] }), column('target')] }) }));
321
+ return (_jsxs("div", { ref: composeRefs(rootRef, ref), className: cn('kpt-pick-list-host', className), ...rest, children: [_jsxs("div", { className: "kpt-pick-list", children: [column('source'), _jsxs("div", { className: "kpt-pick-list__controls", children: [_jsxs("button", { type: "button", "aria-label": t('pickList.moveAllRight'), "aria-disabled": !left.length || undefined, onClick: (event) => move('source', true, event.currentTarget), children: [_jsx(KptIcon, { name: "chevron-right" }), _jsx(KptIcon, { name: "chevron-right" })] }), _jsx("button", { type: "button", "aria-label": t('pickList.moveRight'), "aria-disabled": !selLeft.size || undefined, onClick: (event) => move('source', false, event.currentTarget), children: _jsx(KptIcon, { name: "chevron-right" }) }), _jsx("button", { type: "button", "aria-label": t('pickList.moveLeft'), "aria-disabled": !selRight.size || undefined, onClick: (event) => move('target', false, event.currentTarget), children: _jsx(KptIcon, { name: "chevron-left" }) }), _jsxs("button", { type: "button", "aria-label": t('pickList.moveAllLeft'), "aria-disabled": !right.length || undefined, onClick: (event) => move('target', true, event.currentTarget), children: [_jsx(KptIcon, { name: "chevron-left" }), _jsx(KptIcon, { name: "chevron-left" })] })] }), column('target')] }), _jsx("p", { className: "kpt-visually-hidden", "aria-live": "polite", children: announcement })] }));
218
322
  }
@@ -1,20 +1,20 @@
1
1
  # KptPopover (@konce-pt/react)
2
2
 
3
- Any content in a bubble pinned to its trigger — richer than a tooltip.
3
+ Any content in a bubble pinned to its trigger - richer than a tooltip.
4
4
  Import: `import { KptPopover } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <span class="kpt-popover-host">
8
- <span class="kpt-popover__trigger">…trigger…</span>
8
+ <span class="kpt-popover__trigger">...trigger...</span>
9
9
  </span>
10
10
  <!-- while open, in a portal on document.body: -->
11
- <div class="kpt-popover__panel" role="dialog">…children…</div>
11
+ <div class="kpt-popover__panel" role="dialog">...children...</div>
12
12
 
13
13
  ## Props
14
- - `trigger`: ReactNode — the element that opens the bubble, rendered in place
15
- - `children`: ReactNode — the panel content
16
- - `open` / `defaultOpen` / `onOpenChange` — controlled or uncontrolled
17
- - `placement`: 'bottom' (default) | 'top' — the preferred side; it flips when there is no room
14
+ - `trigger`: ReactNode - the element that opens the bubble, rendered in place
15
+ - `children`: ReactNode - the panel content
16
+ - `open` / `defaultOpen` / `onOpenChange` - controlled or uncontrolled
17
+ - `placement`: 'bottom' (default) | 'top' - the preferred side; it flips when there is no room
18
18
  - `className`, `ref` and every other `<span>` prop go to the host
19
19
 
20
20
  ## The panel is a portal
@@ -22,7 +22,7 @@ The Angular port stands on CDK Overlay. Here the panel renders into a portal on
22
22
  with the same behaviour: positioned below the trigger, flipping above when there is no room, closed
23
23
  by a click outside or by Escape, and following scroll and resize.
24
24
 
25
- Clicking the trigger while the bubble is open closes it and does not reopen it — the transparent
25
+ Clicking the trigger while the bubble is open closes it and does not reopen it - the transparent
26
26
  backdrop takes that click, exactly as the CDK backdrop does.
27
27
 
28
28
  ## Examples
@@ -43,7 +43,10 @@ The panel is `role="dialog"` with an `id` the trigger points to.
43
43
 
44
44
  ## Focus and keyboard
45
45
  The control inside the trigger slot gets `aria-haspopup="dialog"`, a live `aria-expanded` and, while
46
- open, `aria-controls` — on the real `<button>`, not on the wrapper. Opening moves focus to the first
46
+ open, `aria-controls` - on the real `<button>`, not on the wrapper. Opening moves focus to the first
47
47
  interactive element of the bubble; `Escape` or a click outside closes it, and focus returns to the
48
- trigger when it was inside the bubble. Focus is not trapped — the popover is supporting content, not
48
+ trigger when it was inside the bubble. Focus is not trapped - the popover is supporting content, not
49
49
  a modal.
50
+
51
+ ## Name and Escape
52
+ Give the panel `ariaLabel` - it is a `role="dialog"`. Escape closes only the top-most panel and does not reach an enclosing `<dialog>`, so a popover inside a dialog closes alone.
@@ -1,6 +1,6 @@
1
1
  import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
2
  export interface KptPopoverProps extends Omit<ComponentPropsWithRef<'span'>, 'content'> {
3
- /** Element otwierający dymek — renderowany w miejscu popovera. */
3
+ /** Element otwierający dymek - renderowany w miejscu popovera. */
4
4
  trigger: ReactNode;
5
5
  /** Treść panelu. */
6
6
  children?: ReactNode;
@@ -9,9 +9,11 @@ export interface KptPopoverProps extends Omit<ComponentPropsWithRef<'span'>, 'co
9
9
  onOpenChange?: (open: boolean) => void;
10
10
  /** Preferowana strona dymka; gdy brakuje miejsca, przechodzi na drugą. */
11
11
  placement?: 'bottom' | 'top';
12
+ /** Nazwa panelu (`role="dialog"`) - okno bez nazwy czytnik ogłasza jako samo "okno dialogowe". */
13
+ ariaLabel?: string;
12
14
  }
13
15
  /**
14
- * Popover — dowolna treść w dymku przypiętym do wyzwalacza (bogatszy niż tooltip).
16
+ * Popover - dowolna treść w dymku przypiętym do wyzwalacza (bogatszy niż tooltip).
15
17
  *
16
18
  * Port Angulara stoi na CDK Overlay; tutaj panel renderuje się w portalu do `document.body`,
17
19
  * z tym samym zachowaniem: pozycja pod wyzwalaczem (albo nad nim przy `placement="top"`)
@@ -23,7 +25,7 @@ export interface KptPopoverProps extends Omit<ComponentPropsWithRef<'span'>, 'co
23
25
  *
24
26
  * @example
25
27
  * <KptPopover trigger={<KptButton variant="outline">Szczegóły</KptButton>}>
26
- * <div>Bogata treść popovera…</div>
28
+ * <div>Bogata treść popovera...</div>
27
29
  * </KptPopover>
28
30
  */
29
- export declare function KptPopover({ trigger, children, open, defaultOpen, onOpenChange, placement, className, ...rest }: Readonly<KptPopoverProps>): import("react").JSX.Element;
31
+ export declare function KptPopover({ trigger, children, open, defaultOpen, onOpenChange, placement, ariaLabel, className, ...rest }: Readonly<KptPopoverProps>): import("react").JSX.Element;
@@ -1,13 +1,14 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useRef } from 'react';
3
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
4
  import { cn } from "../internal/cn.js";
4
5
  import { KptOverlay } from "../internal/overlay.js";
5
6
  import { useControllableState } from "../internal/use-controllable-state.js";
6
7
  import { useKptId } from "../internal/use-id.js";
7
- /** Elementy, które same przyjmują fokus — pierwszy z nich dostaje fokus po otwarciu dymka. */
8
+ /** Elementy, które same przyjmują fokus - pierwszy z nich dostaje fokus po otwarciu dymka. */
8
9
  const FOCUSABLE = 'a[href], button:not(:disabled), input:not(:disabled), select, textarea, [tabindex]:not([tabindex="-1"])';
9
10
  /**
10
- * Popover — dowolna treść w dymku przypiętym do wyzwalacza (bogatszy niż tooltip).
11
+ * Popover - dowolna treść w dymku przypiętym do wyzwalacza (bogatszy niż tooltip).
11
12
  *
12
13
  * Port Angulara stoi na CDK Overlay; tutaj panel renderuje się w portalu do `document.body`,
13
14
  * z tym samym zachowaniem: pozycja pod wyzwalaczem (albo nad nim przy `placement="top"`)
@@ -19,11 +20,17 @@ const FOCUSABLE = 'a[href], button:not(:disabled), input:not(:disabled), select,
19
20
  *
20
21
  * @example
21
22
  * <KptPopover trigger={<KptButton variant="outline">Szczegóły</KptButton>}>
22
- * <div>Bogata treść popovera…</div>
23
+ * <div>Bogata treść popovera...</div>
23
24
  * </KptPopover>
24
25
  */
25
- export function KptPopover({ trigger, children, open, defaultOpen = false, onOpenChange, placement = 'bottom', className, ...rest }) {
26
+ export function KptPopover({ trigger, children, open, defaultOpen = false, onOpenChange, placement = 'bottom', ariaLabel = '', className, ...rest }) {
26
27
  const triggerRef = useRef(null);
28
+ /** Kotwica panelu - w stanie, bo czyta ją render; ref zostaje dla handlerów. */
29
+ const [anchor, setAnchor] = useState(null);
30
+ const setTrigger = useCallback((element) => {
31
+ triggerRef.current = element;
32
+ setAnchor(element);
33
+ }, []);
27
34
  const panelRef = useRef(null);
28
35
  const panelId = useKptId(undefined, 'kpt-popover');
29
36
  const [isOpen, setOpen] = useControllableState({
@@ -44,7 +51,7 @@ export function KptPopover({ trigger, children, open, defaultOpen = false, onOpe
44
51
  else
45
52
  control.removeAttribute('aria-controls');
46
53
  }, [isOpen, trigger, panelId]);
47
- // Fokus do dymka klatkę później — `KptOverlay` trzyma panel niewidoczny, dopóki go nie zmierzy.
54
+ // Fokus do dymka klatkę później - `KptOverlay` trzyma panel niewidoczny, dopóki go nie zmierzy.
48
55
  useEffect(() => {
49
56
  if (!isOpen)
50
57
  return;
@@ -58,5 +65,5 @@ export function KptPopover({ trigger, children, open, defaultOpen = false, onOpe
58
65
  findControl()?.focus();
59
66
  setOpen(false);
60
67
  }, [setOpen]);
61
- return (_jsxs("span", { className: cn('kpt-popover-host', className), ...rest, children: [_jsx("span", { className: "kpt-popover__trigger", ref: triggerRef, onClick: () => setOpen(!isOpen), children: trigger }), _jsx(KptOverlay, { open: isOpen, anchor: triggerRef.current, onClose: close, offset: 6, preferAbove: placement === 'top', children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-popover__panel", role: "dialog", children: children }) })] }));
68
+ return (_jsxs("span", { className: cn('kpt-popover-host', className), ...rest, children: [_jsx("span", { className: "kpt-popover__trigger", ref: setTrigger, onClick: () => setOpen(!isOpen), children: trigger }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, offset: 6, preferAbove: placement === 'top', children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-popover__panel", role: "dialog", "aria-label": ariaLabel || undefined, children: children }) })] }));
62
69
  }
@@ -1,12 +1,12 @@
1
1
  # KptProgress (@konce-pt/react)
2
2
 
3
- A progress indicator — linear or circular, determinate (`min`–`max`) or indeterminate (`value` = null).
3
+ A progress indicator - linear or circular, determinate (`min`-`max`) or indeterminate (`value` = null).
4
4
  Import: `import { KptProgress } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <!-- linear, with a label, a buffer and a value -->
8
8
  <div class="kpt-progress-host" data-type="linear" data-size="md" data-variant="primary" data-label-position="top">
9
- <span class="kpt-progress__label">Loading…</span>
9
+ <span class="kpt-progress__label">Loading...</span>
10
10
  <div class="kpt-progress__linear" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="80">
11
11
  <div class="kpt-progress__buffer" style="width: 92%"></div>
12
12
  <div class="kpt-progress__bar" style="width: 80%"></div>
@@ -23,28 +23,28 @@ Import: `import { KptProgress } from '@konce-pt/react';`
23
23
  <span class="kpt-progress__value" aria-hidden="true">75%</span>
24
24
  </div>
25
25
 
26
- The label, the track and the value are siblings straight under the host — there is no wrapper element.
26
+ The label, the track and the value are siblings straight under the host - there is no wrapper element.
27
27
  `data-variant`, `data-type`, `data-size` and `data-label-position` all sit on the host, which is also
28
28
  where the private `--_color` and `--_thickness` are resolved. This markup matches the Angular port
29
29
  element for element, so both share one stylesheet.
30
30
 
31
31
  ## Props
32
- - `value`: number | null (default null) — a value on the `min`–`max` scale, or null for indeterminate
32
+ - `value`: number | null (default null) - a value on the `min`-`max` scale, or null for indeterminate
33
33
  - `min`: number (default 0); `max`: number (default 100)
34
34
  - `variant`: 'primary' | 'success' | 'danger' | 'warning' | 'info' (default 'primary')
35
35
  - `type`: 'linear' | 'circular' (default 'linear')
36
- - `size`: 'sm' | 'md' | 'lg' (default 'md') — track thickness, and arc width on the circular variant
37
- - `diameter`: number (default 40) — the circular variant's size in pixels
38
- - `bufferValue`: number | null (default null) — a second, dimmed bar behind the main one; linear only
39
- - `showValue`: boolean (default false) — turns the value area on; `children` needs it too
36
+ - `size`: 'sm' | 'md' | 'lg' (default 'md') - track thickness, and arc width on the circular variant
37
+ - `diameter`: number (default 40) - the circular variant's size in pixels
38
+ - `bufferValue`: number | null (default null) - a second, dimmed bar behind the main one; linear only
39
+ - `showValue`: boolean (default false) - turns the value area on; `children` needs it too
40
40
  - `valueFormat`: 'percent' | 'fraction' | 'none' (default 'percent')
41
- - `label`: string — descriptive text next to the bar; it also becomes the `aria-label`
42
- - `labelPosition`: 'top' | 'bottom' | 'end' (default 'top') — ignored by the circular variant
43
- - `locale`, `dictionary` — per-instance dictionary overrides
41
+ - `label`: string - descriptive text next to the bar; it also becomes the `aria-label`
42
+ - `labelPosition`: 'top' | 'bottom' | 'end' (default 'top') - ignored by the circular variant
43
+ - `locale`, `dictionary` - per-instance dictionary overrides
44
44
  - `className`, `ref` and every other `<div>` prop go to the host
45
45
 
46
46
  ## Value label
47
- `showValue` opens the value area; `valueFormat` decides what goes in it — `percent` renders `80%`,
47
+ `showValue` opens the value area; `valueFormat` decides what goes in it - `percent` renders `80%`,
48
48
  `fraction` renders `152 / 160` from `value` and `max`, `none` leaves it empty. Both strings come from
49
49
  the `KptMessages` dictionary (`progress.percent`, `progress.fraction`), so a new locale can reshape them.
50
50
 
@@ -57,17 +57,17 @@ the accessible name.
57
57
 
58
58
  ## How the arc is drawn
59
59
  The circle lives in a fixed `viewBox="0 0 40 40"` with `r=16`, so the circumference is computed from
60
- that radius, not from `diameter` — the SVG scales, the maths does not change. The arc is the dash
60
+ that radius, not from `diameter` - the SVG scales, the maths does not change. The arc is the dash
61
61
  offset: full circumference means empty, zero means complete. `size` only changes `stroke-width`, and
62
62
  the widest step still fits inside the box, so no arc is ever clipped.
63
63
 
64
- Values outside the range are clamped rather than rejected, `max` ≤ `min` collapses to zero, and the
65
- buffer is never allowed behind the main bar — a computed percentage that briefly overshoots cannot
64
+ Values outside the range are clamped rather than rejected, `max` <= `min` collapses to zero, and the
65
+ buffer is never allowed behind the main bar - a computed percentage that briefly overshoots cannot
66
66
  break the drawing.
67
67
 
68
68
  ## Examples
69
69
  <KptProgress value={60} />
70
- <KptProgress value={80} label="Loading…" showValue />
70
+ <KptProgress value={80} label="Loading..." showValue />
71
71
  <KptProgress value={152} max={160} size="lg" showValue valueFormat="fraction" labelPosition="bottom" />
72
72
  <KptProgress value={65} showValue labelPosition="end" />
73
73
  <KptProgress value={38} bufferValue={62} />
@@ -91,5 +91,5 @@ leaves the value out, which is how a screen reader learns the progress is unknow
91
91
  announcing the raw number as a percentage. The visible value is `aria-hidden`, so it is never read
92
92
  twice. The accessible name comes from `label`, or from the dictionary when there is none.
93
93
 
94
- Under `prefers-reduced-motion: reduce` the indeterminate animation slows down instead of stopping —
94
+ Under `prefers-reduced-motion: reduce` the indeterminate animation slows down instead of stopping -
95
95
  a frozen progress indicator reads as a hung application.
@@ -3,12 +3,12 @@ import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
3
  export type KptProgressVariant = 'primary' | 'success' | 'danger' | 'warning' | 'info';
4
4
  export type KptProgressType = 'linear' | 'circular';
5
5
  export type KptProgressSize = 'sm' | 'md' | 'lg';
6
- /** Postać etykiety wartości: procent, „ile z ilu" albo brak. */
6
+ /** Postać etykiety wartości: procent, "ile z ilu" albo brak. */
7
7
  export type KptProgressValueFormat = 'percent' | 'fraction' | 'none';
8
8
  /** Gdzie siada wiersz etykiety względem paska (tylko `type="linear"`). */
9
9
  export type KptProgressLabelPosition = 'top' | 'bottom' | 'end';
10
10
  export interface KptProgressProps extends ComponentPropsWithRef<'div'>, KptI18nOverrides {
11
- /** Wartość w skali `min`–`max` albo `null` = postęp nieokreślony. */
11
+ /** Wartość w skali `min`-`max` albo `null` = postęp nieokreślony. */
12
12
  value?: number | null;
13
13
  min?: number;
14
14
  max?: number;
@@ -18,26 +18,26 @@ export interface KptProgressProps extends ComponentPropsWithRef<'div'>, KptI18nO
18
18
  size?: KptProgressSize;
19
19
  /** Średnica wariantu kołowego w pikselach. */
20
20
  diameter?: number;
21
- /** Postęp buforowania — drugi, przygaszony pasek pod głównym (tylko liniowy). */
21
+ /** Postęp buforowania - drugi, przygaszony pasek pod głównym (tylko liniowy). */
22
22
  bufferValue?: number | null;
23
- /** Włącza obszar etykiety wartości — razem z nim renderuje się `children`. */
23
+ /** Włącza obszar etykiety wartości - razem z nim renderuje się `children`. */
24
24
  showValue?: boolean;
25
25
  valueFormat?: KptProgressValueFormat;
26
26
  /** Tekst opisowy obok paska; służy też za `aria-label`. */
27
27
  label?: string;
28
28
  labelPosition?: KptProgressLabelPosition;
29
- /** Zastępuje sformatowaną wartość — wymaga `showValue`. */
29
+ /** Zastępuje sformatowaną wartość - wymaga `showValue`. */
30
30
  children?: ReactNode;
31
31
  }
32
32
  /**
33
- * Wskaźnik postępu — liniowy lub kołowy, określony (`min`–`max`) albo nieokreślony (`value` = null).
33
+ * Wskaźnik postępu - liniowy lub kołowy, określony (`min`-`max`) albo nieokreślony (`value` = null).
34
34
  *
35
35
  * Etykietę wartości włącza `showValue`; `children` zastępuje sformatowaną wartość,
36
36
  * więc w środku koła można pokazać cokolwiek.
37
37
  *
38
38
  * @example
39
39
  * <KptProgress value={60} />
40
- * <KptProgress value={80} label="Ładowanie…" showValue />
40
+ * <KptProgress value={80} label="Ładowanie..." showValue />
41
41
  * <KptProgress value={152} max={160} showValue valueFormat="fraction" labelPosition="bottom" />
42
42
  * <KptProgress value={38} bufferValue={62} />
43
43
  * <KptProgress type="circular" value={75} variant="success" showValue />