Phase 5 Stage D ceiling: port placement + move + boundary/hole editors

Replicates the slab Stage D recipe for ceiling: four affordances
routed through the registry — def.tool for the placement flow,
def.affordanceTools for boundary edit / hole edit / whole-ceiling move.

Ceiling-specific bits preserved:
- Placement tool keeps the dual-cursor + vertical TSL-gradient
  connector + ground-shadow lines (1:1 with legacy).
- Move tool wrapper renders the translucent preview fill + outline
  overlay so the user sees the destination before clicking.

ToolManager mount sites for CeilingBoundaryEditor / CeilingHoleEditor
now route through `getRegistryAffordanceTool` with legacy fallback.

Per-kind progress: ceiling A  B (n/a, def.renderer escape hatch
preserved) C  D ; E + F pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-05-15 18:31:40 -04:00
co-authored by Claude Opus 4.7
parent b2e5d84986
commit de3efa1b53
7 changed files with 733 additions and 6 deletions
@@ -204,12 +204,31 @@ export const ToolManager: React.FC = () => {
<SlabHoleEditor holeIndex={editingHole.holeIndex} slabId={selectedSlabId} />
)
})()}
{showCeilingBoundaryEditor && selectedCeilingId && (
<CeilingBoundaryEditor ceilingId={selectedCeilingId} />
)}
{showCeilingHoleEditor && selectedCeilingId && editingHole && (
<CeilingHoleEditor ceilingId={selectedCeilingId} holeIndex={editingHole.holeIndex} />
)}
{showCeilingBoundaryEditor &&
selectedCeilingId &&
(() => {
const Registry = getRegistryAffordanceTool('ceiling', 'boundary-edit')
return Registry ? (
<Suspense fallback={null}>
<Registry ceilingId={selectedCeilingId} />
</Suspense>
) : (
<CeilingBoundaryEditor ceilingId={selectedCeilingId} />
)
})()}
{showCeilingHoleEditor &&
selectedCeilingId &&
editingHole &&
(() => {
const Registry = getRegistryAffordanceTool('ceiling', 'hole-edit')
return Registry ? (
<Suspense fallback={null}>
<Registry ceilingId={selectedCeilingId} holeIndex={editingHole.holeIndex} />
</Suspense>
) : (
<CeilingHoleEditor ceilingId={selectedCeilingId} holeIndex={editingHole.holeIndex} />
)
})()}
{movingWallEndpoint && <MoveWallEndpointTool target={movingWallEndpoint} />}
{movingFenceEndpoint &&
(() => {