UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

253 lines (252 loc) 9.52 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _classnames = _interopRequireDefault(require("classnames")); var _componentHelper = require("../../shared/component-helper.js"); var _TooltipHelpers = require("./TooltipHelpers.js"); var _Popover = _interopRequireDefault(require("../popover/Popover.js")); var _getRefElement = _interopRequireDefault(require("../../shared/internal/getRefElement.js")); var _TooltipContext = require("./TooltipContext.js"); var _AriaLive = _interopRequireDefault(require("../AriaLive.js")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function TooltipWithEvents(props) { const { children, attributes, ...restProps } = props; const { active, target, skipPortal, noAnimation, showDelay, hideDelay, arrow, position, align, fixedPosition, portalRootClass, triggerOffset, contentRef, size, keepInDOM = false, targetRefreshKey, forceActive } = restProps; const { internalId, isControlled } = (0, _react.useContext)(_TooltipContext.TooltipContext); const [isActive, setIsActive] = (0, _react.useState)(active); const [isOverlayHovered, setOverlayHovered] = (0, _react.useState)(false); const delayTimeout = (0, _react.useRef)(); const overlayDelayTimeout = (0, _react.useRef)(); const cloneRef = (0, _react.useRef)(); const previousDescribedByIdRef = (0, _react.useRef)(null); const clearTimers = () => { clearTimeout(delayTimeout.current); }; const onMouseEnter = (0, _react.useCallback)(e => { try { const elem = e.currentTarget; if (elem.getAttribute('data-autofocus')) { return; } if ((0, _TooltipHelpers.isTouch)(e.type)) { elem.style.userSelect = 'none'; } } catch (e) { (0, _componentHelper.warn)(e); } const run = () => { setIsActive(true); }; if (noAnimation || globalThis.IS_TEST) { run(); } else { clearTimers(); delayTimeout.current = setTimeout(run, parseFloat(String(showDelay)) || 1); } }, [noAnimation, showDelay]); const onFocus = (0, _react.useCallback)(e => { return onMouseEnter(e); }, [onMouseEnter]); const onMouseLeave = (0, _react.useCallback)(e => { if (active) { return; } try { if ((0, _TooltipHelpers.isTouch)(e.type)) { const elem = e.currentTarget; elem.style.userSelect = ''; } } catch (e) { (0, _componentHelper.warn)(e); } clearTimers(); const run = () => { setIsActive(false); }; if (skipPortal) { delayTimeout.current = setTimeout(run, parseFloat(String(hideDelay))); } else { run(); } }, [active, hideDelay, skipPortal]); const addEvents = (0, _react.useCallback)(element => { try { element.addEventListener('focus', onFocus); element.addEventListener('blur', onMouseLeave); element.addEventListener('mouseenter', onMouseEnter); element.addEventListener('mouseleave', onMouseLeave); element.addEventListener('touchstart', onMouseEnter); element.addEventListener('touchend', onMouseLeave); } catch (e) { (0, _componentHelper.warn)(e); } }, [onFocus, onMouseLeave, onMouseEnter]); const removeEvents = (0, _react.useCallback)(element => { if (!(element instanceof HTMLElement)) { return; } try { element.removeEventListener('focus', onFocus); element.removeEventListener('blur', onMouseLeave); element.removeEventListener('mouseenter', onMouseEnter); element.removeEventListener('mouseleave', onMouseLeave); element.removeEventListener('touchstart', onMouseEnter); element.removeEventListener('touchend', onMouseLeave); } catch (e) { (0, _componentHelper.warn)(e); } }, [onFocus, onMouseEnter, onMouseLeave]); const overlayActive = Boolean(isActive || isOverlayHovered || forceActive); const describedById = overlayActive ? internalId : null; const componentWrapper = (0, _react.useMemo)(() => { if ((0, _react.isValidElement)(target)) { return (0, _react.cloneElement)(target, { ref: cloneRef, 'aria-describedby': (0, _componentHelper.combineDescribedBy)(target.props['aria-describedby'], describedById) }); } cloneRef.current = target; return null; }, [describedById, target]); (0, _react.useEffect)(() => { if (!target) { return () => clearTimers(); } const element = (0, _getRefElement.default)(cloneRef); if (!(element instanceof HTMLElement) || isControlled) { return () => clearTimers(); } addEvents(element); return () => { clearTimers(); removeEvents(element); }; }, [addEvents, removeEvents, isControlled, target]); (0, _react.useEffect)(() => { if (isControlled) { setIsActive(active); } }, [active, isControlled]); (0, _react.useEffect)(() => { const targetElement = (0, _getRefElement.default)(cloneRef); if (!(targetElement instanceof HTMLElement)) { previousDescribedByIdRef.current = null; return; } const updateAriaDescribedBy = nextId => { var _targetElement$getAtt, _targetElement$getAtt2; const existingValues = (_targetElement$getAtt = (_targetElement$getAtt2 = targetElement.getAttribute('aria-describedby')) === null || _targetElement$getAtt2 === void 0 ? void 0 : _targetElement$getAtt2.split(/\s+/).map(value => value.trim()).filter(Boolean)) !== null && _targetElement$getAtt !== void 0 ? _targetElement$getAtt : []; const withoutPrevious = previousDescribedByIdRef.current !== null ? existingValues.filter(value => value !== previousDescribedByIdRef.current) : existingValues; let nextValues = withoutPrevious; if (nextId) { nextValues = nextValues.filter(value => value !== nextId); nextValues = [...nextValues, nextId]; } if (nextValues.length > 0) { targetElement.setAttribute('aria-describedby', nextValues.join(' ')); } else { targetElement.removeAttribute('aria-describedby'); } previousDescribedByIdRef.current = nextId; }; updateAriaDescribedBy(describedById); return () => { updateAriaDescribedBy(null); }; }, [cloneRef, describedById, target]); const clearOverlayTimers = () => { clearTimeout(overlayDelayTimeout.current); }; (0, _react.useEffect)(() => clearOverlayTimers, []); const handleOverlayMouseEnter = (0, _react.useCallback)(() => { clearOverlayTimers(); if (!isControlled) { setOverlayHovered(true); } }, [isControlled]); const handleOverlayMouseLeave = (0, _react.useCallback)(() => { if (isControlled) { return; } const run = () => setOverlayHovered(false); clearOverlayTimers(); if (skipPortal) { overlayDelayTimeout.current = setTimeout(run, parseFloat(String(hideDelay)) || 1); } else { run(); } }, [hideDelay, isControlled, skipPortal]); const { className: attributeClassName, ...restAttributes } = attributes || {}; return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(_Popover.default, _extends({ baseClassName: "dnb-tooltip", className: (0, _classnames.default)(attributeClassName, 'dnb-tooltip', size && `dnb-tooltip--${size}`), theme: "dark", id: internalId, open: overlayActive, targetElement: cloneRef, arrowEdgeOffset: 4, hideDelay: hideDelay, skipPortal: skipPortal, keepInDOM: keepInDOM, noAnimation: noAnimation, triggerOffset: triggerOffset, targetRefreshKey: targetRefreshKey, arrowPosition: arrow, placement: position, alignOnTarget: align, fixedPosition: fixedPosition, portalRootClass: portalRootClass, contentClassName: "dnb-tooltip__content", contentRef: contentRef, focusOnOpen: false, restoreFocus: false, preventClose: false, noInnerSpace: true, noMaxWidth: true, hideOutline: true, hideCloseButton: true, disableFocusTrap: true, onMouseEnter: handleOverlayMouseEnter, onMouseLeave: handleOverlayMouseLeave, role: "tooltip" }, restAttributes), children), _react.default.createElement(_AriaLive.default, { element: "span", priority: "low" }, overlayActive ? children : null), componentWrapper); } var _default = exports.default = TooltipWithEvents; //# sourceMappingURL=TooltipWithEvents.js.map