Skip to content

Commit 31135aa

Browse files
authored
feat(design): Radio.Button add icon prop (#1398)
1 parent 3c6189e commit 31135aa

File tree

6 files changed

+133
-3
lines changed

6 files changed

+133
-3
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Radio as AntRadio } from 'antd';
2+
import type { RadioButtonProps as AntRadioButtonProps } from 'antd/es/radio/radioButton';
3+
import type { RadioRef } from 'antd/es/radio';
4+
import classNames from 'classnames';
5+
import React, { useContext } from 'react';
6+
import ConfigProvider from '../config-provider';
7+
8+
export interface RadioButtonProps extends AntRadioButtonProps {
9+
icon?: React.ReactNode;
10+
}
11+
12+
const RadioButton = React.forwardRef<RadioRef, RadioButtonProps>(
13+
({ prefixCls: customizePrefixCls, className, icon, children, ...restProps }, ref) => {
14+
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
15+
const prefixCls = getPrefixCls('radio', customizePrefixCls);
16+
17+
const hasChildren = React.Children.count(children) > 0;
18+
const isIconOnly = icon && !hasChildren;
19+
20+
const buttonPrefixCls = `${prefixCls}-button`;
21+
const buttonCls = classNames(
22+
{
23+
[`${buttonPrefixCls}-wrapper-with-icon`]: !!icon,
24+
[`${buttonPrefixCls}-wrapper-icon-only`]: isIconOnly,
25+
},
26+
className
27+
);
28+
29+
return (
30+
<AntRadio.Button
31+
ref={ref}
32+
prefixCls={customizePrefixCls}
33+
className={buttonCls}
34+
{...restProps}
35+
>
36+
{icon ? (
37+
<>
38+
{icon}
39+
{children}
40+
</>
41+
) : (
42+
children
43+
)}
44+
</AntRadio.Button>
45+
);
46+
}
47+
);
48+
49+
RadioButton.displayName = 'Radio.Button';
50+
51+
export default RadioButton;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { PlusOutlined, DeleteOutlined, EditOutlined, DownloadOutlined } from '@oceanbase/icons';
3+
import { Radio, Space, Divider } from '@oceanbase/design';
4+
import type { RadioChangeEvent } from '@oceanbase/design';
5+
6+
const App: React.FC = () => {
7+
const onChange = (e: RadioChangeEvent) => {
8+
console.log(`radio checked:${e.target.value}`);
9+
};
10+
11+
return (
12+
<Space direction="vertical" size="middle">
13+
<Radio.Group onChange={onChange} defaultValue="a">
14+
<Radio.Button value="a" icon={<PlusOutlined />}>
15+
Add
16+
</Radio.Button>
17+
<Radio.Button value="b" icon={<EditOutlined />}>
18+
Edit
19+
</Radio.Button>
20+
<Radio.Button value="c" icon={<DeleteOutlined />}>
21+
Delete
22+
</Radio.Button>
23+
<Radio.Button value="d" icon={<DownloadOutlined />}>
24+
Download
25+
</Radio.Button>
26+
</Radio.Group>
27+
<Radio.Group onChange={onChange} defaultValue="a">
28+
<Radio.Button value="a" icon={<PlusOutlined />}>
29+
Add
30+
</Radio.Button>
31+
<Radio.Button value="b" icon={<EditOutlined />} disabled>
32+
Edit
33+
</Radio.Button>
34+
<Radio.Button value="c" icon={<DeleteOutlined />}>
35+
Delete
36+
</Radio.Button>
37+
</Radio.Group>
38+
<Radio.Group onChange={onChange} defaultValue="a">
39+
<Radio.Button value="a" icon={<PlusOutlined />} />
40+
<Radio.Button value="b" icon={<EditOutlined />} />
41+
<Radio.Button value="c" icon={<DeleteOutlined />} />
42+
<Radio.Button value="d" icon={<DownloadOutlined />} />
43+
</Radio.Group>
44+
</Space>
45+
);
46+
};
47+
48+
export default App;

packages/design/src/radio/index.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,24 @@ demo:
99

1010
- 🔥 完全继承 antd [Radio](https://ant.design/components/radio-cn) 的能力和 API,可无缝切换。
1111
- 💄 定制主题和样式,符合 OceanBase Design 设计规范。
12+
- 🆕 Radio.Button 新增 `icon` 属性,用于设置图标。
1213

1314
## 代码演示
1415

1516
<!-- prettier-ignore -->
1617
<code src="./demo/radio.tsx" title="单选"></code>
1718
<code src="./demo/radio-button.tsx" title="单选按钮"></code>
19+
<code src="./demo/radio-button-icon.tsx" title="带图标的单选按钮"></code>
1820
<code src="./demo/over-length.tsx" title="超长内容"></code>
1921

2022
## API
2123

22-
- 详见 antd Radio 文档: https://ant.design/components/radio-cn
24+
### Radio.Button
25+
26+
| 属性 | 说明 | 类型 | 默认值 |
27+
| ---- | ---- | ----------- | ------ |
28+
| icon | 图标 | `ReactNode` | - |
29+
30+
除了上述属性外,`Radio.Button` 完全继承 antd [Radio.Button](https://ant.design/components/radio-cn#radioradiobutton) 的所有属性。
31+
32+
- 更多属性详见 antd Radio 文档: https://ant.design/components/radio-cn

packages/design/src/radio/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import type { RadioProps as AntRadioProps, RadioRef } from 'antd/es/radio';
33
import classNames from 'classnames';
44
import React, { useContext } from 'react';
55
import ConfigProvider from '../config-provider';
6+
import RadioButton from './RadioButton';
67
import useStyle from './style';
78

89
export * from 'antd/es/radio';
10+
export type { RadioButtonProps } from './RadioButton';
911

1012
const InternalRadio = React.forwardRef<RadioRef, AntRadioProps>(
1113
({ prefixCls: customizePrefixCls, className, ...restProps }, ref) => {
@@ -19,9 +21,9 @@ const InternalRadio = React.forwardRef<RadioRef, AntRadioProps>(
1921
}
2022
);
2123

22-
const Radio = InternalRadio as typeof AntRadio;
24+
const Radio = InternalRadio as typeof AntRadio & { Button: typeof RadioButton };
2325

24-
Radio.Button = AntRadio.Button;
26+
Radio.Button = RadioButton;
2527
Radio.Group = AntRadio.Group;
2628
// @ts-ignore
2729
Radio.__ANT_RADIO = AntRadio.__ANT_RADIO;

packages/design/src/radio/style/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const genRadioStyle: GenerateStyle<RadioToken> = (token: RadioToken): CSS
99
const marginBottom = calc(calc(fontSize).mul(lineHeight).equal())
1010
.sub(radioSize || fontSizeLG)
1111
.div(-2)
12+
.sub(1)
1213
.equal();
1314
return {
1415
[`${componentCls}-wrapper`]: {
@@ -36,6 +37,22 @@ export const genRadioStyle: GenerateStyle<RadioToken> = (token: RadioToken): CSS
3637
borderColor: token.gray7,
3738
color: token.colorText,
3839
},
40+
// Radio.Button with icon style
41+
[`${componentCls}-button-wrapper`]: {
42+
[`&${componentCls}-button-wrapper-with-icon`]: {
43+
[`${componentCls}-button-label`]: {
44+
gap: token.sizeXXS,
45+
display: 'inline-flex',
46+
alignItems: 'center',
47+
justifyContent: 'center',
48+
height: '100%',
49+
},
50+
},
51+
// Radio.Button icon-only style
52+
[`&${componentCls}-button-wrapper-icon-only`]: {
53+
paddingInline: token.paddingXS,
54+
},
55+
},
3956
},
4057
};
4158
};

packages/design/src/theme/default.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ const defaultTheme: ThemeConfig = {
349349
Radio: {
350350
// temporarily fix style for checked disabled Radio.Button
351351
controlItemBgActiveDisabled: colorFillSecondary,
352+
// to match Button padding
353+
buttonPaddingInline: 12,
352354
},
353355
Segmented: {
354356
trackBg: colorFillTertiary,

0 commit comments

Comments
 (0)