Storybook & Addons
Start writing your stories
What is storybook ?
- create components independently
Setup Guide
.storybook
main.js
preview-head.html
(required)
preview-body.html
preview.js
保留字
main.js
module.exports = {
stories: ['../stories/**/*.stories.jsx'],
addons: [
'@storybook/addon-actions/register',
'@storybook/addon-notes/register',
],
webpackFinal: (config) => {
/* Add your custom webpack config */
return config;
},
};
{
test: /\.(mjs|jsx?)$/,
use: [ { loader: 'babel-loader', options: [Object] } ],
include: [ '/Users/travor/Desktop/rytass/NTCH-Official' ],
exclude: [ '/Users/travor/Desktop/rytass/NTCH-Official/node_modules' ]
}
{
test: /\.md$/,
use: [
{
loader: '/node_modules/raw-loader/dist/cjs.js'
}
]
}
{
test: /\.css$/,
sideEffects: true,
use: [
'/Users/travor/Desktop/rytass/NTCH-Official/node_modules/style-loader/dist/cjs.js',
{
loader: '/node_modules/css-loader/dist/cjs.js',
options: [Object]
},
{
loader: '/node_modules/postcss-loader/src/index.js',
options: [Object]
}
]
}
{
test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/,
loader: '/node_modules/@storybook/core/node_modules/file-loader/dist/cjs.js',
query: { name: 'static/media/[name].[hash:8].[ext]' }
}
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
loader: '/node_modules/@storybook/core/node_modules/url-loader/dist/cjs.js',
query: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' }
}
Default webpack module rules
main.js
const webpack = require('webpack');
const COLORS = require('../colors.json');
module.exports = {
stories: ['../stories/**/*.stories.jsx'],
addons: [
'@storybook/addon-actions/register',
'@storybook/addon-notes/register',
],
webpackFinal: (config) => {
config.plugins.push(new webpack.DefinePlugin({
Colors: JSON.stringify(COLORS),
}));
return config;
},
};
main.js
const customWebpackConfig = require('../client/webpack.config.js');
module.exports = {
stories: ['../stories/**/*.stories.jsx'],
addons: [
'@storybook/addon-actions/register',
'@storybook/addon-notes/register',
],
webpackFinal: (config) => {
return {
...config,
plugins: [
...config.plugins,
...customWebpackConfig.plugins,
],
module: {
...config.module,
rules: [
...config.module.rules,
...customWebpackConfig.module.rules,
]
}
};
},
};
preview.js
放 global decorator 的地方
import React from 'react';
import { Provider } from 'react-redux';
import {
addDecorator,
} from '@storybook/react';
import {
BrowserRouter,
} from 'react-router-dom';
import '../static/main.css';
import './canvas.css';
import store from '../store';
import 'moment/locale/zh-tw';
addDecorator(storyFn => (
<Provider store={store}>
<BrowserRouter basename="/">
{storyFn()}
</BrowserRouter>
</Provider>
));
from NTCH
import {
addParameters,
addDecorator,
} from '@storybook/client-api';
import {
INITIAL_VIEWPORTS,
} from '@storybook/addon-viewport';
import {
jsxDecorator,
} from 'storybook-addon-jsx';
addDecorator(jsxDecorator);
addParameters({
viewport: {
viewPorts: INITIAL_VIEWPORTS,
},
});
from NTCH-Official
<style type="text/css">
* {
box-sizing: border-box;
font-family: '微軟正黑體', sans-serif;
outline: none;
}
html {
width: 100vw;
height: 100vh;
}
body {
width: 100vw;
min-height: 100vh;
position: relative;
}
</style>
index.html
preview-head.js
<link href='//api.tiles.mapbox.com/mapbox-gl-js/v1.6.1/mapbox-gl.css' rel='stylesheet' />
<style type="text/css">
...
</style>
custom html <head>
preview-body.js
<div id="portal-container" />
custom html <body>
Addons
My Suggestions
log action
customize props
desktop/mobile viewport
description/notes
accessibility test
preview jsx code
Writing Stories
import React from 'react';
import Button from '../SomeWhere/Button';
export default {
title: 'Form/Button',
};
const defaultProps = {
disabled: false,
variant: 'TEXT',
inverse: false,
};
export const Default = () => (
<Button
{...defaultProps}>
預設按鈕
</Button>
);
.storybook
main.js
stories
Modal.stories.js
Button.stories.js
.storybook
main.js
stories
import React from 'react';
import Button from '../SomeWhere/Button';
import note from './Button.stories.md';
export default {
title: 'Form/Button',
parameters: {
notes: { markdown: note },
},
};
const defaultProps = {
disabled: false,
variant: 'TEXT',
inverse: false,
};
export const Default = () => (
<Button
{...defaultProps}>
預設按鈕
</Button>
);
Button.stories.md
Button.stories.js
Modal.stories.js
.storybook
main.js
stories
import React from 'react';
import Button from '../SomeWhere/Button';
import note from './Button.stories.md';
export default {
title: 'Form/Button',
parameters: {
notes: { markdown: note },
},
};
const defaultProps = {
disabled: false,
variant: 'TEXT',
inverse: false,
};
export const Default = () => (
<Button
{...defaultProps}>
預設按鈕
</Button>
);
export const Disabled = () => (
<Button
{...defaultProps}
disabled>
不可按
</Button>
);
Button.stories.md
Modal.stories.js
Button.stories.js
.storybook
main.js
stories
Button.stories.js
Modal.stories.js
import React from 'react';
import { withKnobs, boolean, select } from '@storybook/addon-knobs';
import Button from '../SomeWhere/Button';
import note from './Button.stories.md';
export default {
title: 'Form/Button',
parameters: {
notes: { markdown: note },
},
decorators: [withKnobs],
};
const defaultProps = {
disabled: false,
variant: 'TEXT',
inverse: false,
};
const variantOptions = ['TEXT', 'MAIN'];
export const Default = () => {
const knobs = {
disabled: boolean('disabled', defaultProps.disabled),
variant: select('variant', variantOptions, defaultProps.variant),
inverse: boolean('inverse', defaultProps.inverse),
};
return (
<Button
{...defaultProps}
{...knobs}>
預設按鈕
</Button>
);
};
export const Disabled = () => (
<Button
{...defaultProps}
disabled>
不可按
</Button>
);
Button.stories.md
.storybook
main.js
stories
Button.stories.js
Modal.stories.js
import React from 'react';
import { withKnobs, boolean, select } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import Button from '../SomeWhere/Button';
import note from './Button.stories.md';
export default {
title: 'Form/Button',
parameters: {
notes: { markdown: note },
},
decorators: [withKnobs],
};
const defaultProps = {
disabled: false,
variant: 'TEXT',
inverse: false,
onClick: action('clicked'),
};
const variantOptions = ['TEXT', 'MAIN'];
export const Default = () => {
const knobs = {
disabled: boolean('disabled', defaultProps.disabled),
variant: select('variant', variantOptions, defaultProps.variant),
inverse: boolean('inverse', defaultProps.inverse),
};
return (
<Button
{...defaultProps}
{...knobs}>
預設按鈕
</Button>
);
};
export const Disabled = () => (
<Button
{...defaultProps}
disabled>
不可按
</Button>
);
Button.stories.md
.storybook
main.js
stories
Button.stories.js
Modal.stories.js
import React from 'react';
import { withKnobs, boolean, select } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import { withA11y } from '@storybook/addon-a11y';
import Button from '../SomeWhere/Button';
import note from './Button.stories.md';
export default {
title: 'Form/Button',
parameters: {
notes: { markdown: note },
},
decorators: [withKnobs, withA11y],
};
const defaultProps = {
disabled: false,
variant: 'TEXT',
inverse: false,
onClick: action('clicked'),
};
const variantOptions = ['TEXT', 'MAIN'];
export const Default = () => {
const knobs = {
disabled: boolean('disabled', defaultProps.disabled),
variant: select('variant', variantOptions, defaultProps.variant),
inverse: boolean('inverse', defaultProps.inverse),
};
return (
<Button
{...defaultProps}
{...knobs}>
預設按鈕
</Button>
);
};
export const Disabled = () => (
<Button
{...defaultProps}
disabled>
不可按
</Button>
);
Button.stories.md
.storybook
main.js
stories
Button.stories.js
Modal.stories.js
import { addParameters, addDecorator } from '@storybook/client-api';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import { jsxDecorator } from 'storybook-addon-jsx';
addDecorator(jsxDecorator);
addParameters({
viewport: {
viewPorts: INITIAL_VIEWPORTS,
},
});
Button.stories.md
preview.js
Thanks
storybook and addons
By Travor Lee
storybook and addons
- 250