@kubit-ui-web/react-components
Version:
Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience
156 lines • 6.96 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useTooltip = void 0;
const react_1 = __importDefault(require("react"));
const stylesName_1 = require("../../../constants/stylesName/stylesName");
const useClickOutside_1 = require("../../../hooks/useClickOutside/useClickOutside");
const useEscPressedV2_1 = require("../../../hooks/useEscPressedV2/useEscPressedV2");
const useMediaDevice_1 = require("../../../hooks/useMediaDevice/useMediaDevice");
const useStyles_1 = require("../../../hooks/useStyles/useStyles");
const breakpoints_1 = require("../../../types/breakpoints/breakpoints");
const focusHandlers_1 = require("../../../utils/focusHandlers/focusHandlers");
const computePosition_1 = require("../positioning/computePosition");
// floating
const arrow_1 = require("../positioning/middlewares/arrow");
const flip_1 = require("../positioning/middlewares/flip");
const shift_1 = require("../positioning/middlewares/shift");
const tooltipAlign_1 = require("../types/tooltipAlign");
/**
* @name useTooltip
* @description
* Hook to handle the tooltip functionality
* @param {UseTooltipType} props
* @returns {UseTooltipReturnType}
*/
const useTooltip = ({ align = tooltipAlign_1.TooltipAlignType.TOP, ...props }) => {
const mediaDevice = (0, useMediaDevice_1.useMediaDevice)();
const lastFocus = react_1.default.useRef(null);
// Avoid tooltip is opened automatically after closing the tooltip
const allowFocusOpenTooltip = react_1.default.useRef(true);
const openRef = react_1.default.useRef(false);
const [open, setOpen] = react_1.default.useState(false);
// Need the styles to calc the arrow tooltip position
const styles = (0, useStyles_1.useStyles)(stylesName_1.STYLES_NAME.TOOLTIP, props.variant, props.ctv);
// Avoid to show tooltip when scrolling
react_1.default.useEffect(() => {
const handleResize = () => {
updateTooltipPosition();
};
window.addEventListener('scroll', onScroll, true);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('scroll', onScroll, true);
window.removeEventListener('resize', handleResize);
};
}, []);
const onScroll = (e) => {
if (!props.tooltipRef.current?.contains(e.target)) {
updateTooltipPosition();
}
};
const showTooltip = () => {
if (openRef.current) {
return;
}
openRef.current = true;
// Save last focusable element
lastFocus.current = document.activeElement;
if (mediaDevice === breakpoints_1.DeviceBreakpointsType.DESKTOP) {
if (!props.tooltipRef.current) {
return;
}
props.tooltipRef.current.style.display = 'flex';
updateTooltipPosition();
(0, focusHandlers_1.focusElementOrFirstDescendant)(props.tooltipRef.current);
}
setOpen(true);
props.onOpenClose?.(true);
};
const hideTooltip = react_1.default.useCallback(() => {
if (!openRef.current) {
return;
}
// Apply focus in last focusable element
openRef.current = false;
allowFocusOpenTooltip.current = false;
// Only focus in the last element if the tooltip is a modal
if (props.tooltipAsModal) {
lastFocus.current?.focus();
}
allowFocusOpenTooltip.current = true;
if (mediaDevice === breakpoints_1.DeviceBreakpointsType.DESKTOP) {
if (!props.tooltipRef.current) {
return;
}
props.tooltipRef.current.style.display = 'none';
}
setOpen(false);
props.onOpenClose?.(false);
}, [mediaDevice, props.onOpenClose, props.tooltipAsModal]);
const handleEscPress = react_1.default.useCallback((event) => {
if (!openRef.current) {
return;
}
// Only stop propagation if the tooltip is opened and its going to be closed
event.stopPropagation();
hideTooltip();
}, [hideTooltip]);
// Because desktop do not use popover component, we need to manually call manually to close on scape and click outside functionality
(0, useEscPressedV2_1.useEscPressedV2)({
ref: props.labelRef,
onEscPress: handleEscPress,
disableStopPropagation: true,
});
// Prevent to be closed when clicking the label, it will be handled by the tooltip label click in order to open/close the tooltip
(0, useClickOutside_1.useClickOutside)(props.tooltipRef, hideTooltip, [props.labelRef.current]);
// This function calc the position position where the tooltip should be displayed
const updateTooltipPosition = () => {
if (!props.labelRef.current || !props.tooltipRef.current) {
return;
}
const arrowElement = props.tooltipRef.current.lastElementChild;
const { x, y, placement, middlewareData } = (0, computePosition_1.computePosition)(props.labelRef.current, props.tooltipRef.current, {
placement: align,
middleware: [
// Offset is handle internally with a padding
// Avoiding onMouseLeave label close the tooltip when you want to put the mouse inside
// offset(props.styles.DESKTOP?.tooltip_offset),
(0, flip_1.flip)(),
(0, shift_1.shift)({ crossAxis: true }),
(0, arrow_1.arrow)({ element: arrowElement }),
],
});
Object.assign(props.tooltipRef.current.style, {
left: `${x}px`,
top: `${y}px`,
});
// Arrow pos
const { x: arrowX, y: arrowY } = middlewareData.arrow;
const staticSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[placement.split('-')[0]];
const arrowStyle = {
left: arrowX !== null ? `${arrowX}px` : '',
top: arrowY !== null ? `${arrowY}px` : '',
right: '',
bottom: '',
[staticSide]: `calc(${styles.tooltipExternalContainer?.[breakpoints_1.DeviceBreakpointsType.DESKTOP]?.padding ?? 0} - ${styles.arrowContainer?.arrow_position ?? '0px'} / 2)`,
};
if (arrowElement && arrowElement.style) {
arrowElement.style.removeProperty('left');
arrowElement.style.removeProperty('top');
arrowElement.style.removeProperty('right');
arrowElement.style.removeProperty('bottom');
Object.assign(arrowElement?.style, arrowStyle);
}
};
return { showTooltip, hideTooltip, allowFocusOpenTooltip, open };
};
exports.useTooltip = useTooltip;
//# sourceMappingURL=useTooltip.js.map