@konce-pt/react 0.11.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +128 -64
  2. package/dist/accordion/accordion.d.ts +14 -6
  3. package/dist/accordion/accordion.js +25 -17
  4. package/dist/accordion/llms.txt +22 -10
  5. package/dist/alert/alert.d.ts +2 -2
  6. package/dist/alert/alert.js +3 -2
  7. package/dist/alert/llms.txt +10 -9
  8. package/dist/app-shell/app-shell.d.ts +14 -14
  9. package/dist/app-shell/app-shell.js +22 -15
  10. package/dist/app-shell/llms.txt +16 -15
  11. package/dist/auth/auth-types.d.ts +6 -6
  12. package/dist/auth/auth.d.ts +2 -2
  13. package/dist/auth/auth.js +24 -15
  14. package/dist/auth/llms.txt +12 -11
  15. package/dist/autocomplete/autocomplete.d.ts +19 -6
  16. package/dist/autocomplete/autocomplete.js +32 -11
  17. package/dist/autocomplete/llms.txt +19 -5
  18. package/dist/avatar/avatar.d.ts +6 -6
  19. package/dist/avatar/avatar.js +6 -5
  20. package/dist/avatar/llms.txt +10 -10
  21. package/dist/avatar-group/avatar-group.d.ts +4 -4
  22. package/dist/avatar-group/avatar-group.js +4 -3
  23. package/dist/avatar-group/llms.txt +8 -8
  24. package/dist/backdrop/backdrop.d.ts +7 -26
  25. package/dist/backdrop/backdrop.js +32 -27
  26. package/dist/backdrop/llms.txt +27 -27
  27. package/dist/badge/badge.d.ts +3 -3
  28. package/dist/badge/badge.js +1 -1
  29. package/dist/badge/llms.txt +11 -11
  30. package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
  31. package/dist/bottom-sheet/bottom-sheet.js +5 -4
  32. package/dist/bottom-sheet/llms.txt +11 -8
  33. package/dist/breadcrumb/breadcrumb.d.ts +8 -2
  34. package/dist/breadcrumb/breadcrumb.js +11 -3
  35. package/dist/breadcrumb/llms.txt +10 -2
  36. package/dist/button/button.d.ts +3 -3
  37. package/dist/button/button.js +10 -9
  38. package/dist/button/llms.txt +27 -19
  39. package/dist/button-group/button-group.d.ts +18 -5
  40. package/dist/button-group/button-group.js +54 -6
  41. package/dist/button-group/llms.txt +27 -18
  42. package/dist/card/card.d.ts +8 -8
  43. package/dist/card/card.js +10 -9
  44. package/dist/card/llms.txt +20 -20
  45. package/dist/carousel/carousel.d.ts +6 -6
  46. package/dist/carousel/carousel.js +8 -5
  47. package/dist/carousel/llms.txt +10 -10
  48. package/dist/charts/chart-legend.d.ts +3 -3
  49. package/dist/charts/chart-legend.js +2 -1
  50. package/dist/charts/chart-tooltip.d.ts +3 -3
  51. package/dist/charts/chart-tooltip.js +1 -1
  52. package/dist/charts/chart.d.ts +4 -3
  53. package/dist/charts/chart.js +18 -10
  54. package/dist/charts/llms.txt +10 -7
  55. package/dist/charts-entry/public-api.js +2 -2
  56. package/dist/chat/chat.d.ts +17 -10
  57. package/dist/chat/chat.js +77 -23
  58. package/dist/chat/llms.txt +39 -15
  59. package/dist/chat-composer/chat-composer.d.ts +20 -7
  60. package/dist/chat-composer/chat-composer.js +29 -7
  61. package/dist/chat-composer/llms.txt +20 -11
  62. package/dist/chat-dock/chat-dock.d.ts +11 -4
  63. package/dist/chat-dock/chat-dock.js +10 -6
  64. package/dist/chat-dock/llms.txt +15 -14
  65. package/dist/chat-entry/public-api.js +1 -1
  66. package/dist/chat-message/chat-message.d.ts +12 -5
  67. package/dist/chat-message/chat-message.js +19 -8
  68. package/dist/chat-message/llms.txt +16 -15
  69. package/dist/chat-typing/chat-typing.d.ts +2 -2
  70. package/dist/chat-typing/chat-typing.js +4 -3
  71. package/dist/chat-typing/llms.txt +6 -6
  72. package/dist/checkbox/checkbox.d.ts +13 -6
  73. package/dist/checkbox/checkbox.js +31 -5
  74. package/dist/checkbox/llms.txt +26 -11
  75. package/dist/chip/chip.d.ts +4 -4
  76. package/dist/chip/chip.js +3 -2
  77. package/dist/chip/llms.txt +11 -11
  78. package/dist/chips-input/chips-input.d.ts +6 -4
  79. package/dist/chips-input/chips-input.js +47 -12
  80. package/dist/chips-input/llms.txt +18 -8
  81. package/dist/clock/clock.d.ts +11 -6
  82. package/dist/clock/clock.js +38 -8
  83. package/dist/clock/llms.txt +12 -8
  84. package/dist/color-picker/color-picker.d.ts +9 -5
  85. package/dist/color-picker/color-picker.js +37 -18
  86. package/dist/color-picker/llms.txt +8 -5
  87. package/dist/confirm/confirm-container.d.ts +3 -3
  88. package/dist/confirm/confirm-container.js +6 -5
  89. package/dist/confirm/confirm-store.d.ts +4 -4
  90. package/dist/confirm/confirm-store.js +11 -5
  91. package/dist/confirm/llms.txt +8 -7
  92. package/dist/context-menu/context-menu.d.ts +1 -1
  93. package/dist/context-menu/context-menu.js +37 -14
  94. package/dist/context-menu/llms.txt +10 -7
  95. package/dist/data-table/data-table-types.d.ts +5 -5
  96. package/dist/data-table/data-table.d.ts +37 -5
  97. package/dist/data-table/data-table.js +426 -119
  98. package/dist/data-table/export-csv.d.ts +3 -3
  99. package/dist/data-table/export-csv.js +8 -10
  100. package/dist/data-table/llms.txt +127 -79
  101. package/dist/data-view/data-view.d.ts +13 -5
  102. package/dist/data-view/data-view.js +68 -6
  103. package/dist/data-view/llms.txt +29 -10
  104. package/dist/date-range/date-range.d.ts +20 -8
  105. package/dist/date-range/date-range.js +86 -63
  106. package/dist/date-range/llms.txt +32 -18
  107. package/dist/datepicker/datepicker.d.ts +22 -8
  108. package/dist/datepicker/datepicker.js +103 -71
  109. package/dist/datepicker/llms.txt +36 -22
  110. package/dist/dialog/dialog.d.ts +4 -4
  111. package/dist/dialog/dialog.js +32 -11
  112. package/dist/dialog/llms.txt +13 -10
  113. package/dist/divider/divider.d.ts +7 -1
  114. package/dist/divider/divider.js +3 -2
  115. package/dist/divider/llms.txt +4 -3
  116. package/dist/drawer/drawer.d.ts +9 -4
  117. package/dist/drawer/drawer.js +5 -4
  118. package/dist/drawer/llms.txt +13 -10
  119. package/dist/empty/empty.d.ts +2 -2
  120. package/dist/empty/empty.js +1 -1
  121. package/dist/empty/llms.txt +9 -9
  122. package/dist/fab/fab.d.ts +1 -1
  123. package/dist/fab/fab.js +1 -1
  124. package/dist/fab/llms.txt +10 -6
  125. package/dist/fieldset/fieldset.d.ts +18 -4
  126. package/dist/fieldset/fieldset.js +12 -6
  127. package/dist/fieldset/llms.txt +26 -9
  128. package/dist/file-upload/file-upload.d.ts +8 -2
  129. package/dist/file-upload/file-upload.js +22 -11
  130. package/dist/file-upload/llms.txt +12 -9
  131. package/dist/form-field/form-field-context.d.ts +4 -4
  132. package/dist/form-field/form-field.d.ts +12 -4
  133. package/dist/form-field/form-field.js +27 -6
  134. package/dist/form-field/llms.txt +25 -11
  135. package/dist/galleria/galleria.d.ts +3 -3
  136. package/dist/galleria/galleria.js +9 -6
  137. package/dist/galleria/llms.txt +7 -7
  138. package/dist/grid/col.d.ts +4 -4
  139. package/dist/grid/col.js +2 -2
  140. package/dist/grid/flex.d.ts +3 -3
  141. package/dist/grid/flex.js +1 -1
  142. package/dist/grid/grid.d.ts +7 -7
  143. package/dist/grid/grid.js +3 -3
  144. package/dist/grid/layout.d.ts +2 -2
  145. package/dist/grid/layout.js +2 -2
  146. package/dist/grid/llms.txt +15 -15
  147. package/dist/grid-entry/public-api.js +1 -1
  148. package/dist/i18n/i18n-context.d.ts +6 -6
  149. package/dist/i18n/i18n-context.js +27 -5
  150. package/dist/icon/icon-registry.d.ts +3 -3
  151. package/dist/icon/icon-registry.js +3 -3
  152. package/dist/icon/icon.d.ts +4 -4
  153. package/dist/icon/icon.js +10 -7
  154. package/dist/icon/llms.txt +13 -13
  155. package/dist/icon-button/icon-button.d.ts +2 -2
  156. package/dist/icon-button/icon-button.js +1 -1
  157. package/dist/icon-button/llms.txt +9 -5
  158. package/dist/icons-entry/public-api.d.ts +2 -2
  159. package/dist/icons-entry/public-api.js +3 -3
  160. package/dist/image/image.js +5 -5
  161. package/dist/image/llms.txt +13 -13
  162. package/dist/input/input.d.ts +18 -5
  163. package/dist/input/input.js +22 -6
  164. package/dist/input/llms.txt +25 -11
  165. package/dist/input-mask/input-mask.d.ts +7 -2
  166. package/dist/input-mask/input-mask.js +17 -43
  167. package/dist/input-mask/llms.txt +8 -5
  168. package/dist/input-number/input-number.d.ts +11 -9
  169. package/dist/input-number/input-number.js +25 -21
  170. package/dist/input-number/llms.txt +17 -14
  171. package/dist/input-otp/input-otp.d.ts +18 -5
  172. package/dist/input-otp/input-otp.js +48 -24
  173. package/dist/input-otp/llms.txt +18 -7
  174. package/dist/internal/calendar-focus.d.ts +1 -1
  175. package/dist/internal/calendar-focus.js +3 -3
  176. package/dist/internal/cn.d.ts +1 -1
  177. package/dist/internal/mask.d.ts +14 -0
  178. package/dist/internal/mask.js +62 -0
  179. package/dist/internal/number-group.d.ts +22 -0
  180. package/dist/internal/number-group.js +53 -0
  181. package/dist/internal/option-key.d.ts +6 -0
  182. package/dist/internal/option-key.js +8 -0
  183. package/dist/internal/option-nav.d.ts +4 -4
  184. package/dist/internal/option-nav.js +5 -5
  185. package/dist/internal/overlay-container.js +1 -1
  186. package/dist/internal/overlay.d.ts +3 -3
  187. package/dist/internal/overlay.js +40 -10
  188. package/dist/internal/password-strength.d.ts +6 -0
  189. package/dist/internal/password-strength.js +74 -0
  190. package/dist/internal/roving.d.ts +2 -2
  191. package/dist/internal/roving.js +3 -3
  192. package/dist/internal/scroll-lock.d.ts +6 -0
  193. package/dist/internal/scroll-lock.js +35 -0
  194. package/dist/internal/slot-children.d.ts +13 -0
  195. package/dist/internal/slot-children.js +31 -0
  196. package/dist/internal/slot.d.ts +3 -3
  197. package/dist/internal/slot.js +2 -2
  198. package/dist/internal/step.d.ts +12 -0
  199. package/dist/internal/step.js +31 -0
  200. package/dist/internal/tween.d.ts +5 -5
  201. package/dist/internal/tween.js +7 -8
  202. package/dist/internal/types.d.ts +2 -2
  203. package/dist/internal/use-breakpoint.d.ts +2 -2
  204. package/dist/internal/use-breakpoint.js +4 -4
  205. package/dist/internal/use-controllable-state.d.ts +5 -0
  206. package/dist/internal/use-controllable-state.js +25 -4
  207. package/dist/internal/use-id.d.ts +2 -2
  208. package/dist/internal/use-id.js +2 -2
  209. package/dist/internal/use-modal-focus.d.ts +2 -1
  210. package/dist/internal/use-modal-focus.js +14 -3
  211. package/dist/knob/knob.d.ts +7 -4
  212. package/dist/knob/knob.js +27 -22
  213. package/dist/knob/llms.txt +18 -11
  214. package/dist/listbox/listbox.d.ts +8 -6
  215. package/dist/listbox/listbox.js +37 -17
  216. package/dist/listbox/llms.txt +12 -9
  217. package/dist/loader/llms.txt +56 -0
  218. package/dist/loader/loader.d.ts +49 -0
  219. package/dist/loader/loader.js +68 -0
  220. package/dist/map/llms.txt +30 -23
  221. package/dist/map/map-create-dialog.d.ts +4 -4
  222. package/dist/map/map-create-dialog.js +36 -28
  223. package/dist/map/map-hours-field.d.ts +4 -4
  224. package/dist/map/map-hours-field.js +8 -7
  225. package/dist/map/map-image-field.d.ts +2 -2
  226. package/dist/map/map-image-field.js +6 -5
  227. package/dist/map/map-legend.d.ts +4 -4
  228. package/dist/map/map-legend.js +3 -2
  229. package/dist/map/map-poi-card.d.ts +3 -3
  230. package/dist/map/map-poi-card.js +10 -9
  231. package/dist/map/map-search.d.ts +17 -6
  232. package/dist/map/map-search.js +70 -43
  233. package/dist/map/map.d.ts +25 -13
  234. package/dist/map/map.js +86 -57
  235. package/dist/map/ports.d.ts +9 -9
  236. package/dist/map/ports.js +6 -6
  237. package/dist/map-entry/public-api.js +2 -2
  238. package/dist/megamenu/llms.txt +18 -7
  239. package/dist/megamenu/megamenu.d.ts +12 -6
  240. package/dist/megamenu/megamenu.js +23 -14
  241. package/dist/mention/llms.txt +15 -15
  242. package/dist/mention/mention.d.ts +5 -5
  243. package/dist/mention/mention.js +2 -2
  244. package/dist/mention/mentions.d.ts +1 -1
  245. package/dist/mention/mentions.js +1 -1
  246. package/dist/menu/llms.txt +12 -12
  247. package/dist/menu/menu-item.d.ts +4 -4
  248. package/dist/menu/menu-keys.d.ts +2 -2
  249. package/dist/menu/menu-keys.js +5 -5
  250. package/dist/menu/menu-rows.js +1 -0
  251. package/dist/menu/menu.d.ts +2 -2
  252. package/dist/menu/menu.js +15 -8
  253. package/dist/menubar/llms.txt +19 -8
  254. package/dist/menubar/menubar.d.ts +11 -5
  255. package/dist/menubar/menubar.js +23 -11
  256. package/dist/meter-group/llms.txt +12 -12
  257. package/dist/meter-group/meter-group.d.ts +2 -2
  258. package/dist/meter-group/meter-group.js +2 -1
  259. package/dist/motion/motion-context.d.ts +22 -0
  260. package/dist/motion/motion-context.js +28 -0
  261. package/dist/order-list/llms.txt +24 -9
  262. package/dist/order-list/order-list.d.ts +12 -4
  263. package/dist/order-list/order-list.js +123 -25
  264. package/dist/paginator/llms.txt +8 -8
  265. package/dist/paginator/paginator.js +7 -4
  266. package/dist/panel/llms.txt +25 -13
  267. package/dist/panel/panel.d.ts +11 -3
  268. package/dist/panel/panel.js +12 -7
  269. package/dist/password/llms.txt +19 -7
  270. package/dist/password/password.d.ts +2 -2
  271. package/dist/password/password.js +27 -16
  272. package/dist/peek/llms.txt +11 -11
  273. package/dist/peek/peek.d.ts +6 -6
  274. package/dist/peek/peek.js +41 -19
  275. package/dist/pick-list/llms.txt +35 -12
  276. package/dist/pick-list/pick-list.d.ts +12 -4
  277. package/dist/pick-list/pick-list.js +128 -24
  278. package/dist/popover/llms.txt +13 -10
  279. package/dist/popover/popover.d.ts +6 -4
  280. package/dist/popover/popover.js +14 -7
  281. package/dist/progress/llms.txt +17 -17
  282. package/dist/progress/progress.d.ts +7 -7
  283. package/dist/progress/progress.js +7 -6
  284. package/dist/public-api.d.ts +16 -4
  285. package/dist/public-api.js +13 -7
  286. package/dist/radio-group/llms.txt +16 -6
  287. package/dist/radio-group/radio-group.d.ts +12 -3
  288. package/dist/radio-group/radio-group.js +23 -4
  289. package/dist/rating/llms.txt +20 -13
  290. package/dist/rating/rating-pointer.d.ts +16 -0
  291. package/dist/rating/rating-pointer.js +26 -0
  292. package/dist/rating/rating.d.ts +6 -6
  293. package/dist/rating/rating.js +77 -12
  294. package/dist/rich-text/lists.d.ts +2 -2
  295. package/dist/rich-text/lists.js +7 -7
  296. package/dist/rich-text/llms.txt +35 -12
  297. package/dist/rich-text/rich-text.d.ts +13 -14
  298. package/dist/rich-text/rich-text.js +311 -142
  299. package/dist/rich-text/sanitize.d.ts +11 -2
  300. package/dist/rich-text/sanitize.js +80 -32
  301. package/dist/rich-text/tables.d.ts +3 -3
  302. package/dist/rich-text/tables.js +3 -3
  303. package/dist/roadmap/llms.txt +23 -17
  304. package/dist/roadmap/roadmap.d.ts +6 -6
  305. package/dist/roadmap/roadmap.js +102 -25
  306. package/dist/roadmap-entry/public-api.js +2 -2
  307. package/dist/scroll-top/llms.txt +6 -6
  308. package/dist/scroll-top/scroll-top.d.ts +1 -1
  309. package/dist/scroll-top/scroll-top.js +2 -1
  310. package/dist/select/llms.txt +22 -12
  311. package/dist/select/select.d.ts +10 -8
  312. package/dist/select/select.js +87 -47
  313. package/dist/shared/types.d.ts +22 -1
  314. package/dist/shared/types.js +9 -1
  315. package/dist/sidenav/llms.txt +9 -9
  316. package/dist/sidenav/sidenav.d.ts +2 -3
  317. package/dist/sidenav/sidenav.js +5 -4
  318. package/dist/skeleton/llms.txt +3 -3
  319. package/dist/skeleton/skeleton.d.ts +1 -1
  320. package/dist/skeleton/skeleton.js +1 -1
  321. package/dist/slider/llms.txt +34 -12
  322. package/dist/slider/slider-drag.d.ts +26 -0
  323. package/dist/slider/slider-drag.js +79 -0
  324. package/dist/slider/slider.d.ts +8 -5
  325. package/dist/slider/slider.js +38 -8
  326. package/dist/speech/llms.txt +97 -0
  327. package/dist/speech/speech-button.d.ts +44 -0
  328. package/dist/speech/speech-button.js +86 -0
  329. package/dist/speech/speech-wave.d.ts +19 -0
  330. package/dist/speech/speech-wave.js +16 -0
  331. package/dist/speech/use-speech-recognition.d.ts +81 -0
  332. package/dist/speech/use-speech-recognition.js +179 -0
  333. package/dist/speed-dial/llms.txt +14 -8
  334. package/dist/speed-dial/speed-dial.d.ts +1 -1
  335. package/dist/speed-dial/speed-dial.js +3 -2
  336. package/dist/spinner/llms.txt +7 -7
  337. package/dist/spinner/spinner.d.ts +1 -1
  338. package/dist/spinner/spinner.js +2 -1
  339. package/dist/split-button/llms.txt +21 -15
  340. package/dist/split-button/split-button.d.ts +2 -2
  341. package/dist/split-button/split-button.js +13 -6
  342. package/dist/splitter/llms.txt +11 -11
  343. package/dist/splitter/splitter.d.ts +3 -3
  344. package/dist/splitter/splitter.js +25 -10
  345. package/dist/stepper/llms.txt +35 -13
  346. package/dist/stepper/stepper.d.ts +6 -6
  347. package/dist/stepper/stepper.js +60 -13
  348. package/dist/switch/llms.txt +15 -5
  349. package/dist/switch/switch.d.ts +10 -3
  350. package/dist/switch/switch.js +18 -4
  351. package/dist/switch-group/llms.txt +11 -8
  352. package/dist/switch-group/switch-group.d.ts +6 -4
  353. package/dist/switch-group/switch-group.js +9 -7
  354. package/dist/tabs/llms.txt +12 -9
  355. package/dist/tabs/tabs.d.ts +5 -5
  356. package/dist/tabs/tabs.js +36 -20
  357. package/dist/textarea/llms.txt +23 -12
  358. package/dist/textarea/textarea.d.ts +19 -6
  359. package/dist/textarea/textarea.js +22 -7
  360. package/dist/timeline/llms.txt +4 -4
  361. package/dist/timeline/timeline.d.ts +1 -1
  362. package/dist/timeline/timeline.js +1 -1
  363. package/dist/toast/llms.txt +50 -17
  364. package/dist/toast/toast-container.d.ts +9 -3
  365. package/dist/toast/toast-container.js +18 -9
  366. package/dist/toast/toast-store.d.ts +42 -2
  367. package/dist/toast/toast-store.js +36 -1
  368. package/dist/toolbar/llms.txt +7 -7
  369. package/dist/toolbar/toolbar.d.ts +3 -3
  370. package/dist/toolbar/toolbar.js +2 -2
  371. package/dist/tooltip/llms.txt +14 -12
  372. package/dist/tooltip/tooltip.d.ts +5 -4
  373. package/dist/tooltip/tooltip.js +100 -41
  374. package/dist/tree/llms.txt +25 -11
  375. package/dist/tree/tree-keys.d.ts +5 -5
  376. package/dist/tree/tree-keys.js +7 -7
  377. package/dist/tree/tree.d.ts +17 -5
  378. package/dist/tree/tree.js +62 -20
  379. package/dist/update/llms.txt +54 -0
  380. package/dist/update/update.d.ts +49 -0
  381. package/dist/update/update.js +82 -0
  382. package/package.json +18 -15
@@ -1,53 +1,75 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Fragment, useState } from 'react';
2
4
  import { cn } from "../internal/cn.js";
3
5
  import { useControllableState } from "../internal/use-controllable-state.js";
4
6
  import { useKptFieldA11y } from "../form-field/form-field-context.js";
5
7
  import { useKptMessages } from "../i18n/i18n-context.js";
6
8
  /**
7
- * Pole kodu jednorazowego (OTP/PIN) — N osobnych pól, automatyczne przejście do następnego
8
- * i wklejanie całego kodu naraz. Wartością jest sklejony string.
9
+ * Pole kodu jednorazowego (OTP/PIN) - N osobnych pól, automatyczne przejście do następnego
10
+ * i wklejanie całego kodu naraz. Wartością są wpisane znaki **bez dziur** (`'13'`, nie `'1 3'`), więc
11
+ * walidator długości i backend widzą tyle znaków, ile naprawdę wpisano.
9
12
  *
10
13
  * @example
11
14
  * <KptInputOtp value={code} onValueChange={setCode} length={6} integerOnly />
15
+ * <KptInputOtp value={code} onValueChange={setCode} length={9} groupSize={3} />
12
16
  */
13
- export function KptInputOtp({ value, defaultValue = '', onValueChange, length = 6, integerOnly = false, id, ariaLabel = null, disabled = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
17
+ export function KptInputOtp({ value, defaultValue = '', onValueChange, length = 6, groupSize = 0, groupSeparator = '-', integerOnly = false, id, ariaLabel = null, disabled = false, readOnly = false, required = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
14
18
  const { t } = useKptMessages({ locale, dictionary });
15
19
  const field = useKptFieldA11y(id, 'kpt-input-otp');
16
20
  const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
17
21
  const showInvalid = invalid && (touched ?? true);
18
- const charAt = (index) => current[index] ?? '';
19
22
  /*
20
- * Wartość jest jednym stringiem, a pól jest N — pozycje pośrodku muszą więc dać się zostawić
21
- * puste. Dopełniamy spacjami, podmieniamy znak i obcinamy końcowe spacje, żeby „a__c" dało się
22
- * zapisać, a „a" nie zamieniło się w „a ".
23
+ * Komórki trzymają układ osobno od wartości: wyczyszczenie środkowej zostawia w niej pustkę,
24
+ * zamiast przesuwać resztę kodu w lewo, a wartość to same znaki. Zmiana wartości z zewnątrz
25
+ * (inna niż złożenie bieżących komórek) układa znaki od początku - wzorzec "poprzednia
26
+ * wartość w stanie", bez efektu.
23
27
  */
28
+ const toCells = (text) => Array.from({ length }, (_, index) => text[index] ?? '');
29
+ const [cells, setCells] = useState(() => toCells(current));
30
+ const inSync = cells.length === length && cells.join('') === current;
31
+ if (!inSync)
32
+ setCells(toCells(current));
33
+ const shown = inSync ? cells : toCells(current);
34
+ const charAt = (index) => shown[index] ?? '';
35
+ /** Zapis komórek i złożonej z nich wartości - jedno miejsce, żeby układ i model się nie rozjechały. */
36
+ const commitCells = (next) => {
37
+ setCells(next);
38
+ setCurrent(next.join(''));
39
+ };
24
40
  const setChar = (index, char) => {
25
- const chars = current.padEnd(length, ' ').split('');
26
- chars[index] = char || ' ';
27
- setCurrent(chars.join('').replace(/ +$/, ''));
41
+ const next = [...shown];
42
+ next[index] = char;
43
+ commitCells(next);
28
44
  };
45
+ /** Następna/poprzednia komórka - po polach, nie po rodzeństwie, bo między grupami stoi separator. */
29
46
  const focusSibling = (el, direction) => {
30
- const target = direction === 1 ? el.nextElementSibling : el.previousElementSibling;
31
- target?.focus();
47
+ const cells = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
48
+ cells[cells.indexOf(el) + direction]?.focus();
32
49
  };
33
- /** Wpisuje `text` od komórki `start` (bez spacji i — przy `integerOnly` — bez nie-cyfr). */
50
+ /** Czy za komórką `index` kończy się grupa (a nie cały kod). */
51
+ const group = Math.floor(groupSize);
52
+ const separatorAfter = (index) => group >= 1 && (index + 1) % group === 0 && index < length - 1;
53
+ /** Wpisuje `text` od komórki `start` (bez spacji i - przy `integerOnly` - bez nie-cyfr). */
34
54
  const fillFrom = (start, text, el) => {
35
55
  let chars = text.replace(/\s/g, '');
36
56
  if (integerOnly)
37
57
  chars = chars.replace(/\D/g, '');
38
- const arr = current.padEnd(length, ' ').split('');
58
+ const arr = [...shown];
39
59
  for (let k = 0; k < chars.length && start + k < length; k += 1)
40
60
  arr[start + k] = chars[k];
41
- setCurrent(arr.join('').replace(/ +$/, ''));
42
- // Fokus na pierwszą pustą komórkę, a przy komplecie — na ostatnią.
43
- const cells = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
44
- const empty = arr.findIndex((char) => char === ' ');
45
- cells[empty >= 0 ? empty : cells.length - 1]?.focus();
61
+ commitCells(arr);
62
+ // Fokus na pierwszą pustą komórkę, a przy komplecie - na ostatnią.
63
+ const inputs = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
64
+ const empty = arr.findIndex((char) => char === '');
65
+ inputs[empty >= 0 ? empty : inputs.length - 1]?.focus();
46
66
  };
47
67
  const onInput = (index, event) => {
48
68
  const el = event.target;
69
+ if (readOnly)
70
+ return;
49
71
  // Kilka znaków naraz to autouzupełnienie kodu z SMS (`one-time-code`) albo wklejenie przez
50
- // klawiaturę ekranową — rozkładamy je po komórkach od bieżącej. Dwa znaki w zajętej komórce
72
+ // klawiaturę ekranową - rozkładamy je po komórkach od bieżącej. Dwa znaki w zajętej komórce
51
73
  // to zwykłe nadpisanie: stary znak + nowy.
52
74
  if (el.value.length > 1 && !(el.value.length === 2 && charAt(index))) {
53
75
  const text = el.value;
@@ -67,7 +89,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
67
89
  };
68
90
  const onKeyDown = (index, event) => {
69
91
  const el = event.currentTarget;
70
- if (event.key === 'Backspace' && !charAt(index))
92
+ if (event.key === 'Backspace' && !charAt(index) && !readOnly)
71
93
  focusSibling(el, -1);
72
94
  else if (event.key === 'ArrowLeft')
73
95
  focusSibling(el, -1);
@@ -76,13 +98,15 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
76
98
  };
77
99
  const onPaste = (event) => {
78
100
  event.preventDefault();
101
+ if (readOnly)
102
+ return;
79
103
  fillFrom(0, event.clipboardData.getData('text'), event.currentTarget);
80
104
  };
81
- /** „Dotknięcie” dopiero przy wyjściu fokusu z całej grupy, nie przy przejściu między komórkami. */
105
+ /** "Dotknięcie" dopiero przy wyjściu fokusu z całej grupy, nie przy przejściu między komórkami. */
82
106
  const onGroupBlur = (event) => {
83
107
  const next = event.relatedTarget;
84
108
  if (!next || !event.currentTarget.contains(next))
85
109
  onTouch?.();
86
110
  };
87
- return (_jsx("div", { className: cn('kpt-input-otp-host', className), ...rest, children: _jsx("div", { className: cn('kpt-input-otp', showInvalid && 'kpt-input-otp--invalid'), role: "group", "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onBlur: onGroupBlur, children: Array.from({ length }, (_, index) => (_jsx("input", { className: "kpt-input-otp__cell", id: index === 0 ? field.id : undefined, "aria-label": t('inputOtp.cell', { index: index + 1, count: length }), "aria-invalid": showInvalid || undefined, type: "text", inputMode: integerOnly ? 'numeric' : 'text', autoComplete: index === 0 ? 'one-time-code' : 'off', value: charAt(index), disabled: disabled, onChange: (event) => onInput(index, event), onKeyDown: (event) => onKeyDown(index, event), onPaste: onPaste, onFocus: (event) => event.target.select() }, index))) }) }));
111
+ return (_jsx("div", { className: cn('kpt-input-otp-host', className), ...rest, children: _jsx("div", { className: cn('kpt-input-otp', showInvalid && 'kpt-input-otp--invalid'), role: "group", "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onBlur: onGroupBlur, children: Array.from({ length }, (_, index) => (_jsxs(Fragment, { children: [_jsx("input", { className: "kpt-input-otp__cell", id: index === 0 ? field.id : undefined, "aria-label": t('inputOtp.cell', { index: index + 1, count: length }), "aria-invalid": showInvalid || undefined, type: "text", inputMode: integerOnly ? 'numeric' : 'text', autoComplete: index === 0 ? 'one-time-code' : 'off', value: charAt(index), disabled: disabled, readOnly: readOnly, "aria-required": required || undefined, onChange: (event) => onInput(index, event), onKeyDown: (event) => onKeyDown(index, event), onPaste: onPaste, onFocus: (event) => event.target.select() }), separatorAfter(index) ? (_jsx("span", { className: "kpt-input-otp__sep", "aria-hidden": "true", children: groupSeparator })) : null] }, index))) }) }));
88
112
  }
@@ -1,25 +1,25 @@
1
1
  # KptInputOtp (@konce-pt/react)
2
2
 
3
- A one-time code field (OTP / PIN) — N separate boxes, auto-advance and paste.
3
+ A one-time code field (OTP / PIN) - N separate boxes, auto-advance and paste.
4
4
  Import: `import { KptInputOtp } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
7
  <div class="kpt-input-otp-host">
8
8
  <div class="kpt-input-otp">
9
9
  <input class="kpt-input-otp__cell" type="text" inputmode="numeric" maxlength="1" value="1">
10
- …N cells…
10
+ ...N cells...
11
11
  </div>
12
12
  </div>
13
13
 
14
14
  ## Props
15
- - `value` / `defaultValue` / `onValueChange` — one string, the characters joined
15
+ - `value` / `defaultValue` / `onValueChange` - one string, the characters joined
16
16
  - `length`: number (default 6)
17
- - `integerOnly`: boolean — digits only, and a numeric keyboard on mobile
17
+ - `integerOnly`: boolean - digits only, and a numeric keyboard on mobile
18
18
  - `disabled`, `invalid`, `touched`, `onTouch()`
19
19
 
20
20
  ## One string, N boxes
21
21
  The value is a single string while the UI is N inputs, so a gap in the middle has to be
22
- expressible. Writing pads with spaces, replaces the character and trims trailing spaces — that way
22
+ expressible. Writing pads with spaces, replaces the character and trims trailing spaces - that way
23
23
  a code with a hole round-trips and a single character does not turn into one followed by blanks.
24
24
 
25
25
  The DOM of a cell is also synced by hand after a rejected character: the value did not change, so
@@ -28,7 +28,7 @@ React has nothing to re-render, and the typed character would otherwise stay on
28
28
  ## Keyboard and paste
29
29
  A character moves focus to the next cell; Backspace in an empty cell moves back; ArrowLeft and
30
30
  ArrowRight walk the cells; focus selects the content so typing overwrites. Pasting fills the whole
31
- code at once — with `integerOnly` everything non-numeric is stripped first, so a copied
31
+ code at once - with `integerOnly` everything non-numeric is stripped first, so a copied
32
32
  "123-456" still lands correctly.
33
33
 
34
34
  ## Examples
@@ -38,7 +38,7 @@ code at once — with `integerOnly` everything non-numeric is stripped first, so
38
38
  ## Screen reader and keyboard
39
39
  The first cell has `autocomplete="one-time-code"`, so phones offer the code from an SMS; a code that
40
40
  arrives in one cell at once (autofill, an on-screen keyboard paste) is spread over the cells like a
41
- paste. `touch` fires when focus leaves the whole group — not after a paste, and not when moving
41
+ paste. `touch` fires when focus leaves the whole group - not after a paste, and not when moving
42
42
  between cells.
43
43
 
44
44
  ## Label and description
@@ -55,3 +55,14 @@ is added to `aria-describedby`. The cells form a named `role="group"`; `id` goes
55
55
  ## Accessibility
56
56
  Native inputs with `inputmode` matched to the allowed characters, so a phone shows the numeric
57
57
  keypad for a PIN instead of the full keyboard.
58
+
59
+ ## Read-only and required
60
+ `readOnly` shows the code but blocks typing and paste; `required` sets `aria-required` on the cells (`group` does not accept it). The value holds the typed characters **without gaps**: clearing a middle cell gives `"13"`, not `"1 3"`, while the cell itself stays empty on screen.
61
+
62
+ ## Groups
63
+ `groupSize` (default `0` = no groups) inserts a separator after every N boxes, counted from the
64
+ left; `groupSeparator` sets the character (default `-`). With `length` 9 and `groupSize` 3 you get
65
+ `[][][]-[][][]-[][][]`. The separator is purely visual (`aria-hidden`): the value is the bare characters
66
+ (`"123456789"`), each box keeps its name "Character 4 of 9", and arrows/Backspace jump over it.
67
+
68
+ <KptInputOtp value={code} onValueChange={setCode} length={9} groupSize={3} integerOnly />
@@ -1,7 +1,7 @@
1
1
  /** Zawija `Tab` / `Shift+Tab` w obrębie `panel`. */
2
2
  export declare function trapTab(panel: HTMLElement, event: KeyboardEvent): void;
3
3
  /**
4
- * Fokus na „aktywną” komórkę panelu: dzień `iso`, przystanek siatki komórek, a bez nich — pierwszy
4
+ * Fokus na "aktywną" komórkę panelu: dzień `iso`, przystanek siatki komórek, a bez nich - pierwszy
5
5
  * element panelu (zegar). Panel w nakładce jest niewidoczny do pierwszego pomiaru, więc wołający
6
6
  * odkłada to na `requestAnimationFrame`.
7
7
  */
@@ -1,9 +1,9 @@
1
1
  /*
2
- * Fokus w panelu kalendarza — wspólny dla `KptDatepicker` i `KptDateRange`. Panel stoi
2
+ * Fokus w panelu kalendarza - wspólny dla `KptDatepicker` i `KptDateRange`. Panel stoi
3
3
  * w nakładce na końcu strony, więc `Tab` z ostatniego elementu uciekłby poza niego; zawijamy go
4
4
  * w obrębie panelu, jak w oknie dialogowym.
5
5
  *
6
- * Bliźniak w porcie Angulara: `shared/calendar-focus.ts` — zmiana zachowania w obu.
6
+ * Bliźniak w porcie Angulara: `shared/calendar-focus.ts` - zmiana zachowania w obu.
7
7
  */
8
8
  const FOCUSABLE = 'button:not(:disabled):not([tabindex="-1"]), input:not(:disabled), [tabindex="0"]';
9
9
  /** Zawija `Tab` / `Shift+Tab` w obrębie `panel`. */
@@ -24,7 +24,7 @@ export function trapTab(panel, event) {
24
24
  }
25
25
  }
26
26
  /**
27
- * Fokus na „aktywną” komórkę panelu: dzień `iso`, przystanek siatki komórek, a bez nich — pierwszy
27
+ * Fokus na "aktywną" komórkę panelu: dzień `iso`, przystanek siatki komórek, a bez nich - pierwszy
28
28
  * element panelu (zegar). Panel w nakładce jest niewidoczny do pierwszego pomiaru, więc wołający
29
29
  * odkłada to na `requestAnimationFrame`.
30
30
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Sklejanie klas CSS. Odpowiednik `clsx` w kilkunastu linijkach — biblioteka
2
+ * Sklejanie klas CSS. Odpowiednik `clsx` w kilkunastu linijkach - biblioteka
3
3
  * zostaje bez zależności runtime, a konsument nie ryzykuje konfliktu wersji.
4
4
  *
5
5
  * Wartości fałszywe są pomijane, tablice spłaszczane, duplikaty usuwane
@@ -0,0 +1,14 @@
1
+ /** Tokeny maski: `9` = cyfra, `a` = litera (także `ą`, `ł`, `ß`), `*` = litera albo cyfra. */
2
+ export declare const KPT_MASK_TOKENS: Readonly<Record<string, RegExp>>;
3
+ /**
4
+ * Maska przepisuje wejście od zera: z tekstu bierze wyłącznie znaki pasujące do kolejnych
5
+ * tokenów, a literały wstawia sama. Dzięki temu wklejenie "48123456789" i wpisanie "(48) 123..."
6
+ * dają ten sam wynik, a usunięcie literału nie zostawia dziury we wzorcu.
7
+ */
8
+ export declare function kptApplyMask(raw: string, mask: string): string;
9
+ /**
10
+ * Pozycja kursora po przeformatowaniu. Liczy znaczące znaki (te, które maska zabrała) przed
11
+ * kursorem w surowym tekście i stawia kursor za tyloma samymi znakami w wyniku - poprawienie
12
+ * cyfry w środku numeru nie przerzuca kursora na koniec pola.
13
+ */
14
+ export declare function kptMaskCaret(raw: string, caret: number, mask: string): number;
@@ -0,0 +1,62 @@
1
+ /*
2
+ * Maska znakowa `kpt-input-mask`. Bliźniak w porcie Angulara (`shared/mask.ts`) - zmiana w obu.
3
+ */
4
+ /** Tokeny maski: `9` = cyfra, `a` = litera (także `ą`, `ł`, `ß`), `*` = litera albo cyfra. */
5
+ export const KPT_MASK_TOKENS = {
6
+ '9': /\d/,
7
+ a: /\p{L}/u,
8
+ '*': /[\p{L}\p{N}]/u,
9
+ };
10
+ /**
11
+ * Maska przepisuje wejście od zera: z tekstu bierze wyłącznie znaki pasujące do kolejnych
12
+ * tokenów, a literały wstawia sama. Dzięki temu wklejenie "48123456789" i wpisanie "(48) 123..."
13
+ * dają ten sam wynik, a usunięcie literału nie zostawia dziury we wzorcu.
14
+ */
15
+ export function kptApplyMask(raw, mask) {
16
+ if (!mask)
17
+ return raw;
18
+ const chars = [...raw];
19
+ let charIndex = 0;
20
+ let out = '';
21
+ for (let maskIndex = 0; maskIndex < mask.length && charIndex < chars.length;) {
22
+ const rule = KPT_MASK_TOKENS[mask[maskIndex]];
23
+ if (rule) {
24
+ while (charIndex < chars.length && !rule.test(chars[charIndex]))
25
+ charIndex++;
26
+ if (charIndex >= chars.length)
27
+ break;
28
+ out += chars[charIndex];
29
+ charIndex++;
30
+ }
31
+ else {
32
+ out += mask[maskIndex];
33
+ }
34
+ maskIndex++;
35
+ }
36
+ return out;
37
+ }
38
+ /**
39
+ * Pozycja kursora po przeformatowaniu. Liczy znaczące znaki (te, które maska zabrała) przed
40
+ * kursorem w surowym tekście i stawia kursor za tyloma samymi znakami w wyniku - poprawienie
41
+ * cyfry w środku numeru nie przerzuca kursora na koniec pola.
42
+ */
43
+ export function kptMaskCaret(raw, caret, mask) {
44
+ const formatted = kptApplyMask(raw, mask);
45
+ if (!mask)
46
+ return Math.min(caret, formatted.length);
47
+ const before = kptApplyMask(raw.slice(0, caret), mask);
48
+ // Ile znaczących znaków jest przed kursorem - liczone na wyniku, więc literały się nie liczą.
49
+ let significant = 0;
50
+ for (let i = 0; i < before.length; i += 1)
51
+ if (KPT_MASK_TOKENS[mask[i]])
52
+ significant += 1;
53
+ let seen = 0;
54
+ for (let i = 0; i < formatted.length; i += 1) {
55
+ if (KPT_MASK_TOKENS[mask[i]]) {
56
+ if (seen === significant)
57
+ return i;
58
+ seen += 1;
59
+ }
60
+ }
61
+ return formatted.length;
62
+ }
@@ -0,0 +1,22 @@
1
+ /** Grupowanie włączone, gdy grupa ma co najmniej jedną cyfrę, a separator nie jest pusty. */
2
+ export interface KptDigitGrouping {
3
+ readonly size: number;
4
+ readonly separator: string;
5
+ }
6
+ /**
7
+ * Zdejmuje separatory grup. Wiodący znak `-`/`+` zostaje nawet wtedy, gdy separatorem jest `-`
8
+ * (`-123-456` → `-123456`), bo na początku to znak liczby, a nie granica grupy.
9
+ */
10
+ export declare function kptStripGroups(text: string, separator: string): string;
11
+ /**
12
+ * Wstawia separator co `size` cyfr części całkowitej, licząc od prawej — tak jak tysiące:
13
+ * `123456789` → `123-456-789`, `1234` → `1-234`. Część ułamkowa (po `.` albo `,`) i znak zostają
14
+ * bez zmian. Tekst, który nie wygląda na liczbę w trakcie pisania, wraca nietknięty.
15
+ */
16
+ export declare function kptGroupDigits(text: string, grouping: KptDigitGrouping): string;
17
+ /**
18
+ * Pozycja kursora po przeformatowaniu: tyle samo „znaczących” znaków (cyfry, znak, przecinek
19
+ * dziesiętny) przed kursorem co w tekście sprzed grupowania. Bez tego wstawiony separator
20
+ * przesuwałby kursor o jedno miejsce przy każdej trzeciej cyfrze.
21
+ */
22
+ export declare function kptCaretAfterGrouping(before: string, caret: number, after: string, separator: string): number;
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Grupowanie cyfr w polu liczbowym (`kpt-input-number`, `groupSize` + `groupSeparator`).
3
+ * Bliźniak: packages/angular/src/lib/shared/number-group.ts — zmiana tutaj wymaga zmiany tam.
4
+ */
5
+ /**
6
+ * Zdejmuje separatory grup. Wiodący znak `-`/`+` zostaje nawet wtedy, gdy separatorem jest `-`
7
+ * (`-123-456` → `-123456`), bo na początku to znak liczby, a nie granica grupy.
8
+ */
9
+ export function kptStripGroups(text, separator) {
10
+ if (!separator)
11
+ return text;
12
+ const sign = /^[-+]/.exec(text)?.[0] ?? '';
13
+ return sign + text.slice(sign.length).split(separator).join('');
14
+ }
15
+ /**
16
+ * Wstawia separator co `size` cyfr części całkowitej, licząc od prawej — tak jak tysiące:
17
+ * `123456789` → `123-456-789`, `1234` → `1-234`. Część ułamkowa (po `.` albo `,`) i znak zostają
18
+ * bez zmian. Tekst, który nie wygląda na liczbę w trakcie pisania, wraca nietknięty.
19
+ */
20
+ export function kptGroupDigits(text, grouping) {
21
+ const { size, separator } = grouping;
22
+ if (size < 1 || !separator)
23
+ return text;
24
+ const match = /^([-+]?)(\d*)([.,]\d*)?$/.exec(kptStripGroups(text, separator));
25
+ if (!match)
26
+ return text;
27
+ const [, sign, integer, fraction = ''] = match;
28
+ const groups = [];
29
+ for (let end = integer.length; end > 0; end -= size)
30
+ groups.unshift(integer.slice(Math.max(0, end - size), end));
31
+ return sign + groups.join(separator) + fraction;
32
+ }
33
+ /**
34
+ * Pozycja kursora po przeformatowaniu: tyle samo „znaczących” znaków (cyfry, znak, przecinek
35
+ * dziesiętny) przed kursorem co w tekście sprzed grupowania. Bez tego wstawiony separator
36
+ * przesuwałby kursor o jedno miejsce przy każdej trzeciej cyfrze.
37
+ */
38
+ export function kptCaretAfterGrouping(before, caret, after, separator) {
39
+ const significant = kptStripGroups(before.slice(0, caret), separator).length;
40
+ let seen = 0;
41
+ let index = 0;
42
+ // Wiodący znak liczby liczy się zawsze, nawet gdy jest identyczny z separatorem.
43
+ if (significant > 0 && /^[-+]/.test(after)) {
44
+ seen = 1;
45
+ index = 1;
46
+ }
47
+ while (index < after.length && seen < significant) {
48
+ if (!after.startsWith(separator, index))
49
+ seen += 1;
50
+ index += after.startsWith(separator, index) ? separator.length : 1;
51
+ }
52
+ return index;
53
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Klucz Reacta dla opcji kontrolki generycznej: wartość prymitywna jako tekst, obiekt - pozycja.
3
+ * `String(obiekt)` dawałby "[object Object]" dla każdej opcji, czyli zdublowane klucze i stan
4
+ * przenoszony między opcjami przy zmianie listy.
5
+ */
6
+ export declare function optionKey(value: unknown, index: number): string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Klucz Reacta dla opcji kontrolki generycznej: wartość prymitywna jako tekst, obiekt - pozycja.
3
+ * `String(obiekt)` dawałby "[object Object]" dla każdej opcji, czyli zdublowane klucze i stan
4
+ * przenoszony między opcjami przy zmianie listy.
5
+ */
6
+ export function optionKey(value, index) {
7
+ return typeof value === 'object' && value !== null ? `#${index}` : String(value);
8
+ }
@@ -1,16 +1,16 @@
1
1
  /** Klawisze, które przesuwają aktywną opcję. */
2
2
  export declare const OPTION_NAV_KEYS: Set<string>;
3
3
  /**
4
- * Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania — na
5
- * końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy „nic
6
- * aktywnego”: `↓` idzie wtedy na pierwszą, `↑` na ostatnią. `null` dla innych klawiszy albo listy
4
+ * Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania - na
5
+ * końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy "nic
6
+ * aktywnego": `ArrowDown` idzie wtedy na pierwszą, `ArrowUp` na ostatnią. `null` dla innych klawiszy albo listy
7
7
  * bez aktywnych opcji.
8
8
  */
9
9
  export declare function nextOptionIndex(disabled: readonly boolean[], current: number, key: string): number | null;
10
10
  /**
11
11
  * Wyszukiwanie po pierwszych literach (type-ahead): pierwsza aktywna opcja zaczynająca się od
12
12
  * `query`, licząc od pozycji za `current` i zawijając. Porównanie bez wielkości liter i polskich
13
- * znaków — „lo” znajduje „Łódź”.
13
+ * znaków - "lo" znajduje "Łódź".
14
14
  */
15
15
  export declare function typeaheadIndex(labels: readonly string[], disabled: readonly boolean[], current: number, query: string): number | null;
16
16
  /** Bufor wpisywanych liter dla type-ahead: zeruje się po chwili bez pisania. */
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Nawigacja klawiaturą po liście opcji z aktywną pozycją (`aria-activedescendant`) — wspólna dla
2
+ * Nawigacja klawiaturą po liście opcji z aktywną pozycją (`aria-activedescendant`) - wspólna dla
3
3
  * `KptSelect`, `KptListbox` i `KptAutocomplete`. Port Angulara ma bliźniaczy plik
4
4
  * `shared/option-nav.ts`. Fokus zostaje na kontrolce; zmienia się tylko indeks aktywnej opcji.
5
5
  */
@@ -9,9 +9,9 @@ const PAGE = 10;
9
9
  /** Klawisze, które przesuwają aktywną opcję. */
10
10
  export const OPTION_NAV_KEYS = new Set(['ArrowDown', 'ArrowUp', 'Home', 'End', 'PageDown', 'PageUp']);
11
11
  /**
12
- * Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania — na
13
- * końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy „nic
14
- * aktywnego”: `↓` idzie wtedy na pierwszą, `↑` na ostatnią. `null` dla innych klawiszy albo listy
12
+ * Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania - na
13
+ * końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy "nic
14
+ * aktywnego": `ArrowDown` idzie wtedy na pierwszą, `ArrowUp` na ostatnią. `null` dla innych klawiszy albo listy
15
15
  * bez aktywnych opcji.
16
16
  */
17
17
  export function nextOptionIndex(disabled, current, key) {
@@ -47,7 +47,7 @@ export function nextOptionIndex(disabled, current, key) {
47
47
  /**
48
48
  * Wyszukiwanie po pierwszych literach (type-ahead): pierwsza aktywna opcja zaczynająca się od
49
49
  * `query`, licząc od pozycji za `current` i zawijając. Porównanie bez wielkości liter i polskich
50
- * znaków — „lo” znajduje „Łódź”.
50
+ * znaków - "lo" znajduje "Łódź".
51
51
  */
52
52
  export function typeaheadIndex(labels, disabled, current, query) {
53
53
  const q = foldMentionText(query);
@@ -3,7 +3,7 @@ import { createContext, useContext } from 'react';
3
3
  * Miejsce, do którego portalują się panele nakładek.
4
4
  *
5
5
  * `showModal()` wynosi `<dialog>` do warstwy szczytowej przeglądarki, a ta stoi ponad całym
6
- * drzewem dokumentu — żaden `z-index` tego nie przebije. Panel selecta czy menu otwarty
6
+ * drzewem dokumentu - żaden `z-index` tego nie przebije. Panel selecta czy menu otwarty
7
7
  * z wnętrza modala portalowałby się na `document.body` i byłby NIEWIDOCZNY, schowany za tłem
8
8
  * okna. `KptDialog` podstawia więc siebie jako kontener na czas, gdy jest otwarty.
9
9
  *
@@ -5,7 +5,7 @@ export interface KptOverlayProps {
5
5
  anchor: HTMLElement | null;
6
6
  /** Kliknięcie w backdrop albo Escape. */
7
7
  onClose: () => void;
8
- /** Panel dostaje szerokość wyzwalacza — dokładnie tę (podpowiedzi autocomplete pod polem). */
8
+ /** Panel dostaje szerokość wyzwalacza - dokładnie tę (podpowiedzi autocomplete pod polem). */
9
9
  matchAnchorWidth?: boolean;
10
10
  /**
11
11
  * Panel jest co najmniej tak szeroki jak wyzwalacz, ale rośnie do treści (lista selecta:
@@ -16,13 +16,13 @@ export interface KptOverlayProps {
16
16
  offset?: number;
17
17
  /**
18
18
  * Krawędź, do której wyrównujemy panel: `start` (lewa, domyślnie) albo `end` (prawa).
19
- * `end` przydaje się, gdy wyzwalacz siedzi przy prawej krawędzi kontrolki — panel otwiera się
19
+ * `end` przydaje się, gdy wyzwalacz siedzi przy prawej krawędzi kontrolki - panel otwiera się
20
20
  * wtedy w lewo i nie wychodzi poza nią.
21
21
  */
22
22
  align?: 'start' | 'end';
23
23
  /**
24
24
  * Przezroczysty backdrop przechwytujący kliknięcie poza panelem. Wyłącz go tam, gdzie panel
25
- * ma zostawić wyzwalacz klikalnym — autocomplete zamyka się na `blur` pola, a backdrop
25
+ * ma zostawić wyzwalacz klikalnym - autocomplete zamyka się na `blur` pola, a backdrop
26
26
  * zasłoniłby to pole i zabrałby mu każde kliknięcie.
27
27
  */
28
28
  withBackdrop?: boolean;
@@ -1,8 +1,20 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
3
4
  import { createPortal } from 'react-dom';
4
5
  import { useKptOverlayContainer } from "./overlay-container.js";
5
- /** Ta sama warstwa co `--kpt-z-overlay` w tokenach — panel ma być nad treścią aplikacji. */
6
+ /*
7
+ * Prymityw nakładki: panel przypięty do wyzwalacza, renderowany w portalu do `document.body`.
8
+ *
9
+ * Port Angulara stoi tu na CDK Overlay, którego w Reakcie nie ma. Odtwarzamy jego zachowanie:
10
+ * pozycjonowanie względem wyzwalacza z odbiciem w górę, gdy pod spodem brakuje miejsca,
11
+ * przezroczysty backdrop zamykający kliknięciem oraz Escape. Style samego panelu pochodzą
12
+ * ze wspólnego arkusza (`.kpt-select__panel`, `.kpt-popover__panel`) - tutaj są wyłącznie
13
+ * współrzędne, więc nic nie duplikuje wyglądu.
14
+ */
15
+ /** Otwarte nakładki od najstarszej - Escape obsługuje tylko ostatnia. */
16
+ const overlayStack = [];
17
+ /** Ta sama warstwa co `--kpt-z-overlay` w tokenach - panel ma być nad treścią aplikacji. */
6
18
  const Z_INDEX = 'var(--kpt-z-overlay, 1100)';
7
19
  export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, minAnchorWidth = false, offset = 4, align = 'start', withBackdrop = true, preferAbove = false, children, }) {
8
20
  const container = useKptOverlayContainer();
@@ -16,7 +28,7 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
16
28
  const panelWidth = panelRef.current?.offsetWidth ?? 0;
17
29
  const below = window.innerHeight - rect.bottom;
18
30
  // Odbicie w górę tylko wtedy, gdy pod spodem naprawdę brakuje miejsca, a nad wyzwalaczem
19
- // jest go więcej — inaczej panel skakałby przy każdym przewinięciu o kilka pikseli.
31
+ // jest go więcej - inaczej panel skakałby przy każdym przewinięciu o kilka pikseli.
20
32
  // Przy `preferAbove` jest odwrotnie: panel stoi nad wyzwalaczem, dopóki się tam mieści.
21
33
  const fitsAbove = panelHeight === 0 || rect.top > panelHeight + offset;
22
34
  const flip = preferAbove ? fitsAbove : panelHeight > 0 && below < panelHeight + offset && rect.top > below;
@@ -27,12 +39,17 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
27
39
  ...(minAnchorWidth ? { minWidth: rect.width } : {}),
28
40
  });
29
41
  }, [anchor, matchAnchorWidth, minAnchorWidth, offset, align, preferAbove]);
30
- useLayoutEffect(() => {
31
- if (!open) {
42
+ // Zamknięcie zeruje pozycję w tym samym renderze (wzorzec "poprzednia wartość w stanie"), więc
43
+ // ponowne otwarcie nie pokaże panelu na klatkę w starym miejscu - bez setState w efekcie.
44
+ const [wasOpen, setWasOpen] = useState(open);
45
+ if (wasOpen !== open) {
46
+ setWasOpen(open);
47
+ if (!open)
32
48
  setPosition(null);
33
- return;
34
- }
35
- update();
49
+ }
50
+ useLayoutEffect(() => {
51
+ if (open)
52
+ update();
36
53
  }, [open, update]);
37
54
  useEffect(() => {
38
55
  if (!open)
@@ -41,15 +58,28 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
41
58
  // `capture` łapie też przewijanie kontenerów w środku strony, nie tylko okna.
42
59
  window.addEventListener('scroll', onScrollOrResize, true);
43
60
  window.addEventListener('resize', onScrollOrResize);
61
+ /*
62
+ * Escape zamyka tylko najwyższą nakładkę (stos jak `OverlayKeyboardDispatcher` w CDK) i tylko
63
+ * wtedy, gdy komponent nie obsłużył klawisza sam. `preventDefault` jest konieczne: natywny
64
+ * `<dialog>` traktuje ten sam Escape jako żądanie zamknięcia - popover w `KptDialog` zamykał
65
+ * razem ze sobą całe okno.
66
+ */
67
+ const token = {};
68
+ overlayStack.push(token);
44
69
  const onKeyDown = (event) => {
45
- if (event.key === 'Escape')
46
- onClose();
70
+ if (event.key !== 'Escape' || event.defaultPrevented)
71
+ return;
72
+ if (overlayStack[overlayStack.length - 1] !== token)
73
+ return;
74
+ event.preventDefault();
75
+ onClose();
47
76
  };
48
77
  document.addEventListener('keydown', onKeyDown);
49
78
  return () => {
50
79
  window.removeEventListener('scroll', onScrollOrResize, true);
51
80
  window.removeEventListener('resize', onScrollOrResize);
52
81
  document.removeEventListener('keydown', onKeyDown);
82
+ overlayStack.splice(overlayStack.indexOf(token), 1);
53
83
  };
54
84
  }, [open, update, onClose]);
55
85
  if (!open || !container)
@@ -61,7 +91,7 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
61
91
  width: position?.width,
62
92
  minWidth: position?.minWidth,
63
93
  zIndex: Z_INDEX,
64
- // Panel bez pozycji jeszcze nie został zmierzony — chowamy go na pierwszej klatce,
94
+ // Panel bez pozycji jeszcze nie został zmierzony - chowamy go na pierwszej klatce,
65
95
  // żeby nie mrugnął w lewym górnym rogu.
66
96
  visibility: position ? 'visible' : 'hidden',
67
97
  }, children: children })] }), container);
@@ -0,0 +1,6 @@
1
+ /** 0 = bardzo słabe ... 4 = silne. */
2
+ export type KptPasswordScore = 0 | 1 | 2 | 3 | 4;
3
+ /** Przybliżona entropia w bitach. */
4
+ export declare function kptPasswordBits(value: string): number;
5
+ /** Wynik 0-4 z entropii: <28 bardzo słabe, <36 słabe, <50 średnie, <64 dobre, reszta silne. */
6
+ export declare function kptPasswordScore(value: string): KptPasswordScore;