@konce-pt/react 0.12.0 → 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 (378) hide show
  1. package/README.md +122 -64
  2. package/dist/accordion/accordion.d.ts +14 -6
  3. package/dist/accordion/accordion.js +14 -7
  4. package/dist/accordion/llms.txt +22 -10
  5. package/dist/alert/alert.d.ts +2 -2
  6. package/dist/alert/alert.js +2 -2
  7. package/dist/alert/llms.txt +10 -10
  8. package/dist/app-shell/app-shell.d.ts +14 -14
  9. package/dist/app-shell/app-shell.js +11 -11
  10. package/dist/app-shell/llms.txt +13 -13
  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 +7 -7
  14. package/dist/auth/llms.txt +9 -9
  15. package/dist/autocomplete/autocomplete.d.ts +19 -6
  16. package/dist/autocomplete/autocomplete.js +23 -10
  17. package/dist/autocomplete/llms.txt +16 -5
  18. package/dist/avatar/avatar.d.ts +6 -6
  19. package/dist/avatar/avatar.js +5 -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 +3 -3
  23. package/dist/avatar-group/llms.txt +8 -8
  24. package/dist/backdrop/backdrop.d.ts +7 -7
  25. package/dist/backdrop/backdrop.js +16 -16
  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 +4 -4
  31. package/dist/bottom-sheet/bottom-sheet.js +2 -2
  32. package/dist/bottom-sheet/llms.txt +9 -9
  33. package/dist/breadcrumb/breadcrumb.d.ts +2 -2
  34. package/dist/breadcrumb/breadcrumb.js +3 -3
  35. package/dist/breadcrumb/llms.txt +3 -3
  36. package/dist/button/button.d.ts +3 -3
  37. package/dist/button/button.js +8 -8
  38. package/dist/button/llms.txt +27 -19
  39. package/dist/button-group/button-group.d.ts +9 -9
  40. package/dist/button-group/button-group.js +30 -8
  41. package/dist/button-group/llms.txt +20 -14
  42. package/dist/card/card.d.ts +8 -8
  43. package/dist/card/card.js +6 -6
  44. package/dist/card/llms.txt +20 -20
  45. package/dist/carousel/carousel.d.ts +6 -6
  46. package/dist/carousel/carousel.js +4 -4
  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 +1 -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 +1 -1
  53. package/dist/charts/chart.js +8 -8
  54. package/dist/charts/llms.txt +6 -6
  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 +42 -18
  58. package/dist/chat/llms.txt +32 -17
  59. package/dist/chat-composer/chat-composer.d.ts +17 -7
  60. package/dist/chat-composer/chat-composer.js +21 -8
  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 +9 -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 +17 -7
  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 +3 -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 +26 -7
  74. package/dist/checkbox/llms.txt +24 -12
  75. package/dist/chip/chip.d.ts +4 -4
  76. package/dist/chip/chip.js +2 -2
  77. package/dist/chip/llms.txt +11 -11
  78. package/dist/chips-input/chips-input.d.ts +4 -4
  79. package/dist/chips-input/chips-input.js +35 -9
  80. package/dist/chips-input/llms.txt +15 -8
  81. package/dist/clock/clock.d.ts +4 -4
  82. package/dist/clock/clock.js +7 -7
  83. package/dist/clock/llms.txt +8 -8
  84. package/dist/color-picker/color-picker.d.ts +6 -6
  85. package/dist/color-picker/color-picker.js +3 -3
  86. package/dist/color-picker/llms.txt +5 -5
  87. package/dist/confirm/confirm-container.d.ts +3 -3
  88. package/dist/confirm/confirm-container.js +5 -5
  89. package/dist/confirm/confirm-store.d.ts +4 -4
  90. package/dist/confirm/confirm-store.js +7 -7
  91. package/dist/confirm/llms.txt +6 -6
  92. package/dist/context-menu/context-menu.d.ts +1 -1
  93. package/dist/context-menu/context-menu.js +5 -5
  94. package/dist/context-menu/llms.txt +7 -7
  95. package/dist/data-table/data-table-types.d.ts +5 -5
  96. package/dist/data-table/data-table.d.ts +29 -8
  97. package/dist/data-table/data-table.js +340 -95
  98. package/dist/data-table/export-csv.d.ts +3 -3
  99. package/dist/data-table/export-csv.js +4 -4
  100. package/dist/data-table/llms.txt +127 -94
  101. package/dist/data-view/data-view.d.ts +13 -5
  102. package/dist/data-view/data-view.js +67 -6
  103. package/dist/data-view/llms.txt +29 -10
  104. package/dist/date-range/date-range.d.ts +9 -9
  105. package/dist/date-range/date-range.js +24 -24
  106. package/dist/date-range/llms.txt +20 -20
  107. package/dist/datepicker/datepicker.d.ts +10 -10
  108. package/dist/datepicker/datepicker.js +29 -29
  109. package/dist/datepicker/llms.txt +24 -24
  110. package/dist/dialog/dialog.d.ts +4 -4
  111. package/dist/dialog/dialog.js +4 -4
  112. package/dist/dialog/llms.txt +11 -11
  113. package/dist/divider/divider.d.ts +1 -1
  114. package/dist/divider/llms.txt +4 -4
  115. package/dist/drawer/drawer.d.ts +5 -5
  116. package/dist/drawer/drawer.js +2 -2
  117. package/dist/drawer/llms.txt +11 -11
  118. package/dist/empty/empty.d.ts +2 -2
  119. package/dist/empty/empty.js +1 -1
  120. package/dist/empty/llms.txt +9 -9
  121. package/dist/fab/fab.d.ts +1 -1
  122. package/dist/fab/fab.js +1 -1
  123. package/dist/fab/llms.txt +10 -6
  124. package/dist/fieldset/fieldset.d.ts +18 -4
  125. package/dist/fieldset/fieldset.js +9 -6
  126. package/dist/fieldset/llms.txt +26 -9
  127. package/dist/file-upload/file-upload.d.ts +3 -3
  128. package/dist/file-upload/file-upload.js +7 -7
  129. package/dist/file-upload/llms.txt +7 -7
  130. package/dist/form-field/form-field-context.d.ts +4 -4
  131. package/dist/form-field/form-field.d.ts +12 -4
  132. package/dist/form-field/form-field.js +26 -6
  133. package/dist/form-field/llms.txt +25 -11
  134. package/dist/galleria/galleria.d.ts +3 -3
  135. package/dist/galleria/galleria.js +5 -5
  136. package/dist/galleria/llms.txt +7 -7
  137. package/dist/grid/col.d.ts +4 -4
  138. package/dist/grid/col.js +2 -2
  139. package/dist/grid/flex.d.ts +3 -3
  140. package/dist/grid/flex.js +1 -1
  141. package/dist/grid/grid.d.ts +7 -7
  142. package/dist/grid/grid.js +3 -3
  143. package/dist/grid/layout.d.ts +2 -2
  144. package/dist/grid/layout.js +2 -2
  145. package/dist/grid/llms.txt +15 -15
  146. package/dist/grid-entry/public-api.js +1 -1
  147. package/dist/i18n/i18n-context.d.ts +3 -3
  148. package/dist/i18n/i18n-context.js +7 -7
  149. package/dist/icon/icon-registry.d.ts +3 -3
  150. package/dist/icon/icon-registry.js +3 -3
  151. package/dist/icon/icon.d.ts +4 -4
  152. package/dist/icon/icon.js +6 -6
  153. package/dist/icon/llms.txt +13 -13
  154. package/dist/icon-button/icon-button.d.ts +2 -2
  155. package/dist/icon-button/icon-button.js +1 -1
  156. package/dist/icon-button/llms.txt +9 -5
  157. package/dist/icons-entry/public-api.d.ts +2 -2
  158. package/dist/icons-entry/public-api.js +3 -3
  159. package/dist/image/image.js +1 -1
  160. package/dist/image/llms.txt +13 -13
  161. package/dist/input/input.d.ts +18 -5
  162. package/dist/input/input.js +21 -6
  163. package/dist/input/llms.txt +25 -11
  164. package/dist/input-mask/input-mask.d.ts +1 -1
  165. package/dist/input-mask/input-mask.js +2 -2
  166. package/dist/input-mask/llms.txt +5 -5
  167. package/dist/input-number/input-number.d.ts +9 -9
  168. package/dist/input-number/input-number.js +11 -11
  169. package/dist/input-number/llms.txt +14 -14
  170. package/dist/input-otp/input-otp.d.ts +6 -6
  171. package/dist/input-otp/input-otp.js +10 -10
  172. package/dist/input-otp/llms.txt +9 -9
  173. package/dist/internal/calendar-focus.d.ts +1 -1
  174. package/dist/internal/calendar-focus.js +3 -3
  175. package/dist/internal/cn.d.ts +1 -1
  176. package/dist/internal/mask.d.ts +2 -2
  177. package/dist/internal/mask.js +4 -4
  178. package/dist/internal/option-key.d.ts +2 -2
  179. package/dist/internal/option-key.js +2 -2
  180. package/dist/internal/option-nav.d.ts +4 -4
  181. package/dist/internal/option-nav.js +5 -5
  182. package/dist/internal/overlay-container.js +1 -1
  183. package/dist/internal/overlay.d.ts +3 -3
  184. package/dist/internal/overlay.js +8 -8
  185. package/dist/internal/password-strength.d.ts +2 -2
  186. package/dist/internal/password-strength.js +6 -6
  187. package/dist/internal/roving.d.ts +2 -2
  188. package/dist/internal/roving.js +3 -3
  189. package/dist/internal/scroll-lock.d.ts +1 -1
  190. package/dist/internal/scroll-lock.js +2 -2
  191. package/dist/internal/slot-children.d.ts +3 -3
  192. package/dist/internal/slot-children.js +4 -4
  193. package/dist/internal/slot.d.ts +3 -3
  194. package/dist/internal/slot.js +2 -2
  195. package/dist/internal/step.d.ts +3 -3
  196. package/dist/internal/step.js +4 -4
  197. package/dist/internal/tween.d.ts +5 -5
  198. package/dist/internal/tween.js +5 -5
  199. package/dist/internal/types.d.ts +2 -2
  200. package/dist/internal/use-breakpoint.d.ts +2 -2
  201. package/dist/internal/use-breakpoint.js +4 -4
  202. package/dist/internal/use-controllable-state.d.ts +1 -1
  203. package/dist/internal/use-controllable-state.js +3 -3
  204. package/dist/internal/use-id.d.ts +2 -2
  205. package/dist/internal/use-id.js +2 -2
  206. package/dist/internal/use-modal-focus.d.ts +1 -1
  207. package/dist/internal/use-modal-focus.js +3 -3
  208. package/dist/knob/knob.d.ts +4 -4
  209. package/dist/knob/knob.js +14 -10
  210. package/dist/knob/llms.txt +17 -12
  211. package/dist/listbox/listbox.d.ts +6 -6
  212. package/dist/listbox/listbox.js +9 -9
  213. package/dist/listbox/llms.txt +10 -10
  214. package/dist/loader/llms.txt +56 -0
  215. package/dist/loader/loader.d.ts +49 -0
  216. package/dist/loader/loader.js +68 -0
  217. package/dist/map/llms.txt +25 -22
  218. package/dist/map/map-create-dialog.d.ts +4 -4
  219. package/dist/map/map-create-dialog.js +10 -10
  220. package/dist/map/map-hours-field.d.ts +4 -4
  221. package/dist/map/map-hours-field.js +7 -7
  222. package/dist/map/map-image-field.d.ts +2 -2
  223. package/dist/map/map-image-field.js +4 -4
  224. package/dist/map/map-legend.d.ts +4 -4
  225. package/dist/map/map-legend.js +2 -2
  226. package/dist/map/map-poi-card.d.ts +3 -3
  227. package/dist/map/map-poi-card.js +9 -9
  228. package/dist/map/map-search.d.ts +17 -6
  229. package/dist/map/map-search.js +21 -18
  230. package/dist/map/map.d.ts +21 -14
  231. package/dist/map/map.js +30 -29
  232. package/dist/map/ports.d.ts +9 -9
  233. package/dist/map/ports.js +6 -6
  234. package/dist/map-entry/public-api.js +2 -2
  235. package/dist/megamenu/llms.txt +9 -9
  236. package/dist/megamenu/megamenu.d.ts +6 -6
  237. package/dist/megamenu/megamenu.js +10 -10
  238. package/dist/mention/llms.txt +15 -15
  239. package/dist/mention/mention.d.ts +5 -5
  240. package/dist/mention/mention.js +2 -2
  241. package/dist/mention/mentions.d.ts +1 -1
  242. package/dist/mention/mentions.js +1 -1
  243. package/dist/menu/llms.txt +12 -12
  244. package/dist/menu/menu-item.d.ts +4 -4
  245. package/dist/menu/menu-keys.d.ts +2 -2
  246. package/dist/menu/menu-keys.js +5 -5
  247. package/dist/menu/menu.d.ts +2 -2
  248. package/dist/menu/menu.js +6 -6
  249. package/dist/menubar/llms.txt +10 -10
  250. package/dist/menubar/menubar.d.ts +5 -5
  251. package/dist/menubar/menubar.js +10 -10
  252. package/dist/meter-group/llms.txt +12 -12
  253. package/dist/meter-group/meter-group.d.ts +2 -2
  254. package/dist/meter-group/meter-group.js +1 -1
  255. package/dist/motion/motion-context.d.ts +22 -0
  256. package/dist/motion/motion-context.js +28 -0
  257. package/dist/order-list/llms.txt +22 -10
  258. package/dist/order-list/order-list.d.ts +12 -4
  259. package/dist/order-list/order-list.js +104 -21
  260. package/dist/paginator/llms.txt +8 -8
  261. package/dist/paginator/paginator.js +1 -1
  262. package/dist/panel/llms.txt +25 -13
  263. package/dist/panel/panel.d.ts +11 -3
  264. package/dist/panel/panel.js +7 -4
  265. package/dist/password/llms.txt +16 -8
  266. package/dist/password/password.d.ts +2 -2
  267. package/dist/password/password.js +24 -3
  268. package/dist/peek/llms.txt +10 -10
  269. package/dist/peek/peek.d.ts +6 -6
  270. package/dist/peek/peek.js +7 -7
  271. package/dist/pick-list/llms.txt +33 -13
  272. package/dist/pick-list/pick-list.d.ts +12 -4
  273. package/dist/pick-list/pick-list.js +111 -23
  274. package/dist/popover/llms.txt +11 -11
  275. package/dist/popover/popover.d.ts +4 -4
  276. package/dist/popover/popover.js +5 -5
  277. package/dist/progress/llms.txt +17 -17
  278. package/dist/progress/progress.d.ts +7 -7
  279. package/dist/progress/progress.js +6 -6
  280. package/dist/public-api.d.ts +15 -3
  281. package/dist/public-api.js +13 -7
  282. package/dist/radio-group/llms.txt +13 -6
  283. package/dist/radio-group/radio-group.d.ts +11 -4
  284. package/dist/radio-group/radio-group.js +15 -7
  285. package/dist/rating/llms.txt +20 -13
  286. package/dist/rating/rating-pointer.d.ts +16 -0
  287. package/dist/rating/rating-pointer.js +26 -0
  288. package/dist/rating/rating.d.ts +6 -6
  289. package/dist/rating/rating.js +76 -12
  290. package/dist/rich-text/lists.d.ts +2 -2
  291. package/dist/rich-text/lists.js +7 -7
  292. package/dist/rich-text/llms.txt +26 -17
  293. package/dist/rich-text/rich-text.d.ts +12 -7
  294. package/dist/rich-text/rich-text.js +78 -54
  295. package/dist/rich-text/sanitize.d.ts +3 -3
  296. package/dist/rich-text/sanitize.js +12 -12
  297. package/dist/rich-text/tables.d.ts +3 -3
  298. package/dist/rich-text/tables.js +3 -3
  299. package/dist/roadmap/llms.txt +15 -15
  300. package/dist/roadmap/roadmap.d.ts +6 -6
  301. package/dist/roadmap/roadmap.js +19 -19
  302. package/dist/roadmap-entry/public-api.js +2 -2
  303. package/dist/scroll-top/llms.txt +6 -6
  304. package/dist/scroll-top/scroll-top.d.ts +1 -1
  305. package/dist/scroll-top/scroll-top.js +1 -1
  306. package/dist/select/llms.txt +19 -12
  307. package/dist/select/select.d.ts +8 -8
  308. package/dist/select/select.js +47 -21
  309. package/dist/shared/types.d.ts +5 -5
  310. package/dist/shared/types.js +1 -1
  311. package/dist/sidenav/llms.txt +9 -9
  312. package/dist/sidenav/sidenav.d.ts +1 -1
  313. package/dist/sidenav/sidenav.js +1 -1
  314. package/dist/skeleton/llms.txt +3 -3
  315. package/dist/skeleton/skeleton.d.ts +1 -1
  316. package/dist/skeleton/skeleton.js +1 -1
  317. package/dist/slider/llms.txt +32 -13
  318. package/dist/slider/slider-drag.d.ts +26 -0
  319. package/dist/slider/slider-drag.js +79 -0
  320. package/dist/slider/slider.d.ts +6 -5
  321. package/dist/slider/slider.js +27 -8
  322. package/dist/speech/llms.txt +97 -0
  323. package/dist/speech/speech-button.d.ts +44 -0
  324. package/dist/speech/speech-button.js +86 -0
  325. package/dist/speech/speech-wave.d.ts +19 -0
  326. package/dist/speech/speech-wave.js +16 -0
  327. package/dist/speech/use-speech-recognition.d.ts +81 -0
  328. package/dist/speech/use-speech-recognition.js +179 -0
  329. package/dist/speed-dial/llms.txt +14 -8
  330. package/dist/speed-dial/speed-dial.d.ts +1 -1
  331. package/dist/speed-dial/speed-dial.js +1 -1
  332. package/dist/spinner/llms.txt +7 -7
  333. package/dist/spinner/spinner.d.ts +1 -1
  334. package/dist/spinner/spinner.js +1 -1
  335. package/dist/split-button/llms.txt +21 -15
  336. package/dist/split-button/split-button.d.ts +2 -2
  337. package/dist/split-button/split-button.js +4 -4
  338. package/dist/splitter/llms.txt +11 -11
  339. package/dist/splitter/splitter.d.ts +3 -3
  340. package/dist/splitter/splitter.js +5 -5
  341. package/dist/stepper/llms.txt +33 -14
  342. package/dist/stepper/stepper.d.ts +6 -6
  343. package/dist/stepper/stepper.js +53 -10
  344. package/dist/switch/llms.txt +12 -5
  345. package/dist/switch/switch.d.ts +10 -3
  346. package/dist/switch/switch.js +12 -5
  347. package/dist/switch-group/llms.txt +9 -9
  348. package/dist/switch-group/switch-group.d.ts +4 -4
  349. package/dist/switch-group/switch-group.js +4 -4
  350. package/dist/tabs/llms.txt +10 -10
  351. package/dist/tabs/tabs.d.ts +5 -5
  352. package/dist/tabs/tabs.js +8 -8
  353. package/dist/textarea/llms.txt +23 -12
  354. package/dist/textarea/textarea.d.ts +19 -6
  355. package/dist/textarea/textarea.js +21 -7
  356. package/dist/timeline/llms.txt +4 -4
  357. package/dist/timeline/timeline.d.ts +1 -1
  358. package/dist/timeline/timeline.js +1 -1
  359. package/dist/toast/llms.txt +47 -17
  360. package/dist/toast/toast-container.d.ts +9 -3
  361. package/dist/toast/toast-container.js +17 -9
  362. package/dist/toast/toast-store.d.ts +40 -4
  363. package/dist/toast/toast-store.js +36 -1
  364. package/dist/toolbar/llms.txt +7 -7
  365. package/dist/toolbar/toolbar.d.ts +3 -3
  366. package/dist/toolbar/toolbar.js +2 -2
  367. package/dist/tooltip/llms.txt +10 -10
  368. package/dist/tooltip/tooltip.d.ts +3 -3
  369. package/dist/tooltip/tooltip.js +18 -18
  370. package/dist/tree/llms.txt +25 -12
  371. package/dist/tree/tree-keys.d.ts +5 -5
  372. package/dist/tree/tree-keys.js +7 -7
  373. package/dist/tree/tree.d.ts +14 -7
  374. package/dist/tree/tree.js +53 -18
  375. package/dist/update/llms.txt +54 -0
  376. package/dist/update/update.d.ts +49 -0
  377. package/dist/update/update.js +82 -0
  378. package/package.json +15 -13
@@ -13,23 +13,23 @@ export interface KptKnobProps extends Omit<ComponentPropsWithRef<'div'>, 'onChan
13
13
  /** Dopisek za wartością w środku (np. '%'). */
14
14
  suffix?: string;
15
15
  showValue?: boolean;
16
- /** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
16
+ /** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` - z wrappera. */
17
17
  id?: string;
18
18
  /** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
19
19
  ariaLabel?: string | null;
20
20
  disabled?: boolean;
21
- /** Tylko do odczytu — pokrętło widać i da się na nim stanąć, ale nie zmienić wartości. */
21
+ /** Tylko do odczytu - pokrętło widać i da się na nim stanąć, ale nie zmienić wartości. */
22
22
  readOnly?: boolean;
23
23
  invalid?: boolean;
24
24
  touched?: boolean;
25
25
  onTouch?: () => void;
26
26
  }
27
27
  /**
28
- * Pokrętło — wybór wartości po łuku, przeciąganiem albo strzałkami.
28
+ * Pokrętło - wybór wartości po łuku, przeciąganiem albo strzałkami.
29
29
  *
30
30
  * Skok wartości (strzałka, `Home`/`End`, klik w łuk, zmiana z zewnątrz) łuk i licznik pokonują
31
31
  * płynnie; przy przeciąganiu idą za kursorem bez opóźnienia. `PageUp`/`PageDown` skaczą o dziesięć
32
- * kroków, a wartości leżą na siatce `min + k·step` dla myszy i klawiatury. `prefers-reduced-motion` wyłącza
32
+ * kroków, a wartości leżą na siatce `min + k,step` dla myszy i klawiatury. `prefers-reduced-motion` wyłącza
33
33
  * animację, a `aria-valuenow` zawsze niesie wartość docelową, nie pośrednią.
34
34
  *
35
35
  * @example
package/dist/knob/knob.js CHANGED
@@ -7,18 +7,18 @@ import { kptStepDecimals, kptTween } from "../internal/tween.js";
7
7
  import { useControllableState } from "../internal/use-controllable-state.js";
8
8
  import { useKptFieldA11y } from "../form-field/form-field-context.js";
9
9
  const TAU = Math.PI * 2;
10
- /** Przerwa u dołu — kąt „otwarcia" łuku, żeby początek i koniec były rozróżnialne. */
10
+ /** Przerwa u dołu - kąt "otwarcia" łuku, żeby początek i koniec były rozróżnialne. */
11
11
  const GAP = Math.PI / 4;
12
12
  const START_ANGLE = Math.PI / 2 + GAP;
13
13
  const SWEEP = TAU - GAP * 2;
14
14
  /** Czas dojścia łuku i licznika po skoku wartości (klawisz, klik, zmiana z zewnątrz). */
15
15
  const TWEEN_MS = 220;
16
16
  /**
17
- * Pokrętło — wybór wartości po łuku, przeciąganiem albo strzałkami.
17
+ * Pokrętło - wybór wartości po łuku, przeciąganiem albo strzałkami.
18
18
  *
19
19
  * Skok wartości (strzałka, `Home`/`End`, klik w łuk, zmiana z zewnątrz) łuk i licznik pokonują
20
20
  * płynnie; przy przeciąganiu idą za kursorem bez opóźnienia. `PageUp`/`PageDown` skaczą o dziesięć
21
- * kroków, a wartości leżą na siatce `min + k·step` dla myszy i klawiatury. `prefers-reduced-motion` wyłącza
21
+ * kroków, a wartości leżą na siatce `min + k,step` dla myszy i klawiatury. `prefers-reduced-motion` wyłącza
22
22
  * animację, a `aria-valuenow` zawsze niesie wartość docelową, nie pośrednią.
23
23
  *
24
24
  * @example
@@ -30,11 +30,13 @@ export function KptKnob({ value, defaultValue = 0, onValueChange, min = 0, max =
30
30
  const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
31
31
  const showInvalid = invalid && (touched ?? true);
32
32
  const range = max - min;
33
- /** Wartość na rysunku — w trakcie animacji pośrednia, poza nią równa `current`. */
33
+ /** Wartość na rysunku - w trakcie animacji pośrednia, poza nią równa `current`. */
34
34
  const [shown, setShown] = useState(current);
35
35
  const shownRef = useRef(current);
36
- /** Przeciąganie trwa — wtedy rysunek idzie za kursorem bez animacji. */
36
+ /** Przeciąganie trwa - wtedy rysunek idzie za kursorem bez animacji. */
37
37
  const dragging = useRef(false);
38
+ /** Pokrętło trzymane wskaźnikiem (od wciśnięcia do puszczenia) - steruje reakcją w CSS. */
39
+ const [grabbing, setGrabbing] = useState(false);
38
40
  useEffect(() => {
39
41
  const paint = (v) => {
40
42
  shownRef.current = v;
@@ -70,7 +72,7 @@ export function KptKnob({ value, defaultValue = 0, onValueChange, min = 0, max =
70
72
  const cy = rect.top + rect.height / 2;
71
73
  let angle = Math.atan2(clientY - cy, clientX - cx) - START_ANGLE;
72
74
  angle = ((angle % TAU) + TAU) % TAU;
73
- // Kursor w przerwie u dołu nie ma swojej wartości — przyciągamy go do bliższego końca łuku,
75
+ // Kursor w przerwie u dołu nie ma swojej wartości - przyciągamy go do bliższego końca łuku,
74
76
  // inaczej przeciągnięcie przez dół przeskakiwałoby z maksimum na minimum.
75
77
  if (angle > SWEEP + GAP)
76
78
  angle = angle > SWEEP + GAP / 2 ? 0 : SWEEP;
@@ -79,14 +81,15 @@ export function KptKnob({ value, defaultValue = 0, onValueChange, min = 0, max =
79
81
  const onPointerDown = (event) => {
80
82
  if (disabled || readOnly)
81
83
  return;
82
- // Bez tego przeciąganie zaznacza tekst: licznik w środku i — przez SVG — całe koło, jak po
84
+ // Bez tego przeciąganie zaznacza tekst: licznik w środku i - przez SVG - całe koło, jak po
83
85
  // `Ctrl+A`. Zablokowanie domyślnej akcji zabiera też fokus, więc oddajemy go ręcznie.
84
86
  event.preventDefault();
85
87
  event.currentTarget.focus();
86
- // Klik w łuk to skok — animowany. Dopiero ruch po nim jest przeciąganiem.
88
+ setGrabbing(true);
89
+ // Klik w łuk to skok - animowany. Dopiero ruch po nim jest przeciąganiem.
87
90
  setFromPoint(event.clientX, event.clientY);
88
91
  // Nasłuch wisi na oknie, a nie na pokrętle: przeciąganie ma nie gubić wartości,
89
- // gdy kursor wyjedzie poza koło — a wyjeżdża praktycznie zawsze.
92
+ // gdy kursor wyjedzie poza koło - a wyjeżdża praktycznie zawsze.
90
93
  const move = (e) => {
91
94
  dragging.current = true;
92
95
  setFromPoint(e.clientX, e.clientY);
@@ -96,6 +99,7 @@ export function KptKnob({ value, defaultValue = 0, onValueChange, min = 0, max =
96
99
  window.removeEventListener('pointerup', up);
97
100
  window.removeEventListener('pointercancel', up);
98
101
  dragging.current = false;
102
+ setGrabbing(false);
99
103
  onTouch?.();
100
104
  };
101
105
  window.addEventListener('pointermove', move);
@@ -119,5 +123,5 @@ export function KptKnob({ value, defaultValue = 0, onValueChange, min = 0, max =
119
123
  setCurrent(kptSnapToStep(next, min, max, step));
120
124
  onTouch?.();
121
125
  };
122
- return (_jsx("div", { className: cn('kpt-knob-host', className), ...rest, children: _jsx("div", { className: cn('kpt-knob', showInvalid && 'kpt-knob--invalid'), role: "slider", id: field.id, tabIndex: disabled ? -1 : 0, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": current, "aria-valuetext": suffix ? `${current}${suffix}` : undefined, "aria-disabled": disabled || undefined, "aria-readonly": readOnly || undefined, "aria-invalid": showInvalid || undefined, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onPointerDown: onPointerDown, onKeyDown: onKeyDown, children: _jsxs("svg", { ref: svgRef, viewBox: `0 0 ${size} ${size}`, style: { width: size, height: size }, children: [_jsx("path", { className: "kpt-knob__range", d: arc(0, 1), fill: "none", strokeWidth: stroke, strokeLinecap: "round" }), _jsx("path", { className: "kpt-knob__value", d: arc(0, ratio), fill: "none", strokeWidth: stroke, strokeLinecap: "round" }), showValue ? (_jsxs("text", { className: "kpt-knob__text", x: size / 2, y: size / 2, textAnchor: "middle", dominantBaseline: "central", children: [shown.toFixed(kptStepDecimals(step)), suffix] })) : null] }) }) }));
126
+ return (_jsx("div", { className: cn('kpt-knob-host', className), ...rest, children: _jsx("div", { className: cn('kpt-knob', showInvalid && 'kpt-knob--invalid', grabbing && 'is-grabbing'), role: "slider", id: field.id, tabIndex: disabled ? -1 : 0, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": current, "aria-valuetext": suffix ? `${current}${suffix}` : undefined, "aria-disabled": disabled || undefined, "aria-readonly": readOnly || undefined, "aria-invalid": showInvalid || undefined, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onPointerDown: onPointerDown, onKeyDown: onKeyDown, children: _jsxs("svg", { ref: svgRef, viewBox: `0 0 ${size} ${size}`, style: { width: size, height: size }, children: [_jsx("path", { className: "kpt-knob__range", d: arc(0, 1), fill: "none", strokeWidth: stroke, strokeLinecap: "round" }), _jsx("path", { className: "kpt-knob__value", d: arc(0, ratio), fill: "none", strokeWidth: stroke, strokeLinecap: "round" }), showValue ? (_jsxs("text", { className: "kpt-knob__text", x: size / 2, y: size / 2, textAnchor: "middle", dominantBaseline: "central", children: [shown.toFixed(kptStepDecimals(step)), suffix] })) : null] }) }) }));
123
127
  }
@@ -1,37 +1,37 @@
1
1
  # KptKnob (@konce-pt/react)
2
2
 
3
- A knob — pick a value along an SVG arc, by dragging or with the arrow keys.
3
+ A knob - pick a value along an SVG arc, by dragging or with the arrow keys.
4
4
  Import: `import { KptKnob } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-knob-host">
8
8
  <div class="kpt-knob" role="slider" tabindex="0" aria-valuenow="40">
9
9
  <svg viewBox="0 0 96 96">
10
- <path class="kpt-knob__range" d="M …" />
11
- <path class="kpt-knob__value" d="M …" />
10
+ <path class="kpt-knob__range" d="M ..." />
11
+ <path class="kpt-knob__value" d="M ..." />
12
12
  <text class="kpt-knob__text">40%</text>
13
13
  </svg>
14
14
  </div>
15
15
  </div>
16
16
 
17
17
  ## Props
18
- - `value` / `defaultValue` / `onValueChange` — the number
18
+ - `value` / `defaultValue` / `onValueChange` - the number
19
19
  - `min` (0), `max` (100), `step` (1)
20
- - `size`: px (96) — the side of the SVG square; `stroke`: px (10) — arc thickness
20
+ - `size`: px (96) - the side of the SVG square; `stroke`: px (10) - arc thickness
21
21
  - `suffix`: string appended to the value in the middle; `showValue`: boolean (default true)
22
- - `disabled`, `readOnly`, `invalid`, `touched`, `onTouch()` — `readOnly` keeps the knob focusable but ignores
22
+ - `disabled`, `readOnly`, `invalid`, `touched`, `onTouch()` - `readOnly` keeps the knob focusable but ignores
23
23
  the pointer and the keys (`aria-readonly`)
24
24
  - `className`, `ref` and every other `<div>` prop go to the host
25
25
 
26
26
  ## The gap at the bottom
27
27
  The arc is a full circle minus a 45° gap at the bottom, so its start and end are distinguishable.
28
- A pointer inside that gap has no value of its own — it is snapped to the nearer end, otherwise
28
+ A pointer inside that gap has no value of its own - it is snapped to the nearer end, otherwise
29
29
  dragging across the bottom would jump between minimum and maximum.
30
30
 
31
31
  ## Dragging listens on the window
32
32
  `pointermove` / `pointerup` are attached to `window`, not to the knob: the pointer leaves the
33
33
  circle during almost every drag, and the value must keep following it. Both listeners are removed
34
- on `pointerup`, which is also where `onTouch` fires — one touch per drag, not per pixel.
34
+ on `pointerup`, which is also where `onTouch` fires - one touch per drag, not per pixel.
35
35
 
36
36
  ## Examples
37
37
  <KptKnob value={level} onValueChange={setLevel} min={0} max={100} step={5} suffix="%" />
@@ -42,15 +42,20 @@ on `pointerup`, which is also where `onTouch` fires — one touch per drag, not
42
42
  generated. A `div` with a role is not named by `label[for]`, so inside `KptFormField` it gets
43
43
  `aria-labelledby` pointing at the wrapper's label (unless `ariaLabel` is set), and the hint or error
44
44
  is added to `aria-describedby`. New: `id`, `ariaLabel`; `aria-valuetext` includes `suffix` ("40%"),
45
- and a disabled knob leaves the Tab order. Use `ariaLabel`, not `aria-label` on the host — that one
45
+ and a disabled knob leaves the Tab order. Use `ariaLabel`, not `aria-label` on the host - that one
46
46
  lands on the wrapper.
47
47
 
48
+ ## Pointer
49
+ While held (from press to release) the knob reacts: the cursor becomes `grabbing`, the dial grows
50
+ slightly, the value arc glows stronger and the number in the middle scales up. On hover the arc glows
51
+ softly. All of it is CSS on the `is-grabbing` class and drops out under "reduce motion".
52
+
48
53
  ## Tokens
49
54
  The background arc `--kpt-color-border`, the value `--kpt-color-primary`, the text
50
55
  `--kpt-color-on-surface`.
51
56
 
52
57
  ## Motion
53
- A jump in value — an arrow key, Home/End, a click on the arc, a change from outside — moves the arc
58
+ A jump in value - an arrow key, Home/End, a click on the arc, a change from outside - moves the arc
54
59
  and counts the number up or down over ~220 ms (ease-out). Dragging follows the pointer with no
55
60
  delay, so it never feels laggy. `prefers-reduced-motion: reduce` turns the animation off.
56
61
  `aria-valuenow` always carries the target value, never an in-between frame. Dragging does not
@@ -58,6 +63,6 @@ select the number or the arc.
58
63
 
59
64
  ## Accessibility
60
65
  `role="slider"` with `aria-valuemin` / `aria-valuemax` / `aria-valuenow`; arrows step by `step`,
61
- PageUp/PageDown by ten steps, Home and End jump to the bounds. Values sit on the grid `min + k·step` for
62
- both the pointer and the keys — with `min={1} step={2}` that is 1, 3, 5…. `disabled` sets `aria-disabled` and drops the knob out of the
66
+ PageUp/PageDown by ten steps, Home and End jump to the bounds. Values sit on the grid `min + k,step` for
67
+ both the pointer and the keys - with `min={1} step={2}` that is 1, 3, 5.... `disabled` sets `aria-disabled` and drops the knob out of the
63
68
  tab order.
@@ -9,14 +9,14 @@ export interface KptListboxProps<T> extends Omit<ComponentPropsWithRef<'div'>, '
9
9
  multiple?: boolean;
10
10
  /** Pole filtrowania nad listą. */
11
11
  filter?: boolean;
12
- /** Id listy (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
12
+ /** Id listy (nie hosta); bez niego generowane, w `KptFormField` - z wrappera. */
13
13
  id?: string;
14
14
  /** Nazwa dostępna listy, gdy nie opisuje jej etykieta (`KptFormField`). */
15
15
  ariaLabel?: string | null;
16
16
  /** Oznacza listę jako wymaganą atrybutem `aria-required`. */
17
17
  required?: boolean;
18
18
  disabled?: boolean;
19
- /** Tylko do odczytu — po liście da się chodzić i czytać wybór, ale nie da się go zmienić. */
19
+ /** Tylko do odczytu - po liście da się chodzić i czytać wybór, ale nie da się go zmienić. */
20
20
  readOnly?: boolean;
21
21
  invalid?: boolean;
22
22
  touched?: boolean;
@@ -26,14 +26,14 @@ export interface KptListboxProps<T> extends Omit<ComponentPropsWithRef<'div'>, '
26
26
  * Lista wyboru widoczna w całości, bez rozwijania. Pojedynczy albo wielokrotny wybór,
27
27
  * opcjonalny filtr.
28
28
  *
29
- * W trybie pojedynczym ponowny klik w zaznaczoną opcję odznacza ją — lista bywa filtrem,
29
+ * W trybie pojedynczym ponowny klik w zaznaczoną opcję odznacza ją - lista bywa filtrem,
30
30
  * a filtr trzeba dać się wyczyścić bez sięgania po osobny przycisk.
31
31
  *
32
- * Klawiatura według wzorca WAI-ARIA „listbox”: lista to jeden przystanek Tab, a aktywną opcję
32
+ * Klawiatura według wzorca WAI-ARIA "listbox": lista to jeden przystanek Tab, a aktywną opcję
33
33
  * ogłasza `aria-activedescendant`. Strzałki, `Home`/`End`, `PageUp`/`PageDown` przesuwają aktywną
34
34
  * opcję (wyłączone są pomijane), pisanie liter skacze do kolejnej pasującej (bez względu na
35
- * diakrytyki), `Spacja`/`Enter` wybiera, a w trybie wielokrotnym `Ctrl`/`⌘`+`A` zaznacza wszystkie
36
- * widoczne. Pole filtra stoi przed listą; `↓` przenosi z niego fokus do listy.
35
+ * diakrytyki), `Spacja`/`Enter` wybiera, a w trybie wielokrotnym `Ctrl`/`Cmd`+`A` zaznacza wszystkie
36
+ * widoczne. Pole filtra stoi przed listą; `ArrowDown` przenosi z niego fokus do listy.
37
37
  *
38
38
  * @example
39
39
  * <KptListbox options={roles} value={role} onValueChange={setRole} filter />
@@ -12,14 +12,14 @@ import { KptIcon } from "../icon/icon.js";
12
12
  * Lista wyboru widoczna w całości, bez rozwijania. Pojedynczy albo wielokrotny wybór,
13
13
  * opcjonalny filtr.
14
14
  *
15
- * W trybie pojedynczym ponowny klik w zaznaczoną opcję odznacza ją — lista bywa filtrem,
15
+ * W trybie pojedynczym ponowny klik w zaznaczoną opcję odznacza ją - lista bywa filtrem,
16
16
  * a filtr trzeba dać się wyczyścić bez sięgania po osobny przycisk.
17
17
  *
18
- * Klawiatura według wzorca WAI-ARIA „listbox”: lista to jeden przystanek Tab, a aktywną opcję
18
+ * Klawiatura według wzorca WAI-ARIA "listbox": lista to jeden przystanek Tab, a aktywną opcję
19
19
  * ogłasza `aria-activedescendant`. Strzałki, `Home`/`End`, `PageUp`/`PageDown` przesuwają aktywną
20
20
  * opcję (wyłączone są pomijane), pisanie liter skacze do kolejnej pasującej (bez względu na
21
- * diakrytyki), `Spacja`/`Enter` wybiera, a w trybie wielokrotnym `Ctrl`/`⌘`+`A` zaznacza wszystkie
22
- * widoczne. Pole filtra stoi przed listą; `↓` przenosi z niego fokus do listy.
21
+ * diakrytyki), `Spacja`/`Enter` wybiera, a w trybie wielokrotnym `Ctrl`/`Cmd`+`A` zaznacza wszystkie
22
+ * widoczne. Pole filtra stoi przed listą; `ArrowDown` przenosi z niego fokus do listy.
23
23
  *
24
24
  * @example
25
25
  * <KptListbox options={roles} value={role} onValueChange={setRole} filter />
@@ -27,7 +27,7 @@ import { KptIcon } from "../icon/icon.js";
27
27
  */
28
28
  export function KptListbox({ options = [], value, defaultValue = null, onValueChange, multiple = false, filter = false, id, ariaLabel = null, required = false, disabled = false, readOnly = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
29
29
  const { t } = useKptMessages({ locale, dictionary });
30
- /** `div` z rolą nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
30
+ /** `div` z rolą nie dostaje nazwy z `label[for]` - stąd `aria-labelledby` na etykietę wrappera. */
31
31
  const field = useKptFieldA11y(id, 'kpt-listbox');
32
32
  const [current, setCurrent] = useControllableState({
33
33
  value,
@@ -40,7 +40,7 @@ export function KptListbox({ options = [], value, defaultValue = null, onValueCh
40
40
  const listRef = useRef(null);
41
41
  const typeahead = useRef(new KptTypeahead()).current;
42
42
  const showInvalid = invalid && (touched ?? true);
43
- /** Filtr bez względu na wielkość liter i diakrytyki („lodz” znajduje „Łódź”). */
43
+ /** Filtr bez względu na wielkość liter i diakrytyki ("lodz" znajduje "Łódź"). */
44
44
  const visible = useMemo(() => {
45
45
  const q = foldMentionText(query.trim());
46
46
  return q ? options.filter((option) => foldMentionText(option.label).includes(q)) : options;
@@ -63,7 +63,7 @@ export function KptListbox({ options = [], value, defaultValue = null, onValueCh
63
63
  setCurrent(current === candidate ? null : candidate);
64
64
  }
65
65
  };
66
- /** Ostatnio kliknięta opcja — początek zakresu dla `Shift+klik` w trybie `multiple`. */
66
+ /** Ostatnio kliknięta opcja - początek zakresu dla `Shift+klik` w trybie `multiple`. */
67
67
  const anchorIndex = useRef(-1);
68
68
  const pick = (index, extend = false) => {
69
69
  const option = visible[index];
@@ -71,7 +71,7 @@ export function KptListbox({ options = [], value, defaultValue = null, onValueCh
71
71
  return;
72
72
  setActiveIndex(index);
73
73
  if (extend && multiple && anchorIndex.current >= 0) {
74
- // Zaznacza (dokłada) dozwolone opcje między kotwicą a klikniętą — `Shift+klik` (APG).
74
+ // Zaznacza (dokłada) dozwolone opcje między kotwicą a klikniętą - `Shift+klik` (APG).
75
75
  const [lo, hi] = anchorIndex.current <= index ? [anchorIndex.current, index] : [index, anchorIndex.current];
76
76
  const list = Array.isArray(current) ? current : [];
77
77
  const add = visible
@@ -123,7 +123,7 @@ export function KptListbox({ options = [], value, defaultValue = null, onValueCh
123
123
  event.preventDefault();
124
124
  const all = visible.filter((_, index) => !disabledMap[index]).map((option) => option.value);
125
125
  const list = Array.isArray(current) ? (current) : [];
126
- // Drugi raz `Ctrl+A` przy wszystkich zaznaczonych — odznacza widoczne.
126
+ // Drugi raz `Ctrl+A` przy wszystkich zaznaczonych - odznacza widoczne.
127
127
  const allOn = all.every((item) => list.includes(item));
128
128
  setCurrent(allOn ? list.filter((item) => !all.includes(item)) : [...list, ...all.filter((item) => !list.includes(item))]);
129
129
  return;
@@ -6,19 +6,19 @@ Import: `import { KptListbox } from '@konce-pt/react';`
6
6
  ## DOM
7
7
  <div class="kpt-listbox-host">
8
8
  <div class="kpt-listbox">
9
- <div class="kpt-listbox__filter">…icon + input…</div>
10
- <div class="kpt-listbox__items" role="listbox" tabindex="0" aria-activedescendant="…-opt-0">
11
- <div class="kpt-listbox__item is-selected is-active" role="option" id="…-opt-0" aria-selected="true">Admin</div>
9
+ <div class="kpt-listbox__filter">...icon + input...</div>
10
+ <div class="kpt-listbox__items" role="listbox" tabindex="0" aria-activedescendant="...-opt-0">
11
+ <div class="kpt-listbox__item is-selected is-active" role="option" id="...-opt-0" aria-selected="true">Admin</div>
12
12
  </div>
13
13
  </div>
14
14
  </div>
15
15
 
16
16
  ## Props
17
17
  - `options`: `KptOption<T>[]`
18
- - `value` / `defaultValue` / `onValueChange` — `T` (single) or `T[]` (multiple)
18
+ - `value` / `defaultValue` / `onValueChange` - `T` (single) or `T[]` (multiple)
19
19
  - `multiple`, `filter`, `disabled`, `invalid`, `touched`, `onTouch()`
20
20
  - `id`, `ariaLabel`, `required`
21
- - `locale`, `dictionary` — i18n overrides for this component only
21
+ - `locale`, `dictionary` - i18n overrides for this component only
22
22
 
23
23
  ## Clicking the selection clears it
24
24
  In single mode clicking the already selected option deselects it. A listbox is often a filter, and a
@@ -33,17 +33,17 @@ filter has to be clearable without a separate button.
33
33
 
34
34
  ## Keyboard
35
35
  The WAI-ARIA listbox pattern: the list is one Tab stop and the active option is announced through
36
- `aria-activedescendant`. `↑`/`↓`, `Home`/`End` and `PageUp`/`PageDown` move the active option,
36
+ `aria-activedescendant`. `ArrowUp`/`ArrowDown`, `Home`/`End` and `PageUp`/`PageDown` move the active option,
37
37
  skipping disabled ones (no wrapping); typing letters jumps to the next match, diacritics ignored;
38
- `Space`/`Enter` picks; in `multiple` mode `Ctrl`/`⌘`+`A` selects every visible option (again —
39
- clears them). The filter field sits before the list (outside the `listbox`) and `↓` moves focus
38
+ `Space`/`Enter` picks; in `multiple` mode `Ctrl`/`Cmd`+`A` selects every visible option (again -
39
+ clears them). The filter field sits before the list (outside the `listbox`) and `ArrowDown` moves focus
40
40
  from it into the list; the filter itself ignores diacritics ("lodz" finds "Łódź").
41
41
 
42
42
  ## Label and description
43
43
  `id` goes to the list (`role="listbox"`), never the host. A `div` with a role is not named by
44
44
  `label[for]`, so inside `KptFormField` the list gets `aria-labelledby` pointing at the wrapper's
45
45
  label (unless `ariaLabel` is set) and the hint or error in `aria-describedby`. New: `id`,
46
- `ariaLabel`, `required` (→ `aria-required`); `aria-invalid` after touch; `touch` fires on blur of the list.
46
+ `ariaLabel`, `required` (-> `aria-required`); `aria-invalid` after touch; `touch` fires on blur of the list.
47
47
 
48
48
  ## Tokens
49
49
  `--kpt-color-surface`, `--kpt-color-border`, `--kpt-color-primary-subtle` (the selected row),
@@ -55,4 +55,4 @@ The list is `role="listbox"` with `aria-multiselectable`, `aria-activedescendant
55
55
  The keyboard is described above.
56
56
 
57
57
  ## Read-only and required
58
- `readOnly` lets you move through the list and read the choice but not change it (`aria-readonly`). With `multiple`, `Shift+↑/↓` selects the option focus moves to and `Shift+click` adds the range from the last clicked option (APG). The empty message sits next to the list.
58
+ `readOnly` lets you move through the list and read the choice but not change it (`aria-readonly`). With `multiple`, `Shift+ArrowUp/ArrowDown` selects the option focus moves to and `Shift+click` adds the range from the last clicked option (APG). The empty message sits next to the list.
@@ -0,0 +1,56 @@
1
+ # KptLoader (@konce-pt/react)
2
+
3
+ A loader with character: a loop in one of six materials that turns into a result mark instead of
4
+ disappearing. Same classes and the same drawing as `kpt-loader` in Angular - the SVG and its
5
+ choreography come from `createLoader` in `@konce-pt/motion`. Import:
6
+ `import { KptLoader } from '@konce-pt/react';`
7
+
8
+ Variants: `bubbles` (default), `bridge` (the result is a pill with text), `shapes`, `ring` (progress,
9
+ an icon in the centre), `wave` (progress), `bounce`. Use `KptSpinner` for a small inline "wait".
10
+
11
+ ## DOM
12
+ <span class="kpt-loader-host">
13
+ <span class="kpt-loader" data-variant="bubbles" data-status="loading" style="--_size: 5rem">
14
+ <span class="kpt-loader__stage" aria-hidden="true"><svg class="kpt-loader__svg">...</svg></span>
15
+ <span class="kpt-loader__content"></span>
16
+ <span class="kpt-loader__label" role="status">Loading</span>
17
+ </span>
18
+ </span>
19
+
20
+ ## Props
21
+ - `variant`: KptLoaderVariant (default 'bubbles')
22
+ - `status`: 'loading' | 'success' | 'error' (default 'loading') - a result plays once and the mark
23
+ stays; back to `loading` restarts the loop
24
+ - `value`: number | null (default null), `min` (0), `max` (100) - progress for `ring` and `wave`
25
+ - `size`: string (default '5rem') - the CSS length of 100 drawing units, shared by all variants
26
+ - `colors`: KptLoaderColor[] | null - theme roles ('primary', 'info', 'success', 'warning',
27
+ 'danger') or CSS colours, repeated in order; without it each variant has its palette
28
+ - `successColor` (default 'success'), `errorColor` (default 'danger')
29
+ - `speed`: number (default 1) - multiplies the loop tempo
30
+ - `label`, `successLabel`, `errorLabel`: string - default `loader.label`, `loader.success`,
31
+ `loader.error`; the result texts also go into the `bridge` pill and follow the language live
32
+ - `announce`: boolean (default true) - `false` drops the own status region
33
+ - `onSettled`: (result: KptLoaderResult) => void - the result choreography has finished; not called
34
+ when the loader mounts already in a result
35
+ - `children` - content in the centre of `ring` (other variants ignore it)
36
+ - `locale`, `dictionary` - i18n overrides for this component only
37
+ - `className`, `style`, `ref` and other `<span>` props go to `.kpt-loader`; `hostProps` to the wrapper
38
+
39
+ ## Examples
40
+ <KptLoader />
41
+ <KptLoader variant="bridge" status={saving ? 'loading' : 'success'} onSettled={() => setShown(false)} />
42
+ <KptLoader variant="wave" value={uploaded} max={total} />
43
+ <KptLoader variant="ring" status={status}><KptIcon name="download" /></KptLoader>
44
+ <KptLoader variant="bounce" colors={['danger', 'oklch(0.6 0.2 300)']} speed={1.5} />
45
+
46
+ ## Tokens
47
+ Roles resolve to `--kpt-color-<role>`, marks on filled shapes to `--kpt-color-<role>-contrast`
48
+ (a custom colour gets `--kpt-color-surface`), the `shapes` backdrop to `--kpt-color-<role>-subtle`;
49
+ tracks `--kpt-color-border`, shadows `--kpt-color-overlay-scrim`.
50
+
51
+ ## Motion and accessibility
52
+ One `requestAnimationFrame` loop per loader, stopped off-screen and after the result.
53
+ `<KptMotionProvider enabled={false}>` and the system "reduce motion" setting slow the loop down and
54
+ replace the choreography with the mark in a circle. The drawing is `aria-hidden`; a visually hidden
55
+ `role="status"` region gets the label a frame after mount, then the result text. While `ring` or
56
+ `wave` draws progress the stage is a `role="progressbar"` with `aria-valuenow` 0-100.
@@ -0,0 +1,49 @@
1
+ import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
+ import { type KptLoaderColor, type KptLoaderResult, type KptLoaderStatus, type KptLoaderVariant } from '@konce-pt/motion';
3
+ import type { KptHostProps } from '../internal/types.ts';
4
+ import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
5
+ export type { KptLoaderColor, KptLoaderResult, KptLoaderStatus, KptLoaderVariant } from '@konce-pt/motion';
6
+ export interface KptLoaderProps extends Omit<ComponentPropsWithRef<'span'>, 'children'>, KptI18nOverrides {
7
+ /** Materiał pętli. Domyślnie `bubbles`. */
8
+ variant?: KptLoaderVariant;
9
+ /** `loading` - pętla; `success` / `error` - choreografia wyniku i znak, który zostaje. */
10
+ status?: KptLoaderStatus;
11
+ /** Postęp (`ring`, `wave`); `null` = nieokreślony. Zakres jak w `KptProgress`. */
12
+ value?: number | null;
13
+ min?: number;
14
+ max?: number;
15
+ /** Długość 100 jednostek rysunku (CSS). Wszystkie warianty dzielą skalę. Domyślnie `5rem`. */
16
+ size?: string;
17
+ /** Barwy pętli - role motywu (`primary`, `info`, ...) albo kolory CSS; powtarzane po kolei. */
18
+ colors?: readonly KptLoaderColor[] | null;
19
+ successColor?: KptLoaderColor;
20
+ errorColor?: KptLoaderColor;
21
+ /** Mnożnik tempa pętli. Domyślnie 1. */
22
+ speed?: number;
23
+ /** Etykieta a11y w trakcie; pominięta = `loader.label`. */
24
+ label?: string;
25
+ /** Napis sukcesu (region statusu i kapsuła `bridge`); pominięty = `loader.success`. */
26
+ successLabel?: string;
27
+ /** Napis błędu; pominięty = `loader.error`. */
28
+ errorLabel?: string;
29
+ /** `false` - bez własnego regionu statusu (stan ogłasza komponent wokół, np. `KptUpdate`). */
30
+ announce?: boolean;
31
+ /** Koniec choreografii wyniku - dobry moment, żeby schować loader. */
32
+ onSettled?: (result: KptLoaderResult) => void;
33
+ /** Treść w środku pierścienia (`ring`) - np. ikona. */
34
+ children?: ReactNode;
35
+ /** Propsy wrappera `kpt-loader-host` (odpowiednik hosta Angulara). */
36
+ hostProps?: KptHostProps<'span'>;
37
+ }
38
+ /**
39
+ * Loader z charakterem: pętla w jednym z sześciu materiałów, która przy `status` `success` albo
40
+ * `error` przechodzi w znak wyniku zamiast znikać. Te same klasy co `kpt-loader` w Angularze,
41
+ * a rysunek i choreografię daje `createLoader` z `@konce-pt/motion` - wspólne dla obu portów.
42
+ *
43
+ * @example
44
+ * <KptLoader />
45
+ * <KptLoader variant="bridge" status={saving ? 'loading' : 'success'} />
46
+ * <KptLoader variant="wave" value={uploaded} max={total} />
47
+ * <KptLoader variant="ring" status={status}><KptIcon name="download" /></KptLoader>
48
+ */
49
+ export declare function KptLoader({ variant, status, value, min, max, size, colors, successColor, errorColor, speed, label, successLabel, errorLabel, announce, onSettled, locale, dictionary, children, hostProps, className, style, ...rest }: Readonly<KptLoaderProps>): import("react").JSX.Element;
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useEffectEvent, useRef, useState } from 'react';
4
+ import { createLoader, loaderProgress, } from '@konce-pt/motion';
5
+ import { cn } from "../internal/cn.js";
6
+ import { useKptMessages } from "../i18n/i18n-context.js";
7
+ import { useKptMotion } from "../motion/motion-context.js";
8
+ /**
9
+ * Loader z charakterem: pętla w jednym z sześciu materiałów, która przy `status` `success` albo
10
+ * `error` przechodzi w znak wyniku zamiast znikać. Te same klasy co `kpt-loader` w Angularze,
11
+ * a rysunek i choreografię daje `createLoader` z `@konce-pt/motion` - wspólne dla obu portów.
12
+ *
13
+ * @example
14
+ * <KptLoader />
15
+ * <KptLoader variant="bridge" status={saving ? 'loading' : 'success'} />
16
+ * <KptLoader variant="wave" value={uploaded} max={total} />
17
+ * <KptLoader variant="ring" status={status}><KptIcon name="download" /></KptLoader>
18
+ */
19
+ export function KptLoader({ variant = 'bubbles', status = 'loading', value = null, min = 0, max = 100, size = '5rem', colors = null, successColor = 'success', errorColor = 'danger', speed = 1, label, successLabel, errorLabel, announce = true, onSettled, locale, dictionary, children, hostProps, className, style, ...rest }) {
20
+ const { t } = useKptMessages({ locale, dictionary });
21
+ const motion = useKptMotion();
22
+ const stageRef = useRef(null);
23
+ const contentRef = useRef(null);
24
+ const controllerRef = useRef(null);
25
+ const [ready, setReady] = useState(false);
26
+ const effectiveLabel = label ?? t('loader.label');
27
+ const successText = successLabel ?? t('loader.success');
28
+ const errorText = errorLabel ?? t('loader.error');
29
+ const progress = loaderProgress(value, min, max);
30
+ // Postęp widać tylko w `ring` i `wave` - tylko tam loader jest paskiem postępu dla czytnika.
31
+ const determinate = status === 'loading' && progress !== null && (variant === 'ring' || variant === 'wave');
32
+ const reduced = motion?.enabled === false;
33
+ const settled = useEffectEvent((result) => onSettled?.(result));
34
+ // Najświeższe opcje dla efektów - bez przepisywania refa w trakcie renderu.
35
+ const currentOptions = useEffectEvent(() => ({
36
+ variant,
37
+ status,
38
+ progress,
39
+ colors,
40
+ successColor,
41
+ errorColor,
42
+ successText,
43
+ errorText,
44
+ speed,
45
+ reduced,
46
+ onSettled: (result) => settled(result),
47
+ }));
48
+ useEffect(() => {
49
+ if (!stageRef.current)
50
+ return;
51
+ const controller = createLoader(stageRef.current, contentRef.current, currentOptions());
52
+ controllerRef.current = controller;
53
+ // Tekst regionu statusu wpisujemy klatkę po pojawieniu się - pusty region nie jest ogłaszany.
54
+ const frame = requestAnimationFrame(() => setReady(true));
55
+ return () => {
56
+ cancelAnimationFrame(frame);
57
+ controller.destroy();
58
+ controllerRef.current = null;
59
+ };
60
+ }, []);
61
+ const colorsKey = (colors ?? []).join('|');
62
+ useEffect(() => {
63
+ controllerRef.current?.update(currentOptions());
64
+ }, [variant, status, progress, colorsKey, successColor, errorColor, successText, errorText, speed, reduced]);
65
+ const announced = !ready ? '' : status === 'success' ? successText : status === 'error' ? errorText : effectiveLabel;
66
+ const { className: hostClassName, ...hostRest } = hostProps ?? {};
67
+ return (_jsx("span", { className: cn('kpt-loader-host', hostClassName), ...hostRest, children: _jsxs("span", { className: cn('kpt-loader', className), "data-variant": variant, "data-status": status, style: { '--_size': size, ...style }, ...rest, children: [_jsx("span", { ref: stageRef, className: "kpt-loader__stage", role: determinate ? 'progressbar' : undefined, "aria-hidden": determinate ? undefined : true, "aria-label": determinate ? effectiveLabel : undefined, "aria-valuemin": determinate ? 0 : undefined, "aria-valuemax": determinate ? 100 : undefined, "aria-valuenow": determinate ? Math.round((progress ?? 0) * 100) : undefined }), _jsx("span", { ref: contentRef, className: "kpt-loader__content", children: children }), announce ? (_jsx("span", { className: "kpt-loader__label", role: "status", children: announced })) : null] }) }));
68
+ }
package/dist/map/llms.txt CHANGED
@@ -9,34 +9,37 @@ interface.
9
9
  Import: `import { KptMap, createLeafletEngine } from '@konce-pt/react/map';`
10
10
 
11
11
  ## Requirements
12
- 1. The **optional** `leaflet` dependency — the library does not install it: `pnpm add leaflet`
12
+ 1. The **optional** `leaflet` dependency - the library does not install it: `pnpm add leaflet`
13
13
  2. Its stylesheet: `import 'leaflet/dist/leaflet.css';`
14
14
  3. An engine factory on the `engine` prop: `engine={() => createLeafletEngine()}`
15
15
 
16
16
  Leaflet is loaded with a dynamic `import()`, so an app that never renders a map does not download
17
- it. Without the package the component still imports and compiles — only rendering the map ends with
17
+ it. Without the package the component still imports and compiles - only rendering the map ends with
18
18
  a readable message.
19
19
 
20
20
  ## Props
21
- - `locations`: `readonly KptMapLocation<T>[]` — **required**
22
- - `categories`: `readonly KptMapCategory[]` — **required**
23
- - `engine`: `KptMapEngineFactory` — **required**; a factory, not an instance, because every map
21
+ - `locations`: `readonly KptMapLocation<T>[]` - **required**
22
+ - `categories`: `readonly KptMapCategory[]` - **required**
23
+ - `engine`: `KptMapEngineFactory` - **required**; a factory, not an instance, because every map
24
24
  needs its own object. Read once, at mount.
25
- - `country`: string = `'PL'` — the initial view preset; an unknown code falls back to Poland
26
- - `view`, `bounds` — an explicit view or extent; they override `country`
27
- - `restrictToCountry`: boolean — blocks panning outside the country's bounds
25
+ - `country`: string = `'PL'` - the initial view preset; an unknown code falls back to Poland
26
+ - `view`, `bounds` - an explicit view or extent; they override `country`
27
+ - `restrictToCountry`: boolean - blocks panning outside the country's bounds
28
28
  - `cluster`: boolean = true, `clusterOptions`, `clusterColorBy`: `'dominant' | 'none'`
29
29
  - `legend`, `legendCounts`: boolean = true
30
- - `hiddenCategories` / `defaultHiddenCategories` / `onHiddenCategoriesChange` — the ids hidden in
30
+ - `hiddenCategories` / `defaultHiddenCategories` / `onHiddenCategoriesChange` - the ids hidden in
31
31
  the legend, controlled or uncontrolled
32
32
  - `showUserLocation`, `followUser`: boolean; `geolocation`: `KptMapGeolocationPort | null`
33
- - `allowCreate`: boolean — the "Add location" menu under the right mouse button
33
+ - `allowCreate`: boolean - the "Add location" menu under the right mouse button
34
34
  - `search`: boolean, `searchPlaceholder`, `searchOptions`, `searchZoom`, `searchMarker`
35
- - `geocoder`: `KptMapGeocoderPort | null` — this map's geocoder; it feeds both the search and the
35
+ - `searchSpeech`: boolean = false - a microphone in the search field: a click clears the phrase and one
36
+ spoken utterance becomes the query (same `debounce`/`minLength` as typing); `searchSpeechLang`: string -
37
+ its language (BCP 47); `searchSpeechColor` - listening colour (theme colour by default). Hidden without browser support. `KptMapSearch` on its own takes `speech` / `speechLang` / `speechColor`
38
+ - `geocoder`: `KptMapGeocoderPort | null` - this map's geocoder; it feeds both the search and the
36
39
  address suggestions in the create form
37
40
  - `popupLayout`: `'plain' | 'card'`; `distanceFrom`: `KptLatLng | null`
38
41
  - `height`: string = `'480px'`; `tileUrl`, `attribution` (ignored by the Google engine)
39
- - `renderPopup`, `renderCreateForm` — see below
42
+ - `renderPopup`, `renderCreateForm` - see below
40
43
  - `className`, `ref` and every other `<div>` prop go to the host
41
44
 
42
45
  ## Events
@@ -47,12 +50,12 @@ a readable message.
47
50
  the error is also logged to the console. `followUser` and the position callbacks are read fresh on every
48
51
  fix, so changing them does not restart the geolocation watch.
49
52
 
50
- `onLocationCreate` gives `{ at, categoryId, value }` — the component appends **nothing** to
53
+ `onLocationCreate` gives `{ at, categoryId, value }` - the component appends **nothing** to
51
54
  `locations`; the application is the source of truth.
52
55
 
53
56
  ## Render props instead of templates
54
- The Angular port picks a popup template per category (`kptMapPopup category="…"`). React has one
55
- prop and a `switch`: `renderPopup({ location, data, category, distance, close })` — the category
57
+ The Angular port picks a popup template per category (`kptMapPopup category="..."`). React has one
58
+ prop and a `switch`: `renderPopup({ location, data, category, distance, close })` - the category
56
59
  travels in the context, and the type of `data` follows the map's generic without an extra input.
57
60
 
58
61
  <KptMap
@@ -68,7 +71,7 @@ travels in the context, and the type of `data` follows the map's generic without
68
71
 
69
72
  ## Ports are props, not DI
70
73
  Angular injects `KPT_MAP_ENGINE`, `KPT_MAP_GEOCODER` and `KPT_MAP_GEOLOCATION`. React has no
71
- injector, so all three arrive as props — and the geocoder was already per-map in Angular for a
74
+ injector, so all three arrive as props - and the geocoder was already per-map in Angular for a
72
75
  licensing reason (a Google geocoder may only be paired with a Google map), so nothing is lost.
73
76
 
74
77
  The ports themselves are promise-shaped rather than `Observable`-shaped: `reverse()`, `search()`
@@ -76,7 +79,7 @@ and `resolve()` return promises and take an `AbortSignal`, which is what `fetch`
76
79
 
77
80
  import { createNominatimGeocoder, browserGeolocation } from '@konce-pt/react/map';
78
81
 
79
- <KptMap geocoder={createNominatimGeocoder()} geolocation={browserGeolocation()} … />
82
+ <KptMap geocoder={createNominatimGeocoder()} geolocation={browserGeolocation()} ... />
80
83
 
81
84
  `createGeocoderStub()` and `geolocationStub(at)` cover demos and tests.
82
85
 
@@ -87,18 +90,18 @@ second mount waits for the first teardown to finish, instead of failing with "Ma
87
90
  already initialized".
88
91
 
89
92
  ## Sub-components
90
- - `KptMapLegend` — the legend on its own, when you want it somewhere other than under the map
93
+ - `KptMapLegend` - the legend on its own, when you want it somewhere other than under the map
91
94
  (`hiddenCategories` instead of Angular's `hidden`: `hidden` on a DOM element is a boolean and
92
95
  would clash with the `<div>` prop)
93
- - `KptMapPoiCard` — the ready-made place card for `popupLayout="card"`
94
- - `KptMapSearch` — the address field alone
95
- - `KptMapCreateDialog`, `KptMapHoursField`, `KptMapImageField` — the schema-built form and its two
96
+ - `KptMapPoiCard` - the ready-made place card for `popupLayout="card"`
97
+ - `KptMapSearch` - the address field alone
98
+ - `KptMapCreateDialog`, `KptMapHoursField`, `KptMapImageField` - the schema-built form and its two
96
99
  non-trivial field types
97
100
 
98
101
  ## Validation without a form framework
99
102
  The create dialog is built from `category.fields`. The Angular port stands on Signal Forms; here the
100
103
  model is plain state and the rules are a map of functions beside it. The contract is the same:
101
- declared once with the schema, and the "do not shout in red" gate lives in presentation — an error
104
+ declared once with the schema, and the "do not shout in red" gate lives in presentation - an error
102
105
  shows after the field is touched or after a failed submit.
103
106
 
104
107
  ## Tokens