@tscircuit/schematic-viewer 2.0.4 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/biome.json CHANGED
@@ -29,11 +29,15 @@
29
29
  "noExplicitAny": "off"
30
30
  },
31
31
  "complexity": {
32
- "noForEach": "info"
32
+ "noForEach": "off"
33
33
  },
34
34
  "correctness": {
35
35
  "useExhaustiveDependencies": "off"
36
36
  },
37
+ "a11y": {
38
+ "useKeyWithClickEvents": "off",
39
+ "noSvgWithoutTitle": "off"
40
+ },
37
41
  "style": {
38
42
  "noUselessElse": "off",
39
43
  "noNonNullAssertion": "off",
package/bun.lockb CHANGED
Binary file
package/dist/index.d.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ManualEditEvent } from '@tscircuit/props';
3
+ import { CircuitJson } from 'circuit-json';
2
4
 
3
5
  interface Props {
4
- circuitJson: Array<{
5
- type: string;
6
- }>;
6
+ circuitJson: CircuitJson;
7
7
  containerStyle?: React.CSSProperties;
8
+ editEvents?: ManualEditEvent[];
9
+ onEditEvent?: (event: ManualEditEvent) => void;
10
+ defaultEditMode?: boolean;
11
+ debugGrid?: boolean;
12
+ editingEnabled?: boolean;
8
13
  }
9
- declare const SchematicViewer: ({ circuitJson, containerStyle }: Props) => react_jsx_runtime.JSX.Element;
14
+ declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, }: Props) => react_jsx_runtime.JSX.Element;
10
15
 
11
16
  export { SchematicViewer };
package/dist/index.js CHANGED
@@ -1,17 +1,55 @@
1
1
  // lib/components/SchematicViewer.tsx
2
2
  import { useMouseMatrixTransform } from "use-mouse-matrix-transform";
3
3
  import { convertCircuitJsonToSchematicSvg } from "circuit-to-svg";
4
- import { useEffect, useMemo, useRef, useState } from "react";
5
- import { toString as transformToString } from "transformation-matrix";
6
- import { jsx } from "react/jsx-runtime";
7
- var SchematicViewer = ({ circuitJson, containerStyle }) => {
8
- const svgDivRef = useRef(null);
9
- const { ref: containerRef } = useMouseMatrixTransform({
10
- onSetTransform(transform) {
11
- if (!svgDivRef.current) return;
12
- svgDivRef.current.style.transform = transformToString(transform);
4
+ import { useMemo, useRef as useRef4, useState as useState3 } from "react";
5
+
6
+ // lib/components/EditIcon.tsx
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var EditIcon = ({
9
+ onClick,
10
+ active
11
+ }) => {
12
+ return /* @__PURE__ */ jsx(
13
+ "div",
14
+ {
15
+ onClick,
16
+ style: {
17
+ position: "absolute",
18
+ top: "16px",
19
+ right: "16px",
20
+ backgroundColor: active ? "#4CAF50" : "#fff",
21
+ color: active ? "#fff" : "#000",
22
+ padding: "8px",
23
+ borderRadius: "4px",
24
+ cursor: "pointer",
25
+ boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
26
+ display: "flex",
27
+ alignItems: "center",
28
+ gap: "4px",
29
+ zIndex: 1e3
30
+ },
31
+ children: /* @__PURE__ */ jsxs(
32
+ "svg",
33
+ {
34
+ width: "16",
35
+ height: "16",
36
+ viewBox: "0 0 24 24",
37
+ fill: "none",
38
+ stroke: "currentColor",
39
+ strokeWidth: "2",
40
+ children: [
41
+ /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
42
+ /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
43
+ ]
44
+ }
45
+ )
13
46
  }
14
- });
47
+ );
48
+ };
49
+
50
+ // lib/hooks/use-resize-handling.ts
51
+ import { useEffect, useState } from "react";
52
+ var useResizeHandling = (containerRef) => {
15
53
  const [containerWidth, setContainerWidth] = useState(0);
16
54
  const [containerHeight, setContainerHeight] = useState(0);
17
55
  useEffect(() => {
@@ -30,35 +68,427 @@ var SchematicViewer = ({ circuitJson, containerStyle }) => {
30
68
  window.removeEventListener("resize", updateDimensions);
31
69
  };
32
70
  }, []);
33
- const svg = useMemo(() => {
71
+ return { containerWidth, containerHeight };
72
+ };
73
+
74
+ // lib/hooks/useComponentDragging.ts
75
+ import { useCallback, useEffect as useEffect2, useRef, useState as useState2 } from "react";
76
+ import {
77
+ compose
78
+ } from "transformation-matrix";
79
+
80
+ // lib/utils/get-component-offset-due-to-events.ts
81
+ var getComponentOffsetDueToEvents = ({
82
+ editEvents,
83
+ schematic_component_id
84
+ }) => {
85
+ const editEventsForComponent = editEvents.filter(
86
+ (event) => "schematic_component_id" in event && event.schematic_component_id === schematic_component_id
87
+ ).filter(
88
+ (event) => "edit_event_type" in event && event.edit_event_type === "edit_schematic_component_location"
89
+ );
90
+ const totalOffsetX = editEventsForComponent.reduce((acc, event) => {
91
+ return acc + event.new_center.x - event.original_center.x;
92
+ }, 0);
93
+ const totalOffsetY = editEventsForComponent.reduce((acc, event) => {
94
+ return acc + event.new_center.y - event.original_center.y;
95
+ }, 0);
96
+ return {
97
+ x: totalOffsetX,
98
+ y: totalOffsetY
99
+ };
100
+ };
101
+
102
+ // lib/hooks/useComponentDragging.ts
103
+ import { su } from "@tscircuit/soup-util";
104
+ var useComponentDragging = ({
105
+ onEditEvent,
106
+ editEvents = [],
107
+ circuitJson,
108
+ cancelDrag,
109
+ svgToScreenProjection,
110
+ realToSvgProjection,
111
+ enabled = false
112
+ }) => {
113
+ const [activeEditEvent, setActiveEditEvent] = useState2(null);
114
+ const realToScreenProjection = compose(
115
+ realToSvgProjection,
116
+ svgToScreenProjection
117
+ );
118
+ const dragStartPosRef = useRef(null);
119
+ const activeEditEventRef = useRef(null);
120
+ const handleMouseDown = useCallback(
121
+ (e) => {
122
+ if (!enabled) return;
123
+ const target = e.target;
124
+ const componentGroup = target.closest(
125
+ '[data-circuit-json-type="schematic_component"]'
126
+ );
127
+ if (!componentGroup) return;
128
+ const schematic_component_id = componentGroup.getAttribute(
129
+ "data-schematic-component-id"
130
+ );
131
+ if (!schematic_component_id) return;
132
+ if (cancelDrag) cancelDrag();
133
+ const schematic_component = su(circuitJson).schematic_component.get(
134
+ schematic_component_id
135
+ );
136
+ if (!schematic_component) return;
137
+ const editEventOffset = getComponentOffsetDueToEvents({
138
+ editEvents,
139
+ schematic_component_id
140
+ });
141
+ dragStartPosRef.current = {
142
+ x: e.clientX,
143
+ y: e.clientY
144
+ };
145
+ const original_center = {
146
+ x: schematic_component.center.x + editEventOffset.x,
147
+ y: schematic_component.center.y + editEventOffset.y
148
+ };
149
+ const newEditEvent = {
150
+ edit_event_id: Math.random().toString(36).substr(2, 9),
151
+ edit_event_type: "edit_schematic_component_location",
152
+ schematic_component_id,
153
+ original_center,
154
+ new_center: { ...original_center },
155
+ in_progress: true,
156
+ created_at: Date.now(),
157
+ _element: componentGroup
158
+ };
159
+ activeEditEventRef.current = newEditEvent;
160
+ },
161
+ [cancelDrag, enabled]
162
+ );
163
+ const handleMouseMove = useCallback(
164
+ (e) => {
165
+ if (!activeEditEventRef.current || !dragStartPosRef.current) return;
166
+ const screenDelta = {
167
+ x: e.clientX - dragStartPosRef.current.x,
168
+ y: e.clientY - dragStartPosRef.current.y
169
+ };
170
+ const mmDelta = {
171
+ x: screenDelta.x / realToScreenProjection.a,
172
+ y: screenDelta.y / realToScreenProjection.d
173
+ };
174
+ const newEditEvent = {
175
+ ...activeEditEventRef.current,
176
+ new_center: {
177
+ x: activeEditEventRef.current.original_center.x + mmDelta.x,
178
+ y: activeEditEventRef.current.original_center.y + mmDelta.y
179
+ }
180
+ };
181
+ activeEditEventRef.current = newEditEvent;
182
+ setActiveEditEvent(newEditEvent);
183
+ },
184
+ [realToScreenProjection]
185
+ );
186
+ const handleMouseUp = useCallback(() => {
187
+ if (!activeEditEventRef.current) return;
188
+ const finalEvent = {
189
+ ...activeEditEventRef.current,
190
+ in_progress: false
191
+ };
192
+ if (onEditEvent) onEditEvent(finalEvent);
193
+ activeEditEventRef.current = null;
194
+ dragStartPosRef.current = null;
195
+ setActiveEditEvent(null);
196
+ }, [onEditEvent]);
197
+ useEffect2(() => {
198
+ window.addEventListener("mousemove", handleMouseMove);
199
+ window.addEventListener("mouseup", handleMouseUp);
200
+ return () => {
201
+ window.removeEventListener("mousemove", handleMouseMove);
202
+ window.removeEventListener("mouseup", handleMouseUp);
203
+ };
204
+ }, [handleMouseMove, handleMouseUp]);
205
+ return {
206
+ handleMouseDown,
207
+ isDragging: !!activeEditEventRef.current,
208
+ activeEditEvent
209
+ };
210
+ };
211
+
212
+ // lib/components/SchematicViewer.tsx
213
+ import {
214
+ identity,
215
+ fromString,
216
+ toString as transformToString
217
+ } from "transformation-matrix";
218
+
219
+ // lib/hooks/useChangeSchematicComponentLocationsInSvg.ts
220
+ import "@tscircuit/soup-util";
221
+ import "transformation-matrix";
222
+ import { useEffect as useEffect3, useRef as useRef2 } from "react";
223
+ var useChangeSchematicComponentLocationsInSvg = ({
224
+ svgDivRef,
225
+ realToSvgProjection,
226
+ svgToScreenProjection,
227
+ activeEditEvent,
228
+ editEvents
229
+ }) => {
230
+ const lastSvgContentRef = useRef2(null);
231
+ useEffect3(() => {
232
+ const svg = svgDivRef.current;
233
+ if (!svg) return;
234
+ const observer = new MutationObserver((mutations) => {
235
+ const currentSvgContent = svg.innerHTML;
236
+ if (currentSvgContent !== lastSvgContentRef.current) {
237
+ lastSvgContentRef.current = currentSvgContent;
238
+ applyTransforms();
239
+ }
240
+ });
241
+ const applyTransforms = () => {
242
+ const componentsThatHaveBeenMoved = /* @__PURE__ */ new Set();
243
+ for (const event of editEvents) {
244
+ if ("edit_event_type" in event && event.edit_event_type === "edit_schematic_component_location") {
245
+ componentsThatHaveBeenMoved.add(event.schematic_component_id);
246
+ }
247
+ }
248
+ if (activeEditEvent) {
249
+ componentsThatHaveBeenMoved.add(activeEditEvent.schematic_component_id);
250
+ }
251
+ const allComponents = svg.querySelectorAll(
252
+ '[data-circuit-json-type="schematic_component"]'
253
+ );
254
+ for (const component of Array.from(allComponents)) {
255
+ const schematic_component_id = component.getAttribute(
256
+ "data-schematic-component-id"
257
+ );
258
+ const offsetMm = getComponentOffsetDueToEvents({
259
+ editEvents: [
260
+ ...editEvents,
261
+ ...activeEditEvent ? [activeEditEvent] : []
262
+ ],
263
+ schematic_component_id
264
+ });
265
+ const offsetPx = {
266
+ x: offsetMm.x * realToSvgProjection.a,
267
+ y: offsetMm.y * realToSvgProjection.d
268
+ };
269
+ const style = component.style;
270
+ style.transform = `translate(${offsetPx.x}px, ${offsetPx.y}px)`;
271
+ if (activeEditEvent?.schematic_component_id === schematic_component_id) {
272
+ style.outline = "solid 2px rgba(255,0,0,0.5)";
273
+ style.outlineOffset = "5px";
274
+ } else if (style.outline) {
275
+ style.outline = "";
276
+ }
277
+ }
278
+ };
279
+ observer.observe(svg, {
280
+ childList: true,
281
+ // Watch for changes to the child elements
282
+ subtree: false,
283
+ // Watch for changes in the entire subtree
284
+ characterData: false
285
+ // Watch for changes to text content
286
+ });
287
+ applyTransforms();
288
+ return () => {
289
+ observer.disconnect();
290
+ };
291
+ }, [svgDivRef, editEvents, activeEditEvent]);
292
+ };
293
+
294
+ // lib/hooks/useChangeSchematicTracesForMovedComponents.ts
295
+ import { useEffect as useEffect4, useRef as useRef3 } from "react";
296
+ import { su as su3 } from "@tscircuit/soup-util";
297
+ var useChangeSchematicTracesForMovedComponents = ({
298
+ svgDivRef,
299
+ circuitJson,
300
+ activeEditEvent,
301
+ editEvents
302
+ }) => {
303
+ const lastSvgContentRef = useRef3(null);
304
+ useEffect4(() => {
305
+ const svg = svgDivRef.current;
306
+ if (!svg) return;
307
+ const updateTraceStyles = () => {
308
+ const allTraces = svg.querySelectorAll(
309
+ '[data-circuit-json-type="schematic_trace"] path'
310
+ );
311
+ for (const trace of Array.from(allTraces)) {
312
+ trace.setAttribute("stroke-dasharray", "0");
313
+ trace.style.animation = "";
314
+ }
315
+ for (const editEvent of [
316
+ ...editEvents,
317
+ ...activeEditEvent ? [activeEditEvent] : []
318
+ ]) {
319
+ if ("schematic_component_id" in editEvent && editEvent.edit_event_type === "edit_schematic_component_location") {
320
+ const sch_component = su3(circuitJson).schematic_component.get(
321
+ editEvent.schematic_component_id
322
+ );
323
+ if (!sch_component) return;
324
+ const src_ports = su3(circuitJson).source_port.list({
325
+ source_component_id: sch_component.source_component_id
326
+ });
327
+ const src_port_ids = new Set(src_ports.map((sp) => sp.source_port_id));
328
+ const src_traces = su3(circuitJson).source_trace.list().filter(
329
+ (st) => st.connected_source_port_ids?.some(
330
+ (spi) => src_port_ids.has(spi)
331
+ )
332
+ );
333
+ const src_trace_ids = new Set(
334
+ src_traces.map((st) => st.source_trace_id)
335
+ );
336
+ const schematic_traces = su3(circuitJson).schematic_trace.list().filter((st) => src_trace_ids.has(st.source_trace_id));
337
+ schematic_traces.forEach((trace) => {
338
+ const traceElements = svg.querySelectorAll(
339
+ `[data-schematic-trace-id="${trace.schematic_trace_id}"] path`
340
+ );
341
+ for (const traceElement of Array.from(traceElements)) {
342
+ if (traceElement.getAttribute("class")?.includes("invisible"))
343
+ continue;
344
+ traceElement.setAttribute("stroke-dasharray", "20,20");
345
+ traceElement.style.animation = "dash-animation 350ms linear infinite, pulse-animation 900ms linear infinite";
346
+ if (!svg.querySelector("style#dash-animation")) {
347
+ const style = document.createElement("style");
348
+ style.id = "dash-animation";
349
+ style.textContent = `
350
+ @keyframes dash-animation {
351
+ to {
352
+ stroke-dashoffset: -40;
353
+ }
354
+ }
355
+ @keyframes pulse-animation {
356
+ 0% { opacity: 0.6; }
357
+ 50% { opacity: 0.2; }
358
+ 100% { opacity: 0.6; }
359
+ }
360
+ `;
361
+ svg.appendChild(style);
362
+ }
363
+ }
364
+ });
365
+ }
366
+ }
367
+ };
368
+ updateTraceStyles();
369
+ const observer = new MutationObserver(updateTraceStyles);
370
+ observer.observe(svg, {
371
+ childList: true,
372
+ // Watch for changes to the child elements
373
+ subtree: false,
374
+ // Watch for changes in the entire subtree
375
+ characterData: false
376
+ // Watch for changes to text content
377
+ });
378
+ return () => {
379
+ observer.disconnect();
380
+ };
381
+ }, [svgDivRef, activeEditEvent, circuitJson, editEvents]);
382
+ };
383
+
384
+ // lib/components/SchematicViewer.tsx
385
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
386
+ var SchematicViewer = ({
387
+ circuitJson,
388
+ containerStyle,
389
+ editEvents = [],
390
+ onEditEvent,
391
+ defaultEditMode = false,
392
+ debugGrid = false,
393
+ editingEnabled = false
394
+ }) => {
395
+ const [editModeEnabled, setEditModeEnabled] = useState3(defaultEditMode);
396
+ const svgDivRef = useRef4(null);
397
+ const {
398
+ ref: containerRef,
399
+ cancelDrag,
400
+ transform: svgToScreenProjection
401
+ } = useMouseMatrixTransform({
402
+ onSetTransform(transform) {
403
+ if (!svgDivRef.current) return;
404
+ svgDivRef.current.style.transform = transformToString(transform);
405
+ }
406
+ });
407
+ const { containerWidth, containerHeight } = useResizeHandling(containerRef);
408
+ const svgString = useMemo(() => {
34
409
  if (!containerWidth || !containerHeight) return "";
35
410
  return convertCircuitJsonToSchematicSvg(circuitJson, {
36
411
  width: containerWidth,
37
- height: containerHeight || 720
412
+ height: containerHeight || 720,
413
+ grid: !debugGrid ? void 0 : {
414
+ cellSize: 1,
415
+ labelCells: true
416
+ }
38
417
  });
39
418
  }, [circuitJson, containerWidth, containerHeight]);
40
- return /* @__PURE__ */ jsx(
419
+ const realToSvgProjection = useMemo(() => {
420
+ if (!svgString) return identity();
421
+ const transformString = svgString.match(
422
+ /data-real-to-screen-transform="([^"]+)"/
423
+ )?.[1];
424
+ try {
425
+ return fromString(transformString);
426
+ } catch (e) {
427
+ console.error(e);
428
+ return identity();
429
+ }
430
+ }, [svgString]);
431
+ const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
432
+ {
433
+ onEditEvent,
434
+ cancelDrag,
435
+ realToSvgProjection,
436
+ svgToScreenProjection,
437
+ circuitJson,
438
+ editEvents,
439
+ enabled: editModeEnabled
440
+ }
441
+ );
442
+ useChangeSchematicComponentLocationsInSvg({
443
+ svgDivRef,
444
+ editEvents,
445
+ realToSvgProjection,
446
+ svgToScreenProjection,
447
+ activeEditEvent
448
+ });
449
+ useChangeSchematicTracesForMovedComponents({
450
+ svgDivRef,
451
+ circuitJson,
452
+ activeEditEvent,
453
+ editEvents
454
+ });
455
+ const svgDiv = useMemo(
456
+ () => /* @__PURE__ */ jsx2(
457
+ "div",
458
+ {
459
+ ref: svgDivRef,
460
+ style: {
461
+ pointerEvents: "auto",
462
+ transformOrigin: "0 0"
463
+ },
464
+ dangerouslySetInnerHTML: { __html: svgString }
465
+ }
466
+ ),
467
+ [svgString]
468
+ );
469
+ return /* @__PURE__ */ jsxs2(
41
470
  "div",
42
471
  {
43
472
  ref: containerRef,
44
473
  style: {
474
+ position: "relative",
45
475
  backgroundColor: "#F5F1ED",
46
476
  overflow: "hidden",
47
- cursor: "grab",
477
+ cursor: isDragging ? "grabbing" : "grab",
48
478
  minHeight: "300px",
49
479
  ...containerStyle
50
480
  },
51
- children: /* @__PURE__ */ jsx(
52
- "div",
53
- {
54
- ref: svgDivRef,
55
- style: {
56
- pointerEvents: "auto",
57
- transformOrigin: "0 0"
58
- },
59
- dangerouslySetInnerHTML: { __html: svg }
60
- }
61
- )
481
+ onMouseDown: handleMouseDown,
482
+ children: [
483
+ editingEnabled && /* @__PURE__ */ jsx2(
484
+ EditIcon,
485
+ {
486
+ active: editModeEnabled,
487
+ onClick: () => setEditModeEnabled(!editModeEnabled)
488
+ }
489
+ ),
490
+ svgDiv
491
+ ]
62
492
  }
63
493
  );
64
494
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/components/SchematicViewer.tsx"],"sourcesContent":["import { useMouseMatrixTransform } from \"use-mouse-matrix-transform\"\nimport { convertCircuitJsonToSchematicSvg } from \"circuit-to-svg\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\nimport { toString as transformToString } from \"transformation-matrix\"\n\ninterface Props {\n circuitJson: Array<{ type: string }>\n containerStyle?: React.CSSProperties\n}\n\nexport const SchematicViewer = ({ circuitJson, containerStyle }: Props) => {\n const svgDivRef = useRef<HTMLDivElement>(null)\n const { ref: containerRef } = useMouseMatrixTransform({\n onSetTransform(transform) {\n if (!svgDivRef.current) return\n svgDivRef.current.style.transform = transformToString(transform)\n },\n })\n const [containerWidth, setContainerWidth] = useState(0)\n const [containerHeight, setContainerHeight] = useState(0)\n\n useEffect(() => {\n if (!containerRef.current) return\n\n const updateDimensions = () => {\n const rect = containerRef.current?.getBoundingClientRect()\n\n setContainerWidth(rect?.width || 0)\n setContainerHeight(rect?.height || 0)\n }\n\n // Set initial dimensions\n updateDimensions()\n\n // Add resize listener\n const resizeObserver = new ResizeObserver(updateDimensions)\n resizeObserver.observe(containerRef.current)\n\n // Fallback to window resize\n window.addEventListener(\"resize\", updateDimensions)\n\n return () => {\n resizeObserver.disconnect()\n window.removeEventListener(\"resize\", updateDimensions)\n }\n }, [])\n\n const svg = useMemo(() => {\n if (!containerWidth || !containerHeight) return \"\"\n\n return convertCircuitJsonToSchematicSvg(circuitJson as any, {\n width: containerWidth,\n height: containerHeight || 720,\n })\n }, [circuitJson, containerWidth, containerHeight])\n\n return (\n <div\n ref={containerRef}\n style={{\n backgroundColor: \"#F5F1ED\",\n overflow: \"hidden\",\n cursor: \"grab\",\n minHeight: \"300px\",\n ...containerStyle,\n }}\n >\n <div\n ref={svgDivRef}\n style={{\n pointerEvents: \"auto\",\n transformOrigin: \"0 0\",\n }}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n </div>\n )\n}\n"],"mappings":";AAAA,SAAS,+BAA+B;AACxC,SAAS,wCAAwC;AACjD,SAAS,WAAW,SAAS,QAAQ,gBAAgB;AACrD,SAAS,YAAY,yBAAyB;AAgExC;AAzDC,IAAM,kBAAkB,CAAC,EAAE,aAAa,eAAe,MAAa;AACzE,QAAM,YAAY,OAAuB,IAAI;AAC7C,QAAM,EAAE,KAAK,aAAa,IAAI,wBAAwB;AAAA,IACpD,eAAe,WAAW;AACxB,UAAI,CAAC,UAAU,QAAS;AACxB,gBAAU,QAAQ,MAAM,YAAY,kBAAkB,SAAS;AAAA,IACjE;AAAA,EACF,CAAC;AACD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,CAAC;AACtD,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAS,CAAC;AAExD,YAAU,MAAM;AACd,QAAI,CAAC,aAAa,QAAS;AAE3B,UAAM,mBAAmB,MAAM;AAC7B,YAAM,OAAO,aAAa,SAAS,sBAAsB;AAEzD,wBAAkB,MAAM,SAAS,CAAC;AAClC,yBAAmB,MAAM,UAAU,CAAC;AAAA,IACtC;AAGA,qBAAiB;AAGjB,UAAM,iBAAiB,IAAI,eAAe,gBAAgB;AAC1D,mBAAe,QAAQ,aAAa,OAAO;AAG3C,WAAO,iBAAiB,UAAU,gBAAgB;AAElD,WAAO,MAAM;AACX,qBAAe,WAAW;AAC1B,aAAO,oBAAoB,UAAU,gBAAgB;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,MAAM,QAAQ,MAAM;AACxB,QAAI,CAAC,kBAAkB,CAAC,gBAAiB,QAAO;AAEhD,WAAO,iCAAiC,aAAoB;AAAA,MAC1D,OAAO;AAAA,MACP,QAAQ,mBAAmB;AAAA,IAC7B,CAAC;AAAA,EACH,GAAG,CAAC,aAAa,gBAAgB,eAAe,CAAC;AAEjD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,QACL,iBAAiB;AAAA,QACjB,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,GAAG;AAAA,MACL;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,OAAO;AAAA,YACL,eAAe;AAAA,YACf,iBAAiB;AAAA,UACnB;AAAA,UAEA,yBAAyB,EAAE,QAAQ,IAAI;AAAA;AAAA,MACzC;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../lib/components/SchematicViewer.tsx","../lib/components/EditIcon.tsx","../lib/hooks/use-resize-handling.ts","../lib/hooks/useComponentDragging.ts","../lib/utils/get-component-offset-due-to-events.ts","../lib/hooks/useChangeSchematicComponentLocationsInSvg.ts","../lib/hooks/useChangeSchematicTracesForMovedComponents.ts"],"sourcesContent":["import { useMouseMatrixTransform } from \"use-mouse-matrix-transform\"\nimport { convertCircuitJsonToSchematicSvg } from \"circuit-to-svg\"\nimport { useMemo, useRef, useState } from \"react\"\nimport { EditIcon } from \"./EditIcon\"\nimport { useResizeHandling } from \"../hooks/use-resize-handling\"\nimport { useComponentDragging } from \"../hooks/useComponentDragging\"\nimport type { ManualEditEvent } from \"../types/edit-events\"\nimport {\n identity,\n fromString,\n toString as transformToString,\n} from \"transformation-matrix\"\nimport { useChangeSchematicComponentLocationsInSvg } from \"lib/hooks/useChangeSchematicComponentLocationsInSvg\"\nimport { useChangeSchematicTracesForMovedComponents } from \"lib/hooks/useChangeSchematicTracesForMovedComponents\"\nimport type { CircuitJson } from \"circuit-json\"\n\ninterface Props {\n circuitJson: CircuitJson\n containerStyle?: React.CSSProperties\n editEvents?: ManualEditEvent[]\n onEditEvent?: (event: ManualEditEvent) => void\n defaultEditMode?: boolean\n debugGrid?: boolean\n editingEnabled?: boolean\n}\n\nexport const SchematicViewer = ({\n circuitJson,\n containerStyle,\n editEvents = [],\n onEditEvent,\n defaultEditMode = false,\n debugGrid = false,\n editingEnabled = false,\n}: Props) => {\n const [editModeEnabled, setEditModeEnabled] = useState(defaultEditMode)\n const svgDivRef = useRef<HTMLDivElement>(null)\n\n const {\n ref: containerRef,\n cancelDrag,\n transform: svgToScreenProjection,\n } = useMouseMatrixTransform({\n onSetTransform(transform) {\n if (!svgDivRef.current) return\n svgDivRef.current.style.transform = transformToString(transform)\n },\n })\n\n const { containerWidth, containerHeight } = useResizeHandling(containerRef)\n const svgString = useMemo(() => {\n if (!containerWidth || !containerHeight) return \"\"\n\n return convertCircuitJsonToSchematicSvg(circuitJson as any, {\n width: containerWidth,\n height: containerHeight || 720,\n grid: !debugGrid\n ? undefined\n : {\n cellSize: 1,\n labelCells: true,\n },\n })\n }, [circuitJson, containerWidth, containerHeight])\n\n const realToSvgProjection = useMemo(() => {\n if (!svgString) return identity()\n const transformString = svgString.match(\n /data-real-to-screen-transform=\"([^\"]+)\"/,\n )?.[1]!\n\n try {\n return fromString(transformString)\n } catch (e) {\n console.error(e)\n return identity()\n }\n }, [svgString])\n\n const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(\n {\n onEditEvent,\n cancelDrag,\n realToSvgProjection,\n svgToScreenProjection,\n circuitJson,\n editEvents,\n enabled: editModeEnabled,\n },\n )\n\n useChangeSchematicComponentLocationsInSvg({\n svgDivRef,\n editEvents,\n realToSvgProjection,\n svgToScreenProjection,\n activeEditEvent,\n })\n\n useChangeSchematicTracesForMovedComponents({\n svgDivRef,\n circuitJson,\n activeEditEvent,\n editEvents,\n })\n\n const svgDiv = useMemo(\n () => (\n <div\n ref={svgDivRef}\n style={{\n pointerEvents: \"auto\",\n transformOrigin: \"0 0\",\n }}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>\n dangerouslySetInnerHTML={{ __html: svgString }}\n />\n ),\n [svgString],\n )\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"relative\",\n backgroundColor: \"#F5F1ED\",\n overflow: \"hidden\",\n cursor: isDragging ? \"grabbing\" : \"grab\",\n minHeight: \"300px\",\n ...containerStyle,\n }}\n onMouseDown={handleMouseDown}\n >\n {editingEnabled && (\n <EditIcon\n active={editModeEnabled}\n onClick={() => setEditModeEnabled(!editModeEnabled)}\n />\n )}\n {svgDiv}\n </div>\n )\n}\n","export const EditIcon = ({\n onClick,\n active,\n}: { onClick: () => void; active: boolean }) => {\n return (\n <div\n onClick={onClick}\n style={{\n position: \"absolute\",\n top: \"16px\",\n right: \"16px\",\n backgroundColor: active ? \"#4CAF50\" : \"#fff\",\n color: active ? \"#fff\" : \"#000\",\n padding: \"8px\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n boxShadow: \"0 2px 4px rgba(0,0,0,0.1)\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"4px\",\n zIndex: 1000,\n }}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\n </svg>\n </div>\n )\n}\n","import { useEffect, useState } from \"react\"\n\nexport const useResizeHandling = (\n containerRef: React.RefObject<HTMLElement>,\n) => {\n const [containerWidth, setContainerWidth] = useState(0)\n const [containerHeight, setContainerHeight] = useState(0)\n\n useEffect(() => {\n if (!containerRef.current) return\n\n const updateDimensions = () => {\n const rect = containerRef.current?.getBoundingClientRect()\n setContainerWidth(rect?.width || 0)\n setContainerHeight(rect?.height || 0)\n }\n\n // Set initial dimensions\n updateDimensions()\n\n // Add resize listener\n const resizeObserver = new ResizeObserver(updateDimensions)\n resizeObserver.observe(containerRef.current)\n\n // Fallback to window resize\n window.addEventListener(\"resize\", updateDimensions)\n\n return () => {\n resizeObserver.disconnect()\n window.removeEventListener(\"resize\", updateDimensions)\n }\n }, [])\n\n return { containerWidth, containerHeight }\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\"\nimport type {\n EditSchematicComponentLocationEventWithElement,\n ManualEditEvent,\n} from \"../types/edit-events\"\nimport {\n type Matrix,\n applyToPoint,\n inverse,\n compose,\n} from \"transformation-matrix\"\nimport { getComponentOffsetDueToEvents } from \"lib/utils/get-component-offset-due-to-events\"\nimport type { CircuitJson } from \"circuit-json\"\nimport { su } from \"@tscircuit/soup-util\"\n\nexport const useComponentDragging = ({\n onEditEvent,\n editEvents = [],\n circuitJson,\n cancelDrag,\n svgToScreenProjection,\n realToSvgProjection,\n enabled = false,\n}: {\n circuitJson: any[]\n editEvents: ManualEditEvent[]\n /** The projection returned from use-mouse-matrix-transform, indicating zoom on svg */\n svgToScreenProjection: Matrix\n /** The projection returned from circuit-to-svg, mm to svg */\n realToSvgProjection: Matrix\n onEditEvent?: (event: ManualEditEvent) => void\n cancelDrag?: () => void\n enabled?: boolean\n}): {\n handleMouseDown: (e: React.MouseEvent) => void\n isDragging: boolean\n activeEditEvent: EditSchematicComponentLocationEventWithElement | null\n} => {\n const [activeEditEvent, setActiveEditEvent] =\n useState<EditSchematicComponentLocationEventWithElement | null>(null)\n const realToScreenProjection = compose(\n realToSvgProjection,\n svgToScreenProjection,\n )\n\n /**\n * Drag start position in screen space\n */\n const dragStartPosRef = useRef<{\n x: number\n y: number\n } | null>(null)\n\n const activeEditEventRef =\n useRef<EditSchematicComponentLocationEventWithElement | null>(null)\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled) return\n\n const target = e.target as SVGElement\n const componentGroup = target.closest(\n '[data-circuit-json-type=\"schematic_component\"]',\n )\n if (!componentGroup) return\n\n const schematic_component_id = componentGroup.getAttribute(\n \"data-schematic-component-id\",\n )\n if (!schematic_component_id) return\n\n if (cancelDrag) cancelDrag()\n\n const schematic_component = su(circuitJson).schematic_component.get(\n schematic_component_id,\n )\n if (!schematic_component) return\n const editEventOffset = getComponentOffsetDueToEvents({\n editEvents,\n schematic_component_id: schematic_component_id,\n })\n\n dragStartPosRef.current = {\n x: e.clientX,\n y: e.clientY,\n }\n\n const original_center = {\n x: schematic_component.center.x + editEventOffset.x,\n y: schematic_component.center.y + editEventOffset.y,\n }\n\n const newEditEvent: EditSchematicComponentLocationEventWithElement = {\n edit_event_id: Math.random().toString(36).substr(2, 9),\n edit_event_type: \"edit_schematic_component_location\",\n schematic_component_id: schematic_component_id,\n original_center,\n new_center: { ...original_center },\n in_progress: true,\n created_at: Date.now(),\n _element: componentGroup as any,\n }\n\n activeEditEventRef.current = newEditEvent\n },\n [cancelDrag, enabled],\n )\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n if (!activeEditEventRef.current || !dragStartPosRef.current) return\n\n const screenDelta = {\n x: e.clientX - dragStartPosRef.current.x,\n y: e.clientY - dragStartPosRef.current.y,\n }\n\n const mmDelta = {\n x: screenDelta.x / realToScreenProjection.a,\n y: screenDelta.y / realToScreenProjection.d,\n }\n\n const newEditEvent = {\n ...activeEditEventRef.current,\n new_center: {\n x: activeEditEventRef.current.original_center.x + mmDelta.x,\n y: activeEditEventRef.current.original_center.y + mmDelta.y,\n },\n }\n\n activeEditEventRef.current = newEditEvent\n setActiveEditEvent(newEditEvent)\n },\n [realToScreenProjection],\n )\n\n const handleMouseUp = useCallback(() => {\n if (!activeEditEventRef.current) return\n const finalEvent = {\n ...activeEditEventRef.current,\n in_progress: false,\n }\n if (onEditEvent) onEditEvent(finalEvent)\n activeEditEventRef.current = null\n dragStartPosRef.current = null\n setActiveEditEvent(null)\n }, [onEditEvent])\n\n useEffect(() => {\n window.addEventListener(\"mousemove\", handleMouseMove)\n window.addEventListener(\"mouseup\", handleMouseUp)\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove)\n window.removeEventListener(\"mouseup\", handleMouseUp)\n }\n }, [handleMouseMove, handleMouseUp])\n\n return {\n handleMouseDown,\n isDragging: !!activeEditEventRef.current,\n activeEditEvent: activeEditEvent,\n }\n}\n","import type {\n EditSchematicComponentLocationEvent,\n EditSchematicComponentLocationEventWithElement,\n ManualEditEvent,\n} from \"lib/types/edit-events\"\n\n/**\n * Returns the total offset of a component due to a set of edit events in\n * mm\n */\nexport const getComponentOffsetDueToEvents = ({\n editEvents,\n schematic_component_id,\n}: {\n editEvents: ManualEditEvent[]\n schematic_component_id: string\n}) => {\n const editEventsForComponent: EditSchematicComponentLocationEvent[] =\n editEvents\n .filter(\n (event) =>\n \"schematic_component_id\" in event &&\n event.schematic_component_id === schematic_component_id,\n )\n .filter(\n (event) =>\n \"edit_event_type\" in event &&\n event.edit_event_type === \"edit_schematic_component_location\",\n )\n\n const totalOffsetX = editEventsForComponent.reduce((acc, event) => {\n return acc + event.new_center.x - event.original_center.x\n }, 0)\n\n const totalOffsetY = editEventsForComponent.reduce((acc, event) => {\n return acc + event.new_center.y - event.original_center.y\n }, 0)\n\n return {\n x: totalOffsetX,\n y: totalOffsetY,\n }\n}\n","import { su } from \"@tscircuit/soup-util\"\nimport type {\n ManualEditEvent,\n EditSchematicComponentLocationEventWithElement,\n} from \"lib/types/edit-events\"\nimport { type Matrix, compose, applyToPoint } from \"transformation-matrix\"\nimport { useEffect, useRef } from \"react\"\nimport { getComponentOffsetDueToEvents } from \"lib/utils/get-component-offset-due-to-events\"\nimport type { CircuitJson } from \"circuit-json\"\n\n/**\n * This hook automatically applies the edit events to the schematic components\n * inside the svg div.\n *\n * Schematic components are \"<g>\" elements with a \"data-circuit-json-type\"\n * attribute equal to \"schematic_component\", these elements also have a\n * data-schematic-component-id attribute equal to the schematic_component_id\n */\nexport const useChangeSchematicComponentLocationsInSvg = ({\n svgDivRef,\n realToSvgProjection,\n svgToScreenProjection,\n activeEditEvent,\n editEvents,\n}: {\n svgDivRef: React.RefObject<HTMLDivElement | null>\n realToSvgProjection: Matrix\n svgToScreenProjection: Matrix\n activeEditEvent: EditSchematicComponentLocationEventWithElement | null\n editEvents: ManualEditEvent[]\n}) => {\n // Keep track of the last known SVG content\n const lastSvgContentRef = useRef<string | null>(null)\n\n useEffect(() => {\n const svg = svgDivRef.current\n if (!svg) return\n\n // Create a MutationObserver to watch for changes in the div's content\n const observer = new MutationObserver((mutations) => {\n // Check if the SVG content has changed\n const currentSvgContent = svg.innerHTML\n if (currentSvgContent !== lastSvgContentRef.current) {\n lastSvgContentRef.current = currentSvgContent\n\n // Apply the transforms\n applyTransforms()\n }\n })\n\n // Function to apply transforms to components\n const applyTransforms = () => {\n const componentsThatHaveBeenMoved = new Set<string>()\n for (const event of editEvents) {\n if (\n \"edit_event_type\" in event &&\n event.edit_event_type === \"edit_schematic_component_location\"\n ) {\n componentsThatHaveBeenMoved.add(event.schematic_component_id)\n }\n }\n if (activeEditEvent) {\n componentsThatHaveBeenMoved.add(activeEditEvent.schematic_component_id)\n }\n\n // Reset all transforms\n const allComponents = svg.querySelectorAll(\n '[data-circuit-json-type=\"schematic_component\"]',\n )\n\n for (const component of Array.from(allComponents)) {\n const schematic_component_id = component.getAttribute(\n \"data-schematic-component-id\",\n )!\n\n const offsetMm = getComponentOffsetDueToEvents({\n editEvents: [\n ...editEvents,\n ...(activeEditEvent ? [activeEditEvent] : []),\n ],\n schematic_component_id,\n })\n\n const offsetPx = {\n x: offsetMm.x * realToSvgProjection.a,\n y: offsetMm.y * realToSvgProjection.d,\n }\n\n const style: any = (component as any).style\n style.transform = `translate(${offsetPx.x}px, ${offsetPx.y}px)`\n if (\n activeEditEvent?.schematic_component_id === schematic_component_id\n ) {\n style.outline = \"solid 2px rgba(255,0,0,0.5)\"\n style.outlineOffset = \"5px\"\n } else if (style.outline) {\n style.outline = \"\"\n }\n }\n }\n\n // Start observing the div for changes\n observer.observe(svg, {\n childList: true, // Watch for changes to the child elements\n subtree: false, // Watch for changes in the entire subtree\n characterData: false, // Watch for changes to text content\n })\n\n // Apply transforms immediately on mount or when editEvents change\n applyTransforms()\n\n // Cleanup function\n return () => {\n observer.disconnect()\n }\n }, [svgDivRef, editEvents, activeEditEvent]) // Dependencies remain the same\n}\n","import { useEffect, useRef } from \"react\"\nimport { su } from \"@tscircuit/soup-util\"\nimport type { ManualEditEvent } from \"../types/edit-events\"\nimport type { CircuitJson } from \"circuit-json\"\n\n/**\n * This hook makes traces dashed when their connected components are being moved\n */\nexport const useChangeSchematicTracesForMovedComponents = ({\n svgDivRef,\n circuitJson,\n activeEditEvent,\n editEvents,\n}: {\n svgDivRef: React.RefObject<HTMLDivElement | null>\n circuitJson: CircuitJson\n activeEditEvent: ManualEditEvent | null\n editEvents: ManualEditEvent[]\n}) => {\n // Keep track of the last known SVG content\n const lastSvgContentRef = useRef<string | null>(null)\n\n useEffect(() => {\n const svg = svgDivRef.current\n if (!svg) return\n\n const updateTraceStyles = () => {\n // Reset all traces to solid\n const allTraces = svg.querySelectorAll(\n '[data-circuit-json-type=\"schematic_trace\"] path',\n )\n\n // Reset all traces to solid\n for (const trace of Array.from(allTraces)) {\n trace.setAttribute(\"stroke-dasharray\", \"0\")\n ;(trace as any).style.animation = \"\"\n }\n\n // If there's an active edit event, make connected traces dashed\n for (const editEvent of [\n ...editEvents,\n ...(activeEditEvent ? [activeEditEvent] : []),\n ]) {\n if (\n \"schematic_component_id\" in editEvent &&\n editEvent.edit_event_type === \"edit_schematic_component_location\"\n ) {\n const sch_component = su(circuitJson).schematic_component.get(\n editEvent.schematic_component_id,\n )\n if (!sch_component) return\n\n const src_ports = su(circuitJson).source_port.list({\n source_component_id: sch_component.source_component_id,\n })\n const src_port_ids = new Set(src_ports.map((sp) => sp.source_port_id))\n const src_traces = su(circuitJson)\n .source_trace.list()\n .filter((st) =>\n st.connected_source_port_ids?.some((spi) =>\n src_port_ids.has(spi),\n ),\n )\n const src_trace_ids = new Set(\n src_traces.map((st) => st.source_trace_id),\n )\n const schematic_traces = su(circuitJson)\n .schematic_trace.list()\n .filter((st) => src_trace_ids.has(st.source_trace_id))\n\n // Make the connected traces dashed\n schematic_traces.forEach((trace) => {\n const traceElements = svg.querySelectorAll(\n `[data-schematic-trace-id=\"${trace.schematic_trace_id}\"] path`,\n )\n for (const traceElement of Array.from(traceElements)) {\n if (traceElement.getAttribute(\"class\")?.includes(\"invisible\"))\n continue\n traceElement.setAttribute(\"stroke-dasharray\", \"20,20\")\n ;(traceElement as any).style.animation =\n \"dash-animation 350ms linear infinite, pulse-animation 900ms linear infinite\"\n\n if (!svg.querySelector(\"style#dash-animation\")) {\n const style = document.createElement(\"style\")\n style.id = \"dash-animation\"\n style.textContent = `\n @keyframes dash-animation {\n to {\n stroke-dashoffset: -40;\n }\n }\n @keyframes pulse-animation {\n 0% { opacity: 0.6; }\n 50% { opacity: 0.2; }\n 100% { opacity: 0.6; }\n }\n `\n svg.appendChild(style)\n }\n }\n })\n }\n }\n }\n\n // Apply styles immediately\n updateTraceStyles()\n\n // Cleanup function\n const observer = new MutationObserver(updateTraceStyles)\n observer.observe(svg, {\n childList: true, // Watch for changes to the child elements\n subtree: false, // Watch for changes in the entire subtree\n characterData: false, // Watch for changes to text content\n })\n\n return () => {\n observer.disconnect()\n }\n }, [svgDivRef, activeEditEvent, circuitJson, editEvents])\n}\n"],"mappings":"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","names":["useRef","useState","useEffect","useState","useState","useEffect","useEffect","useRef","useRef","useEffect","useEffect","useRef","su","jsx","jsxs","useState","useRef"]}