-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathbutton.tsx
More file actions
100 lines (91 loc) · 3.19 KB
/
Copy pathbutton.tsx
File metadata and controls
100 lines (91 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import React, { useContext } from 'react';
import classNames from 'classnames';
import { INPUT_GROUP_CONTROL_MARK, markComponent } from '../_utils/component-markers';
import { ConfigContext } from '../config-provider/config-context';
import { getPrefixCls } from '../_utils/general';
import { ButtonProps } from './types';
export const BUTTON_MARK = Symbol('tiny-design.button');
const isProduction = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV === 'production';
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props: ButtonProps, ref) => {
const {
size = 'md',
variant = 'solid',
color = 'default',
loading = false,
disabled = false,
block = false,
onClick,
icon,
iconPosition = 'start',
loadingIcon,
round,
shape,
children,
className,
style,
prefixCls: customisedCls,
...otherProps
} = props;
const configContext = useContext(ConfigContext);
const prefixCls = getPrefixCls('btn', configContext.prefixCls, customisedCls);
const btnSize = props.size || configContext.componentSize || size;
const resolvedShape = shape || (round ? 'round' : 'default');
const isDisabled = disabled || loading;
const hasChildren = React.Children.count(children) > 0;
const visualIcon = loading ? loadingIcon || <span className={`${prefixCls}__loader`} /> : icon;
const isIconOnly = !hasChildren && !!visualIcon;
const accessibleName =
otherProps['aria-label'] || otherProps['aria-labelledby'] || otherProps.title;
if (!isProduction && isIconOnly && !accessibleName) {
// Icon-only buttons need an accessible name.
console.warn(
'Button with icon only should provide `aria-label`, `aria-labelledby`, or `title`.'
);
}
const cls = classNames(
prefixCls,
`${prefixCls}_${btnSize}`,
{
[`${prefixCls}_variant-${variant}`]: variant,
[`${prefixCls}_color-${color}`]: color,
[`${prefixCls}_block`]: block,
[`${prefixCls}_round`]: resolvedShape === 'round',
[`${prefixCls}_circle`]: resolvedShape === 'circle',
[`${prefixCls}_disabled`]: isDisabled,
[`${prefixCls}_loading`]: loading,
[`${prefixCls}_icon-start`]: !!visualIcon && iconPosition === 'start',
[`${prefixCls}_icon-end`]: !!visualIcon && iconPosition === 'end',
[`${prefixCls}_icon-only`]: isIconOnly,
},
className
);
const btnOnClick = (e: React.MouseEvent<HTMLButtonElement>) => {
if (isDisabled) {
return;
}
onClick && onClick(e);
};
const iconNode = visualIcon ? (
<span className={`${prefixCls}__icon-container`}>{visualIcon}</span>
) : null;
const contentNode = hasChildren ? (
<span className={`${prefixCls}__children`}>{children}</span>
) : null;
return (
<button
{...otherProps}
ref={ref}
className={cls}
disabled={isDisabled}
aria-busy={loading || undefined}
onClick={btnOnClick}
style={style}>
{iconPosition === 'end' ? contentNode : iconNode}
{iconPosition === 'end' ? iconNode : contentNode}
</button>
);
});
Button.displayName = 'Button';
markComponent(Button, BUTTON_MARK);
markComponent(Button, INPUT_GROUP_CONTROL_MARK);
export default Button;