[Bug Fix] Overlays: release Command scroll lock on teardown, settle Tooltip exit on cancel
Follow-up to #506. That PR moved every overlay's hide behind the exit animation. Two overlays still leak on an interrupted/torn-down close.
CommandDialog — body stays scroll-locked after teardown
show() adds overflow-hidden to <body>; it is removed only in afterExit(). When the dialog is destroyed without a dismiss() (Turbo navigation, turbo:morph on a persisted body), disconnect() → settleExit(panel) sees data-state="open" and returns early, so afterExit() never runs and the page stays unscrollable.
Fix: disconnect() releases the lock unconditionally, independent of exit state.
Tooltip — exit run cut short orphans the cloned node
Tooltip mounts a clone on <body> and removes it on animationend. It never listened for animationcancel, so an exit animation interrupted by a backgrounded tab or a competing style change leaves the clone in the DOM forever. The other overlays already listen for both events; this brings Tooltip in line. The existing animationName === "exit" + data-state === "closed" guards already do the right thing for the cancel case.
How to test
CommandDialog scroll lock
- Open a Command dialog (
<body>gainsoverflow-hidden). - Navigate away via a Turbo link (or trigger a morph) while it is open, instead of closing it.
- Before: the next page cannot scroll —
overflow-hiddenis stuck on<body>. After: the page scrolls normally.
Tooltip orphan
- Hover a tooltip trigger to show it, then move away to start the exit animation.
- Interrupt the exit (switch tabs mid-fade, or remove the trigger).
- Before: a stray tooltip node remains under
document.body. After: it is removed.
Both are JS-only lifecycle fixes; mcp/data/registry.json is regenerated from the two controllers.
Summary by cubic
Fixes CommandDialog leaving <body> scroll-locked when Turbo navigation or morph tears it down mid-open, and fixes Tooltip leaving a cloned node behind when its exit animation is cancelled.
Bug Fixes
- CommandDialog releases the
overflow-hiddenscroll lock ondisconnect()only when the panel is still open; the normal close path already releases it inafterExit(). - Tooltip now listens for
animationcancelin addition toanimationend, so a cut-short exit removes the cloned node. - Both fixes are JS-only;
mcp/data/registry.jsonis regenerated from the two controllers.