@weasel-js/forge 1.15.1 → 1.15.2
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.
|
@@ -6,7 +6,7 @@ import { createContext, memo, useContext, useCallback, useSyncExternalStore, use
|
|
|
6
6
|
import { useLatest } from '@weasel-js/core';
|
|
7
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
|
+
import { useNearViewport, systemColorScheme } from '@weasel-js/react';
|
|
10
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
11
|
import { createPortal } from 'react-dom';
|
|
12
12
|
import { withValueAtPath } from '@weasel-js/labkit/config';
|
|
@@ -333,13 +333,13 @@ function describeLens(c, lab, trialConfig, pixels) {
|
|
|
333
333
|
}
|
|
334
334
|
var withArgs = (config, args) => Object.entries(args).reduce((c, [path, value]) => withValueAtPath(c, path, value), config);
|
|
335
335
|
function resolveContextOf(lab) {
|
|
336
|
-
const prefersDark =
|
|
336
|
+
const prefersDark = systemColorScheme() === "dark";
|
|
337
337
|
return { declarations: lab.declarations, modeGlobal: lab.modeGlobal, prefersDark, labMode: lab.mode };
|
|
338
338
|
}
|
|
339
339
|
var NONE2 = [];
|
|
340
340
|
function createLiveLenses() {
|
|
341
341
|
const requests = /* @__PURE__ */ new Map();
|
|
342
|
-
const
|
|
342
|
+
const changed = createEmitter();
|
|
343
343
|
let byTrial = /* @__PURE__ */ new Map();
|
|
344
344
|
return {
|
|
345
345
|
set(lensId, request) {
|
|
@@ -347,7 +347,7 @@ function createLiveLenses() {
|
|
|
347
347
|
if (!requests.delete(lensId)) return;
|
|
348
348
|
} else requests.set(lensId, request);
|
|
349
349
|
byTrial = /* @__PURE__ */ new Map();
|
|
350
|
-
|
|
350
|
+
changed.emit();
|
|
351
351
|
},
|
|
352
352
|
forTrial(trialId) {
|
|
353
353
|
let found = byTrial.get(trialId);
|
|
@@ -358,10 +358,7 @@ function createLiveLenses() {
|
|
|
358
358
|
}
|
|
359
359
|
return found;
|
|
360
360
|
},
|
|
361
|
-
subscribe
|
|
362
|
-
listeners.add(listener);
|
|
363
|
-
return () => listeners.delete(listener);
|
|
364
|
-
}
|
|
361
|
+
subscribe: changed.subscribe
|
|
365
362
|
};
|
|
366
363
|
}
|
|
367
364
|
var LiveLensesContext = createContext(null);
|
|
@@ -542,5 +539,5 @@ function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
|
|
|
542
539
|
}
|
|
543
540
|
|
|
544
541
|
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-
|
|
546
|
-
//# sourceMappingURL=chunk-
|
|
542
|
+
//# sourceMappingURL=chunk-SZ2SMRE6.js.map
|
|
543
|
+
//# sourceMappingURL=chunk-SZ2SMRE6.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","createEmitter","useMemo","useSyncExternalStore","useLatest","useRef","TrialIdContext","jsxs","Fragment"],"mappings":";;;;;;;;;;;;;AAkCA,IAAM,QAAA,GAAuB,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,EAAC,EAAG,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,IAAA,EAAK;AAEtE,SAAS,iBAAA,GAAiC;AAC/C,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwB;AAC3C,EAAA,MAAM,UAAU,aAAA,EAAc;AAC9B,EAAA,MAAM,UAAU,OAAA,CAAQ,IAAA;AACxB,EAAA,MAAM,KAAA,GAAQ,CAAC,OAAA,EAAiB,IAAA,KAA8B;AAC5D,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA;AAChC,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,MAAA,CAAO,IAAI,OAAA,EAAS,EAAE,GAAG,KAAA,EAAO,GAAG,MAAM,CAAA;AACzC,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AACA,EAAA,OAAO;AAAA,IACL,OAAA,CAAQ,SAAS,KAAA,EAAO;AACtB,MAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,IAAA,EAAM,IAAA,EAAM,EAAC,EAAG,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,IAAA,EAAM,MAAM,CAAA;AAClF,MAAA,OAAA,EAAQ;AACR,MAAA,OAAO,MAAM;AACX,QAAA,IAAI,OAAO,GAAA,CAAI,OAAO,CAAA,EAAG,IAAA,KAAS,MAAM,IAAA,EAAM;AAC9C,QAAA,MAAA,CAAO,OAAO,OAAO,CAAA;AACrB,QAAA,OAAA,EAAQ;AAAA,MACV,CAAA;AAAA,IACF,CAAA;AAAA,IACA,MAAA,EAAQ,CAAC,OAAA,EAAS,IAAA,KAAS,MAAM,OAAA,EAAS,EAAE,MAAM,CAAA;AAAA,IAClD,UAAA,EAAY,CAAC,OAAA,EAAS,IAAA,KAAS,MAAM,OAAA,EAAS,EAAE,MAAM,CAAA;AAAA,IACtD,KAAK,CAAC,OAAA,KAAY,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA,IAAK,QAAA;AAAA,IACzC,WAAW,OAAA,CAAQ;AAAA,GACrB;AACF;AAGO,IAAM,kBAAA,GAAqB,cAAkC,IAAI;AAGjE,SAAS,cAAc,OAAA,EAA6B;AACzD,EAAA,MAAM,MAAA,GAAS,WAAW,kBAAkB,CAAA;AAC5C,EAAA,MAAM,SAAA,GAAY,YAAY,CAAC,QAAA,KAAyB,QAAQ,SAAA,CAAU,QAAQ,MAAM,MAAM;AAAA,EAAC,CAAA,CAAA,EAAI,CAAC,MAAM,CAAC,CAAA;AAC3G,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,EAAQ,GAAA,CAAI,OAAO,CAAA,IAAK,QAAA;AAC3C,EAAA,OAAO,oBAAA,CAAqB,SAAA,EAAW,IAAA,EAAM,IAAI,CAAA;AACnD;ACpEO,IAAM,mBAAA,GAAsBA,aAAAA,CAAuB,EAAE;;;ACHrD,IAAM,cAAA,GAAiB;ACG9B,IAAM,OAAqB,EAAC;AAGrB,SAAS,eAAA,GAAkB;AAChC,EAAA,OAAO,kBAAgC,kBAAA,EAAoB,IAAA,EAAM,EAAE,KAAA,EAAO,SAAS,CAAA;AACrF;ACNA,IAAM,SAAA,GAAY,CAAC,EAAA,KAAoB,EAAA,CAAG,eAAe,EAAA,CAAG,YAAA,IAAgB,EAAA,CAAG,WAAA,GAAc,EAAA,CAAG,WAAA;AAGhG,SAAS,eAAe,EAAA,EAAiC;AACvD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,KAAK,CAAA;AACpD,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,CAAC,EAAA,IAAM,OAAO,cAAA,KAAmB,WAAA,EAAa;AAClD,IAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,SAAA,CAAU,EAAE,CAAC,CAAA;AAChD,IAAA,MAAM,KAAA,GAAQ,IAAI,cAAA,CAAe,KAAK,CAAA;AACtC,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,KAAA,CAAM,UAAA,EAAW;AACjB,MAAA,KAAA,CAAM,QAAQ,EAAE,CAAA;AAChB,MAAA,KAAA,MAAW,KAAA,IAAS,GAAG,QAAA,EAAU,KAAA,CAAM,QAAQ,KAAA,EAAO,EAAE,GAAA,EAAK,YAAA,EAAc,CAAA;AAAA,IAC7E,CAAA;AACA,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM;AAC1C,MAAA,KAAA,EAAM;AACN,MAAA,KAAA,EAAM;AAAA,IACR,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,OAAA,CAAQ,EAAA,EAAI,EAAE,SAAA,EAAW,MAAM,CAAA;AACxC,IAAA,KAAA,EAAM;AACN,IAAA,KAAA,EAAM;AACN,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,KAAA,CAAM,UAAA,EAAW;AAAA,IACnB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,EAAE,CAAC,CAAA;AACP,EAAA,OAAO,WAAA;AACT;AAMO,SAAS,aAAA,CAAc,EAAE,QAAA,EAAS,EAA4B;AACnE,EAAA,MAAM,CAAC,EAAA,EAAI,KAAK,CAAA,GAAI,SAAgC,IAAI,CAAA;AACxD,EAAA,MAAM,WAAA,GAAc,eAAe,EAAE,CAAA;AACrC,EAAA,MAAM,QAAQ,aAAA,EAAc;AAC5B,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,KAAA;AAAA,MACL,SAAA,EAAU,kBAAA;AAAA,MACT,GAAI,WAAA,GAAc,EAAE,QAAA,EAAU,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,KAAA,IAAS,OAAA,EAAQ,GAAI,EAAC;AAAA,MAErF;AAAA;AAAA,GACH;AAEJ;AClCO,SAAS,gBAAA,GAA+B;AAC7C,EAAA,MAAM,IAAA,uBAAW,GAAA,EAA2C;AAC5D,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAoE;AACtF,EAAA,MAAM,GAAA,GAAM,CAAC,OAAA,KAAoB;AAC/B,IAAA,IAAI,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA;AAC3B,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,EAAE,SAAS,IAAA,EAAK;AACvB,MAAA,IAAA,CAAK,GAAA,CAAI,SAAS,IAAI,CAAA;AAAA,IACxB;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AACA,EAAA,OAAO;AAAA,IACL,GAAA;AAAA,IACA,MAAA,CAAO,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM;AAC1B,MAAA,MAAM,IAAA,GAAO,IAAI,OAAO,CAAA;AACxB,MAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,MAAA,IAAI,MAAM,KAAA,CAAM,GAAA,CAAI,SAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAC3C,MAAA,OAAO,MAAM;AACX,QAAA,IAAI,IAAA,CAAK,OAAA,KAAY,IAAA,EAAM,IAAA,CAAK,OAAA,GAAU,IAAA;AAC1C,QAAA,IAAI,KAAA,CAAM,IAAI,OAAO,CAAA,EAAG,SAAS,IAAA,EAAM,KAAA,CAAM,OAAO,OAAO,CAAA;AAAA,MAC7D,CAAA;AAAA,IACF,CAAA;AAAA,IACA,KAAK,OAAA,EAAS;AACZ,MAAA,OAAO,KAAA,CAAM,IAAI,OAAO,CAAA,EAAG,MAAK,IAAK,OAAA,CAAQ,QAAQ,MAAM;AAAA,MAAC,CAAC,CAAA;AAAA,IAC/D;AAAA,GACF;AACF;AAGO,IAAM,iBAAA,GAAoBA,cAAiC,IAAI;AAG/D,SAAS,YAAA,CACd,OAAA,EACA,IAAA,EACA,IAAA,EACM;AACN,EAAA,MAAM,KAAA,GAAQC,WAAW,iBAAiB,CAAA;AAC1C,EAAAC,eAAAA;AAAA,IACE,MAAO,QAAQ,KAAA,IAAS,OAAA,GAAU,MAAM,MAAA,CAAO,OAAA,EAAS,IAAA,EAAM,IAAI,CAAA,GAAI,MAAA;AAAA,IACtE,CAAC,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,IAAI;AAAA,GAC7B;AACF;ACtDO,SAAS,UAAA,CAAW,MAAmB,IAAA,EAA8B;AAC1E,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI,CAAC,UAAU,IAAA,EAAK;AAAA,EACtB,CAAA;AACA,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,IAAA,CAAK,aAAA;AACvB,EAAA,IAAI,CAAC,OAAO,MAAA,EAAO;AAAA,OACd;AACH,IAAA,MAAM,KAAA,GAAQ,MAAM,qBAAA,CAAsB,MAAM,CAAA;AAChD,IAAA,KAAK,KAAA,CAAM,KAAA,CAAM,IAAA,CAAK,KAAA,EAAO,KAAK,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAM;AACX,IAAA,QAAA,GAAW,IAAA;AAAA,EACb,CAAA;AACF;AAMO,SAAS,YAAA,CACd,MACA,MAAA,EACoD;AACpD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIC,SAAS,CAAC,CAAA;AAClC,EAAA,MAAM,CAAC,OAAO,CAAA,GAAIA,QAAAA,CAAyB,MAAM,EAAE,CAAA;AACnD,EAAA,MAAM,IAAA,GAAO,UAAU,IAAA,GAAO,CAAA;AAE9B,EAAA,MAAM,IAAA,GAAOC,WAAAA;AAAA,IACX,MACE,IAAI,OAAA,CAAoB,CAAC,OAAA,KAAY;AACnC,MAAA,IAAI,QAAA,GAAW,KAAA;AACf,MAAA,MAAM,UAAU,MAAM;AACpB,QAAA,IAAI,QAAA,EAAU;AACd,QAAA,QAAA,GAAW,IAAA;AACX,QAAA,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAAA,MACtB,CAAA;AACA,MAAA,OAAA,CAAQ,IAAA,CAAK,MAAM,OAAA,CAAQ,OAAO,CAAC,CAAA;AACnC,MAAA,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAAA,IACtB,CAAC,CAAA;AAAA,IACH,CAAC,OAAO;AAAA,GACV;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,IAAQ,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC5C,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA;AAChC,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,MAAM,MAAA,GAAS,UAAA,CAAW,IAAA,EAAM,MAAM;AACpC,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,KAAA,MAAW,OAAA,IAAW,SAAS,OAAA,EAAQ;AAAA,IACzC,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,EAAO;AACP,MAAA,IAAI,CAAC,OAAA,EAAS,OAAA,CAAQ,OAAA,CAAQ,GAAG,OAAO,CAAA;AAAA,IAC1C,CAAA;AAAA,EACF,GAAG,CAAC,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,OAAO,CAAC,CAAA;AAG9B,EAAA,SAAA;AAAA,IACE,MAAM,MAAM;AACV,MAAA,KAAA,MAAW,OAAA,IAAW,OAAA,CAAQ,MAAA,CAAO,CAAC,GAAG,OAAA,EAAQ;AAAA,IACnD,CAAA;AAAA,IACA,CAAC,OAAO;AAAA,GACV;AAEA,EAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AACtB;ACpBA,IAAM,cAAA,GAAiB,GAAA;AAOvB,SAAS,YAAA,CAAa,EAAE,IAAA,EAAM,QAAA,EAAS,EAA+C;AACpF,EAAA,uBACEC,GAAAA,CAAC,WAAA,EAAA,EACC,QAAA,kBAAAA,GAAAA,CAAC,qBAAA,EAAA,EAAsB,SAAA,EAAW,IAAA,EAAM,SAAA,EAAS,IAAA,EAAE,QAAA,EAAS,CAAA,EAC9D,CAAA;AAEJ;AAOO,SAAS,SAAA,CAAU,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAQ,QAAA,EAAU,OAAA,EAAS,UAAA,EAAY,IAAA,EAAK,EAAmB;AACxG,EAAA,MAAM,OAAA,GAAUJ,WAAW,cAAc,CAAA;AACzC,EAAA,MAAM,MAAA,GAASA,WAAW,kBAAkB,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAaA,WAAW,mBAAmB,CAAA;AACjD,EAAA,MAAM,IAAA,GAAQ,SAAwD,WAAW,CAAA;AACjF,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAM,gBAAA,CAAiB,UAAA,EAAY,IAAI,CAAA,EAAG,CAAC,UAAA,EAAY,IAAI,CAAC,CAAA;AACrF,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,IAAW,QAAA;AACjC,EAAA,MAAM,CAAC,SAAS,CAAA,GAAI,eAAA,EAAgB;AACpC,EAAA,MAAM,UAAU,KAAA,EAAM;AACtB,EAAA,MAAM,MAAA,GAAS,IAAA,EAAM,EAAA,IAAM,OAAA,IAAW,OAAA;AACtC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIE,SAAgC,IAAI,CAAA;AAC5D,EAAA,MAAM,UAAA,GAAa,OAA8B,IAAI,CAAA;AACrD,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,UAAA,EAAY,cAAc,CAAA;AACzD,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,YAAA,CAAa,MAAM,MAAM,CAAA;AAChD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAE3C,EAAA,MAAM,CAAC,QAAQ,CAAA,GAAIA,QAAAA,CAAS,MAAM;AAChC,IAAA,IAAI,OAAA;AACJ,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAc,CAAC,CAAA,KAAM;AAAE,MAAA,OAAA,GAAU,CAAA;AAAA,IAAG,CAAC,CAAA;AACzD,IAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAAA,EAC5B,CAAC,CAAA;AACD,EAAA,MAAM,SAAS,SAAA,CAAU,EAAE,YAAY,IAAA,GAAO,MAAA,GAAY,YAAY,CAAA;AAEtE,EAAA,MAAM,YAAA,GAAe,kBAAkB,IAAA,EAAM,EAAE,QAAQ,OAAA,EAAS,SAAA,EAAW,SAAA,EAAW,KAAA,EAAO,CAAA;AAG7F,EAAAD,gBAAgB,MAAM;AACpB,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,SAAA,IAAa,IAAA,EAAM;AACjC,IAAA,MAAM,MAAM,IAAA,CAAK,aAAA;AACjB,IAAA,IAAI,QAAA,GAAkC,IAAA;AACtC,IAAA,IAAI,QAAA,GAA0B,IAAA;AAC9B,IAAA,MAAM,OAAA,GAAU,CAAC,IAAA,KAAyB;AACxC,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAC/B,MAAA,IAAI,QAAQ,QAAA,EAAU;AACtB,MAAA,QAAA,GAAW,GAAA;AACX,MAAA,IAAI,OAAA,EAAS,MAAA,EAAQ,MAAA,CAAO,OAAA,EAAS,IAAI,CAAA;AAAA,IAC3C,CAAA;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,WAAA,CAAY,KAAK,SAAA,CAAU,GAAA,EAAK,IAAI,CAAC,CAAA;AAChE,IAAA,IAAI,WAAA;AACJ,IAAA,MAAM,WAAA,GAAc,CAAC,MAAA,KACnB,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,IAC3B,MAAA,CAAO,IAAA,KAAS,WAAA,IACf,CAAC,GAAG,MAAA,CAAO,UAAA,EAAY,GAAG,MAAA,CAAO,YAAY,CAAA,CAAE,MAAA,GAAS,CAAA,IACxD,CAAC,GAAG,MAAA,CAAO,UAAA,EAAY,GAAG,MAAA,CAAO,YAAY,CAAA,CAAE,KAAA,CAAM,UAAU,IAAI,CAAA;AACvE,IAAA,MAAM,SAAA,GACJ,OAAO,gBAAA,KAAqB,WAAA,GACxB,OACA,IAAI,gBAAA,CAAiB,CAAC,OAAA,KAAY;AAChC,MAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,WAAW,CAAA,EAAG;AAChC,MAAA,YAAA,CAAa,WAAW,CAAA;AACxB,MAAA,WAAA,GAAc,UAAA,CAAW,MAAM,cAAc,CAAA;AAAA,IAC/C,CAAC,CAAA;AACP,IAAA,SAAA,EAAW,OAAA,CAAQ,IAAA,EAAM,EAAE,OAAA,EAAS,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,CAAA;AAElG,IAAA,MAAM,WAAA,GAAc,sBAAsB,GAAG,CAAA;AAC7C,IAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAiB;AAC7B,MAAA,IAAI,IAAI,IAAA,KAAS,gBAAA,EAAkB,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC/D,MAAA,IAAI,GAAA,CAAI,SAAS,UAAA,EAAY;AAC7B,MAAA,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,KAAK,CAAA;AACjC,MAAA,IAAI,QAAA,EAAU,KAAK,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,GAAA,CAAI,IAAI,CAAA,EAAG,IAAA,EAAK;AAAA,IACvD,CAAA;AACA,IAAA,MAAM,QAAQ,YAAY;AACxB,MAAA,MAAM,QAAA,CAAS,OAAA;AACf,MAAA,MAAM,UAAU,MAAM,YAAA,CAAa,MAAM,EAAE,IAAA,EAAM,OAAO,CAAA;AACxD,MAAA,IAAI,OAAA,EAAS,MAAA,EAAQ,UAAA,CAAW,OAAA,EAAS,OAAO,CAAA;AAChD,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AACA,IAAA,MAAM,UAAA,GAAa,MAAA,IAAU,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,OAAA,EAAS,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA,GAAI,MAAM;AAAA,IAAC,CAAA;AAEzF,IAAA,OAAO,MAAM;AACX,MAAA,UAAA,EAAW;AACX,MAAA,WAAA,CAAY,OAAA,EAAQ;AACpB,MAAA,SAAA,EAAW,UAAA,EAAW;AACtB,MAAA,YAAA,CAAa,WAAW,CAAA;AAAA,IAC1B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,MAAA,EAAQ,SAAS,MAAA,EAAQ,IAAA,EAAM,YAAA,EAAc,QAAQ,CAAC,CAAA;AAEhE,EAAA,YAAA,CAAa,OAAA,EAAS,IAAA,GAAO,IAAA,GAAO,IAAA,EAAM,IAAI,CAAA;AAE9C,EAAA,MAAM,SAAA,GAAY,OAAO,KAAK,CAAA;AAC9B,EAAAI,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,IAAQ,UAAU,OAAA,EAAS;AACzC,IAAA,OAAO,UAAA,CAAW,MAAM,MAAM;AAC5B,MAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AACpB,MAAA,QAAA,CAAS,OAAA,EAAQ;AACjB,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,MAAA,CAAO,QAAQ,UAAA,IAAa;AAAA,IAC9B,CAAC,CAAA;AAAA,EACH,GAAG,CAAC,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAEjC,EAAA,uBACED,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,CAAC,EAAA,KAAO;AACX,QAAA,UAAA,CAAW,OAAA,GAAU,EAAA;AACrB,QAAA,IAAI,OAAA,UAAiB,OAAA,GAAU,EAAA;AAC/B,QAAA,OAAA,CAAQ,EAAE,CAAA;AAAA,MACZ,CAAA;AAAA,MACA,SAAA,EAAU,UAAA;AAAA,MACV,cAAA,EAAc,MAAA;AAAA,MACd,cAAA,EAAc,OAAO,EAAA,GAAK,MAAA;AAAA,MAC1B,gBAAA,EAAgB,MAAA;AAAA,MAChB,gBAAc,OAAA,IAAW,MAAA;AAAA,MAEzB,QAAA,kBAAAA,GAAAA,CAAC,aAAA,EAAA,EAAe,QAAA,EAAA,IAAA,IAAQ,IAAA,mBAAOA,GAAAA,CAAC,YAAA,EAAA,EAAa,IAAA,EAAa,QAAA,EAAA,QAAA,CAAS,OAAO,CAAA,EAAE,IAAkB,IAAA,EAAK;AAAA;AAAA,GACrG;AAEJ;AC9JO,IAAM,SAAA,GAAY,IAAA,CAAK,SAASE,UAAAA,CAAU,EAAE,KAAA,EAAO,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO,QAAA,EAAU,OAAA,EAAS,UAAA,EAAY,QAAA,EAAU,SAAQ,EAAmB;AACtJ,EAAA,MAAM,QAAA,GAAyB,EAAE,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO,QAAA,EAAU,OAAA,EAAS,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,IAAA,EAAM,KAAA,CAAM,IAAA,EAAK;AACnH,EAAA,uBAAOF,IAAC,SAAA,EAAA,EAAU,KAAA,EAAc,KAAK,QAAA,EAAU,UAAA,EAAwB,UAAoB,OAAA,EAAkB,CAAA;AAC/G,CAAC,CAAA;ACSD,IAAM,UAA6C,EAAC;AAGpD,SAAS,SAAA,CAAU,OAAe,GAAA,EAA6B;AAC7D,EAAA,MAAM,QAAA,GAAW,KAAA,KAAU,UAAA,GAAa,GAAA,CAAI,OAAA,GAAU,KAAA;AACtD,EAAA,OAAO,QAAA,KAAa,MAAA,GAAU,GAAA,CAAI,WAAA,GAAc,SAAS,OAAA,GAAW,QAAA;AACtE;AAEA,IAAM,IAAA,GAAyC,EAAE,KAAA,EAAO,MAAA,EAAQ,MAAM,OAAA,EAAQ;AAMvE,SAAS,YAAA,CAAa,MAAe,GAAA,EAA+D;AACzG,EAAA,MAAM,IAAA,GAAO,UAAU,MAAA,CAAO,IAAA,CAAK,IAAI,UAAU,CAAA,IAAK,EAAE,CAAA,EAAG,GAAG,CAAA;AAC9D,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA,EAAG,QAAA;AAC9C,EAAA,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,GAAA,GAAM,GAAA,CAAI,MAAM,IAAI,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,EAAE;AACxD;AAOO,SAAS,iBAAA,CAAkB,CAAA,EAA2B,IAAA,EAAe,GAAA,EAAyC;AACnH,EAAA,IAAI,CAAA,KAAM,MAAM,OAAO,EAAE,SAAS,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,GAAA,EAAK,IAAA,EAAK;AACjE,EAAA,IAAI,CAAA,CAAE,SAAS,eAAA,EAAiB;AAC9B,IAAA,MAAM,EAAE,EAAA,EAAG,GAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AACrC,IAAA,OAAO,EAAE,OAAA,EAAS,EAAA,KAAO,MAAA,GAAY,IAAA,GAAO,EAAE,GAAG,IAAA,EAAM,CAAC,GAAA,CAAI,UAAU,GAAG,EAAA,IAAM,IAAA,EAAM,OAAA,EAAS,KAAK,IAAA,EAAK;AAAA,EAC1G;AACA,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,EAAE,OAAA,GAAU,EAAE,GAAG,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAA;AAAA,IACjD,IAAA,EAAM,EAAE,IAAA,IAAQ,OAAA;AAAA,IAChB,GAAA,EAAK,EAAE,GAAA,IAAO;AAAA,GAChB;AACF;AAGA,SAAS,WAAA,CAAY,GAAA,EAAa,KAAA,EAAe,YAAA,EAA0C;AACzF,EAAA,MAAM,WAAA,GAAc,aAAa,GAAG,CAAA;AACpC,EAAA,IAAI,CAAC,WAAA,EAAa,OAAO,CAAA,EAAG,GAAG,KAAK,KAAK,CAAA,CAAA;AACzC,EAAA,MAAM,MAAA,GAAS,YAAY,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,KAAK,CAAA;AAChE,EAAA,OAAO,GAAG,WAAA,CAAY,KAAK,CAAA,EAAA,EAAK,MAAA,EAAQ,SAAS,KAAK,CAAA,CAAA;AACxD;AAeO,SAAS,kBAAA,CAAmB,CAAA,EAAoB,YAAA,EAAkC,OAAA,EAAmC;AAC1H,EAAA,IAAI,CAAA,CAAE,SAAS,eAAA,EAAiB;AAC9B,IAAA,MAAM,OAAO,OAAA,GAAU,YAAA,CAAa,QAAQ,IAAA,EAAM,OAAA,CAAQ,GAAG,CAAA,GAAI,IAAA;AACjE,IAAA,OAAO,QAAQ,IAAA,CAAK,EAAA,KAAO,SAAY,CAAA,gCAAA,EAAmC,IAAA,CAAK,IAAI,CAAA,CAAA,CAAA,GAAM,eAAA;AAAA,EAC3F;AACA,EAAA,MAAM,UAAU,MAAA,CAAO,OAAA,CAAQ,EAAE,OAAA,IAAW,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,KAAK,KAAK,CAAA,KAAM,YAAY,GAAA,EAAK,KAAA,EAAO,YAAY,CAAC,CAAA;AAC3G,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,CAAQ,CAAA,CAAE,QAAQ,EAAE,EAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,KAAK,MAAM,CAAA,IAAA,EAAO,IAAI,MAAM,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AACjG,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,GAAA,GAAM,CAAC,OAAO,CAAA,CAAE,GAAG,CAAA,IAAA,EAAI,OAAA,EAAS,WAAW,KAAA,GAAQ,gBAAA,GAAmB,EAAE,CAAA,CAAE,IAAI,EAAC;AAC7F,EAAA,OAAO,CAAC,GAAG,OAAA,EAAS,GAAG,IAAA,EAAM,GAAG,GAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,IAAK,UAAA;AACrD;AAMO,SAAS,YAAA,CAAa,CAAA,EAAoB,GAAA,EAAoB,WAAA,EAAsB,MAAA,EAAyB;AAClH,EAAA,MAAM,IAAA,GAAQ,cAA6D,WAAW,CAAA;AACtF,EAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,GAAA,CAAI,SAAA,EAAW,IAAI,CAAA;AACjD,EAAA,OAAO,kBAAA,CAAmB,CAAA,EAAG,GAAA,CAAI,YAAA,EAAc,EAAE,IAAA,EAAM,GAAA,EAAK,gBAAA,CAAiB,GAAG,CAAA,EAAG,MAAA,EAAQ,CAAA;AAC7F;AAGO,IAAM,QAAA,GAAW,CAAC,MAAA,EAAiB,IAAA,KACxC,OAAO,OAAA,CAAQ,IAAI,EAAE,MAAA,CAAO,CAAC,GAAG,CAAC,IAAA,EAAM,KAAK,CAAA,KAAM,eAAA,CAAgB,GAAG,IAAA,EAAM,KAAK,GAAG,MAAM;AAWpF,SAAS,iBAAiB,GAAA,EAAoC;AACnE,EAAA,MAAM,WAAA,GAAc,mBAAkB,KAAM,MAAA;AAC5C,EAAA,OAAO,EAAE,YAAA,EAAc,GAAA,CAAI,YAAA,EAAc,UAAA,EAAY,IAAI,UAAA,EAAY,WAAA,EAAa,OAAA,EAAS,GAAA,CAAI,IAAA,EAAK;AACtG;AChGA,IAAMG,QAA+B,EAAC;AAE/B,SAAS,gBAAA,GAA+B;AAC7C,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAyB;AAC9C,EAAA,MAAM,UAAUC,aAAAA,EAAc;AAC9B,EAAA,IAAI,OAAA,uBAAc,GAAA,EAAoC;AACtD,EAAA,OAAO;AAAA,IACL,GAAA,CAAI,QAAQ,OAAA,EAAS;AACnB,MAAA,IAAI,YAAY,IAAA,EAAM;AACpB,QAAA,IAAI,CAAC,QAAA,CAAS,MAAA,CAAO,MAAM,CAAA,EAAG;AAAA,MAChC,CAAA,MAAO,QAAA,CAAS,GAAA,CAAI,MAAA,EAAQ,OAAO,CAAA;AACnC,MAAA,OAAA,uBAAc,GAAA,EAAI;AAClB,MAAA,OAAA,CAAQ,IAAA,EAAK;AAAA,IACf,CAAA;AAAA,IACA,SAAS,OAAA,EAAS;AAChB,MAAA,IAAI,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA;AAC/B,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAA,GAAO,CAAC,GAAG,QAAA,CAAS,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,CAAI,YAAY,OAAO,CAAA;AAC3E,QAAA,KAAA,GAAQ,IAAA,CAAK,MAAA,KAAW,CAAA,GAAID,KAAAA,GAAO,IAAA;AACnC,QAAA,OAAA,CAAQ,GAAA,CAAI,SAAS,KAAK,CAAA;AAAA,MAC5B;AACA,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAAA,IACA,WAAW,OAAA,CAAQ;AAAA,GACrB;AACF;AAGO,IAAM,iBAAA,GAAoBR,cAAiC,IAAI;;;AC9C/D,IAAM,aAAa,CAAC,IAAA,KACzB,IAAA,EAAM,aAAA,CAA2B,4BAA4B,CAAA,IAAK;AAEpE,IAAM,OAAA,GAAU,CAAC,MAAA,EAAoB,GAAA,KACnC,GAAA,CAAI,iBAAA,GAAoB,MAAA,CAAO,CAAA,EAAG,MAAA,CAAO,CAAC,CAAA,IAAK,EAAC;AAM3C,SAAS,OAAA,CAAQ,MAAA,EAAoB,GAAA,GAAgB,QAAA,EAA2B;AACrF,EAAA,KAAA,MAAW,EAAA,IAAM,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,EAAG;AACrC,IAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAqB,gBAAgB,CAAA;AACrD,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,YAAA,CAAa,cAAc,CAAA,EAAG;AAChD,IAAA,MAAM,IAAA,GAAO,KAAK,qBAAA,EAAsB;AACxC,IAAA,MAAM,QAAQ,IAAA,CAAK,WAAA,GAAc,IAAI,IAAA,CAAK,KAAA,GAAQ,KAAK,WAAA,GAAc,CAAA;AACrE,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,IAAA,CAAK,OAAA,CAAQ,MAAA,IAAU,EAAA;AAAA,MAChC,IAAA;AAAA,MACA,KAAA,EAAO,EAAE,CAAA,EAAA,CAAI,MAAA,CAAO,CAAA,GAAI,IAAA,CAAK,IAAA,IAAQ,KAAA,EAAO,CAAA,EAAA,CAAI,MAAA,CAAO,CAAA,GAAI,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MAC7E;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;ACSO,SAAS,UAAU,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,MAAK,EAAmB;AACxE,EAAA,MAAM,EAAE,QAAQ,SAAA,EAAU,GAAI,cAAc,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,SAAA,EAAW,IAAI,CAAA;AAC7E,EAAA,uBACEK,GAAAA,CAAC,YAAA,CAAa,QAAA,EAAb,EAAsB,KAAA,EAAO,KAAA,EAC5B,QAAA,kBAAAA,GAAAA,CAAC,aAAW,GAAG,IAAA,EAAM,MAAA,EAAgB,SAAA,EAAsB,SAAkB,CAAA,EAC/E,CAAA;AAEJ;AAGA,IAAM,SAAS,CAAC,GAAA,EAAa,IAAA,KAC3B,IAAA,KAAS,OAAO,IAAA,CAAK,UAAA,CAAW,CAAA,EAAG,GAAG,GAAG,CAAA,IAAK,GAAA,CAAI,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAA;AAEzE,IAAM,EAAA,GAAK,CAAC,CAAA,KAAc,CAAA,EAAG,CAAC,CAAA,EAAA,CAAA;AAI9B,SAAS,UAAU,OAAA,EAAqC;AACtD,EAAA,MAAM,EAAE,GAAA,EAAK,MAAA,EAAQ,IAAA,EAAK,GAAI,OAAA;AAC9B,EAAA,OAAO;AAAA,IACL,CAAC,kBAA4B,GAAG,EAAA,CAAG,GAAA,CAAI,KAAK,WAAW,CAAA;AAAA,IACvD,CAAC,kBAA4B,GAAG,EAAA,CAAG,GAAA,CAAI,KAAK,YAAY,CAAA;AAAA,IACxD,CAAC,kBAA4B,GAAG,EAAA,CAAG,IAAA,CAAK,QAAQ,CAAA,GAAI,GAAA,CAAI,KAAA,CAAM,CAAA,GAAI,MAAM,CAAA;AAAA,IACxE,CAAC,kBAA4B,GAAG,EAAA,CAAG,IAAA,CAAK,SAAS,CAAA,GAAI,GAAA,CAAI,KAAA,CAAM,CAAA,GAAI,MAAM,CAAA;AAAA,IACzE,CAAC,kBAA4B,GAAG,MAAA,CAAO,MAAM;AAAA,GAC/C;AACF;AAIA,SAAS,WAAA,CAAY,EAAE,IAAA,EAAK,EAAyB;AACnD,EAAAH,gBAAgB,IAAI,CAAA;AACpB,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,cAAA,CAAe,SAAsB,WAAA,EAA+B;AAC3E,EAAA,MAAM,UAAA,GAAaD,WAAW,mBAAmB,CAAA;AACjD,EAAA,MAAM,IAAA,GAAQ,cAA6D,WAAW,CAAA;AACtF,EAAA,MAAM,GAAA,GAAMS,OAAAA,CAAQ,MAAM,gBAAA,CAAiB,UAAA,EAAY,IAAI,CAAA,EAAG,CAAC,UAAA,EAAY,IAAI,CAAC,CAAA;AAChF,EAAA,MAAM,EAAE,OAAA,EAAS,GAAA,EAAI,GAAI,OAAA;AACzB,EAAA,OAAOA,OAAAA,CAAiB,MAAM,iBAAA,CAAkB,OAAA,EAAS,GAAA,EAAK,GAAG,CAAA,CAAE,OAAA,EAAS,CAAC,GAAA,EAAK,OAAA,EAAS,GAAG,CAAC,CAAA;AACjG;AAMO,SAAS,aAAA,CACd,WAAA,EACA,cAAA,EACA,IAAA,EACwE;AACxE,EAAA,MAAM,MAAA,GAASA,OAAAA,CAAQ,MAAM,QAAA,CAAS,WAAA,EAAa,IAAI,CAAA,EAAG,CAAC,IAAA,EAAM,WAAW,CAAC,CAAA;AAE7E,EAAA,MAAM,WAAW,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,KAAK,IAAI,CAAA;AAC5C,EAAA,MAAM,SAAA,GAAYN,WAAAA;AAAA,IAChB,CAAC,MAAc,KAAA,KAAmB;AAChC,MAAA,MAAM,QAAQ,QAAA,KAAa,EAAA,GAAK,EAAC,GAAI,QAAA,CAAS,MAAM,IAAI,CAAA;AACxD,MAAA,IAAI,CAAC,KAAA,CAAM,IAAA,CAAK,CAAC,GAAA,KAAQ,MAAA,CAAO,GAAA,EAAK,IAAI,CAAC,CAAA,EAAG,cAAA,CAAe,IAAA,EAAM,KAAK,CAAA;AAAA,IACzE,CAAA;AAAA,IACA,CAAC,UAAU,cAAc;AAAA,GAC3B;AACA,EAAA,OAAO,EAAE,QAAQ,SAAA,EAAU;AAC7B;AAGA,SAAS,UAAA,CAAW,EAAE,OAAA,EAAS,QAAA,EAAS,EAAkD;AACxF,EAAA,OAAO,YAAA;AAAA,oBACLC,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAe,KAAA,EAAO,SAAA,CAAU,OAAO,CAAA,EACnD,QAAA,EACH,CAAA;AAAA,IACA,OAAA,CAAQ;AAAA,GACV;AACF;AAEA,IAAM,MAAA,GAAS,CAAC,OAAA,EAAiB,OAAA,KAAyB,GAAG,OAAO,CAAA,MAAA,EAAS,QAAQ,MAAM,CAAA,CAAA;AAG3F,SAAS,WAAA,CAAY,QAAoB,OAAA,EAAyC;AAChF,EAAA,MAAM,QAAA,GAAWD,WAAAA,CAAY,MAAM,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA,EAAG,CAAC,MAAA,EAAQ,OAAO,CAAC,CAAA;AAC9E,EAAA,OAAOO,oBAAAA,CAAqB,MAAA,CAAO,SAAA,EAAW,QAAQ,CAAA;AACxD;AAEA,SAAS,QAAA,CAAS,EAAE,OAAA,EAAS,OAAA,EAAS,QAAQ,KAAA,EAAO,WAAA,EAAa,UAAS,EAAgE;AACzI,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,OAAA,EAAS,WAAW,CAAA;AACnD,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,OAAA,EAAS,OAAO,CAAA;AAClC,EAAA,MAAM,IAAA,GAAOD,OAAAA,CAAQ,OAAO,EAAE,EAAA,EAAI,SAAQ,CAAA,EAAI,CAAC,EAAA,EAAI,OAAO,CAAC,CAAA;AAE3D,EAAA,MAAM,IAAA,GAAO,QAAQ,GAAA,CAAI,IAAA;AACzB,EAAA,MAAM,EAAE,MAAK,GAAI,OAAA;AAGjB,EAAA,MAAM,IAAA,GAAON,YAAY,MAAM;AAC7B,IAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,IAAA,MAAM,EAAA,GAAK,UAAA,CAAW,IAAA,CAAK,aAAA,CAA2B,yCAAyC,CAAC,CAAA;AAChG,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,EAAA,EAAI;AAClB,IAAA,EAAA,CAAG,YAAY,IAAA,CAAK,SAAA;AACpB,IAAA,EAAA,CAAG,aAAa,IAAA,CAAK,UAAA;AAAA,EACvB,CAAA,EAAG,CAAC,IAAA,EAAM,IAAI,CAAC,CAAA;AACf,EAAAE,UAAU,MAAM;AACd,IAAA,MAAM,IAAA,GAAO,WAAW,IAAI,CAAA;AAC5B,IAAA,IAAA,EAAM,iBAAiB,QAAA,EAAU,IAAA,EAAM,EAAE,OAAA,EAAS,MAAM,CAAA;AACxD,IAAA,OAAO,MAAM,IAAA,EAAM,mBAAA,CAAoB,QAAA,EAAU,IAAI,CAAA;AAAA,EACvD,CAAA,EAAG,CAAC,IAAA,EAAM,IAAI,CAAC,CAAA;AAEf,EAAA,uBACED,GAAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAGV,0BAAAA,GAAAA,CAAC,SAAA,EAAA,EAA+B,MAAA,EAAgB,KAAA,EAAc,MAAA,EAAQ,WAAA,EAAa,IAAA,EAChF,QAAA,EAAA,CAAC,sBACA,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,CAAA,EAAG,QAAQ,IAAI,CAAA;AAAA,oBACzBA,GAAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAY;AAAA,GAAA,EAC3B,CAAA,EAAA,EALY,OAAA,CAAQ,MAOxB,CAAA,EACF,CAAA;AAEJ;AAEA,SAAS,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,GAAG,OAAM,EAA8D;AACxG,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,MAAA,EAAQ,OAAO,CAAA;AAC5C,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,qBACnBA,GAAAA,CAAC,QAAA,EAAA,EAA8B,OAAA,EAAkB,OAAA,EAAmB,GAAG,KAAA,EAAA,EAAxD,OAAA,CAAQ,MAAuD,CAC/E,CAAA;AACH;AAMO,SAAS,WAAW,KAAA,EAAwB;AACjD,EAAA,MAAM,MAAA,GAASJ,WAAW,iBAAiB,CAAA;AAC3C,EAAA,MAAM,EAAE,SAAQ,GAAI,KAAA;AACpB,EAAA,OAAO,MAAA,IAAU,0BAAUI,GAAAA,CAAC,UAAQ,GAAG,KAAA,EAAO,MAAA,EAAgB,OAAA,EAAkB,CAAA,GAAK,IAAA;AACvF;AAuBA,SAAS,cAAc,EAAE,OAAA,EAAS,OAAA,EAAS,WAAA,EAAa,UAAS,EAAsF;AACrJ,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,OAAA,EAAS,WAAW,CAAA;AACnD,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,OAAA,EAAS,OAAO,CAAA;AAClC,EAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,OAAA;AACzB,EAAA,MAAM,IAAA,GAAO,QAAQ,GAAA,CAAI,IAAA;AACzB,EAAA,MAAM,OAAOK,OAAAA,CAAQ,OAAO,EAAE,EAAA,EAAI,MAAM,OAAA,EAAS,IAAA,EAAM,MAAA,EAAO,CAAA,EAAI,CAAC,EAAA,EAAI,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,MAAM,CAAC,CAAA;AACnG,EAAA,uBAAOL,GAAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAmB,QAAA,EAAA,QAAA,CAAS,IAAI,CAAA,EAAE,CAAA;AACvD;AAEA,SAAS,YAAY,EAAE,MAAA,EAAQ,OAAA,EAAS,GAAG,OAAM,EAAoF;AACnI,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,MAAA,EAAQ,OAAO,CAAA;AAC5C,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,qBAAYA,GAAAA,CAAC,aAAA,EAAA,EAAmC,OAAA,EAAkB,OAAA,EAAmB,GAAG,KAAA,EAAA,EAAxD,OAAA,CAAQ,MAAuD,CAAE,CAAA;AACxH;AAOO,SAAS,gBAAgB,KAAA,EAA6B;AAC3D,EAAA,MAAM,MAAA,GAASJ,WAAW,iBAAiB,CAAA;AAC3C,EAAA,MAAM,EAAE,SAAQ,GAAI,KAAA;AACpB,EAAA,OAAO,MAAA,IAAU,0BAAUI,GAAAA,CAAC,eAAa,GAAG,KAAA,EAAO,MAAA,EAAgB,OAAA,EAAkB,CAAA,GAAK,IAAA;AAC5F;AC7MA,IAAM,gBAAsC,EAAC;AAGtC,SAAS,UAAA,CAAW,EAAE,KAAA,EAAO,KAAA,EAAO,KAAK,OAAA,EAAS,UAAA,EAAY,SAAQ,EAAoB;AAC/F,EAAA,MAAM,SAAA,GAAYO,UAAU,GAAG,CAAA;AAE/B,EAAA,MAAM,CAAC,YAAY,aAAa,CAAA,GAAIT,SAAS,MAAM,WAAA,CAAY,GAAA,CAAI,MAAM,CAAC,CAAA;AAC1E,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,UAAU,CAAA;AACjD,EAAA,IAAI,MAAA,KAAW,UAAA,EAAY,aAAA,CAAc,MAAM,CAAA;AAG/C,EAAA,MAAM,MAAA,GAASU,OAAO,KAAK,CAAA;AAC3B,EAAAP,UAAU,MAAM;AACd,IAAA,IAAI,OAAO,OAAA,IAAW,GAAA,CAAI,UAAU,IAAA,IAAQ,CAAC,MAAM,YAAA,EAAc;AACjE,IAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AACjB,IAAA,GAAA,CAAI,QAAA,CAAS,KAAA,CAAM,YAAA,CAAa,MAAM,CAAC,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,GAAA,EAAK,KAAA,EAAO,MAAM,CAAC,CAAA;AAIvB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIH,QAAAA,CAAS,EAAE,MAAA,EAAQ,KAAA,EAAO,GAAA,CAAI,KAAA,EAAO,GAAA,EAAK,CAAA,EAAG,CAAA;AACvE,EAAA,IAAI,WAAW,KAAA,CAAM,GAAA;AACrB,EAAA,IAAI,MAAM,MAAA,KAAW,MAAA,IAAU,KAAA,CAAM,KAAA,KAAU,IAAI,KAAA,EAAO;AACxD,IAAA,QAAA,GAAW,MAAM,GAAA,GAAM,CAAA;AACvB,IAAA,QAAA,CAAS,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAI,KAAA,EAAO,GAAA,EAAK,UAAU,CAAA;AAAA,EACtD;AAIA,EAAA,MAAM,SAAA,GAAYC,WAAAA,CAAY,CAAC,IAAA,EAAc,KAAA,KAAmB;AAC9D,IAAA,IAAI,CAAC,YAAY,IAAI,CAAA,YAAa,OAAA,CAAQ,SAAA,CAAU,MAAM,KAAK,CAAA;AAAA,EACjE,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AACd,EAAA,MAAM,QAAA,GAAWA,WAAAA,CAAY,CAAC,IAAA,KAAkB,SAAA,CAAU,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAG7F,EAAA,MAAM,OAAA,GAAUH,WAAWa,cAAc,CAAA;AACzC,EAAA,MAAM,OAAA,GAAUD,OAA2B,IAAI,CAAA;AAC/C,EAAA,MAAM,OAAO,OAAA,IAAW,OAAA;AACxB,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,QAAA,GAAW,MAAM,CAAA,IAAK,IAAA;AACzC,EAAA,MAAM,aAAa,mBAAA,EAAoB;AACvC,EAAA,MAAM,KAAA,GAAQ,OAAO,UAAA,GAAa,IAAA;AAElC,EAAA,MAAM,UAAA,GAAa,MAAM,UAAA,IAAc,aAAA;AACvC,EAAA,MAAM,WAAA,GAAcD,UAAU,OAAO,CAAA;AACrC,EAAA,MAAM,WAAA,GAAcR,WAAAA,CAAY,CAAC,KAAA,KAAmB,WAAA,CAAY,UAAU,KAAK,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAC/F,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,KAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAO,GAAA,CAAI,KAAA;AAAA,IACX,QAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA,EAAS;AAAA,GACX;AACA,EAAA,MAAM,SAAS,CAAC,OAAA,qBACdC,GAAAA,CAAC,aAAa,QAAA,EAAb,EAAsB,KAAA,EAAO,KAAA,EAC5B,0BAAAA,GAAAA,CAAC,SAAA,EAAA,EAAW,GAAG,IAAA,EAAM,SAAkB,CAAA,EACzC,CAAA;AAGF,EAAA,uBACEU,IAAAA,CAAAC,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAX,GAAAA;AAAA,MAAC,SAAA;AAAA,MAAA;AAAA,QACC,QAAQ,KAAA,CAAM,MAAA;AAAA,QACd,KAAA;AAAA,QACA,QAAQ,GAAA,CAAI,MAAA;AAAA,QACZ,OAAA,EAAS,IAAA;AAAA,QACR,GAAI,UAAA,GAAa,EAAE,UAAA,KAAe,EAAC;AAAA,QAEnC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,oBACAA,IAAC,UAAA,EAAA,EAAW,OAAA,EAAkB,QAAQ,KAAA,CAAM,MAAA,EAAQ,OAAc,WAAA,EAAa,GAAA,CAAI,QAChF,QAAA,EAAA,CAAC,OAAA,EAAS,yBAASA,GAAAA,CAAC,aAAU,IAAA,EAAY,KAAA,EAAc,OAAA,EAAkB,IAAA,EAAY,CAAA,EACzF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"chunk-SZ2SMRE6.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 { systemColorScheme } from '@weasel-js/react';\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 = systemColorScheme() === 'dark';\n return { declarations: lab.declarations, modeGlobal: lab.modeGlobal, prefersDark, labMode: lab.mode };\n}\n","import { createContext } from 'react';\nimport { createEmitter } from '@weasel-js/registry';\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 changed = createEmitter();\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 changed.emit();\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: changed.subscribe,\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"]}
|
package/dist/shell/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { parseRoute, formatRoute, paramsToKnobs, knobPaths, sameKnob, paramsToPins, knobsToParams, PLAYHEAD_PARAM, pinParams, withoutPins, reservedParams } from '../chunk-SFKDHXVE.js';
|
|
2
|
-
import { DEFAULT_TITLE, ISSUES_PATH,
|
|
2
|
+
import { DEFAULT_TITLE, ISSUES_PATH, CAPTURE_PATH, issueLabel, messageOf, MIN_DPR, MAX_DPR } from '../chunk-MRYXJTDO.js';
|
|
3
3
|
import { TITLE_LIBRARIES, loadIndexBundle, librariesFrom, LibrariesContext, LAB_DENSITY, createKitRoot, schemaFromDescription, LibraryBadge, Description, IndexPage, indexEnvOf, LabBadge, openChannel } from '../chunk-PPB7VP6R.js';
|
|
4
4
|
import { isIndexId, indexId, indexEntries } from '../chunk-RVJHUY7W.js';
|
|
5
5
|
import { isGallery, isLab } from '../chunk-VUPN73JP.js';
|
|
6
|
-
import { useTrialFrame, createTrialFrames, createStoryHosts, StoryGlobalsContext, TrialFramesContext, StoryHostsContext, StoryTrial, LiveLensesContext, trialAt, describeLens, createLiveLenses, useCopyConfig, useCssOverrides, IN_VIEW_MARGIN, LiveFrameCopies, TrialHost, LiveCopies, resolveContextOf, resolveComparison, scrollerOf, withArgs } from '../chunk-
|
|
7
|
-
export { StoryGlobalsContext, StoryTrial, TrialFramesContext, TrialHost, useTrialFrame } from '../chunk-
|
|
6
|
+
import { useTrialFrame, createTrialFrames, createStoryHosts, StoryGlobalsContext, TrialFramesContext, StoryHostsContext, StoryTrial, LiveLensesContext, trialAt, describeLens, createLiveLenses, useCopyConfig, useCssOverrides, IN_VIEW_MARGIN, LiveFrameCopies, TrialHost, LiveCopies, resolveContextOf, resolveComparison, scrollerOf, withArgs } from '../chunk-SZ2SMRE6.js';
|
|
7
|
+
export { StoryGlobalsContext, StoryTrial, TrialFramesContext, TrialHost, useTrialFrame } from '../chunk-SZ2SMRE6.js';
|
|
8
8
|
import { labGlobals, withGlobals, storyConfig, followApp, GLOBALS_KEY, effectiveGlobals, labOptions, isForgePath, isGlobalsPath } from '../chunk-FPF2JSWB.js';
|
|
9
9
|
import { loadStories, applyGlobalsTo, scanCssVars, varRefs, cssRulesOf } from '../chunk-PGLOYXDP.js';
|
|
10
10
|
import { clockSpecOf, shownTime } from '../chunk-TT4ZOYB6.js';
|
|
@@ -19,7 +19,7 @@ import { createEmitter } from '@weasel-js/registry';
|
|
|
19
19
|
import { f, valueAtPath, isConfigBranch } from '@weasel-js/labkit/config';
|
|
20
20
|
import { TOKEN_MANIFEST, themeAxes, weaselTheme, THEME_SOURCES, resolveTheme, isColorModePreference, isByAxis } from '@weasel-js/theme';
|
|
21
21
|
import { scale, httpThemeApi } from '@weasel-js/theme/engine';
|
|
22
|
-
import { useLatest, useActionsRegistry, useVisibleRaf, effectivePose, useMenuHost, useMenus, sceneToAdapter, parseColor, contrastRatio, wcagLevels, historyKey, isPlainObject, createHistory, keymapShortcuts, actionBindings, keySpecShortcut, keymapLeaderId, swapOp } from '@weasel-js/core';
|
|
22
|
+
import { useLatest, useActionsRegistry, useVisibleRaf, effectivePose, useMenuHost, useMenus, sceneToAdapter, parseColor, contrastRatio, wcagLevels, luminanceContrast, historyKey, isPlainObject, relativeLuminance, createHistory, keymapShortcuts, actionBindings, keySpecShortcut, keymapLeaderId, swapOp } from '@weasel-js/core';
|
|
23
23
|
import { Button as Button$1 } from '@weasel-js/ui/components/Button';
|
|
24
24
|
import { Checkbox } from '@weasel-js/ui/components/Checkbox';
|
|
25
25
|
import { Icon } from '@weasel-js/ui/components/Icon';
|
|
@@ -494,18 +494,16 @@ function missingInstrument(id, globals = {}) {
|
|
|
494
494
|
render: () => /* @__PURE__ */ jsx("div", { className: "fg-story fg-story--loading", "data-fg-layout": "fullscreen", children: /* @__PURE__ */ jsx(Fault, { phase: "route", message: `No story ${id}` }) })
|
|
495
495
|
};
|
|
496
496
|
}
|
|
497
|
-
var listeners =
|
|
497
|
+
var listeners = createEmitter();
|
|
498
498
|
var pending = null;
|
|
499
499
|
function revealVar(name) {
|
|
500
500
|
pending = name;
|
|
501
|
-
|
|
501
|
+
listeners.emit(name);
|
|
502
502
|
}
|
|
503
503
|
function subscribeReveal(fn) {
|
|
504
|
-
listeners.
|
|
504
|
+
const off = listeners.subscribe(fn);
|
|
505
505
|
if (pending !== null) fn(pending);
|
|
506
|
-
return
|
|
507
|
-
listeners.delete(fn);
|
|
508
|
-
};
|
|
506
|
+
return off;
|
|
509
507
|
}
|
|
510
508
|
var MARK = "data-revealed";
|
|
511
509
|
function useRevealToken(list, tokens, show, storyReported) {
|
|
@@ -1741,8 +1739,6 @@ function CompareMenu({ api, request }) {
|
|
|
1741
1739
|
}, [registry, host, api, request]);
|
|
1742
1740
|
return null;
|
|
1743
1741
|
}
|
|
1744
|
-
|
|
1745
|
-
// src/shell/loupe/liveSource.ts
|
|
1746
1742
|
var NOTHING_UNDER = "Nothing under the reticle";
|
|
1747
1743
|
var sameContext = (a, b) => a.declarations === b.declarations && a.modeGlobal === b.modeGlobal && a.prefersDark === b.prefersDark && a.labMode === b.labMode;
|
|
1748
1744
|
var liveCellId = (lensId, compare) => compare === null ? lensId : `${lensId}~compared`;
|
|
@@ -1765,12 +1761,12 @@ function watchOf(notify) {
|
|
|
1765
1761
|
}
|
|
1766
1762
|
var now = (run) => run();
|
|
1767
1763
|
function createLiveSource(lenses, resolve, conditions, schedule = now) {
|
|
1768
|
-
const measures =
|
|
1769
|
-
const listeners2 =
|
|
1764
|
+
const measures = createEmitter();
|
|
1765
|
+
const listeners2 = createEmitter();
|
|
1770
1766
|
let due = false;
|
|
1771
1767
|
const flush = () => {
|
|
1772
1768
|
due = false;
|
|
1773
|
-
|
|
1769
|
+
listeners2.emit();
|
|
1774
1770
|
};
|
|
1775
1771
|
const notify = () => {
|
|
1776
1772
|
if (due) return;
|
|
@@ -1783,12 +1779,7 @@ function createLiveSource(lenses, resolve, conditions, schedule = now) {
|
|
|
1783
1779
|
label: () => "Live",
|
|
1784
1780
|
status: () => true,
|
|
1785
1781
|
// A reader hears of what it reads: the lens's copy, and with nothing compared, the main story under the reticle.
|
|
1786
|
-
subscribe
|
|
1787
|
-
listeners2.add(listener);
|
|
1788
|
-
return () => {
|
|
1789
|
-
listeners2.delete(listener);
|
|
1790
|
-
};
|
|
1791
|
-
},
|
|
1782
|
+
subscribe: listeners2.subscribe,
|
|
1792
1783
|
attach(slot, first) {
|
|
1793
1784
|
const doc = slot.ownerDocument;
|
|
1794
1785
|
const target = doc.createElement("div");
|
|
@@ -1830,7 +1821,7 @@ function createLiveSource(lenses, resolve, conditions, schedule = now) {
|
|
|
1830
1821
|
args: resolved.args
|
|
1831
1822
|
});
|
|
1832
1823
|
};
|
|
1833
|
-
measures.
|
|
1824
|
+
const unmeasure = measures.subscribe(measure);
|
|
1834
1825
|
measure();
|
|
1835
1826
|
return {
|
|
1836
1827
|
update(next) {
|
|
@@ -1840,7 +1831,7 @@ function createLiveSource(lenses, resolve, conditions, schedule = now) {
|
|
|
1840
1831
|
detach() {
|
|
1841
1832
|
watchCopy(null);
|
|
1842
1833
|
watchStory(null);
|
|
1843
|
-
|
|
1834
|
+
unmeasure();
|
|
1844
1835
|
lenses.set(liveCellId(request.lensId, request.conditions), null);
|
|
1845
1836
|
target.remove();
|
|
1846
1837
|
empty.remove();
|
|
@@ -1848,7 +1839,7 @@ function createLiveSource(lenses, resolve, conditions, schedule = now) {
|
|
|
1848
1839
|
};
|
|
1849
1840
|
},
|
|
1850
1841
|
remeasure() {
|
|
1851
|
-
|
|
1842
|
+
measures.emit();
|
|
1852
1843
|
}
|
|
1853
1844
|
};
|
|
1854
1845
|
}
|
|
@@ -2047,7 +2038,7 @@ function isLarge(style) {
|
|
|
2047
2038
|
const w = style.fontWeight === "bold" ? 700 : Number.parseInt(style.fontWeight, 10);
|
|
2048
2039
|
return px >= 24 || px >= 18.66 && w >= 700;
|
|
2049
2040
|
}
|
|
2050
|
-
var
|
|
2041
|
+
var luminanceAt = (d, i) => relativeLuminance(d[i] / 255, d[i + 1] / 255, d[i + 2] / 255);
|
|
2051
2042
|
function ofPixels(capture, point) {
|
|
2052
2043
|
const img = capture ? readBitmap(capture.bitmap) : null;
|
|
2053
2044
|
if (!capture || !img) return { unavailable: NO_CAPTURE };
|
|
@@ -2068,8 +2059,8 @@ function ofPixels(capture, point) {
|
|
|
2068
2059
|
}
|
|
2069
2060
|
}
|
|
2070
2061
|
}
|
|
2071
|
-
const ratio =
|
|
2072
|
-
return
|
|
2062
|
+
const ratio = luminanceContrast(luminanceAt(data, center), luminanceAt(data, far));
|
|
2063
|
+
return { ratio, ...wcagLevels(ratio, false), large: false };
|
|
2073
2064
|
}
|
|
2074
2065
|
function contrastAt(source, at) {
|
|
2075
2066
|
if (source === "pixels") return ofPixels(at.capture, at.point);
|
|
@@ -2267,20 +2258,18 @@ function trialPayload(trial, lab, hit, dpr, c) {
|
|
|
2267
2258
|
colorScheme
|
|
2268
2259
|
});
|
|
2269
2260
|
}
|
|
2270
|
-
|
|
2271
|
-
// src/shell/loupe/captureClient.ts
|
|
2272
2261
|
var CHECKING = "checking for a capture browser";
|
|
2273
2262
|
var UNAVAILABLE = "captures are unavailable";
|
|
2274
2263
|
var NO_ENDPOINT = "this server takes no captures";
|
|
2275
2264
|
function createCaptureClient(base, send) {
|
|
2276
2265
|
const url = `${base}${CAPTURE_PATH}`;
|
|
2277
|
-
const listeners2 =
|
|
2266
|
+
const listeners2 = createEmitter();
|
|
2278
2267
|
let status = CHECKING;
|
|
2279
2268
|
let polling = null;
|
|
2280
2269
|
const setStatus = (next) => {
|
|
2281
2270
|
if (next === status) return;
|
|
2282
2271
|
status = next;
|
|
2283
|
-
|
|
2272
|
+
listeners2.emit();
|
|
2284
2273
|
};
|
|
2285
2274
|
const poll = () => {
|
|
2286
2275
|
polling ??= (async () => {
|
|
@@ -2299,9 +2288,9 @@ function createCaptureClient(base, send) {
|
|
|
2299
2288
|
return {
|
|
2300
2289
|
status: () => status,
|
|
2301
2290
|
subscribe(listener) {
|
|
2302
|
-
listeners2.
|
|
2291
|
+
const off = listeners2.subscribe(listener);
|
|
2303
2292
|
poll();
|
|
2304
|
-
return
|
|
2293
|
+
return off;
|
|
2305
2294
|
},
|
|
2306
2295
|
poll,
|
|
2307
2296
|
async take(payload) {
|