Skip to content

Commit

Permalink
feat(storybook): Reimplement "Themes" add on with React95 style
Browse files Browse the repository at this point in the history
This also upgrades many dependencies, removes storybook-addon-styled-component-theme and configures babel in preparation for Storybook v7.
  • Loading branch information
WesSouza authored and arturbien committed Aug 4, 2022
1 parent 71a964e commit 2eac4e8
Show file tree
Hide file tree
Showing 20 changed files with 1,524 additions and 1,144 deletions.
73 changes: 58 additions & 15 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,24 +1,67 @@
{
"sourceType": "unambiguous",
"presets": [
[
"@babel/preset-env",
{
"modules": false
"shippedProposals": true,
"loose": true
}
],
"@babel/preset-react"
"@babel/preset-typescript"
],
"plugins": [
"babel-plugin-styled-components",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime"
],
"env": {
"test": {
"presets": ["@babel/preset-env"],
"plugins": [
["babel-plugin-styled-components", { "ssr": false, "displayName": false }]
]
}
}
}
"@babel/plugin-transform-shorthand-properties",
"@babel/plugin-transform-block-scoping",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose": true
}
],
[
"@babel/plugin-proposal-private-property-in-object",
{
"loose": true
}
],
[
"@babel/plugin-proposal-private-methods",
{
"loose": true
}
],
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-syntax-dynamic-import",
[
"@babel/plugin-proposal-object-rest-spread",
{
"loose": true,
"useBuiltIns": true
}
],
"@babel/plugin-transform-classes",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-parameters",
"@babel/plugin-transform-destructuring",
"@babel/plugin-transform-spread",
"@babel/plugin-transform-for-of",
"babel-plugin-macros",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
[
"babel-plugin-polyfill-corejs3",
{
"method": "usage-global",
"absoluteImports": "core-js",
"version": "3.24.1"
}
]
]
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { DecoratorFn } from '@storybook/react';
import React from 'react';
import { createGlobalStyle } from 'styled-components';

import styleReset from '../../src/common/styleReset';
// TODO is there a way to keep import paths consistent with what end user will get?
import ms_sans_serif from '../../src/assets/fonts/dist/ms_sans_serif.woff2';
import ms_sans_serif_bold from '../../src/assets/fonts/dist/ms_sans_serif_bold.woff2';
import styleReset from '../../src/common/styleReset';

const GlobalStyle = createGlobalStyle`
${styleReset}
Expand All @@ -25,9 +25,9 @@ const GlobalStyle = createGlobalStyle`
}
`;

export default storyFn => (
export const withGlobalStyle: DecoratorFn = story => (
<>
<GlobalStyle />
{storyFn()}
{story()}
</>
);
29 changes: 0 additions & 29 deletions .storybook/main.js

This file was deleted.

52 changes: 52 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { StorybookConfig } from '@storybook/react/types';
import type { PropItem } from 'react-docgen-typescript';

const path = require('path');

const storybookConfig: StorybookConfig = {
stories: ['../src/**/*.stories.@(tsx|mdx)'],
addons: [
{
name: '@storybook/addon-docs',
options: {
sourceLoaderOptions: {
injectStoryParameters: false
}
}
},
'@storybook/addon-storysource',
'./theme-picker/register.ts'
],
core: {
builder: 'webpack5'
},
features: {
babelModeV7: true,
storyStoreV7: true,
modernInlineRender: true,
postcss: false
},
typescript: {
check: false,
checkOptions: {},
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop: PropItem) =>
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true
}
},
webpackFinal: config => {
config.resolve = {
...config.resolve,
alias: {
...config.resolve?.alias,
react95: path.resolve(__dirname, '../src/index')
}
};

return config;
}
};

module.exports = storybookConfig;
File renamed without changes.
40 changes: 0 additions & 40 deletions .storybook/preview.js

This file was deleted.

9 changes: 9 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DecoratorFn, Parameters } from '@storybook/react';
import { withGlobalStyle } from './decorators/withGlobalStyle';
import { withThemesProvider } from './theme-picker/ThemeProvider';

export const decorators: DecoratorFn[] = [withGlobalStyle, withThemesProvider];

export const parameters: Parameters = {
layout: 'fullscreen'
};
26 changes: 26 additions & 0 deletions .storybook/theme-picker/ThemeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { useCallback } from 'react';
import { ThemeProvider } from 'styled-components';
import { Button } from '../../src/Button/Button';
import { Theme } from '../../src/types';

export function ThemeButton({
active,
onChoose,
theme
}: {
active: boolean;
onChoose: (themeName: string) => void;
theme: Theme;
}) {
const handleClick = useCallback(() => {
onChoose(theme.name);
}, []);

return (
<ThemeProvider theme={theme}>
<Button active={active} onClick={handleClick}>
{theme.name}
</Button>
</ThemeProvider>
);
}
77 changes: 77 additions & 0 deletions .storybook/theme-picker/ThemeList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useAddonState } from '@storybook/api';
import React, { useCallback } from 'react';
import styled from 'styled-components';

import themes from '../../src/common/themes';
import { Theme } from '../../src/types';
import { THEMES_ID } from './constants';
import { ThemeButton } from './ThemeButton';

const {
original,
rainyDay,
vaporTeal,
theSixtiesUSA,
olive,
tokyoDark,
rose,
plum,
matrix,
travel,
...otherThemes
} = themes;

const themeList = [
original,
rainyDay,
vaporTeal,
theSixtiesUSA,
olive,
tokyoDark,
rose,
plum,
matrix,
travel,
...Object.values(otherThemes)
];

type ThemesProps = {
active?: boolean;
};

const Wrapper = styled.div<{ theme: Theme }>`
display: grid;
padding: 1em;
gap: 1em;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
grid-template-rows: repeat(auto-fill, 40px);
background-color: ${({ theme }) => theme.material};
`;

export function ThemeList({ active }: ThemesProps) {
const [themeName, setThemeName] = useAddonState(THEMES_ID, 'original');

const handleChoose = useCallback(
(newThemeName: string) => {
setThemeName(newThemeName);
},
[setThemeName]
);

if (!active) {
return <></>;
}

return (
<Wrapper key={THEMES_ID} theme={themes.original}>
{themeList.map(theme => (
<ThemeButton
active={themeName === theme.name}
key={theme.name}
onChoose={handleChoose}
theme={theme}
/>
))}
</Wrapper>
);
}
17 changes: 17 additions & 0 deletions .storybook/theme-picker/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useAddonState } from '@storybook/client-api';
import { DecoratorFn } from '@storybook/react';
import React from 'react';
import { ThemeProvider } from 'styled-components';

import themes from '../../src/common/themes/index';
import { THEMES_ID } from './constants';

export const withThemesProvider: DecoratorFn = story => {
const [themeName] = useAddonState(THEMES_ID, 'original');

return (
<ThemeProvider theme={themes[themeName] ?? themes.original}>
{story()}
</ThemeProvider>
);
};
1 change: 1 addition & 0 deletions .storybook/theme-picker/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const THEMES_ID = 'storybook/themes';
17 changes: 17 additions & 0 deletions .storybook/theme-picker/register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import addons, { makeDecorator, types } from '@storybook/addons';
import { THEMES_ID } from './constants';
import { ThemeList } from './ThemeList';

addons.register(THEMES_ID, () => {
addons.addPanel(`${THEMES_ID}/panel`, {
title: 'Themes',
type: types.PANEL,
render: ThemeList
});
});

export default makeDecorator({
name: 'withThemesProvider',
parameterName: 'theme',
wrapper: (getStory, context) => getStory(context)
});
12 changes: 0 additions & 12 deletions .storybook/webpack.config.js

This file was deleted.

Loading

0 comments on commit 2eac4e8

Please sign in to comment.