@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,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 KptPickListProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'children'>, KptI18nOverrides {
|
|
4
5
|
source?: T[];
|
|
@@ -13,13 +14,20 @@ export interface KptPickListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
|
|
|
13
14
|
targetHeader?: string;
|
|
14
15
|
/** Włącza porządkowanie i przenoszenie elementów metodą przeciągnij-i-upuść. */
|
|
15
16
|
dragdrop?: boolean;
|
|
16
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Ruch przy przenoszeniu i przestawianiu elementów: `spring` - element płynie na sprężynie,
|
|
19
|
+
* `arc` - unosi się i leci po łuku, `morph` - natywny morf przeglądarki (View Transitions),
|
|
20
|
+
* `none` - bez ruchu. Bez wartości bierze `layout` z `KptMotionProvider` (domyślnie `spring`);
|
|
21
|
+
* `<KptMotionProvider enabled={false}>` i systemowe "ogranicz ruch" wyłączają go zawsze.
|
|
22
|
+
*/
|
|
23
|
+
layoutMotion?: KptLayoutMotion;
|
|
24
|
+
/** Szablon elementu - odpowiednik `<ng-template let-item>` z Angulara. */
|
|
17
25
|
renderItem: (item: T, index: number) => ReactNode;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
20
|
-
* PickList
|
|
28
|
+
* PickList - transfer elementów między dwiema listami. Klik zaznacza, przyciski pośrodku
|
|
21
29
|
* przenoszą zaznaczone albo wszystko, dwuklik przerzuca pojedynczy element na drugą stronę.
|
|
22
|
-
* Z `dragdrop` dochodzi przeciąganie
|
|
30
|
+
* Z `dragdrop` dochodzi przeciąganie - porządkowanie wewnątrz panelu i przenoszenie na
|
|
23
31
|
* konkretną pozycję drugiego panelu.
|
|
24
32
|
*
|
|
25
33
|
* Każda lista to `listbox` z wielokrotnym wyborem i jednym przystankiem Tab (roving tabindex):
|
|
@@ -34,4 +42,4 @@ export interface KptPickListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
|
|
|
34
42
|
* renderItem={(item) => item.name}
|
|
35
43
|
* />
|
|
36
44
|
*/
|
|
37
|
-
export declare function KptPickList<T>({ source, defaultSource, onSourceChange, target, defaultTarget, onTargetChange, sourceHeader, targetHeader, dragdrop, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptPickListProps<T>>): import("react").JSX.Element;
|
|
45
|
+
export declare function KptPickList<T>({ source, defaultSource, onSourceChange, target, defaultTarget, onTargetChange, sourceHeader, targetHeader, dragdrop, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }: Readonly<KptPickListProps<T>>): import("react").JSX.Element;
|
|
@@ -1,16 +1,32 @@
|
|
|
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";
|
|
9
13
|
const EMPTY = [];
|
|
14
|
+
/** Klasy ruchu przenoszenia - reguły we wspólnym CSS komponentu. */
|
|
15
|
+
const MOTION_CLASSES = {
|
|
16
|
+
ghostClass: 'kpt-pick-list__ghost',
|
|
17
|
+
hiddenClass: 'kpt-pick-list__item--waiting',
|
|
18
|
+
movingClass: 'kpt-pick-list__item--moving',
|
|
19
|
+
};
|
|
20
|
+
/** Klasa View Transitions dla morfu. */
|
|
21
|
+
const MORPH_CLASS = 'kpt-pick-list-morph';
|
|
22
|
+
/** Przewijany pojemnik wiersza - lista panelu. */
|
|
23
|
+
function scrollerOf(element) {
|
|
24
|
+
return element.closest('.kpt-pick-list__items');
|
|
25
|
+
}
|
|
10
26
|
/**
|
|
11
|
-
* PickList
|
|
27
|
+
* PickList - transfer elementów między dwiema listami. Klik zaznacza, przyciski pośrodku
|
|
12
28
|
* przenoszą zaznaczone albo wszystko, dwuklik przerzuca pojedynczy element na drugą stronę.
|
|
13
|
-
* Z `dragdrop` dochodzi przeciąganie
|
|
29
|
+
* Z `dragdrop` dochodzi przeciąganie - porządkowanie wewnątrz panelu i przenoszenie na
|
|
14
30
|
* konkretną pozycję drugiego panelu.
|
|
15
31
|
*
|
|
16
32
|
* Każda lista to `listbox` z wielokrotnym wyborem i jednym przystankiem Tab (roving tabindex):
|
|
@@ -25,7 +41,7 @@ const EMPTY = [];
|
|
|
25
41
|
* renderItem={(item) => item.name}
|
|
26
42
|
* />
|
|
27
43
|
*/
|
|
28
|
-
export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, target, defaultTarget = EMPTY, onTargetChange, sourceHeader, targetHeader, dragdrop = false, renderItem, locale, dictionary, className, ref, ...rest }) {
|
|
44
|
+
export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, target, defaultTarget = EMPTY, onTargetChange, sourceHeader, targetHeader, dragdrop = false, layoutMotion, renderItem, locale, dictionary, className, ref, ...rest }) {
|
|
29
45
|
const { t } = useKptMessages({ locale, dictionary });
|
|
30
46
|
const [left, setLeft] = useControllableState({
|
|
31
47
|
value: source,
|
|
@@ -41,18 +57,80 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
41
57
|
// po obu stronach się przesuwają, a referencja zostaje ta sama.
|
|
42
58
|
const [selLeft, setSelLeft] = useState(new Set());
|
|
43
59
|
const [selRight, setSelRight] = useState(new Set());
|
|
44
|
-
/** Przeciągany element
|
|
60
|
+
/** Przeciągany element - strona i pozycja w jej tablicy. */
|
|
45
61
|
const [drag, setDrag] = useState(null);
|
|
46
|
-
/** Element pod kursorem
|
|
62
|
+
/** Element pod kursorem - rysuje wskaźnik miejsca upuszczenia. */
|
|
47
63
|
const [over, setOver] = useState(null);
|
|
48
|
-
/** Panel, nad którego pustym obszarem jest kursor
|
|
64
|
+
/** Panel, nad którego pustym obszarem jest kursor - upuszczenie tam dopina na koniec. */
|
|
49
65
|
const [listOver, setListOver] = useState(null);
|
|
50
|
-
/** Pozycja, która ostatnio miała fokus w każdej liście
|
|
66
|
+
/** Pozycja, która ostatnio miała fokus w każdej liście - ona jest przystankiem Tab. */
|
|
51
67
|
const [focusLeft, setFocusLeft] = useState(0);
|
|
52
68
|
const [focusRight, setFocusRight] = useState(0);
|
|
53
69
|
/** Pozycja, na którą po renderze trzeba przenieść fokus DOM (klawiatura). */
|
|
54
70
|
const [focusRequest, setFocusRequest] = useState(null);
|
|
55
71
|
const rootRef = useRef(null);
|
|
72
|
+
const motionConfig = useKptMotion();
|
|
73
|
+
// `view-transition-name` musi być poprawnym identyfikatorem CSS - `useId` daje dwukropki.
|
|
74
|
+
const morphPrefix = `kpt-pick-list-${useId().replaceAll(/[^a-zA-Z0-9-]/g, '')}`;
|
|
75
|
+
/** Który element danych pokazuje każdy wiersz - wiersze mają klucz po indeksie, więc go zmieniają. */
|
|
76
|
+
const keyOf = useRef(new WeakMap());
|
|
77
|
+
/** Stan sprzed zmiany, czekający na commit nowego układu. */
|
|
78
|
+
const pending = useRef(null);
|
|
79
|
+
/** Elementy, które przy ostatniej zmianie przeszły na drugą stronę - lista przewija się do nich. */
|
|
80
|
+
const crossed = useRef([]);
|
|
81
|
+
const stage = () => rootRef.current?.querySelector('.kpt-pick-list') ?? null;
|
|
82
|
+
const nodes = () => {
|
|
83
|
+
const root = stage();
|
|
84
|
+
if (!root)
|
|
85
|
+
return [];
|
|
86
|
+
return Array.from(root.querySelectorAll('.kpt-pick-list__items > .kpt-pick-list__item')).flatMap((element) => keyOf.current.has(element) ? [{ key: keyOf.current.get(element), element }] : []);
|
|
87
|
+
};
|
|
88
|
+
/** Przewija listę docelową do ostatniego przeniesionego elementu - ląduje tam, gdzie go widać. */
|
|
89
|
+
const revealCrossed = () => {
|
|
90
|
+
const last = crossed.current.at(-1);
|
|
91
|
+
if (last === undefined)
|
|
92
|
+
return;
|
|
93
|
+
const node = nodes().find((n) => n.key === last);
|
|
94
|
+
if (node)
|
|
95
|
+
revealInScroller(node.element, scrollerOf(node.element));
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Zmiana list z ruchem. Stan sprzed zmiany mierzymy, zanim React zmieni DOM - dlatego animujemy
|
|
99
|
+
* zmiany z interakcji (przyciski, dwuklik, Enter, przeciąganie), a listy podmienione z zewnątrz
|
|
100
|
+
* przełączają się od razu.
|
|
101
|
+
*/
|
|
102
|
+
const withMotion = (apply, origin) => {
|
|
103
|
+
const motion = resolveLayoutMotion(layoutMotion, motionConfig);
|
|
104
|
+
crossed.current = [];
|
|
105
|
+
const root = stage();
|
|
106
|
+
if (motion === 'none' || !root || !layoutMotionAllowed()) {
|
|
107
|
+
apply();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (motion === 'morph') {
|
|
111
|
+
morphKeyed(nodes(), nodes, morphPrefix, MORPH_CLASS, () => {
|
|
112
|
+
flushSync(apply);
|
|
113
|
+
revealCrossed();
|
|
114
|
+
}, (el) => isVisibleInScroller(el, scrollerOf(el)));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
pending.current = { first: snapshotKeyed(root, nodes(), scrollerOf), motion, origin };
|
|
118
|
+
stopKeyedMotion(root, MOTION_CLASSES);
|
|
119
|
+
apply();
|
|
120
|
+
};
|
|
121
|
+
// Nowy układ jest już w DOM (a `keyOf` zaktualizowany refami) - gramy loty od zapamiętanego stanu.
|
|
122
|
+
const playPending = useEffectEvent(() => {
|
|
123
|
+
const job = pending.current;
|
|
124
|
+
pending.current = null;
|
|
125
|
+
const root = stage();
|
|
126
|
+
if (!job || !root)
|
|
127
|
+
return;
|
|
128
|
+
revealCrossed();
|
|
129
|
+
playKeyedMotion(root, job.first, nodes(), { motion: job.motion, scrollerOf, ...MOTION_CLASSES }, job.origin);
|
|
130
|
+
});
|
|
131
|
+
useLayoutEffect(() => {
|
|
132
|
+
playPending();
|
|
133
|
+
}, [left, right]);
|
|
56
134
|
const listOf = (side) => (side === 'source' ? left : right);
|
|
57
135
|
const setListOf = (side) => (side === 'source' ? setLeft : setRight);
|
|
58
136
|
const selectionOf = (side) => (side === 'source' ? selLeft : selRight);
|
|
@@ -60,15 +138,16 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
60
138
|
const other = (side) => (side === 'source' ? 'target' : 'source');
|
|
61
139
|
const focusOf = (side) => (side === 'source' ? focusLeft : focusRight);
|
|
62
140
|
const setFocusOf = (side) => (side === 'source' ? setFocusLeft : setFocusRight);
|
|
63
|
-
/** Przystanek Tab listy
|
|
141
|
+
/** Przystanek Tab listy - ostatnio skupiona pozycja, przycięta do długości listy. */
|
|
64
142
|
const tabIndexOf = (side) => Math.min(focusOf(side), listOf(side).length - 1);
|
|
143
|
+
// Żądanie nie jest zerowane w efekcie (setState w efekcie = dodatkowy przebieg renderu): każde jest
|
|
144
|
+
// nowym obiektem, więc efekt rusza raz na żądanie, także o ten sam indeks.
|
|
65
145
|
useEffect(() => {
|
|
66
146
|
if (!focusRequest)
|
|
67
147
|
return;
|
|
68
148
|
const list = rootRef.current?.querySelectorAll('.kpt-pick-list__items')[focusRequest.side === 'source' ? 0 : 1];
|
|
69
149
|
const options = list?.querySelectorAll('[role="option"]') ?? [];
|
|
70
150
|
options[Math.min(focusRequest.index, options.length - 1)]?.focus();
|
|
71
|
-
setFocusRequest(null);
|
|
72
151
|
}, [focusRequest]);
|
|
73
152
|
const focusItem = (side, index) => {
|
|
74
153
|
setFocusOf(side)(index);
|
|
@@ -82,7 +161,21 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
82
161
|
next.add(item);
|
|
83
162
|
setSelectionOf(side)(next);
|
|
84
163
|
};
|
|
85
|
-
const
|
|
164
|
+
const headerOf = (side) => side === 'source' ? (sourceHeader ?? t('pickList.available')) : (targetHeader ?? t('pickList.selected'));
|
|
165
|
+
/** Treść regionu `aria-live` po przeniesieniu. */
|
|
166
|
+
const [announcement, setAnnouncement] = useState('');
|
|
167
|
+
/**
|
|
168
|
+
* Ogłasza przeniesienie. Ten sam tekst drugi raz pod rząd nie zostałby przeczytany (region
|
|
169
|
+
* reaguje na zmianę), więc naprzemiennie dokładamy niewidoczną spację.
|
|
170
|
+
*/
|
|
171
|
+
const announce = (count, to) => {
|
|
172
|
+
const text = t('pickList.moved', { count, list: headerOf(to) });
|
|
173
|
+
setAnnouncement((current) => (current === text ? text + '\u00a0' : text));
|
|
174
|
+
};
|
|
175
|
+
const move = (from, all, origin) => {
|
|
176
|
+
withMotion(() => moveNow(from, all), origin);
|
|
177
|
+
};
|
|
178
|
+
const moveNow = (from, all) => {
|
|
86
179
|
const to = other(from);
|
|
87
180
|
const fromItems = listOf(from);
|
|
88
181
|
const selection = selectionOf(from);
|
|
@@ -91,7 +184,9 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
91
184
|
return;
|
|
92
185
|
setListOf(from)(fromItems.filter((item) => !moving.includes(item)));
|
|
93
186
|
setListOf(to)([...listOf(to), ...moving]);
|
|
187
|
+
crossed.current = moving;
|
|
94
188
|
setSelectionOf(from)(new Set());
|
|
189
|
+
announce(moving.length, to);
|
|
95
190
|
};
|
|
96
191
|
/** Przenosi jeden element między panelami, wstawiając go pod wskazanym indeksem. */
|
|
97
192
|
const transfer = (fromSide, fromIndex, toSide, toIndex) => {
|
|
@@ -103,7 +198,11 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
103
198
|
toItems.splice(toIndex, 0, moved);
|
|
104
199
|
setListOf(fromSide)(fromItems);
|
|
105
200
|
setListOf(toSide)(toItems);
|
|
106
|
-
|
|
201
|
+
if (fromSide !== toSide) {
|
|
202
|
+
crossed.current = [moved];
|
|
203
|
+
announce(1, toSide);
|
|
204
|
+
}
|
|
205
|
+
// Element opuszcza panel - jego zaznaczenie po tamtej stronie przestaje cokolwiek znaczyć.
|
|
107
206
|
const selection = selectionOf(fromSide);
|
|
108
207
|
if (selection.has(moved)) {
|
|
109
208
|
const next = new Set(selection);
|
|
@@ -112,12 +211,12 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
112
211
|
}
|
|
113
212
|
};
|
|
114
213
|
/** Dwuklik: przenosi wyłącznie klikniętą pozycję, niezależnie od zaznaczenia. */
|
|
115
|
-
const moveOne = (from, item) => {
|
|
214
|
+
const moveOne = (from, item, origin) => {
|
|
116
215
|
const index = listOf(from).indexOf(item);
|
|
117
216
|
if (index === -1)
|
|
118
217
|
return;
|
|
119
218
|
const to = other(from);
|
|
120
|
-
transfer(from, index, to, listOf(to).length);
|
|
219
|
+
withMotion(() => transfer(from, index, to, listOf(to).length), origin);
|
|
121
220
|
};
|
|
122
221
|
const onItemKeyDown = (side, index, item, event) => {
|
|
123
222
|
if (event.key === ' ') {
|
|
@@ -127,8 +226,8 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
127
226
|
}
|
|
128
227
|
if (event.key === 'Enter') {
|
|
129
228
|
event.preventDefault();
|
|
130
|
-
moveOne(side, item);
|
|
131
|
-
// Pozycja zniknęła z listy
|
|
229
|
+
moveOne(side, item, event.currentTarget);
|
|
230
|
+
// Pozycja zniknęła z listy - fokus zostaje w tym samym miejscu listy, na następnej.
|
|
132
231
|
focusItem(side, index);
|
|
133
232
|
return;
|
|
134
233
|
}
|
|
@@ -166,20 +265,21 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
166
265
|
clearDrag();
|
|
167
266
|
if (from === null)
|
|
168
267
|
return;
|
|
268
|
+
const origin = event.currentTarget;
|
|
169
269
|
if (from.side !== side) {
|
|
170
|
-
transfer(from.side, from.index, side, index);
|
|
270
|
+
withMotion(() => transfer(from.side, from.index, side, index), origin);
|
|
171
271
|
return;
|
|
172
272
|
}
|
|
173
273
|
if (from.index === index)
|
|
174
274
|
return;
|
|
175
|
-
// Indeks celu liczony na tablicy sprzed usunięcia
|
|
275
|
+
// Indeks celu liczony na tablicy sprzed usunięcia - element ląduje na pozycji tego,
|
|
176
276
|
// na który go upuszczono (ten sam wzór co przestawianie kolumn w KptDataTable).
|
|
177
277
|
const next = [...listOf(side)];
|
|
178
278
|
const [moved] = next.splice(from.index, 1);
|
|
179
279
|
if (moved === undefined)
|
|
180
280
|
return;
|
|
181
281
|
next.splice(index, 0, moved);
|
|
182
|
-
setListOf(side)(next);
|
|
282
|
+
withMotion(() => setListOf(side)(next), origin);
|
|
183
283
|
};
|
|
184
284
|
const onListDragOver = (side, event) => {
|
|
185
285
|
if (drag === null)
|
|
@@ -194,8 +294,9 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
194
294
|
clearDrag();
|
|
195
295
|
if (from === null)
|
|
196
296
|
return;
|
|
297
|
+
const origin = event.currentTarget;
|
|
197
298
|
if (from.side !== side) {
|
|
198
|
-
transfer(from.side, from.index, side, listOf(side).length);
|
|
299
|
+
withMotion(() => transfer(from.side, from.index, side, listOf(side).length), origin);
|
|
199
300
|
return;
|
|
200
301
|
}
|
|
201
302
|
const next = [...listOf(side)];
|
|
@@ -203,16 +304,19 @@ export function KptPickList({ source, defaultSource = EMPTY, onSourceChange, tar
|
|
|
203
304
|
if (moved === undefined)
|
|
204
305
|
return;
|
|
205
306
|
next.push(moved);
|
|
206
|
-
setListOf(side)(next);
|
|
307
|
+
withMotion(() => setListOf(side)(next), origin);
|
|
207
308
|
};
|
|
208
309
|
const column = (side) => {
|
|
209
310
|
const items = listOf(side);
|
|
210
311
|
const selection = selectionOf(side);
|
|
211
|
-
const header = side
|
|
312
|
+
const header = headerOf(side);
|
|
212
313
|
return (_jsxs("div", { className: "kpt-pick-list__col", children: [_jsx("div", { className: "kpt-pick-list__header", children: header }), _jsx("ul", { className: cn('kpt-pick-list__items', listOver === side && 'is-dragover'), role: "listbox", "aria-multiselectable": "true", "aria-label": header, onDragOver: (event) => onListDragOver(side, event), onDragLeave: () => setListOver(null), onDrop: (event) => onListDrop(side, event), children: items.map((item, index) => {
|
|
213
314
|
const dragging = drag?.side === side && drag.index === index;
|
|
214
|
-
return (_jsx("li", {
|
|
315
|
+
return (_jsx("li", { ref: (element) => {
|
|
316
|
+
if (element)
|
|
317
|
+
keyOf.current.set(element, item);
|
|
318
|
+
}, className: cn('kpt-pick-list__item', selection.has(item) && 'is-selected', dragging && 'is-dragging', dragdrop && 'kpt-pick-list__item--draggable', over?.side === side && over.index === index && !dragging && 'kpt-pick-list__item--dragover'), role: "option", "aria-selected": selection.has(item), tabIndex: index === tabIndexOf(side) ? 0 : -1, onFocus: () => setFocusOf(side)(index), onKeyDown: (event) => onItemKeyDown(side, index, item, event), draggable: dragdrop || undefined, onClick: () => toggle(side, item), onDoubleClick: (event) => moveOne(side, item, event.currentTarget), onDragStart: (event) => onDragStart(side, index, event), onDragOver: (event) => onDragOver(side, index, event), onDragLeave: () => setOver(null), onDrop: (event) => onDrop(side, index, event), onDragEnd: clearDrag, children: renderItem(item, index) }, index));
|
|
215
319
|
}) })] }));
|
|
216
320
|
};
|
|
217
|
-
return (
|
|
321
|
+
return (_jsxs("div", { ref: composeRefs(rootRef, ref), className: cn('kpt-pick-list-host', className), ...rest, children: [_jsxs("div", { className: "kpt-pick-list", children: [column('source'), _jsxs("div", { className: "kpt-pick-list__controls", children: [_jsxs("button", { type: "button", "aria-label": t('pickList.moveAllRight'), "aria-disabled": !left.length || undefined, onClick: (event) => move('source', true, event.currentTarget), children: [_jsx(KptIcon, { name: "chevron-right" }), _jsx(KptIcon, { name: "chevron-right" })] }), _jsx("button", { type: "button", "aria-label": t('pickList.moveRight'), "aria-disabled": !selLeft.size || undefined, onClick: (event) => move('source', false, event.currentTarget), children: _jsx(KptIcon, { name: "chevron-right" }) }), _jsx("button", { type: "button", "aria-label": t('pickList.moveLeft'), "aria-disabled": !selRight.size || undefined, onClick: (event) => move('target', false, event.currentTarget), children: _jsx(KptIcon, { name: "chevron-left" }) }), _jsxs("button", { type: "button", "aria-label": t('pickList.moveAllLeft'), "aria-disabled": !right.length || undefined, onClick: (event) => move('target', true, event.currentTarget), children: [_jsx(KptIcon, { name: "chevron-left" }), _jsx(KptIcon, { name: "chevron-left" })] })] }), column('target')] }), _jsx("p", { className: "kpt-visually-hidden", "aria-live": "polite", children: announcement })] }));
|
|
218
322
|
}
|
package/dist/popover/llms.txt
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# KptPopover (@konce-pt/react)
|
|
2
2
|
|
|
3
|
-
Any content in a bubble pinned to its trigger
|
|
3
|
+
Any content in a bubble pinned to its trigger - richer than a tooltip.
|
|
4
4
|
Import: `import { KptPopover } from '@konce-pt/react';`
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<span class="kpt-popover-host">
|
|
8
|
-
<span class="kpt-popover__trigger"
|
|
8
|
+
<span class="kpt-popover__trigger">...trigger...</span>
|
|
9
9
|
</span>
|
|
10
10
|
<!-- while open, in a portal on document.body: -->
|
|
11
|
-
<div class="kpt-popover__panel" role="dialog"
|
|
11
|
+
<div class="kpt-popover__panel" role="dialog">...children...</div>
|
|
12
12
|
|
|
13
13
|
## Props
|
|
14
|
-
- `trigger`: ReactNode
|
|
15
|
-
- `children`: ReactNode
|
|
16
|
-
- `open` / `defaultOpen` / `onOpenChange`
|
|
17
|
-
- `placement`: 'bottom' (default) | 'top'
|
|
14
|
+
- `trigger`: ReactNode - the element that opens the bubble, rendered in place
|
|
15
|
+
- `children`: ReactNode - the panel content
|
|
16
|
+
- `open` / `defaultOpen` / `onOpenChange` - controlled or uncontrolled
|
|
17
|
+
- `placement`: 'bottom' (default) | 'top' - the preferred side; it flips when there is no room
|
|
18
18
|
- `className`, `ref` and every other `<span>` prop go to the host
|
|
19
19
|
|
|
20
20
|
## The panel is a portal
|
|
@@ -22,7 +22,7 @@ The Angular port stands on CDK Overlay. Here the panel renders into a portal on
|
|
|
22
22
|
with the same behaviour: positioned below the trigger, flipping above when there is no room, closed
|
|
23
23
|
by a click outside or by Escape, and following scroll and resize.
|
|
24
24
|
|
|
25
|
-
Clicking the trigger while the bubble is open closes it and does not reopen it
|
|
25
|
+
Clicking the trigger while the bubble is open closes it and does not reopen it - the transparent
|
|
26
26
|
backdrop takes that click, exactly as the CDK backdrop does.
|
|
27
27
|
|
|
28
28
|
## Examples
|
|
@@ -43,7 +43,10 @@ The panel is `role="dialog"` with an `id` the trigger points to.
|
|
|
43
43
|
|
|
44
44
|
## Focus and keyboard
|
|
45
45
|
The control inside the trigger slot gets `aria-haspopup="dialog"`, a live `aria-expanded` and, while
|
|
46
|
-
open, `aria-controls`
|
|
46
|
+
open, `aria-controls` - on the real `<button>`, not on the wrapper. Opening moves focus to the first
|
|
47
47
|
interactive element of the bubble; `Escape` or a click outside closes it, and focus returns to the
|
|
48
|
-
trigger when it was inside the bubble. Focus is not trapped
|
|
48
|
+
trigger when it was inside the bubble. Focus is not trapped - the popover is supporting content, not
|
|
49
49
|
a modal.
|
|
50
|
+
|
|
51
|
+
## Name and Escape
|
|
52
|
+
Give the panel `ariaLabel` - it is a `role="dialog"`. Escape closes only the top-most panel and does not reach an enclosing `<dialog>`, so a popover inside a dialog closes alone.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
2
|
export interface KptPopoverProps extends Omit<ComponentPropsWithRef<'span'>, 'content'> {
|
|
3
|
-
/** Element otwierający dymek
|
|
3
|
+
/** Element otwierający dymek - renderowany w miejscu popovera. */
|
|
4
4
|
trigger: ReactNode;
|
|
5
5
|
/** Treść panelu. */
|
|
6
6
|
children?: ReactNode;
|
|
@@ -9,9 +9,11 @@ export interface KptPopoverProps extends Omit<ComponentPropsWithRef<'span'>, 'co
|
|
|
9
9
|
onOpenChange?: (open: boolean) => void;
|
|
10
10
|
/** Preferowana strona dymka; gdy brakuje miejsca, przechodzi na drugą. */
|
|
11
11
|
placement?: 'bottom' | 'top';
|
|
12
|
+
/** Nazwa panelu (`role="dialog"`) - okno bez nazwy czytnik ogłasza jako samo "okno dialogowe". */
|
|
13
|
+
ariaLabel?: string;
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
|
-
* Popover
|
|
16
|
+
* Popover - dowolna treść w dymku przypiętym do wyzwalacza (bogatszy niż tooltip).
|
|
15
17
|
*
|
|
16
18
|
* Port Angulara stoi na CDK Overlay; tutaj panel renderuje się w portalu do `document.body`,
|
|
17
19
|
* z tym samym zachowaniem: pozycja pod wyzwalaczem (albo nad nim przy `placement="top"`)
|
|
@@ -23,7 +25,7 @@ export interface KptPopoverProps extends Omit<ComponentPropsWithRef<'span'>, 'co
|
|
|
23
25
|
*
|
|
24
26
|
* @example
|
|
25
27
|
* <KptPopover trigger={<KptButton variant="outline">Szczegóły</KptButton>}>
|
|
26
|
-
* <div>Bogata treść popovera
|
|
28
|
+
* <div>Bogata treść popovera...</div>
|
|
27
29
|
* </KptPopover>
|
|
28
30
|
*/
|
|
29
|
-
export declare function KptPopover({ trigger, children, open, defaultOpen, onOpenChange, placement, className, ...rest }: Readonly<KptPopoverProps>): import("react").JSX.Element;
|
|
31
|
+
export declare function KptPopover({ trigger, children, open, defaultOpen, onOpenChange, placement, ariaLabel, className, ...rest }: Readonly<KptPopoverProps>): import("react").JSX.Element;
|
package/dist/popover/popover.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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";
|
|
6
7
|
import { useKptId } from "../internal/use-id.js";
|
|
7
|
-
/** Elementy, które same przyjmują fokus
|
|
8
|
+
/** Elementy, które same przyjmują fokus - pierwszy z nich dostaje fokus po otwarciu dymka. */
|
|
8
9
|
const FOCUSABLE = 'a[href], button:not(:disabled), input:not(:disabled), select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
9
10
|
/**
|
|
10
|
-
* Popover
|
|
11
|
+
* Popover - dowolna treść w dymku przypiętym do wyzwalacza (bogatszy niż tooltip).
|
|
11
12
|
*
|
|
12
13
|
* Port Angulara stoi na CDK Overlay; tutaj panel renderuje się w portalu do `document.body`,
|
|
13
14
|
* z tym samym zachowaniem: pozycja pod wyzwalaczem (albo nad nim przy `placement="top"`)
|
|
@@ -19,11 +20,17 @@ const FOCUSABLE = 'a[href], button:not(:disabled), input:not(:disabled), select,
|
|
|
19
20
|
*
|
|
20
21
|
* @example
|
|
21
22
|
* <KptPopover trigger={<KptButton variant="outline">Szczegóły</KptButton>}>
|
|
22
|
-
* <div>Bogata treść popovera
|
|
23
|
+
* <div>Bogata treść popovera...</div>
|
|
23
24
|
* </KptPopover>
|
|
24
25
|
*/
|
|
25
|
-
export function KptPopover({ trigger, children, open, defaultOpen = false, onOpenChange, placement = 'bottom', className, ...rest }) {
|
|
26
|
+
export function KptPopover({ trigger, children, open, defaultOpen = false, onOpenChange, placement = 'bottom', ariaLabel = '', className, ...rest }) {
|
|
26
27
|
const triggerRef = useRef(null);
|
|
28
|
+
/** Kotwica panelu - w stanie, bo czyta ją render; ref zostaje dla handlerów. */
|
|
29
|
+
const [anchor, setAnchor] = useState(null);
|
|
30
|
+
const setTrigger = useCallback((element) => {
|
|
31
|
+
triggerRef.current = element;
|
|
32
|
+
setAnchor(element);
|
|
33
|
+
}, []);
|
|
27
34
|
const panelRef = useRef(null);
|
|
28
35
|
const panelId = useKptId(undefined, 'kpt-popover');
|
|
29
36
|
const [isOpen, setOpen] = useControllableState({
|
|
@@ -44,7 +51,7 @@ export function KptPopover({ trigger, children, open, defaultOpen = false, onOpe
|
|
|
44
51
|
else
|
|
45
52
|
control.removeAttribute('aria-controls');
|
|
46
53
|
}, [isOpen, trigger, panelId]);
|
|
47
|
-
// Fokus do dymka klatkę później
|
|
54
|
+
// Fokus do dymka klatkę później - `KptOverlay` trzyma panel niewidoczny, dopóki go nie zmierzy.
|
|
48
55
|
useEffect(() => {
|
|
49
56
|
if (!isOpen)
|
|
50
57
|
return;
|
|
@@ -58,5 +65,5 @@ export function KptPopover({ trigger, children, open, defaultOpen = false, onOpe
|
|
|
58
65
|
findControl()?.focus();
|
|
59
66
|
setOpen(false);
|
|
60
67
|
}, [setOpen]);
|
|
61
|
-
return (_jsxs("span", { className: cn('kpt-popover-host', className), ...rest, children: [_jsx("span", { className: "kpt-popover__trigger", ref:
|
|
68
|
+
return (_jsxs("span", { className: cn('kpt-popover-host', className), ...rest, children: [_jsx("span", { className: "kpt-popover__trigger", ref: setTrigger, onClick: () => setOpen(!isOpen), children: trigger }), _jsx(KptOverlay, { open: isOpen, anchor: anchor, onClose: close, offset: 6, preferAbove: placement === 'top', children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-popover__panel", role: "dialog", "aria-label": ariaLabel || undefined, children: children }) })] }));
|
|
62
69
|
}
|
package/dist/progress/llms.txt
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# KptProgress (@konce-pt/react)
|
|
2
2
|
|
|
3
|
-
A progress indicator
|
|
3
|
+
A progress indicator - linear or circular, determinate (`min`-`max`) or indeterminate (`value` = null).
|
|
4
4
|
Import: `import { KptProgress } from '@konce-pt/react';`
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<!-- linear, with a label, a buffer and a value -->
|
|
8
8
|
<div class="kpt-progress-host" data-type="linear" data-size="md" data-variant="primary" data-label-position="top">
|
|
9
|
-
<span class="kpt-progress__label">Loading
|
|
9
|
+
<span class="kpt-progress__label">Loading...</span>
|
|
10
10
|
<div class="kpt-progress__linear" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="80">
|
|
11
11
|
<div class="kpt-progress__buffer" style="width: 92%"></div>
|
|
12
12
|
<div class="kpt-progress__bar" style="width: 80%"></div>
|
|
@@ -23,28 +23,28 @@ Import: `import { KptProgress } from '@konce-pt/react';`
|
|
|
23
23
|
<span class="kpt-progress__value" aria-hidden="true">75%</span>
|
|
24
24
|
</div>
|
|
25
25
|
|
|
26
|
-
The label, the track and the value are siblings straight under the host
|
|
26
|
+
The label, the track and the value are siblings straight under the host - there is no wrapper element.
|
|
27
27
|
`data-variant`, `data-type`, `data-size` and `data-label-position` all sit on the host, which is also
|
|
28
28
|
where the private `--_color` and `--_thickness` are resolved. This markup matches the Angular port
|
|
29
29
|
element for element, so both share one stylesheet.
|
|
30
30
|
|
|
31
31
|
## Props
|
|
32
|
-
- `value`: number | null (default null)
|
|
32
|
+
- `value`: number | null (default null) - a value on the `min`-`max` scale, or null for indeterminate
|
|
33
33
|
- `min`: number (default 0); `max`: number (default 100)
|
|
34
34
|
- `variant`: 'primary' | 'success' | 'danger' | 'warning' | 'info' (default 'primary')
|
|
35
35
|
- `type`: 'linear' | 'circular' (default 'linear')
|
|
36
|
-
- `size`: 'sm' | 'md' | 'lg' (default 'md')
|
|
37
|
-
- `diameter`: number (default 40)
|
|
38
|
-
- `bufferValue`: number | null (default null)
|
|
39
|
-
- `showValue`: boolean (default false)
|
|
36
|
+
- `size`: 'sm' | 'md' | 'lg' (default 'md') - track thickness, and arc width on the circular variant
|
|
37
|
+
- `diameter`: number (default 40) - the circular variant's size in pixels
|
|
38
|
+
- `bufferValue`: number | null (default null) - a second, dimmed bar behind the main one; linear only
|
|
39
|
+
- `showValue`: boolean (default false) - turns the value area on; `children` needs it too
|
|
40
40
|
- `valueFormat`: 'percent' | 'fraction' | 'none' (default 'percent')
|
|
41
|
-
- `label`: string
|
|
42
|
-
- `labelPosition`: 'top' | 'bottom' | 'end' (default 'top')
|
|
43
|
-
- `locale`, `dictionary`
|
|
41
|
+
- `label`: string - descriptive text next to the bar; it also becomes the `aria-label`
|
|
42
|
+
- `labelPosition`: 'top' | 'bottom' | 'end' (default 'top') - ignored by the circular variant
|
|
43
|
+
- `locale`, `dictionary` - per-instance dictionary overrides
|
|
44
44
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
45
45
|
|
|
46
46
|
## Value label
|
|
47
|
-
`showValue` opens the value area; `valueFormat` decides what goes in it
|
|
47
|
+
`showValue` opens the value area; `valueFormat` decides what goes in it - `percent` renders `80%`,
|
|
48
48
|
`fraction` renders `152 / 160` from `value` and `max`, `none` leaves it empty. Both strings come from
|
|
49
49
|
the `KptMessages` dictionary (`progress.percent`, `progress.fraction`), so a new locale can reshape them.
|
|
50
50
|
|
|
@@ -57,17 +57,17 @@ the accessible name.
|
|
|
57
57
|
|
|
58
58
|
## How the arc is drawn
|
|
59
59
|
The circle lives in a fixed `viewBox="0 0 40 40"` with `r=16`, so the circumference is computed from
|
|
60
|
-
that radius, not from `diameter`
|
|
60
|
+
that radius, not from `diameter` - the SVG scales, the maths does not change. The arc is the dash
|
|
61
61
|
offset: full circumference means empty, zero means complete. `size` only changes `stroke-width`, and
|
|
62
62
|
the widest step still fits inside the box, so no arc is ever clipped.
|
|
63
63
|
|
|
64
|
-
Values outside the range are clamped rather than rejected, `max`
|
|
65
|
-
buffer is never allowed behind the main bar
|
|
64
|
+
Values outside the range are clamped rather than rejected, `max` <= `min` collapses to zero, and the
|
|
65
|
+
buffer is never allowed behind the main bar - a computed percentage that briefly overshoots cannot
|
|
66
66
|
break the drawing.
|
|
67
67
|
|
|
68
68
|
## Examples
|
|
69
69
|
<KptProgress value={60} />
|
|
70
|
-
<KptProgress value={80} label="Loading
|
|
70
|
+
<KptProgress value={80} label="Loading..." showValue />
|
|
71
71
|
<KptProgress value={152} max={160} size="lg" showValue valueFormat="fraction" labelPosition="bottom" />
|
|
72
72
|
<KptProgress value={65} showValue labelPosition="end" />
|
|
73
73
|
<KptProgress value={38} bufferValue={62} />
|
|
@@ -91,5 +91,5 @@ leaves the value out, which is how a screen reader learns the progress is unknow
|
|
|
91
91
|
announcing the raw number as a percentage. The visible value is `aria-hidden`, so it is never read
|
|
92
92
|
twice. The accessible name comes from `label`, or from the dictionary when there is none.
|
|
93
93
|
|
|
94
|
-
Under `prefers-reduced-motion: reduce` the indeterminate animation slows down instead of stopping
|
|
94
|
+
Under `prefers-reduced-motion: reduce` the indeterminate animation slows down instead of stopping -
|
|
95
95
|
a frozen progress indicator reads as a hung application.
|
|
@@ -3,12 +3,12 @@ import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
|
3
3
|
export type KptProgressVariant = 'primary' | 'success' | 'danger' | 'warning' | 'info';
|
|
4
4
|
export type KptProgressType = 'linear' | 'circular';
|
|
5
5
|
export type KptProgressSize = 'sm' | 'md' | 'lg';
|
|
6
|
-
/** Postać etykiety wartości: procent,
|
|
6
|
+
/** Postać etykiety wartości: procent, "ile z ilu" albo brak. */
|
|
7
7
|
export type KptProgressValueFormat = 'percent' | 'fraction' | 'none';
|
|
8
8
|
/** Gdzie siada wiersz etykiety względem paska (tylko `type="linear"`). */
|
|
9
9
|
export type KptProgressLabelPosition = 'top' | 'bottom' | 'end';
|
|
10
10
|
export interface KptProgressProps extends ComponentPropsWithRef<'div'>, KptI18nOverrides {
|
|
11
|
-
/** Wartość w skali `min
|
|
11
|
+
/** Wartość w skali `min`-`max` albo `null` = postęp nieokreślony. */
|
|
12
12
|
value?: number | null;
|
|
13
13
|
min?: number;
|
|
14
14
|
max?: number;
|
|
@@ -18,26 +18,26 @@ export interface KptProgressProps extends ComponentPropsWithRef<'div'>, KptI18nO
|
|
|
18
18
|
size?: KptProgressSize;
|
|
19
19
|
/** Średnica wariantu kołowego w pikselach. */
|
|
20
20
|
diameter?: number;
|
|
21
|
-
/** Postęp buforowania
|
|
21
|
+
/** Postęp buforowania - drugi, przygaszony pasek pod głównym (tylko liniowy). */
|
|
22
22
|
bufferValue?: number | null;
|
|
23
|
-
/** Włącza obszar etykiety wartości
|
|
23
|
+
/** Włącza obszar etykiety wartości - razem z nim renderuje się `children`. */
|
|
24
24
|
showValue?: boolean;
|
|
25
25
|
valueFormat?: KptProgressValueFormat;
|
|
26
26
|
/** Tekst opisowy obok paska; służy też za `aria-label`. */
|
|
27
27
|
label?: string;
|
|
28
28
|
labelPosition?: KptProgressLabelPosition;
|
|
29
|
-
/** Zastępuje sformatowaną wartość
|
|
29
|
+
/** Zastępuje sformatowaną wartość - wymaga `showValue`. */
|
|
30
30
|
children?: ReactNode;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Wskaźnik postępu
|
|
33
|
+
* Wskaźnik postępu - liniowy lub kołowy, określony (`min`-`max`) albo nieokreślony (`value` = null).
|
|
34
34
|
*
|
|
35
35
|
* Etykietę wartości włącza `showValue`; `children` zastępuje sformatowaną wartość,
|
|
36
36
|
* więc w środku koła można pokazać cokolwiek.
|
|
37
37
|
*
|
|
38
38
|
* @example
|
|
39
39
|
* <KptProgress value={60} />
|
|
40
|
-
* <KptProgress value={80} label="Ładowanie
|
|
40
|
+
* <KptProgress value={80} label="Ładowanie..." showValue />
|
|
41
41
|
* <KptProgress value={152} max={160} showValue valueFormat="fraction" labelPosition="bottom" />
|
|
42
42
|
* <KptProgress value={38} bufferValue={62} />
|
|
43
43
|
* <KptProgress type="circular" value={75} variant="success" showValue />
|