Skip to content
Prev Previous commit
Next Next commit
fix(wall): let the 2D-only view own the typed Enter commit
Bugbot cb434c3d (round 4, high): the 3D tool's capture-phase Enter
handler synthesized grid:click and stopped the event, so the 2D Enter
path never ran handleWallPlacementPoint. In 2D-only that click pipeline
commits nothing (the canvas is display:none), so a typed Enter silently
did nothing; in split view the 3D commit left the panel's draftStart on
the previous segment, so the next 2D preview and typed commit projected
from a stale origin.

The tool's key handler now yields in 2D-only view — the floor-plan
panel is the committer there (view-gated createWallOnCurrentLevel
already exists). For split view, the panel subscribes to the chain
start the 3D tool publishes on useSegmentDraftChain and re-bases its
draft onto it, so both views keep drafting from the same point with a
single commit owner. The subscription re-arms reactively on
mode/tool instead of reading the store once at mount.

check-types + biome + editor (1072) + nodes (3393) suites pass.
  • Loading branch information
dkbbdev committed Sep 28, 2026
commit 43d7a64e15230e45f06347d731352bfce2d68672
19 changes: 19 additions & 0 deletions packages/editor/src/components/editor/floorplan-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5159,6 +5159,25 @@ export function FloorplanPanel({
// Walls committed by the current 2D-only chain — exclusion set for the
// T-junction chain-termination test (mirrors the 3D tool's `chainWallIds`).
const wallChainWallIdsRef = useRef<string[]>([])
// Split view: the 3D wall tool owns the commit and publishes each segment's
// resolved end as the chain start. Re-base this panel's draft onto it so a
// typed Enter in the plan projects from the segment the 3D chain is
// actually drafting — without this, `draftStart` stays on the last point
// the panel itself placed and the typed commit uses a stale origin
// (Bugbot cb434c3d). In 2D-only the panel is the committer and never
// publishes, so this subscription stays dormant there.
useEffect(() => {
if (!(mode === 'build' && tool === 'wall')) return
return useSegmentDraftChain.subscribe((state, previousState) => {
const next = state.wall
if (next === previousState.wall) return
if (!next) return
setDraftStart((current) =>
current && current[0] === next[0] && current[1] === next[1] ? current : next,
)
setWallChainFirstVertex((current) => current ?? next)
})
Comment thread
cursor[bot] marked this conversation as resolved.
}, [mode, tool])
const setDraftEnd = useCallback(
(next: WallPlanPoint | null | ((prev: WallPlanPoint | null) => WallPlanPoint | null)) => {
const store = useFloorplanDraftPreview.getState()
Expand Down
9 changes: 9 additions & 0 deletions packages/nodes/src/wall/tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,15 @@ export const WallTool: React.FC = () => {
// Enter commits at the typed length along the current draft direction.
const onKeyDown = (event: KeyboardEvent) => {
if (buildingState.current !== 1) return
// 2D-only view: the floor-plan panel owns the wall commit there — this
// tool's `grid:click` pipeline never commits while the canvas is
// `display:none`, so capture-consuming the typing keys here would leave
// a typed Enter with no owner and commit nothing (Bugbot cb434c3d:
// "Enter skips 2D wall commit"). Let the panel's bubble-phase handler
// see them instead. The panel re-bases its draft onto the chain start
// this tool publishes, so split view keeps a single owner (this tool)
// while 2D-only hands the keyboard to the view that commits.
if (useEditor.getState().viewMode === '2d') return
const as HTMLElement | null
if (
target instanceof HTMLInputElement ||
Expand Down