@konce-pt/react 0.11.2 → 0.12.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 +8 -2
- package/dist/accordion/accordion.js +11 -10
- package/dist/alert/alert.js +1 -0
- package/dist/alert/llms.txt +1 -0
- package/dist/app-shell/app-shell.js +12 -5
- package/dist/app-shell/llms.txt +5 -4
- package/dist/auth/auth.js +17 -8
- package/dist/auth/llms.txt +3 -2
- package/dist/autocomplete/autocomplete.d.ts +1 -1
- package/dist/autocomplete/autocomplete.js +12 -4
- package/dist/autocomplete/llms.txt +3 -0
- package/dist/avatar/avatar.js +1 -0
- package/dist/avatar-group/avatar-group.js +1 -0
- package/dist/backdrop/backdrop.d.ts +0 -19
- package/dist/backdrop/backdrop.js +18 -13
- package/dist/bottom-sheet/bottom-sheet.d.ts +6 -1
- package/dist/bottom-sheet/bottom-sheet.js +3 -2
- package/dist/bottom-sheet/llms.txt +3 -0
- package/dist/breadcrumb/breadcrumb.d.ts +7 -1
- package/dist/breadcrumb/breadcrumb.js +10 -2
- package/dist/breadcrumb/llms.txt +8 -0
- package/dist/button/button.js +2 -1
- package/dist/button-group/button-group.d.ts +14 -1
- package/dist/button-group/button-group.js +30 -4
- package/dist/button-group/llms.txt +9 -6
- package/dist/card/card.js +4 -3
- package/dist/carousel/carousel.js +4 -1
- package/dist/charts/chart-legend.js +1 -0
- package/dist/charts/chart.d.ts +3 -2
- package/dist/charts/chart.js +12 -4
- package/dist/charts/llms.txt +6 -3
- package/dist/chat/chat.js +39 -9
- package/dist/chat/llms.txt +9 -0
- package/dist/chat-composer/chat-composer.d.ts +5 -2
- package/dist/chat-composer/chat-composer.js +10 -1
- package/dist/chat-dock/chat-dock.js +1 -0
- package/dist/chat-message/chat-message.js +2 -1
- package/dist/chat-typing/chat-typing.js +1 -0
- package/dist/checkbox/checkbox.d.ts +1 -1
- package/dist/checkbox/checkbox.js +9 -2
- package/dist/checkbox/llms.txt +3 -0
- package/dist/chip/chip.js +1 -0
- package/dist/chips-input/chips-input.d.ts +3 -1
- package/dist/chips-input/chips-input.js +14 -5
- package/dist/chips-input/llms.txt +3 -0
- package/dist/clock/clock.d.ts +9 -4
- package/dist/clock/clock.js +35 -5
- package/dist/clock/llms.txt +6 -2
- package/dist/color-picker/color-picker.d.ts +5 -1
- package/dist/color-picker/color-picker.js +36 -17
- package/dist/color-picker/llms.txt +3 -0
- package/dist/confirm/confirm-container.js +1 -0
- package/dist/confirm/confirm-store.js +6 -0
- package/dist/confirm/llms.txt +2 -1
- package/dist/context-menu/context-menu.js +35 -12
- package/dist/context-menu/llms.txt +3 -0
- package/dist/data-table/data-table.d.ts +12 -1
- package/dist/data-table/data-table.js +113 -51
- package/dist/data-table/export-csv.d.ts +2 -2
- package/dist/data-table/export-csv.js +7 -9
- package/dist/data-table/llms.txt +19 -4
- package/dist/data-view/data-view.js +1 -0
- package/dist/date-range/date-range.d.ts +16 -4
- package/dist/date-range/date-range.js +69 -46
- package/dist/date-range/llms.txt +17 -3
- package/dist/datepicker/datepicker.d.ts +17 -3
- package/dist/datepicker/datepicker.js +86 -54
- package/dist/datepicker/llms.txt +17 -3
- package/dist/dialog/dialog.js +29 -8
- package/dist/dialog/llms.txt +3 -0
- package/dist/divider/divider.d.ts +7 -1
- package/dist/divider/divider.js +3 -2
- package/dist/divider/llms.txt +1 -0
- package/dist/drawer/drawer.d.ts +6 -1
- package/dist/drawer/drawer.js +3 -2
- package/dist/drawer/llms.txt +3 -0
- package/dist/fieldset/fieldset.js +4 -1
- package/dist/file-upload/file-upload.d.ts +7 -1
- package/dist/file-upload/file-upload.js +18 -7
- package/dist/file-upload/llms.txt +6 -3
- package/dist/form-field/form-field.js +1 -0
- package/dist/galleria/galleria.js +4 -1
- package/dist/i18n/i18n-context.d.ts +3 -3
- package/dist/i18n/i18n-context.js +25 -3
- package/dist/icon/icon.js +4 -1
- package/dist/image/image.js +4 -4
- package/dist/input/input.js +1 -0
- package/dist/input-mask/input-mask.d.ts +7 -2
- package/dist/input-mask/input-mask.js +15 -41
- package/dist/input-mask/llms.txt +3 -0
- package/dist/input-number/input-number.d.ts +3 -1
- package/dist/input-number/input-number.js +15 -11
- package/dist/input-number/llms.txt +5 -2
- package/dist/input-otp/input-otp.d.ts +16 -3
- package/dist/input-otp/input-otp.js +43 -19
- package/dist/input-otp/llms.txt +11 -0
- 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/overlay.js +37 -7
- package/dist/internal/password-strength.d.ts +6 -0
- package/dist/internal/password-strength.js +74 -0
- 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/step.d.ts +12 -0
- package/dist/internal/step.js +31 -0
- package/dist/internal/tween.js +2 -3
- package/dist/internal/use-controllable-state.d.ts +5 -0
- package/dist/internal/use-controllable-state.js +25 -4
- package/dist/internal/use-modal-focus.d.ts +1 -0
- package/dist/internal/use-modal-focus.js +12 -1
- package/dist/knob/knob.d.ts +5 -2
- package/dist/knob/knob.js +15 -14
- package/dist/knob/llms.txt +4 -2
- package/dist/listbox/listbox.d.ts +3 -1
- package/dist/listbox/listbox.js +30 -10
- package/dist/listbox/llms.txt +3 -0
- package/dist/map/llms.txt +5 -1
- package/dist/map/map-create-dialog.js +30 -22
- package/dist/map/map-hours-field.js +1 -0
- package/dist/map/map-image-field.js +2 -1
- package/dist/map/map-legend.js +1 -0
- package/dist/map/map-poi-card.js +2 -1
- package/dist/map/map-search.js +54 -30
- package/dist/map/map.d.ts +6 -1
- package/dist/map/map.js +62 -34
- package/dist/megamenu/llms.txt +11 -0
- package/dist/megamenu/megamenu.d.ts +7 -1
- package/dist/megamenu/megamenu.js +15 -6
- package/dist/menu/menu-rows.js +1 -0
- package/dist/menu/menu.js +10 -3
- package/dist/menubar/llms.txt +11 -0
- package/dist/menubar/menubar.d.ts +7 -1
- package/dist/menubar/menubar.js +15 -3
- package/dist/meter-group/meter-group.js +1 -0
- package/dist/order-list/llms.txt +3 -0
- package/dist/order-list/order-list.js +21 -6
- package/dist/paginator/paginator.js +7 -4
- package/dist/panel/panel.js +5 -3
- package/dist/password/llms.txt +6 -2
- package/dist/password/password.js +4 -14
- package/dist/peek/llms.txt +1 -1
- package/dist/peek/peek.js +37 -15
- package/dist/pick-list/llms.txt +3 -0
- package/dist/pick-list/pick-list.js +19 -3
- package/dist/popover/llms.txt +3 -0
- package/dist/popover/popover.d.ts +3 -1
- package/dist/popover/popover.js +10 -3
- package/dist/progress/progress.js +1 -0
- package/dist/public-api.d.ts +1 -1
- package/dist/radio-group/llms.txt +3 -0
- package/dist/radio-group/radio-group.d.ts +3 -1
- package/dist/radio-group/radio-group.js +13 -2
- package/dist/rating/rating.js +1 -0
- package/dist/rich-text/llms.txt +14 -0
- package/dist/rich-text/rich-text.d.ts +3 -9
- package/dist/rich-text/rich-text.js +241 -96
- package/dist/rich-text/sanitize.d.ts +9 -0
- package/dist/rich-text/sanitize.js +77 -29
- package/dist/roadmap/llms.txt +9 -3
- package/dist/roadmap/roadmap.js +88 -11
- package/dist/scroll-top/scroll-top.js +1 -0
- package/dist/select/llms.txt +3 -0
- package/dist/select/select.d.ts +3 -1
- package/dist/select/select.js +46 -32
- package/dist/shared/types.d.ts +21 -0
- package/dist/shared/types.js +9 -1
- package/dist/sidenav/sidenav.d.ts +1 -2
- package/dist/sidenav/sidenav.js +4 -3
- package/dist/slider/llms.txt +3 -0
- package/dist/slider/slider.d.ts +3 -1
- package/dist/slider/slider.js +15 -4
- package/dist/speed-dial/speed-dial.js +2 -1
- package/dist/spinner/spinner.js +1 -0
- package/dist/split-button/split-button.js +10 -3
- package/dist/splitter/splitter.js +23 -8
- package/dist/stepper/llms.txt +3 -0
- package/dist/stepper/stepper.js +9 -5
- package/dist/switch/llms.txt +3 -0
- package/dist/switch/switch.d.ts +1 -1
- package/dist/switch/switch.js +9 -2
- package/dist/switch-group/llms.txt +3 -0
- package/dist/switch-group/switch-group.d.ts +3 -1
- package/dist/switch-group/switch-group.js +5 -3
- package/dist/tabs/llms.txt +3 -0
- package/dist/tabs/tabs.js +30 -14
- package/dist/textarea/textarea.js +1 -0
- package/dist/toast/llms.txt +3 -0
- package/dist/toast/toast-container.js +1 -0
- package/dist/toast/toast-store.d.ts +5 -1
- package/dist/toast/toast-store.js +1 -1
- package/dist/tooltip/llms.txt +5 -3
- package/dist/tooltip/tooltip.d.ts +3 -2
- package/dist/tooltip/tooltip.js +90 -31
- package/dist/tree/llms.txt +1 -0
- package/dist/tree/tree.d.ts +6 -1
- package/dist/tree/tree.js +14 -7
- package/package.json +15 -14
package/dist/slider/llms.txt
CHANGED
|
@@ -61,3 +61,6 @@ to the single input or the lower thumb.
|
|
|
61
61
|
## Accessibility
|
|
62
62
|
Native range inputs carry their own role and value semantics. In `range` mode each handle gets an
|
|
63
63
|
`aria-label` telling the two apart, because "slider" twice would say nothing.
|
|
64
|
+
|
|
65
|
+
## Read-only and required
|
|
66
|
+
`readOnly` keeps the thumb focusable but undoes every move (`aria-readonly`). The range thumbs can no longer cross: the clamped value is written back to the native input, so the thumb stops at the other one. `slider` does not accept `aria-required` — the field asterisk and the validator carry it.
|
package/dist/slider/slider.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface KptSliderProps extends Omit<ComponentPropsWithRef<'div'>, 'onCh
|
|
|
22
22
|
/** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
|
|
23
23
|
ariaLabel?: string | null;
|
|
24
24
|
disabled?: boolean;
|
|
25
|
+
/** Tylko do odczytu — uchwyt można skupić, ale nie przesunąć (`aria-readonly`). */
|
|
26
|
+
readOnly?: boolean;
|
|
25
27
|
onTouch?: () => void;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
@@ -34,4 +36,4 @@ export interface KptSliderProps extends Omit<ComponentPropsWithRef<'div'>, 'onCh
|
|
|
34
36
|
* <KptSlider value={volume} onValueChange={setVolume} min={0} max={100} step={5} showValue />
|
|
35
37
|
* <KptSlider range value={range} onValueChange={setRange} showValue />
|
|
36
38
|
*/
|
|
37
|
-
export declare function KptSlider({ value, defaultValue, onValueChange, range, min, max, step, showValue, suffix, invalid, touched, id, ariaLabel, disabled, onTouch, locale, dictionary, className, ...rest }: Readonly<KptSliderProps>): import("react").JSX.Element;
|
|
39
|
+
export declare function KptSlider({ value, defaultValue, onValueChange, range, min, max, step, showValue, suffix, invalid, touched, id, ariaLabel, disabled, readOnly, onTouch, locale, dictionary, className, ...rest }: Readonly<KptSliderProps>): import("react").JSX.Element;
|
package/dist/slider/slider.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
3
|
import { cn } from "../internal/cn.js";
|
|
3
4
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
@@ -13,7 +14,7 @@ import { useKptMessages } from "../i18n/i18n-context.js";
|
|
|
13
14
|
* <KptSlider value={volume} onValueChange={setVolume} min={0} max={100} step={5} showValue />
|
|
14
15
|
* <KptSlider range value={range} onValueChange={setRange} showValue />
|
|
15
16
|
*/
|
|
16
|
-
export function KptSlider({ value, defaultValue, onValueChange, range = false, min = 0, max = 100, step = 1, showValue = false, suffix = '', invalid = false, touched, id, ariaLabel = null, disabled = false, onTouch, locale, dictionary, className, ...rest }) {
|
|
17
|
+
export function KptSlider({ value, defaultValue, onValueChange, range = false, min = 0, max = 100, step = 1, showValue = false, suffix = '', invalid = false, touched, id, ariaLabel = null, disabled = false, readOnly = false, onTouch, locale, dictionary, className, ...rest }) {
|
|
17
18
|
const { t } = useKptMessages({ locale, dictionary });
|
|
18
19
|
const field = useKptFieldA11y(id, 'kpt-slider');
|
|
19
20
|
/** Uchwyt zakresu bez etykiety pola: „Cena, Minimum” z `ariaLabel` albo samo „Minimum”. */
|
|
@@ -37,7 +38,17 @@ export function KptSlider({ value, defaultValue, onValueChange, range = false, m
|
|
|
37
38
|
return span <= 0 ? 0 : ((val - min) / span) * 100;
|
|
38
39
|
};
|
|
39
40
|
// Uchwyty nie mogą się wyminąć — dolny nie przekracza górnego i odwrotnie.
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
41
|
+
// Suwaki są kontrolowane: przy `readOnly` stan się nie zmienia, więc React cofa uchwyt sam.
|
|
42
|
+
const setLow = (next) => {
|
|
43
|
+
if (!readOnly)
|
|
44
|
+
setCurrent([Math.min(next, high), high]);
|
|
45
|
+
};
|
|
46
|
+
const setHigh = (next) => {
|
|
47
|
+
if (!readOnly)
|
|
48
|
+
setCurrent([low, Math.max(next, low)]);
|
|
49
|
+
};
|
|
50
|
+
return (_jsx("div", { className: cn('kpt-slider-host', className), ...rest, children: range ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "kpt-slider__range", children: [_jsx("span", { className: "kpt-slider__sr", id: `${field.id}-min-name`, children: t('slider.min') }), _jsx("span", { className: "kpt-slider__sr", id: `${field.id}-max-name`, children: t('slider.max') }), _jsx("div", { className: "kpt-slider__rail" }), _jsx("div", { className: "kpt-slider__fill", style: { left: `${pct(low)}%`, right: `${100 - pct(high)}%` } }), _jsx("input", { className: "kpt-slider__thumb kpt-slider__thumb--low", type: "range", min: min, max: max, step: step, value: low, "aria-valuetext": suffix ? `${low}${suffix}` : undefined, "aria-invalid": invalid && (touched ?? true) ? true : undefined, id: field.id, disabled: disabled, "aria-label": thumbLabel('min'), "aria-labelledby": thumbLabelledBy('min'), "aria-describedby": field.describedBy, "aria-readonly": readOnly || undefined, onChange: (event) => setLow(Number(event.target.value)), onBlur: () => onTouch?.() }), _jsx("input", { className: "kpt-slider__thumb kpt-slider__thumb--high", type: "range", min: min, max: max, step: step, value: high, "aria-valuetext": suffix ? `${high}${suffix}` : undefined, "aria-invalid": invalid && (touched ?? true) ? true : undefined, disabled: disabled, "aria-label": thumbLabel('max'), "aria-labelledby": thumbLabelledBy('max'), "aria-describedby": field.describedBy, "aria-readonly": readOnly || undefined, onChange: (event) => setHigh(Number(event.target.value)), onBlur: () => onTouch?.() })] }), showValue ? (_jsxs("span", { className: "kpt-slider__value", children: [low, suffix, "\u2013", high, suffix] })) : null] })) : (_jsxs(_Fragment, { children: [_jsx("input", { className: "kpt-slider__input", type: "range", min: min, max: max, step: step, value: single, "aria-valuetext": suffix ? `${single}${suffix}` : undefined, "aria-invalid": invalid && (touched ?? true) ? true : undefined, id: field.id, disabled: disabled, "aria-label": ariaLabel ?? undefined, "aria-describedby": field.describedBy, style: { ['--_pct']: `${pct(single)}%` }, "aria-readonly": readOnly || undefined, onChange: (event) => {
|
|
51
|
+
if (!readOnly)
|
|
52
|
+
setCurrent(Number(event.target.value));
|
|
53
|
+
}, onBlur: () => onTouch?.() }), showValue ? (_jsxs("span", { className: "kpt-slider__value", children: [single, suffix] })) : null] })) }));
|
|
43
54
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useRef, useState } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
@@ -30,5 +31,5 @@ export function KptSpeedDial({ items = [], direction = 'up', icon = 'plus', aria
|
|
|
30
31
|
onSelect?.(item);
|
|
31
32
|
setOpen(false);
|
|
32
33
|
};
|
|
33
|
-
return (_jsxs("div", { ref: hostRef, className: cn('kpt-speed-dial-host', className), onKeyDown: onKeyDown, ...rest, children: [_jsxs("div", { className: cn('kpt-speed-dial', open && 'is-open'), "data-direction": direction, children: [_jsx("div", { className: "kpt-speed-dial__actions", id: actionsId, children: items.map((item, index) => (_jsxs("button", { type: "button", className: "kpt-speed-dial__action", disabled: item.disabled, "aria-label": item.label, onClick: () => pick(item), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, item.label ? _jsx("span", { className: "kpt-speed-dial__label", children: item.label }) : null] }, index))) }), _jsx(KptFab, { "aria-label": open ? t('common.close') : (ariaLabel ?? t('speedDial.actions')), "aria-expanded": open, "aria-controls": actionsId, onClick: () => setOpen(!open), children: _jsx("span", { className: "kpt-speed-dial__trigger-icon", children: _jsx(KptIcon, { name: icon }) }) })] }), open ? _jsx("div", { className: "kpt-speed-dial__backdrop", onClick: () => setOpen(false) }) : null] }));
|
|
34
|
+
return (_jsxs("div", { ref: hostRef, className: cn('kpt-speed-dial-host', className), onKeyDown: onKeyDown, ...rest, children: [_jsxs("div", { className: cn('kpt-speed-dial', open && 'is-open'), "data-direction": direction, children: [_jsx("div", { className: "kpt-speed-dial__actions", id: actionsId, children: items.map((item, index) => (_jsxs("button", { type: "button", className: "kpt-speed-dial__action", disabled: item.disabled, "aria-label": item.label, onClick: () => pick(item), children: [item.icon ? _jsx(KptIcon, { name: item.icon }) : null, item.label ? _jsx("span", { className: "kpt-speed-dial__label", children: item.label }) : null] }, index))) }), _jsx(KptFab, { "aria-label": open ? t('common.close') : (ariaLabel ?? t('speedDial.actions')), "aria-expanded": open, "aria-controls": actionsId, onClick: () => setOpen(!open), children: _jsx("span", { className: "kpt-speed-dial__trigger-icon", children: _jsx(KptIcon, { name: icon }) }) })] }), open ? (_jsx("div", { className: "kpt-speed-dial__backdrop", onClick: () => setOpen(false) })) : null] }));
|
|
34
35
|
}
|
package/dist/spinner/spinner.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
4
5
|
import { KptOverlay } from "../internal/overlay.js";
|
|
5
6
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
@@ -20,6 +21,12 @@ import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
|
|
|
20
21
|
export function KptSplitButton({ variant = 'filled', items = [], disabled = false, onPrimaryClick, onSelect, open, defaultOpen = false, onOpenChange, locale, dictionary, className, children, ...rest }) {
|
|
21
22
|
const { t } = useKptMessages({ locale, dictionary });
|
|
22
23
|
const toggleRef = useRef(null);
|
|
24
|
+
/** Kotwica panelu — w stanie, bo czyta ją render; ref zostaje dla przywracania fokusu. */
|
|
25
|
+
const [toggleEl, setToggleEl] = useState(null);
|
|
26
|
+
const setToggle = useCallback((element) => {
|
|
27
|
+
toggleRef.current = element;
|
|
28
|
+
setToggleEl(element);
|
|
29
|
+
}, []);
|
|
23
30
|
const panelRef = useRef(null);
|
|
24
31
|
/** Którą pozycję skupić po otwarciu — strzałka w górę na przycisku otwiera „od końca”. */
|
|
25
32
|
const focusEdge = useRef('first');
|
|
@@ -67,8 +74,8 @@ export function KptSplitButton({ variant = 'filled', items = [], disabled = fals
|
|
|
67
74
|
onSelect?.(item);
|
|
68
75
|
closeAndRestoreFocus();
|
|
69
76
|
};
|
|
70
|
-
return (_jsxs("span", { className: cn('kpt-split-button-host', className), ...rest, children: [_jsxs("div", { className: "kpt-split-button", "data-variant": variant, children: [_jsx("button", { className: "kpt-split-button__main", type: "button", disabled: disabled, onClick: onPrimaryClick, children: children }), _jsx("button", { ref:
|
|
77
|
+
return (_jsxs("span", { className: cn('kpt-split-button-host', className), ...rest, children: [_jsxs("div", { className: "kpt-split-button", "data-variant": variant, children: [_jsx("button", { className: "kpt-split-button__main", type: "button", disabled: disabled, onClick: onPrimaryClick, children: children }), _jsx("button", { ref: setToggle, className: "kpt-split-button__toggle", type: "button", disabled: disabled, onClick: () => {
|
|
71
78
|
focusEdge.current = 'first';
|
|
72
79
|
setOpen(!isOpen);
|
|
73
|
-
}, onKeyDown: onToggleKeyDown, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, "aria-label": t('splitButton.more'), children: _jsx(KptIcon, { name: "chevron-down" }) })] }), _jsx(KptOverlay, { open: isOpen, anchor:
|
|
80
|
+
}, onKeyDown: onToggleKeyDown, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, "aria-label": t('splitButton.more'), children: _jsx(KptIcon, { name: "chevron-down" }) })] }), _jsx(KptOverlay, { open: isOpen, anchor: toggleEl, onClose: close, align: "end", children: _jsx("div", { ref: panelRef, id: panelId, className: "kpt-split-button__panel", role: "menu", tabIndex: -1, onKeyDown: onPanelKeyDown, children: _jsx(MenuRows, { items: items, block: "kpt-split-button", onPick: pick }) }) })] }));
|
|
74
81
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
+
import { isValidElement, useRef, } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
5
|
+
import { slotChildren, warnUnslottedChild } from "../internal/slot-children.js";
|
|
4
6
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
5
7
|
import { useKptId } from "../internal/use-id.js";
|
|
6
8
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
@@ -40,16 +42,18 @@ export function KptSplitter({ orientation = 'horizontal', startSize, defaultStar
|
|
|
40
42
|
});
|
|
41
43
|
let start = null;
|
|
42
44
|
let end = null;
|
|
43
|
-
|
|
44
|
-
if (!isValidElement(child))
|
|
45
|
-
|
|
45
|
+
for (const child of slotChildren(children)) {
|
|
46
|
+
if (!isValidElement(child)) {
|
|
47
|
+
warnUnslottedChild('KptSplitter', child, '<KptSplitter.Start> / <KptSplitter.End>');
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
46
50
|
const slot = child.type?.kptSplitterSlot;
|
|
47
51
|
const content = child.props.children;
|
|
48
52
|
if (slot === 'start')
|
|
49
53
|
start = content;
|
|
50
54
|
else if (slot === 'end')
|
|
51
55
|
end = content;
|
|
52
|
-
}
|
|
56
|
+
}
|
|
53
57
|
const clamp = (pct) => Math.min(100 - minSize, Math.max(minSize, Math.round(pct)));
|
|
54
58
|
const onPointerDown = (event) => {
|
|
55
59
|
event.preventDefault();
|
|
@@ -58,18 +62,24 @@ export function KptSplitter({ orientation = 'horizontal', startSize, defaultStar
|
|
|
58
62
|
return;
|
|
59
63
|
// Nasłuch na oknie, nie na uchwycie: przy szybkim ruchu kursor wyprzedza wąski pasek
|
|
60
64
|
// i bez tego przeciąganie urywałoby się po kilku pikselach.
|
|
65
|
+
// W RTL panel „start” stoi po prawej (flex idzie za kierunkiem pisma), więc mierzymy od prawej.
|
|
66
|
+
const rtl = getComputedStyle(container).direction === 'rtl';
|
|
61
67
|
const move = (e) => {
|
|
62
68
|
const rect = container.getBoundingClientRect();
|
|
63
69
|
setSize(clamp(orientation === 'horizontal'
|
|
64
|
-
? ((e.clientX - rect.left) / rect.width) * 100
|
|
70
|
+
? ((rtl ? rect.right - e.clientX : e.clientX - rect.left) / rect.width) * 100
|
|
65
71
|
: ((e.clientY - rect.top) / rect.height) * 100));
|
|
66
72
|
};
|
|
73
|
+
// `pointercancel`: dotyk przerwany przez system nie wysyła `pointerup` — bez sprzątania
|
|
74
|
+
// `pointermove` dalej przesuwałby uchwyt.
|
|
67
75
|
const up = () => {
|
|
68
76
|
window.removeEventListener('pointermove', move);
|
|
69
77
|
window.removeEventListener('pointerup', up);
|
|
78
|
+
window.removeEventListener('pointercancel', up);
|
|
70
79
|
};
|
|
71
80
|
window.addEventListener('pointermove', move);
|
|
72
81
|
window.addEventListener('pointerup', up);
|
|
82
|
+
window.addEventListener('pointercancel', up);
|
|
73
83
|
};
|
|
74
84
|
const onKeyDown = (event) => {
|
|
75
85
|
if (event.key === 'Home' || event.key === 'End') {
|
|
@@ -85,9 +95,14 @@ export function KptSplitter({ orientation = 'horizontal', startSize, defaultStar
|
|
|
85
95
|
if (!dir)
|
|
86
96
|
return;
|
|
87
97
|
event.preventDefault();
|
|
88
|
-
|
|
98
|
+
// W RTL ← przesuwa uchwyt w lewo, czyli powiększa prawy panel „start” — odwrotnie niż w LTR.
|
|
99
|
+
const horizontal = event.key === 'ArrowLeft' || event.key === 'ArrowRight';
|
|
100
|
+
const rtl = horizontal && getComputedStyle(event.currentTarget).direction === 'rtl';
|
|
101
|
+
setSize(clamp(size + (rtl ? -dir : dir)));
|
|
89
102
|
};
|
|
90
|
-
return (_jsx("div", { className: cn('kpt-splitter-host', className), ...rest, children: _jsxs("div", { ref: containerRef, className: "kpt-splitter", "data-orientation": orientation, children: [_jsx("div", { className: "kpt-splitter__pane", id: startId, style: { flexBasis: `${size}%` }, children: start }), _jsx("div", { className: "kpt-splitter__gutter", role: "separator",
|
|
103
|
+
return (_jsx("div", { className: cn('kpt-splitter-host', className), ...rest, children: _jsxs("div", { ref: containerRef, className: "kpt-splitter", "data-orientation": orientation, children: [_jsx("div", { className: "kpt-splitter__pane", id: startId, style: { flexBasis: `${size}%` }, children: start }), _jsx("div", { className: "kpt-splitter__gutter", role: "separator",
|
|
104
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- separator okna (APG Window Splitter) to fokusowalny widżet ze strzałkami
|
|
105
|
+
tabIndex: 0, "aria-orientation": orientation === 'horizontal' ? 'vertical' : 'horizontal', "aria-valuenow": size, "aria-valuemin": minSize, "aria-valuemax": 100 - minSize, "aria-controls": startId, "aria-label": ariaLabel || t('splitter.resize'), onPointerDown: onPointerDown, onKeyDown: onKeyDown }), _jsx("div", { className: "kpt-splitter__pane", style: { flexBasis: `${100 - size}%` }, children: end })] }) }));
|
|
91
106
|
}
|
|
92
107
|
KptSplitter.Start = KptSplitterStart;
|
|
93
108
|
KptSplitter.End = KptSplitterEnd;
|
package/dist/stepper/llms.txt
CHANGED
|
@@ -66,3 +66,6 @@ announces how many there are. Each marker is named from the dictionary — `step
|
|
|
66
66
|
number or a check; the visible label is `aria-hidden` so it is not read twice. The active marker
|
|
67
67
|
carries `aria-current="step"`. After `next()` focus stays where it was — move it into the new step
|
|
68
68
|
yourself when the step is long.
|
|
69
|
+
|
|
70
|
+
## Inactive content is destroyed
|
|
71
|
+
Switching renders the new panel from scratch (that is what the enter animation starts from), so local state inside the previous one — an unsent file upload, expanded sections, scroll position — is lost. Keep such state in your own model, outside the panel.
|
package/dist/stepper/stepper.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
+
import { createContext, isValidElement, useContext, useState, } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
5
|
+
import { slotChildren, warnUnslottedChild } from "../internal/slot-children.js";
|
|
4
6
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
5
7
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
6
8
|
import { KptIcon } from "../icon/icon.js";
|
|
@@ -46,11 +48,13 @@ export function KptStepper({ activeIndex, defaultActiveIndex = 0, onActiveIndexC
|
|
|
46
48
|
});
|
|
47
49
|
const [direction, setDirection] = useState(1);
|
|
48
50
|
const steps = [];
|
|
49
|
-
|
|
50
|
-
if (!isValidElement(child) || child.type?.kptStepperSlot !== 'step')
|
|
51
|
-
|
|
51
|
+
for (const child of slotChildren(children)) {
|
|
52
|
+
if (!isValidElement(child) || child.type?.kptStepperSlot !== 'step') {
|
|
53
|
+
warnUnslottedChild('KptStepper', child, '<KptStep>');
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
52
56
|
steps.push(child.props);
|
|
53
|
-
}
|
|
57
|
+
}
|
|
54
58
|
const goTo = (index) => {
|
|
55
59
|
const next = Math.max(0, Math.min(index, steps.length - 1));
|
|
56
60
|
// Kierunek karmi `--kpt-anim-dir`, więc panel wjeżdża z tej strony, z której się cofnąłeś.
|
package/dist/switch/llms.txt
CHANGED
|
@@ -50,3 +50,6 @@ Inside `kpt-form-field` the switch gets both names: the wrapper label and its ow
|
|
|
50
50
|
## Accessibility
|
|
51
51
|
`role="switch"` on a native checkbox — a screen reader announces on/off instead of
|
|
52
52
|
checked/unchecked. The track and the thumb are `aria-hidden`.
|
|
53
|
+
|
|
54
|
+
## Read-only and required
|
|
55
|
+
`readOnly` keeps the switch focusable but blocks toggling (`aria-readonly`); `required` sets `aria-required`.
|
package/dist/switch/switch.d.ts
CHANGED
|
@@ -36,4 +36,4 @@ export interface KptSwitchProps extends Omit<ComponentPropsWithRef<'input'>, 'ty
|
|
|
36
36
|
* <KptSwitch name="notifications" label="Powiadomienia" />
|
|
37
37
|
* <KptSwitch checked={on} onCheckedChange={setOn} onLabel="Włączony" offLabel="Wyłączony" />
|
|
38
38
|
*/
|
|
39
|
-
export declare function KptSwitch({ label, labelPosition, onLabel, offLabel, required, invalid, touched, onCheckedChange, onTouch, hostProps, className, disabled, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, ...rest }: Readonly<KptSwitchProps>): import("react").JSX.Element;
|
|
39
|
+
export declare function KptSwitch({ label, labelPosition, onLabel, offLabel, required, invalid, touched, onCheckedChange, onTouch, hostProps, className, disabled, readOnly, onClick, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, ...rest }: Readonly<KptSwitchProps>): import("react").JSX.Element;
|
package/dist/switch/switch.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useCallback } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
@@ -15,7 +16,7 @@ import { joinIds, useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
|
15
16
|
* <KptSwitch name="notifications" label="Powiadomienia" />
|
|
16
17
|
* <KptSwitch checked={on} onCheckedChange={setOn} onLabel="Włączony" offLabel="Wyłączony" />
|
|
17
18
|
*/
|
|
18
|
-
export function KptSwitch({ label = '', labelPosition = 'end', onLabel = '', offLabel = '', required = false, invalid = false, touched, onCheckedChange, onTouch, hostProps, className, disabled = false, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, ...rest }) {
|
|
19
|
+
export function KptSwitch({ label = '', labelPosition = 'end', onLabel = '', offLabel = '', required = false, invalid = false, touched, onCheckedChange, onTouch, hostProps, className, disabled = false, readOnly = false, onClick, checked, onChange, onBlur, children, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, id, ...rest }) {
|
|
19
20
|
const field = useKptFieldA11y(id, 'kpt-switch');
|
|
20
21
|
const { className: hostClassName, ...hostRest } = hostProps ?? {};
|
|
21
22
|
const showInvalid = invalid && (touched ?? true);
|
|
@@ -28,5 +29,11 @@ export function KptSwitch({ label = '', labelPosition = 'end', onLabel = '', off
|
|
|
28
29
|
onBlur?.(event);
|
|
29
30
|
onTouch?.();
|
|
30
31
|
}, [onBlur, onTouch]);
|
|
31
|
-
return (_jsx("span", { className: cn('kpt-switch-host', hostClassName), ...hostRest, children: _jsxs("label", { className: cn('kpt-switch', disabled && 'kpt-switch--disabled', className), children: [label && labelPosition === 'start' ? (_jsx("span", { className: "kpt-switch__label kpt-switch__label--start", children: label })) : null, _jsx("input", { type: "checkbox", role: "switch", className: "kpt-switch__input", id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), checked: checked, disabled: disabled, "aria-required": required || undefined, "aria-
|
|
32
|
+
return (_jsx("span", { className: cn('kpt-switch-host', hostClassName), ...hostRest, children: _jsxs("label", { className: cn('kpt-switch', disabled && 'kpt-switch--disabled', className), children: [label && labelPosition === 'start' ? (_jsx("span", { className: "kpt-switch__label kpt-switch__label--start", children: label })) : null, _jsx("input", { type: "checkbox", role: "switch", className: "kpt-switch__input", id: field.id, "aria-describedby": joinIds(ariaDescribedBy, field.describedBy), checked: checked, disabled: disabled, "aria-required": required || undefined, "aria-readonly": readOnly || undefined,
|
|
33
|
+
// Natywne `readonly` nie działa na polach wyboru — klik (i Spacja) jest blokowany ręcznie.
|
|
34
|
+
onClick: (event) => {
|
|
35
|
+
if (readOnly)
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
onClick?.(event);
|
|
38
|
+
}, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ...rest }), _jsx("span", { className: "kpt-switch__track", "aria-hidden": "true", children: _jsx("span", { className: "kpt-switch__thumb" }) }), label && labelPosition === 'end' ? _jsx("span", { className: "kpt-switch__label", children: label }) : null, hasStateLabels ? (_jsx("span", { className: cn('kpt-switch__state', checked && 'kpt-switch__state--on'), "aria-hidden": "true", children: checked ? onLabel : offLabel })) : null, children] }) }));
|
|
32
39
|
}
|
|
@@ -52,3 +52,6 @@ Layout only: `--kpt-space-2` (vertical gap) and `--kpt-space-4` (horizontal). Th
|
|
|
52
52
|
## Accessibility
|
|
53
53
|
`role="group"` with `aria-invalid` once the field is touched; every entry keeps the native
|
|
54
54
|
checkbox of `KptSwitch`, so keyboard and screen readers work with no extra handling.
|
|
55
|
+
|
|
56
|
+
## Read-only and required
|
|
57
|
+
`readOnly` is passed to every switch. With `allowDeselect=false` turning the active switch off puts it back on — before, the switch looked off while the group value said it was on.
|
|
@@ -16,6 +16,8 @@ export interface KptSwitchGroupProps<T> extends Omit<ComponentPropsWithRef<'div'
|
|
|
16
16
|
/** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
|
|
17
17
|
ariaLabel?: string | null;
|
|
18
18
|
disabled?: boolean;
|
|
19
|
+
/** Tylko do odczytu — przełączniki widać, nie da się ich zmienić. */
|
|
20
|
+
readOnly?: boolean;
|
|
19
21
|
invalid?: boolean;
|
|
20
22
|
touched?: boolean;
|
|
21
23
|
onTouch?: () => void;
|
|
@@ -30,4 +32,4 @@ export interface KptSwitchGroupProps<T> extends Omit<ComponentPropsWithRef<'div'
|
|
|
30
32
|
* <KptSwitchGroup options={plans} value={plan} onValueChange={setPlan} />
|
|
31
33
|
* <KptSwitchGroup multiple options={tags} value={selected} onValueChange={setSelected} />
|
|
32
34
|
*/
|
|
33
|
-
export declare function KptSwitchGroup<T>({ options, value, defaultValue, onValueChange, multiple, orientation, allowDeselect, id, ariaLabel, disabled, invalid, touched, onTouch, className, ...rest }: Readonly<KptSwitchGroupProps<T>>): import("react").JSX.Element;
|
|
35
|
+
export declare function KptSwitchGroup<T>({ options, value, defaultValue, onValueChange, multiple, orientation, allowDeselect, id, ariaLabel, disabled, readOnly, invalid, touched, onTouch, className, ...rest }: Readonly<KptSwitchGroupProps<T>>): import("react").JSX.Element;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import { cn } from "../internal/cn.js";
|
|
4
|
+
import { optionKey } from "../internal/option-key.js";
|
|
3
5
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
4
6
|
import { KptSwitch } from "../switch/switch.js";
|
|
5
7
|
import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
@@ -13,7 +15,7 @@ import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
|
13
15
|
* <KptSwitchGroup options={plans} value={plan} onValueChange={setPlan} />
|
|
14
16
|
* <KptSwitchGroup multiple options={tags} value={selected} onValueChange={setSelected} />
|
|
15
17
|
*/
|
|
16
|
-
export function KptSwitchGroup({ options = [], value, defaultValue = null, onValueChange, multiple = false, orientation = 'vertical', allowDeselect = true, id, ariaLabel = null, disabled = false, invalid = false, touched, onTouch, className, ...rest }) {
|
|
18
|
+
export function KptSwitchGroup({ options = [], value, defaultValue = null, onValueChange, multiple = false, orientation = 'vertical', allowDeselect = true, id, ariaLabel = null, disabled = false, readOnly = false, invalid = false, touched, onTouch, className, ...rest }) {
|
|
17
19
|
/** Grupa nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
|
|
18
20
|
const field = useKptFieldA11y(id, 'kpt-switch-group');
|
|
19
21
|
const [current, setCurrent] = useControllableState({
|
|
@@ -46,7 +48,7 @@ export function KptSwitchGroup({ options = [], value, defaultValue = null, onVal
|
|
|
46
48
|
// Bez `allowDeselect` nie robimy nic: `checked` jest wyliczane z wartości, a ta się nie
|
|
47
49
|
// zmieniła, więc przełącznik sam wraca do włączonego przy najbliższym renderze.
|
|
48
50
|
};
|
|
49
|
-
return (_jsx("div", { className: cn('kpt-switch-group-host', className), ...rest, children: _jsx("div", { className: cn('kpt-switch-group', orientation === 'horizontal' && 'kpt-switch-group--horizontal'), role: "group", id: field.id, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, children: options.map((option) => (_jsx(KptSwitch, { hostProps: { className: 'kpt-switch-group__item' }, checked: isChecked(option.value), label: option.label, disabled: disabled || option.disabled,
|
|
51
|
+
return (_jsx("div", { className: cn('kpt-switch-group-host', className), ...rest, children: _jsx("div", { className: cn('kpt-switch-group', orientation === 'horizontal' && 'kpt-switch-group--horizontal'), role: "group", id: field.id, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, children: options.map((option, index) => (_jsx(KptSwitch, { hostProps: { className: 'kpt-switch-group__item' }, checked: isChecked(option.value), label: option.label, disabled: disabled || option.disabled, readOnly: readOnly,
|
|
50
52
|
// `aria-invalid` nie działa na `role="group"` — stan błędu niesie każdy przełącznik.
|
|
51
|
-
invalid: showInvalid, onCheckedChange: (checked) => toggle(option, checked), onTouch: onTouch },
|
|
53
|
+
invalid: showInvalid, onCheckedChange: (checked) => toggle(option, checked), onTouch: onTouch }, optionKey(option.value, index)))) }) }));
|
|
52
54
|
}
|
package/dist/tabs/llms.txt
CHANGED
|
@@ -52,3 +52,6 @@ The header is `role="tablist"` with `role="tab"` buttons carrying `aria-selected
|
|
|
52
52
|
`aria-controls`. The tab row is a single `Tab` stop (roving `tabindex`): `ArrowLeft`/`ArrowRight`
|
|
53
53
|
move between tabs, wrapping at the ends, `Home`/`End` jump to the first/last one, and disabled tabs
|
|
54
54
|
are skipped. Moving activates the tab straight away; the next `Tab` goes to the panel.
|
|
55
|
+
|
|
56
|
+
## Inactive content is destroyed
|
|
57
|
+
Switching renders the new panel from scratch (that is what the enter animation starts from), so local state inside the previous one — an unsent file upload, expanded sections, scroll position — is lost. Keep such state in your own model, outside the panel.
|
package/dist/tabs/tabs.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
+
import { isValidElement, useCallback, useLayoutEffect, useRef, useState, } from 'react';
|
|
3
4
|
import { cn } from "../internal/cn.js";
|
|
5
|
+
import { slotChildren, warnUnslottedChild } from "../internal/slot-children.js";
|
|
4
6
|
import { nextRovingIndex, rovingStop } from "../internal/roving.js";
|
|
5
7
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
6
8
|
import { useKptId } from "../internal/use-id.js";
|
|
@@ -42,15 +44,23 @@ export function KptTabs({ activeIndex, defaultActiveIndex = 0, onActiveIndexChan
|
|
|
42
44
|
const baseId = useKptId(undefined, 'kpt-tabs');
|
|
43
45
|
const tabs = [];
|
|
44
46
|
const contents = [];
|
|
45
|
-
|
|
46
|
-
if (!isValidElement(child) || child.type?.kptTabsSlot !== 'tab')
|
|
47
|
-
|
|
47
|
+
for (const child of slotChildren(children)) {
|
|
48
|
+
if (!isValidElement(child) || child.type?.kptTabsSlot !== 'tab') {
|
|
49
|
+
warnUnslottedChild('KptTabs', child, '<KptTab>');
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
48
52
|
const props = child.props;
|
|
49
53
|
tabs.push(props);
|
|
50
54
|
contents.push(props.children);
|
|
51
|
-
}
|
|
55
|
+
}
|
|
56
|
+
const disabled = tabs.map((tab) => !!tab.disabled);
|
|
57
|
+
/**
|
|
58
|
+
* Zakładka pokazywana i jedyna w kolejności Tab: aktywna, a gdy ta jest wyłączona — pierwsza
|
|
59
|
+
* dostępna. Wyłączona zakładka nie może wyglądać na wybraną (ani mieć swojego panelu).
|
|
60
|
+
*/
|
|
61
|
+
const shown = rovingStop(disabled, active);
|
|
52
62
|
const measureInk = useCallback(() => {
|
|
53
|
-
const button = buttonsRef.current[
|
|
63
|
+
const button = buttonsRef.current[shown];
|
|
54
64
|
if (!button)
|
|
55
65
|
return;
|
|
56
66
|
const next = { x: button.offsetLeft, w: button.offsetWidth };
|
|
@@ -58,24 +68,30 @@ export function KptTabs({ activeIndex, defaultActiveIndex = 0, onActiveIndexChan
|
|
|
58
68
|
// się zmierzyć przed montażem). Bez porównania `setInk` wywoływałby kolejny render w kółko —
|
|
59
69
|
// React przerywa aktualizację dopiero wtedy, gdy dostanie ten sam obiekt stanu.
|
|
60
70
|
setInk((prev) => (prev.x === next.x && prev.w === next.w ? prev : next));
|
|
61
|
-
}, [
|
|
71
|
+
}, [shown]);
|
|
62
72
|
useLayoutEffect(measureInk);
|
|
73
|
+
// Szerokość paska zakładek zmienia się też bez zmiany okna (panel boczny, splitter) — mierzymy
|
|
74
|
+
// kontener, a `resize` okna zostaje tylko tam, gdzie nie ma ResizeObservera.
|
|
75
|
+
const headerRef = useRef(null);
|
|
63
76
|
useLayoutEffect(() => {
|
|
77
|
+
const header = headerRef.current;
|
|
78
|
+
if (header && typeof ResizeObserver !== 'undefined') {
|
|
79
|
+
const observer = new ResizeObserver(measureInk);
|
|
80
|
+
observer.observe(header);
|
|
81
|
+
return () => observer.disconnect();
|
|
82
|
+
}
|
|
64
83
|
window.addEventListener('resize', measureInk);
|
|
65
84
|
return () => window.removeEventListener('resize', measureInk);
|
|
66
85
|
}, [measureInk]);
|
|
67
|
-
const disabled = tabs.map((tab) => !!tab.disabled);
|
|
68
|
-
// Jedyna zakładka w kolejności Tab: aktywna, a gdy ta jest wyłączona — pierwsza dostępna.
|
|
69
|
-
const tabStop = rovingStop(disabled, active);
|
|
70
86
|
const select = (index) => {
|
|
71
87
|
if (tabs[index]?.disabled)
|
|
72
88
|
return;
|
|
73
|
-
setDirection(index >=
|
|
89
|
+
setDirection(index >= shown ? 1 : -1);
|
|
74
90
|
setActive(index);
|
|
75
91
|
};
|
|
76
92
|
const onKeyDown = (event) => {
|
|
77
93
|
const current = buttonsRef.current.indexOf(document.activeElement);
|
|
78
|
-
const next = nextRovingIndex(disabled, current < 0 ?
|
|
94
|
+
const next = nextRovingIndex(disabled, current < 0 ? shown : current, event.key);
|
|
79
95
|
if (next === null)
|
|
80
96
|
return;
|
|
81
97
|
event.preventDefault();
|
|
@@ -86,8 +102,8 @@ export function KptTabs({ activeIndex, defaultActiveIndex = 0, onActiveIndexChan
|
|
|
86
102
|
['--kpt-anim-duration']: `${animated ? animationDuration : 0}ms`,
|
|
87
103
|
['--kpt-anim-dir']: direction,
|
|
88
104
|
...style,
|
|
89
|
-
}, ...rest, children: [_jsxs("div", { className: "kpt-tabs__header", role: "tablist", onKeyDown: onKeyDown, children: [tabs.map((tab, index) => (_jsx("button", { ref: (el) => {
|
|
105
|
+
}, ...rest, children: [_jsxs("div", { ref: headerRef, className: "kpt-tabs__header", role: "tablist", onKeyDown: onKeyDown, children: [tabs.map((tab, index) => (_jsx("button", { ref: (el) => {
|
|
90
106
|
buttonsRef.current[index] = el;
|
|
91
|
-
}, type: "button", className: cn('kpt-tabs__tab', index ===
|
|
107
|
+
}, type: "button", className: cn('kpt-tabs__tab', index === shown && 'is-active'), role: "tab", id: `${baseId}-tab-${index}`, disabled: tab.disabled, "aria-selected": index === shown, "aria-controls": index === shown ? `${baseId}-panel` : undefined, tabIndex: index === shown ? 0 : -1, onClick: () => select(index), children: tab.label }, index))), _jsx("span", { className: "kpt-tabs__ink", style: { width: ink.w, transform: `translateX(${ink.x}px)` } })] }), _jsx("div", { className: "kpt-tabs__body", role: "tabpanel", tabIndex: 0, id: `${baseId}-panel`, "aria-labelledby": `${baseId}-tab-${shown}`, children: contents[shown] !== undefined ? (_jsx("div", { className: "kpt-tabs__panel", children: contents[shown] }, shown)) : null })] }));
|
|
92
108
|
}
|
|
93
109
|
KptTabs.Tab = KptTab;
|
package/dist/toast/llms.txt
CHANGED
|
@@ -64,3 +64,6 @@ text twice is announced twice, and a dismissed toast never re-announces an older
|
|
|
64
64
|
are toasts the stack is `role="region"` named `toast.region` (“Notifications”). Pointer or focus on
|
|
65
65
|
the stack pauses every timer (WCAG 2.2.1); the timers resume with the time that was left. The close
|
|
66
66
|
button is labelled from `common.close`.
|
|
67
|
+
|
|
68
|
+
## Toasts with an action
|
|
69
|
+
A toast with `action` does not close by itself (`duration` defaults to 0): a keyboard or screen-reader user cannot reach the "Undo" button at the end of the page within four seconds (WCAG 2.2.1). An explicit `duration` still wins.
|
|
@@ -9,7 +9,11 @@ export interface KptToast {
|
|
|
9
9
|
message: string;
|
|
10
10
|
title?: string;
|
|
11
11
|
variant: KptAlertVariant;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Czas życia w ms; 0 = bez auto-zamykania. Domyślnie 4000 ms, a dla toastu z `action` — 0:
|
|
14
|
+
* użytkownik klawiatury albo czytnika nie zdąży dojść do przycisku „Cofnij” w kontenerze na końcu
|
|
15
|
+
* strony, zanim toast zniknie (WCAG 2.2.1). Jawne `duration` zawsze wygrywa.
|
|
16
|
+
*/
|
|
13
17
|
duration: number;
|
|
14
18
|
action?: KptToastAction;
|
|
15
19
|
}
|
|
@@ -10,7 +10,7 @@ function emit() {
|
|
|
10
10
|
}
|
|
11
11
|
function show(message, options = {}) {
|
|
12
12
|
const id = ++seq;
|
|
13
|
-
const toast = { id, message, variant: 'info', duration: 4000, ...options };
|
|
13
|
+
const toast = { id, message, variant: 'info', duration: options.action ? 0 : 4000, ...options };
|
|
14
14
|
toasts = [...toasts, toast];
|
|
15
15
|
emit();
|
|
16
16
|
if (toast.duration > 0) {
|
package/dist/tooltip/llms.txt
CHANGED
|
@@ -24,9 +24,8 @@ change, with no observers. It measures the host AND its direct children, because
|
|
|
24
24
|
available width instead of stretching its parent, so measuring the host alone would find nothing.
|
|
25
25
|
|
|
26
26
|
## Styling
|
|
27
|
-
The bubble
|
|
28
|
-
|
|
29
|
-
attach a stylesheet rule to reliably.
|
|
27
|
+
The bubble is created outside React's tree, so its look comes from `.kpt-tooltip` in `@konce-pt/styles`
|
|
28
|
+
(see "Styling and the top layer" below), the same rule the Angular directive uses.
|
|
30
29
|
|
|
31
30
|
## Examples
|
|
32
31
|
<KptTooltip text="Save changes" position="bottom"><KptButton>Save</KptButton></KptTooltip>
|
|
@@ -47,3 +46,6 @@ attach a stylesheet rule to reliably.
|
|
|
47
46
|
- `Escape` closes the bubble, and the pointer can move onto it without it disappearing (a 120 ms
|
|
48
47
|
grace period) — WCAG 1.4.13.
|
|
49
48
|
- It does NOT replace an accessible name — an icon-only button still needs its own label.
|
|
49
|
+
|
|
50
|
+
## Styling and the top layer
|
|
51
|
+
The bubble is styled by `.kpt-tooltip` from `@konce-pt/styles`, in the `kpt.components` layer — override it from your own CSS without `!important`; only `position: fixed` and the coordinates stay inline. Inside an open `<dialog>` or popover the bubble is attached to that element, because a modal dialog lives in the top layer and anything outside it is hidden behind it regardless of `z-index`. A hover shows the bubble after 300 ms (sliding across a toolbar does not light every icon); focus shows it at once. Changing the text while the bubble is visible updates it.
|
|
@@ -13,8 +13,9 @@ export interface KptTooltipProps {
|
|
|
13
13
|
children: ReactNode;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Dymek podpowiedzi pokazywany na hover i focus. Lekki — element dodawany do `body`
|
|
17
|
-
* i pozycjonowany
|
|
16
|
+
* Dymek podpowiedzi pokazywany na hover i focus. Lekki — element dodawany do `body` (albo do
|
|
17
|
+
* otwartego `<dialog>`/popovera dziecka, żeby był widoczny w warstwie szczytowej) i pozycjonowany
|
|
18
|
+
* względem dziecka. Wygląd daje klasa `.kpt-tooltip` z `@konce-pt/styles` w warstwie `kpt.components`.
|
|
18
19
|
*
|
|
19
20
|
* Port dyrektywy `[kptTooltip]`: nie renderuje własnego opakowania, tylko dokleja handlery
|
|
20
21
|
* i ref do przekazanego elementu, więc drzewo DOM zostaje takie samo jak bez tooltipa.
|