@weasel-js/forge 1.13.0 → 1.14.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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/dist/{FrameController-DgfVaENb.d.ts → FrameController-BM6xuEfY.d.ts} +6 -10
  3. package/dist/{chunk-7XJNVJB5.js → chunk-B26DWEYT.js} +3 -3
  4. package/dist/{chunk-7XJNVJB5.js.map → chunk-B26DWEYT.js.map} +1 -1
  5. package/dist/{chunk-3BAM6M26.js → chunk-FPF2JSWB.js} +3 -3
  6. package/dist/chunk-FPF2JSWB.js.map +1 -0
  7. package/dist/{chunk-ORMMZ5PV.js → chunk-MRYXJTDO.js} +7 -3
  8. package/dist/chunk-MRYXJTDO.js.map +1 -0
  9. package/dist/{chunk-GHPMNT2A.js → chunk-PGLOYXDP.js} +184 -184
  10. package/dist/chunk-PGLOYXDP.js.map +1 -0
  11. package/dist/{chunk-WFT5IOHX.js → chunk-PPB7VP6R.js} +5 -4
  12. package/dist/chunk-PPB7VP6R.js.map +1 -0
  13. package/dist/{chunk-COT4I347.js → chunk-SFKDHXVE.js} +26 -4
  14. package/dist/chunk-SFKDHXVE.js.map +1 -0
  15. package/dist/chunk-STK2AZH2.js +11 -0
  16. package/dist/chunk-STK2AZH2.js.map +1 -0
  17. package/dist/chunk-TT4ZOYB6.js +143 -0
  18. package/dist/chunk-TT4ZOYB6.js.map +1 -0
  19. package/dist/{chunk-XIBKYSRU.js → chunk-UDEUT7AG.js} +124 -80
  20. package/dist/chunk-UDEUT7AG.js.map +1 -0
  21. package/dist/{config-6fWf87Tt.d.ts → config-DOjWyIui.d.ts} +1 -1
  22. package/dist/csf/preview-api.js +2 -2
  23. package/dist/frame/index.css +0 -2
  24. package/dist/frame/index.css.map +1 -1
  25. package/dist/frame/index.d.ts +4 -4
  26. package/dist/frame/index.js +9 -6
  27. package/dist/frame/index.js.map +1 -1
  28. package/dist/index.d.ts +11 -5
  29. package/dist/index.js +4 -4
  30. package/dist/{mountFrame-Bs7u1ro-.d.ts → mountFrame-CRPAjg1M.d.ts} +1 -1
  31. package/dist/shell/index.css +164 -147
  32. package/dist/shell/index.css.map +1 -1
  33. package/dist/shell/index.d.ts +23 -5
  34. package/dist/shell/index.js +454 -318
  35. package/dist/shell/index.js.map +1 -1
  36. package/dist/test/index.d.ts +1 -1
  37. package/dist/test/index.js +8 -10
  38. package/dist/test/index.js.map +1 -1
  39. package/dist/vite/index.js +118 -30
  40. package/dist/vite/index.js.map +1 -1
  41. package/package.json +11 -9
  42. package/dist/chunk-2ZBZRBHI.js +0 -10
  43. package/dist/chunk-2ZBZRBHI.js.map +0 -1
  44. package/dist/chunk-3BAM6M26.js.map +0 -1
  45. package/dist/chunk-COT4I347.js.map +0 -1
  46. package/dist/chunk-GHPMNT2A.js.map +0 -1
  47. package/dist/chunk-L5XM5VKB.js +0 -47
  48. package/dist/chunk-L5XM5VKB.js.map +0 -1
  49. package/dist/chunk-ORMMZ5PV.js.map +0 -1
  50. package/dist/chunk-WFT5IOHX.js.map +0 -1
  51. package/dist/chunk-XIBKYSRU.js.map +0 -1
@@ -0,0 +1,143 @@
1
+ import { useLatest } from '@weasel-js/core';
2
+ import { useTrialClockHandle, useTransportControl } from '@weasel-js/labkit';
3
+ import { createContext, useSyncExternalStore, useMemo, useContext, useCallback } from 'react';
4
+ import { createEmitter } from '@weasel-js/registry';
5
+ import { shownInPass } from '@weasel-js/clock';
6
+
7
+ // src/story/define.ts
8
+ var NATIVE = /* @__PURE__ */ Symbol.for("weaselforge.native");
9
+ function meta(spec) {
10
+ return Object.assign({}, spec, { [NATIVE]: "meta" });
11
+ }
12
+ function story(spec) {
13
+ return Object.assign({}, spec, { [NATIVE]: "story" });
14
+ }
15
+ function isNative(value, kind) {
16
+ return !!value && typeof value === "object" && value[NATIVE] === kind;
17
+ }
18
+
19
+ // src/timeline/clockSpec.ts
20
+ var positive = (n) => typeof n === "number" && Number.isFinite(n) && n > 0;
21
+ var lengthOf = (duration) => positive(duration) ? duration : 1;
22
+ var startOf = (start) => typeof start === "number" && Number.isFinite(start) ? start : 0;
23
+ function clockSpecOf(spec) {
24
+ return {
25
+ duration: lengthOf(spec.duration),
26
+ origin: startOf(spec.start),
27
+ loop: spec.loop ?? true,
28
+ speed: positive(spec.rate) ? spec.rate : 1
29
+ };
30
+ }
31
+ function spanOverrideOf(span) {
32
+ return { duration: lengthOf(span.duration), origin: startOf(span.start) };
33
+ }
34
+ function setLoop(clock, loop) {
35
+ clock.loop = loop;
36
+ }
37
+ var speeds = /* @__PURE__ */ new WeakMap();
38
+ var speedChanged = createEmitter();
39
+ function subscribeSpeed(clock, listener) {
40
+ return speedChanged.subscribe((changed) => {
41
+ if (changed === clock) listener();
42
+ });
43
+ }
44
+ function ownMoves(clock) {
45
+ const speed = () => speeds.get(clock) ?? (Math.abs(clock.rate) || clock.speed);
46
+ return {
47
+ speed,
48
+ play() {
49
+ if (clock.rate !== 0) return;
50
+ if (clock.ended) clock.seek(0);
51
+ clock.rate = speed();
52
+ },
53
+ pause() {
54
+ clock.rate = 0;
55
+ },
56
+ setSpeed(next) {
57
+ speeds.set(clock, next);
58
+ if (clock.rate !== 0) clock.rate = next;
59
+ else speedChanged.emit(clock);
60
+ }
61
+ };
62
+ }
63
+ function shownTime(clock) {
64
+ return shownInPass(clock.origin, clock.elapsed, clock.duration, clock.loop);
65
+ }
66
+ function seekShown(clock, t) {
67
+ const within = Number.isNaN(t) ? 0 : Math.min(Math.max(t - clock.origin, 0), clock.duration);
68
+ clock.seek(within, within >= clock.duration ? "end" : "start");
69
+ }
70
+
71
+ // src/timeline/context.ts
72
+ var ClockContext = createContext(null);
73
+ function useClock(hook) {
74
+ const handle = useContext(ClockContext);
75
+ if (!handle) {
76
+ throw new Error(
77
+ `${hook}: this story declares no timeline. Give it \`timeline: { duration }\`, or \`parameters.forge.timeline\` in CSF.`
78
+ );
79
+ }
80
+ return handle;
81
+ }
82
+ function useClockChanges(handle) {
83
+ return useCallback(
84
+ (listener) => {
85
+ const offChange = handle.clock.subscribe(listener);
86
+ const offFrame = handle.onFrame(listener);
87
+ const offSpeed = subscribeSpeed(handle.clock, listener);
88
+ return () => {
89
+ offChange();
90
+ offFrame();
91
+ offSpeed();
92
+ };
93
+ },
94
+ [handle]
95
+ );
96
+ }
97
+ function usePlayhead() {
98
+ const handle = useClock("usePlayhead");
99
+ return useSyncExternalStore(useClockChanges(handle), () => shownTime(handle.clock));
100
+ }
101
+ var validRate = (rate) => Number.isFinite(rate) && rate > 0;
102
+ function usePlayMoves(handle) {
103
+ const resolved = useTrialClockHandle();
104
+ const control = useTransportControl(resolved === handle ? void 0 : null);
105
+ if (control === null) return ownMoves(handle.clock);
106
+ return { speed: () => control.speed, play: control.play, pause: control.pause, setSpeed: control.setSpeed };
107
+ }
108
+ function useTimeline() {
109
+ const handle = useClock("useTimeline");
110
+ const { clock } = handle;
111
+ const moves = usePlayMoves(handle);
112
+ const latest = useLatest({ moves });
113
+ useSyncExternalStore(
114
+ useClockChanges(handle),
115
+ () => `${shownTime(clock)}|${clock.rate}|${String(clock.loop)}|${clock.origin}|${clock.duration}|${moves.speed()}`
116
+ );
117
+ const time = shownTime(clock);
118
+ const playing = clock.rate !== 0;
119
+ const loop = clock.loop !== false;
120
+ const rate = moves.speed();
121
+ const { origin, duration } = clock;
122
+ const actions = useMemo(
123
+ () => ({
124
+ play: () => latest.current.moves.play(),
125
+ pause: () => latest.current.moves.pause(),
126
+ seek: (t) => seekShown(handle.clock, t),
127
+ setLoop: (next) => setLoop(handle.clock, next),
128
+ setRate: (next) => {
129
+ if (validRate(next)) latest.current.moves.setSpeed(next);
130
+ },
131
+ setSpan: (span) => handle.override(span ? spanOverrideOf(span) : null)
132
+ }),
133
+ [handle, latest]
134
+ );
135
+ return useMemo(
136
+ () => ({ time, playing, loop, rate, span: { start: origin, end: origin + duration }, ...actions }),
137
+ [time, playing, loop, rate, origin, duration, actions]
138
+ );
139
+ }
140
+
141
+ export { ClockContext, clockSpecOf, isNative, meta, shownTime, story, usePlayhead, useTimeline };
142
+ //# sourceMappingURL=chunk-TT4ZOYB6.js.map
143
+ //# sourceMappingURL=chunk-TT4ZOYB6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/story/define.ts","../src/timeline/clockSpec.ts","../src/timeline/moves.ts","../src/timeline/shown.ts","../src/timeline/context.ts"],"names":[],"mappings":"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","file":"chunk-TT4ZOYB6.js","sourcesContent":["import type { MetaSpec, StorySpec } from './types';\n\nexport const NATIVE = Symbol.for('weaselforge.native');\n\n/** Declares a native story file's meta; default-export the result. */\nexport function meta(spec: MetaSpec): MetaSpec {\n return Object.assign({}, spec, { [NATIVE]: 'meta' as const });\n}\n\n/** Declares one native story; export the result under the story's name. `C` and `S` come from `config` and `state`. */\nexport function story<C = Record<string, never>, S = undefined>(spec: StorySpec<C, S>): StorySpec<C, S> {\n return Object.assign({}, spec, { [NATIVE]: 'story' as const });\n}\n\nexport function isNative(value: unknown, kind: 'meta' | 'story'): boolean {\n return !!value && typeof value === 'object' && (value as Record<symbol, unknown>)[NATIVE] === kind;\n}\n","import type { ClockSpec } from '@weasel-js/clock';\nimport type { SpanOverride, TimelineSpec } from './types';\n\nconst positive = (n: number | undefined): n is number => typeof n === 'number' && Number.isFinite(n) && n > 0;\n\n/** A span's length, in ms: anything not a positive finite number stands as 1 ms, so a timeline can never throw. */\nconst lengthOf = (duration: number): number => (positive(duration) ? duration : 1);\n\nconst startOf = (start: number | undefined): number => (typeof start === 'number' && Number.isFinite(start) ? start : 0);\n\n/** The clock a story's timeline declares. It opens paused at the span's start, and loops unless told not to. */\nexport function clockSpecOf(spec: TimelineSpec): ClockSpec {\n return {\n duration: lengthOf(spec.duration),\n origin: startOf(spec.start),\n loop: spec.loop ?? true,\n speed: positive(spec.rate) ? spec.rate : 1,\n };\n}\n\n/** The clock override a story's `setSpan` asks for. */\nexport function spanOverrideOf(span: SpanOverride): { duration: number; origin: number } {\n return { duration: lengthOf(span.duration), origin: startOf(span.start) };\n}\n","import type { Clock } from '@weasel-js/clock';\nimport { createEmitter } from '@weasel-js/registry';\n\n/** Loops the clock without end, or plays it once. */\nexport function setLoop(clock: Clock, loop: boolean): void {\n clock.loop = loop;\n}\n\n/** Play, pause and speed, as `useTimeline` asks for them. */\nexport interface PlayMoves {\n /** Unsigned: what a pause comes back to. */\n speed(): number;\n play(): void;\n pause(): void;\n setSpeed(speed: number): void;\n}\n\nconst speeds = new WeakMap<Clock, number>();\nconst speedChanged = createEmitter<[Clock]>();\n\n/** Calls `listener` when the speed a pause of `clock` returns to changes outside a transport. */\nexport function subscribeSpeed(clock: Clock, listener: () => void): () => void {\n return speedChanged.subscribe((changed) => {\n if (changed === clock) listener();\n });\n}\n\n/** The moves on a clock no transport works, as outside a lab: the speed a pause returns to is kept here. */\nexport function ownMoves(clock: Clock): PlayMoves {\n const speed = (): number => speeds.get(clock) ?? (Math.abs(clock.rate) || clock.speed);\n return {\n speed,\n play() {\n if (clock.rate !== 0) return;\n // Playing from the end starts over, as a player's play button does.\n if (clock.ended) clock.seek(0);\n clock.rate = speed();\n },\n pause() {\n clock.rate = 0;\n },\n setSpeed(next) {\n speeds.set(clock, next);\n if (clock.rate !== 0) clock.rate = next;\n else speedChanged.emit(clock);\n },\n };\n}\n","import { type Clock, shownInPass } from '@weasel-js/clock';\n\n/** The time a story's playhead shows: the clock's origin plus how far it is into the current pass; see `shownInPass`. */\nexport function shownTime(clock: Clock): number {\n return shownInPass(clock.origin, clock.elapsed, clock.duration, clock.loop);\n}\n\n/** Moves the playhead to shown time `t`, clamped to the span; the span's end stands as the end of the first pass. */\nexport function seekShown(clock: Clock, t: number): void {\n const within = Number.isNaN(t) ? 0 : Math.min(Math.max(t - clock.origin, 0), clock.duration);\n clock.seek(within, within >= clock.duration ? 'end' : 'start');\n}\n","import type { ClockHandle } from '@weasel-js/clock';\nimport { useLatest } from '@weasel-js/core';\nimport { useTransportControl, useTrialClockHandle } from '@weasel-js/labkit';\nimport { createContext, useCallback, useContext, useMemo, useSyncExternalStore } from 'react';\nimport { spanOverrideOf } from './clockSpec';\nimport { ownMoves, type PlayMoves, setLoop, subscribeSpeed } from './moves';\nimport { seekShown, shownTime } from './shown';\nimport type { Span, SpanOverride } from './types';\n\n/** The clock of the story rendering below it; null where the story declares no timeline. */\nexport const ClockContext = createContext<ClockHandle | null>(null);\n\n/** What `useTimeline` hands a story: where its playhead stands, and the moves the transport makes. Times in ms. */\nexport interface StoryTimeline {\n /** The playhead, in ms, always inside `span`. */\n time: number;\n playing: boolean;\n loop: boolean;\n rate: number;\n span: Span;\n play(): void;\n pause(): void;\n seek(time: number): void;\n setLoop(loop: boolean): void;\n setRate(rate: number): void;\n /** Replaces the declared span, for one the story only learns once it runs; null goes back to the declared one. */\n setSpan(span: SpanOverride | null): void;\n}\n\nfunction useClock(hook: string): ClockHandle {\n const handle = useContext(ClockContext);\n if (!handle) {\n throw new Error(\n `${hook}: this story declares no timeline. Give it \\`timeline: { duration }\\`, or \\`parameters.forge.timeline\\` in CSF.`,\n );\n }\n return handle;\n}\n\n/** Subscribes to every change of `handle`'s clock: rate, seek, loop and declare, each frame it moves, and a paused\n * speed change. */\nfunction useClockChanges(handle: ClockHandle): (listener: () => void) => () => void {\n return useCallback(\n (listener) => {\n const offChange = handle.clock.subscribe(listener);\n const offFrame = handle.onFrame(listener);\n const offSpeed = subscribeSpeed(handle.clock, listener);\n return () => {\n offChange();\n offFrame();\n offSpeed();\n };\n },\n [handle],\n );\n}\n\n/** The story's playhead, in ms. Re-renders only the component calling it, on every move. Throws outside a story that\n * declares a timeline. */\nexport function usePlayhead(): number {\n const handle = useClock('usePlayhead');\n return useSyncExternalStore(useClockChanges(handle), () => shownTime(handle.clock));\n}\n\nconst validRate = (rate: number): boolean => Number.isFinite(rate) && rate > 0;\n\n/** Play, pause and speed through the trial's transport, so the story and the transport share one speed, or on the\n * clock itself where no transport works it. A transport over another clock goes unread, so its frames re-render\n * nothing here. */\nfunction usePlayMoves(handle: ClockHandle): PlayMoves {\n const resolved = useTrialClockHandle();\n const control = useTransportControl(resolved === handle ? undefined : null);\n if (control === null) return ownMoves(handle.clock);\n return { speed: () => control.speed, play: control.play, pause: control.pause, setSpeed: control.setSpeed };\n}\n\n/** The story's whole clock: playhead, span, play state, loop and rate, and the moves on them. Throws outside a story\n * that declares a timeline. */\nexport function useTimeline(): StoryTimeline {\n const handle = useClock('useTimeline');\n const { clock } = handle;\n const moves = usePlayMoves(handle);\n const latest = useLatest({ moves });\n useSyncExternalStore(\n useClockChanges(handle),\n () =>\n `${shownTime(clock)}|${clock.rate}|${String(clock.loop)}|${clock.origin}|${clock.duration}|${moves.speed()}`,\n );\n const time = shownTime(clock);\n const playing = clock.rate !== 0;\n const loop = clock.loop !== false;\n const rate = moves.speed();\n const { origin, duration } = clock;\n\n const actions = useMemo(\n () => ({\n play: () => latest.current.moves.play(),\n pause: () => latest.current.moves.pause(),\n seek: (t: number) => seekShown(handle.clock, t),\n setLoop: (next: boolean) => setLoop(handle.clock, next),\n setRate: (next: number) => {\n if (validRate(next)) latest.current.moves.setSpeed(next);\n },\n setSpan: (span: SpanOverride | null) => handle.override(span ? spanOverrideOf(span) : null),\n }),\n [handle, latest],\n );\n return useMemo(\n () => ({ time, playing, loop, rate, span: { start: origin, end: origin + duration }, ...actions }),\n [time, playing, loop, rate, origin, duration, actions],\n );\n}\n"]}
@@ -1,11 +1,12 @@
1
- import { GLOBALS_KEY, effectiveGlobals, storyConfig, isForgePath, PLAYHEAD_KEY, FOLLOW_APP } from './chunk-3BAM6M26.js';
2
- import { StoryHost, useNearViewport, IN_VIEW_MARGIN, useHostConditions, createA11yHighlighter, useStoryClock, useClockLoop, scanCssVars, auditElement } from './chunk-GHPMNT2A.js';
3
- import { ClockContext } from './chunk-L5XM5VKB.js';
1
+ import { GLOBALS_KEY, effectiveGlobals, storyConfig, isForgePath, FOLLOW_APP } from './chunk-FPF2JSWB.js';
2
+ import { StoryHost, useHostConditions, createA11yHighlighter, scanCssVars, auditElement } from './chunk-PGLOYXDP.js';
3
+ import { ClockContext } from './chunk-TT4ZOYB6.js';
4
4
  import { createEmitter } from '@weasel-js/registry';
5
5
  import { createContext, memo, useContext, useCallback, useSyncExternalStore, useMemo, useId, useState, useRef, useLayoutEffect, useEffect } from 'react';
6
6
  import { useLatest } from '@weasel-js/core';
7
- import { usePersistedState, TrialIdContext, useTrialTitle, LabBoundary } from '@weasel-js/labkit';
7
+ import { usePersistedState, TrialIdContext, useTrialClockHandle, useTrialTitle, LabBoundary } from '@weasel-js/labkit';
8
8
  import { OverlayPortalProvider } from '@weasel-js/ui/portal-host';
9
+ import { useNearViewport } from '@weasel-js/react';
9
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
11
  import { createPortal } from 'react-dom';
11
12
  import { withValueAtPath } from '@weasel-js/labkit/config';
@@ -46,6 +47,9 @@ function useTrialFrame(trialId) {
46
47
  return useSyncExternalStore(subscribe, read, read);
47
48
  }
48
49
  var StoryGlobalsContext = createContext({});
50
+
51
+ // src/shell/inViewMargin.ts
52
+ var IN_VIEW_MARGIN = "50%";
49
53
  var NONE = {};
50
54
  function useCssOverrides() {
51
55
  return usePersistedState("fg-css-overrides", NONE, { scope: "trial" });
@@ -90,6 +94,95 @@ function StoryScroller({ children }) {
90
94
  }
91
95
  );
92
96
  }
97
+ function createStoryHosts() {
98
+ const refs = /* @__PURE__ */ new Map();
99
+ const shows = /* @__PURE__ */ new Map();
100
+ const ref = (trialId) => {
101
+ let held = refs.get(trialId);
102
+ if (!held) {
103
+ held = { current: null };
104
+ refs.set(trialId, held);
105
+ }
106
+ return held;
107
+ };
108
+ return {
109
+ ref,
110
+ attach(trialId, host, show) {
111
+ const held = ref(trialId);
112
+ held.current = host;
113
+ if (show) shows.set(trialId, { host, show });
114
+ return () => {
115
+ if (held.current === host) held.current = null;
116
+ if (shows.get(trialId)?.host === host) shows.delete(trialId);
117
+ };
118
+ },
119
+ show(trialId) {
120
+ return shows.get(trialId)?.show() ?? Promise.resolve(() => {
121
+ });
122
+ }
123
+ };
124
+ }
125
+ var StoryHostsContext = createContext(null);
126
+ function useStoryHost(trialId, host, show) {
127
+ const hosts = useContext(StoryHostsContext);
128
+ useLayoutEffect(
129
+ () => host && hosts && trialId ? hosts.attach(trialId, host, show) : void 0,
130
+ [host, hosts, trialId, show]
131
+ );
132
+ }
133
+ function afterPaint(host, done) {
134
+ let canceled = false;
135
+ const finish = () => {
136
+ if (!canceled) done();
137
+ };
138
+ const { fonts } = host.ownerDocument;
139
+ if (!fonts) finish();
140
+ else {
141
+ const frame = () => requestAnimationFrame(finish);
142
+ void fonts.ready.then(frame, frame);
143
+ }
144
+ return () => {
145
+ canceled = true;
146
+ };
147
+ }
148
+ function useStoryShow(host, inView) {
149
+ const [held, setHeld] = useState(0);
150
+ const [waiters] = useState(() => []);
151
+ const live = inView || held > 0;
152
+ const show = useCallback(
153
+ () => new Promise((resolve) => {
154
+ let released = false;
155
+ const release = () => {
156
+ if (released) return;
157
+ released = true;
158
+ setHeld((n) => n - 1);
159
+ };
160
+ waiters.push(() => resolve(release));
161
+ setHeld((n) => n + 1);
162
+ }),
163
+ [waiters]
164
+ );
165
+ useEffect(() => {
166
+ if (!host || !live || waiters.length === 0) return;
167
+ const waiting = waiters.splice(0);
168
+ let settled = false;
169
+ const cancel = afterPaint(host, () => {
170
+ settled = true;
171
+ for (const resolve of waiting) resolve();
172
+ });
173
+ return () => {
174
+ cancel();
175
+ if (!settled) waiters.unshift(...waiting);
176
+ };
177
+ }, [host, live, held, waiters]);
178
+ useEffect(
179
+ () => () => {
180
+ for (const resolve of waiters.splice(0)) resolve();
181
+ },
182
+ [waiters]
183
+ );
184
+ return { live, show };
185
+ }
93
186
  var VARS_SETTLE_MS = 100;
94
187
  function StoryContent({ host, children }) {
95
188
  return /* @__PURE__ */ jsx(LabBoundary, { children: /* @__PURE__ */ jsx(OverlayPortalProvider, { container: host, contained: true, children }) });
@@ -107,7 +200,15 @@ function TrialHost({ layout, setup, config, children, hostRef, onRendered, copy
107
200
  const [host, setHost] = useState(null);
108
201
  const elementRef = useRef(null);
109
202
  const inView = useNearViewport(elementRef, IN_VIEW_MARGIN);
203
+ const { live, show } = useStoryShow(host, inView);
110
204
  const [pending, setPending] = useState(true);
205
+ const [rendered] = useState(() => {
206
+ let resolve;
207
+ const promise = new Promise((r) => {
208
+ resolve = r;
209
+ });
210
+ return { promise, resolve };
211
+ });
111
212
  const latest = useLatest({ onRendered: copy ? void 0 : onRendered });
112
213
  const overridesRef = useHostConditions(host, { hostId, globals, overrides: persisted, setup });
113
214
  useLayoutEffect(() => {
@@ -140,6 +241,7 @@ function TrialHost({ layout, setup, config, children, hostRef, onRendered, copy
140
241
  if (lastVars?.some((v) => v.name === msg.name)) scan();
141
242
  };
142
243
  const audit = async () => {
244
+ await rendered.promise;
143
245
  const outcome = await auditElement(host, { page: false });
144
246
  if (trialId) frames?.reportA11y(trialId, outcome);
145
247
  return outcome;
@@ -152,28 +254,18 @@ function TrialHost({ layout, setup, config, children, hostRef, onRendered, copy
152
254
  mutations?.disconnect();
153
255
  clearTimeout(settleTimer);
154
256
  };
155
- }, [host, hostId, trialId, frames, copy, overridesRef]);
257
+ }, [host, hostId, trialId, frames, copy, overridesRef, rendered]);
258
+ useStoryHost(trialId, copy ? null : host, show);
156
259
  const announced = useRef(false);
157
260
  useEffect(() => {
158
- if (!host || !inView || announced.current) return;
159
- let canceled = false;
160
- const done = () => {
161
- if (canceled) return;
261
+ if (!host || !live || announced.current) return;
262
+ return afterPaint(host, () => {
162
263
  announced.current = true;
264
+ rendered.resolve();
163
265
  setPending(false);
164
266
  latest.current.onRendered?.();
165
- };
166
- const { fonts } = host.ownerDocument;
167
- if (!fonts) {
168
- done();
169
- return;
170
- }
171
- const afterPaint = () => requestAnimationFrame(done);
172
- void fonts.ready.then(afterPaint, afterPaint);
173
- return () => {
174
- canceled = true;
175
- };
176
- }, [host, inView, latest]);
267
+ });
268
+ }, [host, live, latest, rendered]);
177
269
  return /* @__PURE__ */ jsx(
178
270
  "div",
179
271
  {
@@ -187,54 +279,10 @@ function TrialHost({ layout, setup, config, children, hostRef, onRendered, copy
187
279
  "data-fg-copy": copy ? "" : void 0,
188
280
  "data-fg-layout": layout,
189
281
  "data-pending": pending || void 0,
190
- children: /* @__PURE__ */ jsx(StoryScroller, { children: host && inView ? /* @__PURE__ */ jsx(StoryContent, { host, children: children(globals) }) : null })
282
+ children: /* @__PURE__ */ jsx(StoryScroller, { children: host && live ? /* @__PURE__ */ jsx(StoryContent, { host, children: children(globals) }) : null })
191
283
  }
192
284
  );
193
285
  }
194
- function createTrialClocks() {
195
- const clocks = /* @__PURE__ */ new Map();
196
- const changed = createEmitter();
197
- const notify = changed.emit;
198
- return {
199
- publish(trialId, clock) {
200
- clocks.set(trialId, clock);
201
- notify();
202
- return () => {
203
- if (clocks.get(trialId) !== clock) return;
204
- clocks.delete(trialId);
205
- notify();
206
- };
207
- },
208
- get: (trialId) => clocks.get(trialId) ?? null,
209
- subscribe: changed.subscribe
210
- };
211
- }
212
- var TrialClocksContext = createContext(null);
213
- var NEVER = () => () => {
214
- };
215
- var NONE2 = () => null;
216
- function useTrialClock(trialId) {
217
- const clocks = useContext(TrialClocksContext);
218
- return useSyncExternalStore(clocks?.subscribe ?? NEVER, clocks ? () => clocks.get(trialId) : NONE2);
219
- }
220
- function usePersistedPlayhead(clock, persisted, write) {
221
- const written = useRef(persisted);
222
- const latestWrite = useLatest(write);
223
- useEffect(() => {
224
- if (!clock || persisted === written.current) return;
225
- written.current = persisted;
226
- clock.request(persisted);
227
- }, [clock, persisted]);
228
- useEffect(() => {
229
- if (!clock) return;
230
- return clock.subscribe(() => {
231
- const { playing, time } = clock.get();
232
- if (playing || clock.pending() !== null || time === written.current) return;
233
- written.current = time;
234
- latestWrite.current(time);
235
- });
236
- }, [clock, latestWrite]);
237
- }
238
286
  var StoryBody = memo(function StoryBody2({ story, config, setConfig, state, setState, globals, decorators, resetKey, onError }) {
239
287
  const storyCtx = { config, setConfig, state, setState, globals, title: story.title, name: story.name };
240
288
  return /* @__PURE__ */ jsx(StoryHost, { story, ctx: storyCtx, decorators, resetKey, onError });
@@ -288,7 +336,7 @@ function resolveContextOf(lab) {
288
336
  const prefersDark = globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false;
289
337
  return { declarations: lab.declarations, modeGlobal: lab.modeGlobal, prefersDark, labMode: lab.mode };
290
338
  }
291
- var NONE3 = [];
339
+ var NONE2 = [];
292
340
  function createLiveLenses() {
293
341
  const requests = /* @__PURE__ */ new Map();
294
342
  const listeners = /* @__PURE__ */ new Set();
@@ -305,7 +353,7 @@ function createLiveLenses() {
305
353
  let found = byTrial.get(trialId);
306
354
  if (!found) {
307
355
  const mine = [...requests.values()].filter((r) => r.hit.trialId === trialId);
308
- found = mine.length === 0 ? NONE3 : mine;
356
+ found = mine.length === 0 ? NONE2 : mine;
309
357
  byTrial.set(trialId, found);
310
358
  }
311
359
  return found;
@@ -421,9 +469,9 @@ function LiveCopies(props) {
421
469
  function FrameLensCopy({ request, trialId, trialConfig, children }) {
422
470
  const globals = useCopyGlobals(request, trialConfig);
423
471
  const id = copyId(trialId, request);
424
- const { args } = request;
472
+ const { args, factor } = request;
425
473
  const main = request.hit.host;
426
- const copy = useMemo(() => ({ id, main, globals, args }), [id, main, globals, args]);
474
+ const copy = useMemo(() => ({ id, main, globals, args, factor }), [id, main, globals, args, factor]);
427
475
  return /* @__PURE__ */ jsx(LensPortal, { request, children: children(copy) });
428
476
  }
429
477
  function FrameCopies({ lenses, trialId, ...props }) {
@@ -458,15 +506,11 @@ function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
458
506
  }, [latestRef]);
459
507
  const setState = useCallback((next) => latestRef.current.setState(next), [latestRef]);
460
508
  const trialId = useContext(TrialIdContext);
461
- const clocks = useContext(TrialClocksContext);
462
509
  const ownHost = useRef(null);
463
510
  const host = hostRef ?? ownHost;
464
- const kept = ctx.config?.[PLAYHEAD_KEY];
465
- const persisted = typeof kept === "number" && Number.isFinite(kept) ? kept : null;
466
- const clock = useStoryClock(story.timeline?.(config) ?? null, () => persisted);
467
- useClockLoop(clock, host);
468
- usePersistedPlayhead(clock, persisted, (time) => latestRef.current.setConfig(PLAYHEAD_KEY, time));
469
- useEffect(() => clock && clocks && trialId ? clocks.publish(trialId, clock) : void 0, [clock, clocks, trialId]);
511
+ const spec = story.timeline?.(config) ?? null;
512
+ const trialClock = useTrialClockHandle();
513
+ const clock = spec ? trialClock : null;
470
514
  const decorators = setup.decorators ?? NO_DECORATORS;
471
515
  const latestError = useLatest(onError);
472
516
  const reportError = useCallback((error) => latestError.current?.(error), [latestError]);
@@ -497,6 +541,6 @@ function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
497
541
  ] });
498
542
  }
499
543
 
500
- export { LiveCopies, LiveFrameCopies, LiveLensesContext, StoryGlobalsContext, StoryTrial, TrialClocksContext, TrialFramesContext, TrialHost, createLiveLenses, createTrialClocks, createTrialFrames, describeLens, resolveComparison, resolveContextOf, scrollerOf, trialAt, useCopyConfig, useCssOverrides, useTrialClock, useTrialFrame, withArgs };
501
- //# sourceMappingURL=chunk-XIBKYSRU.js.map
502
- //# sourceMappingURL=chunk-XIBKYSRU.js.map
544
+ export { IN_VIEW_MARGIN, LiveCopies, LiveFrameCopies, LiveLensesContext, StoryGlobalsContext, StoryHostsContext, StoryTrial, TrialFramesContext, TrialHost, createLiveLenses, createStoryHosts, createTrialFrames, describeLens, resolveComparison, resolveContextOf, scrollerOf, trialAt, useCopyConfig, useCssOverrides, useTrialFrame, withArgs };
545
+ //# sourceMappingURL=chunk-UDEUT7AG.js.map
546
+ //# sourceMappingURL=chunk-UDEUT7AG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shell/trialFrames.ts","../src/shell/StoryGlobalsContext.ts","../src/shell/inViewMargin.ts","../src/shell/cssVars/overrides.ts","../src/shell/StoryScroller.tsx","../src/shell/storyHosts.ts","../src/shell/storyShow.ts","../src/shell/TrialHost.tsx","../src/shell/StoryBody.tsx","../src/shell/loupe/conditions.ts","../src/shell/loupe/liveLenses.ts","../src/shell/loupe/trialAt.ts","../src/shell/loupe/LiveCopies.tsx","../src/shell/StoryTrial.tsx"],"names":["createContext","useContext","useLayoutEffect","useState","useCallback","jsx","useEffect","StoryBody","NONE","useMemo","useSyncExternalStore","useLatest","useRef","TrialIdContext","jsxs","Fragment"],"mappings":"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","file":"chunk-UDEUT7AG.js","sourcesContent":["import { createEmitter } from '@weasel-js/registry';\nimport { createContext, useCallback, useContext, useSyncExternalStore } from 'react';\nimport type { A11yOutcome, CssVarReport, ToFrame } from '../protocol/messages';\n\nexport type { A11yOutcome };\n\n/** The half of a trial's frame that answers a request: each call is one round trip over the frame's channel. */\nexport interface TrialFrameCalls {\n send: (msg: ToFrame) => void;\n audit: () => Promise<A11yOutcome>;\n}\n\n/** What trial chrome can reach of the frame its trial shows. */\nexport interface TrialFrame {\n /** Null while no frame is connected. */\n send: ((msg: ToFrame) => void) | null;\n /** The frame's latest `vars` report. */\n vars: readonly CssVarReport[];\n /** Runs axe over the story and records the answer as `a11y`. Null while no frame is connected. */\n audit: (() => Promise<A11yOutcome>) | null;\n /** What the last audit found; null until one has run against the connected frame. */\n a11y: A11yOutcome | null;\n}\n\n/** Each trial's frame, keyed by trial id: `FrameView` connects and reports, trial chrome reads. */\nexport interface TrialFrames {\n /** Returns a disconnect that does nothing once a newer connection replaced this one. */\n connect(trialId: string, calls: TrialFrameCalls): () => void;\n report(trialId: string, vars: readonly CssVarReport[]): void;\n reportA11y(trialId: string, outcome: A11yOutcome): void;\n get(trialId: string): TrialFrame;\n subscribe(listener: () => void): () => void;\n}\n\nconst NO_FRAME: TrialFrame = { send: null, vars: [], audit: null, a11y: null };\n\nexport function createTrialFrames(): TrialFrames {\n const frames = new Map<string, TrialFrame>();\n const changes = createEmitter();\n const changed = changes.emit;\n const patch = (trialId: string, next: Partial<TrialFrame>) => {\n const frame = frames.get(trialId);\n if (!frame) return;\n frames.set(trialId, { ...frame, ...next });\n changed();\n };\n return {\n connect(trialId, calls) {\n frames.set(trialId, { send: calls.send, vars: [], audit: calls.audit, a11y: null });\n changed();\n return () => {\n if (frames.get(trialId)?.send !== calls.send) return;\n frames.delete(trialId);\n changed();\n };\n },\n report: (trialId, vars) => patch(trialId, { vars }),\n reportA11y: (trialId, a11y) => patch(trialId, { a11y }),\n get: (trialId) => frames.get(trialId) ?? NO_FRAME,\n subscribe: changes.subscribe,\n };\n}\n\n/** The workshop's `TrialFrames`; `null` outside a `Workshop`. */\nexport const TrialFramesContext = createContext<TrialFrames | null>(null);\n\n/** The frame of the trial `trialId` names, re-read when it connects or reports. */\nexport function useTrialFrame(trialId: string): TrialFrame {\n const frames = useContext(TrialFramesContext);\n const subscribe = useCallback((listener: () => void) => frames?.subscribe(listener) ?? (() => {}), [frames]);\n const read = () => frames?.get(trialId) ?? NO_FRAME;\n return useSyncExternalStore(subscribe, read, read);\n}\n","import { createContext } from 'react';\nimport type { Globals } from '../protocol/messages';\n\n/** The lab's global values, which a trial's pins override. A change reaches open frames without replacing instruments. */\nexport const StoryGlobalsContext = createContext<Globals>({});\n","/** How far past the viewport a trial's story stays mounted, so a small scroll back does not reload it. */\nexport const IN_VIEW_MARGIN = '50%';\n","import { usePersistedState } from '@weasel-js/labkit';\n\nexport type CssOverrides = Readonly<Record<string, string>>;\n\nconst NONE: CssOverrides = {};\n\n/** The CSS variable overrides of the trial this is rendered inside, persisted with it. */\nexport function useCssOverrides() {\n return usePersistedState<CssOverrides>('fg-css-overrides', NONE, { scope: 'trial' });\n}\n","import { useTrialTitle } from '@weasel-js/labkit';\nimport { type ReactNode, useLayoutEffect, useState } from 'react';\n\nconst overflows = (el: HTMLElement) => el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;\n\n/** Whether `el` currently has more content than it shows, rechecked as it or any child resizes. */\nfunction useOverflowing(el: HTMLElement | null): boolean {\n const [overflowing, setOverflowing] = useState(false);\n useLayoutEffect(() => {\n if (!el || typeof ResizeObserver === 'undefined') return;\n const check = () => setOverflowing(overflows(el));\n const sizes = new ResizeObserver(check);\n const watch = () => {\n sizes.disconnect();\n sizes.observe(el);\n for (const child of el.children) sizes.observe(child, { box: 'border-box' });\n };\n const children = new MutationObserver(() => {\n watch();\n check();\n });\n children.observe(el, { childList: true });\n watch();\n check();\n return () => {\n children.disconnect();\n sizes.disconnect();\n };\n }, [el]);\n return overflowing;\n}\n\n/**\n * The story's own box. While its story overflows it is a tab stop, so a keyboard can scroll it, and a region named\n * for the trial, as WCAG asks of a focusable scroller.\n */\nexport function StoryScroller({ children }: { children: ReactNode }) {\n const [el, setEl] = useState<HTMLDivElement | null>(null);\n const overflowing = useOverflowing(el);\n const title = useTrialTitle();\n return (\n <div\n ref={setEl}\n className=\"fg-story__scroll\"\n {...(overflowing ? { tabIndex: 0, role: 'region', 'aria-label': title ?? 'Story' } : {})}\n >\n {children}\n </div>\n );\n}\n","import { createContext, type RefObject, useContext, useLayoutEffect } from 'react';\n\n/** Each trial's story host, keyed by trial id: `TrialHost` attaches its element, an annotation target reads it. */\nexport interface StoryHosts {\n /** One ref per trial, the same object every time, holding its host while one is attached. */\n ref(trialId: string): RefObject<HTMLElement | null>;\n /**\n * Returns the detach, which leaves a later attach for the same trial standing. `show` renders the host's content\n * while it is out of view, resolving once that has painted, with the release.\n */\n attach(trialId: string, host: HTMLElement, show?: () => Promise<() => void>): () => void;\n /** Renders trial `trialId`'s story wherever it is, until the release it resolves with is called. */\n show(trialId: string): Promise<() => void>;\n}\n\nexport function createStoryHosts(): StoryHosts {\n const refs = new Map<string, RefObject<HTMLElement | null>>();\n const shows = new Map<string, { host: HTMLElement; show: () => Promise<() => void> }>();\n const ref = (trialId: string) => {\n let held = refs.get(trialId);\n if (!held) {\n held = { current: null };\n refs.set(trialId, held);\n }\n return held;\n };\n return {\n ref,\n attach(trialId, host, show) {\n const held = ref(trialId);\n held.current = host;\n if (show) shows.set(trialId, { host, show });\n return () => {\n if (held.current === host) held.current = null;\n if (shows.get(trialId)?.host === host) shows.delete(trialId);\n };\n },\n show(trialId) {\n return shows.get(trialId)?.show() ?? Promise.resolve(() => {});\n },\n };\n}\n\n/** The workshop's `StoryHosts`; `null` outside a `Workshop`. */\nexport const StoryHostsContext = createContext<StoryHosts | null>(null);\n\n/** Attaches `host` as the story host of trial `trialId` while both are given. */\nexport function useStoryHost(\n trialId: string | null | undefined,\n host: HTMLElement | null,\n show?: () => Promise<() => void>,\n): void {\n const hosts = useContext(StoryHostsContext);\n useLayoutEffect(\n () => (host && hosts && trialId ? hosts.attach(trialId, host, show) : undefined),\n [host, hosts, trialId, show],\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\n\n/** Calls `done` once `host`'s fonts are ready and a frame has painted after; returns the cancel. */\nexport function afterPaint(host: HTMLElement, done: () => void): () => void {\n let canceled = false;\n const finish = () => {\n if (!canceled) done();\n };\n const { fonts } = host.ownerDocument;\n if (!fonts) finish();\n else {\n const frame = () => requestAnimationFrame(finish);\n void fonts.ready.then(frame, frame);\n }\n return () => {\n canceled = true;\n };\n}\n\n/**\n * Whether a story host renders its content: while it is near the viewport, or while a caller of `show` holds it.\n * `show` resolves once the content has painted, with the release.\n */\nexport function useStoryShow(\n host: HTMLElement | null,\n inView: boolean,\n): { live: boolean; show: () => Promise<() => void> } {\n const [held, setHeld] = useState(0);\n const [waiters] = useState<(() => void)[]>(() => []);\n const live = inView || held > 0;\n\n const show = useCallback(\n () =>\n new Promise<() => void>((resolve) => {\n let released = false;\n const release = () => {\n if (released) return;\n released = true;\n setHeld((n) => n - 1);\n };\n waiters.push(() => resolve(release));\n setHeld((n) => n + 1);\n }),\n [waiters],\n );\n\n useEffect(() => {\n if (!host || !live || waiters.length === 0) return;\n const waiting = waiters.splice(0);\n let settled = false;\n const cancel = afterPaint(host, () => {\n settled = true;\n for (const resolve of waiting) resolve();\n });\n return () => {\n cancel();\n if (!settled) waiters.unshift(...waiting);\n };\n }, [host, live, held, waiters]);\n\n // A caller still waiting when the host goes finds it gone rather than hanging.\n useEffect(\n () => () => {\n for (const resolve of waiters.splice(0)) resolve();\n },\n [waiters],\n );\n\n return { live, show };\n}\n","import { useLatest } from '@weasel-js/core';\nimport { LabBoundary, TrialIdContext } from '@weasel-js/labkit';\nimport { OverlayPortalProvider } from '@weasel-js/ui/portal-host';\nimport {\n type ReactNode,\n type RefObject,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { auditElement } from '../frame/a11y';\nimport { createA11yHighlighter } from '../frame/a11yHighlight';\nimport { scanCssVars } from '../frame/cssVars';\nimport type { FrameSetup } from '../frame/FrameController';\nimport { useNearViewport } from '@weasel-js/react';\nimport { IN_VIEW_MARGIN } from './inViewMargin';\nimport type { CssVarReport, Globals, Layout, ToFrame } from '../protocol/messages';\nimport { useCssOverrides } from './cssVars/overrides';\nimport { effectiveGlobals, GLOBALS_KEY } from './globals';\nimport { useHostConditions } from './hostConditions';\nimport { StoryGlobalsContext } from './StoryGlobalsContext';\nimport { StoryScroller } from './StoryScroller';\nimport { useStoryHost } from './storyHosts';\nimport { afterPaint, useStoryShow } from './storyShow';\nimport { TrialFramesContext } from './trialFrames';\n\n/** Props for `TrialHost`. */\nexport interface TrialHostProps {\n layout: Layout;\n setup: FrameSetup;\n /** The trial's config, read for its `$globals` pins. */\n config: unknown;\n /** Rendered once the host element exists, with the globals in force on it. */\n children: (globals: Globals) => ReactNode;\n /** Receives the host element, for a caller with no trial to reach it through. */\n hostRef?: RefObject<HTMLElement | null>;\n /** Called once the children's first commit has painted. */\n onRendered?: () => void;\n /**\n * Makes this host a second copy of the trial's story: it takes `id` as its host id and `globals` in place of the\n * computed ones, carries `data-fg-copy`, and stays out of the frame registry, the a11y highlighter and `onRendered`.\n */\n copy?: { id: string; globals: Globals };\n}\n\nconst VARS_SETTLE_MS = 100;\n\n/**\n * The workshop is itself a lab; below the boundary a story sees no lab, trial or theme above it, as in a document of\n * its own. Overlays portal to the host, outside the scroller, so they stay put as it scrolls, and a modal takes the\n * host for its viewport.\n */\nfunction StoryContent({ host, children }: { host: HTMLElement; children: ReactNode }) {\n return (\n <LabBoundary>\n <OverlayPortalProvider container={host} contained>{children}</OverlayPortalProvider>\n </LabBoundary>\n );\n}\n\n/**\n * One story's box in the workshop document: what a frame document was, as an element. It applies the globals to\n * itself, keeps its CSS variable overrides on itself, contains fixed-position descendants and portals, reports its\n * vars and audits to the trial's frame registry, and unmounts its content while out of view unless something holds it shown.\n */\nexport function TrialHost({ layout, setup, config, children, hostRef, onRendered, copy }: TrialHostProps) {\n const trialId = useContext(TrialIdContext);\n const frames = useContext(TrialFramesContext);\n const labGlobals = useContext(StoryGlobalsContext);\n const pins = (config as Record<string, unknown> | null | undefined)?.[GLOBALS_KEY];\n const computed = useMemo(() => effectiveGlobals(labGlobals, pins), [labGlobals, pins]);\n const globals = copy?.globals ?? computed;\n const [persisted] = useCssOverrides();\n const reactId = useId();\n const hostId = copy?.id ?? trialId ?? reactId;\n const [host, setHost] = useState<HTMLDivElement | null>(null);\n const elementRef = useRef<HTMLDivElement | null>(null);\n const inView = useNearViewport(elementRef, IN_VIEW_MARGIN);\n const { live, show } = useStoryShow(host, inView);\n const [pending, setPending] = useState(true);\n // Settles at the first render below, which an audit waits for: until then the host holds no story to judge.\n const [rendered] = useState(() => {\n let resolve!: () => void;\n const promise = new Promise<void>((r) => { resolve = r; });\n return { promise, resolve };\n });\n const latest = useLatest({ onRendered: copy ? undefined : onRendered });\n\n const overridesRef = useHostConditions(host, { hostId, globals, overrides: persisted, setup });\n\n // The registry connection: the host's vars and audits, reported to the trial. A copy has none.\n useLayoutEffect(() => {\n const overrides = overridesRef.current;\n if (!host || !overrides || copy) return;\n const doc = host.ownerDocument;\n let lastVars: CssVarReport[] | null = null;\n let reported: string | null = null;\n const publish = (vars: CssVarReport[]) => {\n lastVars = vars;\n const key = JSON.stringify(vars);\n if (key === reported) return;\n reported = key;\n if (trialId) frames?.report(trialId, vars);\n };\n const scan = () => publish(scanCssVars(doc, overrides.has, host));\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n const ownMutation = (record: MutationRecord) =>\n overrides.owns(record.target) ||\n (record.type === 'childList' &&\n [...record.addedNodes, ...record.removedNodes].length > 0 &&\n [...record.addedNodes, ...record.removedNodes].every(overrides.owns));\n const mutations =\n typeof MutationObserver === 'undefined'\n ? null\n : new MutationObserver((records) => {\n if (records.every(ownMutation)) return;\n clearTimeout(settleTimer);\n settleTimer = setTimeout(scan, VARS_SETTLE_MS);\n });\n mutations?.observe(host, { subtree: true, childList: true, characterData: true, attributes: true });\n\n const highlighter = createA11yHighlighter(doc);\n const send = (msg: ToFrame) => {\n if (msg.type === 'a11y.highlight') highlighter.show(msg.targets);\n if (msg.type !== 'vars.set') return;\n overrides.set(msg.name, msg.value);\n if (lastVars?.some((v) => v.name === msg.name)) scan();\n };\n const audit = async () => {\n await rendered.promise;\n const outcome = await auditElement(host, { page: false });\n if (trialId) frames?.reportA11y(trialId, outcome);\n return outcome;\n };\n const disconnect = frames && trialId ? frames.connect(trialId, { send, audit }) : () => {};\n\n return () => {\n disconnect();\n highlighter.dispose();\n mutations?.disconnect();\n clearTimeout(settleTimer);\n };\n }, [host, hostId, trialId, frames, copy, overridesRef, rendered]);\n\n useStoryHost(trialId, copy ? null : host, show);\n // The host is hidden until its first commit has painted with its fonts, so a new trial never shows a jump.\n const announced = useRef(false);\n useEffect(() => {\n if (!host || !live || announced.current) return;\n return afterPaint(host, () => {\n announced.current = true;\n rendered.resolve();\n setPending(false);\n latest.current.onRendered?.();\n });\n }, [host, live, latest, rendered]);\n\n return (\n <div\n ref={(el) => {\n elementRef.current = el;\n if (hostRef) hostRef.current = el;\n setHost(el);\n }}\n className=\"fg-story\"\n data-fg-host={hostId}\n data-fg-copy={copy ? '' : undefined}\n data-fg-layout={layout}\n data-pending={pending || undefined}\n >\n <StoryScroller>{host && live ? <StoryContent host={host}>{children(globals)}</StoryContent> : null}</StoryScroller>\n </div>\n );\n}\n","import { memo } from 'react';\nimport { StoryHost } from '../frame/StoryHost';\nimport type { Globals } from '../protocol/messages';\nimport type { Decorator, LoadedStory, StoryContext } from '../story/types';\n\nexport interface StoryBodyProps {\n story: LoadedStory;\n config: StoryContext['config'];\n setConfig: StoryContext['setConfig'];\n state: unknown;\n setState: StoryContext['setState'];\n globals: Globals;\n decorators: readonly Decorator[];\n resetKey: number;\n onError: (error: unknown) => void;\n}\n\n/** Calls `render` only when its inputs change, as Storybook does: the lab re-renders a trial for its own reasons, and a\n * story declaring a component inside `render` remounts it on every extra call. */\nexport const StoryBody = memo(function StoryBody({ story, config, setConfig, state, setState, globals, decorators, resetKey, onError }: StoryBodyProps) {\n const storyCtx: StoryContext = { config, setConfig, state, setState, globals, title: story.title, name: story.name };\n return <StoryHost story={story} ctx={storyCtx} decorators={decorators} resetKey={resetKey} onError={onError} />;\n});\n","import type { LabMode } from '@weasel-js/labkit';\nimport { withValueAtPath } from '@weasel-js/labkit/config';\nimport type { Globals } from '../../protocol/messages';\nimport { effectiveGlobals, FOLLOW_APP, GLOBALS_KEY, type GlobalDeclarations } from '../globals';\n\n/** What a lens compares the story against: the opposite color mode, or globals, args and a DPR of its own. */\nexport type ForgeComparison =\n | { kind: 'opposite-mode' }\n | {\n kind: 'custom';\n globals?: Readonly<Record<string, string>>;\n args?: Readonly<Record<string, unknown>>;\n dpr?: number;\n };\n\n/** The conditions a compared render runs under. `dpr` is null where the comparison leaves it alone. */\nexport interface ResolvedConditions {\n globals: Globals;\n args: Readonly<Record<string, unknown>>;\n dpr: number | null;\n}\n\n/** What resolving a comparison reads besides the comparison and the globals it starts from. */\nexport interface ResolveContext {\n declarations: GlobalDeclarations;\n modeGlobal: string;\n prefersDark: boolean;\n labMode: LabMode;\n}\n\nconst NO_ARGS: Readonly<Record<string, unknown>> = {};\n\n/** `value` with `App` read from the lab's own mode and `auto` from the OS, as the story would be shown. */\nfunction shownMode(value: string, ctx: ResolveContext): string {\n const followed = value === FOLLOW_APP ? ctx.labMode : value;\n return followed === 'auto' ? (ctx.prefersDark ? 'dark' : 'light') : followed;\n}\n\nconst SWAP: Readonly<Record<string, string>> = { light: 'dark', dark: 'light' };\n\n/**\n * The mode opposite the one `base` shows, from its declaration's `opposite` or else a swap of light and dark; `to`\n * is undefined where it has none.\n */\nexport function oppositeMode(base: Globals, ctx: ResolveContext): { from: string; to: string | undefined } {\n const from = shownMode(String(base[ctx.modeGlobal] ?? ''), ctx);\n const own = ctx.declarations[ctx.modeGlobal]?.opposite;\n return { from, to: own ? own(from, base) : SWAP[from] };\n}\n\n/**\n * The conditions `c` asks for, starting from `base` — the globals the story renders under before the comparison,\n * pins included. Resolved when a lens renders rather than when the comparison is chosen, so opposite mode keeps\n * showing the opposite after the lab's mode changes; a mode with no opposite leaves the story as it is.\n */\nexport function resolveComparison(c: ForgeComparison | null, base: Globals, ctx: ResolveContext): ResolvedConditions {\n if (c === null) return { globals: base, args: NO_ARGS, dpr: null };\n if (c.kind === 'opposite-mode') {\n const { to } = oppositeMode(base, ctx);\n return { globals: to === undefined ? base : { ...base, [ctx.modeGlobal]: to }, args: NO_ARGS, dpr: null };\n }\n return {\n globals: c.globals ? { ...base, ...c.globals } : base,\n args: c.args ?? NO_ARGS,\n dpr: c.dpr ?? null,\n };\n}\n\n/** A global's value as the toolbar names it: \"Theme: Ocean\". */\nfunction globalLabel(key: string, value: string, declarations: GlobalDeclarations): string {\n const declaration = declarations[key];\n if (!declaration) return `${key}: ${value}`;\n const option = declaration.options.find((o) => o.value === value);\n return `${declaration.label}: ${option?.label ?? value}`;\n}\n\n/** What a lens's comparison is named against: the globals it resolves over, and whether the lens shows Pixels. */\nexport interface DescribeAgainst {\n base: Globals;\n ctx: ResolveContext;\n /** False on a lens that shows no Pixels, where a DPR comparison changes nothing. */\n pixels?: boolean;\n}\n\n/**\n * How a lens names `c`: \"Opposite mode\", \"Theme: Ocean\", \"Arg size = 3\", \"DPR 2×\". Given what the lens renders\n * against, opposite mode says so when there is no opposite to show, and a DPR says it applies to Pixels only on a\n * lens that shows none.\n */\nexport function describeComparison(c: ForgeComparison, declarations: GlobalDeclarations, against?: DescribeAgainst): string {\n if (c.kind === 'opposite-mode') {\n const flip = against ? oppositeMode(against.base, against.ctx) : null;\n return flip && flip.to === undefined ? `Opposite mode: no opposite for '${flip.from}'` : 'Opposite mode';\n }\n const globals = Object.entries(c.globals ?? {}).map(([key, value]) => globalLabel(key, value, declarations));\n const args = Object.entries(c.args ?? {}).map(([path, value]) => `Arg ${path} = ${String(value)}`);\n const dpr = c.dpr ? [`DPR ${c.dpr}×${against?.pixels === false ? ' (Pixels only)' : ''}`] : [];\n return [...globals, ...args, ...dpr].join(', ') || 'As it is';\n}\n\n/**\n * How a lens over a trial names `c`: against that trial's own globals, pins included, as the lens renders it, and\n * whether the lens shows Pixels.\n */\nexport function describeLens(c: ForgeComparison, lab: LabConditions, trialConfig: unknown, pixels: boolean): string {\n const pins = (trialConfig as Record<string, unknown> | null | undefined)?.[GLOBALS_KEY];\n const base = effectiveGlobals(lab.labValues, pins);\n return describeComparison(c, lab.declarations, { base, ctx: resolveContextOf(lab), pixels });\n}\n\n/** `config` with each of `args` written at its path. */\nexport const withArgs = (config: unknown, args: Readonly<Record<string, unknown>>): unknown =>\n Object.entries(args).reduce((c, [path, value]) => withValueAtPath(c, path, value), config);\n\n/** The lab as a lens reads it when it renders: its globals, its mode, and the declarations behind them. */\nexport interface LabConditions {\n labValues: Globals;\n mode: LabMode;\n declarations: GlobalDeclarations;\n modeGlobal: string;\n}\n\n/** What resolving a comparison against `lab` reads, the OS color scheme included. */\nexport function resolveContextOf(lab: LabConditions): ResolveContext {\n const prefersDark = globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;\n return { declarations: lab.declarations, modeGlobal: lab.modeGlobal, prefersDark, labMode: lab.mode };\n}\n","import { createContext } from 'react';\nimport type { ForgeComparison, ResolveContext } from './conditions';\nimport type { TrialHit } from './trialAt';\n\n/** One Live lens cell's ask of the trial under its reticle: render a copy into `slot`, magnified about `hit.local`. */\nexport interface LiveRequest {\n /** The lens's id; a cell showing a comparison adds `~compared`, so a Split lens's two cells are two requests. */\n lensId: string;\n slot: HTMLElement;\n hit: TrialHit;\n factor: number;\n /** The slot's size, in CSS px. */\n size: { width: number; height: number };\n /** What the copy compares against, resolved over the trial's own globals, pins included; null shows the story\n * as it is. */\n compare: ForgeComparison | null;\n ctx: ResolveContext;\n /** Config values written over the trial's at their paths. */\n args: Readonly<Record<string, unknown>>;\n}\n\n/** The Live requests standing, by lens, read by each trial for the copies it owes. */\nexport interface LiveLenses {\n /** `null` withdraws the lens's request. */\n set(lensId: string, request: LiveRequest | null): void;\n /** The same array until a request changes. */\n forTrial(trialId: string): readonly LiveRequest[];\n subscribe(listener: () => void): () => void;\n}\n\nconst NONE: readonly LiveRequest[] = [];\n\nexport function createLiveLenses(): LiveLenses {\n const requests = new Map<string, LiveRequest>();\n const listeners = new Set<() => void>();\n let byTrial = new Map<string, readonly LiveRequest[]>();\n return {\n set(lensId, request) {\n if (request === null) {\n if (!requests.delete(lensId)) return;\n } else requests.set(lensId, request);\n byTrial = new Map();\n for (const listener of [...listeners]) listener();\n },\n forTrial(trialId) {\n let found = byTrial.get(trialId);\n if (!found) {\n const mine = [...requests.values()].filter((r) => r.hit.trialId === trialId);\n found = mine.length === 0 ? NONE : mine;\n byTrial.set(trialId, found);\n }\n return found;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\n/** The workshop's Live requests; null outside a workshop, where no trial renders copies. */\nexport const LiveLensesContext = createContext<LiveLenses | null>(null);\n","import type { LoupePoint } from '@weasel-js/labkit/loupe';\n\n/** The trial under a client point: its host, and the point in the host's own px. */\nexport interface TrialHit {\n trialId: string;\n host: HTMLElement;\n /** In the host's own px: the client offset from its corner, undone by any zoom on the pane holding it. */\n local: LoupePoint;\n /** Client px per host px. */\n scale: number;\n}\n\n/** The element an in-document story scrolls in, inside its host; null for a host with none, as a frame's. */\nexport const scrollerOf = (host: HTMLElement | null): HTMLElement | null =>\n host?.querySelector<HTMLElement>(':scope > .fg-story__scroll') ?? null;\n\nconst stackAt = (client: LoupePoint, doc: Document): readonly Element[] =>\n doc.elementsFromPoint?.(client.x, client.y) ?? [];\n\n/**\n * The topmost story host under `client`, an in-document story's or an isolated one's frame host, skipping a lens's\n * copies, which only ever show some host beneath them.\n */\nexport function trialAt(client: LoupePoint, doc: Document = document): TrialHit | null {\n for (const el of stackAt(client, doc)) {\n const host = el.closest<HTMLElement>('[data-fg-host]');\n if (!host || host.hasAttribute('data-fg-copy')) continue;\n const rect = host.getBoundingClientRect();\n const scale = host.offsetWidth > 0 ? rect.width / host.offsetWidth : 1;\n return {\n trialId: host.dataset.fgHost ?? '',\n host,\n local: { x: (client.x - rect.left) / scale, y: (client.y - rect.top) / scale },\n scale,\n };\n }\n return null;\n}\n","import './loupe.css';\nimport {\n type CSSProperties,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useSyncExternalStore,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { FrameSetup } from '../../frame/FrameController';\nimport type { Globals, Layout } from '../../protocol/messages';\nimport type { ClockHandle } from '@weasel-js/clock';\nimport { ClockContext } from '../../timeline/context';\nimport { effectiveGlobals, GLOBALS_KEY } from '../globals';\nimport { StoryBody, type StoryBodyProps } from '../StoryBody';\nimport { StoryGlobalsContext } from '../StoryGlobalsContext';\nimport { TrialHost } from '../TrialHost';\nimport { resolveComparison, withArgs } from './conditions';\nimport { type LiveLenses, LiveLensesContext, type LiveRequest } from './liveLenses';\nimport { scrollerOf } from './trialAt';\n\n/** Props for `LiveCopies`: what a trial renders its own content with, which every copy of it shares. */\nexport interface LiveCopiesProps {\n trialId: string | null;\n layout: Layout;\n setup: FrameSetup;\n /** The trial's whole config, read for its `$globals` pins. */\n trialConfig: unknown;\n /** One copy's content, under the copy's globals and with the lens's args to write over the trial's config. */\n children: (globals: Globals, args: Readonly<Record<string, unknown>>) => ReactNode;\n}\n\n/** Props for `StoryCopy`. */\nexport interface StoryCopyProps {\n /** The story's own body props; a copy replaces `config`, `setConfig` and `globals`. */\n body: Omit<StoryBodyProps, 'globals'>;\n /** The trial's clock; a copy reads it and never drives it. */\n clock: ClockHandle | null;\n globals: Globals;\n args: Readonly<Record<string, unknown>>;\n}\n\n/** A story trial's copy: its body under the copy's globals, with the lens's args written over its config. */\nexport function StoryCopy({ body, clock, globals, args }: StoryCopyProps) {\n const { config, setConfig } = useCopyConfig(body.config, body.setConfig, args);\n return (\n <ClockContext.Provider value={clock}>\n <StoryBody {...body} config={config} setConfig={setConfig} globals={globals} />\n </ClockContext.Provider>\n );\n}\n\n/** Whether a write to `path` would land on, inside or over the arg at `arg`. */\nconst covers = (arg: string, path: string) =>\n path === arg || path.startsWith(`${arg}.`) || arg.startsWith(`${path}.`);\n\nconst px = (n: number) => `${n}px`;\n\n/** Where the copy sits in its slot: the host's own size, scaled by the factor about the hit point, which lands on the\n * slot's center. Set as custom properties, which the stylesheet reads. */\nfunction placement(request: LiveRequest): CSSProperties {\n const { hit, factor, size } = request;\n return {\n ['--fg-lens-copy-w' as string]: px(hit.host.offsetWidth),\n ['--fg-lens-copy-h' as string]: px(hit.host.offsetHeight),\n ['--fg-lens-copy-x' as string]: px(size.width / 2 - hit.local.x * factor),\n ['--fg-lens-copy-y' as string]: px(size.height / 2 - hit.local.y * factor),\n ['--fg-lens-copy-f' as string]: String(factor),\n } as CSSProperties;\n}\n\n\n/** Runs `sync` after every commit of the copy's content, which mounts a render after the copy's host does. */\nfunction AfterCommit({ sync }: { sync: () => void }) {\n useLayoutEffect(sync);\n return null;\n}\n\n/** The globals a lens's copy renders under: the comparison resolved over the trial's own, pins included. */\nfunction useCopyGlobals(request: LiveRequest, trialConfig: unknown): Globals {\n const labGlobals = useContext(StoryGlobalsContext);\n const pins = (trialConfig as Record<string, unknown> | null | undefined)?.[GLOBALS_KEY];\n const own = useMemo(() => effectiveGlobals(labGlobals, pins), [labGlobals, pins]);\n const { compare, ctx } = request;\n return useMemo<Globals>(() => resolveComparison(compare, own, ctx).globals, [own, compare, ctx]);\n}\n\n/**\n * A copy's config and its writer: the trial's config with each of `args` written at its path, and a `setConfig`\n * that drops a write to any of them, since the comparison owns those, and passes every other write to the trial.\n */\nexport function useCopyConfig(\n trialConfig: unknown,\n trialSetConfig: (path: string, value: unknown) => void,\n args: Readonly<Record<string, unknown>>,\n): { config: unknown; setConfig: (path: string, value: unknown) => void } {\n const config = useMemo(() => withArgs(trialConfig, args), [args, trialConfig]);\n // Keyed by the paths alone, so a comparison re-resolved to the same args keeps the story's `setConfig` stable.\n const argPaths = Object.keys(args).join('\\n');\n const setConfig = useCallback(\n (path: string, value: unknown) => {\n const owned = argPaths === '' ? [] : argPaths.split('\\n');\n if (!owned.some((arg) => covers(arg, path))) trialSetConfig(path, value);\n },\n [argPaths, trialSetConfig],\n );\n return { config, setConfig };\n}\n\n/** Portals a copy into its lens's slot, placed and scaled about the reticle's point. */\nfunction LensPortal({ request, children }: { request: LiveRequest; children: ReactNode }) {\n return createPortal(\n <div className=\"fg-lens-copy\" style={placement(request)}>\n {children}\n </div>,\n request.slot,\n );\n}\n\nconst copyId = (trialId: string, request: LiveRequest) => `${trialId}~lens-${request.lensId}`;\n\n/** The Live requests standing over `trialId`, re-read as they change. */\nfunction useRequests(lenses: LiveLenses, trialId: string): readonly LiveRequest[] {\n const forTrial = useCallback(() => lenses.forTrial(trialId), [lenses, trialId]);\n return useSyncExternalStore(lenses.subscribe, forTrial);\n}\n\nfunction LensCopy({ request, trialId, layout, setup, trialConfig, children }: LiveCopiesProps & { request: LiveRequest; trialId: string }) {\n const globals = useCopyGlobals(request, trialConfig);\n const id = copyId(trialId, request);\n const copy = useMemo(() => ({ id, globals }), [id, globals]);\n\n const main = request.hit.host;\n const { slot } = request;\n // Found from the slot, not through the copy's host ref, which a re-render of the host detaches until after its\n // content's layout effects have run.\n const sync = useCallback(() => {\n const from = scrollerOf(main);\n const to = scrollerOf(slot.querySelector<HTMLElement>(':scope > .fg-lens-copy > [data-fg-copy]'));\n if (!from || !to) return;\n to.scrollTop = from.scrollTop;\n to.scrollLeft = from.scrollLeft;\n }, [main, slot]);\n useEffect(() => {\n const from = scrollerOf(main);\n from?.addEventListener('scroll', sync, { passive: true });\n return () => from?.removeEventListener('scroll', sync);\n }, [main, sync]);\n\n return (\n <LensPortal request={request}>\n {/* Remounted on a new factor: no observer sees a transform change, and a canvas inside sizes its backing\n store for the magnification it mounted under. */}\n <TrialHost key={request.factor} layout={layout} setup={setup} config={trialConfig} copy={copy}>\n {(g) => (\n <>\n {children(g, request.args)}\n <AfterCommit sync={sync} />\n </>\n )}\n </TrialHost>\n </LensPortal>\n );\n}\n\nfunction Copies({ lenses, trialId, ...props }: LiveCopiesProps & { lenses: LiveLenses; trialId: string }) {\n const requests = useRequests(lenses, trialId);\n return requests.map((request) => (\n <LensCopy key={request.lensId} request={request} trialId={trialId} {...props} />\n ));\n}\n\n/**\n * The trial's copies for the Live lenses over it: each a second render of its content, portaled into its lens, under\n * the lens's globals and args, following its scroll.\n */\nexport function LiveCopies(props: LiveCopiesProps) {\n const lenses = useContext(LiveLensesContext);\n const { trialId } = props;\n return lenses && trialId ? <Copies {...props} lenses={lenses} trialId={trialId} /> : null;\n}\n\n/**\n * What a lens's copy of an isolated story renders: its host id, the globals and args it renders under, the trial's\n * host, whose scroll it follows, and the factor the lens shows it at.\n */\nexport interface LensFrameCopy {\n id: string;\n main: HTMLElement;\n globals: Globals;\n args: Readonly<Record<string, unknown>>;\n factor: number;\n}\n\n/** Props for `LiveFrameCopies`. */\nexport interface LiveFrameCopiesProps {\n trialId: string | null;\n /** The trial's whole config, read for its `$globals` pins. */\n trialConfig: unknown;\n /** The trial's frame view in copy mode. */\n children: (copy: LensFrameCopy) => ReactNode;\n}\n\nfunction FrameLensCopy({ request, trialId, trialConfig, children }: Omit<LiveFrameCopiesProps, 'trialId'> & { request: LiveRequest; trialId: string }) {\n const globals = useCopyGlobals(request, trialConfig);\n const id = copyId(trialId, request);\n const { args, factor } = request;\n const main = request.hit.host;\n const copy = useMemo(() => ({ id, main, globals, args, factor }), [id, main, globals, args, factor]);\n return <LensPortal request={request}>{children(copy)}</LensPortal>;\n}\n\nfunction FrameCopies({ lenses, trialId, ...props }: Omit<LiveFrameCopiesProps, 'trialId'> & { lenses: LiveLenses; trialId: string }) {\n const requests = useRequests(lenses, trialId);\n return requests.map((request) => <FrameLensCopy key={request.lensId} request={request} trialId={trialId} {...props} />);\n}\n\n/**\n * The copies an isolated trial owes the Live lenses over it: each a frame of its own, portaled into its lens, under\n * the lens's globals and args, following its scroll. The trial's frame view renders itself as each copy, through\n * `children`.\n */\nexport function LiveFrameCopies(props: LiveFrameCopiesProps) {\n const lenses = useContext(LiveLensesContext);\n const { trialId } = props;\n return lenses && trialId ? <FrameCopies {...props} lenses={lenses} trialId={trialId} /> : null;\n}\n","import { type RenderContext, TrialIdContext, useTrialClockHandle } from '@weasel-js/labkit';\nimport { useLatest } from '@weasel-js/core';\nimport { type RefObject, useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport type { FrameSetup } from '../frame/FrameController';\nimport type { Globals } from '../protocol/messages';\nimport type { Decorator, LoadedStory } from '../story/types';\nimport { ClockContext } from '../timeline/context';\nimport { isForgePath, storyConfig } from './globals';\nimport { LiveCopies, StoryCopy } from './loupe/LiveCopies';\nimport { StoryBody } from './StoryBody';\nimport { TrialHost } from './TrialHost';\n\n/** Props for `StoryTrial`. */\nexport interface StoryTrialProps {\n story: LoadedStory;\n setup: FrameSetup;\n /** The trial's config and state; the story reads and writes them through its `StoryContext`. */\n ctx: Pick<RenderContext<unknown, unknown>, 'config' | 'state' | 'setConfig' | 'setState'>;\n hostRef?: RefObject<HTMLElement | null>;\n onRendered?: () => void;\n /** A render throw, after the boundary has shown it. */\n onError?: (error: unknown) => void;\n}\n\nconst NO_DECORATORS: readonly Decorator[] = [];\n\n/** A story rendered in the workshop document, inside a `TrialHost`, from the trial's own config and state. */\nexport function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }: StoryTrialProps) {\n const latestRef = useLatest(ctx);\n // Kept across a write to a key forge owns, so moving the playhead or a pin does not re-render the story.\n const [heldConfig, setHeldConfig] = useState(() => storyConfig(ctx.config));\n const config = storyConfig(ctx.config, heldConfig);\n if (config !== heldConfig) setHeldConfig(config);\n\n // A trial opened on the provisional instrument starts at `null`; the story's own initial state fills it once.\n const seeded = useRef(false);\n useEffect(() => {\n if (seeded.current || ctx.state !== null || !story.initialState) return;\n seeded.current = true;\n ctx.setState(story.initialState(config));\n }, [ctx, story, config]);\n\n // Each new input retries a render the boundary caught, as the frame did on each message.\n // State, not a ref: a render React throws away takes its bump with it.\n const [input, setInput] = useState({ config, state: ctx.state, key: 0 });\n let resetKey = input.key;\n if (input.config !== config || input.state !== ctx.state) {\n resetKey = input.key + 1;\n setInput({ config, state: ctx.state, key: resetKey });\n }\n\n // Stable, as the frame's were: a story may list them as effect dependencies.\n // The pins belong to the trial; a story cannot see them, so it cannot set them either.\n const setConfig = useCallback((path: string, value: unknown) => {\n if (!isForgePath(path)) latestRef.current.setConfig(path, value);\n }, [latestRef]);\n const setState = useCallback((next: unknown) => latestRef.current.setState(next), [latestRef]);\n\n // The story's clock is the one labkit made for its trial from the timeline the instrument declares.\n const trialId = useContext(TrialIdContext);\n const ownHost = useRef<HTMLElement | null>(null);\n const host = hostRef ?? ownHost;\n const spec = story.timeline?.(config) ?? null;\n const trialClock = useTrialClockHandle();\n const clock = spec ? trialClock : null;\n\n const decorators = setup.decorators ?? NO_DECORATORS;\n const latestError = useLatest(onError);\n const reportError = useCallback((error: unknown) => latestError.current?.(error), [latestError]);\n const body = {\n story,\n config,\n setConfig,\n state: ctx.state,\n setState,\n decorators,\n resetKey,\n onError: reportError,\n };\n const render = (globals: Globals) => (\n <ClockContext.Provider value={clock}>\n <StoryBody {...body} globals={globals} />\n </ClockContext.Provider>\n );\n\n return (\n <>\n <TrialHost\n layout={story.layout}\n setup={setup}\n config={ctx.config}\n hostRef={host}\n {...(onRendered ? { onRendered } : {})}\n >\n {render}\n </TrialHost>\n <LiveCopies trialId={trialId} layout={story.layout} setup={setup} trialConfig={ctx.config}>\n {(globals, args) => <StoryCopy body={body} clock={clock} globals={globals} args={args} />}\n </LiveCopies>\n </>\n );\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { LabMode, LabContribution, LabPage } from '@weasel-js/labkit';
2
2
  import { Theme } from '@weasel-js/theme';
3
3
  import { ControlRenderer } from '@weasel-js/labkit/config';
4
- import { G as Globals, F as FrameSetup } from './FrameController-DgfVaENb.js';
4
+ import { G as Globals, F as FrameSetup } from './FrameController-BM6xuEfY.js';
5
5
  import { IconRef } from '@weasel-js/icons';
6
6
  import { L as Library } from './library-CdTj-hFp.js';
7
7