From 8cc6c41b5168864d888b29ba9554dbb81f17dad3 Mon Sep 17 00:00:00 2001 From: Wassim SAMAD Date: Sat, 27 Jun 2026 16:09:11 -0400 Subject: [PATCH] fix(editor): unstick empty-click deselect after click-to-move Validated live by Wassim. The click-to-move branch set `clickHandledRef = true` then returned early, skipping the 50ms reset the normal select path runs at the end. The flag stayed true, so `onGridClick`'s guard silently blocked every empty-click deselect until the next normal select cleared it. Schedule the reset right after the flag is set so EVERY branch (incl. the early return) clears it. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/components/editor/selection-manager.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/components/editor/selection-manager.tsx b/packages/editor/src/components/editor/selection-manager.tsx index 2f04384b..443cd444 100644 --- a/packages/editor/src/components/editor/selection-manager.tsx +++ b/packages/editor/src/components/editor/selection-manager.tsx @@ -1460,6 +1460,15 @@ export const SelectionManager = () => { if (activeStrategy?.isValid(node)) { event.stopPropagation() clickHandledRef.current = true + // Reset the handled flag after a short delay so the grid:click that the + // SAME DOM click also raycasts is ignored (it fires synchronously, before + // this 50ms macrotask). Scheduled here — right after the flag is set — so + // EVERY branch below clears it, including the click-to-move early return + // (which previously skipped the reset and left empty-click deselect stuck + // until the next normal select). + setTimeout(() => { + clickHandledRef.current = false + }, 50) let nodeToSelect = node if (node.type === 'roof-segment' && node.parentId) { @@ -1582,11 +1591,6 @@ export const SelectionManager = () => { if (!nextMaterialTargetHandled && useEditor.getState().selectedMaterialTarget) { useEditor.getState().setSelectedMaterialTarget(null) } - - // Reset the handled flag after a short delay to allow grid:click to be ignored - setTimeout(() => { - clickHandledRef.current = false - }, 50) } }