@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 +6 -0
- package/README.md +31 -27
- package/dist/react.d.ts +14 -2
- package/dist/react.js +110 -69
- package/dist/react.js.map +1 -1
- package/dist/solidjs.d.ts +14 -2
- package/dist/solidjs.js +115 -67
- package/dist/solidjs.js.map +1 -1
- package/dist/styles.css +108 -25
- package/package.json +1 -1
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
|
|
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
|
|
16
|
-
|
|
17
|
-
| `@geenius/storybook`
|
|
18
|
-
| `@geenius/storybook/surface` | Story catalog definition and query utilities
|
|
19
|
-
| `@geenius/storybook/react`
|
|
20
|
-
| `@geenius/storybook/solidjs` | Shared SolidJS storybook shell and layout primitives
|
|
21
|
-
| `@geenius/storybook/types`
|
|
22
|
-
| `@geenius/storybook/utils`
|
|
23
|
-
| `@geenius/storybook/vite`
|
|
24
|
-
| `@geenius/storybook/styles`
|
|
25
|
-
| `@geenius/storybook/theme`
|
|
26
|
-
| `@geenius/storybook/html`
|
|
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
|
|
34
|
+
import { defineSurface } from "@geenius/storybook/surface";
|
|
35
35
|
|
|
36
36
|
export const SURFACE = defineSurface([
|
|
37
37
|
{
|
|
38
|
-
title:
|
|
38
|
+
title: "Primitives",
|
|
39
39
|
stories: [
|
|
40
|
-
{ id:
|
|
41
|
-
{ id:
|
|
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
|
|
52
|
-
import react from
|
|
53
|
-
import tailwindcss from
|
|
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:
|
|
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
|
|
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?:
|
|
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?:
|
|
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(
|
|
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(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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"]}
|