@geenius/storybook 0.1.0 → 0.1.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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Finalize the shared storybook shell for package-wide rollout by improving shell resilience, metadata chrome, and UI package integration guidance.
8
+
3
9
  All notable changes to this project will be documented in this file.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Shared storybook shell, theme, layout, and Vite preset for all `@geenius` packages.
4
4
 
5
- Provides a consistent look-and-feel, design tokens, and development infrastructure so every package storybook (React, SolidJS, Vue, Svelte) shares the same UI shell without duplicating code.
5
+ Provides a consistent look-and-feel, design tokens, and development infrastructure so every package storybook can share the same UI shell without duplicating React or SolidJS runtime code.
6
6
 
7
7
  ## Installation
8
8
 
@@ -12,18 +12,18 @@ pnpm add @geenius/storybook
12
12
 
13
13
  ## What's Inside
14
14
 
15
- | Export | Description |
16
- |---|---|
17
- | `@geenius/storybook` | Barrel — all types, surface utils, runtime utils, Vite preset |
18
- | `@geenius/storybook/surface` | Story catalog definition and query utilities |
19
- | `@geenius/storybook/react` | Shared React storybook shell and layout primitives |
20
- | `@geenius/storybook/solidjs` | Shared SolidJS storybook shell and layout primitives |
21
- | `@geenius/storybook/types` | TypeScript type definitions |
22
- | `@geenius/storybook/utils` | Hash routing, theme management, keyboard shortcuts |
23
- | `@geenius/storybook/vite` | `createStorybookViteConfig()` factory |
24
- | `@geenius/storybook/styles` | Shell layout CSS (sidebar, panels, dashboard, comparison) |
25
- | `@geenius/storybook/theme` | Component design tokens (OKLCH dark/light + Tailwind v4 `@theme`) |
26
- | `@geenius/storybook/html` | Base HTML template with font imports |
15
+ | Export | Description |
16
+ | ---------------------------- | ----------------------------------------------------------------- |
17
+ | `@geenius/storybook` | Barrel — all types, surface utils, runtime utils, Vite preset |
18
+ | `@geenius/storybook/surface` | Story catalog definition and query utilities |
19
+ | `@geenius/storybook/react` | Shared React storybook shell and layout primitives |
20
+ | `@geenius/storybook/solidjs` | Shared SolidJS storybook shell and layout primitives |
21
+ | `@geenius/storybook/types` | TypeScript type definitions |
22
+ | `@geenius/storybook/utils` | Hash routing, theme management, keyboard shortcuts |
23
+ | `@geenius/storybook/vite` | `createStorybookViteConfig()` factory |
24
+ | `@geenius/storybook/styles` | Shell layout CSS (sidebar, panels, dashboard, comparison) |
25
+ | `@geenius/storybook/theme` | Component design tokens (OKLCH dark/light + Tailwind v4 `@theme`) |
26
+ | `@geenius/storybook/html` | Base HTML template with font imports |
27
27
 
28
28
  ## Quick Start
29
29
 
@@ -31,33 +31,33 @@ pnpm add @geenius/storybook
31
31
 
32
32
  ```ts
33
33
  // apps/storybook-react/src/surface.ts
34
- import { defineSurface } from '@geenius/storybook/surface'
34
+ import { defineSurface } from "@geenius/storybook/surface";
35
35
 
36
36
  export const SURFACE = defineSurface([
37
37
  {
38
- title: 'Primitives',
38
+ title: "Primitives",
39
39
  stories: [
40
- { id: 'button', label: 'Button' },
41
- { id: 'input', label: 'Input' },
40
+ { id: "button", label: "Button" },
41
+ { id: "input", label: "Input" },
42
42
  ],
43
43
  },
44
- ])
44
+ ]);
45
45
  ```
46
46
 
47
47
  ### 2. Create a Vite config
48
48
 
49
49
  ```ts
50
50
  // apps/storybook-react/vite.config.ts
51
- import { createStorybookViteConfig } from '@geenius/storybook/vite'
52
- import react from '@vitejs/plugin-react'
53
- import tailwindcss from '@tailwindcss/vite'
51
+ import { createStorybookViteConfig } from "@geenius/storybook/vite";
52
+ import react from "@vitejs/plugin-react";
53
+ import tailwindcss from "@tailwindcss/vite";
54
54
 
55
55
  export default createStorybookViteConfig({
56
- framework: 'react',
56
+ framework: "react",
57
57
  port: 3050,
58
58
  plugins: [react()],
59
59
  tailwind: tailwindcss(),
60
- })
60
+ });
61
61
  ```
62
62
 
63
63
  ### 3. Import styles
@@ -72,7 +72,7 @@ export default createStorybookViteConfig({
72
72
  ### 4. Use shell classes in your App
73
73
 
74
74
  ```tsx
75
- import { ReactStorybookApp } from '@geenius/storybook/react'
75
+ import { ReactStorybookApp } from "@geenius/storybook/react";
76
76
 
77
77
  export function App() {
78
78
  return (
@@ -84,7 +84,7 @@ export function App() {
84
84
  components={COMPONENTS}
85
85
  defaultStoryId="button"
86
86
  />
87
- )
87
+ );
88
88
  }
89
89
  ```
90
90
 
@@ -93,17 +93,20 @@ export function App() {
93
93
  All classes use the `gsb-` prefix to avoid collisions.
94
94
 
95
95
  ### Layout
96
+
96
97
  - `.gsb-shell` — Root grid (sidebar + main)
97
98
  - `.gsb-sidebar` — Sticky sidebar with blur backdrop
98
99
  - `.gsb-main` / `.gsb-main__inner` — Constrained content area
99
100
 
100
101
  ### Sidebar
102
+
101
103
  - `.gsb-sidebar__item` — Nav item (add `.is-active` for selected state)
102
104
  - `.gsb-sidebar__section` / `__section-title` — Grouped sections
103
105
  - `.gsb-search__input` — Filter input
104
106
  - `.gsb-theme-toggle` — Theme switch button
105
107
 
106
108
  ### Content
109
+
107
110
  - `.gsb-hero` — Landing hero card
108
111
  - `.gsb-comparison` — 2-column TW vs CSS comparison grid
109
112
  - `.gsb-comparison__canvas` — Individual comparison pane
@@ -112,6 +115,7 @@ All classes use the `gsb-` prefix to avoid collisions.
112
115
  - `.gsb-note` — Callout (modifiers: `--warning`, `--success`, `--danger`)
113
116
 
114
117
  ### Utilities
118
+
115
119
  - `.gsb-stack` — Vertical flex gap
116
120
  - `.gsb-inline` — Horizontal flex wrap
117
121
  - `.gsb-frame` — Bordered container
@@ -121,15 +125,15 @@ All classes use the `gsb-` prefix to avoid collisions.
121
125
  - `.gsb-muted` — Muted text
122
126
 
123
127
  ### Responsive
128
+
124
129
  - `<= 860px`: Sidebar becomes mobile drawer (`.is-open` + `.gsb-backdrop`)
125
130
  - `<= 1080px`: 3-column grids collapse to 2
126
131
  - `<= 640px`: Tighter padding
127
132
 
128
133
  ## Package Contract
129
134
 
130
- This package follows the [Geenius Package Golden Standard](../PACKAGE_GOLDEN_STANDARD.md).
131
-
132
135
  - Versioned via **Changesets**
133
136
  - CI: `ci.yml` (lint + build + test on PR/push)
134
137
  - Release: `release.yml` (changesets/action on main)
135
138
  - ESM-only, Node >= 20
139
+ - Runtime coverage: React and SolidJS shells, plus framework-agnostic surface, theme, utils, and Vite helpers
package/dist/react.d.ts CHANGED
@@ -1,17 +1,20 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ComponentType, ReactNode } from 'react';
3
3
 
4
+ /** Metadata needed by the sidebar and hero surfaces for each registered story. */
4
5
  type StoryEntry<StoryId extends string> = {
5
6
  id: StoryId;
6
7
  label: string;
7
8
  description?: string;
8
9
  tags?: readonly string[];
9
10
  };
11
+ /** Groups related stories into the navigation buckets shown in the sidebar. */
10
12
  type StorySection<StoryId extends string> = {
11
13
  title: string;
12
14
  stories: readonly StoryEntry<StoryId>[];
13
15
  };
14
16
  type StoryComponentMap<StoryId extends string> = Record<StoryId, ComponentType<Record<string, never>>>;
17
+ /** Wraps a story in the common title, summary, and optional action chrome. */
15
18
  declare function StoryDeck(props: {
16
19
  eyebrow?: string;
17
20
  title: string;
@@ -19,20 +22,24 @@ declare function StoryDeck(props: {
19
22
  children: ReactNode;
20
23
  actions?: ReactNode;
21
24
  }): react_jsx_runtime.JSX.Element;
25
+ /** Lays out story cards in the two-column and three-column review modes. */
22
26
  declare function StoryGrid(props: {
23
27
  columns?: 2 | 3;
24
28
  children: ReactNode;
25
29
  }): react_jsx_runtime.JSX.Element;
30
+ /** Applies the shared card chrome used by all package storybooks. */
26
31
  declare function StoryCard(props: {
27
32
  title: string;
28
33
  summary?: string;
29
- tone?: 'default' | 'accent' | 'success' | 'warning' | 'danger';
34
+ tone?: "default" | "accent" | "success" | "warning" | "danger";
30
35
  children: ReactNode;
31
36
  }): react_jsx_runtime.JSX.Element;
37
+ /** Highlights review notes without overpowering the primary story canvas. */
32
38
  declare function StoryNote(props: {
33
- tone?: 'info' | 'warning' | 'success' | 'danger';
39
+ tone?: "info" | "warning" | "success" | "danger";
34
40
  children: ReactNode;
35
41
  }): react_jsx_runtime.JSX.Element;
42
+ /** Renders compact metric callouts beside a story to explain what matters. */
36
43
  declare function StoryMetrics(props: {
37
44
  items: ReadonlyArray<{
38
45
  label: string;
@@ -40,12 +47,17 @@ declare function StoryMetrics(props: {
40
47
  detail?: string;
41
48
  }>;
42
49
  }): react_jsx_runtime.JSX.Element;
50
+ /** Presents two related story canvases side by side for direct comparison. */
43
51
  declare function StoryComparison(props: {
44
52
  primaryLabel: string;
45
53
  secondaryLabel: string;
46
54
  primary: ReactNode;
47
55
  secondary: ReactNode;
48
56
  }): react_jsx_runtime.JSX.Element;
57
+ /**
58
+ * Drives the shared React storybook shell, including URL routing, sidebar
59
+ * filtering, theme persistence, and keyboard-driven navigation.
60
+ */
49
61
  declare function ReactStorybookApp<StoryId extends string>(props: {
50
62
  packageName: string;
51
63
  frameworkLabel: string;
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { filterSurface } from './chunk-FB7KPF72.js';
1
+ import { filterSurface, findSurfaceSection } from './chunk-FB7KPF72.js';
2
2
  import { getStoredTheme, setHashRoute, setStoredTheme, getHashRoute, matchesShortcut, DEFAULT_SHORTCUTS, applyTheme, resolveTheme } from './chunk-IEHIPVSX.js';
3
3
  import { useMemo, useState, useRef, useEffect } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -9,6 +9,9 @@ function isTypingTarget(target) {
9
9
  function isFocusSearchShortcut(event) {
10
10
  return matchesShortcut(event, DEFAULT_SHORTCUTS.focusSearch) || matchesShortcut(event, "Cmd+K") || matchesShortcut(event, "Ctrl+K");
11
11
  }
12
+ function getNextThemeMode(current) {
13
+ return current === "dark" ? "light" : current === "light" ? "system" : "dark";
14
+ }
12
15
  function syncTheme(mode) {
13
16
  applyTheme(resolveTheme(mode));
14
17
  if (mode !== "system" || typeof window === "undefined") {
@@ -71,7 +74,10 @@ function ReactStorybookApp(props) {
71
74
  () => props.sections.flatMap((section) => section.stories),
72
75
  [props.sections]
73
76
  );
74
- const allIds = useMemo(() => allStories.map((story) => story.id), [allStories]);
77
+ const allIds = useMemo(
78
+ () => allStories.map((story) => story.id),
79
+ [allStories]
80
+ );
75
81
  const resolveRoute = () => {
76
82
  const route = getHashRoute(allIds);
77
83
  return route === "dashboard" ? props.defaultStoryId : route;
@@ -138,92 +144,127 @@ function ReactStorybookApp(props) {
138
144
  };
139
145
  });
140
146
  }, [props.sections, search]);
141
- const activeMeta = allStories.find((story) => story.id === activeStory) ?? allStories[0];
147
+ const activeMeta = allStories.find((story) => story.id === activeStory) ?? allStories[0] ?? {
148
+ id: props.defaultStoryId,
149
+ label: "Missing story surface entry",
150
+ description: "The storybook shell could not find a surface entry for the requested story.",
151
+ tags: ["unconfigured"]
152
+ };
142
153
  const ActiveComponent = props.components[activeMeta.id];
154
+ const activeSection = findSurfaceSection(props.sections, activeMeta.id);
155
+ const activeIndex = allStories.findIndex(
156
+ (story) => story.id === activeMeta.id
157
+ );
158
+ const visibleStoryCount = filteredSections.reduce(
159
+ (sum, section) => sum + section.stories.length,
160
+ 0
161
+ );
162
+ const storyPositionLabel = activeIndex >= 0 ? `${activeIndex + 1} of ${allStories.length}` : "Unmapped";
163
+ const hasSearchFilter = search.trim().length > 0;
164
+ const searchMetaLabel = hasSearchFilter ? `${visibleStoryCount} of ${allStories.length} visible` : `${allStories.length} stories indexed`;
165
+ const hasStories = allStories.length > 0;
166
+ const missingStoryMessage = hasStories ? `Missing story implementation for "${activeMeta.id}". Verify the registry matches the declared surface.` : "No stories are registered for this storybook yet.";
143
167
  const themeLabel = themeMode === "dark" ? "Dark" : themeMode === "light" ? "Light" : "System";
144
168
  return /* @__PURE__ */ jsxs(Fragment, { children: [
145
169
  /* @__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(
170
+ /* @__PURE__ */ jsxs(
171
+ "aside",
172
+ {
173
+ id: "gsb-sidebar-nav",
174
+ className: `gsb-sidebar${sidebarOpen ? " is-open" : ""}`,
175
+ children: [
176
+ /* @__PURE__ */ jsxs("div", { className: "gsb-sidebar__top", children: [
177
+ /* @__PURE__ */ jsxs("div", { className: "gsb-sidebar__brand", children: [
178
+ /* @__PURE__ */ jsx("p", { className: "gsb-eyebrow", children: props.frameworkLabel }),
179
+ /* @__PURE__ */ jsx("h1", { className: "gsb-sidebar__title", children: props.packageName }),
180
+ /* @__PURE__ */ jsx("p", { className: "gsb-sidebar__summary", children: props.overview })
181
+ ] }),
182
+ /* @__PURE__ */ jsx("span", { className: "gsb-count", children: allStories.length })
183
+ ] }),
184
+ /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__toolbar", children: /* @__PURE__ */ jsx(
165
185
  "button",
166
186
  {
167
187
  type: "button",
168
188
  className: "gsb-theme-toggle",
189
+ "aria-label": `Cycle theme mode. Current theme: ${themeLabel}`,
169
190
  onClick: () => setThemeMode((previous) => {
170
- const next = previous === "dark" ? "light" : previous === "light" ? "system" : "dark";
191
+ const next = getNextThemeMode(previous);
171
192
  setStoredTheme(next);
172
193
  return next;
173
194
  }),
174
195
  children: themeLabel
175
196
  }
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(
197
+ ) }),
198
+ /* @__PURE__ */ jsxs("div", { className: "gsb-search", children: [
199
+ /* @__PURE__ */ jsx(
200
+ "input",
201
+ {
202
+ ref: searchInputRef,
203
+ type: "search",
204
+ value: search,
205
+ onChange: (event) => setSearch(event.target.value),
206
+ "aria-label": "Search storybook stories",
207
+ placeholder: "Search stories, tags, or ids\u2026",
208
+ className: "gsb-search__input"
209
+ }
210
+ ),
211
+ /* @__PURE__ */ jsxs("div", { className: "gsb-search__meta", children: [
212
+ /* @__PURE__ */ jsx("span", { children: searchMetaLabel }),
213
+ /* @__PURE__ */ jsxs("span", { className: "gsb-inline", children: [
214
+ /* @__PURE__ */ jsx("span", { className: "gsb-kbd", children: "/" }),
215
+ /* @__PURE__ */ jsx("span", { className: "gsb-kbd", children: "T" }),
216
+ /* @__PURE__ */ jsx("span", { className: "gsb-kbd", children: "H" })
217
+ ] })
218
+ ] })
219
+ ] }),
220
+ 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: [
221
+ /* @__PURE__ */ jsx("h2", { className: "gsb-sidebar__section-title", children: section.title }),
222
+ /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__items", children: section.stories.map((story) => /* @__PURE__ */ jsxs(
223
+ "button",
224
+ {
225
+ type: "button",
226
+ className: `gsb-sidebar__item${story.id === activeMeta.id ? " is-active" : ""}`,
227
+ onClick: () => {
228
+ setActiveStory(story.id);
229
+ setSidebarOpen(false);
230
+ },
231
+ children: [
232
+ /* @__PURE__ */ jsxs("div", { className: "gsb-sidebar__item-title", children: [
233
+ /* @__PURE__ */ jsx("span", { children: story.label }),
234
+ story.tags?.[0] ? /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: story.tags[0] }) : null
235
+ ] }),
236
+ /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__item-id", children: story.id }),
237
+ story.description ? /* @__PURE__ */ jsx("div", { className: "gsb-sidebar__item-description", children: story.description }) : null
238
+ ]
239
+ },
240
+ story.id
241
+ )) })
242
+ ] }, section.title))
243
+ ]
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsx("main", { className: "gsb-main", children: /* @__PURE__ */ jsxs("div", { className: "gsb-main__inner", children: [
247
+ /* @__PURE__ */ jsxs("div", { className: "gsb-topbar", children: [
248
+ /* @__PURE__ */ jsxs("div", { className: "gsb-topbar__meta", children: [
249
+ /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: activeSection?.title ?? "Story" }),
250
+ /* @__PURE__ */ jsx("span", { className: "gsb-muted", children: storyPositionLabel })
251
+ ] }),
252
+ /* @__PURE__ */ jsx(
193
253
  "button",
194
254
  {
195
255
  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
- ) }),
256
+ className: "gsb-nav-toggle",
257
+ "aria-controls": "gsb-sidebar-nav",
258
+ "aria-expanded": sidebarOpen,
259
+ onClick: () => setSidebarOpen(true),
260
+ children: "Browse stories"
261
+ }
262
+ )
263
+ ] }),
224
264
  /* @__PURE__ */ jsxs("header", { className: "gsb-hero", children: [
225
265
  /* @__PURE__ */ jsxs("div", { className: "gsb-hero__meta", children: [
226
266
  /* @__PURE__ */ jsx("span", { className: "gsb-pill gsb-pill--accent", children: props.frameworkLabel }),
267
+ activeSection ? /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: activeSection.title }) : null,
227
268
  /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: activeMeta.id }),
228
269
  activeMeta.tags?.map((tag) => /* @__PURE__ */ jsx("span", { className: "gsb-pill", children: tag }, tag))
229
270
  ] }),
@@ -233,7 +274,7 @@ function ReactStorybookApp(props) {
233
274
  activeMeta.description ? /* @__PURE__ */ jsx("p", { className: "gsb-hero__summary", children: activeMeta.description }) : null
234
275
  ] })
235
276
  ] }),
236
- /* @__PURE__ */ jsx("div", { className: "gsb-story-space", children: /* @__PURE__ */ jsx(ActiveComponent, {}) })
277
+ /* @__PURE__ */ jsx("div", { className: "gsb-story-space", children: ActiveComponent ? /* @__PURE__ */ jsx(ActiveComponent, {}) : /* @__PURE__ */ jsx("div", { className: "gsb-empty", children: missingStoryMessage }) })
237
278
  ] }) })
238
279
  ] }),
239
280
  sidebarOpen ? /* @__PURE__ */ jsx(
package/dist/react.js.map CHANGED
@@ -1 +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"]}
1
+ {"version":3,"sources":["../src/react.tsx"],"names":[],"mappings":"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","file":"react.js","sourcesContent":["/* ============================================================================\n @geenius/storybook — React Runtime\n ============================================================================\n Shared React shell primitives used by package storybook apps. This file owns\n the non-obvious runtime behavior: hash routing, search, theme persistence,\n and keyboard shortcuts.\n ============================================================================ */\n\nimport {\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\";\nimport { findSurfaceSection } from \"./surface.js\";\n\n/** Metadata needed by the sidebar and hero surfaces for each registered story. */\nexport type StoryEntry<StoryId extends string> = {\n id: StoryId;\n label: string;\n description?: string;\n tags?: readonly string[];\n};\n\n/** Groups related stories into the navigation buckets shown in the sidebar. */\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\n/** Detects whether a key event originated from an editable target. */\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\n/** Supports both the default `/` shortcut and the familiar Cmd/Ctrl+K pattern. */\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\n/** Rotate through dark, light, and system modes in a fixed order. */\nfunction getNextThemeMode(current: ThemeMode): ThemeMode {\n return current === \"dark\" ? \"light\" : current === \"light\" ? \"system\" : \"dark\";\n}\n\n/** Applies the selected theme immediately and returns any media-listener cleanup. */\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\n/** Wraps a story in the common title, summary, and optional action chrome. */\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\n/** Lays out story cards in the two-column and three-column review modes. */\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\n/** Applies the shared card chrome used by all package storybooks. */\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\n/** Highlights review notes without overpowering the primary story canvas. */\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\n/** Renders compact metric callouts beside a story to explain what matters. */\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\n/** Presents two related story canvases side by side for direct comparison. */\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\n/**\n * Drives the shared React storybook shell, including URL routing, sidebar\n * filtering, theme persistence, and keyboard-driven navigation.\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(\n () => allStories.map((story) => story.id),\n [allStories],\n );\n\n // Hash routing wins on initial load so shared links reopen the same story.\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 // Theme changes are applied at the document root so every story inherits them.\n useEffect(() => syncTheme(themeMode), [themeMode]);\n\n // Persist the active story in the hash for refresh-safe deep links.\n useEffect(() => {\n setHashRoute(activeStory);\n }, [activeStory]);\n\n // Back/forward navigation should reopen the matching story without a full remount.\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 // Home always returns to the package's designated landing story.\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 // Search filters within sections so the original grouping still communicates intent.\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 = allStories.find((story) => story.id === activeStory) ??\n allStories[0] ?? {\n id: props.defaultStoryId,\n label: \"Missing story surface entry\",\n description:\n \"The storybook shell could not find a surface entry for the requested story.\",\n tags: [\"unconfigured\"],\n };\n const ActiveComponent = props.components[activeMeta.id] as\n | ComponentType<Record<string, never>>\n | undefined;\n const activeSection = findSurfaceSection(props.sections, activeMeta.id);\n const activeIndex = allStories.findIndex(\n (story) => story.id === activeMeta.id,\n );\n const visibleStoryCount = filteredSections.reduce(\n (sum, section) => sum + section.stories.length,\n 0,\n );\n const storyPositionLabel =\n activeIndex >= 0\n ? `${activeIndex + 1} of ${allStories.length}`\n : \"Unmapped\";\n const hasSearchFilter = search.trim().length > 0;\n const searchMetaLabel = hasSearchFilter\n ? `${visibleStoryCount} of ${allStories.length} visible`\n : `${allStories.length} stories indexed`;\n const hasStories = allStories.length > 0;\n const missingStoryMessage = hasStories\n ? `Missing story implementation for \"${activeMeta.id}\". Verify the registry matches the declared surface.`\n : \"No stories are registered for this storybook yet.\";\n const themeLabel =\n themeMode === \"dark\" ? \"Dark\" : themeMode === \"light\" ? \"Light\" : \"System\";\n\n return (\n <>\n <div className=\"gsb-shell\">\n <aside\n id=\"gsb-sidebar-nav\"\n className={`gsb-sidebar${sidebarOpen ? \" is-open\" : \"\"}`}\n >\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 className=\"gsb-sidebar__toolbar\">\n <button\n type=\"button\"\n className=\"gsb-theme-toggle\"\n aria-label={`Cycle theme mode. Current theme: ${themeLabel}`}\n onClick={() =>\n setThemeMode((previous) => {\n const next = getNextThemeMode(previous);\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 aria-label=\"Search storybook stories\"\n placeholder=\"Search stories, tags, or ids…\"\n className=\"gsb-search__input\"\n />\n <div className=\"gsb-search__meta\">\n <span>{searchMetaLabel}</span>\n <span className=\"gsb-inline\">\n <span className=\"gsb-kbd\">/</span>\n <span className=\"gsb-kbd\">T</span>\n <span className=\"gsb-kbd\">H</span>\n </span>\n </div>\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 <div className=\"gsb-topbar__meta\">\n <span className=\"gsb-pill\">\n {activeSection?.title ?? \"Story\"}\n </span>\n <span className=\"gsb-muted\">{storyPositionLabel}</span>\n </div>\n <button\n type=\"button\"\n className=\"gsb-nav-toggle\"\n aria-controls=\"gsb-sidebar-nav\"\n aria-expanded={sidebarOpen}\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 {activeSection ? (\n <span className=\"gsb-pill\">{activeSection.title}</span>\n ) : null}\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 <ActiveComponent />\n ) : (\n <div className=\"gsb-empty\">{missingStoryMessage}</div>\n )}\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"]}