@a11y-pulse/tab-orchestrator 0.3.0 → 0.5.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/LICENSE.md +21 -166
- package/README.md +9 -12
- package/dist/adaptor.d.ts +6 -8
- package/dist/adaptors/puppeteer.js +13 -9
- package/dist/adaptors/puppeteer.js.map +1 -1
- package/dist/audit-scaffold.d.ts +6 -7
- package/dist/browser-scripts.d.ts +31 -37
- package/dist/capture-screenshot.d.ts +2 -2
- package/dist/clip.d.ts +3 -3
- package/dist/context-signals.d.ts +3 -4
- package/dist/get-selector.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +39 -88
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/unfocused-pair.d.ts +2 -2
- package/package.json +6 -6
package/LICENSE.md
CHANGED
|
@@ -1,166 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
to
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
License](#changes-and-new-works-license).
|
|
23
|
-
|
|
24
|
-
## Distribution License
|
|
25
|
-
|
|
26
|
-
The licensor grants you an additional copyright license
|
|
27
|
-
to distribute copies of the software. Your license
|
|
28
|
-
to distribute covers distributing the software with
|
|
29
|
-
changes and new works permitted by [Changes and New Works
|
|
30
|
-
License](#changes-and-new-works-license).
|
|
31
|
-
|
|
32
|
-
## Notices
|
|
33
|
-
|
|
34
|
-
You must ensure that anyone who gets a copy of any part of
|
|
35
|
-
the software from you also gets a copy of these terms or the
|
|
36
|
-
URL for them above, as well as copies of any plain-text lines
|
|
37
|
-
beginning with `Required Notice:` that the licensor provided
|
|
38
|
-
with the software. For example:
|
|
39
|
-
|
|
40
|
-
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
41
|
-
|
|
42
|
-
## Changes and New Works License
|
|
43
|
-
|
|
44
|
-
The licensor grants you an additional copyright license to
|
|
45
|
-
make changes and new works based on the software for any
|
|
46
|
-
permitted purpose.
|
|
47
|
-
|
|
48
|
-
## Patent License
|
|
49
|
-
|
|
50
|
-
The licensor grants you a patent license for the software that
|
|
51
|
-
covers patent claims the licensor can license, or becomes able
|
|
52
|
-
to license, that you would infringe by using the software.
|
|
53
|
-
|
|
54
|
-
## Noncompete
|
|
55
|
-
|
|
56
|
-
Any purpose is a permitted purpose, except for providing any
|
|
57
|
-
product that competes with the software or any product the
|
|
58
|
-
licensor or any of its affiliates provides using the software.
|
|
59
|
-
|
|
60
|
-
## Competition
|
|
61
|
-
|
|
62
|
-
Goods and services compete even when they provide functionality
|
|
63
|
-
through different kinds of interfaces or for different technical
|
|
64
|
-
platforms. Applications can compete with services, libraries
|
|
65
|
-
with plugins, frameworks with development tools, and so on,
|
|
66
|
-
even if they're written in different programming languages
|
|
67
|
-
or for different computer architectures. Goods and services
|
|
68
|
-
compete even when provided free of charge. If you market a
|
|
69
|
-
product as a practical substitute for the software or another
|
|
70
|
-
product, it definitely competes.
|
|
71
|
-
|
|
72
|
-
## New Products
|
|
73
|
-
|
|
74
|
-
If you are using the software to provide a product that does
|
|
75
|
-
not compete, but the licensor or any of its affiliates brings
|
|
76
|
-
your product into competition by providing a new version of
|
|
77
|
-
the software or another product using the software, you may
|
|
78
|
-
continue using versions of the software available under these
|
|
79
|
-
terms beforehand to provide your competing product, but not
|
|
80
|
-
any later versions.
|
|
81
|
-
|
|
82
|
-
## Discontinued Products
|
|
83
|
-
|
|
84
|
-
You may begin using the software to compete with a product
|
|
85
|
-
or service that the licensor or any of its affiliates has
|
|
86
|
-
stopped providing, unless the licensor includes a plain-text
|
|
87
|
-
line beginning with `Licensor Line of Business:` with the
|
|
88
|
-
software that mentions that line of business. For example:
|
|
89
|
-
|
|
90
|
-
> Licensor Line of Business: YoyodyneCMS Content Management
|
|
91
|
-
System (http://example.com/cms)
|
|
92
|
-
|
|
93
|
-
## Sales of Business
|
|
94
|
-
|
|
95
|
-
If the licensor or any of its affiliates sells a line of
|
|
96
|
-
business developing the software or using the software
|
|
97
|
-
to provide a product, the buyer can also enforce
|
|
98
|
-
[Noncompete](#noncompete) for that product.
|
|
99
|
-
|
|
100
|
-
## Fair Use
|
|
101
|
-
|
|
102
|
-
You may have "fair use" rights for the software under the
|
|
103
|
-
law. These terms do not limit them.
|
|
104
|
-
|
|
105
|
-
## No Other Rights
|
|
106
|
-
|
|
107
|
-
These terms do not allow you to sublicense or transfer any of
|
|
108
|
-
your licenses to anyone else, or prevent the licensor from
|
|
109
|
-
granting licenses to anyone else. These terms do not imply
|
|
110
|
-
any other licenses.
|
|
111
|
-
|
|
112
|
-
## Patent Defense
|
|
113
|
-
|
|
114
|
-
If you make any written claim that the software infringes or
|
|
115
|
-
contributes to infringement of any patent, your patent license
|
|
116
|
-
for the software granted under these terms ends immediately. If
|
|
117
|
-
your company makes such a claim, your patent license ends
|
|
118
|
-
immediately for work on behalf of your company.
|
|
119
|
-
|
|
120
|
-
## Violations
|
|
121
|
-
|
|
122
|
-
The first time you are notified in writing that you have
|
|
123
|
-
violated any of these terms, or done anything with the software
|
|
124
|
-
not covered by your licenses, your licenses can nonetheless
|
|
125
|
-
continue if you come into full compliance with these terms,
|
|
126
|
-
and take practical steps to correct past violations, within
|
|
127
|
-
32 days of receiving notice. Otherwise, all your licenses
|
|
128
|
-
end immediately.
|
|
129
|
-
|
|
130
|
-
## No Liability
|
|
131
|
-
|
|
132
|
-
***As far as the law allows, the software comes as is, without
|
|
133
|
-
any warranty or condition, and the licensor will not be liable
|
|
134
|
-
to you for any damages arising out of these terms or the use
|
|
135
|
-
or nature of the software, under any kind of legal claim.***
|
|
136
|
-
|
|
137
|
-
## Definitions
|
|
138
|
-
|
|
139
|
-
The **licensor** is the individual or entity offering these
|
|
140
|
-
terms, and the **software** is the software the licensor makes
|
|
141
|
-
available under these terms.
|
|
142
|
-
|
|
143
|
-
A **product** can be a good or service, or a combination
|
|
144
|
-
of them.
|
|
145
|
-
|
|
146
|
-
**You** refers to the individual or entity agreeing to these
|
|
147
|
-
terms.
|
|
148
|
-
|
|
149
|
-
**Your company** is any legal entity, sole proprietorship,
|
|
150
|
-
or other kind of organization that you work for, plus all
|
|
151
|
-
its affiliates.
|
|
152
|
-
|
|
153
|
-
**Affiliates** means the other organizations than an
|
|
154
|
-
organization has control over, is under the control of, or is
|
|
155
|
-
under common control with.
|
|
156
|
-
|
|
157
|
-
**Control** means ownership of substantially all the assets of
|
|
158
|
-
an entity, or the power to direct its management and policies
|
|
159
|
-
by vote, contract, or otherwise. Control can be direct or
|
|
160
|
-
indirect.
|
|
161
|
-
|
|
162
|
-
**Your licenses** are all the licenses granted to you for the
|
|
163
|
-
software under these terms.
|
|
164
|
-
|
|
165
|
-
**Use** means anything you do with the software requiring one
|
|
166
|
-
of your licenses.
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present, A11y Pulse (https://www.a11ypulse.com/)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@a11y-pulse/tab-orchestrator)
|
|
4
4
|
[](https://github.com/A11y-Pulse/audits/actions/workflows/ci.yml)
|
|
5
|
-
[](./LICENSE.md)
|
|
6
6
|
|
|
7
|
-
A shared Tab-session runner for A11y Pulse's keyboard-driven accessibility audits. It drives a page through its focusable elements once
|
|
7
|
+
A shared Tab-session runner for A11y Pulse's keyboard-driven accessibility audits. It drives a page through its focusable elements once (pressing Tab, tracking visited elements, capturing screenshots and styles on demand) while one or more **consumers** each score the tab stops for their own WCAG success criterion. This lets audits like [`@a11y-pulse/focus-appearance-audit`](../focus-appearance-audit) (WCAG 2.4.7) share a single tab loop with sibling audits instead of each re-tabbing the page from scratch.
|
|
8
8
|
|
|
9
9
|
It is not an audit itself: it has no opinion on what "passing" means. It only owns the mechanics of moving focus, tracking cycle completion, and capturing the primitives (computed styles, clipped screenshots, unfocused/focused pairs) that consumers need.
|
|
10
10
|
|
|
11
|
-
This package was developed by [A11y Pulse](https://www.a11ypulse.com/) for its accessibility monitoring service. It is released
|
|
11
|
+
This package was developed by [A11y Pulse](https://www.a11ypulse.com/) for its accessibility monitoring service. It is released under the [MIT License](#license).
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -35,9 +35,9 @@ await orchestrator.run();
|
|
|
35
35
|
- `.attach(consumer)` registers a `TabConsumer`. Attaching after `run()` has started throws.
|
|
36
36
|
- `.run()` presses Tab repeatedly, dispatching each `TabStopSnapshot` to every still-attached consumer, until either a full tab cycle completes, focus is lost, navigation happens, or every consumer has disconnected. Calling it twice throws; calling it with zero attached consumers returns immediately without tabbing.
|
|
37
37
|
|
|
38
|
-
Each consumer declares the `capabilities` it needs (e.g. `baselineStyles`, `unfocusedPair`) and can disconnect independently once it has what it needs (say, after hitting its own element limit)
|
|
38
|
+
Each consumer declares the `capabilities` it needs (e.g. `baselineStyles`, `unfocusedPair`) and can disconnect independently once it has what it needs (say, after hitting its own element limit). The orchestrator keeps driving the remaining consumers. Per-stop work like unfocused-pair screenshots is only captured if a still-attached consumer actually asks for it that stop.
|
|
39
39
|
|
|
40
|
-
Most callers won't build a `TabConsumer` by hand
|
|
40
|
+
Most callers won't build a `TabConsumer` by hand. Audit packages export a `createXAudit(options)` helper that returns one, plus a `runXAudit(adaptor, options)` convenience wrapper that builds a private single-consumer orchestrator for you. See [`@a11y-pulse/focus-appearance-audit`'s "Shared tab session"](../focus-appearance-audit#shared-tab-session) section for a worked example.
|
|
41
41
|
|
|
42
42
|
## `BrowserAdaptor`
|
|
43
43
|
|
|
@@ -50,7 +50,7 @@ The orchestrator drives a page through an **adaptor**: a small interface of prim
|
|
|
50
50
|
| `disposeRef(ref)` | Releases a handle previously returned by `evaluateHandle`. |
|
|
51
51
|
| `pressTab()` | Presses the Tab key, advancing focus to the next focusable element. |
|
|
52
52
|
| `screenshotClip(clip)` | Screenshots a clipped region of the page (`{ x, y, width, height }`) and returns PNG bytes. |
|
|
53
|
-
| `ensureFocusReporting()` | Ensures the page reports focus for its lifetime
|
|
53
|
+
| `ensureFocusReporting()` | Ensures the page reports focus for its lifetime, in particular that `document.hasFocus()` works and `:focus` styles apply, even when the page is not the foreground tab/window. Must not throw. |
|
|
54
54
|
|
|
55
55
|
The orchestrator is the only thing that mutates the page through this adaptor during a session; consumers score snapshots, they don't call `pressTab`, take screenshots, or install observers themselves.
|
|
56
56
|
|
|
@@ -84,10 +84,7 @@ Trusted Publisher on npm must stay configured for:
|
|
|
84
84
|
|
|
85
85
|
## License
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
[MIT](./LICENSE.md). Use it however you like, including in commercial and competing products.
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- **Competing products are forbidden.** You may not use this software (or a modified version of it) to build a product or service that competes with A11y Pulse's accessibility monitoring offering.
|
|
92
|
-
|
|
93
|
-
See [LICENSE.md](./LICENSE.md) for the full, binding terms.
|
|
89
|
+
The audit packages in this repository are licensed separately, under the
|
|
90
|
+
[PolyForm Shield License 1.0.0](../../LICENSE.md).
|
package/dist/adaptor.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export type Rect = {
|
|
|
9
9
|
*/
|
|
10
10
|
export type ElementRef = unknown;
|
|
11
11
|
/**
|
|
12
|
-
* A framework-specific adaptor that provides the primitives needed by the audit. An adaptor wraps
|
|
13
|
-
*
|
|
12
|
+
* A framework-specific adaptor that provides the primitives needed by the audit. An adaptor wraps a
|
|
13
|
+
* single page in a web browser.
|
|
14
14
|
*/
|
|
15
15
|
export interface BrowserAdaptor {
|
|
16
16
|
/**
|
|
@@ -30,10 +30,9 @@ export interface BrowserAdaptor {
|
|
|
30
30
|
*/
|
|
31
31
|
pressTab(): Promise<void>;
|
|
32
32
|
/**
|
|
33
|
-
* Screenshot a clipped region of the page. `scale` is the device scale
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* replace it). The caller is responsible for the page being at a known
|
|
33
|
+
* Screenshot a clipped region of the page. `scale` is the device scale factor (bitmap pixels per
|
|
34
|
+
* CSS pixel), multiplied against whatever deviceScaleFactor the page itself currently has
|
|
35
|
+
* (Puppeteer does not replace it). The caller is responsible for the page being at a known
|
|
37
36
|
* deviceScaleFactor before invoking this.
|
|
38
37
|
*/
|
|
39
38
|
screenshotClip(clip: Rect, scale?: number): Promise<Uint8Array>;
|
|
@@ -41,8 +40,7 @@ export interface BrowserAdaptor {
|
|
|
41
40
|
readonly screenshotClipScale?: number;
|
|
42
41
|
/**
|
|
43
42
|
* Ensure the page reports focus for its lifetime. In particular, `document.hasFocus()` must
|
|
44
|
-
* function correctly and :focus styles must be applied, even when the page is not the
|
|
45
|
-
* foreground.
|
|
43
|
+
* function correctly and :focus styles must be applied, even when the page is not the foreground.
|
|
46
44
|
*
|
|
47
45
|
* This function must not throw.
|
|
48
46
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/adaptors/puppeteer.ts
|
|
2
|
-
var
|
|
2
|
+
var focusEmulationSessions = /* @__PURE__ */ new WeakMap();
|
|
3
3
|
var PuppeteerAdaptor = class {
|
|
4
4
|
constructor(page) {
|
|
5
5
|
this.page = page;
|
|
@@ -29,20 +29,24 @@ var PuppeteerAdaptor = class {
|
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
async ensureFocusReporting() {
|
|
32
|
-
if (focusEmulationEnabled.has(this.page)) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
32
|
try {
|
|
33
|
+
const existing = focusEmulationSessions.get(this.page);
|
|
34
|
+
if (existing) {
|
|
35
|
+
await existing.send("Emulation.setFocusEmulationEnabled", {
|
|
36
|
+
enabled: false
|
|
37
|
+
});
|
|
38
|
+
await existing.send("Emulation.setFocusEmulationEnabled", {
|
|
39
|
+
enabled: true
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
36
43
|
const client = await this.page.createCDPSession();
|
|
37
44
|
await client.send("Emulation.setFocusEmulationEnabled", {
|
|
38
45
|
enabled: true
|
|
39
46
|
});
|
|
40
|
-
|
|
47
|
+
focusEmulationSessions.set(this.page, client);
|
|
41
48
|
} catch (error) {
|
|
42
|
-
console.warn(
|
|
43
|
-
"Could not enable focus emulation for the tab orchestrator",
|
|
44
|
-
{ error }
|
|
45
|
-
);
|
|
49
|
+
console.warn("Could not enable focus emulation for the tab orchestrator", { error });
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
52
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adaptors/puppeteer.ts"],"sourcesContent":["import type { JSHandle, Page } from \"puppeteer\";\nimport type { BrowserAdaptor, ElementRef, Rect } from \"../adaptor\";\n\n//
|
|
1
|
+
{"version":3,"sources":["../../src/adaptors/puppeteer.ts"],"sourcesContent":["import type { CDPSession, JSHandle, Page } from \"puppeteer\";\nimport type { BrowserAdaptor, ElementRef, Rect } from \"../adaptor\";\n\n// The CDP session holding focus emulation for each page. A fresh adaptor is created per audit run,\n// but a page often outlives one run, so without this each run would open another CDP session that\n// is never detached. The session is kept attached for the page's lifetime: Chrome clears the\n// emulation when the CDP client disconnects.\nconst focusEmulationSessions = new WeakMap<Page, CDPSession>();\n\n/** A BrowserAdaptor backed by a Puppeteer Page. */\nexport class PuppeteerAdaptor implements BrowserAdaptor {\n\treadonly screenshotClipScale = 2;\n\n\tconstructor(private readonly page: Page) {}\n\n\tevaluate<T>(\n\t\t// biome-ignore lint/suspicious/noExplicitAny: the page-evaluated fn accepts arbitrary serialised args and element handles.\n\t\tfn: (...args: any[]) => T | Promise<T>,\n\t\t...args: unknown[]\n\t): Promise<T> {\n\t\t// Puppeteer resolves any JSHandle passed as an arg to the live element.\n\t\treturn this.page.evaluate(fn as never, ...(args as never[])) as Promise<T>;\n\t}\n\n\tevaluateHandle(fn: () => Element | null): Promise<ElementRef> {\n\t\treturn this.page.evaluateHandle(fn);\n\t}\n\n\tasync disposeRef(ref: ElementRef): Promise<void> {\n\t\tawait (ref as JSHandle).dispose();\n\t}\n\n\tasync pressTab(): Promise<void> {\n\t\tawait this.page.keyboard.press(\"Tab\");\n\t}\n\n\tasync screenshotClip(clip: Rect, scale = 1): Promise<Uint8Array> {\n\t\treturn (await this.page.screenshot({\n\t\t\ttype: \"png\",\n\t\t\toptimizeForSpeed: true,\n\t\t\tclip: {\n\t\t\t\t...clip,\n\t\t\t\tscale,\n\t\t\t},\n\t\t})) as Uint8Array;\n\t}\n\n\tasync ensureFocusReporting(): Promise<void> {\n\t\t// Pages only report focus while they are the foreground tab. Since this browser instance is\n\t\t// likely running in the background, we need to enable focus emulation to get accurate results.\n\t\t//\n\t\t// Note this function does not throw if enabling emulation fails; it is a best-effort.\n\t\ttry {\n\t\t\tconst existing = focusEmulationSessions.get(this.page);\n\n\t\t\tif (existing) {\n\t\t\t\t// Chromium ignores a redundant enable, so re-asserting has to toggle.\n\t\t\t\tawait existing.send(\"Emulation.setFocusEmulationEnabled\", {\n\t\t\t\t\tenabled: false,\n\t\t\t\t});\n\t\t\t\tawait existing.send(\"Emulation.setFocusEmulationEnabled\", {\n\t\t\t\t\tenabled: true,\n\t\t\t\t});\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst client = await this.page.createCDPSession();\n\t\t\tawait client.send(\"Emulation.setFocusEmulationEnabled\", {\n\t\t\t\tenabled: true,\n\t\t\t});\n\t\t\tfocusEmulationSessions.set(this.page, client);\n\t\t} catch (error) {\n\t\t\tconsole.warn(\"Could not enable focus emulation for the tab orchestrator\", { error });\n\t\t}\n\t}\n}\n"],"mappings":";AAOA,IAAM,yBAAyB,oBAAI,QAA0B;AAGtD,IAAM,mBAAN,MAAiD;AAAA,EAGvD,YAA6B,MAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA,EAFpB,sBAAsB;AAAA,EAI/B,SAEC,OACG,MACU;AAEb,WAAO,KAAK,KAAK,SAAS,IAAa,GAAI,IAAgB;AAAA,EAC5D;AAAA,EAEA,eAAe,IAA+C;AAC7D,WAAO,KAAK,KAAK,eAAe,EAAE;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,KAAgC;AAChD,UAAO,IAAiB,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,WAA0B;AAC/B,UAAM,KAAK,KAAK,SAAS,MAAM,KAAK;AAAA,EACrC;AAAA,EAEA,MAAM,eAAe,MAAY,QAAQ,GAAwB;AAChE,WAAQ,MAAM,KAAK,KAAK,WAAW;AAAA,MAClC,MAAM;AAAA,MACN,kBAAkB;AAAA,MAClB,MAAM;AAAA,QACL,GAAG;AAAA,QACH;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,uBAAsC;AAK3C,QAAI;AACH,YAAM,WAAW,uBAAuB,IAAI,KAAK,IAAI;AAErD,UAAI,UAAU;AAEb,cAAM,SAAS,KAAK,sCAAsC;AAAA,UACzD,SAAS;AAAA,QACV,CAAC;AACD,cAAM,SAAS,KAAK,sCAAsC;AAAA,UACzD,SAAS;AAAA,QACV,CAAC;AAED;AAAA,MACD;AAEA,YAAM,SAAS,MAAM,KAAK,KAAK,iBAAiB;AAChD,YAAM,OAAO,KAAK,sCAAsC;AAAA,QACvD,SAAS;AAAA,MACV,CAAC;AACD,6BAAuB,IAAI,KAAK,MAAM,MAAM;AAAA,IAC7C,SAAS,OAAO;AACf,cAAQ,KAAK,6DAA6D,EAAE,MAAM,CAAC;AAAA,IACpF;AAAA,EACD;AACD;","names":[]}
|
package/dist/audit-scaffold.d.ts
CHANGED
|
@@ -22,13 +22,13 @@ export type BaseAuditSummary = {
|
|
|
22
22
|
/** True if the audit stopped early after hitting `failedElementLimit`. */
|
|
23
23
|
reachedFailedElementLimit: boolean;
|
|
24
24
|
/**
|
|
25
|
-
* True if the audit returned early because `timeout` elapsed. The results
|
|
26
|
-
*
|
|
25
|
+
* True if the audit returned early because `timeout` elapsed. The results are whatever had been
|
|
26
|
+
* gathered when the deadline hit.
|
|
27
27
|
*/
|
|
28
28
|
timedOut: boolean;
|
|
29
29
|
/**
|
|
30
|
-
* Why the tab session ended, or `null` when this consumer disconnected
|
|
31
|
-
*
|
|
30
|
+
* Why the tab session ended, or `null` when this consumer disconnected itself (element limit,
|
|
31
|
+
* failed-element limit, or timeout).
|
|
32
32
|
*/
|
|
33
33
|
sessionEnd: SessionEndReason | null;
|
|
34
34
|
};
|
|
@@ -43,8 +43,7 @@ export type AuditSelfDisconnect = {
|
|
|
43
43
|
clear(): void;
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
|
-
* Arms an optional self-disconnecting timeout and tracks whether this
|
|
47
|
-
*
|
|
48
|
-
* apart from an external end.
|
|
46
|
+
* Arms an optional self-disconnecting timeout and tracks whether this consumer initiated its own
|
|
47
|
+
* disconnect, so `onSessionEnd` can tell that apart from an external end.
|
|
49
48
|
*/
|
|
50
49
|
export declare function createAuditSelfDisconnect(): AuditSelfDisconnect;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* IMPORTANT: Functions in this file are serialized and injected into the audited page, so they
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* IMPORTANT: Functions in this file are serialized and injected into the audited page, so they must
|
|
3
|
+
* not reference any symbols outside their own scope. This also means they cannot share code, so any
|
|
4
|
+
* common logic (like descending into shadow roots) must be duplicated.
|
|
5
5
|
*/
|
|
6
6
|
import type { Rect } from "./adaptor";
|
|
7
7
|
import type { StyleSnapshot } from "./types";
|
|
@@ -30,9 +30,9 @@ export type ActiveElementBase = {
|
|
|
30
30
|
index: number | null;
|
|
31
31
|
isBody: boolean;
|
|
32
32
|
/**
|
|
33
|
-
* The focused element is an <iframe>. Tabbing into a frame passes focus into
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* The focused element is an <iframe>. Tabbing into a frame passes focus into its embedded
|
|
34
|
+
* document, but the parent's document.activeElement is the frame element itself, so the loop uses
|
|
35
|
+
* this to skip the frame as a tab stop.
|
|
36
36
|
*/
|
|
37
37
|
isIframe: boolean;
|
|
38
38
|
html: string;
|
|
@@ -40,9 +40,8 @@ export type ActiveElementBase = {
|
|
|
40
40
|
rect: Rect;
|
|
41
41
|
};
|
|
42
42
|
/**
|
|
43
|
-
* Read the currently focused element (descending open shadow roots), returning
|
|
44
|
-
*
|
|
45
|
-
* styles, and page-relative rect.
|
|
43
|
+
* Read the currently focused element (descending open shadow roots), returning its marker index,
|
|
44
|
+
* opening-tag HTML (marker attribute stripped), focus-relevant styles, and page-relative rect.
|
|
46
45
|
*/
|
|
47
46
|
export declare function probeActiveElementScript(props: string[], markerAttr: string): ActiveElementBase;
|
|
48
47
|
export declare function activeElementHandleScript(): Element | null;
|
|
@@ -52,8 +51,8 @@ export declare function pageDimensionsScript(): {
|
|
|
52
51
|
};
|
|
53
52
|
export declare function elementRectScript(el: Element | null): Rect;
|
|
54
53
|
/**
|
|
55
|
-
* Whether something unrelated (e.g. a fixed cookie banner) covers the element's centre point, so
|
|
56
|
-
*
|
|
54
|
+
* Whether something unrelated (e.g. a fixed cookie banner) covers the element's centre point, so a
|
|
55
|
+
* screenshot of the element's box would show the covering element instead.
|
|
57
56
|
*/
|
|
58
57
|
export declare function isCenterObscuredScript(el: Element | null): boolean;
|
|
59
58
|
/**
|
|
@@ -61,26 +60,18 @@ export declare function isCenterObscuredScript(el: Element | null): boolean;
|
|
|
61
60
|
* afterwards isn't captured mid-animation.
|
|
62
61
|
*/
|
|
63
62
|
export declare function scrollToCenterScript(el: Element | null): void;
|
|
64
|
-
/**
|
|
65
|
-
* Blur (unfocus) an element
|
|
66
|
-
*/
|
|
67
63
|
export declare function blurScript(el: Element | null): void;
|
|
68
|
-
/**
|
|
69
|
-
* Focus an element
|
|
70
|
-
*/
|
|
71
64
|
export declare function focusScript(el: Element | null): void;
|
|
72
65
|
/**
|
|
73
|
-
* Read focus-relevant computed styles from a given element. Unlike
|
|
74
|
-
*
|
|
75
|
-
* still works after the node has been blurred.
|
|
66
|
+
* Read focus-relevant computed styles from a given element. Unlike `probeActiveElementScript`, this
|
|
67
|
+
* does not use `document.activeElement`, so it still works after the node has been blurred.
|
|
76
68
|
*/
|
|
77
69
|
export declare function elementStylesScript(el: Element | null, props: string[]): StyleSnapshot;
|
|
78
70
|
/**
|
|
79
|
-
* Remove the marker attribute from all elements, blur the active element, and
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* ends.
|
|
71
|
+
* Remove the marker attribute from all elements, blur the active element, and scroll back to the
|
|
72
|
+
* top. This is a best-effort attempt to reset state between audits: the tab loop scrolls later
|
|
73
|
+
* elements into view as it walks the page (see scrollToCenterScript), and nothing else undoes that
|
|
74
|
+
* once the session ends.
|
|
84
75
|
*/
|
|
85
76
|
export declare function clearMarkersScript(markerAttr: string): void;
|
|
86
77
|
export type MeasureObscuringResult = {
|
|
@@ -93,9 +84,9 @@ export type MeasureObscuringResult = {
|
|
|
93
84
|
hasObscurer: boolean;
|
|
94
85
|
};
|
|
95
86
|
/**
|
|
96
|
-
* Hit-test whether author-created content entirely hides the focused element.
|
|
97
|
-
*
|
|
98
|
-
*
|
|
87
|
+
* Hit-test whether author-created content entirely hides the focused element. Marks a single
|
|
88
|
+
* covering element with `obscurerAttr` when containment confirms a full cover, so the host can
|
|
89
|
+
* resolve its selector via getSelector.
|
|
99
90
|
*/
|
|
100
91
|
export declare function measureObscuringScript(el: Element | null, obscurerAttr: string): MeasureObscuringResult;
|
|
101
92
|
/** Return the element marked as the obscurer, if any. */
|
|
@@ -116,8 +107,8 @@ declare global {
|
|
|
116
107
|
}
|
|
117
108
|
}
|
|
118
109
|
/**
|
|
119
|
-
* Install once: wrap window.open (record + inert stub), capture-phase submit
|
|
120
|
-
*
|
|
110
|
+
* Install once: wrap window.open (record + inert stub), capture-phase submit (record +
|
|
111
|
+
* preventDefault), track focusin and soft URL changes.
|
|
121
112
|
*/
|
|
122
113
|
export declare function installContextObserverScript(): void;
|
|
123
114
|
export type DrainContextObserverResult = {
|
|
@@ -132,20 +123,23 @@ export type DrainContextObserverResult = {
|
|
|
132
123
|
hasAttributed: boolean;
|
|
133
124
|
};
|
|
134
125
|
/**
|
|
135
|
-
* Drain observer signals for the current tab stop and reset per-stop flags.
|
|
136
|
-
*
|
|
137
|
-
*
|
|
126
|
+
* Drain observer signals for the current tab stop and reset per-stop flags. Classification of focus
|
|
127
|
+
* removal / redirection uses the post-Tab settle activeElement and the focusin history from this
|
|
128
|
+
* stop only.
|
|
138
129
|
*/
|
|
139
130
|
export declare function drainContextObserverScript(markerAttr: string): DrainContextObserverResult;
|
|
140
|
-
/**
|
|
141
|
-
*
|
|
131
|
+
/**
|
|
132
|
+
* Return the element marked as attributed by drainContextObserverScript (the element that received
|
|
133
|
+
* a focus event this stop and then lost it), if any.
|
|
134
|
+
*/
|
|
142
135
|
export declare function attributedHandleScript(): Element | null;
|
|
143
136
|
export declare function clearAttributedScript(): void;
|
|
144
137
|
/**
|
|
145
|
-
* Drop focusin history accumulated after drain (e.g. pixel-diff blur/refocus)
|
|
146
|
-
*
|
|
138
|
+
* Drop focusin history accumulated after drain (e.g. pixel-diff blur/refocus) so the next tab stop
|
|
139
|
+
* does not mis-attribute F55 or redirects.
|
|
147
140
|
*/
|
|
148
141
|
export declare function clearContextFocusInsScript(): void;
|
|
149
142
|
/** Current location.href for navigation comparison in the host. */
|
|
150
143
|
export declare function locationHrefScript(): string;
|
|
144
|
+
export declare function hasFocusScript(): boolean;
|
|
151
145
|
export {};
|
|
@@ -4,7 +4,7 @@ export type CaptureScreenshotOptions = {
|
|
|
4
4
|
};
|
|
5
5
|
/**
|
|
6
6
|
* Screenshot the element `handle` currently refers to, clipped to its box plus
|
|
7
|
-
* `screenshotClipBuffer` padding. The caller owns `handle` and must dispose it
|
|
8
|
-
*
|
|
7
|
+
* `screenshotClipBuffer` padding. The caller owns `handle` and must dispose it after this promise
|
|
8
|
+
* settles.
|
|
9
9
|
*/
|
|
10
10
|
export declare function captureScreenshot(adaptor: BrowserAdaptor, options: CaptureScreenshotOptions, handle: ElementRef): Promise<Uint8Array>;
|
package/dist/clip.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Rect } from "./adaptor";
|
|
2
2
|
/**
|
|
3
|
-
* A screenshot clip framing `rect` with up to `buffer` pixels of padding on each side, shrunk
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* A screenshot clip framing `rect` with up to `buffer` pixels of padding on each side, shrunk where
|
|
4
|
+
* the page edges leave less room. The padding allows for indicators drawn just outside the element
|
|
5
|
+
* box (outlines, shadows) and for anti-aliasing.
|
|
6
6
|
*/
|
|
7
7
|
export declare function bufferedClip(rect: Rect, pageWidth: number, pageHeight: number, buffer: number): Rect;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Whether focus destination Y is inside the subtree of intended focus X
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* same-subtree, not theft.
|
|
2
|
+
* Whether focus destination Y is inside the subtree of intended focus X (descendant or ancestor),
|
|
3
|
+
* which is legitimate delegation rather than theft. Walks across open shadow roots so focusing into
|
|
4
|
+
* a host's shadow content is same-subtree, not theft.
|
|
6
5
|
*/
|
|
7
6
|
export declare function isSameFocusSubtree(intended: Element, settled: Element): boolean;
|
package/dist/get-selector.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Mirrors axe-core's approach: each level contributes the fewest features that discriminate the
|
|
7
7
|
* element (a unique id, the rarest single class, or an :nth-of-type position), and the walk stops
|
|
8
|
-
* as soon as the joined selector matches exactly one element. Selectors stay short because of
|
|
9
|
-
*
|
|
8
|
+
* as soon as the joined selector matches exactly one element. Selectors stay short because of that
|
|
9
|
+
* early stop, not because of truncation; the length budget is only a backstop.
|
|
10
10
|
*/
|
|
11
11
|
export declare function getSelector(root: Node | null): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type { BrowserAdaptor, ElementRef, Rect } from "./adaptor";
|
|
|
2
2
|
export type { AuditSelfDisconnect, BaseAuditOptions, BaseAuditSummary, } from "./audit-scaffold";
|
|
3
3
|
export { createAuditSelfDisconnect, DEFAULT_ELEMENT_LIMIT, DEFAULT_FAILED_ELEMENT_LIMIT, DEFAULT_SCREENSHOT_SETTLE_DELAY, DEFAULT_TIMEOUT, } from "./audit-scaffold";
|
|
4
4
|
export type { ActiveElementBase, BaselinePayload } from "./browser-scripts";
|
|
5
|
-
export { activeElementHandleScript, baselineScript, blurScript, clearMarkersScript, elementRectScript, elementStylesScript, focusScript, isCenterObscuredScript, pageDimensionsScript, probeActiveElementScript, scrollToCenterScript, } from "./browser-scripts";
|
|
5
|
+
export { activeElementHandleScript, baselineScript, blurScript, clearMarkersScript, elementRectScript, elementStylesScript, focusScript, hasFocusScript, isCenterObscuredScript, pageDimensionsScript, probeActiveElementScript, scrollToCenterScript, } from "./browser-scripts";
|
|
6
6
|
export { bufferedClip } from "./clip";
|
|
7
7
|
export { FOCUS_STYLE_PROPERTIES } from "./focus-style";
|
|
8
8
|
export { getSelector } from "./get-selector";
|