@weasel-js/forge 1.9.4 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +12 -4
  2. package/dist/{FrameController-BQjKhdwk.d.ts → FrameController-UeTY7ubF.d.ts} +25 -1
  3. package/dist/{chunk-B3PPHJTS.js → chunk-4NM3RTYK.js} +14 -14
  4. package/dist/chunk-4NM3RTYK.js.map +1 -0
  5. package/dist/{chunk-JHL4ERDA.js → chunk-DFKCLZKS.js} +3 -3
  6. package/dist/chunk-DFKCLZKS.js.map +1 -0
  7. package/dist/{chunk-FRUA5WJF.js → chunk-DKWHGSBZ.js} +3 -3
  8. package/dist/{chunk-FRUA5WJF.js.map → chunk-DKWHGSBZ.js.map} +1 -1
  9. package/dist/{chunk-ZZCCIXEJ.js → chunk-ENXU34PI.js} +16 -25
  10. package/dist/chunk-ENXU34PI.js.map +1 -0
  11. package/dist/{chunk-TXLWQFF6.js → chunk-FL2MUPUL.js} +2 -2
  12. package/dist/chunk-FL2MUPUL.js.map +1 -0
  13. package/dist/{chunk-5KI5YSQ5.js → chunk-GB6PRJET.js} +3 -3
  14. package/dist/{chunk-5KI5YSQ5.js.map → chunk-GB6PRJET.js.map} +1 -1
  15. package/dist/{chunk-MQSFPRF6.js → chunk-V4RI7GWD.js} +37 -19
  16. package/dist/chunk-V4RI7GWD.js.map +1 -0
  17. package/dist/{chunk-HRGPFQBW.js → chunk-ZAWXMUGZ.js} +6 -3
  18. package/dist/chunk-ZAWXMUGZ.js.map +1 -0
  19. package/dist/{config-Dfu-NKxd.d.ts → config-Cz7ZyGF-.d.ts} +5 -5
  20. package/dist/csf/preview-api.d.ts +5 -2
  21. package/dist/csf/preview-api.js +2 -2
  22. package/dist/csf/preview-api.js.map +1 -1
  23. package/dist/frame/index.css +19 -2
  24. package/dist/frame/index.css.map +1 -1
  25. package/dist/frame/index.d.ts +2 -2
  26. package/dist/frame/index.js +5 -5
  27. package/dist/frame/index.js.map +1 -1
  28. package/dist/index.d.ts +4 -4
  29. package/dist/index.js +3 -3
  30. package/dist/shell/index.css +36 -5
  31. package/dist/shell/index.css.map +1 -1
  32. package/dist/shell/index.d.ts +7 -6
  33. package/dist/shell/index.js +398 -274
  34. package/dist/shell/index.js.map +1 -1
  35. package/dist/test/index.d.ts +1 -1
  36. package/dist/test/index.js +6 -6
  37. package/dist/test/play.d.ts +3 -5
  38. package/dist/test/play.js.map +1 -1
  39. package/dist/vite/index.d.ts +16 -1
  40. package/dist/vite/index.js +403 -78
  41. package/dist/vite/index.js.map +1 -1
  42. package/package.json +10 -5
  43. package/dist/chunk-B3PPHJTS.js.map +0 -1
  44. package/dist/chunk-HRGPFQBW.js.map +0 -1
  45. package/dist/chunk-JHL4ERDA.js.map +0 -1
  46. package/dist/chunk-MQSFPRF6.js.map +0 -1
  47. package/dist/chunk-TXLWQFF6.js.map +0 -1
  48. package/dist/chunk-ZZCCIXEJ.js.map +0 -1
@@ -1,6 +1,7 @@
1
- import { GLOBALS_KEY, effectiveGlobals, storyConfig, isForgePath, PLAYHEAD_KEY } from './chunk-JHL4ERDA.js';
2
- import { StoryHost, useNearViewport, IN_VIEW_MARGIN, createOverrides, createGlobalsTarget, useStoryClock, useClockLoop, scanCssVars, runAxe } from './chunk-B3PPHJTS.js';
1
+ import { GLOBALS_KEY, effectiveGlobals, storyConfig, isForgePath, PLAYHEAD_KEY } from './chunk-DFKCLZKS.js';
2
+ import { StoryHost, useNearViewport, IN_VIEW_MARGIN, createOverrides, createGlobalsTarget, useStoryClock, useClockLoop, scanCssVars, runAxe } from './chunk-4NM3RTYK.js';
3
3
  import { ClockContext } from './chunk-L5XM5VKB.js';
4
+ import { createEmitter } from '@weasel-js/registry';
4
5
  import { createContext, memo, useContext, useCallback, useSyncExternalStore, useMemo, useId, useState, useRef, useLayoutEffect, useEffect } from 'react';
5
6
  import { useLatest } from '@weasel-js/core';
6
7
  import { usePersistedState, TrialIdContext, LabBoundary } from '@weasel-js/labkit';
@@ -10,10 +11,8 @@ import { jsx } from 'react/jsx-runtime';
10
11
  var NO_FRAME = { send: null, vars: [], audit: null, a11y: null };
11
12
  function createTrialFrames() {
12
13
  const frames = /* @__PURE__ */ new Map();
13
- const listeners = /* @__PURE__ */ new Set();
14
- const changed = () => {
15
- for (const listener of [...listeners]) listener();
16
- };
14
+ const changes = createEmitter();
15
+ const changed = changes.emit;
17
16
  const patch = (trialId, next) => {
18
17
  const frame = frames.get(trialId);
19
18
  if (!frame) return;
@@ -33,10 +32,7 @@ function createTrialFrames() {
33
32
  report: (trialId, vars) => patch(trialId, { vars }),
34
33
  reportA11y: (trialId, a11y) => patch(trialId, { a11y }),
35
34
  get: (trialId) => frames.get(trialId) ?? NO_FRAME,
36
- subscribe(listener) {
37
- listeners.add(listener);
38
- return () => listeners.delete(listener);
39
- }
35
+ subscribe: changes.subscribe
40
36
  };
41
37
  }
42
38
  var TrialFramesContext = createContext(null);
@@ -176,10 +172,8 @@ function TrialHost({ layout, setup, config, children, hostRef, onRendered }) {
176
172
  }
177
173
  function createTrialClocks() {
178
174
  const clocks = /* @__PURE__ */ new Map();
179
- const listeners = /* @__PURE__ */ new Set();
180
- const notify = () => {
181
- for (const listener of [...listeners]) listener();
182
- };
175
+ const changed = createEmitter();
176
+ const notify = changed.emit;
183
177
  return {
184
178
  publish(trialId, clock) {
185
179
  clocks.set(trialId, clock);
@@ -191,10 +185,7 @@ function createTrialClocks() {
191
185
  };
192
186
  },
193
187
  get: (trialId) => clocks.get(trialId) ?? null,
194
- subscribe(listener) {
195
- listeners.add(listener);
196
- return () => listeners.delete(listener);
197
- }
188
+ subscribe: changed.subscribe
198
189
  };
199
190
  }
200
191
  var TrialClocksContext = createContext(null);
@@ -229,7 +220,7 @@ var StoryBody = memo(function StoryBody2({ story, config, setConfig, state, setS
229
220
  return /* @__PURE__ */ jsx(StoryHost, { story, ctx: storyCtx, decorators, resetKey, onError });
230
221
  });
231
222
  function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
232
- const latest = useLatest(ctx);
223
+ const latestRef = useLatest(ctx);
233
224
  const [heldConfig, setHeldConfig] = useState(() => storyConfig(ctx.config));
234
225
  const config = storyConfig(ctx.config, heldConfig);
235
226
  if (config !== heldConfig) setHeldConfig(config);
@@ -246,9 +237,9 @@ function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
246
237
  setInput({ config, state: ctx.state, key: resetKey });
247
238
  }
248
239
  const setConfig = useCallback((path, value) => {
249
- if (!isForgePath(path)) latest.current.setConfig(path, value);
250
- }, [latest]);
251
- const setState = useCallback((next) => latest.current.setState(next), [latest]);
240
+ if (!isForgePath(path)) latestRef.current.setConfig(path, value);
241
+ }, [latestRef]);
242
+ const setState = useCallback((next) => latestRef.current.setState(next), [latestRef]);
252
243
  const trialId = useContext(TrialIdContext);
253
244
  const clocks = useContext(TrialClocksContext);
254
245
  const ownHost = useRef(null);
@@ -257,7 +248,7 @@ function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
257
248
  const persisted = typeof kept === "number" && Number.isFinite(kept) ? kept : null;
258
249
  const clock = useStoryClock(story.timeline?.(config) ?? null, () => persisted);
259
250
  useClockLoop(clock, host);
260
- usePersistedPlayhead(clock, persisted, (time) => latest.current.setConfig(PLAYHEAD_KEY, time));
251
+ usePersistedPlayhead(clock, persisted, (time) => latestRef.current.setConfig(PLAYHEAD_KEY, time));
261
252
  useEffect(() => clock && clocks && trialId ? clocks.publish(trialId, clock) : void 0, [clock, clocks, trialId]);
262
253
  const decorators = setup.decorators ?? NO_DECORATORS;
263
254
  const latestError = useLatest(onError);
@@ -290,5 +281,5 @@ function StoryTrial({ story, setup, ctx, hostRef, onRendered, onError }) {
290
281
  }
291
282
 
292
283
  export { StoryGlobalsContext, StoryTrial, TrialClocksContext, TrialFramesContext, TrialHost, createTrialClocks, createTrialFrames, useCssOverrides, useTrialClock, useTrialFrame };
293
- //# sourceMappingURL=chunk-ZZCCIXEJ.js.map
294
- //# sourceMappingURL=chunk-ZZCCIXEJ.js.map
284
+ //# sourceMappingURL=chunk-ENXU34PI.js.map
285
+ //# sourceMappingURL=chunk-ENXU34PI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shell/trialFrames.ts","../src/shell/StoryGlobalsContext.ts","../src/shell/cssVars/overrides.ts","../src/shell/TrialHost.tsx","../src/timeline/trialClocks.ts","../src/timeline/usePersistedPlayhead.ts","../src/shell/StoryTrial.tsx"],"names":["createContext","useContext","createEmitter","NONE","useSyncExternalStore","useRef","useLatest","useEffect","StoryBody","jsx","useState","useCallback","TrialIdContext"],"mappings":"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","file":"chunk-ENXU34PI.js","sourcesContent":["import { createEmitter } from '@weasel-js/registry';\nimport { createContext, useCallback, useContext, useSyncExternalStore } from 'react';\nimport type { A11yReport, CssVarReport, ToFrame } from '../protocol/messages';\n\n/** What an axe run in the frame came back with. */\nexport type A11yOutcome = { ok: true; report: A11yReport } | { ok: false; message: string };\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","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 { useLatest } from '@weasel-js/core';\nimport { LabBoundary, TrialIdContext } from '@weasel-js/labkit';\nimport { OverlayPortalProvider } from '@weasel-js/ui';\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 { runAxe } from '../frame/a11y';\nimport { createOverrides, type Overrides, scanCssVars } from '../frame/cssVars';\nimport type { FrameSetup } from '../frame/FrameController';\nimport { IN_VIEW_MARGIN, useNearViewport } from '../frame/useNearViewport';\nimport { createGlobalsTarget } from '../frame/globalsTarget';\nimport type { CssVarReport, Globals, Layout, ToFrame } from '../protocol/messages';\nimport { useCssOverrides } from './cssVars/overrides';\nimport { effectiveGlobals, GLOBALS_KEY } from './globals';\nimport { StoryGlobalsContext } from './StoryGlobalsContext';\nimport { type A11yOutcome, 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\nconst VARS_SETTLE_MS = 100;\n\n/** A selector matching only the element carrying `id`. */\nconst scopeOf = (id: string) => `[data-fg-host=\"${id}\"]`;\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.\n */\nexport function TrialHost({ layout, setup, config, children, hostRef, onRendered }: 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 globals = useMemo(() => effectiveGlobals(labGlobals, pins), [labGlobals, pins]);\n const [persisted] = useCssOverrides();\n const reactId = useId();\n const hostId = 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 [pending, setPending] = useState(true);\n const overridesRef = useRef<Overrides | null>(null);\n const latest = useLatest({ setup, onRendered });\n\n // Everything the host owns for its lifetime: the globals target, the overrides rule, the registry connection.\n useLayoutEffect(() => {\n if (!host) return;\n const doc = host.ownerDocument;\n const scope = scopeOf(hostId);\n const { cssVarsScope } = latest.current.setup;\n const overrides = createOverrides(doc, cssVarsScope ? `${scope}, ${scope} :is(${cssVarsScope})` : scope);\n overridesRef.current = overrides;\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 send = (msg: ToFrame) => {\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 (): Promise<A11yOutcome> => {\n let outcome: A11yOutcome;\n try {\n outcome = { ok: true, report: await runAxe(host, { page: false }) };\n } catch (error) {\n outcome = { ok: false, message: error instanceof Error ? error.message : String(error) };\n }\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 mutations?.disconnect();\n clearTimeout(settleTimer);\n overrides.dispose();\n overridesRef.current = null;\n };\n }, [host, hostId, trialId, frames, latest]);\n\n // The overrides the trial persisted, put back on every mount and kept in step with the panel's edits.\n const applied = useRef<Record<string, string>>({});\n useLayoutEffect(() => {\n const overrides = overridesRef.current;\n if (!overrides) return;\n for (const name of Object.keys(applied.current)) if (!(name in persisted)) overrides.set(name, null);\n for (const [name, value] of Object.entries(persisted)) overrides.set(name, value);\n applied.current = { ...persisted };\n }, [host, persisted]);\n\n useLayoutEffect(() => {\n if (!host) return;\n const target = createGlobalsTarget(host, scopeOf(hostId));\n latest.current.setup.applyGlobals?.(globals, target);\n return () => target.dispose();\n }, [host, hostId, globals, latest]);\n\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 || !inView || announced.current) return;\n let canceled = false;\n const done = () => {\n if (canceled) return;\n announced.current = true;\n setPending(false);\n latest.current.onRendered?.();\n };\n const { fonts } = host.ownerDocument;\n if (!fonts) {\n done();\n return;\n }\n const afterPaint = () => requestAnimationFrame(done);\n void fonts.ready.then(afterPaint, afterPaint);\n return () => {\n canceled = true;\n };\n }, [host, inView, latest]);\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-layout={layout}\n data-pending={pending || undefined}\n >\n {host && inView ? (\n // The workshop is itself a lab; below the boundary a story sees no lab, trial or theme above it, as in a\n // document of its own.\n <LabBoundary>\n <OverlayPortalProvider container={host}>{children(globals)}</OverlayPortalProvider>\n </LabBoundary>\n ) : null}\n </div>\n );\n}\n","import { createEmitter } from '@weasel-js/registry';\nimport { createContext, useContext, useSyncExternalStore } from 'react';\nimport type { Clock } from './clock';\n\n/** Each trial's story clock, by trial id: the story's trial publishes it, and the trial's transport reads it. */\nexport interface TrialClocks {\n /** Publishes `clock` as `trialId`'s; the returned function withdraws it. */\n publish(trialId: string, clock: Clock): () => void;\n get(trialId: string): Clock | null;\n subscribe(listener: () => void): () => void;\n}\n\nexport function createTrialClocks(): TrialClocks {\n const clocks = new Map<string, Clock>();\n const changed = createEmitter();\n const notify = changed.emit;\n return {\n publish(trialId, clock) {\n clocks.set(trialId, clock);\n notify();\n return () => {\n if (clocks.get(trialId) !== clock) return;\n clocks.delete(trialId);\n notify();\n };\n },\n get: (trialId) => clocks.get(trialId) ?? null,\n subscribe: changed.subscribe,\n };\n}\n\nexport const TrialClocksContext = createContext<TrialClocks | null>(null);\n\nconst NEVER = () => () => {};\nconst NONE = () => null;\n\n/** The clock trial `trialId`'s story published, or null. */\nexport function useTrialClock(trialId: string): Clock | null {\n const clocks = useContext(TrialClocksContext);\n return useSyncExternalStore(clocks?.subscribe ?? NEVER, clocks ? () => clocks.get(trialId) : NONE);\n}\n","import { useLatest } from '@weasel-js/core';\nimport { useEffect, useRef } from 'react';\nimport type { Clock } from './clock';\n\n/**\n * Keeps `clock`'s paused time in the trial, through `write`, so a reload or a snapshot brings the story back there.\n * It writes when the clock stops or moves while stopped, never on a playing frame. A `persisted` value arriving from\n * outside — a snapshot loaded, a Reset — is requested of the clock, so a span set later can still hold it; null\n * stands for the span's start. Nothing is written while a request waits on a span.\n */\nexport function usePersistedPlayhead(clock: Clock | null, persisted: number | null, write: (time: number) => void): void {\n const written = useRef(persisted);\n const latestWrite = useLatest(write);\n\n useEffect(() => {\n if (!clock || persisted === written.current) return;\n written.current = persisted;\n clock.request(persisted);\n }, [clock, persisted]);\n\n useEffect(() => {\n if (!clock) return;\n return clock.subscribe(() => {\n const { playing, time } = clock.get();\n if (playing || clock.pending() !== null || time === written.current) return;\n written.current = time;\n latestWrite.current(time);\n });\n }, [clock, latestWrite]);\n}\n","import { type RenderContext, TrialIdContext } from '@weasel-js/labkit';\nimport { useLatest } from '@weasel-js/core';\nimport { memo, type RefObject, useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport type { FrameSetup } from '../frame/FrameController';\nimport { StoryHost } from '../frame/StoryHost';\nimport type { Globals } from '../protocol/messages';\nimport type { Decorator, LoadedStory, StoryContext } from '../story/types';\nimport { ClockContext } from '../timeline/context';\nimport { useStoryClock } from '../timeline/StoryClock';\nimport { TrialClocksContext } from '../timeline/trialClocks';\nimport { useClockLoop } from '../timeline/useClockLoop';\nimport { usePersistedPlayhead } from '../timeline/usePersistedPlayhead';\nimport { isForgePath, PLAYHEAD_KEY, storyConfig } from './globals';\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\ninterface 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. */\nconst 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\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 lives with its trial: the trial's transport reads it from the registry, the story from context.\n const trialId = useContext(TrialIdContext);\n const clocks = useContext(TrialClocksContext);\n const ownHost = useRef<HTMLElement | null>(null);\n const host = hostRef ?? ownHost;\n const kept = (ctx.config as Record<string, unknown> | null)?.[PLAYHEAD_KEY];\n const persisted = typeof kept === 'number' && Number.isFinite(kept) ? kept : null;\n const clock = useStoryClock(story.timeline?.(config) ?? null, () => persisted);\n useClockLoop(clock, host);\n usePersistedPlayhead(clock, persisted, (time) => latestRef.current.setConfig(PLAYHEAD_KEY, time));\n useEffect(() => (clock && clocks && trialId ? clocks.publish(trialId, clock) : undefined), [clock, clocks, trialId]);\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 render = (globals: Globals) => (\n <ClockContext.Provider value={clock}>\n <StoryBody\n story={story}\n config={config}\n setConfig={setConfig}\n state={ctx.state}\n setState={setState}\n globals={globals}\n decorators={decorators}\n resetKey={resetKey}\n onError={reportError}\n />\n </ClockContext.Provider>\n );\n\n return (\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 );\n}\n"]}
@@ -6,5 +6,5 @@ var PORT_HANDOFF = "weaselforge:port";
6
6
  var FRAME_HELLO = "weaselforge:hello";
7
7
 
8
8
  export { FRAME_HELLO, PORT_HANDOFF, PROTOCOL_VERSION };
9
- //# sourceMappingURL=chunk-TXLWQFF6.js.map
10
- //# sourceMappingURL=chunk-TXLWQFF6.js.map
9
+ //# sourceMappingURL=chunk-FL2MUPUL.js.map
10
+ //# sourceMappingURL=chunk-FL2MUPUL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/messages.ts"],"names":[],"mappings":";;;AAEO,IAAM,gBAAA,GAAmB;AAyFzB,IAAM,YAAA,GAAe;AASrB,IAAM,WAAA,GAAc","file":"chunk-FL2MUPUL.js","sourcesContent":["import type { SchemaDescription } from './schema.ts';\n\nexport const PROTOCOL_VERSION = 1;\n\n/** The workshop's toolbar globals as a story reads them, by name. */\nexport type Globals = Readonly<Record<string, unknown>>;\n/** How a story sits in its frame. */\nexport type Layout = 'centered' | 'padded' | 'fullscreen';\n/** A frame size a story asks for, in CSS pixels. */\nexport interface Viewport {\n width: number;\n height: number;\n}\n/** Where a frame's fault happened: loading the story, rendering it, or reading a message. */\nexport type FaultPhase = 'import' | 'render' | 'protocol';\n\n/** One custom property as the frame found it. */\nexport interface CssVarReport {\n name: string;\n value: string;\n /** Whether a `vars.set` override is in force on it. */\n overridden: boolean;\n}\n\n/** Visibility and validation answers, keyed by the config they were computed for. */\nexport interface ConfigAnswers {\n /** `stableStringify(config)` of the config the frame evaluated. */\n configKey: string;\n hidden: string[];\n errors: Record<string, string[]>;\n}\n\n/** One element axe faulted on, inside the frame's own document. */\nexport interface A11yNode {\n /** The CSS selectors, outermost first, that reach the element in the frame. */\n target: readonly string[];\n html: string;\n failureSummary?: string;\n}\n\n/** One axe rule's outcome on the story, with the elements it names. */\nexport interface A11yFinding {\n id: string;\n impact: 'minor' | 'moderate' | 'serious' | 'critical' | null;\n help: string;\n helpUrl: string;\n description: string;\n nodes: readonly A11yNode[];\n}\n\n/** What axe found on one story: the rules it failed, and the ones it could not decide. */\nexport interface A11yReport {\n violations: readonly A11yFinding[];\n incomplete: readonly A11yFinding[];\n /** Rules that passed, and rules no element on the page could be judged by. */\n passes: number;\n inapplicable: number;\n}\n\n/** A message the workshop sends a story's frame. */\nexport type ToFrame =\n | { type: 'init'; config: unknown; state: unknown; globals: Globals }\n | { type: 'config'; config: unknown }\n | { type: 'state'; state: unknown }\n | { type: 'globals'; globals: Globals }\n | { type: 'vars.set'; name: string; value: string | null }\n /** Run axe over the story's own subtree. Answered by `a11y` carrying the same `id`. */\n | { type: 'a11y.run'; id: string };\n\n/** A message a story's frame sends the workshop. */\nexport type FromFrame =\n | { type: 'ready'; schema: SchemaDescription; layout: Layout; viewport: Viewport | null }\n /** Sent once, when the story's first render after `init` has committed. */\n | { type: 'rendered' }\n | { type: 'answers'; answers: ConfigAnswers }\n | { type: 'setConfig'; path: string; value: unknown }\n | { type: 'setState'; state: unknown }\n | { type: 'vars'; vars: CssVarReport[] }\n /** Asks the shell to show story `id` in this frame's trial in place of what it shows now. */\n | { type: 'open'; id: string }\n | { type: 'a11y'; id: string; ok: true; report: A11yReport }\n | { type: 'a11y'; id: string; ok: false; message: string }\n /** `seq`, on a render fault only: how many `init`/`config`/`state`/`globals` messages the frame had received. */\n | { type: 'fault'; phase: FaultPhase; message: string; stack?: string; seq?: number };\n\nexport interface Envelope<M> {\n v: number;\n msg: M;\n}\n\n/** Posted on the frame's window with the port transferred alongside it, as a `PortHandoff`. */\nexport const PORT_HANDOFF = 'weaselforge:port';\n\n/** What the shell posts with the port: `id` names what the frame shows, a story or an index. */\nexport interface PortHandoff {\n type: typeof PORT_HANDOFF;\n id: string;\n}\n\n/** Posted by a frame document to its parent as soon as its entry runs, asking for a port. */\nexport const FRAME_HELLO = 'weaselforge:hello';\n\nexport { stableStringify } from '@weasel-js/core';\n"]}
@@ -1,4 +1,4 @@
1
- import { stableStringify } from './chunk-TXLWQFF6.js';
1
+ import { stableStringify } from './chunk-FL2MUPUL.js';
2
2
  import { createContext } from 'react';
3
3
  import { isPlainObject } from '@weasel-js/core';
4
4
 
@@ -93,5 +93,5 @@ function withUnsent(sent, original) {
93
93
  }
94
94
 
95
95
  export { ArgsContext, appliedLocal, coverOf, isPortSafe, portSafePart, withUnsent };
96
- //# sourceMappingURL=chunk-5KI5YSQ5.js.map
97
- //# sourceMappingURL=chunk-5KI5YSQ5.js.map
96
+ //# sourceMappingURL=chunk-GB6PRJET.js.map
97
+ //# sourceMappingURL=chunk-GB6PRJET.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/csf/argsContext.ts","../src/csf/portSafe.ts"],"names":[],"mappings":"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","file":"chunk-5KI5YSQ5.js","sourcesContent":["import { type Context, createContext, type Dispatch, type SetStateAction } from 'react';\nimport { stableStringify } from '../protocol/messages';\n\ntype Args = Record<string, unknown>;\n\n/** A frame-local arg, and the config value it was set over: it applies only while config still holds that. */\nexport interface LocalArg {\n value: unknown;\n over: string;\n}\n\nexport type LocalArgs = Record<string, LocalArg>;\n\n/** A config value in the form `LocalArg.over` records. */\nexport const coverOf = (value: unknown): string => stableStringify(value) ?? ' undefined';\n\n/** The frame-local values that still apply over `config`. */\nexport const appliedLocal = (local: LocalArgs, config: Args): Args =>\n Object.fromEntries(\n Object.entries(local)\n .filter(([key, entry]) => coverOf(config[key]) === entry.over)\n .map(([key, entry]) => [key, entry.value]),\n );\n\nexport interface ArgsScope {\n /** The args the story renders with: its own, then config, then the frame-local ones that still apply. */\n args: Args;\n /** The trial's config as it stands. An `undefined` key means the story's own arg. */\n config: Args;\n defaults: Args;\n /** The story's own args, before config and the frame-local ones. */\n original: Args;\n setConfig: (path: string, value: unknown) => void;\n /** Args a MessagePort would not deliver intact, kept in the frame because config crosses one. */\n setLocal: Dispatch<SetStateAction<LocalArgs>>;\n}\n\nexport const ArgsContext: Context<ArgsScope | null> = createContext<ArgsScope | null>(null);\n","import { isPlainObject } from '@weasel-js/core';\n\nconst g = globalThis as Record<string, unknown>;\nconst CLONED_WHOLE = new Set<unknown>(\n [\n 'Date',\n 'RegExp',\n 'ArrayBuffer',\n 'DataView',\n 'Int8Array',\n 'Uint8Array',\n 'Uint8ClampedArray',\n 'Int16Array',\n 'Uint16Array',\n 'Int32Array',\n 'Uint32Array',\n 'Float16Array',\n 'Float32Array',\n 'Float64Array',\n 'BigInt64Array',\n 'BigUint64Array',\n ]\n .map((name) => (g[name] as { prototype?: object } | undefined)?.prototype)\n .filter(Boolean),\n);\n\n/** Own keys a clone keeps: enumerable string keys, plus an array's `length`. */\nconst hasOnlyClonedKeys = (v: object): boolean =>\n Reflect.ownKeys(v).every(\n (key) =>\n typeof key === 'string' &&\n (Object.prototype.propertyIsEnumerable.call(v, key) || (Array.isArray(v) && key === 'length')),\n );\n\n/**\n * Whether a MessagePort delivers `value` as the same thing it was. `structuredClone` succeeding is\n * not enough: it copies a class instance's fields onto a plain object and drops its methods.\n */\nexport function isPortSafe(value: unknown): boolean {\n const seen = new Set<object>();\n const safe = (v: unknown): boolean => {\n if (v === null) return true;\n if (typeof v !== 'object') return typeof v !== 'function' && typeof v !== 'symbol';\n if (seen.has(v)) return true;\n seen.add(v);\n const proto = Object.getPrototypeOf(v);\n if (CLONED_WHOLE.has(proto)) return true;\n if (proto === Map.prototype)\n return hasOnlyClonedKeys(v) && [...(v as Map<unknown, unknown>)].every(([key, member]) => safe(key) && safe(member));\n if (proto === Set.prototype) return hasOnlyClonedKeys(v) && [...(v as Set<unknown>)].every(safe);\n if (proto !== Array.prototype && proto !== Object.prototype && proto !== null) return false;\n return hasOnlyClonedKeys(v) && Object.values(v).every(safe);\n };\n try {\n return safe(value);\n } catch {\n return false;\n }\n}\n\n/** A plain object or array whose members can be split: React elements are plain objects, but whole. */\nconst splittable = (v: unknown): v is Record<string, unknown> | unknown[] =>\n (Array.isArray(v) ? Object.getPrototypeOf(v) === Array.prototype : isPlainObject(v) && !('$$typeof' in v)) &&\n hasOnlyClonedKeys(v as object);\n\n/**\n * The part of `value` a port delivers intact, or null when none of it can cross. A plain object\n * keeps its port-safe fields; an array holds null where a member has no part.\n */\nexport function portSafePart(value: unknown): { value: unknown } | null {\n const walking = new Set<object>();\n const part = (v: unknown): { value: unknown } | null => {\n if (isPortSafe(v)) return { value: v };\n if (!splittable(v) || walking.has(v)) return null;\n walking.add(v);\n try {\n if (Array.isArray(v)) return { value: v.map((member) => part(member)?.value ?? null) };\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(v)) {\n const kept = part(member);\n if (kept) out[key] = kept.value;\n }\n return { value: out };\n } finally {\n walking.delete(v);\n }\n };\n try {\n return part(value);\n } catch {\n return null;\n }\n}\n\n/** `sent`, a value that crossed the port as `portSafePart(original)` or an edit of it, with what the part left behind put back. */\nexport function withUnsent(sent: unknown, original: unknown): unknown {\n if (isPortSafe(original)) return sent;\n if (sent === null && portSafePart(original) === null) return original;\n if (Array.isArray(original) && Array.isArray(sent))\n return sent.map((member, i) => (i < original.length ? withUnsent(member, original[i]) : member));\n if (!splittable(original) || Array.isArray(original) || !isPlainObject(sent)) return sent;\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(original)) {\n if (key in sent) out[key] = withUnsent(sent[key], member);\n else if (portSafePart(member) === null) out[key] = member;\n }\n for (const [key, member] of Object.entries(sent)) if (!(key in original)) out[key] = member;\n return out;\n}\n"]}
1
+ {"version":3,"sources":["../src/csf/argsContext.ts","../src/csf/portSafe.ts"],"names":[],"mappings":"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","file":"chunk-GB6PRJET.js","sourcesContent":["import { type Context, createContext, type Dispatch, type SetStateAction } from 'react';\nimport { stableStringify } from '../protocol/messages';\n\ntype Args = Record<string, unknown>;\n\n/** A frame-local arg, and the config value it was set over: it applies only while config still holds that. */\nexport interface LocalArg {\n value: unknown;\n over: string;\n}\n\nexport type LocalArgs = Record<string, LocalArg>;\n\n/** A config value in the form `LocalArg.over` records. */\nexport const coverOf = (value: unknown): string => stableStringify(value) ?? ' undefined';\n\n/** The frame-local values that still apply over `config`. */\nexport const appliedLocal = (local: LocalArgs, config: Args): Args =>\n Object.fromEntries(\n Object.entries(local)\n .filter(([key, entry]) => coverOf(config[key]) === entry.over)\n .map(([key, entry]) => [key, entry.value]),\n );\n\nexport interface ArgsScope {\n /** The args the story renders with: its own, then config, then the frame-local ones that still apply. */\n args: Args;\n /** The trial's config as it stands. An `undefined` key means the story's own arg. */\n config: Args;\n defaults: Args;\n /** The story's own args, before config and the frame-local ones. */\n original: Args;\n setConfig: (path: string, value: unknown) => void;\n /** Args a MessagePort would not deliver intact, kept in the frame because config crosses one. */\n setLocal: Dispatch<SetStateAction<LocalArgs>>;\n}\n\nexport const ArgsContext: Context<ArgsScope | null> = createContext<ArgsScope | null>(null);\n","import { isPlainObject } from '@weasel-js/core';\n\nconst g = globalThis as Record<string, unknown>;\nconst CLONED_WHOLE = new Set<unknown>(\n [\n 'Date',\n 'RegExp',\n 'ArrayBuffer',\n 'DataView',\n 'Int8Array',\n 'Uint8Array',\n 'Uint8ClampedArray',\n 'Int16Array',\n 'Uint16Array',\n 'Int32Array',\n 'Uint32Array',\n 'Float16Array',\n 'Float32Array',\n 'Float64Array',\n 'BigInt64Array',\n 'BigUint64Array',\n ]\n .map((name) => (g[name] as { prototype?: object } | undefined)?.prototype)\n .filter(Boolean),\n);\n\n/** Own keys a clone keeps: enumerable string keys, plus an array's `length`. */\nconst hasOnlyClonedKeys = (v: object): boolean =>\n Reflect.ownKeys(v).every(\n (key) =>\n typeof key === 'string' &&\n (Object.prototype.propertyIsEnumerable.call(v, key) || (Array.isArray(v) && key === 'length')),\n );\n\n/**\n * Whether a MessagePort delivers `value` as the same thing it was. `structuredClone` succeeding is\n * not enough: it copies a class instance's fields onto a plain object and drops its methods.\n */\nexport function isPortSafe(value: unknown): boolean {\n const seen = new Set<object>();\n const safe = (v: unknown): boolean => {\n if (v === null) return true;\n if (typeof v !== 'object') return typeof v !== 'function' && typeof v !== 'symbol';\n if (seen.has(v)) return true;\n seen.add(v);\n const proto = Object.getPrototypeOf(v);\n if (CLONED_WHOLE.has(proto)) return true;\n if (proto === Map.prototype)\n return hasOnlyClonedKeys(v) && [...(v as Map<unknown, unknown>)].every(([key, member]) => safe(key) && safe(member));\n if (proto === Set.prototype) return hasOnlyClonedKeys(v) && [...(v as Set<unknown>)].every(safe);\n if (proto !== Array.prototype && proto !== Object.prototype && proto !== null) return false;\n return hasOnlyClonedKeys(v) && Object.values(v).every(safe);\n };\n try {\n return safe(value);\n } catch {\n return false;\n }\n}\n\n/** A plain object or array whose members can be split: React elements are plain objects, but whole. */\nconst splittable = (v: unknown): v is Record<string, unknown> | unknown[] =>\n (Array.isArray(v) ? Object.getPrototypeOf(v) === Array.prototype : isPlainObject(v) && !('$$typeof' in v)) &&\n hasOnlyClonedKeys(v as object);\n\n/**\n * The part of `value` a port delivers intact, or null when none of it can cross. A plain object\n * keeps its port-safe fields; an array holds null where a member has no part.\n */\nexport function portSafePart(value: unknown): { value: unknown } | null {\n const walking = new Set<object>();\n const part = (v: unknown): { value: unknown } | null => {\n if (isPortSafe(v)) return { value: v };\n if (!splittable(v) || walking.has(v)) return null;\n walking.add(v);\n try {\n if (Array.isArray(v)) return { value: v.map((member) => part(member)?.value ?? null) };\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(v)) {\n const kept = part(member);\n if (kept) out[key] = kept.value;\n }\n return { value: out };\n } finally {\n walking.delete(v);\n }\n };\n try {\n return part(value);\n } catch {\n return null;\n }\n}\n\n/** `sent`, a value that crossed the port as `portSafePart(original)` or an edit of it, with what the part left behind put back. */\nexport function withUnsent(sent: unknown, original: unknown): unknown {\n if (isPortSafe(original)) return sent;\n if (sent === null && portSafePart(original) === null) return original;\n if (Array.isArray(original) && Array.isArray(sent))\n return sent.map((member, i) => (i < original.length ? withUnsent(member, original[i]) : member));\n if (!splittable(original) || Array.isArray(original) || !isPlainObject(sent)) return sent;\n const out: Record<string, unknown> = {};\n for (const [key, member] of Object.entries(original)) {\n if (key in sent) out[key] = withUnsent(sent[key], member);\n else if (portSafePart(member) === null) out[key] = member;\n }\n for (const [key, member] of Object.entries(sent)) if (!(key in original)) out[key] = member;\n return out;\n}\n"]}
@@ -1,12 +1,14 @@
1
- import { useNearViewport, StoryHost } from './chunk-B3PPHJTS.js';
2
- import { sanitize } from './chunk-HRGPFQBW.js';
3
- import { PROTOCOL_VERSION } from './chunk-TXLWQFF6.js';
4
- import { f, isConfigBranch, resolveConfigSchema, schemaNodeAtPath, titleCase } from '@weasel-js/labkit/config';
1
+ import { useNearViewport, StoryHost } from './chunk-4NM3RTYK.js';
2
+ import { sanitize } from './chunk-ZAWXMUGZ.js';
3
+ import { PROTOCOL_VERSION } from './chunk-FL2MUPUL.js';
4
+ import { f, resolveConfigSchema, isEntryShown, isConfigBranch, schemaNodeAtPath, titleCase } from '@weasel-js/labkit/config';
5
+ import { createEmitter } from '@weasel-js/registry';
5
6
  import { createContext, useContext, useMemo, useState, useRef, useEffect, useId } from 'react';
6
7
  import { Badge } from '@weasel-js/ui/components/Badge';
7
8
  import { jsx, jsxs } from 'react/jsx-runtime';
8
9
  import { Button } from '@weasel-js/ui/components/Button';
9
10
  import { isPlainObject } from '@weasel-js/core';
11
+ import num from '@weasel-js/theme/numeric.module.css';
10
12
 
11
13
  var joinPath = (at, key) => at === "" ? key : `${at}.${key}`;
12
14
  function describeShape(shape) {
@@ -66,18 +68,17 @@ function answerSchema(schema, config) {
66
68
  const hidden = [];
67
69
  const errors = {};
68
70
  const record = config;
69
- let group;
71
+ const { group } = resolveConfigSchema(schema);
70
72
  const walk = (shape, at) => {
71
73
  for (const [key, entry] of Object.entries(shape)) {
72
74
  const path = joinPath(at, key);
73
- if (entry.options.showIf && !entry.options.showIf(record)) hidden.push(path);
75
+ if (!isEntryShown(entry, record, group)) hidden.push(path);
74
76
  if (isConfigBranch(entry)) {
75
77
  walk(entry.children, path);
76
78
  continue;
77
79
  }
78
80
  const { validate } = entry.options;
79
81
  if (!validate) continue;
80
- group ??= resolveConfigSchema(schema).group;
81
82
  const leaf = schemaNodeAtPath(group, path);
82
83
  if (!leaf || "children" in leaf) continue;
83
84
  const found = validate(leaf, record);
@@ -87,10 +88,8 @@ function answerSchema(schema, config) {
87
88
  walk(schema.nodes, "");
88
89
  return { hidden, errors };
89
90
  }
90
-
91
- // src/protocol/channel.ts
92
91
  function openChannel(port, options = {}) {
93
- const listeners = /* @__PURE__ */ new Set();
92
+ const messages = createEmitter();
94
93
  const onMessage = (event) => {
95
94
  const data = event.data;
96
95
  if (typeof data !== "object" || data === null || !("msg" in data)) {
@@ -102,19 +101,15 @@ function openChannel(port, options = {}) {
102
101
  options.onMismatch?.({ reason: "version", version: envelope.v });
103
102
  return;
104
103
  }
105
- for (const fn of listeners) fn(envelope.msg);
104
+ messages.emit(envelope.msg);
106
105
  };
107
106
  port.addEventListener("message", onMessage);
108
107
  port.start?.();
109
108
  return {
110
109
  send: (msg) => port.postMessage({ v: PROTOCOL_VERSION, msg }),
111
- on: (fn) => {
112
- listeners.add(fn);
113
- return () => listeners.delete(fn);
114
- },
110
+ on: messages.subscribe,
115
111
  close: () => {
116
112
  port.removeEventListener("message", onMessage);
117
- listeners.clear();
118
113
  port.close();
119
114
  }
120
115
  };
@@ -174,12 +169,13 @@ var MAX_ROWS = 6;
174
169
  var labelOf = (key, name) => name ?? titleCase(key);
175
170
  function variantRows(schema) {
176
171
  const defaults = schema.defaults();
172
+ const { group } = resolveConfigSchema(schema);
177
173
  const rows = [];
178
174
  const walk = (shape, at) => {
179
175
  for (const [key, entry] of Object.entries(shape)) {
180
176
  if (rows.length >= MAX_ROWS) return;
181
177
  const path = at === "" ? key : `${at}.${key}`;
182
- if (entry.options.showIf && !entry.options.showIf(defaults)) continue;
178
+ if (!isEntryShown(entry, defaults, group)) continue;
183
179
  if (isConfigBranch(entry)) {
184
180
  walk(entry.children, path);
185
181
  continue;
@@ -308,6 +304,26 @@ function IndexDependencies() {
308
304
  /* @__PURE__ */ jsx(DependencyList, { label: "Used by", titles: dependencies.usedBy, empty: "No listed component uses it." })
309
305
  ] });
310
306
  }
307
+ var DAY = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
308
+ function HistoryDate({ label, iso }) {
309
+ return /* @__PURE__ */ jsxs("div", { className: "fg-index-history__item", children: [
310
+ /* @__PURE__ */ jsx("dt", { className: "fg-index-history__label", children: label }),
311
+ /* @__PURE__ */ jsx("dd", { className: `fg-index-history__value ${num.numeric}`, children: /* @__PURE__ */ jsx("time", { dateTime: iso, children: DAY.format(new Date(iso)) }) })
312
+ ] });
313
+ }
314
+ function IndexHistory() {
315
+ const { gallery, dependencies } = useEnv();
316
+ const history = gallery ? void 0 : dependencies?.history;
317
+ if (!history) return null;
318
+ return /* @__PURE__ */ jsxs("dl", { className: "fg-index-history", "aria-label": "History", children: [
319
+ /* @__PURE__ */ jsxs("div", { className: "fg-index-history__item", children: [
320
+ /* @__PURE__ */ jsx("dt", { className: "fg-index-history__label", children: "Since" }),
321
+ /* @__PURE__ */ jsx("dd", { className: `fg-index-history__value ${num.numeric}`, children: history.introduced ?? "Unreleased" })
322
+ ] }),
323
+ /* @__PURE__ */ jsx(HistoryDate, { label: "Created", iso: history.created }),
324
+ /* @__PURE__ */ jsx(HistoryDate, { label: "Modified", iso: history.modified })
325
+ ] });
326
+ }
311
327
  function StorySection({ story, variants }) {
312
328
  const env = useEnv();
313
329
  const headingId = useId();
@@ -353,6 +369,7 @@ function DefaultIndex() {
353
369
  env.gallery ? /* @__PURE__ */ jsx(GalleryBadge, {}) : null
354
370
  ] }),
355
371
  env.description ? /* @__PURE__ */ jsx("p", { className: "fg-index__description", children: env.description }) : null,
372
+ /* @__PURE__ */ jsx(IndexHistory, {}),
356
373
  /* @__PURE__ */ jsx(IndexDependencies, {})
357
374
  ] }),
358
375
  env.stories.map((story) => /* @__PURE__ */ jsx(StorySection, { story, variants: withVariants.has(story.id) }, story.id))
@@ -368,6 +385,7 @@ function indexContext(env) {
368
385
  Variants: IndexVariants,
369
386
  DefaultIndex,
370
387
  Dependencies: IndexDependencies,
388
+ History: IndexHistory,
371
389
  gallery: env.gallery ?? false,
372
390
  open: env.open
373
391
  };
@@ -377,5 +395,5 @@ function IndexPage({ env, render }) {
377
395
  }
378
396
 
379
397
  export { IndexPage, LibrariesContext, LibraryBadge, TITLE_LIBRARIES, answerSchema, describeSchema, indexEntries, indexId, isIndexId, librariesFrom, openChannel, schemaFromDescription };
380
- //# sourceMappingURL=chunk-MQSFPRF6.js.map
381
- //# sourceMappingURL=chunk-MQSFPRF6.js.map
398
+ //# sourceMappingURL=chunk-V4RI7GWD.js.map
399
+ //# sourceMappingURL=chunk-V4RI7GWD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/protocol/schema.ts","../src/protocol/channel.ts","../src/story/indexPages.ts","../src/story/library.ts","../src/frame/index/LibraryBadge.tsx","../src/frame/index/variants.ts","../src/frame/index/IndexPage.tsx"],"names":["resolveConfigSchema","isEntryShown","isConfigBranch","createContext","useContext","jsx","Badge"],"mappings":"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","file":"chunk-V4RI7GWD.js","sourcesContent":["import {\n f,\n isConfigBranch,\n isEntryShown,\n resolveConfigSchema,\n schemaNodeAtPath,\n type Annotations,\n type BranchAnnotations,\n type ConfigBranch,\n type ConfigEntry,\n type ConfigNode,\n type ConfigSchema,\n type ConfigShape,\n type NodeOptions,\n} from '@weasel-js/labkit/config';\n\n/** The section a described entry sits in, as structured-clone data. */\nexport interface SectionDescription {\n label: string;\n collapsed?: boolean;\n}\n\n/** One key of a described shape: a leaf, or a branch holding more. */\nexport type DescribedEntry =\n | {\n branch: true;\n annotations: BranchAnnotations;\n section?: SectionDescription;\n conditional: boolean;\n children: DescribedShape;\n }\n | {\n branch: false;\n kind: string | null;\n default: unknown;\n annotations: Annotations;\n section?: SectionDescription;\n conditional: boolean;\n validated: boolean;\n /** The node draws its own row with `.render`, which stays in the frame. */\n customControl: boolean;\n };\n\n/** A config shape as structured-clone data: each key's entry, described. */\nexport type DescribedShape = { [key: string]: DescribedEntry };\n\n/** A story's `f.schema` as structured-clone data. */\nexport interface SchemaDescription {\n nodes: DescribedShape;\n}\n\n/** Answers the workshop has for the rebuilt schema's predicates. */\nexport interface SchemaAnswers {\n hidden(path: string, config: unknown): boolean;\n errors(path: string, config: unknown): string[];\n}\n\nconst joinPath = (at: string, key: string): string => (at === '' ? key : `${at}.${key}`);\n\nfunction describeShape(shape: ConfigShape): DescribedShape {\n const out: DescribedShape = {};\n for (const [key, entry] of Object.entries(shape)) {\n const { section, showIf } = entry.options;\n const common = {\n annotations: { ...entry.annotations },\n ...(section === undefined ? {} : { section: { ...section } }),\n conditional: showIf !== undefined,\n };\n out[key] = isConfigBranch(entry)\n ? { branch: true, ...common, children: describeShape(entry.children) }\n : {\n branch: false,\n kind: entry.kind,\n default: entry.default,\n ...common,\n validated: entry.options.validate !== undefined,\n customControl: entry.options.render !== undefined,\n };\n }\n return out;\n}\n\nexport function describeSchema(schema: ConfigSchema<unknown>): SchemaDescription {\n return { nodes: describeShape(schema.nodes) };\n}\n\nfunction rebuildShape(shape: DescribedShape, at: string, answers: SchemaAnswers): ConfigShape {\n const out: Record<string, ConfigEntry> = {};\n for (const [key, entry] of Object.entries(shape)) {\n const path = joinPath(at, key);\n const options: NodeOptions = {\n ...(entry.section === undefined ? {} : { section: entry.section }),\n ...(entry.conditional ? { showIf: (config) => !answers.hidden(path, config) } : {}),\n };\n if (entry.branch) {\n const branch: ConfigBranch = {\n children: rebuildShape(entry.children, path, answers),\n annotations: entry.annotations,\n options,\n };\n out[key] = branch;\n } else {\n const node: ConfigNode = {\n kind: entry.kind,\n default: entry.default,\n annotations: entry.annotations,\n options: entry.validated ? { ...options, validate: (_leaf, config) => answers.errors(path, config) } : options,\n };\n out[key] = node;\n }\n }\n return out;\n}\n\nexport function schemaFromDescription(\n description: SchemaDescription,\n answers: SchemaAnswers,\n): ConfigSchema<unknown> {\n return f.schema(rebuildShape(description.nodes, '', answers)) as ConfigSchema<unknown>;\n}\n\n/** Evaluate a schema's own predicates for one config — the frame's half of `answers`. */\nexport function answerSchema(\n schema: ConfigSchema<unknown>,\n config: unknown,\n): { hidden: string[]; errors: Record<string, string[]> } {\n const hidden: string[] = [];\n const errors: Record<string, string[]> = {};\n const record = config as Record<string, unknown>;\n const { group } = resolveConfigSchema(schema);\n\n const walk = (shape: ConfigShape, at: string): void => {\n for (const [key, entry] of Object.entries(shape)) {\n const path = joinPath(at, key);\n if (!isEntryShown(entry, record, group)) hidden.push(path);\n if (isConfigBranch(entry)) {\n walk(entry.children, path);\n continue;\n }\n const { validate } = entry.options;\n if (!validate) continue;\n const leaf = schemaNodeAtPath(group, path);\n if (!leaf || 'children' in leaf) continue;\n const found = validate(leaf, record);\n if (found.length > 0) errors[path] = found;\n }\n };\n walk(schema.nodes, '');\n return { hidden, errors };\n}\n","import { createEmitter } from '@weasel-js/registry';\nimport { type Envelope, PROTOCOL_VERSION } from './messages';\n\nexport interface PortLike {\n postMessage(message: unknown): void;\n addEventListener(type: 'message', fn: (event: MessageEvent) => void): void;\n removeEventListener(type: 'message', fn: (event: MessageEvent) => void): void;\n start?(): void;\n close(): void;\n}\n\n/** One end of a two-way message link: sends `Out`, hears `In`. */\nexport interface Channel<In, Out> {\n send(msg: Out): void;\n on(fn: (msg: In) => void): () => void;\n close(): void;\n}\n\nexport type Mismatch = { reason: 'not-an-envelope' } | { reason: 'version'; version: unknown };\n\nexport interface ChannelOptions {\n onMismatch?: (mismatch: Mismatch) => void;\n}\n\nexport function openChannel<In, Out>(port: PortLike, options: ChannelOptions = {}): Channel<In, Out> {\n const messages = createEmitter<[msg: In]>();\n const onMessage = (event: MessageEvent) => {\n const data: unknown = event.data;\n if (typeof data !== 'object' || data === null || !('msg' in data)) {\n options.onMismatch?.({ reason: 'not-an-envelope' });\n return;\n }\n const envelope = data as Partial<Envelope<In>>;\n if (envelope.v !== PROTOCOL_VERSION) {\n options.onMismatch?.({ reason: 'version', version: envelope.v });\n return;\n }\n messages.emit(envelope.msg as In);\n };\n port.addEventListener('message', onMessage);\n port.start?.();\n return {\n send: (msg) => port.postMessage({ v: PROTOCOL_VERSION, msg } satisfies Envelope<Out>),\n on: messages.subscribe,\n close: () => {\n port.removeEventListener('message', onMessage);\n port.close();\n },\n };\n}\n","import { sanitize } from './ids';\nimport type { IndexEntry } from './types';\n\nconst SUFFIX = ':index';\n\n/** The name an index page goes by in the sidebar and in its trial's title. */\nexport const INDEX_NAME = 'Index';\n\n/** The id of `title`'s index page. A colon never survives `sanitize`, so no story id can collide with it. */\nexport function indexId(title: string): string {\n return `${sanitize(title)}${SUFFIX}`;\n}\n\nexport function isIndexId(id: string): boolean {\n return id.endsWith(SUFFIX);\n}\n\n/**\n * One index-page entry per title in `stories`, in the order titles first appear. It routes and runs like a story:\n * its `file` is the title's first story file, its descriptions are the title's own, and its tags are those every story\n * of the title carries.\n */\nexport function indexEntries(stories: readonly IndexEntry[]): IndexEntry[] {\n const byTitle = new Map<string, IndexEntry>();\n for (const entry of stories) {\n const page = byTitle.get(entry.title);\n if (page) {\n if (page.tags) {\n const common = page.tags.filter((tag) => entry.tags?.includes(tag));\n if (common.length > 0) page.tags = common;\n else delete page.tags;\n }\n continue;\n }\n byTitle.set(entry.title, {\n id: indexId(entry.title),\n title: entry.title,\n name: INDEX_NAME,\n exportName: '',\n file: entry.file,\n ...(entry.componentDescription === undefined ? {} : { componentDescription: entry.componentDescription }),\n ...(entry.componentName === undefined ? {} : { componentName: entry.componentName }),\n ...(entry.tags === undefined ? {} : { tags: entry.tags }),\n });\n }\n return [...byTitle.values()];\n}\n","import type { StanceProps } from '@weasel-js/ui';\nimport { createContext } from 'react';\n\n/** One library of a project: the story files under `path` carry `label`. */\nexport interface Library {\n /** A stretch of path every story file of the library has, with forward slashes: `/packages/ui/`. */\n path: string;\n label: string;\n /** The tone of the library's badge, as a `<Badge>` takes one. Default: the badge's own muted tone. */\n tone?: StanceProps['tone'];\n}\n\n/** A project's libraries, as the tree's package filter, the index page header, and Get Info ask about them. */\nexport interface Libraries {\n /** The label of the first library whose `path` the story's file holds, else its title's first segment. */\n of(entry: { file: string; title: string }): string;\n toneOf(label: string): StanceProps['tone'];\n}\n\nexport function librariesFrom(table: readonly Library[] = []): Libraries {\n return {\n of(entry) {\n const file = entry.file.replaceAll('\\\\', '/');\n return table.find((library) => file.includes(library.path))?.label ?? entry.title.split('/')[0] ?? entry.title;\n },\n toneOf: (label) => table.find((library) => library.label === label)?.tone,\n };\n}\n\n/** No table: every story's library is its title's first segment. */\nexport const TITLE_LIBRARIES = librariesFrom();\n\n/** The workshop's libraries, from `ShellConfig.libraries`. */\nexport const LibrariesContext = createContext<Libraries>(TITLE_LIBRARIES);\n","// The component's own entry, not the barrel: the barrel would bring every weasel-ui component into each frame.\nimport { Badge } from '@weasel-js/ui/components/Badge';\nimport { useContext } from 'react';\nimport { LibrariesContext } from '../../story/library';\n\n/** A component's library, as a badge in the tone the project gave that library. */\nexport function LibraryBadge({ library, className }: { library: string; className?: string }) {\n const tone = useContext(LibrariesContext).toneOf(library);\n return (\n <Badge status=\"muted\" {...(tone === undefined ? {} : { tone })} variant=\"subtle\" size=\"sm\" {...(className ? { className } : {})}>\n {library}\n </Badge>\n );\n}\n","import { type ConfigSchema, type ConfigShape, isConfigBranch, isEntryShown, resolveConfigSchema, titleCase } from '@weasel-js/labkit/config';\nimport { isPlainObject } from '@weasel-js/core';\n\nexport interface VariantValue {\n value: unknown;\n label: string;\n}\n\n/** One control a story is shown varying along, with every other control at its default. */\nexport interface VariantRow {\n /** Dotted, as `setConfig` takes it. */\n path: string;\n label: string;\n values: VariantValue[];\n}\n\n/** Above this many choices a row stops being something to scan. */\nexport const MAX_ENUM_OPTIONS = 8;\nexport const MAX_ROWS = 6;\n\nconst labelOf = (key: string, name: string | undefined): string => name ?? titleCase(key);\n\n/**\n * The boolean and enum controls of `schema` a story can be shown varying along, in schema order: skipped are\n * controls that draw their own row, controls hidden at the defaults, and enums with more than\n * `MAX_ENUM_OPTIONS` choices. At most `MAX_ROWS`.\n */\nexport function variantRows(schema: ConfigSchema<unknown>): VariantRow[] {\n const defaults = schema.defaults() as Record<string, unknown>;\n const { group } = resolveConfigSchema(schema);\n const rows: VariantRow[] = [];\n const walk = (shape: ConfigShape, at: string): void => {\n for (const [key, entry] of Object.entries(shape)) {\n if (rows.length >= MAX_ROWS) return;\n const path = at === '' ? key : `${at}.${key}`;\n if (!isEntryShown(entry, defaults, group)) continue;\n if (isConfigBranch(entry)) {\n walk(entry.children, path);\n continue;\n }\n if (entry.annotations.hidden || entry.options.render) continue;\n const label = labelOf(key, entry.annotations.name);\n if (entry.kind === 'boolean') {\n rows.push({ path, label, values: [false, true].map((value) => ({ value, label: String(value) })) });\n } else if (entry.kind === 'enum') {\n const options = entry.annotations.options ?? [];\n if (options.length < 2 || options.length > MAX_ENUM_OPTIONS) continue;\n rows.push({ path, label, values: options.map((o) => ({ value: o.value, label: o.label })) });\n }\n }\n };\n walk(schema.nodes, '');\n return rows;\n}\n\n/** `over` merged into `base`: nested plain objects merge, anything else replaces. */\nexport function mergeConfig(base: unknown, over: unknown): unknown {\n if (!isPlainObject(base) || !isPlainObject(over)) return over === undefined ? base : over;\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(over)) out[key] = mergeConfig(base[key], value);\n return out;\n}\n\n/** `config` with `value` at dotted `path`, copying each object along the way. */\nexport function withValueAt(config: unknown, path: string, value: unknown): unknown {\n const [head, ...rest] = path.split('.');\n if (head === undefined) return value;\n const record = isPlainObject(config) ? config : {};\n return { ...record, [head]: rest.length === 0 ? value : withValueAt(record[head], rest.join('.'), value) };\n}\n","// The components' own entries, not the barrel: the barrel would bring every weasel-ui component into each frame.\nimport { Badge } from '@weasel-js/ui/components/Badge';\nimport { Button } from '@weasel-js/ui/components/Button';\nimport {\n createContext,\n type MouseEvent,\n type ReactNode,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { Globals } from '../../protocol/messages';\nimport { indexId } from '../../story/indexPages';\nimport type { ComponentDeps, Decorator, IndexContext, IndexStoryProps, LoadedStory, StoryContext } from '../../story/types';\nimport { StoryHost } from '../StoryHost';\nimport { useNearViewport } from '../useNearViewport';\nimport { mergeConfig, variantRows, withValueAt } from './variants';\nimport './index.css';\nimport { LibraryBadge } from './LibraryBadge';\nimport num from '@weasel-js/theme/numeric.module.css';\n\n/** What every cell on an index page shares with the frame that hosts it. */\nexport interface IndexEnv {\n title: string;\n /** The package the component ships in. */\n library?: string;\n description?: string;\n stories: readonly LoadedStory[];\n /** Per story id, the JSDoc above its export. */\n descriptions: Readonly<Record<string, string>>;\n /** A catalog or showcase rather than one component: every story of it is tagged `gallery`. */\n gallery?: boolean;\n /** The ids of the stories tagged `gallery`. */\n galleries?: readonly string[];\n /** The component's place in the component graph; absent until the graph arrives, and for a gallery. */\n dependencies?: ComponentDeps;\n globals: Globals;\n /** The frame config's, outermost. */\n decorators: readonly Decorator[];\n open: (id: string) => void;\n onError: (error: unknown) => void;\n}\n\nexport const IndexEnvContext = createContext<IndexEnv | null>(null);\n\nfunction useEnv(): IndexEnv {\n const env = useContext(IndexEnvContext);\n if (!env) throw new Error('An index page part rendered outside its index page');\n return env;\n}\n\n/** How far past the viewport a cell stays mounted. */\nconst NEAR_MARGIN = '100%';\n\n/**\n * One story at its defaults with `config` over them. It keeps its own config and state, so it stays interactive, and\n * it mounts only while near the viewport, so a page of canvas stories stays under the browser's WebGL context cap.\n */\nexport function IndexStory({ story, config: over, label }: IndexStoryProps) {\n const env = useEnv();\n const [config, setConfig] = useState(() => mergeConfig(story.config.defaults(), over));\n const [state, setState] = useState<unknown>(() => story.initialState?.(config) ?? null);\n const cell = useRef<HTMLElement>(null);\n // Starts unmounted, so a page of canvas stories never mounts every cell at once.\n const near = useNearViewport(cell, NEAR_MARGIN, false);\n // Held while unmounted, so scrolling past a cell does not move everything after it.\n const [height, setHeight] = useState<number | null>(null);\n useEffect(() => {\n const el = cell.current;\n if (!near || !el || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => setHeight(el.getBoundingClientRect().height));\n observer.observe(el);\n return () => observer.disconnect();\n }, [near]);\n const ctx: StoryContext = {\n config,\n setConfig: (path, value) => setConfig((prev: unknown) => withValueAt(prev, path, value)),\n state,\n setState: (next) =>\n setState((prev: unknown) => (typeof next === 'function' ? (next as (p: unknown) => unknown)(prev) : next)),\n globals: env.globals,\n title: story.title,\n name: story.name,\n };\n return (\n <figure\n ref={cell}\n className={`fg-index-cell fg-index-cell--${story.layout}`}\n style={!near && height !== null ? { minHeight: height } : undefined}\n >\n <div className=\"fg-index-cell__stage\">\n {near ? (\n <StoryHost story={story} ctx={ctx} decorators={env.decorators} resetKey={0} onError={env.onError} />\n ) : null}\n </div>\n {label === undefined ? null : <figcaption className=\"fg-index-cell__label\">{label}</figcaption>}\n </figure>\n );\n}\n\n/** `story` once per value of each boolean and enum control, every other control at its default. */\nexport function IndexVariants({ story }: { story: LoadedStory }) {\n const rows = useMemo(() => variantRows(story.config), [story]);\n const defaults = useMemo(() => story.config.defaults(), [story]);\n if (rows.length === 0) return null;\n return (\n <div className=\"fg-index-variants\">\n {rows.map((row) => (\n <section key={row.path} className=\"fg-index-variants__row\" aria-label={row.label}>\n <h4 className=\"fg-index-variants__label\">{row.label}</h4>\n <div className=\"fg-index-variants__cells\">\n {row.values.map((v) => (\n <IndexStory\n key={String(v.value)}\n story={story}\n config={withValueAt(defaults, row.path, v.value) as Record<string, unknown>}\n label={v.label}\n />\n ))}\n </div>\n </section>\n ))}\n </div>\n );\n}\n\nfunction GalleryBadge() {\n return (\n <Badge status=\"accent\" variant=\"subtle\" size=\"sm\">\n Gallery\n </Badge>\n );\n}\n\nfunction DependencyList({ label, titles, empty }: { label: string; titles: readonly string[]; empty: string }) {\n const env = useEnv();\n const labelId = useId();\n const follow = (event: MouseEvent, id: string) => {\n if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n event.preventDefault();\n env.open(id);\n };\n return (\n <div className=\"fg-index-deps__row\">\n <dt id={labelId} className=\"fg-index-deps__label\">\n {label}\n </dt>\n <dd className=\"fg-index-deps__value\">\n {titles.length === 0 ? (\n <span className=\"fg-index-deps__empty\">{empty}</span>\n ) : (\n <ul className=\"fg-index-deps__list\" aria-labelledby={labelId}>\n {titles.map((title) => {\n const cut = title.lastIndexOf('/') + 1;\n const id = indexId(title);\n return (\n <li key={title}>\n <a className=\"fg-index-deps__link\" href={`#/${encodeURIComponent(id)}`} onClick={(event) => follow(event, id)}>\n <span className=\"fg-index-deps__prefix\">{title.slice(0, cut)}</span>\n {title.slice(cut)}\n </a>\n </li>\n );\n })}\n </ul>\n )}\n </dd>\n </div>\n );\n}\n\n/** The listed components this one uses and those that use it, read from source. Nothing for a gallery. */\nexport function IndexDependencies() {\n const { gallery, dependencies } = useEnv();\n if (gallery || !dependencies) return null;\n if (dependencies.source === null) {\n return (\n <p className=\"fg-index-deps__none\">\n forge found no source file for this component, so it lists none of its dependencies. It looks for the\n import the meta&rsquo;s <code>component</code> names, or else the one the title&rsquo;s last segment names.\n </p>\n );\n }\n return (\n <dl className=\"fg-index-deps\" aria-label=\"Dependencies\">\n <DependencyList label=\"Uses\" titles={dependencies.uses} empty=\"No listed component.\" />\n <DependencyList label=\"Used by\" titles={dependencies.usedBy} empty=\"No listed component uses it.\" />\n </dl>\n );\n}\n\nconst DAY = new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' });\n\nfunction HistoryDate({ label, iso }: { label: string; iso: string }) {\n return (\n <div className=\"fg-index-history__item\">\n <dt className=\"fg-index-history__label\">{label}</dt>\n <dd className={`fg-index-history__value ${num.numeric}`}>\n <time dateTime={iso}>{DAY.format(new Date(iso))}</time>\n </dd>\n </div>\n );\n}\n\n/** The release the component first shipped in, and when its source file was created and last changed, read from\n * git. Nothing for a gallery, or for a source file git has never committed. */\nexport function IndexHistory() {\n const { gallery, dependencies } = useEnv();\n const history = gallery ? undefined : dependencies?.history;\n if (!history) return null;\n return (\n <dl className=\"fg-index-history\" aria-label=\"History\">\n <div className=\"fg-index-history__item\">\n <dt className=\"fg-index-history__label\">Since</dt>\n <dd className={`fg-index-history__value ${num.numeric}`}>{history.introduced ?? 'Unreleased'}</dd>\n </div>\n <HistoryDate label=\"Created\" iso={history.created} />\n <HistoryDate label=\"Modified\" iso={history.modified} />\n </dl>\n );\n}\n\nfunction StorySection({ story, variants }: { story: LoadedStory; variants: boolean }) {\n const env = useEnv();\n const headingId = useId();\n const description = env.descriptions[story.id];\n const gallery = !env.gallery && env.galleries?.includes(story.id);\n return (\n <section className=\"fg-index-story\" aria-labelledby={headingId}>\n <header className=\"fg-index-story__head\">\n <h2 id={headingId} className=\"fg-index-story__name\">\n {story.name}\n </h2>\n {gallery ? <GalleryBadge /> : null}\n <Button variant=\"secondary\" size=\"sm\" onClick={() => env.open(story.id)}>\n Open\n </Button>\n </header>\n {description ? <p className=\"fg-index-story__description\">{description}</p> : null}\n <IndexStory story={story} />\n {variants ? <IndexVariants story={story} /> : null}\n </section>\n );\n}\n\n/** Which of `stories` show their variants: the first of each set of controls. Stories of one CSF file share their\n * meta's controls, and the same rows under every story would only repeat. */\nfunction firstOfEachControlSet(stories: readonly LoadedStory[]): Set<string> {\n const seen = new Set<string>();\n const shown = new Set<string>();\n for (const story of stories) {\n const key = JSON.stringify(variantRows(story.config));\n if (seen.has(key)) continue;\n seen.add(key);\n shown.add(story.id);\n }\n return shown;\n}\n\n/** The generated page: the component's title and description, then each story, with the variants of the first of\n * each set of controls. */\nexport function DefaultIndex() {\n const env = useEnv();\n const withVariants = useMemo(() => firstOfEachControlSet(env.stories), [env.stories]);\n const segments = env.title.split('/');\n const name = segments.pop();\n const { library } = env;\n if (library !== undefined && segments[0] === library) segments.shift();\n return (\n <article className=\"fg-index\">\n <header className=\"fg-index__head\">\n {segments.length > 0 || library !== undefined ? (\n <p className=\"fg-index__path\">\n {library !== undefined ? <LibraryBadge library={library} className=\"fg-index__library\" /> : null}\n {segments.join(' / ')}\n </p>\n ) : null}\n <div className=\"fg-index__title-row\">\n <h1 className=\"fg-index__title\">{name}</h1>\n {env.gallery ? <GalleryBadge /> : null}\n </div>\n {env.description ? <p className=\"fg-index__description\">{env.description}</p> : null}\n <IndexHistory />\n <IndexDependencies />\n </header>\n {env.stories.map((story) => (\n <StorySection key={story.id} story={story} variants={withVariants.has(story.id)} />\n ))}\n </article>\n );\n}\n\n/** What a component's own index page is handed. */\nexport function indexContext(env: IndexEnv): IndexContext {\n return {\n title: env.title,\n ...(env.description === undefined ? {} : { description: env.description }),\n stories: env.stories,\n globals: env.globals,\n Story: IndexStory,\n Variants: IndexVariants,\n DefaultIndex,\n Dependencies: IndexDependencies,\n History: IndexHistory,\n gallery: env.gallery ?? false,\n open: env.open,\n };\n}\n\n/** The page itself: the component's own, or the generated one. */\nexport function IndexPage({ env, render }: { env: IndexEnv; render: ((ctx: IndexContext) => ReactNode) | null }) {\n return (\n <IndexEnvContext.Provider value={env}>{render ? render(indexContext(env)) : <DefaultIndex />}</IndexEnvContext.Provider>\n );\n}\n"]}
@@ -14,6 +14,9 @@ function storyNameFromExport(exportName) {
14
14
  return exportName.replace(/_/g, " ").replace(/-/g, " ").replace(/\./g, " ").replace(/([^\n])([A-Z])([a-z])/g, (_, a, b, c) => `${a} ${b}${c}`).replace(/([a-z])([A-Z])/g, (_, a, b) => `${a} ${b}`).replace(/([a-z])([0-9])/gi, (_, a, b) => `${a} ${b}`).replace(/([0-9])([a-z])/gi, (_, a, b) => `${a} ${b}`).replace(/(\s|^)(\w)/g, (_, a, b) => `${a}${b.toUpperCase()}`).replace(/ +/g, " ").trim();
15
15
  }
16
16
 
17
- export { sanitize, storyId, storyNameFromExport };
18
- //# sourceMappingURL=chunk-HRGPFQBW.js.map
19
- //# sourceMappingURL=chunk-HRGPFQBW.js.map
17
+ // src/csf/propArgTypes.ts
18
+ var PROP_ARG_TYPES_EXPORT = "__forgeArgTypes";
19
+
20
+ export { PROP_ARG_TYPES_EXPORT, sanitize, storyId, storyNameFromExport };
21
+ //# sourceMappingURL=chunk-ZAWXMUGZ.js.map
22
+ //# sourceMappingURL=chunk-ZAWXMUGZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/story/ids.ts","../src/csf/propArgTypes.ts"],"names":[],"mappings":";AAIO,SAAS,SAAS,IAAA,EAAsB;AAC7C,EAAA,OAAO,KACJ,WAAA,EAAY,CACZ,OAAA,CAAQ,iDAAA,EAAmD,GAAG,CAAA,CAC9D,OAAA,CAAQ,KAAA,EAAO,GAAG,EAClB,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,CACjB,OAAA,CAAQ,OAAO,EAAE,CAAA;AACtB;AAEA,SAAS,YAAA,CAAa,MAAc,IAAA,EAA+B;AACjE,EAAA,MAAM,SAAA,GAAY,SAAS,IAAI,CAAA;AAC/B,EAAA,IAAI,SAAA,KAAc,IAAI,MAAM,IAAI,MAAM,CAAA,QAAA,EAAW,IAAI,CAAA,EAAA,EAAK,IAAI,CAAA,uCAAA,CAAyC,CAAA;AACvG,EAAA,OAAO,SAAA;AACT;AAEO,SAAS,OAAA,CAAQ,OAAe,UAAA,EAA4B;AACjE,EAAA,OAAO,CAAA,EAAG,aAAa,KAAA,EAAO,MAAM,CAAC,CAAA,EAAA,EAAK,YAAA,CAAa,UAAA,EAAY,MAAM,CAAC,CAAA,CAAA;AAC5E;AAGO,SAAS,oBAAoB,UAAA,EAA4B;AAC9D,EAAA,OAAO,WACJ,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CACjB,QAAQ,IAAA,EAAM,GAAG,CAAA,CACjB,OAAA,CAAQ,OAAO,GAAG,CAAA,CAClB,QAAQ,wBAAA,EAA0B,CAAC,GAAG,CAAA,EAAW,CAAA,EAAW,CAAA,KAAc,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,GAAG,CAAC,CAAA,CAAE,EACzF,OAAA,CAAQ,iBAAA,EAAmB,CAAC,CAAA,EAAG,GAAW,CAAA,KAAc,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,EAAE,CAAA,CACnE,OAAA,CAAQ,kBAAA,EAAoB,CAAC,GAAG,CAAA,EAAW,CAAA,KAAc,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA,CAAE,CAAA,CACpE,OAAA,CAAQ,oBAAoB,CAAC,CAAA,EAAG,GAAW,CAAA,KAAc,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,CACpE,QAAQ,aAAA,EAAe,CAAC,GAAG,CAAA,EAAW,CAAA,KAAc,GAAG,CAAC,CAAA,EAAG,CAAA,CAAE,WAAA,EAAa,CAAA,CAAE,CAAA,CAC5E,QAAQ,KAAA,EAAO,GAAG,EAClB,IAAA,EAAK;AACV;;;ACnCO,IAAM,qBAAA,GAAwB","file":"chunk-ZAWXMUGZ.js","sourcesContent":["// sanitize, storyId and storyNameFromExport are ports of storybook/internal/csf (10.4.0)'s\n// sanitize, toId and storyNameFromExport; they must agree or links diverge.\n\n/** Lower-case; runs of the listed separators become one dash. Everything else, non-ASCII letters included, survives. */\nexport function sanitize(part: string): string {\n return part\n .toLowerCase()\n .replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\\-=?;:'\",.<>{}[\\]\\\\/]/gi, '-')\n .replace(/-+/g, '-')\n .replace(/^-+/, '')\n .replace(/-+$/, '');\n}\n\nfunction sanitizeSafe(part: string, kind: 'kind' | 'name'): string {\n const sanitized = sanitize(part);\n if (sanitized === '') throw new Error(`Invalid ${kind} '${part}', must include alphanumeric characters`);\n return sanitized;\n}\n\nexport function storyId(title: string, exportName: string): string {\n return `${sanitizeSafe(title, 'kind')}--${sanitizeSafe(exportName, 'name')}`;\n}\n\n/** `PrimaryButton` → `Primary Button`, `withIcon2` → `With Icon 2`. */\nexport function storyNameFromExport(exportName: string): string {\n return exportName\n .replace(/_/g, ' ')\n .replace(/-/g, ' ')\n .replace(/\\./g, ' ')\n .replace(/([^\\n])([A-Z])([a-z])/g, (_, a: string, b: string, c: string) => `${a} ${b}${c}`)\n .replace(/([a-z])([A-Z])/g, (_, a: string, b: string) => `${a} ${b}`)\n .replace(/([a-z])([0-9])/gi, (_, a: string, b: string) => `${a} ${b}`)\n .replace(/([0-9])([a-z])/gi, (_, a: string, b: string) => `${a} ${b}`)\n .replace(/(\\s|^)(\\w)/g, (_, a: string, b: string) => `${a}${b.toUpperCase()}`)\n .replace(/ +/g, ' ')\n .trim();\n}\n","/** The named export forge's vite plugin adds to a story module: argTypes read from the props of the meta's `component`. */\nexport const PROP_ARG_TYPES_EXPORT = '__forgeArgTypes';\n"]}
@@ -1,8 +1,8 @@
1
1
  import { LabMode, LabContribution, LabPage } from '@weasel-js/labkit';
2
2
  import { Theme } from '@weasel-js/theme';
3
3
  import { ControlRenderer } from '@weasel-js/labkit/config';
4
- import { G as Globals, F as FrameSetup } from './FrameController-BQjKhdwk.js';
5
- import { IconName } from '@weasel-js/ui';
4
+ import { G as Globals, F as FrameSetup } from './FrameController-UeTY7ubF.js';
5
+ import { IconName, StanceProps } from '@weasel-js/ui';
6
6
 
7
7
  /** One global the workshop's toolbar sets for every story, and a trial may pin for its own. */
8
8
  interface GlobalDeclaration {
@@ -42,8 +42,8 @@ interface Library {
42
42
  /** A stretch of path every story file of the library has, with forward slashes: `/packages/ui/`. */
43
43
  path: string;
44
44
  label: string;
45
- /** The CSS color the library's badge is toned with. Default: the badge's own muted tone. */
46
- tone?: string;
45
+ /** The tone of the library's badge, as a `<Badge>` takes one. Default: the badge's own muted tone. */
46
+ tone?: StanceProps['tone'];
47
47
  }
48
48
  /** A project's libraries, as the tree's package filter, the index page header, and Get Info ask about them. */
49
49
  interface Libraries {
@@ -52,7 +52,7 @@ interface Libraries {
52
52
  file: string;
53
53
  title: string;
54
54
  }): string;
55
- toneOf(label: string): string | undefined;
55
+ toneOf(label: string): StanceProps['tone'];
56
56
  }
57
57
 
58
58
  /** A shell config module: what the workshop adds to the lab. Only the workshop page imports it. */
@@ -1,9 +1,12 @@
1
- type Args = Record<string, unknown>;
2
1
  /**
3
2
  * Storybook's `useArgs`, writing through the trial's config. Stands in for `storybook/preview-api`.
4
3
  * A value a MessagePort would not deliver intact, such as a function, a React element or a class
5
4
  * instance, stays in the frame.
6
5
  */
7
- declare function useArgs(): [Args, (patch: Args) => void, (argNames?: string[]) => void];
6
+ declare function useArgs(): [
7
+ Record<string, unknown>,
8
+ (patch: Record<string, unknown>) => void,
9
+ (argNames?: string[]) => void
10
+ ];
8
11
 
9
12
  export { useArgs };
@@ -1,5 +1,5 @@
1
- import { ArgsContext, coverOf, isPortSafe } from '../chunk-5KI5YSQ5.js';
2
- import '../chunk-TXLWQFF6.js';
1
+ import { ArgsContext, coverOf, isPortSafe } from '../chunk-GB6PRJET.js';
2
+ import '../chunk-FL2MUPUL.js';
3
3
  import { useContext } from 'react';
4
4
 
5
5
  var sendable = (value) => {