@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
@@ -0,0 +1,74 @@
1
+ /*
2
+ * Ocena siły hasła dla miernika `kpt-password`. Bliźniak w porcie Angulara (`shared/password-strength.ts`) - zmiana w obu.
3
+ *
4
+ * Wynik idzie przede wszystkim za długością, a nie za regułami składu, które odradza NIST SP 800-63B:
5
+ * `Password1!` spełnia wszystkie "wielka, cyfra, znak specjalny", a jest jednym z najczęściej
6
+ * zgadywanych haseł, podczas gdy trzydzieści małych liter jest bardzo mocne. Liczymy przybliżoną
7
+ * entropię znak po znaku - z puli klas, które naprawdę wystąpiły - i obcinamy ją za powtórzenia,
8
+ * ciągi (`abcd`, `1234`, `qwerty`) i schemat "Słowo + cyfry + znak". Litery spoza ASCII
9
+ * (`ą`, `ż`) są literami, nie znakami specjalnymi. Bez słownika: to podpowiedź, nie zabezpieczenie.
10
+ */
11
+ const KEYBOARD_ROWS = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm', '1234567890'];
12
+ /** Pula znaków z klas, które wystąpiły w haśle. */
13
+ function poolSize(value) {
14
+ let pool = 0;
15
+ if (/\p{Ll}/u.test(value))
16
+ pool += 26;
17
+ if (/\p{Lu}/u.test(value))
18
+ pool += 26;
19
+ if (/\p{N}/u.test(value))
20
+ pool += 10;
21
+ if (/[^\P{L}\p{Ll}\p{Lu}]/u.test(value))
22
+ pool += 40; // litery bez wielkości (np. CJK)
23
+ if (/[^\p{L}\p{N}]/u.test(value))
24
+ pool += 33;
25
+ return Math.max(pool, 10);
26
+ }
27
+ /** Czy `b` stoi zaraz po `a` w alfabecie, cyfrach albo rzędzie klawiatury (w dowolną stronę). */
28
+ function isSequential(a, b) {
29
+ const diff = Math.abs(b.codePointAt(0) - a.codePointAt(0));
30
+ if (diff === 1 && /[\p{L}\p{N}]/u.test(a + b))
31
+ return true;
32
+ const pair = (a + b).toLowerCase();
33
+ const reversed = (b + a).toLowerCase();
34
+ return KEYBOARD_ROWS.some((row) => row.includes(pair) || row.includes(reversed));
35
+ }
36
+ /** Przybliżona entropia w bitach. */
37
+ export function kptPasswordBits(value) {
38
+ if (!value)
39
+ return 0;
40
+ // "Słowo + cyfry + znak" (`Password1!`, `Kwiatek2024`) to pierwsze, co zgaduje atakujący -
41
+ // liczymy je jak samo słowo pisane małymi literami.
42
+ const pattern = /^(\p{Lu}?\p{Ll}+)(\p{N}{0,4})([^\p{L}\p{N}]{0,2})$/u.exec(value);
43
+ const chars = [...(pattern ? pattern[1] : value)];
44
+ const perChar = Math.log2(pattern ? 26 : poolSize(value));
45
+ let bits = 0;
46
+ for (let i = 0; i < chars.length; i += 1) {
47
+ const prev = chars[i - 1];
48
+ if (prev === undefined)
49
+ bits += perChar;
50
+ else if (chars[i] === prev)
51
+ bits += 0.5; // aaaa
52
+ else if (isSequential(prev, chars[i]))
53
+ bits += 1; // abcd, 1234, qwerty
54
+ else
55
+ bits += perChar;
56
+ }
57
+ // Doklejone cyfry i znak w schemacie to kilka bitów, nie pełna pula.
58
+ if (pattern)
59
+ bits += pattern[2].length * 2 + pattern[3].length * 3;
60
+ return bits;
61
+ }
62
+ /** Wynik 0-4 z entropii: <28 bardzo słabe, <36 słabe, <50 średnie, <64 dobre, reszta silne. */
63
+ export function kptPasswordScore(value) {
64
+ const bits = kptPasswordBits(value);
65
+ if (bits < 28)
66
+ return 0;
67
+ if (bits < 36)
68
+ return 1;
69
+ if (bits < 50)
70
+ return 2;
71
+ if (bits < 64)
72
+ return 3;
73
+ return 4;
74
+ }
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Indeks elementu, na który ma przejść fokus po klawiszu `key`. `disabled[i]` mówi, czy element
3
- * `i` jest wyłączony — takie są pomijane. Strzałki zawijają się na końcach, `Home`/`End` idą do
3
+ * `i` jest wyłączony - takie są pomijane. Strzałki zawijają się na końcach, `Home`/`End` idą do
4
4
  * pierwszego/ostatniego aktywnego. Zwraca `null` dla klawisza, który nie nawiguje, albo gdy nie ma
5
5
  * dokąd przejść.
6
6
  */
7
7
  export declare function nextRovingIndex(disabled: readonly boolean[], current: number, key: string): number | null;
8
- /** Pierwszy aktywny indeks od `preferred` — przystanek Tab, gdy wskazany element jest wyłączony. */
8
+ /** Pierwszy aktywny indeks od `preferred` - przystanek Tab, gdy wskazany element jest wyłączony. */
9
9
  export declare function rovingStop(disabled: readonly boolean[], preferred: number): number;
@@ -1,11 +1,11 @@
1
1
  /*
2
- * Nawigacja strzałkami po poziomym rzędzie z jednym przystankiem Tab („roving tabindex”) —
2
+ * Nawigacja strzałkami po poziomym rzędzie z jednym przystankiem Tab ("roving tabindex") -
3
3
  * wspólna dla `KptTabs`, `KptMenubar` i `KptMegamenu`. Port Angulara ma bliźniaczy plik
4
4
  * `shared/roving.ts`.
5
5
  */
6
6
  /**
7
7
  * Indeks elementu, na który ma przejść fokus po klawiszu `key`. `disabled[i]` mówi, czy element
8
- * `i` jest wyłączony — takie są pomijane. Strzałki zawijają się na końcach, `Home`/`End` idą do
8
+ * `i` jest wyłączony - takie są pomijane. Strzałki zawijają się na końcach, `Home`/`End` idą do
9
9
  * pierwszego/ostatniego aktywnego. Zwraca `null` dla klawisza, który nie nawiguje, albo gdy nie ma
10
10
  * dokąd przejść.
11
11
  */
@@ -34,7 +34,7 @@ export function nextRovingIndex(disabled, current, key) {
34
34
  return null;
35
35
  }
36
36
  }
37
- /** Pierwszy aktywny indeks od `preferred` — przystanek Tab, gdy wskazany element jest wyłączony. */
37
+ /** Pierwszy aktywny indeks od `preferred` - przystanek Tab, gdy wskazany element jest wyłączony. */
38
38
  export function rovingStop(disabled, preferred) {
39
39
  if (preferred >= 0 && preferred < disabled.length && !disabled[preferred])
40
40
  return preferred;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Blokuje przewijanie dokumentu i zwraca funkcję zdejmującą tę jedną blokadę. Licznik pozwala
3
+ * zagnieżdżać okna (szuflada -> dialog): przewijanie wraca dopiero po zdjęciu ostatniej.
4
+ * `scrollbar-gutter: stable` trzyma miejsce po pasku przewijania, więc treść nie przeskakuje w bok.
5
+ */
6
+ export declare function kptLockScroll(): () => void;
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Blokada przewijania strony pod oknem modalnym. `showModal()` blokuje interakcję z tłem, ale nie
3
+ * jego przewijanie - kółko myszy dalej przesuwa stronę. Bliźniak w porcie Angulara (`shared/scroll-lock.ts`) - zmiana w obu.
4
+ */
5
+ let locks = 0;
6
+ let savedOverflow = '';
7
+ let savedGutter = '';
8
+ /**
9
+ * Blokuje przewijanie dokumentu i zwraca funkcję zdejmującą tę jedną blokadę. Licznik pozwala
10
+ * zagnieżdżać okna (szuflada -> dialog): przewijanie wraca dopiero po zdjęciu ostatniej.
11
+ * `scrollbar-gutter: stable` trzyma miejsce po pasku przewijania, więc treść nie przeskakuje w bok.
12
+ */
13
+ export function kptLockScroll() {
14
+ if (typeof document === 'undefined')
15
+ return () => undefined;
16
+ const root = document.documentElement;
17
+ if (locks === 0) {
18
+ savedOverflow = root.style.overflow;
19
+ savedGutter = root.style.scrollbarGutter;
20
+ root.style.overflow = 'hidden';
21
+ root.style.scrollbarGutter = 'stable';
22
+ }
23
+ locks += 1;
24
+ let released = false;
25
+ return () => {
26
+ if (released)
27
+ return;
28
+ released = true;
29
+ locks -= 1;
30
+ if (locks === 0) {
31
+ root.style.overflow = savedOverflow;
32
+ root.style.scrollbarGutter = savedGutter;
33
+ }
34
+ };
35
+ }
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Dzieci komponentu ze slotami, z rozwiniętymi fragmentami. `Children.forEach` traktuje
4
+ * `<>...</>` jak jedno dziecko, więc slot owinięty we fragment (np. z warunku
5
+ * `{admin && <><KptTab .../><KptTab .../></>}`) był dla komponentu niewidoczny. Rozwijamy fragmenty
6
+ * rekurencyjnie; `null`, `false` i puste napisy odpadają tak jak w `Children.forEach`.
7
+ */
8
+ export declare function slotChildren(children: ReactNode): ReactNode[];
9
+ /**
10
+ * Ostrzeżenie deweloperskie o dziecku, które komponent przyjmujący wyłącznie sloty pominie.
11
+ * Białe znaki między tagami (`"\n "`) nie są pomyłką - te przemilczamy.
12
+ */
13
+ export declare function warnUnslottedChild(component: string, child: ReactNode, expected: string): void;
@@ -0,0 +1,31 @@
1
+ import { Children, Fragment, isValidElement } from 'react';
2
+ import { isDevBuild } from "./dev.js";
3
+ /**
4
+ * Dzieci komponentu ze slotami, z rozwiniętymi fragmentami. `Children.forEach` traktuje
5
+ * `<>...</>` jak jedno dziecko, więc slot owinięty we fragment (np. z warunku
6
+ * `{admin && <><KptTab .../><KptTab .../></>}`) był dla komponentu niewidoczny. Rozwijamy fragmenty
7
+ * rekurencyjnie; `null`, `false` i puste napisy odpadają tak jak w `Children.forEach`.
8
+ */
9
+ export function slotChildren(children) {
10
+ const out = [];
11
+ Children.forEach(children, (child) => {
12
+ if (isValidElement(child) && child.type === Fragment) {
13
+ out.push(...slotChildren(child.props.children));
14
+ }
15
+ else if (child !== null && child !== undefined && typeof child !== 'boolean') {
16
+ out.push(child);
17
+ }
18
+ });
19
+ return out;
20
+ }
21
+ /**
22
+ * Ostrzeżenie deweloperskie o dziecku, które komponent przyjmujący wyłącznie sloty pominie.
23
+ * Białe znaki między tagami (`"\n "`) nie są pomyłką - te przemilczamy.
24
+ */
25
+ export function warnUnslottedChild(component, child, expected) {
26
+ if (!isDevBuild())
27
+ return;
28
+ if (typeof child === 'string' && child.trim() === '')
29
+ return;
30
+ console.warn(`[${component}] Pominięto dziecko, które nie jest slotem - użyj ${expected}.`, child);
31
+ }
@@ -3,18 +3,18 @@ type AnyProps = Record<string, unknown>;
3
3
  /**
4
4
  * Scala propsy slotu z propsami dziecka. Zasady, w kolejności ważności:
5
5
  * handlery są komponowane (najpierw dziecka, potem slotu), `className` sklejane,
6
- * `style` nakładane (dziecko wygrywa), `ref` łączony, reszta — dziecko nadpisuje slot.
6
+ * `style` nakładane (dziecko wygrywa), `ref` łączony, reszta - dziecko nadpisuje slot.
7
7
  */
8
8
  export declare function mergeSlotProps(slotProps: AnyProps, childProps: AnyProps): AnyProps;
9
9
  /**
10
10
  * Renderuje `child` z propsami slotu i podmienioną treścią. Używane przez komponenty,
11
- * które w trybie `asChild` muszą zachować własne opakowanie treści — na przykład
11
+ * które w trybie `asChild` muszą zachować własne opakowanie treści - na przykład
12
12
  * przycisk owija zawartość w `.kpt-button__content` niezależnie od tego, jakim
13
13
  * elementem ostatecznie jest.
14
14
  */
15
15
  export declare function renderAsChild(child: ReactElement, slotProps: AnyProps, content: ReactNode): ReactElement;
16
16
  export interface SlotProps {
17
- /** Dokładnie jeden element — to on przejmie propsy slotu. */
17
+ /** Dokładnie jeden element - to on przejmie propsy slotu. */
18
18
  children?: ReactNode;
19
19
  [prop: string]: unknown;
20
20
  }
@@ -4,7 +4,7 @@ import { composeRefs } from "./compose-refs.js";
4
4
  /**
5
5
  * Scala propsy slotu z propsami dziecka. Zasady, w kolejności ważności:
6
6
  * handlery są komponowane (najpierw dziecka, potem slotu), `className` sklejane,
7
- * `style` nakładane (dziecko wygrywa), `ref` łączony, reszta — dziecko nadpisuje slot.
7
+ * `style` nakładane (dziecko wygrywa), `ref` łączony, reszta - dziecko nadpisuje slot.
8
8
  */
9
9
  export function mergeSlotProps(slotProps, childProps) {
10
10
  const merged = { ...slotProps };
@@ -33,7 +33,7 @@ export function mergeSlotProps(slotProps, childProps) {
33
33
  }
34
34
  /**
35
35
  * Renderuje `child` z propsami slotu i podmienioną treścią. Używane przez komponenty,
36
- * które w trybie `asChild` muszą zachować własne opakowanie treści — na przykład
36
+ * które w trybie `asChild` muszą zachować własne opakowanie treści - na przykład
37
37
  * przycisk owija zawartość w `.kpt-button__content` niezależnie od tego, jakim
38
38
  * elementem ostatecznie jest.
39
39
  */
@@ -0,0 +1,12 @@
1
+ /** Miejsca po przecinku w zapisie liczby, także wykładniczym (`0.25` -> 2, `1e-7` -> 7). */
2
+ export declare function kptDecimals(n: number): number;
3
+ /**
4
+ * Zaokrągla do precyzji, która nie gubi ani kroku, ani wartości bazowej: `0.1 + 0.2` nie może
5
+ * dać `0.30000000000000004`, a `1.25 + 1` musi dać `2.25`, nie `2`.
6
+ */
7
+ export declare function kptRoundTo(n: number, ...sources: number[]): number;
8
+ /**
9
+ * Przyciąga wartość do siatki `min + k,step` i przycina do zakresu. Siatka zaczyna się od `min`,
10
+ * nie od zera - przy `min=1, step=2` dozwolone są 1, 3, 5..., tak samo myszą jak klawiaturą.
11
+ */
12
+ export declare function kptSnapToStep(raw: number, min: number, max: number, step: number): number;
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Arytmetyka kroku kontrolek liczbowych (`kpt-input-number`, `kpt-knob`).
3
+ * Bliźniak w porcie Angulara (`shared/step.ts`) - zmiana w obu.
4
+ */
5
+ /** Miejsca po przecinku w zapisie liczby, także wykładniczym (`0.25` -> 2, `1e-7` -> 7). */
6
+ export function kptDecimals(n) {
7
+ if (!Number.isFinite(n))
8
+ return 0;
9
+ const [mantissa, exponent] = String(n).toLowerCase().split('e');
10
+ return Math.max(0, (mantissa.split('.')[1] ?? '').length - Number(exponent ?? 0));
11
+ }
12
+ /**
13
+ * Zaokrągla do precyzji, która nie gubi ani kroku, ani wartości bazowej: `0.1 + 0.2` nie może
14
+ * dać `0.30000000000000004`, a `1.25 + 1` musi dać `2.25`, nie `2`.
15
+ */
16
+ export function kptRoundTo(n, ...sources) {
17
+ const decimals = Math.min(20, Math.max(0, ...sources.map(kptDecimals)));
18
+ return Number(n.toFixed(decimals));
19
+ }
20
+ /**
21
+ * Przyciąga wartość do siatki `min + k,step` i przycina do zakresu. Siatka zaczyna się od `min`,
22
+ * nie od zera - przy `min=1, step=2` dozwolone są 1, 3, 5..., tak samo myszą jak klawiaturą.
23
+ */
24
+ export function kptSnapToStep(raw, min, max, step) {
25
+ if (!(step > 0))
26
+ return Math.min(max, Math.max(min, raw));
27
+ const snapped = kptRoundTo(min + Math.round((raw - min) / step) * step, step, min);
28
+ if (snapped > max)
29
+ return kptRoundTo(max - ((max - min) % step), step, min);
30
+ return Math.max(min, snapped);
31
+ }
@@ -1,17 +1,17 @@
1
1
  /**
2
- * Płynne dojście liczby do celu — dla kontrolek, które pokazują wartość rysunkiem (łuk pokrętła)
2
+ * Płynne dojście liczby do celu - dla kontrolek, które pokazują wartość rysunkiem (łuk pokrętła)
3
3
  * i licznikiem. Pure TS bez frameworka; bliźniak portu Angulara: `shared/tween.ts`.
4
4
  *
5
5
  * Bez animacji, gdy użytkownik prosi o ograniczenie ruchu (`prefers-reduced-motion`) albo gdy nie
6
- * ma `requestAnimationFrame` (render po stronie serwera) — wtedy cel ustawia się od razu.
6
+ * ma `requestAnimationFrame` (render po stronie serwera) - wtedy cel ustawia się od razu.
7
7
  */
8
- /** Czy animować — reguła wspólna dla wszystkich kontrolek, żeby „mniej ruchu" działało wszędzie. */
8
+ /** Czy animować - reguła wspólna dla wszystkich kontrolek, żeby "mniej ruchu" działało wszędzie. */
9
9
  export declare function kptMotionAllowed(): boolean;
10
10
  /**
11
11
  * Animuje od `from` do `to` przez `duration` ms, wołając `onFrame` z wartością pośrednią.
12
- * Zwraca funkcję przerwania — kolejny skok przerywa poprzedni i rusza z miejsca, w którym ten był,
12
+ * Zwraca funkcję przerwania - kolejny skok przerywa poprzedni i rusza z miejsca, w którym ten był,
13
13
  * więc szybkie stuknięcia strzałką nie cofają łuku do startu.
14
14
  */
15
15
  export declare function kptTween(from: number, to: number, duration: number, onFrame: (value: number) => void): () => void;
16
- /** Liczba miejsc po przecinku kroku (`0.25` → 2) — licznik w trakcie animacji nie pokazuje szumu. */
16
+ /** Liczba miejsc po przecinku kroku (`0.25` -> 2) - licznik w trakcie animacji nie pokazuje szumu. */
17
17
  export declare function kptStepDecimals(step: number): number;
@@ -1,13 +1,14 @@
1
1
  /**
2
- * Płynne dojście liczby do celu — dla kontrolek, które pokazują wartość rysunkiem (łuk pokrętła)
2
+ * Płynne dojście liczby do celu - dla kontrolek, które pokazują wartość rysunkiem (łuk pokrętła)
3
3
  * i licznikiem. Pure TS bez frameworka; bliźniak portu Angulara: `shared/tween.ts`.
4
4
  *
5
5
  * Bez animacji, gdy użytkownik prosi o ograniczenie ruchu (`prefers-reduced-motion`) albo gdy nie
6
- * ma `requestAnimationFrame` (render po stronie serwera) — wtedy cel ustawia się od razu.
6
+ * ma `requestAnimationFrame` (render po stronie serwera) - wtedy cel ustawia się od razu.
7
7
  */
8
+ import { kptDecimals } from "./step.js";
8
9
  /** Zwolnienie pod koniec (ease-out cubic): ruch rusza od razu i dojeżdża miękko. */
9
10
  const easeOut = (t) => 1 - (1 - t) ** 3;
10
- /** Czy animować — reguła wspólna dla wszystkich kontrolek, żeby „mniej ruchu" działało wszędzie. */
11
+ /** Czy animować - reguła wspólna dla wszystkich kontrolek, żeby "mniej ruchu" działało wszędzie. */
11
12
  export function kptMotionAllowed() {
12
13
  if (typeof requestAnimationFrame === 'undefined')
13
14
  return false;
@@ -15,7 +16,7 @@ export function kptMotionAllowed() {
15
16
  }
16
17
  /**
17
18
  * Animuje od `from` do `to` przez `duration` ms, wołając `onFrame` z wartością pośrednią.
18
- * Zwraca funkcję przerwania — kolejny skok przerywa poprzedni i rusza z miejsca, w którym ten był,
19
+ * Zwraca funkcję przerwania - kolejny skok przerywa poprzedni i rusza z miejsca, w którym ten był,
19
20
  * więc szybkie stuknięcia strzałką nie cofają łuku do startu.
20
21
  */
21
22
  export function kptTween(from, to, duration, onFrame) {
@@ -32,9 +33,7 @@ export function kptTween(from, to, duration, onFrame) {
32
33
  });
33
34
  return () => cancelAnimationFrame(frame);
34
35
  }
35
- /** Liczba miejsc po przecinku kroku (`0.25` → 2) — licznik w trakcie animacji nie pokazuje szumu. */
36
+ /** Liczba miejsc po przecinku kroku (`0.25` -> 2) - licznik w trakcie animacji nie pokazuje szumu. */
36
37
  export function kptStepDecimals(step) {
37
- const text = String(step);
38
- const dot = text.indexOf('.');
39
- return dot === -1 ? 0 : text.length - dot - 1;
38
+ return kptDecimals(step);
40
39
  }
@@ -3,12 +3,12 @@ import type { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';
3
3
  * Propsy wrappera hosta. Port odtwarza dwupoziomowy DOM Angulara
4
4
  * (`<kpt-button class="kpt-button-host">` wokół `<button class="kpt-button">`),
5
5
  * bo host niesie własne style. `className` i `ref` komponentu trafiają na element
6
- * wewnętrzny — wrapper konfiguruje się właśnie tym propem.
6
+ * wewnętrzny - wrapper konfiguruje się właśnie tym propem.
7
7
  */
8
8
  export type KptHostProps<E extends ElementType = 'span'> = Omit<ComponentPropsWithoutRef<E>, 'children'> & {
9
9
  /**
10
10
  * Atrybuty `data-*` hosta. JSX przepuszcza je na elementach wbudowanych sam z siebie,
11
- * ale ten typ opisuje zwykły obiekt — bez tego wpisu stan wariantu, który w Angularze
11
+ * ale ten typ opisuje zwykły obiekt - bez tego wpisu stan wariantu, który w Angularze
12
12
  * siedzi na hoście (`[attr.data-on]`), nie miałby jak tam trafić.
13
13
  */
14
14
  [key: `data-${string}`]: string | number | boolean | undefined;
@@ -1,7 +1,7 @@
1
1
  /** Nazwa breakpointa z tokenów `--kpt-breakpoint-*` (mobile-first). */
2
2
  export type KptBreakpoint = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
3
3
  /**
4
- * Progi breakpointów w pikselach — czytane wprost z `@konce-pt/tokens`, więc nie da się
4
+ * Progi breakpointów w pikselach - czytane wprost z `@konce-pt/tokens`, więc nie da się
5
5
  * ich rozjechać z `@media` biblioteki ani z portem Angulara (tam ta sama tabela powstaje
6
6
  * w kroku generowania).
7
7
  */
@@ -11,7 +11,7 @@ export declare function useKptMediaQuery(query: string): boolean;
11
11
  /**
12
12
  * Czy viewport ma szerokość co najmniej danego breakpointa (mobile-first).
13
13
  *
14
- * O UKŁADZIE komponentów decyduje wyłącznie CSS — ten hook odpowiada tylko za zachowania,
14
+ * O UKŁADZIE komponentów decyduje wyłącznie CSS - ten hook odpowiada tylko za zachowania,
15
15
  * których CSS nie wyrazi (np. w którą stronę ma zadziałać przycisk). Dzięki temu nic nie
16
16
  * migocze przed hydracją.
17
17
  */
@@ -2,7 +2,7 @@ import { useSyncExternalStore } from 'react';
2
2
  import { KPT_BREAKPOINT_2XL, KPT_BREAKPOINT_LG, KPT_BREAKPOINT_MD, KPT_BREAKPOINT_SM, KPT_BREAKPOINT_XL, } from '@konce-pt/tokens';
3
3
  const toPx = (value) => Number.parseFloat(value);
4
4
  /**
5
- * Progi breakpointów w pikselach — czytane wprost z `@konce-pt/tokens`, więc nie da się
5
+ * Progi breakpointów w pikselach - czytane wprost z `@konce-pt/tokens`, więc nie da się
6
6
  * ich rozjechać z `@media` biblioteki ani z portem Angulara (tam ta sama tabela powstaje
7
7
  * w kroku generowania).
8
8
  */
@@ -15,7 +15,7 @@ export const KPT_BREAKPOINTS = {
15
15
  };
16
16
  /**
17
17
  * Jeden `MediaQueryList` i jeden nasłuch na zapytanie, współdzielone przez wszystkie
18
- * komponenty — tak samo jak memoizacja w `KptBreakpointObserver` po stronie Angulara.
18
+ * komponenty - tak samo jak memoizacja w `KptBreakpointObserver` po stronie Angulara.
19
19
  */
20
20
  const stores = new Map();
21
21
  /**
@@ -27,7 +27,7 @@ function storeFor(query) {
27
27
  const cached = stores.get(query);
28
28
  if (cached)
29
29
  return cached;
30
- // Sam brak `window` nie wystarcza: jsdom go dostarcza, ale bez `matchMedia` — bez sprawdzenia
30
+ // Sam brak `window` nie wystarcza: jsdom go dostarcza, ale bez `matchMedia` - bez sprawdzenia
31
31
  // metody każdy test dotykający `KptAppShell` wywala się na TypeError. Wyniku nie zapisujemy
32
32
  // w cache'u, żeby stub podstawiony później (typowy `setup` testów) został podchwycony.
33
33
  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function')
@@ -51,7 +51,7 @@ export function useKptMediaQuery(query) {
51
51
  /**
52
52
  * Czy viewport ma szerokość co najmniej danego breakpointa (mobile-first).
53
53
  *
54
- * O UKŁADZIE komponentów decyduje wyłącznie CSS — ten hook odpowiada tylko za zachowania,
54
+ * O UKŁADZIE komponentów decyduje wyłącznie CSS - ten hook odpowiada tylko za zachowania,
55
55
  * których CSS nie wyrazi (np. w którą stronę ma zadziałać przycisk). Dzięki temu nic nie
56
56
  * migocze przed hydracją.
57
57
  */
@@ -3,6 +3,11 @@
3
3
  * i niekontrolowanym (`defaultValue` + stan wewnętrzny). Kontrakt jest ten sam
4
4
  * co w natywnych polach formularza, więc komponenty współpracują z natywnym
5
5
  * `<form>`, React 19 Actions i React Hook Form bez adapterów.
6
+ *
7
+ * `setValue` ma stałą tożsamość: rodzic przekazujący `onChange` jako funkcję inline nie restartuje
8
+ * efektów, które mają `setValue` w zależnościach. Przejście między trybami (`value` raz podane,
9
+ * raz `undefined`) działa jak w Reakcie - po cichu przełącza źródło - ale w buildzie deweloperskim
10
+ * ostrzega, tak jak React robi to dla `<input>`.
6
11
  */
7
12
  export declare function useControllableState<T>(options: {
8
13
  value: T | undefined;
@@ -1,18 +1,39 @@
1
- import { useCallback, useState } from 'react';
1
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+ import { isDevBuild } from "./dev.js";
2
3
  /**
3
4
  * Stan działający w obu trybach naraz: kontrolowanym (`value` podane z zewnątrz)
4
5
  * i niekontrolowanym (`defaultValue` + stan wewnętrzny). Kontrakt jest ten sam
5
6
  * co w natywnych polach formularza, więc komponenty współpracują z natywnym
6
7
  * `<form>`, React 19 Actions i React Hook Form bez adapterów.
8
+ *
9
+ * `setValue` ma stałą tożsamość: rodzic przekazujący `onChange` jako funkcję inline nie restartuje
10
+ * efektów, które mają `setValue` w zależnościach. Przejście między trybami (`value` raz podane,
11
+ * raz `undefined`) działa jak w Reakcie - po cichu przełącza źródło - ale w buildzie deweloperskim
12
+ * ostrzega, tak jak React robi to dla `<input>`.
7
13
  */
8
14
  export function useControllableState(options) {
9
15
  const { value, defaultValue, onChange } = options;
10
16
  const isControlled = value !== undefined;
11
17
  const [uncontrolled, setUncontrolled] = useState(defaultValue);
18
+ // Najświeższy tryb i callback dla stabilnego `setValue` - odświeżane po zatwierdzeniu renderu.
19
+ const latest = useRef({ isControlled, onChange });
20
+ useLayoutEffect(() => {
21
+ latest.current = { isControlled, onChange };
22
+ });
12
23
  const setValue = useCallback((next) => {
13
- if (!isControlled)
24
+ if (!latest.current.isControlled)
14
25
  setUncontrolled(next);
15
- onChange?.(next);
16
- }, [isControlled, onChange]);
26
+ latest.current.onChange?.(next);
27
+ }, []);
28
+ const [initiallyControlled] = useState(isControlled);
29
+ const warned = useRef(false);
30
+ useEffect(() => {
31
+ if (warned.current || isControlled === initiallyControlled || !isDevBuild())
32
+ return;
33
+ warned.current = true;
34
+ console.warn(isControlled
35
+ ? '[koncept-ui] Komponent przeszedł z trybu niekontrolowanego w kontrolowany (`value` było undefined). Wybierz jeden tryb na całe życie komponentu.'
36
+ : '[koncept-ui] Komponent przeszedł z trybu kontrolowanego w niekontrolowany (`value` stało się undefined). Do "braku wartości" użyj null, nie undefined.');
37
+ }, [isControlled, initiallyControlled]);
17
38
  return [isControlled ? value : uncontrolled, setValue];
18
39
  }
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Stabilny identyfikator elementu w konwencji Angulara (`kpt-input-…`), z tą samą
2
+ * Stabilny identyfikator elementu w konwencji Angulara (`kpt-input-...`), z tą samą
3
3
  * zasadą pierwszeństwa: własne `id` przekazane przez propsy wygrywa.
4
4
  *
5
5
  * `useId()` z Reacta zwraca wartość ze znakami spoza [A-Za-z0-9] (React 19 używa
6
- * `«r0»`), która jest poprawna w atrybucie `id`, ale nie w selektorze CSS —
6
+ * `"r0"`), która jest poprawna w atrybucie `id`, ale nie w selektorze CSS -
7
7
  * dlatego zostawiamy z niej tylko część alfanumeryczną.
8
8
  */
9
9
  export declare function useKptId(provided: string | undefined, prefix: string): string;
@@ -1,10 +1,10 @@
1
1
  import { useId } from 'react';
2
2
  /**
3
- * Stabilny identyfikator elementu w konwencji Angulara (`kpt-input-…`), z tą samą
3
+ * Stabilny identyfikator elementu w konwencji Angulara (`kpt-input-...`), z tą samą
4
4
  * zasadą pierwszeństwa: własne `id` przekazane przez propsy wygrywa.
5
5
  *
6
6
  * `useId()` z Reacta zwraca wartość ze znakami spoza [A-Za-z0-9] (React 19 używa
7
- * `«r0»`), która jest poprawna w atrybucie `id`, ale nie w selektorze CSS —
7
+ * `"r0"`), która jest poprawna w atrybucie `id`, ale nie w selektorze CSS -
8
8
  * dlatego zostawiamy z niej tylko część alfanumeryczną.
9
9
  */
10
10
  export function useKptId(provided, prefix) {
@@ -4,7 +4,8 @@ import { type RefObject } from 'react';
4
4
  * z fokusem, przenosi fokus do panelu (pierwszy element z kolejki Tab albo sam panel) i zawija
5
5
  * `Tab` / `Shift+Tab` w jego obrębie; przy zamknięciu oddaje fokus zapamiętanemu elementowi.
6
6
  * Bez tego `aria-modal="true"` obiecywał czytnikowi okno, z którego Tab po cichu wychodził.
7
+ * Otwarty panel blokuje też przewijanie strony pod spodem (wspólny licznik z `KptDialog`).
7
8
  *
8
- * Port Angulara robi to samo na pułapce CDK (`shared/modal-focus.ts`) — zmiana zachowania w obu.
9
+ * Port Angulara robi to samo na pułapce CDK (`shared/modal-focus.ts`) - zmiana zachowania w obu.
9
10
  */
10
11
  export declare function useModalFocus(open: boolean, panelRef: RefObject<HTMLElement | null>): void;
@@ -1,5 +1,11 @@
1
1
  import { useEffect } from 'react';
2
- /** Elementy z kolejki Tab — na nich zawija się pułapka. */
2
+ import { kptLockScroll } from "./scroll-lock.js";
3
+ /**
4
+ * Stos otwartych paneli modalnych. Pułapki słuchają `keydown` na dokumencie, więc przy dwóch
5
+ * otwartych naraz (szuflada -> dialog) walczyłyby o ten sam Tab - klawisz obsługuje tylko najwyższa.
6
+ */
7
+ const stack = [];
8
+ /** Elementy z kolejki Tab - na nich zawija się pułapka. */
3
9
  const TABBABLE = 'a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])';
4
10
  function tabbables(panel) {
5
11
  return [...panel.querySelectorAll(TABBABLE)].filter((el) => !el.closest('[hidden], [inert]'));
@@ -9,8 +15,9 @@ function tabbables(panel) {
9
15
  * z fokusem, przenosi fokus do panelu (pierwszy element z kolejki Tab albo sam panel) i zawija
10
16
  * `Tab` / `Shift+Tab` w jego obrębie; przy zamknięciu oddaje fokus zapamiętanemu elementowi.
11
17
  * Bez tego `aria-modal="true"` obiecywał czytnikowi okno, z którego Tab po cichu wychodził.
18
+ * Otwarty panel blokuje też przewijanie strony pod spodem (wspólny licznik z `KptDialog`).
12
19
  *
13
- * Port Angulara robi to samo na pułapce CDK (`shared/modal-focus.ts`) — zmiana zachowania w obu.
20
+ * Port Angulara robi to samo na pułapce CDK (`shared/modal-focus.ts`) - zmiana zachowania w obu.
14
21
  */
15
22
  export function useModalFocus(open, panelRef) {
16
23
  useEffect(() => {
@@ -19,6 +26,8 @@ export function useModalFocus(open, panelRef) {
19
26
  return;
20
27
  const active = document.activeElement;
21
28
  const returnTo = active instanceof HTMLElement && !panel.contains(active) ? active : null;
29
+ stack.push(panel);
30
+ const releaseScroll = kptLockScroll();
22
31
  // Klatkę później: panel dostaje `is-open` (i `visibility: visible`) w tym samym commicie,
23
32
  // a przeglądarka nie skupi elementu, który w chwili wywołania jest jeszcze niewidoczny.
24
33
  const frame = requestAnimationFrame(() => {
@@ -26,7 +35,7 @@ export function useModalFocus(open, panelRef) {
26
35
  (first ?? panel).focus();
27
36
  });
28
37
  const onKeyDown = (event) => {
29
- if (event.key !== 'Tab')
38
+ if (event.key !== 'Tab' || stack[stack.length - 1] !== panel)
30
39
  return;
31
40
  const items = tabbables(panel);
32
41
  if (!items.length) {
@@ -50,6 +59,8 @@ export function useModalFocus(open, panelRef) {
50
59
  return () => {
51
60
  cancelAnimationFrame(frame);
52
61
  document.removeEventListener('keydown', onKeyDown);
62
+ stack.splice(stack.indexOf(panel), 1);
63
+ releaseScroll();
53
64
  if (returnTo?.isConnected)
54
65
  returnTo.focus();
55
66
  };
@@ -13,23 +13,26 @@ 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. */
22
+ readOnly?: boolean;
21
23
  invalid?: boolean;
22
24
  touched?: boolean;
23
25
  onTouch?: () => void;
24
26
  }
25
27
  /**
26
- * 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.
27
29
  *
28
30
  * Skok wartości (strzałka, `Home`/`End`, klik w łuk, zmiana z zewnątrz) łuk i licznik pokonują
29
- * płynnie; przy przeciąganiu idą za kursorem bez opóźnienia. `prefers-reduced-motion` wyłącza
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
30
33
  * animację, a `aria-valuenow` zawsze niesie wartość docelową, nie pośrednią.
31
34
  *
32
35
  * @example
33
36
  * <KptKnob value={level} onValueChange={setLevel} min={0} max={100} step={5} suffix="%" />
34
37
  */
35
- export declare function KptKnob({ value, defaultValue, onValueChange, min, max, step, size, stroke, suffix, showValue, id, ariaLabel, disabled, invalid, touched, onTouch, className, ...rest }: Readonly<KptKnobProps>): import("react").JSX.Element;
38
+ export declare function KptKnob({ value, defaultValue, onValueChange, min, max, step, size, stroke, suffix, showValue, id, ariaLabel, disabled, readOnly, invalid, touched, onTouch, className, ...rest }: Readonly<KptKnobProps>): import("react").JSX.Element;