@generative-a11y/devtools 0.1.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 +21 -0
- package/README.md +151 -0
- package/dist/index.cjs +373 -0
- package/dist/index.d.cts +106 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.js +348 -0
- package/dist/overlay.cjs +837 -0
- package/dist/overlay.d.cts +15 -0
- package/dist/overlay.d.ts +15 -0
- package/dist/overlay.js +802 -0
- package/package.json +81 -0
package/dist/overlay.cjs
ADDED
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key2 of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
16
|
+
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/overlay.ts
|
|
31
|
+
var overlay_exports = {};
|
|
32
|
+
__export(overlay_exports, {
|
|
33
|
+
mountDevtoolsOverlay: () => mountDevtoolsOverlay
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(overlay_exports);
|
|
36
|
+
var import_react2 = require("react");
|
|
37
|
+
var import_client = require("react-dom/client");
|
|
38
|
+
|
|
39
|
+
// src/inspector.tsx
|
|
40
|
+
var React4 = __toESM(require("react"), 1);
|
|
41
|
+
var import_lucide_react = require("lucide-react");
|
|
42
|
+
var import_react = require("motion/react");
|
|
43
|
+
|
|
44
|
+
// src/components/ui/button.tsx
|
|
45
|
+
var React = require("react");
|
|
46
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
47
|
+
var import_radix_ui = require("radix-ui");
|
|
48
|
+
|
|
49
|
+
// src/lib/utils.ts
|
|
50
|
+
var import_clsx = require("clsx");
|
|
51
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
52
|
+
function cn(...inputs) {
|
|
53
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/components/ui/button.tsx
|
|
57
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
58
|
+
var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
59
|
+
"ga-:group/button ga-:inline-flex ga-:shrink-0 ga-:items-center ga-:justify-center ga-:rounded-lg ga-:border ga-:border-transparent ga-:bg-clip-padding ga-:text-sm ga-:font-medium ga-:whitespace-nowrap ga-:transition-all ga-:outline-none ga-:select-none ga-:focus-visible:border-ring ga-:focus-visible:ring-3 ga-:focus-visible:ring-ring/50 ga-:active:not-aria-[haspopup]:translate-y-px ga-:disabled:pointer-events-none ga-:disabled:opacity-50 ga-:aria-invalid:border-destructive ga-:aria-invalid:ring-3 ga-:aria-invalid:ring-destructive/20 ga-:dark:aria-invalid:border-destructive/50 ga-:dark:aria-invalid:ring-destructive/40 ga-:[&_svg]:pointer-events-none ga-:[&_svg]:shrink-0 ga-:[&_svg:not([class*=size-])]:size-4",
|
|
60
|
+
{
|
|
61
|
+
variants: {
|
|
62
|
+
variant: {
|
|
63
|
+
default: "ga-:bg-primary ga-:text-primary-foreground ga-:hover:bg-primary/80",
|
|
64
|
+
outline: "ga-:border-border ga-:bg-background ga-:hover:bg-muted ga-:hover:text-foreground ga-:aria-expanded:bg-muted ga-:aria-expanded:text-foreground ga-:dark:border-input ga-:dark:bg-input/30 ga-:dark:hover:bg-input/50",
|
|
65
|
+
secondary: "ga-:bg-secondary ga-:text-secondary-foreground ga-:hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] ga-:aria-expanded:bg-secondary ga-:aria-expanded:text-secondary-foreground",
|
|
66
|
+
ghost: "ga-:hover:bg-muted ga-:hover:text-foreground ga-:aria-expanded:bg-muted ga-:aria-expanded:text-foreground ga-:dark:hover:bg-muted/50",
|
|
67
|
+
destructive: "ga-:bg-destructive/10 ga-:text-destructive ga-:hover:bg-destructive/20 ga-:focus-visible:border-destructive/40 ga-:focus-visible:ring-destructive/20 ga-:dark:bg-destructive/20 ga-:dark:hover:bg-destructive/30 ga-:dark:focus-visible:ring-destructive/40",
|
|
68
|
+
link: "ga-:text-primary ga-:underline-offset-4 ga-:hover:underline"
|
|
69
|
+
},
|
|
70
|
+
size: {
|
|
71
|
+
default: "ga-:h-8 ga-:gap-1.5 ga-:px-2.5 ga-:has-data-[icon=inline-end]:pr-2 ga-:has-data-[icon=inline-start]:pl-2",
|
|
72
|
+
xs: "ga-:h-6 ga-:gap-1 ga-:rounded-[min(var(--radius-md),10px)] ga-:px-2 ga-:text-xs ga-:in-data-[slot=button-group]:rounded-lg ga-:has-data-[icon=inline-end]:pr-1.5 ga-:has-data-[icon=inline-start]:pl-1.5 ga-:[&_svg:not([class*=size-])]:size-3",
|
|
73
|
+
sm: "ga-:h-7 ga-:gap-1 ga-:rounded-[min(var(--radius-md),12px)] ga-:px-2.5 ga-:text-[0.8rem] ga-:in-data-[slot=button-group]:rounded-lg ga-:has-data-[icon=inline-end]:pr-1.5 ga-:has-data-[icon=inline-start]:pl-1.5 ga-:[&_svg:not([class*=size-])]:size-3.5",
|
|
74
|
+
lg: "ga-:h-9 ga-:gap-1.5 ga-:px-2.5 ga-:has-data-[icon=inline-end]:pr-2 ga-:has-data-[icon=inline-start]:pl-2",
|
|
75
|
+
icon: "ga-:size-8",
|
|
76
|
+
"icon-xs": "ga-:size-6 ga-:rounded-[min(var(--radius-md),10px)] ga-:in-data-[slot=button-group]:rounded-lg ga-:[&_svg:not([class*=size-])]:size-3",
|
|
77
|
+
"icon-sm": "ga-:size-7 ga-:rounded-[min(var(--radius-md),12px)] ga-:in-data-[slot=button-group]:rounded-lg",
|
|
78
|
+
"icon-lg": "ga-:size-9"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
defaultVariants: {
|
|
82
|
+
variant: "default",
|
|
83
|
+
size: "default"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
function Button({
|
|
88
|
+
className,
|
|
89
|
+
variant = "default",
|
|
90
|
+
size = "default",
|
|
91
|
+
asChild = false,
|
|
92
|
+
...props
|
|
93
|
+
}) {
|
|
94
|
+
const Comp = asChild ? import_radix_ui.Slot.Root : "button";
|
|
95
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
96
|
+
Comp,
|
|
97
|
+
{
|
|
98
|
+
"data-slot": "button",
|
|
99
|
+
"data-variant": variant,
|
|
100
|
+
"data-size": size,
|
|
101
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
102
|
+
...props
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/components/ui/input.tsx
|
|
108
|
+
var React2 = require("react");
|
|
109
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
110
|
+
function Input({ className, type, ...props }) {
|
|
111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
112
|
+
"input",
|
|
113
|
+
{
|
|
114
|
+
type,
|
|
115
|
+
"data-slot": "input",
|
|
116
|
+
className: cn(
|
|
117
|
+
"ga-:h-8 ga-:w-full ga-:min-w-0 ga-:rounded-lg ga-:border ga-:border-input ga-:bg-transparent ga-:px-2.5 ga-:py-1 ga-:text-base ga-:transition-colors ga-:outline-none ga-:file:inline-flex ga-:file:h-6 ga-:file:border-0 ga-:file:bg-transparent ga-:file:text-sm ga-:file:font-medium ga-:file:text-foreground ga-:placeholder:text-muted-foreground ga-:focus-visible:border-ring ga-:focus-visible:ring-3 ga-:focus-visible:ring-ring/50 ga-:disabled:pointer-events-none ga-:disabled:cursor-not-allowed ga-:disabled:bg-input/50 ga-:disabled:opacity-50 ga-:aria-invalid:border-destructive ga-:aria-invalid:ring-3 ga-:aria-invalid:ring-destructive/20 ga-:md:text-sm ga-:dark:bg-input/30 ga-:dark:disabled:bg-input/80 ga-:dark:aria-invalid:border-destructive/50 ga-:dark:aria-invalid:ring-destructive/40",
|
|
118
|
+
className
|
|
119
|
+
),
|
|
120
|
+
...props
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/components/ui/resizable.tsx
|
|
126
|
+
var ResizablePrimitive = __toESM(require("react-resizable-panels"), 1);
|
|
127
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
128
|
+
function ResizablePanelGroup({
|
|
129
|
+
className,
|
|
130
|
+
...props
|
|
131
|
+
}) {
|
|
132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
133
|
+
ResizablePrimitive.Group,
|
|
134
|
+
{
|
|
135
|
+
"data-slot": "resizable-panel-group",
|
|
136
|
+
className: cn(
|
|
137
|
+
"ga-:flex ga-:h-full ga-:w-full ga-:aria-[orientation=vertical]:flex-col",
|
|
138
|
+
className
|
|
139
|
+
),
|
|
140
|
+
...props
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
function ResizablePanel({ ...props }) {
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ResizablePrimitive.Panel, { "data-slot": "resizable-panel", ...props });
|
|
146
|
+
}
|
|
147
|
+
function ResizableHandle({
|
|
148
|
+
withHandle,
|
|
149
|
+
className,
|
|
150
|
+
...props
|
|
151
|
+
}) {
|
|
152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
153
|
+
ResizablePrimitive.Separator,
|
|
154
|
+
{
|
|
155
|
+
"data-slot": "resizable-handle",
|
|
156
|
+
className: cn(
|
|
157
|
+
"ga-:relative ga-:flex ga-:w-px ga-:items-center ga-:justify-center ga-:bg-border ga-:ring-offset-background ga-:after:absolute ga-:after:inset-y-0 ga-:after:left-1/2 ga-:after:w-1 ga-:after:-translate-x-1/2 ga-:focus-visible:ring-1 ga-:focus-visible:ring-ring ga-:focus-visible:outline-hidden ga-:aria-[orientation=horizontal]:h-px ga-:aria-[orientation=horizontal]:w-full ga-:aria-[orientation=horizontal]:after:left-0 ga-:aria-[orientation=horizontal]:after:h-1 ga-:aria-[orientation=horizontal]:after:w-full ga-:aria-[orientation=horizontal]:after:translate-x-0 ga-:aria-[orientation=horizontal]:after:-translate-y-1/2 ga-:[&[aria-orientation=horizontal]>div]:rotate-90",
|
|
158
|
+
className
|
|
159
|
+
),
|
|
160
|
+
...props,
|
|
161
|
+
children: withHandle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ga-:z-10 ga-:flex ga-:h-6 ga-:w-1 ga-:shrink-0 ga-:rounded-lg ga-:bg-border" })
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/components/ui/scroll-area.tsx
|
|
167
|
+
var React3 = require("react");
|
|
168
|
+
var import_radix_ui2 = require("radix-ui");
|
|
169
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
170
|
+
function ScrollArea({
|
|
171
|
+
className,
|
|
172
|
+
children,
|
|
173
|
+
...props
|
|
174
|
+
}) {
|
|
175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
176
|
+
import_radix_ui2.ScrollArea.Root,
|
|
177
|
+
{
|
|
178
|
+
"data-slot": "scroll-area",
|
|
179
|
+
className: cn("ga-:relative", className),
|
|
180
|
+
...props,
|
|
181
|
+
children: [
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
183
|
+
import_radix_ui2.ScrollArea.Viewport,
|
|
184
|
+
{
|
|
185
|
+
"data-slot": "scroll-area-viewport",
|
|
186
|
+
className: "ga-:size-full ga-:rounded-[inherit] ga-:transition-[color,box-shadow] ga-:outline-none ga-:focus-visible:ring-[3px] ga-:focus-visible:ring-ring/50 ga-:focus-visible:outline-1",
|
|
187
|
+
children
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ScrollBar, {}),
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_radix_ui2.ScrollArea.Corner, {})
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
function ScrollBar({
|
|
197
|
+
className,
|
|
198
|
+
orientation = "vertical",
|
|
199
|
+
...props
|
|
200
|
+
}) {
|
|
201
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
202
|
+
import_radix_ui2.ScrollArea.ScrollAreaScrollbar,
|
|
203
|
+
{
|
|
204
|
+
"data-slot": "scroll-area-scrollbar",
|
|
205
|
+
"data-orientation": orientation,
|
|
206
|
+
orientation,
|
|
207
|
+
className: cn(
|
|
208
|
+
"ga-:flex ga-:touch-none ga-:p-px ga-:transition-colors ga-:select-none ga-:data-horizontal:h-2.5 ga-:data-horizontal:flex-col ga-:data-horizontal:border-t ga-:data-horizontal:border-t-transparent ga-:data-vertical:h-full ga-:data-vertical:w-2.5 ga-:data-vertical:border-l ga-:data-vertical:border-l-transparent",
|
|
209
|
+
className
|
|
210
|
+
),
|
|
211
|
+
...props,
|
|
212
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
213
|
+
import_radix_ui2.ScrollArea.ScrollAreaThumb,
|
|
214
|
+
{
|
|
215
|
+
"data-slot": "scroll-area-thumb",
|
|
216
|
+
className: "ga-:relative ga-:flex-1 ga-:rounded-full ga-:bg-border"
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/inspector.tsx
|
|
224
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
225
|
+
var key = (record) => String(record.captureSequence);
|
|
226
|
+
var time = (value) => value >= 1e10 ? new Date(value).toISOString().slice(11, 23) : `+${(value / 1e3).toFixed(2)}s`;
|
|
227
|
+
var stage = (record) => record.kind === "event-observed" ? "Source evidence" : record.kind === "decision" ? "Runtime decision" : "DOM delivery";
|
|
228
|
+
var title = (record) => record.kind === "event-observed" ? record.sourceType ?? "Observed event" : record.kind === "dom-delivery" ? `${record.deliveryStatus ?? "Delivery"} via ${record.deliveryMethod ?? "browser"}` : record.reason ?? record.disposition ?? "Runtime decision";
|
|
229
|
+
function correlation(record) {
|
|
230
|
+
const prefix = `${record.runtimeId}:`;
|
|
231
|
+
if (record.sourceEventId) return `${prefix}event:${record.sourceEventId}`;
|
|
232
|
+
if (record.responseId)
|
|
233
|
+
return `${prefix}response:${record.responseId}:${record.sourceType ?? "unknown"}`;
|
|
234
|
+
if (record.toolId)
|
|
235
|
+
return `${prefix}tool:${record.toolId}:${record.sourceType ?? "unknown"}`;
|
|
236
|
+
if (record.interactionId)
|
|
237
|
+
return `${prefix}interaction:${record.interactionId}`;
|
|
238
|
+
if (record.approvalId) return `${prefix}approval:${record.approvalId}`;
|
|
239
|
+
if (record.announcementId)
|
|
240
|
+
return `${prefix}announcement:${record.announcementId}`;
|
|
241
|
+
return `${prefix}record:${record.captureSequence}`;
|
|
242
|
+
}
|
|
243
|
+
function explain(record) {
|
|
244
|
+
if (record.kind === "event-observed")
|
|
245
|
+
return "The adapter supplied this normalized public lifecycle signal.";
|
|
246
|
+
if (record.kind === "dom-delivery")
|
|
247
|
+
return record.deliveryStatus === "unavailable" ? "The DOM driver was unavailable, so no browser delivery action was observed." : "The DOM driver reported this delivery action.";
|
|
248
|
+
return {
|
|
249
|
+
scheduled: "The runtime placed an announcement intent into its bounded queue.",
|
|
250
|
+
coalesced: "The runtime merged this work with an existing queued announcement.",
|
|
251
|
+
duplicate: "The runtime suppressed a recently delivered duplicate.",
|
|
252
|
+
"policy-silent": "The active policy intentionally made this event silent.",
|
|
253
|
+
"queue-capacity": "The bounded queue rejected or displaced this work.",
|
|
254
|
+
"scope-cancelled": "The lifecycle scope ended before this queued work delivered.",
|
|
255
|
+
"runtime-disposed": "The runtime was disposed and cancelled remaining queued work.",
|
|
256
|
+
"stale-response": "This signal did not match the active response epoch.",
|
|
257
|
+
"stale-tool": "This signal did not match the active tool instance.",
|
|
258
|
+
"delivery-error": "A registered announcement listener failed during delivery.",
|
|
259
|
+
delivered: "A registered runtime announcement listener accepted this intent."
|
|
260
|
+
}[record.reason ?? ""] ?? "The runtime recorded this policy decision.";
|
|
261
|
+
}
|
|
262
|
+
function useSnapshot(store) {
|
|
263
|
+
return React4.useSyncExternalStore(
|
|
264
|
+
React4.useCallback((listener) => store.subscribe(listener), [store]),
|
|
265
|
+
React4.useCallback(() => store.getSnapshot(), [store])
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
function CausalChain({
|
|
269
|
+
records
|
|
270
|
+
}) {
|
|
271
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-causal-chain", "data-testid": "causal-chain", children: [
|
|
272
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-section-heading", children: [
|
|
273
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
274
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "Related evidence" }),
|
|
275
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: "Observed path" })
|
|
276
|
+
] }),
|
|
277
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
|
|
278
|
+
records.length,
|
|
279
|
+
" records"
|
|
280
|
+
] })
|
|
281
|
+
] }),
|
|
282
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ol", { children: records.map((record, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { "data-stage": record.kind, children: [
|
|
283
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": "true", children: String(index + 1).padStart(2, "0") }),
|
|
284
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
285
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: stage(record) }),
|
|
286
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: title(record) })
|
|
287
|
+
] }),
|
|
288
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("time", { children: time(record.at) })
|
|
289
|
+
] }, key(record))) })
|
|
290
|
+
] });
|
|
291
|
+
}
|
|
292
|
+
function Detail({
|
|
293
|
+
record,
|
|
294
|
+
related,
|
|
295
|
+
snapshot
|
|
296
|
+
}) {
|
|
297
|
+
if (!record)
|
|
298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("aside", { className: "ga-trace-detail", "data-testid": "trace-detail", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-empty-state", children: [
|
|
299
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "Choose a record" }),
|
|
300
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: "Trace one accessibility decision from source to delivery." }),
|
|
301
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Selection never changes the runtime, queue, or host focus." })
|
|
302
|
+
] }) });
|
|
303
|
+
const source = snapshot.runtimeSources[record.runtimeSourceId ?? record.runtimeId];
|
|
304
|
+
const runtime = snapshot.runtimeSnapshots[record.runtimeId];
|
|
305
|
+
const deliveries = related.filter((item) => item.kind === "dom-delivery");
|
|
306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: "ga-trace-detail", "data-testid": "trace-detail", children: [
|
|
307
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-detail-intro", children: [
|
|
308
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: stage(record) }),
|
|
309
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { children: title(record) }),
|
|
310
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: explain(record) })
|
|
311
|
+
] }),
|
|
312
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
|
|
313
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Why inspect this" }),
|
|
314
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: record.reason?.startsWith("stale") ? "Compare the instance with the current runtime snapshot." : "Inspect related evidence and queue context if this was unexpected." })
|
|
315
|
+
] }),
|
|
316
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CausalChain, { records: related }),
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
|
|
318
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Source evidence" }),
|
|
319
|
+
source ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
|
|
320
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
321
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Adapter" }),
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.adapter })
|
|
323
|
+
] }),
|
|
324
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
325
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Interruption" }),
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.interruption })
|
|
327
|
+
] }),
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Retry" }),
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.retries })
|
|
331
|
+
] }),
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Connection" }),
|
|
334
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.connection })
|
|
335
|
+
] }),
|
|
336
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-key-values-wide", children: [
|
|
337
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Public signals" }),
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.evidence.join(", ") })
|
|
339
|
+
] })
|
|
340
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "Adapter evidence was not declared for this runtime." })
|
|
341
|
+
] }),
|
|
342
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
|
|
343
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Policy and scheduling" }),
|
|
344
|
+
runtime ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
|
|
345
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
346
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Queue" }),
|
|
347
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dd", { children: [
|
|
348
|
+
runtime.pendingCount,
|
|
349
|
+
" pending"
|
|
350
|
+
] })
|
|
351
|
+
] }),
|
|
352
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
353
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Minimum gap" }),
|
|
354
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dd", { children: [
|
|
355
|
+
runtime.policy.minimumGapMs,
|
|
356
|
+
" ms"
|
|
357
|
+
] })
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
360
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Due" }),
|
|
361
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.dueAt === void 0 ? "Not scheduled" : time(record.dueAt) })
|
|
362
|
+
] }),
|
|
363
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Queue sequence" }),
|
|
365
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.queueSequence ?? "Not queued" })
|
|
366
|
+
] })
|
|
367
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "No current runtime snapshot is available." })
|
|
368
|
+
] }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
|
|
370
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Delivery evidence" }),
|
|
371
|
+
deliveries.length ? deliveries.map((delivery) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("code", { children: [
|
|
372
|
+
delivery.deliveryMethod,
|
|
373
|
+
" \xB7 ",
|
|
374
|
+
delivery.deliveryStatus
|
|
375
|
+
] }) }, key(delivery))) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "No instrumented DOM delivery result is correlated with this record." }),
|
|
376
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ga-boundary", children: "A runtime intent or DOM result does not prove that a screen reader spoke." })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "ga-raw-record", children: [
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("summary", { children: "Structured record" }),
|
|
380
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { children: JSON.stringify(record, null, 2) })
|
|
381
|
+
] })
|
|
382
|
+
] });
|
|
383
|
+
}
|
|
384
|
+
function List({
|
|
385
|
+
records,
|
|
386
|
+
selected,
|
|
387
|
+
onSelect
|
|
388
|
+
}) {
|
|
389
|
+
const index = Math.max(
|
|
390
|
+
0,
|
|
391
|
+
records.findIndex((record) => key(record) === selected)
|
|
392
|
+
);
|
|
393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
394
|
+
"div",
|
|
395
|
+
{
|
|
396
|
+
"aria-activedescendant": selected ? `trace-${selected}` : void 0,
|
|
397
|
+
"aria-label": "Captured accessibility trace",
|
|
398
|
+
className: "ga-trace-list",
|
|
399
|
+
onKeyDown: (event) => {
|
|
400
|
+
const direction = event.key === "ArrowDown" ? 1 : event.key === "ArrowUp" ? -1 : 0;
|
|
401
|
+
if (!direction || !records.length) return;
|
|
402
|
+
event.preventDefault();
|
|
403
|
+
const next = records[Math.max(0, Math.min(records.length - 1, index + direction))];
|
|
404
|
+
if (next) {
|
|
405
|
+
onSelect(key(next));
|
|
406
|
+
event.currentTarget.querySelector(`#trace-${key(next)}`)?.scrollIntoView({ block: "nearest" });
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
role: "listbox",
|
|
410
|
+
tabIndex: 0,
|
|
411
|
+
children: [
|
|
412
|
+
records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
413
|
+
"div",
|
|
414
|
+
{
|
|
415
|
+
"aria-selected": key(record) === selected,
|
|
416
|
+
className: "ga-trace-row",
|
|
417
|
+
id: `trace-${key(record)}`,
|
|
418
|
+
onClick: () => onSelect(key(record)),
|
|
419
|
+
role: "option",
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("time", { children: time(record.at) }),
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: stage(record) }),
|
|
423
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: title(record) }),
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: record.reason ?? record.sourceType ?? record.deliveryStatus ?? "recorded" })
|
|
425
|
+
]
|
|
426
|
+
},
|
|
427
|
+
key(record)
|
|
428
|
+
)),
|
|
429
|
+
!records.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ga-empty-list", children: "No trace records match this view." }) : null
|
|
430
|
+
]
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
function DevtoolsInspector({
|
|
435
|
+
store,
|
|
436
|
+
onClose,
|
|
437
|
+
onCopy
|
|
438
|
+
}) {
|
|
439
|
+
const snapshot = useSnapshot(store);
|
|
440
|
+
const reduceMotion = (0, import_react.useReducedMotion)();
|
|
441
|
+
const [query, setQuery] = React4.useState("");
|
|
442
|
+
const [filter, setFilter] = React4.useState("all");
|
|
443
|
+
const [selectedKey, setSelectedKey] = React4.useState();
|
|
444
|
+
const [feedback, setFeedback] = React4.useState();
|
|
445
|
+
const feedbackTimer = React4.useRef(void 0);
|
|
446
|
+
const actionRevision = React4.useRef(0);
|
|
447
|
+
const visible = snapshot.records.filter(
|
|
448
|
+
(record) => (filter === "all" || record.kind === filter) && [
|
|
449
|
+
record.kind,
|
|
450
|
+
record.sourceType,
|
|
451
|
+
record.reason,
|
|
452
|
+
record.disposition,
|
|
453
|
+
record.responseId,
|
|
454
|
+
record.toolId,
|
|
455
|
+
record.interactionId,
|
|
456
|
+
record.approvalId
|
|
457
|
+
].filter(Boolean).join(" ").toLowerCase().includes(query.trim().toLowerCase())
|
|
458
|
+
).slice().reverse();
|
|
459
|
+
const selected = visible.find((record) => key(record) === selectedKey) ?? visible[0];
|
|
460
|
+
const related = selected ? snapshot.records.filter(
|
|
461
|
+
(record) => correlation(record) === correlation(selected)
|
|
462
|
+
) : [];
|
|
463
|
+
React4.useEffect(
|
|
464
|
+
() => () => {
|
|
465
|
+
if (feedbackTimer.current !== void 0)
|
|
466
|
+
window.clearTimeout(feedbackTimer.current);
|
|
467
|
+
},
|
|
468
|
+
[]
|
|
469
|
+
);
|
|
470
|
+
const closeInspector = () => {
|
|
471
|
+
actionRevision.current += 1;
|
|
472
|
+
if (feedbackTimer.current !== void 0)
|
|
473
|
+
window.clearTimeout(feedbackTimer.current);
|
|
474
|
+
feedbackTimer.current = void 0;
|
|
475
|
+
setFeedback(void 0);
|
|
476
|
+
onClose();
|
|
477
|
+
};
|
|
478
|
+
const notice = (message) => {
|
|
479
|
+
if (feedbackTimer.current !== void 0)
|
|
480
|
+
window.clearTimeout(feedbackTimer.current);
|
|
481
|
+
setFeedback(message);
|
|
482
|
+
feedbackTimer.current = window.setTimeout(
|
|
483
|
+
() => setFeedback(void 0),
|
|
484
|
+
2200
|
|
485
|
+
);
|
|
486
|
+
};
|
|
487
|
+
const copy = async () => {
|
|
488
|
+
if (!onCopy) return notice("Copy is unavailable in this mount");
|
|
489
|
+
const revision = ++actionRevision.current;
|
|
490
|
+
if (feedbackTimer.current !== void 0)
|
|
491
|
+
window.clearTimeout(feedbackTimer.current);
|
|
492
|
+
setFeedback("Copying trace");
|
|
493
|
+
try {
|
|
494
|
+
await onCopy(JSON.stringify(store.exportTrace(), null, 2));
|
|
495
|
+
if (actionRevision.current === revision) notice("Trace copied");
|
|
496
|
+
} catch {
|
|
497
|
+
if (actionRevision.current === revision)
|
|
498
|
+
notice("Copy could not complete");
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
502
|
+
"section",
|
|
503
|
+
{
|
|
504
|
+
"aria-label": "Generative accessibility trace explorer",
|
|
505
|
+
className: "ga-inspector",
|
|
506
|
+
onKeyDown: (event) => {
|
|
507
|
+
if (event.key === "Escape") {
|
|
508
|
+
event.stopPropagation();
|
|
509
|
+
closeInspector();
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
children: [
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "ga-inspector-header", children: [
|
|
514
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
515
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "Local diagnostic session" }),
|
|
516
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { children: "Accessibility trace" })
|
|
517
|
+
] }),
|
|
518
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-header-actions", children: [
|
|
519
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
520
|
+
Button,
|
|
521
|
+
{
|
|
522
|
+
onClick: () => {
|
|
523
|
+
if (snapshot.paused) {
|
|
524
|
+
store.resumeCapture();
|
|
525
|
+
notice("Capture resumed");
|
|
526
|
+
} else {
|
|
527
|
+
store.pauseCapture();
|
|
528
|
+
notice("Capture paused");
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
size: "sm",
|
|
532
|
+
variant: "secondary",
|
|
533
|
+
children: [
|
|
534
|
+
snapshot.paused ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Play, { "aria-hidden": "true", size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Pause, { "aria-hidden": "true", size: 14 }),
|
|
535
|
+
snapshot.paused ? "Resume" : "Pause"
|
|
536
|
+
]
|
|
537
|
+
}
|
|
538
|
+
),
|
|
539
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
540
|
+
Button,
|
|
541
|
+
{
|
|
542
|
+
"aria-label": "Refresh runtime snapshot",
|
|
543
|
+
onClick: () => {
|
|
544
|
+
store.refreshSnapshots();
|
|
545
|
+
notice("Runtime snapshot refreshed");
|
|
546
|
+
},
|
|
547
|
+
size: "icon-sm",
|
|
548
|
+
variant: "ghost",
|
|
549
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.RefreshCw, { "aria-hidden": "true", size: 15 })
|
|
550
|
+
}
|
|
551
|
+
),
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
553
|
+
Button,
|
|
554
|
+
{
|
|
555
|
+
"aria-label": "Close inspector",
|
|
556
|
+
onClick: closeInspector,
|
|
557
|
+
size: "icon-sm",
|
|
558
|
+
variant: "ghost",
|
|
559
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.X, { "aria-hidden": "true", size: 17 })
|
|
560
|
+
}
|
|
561
|
+
)
|
|
562
|
+
] })
|
|
563
|
+
] }),
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "aria-live": "polite", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react.AnimatePresence, { children: feedback ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
565
|
+
import_react.motion.div,
|
|
566
|
+
{
|
|
567
|
+
animate: reduceMotion ? false : { opacity: 1, y: 0 },
|
|
568
|
+
className: "ga-workspace-feedback",
|
|
569
|
+
"data-testid": "workspace-feedback",
|
|
570
|
+
...reduceMotion ? {} : { exit: { opacity: 0, y: 4 } },
|
|
571
|
+
initial: reduceMotion ? false : { opacity: 0, y: 4 },
|
|
572
|
+
children: feedback
|
|
573
|
+
}
|
|
574
|
+
) : null }) }),
|
|
575
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-session-toolbar", children: [
|
|
576
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "ga-inspector-search", children: [
|
|
577
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Search, { "aria-hidden": "true", size: 15 }),
|
|
578
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
579
|
+
Input,
|
|
580
|
+
{
|
|
581
|
+
"aria-label": "Search trace",
|
|
582
|
+
onChange: (event) => setQuery(event.target.value),
|
|
583
|
+
placeholder: "Search safe metadata",
|
|
584
|
+
type: "search",
|
|
585
|
+
value: query
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
] }),
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
590
|
+
"div",
|
|
591
|
+
{
|
|
592
|
+
"aria-label": "Trace category",
|
|
593
|
+
className: "ga-filter-group",
|
|
594
|
+
role: "group",
|
|
595
|
+
children: ["all", "event-observed", "decision", "dom-delivery"].map(
|
|
596
|
+
(value) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
597
|
+
Button,
|
|
598
|
+
{
|
|
599
|
+
"aria-pressed": filter === value,
|
|
600
|
+
onClick: () => setFilter(value),
|
|
601
|
+
size: "sm",
|
|
602
|
+
variant: filter === value ? "secondary" : "ghost",
|
|
603
|
+
children: value === "all" ? "All" : value === "event-observed" ? "Source" : value === "decision" ? "Decisions" : "Delivery"
|
|
604
|
+
},
|
|
605
|
+
value
|
|
606
|
+
)
|
|
607
|
+
)
|
|
608
|
+
}
|
|
609
|
+
),
|
|
610
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ga-session-count", children: [
|
|
611
|
+
snapshot.records.length,
|
|
612
|
+
" captured \xB7 ",
|
|
613
|
+
snapshot.droppedCount,
|
|
614
|
+
" dropped"
|
|
615
|
+
] }),
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Button, { onClick: () => void copy(), size: "sm", variant: "ghost", children: [
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Copy, { "aria-hidden": "true", size: 14 }),
|
|
618
|
+
" Copy"
|
|
619
|
+
] }),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
621
|
+
Button,
|
|
622
|
+
{
|
|
623
|
+
onClick: () => {
|
|
624
|
+
store.clear();
|
|
625
|
+
setSelectedKey(void 0);
|
|
626
|
+
notice("Local trace cleared");
|
|
627
|
+
},
|
|
628
|
+
size: "sm",
|
|
629
|
+
variant: "ghost",
|
|
630
|
+
children: "Clear"
|
|
631
|
+
}
|
|
632
|
+
)
|
|
633
|
+
] }),
|
|
634
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
635
|
+
ResizablePanelGroup,
|
|
636
|
+
{
|
|
637
|
+
className: "ga-explorer-layout",
|
|
638
|
+
orientation: "horizontal",
|
|
639
|
+
children: [
|
|
640
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ResizablePanel, { defaultSize: 48, minSize: 34, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScrollArea, { className: "ga-trace-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
641
|
+
List,
|
|
642
|
+
{
|
|
643
|
+
onSelect: setSelectedKey,
|
|
644
|
+
records: visible,
|
|
645
|
+
selected: selected ? key(selected) : void 0
|
|
646
|
+
}
|
|
647
|
+
) }) }),
|
|
648
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ResizableHandle, { withHandle: true }),
|
|
649
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ResizablePanel, { defaultSize: 52, minSize: 34, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Detail, { record: selected, related, snapshot }) })
|
|
650
|
+
]
|
|
651
|
+
}
|
|
652
|
+
)
|
|
653
|
+
]
|
|
654
|
+
}
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// src/overlay.ts
|
|
659
|
+
var styles = `
|
|
660
|
+
:host { all: initial; color: #e7e5e4; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
661
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
662
|
+
button, input { font: inherit; }
|
|
663
|
+
button { cursor: pointer; }
|
|
664
|
+
button:focus-visible, input:focus-visible, [role="separator"]:focus-visible { outline: 1px solid #d6d3d1; outline-offset: 2px; }
|
|
665
|
+
.ga-launcher { position: fixed; z-index: 2147483646; left: 50%; bottom: 0; min-width: 184px; min-height: 34px; padding: 0 16px; color: #d6d3d1; background: #18181b; border: 1px solid #3f3f46; border-bottom: 0; border-radius: 8px 8px 0 0; box-shadow: 0 -8px 28px #0004; font-size: 12px; font-weight: 560; letter-spacing: -.005em; transform: translateX(-50%); }
|
|
666
|
+
.ga-launcher:hover { color: #fafaf9; background: #27272a; }
|
|
667
|
+
.ga-bottom-dock { position: fixed; z-index: 2147483647; right: 0; bottom: 0; left: 0; width: 100%; height: min(570px, 62vh); min-height: 340px; overflow: hidden; color: #e7e5e4; background: #18181b; border-top: 1px solid #3f3f46; border-radius: 12px 12px 0 0; box-shadow: 0 -20px 60px #0008; }
|
|
668
|
+
.ga-inspector { position: relative; display: flex; height: 100%; min-height: 0; flex-direction: column; background: #171717; }
|
|
669
|
+
.ga-inspector-header { display: flex; min-height: 48px; align-items: center; justify-content: space-between; gap: 16px; padding: 9px 18px; border-bottom: 1px solid #3f3f46; background: #18181b; }
|
|
670
|
+
[data-slot="button"] { display: inline-flex; min-height: 30px; align-items: center; justify-content: center; gap: 6px; padding: 0 10px; color: #d6d3d1; background: transparent; border: 1px solid transparent; border-radius: 7px; font-size: 12px; font-weight: 600; }
|
|
671
|
+
[data-slot="button"][data-variant="outline"] { border-color: #52525b; background: #27272a; }
|
|
672
|
+
[data-slot="button"][data-variant="outline"]:hover, [data-slot="button"][data-variant="ghost"]:hover { color: #fafaf9; background: #3f3f46; }
|
|
673
|
+
[data-slot="button"][data-variant="secondary"] { color: #1c1917; background: #e7e5e4; }
|
|
674
|
+
[data-slot="button"][data-variant="secondary"]:hover { background: #fafaf9; }
|
|
675
|
+
[data-slot="button"][data-size="icon-sm"] { width: 30px; padding: 0; }
|
|
676
|
+
.ga-workspace-feedback { position: absolute; z-index: 5; top: 58px; right: 16px; padding: 8px 10px; color: #fafaf9; background: #27272a; border: 1px solid #52525b; border-radius: 7px; box-shadow: 0 10px 30px #0007; font-size: 12px; }
|
|
677
|
+
.ga-inspector-search { display: flex; width: min(360px, 50%); align-items: center; gap: 8px; padding: 0 9px; color: #a8a29e; background: #20201f; border: 1px solid #3f3f46; border-radius: 7px; }
|
|
678
|
+
[data-slot="input"] { width: 100%; height: 31px; padding: 0; color: #e7e5e4; background: transparent; border: 0; outline: 0; font-size: 12px; }
|
|
679
|
+
[data-slot="input"]::placeholder { color: #a8a29e; }
|
|
680
|
+
[data-slot="resizable-panel"] { min-width: 0; min-height: 0; }
|
|
681
|
+
[data-slot="resizable-handle"] { position: relative; width: 1px; background: #3f3f46; }
|
|
682
|
+
[data-slot="resizable-handle"] > div { position: absolute; top: calc(50% - 14px); left: -2px; width: 5px; height: 28px; background: #71717a; border-radius: 999px; }
|
|
683
|
+
[data-slot="scroll-area"], [data-slot="scroll-area-viewport"] { height: 100%; }
|
|
684
|
+
@media (prefers-reduced-motion: no-preference) { .ga-bottom-dock { animation: ga-inspector-enter 180ms cubic-bezier(.2,.8,.2,1); } @keyframes ga-inspector-enter { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } } }
|
|
685
|
+
:host { color: #171717; font-family: Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
686
|
+
button:focus-visible, input:focus-visible, [role="listbox"]:focus-visible, [role="separator"]:focus-visible { outline: 2px solid #111; outline-offset: 2px; }
|
|
687
|
+
.ga-launcher { color: #f7f7f7; background: #111; border-color: #111; border-radius: 4px 4px 0 0; box-shadow: none; }
|
|
688
|
+
.ga-launcher:hover { color: #fff; background: #333; }
|
|
689
|
+
.ga-bottom-dock { height: min(620px, 68vh); color: #171717; background: #f7f7f7; border-color: #111; border-radius: 0; box-shadow: 0 -12px 34px #0003; }
|
|
690
|
+
.ga-inspector { background: #f7f7f7; }
|
|
691
|
+
.ga-inspector-header { min-height: 58px; padding: 12px 24px; color: #111; background: #f7f7f7; border-color: #d0d0d0; }
|
|
692
|
+
.ga-inspector-header p, .ga-inspector-header h2 { margin: 0; }
|
|
693
|
+
.ga-inspector-header p, .ga-section-heading p, .ga-detail-intro > p { color: #5f5f5f; font: 600 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .08em; text-transform: uppercase; }
|
|
694
|
+
.ga-inspector-header h2 { margin-top: 3px; color: #111; font-size: 16px; font-weight: 650; letter-spacing: -.03em; }
|
|
695
|
+
.ga-header-actions { display: flex; align-items: center; gap: 4px; }
|
|
696
|
+
[data-slot="button"] { color: #171717; border-radius: 3px; font-weight: 600; }
|
|
697
|
+
[data-slot="button"][data-variant="secondary"] { color: #f7f7f7; background: #111; }
|
|
698
|
+
[data-slot="button"][data-variant="outline"] { color: #171717; border-color: #bdbdbd; background: transparent; }
|
|
699
|
+
[data-slot="button"][data-variant="ghost"]:hover { color: #111; background: #e8e8e8; }
|
|
700
|
+
.ga-session-toolbar { display: flex; min-height: 50px; align-items: center; gap: 8px; padding: 8px 24px; border-bottom: 1px solid #d0d0d0; }
|
|
701
|
+
.ga-inspector-search { width: min(330px, 35%); color: #5f5f5f; background: #fff; border-color: #d0d0d0; border-radius: 3px; }
|
|
702
|
+
[data-slot="input"] { color: #171717; }
|
|
703
|
+
.ga-filter-group { display: inline-flex; gap: 2px; }
|
|
704
|
+
.ga-filter-group [aria-pressed="true"] { color: #f7f7f7; background: #111; }
|
|
705
|
+
.ga-session-count { margin-left: auto; color: #5f5f5f; font: 600 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
706
|
+
.ga-explorer-layout { min-height: 0; flex: 1; }
|
|
707
|
+
.ga-inspector > [data-slot="resizable-panel-group"], .ga-explorer-layout { display: flex; min-height: 0; flex: 1; }
|
|
708
|
+
[data-slot="resizable-handle"] { background: #d0d0d0; }
|
|
709
|
+
.ga-trace-scroll, .ga-trace-detail { height: 100%; }
|
|
710
|
+
.ga-trace-list { min-height: 100%; padding: 8px 0; outline: none; }
|
|
711
|
+
.ga-trace-row { display: grid; grid-template-columns: 76px 110px minmax(130px, 1fr) auto; gap: 9px; align-items: center; min-height: 44px; padding: 8px 24px; cursor: pointer; border-bottom: 1px solid #e0e0e0; }
|
|
712
|
+
.ga-trace-row:hover, .ga-trace-row[aria-selected="true"] { background: #e8e8e8; }
|
|
713
|
+
.ga-trace-row time, .ga-trace-row span, .ga-trace-row code, .ga-causal-chain code, .ga-key-values dt, .ga-key-values dd { font: 600 10px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
714
|
+
.ga-trace-row time, .ga-trace-row span, .ga-trace-row code { color: #5f5f5f; }
|
|
715
|
+
.ga-trace-row strong { overflow: hidden; color: #171717; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
|
716
|
+
.ga-empty-list { padding: 24px; color: #5f5f5f; font-size: 12px; }
|
|
717
|
+
.ga-trace-detail { overflow: auto; padding: 22px 24px; background: #fff; }
|
|
718
|
+
.ga-detail-intro h3, .ga-empty-state h3, .ga-section-heading h3 { margin: 4px 0 8px; color: #111; font-size: 16px; font-weight: 650; letter-spacing: -.03em; }
|
|
719
|
+
.ga-detail-intro > span, .ga-empty-state span, .ga-detail-section p { color: #5f5f5f; font-size: 12px; line-height: 1.55; }
|
|
720
|
+
.ga-detail-section { padding: 16px 0; border-top: 1px solid #d0d0d0; }
|
|
721
|
+
.ga-detail-section h4 { margin: 0 0 8px; color: #111; font-size: 12px; font-weight: 650; }
|
|
722
|
+
.ga-detail-section p { margin: 0 0 6px; }
|
|
723
|
+
.ga-boundary { padding-left: 10px; border-left: 2px solid #111; }
|
|
724
|
+
.ga-causal-chain { margin: 20px 0; padding: 16px 0; border-top: 1px solid #111; border-bottom: 1px solid #111; }
|
|
725
|
+
.ga-section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
|
|
726
|
+
.ga-section-heading > span { color: #5f5f5f; font: 600 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
727
|
+
.ga-causal-chain ol { margin: 14px 0 0; padding: 0; list-style: none; }
|
|
728
|
+
.ga-causal-chain li { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: 8px; align-items: center; min-height: 38px; border-top: 1px solid #e0e0e0; }
|
|
729
|
+
.ga-causal-chain li > span, .ga-causal-chain li b, .ga-causal-chain time { color: #5f5f5f; font: 600 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
730
|
+
.ga-causal-chain li code { display: block; margin-top: 3px; color: #111; }
|
|
731
|
+
.ga-key-values { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin: 0; background: #d0d0d0; border: 1px solid #d0d0d0; }
|
|
732
|
+
.ga-key-values > div { min-width: 0; padding: 8px; background: #f7f7f7; }
|
|
733
|
+
.ga-key-values-wide { grid-column: 1 / -1; }
|
|
734
|
+
.ga-key-values dt { color: #5f5f5f; text-transform: uppercase; }
|
|
735
|
+
.ga-key-values dd { overflow: hidden; margin: 4px 0 0; color: #111; text-overflow: ellipsis; white-space: nowrap; }
|
|
736
|
+
.ga-raw-record { margin-top: 16px; color: #171717; font-size: 12px; }
|
|
737
|
+
.ga-raw-record summary { cursor: pointer; font-weight: 650; }
|
|
738
|
+
.ga-raw-record pre { overflow: auto; margin: 10px 0 0; padding: 10px; color: #f7f7f7; background: #111; font: 10px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
739
|
+
.ga-workspace-feedback { top: 68px; color: #f7f7f7; background: #111; border-color: #111; border-radius: 3px; box-shadow: none; }
|
|
740
|
+
@media (max-width: 760px) { .ga-bottom-dock { height: min(720px, 80vh); } .ga-inspector-header, .ga-session-toolbar { padding-right: 12px; padding-left: 12px; } .ga-session-toolbar { flex-wrap: wrap; } .ga-inspector-search { width: 100%; } .ga-session-count { margin-left: 0; } .ga-explorer-layout { flex-direction: column; } [data-slot="resizable-handle"] { width: 100%; height: 1px; } .ga-trace-row { grid-template-columns: 70px 1fr; padding: 8px 12px; } .ga-trace-row span, .ga-trace-row code { grid-column: 2; } .ga-trace-detail { padding: 18px 12px; } .ga-key-values { grid-template-columns: 1fr; } .ga-key-values-wide { grid-column: auto; } }
|
|
741
|
+
`;
|
|
742
|
+
function mountDevtoolsOverlay(options) {
|
|
743
|
+
const selectedDocument = options.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
744
|
+
if (!selectedDocument?.body)
|
|
745
|
+
throw new Error("A mountable document is required");
|
|
746
|
+
const host = selectedDocument.createElement("generative-a11y-devtools");
|
|
747
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
748
|
+
const style = selectedDocument.createElement("style");
|
|
749
|
+
style.textContent = styles;
|
|
750
|
+
const launcher = selectedDocument.createElement("button");
|
|
751
|
+
launcher.className = "ga-launcher";
|
|
752
|
+
launcher.type = "button";
|
|
753
|
+
launcher.textContent = "Open workspace";
|
|
754
|
+
launcher.setAttribute("aria-expanded", "false");
|
|
755
|
+
const panel = selectedDocument.createElement("aside");
|
|
756
|
+
panel.className = "ga-bottom-dock";
|
|
757
|
+
panel.hidden = true;
|
|
758
|
+
panel.tabIndex = -1;
|
|
759
|
+
panel.setAttribute(
|
|
760
|
+
"aria-label",
|
|
761
|
+
"Generative accessibility runtime inspector"
|
|
762
|
+
);
|
|
763
|
+
const reactContainer = selectedDocument.createElement("div");
|
|
764
|
+
reactContainer.style.height = "100%";
|
|
765
|
+
panel.append(reactContainer);
|
|
766
|
+
shadow.append(style, launcher, panel);
|
|
767
|
+
let root;
|
|
768
|
+
let open = false;
|
|
769
|
+
let disposed = false;
|
|
770
|
+
let previousFocus = null;
|
|
771
|
+
let focusBeforePointer = null;
|
|
772
|
+
const asHTMLElement = (element) => {
|
|
773
|
+
const HTMLElementConstructor = selectedDocument.defaultView?.HTMLElement;
|
|
774
|
+
return HTMLElementConstructor && element instanceof HTMLElementConstructor ? element : null;
|
|
775
|
+
};
|
|
776
|
+
const close = () => {
|
|
777
|
+
open = false;
|
|
778
|
+
panel.hidden = true;
|
|
779
|
+
panel.setAttribute("data-state", "collapsed");
|
|
780
|
+
launcher.setAttribute("aria-expanded", "false");
|
|
781
|
+
root?.unmount();
|
|
782
|
+
root = void 0;
|
|
783
|
+
(previousFocus ?? launcher).focus();
|
|
784
|
+
};
|
|
785
|
+
const openPanel = () => {
|
|
786
|
+
open = true;
|
|
787
|
+
panel.hidden = false;
|
|
788
|
+
panel.setAttribute("data-state", "expanded");
|
|
789
|
+
launcher.setAttribute("aria-expanded", "true");
|
|
790
|
+
if (!root) root = (0, import_client.createRoot)(reactContainer);
|
|
791
|
+
const copyText = options.copyText ?? ((value) => {
|
|
792
|
+
const clipboard = selectedDocument.defaultView?.navigator.clipboard;
|
|
793
|
+
if (!clipboard) throw new Error("Clipboard access is unavailable");
|
|
794
|
+
return clipboard.writeText(value);
|
|
795
|
+
});
|
|
796
|
+
root.render(
|
|
797
|
+
(0, import_react2.createElement)(DevtoolsInspector, {
|
|
798
|
+
onClose: close,
|
|
799
|
+
onCopy: copyText,
|
|
800
|
+
store: options.store
|
|
801
|
+
})
|
|
802
|
+
);
|
|
803
|
+
panel.focus();
|
|
804
|
+
};
|
|
805
|
+
launcher.addEventListener("pointerdown", () => {
|
|
806
|
+
const active = asHTMLElement(selectedDocument.activeElement);
|
|
807
|
+
focusBeforePointer = active === host ? null : active;
|
|
808
|
+
});
|
|
809
|
+
launcher.addEventListener("click", () => {
|
|
810
|
+
if (open) close();
|
|
811
|
+
else {
|
|
812
|
+
const documentFocus = asHTMLElement(selectedDocument.activeElement);
|
|
813
|
+
previousFocus = focusBeforePointer ?? asHTMLElement(shadow.activeElement) ?? (documentFocus === selectedDocument.body ? null : documentFocus);
|
|
814
|
+
focusBeforePointer = null;
|
|
815
|
+
openPanel();
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
shadow.addEventListener("keydown", (event) => {
|
|
819
|
+
if (open && event.key === "Escape") close();
|
|
820
|
+
});
|
|
821
|
+
selectedDocument.body.append(host);
|
|
822
|
+
return {
|
|
823
|
+
host,
|
|
824
|
+
dispose() {
|
|
825
|
+
if (disposed) return;
|
|
826
|
+
disposed = true;
|
|
827
|
+
if (open) close();
|
|
828
|
+
else root?.unmount();
|
|
829
|
+
root = void 0;
|
|
830
|
+
host.remove();
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
835
|
+
0 && (module.exports = {
|
|
836
|
+
mountDevtoolsOverlay
|
|
837
|
+
});
|