From 79cb020c85a2a8de1c4baa928c3128fc510a0255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86motion=20Studio?= <163354043+AEmotionStudio@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:04:09 -0800 Subject: [PATCH] fix: glass drag cursor stuck in grab mode after release --- CHANGELOG.md | 1 + src/magnify-glass/UiManager.ts | 12 ++++++++++++ web/magnify-glass/UiManager.js | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d7e18..3ffcea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `UIManager.hide()` now calls `cleanupEditors()` to destroy all active drag controllers, editors, and inline controls. - Fixed CSS `display: flex !important` on `.persist-active` overriding inline `display: none`, keeping the panel fully interactive while visually hidden. - Added `pointer-events: none` safety net on panel and floating controls when hidden, with proper restoration on re-show. +- **Glass Drag Cursor Stuck**: Fixed the magnify glass drag mode not resetting `document.body` cursor and `userSelect` after releasing, leaving the cursor permanently in grab/scroll mode. --- diff --git a/src/magnify-glass/UiManager.ts b/src/magnify-glass/UiManager.ts index 5107751..33d52e4 100644 --- a/src/magnify-glass/UiManager.ts +++ b/src/magnify-glass/UiManager.ts @@ -134,6 +134,10 @@ export class UiManager { this.glassDiv!.style.bottom = 'auto'; this.glassDiv!.style.transform = 'none'; // Clear any centering transforms if they exist + // Set body cursor so it persists even when dragging outside the glass div + document.body.style.cursor = 'all-scroll'; + document.body.style.userSelect = 'none'; + const onMouseMove = (moveEvent: MouseEvent) => { moveEvent.preventDefault(); moveEvent.stopPropagation(); @@ -153,6 +157,10 @@ export class UiManager { document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); + // Reset body cursor and user-select + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + // Disable drag mode after drop this.state.isDragModeEnabled = false; this.setDragMode(false); @@ -175,6 +183,10 @@ export class UiManager { this.glassDiv.style.pointerEvents = 'none'; this.glassDiv.classList.remove('drag-mode'); + // Safety: ensure body cursor/userSelect are reset in case mouseup was missed + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + // Remove drag handler if ((this.glassDiv as any)._dragHandler) { this.glassDiv.removeEventListener('mousedown', (this.glassDiv as any)._dragHandler); diff --git a/web/magnify-glass/UiManager.js b/web/magnify-glass/UiManager.js index 9f45d78..b70b813 100644 --- a/web/magnify-glass/UiManager.js +++ b/web/magnify-glass/UiManager.js @@ -98,6 +98,8 @@ class UiManager { this.glassDiv.style.right = "auto"; this.glassDiv.style.bottom = "auto"; this.glassDiv.style.transform = "none"; + document.body.style.cursor = "all-scroll"; + document.body.style.userSelect = "none"; const onMouseMove = (moveEvent) => { moveEvent.preventDefault(); moveEvent.stopPropagation(); @@ -111,6 +113,8 @@ class UiManager { const onMouseUp = (upEvent) => { document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mouseup", onMouseUp); + document.body.style.cursor = ""; + document.body.style.userSelect = ""; this.state.isDragModeEnabled = false; this.setDragMode(false); const infoPanel = window.infoPanelManager; @@ -127,6 +131,8 @@ class UiManager { this.glassDiv.style.cursor = ""; this.glassDiv.style.pointerEvents = "none"; this.glassDiv.classList.remove("drag-mode"); + document.body.style.cursor = ""; + document.body.style.userSelect = ""; if (this.glassDiv._dragHandler) { this.glassDiv.removeEventListener("mousedown", this.glassDiv._dragHandler); delete this.glassDiv._dragHandler;