@konce-pt/react 0.11.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +128 -64
  2. package/dist/accordion/accordion.d.ts +14 -6
  3. package/dist/accordion/accordion.js +25 -17
  4. package/dist/accordion/llms.txt +22 -10
  5. package/dist/alert/alert.d.ts +2 -2
  6. package/dist/alert/alert.js +3 -2
  7. package/dist/alert/llms.txt +10 -9
  8. package/dist/app-shell/app-shell.d.ts +14 -14
  9. package/dist/app-shell/app-shell.js +22 -15
  10. package/dist/app-shell/llms.txt +16 -15
  11. package/dist/auth/auth-types.d.ts +6 -6
  12. package/dist/auth/auth.d.ts +2 -2
  13. package/dist/auth/auth.js +24 -15
  14. package/dist/auth/llms.txt +12 -11
  15. package/dist/autocomplete/autocomplete.d.ts +19 -6
  16. package/dist/autocomplete/autocomplete.js +32 -11
  17. package/dist/autocomplete/llms.txt +19 -5
  18. package/dist/avatar/avatar.d.ts +6 -6
  19. package/dist/avatar/avatar.js +6 -5
  20. package/dist/avatar/llms.txt +10 -10
  21. package/dist/avatar-group/avatar-group.d.ts +4 -4
  22. package/dist/avatar-group/avatar-group.js +4 -3
  23. package/dist/avatar-group/llms.txt +8 -8
  24. package/dist/backdrop/backdrop.d.ts +7 -26
  25. package/dist/backdrop/backdrop.js +32 -27
  26. package/dist/backdrop/llms.txt +27 -27
  27. package/dist/badge/badge.d.ts +3 -3
  28. package/dist/badge/badge.js +1 -1
  29. package/dist/badge/llms.txt +11 -11
  30. package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
  31. package/dist/bottom-sheet/bottom-sheet.js +5 -4
  32. package/dist/bottom-sheet/llms.txt +11 -8
  33. package/dist/breadcrumb/breadcrumb.d.ts +8 -2
  34. package/dist/breadcrumb/breadcrumb.js +11 -3
  35. package/dist/breadcrumb/llms.txt +10 -2
  36. package/dist/button/button.d.ts +3 -3
  37. package/dist/button/button.js +10 -9
  38. package/dist/button/llms.txt +27 -19
  39. package/dist/button-group/button-group.d.ts +18 -5
  40. package/dist/button-group/button-group.js +54 -6
  41. package/dist/button-group/llms.txt +27 -18
  42. package/dist/card/card.d.ts +8 -8
  43. package/dist/card/card.js +10 -9
  44. package/dist/card/llms.txt +20 -20
  45. package/dist/carousel/carousel.d.ts +6 -6
  46. package/dist/carousel/carousel.js +8 -5
  47. package/dist/carousel/llms.txt +10 -10
  48. package/dist/charts/chart-legend.d.ts +3 -3
  49. package/dist/charts/chart-legend.js +2 -1
  50. package/dist/charts/chart-tooltip.d.ts +3 -3
  51. package/dist/charts/chart-tooltip.js +1 -1
  52. package/dist/charts/chart.d.ts +4 -3
  53. package/dist/charts/chart.js +18 -10
  54. package/dist/charts/llms.txt +10 -7
  55. package/dist/charts-entry/public-api.js +2 -2
  56. package/dist/chat/chat.d.ts +17 -10
  57. package/dist/chat/chat.js +77 -23
  58. package/dist/chat/llms.txt +39 -15
  59. package/dist/chat-composer/chat-composer.d.ts +20 -7
  60. package/dist/chat-composer/chat-composer.js +29 -7
  61. package/dist/chat-composer/llms.txt +20 -11
  62. package/dist/chat-dock/chat-dock.d.ts +11 -4
  63. package/dist/chat-dock/chat-dock.js +10 -6
  64. package/dist/chat-dock/llms.txt +15 -14
  65. package/dist/chat-entry/public-api.js +1 -1
  66. package/dist/chat-message/chat-message.d.ts +12 -5
  67. package/dist/chat-message/chat-message.js +19 -8
  68. package/dist/chat-message/llms.txt +16 -15
  69. package/dist/chat-typing/chat-typing.d.ts +2 -2
  70. package/dist/chat-typing/chat-typing.js +4 -3
  71. package/dist/chat-typing/llms.txt +6 -6
  72. package/dist/checkbox/checkbox.d.ts +13 -6
  73. package/dist/checkbox/checkbox.js +31 -5
  74. package/dist/checkbox/llms.txt +26 -11
  75. package/dist/chip/chip.d.ts +4 -4
  76. package/dist/chip/chip.js +3 -2
  77. package/dist/chip/llms.txt +11 -11
  78. package/dist/chips-input/chips-input.d.ts +6 -4
  79. package/dist/chips-input/chips-input.js +47 -12
  80. package/dist/chips-input/llms.txt +18 -8
  81. package/dist/clock/clock.d.ts +11 -6
  82. package/dist/clock/clock.js +38 -8
  83. package/dist/clock/llms.txt +12 -8
  84. package/dist/color-picker/color-picker.d.ts +9 -5
  85. package/dist/color-picker/color-picker.js +37 -18
  86. package/dist/color-picker/llms.txt +8 -5
  87. package/dist/confirm/confirm-container.d.ts +3 -3
  88. package/dist/confirm/confirm-container.js +6 -5
  89. package/dist/confirm/confirm-store.d.ts +4 -4
  90. package/dist/confirm/confirm-store.js +11 -5
  91. package/dist/confirm/llms.txt +8 -7
  92. package/dist/context-menu/context-menu.d.ts +1 -1
  93. package/dist/context-menu/context-menu.js +37 -14
  94. package/dist/context-menu/llms.txt +10 -7
  95. package/dist/data-table/data-table-types.d.ts +5 -5
  96. package/dist/data-table/data-table.d.ts +37 -5
  97. package/dist/data-table/data-table.js +426 -119
  98. package/dist/data-table/export-csv.d.ts +3 -3
  99. package/dist/data-table/export-csv.js +8 -10
  100. package/dist/data-table/llms.txt +127 -79
  101. package/dist/data-view/data-view.d.ts +13 -5
  102. package/dist/data-view/data-view.js +68 -6
  103. package/dist/data-view/llms.txt +29 -10
  104. package/dist/date-range/date-range.d.ts +20 -8
  105. package/dist/date-range/date-range.js +86 -63
  106. package/dist/date-range/llms.txt +32 -18
  107. package/dist/datepicker/datepicker.d.ts +22 -8
  108. package/dist/datepicker/datepicker.js +103 -71
  109. package/dist/datepicker/llms.txt +36 -22
  110. package/dist/dialog/dialog.d.ts +4 -4
  111. package/dist/dialog/dialog.js +32 -11
  112. package/dist/dialog/llms.txt +13 -10
  113. package/dist/divider/divider.d.ts +7 -1
  114. package/dist/divider/divider.js +3 -2
  115. package/dist/divider/llms.txt +4 -3
  116. package/dist/drawer/drawer.d.ts +9 -4
  117. package/dist/drawer/drawer.js +5 -4
  118. package/dist/drawer/llms.txt +13 -10
  119. package/dist/empty/empty.d.ts +2 -2
  120. package/dist/empty/empty.js +1 -1
  121. package/dist/empty/llms.txt +9 -9
  122. package/dist/fab/fab.d.ts +1 -1
  123. package/dist/fab/fab.js +1 -1
  124. package/dist/fab/llms.txt +10 -6
  125. package/dist/fieldset/fieldset.d.ts +18 -4
  126. package/dist/fieldset/fieldset.js +12 -6
  127. package/dist/fieldset/llms.txt +26 -9
  128. package/dist/file-upload/file-upload.d.ts +8 -2
  129. package/dist/file-upload/file-upload.js +22 -11
  130. package/dist/file-upload/llms.txt +12 -9
  131. package/dist/form-field/form-field-context.d.ts +4 -4
  132. package/dist/form-field/form-field.d.ts +12 -4
  133. package/dist/form-field/form-field.js +27 -6
  134. package/dist/form-field/llms.txt +25 -11
  135. package/dist/galleria/galleria.d.ts +3 -3
  136. package/dist/galleria/galleria.js +9 -6
  137. package/dist/galleria/llms.txt +7 -7
  138. package/dist/grid/col.d.ts +4 -4
  139. package/dist/grid/col.js +2 -2
  140. package/dist/grid/flex.d.ts +3 -3
  141. package/dist/grid/flex.js +1 -1
  142. package/dist/grid/grid.d.ts +7 -7
  143. package/dist/grid/grid.js +3 -3
  144. package/dist/grid/layout.d.ts +2 -2
  145. package/dist/grid/layout.js +2 -2
  146. package/dist/grid/llms.txt +15 -15
  147. package/dist/grid-entry/public-api.js +1 -1
  148. package/dist/i18n/i18n-context.d.ts +6 -6
  149. package/dist/i18n/i18n-context.js +27 -5
  150. package/dist/icon/icon-registry.d.ts +3 -3
  151. package/dist/icon/icon-registry.js +3 -3
  152. package/dist/icon/icon.d.ts +4 -4
  153. package/dist/icon/icon.js +10 -7
  154. package/dist/icon/llms.txt +13 -13
  155. package/dist/icon-button/icon-button.d.ts +2 -2
  156. package/dist/icon-button/icon-button.js +1 -1
  157. package/dist/icon-button/llms.txt +9 -5
  158. package/dist/icons-entry/public-api.d.ts +2 -2
  159. package/dist/icons-entry/public-api.js +3 -3
  160. package/dist/image/image.js +5 -5
  161. package/dist/image/llms.txt +13 -13
  162. package/dist/input/input.d.ts +18 -5
  163. package/dist/input/input.js +22 -6
  164. package/dist/input/llms.txt +25 -11
  165. package/dist/input-mask/input-mask.d.ts +7 -2
  166. package/dist/input-mask/input-mask.js +17 -43
  167. package/dist/input-mask/llms.txt +8 -5
  168. package/dist/input-number/input-number.d.ts +11 -9
  169. package/dist/input-number/input-number.js +25 -21
  170. package/dist/input-number/llms.txt +17 -14
  171. package/dist/input-otp/input-otp.d.ts +18 -5
  172. package/dist/input-otp/input-otp.js +48 -24
  173. package/dist/input-otp/llms.txt +18 -7
  174. package/dist/internal/calendar-focus.d.ts +1 -1
  175. package/dist/internal/calendar-focus.js +3 -3
  176. package/dist/internal/cn.d.ts +1 -1
  177. package/dist/internal/mask.d.ts +14 -0
  178. package/dist/internal/mask.js +62 -0
  179. package/dist/internal/number-group.d.ts +22 -0
  180. package/dist/internal/number-group.js +53 -0
  181. package/dist/internal/option-key.d.ts +6 -0
  182. package/dist/internal/option-key.js +8 -0
  183. package/dist/internal/option-nav.d.ts +4 -4
  184. package/dist/internal/option-nav.js +5 -5
  185. package/dist/internal/overlay-container.js +1 -1
  186. package/dist/internal/overlay.d.ts +3 -3
  187. package/dist/internal/overlay.js +40 -10
  188. package/dist/internal/password-strength.d.ts +6 -0
  189. package/dist/internal/password-strength.js +74 -0
  190. package/dist/internal/roving.d.ts +2 -2
  191. package/dist/internal/roving.js +3 -3
  192. package/dist/internal/scroll-lock.d.ts +6 -0
  193. package/dist/internal/scroll-lock.js +35 -0
  194. package/dist/internal/slot-children.d.ts +13 -0
  195. package/dist/internal/slot-children.js +31 -0
  196. package/dist/internal/slot.d.ts +3 -3
  197. package/dist/internal/slot.js +2 -2
  198. package/dist/internal/step.d.ts +12 -0
  199. package/dist/internal/step.js +31 -0
  200. package/dist/internal/tween.d.ts +5 -5
  201. package/dist/internal/tween.js +7 -8
  202. package/dist/internal/types.d.ts +2 -2
  203. package/dist/internal/use-breakpoint.d.ts +2 -2
  204. package/dist/internal/use-breakpoint.js +4 -4
  205. package/dist/internal/use-controllable-state.d.ts +5 -0
  206. package/dist/internal/use-controllable-state.js +25 -4
  207. package/dist/internal/use-id.d.ts +2 -2
  208. package/dist/internal/use-id.js +2 -2
  209. package/dist/internal/use-modal-focus.d.ts +2 -1
  210. package/dist/internal/use-modal-focus.js +14 -3
  211. package/dist/knob/knob.d.ts +7 -4
  212. package/dist/knob/knob.js +27 -22
  213. package/dist/knob/llms.txt +18 -11
  214. package/dist/listbox/listbox.d.ts +8 -6
  215. package/dist/listbox/listbox.js +37 -17
  216. package/dist/listbox/llms.txt +12 -9
  217. package/dist/loader/llms.txt +56 -0
  218. package/dist/loader/loader.d.ts +49 -0
  219. package/dist/loader/loader.js +68 -0
  220. package/dist/map/llms.txt +30 -23
  221. package/dist/map/map-create-dialog.d.ts +4 -4
  222. package/dist/map/map-create-dialog.js +36 -28
  223. package/dist/map/map-hours-field.d.ts +4 -4
  224. package/dist/map/map-hours-field.js +8 -7
  225. package/dist/map/map-image-field.d.ts +2 -2
  226. package/dist/map/map-image-field.js +6 -5
  227. package/dist/map/map-legend.d.ts +4 -4
  228. package/dist/map/map-legend.js +3 -2
  229. package/dist/map/map-poi-card.d.ts +3 -3
  230. package/dist/map/map-poi-card.js +10 -9
  231. package/dist/map/map-search.d.ts +17 -6
  232. package/dist/map/map-search.js +70 -43
  233. package/dist/map/map.d.ts +25 -13
  234. package/dist/map/map.js +86 -57
  235. package/dist/map/ports.d.ts +9 -9
  236. package/dist/map/ports.js +6 -6
  237. package/dist/map-entry/public-api.js +2 -2
  238. package/dist/megamenu/llms.txt +18 -7
  239. package/dist/megamenu/megamenu.d.ts +12 -6
  240. package/dist/megamenu/megamenu.js +23 -14
  241. package/dist/mention/llms.txt +15 -15
  242. package/dist/mention/mention.d.ts +5 -5
  243. package/dist/mention/mention.js +2 -2
  244. package/dist/mention/mentions.d.ts +1 -1
  245. package/dist/mention/mentions.js +1 -1
  246. package/dist/menu/llms.txt +12 -12
  247. package/dist/menu/menu-item.d.ts +4 -4
  248. package/dist/menu/menu-keys.d.ts +2 -2
  249. package/dist/menu/menu-keys.js +5 -5
  250. package/dist/menu/menu-rows.js +1 -0
  251. package/dist/menu/menu.d.ts +2 -2
  252. package/dist/menu/menu.js +15 -8
  253. package/dist/menubar/llms.txt +19 -8
  254. package/dist/menubar/menubar.d.ts +11 -5
  255. package/dist/menubar/menubar.js +23 -11
  256. package/dist/meter-group/llms.txt +12 -12
  257. package/dist/meter-group/meter-group.d.ts +2 -2
  258. package/dist/meter-group/meter-group.js +2 -1
  259. package/dist/motion/motion-context.d.ts +22 -0
  260. package/dist/motion/motion-context.js +28 -0
  261. package/dist/order-list/llms.txt +24 -9
  262. package/dist/order-list/order-list.d.ts +12 -4
  263. package/dist/order-list/order-list.js +123 -25
  264. package/dist/paginator/llms.txt +8 -8
  265. package/dist/paginator/paginator.js +7 -4
  266. package/dist/panel/llms.txt +25 -13
  267. package/dist/panel/panel.d.ts +11 -3
  268. package/dist/panel/panel.js +12 -7
  269. package/dist/password/llms.txt +19 -7
  270. package/dist/password/password.d.ts +2 -2
  271. package/dist/password/password.js +27 -16
  272. package/dist/peek/llms.txt +11 -11
  273. package/dist/peek/peek.d.ts +6 -6
  274. package/dist/peek/peek.js +41 -19
  275. package/dist/pick-list/llms.txt +35 -12
  276. package/dist/pick-list/pick-list.d.ts +12 -4
  277. package/dist/pick-list/pick-list.js +128 -24
  278. package/dist/popover/llms.txt +13 -10
  279. package/dist/popover/popover.d.ts +6 -4
  280. package/dist/popover/popover.js +14 -7
  281. package/dist/progress/llms.txt +17 -17
  282. package/dist/progress/progress.d.ts +7 -7
  283. package/dist/progress/progress.js +7 -6
  284. package/dist/public-api.d.ts +16 -4
  285. package/dist/public-api.js +13 -7
  286. package/dist/radio-group/llms.txt +16 -6
  287. package/dist/radio-group/radio-group.d.ts +12 -3
  288. package/dist/radio-group/radio-group.js +23 -4
  289. package/dist/rating/llms.txt +20 -13
  290. package/dist/rating/rating-pointer.d.ts +16 -0
  291. package/dist/rating/rating-pointer.js +26 -0
  292. package/dist/rating/rating.d.ts +6 -6
  293. package/dist/rating/rating.js +77 -12
  294. package/dist/rich-text/lists.d.ts +2 -2
  295. package/dist/rich-text/lists.js +7 -7
  296. package/dist/rich-text/llms.txt +35 -12
  297. package/dist/rich-text/rich-text.d.ts +13 -14
  298. package/dist/rich-text/rich-text.js +311 -142
  299. package/dist/rich-text/sanitize.d.ts +11 -2
  300. package/dist/rich-text/sanitize.js +80 -32
  301. package/dist/rich-text/tables.d.ts +3 -3
  302. package/dist/rich-text/tables.js +3 -3
  303. package/dist/roadmap/llms.txt +23 -17
  304. package/dist/roadmap/roadmap.d.ts +6 -6
  305. package/dist/roadmap/roadmap.js +102 -25
  306. package/dist/roadmap-entry/public-api.js +2 -2
  307. package/dist/scroll-top/llms.txt +6 -6
  308. package/dist/scroll-top/scroll-top.d.ts +1 -1
  309. package/dist/scroll-top/scroll-top.js +2 -1
  310. package/dist/select/llms.txt +22 -12
  311. package/dist/select/select.d.ts +10 -8
  312. package/dist/select/select.js +87 -47
  313. package/dist/shared/types.d.ts +22 -1
  314. package/dist/shared/types.js +9 -1
  315. package/dist/sidenav/llms.txt +9 -9
  316. package/dist/sidenav/sidenav.d.ts +2 -3
  317. package/dist/sidenav/sidenav.js +5 -4
  318. package/dist/skeleton/llms.txt +3 -3
  319. package/dist/skeleton/skeleton.d.ts +1 -1
  320. package/dist/skeleton/skeleton.js +1 -1
  321. package/dist/slider/llms.txt +34 -12
  322. package/dist/slider/slider-drag.d.ts +26 -0
  323. package/dist/slider/slider-drag.js +79 -0
  324. package/dist/slider/slider.d.ts +8 -5
  325. package/dist/slider/slider.js +38 -8
  326. package/dist/speech/llms.txt +97 -0
  327. package/dist/speech/speech-button.d.ts +44 -0
  328. package/dist/speech/speech-button.js +86 -0
  329. package/dist/speech/speech-wave.d.ts +19 -0
  330. package/dist/speech/speech-wave.js +16 -0
  331. package/dist/speech/use-speech-recognition.d.ts +81 -0
  332. package/dist/speech/use-speech-recognition.js +179 -0
  333. package/dist/speed-dial/llms.txt +14 -8
  334. package/dist/speed-dial/speed-dial.d.ts +1 -1
  335. package/dist/speed-dial/speed-dial.js +3 -2
  336. package/dist/spinner/llms.txt +7 -7
  337. package/dist/spinner/spinner.d.ts +1 -1
  338. package/dist/spinner/spinner.js +2 -1
  339. package/dist/split-button/llms.txt +21 -15
  340. package/dist/split-button/split-button.d.ts +2 -2
  341. package/dist/split-button/split-button.js +13 -6
  342. package/dist/splitter/llms.txt +11 -11
  343. package/dist/splitter/splitter.d.ts +3 -3
  344. package/dist/splitter/splitter.js +25 -10
  345. package/dist/stepper/llms.txt +35 -13
  346. package/dist/stepper/stepper.d.ts +6 -6
  347. package/dist/stepper/stepper.js +60 -13
  348. package/dist/switch/llms.txt +15 -5
  349. package/dist/switch/switch.d.ts +10 -3
  350. package/dist/switch/switch.js +18 -4
  351. package/dist/switch-group/llms.txt +11 -8
  352. package/dist/switch-group/switch-group.d.ts +6 -4
  353. package/dist/switch-group/switch-group.js +9 -7
  354. package/dist/tabs/llms.txt +12 -9
  355. package/dist/tabs/tabs.d.ts +5 -5
  356. package/dist/tabs/tabs.js +36 -20
  357. package/dist/textarea/llms.txt +23 -12
  358. package/dist/textarea/textarea.d.ts +19 -6
  359. package/dist/textarea/textarea.js +22 -7
  360. package/dist/timeline/llms.txt +4 -4
  361. package/dist/timeline/timeline.d.ts +1 -1
  362. package/dist/timeline/timeline.js +1 -1
  363. package/dist/toast/llms.txt +50 -17
  364. package/dist/toast/toast-container.d.ts +9 -3
  365. package/dist/toast/toast-container.js +18 -9
  366. package/dist/toast/toast-store.d.ts +42 -2
  367. package/dist/toast/toast-store.js +36 -1
  368. package/dist/toolbar/llms.txt +7 -7
  369. package/dist/toolbar/toolbar.d.ts +3 -3
  370. package/dist/toolbar/toolbar.js +2 -2
  371. package/dist/tooltip/llms.txt +14 -12
  372. package/dist/tooltip/tooltip.d.ts +5 -4
  373. package/dist/tooltip/tooltip.js +100 -41
  374. package/dist/tree/llms.txt +25 -11
  375. package/dist/tree/tree-keys.d.ts +5 -5
  376. package/dist/tree/tree-keys.js +7 -7
  377. package/dist/tree/tree.d.ts +17 -5
  378. package/dist/tree/tree.js +62 -20
  379. package/dist/update/llms.txt +54 -0
  380. package/dist/update/update.d.ts +49 -0
  381. package/dist/update/update.js +82 -0
  382. package/package.json +18 -15
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
3
4
  import { cn } from "../internal/cn.js";
@@ -7,21 +8,37 @@ import { useControllableState } from "../internal/use-controllable-state.js";
7
8
  import { foldMentionText } from '@konce-pt/mention';
8
9
  import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
9
10
  import { useKptMessages } from "../i18n/i18n-context.js";
11
+ import { KptSpeechButton } from "../speech/speech-button.js";
12
+ import { useKptSpeechRecognition } from "../speech/use-speech-recognition.js";
10
13
  /**
11
- * Pole z podpowiedziami. Wartością jest wpisany tekst, nie wybrana opcja — podpowiedzi
14
+ * Pole z podpowiedziami. Wartością jest wpisany tekst, nie wybrana opcja - podpowiedzi
12
15
  * skracają pisanie, ale nie ograniczają wpisu, więc pole nadaje się też do wartości spoza listy.
13
16
  *
14
- * Wzorzec WAI-ARIA „combobox z listą”: fokus zostaje w polu, aktywną podpowiedź ogłasza
15
- * `aria-activedescendant`, a liczbę podpowiedzi (albo ich brak) — region `polite`. Dopasowanie
16
- * pomija wielkość liter i diakrytyki („lodz” znajduje „Łódź”).
17
+ * Wzorzec WAI-ARIA "combobox z listą": fokus zostaje w polu, aktywną podpowiedź ogłasza
18
+ * `aria-activedescendant`, a liczbę podpowiedzi (albo ich brak) - region `polite`. Dopasowanie
19
+ * pomija wielkość liter i diakrytyki ("lodz" znajduje "Łódź").
17
20
  *
18
21
  * @example
19
- * <KptAutocomplete options={cities} value={city} onValueChange={setCity} placeholder="Miasto…" />
22
+ * <KptAutocomplete options={cities} value={city} onValueChange={setCity} placeholder="Miasto..." />
20
23
  */
21
- export function KptAutocomplete({ options = [], value, defaultValue = '', onValueChange, invalid = false, touched, onTouch, disabled = false, className, onBlur, onFocus, onKeyDown, ref, id, 'aria-describedby': ariaDescribedBy, locale, dictionary, ...rest }) {
24
+ export function KptAutocomplete({ options = [], value, defaultValue = '', onValueChange, invalid = false, touched, onTouch, disabled = false, readOnly = false, className, onBlur, onFocus, onKeyDown, ref, id, 'aria-describedby': ariaDescribedBy, locale, dictionary, speech = false, speechLang, speechColor, speechMode = 'replace', ...rest }) {
22
25
  const { t } = useKptMessages({ locale, dictionary });
23
26
  const field = useKptFieldA11y(id, 'kpt-autocomplete');
24
27
  const inputRef = useRef(null);
28
+ /** Kotwica nakładki w stanie (callback ref), nie `inputRef.current` czytane w renderze. */
29
+ const [anchor, setAnchor] = useState(null);
30
+ const setRefs = useMemo(() => composeRefs(inputRef, ref, setAnchor), [ref]);
31
+ // Podyktowana wartość wchodzi przez `onChange` pola, więc lista otwiera się jak po wpisaniu;
32
+ // słowa tymczasowe nie filtrują - nie ma ich w stanie. Bez `speech` kontroler nie tworzy sesji.
33
+ const mic = useKptSpeechRecognition({
34
+ enabled: speech,
35
+ target: inputRef,
36
+ lang: speechLang,
37
+ mode: speechMode,
38
+ continuous: speechMode !== 'replace',
39
+ disabled: disabled || readOnly,
40
+ });
41
+ const speechState = speech && mic.available ? (mic.listening ? 'listening' : 'idle') : undefined;
25
42
  const [current, setCurrent] = useControllableState({
26
43
  value,
27
44
  defaultValue,
@@ -29,7 +46,7 @@ export function KptAutocomplete({ options = [], value, defaultValue = '', onValu
29
46
  });
30
47
  const [open, setOpen] = useState(false);
31
48
  const [activeIndex, setActiveIndex] = useState(-1);
32
- /** Wpisano coś od ostatniego otwarcia — dopiero wtedy ogłaszamy liczbę podpowiedzi. */
49
+ /** Wpisano coś od ostatniego otwarcia - dopiero wtedy ogłaszamy liczbę podpowiedzi. */
33
50
  const [typed, setTyped] = useState(false);
34
51
  const showInvalid = invalid && (touched ?? true);
35
52
  const filtered = useMemo(() => {
@@ -55,6 +72,9 @@ export function KptAutocomplete({ options = [], value, defaultValue = '', onValu
55
72
  }, [setCurrent]);
56
73
  const handleKeyDown = (event) => {
57
74
  onKeyDown?.(event);
75
+ // Tylko do odczytu: podpowiedzi się nie otwierają, a Escape nie czyści wartości.
76
+ if (readOnly)
77
+ return;
58
78
  if (event.key === 'ArrowDown') {
59
79
  event.preventDefault();
60
80
  setOpen(true);
@@ -63,7 +83,7 @@ export function KptAutocomplete({ options = [], value, defaultValue = '', onValu
63
83
  else if (event.key === 'ArrowUp') {
64
84
  event.preventDefault();
65
85
  setOpen(true);
66
- // Z pola (bez aktywnej) `↑` idzie na ostatnią podpowiedź.
86
+ // Z pola (bez aktywnej) `ArrowUp` idzie na ostatnią podpowiedź.
67
87
  setActiveIndex((index) => (index <= 0 ? filtered.length - 1 : index - 1));
68
88
  }
69
89
  else if (event.key === 'Enter') {
@@ -86,20 +106,21 @@ export function KptAutocomplete({ options = [], value, defaultValue = '', onValu
86
106
  }
87
107
  }
88
108
  };
89
- return (_jsxs("span", { className: "kpt-autocomplete-host", children: [_jsx("input", { ref: composeRefs(inputRef, ref), className: cn('kpt-autocomplete__input', className), type: "text", id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), role: "combobox", "aria-autocomplete": "list", autoComplete: "off", "aria-expanded": panelOpen, "aria-controls": panelOpen ? listId : undefined, "aria-activedescendant": activeOptionId, "aria-invalid": showInvalid || undefined, disabled: disabled, value: current, onChange: (event) => {
109
+ return (_jsxs("span", { className: "kpt-autocomplete-host", "data-speech": speechState, children: [_jsx("input", { ref: setRefs, className: cn('kpt-autocomplete__input', className), type: "text", id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), role: "combobox", "aria-autocomplete": "list", autoComplete: "off", "aria-expanded": panelOpen, "aria-controls": panelOpen ? listId : undefined, "aria-activedescendant": activeOptionId, "aria-invalid": showInvalid || undefined, "aria-readonly": readOnly || undefined, disabled: disabled, readOnly: readOnly, value: current, onChange: (event) => {
90
110
  setCurrent(event.target.value);
91
111
  setOpen(true);
92
112
  setTyped(true);
93
113
  setActiveIndex(-1);
94
114
  }, onFocus: (event) => {
95
115
  onFocus?.(event);
96
- setOpen(true);
116
+ if (!readOnly)
117
+ setOpen(true);
97
118
  }, onBlur: (event) => {
98
119
  onBlur?.(event);
99
120
  setOpen(false);
100
121
  setTyped(false);
101
122
  onTouch?.();
102
- }, onKeyDown: handleKeyDown, ...rest }), _jsx(KptOverlay, { open: panelOpen, anchor: inputRef.current, onClose: () => setOpen(false), matchAnchorWidth: true, withBackdrop: false, children: _jsx("ul", { className: "kpt-autocomplete__panel", role: "listbox", id: listId, "aria-label": rest['aria-label'], children: filtered.map((option, index) => (_jsx("li", { id: optionId(index), className: cn('kpt-autocomplete__option', index === activeIndex && 'is-active'), role: "option", "aria-selected": index === activeIndex,
123
+ }, onKeyDown: handleKeyDown, ...rest }), speech ? (_jsx(KptSpeechButton, { listeningColor: speechColor, speech: mic, size: "sm", unsupported: "hide", disabled: disabled || readOnly, hostProps: { className: 'kpt-autocomplete__speech' } })) : null, _jsx(KptOverlay, { open: panelOpen, anchor: anchor, onClose: () => setOpen(false), matchAnchorWidth: true, withBackdrop: false, children: _jsx("ul", { className: "kpt-autocomplete__panel", role: "listbox", id: listId, "aria-label": rest['aria-label'], children: filtered.map((option, index) => (_jsx("li", { id: optionId(index), className: cn('kpt-autocomplete__option', index === activeIndex && 'is-active'), role: "option", "aria-selected": index === activeIndex,
103
124
  // `mousedown` z zablokowanym domyślnym zachowaniem: klik w opcję nie może
104
125
  // zabrać fokusu polu, bo `blur` zamknąłby panel przed wyborem.
105
126
  onMouseDown: (event) => {
@@ -12,14 +12,14 @@ A text field with suggestions. Import: `import { KptAutocomplete } from '@konce-
12
12
  </ul>
13
13
 
14
14
  ## Props
15
- - `options`: string[] — the suggestions
16
- - `value` / `defaultValue` / `onValueChange` — the typed text
15
+ - `options`: string[] - the suggestions
16
+ - `value` / `defaultValue` / `onValueChange` - the typed text
17
17
  - `invalid`, `touched`, `onTouch()`
18
18
  - `className`, `ref` and every other `<input>` prop go to the input
19
19
 
20
20
  ## The value is the text, not the option
21
21
  Whatever is typed becomes the value; the suggestions only shorten the typing. That makes the field
22
- usable for values outside the list — a city nobody put in `options` still submits. When the value
22
+ usable for values outside the list - a city nobody put in `options` still submits. When the value
23
23
  must come from the list, reach for `KptSelect` instead.
24
24
 
25
25
  ## No backdrop
@@ -33,13 +33,13 @@ ArrowDown opens the list and moves the active option, ArrowUp moves back, Enter
33
33
  one, Escape closes.
34
34
 
35
35
  ## Examples
36
- <KptAutocomplete options={cities} value={city} onValueChange={setCity} placeholder="City…" />
36
+ <KptAutocomplete options={cities} value={city} onValueChange={setCity} placeholder="City..." />
37
37
 
38
38
  ## Screen reader and keyboard
39
39
  The WAI-ARIA combobox-with-list pattern: focus stays in the field, `aria-autocomplete="list"`,
40
40
  `aria-controls` and `aria-activedescendant` point at the active suggestion, and a polite live region
41
41
  says how many suggestions there are (`autocomplete.results`) or that there are none
42
- (`autocomplete.noResults`). Matching ignores case and diacritics ("lodz" finds "Łódź"). `↑` from the
42
+ (`autocomplete.noResults`). Matching ignores case and diacritics ("lodz" finds "Łódź"). `ArrowUp` from the
43
43
  field goes to the last suggestion; the first `Escape` closes the list, the second clears the field.
44
44
 
45
45
  ## Label and description
@@ -54,3 +54,17 @@ added to `aria-describedby` (merged with your own). Without a wrapper, name it w
54
54
  ## Accessibility
55
55
  The input is `role="combobox"` with `aria-expanded`; the panel is `role="listbox"` with
56
56
  `role="option"` rows carrying `aria-selected`.
57
+
58
+ ## Read-only and required
59
+ `readOnly` is the native read-only field with `aria-readonly`; the suggestions do not open and Escape does not clear the value.
60
+
61
+ ## Dictation
62
+ - `speech`: boolean = false - a microphone at the end of the field (`KptSpeechButton`). Hidden without
63
+ browser support.
64
+ - `speechLang`: string - BCP 47 tag; without it from `KptI18nProvider`.
65
+ - `speechColor`: `'primary' | 'danger' | 'success' | 'warning' | 'info'` = `'primary'` - colour of "stop" and the wave while listening.
66
+ - `speechMode`: `'insert' | 'append' | 'replace'` = `'replace'` - the field picks one value, so a click
67
+ clears it and one utterance replaces it; the suggestion list opens for the spoken text like for typed
68
+ text. Interim words are visible but do not filter the list - only final text reaches the state.
69
+
70
+ <KptAutocomplete options={cities} value={city} onValueChange={setCity} speech />
@@ -5,7 +5,7 @@ export type KptAvatarShape = 'circle' | 'square';
5
5
  export interface KptAvatarProps extends Omit<ComponentPropsWithRef<'span'>, 'children'> {
6
6
  /** Adres obrazu; ma pierwszeństwo przed inicjałami i ikoną. */
7
7
  src?: string | null;
8
- /** Imię i nazwisko — źródło inicjałów, `title` oraz etykiety dostępności. */
8
+ /** Imię i nazwisko - źródło inicjałów, `title` oraz etykiety dostępności. */
9
9
  name?: string;
10
10
  /** Nazwa ikony z rejestru, gdy nie ma obrazu ani nazwy. */
11
11
  icon?: string | null;
@@ -15,17 +15,17 @@ export interface KptAvatarProps extends Omit<ComponentPropsWithRef<'span'>, 'chi
15
15
  decorative?: boolean;
16
16
  /**
17
17
  * Propsy wrappera hosta (`.kpt-avatar-host`). To on jest elementem układu, więc klasy
18
- * pozycjonujące awatar w rodzicu — jak `kpt-card__avatar` — idą właśnie tutaj.
18
+ * pozycjonujące awatar w rodzicu - jak `kpt-card__avatar` - idą właśnie tutaj.
19
19
  */
20
20
  hostProps?: KptHostProps<'span'>;
21
21
  }
22
22
  /**
23
- * Awatar — obraz, inicjały (z `name`) lub ikona.
23
+ * Awatar - obraz, inicjały (z `name`) lub ikona.
24
24
  *
25
- * `name` trafia do natywnego `title` (podpowiedź spod kursora — inicjały same w sobie nie mówią,
25
+ * `name` trafia do natywnego `title` (podpowiedź spod kursora - inicjały same w sobie nie mówią,
26
26
  * kto to jest). Bez `src` awatar dostaje dodatkowo `role="img"` i `aria-label`, a same inicjały
27
- * są `aria-hidden`, żeby czytnik nie przeczytał „AK" litera po literze. Przy `src` etykietę
28
- * niesie już `alt` obrazu — nie dublujemy jej.
27
+ * są `aria-hidden`, żeby czytnik nie przeczytał "AK" litera po literze. Przy `src` etykietę
28
+ * niesie już `alt` obrazu - nie dublujemy jej.
29
29
  *
30
30
  * @example
31
31
  * <KptAvatar src="/u/anna.jpg" />
@@ -1,14 +1,15 @@
1
+ 'use client';
1
2
  import { jsx as _jsx } from "react/jsx-runtime";
2
3
  import { useState } from 'react';
3
4
  import { cn } from "../internal/cn.js";
4
5
  import { KptIcon } from "../icon/icon.js";
5
6
  /**
6
- * Awatar — obraz, inicjały (z `name`) lub ikona.
7
+ * Awatar - obraz, inicjały (z `name`) lub ikona.
7
8
  *
8
- * `name` trafia do natywnego `title` (podpowiedź spod kursora — inicjały same w sobie nie mówią,
9
+ * `name` trafia do natywnego `title` (podpowiedź spod kursora - inicjały same w sobie nie mówią,
9
10
  * kto to jest). Bez `src` awatar dostaje dodatkowo `role="img"` i `aria-label`, a same inicjały
10
- * są `aria-hidden`, żeby czytnik nie przeczytał „AK" litera po literze. Przy `src` etykietę
11
- * niesie już `alt` obrazu — nie dublujemy jej.
11
+ * są `aria-hidden`, żeby czytnik nie przeczytał "AK" litera po literze. Przy `src` etykietę
12
+ * niesie już `alt` obrazu - nie dublujemy jej.
12
13
  *
13
14
  * @example
14
15
  * <KptAvatar src="/u/anna.jpg" />
@@ -17,7 +18,7 @@ import { KptIcon } from "../icon/icon.js";
17
18
  */
18
19
  export function KptAvatar({ src = null, name = '', icon = null, size = 'md', shape = 'circle', decorative = false, hostProps, className, ...rest }) {
19
20
  const { className: hostClassName, ...hostRest } = hostProps ?? {};
20
- // Zdjęcie, które się nie wczytało — awatar wraca wtedy do inicjałów (albo ikony). Pamiętamy,
21
+ // Zdjęcie, które się nie wczytało - awatar wraca wtedy do inicjałów (albo ikony). Pamiętamy,
21
22
  // którego `src` dotyczy błąd, więc nowy adres próbuje się wczytać od nowa.
22
23
  const [brokenSrc, setBrokenSrc] = useState(null);
23
24
  const showImage = !!src && brokenSrc !== src;
@@ -1,32 +1,32 @@
1
1
  # KptAvatar (@konce-pt/react)
2
2
 
3
- An avatar — a photo, initials (from `name`) or an icon.
3
+ An avatar - a photo, initials (from `name`) or an icon.
4
4
  Import: `import { KptAvatar } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <span class="kpt-avatar-host">
8
8
  <span class="kpt-avatar" data-size="md" data-shape="circle" title="Anna Kowalska">
9
- <img class="kpt-avatar__img" src="…" alt="Anna Kowalska">
9
+ <img class="kpt-avatar__img" src="..." alt="Anna Kowalska">
10
10
  </span>
11
11
  </span>
12
12
 
13
13
  ## Props
14
- - `src`: string | null — a photo; it wins over initials and the icon
15
- - `name`: string — the source of the initials, the `title` and the accessible label
16
- - `icon`: string | null — a registry icon name, used when there is neither photo nor name
14
+ - `src`: string | null - a photo; it wins over initials and the icon
15
+ - `name`: string - the source of the initials, the `title` and the accessible label
16
+ - `icon`: string | null - a registry icon name, used when there is neither photo nor name
17
17
  - `size`: 'sm' | 'md' | 'lg' | 'xl' (default 'md')
18
18
  - `shape`: 'circle' | 'square' (default 'circle')
19
- - `decorative`: boolean — hides the avatar from screen readers (the name is written next to it)
20
- - `hostProps` — props for the `.kpt-avatar-host` wrapper
19
+ - `decorative`: boolean - hides the avatar from screen readers (the name is written next to it)
20
+ - `hostProps` - props for the `.kpt-avatar-host` wrapper
21
21
  - `className`, `ref` and every other `<span>` prop go to the inner `.kpt-avatar`
22
22
 
23
23
  ## Fallback order
24
- `src` → `name` (up to two initials, uppercased) → `icon`. A photo that fails to load drops to the
24
+ `src` -> `name` (up to two initials, uppercased) -> `icon`. A photo that fails to load drops to the
25
25
  next step by itself, and a new `src` is tried again. With none of them the avatar renders as an
26
26
  empty shape, which is a valid placeholder.
27
27
 
28
28
  ## Positioning inside a parent
29
- The host is the layout element, so classes that place the avatar in its parent go to `hostProps` —
29
+ The host is the layout element, so classes that place the avatar in its parent go to `hostProps` -
30
30
  the overlapping avatar on a card is `hostProps={{ className: 'kpt-card__avatar' }}`.
31
31
 
32
32
  ## Examples
@@ -42,5 +42,5 @@ the overlapping avatar on a card is `hostProps={{ className: 'kpt-card__avatar'
42
42
  `name` goes into the native `title` (initials alone say nothing). With a photo the name is the
43
43
  image's `alt`; without one the avatar is `role="img"` with `aria-label`, and the initials are
44
44
  `aria-hidden`. A photo that fails to load falls back to the initials (or the icon); a new `src` is
45
- tried again. `decorative` removes the avatar from the accessibility tree — use it when the name is
45
+ tried again. `decorative` removes the avatar from the accessibility tree - use it when the name is
46
46
  already written next to it.
@@ -8,15 +8,15 @@ export interface KptAvatarItem {
8
8
  }
9
9
  export interface KptAvatarGroupProps extends ComponentPropsWithRef<'div'>, KptI18nOverrides {
10
10
  avatars?: readonly KptAvatarItem[];
11
- /** Ile awatarów pokazać, zanim pojawi się „+N". */
11
+ /** Ile awatarów pokazać, zanim pojawi się "+N". */
12
12
  max?: number;
13
13
  size?: KptAvatarSize;
14
- /** Nazwa grupy dla czytników ekranu, np. „Członkowie projektu”; bez niej grupa nie ma roli. */
14
+ /** Nazwa grupy dla czytników ekranu, np. "Członkowie projektu"; bez niej grupa nie ma roli. */
15
15
  label?: string;
16
16
  }
17
17
  /**
18
- * Grupa nakładających się awatarów z licznikiem „+N". Buduje na `KptAvatar`, więc każdy element
19
- * dziedziczy jego `title` z imieniem — inicjały same w sobie nie mówią, kto to jest.
18
+ * Grupa nakładających się awatarów z licznikiem "+N". Buduje na `KptAvatar`, więc każdy element
19
+ * dziedziczy jego `title` z imieniem - inicjały same w sobie nie mówią, kto to jest.
20
20
  *
21
21
  * @example
22
22
  * <KptAvatarGroup avatars={team} max={4} />
@@ -1,10 +1,11 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { cn } from "../internal/cn.js";
3
4
  import { useKptMessages } from "../i18n/i18n-context.js";
4
5
  import { KptAvatar } from "../avatar/avatar.js";
5
6
  /**
6
- * Grupa nakładających się awatarów z licznikiem „+N". Buduje na `KptAvatar`, więc każdy element
7
- * dziedziczy jego `title` z imieniem — inicjały same w sobie nie mówią, kto to jest.
7
+ * Grupa nakładających się awatarów z licznikiem "+N". Buduje na `KptAvatar`, więc każdy element
8
+ * dziedziczy jego `title` z imieniem - inicjały same w sobie nie mówią, kto to jest.
8
9
  *
9
10
  * @example
10
11
  * <KptAvatarGroup avatars={team} max={4} />
@@ -13,7 +14,7 @@ export function KptAvatarGroup({ avatars = [], max = 4, size = 'md', label = '',
13
14
  const { t } = useKptMessages({ locale, dictionary });
14
15
  const shown = avatars.slice(0, max);
15
16
  const overflow = Math.max(0, avatars.length - max);
16
- // Sam „+2” nic czytnikowi nie mówi — licznik ma nazwę „i 2 więcej” i podpowiedź z imionami.
17
+ // Sam "+2" nic czytnikowi nie mówi - licznik ma nazwę "i 2 więcej" i podpowiedź z imionami.
17
18
  const hiddenNames = avatars
18
19
  .slice(max)
19
20
  .map((avatar) => avatar.name)
@@ -6,22 +6,22 @@ Import: `import { KptAvatarGroup } from '@konce-pt/react';`
6
6
  ## DOM
7
7
  <div class="kpt-avatar-group-host">
8
8
  <div class="kpt-avatar-group" data-size="lg" role="group" aria-label="Project members">
9
- <span class="kpt-avatar-group__item">…KptAvatar…</span>…
9
+ <span class="kpt-avatar-group__item">...KptAvatar...</span>...
10
10
  <span class="kpt-avatar-group__item kpt-avatar-group__more" role="img" data-size="lg"
11
11
  aria-label="2 more" title="Marta, Tomasz"><span aria-hidden="true">+2</span></span>
12
12
  </div>
13
13
  </div>
14
14
 
15
15
  ## Props
16
- - `avatars`: `KptAvatarItem[]` — `{ name?, src?, icon? }`
17
- - `max`: number (default 4) — how many to show before "+N"
16
+ - `avatars`: `KptAvatarItem[]` - `{ name?, src?, icon? }`
17
+ - `max`: number (default 4) - how many to show before "+N"
18
18
  - `size`: `'sm' | 'md' | 'lg' | 'xl'`
19
- - `label`: string — the group's name; with it the row is `role="group"`
19
+ - `label`: string - the group's name; with it the row is `role="group"`
20
20
  - `className`, `ref` and every other `<div>` prop go to the host
21
21
 
22
22
  ## One list, three fallbacks
23
- Each entry falls back in order: `src` (a photo) → `name` (initials) → `icon`. A team where only
24
- some people have a photo therefore needs no branching at the call site — which is exactly the
23
+ Each entry falls back in order: `src` (a photo) -> `name` (initials) -> `icon`. A team where only
24
+ some people have a photo therefore needs no branching at the call site - which is exactly the
25
25
  common case.
26
26
 
27
27
  ## The name survives the overlap
@@ -36,6 +36,6 @@ Every avatar keeps the `title` from `KptAvatar`, so hovering tells you who it is
36
36
  The overlap ring uses `--kpt-color-surface`, the "+N" chip `--kpt-color-muted`.
37
37
 
38
38
  ## Accessibility
39
- Every avatar keeps its own name. With `label` the row is `role="group"` with that name. The “+N”
40
- counter is `role="img"` named from `avatarGroup.more` (`{count}` — “2 more”), with the hidden names
39
+ Every avatar keeps its own name. With `label` the row is `role="group"` with that name. The "+N"
40
+ counter is `role="img"` named from `avatarGroup.more` (`{count}` - "2 more"), with the hidden names
41
41
  in its `title`. The overlap uses `margin-inline-start`, so it mirrors in RTL.
@@ -8,22 +8,22 @@ export interface KptBackdropProps extends ComponentPropsWithRef<'div'> {
8
8
  background?: string;
9
9
  /** Tempo; 1 to spokojne tempo obu efektów, 0 zatrzymuje obraz. */
10
10
  speed?: number;
11
- /** Ziarno losowania — ta sama wartość daje ten sam układ kwadratów i ten sam przebieg wstęgi. */
11
+ /** Ziarno losowania - ta sama wartość daje ten sam układ kwadratów i ten sam przebieg wstęgi. */
12
12
  seed?: number;
13
13
  /** Zatrzymuje animację, zostawiając ostatnią klatkę. */
14
14
  paused?: boolean;
15
15
  /**
16
16
  * Przenosi barwy wpisane na sztywno na powierzchnię bieżącego motywu: czerń dobrana do białego
17
- * tła staje się bielą, gdy tło jest ciemne. Rusza wyłącznie jasność — odcień i nasycenie
17
+ * tła staje się bielą, gdy tło jest ciemne. Rusza wyłącznie jasność - odcień i nasycenie
18
18
  * zostają, więc barwa marki nie zmienia się w inną barwę.
19
19
  *
20
20
  * Dotyczy `color`, `colors` i `background`, ale tylko wtedy, gdy podano je literałem. Prop pusty
21
- * bierze token, a zapis z `var()` sam po token sięga — jedno i drugie już idzie za motywem
21
+ * bierze token, a zapis z `var()` sam po token sięga - jedno i drugie już idzie za motywem
22
22
  * i adaptacja odwróciłaby je drugi raz.
23
23
  */
24
24
  adaptive?: boolean;
25
25
  /**
26
- * `signal-grid`: kolor kwadratów — dowolny zapis CSS, także sięgający po tokeny, np.
26
+ * `signal-grid`: kolor kwadratów - dowolny zapis CSS, także sięgający po tokeny, np.
27
27
  * `color-mix(in oklab, #5b8af2, var(--kpt-color-surface) 30%)`. Taki zapis przelicza się przy
28
28
  * zmianie motywu; literał zostaje literałem. Puste bierze `--kpt-color-primary`.
29
29
  */
@@ -34,14 +34,14 @@ export interface KptBackdropProps extends ComponentPropsWithRef<'div'> {
34
34
  cell?: number;
35
35
  /** `signal-grid`: odstęp między kwadratami (px). */
36
36
  gap?: number;
37
- /** `signal-grid`: udział zapalonych komórek przy kotwicy, 0–1. */
37
+ /** `signal-grid`: udział zapalonych komórek przy kotwicy, 0-1. */
38
38
  density?: number;
39
39
  /** `signal-grid`: jak szybko siatka gaśnie ku przeciwnej krawędzi. */
40
40
  falloff?: number;
41
41
  /**
42
- * `wave`: rampa barw, po której przesuwa się wstęga — każdy przystanek dowolnym zapisem CSS.
42
+ * `wave`: rampa barw, po której przesuwa się wstęga - każdy przystanek dowolnym zapisem CSS.
43
43
  * Zamknięta w pętlę, więc ostatnia barwa wraca do pierwszej. Pusta bierze `--kpt-color-primary`
44
- * i dwie barwy wyprowadzone z niego obrotem odcienia — paleta biblioteki jest neutralna, więc
44
+ * i dwie barwy wyprowadzone z niego obrotem odcienia - paleta biblioteki jest neutralna, więc
45
45
  * domyślna wstęga jest jednobarwna i przygaszona. Po kolory sięga się tu, nie do tokenów
46
46
  * statusowych. Zapis może sięgać po tokeny i wtedy idzie za motywem. Przystanek, którego
47
47
  * przeglądarka nie uznaje za kolor, wypada z rampy; gdy wypadną wszystkie, zostaje rampa
@@ -57,23 +57,4 @@ export interface KptBackdropProps extends ComponentPropsWithRef<'div'> {
57
57
  /** Propsy warstwy z treścią (`.kpt-backdrop__content`). */
58
58
  contentProps?: ComponentPropsWithRef<'div'>;
59
59
  }
60
- /**
61
- * Dekoracyjna warstwa tła dla sekcji: komponent obejmuje treść i maluje pod nią animowany canvas.
62
- * Sięga się po niego tam, gdzie płaska powierzchnia wygląda na niedokończoną, a wideo albo duży
63
- * obraz kosztowałyby transfer i nie poszłyby za motywem.
64
- *
65
- * Komponent jest opakowaniem: canvas leży pod spodem, a dzieci idą warstwę wyżej i zachowują się
66
- * zwyczajnie. Rysowanie stoi, gdy nie ma czego oglądać — sekcja poza ekranem, karta w tle,
67
- * `paused`, `speed` równe zeru albo ograniczony ruch w systemie; wtedy zostaje jedna statyczna
68
- * klatka zamiast pustki, bo efekt jest częścią kompozycji, nie ozdobą.
69
- *
70
- * Rysowanie i cała matematyka siedzą w `@konce-pt/backdrop`, wspólnym z portem Angulara —
71
- * ten komponent to sam cykl życia.
72
- *
73
- * @example
74
- * <KptBackdrop effect="wave" rotation={18} colors={['#5b8af2', '#a86df2', '#f25b9e']}>
75
- * <h1>Build your app from the first prompt</h1>
76
- * <KptButton>Get started</KptButton>
77
- * </KptBackdrop>
78
- */
79
60
  export declare function KptBackdrop({ effect, background, speed, seed, paused, adaptive, color, anchor, cell, gap, density, falloff, colors, rotation, band, amplitude, contentProps, className, style, children, ...rest }: Readonly<KptBackdropProps>): import("react").JSX.Element;
@@ -1,5 +1,6 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
3
4
  import { KPT_BACKDROP_MAX_DPR, KPT_BACKDROP_MAX_STEP, KPT_SIGNAL_GRID_CELL, KPT_SIGNAL_GRID_DENSITY, KPT_SIGNAL_GRID_FALLOFF, KPT_SIGNAL_GRID_GAP, KPT_WAVE_AMPLITUDE, KPT_WAVE_BAND, KPT_WAVE_ROTATION, adaptBackdropValue, createBackdropRenderer, observeBackdropTheme, readBackdropInk, readBackdropLead, readBackdropSurface, resolveBackdropColors, } from '@konce-pt/backdrop';
4
5
  import { cn } from "../internal/cn.js";
5
6
  import { isDevBuild } from "../internal/dev.js";
@@ -10,11 +11,11 @@ const EMPTY = [];
10
11
  * obraz kosztowałyby transfer i nie poszłyby za motywem.
11
12
  *
12
13
  * Komponent jest opakowaniem: canvas leży pod spodem, a dzieci idą warstwę wyżej i zachowują się
13
- * zwyczajnie. Rysowanie stoi, gdy nie ma czego oglądać — sekcja poza ekranem, karta w tle,
14
+ * zwyczajnie. Rysowanie stoi, gdy nie ma czego oglądać - sekcja poza ekranem, karta w tle,
14
15
  * `paused`, `speed` równe zeru albo ograniczony ruch w systemie; wtedy zostaje jedna statyczna
15
16
  * klatka zamiast pustki, bo efekt jest częścią kompozycji, nie ozdobą.
16
17
  *
17
- * Rysowanie i cała matematyka siedzą w `@konce-pt/backdrop`, wspólnym z portem Angulara —
18
+ * Rysowanie i cała matematyka siedzą w `@konce-pt/backdrop`, wspólnym z portem Angulara -
18
19
  * ten komponent to sam cykl życia.
19
20
  *
20
21
  * @example
@@ -23,29 +24,39 @@ const EMPTY = [];
23
24
  * <KptButton>Get started</KptButton>
24
25
  * </KptBackdrop>
25
26
  */
27
+ const REDUCED_MOTION = '(prefers-reduced-motion: reduce)';
28
+ /** `prefers-reduced-motion` jako zewnętrzny magazyn - bez `setState` w efekcie i bez mignięcia ruchu. */
29
+ function subscribeReducedMotion(onChange) {
30
+ if (typeof matchMedia === 'undefined')
31
+ return () => undefined;
32
+ const query = matchMedia(REDUCED_MOTION);
33
+ query.addEventListener('change', onChange);
34
+ return () => query.removeEventListener('change', onChange);
35
+ }
36
+ function readReducedMotion() {
37
+ return typeof matchMedia !== 'undefined' && matchMedia(REDUCED_MOTION).matches;
38
+ }
26
39
  export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1, seed = 0, paused = false, adaptive = false, color = '', anchor = 'right', cell = KPT_SIGNAL_GRID_CELL, gap = KPT_SIGNAL_GRID_GAP, density = KPT_SIGNAL_GRID_DENSITY, falloff = KPT_SIGNAL_GRID_FALLOFF, colors = EMPTY, rotation = KPT_WAVE_ROTATION, band = KPT_WAVE_BAND, amplitude = KPT_WAVE_AMPLITUDE, contentProps, className, style, children, ...rest }) {
27
40
  const host = useRef(null);
28
41
  const canvas = useRef(null);
29
42
  const context = useRef(null);
30
43
  const renderer = useRef(null);
31
44
  const size = useRef({ width: 0, height: 0 });
32
- /** Zegar animacji w sekundach — w refie, żeby przebudowa renderera nie cofała obrazu. */
45
+ /** Zegar animacji w sekundach - w refie, żeby przebudowa renderera nie cofała obrazu. */
33
46
  const clock = useRef(0);
34
- /** Kolor wiodący, z którym zbudowany jest bieżący renderer — punkt odniesienia dla zmiany motywu. */
47
+ /** Kolor wiodący, z którym zbudowany jest bieżący renderer - punkt odniesienia dla zmiany motywu. */
35
48
  const lead = useRef('');
36
- /** Ostatnio zgłoszony zestaw odrzuconych barw — żeby nie powtarzać tego samego ostrzeżenia. */
49
+ /** Ostatnio zgłoszony zestaw odrzuconych barw - żeby nie powtarzać tego samego ostrzeżenia. */
37
50
  const reported = useRef('');
38
- /** Tło po adaptacji. Puste znaczy „nie ma czego podmieniać" i wtedy liczy się samo `background`. */
51
+ /** Tło po adaptacji. Puste znaczy "nie ma czego podmieniać" i wtedy liczy się samo `background`. */
39
52
  const [adapted, setAdapted] = useState('');
40
53
  /**
41
- * Ton i kolor treści dobrane do malowanego tła. Puste znaczy „sekcja nie ma własnego tła"
54
+ * Ton i kolor treści dobrane do malowanego tła. Puste znaczy "sekcja nie ma własnego tła"
42
55
  * i wtedy treść zostaje przy `--kpt-color-on-surface` ze stylu.
43
56
  */
44
57
  const [ink, setInk] = useState({ tone: '', color: '' });
45
- const rate = useRef(speed);
46
- rate.current = speed;
47
58
  const [onScreen, setOnScreen] = useState(true);
48
- const [reduced, setReduced] = useState(false);
59
+ const reduced = useSyncExternalStore(subscribeReducedMotion, readReducedMotion, () => false);
49
60
  /** Licznik zmian motywu; podbicie każe przeliczyć kolory z tokenów na nowo. */
50
61
  const [theme, setTheme] = useState(0);
51
62
  const paint = useCallback(() => {
@@ -70,10 +81,10 @@ export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1
70
81
  // Tablica barw przychodzi nowa przy każdym renderze rodzica, więc do zależności idzie jej treść.
71
82
  const ramp = colors.join('|');
72
83
  const list = useMemo(() => (ramp === '' ? EMPTY : ramp.split('|')), [ramp]);
73
- // Każda zmiana wejść buduje renderer od nowa — zamiast doklejać ścieżki „co się zmieniło".
84
+ // Każda zmiana wejść buduje renderer od nowa - zamiast doklejać ścieżki "co się zmieniło".
74
85
  useEffect(() => {
75
86
  // Kolory rozwiązuje się na canvasie, nie na hoście: sonda `var()` pisze inline style, a nasłuch
76
- // motywu ogląda `style` hosta i jego przodków — zapis na hoście zapętliłby przebudowy.
87
+ // motywu ogląda `style` hosta i jego przodków - zapis na hoście zapętliłby przebudowy.
77
88
  const scope = canvas.current;
78
89
  if (!scope)
79
90
  return undefined;
@@ -82,10 +93,10 @@ export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1
82
93
  lead.current = resolved.color;
83
94
  const painted = adaptive ? adaptBackdropValue(background, readBackdropSurface(scope)) : background;
84
95
  setAdapted(adaptive ? painted : '');
85
- // Ton liczymy z tła, które sekcja naprawdę pomaluje — czyli już po adaptacji.
96
+ // Ton liczymy z tła, które sekcja naprawdę pomaluje - czyli już po adaptacji.
86
97
  setInk(readBackdropInk(scope, painted));
87
98
  // Efekt chodzi przy każdej zmianie wejść, więc ciągnięcie suwaka nad wadliwą rampą zasypałoby
88
- // konsolę tym samym zdaniem — zgłaszamy dopiero zestaw inny niż poprzednio.
99
+ // konsolę tym samym zdaniem - zgłaszamy dopiero zestaw inny niż poprzednio.
89
100
  const rejected = resolved.invalid.join(', ');
90
101
  if (rejected !== reported.current) {
91
102
  reported.current = rejected;
@@ -115,7 +126,7 @@ export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1
115
126
  renderer.current = null;
116
127
  };
117
128
  }, [effect, color, list, anchor, cell, gap, density, falloff, rotation, band, amplitude, seed, adaptive, background, theme, measure, paint]);
118
- // Sam rozmiar nie zmienia ustawień, więc renderer zostaje — przelicza tylko geometrię.
129
+ // Sam rozmiar nie zmienia ustawień, więc renderer zostaje - przelicza tylko geometrię.
119
130
  useEffect(() => {
120
131
  const element = canvas.current;
121
132
  if (!element)
@@ -146,14 +157,7 @@ export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1
146
157
  document.removeEventListener('visibilitychange', onTabSwitch);
147
158
  };
148
159
  }, []);
149
- useEffect(() => {
150
- const query = matchMedia('(prefers-reduced-motion: reduce)');
151
- setReduced(query.matches);
152
- const onChange = (event) => setReduced(event.matches);
153
- query.addEventListener('change', onChange);
154
- return () => query.removeEventListener('change', onChange);
155
- }, []);
156
- // Zmiana motywu przestawia tokeny, a kolory renderera są już wyliczone — trzeba je odczytać
160
+ // Zmiana motywu przestawia tokeny, a kolory renderera są już wyliczone - trzeba je odczytać
157
161
  // na nowo. Nasłuch trafia też w zmiany niezwiązane z barwą, więc licznik podbija się dopiero
158
162
  // wtedy, gdy odczyt naprawdę dał inny kolor.
159
163
  useEffect(() => {
@@ -164,7 +168,7 @@ export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1
164
168
  const scope = canvas.current;
165
169
  if (!scope)
166
170
  return;
167
- // Ten sam rachunek co w efekcie budującym — inaczej strażnik porównywałby wartość sprzed
171
+ // Ten sam rachunek co w efekcie budującym - inaczej strażnik porównywałby wartość sprzed
168
172
  // adaptacji z zapamiętaną po adaptacji i podbijałby licznik bez przerwy.
169
173
  const next = adaptive ? adaptBackdropValue(color, readBackdropSurface(scope)) : color;
170
174
  if (readBackdropLead(scope, next) === lead.current)
@@ -180,8 +184,9 @@ export function KptBackdrop({ effect = 'signal-grid', background = '', speed = 1
180
184
  const tick = (now) => {
181
185
  const step = last === 0 ? 0 : Math.min(now - last, KPT_BACKDROP_MAX_STEP);
182
186
  last = now;
183
- // Prędkość wchodzi w zegar, nie w fazę — suwak przyspiesza obraz zamiast go przeskakiwać.
184
- clock.current += (step / 1000) * rate.current;
187
+ // Prędkość wchodzi w zegar, nie w fazę - suwak przyspiesza obraz zamiast go przeskakiwać. Pętla
188
+ // restartuje się przy zmianie `speed` (zależność efektu), a zegar żyje w refie, więc nic nie skacze.
189
+ clock.current += (step / 1000) * speed;
185
190
  paint();
186
191
  frame = requestAnimationFrame(tick);
187
192
  };