Storybook Addon Themes
深受 @storybook/addon-backgrounds 启发。
这个 Storybook 主题装饰器可用于在 Storybook 预览中添加自定义 HTML 类或多个类。
兼容性
此版本与 storybook 版本 6.0.x
兼容。
安装
npm i -D storybook-addon-themes
开始使用
然后将其添加到 storybook 配置目录中的 main.js
文件中,以激活该插件
module.exports = {
addons: [
// Maybe other addons here...
'storybook-addon-themes'
// Or here...
],
};
更多信息请参阅storybook 文档。
参数
themes
参数接受一个 Theme
对象数组。
每个 Theme
是一个具有以下属性的对象
name
(string
): 主题名称class
(string | string[]
- 可选): 与主题相关的 HTML 类或类数组color
(string
): 主题选择器中徽章的颜色default
[已弃用] (boolean
- 可选): 是否默认选择该主题?
themes
参数也接受一个具有以下属性的对象
default
(string
- 可选): 默认选择的主题名称list
(Theme[]
- 必填): 主题列表clearable
(boolean
- 可选 - 默认为true
): 用户是否可以清除选定的主题?disable
(boolean
- 可选): 为某个故事禁用插件Decorator
(Component
- 可选): 用作装饰器组件的组件 (更多信息请参见下方)onChange
((themeName: Theme) => void
- 可选): 主题更改时执行的回调函数target
(string
- 可选): 使用document.querySelector()
选择要应用类的目标元素。默认为body
,如果要应用于documentElement
则为root
。
配置
全局配置
您可以在 storybook 的 preview.js
文件中全局配置主题
export const parameters = {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: 'theme-twt', color: '#00aced' },
{ name: 'facebook', class: 'theme-fb', color: '#3b5998' }
],
},
};
为了向后兼容,default
(boolean
) 也可以直接在 Theme
对象上设置。**此方式已弃用**,因为它需要重新定义所有 Theme
对象,导致更改默认主题变得困难。
// deprecated
export const parameters = {
themes: [
{ name: 'twitter', class: 'theme-twt', color: '#00aced', default: true },
{ name: 'facebook', class: 'theme-fb', color: '#3b5998' }
],
};
更多信息请参阅storybook 文档。
在故事中 (组件故事格式)
或者像这样在您的故事文件中配置主题
export default {
title: 'CSF|Button',
component: Button,
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
如果您只想为特定故事激活插件或覆盖主题,您可以这样写
export default {
title: 'CSF|Button',
component: Button,
};
export const withText = () => <Button onClick={action('clicked')}>Hello Button</Button>;
withText.story = {
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
在故事中 (StoriesOf API)
或者使用旧的 StoriesOf API
import { storiesOf } from '@storybook/react'; // <- or your storybook framework
storiesOf('StoriesOf|Button', module)
.addParameters({
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
})
.add('with text', () => <button>Click me</button>);
对于单个故事
import { storiesOf } from '@storybook/react';
storiesOf('StoriesOf|Button', module)
.add('with text', () => <button>Click me</button>, {
themes: {
list: [
{ name: 'red', class: 'theme-red', color: 'rgba(255, 0, 0)' },
],
},
});
覆盖单个属性
您也可以只覆盖 themes 参数中的单个键,例如为单个故事设置不同的默认值
export default {
title: 'CSF|Button',
component: Button,
};
export const withText = () => <Button onClick={action('clicked')}>Hello Button</Button>;
withText.story = {
parameters: {
themes: {
default: 'facebook',
},
},
};
结合装饰器使用
默认情况下,类将被添加到 body
元素或通过 target
配置的元素。
但在这种情况下,您的主题将不会被其他插件(例如 @storybook/addon-storyshots)看到。
为了解决这个问题,您可以在您的故事中添加 withThemes
装饰器。
但是装饰器方法并非适用于所有框架
支持的框架列表请参见此处。
全局配置
在 preview.js
文件中全局设置装饰器
import { addDecorator } from '@storybook/react'; // <- or your storybook framework
import { withThemes } from 'storybook-addon-themes/react'; // <- or your storybook framework
addDecorator(withThemes);
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
};
在故事中 (组件故事格式)
或者在您的故事文件中(适用于该文件中的所有故事)
export default {
title: 'CSF|Button',
component: Button,
decorators: [ withThemes ],
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
或者仅用于特定故事
export const withText = () => <Button onClick={action('clicked')}>Hello Button</Button>;
withText.story = {
decorators: [ withThemes ],
parameters: {
themes: {
default: 'twitter',
list: [
{ name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
{ name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
],
},
},
};
在故事中 (StoriesOf API)
或者使用旧的 StoriesOf API
import { storiesOf } from '@storybook/react'; // <- or your storybook framework
import { withThemes } from 'storybook-addon-themes/react';
storiesOf('StoriesOf|Button', module)
.addDecorator(withThemes)
.add('with text', () => <button>Click me</button>);
自定义装饰器
通用
您可以在 theme
参数中使用 Decorator
选项提供一个用作装饰器的组件。
装饰器将获得以下属性
theme
: 选定的主题,如果未选择任何主题则为undefined
。themes
: 作为theme
参数的list
选项提供的所有主题列表。themeClasses
: 选定主题的格式化主题类(如果选定主题存在class
选项)。themeName
: 选定主题的名称(如果未选择任何主题则等于none
)。
不要忘记使用 children
prop (React/HTML) 或 <slot></slot>
元素 (Vue/Svelte) 渲染故事。
HTML 示例
为了管理与 HTML storybook 的响应性,您的装饰器必须返回一个包含两个元素的数组
- 要在故事中显示的 HTML 元素
- 一个更新回调函数,当主题更改时将被调用。与装饰器一样,回调函数将接收相同的 props(不包含
children
)。
使用 CSS 文件更改主题的自定义装饰器示例
function getOrCreate(id) {
const elementOnDom = document.getElementById(id);
if (elementOnDom) {
return elementOnDom;
}
const element = document.createElement('link');
element.setAttribute('id', id);
element.setAttribute('rel', 'stylesheet');
return element;
}
function Decorator(props) {
const { children } = props;
function setStyles({ theme, themeName }) {
const link = getOrCreate('theme-stylesheet');
if (!theme) {
link.parentNode && link.parentNode.removeChild(link);
} else {
link.href = themeName === 'facebook' ? 'Button-fb.css' : 'Button-twt.css';
children.appendChild(link);
}
}
setStyles(props);
return [children, setStyles];
}
React 示例
与上面相同的 React 示例
function Decorator(props) {
const { children, themeName } = props;
return (
<>
{children}
{themeName === 'twitter' && <link rel="stylesheet" href="twitter.css"/>}
{themeName === 'facebook' && <link rel="stylesheet" href="facebook.css"/>}
</>
);
};
框架支持列表
React | React Native | Vue | Angular | Polymer | Mithril | HTML | Marko | Svelte | Riot | Ember | Preact | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
不使用装饰器时的用法 | + | + | + | + | + | + | + | + | + | + | + | |
结合装饰器使用 | + | + | + | + |