fix(web): stop the resize cursor sticking when the panel changes mid-drag - #8503
fix(web): stop the resize cursor sticking when the panel changes mid-drag#8503alundgren wants to merge 6 commits into
Conversation
…drag useResizableWidth sets cursor and user-select on document.body when a drag starts and only clears them from onPointerUp and onPointerCancel. The drag handle unmounts mid-drag when the panel is maximized, switched out of inline mode, or closed, after which no pointer handler can run and both global styles stay behind for the rest of the session. Clean up on unmount when a drag is still in flight, and add regression coverage for the hook. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Warning Your free Security trial is over. An organization admin can activate Security or dismiss this notice. Comment |
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a narrowly scoped web bug fix that ties existing resize cleanup to the drag handle's lifecycle, preventing stale global cursor and selection styles when the panel changes mid-drag. Dedicated regression tests cover both interrupted and normal drag lifecycles without introducing broader production behavior. You can add or adjust custom eligibility rules. Learn more. |
PreviewPanelShell owns the hook but renders the handle only while the panel is inline and not maximized, so maximizing removes the handle without unmounting the hook. The unmount effect never ran for that case, which is the most common way the drag is interrupted. Clean up from a ref callback on the handle instead. It runs when the element leaves the DOM, covering both handle removal and full unmount, and cannot drift out of sync with the condition that renders the handle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Superseded by #10461, which landed on That PR clears the stuck |
Problem
The app can get stuck showing the
col-resizecursor everywhere in the main content area, with text selection disabled alongside it. It persists for the rest of the session. Moving the pointer outside the window restores the normal cursor, and coming back shows the resize cursor again.useResizableWidth()setscursor: col-resizeanduser-select: noneondocument.bodywhen a drag starts, and only clears them fromonPointerUpandonPointerCancel.PreviewPanelShellowns the hook but renders the drag handle only while the panel is inline and not maximized. Maximizing the panel (rightPanel.toggleMaximized), switching its mode, or closing it therefore removes the handle mid-drag. After that no pointer handler can ever run, and both global styles stay behind.Fix
Clean up from a ref callback on the drag handle, reusing the existing
releasePointer(). React runs it when the element leaves the DOM, so it covers both the handle being removed while the hook stays mounted and the panel unmounting outright, and it cannot drift out of sync with the condition that renders the handle.releasePointer()already no-ops without an active drag and tolerates a double release, so normal pointer-up and pointer-cancel are unaffected and the final width still persists.Tests
useResizableWidthhad no coverage. AddeduseResizableWidth.test.tsx, using the DOM-free React harness this suite already uses incomponents/preview/PreviewView.test.tsx. The harness mirrorsPreviewPanelShell: the hook lives in the parent and the handle is rendered conditionally beneath it.Three cases: a normal pointer-down/pointer-up drag, the handle being removed while the hook stays mounted, and the whole panel unmounting mid-drag. The last two fail on
mainwith the body still holdingcol-resize.vp test run apps/web/src/hooks/useResizableWidth.test.tsxvp test run apps/web/src/components/preview/PreviewPanelShell.test.ts apps/web/src/components/preview/PreviewView.test.tsxvp run --filter @t3tools/web typecheckVisual evidence
None. The symptom is the shape of the OS pointer, which a screenshot does not capture.
Not covered
Whether pointer capture can also be lost without the handle being removed, for example on window blur or a native menu opening mid-drag.
Made with Claude Opus 5 in Claude Code.
Note
Fix resize cursor sticking when panel closes mid-drag in
useResizableWidthuseResizableWidthhook now exposes arefcallback on its returned handlers object. Attaching it to the drag handle element ensures that an active drag is terminated and globalcursor/user-selectstyles are cleared if the handle unmounts mid-drag.releasePointer(state.pointerId)when the element is removed while dragging.ResizableWidthHandlersnow requires consumers to attach the newrefto the drag handle; existing consumers that do not wire up the ref will not get the mid-drag unmount cleanup.Macroscope summarized b8702f4.
Note
Low Risk
Localized UI/pointer-drag cleanup with idempotent release logic; no auth, data, or API changes.
Overview
Fixes a session-long col-resize cursor and disabled text selection when the preview panel is maximized, closed, or otherwise removes its drag handle while a resize drag is still active. Previously, global
document.bodystyles were only cleared on pointer up/cancel, so unmounting the handle left no handler to run.useResizableWidthnow returns arefcallback onhandlersthat, on handle unmount, calls the existingreleasePointerpath to drop pointer capture and remove bodycursor/user-select. Consumers that spread handlers onto the handle (e.g.RightPanelResizeHandle) pick this up without extra wiring.Adds
useResizableWidth.test.tsxwith a DOM-free React harness (aligned with preview tests): normal pointer-up cleanup, handle removed mid-drag, and full unmount mid-drag.Reviewed by Cursor Bugbot for commit b8702f4. Bugbot is set up for automated code reviews on this repo. Configure here.