From 5c89a72dc8e7447f94f90a763850690a5198546a Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Fri, 3 Apr 2026 02:35:30 +0200 Subject: [PATCH] Add support for hovered viewport panel in transform operations --- src/app/App.tsx | 12 +++++-- .../transform-foundation.integration.test.tsx | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index 7617b864..c1af4b51 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -922,6 +922,7 @@ export function App({ store, initialStatusMessage }: AppProps) { const [statusMessage, setStatusMessage] = useState(initialStatusMessage ?? "Slice 3.5 advanced rendering ready."); const [assetStatusMessage, setAssetStatusMessage] = useState(null); const [hoveredAssetId, setHoveredAssetId] = useState(null); + const [hoveredViewportPanelId, setHoveredViewportPanelId] = useState(null); const [addMenuPosition, setAddMenuPosition] = useState(null); const [preferredNavigationMode, setPreferredNavigationMode] = useState( primaryPlayerStart === null ? "orbitVisitor" : "firstPerson" @@ -1691,6 +1692,8 @@ export function App({ store, initialStatusMessage }: AppProps) { return; } + const transformSourcePanelId = hoveredViewportPanelId ?? activePanelId; + const transformTargetResult = resolveTransformTarget(editorState.document, editorState.selection); const transformTarget = transformTargetResult.target; @@ -1707,17 +1710,21 @@ export function App({ store, initialStatusMessage }: AppProps) { blurActiveTextEntry(); closeAddMenu(); + if (editorState.activeViewportPanelId !== transformSourcePanelId) { + store.setActiveViewportPanel(transformSourcePanelId); + } + store.setTransformSession( createTransformSession({ source, - sourcePanelId: activePanelId, + sourcePanelId: transformSourcePanelId, operation, target: transformTarget }) ); setStatusMessage( `${getTransformOperationLabel(operation)} ${getTransformTargetLabel(transformTarget).toLowerCase()} in ${getViewportPanelLabel( - activePanelId + transformSourcePanelId )}. Move the pointer, press X/Y/Z to constrain, click or press Enter to commit, Escape cancels.` ); }; @@ -4860,6 +4867,7 @@ export function App({ store, initialStatusMessage }: AppProps) { focusRequestId={focusRequest.panelId === panelId ? focusRequest.id : 0} focusSelection={focusRequest.selection} onActivatePanel={handleActivateViewportPanel} + onHoverPanel={setHoveredViewportPanelId} onSetPanelViewMode={handleSetViewportPanelViewMode} onSetPanelDisplayMode={handleSetViewportPanelDisplayMode} onCommitCreation={handleCommitCreation} diff --git a/tests/unit/transform-foundation.integration.test.tsx b/tests/unit/transform-foundation.integration.test.tsx index 1a8c117f..2aee49ce 100644 --- a/tests/unit/transform-foundation.integration.test.tsx +++ b/tests/unit/transform-foundation.integration.test.tsx @@ -194,6 +194,16 @@ async function renderTransformFixtureApp() { }; } +async function renderQuadTransformFixtureApp() { + const fixture = await renderTransformFixtureApp(); + + act(() => { + fixture.store.setViewportLayoutMode("quad"); + }); + + return fixture; +} + function getLatestTransformSession(store: ReturnType): ActiveTransformSession { const transformSession = store.getState().viewportTransientState.transformSession; @@ -418,4 +428,29 @@ describe("transform foundation integration", () => { } }); }); + + it("uses the hovered quad viewport as the active transform panel for keyboard entry", async () => { + const { store, brush } = await renderQuadTransformFixtureApp(); + + await act(async () => { + fireEvent.click(screen.getByRole("button", { name: /^Brush Transform Fixture$/ })); + }); + + fireEvent.pointerEnter(screen.getByTestId("viewport-panel-bottomRight")); + fireEvent.keyDown(window, { + key: "g", + code: "KeyG" + }); + + expect(store.getState().activeViewportPanelId).toBe("bottomRight"); + expect(store.getState().viewportTransientState.transformSession).toMatchObject({ + kind: "active", + operation: "translate", + sourcePanelId: "bottomRight", + target: { + kind: "brush", + brushId: brush.id + } + }); + }); });