@cssints/apg-specs 0.0.0-stage → 0.5.1
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/LICENSE +21 -0
- package/README.md +65 -2
- package/dist/apg/accordion.bridge.d.mts +35 -0
- package/dist/apg/accordion.bridge.mjs +326 -0
- package/dist/apg/accordion.model.json +8397 -0
- package/dist/apg/alert.bridge.d.mts +22 -0
- package/dist/apg/alert.bridge.mjs +86 -0
- package/dist/apg/alert.model.json +871 -0
- package/dist/apg/alertdialog.bridge.d.mts +21 -0
- package/dist/apg/alertdialog.bridge.mjs +221 -0
- package/dist/apg/alertdialog.model.json +5232 -0
- package/dist/apg/breadcrumb.bridge.d.mts +26 -0
- package/dist/apg/breadcrumb.bridge.mjs +120 -0
- package/dist/apg/breadcrumb.model.json +574 -0
- package/dist/apg/button.bridge.d.mts +35 -0
- package/dist/apg/button.bridge.mjs +208 -0
- package/dist/apg/button.model.json +5814 -0
- package/dist/apg/carousel.bridge.d.mts +44 -0
- package/dist/apg/carousel.bridge.mjs +262 -0
- package/dist/apg/carousel.model.json +8963 -0
- package/dist/apg/checkbox-group.bridge.d.mts +25 -0
- package/dist/apg/checkbox-group.bridge.mjs +276 -0
- package/dist/apg/checkbox-group.model.json +3863 -0
- package/dist/apg/checkbox.bridge.d.mts +34 -0
- package/dist/apg/checkbox.bridge.mjs +253 -0
- package/dist/apg/checkbox.model.json +3158 -0
- package/dist/apg/combobox-autocomplete.bridge.d.mts +14 -0
- package/dist/apg/combobox-autocomplete.bridge.mjs +326 -0
- package/dist/apg/combobox-autocomplete.model.json +11586 -0
- package/dist/apg/combobox-dialog.bridge.d.mts +17 -0
- package/dist/apg/combobox-dialog.bridge.mjs +250 -0
- package/dist/apg/combobox-dialog.model.json +8981 -0
- package/dist/apg/combobox-grid.bridge.d.mts +17 -0
- package/dist/apg/combobox-grid.bridge.mjs +227 -0
- package/dist/apg/combobox-grid.model.json +8554 -0
- package/dist/apg/combobox-select-only.bridge.d.mts +24 -0
- package/dist/apg/combobox-select-only.bridge.mjs +304 -0
- package/dist/apg/combobox-select-only.model.json +7846 -0
- package/dist/apg/combobox-tree.bridge.d.mts +17 -0
- package/dist/apg/combobox-tree.bridge.mjs +211 -0
- package/dist/apg/combobox-tree.model.json +9345 -0
- package/dist/apg/dialog-modal.bridge.d.mts +35 -0
- package/dist/apg/dialog-modal.bridge.mjs +186 -0
- package/dist/apg/dialog-modal.model.json +7580 -0
- package/dist/apg/disclosure.bridge.d.mts +25 -0
- package/dist/apg/disclosure.bridge.mjs +202 -0
- package/dist/apg/disclosure.model.json +4703 -0
- package/dist/apg/feed.bridge.d.mts +31 -0
- package/dist/apg/feed.bridge.mjs +246 -0
- package/dist/apg/feed.model.json +4523 -0
- package/dist/apg/grid-selection.bridge.d.mts +13 -0
- package/dist/apg/grid-selection.bridge.mjs +160 -0
- package/dist/apg/grid-selection.model.json +6974 -0
- package/dist/apg/grid-sort.bridge.d.mts +12 -0
- package/dist/apg/grid-sort.bridge.mjs +138 -0
- package/dist/apg/grid-sort.model.json +3799 -0
- package/dist/apg/grid.bridge.d.mts +54 -0
- package/dist/apg/grid.bridge.mjs +441 -0
- package/dist/apg/grid.model.json +3802 -0
- package/dist/apg/link.bridge.d.mts +24 -0
- package/dist/apg/link.bridge.mjs +126 -0
- package/dist/apg/link.model.json +694 -0
- package/dist/apg/listbox-multi.bridge.d.mts +10 -0
- package/dist/apg/listbox-multi.bridge.mjs +261 -0
- package/dist/apg/listbox-multi.model.json +10893 -0
- package/dist/apg/listbox-rearrangeable.bridge.d.mts +20 -0
- package/dist/apg/listbox-rearrangeable.bridge.mjs +237 -0
- package/dist/apg/listbox-rearrangeable.model.json +17592 -0
- package/dist/apg/listbox-shared.d.mts +58 -0
- package/dist/apg/listbox-shared.mjs +171 -0
- package/dist/apg/listbox-single.bridge.d.mts +10 -0
- package/dist/apg/listbox-single.bridge.mjs +196 -0
- package/dist/apg/listbox-single.model.json +8024 -0
- package/dist/apg/listbox-typeahead.bridge.d.mts +10 -0
- package/dist/apg/listbox-typeahead.bridge.mjs +153 -0
- package/dist/apg/listbox-typeahead.model.json +5615 -0
- package/dist/apg/menu-button.bridge.d.mts +29 -0
- package/dist/apg/menu-button.bridge.mjs +259 -0
- package/dist/apg/menu-button.model.json +5706 -0
- package/dist/apg/menu-checkable.bridge.d.mts +25 -0
- package/dist/apg/menu-checkable.bridge.mjs +226 -0
- package/dist/apg/menu-checkable.model.json +4277 -0
- package/dist/apg/menu-menubar.bridge.d.mts +27 -0
- package/dist/apg/menu-menubar.bridge.mjs +273 -0
- package/dist/apg/menu-menubar.model.json +9540 -0
- package/dist/apg/meter.bridge.d.mts +28 -0
- package/dist/apg/meter.bridge.mjs +159 -0
- package/dist/apg/meter.model.json +1185 -0
- package/dist/apg/player.bridge.d.mts +24 -0
- package/dist/apg/player.bridge.mjs +342 -0
- package/dist/apg/player.model.json +11013 -0
- package/dist/apg/radio.bridge.d.mts +35 -0
- package/dist/apg/radio.bridge.mjs +371 -0
- package/dist/apg/radio.model.json +5011 -0
- package/dist/apg/slider-multithumb.bridge.d.mts +34 -0
- package/dist/apg/slider-multithumb.bridge.mjs +365 -0
- package/dist/apg/slider-multithumb.model.json +5774 -0
- package/dist/apg/slider.bridge.d.mts +54 -0
- package/dist/apg/slider.bridge.mjs +359 -0
- package/dist/apg/slider.model.json +4881 -0
- package/dist/apg/spinbutton.bridge.d.mts +41 -0
- package/dist/apg/spinbutton.bridge.mjs +327 -0
- package/dist/apg/spinbutton.model.json +7571 -0
- package/dist/apg/switch.bridge.d.mts +30 -0
- package/dist/apg/switch.bridge.mjs +243 -0
- package/dist/apg/switch.model.json +3159 -0
- package/dist/apg/tabs.bridge.d.mts +41 -0
- package/dist/apg/tabs.bridge.mjs +294 -0
- package/dist/apg/tabs.model.json +7659 -0
- package/dist/apg/timeline.bridge.d.mts +36 -0
- package/dist/apg/timeline.bridge.mjs +265 -0
- package/dist/apg/timeline.model.json +6189 -0
- package/dist/apg/toolbar.bridge.d.mts +25 -0
- package/dist/apg/toolbar.bridge.mjs +307 -0
- package/dist/apg/toolbar.model.json +6616 -0
- package/dist/apg/tooltip.bridge.d.mts +36 -0
- package/dist/apg/tooltip.bridge.mjs +208 -0
- package/dist/apg/tooltip.model.json +8295 -0
- package/dist/apg/treegrid.bridge.d.mts +28 -0
- package/dist/apg/treegrid.bridge.mjs +311 -0
- package/dist/apg/treegrid.model.json +17358 -0
- package/dist/apg/treeview.bridge.d.mts +26 -0
- package/dist/apg/treeview.bridge.mjs +396 -0
- package/dist/apg/treeview.model.json +13745 -0
- package/dist/apg/windowsplitter.bridge.d.mts +36 -0
- package/dist/apg/windowsplitter.bridge.mjs +242 -0
- package/dist/apg/windowsplitter.model.json +6253 -0
- package/dist/canvas/camera.model.json +6568 -0
- package/dist/canvas/canvas.bridge.d.mts +190 -0
- package/dist/canvas/canvas.bridge.mjs +729 -0
- package/dist/canvas/pointer.model.json +17095 -0
- package/dist/scenario.d.mts +233 -0
- package/dist/scenario.mjs +313 -0
- package/package.json +57 -4
- package/scenarios/apg/README.md +221 -0
- package/scenarios/apg/accordion.base-ui.json +1005 -0
- package/scenarios/apg/accordion.react-aria.json +929 -0
- package/scenarios/apg/alert.base-ui.json +81 -0
- package/scenarios/apg/alert.react-aria.json +98 -0
- package/scenarios/apg/alertdialog.base-ui.json +331 -0
- package/scenarios/apg/alertdialog.react-aria.json +225 -0
- package/scenarios/apg/breadcrumb.react-aria.json +312 -0
- package/scenarios/apg/button.ariakit.json +136 -0
- package/scenarios/apg/button.base-ui.json +747 -0
- package/scenarios/apg/button.react-aria.json +443 -0
- package/scenarios/apg/carousel.apg.json +909 -0
- package/scenarios/apg/checkbox.ariakit.json +299 -0
- package/scenarios/apg/checkbox.base-ui.json +1126 -0
- package/scenarios/apg/checkbox.react-aria.json +518 -0
- package/scenarios/apg/combobox.ariakit.json +945 -0
- package/scenarios/apg/combobox.base-ui.json +2444 -0
- package/scenarios/apg/combobox.react-aria.json +845 -0
- package/scenarios/apg/dialog-modal.ariakit.json +1102 -0
- package/scenarios/apg/dialog-modal.base-ui.json +775 -0
- package/scenarios/apg/dialog-modal.react-aria.json +638 -0
- package/scenarios/apg/disclosure.apg.json +349 -0
- package/scenarios/apg/disclosure.ariakit.json +163 -0
- package/scenarios/apg/disclosure.base-ui.json +451 -0
- package/scenarios/apg/disclosure.react-aria.json +643 -0
- package/scenarios/apg/feed.apg.json +442 -0
- package/scenarios/apg/grid.ariakit.json +197 -0
- package/scenarios/apg/grid.base-ui.json +720 -0
- package/scenarios/apg/grid.react-aria.json +969 -0
- package/scenarios/apg/landmarks.ariakit.json +93 -0
- package/scenarios/apg/landmarks.react-aria.json +330 -0
- package/scenarios/apg/link.ariakit.json +83 -0
- package/scenarios/apg/link.base-ui.json +88 -0
- package/scenarios/apg/link.react-aria.json +186 -0
- package/scenarios/apg/listbox.ariakit.json +78 -0
- package/scenarios/apg/listbox.base-ui.json +163 -0
- package/scenarios/apg/listbox.react-aria.json +1118 -0
- package/scenarios/apg/menu-button.ariakit.json +924 -0
- package/scenarios/apg/menu-button.base-ui.json +1155 -0
- package/scenarios/apg/menu-button.react-aria.json +1080 -0
- package/scenarios/apg/menubar.ariakit.json +758 -0
- package/scenarios/apg/menubar.base-ui.json +673 -0
- package/scenarios/apg/meter.base-ui.json +243 -0
- package/scenarios/apg/meter.react-aria.json +201 -0
- package/scenarios/apg/radio.ariakit.json +459 -0
- package/scenarios/apg/radio.base-ui.json +581 -0
- package/scenarios/apg/radio.react-aria.json +576 -0
- package/scenarios/apg/slider-multithumb.base-ui.json +316 -0
- package/scenarios/apg/slider-multithumb.react-aria.json +363 -0
- package/scenarios/apg/slider.base-ui.json +544 -0
- package/scenarios/apg/slider.react-aria.json +456 -0
- package/scenarios/apg/spinbutton.base-ui.json +1688 -0
- package/scenarios/apg/spinbutton.react-aria.json +426 -0
- package/scenarios/apg/switch.base-ui.json +456 -0
- package/scenarios/apg/switch.react-aria.json +303 -0
- package/scenarios/apg/table.ariakit.json +65 -0
- package/scenarios/apg/table.react-aria.json +221 -0
- package/scenarios/apg/tabs.ariakit.json +329 -0
- package/scenarios/apg/tabs.base-ui.json +875 -0
- package/scenarios/apg/tabs.react-aria.json +644 -0
- package/scenarios/apg/toolbar.ariakit.json +595 -0
- package/scenarios/apg/toolbar.base-ui.json +1189 -0
- package/scenarios/apg/toolbar.react-aria.json +383 -0
- package/scenarios/apg/tooltip.ariakit.json +441 -0
- package/scenarios/apg/tooltip.base-ui.json +411 -0
- package/scenarios/apg/tooltip.react-aria.json +454 -0
- package/scenarios/apg/treegrid.apg.json +2558 -0
- package/scenarios/apg/treegrid.react-aria.json +5094 -0
- package/scenarios/apg/treeview.apg.json +928 -0
- package/scenarios/apg/windowsplitter.apg.json +557 -0
- package/scenarios/canvas/README.md +69 -0
- package/scenarios/canvas/camera.contract.json +237 -0
- package/scenarios/canvas/camera.excalidraw.json +57 -0
- package/scenarios/canvas/marquee.excalidraw.json +122 -0
- package/scenarios/canvas/pan.excalidraw.json +46 -0
- package/scenarios/canvas/pointer.contract.json +528 -0
- package/scenarios/parts.json +291 -0
- package/shared/aria.qnt +186 -0
- package/shared/details-group.qnt +50 -0
- package/shared/focusgroup.qnt +152 -0
- package/shared/invokers.qnt +81 -0
- package/shared/popover.qnt +71 -0
- package/specs/apg/STATIC.md +103 -0
- package/specs/apg/accordion.qnt +578 -0
- package/specs/apg/alert.qnt +131 -0
- package/specs/apg/alertdialog.qnt +455 -0
- package/specs/apg/breadcrumb.qnt +88 -0
- package/specs/apg/button.qnt +445 -0
- package/specs/apg/carousel.qnt +732 -0
- package/specs/apg/checkbox-group.qnt +388 -0
- package/specs/apg/checkbox.qnt +394 -0
- package/specs/apg/combobox-autocomplete.qnt +764 -0
- package/specs/apg/combobox-dialog.qnt +627 -0
- package/specs/apg/combobox-grid.qnt +632 -0
- package/specs/apg/combobox-select-only.qnt +626 -0
- package/specs/apg/combobox-tree.qnt +633 -0
- package/specs/apg/dialog-modal.qnt +499 -0
- package/specs/apg/disclosure.qnt +309 -0
- package/specs/apg/feed.qnt +485 -0
- package/specs/apg/grid-selection.qnt +512 -0
- package/specs/apg/grid-sort.qnt +330 -0
- package/specs/apg/grid.qnt +360 -0
- package/specs/apg/link.qnt +119 -0
- package/specs/apg/listbox-multi.qnt +799 -0
- package/specs/apg/listbox-rearrangeable.qnt +801 -0
- package/specs/apg/listbox-single.qnt +511 -0
- package/specs/apg/listbox-typeahead.qnt +396 -0
- package/specs/apg/menu-button.qnt +363 -0
- package/specs/apg/menu-checkable.qnt +304 -0
- package/specs/apg/menu-menubar.qnt +531 -0
- package/specs/apg/meter.qnt +129 -0
- package/specs/apg/player.qnt +1081 -0
- package/specs/apg/radio.qnt +394 -0
- package/specs/apg/slider-multithumb.qnt +441 -0
- package/specs/apg/slider.qnt +396 -0
- package/specs/apg/spinbutton.qnt +494 -0
- package/specs/apg/switch.qnt +389 -0
- package/specs/apg/tabs.qnt +412 -0
- package/specs/apg/timeline.qnt +612 -0
- package/specs/apg/toolbar.qnt +364 -0
- package/specs/apg/tooltip.qnt +553 -0
- package/specs/apg/treegrid.qnt +983 -0
- package/specs/apg/treeview.qnt +1004 -0
- package/specs/apg/windowsplitter.qnt +487 -0
- package/specs/canvas/camera.qnt +407 -0
- package/specs/canvas/pointer.qnt +841 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ActionStep, Probe, ScenarioConfig, SpecBridge } from "../scenario.mjs";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
//#region src/apg/radio.bridge.d.ts
|
|
4
|
+
/** Scenario `config` -> what both targets are mounted with. */
|
|
5
|
+
export interface RadioConfig {
|
|
6
|
+
/** Radio count; the spec fixes it at four, so more is unsupported. */
|
|
7
|
+
readonly items: number;
|
|
8
|
+
readonly values: ReadonlyArray<Schema.Json>;
|
|
9
|
+
readonly checked: number | null;
|
|
10
|
+
readonly flavor: "roving" | "activedescendant";
|
|
11
|
+
readonly disabled: ReadonlyArray<number>;
|
|
12
|
+
readonly direction: "ltr" | "rtl";
|
|
13
|
+
readonly orientation: "horizontal" | "vertical" | undefined;
|
|
14
|
+
readonly describedby: string | undefined;
|
|
15
|
+
/** The host owns the check (`value` prop present). */
|
|
16
|
+
readonly controlled: boolean;
|
|
17
|
+
/** Controlled only: the host writes every request's intent back. */
|
|
18
|
+
readonly accepts: boolean;
|
|
19
|
+
/** Controlled only: a pinned checked index the host holds (rejects). */
|
|
20
|
+
readonly pinned: number | null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Radio-group vocabulary <-> `specs/apg/radio.qnt`. Parts: `radiogroup` and
|
|
24
|
+
* `radio:N`. The spec fixes the group at four radios, so a scenario with more
|
|
25
|
+
* (or a value count that disagrees with `items`) is unsupported; a smaller
|
|
26
|
+
* group still maps onto the same events for scenario replay.
|
|
27
|
+
*/
|
|
28
|
+
export declare const radioConfig: (config: ScenarioConfig) => RadioConfig;
|
|
29
|
+
/** base-ui calls the callback `onValueChange`; ariakit/react-aria call it `onChange`. */
|
|
30
|
+
export declare const canonicalEvent: (name: string) => string;
|
|
31
|
+
export declare const radioBridge: SpecBridge;
|
|
32
|
+
/** The user-level steps a differential walk draws from. */
|
|
33
|
+
export declare const radioSteps: ReadonlyArray<ActionStep>;
|
|
34
|
+
export declare const radioProbe: Probe;
|
|
35
|
+
//#endregion
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { Unsupported } from "../scenario.mjs";
|
|
2
|
+
//#region src/apg/radio.bridge.ts
|
|
3
|
+
const specEvent = (tag, params = {}) => ({
|
|
4
|
+
_tag: tag,
|
|
5
|
+
...params
|
|
6
|
+
});
|
|
7
|
+
const FLAVORS = /* @__PURE__ */ new Set(["roving", "activedescendant"]);
|
|
8
|
+
const DIRECTIONS = /* @__PURE__ */ new Set(["ltr", "rtl"]);
|
|
9
|
+
const ORIENTATIONS = /* @__PURE__ */ new Set(["horizontal", "vertical"]);
|
|
10
|
+
const parseChecked = (value) => {
|
|
11
|
+
if (value === null || value === void 0) return null;
|
|
12
|
+
if (typeof value === "number" && Number.isInteger(value)) return value;
|
|
13
|
+
if (typeof value === "string") {
|
|
14
|
+
const match = /^radio:(\d+)$/.exec(value);
|
|
15
|
+
if (match?.[1] !== void 0) return Number(match[1]);
|
|
16
|
+
}
|
|
17
|
+
throw new Unsupported(`checked ${JSON.stringify(value)}`);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Radio-group vocabulary <-> `specs/apg/radio.qnt`. Parts: `radiogroup` and
|
|
21
|
+
* `radio:N`. The spec fixes the group at four radios, so a scenario with more
|
|
22
|
+
* (or a value count that disagrees with `items`) is unsupported; a smaller
|
|
23
|
+
* group still maps onto the same events for scenario replay.
|
|
24
|
+
*/
|
|
25
|
+
const radioConfig = (config) => {
|
|
26
|
+
let items;
|
|
27
|
+
let values;
|
|
28
|
+
let checked = null;
|
|
29
|
+
let flavor = "roving";
|
|
30
|
+
let disabled = [];
|
|
31
|
+
let direction = "ltr";
|
|
32
|
+
let orientation;
|
|
33
|
+
let describedby;
|
|
34
|
+
let controlled = false;
|
|
35
|
+
let pinned = null;
|
|
36
|
+
for (const [key, value] of Object.entries(config)) switch (key) {
|
|
37
|
+
case "items":
|
|
38
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1) throw new Unsupported(`items ${JSON.stringify(value)}`);
|
|
39
|
+
items = value;
|
|
40
|
+
break;
|
|
41
|
+
case "values":
|
|
42
|
+
if (!Array.isArray(value)) throw new Unsupported(`values ${JSON.stringify(value)}`);
|
|
43
|
+
values = value;
|
|
44
|
+
break;
|
|
45
|
+
case "checked":
|
|
46
|
+
checked = parseChecked(value);
|
|
47
|
+
break;
|
|
48
|
+
case "flavor":
|
|
49
|
+
if (typeof value !== "string" || !FLAVORS.has(value)) throw new Unsupported(`flavor ${JSON.stringify(value)}`);
|
|
50
|
+
flavor = value;
|
|
51
|
+
break;
|
|
52
|
+
case "disabled":
|
|
53
|
+
if (!Array.isArray(value) || !value.every((v) => typeof v === "number" && Number.isInteger(v))) throw new Unsupported(`disabled ${JSON.stringify(value)}`);
|
|
54
|
+
disabled = value;
|
|
55
|
+
break;
|
|
56
|
+
case "direction":
|
|
57
|
+
if (typeof value !== "string" || !DIRECTIONS.has(value)) throw new Unsupported(`direction ${JSON.stringify(value)}`);
|
|
58
|
+
direction = value;
|
|
59
|
+
break;
|
|
60
|
+
case "orientation":
|
|
61
|
+
if (typeof value !== "string" || !ORIENTATIONS.has(value)) throw new Unsupported(`orientation ${JSON.stringify(value)}`);
|
|
62
|
+
orientation = value;
|
|
63
|
+
break;
|
|
64
|
+
case "radioDescribedby":
|
|
65
|
+
if (typeof value !== "string") throw new Unsupported(`radioDescribedby ${JSON.stringify(value)}`);
|
|
66
|
+
describedby = value;
|
|
67
|
+
break;
|
|
68
|
+
case "controlled":
|
|
69
|
+
if (typeof value !== "boolean") throw new Unsupported(`controlled ${JSON.stringify(value)}`);
|
|
70
|
+
controlled ||= value;
|
|
71
|
+
break;
|
|
72
|
+
case "value": {
|
|
73
|
+
const index = parseChecked(value);
|
|
74
|
+
if (index === null) throw new Unsupported(`value ${JSON.stringify(value)}`);
|
|
75
|
+
pinned = index;
|
|
76
|
+
controlled = true;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
default: throw new Unsupported(`config ${key}=${JSON.stringify(value)}`);
|
|
80
|
+
}
|
|
81
|
+
if (items === void 0 && values === void 0) throw new Unsupported("radio config needs items or values");
|
|
82
|
+
if (items !== void 0 && items > 4) throw new Unsupported(`items ${items} (spec models four)`);
|
|
83
|
+
if (items === void 0) {
|
|
84
|
+
if (values === void 0) throw new Unsupported("no items");
|
|
85
|
+
items = values.length;
|
|
86
|
+
}
|
|
87
|
+
if (values !== void 0 && values.length !== items) throw new Unsupported(`values ${values.length} vs items ${items}`);
|
|
88
|
+
if (values === void 0) values = Array.from({ length: items }, (_, i) => String(i));
|
|
89
|
+
if (pinned !== null && (pinned < 0 || pinned > 3 || disabled.includes(pinned))) throw new Unsupported(`value ${pinned} cannot be checked`);
|
|
90
|
+
return {
|
|
91
|
+
items,
|
|
92
|
+
values,
|
|
93
|
+
checked,
|
|
94
|
+
flavor,
|
|
95
|
+
disabled,
|
|
96
|
+
direction,
|
|
97
|
+
orientation,
|
|
98
|
+
describedby,
|
|
99
|
+
controlled,
|
|
100
|
+
accepts: controlled && pinned === null,
|
|
101
|
+
pinned
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
const partOf = (target) => {
|
|
105
|
+
if (target === void 0) throw new Unsupported("step needs a target");
|
|
106
|
+
return target.replace(/:0$/, "");
|
|
107
|
+
};
|
|
108
|
+
/** base-ui calls the callback `onValueChange`; ariakit/react-aria call it `onChange`. */
|
|
109
|
+
const canonicalEvent = (name) => name === "onValueChange" ? "onChange" : name;
|
|
110
|
+
const jsonKey = (value) => {
|
|
111
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return;
|
|
112
|
+
const key = value["key"];
|
|
113
|
+
return typeof key === "string" ? key : void 0;
|
|
114
|
+
};
|
|
115
|
+
const radioIndexOf = (target) => {
|
|
116
|
+
const part = partOf(target);
|
|
117
|
+
if (part === "radio") return 0;
|
|
118
|
+
const match = /^radio:(\d+)$/.exec(part);
|
|
119
|
+
const index = match?.[1] === void 0 ? NaN : Number(match[1]);
|
|
120
|
+
if (!Number.isInteger(index) || index < 0 || index > 3) throw new Unsupported(`target ${target ?? ""}`);
|
|
121
|
+
return index;
|
|
122
|
+
};
|
|
123
|
+
const keyEvents = (key) => {
|
|
124
|
+
switch (key) {
|
|
125
|
+
case "ArrowDown":
|
|
126
|
+
case "ArrowRight": return [specEvent("arrow_next")];
|
|
127
|
+
case "ArrowUp":
|
|
128
|
+
case "ArrowLeft": return [specEvent("arrow_prev")];
|
|
129
|
+
case " ":
|
|
130
|
+
case "Space": return [specEvent("space")];
|
|
131
|
+
case "Enter": return [];
|
|
132
|
+
default: throw new Unsupported(`key ${key ?? ""}`);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const programmatic = (step) => {
|
|
136
|
+
switch (step.prop) {
|
|
137
|
+
case "focus": return [specEvent("enter")];
|
|
138
|
+
case "blur": return [specEvent("leave")];
|
|
139
|
+
case "key": {
|
|
140
|
+
const key = jsonKey(step.value);
|
|
141
|
+
if (key === void 0) throw new Unsupported(`prop key ${JSON.stringify(step.value)}`);
|
|
142
|
+
return keyEvents(key);
|
|
143
|
+
}
|
|
144
|
+
case "click":
|
|
145
|
+
if (typeof step.value !== "number" || !Number.isInteger(step.value)) throw new Unsupported(`prop click ${JSON.stringify(step.value)}`);
|
|
146
|
+
return [specEvent("click", { target: BigInt(step.value) })];
|
|
147
|
+
case "preselect": {
|
|
148
|
+
const pick = typeof step.value === "number" ? step.value : -1;
|
|
149
|
+
return [specEvent("preselect", { pick: BigInt(pick) })];
|
|
150
|
+
}
|
|
151
|
+
case "setValue":
|
|
152
|
+
if (typeof step.value !== "number" || !Number.isInteger(step.value)) throw new Unsupported(`setValue ${JSON.stringify(step.value)}`);
|
|
153
|
+
return [specEvent("setValue", { v: BigInt(step.value) })];
|
|
154
|
+
case "disabled":
|
|
155
|
+
if (typeof step.value !== "number" || !Number.isInteger(step.value)) throw new Unsupported(`prop disabled ${JSON.stringify(step.value)}`);
|
|
156
|
+
return [specEvent("set_disabled", { m: BigInt(step.value) })];
|
|
157
|
+
case "flavor":
|
|
158
|
+
if (typeof step.value !== "string" || !FLAVORS.has(step.value)) throw new Unsupported(`prop flavor ${JSON.stringify(step.value)}`);
|
|
159
|
+
return [specEvent("set_flavor", { v: step.value })];
|
|
160
|
+
default: throw new Unsupported(`prop ${step.prop ?? ""}`);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const asInt = (value) => {
|
|
164
|
+
if (typeof value === "bigint") return Number(value);
|
|
165
|
+
return -1;
|
|
166
|
+
};
|
|
167
|
+
const bit = (mask, index) => (mask >> BigInt(index)) % 2n === 1n;
|
|
168
|
+
const tabStop = (mask, checked) => {
|
|
169
|
+
if (checked >= 0) return checked;
|
|
170
|
+
for (let index = 0; index < 4; index += 1) if (!bit(mask, index)) return index;
|
|
171
|
+
return 0;
|
|
172
|
+
};
|
|
173
|
+
const radioBridge = {
|
|
174
|
+
setup: (config) => {
|
|
175
|
+
const mount = radioConfig(config);
|
|
176
|
+
const events = [];
|
|
177
|
+
if (mount.flavor === "activedescendant") events.push(specEvent("set_flavor", { v: "activedescendant" }));
|
|
178
|
+
if (mount.disabled.length > 0) {
|
|
179
|
+
const mask = mount.disabled.reduce((acc, index) => acc | 1 << index, 0);
|
|
180
|
+
events.push(specEvent("set_disabled", { m: BigInt(mask) }));
|
|
181
|
+
}
|
|
182
|
+
const initialChecked = mount.controlled ? mount.pinned ?? mount.checked : mount.checked;
|
|
183
|
+
if (initialChecked !== null) events.push(specEvent("preselect", { pick: BigInt(initialChecked) }));
|
|
184
|
+
if (mount.controlled) {
|
|
185
|
+
events.push(specEvent("control"));
|
|
186
|
+
if (mount.accepts) events.push(specEvent("acceptRequests"));
|
|
187
|
+
}
|
|
188
|
+
return events;
|
|
189
|
+
},
|
|
190
|
+
event: (step) => {
|
|
191
|
+
switch (step.event) {
|
|
192
|
+
case "focus":
|
|
193
|
+
radioIndexOf(step.target);
|
|
194
|
+
return [specEvent("enter")];
|
|
195
|
+
case "blur":
|
|
196
|
+
partOf(step.target);
|
|
197
|
+
return [specEvent("leave")];
|
|
198
|
+
case "click": return [specEvent("click", { target: BigInt(radioIndexOf(step.target)) })];
|
|
199
|
+
case "key":
|
|
200
|
+
partOf(step.target);
|
|
201
|
+
if (step.repeat === true) throw new Unsupported("key repeat is not modelled as one event");
|
|
202
|
+
return keyEvents(step.key);
|
|
203
|
+
case "prop": return programmatic(step);
|
|
204
|
+
default: throw new Unsupported(`event ${step.event}`);
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
focus: (state) => {
|
|
208
|
+
const focus = asInt(state["focus"]);
|
|
209
|
+
if (state["flavor"] === "activedescendant") return focus >= 0 ? "radiogroup" : null;
|
|
210
|
+
return focus >= 0 ? `radio:${focus}` : null;
|
|
211
|
+
},
|
|
212
|
+
attr: (state, target, name) => {
|
|
213
|
+
const part = partOf(target);
|
|
214
|
+
const flavor = String(state["flavor"]);
|
|
215
|
+
const checked = asInt(state["checked"]);
|
|
216
|
+
const focus = asInt(state["focus"]);
|
|
217
|
+
const mask = typeof state["mask"] === "bigint" ? state["mask"] : 0n;
|
|
218
|
+
if (part === "radiogroup") {
|
|
219
|
+
if (name === "aria-activedescendant") return flavor === "activedescendant" && focus >= 0 ? `radio:${focus}` : null;
|
|
220
|
+
throw new Unsupported(`attribute ${name} on ${target}`);
|
|
221
|
+
}
|
|
222
|
+
const index = radioIndexOf(target);
|
|
223
|
+
switch (name) {
|
|
224
|
+
case "aria-checked": return checked === index ? "true" : "false";
|
|
225
|
+
case "aria-disabled": return bit(mask, index) ? "true" : "false";
|
|
226
|
+
case "tabindex":
|
|
227
|
+
if (flavor !== "roving") return null;
|
|
228
|
+
return index === tabStop(mask, checked) ? "0" : "-1";
|
|
229
|
+
default: throw new Unsupported(`attribute ${name} on ${target}`);
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
visible: () => [],
|
|
233
|
+
events: (before, after) => before["requests"] === after["requests"] ? [] : [["onChangeIndex", Number(after["requested"])]],
|
|
234
|
+
eventName: canonicalEvent
|
|
235
|
+
};
|
|
236
|
+
/** The user-level steps a differential walk draws from. */
|
|
237
|
+
const radioSteps = [
|
|
238
|
+
{
|
|
239
|
+
event: "prop",
|
|
240
|
+
prop: "focus"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
event: "prop",
|
|
244
|
+
prop: "blur"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
event: "prop",
|
|
248
|
+
prop: "key",
|
|
249
|
+
value: { key: "ArrowDown" }
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
event: "prop",
|
|
253
|
+
prop: "key",
|
|
254
|
+
value: { key: "ArrowUp" }
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
event: "prop",
|
|
258
|
+
prop: "key",
|
|
259
|
+
value: { key: "ArrowLeft" }
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
event: "prop",
|
|
263
|
+
prop: "key",
|
|
264
|
+
value: { key: "ArrowRight" }
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
event: "prop",
|
|
268
|
+
prop: "key",
|
|
269
|
+
value: { key: " " }
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
event: "prop",
|
|
273
|
+
prop: "preselect",
|
|
274
|
+
value: 0
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
event: "prop",
|
|
278
|
+
prop: "preselect",
|
|
279
|
+
value: 1
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
event: "prop",
|
|
283
|
+
prop: "preselect",
|
|
284
|
+
value: 2
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
event: "prop",
|
|
288
|
+
prop: "preselect",
|
|
289
|
+
value: 3
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
event: "prop",
|
|
293
|
+
prop: "disabled",
|
|
294
|
+
value: 0
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
event: "prop",
|
|
298
|
+
prop: "disabled",
|
|
299
|
+
value: 1
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
event: "prop",
|
|
303
|
+
prop: "disabled",
|
|
304
|
+
value: 6
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
event: "prop",
|
|
308
|
+
prop: "disabled",
|
|
309
|
+
value: 9
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
event: "prop",
|
|
313
|
+
prop: "disabled",
|
|
314
|
+
value: 14
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
event: "prop",
|
|
318
|
+
prop: "flavor",
|
|
319
|
+
value: "roving"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
event: "prop",
|
|
323
|
+
prop: "flavor",
|
|
324
|
+
value: "activedescendant"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
event: "prop",
|
|
328
|
+
prop: "click",
|
|
329
|
+
value: 0
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
event: "prop",
|
|
333
|
+
prop: "click",
|
|
334
|
+
value: 1
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
event: "prop",
|
|
338
|
+
prop: "click",
|
|
339
|
+
value: 2
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
event: "prop",
|
|
343
|
+
prop: "click",
|
|
344
|
+
value: 3
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
event: "prop",
|
|
348
|
+
prop: "setValue",
|
|
349
|
+
value: 2
|
|
350
|
+
}
|
|
351
|
+
];
|
|
352
|
+
const radioProbe = {
|
|
353
|
+
attrs: [
|
|
354
|
+
["radiogroup", "aria-activedescendant"],
|
|
355
|
+
["radio:0", "aria-checked"],
|
|
356
|
+
["radio:1", "aria-checked"],
|
|
357
|
+
["radio:2", "aria-checked"],
|
|
358
|
+
["radio:3", "aria-checked"],
|
|
359
|
+
["radio:0", "aria-disabled"],
|
|
360
|
+
["radio:1", "aria-disabled"],
|
|
361
|
+
["radio:2", "aria-disabled"],
|
|
362
|
+
["radio:3", "aria-disabled"],
|
|
363
|
+
["radio:0", "tabindex"],
|
|
364
|
+
["radio:1", "tabindex"],
|
|
365
|
+
["radio:2", "tabindex"],
|
|
366
|
+
["radio:3", "tabindex"]
|
|
367
|
+
],
|
|
368
|
+
events: ["onChangeIndex"]
|
|
369
|
+
};
|
|
370
|
+
//#endregion
|
|
371
|
+
export { canonicalEvent, radioBridge, radioConfig, radioProbe, radioSteps };
|