useDragAction: activation-click grace + curve fence commit sfx

The legacy CurveFenceTool ignored grid:click for 150ms after mount —
otherwise the very click that activates a tool (e.g. the floating menu
"curve" button) cascades through the R3F drei <Html> portal into the
grid, fires grid:click on the just-mounted tool, and commits the drag
before any preview move runs. The new useDragAction was missing this
guard, so the Stage D fence curve port "click → place sfx → exit"
without ever letting the user adjust.

Adds `activationGraceMs` (default 150) on useDragAction; ports the
sfx:item-place commit emission into FenceCurveTool so the kind-owned
tool matches legacy UX. Same guard will cover the upcoming Stage D
ports (endpoint move, whole-fence move, placement, plus
slab/ceiling/wall D).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-05-15 17:29:04 -04:00
co-authored by Claude Opus 4.7
parent 8ca9686b27
commit 1082b62552
2 changed files with 23 additions and 5 deletions
+5 -4
View File
@@ -1,7 +1,7 @@
'use client'
import { type FenceNode, getWallMidpointHandlePoint, useScene } from '@pascal-app/core'
import { CursorSphere, useDragAction, useEditor } from '@pascal-app/editor'
import { CursorSphere, triggerSFX, useDragAction, useEditor } from '@pascal-app/editor'
import { useViewer } from '@pascal-app/viewer'
import { useEffect, useState } from 'react'
import { curveFenceDragAction } from './actions/curve'
@@ -31,7 +31,8 @@ export const FenceCurveTool: React.FC<{ node: FenceNode }> = ({ node }) => {
initialHandle.y,
])
const exitCurveMode = () => {
const exitCurveMode = (committed: boolean) => {
if (committed) triggerSFX('sfx:item-place')
useViewer.getState().setSelection({ selectedIds: [node.id] })
useEditor.getState().setCurvingFence(null)
}
@@ -46,8 +47,8 @@ export const FenceCurveTool: React.FC<{ node: FenceNode }> = ({ node }) => {
// placeholder until the first grid:move fires.
point: [initialHandle.x, initialHandle.y],
},
onCommit: exitCurveMode,
onCancel: exitCurveMode,
onCommit: () => exitCurveMode(true),
onCancel: () => exitCurveMode(false),
})
// Mirror the active curveOffset back into the cursor position. The