Skip to content

Commit a9cae88

Browse files
committed
feat(button): refactor antd button, rewrite icon
#584
1 parent 6014bb0 commit a9cae88

File tree

8 files changed

+351
-0
lines changed

8 files changed

+351
-0
lines changed

src/button/__tests__/index.test.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import { UploadOutlined } from '@dtinsight/react-icons';
3+
import { render, screen } from '@testing-library/react';
4+
5+
import Button from '../index';
6+
7+
describe('Button', () => {
8+
it('renders button with text correctly', () => {
9+
render(<Button>Test Button</Button>);
10+
expect(screen.getByText('Test Button')).toBeInTheDocument();
11+
});
12+
13+
it('renders button with icon correctly', () => {
14+
const { container } = render(<Button icon={<UploadOutlined />}>With Icon</Button>);
15+
expect(container.querySelector('.dtc-button__icon')).toBeInTheDocument();
16+
expect(screen.getByText('With Icon')).toBeInTheDocument();
17+
});
18+
19+
it('renders icon-only button correctly', () => {
20+
const { container } = render(<Button icon={<UploadOutlined />} />);
21+
expect(container.querySelector('.dtc-button__icon')).toBeInTheDocument();
22+
expect(container.querySelector('.dtc-button__text')).toBeNull();
23+
});
24+
25+
it('applies custom className correctly', () => {
26+
const { container } = render(<Button className="custom-class">Custom Class</Button>);
27+
expect(container.querySelector('.dtc-button.custom-class')).toBeInTheDocument();
28+
});
29+
30+
it('passes other props to antd Button', () => {
31+
render(
32+
<Button type="primary" data-testid="primary-button">
33+
Primary
34+
</Button>
35+
);
36+
const button = screen.getByTestId('primary-button');
37+
expect(button).toHaveClass('ant-btn-primary');
38+
});
39+
40+
it('applies correct size to icon and text', () => {
41+
const { container } = render(
42+
<Button size="small" icon={<UploadOutlined />}>
43+
Small Button
44+
</Button>
45+
);
46+
expect(container.querySelector('.dtc-button__icon--small')).toBeInTheDocument();
47+
expect(container.querySelector('.dtc-button__text--small')).toBeInTheDocument();
48+
});
49+
});

src/button/demos/basic.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React, { useState } from 'react';
2+
import { UploadOutlined } from '@dtinsight/react-icons';
3+
import { Radio, Space } from 'antd';
4+
import { Button } from 'dt-react-component';
5+
6+
import { ButtonProps } from '..';
7+
8+
export default function Basic() {
9+
const [size, setSize] = useState<ButtonProps['size']>('large');
10+
11+
return (
12+
<Space direction="vertical" size="large">
13+
<Radio.Group value={size} onChange={(e) => setSize(e.target.value)}>
14+
<Radio.Button value="large">Large</Radio.Button>
15+
<Radio.Button value="middle">Default</Radio.Button>
16+
<Radio.Button value="small">Small</Radio.Button>
17+
</Radio.Group>
18+
19+
<div>
20+
<h3>按钮类型</h3>
21+
<Space>
22+
<Button type="primary" size={size}>
23+
Primary Button
24+
</Button>
25+
<Button size={size}>Default Button</Button>
26+
<Button type="dashed" size={size}>
27+
Dashed Button
28+
</Button>
29+
<Button type="link" size={size}>
30+
Link Button
31+
</Button>
32+
</Space>
33+
</div>
34+
35+
<div>
36+
<h3>带图标的按钮</h3>
37+
<Space>
38+
<Button type="primary" size={size} icon={<UploadOutlined />}>
39+
Search
40+
</Button>
41+
<Button icon={<UploadOutlined />} size={size}>
42+
Search
43+
</Button>
44+
<Button type="dashed" size={size} icon={<UploadOutlined />}>
45+
Search
46+
</Button>
47+
<Button type="link" size={size} icon={<UploadOutlined />}>
48+
Search
49+
</Button>
50+
</Space>
51+
</div>
52+
53+
<div>
54+
<h3>纯图标按钮</h3>
55+
<Space>
56+
<Button type="primary" size={size} icon={<UploadOutlined />} />
57+
<Button size={size} icon={<UploadOutlined />} />
58+
<Button size={size} type="dashed" icon={<UploadOutlined />} />
59+
<Button size={size} type="link" icon={<UploadOutlined />} />
60+
</Space>
61+
</div>
62+
63+
<div>
64+
<h3>禁用状态</h3>
65+
<Space>
66+
<Button size={size} type="primary" disabled>
67+
Primary(Disabled)
68+
</Button>
69+
<Button size={size} disabled>
70+
Default(Disabled)
71+
</Button>
72+
<Button size={size} type="dashed" disabled>
73+
Dashed(Disabled)
74+
</Button>
75+
<Button size={size} type="link" disabled>
76+
Link(Disabled)
77+
</Button>
78+
</Space>
79+
</div>
80+
</Space>
81+
);
82+
}

src/button/demos/block.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
import { UploadOutlined } from '@dtinsight/react-icons';
3+
import { Space } from 'antd';
4+
import { Button } from 'dt-react-component';
5+
6+
export default function BlockDemo() {
7+
return (
8+
<Space direction="vertical" size="large" style={{ width: '100%' }}>
9+
<div>
10+
<h3>块级按钮</h3>
11+
<Space direction="vertical" style={{ width: '100%' }}>
12+
<Button type="primary" block>
13+
Primary Block Button
14+
</Button>
15+
<Button block>Default Block Button</Button>
16+
<Button type="dashed" block>
17+
Dashed Block Button
18+
</Button>
19+
<Button type="link" block>
20+
Link Block Button
21+
</Button>
22+
</Space>
23+
</div>
24+
25+
<div style={{ background: 'rgb(190, 200, 200)', padding: '16px' }}>
26+
<h3>幽灵按钮</h3>
27+
<Space>
28+
<Button type="primary" ghost>
29+
Primary Ghost
30+
</Button>
31+
<Button ghost>Default Ghost</Button>
32+
<Button type="dashed" ghost>
33+
Dashed Ghost
34+
</Button>
35+
<Button type="primary" ghost icon={<UploadOutlined />}>
36+
Ghost with Icon
37+
</Button>
38+
</Space>
39+
</div>
40+
</Space>
41+
);
42+
}

src/button/demos/loading.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React, { useState } from 'react';
2+
import { UploadOutlined } from '@dtinsight/react-icons';
3+
import { Space } from 'antd';
4+
import { Button } from 'dt-react-component';
5+
6+
export default function LoadingDemo() {
7+
const [loading, setLoading] = useState(false);
8+
9+
const handleClick = () => {
10+
setLoading(true);
11+
setTimeout(() => {
12+
setLoading(false);
13+
}, 2000);
14+
};
15+
16+
return (
17+
<Space direction="vertical" size="large">
18+
<div>
19+
<h3>加载状态</h3>
20+
<Space>
21+
<Button type="primary" loading>
22+
Loading
23+
</Button>
24+
<Button loading>Loading</Button>
25+
<Button type="dashed" loading>
26+
Loading
27+
</Button>
28+
<Button type="link" loading>
29+
Loading
30+
</Button>
31+
</Space>
32+
</div>
33+
34+
<div>
35+
<h3>点击后加载</h3>
36+
<Space>
37+
<Button type="primary" loading={loading} onClick={handleClick}>
38+
Click me!
39+
</Button>
40+
<Button loading={loading} onClick={handleClick}>
41+
Click me!
42+
</Button>
43+
<Button
44+
type="primary"
45+
icon={<UploadOutlined />}
46+
loading={loading}
47+
onClick={handleClick}
48+
>
49+
Click me!
50+
</Button>
51+
</Space>
52+
</div>
53+
54+
<div>
55+
<h3>危险按钮</h3>
56+
<Space>
57+
<Button type="primary" danger>
58+
Primary Danger
59+
</Button>
60+
<Button danger>Default Danger</Button>
61+
<Button type="dashed" danger>
62+
Dashed Danger
63+
</Button>
64+
<Button type="link" danger>
65+
Link Danger
66+
</Button>
67+
</Space>
68+
</div>
69+
</Space>
70+
);
71+
}

src/button/index.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Button 按钮
3+
group: 组件
4+
toc: content
5+
demo:
6+
cols: 2
7+
---
8+
9+
# Button 按钮
10+
11+
## 何时使用
12+
13+
按钮用于开始一个即时操作。
14+
15+
## 代码演示
16+
17+
<code src="./demos/basic.tsx" title="基本使用" description="按钮的基本使用,包括不同类型的按钮、带图标的按钮、纯图标按钮、不同尺寸的按钮以及禁用状态的按钮。"></code>
18+
19+
<code src="./demos/loading.tsx" title="加载状态" description="展示按钮的加载状态和危险按钮。"></code>
20+
21+
<code src="./demos/block.tsx" title="块级按钮" description="展示块级按钮和幽灵按钮。"></code>
22+
23+
## API
24+
25+
### Button
26+
27+
Button 组件支持 antd Button 组件的所有属性,详见 [Ant Design Button API](https://ant.design/components/button-cn/#API)
28+
29+
## 注意事项
30+
31+
- 使用自定义图标时,请确保图标组件符合规范,建议使用项目内的图标组件。
32+
- 图标大小会根据按钮的 `size` 属性自动调整,也可以通过设置图标组件的 `style` 属性来手动调整大小。
33+
- 当只设置 `icon` 而不设置 `children` 时,按钮将只显示图标。
34+
- 本组件是对 antd Button 的封装,支持 antd Button 的所有属性和事件。

src/button/index.scss

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.dtc-button {
2+
display: inline-flex;
3+
align-items: center;
4+
justify-content: center;
5+
&__icon {
6+
display: inline-flex;
7+
align-items: center;
8+
justify-content: center;
9+
font-size: inherit;
10+
line-height: 0;
11+
// 因为 dtstack-icon 组件的 font-size 是 16px,现在需要继承 Button 组件的 font-size
12+
.dtstack-icon {
13+
font-size: inherit;
14+
}
15+
&--small {
16+
font-size: 12px;
17+
}
18+
&--middle {
19+
font-size: 16px;
20+
}
21+
&--large {
22+
font-size: 18px;
23+
}
24+
& + .dtc-button__text {
25+
&--small {
26+
margin-left: 2px;
27+
}
28+
&--middle {
29+
margin-left: 4px;
30+
}
31+
&--large {
32+
margin-left: 8px;
33+
}
34+
}
35+
}
36+
&__text {
37+
display: inline-block;
38+
&--small {
39+
font-size: 12px;
40+
}
41+
&--middle {
42+
font-size: 12px;
43+
}
44+
&--large {
45+
font-size: 16px;
46+
}
47+
}
48+
}

src/button/index.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import { Button as AntdButton, ButtonProps as AntdButtonProps } from 'antd';
3+
import classNames from 'classnames';
4+
5+
import './index.scss';
6+
7+
export interface ButtonProps extends AntdButtonProps {}
8+
9+
export default function Button({
10+
className,
11+
icon,
12+
children,
13+
size = 'middle',
14+
...rest
15+
}: ButtonProps) {
16+
return (
17+
<AntdButton className={classNames('dtc-button', className)} {...rest}>
18+
{icon && <span className={`dtc-button__icon dtc-button__icon--${size}`}>{icon}</span>}
19+
{children && (
20+
<span className={`dtc-button__text dtc-button__text--${size}`}>{children}</span>
21+
)}
22+
</AntdButton>
23+
);
24+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '@dtinsight/react-icons/dist/index.css';
22

33
export { default as BlockHeader } from './blockHeader';
4+
export { default as Button } from './button';
45
export { default as Catalogue } from './catalogue';
56
export { default as Chat } from './chat';
67
export { default as CollapsibleActionItems } from './collapsibleActionItems';

0 commit comments

Comments
 (0)