UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

224 lines (223 loc) 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = TooltipContainer; require("core-js/modules/web.dom-collections.iterator.js"); var _react = _interopRequireDefault(require("react")); var _componentHelper = require("../../shared/component-helper"); var _helpers = require("../../shared/helpers"); var _classnames = _interopRequireDefault(require("classnames")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } 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 ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function TooltipContainer(props) { const { internalId, active, attributes, arrow, position, align, hideDelay, fixedPosition, noAnimation, skipPortal, useHover, children, targetElement: target } = props; const [style, setStyle] = _react.default.useState(null); const [arrowStyle, setArrowStyle] = _react.default.useState(null); const [hover, setHover] = _react.default.useState(false); const isActive = (0, _componentHelper.isTrue)(active) || hover; const [wasActive, makeActive] = _react.default.useState(false); const [renewStyles, forceRerender] = _react.default.useState(getBodySize); const elementRef = _react.default.useRef(null); const offset = _react.default.useRef(16); const debounceTimeout = _react.default.useRef(); const resizeObserver = _react.default.useRef(null); function getBodySize() { if (!isActive || typeof document === 'undefined') { return 0; } const { width, height } = document.body.getBoundingClientRect(); return width + height; } const clearTimers = () => { clearTimeout(debounceTimeout.current); }; _react.default.useLayoutEffect(() => { const addPositionObserver = () => { if (resizeObserver.current || typeof document === 'undefined') { return; } try { resizeObserver.current = new ResizeObserver(() => { clearTimers(); debounceTimeout.current = setTimeout(() => forceRerender(getBodySize()), 100); }); resizeObserver.current.observe(document.body); } catch (e) {} }; const removePositionObserver = () => { var _resizeObserver$curre; clearTimers(); (_resizeObserver$curre = resizeObserver.current) === null || _resizeObserver$curre === void 0 ? void 0 : _resizeObserver$curre.disconnect(); }; if (isActive) { makeActive(true); addPositionObserver(); } else { removePositionObserver(); } return removePositionObserver; }, [isActive]); const offsetLeft = _react.default.useRef(0); const offsetTop = _react.default.useRef(0); _react.default.useLayoutEffect(() => { var _stylesFromPosition$p, _stylesFromArrow$arro; if (!isActive) { if (wasActive) { clearTimeout(debounceTimeout.current); debounceTimeout.current = setTimeout(() => setStyle(null), hideDelay); } return; } const element = elementRef === null || elementRef === void 0 ? void 0 : elementRef.current; if (typeof window === 'undefined' || !element || !(target !== null && target !== void 0 && target.getBoundingClientRect)) { return; } let alignOffset = 0; const elementWidth = element.offsetWidth; const elementHeight = element.offsetHeight; const rect = target.getBoundingClientRect(); const targetBodySize = { width: target.offsetWidth, height: target.offsetHeight }; if (!target.offsetHeight) { targetBodySize.width = rect.width; targetBodySize.height = rect.height; } if (skipPortal && (!offsetLeft.current || !offsetTop.current)) { offsetLeft.current = (0, _helpers.getOffsetLeft)(element) - offset.current; offsetTop.current = (0, _helpers.getOffsetTop)(element) - offset.current; } const scrollY = window.scrollY !== undefined ? window.scrollY : window.pageYOffset; const scrollX = window.scrollX !== undefined ? window.scrollX : window.pageXOffset; const top = ((0, _componentHelper.isTrue)(fixedPosition) ? 0 : scrollY) + rect.top - offsetTop.current; const useMouseWhen = targetBodySize.width > 400; const mousePos = (0, _helpers.getOffsetLeft)(target) + rect.left / 2 + (element ? element.offsetWidth : 0); const widthBased = scrollX + rect.left; const left = (useMouseWhen && mousePos < targetBodySize.width ? mousePos : widthBased) - offsetLeft.current; const style = _objectSpread({}, props.style); const arrowStyle = { top: null, left: null }; if (align === 'left') { alignOffset = -targetBodySize.width / 2; } else if (align === 'right') { alignOffset = targetBodySize.width / 2; } const topHorizontal = top + targetBodySize.height / 2 - elementHeight / 2; const leftVertical = left - elementWidth / 2 + targetBodySize.width / 2 + alignOffset; const stylesFromPosition = { left: () => { style.top = topHorizontal; style.left = left - elementWidth - offset.current; }, right: () => { style.top = topHorizontal; style.left = left + targetBodySize.width + offset.current; }, top: () => { style.left = leftVertical; style.top = top - elementHeight - offset.current; }, bottom: () => { style.left = leftVertical; style.top = top + targetBodySize.height + offset.current; } }; const stylesFromArrow = { left: () => { style.left = left + targetBodySize.width / 2 - offset.current + alignOffset; }, right: () => { style.left = left - elementWidth + targetBodySize.width / 2 + offset.current + alignOffset; }, top: () => { style.top = top + targetBodySize.height / 2 - offset.current; }, bottom: () => { style.top = top + targetBodySize.height / 2 - elementHeight + offset.current; } }; (_stylesFromPosition$p = stylesFromPosition[position]) === null || _stylesFromPosition$p === void 0 ? void 0 : _stylesFromPosition$p.call(stylesFromPosition); (_stylesFromArrow$arro = stylesFromArrow[arrow]) === null || _stylesFromArrow$arro === void 0 ? void 0 : _stylesFromArrow$arro.call(stylesFromArrow); const rightOffset = parseFloat(String(style.left)) + elementWidth - window.innerWidth; if (rightOffset > 0) { style.left = window.innerWidth - elementWidth; } if (parseFloat(String(style.left)) < 0) { style.left = 0; if (position === 'top' || position === 'bottom') { const arrowWidth = 16; const arrowStyleBasisWidth = left - arrowWidth / 2; if (align === 'left') { arrowStyle.left = arrowStyleBasisWidth; } else if (align === 'right') { arrowStyle.left = arrowStyleBasisWidth + targetBodySize.width; } else { arrowStyle.left = arrowStyleBasisWidth + targetBodySize.width / 2; } } } if (parseFloat(String(style.top)) < 0) { style.top = 0; arrowStyle.top = 0; } setStyle(style); setArrowStyle(arrowStyle); }, [active, arrow, position, children, renewStyles]); const handleMouseEnter = () => { if ((0, _componentHelper.isTrue)(active) && useHover !== false) { setHover(true); } }; const handleMouseLeave = () => { if (useHover !== false) { setHover(false); } }; const handlePropagation = e => e.stopPropagation(); return _react.default.createElement("span", _extends({ role: "tooltip", "aria-hidden": target ? true : undefined, ref: elementRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handlePropagation, onMouseDown: handlePropagation, onTouchStart: handlePropagation }, attributes, { className: (0, _classnames.default)(attributes === null || attributes === void 0 ? void 0 : attributes.className, isActive ? 'dnb-tooltip--active' : wasActive && 'dnb-tooltip--hide', (0, _componentHelper.isTrue)(noAnimation) && 'dnb-tooltip--no-animation', (0, _componentHelper.isTrue)(fixedPosition) && 'dnb-tooltip--fixed'), style: _objectSpread(_objectSpread({}, style), attributes.style) }), arrow && _react.default.createElement("span", { className: `dnb-tooltip__arrow dnb-tooltip__arrow__arrow--${arrow} dnb-tooltip__arrow__position--${position}`, style: _objectSpread({}, arrowStyle) }), _react.default.createElement("span", { id: internalId, className: "dnb-tooltip__content" }, children)); } //# sourceMappingURL=TooltipContainer.js.map