@geenius/storybook 0.1.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/react.js ADDED
@@ -0,0 +1,253 @@
1
+ import { filterSurface } from './chunk-FB7KPF72.js';
2
+ import { getStoredTheme, setHashRoute, setStoredTheme, getHashRoute, matchesShortcut, DEFAULT_SHORTCUTS, applyTheme, resolveTheme } from './chunk-IEHIPVSX.js';
3
+ import { useMemo, useState, useRef, useEffect } from 'react';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+
6
+ function isTypingTarget(target) {
7
+ return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement || target instanceof HTMLElement && target.isContentEditable;
8
+ }
9
+ function isFocusSearchShortcut(event) {
10
+ return matchesShortcut(event, DEFAULT_SHORTCUTS.focusSearch) || matchesShortcut(event, "Cmd+K") || matchesShortcut(event, "Ctrl+K");
11
+ }
12
+ function syncTheme(mode) {
13
+ applyTheme(resolveTheme(mode));
14
+ if (mode !== "system" || typeof window === "undefined") {
15
+ return () => void 0;
16
+ }
17
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
18
+ const handleChange = () => applyTheme(resolveTheme("system"));
19
+ media.addEventListener("change", handleChange);
20
+ return () => media.removeEventListener("change", handleChange);
21
+ }
22
+ function StoryDeck(props) {
23
+ return /* @__PURE__ */ jsxs("section", { className: "gsb-story-deck", children: [
24
+ /* @__PURE__ */ jsxs("header", { className: "gsb-story-deck__header", children: [
25
+ props.eyebrow ? /* @__PURE__ */ jsx("p", { className: "gsb-eyebrow", children: props.eyebrow }) : null,
26
+ /* @__PURE__ */ jsx("h2", { className: "gsb-story-deck__title", children: props.title }),
27
+ /* @__PURE__ */ jsx("p", { className: "gsb-story-deck__summary", children: props.summary }),
28
+ props.actions
29
+ ] }),
30
+ props.children
31
+ ] });
32
+ }
33
+ function StoryGrid(props) {
34
+ return /* @__PURE__ */ jsx("div", { className: `gsb-story-grid gsb-story-grid--${props.columns ?? 2}`, children: props.children });
35
+ }
36
+ function StoryCard(props) {
37
+ const toneClass = props.tone && props.tone !== "default" ? ` gsb-card--${props.tone}` : "";
38
+ return /* @__PURE__ */ jsxs("section", { className: `gsb-card${toneClass}`, children: [
39
+ /* @__PURE__ */ jsxs("div", { children: [
40
+ /* @__PURE__ */ jsx("h3", { className: "gsb-card__title", children: props.title }),
41
+ props.summary ? /* @__PURE__ */ jsx("p", { className: "gsb-card__summary", children: props.summary }) : null
42
+ ] }),
43
+ props.children
44
+ ] });
45
+ }
46
+ function StoryNote(props) {
47
+ const toneClass = props.tone && props.tone !== "info" ? ` gsb-note--${props.tone}` : "";
48
+ return /* @__PURE__ */ jsx("div", { className: `gsb-note${toneClass}`, children: props.children });
49
+ }
50
+ function StoryMetrics(props) {
51
+ return /* @__PURE__ */ jsx("div", { className: "gsb-metrics", children: props.items.map((item) => /* @__PURE__ */ jsxs("div", { className: "gsb-metric", children: [
52
+ /* @__PURE__ */ jsx("p", { className: "gsb-metric__label", children: item.label }),
53
+ /* @__PURE__ */ jsx("p", { className: "gsb-metric__value", children: item.value }),
54
+ item.detail ? /* @__PURE__ */ jsx("p", { className: "gsb-metric__detail", children: item.detail }) : null
55
+ ] }, item.label)) });
56
+ }
57
+ function StoryComparison(props) {
58
+ return /* @__PURE__ */ jsxs("div", { className: "gsb-comparison", children: [
59
+ /* @__PURE__ */ jsxs("section", { className: "gsb-comparison__pane", children: [
60
+ /* @__PURE__ */ jsx("span", { className: "gsb-pill gsb-pill--accent", children: props.primaryLabel }),
61
+ /* @__PURE__ */ jsx("div", { className: "gsb-comparison__canvas", children: props.primary })
62
+ ] }),
63
+ /* @__PURE__ */ jsxs("section", { className: "gsb-comparison__pane", children: [
64
+ /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: props.secondaryLabel }),
65
+ /* @__PURE__ */ jsx("div", { className: "gsb-comparison__canvas", children: props.secondary })
66
+ ] })
67
+ ] });
68
+ }
69
+ function ReactStorybookApp(props) {
70
+ const allStories = useMemo(
71
+ () => props.sections.flatMap((section) => section.stories),
72
+ [props.sections]
73
+ );
74
+ const allIds = useMemo(() => allStories.map((story) => story.id), [allStories]);
75
+ const resolveRoute = () => {
76
+ const route = getHashRoute(allIds);
77
+ return route === "dashboard" ? props.defaultStoryId : route;
78
+ };
79
+ const [activeStory, setActiveStory] = useState(resolveRoute);
80
+ const [search, setSearch] = useState("");
81
+ const [sidebarOpen, setSidebarOpen] = useState(false);
82
+ const [themeMode, setThemeMode] = useState(
83
+ () => getStoredTheme("dark")
84
+ );
85
+ const searchInputRef = useRef(null);
86
+ useEffect(() => syncTheme(themeMode), [themeMode]);
87
+ useEffect(() => {
88
+ setHashRoute(activeStory);
89
+ }, [activeStory]);
90
+ useEffect(() => {
91
+ const handleHashChange = () => setActiveStory(resolveRoute());
92
+ window.addEventListener("hashchange", handleHashChange);
93
+ return () => window.removeEventListener("hashchange", handleHashChange);
94
+ }, [allIds, props.defaultStoryId]);
95
+ useEffect(() => {
96
+ const handleKeyDown = (event) => {
97
+ if (!isTypingTarget(event.target) && isFocusSearchShortcut(event)) {
98
+ event.preventDefault();
99
+ setSidebarOpen(true);
100
+ searchInputRef.current?.focus();
101
+ return;
102
+ }
103
+ if (isTypingTarget(event.target)) return;
104
+ if (matchesShortcut(event, DEFAULT_SHORTCUTS.toggleTheme)) {
105
+ event.preventDefault();
106
+ setThemeMode((previous) => {
107
+ const next = previous === "dark" ? "light" : previous === "light" ? "system" : "dark";
108
+ setStoredTheme(next);
109
+ return next;
110
+ });
111
+ return;
112
+ }
113
+ if (matchesShortcut(event, DEFAULT_SHORTCUTS.goHome)) {
114
+ event.preventDefault();
115
+ setActiveStory(props.defaultStoryId);
116
+ return;
117
+ }
118
+ if (matchesShortcut(event, DEFAULT_SHORTCUTS.toggleSidebar)) {
119
+ event.preventDefault();
120
+ setSidebarOpen((previous) => !previous);
121
+ }
122
+ };
123
+ window.addEventListener("keydown", handleKeyDown);
124
+ return () => window.removeEventListener("keydown", handleKeyDown);
125
+ }, [props.defaultStoryId]);
126
+ const filteredSections = useMemo(() => {
127
+ if (!search.trim()) return props.sections;
128
+ const filtered = filterSurface(props.sections, search);
129
+ return filtered.map((section) => {
130
+ const original = props.sections.find(
131
+ (candidate) => candidate.title === section.title
132
+ );
133
+ return {
134
+ ...original,
135
+ stories: original.stories.filter(
136
+ (story) => section.stories.some((candidate) => candidate.id === story.id)
137
+ )
138
+ };
139
+ });
140
+ }, [props.sections, search]);
141
+ const activeMeta = allStories.find((story) => story.id === activeStory) ?? allStories[0];
142
+ const ActiveComponent = props.components[activeMeta.id];
143
+ const themeLabel = themeMode === "dark" ? "Dark" : themeMode === "light" ? "Light" : "System";
144
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
145
+ /* @__PURE__ */ jsxs("div", { className: "gsb-shell", children: [
146
+ /* @__PURE__ */ jsxs("aside", { className: `gsb-sidebar${sidebarOpen ? " is-open" : ""}`, children: [
147
+ /* @__PURE__ */ jsxs("div", { className: "gsb-sidebar__top", children: [
148
+ /* @__PURE__ */ jsxs("div", { className: "gsb-sidebar__brand", children: [
149
+ /* @__PURE__ */ jsx("p", { className: "gsb-eyebrow", children: props.frameworkLabel }),
150
+ /* @__PURE__ */ jsx("h1", { className: "gsb-sidebar__title", children: props.packageName }),
151
+ /* @__PURE__ */ jsx("p", { className: "gsb-sidebar__summary", children: props.overview })
152
+ ] }),
153
+ /* @__PURE__ */ jsx("span", { className: "gsb-count", children: allStories.length })
154
+ ] }),
155
+ /* @__PURE__ */ jsx(
156
+ "div",
157
+ {
158
+ style: {
159
+ display: "flex",
160
+ gap: "0.5rem",
161
+ marginBottom: "1rem",
162
+ padding: "0 0.25rem"
163
+ },
164
+ children: /* @__PURE__ */ jsx(
165
+ "button",
166
+ {
167
+ type: "button",
168
+ className: "gsb-theme-toggle",
169
+ onClick: () => setThemeMode((previous) => {
170
+ const next = previous === "dark" ? "light" : previous === "light" ? "system" : "dark";
171
+ setStoredTheme(next);
172
+ return next;
173
+ }),
174
+ children: themeLabel
175
+ }
176
+ )
177
+ }
178
+ ),
179
+ /* @__PURE__ */ jsx("div", { className: "gsb-search", children: /* @__PURE__ */ jsx(
180
+ "input",
181
+ {
182
+ ref: searchInputRef,
183
+ type: "search",
184
+ value: search,
185
+ onChange: (event) => setSearch(event.target.value),
186
+ placeholder: "Search stories, tags, or ids\u2026",
187
+ className: "gsb-search__input"
188
+ }
189
+ ) }),
190
+ filteredSections.length === 0 ? /* @__PURE__ */ jsx("div", { className: "gsb-empty", children: "No stories match this search." }) : filteredSections.map((section) => /* @__PURE__ */ jsxs("section", { className: "gsb-sidebar__section", children: [
191
+ /* @__PURE__ */ jsx("h2", { className: "gsb-sidebar__section-title", children: section.title }),
192
+ /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__items", children: section.stories.map((story) => /* @__PURE__ */ jsxs(
193
+ "button",
194
+ {
195
+ type: "button",
196
+ className: `gsb-sidebar__item${story.id === activeMeta.id ? " is-active" : ""}`,
197
+ onClick: () => {
198
+ setActiveStory(story.id);
199
+ setSidebarOpen(false);
200
+ },
201
+ children: [
202
+ /* @__PURE__ */ jsxs("div", { className: "gsb-sidebar__item-title", children: [
203
+ /* @__PURE__ */ jsx("span", { children: story.label }),
204
+ story.tags?.[0] ? /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: story.tags[0] }) : null
205
+ ] }),
206
+ /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__item-id", children: story.id }),
207
+ story.description ? /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__item-description", children: story.description }) : null
208
+ ]
209
+ },
210
+ story.id
211
+ )) })
212
+ ] }, section.title))
213
+ ] }),
214
+ /* @__PURE__ */ jsx("main", { className: "gsb-main", children: /* @__PURE__ */ jsxs("div", { className: "gsb-main__inner", children: [
215
+ /* @__PURE__ */ jsx("div", { className: "gsb-topbar", children: /* @__PURE__ */ jsx(
216
+ "button",
217
+ {
218
+ type: "button",
219
+ className: "gsb-nav-toggle",
220
+ onClick: () => setSidebarOpen(true),
221
+ children: "Browse stories"
222
+ }
223
+ ) }),
224
+ /* @__PURE__ */ jsxs("header", { className: "gsb-hero", children: [
225
+ /* @__PURE__ */ jsxs("div", { className: "gsb-hero__meta", children: [
226
+ /* @__PURE__ */ jsx("span", { className: "gsb-pill gsb-pill--accent", children: props.frameworkLabel }),
227
+ /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: activeMeta.id }),
228
+ activeMeta.tags?.map((tag) => /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: tag }, tag))
229
+ ] }),
230
+ /* @__PURE__ */ jsxs("div", { className: "gsb-story-deck__header", children: [
231
+ /* @__PURE__ */ jsx("p", { className: "gsb-eyebrow", children: "Story surface" }),
232
+ /* @__PURE__ */ jsx("h2", { className: "gsb-hero__title", children: activeMeta.label }),
233
+ activeMeta.description ? /* @__PURE__ */ jsx("p", { className: "gsb-hero__summary", children: activeMeta.description }) : null
234
+ ] })
235
+ ] }),
236
+ /* @__PURE__ */ jsx("div", { className: "gsb-story-space", children: /* @__PURE__ */ jsx(ActiveComponent, {}) })
237
+ ] }) })
238
+ ] }),
239
+ sidebarOpen ? /* @__PURE__ */ jsx(
240
+ "button",
241
+ {
242
+ type: "button",
243
+ className: "gsb-backdrop",
244
+ onClick: () => setSidebarOpen(false),
245
+ "aria-label": "Close navigation"
246
+ }
247
+ ) : null
248
+ ] });
249
+ }
250
+
251
+ export { ReactStorybookApp, StoryCard, StoryComparison, StoryDeck, StoryGrid, StoryMetrics, StoryNote };
252
+ //# sourceMappingURL=react.js.map
253
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"names":[],"mappings":"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","file":"react.js","sourcesContent":["import {\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from 'react'\nimport { filterSurface } from './surface.js'\nimport type { ThemeMode } from './types.js'\nimport {\n applyTheme,\n DEFAULT_SHORTCUTS,\n getHashRoute,\n getStoredTheme,\n matchesShortcut,\n resolveTheme,\n setHashRoute,\n setStoredTheme,\n} from './utils.js'\n\nexport type StoryEntry<StoryId extends string> = {\n id: StoryId\n label: string\n description?: string\n tags?: readonly string[]\n}\n\nexport type StorySection<StoryId extends string> = {\n title: string\n stories: readonly StoryEntry<StoryId>[]\n}\n\nexport type StoryComponentMap<StoryId extends string> = Record<\n StoryId,\n ComponentType<Record<string, never>>\n>\n\nfunction isTypingTarget(target: EventTarget | null): boolean {\n return (\n target instanceof HTMLInputElement ||\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLSelectElement ||\n (target instanceof HTMLElement && target.isContentEditable)\n )\n}\n\nfunction isFocusSearchShortcut(event: KeyboardEvent): boolean {\n return (\n matchesShortcut(event, DEFAULT_SHORTCUTS.focusSearch) ||\n matchesShortcut(event, 'Cmd+K') ||\n matchesShortcut(event, 'Ctrl+K')\n )\n}\n\nfunction syncTheme(mode: ThemeMode): () => void {\n applyTheme(resolveTheme(mode))\n\n if (mode !== 'system' || typeof window === 'undefined') {\n return () => undefined\n }\n\n const media = window.matchMedia('(prefers-color-scheme: dark)')\n const handleChange = () => applyTheme(resolveTheme('system'))\n\n media.addEventListener('change', handleChange)\n return () => media.removeEventListener('change', handleChange)\n}\n\nexport function StoryDeck(props: {\n eyebrow?: string\n title: string\n summary: string\n children: ReactNode\n actions?: ReactNode\n}) {\n return (\n <section className=\"gsb-story-deck\">\n <header className=\"gsb-story-deck__header\">\n {props.eyebrow ? <p className=\"gsb-eyebrow\">{props.eyebrow}</p> : null}\n <h2 className=\"gsb-story-deck__title\">{props.title}</h2>\n <p className=\"gsb-story-deck__summary\">{props.summary}</p>\n {props.actions}\n </header>\n {props.children}\n </section>\n )\n}\n\nexport function StoryGrid(props: { columns?: 2 | 3; children: ReactNode }) {\n return (\n <div className={`gsb-story-grid gsb-story-grid--${props.columns ?? 2}`}>\n {props.children}\n </div>\n )\n}\n\nexport function StoryCard(props: {\n title: string\n summary?: string\n tone?: 'default' | 'accent' | 'success' | 'warning' | 'danger'\n children: ReactNode\n}) {\n const toneClass =\n props.tone && props.tone !== 'default' ? ` gsb-card--${props.tone}` : ''\n\n return (\n <section className={`gsb-card${toneClass}`}>\n <div>\n <h3 className=\"gsb-card__title\">{props.title}</h3>\n {props.summary ? (\n <p className=\"gsb-card__summary\">{props.summary}</p>\n ) : null}\n </div>\n {props.children}\n </section>\n )\n}\n\nexport function StoryNote(props: {\n tone?: 'info' | 'warning' | 'success' | 'danger'\n children: ReactNode\n}) {\n const toneClass =\n props.tone && props.tone !== 'info' ? ` gsb-note--${props.tone}` : ''\n return <div className={`gsb-note${toneClass}`}>{props.children}</div>\n}\n\nexport function StoryMetrics(props: {\n items: ReadonlyArray<{ label: string; value: string; detail?: string }>\n}) {\n return (\n <div className=\"gsb-metrics\">\n {props.items.map((item) => (\n <div key={item.label} className=\"gsb-metric\">\n <p className=\"gsb-metric__label\">{item.label}</p>\n <p className=\"gsb-metric__value\">{item.value}</p>\n {item.detail ? (\n <p className=\"gsb-metric__detail\">{item.detail}</p>\n ) : null}\n </div>\n ))}\n </div>\n )\n}\n\nexport function StoryComparison(props: {\n primaryLabel: string\n secondaryLabel: string\n primary: ReactNode\n secondary: ReactNode\n}) {\n return (\n <div className=\"gsb-comparison\">\n <section className=\"gsb-comparison__pane\">\n <span className=\"gsb-pill gsb-pill--accent\">{props.primaryLabel}</span>\n <div className=\"gsb-comparison__canvas\">{props.primary}</div>\n </section>\n <section className=\"gsb-comparison__pane\">\n <span className=\"gsb-pill\">{props.secondaryLabel}</span>\n <div className=\"gsb-comparison__canvas\">{props.secondary}</div>\n </section>\n </div>\n )\n}\n\nexport function ReactStorybookApp<StoryId extends string>(props: {\n packageName: string\n frameworkLabel: string\n overview: string\n sections: readonly StorySection<StoryId>[]\n components: StoryComponentMap<StoryId>\n defaultStoryId: StoryId\n}) {\n const allStories = useMemo(\n () => props.sections.flatMap((section) => section.stories),\n [props.sections],\n )\n const allIds = useMemo(() => allStories.map((story) => story.id), [allStories])\n\n const resolveRoute = () => {\n const route = getHashRoute(allIds)\n return route === 'dashboard' ? props.defaultStoryId : (route as StoryId)\n }\n\n const [activeStory, setActiveStory] = useState<StoryId>(resolveRoute)\n const [search, setSearch] = useState('')\n const [sidebarOpen, setSidebarOpen] = useState(false)\n const [themeMode, setThemeMode] = useState<ThemeMode>(() =>\n getStoredTheme('dark'),\n )\n const searchInputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => syncTheme(themeMode), [themeMode])\n\n useEffect(() => {\n setHashRoute(activeStory)\n }, [activeStory])\n\n useEffect(() => {\n const handleHashChange = () => setActiveStory(resolveRoute())\n window.addEventListener('hashchange', handleHashChange)\n return () => window.removeEventListener('hashchange', handleHashChange)\n }, [allIds, props.defaultStoryId])\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isTypingTarget(event.target) && isFocusSearchShortcut(event)) {\n event.preventDefault()\n setSidebarOpen(true)\n searchInputRef.current?.focus()\n return\n }\n\n if (isTypingTarget(event.target)) return\n\n if (matchesShortcut(event, DEFAULT_SHORTCUTS.toggleTheme)) {\n event.preventDefault()\n setThemeMode((previous) => {\n const next =\n previous === 'dark'\n ? 'light'\n : previous === 'light'\n ? 'system'\n : 'dark'\n setStoredTheme(next)\n return next\n })\n return\n }\n\n if (matchesShortcut(event, DEFAULT_SHORTCUTS.goHome)) {\n event.preventDefault()\n setActiveStory(props.defaultStoryId)\n return\n }\n\n if (matchesShortcut(event, DEFAULT_SHORTCUTS.toggleSidebar)) {\n event.preventDefault()\n setSidebarOpen((previous) => !previous)\n }\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [props.defaultStoryId])\n\n const filteredSections = useMemo(() => {\n if (!search.trim()) return props.sections\n\n const filtered = filterSurface(props.sections, search)\n return filtered.map((section) => {\n const original = props.sections.find(\n (candidate) => candidate.title === section.title,\n )!\n\n return {\n ...original,\n stories: original.stories.filter((story) =>\n section.stories.some((candidate) => candidate.id === story.id),\n ),\n }\n })\n }, [props.sections, search])\n\n const activeMeta =\n allStories.find((story) => story.id === activeStory) ?? allStories[0]\n const ActiveComponent = props.components[activeMeta.id] as ComponentType<\n Record<string, never>\n >\n const themeLabel =\n themeMode === 'dark'\n ? 'Dark'\n : themeMode === 'light'\n ? 'Light'\n : 'System'\n\n return (\n <>\n <div className=\"gsb-shell\">\n <aside className={`gsb-sidebar${sidebarOpen ? ' is-open' : ''}`}>\n <div className=\"gsb-sidebar__top\">\n <div className=\"gsb-sidebar__brand\">\n <p className=\"gsb-eyebrow\">{props.frameworkLabel}</p>\n <h1 className=\"gsb-sidebar__title\">{props.packageName}</h1>\n <p className=\"gsb-sidebar__summary\">{props.overview}</p>\n </div>\n <span className=\"gsb-count\">{allStories.length}</span>\n </div>\n\n <div\n style={{\n display: 'flex',\n gap: '0.5rem',\n marginBottom: '1rem',\n padding: '0 0.25rem',\n }}\n >\n <button\n type=\"button\"\n className=\"gsb-theme-toggle\"\n onClick={() =>\n setThemeMode((previous) => {\n const next =\n previous === 'dark'\n ? 'light'\n : previous === 'light'\n ? 'system'\n : 'dark'\n setStoredTheme(next)\n return next\n })\n }\n >\n {themeLabel}\n </button>\n </div>\n\n <div className=\"gsb-search\">\n <input\n ref={searchInputRef}\n type=\"search\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n placeholder=\"Search stories, tags, or ids…\"\n className=\"gsb-search__input\"\n />\n </div>\n\n {filteredSections.length === 0 ? (\n <div className=\"gsb-empty\">No stories match this search.</div>\n ) : (\n filteredSections.map((section) => (\n <section key={section.title} className=\"gsb-sidebar__section\">\n <h2 className=\"gsb-sidebar__section-title\">{section.title}</h2>\n <div className=\"gsb-sidebar__items\">\n {section.stories.map((story) => (\n <button\n key={story.id}\n type=\"button\"\n className={`gsb-sidebar__item${story.id === activeMeta.id ? ' is-active' : ''}`}\n onClick={() => {\n setActiveStory(story.id)\n setSidebarOpen(false)\n }}\n >\n <div className=\"gsb-sidebar__item-title\">\n <span>{story.label}</span>\n {story.tags?.[0] ? (\n <span className=\"gsb-pill\">{story.tags[0]}</span>\n ) : null}\n </div>\n <div className=\"gsb-sidebar__item-id\">{story.id}</div>\n {story.description ? (\n <div className=\"gsb-sidebar__item-description\">\n {story.description}\n </div>\n ) : null}\n </button>\n ))}\n </div>\n </section>\n ))\n )}\n </aside>\n\n <main className=\"gsb-main\">\n <div className=\"gsb-main__inner\">\n <div className=\"gsb-topbar\">\n <button\n type=\"button\"\n className=\"gsb-nav-toggle\"\n onClick={() => setSidebarOpen(true)}\n >\n Browse stories\n </button>\n </div>\n\n <header className=\"gsb-hero\">\n <div className=\"gsb-hero__meta\">\n <span className=\"gsb-pill gsb-pill--accent\">\n {props.frameworkLabel}\n </span>\n <span className=\"gsb-pill\">{activeMeta.id}</span>\n {activeMeta.tags?.map((tag) => (\n <span key={tag} className=\"gsb-pill\">\n {tag}\n </span>\n ))}\n </div>\n <div className=\"gsb-story-deck__header\">\n <p className=\"gsb-eyebrow\">Story surface</p>\n <h2 className=\"gsb-hero__title\">{activeMeta.label}</h2>\n {activeMeta.description ? (\n <p className=\"gsb-hero__summary\">{activeMeta.description}</p>\n ) : null}\n </div>\n </header>\n\n <div className=\"gsb-story-space\">\n <ActiveComponent />\n </div>\n </div>\n </main>\n </div>\n\n {sidebarOpen ? (\n <button\n type=\"button\"\n className=\"gsb-backdrop\"\n onClick={() => setSidebarOpen(false)}\n aria-label=\"Close navigation\"\n />\n ) : null}\n </>\n )\n}\n"]}
@@ -0,0 +1,58 @@
1
+ import * as solid_js_h_jsx_runtime from 'solid-js/h/jsx-runtime';
2
+ import { Component, JSX } from 'solid-js';
3
+
4
+ type StoryEntry<StoryId extends string> = {
5
+ id: StoryId;
6
+ label: string;
7
+ description?: string;
8
+ tags?: readonly string[];
9
+ };
10
+ type StorySection<StoryId extends string> = {
11
+ title: string;
12
+ stories: readonly StoryEntry<StoryId>[];
13
+ };
14
+ type StoryComponentMap<StoryId extends string> = Record<StoryId, Component<Record<string, never>>>;
15
+ declare function StoryDeck(props: {
16
+ eyebrow?: string;
17
+ title: string;
18
+ summary: string;
19
+ children: JSX.Element;
20
+ actions?: JSX.Element;
21
+ }): solid_js_h_jsx_runtime.JSX.Element;
22
+ declare function StoryGrid(props: {
23
+ columns?: 2 | 3;
24
+ children: JSX.Element;
25
+ }): solid_js_h_jsx_runtime.JSX.Element;
26
+ declare function StoryCard(props: {
27
+ title: string;
28
+ summary?: string;
29
+ tone?: 'default' | 'accent' | 'success' | 'warning' | 'danger';
30
+ children: JSX.Element;
31
+ }): solid_js_h_jsx_runtime.JSX.Element;
32
+ declare function StoryNote(props: {
33
+ tone?: 'info' | 'warning' | 'success' | 'danger';
34
+ children: JSX.Element;
35
+ }): solid_js_h_jsx_runtime.JSX.Element;
36
+ declare function StoryMetrics(props: {
37
+ items: ReadonlyArray<{
38
+ label: string;
39
+ value: string;
40
+ detail?: string;
41
+ }>;
42
+ }): solid_js_h_jsx_runtime.JSX.Element;
43
+ declare function StoryComparison(props: {
44
+ primaryLabel: string;
45
+ secondaryLabel: string;
46
+ primary: JSX.Element;
47
+ secondary: JSX.Element;
48
+ }): solid_js_h_jsx_runtime.JSX.Element;
49
+ declare function SolidStorybookApp<StoryId extends string>(props: {
50
+ packageName: string;
51
+ frameworkLabel: string;
52
+ overview: string;
53
+ sections: readonly StorySection<StoryId>[];
54
+ components: StoryComponentMap<StoryId>;
55
+ defaultStoryId: StoryId;
56
+ }): solid_js_h_jsx_runtime.JSX.Element;
57
+
58
+ export { SolidStorybookApp, StoryCard, StoryComparison, type StoryComponentMap, StoryDeck, type StoryEntry, StoryGrid, StoryMetrics, StoryNote, type StorySection };
@@ -0,0 +1,260 @@
1
+ import { filterSurface } from './chunk-FB7KPF72.js';
2
+ import { getStoredTheme, setHashRoute, setStoredTheme, getHashRoute, matchesShortcut, DEFAULT_SHORTCUTS, applyTheme, resolveTheme } from './chunk-IEHIPVSX.js';
3
+ import { createMemo, createSignal, createEffect, onCleanup } from 'solid-js';
4
+ import { jsxs, jsx, Fragment } from 'solid-js/h/jsx-runtime';
5
+
6
+ function isTypingTarget(target) {
7
+ return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement || target instanceof HTMLElement && target.isContentEditable;
8
+ }
9
+ function isFocusSearchShortcut(event) {
10
+ return matchesShortcut(event, DEFAULT_SHORTCUTS.focusSearch) || matchesShortcut(event, "Cmd+K") || matchesShortcut(event, "Ctrl+K");
11
+ }
12
+ function syncTheme(mode) {
13
+ applyTheme(resolveTheme(mode));
14
+ if (mode !== "system" || typeof window === "undefined") {
15
+ return () => void 0;
16
+ }
17
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
18
+ const handleChange = () => applyTheme(resolveTheme("system"));
19
+ media.addEventListener("change", handleChange);
20
+ return () => media.removeEventListener("change", handleChange);
21
+ }
22
+ function StoryDeck(props) {
23
+ return /* @__PURE__ */ jsxs("section", { class: "gsb-story-deck", children: [
24
+ /* @__PURE__ */ jsxs("header", { class: "gsb-story-deck__header", children: [
25
+ props.eyebrow ? /* @__PURE__ */ jsx("p", { class: "gsb-eyebrow", children: props.eyebrow }) : null,
26
+ /* @__PURE__ */ jsx("h2", { class: "gsb-story-deck__title", children: props.title }),
27
+ /* @__PURE__ */ jsx("p", { class: "gsb-story-deck__summary", children: props.summary }),
28
+ props.actions
29
+ ] }),
30
+ props.children
31
+ ] });
32
+ }
33
+ function StoryGrid(props) {
34
+ return /* @__PURE__ */ jsx("div", { class: `gsb-story-grid gsb-story-grid--${props.columns ?? 2}`, children: props.children });
35
+ }
36
+ function StoryCard(props) {
37
+ const toneClass = props.tone && props.tone !== "default" ? ` gsb-card--${props.tone}` : "";
38
+ return /* @__PURE__ */ jsxs("section", { class: `gsb-card${toneClass}`, children: [
39
+ /* @__PURE__ */ jsxs("div", { children: [
40
+ /* @__PURE__ */ jsx("h3", { class: "gsb-card__title", children: props.title }),
41
+ props.summary ? /* @__PURE__ */ jsx("p", { class: "gsb-card__summary", children: props.summary }) : null
42
+ ] }),
43
+ props.children
44
+ ] });
45
+ }
46
+ function StoryNote(props) {
47
+ const toneClass = props.tone && props.tone !== "info" ? ` gsb-note--${props.tone}` : "";
48
+ return /* @__PURE__ */ jsx("div", { class: `gsb-note${toneClass}`, children: props.children });
49
+ }
50
+ function StoryMetrics(props) {
51
+ return /* @__PURE__ */ jsx("div", { class: "gsb-metrics", children: props.items.map((item) => /* @__PURE__ */ jsxs("div", { class: "gsb-metric", children: [
52
+ /* @__PURE__ */ jsx("p", { class: "gsb-metric__label", children: item.label }),
53
+ /* @__PURE__ */ jsx("p", { class: "gsb-metric__value", children: item.value }),
54
+ item.detail ? /* @__PURE__ */ jsx("p", { class: "gsb-metric__detail", children: item.detail }) : null
55
+ ] })) });
56
+ }
57
+ function StoryComparison(props) {
58
+ return /* @__PURE__ */ jsxs("div", { class: "gsb-comparison", children: [
59
+ /* @__PURE__ */ jsxs("section", { class: "gsb-comparison__pane", children: [
60
+ /* @__PURE__ */ jsx("span", { class: "gsb-pill gsb-pill--accent", children: props.primaryLabel }),
61
+ /* @__PURE__ */ jsx("div", { class: "gsb-comparison__canvas", children: props.primary })
62
+ ] }),
63
+ /* @__PURE__ */ jsxs("section", { class: "gsb-comparison__pane", children: [
64
+ /* @__PURE__ */ jsx("span", { class: "gsb-pill", children: props.secondaryLabel }),
65
+ /* @__PURE__ */ jsx("div", { class: "gsb-comparison__canvas", children: props.secondary })
66
+ ] })
67
+ ] });
68
+ }
69
+ function SolidStorybookApp(props) {
70
+ const allStories = createMemo(
71
+ () => props.sections.flatMap((section) => section.stories)
72
+ );
73
+ const allIds = createMemo(() => allStories().map((story) => story.id));
74
+ const resolveRoute = () => {
75
+ const route = getHashRoute(allIds());
76
+ return route === "dashboard" ? props.defaultStoryId : route;
77
+ };
78
+ const [activeStory, setActiveStory] = createSignal(
79
+ resolveRoute()
80
+ );
81
+ const [search, setSearch] = createSignal("");
82
+ const [sidebarOpen, setSidebarOpen] = createSignal(false);
83
+ const [themeMode, setThemeMode] = createSignal(getStoredTheme("dark"));
84
+ let searchInput;
85
+ createEffect(() => {
86
+ const cleanup = syncTheme(themeMode());
87
+ onCleanup(cleanup);
88
+ });
89
+ createEffect(() => {
90
+ setHashRoute(activeStory());
91
+ });
92
+ if (typeof window !== "undefined") {
93
+ const handleHashChange = () => setActiveStory(() => resolveRoute());
94
+ window.addEventListener("hashchange", handleHashChange);
95
+ onCleanup(() => window.removeEventListener("hashchange", handleHashChange));
96
+ }
97
+ if (typeof window !== "undefined") {
98
+ const handleKeyDown = (event) => {
99
+ if (!isTypingTarget(event.target) && isFocusSearchShortcut(event)) {
100
+ event.preventDefault();
101
+ setSidebarOpen(true);
102
+ return;
103
+ }
104
+ if (isTypingTarget(event.target)) return;
105
+ if (matchesShortcut(event, DEFAULT_SHORTCUTS.toggleTheme)) {
106
+ event.preventDefault();
107
+ setThemeMode((previous) => {
108
+ const next = previous === "dark" ? "light" : previous === "light" ? "system" : "dark";
109
+ setStoredTheme(next);
110
+ return next;
111
+ });
112
+ return;
113
+ }
114
+ if (matchesShortcut(event, DEFAULT_SHORTCUTS.goHome)) {
115
+ event.preventDefault();
116
+ setActiveStory(() => props.defaultStoryId);
117
+ return;
118
+ }
119
+ if (matchesShortcut(event, DEFAULT_SHORTCUTS.toggleSidebar)) {
120
+ event.preventDefault();
121
+ setSidebarOpen((previous) => !previous);
122
+ }
123
+ };
124
+ window.addEventListener("keydown", handleKeyDown);
125
+ onCleanup(() => window.removeEventListener("keydown", handleKeyDown));
126
+ }
127
+ const filteredSections = createMemo(() => {
128
+ if (!search().trim()) return props.sections;
129
+ const filtered = filterSurface(props.sections, search());
130
+ return filtered.map((section) => {
131
+ const original = props.sections.find(
132
+ (candidate) => candidate.title === section.title
133
+ );
134
+ return {
135
+ ...original,
136
+ stories: original.stories.filter(
137
+ (story) => section.stories.some((candidate) => candidate.id === story.id)
138
+ )
139
+ };
140
+ });
141
+ });
142
+ const activeMeta = createMemo(
143
+ () => allStories().find((story) => story.id === activeStory()) ?? allStories()[0]
144
+ );
145
+ const ActiveComponent = createMemo(() => props.components[activeMeta().id]);
146
+ const themeLabel = createMemo(
147
+ () => themeMode() === "dark" ? "Dark" : themeMode() === "light" ? "Light" : "System"
148
+ );
149
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
150
+ /* @__PURE__ */ jsxs("div", { class: "gsb-shell", children: [
151
+ /* @__PURE__ */ jsxs("aside", { class: `gsb-sidebar${sidebarOpen() ? " is-open" : ""}`, children: [
152
+ /* @__PURE__ */ jsxs("div", { class: "gsb-sidebar__top", children: [
153
+ /* @__PURE__ */ jsxs("div", { class: "gsb-sidebar__brand", children: [
154
+ /* @__PURE__ */ jsx("p", { class: "gsb-eyebrow", children: props.frameworkLabel }),
155
+ /* @__PURE__ */ jsx("h1", { class: "gsb-sidebar__title", children: props.packageName }),
156
+ /* @__PURE__ */ jsx("p", { class: "gsb-sidebar__summary", children: props.overview })
157
+ ] }),
158
+ /* @__PURE__ */ jsx("span", { class: "gsb-count", children: allStories().length })
159
+ ] }),
160
+ /* @__PURE__ */ jsx(
161
+ "div",
162
+ {
163
+ style: {
164
+ display: "flex",
165
+ gap: "0.5rem",
166
+ "margin-bottom": "1rem",
167
+ padding: "0 0.25rem"
168
+ },
169
+ children: /* @__PURE__ */ jsx(
170
+ "button",
171
+ {
172
+ type: "button",
173
+ class: "gsb-theme-toggle",
174
+ onClick: () => setThemeMode((previous) => {
175
+ const next = previous === "dark" ? "light" : previous === "light" ? "system" : "dark";
176
+ setStoredTheme(next);
177
+ return next;
178
+ }),
179
+ children: themeLabel()
180
+ }
181
+ )
182
+ }
183
+ ),
184
+ /* @__PURE__ */ jsx("div", { class: "gsb-search", children: /* @__PURE__ */ jsx(
185
+ "input",
186
+ {
187
+ ref: searchInput,
188
+ type: "search",
189
+ value: search(),
190
+ onInput: (event) => setSearch(event.currentTarget.value),
191
+ placeholder: "Search stories, tags, or ids\u2026",
192
+ class: "gsb-search__input"
193
+ }
194
+ ) }),
195
+ filteredSections().length === 0 ? /* @__PURE__ */ jsx("div", { class: "gsb-empty", children: "No stories match this search." }) : filteredSections().map((section) => /* @__PURE__ */ jsxs("section", { class: "gsb-sidebar__section", children: [
196
+ /* @__PURE__ */ jsx("h2", { class: "gsb-sidebar__section-title", children: section.title }),
197
+ /* @__PURE__ */ jsx("div", { class: "gsb-sidebar__items", children: section.stories.map((story) => /* @__PURE__ */ jsxs(
198
+ "button",
199
+ {
200
+ type: "button",
201
+ class: `gsb-sidebar__item${story.id === activeMeta().id ? " is-active" : ""}`,
202
+ onClick: () => {
203
+ setActiveStory(() => story.id);
204
+ setSidebarOpen(false);
205
+ },
206
+ children: [
207
+ /* @__PURE__ */ jsxs("div", { class: "gsb-sidebar__item-title", children: [
208
+ /* @__PURE__ */ jsx("span", { children: story.label }),
209
+ story.tags?.[0] ? /* @__PURE__ */ jsx("span", { class: "gsb-pill", children: story.tags[0] }) : null
210
+ ] }),
211
+ /* @__PURE__ */ jsx("div", { class: "gsb-sidebar__item-id", children: story.id }),
212
+ story.description ? /* @__PURE__ */ jsx("div", { class: "gsb-sidebar__item-description", children: story.description }) : null
213
+ ]
214
+ }
215
+ )) })
216
+ ] }))
217
+ ] }),
218
+ /* @__PURE__ */ jsx("main", { class: "gsb-main", children: /* @__PURE__ */ jsxs("div", { class: "gsb-main__inner", children: [
219
+ /* @__PURE__ */ jsx("div", { class: "gsb-topbar", children: /* @__PURE__ */ jsx(
220
+ "button",
221
+ {
222
+ type: "button",
223
+ class: "gsb-nav-toggle",
224
+ onClick: () => setSidebarOpen(true),
225
+ children: "Browse stories"
226
+ }
227
+ ) }),
228
+ /* @__PURE__ */ jsxs("header", { class: "gsb-hero", children: [
229
+ /* @__PURE__ */ jsxs("div", { class: "gsb-hero__meta", children: [
230
+ /* @__PURE__ */ jsx("span", { class: "gsb-pill gsb-pill--accent", children: props.frameworkLabel }),
231
+ /* @__PURE__ */ jsx("span", { class: "gsb-pill", children: activeMeta().id }),
232
+ activeMeta().tags?.map((tag) => /* @__PURE__ */ jsx("span", { class: "gsb-pill", children: tag }))
233
+ ] }),
234
+ /* @__PURE__ */ jsxs("div", { class: "gsb-story-deck__header", children: [
235
+ /* @__PURE__ */ jsx("p", { class: "gsb-eyebrow", children: "Story surface" }),
236
+ /* @__PURE__ */ jsx("h2", { class: "gsb-hero__title", children: activeMeta().label }),
237
+ activeMeta().description ? /* @__PURE__ */ jsx("p", { class: "gsb-hero__summary", children: activeMeta().description }) : null
238
+ ] })
239
+ ] }),
240
+ /* @__PURE__ */ jsx("div", { class: "gsb-story-space", children: (() => {
241
+ const StoryComponent = ActiveComponent();
242
+ return /* @__PURE__ */ jsx(StoryComponent, {});
243
+ })() })
244
+ ] }) })
245
+ ] }),
246
+ sidebarOpen() ? /* @__PURE__ */ jsx(
247
+ "button",
248
+ {
249
+ type: "button",
250
+ class: "gsb-backdrop",
251
+ onClick: () => setSidebarOpen(false),
252
+ "aria-label": "Close navigation"
253
+ }
254
+ ) : null
255
+ ] });
256
+ }
257
+
258
+ export { SolidStorybookApp, StoryCard, StoryComparison, StoryDeck, StoryGrid, StoryMetrics, StoryNote };
259
+ //# sourceMappingURL=solidjs.js.map
260
+ //# sourceMappingURL=solidjs.js.map