@weasel-js/forge 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +33 -0
  2. package/dist/{FrameController-BspC9Zr5.d.ts → FrameController-HEcTM04H.d.ts} +24 -1
  3. package/dist/{chunk-DIOLWCH7.js → chunk-7GQI2PDH.js} +7 -63
  4. package/dist/chunk-7GQI2PDH.js.map +1 -0
  5. package/dist/{chunk-CSAXZIMV.js → chunk-DDDCZ6XW.js} +98 -11
  6. package/dist/chunk-DDDCZ6XW.js.map +1 -0
  7. package/dist/{chunk-OLWZURU3.js → chunk-ERRLEH6S.js} +10 -11
  8. package/dist/chunk-ERRLEH6S.js.map +1 -0
  9. package/dist/chunk-LLGBNJAZ.js +77 -0
  10. package/dist/chunk-LLGBNJAZ.js.map +1 -0
  11. package/dist/chunk-WEQSLPKT.js +9 -0
  12. package/dist/chunk-WEQSLPKT.js.map +1 -0
  13. package/dist/{chunk-JXIWZFD4.js → chunk-YKN3IAEX.js} +12 -10
  14. package/dist/chunk-YKN3IAEX.js.map +1 -0
  15. package/dist/{config-C5Vq5Kjj.d.ts → config-pDbcbGco.d.ts} +15 -3
  16. package/dist/csf/preview-api.js +1 -1
  17. package/dist/frame/index.css +63 -7
  18. package/dist/frame/index.css.map +1 -1
  19. package/dist/frame/index.d.ts +4 -2
  20. package/dist/frame/index.js +10 -3
  21. package/dist/frame/index.js.map +1 -1
  22. package/dist/index.d.ts +12 -4
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/shell/index.css +162 -3
  26. package/dist/shell/index.css.map +1 -1
  27. package/dist/shell/index.d.ts +34 -31
  28. package/dist/shell/index.js +166 -188
  29. package/dist/shell/index.js.map +1 -1
  30. package/dist/test/index.d.ts +1 -1
  31. package/dist/test/index.js +4 -3
  32. package/dist/test/index.js.map +1 -1
  33. package/dist/vite/index.js +344 -18
  34. package/dist/vite/index.js.map +1 -1
  35. package/package.json +10 -10
  36. package/dist/chunk-CSAXZIMV.js.map +0 -1
  37. package/dist/chunk-DIOLWCH7.js.map +0 -1
  38. package/dist/chunk-JXIWZFD4.js.map +0 -1
  39. package/dist/chunk-OLWZURU3.js.map +0 -1
@@ -1,15 +1,17 @@
1
- import { isIndexId, indexId, indexEntries, schemaFromDescription, openChannel, IndexPage } from '../chunk-CSAXZIMV.js';
2
- import { useTrialFrame, createTrialFrames, labGlobals, StoryGlobalsContext, TrialFramesContext, withGlobals, StoryTrial, storyConfig, GLOBALS_KEY, effectiveGlobals, useCssOverrides, TrialHost, shownOptions, isGlobalsPath } from '../chunk-DIOLWCH7.js';
3
- export { StoryGlobalsContext, StoryTrial, TrialFramesContext, TrialHost, useTrialFrame } from '../chunk-DIOLWCH7.js';
4
- import { loadStories, indexRenderOf } from '../chunk-OLWZURU3.js';
1
+ import { isIndexId, indexId, libraryOf, indexEntries, schemaFromDescription, LibraryBadge, openChannel, IndexPage } from '../chunk-DDDCZ6XW.js';
2
+ import { isGallery } from '../chunk-WEQSLPKT.js';
3
+ import { useTrialFrame, createTrialFrames, StoryGlobalsContext, TrialFramesContext, StoryTrial, useCssOverrides, TrialHost } from '../chunk-7GQI2PDH.js';
4
+ export { StoryGlobalsContext, StoryTrial, TrialFramesContext, TrialHost, useTrialFrame } from '../chunk-7GQI2PDH.js';
5
+ import { labGlobals, withGlobals, followApp, storyConfig, GLOBALS_KEY, effectiveGlobals, labOptions, isGlobalsPath } from '../chunk-LLGBNJAZ.js';
6
+ import { loadStories, indexRenderOf } from '../chunk-ERRLEH6S.js';
5
7
  import '../chunk-2GXKNXTJ.js';
6
8
  import '../chunk-HRGPFQBW.js';
7
- import { stableStringify, PORT_HANDOFF, FRAME_HELLO, PROTOCOL_VERSION } from '../chunk-JXIWZFD4.js';
9
+ import { stableStringify, PORT_HANDOFF, FRAME_HELLO, PROTOCOL_VERSION } from '../chunk-YKN3IAEX.js';
8
10
  import { useTrialId, Button, Lab, useLabContext, TrialIdContext, usePersistedState, Select, inferTokenType, ToggleBar as ToggleBar$1, Input, TokenPanel, refitScale } from '@weasel-js/labkit';
9
11
  import { createContext, useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect, useId, useContext } from 'react';
10
12
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
13
  import { createRoot } from 'react-dom/client';
12
- import { InfoIcon, ToggleBar, Checkbox, Dialog, Badge, DisclosureMark, Button as Button$1, TuneIcon, Callout } from '@weasel-js/ui';
14
+ import { InfoIcon, ToggleBar, Checkbox, Dialog, DisclosureMark, Button as Button$1, TuneIcon, Callout } from '@weasel-js/ui';
13
15
  import { TOKEN_MANIFEST, THEME_SOURCES, isByAxis } from '@weasel-js/theme';
14
16
  import { scale, httpThemeApi } from '@weasel-js/theme/engine';
15
17
  import { f, valueAtPath, isConfigBranch } from '@weasel-js/labkit/config';
@@ -105,6 +107,7 @@ function createStoryChanges() {
105
107
  }
106
108
  };
107
109
  }
110
+ var DependenciesContext = createContext(null);
108
111
  var SEED_REF = /^\{seeds\.([^}]+)\}$/;
109
112
  var RULE_KEYS = { factors: "factors", ratio: "ratio", step: "step" };
110
113
  function selectionFor(axes, globals) {
@@ -445,113 +448,6 @@ function breadcrumb(title, name) {
445
448
  const segments = [...title.split("/"), name].filter((segment, i) => i === 0 || segment.toLowerCase() !== "index");
446
449
  return segments.join(" > ");
447
450
  }
448
-
449
- // src/shell/tree/buildComponents.ts
450
- var LIBRARIES = [
451
- ["/packages/ui/", "ui"],
452
- ["/packages/labkit/", "labkit"],
453
- ["/packages/forge/", "forge"],
454
- ["/apps/draw/", "draw"],
455
- ["/apps/forge/", "forge"]
456
- ];
457
- function libraryOf(entry) {
458
- const file = entry.file.replaceAll("\\", "/");
459
- for (const [marker, label] of LIBRARIES) {
460
- if (file.includes(marker)) return label;
461
- }
462
- return entry.title.split("/")[0];
463
- }
464
- function buildComponents(index) {
465
- const byTitle = /* @__PURE__ */ new Map();
466
- for (const entry of index) {
467
- let row = byTitle.get(entry.title);
468
- if (!row) {
469
- const segments = entry.title.split("/");
470
- row = {
471
- path: entry.title,
472
- label: segments[segments.length - 1],
473
- library: libraryOf(entry),
474
- index: indexEntries([entry])[0],
475
- entries: []
476
- };
477
- byTitle.set(entry.title, row);
478
- }
479
- row.entries.push(entry);
480
- }
481
- const rows = [...byTitle.values()];
482
- disambiguate(rows);
483
- return rows.sort(
484
- (a, b) => a.label.localeCompare(b.label) || a.library.localeCompare(b.library) || a.path.localeCompare(b.path)
485
- );
486
- }
487
- function disambiguate(rows) {
488
- const byLabel = /* @__PURE__ */ new Map();
489
- for (const row of rows) {
490
- const key = `${row.library}\0${row.label}`;
491
- const group = byLabel.get(key);
492
- if (group) group.push(row);
493
- else byLabel.set(key, [row]);
494
- }
495
- for (const group of byLabel.values()) {
496
- if (group.length < 2) continue;
497
- for (const row of group) {
498
- const segments = row.path.split("/");
499
- for (let take = 2; take <= segments.length; take++) {
500
- row.label = segments.slice(-take).join("/");
501
- if (group.every((other) => other === row || !other.path.endsWith(`/${row.label}`))) break;
502
- }
503
- }
504
- }
505
- }
506
- function filterComponents(rows, query) {
507
- const needle = query.trim().toLowerCase();
508
- if (!needle) return [...rows];
509
- const out = [];
510
- for (const row of rows) {
511
- if (`${row.path}/${row.library}`.toLowerCase().includes(needle)) {
512
- out.push(row);
513
- continue;
514
- }
515
- const entries = row.entries.filter((entry) => entry.name.toLowerCase().includes(needle));
516
- if (entries.length > 0) out.push({ path: row.path, label: row.label, library: row.library, entries });
517
- }
518
- return out;
519
- }
520
- function componentNodes(rows) {
521
- const root = [];
522
- const folders = /* @__PURE__ */ new Map();
523
- for (const row of rows) {
524
- const labels = row.label.split("/");
525
- const title = row.path.split("/");
526
- let siblings = root;
527
- let tag = row.library;
528
- for (let i = 0; i < labels.length - 1; i++) {
529
- const path = title.slice(0, title.length - labels.length + i + 1).join("/");
530
- let folder = folders.get(path);
531
- if (!folder) {
532
- folder = { kind: "folder", label: labels[i], path, tag, children: [] };
533
- folders.set(path, folder);
534
- siblings.push(folder);
535
- }
536
- siblings = folder.children;
537
- tag = void 0;
538
- }
539
- siblings.push({
540
- kind: "folder",
541
- label: labels[labels.length - 1],
542
- path: row.path,
543
- tag,
544
- ...row.index ? { index: row.index } : {},
545
- children: row.entries.map((entry) => ({ kind: "story", entry }))
546
- });
547
- }
548
- return root;
549
- }
550
- function librariesIn(index) {
551
- return [...new Set(index.map(libraryOf))].sort((a, b) => a.localeCompare(b));
552
- }
553
-
554
- // src/shell/info/dossier.ts
555
451
  var GLOBALS = "$globals";
556
452
  function leaves(shape, prefix = "") {
557
453
  const out = [];
@@ -745,20 +641,21 @@ function GlobalSelect({ name, declaration, values, set, labeled = false }) {
745
641
  width: labeled ? "fill" : "fit",
746
642
  selectedKey: String(values[name]),
747
643
  onSelectionChange: (value) => set(name, value),
748
- options: shownOptions(declaration, values)
644
+ options: labOptions(declaration, values)
749
645
  }
750
646
  );
751
647
  }
752
648
  function GlobalsToolbar({ declarations }) {
753
649
  const [values, set] = useLabGlobals(declarations);
754
650
  const entries = Object.entries(declarations);
755
- return /* @__PURE__ */ jsx("div", { className: "fg-globals", role: "toolbar", "aria-label": "Globals", children: entries.filter(([, declaration]) => declaration.under === void 0).map(([key, declaration]) => {
756
- const nested = entries.filter(([, other]) => other.under === key);
757
- return /* @__PURE__ */ jsxs("div", { className: "fg-globals__item", children: [
758
- /* @__PURE__ */ jsx(GlobalSelect, { name: key, declaration, values, set }),
759
- nested.length > 0 ? /* @__PURE__ */ jsx(NestedGlobals, { label: declaration.label, nested, values, set }) : null
760
- ] }, key);
761
- }) });
651
+ const top = entries.filter(([, declaration]) => declaration.under === void 0);
652
+ return /* @__PURE__ */ jsxs("div", { className: "fg-globals", role: "toolbar", "aria-label": "Globals", children: [
653
+ top.map(([key, declaration]) => /* @__PURE__ */ jsx("div", { className: "fg-globals__item", children: /* @__PURE__ */ jsx(GlobalSelect, { name: key, declaration, values, set }) }, key)),
654
+ top.map(([key, declaration]) => {
655
+ const nested = entries.filter(([, other]) => other.under === key);
656
+ return nested.length > 0 ? /* @__PURE__ */ jsx(NestedGlobals, { label: declaration.label, nested, values, set }, key) : null;
657
+ })
658
+ ] });
762
659
  }
763
660
  function NestedGlobals({
764
661
  label,
@@ -802,7 +699,9 @@ function LabGlobals({
802
699
  onChange
803
700
  }) {
804
701
  const [values] = useLabGlobals(declarations);
805
- useEffect(() => onChange(values), [values, onChange]);
702
+ const { mode } = useLabContext();
703
+ const resolved = useMemo(() => followApp(declarations, values, { mode }), [declarations, values, mode]);
704
+ useEffect(() => onChange(resolved), [resolved, onChange]);
806
705
  return null;
807
706
  }
808
707
 
@@ -872,6 +771,17 @@ function sortFolder(nodes) {
872
771
  for (const folder of folders) folder.children = sortFolder(folder.children);
873
772
  return [...folders, ...nodes.filter((n) => n.kind === "story")];
874
773
  }
774
+ function foldGalleries(nodes) {
775
+ return nodes.map((node) => {
776
+ if (node.kind !== "folder") return node;
777
+ const children = foldGalleries(node.children);
778
+ const [only] = children;
779
+ if (!node.index && children.length === 1 && only?.kind === "folder" && only.path === `${node.path}/${only.label}` && only.index && isGallery(only.index)) {
780
+ return { ...only, label: node.label, tag: node.tag ?? only.tag };
781
+ }
782
+ return { ...node, children };
783
+ });
784
+ }
875
785
  function buildTree(index) {
876
786
  const root = [];
877
787
  const folders = /* @__PURE__ */ new Map();
@@ -908,9 +818,102 @@ function filterTree(nodes, query) {
908
818
  });
909
819
  return walk(nodes);
910
820
  }
821
+
822
+ // src/shell/tree/buildComponents.ts
823
+ function buildComponents(index) {
824
+ const byTitle = /* @__PURE__ */ new Map();
825
+ const pages = new Map(indexEntries(index).map((page) => [page.title, page]));
826
+ for (const entry of index) {
827
+ let row = byTitle.get(entry.title);
828
+ if (!row) {
829
+ const segments = entry.title.split("/");
830
+ row = {
831
+ path: entry.title,
832
+ label: segments[segments.length - 1],
833
+ library: libraryOf(entry),
834
+ index: pages.get(entry.title),
835
+ entries: []
836
+ };
837
+ byTitle.set(entry.title, row);
838
+ }
839
+ row.entries.push(entry);
840
+ }
841
+ const rows = [...byTitle.values()];
842
+ disambiguate(rows);
843
+ return rows.sort(
844
+ (a, b) => a.label.localeCompare(b.label) || a.library.localeCompare(b.library) || a.path.localeCompare(b.path)
845
+ );
846
+ }
847
+ function disambiguate(rows) {
848
+ const byLabel = /* @__PURE__ */ new Map();
849
+ for (const row of rows) {
850
+ const key = `${row.library}\0${row.label}`;
851
+ const group = byLabel.get(key);
852
+ if (group) group.push(row);
853
+ else byLabel.set(key, [row]);
854
+ }
855
+ for (const group of byLabel.values()) {
856
+ if (group.length < 2) continue;
857
+ for (const row of group) {
858
+ const segments = row.path.split("/");
859
+ for (let take = 2; take <= segments.length; take++) {
860
+ row.label = segments.slice(-take).join("/");
861
+ if (group.every((other) => other === row || !other.path.endsWith(`/${row.label}`))) break;
862
+ }
863
+ }
864
+ }
865
+ }
866
+ function filterComponents(rows, query) {
867
+ const needle = query.trim().toLowerCase();
868
+ if (!needle) return [...rows];
869
+ const out = [];
870
+ for (const row of rows) {
871
+ if (`${row.path}/${row.library}`.toLowerCase().includes(needle)) {
872
+ out.push(row);
873
+ continue;
874
+ }
875
+ const entries = row.entries.filter((entry) => entry.name.toLowerCase().includes(needle));
876
+ if (entries.length > 0) out.push({ path: row.path, label: row.label, library: row.library, entries });
877
+ }
878
+ return out;
879
+ }
880
+ function componentNodes(rows) {
881
+ const root = [];
882
+ const folders = /* @__PURE__ */ new Map();
883
+ for (const row of rows) {
884
+ const labels = row.label.split("/");
885
+ const title = row.path.split("/");
886
+ let siblings = root;
887
+ let tag = row.library;
888
+ for (let i = 0; i < labels.length - 1; i++) {
889
+ const path = title.slice(0, title.length - labels.length + i + 1).join("/");
890
+ let folder = folders.get(path);
891
+ if (!folder) {
892
+ folder = { kind: "folder", label: labels[i], path, tag, children: [] };
893
+ folders.set(path, folder);
894
+ siblings.push(folder);
895
+ }
896
+ siblings = folder.children;
897
+ tag = void 0;
898
+ }
899
+ siblings.push({
900
+ kind: "folder",
901
+ label: labels[labels.length - 1],
902
+ path: row.path,
903
+ tag,
904
+ ...row.index ? { index: row.index } : {},
905
+ children: row.entries.map((entry) => ({ kind: "story", entry }))
906
+ });
907
+ }
908
+ return foldGalleries(root);
909
+ }
910
+ function librariesIn(index) {
911
+ return [...new Set(index.map(libraryOf))].sort((a, b) => a.localeCompare(b));
912
+ }
911
913
  var VIEWS = [
912
914
  { value: "tree", label: "Tree" },
913
- { value: "components", label: "Components" }
915
+ { value: "components", label: "Components" },
916
+ { value: "gallery", label: "Gallery" }
914
917
  ];
915
918
  var keyOf = (node) => node.kind === "folder" ? `folder:${node.path}` : `story:${node.entry.id}`;
916
919
  function ancestorsOf(entry) {
@@ -923,14 +926,8 @@ function ancestorsOf(entry) {
923
926
  }
924
927
  return paths;
925
928
  }
926
- var LIBRARY_TONES = {
927
- ui: "color-mix(in oklab, var(--wzl-swatch-blue), var(--wzl-fg) 35%)",
928
- labkit: "color-mix(in oklab, var(--wzl-swatch-teal), var(--wzl-fg) 45%)",
929
- forge: "color-mix(in oklab, var(--wzl-swatch-amber), var(--wzl-fg) 40%)",
930
- draw: "color-mix(in oklab, var(--wzl-swatch-rose), var(--wzl-fg) 35%)"
931
- };
932
- function LibraryBadge({ library }) {
933
- return /* @__PURE__ */ jsx(Badge, { status: "muted", tone: LIBRARY_TONES[library], variant: "subtle", size: "sm", className: "fg-tree__tag", children: library });
929
+ function LibraryBadge2({ library }) {
930
+ return /* @__PURE__ */ jsx(LibraryBadge, { library, className: "fg-tree__tag" });
934
931
  }
935
932
  function StoryTree({ ctx, index }) {
936
933
  const headingId = useId();
@@ -943,11 +940,18 @@ function StoryTree({ ctx, index }) {
943
940
  const items = useRef(/* @__PURE__ */ new Map());
944
941
  const libraries = useMemo(() => librariesIn(index), [index]);
945
942
  const kept = useMemo(() => index.filter((entry) => !hidden[libraryOf(entry)]), [index, hidden]);
946
- const tree = useMemo(() => buildTree(kept), [kept]);
947
- const components = useMemo(() => buildComponents(kept), [kept]);
943
+ const [galleryEntries, rest] = useMemo(() => {
944
+ const yes = [];
945
+ const no = [];
946
+ for (const entry of kept) (isGallery(entry) ? yes : no).push(entry);
947
+ return [yes, no];
948
+ }, [kept]);
949
+ const tree = useMemo(() => buildTree(rest), [rest]);
950
+ const components = useMemo(() => buildComponents(rest), [rest]);
951
+ const galleries = useMemo(() => buildComponents(galleryEntries), [galleryEntries]);
948
952
  const shown = useMemo(
949
- () => view === "components" ? componentNodes(filterComponents(components, query)) : filterTree(tree, query),
950
- [view, components, tree, query]
953
+ () => view === "tree" ? filterTree(tree, query) : componentNodes(filterComponents(view === "gallery" ? galleries : components, query)),
954
+ [view, components, galleries, tree, query]
951
955
  );
952
956
  const routable = useMemo(() => [...kept, ...indexEntries(kept)], [kept]);
953
957
  const routed = routable.find((entry) => entry.id === route);
@@ -989,7 +993,7 @@ function StoryTree({ ctx, index }) {
989
993
  return;
990
994
  }
991
995
  if (folds[node.path] === false) {
992
- setFolds(({ [node.path]: _dropped, ...rest }) => rest);
996
+ setFolds(({ [node.path]: _dropped, ...rest2 }) => rest2);
993
997
  }
994
998
  activate(node.index, another);
995
999
  };
@@ -1080,7 +1084,7 @@ function StoryTree({ ctx, index }) {
1080
1084
  }
1081
1085
  ),
1082
1086
  /* @__PURE__ */ jsx("span", { className: "fg-tree__label", children: node.label }),
1083
- node.tag ? /* @__PURE__ */ jsx(LibraryBadge, { library: node.tag }) : null
1087
+ node.tag ? /* @__PURE__ */ jsx(LibraryBadge2, { library: node.tag }) : null
1084
1088
  ]
1085
1089
  }
1086
1090
  ),
@@ -1106,7 +1110,7 @@ function StoryTree({ ctx, index }) {
1106
1110
  },
1107
1111
  children: [
1108
1112
  /* @__PURE__ */ jsx("span", { className: "fg-tree__label", children: node.label ?? entry.name }),
1109
- node.tag ? /* @__PURE__ */ jsx(LibraryBadge, { library: node.tag }) : null
1113
+ node.tag ? /* @__PURE__ */ jsx(LibraryBadge2, { library: node.tag }) : null
1110
1114
  ]
1111
1115
  },
1112
1116
  keyOf(node)
@@ -1137,7 +1141,7 @@ function StoryTree({ ctx, index }) {
1137
1141
  {
1138
1142
  isSelected: !hidden[library],
1139
1143
  onChange: (on) => setHidden((prev) => ({ ...prev, [library]: !on })),
1140
- children: /* @__PURE__ */ jsx(LibraryBadge, { library })
1144
+ children: /* @__PURE__ */ jsx(LibraryBadge2, { library })
1141
1145
  },
1142
1146
  library
1143
1147
  ))
@@ -1202,6 +1206,9 @@ function createAnswerBook() {
1202
1206
  function IndexTrial({ bundle, setup, config }) {
1203
1207
  const lab = useLabContext();
1204
1208
  const trialId = useContext(TrialIdContext);
1209
+ const graph = useContext(DependenciesContext);
1210
+ const gallery = isGallery(bundle);
1211
+ const dependencies = gallery ? void 0 : graph?.[bundle.title];
1205
1212
  const open = (id) => {
1206
1213
  if (!trialId || !lab.instruments.some((instrument) => instrument.name === id)) return;
1207
1214
  lab.swapTrial(trialId, id);
@@ -1210,9 +1217,13 @@ function IndexTrial({ bundle, setup, config }) {
1210
1217
  const render = (globals) => {
1211
1218
  const env = {
1212
1219
  title: bundle.title,
1220
+ library: bundle.library,
1213
1221
  ...bundle.description === void 0 ? {} : { description: bundle.description },
1214
1222
  stories: bundle.stories,
1215
1223
  descriptions: bundle.descriptions,
1224
+ gallery,
1225
+ galleries: bundle.galleries,
1226
+ ...dependencies ? { dependencies } : {},
1216
1227
  globals,
1217
1228
  decorators: setup.decorators ?? [],
1218
1229
  open,
@@ -1223,26 +1234,8 @@ function IndexTrial({ bundle, setup, config }) {
1223
1234
  };
1224
1235
  return /* @__PURE__ */ jsx(TrialHost, { layout: "fullscreen", setup, config, children: render });
1225
1236
  }
1226
- function annotationsOn(frames) {
1227
- return {
1228
- targets: (_state, _config, trial) => {
1229
- const ref = frames.hostRef(trial.id);
1230
- const frame = frames.get(trial.id);
1231
- const box = frame.size ?? { width: ref.current?.clientWidth ?? 0, height: ref.current?.clientHeight ?? 0 };
1232
- const capture = frame.capture;
1233
- return [
1234
- {
1235
- id: "story",
1236
- ref,
1237
- content: { w: Math.max(1, box.width), h: Math.max(1, box.height) },
1238
- ...capture ? { base: () => capture() } : {}
1239
- }
1240
- ];
1241
- }
1242
- };
1243
- }
1244
1237
  function documentInstrument(options) {
1245
- const { entry, loaded, setup, globals = {}, frames } = options;
1238
+ const { entry, loaded, setup, globals = {} } = options;
1246
1239
  const schema = loaded.kind === "story" ? loaded.story.config : f.schema({});
1247
1240
  const config = withGlobals(schema, globals);
1248
1241
  const initialState = loaded.kind === "story" ? loaded.story.initialState : null;
@@ -1253,7 +1246,6 @@ function documentInstrument(options) {
1253
1246
  defaultConfig: () => config.defaults(),
1254
1247
  initialState: (c) => initialState?.(c) ?? null,
1255
1248
  render: (ctx) => loaded.kind === "story" ? /* @__PURE__ */ jsx(StoryTrial, { story: loaded.story, setup, ctx }) : /* @__PURE__ */ jsx(IndexTrial, { bundle: loaded.bundle, setup, config: ctx.config }),
1256
- ...frames ? { annotations: annotationsOn(frames) } : {},
1257
1249
  ...loaded.kind === "story" && loaded.story.viewport ? { stage: { size: { width: loaded.story.viewport.width, height: loaded.story.viewport.height } } } : {}
1258
1250
  };
1259
1251
  }
@@ -1559,26 +1551,8 @@ function FrameView(props) {
1559
1551
  }
1560
1552
  );
1561
1553
  }
1562
- function annotationsOn2(frames) {
1563
- return {
1564
- targets: (_state, _config, trial) => {
1565
- const ref = frames.hostRef(trial.id);
1566
- const frame = frames.get(trial.id);
1567
- const box = frame.size ?? { width: ref.current?.clientWidth ?? 0, height: ref.current?.clientHeight ?? 0 };
1568
- const capture = frame.capture;
1569
- return [
1570
- {
1571
- id: "story",
1572
- ref,
1573
- content: { w: Math.max(1, box.width), h: Math.max(1, box.height) },
1574
- ...capture ? { base: () => capture() } : {}
1575
- }
1576
- ];
1577
- }
1578
- };
1579
- }
1580
1554
  function storyInstrument(options) {
1581
- const { entry, ready, answers, frameUrl, onReady, globals = {}, frames } = options;
1555
+ const { entry, ready, answers, frameUrl, onReady, globals = {} } = options;
1582
1556
  const config = withGlobals(
1583
1557
  ready ? schemaFromDescription(ready.schema, answers) : f.schema({}),
1584
1558
  globals
@@ -1601,7 +1575,6 @@ function storyInstrument(options) {
1601
1575
  ctx
1602
1576
  }
1603
1577
  ),
1604
- ...frames ? { annotations: annotationsOn2(frames) } : {},
1605
1578
  ...ready?.viewport ? { stage: { size: { width: ready.viewport.width, height: ready.viewport.height } } } : {}
1606
1579
  };
1607
1580
  }
@@ -1612,7 +1585,7 @@ var NO_SETUP = {};
1612
1585
  var pruned = (map, ids) => [...map.keys()].every((id) => ids.has(id)) ? map : new Map([...map].filter(([id]) => ids.has(id)));
1613
1586
  var toError = (error) => error instanceof Error ? error : new Error(String(error));
1614
1587
  function useStoryRegistry(index, options) {
1615
- const { frameUrl, globals = NO_GLOBALS2, frames, importers, setup = NO_SETUP, load = loadStories } = options;
1588
+ const { frameUrl, globals = NO_GLOBALS2, importers, setup = NO_SETUP, load = loadStories } = options;
1616
1589
  const [readies, setReadies] = useState(() => /* @__PURE__ */ new Map());
1617
1590
  const [loaded, setLoaded] = useState(() => /* @__PURE__ */ new Map());
1618
1591
  const [faults, setFaults] = useState(() => /* @__PURE__ */ new Map());
@@ -1677,7 +1650,10 @@ function useStoryRegistry(index, options) {
1677
1650
  kind: "index",
1678
1651
  bundle: {
1679
1652
  title: entry.title,
1653
+ library: libraryOf(entry),
1680
1654
  ...entry.componentDescription === void 0 ? {} : { description: entry.componentDescription },
1655
+ ...entry.tags === void 0 ? {} : { tags: entry.tags },
1656
+ galleries: entries.filter(isGallery).map((e) => e.id),
1681
1657
  stories,
1682
1658
  descriptions: Object.fromEntries(entries.flatMap((e) => e.description ? [[e.id, e.description]] : [])),
1683
1659
  render: mods.map(indexRenderOf).find((render) => render !== null) ?? null
@@ -1731,26 +1707,25 @@ function useStoryRegistry(index, options) {
1731
1707
  const answers = previous.books.get(entry.id) ?? createAnswerBook();
1732
1708
  books.set(entry.id, answers);
1733
1709
  const held = previous.built.get(entry.id);
1734
- const kept = held && held.entryKey === entryKey && held.ready === ready && held.loaded === had && held.fault === fault && held.frameUrl === frameUrl && held.globals === globals && held.frames === frames && held.setup === setup && held.inDocument === inDocument && held.generation === generation && held.revision === revision ? held : {
1710
+ const kept = held && held.entryKey === entryKey && held.ready === ready && held.loaded === had && held.fault === fault && held.frameUrl === frameUrl && held.globals === globals && held.setup === setup && held.inDocument === inDocument && held.generation === generation && held.revision === revision ? held : {
1735
1711
  entryKey,
1736
1712
  ready,
1737
1713
  loaded: had,
1738
1714
  fault,
1739
1715
  frameUrl,
1740
1716
  globals,
1741
- frames,
1742
1717
  setup,
1743
1718
  inDocument,
1744
1719
  generation,
1745
1720
  revision,
1746
- instrument: !inDocument ? storyInstrument({ entry, ready, answers, frameUrl, onReady, globals, ...frames ? { frames } : {} }) : had ? documentInstrument({ entry, loaded: had, setup, globals, ...frames ? { frames } : {} }) : pendingInstrument({ entry, globals, load: request, generation, ...fault ? { fault } : {} })
1721
+ instrument: !inDocument ? storyInstrument({ entry, ready, answers, frameUrl, onReady, globals }) : had ? documentInstrument({ entry, loaded: had, setup, globals }) : pendingInstrument({ entry, globals, load: request, generation, ...fault ? { fault } : {} })
1747
1722
  };
1748
1723
  built.set(entry.id, kept);
1749
1724
  return kept.instrument;
1750
1725
  });
1751
1726
  const unchanged = list.length === previous.list.length && list.every((i, n) => i === previous.list[n]);
1752
1727
  return { built, books, list: unchanged ? previous.list : list };
1753
- }, [index, readies, loaded, faults, generations, revisions, frameUrl, globals, frames, setup, importers, onReady, request]);
1728
+ }, [index, readies, loaded, faults, generations, revisions, frameUrl, globals, setup, importers, onReady, request]);
1754
1729
  useLayoutEffect(() => {
1755
1730
  committed.current = cache;
1756
1731
  }, [cache]);
@@ -1802,7 +1777,7 @@ function useInfoShortcut(open) {
1802
1777
  return () => window.removeEventListener("keydown", onKeyDown);
1803
1778
  }, [open]);
1804
1779
  }
1805
- function Workshop({ index, frameUrl, importers, setup, changes, config, stories = [], storageKey, storage }) {
1780
+ function Workshop({ index, frameUrl, importers, setup, changes, config, stories = [], storageKey, storage, dependencies }) {
1806
1781
  const declarations = config?.globals ?? NO_DECLARATIONS;
1807
1782
  const [frames] = useState(createTrialFrames);
1808
1783
  const [pool, setPool] = useState(null);
@@ -1820,7 +1795,6 @@ function Workshop({ index, frameUrl, importers, setup, changes, config, stories
1820
1795
  const registry = useStoryRegistry(entries, {
1821
1796
  frameUrl,
1822
1797
  globals: declarations,
1823
- frames,
1824
1798
  ...importers ? { importers } : {},
1825
1799
  ...setup ? { setup } : {}
1826
1800
  });
@@ -1857,7 +1831,7 @@ function Workshop({ index, frameUrl, importers, setup, changes, config, stories
1857
1831
  stories.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "fg-empty__globs", "aria-label": "Story globs", children: stories.map((glob) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: glob }) }, glob)) }) : null
1858
1832
  ] });
1859
1833
  }
1860
- return /* @__PURE__ */ jsx(StoryGlobalsContext.Provider, { value: labValues, children: /* @__PURE__ */ jsx(FramePoolContext.Provider, { value: pool, children: /* @__PURE__ */ jsx(TrialFramesContext.Provider, { value: frames, children: /* @__PURE__ */ jsxs(
1834
+ return /* @__PURE__ */ jsx(StoryGlobalsContext.Provider, { value: labValues, children: /* @__PURE__ */ jsx(DependenciesContext.Provider, { value: dependencies ?? null, children: /* @__PURE__ */ jsx(FramePoolContext.Provider, { value: pool, children: /* @__PURE__ */ jsx(TrialFramesContext.Provider, { value: frames, children: /* @__PURE__ */ jsxs(
1861
1835
  Lab,
1862
1836
  {
1863
1837
  title: "weaselforge",
@@ -1886,7 +1860,7 @@ function Workshop({ index, frameUrl, importers, setup, changes, config, stories
1886
1860
  /* @__PURE__ */ jsx(LabGlobals, { declarations, onChange: reportLabValues })
1887
1861
  ]
1888
1862
  }
1889
- ) }) }) });
1863
+ ) }) }) }) });
1890
1864
  }
1891
1865
  function mountWorkshop({ container, ...props }) {
1892
1866
  const target = container ?? document.getElementById("root");
@@ -1905,6 +1879,10 @@ function mountWorkshop({ container, ...props }) {
1905
1879
  root.render(/* @__PURE__ */ jsx(Workshop, { ...current }));
1906
1880
  },
1907
1881
  reloadStory: (file) => changes.emit(file),
1882
+ setDependencies(dependencies) {
1883
+ current = { ...current, dependencies };
1884
+ root.render(/* @__PURE__ */ jsx(Workshop, { ...current }));
1885
+ },
1908
1886
  unmount: () => root.unmount()
1909
1887
  };
1910
1888
  }