UNPKG

@zohodesk/hooks

Version:

Unified Component Library - Hooks

114 lines (104 loc) 3.29 kB
import { useState, useEffect, useRef } from 'react'; import { useFloating, shift, flip, arrow, offset } from '@floating-ui/react-dom'; import selectn from 'selectn'; import { useThemeByComponent } from "../themeprovider/ThemeProvider"; import useEscapeEffect from "../../custom-hooks/useEscapeEffect"; import debounce from "../../utils/debounce"; import useCommonReducer from "../../libraries/reducerHandler"; import tooltipReducer, { initialState } from "./Tooltip.reducers"; import { reset, setTitle } from "./Tooltip.actions"; import { getClosestTitleElement } from "./utils"; import { DATA_TITLE_ATTR, TITLE_ATTR, DATA_TITLE_ISHTML, TOOLTIP_DELAY, COMPONENT_NAME, ARROW_PLACEMENT } from "./Tooltip.constants"; export default function useTooltip(_ref) { let { container, reducer, offsetOption, placement: tooltipPlacement } = _ref; const { state, dispatch } = useCommonReducer(tooltipReducer, reducer, initialState); const arrowReference = useRef(null); const { x, y, reference, floating, strategy: position, middlewareData, placement } = useFloating({ placement: tooltipPlacement, middleware: [offset(offsetOption), flip(), shift(), arrow({ element: arrowReference })] }); const { title, isHtmlTitle } = state; useEscapeEffect(() => { handleReset(); }, [title]); const componentThemeProps = useThemeByComponent(COMPONENT_NAME); function handleReset() { if (title) { dispatch(reset()); } } function mouseHover(e) { // For handling nested tooltip avoid call multiple times if (e.isTooltipHanlde) { handleReset(); return null; } const element = e.target; const titleElement = getClosestTitleElement(element); if (titleElement) { const title = titleElement.getAttribute(DATA_TITLE_ATTR) || titleElement.getAttribute(TITLE_ATTR); if (title != '') { titleElement.setAttribute(DATA_TITLE_ATTR, title); /* reason for removing title attribute avoiding default browser tooltip */ titleElement.removeAttribute(TITLE_ATTR); } const isHtmlTitle = titleElement.getAttribute(DATA_TITLE_ISHTML); if (isHtmlTitle) { dispatch(setTitle(title, isHtmlTitle == 'true')); } else { dispatch(setTitle(title)); } e.isTooltipHanlde = true; reference(titleElement); } else { handleReset(); } } const mouseHoverDebounced = debounce(mouseHover, TOOLTIP_DELAY); useEffect(() => { container.addEventListener('mouseover', mouseHoverDebounced); container.addEventListener('mouseleave', handleReset); container.addEventListener('click', handleReset); return () => { container.removeEventListener('mouseover', mouseHoverDebounced); container.removeEventListener('mouseleave', handleReset); container.removeEventListener('click', handleReset); }; }, [title, container]); const arrowX = selectn('arrow.x', middlewareData); const arrowY = selectn('arrow.y', middlewareData); return { title, isHtmlTitle, floating, position, x, y, arrowReference, arrowX, arrowY, arrowPlacement: ARROW_PLACEMENT[placement.split('-')[0]], componentThemeProps }; }