@konce-pt/react 0.9.1 → 0.11.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/dist/accordion/accordion.js +7 -1
- package/dist/accordion/llms.txt +8 -4
- package/dist/alert/alert.d.ts +10 -4
- package/dist/alert/alert.js +13 -6
- package/dist/alert/llms.txt +8 -6
- package/dist/app-shell/app-shell.js +28 -2
- package/dist/app-shell/llms.txt +3 -0
- package/dist/autocomplete/autocomplete.d.ts +7 -2
- package/dist/autocomplete/autocomplete.js +46 -9
- package/dist/autocomplete/llms.txt +12 -0
- package/dist/avatar/avatar.d.ts +4 -2
- package/dist/avatar/avatar.js +8 -3
- package/dist/avatar/llms.txt +9 -5
- package/dist/avatar-group/avatar-group.d.ts +5 -2
- package/dist/avatar-group/avatar-group.js +10 -2
- package/dist/avatar-group/llms.txt +7 -4
- package/dist/badge/badge.d.ts +8 -1
- package/dist/badge/badge.js +3 -2
- package/dist/badge/llms.txt +11 -5
- package/dist/bottom-sheet/bottom-sheet.d.ts +1 -1
- package/dist/bottom-sheet/bottom-sheet.js +8 -2
- package/dist/bottom-sheet/llms.txt +8 -2
- package/dist/breadcrumb/breadcrumb.js +4 -4
- package/dist/breadcrumb/llms.txt +12 -5
- package/dist/card/card.d.ts +9 -1
- package/dist/card/card.js +2 -2
- package/dist/card/llms.txt +6 -2
- package/dist/carousel/carousel.d.ts +8 -1
- package/dist/carousel/carousel.js +9 -2
- package/dist/carousel/llms.txt +24 -10
- package/dist/checkbox/checkbox.d.ts +6 -1
- package/dist/checkbox/checkbox.js +11 -3
- package/dist/checkbox/llms.txt +11 -0
- package/dist/chip/chip.js +10 -1
- package/dist/chip/llms.txt +7 -4
- package/dist/chips-input/chips-input.d.ts +7 -1
- package/dist/chips-input/chips-input.js +21 -5
- package/dist/chips-input/llms.txt +12 -0
- package/dist/color-picker/color-picker.d.ts +18 -5
- package/dist/color-picker/color-picker.js +48 -14
- package/dist/color-picker/llms.txt +14 -0
- package/dist/confirm/confirm-container.d.ts +5 -1
- package/dist/confirm/confirm-container.js +15 -1
- package/dist/confirm/llms.txt +4 -2
- package/dist/context-menu/context-menu.d.ts +5 -0
- package/dist/context-menu/context-menu.js +48 -4
- package/dist/context-menu/llms.txt +11 -4
- package/dist/date-range/date-range.d.ts +14 -1
- package/dist/date-range/date-range.js +133 -17
- package/dist/date-range/llms.txt +26 -3
- package/dist/datepicker/datepicker.d.ts +10 -1
- package/dist/datepicker/datepicker.js +147 -14
- package/dist/datepicker/llms.txt +27 -3
- package/dist/dialog/dialog.d.ts +4 -0
- package/dist/dialog/dialog.js +7 -1
- package/dist/dialog/llms.txt +2 -0
- package/dist/drawer/drawer.js +7 -2
- package/dist/drawer/llms.txt +10 -5
- package/dist/empty/empty.d.ts +6 -1
- package/dist/empty/empty.js +2 -2
- package/dist/empty/llms.txt +4 -3
- package/dist/fab/llms.txt +2 -1
- package/dist/file-upload/file-upload.d.ts +5 -0
- package/dist/file-upload/file-upload.js +24 -3
- package/dist/file-upload/llms.txt +15 -4
- package/dist/form-field/form-field-context.d.ts +30 -1
- package/dist/form-field/form-field-context.js +27 -0
- package/dist/form-field/form-field.js +16 -2
- package/dist/form-field/llms.txt +10 -1
- package/dist/galleria/galleria.d.ts +6 -1
- package/dist/galleria/galleria.js +40 -1
- package/dist/galleria/llms.txt +17 -8
- package/dist/icon/icon.d.ts +7 -1
- package/dist/icon/icon.js +18 -4
- package/dist/icon/llms.txt +5 -2
- package/dist/image/image.d.ts +5 -0
- package/dist/image/image.js +38 -2
- package/dist/image/llms.txt +24 -17
- package/dist/input/input.d.ts +1 -1
- package/dist/input/input.js +4 -6
- package/dist/input/llms.txt +5 -0
- package/dist/input-mask/input-mask.d.ts +1 -1
- package/dist/input-mask/input-mask.js +8 -6
- package/dist/input-mask/llms.txt +11 -0
- package/dist/input-number/input-number.d.ts +13 -1
- package/dist/input-number/input-number.js +49 -9
- package/dist/input-number/llms.txt +21 -3
- package/dist/input-otp/input-otp.d.ts +7 -2
- package/dist/input-otp/input-otp.js +36 -7
- package/dist/input-otp/llms.txt +14 -0
- package/dist/internal/calendar-focus.d.ts +8 -0
- package/dist/internal/calendar-focus.js +38 -0
- package/dist/internal/option-nav.d.ts +24 -0
- package/dist/internal/option-nav.js +80 -0
- package/dist/internal/overlay.d.ts +7 -2
- package/dist/internal/overlay.js +4 -2
- package/dist/internal/roving.d.ts +9 -0
- package/dist/internal/roving.js +43 -0
- package/dist/internal/tween.d.ts +17 -0
- package/dist/internal/tween.js +40 -0
- package/dist/internal/use-modal-focus.d.ts +10 -0
- package/dist/internal/use-modal-focus.js +57 -0
- package/dist/knob/knob.d.ts +9 -1
- package/dist/knob/knob.js +41 -5
- package/dist/knob/llms.txt +15 -0
- package/dist/listbox/listbox.d.ts +13 -1
- package/dist/listbox/listbox.js +89 -6
- package/dist/listbox/llms.txt +21 -5
- package/dist/megamenu/llms.txt +28 -10
- package/dist/megamenu/megamenu.d.ts +10 -1
- package/dist/megamenu/megamenu.js +116 -5
- package/dist/menu/llms.txt +12 -1
- package/dist/menu/menu-keys.d.ts +15 -0
- package/dist/menu/menu-keys.js +53 -0
- package/dist/menu/menu-rows.js +1 -1
- package/dist/menu/menu.js +52 -4
- package/dist/menubar/llms.txt +24 -7
- package/dist/menubar/menubar.d.ts +8 -1
- package/dist/menubar/menubar.js +92 -6
- package/dist/meter-group/llms.txt +10 -3
- package/dist/meter-group/meter-group.d.ts +9 -2
- package/dist/meter-group/meter-group.js +8 -2
- package/dist/order-list/llms.txt +11 -3
- package/dist/order-list/order-list.d.ts +5 -1
- package/dist/order-list/order-list.js +46 -8
- package/dist/panel/llms.txt +9 -6
- package/dist/panel/panel.js +3 -1
- package/dist/password/llms.txt +8 -0
- package/dist/password/password.d.ts +6 -1
- package/dist/password/password.js +6 -5
- package/dist/pick-list/llms.txt +12 -3
- package/dist/pick-list/pick-list.d.ts +5 -1
- package/dist/pick-list/pick-list.js +52 -5
- package/dist/popover/llms.txt +9 -2
- package/dist/popover/popover.d.ts +9 -3
- package/dist/popover/popover.js +41 -6
- package/dist/public-api.d.ts +6 -6
- package/dist/public-api.js +1 -1
- package/dist/radio-group/llms.txt +11 -0
- package/dist/radio-group/radio-group.d.ts +9 -1
- package/dist/radio-group/radio-group.js +5 -2
- package/dist/rating/llms.txt +18 -5
- package/dist/rating/rating.d.ts +21 -3
- package/dist/rating/rating.js +87 -12
- package/dist/rich-text/llms.txt +20 -0
- package/dist/rich-text/rich-text.d.ts +7 -1
- package/dist/rich-text/rich-text.js +155 -28
- package/dist/scroll-top/llms.txt +5 -1
- package/dist/scroll-top/scroll-top.js +3 -1
- package/dist/select/llms.txt +21 -7
- package/dist/select/select.d.ts +12 -1
- package/dist/select/select.js +110 -38
- package/dist/sidenav/llms.txt +6 -0
- package/dist/skeleton/llms.txt +3 -2
- package/dist/skeleton/skeleton.d.ts +1 -1
- package/dist/skeleton/skeleton.js +2 -2
- package/dist/slider/llms.txt +14 -1
- package/dist/slider/slider.d.ts +11 -2
- package/dist/slider/slider.js +15 -2
- package/dist/speed-dial/llms.txt +6 -2
- package/dist/speed-dial/speed-dial.d.ts +1 -1
- package/dist/speed-dial/speed-dial.js +14 -3
- package/dist/spinner/llms.txt +12 -8
- package/dist/spinner/spinner.d.ts +5 -1
- package/dist/spinner/spinner.js +12 -2
- package/dist/split-button/llms.txt +11 -3
- package/dist/split-button/split-button.d.ts +3 -1
- package/dist/split-button/split-button.js +43 -3
- package/dist/splitter/llms.txt +14 -4
- package/dist/splitter/splitter.d.ts +9 -2
- package/dist/splitter/splitter.js +15 -2
- package/dist/stepper/llms.txt +8 -4
- package/dist/stepper/stepper.d.ts +3 -2
- package/dist/stepper/stepper.js +7 -2
- package/dist/switch/llms.txt +10 -0
- package/dist/switch/switch.d.ts +1 -1
- package/dist/switch/switch.js +4 -2
- package/dist/switch-group/llms.txt +11 -0
- package/dist/switch-group/switch-group.d.ts +5 -1
- package/dist/switch-group/switch-group.js +7 -2
- package/dist/tabs/llms.txt +10 -4
- package/dist/tabs/tabs.d.ts +4 -0
- package/dist/tabs/tabs.js +21 -2
- package/dist/textarea/llms.txt +10 -0
- package/dist/textarea/textarea.d.ts +3 -1
- package/dist/textarea/textarea.js +13 -8
- package/dist/toast/llms.txt +21 -7
- package/dist/toast/toast-container.d.ts +6 -1
- package/dist/toast/toast-container.js +52 -1
- package/dist/toast/toast-store.d.ts +12 -0
- package/dist/toast/toast-store.js +46 -7
- package/dist/tooltip/llms.txt +10 -3
- package/dist/tooltip/tooltip.d.ts +5 -0
- package/dist/tooltip/tooltip.js +80 -7
- package/dist/tree/llms.txt +20 -8
- package/dist/tree/tree-keys.d.ts +27 -0
- package/dist/tree/tree-keys.js +39 -0
- package/dist/tree/tree.d.ts +12 -5
- package/dist/tree/tree.js +75 -29
- package/package.json +12 -12
package/dist/public-api.js
CHANGED
|
@@ -71,7 +71,7 @@ export { KptOverlay } from "./internal/overlay.js";
|
|
|
71
71
|
export { KptButtonGroup } from "./button-group/button-group.js";
|
|
72
72
|
export { KptSelect } from "./select/select.js";
|
|
73
73
|
export { KptFormField } from "./form-field/form-field.js";
|
|
74
|
-
export { useKptFormFieldContext, useKptFormFieldFilled } from "./form-field/form-field-context.js";
|
|
74
|
+
export { useKptFieldA11y, useKptFormFieldContext, useKptFormFieldFilled } from "./form-field/form-field-context.js";
|
|
75
75
|
export { KptCheckbox } from "./checkbox/checkbox.js";
|
|
76
76
|
export { KptAutocomplete } from "./autocomplete/autocomplete.js";
|
|
77
77
|
export { KptListbox } from "./listbox/listbox.js";
|
|
@@ -31,6 +31,17 @@ interfere.
|
|
|
31
31
|
<KptRadioGroup options={plans} value={plan} onValueChange={setPlan} />
|
|
32
32
|
<KptRadioGroup name="plan" options={plans} defaultValue="pro" />
|
|
33
33
|
|
|
34
|
+
## Screen reader and keyboard
|
|
35
|
+
`orientation`: 'vertical' (default) | 'horizontal' — options in a column or in a wrapping row; also
|
|
36
|
+
sets `aria-orientation`.
|
|
37
|
+
|
|
38
|
+
## Label and description
|
|
39
|
+
`id` goes to the focusable element, not the host; without one it comes from `KptFormField` or is
|
|
40
|
+
generated. A `div` with a role is not named by `label[for]`, so inside `KptFormField` it gets
|
|
41
|
+
`aria-labelledby` pointing at the wrapper's label (unless `ariaLabel` is set), and the hint or error
|
|
42
|
+
is added to `aria-describedby`. New: `id`, `ariaLabel` and `required` (→ `aria-required`) on the
|
|
43
|
+
`radiogroup`.
|
|
44
|
+
|
|
34
45
|
## Tokens
|
|
35
46
|
`--kpt-color-primary` (the checked dot), `--kpt-form-field-border`,
|
|
36
47
|
`--kpt-form-field-border-error`.
|
|
@@ -7,6 +7,14 @@ export interface KptRadioGroupProps<T> extends Omit<ComponentPropsWithRef<'div'>
|
|
|
7
7
|
onValueChange?: (value: T) => void;
|
|
8
8
|
/** Nazwa grupy w formularzu; pominięta = generowana. */
|
|
9
9
|
name?: string;
|
|
10
|
+
/** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
|
|
11
|
+
id?: string;
|
|
12
|
+
/** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
|
|
13
|
+
ariaLabel?: string | null;
|
|
14
|
+
/** Oznacza grupę jako wymaganą atrybutem `aria-required`. */
|
|
15
|
+
required?: boolean;
|
|
16
|
+
/** Układ opcji: pod sobą (domyślnie) albo w rzędzie, z zawijaniem. */
|
|
17
|
+
orientation?: 'vertical' | 'horizontal';
|
|
10
18
|
disabled?: boolean;
|
|
11
19
|
invalid?: boolean;
|
|
12
20
|
touched?: boolean;
|
|
@@ -21,4 +29,4 @@ export interface KptRadioGroupProps<T> extends Omit<ComponentPropsWithRef<'div'>
|
|
|
21
29
|
* @example
|
|
22
30
|
* <KptRadioGroup options={plans} value={plan} onValueChange={setPlan} />
|
|
23
31
|
*/
|
|
24
|
-
export declare function KptRadioGroup<T>({ options, value, defaultValue, onValueChange, name, disabled, invalid, touched, onTouch, className, ...rest }: Readonly<KptRadioGroupProps<T>>): import("react").JSX.Element;
|
|
32
|
+
export declare function KptRadioGroup<T>({ options, value, defaultValue, onValueChange, name, id, ariaLabel, required, orientation, disabled, invalid, touched, onTouch, className, ...rest }: Readonly<KptRadioGroupProps<T>>): import("react").JSX.Element;
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../internal/cn.js";
|
|
3
3
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
4
4
|
import { useKptId } from "../internal/use-id.js";
|
|
5
|
+
import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
5
6
|
/**
|
|
6
7
|
* Grupa przycisków opcji (radio). Opcje przez `options`.
|
|
7
8
|
*
|
|
@@ -11,7 +12,9 @@ import { useKptId } from "../internal/use-id.js";
|
|
|
11
12
|
* @example
|
|
12
13
|
* <KptRadioGroup options={plans} value={plan} onValueChange={setPlan} />
|
|
13
14
|
*/
|
|
14
|
-
export function KptRadioGroup({ options = [], value, defaultValue, onValueChange, name, disabled = false, invalid = false, touched, onTouch, className, ...rest }) {
|
|
15
|
+
export function KptRadioGroup({ options = [], value, defaultValue, onValueChange, name, id, ariaLabel = null, required = false, orientation = 'vertical', disabled = false, invalid = false, touched, onTouch, className, ...rest }) {
|
|
16
|
+
/** Grupa nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
|
|
17
|
+
const field = useKptFieldA11y(id, 'kpt-radio-group');
|
|
15
18
|
const groupName = useKptId(name, 'kpt-radio');
|
|
16
19
|
const [current, setCurrent] = useControllableState({
|
|
17
20
|
value,
|
|
@@ -19,5 +22,5 @@ export function KptRadioGroup({ options = [], value, defaultValue, onValueChange
|
|
|
19
22
|
onChange: onValueChange,
|
|
20
23
|
});
|
|
21
24
|
const showInvalid = invalid && (touched ?? true);
|
|
22
|
-
return (_jsx("div", { className: cn('kpt-radio-group-host', className), ...rest, children: _jsx("div", { className:
|
|
25
|
+
return (_jsx("div", { className: cn('kpt-radio-group-host', className), ...rest, children: _jsx("div", { className: cn('kpt-radio-group', orientation === 'horizontal' && 'kpt-radio-group--horizontal'), role: "radiogroup", "aria-orientation": orientation, "aria-invalid": showInvalid || undefined, id: field.id, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, "aria-required": required || undefined, children: options.map((option) => (_jsxs("label", { className: cn('kpt-radio', (disabled || option.disabled) && 'kpt-radio--disabled'), children: [_jsx("input", { type: "radio", className: "kpt-radio__input", name: groupName, checked: option.value === current, disabled: disabled || option.disabled, onChange: () => setCurrent(option.value), onBlur: () => onTouch?.() }), _jsx("span", { className: "kpt-radio__dot", "aria-hidden": "true" }), _jsx("span", { className: "kpt-radio__label", children: option.label })] }, String(option.value)))) }) }));
|
|
23
26
|
}
|
package/dist/rating/llms.txt
CHANGED
|
@@ -5,8 +5,8 @@ Import: `import { KptRating } from '@konce-pt/react';`
|
|
|
5
5
|
|
|
6
6
|
## DOM
|
|
7
7
|
<div class="kpt-rating-host">
|
|
8
|
-
<div class="kpt-rating" role="
|
|
9
|
-
<button class="kpt-rating__star is-filled" aria-label="1 of 5">…</button>
|
|
8
|
+
<div class="kpt-rating" role="radiogroup" aria-label="…">
|
|
9
|
+
<button class="kpt-rating__star is-filled" role="radio" aria-checked="false" tabindex="-1" aria-label="1 of 5">…</button>
|
|
10
10
|
…count buttons…
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
@@ -14,9 +14,11 @@ Import: `import { KptRating } from '@konce-pt/react';`
|
|
|
14
14
|
## Props
|
|
15
15
|
- `value` / `defaultValue` / `onValueChange` — the score as a number, `0` means unrated
|
|
16
16
|
- `count`: number (default 5)
|
|
17
|
+
- `allowHalf`: boolean — half stars, the value goes in steps of 0.5
|
|
17
18
|
- `readOnly`: boolean — display only, no clicking and no hover preview
|
|
18
19
|
- `disabled`: boolean
|
|
19
|
-
- `onTouch()` —
|
|
20
|
+
- `onTouch()` — when focus leaves the group
|
|
21
|
+
- `id`, `ariaLabel`, `required`, `invalid`, `touched`
|
|
20
22
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
21
23
|
|
|
22
24
|
## Clicking a lit star clears the score
|
|
@@ -35,9 +37,20 @@ per instance with the `locale` / `dictionary` props.
|
|
|
35
37
|
<KptRating value={score} onValueChange={setScore} count={5} />
|
|
36
38
|
<KptRating value={4} readOnly />
|
|
37
39
|
|
|
40
|
+
## Half stars
|
|
41
|
+
`allowHalf` splits every star into two halves, each its own `role="radio"` ("3.5 of 5" — the number
|
|
42
|
+
follows the page language, PL "3,5 z 5"), so the group keeps the radio pattern: clicking the left half
|
|
43
|
+
gives x.5, and the arrows step by 0.5. Read-only stars show the value rounded to a half (4.3 → four
|
|
44
|
+
and a half stars) while the name carries the exact score ("4.3 of 5"), so an average can be shown
|
|
45
|
+
as it is.
|
|
46
|
+
|
|
38
47
|
## Tokens
|
|
39
48
|
Lit stars `--kpt-color-warning`, empty ones `--kpt-color-border-strong`.
|
|
40
49
|
|
|
41
50
|
## Accessibility
|
|
42
|
-
`role="
|
|
43
|
-
|
|
51
|
+
`role="radiogroup"` named by `ariaLabel` or the `KptFormField` label; each star is
|
|
52
|
+
`role="radio"` with `aria-checked`, labelled from `rating.star` (`{value}`, `{max}`) — EN `1 of 5`,
|
|
53
|
+
PL `1 z 5`. One Tab stop: `→`/`↑` raise the score by one, `←`/`↓` lower it (mirrored in RTL),
|
|
54
|
+
`Home`/`End` set the extremes, `Delete`/`Backspace` clear it; clicking the chosen star also clears it.
|
|
55
|
+
`readOnly` renders `role="img"` named "4 of 5" with no buttons, so a screen reader does not announce
|
|
56
|
+
a row of disabled controls. `touch` fires when focus leaves the group.
|
package/dist/rating/rating.d.ts
CHANGED
|
@@ -6,17 +6,35 @@ export interface KptRatingProps extends Omit<ComponentPropsWithRef<'div'>, 'onCh
|
|
|
6
6
|
onValueChange?: (value: number) => void;
|
|
7
7
|
/** Liczba gwiazdek. */
|
|
8
8
|
count?: number;
|
|
9
|
+
/** Połówki gwiazdek: wartość co 0,5, każda połówka to osobne `radio`. */
|
|
10
|
+
allowHalf?: boolean;
|
|
9
11
|
/** Ocena tylko do odczytu — bez klikania i bez podglądu pod kursorem. */
|
|
10
12
|
readOnly?: boolean;
|
|
13
|
+
/** Id grupy (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Nazwa dostępna grupy, gdy nie opisuje jej etykieta (`KptFormField`). */
|
|
16
|
+
ariaLabel?: string | null;
|
|
17
|
+
/** Oznacza ocenę jako wymaganą atrybutem `aria-required`. */
|
|
18
|
+
required?: boolean;
|
|
11
19
|
disabled?: boolean;
|
|
20
|
+
invalid?: boolean;
|
|
21
|
+
touched?: boolean;
|
|
12
22
|
onTouch?: () => void;
|
|
13
23
|
}
|
|
14
24
|
/**
|
|
15
25
|
* Ocena gwiazdkami. Kliknięcie zapalonej gwiazdki zeruje ocenę, więc wystawioną można cofnąć
|
|
16
26
|
* bez osobnego przycisku „wyczyść".
|
|
17
27
|
*
|
|
28
|
+
* Do edycji to grupa radiowa (`role="radiogroup"`, gwiazdki jako `role="radio"`): jeden przystanek
|
|
29
|
+
* Tab, strzałki zmieniają ocenę o krok (w RTL odwrócone w poziomie), `Home`/`End` ustawiają
|
|
30
|
+
* skrajne, `Delete`/`Backspace` zeruje. Z `allowHalf` każda gwiazdka ma dwie połówki — dwa osobne
|
|
31
|
+
* `radio` („3,5 z 5”), a krok strzałek to 0,5. Tylko do odczytu (`readOnly`) to obrazek z nazwą
|
|
32
|
+
* „4,3 z 5” — bez przycisków, które czytnik ogłaszałby jako wyłączone; gwiazdki pokazują wartość
|
|
33
|
+
* zaokrągloną do połówki.
|
|
34
|
+
*
|
|
18
35
|
* @example
|
|
19
|
-
* <KptRating value={score} onValueChange={setScore} count={5} />
|
|
20
|
-
* <KptRating value={
|
|
36
|
+
* <KptRating value={score} onValueChange={setScore} count={5} ariaLabel="Ocena" />
|
|
37
|
+
* <KptRating value={score} onValueChange={setScore} allowHalf ariaLabel="Ocena" />
|
|
38
|
+
* <KptRating value={4.3} readOnly />
|
|
21
39
|
*/
|
|
22
|
-
export declare function KptRating({ value, defaultValue, onValueChange, count, readOnly, disabled, onTouch, locale, dictionary, className, ...rest }: Readonly<KptRatingProps>): import("react").JSX.Element;
|
|
40
|
+
export declare function KptRating({ value, defaultValue, onValueChange, count, allowHalf, readOnly, id, ariaLabel, required, disabled, invalid, touched, onTouch, locale, dictionary, className, ...rest }: Readonly<KptRatingProps>): import("react").JSX.Element;
|
package/dist/rating/rating.js
CHANGED
|
@@ -1,30 +1,105 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { cn } from "../internal/cn.js";
|
|
4
4
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
5
5
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
6
|
+
import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
6
7
|
import { KptIcon } from "../icon/icon.js";
|
|
8
|
+
const fillOf = (star, shown) => shown >= star ? 'full' : shown >= star - 0.5 ? 'half' : 'empty';
|
|
7
9
|
/**
|
|
8
10
|
* Ocena gwiazdkami. Kliknięcie zapalonej gwiazdki zeruje ocenę, więc wystawioną można cofnąć
|
|
9
11
|
* bez osobnego przycisku „wyczyść".
|
|
10
12
|
*
|
|
13
|
+
* Do edycji to grupa radiowa (`role="radiogroup"`, gwiazdki jako `role="radio"`): jeden przystanek
|
|
14
|
+
* Tab, strzałki zmieniają ocenę o krok (w RTL odwrócone w poziomie), `Home`/`End` ustawiają
|
|
15
|
+
* skrajne, `Delete`/`Backspace` zeruje. Z `allowHalf` każda gwiazdka ma dwie połówki — dwa osobne
|
|
16
|
+
* `radio` („3,5 z 5”), a krok strzałek to 0,5. Tylko do odczytu (`readOnly`) to obrazek z nazwą
|
|
17
|
+
* „4,3 z 5” — bez przycisków, które czytnik ogłaszałby jako wyłączone; gwiazdki pokazują wartość
|
|
18
|
+
* zaokrągloną do połówki.
|
|
19
|
+
*
|
|
11
20
|
* @example
|
|
12
|
-
* <KptRating value={score} onValueChange={setScore} count={5} />
|
|
13
|
-
* <KptRating value={
|
|
21
|
+
* <KptRating value={score} onValueChange={setScore} count={5} ariaLabel="Ocena" />
|
|
22
|
+
* <KptRating value={score} onValueChange={setScore} allowHalf ariaLabel="Ocena" />
|
|
23
|
+
* <KptRating value={4.3} readOnly />
|
|
14
24
|
*/
|
|
15
|
-
export function KptRating({ value, defaultValue = 0, onValueChange, count = 5, readOnly = false, disabled = false, onTouch, locale, dictionary, className, ...rest }) {
|
|
16
|
-
const { t } = useKptMessages({ locale, dictionary });
|
|
25
|
+
export function KptRating({ value, defaultValue = 0, onValueChange, count = 5, allowHalf = false, readOnly = false, id, ariaLabel = null, required = false, disabled = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
|
|
26
|
+
const { t, locale: activeLocale } = useKptMessages({ locale, dictionary });
|
|
27
|
+
const field = useKptFieldA11y(id, 'kpt-rating');
|
|
17
28
|
const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
|
|
18
29
|
const [hover, setHover] = useState(0);
|
|
19
|
-
const
|
|
30
|
+
const groupRef = useRef(null);
|
|
31
|
+
/** Prośba o fokus na przystanek Tab po najbliższym renderze (zmiana oceny klawiszem). */
|
|
32
|
+
const wantFocus = useRef(false);
|
|
33
|
+
const showInvalid = invalid && (touched ?? true);
|
|
34
|
+
const stars = Array.from({ length: count }, (_, index) => index + 1);
|
|
35
|
+
const step = allowHalf ? 0.5 : 1;
|
|
20
36
|
// Podgląd pod kursorem wygrywa z oceną, ale tylko dopóki kursor jest nad gwiazdkami —
|
|
21
37
|
// po `mouseleave` wraca 0 i zapalona zostaje sama wartość.
|
|
22
38
|
const shown = hover || current;
|
|
23
|
-
|
|
24
|
-
|
|
39
|
+
/** Przystanek Tab: wybrana wartość, a bez oceny — pierwsza możliwa. */
|
|
40
|
+
const tabStop = current >= step && current <= count ? current : step;
|
|
41
|
+
/** Liczba w zapisie języka strony („3,5” po polsku). */
|
|
42
|
+
const numberFormat = new Intl.NumberFormat(activeLocale, { maximumFractionDigits: 2 });
|
|
43
|
+
const starLabel = (score) => t('rating.star', { value: numberFormat.format(score), max: count });
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!wantFocus.current)
|
|
46
|
+
return;
|
|
47
|
+
wantFocus.current = false;
|
|
48
|
+
groupRef.current?.querySelector(`[data-value="${tabStop}"]`)?.focus();
|
|
49
|
+
});
|
|
50
|
+
const starVisual = (star, fill, children, hidden = false) => (_jsxs("span", { className: "kpt-rating__star", "data-fill": fill, "aria-hidden": hidden || undefined, children: [_jsx(KptIcon, { name: "star" }), _jsx("span", { className: "kpt-rating__fill", "aria-hidden": "true", children: _jsx(KptIcon, { name: "star" }) }), children] }, star));
|
|
51
|
+
if (readOnly) {
|
|
52
|
+
const score = starLabel(current);
|
|
53
|
+
// Gwiazdki pokazują wartość zaokrągloną do połówki (4,3 → 4,5), nazwa — dokładną.
|
|
54
|
+
const display = Math.round(current * 2) / 2;
|
|
55
|
+
return (_jsx("div", { className: cn('kpt-rating-host', className), ...rest, children: _jsx("div", { className: "kpt-rating kpt-rating--readonly", role: "img", id: field.id, "aria-label": ariaLabel ? `${ariaLabel}: ${score}` : score, "aria-describedby": field.describedBy, children: stars.map((star) => starVisual(star, fillOf(star, display), null, true)) }) }));
|
|
56
|
+
}
|
|
57
|
+
const pick = (score) => {
|
|
58
|
+
if (disabled)
|
|
59
|
+
return;
|
|
60
|
+
setCurrent(current === score ? 0 : score);
|
|
61
|
+
};
|
|
62
|
+
const onKeyDown = (event) => {
|
|
63
|
+
if (disabled)
|
|
64
|
+
return;
|
|
65
|
+
const rtl = getComputedStyle(event.currentTarget).direction === 'rtl';
|
|
66
|
+
const forward = rtl ? 'ArrowLeft' : 'ArrowRight';
|
|
67
|
+
const back = rtl ? 'ArrowRight' : 'ArrowLeft';
|
|
68
|
+
let next = null;
|
|
69
|
+
if (event.key === forward || event.key === 'ArrowUp')
|
|
70
|
+
next = Math.min(count, Math.max(step, current + step));
|
|
71
|
+
else if (event.key === back || event.key === 'ArrowDown')
|
|
72
|
+
next = Math.max(step, current - step);
|
|
73
|
+
else if (event.key === 'Home')
|
|
74
|
+
next = step;
|
|
75
|
+
else if (event.key === 'End')
|
|
76
|
+
next = count;
|
|
77
|
+
else if (event.key === 'Delete' || event.key === 'Backspace')
|
|
78
|
+
next = 0;
|
|
79
|
+
else if (event.key === ' ' || event.key === 'Enter') {
|
|
80
|
+
// Spacja na gwiazdce wybiera ją (jak radio); ponowna nie zeruje — od tego jest Delete.
|
|
81
|
+
const score = Number(event.target.dataset['value']);
|
|
82
|
+
if (score)
|
|
83
|
+
next = score;
|
|
84
|
+
}
|
|
85
|
+
if (next === null)
|
|
25
86
|
return;
|
|
26
|
-
|
|
27
|
-
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
setCurrent(next);
|
|
89
|
+
wantFocus.current = true;
|
|
90
|
+
};
|
|
91
|
+
/** „Dotknięcie” dopiero przy wyjściu fokusu z całej grupy, nie przy przejściu między gwiazdkami. */
|
|
92
|
+
const onBlur = (event) => {
|
|
93
|
+
const next = event.relatedTarget;
|
|
94
|
+
if (!next || !event.currentTarget.contains(next))
|
|
95
|
+
onTouch?.();
|
|
28
96
|
};
|
|
29
|
-
|
|
97
|
+
/** Pola wyboru jednej gwiazdki: całość albo — z `allowHalf` — dwie połówki. */
|
|
98
|
+
const optionsOf = (star) => allowHalf
|
|
99
|
+
? [
|
|
100
|
+
{ score: star - 0.5, part: 'start' },
|
|
101
|
+
{ score: star, part: 'end' },
|
|
102
|
+
]
|
|
103
|
+
: [{ score: star, part: 'full' }];
|
|
104
|
+
return (_jsx("div", { className: cn('kpt-rating-host', className), ...rest, children: _jsx("div", { ref: groupRef, className: cn('kpt-rating', disabled && 'kpt-rating--disabled'), role: "radiogroup", id: field.id, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, "aria-required": required || undefined, "aria-invalid": showInvalid || undefined, "aria-disabled": disabled || undefined, onKeyDown: onKeyDown, onBlur: onBlur, onMouseLeave: () => setHover(0), children: stars.map((star) => starVisual(star, fillOf(star, shown), optionsOf(star).map((option) => (_jsx("button", { type: "button", role: "radio", className: cn('kpt-rating__hit', `kpt-rating__hit--${option.part}`), "aria-checked": option.score === current, tabIndex: !disabled && option.score === tabStop ? 0 : -1, "aria-disabled": disabled || undefined, "data-value": option.score, "aria-label": starLabel(option.score), onClick: () => pick(option.score), onMouseEnter: () => !disabled && setHover(option.score) }, option.part))))) }) }));
|
|
30
105
|
}
|
package/dist/rich-text/llms.txt
CHANGED
|
@@ -45,6 +45,11 @@ only when the operation actually changed something — otherwise Tab stays nativ
|
|
|
45
45
|
never becomes a keyboard trap (WCAG 2.1.2). In a table cell Tab moves to the next cell; a list
|
|
46
46
|
inside the cell takes precedence.
|
|
47
47
|
|
|
48
|
+
## The toolbar is one Tab stop
|
|
49
|
+
The toolbar is a named `role="toolbar"` ("Formatting", `richText.toolbar`) with a roving tabindex:
|
|
50
|
+
`←`/`→` (mirrored in RTL) and `Home`/`End` move between tools, skipping disabled ones; the stop
|
|
51
|
+
remembers the last tool, so Tab from the toolbar goes straight to the editor.
|
|
52
|
+
|
|
48
53
|
## Tables
|
|
49
54
|
Insert from an 8×8 grid popover. Dragging across cells makes a rectangular selection that grows
|
|
50
55
|
until it fully covers merged cells on its edges. Right-click opens the menu: insert and delete rows
|
|
@@ -69,3 +74,18 @@ Every label comes from the `richText` namespace, including `richText.menu.*` and
|
|
|
69
74
|
Formatting goes through `document.execCommand`. The API is formally deprecated, but it is the only
|
|
70
75
|
route into the browser's native undo stack (Ctrl+Z); replacing it would mean writing our own
|
|
71
76
|
history, that is, a different editor.
|
|
77
|
+
|
|
78
|
+
## Screen reader and keyboard
|
|
79
|
+
`link` opens a small dialog instead of the browser's `prompt()`: a labelled URL field (prefilled
|
|
80
|
+
with the current link), `Enter` inserts, `Escape` returns to the text with the selection restored.
|
|
81
|
+
The table context menu is a `role="menu"` of `menuitem`s: it also opens from the keyboard (the menu
|
|
82
|
+
key or `Shift+F10` in a cell), the arrows and `Home`/`End` move, `Escape`/`Tab` close it, and focus
|
|
83
|
+
goes back to the cell. Colour swatches are named ("Dark grey", `richText.swatches.*`) instead of
|
|
84
|
+
their hex codes. The table size grid is still mouse-only.
|
|
85
|
+
|
|
86
|
+
## Label and description
|
|
87
|
+
`id` goes to the focusable element, not the host; without one it comes from `KptFormField` or is
|
|
88
|
+
generated. A `div` with a role is not named by `label[for]`, so inside `KptFormField` it gets
|
|
89
|
+
`aria-labelledby` pointing at the wrapper's label (unless `ariaLabel` is set), and the hint or error
|
|
90
|
+
is added to `aria-describedby`. New: `id`, `ariaLabel` and `required` (→ `aria-required`) on the
|
|
91
|
+
`role="textbox"` area.
|
|
@@ -13,6 +13,12 @@ export interface KptRichTextProps extends Omit<ComponentPropsWithRef<'div'>, 'on
|
|
|
13
13
|
placeholder?: string;
|
|
14
14
|
/** Maksymalna głębokość zagnieżdżenia list (Tab, „Dodaj wcięcie"). */
|
|
15
15
|
maxListLevel?: number;
|
|
16
|
+
/** Id elementu fokusowalnego (nie hosta); bez niego generowane, w `KptFormField` — z wrappera. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** Nazwa dostępna, gdy kontrolki nie opisuje etykieta (`<label for>` albo `KptFormField`). */
|
|
19
|
+
ariaLabel?: string | null;
|
|
20
|
+
/** Oznacza pole jako wymagane atrybutem `aria-required`. */
|
|
21
|
+
required?: boolean;
|
|
16
22
|
disabled?: boolean;
|
|
17
23
|
invalid?: boolean;
|
|
18
24
|
touched?: boolean;
|
|
@@ -35,4 +41,4 @@ export interface KptRichTextProps extends Omit<ComponentPropsWithRef<'div'>, 'on
|
|
|
35
41
|
* <KptRichText value={html} onValueChange={setHtml} />
|
|
36
42
|
* <KptRichText value={html} onValueChange={setHtml} toolbar={[['bold', 'italic'], ['link']]} />
|
|
37
43
|
*/
|
|
38
|
-
export declare function KptRichText({ value, defaultValue, onValueChange, toolbar, placeholder, maxListLevel, disabled, invalid, touched, onTouch, mentions, mentionLimit, onMention, locale, dictionary, className, ...rest }: Readonly<KptRichTextProps>): import("react").JSX.Element;
|
|
44
|
+
export declare function KptRichText({ value, defaultValue, onValueChange, toolbar, placeholder, maxListLevel, id, ariaLabel, required, disabled, invalid, touched, onTouch, mentions, mentionLimit, onMention, locale, dictionary, className, ...rest }: Readonly<KptRichTextProps>): import("react").JSX.Element;
|