@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
253 lines (252 loc) • 9.52 kB
JavaScript
"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