Skip to content

Commit

Permalink
feat(Button): 按钮组件新增按钮组模式
Browse files Browse the repository at this point in the history
  • Loading branch information
79E committed Jan 13, 2023
1 parent 429bda7 commit e82e897
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 61 deletions.
38 changes: 27 additions & 11 deletions src/components/button/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,36 @@ import { Button } from "aunt";
通过 color 属性可以自定义按钮的颜色。
<code src="./demos/demo-color.tsx"></code>

### 按钮组

通过 Button.Group 包裹可以实现按钮组的概念。
<code src="./demos/demo-group.tsx"></code>

## 参数

| 参数 | 说明 | 类型 | 默认值 |
| -------- | ----------------------------------------- | ------------------------------------------------------ | --------- |
| type | 统一设置按钮类型 | `'default'\|'primary'\|'success'\|'warning'\|'danger'` | `default` |
| size | 统一设置按钮尺寸 | `'large'\|'normal'\|'small'\|'mini'` | `normal` |
| block | 是否是块级元素 | `boolean` | `false` |
| 参数 | 说明 | 类型 | 默认值 |
| -------- | ------ | ------- | --- |
| type | 统一设置按钮类型 | `'default'\|'primary'\|'success'\|'warning'\|'danger'` | `default` |
| size | 统一设置按钮尺寸 | `'large'\|'normal'\|'small'\|'mini'` | `normal` |
| block | 是否是块级元素 | `boolean` | `false` |
| color | 按钮颜色,支持传入 linear-gradient 渐变色 | `string` | `-` |
| disabled | 是否禁用 | `boolean` | `false` |
| shape | 按钮的形状 | `'default' \| 'square' \| 'round'` | `default` |
| plain | 是否为朴素按钮 | `boolean` | `false` |
| hairline | 是否使用 0.5px 边框 | `boolean` | `false` |

## 事件
| disabled | 是否禁用 | `boolean` | `false` |
| shape | 按钮的形状 | `'default' \| 'square' \| 'round'` | `default` |
| plain | 是否为朴素按钮 | `boolean` | `false` |
| hairline | 是否使用 0.5px 边框 | `boolean` | `false` |


### Button.Group
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| type | 统一设置按钮类型 | `string` | `default` |
| size | 统一设置按钮尺寸 | `string` | `normal` |
| iconPosition | 统一设置按钮图标展示位置 | `string` | `left` |
| block | 统一设置按钮为块级元素 | `boolean` | `false` |
| plain | 是否为朴素按钮组 | `boolean` | `false` |
| disabled | 是否禁用按钮组 | `boolean` | `false` |

### 事件

| 事件名 | 说明 | 类型 | 默认值 |
| ------- | -------------- | ----------------------------------------------------------------------------------- | ------ |
Expand Down
10 changes: 10 additions & 0 deletions src/components/button/button-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { ButtonGroupProps } from './types';

type ButtonContextType = {
parent?: ButtonGroupProps;
};

const ButtonContext = React.createContext<ButtonContextType>({});

export default ButtonContext;
45 changes: 45 additions & 0 deletions src/components/button/button-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useContext } from 'react';
import ConfigProviderContext from '../config-provider/config-provider-context';
import ButtonContext from './button-context';
import { useNamespace } from '../../hooks';
import { joinTrim } from '../../utils';
import { ButtonGroupProps } from './types';

const ButtonGroup = (props: ButtonGroupProps) => {
const { shape = 'default', type = 'default' } = props;

const internalClick = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (props.disabled) return;
props.onClick?.(e);
};

const { prefix } = useContext(ConfigProviderContext);
const ns = useNamespace('button', prefix);

return (
<div
className={joinTrim([
props.className,
ns.e('group'),
ns.em('group', type),
ns.em('group__shape', shape),
props.disabled ? ns.em('group', 'disabled') : '',
])}
style={props.style}
onClick={internalClick}
>
<ButtonContext.Provider
value={{
parent: {
...props,
shape: 'square',
},
}}
>
{props.children}
</ButtonContext.Provider>
</div>
);
};

export default ButtonGroup;
67 changes: 51 additions & 16 deletions src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,82 @@ import React, { CSSProperties, FunctionComponent, useContext, useMemo } from 're
import { ButtonProps } from './types';
import Loading from '../loading';
import ConfigProviderContext from '../config-provider/config-provider-context';
import ButtonContext from './button-context';
import { useNamespace } from '../../hooks';
import { joinTrim } from '../../utils';

export const Button: FunctionComponent<Partial<ButtonProps>> = props => {
const {
color,
shape = 'default',
plain = false,
iconPosition = 'left',
hairline = false,
loading = false,
disabled = false,
type = 'default',
size = 'normal',
block = false,
children,
iconPosition = 'left',
icon,
className,
style,
loadingText,
block,
plain,
...rest
} = props;

const { parent } = useContext(ButtonContext);

const currentSize = useMemo(() => props.size || parent?.size || 'normal', [
props.size,
parent?.size,
]);

const currentType = useMemo(() => props.type || parent?.type || 'default', [
props.type,
parent?.type,
]);

const currentPlain = useMemo(() => !!plain || !!parent?.plain, [plain, parent?.plain]);

const currentBlock = useMemo(() => !!block || !!parent?.block, [parent?.block, block]);

const currentIconPosition = useMemo(() => parent?.iconPosition || iconPosition, [
parent?.iconPosition,
iconPosition,
]);

const currentDisabled = React.useMemo(() => props.disabled ?? parent?.disabled, [
parent?.disabled,
props.disabled,
]);

const { prefix } = useContext(ConfigProviderContext);
const ns = useNamespace('button', prefix);

const varClasses = useMemo(() => {
return joinTrim([
ns.b(),
type ? ns.m(type) : '',
size ? ns.m(size) : '',
ns.m(currentType),
ns.m(currentSize),
shape ? ns.em('shape', shape) : '',
plain ? ns.m('plain') : '',
block ? ns.m('block') : '',
disabled ? ns.m('disabled') : '',
currentPlain ? ns.m('plain') : '',
currentBlock ? ns.m('block') : '',
currentDisabled ? ns.m('disabled') : '',
hairline ? ns.m('hairline') : '',
icon ? ns.e('icon') : '',
loading ? ns.e('loading') : '',
className,
]);
}, [type, size, shape, plain, block, disabled, hairline, icon, loading, className]);
}, [
currentBlock,
currentPlain,
currentDisabled,
currentType,
currentSize,
shape,
hairline,
icon,
loading,
className,
]);

const varStyles = useMemo(() => {
const styles: CSSProperties = {};
Expand All @@ -59,7 +94,7 @@ export const Button: FunctionComponent<Partial<ButtonProps>> = props => {
}, [plain, color, style]);

const handleClick = (event: any) => {
if (!loading && !disabled && props.onClick) {
if (!loading && !currentDisabled && props.onClick) {
props.onClick(event);
}
};
Expand All @@ -85,7 +120,7 @@ export const Button: FunctionComponent<Partial<ButtonProps>> = props => {
<Loading
size={loadingSize}
type={loadingType}
color={type === 'default' ? undefined : ''}
color={currentType === 'default' ? undefined : ''}
className={ns.em('icon', position)}
/>
);
Expand All @@ -108,9 +143,9 @@ export const Button: FunctionComponent<Partial<ButtonProps>> = props => {

return (
<div className={varClasses} style={{ ...varStyles }} {...rest} onClick={handleClick}>
{iconPosition === 'left' && renderIcon('left')}
{currentIconPosition === 'left' && renderIcon('left')}
{renderText()}
{iconPosition === 'right' && renderIcon('right')}
{currentIconPosition === 'right' && renderIcon('right')}
</div>
);
};
29 changes: 29 additions & 0 deletions src/components/button/demos/demo-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { Button, Space, AuntIconArrowLeft, AuntIconArrowRight, AuntIconRefreshCcw } from 'aunt';

export default () => (
<Space direction='vertical'>
<Button.Group plain type='primary' shape='round' disabled>
<Button>按钮1</Button>
<Button>按钮2</Button>
<Button>按钮3</Button>
</Button.Group>
<Button.Group shape='round'>
<Button type='primary'>按钮1</Button>
<Button type='primary'>按钮2</Button>
<Button type='primary'>按钮3</Button>
</Button.Group>
<Button.Group type='success' shape='round'>
<Button type='success'>按钮1</Button>
<Button type='default'>按钮2</Button>
<Button type='success'>按钮3</Button>
</Button.Group>
<Button.Group shape='round'>
<Button icon={<AuntIconArrowLeft size={18} />}>上一步</Button>
<Button icon={<AuntIconRefreshCcw size={18} />}>刷新</Button>
<Button icon={<AuntIconArrowRight size={18} />} iconPosition='right'>
下一步
</Button>
</Button.Group>
</Space>
);
68 changes: 37 additions & 31 deletions src/components/button/demos/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,58 @@ import DemoShape from './demo-shape';
import DemoSize from './demo-size';
import DemoButtonBlock from './demo-block';
import DemoColor from './demo-color';
import DemoGroup from './demo-group';

import './index.less';

function Demo() {
return (
<div className='demo-button'>
<DemoBlock title='按钮类型'>
<DemoType />
</DemoBlock>
<>
<div className='demo-button'>
<DemoBlock title='按钮类型'>
<DemoType />
</DemoBlock>

<DemoBlock title='按钮类型'>
<DemoPlain />
</DemoBlock>
<DemoBlock title='按钮类型'>
<DemoPlain />
</DemoBlock>

<DemoBlock title='细边按钮'>
<DemoHairline />
</DemoBlock>
<DemoBlock title='细边按钮'>
<DemoHairline />
</DemoBlock>

<DemoBlock title='图标按钮'>
<DemoIcon />
</DemoBlock>
<DemoBlock title='图标按钮'>
<DemoIcon />
</DemoBlock>

<DemoBlock title='禁用状态'>
<DemoDisabled />
</DemoBlock>
<DemoBlock title='禁用状态'>
<DemoDisabled />
</DemoBlock>

<DemoBlock title='加载状态'>
<DemoLoading />
</DemoBlock>
<DemoBlock title='加载状态'>
<DemoLoading />
</DemoBlock>

<DemoBlock title='按钮形状'>
<DemoShape />
</DemoBlock>
<DemoBlock title='按钮形状'>
<DemoShape />
</DemoBlock>

<DemoBlock title='按钮尺寸'>
<DemoSize />
</DemoBlock>
<DemoBlock title='按钮尺寸'>
<DemoSize />
</DemoBlock>

<DemoBlock title='块级按钮'>
<DemoButtonBlock />
</DemoBlock>
<DemoBlock title='块级按钮'>
<DemoButtonBlock />
</DemoBlock>

<DemoBlock title='按钮颜色'>
<DemoColor />
<DemoBlock title='按钮颜色'>
<DemoColor />
</DemoBlock>
</div>
<DemoBlock title='按钮组'>
<DemoGroup />
</DemoBlock>
</div>
</>
);
}

Expand Down
7 changes: 6 additions & 1 deletion src/components/button/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import './styles/index.less';
import { Button } from './button';
import { Button as _Button } from './button';
import ButtonGroup from './button-group';

export type { ButtonProps, ButtonType, ButtonSize, ButtonShape } from './types';

const Button = Object.assign(_Button, {
Group: ButtonGroup,
});

export { Button };
export default Button;
Loading

0 comments on commit e82e897

Please sign in to comment.