From 316c11035c6fe622100841d59cf862b9155c4910 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Tue, 21 Apr 2026 02:25:56 +0700 Subject: [PATCH] fix(launch): keep HUD interactive after short drags --- src/components/launch/LaunchWindow.tsx | 30 ++++++++++---- .../launch/hudMousePassthrough.test.ts | 39 +++++++++++++++++++ src/components/launch/hudMousePassthrough.ts | 23 +++++++++++ 3 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 src/components/launch/hudMousePassthrough.test.ts create mode 100644 src/components/launch/hudMousePassthrough.ts diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index 2c4e6146..31ffd0c7 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -1,27 +1,27 @@ import { AppWindow, ArrowCircleUp as ArrowUpCircle, - ArrowClockwise as RefreshCw, - CaretUp as ChevronUp, CheckCircle as CheckCircle2, - DotsThreeVertical as MoreVertical, + CaretUp as ChevronUp, Eye, EyeSlash as EyeOff, FolderOpen, + Translate as Languages, Microphone as Mic, MicrophoneSlash as MicOff, Minus, Monitor, + DotsThreeVertical as MoreVertical, Pause, Play, - SpeakerHigh as Volume2, - SpeakerX as VolumeX, + ArrowClockwise as RefreshCw, Stop as Square, Timer, - Translate as Languages, VideoCamera as Video, VideoCamera as VideoIcon, VideoCameraSlash as VideoOff, + SpeakerHigh as Volume2, + SpeakerX as VolumeX, X, } from "@phosphor-icons/react"; import { AnimatePresence, motion } from "motion/react"; @@ -41,6 +41,7 @@ import { ContentClamp } from "../ui/content-clamp"; import ProjectBrowserDialog, { type ProjectLibraryEntry, } from "../video-editor/ProjectBrowserDialog"; +import { shouldRestoreHudMousePassthroughAfterDrag } from "./hudMousePassthrough"; import styles from "./LaunchWindow.module.css"; interface DesktopSource { @@ -465,7 +466,22 @@ export function LaunchWindow() { if (event.currentTarget.hasPointerCapture(event.pointerId)) { event.currentTarget.releasePointerCapture(event.pointerId); } - if (wasDragging) { + const hudBounds = hudContentRef.current?.getBoundingClientRect(); + if ( + wasDragging && + shouldRestoreHudMousePassthroughAfterDrag( + hudBounds + ? { + left: hudBounds.left, + top: hudBounds.top, + right: hudBounds.right, + bottom: hudBounds.bottom, + } + : null, + event.clientX, + event.clientY, + ) + ) { window.electronAPI?.hudOverlaySetIgnoreMouse?.(true); } }; diff --git a/src/components/launch/hudMousePassthrough.test.ts b/src/components/launch/hudMousePassthrough.test.ts new file mode 100644 index 00000000..bc17e697 --- /dev/null +++ b/src/components/launch/hudMousePassthrough.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; + +import { shouldRestoreHudMousePassthroughAfterDrag } from "./hudMousePassthrough"; + +describe("shouldRestoreHudMousePassthroughAfterDrag", () => { + it("keeps the HUD interactive when the pointer is still inside the HUD", () => { + expect( + shouldRestoreHudMousePassthroughAfterDrag( + { left: 100, top: 200, right: 300, bottom: 260 }, + 180, + 230, + ), + ).toBe(false); + }); + + it("keeps the HUD interactive when the pointer ends on the HUD edge", () => { + expect( + shouldRestoreHudMousePassthroughAfterDrag( + { left: 100, top: 200, right: 300, bottom: 260 }, + 300, + 260, + ), + ).toBe(false); + }); + + it("restores passthrough when the pointer ends outside the HUD", () => { + expect( + shouldRestoreHudMousePassthroughAfterDrag( + { left: 100, top: 200, right: 300, bottom: 260 }, + 301, + 261, + ), + ).toBe(true); + }); + + it("restores passthrough when no HUD bounds are available", () => { + expect(shouldRestoreHudMousePassthroughAfterDrag(null, 180, 230)).toBe(true); + }); +}); diff --git a/src/components/launch/hudMousePassthrough.ts b/src/components/launch/hudMousePassthrough.ts new file mode 100644 index 00000000..50d190d4 --- /dev/null +++ b/src/components/launch/hudMousePassthrough.ts @@ -0,0 +1,23 @@ +export interface HudInteractiveBounds { + left: number; + top: number; + right: number; + bottom: number; +} + +export function shouldRestoreHudMousePassthroughAfterDrag( + bounds: HudInteractiveBounds | null, + clientX: number, + clientY: number, +): boolean { + if (!bounds) { + return true; + } + + return ( + clientX < bounds.left || + clientX > bounds.right || + clientY < bounds.top || + clientY > bounds.bottom + ); +}