@konce-pt/react 0.11.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +128 -64
  2. package/dist/accordion/accordion.d.ts +14 -6
  3. package/dist/accordion/accordion.js +25 -17
  4. package/dist/accordion/llms.txt +22 -10
  5. package/dist/alert/alert.d.ts +2 -2
  6. package/dist/alert/alert.js +3 -2
  7. package/dist/alert/llms.txt +10 -9
  8. package/dist/app-shell/app-shell.d.ts +14 -14
  9. package/dist/app-shell/app-shell.js +22 -15
  10. package/dist/app-shell/llms.txt +16 -15
  11. package/dist/auth/auth-types.d.ts +6 -6
  12. package/dist/auth/auth.d.ts +2 -2
  13. package/dist/auth/auth.js +24 -15
  14. package/dist/auth/llms.txt +12 -11
  15. package/dist/autocomplete/autocomplete.d.ts +19 -6
  16. package/dist/autocomplete/autocomplete.js +32 -11
  17. package/dist/autocomplete/llms.txt +19 -5
  18. package/dist/avatar/avatar.d.ts +6 -6
  19. package/dist/avatar/avatar.js +6 -5
  20. package/dist/avatar/llms.txt +10 -10
  21. package/dist/avatar-group/avatar-group.d.ts +4 -4
  22. package/dist/avatar-group/avatar-group.js +4 -3
  23. package/dist/avatar-group/llms.txt +8 -8
  24. package/dist/backdrop/backdrop.d.ts +7 -26
  25. package/dist/backdrop/backdrop.js +32 -27
  26. package/dist/backdrop/llms.txt +27 -27
  27. package/dist/badge/badge.d.ts +3 -3
  28. package/dist/badge/badge.js +1 -1
  29. package/dist/badge/llms.txt +11 -11
  30. package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
  31. package/dist/bottom-sheet/bottom-sheet.js +5 -4
  32. package/dist/bottom-sheet/llms.txt +11 -8
  33. package/dist/breadcrumb/breadcrumb.d.ts +8 -2
  34. package/dist/breadcrumb/breadcrumb.js +11 -3
  35. package/dist/breadcrumb/llms.txt +10 -2
  36. package/dist/button/button.d.ts +3 -3
  37. package/dist/button/button.js +10 -9
  38. package/dist/button/llms.txt +27 -19
  39. package/dist/button-group/button-group.d.ts +18 -5
  40. package/dist/button-group/button-group.js +54 -6
  41. package/dist/button-group/llms.txt +27 -18
  42. package/dist/card/card.d.ts +8 -8
  43. package/dist/card/card.js +10 -9
  44. package/dist/card/llms.txt +20 -20
  45. package/dist/carousel/carousel.d.ts +6 -6
  46. package/dist/carousel/carousel.js +8 -5
  47. package/dist/carousel/llms.txt +10 -10
  48. package/dist/charts/chart-legend.d.ts +3 -3
  49. package/dist/charts/chart-legend.js +2 -1
  50. package/dist/charts/chart-tooltip.d.ts +3 -3
  51. package/dist/charts/chart-tooltip.js +1 -1
  52. package/dist/charts/chart.d.ts +4 -3
  53. package/dist/charts/chart.js +18 -10
  54. package/dist/charts/llms.txt +10 -7
  55. package/dist/charts-entry/public-api.js +2 -2
  56. package/dist/chat/chat.d.ts +17 -10
  57. package/dist/chat/chat.js +77 -23
  58. package/dist/chat/llms.txt +39 -15
  59. package/dist/chat-composer/chat-composer.d.ts +20 -7
  60. package/dist/chat-composer/chat-composer.js +29 -7
  61. package/dist/chat-composer/llms.txt +20 -11
  62. package/dist/chat-dock/chat-dock.d.ts +11 -4
  63. package/dist/chat-dock/chat-dock.js +10 -6
  64. package/dist/chat-dock/llms.txt +15 -14
  65. package/dist/chat-entry/public-api.js +1 -1
  66. package/dist/chat-message/chat-message.d.ts +12 -5
  67. package/dist/chat-message/chat-message.js +19 -8
  68. package/dist/chat-message/llms.txt +16 -15
  69. package/dist/chat-typing/chat-typing.d.ts +2 -2
  70. package/dist/chat-typing/chat-typing.js +4 -3
  71. package/dist/chat-typing/llms.txt +6 -6
  72. package/dist/checkbox/checkbox.d.ts +13 -6
  73. package/dist/checkbox/checkbox.js +31 -5
  74. package/dist/checkbox/llms.txt +26 -11
  75. package/dist/chip/chip.d.ts +4 -4
  76. package/dist/chip/chip.js +3 -2
  77. package/dist/chip/llms.txt +11 -11
  78. package/dist/chips-input/chips-input.d.ts +6 -4
  79. package/dist/chips-input/chips-input.js +47 -12
  80. package/dist/chips-input/llms.txt +18 -8
  81. package/dist/clock/clock.d.ts +11 -6
  82. package/dist/clock/clock.js +38 -8
  83. package/dist/clock/llms.txt +12 -8
  84. package/dist/color-picker/color-picker.d.ts +9 -5
  85. package/dist/color-picker/color-picker.js +37 -18
  86. package/dist/color-picker/llms.txt +8 -5
  87. package/dist/confirm/confirm-container.d.ts +3 -3
  88. package/dist/confirm/confirm-container.js +6 -5
  89. package/dist/confirm/confirm-store.d.ts +4 -4
  90. package/dist/confirm/confirm-store.js +11 -5
  91. package/dist/confirm/llms.txt +8 -7
  92. package/dist/context-menu/context-menu.d.ts +1 -1
  93. package/dist/context-menu/context-menu.js +37 -14
  94. package/dist/context-menu/llms.txt +10 -7
  95. package/dist/data-table/data-table-types.d.ts +5 -5
  96. package/dist/data-table/data-table.d.ts +37 -5
  97. package/dist/data-table/data-table.js +426 -119
  98. package/dist/data-table/export-csv.d.ts +3 -3
  99. package/dist/data-table/export-csv.js +8 -10
  100. package/dist/data-table/llms.txt +127 -79
  101. package/dist/data-view/data-view.d.ts +13 -5
  102. package/dist/data-view/data-view.js +68 -6
  103. package/dist/data-view/llms.txt +29 -10
  104. package/dist/date-range/date-range.d.ts +20 -8
  105. package/dist/date-range/date-range.js +86 -63
  106. package/dist/date-range/llms.txt +32 -18
  107. package/dist/datepicker/datepicker.d.ts +22 -8
  108. package/dist/datepicker/datepicker.js +103 -71
  109. package/dist/datepicker/llms.txt +36 -22
  110. package/dist/dialog/dialog.d.ts +4 -4
  111. package/dist/dialog/dialog.js +32 -11
  112. package/dist/dialog/llms.txt +13 -10
  113. package/dist/divider/divider.d.ts +7 -1
  114. package/dist/divider/divider.js +3 -2
  115. package/dist/divider/llms.txt +4 -3
  116. package/dist/drawer/drawer.d.ts +9 -4
  117. package/dist/drawer/drawer.js +5 -4
  118. package/dist/drawer/llms.txt +13 -10
  119. package/dist/empty/empty.d.ts +2 -2
  120. package/dist/empty/empty.js +1 -1
  121. package/dist/empty/llms.txt +9 -9
  122. package/dist/fab/fab.d.ts +1 -1
  123. package/dist/fab/fab.js +1 -1
  124. package/dist/fab/llms.txt +10 -6
  125. package/dist/fieldset/fieldset.d.ts +18 -4
  126. package/dist/fieldset/fieldset.js +12 -6
  127. package/dist/fieldset/llms.txt +26 -9
  128. package/dist/file-upload/file-upload.d.ts +8 -2
  129. package/dist/file-upload/file-upload.js +22 -11
  130. package/dist/file-upload/llms.txt +12 -9
  131. package/dist/form-field/form-field-context.d.ts +4 -4
  132. package/dist/form-field/form-field.d.ts +12 -4
  133. package/dist/form-field/form-field.js +27 -6
  134. package/dist/form-field/llms.txt +25 -11
  135. package/dist/galleria/galleria.d.ts +3 -3
  136. package/dist/galleria/galleria.js +9 -6
  137. package/dist/galleria/llms.txt +7 -7
  138. package/dist/grid/col.d.ts +4 -4
  139. package/dist/grid/col.js +2 -2
  140. package/dist/grid/flex.d.ts +3 -3
  141. package/dist/grid/flex.js +1 -1
  142. package/dist/grid/grid.d.ts +7 -7
  143. package/dist/grid/grid.js +3 -3
  144. package/dist/grid/layout.d.ts +2 -2
  145. package/dist/grid/layout.js +2 -2
  146. package/dist/grid/llms.txt +15 -15
  147. package/dist/grid-entry/public-api.js +1 -1
  148. package/dist/i18n/i18n-context.d.ts +6 -6
  149. package/dist/i18n/i18n-context.js +27 -5
  150. package/dist/icon/icon-registry.d.ts +3 -3
  151. package/dist/icon/icon-registry.js +3 -3
  152. package/dist/icon/icon.d.ts +4 -4
  153. package/dist/icon/icon.js +10 -7
  154. package/dist/icon/llms.txt +13 -13
  155. package/dist/icon-button/icon-button.d.ts +2 -2
  156. package/dist/icon-button/icon-button.js +1 -1
  157. package/dist/icon-button/llms.txt +9 -5
  158. package/dist/icons-entry/public-api.d.ts +2 -2
  159. package/dist/icons-entry/public-api.js +3 -3
  160. package/dist/image/image.js +5 -5
  161. package/dist/image/llms.txt +13 -13
  162. package/dist/input/input.d.ts +18 -5
  163. package/dist/input/input.js +22 -6
  164. package/dist/input/llms.txt +25 -11
  165. package/dist/input-mask/input-mask.d.ts +7 -2
  166. package/dist/input-mask/input-mask.js +17 -43
  167. package/dist/input-mask/llms.txt +8 -5
  168. package/dist/input-number/input-number.d.ts +11 -9
  169. package/dist/input-number/input-number.js +25 -21
  170. package/dist/input-number/llms.txt +17 -14
  171. package/dist/input-otp/input-otp.d.ts +18 -5
  172. package/dist/input-otp/input-otp.js +48 -24
  173. package/dist/input-otp/llms.txt +18 -7
  174. package/dist/internal/calendar-focus.d.ts +1 -1
  175. package/dist/internal/calendar-focus.js +3 -3
  176. package/dist/internal/cn.d.ts +1 -1
  177. package/dist/internal/mask.d.ts +14 -0
  178. package/dist/internal/mask.js +62 -0
  179. package/dist/internal/number-group.d.ts +22 -0
  180. package/dist/internal/number-group.js +53 -0
  181. package/dist/internal/option-key.d.ts +6 -0
  182. package/dist/internal/option-key.js +8 -0
  183. package/dist/internal/option-nav.d.ts +4 -4
  184. package/dist/internal/option-nav.js +5 -5
  185. package/dist/internal/overlay-container.js +1 -1
  186. package/dist/internal/overlay.d.ts +3 -3
  187. package/dist/internal/overlay.js +40 -10
  188. package/dist/internal/password-strength.d.ts +6 -0
  189. package/dist/internal/password-strength.js +74 -0
  190. package/dist/internal/roving.d.ts +2 -2
  191. package/dist/internal/roving.js +3 -3
  192. package/dist/internal/scroll-lock.d.ts +6 -0
  193. package/dist/internal/scroll-lock.js +35 -0
  194. package/dist/internal/slot-children.d.ts +13 -0
  195. package/dist/internal/slot-children.js +31 -0
  196. package/dist/internal/slot.d.ts +3 -3
  197. package/dist/internal/slot.js +2 -2
  198. package/dist/internal/step.d.ts +12 -0
  199. package/dist/internal/step.js +31 -0
  200. package/dist/internal/tween.d.ts +5 -5
  201. package/dist/internal/tween.js +7 -8
  202. package/dist/internal/types.d.ts +2 -2
  203. package/dist/internal/use-breakpoint.d.ts +2 -2
  204. package/dist/internal/use-breakpoint.js +4 -4
  205. package/dist/internal/use-controllable-state.d.ts +5 -0
  206. package/dist/internal/use-controllable-state.js +25 -4
  207. package/dist/internal/use-id.d.ts +2 -2
  208. package/dist/internal/use-id.js +2 -2
  209. package/dist/internal/use-modal-focus.d.ts +2 -1
  210. package/dist/internal/use-modal-focus.js +14 -3
  211. package/dist/knob/knob.d.ts +7 -4
  212. package/dist/knob/knob.js +27 -22
  213. package/dist/knob/llms.txt +18 -11
  214. package/dist/listbox/listbox.d.ts +8 -6
  215. package/dist/listbox/listbox.js +37 -17
  216. package/dist/listbox/llms.txt +12 -9
  217. package/dist/loader/llms.txt +56 -0
  218. package/dist/loader/loader.d.ts +49 -0
  219. package/dist/loader/loader.js +68 -0
  220. package/dist/map/llms.txt +30 -23
  221. package/dist/map/map-create-dialog.d.ts +4 -4
  222. package/dist/map/map-create-dialog.js +36 -28
  223. package/dist/map/map-hours-field.d.ts +4 -4
  224. package/dist/map/map-hours-field.js +8 -7
  225. package/dist/map/map-image-field.d.ts +2 -2
  226. package/dist/map/map-image-field.js +6 -5
  227. package/dist/map/map-legend.d.ts +4 -4
  228. package/dist/map/map-legend.js +3 -2
  229. package/dist/map/map-poi-card.d.ts +3 -3
  230. package/dist/map/map-poi-card.js +10 -9
  231. package/dist/map/map-search.d.ts +17 -6
  232. package/dist/map/map-search.js +70 -43
  233. package/dist/map/map.d.ts +25 -13
  234. package/dist/map/map.js +86 -57
  235. package/dist/map/ports.d.ts +9 -9
  236. package/dist/map/ports.js +6 -6
  237. package/dist/map-entry/public-api.js +2 -2
  238. package/dist/megamenu/llms.txt +18 -7
  239. package/dist/megamenu/megamenu.d.ts +12 -6
  240. package/dist/megamenu/megamenu.js +23 -14
  241. package/dist/mention/llms.txt +15 -15
  242. package/dist/mention/mention.d.ts +5 -5
  243. package/dist/mention/mention.js +2 -2
  244. package/dist/mention/mentions.d.ts +1 -1
  245. package/dist/mention/mentions.js +1 -1
  246. package/dist/menu/llms.txt +12 -12
  247. package/dist/menu/menu-item.d.ts +4 -4
  248. package/dist/menu/menu-keys.d.ts +2 -2
  249. package/dist/menu/menu-keys.js +5 -5
  250. package/dist/menu/menu-rows.js +1 -0
  251. package/dist/menu/menu.d.ts +2 -2
  252. package/dist/menu/menu.js +15 -8
  253. package/dist/menubar/llms.txt +19 -8
  254. package/dist/menubar/menubar.d.ts +11 -5
  255. package/dist/menubar/menubar.js +23 -11
  256. package/dist/meter-group/llms.txt +12 -12
  257. package/dist/meter-group/meter-group.d.ts +2 -2
  258. package/dist/meter-group/meter-group.js +2 -1
  259. package/dist/motion/motion-context.d.ts +22 -0
  260. package/dist/motion/motion-context.js +28 -0
  261. package/dist/order-list/llms.txt +24 -9
  262. package/dist/order-list/order-list.d.ts +12 -4
  263. package/dist/order-list/order-list.js +123 -25
  264. package/dist/paginator/llms.txt +8 -8
  265. package/dist/paginator/paginator.js +7 -4
  266. package/dist/panel/llms.txt +25 -13
  267. package/dist/panel/panel.d.ts +11 -3
  268. package/dist/panel/panel.js +12 -7
  269. package/dist/password/llms.txt +19 -7
  270. package/dist/password/password.d.ts +2 -2
  271. package/dist/password/password.js +27 -16
  272. package/dist/peek/llms.txt +11 -11
  273. package/dist/peek/peek.d.ts +6 -6
  274. package/dist/peek/peek.js +41 -19
  275. package/dist/pick-list/llms.txt +35 -12
  276. package/dist/pick-list/pick-list.d.ts +12 -4
  277. package/dist/pick-list/pick-list.js +128 -24
  278. package/dist/popover/llms.txt +13 -10
  279. package/dist/popover/popover.d.ts +6 -4
  280. package/dist/popover/popover.js +14 -7
  281. package/dist/progress/llms.txt +17 -17
  282. package/dist/progress/progress.d.ts +7 -7
  283. package/dist/progress/progress.js +7 -6
  284. package/dist/public-api.d.ts +16 -4
  285. package/dist/public-api.js +13 -7
  286. package/dist/radio-group/llms.txt +16 -6
  287. package/dist/radio-group/radio-group.d.ts +12 -3
  288. package/dist/radio-group/radio-group.js +23 -4
  289. package/dist/rating/llms.txt +20 -13
  290. package/dist/rating/rating-pointer.d.ts +16 -0
  291. package/dist/rating/rating-pointer.js +26 -0
  292. package/dist/rating/rating.d.ts +6 -6
  293. package/dist/rating/rating.js +77 -12
  294. package/dist/rich-text/lists.d.ts +2 -2
  295. package/dist/rich-text/lists.js +7 -7
  296. package/dist/rich-text/llms.txt +35 -12
  297. package/dist/rich-text/rich-text.d.ts +13 -14
  298. package/dist/rich-text/rich-text.js +311 -142
  299. package/dist/rich-text/sanitize.d.ts +11 -2
  300. package/dist/rich-text/sanitize.js +80 -32
  301. package/dist/rich-text/tables.d.ts +3 -3
  302. package/dist/rich-text/tables.js +3 -3
  303. package/dist/roadmap/llms.txt +23 -17
  304. package/dist/roadmap/roadmap.d.ts +6 -6
  305. package/dist/roadmap/roadmap.js +102 -25
  306. package/dist/roadmap-entry/public-api.js +2 -2
  307. package/dist/scroll-top/llms.txt +6 -6
  308. package/dist/scroll-top/scroll-top.d.ts +1 -1
  309. package/dist/scroll-top/scroll-top.js +2 -1
  310. package/dist/select/llms.txt +22 -12
  311. package/dist/select/select.d.ts +10 -8
  312. package/dist/select/select.js +87 -47
  313. package/dist/shared/types.d.ts +22 -1
  314. package/dist/shared/types.js +9 -1
  315. package/dist/sidenav/llms.txt +9 -9
  316. package/dist/sidenav/sidenav.d.ts +2 -3
  317. package/dist/sidenav/sidenav.js +5 -4
  318. package/dist/skeleton/llms.txt +3 -3
  319. package/dist/skeleton/skeleton.d.ts +1 -1
  320. package/dist/skeleton/skeleton.js +1 -1
  321. package/dist/slider/llms.txt +34 -12
  322. package/dist/slider/slider-drag.d.ts +26 -0
  323. package/dist/slider/slider-drag.js +79 -0
  324. package/dist/slider/slider.d.ts +8 -5
  325. package/dist/slider/slider.js +38 -8
  326. package/dist/speech/llms.txt +97 -0
  327. package/dist/speech/speech-button.d.ts +44 -0
  328. package/dist/speech/speech-button.js +86 -0
  329. package/dist/speech/speech-wave.d.ts +19 -0
  330. package/dist/speech/speech-wave.js +16 -0
  331. package/dist/speech/use-speech-recognition.d.ts +81 -0
  332. package/dist/speech/use-speech-recognition.js +179 -0
  333. package/dist/speed-dial/llms.txt +14 -8
  334. package/dist/speed-dial/speed-dial.d.ts +1 -1
  335. package/dist/speed-dial/speed-dial.js +3 -2
  336. package/dist/spinner/llms.txt +7 -7
  337. package/dist/spinner/spinner.d.ts +1 -1
  338. package/dist/spinner/spinner.js +2 -1
  339. package/dist/split-button/llms.txt +21 -15
  340. package/dist/split-button/split-button.d.ts +2 -2
  341. package/dist/split-button/split-button.js +13 -6
  342. package/dist/splitter/llms.txt +11 -11
  343. package/dist/splitter/splitter.d.ts +3 -3
  344. package/dist/splitter/splitter.js +25 -10
  345. package/dist/stepper/llms.txt +35 -13
  346. package/dist/stepper/stepper.d.ts +6 -6
  347. package/dist/stepper/stepper.js +60 -13
  348. package/dist/switch/llms.txt +15 -5
  349. package/dist/switch/switch.d.ts +10 -3
  350. package/dist/switch/switch.js +18 -4
  351. package/dist/switch-group/llms.txt +11 -8
  352. package/dist/switch-group/switch-group.d.ts +6 -4
  353. package/dist/switch-group/switch-group.js +9 -7
  354. package/dist/tabs/llms.txt +12 -9
  355. package/dist/tabs/tabs.d.ts +5 -5
  356. package/dist/tabs/tabs.js +36 -20
  357. package/dist/textarea/llms.txt +23 -12
  358. package/dist/textarea/textarea.d.ts +19 -6
  359. package/dist/textarea/textarea.js +22 -7
  360. package/dist/timeline/llms.txt +4 -4
  361. package/dist/timeline/timeline.d.ts +1 -1
  362. package/dist/timeline/timeline.js +1 -1
  363. package/dist/toast/llms.txt +50 -17
  364. package/dist/toast/toast-container.d.ts +9 -3
  365. package/dist/toast/toast-container.js +18 -9
  366. package/dist/toast/toast-store.d.ts +42 -2
  367. package/dist/toast/toast-store.js +36 -1
  368. package/dist/toolbar/llms.txt +7 -7
  369. package/dist/toolbar/toolbar.d.ts +3 -3
  370. package/dist/toolbar/toolbar.js +2 -2
  371. package/dist/tooltip/llms.txt +14 -12
  372. package/dist/tooltip/tooltip.d.ts +5 -4
  373. package/dist/tooltip/tooltip.js +100 -41
  374. package/dist/tree/llms.txt +25 -11
  375. package/dist/tree/tree-keys.d.ts +5 -5
  376. package/dist/tree/tree-keys.js +7 -7
  377. package/dist/tree/tree.d.ts +17 -5
  378. package/dist/tree/tree.js +62 -20
  379. package/dist/update/llms.txt +54 -0
  380. package/dist/update/update.d.ts +49 -0
  381. package/dist/update/update.js +82 -0
  382. package/package.json +18 -15
@@ -1,6 +1,8 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Children, isValidElement, useRef, } from 'react';
3
+ import { isValidElement, useRef, } from 'react';
3
4
  import { cn } from "../internal/cn.js";
5
+ import { slotChildren, warnUnslottedChild } from "../internal/slot-children.js";
4
6
  import { useControllableState } from "../internal/use-controllable-state.js";
5
7
  import { useKptId } from "../internal/use-id.js";
6
8
  import { useKptMessages } from "../i18n/i18n-context.js";
@@ -19,9 +21,9 @@ KptSplitterEnd.kptSplitterSlot = 'end';
19
21
  * Dwa panele z przeciąganym uchwytem. `horizontal` stawia je obok siebie, `vertical` jeden pod
20
22
  * drugim.
21
23
  *
22
- * Uchwyt to `role="separator"` z wartością (wzorzec WAI-ARIA „window splitter”): strzałki
24
+ * Uchwyt to `role="separator"` z wartością (wzorzec WAI-ARIA "window splitter"): strzałki
23
25
  * przesuwają go o 2%, `Home`/`End` dosuwają do minimum i maksimum. `aria-orientation` opisuje
24
- * linię uchwytu, nie układ — przy panelach obok siebie linia jest pionowa.
26
+ * linię uchwytu, nie układ - przy panelach obok siebie linia jest pionowa.
25
27
  *
26
28
  * @example
27
29
  * <KptSplitter startSize={size} onStartSizeChange={setSize}>
@@ -40,16 +42,18 @@ export function KptSplitter({ orientation = 'horizontal', startSize, defaultStar
40
42
  });
41
43
  let start = null;
42
44
  let end = null;
43
- Children.forEach(children, (child) => {
44
- if (!isValidElement(child))
45
- return;
45
+ for (const child of slotChildren(children)) {
46
+ if (!isValidElement(child)) {
47
+ warnUnslottedChild('KptSplitter', child, '<KptSplitter.Start> / <KptSplitter.End>');
48
+ continue;
49
+ }
46
50
  const slot = child.type?.kptSplitterSlot;
47
51
  const content = child.props.children;
48
52
  if (slot === 'start')
49
53
  start = content;
50
54
  else if (slot === 'end')
51
55
  end = content;
52
- });
56
+ }
53
57
  const clamp = (pct) => Math.min(100 - minSize, Math.max(minSize, Math.round(pct)));
54
58
  const onPointerDown = (event) => {
55
59
  event.preventDefault();
@@ -58,18 +62,24 @@ export function KptSplitter({ orientation = 'horizontal', startSize, defaultStar
58
62
  return;
59
63
  // Nasłuch na oknie, nie na uchwycie: przy szybkim ruchu kursor wyprzedza wąski pasek
60
64
  // i bez tego przeciąganie urywałoby się po kilku pikselach.
65
+ // W RTL panel "start" stoi po prawej (flex idzie za kierunkiem pisma), więc mierzymy od prawej.
66
+ const rtl = getComputedStyle(container).direction === 'rtl';
61
67
  const move = (e) => {
62
68
  const rect = container.getBoundingClientRect();
63
69
  setSize(clamp(orientation === 'horizontal'
64
- ? ((e.clientX - rect.left) / rect.width) * 100
70
+ ? ((rtl ? rect.right - e.clientX : e.clientX - rect.left) / rect.width) * 100
65
71
  : ((e.clientY - rect.top) / rect.height) * 100));
66
72
  };
73
+ // `pointercancel`: dotyk przerwany przez system nie wysyła `pointerup` - bez sprzątania
74
+ // `pointermove` dalej przesuwałby uchwyt.
67
75
  const up = () => {
68
76
  window.removeEventListener('pointermove', move);
69
77
  window.removeEventListener('pointerup', up);
78
+ window.removeEventListener('pointercancel', up);
70
79
  };
71
80
  window.addEventListener('pointermove', move);
72
81
  window.addEventListener('pointerup', up);
82
+ window.addEventListener('pointercancel', up);
73
83
  };
74
84
  const onKeyDown = (event) => {
75
85
  if (event.key === 'Home' || event.key === 'End') {
@@ -85,9 +95,14 @@ export function KptSplitter({ orientation = 'horizontal', startSize, defaultStar
85
95
  if (!dir)
86
96
  return;
87
97
  event.preventDefault();
88
- setSize(clamp(size + dir));
98
+ // W RTL <- przesuwa uchwyt w lewo, czyli powiększa prawy panel "start" - odwrotnie niż w LTR.
99
+ const horizontal = event.key === 'ArrowLeft' || event.key === 'ArrowRight';
100
+ const rtl = horizontal && getComputedStyle(event.currentTarget).direction === 'rtl';
101
+ setSize(clamp(size + (rtl ? -dir : dir)));
89
102
  };
90
- return (_jsx("div", { className: cn('kpt-splitter-host', className), ...rest, children: _jsxs("div", { ref: containerRef, className: "kpt-splitter", "data-orientation": orientation, children: [_jsx("div", { className: "kpt-splitter__pane", id: startId, style: { flexBasis: `${size}%` }, children: start }), _jsx("div", { className: "kpt-splitter__gutter", role: "separator", tabIndex: 0, "aria-orientation": orientation === 'horizontal' ? 'vertical' : 'horizontal', "aria-valuenow": size, "aria-valuemin": minSize, "aria-valuemax": 100 - minSize, "aria-controls": startId, "aria-label": ariaLabel || t('splitter.resize'), onPointerDown: onPointerDown, onKeyDown: onKeyDown }), _jsx("div", { className: "kpt-splitter__pane", style: { flexBasis: `${100 - size}%` }, children: end })] }) }));
103
+ return (_jsx("div", { className: cn('kpt-splitter-host', className), ...rest, children: _jsxs("div", { ref: containerRef, className: "kpt-splitter", "data-orientation": orientation, children: [_jsx("div", { className: "kpt-splitter__pane", id: startId, style: { flexBasis: `${size}%` }, children: start }), _jsx("div", { className: "kpt-splitter__gutter", role: "separator",
104
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- separator okna (APG Window Splitter) to fokusowalny widżet ze strzałkami
105
+ tabIndex: 0, "aria-orientation": orientation === 'horizontal' ? 'vertical' : 'horizontal', "aria-valuenow": size, "aria-valuemin": minSize, "aria-valuemax": 100 - minSize, "aria-controls": startId, "aria-label": ariaLabel || t('splitter.resize'), onPointerDown: onPointerDown, onKeyDown: onKeyDown }), _jsx("div", { className: "kpt-splitter__pane", style: { flexBasis: `${100 - size}%` }, children: end })] }) }));
91
106
  }
92
107
  KptSplitter.Start = KptSplitterStart;
93
108
  KptSplitter.End = KptSplitterEnd;
@@ -1,38 +1,42 @@
1
1
  # KptStepper + KptStep (@konce-pt/react)
2
2
 
3
- A step wizard — a header of numbered steps plus the active step's content.
3
+ A step wizard - a header of numbered steps plus the active step's content.
4
4
  Import: `import { KptStepper, useKptStepper } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-stepper-host" style="--kpt-anim-duration:500ms; --kpt-anim-dir:1">
8
8
  <ol class="kpt-stepper__header">
9
9
  <li class="kpt-stepper__step is-done">
10
- <button class="kpt-stepper__marker" aria-label="Step 1: Account, completed">✓</button>
10
+ <button class="kpt-stepper__marker" aria-label="Step 1: Account, completed">
11
+ <span class="kpt-stepper__num">1</span><span class="kpt-icon-host kpt-stepper__check"><!-- check --></span>
12
+ </button>
11
13
  <span class="kpt-stepper__label" aria-hidden="true">Account</span>
12
- <span class="kpt-stepper__connector"></span>
14
+ <span class="kpt-stepper__connector" style="--kpt-stepper-line-delay:60ms; --kpt-stepper-line-dur:420ms"></span>
13
15
  </li>
14
- …
16
+ ...
15
17
  </ol>
16
- <div class="kpt-stepper__body"><div class="kpt-stepper__panel">…</div></div>
18
+ <span class="kpt-stepper__comet" aria-hidden="true"></span>
19
+ <div class="kpt-stepper__body"><div class="kpt-stepper__panel">...</div></div>
17
20
  </div>
18
21
 
19
22
  ## KptStepper props
20
23
  - `activeIndex` / `defaultActiveIndex` / `onActiveIndexChange`
21
- - `animated`: boolean (default true), `animationDuration`: ms (default 500)
24
+ - `animated`: boolean (default true), `animationDuration`: ms (default 500) - the pace of the whole motion:
25
+ the content enter, and the line (a segment takes 0.84x, a multi-step jump fits in 1.8x)
22
26
  - `className`, `ref` and every other `<div>` prop go to the host
23
27
 
24
28
  ## KptStepper.Step props
25
- - `label`: string (required); `children` — the step's content
29
+ - `label`: string (required); `children` - the step's content
26
30
 
27
31
  ## useKptStepper()
28
- `{ activeIndex, count, next, prev, goTo }` — the replacement for Angular's `#s` + `s.next()`.
32
+ `{ activeIndex, count, next, prev, goTo }` - the replacement for Angular's `#s` + `s.next()`.
29
33
  It reads a context the stepper provides around the panel, so it works only in a component
30
34
  rendered inside a step (a hook cannot be called in the parent's body) and throws elsewhere.
31
35
  `count` lets a step hide "Next" on the last one.
32
36
 
33
37
  ## The step is a config carrier
34
38
  `KptStep` renders `null`; `KptStepper` reads its props and decides what to show, so only the
35
- active step's content is ever mounted — the same laziness as the `kpt-step` template in Angular.
39
+ active step's content is ever mounted - the same laziness as the `kpt-step` template in Angular.
36
40
 
37
41
  ## The panel is keyed by index
38
42
  `key={active}` forces a remount on every change, otherwise the enter animation would have nothing
@@ -42,7 +46,7 @@ an earlier step animates from the other side.
42
46
  ## Examples
43
47
  <KptStepper>
44
48
  <KptStepper.Step label="Account"><StepNav /></KptStepper.Step>
45
- <KptStepper.Step label="Profile">…</KptStepper.Step>
49
+ <KptStepper.Step label="Profile">...</KptStepper.Step>
46
50
  </KptStepper>
47
51
 
48
52
  function StepNav() {
@@ -55,14 +59,32 @@ an earlier step animates from the other side.
55
59
  );
56
60
  }
57
61
 
62
+ ## Motion
63
+ Switching steps reads as colour flowing: the state changes at once (classes, `aria-current`,
64
+ the marker names), but the connector fills from grey to `--kpt-color-primary` with a glowing comet
65
+ running along it, and a marker turns "done" (fills from the centre, the check pops in) only when the
66
+ colour reaches it; the new active step sends out a ring and keeps a soft glow. A jump over several
67
+ steps runs the segments one after another within ~0.9 s; going back retracts them from the end.
68
+ The content of the new step slides in from the side of the move and sharpens out of a blur, the old
69
+ one leaves as a ghost the other way, and the body height changes smoothly.
70
+
71
+ The timings come from `stepperSchedule` in `@konce-pt/motion` (CSS variables
72
+ `--kpt-stepper-mark-delay`, `--kpt-stepper-line-delay`, `--kpt-stepper-line-dur` on the steps), the comet
73
+ and the ring from `playStepperLight`, the ghost from `preparePanelSwap`. Follows `animated` and `enter`
74
+ from `KptMotionProvider` (`none` - everything switches at once, `fade` - no comet and ring); `enabled: false` and the
75
+ system "reduce motion" setting always win.
76
+
58
77
  ## Tokens
59
78
  The active and completed step: `--kpt-color-primary` (marker, connector); the rest
60
79
  `--kpt-color-border-strong` and `--kpt-color-on-surface-muted`.
61
80
 
62
81
  ## Accessibility
63
82
  The header is an `<ol>` of real buttons, so every step is reachable with the keyboard and the list
64
- announces how many there are. Each marker is named from the dictionary — `stepper.step`
65
- (“Step 2: Delivery”) or `stepper.stepDone` (“…, completed”) — because the visible marker is only a
83
+ announces how many there are. Each marker is named from the dictionary - `stepper.step`
84
+ ("Step 2: Delivery") or `stepper.stepDone` ("..., completed") - because the visible marker is only a
66
85
  number or a check; the visible label is `aria-hidden` so it is not read twice. The active marker
67
- carries `aria-current="step"`. After `next()` focus stays where it was — move it into the new step
86
+ carries `aria-current="step"`. After `next()` focus stays where it was - move it into the new step
68
87
  yourself when the step is long.
88
+
89
+ ## Inactive content is destroyed
90
+ Switching renders the new panel from scratch (that is what the enter animation starts from), so local state inside the previous one - an unsent file upload, expanded sections, scroll position - is lost. Keep such state in your own model, outside the panel.
@@ -2,14 +2,14 @@ import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
2
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
3
  export interface KptStepperContextValue {
4
4
  activeIndex: number;
5
- /** Liczba kroków — pozwala treści kroku ukryć „Dalej" na ostatnim. */
5
+ /** Liczba kroków - pozwala treści kroku ukryć "Dalej" na ostatnim. */
6
6
  count: number;
7
7
  next: () => void;
8
8
  prev: () => void;
9
9
  goTo: (index: number) => void;
10
10
  }
11
11
  /**
12
- * Sterowanie kreatorem z wnętrza kroku — odpowiednik `#s` + `s.next()` z portu Angulara.
12
+ * Sterowanie kreatorem z wnętrza kroku - odpowiednik `#s` + `s.next()` z portu Angulara.
13
13
  * Poza `<KptStepper>` rzuca błąd, bo bez kreatora nie ma czym sterować.
14
14
  *
15
15
  * @example
@@ -21,7 +21,7 @@ export interface KptStepProps {
21
21
  children?: ReactNode;
22
22
  }
23
23
  /**
24
- * Pojedynczy krok. Umieszczaj w `<KptStepper>`. Treść renderuje się leniwie — dopiero gdy krok
24
+ * Pojedynczy krok. Umieszczaj w `<KptStepper>`. Treść renderuje się leniwie - dopiero gdy krok
25
25
  * jest aktywny, tak samo jak szablon `kpt-step` w porcie Angulara.
26
26
  */
27
27
  export declare function KptStep(_props: Readonly<KptStepProps>): ReactNode;
@@ -37,13 +37,13 @@ export interface KptStepperProps extends Omit<ComponentPropsWithRef<'div'>, 'onC
37
37
  children?: ReactNode;
38
38
  }
39
39
  /**
40
- * Kreator kroków — nagłówek z numerowanymi krokami i treść aktywnego kroku.
40
+ * Kreator kroków - nagłówek z numerowanymi krokami i treść aktywnego kroku.
41
41
  * Treścią sterują `next()`/`prev()`/`goTo()` z hooka `useKptStepper()`.
42
42
  *
43
43
  * @example
44
44
  * <KptStepper>
45
- * <KptStepper.Step label="Konto">…</KptStepper.Step>
46
- * <KptStepper.Step label="Profil">…</KptStepper.Step>
45
+ * <KptStepper.Step label="Konto">...</KptStepper.Step>
46
+ * <KptStepper.Step label="Profil">...</KptStepper.Step>
47
47
  * </KptStepper>
48
48
  */
49
49
  export declare function KptStepper({ activeIndex, defaultActiveIndex, onActiveIndexChange, animated, animationDuration, locale, dictionary, className, style, children, ...rest }: Readonly<KptStepperProps>): import("react").JSX.Element;
@@ -1,12 +1,16 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Children, createContext, isValidElement, useContext, useState, } from 'react';
3
+ import { createContext, isValidElement, useContext, useLayoutEffect, useRef, useState, } from 'react';
3
4
  import { cn } from "../internal/cn.js";
5
+ import { slotChildren, warnUnslottedChild } from "../internal/slot-children.js";
4
6
  import { useControllableState } from "../internal/use-controllable-state.js";
5
7
  import { useKptMessages } from "../i18n/i18n-context.js";
6
8
  import { KptIcon } from "../icon/icon.js";
9
+ import { playStepperLight, preparePanelSwap, resolveEnterMotion, stepperSchedule, stepperScheduleOptions } from '@konce-pt/motion';
10
+ import { useKptMotion } from "../motion/motion-context.js";
7
11
  const StepperContext = createContext(null);
8
12
  /**
9
- * Sterowanie kreatorem z wnętrza kroku — odpowiednik `#s` + `s.next()` z portu Angulara.
13
+ * Sterowanie kreatorem z wnętrza kroku - odpowiednik `#s` + `s.next()` z portu Angulara.
10
14
  * Poza `<KptStepper>` rzuca błąd, bo bez kreatora nie ma czym sterować.
11
15
  *
12
16
  * @example
@@ -19,7 +23,7 @@ export function useKptStepper() {
19
23
  return context;
20
24
  }
21
25
  /**
22
- * Pojedynczy krok. Umieszczaj w `<KptStepper>`. Treść renderuje się leniwie — dopiero gdy krok
26
+ * Pojedynczy krok. Umieszczaj w `<KptStepper>`. Treść renderuje się leniwie - dopiero gdy krok
23
27
  * jest aktywny, tak samo jak szablon `kpt-step` w porcie Angulara.
24
28
  */
25
29
  export function KptStep(_props) {
@@ -28,13 +32,13 @@ export function KptStep(_props) {
28
32
  }
29
33
  KptStep.kptStepperSlot = 'step';
30
34
  /**
31
- * Kreator kroków — nagłówek z numerowanymi krokami i treść aktywnego kroku.
35
+ * Kreator kroków - nagłówek z numerowanymi krokami i treść aktywnego kroku.
32
36
  * Treścią sterują `next()`/`prev()`/`goTo()` z hooka `useKptStepper()`.
33
37
  *
34
38
  * @example
35
39
  * <KptStepper>
36
- * <KptStepper.Step label="Konto">…</KptStepper.Step>
37
- * <KptStepper.Step label="Profil">…</KptStepper.Step>
40
+ * <KptStepper.Step label="Konto">...</KptStepper.Step>
41
+ * <KptStepper.Step label="Profil">...</KptStepper.Step>
38
42
  * </KptStepper>
39
43
  */
40
44
  export function KptStepper({ activeIndex, defaultActiveIndex = 0, onActiveIndexChange, animated = true, animationDuration = 500, locale, dictionary, className, style, children, ...rest }) {
@@ -45,16 +49,56 @@ export function KptStepper({ activeIndex, defaultActiveIndex = 0, onActiveIndexC
45
49
  onChange: onActiveIndexChange,
46
50
  });
47
51
  const [direction, setDirection] = useState(1);
52
+ /** Ruch przełączania idzie za `animated` i za `enter` z `KptMotionProvider` (`none` go wyłącza). */
53
+ const motionConfig = useKptMotion();
54
+ const motion = animated ? resolveEnterMotion(undefined, motionConfig) : 'none';
55
+ // Krok sprzed ostatniej zmiany - także przy zmianie z zewnątrz (`activeIndex`). Zapamiętany
56
+ // w stanie w trakcie renderu (wzorzec "informacja z poprzedniego renderu"), nie w efekcie.
57
+ const [transition, setTransition] = useState({ from: active, to: active });
58
+ if (transition.to !== active)
59
+ setTransition({ from: transition.to, to: active });
60
+ const rootRef = useRef(null);
61
+ const bodyRef = useRef(null);
62
+ /** Duch starej treści przygotowany przed zmianą kroku, odtwarzany po jej wyrenderowaniu. */
63
+ const pendingSwap = useRef(null);
48
64
  const steps = [];
49
- Children.forEach(children, (child) => {
50
- if (!isValidElement(child) || child.type?.kptStepperSlot !== 'step')
51
- return;
65
+ for (const child of slotChildren(children)) {
66
+ if (!isValidElement(child) || child.type?.kptStepperSlot !== 'step') {
67
+ warnUnslottedChild('KptStepper', child, '<KptStep>');
68
+ continue;
69
+ }
52
70
  steps.push(child.props);
71
+ }
72
+ /**
73
+ * Kiedy widać zmianę każdego znacznika i odcinka linii (`stepperSchedule` z @konce-pt/motion):
74
+ * kolor płynie po linii i zapala znacznik dopiero, gdy do niego dotrze. Bez ruchu - same zera.
75
+ */
76
+ // Tempo linii idzie za `animationDuration` - ten sam czas steruje całym ruchem, nie tylko treścią.
77
+ const schedule = stepperSchedule(steps.length, motion === 'none' ? active : transition.from, active, stepperScheduleOptions(animationDuration));
78
+ // Kometa po linii i fala w znaczniku, do którego dociera kolor; duch starej treści - przed malowaniem.
79
+ useLayoutEffect(() => {
80
+ const play = pendingSwap.current;
81
+ pendingSwap.current = null;
82
+ play?.();
53
83
  });
84
+ useLayoutEffect(() => {
85
+ const root = rootRef.current;
86
+ if (!root || motion !== 'spring' || !schedule.direction)
87
+ return;
88
+ playStepperLight(schedule, root.querySelector('.kpt-stepper__comet'), Array.from(root.querySelectorAll('.kpt-stepper__connector')), Array.from(root.querySelectorAll('.kpt-stepper__marker')));
89
+ // Harmonogram liczy się z `transition` - gra raz na zmianę kroku, nie na każdy render.
90
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- schedule to pochodna transition i liczby kroków
91
+ }, [transition, motion]);
54
92
  const goTo = (index) => {
55
93
  const next = Math.max(0, Math.min(index, steps.length - 1));
94
+ if (next === active)
95
+ return;
56
96
  // Kierunek karmi `--kpt-anim-dir`, więc panel wjeżdża z tej strony, z której się cofnąłeś.
57
- setDirection(next >= active ? 1 : -1);
97
+ const dir = next > active ? 1 : -1;
98
+ setDirection(dir);
99
+ // Stara treść wychodzi jako duch, a pojemnik płynnie zmienia wysokość - mierzone przed zmianą.
100
+ if (motion !== 'none' && bodyRef.current)
101
+ pendingSwap.current = preparePanelSwap(bodyRef.current, dir);
58
102
  setActive(next);
59
103
  };
60
104
  const context = {
@@ -64,13 +108,16 @@ export function KptStepper({ activeIndex, defaultActiveIndex = 0, onActiveIndexC
64
108
  prev: () => goTo(active - 1),
65
109
  goTo,
66
110
  };
67
- return (_jsxs("div", { className: cn('kpt-stepper-host', className), style: {
111
+ return (_jsxs("div", { ref: rootRef, className: cn('kpt-stepper-host', className), style: {
68
112
  ['--kpt-anim-duration']: `${animated ? animationDuration : 0}ms`,
69
113
  ['--kpt-anim-dir']: direction,
70
114
  ...style,
71
- }, ...rest, children: [_jsx("ol", { className: "kpt-stepper__header", children: steps.map((step, index) => (_jsxs("li", { className: cn('kpt-stepper__step', index === active && 'is-active', index < active && 'is-done'), children: [_jsx("button", { type: "button", className: "kpt-stepper__marker", "aria-current": index === active ? 'step' : undefined, "aria-label": t(index < active ? 'stepper.stepDone' : 'stepper.step', {
115
+ }, ...rest, children: [_jsx("ol", { className: "kpt-stepper__header", children: steps.map((step, index) => (_jsxs("li", { className: cn('kpt-stepper__step', index === active && 'is-active', index < active && 'is-done'), style: { ['--kpt-stepper-mark-delay']: `${schedule.markers[index] ?? 0}ms` }, children: [_jsxs("button", { type: "button", className: "kpt-stepper__marker", "aria-current": index === active ? 'step' : undefined, "aria-label": t(index < active ? 'stepper.stepDone' : 'stepper.step', {
72
116
  index: index + 1,
73
117
  label: step.label,
74
- }), onClick: () => goTo(index), children: index < active ? _jsx(KptIcon, { name: "check" }) : index + 1 }), _jsx("span", { className: "kpt-stepper__label", "aria-hidden": "true", children: step.label }), index < steps.length - 1 ? _jsx("span", { className: "kpt-stepper__connector" }) : null] }, index))) }), _jsx(StepperContext.Provider, { value: context, children: _jsx("div", { className: "kpt-stepper__body", children: steps[active] ? (_jsx("div", { className: "kpt-stepper__panel", children: steps[active].children }, active)) : null }) })] }));
118
+ }), onClick: () => goTo(index), children: [_jsx("span", { className: "kpt-stepper__num", children: index + 1 }), _jsx(KptIcon, { className: "kpt-stepper__check", name: "check" })] }), _jsx("span", { className: "kpt-stepper__label", "aria-hidden": "true", children: step.label }), index < steps.length - 1 ? (_jsx("span", { className: "kpt-stepper__connector", style: {
119
+ ['--kpt-stepper-line-delay']: `${schedule.lines[index]?.delay ?? 0}ms`,
120
+ ['--kpt-stepper-line-dur']: `${schedule.lines[index]?.duration ?? 0}ms`,
121
+ } })) : null] }, index))) }), _jsx("span", { className: "kpt-stepper__comet", "aria-hidden": "true" }), _jsx(StepperContext.Provider, { value: context, children: _jsx("div", { className: "kpt-stepper__body", ref: bodyRef, children: steps[active] ? (_jsx("div", { className: "kpt-stepper__panel", children: steps[active].children }, active)) : null }) })] }));
75
122
  }
76
123
  KptStepper.Step = KptStep;
@@ -16,16 +16,17 @@ Import: `import { KptSwitch } from '@konce-pt/react';`
16
16
 
17
17
  ## Props
18
18
  - `label`: string, `labelPosition`: 'start' | 'end' (default 'end')
19
- - `onLabel`, `offLabel`: string — the state text, swapped on toggle
19
+ - `onLabel`, `offLabel`: string - the state text, swapped on toggle
20
20
  - `checked` / `defaultChecked`, `onCheckedChange(checked)`, `onTouch()`
21
- - `required`, `invalid`, `touched` — as in `KptCheckbox`
22
- - `hostProps` — props for the `.kpt-switch-host` wrapper
21
+ - `required`, `invalid`, `touched` - as in `KptCheckbox`
22
+ - `toggleMotion`: 'spring' | 'fade' | 'none' (default from `KptMotionProvider`, else `spring`) - see "Toggle motion"
23
+ - `hostProps` - props for the `.kpt-switch-host` wrapper
23
24
  - `className` goes to the `.kpt-switch` block; the rest to the native `<input>`
24
25
 
25
26
  ## The state text needs a controlled value
26
27
  `onLabel` and `offLabel` read `checked`, so they only follow the switch in controlled mode.
27
28
  Uncontrolled, the value belongs to the DOM and React never learns about a toggle, which would
28
- freeze the state text on its initial value — use `checked` with `onCheckedChange` whenever you
29
+ freeze the state text on its initial value - use `checked` with `onCheckedChange` whenever you
29
30
  show one.
30
31
 
31
32
  ## Examples
@@ -43,10 +44,19 @@ generated. Inside `KptFormField` the wrapper's `label[for]` points at it and the
43
44
  added to `aria-describedby` (merged with your own). Without a wrapper, name it with `aria-label`.
44
45
  Inside `kpt-form-field` the switch gets both names: the wrapper label and its own `label`.
45
46
 
47
+ ## Toggle motion
48
+ `toggleMotion`: `spring` - the thumb travels on a spring and stretches while moving; `fade` - a calm colour and mark transition; `none` - no
49
+ motion. The bounce is started by the change handler, so a control that is checked on load does not
50
+ move. With no value it takes `toggle` from `KptMotionProvider` (default `spring`); `enabled: false` and the
51
+ system "reduce motion" setting always win.
52
+
46
53
  ## Tokens
47
54
  `--kpt-color-primary` (the on track), `--kpt-color-muted` (the off track), `--kpt-color-surface`
48
55
  (the thumb), `--kpt-motion-duration-fast`.
49
56
 
50
57
  ## Accessibility
51
- `role="switch"` on a native checkbox — a screen reader announces on/off instead of
58
+ `role="switch"` on a native checkbox - a screen reader announces on/off instead of
52
59
  checked/unchecked. The track and the thumb are `aria-hidden`.
60
+
61
+ ## Read-only and required
62
+ `readOnly` keeps the switch focusable but blocks toggling (`aria-readonly`); `required` sets `aria-required`.
@@ -1,6 +1,13 @@
1
1
  import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
2
  import type { KptHostProps } from '../internal/types.ts';
3
+ import { type KptToggleMotion } from '@konce-pt/motion';
3
4
  export interface KptSwitchProps extends Omit<ComponentPropsWithRef<'input'>, 'type' | 'required'> {
5
+ /**
6
+ * Ruch przełączania: `spring` - kciuk jedzie na sprężynie i rozciąga się w ruchu; `fade` - spokojne przejście koloru i znaku; `none` - bez ruchu.
7
+ * Bez wartości bierze `toggle` z `KptMotionProvider` (domyślnie `spring`); `enabled={false}` i systemowe
8
+ * "ogranicz ruch" wyłączają go zawsze.
9
+ */
10
+ toggleMotion?: KptToggleMotion;
4
11
  /** Etykieta obok przełącznika. */
5
12
  label?: string;
6
13
  /** Pozycja etykiety względem przełącznika. */
@@ -15,7 +22,7 @@ export interface KptSwitchProps extends Omit<ComponentPropsWithRef<'input'>, 'ty
15
22
  invalid?: boolean;
16
23
  /** Czy pole było dotknięte; pominięty = stan błędu pokazuje się od razu po `invalid`. */
17
24
  touched?: boolean;
18
- /** Wygodniejszy odpowiednik `onChange` — dostaje samo zaznaczenie. */
25
+ /** Wygodniejszy odpowiednik `onChange` - dostaje samo zaznaczenie. */
19
26
  onCheckedChange?: (checked: boolean) => void;
20
27
  /** Wywoływane na `blur`. */
21
28
  onTouch?: () => void;
@@ -27,7 +34,7 @@ export interface KptSwitchProps extends Omit<ComponentPropsWithRef<'input'>, 'ty
27
34
  * Przełącznik (switch/toggle). Pod spodem natywny `<input type="checkbox" role="switch">`,
28
35
  * więc klawiatura i czytniki ekranu działają bez dodatkowej obsługi.
29
36
  *
30
- * Wariant z tekstem stanu: `onLabel`/`offLabel` — wyświetlany tekst zmienia się przy przełączaniu.
37
+ * Wariant z tekstem stanu: `onLabel`/`offLabel` - wyświetlany tekst zmienia się przy przełączaniu.
31
38
  *
32
39
  * Tekst stanu wymaga `checked` (tryb kontrolowany), bo w trybie niekontrolowanym wartość należy
33
40
  * do DOM i React o niej nie wie; bez tego etykieta stanu zamarłaby na wartości początkowej.
@@ -36,4 +43,4 @@ export interface KptSwitchProps extends Omit<ComponentPropsWithRef<'input'>, 'ty
36
43
  * <KptSwitch name="notifications" label="Powiadomienia" />
37
44
  * <KptSwitch checked={on} onCheckedChange={setOn} onLabel="Włączony" offLabel="Wyłączony" />
38
45
  */
39
- export declare function KptSwitch({ label, labelPosition, onLabel, offLabel, required, invalid, touched, onCheckedChange, onTouch, hostProps, className, disabled, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, ...rest }: Readonly<KptSwitchProps>): import("react").JSX.Element;
46
+ export declare function KptSwitch({ label, labelPosition, onLabel, offLabel, required, invalid, touched, onCheckedChange, onTouch, hostProps, className, disabled, readOnly, onClick, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, toggleMotion, ...rest }: Readonly<KptSwitchProps>): import("react").JSX.Element;
@@ -1,12 +1,15 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useCallback } from 'react';
3
4
  import { cn } from "../internal/cn.js";
4
5
  import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
6
+ import { playPopMotion, resolveToggleMotion } from '@konce-pt/motion';
7
+ import { useKptMotion } from "../motion/motion-context.js";
5
8
  /**
6
9
  * Przełącznik (switch/toggle). Pod spodem natywny `<input type="checkbox" role="switch">`,
7
10
  * więc klawiatura i czytniki ekranu działają bez dodatkowej obsługi.
8
11
  *
9
- * Wariant z tekstem stanu: `onLabel`/`offLabel` — wyświetlany tekst zmienia się przy przełączaniu.
12
+ * Wariant z tekstem stanu: `onLabel`/`offLabel` - wyświetlany tekst zmienia się przy przełączaniu.
10
13
  *
11
14
  * Tekst stanu wymaga `checked` (tryb kontrolowany), bo w trybie niekontrolowanym wartość należy
12
15
  * do DOM i React o niej nie wie; bez tego etykieta stanu zamarłaby na wartości początkowej.
@@ -15,18 +18,29 @@ import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
15
18
  * <KptSwitch name="notifications" label="Powiadomienia" />
16
19
  * <KptSwitch checked={on} onCheckedChange={setOn} onLabel="Włączony" offLabel="Wyłączony" />
17
20
  */
18
- export function KptSwitch({ label = '', labelPosition = 'end', onLabel = '', offLabel = '', required = false, invalid = false, touched, onCheckedChange, onTouch, hostProps, className, disabled = false, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, ...rest }) {
21
+ export function KptSwitch({ label = '', labelPosition = 'end', onLabel = '', offLabel = '', required = false, invalid = false, touched, onCheckedChange, onTouch, hostProps, className, disabled = false, readOnly = false, onClick, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, toggleMotion, ...rest }) {
19
22
  const field = useKptFieldA11y(id, 'kpt-switch');
20
23
  const { className: hostClassName, ...hostRest } = hostProps ?? {};
21
24
  const showInvalid = invalid && (touched ?? true);
22
25
  const hasStateLabels = !!(onLabel || offLabel);
26
+ const motion = resolveToggleMotion(toggleMotion, useKptMotion());
23
27
  const handleChange = useCallback((event) => {
24
28
  onChange?.(event);
25
29
  onCheckedChange?.(event.target.checked);
26
- }, [onChange, onCheckedChange]);
30
+ // Kciuk rozciąga się w ruchu - z handlera, nie z CSS, bo reguła na `:checked` grałaby przy starcie.
31
+ const thumb = event.currentTarget.nextElementSibling?.firstElementChild;
32
+ if (motion === 'spring' && thumb instanceof HTMLElement)
33
+ playPopMotion(thumb, 'squash');
34
+ }, [onChange, onCheckedChange, motion]);
27
35
  const handleBlur = useCallback((event) => {
28
36
  onBlur?.(event);
29
37
  onTouch?.();
30
38
  }, [onBlur, onTouch]);
31
- return (_jsx("span", { className: cn('kpt-switch-host', hostClassName), ...hostRest, children: _jsxs("label", { className: cn('kpt-switch', disabled && 'kpt-switch--disabled', className), children: [label && labelPosition === 'start' ? (_jsx("span", { className: "kpt-switch__label kpt-switch__label--start", children: label })) : null, _jsx("input", { type: "checkbox", role: "switch", className: "kpt-switch__input", id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), checked: checked, disabled: disabled, "aria-required": required || undefined, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ...rest }), _jsx("span", { className: "kpt-switch__track", "aria-hidden": "true", children: _jsx("span", { className: "kpt-switch__thumb" }) }), label && labelPosition === 'end' ? _jsx("span", { className: "kpt-switch__label", children: label }) : null, hasStateLabels ? (_jsx("span", { className: cn('kpt-switch__state', checked && 'kpt-switch__state--on'), "aria-hidden": "true", children: checked ? onLabel : offLabel })) : null, children] }) }));
39
+ return (_jsx("span", { className: cn('kpt-switch-host', hostClassName), ...hostRest, children: _jsxs("label", { className: cn('kpt-switch', disabled && 'kpt-switch--disabled', className), "data-motion": motion, children: [label && labelPosition === 'start' ? (_jsx("span", { className: "kpt-switch__label kpt-switch__label--start", children: label })) : null, _jsx("input", { type: "checkbox", role: "switch", className: "kpt-switch__input", id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), checked: checked, disabled: disabled, "aria-required": required || undefined, "aria-readonly": readOnly || undefined,
40
+ // Natywne `readonly` nie działa na polach wyboru - klik (i Spacja) jest blokowany ręcznie.
41
+ onClick: (event) => {
42
+ if (readOnly)
43
+ event.preventDefault();
44
+ onClick?.(event);
45
+ }, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ...rest }), _jsx("span", { className: "kpt-switch__track", "aria-hidden": "true", children: _jsx("span", { className: "kpt-switch__thumb" }) }), label && labelPosition === 'end' ? _jsx("span", { className: "kpt-switch__label", children: label }) : null, hasStateLabels ? (_jsx("span", { className: cn('kpt-switch__state', checked && 'kpt-switch__state--on'), "aria-hidden": "true", children: checked ? onLabel : offLabel })) : null, children] }) }));
32
46
  }
@@ -1,30 +1,30 @@
1
1
  # KptSwitchGroup (@konce-pt/react)
2
2
 
3
- A group of switches — mutually exclusive by default, multi-select with `multiple`.
3
+ A group of switches - mutually exclusive by default, multi-select with `multiple`.
4
4
  Import: `import { KptSwitchGroup } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-switch-group-host">
8
8
  <div class="kpt-switch-group" role="group">
9
- <span class="kpt-switch-host kpt-switch-group__item">…KptSwitch…</span>
10
- …one per option…
9
+ <span class="kpt-switch-host kpt-switch-group__item">...KptSwitch...</span>
10
+ ...one per option...
11
11
  </div>
12
12
  </div>
13
13
 
14
14
  ## Props
15
- - `options`: `KptOption<T>[]` — `{ label, value, disabled? }`
16
- - `value` / `defaultValue` / `onValueChange` — single select: the option's value or `null`;
15
+ - `options`: `KptOption<T>[]` - `{ label, value, disabled? }`
16
+ - `value` / `defaultValue` / `onValueChange` - single select: the option's value or `null`;
17
17
  with `multiple`: an array of the selected values
18
18
  - `multiple`: boolean (default false)
19
19
  - `orientation`: `'vertical'` (default) | `'horizontal'`
20
- - `allowDeselect`: boolean (default true) — single select only; in `multiple` mode turning an
20
+ - `allowDeselect`: boolean (default true) - single select only; in `multiple` mode turning an
21
21
  option off is always allowed
22
22
  - `disabled`, `invalid`, `touched`, `onTouch()`
23
23
  - `className`, `ref` and every other `<div>` prop go to the host
24
24
 
25
25
  ## Single select comes out of the value, not out of the switches
26
26
  Every entry is a `KptSwitch` whose `checked` is derived from the group value, so turning one on
27
- turns the rest off by itself — there is no per-switch state to keep in sync.
27
+ turns the rest off by itself - there is no per-switch state to keep in sync.
28
28
 
29
29
  That is also why `allowDeselect={false}` needs no code: the handler writes nothing, so React
30
30
  re-applies the controlled `checked` and the switch snaps back on.
@@ -37,7 +37,7 @@ re-applies the controlled `checked` and the switch snaps back on.
37
37
  ## Screen reader and keyboard
38
38
  `aria-invalid` is not supported on `role="group"`, so the error state is carried by each switch. In
39
39
  single mode the switches are mutually exclusive and nothing announces that turning one on turned
40
- another off — for a single choice prefer `KptRadioGroup`.
40
+ another off - for a single choice prefer `KptRadioGroup`.
41
41
 
42
42
  ## Label and description
43
43
  `id` goes to the focusable element, not the host; without one it comes from `KptFormField` or is
@@ -52,3 +52,6 @@ Layout only: `--kpt-space-2` (vertical gap) and `--kpt-space-4` (horizontal). Th
52
52
  ## Accessibility
53
53
  `role="group"` with `aria-invalid` once the field is touched; every entry keeps the native
54
54
  checkbox of `KptSwitch`, so keyboard and screen readers work with no extra handling.
55
+
56
+ ## Read-only and required
57
+ `readOnly` is passed to every switch. With `allowDeselect=false` turning the active switch off puts it back on - before, the switch looked off while the group value said it was on.
@@ -6,22 +6,24 @@ export interface KptSwitchGroupProps<T> extends Omit<ComponentPropsWithRef<'div'
6
6
  value?: T | T[] | null;
7
7
  defaultValue?: T | T[] | null;
8
8
  onValueChange?: (value: T | T[] | null) => void;
9
- /** Wielokrotny wybór — wartością staje się tablica `T[]`. */
9
+ /** Wielokrotny wybór - wartością staje się tablica `T[]`. */
10
10
  multiple?: boolean;
11
11
  orientation?: 'vertical' | 'horizontal';
12
12
  /** Czy wyłączenie aktywnej opcji zeruje wartość. Dotyczy tylko trybu pojedynczego. */
13
13
  allowDeselect?: boolean;
14
- /** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
14
+ /** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` - z wrappera. */
15
15
  id?: string;
16
16
  /** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
17
17
  ariaLabel?: string | null;
18
18
  disabled?: boolean;
19
+ /** Tylko do odczytu - przełączniki widać, nie da się ich zmienić. */
20
+ readOnly?: boolean;
19
21
  invalid?: boolean;
20
22
  touched?: boolean;
21
23
  onTouch?: () => void;
22
24
  }
23
25
  /**
24
- * Grupa przełączników. Domyślnie wzajemnie wykluczających się — włączenie jednego wyłącza
26
+ * Grupa przełączników. Domyślnie wzajemnie wykluczających się - włączenie jednego wyłącza
25
27
  * pozostałe; z `multiple` wartością jest tablica zaznaczonych opcji.
26
28
  *
27
29
  * Renderuje `KptSwitch`, więc dziedziczy jego wygląd, tokeny i obsługę klawiatury.
@@ -30,4 +32,4 @@ export interface KptSwitchGroupProps<T> extends Omit<ComponentPropsWithRef<'div'
30
32
  * <KptSwitchGroup options={plans} value={plan} onValueChange={setPlan} />
31
33
  * <KptSwitchGroup multiple options={tags} value={selected} onValueChange={setSelected} />
32
34
  */
33
- export declare function KptSwitchGroup<T>({ options, value, defaultValue, onValueChange, multiple, orientation, allowDeselect, id, ariaLabel, disabled, invalid, touched, onTouch, className, ...rest }: Readonly<KptSwitchGroupProps<T>>): import("react").JSX.Element;
35
+ export declare function KptSwitchGroup<T>({ options, value, defaultValue, onValueChange, multiple, orientation, allowDeselect, id, ariaLabel, disabled, readOnly, invalid, touched, onTouch, className, ...rest }: Readonly<KptSwitchGroupProps<T>>): import("react").JSX.Element;