- 🧑💻 无需 Codepen 等第三方服务即可使用代码
- 👥 与他人分享示例
- 🐛 与他人分享错误重现链接
- 🧱 检查组件如何协同工作
- 支持 Typescript
入门指南
1. 安装插件
yarn add -D storybook-addon-live-examples
# npm install --save-dev storybook-addon-live-examples
2. 在 main.js 中注册插件
module.exports = {
addons: ['storybook-addon-live-examples'],
};
3. 在 preview.js 中设置插件(可选步骤)
import { addons } from '@storybook/addons';
import { LIVE_EXAMPLES_ADDON_ID } from 'storybook-addon-live-examples';
import theme from 'prism-react-renderer/themes/github';
import AllComponents from '../packages';
addons.setConfig({
[LIVE_EXAMPLES_ADDON_ID]: {
// custom theme from prism-react-renderer (optional)
editorTheme: theme,
// internationalization (optional)
copyText: ['Copy', 'Copied'],
expandText: ['Show code', 'Hide code'],
shareText: ['Share', 'Shared'],
// scope (globally accessible components & functions) (optional)
scope: {
...AllComponents,
someFunction: () => 42
},
},
});
4. 配置 webpack(仅适用于 Storybook 7)
const { patchWebpackConfig } = require('storybook-addon-live-examples/dist/cjs/utils');
module.exports = {
webpackFinal: (config) => {
patchWebpackConfig(config);
return config;
}
};
使用方法
CSF
实时示例将取代默认的 addon-docs 画布进行渲染。
您可以通过参数自定义示例
export default {
title: 'Components/Button',
parameters: {
scope: {
scopeValue,
},
}
};
const scopeValue = 42;
export const Primary = () => <button>{scopeValue}</button>;
Primary.parameters = {
expanded: true
};
export const Secondary = () => <button>{scopeValue}</button>;
注意: 安装插件后,您很可能会遇到错误。不要惊慌,只需将故事中使用的所有变量传递给 scope
MDX
在基于 MDX 的故事中,您可以使用纯 markdown 编写代码示例。
只需将代码放在三引号内即可
|```tsx live
|<h4>Wow, so simple</h4>
|```
或者渲染自定义画布
// Import custom Canvas from addon
import { Canvas } from 'storybook-addon-live-examples';
<Canvas live={true} scope={{ value: 42 }}>
<h4>Wow, so simple, {value}</h4>
</Canvas>
或者直接使用 Example
import { Example } from 'storybook-addon-live-examples';
<Example live={true} code={`<h4>Wow, so simple</h4>`} />
CSF 与 MDX 结合
// Button.stories.js
import mdx from './Button.mdx';
export default {
title: 'Components/Button',
parameters: {
docs: {
page: mdx,
},
},
};
const scopeValue = 42;
export const Primary = () => <button>{scopeValue}</button>;
Primary.parameters = {
scope: {
scopeValue,
},
};
// Button.mdx
import { ArgsTable, Story } from '@storybook/addon-docs';
import { Button } from './Button';
# Button
<ArgsTable of={Button} />
<Story id='components-button--primary' />
Example props
您可以使用 props 或 metastring 自定义示例的显示
live
|```tsx live
|<span>This example can be edited</span>
|```
<span>This example can be edited</span>
expanded
|```tsx live expanded
|<span>This example will be rendered with expanded code sources</span>
|```
<span>This example will be rendered with expanded code sources</span>
复杂示例
render(() => {
const [counter, setCounter] = React.useState(0);
return (
<>
<h2>Super live counter: {counter}</h2>
<button type='button' onClick={() => setCounter((c) => c + 1)}>
Increment
</button>
</>
);
});
Scope
Storybook-addon-live-examples 内部使用了 react-live。
Scope 允许您将一些全局变量传递给代码示例。默认情况下,它只注入 React,这意味着您可以在这样的代码中使用它
render(() => {
// ↓↓↓↓↓
const [counter, setCounter] = React.useState(0);
return counter;
}
- 通过 props 将您自己的组件传递给 scope
import { Canvas } from 'storybook-addon-live-examples';
import MyComponent from '../packages/my-component';
<Canvas live={true} scope={{ MyComponent }}>
<MyComponent>Amazing</MyComponent>
</Canvas>
- 全局设置 scope
这是为整个项目一次性设置 scope 的最简单方法
//.storybook/manager.js
import { addons } from '@storybook/addons';
import { LIVE_EXAMPLES_ADDON_ID } from 'storybook-addon-live-examples';
addons.setConfig({
[LIVE_EXAMPLES_ADDON_ID]: {
scope: {
MyComponent,
},
},
});
<MyComponent>Now, you can use MyComponent in all examples</MyComponent>
- 在 monorepo 中设置 scope
这是一个如何将所有使用的组件和辅助函数添加到 scope 的示例。
// .storybook/scope.ts
import { ComponentType } from 'react';
import * as icons from 'some-icons-pack';
import * as knobs from '@storybook/addon-knobs';
// packages/{componentName}/index.ts
const req = require.context('../packages', true, /^\.\/(.*)\/index.ts$/);
const components = req.keys().reduce((acc: Record<string, ComponentType>, key) => {
Object.entries(req(key)).forEach(([componentName, component]: [string, any]) => {
acc[componentName] = component;
});
return acc;
}, {});
export default {
...components,
...icons,
...knobs,
};
// .storybook/manager.js
import scope from './scope';
addons.setConfig({
[LIVE_EXAMPLES_ADDON_ID]: {
scope,
},
});