@repobuddy/storybook 2.12.0 → 2.14.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 CHANGED
@@ -42,10 +42,12 @@ declare function ShowHtml({
42
42
  //#endregion
43
43
  //#region src/components/story_card.d.ts
44
44
  /**
45
- * Visual status of the card, affecting its background color.
46
- * - `'error'`: Red background (rbsb:bg-red-100 rbsb:dark:bg-red-900)
47
- * - `'warn'`: Yellow background (rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900)
48
- * - `'info'`: Blue background (rbsb:bg-sky-100 rbsb:dark:bg-sky-900) - default
45
+ * Resolved appearance of the card (error | warn | info | source | output).
46
+ * Used for styling; when only `status` is provided it is mapped to this.
47
+ */
48
+ type StoryCardAppearance = 'error' | 'warn' | 'info' | 'source' | 'output';
49
+ /**
50
+ * @deprecated Use `appearance` instead. Visual status of the card; equivalent to `appearance` for 'error' | 'warn' | 'info'.
49
51
  */
50
52
  type StoryCardStatus = 'error' | 'warn' | 'info' | undefined;
51
53
  type StoryCardProps = {
@@ -55,12 +57,18 @@ type StoryCardProps = {
55
57
  */
56
58
  title?: ReactNode | undefined;
57
59
  /**
58
- * Visual status of the card, affecting its background color.
59
- * - `'error'`: Red background (rbsb:bg-red-100 rbsb:dark:bg-red-900)
60
- * - `'warn'`: Yellow background (rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900)
61
- * - `'info'`: Blue background (rbsb:bg-sky-100 rbsb:dark:bg-sky-900) - default
60
+ * @deprecated Use `appearance` instead. When set, behaves like `appearance` for the same value.
62
61
  */
63
62
  status?: StoryCardStatus;
63
+ /**
64
+ * Appearance of the card, affecting its background and border color.
65
+ * - `'error'`: Red
66
+ * - `'warn'`: Yellow
67
+ * - `'info'`: Blue (default when neither appearance nor status is set)
68
+ * - `'source'`: Transparent
69
+ * - `'output'`: Green
70
+ */
71
+ appearance?: StoryCardAppearance | undefined;
64
72
  /**
65
73
  * Additional CSS classes or a function to compute classes.
66
74
  *
@@ -68,7 +76,7 @@ type StoryCardProps = {
68
76
  * If a function is provided, it receives the card state and default className,
69
77
  * and should return the final className string.
70
78
  */
71
- className?: ((state: Pick<StoryCardProps, 'status'> & {
79
+ className?: ((state: Pick<StoryCardProps, 'status' | 'appearance'> & {
72
80
  defaultClassName: string;
73
81
  }) => string) | string | undefined;
74
82
  /**
@@ -77,14 +85,18 @@ type StoryCardProps = {
77
85
  */
78
86
  children?: ReactNode | undefined;
79
87
  };
88
+ type StoryCardThemeState = Pick<StoryCardProps, 'status' | 'appearance'> & {
89
+ defaultClassName: string;
90
+ };
80
91
  /**
81
- * A card component that displays information with optional title and status styling.
92
+ * A card component that displays information with optional title and appearance styling.
82
93
  *
83
94
  * @param props - StoryCard component props
84
95
  * @returns A section element containing the card content
85
96
  */
86
97
  declare function StoryCard({
87
98
  status,
99
+ appearance,
88
100
  className,
89
101
  children,
90
102
  title
@@ -115,6 +127,10 @@ declare function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Ar
115
127
  //#endregion
116
128
  //#region src/decorators/with_story_card.d.ts
117
129
  type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'> & {
130
+ /**
131
+ * @deprecated Use `appearance` instead. When set, behaves like `appearance` for the same value.
132
+ */
133
+ status?: StoryCardStatus;
118
134
  /**
119
135
  * Additional CSS classes or a function to compute classes.
120
136
  *
@@ -122,7 +138,7 @@ type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'> & {
122
138
  * If a function is provided, it receives the card state and default className,
123
139
  * and should return the final className string.
124
140
  */
125
- className?: ((state: Pick<StoryCardProps, 'status'> & {
141
+ className?: ((state: Pick<StoryCardProps, 'status' | 'appearance'> & {
126
142
  defaultClassName: string;
127
143
  }) => string) | string | undefined;
128
144
  /**
@@ -213,10 +229,12 @@ type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'> & {
213
229
  * - If `content` is not provided, it will automatically use the story description,
214
230
  * or fall back to the component description.
215
231
  * - Cards are collected and displayed in the order they are defined in the decorators array.
232
+ * - The `status` option is deprecated; use `appearance` instead for the same behavior and additional variants (`source`, `output`).
216
233
  */
217
234
  declare function withStoryCard<TRenderer extends Renderer = Renderer>({
218
235
  title,
219
236
  status,
237
+ appearance,
220
238
  content: contentProp,
221
239
  className,
222
240
  ...rest
@@ -722,12 +740,13 @@ interface StoryCardParam {
722
740
  */
723
741
  title?: ReactNode | undefined;
724
742
  /**
725
- * Visual status of the card, affecting its background color.
726
- * - `'error'`: Red background
727
- * - `'warn'`: Yellow background
728
- * - `'info'`: Blue background - default
743
+ * @deprecated Use `appearance` instead.
729
744
  */
730
745
  status?: StoryCardStatus;
746
+ /**
747
+ * Appearance of the card (error | warn | info | source | output). Default: `'info'`.
748
+ */
749
+ appearance?: StoryCardAppearance | undefined;
731
750
  /**
732
751
  * Additional CSS classes or a function to compute classes.
733
752
  *
@@ -735,7 +754,7 @@ interface StoryCardParam {
735
754
  * If a function is provided, it receives the card state and default className,
736
755
  * and should return the final className string.
737
756
  */
738
- className?: ((state: Pick<StoryCardProps, 'status'> & {
757
+ className?: ((state: Pick<StoryCardProps, 'status' | 'appearance'> & {
739
758
  defaultClassName: string;
740
759
  }) => string) | string | undefined;
741
760
  /**
@@ -921,4 +940,4 @@ type ExtendStoryObj<TMetaOrCmpOrArgs, S extends StoryObj<TMetaOrCmpOrArgs>, E ex
921
940
  tags?: Array<E['tag'] | (string & {})> | undefined;
922
941
  };
923
942
  //#endregion
924
- export { ActionsParam, BackgroundsParam, DocsParam, ExtendMeta, ExtendStoryObj, ExtendsMeta, ExtendsStoryObj, FnToArgTypes, GlobalApiBackgroundsParam, GlobalApiViewportParam, LayoutParam, ShowHtml, ShowHtmlProps, SourceProps, StoryCard, StoryCardParam, StoryCardProps, StoryCardStatus, StorySortParam, StorybookBuiltInParams, TestParam, Viewport, ViewportParam, WithStoryCardProps, defineActionsParam, defineBackgroundsParam, defineDocsParam, defineLayoutParam, defineParameters, defineStoryCardParam, defineTestParam, defineViewportParam, showDocSource, whenRunningInTest, withStoryCard };
943
+ export { ActionsParam, BackgroundsParam, DocsParam, ExtendMeta, ExtendStoryObj, ExtendsMeta, ExtendsStoryObj, FnToArgTypes, GlobalApiBackgroundsParam, GlobalApiViewportParam, LayoutParam, ShowHtml, ShowHtmlProps, SourceProps, StoryCard, StoryCardAppearance, StoryCardParam, StoryCardProps, StoryCardStatus, StoryCardThemeState, StorySortParam, StorybookBuiltInParams, TestParam, Viewport, ViewportParam, WithStoryCardProps, defineActionsParam, defineBackgroundsParam, defineDocsParam, defineLayoutParam, defineParameters, defineStoryCardParam, defineTestParam, defineViewportParam, showDocSource, whenRunningInTest, withStoryCard };
package/esm/index.js CHANGED
@@ -39,31 +39,39 @@ function ShowHtml({ selector = "[data-testid=\"subject\"]", config, ...props })
39
39
 
40
40
  //#endregion
41
41
  //#region src/components/story_card.tsx
42
+ function resolveAppearance(appearance, status) {
43
+ if (appearance !== void 0) return appearance;
44
+ if (status !== void 0) return status;
45
+ return "info";
46
+ }
42
47
  function storyCardTheme(state, className) {
43
- const defaultClassName = storyCardVariants(state);
44
- if (!className) return defaultClassName;
45
- return twMerge(typeof className === "function" ? className({
46
- ...state,
47
- defaultClassName
48
- }) : twJoin(defaultClassName, className));
48
+ if (!className) return state.defaultClassName;
49
+ return twMerge(typeof className === "function" ? className(state) : twJoin(state.defaultClassName, className));
49
50
  }
50
- const storyCardVariants = cva("rbsb:flex rbsb:flex-col rbsb:gap-1 rbsb:py-3 rbsb:px-4 rbsb:rounded rbsb:text-black rbsb:dark:text-gray-100", {
51
- variants: { status: {
52
- error: "rbsb:bg-red-100 rbsb:dark:bg-red-900",
53
- warn: "rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900",
54
- info: "rbsb:bg-sky-100 rbsb:dark:bg-sky-900"
51
+ const storyCardVariants = cva("rbsb:flex rbsb:flex-col rbsb:gap-1 rbsb:py-3 rbsb:px-4 rbsb:rounded rbsb:border rbsb:border-solid rbsb:text-black rbsb:dark:text-gray-100", {
52
+ variants: { appearance: {
53
+ error: "rbsb:bg-red-100 rbsb:dark:bg-red-900 rbsb:border-red-300 rbsb:dark:border-red-700",
54
+ warn: "rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900 rbsb:border-yellow-300 rbsb:dark:border-yellow-700",
55
+ info: "rbsb:bg-sky-100 rbsb:dark:bg-sky-900 rbsb:border-sky-300 rbsb:dark:border-sky-700",
56
+ source: "rbsb:bg-gray-100 rbsb:dark:bg-gray-900 rbsb:border-gray-300 rbsb:dark:border-gray-700",
57
+ output: "rbsb:bg-green-100 rbsb:dark:bg-green-900 rbsb:border-green-300 rbsb:dark:border-green-700"
55
58
  } },
56
- defaultVariants: { status: "info" }
59
+ defaultVariants: { appearance: "info" }
57
60
  });
58
61
  /**
59
- * A card component that displays information with optional title and status styling.
62
+ * A card component that displays information with optional title and appearance styling.
60
63
  *
61
64
  * @param props - StoryCard component props
62
65
  * @returns A section element containing the card content
63
66
  */
64
- function StoryCard({ status, className, children, title }) {
67
+ function StoryCard({ status, appearance, className, children, title }) {
68
+ const resolvedAppearance = resolveAppearance(appearance, status);
65
69
  return /* @__PURE__ */ jsxs("section", {
66
- className: storyCardTheme({ status }, className),
70
+ className: storyCardTheme({
71
+ status,
72
+ appearance: resolvedAppearance,
73
+ defaultClassName: storyCardVariants({ appearance: resolvedAppearance })
74
+ }, className),
67
75
  children: [title && /* @__PURE__ */ jsx("h2", {
68
76
  className: "rbsb:text-lg rbsb:font-bold",
69
77
  children: title
@@ -129,13 +137,14 @@ function StoryCardContainer({ children }) {
129
137
  })
130
138
  });
131
139
  }
132
- function StoryCardCollector({ Story, title, status, className, content }) {
140
+ function StoryCardCollector({ Story, title, status, appearance, className, content }) {
133
141
  const context = useContext(StoryCardRegistryContext);
134
142
  const cardIdRef = useRef(null);
135
143
  useLayoutEffect(() => {
136
144
  if (cardIdRef.current === null) cardIdRef.current = context.add({
137
145
  title,
138
146
  status,
147
+ appearance,
139
148
  className,
140
149
  content
141
150
  });
@@ -183,7 +192,7 @@ function showDocSource(options) {
183
192
  const sourceCardClassName = (state) => {
184
193
  const modifiedState = {
185
194
  ...state,
186
- defaultClassName: twJoin(state.defaultClassName, isOriginalSource ? "rbsb:bg-transparent rbsb:dark:bg-transparent" : "rbsb:bg-gray-100 rbsb:dark:bg-gray-900")
195
+ defaultClassName: twJoin(state.defaultClassName, isOriginalSource && "rbsb:bg-transparent rbsb:dark:bg-transparent")
187
196
  };
188
197
  const className = options?.className;
189
198
  return typeof className === "function" ? className(modifiedState) : twJoin(modifiedState.defaultClassName, className);
@@ -195,7 +204,7 @@ function showDocSource(options) {
195
204
  Story,
196
205
  content: sourceContent,
197
206
  className: sourceCardClassName,
198
- status: "info"
207
+ appearance: "source"
199
208
  })
200
209
  });
201
210
  return /* @__PURE__ */ jsx(ThemeProvider, {
@@ -208,7 +217,7 @@ function showDocSource(options) {
208
217
  },
209
218
  children: [/* @__PURE__ */ jsx(Story, {}), /* @__PURE__ */ jsx(StoryCard, {
210
219
  className: sourceCardClassName,
211
- status: "info",
220
+ appearance: "source",
212
221
  children: sourceContent
213
222
  })]
214
223
  })
@@ -295,13 +304,15 @@ function showDocSource(options) {
295
304
  * - If `content` is not provided, it will automatically use the story description,
296
305
  * or fall back to the component description.
297
306
  * - Cards are collected and displayed in the order they are defined in the decorators array.
307
+ * - The `status` option is deprecated; use `appearance` instead for the same behavior and additional variants (`source`, `output`).
298
308
  */
299
- function withStoryCard({ title, status, content: contentProp, className, ...rest } = {}) {
309
+ function withStoryCard({ title, status, appearance, content: contentProp, className, ...rest } = {}) {
300
310
  return (Story, { parameters, viewMode }) => {
301
311
  if (viewMode === "docs") return /* @__PURE__ */ jsx(Story, {});
302
312
  const storyCardParam = parameters.storyCard;
303
313
  const finalTitle = title ?? storyCardParam?.title;
304
- const finalStatus = status ?? storyCardParam?.status ?? "info";
314
+ const finalAppearance = appearance ?? storyCardParam?.appearance ?? status ?? storyCardParam?.status ?? "info";
315
+ const finalStatus = status ?? storyCardParam?.status;
305
316
  const finalContent = contentProp ?? storyCardParam?.content;
306
317
  const finalClassName = className ?? storyCardParam?.className;
307
318
  const content = finalContent ?? parameters.docs?.description?.story ?? parameters.docs?.description?.component;
@@ -311,6 +322,7 @@ function withStoryCard({ title, status, content: contentProp, className, ...rest
311
322
  content,
312
323
  title: finalTitle,
313
324
  status: finalStatus,
325
+ appearance: finalAppearance,
314
326
  className: finalClassName,
315
327
  ...rest
316
328
  });
@@ -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' | 'version:next';
11
+ type TagNames = 'editor' | 'source' | '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.
@@ -37,6 +37,7 @@ declare const outdatedBadge: TagBadgeParameter;
37
37
  declare const dangerBadge: TagBadgeParameter;
38
38
  declare const todoBadge: TagBadgeParameter;
39
39
  declare const codeOnlyBadge: TagBadgeParameter;
40
+ declare const sourceBadge: TagBadgeParameter;
40
41
  declare const snapshotBadge: TagBadgeParameter;
41
42
  declare const unitBadge: TagBadgeParameter;
42
43
  declare const integrationBadge: TagBadgeParameter;
@@ -115,4 +116,4 @@ type StoryObj<TMetaOrCmpOrArgs = Args> = ExtendStoryObj<TMetaOrCmpOrArgs, StoryO
115
116
  tag: TagNames;
116
117
  }>;
117
118
  //#endregion
118
- export { Meta, StoryObj, TagNames, betaBadge, codeOnlyBadge, dangerBadge, deprecatedBadge, editorBadge, integrationBadge, internalBadge, keyboardBadge, newBadge, outdatedBadge, propsBadge, snapshotBadge, tagBadges, todoBadge, unitBadge };
119
+ export { Meta, StoryObj, TagNames, betaBadge, codeOnlyBadge, dangerBadge, deprecatedBadge, editorBadge, integrationBadge, internalBadge, keyboardBadge, newBadge, outdatedBadge, propsBadge, snapshotBadge, sourceBadge, tagBadges, todoBadge, unitBadge };
@@ -123,7 +123,20 @@ const codeOnlyBadge = {
123
123
  borderColor: "transparent"
124
124
  },
125
125
  tooltip: "Code Only"
126
- }
126
+ },
127
+ display: { mdx: false }
128
+ };
129
+ const sourceBadge = {
130
+ tags: "source",
131
+ badge: {
132
+ text: "</>",
133
+ style: {
134
+ backgroundColor: "transparent",
135
+ borderColor: "transparent"
136
+ },
137
+ tooltip: "Source Code"
138
+ },
139
+ display: { mdx: false }
127
140
  };
128
141
  const snapshotBadge = {
129
142
  tags: "snapshot",
@@ -188,6 +201,7 @@ const internalBadge = {
188
201
  };
189
202
  const tagBadges = [
190
203
  editorBadge,
204
+ sourceBadge,
191
205
  unitBadge,
192
206
  integrationBadge,
193
207
  keyboardBadge,
@@ -205,4 +219,4 @@ const tagBadges = [
205
219
  ];
206
220
 
207
221
  //#endregion
208
- export { betaBadge, codeOnlyBadge, dangerBadge, deprecatedBadge, editorBadge, integrationBadge, internalBadge, keyboardBadge, newBadge, outdatedBadge, propsBadge, snapshotBadge, tagBadges, todoBadge, unitBadge };
222
+ export { betaBadge, codeOnlyBadge, dangerBadge, deprecatedBadge, editorBadge, integrationBadge, internalBadge, keyboardBadge, newBadge, outdatedBadge, propsBadge, snapshotBadge, sourceBadge, tagBadges, todoBadge, unitBadge };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@repobuddy/storybook",
3
- "version": "2.12.0",
3
+ "version": "2.14.0",
4
4
  "description": "Storybook repo buddy",
5
5
  "keywords": [
6
6
  "storybook",
@@ -3,10 +3,13 @@ import type { ReactNode } from 'react'
3
3
  import { twJoin, twMerge } from 'tailwind-merge'
4
4
 
5
5
  /**
6
- * Visual status of the card, affecting its background color.
7
- * - `'error'`: Red background (rbsb:bg-red-100 rbsb:dark:bg-red-900)
8
- * - `'warn'`: Yellow background (rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900)
9
- * - `'info'`: Blue background (rbsb:bg-sky-100 rbsb:dark:bg-sky-900) - default
6
+ * Resolved appearance of the card (error | warn | info | source | output).
7
+ * Used for styling; when only `status` is provided it is mapped to this.
8
+ */
9
+ export type StoryCardAppearance = 'error' | 'warn' | 'info' | 'source' | 'output'
10
+
11
+ /**
12
+ * @deprecated Use `appearance` instead. Visual status of the card; equivalent to `appearance` for 'error' | 'warn' | 'info'.
10
13
  */
11
14
  export type StoryCardStatus = 'error' | 'warn' | 'info' | undefined
12
15
 
@@ -17,12 +20,18 @@ export type StoryCardProps = {
17
20
  */
18
21
  title?: ReactNode | undefined
19
22
  /**
20
- * Visual status of the card, affecting its background color.
21
- * - `'error'`: Red background (rbsb:bg-red-100 rbsb:dark:bg-red-900)
22
- * - `'warn'`: Yellow background (rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900)
23
- * - `'info'`: Blue background (rbsb:bg-sky-100 rbsb:dark:bg-sky-900) - default
23
+ * @deprecated Use `appearance` instead. When set, behaves like `appearance` for the same value.
24
24
  */
25
25
  status?: StoryCardStatus
26
+ /**
27
+ * Appearance of the card, affecting its background and border color.
28
+ * - `'error'`: Red
29
+ * - `'warn'`: Yellow
30
+ * - `'info'`: Blue (default when neither appearance nor status is set)
31
+ * - `'source'`: Transparent
32
+ * - `'output'`: Green
33
+ */
34
+ appearance?: StoryCardAppearance | undefined
26
35
  /**
27
36
  * Additional CSS classes or a function to compute classes.
28
37
  *
@@ -30,7 +39,10 @@ export type StoryCardProps = {
30
39
  * If a function is provided, it receives the card state and default className,
31
40
  * and should return the final className string.
32
41
  */
33
- className?: ((state: Pick<StoryCardProps, 'status'> & { defaultClassName: string }) => string) | string | undefined
42
+ className?:
43
+ | ((state: Pick<StoryCardProps, 'status' | 'appearance'> & { defaultClassName: string }) => string)
44
+ | string
45
+ | undefined
34
46
  /**
35
47
  * Content to display in the card body.
36
48
  * Can be any React node (string, JSX, etc.).
@@ -38,39 +50,55 @@ export type StoryCardProps = {
38
50
  children?: ReactNode | undefined
39
51
  }
40
52
 
41
- function storyCardTheme(state: Pick<StoryCardProps, 'status'>, className: StoryCardProps['className']) {
42
- const defaultClassName = storyCardVariants(state)
43
- if (!className) return defaultClassName
44
- return twMerge(
45
- typeof className === 'function' ? className({ ...state, defaultClassName }) : twJoin(defaultClassName, className)
46
- )
53
+ export type StoryCardThemeState = Pick<StoryCardProps, 'status' | 'appearance'> & { defaultClassName: string }
54
+
55
+ function resolveAppearance(
56
+ appearance: StoryCardProps['appearance'],
57
+ status: StoryCardProps['status']
58
+ ): NonNullable<StoryCardAppearance> {
59
+ if (appearance !== undefined) return appearance
60
+ if (status !== undefined) return status
61
+ return 'info'
62
+ }
63
+
64
+ function storyCardTheme(state: StoryCardThemeState, className: StoryCardProps['className']) {
65
+ if (!className) return state.defaultClassName
66
+ return twMerge(typeof className === 'function' ? className(state) : twJoin(state.defaultClassName, className))
47
67
  }
48
68
 
49
69
  const storyCardVariants = cva(
50
- 'rbsb:flex rbsb:flex-col rbsb:gap-1 rbsb:py-3 rbsb:px-4 rbsb:rounded rbsb:text-black rbsb:dark:text-gray-100',
70
+ 'rbsb:flex rbsb:flex-col rbsb:gap-1 rbsb:py-3 rbsb:px-4 rbsb:rounded rbsb:border rbsb:border-solid rbsb:text-black rbsb:dark:text-gray-100',
51
71
  {
52
72
  variants: {
53
- status: {
54
- error: 'rbsb:bg-red-100 rbsb:dark:bg-red-900',
55
- warn: 'rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900',
56
- info: 'rbsb:bg-sky-100 rbsb:dark:bg-sky-900'
73
+ appearance: {
74
+ error: 'rbsb:bg-red-100 rbsb:dark:bg-red-900 rbsb:border-red-300 rbsb:dark:border-red-700',
75
+ warn: 'rbsb:bg-yellow-100 rbsb:dark:bg-yellow-900 rbsb:border-yellow-300 rbsb:dark:border-yellow-700',
76
+ info: 'rbsb:bg-sky-100 rbsb:dark:bg-sky-900 rbsb:border-sky-300 rbsb:dark:border-sky-700',
77
+ source: 'rbsb:bg-gray-100 rbsb:dark:bg-gray-900 rbsb:border-gray-300 rbsb:dark:border-gray-700',
78
+ output: 'rbsb:bg-green-100 rbsb:dark:bg-green-900 rbsb:border-green-300 rbsb:dark:border-green-700'
57
79
  }
58
80
  },
59
81
  defaultVariants: {
60
- status: 'info'
82
+ appearance: 'info'
61
83
  }
62
84
  }
63
85
  )
64
86
 
65
87
  /**
66
- * A card component that displays information with optional title and status styling.
88
+ * A card component that displays information with optional title and appearance styling.
67
89
  *
68
90
  * @param props - StoryCard component props
69
91
  * @returns A section element containing the card content
70
92
  */
71
- export function StoryCard({ status, className, children, title }: StoryCardProps) {
93
+ export function StoryCard({ status, appearance, className, children, title }: StoryCardProps) {
94
+ const resolvedAppearance = resolveAppearance(appearance, status)
95
+ const state: StoryCardThemeState = {
96
+ status,
97
+ appearance: resolvedAppearance,
98
+ defaultClassName: storyCardVariants({ appearance: resolvedAppearance })
99
+ }
72
100
  return (
73
- <section className={storyCardTheme({ status }, className)}>
101
+ <section className={storyCardTheme(state, className)}>
74
102
  {title && <h2 className="rbsb:text-lg rbsb:font-bold">{title}</h2>}
75
103
  {children}
76
104
  </section>
@@ -1,13 +1,12 @@
1
1
  import type { ReactNode } from 'react'
2
2
  import { createContext } from 'react'
3
- import type { RequiredPick } from 'type-plus'
4
3
  import type { StoryCardProps } from '../components/story_card.js'
5
4
 
6
5
  /**
7
6
  * Payload for adding a card to the story card registry.
8
7
  * Matches the shape of card props with `status` required.
9
8
  */
10
- export type StoryCardEntry = RequiredPick<Omit<StoryCardProps, 'children'> & { content?: ReactNode }, 'status'>
9
+ export type StoryCardEntry = Omit<StoryCardProps, 'children'> & { content?: ReactNode }
11
10
 
12
11
  export interface StoryCardRegistryContextValue {
13
12
  add: (card: StoryCardEntry) => string
@@ -59,7 +59,7 @@ type StoryCardEntryWithKey = StoryCardEntry & { key: string }
59
59
 
60
60
  interface StoryCardCollectorProps extends StoryCardScopeProps {}
61
61
 
62
- function StoryCardCollector({ Story, title, status, className, content }: StoryCardCollectorProps) {
62
+ function StoryCardCollector({ Story, title, status, appearance, className, content }: StoryCardCollectorProps) {
63
63
  // StoryCardCollector is an internal component. Context is guaranteed to be not null by `StoryCardContainer`.
64
64
  const context = useContext(StoryCardRegistryContext)!
65
65
  const cardIdRef = useRef<string | null>(null)
@@ -68,7 +68,7 @@ function StoryCardCollector({ Story, title, status, className, content }: StoryC
68
68
  useLayoutEffect(() => {
69
69
  // Only add if not already added (handles Strict Mode double-render)
70
70
  if (cardIdRef.current === null) {
71
- cardIdRef.current = context.add({ title, status, className, content })
71
+ cardIdRef.current = context.add({ title, status, appearance, className, content })
72
72
  }
73
73
 
74
74
  return () => {
@@ -58,12 +58,14 @@ export function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Arg
58
58
 
59
59
  const showBefore = options?.placement === 'before'
60
60
 
61
- const sourceCardClassName = (state: Pick<StoryCardProps, 'status'> & { defaultClassName: string }) => {
61
+ const sourceCardClassName = (
62
+ state: Pick<StoryCardProps, 'status' | 'appearance'> & { defaultClassName: string }
63
+ ) => {
62
64
  const modifiedState = {
63
65
  ...state,
64
66
  defaultClassName: twJoin(
65
67
  state.defaultClassName,
66
- isOriginalSource ? 'rbsb:bg-transparent rbsb:dark:bg-transparent' : 'rbsb:bg-gray-100 rbsb:dark:bg-gray-900'
68
+ isOriginalSource && 'rbsb:bg-transparent rbsb:dark:bg-transparent'
67
69
  )
68
70
  }
69
71
 
@@ -78,13 +80,13 @@ export function showDocSource<TRenderer extends Renderer = Renderer, TArgs = Arg
78
80
  if (showBefore) {
79
81
  return (
80
82
  <ThemeProvider theme={theme}>
81
- <StoryCardScope Story={Story} content={sourceContent} className={sourceCardClassName} status="info" />
83
+ <StoryCardScope Story={Story} content={sourceContent} className={sourceCardClassName} appearance="source" />
82
84
  </ThemeProvider>
83
85
  )
84
86
  }
85
87
 
86
88
  const storyCard = (
87
- <StoryCard className={sourceCardClassName} status="info">
89
+ <StoryCard className={sourceCardClassName} appearance="source">
88
90
  {sourceContent}
89
91
  </StoryCard>
90
92
  )
@@ -1,10 +1,14 @@
1
1
  import type { ReactNode } from 'react'
2
2
  import type { DecoratorFunction, Renderer } from 'storybook/internal/csf'
3
- import type { StoryCardProps } from '../components/story_card.js'
3
+ import type { StoryCardProps, StoryCardStatus } from '../components/story_card.js'
4
4
  import { StoryCardScope } from '../contexts/story_card_scope.js'
5
5
  import type { StoryCardParam } from '../parameters/define_story_card_param.js'
6
6
 
7
7
  export type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'> & {
8
+ /**
9
+ * @deprecated Use `appearance` instead. When set, behaves like `appearance` for the same value.
10
+ */
11
+ status?: StoryCardStatus
8
12
  /**
9
13
  * Additional CSS classes or a function to compute classes.
10
14
  *
@@ -12,7 +16,10 @@ export type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'>
12
16
  * If a function is provided, it receives the card state and default className,
13
17
  * and should return the final className string.
14
18
  */
15
- className?: ((state: Pick<StoryCardProps, 'status'> & { defaultClassName: string }) => string) | string | undefined
19
+ className?:
20
+ | ((state: Pick<StoryCardProps, 'status' | 'appearance'> & { defaultClassName: string }) => string)
21
+ | string
22
+ | undefined
16
23
  /**
17
24
  * Content to display in the card body.
18
25
  * Can be any React node (string, JSX, etc.).
@@ -102,10 +109,12 @@ export type WithStoryCardProps = Omit<StoryCardProps, 'children' | 'className'>
102
109
  * - If `content` is not provided, it will automatically use the story description,
103
110
  * or fall back to the component description.
104
111
  * - Cards are collected and displayed in the order they are defined in the decorators array.
112
+ * - The `status` option is deprecated; use `appearance` instead for the same behavior and additional variants (`source`, `output`).
105
113
  */
106
114
  export function withStoryCard<TRenderer extends Renderer = Renderer>({
107
115
  title,
108
116
  status,
117
+ appearance,
109
118
  content: contentProp,
110
119
  className,
111
120
  ...rest
@@ -118,7 +127,8 @@ export function withStoryCard<TRenderer extends Renderer = Renderer>({
118
127
  // Decorator props override parameter values
119
128
  // Use parameters as fallback when decorator props are not provided
120
129
  const finalTitle = title ?? storyCardParam?.title
121
- const finalStatus = status ?? storyCardParam?.status ?? 'info'
130
+ const finalAppearance = appearance ?? storyCardParam?.appearance ?? status ?? storyCardParam?.status ?? 'info'
131
+ const finalStatus = status ?? storyCardParam?.status
122
132
  const finalContent = contentProp ?? storyCardParam?.content
123
133
  const finalClassName = className ?? storyCardParam?.className
124
134
 
@@ -132,6 +142,7 @@ export function withStoryCard<TRenderer extends Renderer = Renderer>({
132
142
  content={content}
133
143
  title={finalTitle}
134
144
  status={finalStatus}
145
+ appearance={finalAppearance}
135
146
  className={finalClassName}
136
147
  {...rest}
137
148
  />
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react'
2
- import type { StoryCardProps, StoryCardStatus } from '../components/story_card.js'
2
+ import type { StoryCardAppearance, StoryCardProps, StoryCardStatus } from '../components/story_card.js'
3
3
 
4
4
  export interface StoryCardParam {
5
5
  storyCard: {
@@ -9,12 +9,13 @@ export interface StoryCardParam {
9
9
  */
10
10
  title?: ReactNode | undefined
11
11
  /**
12
- * Visual status of the card, affecting its background color.
13
- * - `'error'`: Red background
14
- * - `'warn'`: Yellow background
15
- * - `'info'`: Blue background - default
12
+ * @deprecated Use `appearance` instead.
16
13
  */
17
14
  status?: StoryCardStatus
15
+ /**
16
+ * Appearance of the card (error | warn | info | source | output). Default: `'info'`.
17
+ */
18
+ appearance?: StoryCardAppearance | undefined
18
19
  /**
19
20
  * Additional CSS classes or a function to compute classes.
20
21
  *
@@ -22,7 +23,10 @@ export interface StoryCardParam {
22
23
  * If a function is provided, it receives the card state and default className,
23
24
  * and should return the final className string.
24
25
  */
25
- className?: ((state: Pick<StoryCardProps, 'status'> & { defaultClassName: string }) => string) | string | undefined
26
+ className?:
27
+ | ((state: Pick<StoryCardProps, 'status' | 'appearance'> & { defaultClassName: string }) => string)
28
+ | string
29
+ | undefined
26
30
  /**
27
31
  * Content to display in the card body.
28
32
  * Can be any React node (string, JSX, etc.).
@@ -9,6 +9,7 @@ type TagBadgeParameter = TagBadgeParameters[0]
9
9
  */
10
10
  export type TagNames =
11
11
  | 'editor'
12
+ | 'source'
12
13
  | 'new'
13
14
  | 'beta'
14
15
  | 'props'
@@ -155,6 +156,24 @@ export const codeOnlyBadge: TagBadgeParameter = {
155
156
  borderColor: 'transparent'
156
157
  },
157
158
  tooltip: 'Code Only'
159
+ },
160
+ display: {
161
+ mdx: false
162
+ }
163
+ }
164
+
165
+ export const sourceBadge: TagBadgeParameter = {
166
+ tags: 'source',
167
+ badge: {
168
+ text: '</>',
169
+ style: {
170
+ backgroundColor: 'transparent',
171
+ borderColor: 'transparent'
172
+ },
173
+ tooltip: 'Source Code'
174
+ },
175
+ display: {
176
+ mdx: false
158
177
  }
159
178
  }
160
179
 
@@ -230,6 +249,7 @@ export const internalBadge: TagBadgeParameter = {
230
249
 
231
250
  export const tagBadges: TagBadgeParameters = [
232
251
  editorBadge,
252
+ sourceBadge,
233
253
  unitBadge,
234
254
  integrationBadge,
235
255
  keyboardBadge,
package/styles.css CHANGED
@@ -3,19 +3,31 @@
3
3
  @layer theme {
4
4
  :root, :host {
5
5
  --rbsb-color-red-100: oklch(93.6% 0.032 17.717);
6
+ --rbsb-color-red-300: oklch(80.8% 0.114 19.571);
6
7
  --rbsb-color-red-500: oklch(63.7% 0.237 25.331);
8
+ --rbsb-color-red-700: oklch(50.5% 0.213 27.518);
7
9
  --rbsb-color-red-800: oklch(44.4% 0.177 26.899);
8
10
  --rbsb-color-red-900: oklch(39.6% 0.141 25.723);
9
11
  --rbsb-color-amber-300: oklch(87.9% 0.169 91.605);
10
12
  --rbsb-color-amber-900: oklch(41.4% 0.112 45.904);
11
13
  --rbsb-color-yellow-100: oklch(97.3% 0.071 103.193);
14
+ --rbsb-color-yellow-300: oklch(90.5% 0.182 98.111);
12
15
  --rbsb-color-yellow-500: oklch(79.5% 0.184 86.047);
16
+ --rbsb-color-yellow-700: oklch(55.4% 0.135 66.442);
13
17
  --rbsb-color-yellow-900: oklch(42.1% 0.095 57.708);
18
+ --rbsb-color-green-100: oklch(96.2% 0.044 156.743);
14
19
  --rbsb-color-green-200: oklch(92.5% 0.084 155.995);
20
+ --rbsb-color-green-300: oklch(87.1% 0.15 154.449);
15
21
  --rbsb-color-green-500: oklch(72.3% 0.219 149.579);
22
+ --rbsb-color-green-700: oklch(52.7% 0.154 150.069);
16
23
  --rbsb-color-green-800: oklch(44.8% 0.119 151.328);
24
+ --rbsb-color-green-900: oklch(39.3% 0.095 152.535);
25
+ --rbsb-color-emerald-200: oklch(90.5% 0.093 164.15);
26
+ --rbsb-color-emerald-800: oklch(43.2% 0.095 166.913);
17
27
  --rbsb-color-sky-100: oklch(95.1% 0.026 236.824);
28
+ --rbsb-color-sky-300: oklch(82.8% 0.111 230.318);
18
29
  --rbsb-color-sky-500: oklch(68.5% 0.169 237.323);
30
+ --rbsb-color-sky-700: oklch(50% 0.134 242.749);
19
31
  --rbsb-color-sky-900: oklch(39.1% 0.09 240.876);
20
32
  --rbsb-color-blue-200: oklch(88.2% 0.059 254.128);
21
33
  --rbsb-color-blue-500: oklch(62.3% 0.214 259.815);
@@ -25,7 +37,9 @@
25
37
  --rbsb-color-rose-400: oklch(71.2% 0.194 13.428);
26
38
  --rbsb-color-rose-900: oklch(41% 0.159 10.272);
27
39
  --rbsb-color-gray-100: oklch(96.7% 0.003 264.542);
40
+ --rbsb-color-gray-300: oklch(87.2% 0.01 258.338);
28
41
  --rbsb-color-gray-500: oklch(55.1% 0.027 264.364);
42
+ --rbsb-color-gray-700: oklch(37.3% 0.034 259.733);
29
43
  --rbsb-color-gray-900: oklch(21% 0.034 264.665);
30
44
  --rbsb-color-black: #000;
31
45
  --rbsb-color-white: #fff;
@@ -72,28 +86,51 @@
72
86
  .rbsb\:rounded-lg {
73
87
  border-radius: var(--rbsb-radius-lg);
74
88
  }
89
+ .rbsb\:border {
90
+ border-style: var(--tw-border-style);
91
+ border-width: 1px;
92
+ }
75
93
  .rbsb\:border-2 {
76
94
  border-style: var(--tw-border-style);
77
95
  border-width: 2px;
78
96
  }
97
+ .rbsb\:border-solid {
98
+ --tw-border-style: solid;
99
+ border-style: solid;
100
+ }
79
101
  .rbsb\:border-blue-500 {
80
102
  border-color: var(--rbsb-color-blue-500);
81
103
  }
104
+ .rbsb\:border-gray-300 {
105
+ border-color: var(--rbsb-color-gray-300);
106
+ }
82
107
  .rbsb\:border-gray-500 {
83
108
  border-color: var(--rbsb-color-gray-500);
84
109
  }
110
+ .rbsb\:border-green-300 {
111
+ border-color: var(--rbsb-color-green-300);
112
+ }
85
113
  .rbsb\:border-green-500 {
86
114
  border-color: var(--rbsb-color-green-500);
87
115
  }
88
116
  .rbsb\:border-purple-500 {
89
117
  border-color: var(--rbsb-color-purple-500);
90
118
  }
119
+ .rbsb\:border-red-300 {
120
+ border-color: var(--rbsb-color-red-300);
121
+ }
91
122
  .rbsb\:border-red-500 {
92
123
  border-color: var(--rbsb-color-red-500);
93
124
  }
125
+ .rbsb\:border-sky-300 {
126
+ border-color: var(--rbsb-color-sky-300);
127
+ }
94
128
  .rbsb\:border-sky-500 {
95
129
  border-color: var(--rbsb-color-sky-500);
96
130
  }
131
+ .rbsb\:border-yellow-300 {
132
+ border-color: var(--rbsb-color-yellow-300);
133
+ }
97
134
  .rbsb\:border-yellow-500 {
98
135
  border-color: var(--rbsb-color-yellow-500);
99
136
  }
@@ -106,9 +143,15 @@
106
143
  .rbsb\:bg-blue-500 {
107
144
  background-color: var(--rbsb-color-blue-500);
108
145
  }
146
+ .rbsb\:bg-emerald-200 {
147
+ background-color: var(--rbsb-color-emerald-200);
148
+ }
109
149
  .rbsb\:bg-gray-100 {
110
150
  background-color: var(--rbsb-color-gray-100);
111
151
  }
152
+ .rbsb\:bg-green-100 {
153
+ background-color: var(--rbsb-color-green-100);
154
+ }
112
155
  .rbsb\:bg-green-200 {
113
156
  background-color: var(--rbsb-color-green-200);
114
157
  }
@@ -184,6 +227,31 @@
184
227
  .rbsb\:ring-blue-200 {
185
228
  --tw-ring-color: var(--rbsb-color-blue-200);
186
229
  }
230
+ .rbsb\:dark\:border-gray-700 {
231
+ @media (prefers-color-scheme: dark) {
232
+ border-color: var(--rbsb-color-gray-700);
233
+ }
234
+ }
235
+ .rbsb\:dark\:border-green-700 {
236
+ @media (prefers-color-scheme: dark) {
237
+ border-color: var(--rbsb-color-green-700);
238
+ }
239
+ }
240
+ .rbsb\:dark\:border-red-700 {
241
+ @media (prefers-color-scheme: dark) {
242
+ border-color: var(--rbsb-color-red-700);
243
+ }
244
+ }
245
+ .rbsb\:dark\:border-sky-700 {
246
+ @media (prefers-color-scheme: dark) {
247
+ border-color: var(--rbsb-color-sky-700);
248
+ }
249
+ }
250
+ .rbsb\:dark\:border-yellow-700 {
251
+ @media (prefers-color-scheme: dark) {
252
+ border-color: var(--rbsb-color-yellow-700);
253
+ }
254
+ }
187
255
  .rbsb\:dark\:bg-amber-900 {
188
256
  @media (prefers-color-scheme: dark) {
189
257
  background-color: var(--rbsb-color-amber-900);
@@ -194,6 +262,11 @@
194
262
  background-color: var(--rbsb-color-blue-900);
195
263
  }
196
264
  }
265
+ .rbsb\:dark\:bg-emerald-800 {
266
+ @media (prefers-color-scheme: dark) {
267
+ background-color: var(--rbsb-color-emerald-800);
268
+ }
269
+ }
197
270
  .rbsb\:dark\:bg-gray-500 {
198
271
  @media (prefers-color-scheme: dark) {
199
272
  background-color: var(--rbsb-color-gray-500);
@@ -209,6 +282,11 @@
209
282
  background-color: var(--rbsb-color-green-800);
210
283
  }
211
284
  }
285
+ .rbsb\:dark\:bg-green-900 {
286
+ @media (prefers-color-scheme: dark) {
287
+ background-color: var(--rbsb-color-green-900);
288
+ }
289
+ }
212
290
  .rbsb\:dark\:bg-red-900 {
213
291
  @media (prefers-color-scheme: dark) {
214
292
  background-color: var(--rbsb-color-red-900);