@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 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 };
@@ -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
@@ -0,0 +1,2 @@
1
+ import { n as a11yDevframe, r as createA11yDevframe, t as a11yAgentBundlePath } from "./src-D4BUVI3M.mjs";
2
+ export { a11yAgentBundlePath, createA11yDevframe, a11yDevframe as default };