Storybook 主题插件
很大程度上受到 @storybook/addon-backgrounds 的启发。
此 Storybook 主题装饰器可用于在 Storybook 中向预览添加自定义 HTML 类或多个类。
兼容性
此版本与 storybook 版本 6.0.x
兼容。
安装
npm i -D storybook-addon-themes
入门
然后通过将其添加到 storybook 的 main.js
文件(位于 Storybook 配置目录中)来激活插件
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' }
],
},
};
为了向后兼容,也可以直接在 Theme
对象上设置 default
(boolean
)。此功能已弃用,因为由于需要重新定义所有 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
属性(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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
不使用装饰器 | + | + | + | + | + | + | + | + | + | + | + | |
与装饰器一起使用 | + | + | + | + |