@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
224 lines (223 loc) • 10.1 kB
JavaScript
;
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