Skip to content

Commit 68c4d79

Browse files
chore(storybook): use custom toolbar button for theme selection (#652)
1 parent a79703d commit 68c4d79

File tree

2 files changed

+95
-42
lines changed

2 files changed

+95
-42
lines changed

.storybook/preview.tsx

Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,104 @@
1-
import React from "react";
1+
import React, { useEffect } from "react";
2+
import type { Preview, Decorator } from "@storybook/react";
23
import "../src/base.css";
34
import "../src/fonts.css";
45

5-
export const parameters = {
6-
controls: {
7-
matchers: {
8-
color: /(background|color)$/i,
9-
date: /Date$/,
10-
},
6+
const THEME_OPTIONS = {
7+
light: {
8+
name: "Light",
9+
value: "light-palette",
10+
backgroundColor: "#f5f6f7",
1111
},
12-
backgrounds: {
13-
default: "light-palette",
14-
values: [
15-
{
16-
name: "light-palette",
17-
value: "#f5f6f7",
18-
},
19-
{
20-
name: "dark-palette",
21-
value: "#1b1b32",
22-
},
23-
],
12+
dark: {
13+
name: "Dark",
14+
value: "dark-palette",
15+
backgroundColor: "#1b1b32",
2416
},
25-
};
26-
27-
export const decorators = [renderTheme];
17+
} as const;
2818

2919
/**
30-
* Gets matching theme name for currently selected background and provides it
31-
* to the story.
20+
* Theme decorator that applies theme classes to the body and story container
3221
*/
33-
function renderTheme(Story, context) {
34-
const selectedBackgroundValue = context.globals.backgrounds?.value;
35-
const selectedBackgroundName = parameters.backgrounds.values.find(
36-
(bg) => bg.value === selectedBackgroundValue,
37-
)?.name;
38-
39-
// Use the value of the default background to prevent "undefined" className
40-
const className = selectedBackgroundName || parameters.backgrounds.default;
41-
42-
if (className === "light-palette") {
43-
document.body.classList.remove("dark-palette");
44-
document.body.classList.add("light-palette");
45-
} else {
46-
document.body.classList.remove("light-palette");
47-
document.body.classList.add("dark-palette");
48-
}
22+
const withThemeProvider: Decorator = (Story, context) => {
23+
const theme = context.globals.theme || THEME_OPTIONS.light.value;
24+
const themeConfig =
25+
Object.values(THEME_OPTIONS).find((t) => t.value === theme) ||
26+
THEME_OPTIONS.light;
27+
28+
useEffect(() => {
29+
const body = document.body;
30+
31+
Object.values(THEME_OPTIONS).forEach((t) => {
32+
body.classList.remove(t.value);
33+
});
34+
35+
body.classList.add(theme);
36+
37+
// Story page
38+
const canvas = document.querySelector(".sb-show-main") as HTMLElement;
39+
40+
// Docs page
41+
const docsStories = document.querySelectorAll(".docs-story");
42+
43+
if (canvas) {
44+
canvas.style.backgroundColor = themeConfig.backgroundColor;
45+
}
46+
47+
if (docsStories.length > 0) {
48+
docsStories.forEach((el) => {
49+
(el as HTMLElement).style.backgroundColor = themeConfig.backgroundColor;
50+
});
51+
}
52+
53+
return () => {
54+
Object.values(THEME_OPTIONS).forEach((t) => {
55+
body.classList.remove(t.value);
56+
});
57+
};
58+
}, [theme, themeConfig.backgroundColor]);
4959

5060
return <Story />;
51-
}
61+
};
62+
63+
export const globalTypes = {
64+
theme: {
65+
name: "Theme",
66+
description: "Global theme for components",
67+
defaultValue: THEME_OPTIONS.light.value,
68+
toolbar: {
69+
icon: "paintbrush",
70+
// Array of plain string values or MenuItem shape
71+
items: [
72+
{
73+
value: THEME_OPTIONS.light.value,
74+
title: THEME_OPTIONS.light.name,
75+
icon: "sun",
76+
},
77+
{
78+
value: THEME_OPTIONS.dark.value,
79+
title: THEME_OPTIONS.dark.name,
80+
icon: "moon",
81+
},
82+
],
83+
// Change title based on selected value
84+
dynamicTitle: true,
85+
},
86+
},
87+
};
88+
89+
const preview: Preview = {
90+
parameters: {
91+
controls: {
92+
matchers: {
93+
color: /(background|color)$/i,
94+
date: /Date$/i,
95+
},
96+
},
97+
// Remove backgrounds to disable the default background selector
98+
backgrounds: { disable: true },
99+
},
100+
globalTypes,
101+
decorators: [withThemeProvider],
102+
};
103+
104+
export default preview;

src/row/row.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const Default: Story = {
2222
Column 1
2323
</Col>
2424
<Col
25-
xs={2}
25+
xs={4}
2626
md={8}
2727
className="bg-blue-700 my-2 px-3 py-2 text-white text-center"
2828
>

0 commit comments

Comments
 (0)