feat: replace Radix Tooltip with Tamagui (#583) - #791
Draft
gaidheal1 wants to merge 1 commit into
Draft
Conversation
Preserves the click/tap-to-toggle model #568 already established (open state fully app-controlled, not driven by Tamagui's built-in interaction system) - the trigger's own onFocusCapture opens the tooltip directly, which sidesteps the confirmed upstream focus-to-open bug in tamagui/tamagui#4152 entirely rather than needing a workaround for it. Hover suppression required capturing the bubbling mouseover/mouseout/ mousemove (and pointer equivalents) events React derives its synthetic onMouseEnter/onMouseLeave/onMouseMove from at the document level, since Tamagui's Tooltip hardcodes hoverable interaction with no prop to disable it and asChild always lets Tamagui's own same-named props win. Outside- click and Escape dismissal are handled with the app's own document listeners for the same reason, rather than relying on Tamagui's dismiss wiring (unclear/untested for Tooltip content). Map.tsx no longer uses the shared Tooltip/TooltipProvider (it grew its own custom overlay since #583 was filed), so the per-subtree provider override this issue called out doesn't apply.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #583: replaces
@radix-ui/react-tooltipinfrontend/src/components/Tooltip/Tooltip.tsxwith Tamagui'sTooltipprimitive, part of epic #578. Branched off #582's Tamagui Modal/AlertDialog branch per the user's explicit instruction.Since #568 (unify tap/click tooltip behaviour) already merged to
developmentbefore this branch was cut, the existingTooltip.tsxwas already fully self-controlled: it ownsopenstate directly and decides opens/closes itself via explicit pointerdown/focus handlers, never relying on the underlying primitive's own hover/focus logic. That existing architecture turned out to be exactly what was needed to route around Tamagui's confirmed upstream focus-to-open bug (tamagui/tamagui#4152, documented in.claude/plans/issue-629-tamagui-poc.md): since we never rely on Tamagui's built-infocus={{enabled:true}}wiring at all (our ownonFocusCaptureopens it directly), that bug simply doesn't apply here — no workaround needed, it's moot by construction.Key implementation notes
mouseenter/mouseleave. Tamagui'sTooltiphardcodeshoverable: truewith no prop to disable it, and exposes hover-open via agetReferenceProps()-suppliedonMouseMoveReact prop thatasChildmerges onto the trigger (winning over any same-named prop we pass — the same "parent wins" merge Replace Radix Dialog and AlertDialog with a shared overlay primitive #582 hit withDialog.Title'saria-label). That prop is dispatched through React's own delegated root listener, and React derives its syntheticonMouseEnter/onMouseLeavefrom the bubblingmouseover/mouseout(they don't listen for the non-bubbling names directly). The fix: adocument-level capture-phase listener formouseover/mouseout/mousemove(+ pointer equivalents) — an ancestor's capture-phase listener always runs before React's own listener on its root container ever sees the event. Verified manually in a real Chromium browser (Playwright, pinned executable) since this exact interaction falls outside whattest:storybook/test:a11ycan run in this sandbox (see below).documentlisteners, not Tamagui's built-in dismiss wiring — same reasoning as Replace Radix Dialog and AlertDialog with a shared overlay primitive #582's choice to use plainButtons overDialog.Close/AlertDialog.Cancel: more reliable than leaning on internal composition that's untested for this specific usage.Map.tsxno longer uses the sharedTooltip/TooltipProvider— it grew its own custom MapLibre-driven overlay (role="tooltip"div + its ownTamaguiProvider) since Replace Radix Tooltip — coordinate with the tap/click unification in #568 #583 was filed, so the issue's "verify Map.tsx's zero-delay tooltips" acceptance item doesn't apply; confirmed via code read, not assumed.TooltipProvideris now a passthrough (Tamagui needs no ambient ancestor) but keeps its exact prop signature for call-site/test compatibility, consistent with Replace Radix Dialog and AlertDialog with a shared overlay primitive #582's approach forModal/AlertDialog.data-side→data-placement(prefix-matched) in the SCSS; Tamagui setstransform-origininline itself; the arrow is a rotated box, not an SVG polygon, sofill→background-color.Acceptance criteria
@radix-ui/react-tooltipimport remains (uninstalled frompackage.json)Tooltip/TooltipProviderunchanged; all consumers (TasksPanel,ActivitiesPanel,ActivityTimeline,AchievementBadges) work untouchedMap.tsxno longer uses the shared component (see above)allowFlip/stayInFramedisabled/emptycontentstill short-circuits to bare childrendevelopmentbefore this branch; click/tap-to-toggle preserved and testedaria-describedbywiring — confirmed via test + real browserTooltip.test.tsx,TasksPanel.test.tsx,Map.test.tsxpasstouch-action/-webkit-touch-calloutCSS carried over unchanged from the pre-Replace Radix Tooltip — coordinate with the tap/click unification in #568 #583 implementation, but real hardware verification is still openTest plan
npm run test— 566/567 passing (1 pre-existing, unrelated flake inUnifiedTimerHome.test.tsx, confirmed identical on the base branch and untouched by this change — doesn't renderTooltip)npm run lint/tsc --noEmit— cleannpm run build:production— succeedsdisabledstory doesn't opennpm run test:storybook/npm run test:a11y— blocked by a pre-existing Playwright browser version mismatch in this sandbox (chromium_headless_shell-1234expected vs-1194available), same limitation documented in Replace Radix Dialog and AlertDialog with a shared overlay primitive #582's PRGenerated by Claude Code