@repobuddy/storybook 2.3.0 → 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 +26 -5
- package/esm/index.js +52 -27
- package/esm/storybook-addon-tag-badges/index.d.ts +1 -1
- 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/storybook-addon-tag-badges/tag_badges.ts +1 -0
- package/styles.css +6 -0
package/esm/index.d.ts
CHANGED
|
@@ -33,9 +33,11 @@ declare function ShowHtml({
|
|
|
33
33
|
* A decorator that shows the source code of a story above the rendered story.
|
|
34
34
|
* The source code is taken from the story's `parameters.docs.source.code`.
|
|
35
35
|
*/
|
|
36
|
-
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>;
|
|
37
39
|
//#endregion
|
|
38
|
-
//#region src/
|
|
40
|
+
//#region src/components/story_card.d.ts
|
|
39
41
|
type StoryCardProps = {
|
|
40
42
|
/**
|
|
41
43
|
* Optional title displayed as a heading in the card.
|
|
@@ -56,7 +58,26 @@ type StoryCardProps = {
|
|
|
56
58
|
* If a function is provided, it receives the card state and default className,
|
|
57
59
|
* and should return the final className string.
|
|
58
60
|
*/
|
|
59
|
-
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'> & {
|
|
60
81
|
defaultClassName: string;
|
|
61
82
|
}) => string) | string | undefined;
|
|
62
83
|
/**
|
|
@@ -140,7 +161,7 @@ declare function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
|
140
161
|
status,
|
|
141
162
|
content: contentProp,
|
|
142
163
|
...rest
|
|
143
|
-
}?:
|
|
164
|
+
}?: WithStoryCardProps): DecoratorFunction<TRenderer>;
|
|
144
165
|
//#endregion
|
|
145
166
|
//#region src/parameters/define_actions_param.d.ts
|
|
146
167
|
interface ActionsParam {
|
|
@@ -760,4 +781,4 @@ type ExtendsStoryObj<S extends {
|
|
|
760
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;
|
|
761
782
|
};
|
|
762
783
|
//#endregion
|
|
763
|
-
export { ActionsParam, BackgroundsParam, DocsParam, ExtendMeta, ExtendStoryObj, ExtendsMeta, ExtendsStoryObj, GlobalApiBackgroundsParam, GlobalApiViewportParam, LayoutParam, ShowHtml, ShowHtmlProps, SourceProps,
|
|
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
|
|
@@ -8,7 +8,7 @@ type TagBadgeParameter = TagBadgeParameters[0];
|
|
|
8
8
|
/**
|
|
9
9
|
* Type representing the names of predefined tags used in Storybook stories.
|
|
10
10
|
*/
|
|
11
|
-
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';
|
|
12
12
|
/**
|
|
13
13
|
* Configuration for story tag badges that appear in the Storybook sidebar.
|
|
14
14
|
* Each badge is associated with a specific tag and displays an emoji with a tooltip.
|
|
@@ -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/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);
|