-
Notifications
You must be signed in to change notification settings - Fork 31
组件开发规范
$ tree -L 2 date-picker
date-picker
├── DatePicker.tsx
├── __test__
│ └── DatePicker.test.tsx
├── demos
│ ├── DatePicker.stories.tsx
│ └── DatePickerPage.tsx
├── index.ts
├── interfaces.ts
├── locales
│ ├── en-US.ts
│ └── zh-CN.ts
└── style
├── index.less
└── index.ts
4 directories, 10 files
- 组件实现:包含组件实现、组件接口定义和组件导出等文件;
- Demo:
demos
目录下,组件各种样式的 Demo 和组件文档; - 单元测试:
__test__
目录下,使用 Jest 和 React Testing Library 实现的测试用例; - 国际化:
locales
目录下,每种语言对应一个文件; - 样式:
style
目录下,Less 实现的组件样式。
-
index.ts
导出组件和组件的 Props -
interfaces.ts
定义组件的 Props - 组件实现文件的文件名要和组件名一致
主要包含 DatePicker.stories.tsx
和 DatePickerPage.tsx
两种文件。前者是组件的故事集,包含各种组件的样式;后者是组件文档。
每个组件都有一个默认的 Story,使用 Props
的默认值,然后可通过 Storybook 的 Controls 来修改 Props
值,来查看各种样式。
示例:
const Template: Story = (args) => <DatePicker {...args} />;
export const Basic = Template.bind({});
Basic.args = {};
只要返回 Story
类型值即可,如果为 Story
设置了 Props
类型,在 Controls 面板即可控制这些 Props
。
示例:
export const DisabledDate = Template.bind({});
DisabledDate.args = {
disabledDate: (date: Date) => isBefore(startOfToday(), date),
};
为了方便开发效果和设计对比,集成了 storybook-addon-designs 插件,可以在 Storybook 网站上直接预览设计稿。
集成方式如下:
export default {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GrowingIO-Design-Components?node-id=2672%3A30128',
allowFullscreen: true,
},
},
} as Meta;
如果某个 Story 有单独的样式,它的设计稿也可以单独设置:
Indicator.story = {
parameters: {
design: {
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GrowingIO-Design-Components?node-id=889%3A1159',
},
},
};
文档主要包含以下几部分:
- 标题
- 代码演示
- 参数说明
标题直接是组件的名称,使用 Storybook 的 Title
组件。关于组件的定义,直接使用 p
标签即可。
示例:
<Title>{formatMessage({ defaultMessage: 'DatePicker 日期选择器' })}</Title>
<p>{formatMessage({ defaultMessage: '当用户需要一个日期,可以在面板中进行选择。' })}</p>
“代码演示”用 Heading
标签,各种样式名称用 Subheading
。用 Story
来展示组件的各种使用场景,每种场景对应一个 Story
。
主要提供场景的描述和 Story
链接。另外,Story
外面包一层 Canvas
,这样可以在文档中直接显示组件。
示例:
<Heading>{formatMessage({ defaultMessage: '代码演示' })}</Heading>
<Subheading>{formatMessage({ defaultMessage: '基本样式' })}</Subheading>
<Canvas>
<Story id="pickers-datepicker--basic" />
</Canvas>
“参数说明”使用 Heading
标签,使用 Storybook 的 ArgsTable
展示组件的 Props
类型。
示例:
<Heading>{formatMessage({ defaultMessage: '参数说明' })}</Heading>
<ArgsTable of={DatePicker} />
组件文档的国际化使用 react-intl
工具来实现。所以上文中所有文案都用 formatMessage
函数。
import React from 'react';
import { Canvas, Title, Heading, Story, Subheading, ArgsTable } from '@storybook/addon-docs';
import { useIntl } from 'react-intl';
import DatePicker from '../DatePicker';
export default function DatePickerPage() {
const { formatMessage } = useIntl();
return (
<>
<Title>{formatMessage({ defaultMessage: 'DatePicker 日期选择器' })}</Title>
...
</>
);
}
测试工具使用 Jest + React Testing Library。 在使用 Storybook 时,我们创建了组件的各种使用场景,当我们编写测试用例时,为了提高测试覆盖率,我们需要做同样的工作!所以,在单元测试中要复用 Storybook 的故事集。示例如下:
import { Basic, DisabledDate } from '../demos/DatePicker.stories';
describe('DatePicker', () => {
it('render with default', () => {
const handleOnSelect = jest.fn();
render(<Basic {...Basic.args} onSelect={handleOnSelect} />);
expect(screen.getAllByText(20)).toHaveLength(1);
fireEvent.click(screen.getByText(20));
expect(handleOnSelect).toHaveBeenCalledWith(new Date());
});
it('render with disabled date', () => {
const handleOnSelect = jest.fn();
render(<DisabledDate {...DisabledDate.args} onSelect={handleOnSelect} />);
expect(screen.getAllByText(21)).toHaveLength(1);
fireEvent.click(screen.getByText(21));
expect(handleOnSelect).not.toHaveBeenCalled();
});
});
- 每个组件有自己的 Locale 文件
- 在
src/locales
目录下是汇总所有组件的 Locale 文件 - 每种语言对应一个文件,语言代码参考 LCID
DatePicker
组件的示例:
import rcPickerLocale from 'rc-picker/lib/locale/zh_CN';
const locale = {
...rcPickerLocale,
};
export default locale;
汇总的 Locale 文件:
import type { Locale } from '@gio-design/utils';
import datePickerLocale from '../date-picker/locales/zh-CN';
export const locale: Locale = {
code: 'zh-CN',
DatePicker: {
...datePickerLocale,
},
};
export default locale;
-
index.less
中实现组件的样式,实现时遵循 CSS BEM 书写规范; -
index.ts
要import './index.less'
。如果使用了其他组件,也要import
对应组件的 Less 文件。