@primitiv-ui/core 0.1.58 → 0.1.60
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/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { getKeyToActionMap, type RovingKeyAction } from "./keyboard/getKeyToActi
|
|
|
3
3
|
export { resolveRovingTarget, type ResolveRovingTargetOptions, } from "./keyboard/resolveRovingTarget.js";
|
|
4
4
|
export { tabsClick, tabsKeydown, tabsTabStop, type TabsActivationMode, type TabsKeyOutcome, type TabsOrientation, type TabsReadingDirection, type TabsState, } from "./tabs/policy.js";
|
|
5
5
|
export { accordionKeydown, accordionToggle, type AccordionKeyOutcome, type AccordionOrientation, type AccordionReadingDirection, type AccordionState, } from "./accordion/policy.js";
|
|
6
|
+
export { toggleGroupKeydown, toggleGroupTabStop, toggleGroupToggle, type ToggleGroupKeyOutcome, type ToggleGroupOrientation, type ToggleGroupReadingDirection, type ToggleGroupState, } from "./toggle-group/policy.js";
|
|
7
|
+
export { segmentedControlKeydown, segmentedControlSelect, segmentedControlTabStop, type SegmentedControlKeyOutcome, type SegmentedControlOrientation, type SegmentedControlReadingDirection, type SegmentedControlState, } from "./segmented-control/policy.js";
|
|
6
8
|
export { collapsibleKeydown, collapsibleToggle, type CollapsibleKeyOutcome, type CollapsibleState, } from "./collapsible/policy.js";
|
|
7
9
|
export { FOCUSABLE_SELECTOR } from "./focus/focusable.js";
|
|
8
10
|
export { MENU_ITEM_SELECTOR, MENU_TYPEAHEAD_RESET_MS, menuKeydown, menuTypeahead, type MenuKeyOutcome, type MenuKeyState, type MenuTypeaheadOutcome, type MenuTypeaheadState, } from "./menu/policy.js";
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ export { getKeyToActionMap } from "./keyboard/getKeyToActionMap.js";
|
|
|
3
3
|
export { resolveRovingTarget, } from "./keyboard/resolveRovingTarget.js";
|
|
4
4
|
export { tabsClick, tabsKeydown, tabsTabStop, } from "./tabs/policy.js";
|
|
5
5
|
export { accordionKeydown, accordionToggle, } from "./accordion/policy.js";
|
|
6
|
+
export { toggleGroupKeydown, toggleGroupTabStop, toggleGroupToggle, } from "./toggle-group/policy.js";
|
|
7
|
+
export { segmentedControlKeydown, segmentedControlSelect, segmentedControlTabStop, } from "./segmented-control/policy.js";
|
|
6
8
|
export { collapsibleKeydown, collapsibleToggle, } from "./collapsible/policy.js";
|
|
7
9
|
export { FOCUSABLE_SELECTOR } from "./focus/focusable.js";
|
|
8
10
|
export { MENU_ITEM_SELECTOR, MENU_TYPEAHEAD_RESET_MS, menuKeydown, menuTypeahead, } from "./menu/policy.js";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Layout axis of the control: which arrow pair moves between segments. */
|
|
2
|
+
export type SegmentedControlOrientation = "horizontal" | "vertical";
|
|
3
|
+
/** Reading direction. Under `"rtl"` the horizontal arrows are mirrored. */
|
|
4
|
+
export type SegmentedControlReadingDirection = "ltr" | "rtl";
|
|
5
|
+
/**
|
|
6
|
+
* Everything SegmentedControl's selection and keyboard rules depend on, as
|
|
7
|
+
* plain data. Each surface builds it from wherever it keeps state — React
|
|
8
|
+
* state, or a custom element's attributes — and applies the outcome back the
|
|
9
|
+
* same way. A whole-control disable is every value in `disabled`.
|
|
10
|
+
*/
|
|
11
|
+
export type SegmentedControlState = {
|
|
12
|
+
/** Every segment's value, in DOM order, disabled ones included. */
|
|
13
|
+
values: readonly string[];
|
|
14
|
+
/** The values of the disabled segments. */
|
|
15
|
+
disabled: ReadonlySet<string>;
|
|
16
|
+
/** The selected segment's value, or `undefined` while none is selected. */
|
|
17
|
+
selected: string | undefined;
|
|
18
|
+
orientation: SegmentedControlOrientation;
|
|
19
|
+
dir: SegmentedControlReadingDirection;
|
|
20
|
+
};
|
|
21
|
+
/** What a key press on a segment asks for: a segment to focus, and the segment
|
|
22
|
+
* to select — `null` when it is already selected, so no change is reported. */
|
|
23
|
+
export type SegmentedControlKeyOutcome = {
|
|
24
|
+
focus: string;
|
|
25
|
+
select: string | null;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The segment a click on `value` selects: `null` when it is disabled or
|
|
29
|
+
* already selected. A selected segment never lets go, so — unlike a toggle
|
|
30
|
+
* group — the selection cannot be cleared to nothing.
|
|
31
|
+
*/
|
|
32
|
+
export declare function segmentedControlSelect(state: Pick<SegmentedControlState, "disabled" | "selected">, value: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* SegmentedControl's keyboard contract — the WAI-ARIA radio group's — for a key
|
|
35
|
+
* press on the segment `focused`: the arrows follow `orientation`, mirrored
|
|
36
|
+
* under RTL, wrap at the ends and skip disabled segments, and each one moves
|
|
37
|
+
* focus **and** selection. While focus sits on a disabled segment they do
|
|
38
|
+
* nothing. There is no Home / End, and Enter / Space are the native button's
|
|
39
|
+
* click.
|
|
40
|
+
*
|
|
41
|
+
* Returns `null` for a key the control does not handle, which tells the caller
|
|
42
|
+
* to leave the event alone (no `preventDefault`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function segmentedControlKeydown(state: SegmentedControlState, focused: string, key: string): SegmentedControlKeyOutcome | null;
|
|
45
|
+
/**
|
|
46
|
+
* The segment that takes part in the page's Tab order (the roving tab stop):
|
|
47
|
+
* the selected segment, else the first enabled one so the control is still
|
|
48
|
+
* reachable by keyboard — or none, while nothing is selected and every segment
|
|
49
|
+
* is disabled.
|
|
50
|
+
*/
|
|
51
|
+
export declare function segmentedControlTabStop(state: Pick<SegmentedControlState, "values" | "disabled" | "selected">): string | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getKeyToActionMap } from "../keyboard/getKeyToActionMap.js";
|
|
2
|
+
import { resolveRovingTarget } from "../keyboard/resolveRovingTarget.js";
|
|
3
|
+
/**
|
|
4
|
+
* The segment a click on `value` selects: `null` when it is disabled or
|
|
5
|
+
* already selected. A selected segment never lets go, so — unlike a toggle
|
|
6
|
+
* group — the selection cannot be cleared to nothing.
|
|
7
|
+
*/
|
|
8
|
+
export function segmentedControlSelect(state, value) {
|
|
9
|
+
return state.disabled.has(value) || state.selected === value ? null : value;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* SegmentedControl's keyboard contract — the WAI-ARIA radio group's — for a key
|
|
13
|
+
* press on the segment `focused`: the arrows follow `orientation`, mirrored
|
|
14
|
+
* under RTL, wrap at the ends and skip disabled segments, and each one moves
|
|
15
|
+
* focus **and** selection. While focus sits on a disabled segment they do
|
|
16
|
+
* nothing. There is no Home / End, and Enter / Space are the native button's
|
|
17
|
+
* click.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` for a key the control does not handle, which tells the caller
|
|
20
|
+
* to leave the event alone (no `preventDefault`).
|
|
21
|
+
*/
|
|
22
|
+
export function segmentedControlKeydown(state, focused, key) {
|
|
23
|
+
const action = getKeyToActionMap({ orientation: state.orientation, dir: state.dir })[key];
|
|
24
|
+
const navigable = state.values.filter((value) => !state.disabled.has(value));
|
|
25
|
+
const result = resolveRovingTarget({ action, navigable, currentKey: focused });
|
|
26
|
+
return result && { focus: result.target, select: segmentedControlSelect(state, result.target) };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The segment that takes part in the page's Tab order (the roving tab stop):
|
|
30
|
+
* the selected segment, else the first enabled one so the control is still
|
|
31
|
+
* reachable by keyboard — or none, while nothing is selected and every segment
|
|
32
|
+
* is disabled.
|
|
33
|
+
*/
|
|
34
|
+
export function segmentedControlTabStop(state) {
|
|
35
|
+
return state.selected ?? state.values.find((value) => !state.disabled.has(value));
|
|
36
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Layout axis of the group: which arrow pair moves between items. */
|
|
2
|
+
export type ToggleGroupOrientation = "horizontal" | "vertical";
|
|
3
|
+
/** Reading direction. Under `"rtl"` the horizontal arrows are mirrored. */
|
|
4
|
+
export type ToggleGroupReadingDirection = "ltr" | "rtl";
|
|
5
|
+
/**
|
|
6
|
+
* Everything ToggleGroup's toggle and keyboard rules depend on, as plain data.
|
|
7
|
+
* Each surface builds it from wherever it keeps state — React state, or a
|
|
8
|
+
* custom element's attributes — and applies the outcome back the same way.
|
|
9
|
+
*/
|
|
10
|
+
export type ToggleGroupState = {
|
|
11
|
+
/** Every item's value, in DOM order, disabled ones included. */
|
|
12
|
+
values: readonly string[];
|
|
13
|
+
/** The values of the disabled items. */
|
|
14
|
+
disabled: ReadonlySet<string>;
|
|
15
|
+
/** The values of the pressed items. */
|
|
16
|
+
pressed: readonly string[];
|
|
17
|
+
/** Whether more than one item may be pressed at once (`type="multiple"`). */
|
|
18
|
+
multiple: boolean;
|
|
19
|
+
orientation: ToggleGroupOrientation;
|
|
20
|
+
dir: ToggleGroupReadingDirection;
|
|
21
|
+
};
|
|
22
|
+
/** What a key press on an item asks for: an item to move focus to, or an item
|
|
23
|
+
* to toggle — never both. */
|
|
24
|
+
export type ToggleGroupKeyOutcome = {
|
|
25
|
+
focus: string | null;
|
|
26
|
+
toggle: string | null;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The pressed items after toggling `value`: a pressed item lets go — in single
|
|
30
|
+
* mode that leaves nothing pressed; one that is off is pressed and, unless
|
|
31
|
+
* `multiple`, replaces the pressed one. `null` for a disabled item, which never
|
|
32
|
+
* toggles, so no change is reported. The same rule as an accordion's open items.
|
|
33
|
+
*/
|
|
34
|
+
export declare function toggleGroupToggle(state: Pick<ToggleGroupState, "disabled" | "pressed" | "multiple">, value: string): string[] | null;
|
|
35
|
+
/**
|
|
36
|
+
* ToggleGroup's keyboard contract for a key press on the item `focused`: arrows
|
|
37
|
+
* follow `orientation`, mirrored under RTL, wrap at the ends and skip disabled
|
|
38
|
+
* items; Home / End jump to the ends. They move focus only — Enter / Space
|
|
39
|
+
* toggle the focused item. Returns `null` for a key the group does not handle,
|
|
40
|
+
* which tells the caller to leave the event alone (no `preventDefault`).
|
|
41
|
+
*/
|
|
42
|
+
export declare function toggleGroupKeydown(state: ToggleGroupState, focused: string, key: string): ToggleGroupKeyOutcome | null;
|
|
43
|
+
/**
|
|
44
|
+
* The item that takes part in the page's Tab order (the roving tab stop): the
|
|
45
|
+
* item focus last moved to, else the first pressed item, else the first item —
|
|
46
|
+
* always an enabled one that is still there, so Tab reaches the group.
|
|
47
|
+
*/
|
|
48
|
+
export declare function toggleGroupTabStop(state: Pick<ToggleGroupState, "values" | "disabled" | "pressed"> & {
|
|
49
|
+
focused: string | undefined;
|
|
50
|
+
}): string | undefined;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { accordionKeydown, accordionToggle } from "../accordion/policy.js";
|
|
2
|
+
/**
|
|
3
|
+
* The pressed items after toggling `value`: a pressed item lets go — in single
|
|
4
|
+
* mode that leaves nothing pressed; one that is off is pressed and, unless
|
|
5
|
+
* `multiple`, replaces the pressed one. `null` for a disabled item, which never
|
|
6
|
+
* toggles, so no change is reported. The same rule as an accordion's open items.
|
|
7
|
+
*/
|
|
8
|
+
export function toggleGroupToggle(state, value) {
|
|
9
|
+
return accordionToggle({ disabled: state.disabled, expanded: state.pressed, multiple: state.multiple }, value);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* ToggleGroup's keyboard contract for a key press on the item `focused`: arrows
|
|
13
|
+
* follow `orientation`, mirrored under RTL, wrap at the ends and skip disabled
|
|
14
|
+
* items; Home / End jump to the ends. They move focus only — Enter / Space
|
|
15
|
+
* toggle the focused item. Returns `null` for a key the group does not handle,
|
|
16
|
+
* which tells the caller to leave the event alone (no `preventDefault`).
|
|
17
|
+
*/
|
|
18
|
+
export function toggleGroupKeydown(state, focused, key) {
|
|
19
|
+
return accordionKeydown({ ...state, expanded: state.pressed }, focused, key);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The item that takes part in the page's Tab order (the roving tab stop): the
|
|
23
|
+
* item focus last moved to, else the first pressed item, else the first item —
|
|
24
|
+
* always an enabled one that is still there, so Tab reaches the group.
|
|
25
|
+
*/
|
|
26
|
+
export function toggleGroupTabStop(state) {
|
|
27
|
+
const enabled = state.values.filter((value) => !state.disabled.has(value));
|
|
28
|
+
// `undefined` is never an enabled value, so a missing focus or first item drops out.
|
|
29
|
+
return [state.focused, ...state.pressed, enabled[0]].find((value) => enabled.includes(value));
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitiv-ui/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.60",
|
|
4
4
|
"description": "The framework-free behaviour core shared by every Primitiv surface — keyboard maps, roving-focus targets, id derivation and per-component policy, as pure functions with no DOM and no dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|