From ac0c7b221006dd4e208e9db9dd0af1053963d8d8 Mon Sep 17 00:00:00 2001 From: Tanish Manku Date: Fri, 1 May 2026 17:18:07 -0700 Subject: [PATCH] PageScene: stop overlay click handler from silencing portal'd modal clicks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two PageScene-only divergences from how the working pages (PageDraw / PageImage / PageVideo) handle the same upload modals: 1. `handleOverlayClick` on the top/bottom controls overlays called `event.stopPropagation()` for every click that bubbled through them. Modals rendered as JSX children of `Controls3D` (the upload-3D / upload-image / upload-splat dialogs) are React-tree descendants even though `Modal`'s `Dialog.Portal` puts them at `document.body` in the DOM. React synthetic stopPropagation calls native `Event.stopPropagation()`, which silences `react-drag-drop-files`'s native `addEventListener("click", u)` on the file-input label — so clicking the drop zone never opens the OS file picker. Narrow the handler to `event.target === event.currentTarget` so it only fires on the transparent overlay area itself, never on bubbles from children. The original "control buttons don't interact with canvas" intent is preserved without the side effect — the canvas listener is bound to the canvas element only, so clicks on overlay siblings never reach it regardless. 2. `tabIndex={0}` + `outline: none` on the editor canvas. Added in `61c4936c29` "so [the canvas] can receive keyboard focus," but `useViewportKeyboard` listens at `document` (not on canvas) so the focus isn't actually required. Other pages don't make their canvas focusable; remove for parity. --- .../apps/artcraft/app/src/pages/PageScene/PageEditor.tsx | 9 ++++++++- .../app/src/pages/PageScene/comps/EngineCanvases.tsx | 2 -- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/PageEditor.tsx b/frontend/apps/artcraft/app/src/pages/PageScene/PageEditor.tsx index 73fb79432f..0227f8e9db 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/PageEditor.tsx +++ b/frontend/apps/artcraft/app/src/pages/PageScene/PageEditor.tsx @@ -112,8 +112,15 @@ export const PageEditor = () => { const updateCamera = usePageSceneStore((s) => s.updateCamera); const deleteCamera = usePageSceneStore((s) => s.deleteCamera); const setSelectedCameraId = usePageSceneStore((s) => s.setSelectedCameraId); + // Only stops propagation for clicks on the overlay div itself (the + // transparent gaps between control buttons). Clicks that bubbled up + // from child controls pass through untouched, so React-tree-portal'd + // modals further down the JSX (the upload modals inside Controls3D) + // aren't silenced when the user clicks inside them. const handleOverlayClick = (event: React.MouseEvent) => { - event.stopPropagation(); + if (event.target === event.currentTarget) { + event.stopPropagation(); + } }; useEffect(() => { diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/comps/EngineCanvases.tsx b/frontend/apps/artcraft/app/src/pages/PageScene/comps/EngineCanvases.tsx index b41e095d0e..45e56c46c9 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/comps/EngineCanvases.tsx +++ b/frontend/apps/artcraft/app/src/pages/PageScene/comps/EngineCanvases.tsx @@ -17,8 +17,6 @@ export const EditorCanvas = () => { id="video-scene" width="1280px" height="720px" - tabIndex={0} - style={{ outline: "none" }} /> ); };