UNPKG

@jstarpl/react-contextmenu

Version:
301 lines (253 loc) 9.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _objectAssign = _interopRequireDefault(require("object-assign")); var _actions = require("./actions"); var _AbstractMenu = _interopRequireDefault(require("./AbstractMenu")); var _helpers = require("./helpers"); var _globalEventListener = _interopRequireDefault(require("./globalEventListener")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } class SubMenu extends _AbstractMenu.default { constructor(props) { super(props); _defineProperty(this, "getMenuPosition", () => { const { innerWidth, innerHeight } = window; const rect = this.subMenu.getBoundingClientRect(); const position = {}; if (rect.bottom > innerHeight) { position.bottom = 0; } else { position.top = 0; } if (rect.right < innerWidth) { position.left = '100%'; } else { position.right = '100%'; } return position; }); _defineProperty(this, "getRTLMenuPosition", () => { const { innerHeight } = window; const rect = this.subMenu.getBoundingClientRect(); const position = {}; if (rect.bottom > innerHeight) { position.bottom = 0; } else { position.top = 0; } // eslint-disable-next-line no-magic-numbers if (rect.left < 0) { position.left = '100%'; } else { position.right = '100%'; } return position; }); _defineProperty(this, "hideMenu", e => { e.preventDefault(); this.hideSubMenu(e); }); _defineProperty(this, "hideSubMenu", e => { // avoid closing submenus of a different menu tree if (e.detail && e.detail.id && this.menu && e.detail.id !== this.menu.id) { return; } if (this.props.forceOpen) { this.props.forceClose(); } this.setState({ visible: false, selectedItem: null }); this.unregisterHandlers(); }); _defineProperty(this, "handleClick", event => { event.preventDefault(); if (this.props.disabled) return; (0, _helpers.callIfExists)(this.props.onClick, event, (0, _objectAssign.default)({}, this.props.data, _helpers.store.data), _helpers.store.target); if (!this.props.onClick || this.props.preventCloseOnClick) return; (0, _actions.hideMenu)(); }); _defineProperty(this, "handleMouseEnter", () => { if (this.closetimer) clearTimeout(this.closetimer); if (this.props.disabled || this.state.visible) return; this.opentimer = setTimeout(() => this.setState({ visible: true, selectedItem: null }), this.props.hoverDelay); }); _defineProperty(this, "handleMouseLeave", () => { if (this.opentimer) clearTimeout(this.opentimer); if (!this.state.visible) return; this.closetimer = setTimeout(() => this.setState({ visible: false, selectedItem: null }), this.props.hoverDelay); }); _defineProperty(this, "menuRef", c => { this.menu = c; }); _defineProperty(this, "subMenuRef", c => { this.subMenu = c; }); _defineProperty(this, "registerHandlers", () => { document.removeEventListener('keydown', this.props.parentKeyNavigationHandler); document.addEventListener('keydown', this.handleKeyNavigation); }); _defineProperty(this, "unregisterHandlers", dismounting => { document.removeEventListener('keydown', this.handleKeyNavigation); if (!dismounting) { document.addEventListener('keydown', this.props.parentKeyNavigationHandler); } }); this.state = (0, _objectAssign.default)({}, this.state, { visible: false }); } componentDidMount() { this.listenId = _globalEventListener.default.register(() => {}, this.hideSubMenu); } getSubMenuType() { // eslint-disable-line class-methods-use-this return SubMenu; } shouldComponentUpdate(nextProps, nextState) { this.isVisibilityChange = (this.state.visible !== nextState.visible || this.props.forceOpen !== nextProps.forceOpen) && !(this.state.visible && nextProps.forceOpen) && !(this.props.forceOpen && nextState.visible); return true; } componentDidUpdate() { if (!this.isVisibilityChange) return; if (this.props.forceOpen || this.state.visible) { const wrapper = window.requestAnimationFrame || setTimeout; wrapper(() => { const styles = this.props.rtl ? this.getRTLMenuPosition() : this.getMenuPosition(); this.subMenu.style.removeProperty('top'); this.subMenu.style.removeProperty('bottom'); this.subMenu.style.removeProperty('left'); this.subMenu.style.removeProperty('right'); if ((0, _helpers.hasOwnProp)(styles, 'top')) this.subMenu.style.top = styles.top; if ((0, _helpers.hasOwnProp)(styles, 'left')) this.subMenu.style.left = styles.left; if ((0, _helpers.hasOwnProp)(styles, 'bottom')) this.subMenu.style.bottom = styles.bottom; if ((0, _helpers.hasOwnProp)(styles, 'right')) this.subMenu.style.right = styles.right; this.subMenu.classList.add(_helpers.cssClasses.menuVisible); this.registerHandlers(); this.setState({ selectedItem: null }); }); } else { const cleanup = () => { this.subMenu.removeEventListener('transitionend', cleanup); this.subMenu.style.removeProperty('bottom'); this.subMenu.style.removeProperty('right'); this.subMenu.style.top = 0; this.subMenu.style.left = '100%'; this.unregisterHandlers(); }; this.subMenu.addEventListener('transitionend', cleanup); this.subMenu.classList.remove(_helpers.cssClasses.menuVisible); } } componentWillUnmount() { if (this.listenId) { _globalEventListener.default.unregister(this.listenId); } if (this.opentimer) clearTimeout(this.opentimer); if (this.closetimer) clearTimeout(this.closetimer); this.unregisterHandlers(true); } render() { const { children, attributes, disabled, title, selected } = this.props; const { visible } = this.state; const menuProps = { ref: this.menuRef, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, className: (0, _classnames.default)(_helpers.cssClasses.menuItem, _helpers.cssClasses.subMenu, attributes.listClassName), style: { position: 'relative' } }; const menuItemProps = { className: (0, _classnames.default)(_helpers.cssClasses.menuItem, attributes.className, { [(0, _classnames.default)(_helpers.cssClasses.menuItemDisabled, attributes.disabledClassName)]: disabled, [(0, _classnames.default)(_helpers.cssClasses.menuItemActive, attributes.visibleClassName)]: visible, [(0, _classnames.default)(_helpers.cssClasses.menuItemSelected, attributes.selectedClassName)]: selected }), onMouseMove: this.props.onMouseMove, onMouseOut: this.props.onMouseOut, onClick: this.handleClick }; const subMenuProps = { ref: this.subMenuRef, style: { position: 'absolute', transition: 'opacity 1ms', // trigger transitionend event top: 0, left: '100%' }, className: (0, _classnames.default)(_helpers.cssClasses.menu, this.props.className) }; return ( /*#__PURE__*/ // eslint-disable-next-line react/jsx-props-no-spreading _react.default.createElement("nav", _extends({}, menuProps, { role: "menuitem", tabIndex: "-1", "aria-haspopup": "true" }), /*#__PURE__*/_react.default.createElement("div", _extends({}, attributes, menuItemProps), title), /*#__PURE__*/_react.default.createElement("nav", _extends({}, subMenuProps, { role: "menu", tabIndex: "-1" }), this.renderChildren(children))) ); } } exports.default = SubMenu; _defineProperty(SubMenu, "propTypes", { children: _propTypes.default.node.isRequired, attributes: _propTypes.default.object, title: _propTypes.default.node.isRequired, className: _propTypes.default.string, disabled: _propTypes.default.bool, hoverDelay: _propTypes.default.number, rtl: _propTypes.default.bool, selected: _propTypes.default.bool, onMouseMove: _propTypes.default.func, onMouseOut: _propTypes.default.func, forceOpen: _propTypes.default.bool, forceClose: _propTypes.default.func, parentKeyNavigationHandler: _propTypes.default.func }); _defineProperty(SubMenu, "defaultProps", { disabled: false, hoverDelay: 500, attributes: {}, className: '', rtl: false, selected: false, onMouseMove: () => null, onMouseOut: () => null, forceOpen: false, forceClose: () => null, parentKeyNavigationHandler: () => null });