import '@tamagui/polyfill-dev' import { FloatingDelayGroup, useDelayGroupContext, type Delay } from '@tamagui/floating' import type { SizeTokens, TamaguiElement } from '@tamagui/core' import { useEvent } from '@tamagui/core' import { FloatingOverrideContext } from '@tamagui/floating' import { getSize } from '@tamagui/get-token' import { withStaticProperties } from '@tamagui/helpers' import type { PopoverAnchorProps, PopoverContentProps, PopoverTriggerProps, } from '@tamagui/popover' import { PopoverAnchor, PopoverArrow, PopoverContent, PopoverContextProvider, PopoverTrigger, useFloatingContext, } from '@tamagui/popover' import type { PopperArrowProps, PopperProps } from '@tamagui/popper' import { Popper, PopperContentFrame } from '@tamagui/popper' import { useControllableState } from '@tamagui/use-controllable-state' import * as React from 'react' const TOOLTIP_SCOPE = '' export type TooltipScopes = string type ScopedProps

= Omit & { scope?: TooltipScopes } export type TooltipContentProps = ScopedProps // warning: setting to stylebale causes issues with themeInverse across portal root // performance: avoid 2 components we never use const ALWAYS_DISABLE_TOOLTIP = { focus: true, 'remove-scroll': true, // it's nice to hit escape to hide a tooltip // dismiss: true } as const const TooltipContent = PopperContentFrame.styleable( (props, ref) => { const preventAnimation = React.useContext(PreventTooltipAnimationContext) const zIndexFromContext = React.useContext(TooltipZIndexContext) return ( ) }, { staticConfig: { componentName: 'Tooltip', }, } ) const TooltipArrow = React.forwardRef((props, ref) => { return ( ) }) export type TooltipProps = ScopedProps< PopperProps & { open?: boolean unstyled?: boolean children?: React.ReactNode onOpenChange?: (open: boolean) => void focus?: { enabled?: boolean visibleOnly?: boolean } groupId?: string restMs?: number delay?: | number | { open?: number close?: number } disableAutoCloseOnScroll?: boolean /** * z-index for the tooltip portal. Use this when tooltips need to appear * above other portaled content like dialogs. */ zIndex?: number } > const PreventTooltipAnimationContext = React.createContext(false) const TooltipZIndexContext = React.createContext(undefined) export const TooltipGroup = ({ children, delay, preventAnimation = false, timeoutMs, }: { children?: any delay: Delay preventAnimation?: boolean timeoutMs?: number }) => { return ( delay, [JSON.stringify(delay)])} > {children} ) } const setOpens = new Set>>() export const closeOpenTooltips = () => { setOpens.forEach((x) => x(false)) } const TooltipComponent = React.forwardRef(function Tooltip( props: TooltipProps, // no real ref here but React complaining need to see why see SandboxCustomStyledAnimatedTooltip.ts ref ) { // hooks inside useFloatingFn confuse the React Compiler 'use no memo' const { children, delay: delayProp, restMs: restMsProp, onOpenChange: onOpenChangeProp, focus, open: openProp, disableAutoCloseOnScroll, zIndex, scope = TOOLTIP_SCOPE, ...restProps } = props const triggerRef = React.useRef(null) const [hasCustomAnchor, setHasCustomAnchor] = React.useState(false) const { delay: delayGroup, setCurrentId } = useDelayGroupContext() // Use delayProp if explicitly provided, otherwise fall back to group delay or default 400 const delay = delayProp !== undefined ? delayProp : (delayGroup ?? 400) const restMs = restMsProp ?? (typeof delay === 'number' ? delay : 0) const [open, setOpen] = useControllableState({ prop: openProp, defaultProp: false, onChange: onOpenChangeProp, }) const id = props.groupId const onOpenChange = useEvent((open: boolean) => { if (open) { setCurrentId(id) } setOpen(open) }) // Auto close when document scroll React.useEffect(() => { if (!open) return if (disableAutoCloseOnScroll) return if (typeof document === 'undefined') return const closeIt = () => { setOpen(false) } setOpens.add(setOpen) document.documentElement.addEventListener('scroll', closeIt) return () => { setOpens.delete(setOpen) document.documentElement.removeEventListener('scroll', closeIt) } }, [open, disableAutoCloseOnScroll]) // use the shared floating context from popover — gives us multi-trigger // hover coordination (onHoverReference/onLeaveReference + grace period) // and safePolygon for free const floatingContext = useFloatingContext({ open, setOpen: onOpenChange, disable: false, disableFocus: false, hoverable: true, role: 'tooltip', focus, groupId: id, delay, restMs, }) const onCustomAnchorAdd = React.useCallback(() => setHasCustomAnchor(true), []) const onCustomAnchorRemove = React.useCallback(() => setHasCustomAnchor(false), []) const contentId = React.useId() const smallerSize = props.unstyled ? null : getSize('$true', { shift: -2, bounds: [0], }) const content = ( {/* default tooltip to a smaller size */} {children} ) if (zIndex !== undefined) { return ( {content} ) } return content }) const TooltipTrigger = React.forwardRef(function TooltipTrigger( props: ScopedProps, ref: any ) { const { scope, ...rest } = props return }) const TooltipAnchor = React.forwardRef(function TooltipAnchor( props: ScopedProps, ref: any ) { const { scope, ...rest } = props return }) export const Tooltip = withStaticProperties(TooltipComponent, { Anchor: TooltipAnchor, Arrow: TooltipArrow, Content: TooltipContent, Trigger: TooltipTrigger, }) const voidFn = () => {}