@weasel-js/forge 1.5.2 → 1.6.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.
Files changed (39) hide show
  1. package/README.md +72 -10
  2. package/dist/{FrameController-eZM3hlcE.d.ts → FrameController-BspC9Zr5.d.ts} +61 -4
  3. package/dist/chunk-A4JOEGYQ.js +325 -0
  4. package/dist/chunk-A4JOEGYQ.js.map +1 -0
  5. package/dist/{chunk-5YHEO26U.js → chunk-FWPBKKYB.js} +58 -240
  6. package/dist/chunk-FWPBKKYB.js.map +1 -0
  7. package/dist/{chunk-6SRQIHJQ.js → chunk-HRGPFQBW.js} +3 -3
  8. package/dist/{chunk-6SRQIHJQ.js.map → chunk-HRGPFQBW.js.map} +1 -1
  9. package/dist/chunk-PO5JLVYT.js +318 -0
  10. package/dist/chunk-PO5JLVYT.js.map +1 -0
  11. package/dist/{chunk-TLO6UHF2.js → chunk-VEKEBILL.js} +17 -4
  12. package/dist/chunk-VEKEBILL.js.map +1 -0
  13. package/dist/{config-CSVP6duU.d.ts → config-DU_WuORS.d.ts} +7 -1
  14. package/dist/csf/preview-api.js +1 -2
  15. package/dist/csf/preview-api.js.map +1 -1
  16. package/dist/frame/index.css +102 -0
  17. package/dist/frame/index.css.map +1 -1
  18. package/dist/frame/index.d.ts +11 -3
  19. package/dist/frame/index.js +365 -5
  20. package/dist/frame/index.js.map +1 -1
  21. package/dist/index.d.ts +4 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/shell/index.css +96 -19
  24. package/dist/shell/index.css.map +1 -1
  25. package/dist/shell/index.d.ts +75 -15
  26. package/dist/shell/index.js +762 -214
  27. package/dist/shell/index.js.map +1 -1
  28. package/dist/test/index.d.ts +3 -3
  29. package/dist/test/index.js +67 -72
  30. package/dist/test/index.js.map +1 -1
  31. package/dist/vite/index.js +43 -5
  32. package/dist/vite/index.js.map +1 -1
  33. package/package.json +5 -4
  34. package/dist/chunk-2JDYOBWM.js +0 -118
  35. package/dist/chunk-2JDYOBWM.js.map +0 -1
  36. package/dist/chunk-5YHEO26U.js.map +0 -1
  37. package/dist/chunk-FTFR2YPM.js +0 -13
  38. package/dist/chunk-FTFR2YPM.js.map +0 -1
  39. package/dist/chunk-TLO6UHF2.js.map +0 -1
@@ -0,0 +1,318 @@
1
+ import { StoryHost, isPlainObject } from './chunk-FWPBKKYB.js';
2
+ import { sanitize } from './chunk-HRGPFQBW.js';
3
+ import { PROTOCOL_VERSION } from './chunk-VEKEBILL.js';
4
+ import { f, isConfigBranch, resolveConfigSchema, schemaNodeAtPath, titleCase } from '@weasel-js/labkit/config';
5
+ import { Button } from '@weasel-js/ui/components/Button';
6
+ import { createContext, useMemo, useState, useRef, useEffect, useContext, useId } from 'react';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ var joinPath = (at, key) => at === "" ? key : `${at}.${key}`;
10
+ function describeShape(shape) {
11
+ const out = {};
12
+ for (const [key, entry] of Object.entries(shape)) {
13
+ const { section, showIf } = entry.options;
14
+ const common = {
15
+ annotations: { ...entry.annotations },
16
+ ...section === void 0 ? {} : { section: { ...section } },
17
+ conditional: showIf !== void 0
18
+ };
19
+ out[key] = isConfigBranch(entry) ? { branch: true, ...common, children: describeShape(entry.children) } : {
20
+ branch: false,
21
+ kind: entry.kind,
22
+ default: entry.default,
23
+ ...common,
24
+ validated: entry.options.validate !== void 0,
25
+ customControl: entry.options.render !== void 0
26
+ };
27
+ }
28
+ return out;
29
+ }
30
+ function describeSchema(schema) {
31
+ return { nodes: describeShape(schema.nodes) };
32
+ }
33
+ function rebuildShape(shape, at, answers) {
34
+ const out = {};
35
+ for (const [key, entry] of Object.entries(shape)) {
36
+ const path = joinPath(at, key);
37
+ const options = {
38
+ ...entry.section === void 0 ? {} : { section: entry.section },
39
+ ...entry.conditional ? { showIf: (config) => !answers.hidden(path, config) } : {}
40
+ };
41
+ if (entry.branch) {
42
+ const branch = {
43
+ children: rebuildShape(entry.children, path, answers),
44
+ annotations: entry.annotations,
45
+ options
46
+ };
47
+ out[key] = branch;
48
+ } else {
49
+ const node = {
50
+ kind: entry.kind,
51
+ default: entry.default,
52
+ annotations: entry.annotations,
53
+ options: entry.validated ? { ...options, validate: (_leaf, config) => answers.errors(path, config) } : options
54
+ };
55
+ out[key] = node;
56
+ }
57
+ }
58
+ return out;
59
+ }
60
+ function schemaFromDescription(description, answers) {
61
+ return f.schema(rebuildShape(description.nodes, "", answers));
62
+ }
63
+ function answerSchema(schema, config) {
64
+ const hidden = [];
65
+ const errors = {};
66
+ const record = config;
67
+ let group;
68
+ const walk = (shape, at) => {
69
+ for (const [key, entry] of Object.entries(shape)) {
70
+ const path = joinPath(at, key);
71
+ if (entry.options.showIf && !entry.options.showIf(record)) hidden.push(path);
72
+ if (isConfigBranch(entry)) {
73
+ walk(entry.children, path);
74
+ continue;
75
+ }
76
+ const { validate } = entry.options;
77
+ if (!validate) continue;
78
+ group ??= resolveConfigSchema(schema).group;
79
+ const leaf = schemaNodeAtPath(group, path);
80
+ if (!leaf || "children" in leaf) continue;
81
+ const found = validate(leaf, record);
82
+ if (found.length > 0) errors[path] = found;
83
+ }
84
+ };
85
+ walk(schema.nodes, "");
86
+ return { hidden, errors };
87
+ }
88
+
89
+ // src/protocol/channel.ts
90
+ function openChannel(port, options = {}) {
91
+ const listeners = /* @__PURE__ */ new Set();
92
+ const onMessage = (event) => {
93
+ const data = event.data;
94
+ if (typeof data !== "object" || data === null || !("msg" in data)) {
95
+ options.onMismatch?.({ reason: "not-an-envelope" });
96
+ return;
97
+ }
98
+ const envelope = data;
99
+ if (envelope.v !== PROTOCOL_VERSION) {
100
+ options.onMismatch?.({ reason: "version", version: envelope.v });
101
+ return;
102
+ }
103
+ for (const fn of listeners) fn(envelope.msg);
104
+ };
105
+ port.addEventListener("message", onMessage);
106
+ port.start?.();
107
+ return {
108
+ send: (msg) => port.postMessage({ v: PROTOCOL_VERSION, msg }),
109
+ on: (fn) => {
110
+ listeners.add(fn);
111
+ return () => listeners.delete(fn);
112
+ },
113
+ close: () => {
114
+ port.removeEventListener("message", onMessage);
115
+ listeners.clear();
116
+ port.close();
117
+ }
118
+ };
119
+ }
120
+
121
+ // src/story/indexPages.ts
122
+ var SUFFIX = ":index";
123
+ var INDEX_NAME = "Index";
124
+ function indexId(title) {
125
+ return `${sanitize(title)}${SUFFIX}`;
126
+ }
127
+ function isIndexId(id) {
128
+ return id.endsWith(SUFFIX);
129
+ }
130
+ function indexEntries(stories) {
131
+ const byTitle = /* @__PURE__ */ new Map();
132
+ for (const entry of stories) {
133
+ if (byTitle.has(entry.title)) continue;
134
+ byTitle.set(entry.title, {
135
+ id: indexId(entry.title),
136
+ title: entry.title,
137
+ name: INDEX_NAME,
138
+ exportName: "",
139
+ file: entry.file,
140
+ ...entry.componentDescription === void 0 ? {} : { componentDescription: entry.componentDescription },
141
+ ...entry.componentName === void 0 ? {} : { componentName: entry.componentName }
142
+ });
143
+ }
144
+ return [...byTitle.values()];
145
+ }
146
+ var MAX_ENUM_OPTIONS = 8;
147
+ var MAX_ROWS = 6;
148
+ var labelOf = (key, name) => name ?? titleCase(key);
149
+ function variantRows(schema) {
150
+ const defaults = schema.defaults();
151
+ const rows = [];
152
+ const walk = (shape, at) => {
153
+ for (const [key, entry] of Object.entries(shape)) {
154
+ if (rows.length >= MAX_ROWS) return;
155
+ const path = at === "" ? key : `${at}.${key}`;
156
+ if (entry.options.showIf && !entry.options.showIf(defaults)) continue;
157
+ if (isConfigBranch(entry)) {
158
+ walk(entry.children, path);
159
+ continue;
160
+ }
161
+ if (entry.annotations.hidden || entry.options.render) continue;
162
+ const label = labelOf(key, entry.annotations.name);
163
+ if (entry.kind === "boolean") {
164
+ rows.push({ path, label, values: [false, true].map((value) => ({ value, label: String(value) })) });
165
+ } else if (entry.kind === "enum") {
166
+ const options = entry.annotations.options ?? [];
167
+ if (options.length < 2 || options.length > MAX_ENUM_OPTIONS) continue;
168
+ rows.push({ path, label, values: options.map((o) => ({ value: o.value, label: o.label })) });
169
+ }
170
+ }
171
+ };
172
+ walk(schema.nodes, "");
173
+ return rows;
174
+ }
175
+ function mergeConfig(base, over) {
176
+ if (!isPlainObject(base) || !isPlainObject(over)) return over === void 0 ? base : over;
177
+ const out = { ...base };
178
+ for (const [key, value] of Object.entries(over)) out[key] = mergeConfig(base[key], value);
179
+ return out;
180
+ }
181
+ function withValueAt(config, path, value) {
182
+ const [head, ...rest] = path.split(".");
183
+ if (head === void 0) return value;
184
+ const record = isPlainObject(config) ? config : {};
185
+ return { ...record, [head]: rest.length === 0 ? value : withValueAt(record[head], rest.join("."), value) };
186
+ }
187
+ var IndexEnvContext = createContext(null);
188
+ function useEnv() {
189
+ const env = useContext(IndexEnvContext);
190
+ if (!env) throw new Error("An index page part rendered outside its index page");
191
+ return env;
192
+ }
193
+ var NEAR_MARGIN = "100%";
194
+ function useNearViewport(ref) {
195
+ const [near, setNear] = useState(typeof IntersectionObserver === "undefined");
196
+ useEffect(() => {
197
+ const el = ref.current;
198
+ if (!el || typeof IntersectionObserver === "undefined") return;
199
+ const observer = new IntersectionObserver((entries) => {
200
+ const last = entries.at(-1);
201
+ if (last) setNear(last.isIntersecting);
202
+ }, { rootMargin: NEAR_MARGIN });
203
+ observer.observe(el);
204
+ return () => observer.disconnect();
205
+ }, [ref]);
206
+ return near;
207
+ }
208
+ function IndexStory({ story, config: over, label }) {
209
+ const env = useEnv();
210
+ const [config, setConfig] = useState(() => mergeConfig(story.config.defaults(), over));
211
+ const [state, setState] = useState(() => story.initialState?.(config) ?? null);
212
+ const cell = useRef(null);
213
+ const near = useNearViewport(cell);
214
+ const [height, setHeight] = useState(null);
215
+ useEffect(() => {
216
+ const el = cell.current;
217
+ if (!near || !el || typeof ResizeObserver === "undefined") return;
218
+ const observer = new ResizeObserver(() => setHeight(el.getBoundingClientRect().height));
219
+ observer.observe(el);
220
+ return () => observer.disconnect();
221
+ }, [near]);
222
+ const ctx = {
223
+ config,
224
+ setConfig: (path, value) => setConfig((prev) => withValueAt(prev, path, value)),
225
+ state,
226
+ setState: (next) => setState((prev) => typeof next === "function" ? next(prev) : next),
227
+ globals: env.globals,
228
+ title: story.title,
229
+ name: story.name
230
+ };
231
+ return /* @__PURE__ */ jsxs(
232
+ "figure",
233
+ {
234
+ ref: cell,
235
+ className: `fg-index-cell fg-index-cell--${story.layout}`,
236
+ style: !near && height !== null ? { minHeight: height } : void 0,
237
+ children: [
238
+ /* @__PURE__ */ jsx("div", { className: "fg-index-cell__stage", children: near ? /* @__PURE__ */ jsx(StoryHost, { story, ctx, decorators: env.decorators, resetKey: 0, onError: env.onError }) : null }),
239
+ label === void 0 ? null : /* @__PURE__ */ jsx("figcaption", { className: "fg-index-cell__label", children: label })
240
+ ]
241
+ }
242
+ );
243
+ }
244
+ function IndexVariants({ story }) {
245
+ const rows = useMemo(() => variantRows(story.config), [story]);
246
+ const defaults = useMemo(() => story.config.defaults(), [story]);
247
+ if (rows.length === 0) return null;
248
+ return /* @__PURE__ */ jsx("div", { className: "fg-index-variants", children: rows.map((row) => /* @__PURE__ */ jsxs("section", { className: "fg-index-variants__row", "aria-label": row.label, children: [
249
+ /* @__PURE__ */ jsx("h4", { className: "fg-index-variants__label", children: row.label }),
250
+ /* @__PURE__ */ jsx("div", { className: "fg-index-variants__cells", children: row.values.map((v) => /* @__PURE__ */ jsx(
251
+ IndexStory,
252
+ {
253
+ story,
254
+ config: withValueAt(defaults, row.path, v.value),
255
+ label: v.label
256
+ },
257
+ String(v.value)
258
+ )) })
259
+ ] }, row.path)) });
260
+ }
261
+ function StorySection({ story, variants }) {
262
+ const env = useEnv();
263
+ const headingId = useId();
264
+ const description = env.descriptions[story.id];
265
+ return /* @__PURE__ */ jsxs("section", { className: "fg-index-story", "aria-labelledby": headingId, children: [
266
+ /* @__PURE__ */ jsxs("header", { className: "fg-index-story__head", children: [
267
+ /* @__PURE__ */ jsx("h2", { id: headingId, className: "fg-index-story__name", children: story.name }),
268
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => env.open(story.id), children: "Open" })
269
+ ] }),
270
+ description ? /* @__PURE__ */ jsx("p", { className: "fg-index-story__description", children: description }) : null,
271
+ /* @__PURE__ */ jsx(IndexStory, { story }),
272
+ variants ? /* @__PURE__ */ jsx(IndexVariants, { story }) : null
273
+ ] });
274
+ }
275
+ function firstOfEachControlSet(stories) {
276
+ const seen = /* @__PURE__ */ new Set();
277
+ const shown = /* @__PURE__ */ new Set();
278
+ for (const story of stories) {
279
+ const key = JSON.stringify(variantRows(story.config));
280
+ if (seen.has(key)) continue;
281
+ seen.add(key);
282
+ shown.add(story.id);
283
+ }
284
+ return shown;
285
+ }
286
+ function DefaultIndex() {
287
+ const env = useEnv();
288
+ const withVariants = useMemo(() => firstOfEachControlSet(env.stories), [env.stories]);
289
+ const segments = env.title.split("/");
290
+ const name = segments.pop();
291
+ return /* @__PURE__ */ jsxs("article", { className: "fg-index", children: [
292
+ /* @__PURE__ */ jsxs("header", { className: "fg-index__head", children: [
293
+ segments.length > 0 ? /* @__PURE__ */ jsx("p", { className: "fg-index__path", children: segments.join(" / ") }) : null,
294
+ /* @__PURE__ */ jsx("h1", { className: "fg-index__title", children: name }),
295
+ env.description ? /* @__PURE__ */ jsx("p", { className: "fg-index__description", children: env.description }) : null
296
+ ] }),
297
+ env.stories.map((story) => /* @__PURE__ */ jsx(StorySection, { story, variants: withVariants.has(story.id) }, story.id))
298
+ ] });
299
+ }
300
+ function indexContext(env) {
301
+ return {
302
+ title: env.title,
303
+ ...env.description === void 0 ? {} : { description: env.description },
304
+ stories: env.stories,
305
+ globals: env.globals,
306
+ Story: IndexStory,
307
+ Variants: IndexVariants,
308
+ DefaultIndex,
309
+ open: env.open
310
+ };
311
+ }
312
+ function IndexPage({ env, render }) {
313
+ return /* @__PURE__ */ jsx(IndexEnvContext.Provider, { value: env, children: render ? render(indexContext(env)) : /* @__PURE__ */ jsx(DefaultIndex, {}) });
314
+ }
315
+
316
+ export { IndexPage, answerSchema, describeSchema, indexEntries, indexId, isIndexId, openChannel, schemaFromDescription };
317
+ //# sourceMappingURL=chunk-PO5JLVYT.js.map
318
+ //# sourceMappingURL=chunk-PO5JLVYT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/schema.ts","../src/protocol/channel.ts","../src/story/indexPages.ts","../src/frame/index/variants.ts","../src/frame/index/IndexPage.tsx"],"names":["isConfigBranch"],"mappings":"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","file":"chunk-PO5JLVYT.js","sourcesContent":["import {\n f,\n isConfigBranch,\n resolveConfigSchema,\n schemaNodeAtPath,\n type Annotations,\n type BranchAnnotations,\n type ConfigBranch,\n type ConfigEntry,\n type ConfigNode,\n type ConfigSchema,\n type ConfigShape,\n type NodeOptions,\n} from '@weasel-js/labkit/config';\n\nexport interface SectionDescription {\n label: string;\n collapsed?: boolean;\n}\n\nexport type DescribedEntry =\n | {\n branch: true;\n annotations: BranchAnnotations;\n section?: SectionDescription;\n conditional: boolean;\n children: DescribedShape;\n }\n | {\n branch: false;\n kind: string | null;\n default: unknown;\n annotations: Annotations;\n section?: SectionDescription;\n conditional: boolean;\n validated: boolean;\n /** The node draws its own row with `.render`, which stays in the frame. */\n customControl: boolean;\n };\n\nexport type DescribedShape = { [key: string]: DescribedEntry };\n\n/** A story's `f.schema` as structured-clone data. */\nexport interface SchemaDescription {\n nodes: DescribedShape;\n}\n\n/** Answers the workshop has for the rebuilt schema's predicates. */\nexport interface SchemaAnswers {\n hidden(path: string, config: unknown): boolean;\n errors(path: string, config: unknown): string[];\n}\n\nconst joinPath = (at: string, key: string): string => (at === '' ? key : `${at}.${key}`);\n\nfunction describeShape(shape: ConfigShape): DescribedShape {\n const out: DescribedShape = {};\n for (const [key, entry] of Object.entries(shape)) {\n const { section, showIf } = entry.options;\n const common = {\n annotations: { ...entry.annotations },\n ...(section === undefined ? {} : { section: { ...section } }),\n conditional: showIf !== undefined,\n };\n out[key] = isConfigBranch(entry)\n ? { branch: true, ...common, children: describeShape(entry.children) }\n : {\n branch: false,\n kind: entry.kind,\n default: entry.default,\n ...common,\n validated: entry.options.validate !== undefined,\n customControl: entry.options.render !== undefined,\n };\n }\n return out;\n}\n\nexport function describeSchema(schema: ConfigSchema<unknown>): SchemaDescription {\n return { nodes: describeShape(schema.nodes) };\n}\n\nfunction rebuildShape(shape: DescribedShape, at: string, answers: SchemaAnswers): ConfigShape {\n const out: Record<string, ConfigEntry> = {};\n for (const [key, entry] of Object.entries(shape)) {\n const path = joinPath(at, key);\n const options: NodeOptions = {\n ...(entry.section === undefined ? {} : { section: entry.section }),\n ...(entry.conditional ? { showIf: (config) => !answers.hidden(path, config) } : {}),\n };\n if (entry.branch) {\n const branch: ConfigBranch = {\n children: rebuildShape(entry.children, path, answers),\n annotations: entry.annotations,\n options,\n };\n out[key] = branch;\n } else {\n const node: ConfigNode = {\n kind: entry.kind,\n default: entry.default,\n annotations: entry.annotations,\n options: entry.validated ? { ...options, validate: (_leaf, config) => answers.errors(path, config) } : options,\n };\n out[key] = node;\n }\n }\n return out;\n}\n\nexport function schemaFromDescription(\n description: SchemaDescription,\n answers: SchemaAnswers,\n): ConfigSchema<unknown> {\n return f.schema(rebuildShape(description.nodes, '', answers)) as ConfigSchema<unknown>;\n}\n\n/** Evaluate a schema's own predicates for one config — the frame's half of `answers`. */\nexport function answerSchema(\n schema: ConfigSchema<unknown>,\n config: unknown,\n): { hidden: string[]; errors: Record<string, string[]> } {\n const hidden: string[] = [];\n const errors: Record<string, string[]> = {};\n const record = config as Record<string, unknown>;\n let group: ReturnType<typeof resolveConfigSchema>['group'] | undefined;\n\n const walk = (shape: ConfigShape, at: string): void => {\n for (const [key, entry] of Object.entries(shape)) {\n const path = joinPath(at, key);\n if (entry.options.showIf && !entry.options.showIf(record)) hidden.push(path);\n if (isConfigBranch(entry)) {\n walk(entry.children, path);\n continue;\n }\n const { validate } = entry.options;\n if (!validate) continue;\n group ??= resolveConfigSchema(schema).group;\n const leaf = schemaNodeAtPath(group, path);\n if (!leaf || 'children' in leaf) continue;\n const found = validate(leaf, record);\n if (found.length > 0) errors[path] = found;\n }\n };\n walk(schema.nodes, '');\n return { hidden, errors };\n}\n","import { type Envelope, PROTOCOL_VERSION } from './messages';\n\nexport interface PortLike {\n postMessage(message: unknown): void;\n addEventListener(type: 'message', fn: (event: MessageEvent) => void): void;\n removeEventListener(type: 'message', fn: (event: MessageEvent) => void): void;\n start?(): void;\n close(): void;\n}\n\nexport interface Channel<In, Out> {\n send(msg: Out): void;\n on(fn: (msg: In) => void): () => void;\n close(): void;\n}\n\nexport type Mismatch = { reason: 'not-an-envelope' } | { reason: 'version'; version: unknown };\n\nexport interface ChannelOptions {\n onMismatch?: (mismatch: Mismatch) => void;\n}\n\nexport function openChannel<In, Out>(port: PortLike, options: ChannelOptions = {}): Channel<In, Out> {\n const listeners = new Set<(msg: In) => void>();\n const onMessage = (event: MessageEvent) => {\n const data: unknown = event.data;\n if (typeof data !== 'object' || data === null || !('msg' in data)) {\n options.onMismatch?.({ reason: 'not-an-envelope' });\n return;\n }\n const envelope = data as Partial<Envelope<In>>;\n if (envelope.v !== PROTOCOL_VERSION) {\n options.onMismatch?.({ reason: 'version', version: envelope.v });\n return;\n }\n for (const fn of listeners) fn(envelope.msg as In);\n };\n port.addEventListener('message', onMessage);\n port.start?.();\n return {\n send: (msg) => port.postMessage({ v: PROTOCOL_VERSION, msg } satisfies Envelope<Out>),\n on: (fn) => {\n listeners.add(fn);\n return () => listeners.delete(fn);\n },\n close: () => {\n port.removeEventListener('message', onMessage);\n listeners.clear();\n port.close();\n },\n };\n}\n","import { sanitize } from './ids';\nimport type { IndexEntry } from './types';\n\nconst SUFFIX = ':index';\n\n/** The name an index page goes by in the sidebar and in its trial's title. */\nexport const INDEX_NAME = 'Index';\n\n/** The id of `title`'s index page. A colon never survives `sanitize`, so no story id can collide with it. */\nexport function indexId(title: string): string {\n return `${sanitize(title)}${SUFFIX}`;\n}\n\nexport function isIndexId(id: string): boolean {\n return id.endsWith(SUFFIX);\n}\n\n/**\n * One index-page entry per title in `stories`, in the order titles first appear. It routes and runs like a story:\n * its `file` is the title's first story file, and its descriptions are the title's own.\n */\nexport function indexEntries(stories: readonly IndexEntry[]): IndexEntry[] {\n const byTitle = new Map<string, IndexEntry>();\n for (const entry of stories) {\n if (byTitle.has(entry.title)) continue;\n byTitle.set(entry.title, {\n id: indexId(entry.title),\n title: entry.title,\n name: INDEX_NAME,\n exportName: '',\n file: entry.file,\n ...(entry.componentDescription === undefined ? {} : { componentDescription: entry.componentDescription }),\n ...(entry.componentName === undefined ? {} : { componentName: entry.componentName }),\n });\n }\n return [...byTitle.values()];\n}\n","import { type ConfigSchema, type ConfigShape, isConfigBranch, titleCase } from '@weasel-js/labkit/config';\nimport { isPlainObject } from '../../csf/isPlainObject';\n\nexport interface VariantValue {\n value: unknown;\n label: string;\n}\n\n/** One control a story is shown varying along, with every other control at its default. */\nexport interface VariantRow {\n /** Dotted, as `setConfig` takes it. */\n path: string;\n label: string;\n values: VariantValue[];\n}\n\n/** Above this many choices a row stops being something to scan. */\nexport const MAX_ENUM_OPTIONS = 8;\nexport const MAX_ROWS = 6;\n\nconst labelOf = (key: string, name: string | undefined): string => name ?? titleCase(key);\n\n/**\n * The boolean and enum controls of `schema` a story can be shown varying along, in schema order: skipped are\n * controls that draw their own row, controls hidden at the defaults, and enums with more than\n * `MAX_ENUM_OPTIONS` choices. At most `MAX_ROWS`.\n */\nexport function variantRows(schema: ConfigSchema<unknown>): VariantRow[] {\n const defaults = schema.defaults() as Record<string, unknown>;\n const rows: VariantRow[] = [];\n const walk = (shape: ConfigShape, at: string): void => {\n for (const [key, entry] of Object.entries(shape)) {\n if (rows.length >= MAX_ROWS) return;\n const path = at === '' ? key : `${at}.${key}`;\n if (entry.options.showIf && !entry.options.showIf(defaults)) continue;\n if (isConfigBranch(entry)) {\n walk(entry.children, path);\n continue;\n }\n if (entry.annotations.hidden || entry.options.render) continue;\n const label = labelOf(key, entry.annotations.name);\n if (entry.kind === 'boolean') {\n rows.push({ path, label, values: [false, true].map((value) => ({ value, label: String(value) })) });\n } else if (entry.kind === 'enum') {\n const options = entry.annotations.options ?? [];\n if (options.length < 2 || options.length > MAX_ENUM_OPTIONS) continue;\n rows.push({ path, label, values: options.map((o) => ({ value: o.value, label: o.label })) });\n }\n }\n };\n walk(schema.nodes, '');\n return rows;\n}\n\n/** `over` merged into `base`: nested plain objects merge, anything else replaces. */\nexport function mergeConfig(base: unknown, over: unknown): unknown {\n if (!isPlainObject(base) || !isPlainObject(over)) return over === undefined ? base : over;\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(over)) out[key] = mergeConfig(base[key], value);\n return out;\n}\n\n/** `config` with `value` at dotted `path`, copying each object along the way. */\nexport function withValueAt(config: unknown, path: string, value: unknown): unknown {\n const [head, ...rest] = path.split('.');\n if (head === undefined) return value;\n const record = isPlainObject(config) ? config : {};\n return { ...record, [head]: rest.length === 0 ? value : withValueAt(record[head], rest.join('.'), value) };\n}\n","// The component's own entry, not the barrel: the barrel would bring every weasel-ui component into each frame.\nimport { Button } from '@weasel-js/ui/components/Button';\nimport { createContext, type ReactNode, type RefObject, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { Globals } from '../../protocol/messages';\nimport type { Decorator, IndexContext, IndexStoryProps, LoadedStory, StoryContext } from '../../story/types';\nimport { StoryHost } from '../StoryHost';\nimport { mergeConfig, variantRows, withValueAt } from './variants';\n\n/** What every cell on an index page shares with the frame that hosts it. */\nexport interface IndexEnv {\n title: string;\n description?: string;\n stories: readonly LoadedStory[];\n /** Per story id, the JSDoc above its export. */\n descriptions: Readonly<Record<string, string>>;\n globals: Globals;\n /** The frame config's, outermost. */\n decorators: readonly Decorator[];\n open: (id: string) => void;\n onError: (error: unknown) => void;\n}\n\nexport const IndexEnvContext = createContext<IndexEnv | null>(null);\n\nfunction useEnv(): IndexEnv {\n const env = useContext(IndexEnvContext);\n if (!env) throw new Error('An index page part rendered outside its index page');\n return env;\n}\n\n/** How far past the viewport a cell stays mounted. */\nconst NEAR_MARGIN = '100%';\n\n/** Whether `ref`'s element is near the viewport; true where the browser cannot say. */\nfunction useNearViewport(ref: RefObject<Element | null>): boolean {\n const [near, setNear] = useState(typeof IntersectionObserver === 'undefined');\n useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === 'undefined') return;\n const observer = new IntersectionObserver((entries) => {\n const last = entries.at(-1);\n if (last) setNear(last.isIntersecting);\n }, { rootMargin: NEAR_MARGIN });\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref]);\n return near;\n}\n\n/**\n * One story at its defaults with `config` over them. It keeps its own config and state, so it stays interactive, and\n * it mounts only while near the viewport, so a page of canvas stories stays under the browser's WebGL context cap.\n */\nexport function IndexStory({ story, config: over, label }: IndexStoryProps) {\n const env = useEnv();\n const [config, setConfig] = useState(() => mergeConfig(story.config.defaults(), over));\n const [state, setState] = useState<unknown>(() => story.initialState?.(config) ?? null);\n const cell = useRef<HTMLElement>(null);\n const near = useNearViewport(cell);\n // Held while unmounted, so scrolling past a cell does not move everything after it.\n const [height, setHeight] = useState<number | null>(null);\n useEffect(() => {\n const el = cell.current;\n if (!near || !el || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => setHeight(el.getBoundingClientRect().height));\n observer.observe(el);\n return () => observer.disconnect();\n }, [near]);\n const ctx: StoryContext = {\n config,\n setConfig: (path, value) => setConfig((prev: unknown) => withValueAt(prev, path, value)),\n state,\n setState: (next) =>\n setState((prev: unknown) => (typeof next === 'function' ? (next as (p: unknown) => unknown)(prev) : next)),\n globals: env.globals,\n title: story.title,\n name: story.name,\n };\n return (\n <figure\n ref={cell}\n className={`fg-index-cell fg-index-cell--${story.layout}`}\n style={!near && height !== null ? { minHeight: height } : undefined}\n >\n <div className=\"fg-index-cell__stage\">\n {near ? (\n <StoryHost story={story} ctx={ctx} decorators={env.decorators} resetKey={0} onError={env.onError} />\n ) : null}\n </div>\n {label === undefined ? null : <figcaption className=\"fg-index-cell__label\">{label}</figcaption>}\n </figure>\n );\n}\n\n/** `story` once per value of each boolean and enum control, every other control at its default. */\nexport function IndexVariants({ story }: { story: LoadedStory }) {\n const rows = useMemo(() => variantRows(story.config), [story]);\n const defaults = useMemo(() => story.config.defaults(), [story]);\n if (rows.length === 0) return null;\n return (\n <div className=\"fg-index-variants\">\n {rows.map((row) => (\n <section key={row.path} className=\"fg-index-variants__row\" aria-label={row.label}>\n <h4 className=\"fg-index-variants__label\">{row.label}</h4>\n <div className=\"fg-index-variants__cells\">\n {row.values.map((v) => (\n <IndexStory\n key={String(v.value)}\n story={story}\n config={withValueAt(defaults, row.path, v.value) as Record<string, unknown>}\n label={v.label}\n />\n ))}\n </div>\n </section>\n ))}\n </div>\n );\n}\n\nfunction StorySection({ story, variants }: { story: LoadedStory; variants: boolean }) {\n const env = useEnv();\n const headingId = useId();\n const description = env.descriptions[story.id];\n return (\n <section className=\"fg-index-story\" aria-labelledby={headingId}>\n <header className=\"fg-index-story__head\">\n <h2 id={headingId} className=\"fg-index-story__name\">\n {story.name}\n </h2>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => env.open(story.id)}>\n Open\n </Button>\n </header>\n {description ? <p className=\"fg-index-story__description\">{description}</p> : null}\n <IndexStory story={story} />\n {variants ? <IndexVariants story={story} /> : null}\n </section>\n );\n}\n\n/** Which of `stories` show their variants: the first of each set of controls. Stories of one CSF file share their\n * meta's controls, and the same rows under every story would only repeat. */\nfunction firstOfEachControlSet(stories: readonly LoadedStory[]): Set<string> {\n const seen = new Set<string>();\n const shown = new Set<string>();\n for (const story of stories) {\n const key = JSON.stringify(variantRows(story.config));\n if (seen.has(key)) continue;\n seen.add(key);\n shown.add(story.id);\n }\n return shown;\n}\n\n/** The generated page: the component's title and description, then each story, with the variants of the first of\n * each set of controls. */\nexport function DefaultIndex() {\n const env = useEnv();\n const withVariants = useMemo(() => firstOfEachControlSet(env.stories), [env.stories]);\n const segments = env.title.split('/');\n const name = segments.pop();\n return (\n <article className=\"fg-index\">\n <header className=\"fg-index__head\">\n {segments.length > 0 ? <p className=\"fg-index__path\">{segments.join(' / ')}</p> : null}\n <h1 className=\"fg-index__title\">{name}</h1>\n {env.description ? <p className=\"fg-index__description\">{env.description}</p> : null}\n </header>\n {env.stories.map((story) => (\n <StorySection key={story.id} story={story} variants={withVariants.has(story.id)} />\n ))}\n </article>\n );\n}\n\n/** What a component's own index page is handed. */\nexport function indexContext(env: IndexEnv): IndexContext {\n return {\n title: env.title,\n ...(env.description === undefined ? {} : { description: env.description }),\n stories: env.stories,\n globals: env.globals,\n Story: IndexStory,\n Variants: IndexVariants,\n DefaultIndex,\n open: env.open,\n };\n}\n\n/** The page itself: the component's own, or the generated one. */\nexport function IndexPage({ env, render }: { env: IndexEnv; render: ((ctx: IndexContext) => ReactNode) | null }) {\n return (\n <IndexEnvContext.Provider value={env}>{render ? render(indexContext(env)) : <DefaultIndex />}</IndexEnvContext.Provider>\n );\n}\n"]}
@@ -1,6 +1,19 @@
1
- import { stableStringify } from './chunk-FTFR2YPM.js';
2
1
  import { createContext } from 'react';
3
2
 
3
+ // src/csf/argsContext.ts
4
+
5
+ // src/protocol/messages.ts
6
+ var PROTOCOL_VERSION = 1;
7
+ var PORT_HANDOFF = "weaselforge:port";
8
+ var FRAME_HELLO = "weaselforge:hello";
9
+ function stableStringify(value) {
10
+ return JSON.stringify(
11
+ value,
12
+ (_key, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a < b ? -1 : 1)) : v
13
+ );
14
+ }
15
+
16
+ // src/csf/argsContext.ts
4
17
  var coverOf = (value) => stableStringify(value) ?? " undefined";
5
18
  var appliedLocal = (local, config) => Object.fromEntries(
6
19
  Object.entries(local).filter(([key, entry]) => coverOf(config[key]) === entry.over).map(([key, entry]) => [key, entry.value])
@@ -98,6 +111,6 @@ function withUnsent(sent, original) {
98
111
  return out;
99
112
  }
100
113
 
101
- export { ArgsContext, appliedLocal, coverOf, isPortSafe, portSafePart, withUnsent };
102
- //# sourceMappingURL=chunk-TLO6UHF2.js.map
103
- //# sourceMappingURL=chunk-TLO6UHF2.js.map
114
+ export { ArgsContext, FRAME_HELLO, PORT_HANDOFF, PROTOCOL_VERSION, appliedLocal, coverOf, isPortSafe, portSafePart, stableStringify, withUnsent };
115
+ //# sourceMappingURL=chunk-VEKEBILL.js.map
116
+ //# sourceMappingURL=chunk-VEKEBILL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/messages.ts","../src/csf/argsContext.ts","../src/csf/portSafe.ts"],"names":[],"mappings":"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","file":"chunk-VEKEBILL.js","sourcesContent":["import type { SchemaDescription } from './schema';\n\nexport const PROTOCOL_VERSION = 1;\n\nexport type Globals = Readonly<Record<string, unknown>>;\nexport type Layout = 'centered' | 'padded' | 'fullscreen';\nexport interface Viewport {\n width: number;\n height: number;\n}\nexport type FaultPhase = 'import' | 'render' | 'play' | 'protocol';\n\n/** One custom property as the frame found it. */\nexport interface CssVarReport {\n name: string;\n value: string;\n /** Whether a `vars.set` override is in force on it. */\n overridden: boolean;\n}\n\n/** Visibility and validation answers, keyed by the config they were computed for. */\nexport interface ConfigAnswers {\n /** `stableStringify(config)` of the config the frame evaluated. */\n configKey: string;\n hidden: string[];\n errors: Record<string, string[]>;\n}\n\n/** One element axe faulted on, inside the frame's own document. */\nexport interface A11yNode {\n /** The CSS selectors, outermost first, that reach the element in the frame. */\n target: readonly string[];\n html: string;\n failureSummary?: string;\n}\n\n/** One axe rule's outcome on the story, with the elements it names. */\nexport interface A11yFinding {\n id: string;\n impact: 'minor' | 'moderate' | 'serious' | 'critical' | null;\n help: string;\n helpUrl: string;\n description: string;\n nodes: readonly A11yNode[];\n}\n\n/** What axe found on one story: the rules it failed, and the ones it could not decide. */\nexport interface A11yReport {\n violations: readonly A11yFinding[];\n incomplete: readonly A11yFinding[];\n /** Rules that passed, and rules no element on the page could be judged by. */\n passes: number;\n inapplicable: number;\n}\n\n/** A picture of the story the frame can put in a message: labkit's `CaptureSource` without the canvas,\n * which no structured clone carries. */\nexport type CapturedPicture = { kind: 'svg'; markup: string } | { kind: 'image'; src: string };\n\nexport type ToFrame =\n | { type: 'init'; config: unknown; state: unknown; globals: Globals }\n | { type: 'config'; config: unknown }\n | { type: 'state'; state: unknown }\n | { type: 'globals'; globals: Globals }\n | { type: 'vars.set'; name: string; value: string | null }\n | { type: 'play' }\n /** Run axe over the story's own subtree. Answered by `a11y` carrying the same `id`. */\n | { type: 'a11y.run'; id: string }\n /** Serialize the story's own subtree as a picture. Answered by `capture` carrying the same `id`. */\n | { type: 'capture.run'; id: string };\n\nexport type FromFrame =\n | { type: 'ready'; schema: SchemaDescription; layout: Layout; viewport: Viewport | null }\n /** Sent once, when the story's first render after `init` has committed. */\n | { type: 'rendered' }\n | { type: 'answers'; answers: ConfigAnswers }\n | { type: 'setConfig'; path: string; value: unknown }\n | { type: 'setState'; state: unknown }\n | { type: 'size'; width: number; height: number }\n | { type: 'vars'; vars: CssVarReport[] }\n /** Asks the shell to show story `id` in this frame's trial in place of what it shows now. */\n | { type: 'open'; id: string }\n | { type: 'played'; ok: boolean; message?: string }\n | { type: 'a11y'; id: string; ok: true; report: A11yReport }\n | { type: 'a11y'; id: string; ok: false; message: string }\n | { type: 'capture'; id: string; ok: true; picture: CapturedPicture }\n | { type: 'capture'; id: string; ok: false; message: string }\n /** `seq`, on a render fault only: how many `init`/`config`/`state`/`globals` messages the frame had received. */\n | { type: 'fault'; phase: FaultPhase; message: string; stack?: string; seq?: number };\n\nexport interface Envelope<M> {\n v: number;\n msg: M;\n}\n\n/** Posted on the frame's window with the port transferred alongside it, as a `PortHandoff`. */\nexport const PORT_HANDOFF = 'weaselforge:port';\n\n/** What the shell posts with the port: `id` names what the frame shows, a story or an index. */\nexport interface PortHandoff {\n type: typeof PORT_HANDOFF;\n id: string;\n}\n\n/** Posted by a frame document to its parent as soon as its entry runs, asking for a port. */\nexport const FRAME_HELLO = 'weaselforge:hello';\n\n/** JSON with object keys sorted, so two equal configs produce one key. */\nexport function stableStringify(value: unknown): string {\n return JSON.stringify(value, (_key, v) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : 1)))\n : v,\n );\n}\n","import { type Context, createContext, type Dispatch, type SetStateAction } from 'react';\nimport { stableStringify } from '../protocol/messages';\n\ntype Args = Record<string, unknown>;\n\n/** A frame-local arg, and the config value it was set over: it applies only while config still holds that. */\nexport interface LocalArg {\n value: unknown;\n over: string;\n}\n\nexport type LocalArgs = Record<string, LocalArg>;\n\n/** A config value in the form `LocalArg.over` records. */\nexport const coverOf = (value: unknown): string => stableStringify(value) ?? ' undefined';\n\n/** The frame-local values that still apply over `config`. */\nexport const appliedLocal = (local: LocalArgs, config: Args): Args =>\n Object.fromEntries(\n Object.entries(local)\n .filter(([key, entry]) => coverOf(config[key]) === entry.over)\n .map(([key, entry]) => [key, entry.value]),\n );\n\nexport interface ArgsScope {\n /** The args the story renders with: its own, then config, then the frame-local ones that still apply. */\n args: Args;\n /** The trial's config as it stands. An `undefined` key means the story's own arg. */\n config: Args;\n defaults: Args;\n /** The story's own args, before config and the frame-local ones. */\n original: Args;\n setConfig: (path: string, value: unknown) => void;\n /** Args a MessagePort would not deliver intact, kept in the frame because config crosses one. */\n setLocal: Dispatch<SetStateAction<LocalArgs>>;\n}\n\nexport const ArgsContext: Context<ArgsScope | null> = createContext<ArgsScope | null>(null);\n","const g = globalThis as Record<string, unknown>;\nconst CLONED_WHOLE = new Set<unknown>(\n [\n 'Date',\n 'RegExp',\n 'ArrayBuffer',\n 'DataView',\n 'Int8Array',\n 'Uint8Array',\n 'Uint8ClampedArray',\n 'Int16Array',\n 'Uint16Array',\n 'Int32Array',\n 'Uint32Array',\n 'Float16Array',\n 'Float32Array',\n 'Float64Array',\n 'BigInt64Array',\n 'BigUint64Array',\n ]\n .map((name) => (g[name] as { prototype?: object } | undefined)?.prototype)\n .filter(Boolean),\n);\n\n/** Own keys a clone keeps: enumerable string keys, plus an array's `length`. */\nconst hasOnlyClonedKeys = (v: object): boolean =>\n Reflect.ownKeys(v).every(\n (key) =>\n typeof key === 'string' &&\n (Object.prototype.propertyIsEnumerable.call(v, key) || (Array.isArray(v) && key === 'length')),\n );\n\n/**\n * Whether a MessagePort delivers `value` as the same thing it was. `structuredClone` succeeding is\n * not enough: it copies a class instance's fields onto a plain object and drops its methods.\n */\nexport function isPortSafe(value: unknown): boolean {\n const seen = new Set<object>();\n const safe = (v: unknown): boolean => {\n if (v === null) return true;\n if (typeof v !== 'object') return typeof v !== 'function' && typeof v !== 'symbol';\n if (seen.has(v)) return true;\n seen.add(v);\n const proto = Object.getPrototypeOf(v);\n if (CLONED_WHOLE.has(proto)) return true;\n if (proto === Map.prototype)\n return hasOnlyClonedKeys(v) && [...(v as Map<unknown, unknown>)].every(([key, member]) => safe(key) && safe(member));\n if (proto === Set.prototype) return hasOnlyClonedKeys(v) && [...(v as Set<unknown>)].every(safe);\n if (proto !== Array.prototype && proto !== Object.prototype && proto !== null) return false;\n return hasOnlyClonedKeys(v) && Object.values(v).every(safe);\n };\n try {\n return safe(value);\n } catch {\n return false;\n }\n}\n\nconst isPlainOrNull = (v: unknown): v is Record<string, unknown> => {\n if (!v || typeof v !== 'object') return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n};\n\n/** A plain object or array whose members can be split: React elements are plain objects, but whole. */\nconst splittable = (v: unknown): v is Record<string, unknown> | unknown[] =>\n (Array.isArray(v) ? Object.getPrototypeOf(v) === Array.prototype : isPlainOrNull(v) && !('$$typeof' in v)) &&\n hasOnlyClonedKeys(v as object);\n\n/**\n * The part of `value` a port delivers intact, or null when none of it can cross. A plain object\n * keeps its port-safe fields; an array holds null where a member has no part.\n */\nexport function portSafePart(value: unknown): { value: unknown } | null {\n const walking = new Set<object>();\n const part = (v: unknown): { value: unknown } | null => {\n if (isPortSafe(v)) return { value: v };\n if (!splittable(v) || walking.has(v)) return null;\n walking.add(v);\n try {\n if (Array.isArray(v)) return { value: v.map((member) => part(member)?.value ?? null) };\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(v)) {\n const kept = part(member);\n if (kept) out[key] = kept.value;\n }\n return { value: out };\n } finally {\n walking.delete(v);\n }\n };\n try {\n return part(value);\n } catch {\n return null;\n }\n}\n\n/** `sent`, a value that crossed the port as `portSafePart(original)` or an edit of it, with what the part left behind put back. */\nexport function withUnsent(sent: unknown, original: unknown): unknown {\n if (isPortSafe(original)) return sent;\n if (sent === null && portSafePart(original) === null) return original;\n if (Array.isArray(original) && Array.isArray(sent))\n return sent.map((member, i) => (i < original.length ? withUnsent(member, original[i]) : member));\n if (!splittable(original) || Array.isArray(original) || !isPlainOrNull(sent)) return sent;\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(original)) {\n if (key in sent) out[key] = withUnsent(sent[key], member);\n else if (portSafePart(member) === null) out[key] = member;\n }\n for (const [key, member] of Object.entries(sent)) if (!(key in original)) out[key] = member;\n return out;\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { LabContribution, LabPage } from '@weasel-js/labkit';
2
+ import { Theme } from '@weasel-js/theme';
2
3
  import { ControlRenderer } from '@weasel-js/labkit/config';
3
- import { F as FrameSetup } from './FrameController-eZM3hlcE.js';
4
+ import { G as Globals, F as FrameSetup } from './FrameController-BspC9Zr5.js';
4
5
 
5
6
  /** One global the workshop's toolbar sets for every story, and a trial may pin for its own. */
6
7
  interface GlobalDeclaration {
@@ -10,6 +11,8 @@ interface GlobalDeclaration {
10
11
  label: string;
11
12
  }[];
12
13
  default: string;
14
+ /** Another global's key: the toolbar shows this one in a popover beside that one rather than in the bar itself. */
15
+ under?: string;
13
16
  }
14
17
  type GlobalDeclarations = Readonly<Record<string, GlobalDeclaration>>;
15
18
 
@@ -19,6 +22,9 @@ interface ShellConfig {
19
22
  controls?: Record<string, ControlRenderer>;
20
23
  /** Globals the lab's header sets for every story, each pinnable per trial. Frames apply them with `applyGlobals`. */
21
24
  globals?: GlobalDeclarations;
25
+ /** The theme the workshop's own chrome takes at the lab's current globals, so a global can restyle the workshop
26
+ * as well as the stories. Default: labkit's. */
27
+ labTheme?: (globals: Globals) => Theme;
22
28
  /** The project's other labs, offered in the workshop's title menu. */
23
29
  pages?: readonly LabPage[];
24
30
  /** Which of `pages` the workshop is, when the URL alone cannot say, as across dev servers on different ports. */
@@ -1,5 +1,4 @@
1
- import { ArgsContext, coverOf, isPortSafe } from '../chunk-TLO6UHF2.js';
2
- import '../chunk-FTFR2YPM.js';
1
+ import { ArgsContext, coverOf, isPortSafe } from '../chunk-VEKEBILL.js';
3
2
  import { useContext } from 'react';
4
3
 
5
4
  var sendable = (value) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/csf/shims/preview-api.ts"],"names":[],"mappings":";;;;AAOA,IAAM,QAAA,GAAW,CAAC,KAAA,KAA4B;AAC5C,EAAA,IAAI,CAAC,UAAA,CAAW,KAAK,CAAA,EAAG,OAAO,KAAA;AAC/B,EAAA,IAAI;AACF,IAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF,CAAA;AAEA,IAAM,OAAA,GAAU,CAAC,KAAA,EAAkB,IAAA,KACjC,OAAO,WAAA,CAAY,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,OAAO,CAAC,CAAC,GAAG,CAAA,KAAM,CAAC,KAAK,QAAA,CAAS,GAAG,CAAC,CAAC,CAAA;AAO1E,SAAS,OAAA,GAAwE;AACtF,EAAA,MAAM,KAAA,GAAQ,WAAW,WAAW,CAAA;AACpC,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,MAAM,2DAA2D,CAAA;AACvF,EAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAU,QAAA,EAAU,SAAA,EAAW,UAAS,GAAI,KAAA;AAClE,EAAA,MAAM,UAAA,GAAa,CAAC,KAAA,KAAgB;AAClC,IAAA,MAAM,OAA4B,EAAC;AACnC,IAAA,MAAM,OAAkB,EAAC;AACzB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAChD,MAAA,IAAI,QAAA,CAAS,KAAK,CAAA,EAAG,IAAA,CAAK,KAAK,CAAC,GAAA,EAAK,KAAK,CAAC,CAAA;AAAA,WACtC,IAAA,CAAK,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,MAAM,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAC,CAAA,EAAE;AAAA,IACvD;AACA,IAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAG,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA,EAAG,GAAG,MAAK,CAAE,CAAA;AACtE,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,IAAA,EAAM,SAAA,CAAU,KAAK,KAAK,CAAA;AAAA,EACvD,CAAA;AACA,EAAA,MAAM,SAAA,GAAY,CAAC,QAAA,KAAwB;AACzC,IAAA,MAAM,OAAO,QAAA,IAAY,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,MAAA,CAAO,IAAA,CAAK,QAAQ,GAAG,GAAG,MAAA,CAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAA;AAEtF,IAAA,MAAM,UAAqB,EAAC;AAC5B,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,OAAO,QAAA,EAAU;AACnB,QAAA,SAAA,CAAU,GAAA,EAAK,QAAA,CAAS,GAAG,CAAC,CAAA;AAC5B,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAA,CAAO,GAAG,CAAA,KAAM,MAAA,EAAW;AAC/B,MAAA,OAAA,CAAQ,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,QAAA,CAAS,GAAG,CAAA,EAAG,IAAA,EAAM,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAC,CAAA,EAAE;AAClE,MAAA,SAAA,CAAU,KAAK,MAAS,CAAA;AAAA,IAC1B;AACA,IAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAI,QAAA,GAAW,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAA,GAAI,EAAC,EAAI,GAAG,SAAQ,CAAE,CAAA;AAAA,EAC/E,CAAA;AACA,EAAA,OAAO,CAAC,IAAA,EAAM,UAAA,EAAY,SAAS,CAAA;AACrC","file":"preview-api.js","sourcesContent":["import { useContext } from 'react';\nimport { ArgsContext, coverOf, type LocalArgs } from '../argsContext';\nimport { isPortSafe } from '../portSafe';\n\ntype Args = Record<string, unknown>;\n\n/** A Proxy passes `isPortSafe` and still makes `structuredClone` throw. */\nconst sendable = (value: unknown): boolean => {\n if (!isPortSafe(value)) return false;\n try {\n structuredClone(value);\n return true;\n } catch {\n return false;\n }\n};\n\nconst without = (local: LocalArgs, keys: string[]): LocalArgs =>\n Object.fromEntries(Object.entries(local).filter(([key]) => !keys.includes(key)));\n\n/**\n * Storybook's `useArgs`, writing through the trial's config. Stands in for `storybook/preview-api`.\n * A value a MessagePort would not deliver intact, such as a function, a React element or a class\n * instance, stays in the frame.\n */\nexport function useArgs(): [Args, (patch: Args) => void, (argNames?: string[]) => void] {\n const scope = useContext(ArgsContext);\n if (!scope) throw new Error('useArgs must be called inside a CSF story loaded by forge');\n const { args, config, defaults, original, setConfig, setLocal } = scope;\n const updateArgs = (patch: Args) => {\n const sent: [string, unknown][] = [];\n const kept: LocalArgs = {};\n for (const [key, value] of Object.entries(patch)) {\n if (sendable(value)) sent.push([key, value]);\n else kept[key] = { value, over: coverOf(config[key]) };\n }\n setLocal((prev) => ({ ...without(prev, Object.keys(patch)), ...kept }));\n for (const [key, value] of sent) setConfig(key, value);\n };\n const resetArgs = (argNames?: string[]) => {\n const keys = argNames ?? [...new Set([...Object.keys(defaults), ...Object.keys(args)])];\n // A key with no control shows its original from the frame, so the render does not wait on the port.\n const overlay: LocalArgs = {};\n for (const key of keys) {\n if (key in defaults) {\n setConfig(key, defaults[key]);\n continue;\n }\n if (config[key] === undefined) continue;\n overlay[key] = { value: original[key], over: coverOf(config[key]) };\n setConfig(key, undefined);\n }\n setLocal((prev) => ({ ...(argNames ? without(prev, keys) : {}), ...overlay }));\n };\n return [args, updateArgs, resetArgs];\n}\n"]}
1
+ {"version":3,"sources":["../../src/csf/shims/preview-api.ts"],"names":[],"mappings":";;;AAOA,IAAM,QAAA,GAAW,CAAC,KAAA,KAA4B;AAC5C,EAAA,IAAI,CAAC,UAAA,CAAW,KAAK,CAAA,EAAG,OAAO,KAAA;AAC/B,EAAA,IAAI;AACF,IAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF,CAAA;AAEA,IAAM,OAAA,GAAU,CAAC,KAAA,EAAkB,IAAA,KACjC,OAAO,WAAA,CAAY,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,OAAO,CAAC,CAAC,GAAG,CAAA,KAAM,CAAC,KAAK,QAAA,CAAS,GAAG,CAAC,CAAC,CAAA;AAO1E,SAAS,OAAA,GAAwE;AACtF,EAAA,MAAM,KAAA,GAAQ,WAAW,WAAW,CAAA;AACpC,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,MAAM,2DAA2D,CAAA;AACvF,EAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAU,QAAA,EAAU,SAAA,EAAW,UAAS,GAAI,KAAA;AAClE,EAAA,MAAM,UAAA,GAAa,CAAC,KAAA,KAAgB;AAClC,IAAA,MAAM,OAA4B,EAAC;AACnC,IAAA,MAAM,OAAkB,EAAC;AACzB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAChD,MAAA,IAAI,QAAA,CAAS,KAAK,CAAA,EAAG,IAAA,CAAK,KAAK,CAAC,GAAA,EAAK,KAAK,CAAC,CAAA;AAAA,WACtC,IAAA,CAAK,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,MAAM,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAC,CAAA,EAAE;AAAA,IACvD;AACA,IAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAG,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA,EAAG,GAAG,MAAK,CAAE,CAAA;AACtE,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,IAAA,EAAM,SAAA,CAAU,KAAK,KAAK,CAAA;AAAA,EACvD,CAAA;AACA,EAAA,MAAM,SAAA,GAAY,CAAC,QAAA,KAAwB;AACzC,IAAA,MAAM,OAAO,QAAA,IAAY,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,MAAA,CAAO,IAAA,CAAK,QAAQ,GAAG,GAAG,MAAA,CAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAA;AAEtF,IAAA,MAAM,UAAqB,EAAC;AAC5B,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,OAAO,QAAA,EAAU;AACnB,QAAA,SAAA,CAAU,GAAA,EAAK,QAAA,CAAS,GAAG,CAAC,CAAA;AAC5B,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAA,CAAO,GAAG,CAAA,KAAM,MAAA,EAAW;AAC/B,MAAA,OAAA,CAAQ,GAAG,CAAA,GAAI,EAAE,KAAA,EAAO,QAAA,CAAS,GAAG,CAAA,EAAG,IAAA,EAAM,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAC,CAAA,EAAE;AAClE,MAAA,SAAA,CAAU,KAAK,MAAS,CAAA;AAAA,IAC1B;AACA,IAAA,QAAA,CAAS,CAAC,IAAA,MAAU,EAAE,GAAI,QAAA,GAAW,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAA,GAAI,EAAC,EAAI,GAAG,SAAQ,CAAE,CAAA;AAAA,EAC/E,CAAA;AACA,EAAA,OAAO,CAAC,IAAA,EAAM,UAAA,EAAY,SAAS,CAAA;AACrC","file":"preview-api.js","sourcesContent":["import { useContext } from 'react';\nimport { ArgsContext, coverOf, type LocalArgs } from '../argsContext';\nimport { isPortSafe } from '../portSafe';\n\ntype Args = Record<string, unknown>;\n\n/** A Proxy passes `isPortSafe` and still makes `structuredClone` throw. */\nconst sendable = (value: unknown): boolean => {\n if (!isPortSafe(value)) return false;\n try {\n structuredClone(value);\n return true;\n } catch {\n return false;\n }\n};\n\nconst without = (local: LocalArgs, keys: string[]): LocalArgs =>\n Object.fromEntries(Object.entries(local).filter(([key]) => !keys.includes(key)));\n\n/**\n * Storybook's `useArgs`, writing through the trial's config. Stands in for `storybook/preview-api`.\n * A value a MessagePort would not deliver intact, such as a function, a React element or a class\n * instance, stays in the frame.\n */\nexport function useArgs(): [Args, (patch: Args) => void, (argNames?: string[]) => void] {\n const scope = useContext(ArgsContext);\n if (!scope) throw new Error('useArgs must be called inside a CSF story loaded by forge');\n const { args, config, defaults, original, setConfig, setLocal } = scope;\n const updateArgs = (patch: Args) => {\n const sent: [string, unknown][] = [];\n const kept: LocalArgs = {};\n for (const [key, value] of Object.entries(patch)) {\n if (sendable(value)) sent.push([key, value]);\n else kept[key] = { value, over: coverOf(config[key]) };\n }\n setLocal((prev) => ({ ...without(prev, Object.keys(patch)), ...kept }));\n for (const [key, value] of sent) setConfig(key, value);\n };\n const resetArgs = (argNames?: string[]) => {\n const keys = argNames ?? [...new Set([...Object.keys(defaults), ...Object.keys(args)])];\n // A key with no control shows its original from the frame, so the render does not wait on the port.\n const overlay: LocalArgs = {};\n for (const key of keys) {\n if (key in defaults) {\n setConfig(key, defaults[key]);\n continue;\n }\n if (config[key] === undefined) continue;\n overlay[key] = { value: original[key], over: coverOf(config[key]) };\n setConfig(key, undefined);\n }\n setLocal((prev) => ({ ...(argNames ? without(prev, keys) : {}), ...overlay }));\n };\n return [args, updateArgs, resetArgs];\n}\n"]}
@@ -32,4 +32,106 @@ body {
32
32
  Menlo,
33
33
  monospace;
34
34
  }
35
+
36
+ /* src/frame/index/index.css */
37
+ .fg-index {
38
+ box-sizing: border-box;
39
+ max-width: 1200px;
40
+ margin: 0 auto;
41
+ padding: calc(var(--wzl-space-lg) * 2) var(--wzl-space-lg) calc(var(--wzl-space-lg) * 4);
42
+ font-family: var(--wzl-font-body);
43
+ font-size: var(--wzl-font-size);
44
+ color: var(--wzl-fg);
45
+ }
46
+ .fg-index__head {
47
+ margin-bottom: calc(var(--wzl-space-lg) * 2);
48
+ }
49
+ .fg-index__path {
50
+ margin: 0 0 var(--wzl-space-2);
51
+ font-family: var(--wzl-font-ui);
52
+ font-size: var(--wzl-font-size-sm);
53
+ color: var(--wzl-fg-muted);
54
+ }
55
+ .fg-index__title {
56
+ margin: 0;
57
+ font-family: var(--wzl-panel-title-font);
58
+ font-size: calc(var(--wzl-font-size-xl) * 1.6);
59
+ font-weight: var(--wzl-font-weight-medium);
60
+ letter-spacing: var(--wzl-panel-title-tracking);
61
+ text-transform: var(--wzl-panel-title-case);
62
+ }
63
+ .fg-index__description,
64
+ .fg-index-story__description {
65
+ max-width: 72ch;
66
+ margin: var(--wzl-space-4) 0 0;
67
+ line-height: 1.5;
68
+ color: var(--wzl-fg-muted);
69
+ }
70
+ .fg-index-story {
71
+ padding-top: calc(var(--wzl-space-lg) * 1.5);
72
+ margin-top: calc(var(--wzl-space-lg) * 1.5);
73
+ border-top: var(--wzl-border-w) solid var(--wzl-border);
74
+ }
75
+ .fg-index-story__head {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: var(--wzl-space-6);
79
+ }
80
+ .fg-index-story__name {
81
+ margin: 0;
82
+ font-family: var(--wzl-panel-title-font);
83
+ font-size: var(--wzl-font-size-xl);
84
+ font-weight: var(--wzl-panel-title-weight);
85
+ letter-spacing: var(--wzl-panel-title-tracking);
86
+ text-transform: var(--wzl-panel-title-case);
87
+ color: var(--wzl-panel-title-color);
88
+ }
89
+ .fg-index-cell {
90
+ margin: var(--wzl-space-8) 0 0;
91
+ }
92
+ .fg-index-cell__stage {
93
+ display: flex;
94
+ align-items: center;
95
+ justify-content: center;
96
+ min-height: 96px;
97
+ padding: var(--wzl-space-8);
98
+ border: var(--wzl-border-w) solid var(--wzl-border);
99
+ border-radius: var(--wzl-radius-md);
100
+ background: var(--wzl-surface);
101
+ overflow: auto;
102
+ }
103
+ .fg-index-cell--padded > .fg-index-cell__stage {
104
+ display: block;
105
+ }
106
+ .fg-index-cell--fullscreen > .fg-index-cell__stage {
107
+ display: block;
108
+ height: 360px;
109
+ padding: 0;
110
+ }
111
+ .fg-index-cell__label {
112
+ margin-top: var(--wzl-space-3);
113
+ font-family: var(--wzl-font-mono);
114
+ font-size: var(--wzl-font-size-sm);
115
+ color: var(--wzl-fg-muted);
116
+ }
117
+ .fg-index-variants__row {
118
+ margin-top: calc(var(--wzl-space-lg) * 1.25);
119
+ }
120
+ .fg-index-variants__label {
121
+ margin: 0;
122
+ font-family: var(--wzl-panel-title-font);
123
+ font-size: var(--wzl-font-size-sm);
124
+ font-weight: var(--wzl-panel-title-weight);
125
+ letter-spacing: 0.06em;
126
+ text-transform: uppercase;
127
+ color: var(--wzl-fg-muted);
128
+ }
129
+ .fg-index-variants__cells {
130
+ display: grid;
131
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
132
+ gap: var(--wzl-space-6);
133
+ }
134
+ .fg-index-variants__cells > .fg-index-cell {
135
+ margin-top: var(--wzl-space-4);
136
+ }
35
137
  /*# sourceMappingURL=index.css.map */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/frame/frame.css"],"sourcesContent":["html,\nbody {\n margin: 0;\n}\n\n.fg-frame {\n box-sizing: border-box;\n}\n\n.fg-frame--centered {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n}\n\n.fg-frame--padded {\n padding: 16px;\n}\n\n.fg-frame--fullscreen {\n padding: 0;\n}\n\n.fg-frame__fault {\n margin: 0;\n padding: 16px;\n white-space: pre-wrap;\n border: 1px solid #f2b8b5;\n border-radius: 4px;\n background: #fdecea;\n color: #8c1d18;\n font: 13px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;\n}\n"],"mappings":";AAAA;AACA;AACE,UAAQ;AACV;AAEA,CAAC;AACC,cAAY;AACd;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,cAAY;AACd;AAEA,CAAC;AACC,WAAS;AACX;AAEA,CAAC;AACC,WAAS;AACX;AAEA,CAAC;AACC,UAAQ;AACR,WAAS;AACT,eAAa;AACb,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP;AAAA,IAAM,IAAI,CAAC,IAAI,YAAY;AAAA,IAAE,cAAc;AAAA,IAAE,KAAK;AAAA,IAAE;AACtD;","names":[]}
1
+ {"version":3,"sources":["../../src/frame/frame.css","../../src/frame/index/index.css"],"sourcesContent":["html,\nbody {\n margin: 0;\n}\n\n.fg-frame {\n box-sizing: border-box;\n}\n\n.fg-frame--centered {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n}\n\n.fg-frame--padded {\n padding: 16px;\n}\n\n.fg-frame--fullscreen {\n padding: 0;\n}\n\n.fg-frame__fault {\n margin: 0;\n padding: 16px;\n white-space: pre-wrap;\n border: 1px solid #f2b8b5;\n border-radius: 4px;\n background: #fdecea;\n color: #8c1d18;\n font: 13px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;\n}\n",".fg-index {\n box-sizing: border-box;\n max-width: 1200px;\n margin: 0 auto;\n padding: calc(var(--wzl-space-lg) * 2) var(--wzl-space-lg) calc(var(--wzl-space-lg) * 4);\n font-family: var(--wzl-font-body);\n font-size: var(--wzl-font-size);\n color: var(--wzl-fg);\n}\n\n.fg-index__head {\n margin-bottom: calc(var(--wzl-space-lg) * 2);\n}\n\n.fg-index__path {\n margin: 0 0 var(--wzl-space-2);\n font-family: var(--wzl-font-ui);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-muted);\n}\n\n.fg-index__title {\n margin: 0;\n font-family: var(--wzl-panel-title-font);\n font-size: calc(var(--wzl-font-size-xl) * 1.6);\n font-weight: var(--wzl-font-weight-medium);\n letter-spacing: var(--wzl-panel-title-tracking);\n text-transform: var(--wzl-panel-title-case);\n}\n\n.fg-index__description,\n.fg-index-story__description {\n max-width: 72ch;\n margin: var(--wzl-space-4) 0 0;\n line-height: 1.5;\n color: var(--wzl-fg-muted);\n}\n\n.fg-index-story {\n padding-top: calc(var(--wzl-space-lg) * 1.5);\n margin-top: calc(var(--wzl-space-lg) * 1.5);\n border-top: var(--wzl-border-w) solid var(--wzl-border);\n}\n\n.fg-index-story__head {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-6);\n}\n\n.fg-index-story__name {\n margin: 0;\n font-family: var(--wzl-panel-title-font);\n font-size: var(--wzl-font-size-xl);\n font-weight: var(--wzl-panel-title-weight);\n letter-spacing: var(--wzl-panel-title-tracking);\n text-transform: var(--wzl-panel-title-case);\n color: var(--wzl-panel-title-color);\n}\n\n.fg-index-cell {\n margin: var(--wzl-space-8) 0 0;\n}\n\n.fg-index-cell__stage {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 96px;\n padding: var(--wzl-space-8);\n border: var(--wzl-border-w) solid var(--wzl-border);\n border-radius: var(--wzl-radius-md);\n background: var(--wzl-surface);\n overflow: auto;\n}\n\n.fg-index-cell--padded > .fg-index-cell__stage {\n display: block;\n}\n\n.fg-index-cell--fullscreen > .fg-index-cell__stage {\n display: block;\n height: 360px;\n padding: 0;\n}\n\n.fg-index-cell__label {\n margin-top: var(--wzl-space-3);\n font-family: var(--wzl-font-mono);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-muted);\n}\n\n.fg-index-variants__row {\n margin-top: calc(var(--wzl-space-lg) * 1.25);\n}\n\n/* Set as the kit's panel titles are, at the small size. */\n.fg-index-variants__label {\n margin: 0;\n font-family: var(--wzl-panel-title-font);\n font-size: var(--wzl-font-size-sm);\n font-weight: var(--wzl-panel-title-weight);\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--wzl-fg-muted);\n}\n\n.fg-index-variants__cells {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: var(--wzl-space-6);\n}\n\n.fg-index-variants__cells > .fg-index-cell {\n margin-top: var(--wzl-space-4);\n}\n"],"mappings":";AAAA;AACA;AACE,UAAQ;AACV;AAEA,CAAC;AACC,cAAY;AACd;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,cAAY;AACd;AAEA,CAAC;AACC,WAAS;AACX;AAEA,CAAC;AACC,WAAS;AACX;AAEA,CAAC;AACC,UAAQ;AACR,WAAS;AACT,eAAa;AACb,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP;AAAA,IAAM,IAAI,CAAC,IAAI,YAAY;AAAA,IAAE,cAAc;AAAA,IAAE,KAAK;AAAA,IAAE;AACtD;;;ACjCA,CAAC;AACC,cAAY;AACZ,aAAW;AACX,UAAQ,EAAE;AACV,WAAS,KAAK,IAAI,gBAAgB,EAAE,GAAG,IAAI,gBAAgB,KAAK,IAAI,gBAAgB,EAAE;AACtF,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,SAAO,IAAI;AACb;AAEA,CAAC;AACC,iBAAe,KAAK,IAAI,gBAAgB,EAAE;AAC5C;AAEA,CAAC;AACC,UAAQ,EAAE,EAAE,IAAI;AAChB,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,SAAO,IAAI;AACb;AAEA,CAAC;AACC,UAAQ;AACR,eAAa,IAAI;AACjB,aAAW,KAAK,IAAI,oBAAoB,EAAE;AAC1C,eAAa,IAAI;AACjB,kBAAgB,IAAI;AACpB,kBAAgB,IAAI;AACtB;AAEA,CAAC;AACD,CAAC;AACC,aAAW;AACX,UAAQ,IAAI,eAAe,EAAE;AAC7B,eAAa;AACb,SAAO,IAAI;AACb;AAEA,CAAC;AACC,eAAa,KAAK,IAAI,gBAAgB,EAAE;AACxC,cAAY,KAAK,IAAI,gBAAgB,EAAE;AACvC,cAAY,IAAI,gBAAgB,MAAM,IAAI;AAC5C;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,OAAK,IAAI;AACX;AAEA,CAAC;AACC,UAAQ;AACR,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,eAAa,IAAI;AACjB,kBAAgB,IAAI;AACpB,kBAAgB,IAAI;AACpB,SAAO,IAAI;AACb;AAEA,CAAC;AACC,UAAQ,IAAI,eAAe,EAAE;AAC/B;AAEA,CAAC;AACC,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,cAAY;AACZ,WAAS,IAAI;AACb,UAAQ,IAAI,gBAAgB,MAAM,IAAI;AACtC,iBAAe,IAAI;AACnB,cAAY,IAAI;AAChB,YAAU;AACZ;AAEA,CAAC,sBAAsB,EAAE,CAZxB;AAaC,WAAS;AACX;AAEA,CAAC,0BAA0B,EAAE,CAhB5B;AAiBC,WAAS;AACT,UAAQ;AACR,WAAS;AACX;AAEA,CAAC;AACC,cAAY,IAAI;AAChB,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,SAAO,IAAI;AACb;AAEA,CAAC;AACC,cAAY,KAAK,IAAI,gBAAgB,EAAE;AACzC;AAGA,CAAC;AACC,UAAQ;AACR,eAAa,IAAI;AACjB,aAAW,IAAI;AACf,eAAa,IAAI;AACjB,kBAAgB;AAChB,kBAAgB;AAChB,SAAO,IAAI;AACb;AAEA,CAAC;AACC,WAAS;AACT,yBAAuB,OAAO,SAAS,EAAE,OAAO,KAAK,EAAE;AACvD,OAAK,IAAI;AACX;AAEA,CANC,yBAMyB,EAAE,CAtD3B;AAuDC,cAAY,IAAI;AAClB;","names":[]}