@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
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import { type KptSpeechEndReason, type KptSpeechErrorCode, type KptSpeechInterimDisplay, type KptSpeechMode, type KptSpeechSnapshot, type KptSpeechStatus, type KptSpeechSupport, type KptSpeechTargetInput, type KptSpeechWaveMode } from '@konce-pt/speech';
|
|
3
|
+
/** Cel dyktowania: element, `ref` do elementu, gotowy `KptSpeechTarget` albo funkcja. */
|
|
4
|
+
export type KptSpeechTargetRef = KptSpeechTargetInput | RefObject<HTMLElement | null>;
|
|
5
|
+
export interface KptSpeechRecognitionOptions {
|
|
6
|
+
/** Gdzie trafia tekst. Bez celu kontroler tylko zgłasza `onResult`. */
|
|
7
|
+
target?: KptSpeechTargetRef | null;
|
|
8
|
+
/** Język rozpoznawania (BCP 47); bez niego z `KptI18nProvider` i języka przeglądarki. */
|
|
9
|
+
lang?: string;
|
|
10
|
+
/** Słuchaj do "stop" (domyślnie) albo do końca jednej wypowiedzi. */
|
|
11
|
+
continuous?: boolean;
|
|
12
|
+
/** `insert` (w kursor, domyślnie), `append` albo `replace` (czyści cel w chwili startu). */
|
|
13
|
+
mode?: KptSpeechMode;
|
|
14
|
+
/** Pokaz tekstu tymczasowego; bez wartości - domyślny dla rodzaju celu. */
|
|
15
|
+
interim?: KptSpeechInterimDisplay;
|
|
16
|
+
/** Wielka litera na początku zdania. Domyślnie `true`. */
|
|
17
|
+
capitalize?: boolean;
|
|
18
|
+
/** Fala: `auto` (na żywo na desktopie, syntetyczna na telefonie), `live`, `synthetic`, `none`. */
|
|
19
|
+
wave?: KptSpeechWaveMode;
|
|
20
|
+
/** Słupki fali na żywo. Domyślnie 5. */
|
|
21
|
+
bars?: number;
|
|
22
|
+
/** Zatrzymaj po tylu ms bez nowego słowa; `0` - nigdy. */
|
|
23
|
+
silenceMs?: number;
|
|
24
|
+
/** Twardy limit długości dyktowania w ms; `0` - bez limitu. */
|
|
25
|
+
maxDuration?: number;
|
|
26
|
+
/** Rozpoznawanie wyłącznie w urządzeniu (Chrome 135+). */
|
|
27
|
+
processLocally?: boolean;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Czy kontroler w ogóle istnieje. `false` nie tworzy sesji ani nasłuchów strony - dla pól,
|
|
31
|
+
* w których mikrofon jest opcją (`speech` w `KptInput`). Domyślnie `true`.
|
|
32
|
+
*/
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
onStart?: () => void;
|
|
35
|
+
onEnd?: (reason: KptSpeechEndReason) => void;
|
|
36
|
+
/** Stan transkryptu po każdej zmianie: zatwierdzony i tymczasowy osobno. */
|
|
37
|
+
onResult?: (snapshot: KptSpeechSnapshot) => void;
|
|
38
|
+
onError?: (code: KptSpeechErrorCode) => void;
|
|
39
|
+
}
|
|
40
|
+
export interface KptSpeechRecognition {
|
|
41
|
+
status: KptSpeechStatus;
|
|
42
|
+
/** Trwa nasłuch (także start i łagodne zatrzymywanie). */
|
|
43
|
+
listening: boolean;
|
|
44
|
+
/** Wsparcie przeglądarki - `null` do pierwszego renderu po stronie klienta (SSR). */
|
|
45
|
+
support: KptSpeechSupport | null;
|
|
46
|
+
/** Da się dyktować: przeglądarka rozpoznaje mowę, a usługa nie odmówiła (`network`). */
|
|
47
|
+
available: boolean;
|
|
48
|
+
/** Ostatni błąd albo `null`. */
|
|
49
|
+
error: KptSpeechErrorCode | null;
|
|
50
|
+
/** Powód końca ostatniego dyktowania; `null` przed pierwszym i w trakcie nasłuchu. */
|
|
51
|
+
lastEnd: KptSpeechEndReason | null;
|
|
52
|
+
/** Silnik słyszy mowę - napęd fali syntetycznej. */
|
|
53
|
+
speaking: boolean;
|
|
54
|
+
/** Poziomy fali na żywo (0..1), puste poza nasłuchem i w trybie syntetycznym. */
|
|
55
|
+
levels: readonly number[];
|
|
56
|
+
/** Rozstrzygnięty tryb fali. */
|
|
57
|
+
waveMode: Exclude<KptSpeechWaveMode, 'auto'>;
|
|
58
|
+
snapshot: KptSpeechSnapshot;
|
|
59
|
+
start: () => void;
|
|
60
|
+
/** Łagodny stop: ostatnie słowa jeszcze się zatwierdzą. */
|
|
61
|
+
stop: () => void;
|
|
62
|
+
/** Zatwierdź to, co widać, i skończ od razu - przed wysłaniem treści. */
|
|
63
|
+
flush: () => void;
|
|
64
|
+
/** Przerwij bez zatwierdzania tekstu tymczasowego. */
|
|
65
|
+
abort: () => void;
|
|
66
|
+
toggle: () => void;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Dyktowanie bez UI - sesja Web Speech API, wstawianie w cel i poziomy fali z `@konce-pt/speech`.
|
|
70
|
+
* `KptSpeechButton` używa go pod spodem; własny przycisk albo skrót klawiszowy dostaje to samo.
|
|
71
|
+
*
|
|
72
|
+
* Tekst tymczasowy widać w celu, ale do wartości (stanu kontrolowanego pola) trafia wyłącznie
|
|
73
|
+
* zatwierdzony - przez zwykłą edycję, którą `onChange` widzi jak wpisany tekst.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* const fieldRef = useRef<HTMLTextAreaElement>(null);
|
|
77
|
+
* const speech = useKptSpeechRecognition({ target: fieldRef });
|
|
78
|
+
* <KptSpeechButton speech={speech} />
|
|
79
|
+
* <KptButton onClick={() => { speech.flush(); send(); }}>Send</KptButton>
|
|
80
|
+
*/
|
|
81
|
+
export declare function useKptSpeechRecognition(options?: KptSpeechRecognitionOptions): KptSpeechRecognition;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useEffectEvent, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
|
+
import { browserSpeechEngine, createSpeechSession, defaultSpeechLang, mirrorSpeechLevels, onSpeechPageHidden, resolveSpeechTarget, resolveWaveMode, speechSupport, speechUnavailable, startSpeechMeter, } from '@konce-pt/speech';
|
|
4
|
+
import { useKptI18n } from "../i18n/i18n-context.js";
|
|
5
|
+
// Wsparcie przeglądarki nie zmienia się w trakcie życia strony - liczone raz, czytane przez
|
|
6
|
+
// `useSyncExternalStore`, żeby serwer i hydracja widziały "nieznane", a klient od razu prawdę.
|
|
7
|
+
let supportCache = null;
|
|
8
|
+
const readSupport = () => (supportCache ??= speechSupport());
|
|
9
|
+
const readServerSupport = () => null;
|
|
10
|
+
const subscribeNever = () => () => undefined;
|
|
11
|
+
const EMPTY_SNAPSHOT = { finalText: '', interimText: '' };
|
|
12
|
+
const NO_LEVELS = [];
|
|
13
|
+
function isRef(value) {
|
|
14
|
+
return typeof value === 'object' && value !== null && 'current' in value && !('begin' in value);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Dyktowanie bez UI - sesja Web Speech API, wstawianie w cel i poziomy fali z `@konce-pt/speech`.
|
|
18
|
+
* `KptSpeechButton` używa go pod spodem; własny przycisk albo skrót klawiszowy dostaje to samo.
|
|
19
|
+
*
|
|
20
|
+
* Tekst tymczasowy widać w celu, ale do wartości (stanu kontrolowanego pola) trafia wyłącznie
|
|
21
|
+
* zatwierdzony - przez zwykłą edycję, którą `onChange` widzi jak wpisany tekst.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const fieldRef = useRef<HTMLTextAreaElement>(null);
|
|
25
|
+
* const speech = useKptSpeechRecognition({ target: fieldRef });
|
|
26
|
+
* <KptSpeechButton speech={speech} />
|
|
27
|
+
* <KptButton onClick={() => { speech.flush(); send(); }}>Send</KptButton>
|
|
28
|
+
*/
|
|
29
|
+
export function useKptSpeechRecognition(options = {}) {
|
|
30
|
+
const { locale } = useKptI18n();
|
|
31
|
+
const support = useSyncExternalStore(subscribeNever, readSupport, readServerSupport);
|
|
32
|
+
const enabled = options.enabled ?? true;
|
|
33
|
+
const [status, setStatus] = useState('idle');
|
|
34
|
+
const [error, setError] = useState(null);
|
|
35
|
+
const [speaking, setSpeaking] = useState(false);
|
|
36
|
+
const [levels, setLevels] = useState(NO_LEVELS);
|
|
37
|
+
const [meterFailed, setMeterFailed] = useState(false);
|
|
38
|
+
const [unavailable, setUnavailable] = useState(false);
|
|
39
|
+
const [snapshot, setSnapshot] = useState(EMPTY_SNAPSHOT);
|
|
40
|
+
const [lastEnd, setLastEnd] = useState(null);
|
|
41
|
+
const sessionRef = useRef(null);
|
|
42
|
+
const targetRef = useRef(null);
|
|
43
|
+
const targetElementRef = useRef(null);
|
|
44
|
+
const meterRef = useRef(null);
|
|
45
|
+
const listening = status === 'starting' || status === 'listening' || status === 'stopping';
|
|
46
|
+
const available = enabled && !!support?.supported && !unavailable && !speechUnavailable();
|
|
47
|
+
const resolvedWave = support ? resolveWaveMode(options.wave ?? 'auto', support) : 'none';
|
|
48
|
+
const waveMode = resolvedWave === 'live' && meterFailed ? 'synthetic' : resolvedWave;
|
|
49
|
+
const emitStart = useEffectEvent(() => options.onStart?.());
|
|
50
|
+
const emitEnd = useEffectEvent((reason) => options.onEnd?.(reason));
|
|
51
|
+
const emitResult = useEffectEvent((next) => options.onResult?.(next));
|
|
52
|
+
const emitError = useEffectEvent((code) => options.onError?.(code));
|
|
53
|
+
// Escape w celu zatrzymuje dyktowanie - jak na samym przycisku.
|
|
54
|
+
const onTargetKeydown = useRef((event) => {
|
|
55
|
+
if (event.key !== 'Escape')
|
|
56
|
+
return;
|
|
57
|
+
const session = sessionRef.current;
|
|
58
|
+
if (!session || session.status === 'idle' || session.status === 'error')
|
|
59
|
+
return;
|
|
60
|
+
event.preventDefault();
|
|
61
|
+
session.stop();
|
|
62
|
+
});
|
|
63
|
+
// Sesja żyje tyle, co komponent. Słuchacze wołają zdarzenia efektu - zawsze z najnowszymi
|
|
64
|
+
// propsami, bez odtwarzania sesji przy każdym renderze.
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!enabled)
|
|
67
|
+
return;
|
|
68
|
+
const engine = browserSpeechEngine();
|
|
69
|
+
if (!engine)
|
|
70
|
+
return;
|
|
71
|
+
const releaseTarget = () => {
|
|
72
|
+
targetRef.current?.end();
|
|
73
|
+
targetRef.current = null;
|
|
74
|
+
targetElementRef.current?.removeEventListener('keydown', onTargetKeydown.current);
|
|
75
|
+
targetElementRef.current = null;
|
|
76
|
+
meterRef.current?.stop();
|
|
77
|
+
meterRef.current = null;
|
|
78
|
+
setLevels(NO_LEVELS);
|
|
79
|
+
setSpeaking(false);
|
|
80
|
+
};
|
|
81
|
+
const session = createSpeechSession({ engine }, { lang: 'en-US' }, {
|
|
82
|
+
status: (next) => {
|
|
83
|
+
setStatus(next);
|
|
84
|
+
if (next === 'starting')
|
|
85
|
+
emitStart();
|
|
86
|
+
},
|
|
87
|
+
interim: (text) => targetRef.current?.interim(text),
|
|
88
|
+
commit: (text) => targetRef.current?.commit(text),
|
|
89
|
+
snapshot: (next) => {
|
|
90
|
+
setSnapshot(next);
|
|
91
|
+
emitResult(next);
|
|
92
|
+
},
|
|
93
|
+
speech: (active) => setSpeaking(active),
|
|
94
|
+
error: (code) => {
|
|
95
|
+
setError(code);
|
|
96
|
+
if (speechUnavailable())
|
|
97
|
+
setUnavailable(true);
|
|
98
|
+
emitError(code);
|
|
99
|
+
},
|
|
100
|
+
end: (reason) => {
|
|
101
|
+
setLastEnd(reason);
|
|
102
|
+
releaseTarget();
|
|
103
|
+
emitEnd(reason);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
sessionRef.current = session;
|
|
107
|
+
const offPageHidden = onSpeechPageHidden(() => session.stop());
|
|
108
|
+
return () => {
|
|
109
|
+
offPageHidden();
|
|
110
|
+
session.abort();
|
|
111
|
+
releaseTarget();
|
|
112
|
+
sessionRef.current = null;
|
|
113
|
+
};
|
|
114
|
+
}, [enabled]);
|
|
115
|
+
// Kontrolowane pole nadpisuje `value` stanem przy każdym renderze rodzica - a stan nie zna
|
|
116
|
+
// tekstu tymczasowego, więc React by go zmywał (przy fali na żywo co klatkę). Po każdym commicie,
|
|
117
|
+
// jeszcze przed malowaniem, cel przywraca tekst tymczasowy na swoje miejsce: nic nie mruga.
|
|
118
|
+
useLayoutEffect(() => {
|
|
119
|
+
targetRef.current?.refresh?.();
|
|
120
|
+
});
|
|
121
|
+
const start = () => {
|
|
122
|
+
const session = sessionRef.current;
|
|
123
|
+
if (!session || !support || !available || options.disabled)
|
|
124
|
+
return;
|
|
125
|
+
if (session.status !== 'idle' && session.status !== 'error')
|
|
126
|
+
return;
|
|
127
|
+
setError(null);
|
|
128
|
+
setLastEnd(null);
|
|
129
|
+
setMeterFailed(false);
|
|
130
|
+
setSnapshot(EMPTY_SNAPSHOT);
|
|
131
|
+
const raw = options.target;
|
|
132
|
+
const target = isRef(raw) ? raw.current : raw;
|
|
133
|
+
if (target) {
|
|
134
|
+
targetElementRef.current = target instanceof HTMLElement ? target : null;
|
|
135
|
+
targetElementRef.current?.addEventListener('keydown', onTargetKeydown.current);
|
|
136
|
+
const capitalize = options.capitalize ?? true;
|
|
137
|
+
targetRef.current = resolveSpeechTarget(target, options.interim ? { capitalize, interim: options.interim } : { capitalize });
|
|
138
|
+
targetRef.current.begin(options.mode ?? 'insert');
|
|
139
|
+
}
|
|
140
|
+
session.configure({
|
|
141
|
+
lang: options.lang ?? defaultSpeechLang(locale, globalThis.navigator?.language),
|
|
142
|
+
continuous: options.continuous ?? true,
|
|
143
|
+
processLocally: options.processLocally ?? false,
|
|
144
|
+
autoRestart: !support.ios,
|
|
145
|
+
silenceMs: options.silenceMs ?? 0,
|
|
146
|
+
maxDurationMs: options.maxDuration ?? 0,
|
|
147
|
+
});
|
|
148
|
+
// Miernik startuje jeszcze w geście kliknięcia - poza nim `AudioContext` jest zawieszony.
|
|
149
|
+
if (waveMode === 'live') {
|
|
150
|
+
meterRef.current = startSpeechMeter({
|
|
151
|
+
bars: options.bars ?? 5,
|
|
152
|
+
onLevels: (next) => setLevels(mirrorSpeechLevels(next)),
|
|
153
|
+
onFail: () => setMeterFailed(true),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
session.start();
|
|
157
|
+
};
|
|
158
|
+
const stop = () => sessionRef.current?.stop();
|
|
159
|
+
const flush = () => sessionRef.current?.flush();
|
|
160
|
+
const abort = () => sessionRef.current?.abort();
|
|
161
|
+
const toggle = () => (listening ? stop() : start());
|
|
162
|
+
return {
|
|
163
|
+
status,
|
|
164
|
+
listening,
|
|
165
|
+
support,
|
|
166
|
+
available,
|
|
167
|
+
error,
|
|
168
|
+
lastEnd,
|
|
169
|
+
speaking,
|
|
170
|
+
levels,
|
|
171
|
+
waveMode,
|
|
172
|
+
snapshot,
|
|
173
|
+
start,
|
|
174
|
+
stop,
|
|
175
|
+
flush,
|
|
176
|
+
abort,
|
|
177
|
+
toggle,
|
|
178
|
+
};
|
|
179
|
+
}
|
package/dist/speed-dial/llms.txt
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# KptSpeedDial (@konce-pt/react)
|
|
2
2
|
|
|
3
|
-
A speed dial
|
|
3
|
+
A speed dial - a FAB that fans out a set of actions. Built on `KptFab`.
|
|
4
4
|
Import: `import { KptSpeedDial } from '@konce-pt/react';`
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<div class="kpt-speed-dial-host">
|
|
8
8
|
<div class="kpt-speed-dial is-open" data-direction="up">
|
|
9
9
|
<div class="kpt-speed-dial__actions">
|
|
10
|
-
<button class="kpt-speed-dial__action" aria-label="Upload file"
|
|
10
|
+
<button class="kpt-speed-dial__action" aria-label="Upload file">...</button>...
|
|
11
11
|
</div>
|
|
12
|
-
<span class="kpt-fab-host"><button class="kpt-fab"
|
|
12
|
+
<span class="kpt-fab-host"><button class="kpt-fab">...</button></span>
|
|
13
13
|
</div>
|
|
14
14
|
<div class="kpt-speed-dial__backdrop"></div>
|
|
15
15
|
</div>
|
|
16
16
|
|
|
17
17
|
## Props
|
|
18
|
-
- `items`: `KptMenuItem<T>[]`
|
|
18
|
+
- `items`: `KptMenuItem<T>[]` - the actions (`label`, `icon`, `disabled`)
|
|
19
19
|
- `direction`: `'up'` (default) | `'down'` | `'left'` | `'right'`
|
|
20
|
-
- `icon`: string (default `'plus'`)
|
|
21
|
-
- `ariaLabel`: string
|
|
22
|
-
- `onSelect(item)`
|
|
20
|
+
- `icon`: string (default `'plus'`) - the SCSS rotates it 45° when open
|
|
21
|
+
- `ariaLabel`: string - the closed-state label; without it `speedDial.actions`
|
|
22
|
+
- `onSelect(item)` - fired on pick; a disabled item fires nothing
|
|
23
23
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
24
24
|
|
|
25
25
|
## The label follows the state
|
|
@@ -37,6 +37,12 @@ present would swallow clicks meant for the page underneath.
|
|
|
37
37
|
## i18n
|
|
38
38
|
`speedDial.actions` and `common.close`; `locale` and `dictionary` override them per instance.
|
|
39
39
|
|
|
40
|
+
## Motion
|
|
41
|
+
The actions fan out from the button in a cascade - the nearest first, on a spring, from the side of the
|
|
42
|
+
button - and fold back in reverse order; the trigger icon turns on a spring. The container hides
|
|
43
|
+
(`visibility`) only after the last action, so the closing cascade is not cut off. Pressed, it squeezes slightly and springs back on release (shared mixin `styles/_press.scss`). Pure CSS; durations follow `--kpt-motion-scale`, so `enabled: false` turns it off, and it drops out
|
|
44
|
+
under "reduce motion".
|
|
45
|
+
|
|
40
46
|
## Tokens
|
|
41
47
|
The main button comes from `KptFab`; the actions use `--kpt-color-surface-raised` and
|
|
42
48
|
`--kpt-elevation-2`.
|
|
@@ -44,7 +50,7 @@ The main button comes from `KptFab`; the actions use `--kpt-color-surface-raised
|
|
|
44
50
|
## Accessibility
|
|
45
51
|
- The main button carries `aria-expanded` and `aria-controls` pointing at the actions container.
|
|
46
52
|
- Closed actions are `visibility: hidden` (switched after the fade-out), so they are out of the Tab
|
|
47
|
-
order and the accessibility tree
|
|
53
|
+
order and the accessibility tree - not just transparent.
|
|
48
54
|
- `Escape` anywhere in the dial closes it and returns focus to the main button.
|
|
49
55
|
- Every action is a `<button>` labelled with its own `label`, so the fan works from the keyboard even
|
|
50
56
|
when the actions show icons only.
|
|
@@ -12,7 +12,7 @@ export interface KptSpeedDialProps<T> extends Omit<ComponentPropsWithRef<'div'>,
|
|
|
12
12
|
onSelect?: (item: KptMenuItem<T>) => void;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Speed dial
|
|
15
|
+
* Speed dial - FAB rozwijający zestaw akcji wachlarzem. Buduje na `KptFab`.
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* <KptSpeedDial items={actions} direction="up" onSelect={onAction} />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useRef, useState } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
@@ -6,7 +7,7 @@ import { useKptMessages } from "../i18n/i18n-context.js";
|
|
|
6
7
|
import { KptFab } from "../fab/fab.js";
|
|
7
8
|
import { KptIcon } from "../icon/icon.js";
|
|
8
9
|
/**
|
|
9
|
-
* Speed dial
|
|
10
|
+
* Speed dial - FAB rozwijający zestaw akcji wachlarzem. Buduje na `KptFab`.
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
13
|
* <KptSpeedDial items={actions} direction="up" onSelect={onAction} />
|
|
@@ -30,5 +31,5 @@ export function KptSpeedDial({ items = [], direction = 'up', icon = 'plus', aria
|
|
|
30
31
|
onSelect?.(item);
|
|
31
32
|
setOpen(false);
|
|
32
33
|
};
|
|
33
|
-
return (_jsxs("div", { ref: hostRef, className: cn('kpt-speed-dial-host', className), onKeyDown: onKeyDown, ...rest, children: [_jsxs("div", { className: cn('kpt-speed-dial', open && 'is-open'), "data-direction": direction, children: [_jsx("div", { className: "kpt-speed-dial__actions", id: actionsId, children: items.map((item, index) => (_jsxs("button", { type: "button", className: "kpt-speed-dial__action", disabled: item.disabled, "aria-label": item.label, onClick: () => pick(item), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, item.label ? _jsx("span", { className: "kpt-speed-dial__label", children: item.label }) : null] }, index))) }), _jsx(KptFab, { "aria-label": open ? t('common.close') : (ariaLabel ?? t('speedDial.actions')), "aria-expanded": open, "aria-controls": actionsId, onClick: () => setOpen(!open), children: _jsx("span", { className: "kpt-speed-dial__trigger-icon", children: _jsx(KptIcon, { name: icon }) }) })] }), open ? _jsx("div", { className: "kpt-speed-dial__backdrop", onClick: () => setOpen(false) }) : null] }));
|
|
34
|
+
return (_jsxs("div", { ref: hostRef, className: cn('kpt-speed-dial-host', className), onKeyDown: onKeyDown, ...rest, children: [_jsxs("div", { className: cn('kpt-speed-dial', open && 'is-open'), "data-direction": direction, children: [_jsx("div", { className: "kpt-speed-dial__actions", id: actionsId, children: items.map((item, index) => (_jsxs("button", { type: "button", className: "kpt-speed-dial__action", disabled: item.disabled, "aria-label": item.label, onClick: () => pick(item), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, item.label ? _jsx("span", { className: "kpt-speed-dial__label", children: item.label }) : null] }, index))) }), _jsx(KptFab, { "aria-label": open ? t('common.close') : (ariaLabel ?? t('speedDial.actions')), "aria-expanded": open, "aria-controls": actionsId, onClick: () => setOpen(!open), children: _jsx("span", { className: "kpt-speed-dial__trigger-icon", children: _jsx(KptIcon, { name: icon }) }) })] }), open ? (_jsx("div", { className: "kpt-speed-dial__backdrop", onClick: () => setOpen(false) })) : null] }));
|
|
34
35
|
}
|
package/dist/spinner/llms.txt
CHANGED
|
@@ -9,13 +9,13 @@ A loading indicator. Import: `import { KptSpinner } from '@konce-pt/react';`
|
|
|
9
9
|
</span>
|
|
10
10
|
|
|
11
11
|
## Props
|
|
12
|
-
- `size`: string (default '1.5rem')
|
|
13
|
-
- `label`: string
|
|
14
|
-
- `locale`, `dictionary`
|
|
12
|
+
- `size`: string (default '1.5rem') - a CSS length, applied to width and height
|
|
13
|
+
- `label`: string - the accessibility label; omitted falls back to `spinner.label`
|
|
14
|
+
- `locale`, `dictionary` - i18n overrides for this component only
|
|
15
15
|
- `className`, `ref` and every other `<span>` prop go to the host
|
|
16
16
|
|
|
17
17
|
## The colour is inherited
|
|
18
|
-
The host sets `color: var(--kpt-color-primary)`, and the ring is drawn in `currentColor`
|
|
18
|
+
The host sets `color: var(--kpt-color-primary)`, and the ring is drawn in `currentColor` - so the
|
|
19
19
|
spinner is primary by default, and anything that sets `color` on the host changes it. Pass
|
|
20
20
|
`style={{ color: 'inherit' }}` (or a class) to take the colour of the text around it, e.g. inside a
|
|
21
21
|
filled chip. There is no colour prop, on purpose.
|
|
@@ -23,15 +23,15 @@ filled chip. There is no colour prop, on purpose.
|
|
|
23
23
|
## Examples
|
|
24
24
|
<KptSpinner />
|
|
25
25
|
<KptSpinner size="2rem" label="Loading data" />
|
|
26
|
-
<KptButton disabled><KptSpinner size="1em" /> Saving
|
|
26
|
+
<KptButton disabled><KptSpinner size="1em" /> Saving...</KptButton>
|
|
27
27
|
|
|
28
28
|
## Tokens
|
|
29
|
-
None of its own
|
|
29
|
+
None of its own - the colour is `--kpt-color-primary` on the host (drawn in `currentColor`), the
|
|
30
30
|
size comes from the prop, the ring width is 8% of the size (at least 2px), the speed from
|
|
31
31
|
`--kpt-motion-duration-*`.
|
|
32
32
|
|
|
33
33
|
## Accessibility
|
|
34
34
|
The ring is `aria-hidden`; next to it sits a visually hidden `.kpt-spinner__label` with
|
|
35
|
-
`role="status"`. Its text
|
|
35
|
+
`role="status"`. Its text - `label`, or `spinner.label` - is written a frame after the spinner
|
|
36
36
|
appears, because a status region that is born already filled in is skipped by most screen readers.
|
|
37
37
|
Under `prefers-reduced-motion` the rotation slows down instead of stopping.
|
|
@@ -10,7 +10,7 @@ export interface KptSpinnerProps extends Omit<ComponentPropsWithRef<'span'>, 'ch
|
|
|
10
10
|
*
|
|
11
11
|
* Pierścień jest dekoracją (`aria-hidden`); dla czytnika jest osobny, wizualnie ukryty region
|
|
12
12
|
* `role="status"` z etykietą. Tekst trafia do regionu klatkę po pojawieniu się spinnera: region,
|
|
13
|
-
* który powstaje od razu z treścią, większość czytników przemilcza
|
|
13
|
+
* który powstaje od razu z treścią, większość czytników przemilcza - ogłaszają dopiero zmianę.
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* <KptSpinner />
|
package/dist/spinner/spinner.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useEffect, useState } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
@@ -7,7 +8,7 @@ import { useKptMessages } from "../i18n/i18n-context.js";
|
|
|
7
8
|
*
|
|
8
9
|
* Pierścień jest dekoracją (`aria-hidden`); dla czytnika jest osobny, wizualnie ukryty region
|
|
9
10
|
* `role="status"` z etykietą. Tekst trafia do regionu klatkę po pojawieniu się spinnera: region,
|
|
10
|
-
* który powstaje od razu z treścią, większość czytników przemilcza
|
|
11
|
+
* który powstaje od razu z treścią, większość czytników przemilcza - ogłaszają dopiero zmianę.
|
|
11
12
|
*
|
|
12
13
|
* @example
|
|
13
14
|
* <KptSpinner />
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
# KptSplitButton (@konce-pt/react)
|
|
2
2
|
|
|
3
|
-
A split button
|
|
3
|
+
A split button - a primary action plus a dropdown of further actions.
|
|
4
4
|
Import: `import { KptSplitButton } from '@konce-pt/react';`
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<span class="kpt-split-button-host">
|
|
8
8
|
<div class="kpt-split-button" data-variant="filled">
|
|
9
9
|
<button class="kpt-split-button__main" type="button">Save</button>
|
|
10
|
-
<button class="kpt-split-button__toggle" type="button" aria-label="More actions"
|
|
10
|
+
<button class="kpt-split-button__toggle" type="button" aria-label="More actions">...chevron...</button>
|
|
11
11
|
</div>
|
|
12
12
|
</span>
|
|
13
13
|
<!-- while open, in a portal: -->
|
|
14
|
-
<div class="kpt-split-button__panel" role="menu"
|
|
14
|
+
<div class="kpt-split-button__panel" role="menu">...rows...</div>
|
|
15
15
|
|
|
16
16
|
## Props
|
|
17
|
-
- `variant`: `KptSplitButtonVariant` = 'filled' | 'tonal' | 'outline' | 'text' (default 'filled')
|
|
17
|
+
- `variant`: `KptSplitButtonVariant` = 'filled' | 'tonal' | 'outline' | 'text' (default 'filled') -
|
|
18
18
|
the subset of `KptButtonVariant` that has a style; `outline` and `text` use the `--kpt-button-outline-*`
|
|
19
19
|
and `--kpt-button-text-*` tokens, so they match `kpt-button` in the same row
|
|
20
|
-
- `items`: `KptMenuItem<T>[]`
|
|
21
|
-
- `disabled`: boolean
|
|
22
|
-
- `onPrimaryClick()`
|
|
23
|
-
- `onSelect(item)`
|
|
24
|
-
- `open` / `defaultOpen` / `onOpenChange`
|
|
25
|
-
- `children`
|
|
26
|
-
- `locale`, `dictionary`
|
|
20
|
+
- `items`: `KptMenuItem<T>[]` - the same shape as `KptMenu`
|
|
21
|
+
- `disabled`: boolean - disables both buttons
|
|
22
|
+
- `onPrimaryClick()` - the main action
|
|
23
|
+
- `onSelect(item)` - a pick from the menu
|
|
24
|
+
- `open` / `defaultOpen` / `onOpenChange` - the panel state
|
|
25
|
+
- `children` - the content of the main action
|
|
26
|
+
- `locale`, `dictionary` - i18n overrides for this component only
|
|
27
27
|
|
|
28
28
|
## The panel aligns to the right
|
|
29
29
|
The toggle sits on the right-hand side of the control, so the panel is anchored by its RIGHT edge
|
|
30
30
|
(`align="end"` on the overlay). Anchored to the left it would hang off the control instead of under
|
|
31
|
-
it
|
|
31
|
+
it - the same reasoning the Angular port encodes in its CDK position list.
|
|
32
32
|
|
|
33
33
|
## Shared rows
|
|
34
|
-
The panel renders the same rows as `KptMenu`
|
|
34
|
+
The panel renders the same rows as `KptMenu` - icons, descriptions, badges, separators, headers and
|
|
35
35
|
the `danger` modifier all behave identically, only the BEM block differs.
|
|
36
36
|
|
|
37
37
|
## i18n
|
|
@@ -39,9 +39,9 @@ The toggle's label comes from `splitButton.more` in the dictionary.
|
|
|
39
39
|
|
|
40
40
|
## Keyboard
|
|
41
41
|
The toggle is a menu button: `aria-haspopup="menu"`, a live `aria-expanded`, `aria-controls` while
|
|
42
|
-
open.
|
|
42
|
+
open. `ArrowDown` / `ArrowUp` on it open the menu on the first / last item; inside, `ArrowDown` / `ArrowUp` wrap, `Home` / `End`
|
|
43
43
|
jump, `Escape` / `Tab` close, and closing or picking returns focus to the toggle. Same rules as the
|
|
44
|
-
menu
|
|
44
|
+
menu - see the `KptMenu` docs.
|
|
45
45
|
|
|
46
46
|
## Examples
|
|
47
47
|
<KptSplitButton items={items} onPrimaryClick={save} onSelect={onItem}>Save</KptSplitButton>
|
|
@@ -53,6 +53,12 @@ menu — see the `KptMenu` docs.
|
|
|
53
53
|
{ label: 'Discard', value: 'discard', danger: true },
|
|
54
54
|
];
|
|
55
55
|
|
|
56
|
+
## Motion
|
|
57
|
+
Pressing either part squeezes the whole pill (one part alone would come apart from the other inside
|
|
58
|
+
the clipped container); the arrow turns over when the menu opens and the menu slides out from under the
|
|
59
|
+
button. Pure CSS; durations follow `--kpt-motion-scale`, so `enabled: false` turns it off, and it drops out
|
|
60
|
+
under "reduce motion".
|
|
61
|
+
|
|
56
62
|
## Tokens
|
|
57
63
|
The `--kpt-button-*` tokens of the chosen variant, plus `--kpt-color-surface-raised` and
|
|
58
64
|
`--kpt-elevation-3` for the panel.
|
|
@@ -2,7 +2,7 @@ import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
|
2
2
|
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
3
|
import type { KptMenuItem } from '../menu/menu-item.ts';
|
|
4
4
|
import type { KptButtonVariant } from '../button/button.tsx';
|
|
5
|
-
/** Warianty, które mają styl
|
|
5
|
+
/** Warianty, które mają styl - podzbiór `KptButtonVariant`. */
|
|
6
6
|
export type KptSplitButtonVariant = Extract<KptButtonVariant, 'filled' | 'tonal' | 'outline' | 'text'>;
|
|
7
7
|
export interface KptSplitButtonProps<T> extends Omit<ComponentPropsWithRef<'span'>, 'onSelect'>, KptI18nOverrides {
|
|
8
8
|
variant?: KptSplitButtonVariant;
|
|
@@ -19,7 +19,7 @@ export interface KptSplitButtonProps<T> extends Omit<ComponentPropsWithRef<'span
|
|
|
19
19
|
children?: ReactNode;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Przycisk dzielony
|
|
22
|
+
* Przycisk dzielony - akcja główna plus rozwijane menu dodatkowych akcji.
|
|
23
23
|
*
|
|
24
24
|
* Panel wyrównuje się do PRAWEJ krawędzi przycisku, nie do lewej: rozwijacz siedzi po prawej
|
|
25
25
|
* stronie kontrolki, więc menu otwierające się w lewo nie wychodzi poza nią.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
4
5
|
import { KptOverlay } from "../internal/overlay.js";
|
|
5
6
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
@@ -9,7 +10,7 @@ import { KptIcon } from "../icon/icon.js";
|
|
|
9
10
|
import { MenuRows } from "../menu/menu-rows.js";
|
|
10
11
|
import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
|
|
11
12
|
/**
|
|
12
|
-
* Przycisk dzielony
|
|
13
|
+
* Przycisk dzielony - akcja główna plus rozwijane menu dodatkowych akcji.
|
|
13
14
|
*
|
|
14
15
|
* Panel wyrównuje się do PRAWEJ krawędzi przycisku, nie do lewej: rozwijacz siedzi po prawej
|
|
15
16
|
* stronie kontrolki, więc menu otwierające się w lewo nie wychodzi poza nią.
|
|
@@ -20,8 +21,14 @@ import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
|
|
|
20
21
|
export function KptSplitButton({ variant = 'filled', items = [], disabled = false, onPrimaryClick, onSelect, open, defaultOpen = false, onOpenChange, locale, dictionary, className, children, ...rest }) {
|
|
21
22
|
const { t } = useKptMessages({ locale, dictionary });
|
|
22
23
|
const toggleRef = useRef(null);
|
|
24
|
+
/** Kotwica panelu - w stanie, bo czyta ją render; ref zostaje dla przywracania fokusu. */
|
|
25
|
+
const [toggleEl, setToggleEl] = useState(null);
|
|
26
|
+
const setToggle = useCallback((element) => {
|
|
27
|
+
toggleRef.current = element;
|
|
28
|
+
setToggleEl(element);
|
|
29
|
+
}, []);
|
|
23
30
|
const panelRef = useRef(null);
|
|
24
|
-
/** Którą pozycję skupić po otwarciu
|
|
31
|
+
/** Którą pozycję skupić po otwarciu - strzałka w górę na przycisku otwiera "od końca". */
|
|
25
32
|
const focusEdge = useRef('first');
|
|
26
33
|
const panelId = useKptId(undefined, 'kpt-split-button-menu');
|
|
27
34
|
const [isOpen, setOpen] = useControllableState({
|
|
@@ -41,7 +48,7 @@ export function KptSplitButton({ variant = 'filled', items = [], disabled = fals
|
|
|
41
48
|
});
|
|
42
49
|
return () => cancelAnimationFrame(frame);
|
|
43
50
|
}, [isOpen]);
|
|
44
|
-
/** Fokus wraca na strzałkę
|
|
51
|
+
/** Fokus wraca na strzałkę - inaczej po zniknięciu panelu spadłby na `<body>`. */
|
|
45
52
|
const closeAndRestoreFocus = () => {
|
|
46
53
|
close();
|
|
47
54
|
toggleRef.current?.focus();
|
|
@@ -67,8 +74,8 @@ export function KptSplitButton({ variant = 'filled', items = [], disabled = fals
|
|
|
67
74
|
onSelect?.(item);
|
|
68
75
|
closeAndRestoreFocus();
|
|
69
76
|
};
|
|
70
|
-
return (_jsxs("span", { className: cn('kpt-split-button-host', className), ...rest, children: [_jsxs("div", { className: "kpt-split-button", "data-variant": variant, children: [_jsx("button", { className: "kpt-split-button__main", type: "button", disabled: disabled, onClick: onPrimaryClick, children: children }), _jsx("button", { ref:
|
|
77
|
+
return (_jsxs("span", { className: cn('kpt-split-button-host', className), ...rest, children: [_jsxs("div", { className: "kpt-split-button", "data-variant": variant, children: [_jsx("button", { className: "kpt-split-button__main", type: "button", disabled: disabled, onClick: onPrimaryClick, children: children }), _jsx("button", { ref: setToggle, className: "kpt-split-button__toggle", type: "button", disabled: disabled, onClick: () => {
|
|
71
78
|
focusEdge.current = 'first';
|
|
72
79
|
setOpen(!isOpen);
|
|
73
|
-
}, onKeyDown: onToggleKeyDown, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, "aria-label": t('splitButton.more'), children: _jsx(KptIcon, { name: "chevron-down" }) })] }), _jsx(KptOverlay, { open: isOpen, anchor:
|
|
80
|
+
}, onKeyDown: onToggleKeyDown, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, "aria-label": t('splitButton.more'), children: _jsx(KptIcon, { name: "chevron-down" }) })] }), _jsx(KptOverlay, { open: isOpen, anchor: toggleEl, onClose: close, align: "end", children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-split-button__panel", role: "menu", tabIndex: -1, onKeyDown: onPanelKeyDown, children: _jsx(MenuRows, { items: items, block: "kpt-split-button", onPick: pick }) }) })] }));
|
|
74
81
|
}
|
package/dist/splitter/llms.txt
CHANGED
|
@@ -6,22 +6,22 @@ Import: `import { KptSplitter } from '@konce-pt/react';`
|
|
|
6
6
|
## DOM
|
|
7
7
|
<div class="kpt-splitter-host">
|
|
8
8
|
<div class="kpt-splitter" data-orientation="horizontal">
|
|
9
|
-
<div class="kpt-splitter__pane" id="kpt-splitter-start-r1" style="flex-basis:40%"
|
|
9
|
+
<div class="kpt-splitter__pane" id="kpt-splitter-start-r1" style="flex-basis:40%">...</div>
|
|
10
10
|
<div class="kpt-splitter__gutter" role="separator" tabindex="0" aria-orientation="vertical"
|
|
11
11
|
aria-valuenow="40" aria-valuemin="10" aria-valuemax="90"
|
|
12
12
|
aria-controls="kpt-splitter-start-r1" aria-label="Resize panes"></div>
|
|
13
|
-
<div class="kpt-splitter__pane" style="flex-basis:60%"
|
|
13
|
+
<div class="kpt-splitter__pane" style="flex-basis:60%">...</div>
|
|
14
14
|
</div>
|
|
15
15
|
</div>
|
|
16
16
|
|
|
17
17
|
## Props
|
|
18
18
|
- `orientation`: `'horizontal'` (default) | `'vertical'`
|
|
19
|
-
- `startSize` / `defaultStartSize` / `onStartSizeChange`
|
|
20
|
-
- `minSize`: number (percent, default 10)
|
|
21
|
-
- `ariaLabel`: string
|
|
22
|
-
- `ariaLabel`: string
|
|
23
|
-
- `ariaLabel`: string
|
|
24
|
-
- `ariaLabel`: string
|
|
19
|
+
- `startSize` / `defaultStartSize` / `onStartSizeChange` - the first pane's size in percent
|
|
20
|
+
- `minSize`: number (percent, default 10) - neither pane goes below it
|
|
21
|
+
- `ariaLabel`: string - the handle's name; empty = `splitter.resize` from the dictionary
|
|
22
|
+
- `ariaLabel`: string - the handle's name; empty = `splitter.resize` from the dictionary
|
|
23
|
+
- `ariaLabel`: string - the handle's name; empty = `splitter.resize` from the dictionary
|
|
24
|
+
- `ariaLabel`: string - the handle's name; empty = `splitter.resize` from the dictionary
|
|
25
25
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
26
26
|
|
|
27
27
|
## Panes
|
|
@@ -39,16 +39,16 @@ pointer outruns a 6px strip, and a handle-bound listener would drop the drag aft
|
|
|
39
39
|
<KptSplitter.End>Right</KptSplitter.End>
|
|
40
40
|
</KptSplitter>
|
|
41
41
|
|
|
42
|
-
<KptSplitter orientation="vertical" defaultStartSize={30} minSize={20}
|
|
42
|
+
<KptSplitter orientation="vertical" defaultStartSize={30} minSize={20}>...</KptSplitter>
|
|
43
43
|
|
|
44
44
|
## Tokens
|
|
45
|
-
The handle `--kpt-color-border`
|
|
45
|
+
The handle `--kpt-color-border` -> `--kpt-color-primary` on hover and focus; the frame
|
|
46
46
|
`--kpt-color-border` with `--kpt-radius-md`.
|
|
47
47
|
|
|
48
48
|
## Accessibility
|
|
49
49
|
The handle is a focusable `role="separator"` (the WAI-ARIA window splitter): `aria-valuenow`,
|
|
50
50
|
`aria-valuemin`/`aria-valuemax` (from `minSize`), `aria-controls` pointing at the first pane, and a
|
|
51
51
|
name from `ariaLabel` or `splitter.resize` in the dictionary. Arrow keys resize by 2%, `Home`/`End`
|
|
52
|
-
jump to the minimum/maximum. `aria-orientation` describes the handle's line, not the layout
|
|
52
|
+
jump to the minimum/maximum. `aria-orientation` describes the handle's line, not the layout -
|
|
53
53
|
side-by-side panes have a vertical handle. The host takes `height: 100%`, so a height set on the
|
|
54
54
|
parent reaches the panes.
|
|
@@ -15,7 +15,7 @@ export declare namespace KptSplitterEnd {
|
|
|
15
15
|
}
|
|
16
16
|
export interface KptSplitterProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'>, KptI18nOverrides {
|
|
17
17
|
orientation?: KptSplitterOrientation;
|
|
18
|
-
/** Rozmiar pierwszego panelu w procentach (0
|
|
18
|
+
/** Rozmiar pierwszego panelu w procentach (0-100). */
|
|
19
19
|
startSize?: number;
|
|
20
20
|
defaultStartSize?: number;
|
|
21
21
|
onStartSizeChange?: (size: number) => void;
|
|
@@ -29,9 +29,9 @@ export interface KptSplitterProps extends Omit<ComponentPropsWithRef<'div'>, 'on
|
|
|
29
29
|
* Dwa panele z przeciąganym uchwytem. `horizontal` stawia je obok siebie, `vertical` jeden pod
|
|
30
30
|
* drugim.
|
|
31
31
|
*
|
|
32
|
-
* Uchwyt to `role="separator"` z wartością (wzorzec WAI-ARIA
|
|
32
|
+
* Uchwyt to `role="separator"` z wartością (wzorzec WAI-ARIA "window splitter"): strzałki
|
|
33
33
|
* przesuwają go o 2%, `Home`/`End` dosuwają do minimum i maksimum. `aria-orientation` opisuje
|
|
34
|
-
* linię uchwytu, nie układ
|
|
34
|
+
* linię uchwytu, nie układ - przy panelach obok siebie linia jest pionowa.
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
37
|
* <KptSplitter startSize={size} onStartSizeChange={setSize}>
|