Skip to content

Commit 2eac4e8

Browse files
WesSouzaarturbien
authored andcommitted
feat(storybook): Reimplement "Themes" add on with React95 style
This also upgrades many dependencies, removes storybook-addon-styled-component-theme and configures babel in preparation for Storybook v7.
1 parent 71a964e commit 2eac4e8

20 files changed

+1524
-1144
lines changed

.babelrc

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,67 @@
11
{
2+
"sourceType": "unambiguous",
23
"presets": [
34
[
45
"@babel/preset-env",
56
{
6-
"modules": false
7+
"shippedProposals": true,
8+
"loose": true
79
}
810
],
9-
"@babel/preset-react"
11+
"@babel/preset-typescript"
1012
],
1113
"plugins": [
12-
"babel-plugin-styled-components",
13-
"@babel/plugin-proposal-class-properties",
14-
"@babel/plugin-transform-runtime"
15-
],
16-
"env": {
17-
"test": {
18-
"presets": ["@babel/preset-env"],
19-
"plugins": [
20-
["babel-plugin-styled-components", { "ssr": false, "displayName": false }]
21-
]
22-
}
23-
}
24-
}
14+
"@babel/plugin-transform-shorthand-properties",
15+
"@babel/plugin-transform-block-scoping",
16+
[
17+
"@babel/plugin-proposal-decorators",
18+
{
19+
"legacy": true
20+
}
21+
],
22+
[
23+
"@babel/plugin-proposal-class-properties",
24+
{
25+
"loose": true
26+
}
27+
],
28+
[
29+
"@babel/plugin-proposal-private-property-in-object",
30+
{
31+
"loose": true
32+
}
33+
],
34+
[
35+
"@babel/plugin-proposal-private-methods",
36+
{
37+
"loose": true
38+
}
39+
],
40+
"@babel/plugin-proposal-export-default-from",
41+
"@babel/plugin-syntax-dynamic-import",
42+
[
43+
"@babel/plugin-proposal-object-rest-spread",
44+
{
45+
"loose": true,
46+
"useBuiltIns": true
47+
}
48+
],
49+
"@babel/plugin-transform-classes",
50+
"@babel/plugin-transform-arrow-functions",
51+
"@babel/plugin-transform-parameters",
52+
"@babel/plugin-transform-destructuring",
53+
"@babel/plugin-transform-spread",
54+
"@babel/plugin-transform-for-of",
55+
"babel-plugin-macros",
56+
"@babel/plugin-proposal-optional-chaining",
57+
"@babel/plugin-proposal-nullish-coalescing-operator",
58+
[
59+
"babel-plugin-polyfill-corejs3",
60+
{
61+
"method": "usage-global",
62+
"absoluteImports": "core-js",
63+
"version": "3.24.1"
64+
}
65+
]
66+
]
67+
}

.storybook/decorators/globalStyle.js renamed to .storybook/decorators/withGlobalStyle.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { DecoratorFn } from '@storybook/react';
12
import React from 'react';
23
import { createGlobalStyle } from 'styled-components';
34

4-
import styleReset from '../../src/common/styleReset';
5-
// TODO is there a way to keep import paths consistent with what end user will get?
65
import ms_sans_serif from '../../src/assets/fonts/dist/ms_sans_serif.woff2';
76
import ms_sans_serif_bold from '../../src/assets/fonts/dist/ms_sans_serif_bold.woff2';
7+
import styleReset from '../../src/common/styleReset';
88

99
const GlobalStyle = createGlobalStyle`
1010
${styleReset}
@@ -25,9 +25,9 @@ const GlobalStyle = createGlobalStyle`
2525
}
2626
`;
2727

28-
export default storyFn => (
28+
export const withGlobalStyle: DecoratorFn = story => (
2929
<>
3030
<GlobalStyle />
31-
{storyFn()}
31+
{story()}
3232
</>
3333
);

.storybook/main.js

Lines changed: 0 additions & 29 deletions
This file was deleted.

.storybook/main.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { StorybookConfig } from '@storybook/react/types';
2+
import type { PropItem } from 'react-docgen-typescript';
3+
4+
const path = require('path');
5+
6+
const storybookConfig: StorybookConfig = {
7+
stories: ['../src/**/*.stories.@(tsx|mdx)'],
8+
addons: [
9+
{
10+
name: '@storybook/addon-docs',
11+
options: {
12+
sourceLoaderOptions: {
13+
injectStoryParameters: false
14+
}
15+
}
16+
},
17+
'@storybook/addon-storysource',
18+
'./theme-picker/register.ts'
19+
],
20+
core: {
21+
builder: 'webpack5'
22+
},
23+
features: {
24+
babelModeV7: true,
25+
storyStoreV7: true,
26+
modernInlineRender: true,
27+
postcss: false
28+
},
29+
typescript: {
30+
check: false,
31+
checkOptions: {},
32+
reactDocgen: 'react-docgen-typescript',
33+
reactDocgenTypescriptOptions: {
34+
shouldExtractLiteralValuesFromEnum: true,
35+
propFilter: (prop: PropItem) =>
36+
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true
37+
}
38+
},
39+
webpackFinal: config => {
40+
config.resolve = {
41+
...config.resolve,
42+
alias: {
43+
...config.resolve?.alias,
44+
react95: path.resolve(__dirname, '../src/index')
45+
}
46+
};
47+
48+
return config;
49+
}
50+
};
51+
52+
module.exports = storybookConfig;
File renamed without changes.

.storybook/preview.js

Lines changed: 0 additions & 40 deletions
This file was deleted.

.storybook/preview.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { DecoratorFn, Parameters } from '@storybook/react';
2+
import { withGlobalStyle } from './decorators/withGlobalStyle';
3+
import { withThemesProvider } from './theme-picker/ThemeProvider';
4+
5+
export const decorators: DecoratorFn[] = [withGlobalStyle, withThemesProvider];
6+
7+
export const parameters: Parameters = {
8+
layout: 'fullscreen'
9+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { useCallback } from 'react';
2+
import { ThemeProvider } from 'styled-components';
3+
import { Button } from '../../src/Button/Button';
4+
import { Theme } from '../../src/types';
5+
6+
export function ThemeButton({
7+
active,
8+
onChoose,
9+
theme
10+
}: {
11+
active: boolean;
12+
onChoose: (themeName: string) => void;
13+
theme: Theme;
14+
}) {
15+
const handleClick = useCallback(() => {
16+
onChoose(theme.name);
17+
}, []);
18+
19+
return (
20+
<ThemeProvider theme={theme}>
21+
<Button active={active} onClick={handleClick}>
22+
{theme.name}
23+
</Button>
24+
</ThemeProvider>
25+
);
26+
}

.storybook/theme-picker/ThemeList.tsx

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { useAddonState } from '@storybook/api';
2+
import React, { useCallback } from 'react';
3+
import styled from 'styled-components';
4+
5+
import themes from '../../src/common/themes';
6+
import { Theme } from '../../src/types';
7+
import { THEMES_ID } from './constants';
8+
import { ThemeButton } from './ThemeButton';
9+
10+
const {
11+
original,
12+
rainyDay,
13+
vaporTeal,
14+
theSixtiesUSA,
15+
olive,
16+
tokyoDark,
17+
rose,
18+
plum,
19+
matrix,
20+
travel,
21+
...otherThemes
22+
} = themes;
23+
24+
const themeList = [
25+
original,
26+
rainyDay,
27+
vaporTeal,
28+
theSixtiesUSA,
29+
olive,
30+
tokyoDark,
31+
rose,
32+
plum,
33+
matrix,
34+
travel,
35+
...Object.values(otherThemes)
36+
];
37+
38+
type ThemesProps = {
39+
active?: boolean;
40+
};
41+
42+
const Wrapper = styled.div<{ theme: Theme }>`
43+
display: grid;
44+
padding: 1em;
45+
gap: 1em;
46+
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
47+
grid-template-rows: repeat(auto-fill, 40px);
48+
background-color: ${({ theme }) => theme.material};
49+
`;
50+
51+
export function ThemeList({ active }: ThemesProps) {
52+
const [themeName, setThemeName] = useAddonState(THEMES_ID, 'original');
53+
54+
const handleChoose = useCallback(
55+
(newThemeName: string) => {
56+
setThemeName(newThemeName);
57+
},
58+
[setThemeName]
59+
);
60+
61+
if (!active) {
62+
return <></>;
63+
}
64+
65+
return (
66+
<Wrapper key={THEMES_ID} theme={themes.original}>
67+
{themeList.map(theme => (
68+
<ThemeButton
69+
active={themeName === theme.name}
70+
key={theme.name}
71+
onChoose={handleChoose}
72+
theme={theme}
73+
/>
74+
))}
75+
</Wrapper>
76+
);
77+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useAddonState } from '@storybook/client-api';
2+
import { DecoratorFn } from '@storybook/react';
3+
import React from 'react';
4+
import { ThemeProvider } from 'styled-components';
5+
6+
import themes from '../../src/common/themes/index';
7+
import { THEMES_ID } from './constants';
8+
9+
export const withThemesProvider: DecoratorFn = story => {
10+
const [themeName] = useAddonState(THEMES_ID, 'original');
11+
12+
return (
13+
<ThemeProvider theme={themes[themeName] ?? themes.original}>
14+
{story()}
15+
</ThemeProvider>
16+
);
17+
};

.storybook/theme-picker/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const THEMES_ID = 'storybook/themes';

.storybook/theme-picker/register.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import addons, { makeDecorator, types } from '@storybook/addons';
2+
import { THEMES_ID } from './constants';
3+
import { ThemeList } from './ThemeList';
4+
5+
addons.register(THEMES_ID, () => {
6+
addons.addPanel(`${THEMES_ID}/panel`, {
7+
title: 'Themes',
8+
type: types.PANEL,
9+
render: ThemeList
10+
});
11+
});
12+
13+
export default makeDecorator({
14+
name: 'withThemesProvider',
15+
parameterName: 'theme',
16+
wrapper: (getStory, context) => getStory(context)
17+
});

.storybook/webpack.config.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)