构建 UI 组件
在第 3 章中,我们将从最流行的组件浏览器 Storybook 开始,设置必要的设计系统工具。本指南的目标是向您展示专业团队如何构建设计系统,因此我们还将关注更精细的细节,例如代码卫生、节省时间的 Storybook 插件和目录结构。
代码格式化和代码检查以保证代码卫生
设计系统是协作性的,因此修复语法和标准化格式的工具可以提高贡献质量。与手动检查代码相比,使用工具强制执行代码一致性所需的工作量要少得多,这对足智多谋的设计系统作者来说是一个好处。
在本教程中,我们将使用 VSCode 作为我们的编辑器,但您可以将相同的原则应用于其他现代编辑器,如 Atom、Sublime 或 IntelliJ。
为了确保一致的代码风格,我们将使用 Prettier。这个代码格式化工具被广泛使用,并支持多种语言。它可以与大多数编辑器无缝集成,包括我们正在使用的编辑器,并且在我们初始化设计系统时,它已包含在我们之前在本指南中克隆的模板中。如果您是 Prettier 的初次用户,您可能需要为您的编辑器配置它。对于 VSCode,请安装 Prettier 插件。
如果您尚未启用“保存时格式化”editor.formatOnSave
,请启用它。安装 Prettier 后,您应该会发现它会在您每次保存文件时自动格式化您的代码。
安装 Storybook
Storybook 是行业标准的 组件浏览器,用于隔离开发 UI 组件。由于设计系统专注于 UI 组件,因此 Storybook 是此用例的理想工具。我们将依赖以下功能
- 📕编目 UI 组件
- 📄将组件变体另存为 stories
- ⚡️开发者体验工具,如热模块重载
- 🛠支持多种视图层,包括 React
使用以下命令安装并运行 Storybook
# Installs Storybook
npx storybook@latest init
# Starts Storybook in development mode
yarn storybook
您应该看到这个
不错,我们已经设置了一个组件浏览器!
每次您将 Storybook 安装到应用程序中时,它都会在 stories
文件夹中添加一些示例。如果您愿意,可以花一些时间探索它们。但我们的设计系统不需要它们,因此可以安全地删除 stories
目录。
现在您的 Storybook 应该看起来像这样(请注意,字体样式有点偏差,例如,请参阅“Avatar: Initials” story)
添加全局样式
我们的设计系统需要将一些全局样式(CSS reset)应用于文档,以正确渲染我们的组件。我们可以使用 Emotion 的 global style prop 轻松添加它们。将您的 src/shared/global.js
文件更新为以下内容
import { css } from '@emotion/react';
import { color, typography } from './styles';
+ export const fontUrl = 'https://fonts.googleapis.com/css?family=Nunito+Sans:400,700,800,900';
export const bodyStyles = css`
/* Same as before */
`;
export const GlobalStyle = css`
body {
${bodyStyles}
}
`;
要在 Storybook 中使用 Global
“组件”,我们可以使用 decorator(组件包装器)。在应用程序中,我们会将该组件放置在顶层应用程序布局中,但在 Storybook 中,我们使用预览配置文件 .storybook/preview.js
包装所有 stories。将文件重命名为 .storybook/preview.jsx
并将其更新为以下内容
+ import { Global } from '@emotion/react';
+ import { GlobalStyle } from '../src/shared/global';
/** @type { import('@storybook/react').Preview } */
const preview = {
+ decorators: [
+ (Story) => (
+ <>
+ <Global styles={GlobalStyle} />
+ <Story />
+ </>
+ ),
+ ],
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
};
export default preview;
<>
不是错别字,它是一个 React Fragment,我们在此处使用它以避免向输出添加不必要的额外 HTML 标签。decorator 确保无论选择哪个 story,GlobalStyle
都会渲染。
使用插件增强 Storybook 功能
Storybook 包含一个由庞大社区创建的强大的 插件生态系统。对于务实的开发者来说,使用生态系统构建我们的工作流程比自己创建自定义工具(这可能很耗时)更容易。
Actions 插件用于验证交互性
actions 插件 在 Storybook 中,当对 Button 或 Link 等交互元素执行操作时,为您提供 UI 反馈。Actions 默认安装在 Storybook 中,您只需将“action”作为回调 prop 传递给组件即可使用它。
让我们看看如何在我们的 Button 元素中使用它,该元素可以选择性地接受一个包装器组件来响应点击。我们有一个 story 将 action 传递给该包装器
import styled from '@emotion/styled';
import { Button } from './Button';
import { Icon } from '../Icon/Icon';
import { StoryLinkWrapper } from '../LinkWrapper';
// When the user clicks a button, it will trigger the `action()`,
// ultimately showing up in Storybook's addon panel.
function ButtonWrapper(props) {
return <CustomButton {...props} />;
}
export const buttonWrapper = {
name: 'button wrapper',
render: () => (
<div>
<ButtonWrapper>Original Button Wrapper</ButtonWrapper>
<br />
<Button ButtonWrapper={ButtonWrapper} appearance='primary'>
Primary
</Button>
/* Removed for brevity */
</div>
),
};
Controls 用于压力测试组件
全新安装的 Storybook 包含 Controls 插件,该插件已开箱即用配置完成。
它允许您在 Storybook UI 中动态地与组件输入 (props) 交互。您可以通过 arguments(或简称为 args)向组件 prop 提供多个值,并通过 UI 调整它们。它帮助设计系统创建者通过调整参数值来压力测试组件输入 (props)。它还使设计系统消费者能够在集成组件之前尝试组件,以了解每个输入 (prop) 如何影响它们。
让我们通过在 Avatar
组件(位于 src/Avatar/Avatar.stories.jsx
中)中添加一个新的 story 来看看它们是如何工作的
import { Avatar } from './Avatar';
export default {
title: 'Design System/Avatar',
component: Avatar,
/*
* More on Storybook argTypes at:
* https://storybook.org.cn/docs/react/api/argtypes
*/
argTypes: {
size: {
control: {
type: 'select',
},
options: ['tiny', 'small', 'medium', 'large'],
},
},
};
// Other Avatar stories
/*
* New story using Controls
* Read more about Storybook templates at:
* https://storybook.org.cn/docs/react/writing-stories/introduction#using-args
*/
export const Controls = {
args: {
loading: false,
size: 'tiny',
username: 'Dominic Nguyen',
src: 'https://avatars.githubusercontent.com/u/263385',
},
};
请注意插件面板中的“Controls”选项卡。Controls 自动生成图形 UI 以调整 props。例如,“size”选择元素允许我们循环浏览支持的 Avatar 尺寸 tiny
、small
、medium
和 large
。同样的方法也应用于其余组件的 props(“loading”、“username”和“src”),从而使我们能够创建一种用户友好的方式来压力测试组件。
话虽如此,Controls 不能取代 stories。它们非常适合探索组件的边缘情况,而 stories 则用于展示假定的状态。
我们将在后面的章节中介绍 Accessibility 和 Docs 插件。
“Storybook 是一个强大的前端工作坊环境工具,它使团队能够设计、构建和组织 UI 组件(甚至包括全屏!),而不会被业务逻辑和底层细节所困扰。” – Brad Frost,《Atomic Design》作者
了解如何自动化维护
现在我们的设计系统组件已在 Storybook 中,我们已经向创建行业标准设计系统迈出了一步。现在是将我们的工作提交到远程仓库的绝佳时机。然后我们可以开始考虑如何设置自动化工具,以简化持续维护。
设计系统与所有软件一样,应该不断发展。挑战在于确保 UI 组件随着设计系统的增长继续保持预期的外观和感觉。
在第 4 章中,我们将学习如何设置持续集成并自动在线发布设计系统以进行协作。