UNPKG

saagie-ui

Version:

Saagie UI from Saagie Design System

185 lines (164 loc) 5.14 kB
import React, { useState, useRef, useEffect } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { Manager, Reference } from 'react-popper'; import { modifierCSS, usePopper } from '../../../helpers'; const propTypes = { children: PropTypes.node, className: PropTypes.string, color: PropTypes.oneOf(['', 'primary', 'secondary', 'success', 'warning', 'danger', 'light', 'dark', 'new']), defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), /** * Add a delay before closing the tooltip */ hideDelay: PropTypes.bool, /** * The number of second before the closing of the tooltip when hideDelay is set to true */ hideDelayCustomTimeOut: PropTypes.oneOf([ 0.05, 0.1, 0.2, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ]), /** * Automatically display the tooltip on first render */ autoDisplay: PropTypes.bool, /** * The number of seconds before closing the tooltip when autoDisplay is set to true */ autoDisplayCustomTimeOut: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), isLight: PropTypes.bool, /* deprecated 0.65 */ isPortalDisabled: PropTypes.bool, label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), portalTarget: PropTypes.instanceOf(Element), defaultPlacement: PropTypes.oneOf(['auto', 'top', 'right', 'bottom', 'left']), size: PropTypes.oneOf(['', 'sm', 'md', 'lg']), tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), wrapperTag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), }; const defaultProps = { children: '', className: '', color: '', defaultClassName: 'sui-a-tooltip', hideDelay: false, hideDelayCustomTimeOut: 2, autoDisplay: false, autoDisplayCustomTimeOut: 6, isLight: false, isPortalDisabled: false, label: '', portalTarget: document.body, defaultPlacement: 'auto', size: '', tag: 'div', wrapperTag: 'div', }; export const Tooltip = ({ children, className, color, defaultClassName, autoDisplay, autoDisplayCustomTimeOut, hideDelay, hideDelayCustomTimeOut, isLight, isPortalDisabled, label, portalTarget, defaultPlacement, size, tag: Tag, wrapperTag: WrapperTag, ...attributes }) => { const [isOpen, setIsOpen] = useState(autoDisplay || false); const [isMouseOver, setIsMouseOver] = useState(false); const exitTimeoutRef = useRef(); const autoDisplayTimeoutRef = useRef(); const { mountPopperNode } = usePopper(defaultPlacement, { target: portalTarget, isDisabled: isPortalDisabled }); useEffect(() => () => clearTimeout(exitTimeoutRef.current), []); useEffect(() => { if (!autoDisplay) { return () => {}; } autoDisplayTimeoutRef.current = setTimeout(() => { // Don't hide the tooltip if mouse is over if (isMouseOver) { return; } setIsOpen(false); }, autoDisplayCustomTimeOut * 1000); return () => clearTimeout(autoDisplayTimeoutRef.current); }, [autoDisplay, setIsOpen]); const handleClose = () => { if (hideDelay) { exitTimeoutRef.current = setTimeout(() => setIsOpen(false), hideDelayCustomTimeOut * 1000); return; } setIsOpen(false); }; const wrappedChildren = React.isValidElement(children) ? children : <WrapperTag>{children}</WrapperTag>; const handleWrapperFocus = () => { clearTimeout(exitTimeoutRef.current); clearTimeout(autoDisplayTimeoutRef.current); setIsOpen(true); }; const handleTooltipHover = () => { clearTimeout(exitTimeoutRef.current); clearTimeout(autoDisplayTimeoutRef.current); setIsMouseOver(true); }; return ( <Manager> <Reference> {({ ref }) => React.cloneElement(wrappedChildren, { ref, onMouseOver: handleWrapperFocus, onFocus: handleWrapperFocus, onMouseLeave: handleClose, onBlur: handleClose, })} </Reference> {isOpen && mountPopperNode(({ ref, style, placement }) => { const classes = classnames( className, defaultClassName, isLight ? 'as--light' : '', modifierCSS(color), modifierCSS(placement, 'placement') ); const innerClasses = classnames( 'sui-a-tooltip__inner', modifierCSS(size), ); const onMouseEnterCallback = hideDelay ? handleTooltipHover : null; const onMouseLeaveCallback = hideDelay ? handleClose : null; return ( <Tag {...attributes} className={classes} ref={ref} style={style} role="tooltip" onMouseEnter={onMouseEnterCallback} onFocus={onMouseEnterCallback} onMouseLeave={onMouseLeaveCallback} onBlur={onMouseLeaveCallback} > <div className="sui-a-tooltip__arrow" /> <div className={innerClasses}> {label} </div> </Tag> ); })} </Manager> ); }; Tooltip.propTypes = propTypes; Tooltip.defaultProps = defaultProps;