参加直播会议:周四,美国东部时间上午11点,Storybook 9发布 & AMA

旨在简化 Web Components 与 Storybook 集成的助手工具。

在 Github 上查看

适用于 Web Components 的 Storybook 助手

[!WARNING] 此项目已迁移,现在可以在这里找到

这些助手旨在简化 Web Components 与 Storybook 的集成。

这个助手库通过多种方式为开发者提供更好的 Storybook 和 Web Components 使用体验

  1. 利用类型提供更优的控件
  2. 防止 HTML 属性、JS 特性、插槽和 CSS Shadow Parts 名称冲突
  3. 提供带有 HTML 属性、JS 特性、CSS 自定义属性和 CSS Shadow Parts 绑定的模板。
  4. 提供模板中控件与组件属性的双向绑定,帮助控件值与组件保持同步

安装前

  1. 遵循Storybook 文档中的安装步骤
  2. 将您的自定义元素清单加载到 Storybook 的 preview.js 文件中
import { setCustomElementsManifest } from "@storybook/web-components";
import customElements from "./path/to/custom-elements.json";

setCustomElementsManifest(customElements);
  1. 将展开的控件添加到 preview.js 文件中的配置中
export const parameters = {
  ...
  controls: {
    expanded: true,
    ...
  },
}

安装

npm i -D wc-storybook-helpers

设置

将 storybook 助手导入到您的 story 中

import { getWcStorybookHelpers } from "wc-storybook-helpers";

将元素的标签名称传递给 Storybook 助手函数。

const { events, args, argTypes, template } =
  getWcStorybookHelpers("my-element");

argTypesevents 添加到您的 story 配置中

import type { Meta, StoryObj } from "@storybook/web-components";

const meta: Meta<MyElement> = {
  title: "Components/My Element",
  component: "my-element",
  args,
  argTypes,
  parameters: {
    actions: {
      handles: events,
    },
  },
};
export default meta;

将模板添加到您的 story 模板中,并将 story 的 args 传递给 template 函数(这是一个可选参数,但要使参数正常工作则必需)

/**
 * create Story type that will provide autocomplete and docs for `args`,
 * but also allow for namespaced args like CSS Shadow Parts and Slots
 */
type Story = StoryObj<MyElement & typeof args>;

export const Default: Story = {
  render: (args) => template(args),
  args: {},
};

argTypes

根据自定义元素清单中的数据,助手将为您的参数应用适当的描述和控件类型。

控件类型

默认的控件类型并非总是最有帮助。助手将利用您的类型来尝试识别适合您控件的输入和选项。

例如,如果您的组件有一个名为 variant 的属性,带有预定义的值,助手会将其转换为一个选择框,该选择框会预先填充适当的值,并选中默认值。

screenshot of storybook control panel with a select input expanded displaying options

带命名空间的控件

默认实现的一个挑战是,如果存在多个同名属性,它们会被覆盖。例如,如果有一个名为 label 的属性和一个名为 label 的插槽,只会显示其中一个。为了确保每个参数都能正确显示,CSS Shadow Part 和 Slot 参数将分别被加上后缀 -part-slot。CSS 自定义属性则不会被加上后缀,因为它们已经有唯一的属性值,而属性和特性将依赖于驼峰命名的特性名。

参考名称将与控件的描述一起记录。

screenshot of storybook control panel with arrow pointing to the "arg ref" label

然后可以使用该参考名称将默认值绑定到模板。

const DefaultTemplate = (args: any) => template(args);

export const Default: any = DefaultTemplate.bind({});
Default.args = {
  docsHint: "Some other value than the default",
};
export const Default: Story = {
  render: (args) => template(args),
  args: {
    docsHint: "Some other value than the default",
  },
};

已废弃的控件

如果您在 jsDoc 描述中使用 @deprecated 标签,这些信息也会显示在描述中。

/**
 * @deprecated replaced by `docs-hint`
 * Copy for the read the docs hint.
 */
@property({ attribute: "old-docs-hint", reflect: true })
oldDocsHint = "Click on the Vite and Lit logos to learn more";

screenshot of storybook control panel with "deprecated" label in the description

覆盖控件

如果您想更改任何控件,可以使用展开运算符(spread operator)轻松覆盖它,将更新的 argType 传入到助手的 argTypes 之后。

export default {
  title: "Components/My Element",
  component: "my-element",
  argTypes: {
    ...argTypes,
    docsHintAttr: {
      name: 'docs-hint',
      description: '...',
      defaultValue: '...',
      control: {
        type: '...',
      },
      table: {
        category: 'attributes',
        defaultValue: {
          summary: '...',
        },
        type: {
          summary: '`string`',
        },
      },
  },
  ...
};

事件

如果您想捕获组件输出的事件,可以在 story 配置的参数部分中进行映射。

注意: 只有当您的 CustomEventbubbles 选项设置为 true 时,它们才会被捕获(注意 - 默认为 true)。

export default {
  ...
  parameters: {
    actions: {
      handles: events,
    },
  },
};

如果您想将更多事件映射到您的 story 中,可以使用展开运算符(spread operator)扩展值。

export default {
  ...
  parameters: {
    actions: {
      handles: [...events, 'my-other-event'],
    },
  },
};

Actions(操作)选项卡中的事件

如果您在 actions(操作)选项卡中没有看到事件显示,可能有以下两个原因之一

  1. 您的事件未配置为冒泡
  2. 您的 Storybook 配置需要更新以包含 withActions decorator。
// preview.js
import { withActions } from '@storybook/addon-actions/decorator';

const preview: Preview = {
  parameters: {
    controls: {
      expanded: true,
      sort: 'alpha'
    },
  },
  decorators: [withActions],
};

模板

模板配置为自动将控件的 HTML 属性、JS 特性、CSS 自定义属性和 CSS Shadow Parts 映射到您的元素,并为组件属性提供双向数据绑定,以便与控件保持同步。

模板接受两个参数 - story 参数和插槽数据。您可以使用控件和 story 的 args 提供插槽数据,但如果您需要更精细的控制,可以在模板上使用 slot 参数,这将获得更多编辑器支持。

const SelectTemplate = (args: any) =>
  template(
    args,
    html`
      <span slot="label">My Select</span>
      <my-option>Option 1</my-option>
      <my-option>Option 2</my-option>
      <my-option>Option 3</my-option>
    `
  );

export const Default: any = SelectTemplate.bind({});
Default.args = {
  docsHint: "Some other value than the default",
};

扩展模板

组件模板可以插入到 story 的模板中,并带有额外的内容。

const FormTemplate = (args: any) => html`
  <form>
    ${template(
      args,
      html`
        <span slot="label">My Select</span>
        <my-option>Option 1</my-option>
        <my-option>Option 2</my-option>
        <my-option>Option 3</my-option>
      `
    )}

    <button>Submit</button>
  </form>
`;

模板还暴露了一个名为 component 的变量,它引用了自定义元素,这样您就可以使用自定义逻辑。

const ComponentTemplate = (args: any) => html`
  ${template(
    args,
    html`
      <span slot="label">My Select</span>
      <my-option value="1">Option 1</my-option>
      <my-option value="2">Option 2</my-option>
      <my-option value="3">Option 3</my-option>
    `
  )}
  <script>
    // set property values
    component.value = "2";

    // call component methods
    component.show();
  </script>
`;

使用插槽控件

如果您正在使用 template,使用控件面板的插槽非常直接。输入框已连接到相应的插槽,因此可以直接将富文本内容添加到输入框中,无需额外设置。

screenshot of storybook control panel with a select input expanded displaying options

使用 CSS Shadow Parts 控件

与插槽控件类似,template 使处理 CSS Shadow Parts 变得容易。模板已预先配置了适当的代码,用于将样式应用到组件的部分。您可以直接将样式应用于控件输入框。

screenshot of storybook control panel with a select input expanded displaying options

配置

助手包提供了一种方法,可以使用 setWcStorybookHelpersConfig 函数为您的 stories 设置全局配置。这可以添加到 .storybook/preview.js 文件中。

//preview.js
import { setWcStorybookHelpersConfig } from "wc-storybook-helpers";

setWcStorybookHelpersConfig({ ... });
setCustomElementsManifest(customElements);

助手可以接受以下选项

interface Options {
  /** hides the `arg ref` label on each control */
  hideArgRef?: boolean;
  /** sets the custom type reference in the Custom Elements Manifest */
  typeRef?: string;
  /** Adds a <script> tag where a `component` variable will reference the story's component */
  setComponentVariable: false,
  /** renders default values for attributes and CSS properties */
  renderDefaultValues: false,
}

隐藏“参数参考”

有时您可能想隐藏“参数参考”标签。您可以将 hideArgRef 设置为 true,这将从控件中移除该标签。

setWcStorybookHelpersConfig({ hideArgRef: true });

使用 typeRef 的自定义类型

团队通常会解析或创建自定义类型,并将其添加到自定义元素清单中以供其他工具使用(如果您还没有这样做,CEM Analyzer Expanded Types plugin 可以提供帮助)。可以使用 typeRef 将助手配置为使用这些类型,而不是清单中的默认类型。如果找不到自定义类型,将回退到默认类型。

setWcStorybookHelpersConfig({ typeRef: "expandedType" });

添加组件变量

每个使用 template 助手的 story 都包含一个选项,可以添加一个 script 标签,其中在 component 变量中引用自定义元素。setComponentVariable 选项会添加此 script 标签和变量。

setWcStorybookHelpersConfig({ setComponentVariable: true });

渲染默认属性值

如果一个 arg 值与默认值匹配,它将不会添加到组件中。要始终显示属性和 CSS 自定义属性的默认值,请启用 renderDefaultValues 设置

setWcStorybookHelpersConfig({ renderDefaultValues: true });