@weasel-js/forge 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/{chunk-4NM3RTYK.js → chunk-AP3DRQLI.js} +4 -4
- package/dist/chunk-AP3DRQLI.js.map +1 -0
- package/dist/{chunk-V4RI7GWD.js → chunk-BIAEGWGJ.js} +3 -3
- package/dist/{chunk-V4RI7GWD.js.map → chunk-BIAEGWGJ.js.map} +1 -1
- package/dist/{chunk-ENXU34PI.js → chunk-E2FHBDNQ.js} +3 -3
- package/dist/{chunk-ENXU34PI.js.map → chunk-E2FHBDNQ.js.map} +1 -1
- package/dist/frame/index.js +2 -2
- package/dist/shell/index.css +5 -0
- package/dist/shell/index.css.map +1 -1
- package/dist/shell/index.js +149 -70
- package/dist/shell/index.js.map +1 -1
- package/dist/test/index.js +2 -2
- package/dist/vite/index.d.ts +13 -1
- package/dist/vite/index.js +11 -2
- package/dist/vite/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/chunk-4NM3RTYK.js.map +0 -1
package/dist/shell/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { parseRoute, formatRoute, paramsToKnobs, knobPaths, sameKnob, knobsToParams, PLAYHEAD_PARAM, reservedParams } from '../chunk-DKWHGSBZ.js';
|
|
2
2
|
import { DEFAULT_TITLE } from '../chunk-5DXUNLV2.js';
|
|
3
|
-
import { TITLE_LIBRARIES, isIndexId, indexId, indexEntries, librariesFrom, LibrariesContext, schemaFromDescription, LibraryBadge, openChannel, IndexPage } from '../chunk-
|
|
3
|
+
import { TITLE_LIBRARIES, isIndexId, indexId, indexEntries, librariesFrom, LibrariesContext, schemaFromDescription, LibraryBadge, openChannel, IndexPage } from '../chunk-BIAEGWGJ.js';
|
|
4
4
|
import { isGallery } from '../chunk-WEQSLPKT.js';
|
|
5
|
-
import { useTrialFrame, createTrialFrames, createTrialClocks, StoryGlobalsContext, TrialFramesContext, TrialClocksContext, StoryTrial, useCssOverrides, useTrialClock, TrialHost } from '../chunk-
|
|
6
|
-
export { StoryGlobalsContext, StoryTrial, TrialFramesContext, TrialHost, useTrialFrame } from '../chunk-
|
|
5
|
+
import { useTrialFrame, createTrialFrames, createTrialClocks, StoryGlobalsContext, TrialFramesContext, TrialClocksContext, StoryTrial, useCssOverrides, useTrialClock, TrialHost } from '../chunk-E2FHBDNQ.js';
|
|
6
|
+
export { StoryGlobalsContext, StoryTrial, TrialFramesContext, TrialHost, useTrialFrame } from '../chunk-E2FHBDNQ.js';
|
|
7
7
|
import { labGlobals, withGlobals, followApp, storyConfig, GLOBALS_KEY, effectiveGlobals, PLAYHEAD_KEY, labOptions, isGlobalsPath } from '../chunk-DFKCLZKS.js';
|
|
8
|
-
import { loadStories, indexRenderOf, useNearViewport, IN_VIEW_MARGIN } from '../chunk-
|
|
8
|
+
import { loadStories, indexRenderOf, useNearViewport, IN_VIEW_MARGIN } from '../chunk-AP3DRQLI.js';
|
|
9
9
|
import '../chunk-L5XM5VKB.js';
|
|
10
10
|
import '../chunk-ZAWXMUGZ.js';
|
|
11
11
|
import '../chunk-GB6PRJET.js';
|
|
@@ -18,9 +18,10 @@ import { createRoot } from 'react-dom/client';
|
|
|
18
18
|
import { createEmitter } from '@weasel-js/registry';
|
|
19
19
|
import { f, valueAtPath, isConfigBranch } from '@weasel-js/labkit/config';
|
|
20
20
|
import { InfoIcon, ToggleBar, Checkbox, Dialog, TOKEN_CATEGORIES, Icon, DisclosureMark, Button as Button$1, Callout, Slider, Transport, SearchIcon } from '@weasel-js/ui';
|
|
21
|
-
import { TOKEN_MANIFEST, THEME_SOURCES, isByAxis } from '@weasel-js/theme';
|
|
21
|
+
import { themeAxes, weaselTheme, TOKEN_MANIFEST, THEME_SOURCES, resolveTheme, isColorModePreference, isByAxis } from '@weasel-js/theme';
|
|
22
22
|
import { scale, httpThemeApi } from '@weasel-js/theme/engine';
|
|
23
23
|
import { useLatest, historyKey, createHistory, swapOp, isPlainObject } from '@weasel-js/core';
|
|
24
|
+
import { useResolvedColorMode } from '@weasel-js/theme/react';
|
|
24
25
|
|
|
25
26
|
function Finding({ finding }) {
|
|
26
27
|
return /* @__PURE__ */ jsxs("li", { className: "fg-a11y__finding", children: [
|
|
@@ -553,15 +554,24 @@ function applyTokenEdits(definition, edits, selection) {
|
|
|
553
554
|
}
|
|
554
555
|
return { ok: true, definition: root };
|
|
555
556
|
}
|
|
557
|
+
function useTrialSelection(axes, globals) {
|
|
558
|
+
const { mode } = globals;
|
|
559
|
+
const osMode = useResolvedColorMode(isColorModePreference(mode) ? mode : "auto");
|
|
560
|
+
return useMemo(() => {
|
|
561
|
+
const selection = selectionFor(axes, globals);
|
|
562
|
+
return axes.mode && osMode in axes.mode.values ? { mode: osMode, ...selection } : selection;
|
|
563
|
+
}, [axes, globals, osMode]);
|
|
564
|
+
}
|
|
556
565
|
|
|
557
566
|
// src/shell/cssVars/useThemeSave.ts
|
|
558
567
|
var THEME_NAME = "weasel";
|
|
559
568
|
var TOKEN_PREFIX = "--wzl-";
|
|
569
|
+
var NO_AXES = {};
|
|
560
570
|
function useThemeSave({ trialId, globals, themeApi, scales, overrides, history: history2 }) {
|
|
571
|
+
const definition = THEME_SOURCES[THEME_NAME];
|
|
572
|
+
const selection = useTrialSelection(definition?.axes ?? NO_AXES, globals);
|
|
561
573
|
const tokens = useMemo(() => {
|
|
562
|
-
const definition = THEME_SOURCES[THEME_NAME];
|
|
563
574
|
if (!definition) return {};
|
|
564
|
-
const selection = selectionFor(definition.axes ?? {}, globals);
|
|
565
575
|
const generated = new Set(scales.flatMap((scale) => scale.tokens));
|
|
566
576
|
return Object.fromEntries(
|
|
567
577
|
Object.entries(overrides).flatMap(([name, value]) => {
|
|
@@ -570,7 +580,7 @@ function useThemeSave({ trialId, globals, themeApi, scales, overrides, history:
|
|
|
570
580
|
return writtenOut(definition, token, selection) ? [[token, value]] : [];
|
|
571
581
|
})
|
|
572
582
|
);
|
|
573
|
-
}, [
|
|
583
|
+
}, [definition, selection, scales, overrides]);
|
|
574
584
|
const [saving, setSaving] = useState(false);
|
|
575
585
|
const [held, setHeld] = useState(null);
|
|
576
586
|
const setNotice = (next) => setHeld(next && { ...next, trialId });
|
|
@@ -585,7 +595,6 @@ function useThemeSave({ trialId, globals, themeApi, scales, overrides, history:
|
|
|
585
595
|
setNotice({ tone: "error", text: `${file} has changed since this page loaded. Reload to edit against it.` });
|
|
586
596
|
return;
|
|
587
597
|
}
|
|
588
|
-
const selection = selectionFor(stored.definition.axes ?? {}, globals);
|
|
589
598
|
const scaled = applyScaleEdits(stored.definition, Object.fromEntries(scales.map((s) => [s.name, s.edit])), selection);
|
|
590
599
|
const next = scaled.ok ? applyTokenEdits(scaled.definition, tokens, selection) : scaled;
|
|
591
600
|
if (!next.ok) {
|
|
@@ -627,6 +636,21 @@ function useThemeSave({ trialId, globals, themeApi, scales, overrides, history:
|
|
|
627
636
|
save
|
|
628
637
|
};
|
|
629
638
|
}
|
|
639
|
+
var AXES = themeAxes(weaselTheme);
|
|
640
|
+
function useThemeTokens(globals, vars) {
|
|
641
|
+
const selection = useTrialSelection(AXES, globals);
|
|
642
|
+
const themed = useMemo(() => resolveTheme(weaselTheme, selection), [selection]);
|
|
643
|
+
return useMemo(() => {
|
|
644
|
+
const reported = new Map(vars.map((v) => [v.name, v.value]));
|
|
645
|
+
return TOKEN_MANIFEST.map((token) => ({
|
|
646
|
+
name: token.name,
|
|
647
|
+
type: token.type,
|
|
648
|
+
group: token.group,
|
|
649
|
+
value: reported.get(token.name) ?? themed[token.name] ?? token.defaultValue,
|
|
650
|
+
description: token.description
|
|
651
|
+
}));
|
|
652
|
+
}, [vars, themed]);
|
|
653
|
+
}
|
|
630
654
|
var SWAP = "fg.vars.swap";
|
|
631
655
|
var COALESCE_MS = 800;
|
|
632
656
|
var LIMIT = 100;
|
|
@@ -743,22 +767,14 @@ function CssVarsPanel({ globals = NO_GLOBALS, themeApi } = {}) {
|
|
|
743
767
|
const [edited, setEdited] = usePersistedState("fg-css-vars-scales", {}, { scope: "trial" });
|
|
744
768
|
const [tab, setTab] = useState("theme");
|
|
745
769
|
const [filter, setFilter] = useState("");
|
|
770
|
+
const themeTokens = useThemeTokens(globals, frame.vars);
|
|
746
771
|
const tokens = useMemo(() => {
|
|
747
|
-
if (tab === "
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
const reported = new Map(frame.vars.map((v) => [v.name, v.value]));
|
|
754
|
-
return TOKEN_MANIFEST.map((token) => ({
|
|
755
|
-
name: token.name,
|
|
756
|
-
type: token.type,
|
|
757
|
-
group: token.group,
|
|
758
|
-
value: reported.get(token.name) ?? token.defaultValue,
|
|
759
|
-
description: token.description
|
|
760
|
-
}));
|
|
761
|
-
}, [tab, frame.vars]);
|
|
772
|
+
if (tab === "theme") return themeTokens;
|
|
773
|
+
return frame.vars.map(({ name, value }) => {
|
|
774
|
+
const known = MANIFEST.get(name);
|
|
775
|
+
return { name, type: known?.type ?? inferTokenType(value), group: known?.group ?? groupOf(name), value };
|
|
776
|
+
});
|
|
777
|
+
}, [tab, frame.vars, themeTokens]);
|
|
762
778
|
const query = filter.trim().toLowerCase();
|
|
763
779
|
const shown = tokens.map((token) => {
|
|
764
780
|
const override = overrides[token.name];
|
|
@@ -1036,10 +1052,10 @@ var whenIdle = (fn) => {
|
|
|
1036
1052
|
return () => clearTimeout(handle);
|
|
1037
1053
|
};
|
|
1038
1054
|
function createFramePool(frameUrl, size = 2) {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
document.body.append(
|
|
1055
|
+
const shelf2 = document.createElement("div");
|
|
1056
|
+
shelf2.className = "fg-frame-pool";
|
|
1057
|
+
shelf2.setAttribute("aria-hidden", "true");
|
|
1058
|
+
document.body.append(shelf2);
|
|
1043
1059
|
const warm = [];
|
|
1044
1060
|
const waits = /* @__PURE__ */ new Set();
|
|
1045
1061
|
let cancelRefill = null;
|
|
@@ -1066,7 +1082,7 @@ function createFramePool(frameUrl, size = 2) {
|
|
|
1066
1082
|
}, HELLO_TIMEOUT_MS);
|
|
1067
1083
|
waits.add(stop);
|
|
1068
1084
|
window.addEventListener("message", onMessage);
|
|
1069
|
-
|
|
1085
|
+
shelf2.append(frame);
|
|
1070
1086
|
};
|
|
1071
1087
|
const refill = () => {
|
|
1072
1088
|
if (disposed || cancelRefill) return;
|
|
@@ -1087,7 +1103,7 @@ function createFramePool(frameUrl, size = 2) {
|
|
|
1087
1103
|
disposed = true;
|
|
1088
1104
|
cancelRefill?.();
|
|
1089
1105
|
for (const stop of [...waits]) stop();
|
|
1090
|
-
|
|
1106
|
+
shelf2.remove();
|
|
1091
1107
|
}
|
|
1092
1108
|
};
|
|
1093
1109
|
}
|
|
@@ -1097,7 +1113,7 @@ var FramePoolContext = createContext(null);
|
|
|
1097
1113
|
function routedTrial(trials, focusedTrialId, route) {
|
|
1098
1114
|
return trials.find((t) => t.id === focusedTrialId && t.instrumentName === route) ?? trials.find((t) => t.instrumentName === route);
|
|
1099
1115
|
}
|
|
1100
|
-
function PlayheadSync({ trialId, route,
|
|
1116
|
+
function PlayheadSync({ trialId, route, appliedRef }) {
|
|
1101
1117
|
const clock = useTrialClock(trialId);
|
|
1102
1118
|
useEffect(() => {
|
|
1103
1119
|
if (!clock) return;
|
|
@@ -1115,8 +1131,8 @@ function PlayheadSync({ trialId, route, applied }) {
|
|
|
1115
1131
|
held = next;
|
|
1116
1132
|
writePlayheadParam(next);
|
|
1117
1133
|
};
|
|
1118
|
-
if (
|
|
1119
|
-
|
|
1134
|
+
if (appliedRef.current !== route) {
|
|
1135
|
+
appliedRef.current = route;
|
|
1120
1136
|
fromUrl();
|
|
1121
1137
|
}
|
|
1122
1138
|
toUrl();
|
|
@@ -1132,7 +1148,7 @@ function PlayheadSync({ trialId, route, applied }) {
|
|
|
1132
1148
|
off();
|
|
1133
1149
|
window.removeEventListener("hashchange", onHashChange);
|
|
1134
1150
|
};
|
|
1135
|
-
}, [clock, route,
|
|
1151
|
+
}, [clock, route, appliedRef]);
|
|
1136
1152
|
return null;
|
|
1137
1153
|
}
|
|
1138
1154
|
function RoutePlayhead() {
|
|
@@ -1141,7 +1157,7 @@ function RoutePlayhead() {
|
|
|
1141
1157
|
const applied = useRef(null);
|
|
1142
1158
|
const trial = route === null ? void 0 : routedTrial(lab.trials, lab.focusedTrialId, route);
|
|
1143
1159
|
if (!trial || route === null) return null;
|
|
1144
|
-
return /* @__PURE__ */ jsx(PlayheadSync, { trialId: trial.id, route, applied }, `${trial.id} ${route}`);
|
|
1160
|
+
return /* @__PURE__ */ jsx(PlayheadSync, { trialId: trial.id, route, appliedRef: applied }, `${trial.id} ${route}`);
|
|
1145
1161
|
}
|
|
1146
1162
|
var RECORD = "fg-globals";
|
|
1147
1163
|
function useLabGlobals(declarations) {
|
|
@@ -1481,13 +1497,13 @@ function StoryTree({ ctx, index }) {
|
|
|
1481
1497
|
}, [index]);
|
|
1482
1498
|
const enabled = (value) => views.some((item) => item.value === value && !item.disabled);
|
|
1483
1499
|
const view = [chosen, "components", "gallery"].find(enabled) ?? chosen;
|
|
1484
|
-
const
|
|
1500
|
+
const kept2 = useMemo(() => index.filter((entry) => !hidden[table.of(entry)]), [index, hidden, table]);
|
|
1485
1501
|
const [galleryEntries, rest] = useMemo(() => {
|
|
1486
1502
|
const yes = [];
|
|
1487
1503
|
const no = [];
|
|
1488
|
-
for (const entry of
|
|
1504
|
+
for (const entry of kept2) (isGallery(entry) ? yes : no).push(entry);
|
|
1489
1505
|
return [yes, no];
|
|
1490
|
-
}, [
|
|
1506
|
+
}, [kept2]);
|
|
1491
1507
|
const tree = useMemo(() => buildTree(rest), [rest]);
|
|
1492
1508
|
const components = useMemo(() => buildComponents(rest, table), [rest, table]);
|
|
1493
1509
|
const galleries = useMemo(() => buildComponents(galleryEntries, table), [galleryEntries, table]);
|
|
@@ -1495,7 +1511,7 @@ function StoryTree({ ctx, index }) {
|
|
|
1495
1511
|
() => view === "tree" ? filterTree(tree, query) : componentNodes(filterComponents(view === "gallery" ? galleries : components, query)),
|
|
1496
1512
|
[view, components, galleries, tree, query]
|
|
1497
1513
|
);
|
|
1498
|
-
const routable = useMemo(() => [...
|
|
1514
|
+
const routable = useMemo(() => [...kept2, ...indexEntries(kept2)], [kept2]);
|
|
1499
1515
|
const routed = routable.find((entry) => entry.id === route);
|
|
1500
1516
|
const routeAncestors = useMemo(() => ancestorsOf(routed), [routed]);
|
|
1501
1517
|
const filtering = query.trim() !== "";
|
|
@@ -1786,6 +1802,54 @@ function createAnswerBook() {
|
|
|
1786
1802
|
|
|
1787
1803
|
// src/shell/readyKey.ts
|
|
1788
1804
|
var readyKey = (ready) => stableStringify({ schema: ready.schema, layout: ready.layout, viewport: ready.viewport });
|
|
1805
|
+
var kept = /* @__PURE__ */ new Map();
|
|
1806
|
+
var shelf = null;
|
|
1807
|
+
function shelfElement() {
|
|
1808
|
+
if (!shelf) {
|
|
1809
|
+
shelf = document.createElement("div");
|
|
1810
|
+
shelf.className = "fg-frame-pool";
|
|
1811
|
+
shelf.setAttribute("aria-hidden", "true");
|
|
1812
|
+
}
|
|
1813
|
+
if (!shelf.isConnected) document.body.append(shelf);
|
|
1814
|
+
return shelf;
|
|
1815
|
+
}
|
|
1816
|
+
function adopt({ key, slot, frame, link, onAdopt }) {
|
|
1817
|
+
const waiting = key === null ? void 0 : kept.get(key);
|
|
1818
|
+
if (key === null || !waiting || !slot.current) return;
|
|
1819
|
+
kept.delete(key);
|
|
1820
|
+
moveFrame(slot.current, waiting.frame);
|
|
1821
|
+
frame.current = waiting.frame;
|
|
1822
|
+
link.current = waiting.link;
|
|
1823
|
+
onAdopt(waiting.link);
|
|
1824
|
+
}
|
|
1825
|
+
function shelve(options) {
|
|
1826
|
+
const { key, frame, link, onDrop } = options.current;
|
|
1827
|
+
const element = frame.current;
|
|
1828
|
+
const current = link.current;
|
|
1829
|
+
if (key === null || !element?.isConnected || !current || !canMoveFrames()) return false;
|
|
1830
|
+
if (current.awaiting === null && current.sent === null) return false;
|
|
1831
|
+
const entry = { frame: element, link: current };
|
|
1832
|
+
moveFrame(shelfElement(), element);
|
|
1833
|
+
kept.set(key, entry);
|
|
1834
|
+
queueMicrotask(() => {
|
|
1835
|
+
if (kept.get(key) !== entry) return;
|
|
1836
|
+
kept.delete(key);
|
|
1837
|
+
onDrop();
|
|
1838
|
+
element.remove();
|
|
1839
|
+
});
|
|
1840
|
+
return true;
|
|
1841
|
+
}
|
|
1842
|
+
function useKeptFrame(options) {
|
|
1843
|
+
const handedOn = useRef(false);
|
|
1844
|
+
const latest = useLatest(options);
|
|
1845
|
+
useLayoutEffect(() => {
|
|
1846
|
+
adopt(latest.current);
|
|
1847
|
+
return () => {
|
|
1848
|
+
if (shelve(latest)) handedOn.current = true;
|
|
1849
|
+
};
|
|
1850
|
+
}, [latest]);
|
|
1851
|
+
return useCallback(() => handedOn.current, []);
|
|
1852
|
+
}
|
|
1789
1853
|
var START_TIMEOUT_MS = 1e4;
|
|
1790
1854
|
var requests = 0;
|
|
1791
1855
|
function closeLink(link) {
|
|
@@ -1800,6 +1864,27 @@ function closeLink(link) {
|
|
|
1800
1864
|
function mismatchMessage(mismatch) {
|
|
1801
1865
|
return mismatch.reason === "version" ? `Frame speaks protocol ${String(mismatch.version)}; this workshop speaks ${PROTOCOL_VERSION}` : "Frame sent a message that is not a forge envelope";
|
|
1802
1866
|
}
|
|
1867
|
+
function sendInputs(current, sent, next) {
|
|
1868
|
+
const before = current.inputs;
|
|
1869
|
+
const { state, globals } = next;
|
|
1870
|
+
const config = storyConfig(next.config, sent.config);
|
|
1871
|
+
if (config !== sent.config) {
|
|
1872
|
+
sent.config = config;
|
|
1873
|
+
current.channel.send({ type: "config", config });
|
|
1874
|
+
current.inputs += 1;
|
|
1875
|
+
}
|
|
1876
|
+
if (state !== sent.state) {
|
|
1877
|
+
sent.state = state;
|
|
1878
|
+
current.channel.send({ type: "state", state });
|
|
1879
|
+
current.inputs += 1;
|
|
1880
|
+
}
|
|
1881
|
+
if (globals !== sent.globals && stableStringify(globals) !== stableStringify(sent.globals)) {
|
|
1882
|
+
sent.globals = globals;
|
|
1883
|
+
current.channel.send({ type: "globals", globals });
|
|
1884
|
+
current.inputs += 1;
|
|
1885
|
+
}
|
|
1886
|
+
return current.inputs !== before;
|
|
1887
|
+
}
|
|
1803
1888
|
function FrameView(props) {
|
|
1804
1889
|
const { entry, frameUrl, answers, descriptionKey, ctx } = props;
|
|
1805
1890
|
const labGlobals2 = useContext(StoryGlobalsContext);
|
|
@@ -1906,6 +1991,7 @@ function FrameView(props) {
|
|
|
1906
1991
|
};
|
|
1907
1992
|
const current = {
|
|
1908
1993
|
channel,
|
|
1994
|
+
deliver: (msg) => receive(current, msg),
|
|
1909
1995
|
timer,
|
|
1910
1996
|
awaiting: null,
|
|
1911
1997
|
sent: null,
|
|
@@ -1916,23 +2002,35 @@ function FrameView(props) {
|
|
|
1916
2002
|
queued: []
|
|
1917
2003
|
};
|
|
1918
2004
|
link.current = current;
|
|
1919
|
-
channel.on((msg) =>
|
|
2005
|
+
channel.on((msg) => current.deliver(msg));
|
|
1920
2006
|
target.postMessage({ type: PORT_HANDOFF, id: latestRef.current.entry.id }, location.origin, [
|
|
1921
2007
|
port2
|
|
1922
2008
|
]);
|
|
1923
2009
|
};
|
|
1924
2010
|
const connectRef = useLatest(connect);
|
|
2011
|
+
const handedOn = useKeptFrame({
|
|
2012
|
+
key: trialId ? `${trialId} ${src}` : null,
|
|
2013
|
+
slot: slotRef,
|
|
2014
|
+
frame: iframeRef,
|
|
2015
|
+
link,
|
|
2016
|
+
onAdopt: (adopted) => {
|
|
2017
|
+
adopted.deliver = (msg) => receive(adopted, msg);
|
|
2018
|
+
setPending(!adopted.hasRendered);
|
|
2019
|
+
},
|
|
2020
|
+
onDrop: () => closeLink(link)
|
|
2021
|
+
});
|
|
1925
2022
|
useEffect(() => {
|
|
1926
2023
|
const slot = slotRef.current;
|
|
1927
2024
|
if (!inView || !slot) return;
|
|
1928
|
-
const
|
|
1929
|
-
const
|
|
2025
|
+
const adopted = iframeRef.current;
|
|
2026
|
+
const claimed = adopted ? null : latestRef.current.pool?.claim() ?? null;
|
|
2027
|
+
const frame = adopted ?? claimed ?? document.createElement("iframe");
|
|
1930
2028
|
frame.className = "fg-frame-view";
|
|
1931
2029
|
frame.title = latestRef.current.title;
|
|
1932
2030
|
frame.removeAttribute("tabindex");
|
|
1933
2031
|
frame.toggleAttribute("data-pending", true);
|
|
1934
2032
|
iframeRef.current = frame;
|
|
1935
|
-
const unheard = claimed ? void 0 : setTimeout(() => setFault({ phase: null, message: `Frame did not start: ${src}` }), HELLO_TIMEOUT_MS);
|
|
2033
|
+
const unheard = adopted || claimed ? void 0 : setTimeout(() => setFault({ phase: null, message: `Frame did not start: ${src}` }), HELLO_TIMEOUT_MS);
|
|
1936
2034
|
const onMessage = (event) => {
|
|
1937
2035
|
if (event.source !== frame.contentWindow || event.origin !== location.origin) return;
|
|
1938
2036
|
if (event.data?.type !== FRAME_HELLO) return;
|
|
@@ -1943,20 +2041,21 @@ function FrameView(props) {
|
|
|
1943
2041
|
if (claimed) {
|
|
1944
2042
|
moveFrame(slot, claimed);
|
|
1945
2043
|
connectRef.current(claimed);
|
|
1946
|
-
} else {
|
|
2044
|
+
} else if (!adopted) {
|
|
1947
2045
|
frame.src = src;
|
|
1948
2046
|
slot.append(frame);
|
|
1949
2047
|
}
|
|
1950
2048
|
return () => {
|
|
1951
2049
|
window.removeEventListener("message", onMessage);
|
|
1952
2050
|
clearTimeout(unheard);
|
|
2051
|
+
if (handedOn()) return;
|
|
1953
2052
|
closeLink(link);
|
|
1954
2053
|
frame.remove();
|
|
1955
2054
|
iframeRef.current = null;
|
|
1956
2055
|
setPending(true);
|
|
1957
2056
|
setFault(null);
|
|
1958
2057
|
};
|
|
1959
|
-
}, [inView, src, connectRef, latestRef]);
|
|
2058
|
+
}, [inView, src, connectRef, latestRef, handedOn]);
|
|
1960
2059
|
useEffect(() => {
|
|
1961
2060
|
iframeRef.current?.toggleAttribute("data-pending", pending && !fault);
|
|
1962
2061
|
}, [pending, fault, inView, src]);
|
|
@@ -1971,29 +2070,9 @@ function FrameView(props) {
|
|
|
1971
2070
|
if (current.awaiting === descriptionKey) init(current);
|
|
1972
2071
|
return;
|
|
1973
2072
|
}
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
let input = false;
|
|
1977
|
-
const config = storyConfig(ctx.config, sent.config);
|
|
1978
|
-
if (config !== sent.config) {
|
|
1979
|
-
sent.config = config;
|
|
1980
|
-
current.channel.send({ type: "config", config });
|
|
1981
|
-
current.inputs += 1;
|
|
1982
|
-
input = true;
|
|
1983
|
-
}
|
|
1984
|
-
if (ctx.state !== sent.state) {
|
|
1985
|
-
sent.state = ctx.state;
|
|
1986
|
-
current.channel.send({ type: "state", state: ctx.state });
|
|
1987
|
-
current.inputs += 1;
|
|
1988
|
-
input = true;
|
|
1989
|
-
}
|
|
1990
|
-
if (globals !== sent.globals && stableStringify(globals) !== stableStringify(sent.globals)) {
|
|
1991
|
-
sent.globals = globals;
|
|
1992
|
-
current.channel.send({ type: "globals", globals });
|
|
1993
|
-
current.inputs += 1;
|
|
1994
|
-
input = true;
|
|
2073
|
+
if (current.sent && sendInputs(current, current.sent, { config: ctx.config, state: ctx.state, globals })) {
|
|
2074
|
+
setFault((shown) => shown?.phase === "render" ? null : shown);
|
|
1995
2075
|
}
|
|
1996
|
-
if (input) setFault((shown) => shown?.phase === "render" ? null : shown);
|
|
1997
2076
|
}, [ctx.config, ctx.state, globals, descriptionKey, init]);
|
|
1998
2077
|
return /* @__PURE__ */ jsxs("div", { ref: hostRef, className: "fg-frame-host", children: [
|
|
1999
2078
|
/* @__PURE__ */ jsx("div", { ref: slotRef, className: "fg-frame-slot" }),
|
|
@@ -2172,7 +2251,7 @@ function useStoryRegistry(index, options) {
|
|
|
2172
2251
|
const answers = previous.books.get(entry.id) ?? createAnswerBook();
|
|
2173
2252
|
books.set(entry.id, answers);
|
|
2174
2253
|
const held = previous.built.get(entry.id);
|
|
2175
|
-
const
|
|
2254
|
+
const kept2 = held && held.entryKey === entryKey && held.ready === ready && held.loaded === had && held.fault === fault && held.frameUrl === frameUrl && held.globals === globals && held.setup === setup && held.inDocument === inDocument && held.generation === generation && held.revision === revision ? held : {
|
|
2176
2255
|
entryKey,
|
|
2177
2256
|
ready,
|
|
2178
2257
|
loaded: had,
|
|
@@ -2185,8 +2264,8 @@ function useStoryRegistry(index, options) {
|
|
|
2185
2264
|
revision,
|
|
2186
2265
|
instrument: !inDocument ? storyInstrument({ entry, ready, answers, frameUrl, onReady, globals }) : had ? documentInstrument({ entry, loaded: had, setup, globals }) : pendingInstrument({ entry, globals, load: request, generation, ...fault ? { fault } : {} })
|
|
2187
2266
|
};
|
|
2188
|
-
built.set(entry.id,
|
|
2189
|
-
return
|
|
2267
|
+
built.set(entry.id, kept2);
|
|
2268
|
+
return kept2.instrument;
|
|
2190
2269
|
});
|
|
2191
2270
|
const unchanged = list.length === previous.list.length && list.every((i, n) => i === previous.list[n]);
|
|
2192
2271
|
return { built, books, list: unchanged ? previous.list : list };
|