@konce-pt/react 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -64
- package/dist/accordion/accordion.d.ts +14 -6
- package/dist/accordion/accordion.js +14 -7
- package/dist/accordion/llms.txt +22 -10
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert/alert.js +2 -2
- package/dist/alert/llms.txt +10 -10
- package/dist/app-shell/app-shell.d.ts +14 -14
- package/dist/app-shell/app-shell.js +11 -11
- package/dist/app-shell/llms.txt +13 -13
- package/dist/auth/auth-types.d.ts +6 -6
- package/dist/auth/auth.d.ts +2 -2
- package/dist/auth/auth.js +7 -7
- package/dist/auth/llms.txt +9 -9
- package/dist/autocomplete/autocomplete.d.ts +19 -6
- package/dist/autocomplete/autocomplete.js +23 -10
- package/dist/autocomplete/llms.txt +16 -5
- package/dist/avatar/avatar.d.ts +6 -6
- package/dist/avatar/avatar.js +5 -5
- package/dist/avatar/llms.txt +10 -10
- package/dist/avatar-group/avatar-group.d.ts +4 -4
- package/dist/avatar-group/avatar-group.js +3 -3
- package/dist/avatar-group/llms.txt +8 -8
- package/dist/backdrop/backdrop.d.ts +7 -7
- package/dist/backdrop/backdrop.js +16 -16
- package/dist/backdrop/llms.txt +27 -27
- package/dist/badge/badge.d.ts +3 -3
- package/dist/badge/badge.js +1 -1
- package/dist/badge/llms.txt +11 -11
- package/dist/bottom-sheet/bottom-sheet.d.ts +4 -4
- package/dist/bottom-sheet/bottom-sheet.js +2 -2
- package/dist/bottom-sheet/llms.txt +9 -9
- package/dist/breadcrumb/breadcrumb.d.ts +2 -2
- package/dist/breadcrumb/breadcrumb.js +3 -3
- package/dist/breadcrumb/llms.txt +3 -3
- package/dist/button/button.d.ts +3 -3
- package/dist/button/button.js +8 -8
- package/dist/button/llms.txt +27 -19
- package/dist/button-group/button-group.d.ts +9 -9
- package/dist/button-group/button-group.js +30 -8
- package/dist/button-group/llms.txt +20 -14
- package/dist/card/card.d.ts +8 -8
- package/dist/card/card.js +6 -6
- package/dist/card/llms.txt +20 -20
- package/dist/carousel/carousel.d.ts +6 -6
- package/dist/carousel/carousel.js +4 -4
- package/dist/carousel/llms.txt +10 -10
- package/dist/charts/chart-legend.d.ts +3 -3
- package/dist/charts/chart-legend.js +1 -1
- package/dist/charts/chart-tooltip.d.ts +3 -3
- package/dist/charts/chart-tooltip.js +1 -1
- package/dist/charts/chart.d.ts +1 -1
- package/dist/charts/chart.js +8 -8
- package/dist/charts/llms.txt +6 -6
- package/dist/charts-entry/public-api.js +2 -2
- package/dist/chat/chat.d.ts +17 -10
- package/dist/chat/chat.js +42 -18
- package/dist/chat/llms.txt +32 -17
- package/dist/chat-composer/chat-composer.d.ts +17 -7
- package/dist/chat-composer/chat-composer.js +21 -8
- package/dist/chat-composer/llms.txt +20 -11
- package/dist/chat-dock/chat-dock.d.ts +11 -4
- package/dist/chat-dock/chat-dock.js +9 -6
- package/dist/chat-dock/llms.txt +15 -14
- package/dist/chat-entry/public-api.js +1 -1
- package/dist/chat-message/chat-message.d.ts +12 -5
- package/dist/chat-message/chat-message.js +17 -7
- package/dist/chat-message/llms.txt +16 -15
- package/dist/chat-typing/chat-typing.d.ts +2 -2
- package/dist/chat-typing/chat-typing.js +3 -3
- package/dist/chat-typing/llms.txt +6 -6
- package/dist/checkbox/checkbox.d.ts +13 -6
- package/dist/checkbox/checkbox.js +26 -7
- package/dist/checkbox/llms.txt +24 -12
- package/dist/chip/chip.d.ts +4 -4
- package/dist/chip/chip.js +2 -2
- package/dist/chip/llms.txt +11 -11
- package/dist/chips-input/chips-input.d.ts +4 -4
- package/dist/chips-input/chips-input.js +35 -9
- package/dist/chips-input/llms.txt +15 -8
- package/dist/clock/clock.d.ts +4 -4
- package/dist/clock/clock.js +7 -7
- package/dist/clock/llms.txt +8 -8
- package/dist/color-picker/color-picker.d.ts +6 -6
- package/dist/color-picker/color-picker.js +3 -3
- package/dist/color-picker/llms.txt +5 -5
- package/dist/confirm/confirm-container.d.ts +3 -3
- package/dist/confirm/confirm-container.js +5 -5
- package/dist/confirm/confirm-store.d.ts +4 -4
- package/dist/confirm/confirm-store.js +7 -7
- package/dist/confirm/llms.txt +6 -6
- package/dist/context-menu/context-menu.d.ts +1 -1
- package/dist/context-menu/context-menu.js +5 -5
- package/dist/context-menu/llms.txt +7 -7
- package/dist/data-table/data-table-types.d.ts +5 -5
- package/dist/data-table/data-table.d.ts +29 -8
- package/dist/data-table/data-table.js +340 -95
- package/dist/data-table/export-csv.d.ts +3 -3
- package/dist/data-table/export-csv.js +4 -4
- package/dist/data-table/llms.txt +127 -94
- package/dist/data-view/data-view.d.ts +13 -5
- package/dist/data-view/data-view.js +67 -6
- package/dist/data-view/llms.txt +29 -10
- package/dist/date-range/date-range.d.ts +9 -9
- package/dist/date-range/date-range.js +24 -24
- package/dist/date-range/llms.txt +20 -20
- package/dist/datepicker/datepicker.d.ts +10 -10
- package/dist/datepicker/datepicker.js +29 -29
- package/dist/datepicker/llms.txt +24 -24
- package/dist/dialog/dialog.d.ts +4 -4
- package/dist/dialog/dialog.js +4 -4
- package/dist/dialog/llms.txt +11 -11
- package/dist/divider/divider.d.ts +1 -1
- package/dist/divider/llms.txt +4 -4
- package/dist/drawer/drawer.d.ts +5 -5
- package/dist/drawer/drawer.js +2 -2
- package/dist/drawer/llms.txt +11 -11
- package/dist/empty/empty.d.ts +2 -2
- package/dist/empty/empty.js +1 -1
- package/dist/empty/llms.txt +9 -9
- package/dist/fab/fab.d.ts +1 -1
- package/dist/fab/fab.js +1 -1
- package/dist/fab/llms.txt +10 -6
- package/dist/fieldset/fieldset.d.ts +18 -4
- package/dist/fieldset/fieldset.js +9 -6
- package/dist/fieldset/llms.txt +26 -9
- package/dist/file-upload/file-upload.d.ts +3 -3
- package/dist/file-upload/file-upload.js +7 -7
- package/dist/file-upload/llms.txt +7 -7
- package/dist/form-field/form-field-context.d.ts +4 -4
- package/dist/form-field/form-field.d.ts +12 -4
- package/dist/form-field/form-field.js +26 -6
- package/dist/form-field/llms.txt +25 -11
- package/dist/galleria/galleria.d.ts +3 -3
- package/dist/galleria/galleria.js +5 -5
- package/dist/galleria/llms.txt +7 -7
- package/dist/grid/col.d.ts +4 -4
- package/dist/grid/col.js +2 -2
- package/dist/grid/flex.d.ts +3 -3
- package/dist/grid/flex.js +1 -1
- package/dist/grid/grid.d.ts +7 -7
- package/dist/grid/grid.js +3 -3
- package/dist/grid/layout.d.ts +2 -2
- package/dist/grid/layout.js +2 -2
- package/dist/grid/llms.txt +15 -15
- package/dist/grid-entry/public-api.js +1 -1
- package/dist/i18n/i18n-context.d.ts +3 -3
- package/dist/i18n/i18n-context.js +7 -7
- package/dist/icon/icon-registry.d.ts +3 -3
- package/dist/icon/icon-registry.js +3 -3
- package/dist/icon/icon.d.ts +4 -4
- package/dist/icon/icon.js +6 -6
- package/dist/icon/llms.txt +13 -13
- package/dist/icon-button/icon-button.d.ts +2 -2
- package/dist/icon-button/icon-button.js +1 -1
- package/dist/icon-button/llms.txt +9 -5
- package/dist/icons-entry/public-api.d.ts +2 -2
- package/dist/icons-entry/public-api.js +3 -3
- package/dist/image/image.js +1 -1
- package/dist/image/llms.txt +13 -13
- package/dist/input/input.d.ts +18 -5
- package/dist/input/input.js +21 -6
- package/dist/input/llms.txt +25 -11
- package/dist/input-mask/input-mask.d.ts +1 -1
- package/dist/input-mask/input-mask.js +2 -2
- package/dist/input-mask/llms.txt +5 -5
- package/dist/input-number/input-number.d.ts +9 -9
- package/dist/input-number/input-number.js +11 -11
- package/dist/input-number/llms.txt +14 -14
- package/dist/input-otp/input-otp.d.ts +6 -6
- package/dist/input-otp/input-otp.js +10 -10
- package/dist/input-otp/llms.txt +9 -9
- package/dist/internal/calendar-focus.d.ts +1 -1
- package/dist/internal/calendar-focus.js +3 -3
- package/dist/internal/cn.d.ts +1 -1
- package/dist/internal/mask.d.ts +2 -2
- package/dist/internal/mask.js +4 -4
- package/dist/internal/option-key.d.ts +2 -2
- package/dist/internal/option-key.js +2 -2
- package/dist/internal/option-nav.d.ts +4 -4
- package/dist/internal/option-nav.js +5 -5
- package/dist/internal/overlay-container.js +1 -1
- package/dist/internal/overlay.d.ts +3 -3
- package/dist/internal/overlay.js +8 -8
- package/dist/internal/password-strength.d.ts +2 -2
- package/dist/internal/password-strength.js +6 -6
- package/dist/internal/roving.d.ts +2 -2
- package/dist/internal/roving.js +3 -3
- package/dist/internal/scroll-lock.d.ts +1 -1
- package/dist/internal/scroll-lock.js +2 -2
- package/dist/internal/slot-children.d.ts +3 -3
- package/dist/internal/slot-children.js +4 -4
- package/dist/internal/slot.d.ts +3 -3
- package/dist/internal/slot.js +2 -2
- package/dist/internal/step.d.ts +3 -3
- package/dist/internal/step.js +4 -4
- package/dist/internal/tween.d.ts +5 -5
- package/dist/internal/tween.js +5 -5
- package/dist/internal/types.d.ts +2 -2
- package/dist/internal/use-breakpoint.d.ts +2 -2
- package/dist/internal/use-breakpoint.js +4 -4
- package/dist/internal/use-controllable-state.d.ts +1 -1
- package/dist/internal/use-controllable-state.js +3 -3
- package/dist/internal/use-id.d.ts +2 -2
- package/dist/internal/use-id.js +2 -2
- package/dist/internal/use-modal-focus.d.ts +1 -1
- package/dist/internal/use-modal-focus.js +3 -3
- package/dist/knob/knob.d.ts +4 -4
- package/dist/knob/knob.js +14 -10
- package/dist/knob/llms.txt +17 -12
- package/dist/listbox/listbox.d.ts +6 -6
- package/dist/listbox/listbox.js +9 -9
- package/dist/listbox/llms.txt +10 -10
- package/dist/loader/llms.txt +56 -0
- package/dist/loader/loader.d.ts +49 -0
- package/dist/loader/loader.js +68 -0
- package/dist/map/llms.txt +25 -22
- package/dist/map/map-create-dialog.d.ts +4 -4
- package/dist/map/map-create-dialog.js +10 -10
- package/dist/map/map-hours-field.d.ts +4 -4
- package/dist/map/map-hours-field.js +7 -7
- package/dist/map/map-image-field.d.ts +2 -2
- package/dist/map/map-image-field.js +4 -4
- package/dist/map/map-legend.d.ts +4 -4
- package/dist/map/map-legend.js +2 -2
- package/dist/map/map-poi-card.d.ts +3 -3
- package/dist/map/map-poi-card.js +9 -9
- package/dist/map/map-search.d.ts +17 -6
- package/dist/map/map-search.js +21 -18
- package/dist/map/map.d.ts +21 -14
- package/dist/map/map.js +30 -29
- package/dist/map/ports.d.ts +9 -9
- package/dist/map/ports.js +6 -6
- package/dist/map-entry/public-api.js +2 -2
- package/dist/megamenu/llms.txt +9 -9
- package/dist/megamenu/megamenu.d.ts +6 -6
- package/dist/megamenu/megamenu.js +10 -10
- package/dist/mention/llms.txt +15 -15
- package/dist/mention/mention.d.ts +5 -5
- package/dist/mention/mention.js +2 -2
- package/dist/mention/mentions.d.ts +1 -1
- package/dist/mention/mentions.js +1 -1
- package/dist/menu/llms.txt +12 -12
- package/dist/menu/menu-item.d.ts +4 -4
- package/dist/menu/menu-keys.d.ts +2 -2
- package/dist/menu/menu-keys.js +5 -5
- package/dist/menu/menu.d.ts +2 -2
- package/dist/menu/menu.js +6 -6
- package/dist/menubar/llms.txt +10 -10
- package/dist/menubar/menubar.d.ts +5 -5
- package/dist/menubar/menubar.js +10 -10
- package/dist/meter-group/llms.txt +12 -12
- package/dist/meter-group/meter-group.d.ts +2 -2
- package/dist/meter-group/meter-group.js +1 -1
- package/dist/motion/motion-context.d.ts +22 -0
- package/dist/motion/motion-context.js +28 -0
- package/dist/order-list/llms.txt +22 -10
- package/dist/order-list/order-list.d.ts +12 -4
- package/dist/order-list/order-list.js +104 -21
- package/dist/paginator/llms.txt +8 -8
- package/dist/paginator/paginator.js +1 -1
- package/dist/panel/llms.txt +25 -13
- package/dist/panel/panel.d.ts +11 -3
- package/dist/panel/panel.js +7 -4
- package/dist/password/llms.txt +16 -8
- package/dist/password/password.d.ts +2 -2
- package/dist/password/password.js +24 -3
- package/dist/peek/llms.txt +10 -10
- package/dist/peek/peek.d.ts +6 -6
- package/dist/peek/peek.js +7 -7
- package/dist/pick-list/llms.txt +33 -13
- package/dist/pick-list/pick-list.d.ts +12 -4
- package/dist/pick-list/pick-list.js +111 -23
- package/dist/popover/llms.txt +11 -11
- package/dist/popover/popover.d.ts +4 -4
- package/dist/popover/popover.js +5 -5
- package/dist/progress/llms.txt +17 -17
- package/dist/progress/progress.d.ts +7 -7
- package/dist/progress/progress.js +6 -6
- package/dist/public-api.d.ts +15 -3
- package/dist/public-api.js +13 -7
- package/dist/radio-group/llms.txt +13 -6
- package/dist/radio-group/radio-group.d.ts +11 -4
- package/dist/radio-group/radio-group.js +15 -7
- package/dist/rating/llms.txt +20 -13
- package/dist/rating/rating-pointer.d.ts +16 -0
- package/dist/rating/rating-pointer.js +26 -0
- package/dist/rating/rating.d.ts +6 -6
- package/dist/rating/rating.js +76 -12
- package/dist/rich-text/lists.d.ts +2 -2
- package/dist/rich-text/lists.js +7 -7
- package/dist/rich-text/llms.txt +26 -17
- package/dist/rich-text/rich-text.d.ts +12 -7
- package/dist/rich-text/rich-text.js +78 -54
- package/dist/rich-text/sanitize.d.ts +3 -3
- package/dist/rich-text/sanitize.js +12 -12
- package/dist/rich-text/tables.d.ts +3 -3
- package/dist/rich-text/tables.js +3 -3
- package/dist/roadmap/llms.txt +15 -15
- package/dist/roadmap/roadmap.d.ts +6 -6
- package/dist/roadmap/roadmap.js +19 -19
- package/dist/roadmap-entry/public-api.js +2 -2
- package/dist/scroll-top/llms.txt +6 -6
- package/dist/scroll-top/scroll-top.d.ts +1 -1
- package/dist/scroll-top/scroll-top.js +1 -1
- package/dist/select/llms.txt +19 -12
- package/dist/select/select.d.ts +8 -8
- package/dist/select/select.js +47 -21
- package/dist/shared/types.d.ts +5 -5
- package/dist/shared/types.js +1 -1
- package/dist/sidenav/llms.txt +9 -9
- package/dist/sidenav/sidenav.d.ts +1 -1
- package/dist/sidenav/sidenav.js +1 -1
- package/dist/skeleton/llms.txt +3 -3
- package/dist/skeleton/skeleton.d.ts +1 -1
- package/dist/skeleton/skeleton.js +1 -1
- package/dist/slider/llms.txt +32 -13
- package/dist/slider/slider-drag.d.ts +26 -0
- package/dist/slider/slider-drag.js +79 -0
- package/dist/slider/slider.d.ts +6 -5
- package/dist/slider/slider.js +27 -8
- package/dist/speech/llms.txt +97 -0
- package/dist/speech/speech-button.d.ts +44 -0
- package/dist/speech/speech-button.js +86 -0
- package/dist/speech/speech-wave.d.ts +19 -0
- package/dist/speech/speech-wave.js +16 -0
- package/dist/speech/use-speech-recognition.d.ts +81 -0
- package/dist/speech/use-speech-recognition.js +179 -0
- package/dist/speed-dial/llms.txt +14 -8
- package/dist/speed-dial/speed-dial.d.ts +1 -1
- package/dist/speed-dial/speed-dial.js +1 -1
- package/dist/spinner/llms.txt +7 -7
- package/dist/spinner/spinner.d.ts +1 -1
- package/dist/spinner/spinner.js +1 -1
- package/dist/split-button/llms.txt +21 -15
- package/dist/split-button/split-button.d.ts +2 -2
- package/dist/split-button/split-button.js +4 -4
- package/dist/splitter/llms.txt +11 -11
- package/dist/splitter/splitter.d.ts +3 -3
- package/dist/splitter/splitter.js +5 -5
- package/dist/stepper/llms.txt +33 -14
- package/dist/stepper/stepper.d.ts +6 -6
- package/dist/stepper/stepper.js +53 -10
- package/dist/switch/llms.txt +12 -5
- package/dist/switch/switch.d.ts +10 -3
- package/dist/switch/switch.js +12 -5
- package/dist/switch-group/llms.txt +9 -9
- package/dist/switch-group/switch-group.d.ts +4 -4
- package/dist/switch-group/switch-group.js +4 -4
- package/dist/tabs/llms.txt +10 -10
- package/dist/tabs/tabs.d.ts +5 -5
- package/dist/tabs/tabs.js +8 -8
- package/dist/textarea/llms.txt +23 -12
- package/dist/textarea/textarea.d.ts +19 -6
- package/dist/textarea/textarea.js +21 -7
- package/dist/timeline/llms.txt +4 -4
- package/dist/timeline/timeline.d.ts +1 -1
- package/dist/timeline/timeline.js +1 -1
- package/dist/toast/llms.txt +47 -17
- package/dist/toast/toast-container.d.ts +9 -3
- package/dist/toast/toast-container.js +17 -9
- package/dist/toast/toast-store.d.ts +40 -4
- package/dist/toast/toast-store.js +36 -1
- package/dist/toolbar/llms.txt +7 -7
- package/dist/toolbar/toolbar.d.ts +3 -3
- package/dist/toolbar/toolbar.js +2 -2
- package/dist/tooltip/llms.txt +10 -10
- package/dist/tooltip/tooltip.d.ts +3 -3
- package/dist/tooltip/tooltip.js +18 -18
- package/dist/tree/llms.txt +25 -12
- package/dist/tree/tree-keys.d.ts +5 -5
- package/dist/tree/tree-keys.js +7 -7
- package/dist/tree/tree.d.ts +14 -7
- package/dist/tree/tree.js +53 -18
- package/dist/update/llms.txt +54 -0
- package/dist/update/update.d.ts +49 -0
- package/dist/update/update.js +82 -0
- package/package.json +15 -13
package/dist/input/input.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback } from 'react';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useRef } from 'react';
|
|
4
4
|
import { cn } from "../internal/cn.js";
|
|
5
|
+
import { composeRefs } from "../internal/compose-refs.js";
|
|
6
|
+
import { KptSpeechButton } from "../speech/speech-button.js";
|
|
7
|
+
import { useKptSpeechRecognition } from "../speech/use-speech-recognition.js";
|
|
5
8
|
import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
6
9
|
/**
|
|
7
10
|
* Pole tekstowe Koncept UI. Renderuje natywny `<input>` w hoście `.kpt-input-host`.
|
|
8
11
|
*
|
|
9
|
-
* Działa kontrolowane (`value` + `onValueChange`) i niekontrolowane (`defaultValue`)
|
|
12
|
+
* Działa kontrolowane (`value` + `onValueChange`) i niekontrolowane (`defaultValue`) -
|
|
10
13
|
* w drugim trybie wartość należy do DOM, więc natywny `<form>`, `<form action>`, reset
|
|
11
14
|
* formularza i React Hook Form (`register`) działają bez adaptera.
|
|
12
15
|
*
|
|
@@ -17,10 +20,22 @@ import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
|
17
20
|
* <KptInput name="email" type="email" defaultValue="" />
|
|
18
21
|
* <KptInput value={email} onValueChange={setEmail} invalid={!ok} touched={blurred} />
|
|
19
22
|
*/
|
|
20
|
-
export function KptInput({ type = 'text', required = false, invalid = false, touched, onValueChange, onTouch, hostProps, className, id, onChange, onBlur, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, ...rest }) {
|
|
23
|
+
export function KptInput({ type = 'text', required = false, invalid = false, touched, onValueChange, onTouch, hostProps, className, id, onChange, onBlur, ref, speech = false, speechLang, speechColor, speechMode = 'insert', 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, ...rest }) {
|
|
21
24
|
const { className: hostClassName, ...hostRest } = hostProps ?? {};
|
|
22
25
|
const field = useKptFieldA11y(id, 'kpt-input');
|
|
23
|
-
|
|
26
|
+
const innerRef = useRef(null);
|
|
27
|
+
// Tekst zatwierdzony wchodzi przez zdarzenie `input` pola, więc `onChange` dostaje go jak wpisany;
|
|
28
|
+
// tymczasowy jest tylko na ekranie. Bez `speech` kontroler nie tworzy sesji.
|
|
29
|
+
const mic = useKptSpeechRecognition({
|
|
30
|
+
enabled: speech,
|
|
31
|
+
target: innerRef,
|
|
32
|
+
lang: speechLang,
|
|
33
|
+
mode: speechMode,
|
|
34
|
+
continuous: speechMode !== 'replace',
|
|
35
|
+
disabled: !!rest.disabled || !!rest.readOnly,
|
|
36
|
+
});
|
|
37
|
+
const speechState = speech && mic.available ? (mic.listening ? 'listening' : 'idle') : undefined;
|
|
38
|
+
// Stan nieprawidłowy pokazujemy dopiero po dotknięciu pola - jak natywne `:user-invalid`.
|
|
24
39
|
// Bez `touched` nie ma czego bramkować, więc decyduje samo `invalid`.
|
|
25
40
|
const showInvalid = invalid && (touched ?? true);
|
|
26
41
|
const handleChange = useCallback((event) => {
|
|
@@ -31,5 +46,5 @@ export function KptInput({ type = 'text', required = false, invalid = false, tou
|
|
|
31
46
|
onBlur?.(event);
|
|
32
47
|
onTouch?.();
|
|
33
48
|
}, [onBlur, onTouch]);
|
|
34
|
-
return (
|
|
49
|
+
return (_jsxs("span", { className: cn('kpt-input-host', hostClassName), "data-speech": speechState, ...hostRest, children: [_jsx("input", { className: cn('kpt-input__field', className), id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), type: type, "aria-required": required || undefined, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ref: composeRefs(innerRef, ref), ...rest }), speech ? (_jsx(KptSpeechButton, { listeningColor: speechColor, speech: mic, size: "sm", unsupported: "hide", disabled: !!rest.disabled || !!rest.readOnly, hostProps: { className: 'kpt-input__speech' } })) : null] }));
|
|
35
50
|
}
|
package/dist/input/llms.txt
CHANGED
|
@@ -5,28 +5,28 @@ Import: `import { KptInput } from '@konce-pt/react';`
|
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<span class="kpt-input-host">
|
|
8
|
-
<input class="kpt-input__field" id="
|
|
8
|
+
<input class="kpt-input__field" id="..." type="text">
|
|
9
9
|
</span>
|
|
10
10
|
|
|
11
11
|
## Props
|
|
12
12
|
- `type`: 'text' | 'email' | 'password' | 'number' | 'search' | 'tel' | 'url' | 'time' (default 'text')
|
|
13
|
-
- `value` / `defaultValue`
|
|
14
|
-
- `onValueChange(value)`
|
|
15
|
-
- `onTouch()`
|
|
16
|
-
- `required`: boolean
|
|
17
|
-
- `invalid`: boolean, `touched`: boolean
|
|
18
|
-
- `hostProps`
|
|
13
|
+
- `value` / `defaultValue` - controlled or uncontrolled, exactly like a native input
|
|
14
|
+
- `onValueChange(value)` - the value alone; `onChange` still fires with the full event
|
|
15
|
+
- `onTouch()` - fires on blur, the moment the field becomes touched
|
|
16
|
+
- `required`: boolean - see the note below
|
|
17
|
+
- `invalid`: boolean, `touched`: boolean - the error state
|
|
18
|
+
- `hostProps` - props for the `.kpt-input-host` wrapper
|
|
19
19
|
- `className`, `ref`, `name`, `placeholder`, `autoComplete` and every other `<input>` prop go to
|
|
20
20
|
the inner `<input>`
|
|
21
21
|
|
|
22
22
|
## Controlled and uncontrolled
|
|
23
23
|
Pass `value` and the field is controlled. Pass `defaultValue` (or nothing) and the value belongs
|
|
24
|
-
to the DOM, so a native `<form>`, `<form action={
|
|
25
|
-
`register()` all work without an adapter
|
|
24
|
+
to the DOM, so a native `<form>`, `<form action={...}>`, a form reset and React Hook Form's
|
|
25
|
+
`register()` all work without an adapter - there is no internal mirror of the value to fight with.
|
|
26
26
|
|
|
27
27
|
## The error state
|
|
28
28
|
`aria-invalid="true"` is set when `invalid` is true. Pass `touched` as well to reproduce the
|
|
29
|
-
Angular port's gate
|
|
29
|
+
Angular port's gate - the error then shows only after the field has been touched, like the native
|
|
30
30
|
`:user-invalid`. With `touched` omitted there is nothing to gate on, so `invalid` decides alone;
|
|
31
31
|
that is the common case in React, where the form library already knows when an error is ready.
|
|
32
32
|
The style hangs off `aria-invalid`, never off a class.
|
|
@@ -55,5 +55,19 @@ added to `aria-describedby` (merged with your own). Without a wrapper, name it w
|
|
|
55
55
|
`--kpt-form-field-{bg,text,placeholder,border,border-hover,border-focus,border-error,radius}`.
|
|
56
56
|
|
|
57
57
|
## Accessibility
|
|
58
|
-
A native `<input>`
|
|
58
|
+
A native `<input>` - full keyboard and screen reader support. `aria-required` marks the field as
|
|
59
59
|
required, `aria-invalid` marks it as erroneous, and the focus ring comes from `@konce-pt/styles`.
|
|
60
|
+
|
|
61
|
+
## Dictation
|
|
62
|
+
- `speech`: boolean = false - a microphone at the end of the field (`KptSpeechButton`, Web Speech
|
|
63
|
+
API). Without browser support it is not shown and the field keeps its normal padding.
|
|
64
|
+
- `speechLang`: string - BCP 47 tag; without it from `KptI18nProvider`.
|
|
65
|
+
- `speechColor`: `'primary' | 'danger' | 'success' | 'warning' | 'info'` = `'primary'` - colour of "stop" and the wave while listening.
|
|
66
|
+
- `speechMode`: `'insert' | 'append' | 'replace'` = `'insert'`. `replace` clears the field the moment
|
|
67
|
+
the microphone is clicked (undoable with Ctrl+Z) and stops after one utterance - the search pattern.
|
|
68
|
+
|
|
69
|
+
Interim words are visible in the field but never reach your state; final text comes through
|
|
70
|
+
`onChange` / `onValueChange` like typed text.
|
|
71
|
+
|
|
72
|
+
<KptInput value={title} onValueChange={setTitle} speech />
|
|
73
|
+
<KptInput type="search" speech speechMode="replace" />
|
|
@@ -6,7 +6,7 @@ export interface KptInputMaskProps extends Omit<ComponentPropsWithRef<'input'>,
|
|
|
6
6
|
/** Wzorzec maski; pozostałe znaki to literały (spacje, nawiasy, myślniki). */
|
|
7
7
|
mask?: string;
|
|
8
8
|
/**
|
|
9
|
-
* Pole wymagane
|
|
9
|
+
* Pole wymagane - `aria-required`, a nie natywne `required` (jak w `KptInput`): natywne
|
|
10
10
|
* blokowałoby wysyłkę i uruchamiało walidację przeglądarki obok Twojej.
|
|
11
11
|
*/
|
|
12
12
|
required?: boolean;
|
|
@@ -13,7 +13,7 @@ import { KPT_MASK_TOKENS, kptApplyMask, kptMaskCaret } from "../internal/mask.js
|
|
|
13
13
|
*/
|
|
14
14
|
export function KptInputMask({ value, defaultValue = '', onValueChange, mask = '', placeholder, required = false, invalid = false, touched, onTouch, disabled = false, className, id, onBlur, 'aria-describedby': ariaDescribedBy, inputMode, ...rest }) {
|
|
15
15
|
const field = useKptFieldA11y(id, 'kpt-input-mask');
|
|
16
|
-
// Klawiatura ekranowa z maski: same tokeny `9` (telefon, kod pocztowy)
|
|
16
|
+
// Klawiatura ekranowa z maski: same tokeny `9` (telefon, kod pocztowy) -> numeryczna.
|
|
17
17
|
const tokens = [...mask].filter((char) => char in KPT_MASK_TOKENS);
|
|
18
18
|
const autoInputMode = tokens.length && tokens.every((char) => char === '9') ? 'numeric' : 'text';
|
|
19
19
|
const inputId = field.id;
|
|
@@ -25,7 +25,7 @@ export function KptInputMask({ value, defaultValue = '', onValueChange, mask = '
|
|
|
25
25
|
const caret = el.selectionStart ?? raw.length;
|
|
26
26
|
const formatted = kptApplyMask(raw, mask);
|
|
27
27
|
setCurrent(formatted);
|
|
28
|
-
// Gdy maska odrzuci znak, wartość się nie zmienia i React nie przerysuje pola
|
|
28
|
+
// Gdy maska odrzuci znak, wartość się nie zmienia i React nie przerysuje pola -
|
|
29
29
|
// wpisany znak zostałby na ekranie, więc DOM zrównujemy ręcznie.
|
|
30
30
|
el.value = formatted;
|
|
31
31
|
// Przepisanie `value` przenosi kursor na koniec; wraca za tyle samo znaczących znaków co przed zmianą.
|
package/dist/input-mask/llms.txt
CHANGED
|
@@ -9,9 +9,9 @@ Import: `import { KptInputMask } from '@konce-pt/react';`
|
|
|
9
9
|
</span>
|
|
10
10
|
|
|
11
11
|
## Props
|
|
12
|
-
- `value` / `defaultValue` / `onValueChange`
|
|
13
|
-
- `mask`: string
|
|
14
|
-
- `placeholder`: string
|
|
12
|
+
- `value` / `defaultValue` / `onValueChange` - the formatted text
|
|
13
|
+
- `mask`: string - `9` a digit, `a` a letter, `*` alphanumeric; everything else is a literal
|
|
14
|
+
- `placeholder`: string - defaults to the mask itself, which doubles as a hint
|
|
15
15
|
- `invalid`, `touched`, `onTouch()`
|
|
16
16
|
- `className`, `ref` and every other `<input>` prop go to the input
|
|
17
17
|
|
|
@@ -22,7 +22,7 @@ digits therefore produce the same result, and deleting a literal cannot leave a
|
|
|
22
22
|
pattern. Characters that match nothing are skipped rather than rejected, so stray letters around a
|
|
23
23
|
number still format.
|
|
24
24
|
|
|
25
|
-
Like the OTP field, the DOM is synced by hand when the mask drops a character
|
|
25
|
+
Like the OTP field, the DOM is synced by hand when the mask drops a character - the value did not
|
|
26
26
|
change, so React would not re-render and the character would linger on screen.
|
|
27
27
|
|
|
28
28
|
## Examples
|
|
@@ -32,7 +32,7 @@ change, so React would not re-render and the character would linger on screen.
|
|
|
32
32
|
## Screen reader and keyboard
|
|
33
33
|
The on-screen keyboard follows the mask: only `9` tokens (phone, postal code) give
|
|
34
34
|
`inputMode="numeric"`, otherwise `text`; pass `inputMode` to override it, and `autoComplete` (`tel`,
|
|
35
|
-
`postal-code
|
|
35
|
+
`postal-code`...) so the browser can fill the field in.
|
|
36
36
|
|
|
37
37
|
## Label and description
|
|
38
38
|
`id` goes to the native field, not the host; without one it comes from `KptFormField` or is
|
|
@@ -10,29 +10,29 @@ export interface KptInputNumberProps extends Omit<ComponentPropsWithRef<'div'>,
|
|
|
10
10
|
placeholder?: string;
|
|
11
11
|
/** Dopisek pokazywany za liczbą, np. ' szt.' albo 'ms'. */
|
|
12
12
|
suffix?: string;
|
|
13
|
-
/** Przyciski krokowania. `false` daje samo pole
|
|
13
|
+
/** Przyciski krokowania. `false` daje samo pole - wariant do zakresów "od-do". */
|
|
14
14
|
showButtons?: boolean;
|
|
15
|
-
/** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField`
|
|
15
|
+
/** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` - z wrappera. */
|
|
16
16
|
id?: string;
|
|
17
17
|
/** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
|
|
18
18
|
ariaLabel?: string | null;
|
|
19
19
|
/** Oznacza pole jako wymagane atrybutem `aria-required`. */
|
|
20
20
|
required?: boolean;
|
|
21
21
|
disabled?: boolean;
|
|
22
|
-
/** Tylko do odczytu
|
|
22
|
+
/** Tylko do odczytu - wartość widać i da się ją zaznaczyć, ale nie zmienić (także strzałkami). */
|
|
23
23
|
readOnly?: boolean;
|
|
24
24
|
invalid?: boolean;
|
|
25
25
|
touched?: boolean;
|
|
26
26
|
onTouch?: () => void;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Pole liczbowe ze strzałkami krokowania. Wartość to `number | null`
|
|
30
|
-
* bo
|
|
29
|
+
* Pole liczbowe ze strzałkami krokowania. Wartość to `number | null` - puste pole ma znaczenie,
|
|
30
|
+
* bo "brak wartości" to nie to samo co zero.
|
|
31
31
|
*
|
|
32
|
-
* Pole to `role="spinbutton"` (z `aria-valuemin`/`max`/`now`, a przy `suffix`
|
|
33
|
-
*
|
|
34
|
-
* jest przycinana w trakcie pisania (inaczej
|
|
35
|
-
* granice działają przy krokowaniu i na `blur`. Przyciski
|
|
32
|
+
* Pole to `role="spinbutton"` (z `aria-valuemin`/`max`/`now`, a przy `suffix` - `aria-valuetext`):
|
|
33
|
+
* `ArrowUp`/`ArrowDown` zmieniają wartość o `step`, `PageUp`/`PageDown` o dziesięć kroków. Wpisywana liczba nie
|
|
34
|
+
* jest przycinana w trakcie pisania (inaczej "150" przy `max` 99 stawało się "99", zanim user skończył) -
|
|
35
|
+
* granice działają przy krokowaniu i na `blur`. Przyciski `-`/`+` stoją poza kolejnością Tab i nie
|
|
36
36
|
* zabierają fokusu polu.
|
|
37
37
|
*
|
|
38
38
|
* @example
|
|
@@ -10,13 +10,13 @@ import { kptRoundTo } from "../internal/step.js";
|
|
|
10
10
|
/** Liczba dziesiętna wpisana przez człowieka: bez `0x1A`, `1e3` i `Infinity`, które `Number()` też przyjmuje. */
|
|
11
11
|
const DECIMAL = /^[-+]?(?:\d+\.?\d*|\.\d+)$/;
|
|
12
12
|
/**
|
|
13
|
-
* Pole liczbowe ze strzałkami krokowania. Wartość to `number | null`
|
|
14
|
-
* bo
|
|
13
|
+
* Pole liczbowe ze strzałkami krokowania. Wartość to `number | null` - puste pole ma znaczenie,
|
|
14
|
+
* bo "brak wartości" to nie to samo co zero.
|
|
15
15
|
*
|
|
16
|
-
* Pole to `role="spinbutton"` (z `aria-valuemin`/`max`/`now`, a przy `suffix`
|
|
17
|
-
*
|
|
18
|
-
* jest przycinana w trakcie pisania (inaczej
|
|
19
|
-
* granice działają przy krokowaniu i na `blur`. Przyciski
|
|
16
|
+
* Pole to `role="spinbutton"` (z `aria-valuemin`/`max`/`now`, a przy `suffix` - `aria-valuetext`):
|
|
17
|
+
* `ArrowUp`/`ArrowDown` zmieniają wartość o `step`, `PageUp`/`PageDown` o dziesięć kroków. Wpisywana liczba nie
|
|
18
|
+
* jest przycinana w trakcie pisania (inaczej "150" przy `max` 99 stawało się "99", zanim user skończył) -
|
|
19
|
+
* granice działają przy krokowaniu i na `blur`. Przyciski `-`/`+` stoją poza kolejnością Tab i nie
|
|
20
20
|
* zabierają fokusu polu.
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
@@ -32,7 +32,7 @@ export function KptInputNumber({ value, defaultValue = null, onValueChange, min,
|
|
|
32
32
|
onChange: onValueChange,
|
|
33
33
|
});
|
|
34
34
|
const showInvalid = invalid && (touched ?? true);
|
|
35
|
-
/** Tekst w trakcie pisania
|
|
35
|
+
/** Tekst w trakcie pisania - dopóki jest, pole pokazuje go zamiast sformatowanej wartości. */
|
|
36
36
|
const [draft, setDraft] = useState(null);
|
|
37
37
|
const clamp = useCallback((n) => {
|
|
38
38
|
if (min !== undefined && n < min)
|
|
@@ -41,17 +41,17 @@ export function KptInputNumber({ value, defaultValue = null, onValueChange, min,
|
|
|
41
41
|
return max;
|
|
42
42
|
return n;
|
|
43
43
|
}, [min, max]);
|
|
44
|
-
// Zapis liczby wg aktywnego języka (PL: `12,5`), bez separatorów tysięcy
|
|
44
|
+
// Zapis liczby wg aktywnego języka (PL: `12,5`), bez separatorów tysięcy - pole przyjmuje i kropkę,
|
|
45
45
|
// i przecinek, a grupowanie cyfr rozjechałoby się z tym, co user wpisuje.
|
|
46
|
-
// `latn`: cyfry łacińskie także w locale z własnymi (np. `ar`)
|
|
46
|
+
// `latn`: cyfry łacińskie także w locale z własnymi (np. `ar`) - inaczej pole pokazywałoby zapis,
|
|
47
47
|
// którego parser niżej nie przeczyta.
|
|
48
48
|
const format = new Intl.NumberFormat(activeLocale, { useGrouping: false, maximumFractionDigits: 20, numberingSystem: 'latn' });
|
|
49
49
|
const display = current === null || current === undefined || Number.isNaN(current) ? '' : `${format.format(current)}${suffix}`;
|
|
50
50
|
const canIncrement = max === undefined || (current ?? -Infinity) < max;
|
|
51
51
|
const canDecrement = min === undefined || (current ?? Infinity) > min;
|
|
52
52
|
const onInput = (event) => {
|
|
53
|
-
// Przecinek jako separator dziesiętny i dopisek trafiają do pola razem z liczbą
|
|
54
|
-
// czyścimy je przed parsowaniem, żeby wpisywanie
|
|
53
|
+
// Przecinek jako separator dziesiętny i dopisek trafiają do pola razem z liczbą -
|
|
54
|
+
// czyścimy je przed parsowaniem, żeby wpisywanie "12,5 zł" działało naturalnie.
|
|
55
55
|
setDraft(event.target.value);
|
|
56
56
|
const raw = event.target.value.replace(suffix, '').replace(',', '.').trim();
|
|
57
57
|
if (raw === '') {
|
|
@@ -5,20 +5,20 @@ A number field with stepper arrows. Import: `import { KptInputNumber } from '@ko
|
|
|
5
5
|
## DOM
|
|
6
6
|
<div class="kpt-input-number-host">
|
|
7
7
|
<div class="kpt-input-number">
|
|
8
|
-
<button class="kpt-input-number__btn" aria-label="Decrease"
|
|
8
|
+
<button class="kpt-input-number__btn" aria-label="Decrease">...</button>
|
|
9
9
|
<input class="kpt-input-number__input" type="text" inputmode="decimal" value="12 zł">
|
|
10
|
-
<button class="kpt-input-number__btn" aria-label="Increase"
|
|
10
|
+
<button class="kpt-input-number__btn" aria-label="Increase">...</button>
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
14
|
## Props
|
|
15
|
-
- `value` / `defaultValue` / `onValueChange`
|
|
15
|
+
- `value` / `defaultValue` / `onValueChange` - `number | null`
|
|
16
16
|
- `min`, `max`, `step` (default 1)
|
|
17
|
-
- `placeholder`, `suffix`
|
|
18
|
-
- `showButtons`: boolean (default true)
|
|
19
|
-
- `disabled`, `readOnly`, `invalid`, `touched`, `onTouch()`
|
|
17
|
+
- `placeholder`, `suffix` - text shown after the number, e.g. ' szt.' or 'ms'
|
|
18
|
+
- `showButtons`: boolean (default true) - `false` leaves the bare field
|
|
19
|
+
- `disabled`, `readOnly`, `invalid`, `touched`, `onTouch()` - `readOnly` leaves the value selectable but
|
|
20
20
|
blocks typing, the arrows and the buttons (`aria-readonly`)
|
|
21
|
-
- `locale`, `dictionary`
|
|
21
|
+
- `locale`, `dictionary` - i18n overrides for this component only
|
|
22
22
|
|
|
23
23
|
## Null is a value
|
|
24
24
|
The value is `number | null`, not `number`: an empty field means "no value", which is not the same
|
|
@@ -27,8 +27,8 @@ nothing to step from.
|
|
|
27
27
|
|
|
28
28
|
## A text input, not a number input
|
|
29
29
|
The field is `type="text"` with `inputmode="decimal"`, so the suffix can live inside it and a comma
|
|
30
|
-
works as the decimal separator
|
|
31
|
-
reject both. Values out of range are clamped on blur and when stepping
|
|
30
|
+
works as the decimal separator - typing "12,5 zł" parses correctly. A native `type="number"` would
|
|
31
|
+
reject both. Values out of range are clamped on blur and when stepping - not while typing.
|
|
32
32
|
|
|
33
33
|
## i18n
|
|
34
34
|
The stepper labels come from `inputNumber.decrement` and `inputNumber.increment`.
|
|
@@ -39,16 +39,16 @@ The stepper labels come from `inputNumber.decrement` and `inputNumber.increment`
|
|
|
39
39
|
|
|
40
40
|
## Keyboard
|
|
41
41
|
The field is `role="spinbutton"` with `aria-valuemin`/`aria-valuemax`/`aria-valuenow` (and
|
|
42
|
-
`aria-valuetext` with the `suffix`, "5 pcs").
|
|
42
|
+
`aria-valuetext` with the `suffix`, "5 pcs"). `ArrowUp`/`ArrowDown` change the value by `step`,
|
|
43
43
|
`PageUp`/`PageDown` by ten steps; stepping is rounded to the precision of `step` or of the current
|
|
44
44
|
value, whichever is finer (`1.25` + 1 gives `2.25`, not `2`). Only a plain decimal is accepted while
|
|
45
|
-
typing
|
|
46
|
-
**not** clamped while typing ("150" with `max` 99 stays "150", so the form's `max()` can report it)
|
|
47
|
-
it is clamped on blur. The
|
|
45
|
+
typing - `0x1A`, `1e3` and `Infinity` are ignored. A typed value is
|
|
46
|
+
**not** clamped while typing ("150" with `max` 99 stays "150", so the form's `max()` can report it) -
|
|
47
|
+
it is clamped on blur. The `-`/`+` buttons sit outside the Tab order and do not take focus from the
|
|
48
48
|
field, so focus never drops to `<body>` when a button goes disabled at a limit.
|
|
49
49
|
|
|
50
50
|
## Screen reader and keyboard
|
|
51
|
-
The value is shown in the active locale's notation (PL `12,5`), without thousands separators
|
|
51
|
+
The value is shown in the active locale's notation (PL `12,5`), without thousands separators - the
|
|
52
52
|
field accepts both a dot and a comma, and digit grouping would clash with what the user types.
|
|
53
53
|
|
|
54
54
|
## Label and description
|
|
@@ -6,29 +6,29 @@ export interface KptInputOtpProps extends Omit<ComponentPropsWithRef<'div'>, 'on
|
|
|
6
6
|
onValueChange?: (value: string) => void;
|
|
7
7
|
length?: number;
|
|
8
8
|
/**
|
|
9
|
-
* Co ile komórek wstawić separator, licząc od lewej (`3` przy `length` 9
|
|
10
|
-
* `0` (domyślnie)
|
|
9
|
+
* Co ile komórek wstawić separator, licząc od lewej (`3` przy `length` 9 -> `[][][]-[][][]-[][][]`).
|
|
10
|
+
* `0` (domyślnie) - bez grup. Separator jest wyłącznie wizualny: wartość to same znaki.
|
|
11
11
|
*/
|
|
12
12
|
groupSize?: number;
|
|
13
13
|
/** Znak między grupami komórek. */
|
|
14
14
|
groupSeparator?: string;
|
|
15
15
|
/** Dopuszcza wyłącznie cyfry i przełącza klawiaturę mobilną na numeryczną. */
|
|
16
16
|
integerOnly?: boolean;
|
|
17
|
-
/** Id pierwszej komórki (nie hosta)
|
|
17
|
+
/** Id pierwszej komórki (nie hosta) - klik w etykietę zaczyna wpisywanie od początku. */
|
|
18
18
|
id?: string;
|
|
19
19
|
/** Nazwa grupy komórek, gdy nie opisuje jej etykieta (`KptFormField`). */
|
|
20
20
|
ariaLabel?: string | null;
|
|
21
21
|
disabled?: boolean;
|
|
22
|
-
/** Tylko do odczytu
|
|
22
|
+
/** Tylko do odczytu - kod widać, nie da się go zmienić. */
|
|
23
23
|
readOnly?: boolean;
|
|
24
|
-
/** Pole wymagane
|
|
24
|
+
/** Pole wymagane - `aria-required` na komórkach. */
|
|
25
25
|
required?: boolean;
|
|
26
26
|
invalid?: boolean;
|
|
27
27
|
touched?: boolean;
|
|
28
28
|
onTouch?: () => void;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Pole kodu jednorazowego (OTP/PIN)
|
|
31
|
+
* Pole kodu jednorazowego (OTP/PIN) - N osobnych pól, automatyczne przejście do następnego
|
|
32
32
|
* i wklejanie całego kodu naraz. Wartością są wpisane znaki **bez dziur** (`'13'`, nie `'1 3'`), więc
|
|
33
33
|
* walidator długości i backend widzą tyle znaków, ile naprawdę wpisano.
|
|
34
34
|
*
|
|
@@ -6,7 +6,7 @@ import { useControllableState } from "../internal/use-controllable-state.js";
|
|
|
6
6
|
import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
7
7
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
8
8
|
/**
|
|
9
|
-
* Pole kodu jednorazowego (OTP/PIN)
|
|
9
|
+
* Pole kodu jednorazowego (OTP/PIN) - N osobnych pól, automatyczne przejście do następnego
|
|
10
10
|
* i wklejanie całego kodu naraz. Wartością są wpisane znaki **bez dziur** (`'13'`, nie `'1 3'`), więc
|
|
11
11
|
* walidator długości i backend widzą tyle znaków, ile naprawdę wpisano.
|
|
12
12
|
*
|
|
@@ -14,7 +14,7 @@ import { useKptMessages } from "../i18n/i18n-context.js";
|
|
|
14
14
|
* <KptInputOtp value={code} onValueChange={setCode} length={6} integerOnly />
|
|
15
15
|
* <KptInputOtp value={code} onValueChange={setCode} length={9} groupSize={3} />
|
|
16
16
|
*/
|
|
17
|
-
export function KptInputOtp({ value, defaultValue = '', onValueChange, length = 6, groupSize = 0, groupSeparator = '
|
|
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 }) {
|
|
18
18
|
const { t } = useKptMessages({ locale, dictionary });
|
|
19
19
|
const field = useKptFieldA11y(id, 'kpt-input-otp');
|
|
20
20
|
const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
|
|
@@ -22,8 +22,8 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
22
22
|
/*
|
|
23
23
|
* Komórki trzymają układ osobno od wartości: wyczyszczenie środkowej zostawia w niej pustkę,
|
|
24
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
|
|
26
|
-
* wartość w stanie
|
|
25
|
+
* (inna niż złożenie bieżących komórek) układa znaki od początku - wzorzec "poprzednia
|
|
26
|
+
* wartość w stanie", bez efektu.
|
|
27
27
|
*/
|
|
28
28
|
const toCells = (text) => Array.from({ length }, (_, index) => text[index] ?? '');
|
|
29
29
|
const [cells, setCells] = useState(() => toCells(current));
|
|
@@ -32,7 +32,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
32
32
|
setCells(toCells(current));
|
|
33
33
|
const shown = inSync ? cells : toCells(current);
|
|
34
34
|
const charAt = (index) => shown[index] ?? '';
|
|
35
|
-
/** Zapis komórek i złożonej z nich wartości
|
|
35
|
+
/** Zapis komórek i złożonej z nich wartości - jedno miejsce, żeby układ i model się nie rozjechały. */
|
|
36
36
|
const commitCells = (next) => {
|
|
37
37
|
setCells(next);
|
|
38
38
|
setCurrent(next.join(''));
|
|
@@ -42,7 +42,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
42
42
|
next[index] = char;
|
|
43
43
|
commitCells(next);
|
|
44
44
|
};
|
|
45
|
-
/** Następna/poprzednia komórka
|
|
45
|
+
/** Następna/poprzednia komórka - po polach, nie po rodzeństwie, bo między grupami stoi separator. */
|
|
46
46
|
const focusSibling = (el, direction) => {
|
|
47
47
|
const cells = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
|
|
48
48
|
cells[cells.indexOf(el) + direction]?.focus();
|
|
@@ -50,7 +50,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
50
50
|
/** Czy za komórką `index` kończy się grupa (a nie cały kod). */
|
|
51
51
|
const group = Math.floor(groupSize);
|
|
52
52
|
const separatorAfter = (index) => group >= 1 && (index + 1) % group === 0 && index < length - 1;
|
|
53
|
-
/** Wpisuje `text` od komórki `start` (bez spacji i
|
|
53
|
+
/** Wpisuje `text` od komórki `start` (bez spacji i - przy `integerOnly` - bez nie-cyfr). */
|
|
54
54
|
const fillFrom = (start, text, el) => {
|
|
55
55
|
let chars = text.replace(/\s/g, '');
|
|
56
56
|
if (integerOnly)
|
|
@@ -59,7 +59,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
59
59
|
for (let k = 0; k < chars.length && start + k < length; k += 1)
|
|
60
60
|
arr[start + k] = chars[k];
|
|
61
61
|
commitCells(arr);
|
|
62
|
-
// Fokus na pierwszą pustą komórkę, a przy komplecie
|
|
62
|
+
// Fokus na pierwszą pustą komórkę, a przy komplecie - na ostatnią.
|
|
63
63
|
const inputs = [...(el.closest('.kpt-input-otp')?.querySelectorAll('input') ?? [])];
|
|
64
64
|
const empty = arr.findIndex((char) => char === '');
|
|
65
65
|
inputs[empty >= 0 ? empty : inputs.length - 1]?.focus();
|
|
@@ -69,7 +69,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
69
69
|
if (readOnly)
|
|
70
70
|
return;
|
|
71
71
|
// Kilka znaków naraz to autouzupełnienie kodu z SMS (`one-time-code`) albo wklejenie przez
|
|
72
|
-
// klawiaturę ekranową
|
|
72
|
+
// klawiaturę ekranową - rozkładamy je po komórkach od bieżącej. Dwa znaki w zajętej komórce
|
|
73
73
|
// to zwykłe nadpisanie: stary znak + nowy.
|
|
74
74
|
if (el.value.length > 1 && !(el.value.length === 2 && charAt(index))) {
|
|
75
75
|
const text = el.value;
|
|
@@ -102,7 +102,7 @@ export function KptInputOtp({ value, defaultValue = '', onValueChange, length =
|
|
|
102
102
|
return;
|
|
103
103
|
fillFrom(0, event.clipboardData.getData('text'), event.currentTarget);
|
|
104
104
|
};
|
|
105
|
-
/**
|
|
105
|
+
/** "Dotknięcie" dopiero przy wyjściu fokusu z całej grupy, nie przy przejściu między komórkami. */
|
|
106
106
|
const onGroupBlur = (event) => {
|
|
107
107
|
const next = event.relatedTarget;
|
|
108
108
|
if (!next || !event.currentTarget.contains(next))
|
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
|
|
@@ -61,8 +61,8 @@ keypad for a PIN instead of the full keyboard.
|
|
|
61
61
|
|
|
62
62
|
## Groups
|
|
63
63
|
`groupSize` (default `0` = no groups) inserts a separator after every N boxes, counted from the
|
|
64
|
-
left; `groupSeparator` sets the character (default
|
|
65
|
-
`[][][]
|
|
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
66
|
(`"123456789"`), each box keeps its name "Character 4 of 9", and arrows/Backspace jump over it.
|
|
67
67
|
|
|
68
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
|
package/dist/internal/mask.d.ts
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
export declare const KPT_MASK_TOKENS: Readonly<Record<string, RegExp>>;
|
|
3
3
|
/**
|
|
4
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
|
|
5
|
+
* tokenów, a literały wstawia sama. Dzięki temu wklejenie "48123456789" i wpisanie "(48) 123..."
|
|
6
6
|
* dają ten sam wynik, a usunięcie literału nie zostawia dziury we wzorcu.
|
|
7
7
|
*/
|
|
8
8
|
export declare function kptApplyMask(raw: string, mask: string): string;
|
|
9
9
|
/**
|
|
10
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
|
|
11
|
+
* kursorem w surowym tekście i stawia kursor za tyloma samymi znakami w wyniku - poprawienie
|
|
12
12
|
* cyfry w środku numeru nie przerzuca kursora na koniec pola.
|
|
13
13
|
*/
|
|
14
14
|
export declare function kptMaskCaret(raw: string, caret: number, mask: string): number;
|
package/dist/internal/mask.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Maska znakowa `kpt-input-mask`. Bliźniak w porcie Angulara (`shared/mask.ts`)
|
|
2
|
+
* Maska znakowa `kpt-input-mask`. Bliźniak w porcie Angulara (`shared/mask.ts`) - zmiana w obu.
|
|
3
3
|
*/
|
|
4
4
|
/** Tokeny maski: `9` = cyfra, `a` = litera (także `ą`, `ł`, `ß`), `*` = litera albo cyfra. */
|
|
5
5
|
export const KPT_MASK_TOKENS = {
|
|
@@ -9,7 +9,7 @@ export const KPT_MASK_TOKENS = {
|
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
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
|
|
12
|
+
* tokenów, a literały wstawia sama. Dzięki temu wklejenie "48123456789" i wpisanie "(48) 123..."
|
|
13
13
|
* dają ten sam wynik, a usunięcie literału nie zostawia dziury we wzorcu.
|
|
14
14
|
*/
|
|
15
15
|
export function kptApplyMask(raw, mask) {
|
|
@@ -37,7 +37,7 @@ export function kptApplyMask(raw, mask) {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
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
|
|
40
|
+
* kursorem w surowym tekście i stawia kursor za tyloma samymi znakami w wyniku - poprawienie
|
|
41
41
|
* cyfry w środku numeru nie przerzuca kursora na koniec pola.
|
|
42
42
|
*/
|
|
43
43
|
export function kptMaskCaret(raw, caret, mask) {
|
|
@@ -45,7 +45,7 @@ export function kptMaskCaret(raw, caret, mask) {
|
|
|
45
45
|
if (!mask)
|
|
46
46
|
return Math.min(caret, formatted.length);
|
|
47
47
|
const before = kptApplyMask(raw.slice(0, caret), mask);
|
|
48
|
-
// Ile znaczących znaków jest przed kursorem
|
|
48
|
+
// Ile znaczących znaków jest przed kursorem - liczone na wyniku, więc literały się nie liczą.
|
|
49
49
|
let significant = 0;
|
|
50
50
|
for (let i = 0; i < before.length; i += 1)
|
|
51
51
|
if (KPT_MASK_TOKENS[mask[i]])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Klucz Reacta dla opcji kontrolki generycznej: wartość prymitywna jako tekst, obiekt
|
|
3
|
-
* `String(obiekt)` dawałby
|
|
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
4
|
* przenoszony między opcjami przy zmianie listy.
|
|
5
5
|
*/
|
|
6
6
|
export declare function optionKey(value: unknown, index: number): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Klucz Reacta dla opcji kontrolki generycznej: wartość prymitywna jako tekst, obiekt
|
|
3
|
-
* `String(obiekt)` dawałby
|
|
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
4
|
* przenoszony między opcjami przy zmianie listy.
|
|
5
5
|
*/
|
|
6
6
|
export function optionKey(value, index) {
|