@weasel-js/forge 1.12.0 → 1.13.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 (46) hide show
  1. package/README.md +20 -5
  2. package/dist/{FrameController-CdnaIo4C.d.ts → FrameController-DgfVaENb.d.ts} +15 -3
  3. package/dist/{chunk-GH5RE5X5.js → chunk-2ZBZRBHI.js} +2 -2
  4. package/dist/{chunk-GH5RE5X5.js.map → chunk-2ZBZRBHI.js.map} +1 -1
  5. package/dist/{chunk-KEQBGDUZ.js → chunk-7XJNVJB5.js} +3 -3
  6. package/dist/{chunk-KEQBGDUZ.js.map → chunk-7XJNVJB5.js.map} +1 -1
  7. package/dist/{chunk-LTTEILXY.js → chunk-COT4I347.js} +3 -3
  8. package/dist/{chunk-LTTEILXY.js.map → chunk-COT4I347.js.map} +1 -1
  9. package/dist/{chunk-WMGEO5M6.js → chunk-GHPMNT2A.js} +83 -13
  10. package/dist/chunk-GHPMNT2A.js.map +1 -0
  11. package/dist/chunk-RVJHUY7W.js +60 -0
  12. package/dist/chunk-RVJHUY7W.js.map +1 -0
  13. package/dist/chunk-VUPN73JP.js +16 -0
  14. package/dist/chunk-VUPN73JP.js.map +1 -0
  15. package/dist/{chunk-ATI7FYJ7.js → chunk-WFT5IOHX.js} +98 -63
  16. package/dist/chunk-WFT5IOHX.js.map +1 -0
  17. package/dist/{chunk-YDLRSEUN.js → chunk-XIBKYSRU.js} +5 -4
  18. package/dist/chunk-XIBKYSRU.js.map +1 -0
  19. package/dist/{config-Mg05Ja9r.d.ts → config-6fWf87Tt.d.ts} +3 -21
  20. package/dist/csf/preview-api.js +2 -2
  21. package/dist/frame/index.css +26 -0
  22. package/dist/frame/index.css.map +1 -1
  23. package/dist/frame/index.d.ts +14 -8
  24. package/dist/frame/index.js +109 -75
  25. package/dist/frame/index.js.map +1 -1
  26. package/dist/index.d.ts +29 -5
  27. package/dist/index.js +3 -3
  28. package/dist/library-CdTj-hFp.d.ts +21 -0
  29. package/dist/{mountFrame-Ds3QLnBF.d.ts → mountFrame-Bs7u1ro-.d.ts} +1 -1
  30. package/dist/shell/index.css +33 -5
  31. package/dist/shell/index.css.map +1 -1
  32. package/dist/shell/index.d.ts +6 -5
  33. package/dist/shell/index.js +190 -108
  34. package/dist/shell/index.js.map +1 -1
  35. package/dist/test/index.css +2 -3
  36. package/dist/test/index.css.map +1 -1
  37. package/dist/test/index.d.ts +1 -1
  38. package/dist/test/index.js +4 -4
  39. package/dist/vite/index.js +78 -16
  40. package/dist/vite/index.js.map +1 -1
  41. package/package.json +9 -9
  42. package/dist/chunk-ATI7FYJ7.js.map +0 -1
  43. package/dist/chunk-WEQSLPKT.js +0 -9
  44. package/dist/chunk-WEQSLPKT.js.map +0 -1
  45. package/dist/chunk-WMGEO5M6.js.map +0 -1
  46. package/dist/chunk-YDLRSEUN.js.map +0 -1
@@ -13,9 +13,8 @@
13
13
  transform-origin: 0 0;
14
14
  transform: translate(var(--fg-lens-copy-x), var(--fg-lens-copy-y)) scale(var(--fg-lens-copy-f));
15
15
  }
16
- .fg-lens-copy > .fg-story,
17
16
  .fg-lens-copy > .fg-frame-host {
18
- background: var(--wzl-bg);
17
+ background: var(--wzl-surface);
19
18
  }
20
19
  .fg-lens-pixels {
21
20
  position: absolute;
@@ -34,7 +33,7 @@
34
33
  text-align: center;
35
34
  font-size: 11px;
36
35
  color: var(--wzl-fg-muted);
37
- background: var(--wzl-bg);
36
+ background: var(--wzl-surface);
38
37
  }
39
38
  .fg-lens-empty[hidden] {
40
39
  display: none;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/shell/loupe/loupe.css"],"sourcesContent":["/* A Live lens's own box inside its slot: the copy is portaled into it, and the message beneath it shows when no copy is. */\n.fg-lens-live {\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n/* A second render of a story, at its host's own size, scaled about the reticle's point onto the slot's center. */\n.fg-lens-copy {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--fg-lens-copy-w);\n height: var(--fg-lens-copy-h);\n transform-origin: 0 0;\n transform: translate(var(--fg-lens-copy-x), var(--fg-lens-copy-y)) scale(var(--fg-lens-copy-f));\n}\n\n/* Painted in the copy's own mode, so a transparent story does not show the lab through the lens. */\n.fg-lens-copy > .fg-story,\n.fg-lens-copy > .fg-frame-host {\n background: var(--wzl-bg);\n}\n\n/* A Pixels lens's capture, enlarged nearest-neighbor: the browser scaling the canvas to the screen keeps it so. */\n.fg-lens-pixels {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n image-rendering: pixelated;\n}\n\n/* What a lens says in place of its story: nothing under the reticle, or why it cannot show it. */\n.fg-lens-empty {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wzl-space-4);\n text-align: center;\n font-size: 11px;\n color: var(--wzl-fg-muted);\n background: var(--wzl-bg);\n}\n\n.fg-lens-empty[hidden] {\n display: none;\n}\n\n/* Above the lens layer, in the lab body's corner. */\n.fg-loupe-hint {\n position: absolute;\n left: var(--wzl-space-8);\n bottom: var(--wzl-space-8);\n z-index: 4;\n}\n\n/* A token in the Token readout: the readouts take no pointer, so the link takes it back. */\n.fg-lens-token__link {\n padding: 0;\n border: 0;\n font: inherit;\n color: inherit;\n text-decoration: underline;\n background: none;\n cursor: pointer;\n pointer-events: auto;\n}\n"],"mappings":";AACA,CAAC;AACC,YAAU;AACV,SAAO;AACP,YAAU;AACZ;AAGA,CAAC;AACC,YAAU;AACV,OAAK;AACL,QAAM;AACN,SAAO,IAAI;AACX,UAAQ,IAAI;AACZ,oBAAkB,EAAE;AACpB,aAAW,UAAU,IAAI,iBAAiB,EAAE,IAAI,mBAAmB,MAAM,IAAI;AAC/E;AAGA,CAXC,aAWa,EAAE,CAAC;AACjB,CAZC,aAYa,EAAE,CAAC;AACf,cAAY,IAAI;AAClB;AAGA,CAAC;AACC,YAAU;AACV,SAAO;AACP,SAAO;AACP,UAAQ;AACR,mBAAiB;AACnB;AAGA,CAAC;AACC,YAAU;AACV,SAAO;AACP,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,WAAS,IAAI;AACb,cAAY;AACZ,aAAW;AACX,SAAO,IAAI;AACX,cAAY,IAAI;AAClB;AAEA,CAbC,aAaa,CAAC;AACb,WAAS;AACX;AAGA,CAAC;AACC,YAAU;AACV,QAAM,IAAI;AACV,UAAQ,IAAI;AACZ,WAAS;AACX;AAGA,CAAC;AACC,WAAS;AACT,UAAQ;AACR,QAAM;AACN,SAAO;AACP,mBAAiB;AACjB,cAAY;AACZ,UAAQ;AACR,kBAAgB;AAClB;","names":[]}
1
+ {"version":3,"sources":["../../src/shell/loupe/loupe.css"],"sourcesContent":["/* A Live lens's own box inside its slot: the copy is portaled into it, and the message beneath it shows when no copy is. */\n.fg-lens-live {\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n/* A second render of a story, at its host's own size, scaled about the reticle's point onto the slot's center. */\n.fg-lens-copy {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--fg-lens-copy-w);\n height: var(--fg-lens-copy-h);\n transform-origin: 0 0;\n transform: translate(var(--fg-lens-copy-x), var(--fg-lens-copy-y)) scale(var(--fg-lens-copy-f));\n}\n\n/* As `.fg-story` paints an in-document host: in the copy's mode, which its globals apply to the host. */\n.fg-lens-copy > .fg-frame-host {\n background: var(--wzl-surface);\n}\n\n/* A Pixels lens's capture, enlarged nearest-neighbor: the browser scaling the canvas to the screen keeps it so. */\n.fg-lens-pixels {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n image-rendering: pixelated;\n}\n\n/* What a lens says in place of its story: nothing under the reticle, or why it cannot show it. */\n.fg-lens-empty {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wzl-space-4);\n text-align: center;\n font-size: 11px;\n color: var(--wzl-fg-muted);\n background: var(--wzl-surface);\n}\n\n.fg-lens-empty[hidden] {\n display: none;\n}\n\n/* Above the lens layer, in the lab body's corner. */\n.fg-loupe-hint {\n position: absolute;\n left: var(--wzl-space-8);\n bottom: var(--wzl-space-8);\n z-index: 4;\n}\n\n/* A token in the Token readout: the readouts take no pointer, so the link takes it back. */\n.fg-lens-token__link {\n padding: 0;\n border: 0;\n font: inherit;\n color: inherit;\n text-decoration: underline;\n background: none;\n cursor: pointer;\n pointer-events: auto;\n}\n"],"mappings":";AACA,CAAC;AACC,YAAU;AACV,SAAO;AACP,YAAU;AACZ;AAGA,CAAC;AACC,YAAU;AACV,OAAK;AACL,QAAM;AACN,SAAO,IAAI;AACX,UAAQ,IAAI;AACZ,oBAAkB,EAAE;AACpB,aAAW,UAAU,IAAI,iBAAiB,EAAE,IAAI,mBAAmB,MAAM,IAAI;AAC/E;AAGA,CAXC,aAWa,EAAE,CAAC;AACf,cAAY,IAAI;AAClB;AAGA,CAAC;AACC,YAAU;AACV,SAAO;AACP,SAAO;AACP,UAAQ;AACR,mBAAiB;AACnB;AAGA,CAAC;AACC,YAAU;AACV,SAAO;AACP,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,WAAS,IAAI;AACb,cAAY;AACZ,aAAW;AACX,SAAO,IAAI;AACX,cAAY,IAAI;AAClB;AAEA,CAbC,aAaa,CAAC;AACb,WAAS;AACX;AAGA,CAAC;AACC,YAAU;AACV,QAAM,IAAI;AACV,UAAQ,IAAI;AACZ,WAAS;AACX;AAGA,CAAC;AACC,WAAS;AACT,UAAQ;AACR,QAAM;AACN,SAAO;AACP,mBAAiB;AACjB,cAAY;AACZ,UAAQ;AACR,kBAAgB;AAClB;","names":[]}
@@ -1,4 +1,4 @@
1
- import { F as FrameSetup } from '../FrameController-CdnaIo4C.js';
1
+ import { F as FrameSetup } from '../FrameController-DgfVaENb.js';
2
2
  import '@weasel-js/icons';
3
3
  import '@weasel-js/labkit/config';
4
4
  import 'react';
@@ -1,10 +1,10 @@
1
- import { StoryTrial } from '../chunk-YDLRSEUN.js';
1
+ import { StoryTrial } from '../chunk-XIBKYSRU.js';
2
2
  import '../chunk-3BAM6M26.js';
3
- import { loadStories } from '../chunk-WMGEO5M6.js';
3
+ import { loadStories } from '../chunk-GHPMNT2A.js';
4
4
  import '../chunk-L5XM5VKB.js';
5
5
  import '../chunk-5WS67HMU.js';
6
- import '../chunk-KEQBGDUZ.js';
7
- import '../chunk-GH5RE5X5.js';
6
+ import '../chunk-7XJNVJB5.js';
7
+ import '../chunk-2ZBZRBHI.js';
8
8
  import { withValueAtPath } from '@weasel-js/labkit/config';
9
9
  import { useState, useEffect } from 'react';
10
10
  import { createRoot } from 'react-dom/client';
@@ -1,5 +1,6 @@
1
1
  import { CAPTURE_PAGES, DEFAULT_TITLE, CAPTURE_PATH, parsePayload, messageOf } from '../chunk-ORMMZ5PV.js';
2
- import { isGallery } from '../chunk-WEQSLPKT.js';
2
+ import { byComponent } from '../chunk-RVJHUY7W.js';
3
+ import { isGallery } from '../chunk-VUPN73JP.js';
3
4
  import { PROP_ARG_TYPES_EXPORT, storyNameFromExport, storyId } from '../chunk-5WS67HMU.js';
4
5
  import { readFileSync, mkdtempSync, existsSync, mkdirSync, writeFileSync, globSync, statSync, watch, rmSync } from 'fs';
5
6
  import { resolve, sep, relative, join, dirname, basename, matchesGlob, posix } from 'path';
@@ -1022,36 +1023,89 @@ function componentProps(tsm, checker, source) {
1022
1023
  }
1023
1024
  function propTable(tsm, checker, props, at, skipped) {
1024
1025
  const argTypes = {};
1025
- const sources = /* @__PURE__ */ new Set();
1026
+ const reading = { tsm, checker, at, skipped, sources: /* @__PURE__ */ new Set() };
1026
1027
  for (const prop2 of checker.getPropertiesOfType(checker.getApparentType(props))) {
1027
- const files = (prop2.getDeclarations() ?? []).map((declaration) => declaration.getSourceFile().fileName);
1028
+ const files = declaredIn(prop2);
1028
1029
  if (files.length > 0 && files.every(skipped)) continue;
1029
1030
  const argType = controlFor(
1030
- tsm,
1031
+ reading,
1031
1032
  checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(prop2, at)),
1032
1033
  () => writtenOrder(tsm, checker, prop2)
1033
1034
  );
1034
1035
  if (!argType) continue;
1035
1036
  const description = tsm.displayPartsToString(prop2.getDocumentationComment(checker)).replace(/\s+/g, " ").trim();
1036
1037
  argTypes[prop2.getName()] = description ? { ...argType, description } : argType;
1037
- for (const file of files) if (!/[\\/]node_modules[\\/]/.test(file)) sources.add(file);
1038
+ record(reading, files);
1038
1039
  }
1039
- return { argTypes, sources: [...sources] };
1040
+ return { argTypes, sources: [...reading.sources] };
1040
1041
  }
1041
- function controlFor(tsm, type, written) {
1042
- const { TypeFlags } = tsm;
1042
+ var declaredIn = (symbol) => (symbol.getDeclarations() ?? []).map((declaration) => declaration.getSourceFile().fileName);
1043
+ var IN_PACKAGES = /[\\/]node_modules[\\/]/;
1044
+ function record({ sources }, files) {
1045
+ for (const file of files) if (!IN_PACKAGES.test(file)) sources.add(file);
1046
+ }
1047
+ function controlFor(reading, type, written) {
1048
+ const { TypeFlags } = reading.tsm;
1043
1049
  const parts = type.isUnion() ? type.types : [type];
1044
- const every = (flags) => parts.every((part) => part.flags & flags);
1045
- if (every(TypeFlags.BooleanLike)) return { control: { type: "boolean" } };
1046
- if (type.flags & TypeFlags.String) return { control: { type: "text" } };
1050
+ if (parts.every((part) => part.flags & TypeFlags.BooleanLike)) return { control: { type: "boolean" } };
1051
+ if (parts.some((part) => part.flags & TypeFlags.String)) return { control: { type: "text" } };
1047
1052
  if (type.flags & TypeFlags.Number) return { control: { type: "number" } };
1048
- if (parts.length > 1 && every(TypeFlags.StringLiteral)) {
1049
- const options = parts.map((part) => part.value);
1053
+ const options = literalsOf(reading, parts);
1054
+ if (options.length > 1) {
1050
1055
  const order = written();
1051
1056
  const same = order?.length === options.length && options.every((option) => order.includes(option));
1052
1057
  return { options: same ? order : options };
1053
1058
  }
1054
- return null;
1059
+ const shape = shapeOf(reading, type, 0);
1060
+ return shape && shape.name !== "enum" && !(shape.name in SCALARS) ? { control: "object", type: shape } : null;
1061
+ }
1062
+ var SCALARS = { boolean: true, string: true, number: true };
1063
+ function literalsOf({ tsm }, parts) {
1064
+ return parts.filter((part) => part.flags & tsm.TypeFlags.StringLiteral).map((part) => part.value);
1065
+ }
1066
+ var MAX_DEPTH2 = 4;
1067
+ function shapeOf(reading, type, depth) {
1068
+ const { tsm, checker } = reading;
1069
+ const { TypeFlags } = tsm;
1070
+ if (depth > MAX_DEPTH2) return null;
1071
+ const whole = checker.getNonNullableType(type);
1072
+ const parts = whole.isUnion() ? whole.types : [whole];
1073
+ if (parts.length === 0) return null;
1074
+ if (parts.every((part) => part.flags & TypeFlags.BooleanLike)) return { name: "boolean" };
1075
+ if (parts.some((part) => part.flags & TypeFlags.String)) return { name: "string" };
1076
+ if (whole.flags & TypeFlags.Number) return { name: "number" };
1077
+ const literals = literalsOf(reading, parts);
1078
+ if (literals.length === parts.length || literals.length > 1) return { name: "enum", value: literals };
1079
+ if (parts.length > 1) {
1080
+ const members = parts.map((part) => shapeOf(reading, part, depth + 1));
1081
+ return members.every((member) => member?.name === "object") ? { name: "union", value: members } : null;
1082
+ }
1083
+ if (checker.isArrayType(whole)) {
1084
+ const [item] = checker.getTypeArguments(whole);
1085
+ const shape = item && shapeOf(reading, item, depth + 1);
1086
+ return shape ? { name: "array", value: shape } : null;
1087
+ }
1088
+ if (checker.isTupleType(whole)) {
1089
+ const items = checker.getTypeArguments(whole).map((item) => shapeOf(reading, item, depth + 1));
1090
+ const [first] = items;
1091
+ const same = first && items.every((item) => JSON.stringify(item) === JSON.stringify(first));
1092
+ return same ? { name: "array", value: first } : null;
1093
+ }
1094
+ if (!(whole.flags & (TypeFlags.Object | TypeFlags.Intersection))) return null;
1095
+ if (whole.getCallSignatures().length > 0 || whole.getConstructSignatures().length > 0) return null;
1096
+ if (checker.getIndexInfosOfType(whole).length > 0) return null;
1097
+ const declared = (whole.getSymbol() ?? whole.aliasSymbol)?.getDeclarations() ?? [];
1098
+ if (declared.some((declaration) => IN_PACKAGES.test(declaration.getSourceFile().fileName))) return null;
1099
+ const fields = {};
1100
+ for (const prop2 of checker.getPropertiesOfType(whole)) {
1101
+ const files = declaredIn(prop2);
1102
+ if (files.some((file) => IN_PACKAGES.test(file) || reading.skipped(file))) return null;
1103
+ const field = shapeOf(reading, checker.getTypeOfSymbolAtLocation(prop2, reading.at), depth + 1);
1104
+ if (field) fields[prop2.getName()] = field;
1105
+ else if (!(prop2.flags & tsm.SymbolFlags.Optional)) return null;
1106
+ record(reading, files);
1107
+ }
1108
+ return Object.keys(fields).length > 0 ? { name: "object", value: fields } : null;
1055
1109
  }
1056
1110
  function writtenOrder(tsm, checker, prop2) {
1057
1111
  const [declaration, ...others] = prop2.getDeclarations() ?? [];
@@ -1078,6 +1132,7 @@ function writtenOrder(tsm, checker, prop2) {
1078
1132
  if (alias && rest.length === 0 && tsm.isTypeAliasDeclaration(alias) && !alias.typeParameters) {
1079
1133
  return literals(alias.type);
1080
1134
  }
1135
+ if (target && target.flags & (tsm.SymbolFlags.Interface | tsm.SymbolFlags.Class)) return [];
1081
1136
  }
1082
1137
  return null;
1083
1138
  };
@@ -1553,7 +1608,14 @@ function captureEntry() {
1553
1608
  import '@weasel-js/labkit/styles.css';
1554
1609
  import '@weasel-js/forge/shell.css';
1555
1610
  import config from 'virtual:forge/shell-config.js';
1556
- ${body("mountCapture({ index, importers, setup, labTheme: config.labTheme });")}`;
1611
+ ${body(`mountCapture({
1612
+ index,
1613
+ importers,
1614
+ setup,
1615
+ labTheme: config.labTheme,
1616
+ libraries: config.libraries,
1617
+ dependencies: () => import('virtual:forge/deps.js').then((m) => m.default),
1618
+ });`)}`;
1557
1619
  }
1558
1620
  function captureFrameEntry(styles) {
1559
1621
  return `import { mountCapture } from '@weasel-js/forge/frame';
@@ -1730,7 +1792,7 @@ function forge(options) {
1730
1792
  );
1731
1793
  return byFile;
1732
1794
  };
1733
- const index = () => [...files().values()].flat();
1795
+ const index = () => byComponent([...files().values()].flat());
1734
1796
  const settle = async (targets, resolveImport) => {
1735
1797
  const decide = createWrapperResolver((file) => readFileSync(file, "utf8"));
1736
1798
  const current = files();