bug: Component hover outline stays visible after a drag starts

Fixes: #3591929

Problem

The hover outline Canvas draws around a component in the preview can stay on a component the pointer is no longer interacting with. Reported with two triggers: it stays visible when you start dragging, and it stays visible when you move the pointer out of the component.

Root cause

The preview overlay keeps a single uuid. writes it on and clears it on , and the handler already refuses to set it while a drag is in progress — so the intended invariant is "nothing is hovered while dragging". Nothing enforced that invariant on the transition into a drag.

The drag sensor activates after 3px of pointer movement and components are much bigger than 3px, so a normal drag starts without the pointer ever crossing the component's boundary. No fires, the stale uuid survives, and the component keeps its hover outline for the whole drag — and past the end of it, through drop, through an invalid drop, and through cancelling with Escape. It only clears the next time the pointer happens to cross some overlay's boundary, which is why it reads as intermittent, and why "moving the pointer out doesn't hide it" is the second face of the same defect.

Reproduced live in the editor, with the component's computed staying at the hover purple through the drag and after release:

The layers panel already clears the hovered component on its own drag start; the preview overlay had no equivalent.

Fix

clears . That is the one place that observes the start of every drag regardless of origin (preview overlay, library, layers panel, code editor), so the invariant is enforced once rather than per drag source. No new state, no timers, no global pointer listeners.

Testing

  • New Playwright test in
    hovers a component with a real pointer, starts a drag that stays inside its bounds, and asserts nothing is hovered during and after the drag. Fails before the fix ( hovered overlays), passes after.
  • Manually verified in a live editor against a production UI build, before and after: the repro, plus exiting the component slowly / in one jump / across each edge / past the viewport bounds / into the sidebar, releasing over an invalid target, Escape mid-drag, right-click context menu open and dismiss, undo and duplicate while hovered, layers-panel hover, library drag-in, and a real drag-and-drop that moves a component. Normal hover, drop-target name tags, and drop behaviour are unchanged.
  • UI Vitest: 762 tests in 65 files pass. , ESLint, and Prettier clean.

🤖 Generated with Claude Code

Edited by Lauri Timmanee

Merge request reports

Loading