UNPKG

@xcritical/popover

Version:
439 lines (395 loc) 15.4 kB
import React, { memo, useRef, useState, useMemo, useCallback, useEffect } from 'react'; import ResizeObserver from 'resize-observer-polyfill'; import Popper from '@xcritical/popper'; import styled from 'styled-components'; import { getAppearanceTheme } from '@xcritical/theme'; 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 _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _taggedTemplateLiteralLoose(strings, raw) { if (!raw) { raw = strings.slice(0); } strings.raw = raw; return strings; } var popoverThemeNamespace = '@xcritical\\xc-popover'; var defaultPopoverTheme = { content: { offset: '5px', background: '#fff', padding: '5px', border: '1px solid #ddd', borderRadius: '2px' }, arrow: { offset: '10px', size: '5px', background: '#fff', border: { width: '1px', color: '#ddd' } }, wrapper: { cursor: 'pointer' } }; var _excluded = ["offset"]; var getPopperProperty = function getPopperProperty(_ref) { var theme = _ref.theme, appearance = _ref.appearance, baseAppearance = _ref.baseAppearance; var func = getAppearanceTheme(popoverThemeNamespace, defaultPopoverTheme); return function (propertyPath) { return func(theme, appearance, propertyPath, baseAppearance); }; }; var getContentStyles = function getContentStyles(props) { // eslint-disable-next-line @typescript-eslint/no-unused-vars var _getPopperProperty = getPopperProperty(props)(['content']), contentStyles = _objectWithoutPropertiesLoose(_getPopperProperty, _excluded); return contentStyles; }; var getArrowSizes = function getArrowSizes(props, arrowDirection) { var size = getPopperProperty(props)(['arrow', 'size']); switch (arrowDirection) { case 'top': case 'bottom': { return { width: "calc(" + size + " * 2)", height: size }; } case 'right': case 'left': { return { width: size, height: "calc(" + size + " * 2)" }; } default: return { width: '0', height: '0' }; } }; var getArrowBorderWidth = function getArrowBorderWidth(props, arrowDirection) { var size = getPopperProperty(props)(['arrow', 'size']); switch (arrowDirection) { case 'top': return size + " " + size + " 0 " + size; case 'right': return size + " " + size + " " + size + " 0"; case 'bottom': return "0 " + size + " " + size + " " + size; case 'left': return size + " 0 " + size + " " + size; default: return ''; } }; var _templateObject; var Content = /*#__PURE__*/styled.div(_templateObject || (_templateObject = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n box-sizing: border-box;\n\n &[data-content-position^='top'] {\n margin-bottom: ", ";\n }\n\n &[data-content-position^='right'] {\n margin-left: ", ";\n }\n\n &[data-content-position^='bottom'] {\n margin-top: ", ";\n }\n\n &[data-content-position^='left'] {\n margin-right: ", ";\n }\n\n width: ", ";\n\n ", "\n"])), function (props) { return getPopperProperty(props)(['content', 'offset']); }, function (props) { return getPopperProperty(props)(['content', 'offset']); }, function (props) { return getPopperProperty(props)(['content', 'offset']); }, function (props) { return getPopperProperty(props)(['content', 'offset']); }, function (_ref) { var shouldFitContainer = _ref.shouldFitContainer; return shouldFitContainer ? '100%' : 'auto'; }, function (props) { return getContentStyles(props); }); var _templateObject$1; var Arrow = /*#__PURE__*/styled.div(_templateObject$1 || (_templateObject$1 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n position: absolute;\n display: block;\n\n &:before,\n &:after {\n content: '';\n display: block;\n position: absolute;\n border-color: transparent;\n border-style: solid;\n }\n\n &[data-arrow-position^='top'] {\n ", ";\n margin: 0 ", ";\n bottom: ", ";\n\n &:before {\n border-width: ", ";\n border-top-color: ", ";\n }\n\n &:after {\n bottom: ", ";\n border-width: ", ";\n border-top-color: ", ";\n }\n }\n\n &[data-arrow-position^='right'] {\n ", ";\n margin: ", " 0;\n left: ", ";\n\n &:before {\n border-width: ", ";\n border-right-color: ", ";\n }\n\n &:after {\n left: ", ";\n border-width: ", ";\n border-right-color: ", ";\n }\n }\n\n &[data-arrow-position^='bottom'] {\n ", ";\n margin: 0 ", ";\n top: ", ";\n\n &:before {\n border-width: ", ";\n border-bottom-color: ", ";\n }\n\n &:after {\n top: ", ";\n border-width: ", ";\n border-bottom-color: ", ";\n }\n }\n\n &[data-arrow-position^='left'] {\n ", ";\n margin: ", " 0;\n right: ", ";\n\n &:before {\n border-width: ", ";\n border-left-color: ", ";\n }\n\n &:after {\n right: ", ";\n border-width: ", ";\n border-left-color: ", ";\n }\n }\n"])), function (props) { return getArrowSizes(props, 'top'); }, function (props) { return getPopperProperty(props)(['arrow', 'offset']); }, function (props) { return "-" + getPopperProperty(props)(['arrow', 'size']); }, function (props) { return getArrowBorderWidth(props, 'top'); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'color']); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'width']); }, function (props) { return getArrowBorderWidth(props, 'top'); }, function (props) { return getPopperProperty(props)(['arrow', 'background']); }, function (props) { return getArrowSizes(props, 'right'); }, function (props) { return getPopperProperty(props)(['arrow', 'offset']); }, function (props) { return "-" + getPopperProperty(props)(['arrow', 'size']); }, function (props) { return getArrowBorderWidth(props, 'right'); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'color']); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'width']); }, function (props) { return getArrowBorderWidth(props, 'right'); }, function (props) { return getPopperProperty(props)(['arrow', 'background']); }, function (props) { return getArrowSizes(props, 'bottom'); }, function (props) { return getPopperProperty(props)(['arrow', 'offset']); }, function (props) { return "-" + getPopperProperty(props)(['arrow', 'size']); }, function (props) { return getArrowBorderWidth(props, 'bottom'); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'color']); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'width']); }, function (props) { return getArrowBorderWidth(props, 'bottom'); }, function (props) { return getPopperProperty(props)(['arrow', 'background']); }, function (props) { return getArrowSizes(props, 'left'); }, function (props) { return getPopperProperty(props)(['arrow', 'offset']); }, function (props) { return "-" + getPopperProperty(props)(['arrow', 'size']); }, function (props) { return getArrowBorderWidth(props, 'left'); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'color']); }, function (props) { return getPopperProperty(props)(['arrow', 'border', 'width']); }, function (props) { return getArrowBorderWidth(props, 'left'); }, function (props) { return getPopperProperty(props)(['arrow', 'background']); }); var _templateObject$2; var PopoverWrapper = /*#__PURE__*/styled.div(_templateObject$2 || (_templateObject$2 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n position: relative;\n ", "\n"])), function (props) { return getPopperProperty(props)(['wrapper']); }); var Popover = /*#__PURE__*/memo(function (_ref) { var position = _ref.position, content = _ref.content, autoFlip = _ref.autoFlip, positionFixed = _ref.positionFixed, children = _ref.children, visible = _ref.visible, onVisibleChange = _ref.onVisibleChange, _ref$withArrow = _ref.withArrow, withArrow = _ref$withArrow === void 0 ? true : _ref$withArrow, convertStyles = _ref.convertStyles, _ref$shouldFitContain = _ref.shouldFitContainer, shouldFitContainer = _ref$shouldFitContain === void 0 ? false : _ref$shouldFitContain, _ref$autoContentSize = _ref.autoContentSize, autoContentSize = _ref$autoContentSize === void 0 ? false : _ref$autoContentSize, _ref$preventOverflowV = _ref.preventOverflowViewport, preventOverflowViewport = _ref$preventOverflowV === void 0 ? false : _ref$preventOverflowV, _ref$hoverOutTimeout = _ref.hoverOutTimeout, hoverOutTimeout = _ref$hoverOutTimeout === void 0 ? 150 : _ref$hoverOutTimeout, _ref$trigger = _ref.trigger, trigger = _ref$trigger === void 0 ? 'hover' : _ref$trigger, theme = _ref.theme, _ref$appearance = _ref.appearance, appearance = _ref$appearance === void 0 ? 'default' : _ref$appearance, _ref$baseAppearance = _ref.baseAppearance, baseAppearance = _ref$baseAppearance === void 0 ? 'default' : _ref$baseAppearance, className = _ref.className, classNamePrefix = _ref.classNamePrefix, onOutsideClick = _ref.onOutsideClick; var popoverTargetRef = useRef(); var popoverContentRef = useRef(); var popperScheduleUpdateRef = useRef(); var popoverContentObserverRef = useRef(); var _useState = useState(false), _visible = _useState[0], _setVisible = _useState[1]; var _useState2 = useState(null), hideTimeoutId = _useState2[0], setHideTimeoutId = _useState2[1]; var popperModifiers = useMemo(function () { if (preventOverflowViewport) { return { preventOverflow: { boundariesElement: 'viewport' } }; } return {}; }, [preventOverflowViewport]); var changeVisible = useCallback(function (newVisible) { if (onVisibleChange) { onVisibleChange(newVisible); } }, [onVisibleChange]); var handleClick = useCallback(function (e) { if (popoverContentRef.current && popoverContentRef.current.contains(e.target)) { return; } if (e.target === popoverTargetRef.current) { _setVisible(false); changeVisible(false); return; } if (popoverTargetRef.current && popoverTargetRef.current.contains(e.target)) { _setVisible(!_visible); changeVisible(!_visible); return; } _setVisible(false); changeVisible(false); }, [_visible, changeVisible]); var handleClickOutside = useCallback(function (e) { if (popoverContentRef.current && !popoverContentRef.current.contains(e.target) && !!onOutsideClick) { onOutsideClick(e); } }, [onOutsideClick]); var handleMouseOver = useCallback(function (e) { if (e.target === popoverTargetRef.current) { return; } if (hideTimeoutId) { clearTimeout(hideTimeoutId); } _setVisible(true); changeVisible(true); }, [hideTimeoutId, changeVisible]); var handleMouseOut = useCallback(function () { var timeoutId = window.setTimeout(function () { _setVisible(false); changeVisible(false); }, hoverOutTimeout); setHideTimeoutId(timeoutId); }, [changeVisible, hoverOutTimeout]); var createContentObserver = useCallback(function () { if (popoverContentRef.current) { var observer = new ResizeObserver(function () { if (popperScheduleUpdateRef.current) { popperScheduleUpdateRef.current(); } }); popoverContentObserverRef.current = observer; observer.observe(popoverContentRef.current); } }, []); var destroyContentObserver = useCallback(function () { if (popoverContentObserverRef.current) { popoverContentObserverRef.current.disconnect(); } }, []); var isVisible = visible === undefined ? _visible : visible; var events = {}; if (trigger === 'hover') { events.onMouseOver = handleMouseOver; events.onMouseOut = handleMouseOut; } useEffect(function () { if (autoContentSize) { if (isVisible) { createContentObserver(); } else { destroyContentObserver(); } } }, [autoContentSize, isVisible, createContentObserver, destroyContentObserver]); useEffect(function () { return function () { if (autoContentSize) { destroyContentObserver(); } }; }, [autoContentSize, destroyContentObserver]); useEffect(function () { if (trigger === 'click') { document.addEventListener('click', handleClick); return function () { document.removeEventListener('click', handleClick); }; } return function () {}; }, [trigger, handleClick]); useEffect(function () { if (onOutsideClick) { document.addEventListener('mousedown', handleClickOutside); return function () { return document.removeEventListener('mousedown', handleClickOutside); }; } return function () {}; }, [handleClickOutside, onOutsideClick]); return React.createElement(Popper, { position: position, autoFlip: autoFlip, positionFixed: positionFixed, visible: isVisible, modifiers: popperModifiers }, function (popperProps) { popperScheduleUpdateRef.current = popperProps.scheduleUpdate; return React.createElement(PopoverWrapper, _extends({ className: className && className + "__wrapper", theme: theme, appearance: appearance, baseAppearance: baseAppearance, ref: function ref(node) { var targetRef = popperProps.targetRef; targetRef.current = node == null ? void 0 : node.firstChild; popoverTargetRef.current = node; } }, events), children, popperProps.visible && React.createElement(Content, { className: classNamePrefix && classNamePrefix + "__content", ref: function ref(node) { var contentRef = popperProps.contentRef; contentRef.current = node; popoverContentRef.current = node; }, "data-content-position": popperProps.position, shouldFitContainer: shouldFitContainer, theme: theme, appearance: appearance, baseAppearance: baseAppearance, style: convertStyles ? convertStyles(popperProps.popperStyles) : popperProps.popperStyles }, content, withArrow && React.createElement(Arrow, { className: classNamePrefix && classNamePrefix + "__arrow", "x-arrow": "", style: popperProps.arrowStyles, "data-arrow-position": popperProps.position, theme: theme, appearance: appearance, baseAppearance: baseAppearance }))); }); }); export { Popover, popoverThemeNamespace }; //# sourceMappingURL=popover.esm.js.map