- 🧑💻 無需像 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>`} />
具有 MDX 的 CSF
// 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' />
範例屬性
您可以使用屬性或元字串自訂範例的顯示
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;
}
- 透過屬性將您自己的元件傳遞到 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
這是一個範例,說明如何將所有已使用的元件和 helpers 新增到 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,
},
});