()
| 91 | const silllessWindowTypes = new Set<WindowNode['windowType']>(['bay', 'bow']) |
| 92 | |
| 93 | export default function WindowPanel() { |
| 94 | const selectedId = useViewer((s) => s.selection.selectedIds[0]) |
| 95 | const setSelection = useViewer((s) => s.setSelection) |
| 96 | const deleteNode = useScene((s) => s.deleteNode) |
| 97 | const setMovingNode = useEditor((s) => s.setMovingNode) |
| 98 | const previewRef = useRef<{ |
| 99 | id: AnyNodeId |
| 100 | key: keyof WindowNode |
| 101 | value: unknown |
| 102 | } | null>(null) |
| 103 | |
| 104 | const node = useScene((s) => |
| 105 | selectedId ? (s.nodes[selectedId as AnyNode['id']] as WindowNode | undefined) : undefined, |
| 106 | ) |
| 107 | |
| 108 | // Panel slider-drag fix recipe (plans/editor-node-registry.md). Without |
| 109 | // it, the 15+ SliderControls in this panel would loop on drag. |
| 110 | const handleUpdate = useCallback( |
| 111 | (updates: Partial<WindowNode>) => { |
| 112 | if (!selectedId) return |
| 113 | const liveNode = useScene.getState().nodes[selectedId as AnyNodeId] |
| 114 | if (liveNode?.type !== 'window') return |
| 115 | |
| 116 | const hasChange = Object.entries(updates).some(([key, value]) => { |
| 117 | const currentValue = liveNode[key as keyof WindowNode] |
| 118 | return !isSameWindowValue(currentValue, value) |
| 119 | }) |
| 120 | if (!hasChange) return |
| 121 | |
| 122 | useScene.getState().updateNode(selectedId as AnyNode['id'], updates) |
| 123 | const scene = useScene.getState() |
| 124 | scene.dirtyNodes.add(selectedId as AnyNodeId) |
| 125 | if (liveNode.parentId) scene.dirtyNodes.add(liveNode.parentId as AnyNodeId) |
| 126 | }, |
| 127 | [selectedId], |
| 128 | ) |
| 129 | |
| 130 | const previewWindowUpdate = useCallback( |
| 131 | <K extends keyof WindowNode>(key: K, value: WindowNode[K]) => { |
| 132 | if (!selectedId) return |
| 133 | const liveNode = useScene.getState().nodes[selectedId as AnyNodeId] |
| 134 | if (liveNode?.type !== 'window') return |
| 135 | |
| 136 | if ( |
| 137 | !( |
| 138 | previewRef.current && |
| 139 | previewRef.current.id === selectedId && |
| 140 | previewRef.current.key === key |
| 141 | ) |
| 142 | ) { |
| 143 | previewRef.current = { |
| 144 | id: selectedId as AnyNodeId, |
| 145 | key, |
| 146 | value: liveNode[key], |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | if (isSameWindowValue(liveNode[key], value)) return |
nothing calls this directly
no test coverage detected
searching dependent graphs…