@konce-pt/react 0.12.0 → 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 +122 -64
- package/dist/accordion/accordion.d.ts +14 -6
- package/dist/accordion/accordion.js +14 -7
- package/dist/accordion/llms.txt +22 -10
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert/alert.js +2 -2
- package/dist/alert/llms.txt +10 -10
- package/dist/app-shell/app-shell.d.ts +14 -14
- package/dist/app-shell/app-shell.js +11 -11
- package/dist/app-shell/llms.txt +13 -13
- package/dist/auth/auth-types.d.ts +6 -6
- package/dist/auth/auth.d.ts +2 -2
- package/dist/auth/auth.js +7 -7
- package/dist/auth/llms.txt +9 -9
- package/dist/autocomplete/autocomplete.d.ts +19 -6
- package/dist/autocomplete/autocomplete.js +23 -10
- package/dist/autocomplete/llms.txt +16 -5
- package/dist/avatar/avatar.d.ts +6 -6
- package/dist/avatar/avatar.js +5 -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 +3 -3
- package/dist/avatar-group/llms.txt +8 -8
- package/dist/backdrop/backdrop.d.ts +7 -7
- package/dist/backdrop/backdrop.js +16 -16
- 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 +4 -4
- package/dist/bottom-sheet/bottom-sheet.js +2 -2
- package/dist/bottom-sheet/llms.txt +9 -9
- package/dist/breadcrumb/breadcrumb.d.ts +2 -2
- package/dist/breadcrumb/breadcrumb.js +3 -3
- package/dist/breadcrumb/llms.txt +3 -3
- package/dist/button/button.d.ts +3 -3
- package/dist/button/button.js +8 -8
- package/dist/button/llms.txt +27 -19
- package/dist/button-group/button-group.d.ts +9 -9
- package/dist/button-group/button-group.js +30 -8
- package/dist/button-group/llms.txt +20 -14
- package/dist/card/card.d.ts +8 -8
- package/dist/card/card.js +6 -6
- package/dist/card/llms.txt +20 -20
- package/dist/carousel/carousel.d.ts +6 -6
- package/dist/carousel/carousel.js +4 -4
- package/dist/carousel/llms.txt +10 -10
- package/dist/charts/chart-legend.d.ts +3 -3
- package/dist/charts/chart-legend.js +1 -1
- package/dist/charts/chart-tooltip.d.ts +3 -3
- package/dist/charts/chart-tooltip.js +1 -1
- package/dist/charts/chart.d.ts +1 -1
- package/dist/charts/chart.js +8 -8
- package/dist/charts/llms.txt +6 -6
- package/dist/charts-entry/public-api.js +2 -2
- package/dist/chat/chat.d.ts +17 -10
- package/dist/chat/chat.js +42 -18
- package/dist/chat/llms.txt +32 -17
- package/dist/chat-composer/chat-composer.d.ts +17 -7
- package/dist/chat-composer/chat-composer.js +21 -8
- 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 +9 -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 +17 -7
- 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 +3 -3
- package/dist/chat-typing/llms.txt +6 -6
- package/dist/checkbox/checkbox.d.ts +13 -6
- package/dist/checkbox/checkbox.js +26 -7
- package/dist/checkbox/llms.txt +24 -12
- package/dist/chip/chip.d.ts +4 -4
- package/dist/chip/chip.js +2 -2
- package/dist/chip/llms.txt +11 -11
- package/dist/chips-input/chips-input.d.ts +4 -4
- package/dist/chips-input/chips-input.js +35 -9
- package/dist/chips-input/llms.txt +15 -8
- package/dist/clock/clock.d.ts +4 -4
- package/dist/clock/clock.js +7 -7
- package/dist/clock/llms.txt +8 -8
- package/dist/color-picker/color-picker.d.ts +6 -6
- package/dist/color-picker/color-picker.js +3 -3
- package/dist/color-picker/llms.txt +5 -5
- package/dist/confirm/confirm-container.d.ts +3 -3
- package/dist/confirm/confirm-container.js +5 -5
- package/dist/confirm/confirm-store.d.ts +4 -4
- package/dist/confirm/confirm-store.js +7 -7
- package/dist/confirm/llms.txt +6 -6
- package/dist/context-menu/context-menu.d.ts +1 -1
- package/dist/context-menu/context-menu.js +5 -5
- package/dist/context-menu/llms.txt +7 -7
- package/dist/data-table/data-table-types.d.ts +5 -5
- package/dist/data-table/data-table.d.ts +29 -8
- package/dist/data-table/data-table.js +340 -95
- package/dist/data-table/export-csv.d.ts +3 -3
- package/dist/data-table/export-csv.js +4 -4
- package/dist/data-table/llms.txt +127 -94
- package/dist/data-view/data-view.d.ts +13 -5
- package/dist/data-view/data-view.js +67 -6
- package/dist/data-view/llms.txt +29 -10
- package/dist/date-range/date-range.d.ts +9 -9
- package/dist/date-range/date-range.js +24 -24
- package/dist/date-range/llms.txt +20 -20
- package/dist/datepicker/datepicker.d.ts +10 -10
- package/dist/datepicker/datepicker.js +29 -29
- package/dist/datepicker/llms.txt +24 -24
- package/dist/dialog/dialog.d.ts +4 -4
- package/dist/dialog/dialog.js +4 -4
- package/dist/dialog/llms.txt +11 -11
- package/dist/divider/divider.d.ts +1 -1
- package/dist/divider/llms.txt +4 -4
- package/dist/drawer/drawer.d.ts +5 -5
- package/dist/drawer/drawer.js +2 -2
- package/dist/drawer/llms.txt +11 -11
- 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 +9 -6
- package/dist/fieldset/llms.txt +26 -9
- package/dist/file-upload/file-upload.d.ts +3 -3
- package/dist/file-upload/file-upload.js +7 -7
- package/dist/file-upload/llms.txt +7 -7
- 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 +26 -6
- package/dist/form-field/llms.txt +25 -11
- package/dist/galleria/galleria.d.ts +3 -3
- package/dist/galleria/galleria.js +5 -5
- 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 +3 -3
- package/dist/i18n/i18n-context.js +7 -7
- 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 +6 -6
- 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 +1 -1
- package/dist/image/llms.txt +13 -13
- package/dist/input/input.d.ts +18 -5
- package/dist/input/input.js +21 -6
- package/dist/input/llms.txt +25 -11
- package/dist/input-mask/input-mask.d.ts +1 -1
- package/dist/input-mask/input-mask.js +2 -2
- package/dist/input-mask/llms.txt +5 -5
- package/dist/input-number/input-number.d.ts +9 -9
- package/dist/input-number/input-number.js +11 -11
- package/dist/input-number/llms.txt +14 -14
- package/dist/input-otp/input-otp.d.ts +6 -6
- package/dist/input-otp/input-otp.js +10 -10
- package/dist/input-otp/llms.txt +9 -9
- 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 +2 -2
- package/dist/internal/mask.js +4 -4
- package/dist/internal/option-key.d.ts +2 -2
- package/dist/internal/option-key.js +2 -2
- 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 +8 -8
- package/dist/internal/password-strength.d.ts +2 -2
- package/dist/internal/password-strength.js +6 -6
- package/dist/internal/roving.d.ts +2 -2
- package/dist/internal/roving.js +3 -3
- package/dist/internal/scroll-lock.d.ts +1 -1
- package/dist/internal/scroll-lock.js +2 -2
- package/dist/internal/slot-children.d.ts +3 -3
- package/dist/internal/slot-children.js +4 -4
- package/dist/internal/slot.d.ts +3 -3
- package/dist/internal/slot.js +2 -2
- package/dist/internal/step.d.ts +3 -3
- package/dist/internal/step.js +4 -4
- package/dist/internal/tween.d.ts +5 -5
- package/dist/internal/tween.js +5 -5
- 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 +1 -1
- package/dist/internal/use-controllable-state.js +3 -3
- 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 +1 -1
- package/dist/internal/use-modal-focus.js +3 -3
- package/dist/knob/knob.d.ts +4 -4
- package/dist/knob/knob.js +14 -10
- package/dist/knob/llms.txt +17 -12
- package/dist/listbox/listbox.d.ts +6 -6
- package/dist/listbox/listbox.js +9 -9
- package/dist/listbox/llms.txt +10 -10
- 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 +25 -22
- package/dist/map/map-create-dialog.d.ts +4 -4
- package/dist/map/map-create-dialog.js +10 -10
- package/dist/map/map-hours-field.d.ts +4 -4
- package/dist/map/map-hours-field.js +7 -7
- package/dist/map/map-image-field.d.ts +2 -2
- package/dist/map/map-image-field.js +4 -4
- package/dist/map/map-legend.d.ts +4 -4
- package/dist/map/map-legend.js +2 -2
- package/dist/map/map-poi-card.d.ts +3 -3
- package/dist/map/map-poi-card.js +9 -9
- package/dist/map/map-search.d.ts +17 -6
- package/dist/map/map-search.js +21 -18
- package/dist/map/map.d.ts +21 -14
- package/dist/map/map.js +30 -29
- 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 +9 -9
- package/dist/megamenu/megamenu.d.ts +6 -6
- package/dist/megamenu/megamenu.js +10 -10
- 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.d.ts +2 -2
- package/dist/menu/menu.js +6 -6
- package/dist/menubar/llms.txt +10 -10
- package/dist/menubar/menubar.d.ts +5 -5
- package/dist/menubar/menubar.js +10 -10
- 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 +1 -1
- package/dist/motion/motion-context.d.ts +22 -0
- package/dist/motion/motion-context.js +28 -0
- package/dist/order-list/llms.txt +22 -10
- package/dist/order-list/order-list.d.ts +12 -4
- package/dist/order-list/order-list.js +104 -21
- package/dist/paginator/llms.txt +8 -8
- package/dist/paginator/paginator.js +1 -1
- package/dist/panel/llms.txt +25 -13
- package/dist/panel/panel.d.ts +11 -3
- package/dist/panel/panel.js +7 -4
- package/dist/password/llms.txt +16 -8
- package/dist/password/password.d.ts +2 -2
- package/dist/password/password.js +24 -3
- package/dist/peek/llms.txt +10 -10
- package/dist/peek/peek.d.ts +6 -6
- package/dist/peek/peek.js +7 -7
- package/dist/pick-list/llms.txt +33 -13
- package/dist/pick-list/pick-list.d.ts +12 -4
- package/dist/pick-list/pick-list.js +111 -23
- package/dist/popover/llms.txt +11 -11
- package/dist/popover/popover.d.ts +4 -4
- package/dist/popover/popover.js +5 -5
- package/dist/progress/llms.txt +17 -17
- package/dist/progress/progress.d.ts +7 -7
- package/dist/progress/progress.js +6 -6
- package/dist/public-api.d.ts +15 -3
- package/dist/public-api.js +13 -7
- package/dist/radio-group/llms.txt +13 -6
- package/dist/radio-group/radio-group.d.ts +11 -4
- package/dist/radio-group/radio-group.js +15 -7
- 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 +76 -12
- package/dist/rich-text/lists.d.ts +2 -2
- package/dist/rich-text/lists.js +7 -7
- package/dist/rich-text/llms.txt +26 -17
- package/dist/rich-text/rich-text.d.ts +12 -7
- package/dist/rich-text/rich-text.js +78 -54
- package/dist/rich-text/sanitize.d.ts +3 -3
- package/dist/rich-text/sanitize.js +12 -12
- package/dist/rich-text/tables.d.ts +3 -3
- package/dist/rich-text/tables.js +3 -3
- package/dist/roadmap/llms.txt +15 -15
- package/dist/roadmap/roadmap.d.ts +6 -6
- package/dist/roadmap/roadmap.js +19 -19
- 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 +1 -1
- package/dist/select/llms.txt +19 -12
- package/dist/select/select.d.ts +8 -8
- package/dist/select/select.js +47 -21
- package/dist/shared/types.d.ts +5 -5
- package/dist/shared/types.js +1 -1
- package/dist/sidenav/llms.txt +9 -9
- package/dist/sidenav/sidenav.d.ts +1 -1
- package/dist/sidenav/sidenav.js +1 -1
- 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 +32 -13
- package/dist/slider/slider-drag.d.ts +26 -0
- package/dist/slider/slider-drag.js +79 -0
- package/dist/slider/slider.d.ts +6 -5
- package/dist/slider/slider.js +27 -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 +1 -1
- package/dist/spinner/llms.txt +7 -7
- package/dist/spinner/spinner.d.ts +1 -1
- package/dist/spinner/spinner.js +1 -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 +4 -4
- package/dist/splitter/llms.txt +11 -11
- package/dist/splitter/splitter.d.ts +3 -3
- package/dist/splitter/splitter.js +5 -5
- package/dist/stepper/llms.txt +33 -14
- package/dist/stepper/stepper.d.ts +6 -6
- package/dist/stepper/stepper.js +53 -10
- package/dist/switch/llms.txt +12 -5
- package/dist/switch/switch.d.ts +10 -3
- package/dist/switch/switch.js +12 -5
- package/dist/switch-group/llms.txt +9 -9
- package/dist/switch-group/switch-group.d.ts +4 -4
- package/dist/switch-group/switch-group.js +4 -4
- package/dist/tabs/llms.txt +10 -10
- package/dist/tabs/tabs.d.ts +5 -5
- package/dist/tabs/tabs.js +8 -8
- package/dist/textarea/llms.txt +23 -12
- package/dist/textarea/textarea.d.ts +19 -6
- package/dist/textarea/textarea.js +21 -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 +47 -17
- package/dist/toast/toast-container.d.ts +9 -3
- package/dist/toast/toast-container.js +17 -9
- package/dist/toast/toast-store.d.ts +40 -4
- 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 +10 -10
- package/dist/tooltip/tooltip.d.ts +3 -3
- package/dist/tooltip/tooltip.js +18 -18
- package/dist/tree/llms.txt +25 -12
- package/dist/tree/tree-keys.d.ts +5 -5
- package/dist/tree/tree-keys.js +7 -7
- package/dist/tree/tree.d.ts +14 -7
- package/dist/tree/tree.js +53 -18
- 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 +15 -13
package/dist/tooltip/llms.txt
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
# KptTooltip (@konce-pt/react)
|
|
2
2
|
|
|
3
|
-
A tooltip shown on hover and focus. Light
|
|
3
|
+
A tooltip shown on hover and focus. Light - the element is appended to `body` and positioned
|
|
4
4
|
against the child. Import: `import { KptTooltip } from '@konce-pt/react';`
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
|
-
The component renders NO wrapper of its own
|
|
7
|
+
The component renders NO wrapper of its own - it clones the child and attaches the handlers and a
|
|
8
8
|
ref to it, so the tree stays exactly as it would be without the tooltip. This is the port of the
|
|
9
9
|
`[kptTooltip]` directive, which likewise added nothing to the DOM.
|
|
10
10
|
|
|
11
11
|
<!-- while visible, appended to body: -->
|
|
12
|
-
<div class="kpt-tooltip" role="tooltip" style="position: fixed;
|
|
12
|
+
<div class="kpt-tooltip" role="tooltip" style="position: fixed; ...">Save changes</div>
|
|
13
13
|
|
|
14
14
|
## Props
|
|
15
|
-
- `text`: string
|
|
15
|
+
- `text`: string - the bubble content; empty text disables the tooltip
|
|
16
16
|
- `position`: 'top' | 'bottom' | 'left' | 'right' (default 'top')
|
|
17
|
-
- `onlyWhenTruncated`: boolean
|
|
18
|
-
- `children`
|
|
17
|
+
- `onlyWhenTruncated`: boolean - show it only when the content does not fit
|
|
18
|
+
- `children` - exactly one element, the one that gets hover and focus
|
|
19
19
|
|
|
20
20
|
## onlyWhenTruncated
|
|
21
21
|
The check runs at hover time, not at render, so the result is always current after a width or zoom
|
|
22
22
|
change, with no observers. It measures the host AND its direct children, because
|
|
23
|
-
`text-overflow: ellipsis` usually sits on an inner element
|
|
23
|
+
`text-overflow: ellipsis` usually sits on an inner element - and such an element shrinks to the
|
|
24
24
|
available width instead of stretching its parent, so measuring the host alone would find nothing.
|
|
25
25
|
|
|
26
26
|
## Styling
|
|
@@ -44,8 +44,8 @@ The bubble is created outside React's tree, so its look comes from `.kpt-tooltip
|
|
|
44
44
|
the tooltip) and with `onlyWhenTruncated`, where the text is already in the DOM; the visible
|
|
45
45
|
bubble is then `aria-hidden`.
|
|
46
46
|
- `Escape` closes the bubble, and the pointer can move onto it without it disappearing (a 120 ms
|
|
47
|
-
grace period)
|
|
48
|
-
- It does NOT replace an accessible name
|
|
47
|
+
grace period) - WCAG 1.4.13.
|
|
48
|
+
- It does NOT replace an accessible name - an icon-only button still needs its own label.
|
|
49
49
|
|
|
50
50
|
## Styling and the top layer
|
|
51
|
-
The bubble is styled by `.kpt-tooltip` from `@konce-pt/styles`, in the `kpt.components` layer
|
|
51
|
+
The bubble is styled by `.kpt-tooltip` from `@konce-pt/styles`, in the `kpt.components` layer - override it from your own CSS without `!important`; only `position: fixed` and the coordinates stay inline. Inside an open `<dialog>` or popover the bubble is attached to that element, because a modal dialog lives in the top layer and anything outside it is hidden behind it regardless of `z-index`. A hover shows the bubble after 300 ms (sliding across a toolbar does not light every icon); focus shows it at once. Changing the text while the bubble is visible updates it.
|
|
@@ -9,11 +9,11 @@ export interface KptTooltipProps {
|
|
|
9
9
|
* Dzięki temu podpowiedź nie powtarza tekstu, który i tak widać.
|
|
10
10
|
*/
|
|
11
11
|
onlyWhenTruncated?: boolean;
|
|
12
|
-
/** Dokładnie jeden element
|
|
12
|
+
/** Dokładnie jeden element - to on dostaje obsługę hovera i fokusu. */
|
|
13
13
|
children: ReactNode;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Dymek podpowiedzi pokazywany na hover i focus. Lekki
|
|
16
|
+
* Dymek podpowiedzi pokazywany na hover i focus. Lekki - element dodawany do `body` (albo do
|
|
17
17
|
* otwartego `<dialog>`/popovera dziecka, żeby był widoczny w warstwie szczytowej) i pozycjonowany
|
|
18
18
|
* względem dziecka. Wygląd daje klasa `.kpt-tooltip` z `@konce-pt/styles` w warstwie `kpt.components`.
|
|
19
19
|
*
|
|
@@ -21,7 +21,7 @@ export interface KptTooltipProps {
|
|
|
21
21
|
* i ref do przekazanego elementu, więc drzewo DOM zostaje takie samo jak bez tooltipa.
|
|
22
22
|
*
|
|
23
23
|
* Dostępność (jak w porcie Angulara): tekst trafia do czytników przez trwały, ukryty opis
|
|
24
|
-
* powiązany `aria-describedby` z elementem przyjmującym fokus
|
|
24
|
+
* powiązany `aria-describedby` z elementem przyjmującym fokus - pomijany, gdy powtarzałby
|
|
25
25
|
* jego nazwę albo przy `onlyWhenTruncated`. `Escape` zamyka dymek, a wskaźnik może na niego
|
|
26
26
|
* przejść bez zniknięcia (WCAG 1.4.13).
|
|
27
27
|
*
|
package/dist/tooltip/tooltip.js
CHANGED
|
@@ -3,24 +3,24 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { cloneElement, isValidElement, useCallback, useEffect, useId, useRef } from 'react';
|
|
4
4
|
import { composeRefs } from "../internal/compose-refs.js";
|
|
5
5
|
import { isDevBuild } from "../internal/dev.js";
|
|
6
|
-
/** Elementy, które same przyjmują fokus
|
|
6
|
+
/** Elementy, które same przyjmują fokus - na nie trafia `aria-describedby`. */
|
|
7
7
|
const FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
8
8
|
/** Ile czasu ma wskaźnik na przejście z elementu na dymek, zanim ten zniknie (WCAG 1.4.13). */
|
|
9
9
|
const HIDE_DELAY_MS = 120;
|
|
10
10
|
/**
|
|
11
|
-
* Zwłoka pokazania pod wskaźnikiem
|
|
11
|
+
* Zwłoka pokazania pod wskaźnikiem - przejazd myszą po pasku ikon nie zapala po kolei wszystkich
|
|
12
12
|
* dymków. Fokus z klawiatury pokazuje dymek od razu.
|
|
13
13
|
*/
|
|
14
14
|
const SHOW_DELAY_MS = 300;
|
|
15
15
|
/**
|
|
16
16
|
* Gdzie dokleić dymek: do najbliższego otwartego `<dialog>` albo popovera hosta, inaczej do `body`.
|
|
17
|
-
* Modalny `<dialog>` leży w warstwie szczytowej
|
|
17
|
+
* Modalny `<dialog>` leży w warstwie szczytowej - dymek z `body` byłby pod nim niewidoczny.
|
|
18
18
|
* Bliźniak w porcie Angulara.
|
|
19
19
|
*/
|
|
20
20
|
function tooltipContainer(host) {
|
|
21
21
|
return host.closest('dialog[open], [popover]') ?? host.ownerDocument.body;
|
|
22
22
|
}
|
|
23
|
-
/** Strona przeciwna i dwie boczne
|
|
23
|
+
/** Strona przeciwna i dwie boczne - kolejność prób, gdy zadana strona się nie nadaje. */
|
|
24
24
|
const FALLBACKS = {
|
|
25
25
|
top: ['top', 'bottom', 'right', 'left'],
|
|
26
26
|
bottom: ['bottom', 'top', 'right', 'left'],
|
|
@@ -30,10 +30,10 @@ const FALLBACKS = {
|
|
|
30
30
|
/**
|
|
31
31
|
* Ustawia dymek przy hoście, na pierwszej stronie z `FALLBACKS`, która się nadaje: dymek mieści się
|
|
32
32
|
* w oknie, a krawędź hosta od tej strony nie jest niczym przykryta (przyklejony nagłówek, menu, panel
|
|
33
|
-
*
|
|
33
|
+
* - sprawdzane `elementFromPoint` tuż przy krawędzi). Bez tego dymek przycisku wsuniętego pod
|
|
34
34
|
* nagłówek wyskakiwał nad nagłówkiem, odcięty od tego, co opisuje. Gdy żadna strona się nie nadaje,
|
|
35
35
|
* zostaje zadana. Na koniec dymek jest dociśnięty do okna z marginesem 4 px.
|
|
36
|
-
* Bliźniak tej funkcji żyje w drugim porcie
|
|
36
|
+
* Bliźniak tej funkcji żyje w drugim porcie - zmiany w obu naraz.
|
|
37
37
|
*/
|
|
38
38
|
function placeTooltip(host, tip, preferred) {
|
|
39
39
|
const r = host.getBoundingClientRect();
|
|
@@ -56,7 +56,7 @@ function placeTooltip(host, tip, preferred) {
|
|
|
56
56
|
};
|
|
57
57
|
const fits = (side) => {
|
|
58
58
|
const { top, left } = at(side);
|
|
59
|
-
// Po osi poprzecznej dymek i tak zostanie dociśnięty do okna
|
|
59
|
+
// Po osi poprzecznej dymek i tak zostanie dociśnięty do okna - liczy się tylko oś strony.
|
|
60
60
|
return side === 'top' || side === 'bottom'
|
|
61
61
|
? top >= margin && top + t.height <= vh - margin
|
|
62
62
|
: left >= margin && left + t.width <= vw - margin;
|
|
@@ -78,7 +78,7 @@ function placeTooltip(host, tip, preferred) {
|
|
|
78
78
|
tip.style.left = `${Math.min(Math.max(margin, left), Math.max(margin, vw - t.width - margin))}px`;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
|
-
* Dymek podpowiedzi pokazywany na hover i focus. Lekki
|
|
81
|
+
* Dymek podpowiedzi pokazywany na hover i focus. Lekki - element dodawany do `body` (albo do
|
|
82
82
|
* otwartego `<dialog>`/popovera dziecka, żeby był widoczny w warstwie szczytowej) i pozycjonowany
|
|
83
83
|
* względem dziecka. Wygląd daje klasa `.kpt-tooltip` z `@konce-pt/styles` w warstwie `kpt.components`.
|
|
84
84
|
*
|
|
@@ -86,7 +86,7 @@ function placeTooltip(host, tip, preferred) {
|
|
|
86
86
|
* i ref do przekazanego elementu, więc drzewo DOM zostaje takie samo jak bez tooltipa.
|
|
87
87
|
*
|
|
88
88
|
* Dostępność (jak w porcie Angulara): tekst trafia do czytników przez trwały, ukryty opis
|
|
89
|
-
* powiązany `aria-describedby` z elementem przyjmującym fokus
|
|
89
|
+
* powiązany `aria-describedby` z elementem przyjmującym fokus - pomijany, gdy powtarzałby
|
|
90
90
|
* jego nazwę albo przy `onlyWhenTruncated`. `Escape` zamyka dymek, a wskaźnik może na niego
|
|
91
91
|
* przejść bez zniknięcia (WCAG 1.4.13).
|
|
92
92
|
*
|
|
@@ -97,10 +97,10 @@ function placeTooltip(host, tip, preferred) {
|
|
|
97
97
|
export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false, children }) {
|
|
98
98
|
const hostRef = useRef(null);
|
|
99
99
|
// Dymek przypina się do elementu przez `ref` dziecka. Własny komponent, który nie przekazuje
|
|
100
|
-
// `ref` do elementu DOM, zostawia hosta pustym
|
|
100
|
+
// `ref` do elementu DOM, zostawia hosta pustym - dymek wtedy po cichu nie działa.
|
|
101
101
|
useEffect(() => {
|
|
102
102
|
if (isDevBuild() && isValidElement(children) && !hostRef.current) {
|
|
103
|
-
console.warn('[KptTooltip] Dziecko nie przekazało `ref` do elementu DOM
|
|
103
|
+
console.warn('[KptTooltip] Dziecko nie przekazało `ref` do elementu DOM - dymek nie ma się do czego przypiąć.');
|
|
104
104
|
}
|
|
105
105
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- sprawdzenie raz, po montażu
|
|
106
106
|
}, []);
|
|
@@ -144,7 +144,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
144
144
|
return;
|
|
145
145
|
placeTooltip(host, tip, position);
|
|
146
146
|
}, [position]);
|
|
147
|
-
/** Sprzątanie bieżącego dymka (nasłuchy i element)
|
|
147
|
+
/** Sprzątanie bieżącego dymka (nasłuchy i element) - ustawiane przy pokazaniu, wołane przy ukryciu. */
|
|
148
148
|
const cleanupRef = useRef(null);
|
|
149
149
|
const cancelHide = useCallback(() => {
|
|
150
150
|
if (hideTimer.current !== undefined)
|
|
@@ -181,7 +181,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
181
181
|
const tip = document.createElement('div');
|
|
182
182
|
tip.className = 'kpt-tooltip';
|
|
183
183
|
tip.setAttribute('role', 'tooltip');
|
|
184
|
-
// Treść czytnik dostaje z trwałego opisu
|
|
184
|
+
// Treść czytnik dostaje z trwałego opisu - dymek by ją zdublował.
|
|
185
185
|
if (descRef.current)
|
|
186
186
|
tip.setAttribute('aria-hidden', 'true');
|
|
187
187
|
tip.textContent = text;
|
|
@@ -213,7 +213,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
213
213
|
tipRef.current = null;
|
|
214
214
|
};
|
|
215
215
|
}, [text, onlyWhenTruncated, reposition, cancelHide, cancelShow, scheduleHide, hide]);
|
|
216
|
-
/** Najechanie wskaźnikiem pokazuje dymek po chwili; fokus
|
|
216
|
+
/** Najechanie wskaźnikiem pokazuje dymek po chwili; fokus - od razu. */
|
|
217
217
|
const scheduleShow = useCallback(() => {
|
|
218
218
|
cancelHide();
|
|
219
219
|
if (tipRef.current || showTimer.current !== undefined)
|
|
@@ -223,7 +223,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
223
223
|
show();
|
|
224
224
|
}, SHOW_DELAY_MS);
|
|
225
225
|
}, [cancelHide, show]);
|
|
226
|
-
// Zmiana tekstu przy widocznym dymku
|
|
226
|
+
// Zmiana tekstu przy widocznym dymku - bez tego dymek pokazywałby starą treść do zamknięcia.
|
|
227
227
|
useEffect(() => {
|
|
228
228
|
const tip = tipRef.current;
|
|
229
229
|
if (!tip)
|
|
@@ -235,7 +235,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
235
235
|
reposition();
|
|
236
236
|
}
|
|
237
237
|
}, [text, hide, reposition]);
|
|
238
|
-
/** Fokus przeszedł do innego elementu w obrębie hosta
|
|
238
|
+
/** Fokus przeszedł do innego elementu w obrębie hosta - dymek zostaje. */
|
|
239
239
|
const onBlur = (event) => {
|
|
240
240
|
const next = event.relatedTarget;
|
|
241
241
|
if (next && hostRef.current?.contains(next))
|
|
@@ -257,7 +257,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
257
257
|
});
|
|
258
258
|
/* eslint-enable react-hooks/refs */
|
|
259
259
|
}
|
|
260
|
-
/** Handler dziecka najpierw, nasz po nim
|
|
260
|
+
/** Handler dziecka najpierw, nasz po nim - jak w scalaniu propsów slotu. */
|
|
261
261
|
function chain(theirs, ours) {
|
|
262
262
|
return (...args) => {
|
|
263
263
|
if (typeof theirs === 'function')
|
|
@@ -267,7 +267,7 @@ function chain(theirs, ours) {
|
|
|
267
267
|
}
|
|
268
268
|
/**
|
|
269
269
|
* Czy treść jest przycięta? Sprawdzamy hosta oraz jego bezpośrednie dzieci, bo
|
|
270
|
-
* `text-overflow: ellipsis` siedzi zwykle na wewnętrznym elemencie
|
|
270
|
+
* `text-overflow: ellipsis` siedzi zwykle na wewnętrznym elemencie - a taki element kurczy się
|
|
271
271
|
* do dostępnej szerokości i nie rozpycha rodzica, więc pomiar samego hosta nie wykryłby niczego.
|
|
272
272
|
*/
|
|
273
273
|
function isTruncated(root) {
|
package/dist/tree/llms.txt
CHANGED
|
@@ -8,25 +8,26 @@ Import: `import { KptTree, type KptTreeNode } from '@konce-pt/react';`
|
|
|
8
8
|
<ul class="kpt-tree" role="tree">
|
|
9
9
|
<li class="kpt-tree__node" role="treeitem" aria-expanded="true">
|
|
10
10
|
<div class="kpt-tree__row is-selected">
|
|
11
|
-
<span class="kpt-tree__toggle" aria-hidden="true"
|
|
12
|
-
<span class="kpt-tree__icon"
|
|
11
|
+
<span class="kpt-tree__toggle" aria-hidden="true">...chevron...</span>
|
|
12
|
+
<span class="kpt-tree__icon">...</span>
|
|
13
13
|
<span class="kpt-tree__label">src</span>
|
|
14
14
|
</div>
|
|
15
|
-
<ul role="group"
|
|
15
|
+
<ul role="group">...</ul>
|
|
16
16
|
</li>
|
|
17
17
|
</ul>
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
20
|
## Props
|
|
21
|
-
- `nodes`: `KptTreeNode<T>[]`
|
|
22
|
-
- `selectable`: boolean
|
|
23
|
-
- `
|
|
21
|
+
- `nodes`: `KptTreeNode<T>[]` - `{ label, value?, icon?, children?, expanded?, disabled? }`
|
|
22
|
+
- `selectable`: boolean - a row click selects instead of expanding
|
|
23
|
+
- `collapseMotion` - `'spring' | 'fade' | 'none'` (default from `KptMotionProvider`, else `spring`) - see below
|
|
24
|
+
- `selected` / `defaultSelected` / `onSelectedChange` - the node object, or `null`
|
|
24
25
|
- `onNodeClick(node)`
|
|
25
26
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
26
27
|
|
|
27
28
|
## Expansion is component state, not data
|
|
28
29
|
`expanded` in a node is the initial state only. The component keeps what the user opened or closed
|
|
29
|
-
itself and never writes to the node objects
|
|
30
|
+
itself and never writes to the node objects - so two trees fed the same nodes open and close
|
|
30
31
|
independently, and replacing `nodes` with new objects brings their own initial state.
|
|
31
32
|
|
|
32
33
|
## Examples
|
|
@@ -36,16 +37,28 @@ independently, and replacing `nodes` with new objects brings their own initial s
|
|
|
36
37
|
## Keyboard
|
|
37
38
|
The tree is one Tab stop (roving tabindex on the `treeitem` elements), following the WAI-ARIA tree view
|
|
38
39
|
pattern:
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
- `Enter` / `Space`
|
|
40
|
+
- `ArrowDown` / `ArrowUp` - the next / previous visible row, `Home` / `End` - the first / last;
|
|
41
|
+
- `ArrowRight` - expands a closed branch, on an open one moves to its first child;
|
|
42
|
+
- `ArrowLeft` - collapses an open branch, otherwise moves to the parent;
|
|
43
|
+
- `Enter` / `Space` - the same as a click: selects (with `selectable`) or toggles the branch.
|
|
43
44
|
The logic is the pure function `treeKeyAction` in `tree-keys.ts`; the other port has a twin file.
|
|
44
45
|
|
|
45
46
|
## i18n
|
|
46
47
|
No labels of its own any more: the chevron is mouse-only and the keyboard expands with the arrows.
|
|
47
48
|
`locale` and `dictionary` are still accepted, so existing call sites keep compiling.
|
|
48
49
|
|
|
50
|
+
## Branch motion
|
|
51
|
+
`collapseMotion` animates expanding and collapsing a branch:
|
|
52
|
+
- `spring` - the height opens on a soft spring, children slide in as a cascade and sharpen out of a
|
|
53
|
+
blur; when collapsing, the children fade first;
|
|
54
|
+
- `fade` - children cross-fade;
|
|
55
|
+
- `none` - no motion.
|
|
56
|
+
|
|
57
|
+
A collapsing branch stays in the DOM (`inert`) until its animation ends, so it does not cut off
|
|
58
|
+
mid-way; keyboard navigation already skips it. Entry rules apply only after the first render, so
|
|
59
|
+
branches expanded in the data do not animate on page load. With no value it takes `collapse` from
|
|
60
|
+
`KptMotionProvider` (default `spring`); `enabled: false` and the system "reduce motion" setting always win.
|
|
61
|
+
|
|
49
62
|
## Tokens
|
|
50
63
|
The selected row `--kpt-color-primary`, the hover `--kpt-color-surface-variant`.
|
|
51
64
|
|
|
@@ -55,4 +68,4 @@ selectable trees `aria-selected`, disabled rows `aria-disabled`. The chevron is
|
|
|
55
68
|
(`aria-hidden`): a button inside a `treeitem` would be a nested control and a second Tab stop per
|
|
56
69
|
row, and the keyboard expands with the arrows anyway. The focus ring is drawn on the row, not on the
|
|
57
70
|
`<li>`, which would outline the whole subtree.
|
|
58
|
-
`ariaLabel` names the `role="tree"` element (e.g. "Project files")
|
|
71
|
+
`ariaLabel` names the `role="tree"` element (e.g. "Project files") - a separate prop because `aria-label` from the rest props lands on the wrapper, not on the tree.
|
package/dist/tree/tree-keys.d.ts
CHANGED
|
@@ -18,10 +18,10 @@ export type KptTreeKeyAction = {
|
|
|
18
18
|
index: number;
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* `Enter` / spacja
|
|
25
|
-
* Zwraca `null` dla klawisza, który nic nie robi
|
|
21
|
+
* ArrowDown / ArrowUp - następny / poprzedni widoczny wiersz (bez zawijania), `Home` / `End` - pierwszy / ostatni.
|
|
22
|
+
* -> - zamkniętą gałąź rozwija, w otwartej przechodzi do pierwszego dziecka.
|
|
23
|
+
* <- - otwartą gałąź zwija, w pozostałych przypadkach przechodzi do rodzica.
|
|
24
|
+
* `Enter` / spacja - aktywuje wiersz (zaznaczenie albo przełączenie, jak kliknięcie).
|
|
25
|
+
* Zwraca `null` dla klawisza, który nic nie robi - wtedy nie blokujemy jego domyślnej akcji.
|
|
26
26
|
*/
|
|
27
27
|
export declare function treeKeyAction(rows: readonly KptTreeRow[], current: number, key: string): KptTreeKeyAction | null;
|
package/dist/tree/tree-keys.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Klawiatura drzewa (wzorzec WAI-ARIA
|
|
3
|
-
* widocznych wierszy. Port Angulara ma bliźniaczy plik `lib/tree/tree-keys.ts`
|
|
2
|
+
* Klawiatura drzewa (wzorzec WAI-ARIA "tree view") - czysta funkcja na spłaszczonej liście
|
|
3
|
+
* widocznych wierszy. Port Angulara ma bliźniaczy plik `lib/tree/tree-keys.ts` - zmiana zachowania w obu.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `Enter` / spacja
|
|
10
|
-
* Zwraca `null` dla klawisza, który nic nie robi
|
|
6
|
+
* ArrowDown / ArrowUp - następny / poprzedni widoczny wiersz (bez zawijania), `Home` / `End` - pierwszy / ostatni.
|
|
7
|
+
* -> - zamkniętą gałąź rozwija, w otwartej przechodzi do pierwszego dziecka.
|
|
8
|
+
* <- - otwartą gałąź zwija, w pozostałych przypadkach przechodzi do rodzica.
|
|
9
|
+
* `Enter` / spacja - aktywuje wiersz (zaznaczenie albo przełączenie, jak kliknięcie).
|
|
10
|
+
* Zwraca `null` dla klawisza, który nic nie robi - wtedy nie blokujemy jego domyślnej akcji.
|
|
11
11
|
*/
|
|
12
12
|
export function treeKeyAction(rows, current, key) {
|
|
13
13
|
const row = rows[current];
|
package/dist/tree/tree.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef } from 'react';
|
|
2
2
|
import type { KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
|
+
import { type KptCollapseMotion } from '@konce-pt/motion';
|
|
3
4
|
export interface KptTreeNode<T = unknown> {
|
|
4
5
|
label: string;
|
|
5
6
|
value?: T;
|
|
@@ -18,26 +19,32 @@ export interface KptTreeProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onS
|
|
|
18
19
|
onSelectedChange?: (node: KptTreeNode<T> | null) => void;
|
|
19
20
|
onNodeClick?: (node: KptTreeNode<T>) => void;
|
|
20
21
|
/**
|
|
21
|
-
* Nazwa drzewa dla czytnika (`role="tree"` bez nazwy to samo
|
|
22
|
-
* Trafia na element `role="tree"`, nie na opakowanie
|
|
22
|
+
* Nazwa drzewa dla czytnika (`role="tree"` bez nazwy to samo "drzewo"), np. "Pliki projektu".
|
|
23
|
+
* Trafia na element `role="tree"`, nie na opakowanie - dlatego osobny prop, a nie `aria-label`.
|
|
23
24
|
*/
|
|
24
25
|
ariaLabel?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Ruch rozwijania gałęzi: `spring` - wysokość na sprężynie, dzieci wjeżdżają kaskadą i wyostrzają
|
|
28
|
+
* się z rozmycia; `fade` - dzieci się przenikają; `none` - bez ruchu. Bez wartości bierze `collapse`
|
|
29
|
+
* z `KptMotionProvider` (domyślnie `spring`); `enabled={false}` i systemowe "ogranicz ruch" wyłączają go zawsze.
|
|
30
|
+
*/
|
|
31
|
+
collapseMotion?: KptCollapseMotion;
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Drzewo hierarchiczne: rozwijanie, zaznaczanie, ikony.
|
|
28
35
|
*
|
|
29
36
|
* Stan rozwinięcia trzyma komponent, a nie pole `expanded` w danych: mutowanie cudzej tablicy
|
|
30
37
|
* przy każdym kliknięciu byłoby w Reakcie efektem ubocznym renderu, a `expanded` z danych zostaje
|
|
31
|
-
* tym, czym powinno być
|
|
38
|
+
* tym, czym powinno być - stanem początkowym.
|
|
32
39
|
*
|
|
33
|
-
* Klawiatura według wzorca WAI-ARIA
|
|
34
|
-
* tabindex), strzałki po widocznych wierszach,
|
|
40
|
+
* Klawiatura według wzorca WAI-ARIA "tree view": jeden przystanek Tab na całe drzewo (roving
|
|
41
|
+
* tabindex), strzałki po widocznych wierszach, -> / <- rozwijają i zwijają, `Enter` / spacja
|
|
35
42
|
* działają jak kliknięcie. Logika klawiszy siedzi w czystej funkcji `treeKeyAction`.
|
|
36
43
|
*
|
|
37
|
-
* `locale` i `dictionary` są przyjmowane dla zgodności
|
|
44
|
+
* `locale` i `dictionary` są przyjmowane dla zgodności - drzewo nie ma już własnych etykiet:
|
|
38
45
|
* przełącznik gałęzi jest tylko dla myszy, a z klawiatury rozwija się strzałkami.
|
|
39
46
|
*
|
|
40
47
|
* @example
|
|
41
48
|
* <KptTree nodes={tree} selectable selected={node} onSelectedChange={setNode} />
|
|
42
49
|
*/
|
|
43
|
-
export declare function KptTree<T>({ nodes, selectable, selected, defaultSelected, onSelectedChange, onNodeClick, ariaLabel, locale: _locale, dictionary: _dictionary, className, ...rest }: Readonly<KptTreeProps<T>>): import("react").JSX.Element;
|
|
50
|
+
export declare function KptTree<T>({ nodes, selectable, selected, defaultSelected, onSelectedChange, onNodeClick, ariaLabel, collapseMotion, locale: _locale, dictionary: _dictionary, className, ...rest }: Readonly<KptTreeProps<T>>): import("react").JSX.Element;
|
package/dist/tree/tree.js
CHANGED
|
@@ -5,41 +5,55 @@ import { cn } from "../internal/cn.js";
|
|
|
5
5
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
6
6
|
import { KptIcon } from "../icon/icon.js";
|
|
7
7
|
import { treeKeyAction } from "./tree-keys.js";
|
|
8
|
+
import { layoutMotionAllowed, resolveCollapseMotion } from '@konce-pt/motion';
|
|
9
|
+
import { useKptMotion } from "../motion/motion-context.js";
|
|
10
|
+
/** Ile gałąź w trakcie zwijania zostaje w DOM - z zapasem nad `--kpt-motion-duration-slow`. */
|
|
11
|
+
const CLOSE_MS = 420;
|
|
12
|
+
/** Wiersze drzewa z pominięciem tych w zwijanej gałęzi - ich kolejność to kolejność `rows`. */
|
|
13
|
+
const VISIBLE_ITEMS = '[role="treeitem"]:not(.kpt-tree__collapse:not(.is-open) *)';
|
|
8
14
|
/**
|
|
9
15
|
* Drzewo hierarchiczne: rozwijanie, zaznaczanie, ikony.
|
|
10
16
|
*
|
|
11
17
|
* Stan rozwinięcia trzyma komponent, a nie pole `expanded` w danych: mutowanie cudzej tablicy
|
|
12
18
|
* przy każdym kliknięciu byłoby w Reakcie efektem ubocznym renderu, a `expanded` z danych zostaje
|
|
13
|
-
* tym, czym powinno być
|
|
19
|
+
* tym, czym powinno być - stanem początkowym.
|
|
14
20
|
*
|
|
15
|
-
* Klawiatura według wzorca WAI-ARIA
|
|
16
|
-
* tabindex), strzałki po widocznych wierszach,
|
|
21
|
+
* Klawiatura według wzorca WAI-ARIA "tree view": jeden przystanek Tab na całe drzewo (roving
|
|
22
|
+
* tabindex), strzałki po widocznych wierszach, -> / <- rozwijają i zwijają, `Enter` / spacja
|
|
17
23
|
* działają jak kliknięcie. Logika klawiszy siedzi w czystej funkcji `treeKeyAction`.
|
|
18
24
|
*
|
|
19
|
-
* `locale` i `dictionary` są przyjmowane dla zgodności
|
|
25
|
+
* `locale` i `dictionary` są przyjmowane dla zgodności - drzewo nie ma już własnych etykiet:
|
|
20
26
|
* przełącznik gałęzi jest tylko dla myszy, a z klawiatury rozwija się strzałkami.
|
|
21
27
|
*
|
|
22
28
|
* @example
|
|
23
29
|
* <KptTree nodes={tree} selectable selected={node} onSelectedChange={setNode} />
|
|
24
30
|
*/
|
|
25
|
-
export function KptTree({ nodes = [], selectable = false, selected, defaultSelected = null, onSelectedChange, onNodeClick, ariaLabel, locale: _locale, dictionary: _dictionary, className, ...rest }) {
|
|
31
|
+
export function KptTree({ nodes = [], selectable = false, selected, defaultSelected = null, onSelectedChange, onNodeClick, ariaLabel, collapseMotion, locale: _locale, dictionary: _dictionary, className, ...rest }) {
|
|
26
32
|
const [active, setActive] = useControllableState({
|
|
27
33
|
value: selected,
|
|
28
34
|
defaultValue: defaultSelected,
|
|
29
35
|
onChange: onSelectedChange,
|
|
30
36
|
});
|
|
31
|
-
// Gałęzie przełączone przez użytkownika (węzeł
|
|
32
|
-
// w danych
|
|
37
|
+
// Gałęzie przełączone przez użytkownika (węzeł -> otwarta?). Węzeł spoza mapy ma stan z `expanded`
|
|
38
|
+
// w danych - dzięki temu nowa tablica `nodes` przychodzi z własnym stanem początkowym.
|
|
33
39
|
const [toggled, setToggled] = useState(() => new Map());
|
|
34
|
-
/** Wiersz, który ostatnio miał fokus
|
|
40
|
+
/** Wiersz, który ostatnio miał fokus - on jest przystankiem Tab. */
|
|
35
41
|
const [focused, setFocused] = useState(null);
|
|
36
42
|
/** Węzeł, na który po renderze trzeba przenieść fokus DOM (klawiatura). */
|
|
37
43
|
const [focusRequest, setFocusRequest] = useState(null);
|
|
38
44
|
const handledFocus = useRef(null);
|
|
39
45
|
const treeRef = useRef(null);
|
|
46
|
+
const motion = resolveCollapseMotion(collapseMotion, useKptMotion());
|
|
47
|
+
/** Gałęzie w trakcie zwijania - zostają w DOM, dopóki gra animacja. */
|
|
48
|
+
const [closing, setClosing] = useState(() => new Set());
|
|
49
|
+
// Reguły wejścia (`@starting-style`) dopiero po pierwszym renderze - start strony się nie rusza.
|
|
50
|
+
// Klasa idzie wprost na element: osobny stan dałby drugi przebieg renderu tylko po to.
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
treeRef.current?.classList.add('is-live');
|
|
53
|
+
}, []);
|
|
40
54
|
const hasChildren = (node) => !!node.children?.length;
|
|
41
55
|
const isOpen = (node) => toggled.get(node) ?? !!node.expanded;
|
|
42
|
-
// Widoczne wiersze w kolejności DOM
|
|
56
|
+
// Widoczne wiersze w kolejności DOM - tyle widzi klawiatura.
|
|
43
57
|
const rows = useMemo(() => {
|
|
44
58
|
const out = [];
|
|
45
59
|
const walk = (list, level, parent) => {
|
|
@@ -55,25 +69,46 @@ export function KptTree({ nodes = [], selectable = false, selected, defaultSelec
|
|
|
55
69
|
walk(nodes, 0, -1);
|
|
56
70
|
return out;
|
|
57
71
|
}, [nodes, toggled]);
|
|
58
|
-
// Jedyny wiersz z `tabIndex=0`: ostatnio skupiony, a gdy go nie widać
|
|
72
|
+
// Jedyny wiersz z `tabIndex=0`: ostatnio skupiony, a gdy go nie widać - zaznaczony albo pierwszy.
|
|
59
73
|
const visible = rows.map((r) => r.node);
|
|
60
74
|
const tabStop = focused && visible.includes(focused) ? focused : active && visible.includes(active) ? active : (visible[0] ?? null);
|
|
61
75
|
// Żądanie nie jest zerowane w efekcie (setState w efekcie = dodatkowy przebieg renderu): każde jest
|
|
62
|
-
// nowym obiektem, a obsłużone zapamiętuje ref
|
|
76
|
+
// nowym obiektem, a obsłużone zapamiętuje ref - kolejne przebiegi efektu go pomijają.
|
|
63
77
|
useEffect(() => {
|
|
64
78
|
if (!focusRequest || handledFocus.current === focusRequest)
|
|
65
79
|
return;
|
|
66
80
|
const index = rows.findIndex((r) => r.node === focusRequest.node);
|
|
67
|
-
const element = treeRef.current?.querySelectorAll(
|
|
81
|
+
const element = treeRef.current?.querySelectorAll(VISIBLE_ITEMS)[index];
|
|
68
82
|
if (!element)
|
|
69
|
-
return; // wiersz jeszcze nie wyrenderowany (rozwijanie)
|
|
83
|
+
return; // wiersz jeszcze nie wyrenderowany (rozwijanie) - spróbujemy po zmianie `rows`
|
|
70
84
|
handledFocus.current = focusRequest;
|
|
71
85
|
element.focus();
|
|
72
86
|
}, [focusRequest, rows]);
|
|
73
87
|
const toggle = (node) => {
|
|
88
|
+
const willOpen = !isOpen(node);
|
|
74
89
|
const next = new Map(toggled);
|
|
75
|
-
next.set(node,
|
|
90
|
+
next.set(node, willOpen);
|
|
76
91
|
setToggled(next);
|
|
92
|
+
// Zwijana gałąź zostaje w DOM na czas animacji; ponowne otwarcie w trakcie ją po prostu zatrzymuje.
|
|
93
|
+
const animate = motion !== 'none' && layoutMotionAllowed();
|
|
94
|
+
setClosing((current) => {
|
|
95
|
+
const set = new Set(current);
|
|
96
|
+
set.delete(node);
|
|
97
|
+
if (!willOpen && animate)
|
|
98
|
+
set.add(node);
|
|
99
|
+
return set;
|
|
100
|
+
});
|
|
101
|
+
if (!willOpen && animate) {
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
setClosing((current) => {
|
|
104
|
+
if (!current.has(node))
|
|
105
|
+
return current;
|
|
106
|
+
const set = new Set(current);
|
|
107
|
+
set.delete(node);
|
|
108
|
+
return set;
|
|
109
|
+
});
|
|
110
|
+
}, CLOSE_MS);
|
|
111
|
+
}
|
|
77
112
|
};
|
|
78
113
|
const onRow = (node) => {
|
|
79
114
|
setFocused(node);
|
|
@@ -86,7 +121,7 @@ export function KptTree({ nodes = [], selectable = false, selected, defaultSelec
|
|
|
86
121
|
onNodeClick?.(node);
|
|
87
122
|
};
|
|
88
123
|
const onKeyDown = (node, event) => {
|
|
89
|
-
// Zagnieżdżone `<li>` przepuszczają zdarzenie w górę
|
|
124
|
+
// Zagnieżdżone `<li>` przepuszczają zdarzenie w górę - obsługuje je tylko wiersz z fokusem.
|
|
90
125
|
if (event.target !== event.currentTarget)
|
|
91
126
|
return;
|
|
92
127
|
const current = rows.findIndex((r) => r.node === node);
|
|
@@ -104,12 +139,12 @@ export function KptTree({ nodes = [], selectable = false, selected, defaultSelec
|
|
|
104
139
|
setFocusRequest({ node: target });
|
|
105
140
|
}
|
|
106
141
|
};
|
|
107
|
-
const renderList = (list, level) => list.map((node, index) => (_jsxs("li", { className: "kpt-tree__node", role: "treeitem", "aria-level": level + 1, "aria-expanded": hasChildren(node) ? isOpen(node) : undefined, "aria-selected": selectable ? active === node : undefined, "aria-disabled": node.disabled ? true : undefined, tabIndex: node === tabStop ? 0 : -1, onFocus: (event) => {
|
|
142
|
+
const renderList = (list, level) => list.map((node, index) => (_jsxs("li", { className: "kpt-tree__node", style: { '--_i': index }, role: "treeitem", "aria-level": level + 1, "aria-expanded": hasChildren(node) ? isOpen(node) : undefined, "aria-selected": selectable ? active === node : undefined, "aria-disabled": node.disabled ? true : undefined, tabIndex: node === tabStop ? 0 : -1, onFocus: (event) => {
|
|
108
143
|
if (event.target === event.currentTarget)
|
|
109
144
|
setFocused(node);
|
|
110
145
|
}, onKeyDown: (event) => onKeyDown(node, event), children: [_jsxs("div", { className: cn('kpt-tree__row', active === node && 'is-selected', node.disabled && 'is-disabled'), style: { paddingInlineStart: `${0.5 + level * 1.1}rem` }, onClick: () => onRow(node), children: [hasChildren(node) ? (_jsx("span", { className: "kpt-tree__toggle", "aria-hidden": "true", onClick: (event) => {
|
|
111
146
|
event.stopPropagation();
|
|
112
147
|
toggle(node);
|
|
113
|
-
}, children: _jsx(KptIcon, { name: "chevron-right", className: cn('kpt-tree__chevron', isOpen(node) && 'is-open') }) })) : (_jsx("span", { className: "kpt-tree__spacer" })), node.icon ? _jsx(KptIcon, { name: node.icon, className: "kpt-tree__icon" }) : null, _jsx("span", { className: "kpt-tree__label", children: node.label })] }), hasChildren(node) && isOpen(node) ? _jsx("ul", { role: "group", children: renderList(node.children, level + 1) }) : null] }, index)));
|
|
114
|
-
return (_jsx("div", { className: cn('kpt-tree-host', className), ...rest, children: _jsx("ul", { ref: treeRef, className: "kpt-tree", role: "tree", "aria-label": ariaLabel || undefined, children: renderList(nodes, 0) }) }));
|
|
148
|
+
}, children: _jsx(KptIcon, { name: "chevron-right", className: cn('kpt-tree__chevron', isOpen(node) && 'is-open') }) })) : (_jsx("span", { className: "kpt-tree__spacer" })), node.icon ? _jsx(KptIcon, { name: node.icon, className: "kpt-tree__icon" }) : null, _jsx("span", { className: "kpt-tree__label", children: node.label })] }), hasChildren(node) && (isOpen(node) || closing.has(node)) ? (_jsx("div", { className: cn('kpt-tree__collapse', isOpen(node) && 'is-open'), inert: !isOpen(node), children: _jsx("ul", { role: "group", className: "kpt-tree__group", children: renderList(node.children, level + 1) }) })) : null] }, index)));
|
|
149
|
+
return (_jsx("div", { className: cn('kpt-tree-host', className), ...rest, children: _jsx("ul", { ref: treeRef, className: "kpt-tree", role: "tree", "aria-label": ariaLabel || undefined, "data-motion": motion, children: renderList(nodes, 0) }) }));
|
|
115
150
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# KptUpdate (@konce-pt/react)
|
|
2
|
+
|
|
3
|
+
An app update row: the icon in `KptLoader variant="ring"`, the name, a status line
|
|
4
|
+
("12.3 MB of 24 MB") and a button whose label follows the state; texts cross-fade on a state change.
|
|
5
|
+
Same classes as `kpt-update` in Angular. Import: `import { KptUpdate } from '@konce-pt/react';`
|
|
6
|
+
|
|
7
|
+
The component downloads nothing - the app owns the state, the byte counts and what an action does.
|
|
8
|
+
|
|
9
|
+
## DOM
|
|
10
|
+
<div class="kpt-update-host">
|
|
11
|
+
<div class="kpt-update" data-status="downloading">
|
|
12
|
+
<span class="kpt-loader-host kpt-update__ring">...<span class="kpt-update__icon">...</span>...</span>
|
|
13
|
+
<div class="kpt-update__meta">
|
|
14
|
+
<span class="kpt-update__name">Kompas</span>
|
|
15
|
+
<span class="kpt-update__line kpt-update__swap" aria-hidden="true"><span>0.4 MB of 24 MB</span></span>
|
|
16
|
+
<span class="kpt-button-host kpt-update__action"><button class="kpt-button">...</button></span>
|
|
17
|
+
</div>
|
|
18
|
+
<span class="kpt-update__live" role="status">Kompas: Downloading...</span>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
## States (`status`)
|
|
23
|
+
`pending` (default, ring loops, button "Update") -> `downloading` (with `total` the ring draws
|
|
24
|
+
progress and the line shows both sizes in the unit of the total; button "Cancel") -> `success`
|
|
25
|
+
(the ring releases the icon; "Open") or `error` (a badge on the icon; "Retry").
|
|
26
|
+
|
|
27
|
+
## Props
|
|
28
|
+
- `name`: string (required)
|
|
29
|
+
- `status`: KptUpdateStatus (default 'pending')
|
|
30
|
+
- `loaded`, `total`: number | null (bytes) - formatted with `Intl` in the interface language
|
|
31
|
+
- `size`: string (default '5.5rem'), `color`: KptLoaderColor (default 'info')
|
|
32
|
+
- `showAction`: boolean (default true)
|
|
33
|
+
- `pendingText`, `downloadingText`, `successText`, `errorText`, `updateLabel`, `cancelLabel`,
|
|
34
|
+
`openLabel`, `retryLabel` - override the `update.*` texts
|
|
35
|
+
- `onAction`: (action: KptUpdateAction) => void - 'update' | 'cancel' | 'open' | 'retry' by state
|
|
36
|
+
- `children` - the icon (`<img>`, SVG, `KptIcon`); omitted = `download`
|
|
37
|
+
- `locale`, `dictionary` - i18n overrides for this component only
|
|
38
|
+
- `className`, `style`, `ref` and other `<div>` props go to `.kpt-update`; `hostProps` to the wrapper
|
|
39
|
+
|
|
40
|
+
## Example
|
|
41
|
+
<KptUpdate name="Kompas" status={status} loaded={loaded} total={total} onAction={handle}>
|
|
42
|
+
<img src="/kompas.svg" alt="" />
|
|
43
|
+
</KptUpdate>
|
|
44
|
+
|
|
45
|
+
## Tokens
|
|
46
|
+
The tile: a gradient from the `color` role to `--kpt-color-success`, the icon in
|
|
47
|
+
`--kpt-color-<role>-contrast`, `--kpt-shadow-sm`. Text: `--kpt-font-weight-semibold`,
|
|
48
|
+
`--kpt-font-size-sm`, `--kpt-color-text-muted`.
|
|
49
|
+
|
|
50
|
+
## Accessibility
|
|
51
|
+
A visually hidden `role="status"` region holds "name: state" and announces state changes, not
|
|
52
|
+
bytes (the line is `aria-hidden`). While downloading with a known total the ring is a
|
|
53
|
+
`role="progressbar"`. During the cross-fade the leaving label is `aria-hidden`; with motion off
|
|
54
|
+
texts change at once.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
import { type KptLoaderColor } from '@konce-pt/motion';
|
|
3
|
+
import type { KptHostProps } from '../internal/types.ts';
|
|
4
|
+
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
5
|
+
/** `pending` - czeka na decyzję albo w kolejce; `downloading` - pobiera; potem wynik. */
|
|
6
|
+
export type KptUpdateStatus = 'pending' | 'downloading' | 'success' | 'error';
|
|
7
|
+
/** Co kliknął użytkownik - zależy od stanu: aktualizuj, anuluj, otwórz, ponów. */
|
|
8
|
+
export type KptUpdateAction = 'update' | 'cancel' | 'open' | 'retry';
|
|
9
|
+
export interface KptUpdateProps extends Omit<ComponentPropsWithRef<'div'>, 'children'>, KptI18nOverrides {
|
|
10
|
+
/** Nazwa aplikacji albo pakietu. */
|
|
11
|
+
name: string;
|
|
12
|
+
status?: KptUpdateStatus;
|
|
13
|
+
/** Pobrane bajty; z `total` daje postęp i linię "x z y". */
|
|
14
|
+
loaded?: number | null;
|
|
15
|
+
/** Rozmiar całości w bajtach; bez niego pobieranie jest nieokreślone. */
|
|
16
|
+
total?: number | null;
|
|
17
|
+
/** Rozmiar pierścienia (100 jednostek rysunku `KptLoader`). Domyślnie `5.5rem`. */
|
|
18
|
+
size?: string;
|
|
19
|
+
/** Barwa pierścienia i kafla ikony - rola motywu albo kolor CSS. Domyślnie `info`. */
|
|
20
|
+
color?: KptLoaderColor;
|
|
21
|
+
/** `false` chowa przycisk akcji. */
|
|
22
|
+
showAction?: boolean;
|
|
23
|
+
/** Nadpisania napisów; pominięte = słownik `update.*`. */
|
|
24
|
+
pendingText?: string;
|
|
25
|
+
downloadingText?: string;
|
|
26
|
+
successText?: string;
|
|
27
|
+
errorText?: string;
|
|
28
|
+
updateLabel?: string;
|
|
29
|
+
cancelLabel?: string;
|
|
30
|
+
openLabel?: string;
|
|
31
|
+
retryLabel?: string;
|
|
32
|
+
/** Klik w przycisk: `update`, `cancel`, `open` albo `retry` - wg stanu w chwili kliknięcia. */
|
|
33
|
+
onAction?: (action: KptUpdateAction) => void;
|
|
34
|
+
/** Ikona aplikacji; pominięta = `download`. */
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
/** Propsy wrappera `kpt-update-host` (odpowiednik hosta Angulara). */
|
|
37
|
+
hostProps?: KptHostProps<'div'>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Wiersz aktualizacji aplikacji: ikona w pierścieniu `KptLoader variant="ring"`, nazwa, linia
|
|
41
|
+
* stanu ("12,3 MB z 24 MB") i przycisk, którego napis idzie za stanem. Napisy przenikają się
|
|
42
|
+
* przy zmianie stanu. Komponent nic nie pobiera - stan, bajty i reakcję na `onAction` daje aplikacja.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* <KptUpdate name="Kompas" status={status} loaded={loaded} total={total} onAction={handle}>
|
|
46
|
+
* <img src="/kompas.svg" alt="" />
|
|
47
|
+
* </KptUpdate>
|
|
48
|
+
*/
|
|
49
|
+
export declare function KptUpdate({ name, status, loaded, total, size, color, showAction, pendingText, downloadingText, successText, errorText, updateLabel, cancelLabel, openLabel, retryLabel, onAction, locale, dictionary, children, hostProps, className, style, ...rest }: Readonly<KptUpdateProps>): import("react").JSX.Element;
|