@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.
- package/README.md +128 -64
- package/dist/accordion/accordion.d.ts +14 -6
- package/dist/accordion/accordion.js +25 -17
- package/dist/accordion/llms.txt +22 -10
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert/alert.js +3 -2
- package/dist/alert/llms.txt +10 -9
- package/dist/app-shell/app-shell.d.ts +14 -14
- package/dist/app-shell/app-shell.js +22 -15
- package/dist/app-shell/llms.txt +16 -15
- package/dist/auth/auth-types.d.ts +6 -6
- package/dist/auth/auth.d.ts +2 -2
- package/dist/auth/auth.js +24 -15
- package/dist/auth/llms.txt +12 -11
- package/dist/autocomplete/autocomplete.d.ts +19 -6
- package/dist/autocomplete/autocomplete.js +32 -11
- package/dist/autocomplete/llms.txt +19 -5
- package/dist/avatar/avatar.d.ts +6 -6
- package/dist/avatar/avatar.js +6 -5
- package/dist/avatar/llms.txt +10 -10
- package/dist/avatar-group/avatar-group.d.ts +4 -4
- package/dist/avatar-group/avatar-group.js +4 -3
- package/dist/avatar-group/llms.txt +8 -8
- package/dist/backdrop/backdrop.d.ts +7 -26
- package/dist/backdrop/backdrop.js +32 -27
- package/dist/backdrop/llms.txt +27 -27
- package/dist/badge/badge.d.ts +3 -3
- package/dist/badge/badge.js +1 -1
- package/dist/badge/llms.txt +11 -11
- package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
- package/dist/bottom-sheet/bottom-sheet.js +5 -4
- package/dist/bottom-sheet/llms.txt +11 -8
- package/dist/breadcrumb/breadcrumb.d.ts +8 -2
- package/dist/breadcrumb/breadcrumb.js +11 -3
- package/dist/breadcrumb/llms.txt +10 -2
- package/dist/button/button.d.ts +3 -3
- package/dist/button/button.js +10 -9
- package/dist/button/llms.txt +27 -19
- package/dist/button-group/button-group.d.ts +18 -5
- package/dist/button-group/button-group.js +54 -6
- package/dist/button-group/llms.txt +27 -18
- package/dist/card/card.d.ts +8 -8
- package/dist/card/card.js +10 -9
- package/dist/card/llms.txt +20 -20
- package/dist/carousel/carousel.d.ts +6 -6
- package/dist/carousel/carousel.js +8 -5
- package/dist/carousel/llms.txt +10 -10
- package/dist/charts/chart-legend.d.ts +3 -3
- package/dist/charts/chart-legend.js +2 -1
- package/dist/charts/chart-tooltip.d.ts +3 -3
- package/dist/charts/chart-tooltip.js +1 -1
- package/dist/charts/chart.d.ts +4 -3
- package/dist/charts/chart.js +18 -10
- package/dist/charts/llms.txt +10 -7
- package/dist/charts-entry/public-api.js +2 -2
- package/dist/chat/chat.d.ts +17 -10
- package/dist/chat/chat.js +77 -23
- package/dist/chat/llms.txt +39 -15
- package/dist/chat-composer/chat-composer.d.ts +20 -7
- package/dist/chat-composer/chat-composer.js +29 -7
- package/dist/chat-composer/llms.txt +20 -11
- package/dist/chat-dock/chat-dock.d.ts +11 -4
- package/dist/chat-dock/chat-dock.js +10 -6
- package/dist/chat-dock/llms.txt +15 -14
- package/dist/chat-entry/public-api.js +1 -1
- package/dist/chat-message/chat-message.d.ts +12 -5
- package/dist/chat-message/chat-message.js +19 -8
- package/dist/chat-message/llms.txt +16 -15
- package/dist/chat-typing/chat-typing.d.ts +2 -2
- package/dist/chat-typing/chat-typing.js +4 -3
- package/dist/chat-typing/llms.txt +6 -6
- package/dist/checkbox/checkbox.d.ts +13 -6
- package/dist/checkbox/checkbox.js +31 -5
- package/dist/checkbox/llms.txt +26 -11
- package/dist/chip/chip.d.ts +4 -4
- package/dist/chip/chip.js +3 -2
- package/dist/chip/llms.txt +11 -11
- package/dist/chips-input/chips-input.d.ts +6 -4
- package/dist/chips-input/chips-input.js +47 -12
- package/dist/chips-input/llms.txt +18 -8
- package/dist/clock/clock.d.ts +11 -6
- package/dist/clock/clock.js +38 -8
- package/dist/clock/llms.txt +12 -8
- package/dist/color-picker/color-picker.d.ts +9 -5
- package/dist/color-picker/color-picker.js +37 -18
- package/dist/color-picker/llms.txt +8 -5
- package/dist/confirm/confirm-container.d.ts +3 -3
- package/dist/confirm/confirm-container.js +6 -5
- package/dist/confirm/confirm-store.d.ts +4 -4
- package/dist/confirm/confirm-store.js +11 -5
- package/dist/confirm/llms.txt +8 -7
- package/dist/context-menu/context-menu.d.ts +1 -1
- package/dist/context-menu/context-menu.js +37 -14
- package/dist/context-menu/llms.txt +10 -7
- package/dist/data-table/data-table-types.d.ts +5 -5
- package/dist/data-table/data-table.d.ts +37 -5
- package/dist/data-table/data-table.js +426 -119
- package/dist/data-table/export-csv.d.ts +3 -3
- package/dist/data-table/export-csv.js +8 -10
- package/dist/data-table/llms.txt +127 -79
- package/dist/data-view/data-view.d.ts +13 -5
- package/dist/data-view/data-view.js +68 -6
- package/dist/data-view/llms.txt +29 -10
- package/dist/date-range/date-range.d.ts +20 -8
- package/dist/date-range/date-range.js +86 -63
- package/dist/date-range/llms.txt +32 -18
- package/dist/datepicker/datepicker.d.ts +22 -8
- package/dist/datepicker/datepicker.js +103 -71
- package/dist/datepicker/llms.txt +36 -22
- package/dist/dialog/dialog.d.ts +4 -4
- package/dist/dialog/dialog.js +32 -11
- package/dist/dialog/llms.txt +13 -10
- package/dist/divider/divider.d.ts +7 -1
- package/dist/divider/divider.js +3 -2
- package/dist/divider/llms.txt +4 -3
- package/dist/drawer/drawer.d.ts +9 -4
- package/dist/drawer/drawer.js +5 -4
- package/dist/drawer/llms.txt +13 -10
- package/dist/empty/empty.d.ts +2 -2
- package/dist/empty/empty.js +1 -1
- package/dist/empty/llms.txt +9 -9
- package/dist/fab/fab.d.ts +1 -1
- package/dist/fab/fab.js +1 -1
- package/dist/fab/llms.txt +10 -6
- package/dist/fieldset/fieldset.d.ts +18 -4
- package/dist/fieldset/fieldset.js +12 -6
- package/dist/fieldset/llms.txt +26 -9
- package/dist/file-upload/file-upload.d.ts +8 -2
- package/dist/file-upload/file-upload.js +22 -11
- package/dist/file-upload/llms.txt +12 -9
- package/dist/form-field/form-field-context.d.ts +4 -4
- package/dist/form-field/form-field.d.ts +12 -4
- package/dist/form-field/form-field.js +27 -6
- package/dist/form-field/llms.txt +25 -11
- package/dist/galleria/galleria.d.ts +3 -3
- package/dist/galleria/galleria.js +9 -6
- package/dist/galleria/llms.txt +7 -7
- package/dist/grid/col.d.ts +4 -4
- package/dist/grid/col.js +2 -2
- package/dist/grid/flex.d.ts +3 -3
- package/dist/grid/flex.js +1 -1
- package/dist/grid/grid.d.ts +7 -7
- package/dist/grid/grid.js +3 -3
- package/dist/grid/layout.d.ts +2 -2
- package/dist/grid/layout.js +2 -2
- package/dist/grid/llms.txt +15 -15
- package/dist/grid-entry/public-api.js +1 -1
- package/dist/i18n/i18n-context.d.ts +6 -6
- package/dist/i18n/i18n-context.js +27 -5
- package/dist/icon/icon-registry.d.ts +3 -3
- package/dist/icon/icon-registry.js +3 -3
- package/dist/icon/icon.d.ts +4 -4
- package/dist/icon/icon.js +10 -7
- package/dist/icon/llms.txt +13 -13
- package/dist/icon-button/icon-button.d.ts +2 -2
- package/dist/icon-button/icon-button.js +1 -1
- package/dist/icon-button/llms.txt +9 -5
- package/dist/icons-entry/public-api.d.ts +2 -2
- package/dist/icons-entry/public-api.js +3 -3
- package/dist/image/image.js +5 -5
- package/dist/image/llms.txt +13 -13
- package/dist/input/input.d.ts +18 -5
- package/dist/input/input.js +22 -6
- package/dist/input/llms.txt +25 -11
- package/dist/input-mask/input-mask.d.ts +7 -2
- package/dist/input-mask/input-mask.js +17 -43
- package/dist/input-mask/llms.txt +8 -5
- package/dist/input-number/input-number.d.ts +11 -9
- package/dist/input-number/input-number.js +25 -21
- package/dist/input-number/llms.txt +17 -14
- package/dist/input-otp/input-otp.d.ts +18 -5
- package/dist/input-otp/input-otp.js +48 -24
- package/dist/input-otp/llms.txt +18 -7
- package/dist/internal/calendar-focus.d.ts +1 -1
- package/dist/internal/calendar-focus.js +3 -3
- package/dist/internal/cn.d.ts +1 -1
- package/dist/internal/mask.d.ts +14 -0
- package/dist/internal/mask.js +62 -0
- package/dist/internal/number-group.d.ts +22 -0
- package/dist/internal/number-group.js +53 -0
- package/dist/internal/option-key.d.ts +6 -0
- package/dist/internal/option-key.js +8 -0
- package/dist/internal/option-nav.d.ts +4 -4
- package/dist/internal/option-nav.js +5 -5
- package/dist/internal/overlay-container.js +1 -1
- package/dist/internal/overlay.d.ts +3 -3
- package/dist/internal/overlay.js +40 -10
- package/dist/internal/password-strength.d.ts +6 -0
- package/dist/internal/password-strength.js +74 -0
- package/dist/internal/roving.d.ts +2 -2
- package/dist/internal/roving.js +3 -3
- package/dist/internal/scroll-lock.d.ts +6 -0
- package/dist/internal/scroll-lock.js +35 -0
- package/dist/internal/slot-children.d.ts +13 -0
- package/dist/internal/slot-children.js +31 -0
- package/dist/internal/slot.d.ts +3 -3
- package/dist/internal/slot.js +2 -2
- package/dist/internal/step.d.ts +12 -0
- package/dist/internal/step.js +31 -0
- package/dist/internal/tween.d.ts +5 -5
- package/dist/internal/tween.js +7 -8
- package/dist/internal/types.d.ts +2 -2
- package/dist/internal/use-breakpoint.d.ts +2 -2
- package/dist/internal/use-breakpoint.js +4 -4
- package/dist/internal/use-controllable-state.d.ts +5 -0
- package/dist/internal/use-controllable-state.js +25 -4
- package/dist/internal/use-id.d.ts +2 -2
- package/dist/internal/use-id.js +2 -2
- package/dist/internal/use-modal-focus.d.ts +2 -1
- package/dist/internal/use-modal-focus.js +14 -3
- package/dist/knob/knob.d.ts +7 -4
- package/dist/knob/knob.js +27 -22
- package/dist/knob/llms.txt +18 -11
- package/dist/listbox/listbox.d.ts +8 -6
- package/dist/listbox/listbox.js +37 -17
- package/dist/listbox/llms.txt +12 -9
- package/dist/loader/llms.txt +56 -0
- package/dist/loader/loader.d.ts +49 -0
- package/dist/loader/loader.js +68 -0
- package/dist/map/llms.txt +30 -23
- package/dist/map/map-create-dialog.d.ts +4 -4
- package/dist/map/map-create-dialog.js +36 -28
- package/dist/map/map-hours-field.d.ts +4 -4
- package/dist/map/map-hours-field.js +8 -7
- package/dist/map/map-image-field.d.ts +2 -2
- package/dist/map/map-image-field.js +6 -5
- package/dist/map/map-legend.d.ts +4 -4
- package/dist/map/map-legend.js +3 -2
- package/dist/map/map-poi-card.d.ts +3 -3
- package/dist/map/map-poi-card.js +10 -9
- package/dist/map/map-search.d.ts +17 -6
- package/dist/map/map-search.js +70 -43
- package/dist/map/map.d.ts +25 -13
- package/dist/map/map.js +86 -57
- package/dist/map/ports.d.ts +9 -9
- package/dist/map/ports.js +6 -6
- package/dist/map-entry/public-api.js +2 -2
- package/dist/megamenu/llms.txt +18 -7
- package/dist/megamenu/megamenu.d.ts +12 -6
- package/dist/megamenu/megamenu.js +23 -14
- package/dist/mention/llms.txt +15 -15
- package/dist/mention/mention.d.ts +5 -5
- package/dist/mention/mention.js +2 -2
- package/dist/mention/mentions.d.ts +1 -1
- package/dist/mention/mentions.js +1 -1
- package/dist/menu/llms.txt +12 -12
- package/dist/menu/menu-item.d.ts +4 -4
- package/dist/menu/menu-keys.d.ts +2 -2
- package/dist/menu/menu-keys.js +5 -5
- package/dist/menu/menu-rows.js +1 -0
- package/dist/menu/menu.d.ts +2 -2
- package/dist/menu/menu.js +15 -8
- package/dist/menubar/llms.txt +19 -8
- package/dist/menubar/menubar.d.ts +11 -5
- package/dist/menubar/menubar.js +23 -11
- package/dist/meter-group/llms.txt +12 -12
- package/dist/meter-group/meter-group.d.ts +2 -2
- package/dist/meter-group/meter-group.js +2 -1
- package/dist/motion/motion-context.d.ts +22 -0
- package/dist/motion/motion-context.js +28 -0
- package/dist/order-list/llms.txt +24 -9
- package/dist/order-list/order-list.d.ts +12 -4
- package/dist/order-list/order-list.js +123 -25
- package/dist/paginator/llms.txt +8 -8
- package/dist/paginator/paginator.js +7 -4
- package/dist/panel/llms.txt +25 -13
- package/dist/panel/panel.d.ts +11 -3
- package/dist/panel/panel.js +12 -7
- package/dist/password/llms.txt +19 -7
- package/dist/password/password.d.ts +2 -2
- package/dist/password/password.js +27 -16
- package/dist/peek/llms.txt +11 -11
- package/dist/peek/peek.d.ts +6 -6
- package/dist/peek/peek.js +41 -19
- package/dist/pick-list/llms.txt +35 -12
- package/dist/pick-list/pick-list.d.ts +12 -4
- package/dist/pick-list/pick-list.js +128 -24
- package/dist/popover/llms.txt +13 -10
- package/dist/popover/popover.d.ts +6 -4
- package/dist/popover/popover.js +14 -7
- package/dist/progress/llms.txt +17 -17
- package/dist/progress/progress.d.ts +7 -7
- package/dist/progress/progress.js +7 -6
- package/dist/public-api.d.ts +16 -4
- package/dist/public-api.js +13 -7
- package/dist/radio-group/llms.txt +16 -6
- package/dist/radio-group/radio-group.d.ts +12 -3
- package/dist/radio-group/radio-group.js +23 -4
- package/dist/rating/llms.txt +20 -13
- package/dist/rating/rating-pointer.d.ts +16 -0
- package/dist/rating/rating-pointer.js +26 -0
- package/dist/rating/rating.d.ts +6 -6
- package/dist/rating/rating.js +77 -12
- package/dist/rich-text/lists.d.ts +2 -2
- package/dist/rich-text/lists.js +7 -7
- package/dist/rich-text/llms.txt +35 -12
- package/dist/rich-text/rich-text.d.ts +13 -14
- package/dist/rich-text/rich-text.js +311 -142
- package/dist/rich-text/sanitize.d.ts +11 -2
- package/dist/rich-text/sanitize.js +80 -32
- package/dist/rich-text/tables.d.ts +3 -3
- package/dist/rich-text/tables.js +3 -3
- package/dist/roadmap/llms.txt +23 -17
- package/dist/roadmap/roadmap.d.ts +6 -6
- package/dist/roadmap/roadmap.js +102 -25
- package/dist/roadmap-entry/public-api.js +2 -2
- package/dist/scroll-top/llms.txt +6 -6
- package/dist/scroll-top/scroll-top.d.ts +1 -1
- package/dist/scroll-top/scroll-top.js +2 -1
- package/dist/select/llms.txt +22 -12
- package/dist/select/select.d.ts +10 -8
- package/dist/select/select.js +87 -47
- package/dist/shared/types.d.ts +22 -1
- package/dist/shared/types.js +9 -1
- package/dist/sidenav/llms.txt +9 -9
- package/dist/sidenav/sidenav.d.ts +2 -3
- package/dist/sidenav/sidenav.js +5 -4
- package/dist/skeleton/llms.txt +3 -3
- package/dist/skeleton/skeleton.d.ts +1 -1
- package/dist/skeleton/skeleton.js +1 -1
- package/dist/slider/llms.txt +34 -12
- package/dist/slider/slider-drag.d.ts +26 -0
- package/dist/slider/slider-drag.js +79 -0
- package/dist/slider/slider.d.ts +8 -5
- package/dist/slider/slider.js +38 -8
- package/dist/speech/llms.txt +97 -0
- package/dist/speech/speech-button.d.ts +44 -0
- package/dist/speech/speech-button.js +86 -0
- package/dist/speech/speech-wave.d.ts +19 -0
- package/dist/speech/speech-wave.js +16 -0
- package/dist/speech/use-speech-recognition.d.ts +81 -0
- package/dist/speech/use-speech-recognition.js +179 -0
- package/dist/speed-dial/llms.txt +14 -8
- package/dist/speed-dial/speed-dial.d.ts +1 -1
- package/dist/speed-dial/speed-dial.js +3 -2
- package/dist/spinner/llms.txt +7 -7
- package/dist/spinner/spinner.d.ts +1 -1
- package/dist/spinner/spinner.js +2 -1
- package/dist/split-button/llms.txt +21 -15
- package/dist/split-button/split-button.d.ts +2 -2
- package/dist/split-button/split-button.js +13 -6
- package/dist/splitter/llms.txt +11 -11
- package/dist/splitter/splitter.d.ts +3 -3
- package/dist/splitter/splitter.js +25 -10
- package/dist/stepper/llms.txt +35 -13
- package/dist/stepper/stepper.d.ts +6 -6
- package/dist/stepper/stepper.js +60 -13
- package/dist/switch/llms.txt +15 -5
- package/dist/switch/switch.d.ts +10 -3
- package/dist/switch/switch.js +18 -4
- package/dist/switch-group/llms.txt +11 -8
- package/dist/switch-group/switch-group.d.ts +6 -4
- package/dist/switch-group/switch-group.js +9 -7
- package/dist/tabs/llms.txt +12 -9
- package/dist/tabs/tabs.d.ts +5 -5
- package/dist/tabs/tabs.js +36 -20
- package/dist/textarea/llms.txt +23 -12
- package/dist/textarea/textarea.d.ts +19 -6
- package/dist/textarea/textarea.js +22 -7
- package/dist/timeline/llms.txt +4 -4
- package/dist/timeline/timeline.d.ts +1 -1
- package/dist/timeline/timeline.js +1 -1
- package/dist/toast/llms.txt +50 -17
- package/dist/toast/toast-container.d.ts +9 -3
- package/dist/toast/toast-container.js +18 -9
- package/dist/toast/toast-store.d.ts +42 -2
- package/dist/toast/toast-store.js +36 -1
- package/dist/toolbar/llms.txt +7 -7
- package/dist/toolbar/toolbar.d.ts +3 -3
- package/dist/toolbar/toolbar.js +2 -2
- package/dist/tooltip/llms.txt +14 -12
- package/dist/tooltip/tooltip.d.ts +5 -4
- package/dist/tooltip/tooltip.js +100 -41
- package/dist/tree/llms.txt +25 -11
- package/dist/tree/tree-keys.d.ts +5 -5
- package/dist/tree/tree-keys.js +7 -7
- package/dist/tree/tree.d.ts +17 -5
- package/dist/tree/tree.js +62 -20
- package/dist/update/llms.txt +54 -0
- package/dist/update/update.d.ts +49 -0
- package/dist/update/update.js +82 -0
- 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
|
|
11
|
-
* Struktura: pozycja górna
|
|
12
|
-
* Pozycja górna bez kolumn działa jak akcja
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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>`
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
}
|
package/dist/mention/llms.txt
CHANGED
|
@@ -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
|
|
18
|
-
- `item`: `KptMentionItem`
|
|
19
|
-
- `id`, `label`, `kind`: string
|
|
20
|
-
- `prefix`: string (default '@'), `href`: string | null
|
|
21
|
-
- `placement`, `openDelay`
|
|
22
|
-
- `disabled`: boolean
|
|
23
|
-
- `children`: ReactNode
|
|
24
|
-
|
|
25
|
-
## KptMentions
|
|
26
|
-
- `text`: string
|
|
27
|
-
- `items`: `readonly KptMentionItem[]`
|
|
28
|
-
- `prefix`, `placement`
|
|
29
|
-
- `renderCard`: `(item, id, label) => ReactNode`
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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;
|
package/dist/mention/mention.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
*
|
package/dist/mention/mentions.js
CHANGED
|
@@ -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
|
|
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
|
*
|
package/dist/menu/llms.txt
CHANGED
|
@@ -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"
|
|
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"
|
|
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"
|
|
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
|
|
18
|
-
- `onSelect(item)`
|
|
19
|
-
- `open` / `defaultOpen` / `onOpenChange`
|
|
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? }`
|
|
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
|
|
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
|
-
-
|
|
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:
|
|
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
|
|
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
|
|
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`.
|
package/dist/menu/menu-item.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { KptBadgeVariant } from '../badge/badge.tsx';
|
|
2
|
-
/** Awatar wiersza nagłówkowego
|
|
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
|
|
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
|
|
17
|
+
/** Wariant odznaki - domyślnie `primary`. */
|
|
18
18
|
badgeVariant?: KptBadgeVariant;
|
|
19
|
-
/** Awatar po lewej
|
|
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
|
package/dist/menu/menu-keys.d.ts
CHANGED
|
@@ -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ę
|
|
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`
|
|
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;
|
package/dist/menu/menu-keys.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Klawiatura panelu menu (wzorzec WAI-ARIA
|
|
3
|
-
* i `kpt-split-button`
|
|
4
|
-
* Port Angulara ma bliźniaczy plik `lib/menu/menu-keys.ts`
|
|
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ę
|
|
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`
|
|
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') {
|
package/dist/menu/menu-rows.js
CHANGED
package/dist/menu/menu.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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ę
|
|
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:
|
|
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:
|
|
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
|
}
|
package/dist/menubar/llms.txt
CHANGED
|
@@ -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
|
|
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"
|
|
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>[]`
|
|
20
|
-
- `onSelect(item)`
|
|
21
|
-
- `ariaLabel`: string
|
|
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
|
|
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
|
|
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>`
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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ę
|
|
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;
|