|
|
@@ -3,6 +3,7 @@ import {
|
|
|
useEffect,
|
|
|
forwardRef,
|
|
|
useState,
|
|
|
+ useMemo,
|
|
|
useCallback,
|
|
|
} from 'react'
|
|
|
import {
|
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
TooltipProps as BSTooltipProps,
|
|
|
} from 'react-bootstrap'
|
|
|
import { callFnsInSequence } from '@/utils/functions'
|
|
|
+import { useTooltipContext } from '@/shared/context/tooltip-provider'
|
|
|
|
|
|
const DEFAULT_DELAY_SHOW = 300
|
|
|
// Slightly lower value avoids flickering when an adjacent tooltip is shown before the previous one hides
|
|
|
@@ -34,6 +36,26 @@ const UpdatingTooltip = forwardRef<HTMLDivElement, BSTooltipProps>(
|
|
|
)
|
|
|
UpdatingTooltip.displayName = 'UpdatingTooltip'
|
|
|
|
|
|
+const chooseDelayOptions = (
|
|
|
+ delay?: number | { show: number; hide: number }
|
|
|
+): { show: number; hide: number } => {
|
|
|
+ if (typeof delay === 'object') {
|
|
|
+ return delay
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof delay === 'number') {
|
|
|
+ return {
|
|
|
+ show: delay,
|
|
|
+ hide: Math.max(delay - 10, 0),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ show: DEFAULT_DELAY_SHOW,
|
|
|
+ hide: DEFAULT_DELAY_HIDE,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
export type TooltipProps = {
|
|
|
description: React.ReactNode
|
|
|
id: string
|
|
|
@@ -53,20 +75,22 @@ function Tooltip({
|
|
|
}: TooltipProps) {
|
|
|
const [show, setShow] = useState(false)
|
|
|
|
|
|
- const handleKeyDown = useCallback(
|
|
|
- (e: KeyboardEvent) => {
|
|
|
+ const tooltipContext = useTooltipContext()
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const listener = (e: KeyboardEvent) => {
|
|
|
if (show && e.key === 'Escape') {
|
|
|
setShow(false)
|
|
|
e.stopPropagation()
|
|
|
}
|
|
|
- },
|
|
|
- [show, setShow]
|
|
|
- )
|
|
|
+ }
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- document.addEventListener('keydown', handleKeyDown, true)
|
|
|
- return () => document.removeEventListener('keydown', handleKeyDown, true)
|
|
|
- }, [handleKeyDown])
|
|
|
+ document.addEventListener('keydown', listener, true)
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ document.removeEventListener('keydown', listener, true)
|
|
|
+ }
|
|
|
+ }, [show])
|
|
|
|
|
|
const hideTooltip = (e: React.MouseEvent) => {
|
|
|
if (e.currentTarget instanceof HTMLElement) {
|
|
|
@@ -75,13 +99,22 @@ function Tooltip({
|
|
|
setShow(false)
|
|
|
}
|
|
|
|
|
|
- const delay = overlayProps?.delay
|
|
|
- let delayShow = DEFAULT_DELAY_SHOW
|
|
|
- let delayHide = DEFAULT_DELAY_HIDE
|
|
|
- if (delay !== undefined) {
|
|
|
- delayShow = typeof delay === 'number' ? delay : delay.show
|
|
|
- delayHide = typeof delay === 'number' ? Math.max(delay - 10, 0) : delay.hide
|
|
|
- }
|
|
|
+ const delayProps = useMemo(() => {
|
|
|
+ const delayOptions = chooseDelayOptions(overlayProps?.delay)
|
|
|
+ if (tooltipContext?.isTooltipOpen) {
|
|
|
+ delayOptions.show = 0
|
|
|
+ delayOptions.hide = 0
|
|
|
+ }
|
|
|
+ return delayOptions
|
|
|
+ }, [overlayProps?.delay, tooltipContext])
|
|
|
+
|
|
|
+ const handleToggle = useCallback(
|
|
|
+ (value: boolean) => {
|
|
|
+ tooltipContext?.setIsTooltipOpen(value)
|
|
|
+ setShow(value)
|
|
|
+ },
|
|
|
+ [tooltipContext]
|
|
|
+ )
|
|
|
|
|
|
return (
|
|
|
<OverlayTrigger
|
|
|
@@ -95,10 +128,11 @@ function Tooltip({
|
|
|
</UpdatingTooltip>
|
|
|
}
|
|
|
{...overlayProps}
|
|
|
- delay={{ show: delayShow, hide: delayHide }}
|
|
|
+ delay={delayProps}
|
|
|
placement={overlayProps?.placement || 'top'}
|
|
|
show={show}
|
|
|
- onToggle={setShow}
|
|
|
+ onToggle={handleToggle}
|
|
|
+ transition={!tooltipContext?.isTooltipOpen}
|
|
|
>
|
|
|
{overlayProps?.trigger === 'click'
|
|
|
? children
|