@repobuddy/storybook 2.2.2 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.d.ts +106 -5
- package/esm/index.js +52 -27
- package/esm/storybook-addon-tag-badges/index.d.ts +44 -22
- package/esm/storybook-dark-mode/index.d.ts +0 -1
- package/package.json +3 -3
- package/src/components/story_card.tsx +67 -0
- package/src/decorators/show_doc_source.tsx +15 -5
- package/src/decorators/with_story_card.tsx +11 -46
- package/src/index.ts +2 -0
- package/src/storybook-addon-tag-badges/tag_badges.ts +1 -0
- package/src/storybook-addon-tag-badges/types.ts +3 -2
- package/src/types/_extract_string_literals.ts +1 -0
- package/src/types/extends_meta.ts +37 -0
- package/src/types/extends_story_obj.ts +42 -0
- package/src/types.ts +4 -0
- package/styles.css +6 -0
package/esm/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
|
5
5
|
import { ClassNameProps, StyleProps } from "@just-web/css";
|
|
6
6
|
import { Args, DecoratorFunction, Renderer } from "storybook/internal/csf";
|
|
7
7
|
import { Decorator, Meta, StoryContext, StoryObj, StrictArgs } from "@storybook/react-vite";
|
|
8
|
+
import { IsStringLiteral } from "type-plus";
|
|
8
9
|
export * from "@repobuddy/test";
|
|
9
10
|
|
|
10
11
|
//#region src/components/show_html.d.ts
|
|
@@ -32,9 +33,11 @@ declare function ShowHtml({
|
|
|
32
33
|
* A decorator that shows the source code of a story above the rendered story.
|
|
33
34
|
* The source code is taken from the story's `parameters.docs.source.code`.
|
|
34
35
|
*/
|
|
35
|
-
declare function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Args>(
|
|
36
|
+
declare function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Args>(options?: {
|
|
37
|
+
showOriginalSource?: boolean | undefined;
|
|
38
|
+
}): DecoratorFunction<TRenderer, TArgs>;
|
|
36
39
|
//#endregion
|
|
37
|
-
//#region src/
|
|
40
|
+
//#region src/components/story_card.d.ts
|
|
38
41
|
type StoryCardProps = {
|
|
39
42
|
/**
|
|
40
43
|
* Optional title displayed as a heading in the card.
|
|
@@ -55,7 +58,26 @@ type StoryCardProps = {
|
|
|
55
58
|
* If a function is provided, it receives the card state and default className,
|
|
56
59
|
* and should return the final className string.
|
|
57
60
|
*/
|
|
58
|
-
className?: ((state:
|
|
61
|
+
className?: ((state: Pick<StoryCardProps, 'status'> & {
|
|
62
|
+
defaultClassName: string;
|
|
63
|
+
}) => string) | string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Content to display in the card body.
|
|
66
|
+
* Can be any React node (string, JSX, etc.).
|
|
67
|
+
*/
|
|
68
|
+
children?: ReactNode | undefined;
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/decorators/with_story_card.d.ts
|
|
72
|
+
type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'> & {
|
|
73
|
+
/**
|
|
74
|
+
* Additional CSS classes or a function to compute classes.
|
|
75
|
+
*
|
|
76
|
+
* If a string is provided, it will be merged with the default classes.
|
|
77
|
+
* If a function is provided, it receives the card state and default className,
|
|
78
|
+
* and should return the final className string.
|
|
79
|
+
*/
|
|
80
|
+
className?: ((state: Pick<StoryCardProps, 'status'> & {
|
|
59
81
|
defaultClassName: string;
|
|
60
82
|
}) => string) | string | undefined;
|
|
61
83
|
/**
|
|
@@ -139,7 +161,7 @@ declare function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
|
139
161
|
status,
|
|
140
162
|
content: contentProp,
|
|
141
163
|
...rest
|
|
142
|
-
}?:
|
|
164
|
+
}?: WithStoryCardProps): DecoratorFunction<TRenderer>;
|
|
143
165
|
//#endregion
|
|
144
166
|
//#region src/parameters/define_actions_param.d.ts
|
|
145
167
|
interface ActionsParam {
|
|
@@ -645,6 +667,8 @@ declare function whenRunningInTest<TArgs = StrictArgs>(decoratorOrHandler: ((...
|
|
|
645
667
|
* @template M - The base Meta type
|
|
646
668
|
* @template E - The extension type containing tagType
|
|
647
669
|
*
|
|
670
|
+
* @deprecated use `import { ExtendsMeta } from '@repobuddy/storybook'` instead.
|
|
671
|
+
*
|
|
648
672
|
* @example
|
|
649
673
|
* ```ts
|
|
650
674
|
* // Create a generic Meta type for a project
|
|
@@ -665,6 +689,8 @@ type ExtendMeta<TCmpOrArgs, M extends Meta<TCmpOrArgs>, E extends {
|
|
|
665
689
|
* @template S - The base StoryObj type
|
|
666
690
|
* @template E - The extension type containing tagType
|
|
667
691
|
*
|
|
692
|
+
* @deprecated use `import { ExtendsStoryObj } from '@repobuddy/storybook'` instead.
|
|
693
|
+
*
|
|
668
694
|
* @example
|
|
669
695
|
* ```ts
|
|
670
696
|
* // Create a generic StoryObj type for a project
|
|
@@ -680,4 +706,79 @@ type ExtendStoryObj<TMetaOrCmpOrArgs, S extends StoryObj<TMetaOrCmpOrArgs>, E ex
|
|
|
680
706
|
tags?: Array<E['tag'] | (string & {})> | undefined;
|
|
681
707
|
};
|
|
682
708
|
//#endregion
|
|
683
|
-
|
|
709
|
+
//#region src/types/_extract_string_literals.d.ts
|
|
710
|
+
type ExtractStringLiterals<T> = T extends any ? (string extends T ? never : T) : never;
|
|
711
|
+
//#endregion
|
|
712
|
+
//#region src/types/extends_meta.d.ts
|
|
713
|
+
/**
|
|
714
|
+
* Extends the Storybook Meta type with custom tag types.
|
|
715
|
+
*
|
|
716
|
+
* This utility type allows you to extend the `tags` property of a Storybook Meta type
|
|
717
|
+
* with custom string literal types while preserving existing tag types from the base Meta.
|
|
718
|
+
*
|
|
719
|
+
* @template M - The base Meta type to extend
|
|
720
|
+
* @template E - The extension type containing a `tag` property with the custom tag types
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* ```ts
|
|
724
|
+
* import type { ExtendsMeta } from '@repobuddy/storybook'
|
|
725
|
+
* import type { Args, Meta as M } from '@storybook/your-framework'
|
|
726
|
+
*
|
|
727
|
+
* // Create a generic Meta type for your project
|
|
728
|
+
* type Meta<TCmpOrArgs = Args> = ExtendsMeta<
|
|
729
|
+
* M<TCmpOrArgs>,
|
|
730
|
+
* { tag: 'new' | 'beta' | 'deprecated' }
|
|
731
|
+
* >
|
|
732
|
+
*
|
|
733
|
+
* // Use in component stories
|
|
734
|
+
* const meta: Meta<typeof Component> = {
|
|
735
|
+
* tags: ['new'], // <--- gets auto-completion for 'new' | 'beta' | 'deprecated'
|
|
736
|
+
* // ...
|
|
737
|
+
* }
|
|
738
|
+
* ```
|
|
739
|
+
*/
|
|
740
|
+
type ExtendsMeta<M extends {
|
|
741
|
+
tags?: string[] | undefined;
|
|
742
|
+
}, E extends {
|
|
743
|
+
tag: string;
|
|
744
|
+
}> = Omit<M, 'tags'> & {
|
|
745
|
+
tags?: ExtractStringLiterals<NonNullable<M['tags']>[number]> extends infer MT ? IsStringLiteral<MT> extends true ? Array<(string & {}) | MT | E['tag']> | undefined : Array<(string & {}) | E['tag']> | undefined : never;
|
|
746
|
+
};
|
|
747
|
+
//#endregion
|
|
748
|
+
//#region src/types/extends_story_obj.d.ts
|
|
749
|
+
/**
|
|
750
|
+
* Extends the Storybook StoryObj type with custom tag types.
|
|
751
|
+
*
|
|
752
|
+
* This utility type allows you to extend the `tags` property of a Storybook StoryObj type
|
|
753
|
+
* with custom string literal types while preserving existing tag types from the base StoryObj.
|
|
754
|
+
*
|
|
755
|
+
* @template S - The base StoryObj type to extend (must have an optional `tags` property)
|
|
756
|
+
* @template E - The extension type containing a `tag` property with the custom tag types
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* ```ts
|
|
760
|
+
* import type { ExtendsStoryObj } from '@repobuddy/storybook'
|
|
761
|
+
* import type { Args, StoryObj as S } from '@storybook/your-framework'
|
|
762
|
+
*
|
|
763
|
+
* // Create a generic StoryObj type for your project
|
|
764
|
+
* type StoryObj<TCmpOrArgs = Args> = ExtendsStoryObj<
|
|
765
|
+
* S<TCmpOrArgs>,
|
|
766
|
+
* { tag: 'new' | 'beta' | 'deprecated' }
|
|
767
|
+
* >
|
|
768
|
+
*
|
|
769
|
+
* // Use in component stories
|
|
770
|
+
* const story: StoryObj<typeof Component> = {
|
|
771
|
+
* tags: ['new'], // <--- gets auto-completion for 'new' | 'beta' | 'deprecated'
|
|
772
|
+
* // ...
|
|
773
|
+
* }
|
|
774
|
+
* ```
|
|
775
|
+
*/
|
|
776
|
+
type ExtendsStoryObj<S extends {
|
|
777
|
+
tags?: string[] | undefined;
|
|
778
|
+
}, E extends {
|
|
779
|
+
tag: string;
|
|
780
|
+
}> = Omit<S, 'tags'> & {
|
|
781
|
+
tags?: ExtractStringLiterals<NonNullable<S['tags']>[number]> extends infer MT ? IsStringLiteral<MT> extends true ? Array<(string & {}) | MT | E['tag']> | undefined : Array<(string & {}) | E['tag']> | undefined : never;
|
|
782
|
+
};
|
|
783
|
+
//#endregion
|
|
784
|
+
export { ActionsParam, BackgroundsParam, DocsParam, ExtendMeta, ExtendStoryObj, ExtendsMeta, ExtendsStoryObj, GlobalApiBackgroundsParam, GlobalApiViewportParam, LayoutParam, ShowHtml, ShowHtmlProps, SourceProps, StorySortParam, StorybookBuiltInParams, TestParam, Viewport, ViewportParam, WithStoryCardProps, defineActionsParam, defineBackgroundsParam, defineDocsParam, defineLayoutParam, defineParameters, defineTestParam, defineViewportParam, showDocSource, whenRunningInTest, withStoryCard };
|
package/esm/index.js
CHANGED
|
@@ -37,6 +37,40 @@ function ShowHtml({ selector = "[data-testid=\"subject\"]", config, ...props })
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/components/story_card.tsx
|
|
42
|
+
function storyCardTheme(state, className) {
|
|
43
|
+
const defaultClassName = storyCardVariants(state);
|
|
44
|
+
if (!className) return defaultClassName;
|
|
45
|
+
return typeof className === "function" ? className({
|
|
46
|
+
...state,
|
|
47
|
+
defaultClassName
|
|
48
|
+
}) : twMerge(defaultClassName, className);
|
|
49
|
+
}
|
|
50
|
+
const storyCardVariants = cva("flex flex-col gap-1 py-3 px-4 rounded text-black dark:text-gray-100", {
|
|
51
|
+
variants: { status: {
|
|
52
|
+
error: "bg-red-100 dark:bg-red-900",
|
|
53
|
+
warn: "bg-yellow-100 dark:bg-yellow-900",
|
|
54
|
+
info: "bg-sky-100 dark:bg-sky-900"
|
|
55
|
+
} },
|
|
56
|
+
defaultVariants: { status: "info" }
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* A card component that displays information with optional title and status styling.
|
|
60
|
+
*
|
|
61
|
+
* @param props - StoryCard component props
|
|
62
|
+
* @returns A section element containing the card content
|
|
63
|
+
*/
|
|
64
|
+
function StoryCard({ status, className, children, title }) {
|
|
65
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
66
|
+
className: storyCardTheme({ status }, className),
|
|
67
|
+
children: [title && /* @__PURE__ */ jsx("h2", {
|
|
68
|
+
className: "text-lg font-bold",
|
|
69
|
+
children: title
|
|
70
|
+
}), children]
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
40
74
|
//#endregion
|
|
41
75
|
//#region src/decorators/show_doc_source.tsx
|
|
42
76
|
const channel = addons.getChannel();
|
|
@@ -44,7 +78,7 @@ const channel = addons.getChannel();
|
|
|
44
78
|
* A decorator that shows the source code of a story above the rendered story.
|
|
45
79
|
* The source code is taken from the story's `parameters.docs.source.code`.
|
|
46
80
|
*/
|
|
47
|
-
function showDocSource() {
|
|
81
|
+
function showDocSource(options) {
|
|
48
82
|
return (Story, { parameters: { docs, darkMode } }) => {
|
|
49
83
|
const storedItem = window.localStorage.getItem("sb-addon-themes-3");
|
|
50
84
|
const current = typeof storedItem === "string" ? JSON.parse(storedItem).current : darkMode?.current;
|
|
@@ -53,6 +87,13 @@ function showDocSource() {
|
|
|
53
87
|
channel.on("DARK_MODE", setIsDark);
|
|
54
88
|
return () => channel.off("DARK_MODE", setIsDark);
|
|
55
89
|
}, []);
|
|
90
|
+
const code = options?.showOriginalSource ? docs?.source?.originalSource : docs?.source?.code ?? docs?.source?.originalSource;
|
|
91
|
+
const language = code === docs?.source?.originalSource ? void 0 : docs?.source?.language;
|
|
92
|
+
const isOriginalSource = code === docs?.source?.originalSource;
|
|
93
|
+
const content = /* @__PURE__ */ jsx(SyntaxHighlighter, {
|
|
94
|
+
language,
|
|
95
|
+
children: code
|
|
96
|
+
});
|
|
56
97
|
return /* @__PURE__ */ jsx(ThemeProvider, {
|
|
57
98
|
theme: convert(docs?.theme ?? (isDark ? themes.dark : themes.light)),
|
|
58
99
|
children: /* @__PURE__ */ jsxs("section", {
|
|
@@ -61,10 +102,10 @@ function showDocSource() {
|
|
|
61
102
|
flexDirection: "column",
|
|
62
103
|
gap: "1rem"
|
|
63
104
|
},
|
|
64
|
-
children: [/* @__PURE__ */ jsx(
|
|
65
|
-
|
|
66
|
-
children:
|
|
67
|
-
})
|
|
105
|
+
children: [/* @__PURE__ */ jsx(Story, {}), isOriginalSource ? /* @__PURE__ */ jsx(StoryCard, {
|
|
106
|
+
className: "bg-gray-100 dark:bg-gray-900",
|
|
107
|
+
children: content
|
|
108
|
+
}) : content]
|
|
68
109
|
})
|
|
69
110
|
});
|
|
70
111
|
};
|
|
@@ -178,43 +219,27 @@ function StoryCardContainer({ children }) {
|
|
|
178
219
|
const contextValue = useMemo(() => ({
|
|
179
220
|
addCard(card) {
|
|
180
221
|
const key = generateKey("story-card");
|
|
181
|
-
setCards((cards
|
|
222
|
+
setCards((cards) => [...cards, {
|
|
182
223
|
...card,
|
|
183
224
|
key
|
|
184
225
|
}]);
|
|
185
226
|
return key;
|
|
186
227
|
},
|
|
187
228
|
removeCard(key) {
|
|
188
|
-
setCards((cards
|
|
229
|
+
setCards((cards) => cards.filter((card) => card.key !== key));
|
|
189
230
|
}
|
|
190
231
|
}), []);
|
|
191
232
|
return /* @__PURE__ */ jsx(StoryCardContext.Provider, {
|
|
192
233
|
value: contextValue,
|
|
193
234
|
children: /* @__PURE__ */ jsxs("div", {
|
|
194
235
|
className: "flex flex-col gap-2",
|
|
195
|
-
children: [cards.map(({
|
|
196
|
-
|
|
197
|
-
children:
|
|
198
|
-
className: "text-lg font-bold",
|
|
199
|
-
children: title
|
|
200
|
-
}), content]
|
|
236
|
+
children: [cards.map(({ content, key, ...rest }) => /* @__PURE__ */ jsx(StoryCard, {
|
|
237
|
+
...rest,
|
|
238
|
+
children: content
|
|
201
239
|
}, key)), children]
|
|
202
240
|
})
|
|
203
241
|
});
|
|
204
242
|
}
|
|
205
|
-
function storyCardTheme(state, className) {
|
|
206
|
-
const defaultClassName = storyCardVariants(state);
|
|
207
|
-
if (!className) return defaultClassName;
|
|
208
|
-
return typeof className === "function" ? className({
|
|
209
|
-
...state,
|
|
210
|
-
defaultClassName
|
|
211
|
-
}) : twMerge(defaultClassName, className);
|
|
212
|
-
}
|
|
213
|
-
const storyCardVariants = cva("flex flex-col gap-1 py-3 px-4 rounded text-black dark:text-gray-100", { variants: { status: {
|
|
214
|
-
error: "bg-red-100 dark:bg-red-900",
|
|
215
|
-
warn: "bg-yellow-100 dark:bg-yellow-900",
|
|
216
|
-
info: "bg-sky-100 dark:bg-sky-900"
|
|
217
|
-
} } });
|
|
218
243
|
function StoryCardCollector({ Story, title, status, className, content }) {
|
|
219
244
|
const context = useContext(StoryCardContext);
|
|
220
245
|
const cardIdRef = useRef(null);
|
|
@@ -343,7 +368,7 @@ const defineLayoutParam = (layout) => ({ layout });
|
|
|
343
368
|
* ```
|
|
344
369
|
*/
|
|
345
370
|
function defineParameters(param, ...rest) {
|
|
346
|
-
return rest.reduce((acc, param
|
|
371
|
+
return rest.reduce((acc, param) => Object.assign(acc, param), param);
|
|
347
372
|
}
|
|
348
373
|
|
|
349
374
|
//#endregion
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
import { TagBadgeParameters } from "storybook-addon-tag-badges/manager-helpers";
|
|
3
3
|
import { Args, Meta as Meta$1, StoryObj as StoryObj$1 } from "@storybook/react-vite";
|
|
4
|
+
import { IsStringLiteral } from "type-plus";
|
|
4
5
|
|
|
5
6
|
//#region src/storybook-addon-tag-badges/tag_badges.d.ts
|
|
6
7
|
type TagBadgeParameter = TagBadgeParameters[0];
|
|
7
8
|
/**
|
|
8
9
|
* Type representing the names of predefined tags used in Storybook stories.
|
|
9
10
|
*/
|
|
10
|
-
type TagNames = 'editor' | 'new' | 'beta' | 'props' | 'deprecated' | 'outdated' | 'danger' | 'todo' | 'code-only' | 'snapshot' | 'unit' | 'integration' | 'keyboard' | 'internal' | 'usecase';
|
|
11
|
+
type TagNames = 'editor' | 'new' | 'beta' | 'props' | 'deprecated' | 'outdated' | 'danger' | 'todo' | 'code-only' | 'snapshot' | 'unit' | 'integration' | 'keyboard' | 'internal' | 'usecase' | 'version:next';
|
|
11
12
|
/**
|
|
12
13
|
* Configuration for story tag badges that appear in the Storybook sidebar.
|
|
13
14
|
* Each badge is associated with a specific tag and displays an emoji with a tooltip.
|
|
@@ -44,32 +45,14 @@ declare const internalBadge: TagBadgeParameter;
|
|
|
44
45
|
declare const tagBadges: TagBadgeParameters;
|
|
45
46
|
//#endregion
|
|
46
47
|
//#region src/types.d.ts
|
|
47
|
-
/**
|
|
48
|
-
* Extends the Storybook Meta type with custom tag types
|
|
49
|
-
* @template TCmpOrArgs - The component or args type
|
|
50
|
-
* @template M - The base Meta type
|
|
51
|
-
* @template E - The extension type containing tagType
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```ts
|
|
55
|
-
* // Create a generic Meta type for a project
|
|
56
|
-
* type Meta<TCmpOrArgs = Args> = ExtendMeta<TCmpOrArgs, Meta<TCmpOrArgs>, { tagType: 'tag1' | 'tag2' }>
|
|
57
|
-
*
|
|
58
|
-
* // Create a specific Meta type for a component
|
|
59
|
-
* type Meta = ExtendMeta<typeof Component, Meta<typeof Component>, { tagType: 'tag1' | 'tag2' }>
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
type ExtendMeta<TCmpOrArgs, M extends Meta$1<TCmpOrArgs>, E extends {
|
|
63
|
-
tag: string;
|
|
64
|
-
}> = Omit<M, 'tags'> & {
|
|
65
|
-
tags?: Array<E['tag'] | (string & {})> | undefined;
|
|
66
|
-
};
|
|
67
48
|
/**
|
|
68
49
|
* Extends the Storybook StoryObj type with custom tag types
|
|
69
50
|
* @template TMetaOrCmpOrArgs - The meta, component or args type
|
|
70
51
|
* @template S - The base StoryObj type
|
|
71
52
|
* @template E - The extension type containing tagType
|
|
72
53
|
*
|
|
54
|
+
* @deprecated use `import { ExtendsStoryObj } from '@repobuddy/storybook'` instead.
|
|
55
|
+
*
|
|
73
56
|
* @example
|
|
74
57
|
* ```ts
|
|
75
58
|
* // Create a generic StoryObj type for a project
|
|
@@ -85,8 +68,47 @@ type ExtendStoryObj<TMetaOrCmpOrArgs, S extends StoryObj$1<TMetaOrCmpOrArgs>, E
|
|
|
85
68
|
tags?: Array<E['tag'] | (string & {})> | undefined;
|
|
86
69
|
};
|
|
87
70
|
//#endregion
|
|
71
|
+
//#region src/types/_extract_string_literals.d.ts
|
|
72
|
+
type ExtractStringLiterals<T> = T extends any ? (string extends T ? never : T) : never;
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/types/extends_meta.d.ts
|
|
75
|
+
/**
|
|
76
|
+
* Extends the Storybook Meta type with custom tag types.
|
|
77
|
+
*
|
|
78
|
+
* This utility type allows you to extend the `tags` property of a Storybook Meta type
|
|
79
|
+
* with custom string literal types while preserving existing tag types from the base Meta.
|
|
80
|
+
*
|
|
81
|
+
* @template M - The base Meta type to extend
|
|
82
|
+
* @template E - The extension type containing a `tag` property with the custom tag types
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import type { ExtendsMeta } from '@repobuddy/storybook'
|
|
87
|
+
* import type { Args, Meta as M } from '@storybook/your-framework'
|
|
88
|
+
*
|
|
89
|
+
* // Create a generic Meta type for your project
|
|
90
|
+
* type Meta<TCmpOrArgs = Args> = ExtendsMeta<
|
|
91
|
+
* M<TCmpOrArgs>,
|
|
92
|
+
* { tag: 'new' | 'beta' | 'deprecated' }
|
|
93
|
+
* >
|
|
94
|
+
*
|
|
95
|
+
* // Use in component stories
|
|
96
|
+
* const meta: Meta<typeof Component> = {
|
|
97
|
+
* tags: ['new'], // <--- gets auto-completion for 'new' | 'beta' | 'deprecated'
|
|
98
|
+
* // ...
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
type ExtendsMeta<M extends {
|
|
103
|
+
tags?: string[] | undefined;
|
|
104
|
+
}, E extends {
|
|
105
|
+
tag: string;
|
|
106
|
+
}> = Omit<M, 'tags'> & {
|
|
107
|
+
tags?: ExtractStringLiterals<NonNullable<M['tags']>[number]> extends infer MT ? IsStringLiteral<MT> extends true ? Array<(string & {}) | MT | E['tag']> | undefined : Array<(string & {}) | E['tag']> | undefined : never;
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
88
110
|
//#region src/storybook-addon-tag-badges/types.d.ts
|
|
89
|
-
type Meta<TCmpOrArgs = Args> =
|
|
111
|
+
type Meta<TCmpOrArgs = Args> = ExtendsMeta<Meta$1<TCmpOrArgs>, {
|
|
90
112
|
tag: TagNames;
|
|
91
113
|
}>;
|
|
92
114
|
type StoryObj<TMetaOrCmpOrArgs = Args> = ExtendStoryObj<TMetaOrCmpOrArgs, StoryObj$1<TMetaOrCmpOrArgs>, {
|
|
@@ -7,7 +7,6 @@ import { CSSProperties } from "@just-web/css";
|
|
|
7
7
|
import { DecoratorFunction } from "storybook/internal/types";
|
|
8
8
|
|
|
9
9
|
//#region src/storybook-dark-mode/dark_mode_docs_container.d.ts
|
|
10
|
-
|
|
11
10
|
/**
|
|
12
11
|
* Creates a `DocsContainer` for `storybook` that works with `@storybook-community/storybook-dark-mode`.
|
|
13
12
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@repobuddy/storybook",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Storybook repo buddy",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"!**/*.mdx"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@just-web/css": "^0.
|
|
53
|
+
"@just-web/css": "^0.8.0",
|
|
54
54
|
"@repobuddy/test": "^1.0.0",
|
|
55
55
|
"class-variance-authority": "^0.7.1",
|
|
56
56
|
"htmlfy": "^1.0.0",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"storybook": "^10.1.10",
|
|
77
77
|
"storybook-addon-tag-badges": "^3.0.2",
|
|
78
78
|
"tailwindcss": "^4.1.17",
|
|
79
|
-
"tsdown": "^0.
|
|
79
|
+
"tsdown": "^0.20.0",
|
|
80
80
|
"vite": "^7.3.0",
|
|
81
81
|
"vitest": "^4.0.16"
|
|
82
82
|
},
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority'
|
|
2
|
+
import type { ReactNode } from 'react'
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
4
|
+
|
|
5
|
+
export type StoryCardProps = {
|
|
6
|
+
/**
|
|
7
|
+
* Optional title displayed as a heading in the card.
|
|
8
|
+
* Can be any React node (string, JSX, etc.).
|
|
9
|
+
*/
|
|
10
|
+
title?: ReactNode | undefined
|
|
11
|
+
/**
|
|
12
|
+
* Visual status of the card, affecting its background color.
|
|
13
|
+
* - `'error'`: Red background (bg-red-100 dark:bg-red-900)
|
|
14
|
+
* - `'warn'`: Yellow background (bg-yellow-100 dark:bg-yellow-900)
|
|
15
|
+
* - `'info'`: Blue background (bg-sky-100 dark:bg-sky-900) - default
|
|
16
|
+
*/
|
|
17
|
+
status?: 'error' | 'warn' | 'info' | undefined
|
|
18
|
+
/**
|
|
19
|
+
* Additional CSS classes or a function to compute classes.
|
|
20
|
+
*
|
|
21
|
+
* If a string is provided, it will be merged with the default classes.
|
|
22
|
+
* If a function is provided, it receives the card state and default className,
|
|
23
|
+
* and should return the final className string.
|
|
24
|
+
*/
|
|
25
|
+
className?: ((state: Pick<StoryCardProps, 'status'> & { defaultClassName: string }) => string) | string | undefined
|
|
26
|
+
/**
|
|
27
|
+
* Content to display in the card body.
|
|
28
|
+
* Can be any React node (string, JSX, etc.).
|
|
29
|
+
*/
|
|
30
|
+
children?: ReactNode | undefined
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function storyCardTheme(state: Pick<StoryCardProps, 'status'>, className: StoryCardProps['className']) {
|
|
34
|
+
const defaultClassName = storyCardVariants(state)
|
|
35
|
+
if (!className) return defaultClassName
|
|
36
|
+
return typeof className === 'function'
|
|
37
|
+
? className({ ...state, defaultClassName })
|
|
38
|
+
: twMerge(defaultClassName, className)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const storyCardVariants = cva('flex flex-col gap-1 py-3 px-4 rounded text-black dark:text-gray-100', {
|
|
42
|
+
variants: {
|
|
43
|
+
status: {
|
|
44
|
+
error: 'bg-red-100 dark:bg-red-900',
|
|
45
|
+
warn: 'bg-yellow-100 dark:bg-yellow-900',
|
|
46
|
+
info: 'bg-sky-100 dark:bg-sky-900'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
status: 'info'
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A card component that displays information with optional title and status styling.
|
|
56
|
+
*
|
|
57
|
+
* @param props - StoryCard component props
|
|
58
|
+
* @returns A section element containing the card content
|
|
59
|
+
*/
|
|
60
|
+
export function StoryCard({ status, className, children, title }: StoryCardProps) {
|
|
61
|
+
return (
|
|
62
|
+
<section className={storyCardTheme({ status }, className)}>
|
|
63
|
+
{title && <h2 className="text-lg font-bold">{title}</h2>}
|
|
64
|
+
{children}
|
|
65
|
+
</section>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
@@ -3,6 +3,7 @@ import { SyntaxHighlighter } from 'storybook/internal/components'
|
|
|
3
3
|
import type { Args, DecoratorFunction, Renderer } from 'storybook/internal/csf'
|
|
4
4
|
import { addons } from 'storybook/preview-api'
|
|
5
5
|
import { convert, ThemeProvider, themes } from 'storybook/theming'
|
|
6
|
+
import { StoryCard } from '../components/story_card'
|
|
6
7
|
|
|
7
8
|
const channel = addons.getChannel()
|
|
8
9
|
|
|
@@ -10,10 +11,9 @@ const channel = addons.getChannel()
|
|
|
10
11
|
* A decorator that shows the source code of a story above the rendered story.
|
|
11
12
|
* The source code is taken from the story's `parameters.docs.source.code`.
|
|
12
13
|
*/
|
|
13
|
-
export function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Args>(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
> {
|
|
14
|
+
export function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Args>(options?: {
|
|
15
|
+
showOriginalSource?: boolean | undefined
|
|
16
|
+
}): DecoratorFunction<TRenderer, TArgs> {
|
|
17
17
|
return (Story, { parameters: { docs, darkMode } }) => {
|
|
18
18
|
// This is a workaround to get the current dark mode from `@storybook-community/storybook-dark-mode` without referencing it.
|
|
19
19
|
const storedItem = window.localStorage.getItem('sb-addon-themes-3')
|
|
@@ -26,6 +26,16 @@ export function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Arg
|
|
|
26
26
|
return () => channel.off('DARK_MODE', setIsDark)
|
|
27
27
|
}, [])
|
|
28
28
|
|
|
29
|
+
const code = options?.showOriginalSource
|
|
30
|
+
? docs?.source?.originalSource
|
|
31
|
+
: (docs?.source?.code ?? docs?.source?.originalSource)
|
|
32
|
+
|
|
33
|
+
const language = code === docs?.source?.originalSource ? undefined : docs?.source?.language
|
|
34
|
+
|
|
35
|
+
const isOriginalSource = code === docs?.source?.originalSource
|
|
36
|
+
|
|
37
|
+
const content = <SyntaxHighlighter language={language}>{code}</SyntaxHighlighter>
|
|
38
|
+
|
|
29
39
|
return (
|
|
30
40
|
<ThemeProvider theme={convert(docs?.theme ?? (isDark ? themes.dark : themes.light))}>
|
|
31
41
|
<section
|
|
@@ -35,8 +45,8 @@ export function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Arg
|
|
|
35
45
|
gap: '1rem'
|
|
36
46
|
}}
|
|
37
47
|
>
|
|
38
|
-
<SyntaxHighlighter language={docs?.source?.language}>{docs?.source?.code}</SyntaxHighlighter>
|
|
39
48
|
<Story />
|
|
49
|
+
{isOriginalSource ? <StoryCard className="bg-gray-100 dark:bg-gray-900">{content}</StoryCard> : content}
|
|
40
50
|
</section>
|
|
41
51
|
</ThemeProvider>
|
|
42
52
|
)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { cva } from 'class-variance-authority'
|
|
2
1
|
import {
|
|
3
2
|
createContext,
|
|
4
3
|
useContext,
|
|
@@ -10,23 +9,11 @@ import {
|
|
|
10
9
|
type ReactNode
|
|
11
10
|
} from 'react'
|
|
12
11
|
import type { DecoratorFunction, Renderer } from 'storybook/internal/csf'
|
|
13
|
-
import { twMerge } from 'tailwind-merge'
|
|
14
12
|
import type { RequiredPick } from 'type-plus'
|
|
13
|
+
import { StoryCard, type StoryCardProps } from '../components/story_card.js'
|
|
15
14
|
import { generateKey } from '../utils/generate_key.js'
|
|
16
15
|
|
|
17
|
-
export type
|
|
18
|
-
/**
|
|
19
|
-
* Optional title displayed as a heading in the card.
|
|
20
|
-
* Can be any React node (string, JSX, etc.).
|
|
21
|
-
*/
|
|
22
|
-
title?: ReactNode | undefined
|
|
23
|
-
/**
|
|
24
|
-
* Visual status of the card, affecting its background color.
|
|
25
|
-
* - `'error'`: Red background (bg-red-100 dark:bg-red-900)
|
|
26
|
-
* - `'warn'`: Yellow background (bg-yellow-100 dark:bg-yellow-900)
|
|
27
|
-
* - `'info'`: Blue background (bg-sky-100 dark:bg-sky-900) - default
|
|
28
|
-
*/
|
|
29
|
-
status?: 'error' | 'warn' | 'info' | undefined
|
|
16
|
+
export type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'> & {
|
|
30
17
|
/**
|
|
31
18
|
* Additional CSS classes or a function to compute classes.
|
|
32
19
|
*
|
|
@@ -34,10 +21,7 @@ export type StoryCardProps = {
|
|
|
34
21
|
* If a function is provided, it receives the card state and default className,
|
|
35
22
|
* and should return the final className string.
|
|
36
23
|
*/
|
|
37
|
-
className?:
|
|
38
|
-
| ((state: Required<Pick<StoryCardProps, 'status'>> & { defaultClassName: string }) => string)
|
|
39
|
-
| string
|
|
40
|
-
| undefined
|
|
24
|
+
className?: ((state: Pick<StoryCardProps, 'status'> & { defaultClassName: string }) => string) | string | undefined
|
|
41
25
|
/**
|
|
42
26
|
* Content to display in the card body.
|
|
43
27
|
* Can be any React node (string, JSX, etc.).
|
|
@@ -120,7 +104,7 @@ export function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
|
120
104
|
status = 'info',
|
|
121
105
|
content: contentProp,
|
|
122
106
|
...rest
|
|
123
|
-
}:
|
|
107
|
+
}: WithStoryCardProps = {}): DecoratorFunction<TRenderer> {
|
|
124
108
|
return (Story, { parameters, viewMode }) => {
|
|
125
109
|
if (viewMode === 'docs') return <Story />
|
|
126
110
|
|
|
@@ -131,7 +115,7 @@ export function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
|
131
115
|
}
|
|
132
116
|
}
|
|
133
117
|
|
|
134
|
-
interface StoryCardContainerWrapperProps extends RequiredPick<
|
|
118
|
+
interface StoryCardContainerWrapperProps extends RequiredPick<WithStoryCardProps, 'status'> {
|
|
135
119
|
Story: ComponentType
|
|
136
120
|
}
|
|
137
121
|
|
|
@@ -166,11 +150,10 @@ function StoryCardContainer({ children }: { children: ReactNode }) {
|
|
|
166
150
|
return (
|
|
167
151
|
<StoryCardContext.Provider value={contextValue}>
|
|
168
152
|
<div className="flex flex-col gap-2">
|
|
169
|
-
{cards.map(({
|
|
170
|
-
<
|
|
171
|
-
{title && <h2 className="text-lg font-bold">{title}</h2>}
|
|
153
|
+
{cards.map(({ content, key, ...rest }) => (
|
|
154
|
+
<StoryCard key={key} {...rest}>
|
|
172
155
|
{content}
|
|
173
|
-
</
|
|
156
|
+
</StoryCard>
|
|
174
157
|
))}
|
|
175
158
|
{children}
|
|
176
159
|
</div>
|
|
@@ -178,27 +161,9 @@ function StoryCardContainer({ children }: { children: ReactNode }) {
|
|
|
178
161
|
)
|
|
179
162
|
}
|
|
180
163
|
|
|
181
|
-
type StoryCardWithKey = RequiredPick<
|
|
182
|
-
|
|
183
|
-
function storyCardTheme(state: Required<Pick<StoryCardProps, 'status'>>, className: StoryCardProps['className']) {
|
|
184
|
-
const defaultClassName = storyCardVariants(state)
|
|
185
|
-
if (!className) return defaultClassName
|
|
186
|
-
return typeof className === 'function'
|
|
187
|
-
? className({ ...state, defaultClassName })
|
|
188
|
-
: twMerge(defaultClassName, className)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const storyCardVariants = cva('flex flex-col gap-1 py-3 px-4 rounded text-black dark:text-gray-100', {
|
|
192
|
-
variants: {
|
|
193
|
-
status: {
|
|
194
|
-
error: 'bg-red-100 dark:bg-red-900',
|
|
195
|
-
warn: 'bg-yellow-100 dark:bg-yellow-900',
|
|
196
|
-
info: 'bg-sky-100 dark:bg-sky-900'
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
})
|
|
164
|
+
type StoryCardWithKey = RequiredPick<WithStoryCardProps, 'status'> & { key: string }
|
|
200
165
|
|
|
201
|
-
interface StoryCardCollectorProps extends RequiredPick<
|
|
166
|
+
interface StoryCardCollectorProps extends RequiredPick<WithStoryCardProps, 'status'> {
|
|
202
167
|
Story: ComponentType
|
|
203
168
|
}
|
|
204
169
|
|
|
@@ -226,7 +191,7 @@ function StoryCardCollector({ Story, title, status, className, content }: StoryC
|
|
|
226
191
|
}
|
|
227
192
|
|
|
228
193
|
interface StoryCardContextValue {
|
|
229
|
-
addCard: (card: RequiredPick<
|
|
194
|
+
addCard: (card: RequiredPick<WithStoryCardProps, 'status'>) => string
|
|
230
195
|
removeCard: (id: string) => void
|
|
231
196
|
}
|
|
232
197
|
|
package/src/index.ts
CHANGED
|
@@ -12,3 +12,5 @@ export * from './parameters/define_viewport_param.ts'
|
|
|
12
12
|
export * from './parameters/story_sort.ts'
|
|
13
13
|
export * from './testing/decorators/when_running_in_test.tsx'
|
|
14
14
|
export type * from './types.ts'
|
|
15
|
+
export * from './types/extends_meta.ts'
|
|
16
|
+
export * from './types/extends_story_obj.ts'
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Args, Meta as M, StoryObj as SBO } from '@storybook/react-vite'
|
|
2
|
-
import type {
|
|
2
|
+
import type { ExtendStoryObj } from '../types.js'
|
|
3
|
+
import type { ExtendsMeta } from '../types/extends_meta.js'
|
|
3
4
|
import type { TagNames } from './tag_badges.js'
|
|
4
5
|
|
|
5
|
-
export type Meta<TCmpOrArgs = Args> =
|
|
6
|
+
export type Meta<TCmpOrArgs = Args> = ExtendsMeta<M<TCmpOrArgs>, { tag: TagNames }>
|
|
6
7
|
|
|
7
8
|
export type StoryObj<TMetaOrCmpOrArgs = Args> = ExtendStoryObj<
|
|
8
9
|
TMetaOrCmpOrArgs,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ExtractStringLiterals<T> = T extends any ? (string extends T ? never : T) : never
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IsStringLiteral } from 'type-plus'
|
|
2
|
+
import type { ExtractStringLiterals } from './_extract_string_literals.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Extends the Storybook Meta type with custom tag types.
|
|
6
|
+
*
|
|
7
|
+
* This utility type allows you to extend the `tags` property of a Storybook Meta type
|
|
8
|
+
* with custom string literal types while preserving existing tag types from the base Meta.
|
|
9
|
+
*
|
|
10
|
+
* @template M - The base Meta type to extend
|
|
11
|
+
* @template E - The extension type containing a `tag` property with the custom tag types
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import type { ExtendsMeta } from '@repobuddy/storybook'
|
|
16
|
+
* import type { Args, Meta as M } from '@storybook/your-framework'
|
|
17
|
+
*
|
|
18
|
+
* // Create a generic Meta type for your project
|
|
19
|
+
* type Meta<TCmpOrArgs = Args> = ExtendsMeta<
|
|
20
|
+
* M<TCmpOrArgs>,
|
|
21
|
+
* { tag: 'new' | 'beta' | 'deprecated' }
|
|
22
|
+
* >
|
|
23
|
+
*
|
|
24
|
+
* // Use in component stories
|
|
25
|
+
* const meta: Meta<typeof Component> = {
|
|
26
|
+
* tags: ['new'], // <--- gets auto-completion for 'new' | 'beta' | 'deprecated'
|
|
27
|
+
* // ...
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export type ExtendsMeta<M extends { tags?: string[] | undefined }, E extends { tag: string }> = Omit<M, 'tags'> & {
|
|
32
|
+
tags?: ExtractStringLiterals<NonNullable<M['tags']>[number]> extends infer MT
|
|
33
|
+
? IsStringLiteral<MT> extends true
|
|
34
|
+
? Array<(string & {}) | MT | E['tag']> | undefined
|
|
35
|
+
: Array<(string & {}) | E['tag']> | undefined
|
|
36
|
+
: never
|
|
37
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { IsStringLiteral } from 'type-plus'
|
|
2
|
+
import type { ExtractStringLiterals } from './_extract_string_literals.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Extends the Storybook StoryObj type with custom tag types.
|
|
6
|
+
*
|
|
7
|
+
* This utility type allows you to extend the `tags` property of a Storybook StoryObj type
|
|
8
|
+
* with custom string literal types while preserving existing tag types from the base StoryObj.
|
|
9
|
+
*
|
|
10
|
+
* @template S - The base StoryObj type to extend (must have an optional `tags` property)
|
|
11
|
+
* @template E - The extension type containing a `tag` property with the custom tag types
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import type { ExtendsStoryObj } from '@repobuddy/storybook'
|
|
16
|
+
* import type { Args, StoryObj as S } from '@storybook/your-framework'
|
|
17
|
+
*
|
|
18
|
+
* // Create a generic StoryObj type for your project
|
|
19
|
+
* type StoryObj<TCmpOrArgs = Args> = ExtendsStoryObj<
|
|
20
|
+
* S<TCmpOrArgs>,
|
|
21
|
+
* { tag: 'new' | 'beta' | 'deprecated' }
|
|
22
|
+
* >
|
|
23
|
+
*
|
|
24
|
+
* // Use in component stories
|
|
25
|
+
* const story: StoryObj<typeof Component> = {
|
|
26
|
+
* tags: ['new'], // <--- gets auto-completion for 'new' | 'beta' | 'deprecated'
|
|
27
|
+
* // ...
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export type ExtendsStoryObj<
|
|
32
|
+
S extends { tags?: string[] | undefined },
|
|
33
|
+
E extends {
|
|
34
|
+
tag: string
|
|
35
|
+
}
|
|
36
|
+
> = Omit<S, 'tags'> & {
|
|
37
|
+
tags?: ExtractStringLiterals<NonNullable<S['tags']>[number]> extends infer MT
|
|
38
|
+
? IsStringLiteral<MT> extends true
|
|
39
|
+
? Array<(string & {}) | MT | E['tag']> | undefined
|
|
40
|
+
: Array<(string & {}) | E['tag']> | undefined
|
|
41
|
+
: never
|
|
42
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -6,6 +6,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
|
6
6
|
* @template M - The base Meta type
|
|
7
7
|
* @template E - The extension type containing tagType
|
|
8
8
|
*
|
|
9
|
+
* @deprecated use `import { ExtendsMeta } from '@repobuddy/storybook'` instead.
|
|
10
|
+
*
|
|
9
11
|
* @example
|
|
10
12
|
* ```ts
|
|
11
13
|
* // Create a generic Meta type for a project
|
|
@@ -31,6 +33,8 @@ export type ExtendMeta<
|
|
|
31
33
|
* @template S - The base StoryObj type
|
|
32
34
|
* @template E - The extension type containing tagType
|
|
33
35
|
*
|
|
36
|
+
* @deprecated use `import { ExtendsStoryObj } from '@repobuddy/storybook'` instead.
|
|
37
|
+
*
|
|
34
38
|
* @example
|
|
35
39
|
* ```ts
|
|
36
40
|
* // Create a generic StoryObj type for a project
|
package/styles.css
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
--color-rose-900: oklch(41% 0.159 10.272);
|
|
21
21
|
--color-gray-100: oklch(96.7% 0.003 264.542);
|
|
22
22
|
--color-gray-500: oklch(55.1% 0.027 264.364);
|
|
23
|
+
--color-gray-900: oklch(21% 0.034 264.665);
|
|
23
24
|
--color-black: #000;
|
|
24
25
|
--color-white: #fff;
|
|
25
26
|
--spacing: 0.25rem;
|
|
@@ -179,6 +180,11 @@
|
|
|
179
180
|
background-color: var(--color-gray-500);
|
|
180
181
|
}
|
|
181
182
|
}
|
|
183
|
+
.dark\:bg-gray-900 {
|
|
184
|
+
&:where(.dark, .dark *) {
|
|
185
|
+
background-color: var(--color-gray-900);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
182
188
|
.dark\:bg-green-800 {
|
|
183
189
|
&:where(.dark, .dark *) {
|
|
184
190
|
background-color: var(--color-green-800);
|