@kiwicom/orbit-components
Version:
Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com's products.
113 lines • 4.17 kB
JavaScript
import * as React from "react";
import cx from "clsx";
import { useFloating, offset, flip, autoPlacement, arrow, FloatingArrow, autoUpdate, shift } from "@floating-ui/react";
import { AUTO_PLACEMENTS, getAutoAlignment, isFixedPlacement } from "../../../common/placements";
import FOCUSABLE_ELEMENT_SELECTORS from "../../../hooks/useFocusTrap/consts";
import useTheme from "../../../hooks/useTheme";
const ARROW_SIZE = 6;
const BORDER_RADIUS = 12;
const getArrowColor = ({
error,
help,
theme
}) => {
if (error) return theme.orbit.paletteRedNormal;
if (help) return theme.orbit.paletteBlueNormal;
return theme.orbit.paletteInkDark;
};
const TooltipContent = ({
dataTest,
shown,
size,
tooltipId,
error,
help,
children,
onClick,
onClose,
onCloseMobile,
onEnter,
placement = AUTO_PLACEMENTS.AUTO,
noFlip,
offset: offsetProp = [0, 5],
referenceElement
}) => {
const arrowRef = React.useRef(null);
const [contentHeight, setContentHeight] = React.useState(0);
const content = React.useRef(null);
const isAutoPlacement = !isFixedPlacement(placement);
const {
refs,
floatingStyles,
context,
elements
} = useFloating({
placement: isAutoPlacement ? undefined : placement,
elements: {
reference: referenceElement
},
whileElementsMounted: autoUpdate,
middleware: [offset({
mainAxis: offsetProp[0] + ARROW_SIZE,
crossAxis: offsetProp[1] - ARROW_SIZE
}), !noFlip && !isAutoPlacement && flip({
fallbackAxisSideDirection: "start",
crossAxis: false
}), isAutoPlacement && autoPlacement({
alignment: getAutoAlignment(placement),
autoAlignment: !noFlip
}), shift(), arrow({
element: arrowRef,
padding: BORDER_RADIUS
})]
});
React.useEffect(() => {
if (content.current) setContentHeight(content.current.clientHeight);
}, [setContentHeight]);
const theme = useTheme();
const arrowColor = getArrowColor({
error,
help,
theme
});
const handleInnerClick = React.useCallback(ev => {
if (elements.floating) {
const focusableElements = elements.floating.querySelectorAll(FOCUSABLE_ELEMENT_SELECTORS);
if (Object.values(focusableElements).some(v => v === ev.target)) {
onClose();
onCloseMobile();
}
}
}, [onClose, onCloseMobile, elements.floating]);
const handleCombinedClick = ev => {
handleInnerClick(ev);
onClick(ev);
};
return (
/*#__PURE__*/
// Disabling because the onClick exists to close tooltip when clicking in interactive elements, which should not happen with keyboard.
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
React.createElement("div", {
className: cx("rounded-300 px-300 shadow-level3 z-[10012] box-border block w-auto overflow-visible", "duration-fast transition-[visibility,_opacity] ease-in-out", "[&_img]:max-w-full]", contentHeight <= Math.floor(parseFloat(theme.orbit.lineHeightNormal)) ? "py-200" : "py-300", shown ? "visible opacity-100" : "invisible opacity-0", size === "small" && "max-w-[240px]", size === "medium" && "max-w-[380px]", error && "bg-red-normal", !error && help && "bg-blue-normal", !error && !help && "bg-ink-dark"),
ref: refs.setFloating,
role: "tooltip",
id: tooltipId,
"aria-hidden": !shown,
onMouseEnter: onEnter,
onMouseLeave: onClose,
onClick: handleCombinedClick,
style: floatingStyles,
"data-test": dataTest
}, /*#__PURE__*/React.createElement("div", {
className: cx("font-base text-small text-white-normal mb-0 font-medium leading-normal", "[&_.orbit-text]:text-small [&_.orbit-text]:text-white-normal [&_.orbit-text]:font-medium", "[&_.orbit-list-item]:text-small [&_.orbit-list-item]:text-white-normal [&_.orbit-list-item]:font-medium", "[&_.orbit-text-link]:text-white-normal"),
ref: content
}, children), /*#__PURE__*/React.createElement(FloatingArrow, {
ref: arrowRef,
context: context,
height: ARROW_SIZE,
width: ARROW_SIZE * 2,
fill: arrowColor
}))
);
};
export default TooltipContent;