From 0effda29feba5dc989eae7977b0f8186971f4ed9 Mon Sep 17 00:00:00 2001 From: sudhir Date: Fri, 17 Apr 2026 11:08:01 +0530 Subject: [PATCH] Support duplicating and moving new walls --- .../editor/floating-action-menu.tsx | 7 +++- .../components/tools/wall/move-wall-tool.tsx | 36 +++++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/editor/src/components/editor/floating-action-menu.tsx b/packages/editor/src/components/editor/floating-action-menu.tsx index 05fb368c..db8a00c6 100755 --- a/packages/editor/src/components/editor/floating-action-menu.tsx +++ b/packages/editor/src/components/editor/floating-action-menu.tsx @@ -14,7 +14,7 @@ import { StairSegmentNode, sceneRegistry, useScene, - type WallNode, + WallNode, WindowNode, } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' @@ -210,6 +210,8 @@ export function FloatingActionMenu() { duplicate = WindowNode.parse(duplicateInfo) } else if (node.type === 'item') { duplicate = ItemNode.parse(duplicateInfo) + } else if (node.type === 'wall') { + duplicate = WallNode.parse(duplicateInfo) } else if (node.type === 'fence') { duplicate = FenceNode.parse(duplicateInfo) duplicate.start = [duplicate.start[0] + 1, duplicate.start[1] + 1] @@ -241,6 +243,8 @@ export function FloatingActionMenu() { if (duplicate) { if (duplicate.type === 'door' || duplicate.type === 'window') { useScene.getState().createNode(duplicate, duplicate.parentId as AnyNodeId) + } else if (duplicate.type === 'wall') { + useScene.getState().createNode(duplicate, duplicate.parentId as AnyNodeId) } else if (duplicate.type === 'fence') { useScene.getState().createNode(duplicate, duplicate.parentId as AnyNodeId) } else if ( @@ -310,6 +314,7 @@ export function FloatingActionMenu() { } if ( duplicate.type === 'item' || + duplicate.type === 'wall' || duplicate.type === 'fence' || duplicate.type === 'window' || duplicate.type === 'door' || diff --git a/packages/editor/src/components/tools/wall/move-wall-tool.tsx b/packages/editor/src/components/tools/wall/move-wall-tool.tsx index 28e9cbee..0811992e 100644 --- a/packages/editor/src/components/tools/wall/move-wall-tool.tsx +++ b/packages/editor/src/components/tools/wall/move-wall-tool.tsx @@ -19,6 +19,16 @@ function samePoint(a: [number, number], b: [number, number]) { return a[0] === b[0] && a[1] === b[1] } +function stripWallIsNewMetadata(meta: WallNode['metadata']): WallNode['metadata'] { + if (!meta || typeof meta !== 'object' || Array.isArray(meta)) { + return meta + } + + const nextMeta = { ...(meta as Record) } + delete nextMeta.isNew + return nextMeta +} + type LinkedWallSnapshot = { id: WallNode['id'] start: [number, number] @@ -86,6 +96,11 @@ function getLinkedWallUpdates( } export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { + const meta = + typeof node.metadata === 'object' && node.metadata !== null && !Array.isArray(node.metadata) + ? (node.metadata as Record) + : {} + const isNew = !!meta.isNew const activatedAtRef = useRef(Date.now()) const previousGridPosRef = useRef<[number, number] | null>(null) const originalStartRef = useRef<[number, number]>([...node.start] as [number, number]) @@ -99,12 +114,14 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { (node.end[1] - node.start[1]) / 2, ]) const linkedOriginalsRef = useRef( - getLinkedWallSnapshots({ - wallId: node.id, - wallParentId: node.parentId ?? null, - originalStart: node.start, - originalEnd: node.end, - }), + isNew + ? [] + : getLinkedWallSnapshots({ + wallId: node.id, + wallParentId: node.parentId ?? null, + originalStart: node.start, + originalEnd: node.end, + }), ) const dragAnchorRef = useRef<[number, number] | null>(null) const nodeIdRef = useRef(node.id) @@ -223,6 +240,11 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { preview.end, ), ]) + if (isNew) { + useScene.getState().updateNode(nodeId, { + metadata: stripWallIsNewMetadata(node.metadata), + }) + } useScene.temporal.getState().pause() sfxEmitter.emit('sfx:item-place') @@ -295,7 +317,7 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => { window.removeEventListener('keydown', onKeyDown) window.removeEventListener('keyup', onKeyUp) } - }, [exitMoveMode]) + }, [exitMoveMode, isNew, node.metadata]) return (