@konce-pt/react 0.11.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -64
- package/dist/accordion/accordion.d.ts +14 -6
- package/dist/accordion/accordion.js +25 -17
- package/dist/accordion/llms.txt +22 -10
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert/alert.js +3 -2
- package/dist/alert/llms.txt +10 -9
- package/dist/app-shell/app-shell.d.ts +14 -14
- package/dist/app-shell/app-shell.js +22 -15
- package/dist/app-shell/llms.txt +16 -15
- package/dist/auth/auth-types.d.ts +6 -6
- package/dist/auth/auth.d.ts +2 -2
- package/dist/auth/auth.js +24 -15
- package/dist/auth/llms.txt +12 -11
- package/dist/autocomplete/autocomplete.d.ts +19 -6
- package/dist/autocomplete/autocomplete.js +32 -11
- package/dist/autocomplete/llms.txt +19 -5
- package/dist/avatar/avatar.d.ts +6 -6
- package/dist/avatar/avatar.js +6 -5
- package/dist/avatar/llms.txt +10 -10
- package/dist/avatar-group/avatar-group.d.ts +4 -4
- package/dist/avatar-group/avatar-group.js +4 -3
- package/dist/avatar-group/llms.txt +8 -8
- package/dist/backdrop/backdrop.d.ts +7 -26
- package/dist/backdrop/backdrop.js +32 -27
- package/dist/backdrop/llms.txt +27 -27
- package/dist/badge/badge.d.ts +3 -3
- package/dist/badge/badge.js +1 -1
- package/dist/badge/llms.txt +11 -11
- package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
- package/dist/bottom-sheet/bottom-sheet.js +5 -4
- package/dist/bottom-sheet/llms.txt +11 -8
- package/dist/breadcrumb/breadcrumb.d.ts +8 -2
- package/dist/breadcrumb/breadcrumb.js +11 -3
- package/dist/breadcrumb/llms.txt +10 -2
- package/dist/button/button.d.ts +3 -3
- package/dist/button/button.js +10 -9
- package/dist/button/llms.txt +27 -19
- package/dist/button-group/button-group.d.ts +18 -5
- package/dist/button-group/button-group.js +54 -6
- package/dist/button-group/llms.txt +27 -18
- package/dist/card/card.d.ts +8 -8
- package/dist/card/card.js +10 -9
- package/dist/card/llms.txt +20 -20
- package/dist/carousel/carousel.d.ts +6 -6
- package/dist/carousel/carousel.js +8 -5
- package/dist/carousel/llms.txt +10 -10
- package/dist/charts/chart-legend.d.ts +3 -3
- package/dist/charts/chart-legend.js +2 -1
- package/dist/charts/chart-tooltip.d.ts +3 -3
- package/dist/charts/chart-tooltip.js +1 -1
- package/dist/charts/chart.d.ts +4 -3
- package/dist/charts/chart.js +18 -10
- package/dist/charts/llms.txt +10 -7
- package/dist/charts-entry/public-api.js +2 -2
- package/dist/chat/chat.d.ts +17 -10
- package/dist/chat/chat.js +77 -23
- package/dist/chat/llms.txt +39 -15
- package/dist/chat-composer/chat-composer.d.ts +20 -7
- package/dist/chat-composer/chat-composer.js +29 -7
- package/dist/chat-composer/llms.txt +20 -11
- package/dist/chat-dock/chat-dock.d.ts +11 -4
- package/dist/chat-dock/chat-dock.js +10 -6
- package/dist/chat-dock/llms.txt +15 -14
- package/dist/chat-entry/public-api.js +1 -1
- package/dist/chat-message/chat-message.d.ts +12 -5
- package/dist/chat-message/chat-message.js +19 -8
- package/dist/chat-message/llms.txt +16 -15
- package/dist/chat-typing/chat-typing.d.ts +2 -2
- package/dist/chat-typing/chat-typing.js +4 -3
- package/dist/chat-typing/llms.txt +6 -6
- package/dist/checkbox/checkbox.d.ts +13 -6
- package/dist/checkbox/checkbox.js +31 -5
- package/dist/checkbox/llms.txt +26 -11
- package/dist/chip/chip.d.ts +4 -4
- package/dist/chip/chip.js +3 -2
- package/dist/chip/llms.txt +11 -11
- package/dist/chips-input/chips-input.d.ts +6 -4
- package/dist/chips-input/chips-input.js +47 -12
- package/dist/chips-input/llms.txt +18 -8
- package/dist/clock/clock.d.ts +11 -6
- package/dist/clock/clock.js +38 -8
- package/dist/clock/llms.txt +12 -8
- package/dist/color-picker/color-picker.d.ts +9 -5
- package/dist/color-picker/color-picker.js +37 -18
- package/dist/color-picker/llms.txt +8 -5
- package/dist/confirm/confirm-container.d.ts +3 -3
- package/dist/confirm/confirm-container.js +6 -5
- package/dist/confirm/confirm-store.d.ts +4 -4
- package/dist/confirm/confirm-store.js +11 -5
- package/dist/confirm/llms.txt +8 -7
- package/dist/context-menu/context-menu.d.ts +1 -1
- package/dist/context-menu/context-menu.js +37 -14
- package/dist/context-menu/llms.txt +10 -7
- package/dist/data-table/data-table-types.d.ts +5 -5
- package/dist/data-table/data-table.d.ts +37 -5
- package/dist/data-table/data-table.js +426 -119
- package/dist/data-table/export-csv.d.ts +3 -3
- package/dist/data-table/export-csv.js +8 -10
- package/dist/data-table/llms.txt +127 -79
- package/dist/data-view/data-view.d.ts +13 -5
- package/dist/data-view/data-view.js +68 -6
- package/dist/data-view/llms.txt +29 -10
- package/dist/date-range/date-range.d.ts +20 -8
- package/dist/date-range/date-range.js +86 -63
- package/dist/date-range/llms.txt +32 -18
- package/dist/datepicker/datepicker.d.ts +22 -8
- package/dist/datepicker/datepicker.js +103 -71
- package/dist/datepicker/llms.txt +36 -22
- package/dist/dialog/dialog.d.ts +4 -4
- package/dist/dialog/dialog.js +32 -11
- package/dist/dialog/llms.txt +13 -10
- package/dist/divider/divider.d.ts +7 -1
- package/dist/divider/divider.js +3 -2
- package/dist/divider/llms.txt +4 -3
- package/dist/drawer/drawer.d.ts +9 -4
- package/dist/drawer/drawer.js +5 -4
- package/dist/drawer/llms.txt +13 -10
- package/dist/empty/empty.d.ts +2 -2
- package/dist/empty/empty.js +1 -1
- package/dist/empty/llms.txt +9 -9
- package/dist/fab/fab.d.ts +1 -1
- package/dist/fab/fab.js +1 -1
- package/dist/fab/llms.txt +10 -6
- package/dist/fieldset/fieldset.d.ts +18 -4
- package/dist/fieldset/fieldset.js +12 -6
- package/dist/fieldset/llms.txt +26 -9
- package/dist/file-upload/file-upload.d.ts +8 -2
- package/dist/file-upload/file-upload.js +22 -11
- package/dist/file-upload/llms.txt +12 -9
- package/dist/form-field/form-field-context.d.ts +4 -4
- package/dist/form-field/form-field.d.ts +12 -4
- package/dist/form-field/form-field.js +27 -6
- package/dist/form-field/llms.txt +25 -11
- package/dist/galleria/galleria.d.ts +3 -3
- package/dist/galleria/galleria.js +9 -6
- package/dist/galleria/llms.txt +7 -7
- package/dist/grid/col.d.ts +4 -4
- package/dist/grid/col.js +2 -2
- package/dist/grid/flex.d.ts +3 -3
- package/dist/grid/flex.js +1 -1
- package/dist/grid/grid.d.ts +7 -7
- package/dist/grid/grid.js +3 -3
- package/dist/grid/layout.d.ts +2 -2
- package/dist/grid/layout.js +2 -2
- package/dist/grid/llms.txt +15 -15
- package/dist/grid-entry/public-api.js +1 -1
- package/dist/i18n/i18n-context.d.ts +6 -6
- package/dist/i18n/i18n-context.js +27 -5
- package/dist/icon/icon-registry.d.ts +3 -3
- package/dist/icon/icon-registry.js +3 -3
- package/dist/icon/icon.d.ts +4 -4
- package/dist/icon/icon.js +10 -7
- package/dist/icon/llms.txt +13 -13
- package/dist/icon-button/icon-button.d.ts +2 -2
- package/dist/icon-button/icon-button.js +1 -1
- package/dist/icon-button/llms.txt +9 -5
- package/dist/icons-entry/public-api.d.ts +2 -2
- package/dist/icons-entry/public-api.js +3 -3
- package/dist/image/image.js +5 -5
- package/dist/image/llms.txt +13 -13
- package/dist/input/input.d.ts +18 -5
- package/dist/input/input.js +22 -6
- package/dist/input/llms.txt +25 -11
- package/dist/input-mask/input-mask.d.ts +7 -2
- package/dist/input-mask/input-mask.js +17 -43
- package/dist/input-mask/llms.txt +8 -5
- package/dist/input-number/input-number.d.ts +11 -9
- package/dist/input-number/input-number.js +25 -21
- package/dist/input-number/llms.txt +17 -14
- package/dist/input-otp/input-otp.d.ts +18 -5
- package/dist/input-otp/input-otp.js +48 -24
- package/dist/input-otp/llms.txt +18 -7
- package/dist/internal/calendar-focus.d.ts +1 -1
- package/dist/internal/calendar-focus.js +3 -3
- package/dist/internal/cn.d.ts +1 -1
- package/dist/internal/mask.d.ts +14 -0
- package/dist/internal/mask.js +62 -0
- package/dist/internal/number-group.d.ts +22 -0
- package/dist/internal/number-group.js +53 -0
- package/dist/internal/option-key.d.ts +6 -0
- package/dist/internal/option-key.js +8 -0
- package/dist/internal/option-nav.d.ts +4 -4
- package/dist/internal/option-nav.js +5 -5
- package/dist/internal/overlay-container.js +1 -1
- package/dist/internal/overlay.d.ts +3 -3
- package/dist/internal/overlay.js +40 -10
- package/dist/internal/password-strength.d.ts +6 -0
- package/dist/internal/password-strength.js +74 -0
- package/dist/internal/roving.d.ts +2 -2
- package/dist/internal/roving.js +3 -3
- package/dist/internal/scroll-lock.d.ts +6 -0
- package/dist/internal/scroll-lock.js +35 -0
- package/dist/internal/slot-children.d.ts +13 -0
- package/dist/internal/slot-children.js +31 -0
- package/dist/internal/slot.d.ts +3 -3
- package/dist/internal/slot.js +2 -2
- package/dist/internal/step.d.ts +12 -0
- package/dist/internal/step.js +31 -0
- package/dist/internal/tween.d.ts +5 -5
- package/dist/internal/tween.js +7 -8
- package/dist/internal/types.d.ts +2 -2
- package/dist/internal/use-breakpoint.d.ts +2 -2
- package/dist/internal/use-breakpoint.js +4 -4
- package/dist/internal/use-controllable-state.d.ts +5 -0
- package/dist/internal/use-controllable-state.js +25 -4
- package/dist/internal/use-id.d.ts +2 -2
- package/dist/internal/use-id.js +2 -2
- package/dist/internal/use-modal-focus.d.ts +2 -1
- package/dist/internal/use-modal-focus.js +14 -3
- package/dist/knob/knob.d.ts +7 -4
- package/dist/knob/knob.js +27 -22
- package/dist/knob/llms.txt +18 -11
- package/dist/listbox/listbox.d.ts +8 -6
- package/dist/listbox/listbox.js +37 -17
- package/dist/listbox/llms.txt +12 -9
- package/dist/loader/llms.txt +56 -0
- package/dist/loader/loader.d.ts +49 -0
- package/dist/loader/loader.js +68 -0
- package/dist/map/llms.txt +30 -23
- package/dist/map/map-create-dialog.d.ts +4 -4
- package/dist/map/map-create-dialog.js +36 -28
- package/dist/map/map-hours-field.d.ts +4 -4
- package/dist/map/map-hours-field.js +8 -7
- package/dist/map/map-image-field.d.ts +2 -2
- package/dist/map/map-image-field.js +6 -5
- package/dist/map/map-legend.d.ts +4 -4
- package/dist/map/map-legend.js +3 -2
- package/dist/map/map-poi-card.d.ts +3 -3
- package/dist/map/map-poi-card.js +10 -9
- package/dist/map/map-search.d.ts +17 -6
- package/dist/map/map-search.js +70 -43
- package/dist/map/map.d.ts +25 -13
- package/dist/map/map.js +86 -57
- package/dist/map/ports.d.ts +9 -9
- package/dist/map/ports.js +6 -6
- package/dist/map-entry/public-api.js +2 -2
- package/dist/megamenu/llms.txt +18 -7
- package/dist/megamenu/megamenu.d.ts +12 -6
- package/dist/megamenu/megamenu.js +23 -14
- package/dist/mention/llms.txt +15 -15
- package/dist/mention/mention.d.ts +5 -5
- package/dist/mention/mention.js +2 -2
- package/dist/mention/mentions.d.ts +1 -1
- package/dist/mention/mentions.js +1 -1
- package/dist/menu/llms.txt +12 -12
- package/dist/menu/menu-item.d.ts +4 -4
- package/dist/menu/menu-keys.d.ts +2 -2
- package/dist/menu/menu-keys.js +5 -5
- package/dist/menu/menu-rows.js +1 -0
- package/dist/menu/menu.d.ts +2 -2
- package/dist/menu/menu.js +15 -8
- package/dist/menubar/llms.txt +19 -8
- package/dist/menubar/menubar.d.ts +11 -5
- package/dist/menubar/menubar.js +23 -11
- package/dist/meter-group/llms.txt +12 -12
- package/dist/meter-group/meter-group.d.ts +2 -2
- package/dist/meter-group/meter-group.js +2 -1
- package/dist/motion/motion-context.d.ts +22 -0
- package/dist/motion/motion-context.js +28 -0
- package/dist/order-list/llms.txt +24 -9
- package/dist/order-list/order-list.d.ts +12 -4
- package/dist/order-list/order-list.js +123 -25
- package/dist/paginator/llms.txt +8 -8
- package/dist/paginator/paginator.js +7 -4
- package/dist/panel/llms.txt +25 -13
- package/dist/panel/panel.d.ts +11 -3
- package/dist/panel/panel.js +12 -7
- package/dist/password/llms.txt +19 -7
- package/dist/password/password.d.ts +2 -2
- package/dist/password/password.js +27 -16
- package/dist/peek/llms.txt +11 -11
- package/dist/peek/peek.d.ts +6 -6
- package/dist/peek/peek.js +41 -19
- package/dist/pick-list/llms.txt +35 -12
- package/dist/pick-list/pick-list.d.ts +12 -4
- package/dist/pick-list/pick-list.js +128 -24
- package/dist/popover/llms.txt +13 -10
- package/dist/popover/popover.d.ts +6 -4
- package/dist/popover/popover.js +14 -7
- package/dist/progress/llms.txt +17 -17
- package/dist/progress/progress.d.ts +7 -7
- package/dist/progress/progress.js +7 -6
- package/dist/public-api.d.ts +16 -4
- package/dist/public-api.js +13 -7
- package/dist/radio-group/llms.txt +16 -6
- package/dist/radio-group/radio-group.d.ts +12 -3
- package/dist/radio-group/radio-group.js +23 -4
- package/dist/rating/llms.txt +20 -13
- package/dist/rating/rating-pointer.d.ts +16 -0
- package/dist/rating/rating-pointer.js +26 -0
- package/dist/rating/rating.d.ts +6 -6
- package/dist/rating/rating.js +77 -12
- package/dist/rich-text/lists.d.ts +2 -2
- package/dist/rich-text/lists.js +7 -7
- package/dist/rich-text/llms.txt +35 -12
- package/dist/rich-text/rich-text.d.ts +13 -14
- package/dist/rich-text/rich-text.js +311 -142
- package/dist/rich-text/sanitize.d.ts +11 -2
- package/dist/rich-text/sanitize.js +80 -32
- package/dist/rich-text/tables.d.ts +3 -3
- package/dist/rich-text/tables.js +3 -3
- package/dist/roadmap/llms.txt +23 -17
- package/dist/roadmap/roadmap.d.ts +6 -6
- package/dist/roadmap/roadmap.js +102 -25
- package/dist/roadmap-entry/public-api.js +2 -2
- package/dist/scroll-top/llms.txt +6 -6
- package/dist/scroll-top/scroll-top.d.ts +1 -1
- package/dist/scroll-top/scroll-top.js +2 -1
- package/dist/select/llms.txt +22 -12
- package/dist/select/select.d.ts +10 -8
- package/dist/select/select.js +87 -47
- package/dist/shared/types.d.ts +22 -1
- package/dist/shared/types.js +9 -1
- package/dist/sidenav/llms.txt +9 -9
- package/dist/sidenav/sidenav.d.ts +2 -3
- package/dist/sidenav/sidenav.js +5 -4
- package/dist/skeleton/llms.txt +3 -3
- package/dist/skeleton/skeleton.d.ts +1 -1
- package/dist/skeleton/skeleton.js +1 -1
- package/dist/slider/llms.txt +34 -12
- package/dist/slider/slider-drag.d.ts +26 -0
- package/dist/slider/slider-drag.js +79 -0
- package/dist/slider/slider.d.ts +8 -5
- package/dist/slider/slider.js +38 -8
- package/dist/speech/llms.txt +97 -0
- package/dist/speech/speech-button.d.ts +44 -0
- package/dist/speech/speech-button.js +86 -0
- package/dist/speech/speech-wave.d.ts +19 -0
- package/dist/speech/speech-wave.js +16 -0
- package/dist/speech/use-speech-recognition.d.ts +81 -0
- package/dist/speech/use-speech-recognition.js +179 -0
- package/dist/speed-dial/llms.txt +14 -8
- package/dist/speed-dial/speed-dial.d.ts +1 -1
- package/dist/speed-dial/speed-dial.js +3 -2
- package/dist/spinner/llms.txt +7 -7
- package/dist/spinner/spinner.d.ts +1 -1
- package/dist/spinner/spinner.js +2 -1
- package/dist/split-button/llms.txt +21 -15
- package/dist/split-button/split-button.d.ts +2 -2
- package/dist/split-button/split-button.js +13 -6
- package/dist/splitter/llms.txt +11 -11
- package/dist/splitter/splitter.d.ts +3 -3
- package/dist/splitter/splitter.js +25 -10
- package/dist/stepper/llms.txt +35 -13
- package/dist/stepper/stepper.d.ts +6 -6
- package/dist/stepper/stepper.js +60 -13
- package/dist/switch/llms.txt +15 -5
- package/dist/switch/switch.d.ts +10 -3
- package/dist/switch/switch.js +18 -4
- package/dist/switch-group/llms.txt +11 -8
- package/dist/switch-group/switch-group.d.ts +6 -4
- package/dist/switch-group/switch-group.js +9 -7
- package/dist/tabs/llms.txt +12 -9
- package/dist/tabs/tabs.d.ts +5 -5
- package/dist/tabs/tabs.js +36 -20
- package/dist/textarea/llms.txt +23 -12
- package/dist/textarea/textarea.d.ts +19 -6
- package/dist/textarea/textarea.js +22 -7
- package/dist/timeline/llms.txt +4 -4
- package/dist/timeline/timeline.d.ts +1 -1
- package/dist/timeline/timeline.js +1 -1
- package/dist/toast/llms.txt +50 -17
- package/dist/toast/toast-container.d.ts +9 -3
- package/dist/toast/toast-container.js +18 -9
- package/dist/toast/toast-store.d.ts +42 -2
- package/dist/toast/toast-store.js +36 -1
- package/dist/toolbar/llms.txt +7 -7
- package/dist/toolbar/toolbar.d.ts +3 -3
- package/dist/toolbar/toolbar.js +2 -2
- package/dist/tooltip/llms.txt +14 -12
- package/dist/tooltip/tooltip.d.ts +5 -4
- package/dist/tooltip/tooltip.js +100 -41
- package/dist/tree/llms.txt +25 -11
- package/dist/tree/tree-keys.d.ts +5 -5
- package/dist/tree/tree-keys.js +7 -7
- package/dist/tree/tree.d.ts +17 -5
- package/dist/tree/tree.js +62 -20
- package/dist/update/llms.txt +54 -0
- package/dist/update/update.d.ts +49 -0
- package/dist/update/update.js +82 -0
- package/package.json +18 -15
|
@@ -1,53 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, useState } from 'react';
|
|
2
4
|
import { cn } from "../internal/cn.js";
|
|
3
5
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
4
6
|
import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
5
7
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
6
8
|
/**
|
|
7
|
-
* Pole kodu jednorazowego (OTP/PIN)
|
|
8
|
-
* i wklejanie całego kodu naraz. Wartością
|
|
9
|
+
* Pole kodu jednorazowego (OTP/PIN) - N osobnych pól, automatyczne przejście do następnego
|
|
10
|
+
* i wklejanie całego kodu naraz. Wartością są wpisane znaki **bez dziur** (`'13'`, nie `'1 3'`), więc
|
|
11
|
+
* walidator długości i backend widzą tyle znaków, ile naprawdę wpisano.
|
|
9
12
|
*
|
|
10
13
|
* @example
|
|
11
14
|
* <KptInputOtp value={code} onValueChange={setCode} length={6} integerOnly />
|
|
15
|
+
* <KptInputOtp value={code} onValueChange={setCode} length={9} groupSize={3} />
|
|
12
16
|
*/
|
|
13
|
-
export function KptInputOtp({ value, defaultValue = '', onValueChange, length = 6, integerOnly = false, id, ariaLabel = null, disabled = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
|
|
17
|
+
export function KptInputOtp({ value, defaultValue = '', onValueChange, length = 6, groupSize = 0, groupSeparator = '-', integerOnly = false, id, ariaLabel = null, disabled = false, readOnly = false, required = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
|
|
14
18
|
const { t } = useKptMessages({ locale, dictionary });
|
|
15
19
|
const field = useKptFieldA11y(id, 'kpt-input-otp');
|
|
16
20
|
const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
|
|
17
21
|
const showInvalid = invalid && (touched ?? true);
|
|
18
|
-
const charAt = (index) => current[index] ?? '';
|
|
19
22
|
/*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
+
* Komórki trzymają układ osobno od wartości: wyczyszczenie środkowej zostawia w niej pustkę,
|
|
24
|
+
* zamiast przesuwać resztę kodu w lewo, a wartość to same znaki. Zmiana wartości z zewnątrz
|
|
25
|
+
* (inna niż złożenie bieżących komórek) układa znaki od początku - wzorzec "poprzednia
|
|
26
|
+
* wartość w stanie", bez efektu.
|
|
23
27
|
*/
|
|
28
|
+
const toCells = (text) => Array.from({ length }, (_, index) => text[index] ?? '');
|
|
29
|
+
const [cells, setCells] = useState(() => toCells(current));
|
|
30
|
+
const inSync = cells.length === length && cells.join('') === current;
|
|
31
|
+
if (!inSync)
|
|
32
|
+
setCells(toCells(current));
|
|
33
|
+
const shown = inSync ? cells : toCells(current);
|
|
34
|
+
const charAt = (index) => shown[index] ?? '';
|
|
35
|
+
/** Zapis komórek i złożonej z nich wartości - jedno miejsce, żeby układ i model się nie rozjechały. */
|
|
36
|
+
const commitCells = (next) => {
|
|
37
|
+
setCells(next);
|
|
38
|
+
setCurrent(next.join(''));
|
|
39
|
+
};
|
|
24
40
|
const setChar = (index, char) => {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
const next = [...shown];
|
|
42
|
+
next[index] = char;
|
|
43
|
+
commitCells(next);
|
|
28
44
|
};
|
|
45
|
+
/** Następna/poprzednia komórka - po polach, nie po rodzeństwie, bo między grupami stoi separator. */
|
|
29
46
|
const focusSibling = (el, direction) => {
|
|
30
|
-
const
|
|
31
|
-
|
|
47
|
+
const cells = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
|
|
48
|
+
cells[cells.indexOf(el) + direction]?.focus();
|
|
32
49
|
};
|
|
33
|
-
/**
|
|
50
|
+
/** Czy za komórką `index` kończy się grupa (a nie cały kod). */
|
|
51
|
+
const group = Math.floor(groupSize);
|
|
52
|
+
const separatorAfter = (index) => group >= 1 && (index + 1) % group === 0 && index < length - 1;
|
|
53
|
+
/** Wpisuje `text` od komórki `start` (bez spacji i - przy `integerOnly` - bez nie-cyfr). */
|
|
34
54
|
const fillFrom = (start, text, el) => {
|
|
35
55
|
let chars = text.replace(/\s/g, '');
|
|
36
56
|
if (integerOnly)
|
|
37
57
|
chars = chars.replace(/\D/g, '');
|
|
38
|
-
const arr =
|
|
58
|
+
const arr = [...shown];
|
|
39
59
|
for (let k = 0; k < chars.length && start + k < length; k += 1)
|
|
40
60
|
arr[start + k] = chars[k];
|
|
41
|
-
|
|
42
|
-
// Fokus na pierwszą pustą komórkę, a przy komplecie
|
|
43
|
-
const
|
|
44
|
-
const empty = arr.findIndex((char) => char === '
|
|
45
|
-
|
|
61
|
+
commitCells(arr);
|
|
62
|
+
// Fokus na pierwszą pustą komórkę, a przy komplecie - na ostatnią.
|
|
63
|
+
const inputs = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
|
|
64
|
+
const empty = arr.findIndex((char) => char === '');
|
|
65
|
+
inputs[empty >= 0 ? empty : inputs.length - 1]?.focus();
|
|
46
66
|
};
|
|
47
67
|
const onInput = (index, event) => {
|
|
48
68
|
const el = event.target;
|
|
69
|
+
if (readOnly)
|
|
70
|
+
return;
|
|
49
71
|
// Kilka znaków naraz to autouzupełnienie kodu z SMS (`one-time-code`) albo wklejenie przez
|
|
50
|
-
// klawiaturę ekranową
|
|
72
|
+
// klawiaturę ekranową - rozkładamy je po komórkach od bieżącej. Dwa znaki w zajętej komórce
|
|
51
73
|
// to zwykłe nadpisanie: stary znak + nowy.
|
|
52
74
|
if (el.value.length > 1 && !(el.value.length === 2 && charAt(index))) {
|
|
53
75
|
const text = el.value;
|
|
@@ -67,7 +89,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
67
89
|
};
|
|
68
90
|
const onKeyDown = (index, event) => {
|
|
69
91
|
const el = event.currentTarget;
|
|
70
|
-
if (event.key === 'Backspace' && !charAt(index))
|
|
92
|
+
if (event.key === 'Backspace' && !charAt(index) && !readOnly)
|
|
71
93
|
focusSibling(el, -1);
|
|
72
94
|
else if (event.key === 'ArrowLeft')
|
|
73
95
|
focusSibling(el, -1);
|
|
@@ -76,13 +98,15 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
76
98
|
};
|
|
77
99
|
const onPaste = (event) => {
|
|
78
100
|
event.preventDefault();
|
|
101
|
+
if (readOnly)
|
|
102
|
+
return;
|
|
79
103
|
fillFrom(0, event.clipboardData.getData('text'), event.currentTarget);
|
|
80
104
|
};
|
|
81
|
-
/**
|
|
105
|
+
/** "Dotknięcie" dopiero przy wyjściu fokusu z całej grupy, nie przy przejściu między komórkami. */
|
|
82
106
|
const onGroupBlur = (event) => {
|
|
83
107
|
const next = event.relatedTarget;
|
|
84
108
|
if (!next || !event.currentTarget.contains(next))
|
|
85
109
|
onTouch?.();
|
|
86
110
|
};
|
|
87
|
-
return (_jsx("div", { className: cn('kpt-input-otp-host', className), ...rest, children: _jsx("div", { className: cn('kpt-input-otp', showInvalid && 'kpt-input-otp--invalid'), role: "group", "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onBlur: onGroupBlur, children: Array.from({ length }, (_, index) => (_jsx("input", { className: "kpt-input-otp__cell", id: index === 0 ? field.id : undefined, "aria-label": t('inputOtp.cell', { index: index + 1, count: length }), "aria-invalid": showInvalid || undefined, type: "text", inputMode: integerOnly ? 'numeric' : 'text', autoComplete: index === 0 ? 'one-time-code' : 'off', value: charAt(index), disabled: disabled, onChange: (event) => onInput(index, event), onKeyDown: (event) => onKeyDown(index, event), onPaste: onPaste, onFocus: (event) => event.target.select() }, index))) }) }));
|
|
111
|
+
return (_jsx("div", { className: cn('kpt-input-otp-host', className), ...rest, children: _jsx("div", { className: cn('kpt-input-otp', showInvalid && 'kpt-input-otp--invalid'), role: "group", "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onBlur: onGroupBlur, children: Array.from({ length }, (_, index) => (_jsxs(Fragment, { children: [_jsx("input", { className: "kpt-input-otp__cell", id: index === 0 ? field.id : undefined, "aria-label": t('inputOtp.cell', { index: index + 1, count: length }), "aria-invalid": showInvalid || undefined, type: "text", inputMode: integerOnly ? 'numeric' : 'text', autoComplete: index === 0 ? 'one-time-code' : 'off', value: charAt(index), disabled: disabled, readOnly: readOnly, "aria-required": required || undefined, onChange: (event) => onInput(index, event), onKeyDown: (event) => onKeyDown(index, event), onPaste: onPaste, onFocus: (event) => event.target.select() }), separatorAfter(index) ? (_jsx("span", { className: "kpt-input-otp__sep", "aria-hidden": "true", children: groupSeparator })) : null] }, index))) }) }));
|
|
88
112
|
}
|
package/dist/input-otp/llms.txt
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# KptInputOtp (@konce-pt/react)
|
|
2
2
|
|
|
3
|
-
A one-time code field (OTP / PIN)
|
|
3
|
+
A one-time code field (OTP / PIN) - N separate boxes, auto-advance and paste.
|
|
4
4
|
Import: `import { KptInputOtp } from '@konce-pt/react';`
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<div class="kpt-input-otp-host">
|
|
8
8
|
<div class="kpt-input-otp">
|
|
9
9
|
<input class="kpt-input-otp__cell" type="text" inputmode="numeric" maxlength="1" value="1">
|
|
10
|
-
|
|
10
|
+
...N cells...
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
14
|
## Props
|
|
15
|
-
- `value` / `defaultValue` / `onValueChange`
|
|
15
|
+
- `value` / `defaultValue` / `onValueChange` - one string, the characters joined
|
|
16
16
|
- `length`: number (default 6)
|
|
17
|
-
- `integerOnly`: boolean
|
|
17
|
+
- `integerOnly`: boolean - digits only, and a numeric keyboard on mobile
|
|
18
18
|
- `disabled`, `invalid`, `touched`, `onTouch()`
|
|
19
19
|
|
|
20
20
|
## One string, N boxes
|
|
21
21
|
The value is a single string while the UI is N inputs, so a gap in the middle has to be
|
|
22
|
-
expressible. Writing pads with spaces, replaces the character and trims trailing spaces
|
|
22
|
+
expressible. Writing pads with spaces, replaces the character and trims trailing spaces - that way
|
|
23
23
|
a code with a hole round-trips and a single character does not turn into one followed by blanks.
|
|
24
24
|
|
|
25
25
|
The DOM of a cell is also synced by hand after a rejected character: the value did not change, so
|
|
@@ -28,7 +28,7 @@ React has nothing to re-render, and the typed character would otherwise stay on
|
|
|
28
28
|
## Keyboard and paste
|
|
29
29
|
A character moves focus to the next cell; Backspace in an empty cell moves back; ArrowLeft and
|
|
30
30
|
ArrowRight walk the cells; focus selects the content so typing overwrites. Pasting fills the whole
|
|
31
|
-
code at once
|
|
31
|
+
code at once - with `integerOnly` everything non-numeric is stripped first, so a copied
|
|
32
32
|
"123-456" still lands correctly.
|
|
33
33
|
|
|
34
34
|
## Examples
|
|
@@ -38,7 +38,7 @@ code at once — with `integerOnly` everything non-numeric is stripped first, so
|
|
|
38
38
|
## Screen reader and keyboard
|
|
39
39
|
The first cell has `autocomplete="one-time-code"`, so phones offer the code from an SMS; a code that
|
|
40
40
|
arrives in one cell at once (autofill, an on-screen keyboard paste) is spread over the cells like a
|
|
41
|
-
paste. `touch` fires when focus leaves the whole group
|
|
41
|
+
paste. `touch` fires when focus leaves the whole group - not after a paste, and not when moving
|
|
42
42
|
between cells.
|
|
43
43
|
|
|
44
44
|
## Label and description
|
|
@@ -55,3 +55,14 @@ is added to `aria-describedby`. The cells form a named `role="group"`; `id` goes
|
|
|
55
55
|
## Accessibility
|
|
56
56
|
Native inputs with `inputmode` matched to the allowed characters, so a phone shows the numeric
|
|
57
57
|
keypad for a PIN instead of the full keyboard.
|
|
58
|
+
|
|
59
|
+
## Read-only and required
|
|
60
|
+
`readOnly` shows the code but blocks typing and paste; `required` sets `aria-required` on the cells (`group` does not accept it). The value holds the typed characters **without gaps**: clearing a middle cell gives `"13"`, not `"1 3"`, while the cell itself stays empty on screen.
|
|
61
|
+
|
|
62
|
+
## Groups
|
|
63
|
+
`groupSize` (default `0` = no groups) inserts a separator after every N boxes, counted from the
|
|
64
|
+
left; `groupSeparator` sets the character (default `-`). With `length` 9 and `groupSize` 3 you get
|
|
65
|
+
`[][][]-[][][]-[][][]`. The separator is purely visual (`aria-hidden`): the value is the bare characters
|
|
66
|
+
(`"123456789"`), each box keeps its name "Character 4 of 9", and arrows/Backspace jump over it.
|
|
67
|
+
|
|
68
|
+
<KptInputOtp value={code} onValueChange={setCode} length={9} groupSize={3} integerOnly />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Zawija `Tab` / `Shift+Tab` w obrębie `panel`. */
|
|
2
2
|
export declare function trapTab(panel: HTMLElement, event: KeyboardEvent): void;
|
|
3
3
|
/**
|
|
4
|
-
* Fokus na
|
|
4
|
+
* Fokus na "aktywną" komórkę panelu: dzień `iso`, przystanek siatki komórek, a bez nich - pierwszy
|
|
5
5
|
* element panelu (zegar). Panel w nakładce jest niewidoczny do pierwszego pomiaru, więc wołający
|
|
6
6
|
* odkłada to na `requestAnimationFrame`.
|
|
7
7
|
*/
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Fokus w panelu kalendarza
|
|
2
|
+
* Fokus w panelu kalendarza - wspólny dla `KptDatepicker` i `KptDateRange`. Panel stoi
|
|
3
3
|
* w nakładce na końcu strony, więc `Tab` z ostatniego elementu uciekłby poza niego; zawijamy go
|
|
4
4
|
* w obrębie panelu, jak w oknie dialogowym.
|
|
5
5
|
*
|
|
6
|
-
* Bliźniak w porcie Angulara: `shared/calendar-focus.ts`
|
|
6
|
+
* Bliźniak w porcie Angulara: `shared/calendar-focus.ts` - zmiana zachowania w obu.
|
|
7
7
|
*/
|
|
8
8
|
const FOCUSABLE = 'button:not(:disabled):not([tabindex="-1"]), input:not(:disabled), [tabindex="0"]';
|
|
9
9
|
/** Zawija `Tab` / `Shift+Tab` w obrębie `panel`. */
|
|
@@ -24,7 +24,7 @@ export function trapTab(panel, event) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Fokus na
|
|
27
|
+
* Fokus na "aktywną" komórkę panelu: dzień `iso`, przystanek siatki komórek, a bez nich - pierwszy
|
|
28
28
|
* element panelu (zegar). Panel w nakładce jest niewidoczny do pierwszego pomiaru, więc wołający
|
|
29
29
|
* odkłada to na `requestAnimationFrame`.
|
|
30
30
|
*/
|
package/dist/internal/cn.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Sklejanie klas CSS. Odpowiednik `clsx` w kilkunastu linijkach
|
|
2
|
+
* Sklejanie klas CSS. Odpowiednik `clsx` w kilkunastu linijkach - biblioteka
|
|
3
3
|
* zostaje bez zależności runtime, a konsument nie ryzykuje konfliktu wersji.
|
|
4
4
|
*
|
|
5
5
|
* Wartości fałszywe są pomijane, tablice spłaszczane, duplikaty usuwane
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Tokeny maski: `9` = cyfra, `a` = litera (także `ą`, `ł`, `ß`), `*` = litera albo cyfra. */
|
|
2
|
+
export declare const KPT_MASK_TOKENS: Readonly<Record<string, RegExp>>;
|
|
3
|
+
/**
|
|
4
|
+
* Maska przepisuje wejście od zera: z tekstu bierze wyłącznie znaki pasujące do kolejnych
|
|
5
|
+
* tokenów, a literały wstawia sama. Dzięki temu wklejenie "48123456789" i wpisanie "(48) 123..."
|
|
6
|
+
* dają ten sam wynik, a usunięcie literału nie zostawia dziury we wzorcu.
|
|
7
|
+
*/
|
|
8
|
+
export declare function kptApplyMask(raw: string, mask: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Pozycja kursora po przeformatowaniu. Liczy znaczące znaki (te, które maska zabrała) przed
|
|
11
|
+
* kursorem w surowym tekście i stawia kursor za tyloma samymi znakami w wyniku - poprawienie
|
|
12
|
+
* cyfry w środku numeru nie przerzuca kursora na koniec pola.
|
|
13
|
+
*/
|
|
14
|
+
export declare function kptMaskCaret(raw: string, caret: number, mask: string): number;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Maska znakowa `kpt-input-mask`. Bliźniak w porcie Angulara (`shared/mask.ts`) - zmiana w obu.
|
|
3
|
+
*/
|
|
4
|
+
/** Tokeny maski: `9` = cyfra, `a` = litera (także `ą`, `ł`, `ß`), `*` = litera albo cyfra. */
|
|
5
|
+
export const KPT_MASK_TOKENS = {
|
|
6
|
+
'9': /\d/,
|
|
7
|
+
a: /\p{L}/u,
|
|
8
|
+
'*': /[\p{L}\p{N}]/u,
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Maska przepisuje wejście od zera: z tekstu bierze wyłącznie znaki pasujące do kolejnych
|
|
12
|
+
* tokenów, a literały wstawia sama. Dzięki temu wklejenie "48123456789" i wpisanie "(48) 123..."
|
|
13
|
+
* dają ten sam wynik, a usunięcie literału nie zostawia dziury we wzorcu.
|
|
14
|
+
*/
|
|
15
|
+
export function kptApplyMask(raw, mask) {
|
|
16
|
+
if (!mask)
|
|
17
|
+
return raw;
|
|
18
|
+
const chars = [...raw];
|
|
19
|
+
let charIndex = 0;
|
|
20
|
+
let out = '';
|
|
21
|
+
for (let maskIndex = 0; maskIndex < mask.length && charIndex < chars.length;) {
|
|
22
|
+
const rule = KPT_MASK_TOKENS[mask[maskIndex]];
|
|
23
|
+
if (rule) {
|
|
24
|
+
while (charIndex < chars.length && !rule.test(chars[charIndex]))
|
|
25
|
+
charIndex++;
|
|
26
|
+
if (charIndex >= chars.length)
|
|
27
|
+
break;
|
|
28
|
+
out += chars[charIndex];
|
|
29
|
+
charIndex++;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
out += mask[maskIndex];
|
|
33
|
+
}
|
|
34
|
+
maskIndex++;
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Pozycja kursora po przeformatowaniu. Liczy znaczące znaki (te, które maska zabrała) przed
|
|
40
|
+
* kursorem w surowym tekście i stawia kursor za tyloma samymi znakami w wyniku - poprawienie
|
|
41
|
+
* cyfry w środku numeru nie przerzuca kursora na koniec pola.
|
|
42
|
+
*/
|
|
43
|
+
export function kptMaskCaret(raw, caret, mask) {
|
|
44
|
+
const formatted = kptApplyMask(raw, mask);
|
|
45
|
+
if (!mask)
|
|
46
|
+
return Math.min(caret, formatted.length);
|
|
47
|
+
const before = kptApplyMask(raw.slice(0, caret), mask);
|
|
48
|
+
// Ile znaczących znaków jest przed kursorem - liczone na wyniku, więc literały się nie liczą.
|
|
49
|
+
let significant = 0;
|
|
50
|
+
for (let i = 0; i < before.length; i += 1)
|
|
51
|
+
if (KPT_MASK_TOKENS[mask[i]])
|
|
52
|
+
significant += 1;
|
|
53
|
+
let seen = 0;
|
|
54
|
+
for (let i = 0; i < formatted.length; i += 1) {
|
|
55
|
+
if (KPT_MASK_TOKENS[mask[i]]) {
|
|
56
|
+
if (seen === significant)
|
|
57
|
+
return i;
|
|
58
|
+
seen += 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return formatted.length;
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Grupowanie włączone, gdy grupa ma co najmniej jedną cyfrę, a separator nie jest pusty. */
|
|
2
|
+
export interface KptDigitGrouping {
|
|
3
|
+
readonly size: number;
|
|
4
|
+
readonly separator: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Zdejmuje separatory grup. Wiodący znak `-`/`+` zostaje nawet wtedy, gdy separatorem jest `-`
|
|
8
|
+
* (`-123-456` → `-123456`), bo na początku to znak liczby, a nie granica grupy.
|
|
9
|
+
*/
|
|
10
|
+
export declare function kptStripGroups(text: string, separator: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Wstawia separator co `size` cyfr części całkowitej, licząc od prawej — tak jak tysiące:
|
|
13
|
+
* `123456789` → `123-456-789`, `1234` → `1-234`. Część ułamkowa (po `.` albo `,`) i znak zostają
|
|
14
|
+
* bez zmian. Tekst, który nie wygląda na liczbę w trakcie pisania, wraca nietknięty.
|
|
15
|
+
*/
|
|
16
|
+
export declare function kptGroupDigits(text: string, grouping: KptDigitGrouping): string;
|
|
17
|
+
/**
|
|
18
|
+
* Pozycja kursora po przeformatowaniu: tyle samo „znaczących” znaków (cyfry, znak, przecinek
|
|
19
|
+
* dziesiętny) przed kursorem co w tekście sprzed grupowania. Bez tego wstawiony separator
|
|
20
|
+
* przesuwałby kursor o jedno miejsce przy każdej trzeciej cyfrze.
|
|
21
|
+
*/
|
|
22
|
+
export declare function kptCaretAfterGrouping(before: string, caret: number, after: string, separator: string): number;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Grupowanie cyfr w polu liczbowym (`kpt-input-number`, `groupSize` + `groupSeparator`).
|
|
3
|
+
* Bliźniak: packages/angular/src/lib/shared/number-group.ts — zmiana tutaj wymaga zmiany tam.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Zdejmuje separatory grup. Wiodący znak `-`/`+` zostaje nawet wtedy, gdy separatorem jest `-`
|
|
7
|
+
* (`-123-456` → `-123456`), bo na początku to znak liczby, a nie granica grupy.
|
|
8
|
+
*/
|
|
9
|
+
export function kptStripGroups(text, separator) {
|
|
10
|
+
if (!separator)
|
|
11
|
+
return text;
|
|
12
|
+
const sign = /^[-+]/.exec(text)?.[0] ?? '';
|
|
13
|
+
return sign + text.slice(sign.length).split(separator).join('');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wstawia separator co `size` cyfr części całkowitej, licząc od prawej — tak jak tysiące:
|
|
17
|
+
* `123456789` → `123-456-789`, `1234` → `1-234`. Część ułamkowa (po `.` albo `,`) i znak zostają
|
|
18
|
+
* bez zmian. Tekst, który nie wygląda na liczbę w trakcie pisania, wraca nietknięty.
|
|
19
|
+
*/
|
|
20
|
+
export function kptGroupDigits(text, grouping) {
|
|
21
|
+
const { size, separator } = grouping;
|
|
22
|
+
if (size < 1 || !separator)
|
|
23
|
+
return text;
|
|
24
|
+
const match = /^([-+]?)(\d*)([.,]\d*)?$/.exec(kptStripGroups(text, separator));
|
|
25
|
+
if (!match)
|
|
26
|
+
return text;
|
|
27
|
+
const [, sign, integer, fraction = ''] = match;
|
|
28
|
+
const groups = [];
|
|
29
|
+
for (let end = integer.length; end > 0; end -= size)
|
|
30
|
+
groups.unshift(integer.slice(Math.max(0, end - size), end));
|
|
31
|
+
return sign + groups.join(separator) + fraction;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Pozycja kursora po przeformatowaniu: tyle samo „znaczących” znaków (cyfry, znak, przecinek
|
|
35
|
+
* dziesiętny) przed kursorem co w tekście sprzed grupowania. Bez tego wstawiony separator
|
|
36
|
+
* przesuwałby kursor o jedno miejsce przy każdej trzeciej cyfrze.
|
|
37
|
+
*/
|
|
38
|
+
export function kptCaretAfterGrouping(before, caret, after, separator) {
|
|
39
|
+
const significant = kptStripGroups(before.slice(0, caret), separator).length;
|
|
40
|
+
let seen = 0;
|
|
41
|
+
let index = 0;
|
|
42
|
+
// Wiodący znak liczby liczy się zawsze, nawet gdy jest identyczny z separatorem.
|
|
43
|
+
if (significant > 0 && /^[-+]/.test(after)) {
|
|
44
|
+
seen = 1;
|
|
45
|
+
index = 1;
|
|
46
|
+
}
|
|
47
|
+
while (index < after.length && seen < significant) {
|
|
48
|
+
if (!after.startsWith(separator, index))
|
|
49
|
+
seen += 1;
|
|
50
|
+
index += after.startsWith(separator, index) ? separator.length : 1;
|
|
51
|
+
}
|
|
52
|
+
return index;
|
|
53
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Klucz Reacta dla opcji kontrolki generycznej: wartość prymitywna jako tekst, obiekt - pozycja.
|
|
3
|
+
* `String(obiekt)` dawałby "[object Object]" dla każdej opcji, czyli zdublowane klucze i stan
|
|
4
|
+
* przenoszony między opcjami przy zmianie listy.
|
|
5
|
+
*/
|
|
6
|
+
export declare function optionKey(value: unknown, index: number): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Klucz Reacta dla opcji kontrolki generycznej: wartość prymitywna jako tekst, obiekt - pozycja.
|
|
3
|
+
* `String(obiekt)` dawałby "[object Object]" dla każdej opcji, czyli zdublowane klucze i stan
|
|
4
|
+
* przenoszony między opcjami przy zmianie listy.
|
|
5
|
+
*/
|
|
6
|
+
export function optionKey(value, index) {
|
|
7
|
+
return typeof value === 'object' && value !== null ? `#${index}` : String(value);
|
|
8
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/** Klawisze, które przesuwają aktywną opcję. */
|
|
2
2
|
export declare const OPTION_NAV_KEYS: Set<string>;
|
|
3
3
|
/**
|
|
4
|
-
* Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania
|
|
5
|
-
* końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy
|
|
6
|
-
* aktywnego
|
|
4
|
+
* Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania - na
|
|
5
|
+
* końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy "nic
|
|
6
|
+
* aktywnego": `ArrowDown` idzie wtedy na pierwszą, `ArrowUp` na ostatnią. `null` dla innych klawiszy albo listy
|
|
7
7
|
* bez aktywnych opcji.
|
|
8
8
|
*/
|
|
9
9
|
export declare function nextOptionIndex(disabled: readonly boolean[], current: number, key: string): number | null;
|
|
10
10
|
/**
|
|
11
11
|
* Wyszukiwanie po pierwszych literach (type-ahead): pierwsza aktywna opcja zaczynająca się od
|
|
12
12
|
* `query`, licząc od pozycji za `current` i zawijając. Porównanie bez wielkości liter i polskich
|
|
13
|
-
* znaków
|
|
13
|
+
* znaków - "lo" znajduje "Łódź".
|
|
14
14
|
*/
|
|
15
15
|
export declare function typeaheadIndex(labels: readonly string[], disabled: readonly boolean[], current: number, query: string): number | null;
|
|
16
16
|
/** Bufor wpisywanych liter dla type-ahead: zeruje się po chwili bez pisania. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Nawigacja klawiaturą po liście opcji z aktywną pozycją (`aria-activedescendant`)
|
|
2
|
+
* Nawigacja klawiaturą po liście opcji z aktywną pozycją (`aria-activedescendant`) - wspólna dla
|
|
3
3
|
* `KptSelect`, `KptListbox` i `KptAutocomplete`. Port Angulara ma bliźniaczy plik
|
|
4
4
|
* `shared/option-nav.ts`. Fokus zostaje na kontrolce; zmienia się tylko indeks aktywnej opcji.
|
|
5
5
|
*/
|
|
@@ -9,9 +9,9 @@ const PAGE = 10;
|
|
|
9
9
|
/** Klawisze, które przesuwają aktywną opcję. */
|
|
10
10
|
export const OPTION_NAV_KEYS = new Set(['ArrowDown', 'ArrowUp', 'Home', 'End', 'PageDown', 'PageUp']);
|
|
11
11
|
/**
|
|
12
|
-
* Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania
|
|
13
|
-
* końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy
|
|
14
|
-
* aktywnego
|
|
12
|
+
* Indeks opcji po klawiszu `key`, z pominięciem wyłączonych (`disabled[i]`). Bez zawijania - na
|
|
13
|
+
* końcu listy strzałka zostaje na miejscu, jak w natywnym `<select>`. `current` = -1 znaczy "nic
|
|
14
|
+
* aktywnego": `ArrowDown` idzie wtedy na pierwszą, `ArrowUp` na ostatnią. `null` dla innych klawiszy albo listy
|
|
15
15
|
* bez aktywnych opcji.
|
|
16
16
|
*/
|
|
17
17
|
export function nextOptionIndex(disabled, current, key) {
|
|
@@ -47,7 +47,7 @@ export function nextOptionIndex(disabled, current, key) {
|
|
|
47
47
|
/**
|
|
48
48
|
* Wyszukiwanie po pierwszych literach (type-ahead): pierwsza aktywna opcja zaczynająca się od
|
|
49
49
|
* `query`, licząc od pozycji za `current` i zawijając. Porównanie bez wielkości liter i polskich
|
|
50
|
-
* znaków
|
|
50
|
+
* znaków - "lo" znajduje "Łódź".
|
|
51
51
|
*/
|
|
52
52
|
export function typeaheadIndex(labels, disabled, current, query) {
|
|
53
53
|
const q = foldMentionText(query);
|
|
@@ -3,7 +3,7 @@ import { createContext, useContext } from 'react';
|
|
|
3
3
|
* Miejsce, do którego portalują się panele nakładek.
|
|
4
4
|
*
|
|
5
5
|
* `showModal()` wynosi `<dialog>` do warstwy szczytowej przeglądarki, a ta stoi ponad całym
|
|
6
|
-
* drzewem dokumentu
|
|
6
|
+
* drzewem dokumentu - żaden `z-index` tego nie przebije. Panel selecta czy menu otwarty
|
|
7
7
|
* z wnętrza modala portalowałby się na `document.body` i byłby NIEWIDOCZNY, schowany za tłem
|
|
8
8
|
* okna. `KptDialog` podstawia więc siebie jako kontener na czas, gdy jest otwarty.
|
|
9
9
|
*
|
|
@@ -5,7 +5,7 @@ export interface KptOverlayProps {
|
|
|
5
5
|
anchor: HTMLElement | null;
|
|
6
6
|
/** Kliknięcie w backdrop albo Escape. */
|
|
7
7
|
onClose: () => void;
|
|
8
|
-
/** Panel dostaje szerokość wyzwalacza
|
|
8
|
+
/** Panel dostaje szerokość wyzwalacza - dokładnie tę (podpowiedzi autocomplete pod polem). */
|
|
9
9
|
matchAnchorWidth?: boolean;
|
|
10
10
|
/**
|
|
11
11
|
* Panel jest co najmniej tak szeroki jak wyzwalacz, ale rośnie do treści (lista selecta:
|
|
@@ -16,13 +16,13 @@ export interface KptOverlayProps {
|
|
|
16
16
|
offset?: number;
|
|
17
17
|
/**
|
|
18
18
|
* Krawędź, do której wyrównujemy panel: `start` (lewa, domyślnie) albo `end` (prawa).
|
|
19
|
-
* `end` przydaje się, gdy wyzwalacz siedzi przy prawej krawędzi kontrolki
|
|
19
|
+
* `end` przydaje się, gdy wyzwalacz siedzi przy prawej krawędzi kontrolki - panel otwiera się
|
|
20
20
|
* wtedy w lewo i nie wychodzi poza nią.
|
|
21
21
|
*/
|
|
22
22
|
align?: 'start' | 'end';
|
|
23
23
|
/**
|
|
24
24
|
* Przezroczysty backdrop przechwytujący kliknięcie poza panelem. Wyłącz go tam, gdzie panel
|
|
25
|
-
* ma zostawić wyzwalacz klikalnym
|
|
25
|
+
* ma zostawić wyzwalacz klikalnym - autocomplete zamyka się na `blur` pola, a backdrop
|
|
26
26
|
* zasłoniłby to pole i zabrałby mu każde kliknięcie.
|
|
27
27
|
*/
|
|
28
28
|
withBackdrop?: boolean;
|
package/dist/internal/overlay.js
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
4
|
import { createPortal } from 'react-dom';
|
|
4
5
|
import { useKptOverlayContainer } from "./overlay-container.js";
|
|
5
|
-
|
|
6
|
+
/*
|
|
7
|
+
* Prymityw nakładki: panel przypięty do wyzwalacza, renderowany w portalu do `document.body`.
|
|
8
|
+
*
|
|
9
|
+
* Port Angulara stoi tu na CDK Overlay, którego w Reakcie nie ma. Odtwarzamy jego zachowanie:
|
|
10
|
+
* pozycjonowanie względem wyzwalacza z odbiciem w górę, gdy pod spodem brakuje miejsca,
|
|
11
|
+
* przezroczysty backdrop zamykający kliknięciem oraz Escape. Style samego panelu pochodzą
|
|
12
|
+
* ze wspólnego arkusza (`.kpt-select__panel`, `.kpt-popover__panel`) - tutaj są wyłącznie
|
|
13
|
+
* współrzędne, więc nic nie duplikuje wyglądu.
|
|
14
|
+
*/
|
|
15
|
+
/** Otwarte nakładki od najstarszej - Escape obsługuje tylko ostatnia. */
|
|
16
|
+
const overlayStack = [];
|
|
17
|
+
/** Ta sama warstwa co `--kpt-z-overlay` w tokenach - panel ma być nad treścią aplikacji. */
|
|
6
18
|
const Z_INDEX = 'var(--kpt-z-overlay, 1100)';
|
|
7
19
|
export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, minAnchorWidth = false, offset = 4, align = 'start', withBackdrop = true, preferAbove = false, children, }) {
|
|
8
20
|
const container = useKptOverlayContainer();
|
|
@@ -16,7 +28,7 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
|
|
|
16
28
|
const panelWidth = panelRef.current?.offsetWidth ?? 0;
|
|
17
29
|
const below = window.innerHeight - rect.bottom;
|
|
18
30
|
// Odbicie w górę tylko wtedy, gdy pod spodem naprawdę brakuje miejsca, a nad wyzwalaczem
|
|
19
|
-
// jest go więcej
|
|
31
|
+
// jest go więcej - inaczej panel skakałby przy każdym przewinięciu o kilka pikseli.
|
|
20
32
|
// Przy `preferAbove` jest odwrotnie: panel stoi nad wyzwalaczem, dopóki się tam mieści.
|
|
21
33
|
const fitsAbove = panelHeight === 0 || rect.top > panelHeight + offset;
|
|
22
34
|
const flip = preferAbove ? fitsAbove : panelHeight > 0 && below < panelHeight + offset && rect.top > below;
|
|
@@ -27,12 +39,17 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
|
|
|
27
39
|
...(minAnchorWidth ? { minWidth: rect.width } : {}),
|
|
28
40
|
});
|
|
29
41
|
}, [anchor, matchAnchorWidth, minAnchorWidth, offset, align, preferAbove]);
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
// Zamknięcie zeruje pozycję w tym samym renderze (wzorzec "poprzednia wartość w stanie"), więc
|
|
43
|
+
// ponowne otwarcie nie pokaże panelu na klatkę w starym miejscu - bez setState w efekcie.
|
|
44
|
+
const [wasOpen, setWasOpen] = useState(open);
|
|
45
|
+
if (wasOpen !== open) {
|
|
46
|
+
setWasOpen(open);
|
|
47
|
+
if (!open)
|
|
32
48
|
setPosition(null);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
}
|
|
50
|
+
useLayoutEffect(() => {
|
|
51
|
+
if (open)
|
|
52
|
+
update();
|
|
36
53
|
}, [open, update]);
|
|
37
54
|
useEffect(() => {
|
|
38
55
|
if (!open)
|
|
@@ -41,15 +58,28 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
|
|
|
41
58
|
// `capture` łapie też przewijanie kontenerów w środku strony, nie tylko okna.
|
|
42
59
|
window.addEventListener('scroll', onScrollOrResize, true);
|
|
43
60
|
window.addEventListener('resize', onScrollOrResize);
|
|
61
|
+
/*
|
|
62
|
+
* Escape zamyka tylko najwyższą nakładkę (stos jak `OverlayKeyboardDispatcher` w CDK) i tylko
|
|
63
|
+
* wtedy, gdy komponent nie obsłużył klawisza sam. `preventDefault` jest konieczne: natywny
|
|
64
|
+
* `<dialog>` traktuje ten sam Escape jako żądanie zamknięcia - popover w `KptDialog` zamykał
|
|
65
|
+
* razem ze sobą całe okno.
|
|
66
|
+
*/
|
|
67
|
+
const token = {};
|
|
68
|
+
overlayStack.push(token);
|
|
44
69
|
const onKeyDown = (event) => {
|
|
45
|
-
if (event.key
|
|
46
|
-
|
|
70
|
+
if (event.key !== 'Escape' || event.defaultPrevented)
|
|
71
|
+
return;
|
|
72
|
+
if (overlayStack[overlayStack.length - 1] !== token)
|
|
73
|
+
return;
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
onClose();
|
|
47
76
|
};
|
|
48
77
|
document.addEventListener('keydown', onKeyDown);
|
|
49
78
|
return () => {
|
|
50
79
|
window.removeEventListener('scroll', onScrollOrResize, true);
|
|
51
80
|
window.removeEventListener('resize', onScrollOrResize);
|
|
52
81
|
document.removeEventListener('keydown', onKeyDown);
|
|
82
|
+
overlayStack.splice(overlayStack.indexOf(token), 1);
|
|
53
83
|
};
|
|
54
84
|
}, [open, update, onClose]);
|
|
55
85
|
if (!open || !container)
|
|
@@ -61,7 +91,7 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, mi
|
|
|
61
91
|
width: position?.width,
|
|
62
92
|
minWidth: position?.minWidth,
|
|
63
93
|
zIndex: Z_INDEX,
|
|
64
|
-
// Panel bez pozycji jeszcze nie został zmierzony
|
|
94
|
+
// Panel bez pozycji jeszcze nie został zmierzony - chowamy go na pierwszej klatce,
|
|
65
95
|
// żeby nie mrugnął w lewym górnym rogu.
|
|
66
96
|
visibility: position ? 'visible' : 'hidden',
|
|
67
97
|
}, children: children })] }), container);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** 0 = bardzo słabe ... 4 = silne. */
|
|
2
|
+
export type KptPasswordScore = 0 | 1 | 2 | 3 | 4;
|
|
3
|
+
/** Przybliżona entropia w bitach. */
|
|
4
|
+
export declare function kptPasswordBits(value: string): number;
|
|
5
|
+
/** Wynik 0-4 z entropii: <28 bardzo słabe, <36 słabe, <50 średnie, <64 dobre, reszta silne. */
|
|
6
|
+
export declare function kptPasswordScore(value: string): KptPasswordScore;
|