pattern-dump 0.1.0-alpha.0 → 0.1.0-alpha.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.
@@ -1,26 +1,19 @@
1
1
  // ../../packages/contracts/src/dev-protocol.ts
2
- var SCOPE_BOUNDARY = `## Scope \u2014 the boundary is part of the artifact
3
-
4
- **Covers** \u2014 machine-detectable, static, single-render (no browser layout):
5
- - **HTML content-model** (html-validate) \u2014 nesting/permitted-content violations.
6
- - **Structural a11y** (axe, alwaysOn tier) \u2014 labels, names, ARIA, roles, image-alt.
7
- - **Schema** \u2014 required/shape violations against \`component.schema.json\`.
8
- - **Render outcome** \u2014 blank / error / ok (metadata, never itself a defect).
9
-
10
- **Deliberately NOT covered \u2014 named boundaries, not misses:**
11
- - **Rendered-contrast (axe needsRendering tier)** \u2014 contrast, aria-hidden-focus, duplicate-id-aria.
12
- These require real browser layout/paint; the static jsdom sweep cannot produce them. The
13
- per-component panel shows them (live iframe); this aggregate does not. Fewer rule types here is a
14
- scope boundary, not a gap.
15
- - **Structural/graph findings** \u2014 dead subtrees, a shared-base "component", flattened variant families.
16
- Those are the style graph's lens, not this one.
17
- - **PD reporting gaps** \u2014 PD under-claiming (e.g. missing provenance) is not a subject defect.
18
- - **Interactive / behavioural** \u2014 focus traps, keyboard flow, escape handling. Single static render only.
19
- - **Data-masked** \u2014 a component that renders empty for want of data won't throw the violations it would
20
- when populated; findings are annotated with render outcome wherever it is blank.
21
-
22
- A component with zero findings is **not "clean" \u2014 it is "clean of static machine-detectable defects."**
23
- That is the honest claim; never "clean".`;
2
+ var AUDIT_SCOPE = {
3
+ covered: [
4
+ { name: "HTML content model", detail: "invalid nesting and content that isn't permitted where it appears (html-validate)." },
5
+ { name: "Structural accessibility", detail: "labels, accessible names, ARIA attributes, roles and image alternatives (the axe-core rules that don't need layout)." },
6
+ { name: "Schema", detail: "missing required fields and values of the wrong type, checked against each component's `<name>.schema.json`." },
7
+ { name: "Render outcome", detail: "whether each component rendered, rendered empty or failed. It is reported with the component, not counted as a defect." }
8
+ ],
9
+ notCovered: [
10
+ { name: "Checks that need a rendered page", detail: "colour contrast, focusable content hidden with aria-hidden, and duplicate ids referenced by ARIA. They need real browser layout; the Console's Diagnostics tab runs them for the component on screen." },
11
+ { name: "Interaction", detail: "focus traps, keyboard flow and Escape handling. The audit looks at a single static render." },
12
+ { name: "Structure", detail: "unused components, shared bases and near-duplicate copies. The Relationships tab and `pd export` cover those." },
13
+ { name: "Components that need data", detail: "a component that renders empty without data can't show the problems it would have with data. Its findings carry the render outcome." }
14
+ ],
15
+ note: "No findings means no static, machine-detectable defects, not that a component is fully accessible or correct."
16
+ };
24
17
  function buildAuditRollup(graph, opts = {}) {
25
18
  const total = graph.components.length;
26
19
  const affected = new Set(graph.occurrences.map((o) => o.component));
@@ -62,7 +55,7 @@ function buildAuditRollup(graph, opts = {}) {
62
55
  renderOutcomes: { ok: outcomes["ok"] ?? 0, blank: outcomes["blank"] ?? 0, error: outcomes["error"] ?? 0 },
63
56
  rulesByBlast,
64
57
  perComponent,
65
- scope: SCOPE_BOUNDARY
58
+ scope: AUDIT_SCOPE
66
59
  };
67
60
  }
68
61
  function previewUrl(id, variant, theme) {
@@ -237,8 +230,7 @@ var session = {
237
230
  dataCache: null,
238
231
  dataRaw: null,
239
232
  renderedA11y: [],
240
- scanPending: false,
241
- lastPdWidth: null
233
+ scanPending: false
242
234
  };
243
235
 
244
236
  // src/core/runtime.ts
@@ -796,7 +788,7 @@ async function runRenderedA11yScan() {
796
788
  }
797
789
  const axeWindow = dom.iframe.contentWindow;
798
790
  if (!axeWindow.axe) await injectAxe();
799
- const root = dom.iframe.contentDocument.querySelector("main") ?? dom.iframe.contentDocument.body;
791
+ const root = dom.iframe.contentDocument.body;
800
792
  const results = await axeWindow.axe.run(root, { runOnly: session.needsRenderingRules });
801
793
  if (gen !== scanGen) return;
802
794
  session.renderedA11y = mapAxeResults(results);
@@ -983,6 +975,12 @@ var el = (tag, cls, text) => {
983
975
  if (text !== void 0) n.textContent = text;
984
976
  return n;
985
977
  };
978
+ function appendWithCode(parent, text) {
979
+ text.split("`").forEach((part, i) => {
980
+ if (part === "") return;
981
+ parent.appendChild(i % 2 === 1 ? el("code", "audit-scope-code", part) : document.createTextNode(part));
982
+ });
983
+ }
986
984
  function tagBadge(tag) {
987
985
  const s = el("span", "audit-tag", `[${tag}]`);
988
986
  s.dataset.tag = tag;
@@ -1060,8 +1058,22 @@ function renderAuditView(rollup) {
1060
1058
  }
1061
1059
  const scope = el("details", "audit-scope");
1062
1060
  scope.open = true;
1063
- scope.appendChild(el("summary", "audit-scope-summary", "Scope \u2014 what this count does and does not cover"));
1064
- scope.appendChild(el("pre", "audit-scope-body", rollup.scope));
1061
+ scope.appendChild(el("summary", "audit-scope-summary", "Scope: what this count does and does not cover"));
1062
+ const scopeList = (label, items, kind) => {
1063
+ scope.appendChild(el("p", "audit-scope-label", label));
1064
+ const list = el("ul", "audit-scope-list");
1065
+ list.dataset.scope = kind;
1066
+ for (const item of items) {
1067
+ const li = el("li", "audit-scope-item");
1068
+ li.appendChild(el("strong", "audit-scope-name", `${item.name}: `));
1069
+ appendWithCode(li, item.detail);
1070
+ list.appendChild(li);
1071
+ }
1072
+ scope.appendChild(list);
1073
+ };
1074
+ scopeList("Covered: static checks on a single render, without browser layout.", rollup.scope.covered, "covered");
1075
+ scopeList("Not covered:", rollup.scope.notCovered, "not-covered");
1076
+ scope.appendChild(el("p", "audit-scope-note", rollup.scope.note));
1065
1077
  section.appendChild(scope);
1066
1078
  return section;
1067
1079
  }
@@ -1708,6 +1720,133 @@ function withForwarder(doc) {
1708
1720
  return doc.includes("</body>") ? doc.replace("</body>", FORWARDER + "</body>") : doc + FORWARDER;
1709
1721
  }
1710
1722
 
1723
+ // src/stage/preview-sizing.ts
1724
+ function setVpProp(el2, prop, value) {
1725
+ const cur = parseFloat(el2.style.getPropertyValue(prop)) || 0;
1726
+ if (Math.abs(value - cur) > 1) {
1727
+ el2.style.setProperty(prop, `${value}px`);
1728
+ }
1729
+ }
1730
+
1731
+ // src/stage/content-width.ts
1732
+ var measuring = /* @__PURE__ */ new WeakMap();
1733
+ var fitted = /* @__PURE__ */ new WeakMap();
1734
+ function fitsContent(frame) {
1735
+ if (frame === dom.iframe) {
1736
+ const vp = store.url.viewport;
1737
+ return (vp === "fit" || vp === "content") && dom.stageView.dataset.layout !== "full";
1738
+ }
1739
+ return frame.closest(".gallery-item") !== null;
1740
+ }
1741
+ function measureContentWidth(frame) {
1742
+ if (!fitsContent(frame)) {
1743
+ stopMeasuring(frame);
1744
+ return;
1745
+ }
1746
+ frame.classList.add("vp-measuring");
1747
+ frame.style.removeProperty("--vp-w");
1748
+ fitted.delete(frame);
1749
+ measuring.set(frame, frame.clientWidth);
1750
+ }
1751
+ function stopMeasuring(frame) {
1752
+ measuring.delete(frame);
1753
+ fitted.delete(frame);
1754
+ frame.classList.remove("vp-measuring");
1755
+ }
1756
+ function remeasureAll() {
1757
+ for (const frame of document.querySelectorAll("#preview-frame, .gallery-item iframe")) {
1758
+ measureContentWidth(frame);
1759
+ }
1760
+ }
1761
+ function widthThresholds(condition) {
1762
+ const out = [];
1763
+ const px = (n, unit) => parseFloat(n) * (unit.toLowerCase() === "px" ? 1 : 16);
1764
+ for (const query of condition.split(",")) {
1765
+ if (/^\s*(only\s+)?print\b/i.test(query)) continue;
1766
+ for (const m of query.matchAll(/(?:min|max)-(?:width|inline-size)\s*:\s*(-?[\d.]+)(px|r?em)\b/gi)) out.push(px(m[1], m[2]));
1767
+ for (const m of query.matchAll(/(?:width|inline-size)\s*[<>]=?\s*(-?[\d.]+)(px|r?em)\b/gi)) out.push(px(m[1], m[2]));
1768
+ for (const m of query.matchAll(/(-?[\d.]+)(px|r?em)\s*[<>]=?\s*(?:width|inline-size)\b/gi)) out.push(px(m[1], m[2]));
1769
+ }
1770
+ return out;
1771
+ }
1772
+ function widthConditionsChange(frame, narrow, wide) {
1773
+ const doc = frame.contentDocument;
1774
+ if (!doc) return false;
1775
+ const between = (t) => t >= narrow && t <= wide;
1776
+ const matches = (selector) => {
1777
+ try {
1778
+ return doc.querySelector(selector) !== null;
1779
+ } catch {
1780
+ return true;
1781
+ }
1782
+ };
1783
+ const stylesThePreview = (rules) => {
1784
+ for (const rule of rules ?? []) {
1785
+ const r = rule;
1786
+ if (r.selectorText !== void 0 && matches(r.selectorText)) return true;
1787
+ if (r.cssRules !== void 0 && stylesThePreview(r.cssRules)) return true;
1788
+ }
1789
+ return false;
1790
+ };
1791
+ const visit = (rules) => {
1792
+ for (const rule of rules ?? []) {
1793
+ const r = rule;
1794
+ const condition = r.styleSheet === void 0 && r.media !== void 0 ? r.media.mediaText : r.containerName !== void 0 ? r.conditionText ?? null : null;
1795
+ if (condition !== null && widthThresholds(condition).some(between) && stylesThePreview(r.cssRules)) return true;
1796
+ if (r.styleSheet !== void 0) {
1797
+ const imported = sheetRules(r.styleSheet);
1798
+ if (r.media && widthThresholds(r.media.mediaText).some(between) && stylesThePreview(imported)) return true;
1799
+ if (visit(imported)) return true;
1800
+ } else if (r.cssRules !== void 0 && visit(r.cssRules)) return true;
1801
+ }
1802
+ return false;
1803
+ };
1804
+ return [...doc.styleSheets].some((sheet) => visit(sheetRules(sheet)));
1805
+ }
1806
+ function sheetRules(sheet) {
1807
+ try {
1808
+ return sheet?.cssRules;
1809
+ } catch {
1810
+ return void 0;
1811
+ }
1812
+ }
1813
+ function setWidthNow(frame, width) {
1814
+ frame.classList.add("vp-measuring");
1815
+ if (width === null) frame.style.removeProperty("--vp-w");
1816
+ else setVpProp(frame, "--vp-w", width);
1817
+ requestAnimationFrame(() => requestAnimationFrame(() => frame.classList.remove("vp-measuring")));
1818
+ }
1819
+ function acceptContentWidth(frame, width, at, scroll) {
1820
+ const full = measuring.get(frame);
1821
+ if (full === void 0) {
1822
+ const state = fitted.get(frame);
1823
+ if (state === void 0 || scroll <= at + 1) return false;
1824
+ const parentWidth = frame.parentElement?.clientWidth ?? Infinity;
1825
+ if (state === "measured" && scroll < parentWidth) {
1826
+ fitted.set(frame, "widened");
1827
+ setWidthNow(frame, scroll);
1828
+ } else {
1829
+ fitted.delete(frame);
1830
+ setWidthNow(frame, null);
1831
+ }
1832
+ return true;
1833
+ }
1834
+ if (Math.abs(at - full) > 1) return false;
1835
+ measuring.delete(frame);
1836
+ const narrower = width < full - 1 && !widthConditionsChange(frame, width, full);
1837
+ if (narrower) fitted.set(frame, "measured");
1838
+ setWidthNow(frame, narrower ? width : null);
1839
+ return true;
1840
+ }
1841
+ function initContentWidth() {
1842
+ let theme = store.local.theme;
1843
+ store.subscribe(() => {
1844
+ if (store.local.theme === theme) return;
1845
+ theme = store.local.theme;
1846
+ remeasureAll();
1847
+ });
1848
+ }
1849
+
1711
1850
  // src/stage/viewport.ts
1712
1851
  var PRESETS = {
1713
1852
  mobile: { w: 375, h: 667 },
@@ -1755,7 +1894,7 @@ function syncMarks() {
1755
1894
  }
1756
1895
  const sr = dom.stageView.getBoundingClientRect();
1757
1896
  const EPSILON = 2;
1758
- if (fr.width >= sr.width - EPSILON || fr.height >= sr.height - EPSILON) {
1897
+ if (dom.iframe.classList.contains("vp-fit") || fr.width >= sr.width - EPSILON || fr.height >= sr.height - EPSILON) {
1759
1898
  dom.markOverlay.hidden = true;
1760
1899
  return;
1761
1900
  }
@@ -1784,19 +1923,14 @@ function applyViewport() {
1784
1923
  dom.iframe.classList.remove("vp-sized");
1785
1924
  dom.iframe.classList.remove("vp-content");
1786
1925
  dom.iframe.classList.add("vp-fit");
1926
+ measureContentWidth(dom.iframe);
1787
1927
  } else if (vp === "content") {
1788
- const layout = dom.stageView.getAttribute("data-layout") ?? "centered";
1789
- if (session.lastPdWidth !== null) {
1790
- dom.iframe.style.setProperty("--vp-w", `${session.lastPdWidth}px`);
1791
- } else if (layout === "full") {
1792
- dom.iframe.style.removeProperty("--vp-w");
1793
- } else {
1794
- dom.iframe.style.setProperty("--vp-w", "max-content");
1795
- }
1796
1928
  dom.iframe.classList.remove("vp-sized");
1797
1929
  dom.iframe.classList.remove("vp-fit");
1798
1930
  dom.iframe.classList.add("vp-content");
1931
+ measureContentWidth(dom.iframe);
1799
1932
  } else {
1933
+ stopMeasuring(dom.iframe);
1800
1934
  const p = PRESETS[vp];
1801
1935
  dom.iframe.style.setProperty("--vp-w", `${p.w}px`);
1802
1936
  dom.iframe.classList.add("vp-sized");
@@ -1832,6 +1966,7 @@ function stopDisco() {
1832
1966
  function startDisco() {
1833
1967
  if (vpDisco) return;
1834
1968
  vpDisco = true;
1969
+ stopMeasuring(dom.iframe);
1835
1970
  dom.viewportToolbar.setAttribute("data-disco-active", "");
1836
1971
  dom.vpDiscoBtn.setAttribute("aria-pressed", "true");
1837
1972
  dom.vpDiscoBtn.innerHTML = svgIcon("vp-disco-fill");
@@ -1918,6 +2053,7 @@ function initViewport(onFullscreen) {
1918
2053
  iframeObserver.observe(dom.iframe);
1919
2054
  iframeObserver.observe(dom.stageView);
1920
2055
  dom.iframe.addEventListener("load", () => {
2056
+ measureContentWidth(dom.iframe);
1921
2057
  updateReadout();
1922
2058
  syncFrameFocusListeners();
1923
2059
  });
@@ -2191,6 +2327,7 @@ async function buildVariantsGallery() {
2191
2327
  if (store.local.theme) applyThemeToIframe(f, store.local.theme);
2192
2328
  const h = f.contentDocument?.documentElement?.scrollHeight;
2193
2329
  if (typeof h === "number" && h > 0) f.style.setProperty("--vp-h", `${h}px`);
2330
+ measureContentWidth(f);
2194
2331
  });
2195
2332
  fig.appendChild(h2);
2196
2333
  fig.appendChild(f);
@@ -2231,6 +2368,7 @@ function renderOverview(overview) {
2231
2368
  if (store.local.theme) applyThemeToIframe(f, store.local.theme);
2232
2369
  const h = f.contentDocument?.documentElement?.scrollHeight;
2233
2370
  if (typeof h === "number" && h > 0) f.style.setProperty("--vp-h", `${h}px`);
2371
+ measureContentWidth(f);
2234
2372
  });
2235
2373
  f.src = resourceUrl(previewUrl(item.id, void 0, store.local.theme || void 0));
2236
2374
  fig.appendChild(h2);
@@ -2283,7 +2421,6 @@ async function applyComponent(detail, variant) {
2283
2421
  dom.iframe.srcdoc = _html;
2284
2422
  });
2285
2423
  dom.iframe.style.removeProperty("--vp-h");
2286
- session.lastPdWidth = null;
2287
2424
  if (isDiscoRunning()) stopDisco();
2288
2425
  applyViewport();
2289
2426
  delete dom.dockEl.dataset.mode;
@@ -2346,33 +2483,98 @@ async function navigate(componentId, variant) {
2346
2483
  await applyComponent(detail, variant);
2347
2484
  } catch (e) {
2348
2485
  console.error("[pd] Navigate error:", e);
2486
+ showStageMessage(`Could not load \u201C${componentId}\u201D: ${e instanceof Error ? e.message : String(e)}`);
2349
2487
  }
2350
2488
  }
2489
+ async function navigateUnknown(path, variant) {
2490
+ const res = await fetch(componentUrl(path, variant)).catch(() => null);
2491
+ if (res?.ok) {
2492
+ await applyComponent(await res.json(), variant);
2493
+ return;
2494
+ }
2495
+ showStageMessage(`No component or folder \u201C${path}\u201D.`, closestPaths(path));
2496
+ }
2497
+ function closestPaths(path) {
2498
+ const all = [];
2499
+ const walk = (nodes) => {
2500
+ for (const n of nodes) {
2501
+ all.push(n.path);
2502
+ if (n.children) walk(n.children);
2503
+ }
2504
+ };
2505
+ walk(session.tree.roots);
2506
+ const name = path.split("/").pop() ?? path;
2507
+ const sameName = all.filter((p) => p.split("/").pop() === name);
2508
+ const near = all.map((p) => ({ p, d: editDistance(p, path) })).filter(({ p, d }) => d <= Math.max(2, Math.floor(path.length / 5)) && !sameName.includes(p)).sort((a, b) => a.d - b.d).map(({ p }) => p);
2509
+ return [...sameName, ...near].slice(0, 3);
2510
+ }
2511
+ function editDistance(a, b) {
2512
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i);
2513
+ for (let i = 1; i <= a.length; i++) {
2514
+ let prev = row[0];
2515
+ row[0] = i;
2516
+ for (let j = 1; j <= b.length; j++) {
2517
+ const cur = row[j];
2518
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
2519
+ prev = cur;
2520
+ }
2521
+ }
2522
+ return row[b.length];
2523
+ }
2524
+ function showFolderArea(activePath) {
2525
+ session.current = null;
2526
+ session.currentVariant = null;
2527
+ session.renderedHtmlCache = null;
2528
+ session.rawRenderedHtml = null;
2529
+ session.dataCache = null;
2530
+ session.dataRaw = null;
2531
+ session.stageMode = "single";
2532
+ dom.variantBar.hidden = true;
2533
+ dom.panel.hidden = true;
2534
+ dom.singlePreview.hidden = true;
2535
+ dom.categoryOverview.hidden = false;
2536
+ dom.variantsGalleryEl.hidden = true;
2537
+ dom.stageView.removeAttribute("data-layout");
2538
+ dom.dockEl.dataset.mode = "overview";
2539
+ switchDockTab("console");
2540
+ setActiveTreeItem(activePath);
2541
+ }
2542
+ function showStageMessage(message, suggestions = []) {
2543
+ showFolderArea("");
2544
+ dom.categoryOverview.innerHTML = "";
2545
+ const box = document.createElement("div");
2546
+ box.className = "stage-message";
2547
+ box.setAttribute("role", "status");
2548
+ const p = document.createElement("p");
2549
+ p.textContent = message;
2550
+ box.appendChild(p);
2551
+ if (suggestions.length > 0) {
2552
+ const intro = document.createElement("p");
2553
+ intro.textContent = "Did you mean:";
2554
+ const list = document.createElement("ul");
2555
+ for (const s of suggestions) {
2556
+ const li = document.createElement("li");
2557
+ const a = document.createElement("a");
2558
+ a.href = routeHref(`/${s}`);
2559
+ a.textContent = s;
2560
+ li.appendChild(a);
2561
+ list.appendChild(li);
2562
+ }
2563
+ box.append(intro, list);
2564
+ }
2565
+ dom.categoryOverview.appendChild(box);
2566
+ }
2351
2567
  async function navigateOverview(folderPath) {
2352
2568
  try {
2353
2569
  const res = await fetch(overviewUrl(folderPath));
2354
2570
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
2355
2571
  const overview = await res.json();
2356
- session.current = null;
2357
- session.currentVariant = null;
2358
- session.renderedHtmlCache = null;
2359
- session.rawRenderedHtml = null;
2360
- session.dataCache = null;
2361
- session.dataRaw = null;
2362
- session.stageMode = "single";
2363
- dom.variantBar.hidden = true;
2364
- dom.panel.hidden = true;
2365
- dom.singlePreview.hidden = true;
2366
- dom.categoryOverview.hidden = false;
2367
- dom.variantsGalleryEl.hidden = true;
2368
- dom.stageView.removeAttribute("data-layout");
2369
- dom.dockEl.dataset.mode = "overview";
2370
- switchDockTab("console");
2371
- setActiveTreeItem(folderPath);
2572
+ showFolderArea(folderPath);
2372
2573
  renderOverview(overview);
2373
2574
  await renderPanel();
2374
2575
  } catch (e) {
2375
2576
  console.error("[pd] Overview error:", e);
2577
+ showStageMessage(`Could not load \u201C${folderPath}\u201D: ${e instanceof Error ? e.message : String(e)}`);
2376
2578
  }
2377
2579
  }
2378
2580
  async function navigateVariants(componentId) {
@@ -2546,6 +2748,7 @@ function connectHmr() {
2546
2748
  if (link) link.href = href;
2547
2749
  });
2548
2750
  }
2751
+ void pdLinksLoaded().then(remeasureAll);
2549
2752
  if (store.local.panelTab === "relationships" && session.current) {
2550
2753
  void fetch(componentUrl(session.current.id)).then((r) => r.ok ? r.json() : Promise.reject(r.status)).then((d) => {
2551
2754
  session.current = d;
@@ -2618,6 +2821,14 @@ function connectHmr() {
2618
2821
  }
2619
2822
  });
2620
2823
  }
2824
+ function pdLinksLoaded() {
2825
+ const links = [...document.querySelectorAll("iframe")].flatMap((f) => [...f.contentDocument?.querySelectorAll("link[data-pd-comp]") ?? []]);
2826
+ return Promise.all(links.map((link) => new Promise((resolve) => {
2827
+ link.addEventListener("load", () => resolve(), { once: true });
2828
+ link.addEventListener("error", () => resolve(), { once: true });
2829
+ setTimeout(resolve, 1e3);
2830
+ }))).then(() => void 0);
2831
+ }
2621
2832
 
2622
2833
  // src/app/router.ts
2623
2834
  function resolvePathKind(path) {
@@ -2646,6 +2857,10 @@ async function routeFromCurrentLocation() {
2646
2857
  applyCvd();
2647
2858
  }
2648
2859
  const path = routeFromPathname(window.location.pathname).slice(1);
2860
+ if (!path && window.location.hash.startsWith("#/")) {
2861
+ history.replaceState(history.state, "", routeHref(window.location.hash.slice(1)) + window.location.search);
2862
+ return routeFromCurrentLocation();
2863
+ }
2649
2864
  const variant = window.location.hash.slice(1) || void 0;
2650
2865
  if (!path) return;
2651
2866
  if (path.endsWith("/variants")) {
@@ -2662,16 +2877,10 @@ async function routeFromCurrentLocation() {
2662
2877
  } else {
2663
2878
  await navigate(path, variant);
2664
2879
  }
2665
- } else {
2880
+ } else if (kind === "group") {
2666
2881
  await navigateOverview(path);
2667
- }
2668
- }
2669
-
2670
- // src/stage/preview-sizing.ts
2671
- function setVpProp(el2, prop, value) {
2672
- const cur = parseFloat(el2.style.getPropertyValue(prop)) || 0;
2673
- if (Math.abs(value - cur) > 1) {
2674
- el2.style.setProperty(prop, `${value}px`);
2882
+ } else {
2883
+ await navigateUnknown(path, variant);
2675
2884
  }
2676
2885
  }
2677
2886
 
@@ -2689,17 +2898,16 @@ function listenForPreviewMessages() {
2689
2898
  setVpProp(el2, "--vp-h", height);
2690
2899
  }
2691
2900
  });
2692
- } else if (data.type === "pd-width" && typeof data.width === "number") {
2693
- session.lastPdWidth = data.width;
2694
- if (store.url.viewport === "content") {
2695
- const width = data.width;
2696
- document.querySelectorAll("iframe").forEach((f) => {
2697
- if (f.contentWindow === e.source) {
2698
- setVpProp(f, "--vp-w", width);
2699
- }
2700
- });
2701
- requestAnimationFrame(updateReadout);
2702
- }
2901
+ } else if (data.type === "pd-width" && typeof data.width === "number" && typeof data.at === "number") {
2902
+ const { width, at } = data;
2903
+ const scroll = typeof data.scroll === "number" ? data.scroll : at;
2904
+ document.querySelectorAll("iframe").forEach((f) => {
2905
+ const frame = f;
2906
+ if (frame.contentWindow !== e.source) return;
2907
+ if (acceptContentWidth(frame, width, at, scroll) && frame === dom.iframe) {
2908
+ requestAnimationFrame(updateReadout);
2909
+ }
2910
+ });
2703
2911
  } else if (data.type === "pd-fp") {
2704
2912
  if (data.action === "exit") dom.fullpageDialog.close();
2705
2913
  else if (data.action === "active") showFullpageChrome();
@@ -2739,6 +2947,7 @@ function mount() {
2739
2947
  app.innerHTML = renderShellHtml();
2740
2948
  initDom(app);
2741
2949
  listenForPreviewMessages();
2950
+ initContentWidth();
2742
2951
  dom.searchInput.addEventListener("input", () => {
2743
2952
  session.searchQuery = dom.searchInput.value;
2744
2953
  filterTree(session.searchQuery);
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
- // packages/config/src/index.ts
2
- function defineConfig(config) {
3
- return config;
4
- }
1
+ import {
2
+ defineConfig
3
+ } from "./chunks/chunk-3WZHFYHZ.js";
5
4
  export {
6
5
  defineConfig
7
6
  };