|
|
@@ -0,0 +1,86 @@
|
|
|
+import { cloneElement, useEffect, forwardRef } from 'react'
|
|
|
+import { OverlayTrigger, Tooltip as BSTooltip } from 'react-bootstrap-5'
|
|
|
+import { callFnsInSequence } from '@/utils/functions'
|
|
|
+
|
|
|
+type OverlayProps = Omit<
|
|
|
+ React.ComponentProps<typeof OverlayTrigger>,
|
|
|
+ 'overlay' | 'children'
|
|
|
+>
|
|
|
+
|
|
|
+type UpdatingTooltipProps = {
|
|
|
+ popper: {
|
|
|
+ scheduleUpdate: () => void
|
|
|
+ }
|
|
|
+ show: boolean
|
|
|
+ [x: string]: unknown
|
|
|
+}
|
|
|
+
|
|
|
+const UpdatingTooltip = forwardRef<HTMLDivElement, UpdatingTooltipProps>(
|
|
|
+ ({ popper, children, show: _, ...props }, ref) => {
|
|
|
+ useEffect(() => {
|
|
|
+ popper.scheduleUpdate()
|
|
|
+ }, [children, popper])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <BSTooltip ref={ref} {...props}>
|
|
|
+ {children}
|
|
|
+ </BSTooltip>
|
|
|
+ )
|
|
|
+ }
|
|
|
+)
|
|
|
+UpdatingTooltip.displayName = 'UpdatingTooltip'
|
|
|
+
|
|
|
+export type TooltipProps = {
|
|
|
+ description: React.ReactNode
|
|
|
+ id: string
|
|
|
+ overlayProps?: OverlayProps
|
|
|
+ tooltipProps?: React.ComponentProps<typeof BSTooltip>
|
|
|
+ hidden?: boolean
|
|
|
+ children: React.ReactElement
|
|
|
+}
|
|
|
+
|
|
|
+function Tooltip({
|
|
|
+ id,
|
|
|
+ description,
|
|
|
+ children,
|
|
|
+ tooltipProps,
|
|
|
+ overlayProps,
|
|
|
+ hidden,
|
|
|
+}: TooltipProps) {
|
|
|
+ const delay = overlayProps?.delay
|
|
|
+ let delayShow = 300
|
|
|
+ let delayHide = 300
|
|
|
+ if (delay) {
|
|
|
+ delayShow = typeof delay === 'number' ? delay : delay.show
|
|
|
+ delayHide = typeof delay === 'number' ? delay : delay.hide
|
|
|
+ }
|
|
|
+
|
|
|
+ const hideTooltip = (e: React.MouseEvent) => {
|
|
|
+ if (e.currentTarget instanceof HTMLElement) {
|
|
|
+ e.currentTarget.blur()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <OverlayTrigger
|
|
|
+ overlay={
|
|
|
+ <UpdatingTooltip
|
|
|
+ id={`${id}-tooltip`}
|
|
|
+ {...tooltipProps}
|
|
|
+ style={{ display: hidden ? 'none' : 'block' }}
|
|
|
+ >
|
|
|
+ {description}
|
|
|
+ </UpdatingTooltip>
|
|
|
+ }
|
|
|
+ {...overlayProps}
|
|
|
+ delay={{ show: delayShow, hide: delayHide }}
|
|
|
+ placement={overlayProps?.placement || 'top'}
|
|
|
+ >
|
|
|
+ {cloneElement(children, {
|
|
|
+ onClick: callFnsInSequence(children.props.onClick, hideTooltip),
|
|
|
+ })}
|
|
|
+ </OverlayTrigger>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+export default Tooltip
|