@jfrader/storybook-docs 0.8.0 → 0.9.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/index.css +7 -2
- package/dist/index.js +67 -24
- package/dist/styles.css +1 -1
- package/dist/toc.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.css
CHANGED
|
@@ -115,11 +115,13 @@
|
|
|
115
115
|
}
|
|
116
116
|
.toc-track {
|
|
117
117
|
display: block;
|
|
118
|
+
min-width: 0;
|
|
118
119
|
grid-column: 3;
|
|
119
120
|
grid-row: 2;
|
|
120
121
|
}
|
|
121
122
|
.toc {
|
|
122
123
|
display: block;
|
|
124
|
+
min-width: 0;
|
|
123
125
|
padding: 34px 18px 40px 6px;
|
|
124
126
|
font-size: 12.5px;
|
|
125
127
|
}
|
|
@@ -140,9 +142,12 @@
|
|
|
140
142
|
border-left: 1px solid var(--sd-border);
|
|
141
143
|
}
|
|
142
144
|
.toc-link {
|
|
143
|
-
display:
|
|
144
|
-
align-items: center;
|
|
145
|
+
display: block;
|
|
145
146
|
width: 100%;
|
|
147
|
+
min-width: 0;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
white-space: nowrap;
|
|
150
|
+
text-overflow: ellipsis;
|
|
146
151
|
min-block-size: 24px;
|
|
147
152
|
padding: 4px 8px;
|
|
148
153
|
font: inherit;
|
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 { useEffect as useEffect8, useLayoutEffect as useLayoutEffect2, 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
|
|
|
@@ -363,6 +363,9 @@ function serializable(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
|
363
363
|
ancestors.delete(value);
|
|
364
364
|
return result;
|
|
365
365
|
}
|
|
366
|
+
function jsxRootTag(example) {
|
|
367
|
+
return example.replace(/^\s*\/\/[^\n]*(?:\n|$)/gm, "").match(/<([A-Za-z_$][\w$]*(?:\.[\w$]+)*)[\s/>]/)?.[1]?.split(".")[0];
|
|
368
|
+
}
|
|
366
369
|
function usageSnippet(componentName, args) {
|
|
367
370
|
if (!args || Object.keys(args).length === 0) return null;
|
|
368
371
|
const attributes = [];
|
|
@@ -374,8 +377,8 @@ function usageSnippet(componentName, args) {
|
|
|
374
377
|
else attributes.push(`${key}={${JSON.stringify(value)}}`);
|
|
375
378
|
}
|
|
376
379
|
const opening = `<${componentName}${attributes.length ? ` ${attributes.join(" ")}` : ""}`;
|
|
377
|
-
if (args.children === void 0) return attributes.length ? `${opening} />` : null;
|
|
378
|
-
if (!serializable(args.children) ||
|
|
380
|
+
if (args.children === void 0 || args.children === null) return attributes.length ? `${opening} />` : null;
|
|
381
|
+
if (!serializable(args.children) || typeof args.children === "object") return null;
|
|
379
382
|
const children = typeof args.children === "string" && !/[&<>{}]/.test(args.children) ? args.children : `{${JSON.stringify(args.children)}}`;
|
|
380
383
|
return `${opening}>${children}</${componentName}>`;
|
|
381
384
|
}
|
|
@@ -389,11 +392,12 @@ function buildUsageSnippet({ componentName, from, args, source, renderSource, js
|
|
|
389
392
|
const excerpt = extracted?.startsWith(STORY_EXCERPT);
|
|
390
393
|
const example = source?.trim() || (excerpt ? generated() || extracted : extracted || generated());
|
|
391
394
|
if (!example) return null;
|
|
395
|
+
const rootTag = jsxRootTag(example);
|
|
392
396
|
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
397
|
if (excerpt || rootTag !== rootName || !from.trim()) return example;
|
|
395
398
|
}
|
|
396
399
|
if (!from.trim()) return example;
|
|
400
|
+
if (rootTag !== rootName) return example;
|
|
397
401
|
const imports = [...example.matchAll(/import\s*\{([^}]+)\}\s*from\s*(['"])(.*?)\2/g)];
|
|
398
402
|
const imported = imports.some((match) => match[3] === from && match[1].split(",").some((name) => name.trim() === rootName));
|
|
399
403
|
return imported ? example : `import { ${rootName} } from '${from}';
|
|
@@ -522,11 +526,12 @@ function LazySection({ children, placeholder = "\u2026" }) {
|
|
|
522
526
|
}
|
|
523
527
|
|
|
524
528
|
// src/toc.tsx
|
|
525
|
-
import { useCallback, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
529
|
+
import { useCallback, useEffect as useEffect3, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
526
530
|
|
|
527
531
|
// src/rail.ts
|
|
528
532
|
var RAIL_MEDIA = "(min-width: 1180px)";
|
|
529
533
|
var RAIL_GAP = 20;
|
|
534
|
+
var RAIL_SETTLE_MS = 120;
|
|
530
535
|
function followRail(rail, header) {
|
|
531
536
|
const track = rail.parentElement;
|
|
532
537
|
if (!track) return () => {
|
|
@@ -535,6 +540,8 @@ function followRail(rail, header) {
|
|
|
535
540
|
let lastY = window.scrollY;
|
|
536
541
|
let direction = "down";
|
|
537
542
|
let spacer = 0;
|
|
543
|
+
let scrolling = false;
|
|
544
|
+
let settleTimer;
|
|
538
545
|
const geometry = () => {
|
|
539
546
|
const top = header.offsetHeight + RAIL_GAP;
|
|
540
547
|
const viewportBottom = window.innerHeight - RAIL_GAP;
|
|
@@ -544,8 +551,8 @@ function followRail(rail, header) {
|
|
|
544
551
|
viewportBottom,
|
|
545
552
|
height,
|
|
546
553
|
fits: top + height <= viewportBottom,
|
|
547
|
-
trackTop: track.getBoundingClientRect().top + window.scrollY,
|
|
548
|
-
maxOffset: Math.max(0, track.clientHeight - height)
|
|
554
|
+
trackTop: track.getBoundingClientRect().top + window.scrollY + RAIL_GAP,
|
|
555
|
+
maxOffset: Math.max(0, track.clientHeight - height - RAIL_GAP)
|
|
549
556
|
};
|
|
550
557
|
};
|
|
551
558
|
const clear = () => {
|
|
@@ -558,17 +565,28 @@ function followRail(rail, header) {
|
|
|
558
565
|
return;
|
|
559
566
|
}
|
|
560
567
|
spacer = g.fits ? 0 : Math.min(spacer, g.maxOffset);
|
|
568
|
+
track.style.setProperty("--sd-rail-start", `${RAIL_GAP}px`);
|
|
561
569
|
track.style.setProperty("--sd-rail-offset", `${spacer}px`);
|
|
562
570
|
rail.style.position = "sticky";
|
|
563
|
-
|
|
571
|
+
const parkedTop = g.fits ? g.top : g.viewportBottom - g.height;
|
|
572
|
+
const armedTop = Number.parseFloat(rail.style.top);
|
|
573
|
+
const stableTop = scrolling && Number.isFinite(armedTop) ? Math.min(armedTop, parkedTop) : parkedTop;
|
|
574
|
+
rail.style.top = g.fits || direction === "down" ? `${stableTop}px` : "auto";
|
|
564
575
|
rail.style.bottom = g.fits || direction === "down" ? "auto" : `${window.innerHeight - g.top - g.height}px`;
|
|
565
576
|
};
|
|
566
577
|
const onScroll = () => {
|
|
567
578
|
const y = window.scrollY;
|
|
579
|
+
scrolling = true;
|
|
580
|
+
window.clearTimeout(settleTimer);
|
|
581
|
+
settleTimer = window.setTimeout(() => {
|
|
582
|
+
scrolling = false;
|
|
583
|
+
arm();
|
|
584
|
+
}, RAIL_SETTLE_MS);
|
|
568
585
|
const next = y > lastY ? "down" : y < lastY ? "up" : direction;
|
|
569
586
|
if (next !== direction && media.matches) {
|
|
570
587
|
const g = geometry();
|
|
571
|
-
|
|
588
|
+
const armedTop = Number.parseFloat(rail.style.top);
|
|
589
|
+
spacer = direction === "down" ? Math.min(Math.max(spacer, lastY + (Number.isFinite(armedTop) ? armedTop : g.viewportBottom - g.height) - g.trackTop), g.maxOffset) : Math.max(Math.min(spacer, lastY + g.top - g.trackTop), 0);
|
|
572
590
|
direction = next;
|
|
573
591
|
arm(g);
|
|
574
592
|
}
|
|
@@ -586,6 +604,7 @@ function followRail(rail, header) {
|
|
|
586
604
|
arm();
|
|
587
605
|
return () => {
|
|
588
606
|
observer.disconnect();
|
|
607
|
+
window.clearTimeout(settleTimer);
|
|
589
608
|
window.removeEventListener("scroll", onScroll);
|
|
590
609
|
window.removeEventListener("resize", relayout);
|
|
591
610
|
media.removeEventListener("change", relayout);
|
|
@@ -615,13 +634,13 @@ function storyLink(location, story) {
|
|
|
615
634
|
return `${base}${hashPath(location.hash)}?${new URLSearchParams({ [STORY_PARAM]: story })}`;
|
|
616
635
|
}
|
|
617
636
|
var slugify = (text) => text.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
618
|
-
function useRailFollow(ref, ready = true) {
|
|
619
|
-
|
|
637
|
+
function useRailFollow(ref, ready = true, pageKey) {
|
|
638
|
+
useLayoutEffect(() => {
|
|
620
639
|
const element = ref.current;
|
|
621
640
|
const header = element?.closest(".app")?.querySelector(".top");
|
|
622
|
-
if (!element || !header) return;
|
|
641
|
+
if (!ready || !element || !header) return;
|
|
623
642
|
return followRail(element, header);
|
|
624
|
-
}, [ready, ref]);
|
|
643
|
+
}, [ready, ref, pageKey]);
|
|
625
644
|
}
|
|
626
645
|
function scanPage(root, pageKey) {
|
|
627
646
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -677,11 +696,14 @@ function scanPage(root, pageKey) {
|
|
|
677
696
|
var signature = (scan) => `${scan.pageKey}|${scan.sections.map((s) => `${s.id}(${s.subs.map((sub) => sub.id).join("+")}):${s.stories.map((st) => `${st.id}:${st.name}`).join(",")}`).join(";")}`;
|
|
678
697
|
var prefersReducedMotion = () => window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
679
698
|
function scrollToElement(element) {
|
|
699
|
+
const hash = window.location.hash;
|
|
680
700
|
element.scrollIntoView({ behavior: prefersReducedMotion() ? "auto" : "smooth", block: "start" });
|
|
681
701
|
let ticks = SETTLE_TICKS;
|
|
682
702
|
let lastY = window.scrollY;
|
|
703
|
+
let timer;
|
|
704
|
+
let cancelled = false;
|
|
683
705
|
const settle = () => {
|
|
684
|
-
if (!element.isConnected || ticks === 0) return;
|
|
706
|
+
if (cancelled || window.location.hash !== hash || !element.isConnected || ticks === 0) return;
|
|
685
707
|
ticks -= 1;
|
|
686
708
|
const moving = window.scrollY !== lastY;
|
|
687
709
|
lastY = window.scrollY;
|
|
@@ -689,9 +711,13 @@ function scrollToElement(element) {
|
|
|
689
711
|
element.scrollIntoView({ behavior: "auto", block: "start" });
|
|
690
712
|
lastY = window.scrollY;
|
|
691
713
|
}
|
|
692
|
-
window.setTimeout(settle, SETTLE_TICK_MS);
|
|
714
|
+
timer = window.setTimeout(settle, SETTLE_TICK_MS);
|
|
715
|
+
};
|
|
716
|
+
timer = window.setTimeout(settle, SETTLE_TICK_MS);
|
|
717
|
+
return () => {
|
|
718
|
+
cancelled = true;
|
|
719
|
+
window.clearTimeout(timer);
|
|
693
720
|
};
|
|
694
|
-
window.setTimeout(settle, SETTLE_TICK_MS);
|
|
695
721
|
}
|
|
696
722
|
function useActiveIds(scan) {
|
|
697
723
|
const [active, setActive] = useState3({ section: null, story: null });
|
|
@@ -721,6 +747,12 @@ function PageRail({ pageKey }) {
|
|
|
721
747
|
pageKeyRef.current = pageKey;
|
|
722
748
|
const [target, setTarget] = useState3(() => storyFromHash(window.location.hash));
|
|
723
749
|
const flashed = useRef2(null);
|
|
750
|
+
const cancelScroll = useRef2(null);
|
|
751
|
+
const go = useCallback((element) => {
|
|
752
|
+
cancelScroll.current?.();
|
|
753
|
+
cancelScroll.current = scrollToElement(element);
|
|
754
|
+
}, []);
|
|
755
|
+
useEffect3(() => () => cancelScroll.current?.(), []);
|
|
724
756
|
useEffect3(() => {
|
|
725
757
|
const main = document.querySelector(".main");
|
|
726
758
|
if (!main) return;
|
|
@@ -752,17 +784,16 @@ function PageRail({ pageKey }) {
|
|
|
752
784
|
if (!target || !scan || scan.pageKey !== pageKey) return;
|
|
753
785
|
const match = scan.frames.find((frame) => frame.story === target) ?? scan.frames.find((frame) => frame.story.toLowerCase() === target.toLowerCase()) ?? scan.frames.find((frame) => frame.name === target) ?? scan.frames.find((frame) => frame.name.toLowerCase() === target.toLowerCase());
|
|
754
786
|
if (!match) return;
|
|
755
|
-
|
|
787
|
+
go(match.element);
|
|
756
788
|
flashed.current?.classList.remove("toc-flash");
|
|
757
789
|
match.element.classList.add("toc-flash");
|
|
758
790
|
flashed.current = match.element;
|
|
759
791
|
window.setTimeout(() => match.element.classList.remove("toc-flash"), FLASH_MS);
|
|
760
792
|
setTarget(null);
|
|
761
|
-
}, [target, scan, pageKey]);
|
|
793
|
+
}, [target, scan, pageKey, go]);
|
|
762
794
|
const railRef = useRef2(null);
|
|
763
795
|
useRailFollow(railRef, scan !== null);
|
|
764
796
|
const active = useActiveIds(scan);
|
|
765
|
-
const go = useCallback((element) => scrollToElement(element), []);
|
|
766
797
|
if (!scan) return null;
|
|
767
798
|
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: [
|
|
768
799
|
/* @__PURE__ */ jsx5("div", { className: "toc-title", children: "On this page" }),
|
|
@@ -772,17 +803,19 @@ function PageRail({ pageKey }) {
|
|
|
772
803
|
{
|
|
773
804
|
type: "button",
|
|
774
805
|
className: "toc-link",
|
|
806
|
+
title: section.title,
|
|
775
807
|
"aria-current": active.section === section.id ? "location" : void 0,
|
|
776
808
|
onClick: () => go(section.heading),
|
|
777
809
|
children: section.title
|
|
778
810
|
}
|
|
779
811
|
),
|
|
780
|
-
section.subs.length > 0 ? /* @__PURE__ */ jsx5("ul", { children: section.subs.map((sub) => /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsx5("button", { type: "button", className: "toc-link toc-sub", onClick: () => go(sub.element), children: sub.title }) }, sub.id)) }) : null,
|
|
812
|
+
section.subs.length > 0 ? /* @__PURE__ */ jsx5("ul", { children: section.subs.map((sub) => /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsx5("button", { type: "button", className: "toc-link toc-sub", title: sub.title, onClick: () => go(sub.element), children: sub.title }) }, sub.id)) }) : null,
|
|
781
813
|
section.stories.length > 0 ? /* @__PURE__ */ jsx5("ul", { children: section.stories.map((story) => /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsx5(
|
|
782
814
|
"button",
|
|
783
815
|
{
|
|
784
816
|
type: "button",
|
|
785
817
|
className: "toc-link toc-story",
|
|
818
|
+
title: story.name,
|
|
786
819
|
"aria-current": active.story === story.id ? "location" : void 0,
|
|
787
820
|
onClick: () => go(story.element),
|
|
788
821
|
children: story.name
|
|
@@ -1885,9 +1918,20 @@ function DocsApp() {
|
|
|
1885
1918
|
const [mode, setMode] = useState9(theme.values?.[0] ?? "dark");
|
|
1886
1919
|
const [navOpen, setNavOpen] = useState9(false);
|
|
1887
1920
|
const navRef = useRef5(null);
|
|
1888
|
-
|
|
1921
|
+
const pageKey = route.kind === "component" ? `components/${route.slug}` : route.kind;
|
|
1889
1922
|
const headerRef = useRef5(null);
|
|
1890
1923
|
const mainRef = useRef5(null);
|
|
1924
|
+
const renderedPage = useRef5(pageKey);
|
|
1925
|
+
useLayoutEffect2(() => {
|
|
1926
|
+
if (renderedPage.current !== pageKey) {
|
|
1927
|
+
const reset = () => window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
|
1928
|
+
reset();
|
|
1929
|
+
const frame = requestAnimationFrame(reset);
|
|
1930
|
+
renderedPage.current = pageKey;
|
|
1931
|
+
return () => cancelAnimationFrame(frame);
|
|
1932
|
+
}
|
|
1933
|
+
}, [pageKey]);
|
|
1934
|
+
useRailFollow(navRef, true, pageKey);
|
|
1891
1935
|
useEffect8(() => {
|
|
1892
1936
|
const header = headerRef.current;
|
|
1893
1937
|
if (!header) return;
|
|
@@ -1907,7 +1951,6 @@ function DocsApp() {
|
|
|
1907
1951
|
const onHash = () => {
|
|
1908
1952
|
setRoute(parseRoute(window.location.hash));
|
|
1909
1953
|
setNavOpen(false);
|
|
1910
|
-
window.scrollTo(0, 0);
|
|
1911
1954
|
mainRef.current?.focus({ preventScroll: true });
|
|
1912
1955
|
};
|
|
1913
1956
|
window.addEventListener("hashchange", onHash);
|
|
@@ -2019,8 +2062,8 @@ function DocsApp() {
|
|
|
2019
2062
|
)) }, `${group}-${activeSlug ?? route.kind}`);
|
|
2020
2063
|
})
|
|
2021
2064
|
] }) }),
|
|
2022
|
-
/* @__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, {}) }),
|
|
2023
|
-
route.kind !== "overview" ? /* @__PURE__ */ jsx16(PageRail, { pageKey
|
|
2065
|
+
/* @__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) }, pageKey) : 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, {}) }),
|
|
2066
|
+
route.kind !== "overview" ? /* @__PURE__ */ jsx16(PageRail, { pageKey }, pageKey) : null
|
|
2024
2067
|
] });
|
|
2025
2068
|
}
|
|
2026
2069
|
|
package/dist/styles.css
CHANGED
package/dist/toc.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ 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
|
-
export declare function useRailFollow(ref: RefObject<HTMLElement | null>, ready?: boolean): void;
|
|
9
|
+
export declare function useRailFollow(ref: RefObject<HTMLElement | null>, ready?: boolean, pageKey?: string): void;
|
|
10
10
|
/** The "On this page" rail and the `?story=` deep-link landing. */
|
|
11
11
|
export declare function PageRail({ pageKey }: {
|
|
12
12
|
pageKey: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jfrader/storybook-docs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
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": {
|