@konce-pt/react 0.11.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +128 -64
  2. package/dist/accordion/accordion.d.ts +14 -6
  3. package/dist/accordion/accordion.js +25 -17
  4. package/dist/accordion/llms.txt +22 -10
  5. package/dist/alert/alert.d.ts +2 -2
  6. package/dist/alert/alert.js +3 -2
  7. package/dist/alert/llms.txt +10 -9
  8. package/dist/app-shell/app-shell.d.ts +14 -14
  9. package/dist/app-shell/app-shell.js +22 -15
  10. package/dist/app-shell/llms.txt +16 -15
  11. package/dist/auth/auth-types.d.ts +6 -6
  12. package/dist/auth/auth.d.ts +2 -2
  13. package/dist/auth/auth.js +24 -15
  14. package/dist/auth/llms.txt +12 -11
  15. package/dist/autocomplete/autocomplete.d.ts +19 -6
  16. package/dist/autocomplete/autocomplete.js +32 -11
  17. package/dist/autocomplete/llms.txt +19 -5
  18. package/dist/avatar/avatar.d.ts +6 -6
  19. package/dist/avatar/avatar.js +6 -5
  20. package/dist/avatar/llms.txt +10 -10
  21. package/dist/avatar-group/avatar-group.d.ts +4 -4
  22. package/dist/avatar-group/avatar-group.js +4 -3
  23. package/dist/avatar-group/llms.txt +8 -8
  24. package/dist/backdrop/backdrop.d.ts +7 -26
  25. package/dist/backdrop/backdrop.js +32 -27
  26. package/dist/backdrop/llms.txt +27 -27
  27. package/dist/badge/badge.d.ts +3 -3
  28. package/dist/badge/badge.js +1 -1
  29. package/dist/badge/llms.txt +11 -11
  30. package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
  31. package/dist/bottom-sheet/bottom-sheet.js +5 -4
  32. package/dist/bottom-sheet/llms.txt +11 -8
  33. package/dist/breadcrumb/breadcrumb.d.ts +8 -2
  34. package/dist/breadcrumb/breadcrumb.js +11 -3
  35. package/dist/breadcrumb/llms.txt +10 -2
  36. package/dist/button/button.d.ts +3 -3
  37. package/dist/button/button.js +10 -9
  38. package/dist/button/llms.txt +27 -19
  39. package/dist/button-group/button-group.d.ts +18 -5
  40. package/dist/button-group/button-group.js +54 -6
  41. package/dist/button-group/llms.txt +27 -18
  42. package/dist/card/card.d.ts +8 -8
  43. package/dist/card/card.js +10 -9
  44. package/dist/card/llms.txt +20 -20
  45. package/dist/carousel/carousel.d.ts +6 -6
  46. package/dist/carousel/carousel.js +8 -5
  47. package/dist/carousel/llms.txt +10 -10
  48. package/dist/charts/chart-legend.d.ts +3 -3
  49. package/dist/charts/chart-legend.js +2 -1
  50. package/dist/charts/chart-tooltip.d.ts +3 -3
  51. package/dist/charts/chart-tooltip.js +1 -1
  52. package/dist/charts/chart.d.ts +4 -3
  53. package/dist/charts/chart.js +18 -10
  54. package/dist/charts/llms.txt +10 -7
  55. package/dist/charts-entry/public-api.js +2 -2
  56. package/dist/chat/chat.d.ts +17 -10
  57. package/dist/chat/chat.js +77 -23
  58. package/dist/chat/llms.txt +39 -15
  59. package/dist/chat-composer/chat-composer.d.ts +20 -7
  60. package/dist/chat-composer/chat-composer.js +29 -7
  61. package/dist/chat-composer/llms.txt +20 -11
  62. package/dist/chat-dock/chat-dock.d.ts +11 -4
  63. package/dist/chat-dock/chat-dock.js +10 -6
  64. package/dist/chat-dock/llms.txt +15 -14
  65. package/dist/chat-entry/public-api.js +1 -1
  66. package/dist/chat-message/chat-message.d.ts +12 -5
  67. package/dist/chat-message/chat-message.js +19 -8
  68. package/dist/chat-message/llms.txt +16 -15
  69. package/dist/chat-typing/chat-typing.d.ts +2 -2
  70. package/dist/chat-typing/chat-typing.js +4 -3
  71. package/dist/chat-typing/llms.txt +6 -6
  72. package/dist/checkbox/checkbox.d.ts +13 -6
  73. package/dist/checkbox/checkbox.js +31 -5
  74. package/dist/checkbox/llms.txt +26 -11
  75. package/dist/chip/chip.d.ts +4 -4
  76. package/dist/chip/chip.js +3 -2
  77. package/dist/chip/llms.txt +11 -11
  78. package/dist/chips-input/chips-input.d.ts +6 -4
  79. package/dist/chips-input/chips-input.js +47 -12
  80. package/dist/chips-input/llms.txt +18 -8
  81. package/dist/clock/clock.d.ts +11 -6
  82. package/dist/clock/clock.js +38 -8
  83. package/dist/clock/llms.txt +12 -8
  84. package/dist/color-picker/color-picker.d.ts +9 -5
  85. package/dist/color-picker/color-picker.js +37 -18
  86. package/dist/color-picker/llms.txt +8 -5
  87. package/dist/confirm/confirm-container.d.ts +3 -3
  88. package/dist/confirm/confirm-container.js +6 -5
  89. package/dist/confirm/confirm-store.d.ts +4 -4
  90. package/dist/confirm/confirm-store.js +11 -5
  91. package/dist/confirm/llms.txt +8 -7
  92. package/dist/context-menu/context-menu.d.ts +1 -1
  93. package/dist/context-menu/context-menu.js +37 -14
  94. package/dist/context-menu/llms.txt +10 -7
  95. package/dist/data-table/data-table-types.d.ts +5 -5
  96. package/dist/data-table/data-table.d.ts +37 -5
  97. package/dist/data-table/data-table.js +426 -119
  98. package/dist/data-table/export-csv.d.ts +3 -3
  99. package/dist/data-table/export-csv.js +8 -10
  100. package/dist/data-table/llms.txt +127 -79
  101. package/dist/data-view/data-view.d.ts +13 -5
  102. package/dist/data-view/data-view.js +68 -6
  103. package/dist/data-view/llms.txt +29 -10
  104. package/dist/date-range/date-range.d.ts +20 -8
  105. package/dist/date-range/date-range.js +86 -63
  106. package/dist/date-range/llms.txt +32 -18
  107. package/dist/datepicker/datepicker.d.ts +22 -8
  108. package/dist/datepicker/datepicker.js +103 -71
  109. package/dist/datepicker/llms.txt +36 -22
  110. package/dist/dialog/dialog.d.ts +4 -4
  111. package/dist/dialog/dialog.js +32 -11
  112. package/dist/dialog/llms.txt +13 -10
  113. package/dist/divider/divider.d.ts +7 -1
  114. package/dist/divider/divider.js +3 -2
  115. package/dist/divider/llms.txt +4 -3
  116. package/dist/drawer/drawer.d.ts +9 -4
  117. package/dist/drawer/drawer.js +5 -4
  118. package/dist/drawer/llms.txt +13 -10
  119. package/dist/empty/empty.d.ts +2 -2
  120. package/dist/empty/empty.js +1 -1
  121. package/dist/empty/llms.txt +9 -9
  122. package/dist/fab/fab.d.ts +1 -1
  123. package/dist/fab/fab.js +1 -1
  124. package/dist/fab/llms.txt +10 -6
  125. package/dist/fieldset/fieldset.d.ts +18 -4
  126. package/dist/fieldset/fieldset.js +12 -6
  127. package/dist/fieldset/llms.txt +26 -9
  128. package/dist/file-upload/file-upload.d.ts +8 -2
  129. package/dist/file-upload/file-upload.js +22 -11
  130. package/dist/file-upload/llms.txt +12 -9
  131. package/dist/form-field/form-field-context.d.ts +4 -4
  132. package/dist/form-field/form-field.d.ts +12 -4
  133. package/dist/form-field/form-field.js +27 -6
  134. package/dist/form-field/llms.txt +25 -11
  135. package/dist/galleria/galleria.d.ts +3 -3
  136. package/dist/galleria/galleria.js +9 -6
  137. package/dist/galleria/llms.txt +7 -7
  138. package/dist/grid/col.d.ts +4 -4
  139. package/dist/grid/col.js +2 -2
  140. package/dist/grid/flex.d.ts +3 -3
  141. package/dist/grid/flex.js +1 -1
  142. package/dist/grid/grid.d.ts +7 -7
  143. package/dist/grid/grid.js +3 -3
  144. package/dist/grid/layout.d.ts +2 -2
  145. package/dist/grid/layout.js +2 -2
  146. package/dist/grid/llms.txt +15 -15
  147. package/dist/grid-entry/public-api.js +1 -1
  148. package/dist/i18n/i18n-context.d.ts +6 -6
  149. package/dist/i18n/i18n-context.js +27 -5
  150. package/dist/icon/icon-registry.d.ts +3 -3
  151. package/dist/icon/icon-registry.js +3 -3
  152. package/dist/icon/icon.d.ts +4 -4
  153. package/dist/icon/icon.js +10 -7
  154. package/dist/icon/llms.txt +13 -13
  155. package/dist/icon-button/icon-button.d.ts +2 -2
  156. package/dist/icon-button/icon-button.js +1 -1
  157. package/dist/icon-button/llms.txt +9 -5
  158. package/dist/icons-entry/public-api.d.ts +2 -2
  159. package/dist/icons-entry/public-api.js +3 -3
  160. package/dist/image/image.js +5 -5
  161. package/dist/image/llms.txt +13 -13
  162. package/dist/input/input.d.ts +18 -5
  163. package/dist/input/input.js +22 -6
  164. package/dist/input/llms.txt +25 -11
  165. package/dist/input-mask/input-mask.d.ts +7 -2
  166. package/dist/input-mask/input-mask.js +17 -43
  167. package/dist/input-mask/llms.txt +8 -5
  168. package/dist/input-number/input-number.d.ts +11 -9
  169. package/dist/input-number/input-number.js +25 -21
  170. package/dist/input-number/llms.txt +17 -14
  171. package/dist/input-otp/input-otp.d.ts +18 -5
  172. package/dist/input-otp/input-otp.js +48 -24
  173. package/dist/input-otp/llms.txt +18 -7
  174. package/dist/internal/calendar-focus.d.ts +1 -1
  175. package/dist/internal/calendar-focus.js +3 -3
  176. package/dist/internal/cn.d.ts +1 -1
  177. package/dist/internal/mask.d.ts +14 -0
  178. package/dist/internal/mask.js +62 -0
  179. package/dist/internal/number-group.d.ts +22 -0
  180. package/dist/internal/number-group.js +53 -0
  181. package/dist/internal/option-key.d.ts +6 -0
  182. package/dist/internal/option-key.js +8 -0
  183. package/dist/internal/option-nav.d.ts +4 -4
  184. package/dist/internal/option-nav.js +5 -5
  185. package/dist/internal/overlay-container.js +1 -1
  186. package/dist/internal/overlay.d.ts +3 -3
  187. package/dist/internal/overlay.js +40 -10
  188. package/dist/internal/password-strength.d.ts +6 -0
  189. package/dist/internal/password-strength.js +74 -0
  190. package/dist/internal/roving.d.ts +2 -2
  191. package/dist/internal/roving.js +3 -3
  192. package/dist/internal/scroll-lock.d.ts +6 -0
  193. package/dist/internal/scroll-lock.js +35 -0
  194. package/dist/internal/slot-children.d.ts +13 -0
  195. package/dist/internal/slot-children.js +31 -0
  196. package/dist/internal/slot.d.ts +3 -3
  197. package/dist/internal/slot.js +2 -2
  198. package/dist/internal/step.d.ts +12 -0
  199. package/dist/internal/step.js +31 -0
  200. package/dist/internal/tween.d.ts +5 -5
  201. package/dist/internal/tween.js +7 -8
  202. package/dist/internal/types.d.ts +2 -2
  203. package/dist/internal/use-breakpoint.d.ts +2 -2
  204. package/dist/internal/use-breakpoint.js +4 -4
  205. package/dist/internal/use-controllable-state.d.ts +5 -0
  206. package/dist/internal/use-controllable-state.js +25 -4
  207. package/dist/internal/use-id.d.ts +2 -2
  208. package/dist/internal/use-id.js +2 -2
  209. package/dist/internal/use-modal-focus.d.ts +2 -1
  210. package/dist/internal/use-modal-focus.js +14 -3
  211. package/dist/knob/knob.d.ts +7 -4
  212. package/dist/knob/knob.js +27 -22
  213. package/dist/knob/llms.txt +18 -11
  214. package/dist/listbox/listbox.d.ts +8 -6
  215. package/dist/listbox/listbox.js +37 -17
  216. package/dist/listbox/llms.txt +12 -9
  217. package/dist/loader/llms.txt +56 -0
  218. package/dist/loader/loader.d.ts +49 -0
  219. package/dist/loader/loader.js +68 -0
  220. package/dist/map/llms.txt +30 -23
  221. package/dist/map/map-create-dialog.d.ts +4 -4
  222. package/dist/map/map-create-dialog.js +36 -28
  223. package/dist/map/map-hours-field.d.ts +4 -4
  224. package/dist/map/map-hours-field.js +8 -7
  225. package/dist/map/map-image-field.d.ts +2 -2
  226. package/dist/map/map-image-field.js +6 -5
  227. package/dist/map/map-legend.d.ts +4 -4
  228. package/dist/map/map-legend.js +3 -2
  229. package/dist/map/map-poi-card.d.ts +3 -3
  230. package/dist/map/map-poi-card.js +10 -9
  231. package/dist/map/map-search.d.ts +17 -6
  232. package/dist/map/map-search.js +70 -43
  233. package/dist/map/map.d.ts +25 -13
  234. package/dist/map/map.js +86 -57
  235. package/dist/map/ports.d.ts +9 -9
  236. package/dist/map/ports.js +6 -6
  237. package/dist/map-entry/public-api.js +2 -2
  238. package/dist/megamenu/llms.txt +18 -7
  239. package/dist/megamenu/megamenu.d.ts +12 -6
  240. package/dist/megamenu/megamenu.js +23 -14
  241. package/dist/mention/llms.txt +15 -15
  242. package/dist/mention/mention.d.ts +5 -5
  243. package/dist/mention/mention.js +2 -2
  244. package/dist/mention/mentions.d.ts +1 -1
  245. package/dist/mention/mentions.js +1 -1
  246. package/dist/menu/llms.txt +12 -12
  247. package/dist/menu/menu-item.d.ts +4 -4
  248. package/dist/menu/menu-keys.d.ts +2 -2
  249. package/dist/menu/menu-keys.js +5 -5
  250. package/dist/menu/menu-rows.js +1 -0
  251. package/dist/menu/menu.d.ts +2 -2
  252. package/dist/menu/menu.js +15 -8
  253. package/dist/menubar/llms.txt +19 -8
  254. package/dist/menubar/menubar.d.ts +11 -5
  255. package/dist/menubar/menubar.js +23 -11
  256. package/dist/meter-group/llms.txt +12 -12
  257. package/dist/meter-group/meter-group.d.ts +2 -2
  258. package/dist/meter-group/meter-group.js +2 -1
  259. package/dist/motion/motion-context.d.ts +22 -0
  260. package/dist/motion/motion-context.js +28 -0
  261. package/dist/order-list/llms.txt +24 -9
  262. package/dist/order-list/order-list.d.ts +12 -4
  263. package/dist/order-list/order-list.js +123 -25
  264. package/dist/paginator/llms.txt +8 -8
  265. package/dist/paginator/paginator.js +7 -4
  266. package/dist/panel/llms.txt +25 -13
  267. package/dist/panel/panel.d.ts +11 -3
  268. package/dist/panel/panel.js +12 -7
  269. package/dist/password/llms.txt +19 -7
  270. package/dist/password/password.d.ts +2 -2
  271. package/dist/password/password.js +27 -16
  272. package/dist/peek/llms.txt +11 -11
  273. package/dist/peek/peek.d.ts +6 -6
  274. package/dist/peek/peek.js +41 -19
  275. package/dist/pick-list/llms.txt +35 -12
  276. package/dist/pick-list/pick-list.d.ts +12 -4
  277. package/dist/pick-list/pick-list.js +128 -24
  278. package/dist/popover/llms.txt +13 -10
  279. package/dist/popover/popover.d.ts +6 -4
  280. package/dist/popover/popover.js +14 -7
  281. package/dist/progress/llms.txt +17 -17
  282. package/dist/progress/progress.d.ts +7 -7
  283. package/dist/progress/progress.js +7 -6
  284. package/dist/public-api.d.ts +16 -4
  285. package/dist/public-api.js +13 -7
  286. package/dist/radio-group/llms.txt +16 -6
  287. package/dist/radio-group/radio-group.d.ts +12 -3
  288. package/dist/radio-group/radio-group.js +23 -4
  289. package/dist/rating/llms.txt +20 -13
  290. package/dist/rating/rating-pointer.d.ts +16 -0
  291. package/dist/rating/rating-pointer.js +26 -0
  292. package/dist/rating/rating.d.ts +6 -6
  293. package/dist/rating/rating.js +77 -12
  294. package/dist/rich-text/lists.d.ts +2 -2
  295. package/dist/rich-text/lists.js +7 -7
  296. package/dist/rich-text/llms.txt +35 -12
  297. package/dist/rich-text/rich-text.d.ts +13 -14
  298. package/dist/rich-text/rich-text.js +311 -142
  299. package/dist/rich-text/sanitize.d.ts +11 -2
  300. package/dist/rich-text/sanitize.js +80 -32
  301. package/dist/rich-text/tables.d.ts +3 -3
  302. package/dist/rich-text/tables.js +3 -3
  303. package/dist/roadmap/llms.txt +23 -17
  304. package/dist/roadmap/roadmap.d.ts +6 -6
  305. package/dist/roadmap/roadmap.js +102 -25
  306. package/dist/roadmap-entry/public-api.js +2 -2
  307. package/dist/scroll-top/llms.txt +6 -6
  308. package/dist/scroll-top/scroll-top.d.ts +1 -1
  309. package/dist/scroll-top/scroll-top.js +2 -1
  310. package/dist/select/llms.txt +22 -12
  311. package/dist/select/select.d.ts +10 -8
  312. package/dist/select/select.js +87 -47
  313. package/dist/shared/types.d.ts +22 -1
  314. package/dist/shared/types.js +9 -1
  315. package/dist/sidenav/llms.txt +9 -9
  316. package/dist/sidenav/sidenav.d.ts +2 -3
  317. package/dist/sidenav/sidenav.js +5 -4
  318. package/dist/skeleton/llms.txt +3 -3
  319. package/dist/skeleton/skeleton.d.ts +1 -1
  320. package/dist/skeleton/skeleton.js +1 -1
  321. package/dist/slider/llms.txt +34 -12
  322. package/dist/slider/slider-drag.d.ts +26 -0
  323. package/dist/slider/slider-drag.js +79 -0
  324. package/dist/slider/slider.d.ts +8 -5
  325. package/dist/slider/slider.js +38 -8
  326. package/dist/speech/llms.txt +97 -0
  327. package/dist/speech/speech-button.d.ts +44 -0
  328. package/dist/speech/speech-button.js +86 -0
  329. package/dist/speech/speech-wave.d.ts +19 -0
  330. package/dist/speech/speech-wave.js +16 -0
  331. package/dist/speech/use-speech-recognition.d.ts +81 -0
  332. package/dist/speech/use-speech-recognition.js +179 -0
  333. package/dist/speed-dial/llms.txt +14 -8
  334. package/dist/speed-dial/speed-dial.d.ts +1 -1
  335. package/dist/speed-dial/speed-dial.js +3 -2
  336. package/dist/spinner/llms.txt +7 -7
  337. package/dist/spinner/spinner.d.ts +1 -1
  338. package/dist/spinner/spinner.js +2 -1
  339. package/dist/split-button/llms.txt +21 -15
  340. package/dist/split-button/split-button.d.ts +2 -2
  341. package/dist/split-button/split-button.js +13 -6
  342. package/dist/splitter/llms.txt +11 -11
  343. package/dist/splitter/splitter.d.ts +3 -3
  344. package/dist/splitter/splitter.js +25 -10
  345. package/dist/stepper/llms.txt +35 -13
  346. package/dist/stepper/stepper.d.ts +6 -6
  347. package/dist/stepper/stepper.js +60 -13
  348. package/dist/switch/llms.txt +15 -5
  349. package/dist/switch/switch.d.ts +10 -3
  350. package/dist/switch/switch.js +18 -4
  351. package/dist/switch-group/llms.txt +11 -8
  352. package/dist/switch-group/switch-group.d.ts +6 -4
  353. package/dist/switch-group/switch-group.js +9 -7
  354. package/dist/tabs/llms.txt +12 -9
  355. package/dist/tabs/tabs.d.ts +5 -5
  356. package/dist/tabs/tabs.js +36 -20
  357. package/dist/textarea/llms.txt +23 -12
  358. package/dist/textarea/textarea.d.ts +19 -6
  359. package/dist/textarea/textarea.js +22 -7
  360. package/dist/timeline/llms.txt +4 -4
  361. package/dist/timeline/timeline.d.ts +1 -1
  362. package/dist/timeline/timeline.js +1 -1
  363. package/dist/toast/llms.txt +50 -17
  364. package/dist/toast/toast-container.d.ts +9 -3
  365. package/dist/toast/toast-container.js +18 -9
  366. package/dist/toast/toast-store.d.ts +42 -2
  367. package/dist/toast/toast-store.js +36 -1
  368. package/dist/toolbar/llms.txt +7 -7
  369. package/dist/toolbar/toolbar.d.ts +3 -3
  370. package/dist/toolbar/toolbar.js +2 -2
  371. package/dist/tooltip/llms.txt +14 -12
  372. package/dist/tooltip/tooltip.d.ts +5 -4
  373. package/dist/tooltip/tooltip.js +100 -41
  374. package/dist/tree/llms.txt +25 -11
  375. package/dist/tree/tree-keys.d.ts +5 -5
  376. package/dist/tree/tree-keys.js +7 -7
  377. package/dist/tree/tree.d.ts +17 -5
  378. package/dist/tree/tree.js +62 -20
  379. package/dist/update/llms.txt +54 -0
  380. package/dist/update/update.d.ts +49 -0
  381. package/dist/update/update.js +82 -0
  382. package/package.json +18 -15
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useEffect, useRef, useState } from 'react';
3
4
  import { cn } from "../internal/cn.js";
@@ -5,11 +6,12 @@ import { KptOverlay } from "../internal/overlay.js";
5
6
  import { nextRovingIndex, rovingStop } from "../internal/roving.js";
6
7
  import { useKptId } from "../internal/use-id.js";
7
8
  import { KptIcon } from "../icon/icon.js";
9
+ import { kptIsPlainClick } from "../shared/types.js";
8
10
  import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
9
11
  /**
10
- * Mega-menu — pozioma belka z szerokim, wielokolumnowym panelem.
11
- * Struktura: pozycja górna → `items` (kolumny) → `items` kolumny (odnośniki).
12
- * Pozycja górna bez kolumn działa jak akcja — wywołuje `onSelect` zamiast otwierać pusty panel.
12
+ * Mega-menu - pozioma belka z szerokim, wielokolumnowym panelem.
13
+ * Struktura: pozycja górna -> `items` (kolumny) -> `items` kolumny (odnośniki).
14
+ * Pozycja górna bez kolumn działa jak akcja - wywołuje `onSelect` zamiast otwierać pusty panel.
13
15
  *
14
16
  * Panel kotwiczy się do CAŁEJ belki, nie do pojedynczego przycisku: jest szeroki, więc ma
15
17
  * zaczynać się przy krawędzi menu, a nie przy przypadkowej pozycji, w którą kliknięto.
@@ -17,24 +19,25 @@ import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
17
19
  * Klawiatura jak w `KptMenubar`: belka to jeden przystanek Tab, strzałki w lewo/prawo
18
20
  * i `Home`/`End` chodzą po pozycjach górnych, strzałka w dół (albo `Enter`/spacja) otwiera panel
19
21
  * z fokusem na pierwszym odnośniku. W panelu strzałki w górę/dół przechodzą po wszystkich
20
- * odnośnikach kolumna po kolumnie, w lewo/prawo — do panelu sąsiedniej pozycji, a `Escape`
22
+ * odnośnikach kolumna po kolumnie, w lewo/prawo - do panelu sąsiedniej pozycji, a `Escape`
21
23
  * zamyka panel i oddaje fokus belce.
22
24
  *
23
25
  * @example
24
26
  * <KptMegamenu items={items} onSelect={onSelect} />
25
27
  */
26
- export function KptMegamenu({ items = [], onSelect, ariaLabel, className, ...rest }) {
27
- const barRef = useRef(null);
28
+ export function KptMegamenu({ items = [], onSelect, onNavigate, ariaLabel, className, ...rest }) {
29
+ /** Pasek jako kotwica panelu - w stanie, bo czyta go render. */
30
+ const [bar, setBar] = useState(null);
28
31
  const panelRef = useRef(null);
29
32
  const buttonsRef = useRef([]);
30
33
  const [openIndex, setOpenIndex] = useState(null);
31
- // Ostatnio skupiona pozycja górna — ona jest przystankiem Tab belki.
34
+ // Ostatnio skupiona pozycja górna - ona jest przystankiem Tab belki.
32
35
  const [focusIndex, setFocusIndex] = useState(0);
33
- // Który odnośnik skupić po otwarciu — strzałka w górę otwiera „od końca”.
36
+ // Który odnośnik skupić po otwarciu - strzałka w górę otwiera "od końca".
34
37
  const focusEdge = useRef('first');
35
38
  const panelId = useKptId(undefined, 'kpt-megamenu');
36
39
  const disabled = items.map((item) => !!item.disabled);
37
- // Pozycja z `url` (bez kolumn, niewyłączona) to `<a href>` — nawigację robi przeglądarka,
40
+ // Pozycja z `url` (bez kolumn, niewyłączona) to `<a href>` - nawigację robi przeglądarka,
38
41
  // więc działa nowa karta i podgląd adresu. `onSelect` i tak jest wołane.
39
42
  const isLink = (item) => !!item.url && !item.items?.length && !item.disabled;
40
43
  const tabStop = rovingStop(disabled, focusIndex);
@@ -99,7 +102,7 @@ export function KptMegamenu({ items = [], onSelect, ariaLabel, className, ...res
99
102
  if (next === null)
100
103
  return;
101
104
  event.preventDefault();
102
- // Przy otwartym panelu przejście w bok pokazuje panel sąsiada — jak w menu aplikacji.
105
+ // Przy otwartym panelu przejście w bok pokazuje panel sąsiada - jak w menu aplikacji.
103
106
  if (openIndex === null)
104
107
  focusTop(next);
105
108
  else
@@ -122,18 +125,24 @@ export function KptMegamenu({ items = [], onSelect, ariaLabel, className, ...res
122
125
  focusTop(top);
123
126
  }
124
127
  };
125
- return (_jsxs("div", { className: cn('kpt-megamenu-host', className), ...rest, children: [_jsx("div", { className: "kpt-megamenu", role: "menubar", "aria-orientation": "horizontal", "aria-label": ariaLabel || undefined, ref: barRef, children: items.map((item, index) => {
128
+ /** Zwykły klik w odnośnik -> `onNavigate` (Ctrl/Cmd/Shift, środkowy przycisk i `_blank` zostają natywne). */
129
+ const linkClick = (event, item) => {
130
+ if (item.url && onNavigate && kptIsPlainClick(event, event.currentTarget.target)) {
131
+ onNavigate({ item, url: item.url, event: event.nativeEvent });
132
+ }
133
+ };
134
+ return (_jsxs("div", { className: cn('kpt-megamenu-host', className), ...rest, children: [_jsx("div", { className: "kpt-megamenu", role: "menubar", "aria-orientation": "horizontal", "aria-label": ariaLabel || undefined, ref: setBar, children: items.map((item, index) => {
126
135
  const hasMenu = !!item.items?.length;
127
136
  if (isLink(item)) {
128
137
  return (_jsxs("a", { ref: (el) => {
129
138
  buttonsRef.current[index] = el;
130
- }, className: "kpt-megamenu__top", role: "menuitem", href: item.url, tabIndex: index === tabStop ? 0 : -1, onClick: () => toggle(index, item), onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label })] }, index));
139
+ }, className: "kpt-megamenu__top", role: "menuitem", href: item.url, tabIndex: index === tabStop ? 0 : -1, onClick: (event) => { linkClick(event, item); toggle(index, item); }, onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label })] }, index));
131
140
  }
132
141
  return (_jsxs("button", { ref: (el) => {
133
142
  buttonsRef.current[index] = el;
134
143
  }, type: "button", className: cn('kpt-megamenu__top', openIndex === index && 'is-open'), role: "menuitem", disabled: item.disabled, tabIndex: index === tabStop ? 0 : -1, "aria-haspopup": hasMenu ? 'menu' : undefined, "aria-expanded": hasMenu ? openIndex === index : undefined, "aria-controls": openIndex === index ? panelId : undefined, onClick: () => toggle(index, item), onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label }), hasMenu ? _jsx(KptIcon, { name: "chevron-down", className: "kpt-megamenu__caret" }) : null] }, index));
135
- }) }), _jsx(KptOverlay, { open: openIndex !== null, anchor: barRef.current, onClose: closeAll, children: _jsx("div", { ref: panelRef, className: "kpt-megamenu__panel", role: "menu", id: panelId, "aria-label": openIndex === null ? undefined : items[openIndex]?.label, onKeyDown: onPanelKeyDown, children: columns.map((column, columnIndex) => {
144
+ }) }), _jsx(KptOverlay, { open: openIndex !== null, anchor: bar, onClose: closeAll, children: _jsx("div", { ref: panelRef, className: "kpt-megamenu__panel", role: "menu", tabIndex: -1, id: panelId, "aria-label": openIndex === null ? undefined : items[openIndex]?.label, onKeyDown: onPanelKeyDown, children: columns.map((column, columnIndex) => {
136
145
  const titleId = `${panelId}-col-${columnIndex}`;
137
- return (_jsxs("div", { className: "kpt-megamenu__column", role: "group", "aria-labelledby": column.label ? titleId : undefined, children: [column.label ? (_jsx("div", { className: "kpt-megamenu__col-title", role: "presentation", id: titleId, children: column.label })) : null, (column.items ?? []).map((link, linkIndex) => isLink(link) ? (_jsxs("a", { className: "kpt-megamenu__link", role: "menuitem", tabIndex: -1, href: link.url, onClick: () => pick(link), children: [link.icon ? _jsx(KptIcon, { name: link.icon }) : null, _jsx("span", { children: link.label })] }, linkIndex)) : (_jsxs("button", { type: "button", className: "kpt-megamenu__link", role: "menuitem", tabIndex: -1, disabled: link.disabled, onClick: () => pick(link), children: [link.icon ? _jsx(KptIcon, { name: link.icon }) : null, _jsx("span", { children: link.label })] }, linkIndex)))] }, columnIndex));
146
+ return (_jsxs("div", { className: "kpt-megamenu__column", role: "group", "aria-labelledby": column.label ? titleId : undefined, children: [column.label ? (_jsx("div", { className: "kpt-megamenu__col-title", role: "presentation", id: titleId, children: column.label })) : null, (column.items ?? []).map((link, linkIndex) => isLink(link) ? (_jsxs("a", { className: "kpt-megamenu__link", role: "menuitem", tabIndex: -1, href: link.url, onClick: (event) => { linkClick(event, link); pick(link); }, children: [link.icon ? _jsx(KptIcon, { name: link.icon }) : null, _jsx("span", { children: link.label })] }, linkIndex)) : (_jsxs("button", { type: "button", className: "kpt-megamenu__link", role: "menuitem", tabIndex: -1, disabled: link.disabled, onClick: () => pick(link), children: [link.icon ? _jsx(KptIcon, { name: link.icon }) : null, _jsx("span", { children: link.label })] }, linkIndex)))] }, columnIndex));
138
147
  }) }) })] }));
139
148
  }
@@ -14,19 +14,19 @@ Import: `import { KptMention, KptMentions } from '@konce-pt/react';`
14
14
  <span class="kpt-mentions__text"> about the estimate.</span>
15
15
  </span>
16
16
 
17
- ## KptMention — props
18
- - `item`: `KptMentionItem` — the whole entry at once; the single props below win over it
19
- - `id`, `label`, `kind`: string — `kind` lands in `data-kind`, so it can be styled per type
20
- - `prefix`: string (default '@'), `href`: string | null — with `href` the mention is a link
21
- - `placement`, `openDelay` — passed to `KptPeek`
22
- - `disabled`: boolean — no card; the mention stays a plain highlighted word
23
- - `children`: ReactNode — the card
24
-
25
- ## KptMentions — props
26
- - `text`: string — the content with `@id` or `@[Name with spaces](id)`
27
- - `items`: `readonly KptMentionItem[]` — entries the ids resolve against
28
- - `prefix`, `placement` — passed to every mention
29
- - `renderCard`: `(item, id, label) => ReactNode` — the card; without it mentions are plain words
17
+ ## KptMention - props
18
+ - `item`: `KptMentionItem` - the whole entry at once; the single props below win over it
19
+ - `id`, `label`, `kind`: string - `kind` lands in `data-kind`, so it can be styled per type
20
+ - `prefix`: string (default '@'), `href`: string | null - with `href` the mention is a link
21
+ - `placement`, `openDelay` - passed to `KptPeek`
22
+ - `disabled`: boolean - no card; the mention stays a plain highlighted word
23
+ - `children`: ReactNode - the card
24
+
25
+ ## KptMentions - props
26
+ - `text`: string - the content with `@id` or `@[Name with spaces](id)`
27
+ - `items`: `readonly KptMentionItem[]` - entries the ids resolve against
28
+ - `prefix`, `placement` - passed to every mention
29
+ - `renderCard`: `(item, id, label) => ReactNode` - the card; without it mentions are plain words
30
30
 
31
31
  ## Example
32
32
  <KptMentions
@@ -41,7 +41,7 @@ from `@konce-pt/mention` splits it into segments and the mention is an element t
41
41
  itself. An application does not have to push user-written content through a sanitizer to get
42
42
  mentions out of it.
43
43
 
44
- An id that is not on the list still renders — the label falls back to the id, because a note has to
44
+ An id that is not on the list still renders - the label falls back to the id, because a note has to
45
45
  stay readable after someone leaves the team. Without `renderCard` the mention is a highlighted
46
46
  word, not a button: there is nothing to open, so it does not pretend otherwise.
47
47
 
@@ -53,7 +53,7 @@ list, arrows and Enter (or Tab) insert the mention as
53
53
 
54
54
  ## Tokens
55
55
  The mention is underlined with a **dotted** line: `--kpt-color-primary-border` at rest, darkening
56
- to `--kpt-color-primary` on hover and while the card is open. Dotted, not solid — a solid underline
56
+ to `--kpt-color-primary` on hover and while the card is open. Dotted, not solid - a solid underline
57
57
  would read as a link, and a mention usually leads nowhere, it opens a card. Text
58
58
  `--kpt-color-primary`; a mention without a card `--kpt-color-text` + `--kpt-font-weight-medium` and
59
59
  no line at all, since there is nothing to promise. Focus ring `--kpt-color-focus-ring`. The card
@@ -4,11 +4,11 @@ import { type KptPeekPlacement } from '../peek/peek.tsx';
4
4
  export interface KptMentionProps extends Omit<ComponentPropsWithRef<'span'>, 'id' | 'prefix' | 'children'> {
5
5
  /** Cała pozycja naraz. Pojedyncze propsy poniżej mają nad nią priorytet. */
6
6
  item?: KptMentionItem | null;
7
- /** Identyfikator zapisany w treści — nie zmienia się przy zmianie nazwy. */
7
+ /** Identyfikator zapisany w treści - nie zmienia się przy zmianie nazwy. */
8
8
  id?: string;
9
9
  /** Nazwa do pokazania; bez niej bierze się ją z `item`, a w ostateczności z `id`. */
10
10
  label?: string;
11
- /** Rodzaj (osoba, zadanie, dokument) — ląduje w `data-kind`, więc da się go ostylować. */
11
+ /** Rodzaj (osoba, zadanie, dokument) - ląduje w `data-kind`, więc da się go ostylować. */
12
12
  kind?: string;
13
13
  /** Znak przed nazwą. Pusty łańcuch zostawia samą nazwę. */
14
14
  prefix?: string;
@@ -16,13 +16,13 @@ export interface KptMentionProps extends Omit<ComponentPropsWithRef<'span'>, 'id
16
16
  href?: string | null;
17
17
  placement?: KptPeekPlacement;
18
18
  openDelay?: number;
19
- /** Wyłączona wzmianka nie otwiera karty — zostaje samym napisem. */
19
+ /** Wyłączona wzmianka nie otwiera karty - zostaje samym napisem. */
20
20
  disabled?: boolean;
21
21
  /** Treść karty. Bez niej wzmianka też zostaje napisem: nie ma czego pokazać. */
22
22
  children?: ReactNode;
23
23
  }
24
24
  /**
25
- * Wzmianka w tekście — `@ktoś` albo `@coś` jako element, na który da się najechać i zobaczyć
25
+ * Wzmianka w tekście - `@ktoś` albo `@coś` jako element, na który da się najechać i zobaczyć
26
26
  * kartę podglądu z resztą powiązań. Treść karty daje aplikacja przez `children`: biblioteka nie
27
27
  * wie, czym jest wzmiankowana rzecz, a osoba, zadanie i dokument wyglądają inaczej.
28
28
  *
@@ -32,7 +32,7 @@ export interface KptMentionProps extends Omit<ComponentPropsWithRef<'span'>, 'id
32
32
  *
33
33
  * @example
34
34
  * <KptMention id="anna.k" label="Anna Kowalska">
35
- * <KptCard>Profil, projekty, kontakt…</KptCard>
35
+ * <KptCard>Profil, projekty, kontakt...</KptCard>
36
36
  * </KptMention>
37
37
  */
38
38
  export declare function KptMention({ item, id, label, kind, prefix, href, placement, openDelay, disabled, children, className, ...rest }: Readonly<KptMentionProps>): import("react").JSX.Element;
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../internal/cn.js";
3
3
  import { KptPeek } from "../peek/peek.js";
4
4
  /**
5
- * Wzmianka w tekście — `@ktoś` albo `@coś` jako element, na który da się najechać i zobaczyć
5
+ * Wzmianka w tekście - `@ktoś` albo `@coś` jako element, na który da się najechać i zobaczyć
6
6
  * kartę podglądu z resztą powiązań. Treść karty daje aplikacja przez `children`: biblioteka nie
7
7
  * wie, czym jest wzmiankowana rzecz, a osoba, zadanie i dokument wyglądają inaczej.
8
8
  *
@@ -12,7 +12,7 @@ import { KptPeek } from "../peek/peek.js";
12
12
  *
13
13
  * @example
14
14
  * <KptMention id="anna.k" label="Anna Kowalska">
15
- * <KptCard>Profil, projekty, kontakt…</KptCard>
15
+ * <KptCard>Profil, projekty, kontakt...</KptCard>
16
16
  * </KptMention>
17
17
  */
18
18
  export function KptMention({ item = null, id = '', label = '', kind = '', prefix = '@', href = null, placement = 'bottom', openDelay = 300, disabled = false, children, className, ...rest }) {
@@ -13,7 +13,7 @@ export interface KptMentionsProps<T = unknown> extends Omit<ComponentPropsWithRe
13
13
  renderCard?: (item: KptMentionItem<T> | null, id: string, label: string) => ReactNode;
14
14
  }
15
15
  /**
16
- * Akapit ze wzmiankami — tekst wchodzi jako zwykły napis, a `@wzmianki` wychodzą z niego jako
16
+ * Akapit ze wzmiankami - tekst wchodzi jako zwykły napis, a `@wzmianki` wychodzą z niego jako
17
17
  * elementy z kartą podglądu. Rozbiciem zajmuje się `parseMentionText()` z `@konce-pt/mention`
18
18
  * (czysty TS z testami), więc oba porty czytają tę samą treść tak samo.
19
19
  *
@@ -3,7 +3,7 @@ import { parseMentionText } from '@konce-pt/mention';
3
3
  import { cn } from "../internal/cn.js";
4
4
  import { KptMention } from "./mention.js";
5
5
  /**
6
- * Akapit ze wzmiankami — tekst wchodzi jako zwykły napis, a `@wzmianki` wychodzą z niego jako
6
+ * Akapit ze wzmiankami - tekst wchodzi jako zwykły napis, a `@wzmianki` wychodzą z niego jako
7
7
  * elementy z kartą podglądu. Rozbiciem zajmuje się `parseMentionText()` z `@konce-pt/mention`
8
8
  * (czysty TS z testami), więc oba porty czytają tę samą treść tak samo.
9
9
  *
@@ -4,29 +4,29 @@ A dropdown menu. Items come from `items`, the trigger from the `trigger` prop.
4
4
  Import: `import { KptMenu, type KptMenuItem } from '@konce-pt/react';`
5
5
 
6
6
  ## DOM
7
- <span class="kpt-menu-host"><span class="kpt-menu__trigger">…trigger…</span></span>
7
+ <span class="kpt-menu-host"><span class="kpt-menu__trigger">...trigger...</span></span>
8
8
  <!-- while open, in a portal on document.body: -->
9
9
  <div class="kpt-menu__panel" role="menu">
10
- <div class="kpt-menu__header" role="presentation">…</div>
10
+ <div class="kpt-menu__header" role="presentation">...</div>
11
11
  <div class="kpt-menu__separator" role="separator"></div>
12
- <button class="kpt-menu__item" role="menuitem">…</button>
12
+ <button class="kpt-menu__item" role="menuitem">...</button>
13
13
  </div>
14
14
 
15
15
  ## Props
16
16
  - `items`: `KptMenuItem<T>[]`
17
- - `trigger`: ReactNode — the element that opens the menu, rendered in place
18
- - `onSelect(item)` — the picked item; headers, separators and disabled items never arrive here
19
- - `open` / `defaultOpen` / `onOpenChange` — controlled or uncontrolled
17
+ - `trigger`: ReactNode - the element that opens the menu, rendered in place
18
+ - `onSelect(item)` - the picked item; headers, separators and disabled items never arrive here
19
+ - `open` / `defaultOpen` / `onOpenChange` - controlled or uncontrolled
20
20
  - `className`, `ref` and every other `<span>` prop go to the host
21
21
 
22
22
  ## KptMenuItem
23
23
  `label`, `value`, `icon`, `description` (a second line), `badge` + `badgeVariant`,
24
- `avatar` (`{ src?, name?, icon? }` — the header row of a user menu), `header` (a non-clickable
24
+ `avatar` (`{ src?, name?, icon? }` - the header row of a user menu), `header` (a non-clickable
25
25
  block instead of an item), `disabled`, `danger`, `separator`, plus `items` and `url` for the
26
26
  menubar and megamenu that build on the same shape.
27
27
 
28
28
  ## The panel is a portal
29
- It renders through the internal `KptOverlay`, so no overlay stylesheet is required — unlike the
29
+ It renders through the internal `KptOverlay`, so no overlay stylesheet is required - unlike the
30
30
  Angular port, which stands on CDK. Position, backdrop and Escape behave the same.
31
31
 
32
32
  ## Examples
@@ -46,11 +46,11 @@ Angular port, which stands on CDK. Position, backdrop and Escape behave the same
46
46
  (the `danger` item), `--kpt-z-overlay`.
47
47
 
48
48
  ## Keyboard
49
- - `↓` / `↑` on the trigger open the menu with focus on the first / last item; a click, `Enter`
49
+ - `ArrowDown` / `ArrowUp` on the trigger open the menu with focus on the first / last item; a click, `Enter`
50
50
  or `Space` opens it on the first.
51
- - Inside: `↓` / `↑` move between items and wrap around, `Home` / `End` jump to the ends;
51
+ - Inside: `ArrowDown` / `ArrowUp` move between items and wrap around, `Home` / `End` jump to the ends;
52
52
  disabled items, separators and headers are skipped.
53
- - `Escape` and `Tab` close the menu, and so does picking an item — focus returns to the trigger.
53
+ - `Escape` and `Tab` close the menu, and so does picking an item - focus returns to the trigger.
54
54
  - Items carry `tabindex="-1"` (roving focus), so an open menu is one Tab stop, not one per item.
55
55
 
56
56
  The logic lives in `menu-keys.ts`, shared with `KptSplitButton`; the other port has a twin file.
@@ -63,5 +63,5 @@ announcing them as actions.
63
63
  The trigger itself gets `aria-haspopup="menu"`, a live `aria-expanded` and, while open,
64
64
  `aria-controls` pointing at the panel. They are placed on the
65
65
  interactive control INSIDE the slot (the projected `<button>`/`<a>`), never on the
66
- `.kpt-menu__trigger` wrapper — giving that wrapper a role would create a nested control and a second
66
+ `.kpt-menu__trigger` wrapper - giving that wrapper a role would create a nested control and a second
67
67
  tab stop, and state attributes on a roleless element violate `aria-allowed-attr`.
@@ -1,11 +1,11 @@
1
1
  import type { KptBadgeVariant } from '../badge/badge.tsx';
2
- /** Awatar wiersza nagłówkowego — te same dane, które przyjmuje `KptAvatar`. */
2
+ /** Awatar wiersza nagłówkowego - te same dane, które przyjmuje `KptAvatar`. */
3
3
  export interface KptMenuItemAvatar {
4
4
  src?: string;
5
5
  name?: string;
6
6
  icon?: string;
7
7
  }
8
- /** Pozycja menu — wspólny kształt dla `KptMenu` i `KptContextMenu`. */
8
+ /** Pozycja menu - wspólny kształt dla `KptMenu` i `KptContextMenu`. */
9
9
  export interface KptMenuItem<T = unknown> {
10
10
  label?: string;
11
11
  value?: T;
@@ -14,9 +14,9 @@ export interface KptMenuItem<T = unknown> {
14
14
  description?: string;
15
15
  /** Odznaka po prawej stronie pozycji (licznik lub krótka etykieta). */
16
16
  badge?: string | number;
17
- /** Wariant odznaki — domyślnie `primary`. */
17
+ /** Wariant odznaki - domyślnie `primary`. */
18
18
  badgeVariant?: KptBadgeVariant;
19
- /** Awatar po lewej — typowo w wierszu nagłówka menu użytkownika. */
19
+ /** Awatar po lewej - typowo w wierszu nagłówka menu użytkownika. */
20
20
  avatar?: KptMenuItemAvatar;
21
21
  /**
22
22
  * Wiersz nagłówkowy: nieklikalny blok tekstu zamiast pozycji menu. Mieści dane zalogowanego
@@ -6,10 +6,10 @@
6
6
  export declare function nextMenuIndex(count: number, current: number, key: string): number | null;
7
7
  /** Aktywne pozycje panelu w kolejności DOM. */
8
8
  export declare function menuItems(panel: HTMLElement): HTMLElement[];
9
- /** Skupia pierwszą albo ostatnią aktywną pozycję — po otwarciu menu z klawiatury lub myszy. */
9
+ /** Skupia pierwszą albo ostatnią aktywną pozycję - po otwarciu menu z klawiatury lub myszy. */
10
10
  export declare function focusMenuEdge(panel: HTMLElement, edge: 'first' | 'last'): void;
11
11
  /**
12
12
  * Obsługa klawisza w otwartym panelu. Zwraca `'close'`, gdy menu ma się zamknąć z powrotem
13
- * fokusu na przycisk (Escape, Tab), `true`, gdy klawisz przesunął fokus, `false` — inny klawisz.
13
+ * fokusu na przycisk (Escape, Tab), `true`, gdy klawisz przesunął fokus, `false` - inny klawisz.
14
14
  */
15
15
  export declare function handleMenuKeydown(panel: HTMLElement, event: KeyboardEvent): 'close' | boolean;
@@ -1,7 +1,7 @@
1
1
  /*
2
- * Klawiatura panelu menu (wzorzec WAI-ARIA „menu button”), wspólna dla `kpt-menu`
3
- * i `kpt-split-button` — oba mają ten sam panel z pozycjami `role="menuitem"`.
4
- * Port Angulara ma bliźniaczy plik `lib/menu/menu-keys.ts` — zmiana zachowania w obu.
2
+ * Klawiatura panelu menu (wzorzec WAI-ARIA "menu button"), wspólna dla `kpt-menu`
3
+ * i `kpt-split-button` - oba mają ten sam panel z pozycjami `role="menuitem"`.
4
+ * Port Angulara ma bliźniaczy plik `lib/menu/menu-keys.ts` - zmiana zachowania w obu.
5
5
  */
6
6
  /** Klawisze przesuwające fokus po pozycjach. */
7
7
  const NAV_KEYS = new Set(['ArrowDown', 'ArrowUp', 'Home', 'End']);
@@ -28,14 +28,14 @@ export function nextMenuIndex(count, current, key) {
28
28
  export function menuItems(panel) {
29
29
  return [...panel.querySelectorAll('[role="menuitem"]:not(:disabled)')];
30
30
  }
31
- /** Skupia pierwszą albo ostatnią aktywną pozycję — po otwarciu menu z klawiatury lub myszy. */
31
+ /** Skupia pierwszą albo ostatnią aktywną pozycję - po otwarciu menu z klawiatury lub myszy. */
32
32
  export function focusMenuEdge(panel, edge) {
33
33
  const items = menuItems(panel);
34
34
  (edge === 'first' ? items[0] : items[items.length - 1])?.focus();
35
35
  }
36
36
  /**
37
37
  * Obsługa klawisza w otwartym panelu. Zwraca `'close'`, gdy menu ma się zamknąć z powrotem
38
- * fokusu na przycisk (Escape, Tab), `true`, gdy klawisz przesunął fokus, `false` — inny klawisz.
38
+ * fokusu na przycisk (Escape, Tab), `true`, gdy klawisz przesunął fokus, `false` - inny klawisz.
39
39
  */
40
40
  export function handleMenuKeydown(panel, event) {
41
41
  if (event.key === 'Escape' || event.key === 'Tab') {
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { KptAvatar } from "../avatar/avatar.js";
3
4
  import { KptBadge } from "../badge/badge.js";
@@ -2,7 +2,7 @@ import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
2
  import type { KptMenuItem } from './menu-item.ts';
3
3
  export interface KptMenuProps<T> extends Omit<ComponentPropsWithRef<'span'>, 'onSelect'> {
4
4
  items?: readonly KptMenuItem<T>[];
5
- /** Element otwierający menu — renderowany w miejscu komponentu. */
5
+ /** Element otwierający menu - renderowany w miejscu komponentu. */
6
6
  trigger: ReactNode;
7
7
  /** Wybrana pozycja; pozycje `header`, `separator` i wyłączone nigdy tu nie trafiają. */
8
8
  onSelect?: (item: KptMenuItem<T>) => void;
@@ -13,7 +13,7 @@ export interface KptMenuProps<T> extends Omit<ComponentPropsWithRef<'span'>, 'on
13
13
  /**
14
14
  * Menu rozwijane (dropdown). Pozycje przez `items`, wyzwalacz przez prop `trigger`.
15
15
  *
16
- * Panel renderuje się w portalu (`KptOverlay`), więc nie potrzeba żadnych stylów overlay —
16
+ * Panel renderuje się w portalu (`KptOverlay`), więc nie potrzeba żadnych stylów overlay -
17
17
  * w odróżnieniu od portu Angulara, który stoi na CDK.
18
18
  *
19
19
  * @example
package/dist/menu/menu.js CHANGED
@@ -1,5 +1,6 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useRef } from 'react';
3
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
4
  import { cn } from "../internal/cn.js";
4
5
  import { KptOverlay } from "../internal/overlay.js";
5
6
  import { useControllableState } from "../internal/use-controllable-state.js";
@@ -9,7 +10,7 @@ import { MenuRows } from "./menu-rows.js";
9
10
  /**
10
11
  * Menu rozwijane (dropdown). Pozycje przez `items`, wyzwalacz przez prop `trigger`.
11
12
  *
12
- * Panel renderuje się w portalu (`KptOverlay`), więc nie potrzeba żadnych stylów overlay —
13
+ * Panel renderuje się w portalu (`KptOverlay`), więc nie potrzeba żadnych stylów overlay -
13
14
  * w odróżnieniu od portu Angulara, który stoi na CDK.
14
15
  *
15
16
  * @example
@@ -17,8 +18,14 @@ import { MenuRows } from "./menu-rows.js";
17
18
  */
18
19
  export function KptMenu({ items = [], trigger, onSelect, open, defaultOpen = false, onOpenChange, className, ...rest }) {
19
20
  const triggerRef = useRef(null);
21
+ /** Kotwica panelu - w stanie, bo czyta ją render; ref zostaje dla handlerów. */
22
+ const [anchor, setAnchor] = useState(null);
23
+ const setTrigger = useCallback((element) => {
24
+ triggerRef.current = element;
25
+ setAnchor(element);
26
+ }, []);
20
27
  const panelRef = useRef(null);
21
- /** Którą pozycję skupić po otwarciu — strzałka w górę na wyzwalaczu otwiera „od końca”. */
28
+ /** Którą pozycję skupić po otwarciu - strzałka w górę na wyzwalaczu otwiera "od końca". */
22
29
  const focusEdge = useRef('first');
23
30
  const panelId = useKptId(undefined, 'kpt-menu');
24
31
  const [isOpen, setOpen] = useControllableState({
@@ -29,7 +36,7 @@ export function KptMenu({ items = [], trigger, onSelect, open, defaultOpen = fal
29
36
  const close = useCallback(() => setOpen(false), [setOpen]);
30
37
  // ARIA idzie na kontrolkę wewnątrz slotu, nie na `.kpt-menu__trigger`. Trigger to zwykły
31
38
  // `<span>` opakowujący dowolny węzeł z propa `trigger`: nadanie mu `role="button"` zrobiłoby
32
- // zagnieżdżoną kontrolkę i drugi tab stop. `cloneElement` też odpada — `trigger` bywa
39
+ // zagnieżdżoną kontrolkę i drugi tab stop. `cloneElement` też odpada - `trigger` bywa
33
40
  // komponentem, który nie przekazuje nieznanych propsów dalej na DOM.
34
41
  useEffect(() => {
35
42
  const control = findControl();
@@ -53,11 +60,11 @@ export function KptMenu({ items = [], trigger, onSelect, open, defaultOpen = fal
53
60
  });
54
61
  return () => cancelAnimationFrame(frame);
55
62
  }, [isOpen]);
56
- /** Prawdziwa kontrolka w slocie — tam idą ARIA i powrót fokusu. */
63
+ /** Prawdziwa kontrolka w slocie - tam idą ARIA i powrót fokusu. */
57
64
  function findControl() {
58
65
  return triggerRef.current?.querySelector('button, a, [role="button"]') ?? null;
59
66
  }
60
- /** Fokus wraca na kontrolkę — inaczej po zniknięciu panelu spadłby na `<body>`. */
67
+ /** Fokus wraca na kontrolkę - inaczej po zniknięciu panelu spadłby na `<body>`. */
61
68
  const closeAndRestoreFocus = () => {
62
69
  close();
63
70
  findControl()?.focus();
@@ -83,8 +90,8 @@ export function KptMenu({ items = [], trigger, onSelect, open, defaultOpen = fal
83
90
  onSelect?.(item);
84
91
  closeAndRestoreFocus();
85
92
  };
86
- return (_jsxs("span", { className: cn('kpt-menu-host', className), ...rest, children: [_jsx("span", { className: "kpt-menu__trigger", ref: triggerRef, onClick: () => {
93
+ return (_jsxs("span", { className: cn('kpt-menu-host', className), ...rest, children: [_jsx("span", { className: "kpt-menu__trigger", ref: setTrigger, onClick: () => {
87
94
  focusEdge.current = 'first';
88
95
  setOpen(!isOpen);
89
- }, onKeyDown: onTriggerKeyDown, children: trigger }), _jsx(KptOverlay, { open: isOpen, anchor: triggerRef.current, onClose: close, children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-menu__panel", role: "menu", onKeyDown: onPanelKeyDown, children: _jsx(MenuRows, { items: items, block: "kpt-menu", onPick: pick }) }) })] }));
96
+ }, onKeyDown: onTriggerKeyDown, children: trigger }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-menu__panel", role: "menu", tabIndex: -1, onKeyDown: onPanelKeyDown, children: _jsx(MenuRows, { items: items, block: "kpt-menu", onPick: pick }) }) })] }));
90
97
  }
@@ -8,21 +8,21 @@ Import: `import { KptMenubar } from '@konce-pt/react';`
8
8
  <div class="kpt-menubar" role="menubar" aria-orientation="horizontal" aria-label="Editor menu">
9
9
  <div class="kpt-menubar__group" role="none">
10
10
  <button class="kpt-menubar__top is-open" role="menuitem" tabindex="0"
11
- aria-haspopup="menu" aria-expanded="true" aria-controls="kpt-menubar-r1-menu-0">File …caret…</button>
11
+ aria-haspopup="menu" aria-expanded="true" aria-controls="kpt-menubar-r1-menu-0">File ...caret...</button>
12
12
  </div>
13
13
  </div>
14
14
  </div>
15
15
  <!-- while open, in a portal: -->
16
- <div class="kpt-menubar__dropdown" role="menu" id="kpt-menubar-r1-menu-0" aria-label="File">…items and separators…</div>
16
+ <div class="kpt-menubar__dropdown" role="menu" id="kpt-menubar-r1-menu-0" aria-label="File">...items and separators...</div>
17
17
 
18
18
  ## Props
19
- - `items`: `KptMenuItem<T>[]` — a top item's `items` become its dropdown
20
- - `onSelect(item)` — an action item, or a pick from a dropdown
21
- - `ariaLabel`: string — the bar's name for screen readers, e.g. "Editor menu"
19
+ - `items`: `KptMenuItem<T>[]` - a top item's `items` become its dropdown
20
+ - `onSelect(item)` - an action item, or a pick from a dropdown
21
+ - `ariaLabel`: string - the bar's name for screen readers, e.g. "Editor menu"
22
22
  - `className`, `ref` and every other `<div>` prop go to the host
23
23
 
24
24
  ## The dropdown is a portal
25
- It renders outside the bar, so a parent with `overflow: hidden` cannot clip it — the same benefit
25
+ It renders outside the bar, so a parent with `overflow: hidden` cannot clip it - the same benefit
26
26
  the Angular port gets from CDK Overlay, without CDK. Each dropdown is anchored to its own top
27
27
  button, so it opens directly under the label it belongs to.
28
28
 
@@ -40,7 +40,7 @@ bar can mix menus and plain actions with no extra flag.
40
40
 
41
41
  ## Links (`url`)
42
42
  An entry with `url` and no children (and not disabled) renders as a real `<a href>` with the same
43
- look, so the browser handles navigation — opening in a new tab, the status-bar preview. `onSelect`
43
+ look, so the browser handles navigation - opening in a new tab, the status-bar preview. `onSelect`
44
44
  still fires before the browser follows the link.
45
45
 
46
46
  ## Tokens
@@ -51,7 +51,7 @@ still fires before the browser follows the link.
51
51
  The bar is `role="menubar"` (`aria-orientation="horizontal"`, named by `ariaLabel`), top items and
52
52
  dropdown rows are `role="menuitem"`, separators carry `role="separator"`. Top items with a dropdown
53
53
  carry `aria-haspopup="menu"`, `aria-expanded` and, while open, `aria-controls`. The bar is a plain
54
- `<div>`, not `<nav>` — wrap it in your own `<nav aria-label="…">` when it is the site navigation.
54
+ `<div>`, not `<nav>` - wrap it in your own `<nav aria-label="...">` when it is the site navigation.
55
55
 
56
56
  ## Keyboard
57
57
  The bar is a single `Tab` stop (roving `tabindex`), following the WAI-ARIA menubar pattern.
@@ -60,3 +60,14 @@ The bar is a single `Tab` stop (roving `tabindex`), following the WAI-ARIA menub
60
60
  its first row, `ArrowUp` on its last one.
61
61
  - In a dropdown: `ArrowDown`/`ArrowUp`/`Home`/`End` move between rows, `ArrowLeft`/`ArrowRight`
62
62
  open the neighbouring dropdown, `Escape` and `Tab` close it and return focus to the top item.
63
+
64
+ ## Router
65
+ Links are plain `<a href>`, so without a router a click reloads the page. `onNavigate` fires on a plain
66
+ click (left button, no Ctrl/Cmd/Shift, no `target="_blank"`) with `{ item, url, event }`: call
67
+ `event.preventDefault()` and navigate with your router. Modified clicks stay native (a new tab, a new
68
+ window). The library depends on no router.
69
+
70
+ <KptMenubar items={items} onNavigate={({ event, url }) => { event.preventDefault(); navigate(url); }} />
71
+
72
+ ## When to use it
73
+ The `menubar`/`menu` roles switch a screen reader into application mode: page navigation by headings and links stops, and arrow keys are expected. That fits an application menu (File, Edit, View) or a large product menu. For plain site navigation (a few links in a header) the WAI-ARIA APG recommends the disclosure pattern instead - a `<nav>` with buttons carrying `aria-expanded` and ordinary link lists - which you can build from `kpt-button` and lists. The menu does not render a third level: nested `items` of a submenu item are ignored.
@@ -1,23 +1,29 @@
1
1
  import { type ComponentPropsWithRef } from 'react';
2
+ import { type KptNavigateEvent } from '../shared/types.ts';
2
3
  import type { KptMenuItem } from '../menu/menu-item.ts';
3
4
  export interface KptMenubarProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onSelect'> {
4
5
  items?: readonly KptMenuItem<T>[];
5
6
  onSelect?: (item: KptMenuItem<T>) => void;
6
- /** Nazwa belki dla czytników ekranu, np. „Menu edytora”. */
7
+ /**
8
+ * Zwykły klik w pozycję z `url`. Aplikacja z routerem woła `event.preventDefault()` i nawiguje
9
+ * sama - bez tego `<a href>` przeładowuje stronę.
10
+ */
11
+ onNavigate?: (event: KptNavigateEvent<KptMenuItem<T>>) => void;
12
+ /** Nazwa belki dla czytników ekranu, np. "Menu edytora". */
7
13
  ariaLabel?: string;
8
14
  }
9
15
  /**
10
16
  * Pozioma belka menu z rozwijanymi pod-menu. Pozycja bez `items` działa jak akcja lub link.
11
17
  *
12
- * Pod-menu renderuje się w portalu, więc rodzic z `overflow: hidden` go nie przycina — to ta sama
18
+ * Pod-menu renderuje się w portalu, więc rodzic z `overflow: hidden` go nie przycina - to ta sama
13
19
  * korzyść, dla której port Angulara sięga po CDK Overlay, tylko bez CDK.
14
20
  *
15
- * Klawiatura według wzorca WAI-ARIA „menubar”: belka to jeden przystanek Tab, strzałki w lewo/prawo
21
+ * Klawiatura według wzorca WAI-ARIA "menubar": belka to jeden przystanek Tab, strzałki w lewo/prawo
16
22
  * i `Home`/`End` chodzą po pozycjach górnych, strzałka w dół (albo `Enter`/spacja) otwiera
17
- * pod-menu z fokusem na pierwszej pozycji, w górę — na ostatniej. W otwartym pod-menu strzałki
23
+ * pod-menu z fokusem na pierwszej pozycji, w górę - na ostatniej. W otwartym pod-menu strzałki
18
24
  * w lewo/prawo przechodzą do sąsiedniego, a `Escape` zamyka je i oddaje fokus belce.
19
25
  *
20
26
  * @example
21
27
  * <KptMenubar items={items} onSelect={onSelect} />
22
28
  */
23
- export declare function KptMenubar<T>({ items, onSelect, ariaLabel, className, ...rest }: Readonly<KptMenubarProps<T>>): import("react").JSX.Element;
29
+ export declare function KptMenubar<T>({ items, onSelect, onNavigate, ariaLabel, className, ...rest }: Readonly<KptMenubarProps<T>>): import("react").JSX.Element;