@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
package/dist/menubar/menubar.js
CHANGED
|
@@ -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,33 +6,36 @@ 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
12
|
* Pozioma belka menu z rozwijanymi pod-menu. Pozycja bez `items` działa jak akcja lub link.
|
|
11
13
|
*
|
|
12
|
-
* Pod-menu renderuje się w portalu, więc rodzic z `overflow: hidden` go nie przycina
|
|
14
|
+
* Pod-menu renderuje się w portalu, więc rodzic z `overflow: hidden` go nie przycina - to ta sama
|
|
13
15
|
* korzyść, dla której port Angulara sięga po CDK Overlay, tylko bez CDK.
|
|
14
16
|
*
|
|
15
|
-
* Klawiatura według wzorca WAI-ARIA
|
|
17
|
+
* Klawiatura według wzorca WAI-ARIA "menubar": belka to jeden przystanek Tab, strzałki w lewo/prawo
|
|
16
18
|
* 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ę
|
|
19
|
+
* pod-menu z fokusem na pierwszej pozycji, w górę - na ostatniej. W otwartym pod-menu strzałki
|
|
18
20
|
* w lewo/prawo przechodzą do sąsiedniego, a `Escape` zamyka je i oddaje fokus belce.
|
|
19
21
|
*
|
|
20
22
|
* @example
|
|
21
23
|
* <KptMenubar items={items} onSelect={onSelect} />
|
|
22
24
|
*/
|
|
23
|
-
export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest }) {
|
|
25
|
+
export function KptMenubar({ items = [], onSelect, onNavigate, ariaLabel, className, ...rest }) {
|
|
24
26
|
const [openIndex, setOpenIndex] = useState(null);
|
|
25
|
-
|
|
27
|
+
/** Przycisk otwartego pod-menu - w stanie, bo render podaje go nakładce jako kotwicę. */
|
|
28
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
29
|
+
// Ostatnio skupiona pozycja górna - ona jest przystankiem Tab belki.
|
|
26
30
|
const [focusIndex, setFocusIndex] = useState(0);
|
|
27
31
|
const buttonsRef = useRef([]);
|
|
28
32
|
const panelRef = useRef(null);
|
|
29
|
-
// Którą pozycję pod-menu skupić po otwarciu
|
|
33
|
+
// Którą pozycję pod-menu skupić po otwarciu - strzałka w górę otwiera "od końca".
|
|
30
34
|
const focusEdge = useRef('first');
|
|
31
35
|
const baseId = useKptId(undefined, 'kpt-menubar');
|
|
32
36
|
const panelId = (index) => `${baseId}-menu-${index}`;
|
|
33
37
|
const disabled = items.map((item) => !!item.disabled);
|
|
34
|
-
// Pozycja z `url` (bez pod-menu, niewyłączona) to `<a href>`
|
|
38
|
+
// Pozycja z `url` (bez pod-menu, niewyłączona) to `<a href>` - nawigację robi przeglądarka,
|
|
35
39
|
// więc działa nowa karta i podgląd adresu. `onSelect` i tak jest wołane.
|
|
36
40
|
const isLink = (item) => !!item.url && !item.items?.length && !item.disabled;
|
|
37
41
|
const tabStop = rovingStop(disabled, focusIndex);
|
|
@@ -59,6 +63,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
|
|
|
59
63
|
focusMenuEdge(panelRef.current, edge);
|
|
60
64
|
return;
|
|
61
65
|
}
|
|
66
|
+
setAnchorEl(buttonsRef.current[index] ?? null);
|
|
62
67
|
setOpenIndex(hasMenu ? index : null);
|
|
63
68
|
focusTop(index);
|
|
64
69
|
};
|
|
@@ -67,6 +72,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
|
|
|
67
72
|
return;
|
|
68
73
|
if (item.items?.length) {
|
|
69
74
|
focusEdge.current = 'first';
|
|
75
|
+
setAnchorEl(buttonsRef.current[index] ?? null);
|
|
70
76
|
setOpenIndex((current) => (current === index ? null : index));
|
|
71
77
|
}
|
|
72
78
|
else {
|
|
@@ -79,7 +85,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
|
|
|
79
85
|
return;
|
|
80
86
|
onSelect?.(item);
|
|
81
87
|
closeAll();
|
|
82
|
-
// Fokus wraca na pozycję górną
|
|
88
|
+
// Fokus wraca na pozycję górną - inaczej po zniknięciu pod-menu spadłby na `<body>`.
|
|
83
89
|
focusTop(index);
|
|
84
90
|
};
|
|
85
91
|
const onTopKeyDown = (event, index) => {
|
|
@@ -94,7 +100,7 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
|
|
|
94
100
|
if (next === null)
|
|
95
101
|
return;
|
|
96
102
|
event.preventDefault();
|
|
97
|
-
// Przy otwartym pod-menu przejście w bok otwiera pod-menu sąsiada
|
|
103
|
+
// Przy otwartym pod-menu przejście w bok otwiera pod-menu sąsiada - jak w menu aplikacji.
|
|
98
104
|
if (openIndex === null)
|
|
99
105
|
focusTop(next);
|
|
100
106
|
else
|
|
@@ -114,12 +120,18 @@ export function KptMenubar({ items = [], onSelect, ariaLabel, className, ...rest
|
|
|
114
120
|
focusTop(index);
|
|
115
121
|
}
|
|
116
122
|
};
|
|
123
|
+
/** Zwykły klik w odnośnik -> `onNavigate` (Ctrl/Cmd/Shift, środkowy przycisk i `_blank` zostają natywne). */
|
|
124
|
+
const linkClick = (event, item) => {
|
|
125
|
+
if (item.url && onNavigate && kptIsPlainClick(event, event.currentTarget.target)) {
|
|
126
|
+
onNavigate({ item, url: item.url, event: event.nativeEvent });
|
|
127
|
+
}
|
|
128
|
+
};
|
|
117
129
|
return (_jsx("div", { className: cn('kpt-menubar-host', className), ...rest, children: _jsx("div", { className: "kpt-menubar", role: "menubar", "aria-orientation": "horizontal", "aria-label": ariaLabel || undefined, children: items.map((item, index) => {
|
|
118
130
|
const hasMenu = !!item.items?.length;
|
|
119
131
|
return (_jsxs("div", { className: "kpt-menubar__group", role: "none", children: [isLink(item) ? (_jsxs("a", { ref: (el) => {
|
|
120
132
|
buttonsRef.current[index] = el;
|
|
121
|
-
}, className: "kpt-menubar__top", role: "menuitem", href: item.url, tabIndex: index === tabStop ? 0 : -1, onClick: () => pick(item, index), onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label })] })) : (_jsxs("button", { ref: (el) => {
|
|
133
|
+
}, className: "kpt-menubar__top", role: "menuitem", href: item.url, tabIndex: index === tabStop ? 0 : -1, onClick: (event) => { linkClick(event, item); pick(item, index); }, onFocus: () => setFocusIndex(index), onKeyDown: (event) => onTopKeyDown(event, index), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, _jsx("span", { children: item.label })] })) : (_jsxs("button", { ref: (el) => {
|
|
122
134
|
buttonsRef.current[index] = el;
|
|
123
|
-
}, type: "button", className: cn('kpt-menubar__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(index) : 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-menubar__caret" }) : null] })), _jsx(KptOverlay, { open: openIndex === index && hasMenu, anchor:
|
|
135
|
+
}, type: "button", className: cn('kpt-menubar__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(index) : 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-menubar__caret" }) : null] })), _jsx(KptOverlay, { open: openIndex === index && hasMenu, anchor: openIndex === index ? anchorEl : null, onClose: closeAll, children: _jsx("div", { ref: panelRef, className: "kpt-menubar__dropdown", role: "menu", tabIndex: -1, id: panelId(index), "aria-label": item.label, onKeyDown: (event) => onPanelKeyDown(event, index), children: (item.items ?? []).map((sub, subIndex) => sub.separator ? (_jsx("div", { className: "kpt-menubar__separator", role: "separator" }, subIndex)) : isLink(sub) ? (_jsxs("a", { className: cn('kpt-menubar__item', sub.danger && 'kpt-menubar__item--danger'), role: "menuitem", tabIndex: -1, href: sub.url, onClick: (event) => { linkClick(event, sub); pick(sub, index); }, children: [sub.icon ? _jsx(KptIcon, { name: sub.icon }) : null, _jsx("span", { children: sub.label })] }, subIndex)) : (_jsxs("button", { type: "button", className: cn('kpt-menubar__item', sub.danger && 'kpt-menubar__item--danger'), role: "menuitem", tabIndex: -1, disabled: sub.disabled, onClick: () => pick(sub, index), children: [sub.icon ? _jsx(KptIcon, { name: sub.icon }) : null, _jsx("span", { children: sub.label })] }, subIndex))) }) })] }, index));
|
|
124
136
|
}) }) }));
|
|
125
137
|
}
|
|
@@ -7,35 +7,35 @@ Import: `import { KptMeterGroup } from '@konce-pt/react';`
|
|
|
7
7
|
<div class="kpt-meter-group-host">
|
|
8
8
|
<div class="kpt-meter-group">
|
|
9
9
|
<div class="kpt-meter-group__track" role="meter" aria-label="Usage" aria-valuemin="0"
|
|
10
|
-
aria-valuenow="100" aria-valuemax="100" aria-valuetext="Documents 45,
|
|
11
|
-
<span class="kpt-meter-group__segment" style="width:45%" title="Documents"></span
|
|
10
|
+
aria-valuenow="100" aria-valuemax="100" aria-valuetext="Documents 45, ...">
|
|
11
|
+
<span class="kpt-meter-group__segment" style="width:45%" title="Documents"></span>...
|
|
12
12
|
</div>
|
|
13
13
|
<ul class="kpt-meter-group__legend">
|
|
14
14
|
<li class="kpt-meter-group__legend-item">
|
|
15
15
|
<span class="kpt-meter-group__dot"></span><span>Documents</span>
|
|
16
16
|
<span class="kpt-meter-group__val">45%</span>
|
|
17
|
-
</li
|
|
17
|
+
</li>...
|
|
18
18
|
</ul>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
22
|
## Props
|
|
23
|
-
- `values`: `KptMeterItem[]`
|
|
24
|
-
- `max`: number
|
|
23
|
+
- `values`: `KptMeterItem[]` - `{ label, value, color? }`
|
|
24
|
+
- `max`: number - the reference total; without it the values' sum is 100%
|
|
25
25
|
- `showLegend`: boolean (default true)
|
|
26
|
-
- `label`: string
|
|
27
|
-
- `legendValue`: 'percent' | 'value' (default 'percent')
|
|
28
|
-
- `unit`: string
|
|
26
|
+
- `label`: string - the meter's name; empty = `meterGroup.label`
|
|
27
|
+
- `legendValue`: 'percent' | 'value' (default 'percent') - what the legend shows next to each label
|
|
28
|
+
- `unit`: string - appended to the values in the legend and in `aria-valuetext` (e.g. 'GB')
|
|
29
29
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
30
30
|
|
|
31
31
|
## Percentages come from the sum, not from 100
|
|
32
32
|
Without `max` the reference is the sum of the values, so `[45, 25, 15, 15]` and `[9, 5, 3, 3]`
|
|
33
|
-
draw the same picture. Pass `max` when the segments are meant to leave a gap
|
|
33
|
+
draw the same picture. Pass `max` when the segments are meant to leave a gap - a quota that is
|
|
34
34
|
not full yet. All-zero values fall back to a divisor of 1 instead of producing `NaN%`.
|
|
35
35
|
|
|
36
36
|
## Colours
|
|
37
37
|
`color` per item, otherwise the next one from the semantic palette
|
|
38
|
-
(`primary
|
|
38
|
+
(`primary -> info -> success -> warning -> danger`, cycled), so a group of any length stays readable
|
|
39
39
|
without picking colours by hand.
|
|
40
40
|
|
|
41
41
|
## Examples
|
|
@@ -48,7 +48,7 @@ The palette `--kpt-color-{primary,info,success,warning,danger}`, the track
|
|
|
48
48
|
|
|
49
49
|
## Accessibility
|
|
50
50
|
The track is `role="meter"` named by `label` (or `meterGroup.label`), with `aria-valuemin="0"`,
|
|
51
|
-
`aria-valuenow` set to the sum and `aria-valuemax` set to the real total
|
|
52
|
-
it. `aria-valuetext` spells out the split (
|
|
51
|
+
`aria-valuenow` set to the sum and `aria-valuemax` set to the real total - `max`, or the sum without
|
|
52
|
+
it. `aria-valuetext` spells out the split ("Photos 42 GB, Videos 28 GB, ..."), so the segments reach
|
|
53
53
|
the screen reader even with the legend hidden. Keep the legend visible anyway: it is the text
|
|
54
54
|
alternative to the colours.
|
|
@@ -11,11 +11,11 @@ export interface KptMeterGroupProps extends ComponentPropsWithRef<'div'>, KptI18
|
|
|
11
11
|
/** Suma odniesienia; domyślnie suma wartości, czyli segmenty wypełniają całość. */
|
|
12
12
|
max?: number;
|
|
13
13
|
showLegend?: boolean;
|
|
14
|
-
/** Nazwa paska dla czytników ekranu, np.
|
|
14
|
+
/** Nazwa paska dla czytników ekranu, np. "Miejsce na dysku"; domyślnie `meterGroup.label`. */
|
|
15
15
|
label?: string;
|
|
16
16
|
/** Co pokazuje legenda przy etykiecie: udział procentowy albo samą wartość (z `unit`). */
|
|
17
17
|
legendValue?: 'percent' | 'value';
|
|
18
|
-
/** Jednostka dopisywana do wartości
|
|
18
|
+
/** Jednostka dopisywana do wartości - w legendzie (`legendValue="value"`) i w `aria-valuetext`. */
|
|
19
19
|
unit?: string;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { cn } from "../internal/cn.js";
|
|
3
4
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
@@ -24,7 +25,7 @@ export function KptMeterGroup({ values = [], max, showLegend = true, label = '',
|
|
|
24
25
|
const color = (item, index) => item.color || PALETTE[index % PALETTE.length];
|
|
25
26
|
const withUnit = (value) => (unit ? `${value} ${unit}` : String(value));
|
|
26
27
|
const legendText = (item) => legendValue === 'value' ? withUnit(item.value) : `${Math.round(percent(item))}%`;
|
|
27
|
-
// Podział dla czytnika (
|
|
28
|
+
// Podział dla czytnika ("Zdjęcia 42 GB, Filmy 28 GB...") - sam `aria-valuenow` mówi tylko sumę.
|
|
28
29
|
const valueText = values.map((item) => `${item.label} ${withUnit(item.value)}`).join(', ');
|
|
29
30
|
return (_jsx("div", { className: cn('kpt-meter-group-host', className), ...rest, children: _jsxs("div", { className: "kpt-meter-group", children: [_jsx("div", { className: "kpt-meter-group__track", role: "meter", "aria-valuemin": 0, "aria-valuenow": sum, "aria-valuemax": total, "aria-valuetext": valueText, "aria-label": label || t('meterGroup.label'), children: values.map((item, index) => (_jsx("span", { className: "kpt-meter-group__segment", style: { width: `${percent(item)}%`, backgroundColor: color(item, index) }, title: item.label }, index))) }), showLegend ? (_jsx("ul", { className: "kpt-meter-group__legend", children: values.map((item, index) => (_jsxs("li", { className: "kpt-meter-group__legend-item", children: [_jsx("span", { className: "kpt-meter-group__dot", style: { backgroundColor: color(item, index) } }), _jsx("span", { children: item.label }), _jsx("span", { className: "kpt-meter-group__val", children: legendText(item) })] }, index))) })) : null] }) }));
|
|
30
31
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type KptLayoutMotion, type KptMotionConfig } from '@konce-pt/motion';
|
|
3
|
+
export interface KptMotionProviderProps extends KptMotionConfig {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Globalne ustawienie ruchu Koncept UI: czy ruch jest włączony i jaki rodzaj ruchu dostają
|
|
8
|
+
* komponenty, które pozwalają go wybrać. Bez providera ruch jest włączony z domyślnymi
|
|
9
|
+
* wartościami; systemowe "ogranicz ruch" jest respektowane zawsze.
|
|
10
|
+
*
|
|
11
|
+
* `enabled={false}` gasi przejścia CSS wszystkich komponentów (atrybut `data-kpt-motion="off"`
|
|
12
|
+
* i zmienne na `:root` - nakładki w portalach też) oraz ruch sterowany z kodu; wskaźniki
|
|
13
|
+
* ładowania zwalniają zamiast stanąć.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <KptMotionProvider layout="arc" collapse="fade"><App /></KptMotionProvider>
|
|
17
|
+
* <KptMotionProvider enabled={false}><App /></KptMotionProvider>
|
|
18
|
+
*/
|
|
19
|
+
export declare function KptMotionProvider({ enabled, layout, collapse, enter, toggle, children }: Readonly<KptMotionProviderProps>): import("react").JSX.Element;
|
|
20
|
+
/** Konfiguracja ruchu z najbliższego providera; poza providerem `null` (wartości domyślne). */
|
|
21
|
+
export declare function useKptMotion(): KptMotionConfig | null;
|
|
22
|
+
export type { KptLayoutMotion, KptMotionConfig };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useLayoutEffect, useMemo } from 'react';
|
|
4
|
+
import { applyMotionConfig } from '@konce-pt/motion';
|
|
5
|
+
const KptMotionContext = createContext(null);
|
|
6
|
+
/**
|
|
7
|
+
* Globalne ustawienie ruchu Koncept UI: czy ruch jest włączony i jaki rodzaj ruchu dostają
|
|
8
|
+
* komponenty, które pozwalają go wybrać. Bez providera ruch jest włączony z domyślnymi
|
|
9
|
+
* wartościami; systemowe "ogranicz ruch" jest respektowane zawsze.
|
|
10
|
+
*
|
|
11
|
+
* `enabled={false}` gasi przejścia CSS wszystkich komponentów (atrybut `data-kpt-motion="off"`
|
|
12
|
+
* i zmienne na `:root` - nakładki w portalach też) oraz ruch sterowany z kodu; wskaźniki
|
|
13
|
+
* ładowania zwalniają zamiast stanąć.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <KptMotionProvider layout="arc" collapse="fade"><App /></KptMotionProvider>
|
|
17
|
+
* <KptMotionProvider enabled={false}><App /></KptMotionProvider>
|
|
18
|
+
*/
|
|
19
|
+
export function KptMotionProvider({ enabled, layout, collapse, enter, toggle, children }) {
|
|
20
|
+
const config = useMemo(() => ({ enabled, layout, collapse, enter, toggle }), [enabled, layout, collapse, enter, toggle]);
|
|
21
|
+
// Korzeń dokumentu, nie wrapper: przejścia w portalach (dialog, drawer) też muszą zgasnąć.
|
|
22
|
+
useLayoutEffect(() => applyMotionConfig(document.documentElement, config), [config]);
|
|
23
|
+
return _jsx(KptMotionContext.Provider, { value: config, children: children });
|
|
24
|
+
}
|
|
25
|
+
/** Konfiguracja ruchu z najbliższego providera; poza providerem `null` (wartości domyślne). */
|
|
26
|
+
export function useKptMotion() {
|
|
27
|
+
return useContext(KptMotionContext);
|
|
28
|
+
}
|
package/dist/order-list/llms.txt
CHANGED
|
@@ -7,26 +7,27 @@ Import: `import { KptOrderList } from '@konce-pt/react';`
|
|
|
7
7
|
## DOM
|
|
8
8
|
<div class="kpt-order-list-host">
|
|
9
9
|
<div class="kpt-order-list">
|
|
10
|
-
<div class="kpt-order-list__controls"
|
|
10
|
+
<div class="kpt-order-list__controls">...up, down...</div>
|
|
11
11
|
<div class="kpt-order-list__panel">
|
|
12
12
|
<div class="kpt-order-list__header">Order</div>
|
|
13
13
|
<ul class="kpt-order-list__items">
|
|
14
|
-
<li class="kpt-order-list__item is-selected"
|
|
14
|
+
<li class="kpt-order-list__item is-selected">...</li>...
|
|
15
15
|
</ul>
|
|
16
16
|
</div>
|
|
17
17
|
</div>
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
20
|
## Props
|
|
21
|
-
- `items` / `defaultItems` / `onItemsChange`
|
|
21
|
+
- `items` / `defaultItems` / `onItemsChange` - the list; the callback receives the new order
|
|
22
22
|
- `header`: string
|
|
23
|
-
- `dragdrop`
|
|
24
|
-
- `
|
|
23
|
+
- `dragdrop` - `false` by default; enables dragging (opt-in, nothing changes without it)
|
|
24
|
+
- `layoutMotion` - `'spring' | 'arc' | 'morph' | 'none'` (default from `KptMotionProvider`, else `spring`) - see below
|
|
25
|
+
- `renderItem(item, index)` - required; the equivalent of `<ng-template let-item>`
|
|
25
26
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
26
27
|
|
|
27
28
|
## The selection follows the item
|
|
28
29
|
After a move the selection jumps to the new index, so pressing the button again moves the same
|
|
29
|
-
entry
|
|
30
|
+
entry - with the selection pinned to a position, the second press would move its neighbour. A drop
|
|
30
31
|
does the same.
|
|
31
32
|
|
|
32
33
|
## Where a dragged item lands
|
|
@@ -43,18 +44,32 @@ dragged one `is-dragging`.
|
|
|
43
44
|
The buttons use `orderList.up` and `orderList.down`. Dragging carries no visible label, so it adds
|
|
44
45
|
no dictionary keys.
|
|
45
46
|
|
|
47
|
+
## Reorder motion
|
|
48
|
+
`layoutMotion` animates a reorder made by the user (buttons, `Alt`+ArrowUp/ArrowDown, dragging):
|
|
49
|
+
- `spring` - the moved item glides to its new place on a spring;
|
|
50
|
+
- `arc` - the moved item lifts (shadow) and lands, above its neighbours;
|
|
51
|
+
- `morph` - the browser's own morph (View Transitions); without support the change is instant;
|
|
52
|
+
- `none` - no motion.
|
|
53
|
+
|
|
54
|
+
Neighbours always make room with a calm spring, and the list scrolls to keep the moved item in
|
|
55
|
+
view. With no value it takes `layout` from `KptMotionProvider` (default `spring`); `enabled: false` and the
|
|
56
|
+
system "reduce motion" setting always win. A list replaced from outside (`items`) switches instantly.
|
|
57
|
+
|
|
46
58
|
## Tokens
|
|
47
59
|
The selection `--kpt-color-primary`, the buttons `--kpt-color-surface-raised`.
|
|
48
60
|
|
|
49
61
|
## Keyboard
|
|
50
62
|
The list is a `listbox` with a single Tab stop (roving tabindex), and the selection follows focus:
|
|
51
|
-
-
|
|
52
|
-
- `Alt
|
|
63
|
+
- `ArrowDown` / `ArrowUp` select the next / previous item (wrapping), `Home` / `End` the first / last;
|
|
64
|
+
- `Alt`+`ArrowUp` / `Alt`+`ArrowDown` move the selected item one place up / down - focus travels with it, so
|
|
53
65
|
repeated presses keep moving the same entry.
|
|
54
66
|
The up / down buttons stay and act on the same selection.
|
|
55
67
|
|
|
56
68
|
## Accessibility
|
|
57
69
|
The list is named after `header` (`aria-label`) and the selected item carries `aria-selected`.
|
|
58
70
|
Both buttons are labelled from the dictionary and go disabled while nothing is selected. Native
|
|
59
|
-
HTML5 drag and drop has no keyboard equivalent
|
|
71
|
+
HTML5 drag and drop has no keyboard equivalent - `Alt`+arrows and the buttons cover it, and
|
|
60
72
|
`dragdrop` adds to them, it never replaces them.
|
|
73
|
+
|
|
74
|
+
## Announcements
|
|
75
|
+
Every reorder (buttons, Alt+ArrowUp/ArrowDown, drag and drop) is announced in a polite live region: `orderList.moved` with `{position}` and `{total}` - focus does not move, so a screen reader would not hear the new place otherwise.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
import { type KptLayoutMotion } from '@konce-pt/motion';
|
|
2
3
|
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
4
|
export interface KptOrderListProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'children'>, KptI18nOverrides {
|
|
4
5
|
items?: T[];
|
|
@@ -7,18 +8,25 @@ export interface KptOrderListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
|
|
|
7
8
|
header?: string;
|
|
8
9
|
/** Włącza przestawianie pozycji metodą przeciągnij-i-upuść. */
|
|
9
10
|
dragdrop?: boolean;
|
|
10
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Ruch przestawiania: `spring` - pozycja płynie na nowe miejsce na sprężynie, `arc` - unosi się
|
|
13
|
+
* z cieniem i ląduje, `morph` - natywny morf przeglądarki (View Transitions), `none` - bez ruchu.
|
|
14
|
+
* Sąsiedzi zawsze robią miejsce spokojną sprężyną. Bez wartości bierze `layout` z `KptMotionProvider`
|
|
15
|
+
* (domyślnie `spring`); `enabled={false}` i systemowe "ogranicz ruch" wyłączają go zawsze.
|
|
16
|
+
*/
|
|
17
|
+
layoutMotion?: KptLayoutMotion;
|
|
18
|
+
/** Szablon elementu - odpowiednik `<ng-template let-item>` z Angulara. */
|
|
11
19
|
renderItem: (item: T, index: number) => ReactNode;
|
|
12
20
|
}
|
|
13
21
|
/**
|
|
14
|
-
* OrderList
|
|
22
|
+
* OrderList - lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
|
|
15
23
|
* w górę i w dół. Z `dragdrop` pozycje przestawia się także przeciąganiem.
|
|
16
24
|
*
|
|
17
25
|
* Lista to `listbox` z jednym przystankiem Tab (roving tabindex), w którym zaznaczenie idzie
|
|
18
|
-
* za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt
|
|
26
|
+
* za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt`+ArrowUp/ArrowDown przestawia ją o jedno
|
|
19
27
|
* miejsce (fokus jedzie razem z nią).
|
|
20
28
|
*
|
|
21
29
|
* @example
|
|
22
30
|
* <KptOrderList items={tasks} onItemsChange={setTasks} header="Kolejność" dragdrop renderItem={(t) => t.name} />
|
|
23
31
|
*/
|
|
24
|
-
export declare function KptOrderList<T>({ items, defaultItems, onItemsChange, header, dragdrop, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptOrderListProps<T>>): import("react").JSX.Element;
|
|
32
|
+
export declare function KptOrderList<T>({ items, defaultItems, onItemsChange, header, dragdrop, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptOrderListProps<T>>): import("react").JSX.Element;
|
|
@@ -1,24 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useEffect, useEffectEvent, useId, useLayoutEffect, useRef, useState, } from 'react';
|
|
4
|
+
import { flushSync } from 'react-dom';
|
|
5
|
+
import { isVisibleInScroller, layoutMotionAllowed, morphKeyed, playKeyedMotion, resolveLayoutMotion, revealInScroller, snapshotKeyed, stopKeyedMotion, } from '@konce-pt/motion';
|
|
3
6
|
import { cn } from "../internal/cn.js";
|
|
4
7
|
import { composeRefs } from "../internal/compose-refs.js";
|
|
5
8
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
6
9
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
7
10
|
import { KptIcon } from "../icon/icon.js";
|
|
8
11
|
import { nextMenuIndex } from "../menu/menu-keys.js";
|
|
12
|
+
import { useKptMotion } from "../motion/motion-context.js";
|
|
13
|
+
/** Klasy ruchu przestawiania - reguły we wspólnym CSS komponentu (duchów tu nie ma: jedna lista). */
|
|
14
|
+
const MOTION_CLASSES = {
|
|
15
|
+
ghostClass: 'kpt-order-list__ghost',
|
|
16
|
+
hiddenClass: 'kpt-order-list__item--waiting',
|
|
17
|
+
movingClass: 'kpt-order-list__item--moving',
|
|
18
|
+
};
|
|
19
|
+
/** Klasa View Transitions dla morfu. */
|
|
20
|
+
const MORPH_CLASS = 'kpt-order-list-morph';
|
|
21
|
+
/** Przewijany pojemnik wiersza. */
|
|
22
|
+
function scrollerOf(element) {
|
|
23
|
+
return element.closest('.kpt-order-list__items');
|
|
24
|
+
}
|
|
9
25
|
const EMPTY = [];
|
|
10
26
|
/**
|
|
11
|
-
* OrderList
|
|
27
|
+
* OrderList - lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
|
|
12
28
|
* w górę i w dół. Z `dragdrop` pozycje przestawia się także przeciąganiem.
|
|
13
29
|
*
|
|
14
30
|
* Lista to `listbox` z jednym przystankiem Tab (roving tabindex), w którym zaznaczenie idzie
|
|
15
|
-
* za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt
|
|
31
|
+
* za fokusem: strzałki / `Home` / `End` wybierają pozycję, `Alt`+ArrowUp/ArrowDown przestawia ją o jedno
|
|
16
32
|
* miejsce (fokus jedzie razem z nią).
|
|
17
33
|
*
|
|
18
34
|
* @example
|
|
19
35
|
* <KptOrderList items={tasks} onItemsChange={setTasks} header="Kolejność" dragdrop renderItem={(t) => t.name} />
|
|
20
36
|
*/
|
|
21
|
-
export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, header = '', dragdrop = false, renderItem, locale, dictionary, className, ref, ...rest }) {
|
|
37
|
+
export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, header = '', dragdrop = false, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }) {
|
|
22
38
|
const { t } = useKptMessages({ locale, dictionary });
|
|
23
39
|
const [list, setList] = useControllableState({
|
|
24
40
|
value: items,
|
|
@@ -28,46 +44,119 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
|
|
|
28
44
|
const [selected, setSelected] = useState(null);
|
|
29
45
|
/** Indeks przeciąganej pozycji; `null` gdy nic nie jest przeciągane. */
|
|
30
46
|
const [dragIndex, setDragIndex] = useState(null);
|
|
31
|
-
/** Indeks pozycji pod kursorem
|
|
47
|
+
/** Indeks pozycji pod kursorem - rysuje wskaźnik miejsca upuszczenia. */
|
|
32
48
|
const [overIndex, setOverIndex] = useState(null);
|
|
33
|
-
/** Kursor nad pustym obszarem listy
|
|
49
|
+
/** Kursor nad pustym obszarem listy - upuszczenie tam dopina na koniec. */
|
|
34
50
|
const [listOver, setListOver] = useState(false);
|
|
35
51
|
/** Pozycja, na którą po renderze trzeba przenieść fokus DOM (klawiatura). */
|
|
36
52
|
const [focusRequest, setFocusRequest] = useState(null);
|
|
37
53
|
const rootRef = useRef(null);
|
|
54
|
+
const motionConfig = useKptMotion();
|
|
55
|
+
// `view-transition-name` musi być poprawnym identyfikatorem CSS - `useId` daje dwukropki.
|
|
56
|
+
const morphPrefix = `kpt-order-list-${useId().replaceAll(/[^a-zA-Z0-9-]/g, '')}`;
|
|
57
|
+
/** Który element danych pokazuje każdy wiersz - wiersze mają klucz po indeksie, więc go zmieniają. */
|
|
58
|
+
const keyOf = useRef(new WeakMap());
|
|
59
|
+
/** Stan sprzed zmiany, czekający na commit nowej kolejności. */
|
|
60
|
+
const pending = useRef(null);
|
|
61
|
+
/** Indeks przestawionej pozycji - lista przewija się do niej po zmianie. */
|
|
62
|
+
const revealIndex = useRef(null);
|
|
63
|
+
const stage = () => rootRef.current?.querySelector('.kpt-order-list') ?? null;
|
|
64
|
+
const nodes = () => {
|
|
65
|
+
const root = stage();
|
|
66
|
+
if (!root)
|
|
67
|
+
return [];
|
|
68
|
+
return Array.from(root.querySelectorAll('.kpt-order-list__items > .kpt-order-list__item')).flatMap((element) => keyOf.current.has(element) ? [{ key: keyOf.current.get(element), element }] : []);
|
|
69
|
+
};
|
|
70
|
+
const reveal = () => {
|
|
71
|
+
const row = revealIndex.current === null ? undefined : nodes()[revealIndex.current];
|
|
72
|
+
if (row)
|
|
73
|
+
revealInScroller(row.element, scrollerOf(row.element));
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Przestawienie z ruchem. Stan sprzed zmiany mierzymy, zanim React zmieni DOM - dlatego animujemy
|
|
77
|
+
* zmiany z interakcji (przyciski, `Alt`+strzałki, przeciąganie), a lista podmieniona z zewnątrz
|
|
78
|
+
* przełącza się od razu.
|
|
79
|
+
*/
|
|
80
|
+
const withMotion = (apply, lead, target, origin) => {
|
|
81
|
+
const motion = resolveLayoutMotion(layoutMotion, motionConfig);
|
|
82
|
+
revealIndex.current = target;
|
|
83
|
+
const root = stage();
|
|
84
|
+
if (motion === 'none' || !root || !layoutMotionAllowed()) {
|
|
85
|
+
apply();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (motion === 'morph') {
|
|
89
|
+
morphKeyed(nodes(), nodes, morphPrefix, MORPH_CLASS, () => {
|
|
90
|
+
flushSync(apply);
|
|
91
|
+
reveal();
|
|
92
|
+
}, (el) => isVisibleInScroller(el, scrollerOf(el)));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
pending.current = { first: snapshotKeyed(root, nodes(), scrollerOf), motion, lead, origin };
|
|
96
|
+
stopKeyedMotion(root, MOTION_CLASSES);
|
|
97
|
+
apply();
|
|
98
|
+
};
|
|
99
|
+
// Nowa kolejność jest już w DOM (a `keyOf` zaktualizowany refami) - gramy loty od zapamiętanego stanu.
|
|
100
|
+
const playPending = useEffectEvent(() => {
|
|
101
|
+
const job = pending.current;
|
|
102
|
+
pending.current = null;
|
|
103
|
+
const root = stage();
|
|
104
|
+
if (!job || !root)
|
|
105
|
+
return;
|
|
106
|
+
reveal();
|
|
107
|
+
playKeyedMotion(root, job.first, nodes(), { motion: job.motion, scrollerOf, ...MOTION_CLASSES, lead: new Set([job.lead]) }, job.origin);
|
|
108
|
+
});
|
|
109
|
+
useLayoutEffect(() => {
|
|
110
|
+
playPending();
|
|
111
|
+
}, [list]);
|
|
112
|
+
// Żądanie nie jest zerowane w efekcie (setState w efekcie = dodatkowy przebieg renderu): każde jest
|
|
113
|
+
// nowym obiektem, więc efekt rusza raz na żądanie, także o ten sam indeks.
|
|
38
114
|
useEffect(() => {
|
|
39
|
-
if (focusRequest
|
|
115
|
+
if (!focusRequest)
|
|
40
116
|
return;
|
|
41
|
-
rootRef.current?.querySelectorAll('[role="option"]')[focusRequest]?.focus();
|
|
42
|
-
setFocusRequest(null);
|
|
117
|
+
rootRef.current?.querySelectorAll('[role="option"]')[focusRequest.index]?.focus();
|
|
43
118
|
}, [focusRequest]);
|
|
44
119
|
/**
|
|
45
120
|
* Przesuwa pozycję spod `index` o jedno miejsce i zwraca jej nowy indeks. Jawny indeks zamiast
|
|
46
121
|
* `selected`: klawiatura zaznacza i przesuwa w jednym zdarzeniu, a stan z domknięcia byłby stary.
|
|
47
122
|
*/
|
|
48
|
-
|
|
123
|
+
/** Treść regionu `aria-live` po przestawieniu. */
|
|
124
|
+
const [announcement, setAnnouncement] = useState('');
|
|
125
|
+
/**
|
|
126
|
+
* Ogłasza nową pozycję. Ten sam tekst drugi raz pod rząd nie zostałby przeczytany (region reaguje
|
|
127
|
+
* na zmianę), więc naprzemiennie dokładamy niewidoczną spację.
|
|
128
|
+
*/
|
|
129
|
+
const announce = (index, total) => {
|
|
130
|
+
const text = t('orderList.moved', { position: index + 1, total });
|
|
131
|
+
setAnnouncement((current) => (current === text ? text + '\u00a0' : text));
|
|
132
|
+
};
|
|
133
|
+
const moveFrom = (index, dir, origin) => {
|
|
49
134
|
const target = index + dir;
|
|
50
135
|
if (target < 0 || target >= list.length)
|
|
51
136
|
return index;
|
|
52
137
|
const next = [...list];
|
|
138
|
+
const moved = next[index];
|
|
53
139
|
[next[index], next[target]] = [next[target], next[index]];
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
140
|
+
withMotion(() => {
|
|
141
|
+
setList(next);
|
|
142
|
+
// Zaznaczenie wędruje za elementem, nie zostaje na pozycji - inaczej kolejne kliknięcie
|
|
143
|
+
// przesuwałoby sąsiada zamiast tego samego wpisu.
|
|
144
|
+
setSelected(target);
|
|
145
|
+
}, moved, target, origin);
|
|
146
|
+
announce(target, next.length);
|
|
58
147
|
return target;
|
|
59
148
|
};
|
|
60
|
-
const move = (dir) => {
|
|
149
|
+
const move = (dir, origin) => {
|
|
61
150
|
if (selected !== null)
|
|
62
|
-
moveFrom(selected, dir);
|
|
151
|
+
moveFrom(selected, dir, origin);
|
|
63
152
|
};
|
|
64
153
|
/** Przystanek Tab: zaznaczona pozycja albo pierwsza. */
|
|
65
154
|
const tabStop = selected !== null && selected < list.length ? selected : 0;
|
|
66
|
-
// Strzałki wybierają pozycję (zaznaczenie idzie za fokusem), `Alt
|
|
155
|
+
// Strzałki wybierają pozycję (zaznaczenie idzie za fokusem), `Alt`+ArrowUp/ArrowDown ją przestawia.
|
|
67
156
|
const onItemKeyDown = (index, event) => {
|
|
68
157
|
if (event.altKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {
|
|
69
158
|
event.preventDefault();
|
|
70
|
-
setFocusRequest(moveFrom(index, event.key === 'ArrowUp' ? -1 : 1));
|
|
159
|
+
setFocusRequest({ index: moveFrom(index, event.key === 'ArrowUp' ? -1 : 1, event.currentTarget) });
|
|
71
160
|
return;
|
|
72
161
|
}
|
|
73
162
|
const next = nextMenuIndex(list.length, index, event.key);
|
|
@@ -75,7 +164,7 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
|
|
|
75
164
|
return;
|
|
76
165
|
event.preventDefault();
|
|
77
166
|
setSelected(next);
|
|
78
|
-
setFocusRequest(next);
|
|
167
|
+
setFocusRequest({ index: next });
|
|
79
168
|
};
|
|
80
169
|
const clearDrag = () => {
|
|
81
170
|
setDragIndex(null);
|
|
@@ -105,15 +194,18 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
|
|
|
105
194
|
clearDrag();
|
|
106
195
|
if (from === null || from === index)
|
|
107
196
|
return;
|
|
108
|
-
// Indeks celu liczony na tablicy sprzed usunięcia
|
|
197
|
+
// Indeks celu liczony na tablicy sprzed usunięcia - element ląduje na pozycji tego,
|
|
109
198
|
// na który go upuszczono (ten sam wzór co przestawianie kolumn w KptDataTable).
|
|
110
199
|
const next = [...list];
|
|
111
200
|
const [moved] = next.splice(from, 1);
|
|
112
201
|
if (moved === undefined)
|
|
113
202
|
return;
|
|
114
203
|
next.splice(index, 0, moved);
|
|
115
|
-
|
|
116
|
-
|
|
204
|
+
withMotion(() => {
|
|
205
|
+
setList(next);
|
|
206
|
+
setSelected(index);
|
|
207
|
+
}, moved, index, event.currentTarget);
|
|
208
|
+
announce(index, next.length);
|
|
117
209
|
};
|
|
118
210
|
const onListDragOver = (event) => {
|
|
119
211
|
if (dragIndex === null)
|
|
@@ -133,8 +225,14 @@ export function KptOrderList({ items, defaultItems = EMPTY, onItemsChange, heade
|
|
|
133
225
|
if (moved === undefined)
|
|
134
226
|
return;
|
|
135
227
|
next.push(moved);
|
|
136
|
-
|
|
137
|
-
|
|
228
|
+
withMotion(() => {
|
|
229
|
+
setList(next);
|
|
230
|
+
setSelected(next.length - 1);
|
|
231
|
+
}, moved, next.length - 1, event.currentTarget);
|
|
232
|
+
announce(next.length - 1, next.length);
|
|
138
233
|
};
|
|
139
|
-
return (
|
|
234
|
+
return (_jsxs("div", { ref: composeRefs(rootRef, ref), className: cn('kpt-order-list-host', className), ...rest, children: [_jsxs("div", { className: "kpt-order-list", children: [_jsxs("div", { className: "kpt-order-list__controls", children: [_jsx("button", { type: "button", disabled: selected === null, "aria-label": t('orderList.up'), onClick: (event) => move(-1, event.currentTarget), children: _jsx(KptIcon, { name: "arrow-up" }) }), _jsx("button", { type: "button", disabled: selected === null, "aria-label": t('orderList.down'), onClick: (event) => move(1, event.currentTarget), children: _jsx(KptIcon, { name: "arrow-down" }) })] }), _jsxs("div", { className: "kpt-order-list__panel", children: [header ? _jsx("div", { className: "kpt-order-list__header", children: header }) : null, _jsx("ul", { className: cn('kpt-order-list__items', listOver && 'is-dragover'), role: "listbox", "aria-label": header || undefined, onDragOver: onListDragOver, onDragLeave: () => setListOver(false), onDrop: onListDrop, children: list.map((item, index) => (_jsx("li", { ref: (element) => {
|
|
235
|
+
if (element)
|
|
236
|
+
keyOf.current.set(element, item);
|
|
237
|
+
}, className: cn('kpt-order-list__item', selected === index && 'is-selected', dragIndex === index && 'is-dragging', dragdrop && 'kpt-order-list__item--draggable', overIndex === index && dragIndex !== index && 'kpt-order-list__item--dragover'), role: "option", "aria-selected": selected === index, tabIndex: index === tabStop ? 0 : -1, onFocus: () => setSelected(index), onKeyDown: (event) => onItemKeyDown(index, event), draggable: dragdrop || undefined, onClick: () => setSelected(index), onDragStart: (event) => onDragStart(index, event), onDragOver: (event) => onDragOver(index, event), onDragLeave: () => setOverIndex(null), onDrop: (event) => onDrop(index, event), onDragEnd: clearDrag, children: renderItem(item, index) }, index))) })] })] }), _jsx("p", { className: "kpt-visually-hidden", "aria-live": "polite", children: announcement })] }));
|
|
140
238
|
}
|
package/dist/paginator/llms.txt
CHANGED
|
@@ -5,22 +5,22 @@ Import: `import { KptPaginator } from '@konce-pt/react';`
|
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<div class="kpt-paginator">
|
|
8
|
-
<div class="kpt-paginator__size"><label>Rows: <select class="kpt-paginator__select"
|
|
9
|
-
<span class="kpt-paginator__range">1
|
|
10
|
-
<div class="kpt-paginator__nav"
|
|
8
|
+
<div class="kpt-paginator__size"><label>Rows: <select class="kpt-paginator__select">...</select></label></div>
|
|
9
|
+
<span class="kpt-paginator__range">1-10 of 120</span>
|
|
10
|
+
<div class="kpt-paginator__nav">...two KptButton...</div>
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
13
|
## Props
|
|
14
|
-
- `length`: number
|
|
15
|
-
- `pageIndex` / `defaultPageIndex` / `onPageIndexChange`
|
|
16
|
-
- `pageSize` / `defaultPageSize` / `onPageSizeChange`
|
|
14
|
+
- `length`: number - the total number of items (required)
|
|
15
|
+
- `pageIndex` / `defaultPageIndex` / `onPageIndexChange` - the 0-based page
|
|
16
|
+
- `pageSize` / `defaultPageSize` / `onPageSizeChange` - the page size (default 10)
|
|
17
17
|
- `pageSizeOptions`: readonly number[] (default [5, 10, 20, 50])
|
|
18
18
|
|
|
19
19
|
The select always offers the current `pageSize` even when it is absent from this list: without
|
|
20
20
|
that, `pageSize={8}` against the defaults left no matching option, so the control displayed the
|
|
21
21
|
first entry while the table paged by eight.
|
|
22
|
-
- `prevIcon`, `nextIcon`: ReactNode
|
|
23
|
-
- `locale`, `dictionary`
|
|
22
|
+
- `prevIcon`, `nextIcon`: ReactNode - the navigation button content
|
|
23
|
+
- `locale`, `dictionary` - i18n overrides for this component only
|
|
24
24
|
- `className`, `ref` and every other `<div>` prop go to the paginator root
|
|
25
25
|
|
|
26
26
|
## Behaviour
|