@weasel-js/forge 1.5.0 → 1.5.1
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/dist/{FrameController-Ba3LaWfq.d.ts → FrameController-BPfCt4PJ.d.ts} +68 -1
- package/dist/{chunk-O5OQZQRZ.js → chunk-2JDYOBWM.js} +5 -5
- package/dist/chunk-2JDYOBWM.js.map +1 -0
- package/dist/{chunk-KKF7ZX5E.js → chunk-2MADHLRA.js} +124 -23
- package/dist/chunk-2MADHLRA.js.map +1 -0
- package/dist/{chunk-UZCXH724.js → chunk-6SRQIHJQ.js} +3 -8
- package/dist/chunk-6SRQIHJQ.js.map +1 -0
- package/dist/{chunk-IOBG7GZQ.js → chunk-FTFR2YPM.js} +2 -2
- package/dist/chunk-FTFR2YPM.js.map +1 -0
- package/dist/chunk-TLO6UHF2.js +103 -0
- package/dist/chunk-TLO6UHF2.js.map +1 -0
- package/dist/{config-DdumOfyd.d.ts → config-CrLpfSq9.d.ts} +6 -2
- package/dist/csf/preview-api.js +2 -2
- package/dist/frame/index.d.ts +5 -4
- package/dist/frame/index.js +5 -5
- package/dist/index.d.ts +97 -5
- package/dist/index.js.map +1 -1
- package/dist/shell/index.css +97 -12
- package/dist/shell/index.css.map +1 -1
- package/dist/shell/index.d.ts +58 -4
- package/dist/shell/index.js +363 -173
- package/dist/shell/index.js.map +1 -1
- package/dist/test/index.d.ts +2 -2
- package/dist/test/index.js +7 -7
- package/dist/test/index.js.map +1 -1
- package/dist/test/play.d.ts +25 -0
- package/dist/test/play.js +14 -0
- package/dist/test/play.js.map +1 -0
- package/dist/vite/index.js +46 -13
- package/dist/vite/index.js.map +1 -1
- package/package.json +14 -5
- package/dist/chunk-IOBG7GZQ.js.map +0 -1
- package/dist/chunk-KKF7ZX5E.js.map +0 -1
- package/dist/chunk-KKVTFMWV.js +0 -59
- package/dist/chunk-KKVTFMWV.js.map +0 -1
- package/dist/chunk-O5OQZQRZ.js.map +0 -1
- package/dist/chunk-UZCXH724.js.map +0 -1
package/dist/shell/index.js
CHANGED
|
@@ -1,106 +1,60 @@
|
|
|
1
|
-
import { schemaFromDescription, openChannel } from '../chunk-
|
|
2
|
-
import { stableStringify, PORT_HANDOFF, PROTOCOL_VERSION } from '../chunk-
|
|
1
|
+
import { schemaFromDescription, openChannel } from '../chunk-2JDYOBWM.js';
|
|
2
|
+
import { stableStringify, PORT_HANDOFF, PROTOCOL_VERSION } from '../chunk-FTFR2YPM.js';
|
|
3
|
+
import { useTrialId, Button, Lab, useLabContext, TrialIdContext, usePersistedState, Select, inferTokenType, ToggleBar, Input, TokenPanel } from '@weasel-js/labkit';
|
|
4
|
+
import { createContext, useContext, useCallback, useSyncExternalStore, useState, useRef, useEffect, useMemo, useLayoutEffect, useId } from 'react';
|
|
5
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
6
|
import { createRoot } from 'react-dom/client';
|
|
4
|
-
import { PropertyList, TextRow, ColorRow, Button, Lab, usePersistedState, useLabContext, TrialIdContext, useTrialId, ToggleBar } from '@weasel-js/labkit';
|
|
5
|
-
import { createContext, memo, useMemo, useCallback, useState, useEffect, useRef, useLayoutEffect, useId, useContext, useSyncExternalStore } from 'react';
|
|
6
7
|
import { TOKEN_MANIFEST } from '@weasel-js/theme';
|
|
7
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
8
|
import { f } from '@weasel-js/labkit/config';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
var HEX = /^#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i;
|
|
12
|
-
var RGB = /^rgba?\(\s*(\d{1,3})[\s,]+(\d{1,3})[\s,]+(\d{1,3})\b/i;
|
|
13
|
-
var COLOR_FUNCTION = /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color|color-mix)\(.+\)$/i;
|
|
14
|
-
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
15
|
-
"transparent",
|
|
16
|
-
"currentcolor",
|
|
17
|
-
"black",
|
|
18
|
-
"white",
|
|
19
|
-
"gray",
|
|
20
|
-
"silver",
|
|
21
|
-
"red",
|
|
22
|
-
"orange",
|
|
23
|
-
"yellow",
|
|
24
|
-
"gold",
|
|
25
|
-
"lime",
|
|
26
|
-
"green",
|
|
27
|
-
"teal",
|
|
28
|
-
"cyan",
|
|
29
|
-
"blue",
|
|
30
|
-
"navy",
|
|
31
|
-
"purple",
|
|
32
|
-
"magenta",
|
|
33
|
-
"pink",
|
|
34
|
-
"brown"
|
|
35
|
-
]);
|
|
36
|
-
function browserSupports() {
|
|
37
|
-
return typeof CSS !== "undefined" && typeof CSS.supports === "function" ? (value) => CSS.supports("color", value) : null;
|
|
38
|
-
}
|
|
39
|
-
function parsesAsColor(value, supports = browserSupports()) {
|
|
40
|
-
const v = value.trim();
|
|
41
|
-
if (!v || v.includes("var(")) return false;
|
|
42
|
-
if (supports) return supports(v);
|
|
43
|
-
return HEX.test(v) || COLOR_FUNCTION.test(v) || KEYWORDS.has(v.toLowerCase());
|
|
44
|
-
}
|
|
45
|
-
function hexOf(v) {
|
|
46
|
-
if (HEX.test(v)) {
|
|
47
|
-
const digits = v.slice(1).toLowerCase();
|
|
48
|
-
return `#${digits.length <= 4 ? [...digits.slice(0, 3)].map((d) => d + d).join("") : digits.slice(0, 6)}`;
|
|
49
|
-
}
|
|
50
|
-
const rgb = RGB.exec(v);
|
|
51
|
-
return rgb ? `#${rgb.slice(1, 4).map((n) => Math.min(255, Number(n)).toString(16).padStart(2, "0")).join("")}` : null;
|
|
52
|
-
}
|
|
53
|
-
var paint;
|
|
54
|
-
function serialized(value) {
|
|
55
|
-
if (paint === void 0) {
|
|
56
|
-
try {
|
|
57
|
-
paint = document.createElement("canvas").getContext("2d");
|
|
58
|
-
} catch {
|
|
59
|
-
paint = null;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (!paint) return null;
|
|
63
|
-
paint.fillStyle = "#000000";
|
|
64
|
-
paint.fillStyle = value;
|
|
65
|
-
const onBlack = String(paint.fillStyle);
|
|
66
|
-
paint.fillStyle = "#ffffff";
|
|
67
|
-
paint.fillStyle = value;
|
|
68
|
-
return onBlack === String(paint.fillStyle) ? onBlack : null;
|
|
69
|
-
}
|
|
70
|
-
function toHex(value) {
|
|
71
|
-
const v = value.trim();
|
|
72
|
-
const direct = hexOf(v);
|
|
73
|
-
if (direct) return direct;
|
|
74
|
-
const browser = typeof document === "undefined" ? null : serialized(v);
|
|
75
|
-
return browser && browser !== v ? hexOf(browser) : null;
|
|
76
|
-
}
|
|
77
|
-
var NONE = {};
|
|
78
|
-
function useCssOverrides() {
|
|
79
|
-
return usePersistedState("fg-css-overrides", NONE, { scope: "trial" });
|
|
80
|
-
}
|
|
81
|
-
var NO_FRAME = { send: null, vars: [] };
|
|
10
|
+
var NO_FRAME = { send: null, vars: [], audit: null, a11y: null, capture: null, size: null };
|
|
82
11
|
function createTrialFrames() {
|
|
83
12
|
const frames = /* @__PURE__ */ new Map();
|
|
13
|
+
const hosts = /* @__PURE__ */ new Map();
|
|
84
14
|
const listeners = /* @__PURE__ */ new Set();
|
|
85
15
|
const changed = () => {
|
|
86
16
|
for (const listener of [...listeners]) listener();
|
|
87
17
|
};
|
|
18
|
+
const patch = (trialId, next) => {
|
|
19
|
+
const frame = frames.get(trialId);
|
|
20
|
+
if (!frame) return;
|
|
21
|
+
frames.set(trialId, { ...frame, ...next });
|
|
22
|
+
changed();
|
|
23
|
+
};
|
|
88
24
|
return {
|
|
89
|
-
connect(trialId,
|
|
90
|
-
frames.
|
|
25
|
+
connect(trialId, calls) {
|
|
26
|
+
const held = frames.get(trialId);
|
|
27
|
+
frames.set(trialId, {
|
|
28
|
+
send: calls.send,
|
|
29
|
+
vars: [],
|
|
30
|
+
audit: calls.audit,
|
|
31
|
+
a11y: null,
|
|
32
|
+
capture: calls.capture,
|
|
33
|
+
size: held?.size ?? null
|
|
34
|
+
});
|
|
91
35
|
changed();
|
|
92
36
|
return () => {
|
|
93
|
-
if (frames.get(trialId)?.send !== send) return;
|
|
37
|
+
if (frames.get(trialId)?.send !== calls.send) return;
|
|
94
38
|
frames.delete(trialId);
|
|
95
39
|
changed();
|
|
96
40
|
};
|
|
97
41
|
},
|
|
98
|
-
report(trialId, vars) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
frames.
|
|
42
|
+
report: (trialId, vars) => patch(trialId, { vars }),
|
|
43
|
+
reportA11y: (trialId, a11y) => patch(trialId, { a11y }),
|
|
44
|
+
reportSize(trialId, size) {
|
|
45
|
+
const frame = frames.get(trialId) ?? NO_FRAME;
|
|
46
|
+
if (frame.size?.width === size.width && frame.size?.height === size.height) return;
|
|
47
|
+
frames.set(trialId, { ...frame, size });
|
|
102
48
|
changed();
|
|
103
49
|
},
|
|
50
|
+
hostRef(trialId) {
|
|
51
|
+
let ref = hosts.get(trialId);
|
|
52
|
+
if (!ref) {
|
|
53
|
+
ref = { current: null };
|
|
54
|
+
hosts.set(trialId, ref);
|
|
55
|
+
}
|
|
56
|
+
return ref;
|
|
57
|
+
},
|
|
104
58
|
get: (trialId) => frames.get(trialId) ?? NO_FRAME,
|
|
105
59
|
subscribe(listener) {
|
|
106
60
|
listeners.add(listener);
|
|
@@ -116,35 +70,128 @@ function useTrialFrame(trialId) {
|
|
|
116
70
|
const read = () => frames?.get(trialId) ?? NO_FRAME;
|
|
117
71
|
return useSyncExternalStore(subscribe, read, read);
|
|
118
72
|
}
|
|
73
|
+
function Finding({ finding }) {
|
|
74
|
+
return /* @__PURE__ */ jsxs("li", { className: "fg-a11y__finding", children: [
|
|
75
|
+
/* @__PURE__ */ jsxs("p", { className: "fg-a11y__help", children: [
|
|
76
|
+
/* @__PURE__ */ jsx("a", { href: finding.helpUrl, target: "_blank", rel: "noreferrer", children: finding.help }),
|
|
77
|
+
finding.impact ? /* @__PURE__ */ jsx("span", { className: "fg-a11y__impact", "data-impact": finding.impact, children: finding.impact }) : null
|
|
78
|
+
] }),
|
|
79
|
+
/* @__PURE__ */ jsx("ul", { className: "fg-a11y__nodes", children: finding.nodes.map((node) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: node.target.join(" ") }) }, `${finding.id}:${node.target.join(",")}`)) })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
function Findings({ title, findings }) {
|
|
83
|
+
if (findings.length === 0) return null;
|
|
84
|
+
return /* @__PURE__ */ jsxs("section", { className: "fg-a11y__group", children: [
|
|
85
|
+
/* @__PURE__ */ jsxs("h3", { className: "fg-a11y__group-title", children: [
|
|
86
|
+
title,
|
|
87
|
+
" (",
|
|
88
|
+
findings.length,
|
|
89
|
+
")"
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsx("ul", { className: "fg-a11y__findings", children: findings.map((finding) => /* @__PURE__ */ jsx(Finding, { finding }, finding.id)) })
|
|
92
|
+
] });
|
|
93
|
+
}
|
|
94
|
+
function A11yPanel() {
|
|
95
|
+
const trialId = useTrialId();
|
|
96
|
+
const frame = useTrialFrame(trialId);
|
|
97
|
+
const [running, setRunning] = useState(false);
|
|
98
|
+
const audit = frame.audit;
|
|
99
|
+
const ran = useRef(null);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (!audit || ran.current === audit) return;
|
|
102
|
+
ran.current = audit;
|
|
103
|
+
setRunning(true);
|
|
104
|
+
void audit().finally(() => setRunning(false));
|
|
105
|
+
}, [audit]);
|
|
106
|
+
const rerun = () => {
|
|
107
|
+
if (!audit) return;
|
|
108
|
+
setRunning(true);
|
|
109
|
+
void audit().finally(() => setRunning(false));
|
|
110
|
+
};
|
|
111
|
+
const outcome = frame.a11y;
|
|
112
|
+
return /* @__PURE__ */ jsxs("div", { className: "fg-a11y", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("div", { className: "fg-a11y__controls", children: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: rerun, disabled: !audit || running, children: running ? "Checking\u2026" : "Re-check" }) }),
|
|
114
|
+
!audit ? /* @__PURE__ */ jsx("p", { className: "fg-a11y__note", children: "No frame is connected." }) : null,
|
|
115
|
+
audit && !outcome ? /* @__PURE__ */ jsx("p", { className: "fg-a11y__note", children: running ? "Running axe\u2026" : "Not checked yet." }) : null,
|
|
116
|
+
outcome && !outcome.ok ? /* @__PURE__ */ jsxs("p", { className: "fg-a11y__note", role: "alert", children: [
|
|
117
|
+
"axe could not run: ",
|
|
118
|
+
outcome.message
|
|
119
|
+
] }) : null,
|
|
120
|
+
outcome?.ok ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
121
|
+
/* @__PURE__ */ jsxs("p", { className: "fg-a11y__tally", children: [
|
|
122
|
+
outcome.report.violations.length,
|
|
123
|
+
" violations \xB7 ",
|
|
124
|
+
outcome.report.incomplete.length,
|
|
125
|
+
" to review \xB7",
|
|
126
|
+
" ",
|
|
127
|
+
outcome.report.passes,
|
|
128
|
+
" passes"
|
|
129
|
+
] }),
|
|
130
|
+
/* @__PURE__ */ jsx(Findings, { title: "Violations", findings: outcome.report.violations }),
|
|
131
|
+
/* @__PURE__ */ jsx(Findings, { title: "Needs review", findings: outcome.report.incomplete })
|
|
132
|
+
] }) : null
|
|
133
|
+
] });
|
|
134
|
+
}
|
|
135
|
+
function FocusedA11y() {
|
|
136
|
+
const { focusedTrialId, trials, instruments } = useLabContext();
|
|
137
|
+
const record = trials.find((trial) => trial.id === focusedTrialId);
|
|
138
|
+
if (!record) return null;
|
|
139
|
+
const instrument = instruments.find((i) => i.name === record.instrumentName);
|
|
140
|
+
return /* @__PURE__ */ jsxs("section", { className: "fg-a11y-focus", "aria-label": "Accessibility", children: [
|
|
141
|
+
/* @__PURE__ */ jsx("p", { className: "fg-a11y__trial", children: record.title ?? instrument?.title ?? record.instrumentName }),
|
|
142
|
+
/* @__PURE__ */ jsx(TrialIdContext.Provider, { value: record.id, children: /* @__PURE__ */ jsx(A11yPanel, {}) })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
var A11Y_SECTION = {
|
|
146
|
+
id: "fg-a11y",
|
|
147
|
+
region: "aside",
|
|
148
|
+
item: { title: "Accessibility", body: /* @__PURE__ */ jsx(FocusedA11y, {}) }
|
|
149
|
+
};
|
|
150
|
+
var NONE = {};
|
|
151
|
+
function useCssOverrides() {
|
|
152
|
+
return usePersistedState("fg-css-overrides", NONE, { scope: "trial" });
|
|
153
|
+
}
|
|
119
154
|
var TABS = [
|
|
120
155
|
{ value: "theme", label: "Theme" },
|
|
121
156
|
{ value: "story", label: "Story" }
|
|
122
157
|
];
|
|
123
|
-
var
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
/* @__PURE__ */ jsxs(PropertyList, { className: "fg-css-var__rows", pack: "one-up", density: "tight", children: [
|
|
129
|
-
/* @__PURE__ */ jsx(TextRow, { label: name, value, onChange }),
|
|
130
|
-
hex ? /* @__PURE__ */ jsx(ColorRow, { label: "Color", value: hex, onChange }) : null
|
|
131
|
-
] }),
|
|
132
|
-
overridden ? /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", ariaLabel: `Reset ${name}`, onClick: reset, children: "Reset" }) : null
|
|
133
|
-
] });
|
|
134
|
-
});
|
|
158
|
+
var MANIFEST = new Map(TOKEN_MANIFEST.map((token) => [token.name, token]));
|
|
159
|
+
function groupOf(name) {
|
|
160
|
+
const segments = name.replace(/^--/, "").split("-");
|
|
161
|
+
return segments.length > 1 ? segments.slice(0, -1).join("-") : name.replace(/^--/, "");
|
|
162
|
+
}
|
|
135
163
|
function CssVarsPanel() {
|
|
136
164
|
const trialId = useTrialId();
|
|
137
165
|
const frame = useTrialFrame(trialId);
|
|
138
166
|
const [overrides, setOverrides] = useCssOverrides();
|
|
167
|
+
const [folds, setFolds] = usePersistedState(
|
|
168
|
+
"fg-css-vars-folds",
|
|
169
|
+
{},
|
|
170
|
+
{ scope: "lab" }
|
|
171
|
+
);
|
|
139
172
|
const [tab, setTab] = useState("theme");
|
|
140
173
|
const [filter, setFilter] = useState("");
|
|
141
|
-
const
|
|
142
|
-
if (tab === "story")
|
|
174
|
+
const tokens = useMemo(() => {
|
|
175
|
+
if (tab === "story") {
|
|
176
|
+
return frame.vars.map(({ name, value }) => {
|
|
177
|
+
const known = MANIFEST.get(name);
|
|
178
|
+
return { name, type: known?.type ?? inferTokenType(value), group: known?.group ?? groupOf(name), value };
|
|
179
|
+
});
|
|
180
|
+
}
|
|
143
181
|
const reported = new Map(frame.vars.map((v) => [v.name, v.value]));
|
|
144
|
-
return TOKEN_MANIFEST.map((token) => ({
|
|
182
|
+
return TOKEN_MANIFEST.map((token) => ({
|
|
183
|
+
name: token.name,
|
|
184
|
+
type: token.type,
|
|
185
|
+
group: token.group,
|
|
186
|
+
value: reported.get(token.name) ?? token.defaultValue,
|
|
187
|
+
description: token.description
|
|
188
|
+
}));
|
|
145
189
|
}, [tab, frame.vars]);
|
|
146
190
|
const query = filter.trim().toLowerCase();
|
|
147
|
-
const shown =
|
|
191
|
+
const shown = tokens.map((token) => {
|
|
192
|
+
const override = overrides[token.name];
|
|
193
|
+
return override === void 0 ? token : { ...token, value: override, overridden: true };
|
|
194
|
+
}).filter((token) => !query || token.name.toLowerCase().includes(query) || token.value.toLowerCase().includes(query));
|
|
148
195
|
const send = frame.send;
|
|
149
196
|
const write = useCallback(
|
|
150
197
|
(name, value) => {
|
|
@@ -156,36 +203,43 @@ function CssVarsPanel() {
|
|
|
156
203
|
},
|
|
157
204
|
[setOverrides, send]
|
|
158
205
|
);
|
|
206
|
+
const onCollapsedChange = useCallback(
|
|
207
|
+
(category, collapsed) => setFolds((prev) => ({ ...prev, [category]: collapsed })),
|
|
208
|
+
[setFolds]
|
|
209
|
+
);
|
|
159
210
|
return /* @__PURE__ */ jsxs("div", { className: "fg-css-vars", children: [
|
|
160
|
-
/* @__PURE__ */
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
211
|
+
/* @__PURE__ */ jsxs("div", { className: "fg-css-vars__controls", children: [
|
|
212
|
+
/* @__PURE__ */ jsx(
|
|
213
|
+
ToggleBar,
|
|
214
|
+
{
|
|
215
|
+
ariaLabel: "Variables",
|
|
216
|
+
variant: "flat",
|
|
217
|
+
items: TABS,
|
|
218
|
+
value: tab,
|
|
219
|
+
onChange: (next) => {
|
|
220
|
+
if (next) setTab(next);
|
|
221
|
+
}
|
|
169
222
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
shown.length === 0 ? /* @__PURE__ */ jsx("p", { className: "fg-css-vars__empty", children:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
223
|
+
),
|
|
224
|
+
/* @__PURE__ */ jsx(Input, { "aria-label": "Filter", placeholder: "Filter by name or value", value: filter, onChange: setFilter })
|
|
225
|
+
] }),
|
|
226
|
+
shown.length === 0 ? /* @__PURE__ */ jsx("p", { className: "fg-css-vars__empty", children: tokens.length === 0 ? "The story\u2019s frame has reported no variables." : "No variables match." }) : /* @__PURE__ */ jsx(TokenPanel, { tokens: shown, onChange: write, collapsed: folds, onCollapsedChange })
|
|
227
|
+
] });
|
|
228
|
+
}
|
|
229
|
+
function FocusedCssVars() {
|
|
230
|
+
const { focusedTrialId, trials, instruments } = useLabContext();
|
|
231
|
+
const record = trials.find((trial) => trial.id === focusedTrialId);
|
|
232
|
+
if (!record) return null;
|
|
233
|
+
const instrument = instruments.find((i) => i.name === record.instrumentName);
|
|
234
|
+
return /* @__PURE__ */ jsxs("section", { className: "fg-css-vars-focus", "aria-label": "CSS Vars", children: [
|
|
235
|
+
/* @__PURE__ */ jsx("p", { className: "fg-css-vars__trial", children: record.title ?? instrument?.title ?? record.instrumentName }),
|
|
236
|
+
/* @__PURE__ */ jsx(TrialIdContext.Provider, { value: record.id, children: /* @__PURE__ */ jsx(CssVarsPanel, {}) })
|
|
183
237
|
] });
|
|
184
238
|
}
|
|
185
239
|
var CSS_VARS_SECTION = {
|
|
186
240
|
id: "fg-css-vars",
|
|
187
|
-
region: "
|
|
188
|
-
item: { title: "CSS Vars", body: /* @__PURE__ */ jsx(
|
|
241
|
+
region: "aside",
|
|
242
|
+
item: { title: "CSS Vars", body: /* @__PURE__ */ jsx(FocusedCssVars, {}) }
|
|
189
243
|
};
|
|
190
244
|
var GLOBALS_KEY = "$globals";
|
|
191
245
|
var FOLLOW_LAB = "lab";
|
|
@@ -223,7 +277,7 @@ function withGlobals(schema, declarations) {
|
|
|
223
277
|
f.enum(FOLLOW_LAB, [{ value: FOLLOW_LAB, label: "Lab" }, ...declaration.options]).label(declaration.label)
|
|
224
278
|
])
|
|
225
279
|
);
|
|
226
|
-
const group = f.group(leaves).label("").section("Globals");
|
|
280
|
+
const group = f.group(leaves).label("").section("Globals", { layout: "inline", pack: "pairs" });
|
|
227
281
|
return f.schema({ ...schema.nodes, [GLOBALS_KEY]: group });
|
|
228
282
|
}
|
|
229
283
|
var RECORD = "fg-globals";
|
|
@@ -239,13 +293,13 @@ function useLabGlobals(declarations) {
|
|
|
239
293
|
function GlobalsToolbar({ declarations }) {
|
|
240
294
|
const [values, set] = useLabGlobals(declarations);
|
|
241
295
|
return /* @__PURE__ */ jsx("div", { className: "fg-globals", role: "toolbar", "aria-label": "Globals", children: Object.entries(declarations).map(([key, declaration]) => /* @__PURE__ */ jsx(
|
|
242
|
-
|
|
296
|
+
Select,
|
|
243
297
|
{
|
|
244
|
-
className: "fg-globals__select",
|
|
245
298
|
"aria-label": declaration.label,
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
299
|
+
width: "fit",
|
|
300
|
+
selectedKey: String(values[key]),
|
|
301
|
+
onSelectionChange: (value) => set(key, value),
|
|
302
|
+
options: declaration.options
|
|
249
303
|
},
|
|
250
304
|
key
|
|
251
305
|
)) });
|
|
@@ -383,10 +437,11 @@ function StoryTree({ ctx, index }) {
|
|
|
383
437
|
setFocusKey(key);
|
|
384
438
|
items.current.get(key)?.focus();
|
|
385
439
|
};
|
|
386
|
-
const activate = (entry,
|
|
387
|
-
const
|
|
388
|
-
if (
|
|
389
|
-
else
|
|
440
|
+
const activate = (entry, another) => {
|
|
441
|
+
const focused = ctx.trials.find((trial) => trial.id === ctx.focusedTrialId);
|
|
442
|
+
if (another || !focused) ctx.addTrial(entry.id);
|
|
443
|
+
else if (focused.instrumentName === entry.id) revealTrial(focused.id);
|
|
444
|
+
else ctx.swapTrial(focused.id, entry.id);
|
|
390
445
|
setRoute(entry.id);
|
|
391
446
|
};
|
|
392
447
|
const onKeyDown = (event) => {
|
|
@@ -419,7 +474,7 @@ function StoryTree({ ctx, index }) {
|
|
|
419
474
|
case "Enter":
|
|
420
475
|
case " ":
|
|
421
476
|
if (node.kind === "folder") setOpen(node.path, !isOpen(node.path));
|
|
422
|
-
else activate(node.entry, event.
|
|
477
|
+
else activate(node.entry, event.shiftKey);
|
|
423
478
|
break;
|
|
424
479
|
default:
|
|
425
480
|
return;
|
|
@@ -469,10 +524,10 @@ function StoryTree({ ctx, index }) {
|
|
|
469
524
|
"aria-current": openIds.has(entry.id) ? "true" : void 0,
|
|
470
525
|
className: "fg-tree__item fg-tree__story",
|
|
471
526
|
onClick: (event) => {
|
|
472
|
-
if (event.button !== 0 || event.
|
|
527
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.altKey) return;
|
|
473
528
|
event.preventDefault();
|
|
474
529
|
setFocusKey(keyOf(node));
|
|
475
|
-
activate(entry, event.
|
|
530
|
+
activate(entry, event.shiftKey);
|
|
476
531
|
},
|
|
477
532
|
children: /* @__PURE__ */ jsx("span", { className: "fg-tree__label", children: entry.name })
|
|
478
533
|
},
|
|
@@ -504,26 +559,36 @@ var KEPT_CONFIGS = 50;
|
|
|
504
559
|
var UNANSWERED = stableStringify({ hidden: [], errors: {} });
|
|
505
560
|
function createAnswerBook() {
|
|
506
561
|
const byConfig = /* @__PURE__ */ new Map();
|
|
507
|
-
let errors = {};
|
|
508
562
|
const listeners = /* @__PURE__ */ new Set();
|
|
563
|
+
const held = /* @__PURE__ */ new Map();
|
|
564
|
+
const keyOf2 = (config) => stableStringify(storyConfig(config));
|
|
565
|
+
const answerFor = (config) => byConfig.get(keyOf2(config));
|
|
509
566
|
return {
|
|
510
567
|
record(answers) {
|
|
511
568
|
const key = stableStringify({ hidden: answers.hidden, errors: answers.errors });
|
|
512
569
|
const changed = key !== (byConfig.get(answers.configKey)?.key ?? UNANSWERED);
|
|
513
570
|
byConfig.delete(answers.configKey);
|
|
514
|
-
byConfig.set(answers.configKey, { hidden: answers.hidden, key });
|
|
571
|
+
byConfig.set(answers.configKey, { hidden: answers.hidden, errors: answers.errors, key });
|
|
515
572
|
if (byConfig.size > KEPT_CONFIGS) {
|
|
516
573
|
const oldest = byConfig.keys().next().value;
|
|
517
574
|
if (oldest !== void 0) byConfig.delete(oldest);
|
|
518
575
|
}
|
|
519
|
-
|
|
520
|
-
|
|
576
|
+
if (changed && held.has(answers.configKey)) for (const fn of listeners) fn();
|
|
577
|
+
},
|
|
578
|
+
hold(config) {
|
|
579
|
+
const key = keyOf2(config);
|
|
580
|
+
held.set(key, (held.get(key) ?? 0) + 1);
|
|
581
|
+
return () => {
|
|
582
|
+
const count = (held.get(key) ?? 1) - 1;
|
|
583
|
+
if (count > 0) held.set(key, count);
|
|
584
|
+
else held.delete(key);
|
|
585
|
+
};
|
|
521
586
|
},
|
|
522
587
|
hidden(path, config) {
|
|
523
|
-
const hidden =
|
|
588
|
+
const hidden = answerFor(config)?.hidden;
|
|
524
589
|
return hidden?.some((h) => path === h || path.startsWith(`${h}.`)) ?? false;
|
|
525
590
|
},
|
|
526
|
-
errors: (path) => errors[path] ?? [],
|
|
591
|
+
errors: (path, config) => answerFor(config)?.errors[path] ?? [],
|
|
527
592
|
subscribe(fn) {
|
|
528
593
|
listeners.add(fn);
|
|
529
594
|
return () => {
|
|
@@ -536,18 +601,43 @@ function createAnswerBook() {
|
|
|
536
601
|
// src/shell/readyKey.ts
|
|
537
602
|
var readyKey = (ready) => stableStringify({ schema: ready.schema, layout: ready.layout, viewport: ready.viewport });
|
|
538
603
|
var START_TIMEOUT_MS = 1e4;
|
|
604
|
+
var requests = 0;
|
|
605
|
+
var IN_VIEW_MARGIN = "50%";
|
|
606
|
+
function useInView(ref) {
|
|
607
|
+
const [inView, setInView] = useState(true);
|
|
608
|
+
useEffect(() => {
|
|
609
|
+
const el = ref.current;
|
|
610
|
+
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
611
|
+
const observer = new IntersectionObserver(
|
|
612
|
+
(entries) => {
|
|
613
|
+
const last = entries.at(-1);
|
|
614
|
+
if (last) setInView(last.isIntersecting);
|
|
615
|
+
},
|
|
616
|
+
{ rootMargin: IN_VIEW_MARGIN }
|
|
617
|
+
);
|
|
618
|
+
observer.observe(el);
|
|
619
|
+
return () => observer.disconnect();
|
|
620
|
+
}, [ref]);
|
|
621
|
+
return inView;
|
|
622
|
+
}
|
|
539
623
|
function closeLink(link) {
|
|
540
624
|
if (!link.current) return;
|
|
541
625
|
clearTimeout(link.current.timer);
|
|
626
|
+
for (const settle2 of link.current.pending.values()) settle2.gone();
|
|
627
|
+
link.current.pending.clear();
|
|
542
628
|
link.current.disconnect();
|
|
543
629
|
link.current.channel.close();
|
|
544
630
|
link.current = null;
|
|
545
631
|
}
|
|
632
|
+
function settle(link, id, value) {
|
|
633
|
+
link.pending.get(id)?.resolve?.(value);
|
|
634
|
+
link.pending.delete(id);
|
|
635
|
+
}
|
|
546
636
|
function mismatchMessage(mismatch) {
|
|
547
637
|
return mismatch.reason === "version" ? `Frame speaks protocol ${String(mismatch.version)}; this workshop speaks ${PROTOCOL_VERSION}` : "Frame sent a message that is not a forge envelope";
|
|
548
638
|
}
|
|
549
639
|
function FrameView(props) {
|
|
550
|
-
const { entry, frameUrl, descriptionKey, ctx } = props;
|
|
640
|
+
const { entry, frameUrl, answers, descriptionKey, ctx } = props;
|
|
551
641
|
const labGlobals2 = useContext(StoryGlobalsContext);
|
|
552
642
|
const pins = ctx.config?.[GLOBALS_KEY];
|
|
553
643
|
const globals = useMemo(() => effectiveGlobals(labGlobals2, pins), [labGlobals2, pins]);
|
|
@@ -556,10 +646,13 @@ function FrameView(props) {
|
|
|
556
646
|
const [overrides] = useCssOverrides();
|
|
557
647
|
const src = `${frameUrl}#${entry.id}`;
|
|
558
648
|
const iframeRef = useRef(null);
|
|
649
|
+
const hostRef = useRef(null);
|
|
650
|
+
const inView = useInView(hostRef);
|
|
559
651
|
const link = useRef(null);
|
|
560
652
|
const latest = useRef({ ...props, globals, overrides });
|
|
561
653
|
latest.current = { ...props, globals, overrides };
|
|
562
654
|
const [fault, setFault] = useState(null);
|
|
655
|
+
const [pending, setPending] = useState(true);
|
|
563
656
|
const init = (current) => {
|
|
564
657
|
const { ctx: live, globals: liveGlobals } = latest.current;
|
|
565
658
|
current.awaiting = null;
|
|
@@ -568,7 +661,7 @@ function FrameView(props) {
|
|
|
568
661
|
current.channel.send({ type: "init", ...current.sent });
|
|
569
662
|
};
|
|
570
663
|
const receive = (current, msg) => {
|
|
571
|
-
const { ctx: live, answers, onReady } = latest.current;
|
|
664
|
+
const { ctx: live, answers: answers2, onReady } = latest.current;
|
|
572
665
|
switch (msg.type) {
|
|
573
666
|
case "ready": {
|
|
574
667
|
clearTimeout(current.timer);
|
|
@@ -582,6 +675,11 @@ function FrameView(props) {
|
|
|
582
675
|
if (current.awaiting === key && key === latest.current.descriptionKey) init(current);
|
|
583
676
|
break;
|
|
584
677
|
}
|
|
678
|
+
case "rendered":
|
|
679
|
+
setPending(false);
|
|
680
|
+
current.hasRendered = true;
|
|
681
|
+
for (const ask of current.queued.splice(0)) ask();
|
|
682
|
+
break;
|
|
585
683
|
case "setConfig":
|
|
586
684
|
if (!isGlobalsPath(msg.path)) live.setConfig(msg.path, msg.value);
|
|
587
685
|
break;
|
|
@@ -590,11 +688,25 @@ function FrameView(props) {
|
|
|
590
688
|
live.setState(msg.state);
|
|
591
689
|
break;
|
|
592
690
|
case "answers":
|
|
593
|
-
|
|
691
|
+
answers2.record(msg.answers);
|
|
594
692
|
break;
|
|
595
693
|
case "vars":
|
|
596
694
|
if (trialId) frames?.report(trialId, msg.vars);
|
|
597
695
|
break;
|
|
696
|
+
case "size":
|
|
697
|
+
if (trialId) frames?.reportSize(trialId, { width: msg.width, height: msg.height });
|
|
698
|
+
break;
|
|
699
|
+
case "a11y": {
|
|
700
|
+
const outcome = msg.ok ? { ok: true, report: msg.report } : { ok: false, message: msg.message };
|
|
701
|
+
if (trialId) frames?.reportA11y(trialId, outcome);
|
|
702
|
+
settle(current, msg.id, outcome);
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
case "capture":
|
|
706
|
+
if (msg.ok) settle(current, msg.id, msg.picture);
|
|
707
|
+
else current.pending.get(msg.id)?.fail(new Error(msg.message));
|
|
708
|
+
current.pending.delete(msg.id);
|
|
709
|
+
break;
|
|
598
710
|
case "fault":
|
|
599
711
|
if (msg.phase === "render" && msg.seq !== void 0 && msg.seq < current.inputs) break;
|
|
600
712
|
clearTimeout(current.timer);
|
|
@@ -604,6 +716,7 @@ function FrameView(props) {
|
|
|
604
716
|
};
|
|
605
717
|
const onLoad = () => {
|
|
606
718
|
closeLink(link);
|
|
719
|
+
setPending(true);
|
|
607
720
|
const target = iframeRef.current?.contentWindow;
|
|
608
721
|
if (!target) return;
|
|
609
722
|
const { port1, port2 } = new MessageChannel();
|
|
@@ -614,14 +727,58 @@ function FrameView(props) {
|
|
|
614
727
|
setFault({ phase: "protocol", message: mismatchMessage(mismatch) });
|
|
615
728
|
}
|
|
616
729
|
});
|
|
617
|
-
const
|
|
730
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
731
|
+
const request = (id, msg, gone) => new Promise((resolve, reject) => {
|
|
732
|
+
waiting.set(id, {
|
|
733
|
+
resolve,
|
|
734
|
+
fail: reject,
|
|
735
|
+
gone: () => gone(resolve, reject)
|
|
736
|
+
});
|
|
737
|
+
const ask = () => channel.send(msg);
|
|
738
|
+
if (current.hasRendered) ask();
|
|
739
|
+
else current.queued.push(ask);
|
|
740
|
+
});
|
|
741
|
+
const audit = () => {
|
|
742
|
+
const id = `a11y-${requests += 1}`;
|
|
743
|
+
return request(
|
|
744
|
+
id,
|
|
745
|
+
{ type: "a11y.run", id },
|
|
746
|
+
(resolve) => resolve({ ok: false, message: "The frame went away" })
|
|
747
|
+
);
|
|
748
|
+
};
|
|
749
|
+
const capture = () => {
|
|
750
|
+
const id = `capture-${requests += 1}`;
|
|
751
|
+
return request(
|
|
752
|
+
id,
|
|
753
|
+
{ type: "capture.run", id },
|
|
754
|
+
(_resolve, fail) => fail(new Error("The frame could not draw itself"))
|
|
755
|
+
);
|
|
756
|
+
};
|
|
757
|
+
const disconnect = frames && trialId ? frames.connect(trialId, { send: channel.send, audit, capture }) : () => {
|
|
758
|
+
};
|
|
759
|
+
const current = {
|
|
760
|
+
channel,
|
|
761
|
+
timer,
|
|
762
|
+
awaiting: null,
|
|
763
|
+
sent: null,
|
|
764
|
+
inputs: 0,
|
|
765
|
+
disconnect,
|
|
766
|
+
pending: waiting,
|
|
767
|
+
hasRendered: false,
|
|
768
|
+
queued: []
|
|
618
769
|
};
|
|
619
|
-
const current = { channel, timer, awaiting: null, sent: null, inputs: 0, disconnect };
|
|
620
770
|
link.current = current;
|
|
621
771
|
channel.on((msg) => receive(current, msg));
|
|
622
772
|
target.postMessage({ type: PORT_HANDOFF }, location.origin, [port2]);
|
|
623
773
|
};
|
|
624
774
|
useEffect(() => () => closeLink(link), []);
|
|
775
|
+
useEffect(() => {
|
|
776
|
+
if (inView) return;
|
|
777
|
+
closeLink(link);
|
|
778
|
+
setPending(true);
|
|
779
|
+
setFault(null);
|
|
780
|
+
}, [inView]);
|
|
781
|
+
useEffect(() => answers.hold(ctx.config), [answers, ctx.config]);
|
|
625
782
|
useEffect(() => {
|
|
626
783
|
const current = link.current;
|
|
627
784
|
if (!current) return;
|
|
@@ -653,25 +810,54 @@ function FrameView(props) {
|
|
|
653
810
|
}
|
|
654
811
|
if (input) setFault((shown) => shown?.phase === "render" ? null : shown);
|
|
655
812
|
}, [ctx.config, ctx.state, globals, descriptionKey]);
|
|
656
|
-
return /* @__PURE__ */ jsxs(
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
{
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
813
|
+
return /* @__PURE__ */ jsxs(
|
|
814
|
+
"div",
|
|
815
|
+
{
|
|
816
|
+
ref: (el) => {
|
|
817
|
+
hostRef.current = el;
|
|
818
|
+
if (trialId && frames) frames.hostRef(trialId).current = el;
|
|
819
|
+
},
|
|
820
|
+
className: "fg-frame-host",
|
|
821
|
+
children: [
|
|
822
|
+
inView ? /* @__PURE__ */ jsx(
|
|
823
|
+
"iframe",
|
|
824
|
+
{
|
|
825
|
+
ref: iframeRef,
|
|
826
|
+
className: "fg-frame-view",
|
|
827
|
+
src,
|
|
828
|
+
title: `${entry.title} / ${entry.name}`,
|
|
829
|
+
onLoad,
|
|
830
|
+
"data-pending": pending && !fault ? "" : void 0
|
|
831
|
+
}
|
|
832
|
+
) : null,
|
|
833
|
+
fault ? /* @__PURE__ */ jsxs("div", { className: "fg-fault", role: "alert", children: [
|
|
834
|
+
fault.phase ? /* @__PURE__ */ jsx("span", { className: "fg-fault__phase", children: fault.phase }) : null,
|
|
835
|
+
/* @__PURE__ */ jsx("p", { className: "fg-fault__message", children: fault.message })
|
|
836
|
+
] }) : null
|
|
837
|
+
]
|
|
838
|
+
}
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
function annotationsOn(frames) {
|
|
842
|
+
return {
|
|
843
|
+
targets: (_state, _config, trial) => {
|
|
844
|
+
const ref = frames.hostRef(trial.id);
|
|
845
|
+
const frame = frames.get(trial.id);
|
|
846
|
+
const box = frame.size ?? { width: ref.current?.clientWidth ?? 0, height: ref.current?.clientHeight ?? 0 };
|
|
847
|
+
const capture = frame.capture;
|
|
848
|
+
return [
|
|
849
|
+
{
|
|
850
|
+
id: "story",
|
|
851
|
+
ref,
|
|
852
|
+
content: { w: Math.max(1, box.width), h: Math.max(1, box.height) },
|
|
853
|
+
...capture ? { base: () => capture() } : {}
|
|
854
|
+
}
|
|
855
|
+
];
|
|
856
|
+
}
|
|
857
|
+
};
|
|
672
858
|
}
|
|
673
859
|
function storyInstrument(options) {
|
|
674
|
-
const { entry, ready, answers, frameUrl, onReady, globals = {} } = options;
|
|
860
|
+
const { entry, ready, answers, frameUrl, onReady, globals = {}, frames } = options;
|
|
675
861
|
const config = withGlobals(
|
|
676
862
|
ready ? schemaFromDescription(ready.schema, answers) : f.schema({}),
|
|
677
863
|
globals
|
|
@@ -694,6 +880,7 @@ function storyInstrument(options) {
|
|
|
694
880
|
ctx
|
|
695
881
|
}
|
|
696
882
|
),
|
|
883
|
+
...frames ? { annotations: annotationsOn(frames) } : {},
|
|
697
884
|
...ready?.viewport ? { stage: { size: { width: ready.viewport.width, height: ready.viewport.height } } } : {}
|
|
698
885
|
};
|
|
699
886
|
}
|
|
@@ -702,7 +889,7 @@ function storyInstrument(options) {
|
|
|
702
889
|
var NO_GLOBALS = {};
|
|
703
890
|
var pruned = (map, ids) => [...map.keys()].every((id) => ids.has(id)) ? map : new Map([...map].filter(([id]) => ids.has(id)));
|
|
704
891
|
function useStoryRegistry(index, options) {
|
|
705
|
-
const { frameUrl, globals = NO_GLOBALS } = options;
|
|
892
|
+
const { frameUrl, globals = NO_GLOBALS, frames } = options;
|
|
706
893
|
const [readies, setReadies] = useState(() => /* @__PURE__ */ new Map());
|
|
707
894
|
const [revisions, setRevisions] = useState(() => /* @__PURE__ */ new Map());
|
|
708
895
|
const onReady = useCallback((entry, ready) => {
|
|
@@ -729,20 +916,21 @@ function useStoryRegistry(index, options) {
|
|
|
729
916
|
const answers = previous.books.get(entry.id) ?? createAnswerBook();
|
|
730
917
|
books.set(entry.id, answers);
|
|
731
918
|
const held = previous.built.get(entry.id);
|
|
732
|
-
const kept = held && held.entryKey === entryKey && held.ready === ready && held.frameUrl === frameUrl && held.globals === globals && held.revision === revision ? held : {
|
|
919
|
+
const kept = held && held.entryKey === entryKey && held.ready === ready && held.frameUrl === frameUrl && held.globals === globals && held.frames === frames && held.revision === revision ? held : {
|
|
733
920
|
entryKey,
|
|
734
921
|
ready,
|
|
735
922
|
frameUrl,
|
|
736
923
|
globals,
|
|
924
|
+
frames,
|
|
737
925
|
revision,
|
|
738
|
-
instrument: storyInstrument({ entry, ready, answers, frameUrl, onReady, globals })
|
|
926
|
+
instrument: storyInstrument({ entry, ready, answers, frameUrl, onReady, globals, ...frames ? { frames } : {} })
|
|
739
927
|
};
|
|
740
928
|
built.set(entry.id, kept);
|
|
741
929
|
return kept.instrument;
|
|
742
930
|
});
|
|
743
931
|
const unchanged = list.length === previous.list.length && list.every((i, n) => i === previous.list[n]);
|
|
744
932
|
return { built, books, list: unchanged ? previous.list : list };
|
|
745
|
-
}, [index, readies, revisions, frameUrl, globals, onReady]);
|
|
933
|
+
}, [index, readies, revisions, frameUrl, globals, frames, onReady]);
|
|
746
934
|
useLayoutEffect(() => {
|
|
747
935
|
committed.current = cache;
|
|
748
936
|
}, [cache]);
|
|
@@ -757,7 +945,6 @@ function useStoryRegistry(index, options) {
|
|
|
757
945
|
return { instruments: cache.list, onReady };
|
|
758
946
|
}
|
|
759
947
|
var NO_DECLARATIONS = {};
|
|
760
|
-
var TRIAL_CHROME = [CSS_VARS_SECTION];
|
|
761
948
|
function initialStory(index, fallback) {
|
|
762
949
|
const route = readRoute();
|
|
763
950
|
return route !== null && index.some((entry) => entry.id === route) ? route : fallback;
|
|
@@ -775,8 +962,8 @@ function RouteOpener({ index }) {
|
|
|
775
962
|
}
|
|
776
963
|
function Workshop({ index, frameUrl, config, stories = [], storageKey, storage }) {
|
|
777
964
|
const declarations = config?.globals ?? NO_DECLARATIONS;
|
|
778
|
-
const registry = useStoryRegistry(index, { frameUrl, globals: declarations });
|
|
779
965
|
const [frames] = useState(createTrialFrames);
|
|
966
|
+
const registry = useStoryRegistry(index, { frameUrl, globals: declarations, frames });
|
|
780
967
|
const [labValues, setLabValues] = useState(() => labGlobals(declarations, void 0));
|
|
781
968
|
const reportLabValues = useCallback(
|
|
782
969
|
(next) => setLabValues((prev) => stableStringify(prev) === stableStringify(next) ? prev : next),
|
|
@@ -785,6 +972,8 @@ function Workshop({ index, frameUrl, config, stories = [], storageKey, storage }
|
|
|
785
972
|
const labChrome = useMemo(
|
|
786
973
|
() => [
|
|
787
974
|
{ id: "fg-stories", region: "sidebar", render: (ctx) => /* @__PURE__ */ jsx(StoryTree, { ctx, index }) },
|
|
975
|
+
CSS_VARS_SECTION,
|
|
976
|
+
A11Y_SECTION,
|
|
788
977
|
...Object.keys(declarations).length > 0 ? [{ id: "fg-globals", region: "header", render: () => /* @__PURE__ */ jsx(GlobalsToolbar, { declarations }) }] : [],
|
|
789
978
|
...config?.labChrome ?? []
|
|
790
979
|
],
|
|
@@ -806,9 +995,10 @@ function Workshop({ index, frameUrl, config, stories = [], storageKey, storage }
|
|
|
806
995
|
storageKey: storageKey ?? "weaselforge",
|
|
807
996
|
...storage ? { storage } : {},
|
|
808
997
|
labChrome,
|
|
809
|
-
chrome: TRIAL_CHROME,
|
|
810
998
|
addTrial: false,
|
|
811
999
|
...config?.controls ? { controls: config.controls } : {},
|
|
1000
|
+
...config?.pages ? { pages: config.pages } : {},
|
|
1001
|
+
...config?.path !== void 0 ? { path: config.path } : {},
|
|
812
1002
|
children: [
|
|
813
1003
|
/* @__PURE__ */ jsx(RouteOpener, { index }),
|
|
814
1004
|
/* @__PURE__ */ jsx(LabGlobals, { declarations, onChange: reportLabValues })
|
|
@@ -831,6 +1021,6 @@ function mountWorkshop({ container, ...props }) {
|
|
|
831
1021
|
};
|
|
832
1022
|
}
|
|
833
1023
|
|
|
834
|
-
export { StoryGlobalsContext, Workshop, mountWorkshop, useStoryRegistry };
|
|
1024
|
+
export { A11Y_SECTION, A11yPanel, StoryGlobalsContext, TrialFramesContext, Workshop, mountWorkshop, useStoryRegistry, useTrialFrame };
|
|
835
1025
|
//# sourceMappingURL=index.js.map
|
|
836
1026
|
//# sourceMappingURL=index.js.map
|