diff --git a/src/Tooltip/Tooltip.mdx b/src/Tooltip/Tooltip.mdx index 61207acd..e40185ee 100644 --- a/src/Tooltip/Tooltip.mdx +++ b/src/Tooltip/Tooltip.mdx @@ -31,6 +31,19 @@ import { Tooltip } from 'tailor-ui'; +### use mouseEnterDelay and mouseLeaveDelay + + + Tooltip Content} + mouseEnterDelay={500} + mouseLeaveDelay={500} + > + + + + ### Click diff --git a/src/Tooltip/Tooltip.tsx b/src/Tooltip/Tooltip.tsx index cde24465..5ec867cd 100644 --- a/src/Tooltip/Tooltip.tsx +++ b/src/Tooltip/Tooltip.tsx @@ -43,6 +43,14 @@ export type ITooltipProps = Omit & { * Decide how to trigger this tooltip */ trigger?: 'click' | 'hover'; + /** + * Delay in milliseconds, before tooltip is shown on mouse enter + */ + mouseEnterDelay?: number; + /** + * Delay in milliseconds, before tooltip is hidden on mouse leave + */ + mouseLeaveDelay?: number; components?: { ContentComponent: any; ArrowComponent: any; @@ -56,6 +64,7 @@ class Tooltip extends PureComponent { renderOverlay = ({ styles, + handleOpen, handleClose, handlePopupRef, }: IPopupRenderProps) => { @@ -74,8 +83,13 @@ class Tooltip extends PureComponent { return ( {content instanceof Function && trigger === 'click' ? content(handleClose) @@ -94,6 +108,8 @@ class Tooltip extends PureComponent { visible, onVisibleChange, children, + mouseEnterDelay, + mouseLeaveDelay, } = this.props; return ( @@ -108,6 +124,8 @@ class Tooltip extends PureComponent { defaultVisible={defaultVisible} visible={visible} onVisibleChange={onVisibleChange} + mouseEnterDelay={mouseEnterDelay} + mouseLeaveDelay={mouseLeaveDelay} > {children} diff --git a/src/Trigger/Trigger.tsx b/src/Trigger/Trigger.tsx index 3f3a3da7..1b6795b3 100644 --- a/src/Trigger/Trigger.tsx +++ b/src/Trigger/Trigger.tsx @@ -21,6 +21,7 @@ export interface IPopupRenderProps { left: number; [key: string]: any; }; + handleOpen: () => void; handleClose: () => void; handlePopupRef: any; } @@ -61,6 +62,8 @@ export interface ITriggerProps { defaultVisible?: boolean; visible?: boolean; zIndex?: string; + mouseEnterDelay?: number; + mouseLeaveDelay?: number; } interface ITriggerState { @@ -75,12 +78,18 @@ class Trigger extends PureComponent { trigger: 'hover', animation: 'slide', defaultVisible: false, + mouseEnterDelay: 0, + mouseLeaveDelay: 200, }; childrenDOM?: HTMLElement; rectObserver?: any; + enterDelayTimer?: any; + + leaveDelayTimer?: any; + offset: { top: number; left: number; @@ -144,6 +153,21 @@ class Trigger extends PureComponent { }; handleOpen = () => { + const { mouseEnterDelay, trigger } = this.props; + + if (this.leaveDelayTimer) { + clearTimeout(this.leaveDelayTimer); + this.leaveDelayTimer = null; + } + + if (this.props.mouseEnterDelay !== 0 && trigger === 'hover') { + this.enterDelayTimer = setTimeout(this.open, mouseEnterDelay); + } else { + this.open(); + } + }; + + open = () => { const visible = this.getVisible(); if (!visible) { @@ -155,10 +179,28 @@ class Trigger extends PureComponent { if (onVisibleChange) { onVisibleChange(true); } + + clearTimeout(this.enterDelayTimer); + this.enterDelayTimer = null; } }; handleClose = () => { + const { mouseLeaveDelay, trigger } = this.props; + + if (this.enterDelayTimer) { + clearTimeout(this.enterDelayTimer); + this.enterDelayTimer = null; + } + + if (this.props.mouseLeaveDelay !== 0 && trigger === 'hover') { + this.leaveDelayTimer = setTimeout(this.close, mouseLeaveDelay); + } else { + this.close(); + } + }; + + close = () => { const visible = this.getVisible(); if (visible) { @@ -170,6 +212,9 @@ class Trigger extends PureComponent { if (onVisibleChange) { onVisibleChange(false); } + + clearTimeout(this.leaveDelayTimer); + this.leaveDelayTimer = null; } }; @@ -272,6 +317,7 @@ class Trigger extends PureComponent { const renderPopup = () => popup({ styles, + handleOpen: this.handleOpen, handleClose: this.handleClose, handlePopupRef: this.handlePopupRef, });