foss-design 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3693,6 +3693,7 @@ async function openFrame(page, url, options = {}) {
3693
3693
  }
3694
3694
  if (!errors.some((error) => OUTDATED_DEP.test(error))) break;
3695
3695
  }
3696
+ const held = ready ? 0 : await page.evaluate(() => window.__DESIGN_HOLDS__ ?? 0).catch(() => 0);
3696
3697
  await page.waitForTimeout(options.settleMs ?? 700);
3697
3698
  const runtimeErrors = await page.evaluate(() => window.__DESIGN_ERRORS__ ?? []).catch(() => []);
3698
3699
  for (const error of runtimeErrors) if (!errors.includes(error)) errors.push(error);
@@ -3704,7 +3705,7 @@ async function openFrame(page, url, options = {}) {
3704
3705
  const unique2 = errors.filter(
3705
3706
  (error, index) => error && !errors.some((other, j) => j !== index && other && other.length < error.length && error.includes(other))
3706
3707
  );
3707
- return { errors: [...new Set(unique2)], ready };
3708
+ return { errors: [...new Set(unique2)], ready, ...held ? { held } : {} };
3708
3709
  }
3709
3710
 
3710
3711
  // src/server/state.ts
@@ -4341,7 +4342,7 @@ async function renderFrames(jobs) {
4341
4342
  await page.close().catch(() => {
4342
4343
  });
4343
4344
  }
4344
- return { key: job.key, url: job.url, ready: report.ready, errors: report.errors, links };
4345
+ return { key: job.key, url: job.url, ready: report.ready, held: report.held, errors: report.errors, links };
4345
4346
  });
4346
4347
  } finally {
4347
4348
  await browser.close();
@@ -4384,7 +4385,8 @@ async function runCheck(paths, canvases, options) {
4384
4385
  for (const frame of frames) {
4385
4386
  const ok = frame.ready && !frame.errors.length;
4386
4387
  print(`${ok ? green("\u2713") : red("\u2717")} ${frame.key} ${dim(frame.url)}`);
4387
- if (!frame.ready) print(` ${red("did not finish rendering (no ready signal within 20s)")}`);
4388
+ if (frame.held) print(` ${red(`holdReady() was not released within 20s (${frame.held} still held)`)}`);
4389
+ else if (!frame.ready) print(` ${red("did not finish rendering (no ready signal within 20s)")}`);
4388
4390
  for (const error of frame.errors) print(` ${red(error.split("\n")[0])}`);
4389
4391
  }
4390
4392
  }
@@ -637,6 +637,7 @@ var config = window.__DESIGN__ ?? { key: "", canvas: "", id: "", props: {} };
637
637
  var embedded = window.parent !== window;
638
638
  var query = new URLSearchParams(window.location.search);
639
639
  var capture = query.has("capture");
640
+ var frameUrl = location.pathname + location.search + location.hash;
640
641
  servePublicFolder(config.public);
641
642
  var theme = config.theme ?? (query.get("theme") === "dark" ? "dark" : "light");
642
643
  var themeListeners = /* @__PURE__ */ new Set();
@@ -741,9 +742,14 @@ function watchSize() {
741
742
  window.addEventListener("load", queue);
742
743
  queue();
743
744
  }
745
+ var touched = false;
746
+ var inspecting = false;
747
+ var loaded = false;
748
+ var signalled = false;
749
+ var holds = 0;
744
750
  var snapshotTimer;
745
751
  function scheduleSnapshot() {
746
- if (!config.snapshots || !embedded || capture) return;
752
+ if (!config.snapshots || !embedded || capture || touched || !signalled) return;
747
753
  clearTimeout(snapshotTimer);
748
754
  snapshotTimer = setTimeout(() => {
749
755
  const run = () => void takeSnapshot();
@@ -752,6 +758,7 @@ function scheduleSnapshot() {
752
758
  }, 1800);
753
759
  }
754
760
  async function takeSnapshot() {
761
+ if (touched) return;
755
762
  try {
756
763
  const { domToBlob } = await import("modern-screenshot");
757
764
  const width = window.innerWidth;
@@ -763,7 +770,7 @@ async function takeSnapshot() {
763
770
  type: "image/png",
764
771
  backgroundColor: getComputedStyle(document.body).backgroundColor
765
772
  });
766
- if (!blob) return;
773
+ if (!blob || touched) return;
767
774
  const [canvas, id] = [config.canvas, config.id].map(encodeURIComponent);
768
775
  await fetch(`/api/snapshots/${canvas}/${id}?theme=${theme}&height=${config.autoHeight ? height : ""}`, {
769
776
  method: "POST",
@@ -820,12 +827,31 @@ function keepLinksInFrame() {
820
827
  const original = history[name].bind(history);
821
828
  history[name] = (data, unused, url) => {
822
829
  original(data, unused, url);
823
- if (url === void 0 || url === null) return;
830
+ if (url === void 0 || url === null || !signalled) return;
824
831
  const raw = String(url);
825
832
  report(new URL(raw, location.href), false, raw, true);
826
833
  };
827
834
  }
828
835
  }
836
+ function signalReady() {
837
+ if (signalled || !loaded || holds > 0) return;
838
+ signalled = true;
839
+ window.__DESIGN_READY__ = true;
840
+ post({ type: "ready" });
841
+ scheduleSnapshot();
842
+ }
843
+ function holdReady() {
844
+ holds++;
845
+ window.__DESIGN_HOLDS__ = holds;
846
+ let released = false;
847
+ return () => {
848
+ if (released) return;
849
+ released = true;
850
+ holds--;
851
+ window.__DESIGN_HOLDS__ = holds;
852
+ requestAnimationFrame(() => requestAnimationFrame(signalReady));
853
+ };
854
+ }
829
855
  var booted = false;
830
856
  var hmrBound = false;
831
857
  var canvasHost = false;
@@ -844,6 +870,7 @@ function boot() {
844
870
  } else if (data.type === "inspect") {
845
871
  inspector ??= new FrameInspector(post);
846
872
  if (data.tokens) inspector.setTokens(data.tokens);
873
+ inspecting = !!data.on;
847
874
  if (data.on) inspector.enable();
848
875
  else inspector.disable();
849
876
  } else if (data.type === "inspect-select") inspector?.select(data.ref);
@@ -871,6 +898,19 @@ function boot() {
871
898
  if (event.key === "Escape" && !event.defaultPrevented) post({ type: "keydown", code: "Escape" });
872
899
  });
873
900
  const isModifier = (name) => name === "Meta" || name === "Control";
901
+ const touch = (event) => {
902
+ if (!event.isTrusted || inspecting) return;
903
+ touched = true;
904
+ clearTimeout(snapshotTimer);
905
+ };
906
+ window.addEventListener("pointerdown", touch, true);
907
+ window.addEventListener(
908
+ "keydown",
909
+ (event) => {
910
+ if (!isModifier(event.key) && event.key !== "Shift" && event.key !== "Alt") touch(event);
911
+ },
912
+ true
913
+ );
874
914
  window.addEventListener(
875
915
  "keydown",
876
916
  (event) => {
@@ -893,9 +933,8 @@ function boot() {
893
933
  recordError(String(reason?.message ?? reason ?? "Unhandled rejection"));
894
934
  });
895
935
  const ready = () => {
896
- window.__DESIGN_READY__ = true;
897
- post({ type: "ready" });
898
- scheduleSnapshot();
936
+ loaded = true;
937
+ signalReady();
899
938
  };
900
939
  const whenBodyReady = () => {
901
940
  if (embedded) watchSize();
@@ -912,6 +951,9 @@ function hmr(hot) {
912
951
  post({ type: "updated" });
913
952
  scheduleSnapshot();
914
953
  });
954
+ hot.on("vite:beforeFullReload", () => {
955
+ History.prototype.replaceState.call(history, history.state, "", frameUrl);
956
+ });
915
957
  hot.on("vite:error", (payload) => {
916
958
  const err = payload.err;
917
959
  recordError(err?.message ?? "Build error");
@@ -965,6 +1007,7 @@ export {
965
1007
  boot,
966
1008
  go,
967
1009
  hmr,
1010
+ holdReady,
968
1011
  mount,
969
1012
  useScreen,
970
1013
  useTheme
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foss-design",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Design canvases and design systems for coding agents: live, animated, clickable screens on an infinite canvas, served locally from a .design folder.",
5
5
  "type": "module",
6
6
  "license": "MIT",