@jfrader/storybook-docs 0.5.0 → 0.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.
- package/dist/build/snippet-bindings.d.ts +3 -0
- package/dist/index.css +7 -3
- package/dist/index.js +129 -58
- package/dist/rail.d.ts +1 -0
- package/dist/sections.d.ts +12 -0
- package/dist/styles.css +46 -9
- package/dist/toc.d.ts +0 -6
- package/dist/vite-plugin.js +147 -58
- package/package.json +1 -1
package/dist/index.css
CHANGED
|
@@ -106,16 +106,20 @@
|
|
|
106
106
|
.toc {
|
|
107
107
|
display: none;
|
|
108
108
|
}
|
|
109
|
+
.toc-track {
|
|
110
|
+
display: none;
|
|
111
|
+
}
|
|
109
112
|
@media (min-width: 1180px) {
|
|
110
113
|
.app.has-toc {
|
|
111
114
|
grid-template-columns: 276px minmax(0, 1fr) 224px;
|
|
112
115
|
}
|
|
113
|
-
.toc {
|
|
116
|
+
.toc-track {
|
|
114
117
|
display: block;
|
|
115
118
|
grid-column: 3;
|
|
116
119
|
grid-row: 2;
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
}
|
|
121
|
+
.toc {
|
|
122
|
+
display: block;
|
|
119
123
|
padding: 34px 18px 40px 6px;
|
|
120
124
|
font-size: 12.5px;
|
|
121
125
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { createRoot } from "react-dom/client";
|
|
|
5
5
|
import { site as site3, themeCss, theme as theme2 } from "virtual:storybook-docs/site";
|
|
6
6
|
|
|
7
7
|
// src/app.tsx
|
|
8
|
-
import { useEffect as useEffect8, useRef as useRef5, useState as useState9 } from "react";
|
|
8
|
+
import { Children, useEffect as useEffect8, useRef as useRef5, useState as useState9 } from "react";
|
|
9
9
|
import { catalog as catalog3, groups as groups2 } from "virtual:storybook-docs/catalog";
|
|
10
10
|
import { pages, site as site2, theme } from "virtual:storybook-docs/site";
|
|
11
11
|
|
|
@@ -263,6 +263,11 @@ import { useCallback as useCallback2, useEffect as useEffect4, useId, useRef as
|
|
|
263
263
|
import { Component as Component2, createElement as createElement2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
264
264
|
|
|
265
265
|
// src/sections.ts
|
|
266
|
+
function frameSource(meta, story) {
|
|
267
|
+
const unchanged = Object.entries(story.args ?? {}).every(([key, value]) => Object.hasOwn(meta.args ?? {}, key) && Object.is(value, meta.args?.[key]));
|
|
268
|
+
return story.parameters?.docs?.source?.code ?? (unchanged ? meta.parameters?.docs?.source?.code : void 0);
|
|
269
|
+
}
|
|
270
|
+
var STORY_EXCERPT = "// Excerpt from the story";
|
|
266
271
|
function mergeAnnotations(...values) {
|
|
267
272
|
const merged = {};
|
|
268
273
|
const isRecord = (value) => value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype;
|
|
@@ -375,13 +380,20 @@ function usageSnippet(componentName, args) {
|
|
|
375
380
|
return `${opening}>${children}</${componentName}>`;
|
|
376
381
|
}
|
|
377
382
|
function buildUsageSnippet({ componentName, from, args, source, renderSource, jsxName, component }) {
|
|
378
|
-
if (!source?.trim() && renderSource?.trim()) return renderSource;
|
|
379
383
|
const rootName = componentName.split(".")[0];
|
|
380
384
|
const identity = component;
|
|
381
385
|
const tag = jsxName ?? (typeof identity?.displayName === "string" && identity.displayName.startsWith(`${rootName}.`) ? identity.displayName : componentName);
|
|
382
386
|
const compound = component != null && Object.entries(component).some(([name, part]) => /^[A-Z]/.test(name) && (typeof part === "function" || part !== null && typeof part === "object" && "$$typeof" in part));
|
|
383
|
-
const
|
|
387
|
+
const generated = () => compound && !tag.includes(".") ? null : usageSnippet(tag, args);
|
|
388
|
+
const extracted = renderSource?.trim();
|
|
389
|
+
const excerpt = extracted?.startsWith(STORY_EXCERPT);
|
|
390
|
+
const example = source?.trim() || (excerpt ? generated() || extracted : extracted || generated());
|
|
384
391
|
if (!example) return null;
|
|
392
|
+
if (!source?.trim() && example === extracted) {
|
|
393
|
+
const rootTag = example.replace(/^\s*\/\/[^\n]*(?:\n|$)/gm, "").trim().match(/^<([A-Za-z_$][\w$]*(?:\.[\w$]+)*)[\s/>]/)?.[1]?.split(".")[0];
|
|
394
|
+
if (excerpt || rootTag !== rootName || !from.trim()) return example;
|
|
395
|
+
}
|
|
396
|
+
if (!from.trim()) return example;
|
|
385
397
|
const imports = [...example.matchAll(/import\s*\{([^}]+)\}\s*from\s*(['"])(.*?)\2/g)];
|
|
386
398
|
const imported = imports.some((match) => match[3] === from && match[1].split(",").some((name) => name.trim() === rootName));
|
|
387
399
|
return imported ? example : `import { ${rootName} } from '${from}';
|
|
@@ -511,6 +523,77 @@ function LazySection({ children, placeholder = "\u2026" }) {
|
|
|
511
523
|
|
|
512
524
|
// src/toc.tsx
|
|
513
525
|
import { useCallback, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
526
|
+
|
|
527
|
+
// src/rail.ts
|
|
528
|
+
var RAIL_MEDIA = "(min-width: 1180px)";
|
|
529
|
+
var RAIL_GAP = 20;
|
|
530
|
+
function followRail(rail, header) {
|
|
531
|
+
const track = rail.parentElement;
|
|
532
|
+
if (!track) return () => {
|
|
533
|
+
};
|
|
534
|
+
const media = window.matchMedia(RAIL_MEDIA);
|
|
535
|
+
let lastY = window.scrollY;
|
|
536
|
+
let direction = "down";
|
|
537
|
+
let spacer = 0;
|
|
538
|
+
const geometry = () => {
|
|
539
|
+
const top = header.offsetHeight + RAIL_GAP;
|
|
540
|
+
const viewportBottom = window.innerHeight - RAIL_GAP;
|
|
541
|
+
const height = rail.offsetHeight;
|
|
542
|
+
return {
|
|
543
|
+
top,
|
|
544
|
+
viewportBottom,
|
|
545
|
+
height,
|
|
546
|
+
fits: top + height <= viewportBottom,
|
|
547
|
+
trackTop: track.getBoundingClientRect().top + window.scrollY,
|
|
548
|
+
maxOffset: Math.max(0, track.clientHeight - height)
|
|
549
|
+
};
|
|
550
|
+
};
|
|
551
|
+
const clear = () => {
|
|
552
|
+
rail.removeAttribute("style");
|
|
553
|
+
track.removeAttribute("style");
|
|
554
|
+
};
|
|
555
|
+
const arm = (g = geometry()) => {
|
|
556
|
+
if (!media.matches) {
|
|
557
|
+
clear();
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
spacer = g.fits ? 0 : Math.min(spacer, g.maxOffset);
|
|
561
|
+
track.style.setProperty("--sd-rail-offset", `${spacer}px`);
|
|
562
|
+
rail.style.position = "sticky";
|
|
563
|
+
rail.style.top = g.fits ? `${g.top}px` : direction === "down" ? `${g.viewportBottom - g.height}px` : "auto";
|
|
564
|
+
rail.style.bottom = g.fits || direction === "down" ? "auto" : `${window.innerHeight - g.top - g.height}px`;
|
|
565
|
+
};
|
|
566
|
+
const onScroll = () => {
|
|
567
|
+
const y = window.scrollY;
|
|
568
|
+
const next = y > lastY ? "down" : y < lastY ? "up" : direction;
|
|
569
|
+
if (next !== direction && media.matches) {
|
|
570
|
+
const g = geometry();
|
|
571
|
+
spacer = direction === "down" ? Math.min(Math.max(spacer, lastY + g.viewportBottom - g.height - g.trackTop), g.maxOffset) : Math.max(Math.min(spacer, lastY + g.top - g.trackTop), 0);
|
|
572
|
+
direction = next;
|
|
573
|
+
arm(g);
|
|
574
|
+
}
|
|
575
|
+
direction = next;
|
|
576
|
+
lastY = y;
|
|
577
|
+
};
|
|
578
|
+
const relayout = () => arm();
|
|
579
|
+
const observer = new ResizeObserver(relayout);
|
|
580
|
+
observer.observe(rail);
|
|
581
|
+
observer.observe(track);
|
|
582
|
+
observer.observe(header);
|
|
583
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
584
|
+
window.addEventListener("resize", relayout);
|
|
585
|
+
media.addEventListener("change", relayout);
|
|
586
|
+
arm();
|
|
587
|
+
return () => {
|
|
588
|
+
observer.disconnect();
|
|
589
|
+
window.removeEventListener("scroll", onScroll);
|
|
590
|
+
window.removeEventListener("resize", relayout);
|
|
591
|
+
media.removeEventListener("change", relayout);
|
|
592
|
+
clear();
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/toc.tsx
|
|
514
597
|
import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
515
598
|
var STORY_PARAM = "story";
|
|
516
599
|
var SCROLL_OFFSET_PX = 76;
|
|
@@ -535,34 +618,9 @@ var slugify = (text) => text.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCa
|
|
|
535
618
|
function useRailFollow(ref, ready = true) {
|
|
536
619
|
useEffect3(() => {
|
|
537
620
|
const element = ref.current;
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const limit = () => window.innerHeight - (Number.parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--sd-header-height")) || 56) - 20;
|
|
542
|
-
const apply = () => {
|
|
543
|
-
frame = 0;
|
|
544
|
-
const bottomInDocument = element.getBoundingClientRect().bottom + window.scrollY - applied;
|
|
545
|
-
const crossing = bottomInDocument - limit();
|
|
546
|
-
const next = Math.max(0, window.scrollY - crossing);
|
|
547
|
-
if (next !== applied) {
|
|
548
|
-
applied = next;
|
|
549
|
-
element.style.setProperty("--sd-rail-follow", `${next}px`);
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
const schedule = () => {
|
|
553
|
-
if (!frame) frame = requestAnimationFrame(apply);
|
|
554
|
-
};
|
|
555
|
-
apply();
|
|
556
|
-
window.addEventListener("scroll", schedule, { passive: true });
|
|
557
|
-
window.addEventListener("resize", schedule);
|
|
558
|
-
const observer = new ResizeObserver(schedule);
|
|
559
|
-
observer.observe(element);
|
|
560
|
-
return () => {
|
|
561
|
-
window.removeEventListener("scroll", schedule);
|
|
562
|
-
window.removeEventListener("resize", schedule);
|
|
563
|
-
observer.disconnect();
|
|
564
|
-
if (frame) cancelAnimationFrame(frame);
|
|
565
|
-
};
|
|
621
|
+
const header = element?.closest(".app")?.querySelector(".top");
|
|
622
|
+
if (!element || !header) return;
|
|
623
|
+
return followRail(element, header);
|
|
566
624
|
}, [ready, ref]);
|
|
567
625
|
}
|
|
568
626
|
function scanPage(root, pageKey) {
|
|
@@ -706,7 +764,7 @@ function PageRail({ pageKey }) {
|
|
|
706
764
|
const active = useActiveIds(scan);
|
|
707
765
|
const go = useCallback((element) => scrollToElement(element), []);
|
|
708
766
|
if (!scan) return null;
|
|
709
|
-
return /* @__PURE__ */ jsx5(Fragment, { children: scan.sections.length > 0 ? /* @__PURE__ */ jsxs3("aside", { className: "toc", "aria-label": "On this page", ref: railRef, children: [
|
|
767
|
+
return /* @__PURE__ */ jsx5(Fragment, { children: scan.sections.length > 0 ? /* @__PURE__ */ jsx5("div", { className: "rail-track toc-track", children: /* @__PURE__ */ jsxs3("aside", { className: "toc", "aria-label": "On this page", ref: railRef, children: [
|
|
710
768
|
/* @__PURE__ */ jsx5("div", { className: "toc-title", children: "On this page" }),
|
|
711
769
|
/* @__PURE__ */ jsx5("ul", { children: scan.sections.map((section) => /* @__PURE__ */ jsxs3("li", { children: [
|
|
712
770
|
/* @__PURE__ */ jsx5(
|
|
@@ -731,7 +789,7 @@ function PageRail({ pageKey }) {
|
|
|
731
789
|
}
|
|
732
790
|
) }, story.id)) }) : null
|
|
733
791
|
] }, section.id)) })
|
|
734
|
-
] }) : null });
|
|
792
|
+
] }) }) : null });
|
|
735
793
|
}
|
|
736
794
|
|
|
737
795
|
// src/component-demo.tsx
|
|
@@ -992,7 +1050,7 @@ function ControlledStoryFrame({ module, story, componentName, componentDefaults,
|
|
|
992
1050
|
const storyLayout = requestedLayout === "centered" || requestedLayout === "fullscreen" ? requestedLayout : "padded";
|
|
993
1051
|
const docsOverride = definition.parameters?.docs;
|
|
994
1052
|
const docsMeta = meta.parameters?.docs;
|
|
995
|
-
const authoredCode =
|
|
1053
|
+
const authoredCode = frameSource(meta, definition);
|
|
996
1054
|
const authoredStory = docsOverride?.description?.story ?? docsMeta?.description?.story;
|
|
997
1055
|
const storyName = definition.name ?? story;
|
|
998
1056
|
const skipped = ["loaders", "beforeEach"].filter((key) => meta[key] || definition[key]);
|
|
@@ -1251,7 +1309,7 @@ function ComponentPage({ entry }) {
|
|
|
1251
1309
|
" props"
|
|
1252
1310
|
] })
|
|
1253
1311
|
] }),
|
|
1254
|
-
/* @__PURE__ */ jsx8("p", { className: "lede", children: description
|
|
1312
|
+
description ? /* @__PURE__ */ jsx8("p", { className: "lede", children: description }) : null,
|
|
1255
1313
|
error ? /* @__PURE__ */ jsxs5("div", { className: "story-failed", children: [
|
|
1256
1314
|
"Could not load the story module: ",
|
|
1257
1315
|
error
|
|
@@ -1276,9 +1334,7 @@ function ComponentPage({ entry }) {
|
|
|
1276
1334
|
] }, section.title))
|
|
1277
1335
|
] }) : null,
|
|
1278
1336
|
/* @__PURE__ */ jsx8("h2", { children: "Props" }),
|
|
1279
|
-
/* @__PURE__ */ jsx8(PropsTable, { components: props, argTypes, defaultArgs })
|
|
1280
|
-
/* @__PURE__ */ jsx8("h2", { children: "Notes" }),
|
|
1281
|
-
/* @__PURE__ */ jsx8("p", { children: "Everything above is generated from this component\u2019s story module and source files. Editorial judgement \u2014 when to reach for it, when not to \u2014 is written next to the code and rendered as guidance above." })
|
|
1337
|
+
/* @__PURE__ */ jsx8(PropsTable, { components: props, argTypes, defaultArgs })
|
|
1282
1338
|
] });
|
|
1283
1339
|
}
|
|
1284
1340
|
|
|
@@ -1801,6 +1857,23 @@ function SearchBox() {
|
|
|
1801
1857
|
import { releases as releases2 } from "virtual:storybook-docs/releases";
|
|
1802
1858
|
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1803
1859
|
var routeHref = (path) => `#${hrefFor(path)}`;
|
|
1860
|
+
var NAV_GROUP_WINDOW = 12;
|
|
1861
|
+
function NavGroup({ id, title, active, activeIndex = -1, children }) {
|
|
1862
|
+
const [open, setOpen] = useState9(false);
|
|
1863
|
+
const [showAll, setShowAll] = useState9(false);
|
|
1864
|
+
const expanded = active || open;
|
|
1865
|
+
const links = Children.toArray(children);
|
|
1866
|
+
const capped = active && links.length > NAV_GROUP_WINDOW;
|
|
1867
|
+
const start2 = Math.min(Math.max(activeIndex - NAV_GROUP_WINDOW / 2, 0), Math.max(0, links.length - NAV_GROUP_WINDOW));
|
|
1868
|
+
const visibleLinks = capped && !showAll ? links.slice(start2, start2 + NAV_GROUP_WINDOW) : links;
|
|
1869
|
+
return /* @__PURE__ */ jsxs13("div", { role: "group", "aria-labelledby": id, children: [
|
|
1870
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "grp", id, "aria-expanded": expanded, "aria-controls": `${id}-links`, disabled: active, onClick: () => setOpen(!open), children: title }),
|
|
1871
|
+
/* @__PURE__ */ jsxs13("div", { id: `${id}-links`, hidden: !expanded, children: [
|
|
1872
|
+
/* @__PURE__ */ jsx16("div", { id: `${id}-window`, children: visibleLinks }),
|
|
1873
|
+
capped ? /* @__PURE__ */ jsx16("button", { type: "button", className: "nav-more", "aria-expanded": showAll, "aria-controls": `${id}-window`, onClick: () => setShowAll(!showAll), children: showAll ? "Show less" : `Show all ${links.length}` }) : null
|
|
1874
|
+
] })
|
|
1875
|
+
] });
|
|
1876
|
+
}
|
|
1804
1877
|
function parseRoute(hash) {
|
|
1805
1878
|
const path = hashPath(hash).replace(new RegExp(`^#?\\/?${STORYBOOK_DOCS_BASE}`), "").replace(/^\/+/, "");
|
|
1806
1879
|
if (path.startsWith("components/")) {
|
|
@@ -1909,7 +1982,7 @@ function DocsApp() {
|
|
|
1909
1982
|
/* @__PURE__ */ jsx16("span", { "aria-hidden": "true", children: "\u2197" })
|
|
1910
1983
|
] }, link.href))
|
|
1911
1984
|
] }),
|
|
1912
|
-
/* @__PURE__ */ jsxs13("nav", { id: "docs-nav", className: navOpen ? "nav open" : "nav", "aria-label": "Documentation", ref: navRef, children: [
|
|
1985
|
+
/* @__PURE__ */ jsx16("div", { className: "rail-track nav-track", children: /* @__PURE__ */ jsxs13("nav", { id: "docs-nav", className: navOpen ? "nav open" : "nav", "aria-label": "Documentation", ref: navRef, children: [
|
|
1913
1986
|
/* @__PURE__ */ jsx16("a", { href: routeHref("/"), className: route.kind === "overview" ? "on" : void 0, "aria-current": route.kind === "overview" ? "page" : void 0, children: "Overview" }),
|
|
1914
1987
|
releases2.changelog ? /* @__PURE__ */ jsxs13(
|
|
1915
1988
|
"a",
|
|
@@ -1926,22 +1999,20 @@ function DocsApp() {
|
|
|
1926
1999
|
]
|
|
1927
2000
|
}
|
|
1928
2001
|
) : null,
|
|
1929
|
-
foundations.length > 0 ? /* @__PURE__ */
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
))
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
/* @__PURE__ */ jsx16("div", { className: "grp", id: `nav-grp-${index}`, children: group }),
|
|
1944
|
-
catalog3.filter((entry) => entry.group === group).map((entry) => /* @__PURE__ */ jsx16(
|
|
2002
|
+
foundations.length > 0 ? /* @__PURE__ */ jsx16(NavGroup, { id: "nav-grp-foundations", title: "Foundations", active: foundations.some((item) => route.kind === item.kind), children: foundations.map((item) => /* @__PURE__ */ jsx16(
|
|
2003
|
+
"a",
|
|
2004
|
+
{
|
|
2005
|
+
href: item.href,
|
|
2006
|
+
className: route.kind === item.kind ? "on" : void 0,
|
|
2007
|
+
"aria-current": route.kind === item.kind ? "page" : void 0,
|
|
2008
|
+
children: item.label
|
|
2009
|
+
},
|
|
2010
|
+
item.href
|
|
2011
|
+
)) }, `foundations-${activeSlug ?? route.kind}`) : null,
|
|
2012
|
+
groups2.map((group, index) => {
|
|
2013
|
+
const entries = catalog3.filter((entry) => entry.group === group);
|
|
2014
|
+
const activeIndex = entries.findIndex((entry) => entry.slug === activeSlug);
|
|
2015
|
+
return /* @__PURE__ */ jsx16(NavGroup, { id: `nav-grp-${index}`, title: group, active: activeIndex !== -1, activeIndex, children: entries.map((entry) => /* @__PURE__ */ jsx16(
|
|
1945
2016
|
"a",
|
|
1946
2017
|
{
|
|
1947
2018
|
href: routeHref(`/components/${entry.slug}`),
|
|
@@ -1952,9 +2023,9 @@ function DocsApp() {
|
|
|
1952
2023
|
children: entry.name
|
|
1953
2024
|
},
|
|
1954
2025
|
entry.slug
|
|
1955
|
-
))
|
|
1956
|
-
|
|
1957
|
-
] }),
|
|
2026
|
+
)) }, `${group}-${activeSlug ?? route.kind}`);
|
|
2027
|
+
})
|
|
2028
|
+
] }) }),
|
|
1958
2029
|
/* @__PURE__ */ jsx16("main", { id: "main", className: "main", tabIndex: -1, ref: mainRef, children: route.kind === "component" ? /* @__PURE__ */ jsx16(ComponentPage, { entry: catalog3.find((entry) => entry.slug === route.slug) }) : route.kind === "color" ? /* @__PURE__ */ jsx16(ColorPage, {}) : route.kind === "typography" ? /* @__PURE__ */ jsx16(TypePage, {}) : route.kind === "spacing" ? /* @__PURE__ */ jsx16(SpacingPage, {}) : route.kind === "effects" ? /* @__PURE__ */ jsx16(EffectsPage, {}) : route.kind === "releases" ? /* @__PURE__ */ jsx16(ReleasesPage, {}) : /* @__PURE__ */ jsx16(OverviewPage, {}) }),
|
|
1959
2030
|
route.kind !== "overview" ? /* @__PURE__ */ jsx16(PageRail, { pageKey: activeSlug ?? route.kind }) : null
|
|
1960
2031
|
] });
|
package/dist/rail.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function followRail(rail: HTMLElement, header: HTMLElement): () => void;
|
package/dist/sections.d.ts
CHANGED
|
@@ -13,6 +13,18 @@ export type DocsParameters = {
|
|
|
13
13
|
language?: string;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
+
export declare function frameSource(meta: {
|
|
17
|
+
args?: Record<string, unknown>;
|
|
18
|
+
parameters?: {
|
|
19
|
+
docs?: DocsParameters;
|
|
20
|
+
};
|
|
21
|
+
}, story: {
|
|
22
|
+
args?: Record<string, unknown>;
|
|
23
|
+
parameters?: {
|
|
24
|
+
docs?: DocsParameters;
|
|
25
|
+
};
|
|
26
|
+
}): string | undefined;
|
|
27
|
+
export declare const STORY_EXCERPT = "// Excerpt from the story";
|
|
16
28
|
export declare function mergeAnnotations(...values: Array<Record<string, unknown> | undefined>): Record<string, unknown>;
|
|
17
29
|
export interface StorySection {
|
|
18
30
|
title: string;
|
package/dist/styles.css
CHANGED
|
@@ -186,23 +186,44 @@ body {
|
|
|
186
186
|
outline-offset: 2px;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
.rail-track {
|
|
190
|
+
overflow-anchor: none;
|
|
191
|
+
min-width: 0;
|
|
192
|
+
}
|
|
193
|
+
@media (min-width: 1180px) {
|
|
194
|
+
.rail-track::before {
|
|
195
|
+
content: '';
|
|
196
|
+
display: block;
|
|
197
|
+
height: var(--sd-rail-offset, 0px);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
189
200
|
.nav {
|
|
190
201
|
border-right: 0;
|
|
191
202
|
background: var(--sd-surface);
|
|
192
|
-
padding: 14px 12px
|
|
193
|
-
/* Follows the document like the right rail, parking when its own end is visible. */
|
|
194
|
-
align-self: start;
|
|
195
|
-
transform: translateY(var(--sd-rail-follow, 0px));
|
|
203
|
+
padding: 14px 12px 12px;
|
|
196
204
|
}
|
|
197
|
-
.nav a
|
|
198
|
-
|
|
199
|
-
|
|
205
|
+
.nav a,
|
|
206
|
+
.nav-more {
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
box-sizing: border-box;
|
|
210
|
+
min-height: 28px;
|
|
211
|
+
padding: 4px 10px;
|
|
200
212
|
border-radius: 8px;
|
|
201
213
|
color: var(--sd-text-muted);
|
|
202
214
|
font-size: 13.5px;
|
|
203
215
|
text-decoration: none;
|
|
204
216
|
}
|
|
205
|
-
.nav
|
|
217
|
+
.nav-more {
|
|
218
|
+
width: 100%;
|
|
219
|
+
background: none;
|
|
220
|
+
border: 0;
|
|
221
|
+
font-family: inherit;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
text-align: left;
|
|
224
|
+
}
|
|
225
|
+
.nav a:hover,
|
|
226
|
+
.nav-more:hover {
|
|
206
227
|
background: var(--sd-surface-hover);
|
|
207
228
|
color: var(--sd-text);
|
|
208
229
|
}
|
|
@@ -212,13 +233,26 @@ body {
|
|
|
212
233
|
font-weight: 600;
|
|
213
234
|
}
|
|
214
235
|
.grp {
|
|
215
|
-
margin:
|
|
236
|
+
margin: 3px 0 2px;
|
|
216
237
|
padding: 0 10px;
|
|
217
238
|
font-size: 10.5px;
|
|
218
239
|
letter-spacing: 0.09em;
|
|
219
240
|
text-transform: uppercase;
|
|
220
241
|
color: var(--sd-text-muted);
|
|
221
242
|
font-weight: 700;
|
|
243
|
+
display: block;
|
|
244
|
+
width: 100%;
|
|
245
|
+
text-align: left;
|
|
246
|
+
font-family: inherit;
|
|
247
|
+
background: none;
|
|
248
|
+
border: 0;
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
min-height: 28px;
|
|
251
|
+
}
|
|
252
|
+
.grp:focus-visible,
|
|
253
|
+
.nav-more:focus-visible {
|
|
254
|
+
outline: 2px solid var(--sd-focus-ring);
|
|
255
|
+
outline-offset: 2px;
|
|
222
256
|
}
|
|
223
257
|
|
|
224
258
|
.main {
|
|
@@ -618,6 +652,9 @@ code.type {
|
|
|
618
652
|
.nav-toggle {
|
|
619
653
|
display: inline-block;
|
|
620
654
|
}
|
|
655
|
+
.nav-track {
|
|
656
|
+
display: contents;
|
|
657
|
+
}
|
|
621
658
|
.search {
|
|
622
659
|
order: 10;
|
|
623
660
|
flex: 1 1 100%;
|
package/dist/toc.d.ts
CHANGED
|
@@ -6,12 +6,6 @@ export declare function hashPath(hash: string): string;
|
|
|
6
6
|
/** The `?story=` deep-link target of a hash, if any. */
|
|
7
7
|
export declare function storyFromHash(hash: string): string | null;
|
|
8
8
|
export declare function storyLink(location: Location, story: string): string;
|
|
9
|
-
/**
|
|
10
|
-
* A rail travels with the document until its own end would pass the fold, then it parks there —
|
|
11
|
-
* the reader keeps seeing where it continues, and scrolling up lets it fall back into flow. This is
|
|
12
|
-
* the scroll-linked translation docs sites use, because `position: sticky` cannot move an element
|
|
13
|
-
* taller than the viewport.
|
|
14
|
-
*/
|
|
15
9
|
export declare function useRailFollow(ref: RefObject<HTMLElement | null>, ready?: boolean): void;
|
|
16
10
|
/** The "On this page" rail and the `?story=` deep-link landing. */
|
|
17
11
|
export declare function PageRail({ pageKey }: {
|
package/dist/vite-plugin.js
CHANGED
|
@@ -609,58 +609,110 @@ export const cleanup = () => {};
|
|
|
609
609
|
`;
|
|
610
610
|
|
|
611
611
|
// src/build/story-sources.ts
|
|
612
|
+
import ts3 from "typescript";
|
|
613
|
+
|
|
614
|
+
// src/sections.ts
|
|
615
|
+
var STORY_EXCERPT = "// Excerpt from the story";
|
|
616
|
+
|
|
617
|
+
// src/build/snippet-bindings.ts
|
|
612
618
|
import ts2 from "typescript";
|
|
619
|
+
var options = { target: ts2.ScriptTarget.Latest, jsx: ts2.JsxEmit.Preserve, noLib: true };
|
|
620
|
+
var UNRESOLVED_NAME_DIAGNOSTICS = /* @__PURE__ */ new Set([2304, 2552, 2580, 2581, 2582, 2591, 2592, 18004]);
|
|
621
|
+
function snippetProgram(file) {
|
|
622
|
+
const host = ts2.createCompilerHost(options);
|
|
623
|
+
host.getSourceFile = (name) => name === file.fileName ? file : void 0;
|
|
624
|
+
return ts2.createProgram([file.fileName], options, host);
|
|
625
|
+
}
|
|
626
|
+
var globals;
|
|
627
|
+
function globalNames() {
|
|
628
|
+
if (!globals) {
|
|
629
|
+
const host = ts2.createCompilerHost({ target: ts2.ScriptTarget.Latest });
|
|
630
|
+
const lib = host.getDefaultLibFileName({ target: ts2.ScriptTarget.Latest });
|
|
631
|
+
const libraries = ts2.createProgram([lib], { target: ts2.ScriptTarget.Latest });
|
|
632
|
+
const file = libraries.getSourceFile(lib);
|
|
633
|
+
globals = new Set(libraries.getTypeChecker().getSymbolsInScope(file, ts2.SymbolFlags.Value).map((symbol) => symbol.name));
|
|
634
|
+
}
|
|
635
|
+
return globals;
|
|
636
|
+
}
|
|
637
|
+
function unresolvedSnippetBindings(source, localTags = /* @__PURE__ */ new Set()) {
|
|
638
|
+
const file = ts2.createSourceFile("snippet.tsx", `declare const args: any;
|
|
639
|
+
${source}`, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
|
|
640
|
+
const program = snippetProgram(file);
|
|
641
|
+
const expression = file.statements.find(ts2.isExpressionStatement)?.expression;
|
|
642
|
+
const rootTag = expression && (ts2.isJsxElement(expression) ? expression.openingElement.tagName : ts2.isJsxSelfClosingElement(expression) ? expression.tagName : void 0);
|
|
643
|
+
const publicRoot = rootTag?.getText(file).split(".")[0];
|
|
644
|
+
const identifiers = /* @__PURE__ */ new Map();
|
|
645
|
+
const visit = (node) => {
|
|
646
|
+
if (ts2.isIdentifier(node)) identifiers.set(node.getStart(file), node);
|
|
647
|
+
ts2.forEachChild(node, visit);
|
|
648
|
+
};
|
|
649
|
+
visit(file);
|
|
650
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
651
|
+
for (const diagnostic of program.getSemanticDiagnostics(file)) {
|
|
652
|
+
if (!UNRESOLVED_NAME_DIAGNOSTICS.has(diagnostic.code) || diagnostic.start === void 0) continue;
|
|
653
|
+
const node = identifiers.get(diagnostic.start);
|
|
654
|
+
if (!node) continue;
|
|
655
|
+
let tag = node;
|
|
656
|
+
while (ts2.isPropertyAccessExpression(tag.parent) && tag.parent.expression === tag) tag = tag.parent;
|
|
657
|
+
const jsxTag = (ts2.isJsxOpeningElement(tag.parent) || ts2.isJsxClosingElement(tag.parent) || ts2.isJsxSelfClosingElement(tag.parent)) && tag.parent.tagName === tag;
|
|
658
|
+
if (!(jsxTag && node.text === publicRoot && !localTags.has(node.text)) && !globalNames().has(node.text)) unresolved.add(node.text);
|
|
659
|
+
}
|
|
660
|
+
return [...unresolved].sort();
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/build/story-sources.ts
|
|
613
664
|
function unwrap(node) {
|
|
614
|
-
while (
|
|
665
|
+
while (ts3.isParenthesizedExpression(node) || ts3.isAsExpression(node) || ts3.isSatisfiesExpression(node) || ts3.isTypeAssertionExpression(node)) node = node.expression;
|
|
615
666
|
return node;
|
|
616
667
|
}
|
|
617
668
|
var MAX_HELPER_DEPTH = 3;
|
|
618
669
|
function extractStorySourceDetails(source) {
|
|
619
|
-
const file =
|
|
670
|
+
const file = ts3.createSourceFile("stories.tsx", source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
|
|
671
|
+
const checker = snippetProgram(file).getTypeChecker();
|
|
620
672
|
const declarations = /* @__PURE__ */ new Map();
|
|
621
673
|
const exports = /* @__PURE__ */ new Map();
|
|
622
674
|
for (const statement of file.statements) {
|
|
623
|
-
const exported =
|
|
624
|
-
if (
|
|
675
|
+
const exported = ts3.canHaveModifiers(statement) && ts3.getModifiers(statement)?.some((modifier) => modifier.kind === ts3.SyntaxKind.ExportKeyword);
|
|
676
|
+
if (ts3.isVariableStatement(statement)) {
|
|
625
677
|
for (const declaration of statement.declarationList.declarations) {
|
|
626
|
-
if (!
|
|
678
|
+
if (!ts3.isIdentifier(declaration.name) || !declaration.initializer) continue;
|
|
627
679
|
declarations.set(declaration.name.text, declaration.initializer);
|
|
628
680
|
if (exported) exports.set(declaration.name.text, declaration.name.text);
|
|
629
681
|
}
|
|
630
|
-
} else if (
|
|
682
|
+
} else if (ts3.isFunctionDeclaration(statement) && statement.name) {
|
|
631
683
|
declarations.set(statement.name.text, statement);
|
|
632
684
|
if (exported) exports.set(statement.name.text, statement.name.text);
|
|
633
|
-
} else if (
|
|
685
|
+
} else if (ts3.isExportDeclaration(statement) && !statement.moduleSpecifier && statement.exportClause && ts3.isNamedExports(statement.exportClause)) {
|
|
634
686
|
for (const element of statement.exportClause.elements) {
|
|
635
687
|
exports.set(element.name.text, (element.propertyName ?? element.name).text);
|
|
636
688
|
}
|
|
637
689
|
}
|
|
638
690
|
}
|
|
639
691
|
const renderFor = (node, seen = /* @__PURE__ */ new Set()) => {
|
|
640
|
-
if (
|
|
692
|
+
if (ts3.isFunctionDeclaration(node)) return node;
|
|
641
693
|
node = unwrap(node);
|
|
642
|
-
if (
|
|
694
|
+
if (ts3.isIdentifier(node)) {
|
|
643
695
|
if (seen.has(node.text)) return;
|
|
644
696
|
seen.add(node.text);
|
|
645
697
|
const declaration = declarations.get(node.text);
|
|
646
698
|
return declaration ? renderFor(declaration, seen) : void 0;
|
|
647
699
|
}
|
|
648
|
-
if (
|
|
649
|
-
if (
|
|
650
|
-
if (!
|
|
700
|
+
if (ts3.isPropertyAccessExpression(node) && node.name.text === "render" || ts3.isElementAccessExpression(node) && ts3.isStringLiteral(node.argumentExpression) && node.argumentExpression.text === "render") return renderFor(node.expression, seen);
|
|
701
|
+
if (ts3.isArrowFunction(node) || ts3.isFunctionExpression(node)) return node;
|
|
702
|
+
if (!ts3.isObjectLiteralExpression(node)) return;
|
|
651
703
|
for (const property of [...node.properties].reverse()) {
|
|
652
|
-
if (
|
|
704
|
+
if (ts3.isSpreadAssignment(property)) {
|
|
653
705
|
const render = renderFor(property.expression, new Set(seen));
|
|
654
706
|
if (render !== void 0) return render;
|
|
655
|
-
} else if (property.name && (
|
|
656
|
-
if (
|
|
657
|
-
if (
|
|
658
|
-
if (
|
|
707
|
+
} else if (property.name && (ts3.isIdentifier(property.name) || ts3.isStringLiteral(property.name)) && property.name.text === "render") {
|
|
708
|
+
if (ts3.isMethodDeclaration(property)) return property;
|
|
709
|
+
if (ts3.isPropertyAssignment(property)) return renderFor(property.initializer, seen) ?? null;
|
|
710
|
+
if (ts3.isShorthandPropertyAssignment(property)) return renderFor(property.name, seen) ?? null;
|
|
659
711
|
return null;
|
|
660
712
|
}
|
|
661
713
|
}
|
|
662
714
|
};
|
|
663
|
-
const hasJsx = (node) =>
|
|
715
|
+
const hasJsx = (node) => ts3.isJsxElement(node) || ts3.isJsxSelfClosingElement(node) || ts3.isJsxFragment(node) || (ts3.forEachChild(node, hasJsx) ?? false);
|
|
664
716
|
const returnsCache = /* @__PURE__ */ new Map();
|
|
665
717
|
const returnCounts = /* @__PURE__ */ new Map();
|
|
666
718
|
const returnedJsx = (render) => {
|
|
@@ -669,17 +721,17 @@ function extractStorySourceDetails(source) {
|
|
|
669
721
|
const expressions = [];
|
|
670
722
|
if (!render.body) return expressions;
|
|
671
723
|
let returnCount = 0;
|
|
672
|
-
if (
|
|
724
|
+
if (ts3.isBlock(render.body)) {
|
|
673
725
|
const visit = (node) => {
|
|
674
|
-
if (
|
|
675
|
-
if (
|
|
726
|
+
if (ts3.isFunctionLike(node)) return;
|
|
727
|
+
if (ts3.isReturnStatement(node)) {
|
|
676
728
|
returnCount += 1;
|
|
677
729
|
if (node.expression && hasJsx(node.expression)) expressions.push(unwrap(node.expression));
|
|
678
730
|
return;
|
|
679
731
|
}
|
|
680
|
-
|
|
732
|
+
ts3.forEachChild(node, visit);
|
|
681
733
|
};
|
|
682
|
-
|
|
734
|
+
ts3.forEachChild(render.body, visit);
|
|
683
735
|
} else {
|
|
684
736
|
returnCount = 1;
|
|
685
737
|
if (hasJsx(render.body)) expressions.push(unwrap(render.body));
|
|
@@ -693,16 +745,16 @@ function extractStorySourceDetails(source) {
|
|
|
693
745
|
seen.add(name);
|
|
694
746
|
const declaration = declarations.get(name);
|
|
695
747
|
if (!declaration) return;
|
|
696
|
-
if (
|
|
748
|
+
if (ts3.isFunctionDeclaration(declaration)) return declaration;
|
|
697
749
|
const expression = unwrap(declaration);
|
|
698
|
-
if (
|
|
699
|
-
if (
|
|
750
|
+
if (ts3.isIdentifier(expression)) return helperFor(expression.text, seen);
|
|
751
|
+
if (ts3.isArrowFunction(expression) || ts3.isFunctionExpression(expression)) return expression;
|
|
700
752
|
};
|
|
701
|
-
const bindingContains = (binding, name) =>
|
|
753
|
+
const bindingContains = (binding, name) => ts3.isIdentifier(binding) ? binding.text === name : binding.elements.some((element) => ts3.isBindingElement(element) && bindingContains(element.name, name));
|
|
702
754
|
const isShadowed = (expression, name) => {
|
|
703
755
|
for (let node = expression.parent; node; node = node.parent) {
|
|
704
|
-
if (
|
|
705
|
-
if (
|
|
756
|
+
if (ts3.isFunctionLike(node) && node.parameters.some((parameter) => bindingContains(parameter.name, name))) return true;
|
|
757
|
+
if (ts3.isBlock(node) && node.statements.some((statement) => ts3.isVariableStatement(statement) && statement.declarationList.declarations.some((declaration) => bindingContains(declaration.name, name)) || ts3.isFunctionDeclaration(statement) && statement.name?.text === name)) return true;
|
|
706
758
|
}
|
|
707
759
|
return false;
|
|
708
760
|
};
|
|
@@ -712,24 +764,24 @@ function extractStorySourceDetails(source) {
|
|
|
712
764
|
if (cached !== void 0) return cached;
|
|
713
765
|
const bindings = /* @__PURE__ */ new Map();
|
|
714
766
|
for (const [name, declaration] of declarations) {
|
|
715
|
-
bindings.set(name,
|
|
767
|
+
bindings.set(name, ts3.isFunctionDeclaration(declaration) ? void 0 : declaration);
|
|
716
768
|
}
|
|
717
769
|
const bind = (scope2, name, initializer) => {
|
|
718
|
-
if (
|
|
770
|
+
if (ts3.isIdentifier(name)) scope2.set(name.text, initializer);
|
|
719
771
|
else for (const element of name.elements) {
|
|
720
|
-
if (
|
|
772
|
+
if (ts3.isBindingElement(element)) bind(scope2, element.name, element.initializer);
|
|
721
773
|
}
|
|
722
774
|
};
|
|
723
775
|
const addScope = (node, parent) => {
|
|
724
776
|
const scope2 = new Map(parent);
|
|
725
|
-
if (
|
|
777
|
+
if (ts3.isFunctionLike(node)) {
|
|
726
778
|
for (const parameter of node.parameters) bind(scope2, parameter.name, parameter.initializer);
|
|
727
779
|
}
|
|
728
|
-
if (
|
|
780
|
+
if (ts3.isBlock(node)) {
|
|
729
781
|
for (const statement of node.statements) {
|
|
730
|
-
if (
|
|
782
|
+
if (ts3.isVariableStatement(statement)) {
|
|
731
783
|
for (const declaration of statement.declarationList.declarations) bind(scope2, declaration.name, declaration.initializer);
|
|
732
|
-
} else if (
|
|
784
|
+
} else if (ts3.isFunctionDeclaration(statement) && statement.name) scope2.set(statement.name.text, void 0);
|
|
733
785
|
}
|
|
734
786
|
}
|
|
735
787
|
return scope2;
|
|
@@ -740,55 +792,84 @@ function extractStorySourceDetails(source) {
|
|
|
740
792
|
for (const node of ancestors.reverse()) scope = addScope(node, scope);
|
|
741
793
|
const knownCollection = (expression, bindings2, seen = /* @__PURE__ */ new Set()) => {
|
|
742
794
|
expression = unwrap(expression);
|
|
743
|
-
if (
|
|
744
|
-
return expression.elements.every((element) => !
|
|
795
|
+
if (ts3.isArrayLiteralExpression(expression)) {
|
|
796
|
+
return expression.elements.every((element) => !ts3.isSpreadElement(element) || knownCollection(element.expression, bindings2, new Set(seen)));
|
|
745
797
|
}
|
|
746
|
-
if (
|
|
798
|
+
if (ts3.isIdentifier(expression)) {
|
|
747
799
|
if (seen.has(expression.text)) return false;
|
|
748
800
|
seen.add(expression.text);
|
|
749
801
|
const initializer = bindings2.get(expression.text);
|
|
750
802
|
return Boolean(initializer && knownCollection(initializer, bindings2, seen));
|
|
751
803
|
}
|
|
752
|
-
if (
|
|
804
|
+
if (ts3.isCallExpression(expression) && ts3.isPropertyAccessExpression(expression.expression) && ["slice", "filter", "toSorted", "toReversed"].includes(expression.expression.name.text)) {
|
|
753
805
|
return knownCollection(expression.expression.expression, bindings2, seen);
|
|
754
806
|
}
|
|
755
807
|
return false;
|
|
756
808
|
};
|
|
757
809
|
const visit = (node, bindings2) => {
|
|
758
|
-
if (
|
|
759
|
-
if (
|
|
810
|
+
if (ts3.isFunctionLike(node) || ts3.isBlock(node)) bindings2 = addScope(node, bindings2);
|
|
811
|
+
if (ts3.isCallExpression(node)) {
|
|
760
812
|
const target = node.expression;
|
|
761
|
-
const map =
|
|
813
|
+
const map = ts3.isPropertyAccessExpression(target) && target.name.text === "map" || ts3.isElementAccessExpression(target) && ts3.isStringLiteral(target.argumentExpression) && target.argumentExpression.text === "map";
|
|
762
814
|
if (map && !knownCollection(target.expression, bindings2)) return true;
|
|
763
815
|
}
|
|
764
|
-
return
|
|
816
|
+
return ts3.forEachChild(node, (child) => visit(child, bindings2)) ?? false;
|
|
765
817
|
};
|
|
766
818
|
const unknown = visit(jsx, scope);
|
|
767
819
|
mapCache.set(jsx, unknown);
|
|
768
820
|
return unknown;
|
|
769
821
|
};
|
|
770
|
-
const
|
|
771
|
-
const
|
|
772
|
-
const
|
|
822
|
+
const textWithBindings = (expression, bindings) => {
|
|
823
|
+
const edits = [];
|
|
824
|
+
const visit = (node) => {
|
|
825
|
+
if (ts3.isIdentifier(node)) {
|
|
826
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
827
|
+
const text2 = symbol && bindings.get(symbol);
|
|
828
|
+
const parent = node.parent;
|
|
829
|
+
const tag = (ts3.isJsxOpeningElement(parent) || ts3.isJsxClosingElement(parent) || ts3.isJsxSelfClosingElement(parent)) && parent.tagName === node;
|
|
830
|
+
if (text2 && !tag) edits.push({
|
|
831
|
+
start: node.getStart(file) - expression.getStart(file),
|
|
832
|
+
end: node.end - expression.getStart(file),
|
|
833
|
+
text: ts3.isShorthandPropertyAssignment(parent) ? `${node.text}: ${text2}` : text2
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
ts3.forEachChild(node, visit);
|
|
837
|
+
};
|
|
838
|
+
visit(expression);
|
|
839
|
+
let text = expression.getText(file);
|
|
840
|
+
for (const edit of edits.reverse()) text = text.slice(0, edit.start) + edit.text + text.slice(edit.end);
|
|
841
|
+
return text;
|
|
842
|
+
};
|
|
843
|
+
const inlineRoot = (expression, detail, trail = [], bindings = /* @__PURE__ */ new Map()) => {
|
|
844
|
+
const tag = ts3.isJsxElement(expression) ? expression.openingElement.tagName : ts3.isJsxSelfClosingElement(expression) ? expression.tagName : void 0;
|
|
845
|
+
const name = tag && ts3.isIdentifier(tag) && /^[A-Z]/.test(tag.text) ? tag.text : void 0;
|
|
773
846
|
const helper = name && helperFor(name);
|
|
774
|
-
if (!name || !declarations.has(name)) return expression
|
|
847
|
+
if (!name || !declarations.has(name)) return textWithBindings(expression, bindings);
|
|
775
848
|
if (!helper) {
|
|
776
849
|
const reason2 = "local definition is not a direct function";
|
|
777
850
|
detail.remaining.push({ name, reason: reason2 });
|
|
778
851
|
return `// ${name} not expanded: ${reason2}.
|
|
779
|
-
${expression
|
|
852
|
+
${textWithBindings(expression, bindings)}`;
|
|
780
853
|
}
|
|
781
854
|
const returned = returnedJsx(helper);
|
|
782
855
|
const jsx = returned[0];
|
|
783
|
-
const reason = isShadowed(expression, name) ? "file helper is shadowed in this scope" : trail.includes(name) ? "recursive helper cycle" : trail.length >= MAX_HELPER_DEPTH ? `helper depth limit (${MAX_HELPER_DEPTH})` : returnCounts.get(helper) !== 1 || returned.length !== 1 || !jsx || !(
|
|
856
|
+
const reason = isShadowed(expression, name) ? "file helper is shadowed in this scope" : trail.includes(name) ? "recursive helper cycle" : trail.length >= MAX_HELPER_DEPTH ? `helper depth limit (${MAX_HELPER_DEPTH})` : returnCounts.get(helper) !== 1 || returned.length !== 1 || !jsx || !(ts3.isJsxElement(jsx) || ts3.isJsxSelfClosingElement(jsx) || ts3.isJsxFragment(jsx)) ? "no single literal JSX return" : hasUnknownMap(helper, jsx) ? "maps over a collection without a local array definition" : void 0;
|
|
784
857
|
if (reason) {
|
|
785
858
|
detail.remaining.push({ name, reason });
|
|
786
859
|
return `// ${name} not expanded: ${reason}.
|
|
787
|
-
${expression
|
|
860
|
+
${textWithBindings(expression, bindings)}`;
|
|
788
861
|
}
|
|
789
862
|
detail.inlined.push(name);
|
|
863
|
+
const attributes = ts3.isJsxElement(expression) ? expression.openingElement.attributes : ts3.isJsxSelfClosingElement(expression) ? expression.attributes : void 0;
|
|
864
|
+
const parameter = helper.parameters[0]?.name;
|
|
865
|
+
const rootAttributes = ts3.isJsxElement(jsx) ? jsx.openingElement.attributes : ts3.isJsxSelfClosingElement(jsx) ? jsx.attributes : void 0;
|
|
866
|
+
const spread = attributes?.properties.length === 1 ? attributes.properties[0] : void 0;
|
|
867
|
+
if (parameter && ts3.isIdentifier(parameter) && spread && ts3.isJsxSpreadAttribute(spread) && textWithBindings(spread.expression, bindings) === "args" && rootAttributes?.properties.some((prop) => ts3.isJsxSpreadAttribute(prop) && ts3.isIdentifier(prop.expression) && prop.expression.text === parameter.text)) {
|
|
868
|
+
const symbol = checker.getSymbolAtLocation(parameter);
|
|
869
|
+
if (symbol) bindings = new Map(bindings).set(symbol, "args");
|
|
870
|
+
}
|
|
790
871
|
return `// JSX from ${name}, as authored.
|
|
791
|
-
${inlineRoot(jsx, detail, [...trail, name])}`;
|
|
872
|
+
${inlineRoot(jsx, detail, [...trail, name], bindings)}`;
|
|
792
873
|
};
|
|
793
874
|
const sources = {};
|
|
794
875
|
const helpers = {};
|
|
@@ -799,8 +880,16 @@ ${inlineRoot(jsx, detail, [...trail, name])}`;
|
|
|
799
880
|
const expressions = returnedJsx(render);
|
|
800
881
|
if (expressions.length) {
|
|
801
882
|
const detail = { inlined: [], remaining: [] };
|
|
802
|
-
const
|
|
803
|
-
|
|
883
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
884
|
+
const parameter = render.parameters[0]?.name;
|
|
885
|
+
if (parameter && ts3.isIdentifier(parameter)) {
|
|
886
|
+
const symbol = checker.getSymbolAtLocation(parameter);
|
|
887
|
+
if (symbol) bindings.set(symbol, "args");
|
|
888
|
+
}
|
|
889
|
+
const jsx = expressions.map((expression) => inlineRoot(expression, detail, [], bindings)).join("\n\n");
|
|
890
|
+
const unresolved = unresolvedSnippetBindings(jsx, new Set(declarations.keys()));
|
|
891
|
+
const incomplete = detail.remaining.length || unresolved.length || expressions.length > 1;
|
|
892
|
+
sources[name] = incomplete ? `${STORY_EXCERPT}${unresolved.length ? `; unresolved bindings: ${unresolved.join(", ")}` : "; multiple return branches"}.
|
|
804
893
|
${jsx}` : jsx;
|
|
805
894
|
if (detail.inlined.length || detail.remaining.length) helpers[name] = detail;
|
|
806
895
|
}
|
|
@@ -825,9 +914,9 @@ function storySourcesCode(sources) {
|
|
|
825
914
|
}
|
|
826
915
|
|
|
827
916
|
// src/vite-plugin.ts
|
|
828
|
-
function storybookDocs(
|
|
829
|
-
const { config } =
|
|
830
|
-
let projectRoot =
|
|
917
|
+
function storybookDocs(options2) {
|
|
918
|
+
const { config } = options2;
|
|
919
|
+
let projectRoot = options2.root ?? process.cwd();
|
|
831
920
|
let catalog = buildCatalog(scanStories(config.stories, projectRoot), config.groups);
|
|
832
921
|
catalog.files.clear();
|
|
833
922
|
const engineStyles = path7.join(import.meta.dirname, "styles.css");
|
|
@@ -874,7 +963,7 @@ export const storySource = ${JSON.stringify(config.stories.from)};`,
|
|
|
874
963
|
},
|
|
875
964
|
configResolved(resolved) {
|
|
876
965
|
propsCollector.setBuildMode(resolved.command === "build");
|
|
877
|
-
projectRoot =
|
|
966
|
+
projectRoot = options2.root ?? resolved.root;
|
|
878
967
|
catalog = buildCatalog(scanStories(config.stories, projectRoot), config.groups);
|
|
879
968
|
guidanceFiles = indexGuidance(config.guidance, projectRoot);
|
|
880
969
|
this.info?.(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jfrader/storybook-docs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A documentation front for any design system that has Storybook: navigation, live examples and API tables are generated from the story files themselves.",
|
|
6
6
|
"exports": {
|