@tscircuit/schematic-viewer 2.0.32 → 2.0.34

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/dist/index.js CHANGED
@@ -523,27 +523,23 @@ var useComponentDragging = ({
523
523
  }
524
524
  });
525
525
  }, [editEvents]);
526
- const handleMouseDown = useCallback(
527
- (e) => {
528
- if (!enabled) return;
529
- const target = e.target;
526
+ const startDrag = useCallback(
527
+ (clientX, clientY, target) => {
528
+ if (!enabled) return false;
530
529
  const componentGroup = target.closest(
531
530
  '[data-circuit-json-type="schematic_component"]'
532
531
  );
533
- if (!componentGroup) return;
532
+ if (!componentGroup) return false;
534
533
  const schematic_component_id = componentGroup.getAttribute(
535
534
  "data-schematic-component-id"
536
535
  );
537
- if (!schematic_component_id) return;
536
+ if (!schematic_component_id) return false;
538
537
  if (cancelDrag) cancelDrag();
539
538
  const schematic_component = su4(circuitJson).schematic_component.get(
540
539
  schematic_component_id
541
540
  );
542
- if (!schematic_component) return;
543
- dragStartPosRef.current = {
544
- x: e.clientX,
545
- y: e.clientY
546
- };
541
+ if (!schematic_component) return false;
542
+ dragStartPosRef.current = { x: clientX, y: clientY };
547
543
  let current_position;
548
544
  const trackedPosition = componentPositionsRef.current.get(
549
545
  schematic_component_id
@@ -575,15 +571,32 @@ var useComponentDragging = ({
575
571
  };
576
572
  activeEditEventRef.current = newEditEvent;
577
573
  setActiveEditEvent(newEditEvent);
574
+ return true;
578
575
  },
579
576
  [cancelDrag, enabled, circuitJson, editEvents]
580
577
  );
581
- const handleMouseMove = useCallback(
578
+ const handleMouseDown = useCallback(
582
579
  (e) => {
580
+ startDrag(e.clientX, e.clientY, e.target);
581
+ },
582
+ [startDrag]
583
+ );
584
+ const handleTouchStart = useCallback(
585
+ (e) => {
586
+ if (e.touches.length !== 1) return;
587
+ const touch = e.touches[0];
588
+ if (startDrag(touch.clientX, touch.clientY, e.target)) {
589
+ e.preventDefault();
590
+ }
591
+ },
592
+ [startDrag]
593
+ );
594
+ const updateDragPosition = useCallback(
595
+ (clientX, clientY) => {
583
596
  if (!activeEditEventRef.current || !dragStartPosRef.current) return;
584
597
  const screenDelta = {
585
- x: e.clientX - dragStartPosRef.current.x,
586
- y: e.clientY - dragStartPosRef.current.y
598
+ x: clientX - dragStartPosRef.current.x,
599
+ y: clientY - dragStartPosRef.current.y
587
600
  };
588
601
  const mmDelta = {
589
602
  x: screenDelta.x / realToScreenProjection.a,
@@ -606,7 +619,20 @@ var useComponentDragging = ({
606
619
  },
607
620
  [realToScreenProjection, snapToGrid]
608
621
  );
609
- const handleMouseUp = useCallback(() => {
622
+ const handleMouseMove = useCallback(
623
+ (e) => updateDragPosition(e.clientX, e.clientY),
624
+ [updateDragPosition]
625
+ );
626
+ const handleTouchMove = useCallback(
627
+ (e) => {
628
+ if (e.touches.length !== 1 || !activeEditEventRef.current) return;
629
+ e.preventDefault();
630
+ const touch = e.touches[0];
631
+ updateDragPosition(touch.clientX, touch.clientY);
632
+ },
633
+ [updateDragPosition]
634
+ );
635
+ const endDrag = useCallback(() => {
610
636
  if (!activeEditEventRef.current) return;
611
637
  const finalEvent = {
612
638
  ...activeEditEventRef.current,
@@ -615,7 +641,7 @@ var useComponentDragging = ({
615
641
  componentPositionsRef.current.set(finalEvent.schematic_component_id, {
616
642
  ...finalEvent.new_center
617
643
  });
618
- debug2("handleMouseUp calling onEditEvent with new edit event", {
644
+ debug2("endDrag calling onEditEvent with new edit event", {
619
645
  newEditEvent: finalEvent
620
646
  });
621
647
  if (onEditEvent) onEditEvent(finalEvent);
@@ -623,16 +649,23 @@ var useComponentDragging = ({
623
649
  dragStartPosRef.current = null;
624
650
  setActiveEditEvent(null);
625
651
  }, [onEditEvent]);
652
+ const handleMouseUp = useCallback(() => endDrag(), [endDrag]);
653
+ const handleTouchEnd = useCallback(() => endDrag(), [endDrag]);
626
654
  useEffect5(() => {
627
655
  window.addEventListener("mousemove", handleMouseMove);
628
656
  window.addEventListener("mouseup", handleMouseUp);
657
+ window.addEventListener("touchmove", handleTouchMove, { passive: false });
658
+ window.addEventListener("touchend", handleTouchEnd);
629
659
  return () => {
630
660
  window.removeEventListener("mousemove", handleMouseMove);
631
661
  window.removeEventListener("mouseup", handleMouseUp);
662
+ window.removeEventListener("touchmove", handleTouchMove);
663
+ window.removeEventListener("touchend", handleTouchEnd);
632
664
  };
633
- }, [handleMouseMove, handleMouseUp]);
665
+ }, [handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
634
666
  return {
635
667
  handleMouseDown,
668
+ handleTouchStart,
636
669
  isDragging: !!activeEditEventRef.current,
637
670
  activeEditEvent
638
671
  };
@@ -655,10 +688,15 @@ var EditIcon = ({
655
688
  onClick,
656
689
  active
657
690
  }) => {
691
+ const handleInteraction = (e) => {
692
+ e.preventDefault();
693
+ onClick();
694
+ };
658
695
  return /* @__PURE__ */ jsx(
659
696
  "div",
660
697
  {
661
- onClick,
698
+ onClick: handleInteraction,
699
+ onTouchEnd: handleInteraction,
662
700
  style: {
663
701
  position: "absolute",
664
702
  top: "16px",
@@ -699,10 +737,15 @@ var GridIcon = ({
699
737
  onClick,
700
738
  active
701
739
  }) => {
740
+ const handleInteraction = (e) => {
741
+ e.preventDefault();
742
+ onClick();
743
+ };
702
744
  return /* @__PURE__ */ jsx2(
703
745
  "div",
704
746
  {
705
- onClick,
747
+ onClick: handleInteraction,
748
+ onTouchEnd: handleInteraction,
706
749
  style: {
707
750
  position: "absolute",
708
751
  top: "56px",
@@ -740,10 +783,15 @@ var ViewMenuIcon = ({
740
783
  onClick,
741
784
  active
742
785
  }) => {
786
+ const handleInteraction = (e) => {
787
+ e.preventDefault();
788
+ onClick();
789
+ };
743
790
  return /* @__PURE__ */ jsx3(
744
791
  "div",
745
792
  {
746
- onClick,
793
+ onClick: handleInteraction,
794
+ onTouchEnd: handleInteraction,
747
795
  style: {
748
796
  position: "absolute",
749
797
  top: "16px",
@@ -821,6 +869,10 @@ var ViewMenu = ({
821
869
  "div",
822
870
  {
823
871
  onClick: onClose,
872
+ onTouchEnd: (e) => {
873
+ e.preventDefault();
874
+ onClose();
875
+ },
824
876
  style: {
825
877
  position: "absolute",
826
878
  inset: 0,
@@ -853,6 +905,12 @@ var ViewMenu = ({
853
905
  onToggleGroups(!showGroups);
854
906
  }
855
907
  },
908
+ onTouchEnd: (e) => {
909
+ e.preventDefault();
910
+ if (hasGroups) {
911
+ onToggleGroups(!showGroups);
912
+ }
913
+ },
856
914
  style: {
857
915
  padding: "8px 12px",
858
916
  cursor: hasGroups ? "pointer" : "not-allowed",
@@ -1747,18 +1805,21 @@ var SchematicViewer = ({
1747
1805
  const editEventsWithUnappliedEditEvents = useMemo3(() => {
1748
1806
  return [...unappliedEditEvents, ...internalEditEvents];
1749
1807
  }, [unappliedEditEvents, internalEditEvents]);
1750
- const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
1751
- {
1752
- onEditEvent: handleEditEvent,
1753
- cancelDrag,
1754
- realToSvgProjection,
1755
- svgToScreenProjection,
1756
- circuitJson,
1757
- editEvents: editEventsWithUnappliedEditEvents,
1758
- enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
1759
- snapToGrid
1760
- }
1761
- );
1808
+ const {
1809
+ handleMouseDown,
1810
+ handleTouchStart: handleComponentTouchStart,
1811
+ isDragging,
1812
+ activeEditEvent
1813
+ } = useComponentDragging({
1814
+ onEditEvent: handleEditEvent,
1815
+ cancelDrag,
1816
+ realToSvgProjection,
1817
+ svgToScreenProjection,
1818
+ circuitJson,
1819
+ editEvents: editEventsWithUnappliedEditEvents,
1820
+ enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
1821
+ snapToGrid
1822
+ });
1762
1823
  useChangeSchematicComponentLocationsInSvg({
1763
1824
  svgDivRef,
1764
1825
  editEvents: editEventsWithUnappliedEditEvents,
@@ -1787,10 +1848,22 @@ var SchematicViewer = ({
1787
1848
  pointerEvents: clickToInteractEnabled ? isInteractionEnabled ? "auto" : "none" : "auto",
1788
1849
  transformOrigin: "0 0"
1789
1850
  },
1851
+ onTouchStart: (e) => {
1852
+ if (editModeEnabled && isInteractionEnabled && !showSpiceOverlay) {
1853
+ handleComponentTouchStart(e);
1854
+ }
1855
+ },
1790
1856
  dangerouslySetInnerHTML: { __html: svgString }
1791
1857
  }
1792
1858
  ),
1793
- [svgString, isInteractionEnabled, clickToInteractEnabled]
1859
+ [
1860
+ svgString,
1861
+ isInteractionEnabled,
1862
+ clickToInteractEnabled,
1863
+ editModeEnabled,
1864
+ showSpiceOverlay,
1865
+ handleComponentTouchStart
1866
+ ]
1794
1867
  );
1795
1868
  return /* @__PURE__ */ jsxs6(
1796
1869
  "div",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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/hooks/useSchematicGroupsOverlay.ts","../lib/utils/debug.ts","../lib/hooks/use-resize-handling.ts","../lib/hooks/useComponentDragging.ts","../lib/utils/z-index-map.ts","../lib/components/EditIcon.tsx","../lib/components/GridIcon.tsx","../lib/components/ViewMenuIcon.tsx","../lib/components/ViewMenu.tsx","../lib/components/SpiceIcon.tsx","../lib/components/SpiceSimulationIcon.tsx","../lib/components/SpicePlot.tsx","../lib/components/SpiceSimulationOverlay.tsx","../lib/hooks/useSpiceSimulation.ts","../lib/workers/spice-simulation.worker.blob.js","../lib/utils/spice-utils.ts"],"sourcesContent":["import {\n convertCircuitJsonToSchematicSvg,\n type ColorOverrides,\n} from \"circuit-to-svg\"\nimport { useChangeSchematicComponentLocationsInSvg } from \"lib/hooks/useChangeSchematicComponentLocationsInSvg\"\nimport { useChangeSchematicTracesForMovedComponents } from \"lib/hooks/useChangeSchematicTracesForMovedComponents\"\nimport { useSchematicGroupsOverlay } from \"lib/hooks/useSchematicGroupsOverlay\"\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 { GridIcon } from \"./GridIcon\"\nimport { ViewMenuIcon } from \"./ViewMenuIcon\"\nimport { ViewMenu } from \"./ViewMenu\"\nimport type { CircuitJson } from \"circuit-json\"\nimport { SpiceSimulationIcon } from \"./SpiceSimulationIcon\"\nimport { SpiceSimulationOverlay } from \"./SpiceSimulationOverlay\"\nimport { zIndexMap } from \"../utils/z-index-map\"\nimport { useSpiceSimulation } from \"../hooks/useSpiceSimulation\"\nimport { getSpiceFromCircuitJson } from \"../utils/spice-utils\"\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 colorOverrides?: ColorOverrides\n spiceSimulationEnabled?: 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 colorOverrides,\n spiceSimulationEnabled = false,\n}: Props) => {\n if (debug) {\n enableDebug()\n }\n const [showSpiceOverlay, setShowSpiceOverlay] = useState(false)\n const [spiceSimOptions, setSpiceSimOptions] = useState({\n showVoltage: true,\n showCurrent: false,\n startTime: 0, // in ms\n duration: 20, // in ms\n })\n\n const getCircuitHash = (circuitJson: CircuitJson) => {\n return `${circuitJson?.length || 0}_${(circuitJson as any)?.editCount || 0}`\n }\n\n const circuitJsonKey = useMemo(\n () => getCircuitHash(circuitJson),\n [circuitJson],\n )\n\n const spiceString = useMemo(() => {\n if (!spiceSimulationEnabled) return null\n try {\n return getSpiceFromCircuitJson(circuitJson, spiceSimOptions)\n } catch (e) {\n console.error(\"Failed to generate SPICE string\", e)\n return null\n }\n }, [\n circuitJsonKey,\n spiceSimulationEnabled,\n spiceSimOptions.startTime,\n spiceSimOptions.duration,\n ])\n\n const {\n plotData,\n nodes,\n isLoading: isSpiceSimLoading,\n error: spiceSimError,\n } = useSpiceSimulation(spiceString)\n\n const [editModeEnabled, setEditModeEnabled] = useState(defaultEditMode)\n const [snapToGrid, setSnapToGrid] = useState(true)\n const [isInteractionEnabled, setIsInteractionEnabled] = useState<boolean>(\n !clickToInteractEnabled,\n )\n const [showViewMenu, setShowViewMenu] = useState(false)\n const [showSchematicGroups, setShowSchematicGroups] = useState(false)\n const svgDivRef = useRef<HTMLDivElement>(null)\n const touchStartRef = useRef<{ x: number; y: number } | null>(null)\n\n const handleTouchStart = (e: React.TouchEvent) => {\n const touch = e.touches[0]\n touchStartRef.current = {\n x: touch.clientX,\n y: touch.clientY,\n }\n }\n\n const handleTouchEnd = (e: React.TouchEvent) => {\n const touch = e.changedTouches[0]\n const start = touchStartRef.current\n if (!start) return\n\n const deltaX = Math.abs(touch.clientX - start.x)\n const deltaY = Math.abs(touch.clientY - start.y)\n\n if (deltaX < 10 && deltaY < 10) {\n e.preventDefault()\n setIsInteractionEnabled(true)\n }\n\n touchStartRef.current = null\n }\n\n const [internalEditEvents, setInternalEditEvents] = useState<\n ManualEditEvent[]\n >([])\n const circuitJsonRef = useRef<CircuitJson>(circuitJson)\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 && !showSpiceOverlay,\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 colorOverrides,\n })\n }, [circuitJsonKey, containerWidth, containerHeight])\n\n const containerBackgroundColor = useMemo(() => {\n const match = svgString.match(\n /<svg[^>]*style=\"[^\"]*background-color:\\s*([^;\\\"]+)/i,\n )\n return match?.[1] ?? \"transparent\"\n }, [svgString])\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 && !showSpiceOverlay,\n snapToGrid,\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 // Add group overlays when enabled\n useSchematicGroupsOverlay({\n svgDivRef,\n circuitJson,\n circuitJsonKey,\n showGroups: showSchematicGroups,\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: containerBackgroundColor,\n overflow: \"hidden\",\n cursor: showSpiceOverlay\n ? \"auto\"\n : isDragging\n ? \"grabbing\"\n : clickToInteractEnabled && !isInteractionEnabled\n ? \"pointer\"\n : \"grab\",\n minHeight: \"300px\",\n ...containerStyle,\n }}\n onWheelCapture={(e) => {\n if (showSpiceOverlay) {\n e.stopPropagation()\n }\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 onTouchStart={(e) => {\n if (showSpiceOverlay) return\n handleTouchStart(e)\n }}\n onTouchEnd={(e) => {\n if (showSpiceOverlay) return\n handleTouchEnd(e)\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: zIndexMap.clickToInteractOverlay,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"all\",\n touchAction: \"pan-x pan-y pinch-zoom\",\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 {typeof window !== \"undefined\" &&\n (\"ontouchstart\" in window || navigator.maxTouchPoints > 0)\n ? \"Touch to Interact\"\n : \"Click to Interact\"}\n </div>\n </div>\n )}\n <ViewMenuIcon\n active={showViewMenu}\n onClick={() => setShowViewMenu(!showViewMenu)}\n />\n {editingEnabled && (\n <EditIcon\n active={editModeEnabled}\n onClick={() => setEditModeEnabled(!editModeEnabled)}\n />\n )}\n {editingEnabled && editModeEnabled && (\n <GridIcon\n active={snapToGrid}\n onClick={() => setSnapToGrid(!snapToGrid)}\n />\n )}\n <ViewMenu\n circuitJson={circuitJson}\n circuitJsonKey={circuitJsonKey}\n isVisible={showViewMenu}\n onClose={() => setShowViewMenu(false)}\n showGroups={showSchematicGroups}\n onToggleGroups={setShowSchematicGroups}\n />\n {spiceSimulationEnabled && (\n <SpiceSimulationIcon onClick={() => setShowSpiceOverlay(true)} />\n )}\n {showSpiceOverlay && (\n <SpiceSimulationOverlay\n spiceString={spiceString}\n onClose={() => setShowSpiceOverlay(false)}\n plotData={plotData}\n nodes={nodes}\n isLoading={isSpiceSimLoading}\n error={spiceSimError}\n simOptions={spiceSimOptions}\n onSimOptionsChange={setSpiceSimOptions}\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 { useEffect } from \"react\"\nimport { su } from \"@tscircuit/soup-util\"\nimport type { CircuitJson } from \"circuit-json\"\n\ninterface UseSchematicGroupsOverlayOptions {\n svgDivRef: React.RefObject<HTMLDivElement | null>\n circuitJson: CircuitJson\n circuitJsonKey: string\n showGroups: boolean\n}\n\nconst GROUP_COLORS = [\n \"#8B0000\", // Dark Red\n \"#2F4F4F\", // Dark Slate Gray\n \"#191970\", // Midnight Blue\n \"#006400\", // Dark Green\n \"#FF4500\", // Dark Orange\n \"#800080\", // Purple\n \"#2E8B57\", // Sea Green\n \"#B8860B\", // Dark Goldenrod\n \"#C71585\", // Medium Violet Red\n \"#008B8B\", // Dark Cyan\n]\n\nexport const useSchematicGroupsOverlay = (\n options: UseSchematicGroupsOverlayOptions,\n) => {\n const { svgDivRef, circuitJson, circuitJsonKey, showGroups } = options\n\n useEffect(() => {\n if (\n !svgDivRef.current ||\n !showGroups ||\n !circuitJson ||\n circuitJson.length === 0\n ) {\n if (svgDivRef.current) {\n const existingOverlays = svgDivRef.current.querySelectorAll(\n \".schematic-group-overlay\",\n )\n existingOverlays.forEach((overlay) => overlay.remove())\n }\n return\n }\n\n const svg = svgDivRef.current.querySelector(\"svg\")\n if (!svg) {\n return\n }\n\n const existingOverlays = svg.querySelectorAll(\".schematic-group-overlay\")\n existingOverlays.forEach((overlay) => overlay.remove())\n\n try {\n const sourceGroups =\n su(circuitJson)\n .source_group?.list()\n .filter((x) => !!!x.is_subcircuit) || []\n const schematicComponents =\n su(circuitJson).schematic_component?.list() || []\n\n const sourceGroupHierarchy = new Map<string, string[]>()\n sourceGroups.forEach((group) => {\n const groupWithParent = group as any\n if (groupWithParent.parent_source_group_id) {\n const children =\n sourceGroupHierarchy.get(groupWithParent.parent_source_group_id) ||\n []\n children.push(group.source_group_id)\n sourceGroupHierarchy.set(\n groupWithParent.parent_source_group_id,\n children,\n )\n }\n })\n\n const getAllDescendantSourceGroups = (\n sourceGroupId: string,\n ): string[] => {\n const descendants: string[] = []\n const children = sourceGroupHierarchy.get(sourceGroupId) || []\n for (const child of children) {\n descendants.push(child)\n descendants.push(...getAllDescendantSourceGroups(child))\n }\n return descendants\n }\n\n const getGroupDepthLevel = (sourceGroupId: string): number => {\n const groupWithParent = sourceGroups.find(\n (g) => g.source_group_id === sourceGroupId,\n ) as any\n if (!groupWithParent?.parent_source_group_id) {\n return 0\n }\n return 1 + getGroupDepthLevel(groupWithParent.parent_source_group_id)\n }\n\n const hasMeaningfulGroups =\n sourceGroups.length > 0 &&\n sourceGroups.some((group) => group.name && group.name.trim() !== \"\")\n\n let groupsToRender: Array<{\n id: string\n name: string\n components: any[]\n color: string\n depthLevel: number\n hasChildren: boolean\n sourceGroupId?: string\n }> = []\n\n if (hasMeaningfulGroups) {\n const groupMap = new Map<string, any[]>()\n\n for (const comp of schematicComponents) {\n const sourceComp = su(circuitJson).source_component.get(\n comp.source_component_id,\n )\n if (sourceComp?.source_group_id) {\n if (!groupMap.has(sourceComp.source_group_id)) {\n groupMap.set(sourceComp.source_group_id, [])\n }\n groupMap.get(sourceComp.source_group_id)!.push(comp)\n }\n }\n\n sourceGroups.forEach((group, index) => {\n let groupComponents = groupMap.get(group.source_group_id) || []\n\n const descendantGroups = getAllDescendantSourceGroups(\n group.source_group_id,\n )\n for (const descendantGroupId of descendantGroups) {\n const descendantComponents = groupMap.get(descendantGroupId) || []\n groupComponents = [...groupComponents, ...descendantComponents]\n }\n\n if (groupComponents.length > 0) {\n const depthLevel = getGroupDepthLevel(group.source_group_id)\n const hasChildren =\n getAllDescendantSourceGroups(group.source_group_id).length > 0\n\n if (group.name?.startsWith(\"unnamed_board\")) return\n groupsToRender.push({\n id: group.source_group_id,\n name: group.name || `Group ${index + 1}`,\n components: groupComponents,\n color: GROUP_COLORS[index % GROUP_COLORS.length],\n depthLevel,\n hasChildren,\n sourceGroupId: group.source_group_id,\n })\n }\n })\n }\n // else {\n // const componentTypeGroups = new Map<string, any[]>()\n\n // for (const comp of schematicComponents) {\n // const sourceComp = su(circuitJson).source_component.get(comp.source_component_id)\n // if (sourceComp) {\n // const componentType = sourceComp.ftype || \"other\"\n // if (!componentTypeGroups.has(componentType)) {\n // componentTypeGroups.set(componentType, [])\n // }\n // componentTypeGroups.get(componentType)!.push(comp)\n // }\n // }\n // // groupsToRender = Array.from(componentTypeGroups.entries()).map(\n // // ([type, components], index) => ({\n // // id: `type_${type}`,\n // // name: `${type.charAt(0).toUpperCase() + type.slice(1)}s`,\n // // components,\n // // color: GROUP_COLORS[index % GROUP_COLORS.length],\n // // depthLevel: 0,\n // // hasChildren: false,\n // // }),\n // // )\n // }\n\n const viewBox = svg.viewBox.baseVal\n const svgRect = svg.getBoundingClientRect()\n const scale =\n Math.min(\n svgRect.width / viewBox.width,\n svgRect.height / viewBox.height,\n ) || 1\n\n groupsToRender.sort((a, b) => a.depthLevel - b.depthLevel)\n\n groupsToRender.forEach((group) => {\n if (group.components.length === 0) return\n\n const groupBounds = calculateGroupBounds(group.components, svg)\n if (!groupBounds) return\n\n const basePadding = Math.max(8, Math.min(25, 15 / Math.max(scale, 0.3)))\n const hierarchyPadding = group.hasChildren ? basePadding * 0.6 : 0\n const totalPadding = basePadding + hierarchyPadding\n\n const baseStrokeWidth = Math.max(1, 2 / Math.max(scale, 0.5))\n const strokeWidth =\n group.depthLevel === 0 ? baseStrokeWidth : baseStrokeWidth * 0.7\n\n const baseDashSize = Math.max(4, 8 / Math.max(scale, 0.5))\n const dashMultiplier = group.hasChildren ? 1.3 : 1\n const dashSize = baseDashSize * dashMultiplier\n const gapSize = dashSize * 0.5\n\n const groupOverlay = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"rect\",\n )\n groupOverlay.setAttribute(\"class\", \"schematic-group-overlay\")\n groupOverlay.setAttribute(\n \"x\",\n (groupBounds.minX - totalPadding).toString(),\n )\n groupOverlay.setAttribute(\n \"y\",\n (groupBounds.minY - totalPadding).toString(),\n )\n groupOverlay.setAttribute(\n \"width\",\n (groupBounds.maxX - groupBounds.minX + totalPadding * 2).toString(),\n )\n groupOverlay.setAttribute(\n \"height\",\n (groupBounds.maxY - groupBounds.minY + totalPadding * 2).toString(),\n )\n groupOverlay.setAttribute(\"fill\", \"none\")\n groupOverlay.setAttribute(\"stroke\", group.color)\n groupOverlay.setAttribute(\"stroke-width\", strokeWidth.toString())\n groupOverlay.setAttribute(\"stroke-dasharray\", `${dashSize},${gapSize}`)\n groupOverlay.setAttribute(\"opacity\", \"0.8\")\n groupOverlay.setAttribute(\"rx\", \"4\")\n groupOverlay.setAttribute(\"ry\", \"4\")\n\n const baseFontSize = Math.max(\n 6,\n Math.min(20, 14 / Math.max(scale, 0.2)),\n )\n const fontSizeReduction =\n group.depthLevel === 0 || group.depthLevel === 1\n ? 0\n : group.depthLevel * 0.2\n const fontSize = baseFontSize * (1 - fontSizeReduction)\n\n const labelPadding = Math.max(1, fontSize * 0.2)\n const labelText = group.name\n\n const tempText = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"text\",\n )\n tempText.setAttribute(\"font-size\", fontSize.toString())\n tempText.setAttribute(\"font-family\", \"Arial, sans-serif\")\n tempText.textContent = labelText\n svg.appendChild(tempText)\n const textBBox = tempText.getBBox()\n svg.removeChild(tempText)\n\n const labelWidth = textBBox.width + labelPadding * 2\n const labelHeight = fontSize + labelPadding * 2\n const labelX = groupBounds.minX - totalPadding\n const labelY = groupBounds.minY - totalPadding - labelHeight\n\n const labelBg = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"rect\",\n )\n labelBg.setAttribute(\"class\", \"schematic-group-overlay\")\n labelBg.setAttribute(\"x\", labelX.toString())\n labelBg.setAttribute(\"y\", (labelY - labelHeight).toString())\n labelBg.setAttribute(\"width\", labelWidth.toString())\n labelBg.setAttribute(\"height\", labelHeight.toString())\n labelBg.setAttribute(\"fill\", \"transparent\")\n labelBg.setAttribute(\"rx\", \"3\")\n labelBg.setAttribute(\"ry\", \"3\")\n\n const groupLabel = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"text\",\n )\n groupLabel.setAttribute(\"class\", \"schematic-group-overlay\")\n groupLabel.setAttribute(\"x\", (labelX + labelPadding).toString())\n groupLabel.setAttribute(\n \"y\",\n (labelY + labelHeight - labelPadding).toString(),\n )\n groupLabel.setAttribute(\"fill\", group.color)\n groupLabel.setAttribute(\"font-size\", fontSize.toString())\n groupLabel.setAttribute(\"font-family\", \"Arial, sans-serif\")\n groupLabel.setAttribute(\n \"font-weight\",\n group.depthLevel === 0 ? \"600\" : \"500\",\n )\n groupLabel.setAttribute(\"stroke\", group.color)\n groupLabel.setAttribute(\n \"stroke-width\",\n Math.max(0.2, fontSize * 0.02).toString(),\n )\n groupLabel.textContent = labelText\n\n svg.appendChild(groupOverlay)\n svg.appendChild(labelBg)\n svg.appendChild(groupLabel)\n })\n } catch (error) {\n console.error(\"Error creating group overlays:\", error)\n }\n }, [svgDivRef, circuitJsonKey, showGroups])\n}\n\nfunction calculateGroupBounds(components: any[], svg: SVGElement) {\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity\n\n for (const component of components) {\n let componentElement = svg.querySelector(\n `g[data-schematic-component-id=\"${component.schematic_component_id}\"]`,\n )\n\n if (!componentElement) {\n componentElement = svg.querySelector(\n `[data-schematic-component-id=\"${component.schematic_component_id}\"]`,\n )\n }\n\n if (componentElement) {\n const bbox = (componentElement as SVGGraphicsElement).getBBox()\n minX = Math.min(minX, bbox.x)\n minY = Math.min(minY, bbox.y)\n maxX = Math.max(maxX, bbox.x + bbox.width)\n maxY = Math.max(maxY, bbox.y + bbox.height)\n }\n }\n\n if (minX === Infinity) {\n return null\n }\n\n const bounds = { minX, minY, maxX, maxY }\n return bounds\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 { type Matrix, compose } 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 snapToGrid = 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 snapToGrid?: 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 }>>(\n new Map(),\n )\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(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(\n schematic_component_id,\n )\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, {\n ...current_position,\n })\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 let newCenter = {\n x: activeEditEventRef.current.original_center.x + mmDelta.x,\n y: activeEditEventRef.current.original_center.y + mmDelta.y,\n }\n if (snapToGrid) {\n const snap = (v: number) => Math.round(v * 10) / 10\n newCenter = { x: snap(newCenter.x), y: snap(newCenter.y) }\n }\n\n const newEditEvent = {\n ...activeEditEventRef.current,\n new_center: newCenter,\n }\n\n activeEditEventRef.current = newEditEvent\n setActiveEditEvent(newEditEvent)\n },\n [realToScreenProjection, snapToGrid],\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(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 zIndexMap = {\n schematicEditIcon: 50,\n schematicGridIcon: 49,\n spiceSimulationIcon: 51,\n viewMenuIcon: 48,\n viewMenu: 55,\n viewMenuBackdrop: 54,\n clickToInteractOverlay: 100,\n}\n","import { zIndexMap } from \"../utils/z-index-map\"\n\nexport 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: \"64px\",\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: zIndexMap.schematicEditIcon,\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 { zIndexMap } from \"../utils/z-index-map\"\n\nexport const GridIcon = ({\n onClick,\n active,\n}: { onClick: () => void; active: boolean }) => {\n return (\n <div\n onClick={onClick}\n style={{\n position: \"absolute\",\n top: \"56px\",\n right: \"64px\",\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: zIndexMap.schematicGridIcon,\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=\"M3 3h7v7H3zM14 3h7v7h-7zM3 14h7v7H3zM14 14h7v7h-7z\" />\n </svg>\n </div>\n )\n}\n","import { zIndexMap } from \"../utils/z-index-map\"\n\nexport const ViewMenuIcon = ({\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: zIndexMap.viewMenuIcon,\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 <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </div>\n )\n}\n","import { useMemo } from \"react\"\nimport { su } from \"@tscircuit/soup-util\"\nimport type { CircuitJson } from \"circuit-json\"\nimport { zIndexMap } from \"../utils/z-index-map\"\n\ninterface ViewMenuProps {\n circuitJson: CircuitJson\n circuitJsonKey: string\n isVisible: boolean\n onClose: () => void\n showGroups: boolean\n onToggleGroups: (show: boolean) => void\n}\n\nexport const ViewMenu = ({\n circuitJson,\n circuitJsonKey,\n isVisible,\n onClose,\n showGroups,\n onToggleGroups,\n}: ViewMenuProps) => {\n const hasGroups = useMemo(() => {\n if (!circuitJson || circuitJson.length === 0) return false\n\n try {\n // Check if there are explicit groups\n const sourceGroups = su(circuitJson).source_group?.list() || []\n if (sourceGroups.length > 0) return true\n\n // Check if we can create virtual groups by component type\n const schematicComponents =\n su(circuitJson).schematic_component?.list() || []\n if (schematicComponents.length > 1) {\n const componentTypes = new Set()\n for (const comp of schematicComponents) {\n const sourceComp = su(circuitJson).source_component.get(\n comp.source_component_id,\n )\n if (sourceComp?.ftype) {\n componentTypes.add(sourceComp.ftype)\n }\n }\n return componentTypes.size > 1 // Only show if there are multiple types\n }\n\n return false\n } catch (error) {\n console.error(\"Error checking for groups:\", error)\n return false\n }\n }, [circuitJsonKey])\n\n if (!isVisible) return null\n\n return (\n <>\n {/* Backdrop */}\n <div\n onClick={onClose}\n style={{\n position: \"absolute\",\n inset: 0,\n backgroundColor: \"transparent\",\n zIndex: zIndexMap.viewMenuBackdrop,\n }}\n />\n\n {/* Menu */}\n <div\n style={{\n position: \"absolute\",\n top: \"56px\",\n right: \"16px\",\n backgroundColor: \"#ffffff\",\n color: \"#000000\",\n border: \"1px solid #ccc\",\n borderRadius: \"4px\",\n boxShadow: \"0 4px 12px rgba(0,0,0,0.1)\",\n minWidth: \"200px\",\n zIndex: zIndexMap.viewMenu,\n }}\n >\n {/* Groups Toggle Option */}\n <div\n onClick={() => {\n if (hasGroups) {\n onToggleGroups(!showGroups)\n }\n }}\n style={{\n padding: \"8px 12px\",\n cursor: hasGroups ? \"pointer\" : \"not-allowed\",\n opacity: hasGroups ? 1 : 0.5,\n fontSize: \"13px\",\n color: \"#000000\",\n fontFamily: \"sans-serif\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n onMouseEnter={(e) => {\n if (hasGroups) {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\"\n }\n }}\n onMouseLeave={(e) => {\n if (hasGroups) {\n e.currentTarget.style.backgroundColor = \"transparent\"\n }\n }}\n >\n <div\n style={{\n width: \"16px\",\n height: \"16px\",\n border: \"2px solid #000\",\n borderRadius: \"2px\",\n backgroundColor: \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"10px\",\n fontWeight: \"bold\",\n }}\n >\n {showGroups && \"✓\"}\n </div>\n View Schematic Groups\n </div>\n\n {!hasGroups && (\n <div\n style={{\n padding: \"8px 12px\",\n fontSize: \"11px\",\n color: \"#666\",\n fontStyle: \"italic\",\n }}\n >\n No groups found in this schematic\n </div>\n )}\n </div>\n </>\n )\n}\n","export const SpiceIcon = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M3 12h2.5l2.5-9 4 18 4-9h5.5\" />\n </svg>\n)\n","import { SpiceIcon } from \"./SpiceIcon\"\nimport { zIndexMap } from \"../utils/z-index-map\"\n\nexport const SpiceSimulationIcon = ({\n onClick,\n}: {\n onClick: () => void\n}) => {\n return (\n <div\n onClick={onClick}\n style={{\n position: \"absolute\",\n top: \"16px\",\n right: \"112px\",\n backgroundColor: \"#fff\",\n color: \"#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: zIndexMap.spiceSimulationIcon,\n }}\n >\n <SpiceIcon />\n </div>\n )\n}\n","import { useMemo } from \"react\"\nimport {\n Chart as ChartJS,\n type ChartOptions,\n CategoryScale,\n LinearScale,\n PointElement,\n LineElement,\n Title,\n Tooltip,\n Legend,\n} from \"chart.js\"\nimport { Line } from \"react-chartjs-2\"\nimport type { PlotPoint } from \"../hooks/useSpiceSimulation\"\n\nChartJS.register(\n CategoryScale,\n LinearScale,\n PointElement,\n LineElement,\n Title,\n Tooltip,\n Legend,\n)\n\nconst colors = [\"#8884d8\", \"#82ca9d\", \"#ffc658\", \"#ff7300\", \"#387908\"]\n\nconst formatTimeWithUnits = (seconds: number) => {\n if (seconds === 0) return \"0s\"\n const absSeconds = Math.abs(seconds)\n\n let unit = \"s\"\n let scale = 1\n if (absSeconds < 1e-12) {\n unit = \"fs\"\n scale = 1e15\n } else if (absSeconds < 1e-9) {\n unit = \"ps\"\n scale = 1e12\n } else if (absSeconds < 1e-6) {\n unit = \"ns\"\n scale = 1e9\n } else if (absSeconds < 1e-3) {\n unit = \"us\"\n scale = 1e6\n } else if (absSeconds < 1) {\n unit = \"ms\"\n scale = 1e3\n }\n\n return `${parseFloat((seconds * scale).toPrecision(3))}${unit}`\n}\n\nexport const SpicePlot = ({\n plotData,\n nodes,\n isLoading,\n error,\n}: {\n plotData: PlotPoint[]\n nodes: string[]\n isLoading: boolean\n error: string | null\n}) => {\n const yAxisLabel = useMemo(() => {\n const hasVoltage = nodes.some((n) => n.toLowerCase().startsWith(\"v(\"))\n const hasCurrent = nodes.some((n) => n.toLowerCase().startsWith(\"i(\"))\n if (hasVoltage && hasCurrent) return \"Value\"\n if (hasVoltage) return \"Voltage (V)\"\n if (hasCurrent) return \"Current (A)\"\n return \"Value\"\n }, [nodes])\n\n if (isLoading) {\n return (\n <div\n style={{\n height: \"300px\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n Running simulation...\n </div>\n )\n }\n\n if (error) {\n return (\n <div\n style={{\n height: \"300px\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"red\",\n }}\n >\n Error: {error}\n </div>\n )\n }\n\n if (plotData.length === 0) {\n return (\n <div\n style={{\n height: \"300px\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n No data to plot. Check simulation output or SPICE netlist.\n </div>\n )\n }\n\n const chartData = {\n datasets: nodes.map((node, i) => ({\n label: node,\n data: plotData.map((p) => ({\n x: Number(p.name),\n y: p[node] as number,\n })),\n borderColor: colors[i % colors.length],\n backgroundColor: colors[i % colors.length],\n fill: false,\n tension: 0.1,\n })),\n }\n\n const options: ChartOptions<\"line\"> = {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n position: \"top\" as const,\n labels: {\n font: {\n family: \"sans-serif\",\n },\n },\n },\n title: {\n display: false,\n },\n tooltip: {\n callbacks: {\n title: (tooltipItems) => {\n if (tooltipItems.length > 0) {\n const item = tooltipItems[0]\n return formatTimeWithUnits(item.parsed.x)\n }\n return \"\"\n },\n },\n },\n },\n scales: {\n x: {\n type: \"linear\",\n title: {\n display: true,\n text: \"Time\",\n font: {\n family: \"sans-serif\",\n },\n },\n ticks: {\n callback: (value) => formatTimeWithUnits(value as number),\n font: {\n family: \"sans-serif\",\n },\n },\n },\n y: {\n title: {\n display: true,\n text: yAxisLabel,\n font: {\n family: \"sans-serif\",\n },\n },\n ticks: {\n font: {\n family: \"sans-serif\",\n },\n },\n },\n },\n }\n\n return (\n <div style={{ position: \"relative\", height: \"300px\", width: \"100%\" }}>\n <Line options={options} data={chartData} />\n </div>\n )\n}\n","import { SpicePlot } from \"./SpicePlot\"\nimport type { PlotPoint } from \"../hooks/useSpiceSimulation\"\nimport { useEffect, useState } from \"react\"\n\ninterface SpiceSimulationOverlayProps {\n spiceString: string | null\n onClose: () => void\n plotData: PlotPoint[]\n nodes: string[]\n isLoading: boolean\n error: string | null\n simOptions: {\n showVoltage: boolean\n showCurrent: boolean\n startTime: number\n duration: number\n }\n onSimOptionsChange: (\n options: SpiceSimulationOverlayProps[\"simOptions\"],\n ) => void\n}\n\nexport const SpiceSimulationOverlay = ({\n spiceString,\n onClose,\n plotData,\n nodes,\n isLoading,\n error,\n simOptions,\n onSimOptionsChange,\n}: SpiceSimulationOverlayProps) => {\n const [startTimeDraft, setStartTimeDraft] = useState(\n String(simOptions.startTime),\n )\n const [durationDraft, setDurationDraft] = useState(\n String(simOptions.duration),\n )\n\n useEffect(() => {\n setStartTimeDraft(String(simOptions.startTime))\n setDurationDraft(String(simOptions.duration))\n }, [simOptions.startTime, simOptions.duration])\n\n const handleRerun = () => {\n onSimOptionsChange({\n ...simOptions,\n startTime: Number(startTimeDraft),\n duration: Number(durationDraft),\n })\n }\n\n const filteredNodes = nodes.filter((node) => {\n const isVoltage = node.toLowerCase().startsWith(\"v(\")\n const isCurrent = node.toLowerCase().startsWith(\"i(\")\n if (simOptions.showVoltage && isVoltage) return true\n if (simOptions.showCurrent && isCurrent) return true\n return false\n })\n\n return (\n <div\n style={{\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 1002,\n fontFamily: \"sans-serif\",\n }}\n >\n <div\n style={{\n backgroundColor: \"white\",\n padding: \"24px\",\n borderRadius: \"12px\",\n width: \"90%\",\n maxWidth: \"900px\",\n boxShadow: \"0 4px 20px rgba(0, 0, 0, 0.15)\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"24px\",\n borderBottom: \"1px solid #eee\",\n paddingBottom: \"16px\",\n }}\n >\n <h2\n style={{\n margin: 0,\n fontSize: \"22px\",\n fontWeight: 600,\n color: \"#333\",\n }}\n >\n SPICE Simulation\n </h2>\n <button\n onClick={onClose}\n style={{\n background: \"none\",\n border: \"none\",\n fontSize: \"28px\",\n cursor: \"pointer\",\n color: \"#888\",\n padding: 0,\n lineHeight: 1,\n }}\n >\n &times;\n </button>\n </div>\n <div>\n <SpicePlot\n plotData={plotData}\n nodes={filteredNodes}\n isLoading={isLoading}\n error={error}\n />\n </div>\n <div\n style={{\n marginTop: \"16px\",\n padding: \"12px\",\n backgroundColor: \"#f7f7f7\",\n borderRadius: \"6px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"24px\",\n alignItems: \"center\",\n fontSize: \"14px\",\n }}\n >\n <div style={{ display: \"flex\", gap: \"16px\" }}>\n <label\n style={{ display: \"flex\", alignItems: \"center\", gap: \"6px\" }}\n >\n <input\n type=\"checkbox\"\n checked={simOptions.showVoltage}\n onChange={(e) =>\n onSimOptionsChange({\n ...simOptions,\n showVoltage: e.target.checked,\n })\n }\n />\n Voltage\n </label>\n <label\n style={{ display: \"flex\", alignItems: \"center\", gap: \"6px\" }}\n >\n <input\n type=\"checkbox\"\n checked={simOptions.showCurrent}\n onChange={(e) =>\n onSimOptionsChange({\n ...simOptions,\n showCurrent: e.target.checked,\n })\n }\n />\n Current\n </label>\n </div>\n <div style={{ display: \"flex\", gap: \"16px\", alignItems: \"center\" }}>\n <label htmlFor=\"startTime\">Start Time (ms):</label>\n <input\n id=\"startTime\"\n type=\"number\"\n value={startTimeDraft}\n onChange={(e) => setStartTimeDraft(e.target.value)}\n style={{\n width: \"80px\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n border: \"1px solid #ccc\",\n }}\n />\n <label htmlFor=\"duration\">Duration (ms):</label>\n <input\n id=\"duration\"\n type=\"number\"\n value={durationDraft}\n onChange={(e) => setDurationDraft(e.target.value)}\n style={{\n width: \"80px\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n border: \"1px solid #ccc\",\n }}\n />\n <button\n onClick={handleRerun}\n style={{\n padding: \"4px 12px\",\n borderRadius: \"4px\",\n border: \"1px solid #ccc\",\n backgroundColor: \"#f0f0f0\",\n cursor: \"pointer\",\n }}\n >\n Rerun\n </button>\n </div>\n </div>\n <div style={{ marginTop: \"24px\" }}>\n <h3\n style={{\n marginTop: 0,\n marginBottom: \"12px\",\n fontSize: \"18px\",\n fontWeight: 600,\n color: \"#333\",\n }}\n >\n SPICE Netlist\n </h3>\n <pre\n style={{\n backgroundColor: \"#fafafa\",\n padding: \"16px\",\n borderRadius: \"6px\",\n maxHeight: \"150px\",\n overflowY: \"auto\",\n border: \"1px solid #eee\",\n color: \"#333\",\n fontSize: \"13px\",\n fontFamily: \"monospace\",\n }}\n >\n {spiceString}\n </pre>\n </div>\n </div>\n </div>\n )\n}\n","import { useState, useEffect } from \"react\"\nimport type * as EecircuitEngine from \"../types/eecircuit-engine\"\n// @ts-ignore\nimport { getSpiceSimulationWorkerBlobUrl } from \"../workers/spice-simulation.worker.blob.js\"\n\n// Types from eecircuit-engine interface\ntype RealDataType = {\n name: string\n type: string\n values: number[]\n}\ntype ComplexNumber = {\n real: number\n img: number\n}\ntype ComplexDataType = {\n name: string\n type: string\n values: ComplexNumber[]\n}\ntype EecEngineResult =\n | {\n header: string\n numVariables: number\n variableNames: string[]\n numPoints: number\n dataType: \"real\"\n data: RealDataType[]\n }\n | {\n header: string\n numVariables: number\n variableNames: string[]\n numPoints: number\n dataType: \"complex\"\n data: ComplexDataType[]\n }\n\nexport interface PlotPoint {\n name: string // time or sweep variable\n [key: string]: number | string\n}\n\nconst parseEecEngineOutput = (\n result: EecEngineResult,\n): { plotData: PlotPoint[]; nodes: string[] } => {\n const columnData: Record<string, number[]> = {}\n\n if (result.dataType === \"real\") {\n result.data.forEach((col) => {\n columnData[col.name] = col.values\n })\n } else if (result.dataType === \"complex\") {\n result.data.forEach((col) => {\n // For now, plot the real part of complex numbers\n columnData[col.name] = col.values.map((v) => v.real)\n })\n } else {\n throw new Error(\"Unsupported data type in simulation result\")\n }\n\n const timeKey = Object.keys(columnData).find(\n (k) => k.toLowerCase() === \"time\" || k.toLowerCase() === \"frequency\",\n )\n if (!timeKey) {\n throw new Error(\"No time or frequency data in simulation result\")\n }\n const timeValues = columnData[timeKey]\n const probedVariables = Object.keys(columnData).filter((k) => k !== timeKey)\n const plotableNodes = probedVariables\n\n const plotData: PlotPoint[] = timeValues.map((t: number, i: number) => {\n const point: PlotPoint = { name: t.toExponential(2) }\n probedVariables.forEach((variable) => {\n point[variable] = columnData[variable][i]\n })\n return point\n })\n\n return { plotData, nodes: plotableNodes }\n}\n\ntype WorkerMessage =\n | {\n type: \"result\"\n result: EecEngineResult\n }\n | { type: \"error\"; error: string }\n\nexport const useSpiceSimulation = (spiceString: string | null) => {\n const [plotData, setPlotData] = useState<PlotPoint[]>([])\n const [nodes, setNodes] = useState<string[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!spiceString) {\n setIsLoading(false)\n setPlotData([])\n setNodes([])\n setError(null)\n return\n }\n setIsLoading(true)\n setError(null)\n setPlotData([])\n setNodes([])\n\n const workerUrl = getSpiceSimulationWorkerBlobUrl()\n\n if (!workerUrl) {\n setError(\"Could not create SPICE simulation worker.\")\n setIsLoading(false)\n return\n }\n\n const worker = new Worker(workerUrl, { type: \"module\" })\n\n worker.onmessage = (event: MessageEvent<WorkerMessage>) => {\n if (event.data.type === \"result\") {\n try {\n const { plotData: parsedData, nodes: parsedNodes } =\n parseEecEngineOutput(event.data.result)\n setPlotData(parsedData)\n setNodes(parsedNodes)\n } catch (e: any) {\n setError(e.message || \"Failed to parse simulation result\")\n console.error(e)\n }\n } else if (event.data.type === \"error\") {\n setError(event.data.error)\n }\n setIsLoading(false)\n }\n\n worker.onerror = (err) => {\n setError(err.message)\n setIsLoading(false)\n }\n\n worker.postMessage({ spiceString })\n\n return () => {\n worker.terminate()\n }\n }, [spiceString])\n\n return { plotData, nodes, isLoading, error }\n}\n","// This file is generated by scripts/build-worker-blob-url.ts\n// Do not edit this file directly.\n\nconst b64 = \"dmFyIGU9bnVsbCxzPWFzeW5jKCk9Pihhd2FpdCBpbXBvcnQoImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWVjaXJjdWl0LWVuZ2luZUAxLjUuMi8rZXNtIikpLlNpbXVsYXRpb24sYz1hc3luYygpPT57aWYoZSYmZS5pc0luaXRpYWxpemVkKCkpcmV0dXJuO2xldCBpPWF3YWl0IHMoKTtlPW5ldyBpLGF3YWl0IGUuc3RhcnQoKX07c2VsZi5vbm1lc3NhZ2U9YXN5bmMgaT0+e3RyeXtpZihhd2FpdCBjKCksIWUpdGhyb3cgbmV3IEVycm9yKCJTaW11bGF0aW9uIG5vdCBpbml0aWFsaXplZCIpO2xldCB0PWkuZGF0YS5zcGljZVN0cmluZyxhPXQubWF0Y2goL3dyZGF0YVxzKyhcUyspXHMrKC4qKS9pKTtpZihhKXtsZXQgbz1gLnByb2JlICR7YVsyXS50cmltKCkuc3BsaXQoL1xzKy8pLmpvaW4oIiAiKX1gO3Q9dC5yZXBsYWNlKC93cmRhdGEuKi9pLG8pfWVsc2UgaWYoIXQubWF0Y2goL1wucHJvYmUvaSkpdGhyb3cgdC5tYXRjaCgvcGxvdFxzKyguKikvaSk/bmV3IEVycm9yKCJUaGUgJ3Bsb3QnIGNvbW1hbmQgaXMgbm90IHN1cHBvcnRlZCBmb3IgZGF0YSBleHRyYWN0aW9uLiBQbGVhc2UgdXNlICd3cmRhdGEgPGZpbGVuYW1lPiA8dmFyMT4gLi4uJyBvciAnLnByb2JlIDx2YXIxPiAuLi4nIGluc3RlYWQuIik6bmV3IEVycm9yKCJObyAnLnByb2JlJyBvciAnd3JkYXRhJyBjb21tYW5kIGZvdW5kIGluIFNQSUNFIGZpbGUuIFVzZSAnd3JkYXRhIDxmaWxlbmFtZT4gPHZhcjE+IC4uLicgdG8gc3BlY2lmeSBvdXRwdXQuIik7ZS5zZXROZXRMaXN0KHQpO2xldCBuPWF3YWl0IGUucnVuU2ltKCk7c2VsZi5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixyZXN1bHQ6bn0pfWNhdGNoKHQpe3NlbGYucG9zdE1lc3NhZ2Uoe3R5cGU6ImVycm9yIixlcnJvcjp0Lm1lc3NhZ2V9KX19Owo=\";\n\nlet blobUrl = null;\n\nexport const getSpiceSimulationWorkerBlobUrl = () => {\n if (typeof window === \"undefined\") return null;\n if (blobUrl) return blobUrl;\n\n try {\n const blob = new Blob([atob(b64)], { type: \"application/javascript\" });\n blobUrl = URL.createObjectURL(blob);\n return blobUrl;\n } catch (e) {\n console.error(\"Failed to create blob URL for worker\", e);\n return null;\n }\n};\n","import { circuitJsonToSpice } from \"circuit-json-to-spice\"\nimport type { CircuitJson } from \"circuit-json\"\n\nexport interface SpiceSimOptions {\n showVoltage: boolean\n showCurrent: boolean\n startTime: number // in ms\n duration: number // in ms\n}\n\nconst formatSimTime = (seconds: number): string => {\n if (seconds === 0) return \"0\"\n const absSeconds = Math.abs(seconds)\n\n const precision = (v: number) => v.toPrecision(4)\n\n if (absSeconds >= 1) return precision(seconds)\n if (absSeconds >= 1e-3) return `${precision(seconds * 1e3)}m`\n if (absSeconds >= 1e-6) return `${precision(seconds * 1e6)}u`\n if (absSeconds >= 1e-9) return `${precision(seconds * 1e9)}n`\n if (absSeconds >= 1e-12) return `${precision(seconds * 1e12)}p`\n if (absSeconds >= 1e-15) return `${precision(seconds * 1e15)}f`\n\n return seconds.toExponential(3)\n}\n\nexport const getSpiceFromCircuitJson = (\n circuitJson: CircuitJson,\n options?: Partial<SpiceSimOptions>,\n): string => {\n const spiceNetlist = circuitJsonToSpice(circuitJson as any)\n const baseSpiceString = spiceNetlist.toSpiceString()\n\n const lines = baseSpiceString.split(\"\\n\").filter((l) => l.trim() !== \"\")\n const componentLines = lines.filter(\n (l) => !l.startsWith(\"*\") && !l.startsWith(\".\") && l.trim() !== \"\",\n )\n\n const allNodes = new Set<string>()\n const capacitorNodes = new Set<string>()\n const componentNamesToProbeCurrent = new Set<string>()\n\n for (const line of componentLines) {\n const parts = line.trim().split(/\\s+/)\n if (parts.length < 3) continue\n\n const componentName = parts[0]\n const componentType = componentName[0].toUpperCase()\n let nodesOnLine: string[] = []\n\n if ([\"R\", \"C\", \"L\", \"V\", \"I\", \"D\"].includes(componentType)) {\n nodesOnLine = parts.slice(1, 3)\n // Only probe current on voltage sources\n if (componentType === \"V\") {\n componentNamesToProbeCurrent.add(componentName)\n }\n } else if (componentType === \"Q\" && parts.length >= 4) {\n // BJT\n nodesOnLine = parts.slice(1, 4)\n } else if (componentType === \"M\" && parts.length >= 5) {\n // MOSFET\n nodesOnLine = parts.slice(1, 5)\n } else if (componentType === \"X\") {\n // Subcircuit\n // Assume last part is model name, everything in between is a node\n nodesOnLine = parts.slice(1, -1)\n } else {\n continue\n }\n\n nodesOnLine.forEach((node) => allNodes.add(node))\n\n if (componentType === \"C\") {\n nodesOnLine.forEach((node) => capacitorNodes.add(node))\n }\n }\n\n // Do not probe/set IC for ground\n allNodes.delete(\"0\")\n capacitorNodes.delete(\"0\")\n\n const icLines = Array.from(capacitorNodes).map((node) => `.ic V(${node})=0`)\n\n const probes: string[] = []\n const probeVoltages = Array.from(allNodes).map((node) => `V(${node})`)\n probes.push(...probeVoltages)\n const probeCurrents = Array.from(componentNamesToProbeCurrent).map(\n (name) => `I(${name})`,\n )\n probes.push(...probeCurrents)\n\n const probeLine = probes.length > 0 ? `.probe ${probes.join(\" \")}` : \"\"\n\n const tstart_ms = options?.startTime ?? 0\n const duration_ms = options?.duration ?? 20\n const tstart = tstart_ms * 1e-3 // s\n const duration = duration_ms * 1e-3 // s\n\n const tstop = tstart + duration\n const tstep = duration / 50\n const tranLine = `.tran ${formatSimTime(tstep)} ${formatSimTime(\n tstop,\n )} ${formatSimTime(tstart)} UIC`\n\n const endStatement = \".end\"\n const originalLines = baseSpiceString.split(\"\\n\")\n let endIndex = -1\n for (let i = originalLines.length - 1; i >= 0; i--) {\n if (originalLines[i].trim().toLowerCase().startsWith(endStatement)) {\n endIndex = i\n break\n }\n }\n\n const injectionLines = [...icLines, probeLine, tranLine].filter(Boolean)\n\n let finalLines: string[]\n\n if (endIndex !== -1) {\n const beforeEnd = originalLines.slice(0, endIndex)\n const endLineAndAfter = originalLines.slice(endIndex)\n finalLines = [...beforeEnd, ...injectionLines, ...endLineAndAfter]\n } else {\n finalLines = [...originalLines, ...injectionLines, endStatement]\n }\n\n return finalLines.join(\"\\n\")\n}\n"],"mappings":"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","names":["useEffect","useRef","su","useEffect","su","existingOverlays","useEffect","useMemo","useRef","useState","useEffect","su","useEffect","useRef","useState","compose","debug","su","jsx","jsx","jsxs","su","jsx","jsxs","su","jsx","jsx","useMemo","jsx","jsxs","useEffect","useState","jsx","jsxs","useState","useEffect","useState","useEffect","jsx","jsxs","debug","useState","circuitJson","useMemo","useRef","useEffect"]}
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/hooks/useSchematicGroupsOverlay.ts","../lib/utils/debug.ts","../lib/hooks/use-resize-handling.ts","../lib/hooks/useComponentDragging.ts","../lib/utils/z-index-map.ts","../lib/components/EditIcon.tsx","../lib/components/GridIcon.tsx","../lib/components/ViewMenuIcon.tsx","../lib/components/ViewMenu.tsx","../lib/components/SpiceIcon.tsx","../lib/components/SpiceSimulationIcon.tsx","../lib/components/SpicePlot.tsx","../lib/components/SpiceSimulationOverlay.tsx","../lib/hooks/useSpiceSimulation.ts","../lib/workers/spice-simulation.worker.blob.js","../lib/utils/spice-utils.ts"],"sourcesContent":["import {\n convertCircuitJsonToSchematicSvg,\n type ColorOverrides,\n} from \"circuit-to-svg\"\nimport { useChangeSchematicComponentLocationsInSvg } from \"lib/hooks/useChangeSchematicComponentLocationsInSvg\"\nimport { useChangeSchematicTracesForMovedComponents } from \"lib/hooks/useChangeSchematicTracesForMovedComponents\"\nimport { useSchematicGroupsOverlay } from \"lib/hooks/useSchematicGroupsOverlay\"\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 { GridIcon } from \"./GridIcon\"\nimport { ViewMenuIcon } from \"./ViewMenuIcon\"\nimport { ViewMenu } from \"./ViewMenu\"\nimport type { CircuitJson } from \"circuit-json\"\nimport { SpiceSimulationIcon } from \"./SpiceSimulationIcon\"\nimport { SpiceSimulationOverlay } from \"./SpiceSimulationOverlay\"\nimport { zIndexMap } from \"../utils/z-index-map\"\nimport { useSpiceSimulation } from \"../hooks/useSpiceSimulation\"\nimport { getSpiceFromCircuitJson } from \"../utils/spice-utils\"\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 colorOverrides?: ColorOverrides\n spiceSimulationEnabled?: 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 colorOverrides,\n spiceSimulationEnabled = false,\n}: Props) => {\n if (debug) {\n enableDebug()\n }\n const [showSpiceOverlay, setShowSpiceOverlay] = useState(false)\n const [spiceSimOptions, setSpiceSimOptions] = useState({\n showVoltage: true,\n showCurrent: false,\n startTime: 0, // in ms\n duration: 20, // in ms\n })\n\n const getCircuitHash = (circuitJson: CircuitJson) => {\n return `${circuitJson?.length || 0}_${(circuitJson as any)?.editCount || 0}`\n }\n\n const circuitJsonKey = useMemo(\n () => getCircuitHash(circuitJson),\n [circuitJson],\n )\n\n const spiceString = useMemo(() => {\n if (!spiceSimulationEnabled) return null\n try {\n return getSpiceFromCircuitJson(circuitJson, spiceSimOptions)\n } catch (e) {\n console.error(\"Failed to generate SPICE string\", e)\n return null\n }\n }, [\n circuitJsonKey,\n spiceSimulationEnabled,\n spiceSimOptions.startTime,\n spiceSimOptions.duration,\n ])\n\n const {\n plotData,\n nodes,\n isLoading: isSpiceSimLoading,\n error: spiceSimError,\n } = useSpiceSimulation(spiceString)\n\n const [editModeEnabled, setEditModeEnabled] = useState(defaultEditMode)\n const [snapToGrid, setSnapToGrid] = useState(true)\n const [isInteractionEnabled, setIsInteractionEnabled] = useState<boolean>(\n !clickToInteractEnabled,\n )\n const [showViewMenu, setShowViewMenu] = useState(false)\n const [showSchematicGroups, setShowSchematicGroups] = useState(false)\n const svgDivRef = useRef<HTMLDivElement>(null)\n const touchStartRef = useRef<{ x: number; y: number } | null>(null)\n\n const handleTouchStart = (e: React.TouchEvent) => {\n const touch = e.touches[0]\n touchStartRef.current = {\n x: touch.clientX,\n y: touch.clientY,\n }\n }\n\n const handleTouchEnd = (e: React.TouchEvent) => {\n const touch = e.changedTouches[0]\n const start = touchStartRef.current\n if (!start) return\n\n const deltaX = Math.abs(touch.clientX - start.x)\n const deltaY = Math.abs(touch.clientY - start.y)\n\n if (deltaX < 10 && deltaY < 10) {\n e.preventDefault()\n setIsInteractionEnabled(true)\n }\n\n touchStartRef.current = null\n }\n\n const [internalEditEvents, setInternalEditEvents] = useState<\n ManualEditEvent[]\n >([])\n const circuitJsonRef = useRef<CircuitJson>(circuitJson)\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 && !showSpiceOverlay,\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 colorOverrides,\n })\n }, [circuitJsonKey, containerWidth, containerHeight])\n\n const containerBackgroundColor = useMemo(() => {\n const match = svgString.match(\n /<svg[^>]*style=\"[^\"]*background-color:\\s*([^;\\\"]+)/i,\n )\n return match?.[1] ?? \"transparent\"\n }, [svgString])\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 {\n handleMouseDown,\n handleTouchStart: handleComponentTouchStart,\n isDragging,\n activeEditEvent,\n } = useComponentDragging({\n onEditEvent: handleEditEvent,\n cancelDrag,\n realToSvgProjection,\n svgToScreenProjection,\n circuitJson,\n editEvents: editEventsWithUnappliedEditEvents,\n enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,\n snapToGrid,\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 // Add group overlays when enabled\n useSchematicGroupsOverlay({\n svgDivRef,\n circuitJson,\n circuitJsonKey,\n showGroups: showSchematicGroups,\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 onTouchStart={(e) => {\n if (editModeEnabled && isInteractionEnabled && !showSpiceOverlay) {\n handleComponentTouchStart(e)\n }\n }}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>\n dangerouslySetInnerHTML={{ __html: svgString }}\n />\n ),\n [\n svgString,\n isInteractionEnabled,\n clickToInteractEnabled,\n editModeEnabled,\n showSpiceOverlay,\n handleComponentTouchStart,\n ],\n )\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"relative\",\n backgroundColor: containerBackgroundColor,\n overflow: \"hidden\",\n cursor: showSpiceOverlay\n ? \"auto\"\n : isDragging\n ? \"grabbing\"\n : clickToInteractEnabled && !isInteractionEnabled\n ? \"pointer\"\n : \"grab\",\n minHeight: \"300px\",\n ...containerStyle,\n }}\n onWheelCapture={(e) => {\n if (showSpiceOverlay) {\n e.stopPropagation()\n }\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 onTouchStart={(e) => {\n if (showSpiceOverlay) return\n handleTouchStart(e)\n }}\n onTouchEnd={(e) => {\n if (showSpiceOverlay) return\n handleTouchEnd(e)\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: zIndexMap.clickToInteractOverlay,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"all\",\n touchAction: \"pan-x pan-y pinch-zoom\",\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 {typeof window !== \"undefined\" &&\n (\"ontouchstart\" in window || navigator.maxTouchPoints > 0)\n ? \"Touch to Interact\"\n : \"Click to Interact\"}\n </div>\n </div>\n )}\n <ViewMenuIcon\n active={showViewMenu}\n onClick={() => setShowViewMenu(!showViewMenu)}\n />\n {editingEnabled && (\n <EditIcon\n active={editModeEnabled}\n onClick={() => setEditModeEnabled(!editModeEnabled)}\n />\n )}\n {editingEnabled && editModeEnabled && (\n <GridIcon\n active={snapToGrid}\n onClick={() => setSnapToGrid(!snapToGrid)}\n />\n )}\n <ViewMenu\n circuitJson={circuitJson}\n circuitJsonKey={circuitJsonKey}\n isVisible={showViewMenu}\n onClose={() => setShowViewMenu(false)}\n showGroups={showSchematicGroups}\n onToggleGroups={setShowSchematicGroups}\n />\n {spiceSimulationEnabled && (\n <SpiceSimulationIcon onClick={() => setShowSpiceOverlay(true)} />\n )}\n {showSpiceOverlay && (\n <SpiceSimulationOverlay\n spiceString={spiceString}\n onClose={() => setShowSpiceOverlay(false)}\n plotData={plotData}\n nodes={nodes}\n isLoading={isSpiceSimLoading}\n error={spiceSimError}\n simOptions={spiceSimOptions}\n onSimOptionsChange={setSpiceSimOptions}\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 { useEffect } from \"react\"\nimport { su } from \"@tscircuit/soup-util\"\nimport type { CircuitJson } from \"circuit-json\"\n\ninterface UseSchematicGroupsOverlayOptions {\n svgDivRef: React.RefObject<HTMLDivElement | null>\n circuitJson: CircuitJson\n circuitJsonKey: string\n showGroups: boolean\n}\n\nconst GROUP_COLORS = [\n \"#8B0000\", // Dark Red\n \"#2F4F4F\", // Dark Slate Gray\n \"#191970\", // Midnight Blue\n \"#006400\", // Dark Green\n \"#FF4500\", // Dark Orange\n \"#800080\", // Purple\n \"#2E8B57\", // Sea Green\n \"#B8860B\", // Dark Goldenrod\n \"#C71585\", // Medium Violet Red\n \"#008B8B\", // Dark Cyan\n]\n\nexport const useSchematicGroupsOverlay = (\n options: UseSchematicGroupsOverlayOptions,\n) => {\n const { svgDivRef, circuitJson, circuitJsonKey, showGroups } = options\n\n useEffect(() => {\n if (\n !svgDivRef.current ||\n !showGroups ||\n !circuitJson ||\n circuitJson.length === 0\n ) {\n if (svgDivRef.current) {\n const existingOverlays = svgDivRef.current.querySelectorAll(\n \".schematic-group-overlay\",\n )\n existingOverlays.forEach((overlay) => overlay.remove())\n }\n return\n }\n\n const svg = svgDivRef.current.querySelector(\"svg\")\n if (!svg) {\n return\n }\n\n const existingOverlays = svg.querySelectorAll(\".schematic-group-overlay\")\n existingOverlays.forEach((overlay) => overlay.remove())\n\n try {\n const sourceGroups =\n su(circuitJson)\n .source_group?.list()\n .filter((x) => !!!x.is_subcircuit) || []\n const schematicComponents =\n su(circuitJson).schematic_component?.list() || []\n\n const sourceGroupHierarchy = new Map<string, string[]>()\n sourceGroups.forEach((group) => {\n const groupWithParent = group as any\n if (groupWithParent.parent_source_group_id) {\n const children =\n sourceGroupHierarchy.get(groupWithParent.parent_source_group_id) ||\n []\n children.push(group.source_group_id)\n sourceGroupHierarchy.set(\n groupWithParent.parent_source_group_id,\n children,\n )\n }\n })\n\n const getAllDescendantSourceGroups = (\n sourceGroupId: string,\n ): string[] => {\n const descendants: string[] = []\n const children = sourceGroupHierarchy.get(sourceGroupId) || []\n for (const child of children) {\n descendants.push(child)\n descendants.push(...getAllDescendantSourceGroups(child))\n }\n return descendants\n }\n\n const getGroupDepthLevel = (sourceGroupId: string): number => {\n const groupWithParent = sourceGroups.find(\n (g) => g.source_group_id === sourceGroupId,\n ) as any\n if (!groupWithParent?.parent_source_group_id) {\n return 0\n }\n return 1 + getGroupDepthLevel(groupWithParent.parent_source_group_id)\n }\n\n const hasMeaningfulGroups =\n sourceGroups.length > 0 &&\n sourceGroups.some((group) => group.name && group.name.trim() !== \"\")\n\n let groupsToRender: Array<{\n id: string\n name: string\n components: any[]\n color: string\n depthLevel: number\n hasChildren: boolean\n sourceGroupId?: string\n }> = []\n\n if (hasMeaningfulGroups) {\n const groupMap = new Map<string, any[]>()\n\n for (const comp of schematicComponents) {\n const sourceComp = su(circuitJson).source_component.get(\n comp.source_component_id,\n )\n if (sourceComp?.source_group_id) {\n if (!groupMap.has(sourceComp.source_group_id)) {\n groupMap.set(sourceComp.source_group_id, [])\n }\n groupMap.get(sourceComp.source_group_id)!.push(comp)\n }\n }\n\n sourceGroups.forEach((group, index) => {\n let groupComponents = groupMap.get(group.source_group_id) || []\n\n const descendantGroups = getAllDescendantSourceGroups(\n group.source_group_id,\n )\n for (const descendantGroupId of descendantGroups) {\n const descendantComponents = groupMap.get(descendantGroupId) || []\n groupComponents = [...groupComponents, ...descendantComponents]\n }\n\n if (groupComponents.length > 0) {\n const depthLevel = getGroupDepthLevel(group.source_group_id)\n const hasChildren =\n getAllDescendantSourceGroups(group.source_group_id).length > 0\n\n if (group.name?.startsWith(\"unnamed_board\")) return\n groupsToRender.push({\n id: group.source_group_id,\n name: group.name || `Group ${index + 1}`,\n components: groupComponents,\n color: GROUP_COLORS[index % GROUP_COLORS.length],\n depthLevel,\n hasChildren,\n sourceGroupId: group.source_group_id,\n })\n }\n })\n }\n // else {\n // const componentTypeGroups = new Map<string, any[]>()\n\n // for (const comp of schematicComponents) {\n // const sourceComp = su(circuitJson).source_component.get(comp.source_component_id)\n // if (sourceComp) {\n // const componentType = sourceComp.ftype || \"other\"\n // if (!componentTypeGroups.has(componentType)) {\n // componentTypeGroups.set(componentType, [])\n // }\n // componentTypeGroups.get(componentType)!.push(comp)\n // }\n // }\n // // groupsToRender = Array.from(componentTypeGroups.entries()).map(\n // // ([type, components], index) => ({\n // // id: `type_${type}`,\n // // name: `${type.charAt(0).toUpperCase() + type.slice(1)}s`,\n // // components,\n // // color: GROUP_COLORS[index % GROUP_COLORS.length],\n // // depthLevel: 0,\n // // hasChildren: false,\n // // }),\n // // )\n // }\n\n const viewBox = svg.viewBox.baseVal\n const svgRect = svg.getBoundingClientRect()\n const scale =\n Math.min(\n svgRect.width / viewBox.width,\n svgRect.height / viewBox.height,\n ) || 1\n\n groupsToRender.sort((a, b) => a.depthLevel - b.depthLevel)\n\n groupsToRender.forEach((group) => {\n if (group.components.length === 0) return\n\n const groupBounds = calculateGroupBounds(group.components, svg)\n if (!groupBounds) return\n\n const basePadding = Math.max(8, Math.min(25, 15 / Math.max(scale, 0.3)))\n const hierarchyPadding = group.hasChildren ? basePadding * 0.6 : 0\n const totalPadding = basePadding + hierarchyPadding\n\n const baseStrokeWidth = Math.max(1, 2 / Math.max(scale, 0.5))\n const strokeWidth =\n group.depthLevel === 0 ? baseStrokeWidth : baseStrokeWidth * 0.7\n\n const baseDashSize = Math.max(4, 8 / Math.max(scale, 0.5))\n const dashMultiplier = group.hasChildren ? 1.3 : 1\n const dashSize = baseDashSize * dashMultiplier\n const gapSize = dashSize * 0.5\n\n const groupOverlay = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"rect\",\n )\n groupOverlay.setAttribute(\"class\", \"schematic-group-overlay\")\n groupOverlay.setAttribute(\n \"x\",\n (groupBounds.minX - totalPadding).toString(),\n )\n groupOverlay.setAttribute(\n \"y\",\n (groupBounds.minY - totalPadding).toString(),\n )\n groupOverlay.setAttribute(\n \"width\",\n (groupBounds.maxX - groupBounds.minX + totalPadding * 2).toString(),\n )\n groupOverlay.setAttribute(\n \"height\",\n (groupBounds.maxY - groupBounds.minY + totalPadding * 2).toString(),\n )\n groupOverlay.setAttribute(\"fill\", \"none\")\n groupOverlay.setAttribute(\"stroke\", group.color)\n groupOverlay.setAttribute(\"stroke-width\", strokeWidth.toString())\n groupOverlay.setAttribute(\"stroke-dasharray\", `${dashSize},${gapSize}`)\n groupOverlay.setAttribute(\"opacity\", \"0.8\")\n groupOverlay.setAttribute(\"rx\", \"4\")\n groupOverlay.setAttribute(\"ry\", \"4\")\n\n const baseFontSize = Math.max(\n 6,\n Math.min(20, 14 / Math.max(scale, 0.2)),\n )\n const fontSizeReduction =\n group.depthLevel === 0 || group.depthLevel === 1\n ? 0\n : group.depthLevel * 0.2\n const fontSize = baseFontSize * (1 - fontSizeReduction)\n\n const labelPadding = Math.max(1, fontSize * 0.2)\n const labelText = group.name\n\n const tempText = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"text\",\n )\n tempText.setAttribute(\"font-size\", fontSize.toString())\n tempText.setAttribute(\"font-family\", \"Arial, sans-serif\")\n tempText.textContent = labelText\n svg.appendChild(tempText)\n const textBBox = tempText.getBBox()\n svg.removeChild(tempText)\n\n const labelWidth = textBBox.width + labelPadding * 2\n const labelHeight = fontSize + labelPadding * 2\n const labelX = groupBounds.minX - totalPadding\n const labelY = groupBounds.minY - totalPadding - labelHeight\n\n const labelBg = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"rect\",\n )\n labelBg.setAttribute(\"class\", \"schematic-group-overlay\")\n labelBg.setAttribute(\"x\", labelX.toString())\n labelBg.setAttribute(\"y\", (labelY - labelHeight).toString())\n labelBg.setAttribute(\"width\", labelWidth.toString())\n labelBg.setAttribute(\"height\", labelHeight.toString())\n labelBg.setAttribute(\"fill\", \"transparent\")\n labelBg.setAttribute(\"rx\", \"3\")\n labelBg.setAttribute(\"ry\", \"3\")\n\n const groupLabel = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"text\",\n )\n groupLabel.setAttribute(\"class\", \"schematic-group-overlay\")\n groupLabel.setAttribute(\"x\", (labelX + labelPadding).toString())\n groupLabel.setAttribute(\n \"y\",\n (labelY + labelHeight - labelPadding).toString(),\n )\n groupLabel.setAttribute(\"fill\", group.color)\n groupLabel.setAttribute(\"font-size\", fontSize.toString())\n groupLabel.setAttribute(\"font-family\", \"Arial, sans-serif\")\n groupLabel.setAttribute(\n \"font-weight\",\n group.depthLevel === 0 ? \"600\" : \"500\",\n )\n groupLabel.setAttribute(\"stroke\", group.color)\n groupLabel.setAttribute(\n \"stroke-width\",\n Math.max(0.2, fontSize * 0.02).toString(),\n )\n groupLabel.textContent = labelText\n\n svg.appendChild(groupOverlay)\n svg.appendChild(labelBg)\n svg.appendChild(groupLabel)\n })\n } catch (error) {\n console.error(\"Error creating group overlays:\", error)\n }\n }, [svgDivRef, circuitJsonKey, showGroups])\n}\n\nfunction calculateGroupBounds(components: any[], svg: SVGElement) {\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity\n\n for (const component of components) {\n let componentElement = svg.querySelector(\n `g[data-schematic-component-id=\"${component.schematic_component_id}\"]`,\n )\n\n if (!componentElement) {\n componentElement = svg.querySelector(\n `[data-schematic-component-id=\"${component.schematic_component_id}\"]`,\n )\n }\n\n if (componentElement) {\n const bbox = (componentElement as SVGGraphicsElement).getBBox()\n minX = Math.min(minX, bbox.x)\n minY = Math.min(minY, bbox.y)\n maxX = Math.max(maxX, bbox.x + bbox.width)\n maxY = Math.max(maxY, bbox.y + bbox.height)\n }\n }\n\n if (minX === Infinity) {\n return null\n }\n\n const bounds = { minX, minY, maxX, maxY }\n return bounds\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 { type Matrix, compose } 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 snapToGrid = 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 snapToGrid?: boolean\n}): {\n handleMouseDown: (e: React.MouseEvent) => void\n handleTouchStart: (e: React.TouchEvent) => 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 }>>(\n new Map(),\n )\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(event.schematic_component_id, {\n ...event.new_center,\n })\n }\n })\n }, [editEvents])\n\n const startDrag = useCallback(\n (clientX: number, clientY: number, target: Element) => {\n if (!enabled) return false\n\n const componentGroup = target.closest(\n '[data-circuit-json-type=\"schematic_component\"]',\n )\n if (!componentGroup) return false\n\n const schematic_component_id = componentGroup.getAttribute(\n \"data-schematic-component-id\",\n )\n if (!schematic_component_id) return false\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 false\n\n dragStartPosRef.current = { x: clientX, y: clientY }\n\n let current_position: { x: number; y: number }\n const trackedPosition = componentPositionsRef.current.get(\n schematic_component_id,\n )\n\n if (trackedPosition) {\n current_position = { ...trackedPosition }\n } else {\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 componentPositionsRef.current.set(schematic_component_id, {\n ...current_position,\n })\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 return true\n },\n [cancelDrag, enabled, circuitJson, editEvents],\n )\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n startDrag(e.clientX, e.clientY, e.target as Element)\n },\n [startDrag],\n )\n\n const handleTouchStart = useCallback(\n (e: React.TouchEvent) => {\n if (e.touches.length !== 1) return\n const touch = e.touches[0]\n if (startDrag(touch.clientX, touch.clientY, e.target as Element)) {\n e.preventDefault()\n }\n },\n [startDrag],\n )\n\n const updateDragPosition = useCallback(\n (clientX: number, clientY: number) => {\n if (!activeEditEventRef.current || !dragStartPosRef.current) return\n\n const screenDelta = {\n x: clientX - dragStartPosRef.current.x,\n y: clientY - dragStartPosRef.current.y,\n }\n\n const mmDelta = {\n x: screenDelta.x / realToScreenProjection.a,\n y: screenDelta.y / realToScreenProjection.d,\n }\n\n let newCenter = {\n x: activeEditEventRef.current.original_center.x + mmDelta.x,\n y: activeEditEventRef.current.original_center.y + mmDelta.y,\n }\n if (snapToGrid) {\n const snap = (v: number) => Math.round(v * 10) / 10\n newCenter = { x: snap(newCenter.x), y: snap(newCenter.y) }\n }\n\n const newEditEvent = {\n ...activeEditEventRef.current,\n new_center: newCenter,\n }\n\n activeEditEventRef.current = newEditEvent\n setActiveEditEvent(newEditEvent)\n },\n [realToScreenProjection, snapToGrid],\n )\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => updateDragPosition(e.clientX, e.clientY),\n [updateDragPosition],\n )\n\n const handleTouchMove = useCallback(\n (e: TouchEvent) => {\n if (e.touches.length !== 1 || !activeEditEventRef.current) return\n e.preventDefault()\n const touch = e.touches[0]\n updateDragPosition(touch.clientX, touch.clientY)\n },\n [updateDragPosition],\n )\n\n const endDrag = useCallback(() => {\n if (!activeEditEventRef.current) return\n const finalEvent = {\n ...activeEditEventRef.current,\n in_progress: false,\n }\n\n componentPositionsRef.current.set(finalEvent.schematic_component_id, {\n ...finalEvent.new_center,\n })\n\n debug(\"endDrag 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 const handleMouseUp = useCallback(() => endDrag(), [endDrag])\n const handleTouchEnd = useCallback(() => endDrag(), [endDrag])\n\n useEffect(() => {\n window.addEventListener(\"mousemove\", handleMouseMove)\n window.addEventListener(\"mouseup\", handleMouseUp)\n window.addEventListener(\"touchmove\", handleTouchMove, { passive: false })\n window.addEventListener(\"touchend\", handleTouchEnd)\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove)\n window.removeEventListener(\"mouseup\", handleMouseUp)\n window.removeEventListener(\"touchmove\", handleTouchMove)\n window.removeEventListener(\"touchend\", handleTouchEnd)\n }\n }, [handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd])\n\n return {\n handleMouseDown,\n handleTouchStart,\n isDragging: !!activeEditEventRef.current,\n activeEditEvent: activeEditEvent,\n }\n}\n","export const zIndexMap = {\n schematicEditIcon: 50,\n schematicGridIcon: 49,\n spiceSimulationIcon: 51,\n viewMenuIcon: 48,\n viewMenu: 55,\n viewMenuBackdrop: 54,\n clickToInteractOverlay: 100,\n}\n","import { zIndexMap } from \"../utils/z-index-map\"\n\nexport const EditIcon = ({\n onClick,\n active,\n}: { onClick: () => void; active: boolean }) => {\n const handleInteraction = (e: React.MouseEvent | React.TouchEvent) => {\n e.preventDefault()\n onClick()\n }\n\n return (\n <div\n onClick={handleInteraction}\n onTouchEnd={handleInteraction}\n style={{\n position: \"absolute\",\n top: \"16px\",\n right: \"64px\",\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: zIndexMap.schematicEditIcon,\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 { zIndexMap } from \"../utils/z-index-map\"\n\nexport const GridIcon = ({\n onClick,\n active,\n}: { onClick: () => void; active: boolean }) => {\n const handleInteraction = (e: React.MouseEvent | React.TouchEvent) => {\n e.preventDefault()\n onClick()\n }\n\n return (\n <div\n onClick={handleInteraction}\n onTouchEnd={handleInteraction}\n style={{\n position: \"absolute\",\n top: \"56px\",\n right: \"64px\",\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: zIndexMap.schematicGridIcon,\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=\"M3 3h7v7H3zM14 3h7v7h-7zM3 14h7v7H3zM14 14h7v7h-7z\" />\n </svg>\n </div>\n )\n}\n","import { zIndexMap } from \"../utils/z-index-map\"\n\nexport const ViewMenuIcon = ({\n onClick,\n active,\n}: { onClick: () => void; active: boolean }) => {\n const handleInteraction = (e: React.MouseEvent | React.TouchEvent) => {\n e.preventDefault()\n onClick()\n }\n\n return (\n <div\n onClick={handleInteraction}\n onTouchEnd={handleInteraction}\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: zIndexMap.viewMenuIcon,\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 <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </div>\n )\n}\n","import { useMemo } from \"react\"\nimport { su } from \"@tscircuit/soup-util\"\nimport type { CircuitJson } from \"circuit-json\"\nimport { zIndexMap } from \"../utils/z-index-map\"\n\ninterface ViewMenuProps {\n circuitJson: CircuitJson\n circuitJsonKey: string\n isVisible: boolean\n onClose: () => void\n showGroups: boolean\n onToggleGroups: (show: boolean) => void\n}\n\nexport const ViewMenu = ({\n circuitJson,\n circuitJsonKey,\n isVisible,\n onClose,\n showGroups,\n onToggleGroups,\n}: ViewMenuProps) => {\n const hasGroups = useMemo(() => {\n if (!circuitJson || circuitJson.length === 0) return false\n\n try {\n // Check if there are explicit groups\n const sourceGroups = su(circuitJson).source_group?.list() || []\n if (sourceGroups.length > 0) return true\n\n // Check if we can create virtual groups by component type\n const schematicComponents =\n su(circuitJson).schematic_component?.list() || []\n if (schematicComponents.length > 1) {\n const componentTypes = new Set()\n for (const comp of schematicComponents) {\n const sourceComp = su(circuitJson).source_component.get(\n comp.source_component_id,\n )\n if (sourceComp?.ftype) {\n componentTypes.add(sourceComp.ftype)\n }\n }\n return componentTypes.size > 1 // Only show if there are multiple types\n }\n\n return false\n } catch (error) {\n console.error(\"Error checking for groups:\", error)\n return false\n }\n }, [circuitJsonKey])\n\n if (!isVisible) return null\n\n return (\n <>\n {/* Backdrop */}\n <div\n onClick={onClose}\n onTouchEnd={(e) => {\n e.preventDefault()\n onClose()\n }}\n style={{\n position: \"absolute\",\n inset: 0,\n backgroundColor: \"transparent\",\n zIndex: zIndexMap.viewMenuBackdrop,\n }}\n />\n\n {/* Menu */}\n <div\n style={{\n position: \"absolute\",\n top: \"56px\",\n right: \"16px\",\n backgroundColor: \"#ffffff\",\n color: \"#000000\",\n border: \"1px solid #ccc\",\n borderRadius: \"4px\",\n boxShadow: \"0 4px 12px rgba(0,0,0,0.1)\",\n minWidth: \"200px\",\n zIndex: zIndexMap.viewMenu,\n }}\n >\n {/* Groups Toggle Option */}\n <div\n onClick={() => {\n if (hasGroups) {\n onToggleGroups(!showGroups)\n }\n }}\n onTouchEnd={(e) => {\n e.preventDefault()\n if (hasGroups) {\n onToggleGroups(!showGroups)\n }\n }}\n style={{\n padding: \"8px 12px\",\n cursor: hasGroups ? \"pointer\" : \"not-allowed\",\n opacity: hasGroups ? 1 : 0.5,\n fontSize: \"13px\",\n color: \"#000000\",\n fontFamily: \"sans-serif\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n onMouseEnter={(e) => {\n if (hasGroups) {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\"\n }\n }}\n onMouseLeave={(e) => {\n if (hasGroups) {\n e.currentTarget.style.backgroundColor = \"transparent\"\n }\n }}\n >\n <div\n style={{\n width: \"16px\",\n height: \"16px\",\n border: \"2px solid #000\",\n borderRadius: \"2px\",\n backgroundColor: \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"10px\",\n fontWeight: \"bold\",\n }}\n >\n {showGroups && \"✓\"}\n </div>\n View Schematic Groups\n </div>\n\n {!hasGroups && (\n <div\n style={{\n padding: \"8px 12px\",\n fontSize: \"11px\",\n color: \"#666\",\n fontStyle: \"italic\",\n }}\n >\n No groups found in this schematic\n </div>\n )}\n </div>\n </>\n )\n}\n","export const SpiceIcon = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M3 12h2.5l2.5-9 4 18 4-9h5.5\" />\n </svg>\n)\n","import { SpiceIcon } from \"./SpiceIcon\"\nimport { zIndexMap } from \"../utils/z-index-map\"\n\nexport const SpiceSimulationIcon = ({\n onClick,\n}: {\n onClick: () => void\n}) => {\n return (\n <div\n onClick={onClick}\n style={{\n position: \"absolute\",\n top: \"16px\",\n right: \"112px\",\n backgroundColor: \"#fff\",\n color: \"#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: zIndexMap.spiceSimulationIcon,\n }}\n >\n <SpiceIcon />\n </div>\n )\n}\n","import { useMemo } from \"react\"\nimport {\n Chart as ChartJS,\n type ChartOptions,\n CategoryScale,\n LinearScale,\n PointElement,\n LineElement,\n Title,\n Tooltip,\n Legend,\n} from \"chart.js\"\nimport { Line } from \"react-chartjs-2\"\nimport type { PlotPoint } from \"../hooks/useSpiceSimulation\"\n\nChartJS.register(\n CategoryScale,\n LinearScale,\n PointElement,\n LineElement,\n Title,\n Tooltip,\n Legend,\n)\n\nconst colors = [\"#8884d8\", \"#82ca9d\", \"#ffc658\", \"#ff7300\", \"#387908\"]\n\nconst formatTimeWithUnits = (seconds: number) => {\n if (seconds === 0) return \"0s\"\n const absSeconds = Math.abs(seconds)\n\n let unit = \"s\"\n let scale = 1\n if (absSeconds < 1e-12) {\n unit = \"fs\"\n scale = 1e15\n } else if (absSeconds < 1e-9) {\n unit = \"ps\"\n scale = 1e12\n } else if (absSeconds < 1e-6) {\n unit = \"ns\"\n scale = 1e9\n } else if (absSeconds < 1e-3) {\n unit = \"us\"\n scale = 1e6\n } else if (absSeconds < 1) {\n unit = \"ms\"\n scale = 1e3\n }\n\n return `${parseFloat((seconds * scale).toPrecision(3))}${unit}`\n}\n\nexport const SpicePlot = ({\n plotData,\n nodes,\n isLoading,\n error,\n}: {\n plotData: PlotPoint[]\n nodes: string[]\n isLoading: boolean\n error: string | null\n}) => {\n const yAxisLabel = useMemo(() => {\n const hasVoltage = nodes.some((n) => n.toLowerCase().startsWith(\"v(\"))\n const hasCurrent = nodes.some((n) => n.toLowerCase().startsWith(\"i(\"))\n if (hasVoltage && hasCurrent) return \"Value\"\n if (hasVoltage) return \"Voltage (V)\"\n if (hasCurrent) return \"Current (A)\"\n return \"Value\"\n }, [nodes])\n\n if (isLoading) {\n return (\n <div\n style={{\n height: \"300px\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n Running simulation...\n </div>\n )\n }\n\n if (error) {\n return (\n <div\n style={{\n height: \"300px\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"red\",\n }}\n >\n Error: {error}\n </div>\n )\n }\n\n if (plotData.length === 0) {\n return (\n <div\n style={{\n height: \"300px\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n No data to plot. Check simulation output or SPICE netlist.\n </div>\n )\n }\n\n const chartData = {\n datasets: nodes.map((node, i) => ({\n label: node,\n data: plotData.map((p) => ({\n x: Number(p.name),\n y: p[node] as number,\n })),\n borderColor: colors[i % colors.length],\n backgroundColor: colors[i % colors.length],\n fill: false,\n tension: 0.1,\n })),\n }\n\n const options: ChartOptions<\"line\"> = {\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n position: \"top\" as const,\n labels: {\n font: {\n family: \"sans-serif\",\n },\n },\n },\n title: {\n display: false,\n },\n tooltip: {\n callbacks: {\n title: (tooltipItems) => {\n if (tooltipItems.length > 0) {\n const item = tooltipItems[0]\n return formatTimeWithUnits(item.parsed.x)\n }\n return \"\"\n },\n },\n },\n },\n scales: {\n x: {\n type: \"linear\",\n title: {\n display: true,\n text: \"Time\",\n font: {\n family: \"sans-serif\",\n },\n },\n ticks: {\n callback: (value) => formatTimeWithUnits(value as number),\n font: {\n family: \"sans-serif\",\n },\n },\n },\n y: {\n title: {\n display: true,\n text: yAxisLabel,\n font: {\n family: \"sans-serif\",\n },\n },\n ticks: {\n font: {\n family: \"sans-serif\",\n },\n },\n },\n },\n }\n\n return (\n <div style={{ position: \"relative\", height: \"300px\", width: \"100%\" }}>\n <Line options={options} data={chartData} />\n </div>\n )\n}\n","import { SpicePlot } from \"./SpicePlot\"\nimport type { PlotPoint } from \"../hooks/useSpiceSimulation\"\nimport { useEffect, useState } from \"react\"\n\ninterface SpiceSimulationOverlayProps {\n spiceString: string | null\n onClose: () => void\n plotData: PlotPoint[]\n nodes: string[]\n isLoading: boolean\n error: string | null\n simOptions: {\n showVoltage: boolean\n showCurrent: boolean\n startTime: number\n duration: number\n }\n onSimOptionsChange: (\n options: SpiceSimulationOverlayProps[\"simOptions\"],\n ) => void\n}\n\nexport const SpiceSimulationOverlay = ({\n spiceString,\n onClose,\n plotData,\n nodes,\n isLoading,\n error,\n simOptions,\n onSimOptionsChange,\n}: SpiceSimulationOverlayProps) => {\n const [startTimeDraft, setStartTimeDraft] = useState(\n String(simOptions.startTime),\n )\n const [durationDraft, setDurationDraft] = useState(\n String(simOptions.duration),\n )\n\n useEffect(() => {\n setStartTimeDraft(String(simOptions.startTime))\n setDurationDraft(String(simOptions.duration))\n }, [simOptions.startTime, simOptions.duration])\n\n const handleRerun = () => {\n onSimOptionsChange({\n ...simOptions,\n startTime: Number(startTimeDraft),\n duration: Number(durationDraft),\n })\n }\n\n const filteredNodes = nodes.filter((node) => {\n const isVoltage = node.toLowerCase().startsWith(\"v(\")\n const isCurrent = node.toLowerCase().startsWith(\"i(\")\n if (simOptions.showVoltage && isVoltage) return true\n if (simOptions.showCurrent && isCurrent) return true\n return false\n })\n\n return (\n <div\n style={{\n position: \"fixed\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 1002,\n fontFamily: \"sans-serif\",\n }}\n >\n <div\n style={{\n backgroundColor: \"white\",\n padding: \"24px\",\n borderRadius: \"12px\",\n width: \"90%\",\n maxWidth: \"900px\",\n boxShadow: \"0 4px 20px rgba(0, 0, 0, 0.15)\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"24px\",\n borderBottom: \"1px solid #eee\",\n paddingBottom: \"16px\",\n }}\n >\n <h2\n style={{\n margin: 0,\n fontSize: \"22px\",\n fontWeight: 600,\n color: \"#333\",\n }}\n >\n SPICE Simulation\n </h2>\n <button\n onClick={onClose}\n style={{\n background: \"none\",\n border: \"none\",\n fontSize: \"28px\",\n cursor: \"pointer\",\n color: \"#888\",\n padding: 0,\n lineHeight: 1,\n }}\n >\n &times;\n </button>\n </div>\n <div>\n <SpicePlot\n plotData={plotData}\n nodes={filteredNodes}\n isLoading={isLoading}\n error={error}\n />\n </div>\n <div\n style={{\n marginTop: \"16px\",\n padding: \"12px\",\n backgroundColor: \"#f7f7f7\",\n borderRadius: \"6px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"24px\",\n alignItems: \"center\",\n fontSize: \"14px\",\n }}\n >\n <div style={{ display: \"flex\", gap: \"16px\" }}>\n <label\n style={{ display: \"flex\", alignItems: \"center\", gap: \"6px\" }}\n >\n <input\n type=\"checkbox\"\n checked={simOptions.showVoltage}\n onChange={(e) =>\n onSimOptionsChange({\n ...simOptions,\n showVoltage: e.target.checked,\n })\n }\n />\n Voltage\n </label>\n <label\n style={{ display: \"flex\", alignItems: \"center\", gap: \"6px\" }}\n >\n <input\n type=\"checkbox\"\n checked={simOptions.showCurrent}\n onChange={(e) =>\n onSimOptionsChange({\n ...simOptions,\n showCurrent: e.target.checked,\n })\n }\n />\n Current\n </label>\n </div>\n <div style={{ display: \"flex\", gap: \"16px\", alignItems: \"center\" }}>\n <label htmlFor=\"startTime\">Start Time (ms):</label>\n <input\n id=\"startTime\"\n type=\"number\"\n value={startTimeDraft}\n onChange={(e) => setStartTimeDraft(e.target.value)}\n style={{\n width: \"80px\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n border: \"1px solid #ccc\",\n }}\n />\n <label htmlFor=\"duration\">Duration (ms):</label>\n <input\n id=\"duration\"\n type=\"number\"\n value={durationDraft}\n onChange={(e) => setDurationDraft(e.target.value)}\n style={{\n width: \"80px\",\n padding: \"4px 8px\",\n borderRadius: \"4px\",\n border: \"1px solid #ccc\",\n }}\n />\n <button\n onClick={handleRerun}\n style={{\n padding: \"4px 12px\",\n borderRadius: \"4px\",\n border: \"1px solid #ccc\",\n backgroundColor: \"#f0f0f0\",\n cursor: \"pointer\",\n }}\n >\n Rerun\n </button>\n </div>\n </div>\n <div style={{ marginTop: \"24px\" }}>\n <h3\n style={{\n marginTop: 0,\n marginBottom: \"12px\",\n fontSize: \"18px\",\n fontWeight: 600,\n color: \"#333\",\n }}\n >\n SPICE Netlist\n </h3>\n <pre\n style={{\n backgroundColor: \"#fafafa\",\n padding: \"16px\",\n borderRadius: \"6px\",\n maxHeight: \"150px\",\n overflowY: \"auto\",\n border: \"1px solid #eee\",\n color: \"#333\",\n fontSize: \"13px\",\n fontFamily: \"monospace\",\n }}\n >\n {spiceString}\n </pre>\n </div>\n </div>\n </div>\n )\n}\n","import { useState, useEffect } from \"react\"\nimport type * as EecircuitEngine from \"../types/eecircuit-engine\"\n// @ts-ignore\nimport { getSpiceSimulationWorkerBlobUrl } from \"../workers/spice-simulation.worker.blob.js\"\n\n// Types from eecircuit-engine interface\ntype RealDataType = {\n name: string\n type: string\n values: number[]\n}\ntype ComplexNumber = {\n real: number\n img: number\n}\ntype ComplexDataType = {\n name: string\n type: string\n values: ComplexNumber[]\n}\ntype EecEngineResult =\n | {\n header: string\n numVariables: number\n variableNames: string[]\n numPoints: number\n dataType: \"real\"\n data: RealDataType[]\n }\n | {\n header: string\n numVariables: number\n variableNames: string[]\n numPoints: number\n dataType: \"complex\"\n data: ComplexDataType[]\n }\n\nexport interface PlotPoint {\n name: string // time or sweep variable\n [key: string]: number | string\n}\n\nconst parseEecEngineOutput = (\n result: EecEngineResult,\n): { plotData: PlotPoint[]; nodes: string[] } => {\n const columnData: Record<string, number[]> = {}\n\n if (result.dataType === \"real\") {\n result.data.forEach((col) => {\n columnData[col.name] = col.values\n })\n } else if (result.dataType === \"complex\") {\n result.data.forEach((col) => {\n // For now, plot the real part of complex numbers\n columnData[col.name] = col.values.map((v) => v.real)\n })\n } else {\n throw new Error(\"Unsupported data type in simulation result\")\n }\n\n const timeKey = Object.keys(columnData).find(\n (k) => k.toLowerCase() === \"time\" || k.toLowerCase() === \"frequency\",\n )\n if (!timeKey) {\n throw new Error(\"No time or frequency data in simulation result\")\n }\n const timeValues = columnData[timeKey]\n const probedVariables = Object.keys(columnData).filter((k) => k !== timeKey)\n const plotableNodes = probedVariables\n\n const plotData: PlotPoint[] = timeValues.map((t: number, i: number) => {\n const point: PlotPoint = { name: t.toExponential(2) }\n probedVariables.forEach((variable) => {\n point[variable] = columnData[variable][i]\n })\n return point\n })\n\n return { plotData, nodes: plotableNodes }\n}\n\ntype WorkerMessage =\n | {\n type: \"result\"\n result: EecEngineResult\n }\n | { type: \"error\"; error: string }\n\nexport const useSpiceSimulation = (spiceString: string | null) => {\n const [plotData, setPlotData] = useState<PlotPoint[]>([])\n const [nodes, setNodes] = useState<string[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!spiceString) {\n setIsLoading(false)\n setPlotData([])\n setNodes([])\n setError(null)\n return\n }\n setIsLoading(true)\n setError(null)\n setPlotData([])\n setNodes([])\n\n const workerUrl = getSpiceSimulationWorkerBlobUrl()\n\n if (!workerUrl) {\n setError(\"Could not create SPICE simulation worker.\")\n setIsLoading(false)\n return\n }\n\n const worker = new Worker(workerUrl, { type: \"module\" })\n\n worker.onmessage = (event: MessageEvent<WorkerMessage>) => {\n if (event.data.type === \"result\") {\n try {\n const { plotData: parsedData, nodes: parsedNodes } =\n parseEecEngineOutput(event.data.result)\n setPlotData(parsedData)\n setNodes(parsedNodes)\n } catch (e: any) {\n setError(e.message || \"Failed to parse simulation result\")\n console.error(e)\n }\n } else if (event.data.type === \"error\") {\n setError(event.data.error)\n }\n setIsLoading(false)\n }\n\n worker.onerror = (err) => {\n setError(err.message)\n setIsLoading(false)\n }\n\n worker.postMessage({ spiceString })\n\n return () => {\n worker.terminate()\n }\n }, [spiceString])\n\n return { plotData, nodes, isLoading, error }\n}\n","// This file is generated by scripts/build-worker-blob-url.ts\n// Do not edit this file directly.\n\nconst b64 = \"dmFyIGU9bnVsbCxzPWFzeW5jKCk9Pihhd2FpdCBpbXBvcnQoImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWVjaXJjdWl0LWVuZ2luZUAxLjUuMi8rZXNtIikpLlNpbXVsYXRpb24sYz1hc3luYygpPT57aWYoZSYmZS5pc0luaXRpYWxpemVkKCkpcmV0dXJuO2xldCBpPWF3YWl0IHMoKTtlPW5ldyBpLGF3YWl0IGUuc3RhcnQoKX07c2VsZi5vbm1lc3NhZ2U9YXN5bmMgaT0+e3RyeXtpZihhd2FpdCBjKCksIWUpdGhyb3cgbmV3IEVycm9yKCJTaW11bGF0aW9uIG5vdCBpbml0aWFsaXplZCIpO2xldCB0PWkuZGF0YS5zcGljZVN0cmluZyxhPXQubWF0Y2goL3dyZGF0YVxzKyhcUyspXHMrKC4qKS9pKTtpZihhKXtsZXQgbz1gLnByb2JlICR7YVsyXS50cmltKCkuc3BsaXQoL1xzKy8pLmpvaW4oIiAiKX1gO3Q9dC5yZXBsYWNlKC93cmRhdGEuKi9pLG8pfWVsc2UgaWYoIXQubWF0Y2goL1wucHJvYmUvaSkpdGhyb3cgdC5tYXRjaCgvcGxvdFxzKyguKikvaSk/bmV3IEVycm9yKCJUaGUgJ3Bsb3QnIGNvbW1hbmQgaXMgbm90IHN1cHBvcnRlZCBmb3IgZGF0YSBleHRyYWN0aW9uLiBQbGVhc2UgdXNlICd3cmRhdGEgPGZpbGVuYW1lPiA8dmFyMT4gLi4uJyBvciAnLnByb2JlIDx2YXIxPiAuLi4nIGluc3RlYWQuIik6bmV3IEVycm9yKCJObyAnLnByb2JlJyBvciAnd3JkYXRhJyBjb21tYW5kIGZvdW5kIGluIFNQSUNFIGZpbGUuIFVzZSAnd3JkYXRhIDxmaWxlbmFtZT4gPHZhcjE+IC4uLicgdG8gc3BlY2lmeSBvdXRwdXQuIik7ZS5zZXROZXRMaXN0KHQpO2xldCBuPWF3YWl0IGUucnVuU2ltKCk7c2VsZi5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixyZXN1bHQ6bn0pfWNhdGNoKHQpe3NlbGYucG9zdE1lc3NhZ2Uoe3R5cGU6ImVycm9yIixlcnJvcjp0Lm1lc3NhZ2V9KX19Owo=\";\n\nlet blobUrl = null;\n\nexport const getSpiceSimulationWorkerBlobUrl = () => {\n if (typeof window === \"undefined\") return null;\n if (blobUrl) return blobUrl;\n\n try {\n const blob = new Blob([atob(b64)], { type: \"application/javascript\" });\n blobUrl = URL.createObjectURL(blob);\n return blobUrl;\n } catch (e) {\n console.error(\"Failed to create blob URL for worker\", e);\n return null;\n }\n};\n","import { circuitJsonToSpice } from \"circuit-json-to-spice\"\nimport type { CircuitJson } from \"circuit-json\"\n\nexport interface SpiceSimOptions {\n showVoltage: boolean\n showCurrent: boolean\n startTime: number // in ms\n duration: number // in ms\n}\n\nconst formatSimTime = (seconds: number): string => {\n if (seconds === 0) return \"0\"\n const absSeconds = Math.abs(seconds)\n\n const precision = (v: number) => v.toPrecision(4)\n\n if (absSeconds >= 1) return precision(seconds)\n if (absSeconds >= 1e-3) return `${precision(seconds * 1e3)}m`\n if (absSeconds >= 1e-6) return `${precision(seconds * 1e6)}u`\n if (absSeconds >= 1e-9) return `${precision(seconds * 1e9)}n`\n if (absSeconds >= 1e-12) return `${precision(seconds * 1e12)}p`\n if (absSeconds >= 1e-15) return `${precision(seconds * 1e15)}f`\n\n return seconds.toExponential(3)\n}\n\nexport const getSpiceFromCircuitJson = (\n circuitJson: CircuitJson,\n options?: Partial<SpiceSimOptions>,\n): string => {\n const spiceNetlist = circuitJsonToSpice(circuitJson as any)\n const baseSpiceString = spiceNetlist.toSpiceString()\n\n const lines = baseSpiceString.split(\"\\n\").filter((l) => l.trim() !== \"\")\n const componentLines = lines.filter(\n (l) => !l.startsWith(\"*\") && !l.startsWith(\".\") && l.trim() !== \"\",\n )\n\n const allNodes = new Set<string>()\n const capacitorNodes = new Set<string>()\n const componentNamesToProbeCurrent = new Set<string>()\n\n for (const line of componentLines) {\n const parts = line.trim().split(/\\s+/)\n if (parts.length < 3) continue\n\n const componentName = parts[0]\n const componentType = componentName[0].toUpperCase()\n let nodesOnLine: string[] = []\n\n if ([\"R\", \"C\", \"L\", \"V\", \"I\", \"D\"].includes(componentType)) {\n nodesOnLine = parts.slice(1, 3)\n // Only probe current on voltage sources\n if (componentType === \"V\") {\n componentNamesToProbeCurrent.add(componentName)\n }\n } else if (componentType === \"Q\" && parts.length >= 4) {\n // BJT\n nodesOnLine = parts.slice(1, 4)\n } else if (componentType === \"M\" && parts.length >= 5) {\n // MOSFET\n nodesOnLine = parts.slice(1, 5)\n } else if (componentType === \"X\") {\n // Subcircuit\n // Assume last part is model name, everything in between is a node\n nodesOnLine = parts.slice(1, -1)\n } else {\n continue\n }\n\n nodesOnLine.forEach((node) => allNodes.add(node))\n\n if (componentType === \"C\") {\n nodesOnLine.forEach((node) => capacitorNodes.add(node))\n }\n }\n\n // Do not probe/set IC for ground\n allNodes.delete(\"0\")\n capacitorNodes.delete(\"0\")\n\n const icLines = Array.from(capacitorNodes).map((node) => `.ic V(${node})=0`)\n\n const probes: string[] = []\n const probeVoltages = Array.from(allNodes).map((node) => `V(${node})`)\n probes.push(...probeVoltages)\n const probeCurrents = Array.from(componentNamesToProbeCurrent).map(\n (name) => `I(${name})`,\n )\n probes.push(...probeCurrents)\n\n const probeLine = probes.length > 0 ? `.probe ${probes.join(\" \")}` : \"\"\n\n const tstart_ms = options?.startTime ?? 0\n const duration_ms = options?.duration ?? 20\n const tstart = tstart_ms * 1e-3 // s\n const duration = duration_ms * 1e-3 // s\n\n const tstop = tstart + duration\n const tstep = duration / 50\n const tranLine = `.tran ${formatSimTime(tstep)} ${formatSimTime(\n tstop,\n )} ${formatSimTime(tstart)} UIC`\n\n const endStatement = \".end\"\n const originalLines = baseSpiceString.split(\"\\n\")\n let endIndex = -1\n for (let i = originalLines.length - 1; i >= 0; i--) {\n if (originalLines[i].trim().toLowerCase().startsWith(endStatement)) {\n endIndex = i\n break\n }\n }\n\n const injectionLines = [...icLines, probeLine, tranLine].filter(Boolean)\n\n let finalLines: string[]\n\n if (endIndex !== -1) {\n const beforeEnd = originalLines.slice(0, endIndex)\n const endLineAndAfter = originalLines.slice(endIndex)\n finalLines = [...beforeEnd, ...injectionLines, ...endLineAndAfter]\n } else {\n finalLines = [...originalLines, ...injectionLines, endStatement]\n }\n\n return finalLines.join(\"\\n\")\n}\n"],"mappings":"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","names":["useEffect","useRef","su","useEffect","su","existingOverlays","useEffect","useMemo","useRef","useState","useEffect","su","useEffect","useRef","useState","compose","debug","su","jsx","jsx","jsxs","su","jsx","jsxs","su","jsx","jsx","useMemo","jsx","jsxs","useEffect","useState","jsx","jsxs","useState","useEffect","useState","useEffect","jsx","jsxs","debug","useState","circuitJson","useMemo","useRef","useEffect"]}
@@ -4,9 +4,15 @@ export const EditIcon = ({
4
4
  onClick,
5
5
  active,
6
6
  }: { onClick: () => void; active: boolean }) => {
7
+ const handleInteraction = (e: React.MouseEvent | React.TouchEvent) => {
8
+ e.preventDefault()
9
+ onClick()
10
+ }
11
+
7
12
  return (
8
13
  <div
9
- onClick={onClick}
14
+ onClick={handleInteraction}
15
+ onTouchEnd={handleInteraction}
10
16
  style={{
11
17
  position: "absolute",
12
18
  top: "16px",
@@ -4,9 +4,15 @@ export const GridIcon = ({
4
4
  onClick,
5
5
  active,
6
6
  }: { onClick: () => void; active: boolean }) => {
7
+ const handleInteraction = (e: React.MouseEvent | React.TouchEvent) => {
8
+ e.preventDefault()
9
+ onClick()
10
+ }
11
+
7
12
  return (
8
13
  <div
9
- onClick={onClick}
14
+ onClick={handleInteraction}
15
+ onTouchEnd={handleInteraction}
10
16
  style={{
11
17
  position: "absolute",
12
18
  top: "56px",
@@ -207,18 +207,21 @@ export const SchematicViewer = ({
207
207
  return [...unappliedEditEvents, ...internalEditEvents]
208
208
  }, [unappliedEditEvents, internalEditEvents])
209
209
 
210
- const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
211
- {
212
- onEditEvent: handleEditEvent,
213
- cancelDrag,
214
- realToSvgProjection,
215
- svgToScreenProjection,
216
- circuitJson,
217
- editEvents: editEventsWithUnappliedEditEvents,
218
- enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
219
- snapToGrid,
220
- },
221
- )
210
+ const {
211
+ handleMouseDown,
212
+ handleTouchStart: handleComponentTouchStart,
213
+ isDragging,
214
+ activeEditEvent,
215
+ } = useComponentDragging({
216
+ onEditEvent: handleEditEvent,
217
+ cancelDrag,
218
+ realToSvgProjection,
219
+ svgToScreenProjection,
220
+ circuitJson,
221
+ editEvents: editEventsWithUnappliedEditEvents,
222
+ enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
223
+ snapToGrid,
224
+ })
222
225
 
223
226
  useChangeSchematicComponentLocationsInSvg({
224
227
  svgDivRef,
@@ -255,11 +258,23 @@ export const SchematicViewer = ({
255
258
  : "auto",
256
259
  transformOrigin: "0 0",
257
260
  }}
261
+ onTouchStart={(e) => {
262
+ if (editModeEnabled && isInteractionEnabled && !showSpiceOverlay) {
263
+ handleComponentTouchStart(e)
264
+ }
265
+ }}
258
266
  // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
259
267
  dangerouslySetInnerHTML={{ __html: svgString }}
260
268
  />
261
269
  ),
262
- [svgString, isInteractionEnabled, clickToInteractEnabled],
270
+ [
271
+ svgString,
272
+ isInteractionEnabled,
273
+ clickToInteractEnabled,
274
+ editModeEnabled,
275
+ showSpiceOverlay,
276
+ handleComponentTouchStart,
277
+ ],
263
278
  )
264
279
 
265
280
  return (
@@ -58,6 +58,10 @@ export const ViewMenu = ({
58
58
  {/* Backdrop */}
59
59
  <div
60
60
  onClick={onClose}
61
+ onTouchEnd={(e) => {
62
+ e.preventDefault()
63
+ onClose()
64
+ }}
61
65
  style={{
62
66
  position: "absolute",
63
67
  inset: 0,
@@ -88,6 +92,12 @@ export const ViewMenu = ({
88
92
  onToggleGroups(!showGroups)
89
93
  }
90
94
  }}
95
+ onTouchEnd={(e) => {
96
+ e.preventDefault()
97
+ if (hasGroups) {
98
+ onToggleGroups(!showGroups)
99
+ }
100
+ }}
91
101
  style={{
92
102
  padding: "8px 12px",
93
103
  cursor: hasGroups ? "pointer" : "not-allowed",
@@ -4,9 +4,15 @@ export const ViewMenuIcon = ({
4
4
  onClick,
5
5
  active,
6
6
  }: { onClick: () => void; active: boolean }) => {
7
+ const handleInteraction = (e: React.MouseEvent | React.TouchEvent) => {
8
+ e.preventDefault()
9
+ onClick()
10
+ }
11
+
7
12
  return (
8
13
  <div
9
- onClick={onClick}
14
+ onClick={handleInteraction}
15
+ onTouchEnd={handleInteraction}
10
16
  style={{
11
17
  position: "absolute",
12
18
  top: "16px",
@@ -32,6 +32,7 @@ export const useComponentDragging = ({
32
32
  snapToGrid?: boolean
33
33
  }): {
34
34
  handleMouseDown: (e: React.MouseEvent) => void
35
+ handleTouchStart: (e: React.TouchEvent) => void
35
36
  isDragging: boolean
36
37
  activeEditEvent: EditSchematicComponentLocationEventWithElement | null
37
38
  } => {
@@ -74,45 +75,37 @@ export const useComponentDragging = ({
74
75
  })
75
76
  }, [editEvents])
76
77
 
77
- const handleMouseDown = useCallback(
78
- (e: React.MouseEvent) => {
79
- if (!enabled) return
78
+ const startDrag = useCallback(
79
+ (clientX: number, clientY: number, target: Element) => {
80
+ if (!enabled) return false
80
81
 
81
- const target = e.target as SVGElement
82
82
  const componentGroup = target.closest(
83
83
  '[data-circuit-json-type="schematic_component"]',
84
84
  )
85
- if (!componentGroup) return
85
+ if (!componentGroup) return false
86
86
 
87
87
  const schematic_component_id = componentGroup.getAttribute(
88
88
  "data-schematic-component-id",
89
89
  )
90
- if (!schematic_component_id) return
90
+ if (!schematic_component_id) return false
91
91
 
92
92
  if (cancelDrag) cancelDrag()
93
93
 
94
94
  const schematic_component = su(circuitJson).schematic_component.get(
95
95
  schematic_component_id,
96
96
  )
97
- if (!schematic_component) return
97
+ if (!schematic_component) return false
98
98
 
99
- dragStartPosRef.current = {
100
- x: e.clientX,
101
- y: e.clientY,
102
- }
99
+ dragStartPosRef.current = { x: clientX, y: clientY }
103
100
 
104
- // Get the current position of the component
105
- // Check if we're already tracking this component
106
101
  let current_position: { x: number; y: number }
107
102
  const trackedPosition = componentPositionsRef.current.get(
108
103
  schematic_component_id,
109
104
  )
110
105
 
111
106
  if (trackedPosition) {
112
- // Use the tracked position from previous edits
113
107
  current_position = { ...trackedPosition }
114
108
  } else {
115
- // Calculate position based on component data and edit events
116
109
  const editEventOffset = getComponentOffsetDueToEvents({
117
110
  editEvents,
118
111
  schematic_component_id: schematic_component_id,
@@ -123,7 +116,6 @@ export const useComponentDragging = ({
123
116
  y: schematic_component.center.y + editEventOffset.y,
124
117
  }
125
118
 
126
- // Store this initial position
127
119
  componentPositionsRef.current.set(schematic_component_id, {
128
120
  ...current_position,
129
121
  })
@@ -142,17 +134,36 @@ export const useComponentDragging = ({
142
134
 
143
135
  activeEditEventRef.current = newEditEvent
144
136
  setActiveEditEvent(newEditEvent)
137
+ return true
145
138
  },
146
139
  [cancelDrag, enabled, circuitJson, editEvents],
147
140
  )
148
141
 
149
- const handleMouseMove = useCallback(
150
- (e: MouseEvent) => {
142
+ const handleMouseDown = useCallback(
143
+ (e: React.MouseEvent) => {
144
+ startDrag(e.clientX, e.clientY, e.target as Element)
145
+ },
146
+ [startDrag],
147
+ )
148
+
149
+ const handleTouchStart = useCallback(
150
+ (e: React.TouchEvent) => {
151
+ if (e.touches.length !== 1) return
152
+ const touch = e.touches[0]
153
+ if (startDrag(touch.clientX, touch.clientY, e.target as Element)) {
154
+ e.preventDefault()
155
+ }
156
+ },
157
+ [startDrag],
158
+ )
159
+
160
+ const updateDragPosition = useCallback(
161
+ (clientX: number, clientY: number) => {
151
162
  if (!activeEditEventRef.current || !dragStartPosRef.current) return
152
163
 
153
164
  const screenDelta = {
154
- x: e.clientX - dragStartPosRef.current.x,
155
- y: e.clientY - dragStartPosRef.current.y,
165
+ x: clientX - dragStartPosRef.current.x,
166
+ y: clientY - dragStartPosRef.current.y,
156
167
  }
157
168
 
158
169
  const mmDelta = {
@@ -180,19 +191,33 @@ export const useComponentDragging = ({
180
191
  [realToScreenProjection, snapToGrid],
181
192
  )
182
193
 
183
- const handleMouseUp = useCallback(() => {
194
+ const handleMouseMove = useCallback(
195
+ (e: MouseEvent) => updateDragPosition(e.clientX, e.clientY),
196
+ [updateDragPosition],
197
+ )
198
+
199
+ const handleTouchMove = useCallback(
200
+ (e: TouchEvent) => {
201
+ if (e.touches.length !== 1 || !activeEditEventRef.current) return
202
+ e.preventDefault()
203
+ const touch = e.touches[0]
204
+ updateDragPosition(touch.clientX, touch.clientY)
205
+ },
206
+ [updateDragPosition],
207
+ )
208
+
209
+ const endDrag = useCallback(() => {
184
210
  if (!activeEditEventRef.current) return
185
211
  const finalEvent = {
186
212
  ...activeEditEventRef.current,
187
213
  in_progress: false,
188
214
  }
189
215
 
190
- // Update our stored position for this component
191
216
  componentPositionsRef.current.set(finalEvent.schematic_component_id, {
192
217
  ...finalEvent.new_center,
193
218
  })
194
219
 
195
- debug("handleMouseUp calling onEditEvent with new edit event", {
220
+ debug("endDrag calling onEditEvent with new edit event", {
196
221
  newEditEvent: finalEvent,
197
222
  })
198
223
  if (onEditEvent) onEditEvent(finalEvent)
@@ -201,17 +226,25 @@ export const useComponentDragging = ({
201
226
  setActiveEditEvent(null)
202
227
  }, [onEditEvent])
203
228
 
229
+ const handleMouseUp = useCallback(() => endDrag(), [endDrag])
230
+ const handleTouchEnd = useCallback(() => endDrag(), [endDrag])
231
+
204
232
  useEffect(() => {
205
233
  window.addEventListener("mousemove", handleMouseMove)
206
234
  window.addEventListener("mouseup", handleMouseUp)
235
+ window.addEventListener("touchmove", handleTouchMove, { passive: false })
236
+ window.addEventListener("touchend", handleTouchEnd)
207
237
  return () => {
208
238
  window.removeEventListener("mousemove", handleMouseMove)
209
239
  window.removeEventListener("mouseup", handleMouseUp)
240
+ window.removeEventListener("touchmove", handleTouchMove)
241
+ window.removeEventListener("touchend", handleTouchEnd)
210
242
  }
211
- }, [handleMouseMove, handleMouseUp])
243
+ }, [handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd])
212
244
 
213
245
  return {
214
246
  handleMouseDown,
247
+ handleTouchStart,
215
248
  isDragging: !!activeEditEventRef.current,
216
249
  activeEditEvent: activeEditEvent,
217
250
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-viewer",
3
- "version": "2.0.32",
3
+ "version": "2.0.34",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "scripts": {