@repobuddy/storybook 2.2.1 → 2.2.2
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 +3 -3
- package/esm/index.js +18 -20
- package/package.json +8 -7
- package/src/decorators/with_story_card.tsx +22 -25
package/esm/index.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { ReactNode } from "react";
|
|
|
4
4
|
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
|
-
import { ClassValue } from "class-variance-authority/types";
|
|
8
7
|
import { Decorator, Meta, StoryContext, StoryObj, StrictArgs } from "@storybook/react-vite";
|
|
9
8
|
export * from "@repobuddy/test";
|
|
10
9
|
|
|
@@ -56,9 +55,9 @@ type StoryCardProps = {
|
|
|
56
55
|
* If a function is provided, it receives the card state and default className,
|
|
57
56
|
* and should return the final className string.
|
|
58
57
|
*/
|
|
59
|
-
className?: ((state: Pick<StoryCardProps, 'status'
|
|
58
|
+
className?: ((state: Required<Pick<StoryCardProps, 'status'>> & {
|
|
60
59
|
defaultClassName: string;
|
|
61
|
-
}) => string) |
|
|
60
|
+
}) => string) | string | undefined;
|
|
62
61
|
/**
|
|
63
62
|
* Content to display in the card body.
|
|
64
63
|
* Can be any React node (string, JSX, etc.).
|
|
@@ -137,6 +136,7 @@ type StoryCardProps = {
|
|
|
137
136
|
*/
|
|
138
137
|
declare function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
139
138
|
title,
|
|
139
|
+
status,
|
|
140
140
|
content: contentProp,
|
|
141
141
|
...rest
|
|
142
142
|
}?: StoryCardProps): DecoratorFunction<TRenderer>;
|
package/esm/index.js
CHANGED
|
@@ -150,7 +150,7 @@ function generateKey(prefix) {
|
|
|
150
150
|
* or fall back to the component description.
|
|
151
151
|
* - Cards are collected and displayed in the order they are defined in the decorators array.
|
|
152
152
|
*/
|
|
153
|
-
function withStoryCard({ title, content: contentProp, ...rest } = {}) {
|
|
153
|
+
function withStoryCard({ title, status = "info", content: contentProp, ...rest } = {}) {
|
|
154
154
|
return (Story, { parameters, viewMode }) => {
|
|
155
155
|
if (viewMode === "docs") return /* @__PURE__ */ jsx(Story, {});
|
|
156
156
|
const content = contentProp ?? parameters.docs?.description?.story ?? parameters.docs?.description?.component;
|
|
@@ -159,6 +159,7 @@ function withStoryCard({ title, content: contentProp, ...rest } = {}) {
|
|
|
159
159
|
Story,
|
|
160
160
|
content,
|
|
161
161
|
title,
|
|
162
|
+
status,
|
|
162
163
|
...rest
|
|
163
164
|
});
|
|
164
165
|
};
|
|
@@ -176,47 +177,44 @@ function StoryCardContainer({ children }) {
|
|
|
176
177
|
const [cards, setCards] = useState([]);
|
|
177
178
|
const contextValue = useMemo(() => ({
|
|
178
179
|
addCard(card) {
|
|
179
|
-
const
|
|
180
|
+
const key = generateKey("story-card");
|
|
180
181
|
setCards((cards$1) => [...cards$1, {
|
|
181
182
|
...card,
|
|
182
|
-
|
|
183
|
+
key
|
|
183
184
|
}]);
|
|
184
|
-
return
|
|
185
|
+
return key;
|
|
185
186
|
},
|
|
186
|
-
removeCard(
|
|
187
|
-
setCards((cards$1) => cards$1.filter((card) => card.
|
|
187
|
+
removeCard(key) {
|
|
188
|
+
setCards((cards$1) => cards$1.filter((card) => card.key !== key));
|
|
188
189
|
}
|
|
189
190
|
}), []);
|
|
190
191
|
return /* @__PURE__ */ jsx(StoryCardContext.Provider, {
|
|
191
192
|
value: contextValue,
|
|
192
193
|
children: /* @__PURE__ */ jsxs("div", {
|
|
193
194
|
className: "flex flex-col gap-2",
|
|
194
|
-
children: [cards.map(({
|
|
195
|
+
children: [cards.map(({ key, status, className, content, title }) => /* @__PURE__ */ jsxs("section", {
|
|
195
196
|
className: storyCardTheme({ status }, className),
|
|
196
197
|
children: [title && /* @__PURE__ */ jsx("h2", {
|
|
197
198
|
className: "text-lg font-bold",
|
|
198
199
|
children: title
|
|
199
200
|
}), content]
|
|
200
|
-
},
|
|
201
|
+
}, key)), children]
|
|
201
202
|
})
|
|
202
203
|
});
|
|
203
204
|
}
|
|
204
|
-
|
|
205
|
+
function storyCardTheme(state, className) {
|
|
205
206
|
const defaultClassName = storyCardVariants(state);
|
|
206
207
|
if (!className) return defaultClassName;
|
|
207
|
-
return
|
|
208
|
+
return typeof className === "function" ? className({
|
|
208
209
|
...state,
|
|
209
210
|
defaultClassName
|
|
210
|
-
}) : className);
|
|
211
|
-
}
|
|
212
|
-
const storyCardVariants = cva("flex flex-col gap-1 py-3 px-4 rounded text-black dark:text-gray-100", {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} },
|
|
218
|
-
defaultVariants: { status: "info" }
|
|
219
|
-
});
|
|
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
|
+
} } });
|
|
220
218
|
function StoryCardCollector({ Story, title, status, className, content }) {
|
|
221
219
|
const context = useContext(StoryCardContext);
|
|
222
220
|
const cardIdRef = useRef(null);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@repobuddy/storybook",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "Storybook repo buddy",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook",
|
|
@@ -54,14 +54,15 @@
|
|
|
54
54
|
"@repobuddy/test": "^1.0.0",
|
|
55
55
|
"class-variance-authority": "^0.7.1",
|
|
56
56
|
"htmlfy": "^1.0.0",
|
|
57
|
-
"tailwind-merge": "^3.4.0"
|
|
57
|
+
"tailwind-merge": "^3.4.0",
|
|
58
|
+
"type-plus": "8.0.0-beta.7"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"@repobuddy/vitest": "^2.0.0",
|
|
61
62
|
"@storybook-community/storybook-dark-mode": "^7.0.2",
|
|
62
|
-
"@storybook/addon-docs": "^10.
|
|
63
|
-
"@storybook/addon-vitest": "^10.
|
|
64
|
-
"@storybook/react-vite": "^10.
|
|
63
|
+
"@storybook/addon-docs": "^10.1.10",
|
|
64
|
+
"@storybook/addon-vitest": "^10.1.10",
|
|
65
|
+
"@storybook/react-vite": "^10.1.10",
|
|
65
66
|
"@tailwindcss/cli": "^4.1.17",
|
|
66
67
|
"@tailwindcss/vite": "^4.1.17",
|
|
67
68
|
"@vitest/browser": "^4.0.16",
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
"react": "^19.2.0",
|
|
73
74
|
"react-dom": "^19.2.0",
|
|
74
75
|
"rimraf": "^6.1.0",
|
|
75
|
-
"storybook": "^10.
|
|
76
|
+
"storybook": "^10.1.10",
|
|
76
77
|
"storybook-addon-tag-badges": "^3.0.2",
|
|
77
78
|
"tailwindcss": "^4.1.17",
|
|
78
79
|
"tsdown": "^0.18.0",
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
},
|
|
82
83
|
"peerDependencies": {
|
|
83
84
|
"@storybook-community/storybook-dark-mode": "^7.0.0",
|
|
84
|
-
"@storybook/addon-docs": "^10.
|
|
85
|
+
"@storybook/addon-docs": "^10.1.10",
|
|
85
86
|
"storybook-addon-tag-badges": "^3.0.2"
|
|
86
87
|
},
|
|
87
88
|
"peerDependenciesMeta": {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { cva } from 'class-variance-authority'
|
|
2
|
-
import type { ClassValue } from 'class-variance-authority/types'
|
|
3
2
|
import {
|
|
4
3
|
createContext,
|
|
5
4
|
useContext,
|
|
@@ -12,7 +11,8 @@ import {
|
|
|
12
11
|
} from 'react'
|
|
13
12
|
import type { DecoratorFunction, Renderer } from 'storybook/internal/csf'
|
|
14
13
|
import { twMerge } from 'tailwind-merge'
|
|
15
|
-
import {
|
|
14
|
+
import type { RequiredPick } from 'type-plus'
|
|
15
|
+
import { generateKey } from '../utils/generate_key.js'
|
|
16
16
|
|
|
17
17
|
export type StoryCardProps = {
|
|
18
18
|
/**
|
|
@@ -35,8 +35,8 @@ export type StoryCardProps = {
|
|
|
35
35
|
* and should return the final className string.
|
|
36
36
|
*/
|
|
37
37
|
className?:
|
|
38
|
-
| ((state: Pick<StoryCardProps, 'status'
|
|
39
|
-
|
|
|
38
|
+
| ((state: Required<Pick<StoryCardProps, 'status'>> & { defaultClassName: string }) => string)
|
|
39
|
+
| string
|
|
40
40
|
| undefined
|
|
41
41
|
/**
|
|
42
42
|
* Content to display in the card body.
|
|
@@ -117,6 +117,7 @@ export type StoryCardProps = {
|
|
|
117
117
|
*/
|
|
118
118
|
export function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
119
119
|
title,
|
|
120
|
+
status = 'info',
|
|
120
121
|
content: contentProp,
|
|
121
122
|
...rest
|
|
122
123
|
}: StoryCardProps = {}): DecoratorFunction<TRenderer> {
|
|
@@ -126,11 +127,11 @@ export function withStoryCard<TRenderer extends Renderer = Renderer>({
|
|
|
126
127
|
const content = contentProp ?? parameters.docs?.description?.story ?? parameters.docs?.description?.component
|
|
127
128
|
if (!content && !title) return <Story />
|
|
128
129
|
|
|
129
|
-
return <StoryCardContainerWrapper Story={Story} content={content} title={title} {...rest} />
|
|
130
|
+
return <StoryCardContainerWrapper Story={Story} content={content} title={title} status={status} {...rest} />
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
|
|
133
|
-
interface StoryCardContainerWrapperProps extends StoryCardProps {
|
|
134
|
+
interface StoryCardContainerWrapperProps extends RequiredPick<StoryCardProps, 'status'> {
|
|
134
135
|
Story: ComponentType
|
|
135
136
|
}
|
|
136
137
|
|
|
@@ -146,17 +147,17 @@ function StoryCardContainerWrapper({ Story, ...props }: StoryCardContainerWrappe
|
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
function StoryCardContainer({ children }: { children: ReactNode }) {
|
|
149
|
-
const [cards, setCards] = useState<
|
|
150
|
+
const [cards, setCards] = useState<StoryCardWithKey[]>([])
|
|
150
151
|
|
|
151
152
|
const contextValue: StoryCardContextValue = useMemo(
|
|
152
153
|
() => ({
|
|
153
154
|
addCard(card) {
|
|
154
|
-
const
|
|
155
|
-
setCards((cards) => [...cards, { ...card,
|
|
156
|
-
return
|
|
155
|
+
const key = generateKey('story-card')
|
|
156
|
+
setCards((cards) => [...cards, { ...card, key }])
|
|
157
|
+
return key
|
|
157
158
|
},
|
|
158
|
-
removeCard(
|
|
159
|
-
setCards((cards) => cards.filter((card) => card.
|
|
159
|
+
removeCard(key) {
|
|
160
|
+
setCards((cards) => cards.filter((card) => card.key !== key))
|
|
160
161
|
}
|
|
161
162
|
}),
|
|
162
163
|
[]
|
|
@@ -165,8 +166,8 @@ function StoryCardContainer({ children }: { children: ReactNode }) {
|
|
|
165
166
|
return (
|
|
166
167
|
<StoryCardContext.Provider value={contextValue}>
|
|
167
168
|
<div className="flex flex-col gap-2">
|
|
168
|
-
{cards.map(({
|
|
169
|
-
<section key={
|
|
169
|
+
{cards.map(({ key, status, className, content, title }) => (
|
|
170
|
+
<section key={key} className={storyCardTheme({ status }, className)}>
|
|
170
171
|
{title && <h2 className="text-lg font-bold">{title}</h2>}
|
|
171
172
|
{content}
|
|
172
173
|
</section>
|
|
@@ -177,15 +178,14 @@ function StoryCardContainer({ children }: { children: ReactNode }) {
|
|
|
177
178
|
)
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
type
|
|
181
|
+
type StoryCardWithKey = RequiredPick<StoryCardProps, 'status'> & { key: string }
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
function storyCardTheme(state: Required<Pick<StoryCardProps, 'status'>>, className: StoryCardProps['className']) {
|
|
183
184
|
const defaultClassName = storyCardVariants(state)
|
|
184
185
|
if (!className) return defaultClassName
|
|
185
|
-
return
|
|
186
|
-
defaultClassName
|
|
187
|
-
|
|
188
|
-
)
|
|
186
|
+
return typeof className === 'function'
|
|
187
|
+
? className({ ...state, defaultClassName })
|
|
188
|
+
: twMerge(defaultClassName, className)
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
const storyCardVariants = cva('flex flex-col gap-1 py-3 px-4 rounded text-black dark:text-gray-100', {
|
|
@@ -195,13 +195,10 @@ const storyCardVariants = cva('flex flex-col gap-1 py-3 px-4 rounded text-black
|
|
|
195
195
|
warn: 'bg-yellow-100 dark:bg-yellow-900',
|
|
196
196
|
info: 'bg-sky-100 dark:bg-sky-900'
|
|
197
197
|
}
|
|
198
|
-
},
|
|
199
|
-
defaultVariants: {
|
|
200
|
-
status: 'info'
|
|
201
198
|
}
|
|
202
199
|
})
|
|
203
200
|
|
|
204
|
-
interface StoryCardCollectorProps extends StoryCardProps {
|
|
201
|
+
interface StoryCardCollectorProps extends RequiredPick<StoryCardProps, 'status'> {
|
|
205
202
|
Story: ComponentType
|
|
206
203
|
}
|
|
207
204
|
|
|
@@ -229,7 +226,7 @@ function StoryCardCollector({ Story, title, status, className, content }: StoryC
|
|
|
229
226
|
}
|
|
230
227
|
|
|
231
228
|
interface StoryCardContextValue {
|
|
232
|
-
addCard: (card: StoryCardProps) => string
|
|
229
|
+
addCard: (card: RequiredPick<StoryCardProps, 'status'>) => string
|
|
233
230
|
removeCard: (id: string) => void
|
|
234
231
|
}
|
|
235
232
|
|