saagie-ui
Version:
Saagie UI from Saagie Design System
185 lines (164 loc) • 5.14 kB
JavaScript
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;