11/// <reference types="vite-plugin-svgr/client" />
22
3- import { makeIID , placedNodeId } from "@/logic/simulation"
4- import { useContext , useEffect , useRef , useState } from "react"
3+ import { makeIID , placedNodeId , type NodeType } from "@/logic/simulation"
4+ import { useContext , useEffect , useRef , useState , type ReactNode } from "react"
55import { MouseTooltip } from "./MouseTooltip"
6- import { int2hex } from "@/lib/utils"
7- import ShiftComponent from "@/assets/shift.svg?react"
6+ import { cn , int2hex } from "@/lib/utils"
87import { MousePositionContext } from "@/context/MousePositionContext"
98import { useSimulationContext } from "@/context/SimulationContext"
10- import { makeShifter } from "@/logic/nodeTypes/shift "
9+ import { X } from "lucide-react "
1110
1211/**
1312 * The stroke width of the duplicate wires for interaction, in pixels.
@@ -16,19 +15,38 @@ const INTERACTION_STROKE_WIDTH = 6
1615
1716const strokeCSSVariable = ( node : string , input : string ) => `--${ node } -${ input } `
1817
19- function MouseNode ( props : {
20- svg : React . FunctionComponent < React . SVGProps < SVGSVGElement > >
21- placeable : boolean
18+ function PlacedNode ( props : {
19+ type : NodeType
20+ className ?: string
21+ style : React . CSSProperties
22+ children ?: ReactNode
2223} ) {
24+ return (
25+ < div
26+ className = { cn (
27+ "absolute p-2 font-bold bg-white border-[2px] border-black rounded-t-[50%_50%] rounded-b-[50%_50%] pointer-events-none select-none whitespace-pre-line" ,
28+ props . className ,
29+ ) }
30+ style = { {
31+ translate : "-50% -50%" ,
32+ ...props . style ,
33+ } }
34+ >
35+ { props . type . label }
36+ { props . children }
37+ </ div >
38+ )
39+ }
40+
41+ function MouseNode ( props : { type : NodeType ; placeable : boolean } ) {
2342 const mousePos = useContext ( MousePositionContext )
2443
2544 return (
26- < props . svg
27- className = "absolute pointer-events-none"
45+ < PlacedNode
46+ type = { props . type }
2847 style = { {
2948 left : mousePos . x ,
3049 top : mousePos . y ,
31- translate : "-50% -50%" ,
3250 opacity : props . placeable ? 1 : 0.4 ,
3351 } }
3452 />
@@ -38,12 +56,17 @@ function MouseNode(props: {
3856export function Diagram ( props : {
3957 svg : React . FunctionComponent < React . SVGProps < SVGSVGElement > >
4058} ) {
41- const { placedNodes, setPlacedNodes, simulation } = useSimulationContext ( )
59+ const {
60+ placedNodes,
61+ setPlacedNodes,
62+ simulation,
63+ placingNode,
64+ setPlacingNode,
65+ } = useSimulationContext ( )
4266 const svgRef = useRef < SVGSVGElement | null > ( null )
4367 const [ hoveredWire , setHoveredWire ] = useState <
4468 { nodeId : string ; inputId : string ; bits : number } | undefined
4569 > ( undefined )
46- const [ isPlacingNode , setIsPlacingNode ] = useState ( false )
4770
4871 useEffect ( ( ) => {
4972 if ( ! svgRef . current ) {
@@ -89,7 +112,7 @@ export function Diagram(props: {
89112 } , [ ] )
90113
91114 const onDiagramClick : React . MouseEventHandler < SVGSVGElement > = ( e ) => {
92- if ( hoveredWire && isPlacingNode && svgRef . current ) {
115+ if ( hoveredWire && placingNode && svgRef . current ) {
93116 const { left, top } = svgRef . current . getBoundingClientRect ( )
94117 setPlacedNodes (
95118 new Map ( [
@@ -99,12 +122,12 @@ export function Diagram(props: {
99122 {
100123 x : e . clientX - left ,
101124 y : e . clientY - top ,
102- nodeType : makeShifter ( "left" , 2 ) ,
125+ nodeType : placingNode ,
103126 } ,
104127 ] ,
105128 ] ) ,
106129 )
107- setIsPlacingNode ( false )
130+ setPlacingNode ( undefined )
108131 }
109132 }
110133
@@ -143,7 +166,7 @@ export function Diagram(props: {
143166 < props . svg
144167 ref = { svgRef }
145168 style = {
146- hoveredWire && ( ( simulation && tooltipContent ) || isPlacingNode )
169+ hoveredWire && ( ( simulation && tooltipContent ) || placingNode )
147170 ? {
148171 [ strokeCSSVariable ( hoveredWire . nodeId , hoveredWire . inputId ) ] :
149172 "2px" ,
@@ -153,15 +176,28 @@ export function Diagram(props: {
153176 onClick = { onDiagramClick }
154177 />
155178 { [ ...placedNodes . entries ( ) ] . map ( ( [ id , n ] ) => (
156- < ShiftComponent
179+ < PlacedNode
157180 key = { id }
158- className = "absolute pointer-events-none"
181+ className = { "group " + ( simulation ? "" : "pointer-events-auto" ) }
182+ type = { n . nodeType }
159183 style = { { left : n . x , top : n . y , translate : "-50% -50%" } }
160- />
184+ >
185+ { ! simulation && (
186+ < X
187+ size = { 16 }
188+ className = "invisible group-hover:visible absolute bg-red-400 p-0.5 rounded-full text-white right-0 top-0 cursor-pointer"
189+ onClick = { ( ) => {
190+ const newNodes = new Map ( placedNodes )
191+ newNodes . delete ( id )
192+ setPlacedNodes ( newNodes )
193+ } }
194+ />
195+ ) }
196+ </ PlacedNode >
161197 ) ) }
162198 </ div >
163- { isPlacingNode && (
164- < MouseNode svg = { ShiftComponent } placeable = { ! ! hoveredWire } />
199+ { placingNode && (
200+ < MouseNode type = { placingNode } placeable = { ! ! hoveredWire } />
165201 ) }
166202 { tooltipContent && < MouseTooltip > { tooltipContent } </ MouseTooltip > }
167203 </ >
0 commit comments