@gtkx/storybook 2.0.0-beta.12 → 2.0.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +4 -1
- package/dist/catalog.js.map +1 -1
- package/dist/config.d.ts +4 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/controls.d.ts +2 -1
- package/dist/controls.d.ts.map +1 -1
- package/dist/controls.js +9 -5
- package/dist/controls.js.map +1 -1
- package/dist/explorer-navigator.d.ts.map +1 -1
- package/dist/explorer-navigator.js +29 -2
- package/dist/explorer-navigator.js.map +1 -1
- package/dist/explorer-preview.d.ts.map +1 -1
- package/dist/explorer-preview.js +23 -4
- package/dist/explorer-preview.js.map +1 -1
- package/dist/explorer-view.d.ts +5 -1
- package/dist/explorer-view.d.ts.map +1 -1
- package/dist/explorer-view.js +17 -7
- package/dist/explorer-view.js.map +1 -1
- package/dist/explorer.d.ts +4 -0
- package/dist/explorer.d.ts.map +1 -1
- package/dist/explorer.js +6 -1
- package/dist/explorer.js.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/upstream.d.ts +4 -2
- package/dist/upstream.d.ts.map +1 -1
- package/dist/upstream.js +3 -1
- package/dist/upstream.js.map +1 -1
- package/package.json +9 -9
- package/src/catalog.ts +13 -10
- package/src/config.ts +4 -1
- package/src/controls.tsx +12 -6
- package/src/explorer-navigator.tsx +45 -4
- package/src/explorer-preview.tsx +55 -19
- package/src/explorer-view.tsx +40 -11
- package/src/explorer.ts +12 -1
- package/src/types.ts +19 -7
- package/src/upstream.ts +6 -2
package/src/explorer-view.tsx
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
AdwWindowTitle,
|
|
11
11
|
} from "@gtkx/jsx/adw";
|
|
12
12
|
import { quit } from "@gtkx/react";
|
|
13
|
-
import { useCallback, useState, useSyncExternalStore } from "react";
|
|
13
|
+
import { useCallback, useEffect, useEffectEvent, useState, useSyncExternalStore } from "react";
|
|
14
14
|
import type { StoryCatalog } from "./catalog.js";
|
|
15
15
|
import { StoryNavigator } from "./explorer-navigator.js";
|
|
16
16
|
import { StorybookPreview } from "./explorer-preview.js";
|
|
@@ -23,31 +23,53 @@ type StorybookProps = {
|
|
|
23
23
|
applicationId?: string;
|
|
24
24
|
/** Explorer window and sidebar title; defaults to GTKX Storybook. */
|
|
25
25
|
title?: string;
|
|
26
|
+
/** Story selected once the catalog lists it; the first story is selected otherwise. */
|
|
27
|
+
initialStoryId?: string | undefined;
|
|
28
|
+
/** Called with the identifier of each story the explorer selects. */
|
|
29
|
+
onStorySelected?: ((id: string) => void) | undefined;
|
|
26
30
|
};
|
|
27
31
|
|
|
28
|
-
type StorybookViewProps = Pick<StorybookProps, "catalog" | "title">;
|
|
32
|
+
type StorybookViewProps = Pick<StorybookProps, "catalog" | "title" | "initialStoryId" | "onStorySelected">;
|
|
29
33
|
|
|
30
|
-
const
|
|
34
|
+
const storyCount = (count: number): string => (count === 1 ? "1 story" : `${String(count)} stories`);
|
|
35
|
+
|
|
36
|
+
const StorybookView = ({
|
|
37
|
+
catalog,
|
|
38
|
+
title = "GTKX Storybook",
|
|
39
|
+
initialStoryId,
|
|
40
|
+
onStorySelected,
|
|
41
|
+
}: StorybookViewProps): ReactNode => {
|
|
31
42
|
const subscribe = useCallback((listener: () => void) => catalog.subscribe(listener), [catalog]);
|
|
32
43
|
const getSnapshot = useCallback(() => catalog.getSnapshot(), [catalog]);
|
|
33
44
|
const snapshot = useSyncExternalStore(subscribe, getSnapshot);
|
|
34
|
-
const [selectedId, setSelectedId] = useState
|
|
45
|
+
const [selectedId, setSelectedId] = useState(initialStoryId);
|
|
35
46
|
const selected = snapshot.stories.find((entry) => entry.id === selectedId) ?? snapshot.stories[0];
|
|
36
47
|
|
|
37
|
-
if (selectedId !== selected
|
|
38
|
-
setSelectedId(selected
|
|
48
|
+
if (selected !== undefined && selectedId !== selected.id) {
|
|
49
|
+
setSelectedId(selected.id);
|
|
39
50
|
}
|
|
40
51
|
|
|
52
|
+
const selectedStoryId = selected?.id;
|
|
53
|
+
const reportSelection = useEffectEvent((id: string) => {
|
|
54
|
+
onStorySelected?.(id);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (selectedStoryId !== undefined) {
|
|
59
|
+
reportSelection(selectedStoryId);
|
|
60
|
+
}
|
|
61
|
+
}, [selectedStoryId]);
|
|
62
|
+
|
|
41
63
|
return (
|
|
42
64
|
<AdwOverlaySplitView
|
|
43
65
|
minSidebarWidth={220}
|
|
44
66
|
maxSidebarWidth={300}
|
|
45
67
|
sidebar={
|
|
46
68
|
<AdwToolbarView
|
|
47
|
-
|
|
69
|
+
top={
|
|
48
70
|
<AdwHeaderBar
|
|
49
71
|
titleWidget={
|
|
50
|
-
<AdwWindowTitle title={title} subtitle={
|
|
72
|
+
<AdwWindowTitle title={title} subtitle={storyCount(snapshot.stories.length)} />
|
|
51
73
|
}
|
|
52
74
|
/>
|
|
53
75
|
}
|
|
@@ -55,7 +77,7 @@ const StorybookView = ({ catalog, title = "GTKX Storybook" }: StorybookViewProps
|
|
|
55
77
|
<StoryNavigator
|
|
56
78
|
stories={snapshot.stories}
|
|
57
79
|
errors={snapshot.errors}
|
|
58
|
-
selectedId={
|
|
80
|
+
selectedId={selectedStoryId}
|
|
59
81
|
onSelect={setSelectedId}
|
|
60
82
|
/>
|
|
61
83
|
</AdwToolbarView>
|
|
@@ -64,7 +86,7 @@ const StorybookView = ({ catalog, title = "GTKX Storybook" }: StorybookViewProps
|
|
|
64
86
|
{selected ? (
|
|
65
87
|
<StorybookPreview key={selected.id} entry={selected} />
|
|
66
88
|
) : (
|
|
67
|
-
<AdwToolbarView
|
|
89
|
+
<AdwToolbarView top={<AdwHeaderBar />}>
|
|
68
90
|
<AdwStatusPage
|
|
69
91
|
name="storybook-empty"
|
|
70
92
|
title={snapshot.isLoading ? "Loading stories" : "Choose a story"}
|
|
@@ -82,10 +104,17 @@ const Storybook = ({
|
|
|
82
104
|
catalog,
|
|
83
105
|
applicationId = "org.gtkx.Storybook",
|
|
84
106
|
title = "GTKX Storybook",
|
|
107
|
+
initialStoryId,
|
|
108
|
+
onStorySelected,
|
|
85
109
|
}: StorybookProps): ReactNode => (
|
|
86
110
|
<AdwApplication applicationId={applicationId} flags={Gio.ApplicationFlags.NON_UNIQUE}>
|
|
87
111
|
<AdwApplicationWindow title={title} defaultWidth={1200} defaultHeight={800} onCloseRequest={quit}>
|
|
88
|
-
<StorybookView
|
|
112
|
+
<StorybookView
|
|
113
|
+
catalog={catalog}
|
|
114
|
+
title={title}
|
|
115
|
+
initialStoryId={initialStoryId}
|
|
116
|
+
onStorySelected={onStorySelected}
|
|
117
|
+
/>
|
|
89
118
|
</AdwApplicationWindow>
|
|
90
119
|
</AdwApplication>
|
|
91
120
|
);
|
package/src/explorer.ts
CHANGED
|
@@ -19,10 +19,21 @@ type StorybookSession = {
|
|
|
19
19
|
const startStorybook = (options: {
|
|
20
20
|
/** Gio application identifier assigned to the explorer application. */
|
|
21
21
|
applicationId: string;
|
|
22
|
+
/** Story to select once it is loaded, such as the one a restarted explorer was showing. */
|
|
23
|
+
initialStoryId?: string | undefined;
|
|
24
|
+
/** Called with the identifier of each story the explorer selects. */
|
|
25
|
+
onStorySelected?: ((id: string) => void) | undefined;
|
|
22
26
|
}): StorybookSession => {
|
|
23
27
|
const catalog = new StoryCatalog();
|
|
24
28
|
const root = createRoot(undefined, { onUncaughtError: catalog.reportError.bind(catalog) });
|
|
25
|
-
root.render(
|
|
29
|
+
root.render(
|
|
30
|
+
createElement(Storybook, {
|
|
31
|
+
catalog,
|
|
32
|
+
applicationId: options.applicationId,
|
|
33
|
+
initialStoryId: options.initialStoryId,
|
|
34
|
+
onStorySelected: options.onStorySelected,
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
26
37
|
|
|
27
38
|
return {
|
|
28
39
|
updateStories: (sources, preview) => catalog.load(sources, preview),
|
package/src/types.ts
CHANGED
|
@@ -154,21 +154,33 @@ type StoryModule = {
|
|
|
154
154
|
default: unknown;
|
|
155
155
|
};
|
|
156
156
|
|
|
157
|
+
/** Whether a story's declared args name only args of the component metadata, as stories typed from the metadata do. */
|
|
158
|
+
type IsMetaArgs<TArgs, TMetaArgs> = [Exclude<keyof TArgs, keyof TMetaArgs>] extends [never] ? true : false;
|
|
159
|
+
|
|
160
|
+
/** Args of a story export: the component metadata's args, or the args type the story declares itself. */
|
|
161
|
+
type StoryArgs<TModule extends StoryModule, TStory> =
|
|
162
|
+
TStory extends StoryAnnotations<infer TArgs extends object>
|
|
163
|
+
? IsMetaArgs<TArgs, ArgsFrom<TModule["default"]>> extends true
|
|
164
|
+
? TStory extends StoryAnnotations<ArgsFrom<TModule["default"]>>
|
|
165
|
+
? ArgsFrom<TModule["default"]>
|
|
166
|
+
: TArgs
|
|
167
|
+
: TArgs
|
|
168
|
+
: never;
|
|
169
|
+
|
|
157
170
|
/** Named module exports whose types match CSF3 stories, excluding module bookkeeping. */
|
|
158
171
|
type StoryKeys<TModule extends StoryModule> = {
|
|
159
172
|
[Key in keyof TModule]: Key extends "default" | "__esModule" | "__namedExportsOrder"
|
|
160
173
|
? never
|
|
161
|
-
: TModule[Key] extends
|
|
162
|
-
?
|
|
163
|
-
:
|
|
174
|
+
: [StoryArgs<TModule, TModule[Key]>] extends [never]
|
|
175
|
+
? never
|
|
176
|
+
: Key;
|
|
164
177
|
}[keyof TModule] &
|
|
165
178
|
string;
|
|
166
179
|
|
|
167
180
|
/** Composed stories keyed by their original named exports. */
|
|
168
|
-
type ComposedStories<TModule extends StoryModule> =
|
|
169
|
-
StoryKeys<TModule
|
|
170
|
-
|
|
171
|
-
>;
|
|
181
|
+
type ComposedStories<TModule extends StoryModule> = {
|
|
182
|
+
[Key in StoryKeys<TModule>]: ComposedStory<StoryArgs<TModule, TModule[Key]>>;
|
|
183
|
+
};
|
|
172
184
|
|
|
173
185
|
export type {
|
|
174
186
|
Args,
|
package/src/upstream.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { InputType } from "storybook/internal/types";
|
|
2
|
+
import { includeConditionalArg } from "storybook/internal/csf";
|
|
1
3
|
import { composeStory } from "storybook/preview-api";
|
|
2
|
-
import type { ComponentMeta, ComposedStory, Preview, StoryAnnotations, StoryRender } from "./types.js";
|
|
4
|
+
import type { Args, ComponentMeta, ComposedStory, Preview, StoryAnnotations, StoryRender } from "./types.js";
|
|
3
5
|
|
|
4
6
|
type ComposeStory = <TArgs extends object>(
|
|
5
7
|
...annotations: [
|
|
@@ -13,6 +15,8 @@ type ComposeStory = <TArgs extends object>(
|
|
|
13
15
|
|
|
14
16
|
const composeStoryAnnotations = composeStory as ComposeStory;
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
const isConditionalArgIncluded: (argType: InputType, args: Args, globals: Args) => boolean = includeConditionalArg;
|
|
19
|
+
|
|
20
|
+
export { composeStoryAnnotations, isConditionalArgIncluded };
|
|
17
21
|
|
|
18
22
|
export { isExportStory, storyNameFromExport } from "storybook/internal/csf";
|