加入直播会话:周四,美国东部时间上午 11 点,Storybook 9 发布和问答

插件开发工具包

Storybook 插件开发工具包

在 Github 上查看

npm version npm

Storybook ADK

此软件包中最初引入的一些功能已通过 Storybook API 提供。请优先考虑 https://github.com/storybookjs/addon-kit,这是一个使用最新插件 API 的简单 Github 仓库模板。

此工具包为 Storybook API 提供额外的中间件,可用于基于此创建插件。

简化插件创建。通过通道保持插件数据同步。提供智能块来创建插件 UI。提供简单的 API 用于注册插件和创建装饰器。它是快速构建您定制的全新出色插件的基础。

特性

  • 隐藏了通过通道通信和在切换故事时数据同步的所有复杂问题。
  • 通过高阶组件(HOC)将您的插件组件连接到插件存储,并且仅在数据更改时更新它
  • 将插件存储数据分为全局和本地。跟踪故事浏览,以便在管理器和预览端同时切换相应的本地数据
  • 保留不可变的初始数据以及您通过 actions 修改的可覆盖数据
  • 提供类似 Redux 的方法通过 selectors 和 actions 处理您的插件存储(但不用担心,默认 action 只是简单地覆盖您的数据)
  • 允许将任意数量的面板、按钮和任何其他插件类型连接到单个插件存储
  • 提供 UI 容器,该容器自动反映插件面板的纵横比。对于创建响应垂直和水平面板位置的插件 UI 非常有用
  • 包含 Typescript 定义

用法

npm i --save @storybook/addon-devkit
import {
  register,
  createDecorator,
  setParameters,
  setConfig,
  Layout,
  Block,
} from '@storybook/addon-devkit'

API

注册管理器端插件面板

用于注册插件 UI 并将其连接到插件存储的高阶组件(HOC)。

// in your addon `register.js`
import { register } from '@storybook/addon-devkit'

register(
  {
    ...selectors,
  },
  ({ global, local }) => ({
    ...globalActions,
    ...localActions,
  })
)(AddonPanelUI);


其中 selectors 是一个包含类似函数的对象

{
  deepData: store => store.path.to.deep.store.data,
}

actions 可以是“global”(全局)和“local”(本地)。全局 actions 影响存储的全局部分,而本地 actions 仅影响与当前故事相关的数据。


({ global, local }) => ({
    // action to manipulate with common data
    increase: global(store => ({
      ...store,
      index: store.index + 1,
    })),
    // action to manipulate with current story data
    // usage: setBackground('#ff66cc')
    setBackground: local((store, color) => ({
      ...store,
      backgroundColor: color,
    })),
    // action to override data
    // usage: update({...newData})
    update: global(),
  })

AddonPanelUI - 是您选择相应选项卡时出现在插件面板上的组件

注意:该 HOC 会自动跟踪插件的 active 状态,并且仅在必要时显示它

注册 HOC 会将以下 props 传递给 AddonPanelUI 组件

<AddonPanelUI
  {...actions} // generated actions
  {...selectors} // selected pieces of store
  api={api} // storybook API object
  active={active} // you don't need to do anything with it
  store={store} // entire store. prefer to use selectors
  kind={kind} // current story kind
  story={story} // current story
  ADDON_ID={ADDON_ID}
  PANEL_ID={PANEL_ID}
  PANEL_Title={PANEL_Title} // Title on the addon panel
  rect={rect} // dimensions of panel area
/>

一旦您通过 actions 更改存储,AddonPanelUIstoryDecorator 都将使用新数据重新渲染。

同样,如果数据来自故事 - 它将被更新

初始化后,HOC 将等待来自故事的初始数据,只有在此之后才会渲染 UI

创建故事端装饰器

用于创建装饰器并将其连接到插件存储的高阶组件(HOC)。

// in your addon `decorator.js`
import { createDecorator } from '@storybook/addon-devkit'

export const withMyAddon = createDecorator({
    ...selectors,
  },
  ({ global, local }) => ({
    ...globalActions,
    ...localActions,
  })
)(DecoratorUI, { isGlobal });

这样你就可以这样使用你的装饰器了

// stories.js

import React from 'react';
import { storiesOf, addDecorator, addParameters } from '@storybook/react';
import { withMyAddon, myAddonParams } from 'my-addon';

// add decorator globally
addDecorator(withMyAddon({ ...initData }))
addParameters(myAddonParams({ ...globalParams }))

storiesOf('My UI Kit', module)
  // ...or add decorator locally
  .addDecorator(withMyAddon({ ...initData }))
  .add(
    'Awesome',
    () => <Button>Make Awesome</Button>,
    myAddonParams({ ...localParams })
  )

DecoratorUI 可能看起来像这样


const DecoratorUI = ({ context, getStory, selectedData }) => (
  <div>
    <h1>Title: {selectedData}</h1>
    {getStory(context)}
  </div>
);

isGlobal = true 时,装饰器会将所有传递的数据视为全局数据

注意:插件参数将与初始数据合并,并可用于装饰器和面板的 selectors

将参数传递给插件

创建用于将参数传递给插件的函数

参见上面的用法

import { setParameters } from '@storybook/addon-devkit'

export const myAddonParams = setParameters()

插件配置

为了创建插件,您需要指定一些独特的参数,例如事件名称、插件标题、参数键等。它们在管理器和预览端应该相同。如果您不指定它们,addon-devkit 将使用默认值。要指定自己的,请使用 setConfig

import { setConfig } from '@storybook/addon-devkit';

setConfig({
  addId: 'dev_adk',
  panelTitle: 'ADK DEV'
});

您应该在使用 registersetParameterscreateDecorator 之前运行它

注意:不要忘记在管理器和预览端都使用相同的参数调用 setConfig

插件面板 UI 组件

用于在面板位于底部位置时按行组织 UI,在右侧时按列组织 UI 的组件

import { Layout, Block, register } from '@storybook/addon-devkit';
import { styled } from '@storybook/theming';
import './config'

const LayoutBlock = styled(Layout)`
  ...styles
`

const AddonBlock = styled(Block)`
  ...styles
`

const AddonPanel = () => (
  <LayoutBlock>
    <AddonBlock size={200}>
      {UI1}
    </AddonBlock>
    <AddonBlock>
      {UI2}
    </AddonBlock>
    <AddonBlock>
      {UI3}
    </AddonBlock>
  </LayoutBlock>
)

register()(AddonPanel)

<Layout> 在底部时具有 display: flexflex-direction: row,在右侧时为 flex-direction: column

您可以指定 <Block> 的大小。在水平布局中,它将是宽度;在垂直布局中,则是元素的高度。

否则它将具有 flex-grow: 1

致谢

创建者
  • kylegach
    kylegach
  • tooppaaa
    tooppaaa
  • ndelangen
    ndelangen
  • shilman
    shilman
  • alexandrebodin
    alexandrebodin
  • hypnosphi
    hypnosphi
标签