2018-07-25 14:25:08 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*
|
|
|
|
* @format
|
|
|
|
*/
|
|
|
|
import { Button, IconButton, Dropdown, NavigableMenu } from '@wordpress/components';
|
|
|
|
import classnames from 'classnames';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import { noop } from 'lodash';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import './style.scss';
|
|
|
|
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* A component for displaying a button with a main action plus a secondary set of actions behind a menu toggle.
|
|
|
|
*
|
|
|
|
* @return { object } -
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
const SplitButton = ( {
|
|
|
|
isPrimary,
|
|
|
|
mainIcon,
|
|
|
|
mainLabel,
|
|
|
|
onClick,
|
|
|
|
menuLabel,
|
|
|
|
controls,
|
|
|
|
className,
|
|
|
|
} ) => {
|
|
|
|
if ( ! controls || ! controls.length ) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MainButtonComponent = ( mainIcon && IconButton ) || Button;
|
|
|
|
const classes = classnames( 'woocommerce-split-button', className, {
|
|
|
|
'is-primary': isPrimary,
|
|
|
|
'has-label': mainLabel,
|
|
|
|
} );
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={ classes }>
|
|
|
|
<MainButtonComponent
|
|
|
|
icon={ mainIcon }
|
|
|
|
className="woocommerce-split-button__main-action"
|
|
|
|
onClick={ onClick }
|
|
|
|
>
|
|
|
|
{ mainLabel }
|
|
|
|
</MainButtonComponent>
|
|
|
|
<Dropdown
|
|
|
|
className="woocommerce-split-button__menu"
|
|
|
|
position="bottom left"
|
|
|
|
contentClassName="woocommerce-split-button__menu-popover"
|
|
|
|
expandOnMobile
|
|
|
|
headerTitle={ menuLabel }
|
|
|
|
renderToggle={ ( { isOpen, onToggle } ) => {
|
|
|
|
return (
|
|
|
|
<IconButton
|
|
|
|
icon={ isOpen ? 'arrow-up' : 'arrow-down' }
|
|
|
|
className={ classnames( 'woocommerce-split-button__menu-toggle', {
|
|
|
|
'is-active': isOpen,
|
|
|
|
} ) }
|
|
|
|
onClick={ onToggle }
|
|
|
|
aria-haspopup="true"
|
|
|
|
aria-expanded={ isOpen }
|
|
|
|
label={ menuLabel }
|
|
|
|
tooltip={ menuLabel }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
} }
|
|
|
|
renderContent={ ( { onClose } ) => {
|
|
|
|
const renderControl = ( control, index ) => {
|
|
|
|
const ButtonComponent = ( control.icon && IconButton ) || Button;
|
|
|
|
return (
|
|
|
|
<ButtonComponent
|
|
|
|
key={ index }
|
|
|
|
onClick={ event => {
|
|
|
|
event.stopPropagation();
|
|
|
|
onClose();
|
|
|
|
if ( control.onClick ) {
|
|
|
|
control.onClick();
|
|
|
|
}
|
|
|
|
} }
|
|
|
|
className="woocommerce-split-button__menu-item"
|
|
|
|
icon={ control.icon || '' }
|
|
|
|
role="menuitem"
|
|
|
|
>
|
|
|
|
{ control.label }
|
|
|
|
</ButtonComponent>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<NavigableMenu
|
|
|
|
className="woocommerce-split-button__menu-wrapper"
|
|
|
|
role="menu"
|
|
|
|
aria-label={ menuLabel }
|
|
|
|
>
|
|
|
|
{ controls.map( renderControl ) }
|
|
|
|
</NavigableMenu>
|
|
|
|
);
|
|
|
|
} }
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
SplitButton.propTypes = {
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Whether the button is styled as a primary button.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
isPrimary: PropTypes.bool,
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Icon for the main button.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
mainIcon: PropTypes.node,
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Label for the main button.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
mainLabel: PropTypes.string,
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Function to activate when the the main button is clicked.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
onClick: PropTypes.func,
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Label to display for the menu of actions, used as a heading on the mobile popover and for accessible text.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
menuLabel: PropTypes.string,
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* An array of additional actions. Accepts additional icon, label, and onClick props.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
controls: PropTypes.arrayOf(
|
|
|
|
PropTypes.shape( {
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Icon used in button, passed to `IconButton`. Can be either string (dashicon name) or Gridicon.
|
|
|
|
*/
|
|
|
|
icon: PropTypes.oneOfType( [ PropTypes.string, PropTypes.element ] ),
|
|
|
|
/**
|
|
|
|
* Label displayed for this button.
|
|
|
|
*/
|
|
|
|
label: PropTypes.string.isRequired,
|
|
|
|
/**
|
|
|
|
* Click handler for this button.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
onClick: PropTypes.func,
|
|
|
|
} )
|
|
|
|
).isRequired,
|
2018-08-31 17:27:21 +00:00
|
|
|
/**
|
|
|
|
* Additional CSS classes.
|
|
|
|
*/
|
2018-07-25 14:25:08 +00:00
|
|
|
className: PropTypes.string,
|
|
|
|
};
|
|
|
|
|
|
|
|
SplitButton.defaultProps = {
|
|
|
|
isPrimary: false,
|
|
|
|
onClick: noop,
|
|
|
|
};
|
|
|
|
|
|
|
|
export default SplitButton;
|