Adds two new MEP node families (HVAC ductwork, DWV plumbing) built on a shared port-connectivity model. Co-authored by @sudhir9297.
44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
'use client'
|
|
|
|
import { type AnyNodeId, useScene } from '@pascal-app/core'
|
|
import { useViewer } from '@pascal-app/viewer'
|
|
import { useEffect } from 'react'
|
|
import { cycleRotationAxis } from '../shared/fitting-rotation'
|
|
|
|
/**
|
|
* Selection-time rotation support for placed pipe fittings — mirrors
|
|
* the duct-fitting affordance, mounted by the editor's
|
|
* SelectionAffordanceManager (`def.affordanceTools.selection`). R/T
|
|
* rotation lives in `def.keyboardActions`; this contributes the piece
|
|
* that hook can't: **Alt cycles the active rotation axis** while a
|
|
* single fitting is selected. The axis lives on `useEditor.rotationAxis`,
|
|
* which the floating action menu reads to show the axis pill — so this
|
|
* component renders nothing.
|
|
*/
|
|
const PipeFittingSelectionAffordance = () => {
|
|
const selectedIds = useViewer((s) => s.selection.selectedIds)
|
|
const hasSelectedFitting = useScene((s) => {
|
|
if (selectedIds.length !== 1) return false
|
|
return s.nodes[selectedIds[0] as AnyNodeId]?.type === 'pipe-fitting'
|
|
})
|
|
|
|
useEffect(() => {
|
|
if (!hasSelectedFitting) return
|
|
const onKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key !== 'Alt' || e.repeat) return
|
|
const tag = (e.target as HTMLElement | null)?.tagName
|
|
if (tag === 'INPUT' || tag === 'TEXTAREA') return
|
|
e.preventDefault()
|
|
cycleRotationAxis()
|
|
}
|
|
// Bubble phase — when the placement tool is active its capture-phase
|
|
// handler stops propagation, so the two never double-cycle.
|
|
window.addEventListener('keydown', onKeyDown)
|
|
return () => window.removeEventListener('keydown', onKeyDown)
|
|
}, [hasSelectedFitting])
|
|
|
|
return null
|
|
}
|
|
|
|
export default PipeFittingSelectionAffordance
|