mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-08 09:24:41 +00:00
fix(app): show one hover card at a time while scanning sidebar workspaces (#9071)
* fix(app): keep one hover card open while scanning sidebar workspaces Sweeping the pointer down the workspace list showed cards about three frames late, stacked two or three at once, and left some open after the pointer moved on. The card was positioned through an async chain (measureInWindow, then onLayout, then a position effect, then the portal's passive mount), so it painted at -9999 first. While unplaced, its safe-zone bridge covered everything above the trigger, so upward pointer moves kept cancelling its close timer. The previous card also stayed for the close grace period plus its fade while the next one opened. Now each overlay layer holds one open card, and opening another trigger closes it immediately. The card reads its trigger and overlay rects in a layout effect inside the portal, so the first painted frame is already placed. The grace timer still covers jitter and the gap onto the card. * test(app): name the hover scan workspaces so the resting row's card is identified
This commit is contained in:
+1
-1
@@ -135,7 +135,7 @@ Heuristic: if your hover state is going to be `useState`'d and read by anything
|
||||
|
||||
Sometimes the revealed content can't live inside the trigger — a hover card portals into a different layer, a tooltip floats above other content, a popover renders into a `Portal`. There's a real visual gap the user has to cross with the cursor.
|
||||
|
||||
For a card whose content the user can point at or press, use `HoverCard` (`packages/app/src/components/ui/hover-card.tsx`). It is built on `useHoverSafeZone` (`packages/app/src/hooks/use-hover-safe-zone.ts`), which computes a rectangular "bridge" across the gap between the trigger and the content, whether the card sits beside, above, or below the trigger. While the pointer is inside trigger, content, or the bridge, the card stays open. A short grace timer absorbs jitter at the edges. `Tooltip` takes no pointer events and closes as soon as the pointer leaves the trigger. If the trigger has no focusable child, give `HoverCardTrigger` `focusable` and an accessible label so keyboard users can open the same content.
|
||||
For a card whose content the user can point at or press, use `HoverCard` (`packages/app/src/components/ui/hover-card.tsx`). It is built on `useHoverSafeZone` (`packages/app/src/hooks/use-hover-safe-zone.ts`), which computes a rectangular "bridge" across the gap between the trigger and the content, whether the card sits beside, above, or below the trigger. While the pointer is inside trigger, content, or the bridge, the card stays open. A short grace timer absorbs jitter at the edges. Only one card per overlay layer is open: pointing at another trigger replaces the open card at once, so a sweep down a list never shows two cards or leaves one behind. `Tooltip` takes no pointer events and closes as soon as the pointer leaves the trigger. If the trigger has no focusable child, give `HoverCardTrigger` `focusable` and an accessible label so keyboard users can open the same content.
|
||||
|
||||
Don't roll your own. The math is annoying, the edge cases (pointer leaves window, drag in progress, content unmounts) are subtle, and we already paid for the hook.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user