diff --git a/src/frontend/src/components/ui/tooltip.tsx b/src/frontend/src/components/ui/tooltip.tsx index dad190e2a9..59974d47b0 100644 --- a/src/frontend/src/components/ui/tooltip.tsx +++ b/src/frontend/src/components/ui/tooltip.tsx @@ -10,9 +10,65 @@ const TooltipProvider = ({ ); -const Tooltip = TooltipPrimitive.Root; +type TooltipControl = { + open: boolean; + setOpen: (next: boolean) => void; +}; + +const TooltipContext = React.createContext(null); + +/** + * Radix Tooltip is hover/focus driven, so coarse pointers (finger / stylus tap) + * never see it on iPad/iPhone. Wrap Root with a small controlled-state shim and + * let the Trigger toggle it on touch / pen pointerdown without affecting mouse. + */ +const Tooltip = ({ + open: openProp, + defaultOpen, + onOpenChange, + ...props +}: React.ComponentPropsWithoutRef) => { + const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false); + const isControlled = openProp !== undefined; + const open = isControlled ? openProp : internalOpen; + + const setOpen = React.useCallback( + (next: boolean) => { + if (!isControlled) { + setInternalOpen(next); + } + onOpenChange?.(next); + }, + [isControlled, onOpenChange], + ); -const TooltipTrigger = TooltipPrimitive.Trigger; + return ( + + + + ); +}; + +const TooltipTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => { + const ctx = React.useContext(TooltipContext); + return ( + { + props.onPointerDown?.(e); + if (!ctx) return; + if (e.pointerType === "touch" || e.pointerType === "pen") { + ctx.setOpen(!ctx.open); + } + }} + /> + ); +}); +TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName; const hasNoSpaces = (str: string): boolean => { const trimmed = str.trim();