@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 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>(): DecoratorFunction<TRenderer, TArgs>;
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/decorators/with_story_card.d.ts
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: Required<Pick<StoryCardProps, 'status'>> & {
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
- }?: StoryCardProps): DecoratorFunction<TRenderer>;
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, StoryCardProps, StorySortParam, StorybookBuiltInParams, TestParam, Viewport, ViewportParam, defineActionsParam, defineBackgroundsParam, defineDocsParam, defineLayoutParam, defineParameters, defineTestParam, defineViewportParam, showDocSource, whenRunningInTest, withStoryCard };
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(SyntaxHighlighter, {
65
- language: docs?.source?.language,
66
- children: docs?.source?.code
67
- }), /* @__PURE__ */ jsx(Story, {})]
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$1) => [...cards$1, {
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$1) => cards$1.filter((card) => card.key !== key));
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(({ key, status, className, content, title }) => /* @__PURE__ */ jsxs("section", {
196
- className: storyCardTheme({ status }, className),
197
- children: [title && /* @__PURE__ */ jsx("h2", {
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$1) => Object.assign(acc, param$1), 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.0",
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.7.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.18.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>(): DecoratorFunction<
14
- TRenderer,
15
- TArgs
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 StoryCardProps = {
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
- }: StoryCardProps = {}): DecoratorFunction<TRenderer> {
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<StoryCardProps, 'status'> {
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(({ key, status, className, content, title }) => (
170
- <section key={key} className={storyCardTheme({ status }, className)}>
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
- </section>
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<StoryCardProps, 'status'> & { key: string }
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<StoryCardProps, 'status'> {
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<StoryCardProps, 'status'>) => string
194
+ addCard: (card: RequiredPick<WithStoryCardProps, 'status'>) => string
230
195
  removeCard: (id: string) => void
231
196
  }
232
197
 
@@ -23,6 +23,7 @@ export type TagNames =
23
23
  | 'keyboard'
24
24
  | 'internal'
25
25
  | 'usecase'
26
+ | 'version:next'
26
27
 
27
28
  /**
28
29
  * Configuration for story tag badges that appear in the Storybook sidebar.
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);