UNPKG

@cimpress/react-components

Version:
241 lines (239 loc) 11.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Tooltip = void 0; const react_1 = __importStar(require("react")); const react_tether_1 = __importDefault(require("react-tether")); const lodash_debounce_1 = __importDefault(require("lodash.debounce")); const css_1 = require("@emotion/css"); const cvar_1 = __importDefault(require("./theme/cvar")); const attachments = { top: 'bottom center', bottom: 'top center', left: 'middle right', right: 'middle left', }; const targetAttachments = { top: 'top center', bottom: 'bottom center', left: 'middle left', right: 'middle right', }; // The tooltip arrows sit inside their container's padding space, so they must use the same value const tooltipArrowSize = (0, cvar_1.default)('spacing-8'); const tooltipColor = (0, cvar_1.default)('color-tooltip-default'); const tetherStyle = (0, css_1.css) ` z-index: 2000; pointer-events: none; * { pointer-events: auto; } `; const baseTooltipStyle = (direction) => (0, css_1.css) ` display: block; ${`margin-${direction}`}: 3px; padding: ${direction === 'top' || direction === 'bottom' ? `${tooltipArrowSize} 0` : `0 ${tooltipArrowSize}`}; `; const tooltipContentStyle = (0, css_1.css) ` background-color: ${tooltipColor}; border-radius: 2px; box-shadow: 0 4px 4px rgba(0, 0, 0, 0.2); color: #fff; font: ${(0, cvar_1.default)('text-label-default')}; max-width: 200px; padding: ${(0, cvar_1.default)('spacing-12')} ${(0, cvar_1.default)('spacing-16')}; text-align: center; `; const popoverContentStyle = (0, css_1.css) ` background-color: ${(0, cvar_1.default)('color-background')}; border-radius: 2px; border: 1px solid ${(0, cvar_1.default)('color-border-default')}; box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); font: ${(0, cvar_1.default)('text-paragraph-default')}; padding: ${(0, cvar_1.default)('spacing-8')} ${(0, cvar_1.default)('spacing-16')}; `; const directedArrowStyle = (direction, isPopover) => { const opposite = { left: 'right', right: 'left', top: 'bottom', bottom: 'top', }[direction]; const centerDirection = direction === 'top' || direction === 'bottom' ? 'left' : 'top'; const borderColor = isPopover ? (0, cvar_1.default)('color-border-default') : tooltipColor; return (0, css_1.css) ` border-width: ${tooltipArrowSize}; border-color: transparent; border-style: solid; position: absolute; ${opposite}: 1px; ${`border-${opposite}-width: 0px;`} ${`border-${direction}-color: ${borderColor};`} ${centerDirection}: 50%; ${`margin-${centerDirection}: calc(-1 * ${tooltipArrowSize})`}; ${isPopover ? ` &::after { content: ' '; border: 7px solid transparent; position: absolute; bottom: 1px; ${`border-${opposite}-width: 0px;`} ${`border-${direction}-color: ${(0, cvar_1.default)('color-background')};`} ${`margin-${centerDirection}: calc(-1 * calc(${tooltipArrowSize} - 1px))`}; }` : null} `; }; const Tooltip = (_a) => { var { children, contents = '', direction = 'top', style = {}, className = '', containerClassName = '', variety, variant = 'tooltip', tooltipStyle = {}, tooltipInnerStyle = {}, show, delay = 0, constraints = [ { to: 'window', attachment: 'together', pin: ['left', 'right'], }, ], onClickOutside, // Default to maintain compatibility with react-onclickoutside API outsideClickIgnoreClass = 'ignore-react-onclickoutside' } = _a, rest = __rest(_a, ["children", "contents", "direction", "style", "className", "containerClassName", "variety", "variant", "tooltipStyle", "tooltipInnerStyle", "show", "delay", "constraints", "onClickOutside", "outsideClickIgnoreClass"]); const targetRef = (0, react_1.useRef)(); const elementRef = (0, react_1.useRef)(); const tether = (0, react_1.useRef)(null); const [showState, setShowState] = (0, react_1.useState)(show || false); // only used to prevent Tether from rendering on the first render due to perf issues. const [showInitialState, setShowInitialState] = (0, react_1.useState)(show || false); const toggleTether = (enable) => { if (tether.current && tether.current.getTetherInstance()) { if (enable) { tether.current.enable(); tether.current.position(); } else { tether.current.disable(); } } }; const setShowFlag = (value) => { const newShowState = show !== undefined ? show : value; toggleTether(newShowState); setShowState(newShowState); }; const debouncedClose = (0, lodash_debounce_1.default)(close, 50); const debouncedOpen = (0, lodash_debounce_1.default)(open, delay); function open() { debouncedClose.cancel(); setShowFlag(true); } function close() { debouncedOpen.cancel(); setShowFlag(false); } (0, react_1.useEffect)(() => { if (show !== undefined) { setShowState(show); } }, [show, setShowState]); (0, react_1.useEffect)(() => { if (!showState) { toggleTether(false); } }, [showState, toggleTether]); const setShowInitial = () => { setShowInitialState(true); }; function attachTarget(ref) { if (ref.current) { targetRef.current = ref.current; } return ref; } function attachElement(ref) { if (ref.current) { elementRef.current = ref.current; } return ref; } const onClickOutsideRef = (0, react_1.useRef)(onClickOutside); (0, react_1.useLayoutEffect)(() => { onClickOutsideRef.current = onClickOutside; }, [onClickOutside]); const outsideClickIgnoreClassRef = (0, react_1.useRef)(outsideClickIgnoreClass); (0, react_1.useLayoutEffect)(() => { outsideClickIgnoreClassRef.current = outsideClickIgnoreClass; }, [outsideClickIgnoreClass]); (0, react_1.useEffect)(() => { const controller = new AbortController(); const { signal } = controller; if (onClickOutsideRef.current && showState) { document.addEventListener('click', e => { var _a, _b; const shouldIgnoreClickOnIgnoredClass = !(e.target instanceof HTMLElement) || e.target.classList.contains(outsideClickIgnoreClassRef.current); if (elementRef.current && !elementRef.current.contains(e.target) && !((_a = targetRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target)) && !shouldIgnoreClickOnIgnoredClass) { (_b = onClickOutsideRef.current) === null || _b === void 0 ? void 0 : _b.call(onClickOutsideRef); } }, { signal }); } return () => { controller.abort(); }; }, [showState]); const isPopover = (variant || variety) === 'popover'; const popover = isPopover ? { display: 'block' } : {}; if (showInitialState || showState) { return (react_1.default.createElement(react_tether_1.default, { style: style, ref: tether, classPrefix: "tether-tooltip", attachment: attachments[direction], targetAttachment: targetAttachments[direction], constraints: constraints, className: (0, css_1.cx)('crc-tooltip-tether', tetherStyle), renderTarget: ref => (react_1.default.createElement("div", { ref: attachTarget(ref), style: Object.assign({ display: 'inline-block' }, style), onMouseEnter: debouncedOpen, onMouseOver: debouncedOpen, onFocus: debouncedOpen, onMouseOut: debouncedClose, onMouseLeave: debouncedClose, onBlur: debouncedClose, className: (0, css_1.cx)(isPopover ? 'crc-tooltip__container crc-tooltip__container--popover' : 'crc-tooltip__container', containerClassName) }, children)), renderElement: ref => (react_1.default.createElement("div", { ref: attachElement(ref), className: (0, css_1.cx)(isPopover ? 'crc-tooltip crc-tooltip--popover' : 'crc-tooltip', baseTooltipStyle(direction), className), role: "tooltip", style: Object.assign(Object.assign({ visibility: showState ? 'visible' : 'hidden' }, popover), tooltipStyle), onMouseEnter: debouncedOpen, onMouseOver: debouncedOpen, onFocus: debouncedOpen, onMouseOut: debouncedClose, onMouseLeave: debouncedClose, onBlur: debouncedClose }, react_1.default.createElement("div", { className: (0, css_1.cx)(isPopover ? 'crc-tooltip__arrow crc-tooltip__arrow--popover' : 'crc-tooltip__arrow', directedArrowStyle(direction, isPopover)) }), react_1.default.createElement("div", { className: isPopover ? (0, css_1.cx)('crc-tooltip__content crc-tooltip__content--popover', popoverContentStyle) : (0, css_1.cx)('crc-tooltip__content', tooltipContentStyle), style: Object.assign({}, tooltipInnerStyle) }, contents))) })); } const propsWithoutTooltipSpecificOnes = Object.fromEntries(Object.entries(rest).filter(k => ![ 'disableOnClickOutside', 'stopPropagation', 'enableOnClickOutside', 'preventDefault', 'outsideClickIgnoreClass', 'eventTypes', 'onClickOutside', ].includes(k[0]))); return (react_1.default.createElement("div", Object.assign({ style: Object.assign({ display: 'inline-block' }, style), onMouseEnter: setShowInitial, onMouseOver: setShowInitial, onFocus: debouncedOpen, className: containerClassName }, propsWithoutTooltipSpecificOnes), children)); }; exports.Tooltip = Tooltip; //# sourceMappingURL=Tooltip.js.map