UNPKG

wix-style-react

Version:
205 lines 8.82 kB
import React from 'react'; import PropTypes from 'prop-types'; import DropdownBase from '../DropdownBase'; import { placements } from '../Popover'; import { st, classes } from './PopoverMenu.st.css'; import { listItemSectionBuilder } from '../ListItemSection'; /** PopoverMenu */ class PopoverMenu extends React.PureComponent { constructor() { super(...arguments); this.ref = React.createRef(); this._open = () => { if (this.ref.current) { this.ref.current._open(); } }; this._filterChildren = children => { return React.Children.map(children, child => child).filter(child => typeof child !== 'string'); }; this._buildOptions = children => { return children.map((child, id) => { const displayName = child.type && child.type.displayName; if (displayName && displayName === 'PopoverMenu.Divider') { return { id, divider: true, dataHook: child.props.dataHook, }; } if (displayName && displayName === 'PopoverMenu.MenuItem') { return { id, title: child.props.text, onClick: child.props.onClick, skin: child.props.skin, dataHook: child.props.dataHook, prefixIcon: child.props.prefixIcon, disabled: child.props.disabled, subtitle: child.props.subtitle, suffixIcon: child.props.suffixIcon, }; } return { id, value: child, custom: true, overrideStyle: true }; }); }; this._renderOptions = () => { const { textSize, ellipsis } = this.props; const children = this._filterChildren(this.props.children); const options = this._buildOptions(children); return options.map(option => { // Custom if (option.custom) { return option; } // Divider if (option.divider) { return listItemSectionBuilder({ type: 'divider', ...option, }); } const { id, disabled, dataHook, skin, subtitle, title, ...rest } = option; return { ...rest, id, disabled, as: 'button', dataHook: dataHook || `popover-menu-${id}`, skin: skin || 'dark', size: textSize, className: classes.listItem, ellipsis, subtitle, shouldFocusWithoutScroll: true, value: 'action', title: false, optionTitle: title, }; }); }; this._renderTriggerElement = ({ toggle, open, close, isOpen, ref }) => { const { triggerElement } = this.props; if (!triggerElement) { return null; } const commonProps = { onClick: toggle, ref, 'aria-haspopup': 'menu', 'aria-expanded': isOpen, }; return React.isValidElement(triggerElement) ? React.cloneElement(triggerElement, { ...commonProps, }) : triggerElement({ toggle, open, close, isOpen, ...commonProps, }); }; } render() { const { appendTo, placement, minWidth, maxWidth, flip, fixed, showArrow, dataHook, moveBy, maxHeight, zIndex, className, fluid, onHide, onShow, } = this.props; return (React.createElement(DropdownBase, { ref: this.ref, className: st(classes.root, className), dataHook: dataHook, animate: true, options: this._renderOptions(), appendTo: appendTo, placement: placement, minWidth: minWidth, maxWidth: maxWidth, flip: flip, fixed: fixed, showArrow: showArrow, tabIndex: -1, moveBy: moveBy, maxHeight: maxHeight, zIndex: zIndex, fluid: fluid, onHide: onHide, onShow: onShow, listType: "action", autoFocus: true }, ({ toggle, open, close, isOpen, ref }) => this._renderTriggerElement({ toggle, open, close, isOpen, ref }))); } } PopoverMenu.displayName = 'PopoverMenu'; PopoverMenu.MenuItem = () => ({}); PopoverMenu.Divider = () => ({}); PopoverMenu.propTypes = { /** Sets a maximum width for a Popover menu */ maxWidth: PropTypes.number, /** Sets a minimum width for a Popover menu */ minWidth: PropTypes.number, /** Sets a maximum height for a Popover menu */ maxHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the Popover z-index */ zIndex: PropTypes.number, /** Moves Popover menu overlay relative to its trigger element by a defined number of px: * - horizontally (on X-axis) * - or vertically (on Y-axis) */ moveBy: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }), /** Defines a component that calls out a Popover menu (`<IconButton />`, `<Button />` or `<Text Button />`) */ triggerElement: PropTypes.oneOfType([PropTypes.element, PropTypes.func]) .isRequired, /** Defines the Popover menu’s overlay placement in relation to its trigger element: * * auto-start * * auto * * auto-end * * top-start * * top * * top-end * * right-start * * right * * right-end * * bottom-start * * bottom * * bottom-end * * left-start * * left * * left-end */ placement: PropTypes.oneOf(placements), /** Sets the size of text in Popover menu items */ textSize: PropTypes.oneOf(['small', 'medium']), /** Truncates menu item text that overflows component’s max Width */ ellipsis: PropTypes.bool, /** * Stores Popover menu compound components: * - <PopoverMenu.MenuItem /> * - <PopoverMenu.Divider /> (optional) * * `<PopoverMenu.MenuItem>` component has these fields: * * `text` - Sets a label for a Popover menu item * * `onClick` - Defines a callback function which is called when a Popover menu item is clicked on * * `skin` - Controls the appearance of a Popover menu item (one of `standard`, `dark`, `destructive`) * * `prefixIcon` - Contains an icon at the start of a Popover menu item * * `dataHook` - Applies a data-hook HTML attribute to be used in the tests * * `suffixIcon` - suffix icon property * * `disabled` - Disables a Popover menu item * * `subtitle` - Sets a text for a Popover menu item subtitle\ * * `<PopoverMenu.Divider>` component has these fields: * * `dataHook` - Applies a data-hook HTML attribute to be used in the tests */ children: PropTypes.node, /** Enables calculations in relation to a DOM element */ appendTo: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), /** Enables the flip behaviour. This behaviour is used to flip the overlay placement when it starts to overlap the trigger element. */ flip: PropTypes.bool, /** Enables the fixed behaviour. This behaviour is used to keep the overlay at its original placement even when it is being positioned outside the boundary. */ fixed: PropTypes.bool, /* Allows truncating the trigger element to a specified parent container width. */ fluid: PropTypes.bool, /** Controls visibility of the pointer arrow */ showArrow: PropTypes.bool, /** Applies a data-hook HTML attribute to be used in the tests */ dataHook: PropTypes.string, /** Applies a CSS class to the component’s root element */ className: PropTypes.string, /** Defines a callback function which is called when a Popover menu is opened */ onShow: PropTypes.func, /** Defines a callback function which is called when a Popover menu is closed */ onHide: PropTypes.func, }; PopoverMenu.defaultProps = { maxWidth: 204, minWidth: 144, placement: 'bottom', appendTo: 'window', textSize: 'medium', fixed: true, flip: true, showArrow: true, ellipsis: false, maxHeight: 'auto', }; PopoverMenu.MenuItem.displayName = 'PopoverMenu.MenuItem'; PopoverMenu.Divider.displayName = 'PopoverMenu.Divider'; export default PopoverMenu; //# sourceMappingURL=PopoverMenu.js.map