@reticular/speakable 1.5.0 → 1.7.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.
@@ -0,0 +1,7 @@
1
+ import {
2
+ awaitCustomElementsReady
3
+ } from "./chunk-3SVI6IQE.js";
4
+ import "./chunk-JSBRDJBE.js";
5
+ export {
6
+ awaitCustomElementsReady
7
+ };
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Transport-agnostic static accessibility analysis.
3
+ *
4
+ * Wraps the core Speakable engine (tree-builder + per-reader renderers +
5
+ * audit) to produce differentiated screen reader output predictions from a
6
+ * live DOM element. This is the single source of truth consumed by the
7
+ * Storybook addon, the iframe harness, and the browser extension.
8
+ */
9
+ interface AuditFinding {
10
+ severity: 'error' | 'warning' | 'info';
11
+ message: string;
12
+ selector: string;
13
+ }
14
+ interface AnalysisResult {
15
+ nvda: string[];
16
+ jaws: string[];
17
+ voiceover: string[];
18
+ narrator: string[];
19
+ audit: AuditFinding[];
20
+ stats: {
21
+ totalElements: number;
22
+ interactiveElements: number;
23
+ landmarks: number;
24
+ headings: number;
25
+ };
26
+ /** Tree-build and upgrade warnings surfaced to the user. */
27
+ warnings: string[];
28
+ }
29
+ /**
30
+ * Analyze a live DOM element using the core Speakable engine.
31
+ *
32
+ * Reuses buildAccessibilityTree + the four renderers + generateAuditReport.
33
+ * Never throws on empty or detached input — returns a well-formed empty result.
34
+ *
35
+ * @param root - DOM element to analyze
36
+ * @param extraWarnings - Optional warnings to fold in (e.g. upgrade timeouts)
37
+ * @returns Differentiated per-reader analysis result
38
+ */
39
+ declare function analyzeElement(root: Element | null | undefined, extraWarnings?: string[]): AnalysisResult;
40
+ /**
41
+ * Analyze a live DOM element after awaiting custom-element upgrade.
42
+ *
43
+ * Waits for web components under `root` to upgrade/render (bounded by
44
+ * `upgradeTimeoutMs`), then runs `analyzeElement`, folding any upgrade
45
+ * warnings into `result.warnings`. Use this in real-browser surfaces
46
+ * (harness, extension, addon) where components may hydrate asynchronously.
47
+ */
48
+ declare function analyzeElementWithUpgrade(root: Element | null | undefined, upgradeTimeoutMs?: number): Promise<AnalysisResult>;
49
+
50
+ /**
51
+ * Runtime Accessibility Timeline - Type System
52
+ *
53
+ * Normalized event structures for representing accessibility-relevant
54
+ * changes during component interaction. All events use a discriminated
55
+ * union via the `kind` field on payloads and the `type` field on actions.
56
+ */
57
+ /**
58
+ * Classification of accessibility-relevant events observed during runtime.
59
+ */
60
+ type EventType = 'FOCUS_CHANGED' | 'ANNOUNCEMENT' | 'DOM_MUTATION' | 'ROLE_CHANGED' | 'ACCESSIBLE_NAME_CHANGED' | 'STATE_CHANGED' | 'KEYBOARD_ACTION' | 'DIALOG_OPENED' | 'DIALOG_CLOSED' | 'WARNING' | 'REGRESSION';
61
+ /**
62
+ * Identifies the DOM element targeted by an accessibility event.
63
+ */
64
+ interface EventTarget {
65
+ /** ARIA role of the target element */
66
+ role: string;
67
+ /** Computed accessible name */
68
+ accessibleName: string;
69
+ /** Stable CSS selector path for element identification */
70
+ selector: string;
71
+ }
72
+ interface FocusChangedPayload {
73
+ kind: 'focus_changed';
74
+ previousTarget: EventTarget | null;
75
+ }
76
+ interface AnnouncementPayload {
77
+ kind: 'announcement';
78
+ politeness: 'polite' | 'assertive';
79
+ text: string;
80
+ }
81
+ interface RoleChangedPayload {
82
+ kind: 'role_changed';
83
+ previousRole: string;
84
+ newRole: string;
85
+ }
86
+ interface AccessibleNameChangedPayload {
87
+ kind: 'accessible_name_changed';
88
+ previousName: string;
89
+ newName: string;
90
+ }
91
+ interface StateChangedPayload {
92
+ kind: 'state_changed';
93
+ attribute: string;
94
+ previousValue: string | boolean | null;
95
+ newValue: string | boolean | null;
96
+ }
97
+ interface DialogOpenedPayload {
98
+ kind: 'dialog_opened';
99
+ dialogName: string;
100
+ isModal: boolean;
101
+ }
102
+ interface DialogClosedPayload {
103
+ kind: 'dialog_closed';
104
+ dialogName: string;
105
+ }
106
+ interface KeyboardActionPayload {
107
+ kind: 'keyboard_action';
108
+ key: string;
109
+ modifiers: string[];
110
+ }
111
+ interface WarningPayload {
112
+ kind: 'warning';
113
+ message: string;
114
+ relatedEvent?: AccessibilityEvent;
115
+ }
116
+ /**
117
+ * Discriminated union of all event payload types.
118
+ * Use the `kind` field to narrow the type.
119
+ */
120
+ type EventPayload = FocusChangedPayload | AnnouncementPayload | RoleChangedPayload | AccessibleNameChangedPayload | StateChangedPayload | DialogOpenedPayload | DialogClosedPayload | KeyboardActionPayload | WarningPayload;
121
+ /**
122
+ * A normalized event representing a single accessibility-relevant change.
123
+ * Contains common fields for classification, timing, targeting, and
124
+ * type-specific payload data.
125
+ */
126
+ interface AccessibilityEvent {
127
+ /** Event classification */
128
+ type: EventType;
129
+ /** Milliseconds elapsed since session start */
130
+ timestamp: number;
131
+ /** Target element information */
132
+ target: EventTarget;
133
+ /** Type-specific payload data */
134
+ payload: EventPayload;
135
+ }
136
+ /**
137
+ * Discriminated union of interaction actions.
138
+ * Use the `type` field to narrow the action kind.
139
+ */
140
+ type InteractionAction = {
141
+ type: 'click';
142
+ selector: string;
143
+ } | {
144
+ type: 'tab';
145
+ } | {
146
+ type: 'shiftTab';
147
+ } | {
148
+ type: 'escape';
149
+ } | {
150
+ type: 'enter';
151
+ } | {
152
+ type: 'space';
153
+ } | {
154
+ type: 'arrowUp';
155
+ } | {
156
+ type: 'arrowDown';
157
+ } | {
158
+ type: 'arrowLeft';
159
+ } | {
160
+ type: 'arrowRight';
161
+ } | {
162
+ type: 'key';
163
+ combo: string;
164
+ } | {
165
+ type: 'wait';
166
+ ms: number;
167
+ };
168
+ /**
169
+ * An ordered sequence of user actions to perform during timeline capture.
170
+ */
171
+ interface InteractionSequence {
172
+ /** Human-readable description of the interaction */
173
+ description: string;
174
+ /** Ordered list of actions to perform */
175
+ actions: InteractionAction[];
176
+ }
177
+ /**
178
+ * Metadata captured alongside an accessibility timeline session.
179
+ */
180
+ interface TimelineMetadata {
181
+ /** ISO timestamp of when the timeline was captured */
182
+ capturedAt: string;
183
+ /** Speakable package version used for capture */
184
+ speakableVersion: string;
185
+ /** The URL that was analyzed */
186
+ sourceUrl: string;
187
+ /** Browser context identifier (e.g., "jsdom/23.0.0") */
188
+ userAgent: string;
189
+ }
190
+ /**
191
+ * A complete accessibility timeline captured during an interaction session.
192
+ * Contains the ordered event sequence, session metadata, and extracted warnings.
193
+ */
194
+ interface AccessibilityTimeline {
195
+ /** Timeline format version string (e.g., "1.0") */
196
+ version: string;
197
+ /** Component name */
198
+ component: string;
199
+ /** Story or variant name */
200
+ story: string | null;
201
+ /** Human-readable description of the interaction sequence performed */
202
+ interactionSequence: string;
203
+ /** Total session duration in milliseconds */
204
+ duration: number;
205
+ /** All accessibility events in chronological order */
206
+ events: AccessibilityEvent[];
207
+ /** WARNING-type events extracted for quick reference */
208
+ warnings: AccessibilityEvent[];
209
+ /** Session capture metadata */
210
+ metadata: TimelineMetadata;
211
+ }
212
+
213
+ export { type AccessibilityTimeline as A, type InteractionSequence as I, type AnalysisResult as a, type AuditFinding as b, analyzeElement as c, analyzeElementWithUpgrade as d };
@@ -0,0 +1,7 @@
1
+ import {
2
+ awaitCustomElementsReady
3
+ } from "./chunk-WYFXGXYU.js";
4
+ export {
5
+ awaitCustomElementsReady
6
+ };
7
+ //# sourceMappingURL=upgrade-53M5VYGH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,10 +1,25 @@
1
1
  {
2
2
  "name": "@reticular/speakable",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "CLI tool for analyzing HTML accessibility announcements",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./browser": {
14
+ "types": "./dist/browser/index.d.ts",
15
+ "import": "./dist/browser/index.js"
16
+ },
17
+ "./harness": {
18
+ "types": "./dist/harness/index.d.ts",
19
+ "import": "./dist/harness/index.js"
20
+ },
21
+ "./storybook": "./dist/storybook/preset.js"
22
+ },
8
23
  "files": [
9
24
  "dist"
10
25
  ],
@@ -13,12 +28,13 @@
13
28
  "speakable-mcp": "dist/mcp.js"
14
29
  },
15
30
  "scripts": {
16
- "build": "tsup",
31
+ "build": "tsup && npm run build:addon",
32
+ "build:addon": "npm run build --prefix addon-speakable && cp -r addon-speakable/dist dist/storybook",
17
33
  "dev": "tsup --watch",
18
34
  "test": "vitest run",
19
35
  "test:watch": "vitest",
20
36
  "test:coverage": "vitest run --coverage",
21
- "storybook": "storybook dev -p 6006",
37
+ "storybook": "npm run build --prefix addon-speakable && concurrently -n addon,storybook -c blue,magenta \"npm run dev --prefix addon-speakable\" \"storybook dev -p 6006\"",
22
38
  "build-storybook": "storybook build",
23
39
  "test:a11y": "node --loader ts-node/esm stories/speakable-test.ts",
24
40
  "test:a11y:ci": "vitest run tests/multiselect-a11y.test.ts"
@@ -50,6 +66,7 @@
50
66
  "@types/jsdom": "^28.0.1",
51
67
  "@types/node": "^20.0.0",
52
68
  "@vitest/coverage-v8": "^3.1.0",
69
+ "concurrently": "^10.0.4",
53
70
  "fast-check": "^3.15.0",
54
71
  "storybook": "^8.6.18",
55
72
  "tsup": "^8.5.0",
@@ -62,5 +79,13 @@
62
79
  "jsdom": "^23.0.0",
63
80
  "picocolors": "^1.1.1",
64
81
  "zod": "^3.24.0"
82
+ },
83
+ "peerDependencies": {
84
+ "storybook": "^8.0.0"
85
+ },
86
+ "peerDependenciesMeta": {
87
+ "storybook": {
88
+ "optional": true
89
+ }
65
90
  }
66
91
  }