@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.
- package/README.md +86 -2
- package/dist/browser/index.d.ts +58 -0
- package/dist/browser/index.js +3978 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/chunk-WYFXGXYU.js +87 -0
- package/dist/chunk-WYFXGXYU.js.map +1 -0
- package/dist/cli.js +40 -19
- package/dist/cli.js.map +1 -1
- package/dist/harness/index.d.ts +57 -0
- package/dist/harness/index.js +176 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/index.js +44 -22
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +40 -19
- package/dist/mcp.js.map +1 -1
- package/dist/speakable-browser.global.js +10 -0
- package/dist/speakable-browser.global.js.map +1 -0
- package/dist/storybook/dist/chunk-3SVI6IQE.js +86 -0
- package/dist/storybook/dist/chunk-JSBRDJBE.js +30 -0
- package/dist/storybook/dist/chunk-QVJRQZT5.js +16 -0
- package/dist/storybook/dist/index.js +17 -0
- package/dist/storybook/dist/manager.js +701 -0
- package/dist/storybook/dist/preset.js +38 -0
- package/dist/storybook/dist/preview.js +4199 -0
- package/dist/storybook/dist/upgrade-5GL42JH4.js +7 -0
- package/dist/types-Blh0EnZF.d.ts +213 -0
- package/dist/upgrade-53M5VYGH.js +7 -0
- package/dist/upgrade-53M5VYGH.js.map +1 -0
- package/package.json +28 -3
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/browser/upgrade.ts
|
|
2
|
+
var DEFAULT_UPGRADE_TIMEOUT_MS = 2e3;
|
|
3
|
+
function withTimeout(promise, timeoutMs) {
|
|
4
|
+
return new Promise((resolve) => {
|
|
5
|
+
let settled = false;
|
|
6
|
+
const timer = setTimeout(() => {
|
|
7
|
+
if (!settled) {
|
|
8
|
+
settled = true;
|
|
9
|
+
resolve(false);
|
|
10
|
+
}
|
|
11
|
+
}, timeoutMs);
|
|
12
|
+
promise.then(
|
|
13
|
+
() => {
|
|
14
|
+
if (!settled) {
|
|
15
|
+
settled = true;
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
resolve(true);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
() => {
|
|
21
|
+
if (!settled) {
|
|
22
|
+
settled = true;
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
resolve(true);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function collectCustomElementTags(root) {
|
|
31
|
+
const tags = /* @__PURE__ */ new Set();
|
|
32
|
+
const rootEl = "documentElement" in root ? root.documentElement : root;
|
|
33
|
+
if (!rootEl) return [];
|
|
34
|
+
const consider = (el) => {
|
|
35
|
+
if (el.localName && el.localName.includes("-")) {
|
|
36
|
+
tags.add(el.localName);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
consider(rootEl);
|
|
40
|
+
const all = rootEl.querySelectorAll("*");
|
|
41
|
+
all.forEach(consider);
|
|
42
|
+
return Array.from(tags);
|
|
43
|
+
}
|
|
44
|
+
function collectUpdateCompletables(root) {
|
|
45
|
+
const rootEl = "documentElement" in root ? root.documentElement : root;
|
|
46
|
+
if (!rootEl) return [];
|
|
47
|
+
const promises = [];
|
|
48
|
+
const consider = (el) => {
|
|
49
|
+
const uc = el.updateComplete;
|
|
50
|
+
if (uc && typeof uc.then === "function") {
|
|
51
|
+
promises.push(uc);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
consider(rootEl);
|
|
55
|
+
rootEl.querySelectorAll("*").forEach(consider);
|
|
56
|
+
return promises;
|
|
57
|
+
}
|
|
58
|
+
async function awaitCustomElementsReady(root, timeoutMs = DEFAULT_UPGRADE_TIMEOUT_MS) {
|
|
59
|
+
const warnings = [];
|
|
60
|
+
const hasCustomElements = typeof customElements !== "undefined" && customElements !== null;
|
|
61
|
+
if (!hasCustomElements) {
|
|
62
|
+
return warnings;
|
|
63
|
+
}
|
|
64
|
+
const tags = collectCustomElementTags(root);
|
|
65
|
+
await Promise.all(
|
|
66
|
+
tags.map(async (tag) => {
|
|
67
|
+
if (customElements.get(tag)) return;
|
|
68
|
+
const defined = await withTimeout(customElements.whenDefined(tag), timeoutMs);
|
|
69
|
+
if (!defined) {
|
|
70
|
+
warnings.push({
|
|
71
|
+
tag,
|
|
72
|
+
message: `Custom element "${tag}" did not upgrade within ${timeoutMs}ms; analysis may reflect a pre-hydration state.`
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
const updateCompletables = collectUpdateCompletables(root);
|
|
78
|
+
if (updateCompletables.length > 0) {
|
|
79
|
+
await withTimeout(Promise.all(updateCompletables), timeoutMs);
|
|
80
|
+
}
|
|
81
|
+
return warnings;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
awaitCustomElementsReady
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=chunk-WYFXGXYU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/browser/upgrade.ts"],"sourcesContent":["/**\n * Custom-element upgrade awaiting.\n *\n * Runs in a real browser (needs `customElements`). Waits for custom elements\n * under a root to be defined and, where supported, to finish rendering\n * (Lit's `updateComplete`) before analysis/capture proceeds. Bounded by a\n * timeout so it never blocks indefinitely; unresolved tags become warnings.\n */\n\nexport interface UpgradeWarning {\n message: string;\n tag: string;\n}\n\nconst DEFAULT_UPGRADE_TIMEOUT_MS = 2000;\n\n/**\n * Resolve a promise, or resolve with a sentinel when the timeout elapses.\n * Returns true if the promise resolved in time, false on timeout.\n */\nfunction withTimeout(promise: Promise<unknown>, timeoutMs: number): Promise<boolean> {\n return new Promise<boolean>(resolve => {\n let settled = false;\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n resolve(false);\n }\n }, timeoutMs);\n\n promise.then(\n () => {\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve(true);\n }\n },\n () => {\n // A rejected upgrade promise still means \"no longer pending\".\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve(true);\n }\n }\n );\n });\n}\n\n/**\n * Collect distinct custom-element tag names present under a root.\n * A custom element tag always contains a hyphen.\n */\nfunction collectCustomElementTags(root: Document | Element): string[] {\n const tags = new Set<string>();\n const rootEl: Element | null =\n 'documentElement' in root ? (root as Document).documentElement : (root as Element);\n if (!rootEl) return [];\n\n const consider = (el: Element) => {\n if (el.localName && el.localName.includes('-')) {\n tags.add(el.localName);\n }\n };\n\n consider(rootEl);\n const all = rootEl.querySelectorAll('*');\n all.forEach(consider);\n\n return Array.from(tags);\n}\n\n/**\n * Collect elements that expose an `updateComplete` thenable (e.g. Lit).\n */\nfunction collectUpdateCompletables(root: Document | Element): Promise<unknown>[] {\n const rootEl: Element | null =\n 'documentElement' in root ? (root as Document).documentElement : (root as Element);\n if (!rootEl) return [];\n\n const promises: Promise<unknown>[] = [];\n const consider = (el: Element) => {\n const uc = (el as unknown as { updateComplete?: unknown }).updateComplete;\n if (uc && typeof (uc as Promise<unknown>).then === 'function') {\n promises.push(uc as Promise<unknown>);\n }\n };\n\n consider(rootEl);\n rootEl.querySelectorAll('*').forEach(consider);\n return promises;\n}\n\n/**\n * Wait for custom elements under `root` to upgrade and render.\n *\n * - Awaits `customElements.whenDefined(tag)` for each custom tag (bounded).\n * - Awaits any `updateComplete` promises found (bounded).\n * - On timeout, resolves anyway and returns a warning per unresolved tag.\n * - Never blocks indefinitely. No-op when `customElements` is unavailable.\n */\nexport async function awaitCustomElementsReady(\n root: Document | Element,\n timeoutMs: number = DEFAULT_UPGRADE_TIMEOUT_MS\n): Promise<UpgradeWarning[]> {\n const warnings: UpgradeWarning[] = [];\n\n const hasCustomElements =\n typeof customElements !== 'undefined' && customElements !== null;\n\n if (!hasCustomElements) {\n return warnings;\n }\n\n const tags = collectCustomElementTags(root);\n\n // Await definitions.\n await Promise.all(\n tags.map(async tag => {\n // Already defined — nothing to wait for.\n if (customElements.get(tag)) return;\n const defined = await withTimeout(customElements.whenDefined(tag), timeoutMs);\n if (!defined) {\n warnings.push({\n tag,\n message: `Custom element \"${tag}\" did not upgrade within ${timeoutMs}ms; analysis may reflect a pre-hydration state.`,\n });\n }\n })\n );\n\n // Await render completion where components expose it (Lit et al.).\n const updateCompletables = collectUpdateCompletables(root);\n if (updateCompletables.length > 0) {\n await withTimeout(Promise.all(updateCompletables), timeoutMs);\n }\n\n return warnings;\n}\n"],"mappings":";AAcA,IAAM,6BAA6B;AAMnC,SAAS,YAAY,SAA2B,WAAqC;AACnF,SAAO,IAAI,QAAiB,aAAW;AACrC,QAAI,UAAU;AACd,UAAM,QAAQ,WAAW,MAAM;AAC7B,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF,GAAG,SAAS;AAEZ,YAAQ;AAAA,MACN,MAAM;AACJ,YAAI,CAAC,SAAS;AACZ,oBAAU;AACV,uBAAa,KAAK;AAClB,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF;AAAA,MACA,MAAM;AAEJ,YAAI,CAAC,SAAS;AACZ,oBAAU;AACV,uBAAa,KAAK;AAClB,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAMA,SAAS,yBAAyB,MAAoC;AACpE,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SACJ,qBAAqB,OAAQ,KAAkB,kBAAmB;AACpE,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAM,WAAW,CAAC,OAAgB;AAChC,QAAI,GAAG,aAAa,GAAG,UAAU,SAAS,GAAG,GAAG;AAC9C,WAAK,IAAI,GAAG,SAAS;AAAA,IACvB;AAAA,EACF;AAEA,WAAS,MAAM;AACf,QAAM,MAAM,OAAO,iBAAiB,GAAG;AACvC,MAAI,QAAQ,QAAQ;AAEpB,SAAO,MAAM,KAAK,IAAI;AACxB;AAKA,SAAS,0BAA0B,MAA8C;AAC/E,QAAM,SACJ,qBAAqB,OAAQ,KAAkB,kBAAmB;AACpE,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAM,WAA+B,CAAC;AACtC,QAAM,WAAW,CAAC,OAAgB;AAChC,UAAM,KAAM,GAA+C;AAC3D,QAAI,MAAM,OAAQ,GAAwB,SAAS,YAAY;AAC7D,eAAS,KAAK,EAAsB;AAAA,IACtC;AAAA,EACF;AAEA,WAAS,MAAM;AACf,SAAO,iBAAiB,GAAG,EAAE,QAAQ,QAAQ;AAC7C,SAAO;AACT;AAUA,eAAsB,yBACpB,MACA,YAAoB,4BACO;AAC3B,QAAM,WAA6B,CAAC;AAEpC,QAAM,oBACJ,OAAO,mBAAmB,eAAe,mBAAmB;AAE9D,MAAI,CAAC,mBAAmB;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,yBAAyB,IAAI;AAG1C,QAAM,QAAQ;AAAA,IACZ,KAAK,IAAI,OAAM,QAAO;AAEpB,UAAI,eAAe,IAAI,GAAG,EAAG;AAC7B,YAAM,UAAU,MAAM,YAAY,eAAe,YAAY,GAAG,GAAG,SAAS;AAC5E,UAAI,CAAC,SAAS;AACZ,iBAAS,KAAK;AAAA,UACZ;AAAA,UACA,SAAS,mBAAmB,GAAG,4BAA4B,SAAS;AAAA,QACtE,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,qBAAqB,0BAA0B,IAAI;AACzD,MAAI,mBAAmB,SAAS,GAAG;AACjC,UAAM,YAAY,QAAQ,IAAI,kBAAkB,GAAG,SAAS;AAAA,EAC9D;AAEA,SAAO;AACT;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1074,17 +1074,54 @@ function processChildNode(node, children, warnings) {
|
|
|
1074
1074
|
}
|
|
1075
1075
|
}
|
|
1076
1076
|
function collectChildrenFromRolelessElement(element, warnings) {
|
|
1077
|
+
return collectAccessibleChildren(element, warnings);
|
|
1078
|
+
}
|
|
1079
|
+
function collectAccessibleChildren(element, warnings) {
|
|
1077
1080
|
const children = [];
|
|
1078
1081
|
if (element.shadowRoot) {
|
|
1079
1082
|
for (const child of Array.from(element.shadowRoot.childNodes)) {
|
|
1080
|
-
|
|
1083
|
+
processShadowNode(child, children, warnings);
|
|
1081
1084
|
}
|
|
1085
|
+
return children;
|
|
1086
|
+
}
|
|
1087
|
+
if (element.localName && element.localName.includes("-") && element.childNodes.length === 0) {
|
|
1088
|
+
warnings.push({
|
|
1089
|
+
message: `Custom element <${element.localName}> has no accessible children and may have a closed shadow root; its content could not be analyzed.`,
|
|
1090
|
+
element
|
|
1091
|
+
});
|
|
1082
1092
|
}
|
|
1083
1093
|
for (const child of Array.from(element.childNodes)) {
|
|
1084
1094
|
processChildNode(child, children, warnings);
|
|
1085
1095
|
}
|
|
1086
1096
|
return children;
|
|
1087
1097
|
}
|
|
1098
|
+
function processShadowNode(node, children, warnings) {
|
|
1099
|
+
if (node.nodeType === 1) {
|
|
1100
|
+
const element = node;
|
|
1101
|
+
if (element.localName === "slot") {
|
|
1102
|
+
const slot = element;
|
|
1103
|
+
let assigned = [];
|
|
1104
|
+
if (typeof slot.assignedNodes === "function") {
|
|
1105
|
+
try {
|
|
1106
|
+
assigned = Array.from(slot.assignedNodes({ flatten: true }));
|
|
1107
|
+
} catch {
|
|
1108
|
+
assigned = [];
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (assigned.length > 0) {
|
|
1112
|
+
for (const assignedNode of assigned) {
|
|
1113
|
+
processChildNode(assignedNode, children, warnings);
|
|
1114
|
+
}
|
|
1115
|
+
} else {
|
|
1116
|
+
for (const child of Array.from(slot.childNodes)) {
|
|
1117
|
+
processShadowNode(child, children, warnings);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
processChildNode(node, children, warnings);
|
|
1124
|
+
}
|
|
1088
1125
|
function buildAccessibilityTree(rootElement, sourceHash) {
|
|
1089
1126
|
const warnings = [];
|
|
1090
1127
|
if (isHidden(rootElement)) {
|
|
@@ -1177,15 +1214,7 @@ function buildNodeRecursive(element, warnings) {
|
|
|
1177
1214
|
element: w.element
|
|
1178
1215
|
})));
|
|
1179
1216
|
const focusInfo = extractFocusInfo(element);
|
|
1180
|
-
const children =
|
|
1181
|
-
if (element.shadowRoot) {
|
|
1182
|
-
for (const child of Array.from(element.shadowRoot.childNodes)) {
|
|
1183
|
-
processChildNode(child, children, warnings);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
for (const child of Array.from(element.childNodes)) {
|
|
1187
|
-
processChildNode(child, children, warnings);
|
|
1188
|
-
}
|
|
1217
|
+
const children = collectAccessibleChildren(element, warnings);
|
|
1189
1218
|
const node = {
|
|
1190
1219
|
role: roleResult.role,
|
|
1191
1220
|
name: nameResult.name,
|
|
@@ -1198,15 +1227,7 @@ function buildNodeRecursive(element, warnings) {
|
|
|
1198
1227
|
return node;
|
|
1199
1228
|
}
|
|
1200
1229
|
function createGenericContainer(rootElement, warnings) {
|
|
1201
|
-
const children =
|
|
1202
|
-
if (rootElement.shadowRoot) {
|
|
1203
|
-
for (const child of Array.from(rootElement.shadowRoot.childNodes)) {
|
|
1204
|
-
processChildNode(child, children, warnings);
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
for (const child of Array.from(rootElement.childNodes)) {
|
|
1208
|
-
processChildNode(child, children, warnings);
|
|
1209
|
-
}
|
|
1230
|
+
const children = collectAccessibleChildren(rootElement, warnings);
|
|
1210
1231
|
return {
|
|
1211
1232
|
role: "generic",
|
|
1212
1233
|
name: "",
|