UNPKG

react-foundation-components

Version:

Foundation Sites components built with the power of React and CSS Modules

497 lines (369 loc) 14.6 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactDom = require('react-dom'); var _elementType = require('react-prop-types/lib/elementType'); var _elementType2 = _interopRequireDefault(_elementType); var _componentOrElement = require('react-prop-types/lib/componentOrElement'); var _componentOrElement2 = _interopRequireDefault(_componentOrElement); var _Overlay = require('react-overlays/lib/Overlay'); var _Overlay2 = _interopRequireDefault(_Overlay); var _Transition = require('react-overlays/lib/Transition'); var _Transition2 = _interopRequireDefault(_Transition); var _offset = require('dom-helpers/query/offset'); var _offset2 = _interopRequireDefault(_offset); var _position = require('dom-helpers/query/position'); var _position2 = _interopRequireDefault(_position); var _ownerDocument = require('react-overlays/lib/utils/ownerDocument'); var _ownerDocument2 = _interopRequireDefault(_ownerDocument); var _getContainer = require('react-overlays/lib/utils/getContainer'); var _getContainer2 = _interopRequireDefault(_getContainer); var _contains = require('dom-helpers/query/contains'); var _contains2 = _interopRequireDefault(_contains); var _style = require('dom-helpers/style'); var _style2 = _interopRequireDefault(_style); var _debounce = require('lodash/debounce'); var _debounce2 = _interopRequireDefault(_debounce); var _constants = require('../constants'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function mouseOverOut(event, callback) { var target = event.currentTarget; var related = event.relatedTarget || event.nativeEvent.toElement; if (!related || related !== target && !(0, _contains2.default)(target, related)) { callback(event); } } function showOverlay(state) { var showClick = state.showClick, showFocus = state.showFocus, showHover = state.showHover, overlayHoverCount = state.overlayHoverCount; return showClick || showFocus || showHover || overlayHoverCount > 0; } function adjustPosition(elem, getOverlayTarget, getOverlayContainer, position, alignment) { var target = getOverlayTarget(); var container = getOverlayContainer(); var targetPosition = container.tagName === 'BODY' ? (0, _offset2.default)(target) : (0, _position2.default)(target, container); if (position === 'top') { (0, _style2.default)(elem, 'top', targetPosition.top - parseInt((0, _style2.default)(elem, 'height'), 10) + 'px'); } else if (position === 'bottom') { (0, _style2.default)(elem, 'top', targetPosition.top + targetPosition.height + 'px'); } else if (position === 'left') { (0, _style2.default)(elem, 'left', targetPosition.left - parseInt((0, _style2.default)(elem, 'width'), 10) + 'px'); } else if (position === 'right') { (0, _style2.default)(elem, 'left', targetPosition.left + targetPosition.width + 'px'); } if (position === 'top' || position === 'bottom') { var leftOffset = 0; if (alignment !== 'left') { leftOffset = targetPosition.width - parseInt((0, _style2.default)(elem, 'width'), 10); if (alignment !== 'right') { leftOffset /= 2; } } (0, _style2.default)(elem, 'left', targetPosition.left + leftOffset + 'px'); } else if (position === 'left' || position === 'right') { var topOffset = 0; if (alignment !== 'top') { topOffset = targetPosition.height - parseInt((0, _style2.default)(elem, 'height'), 10); if (alignment !== 'bottom') { topOffset /= 2; } } (0, _style2.default)(elem, 'top', targetPosition.top + topOffset + 'px'); } } // This is a hack to align overlay to edges of target instead of always centering it. function hackTransition(CustomTransition, customHandleEntering) { var CombinedTransition = function CombinedTransition(_ref) { var onEntering = _ref.onEntering, props = (0, _objectWithoutProperties3.default)(_ref, ['onEntering']); function handleEntering() { if (customHandleEntering) { customHandleEntering.apply(undefined, arguments); } if (onEntering) { onEntering.apply(undefined, arguments); } } if (CustomTransition) { return _react2.default.createElement(CustomTransition, (0, _extends3.default)({}, props, { onEntering: handleEntering })); } return _react2.default.createElement(_Transition2.default, (0, _extends3.default)({}, props, { onEntering: handleEntering, timeout: 0 })); }; CombinedTransition.propTypes = { onEntering: _propTypes2.default.func }; return CombinedTransition; } var OverlayTrigger = function (_Component) { (0, _inherits3.default)(OverlayTrigger, _Component); function OverlayTrigger(props) { (0, _classCallCheck3.default)(this, OverlayTrigger); var _this = (0, _possibleConstructorReturn3.default)(this, (OverlayTrigger.__proto__ || (0, _getPrototypeOf2.default)(OverlayTrigger)).call(this, props)); _this.state = { showClick: false, showFocus: false, showHover: false, overlayHoverCount: 0 }; _this.getOverlayTarget = function () { return (0, _reactDom.findDOMNode)(_this); }; _this.getOverlayContainer = function () { return (0, _getContainer2.default)(_this.props.container, (0, _ownerDocument2.default)(_this).body); }; _this.handleAnyClick = (0, _debounce2.default)(function (showClick) { var showClickPrev = _this.state.showClick; if (showClick !== showClickPrev) { _this.setState({ showClick: showClick }); } }, 100); _this.handleClick = function () { var _this$props = _this.props, onClick = _this$props.onClick, triggerClick = _this$props.triggerClick; var showClick = _this.state.showClick; if (triggerClick) { _this.handleAnyClick(!showClick); if (onClick) { onClick.apply(undefined, arguments); } } }; _this.handleRootClose = function () { var showClick = _this.state.showClick; if (showClick) { _this.handleAnyClick(false); } }; _this.handleBlur = function () { var _this$props2 = _this.props, onBlur = _this$props2.onBlur, triggerFocus = _this$props2.triggerFocus; var showFocus = _this.state.showFocus; if (triggerFocus) { if (showFocus) { _this.setState({ showFocus: false }); } if (onBlur) { onBlur.apply(undefined, arguments); } } }; _this.handleFocus = function () { var _this$props3 = _this.props, onFocus = _this$props3.onFocus, triggerFocus = _this$props3.triggerFocus; var showFocus = _this.state.showFocus; if (triggerFocus) { if (!showFocus) { _this.setState({ showFocus: true }); } if (onFocus) { onFocus.apply(undefined, arguments); } } }; _this.handleMouseOut = function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var _this$props4 = _this.props, onMouseOut = _this$props4.onMouseOut, triggerHover = _this$props4.triggerHover; var showHover = _this.state.showHover; if (triggerHover) { var event = args[0]; mouseOverOut(event, function () { if (showHover) { _this.setState({ showHover: false }); } if (onMouseOut) { onMouseOut.apply(undefined, args); } }); } }; _this.handleMouseOver = function () { for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } var _this$props5 = _this.props, onMouseOver = _this$props5.onMouseOver, triggerHover = _this$props5.triggerHover; var showHover = _this.state.showHover; if (triggerHover) { var event = args[0]; mouseOverOut(event, function () { if (!showHover) { _this.setState({ showHover: true }); } if (onMouseOver) { onMouseOver.apply(undefined, args); } }); } }; _this.handleOverlayMouseOut = function () { var _this$props6 = _this.props, triggerHover = _this$props6.triggerHover, triggerOverlayHover = _this$props6.triggerOverlayHover; var overlayHoverCount = _this.state.overlayHoverCount; if (triggerHover && triggerOverlayHover) { _this.setState({ overlayHoverCount: overlayHoverCount - 1 }); } }; _this.handleOverlayMouseOver = function () { var _this$props7 = _this.props, triggerHover = _this$props7.triggerHover, triggerOverlayHover = _this$props7.triggerOverlayHover; var overlayHoverCount = _this.state.overlayHoverCount; if (triggerHover && triggerOverlayHover) { _this.setState({ overlayHoverCount: overlayHoverCount + 1 }); } }; _this.handleResize = function () { var _this$props8 = _this.props, position = _this$props8.position, alignment = _this$props8.alignment; var show = showOverlay(_this.state); if (show && _this.elem) { adjustPosition(_this.elem, _this.getOverlayTarget, _this.getOverlayContainer, position, alignment); } }; _this.handleEntering = function (elem) { _this.elem = elem; _this.handleResize(); }; _this._transition = hackTransition(_this.props.transition, _this.handleEntering); _this.createOverlay = function () { var _this$props9 = _this.props, closeOnClickOutside = _this$props9.closeOnClickOutside, overlay = _this$props9.overlay, position = _this$props9.position; var show = showOverlay(_this.state); var clonedOverlay = null; var overalyProps = { onMouseOver: _this.handleOverlayMouseOver, onMouseOut: _this.handleOverlayMouseOut }; if ((0, _react.isValidElement)(overlay)) { clonedOverlay = (0, _react.cloneElement)(overlay, overalyProps); } else { clonedOverlay = _react2.default.createElement( 'span', overalyProps, overlay ); } return _react2.default.createElement( _Overlay2.default, { container: _this.getOverlayContainer, onHide: _this.handleRootClose, placement: position, rootClose: closeOnClickOutside, show: show, target: _this.getOverlayTarget, transition: _this.transition }, clonedOverlay ); }; _this.mountNode = document.createElement('div'); document.body.appendChild(_this.mountNode); return _this; } (0, _createClass3.default)(OverlayTrigger, [{ key: 'componentDidMount', value: function componentDidMount() { var updateWindowResize = this.props.updateWindowResize; if (updateWindowResize) { window.addEventListener('resize', this.handleResize); } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { window.removeEventListener('resize', this.handleResize); (0, _reactDom.unmountComponentAtNode)(this.mountNode); document.body.removeChild(this.mountNode); this.mountNode = null; } }, { key: 'render', value: function render() { var children = this.props.children; var show = this.state.show; var childProps = { 'aria-expanded': show, onBlur: this.handleBlur, onClick: this.handleClick, onFocus: this.handleFocus, onMouseOut: this.handleMouseOut, onMouseOver: this.handleMouseOver }; var clonedChild = null; if ((0, _react.isValidElement)(children)) { clonedChild = (0, _react.cloneElement)(children, childProps); } else { clonedChild = _react2.default.createElement( 'span', childProps, children ); } this.overlay = this.createOverlay(); return _react2.default.createElement( _react.Fragment, null, clonedChild, (0, _reactDom.createPortal)(this.overlay, this.mountNode) ); } }]); return OverlayTrigger; }(_react.Component); OverlayTrigger.propTypes = { alignment: _propTypes2.default.oneOf(_constants.OVERLAY_ALIGNMENTS), children: _propTypes2.default.node, closeOnClickOutside: _propTypes2.default.bool, container: _propTypes2.default.oneOfType([_componentOrElement2.default, _propTypes2.default.func]), onBlur: _propTypes2.default.func, onClick: _propTypes2.default.func, onFocus: _propTypes2.default.func, onMouseOut: _propTypes2.default.func, onMouseOver: _propTypes2.default.func, overlay: _propTypes2.default.node, position: _propTypes2.default.oneOf(_constants.OVERLAY_POSITIONS), transition: _elementType2.default, triggerClick: _propTypes2.default.bool, triggerFocus: _propTypes2.default.bool, triggerHover: _propTypes2.default.bool, triggerOverlayHover: _propTypes2.default.bool, updateWindowResize: _propTypes2.default.bool }; OverlayTrigger.defaultProps = { updateWindowResize: true }; exports.default = OverlayTrigger;