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:
co-authored by
Claude Opus 4.7
parent
b2e5d84986
commit
de3efa1b53
@@ -0,0 +1,47 @@
|
||||
'use client'
|
||||
|
||||
import { type CeilingNode, resolveLevelId, useScene } from '@pascal-app/core'
|
||||
import { PolygonEditor } from '@pascal-app/editor'
|
||||
import { useViewer } from '@pascal-app/viewer'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
/**
|
||||
* Phase 5 Stage D — ceiling boundary editor (registry-driven).
|
||||
*
|
||||
* Thin wrapper around the shared `<PolygonEditor>` (same shape as
|
||||
* slab's boundary-editor). Activates when a ceiling is selected in
|
||||
* structure/select mode and no hole edit is in progress.
|
||||
*/
|
||||
export const CeilingBoundaryEditor: React.FC<{ ceilingId: CeilingNode['id'] }> = ({
|
||||
ceilingId,
|
||||
}) => {
|
||||
const ceilingNode = useScene((s) => s.nodes[ceilingId])
|
||||
const updateNode = useScene((s) => s.updateNode)
|
||||
const setSelection = useViewer((s) => s.setSelection)
|
||||
|
||||
const ceiling = ceilingNode?.type === 'ceiling' ? (ceilingNode as CeilingNode) : null
|
||||
|
||||
const handlePolygonChange = useCallback(
|
||||
(newPolygon: Array<[number, number]>) => {
|
||||
updateNode(ceilingId, { polygon: newPolygon })
|
||||
setSelection({ selectedIds: [ceilingId] })
|
||||
},
|
||||
[ceilingId, updateNode, setSelection],
|
||||
)
|
||||
|
||||
if (!ceiling?.polygon || ceiling.polygon.length < 3) return null
|
||||
|
||||
return (
|
||||
<PolygonEditor
|
||||
allowEdgeMove
|
||||
color="#d4d4d4"
|
||||
levelId={resolveLevelId(ceiling, useScene.getState().nodes)}
|
||||
minVertices={3}
|
||||
onPolygonChange={handlePolygonChange}
|
||||
polygon={ceiling.polygon}
|
||||
surfaceHeight={ceiling.height ?? 2.5}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default CeilingBoundaryEditor
|
||||
Reference in New Issue
Block a user