@tscircuit/schematic-viewer 2.0.14 → 2.0.15

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/bun.lockb CHANGED
Binary file
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ManualEditEvent } from '@tscircuit/props';
3
+ import { CircuitJson } from 'circuit-json';
3
4
 
4
5
  interface Props {
5
- circuitJson: any[];
6
+ circuitJson: CircuitJson;
6
7
  containerStyle?: React.CSSProperties;
7
8
  editEvents?: ManualEditEvent[];
8
9
  onEditEvent?: (event: ManualEditEvent) => void;
@@ -12,6 +13,6 @@ interface Props {
12
13
  debug?: boolean;
13
14
  clickToInteractEnabled?: boolean;
14
15
  }
15
- declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, debug, clickToInteractEnabled, }: Props) => react_jsx_runtime.JSX.Element;
16
+ declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents: unappliedEditEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, debug, clickToInteractEnabled, }: Props) => react_jsx_runtime.JSX.Element;
16
17
 
17
18
  export { SchematicViewer };
package/dist/index.js CHANGED
@@ -1,86 +1,10 @@
1
1
  // lib/components/SchematicViewer.tsx
2
- import { useMouseMatrixTransform } from "use-mouse-matrix-transform";
3
2
  import { convertCircuitJsonToSchematicSvg } from "circuit-to-svg";
4
- import { useMemo, useRef as useRef4, useState as useState3 } from "react";
5
3
 
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
- )
46
- }
47
- );
48
- };
49
-
50
- // lib/hooks/use-resize-handling.ts
51
- import { useEffect, useState } from "react";
52
- var useResizeHandling = (containerRef) => {
53
- const [containerWidth, setContainerWidth] = useState(0);
54
- const [containerHeight, setContainerHeight] = useState(0);
55
- useEffect(() => {
56
- if (!containerRef.current) return;
57
- const updateDimensions = () => {
58
- const rect = containerRef.current?.getBoundingClientRect();
59
- setContainerWidth(rect?.width || 0);
60
- setContainerHeight(rect?.height || 0);
61
- };
62
- updateDimensions();
63
- const resizeObserver = new ResizeObserver(updateDimensions);
64
- resizeObserver.observe(containerRef.current);
65
- window.addEventListener("resize", updateDimensions);
66
- return () => {
67
- resizeObserver.disconnect();
68
- window.removeEventListener("resize", updateDimensions);
69
- };
70
- }, []);
71
- return { containerWidth, containerHeight };
72
- };
73
-
74
- // lib/hooks/useComponentDragging.ts
75
- import { su } from "@tscircuit/soup-util";
76
-
77
- // lib/utils/debug.ts
78
- import Debug from "debug";
79
- var debug = Debug("schematic-viewer");
80
- var enableDebug = () => {
81
- Debug.enable("schematic-viewer*");
82
- };
83
- var debug_default = debug;
4
+ // lib/hooks/useChangeSchematicComponentLocationsInSvg.ts
5
+ import "@tscircuit/soup-util";
6
+ import "transformation-matrix";
7
+ import { useEffect, useRef } from "react";
84
8
 
85
9
  // lib/utils/get-component-offset-due-to-events.ts
86
10
  var getComponentOffsetDueToEvents = ({
@@ -104,134 +28,7 @@ var getComponentOffsetDueToEvents = ({
104
28
  };
105
29
  };
106
30
 
107
- // lib/hooks/useComponentDragging.ts
108
- import { useCallback, useEffect as useEffect2, useRef, useState as useState2 } from "react";
109
- import {
110
- compose
111
- } from "transformation-matrix";
112
- var debug2 = debug_default.extend("useComponentDragging");
113
- var useComponentDragging = ({
114
- onEditEvent,
115
- editEvents = [],
116
- circuitJson,
117
- cancelDrag,
118
- svgToScreenProjection,
119
- realToSvgProjection,
120
- enabled = false
121
- }) => {
122
- const [activeEditEvent, setActiveEditEvent] = useState2(null);
123
- const realToScreenProjection = compose(
124
- realToSvgProjection,
125
- svgToScreenProjection
126
- );
127
- const dragStartPosRef = useRef(null);
128
- const activeEditEventRef = useRef(null);
129
- const handleMouseDown = useCallback(
130
- (e) => {
131
- if (!enabled) return;
132
- const target = e.target;
133
- const componentGroup = target.closest(
134
- '[data-circuit-json-type="schematic_component"]'
135
- );
136
- if (!componentGroup) return;
137
- const schematic_component_id = componentGroup.getAttribute(
138
- "data-schematic-component-id"
139
- );
140
- if (!schematic_component_id) return;
141
- if (cancelDrag) cancelDrag();
142
- const schematic_component = su(circuitJson).schematic_component.get(
143
- schematic_component_id
144
- );
145
- if (!schematic_component) return;
146
- const editEventOffset = getComponentOffsetDueToEvents({
147
- editEvents,
148
- schematic_component_id
149
- });
150
- dragStartPosRef.current = {
151
- x: e.clientX,
152
- y: e.clientY
153
- };
154
- const current_position = {
155
- x: schematic_component.center.x + editEventOffset.x,
156
- y: schematic_component.center.y + editEventOffset.y
157
- };
158
- const newEditEvent = {
159
- edit_event_id: Math.random().toString(36).substr(2, 9),
160
- edit_event_type: "edit_schematic_component_location",
161
- schematic_component_id,
162
- original_center: current_position,
163
- new_center: { ...current_position },
164
- in_progress: true,
165
- created_at: Date.now(),
166
- _element: componentGroup
167
- };
168
- activeEditEventRef.current = newEditEvent;
169
- },
170
- [cancelDrag, enabled, circuitJson, editEvents]
171
- );
172
- const handleMouseMove = useCallback(
173
- (e) => {
174
- if (!activeEditEventRef.current || !dragStartPosRef.current) return;
175
- const screenDelta = {
176
- x: e.clientX - dragStartPosRef.current.x,
177
- y: e.clientY - dragStartPosRef.current.y
178
- };
179
- const mmDelta = {
180
- x: screenDelta.x / realToScreenProjection.a,
181
- y: screenDelta.y / realToScreenProjection.d
182
- };
183
- const newEditEvent = {
184
- ...activeEditEventRef.current,
185
- new_center: {
186
- x: activeEditEventRef.current.original_center.x + mmDelta.x,
187
- y: activeEditEventRef.current.original_center.y + mmDelta.y
188
- }
189
- };
190
- activeEditEventRef.current = newEditEvent;
191
- setActiveEditEvent(newEditEvent);
192
- },
193
- [realToScreenProjection]
194
- );
195
- const handleMouseUp = useCallback(() => {
196
- if (!activeEditEventRef.current) return;
197
- const finalEvent = {
198
- ...activeEditEventRef.current,
199
- in_progress: false
200
- };
201
- debug2("handleMouseUp calling onEditEvent with new edit event", {
202
- newEditEvent: finalEvent
203
- });
204
- if (onEditEvent) onEditEvent(finalEvent);
205
- activeEditEventRef.current = null;
206
- dragStartPosRef.current = null;
207
- setActiveEditEvent(null);
208
- }, [onEditEvent]);
209
- useEffect2(() => {
210
- window.addEventListener("mousemove", handleMouseMove);
211
- window.addEventListener("mouseup", handleMouseUp);
212
- return () => {
213
- window.removeEventListener("mousemove", handleMouseMove);
214
- window.removeEventListener("mouseup", handleMouseUp);
215
- };
216
- }, [handleMouseMove, handleMouseUp]);
217
- return {
218
- handleMouseDown,
219
- isDragging: !!activeEditEventRef.current,
220
- activeEditEvent
221
- };
222
- };
223
-
224
- // lib/components/SchematicViewer.tsx
225
- import {
226
- identity,
227
- fromString,
228
- toString as transformToString
229
- } from "transformation-matrix";
230
-
231
31
  // lib/hooks/useChangeSchematicComponentLocationsInSvg.ts
232
- import "@tscircuit/soup-util";
233
- import "transformation-matrix";
234
- import { useEffect as useEffect3, useRef as useRef2 } from "react";
235
32
  var useChangeSchematicComponentLocationsInSvg = ({
236
33
  svgDivRef,
237
34
  realToSvgProjection,
@@ -239,8 +36,8 @@ var useChangeSchematicComponentLocationsInSvg = ({
239
36
  activeEditEvent,
240
37
  editEvents
241
38
  }) => {
242
- const lastSvgContentRef = useRef2(null);
243
- useEffect3(() => {
39
+ const lastSvgContentRef = useRef(null);
40
+ useEffect(() => {
244
41
  const svg = svgDivRef.current;
245
42
  if (!svg) return;
246
43
  const observer = new MutationObserver((mutations) => {
@@ -304,16 +101,16 @@ var useChangeSchematicComponentLocationsInSvg = ({
304
101
  };
305
102
 
306
103
  // lib/hooks/useChangeSchematicTracesForMovedComponents.ts
307
- import { useEffect as useEffect4, useRef as useRef3 } from "react";
308
- import { su as su3 } from "@tscircuit/soup-util";
104
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
105
+ import { su as su2 } from "@tscircuit/soup-util";
309
106
  var useChangeSchematicTracesForMovedComponents = ({
310
107
  svgDivRef,
311
108
  circuitJson,
312
109
  activeEditEvent,
313
110
  editEvents
314
111
  }) => {
315
- const lastSvgContentRef = useRef3(null);
316
- useEffect4(() => {
112
+ const lastSvgContentRef = useRef2(null);
113
+ useEffect2(() => {
317
114
  const svg = svgDivRef.current;
318
115
  if (!svg) return;
319
116
  const updateTraceStyles = () => {
@@ -329,15 +126,15 @@ var useChangeSchematicTracesForMovedComponents = ({
329
126
  ...activeEditEvent ? [activeEditEvent] : []
330
127
  ]) {
331
128
  if ("schematic_component_id" in editEvent && editEvent.edit_event_type === "edit_schematic_component_location") {
332
- const sch_component = su3(circuitJson).schematic_component.get(
129
+ const sch_component = su2(circuitJson).schematic_component.get(
333
130
  editEvent.schematic_component_id
334
131
  );
335
132
  if (!sch_component) return;
336
- const src_ports = su3(circuitJson).source_port.list({
133
+ const src_ports = su2(circuitJson).source_port.list({
337
134
  source_component_id: sch_component.source_component_id
338
135
  });
339
136
  const src_port_ids = new Set(src_ports.map((sp) => sp.source_port_id));
340
- const src_traces = su3(circuitJson).source_trace.list().filter(
137
+ const src_traces = su2(circuitJson).source_trace.list().filter(
341
138
  (st) => st.connected_source_port_ids?.some(
342
139
  (spi) => src_port_ids.has(spi)
343
140
  )
@@ -345,7 +142,7 @@ var useChangeSchematicTracesForMovedComponents = ({
345
142
  const src_trace_ids = new Set(
346
143
  src_traces.map((st) => st.source_trace_id)
347
144
  );
348
- const schematic_traces = su3(circuitJson).schematic_trace.list().filter((st) => src_trace_ids.has(st.source_trace_id));
145
+ const schematic_traces = su2(circuitJson).schematic_trace.list().filter((st) => src_trace_ids.has(st.source_trace_id));
349
146
  schematic_traces.forEach((trace) => {
350
147
  const traceElements = svg.querySelectorAll(
351
148
  `[data-schematic-trace-id="${trace.schematic_trace_id}"] path`
@@ -393,12 +190,238 @@ var useChangeSchematicTracesForMovedComponents = ({
393
190
  }, [svgDivRef, activeEditEvent, circuitJson, editEvents]);
394
191
  };
395
192
 
193
+ // lib/utils/debug.ts
194
+ import Debug from "debug";
195
+ var debug = Debug("schematic-viewer");
196
+ var enableDebug = () => {
197
+ Debug.enable("schematic-viewer*");
198
+ };
199
+ var debug_default = debug;
200
+
201
+ // lib/components/SchematicViewer.tsx
202
+ import { useEffect as useEffect5, useMemo, useRef as useRef4, useState as useState3 } from "react";
203
+ import {
204
+ fromString,
205
+ identity,
206
+ toString as transformToString
207
+ } from "transformation-matrix";
208
+ import { useMouseMatrixTransform } from "use-mouse-matrix-transform";
209
+
210
+ // lib/hooks/use-resize-handling.ts
211
+ import { useEffect as useEffect3, useState } from "react";
212
+ var useResizeHandling = (containerRef) => {
213
+ const [containerWidth, setContainerWidth] = useState(0);
214
+ const [containerHeight, setContainerHeight] = useState(0);
215
+ useEffect3(() => {
216
+ if (!containerRef.current) return;
217
+ const updateDimensions = () => {
218
+ const rect = containerRef.current?.getBoundingClientRect();
219
+ setContainerWidth(rect?.width || 0);
220
+ setContainerHeight(rect?.height || 0);
221
+ };
222
+ updateDimensions();
223
+ const resizeObserver = new ResizeObserver(updateDimensions);
224
+ resizeObserver.observe(containerRef.current);
225
+ window.addEventListener("resize", updateDimensions);
226
+ return () => {
227
+ resizeObserver.disconnect();
228
+ window.removeEventListener("resize", updateDimensions);
229
+ };
230
+ }, []);
231
+ return { containerWidth, containerHeight };
232
+ };
233
+
234
+ // lib/hooks/useComponentDragging.ts
235
+ import { su as su3 } from "@tscircuit/soup-util";
236
+ import { useCallback, useEffect as useEffect4, useRef as useRef3, useState as useState2 } from "react";
237
+ import {
238
+ compose as compose2
239
+ } from "transformation-matrix";
240
+ var debug2 = debug_default.extend("useComponentDragging");
241
+ var useComponentDragging = ({
242
+ onEditEvent,
243
+ editEvents = [],
244
+ circuitJson,
245
+ cancelDrag,
246
+ svgToScreenProjection,
247
+ realToSvgProjection,
248
+ enabled = false
249
+ }) => {
250
+ const [activeEditEvent, setActiveEditEvent] = useState2(null);
251
+ const realToScreenProjection = compose2(
252
+ realToSvgProjection,
253
+ svgToScreenProjection
254
+ );
255
+ const dragStartPosRef = useRef3(null);
256
+ const activeEditEventRef = useRef3(null);
257
+ const componentPositionsRef = useRef3(/* @__PURE__ */ new Map());
258
+ useEffect4(() => {
259
+ editEvents.forEach((event) => {
260
+ if ("edit_event_type" in event && event.edit_event_type === "edit_schematic_component_location" && !event.in_progress) {
261
+ componentPositionsRef.current.set(
262
+ event.schematic_component_id,
263
+ { ...event.new_center }
264
+ );
265
+ }
266
+ });
267
+ }, [editEvents]);
268
+ const handleMouseDown = useCallback(
269
+ (e) => {
270
+ if (!enabled) return;
271
+ const target = e.target;
272
+ const componentGroup = target.closest(
273
+ '[data-circuit-json-type="schematic_component"]'
274
+ );
275
+ if (!componentGroup) return;
276
+ const schematic_component_id = componentGroup.getAttribute(
277
+ "data-schematic-component-id"
278
+ );
279
+ if (!schematic_component_id) return;
280
+ if (cancelDrag) cancelDrag();
281
+ const schematic_component = su3(circuitJson).schematic_component.get(
282
+ schematic_component_id
283
+ );
284
+ if (!schematic_component) return;
285
+ dragStartPosRef.current = {
286
+ x: e.clientX,
287
+ y: e.clientY
288
+ };
289
+ let current_position;
290
+ const trackedPosition = componentPositionsRef.current.get(schematic_component_id);
291
+ if (trackedPosition) {
292
+ current_position = { ...trackedPosition };
293
+ } else {
294
+ const editEventOffset = getComponentOffsetDueToEvents({
295
+ editEvents,
296
+ schematic_component_id
297
+ });
298
+ current_position = {
299
+ x: schematic_component.center.x + editEventOffset.x,
300
+ y: schematic_component.center.y + editEventOffset.y
301
+ };
302
+ componentPositionsRef.current.set(schematic_component_id, { ...current_position });
303
+ }
304
+ const newEditEvent = {
305
+ edit_event_id: Math.random().toString(36).substr(2, 9),
306
+ edit_event_type: "edit_schematic_component_location",
307
+ schematic_component_id,
308
+ original_center: current_position,
309
+ new_center: { ...current_position },
310
+ in_progress: true,
311
+ created_at: Date.now(),
312
+ _element: componentGroup
313
+ };
314
+ activeEditEventRef.current = newEditEvent;
315
+ setActiveEditEvent(newEditEvent);
316
+ },
317
+ [cancelDrag, enabled, circuitJson, editEvents]
318
+ );
319
+ const handleMouseMove = useCallback(
320
+ (e) => {
321
+ if (!activeEditEventRef.current || !dragStartPosRef.current) return;
322
+ const screenDelta = {
323
+ x: e.clientX - dragStartPosRef.current.x,
324
+ y: e.clientY - dragStartPosRef.current.y
325
+ };
326
+ const mmDelta = {
327
+ x: screenDelta.x / realToScreenProjection.a,
328
+ y: screenDelta.y / realToScreenProjection.d
329
+ };
330
+ const newEditEvent = {
331
+ ...activeEditEventRef.current,
332
+ new_center: {
333
+ x: activeEditEventRef.current.original_center.x + mmDelta.x,
334
+ y: activeEditEventRef.current.original_center.y + mmDelta.y
335
+ }
336
+ };
337
+ activeEditEventRef.current = newEditEvent;
338
+ setActiveEditEvent(newEditEvent);
339
+ },
340
+ [realToScreenProjection]
341
+ );
342
+ const handleMouseUp = useCallback(() => {
343
+ if (!activeEditEventRef.current) return;
344
+ const finalEvent = {
345
+ ...activeEditEventRef.current,
346
+ in_progress: false
347
+ };
348
+ componentPositionsRef.current.set(
349
+ finalEvent.schematic_component_id,
350
+ { ...finalEvent.new_center }
351
+ );
352
+ debug2("handleMouseUp calling onEditEvent with new edit event", {
353
+ newEditEvent: finalEvent
354
+ });
355
+ if (onEditEvent) onEditEvent(finalEvent);
356
+ activeEditEventRef.current = null;
357
+ dragStartPosRef.current = null;
358
+ setActiveEditEvent(null);
359
+ }, [onEditEvent]);
360
+ useEffect4(() => {
361
+ window.addEventListener("mousemove", handleMouseMove);
362
+ window.addEventListener("mouseup", handleMouseUp);
363
+ return () => {
364
+ window.removeEventListener("mousemove", handleMouseMove);
365
+ window.removeEventListener("mouseup", handleMouseUp);
366
+ };
367
+ }, [handleMouseMove, handleMouseUp]);
368
+ return {
369
+ handleMouseDown,
370
+ isDragging: !!activeEditEventRef.current,
371
+ activeEditEvent
372
+ };
373
+ };
374
+
375
+ // lib/components/EditIcon.tsx
376
+ import { jsx, jsxs } from "react/jsx-runtime";
377
+ var EditIcon = ({
378
+ onClick,
379
+ active
380
+ }) => {
381
+ return /* @__PURE__ */ jsx(
382
+ "div",
383
+ {
384
+ onClick,
385
+ style: {
386
+ position: "absolute",
387
+ top: "16px",
388
+ right: "16px",
389
+ backgroundColor: active ? "#4CAF50" : "#fff",
390
+ color: active ? "#fff" : "#000",
391
+ padding: "8px",
392
+ borderRadius: "4px",
393
+ cursor: "pointer",
394
+ boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
395
+ display: "flex",
396
+ alignItems: "center",
397
+ gap: "4px",
398
+ zIndex: 1e3
399
+ },
400
+ children: /* @__PURE__ */ jsxs(
401
+ "svg",
402
+ {
403
+ width: "16",
404
+ height: "16",
405
+ viewBox: "0 0 24 24",
406
+ fill: "none",
407
+ stroke: "currentColor",
408
+ strokeWidth: "2",
409
+ children: [
410
+ /* @__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" }),
411
+ /* @__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" })
412
+ ]
413
+ }
414
+ )
415
+ }
416
+ );
417
+ };
418
+
396
419
  // lib/components/SchematicViewer.tsx
397
420
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
398
421
  var SchematicViewer = ({
399
422
  circuitJson,
400
423
  containerStyle,
401
- editEvents = [],
424
+ editEvents: unappliedEditEvents = [],
402
425
  onEditEvent,
403
426
  defaultEditMode = false,
404
427
  debugGrid = false,
@@ -414,6 +437,19 @@ var SchematicViewer = ({
414
437
  !clickToInteractEnabled
415
438
  );
416
439
  const svgDivRef = useRef4(null);
440
+ const [internalEditEvents, setInternalEditEvents] = useState3([]);
441
+ const circuitJsonRef = useRef4(circuitJson);
442
+ const getCircuitHash = (circuitJson2) => {
443
+ return `${circuitJson2?.length || 0}_${circuitJson2?.editCount || 0}`;
444
+ };
445
+ useEffect5(() => {
446
+ const circuitHash = getCircuitHash(circuitJson);
447
+ const circuitHashRef = getCircuitHash(circuitJsonRef.current);
448
+ if (circuitHash !== circuitHashRef) {
449
+ setInternalEditEvents([]);
450
+ circuitJsonRef.current = circuitJson;
451
+ }
452
+ }, [circuitJson]);
417
453
  const {
418
454
  ref: containerRef,
419
455
  cancelDrag,
@@ -450,20 +486,29 @@ var SchematicViewer = ({
450
486
  return identity();
451
487
  }
452
488
  }, [svgString]);
489
+ const handleEditEvent = (event) => {
490
+ setInternalEditEvents((prev) => [...prev, event]);
491
+ if (onEditEvent) {
492
+ onEditEvent(event);
493
+ }
494
+ };
495
+ const editEventsWithUnappliedEditEvents = useMemo(() => {
496
+ return [...unappliedEditEvents, ...internalEditEvents];
497
+ }, [unappliedEditEvents, internalEditEvents]);
453
498
  const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
454
499
  {
455
- onEditEvent,
500
+ onEditEvent: handleEditEvent,
456
501
  cancelDrag,
457
502
  realToSvgProjection,
458
503
  svgToScreenProjection,
459
504
  circuitJson,
460
- editEvents,
505
+ editEvents: editEventsWithUnappliedEditEvents,
461
506
  enabled: editModeEnabled && isInteractionEnabled
462
507
  }
463
508
  );
464
509
  useChangeSchematicComponentLocationsInSvg({
465
510
  svgDivRef,
466
- editEvents,
511
+ editEvents: editEventsWithUnappliedEditEvents,
467
512
  realToSvgProjection,
468
513
  svgToScreenProjection,
469
514
  activeEditEvent
@@ -472,7 +517,7 @@ var SchematicViewer = ({
472
517
  svgDivRef,
473
518
  circuitJson,
474
519
  activeEditEvent,
475
- editEvents
520
+ editEvents: editEventsWithUnappliedEditEvents
476
521
  });
477
522
  const svgDiv = useMemo(
478
523
  () => /* @__PURE__ */ jsx2(
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/components/SchematicViewer.tsx","../lib/components/EditIcon.tsx","../lib/hooks/use-resize-handling.ts","../lib/hooks/useComponentDragging.ts","../lib/utils/debug.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\"\nimport { enableDebug } from \"lib/utils/debug\"\n\ninterface Props {\n circuitJson: any[]\n containerStyle?: React.CSSProperties\n editEvents?: ManualEditEvent[]\n onEditEvent?: (event: ManualEditEvent) => void\n defaultEditMode?: boolean\n debugGrid?: boolean\n editingEnabled?: boolean\n debug?: boolean\n clickToInteractEnabled?: boolean\n}\n\nexport const SchematicViewer = ({\n circuitJson,\n containerStyle,\n editEvents = [],\n onEditEvent,\n defaultEditMode = false,\n debugGrid = false,\n editingEnabled = false,\n debug = false,\n clickToInteractEnabled = false,\n}: Props) => {\n if (debug) {\n enableDebug()\n }\n const [editModeEnabled, setEditModeEnabled] = useState(defaultEditMode)\n const [isInteractionEnabled, setIsInteractionEnabled] = useState<boolean>(\n !clickToInteractEnabled,\n )\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 // @ts-ignore disabled is a valid prop but not typed\n enabled: isInteractionEnabled,\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 && isInteractionEnabled,\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: clickToInteractEnabled\n ? isInteractionEnabled\n ? \"auto\"\n : \"none\"\n : \"auto\",\n transformOrigin: \"0 0\",\n }}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>\n dangerouslySetInnerHTML={{ __html: svgString }}\n />\n ),\n [svgString, isInteractionEnabled, clickToInteractEnabled],\n )\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"relative\",\n backgroundColor: \"#F5F1ED\",\n overflow: \"hidden\",\n cursor: isDragging\n ? \"grabbing\"\n : clickToInteractEnabled && !isInteractionEnabled\n ? \"pointer\"\n : \"grab\",\n minHeight: \"300px\",\n ...containerStyle,\n }}\n onMouseDown={(e) => {\n if (clickToInteractEnabled && !isInteractionEnabled) {\n e.preventDefault()\n e.stopPropagation()\n return\n }\n handleMouseDown(e)\n }}\n onMouseDownCapture={(e) => {\n if (clickToInteractEnabled && !isInteractionEnabled) {\n e.preventDefault()\n e.stopPropagation()\n return\n }\n }}\n >\n {!isInteractionEnabled && clickToInteractEnabled && (\n <div\n onClick={(e) => {\n e.preventDefault()\n e.stopPropagation()\n setIsInteractionEnabled(true)\n }}\n style={{\n position: \"absolute\",\n inset: 0,\n cursor: \"pointer\",\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"all\",\n }}\n >\n <div\n style={{\n backgroundColor: \"rgba(0, 0, 0, 0.8)\",\n color: \"white\",\n padding: \"12px 24px\",\n borderRadius: \"8px\",\n fontSize: \"16px\",\n fontFamily: \"sans-serif\",\n pointerEvents: \"none\",\n }}\n >\n Click to Interact\n </div>\n </div>\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 { su } from \"@tscircuit/soup-util\"\nimport Debug from \"lib/utils/debug\"\nimport { getComponentOffsetDueToEvents } from \"lib/utils/get-component-offset-due-to-events\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\nimport {\n type Matrix,\n compose\n} from \"transformation-matrix\"\nimport type {\n EditSchematicComponentLocationEventWithElement,\n ManualEditEvent,\n} from \"../types/edit-events\"\n\nconst debug = Debug.extend(\"useComponentDragging\")\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 current_position = {\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: current_position,\n new_center: { ...current_position },\n in_progress: true,\n created_at: Date.now(),\n _element: componentGroup as any,\n }\n\n activeEditEventRef.current = newEditEvent\n },\n [cancelDrag, enabled, circuitJson, editEvents],\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 debug(\"handleMouseUp calling onEditEvent with new edit event\", {\n newEditEvent: finalEvent,\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 Debug from \"debug\"\n\nexport const debug = Debug(\"schematic-viewer\")\n\nexport const enableDebug = () => {\n Debug.enable(\"schematic-viewer*\")\n}\n\nexport default debug\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","debug","useEffect","useRef","useRef","useEffect","useEffect","useRef","su","jsx","jsxs","debug","useState","useRef"]}
1
+ {"version":3,"sources":["../lib/components/SchematicViewer.tsx","../lib/hooks/useChangeSchematicComponentLocationsInSvg.ts","../lib/utils/get-component-offset-due-to-events.ts","../lib/hooks/useChangeSchematicTracesForMovedComponents.ts","../lib/utils/debug.ts","../lib/hooks/use-resize-handling.ts","../lib/hooks/useComponentDragging.ts","../lib/components/EditIcon.tsx"],"sourcesContent":["import { convertCircuitJsonToSchematicSvg } from \"circuit-to-svg\"\nimport { useChangeSchematicComponentLocationsInSvg } from \"lib/hooks/useChangeSchematicComponentLocationsInSvg\"\nimport { useChangeSchematicTracesForMovedComponents } from \"lib/hooks/useChangeSchematicTracesForMovedComponents\"\nimport { enableDebug } from \"lib/utils/debug\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\nimport {\n fromString,\n identity,\n toString as transformToString,\n} from \"transformation-matrix\"\nimport { useMouseMatrixTransform } from \"use-mouse-matrix-transform\"\nimport { useResizeHandling } from \"../hooks/use-resize-handling\"\nimport { useComponentDragging } from \"../hooks/useComponentDragging\"\nimport type { ManualEditEvent } from \"../types/edit-events\"\nimport { EditIcon } from \"./EditIcon\"\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 debug?: boolean\n clickToInteractEnabled?: boolean\n}\n\nexport const SchematicViewer = ({\n circuitJson,\n containerStyle,\n editEvents: unappliedEditEvents = [],\n onEditEvent,\n defaultEditMode = false,\n debugGrid = false,\n editingEnabled = false,\n debug = false,\n clickToInteractEnabled = false,\n}: Props) => {\n if (debug) {\n enableDebug()\n }\n const [editModeEnabled, setEditModeEnabled] = useState(defaultEditMode)\n const [isInteractionEnabled, setIsInteractionEnabled] = useState<boolean>(\n !clickToInteractEnabled,\n )\n const svgDivRef = useRef<HTMLDivElement>(null)\n\n const [internalEditEvents, setInternalEditEvents] = useState<ManualEditEvent[]>([])\n const circuitJsonRef = useRef<CircuitJson>(circuitJson)\n\n const getCircuitHash = (circuitJson: CircuitJson) => {\n return `${circuitJson?.length || 0}_${(circuitJson as any)?.editCount || 0}`\n }\n\n useEffect(() => {\n const circuitHash = getCircuitHash(circuitJson)\n const circuitHashRef = getCircuitHash(circuitJsonRef.current)\n\n if (circuitHash !== circuitHashRef) {\n setInternalEditEvents([])\n circuitJsonRef.current = circuitJson\n }\n }, [circuitJson])\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 // @ts-ignore disabled is a valid prop but not typed\n enabled: isInteractionEnabled,\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 handleEditEvent = (event: ManualEditEvent) => {\n setInternalEditEvents((prev) => [...prev, event])\n if (onEditEvent) {\n onEditEvent(event)\n }\n }\n\n const editEventsWithUnappliedEditEvents = useMemo(() => {\n return [...unappliedEditEvents, ...internalEditEvents]\n }, [unappliedEditEvents, internalEditEvents])\n\n const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(\n {\n onEditEvent: handleEditEvent,\n cancelDrag,\n realToSvgProjection,\n svgToScreenProjection,\n circuitJson,\n editEvents: editEventsWithUnappliedEditEvents,\n enabled: editModeEnabled && isInteractionEnabled,\n },\n )\n\n useChangeSchematicComponentLocationsInSvg({\n svgDivRef,\n editEvents: editEventsWithUnappliedEditEvents,\n realToSvgProjection,\n svgToScreenProjection,\n activeEditEvent,\n })\n\n useChangeSchematicTracesForMovedComponents({\n svgDivRef,\n circuitJson,\n activeEditEvent,\n editEvents: editEventsWithUnappliedEditEvents,\n })\n\n const svgDiv = useMemo(\n () => (\n <div\n ref={svgDivRef}\n style={{\n pointerEvents: clickToInteractEnabled\n ? isInteractionEnabled\n ? \"auto\"\n : \"none\"\n : \"auto\",\n transformOrigin: \"0 0\",\n }}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>\n dangerouslySetInnerHTML={{ __html: svgString }}\n />\n ),\n [svgString, isInteractionEnabled, clickToInteractEnabled],\n )\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"relative\",\n backgroundColor: \"#F5F1ED\",\n overflow: \"hidden\",\n cursor: isDragging\n ? \"grabbing\"\n : clickToInteractEnabled && !isInteractionEnabled\n ? \"pointer\"\n : \"grab\",\n minHeight: \"300px\",\n ...containerStyle,\n }}\n onMouseDown={(e) => {\n if (clickToInteractEnabled && !isInteractionEnabled) {\n e.preventDefault()\n e.stopPropagation()\n return\n }\n handleMouseDown(e)\n }}\n onMouseDownCapture={(e) => {\n if (clickToInteractEnabled && !isInteractionEnabled) {\n e.preventDefault()\n e.stopPropagation()\n return\n }\n }}\n >\n {!isInteractionEnabled && clickToInteractEnabled && (\n <div\n onClick={(e) => {\n e.preventDefault()\n e.stopPropagation()\n setIsInteractionEnabled(true)\n }}\n style={{\n position: \"absolute\",\n inset: 0,\n cursor: \"pointer\",\n zIndex: 10,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"all\",\n }}\n >\n <div\n style={{\n backgroundColor: \"rgba(0, 0, 0, 0.8)\",\n color: \"white\",\n padding: \"12px 24px\",\n borderRadius: \"8px\",\n fontSize: \"16px\",\n fontFamily: \"sans-serif\",\n pointerEvents: \"none\",\n }}\n >\n Click to Interact\n </div>\n </div>\n )}\n {editingEnabled && (\n <EditIcon\n active={editModeEnabled}\n onClick={() => setEditModeEnabled(!editModeEnabled)}\n />\n )}\n {svgDiv}\n </div>\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 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 { 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","import Debug from \"debug\"\n\nexport const debug = Debug(\"schematic-viewer\")\n\nexport const enableDebug = () => {\n Debug.enable(\"schematic-viewer*\")\n}\n\nexport default debug\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 { su } from \"@tscircuit/soup-util\"\nimport Debug from \"lib/utils/debug\"\nimport { getComponentOffsetDueToEvents } from \"lib/utils/get-component-offset-due-to-events\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\nimport {\n type Matrix,\n compose\n} from \"transformation-matrix\"\nimport type {\n EditSchematicComponentLocationEventWithElement,\n ManualEditEvent,\n} from \"../types/edit-events\"\n\nconst debug = Debug.extend(\"useComponentDragging\")\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 // Store the latest positions of components being tracked\n const componentPositionsRef = useRef<Map<string, {x: number, y: number}>>(new Map())\n \n // Update position map with the latest positions from edit events\n useEffect(() => {\n // Process completed edit events to track latest positions\n editEvents.forEach(event => {\n if (\n \"edit_event_type\" in event && \n event.edit_event_type === \"edit_schematic_component_location\" && \n !event.in_progress\n ) {\n componentPositionsRef.current.set(\n event.schematic_component_id, \n {...event.new_center}\n )\n }\n })\n }, [editEvents])\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 \n dragStartPosRef.current = {\n x: e.clientX,\n y: e.clientY,\n }\n\n // Get the current position of the component\n // Check if we're already tracking this component\n let current_position: {x: number, y: number}\n const trackedPosition = componentPositionsRef.current.get(schematic_component_id)\n \n if (trackedPosition) {\n // Use the tracked position from previous edits\n current_position = {...trackedPosition}\n } else {\n // Calculate position based on component data and edit events\n const editEventOffset = getComponentOffsetDueToEvents({\n editEvents,\n schematic_component_id: schematic_component_id,\n })\n \n current_position = {\n x: schematic_component.center.x + editEventOffset.x,\n y: schematic_component.center.y + editEventOffset.y,\n }\n \n // Store this initial position\n componentPositionsRef.current.set(schematic_component_id, {...current_position})\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: current_position,\n new_center: { ...current_position },\n in_progress: true,\n created_at: Date.now(),\n _element: componentGroup as any,\n }\n\n activeEditEventRef.current = newEditEvent\n setActiveEditEvent(newEditEvent)\n },\n [cancelDrag, enabled, circuitJson, editEvents],\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 \n // Update our stored position for this component\n componentPositionsRef.current.set(\n finalEvent.schematic_component_id, \n {...finalEvent.new_center}\n )\n \n debug(\"handleMouseUp calling onEditEvent with new edit event\", {\n newEditEvent: finalEvent,\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","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"],"mappings":";AAAA,SAAS,wCAAwC;;;ACAjD,OAAmB;AAKnB,OAAmD;AACnD,SAAS,WAAW,cAAc;;;ACI3B,IAAM,gCAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AACF,MAGM;AACJ,QAAM,yBACJ,WACG;AAAA,IACC,CAAC,UACC,4BAA4B,SAC5B,MAAM,2BAA2B;AAAA,EACrC,EACC;AAAA,IACC,CAAC,UACC,qBAAqB,SACrB,MAAM,oBAAoB;AAAA,EAC9B;AAEJ,QAAM,eAAe,uBAAuB,OAAO,CAAC,KAAK,UAAU;AACjE,WAAO,MAAM,MAAM,WAAW,IAAI,MAAM,gBAAgB;AAAA,EAC1D,GAAG,CAAC;AAEJ,QAAM,eAAe,uBAAuB,OAAO,CAAC,KAAK,UAAU;AACjE,WAAO,MAAM,MAAM,WAAW,IAAI,MAAM,gBAAgB;AAAA,EAC1D,GAAG,CAAC;AAEJ,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACF;;;ADxBO,IAAM,4CAA4C,CAAC;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAMM;AAEJ,QAAM,oBAAoB,OAAsB,IAAI;AAEpD,YAAU,MAAM;AACd,UAAM,MAAM,UAAU;AACtB,QAAI,CAAC,IAAK;AAGV,UAAM,WAAW,IAAI,iBAAiB,CAAC,cAAc;AAEnD,YAAM,oBAAoB,IAAI;AAC9B,UAAI,sBAAsB,kBAAkB,SAAS;AACnD,0BAAkB,UAAU;AAG5B,wBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAGD,UAAM,kBAAkB,MAAM;AAC5B,YAAM,8BAA8B,oBAAI,IAAY;AACpD,iBAAW,SAAS,YAAY;AAC9B,YACE,qBAAqB,SACrB,MAAM,oBAAoB,qCAC1B;AACA,sCAA4B,IAAI,MAAM,sBAAsB;AAAA,QAC9D;AAAA,MACF;AACA,UAAI,iBAAiB;AACnB,oCAA4B,IAAI,gBAAgB,sBAAsB;AAAA,MACxE;AAGA,YAAM,gBAAgB,IAAI;AAAA,QACxB;AAAA,MACF;AAEA,iBAAW,aAAa,MAAM,KAAK,aAAa,GAAG;AACjD,cAAM,yBAAyB,UAAU;AAAA,UACvC;AAAA,QACF;AAEA,cAAM,WAAW,8BAA8B;AAAA,UAC7C,YAAY;AAAA,YACV,GAAG;AAAA,YACH,GAAI,kBAAkB,CAAC,eAAe,IAAI,CAAC;AAAA,UAC7C;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM,WAAW;AAAA,UACf,GAAG,SAAS,IAAI,oBAAoB;AAAA,UACpC,GAAG,SAAS,IAAI,oBAAoB;AAAA,QACtC;AAEA,cAAM,QAAc,UAAkB;AACtC,cAAM,YAAY,aAAa,SAAS,CAAC,OAAO,SAAS,CAAC;AAC1D,YACE,iBAAiB,2BAA2B,wBAC5C;AACA,gBAAM,UAAU;AAChB,gBAAM,gBAAgB;AAAA,QACxB,WAAW,MAAM,SAAS;AACxB,gBAAM,UAAU;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAGA,aAAS,QAAQ,KAAK;AAAA,MACpB,WAAW;AAAA;AAAA,MACX,SAAS;AAAA;AAAA,MACT,eAAe;AAAA;AAAA,IACjB,CAAC;AAGD,oBAAgB;AAGhB,WAAO,MAAM;AACX,eAAS,WAAW;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,WAAW,YAAY,eAAe,CAAC;AAC7C;;;AEpHA,SAAS,aAAAA,YAAW,UAAAC,eAAc;AAClC,SAAS,MAAAC,WAAU;AAOZ,IAAM,6CAA6C,CAAC;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAKM;AAEJ,QAAM,oBAAoBD,QAAsB,IAAI;AAEpD,EAAAD,WAAU,MAAM;AACd,UAAM,MAAM,UAAU;AACtB,QAAI,CAAC,IAAK;AAEV,UAAM,oBAAoB,MAAM;AAE9B,YAAM,YAAY,IAAI;AAAA,QACpB;AAAA,MACF;AAGA,iBAAW,SAAS,MAAM,KAAK,SAAS,GAAG;AACzC,cAAM,aAAa,oBAAoB,GAAG;AACzC,QAAC,MAAc,MAAM,YAAY;AAAA,MACpC;AAGA,iBAAW,aAAa;AAAA,QACtB,GAAG;AAAA,QACH,GAAI,kBAAkB,CAAC,eAAe,IAAI,CAAC;AAAA,MAC7C,GAAG;AACD,YACE,4BAA4B,aAC5B,UAAU,oBAAoB,qCAC9B;AACA,gBAAM,gBAAgBE,IAAG,WAAW,EAAE,oBAAoB;AAAA,YACxD,UAAU;AAAA,UACZ;AACA,cAAI,CAAC,cAAe;AAEpB,gBAAM,YAAYA,IAAG,WAAW,EAAE,YAAY,KAAK;AAAA,YACjD,qBAAqB,cAAc;AAAA,UACrC,CAAC;AACD,gBAAM,eAAe,IAAI,IAAI,UAAU,IAAI,CAAC,OAAO,GAAG,cAAc,CAAC;AACrE,gBAAM,aAAaA,IAAG,WAAW,EAC9B,aAAa,KAAK,EAClB;AAAA,YAAO,CAAC,OACP,GAAG,2BAA2B;AAAA,cAAK,CAAC,QAClC,aAAa,IAAI,GAAG;AAAA,YACtB;AAAA,UACF;AACF,gBAAM,gBAAgB,IAAI;AAAA,YACxB,WAAW,IAAI,CAAC,OAAO,GAAG,eAAe;AAAA,UAC3C;AACA,gBAAM,mBAAmBA,IAAG,WAAW,EACpC,gBAAgB,KAAK,EACrB,OAAO,CAAC,OAAO,cAAc,IAAI,GAAG,eAAe,CAAC;AAGvD,2BAAiB,QAAQ,CAAC,UAAU;AAClC,kBAAM,gBAAgB,IAAI;AAAA,cACxB,6BAA6B,MAAM,kBAAkB;AAAA,YACvD;AACA,uBAAW,gBAAgB,MAAM,KAAK,aAAa,GAAG;AACpD,kBAAI,aAAa,aAAa,OAAO,GAAG,SAAS,WAAW;AAC1D;AACF,2BAAa,aAAa,oBAAoB,OAAO;AACpD,cAAC,aAAqB,MAAM,YAC3B;AAEF,kBAAI,CAAC,IAAI,cAAc,sBAAsB,GAAG;AAC9C,sBAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,sBAAM,KAAK;AACX,sBAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYpB,oBAAI,YAAY,KAAK;AAAA,cACvB;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,sBAAkB;AAGlB,UAAM,WAAW,IAAI,iBAAiB,iBAAiB;AACvD,aAAS,QAAQ,KAAK;AAAA,MACpB,WAAW;AAAA;AAAA,MACX,SAAS;AAAA;AAAA,MACT,eAAe;AAAA;AAAA,IACjB,CAAC;AAED,WAAO,MAAM;AACX,eAAS,WAAW;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,WAAW,iBAAiB,aAAa,UAAU,CAAC;AAC1D;;;ACxHA,OAAO,WAAW;AAEX,IAAM,QAAQ,MAAM,kBAAkB;AAEtC,IAAM,cAAc,MAAM;AAC/B,QAAM,OAAO,mBAAmB;AAClC;AAEA,IAAO,gBAAQ;;;AJJf,SAAS,aAAAC,YAAW,SAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AACrD;AAAA,EACE;AAAA,EACA;AAAA,EACA,YAAY;AAAA,OACP;AACP,SAAS,+BAA+B;;;AKVxC,SAAS,aAAAC,YAAW,gBAAgB;AAE7B,IAAM,oBAAoB,CAC/B,iBACG;AACH,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,CAAC;AACtD,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAS,CAAC;AAExD,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,aAAa,QAAS;AAE3B,UAAM,mBAAmB,MAAM;AAC7B,YAAM,OAAO,aAAa,SAAS,sBAAsB;AACzD,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,SAAO,EAAE,gBAAgB,gBAAgB;AAC3C;;;AClCA,SAAS,MAAAC,WAAU;AAGnB,SAAS,aAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AACzD;AAAA,EAEE,WAAAC;AAAA,OACK;AAMP,IAAMC,SAAQ,cAAM,OAAO,sBAAsB;AAE1C,IAAM,uBAAuB,CAAC;AAAA,EACnC;AAAA,EACA,aAAa,CAAC;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,MAcK;AACH,QAAM,CAAC,iBAAiB,kBAAkB,IACxCF,UAAgE,IAAI;AACtE,QAAM,yBAAyBC;AAAA,IAC7B;AAAA,IACA;AAAA,EACF;AAKA,QAAM,kBAAkBF,QAGd,IAAI;AAEd,QAAM,qBACJA,QAA8D,IAAI;AAGpE,QAAM,wBAAwBA,QAA4C,oBAAI,IAAI,CAAC;AAGnF,EAAAD,WAAU,MAAM;AAEd,eAAW,QAAQ,WAAS;AAC1B,UACE,qBAAqB,SACrB,MAAM,oBAAoB,uCAC1B,CAAC,MAAM,aACP;AACA,8BAAsB,QAAQ;AAAA,UAC5B,MAAM;AAAA,UACN,EAAC,GAAG,MAAM,WAAU;AAAA,QACtB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,kBAAkB;AAAA,IACtB,CAAC,MAAwB;AACvB,UAAI,CAAC,QAAS;AAEd,YAAM,SAAS,EAAE;AACjB,YAAM,iBAAiB,OAAO;AAAA,QAC5B;AAAA,MACF;AACA,UAAI,CAAC,eAAgB;AAErB,YAAM,yBAAyB,eAAe;AAAA,QAC5C;AAAA,MACF;AACA,UAAI,CAAC,uBAAwB;AAE7B,UAAI,WAAY,YAAW;AAE3B,YAAM,sBAAsBK,IAAG,WAAW,EAAE,oBAAoB;AAAA,QAC9D;AAAA,MACF;AACA,UAAI,CAAC,oBAAqB;AAE1B,sBAAgB,UAAU;AAAA,QACxB,GAAG,EAAE;AAAA,QACL,GAAG,EAAE;AAAA,MACP;AAIA,UAAI;AACJ,YAAM,kBAAkB,sBAAsB,QAAQ,IAAI,sBAAsB;AAEhF,UAAI,iBAAiB;AAEnB,2BAAmB,EAAC,GAAG,gBAAe;AAAA,MACxC,OAAO;AAEL,cAAM,kBAAkB,8BAA8B;AAAA,UACpD;AAAA,UACA;AAAA,QACF,CAAC;AAED,2BAAmB;AAAA,UACjB,GAAG,oBAAoB,OAAO,IAAI,gBAAgB;AAAA,UAClD,GAAG,oBAAoB,OAAO,IAAI,gBAAgB;AAAA,QACpD;AAGA,8BAAsB,QAAQ,IAAI,wBAAwB,EAAC,GAAG,iBAAgB,CAAC;AAAA,MACjF;AAEA,YAAM,eAA+D;AAAA,QACnE,eAAe,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC;AAAA,QACrD,iBAAiB;AAAA,QACjB;AAAA,QACA,iBAAiB;AAAA,QACjB,YAAY,EAAE,GAAG,iBAAiB;AAAA,QAClC,aAAa;AAAA,QACb,YAAY,KAAK,IAAI;AAAA,QACrB,UAAU;AAAA,MACZ;AAEA,yBAAmB,UAAU;AAC7B,yBAAmB,YAAY;AAAA,IACjC;AAAA,IACA,CAAC,YAAY,SAAS,aAAa,UAAU;AAAA,EAC/C;AAEA,QAAM,kBAAkB;AAAA,IACtB,CAAC,MAAkB;AACjB,UAAI,CAAC,mBAAmB,WAAW,CAAC,gBAAgB,QAAS;AAE7D,YAAM,cAAc;AAAA,QAClB,GAAG,EAAE,UAAU,gBAAgB,QAAQ;AAAA,QACvC,GAAG,EAAE,UAAU,gBAAgB,QAAQ;AAAA,MACzC;AAEA,YAAM,UAAU;AAAA,QACd,GAAG,YAAY,IAAI,uBAAuB;AAAA,QAC1C,GAAG,YAAY,IAAI,uBAAuB;AAAA,MAC5C;AAEA,YAAM,eAAe;AAAA,QACnB,GAAG,mBAAmB;AAAA,QACtB,YAAY;AAAA,UACV,GAAG,mBAAmB,QAAQ,gBAAgB,IAAI,QAAQ;AAAA,UAC1D,GAAG,mBAAmB,QAAQ,gBAAgB,IAAI,QAAQ;AAAA,QAC5D;AAAA,MACF;AAEA,yBAAmB,UAAU;AAC7B,yBAAmB,YAAY;AAAA,IACjC;AAAA,IACA,CAAC,sBAAsB;AAAA,EACzB;AAEA,QAAM,gBAAgB,YAAY,MAAM;AACtC,QAAI,CAAC,mBAAmB,QAAS;AACjC,UAAM,aAAa;AAAA,MACjB,GAAG,mBAAmB;AAAA,MACtB,aAAa;AAAA,IACf;AAGA,0BAAsB,QAAQ;AAAA,MAC5B,WAAW;AAAA,MACX,EAAC,GAAG,WAAW,WAAU;AAAA,IAC3B;AAEA,IAAAD,OAAM,yDAAyD;AAAA,MAC7D,cAAc;AAAA,IAChB,CAAC;AACD,QAAI,YAAa,aAAY,UAAU;AACvC,uBAAmB,UAAU;AAC7B,oBAAgB,UAAU;AAC1B,uBAAmB,IAAI;AAAA,EACzB,GAAG,CAAC,WAAW,CAAC;AAEhB,EAAAJ,WAAU,MAAM;AACd,WAAO,iBAAiB,aAAa,eAAe;AACpD,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM;AACX,aAAO,oBAAoB,aAAa,eAAe;AACvD,aAAO,oBAAoB,WAAW,aAAa;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,iBAAiB,aAAa,CAAC;AAEnC,SAAO;AAAA,IACL;AAAA,IACA,YAAY,CAAC,CAAC,mBAAmB;AAAA,IACjC;AAAA,EACF;AACF;;;ACzLM,SAQE,KARF;AAvBC,IAAM,WAAW,CAAC;AAAA,EACvB;AAAA,EACA;AACF,MAAgD;AAC9C,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,KAAK;AAAA,QACL,OAAO;AAAA,QACP,iBAAiB,SAAS,YAAY;AAAA,QACtC,OAAO,SAAS,SAAS;AAAA,QACzB,SAAS;AAAA,QACT,cAAc;AAAA,QACd,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,QAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,QAAO;AAAA,UACP,aAAY;AAAA,UAEZ;AAAA,gCAAC,UAAK,GAAE,8DAA6D;AAAA,YACrE,oBAAC,UAAK,GAAE,2DAA0D;AAAA;AAAA;AAAA,MACpE;AAAA;AAAA,EACF;AAEJ;;;APiHM,gBAAAM,MAkBF,QAAAC,aAlBE;AAxHC,IAAM,kBAAkB,CAAC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,YAAY,sBAAsB,CAAC;AAAA,EACnC;AAAA,EACA,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,OAAAC,SAAQ;AAAA,EACR,yBAAyB;AAC3B,MAAa;AACX,MAAIA,QAAO;AACT,gBAAY;AAAA,EACd;AACA,QAAM,CAAC,iBAAiB,kBAAkB,IAAIC,UAAS,eAAe;AACtE,QAAM,CAAC,sBAAsB,uBAAuB,IAAIA;AAAA,IACtD,CAAC;AAAA,EACH;AACA,QAAM,YAAYC,QAAuB,IAAI;AAE7C,QAAM,CAAC,oBAAoB,qBAAqB,IAAID,UAA4B,CAAC,CAAC;AAClF,QAAM,iBAAiBC,QAAoB,WAAW;AAEtD,QAAM,iBAAiB,CAACC,iBAA6B;AACnD,WAAO,GAAGA,cAAa,UAAU,CAAC,IAAKA,cAAqB,aAAa,CAAC;AAAA,EAC5E;AAEA,EAAAC,WAAU,MAAM;AACd,UAAM,cAAc,eAAe,WAAW;AAC9C,UAAM,iBAAiB,eAAe,eAAe,OAAO;AAE5D,QAAI,gBAAgB,gBAAgB;AAClC,4BAAsB,CAAC,CAAC;AACxB,qBAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM;AAAA,IACJ,KAAK;AAAA,IACL;AAAA,IACA,WAAW;AAAA,EACb,IAAI,wBAAwB;AAAA,IAC1B,eAAe,WAAW;AACxB,UAAI,CAAC,UAAU,QAAS;AACxB,gBAAU,QAAQ,MAAM,YAAY,kBAAkB,SAAS;AAAA,IACjE;AAAA;AAAA,IAEA,SAAS;AAAA,EACX,CAAC;AAED,QAAM,EAAE,gBAAgB,gBAAgB,IAAI,kBAAkB,YAAY;AAC1E,QAAM,YAAY,QAAQ,MAAM;AAC9B,QAAI,CAAC,kBAAkB,CAAC,gBAAiB,QAAO;AAEhD,WAAO,iCAAiC,aAAoB;AAAA,MAC1D,OAAO;AAAA,MACP,QAAQ,mBAAmB;AAAA,MAC3B,MAAM,CAAC,YACH,SACA;AAAA,QACE,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAAA,IACN,CAAC;AAAA,EACH,GAAG,CAAC,aAAa,gBAAgB,eAAe,CAAC;AAEjD,QAAM,sBAAsB,QAAQ,MAAM;AACxC,QAAI,CAAC,UAAW,QAAO,SAAS;AAChC,UAAM,kBAAkB,UAAU;AAAA,MAChC;AAAA,IACF,IAAI,CAAC;AAEL,QAAI;AACF,aAAO,WAAW,eAAe;AAAA,IACnC,SAAS,GAAG;AACV,cAAQ,MAAM,CAAC;AACf,aAAO,SAAS;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,kBAAkB,CAAC,UAA2B;AAClD,0BAAsB,CAAC,SAAS,CAAC,GAAG,MAAM,KAAK,CAAC;AAChD,QAAI,aAAa;AACf,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,oCAAoC,QAAQ,MAAM;AACtD,WAAO,CAAC,GAAG,qBAAqB,GAAG,kBAAkB;AAAA,EACvD,GAAG,CAAC,qBAAqB,kBAAkB,CAAC;AAE5C,QAAM,EAAE,iBAAiB,YAAY,gBAAgB,IAAI;AAAA,IACvD;AAAA,MACE,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,SAAS,mBAAmB;AAAA,IAC9B;AAAA,EACF;AAEA,4CAA0C;AAAA,IACxC;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,6CAA2C;AAAA,IACzC;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AAED,QAAM,SAAS;AAAA,IACb,MACE,gBAAAN;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,OAAO;AAAA,UACL,eAAe,yBACX,uBACE,SACA,SACF;AAAA,UACJ,iBAAiB;AAAA,QACnB;AAAA,QAEA,yBAAyB,EAAE,QAAQ,UAAU;AAAA;AAAA,IAC/C;AAAA,IAEF,CAAC,WAAW,sBAAsB,sBAAsB;AAAA,EAC1D;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,QACL,UAAU;AAAA,QACV,iBAAiB;AAAA,QACjB,UAAU;AAAA,QACV,QAAQ,aACJ,aACA,0BAA0B,CAAC,uBACzB,YACA;AAAA,QACN,WAAW;AAAA,QACX,GAAG;AAAA,MACL;AAAA,MACA,aAAa,CAAC,MAAM;AAClB,YAAI,0BAA0B,CAAC,sBAAsB;AACnD,YAAE,eAAe;AACjB,YAAE,gBAAgB;AAClB;AAAA,QACF;AACA,wBAAgB,CAAC;AAAA,MACnB;AAAA,MACA,oBAAoB,CAAC,MAAM;AACzB,YAAI,0BAA0B,CAAC,sBAAsB;AACnD,YAAE,eAAe;AACjB,YAAE,gBAAgB;AAClB;AAAA,QACF;AAAA,MACF;AAAA,MAEC;AAAA,SAAC,wBAAwB,0BACxB,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,CAAC,MAAM;AACd,gBAAE,eAAe;AACjB,gBAAE,gBAAgB;AAClB,sCAAwB,IAAI;AAAA,YAC9B;AAAA,YACA,OAAO;AAAA,cACL,UAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,gBAAgB;AAAA,cAChB,eAAe;AAAA,YACjB;AAAA,YAEA,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,iBAAiB;AAAA,kBACjB,OAAO;AAAA,kBACP,SAAS;AAAA,kBACT,cAAc;AAAA,kBACd,UAAU;AAAA,kBACV,YAAY;AAAA,kBACZ,eAAe;AAAA,gBACjB;AAAA,gBACD;AAAA;AAAA,YAED;AAAA;AAAA,QACF;AAAA,QAED,kBACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,YACR,SAAS,MAAM,mBAAmB,CAAC,eAAe;AAAA;AAAA,QACpD;AAAA,QAED;AAAA;AAAA;AAAA,EACH;AAEJ;","names":["useEffect","useRef","su","useEffect","useRef","useState","useEffect","su","useEffect","useRef","useState","compose","debug","su","jsx","jsxs","debug","useState","useRef","circuitJson","useEffect"]}
@@ -1,29 +1,50 @@
1
- import { useCallback, useEffect, useState } from "react"
1
+ import { applyEditEventsToManualEditsFile } from "@tscircuit/core"
2
+ import type { CircuitJson } from "circuit-json"
2
3
  import { renderToCircuitJson } from "lib/dev/render-to-circuit-json"
3
- import type { ManualEditEvent } from "lib/types/edit-events"
4
4
  import { SchematicViewer } from "lib/index"
5
- import type { CircuitJson } from "circuit-json"
5
+ import type { ManualEditEvent } from "lib/types/edit-events"
6
+ import { useEffect, useState } from "react"
7
+ import type { ManualEditsFile } from "@tscircuit/props"
6
8
 
7
9
  export default () => {
8
10
  const [editEvents, setEditEvents] = useState<ManualEditEvent[]>([])
9
11
  const [circuitJson, setCircuitJson] = useState<CircuitJson | null>(null)
12
+ const [manualEdits, setManualEdits] = useState<ManualEditsFile>({
13
+ schematic_placements: [{
14
+ center: {
15
+ x: 2,
16
+ y: 3,
17
+ },
18
+ relative_to: "group_center",
19
+ selector: "C1",
20
+ }],
21
+ })
10
22
 
11
- const rerenderCircuitJson = useCallback(() => {
23
+ const rerenderCircuitJson = () => {
12
24
  setCircuitJson(
13
25
  renderToCircuitJson(
14
- <board width="10mm" height="10mm">
15
- <resistor name="R1" resistance={1000} schX={4} />
16
- <capacitor name="C1" capacitance="1uF" schX={-4} />
26
+ <board width="10mm" height="10mm" manualEdits={manualEdits}>
27
+ <resistor name="R1" resistance={1000} />
28
+ <capacitor name="C1" capacitance="1uF" />
17
29
  <trace from=".R1 .pin2" to=".C1 .pin1" />
18
30
  </board>,
19
31
  ) as any,
20
32
  )
21
- }, [])
33
+ }
22
34
 
23
35
  useEffect(() => {
24
36
  rerenderCircuitJson()
25
- }, [])
37
+ },[])
26
38
 
39
+ useEffect(() => {
40
+ // Apply edit events to manual edits for persistence between renders
41
+ const updatedManualEdits = applyEditEventsToManualEditsFile({
42
+ circuitJson: circuitJson ?? [] as any,
43
+ editEvents,
44
+ manualEditsFile: manualEdits,
45
+ })
46
+ setManualEdits(updatedManualEdits)
47
+ }, [editEvents, circuitJson])
27
48
 
28
49
  return (
29
50
  <div style={{ position: "relative", height: "100%" }}>
@@ -48,7 +69,9 @@ export default () => {
48
69
  </button>
49
70
  <button
50
71
  type="button"
51
- onClick={() => setEditEvents([])}
72
+ onClick={() => {
73
+ setEditEvents([])
74
+ }}
52
75
  style={{
53
76
  position: "absolute",
54
77
  top: "16px",
@@ -85,8 +108,9 @@ export default () => {
85
108
  {JSON.stringify(editEvents, null, 2)}
86
109
  </pre>
87
110
  <SchematicViewer
88
- editEvents={editEvents}
89
- onEditEvent={(event) => setEditEvents([...editEvents, event])}
111
+ onEditEvent={(event) => {
112
+ setEditEvents((prev) => [...prev, event])
113
+ }}
90
114
  circuitJson={circuitJson ?? []}
91
115
  containerStyle={{ height: "100%" }}
92
116
  debugGrid
@@ -1,22 +1,22 @@
1
- import { useMouseMatrixTransform } from "use-mouse-matrix-transform"
2
1
  import { convertCircuitJsonToSchematicSvg } from "circuit-to-svg"
3
- import { useMemo, useRef, useState } from "react"
4
- import { EditIcon } from "./EditIcon"
5
- import { useResizeHandling } from "../hooks/use-resize-handling"
6
- import { useComponentDragging } from "../hooks/useComponentDragging"
7
- import type { ManualEditEvent } from "../types/edit-events"
2
+ import { useChangeSchematicComponentLocationsInSvg } from "lib/hooks/useChangeSchematicComponentLocationsInSvg"
3
+ import { useChangeSchematicTracesForMovedComponents } from "lib/hooks/useChangeSchematicTracesForMovedComponents"
4
+ import { enableDebug } from "lib/utils/debug"
5
+ import { useEffect, useMemo, useRef, useState } from "react"
8
6
  import {
9
- identity,
10
7
  fromString,
8
+ identity,
11
9
  toString as transformToString,
12
10
  } from "transformation-matrix"
13
- import { useChangeSchematicComponentLocationsInSvg } from "lib/hooks/useChangeSchematicComponentLocationsInSvg"
14
- import { useChangeSchematicTracesForMovedComponents } from "lib/hooks/useChangeSchematicTracesForMovedComponents"
11
+ import { useMouseMatrixTransform } from "use-mouse-matrix-transform"
12
+ import { useResizeHandling } from "../hooks/use-resize-handling"
13
+ import { useComponentDragging } from "../hooks/useComponentDragging"
14
+ import type { ManualEditEvent } from "../types/edit-events"
15
+ import { EditIcon } from "./EditIcon"
15
16
  import type { CircuitJson } from "circuit-json"
16
- import { enableDebug } from "lib/utils/debug"
17
17
 
18
18
  interface Props {
19
- circuitJson: any[]
19
+ circuitJson: CircuitJson
20
20
  containerStyle?: React.CSSProperties
21
21
  editEvents?: ManualEditEvent[]
22
22
  onEditEvent?: (event: ManualEditEvent) => void
@@ -30,7 +30,7 @@ interface Props {
30
30
  export const SchematicViewer = ({
31
31
  circuitJson,
32
32
  containerStyle,
33
- editEvents = [],
33
+ editEvents: unappliedEditEvents = [],
34
34
  onEditEvent,
35
35
  defaultEditMode = false,
36
36
  debugGrid = false,
@@ -47,6 +47,23 @@ export const SchematicViewer = ({
47
47
  )
48
48
  const svgDivRef = useRef<HTMLDivElement>(null)
49
49
 
50
+ const [internalEditEvents, setInternalEditEvents] = useState<ManualEditEvent[]>([])
51
+ const circuitJsonRef = useRef<CircuitJson>(circuitJson)
52
+
53
+ const getCircuitHash = (circuitJson: CircuitJson) => {
54
+ return `${circuitJson?.length || 0}_${(circuitJson as any)?.editCount || 0}`
55
+ }
56
+
57
+ useEffect(() => {
58
+ const circuitHash = getCircuitHash(circuitJson)
59
+ const circuitHashRef = getCircuitHash(circuitJsonRef.current)
60
+
61
+ if (circuitHash !== circuitHashRef) {
62
+ setInternalEditEvents([])
63
+ circuitJsonRef.current = circuitJson
64
+ }
65
+ }, [circuitJson])
66
+
50
67
  const {
51
68
  ref: containerRef,
52
69
  cancelDrag,
@@ -90,21 +107,32 @@ export const SchematicViewer = ({
90
107
  }
91
108
  }, [svgString])
92
109
 
110
+ const handleEditEvent = (event: ManualEditEvent) => {
111
+ setInternalEditEvents((prev) => [...prev, event])
112
+ if (onEditEvent) {
113
+ onEditEvent(event)
114
+ }
115
+ }
116
+
117
+ const editEventsWithUnappliedEditEvents = useMemo(() => {
118
+ return [...unappliedEditEvents, ...internalEditEvents]
119
+ }, [unappliedEditEvents, internalEditEvents])
120
+
93
121
  const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
94
122
  {
95
- onEditEvent,
123
+ onEditEvent: handleEditEvent,
96
124
  cancelDrag,
97
125
  realToSvgProjection,
98
126
  svgToScreenProjection,
99
127
  circuitJson,
100
- editEvents,
128
+ editEvents: editEventsWithUnappliedEditEvents,
101
129
  enabled: editModeEnabled && isInteractionEnabled,
102
130
  },
103
131
  )
104
132
 
105
133
  useChangeSchematicComponentLocationsInSvg({
106
134
  svgDivRef,
107
- editEvents,
135
+ editEvents: editEventsWithUnappliedEditEvents,
108
136
  realToSvgProjection,
109
137
  svgToScreenProjection,
110
138
  activeEditEvent,
@@ -114,7 +142,7 @@ export const SchematicViewer = ({
114
142
  svgDivRef,
115
143
  circuitJson,
116
144
  activeEditEvent,
117
- editEvents,
145
+ editEvents: editEventsWithUnappliedEditEvents,
118
146
  })
119
147
 
120
148
  const svgDiv = useMemo(
@@ -1,7 +1,8 @@
1
1
  import * as Core from "@tscircuit/core"
2
+ import type { CircuitJson } from "circuit-json"
2
3
 
3
4
  export const renderToCircuitJson = (board: React.ReactElement) => {
4
5
  const circuit = new Core.Circuit()
5
6
  circuit.add(board)
6
- return circuit.getCircuitJson()
7
+ return circuit.getCircuitJson() as CircuitJson
7
8
  }
@@ -54,6 +54,26 @@ export const useComponentDragging = ({
54
54
  const activeEditEventRef =
55
55
  useRef<EditSchematicComponentLocationEventWithElement | null>(null)
56
56
 
57
+ // Store the latest positions of components being tracked
58
+ const componentPositionsRef = useRef<Map<string, {x: number, y: number}>>(new Map())
59
+
60
+ // Update position map with the latest positions from edit events
61
+ useEffect(() => {
62
+ // Process completed edit events to track latest positions
63
+ editEvents.forEach(event => {
64
+ if (
65
+ "edit_event_type" in event &&
66
+ event.edit_event_type === "edit_schematic_component_location" &&
67
+ !event.in_progress
68
+ ) {
69
+ componentPositionsRef.current.set(
70
+ event.schematic_component_id,
71
+ {...event.new_center}
72
+ )
73
+ }
74
+ })
75
+ }, [editEvents])
76
+
57
77
  const handleMouseDown = useCallback(
58
78
  (e: React.MouseEvent) => {
59
79
  if (!enabled) return
@@ -75,19 +95,34 @@ export const useComponentDragging = ({
75
95
  schematic_component_id,
76
96
  )
77
97
  if (!schematic_component) return
78
- const editEventOffset = getComponentOffsetDueToEvents({
79
- editEvents,
80
- schematic_component_id: schematic_component_id,
81
- })
82
-
98
+
83
99
  dragStartPosRef.current = {
84
100
  x: e.clientX,
85
101
  y: e.clientY,
86
102
  }
87
103
 
88
- const current_position = {
89
- x: schematic_component.center.x + editEventOffset.x,
90
- y: schematic_component.center.y + editEventOffset.y,
104
+ // Get the current position of the component
105
+ // Check if we're already tracking this component
106
+ let current_position: {x: number, y: number}
107
+ const trackedPosition = componentPositionsRef.current.get(schematic_component_id)
108
+
109
+ if (trackedPosition) {
110
+ // Use the tracked position from previous edits
111
+ current_position = {...trackedPosition}
112
+ } else {
113
+ // Calculate position based on component data and edit events
114
+ const editEventOffset = getComponentOffsetDueToEvents({
115
+ editEvents,
116
+ schematic_component_id: schematic_component_id,
117
+ })
118
+
119
+ current_position = {
120
+ x: schematic_component.center.x + editEventOffset.x,
121
+ y: schematic_component.center.y + editEventOffset.y,
122
+ }
123
+
124
+ // Store this initial position
125
+ componentPositionsRef.current.set(schematic_component_id, {...current_position})
91
126
  }
92
127
 
93
128
  const newEditEvent: EditSchematicComponentLocationEventWithElement = {
@@ -102,6 +137,7 @@ export const useComponentDragging = ({
102
137
  }
103
138
 
104
139
  activeEditEventRef.current = newEditEvent
140
+ setActiveEditEvent(newEditEvent)
105
141
  },
106
142
  [cancelDrag, enabled, circuitJson, editEvents],
107
143
  )
@@ -140,6 +176,13 @@ export const useComponentDragging = ({
140
176
  ...activeEditEventRef.current,
141
177
  in_progress: false,
142
178
  }
179
+
180
+ // Update our stored position for this component
181
+ componentPositionsRef.current.set(
182
+ finalEvent.schematic_component_id,
183
+ {...finalEvent.new_center}
184
+ )
185
+
143
186
  debug("handleMouseUp calling onEditEvent with new edit event", {
144
187
  newEditEvent: finalEvent,
145
188
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-viewer",
3
- "version": "2.0.14",
3
+ "version": "2.0.15",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -14,13 +14,13 @@
14
14
  "devDependencies": {
15
15
  "@biomejs/biome": "^1.9.4",
16
16
  "@tscircuit/core": "^0.0.362",
17
- "@tscircuit/props": "^0.0.113",
17
+ "@tscircuit/props": "^0.0.172",
18
18
  "@types/bun": "latest",
19
19
  "@types/debug": "^4.1.12",
20
20
  "@types/react": "^19.0.1",
21
21
  "@types/react-dom": "^19.0.2",
22
22
  "@vitejs/plugin-react": "^4.3.4",
23
- "circuit-json": "^0.0.117",
23
+ "circuit-json": "^0.0.154",
24
24
  "circuit-to-svg": "^0.0.96",
25
25
  "react": "18",
26
26
  "react-cosmos": "^6.2.1",