@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,10 +1,12 @@
1
+ 'use client';
1
2
  import { jsx as _jsx } from "react/jsx-runtime";
2
3
  import { cn } from "../internal/cn.js";
4
+ import { optionKey } from "../internal/option-key.js";
3
5
  import { useControllableState } from "../internal/use-controllable-state.js";
4
6
  import { KptSwitch } from "../switch/switch.js";
5
7
  import { useKptFieldA11y } from "../form-field/form-field-context.js";
6
8
  /**
7
- * Grupa przełączników. Domyślnie wzajemnie wykluczających się — włączenie jednego wyłącza
9
+ * Grupa przełączników. Domyślnie wzajemnie wykluczających się - włączenie jednego wyłącza
8
10
  * pozostałe; z `multiple` wartością jest tablica zaznaczonych opcji.
9
11
  *
10
12
  * Renderuje `KptSwitch`, więc dziedziczy jego wygląd, tokeny i obsługę klawiatury.
@@ -13,8 +15,8 @@ import { useKptFieldA11y } from "../form-field/form-field-context.js";
13
15
  * <KptSwitchGroup options={plans} value={plan} onValueChange={setPlan} />
14
16
  * <KptSwitchGroup multiple options={tags} value={selected} onValueChange={setSelected} />
15
17
  */
16
- export function KptSwitchGroup({ options = [], value, defaultValue = null, onValueChange, multiple = false, orientation = 'vertical', allowDeselect = true, id, ariaLabel = null, disabled = false, invalid = false, touched, onTouch, className, ...rest }) {
17
- /** Grupa nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
18
+ export function KptSwitchGroup({ options = [], value, defaultValue = null, onValueChange, multiple = false, orientation = 'vertical', allowDeselect = true, id, ariaLabel = null, disabled = false, readOnly = false, invalid = false, touched, onTouch, className, ...rest }) {
19
+ /** Grupa nie dostaje nazwy z `label[for]` - stąd `aria-labelledby` na etykietę wrappera. */
18
20
  const field = useKptFieldA11y(id, 'kpt-switch-group');
19
21
  const [current, setCurrent] = useControllableState({
20
22
  value,
@@ -22,7 +24,7 @@ export function KptSwitchGroup({ options = [], value, defaultValue = null, onVal
22
24
  onChange: onValueChange,
23
25
  });
24
26
  const showInvalid = invalid && (touched ?? true);
25
- // Wartość normalizujemy do tablicy tylko na potrzeby odczytu w trybie multiple —
27
+ // Wartość normalizujemy do tablicy tylko na potrzeby odczytu w trybie multiple -
26
28
  // `null` i wartość pojedyncza są równie poprawnym wejściem.
27
29
  const selected = Array.isArray(current) ? current : current == null ? [] : [current];
28
30
  const isChecked = (optionValue) => multiple ? selected.includes(optionValue) : optionValue === current;
@@ -46,7 +48,7 @@ export function KptSwitchGroup({ options = [], value, defaultValue = null, onVal
46
48
  // Bez `allowDeselect` nie robimy nic: `checked` jest wyliczane z wartości, a ta się nie
47
49
  // zmieniła, więc przełącznik sam wraca do włączonego przy najbliższym renderze.
48
50
  };
49
- return (_jsx("div", { className: cn('kpt-switch-group-host', className), ...rest, children: _jsx("div", { className: cn('kpt-switch-group', orientation === 'horizontal' && 'kpt-switch-group--horizontal'), role: "group", id: field.id, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, children: options.map((option) => (_jsx(KptSwitch, { hostProps: { className: 'kpt-switch-group__item' }, checked: isChecked(option.value), label: option.label, disabled: disabled || option.disabled,
50
- // `aria-invalid` nie działa na `role="group"` — stan błędu niesie każdy przełącznik.
51
- invalid: showInvalid, onCheckedChange: (checked) => toggle(option, checked), onTouch: onTouch }, String(option.value)))) }) }));
51
+ return (_jsx("div", { className: cn('kpt-switch-group-host', className), ...rest, children: _jsx("div", { className: cn('kpt-switch-group', orientation === 'horizontal' && 'kpt-switch-group--horizontal'), role: "group", id: field.id, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, children: options.map((option, index) => (_jsx(KptSwitch, { hostProps: { className: 'kpt-switch-group__item' }, checked: isChecked(option.value), label: option.label, disabled: disabled || option.disabled, readOnly: readOnly,
52
+ // `aria-invalid` nie działa na `role="group"` - stan błędu niesie każdy przełącznik.
53
+ invalid: showInvalid, onCheckedChange: (checked) => toggle(option, checked), onTouch: onTouch }, optionKey(option.value, index)))) }) }));
52
54
  }
@@ -1,6 +1,6 @@
1
1
  # KptTabs (@konce-pt/react)
2
2
 
3
- Tabs — switching views, with the content rendered lazily.
3
+ Tabs - switching views, with the content rendered lazily.
4
4
  Import: `import { KptTabs } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
@@ -14,33 +14,33 @@ Import: `import { KptTabs } from '@konce-pt/react';`
14
14
  </div>
15
15
  <div class="kpt-tabs__body" role="tabpanel" tabindex="0" id="kpt-tabs-r1-panel"
16
16
  aria-labelledby="kpt-tabs-r1-tab-0">
17
- <div class="kpt-tabs__panel">…active tab content…</div>
17
+ <div class="kpt-tabs__panel">...active tab content...</div>
18
18
  </div>
19
19
  </div>
20
20
 
21
21
  ## Props
22
- - `activeIndex` / `defaultActiveIndex` / `onActiveIndexChange` — controlled or uncontrolled
22
+ - `activeIndex` / `defaultActiveIndex` / `onActiveIndexChange` - controlled or uncontrolled
23
23
  - `animated`: boolean (default true), `animationDuration`: number (ms, default 500)
24
- - `children` — `<KptTabs.Tab>` elements
24
+ - `children` - `<KptTabs.Tab>` elements
25
25
 
26
26
  ## KptTabs.Tab
27
- `label` (required), `disabled`, `children`. The tab component never renders itself — `KptTabs`
27
+ `label` (required), `disabled`, `children`. The tab component never renders itself - `KptTabs`
28
28
  reads its props and decides what to show, exactly as the Angular version reads the `kpt-tab`
29
29
  template. Only the active tab's content is in the DOM.
30
30
 
31
31
  ## The underline is measured, not computed
32
32
  `__ink` takes its width and offset from the active button in the DOM, not from the index: tabs have
33
33
  different widths and the labels change with the language. The measurement runs after every render,
34
- and the state is only replaced when the numbers actually change — otherwise each measurement would
34
+ and the state is only replaced when the numbers actually change - otherwise each measurement would
35
35
  schedule another render and the component would loop.
36
36
 
37
37
  ## Examples
38
38
  <KptTabs>
39
- <KptTabs.Tab label="General">…</KptTabs.Tab>
40
- <KptTabs.Tab label="Advanced">…</KptTabs.Tab>
39
+ <KptTabs.Tab label="General">...</KptTabs.Tab>
40
+ <KptTabs.Tab label="Advanced">...</KptTabs.Tab>
41
41
  </KptTabs>
42
42
 
43
- <KptTabs activeIndex={tab} onActiveIndexChange={setTab} animated={false}>…</KptTabs>
43
+ <KptTabs activeIndex={tab} onActiveIndexChange={setTab} animated={false}>...</KptTabs>
44
44
 
45
45
  ## Tokens
46
46
  `--kpt-color-primary` (the active tab and the ink), `--kpt-color-on-surface-muted`,
@@ -52,3 +52,6 @@ The header is `role="tablist"` with `role="tab"` buttons carrying `aria-selected
52
52
  `aria-controls`. The tab row is a single `Tab` stop (roving `tabindex`): `ArrowLeft`/`ArrowRight`
53
53
  move between tabs, wrapping at the ends, `Home`/`End` jump to the first/last one, and disabled tabs
54
54
  are skipped. Moving activates the tab straight away; the next `Tab` goes to the panel.
55
+
56
+ ## Inactive content is destroyed
57
+ 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.
@@ -5,7 +5,7 @@ export interface KptTabProps {
5
5
  children?: ReactNode;
6
6
  }
7
7
  /**
8
- * Pojedyncza zakładka. Umieszczaj w `<KptTabs>`. Treść renderuje się leniwie — dopiero gdy
8
+ * Pojedyncza zakładka. Umieszczaj w `<KptTabs>`. Treść renderuje się leniwie - dopiero gdy
9
9
  * zakładka jest aktywna, tak samo jak szablon `kpt-tab` w porcie Angulara.
10
10
  */
11
11
  export declare function KptTab(_props: Readonly<KptTabProps>): ReactNode;
@@ -21,9 +21,9 @@ export interface KptTabsProps extends Omit<ComponentPropsWithRef<'div'>, 'onChan
21
21
  children?: ReactNode;
22
22
  }
23
23
  /**
24
- * Zakładki — przełączanie widoków, treść renderowana leniwie.
24
+ * Zakładki - przełączanie widoków, treść renderowana leniwie.
25
25
  *
26
- * Klawiatura według wzorca WAI-ARIA „tabs”: rząd zakładek to jeden przystanek Tab, strzałki
26
+ * Klawiatura według wzorca WAI-ARIA "tabs": rząd zakładek to jeden przystanek Tab, strzałki
27
27
  * w lewo/prawo oraz `Home`/`End` przechodzą po zakładkach (z pominięciem wyłączonych) i od razu je
28
28
  * aktywują, a kolejny `Tab` prowadzi do panelu.
29
29
  *
@@ -32,8 +32,8 @@ export interface KptTabsProps extends Omit<ComponentPropsWithRef<'div'>, 'onChan
32
32
  *
33
33
  * @example
34
34
  * <KptTabs>
35
- * <KptTabs.Tab label="Ogólne">…</KptTabs.Tab>
36
- * <KptTabs.Tab label="Zaawansowane">…</KptTabs.Tab>
35
+ * <KptTabs.Tab label="Ogólne">...</KptTabs.Tab>
36
+ * <KptTabs.Tab label="Zaawansowane">...</KptTabs.Tab>
37
37
  * </KptTabs>
38
38
  */
39
39
  export declare function KptTabs({ activeIndex, defaultActiveIndex, onActiveIndexChange, animated, animationDuration, className, style, children, ...rest }: Readonly<KptTabsProps>): import("react").JSX.Element;
package/dist/tabs/tabs.js CHANGED
@@ -1,11 +1,13 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Children, isValidElement, useCallback, useLayoutEffect, useRef, useState, } from 'react';
3
+ import { isValidElement, useCallback, 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 { nextRovingIndex, rovingStop } from "../internal/roving.js";
5
7
  import { useControllableState } from "../internal/use-controllable-state.js";
6
8
  import { useKptId } from "../internal/use-id.js";
7
9
  /**
8
- * Pojedyncza zakładka. Umieszczaj w `<KptTabs>`. Treść renderuje się leniwie — dopiero gdy
10
+ * Pojedyncza zakładka. Umieszczaj w `<KptTabs>`. Treść renderuje się leniwie - dopiero gdy
9
11
  * zakładka jest aktywna, tak samo jak szablon `kpt-tab` w porcie Angulara.
10
12
  */
11
13
  export function KptTab(_props) {
@@ -15,9 +17,9 @@ export function KptTab(_props) {
15
17
  }
16
18
  KptTab.kptTabsSlot = 'tab';
17
19
  /**
18
- * Zakładki — przełączanie widoków, treść renderowana leniwie.
20
+ * Zakładki - przełączanie widoków, treść renderowana leniwie.
19
21
  *
20
- * Klawiatura według wzorca WAI-ARIA „tabs”: rząd zakładek to jeden przystanek Tab, strzałki
22
+ * Klawiatura według wzorca WAI-ARIA "tabs": rząd zakładek to jeden przystanek Tab, strzałki
21
23
  * w lewo/prawo oraz `Home`/`End` przechodzą po zakładkach (z pominięciem wyłączonych) i od razu je
22
24
  * aktywują, a kolejny `Tab` prowadzi do panelu.
23
25
  *
@@ -26,8 +28,8 @@ KptTab.kptTabsSlot = 'tab';
26
28
  *
27
29
  * @example
28
30
  * <KptTabs>
29
- * <KptTabs.Tab label="Ogólne">…</KptTabs.Tab>
30
- * <KptTabs.Tab label="Zaawansowane">…</KptTabs.Tab>
31
+ * <KptTabs.Tab label="Ogólne">...</KptTabs.Tab>
32
+ * <KptTabs.Tab label="Zaawansowane">...</KptTabs.Tab>
31
33
  * </KptTabs>
32
34
  */
33
35
  export function KptTabs({ activeIndex, defaultActiveIndex = 0, onActiveIndexChange, animated = true, animationDuration = 500, className, style, children, ...rest }) {
@@ -42,40 +44,54 @@ export function KptTabs({ activeIndex, defaultActiveIndex = 0, onActiveIndexChan
42
44
  const baseId = useKptId(undefined, 'kpt-tabs');
43
45
  const tabs = [];
44
46
  const contents = [];
45
- Children.forEach(children, (child) => {
46
- if (!isValidElement(child) || child.type?.kptTabsSlot !== 'tab')
47
- return;
47
+ for (const child of slotChildren(children)) {
48
+ if (!isValidElement(child) || child.type?.kptTabsSlot !== 'tab') {
49
+ warnUnslottedChild('KptTabs', child, '<KptTab>');
50
+ continue;
51
+ }
48
52
  const props = child.props;
49
53
  tabs.push(props);
50
54
  contents.push(props.children);
51
- });
55
+ }
56
+ const disabled = tabs.map((tab) => !!tab.disabled);
57
+ /**
58
+ * Zakładka pokazywana i jedyna w kolejności Tab: aktywna, a gdy ta jest wyłączona - pierwsza
59
+ * dostępna. Wyłączona zakładka nie może wyglądać na wybraną (ani mieć swojego panelu).
60
+ */
61
+ const shown = rovingStop(disabled, active);
52
62
  const measureInk = useCallback(() => {
53
- const button = buttonsRef.current[active];
63
+ const button = buttonsRef.current[shown];
54
64
  if (!button)
55
65
  return;
56
66
  const next = { x: button.offsetLeft, w: button.offsetWidth };
57
67
  // Pomiar biegnie po KAŻDYM renderze (etykiety zmieniają się z językiem, a przycisków nie da
58
- // się zmierzyć przed montażem). Bez porównania `setInk` wywoływałby kolejny render w kółko —
68
+ // się zmierzyć przed montażem). Bez porównania `setInk` wywoływałby kolejny render w kółko -
59
69
  // React przerywa aktualizację dopiero wtedy, gdy dostanie ten sam obiekt stanu.
60
70
  setInk((prev) => (prev.x === next.x && prev.w === next.w ? prev : next));
61
- }, [active]);
71
+ }, [shown]);
62
72
  useLayoutEffect(measureInk);
73
+ // Szerokość paska zakładek zmienia się też bez zmiany okna (panel boczny, splitter) - mierzymy
74
+ // kontener, a `resize` okna zostaje tylko tam, gdzie nie ma ResizeObservera.
75
+ const headerRef = useRef(null);
63
76
  useLayoutEffect(() => {
77
+ const header = headerRef.current;
78
+ if (header && typeof ResizeObserver !== 'undefined') {
79
+ const observer = new ResizeObserver(measureInk);
80
+ observer.observe(header);
81
+ return () => observer.disconnect();
82
+ }
64
83
  window.addEventListener('resize', measureInk);
65
84
  return () => window.removeEventListener('resize', measureInk);
66
85
  }, [measureInk]);
67
- const disabled = tabs.map((tab) => !!tab.disabled);
68
- // Jedyna zakładka w kolejności Tab: aktywna, a gdy ta jest wyłączona — pierwsza dostępna.
69
- const tabStop = rovingStop(disabled, active);
70
86
  const select = (index) => {
71
87
  if (tabs[index]?.disabled)
72
88
  return;
73
- setDirection(index >= active ? 1 : -1);
89
+ setDirection(index >= shown ? 1 : -1);
74
90
  setActive(index);
75
91
  };
76
92
  const onKeyDown = (event) => {
77
93
  const current = buttonsRef.current.indexOf(document.activeElement);
78
- const next = nextRovingIndex(disabled, current < 0 ? tabStop : current, event.key);
94
+ const next = nextRovingIndex(disabled, current < 0 ? shown : current, event.key);
79
95
  if (next === null)
80
96
  return;
81
97
  event.preventDefault();
@@ -86,8 +102,8 @@ export function KptTabs({ activeIndex, defaultActiveIndex = 0, onActiveIndexChan
86
102
  ['--kpt-anim-duration']: `${animated ? animationDuration : 0}ms`,
87
103
  ['--kpt-anim-dir']: direction,
88
104
  ...style,
89
- }, ...rest, children: [_jsxs("div", { className: "kpt-tabs__header", role: "tablist", onKeyDown: onKeyDown, children: [tabs.map((tab, index) => (_jsx("button", { ref: (el) => {
105
+ }, ...rest, children: [_jsxs("div", { ref: headerRef, className: "kpt-tabs__header", role: "tablist", onKeyDown: onKeyDown, children: [tabs.map((tab, index) => (_jsx("button", { ref: (el) => {
90
106
  buttonsRef.current[index] = el;
91
- }, type: "button", className: cn('kpt-tabs__tab', index === active && 'is-active'), role: "tab", id: `${baseId}-tab-${index}`, disabled: tab.disabled, "aria-selected": index === active, "aria-controls": index === active ? `${baseId}-panel` : undefined, tabIndex: index === tabStop ? 0 : -1, onClick: () => select(index), children: tab.label }, index))), _jsx("span", { className: "kpt-tabs__ink", style: { width: ink.w, transform: `translateX(${ink.x}px)` } })] }), _jsx("div", { className: "kpt-tabs__body", role: "tabpanel", tabIndex: 0, id: `${baseId}-panel`, "aria-labelledby": `${baseId}-tab-${active}`, children: contents[active] !== undefined ? (_jsx("div", { className: "kpt-tabs__panel", children: contents[active] }, active)) : null })] }));
107
+ }, type: "button", className: cn('kpt-tabs__tab', index === shown && 'is-active'), role: "tab", id: `${baseId}-tab-${index}`, disabled: tab.disabled, "aria-selected": index === shown, "aria-controls": index === shown ? `${baseId}-panel` : undefined, tabIndex: index === shown ? 0 : -1, onClick: () => select(index), children: tab.label }, index))), _jsx("span", { className: "kpt-tabs__ink", style: { width: ink.w, transform: `translateX(${ink.x}px)` } })] }), _jsx("div", { className: "kpt-tabs__body", role: "tabpanel", tabIndex: 0, id: `${baseId}-panel`, "aria-labelledby": `${baseId}-tab-${shown}`, children: contents[shown] !== undefined ? (_jsx("div", { className: "kpt-tabs__panel", children: contents[shown] }, shown)) : null })] }));
92
108
  }
93
109
  KptTabs.Tab = KptTab;
@@ -9,42 +9,53 @@ A multi-line field, with optional auto-resize. It renders a native `<textarea>`
9
9
  </span>
10
10
 
11
11
  ## Props
12
- - `autoResize`: boolean — matches the height to the content on every change
13
- - `rows`: number (default 3) — the starting height
14
- - `value` / `defaultValue` — controlled or uncontrolled, like a native textarea
15
- - `onValueChange(value)`, `onTouch()` — the value alone, and the blur moment
16
- - `required`: boolean — set as `aria-required`, not as the native attribute
17
- - `invalid`, `touched` — the error state, gated the same way as in `KptInput`
18
- - `hostProps` — props for the wrapper
12
+ - `autoResize`: boolean - matches the height to the content on every change
13
+ - `rows`: number (default 3) - the starting height
14
+ - `value` / `defaultValue` - controlled or uncontrolled, like a native textarea
15
+ - `onValueChange(value)`, `onTouch()` - the value alone, and the blur moment
16
+ - `required`: boolean - set as `aria-required`, not as the native attribute
17
+ - `invalid`, `touched` - the error state, gated the same way as in `KptInput`
18
+ - `hostProps` - props for the wrapper
19
19
  - `className`, `ref`, `name`, `placeholder` and every other `<textarea>` prop go to the textarea
20
20
 
21
21
  ## Auto-resize
22
22
  The height is read straight from the DOM (`scrollHeight`), so it is right for a controlled field, an
23
23
  uncontrolled one, and a prefilled initial value alike. The measurement resets the height to `auto`
24
- first — without that a field can only ever grow, since `scrollHeight` never drops below the current
24
+ first - without that a field can only ever grow, since `scrollHeight` never drops below the current
25
25
  height.
26
26
 
27
27
  ## Examples
28
- <KptTextarea name="notes" placeholder="Notes…" autoResize />
28
+ <KptTextarea name="notes" placeholder="Notes..." autoResize />
29
29
  <KptTextarea value={note} onValueChange={setNote} rows={6} />
30
30
  <KptFormField label="Notes" error={err}>
31
31
  <KptTextarea invalid={!!err} onTouch={markTouched} />
32
32
  </KptFormField>
33
33
 
34
34
  ## Screen reader and keyboard
35
- `counter`: boolean — a "12 / 280" counter under the field (requires the native `maxLength`), read
35
+ `counter`: boolean - a "12 / 280" counter under the field (requires the native `maxLength`), read
36
36
  together with it through `aria-describedby`.
37
37
 
38
38
  ## Label and description
39
39
  `id` goes to the native field, not the host; without one it comes from `KptFormField` or is
40
40
  generated. Inside `KptFormField` the wrapper's `label[for]` points at it and the hint or error is
41
41
  added to `aria-describedby` (merged with your own). Without a wrapper, name it with `aria-label`.
42
- New: `id`, `ariaLabel` and `required` (→ `aria-required`); `[formField]` binds `required`.
42
+ New: `id`, `ariaLabel` and `required` (-> `aria-required`); `[formField]` binds `required`.
43
43
 
44
44
  ## Tokens
45
- `--kpt-form-field-{bg,text,placeholder,border,border-hover,border-focus,border-error,radius}` —
45
+ `--kpt-form-field-{bg,text,placeholder,border,border-hover,border-focus,border-error,radius}` -
46
46
  the same set as the text field, so both controls stay in step.
47
47
 
48
48
  ## Accessibility
49
49
  A native `<textarea>`. Inside `KptFormField` it takes its `id` from the wrapper, so `label[for]`
50
50
  is wired with no configuration.
51
+
52
+ ## Dictation
53
+ - `speech`: boolean = false - a microphone in the top corner of the field (the bottom corner belongs
54
+ to the resize handle); the wave appears under it. The field then sits in `.kpt-textarea__box`.
55
+ Without browser support it is not shown.
56
+ - `speechLang`: string; `speechMode`: `'insert' | 'append' | 'replace'` = `'insert'`.
57
+ - `speechColor`: `'primary' | 'danger' | 'success' | 'warning' | 'info'` = `'primary'` - colour of "stop" and the wave while listening.
58
+
59
+ Interim words are visible but never reach your state; `autoResize` follows the dictated text.
60
+
61
+ <KptTextarea value={notes} onValueChange={setNotes} speech autoResize />
@@ -1,30 +1,43 @@
1
1
  import { type ComponentPropsWithRef } from 'react';
2
+ import type { KptSpeechMode } from '@konce-pt/speech';
2
3
  import type { KptHostProps } from '../internal/types.ts';
4
+ import { type KptSpeechColor } from '../speech/speech-button.tsx';
3
5
  export interface KptTextareaProps extends Omit<ComponentPropsWithRef<'textarea'>, 'required'> {
4
6
  /** Dopasowuje wysokość pola do treści przy każdej zmianie. */
5
7
  autoResize?: boolean;
6
8
  /** Oznacza pole jako wymagane atrybutem `aria-required`, a NIE natywnym `required`. */
7
9
  required?: boolean;
8
- /** Licznik „12 / 280” pod polem (wymaga `maxLength`), czytany razem z polem przez `aria-describedby`. */
10
+ /** Licznik "12 / 280" pod polem (wymaga `maxLength`), czytany razem z polem przez `aria-describedby`. */
9
11
  counter?: boolean;
10
12
  /** Pole jest nieprawidłowe. Widoczne dopiero, gdy `touched` też jest prawdziwe. */
11
13
  invalid?: boolean;
12
14
  /** Czy pole było dotknięte; pominięty = stan błędu pokazuje się od razu po `invalid`. */
13
15
  touched?: boolean;
14
- /** Wygodniejszy odpowiednik `onChange` — dostaje samą wartość. */
16
+ /** Wygodniejszy odpowiednik `onChange` - dostaje samą wartość. */
15
17
  onValueChange?: (value: string) => void;
16
- /** Wywoływane na `blur` — moment, w którym pole staje się dotknięte. */
18
+ /** Wywoływane na `blur` - moment, w którym pole staje się dotknięte. */
17
19
  onTouch?: () => void;
18
20
  /** Propsy wrappera hosta (`.kpt-textarea-host`). `className` i `ref` idą na `<textarea>`. */
19
21
  hostProps?: KptHostProps<'span'>;
22
+ /**
23
+ * Mikrofon w górnym rogu pola (Web Speech API); dolny róg zostaje dla uchwytu zmiany rozmiaru.
24
+ * Bez wsparcia przeglądarki się nie pokazuje.
25
+ */
26
+ speech?: boolean;
27
+ /** Język dyktowania (BCP 47); bez niego z `KptI18nProvider`. */
28
+ speechLang?: string;
29
+ /** Kolor "stop" i fali w trakcie nasłuchu; domyślnie kolor motywu. */
30
+ speechColor?: KptSpeechColor;
31
+ /** `insert` (domyślnie, w kursor), `append` albo `replace` (czyści pole w chwili kliknięcia). */
32
+ speechMode?: KptSpeechMode;
20
33
  }
21
34
  /**
22
35
  * Pole wieloliniowe (textarea), z opcjonalnym auto-resize.
23
36
  *
24
- * Działa kontrolowane (`value` + `onValueChange`) i niekontrolowane (`defaultValue`) — auto-resize
37
+ * Działa kontrolowane (`value` + `onValueChange`) i niekontrolowane (`defaultValue`) - auto-resize
25
38
  * czyta wysokość wprost z DOM, więc jest poprawny w obu trybach, także dla wartości początkowej.
26
39
  *
27
40
  * @example
28
- * <KptTextarea name="notes" placeholder="Notatki…" autoResize />
41
+ * <KptTextarea name="notes" placeholder="Notatki..." autoResize />
29
42
  */
30
- export declare function KptTextarea({ autoResize, required, invalid, touched, onValueChange, onTouch, hostProps, className, id, rows, onChange, onBlur, ref, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, counter, ...rest }: Readonly<KptTextareaProps>): import("react").JSX.Element;
43
+ export declare function KptTextarea({ autoResize, required, invalid, touched, onValueChange, onTouch, hostProps, className, id, rows, onChange, onBlur, ref, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, counter, speech, speechLang, speechColor, speechMode, ...rest }: Readonly<KptTextareaProps>): import("react").JSX.Element;
@@ -1,38 +1,52 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useCallback, useLayoutEffect, useRef, useState } from 'react';
3
4
  import { cn } from "../internal/cn.js";
4
5
  import { composeRefs } from "../internal/compose-refs.js";
5
6
  import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
7
+ import { KptSpeechButton } from "../speech/speech-button.js";
8
+ import { useKptSpeechRecognition } from "../speech/use-speech-recognition.js";
6
9
  /**
7
10
  * Pole wieloliniowe (textarea), z opcjonalnym auto-resize.
8
11
  *
9
- * Działa kontrolowane (`value` + `onValueChange`) i niekontrolowane (`defaultValue`) — auto-resize
12
+ * Działa kontrolowane (`value` + `onValueChange`) i niekontrolowane (`defaultValue`) - auto-resize
10
13
  * czyta wysokość wprost z DOM, więc jest poprawny w obu trybach, także dla wartości początkowej.
11
14
  *
12
15
  * @example
13
- * <KptTextarea name="notes" placeholder="Notatki…" autoResize />
16
+ * <KptTextarea name="notes" placeholder="Notatki..." autoResize />
14
17
  */
15
- export function KptTextarea({ autoResize = false, required = false, invalid = false, touched, onValueChange, onTouch, hostProps, className, id, rows = 3, onChange, onBlur, ref, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, counter = false, ...rest }) {
18
+ export function KptTextarea({ autoResize = false, required = false, invalid = false, touched, onValueChange, onTouch, hostProps, className, id, rows = 3, onChange, onBlur, ref, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, counter = false, speech = false, speechLang, speechColor, speechMode = 'insert', ...rest }) {
16
19
  const { className: hostClassName, ...hostRest } = hostProps ?? {};
17
20
  const field = useKptFieldA11y(id, 'kpt-textarea');
18
21
  const textareaId = field.id;
19
22
  const innerRef = useRef(null);
20
- // Długość tekstu dla licznika: w trybie kontrolowanym z `value`, w niekontrolowanym — z wpisów.
23
+ // Długość tekstu dla licznika: w trybie kontrolowanym z `value`, w niekontrolowanym - z wpisów.
21
24
  const [typedLength, setTypedLength] = useState(() => String(rest.value ?? rest.defaultValue ?? '').length);
22
25
  const length = rest.value !== undefined ? String(rest.value).length : typedLength;
23
26
  const showCounter = counter && !!rest.maxLength;
24
27
  const counterId = `${textareaId}-counter`;
25
28
  const showInvalid = invalid && (touched ?? true);
29
+ // Dyktowanie: przed pomiarem wysokości - hook przywraca tekst tymczasowy w swoim efekcie
30
+ // układu, więc `resize` niżej liczy pole razem z nim. Bez `speech` kontroler nie tworzy sesji.
31
+ const mic = useKptSpeechRecognition({
32
+ enabled: speech,
33
+ target: innerRef,
34
+ lang: speechLang,
35
+ mode: speechMode,
36
+ continuous: speechMode !== 'replace',
37
+ disabled: !!rest.disabled || !!rest.readOnly,
38
+ });
39
+ const speechState = speech && mic.available ? (mic.listening ? 'listening' : 'idle') : undefined;
26
40
  const resize = useCallback(() => {
27
41
  const el = innerRef.current;
28
42
  if (!el || !autoResize)
29
43
  return;
30
- // Zerowanie przed odczytem `scrollHeight` jest konieczne — bez niego pole potrafi tylko
44
+ // Zerowanie przed odczytem `scrollHeight` jest konieczne - bez niego pole potrafi tylko
31
45
  // rosnąć, bo `scrollHeight` nigdy nie spada poniżej bieżącej wysokości.
32
46
  el.style.height = 'auto';
33
47
  el.style.height = `${el.scrollHeight}px`;
34
48
  }, [autoResize]);
35
- // Wartość początkowa i każda zmiana z zewnątrz (tryb kontrolowany) — przed malowaniem,
49
+ // Wartość początkowa i każda zmiana z zewnątrz (tryb kontrolowany) - przed malowaniem,
36
50
  // żeby pole nie mrugnęło niedopasowaną wysokością.
37
51
  useLayoutEffect(resize);
38
52
  const handleChange = useCallback((event) => {
@@ -45,5 +59,6 @@ export function KptTextarea({ autoResize = false, required = false, invalid = fa
45
59
  onBlur?.(event);
46
60
  onTouch?.();
47
61
  }, [onBlur, onTouch]);
48
- return (_jsxs("span", { className: cn('kpt-textarea-host', hostClassName), ...hostRest, children: [_jsx("textarea", { className: cn('kpt-textarea__field', className), id: textareaId, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy, showCounter && counterId), rows: rows, ref: composeRefs(innerRef, ref), "aria-required": required || undefined, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ...rest }), showCounter ? (_jsxs("span", { className: "kpt-textarea__counter", id: counterId, children: [length, " / ", rest.maxLength] })) : null] }));
62
+ const textarea = (_jsx("textarea", { className: cn('kpt-textarea__field', className), id: textareaId, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy, showCounter && counterId), rows: rows, ref: composeRefs(innerRef, ref), "aria-required": required || undefined, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ...rest }));
63
+ return (_jsxs("span", { className: cn('kpt-textarea-host', hostClassName), "data-speech": speechState, ...hostRest, children: [speech ? (_jsxs("span", { className: "kpt-textarea__box", children: [textarea, _jsx(KptSpeechButton, { listeningColor: speechColor, speech: mic, size: "sm", unsupported: "hide", disabled: !!rest.disabled || !!rest.readOnly, hostProps: { className: 'kpt-textarea__speech' } })] })) : (textarea), showCounter ? (_jsxs("span", { className: "kpt-textarea__counter", id: counterId, children: [length, " / ", rest.maxLength] })) : null] }));
49
64
  }
@@ -1,19 +1,19 @@
1
1
  # KptTimeline (@konce-pt/react)
2
2
 
3
- A timeline — a vertical list of events with markers.
3
+ A timeline - a vertical list of events with markers.
4
4
  Import: `import { KptTimeline } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-timeline-host">
8
8
  <ol class="kpt-timeline">
9
9
  <li class="kpt-timeline__item">
10
- <div class="kpt-timeline__marker" data-variant="success">…icon…</div>
10
+ <div class="kpt-timeline__marker" data-variant="success">...icon...</div>
11
11
  <div class="kpt-timeline__content">
12
12
  <div class="kpt-timeline__header">
13
13
  <span class="kpt-timeline__title">Order created</span>
14
14
  <span class="kpt-timeline__time">10:02</span>
15
15
  </div>
16
- <p class="kpt-timeline__desc">…</p>
16
+ <p class="kpt-timeline__desc">...</p>
17
17
  </div>
18
18
  </li>
19
19
  </ol>
@@ -29,7 +29,7 @@ Import: `import { KptTimeline } from '@konce-pt/react';`
29
29
  - `variant?`: `'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info'` (default `'primary'`)
30
30
 
31
31
  ## The variant is an attribute, not a class
32
- The marker carries `data-variant`, and the SCSS maps it to `--_color` — the same contract as every
32
+ The marker carries `data-variant`, and the SCSS maps it to `--_color` - the same contract as every
33
33
  other component in the library, so a new variant is a token, not a new class.
34
34
 
35
35
  ## The connecting line is a pseudo-element
@@ -11,7 +11,7 @@ export interface KptTimelineProps extends ComponentPropsWithRef<'div'> {
11
11
  items?: readonly KptTimelineItem[];
12
12
  }
13
13
  /**
14
- * Oś czasu — pionowa lista zdarzeń z markerami.
14
+ * Oś czasu - pionowa lista zdarzeń z markerami.
15
15
  *
16
16
  * @example
17
17
  * <KptTimeline items={[{ title: 'Utworzono', time: '10:00', variant: 'success', icon: 'check' }]} />
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../internal/cn.js";
3
3
  import { KptIcon } from "../icon/icon.js";
4
4
  /**
5
- * Oś czasu — pionowa lista zdarzeń z markerami.
5
+ * Oś czasu - pionowa lista zdarzeń z markerami.
6
6
  *
7
7
  * @example
8
8
  * <KptTimeline items={[{ title: 'Utworzono', time: '10:00', variant: 'success', icon: 'check' }]} />
@@ -5,15 +5,15 @@ Import: `import { kptToast, KptToastContainer } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-toast-container-host">
8
- <div class="kpt-toast-container" role="region" aria-label="Notifications">
9
- <div class="kpt-toast" data-variant="success">
10
- <span class="kpt-icon-host kpt-toast__icon">…</span>
8
+ <div class="kpt-toast-container" role="region" data-position="bottom-end" aria-label="Notifications">
9
+ <div class="kpt-toast" data-variant="success" data-appearance="outline">
10
+ <span class="kpt-icon-host kpt-toast__icon">...</span>
11
11
  <div class="kpt-toast__content">
12
12
  <div class="kpt-toast__title">Saved</div>
13
13
  <div class="kpt-toast__message">Your changes are stored.</div>
14
14
  </div>
15
15
  <button class="kpt-toast__action" type="button">Undo</button>
16
- <button class="kpt-toast__close" type="button" aria-label="Close">…</button>
16
+ <button class="kpt-toast__close" type="button" aria-label="Close">...</button>
17
17
  </div>
18
18
  </div>
19
19
  <span class="kpt-toast-container__live" aria-live="polite" aria-atomic="true">Saved. Your changes are stored.</span>
@@ -21,15 +21,17 @@ Import: `import { kptToast, KptToastContainer } from '@konce-pt/react';`
21
21
  </div>
22
22
 
23
23
  ## kptToast
24
- - `show(message, options?)` — returns the toast id
25
- - `info` / `success` / `warning` / `error` — the same, with the variant preset
26
- - `dismiss(id)`, `clear()`, `pause()`, `resume()`
27
- - options: `title`, `variant`, `duration` (ms, default 4000; `0` disables auto-dismiss), `action: { label, run }`
24
+ - `show(message, options?)` - returns the toast id
25
+ - `info` / `success` / `warning` / `error` - the same, with the variant preset
26
+ - `dismiss(id)`, `clear()`, `pause()`, `resume()`, `configure(config)`
27
+ - options: `title`, `variant`, `duration` (ms, default 4000; `0` disables auto-dismiss), `action: { label, run }`,
28
+ `position`, `appearance` ('outline' | 'filled'), `closable` (default true), `progress` (default false)
29
+ - `useKptToasts()`, `useKptToastsPaused()` - the queue and the paused state as hooks
28
30
 
29
31
  ## A module singleton, not a provider
30
32
  The store lives in the module, which is the closest equivalent of Angular's
31
- `providedIn: 'root'`. `kptToast.error(...)` therefore works from anywhere — including outside the
32
- React tree, in a data-layer error handler or an HTTP interceptor — with no provider wrapping the
33
+ `providedIn: 'root'`. `kptToast.error(...)` therefore works from anywhere - including outside the
34
+ React tree, in a data-layer error handler or an HTTP interceptor - with no provider wrapping the
33
35
  application. `useKptToasts()` exposes the current list when you want to render them yourself.
34
36
 
35
37
  ## Placement
@@ -42,25 +44,56 @@ mounts are kept in the store and appear as soon as it does.
42
44
 
43
45
  kptToast.success('Saved', { title: 'Saved' });
44
46
  kptToast.error('Could not connect to the server.', { title: 'Error', duration: 0 });
45
- const id = kptToast.info('Uploading…', { duration: 0 });
47
+ const id = kptToast.info('Uploading...', { duration: 0 });
46
48
  kptToast.dismiss(id);
47
49
 
50
+ ## Position
51
+ `<KptToastContainer position="top-end" />` - the corner for toasts without their own `position`:
52
+ `top-start`, `top-center`, `top-end`, `bottom-start`, `bottom-center`, `bottom-end` (default).
53
+ `start`/`end` are logical (they swap in RTL). Each corner is its own stack (`data-position`); the
54
+ newest toast is always next to the edge (bottom of a bottom stack, top of a top one) and slides in
55
+ from it. Distance from the edge: `--kpt-toast-offset` (default `--kpt-space-4`) plus the safe area;
56
+ below 40rem a stack takes the full width. One toast can go elsewhere: `{ position: 'bottom-center' }`.
57
+
58
+ ## Appearance
59
+ `appearance: 'outline'` (default) - a raised surface with the accent on the start edge;
60
+ `'filled'` - the whole toast in the variant colour, content in `--kpt-color-<role>-contrast` (white
61
+ on every variant in the light theme, dark in the dark theme).
62
+ Icon, text, action and close button are centred on one axis.
63
+
64
+ ## Closing and the time bar
65
+ `closable: false` hides the close button. A toast without the close button, without an action and
66
+ with `duration: 0` could never be closed, so it gets `KPT_TOAST_FALLBACK_DURATION` (5000 ms).
67
+ `progress: true` draws a time bar at the bottom that shrinks over `duration` and stops while the
68
+ timers are paused (`useKptToastsPaused()` -> `data-paused` on the stack). It ignores the motion switch -
69
+ it shows time, it is not decoration.
70
+
71
+ ## App-wide defaults
72
+ kptToast.configure({ appearance: 'filled', progress: true, duration: 5000 }); // once, at startup
73
+ `KptToastConfig`: `duration`, `appearance`, `closable`, `progress`. Order: toast option >
74
+ `kptToast.configure` > library default. `resolveKptToast(id, message, options, config)` is the same
75
+ resolution as a pure function.
76
+
48
77
  ## Actions and pausing
49
- `action: { label, run }` adds one button to the toast (typically “Undo”); a click calls `run` and
78
+ `action: { label, run }` adds one button to the toast (typically "Undo"); a click calls `run` and
50
79
  dismisses the toast. Give such toasts a longer `duration`, and keep the action available elsewhere.
51
80
  `pause()` / `resume()` stop and continue every timer; the container calls them on hover and focus,
52
81
  and resumes by itself when the stack empties.
53
82
 
54
83
  ## Tokens
55
- The semantic colour pairs of each variant (`--kpt-color-info` / `-success` / `-warning` /
56
- `-danger` with their `-subtle` and `on-` counterparts), `--kpt-elevation-3`, `--kpt-z-overlay`.
84
+ The accent of each variant (`--kpt-color-info` / `-success` / `-warning` / `-danger`), the content
85
+ of `filled` (`--kpt-color-<role>-contrast`), `--kpt-color-surface-raised`, `--kpt-elevation-3`,
86
+ `--kpt-toast-offset`, `--kpt-z-toast`.
57
87
 
58
88
  ## Accessibility
59
- Announcements go through two permanent, visually hidden live regions next to the stack —
60
- `aria-live="polite"` for ordinary toasts and `aria-live="assertive"` for `danger` — and not through
89
+ Announcements go through two permanent, visually hidden live regions next to the stack -
90
+ `aria-live="polite"` for ordinary toasts and `aria-live="assertive"` for `danger` - and not through
61
91
  the toasts themselves: a live region has to exist before content appears in it, and nested regions
62
92
  are read twice by some screen readers. Each region is cleared before it is written, so the same
63
93
  text twice is announced twice, and a dismissed toast never re-announces an older one. While there
64
- are toasts the stack is `role="region"` named `toast.region` (“Notifications”). Pointer or focus on
94
+ are toasts the stack is `role="region"` named `toast.region` ("Notifications"). Pointer or focus on
65
95
  the stack pauses every timer (WCAG 2.2.1); the timers resume with the time that was left. The close
66
96
  button is labelled from `common.close`.
97
+
98
+ ## Toasts with an action
99
+ A toast with `action` does not close by itself (`duration` defaults to 0): a keyboard or screen-reader user cannot reach the "Undo" button at the end of the page within four seconds (WCAG 2.2.1). An explicit `duration` still wins.