@devframes/plugin-a11y 0.0.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 -0
- package/README.md +85 -0
- package/bin.mjs +13 -0
- package/dist/cli.d.mts +12 -0
- package/dist/cli.mjs +14 -0
- package/dist/client/index.d.mts +14 -0
- package/dist/client/index.mjs +14 -0
- package/dist/index.d.mts +46 -0
- package/dist/index.mjs +2 -0
- package/dist/inject/inject.js +42669 -0
- package/dist/node/index.d.mts +12 -0
- package/dist/node/index.mjs +12 -0
- package/dist/protocol-BptgJFLx.d.mts +41 -0
- package/dist/rpc/index.d.mts +130 -0
- package/dist/rpc/index.mjs +2 -0
- package/dist/rpc-C13Bq70l.mjs +71 -0
- package/dist/spa/assets/index-BWZk-954.js +2 -0
- package/dist/spa/assets/index-bpFdBjWl.css +1 -0
- package/dist/spa/index.html +14 -0
- package/dist/src-D4BUVI3M.mjs +62 -0
- package/dist/vite.d.mts +17 -0
- package/dist/vite.mjs +19 -0
- package/package.json +82 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-PRESENT Anthony Fu <https://github.com/antfu>
|
|
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
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @devframes/plugin-a11y
|
|
2
|
+
|
|
3
|
+
> [!WARNING] Experimental
|
|
4
|
+
> This plugin is experimental and may change without a major version bump until
|
|
5
|
+
> it stabilizes.
|
|
6
|
+
|
|
7
|
+
An accessibility inspector built on [devframe](../../packages/devframe). It runs
|
|
8
|
+
[axe-core](https://github.com/dequelabs/axe-core) against a host application,
|
|
9
|
+
lists the WCAG A/AA violations in a [Solid](https://www.solidjs.com/) panel, and
|
|
10
|
+
**highlights the offending element in the page when you hover a warning**.
|
|
11
|
+
|
|
12
|
+
The scan + highlight loop works the same whether the plugin runs as a live dev
|
|
13
|
+
server or as a baked static build.
|
|
14
|
+
|
|
15
|
+
## How it works
|
|
16
|
+
|
|
17
|
+
Three pieces, two of them browser-side:
|
|
18
|
+
|
|
19
|
+
| Piece | Runs in | Role |
|
|
20
|
+
|-------|---------|------|
|
|
21
|
+
| **Agent** (`src/inject`) | the host app's page | runs axe-core, broadcasts the report, draws the highlight ring |
|
|
22
|
+
| **Panel** (`src/spa`) | the devtools iframe | Solid SPA: lists violations, fires highlight/clear on hover |
|
|
23
|
+
| **Node** (`src/index.ts`, `src/node`, `src/rpc`) | the devframe backend | `get-config` RPC (impact taxonomy) — live in dev, baked in a static build |
|
|
24
|
+
|
|
25
|
+
The agent and panel talk over a same-origin
|
|
26
|
+
[`BroadcastChannel`](src/shared/protocol.ts), not the devframe RPC backend. That
|
|
27
|
+
is what keeps the live loop working in **both modes**: neither half needs a
|
|
28
|
+
server to reach the other, only a shared browser origin (host page + panel
|
|
29
|
+
iframe). devframe RPC carries the data model on top — `get-config` is a `static`
|
|
30
|
+
function, so it resolves over WebSocket in dev and from the baked dump in a
|
|
31
|
+
static build.
|
|
32
|
+
|
|
33
|
+
devframe deliberately provides no access to the host application's DOM, so the
|
|
34
|
+
agent is the author-provided bridge into the page being checked. In a hub, the
|
|
35
|
+
agent is the a11y dock's **client script**: attach `a11yAgentBundlePath` as the
|
|
36
|
+
dock's `clientScript` (resolved to an importable URL — `/@fs/…` under Vite, or a
|
|
37
|
+
statically-served path) and the hub's client runtime (`createDevframeClientHost`
|
|
38
|
+
from `@devframes/hub/client`) imports it into the host page and calls its
|
|
39
|
+
default export with the client-script context. Booted that way, the agent also
|
|
40
|
+
mirrors each scan into the hub's **messages feed** — a summary entry driven
|
|
41
|
+
through the loading → idle lifecycle plus one entry per violated rule, carrying
|
|
42
|
+
the impact-mapped level, WCAG tags as labels, and the first offending element's
|
|
43
|
+
selector and bounding box (rendered by `@devframes/plugin-messages` when the
|
|
44
|
+
hub mounts it). Both minimal hub examples do exactly this. Outside a hub, one
|
|
45
|
+
`<script type="module">` for the same bundle does the job — the demo below
|
|
46
|
+
shows it (no hub context, so the feed mirror simply stays off).
|
|
47
|
+
|
|
48
|
+
## Run the demo
|
|
49
|
+
|
|
50
|
+
The demo serves an intentionally-broken host page and the panel from **one
|
|
51
|
+
origin** so they share the channel.
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
pnpm -C plugins/a11y build # build the panel + the agent bundle
|
|
55
|
+
pnpm -C plugins/a11y demo # dev: live WebSocket RPC → http://localhost:4477/
|
|
56
|
+
|
|
57
|
+
pnpm -C plugins/a11y cli:build # bake the static deploy (dist/static)
|
|
58
|
+
pnpm -C plugins/a11y demo:build # static: baked RPC dump, no server
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Open the URL, then hover any row in the panel — the matching element in the page
|
|
62
|
+
gets a focus ring (and scrolls into view if it's off-screen). Both demo modes
|
|
63
|
+
behave identically; the panel's `websocket` / `static` tag is the only tell.
|
|
64
|
+
|
|
65
|
+
Standalone, without a host app:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
pnpm -C plugins/a11y dev # panel only, at /__devframe-a11y-inspector/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## File map
|
|
72
|
+
|
|
73
|
+
| Path | Export | Purpose |
|
|
74
|
+
|------|--------|---------|
|
|
75
|
+
| `src/index.ts` | `.` | `createA11yDevframe()` + the default `DevframeDefinition`; `a11yAgentBundlePath` — the agent module a hub attaches as this dock's client script |
|
|
76
|
+
| `src/node/index.ts` | `/node` | `setupA11y(ctx)` — registers the RPC functions |
|
|
77
|
+
| `src/cli.ts` | `/cli` | `createA11yCli()` — backs the `devframe-a11y-inspector` bin |
|
|
78
|
+
| `src/vite.ts` | `/vite` | `a11yVitePlugin()` — mounts the panel into a Vite host |
|
|
79
|
+
| `src/client/index.ts` | `/client` | `connectA11y()` — typed browser RPC client wrapper |
|
|
80
|
+
| `src/rpc/` | — | `get-config` static RPC + the type-safe client registry |
|
|
81
|
+
| `src/shared/protocol.ts` | — | the agent ↔ panel `BroadcastChannel` contract |
|
|
82
|
+
| `src/inject/` | — | the host-page agent (axe scan, highlight overlay, hub messages mirror) → `dist/inject/inject.js` |
|
|
83
|
+
| `src/spa/` | — | the Solid panel SPA → `dist/spa` |
|
|
84
|
+
| `demo/` | — | same-origin host page + server (dev + static modes) |
|
|
85
|
+
| `tests/` | — | dev-server RPC + static-build dump |
|
package/bin.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
import { createA11yCli } from './dist/cli.mjs'
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const cli = createA11yCli()
|
|
7
|
+
await cli.parse()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
main().catch((error) => {
|
|
11
|
+
console.error(error)
|
|
12
|
+
process.exit(1)
|
|
13
|
+
})
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CliHandle } from "devframe/adapters/cli";
|
|
2
|
+
|
|
3
|
+
//#region src/cli.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build the standalone CLI for the a11y inspector — backs the package `bin`
|
|
6
|
+
* (`devframe-a11y-inspector`) and `npx @devframes/plugin-a11y`. Wraps the
|
|
7
|
+
* default {@link createA11yDevframe} definition with devframe's
|
|
8
|
+
* `dev` / `build` / `spa` command shell.
|
|
9
|
+
*/
|
|
10
|
+
declare function createA11yCli(): CliHandle;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { createA11yCli };
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { n as a11yDevframe } from "./src-D4BUVI3M.mjs";
|
|
2
|
+
import { createCli } from "devframe/adapters/cli";
|
|
3
|
+
//#region src/cli.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build the standalone CLI for the a11y inspector — backs the package `bin`
|
|
6
|
+
* (`devframe-a11y-inspector`) and `npx @devframes/plugin-a11y`. Wraps the
|
|
7
|
+
* default {@link createA11yDevframe} definition with devframe's
|
|
8
|
+
* `dev` / `build` / `spa` command shell.
|
|
9
|
+
*/
|
|
10
|
+
function createA11yCli() {
|
|
11
|
+
return createCli(a11yDevframe);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createA11yCli };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { i as ViolationNode, n as ScanReport, r as Violation, t as Impact } from "../protocol-BptgJFLx.mjs";
|
|
2
|
+
import { DevframeRpcClient, DevframeRpcClientOptions } from "devframe/client";
|
|
3
|
+
|
|
4
|
+
//#region src/client/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Connect to the a11y inspector's devframe backend. A thin, typed wrapper
|
|
7
|
+
* around devframe's {@link connectDevframe}; the panel derives its base from
|
|
8
|
+
* `document.baseURI`, so no options are required in the common case. The
|
|
9
|
+
* live scan/highlight loop itself rides a same-origin BroadcastChannel,
|
|
10
|
+
* independent of this connection.
|
|
11
|
+
*/
|
|
12
|
+
declare function connectA11y(options?: DevframeRpcClientOptions): Promise<DevframeRpcClient>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { type DevframeRpcClient, type Impact, type ScanReport, type Violation, type ViolationNode, connectA11y };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { connectDevframe } from "devframe/client";
|
|
2
|
+
//#region src/client/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* Connect to the a11y inspector's devframe backend. A thin, typed wrapper
|
|
5
|
+
* around devframe's {@link connectDevframe}; the panel derives its base from
|
|
6
|
+
* `document.baseURI`, so no options are required in the common case. The
|
|
7
|
+
* live scan/highlight loop itself rides a same-origin BroadcastChannel,
|
|
8
|
+
* independent of this connection.
|
|
9
|
+
*/
|
|
10
|
+
function connectA11y(options) {
|
|
11
|
+
return connectDevframe(options);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { connectA11y };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { i as ViolationNode, n as ScanReport, r as Violation, t as Impact } from "./protocol-BptgJFLx.mjs";
|
|
2
|
+
import { DevframeDefinition } from "devframe/types";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Absolute path to the built in-page **agent** module (`dist/inject/inject.js`)
|
|
7
|
+
* — the dock **client script** the hub runtime imports into the host page to
|
|
8
|
+
* scan it (its default export boots the agent; importing it does too).
|
|
9
|
+
*
|
|
10
|
+
* A hub attaches this as the a11y dock's `clientScript`, resolved to a URL the
|
|
11
|
+
* page can import: `/@fs/${a11yAgentBundlePath}` for a Vite host, or a
|
|
12
|
+
* statically-served path for others (see the minimal hub examples). Resolves
|
|
13
|
+
* under `<pkg>/dist/inject/inject.js` from both the source and the published
|
|
14
|
+
* entry. Requires the built bundle (`pnpm -C plugins/a11y build`).
|
|
15
|
+
*/
|
|
16
|
+
declare const a11yAgentBundlePath: string;
|
|
17
|
+
interface A11yDevframeOptions {
|
|
18
|
+
/** Override the devframe id (and the default CLI command / mount path). */
|
|
19
|
+
id?: string;
|
|
20
|
+
/** Override the display name shown in a host dock. */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Override the dock icon. */
|
|
23
|
+
icon?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Override the mount path. Defaults to `/__devframe-a11y-inspector/` so the
|
|
26
|
+
* panel iframe shares an origin with the host page it scans.
|
|
27
|
+
*/
|
|
28
|
+
basePath?: string;
|
|
29
|
+
/** Preferred standalone CLI port. */
|
|
30
|
+
port?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build a {@link DevframeDefinition} for the a11y inspector. The same
|
|
34
|
+
* definition runs standalone (`/cli`, `/build`) and mounts into a host
|
|
35
|
+
* (`/vite`, hub). The panel talks to the in-page agent over a same-origin
|
|
36
|
+
* BroadcastChannel, so the scan/highlight loop works identically in dev
|
|
37
|
+
* (live WebSocket RPC) and in a baked static build.
|
|
38
|
+
*
|
|
39
|
+
* @experimental This plugin is experimental and may change without a major
|
|
40
|
+
* version bump until it stabilizes.
|
|
41
|
+
*/
|
|
42
|
+
declare function createA11yDevframe(options?: A11yDevframeOptions): DevframeDefinition;
|
|
43
|
+
/** The default a11y inspector devframe definition. */
|
|
44
|
+
declare const a11yDevframe: DevframeDefinition;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { A11yDevframeOptions, type Impact, type ScanReport, type Violation, type ViolationNode, a11yAgentBundlePath, createA11yDevframe, a11yDevframe as default };
|
package/dist/index.mjs
ADDED