Phase 5 Stage D wall: port CurveWallTool to DragAction (first wall D)

Direct copy of the fence curve recipe — pure
`curveWallDragAction` (chord-perpendicular projection + clamp +
normalize + single-undo dance) plus a thin wrapper feeding
`useDragAction`. Mounted via `def.affordanceTools.curve`.

Slight precision difference vs legacy: the legacy CurveWallTool snapped
the pointer position to `getWallGridStep()` before projecting onto the
chord normal; the ported action skips that pre-snap and relies on
`normalizeWallCurveOffset` to settle the final value. The user-visible
result is the same magnitude of step, just with the snap applied at
the offset level instead of the position level.

Remaining wall D affordances (endpoint move, whole-wall move,
placement) are larger and queued for future sessions — wall's move
tool alone is 804 LoC with the linked-wall corner-cascade logic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-05-15 18:34:40 -04:00
co-authored by Claude Opus 4.7
parent de3efa1b53
commit 7f2f9c685b
4 changed files with 162 additions and 1 deletions
@@ -244,7 +244,17 @@ export const ToolManager: React.FC = () => {
<MoveFenceEndpointTool target={movingFenceEndpoint} />
)
})()}
{curvingWall && <CurveWallTool node={curvingWall} />}
{curvingWall &&
(() => {
const Registry = getRegistryAffordanceTool(curvingWall.type, 'curve')
return Registry ? (
<Suspense fallback={null}>
<Registry node={curvingWall} />
</Suspense>
) : (
<CurveWallTool node={curvingWall} />
)
})()}
{curvingFence &&
(() => {
const RegistryAffordance = getRegistryAffordanceTool(curvingFence.type, 'curve')