diff --git a/apps/web/reactCompiledFiles.ts b/apps/web/reactCompiledFiles.ts index 2e0355c18391..c6d90758a015 100644 --- a/apps/web/reactCompiledFiles.ts +++ b/apps/web/reactCompiledFiles.ts @@ -91,4 +91,5 @@ export const REACT_COMPILED_FILES = [ "apps/web/src/components/settings/ThemeImportDialog.tsx", "apps/web/src/components/settings/SnapShotSettings.tsx", "apps/web/src/components/settings/ConnectionsSettings.tsx", + "apps/web/src/hooks/useResizeDrag.ts", ] as const; diff --git a/apps/web/src/hooks/useResizeDrag.ts b/apps/web/src/hooks/useResizeDrag.ts index 6f6c8c27dcab..58863bffe10b 100644 --- a/apps/web/src/hooks/useResizeDrag.ts +++ b/apps/web/src/hooks/useResizeDrag.ts @@ -1,4 +1,4 @@ -import { type PointerEvent, useCallback, useEffect, useLayoutEffect, useRef } from "react"; +import { type PointerEvent, useEffect, useEffectEvent, useLayoutEffect, useRef } from "react"; interface ResizeSession { width: number; @@ -23,51 +23,51 @@ export function useResizeDrag( frame: number | null; } | null>(null); - const flush = useCallback(() => { + const flush = () => { const active = drag.current; if (!active) return; const delta = (active.pendingX - active.startX) * (active.session.edge === "left" ? -1 : 1); - active.moved ||= Math.abs(delta) > 2; + if (Math.abs(delta) > 2) active.moved = true; active.width = active.session.resize(active.session.width + delta); - }, []); + }; - const finish = useCallback( - (commit = true) => { - const active = drag.current; - if (!active) return; - if (active.frame !== null) cancelAnimationFrame(active.frame); - if (commit) flush(); - // Release can synchronously dispatch lostpointercapture. - drag.current = null; - try { - if (active.target.hasPointerCapture(active.pointerId)) { - active.target.releasePointerCapture(active.pointerId); - } - } catch {} - document.body.style.removeProperty("cursor"); - document.body.style.removeProperty("user-select"); - active.session.cleanup?.(commit); - if (commit) active.session.finish(active.width, active.moved); - }, - [flush], - ); + const finish = (commit = true) => { + const active = drag.current; + if (!active) return; + if (active.frame !== null) cancelAnimationFrame(active.frame); + if (commit) flush(); + // Release can synchronously dispatch lostpointercapture. + drag.current = null; + try { + if (active.target.hasPointerCapture(active.pointerId)) { + active.target.releasePointerCapture(active.pointerId); + } + } catch {} + document.body.style.removeProperty("cursor"); + document.body.style.removeProperty("user-select"); + active.session.cleanup?.(commit); + if (commit) active.session.finish(active.width, active.moved); + }; + + // The effects must not rerun while a drag is live: their cleanup cancels it. + const finishDrag = useEffectEvent((commit: boolean) => finish(commit)); const previousResetKey = useRef(resetKey); useLayoutEffect(() => { if (previousResetKey.current !== resetKey) { - finish(false); + finishDrag(false); previousResetKey.current = resetKey; } - }, [finish, resetKey]); + }, [resetKey]); useEffect(() => { - const onBlur = () => finish(); + const onBlur = () => finishDrag(true); window.addEventListener("blur", onBlur); return () => { window.removeEventListener("blur", onBlur); - finish(false); + finishDrag(false); }; - }, [finish]); + }, []); const end = (event: PointerEvent, usePosition: boolean) => { const active = drag.current; @@ -109,7 +109,7 @@ export function useResizeDrag( if (!active || active.pointerId !== event.pointerId) return; event.preventDefault(); active.pendingX = event.clientX; - active.moved ||= Math.abs(event.clientX - active.startX) > 2; + if (Math.abs(event.clientX - active.startX) > 2) active.moved = true; if (active.frame !== null) return; active.frame = requestAnimationFrame(() => { active.frame = null;