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()
選取的目標元素,要將類別套用至該元素。如果類別應套用至documentElement
,則預設為body
,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 元素
- 當主題變更時將呼叫的更新回呼。與裝飾器類似,回呼將接收相同的屬性(沒有
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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
不使用裝飾器的用法 | + | + | + | + | + | + | + | + | + | + | + | |
搭配裝飾器使用 | + | + | + | + |