wix-style-react
Version:
199 lines (189 loc) • 5.24 kB
JavaScript
import React, { cloneElement, PureComponent } from 'react';
import PropTypes from 'prop-types';
import { ButtonNext } from 'wix-ui-core/dist/src/components/button-next';
import { withFocusable } from 'wix-ui-core/dist/src/hocs/Focusable/FocusableHOC';
import { st, classes } from './ToggleButton.st.css';
import Tooltip from '../Tooltip';
import Text from '../Text';
import { iconChildSize, dataHooks } from './constants';
import { TooltipCommonProps } from '../common/PropTypes/TooltipCommon';
class Icon extends PureComponent {
render() {
const {
children,
size,
shape,
border,
tooltipProps,
tooltipDisabled,
labelValue,
labelPlacement,
focusableOnBlur,
focusableOnFocus,
className,
} = this.props;
const iconSize = iconChildSize[size];
const isLabelOutside = shape === 'round' && labelPlacement === 'end';
const [icon, label] = React.Children.map(
children,
(children, child => child),
);
// TODO page is scrolled whenever icon focused and we press Space button
return (
children && (
<Tooltip
className={st(classes.tooltip)}
{...tooltipProps}
dataHook={dataHooks.tooltip}
size="small"
content={labelValue}
disabled={tooltipDisabled || tooltipProps.disabled}
>
<span className={isLabelOutside ? classes.labelContainer : ''}>
<div
className={st(classes.icon, { size, border }, className)}
tabIndex={1}
onBlur={focusableOnBlur}
onFocus={focusableOnFocus}
>
{cloneElement(icon, {
width: iconSize,
height: iconSize,
})}
{!isLabelOutside && label}
</div>
{isLabelOutside && label}
</span>
</Tooltip>
)
);
}
}
const ToggleButtonIcon = withFocusable(Icon);
class ToggleButton extends PureComponent {
static displayName = 'ToggleButton';
static propTypes = {
/** render as some other component or DOM tag */
as: PropTypes.oneOfType([
PropTypes.func,
PropTypes.object,
PropTypes.string,
]),
/** Used for passing any wix-style-react icon. For external icon make sure to follow ux sizing guidelines */
children: PropTypes.node,
/** Button skins */
skin: PropTypes.oneOf([
'standard',
'dark',
'inverted',
'destructive',
'success',
]),
/** Button size */
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']),
/** Button shape */
shape: PropTypes.oneOf(['square', 'round']),
/** Label content */
labelValue: PropTypes.node,
/** Label placement */
labelPlacement: PropTypes.oneOf(['tooltip', 'bottom', 'end']),
/** Whether label should have ellipsis */
labelEllipsis: PropTypes.bool,
/** Click event handler */
onClick: PropTypes.func,
/** Applies selected styles */
selected: PropTypes.bool,
/** Applies disabled styles */
disabled: PropTypes.bool,
/** Applies border */
border: PropTypes.bool,
/** String based data hook */
dataHook: PropTypes.string,
/** Tooltip props for label. Applied only when `labelPlacement` is `tooltip`. */
tooltipProps: PropTypes.shape(TooltipCommonProps),
};
static defaultProps = {
skin: 'standard',
size: 'medium',
shape: 'square',
border: false,
disabled: false,
labelValue: '',
labelPlacement: 'tooltip',
labelEllipsis: false,
tooltipProps: {
placement: 'top',
},
};
renderLabel = () => {
const {
disabled,
size,
labelValue,
labelPlacement,
labelEllipsis,
} = this.props;
return (
<Text
className={st(classes.label, { placement: labelPlacement, size })}
disabled={disabled}
dataHook={dataHooks.label}
size="tiny"
weight="thin"
ellipsis={labelEllipsis}
>
{labelValue}
</Text>
);
};
render() {
const {
children,
size,
shape,
skin,
tooltipProps,
labelValue,
selected,
dataHook,
labelPlacement,
labelEllipsis,
disabled,
border,
...rest
} = this.props;
return (
<ButtonNext
{...rest}
className={st(classes.root, {
disabled,
selected,
skin,
labelPlacement,
shape,
})}
tabIndex={-1}
data-hook={dataHook}
data-placement={labelPlacement}
data-selected={selected}
data-skin={skin}
disabled={disabled}
>
<ToggleButtonIcon
size={size}
shape={shape}
border={border}
tooltipProps={tooltipProps}
labelValue={labelValue}
labelPlacement={labelPlacement}
tooltipDisabled={labelPlacement !== 'tooltip'}
>
{children}
{labelPlacement === 'end' ? this.renderLabel() : null}
</ToggleButtonIcon>
{labelPlacement === 'bottom' ? this.renderLabel() : null}
</ButtonNext>
);
}
}
export default ToggleButton;