@xcritical/popover
Version:
439 lines (395 loc) • 15.4 kB
JavaScript
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