@tscircuit/schematic-viewer 2.0.68 → 2.0.70

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
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  convertCircuitJsonToSchematicSvg
4
4
  } from "circuit-to-svg";
5
- import { su as su6 } from "@tscircuit/soup-util";
5
+ import { su as su7 } from "@tscircuit/soup-util";
6
6
 
7
7
  // lib/hooks/useChangeSchematicComponentLocationsInSvg.ts
8
8
  import "@tscircuit/soup-util";
@@ -461,6 +461,125 @@ function calculateGroupBounds(components, svg) {
461
461
  return bounds;
462
462
  }
463
463
 
464
+ // lib/hooks/useSchematicNetHover.ts
465
+ import { su as su4 } from "@tscircuit/soup-util";
466
+ import { useEffect as useEffect4 } from "react";
467
+ var FADED_CLASS = "sch-net-faded";
468
+ var TRACE_SELECTOR = "g.trace[data-subcircuit-connectivity-map-key], g.trace-overlays[data-subcircuit-connectivity-map-key]";
469
+ var NET_LABEL_SELECTOR = "[data-schematic-net-label-id]";
470
+ var useSchematicNetHover = ({
471
+ svgDivRef,
472
+ circuitJson,
473
+ circuitJsonKey,
474
+ enabled
475
+ }) => {
476
+ useEffect4(() => {
477
+ const svgDiv = svgDivRef.current;
478
+ if (!enabled || !svgDiv) return;
479
+ const { componentIdToKeys, netLabelIdToKey } = buildNetRegistry(circuitJson);
480
+ let netElements = [];
481
+ const triggerNetKeys = /* @__PURE__ */ new Map();
482
+ let hoveredNetKey = null;
483
+ const collectNetElements = () => {
484
+ for (const { el } of netElements) el.classList.remove(FADED_CLASS);
485
+ netElements = [];
486
+ triggerNetKeys.clear();
487
+ hoveredNetKey = null;
488
+ const svg = svgDiv.querySelector("svg");
489
+ if (!svg) return;
490
+ for (const el of Array.from(svg.querySelectorAll(TRACE_SELECTOR))) {
491
+ const key = el.getAttribute("data-subcircuit-connectivity-map-key");
492
+ const keys = /* @__PURE__ */ new Set();
493
+ if (key) {
494
+ keys.add(key);
495
+ triggerNetKeys.set(el, key);
496
+ }
497
+ netElements.push({ el, keys });
498
+ }
499
+ for (const el of Array.from(
500
+ svg.querySelectorAll("g[data-schematic-component-id]")
501
+ )) {
502
+ const id = el.getAttribute("data-schematic-component-id");
503
+ netElements.push({ el, keys: componentIdToKeys.get(id) ?? /* @__PURE__ */ new Set() });
504
+ }
505
+ for (const el of Array.from(svg.querySelectorAll(NET_LABEL_SELECTOR))) {
506
+ const key = netLabelIdToKey.get(
507
+ el.getAttribute("data-schematic-net-label-id")
508
+ );
509
+ const keys = /* @__PURE__ */ new Set();
510
+ if (key) {
511
+ keys.add(key);
512
+ triggerNetKeys.set(el, key);
513
+ }
514
+ netElements.push({ el, keys });
515
+ }
516
+ };
517
+ const highlightNet = (key) => {
518
+ if (key === hoveredNetKey) return;
519
+ hoveredNetKey = key;
520
+ for (const { el, keys } of netElements) {
521
+ el.classList.toggle(FADED_CLASS, key !== null && !keys.has(key));
522
+ }
523
+ };
524
+ const handleMouseOver = (e) => {
525
+ const target = e.target;
526
+ if (!(target instanceof Element)) {
527
+ highlightNet(null);
528
+ return;
529
+ }
530
+ const trigger = target.closest(`${TRACE_SELECTOR}, ${NET_LABEL_SELECTOR}`);
531
+ if (!trigger) {
532
+ highlightNet(null);
533
+ return;
534
+ }
535
+ highlightNet(triggerNetKeys.get(trigger) ?? null);
536
+ };
537
+ const handleMouseLeave = () => highlightNet(null);
538
+ collectNetElements();
539
+ svgDiv.addEventListener("mouseover", handleMouseOver);
540
+ svgDiv.addEventListener("mouseleave", handleMouseLeave);
541
+ const observer = new MutationObserver(collectNetElements);
542
+ observer.observe(svgDiv, { childList: true });
543
+ return () => {
544
+ observer.disconnect();
545
+ svgDiv.removeEventListener("mouseover", handleMouseOver);
546
+ svgDiv.removeEventListener("mouseleave", handleMouseLeave);
547
+ for (const { el } of netElements) el.classList.remove(FADED_CLASS);
548
+ };
549
+ }, [svgDivRef, circuitJsonKey, enabled]);
550
+ };
551
+ function buildNetRegistry(circuitJson) {
552
+ const cju = su4(circuitJson);
553
+ const srcCompToSchComp = /* @__PURE__ */ new Map();
554
+ for (const c of cju.schematic_component.list()) {
555
+ if (c.source_component_id) {
556
+ srcCompToSchComp.set(c.source_component_id, c.schematic_component_id);
557
+ }
558
+ }
559
+ const componentIdToKeys = /* @__PURE__ */ new Map();
560
+ for (const sourceTrace of cju.source_trace.list()) {
561
+ const key = sourceTrace.subcircuit_connectivity_map_key;
562
+ if (!key) continue;
563
+ for (const portId of sourceTrace.connected_source_port_ids ?? []) {
564
+ const schCompId = srcCompToSchComp.get(
565
+ cju.source_port.get(portId)?.source_component_id ?? ""
566
+ );
567
+ if (!schCompId) continue;
568
+ if (!componentIdToKeys.has(schCompId)) {
569
+ componentIdToKeys.set(schCompId, /* @__PURE__ */ new Set());
570
+ }
571
+ componentIdToKeys.get(schCompId).add(key);
572
+ }
573
+ }
574
+ const netLabelIdToKey = /* @__PURE__ */ new Map();
575
+ for (const label of cju.schematic_net_label.list()) {
576
+ if (!label.source_net_id) continue;
577
+ const key = cju.source_net.get(label.source_net_id)?.subcircuit_connectivity_map_key ?? label.source_net_id;
578
+ netLabelIdToKey.set(label.schematic_net_label_id, key);
579
+ }
580
+ return { componentIdToKeys, netLabelIdToKey };
581
+ }
582
+
464
583
  // lib/utils/debug.ts
465
584
  import Debug from "debug";
466
585
  var debug = Debug("schematic-viewer");
@@ -470,7 +589,7 @@ var enableDebug = () => {
470
589
  var debug_default = debug;
471
590
 
472
591
  // lib/components/SchematicViewer.tsx
473
- import { useCallback as useCallback6, useEffect as useEffect12, useMemo as useMemo5, useRef as useRef8, useState as useState8 } from "react";
592
+ import { useCallback as useCallback6, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef8, useState as useState6 } from "react";
474
593
  import {
475
594
  fromString,
476
595
  identity,
@@ -479,11 +598,11 @@ import {
479
598
  import { useMouseMatrixTransform } from "use-mouse-matrix-transform";
480
599
 
481
600
  // lib/hooks/use-resize-handling.ts
482
- import { useEffect as useEffect4, useState } from "react";
601
+ import { useEffect as useEffect5, useState } from "react";
483
602
  var useResizeHandling = (containerRef) => {
484
603
  const [containerWidth, setContainerWidth] = useState(0);
485
604
  const [containerHeight, setContainerHeight] = useState(0);
486
- useEffect4(() => {
605
+ useEffect5(() => {
487
606
  if (!containerRef.current) return;
488
607
  const updateDimensions = () => {
489
608
  const rect = containerRef.current?.getBoundingClientRect();
@@ -503,8 +622,8 @@ var useResizeHandling = (containerRef) => {
503
622
  };
504
623
 
505
624
  // lib/hooks/useComponentDragging.ts
506
- import { su as su4 } from "@tscircuit/soup-util";
507
- import { useCallback, useEffect as useEffect5, useRef as useRef3, useState as useState2 } from "react";
625
+ import { su as su5 } from "@tscircuit/soup-util";
626
+ import { useCallback, useEffect as useEffect6, useRef as useRef3, useState as useState2 } from "react";
508
627
  import { compose as compose2 } from "transformation-matrix";
509
628
  var debug2 = debug_default.extend("useComponentDragging");
510
629
  var useComponentDragging = ({
@@ -527,7 +646,7 @@ var useComponentDragging = ({
527
646
  const componentPositionsRef = useRef3(
528
647
  /* @__PURE__ */ new Map()
529
648
  );
530
- useEffect5(() => {
649
+ useEffect6(() => {
531
650
  editEvents.forEach((event) => {
532
651
  if ("edit_event_type" in event && event.edit_event_type === "edit_schematic_component_location" && !event.in_progress) {
533
652
  componentPositionsRef.current.set(event.schematic_component_id, {
@@ -548,7 +667,7 @@ var useComponentDragging = ({
548
667
  );
549
668
  if (!schematic_component_id) return false;
550
669
  if (cancelDrag) cancelDrag();
551
- const schematic_component = su4(circuitJson).schematic_component.get(
670
+ const schematic_component = su5(circuitJson).schematic_component.get(
552
671
  schematic_component_id
553
672
  );
554
673
  if (!schematic_component) return false;
@@ -664,7 +783,7 @@ var useComponentDragging = ({
664
783
  }, [onEditEvent]);
665
784
  const handleMouseUp = useCallback(() => endDrag(), [endDrag]);
666
785
  const handleTouchEnd = useCallback(() => endDrag(), [endDrag]);
667
- useEffect5(() => {
786
+ useEffect6(() => {
668
787
  window.addEventListener("mousemove", handleMouseMove);
669
788
  window.addEventListener("mouseup", handleMouseUp);
670
789
  window.addEventListener("touchmove", handleTouchMove, { passive: false });
@@ -688,7 +807,6 @@ var useComponentDragging = ({
688
807
  var zIndexMap = {
689
808
  schematicEditIcon: 50,
690
809
  schematicGridIcon: 49,
691
- spiceSimulationIcon: 50,
692
810
  viewMenuIcon: 48,
693
811
  viewMenu: 55,
694
812
  viewMenuBackdrop: 54,
@@ -796,22 +914,20 @@ var GridIcon = ({
796
914
 
797
915
  // lib/components/ViewMenu.tsx
798
916
  import { useMemo } from "react";
799
- import { su as su5 } from "@tscircuit/soup-util";
917
+ import { su as su6 } from "@tscircuit/soup-util";
800
918
  import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
801
919
 
802
920
  // package.json
803
921
  var package_default = {
804
922
  name: "@tscircuit/schematic-viewer",
805
- version: "2.0.67",
923
+ version: "2.0.69",
806
924
  main: "dist/index.js",
807
925
  type: "module",
808
926
  scripts: {
809
927
  start: "cosmos",
810
- "build:webworker": "tsup --config tsup-webworker.config.ts",
811
- "build:blob-url": "bun scripts/build-worker-blob-url.ts",
812
- build: "bun run build:webworker && bun run build:blob-url && tsup-node ./lib/index.ts --dts --format esm --sourcemap",
928
+ build: "tsup-node ./lib/index.ts --dts --format esm --sourcemap",
813
929
  "build:site": "cosmos-export",
814
- "vercel-build": "bun run build:webworker && bun run build:blob-url && bun run build:site",
930
+ "vercel-build": "bun run build:site",
815
931
  format: "biome format --write .",
816
932
  "format:check": "biome format ."
817
933
  },
@@ -824,7 +940,6 @@ var package_default = {
824
940
  "@types/debug": "^4.1.12",
825
941
  "@types/react": "^19.0.1",
826
942
  "@types/react-dom": "^19.0.2",
827
- "@types/recharts": "^2.0.1",
828
943
  "@vitejs/plugin-react": "^4.3.4",
829
944
  react: "^19.1.0",
830
945
  "react-cosmos": "^6.2.1",
@@ -832,21 +947,18 @@ var package_default = {
832
947
  "react-dom": "^19.1.0",
833
948
  "react-reconciler": "^0.31.0",
834
949
  semver: "^7.7.2",
835
- tscircuit: "^0.0.1972",
950
+ tscircuit: "^0.0.2012",
836
951
  tsup: "^8.3.5",
837
952
  vite: "^6.0.3"
838
953
  },
839
954
  peerDependencies: {
840
955
  typescript: "^5.0.0",
841
- tscircuit: "*",
842
- "circuit-json-to-spice": "*"
956
+ tscircuit: "*"
843
957
  },
844
958
  dependencies: {
845
959
  "@radix-ui/react-dropdown-menu": "^2.1.16",
846
- "chart.js": "^4.5.0",
847
960
  debug: "^4.4.0",
848
961
  "performance-now": "^2.1.0",
849
- "react-chartjs-2": "^5.3.0",
850
962
  "use-mouse-matrix-transform": "^1.2.2"
851
963
  }
852
964
  };
@@ -976,13 +1088,13 @@ var ViewMenu = ({
976
1088
  const hasGroups = useMemo(() => {
977
1089
  if (!circuitJson || circuitJson.length === 0) return false;
978
1090
  try {
979
- const sourceGroups = su5(circuitJson).source_group?.list() || [];
1091
+ const sourceGroups = su6(circuitJson).source_group?.list() || [];
980
1092
  if (sourceGroups.length > 0) return true;
981
- const schematicComponents = su5(circuitJson).schematic_component?.list() || [];
1093
+ const schematicComponents = su6(circuitJson).schematic_component?.list() || [];
982
1094
  if (schematicComponents.length > 1) {
983
1095
  const componentTypes = /* @__PURE__ */ new Set();
984
1096
  for (const comp of schematicComponents) {
985
- const sourceComp = su5(circuitJson).source_component.get(
1097
+ const sourceComp = su6(circuitJson).source_component.get(
986
1098
  comp.source_component_id
987
1099
  );
988
1100
  if (sourceComp?.ftype) {
@@ -1062,713 +1174,6 @@ var ViewMenu = ({
1062
1174
  ] });
1063
1175
  };
1064
1176
 
1065
- // lib/components/SpiceIcon.tsx
1066
- import { jsx as jsx5 } from "react/jsx-runtime";
1067
- var SpiceIcon = () => /* @__PURE__ */ jsx5(
1068
- "svg",
1069
- {
1070
- width: "16",
1071
- height: "16",
1072
- viewBox: "0 0 24 24",
1073
- fill: "none",
1074
- stroke: "currentColor",
1075
- strokeWidth: "2",
1076
- strokeLinecap: "round",
1077
- strokeLinejoin: "round",
1078
- children: /* @__PURE__ */ jsx5("path", { d: "M3 12h2.5l2.5-9 4 18 4-9h5.5" })
1079
- }
1080
- );
1081
-
1082
- // lib/components/SpiceSimulationIcon.tsx
1083
- import { jsx as jsx6 } from "react/jsx-runtime";
1084
- var SpiceSimulationIcon = ({
1085
- onClick
1086
- }) => {
1087
- return /* @__PURE__ */ jsx6(
1088
- "div",
1089
- {
1090
- onClick,
1091
- title: "Run SPICE simulation",
1092
- style: {
1093
- position: "absolute",
1094
- top: "16px",
1095
- right: "112px",
1096
- backgroundColor: "#fff",
1097
- color: "#000",
1098
- padding: "8px",
1099
- borderRadius: "4px",
1100
- cursor: "pointer",
1101
- boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
1102
- display: "flex",
1103
- alignItems: "center",
1104
- gap: "4px",
1105
- zIndex: zIndexMap.spiceSimulationIcon
1106
- },
1107
- children: /* @__PURE__ */ jsx6(SpiceIcon, {})
1108
- }
1109
- );
1110
- };
1111
-
1112
- // lib/components/SpicePlot.tsx
1113
- import { useMemo as useMemo2 } from "react";
1114
- import {
1115
- Chart as ChartJS,
1116
- CategoryScale,
1117
- LinearScale,
1118
- PointElement,
1119
- LineElement,
1120
- Title,
1121
- Tooltip,
1122
- Legend
1123
- } from "chart.js";
1124
- import { Line } from "react-chartjs-2";
1125
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1126
- ChartJS.register(
1127
- CategoryScale,
1128
- LinearScale,
1129
- PointElement,
1130
- LineElement,
1131
- Title,
1132
- Tooltip,
1133
- Legend
1134
- );
1135
- var colors = ["#8884d8", "#82ca9d", "#ffc658", "#ff7300", "#387908"];
1136
- var formatTimeWithUnits = (seconds) => {
1137
- if (seconds === 0) return "0s";
1138
- const absSeconds = Math.abs(seconds);
1139
- let unit = "s";
1140
- let scale = 1;
1141
- if (absSeconds < 1e-12) {
1142
- unit = "fs";
1143
- scale = 1e15;
1144
- } else if (absSeconds < 1e-9) {
1145
- unit = "ps";
1146
- scale = 1e12;
1147
- } else if (absSeconds < 1e-6) {
1148
- unit = "ns";
1149
- scale = 1e9;
1150
- } else if (absSeconds < 1e-3) {
1151
- unit = "us";
1152
- scale = 1e6;
1153
- } else if (absSeconds < 1) {
1154
- unit = "ms";
1155
- scale = 1e3;
1156
- }
1157
- return `${parseFloat((seconds * scale).toPrecision(3))}${unit}`;
1158
- };
1159
- var SpicePlot = ({
1160
- plotData,
1161
- nodes,
1162
- isLoading,
1163
- error,
1164
- hasRun
1165
- }) => {
1166
- const yAxisLabel = useMemo2(() => {
1167
- const hasVoltage = nodes.some((n) => n.toLowerCase().startsWith("v("));
1168
- const hasCurrent = nodes.some((n) => n.toLowerCase().startsWith("i("));
1169
- if (hasVoltage && hasCurrent) return "Value";
1170
- if (hasVoltage) return "Voltage (V)";
1171
- if (hasCurrent) return "Current (A)";
1172
- return "Value";
1173
- }, [nodes]);
1174
- if (isLoading) {
1175
- return /* @__PURE__ */ jsx7(
1176
- "div",
1177
- {
1178
- style: {
1179
- height: "300px",
1180
- width: "100%",
1181
- display: "flex",
1182
- alignItems: "center",
1183
- justifyContent: "center"
1184
- },
1185
- children: "Running simulation..."
1186
- }
1187
- );
1188
- }
1189
- if (!hasRun) {
1190
- return /* @__PURE__ */ jsx7(
1191
- "div",
1192
- {
1193
- style: {
1194
- height: "300px",
1195
- width: "100%",
1196
- display: "flex",
1197
- alignItems: "center",
1198
- justifyContent: "center"
1199
- },
1200
- children: 'Click "Run" to start the simulation.'
1201
- }
1202
- );
1203
- }
1204
- if (error) {
1205
- return /* @__PURE__ */ jsxs4(
1206
- "div",
1207
- {
1208
- style: {
1209
- height: "300px",
1210
- width: "100%",
1211
- display: "flex",
1212
- alignItems: "center",
1213
- justifyContent: "center",
1214
- color: "red"
1215
- },
1216
- children: [
1217
- "Error: ",
1218
- error
1219
- ]
1220
- }
1221
- );
1222
- }
1223
- if (plotData.length === 0) {
1224
- return /* @__PURE__ */ jsx7(
1225
- "div",
1226
- {
1227
- style: {
1228
- height: "300px",
1229
- width: "100%",
1230
- display: "flex",
1231
- alignItems: "center",
1232
- justifyContent: "center"
1233
- },
1234
- children: "No data to plot. Check simulation output or SPICE netlist."
1235
- }
1236
- );
1237
- }
1238
- const chartData = {
1239
- datasets: nodes.map((node, i) => ({
1240
- label: node,
1241
- data: plotData.map((p) => ({
1242
- x: Number(p.name),
1243
- y: p[node]
1244
- })),
1245
- borderColor: colors[i % colors.length],
1246
- backgroundColor: colors[i % colors.length],
1247
- fill: false,
1248
- tension: 0.1
1249
- }))
1250
- };
1251
- const options = {
1252
- responsive: true,
1253
- maintainAspectRatio: false,
1254
- plugins: {
1255
- legend: {
1256
- position: "top",
1257
- labels: {
1258
- font: {
1259
- family: "sans-serif"
1260
- }
1261
- }
1262
- },
1263
- title: {
1264
- display: false
1265
- },
1266
- tooltip: {
1267
- callbacks: {
1268
- title: (tooltipItems) => {
1269
- if (tooltipItems.length > 0) {
1270
- const item = tooltipItems[0];
1271
- return formatTimeWithUnits(item.parsed.x);
1272
- }
1273
- return "";
1274
- }
1275
- }
1276
- }
1277
- },
1278
- scales: {
1279
- x: {
1280
- type: "linear",
1281
- title: {
1282
- display: true,
1283
- text: "Time",
1284
- font: {
1285
- family: "sans-serif"
1286
- }
1287
- },
1288
- ticks: {
1289
- callback: (value) => formatTimeWithUnits(value),
1290
- font: {
1291
- family: "sans-serif"
1292
- }
1293
- }
1294
- },
1295
- y: {
1296
- title: {
1297
- display: true,
1298
- text: yAxisLabel,
1299
- font: {
1300
- family: "sans-serif"
1301
- }
1302
- },
1303
- ticks: {
1304
- font: {
1305
- family: "sans-serif"
1306
- }
1307
- }
1308
- }
1309
- }
1310
- };
1311
- return /* @__PURE__ */ jsx7("div", { style: { position: "relative", height: "300px", width: "100%" }, children: /* @__PURE__ */ jsx7(Line, { options, data: chartData }) });
1312
- };
1313
-
1314
- // lib/components/SpiceSimulationOverlay.tsx
1315
- import { useEffect as useEffect6, useState as useState3 } from "react";
1316
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1317
- var SpiceSimulationOverlay = ({
1318
- spiceString,
1319
- onClose,
1320
- plotData,
1321
- nodes,
1322
- isLoading,
1323
- error,
1324
- simOptions,
1325
- onSimOptionsChange,
1326
- hasRun
1327
- }) => {
1328
- const [startTimeDraft, setStartTimeDraft] = useState3(
1329
- String(simOptions.startTime)
1330
- );
1331
- const [durationDraft, setDurationDraft] = useState3(
1332
- String(simOptions.duration)
1333
- );
1334
- useEffect6(() => {
1335
- setStartTimeDraft(String(simOptions.startTime));
1336
- setDurationDraft(String(simOptions.duration));
1337
- }, [simOptions.startTime, simOptions.duration]);
1338
- const handleRerun = () => {
1339
- onSimOptionsChange({
1340
- ...simOptions,
1341
- startTime: Number(startTimeDraft),
1342
- duration: Number(durationDraft)
1343
- });
1344
- };
1345
- const filteredNodes = nodes.filter((node) => {
1346
- const isVoltage = node.toLowerCase().startsWith("v(");
1347
- const isCurrent = node.toLowerCase().startsWith("i(");
1348
- if (simOptions.showVoltage && isVoltage) return true;
1349
- if (simOptions.showCurrent && isCurrent) return true;
1350
- return false;
1351
- });
1352
- return /* @__PURE__ */ jsx8(
1353
- "div",
1354
- {
1355
- style: {
1356
- position: "fixed",
1357
- top: 0,
1358
- left: 0,
1359
- right: 0,
1360
- bottom: 0,
1361
- backgroundColor: "rgba(0, 0, 0, 0.5)",
1362
- display: "flex",
1363
- alignItems: "center",
1364
- justifyContent: "center",
1365
- zIndex: 1002,
1366
- fontFamily: "sans-serif"
1367
- },
1368
- children: /* @__PURE__ */ jsxs5(
1369
- "div",
1370
- {
1371
- style: {
1372
- backgroundColor: "white",
1373
- padding: "24px",
1374
- borderRadius: "12px",
1375
- width: "90%",
1376
- maxWidth: "900px",
1377
- boxShadow: "0 4px 20px rgba(0, 0, 0, 0.15)"
1378
- },
1379
- children: [
1380
- /* @__PURE__ */ jsxs5(
1381
- "div",
1382
- {
1383
- style: {
1384
- display: "flex",
1385
- justifyContent: "space-between",
1386
- alignItems: "center",
1387
- marginBottom: "24px",
1388
- borderBottom: "1px solid #eee",
1389
- paddingBottom: "16px"
1390
- },
1391
- children: [
1392
- /* @__PURE__ */ jsx8(
1393
- "h2",
1394
- {
1395
- style: {
1396
- margin: 0,
1397
- fontSize: "22px",
1398
- fontWeight: 600,
1399
- color: "#333"
1400
- },
1401
- children: "SPICE Simulation"
1402
- }
1403
- ),
1404
- /* @__PURE__ */ jsx8(
1405
- "button",
1406
- {
1407
- onClick: onClose,
1408
- style: {
1409
- background: "none",
1410
- border: "none",
1411
- fontSize: "28px",
1412
- cursor: "pointer",
1413
- color: "#888",
1414
- padding: 0,
1415
- lineHeight: 1
1416
- },
1417
- children: "\xD7"
1418
- }
1419
- )
1420
- ]
1421
- }
1422
- ),
1423
- /* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsx8(
1424
- SpicePlot,
1425
- {
1426
- plotData,
1427
- nodes: filteredNodes,
1428
- isLoading,
1429
- error,
1430
- hasRun
1431
- }
1432
- ) }),
1433
- /* @__PURE__ */ jsxs5(
1434
- "div",
1435
- {
1436
- style: {
1437
- marginTop: "16px",
1438
- padding: "12px",
1439
- backgroundColor: "#f7f7f7",
1440
- borderRadius: "6px",
1441
- display: "flex",
1442
- flexWrap: "wrap",
1443
- gap: "24px",
1444
- alignItems: "center",
1445
- fontSize: "14px"
1446
- },
1447
- children: [
1448
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "16px" }, children: [
1449
- /* @__PURE__ */ jsxs5(
1450
- "label",
1451
- {
1452
- style: { display: "flex", alignItems: "center", gap: "6px" },
1453
- children: [
1454
- /* @__PURE__ */ jsx8(
1455
- "input",
1456
- {
1457
- type: "checkbox",
1458
- checked: simOptions.showVoltage,
1459
- onChange: (e) => onSimOptionsChange({
1460
- ...simOptions,
1461
- showVoltage: e.target.checked
1462
- })
1463
- }
1464
- ),
1465
- "Voltage"
1466
- ]
1467
- }
1468
- ),
1469
- /* @__PURE__ */ jsxs5(
1470
- "label",
1471
- {
1472
- style: { display: "flex", alignItems: "center", gap: "6px" },
1473
- children: [
1474
- /* @__PURE__ */ jsx8(
1475
- "input",
1476
- {
1477
- type: "checkbox",
1478
- checked: simOptions.showCurrent,
1479
- onChange: (e) => onSimOptionsChange({
1480
- ...simOptions,
1481
- showCurrent: e.target.checked
1482
- })
1483
- }
1484
- ),
1485
- "Current"
1486
- ]
1487
- }
1488
- )
1489
- ] }),
1490
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "16px", alignItems: "center" }, children: [
1491
- /* @__PURE__ */ jsx8("label", { htmlFor: "startTime", children: "Start Time (ms):" }),
1492
- /* @__PURE__ */ jsx8(
1493
- "input",
1494
- {
1495
- id: "startTime",
1496
- type: "number",
1497
- value: startTimeDraft,
1498
- onChange: (e) => setStartTimeDraft(e.target.value),
1499
- style: {
1500
- width: "80px",
1501
- padding: "4px 8px",
1502
- borderRadius: "4px",
1503
- border: "1px solid #ccc"
1504
- }
1505
- }
1506
- ),
1507
- /* @__PURE__ */ jsx8("label", { htmlFor: "duration", children: "Duration (ms):" }),
1508
- /* @__PURE__ */ jsx8(
1509
- "input",
1510
- {
1511
- id: "duration",
1512
- type: "number",
1513
- value: durationDraft,
1514
- onChange: (e) => setDurationDraft(e.target.value),
1515
- style: {
1516
- width: "80px",
1517
- padding: "4px 8px",
1518
- borderRadius: "4px",
1519
- border: "1px solid #ccc"
1520
- }
1521
- }
1522
- ),
1523
- /* @__PURE__ */ jsx8(
1524
- "button",
1525
- {
1526
- onClick: handleRerun,
1527
- style: {
1528
- padding: "4px 12px",
1529
- borderRadius: "4px",
1530
- border: "1px solid #ccc",
1531
- backgroundColor: "#f0f0f0",
1532
- cursor: "pointer"
1533
- },
1534
- children: hasRun ? "Rerun" : "Run"
1535
- }
1536
- )
1537
- ] })
1538
- ]
1539
- }
1540
- ),
1541
- /* @__PURE__ */ jsxs5("div", { style: { marginTop: "24px" }, children: [
1542
- /* @__PURE__ */ jsx8(
1543
- "h3",
1544
- {
1545
- style: {
1546
- marginTop: 0,
1547
- marginBottom: "12px",
1548
- fontSize: "18px",
1549
- fontWeight: 600,
1550
- color: "#333"
1551
- },
1552
- children: "SPICE Netlist"
1553
- }
1554
- ),
1555
- /* @__PURE__ */ jsx8(
1556
- "pre",
1557
- {
1558
- style: {
1559
- backgroundColor: "#fafafa",
1560
- padding: "16px",
1561
- borderRadius: "6px",
1562
- maxHeight: "150px",
1563
- overflowY: "auto",
1564
- border: "1px solid #eee",
1565
- color: "#333",
1566
- fontSize: "13px",
1567
- fontFamily: "monospace"
1568
- },
1569
- children: spiceString
1570
- }
1571
- )
1572
- ] })
1573
- ]
1574
- }
1575
- )
1576
- }
1577
- );
1578
- };
1579
-
1580
- // lib/hooks/useSpiceSimulation.ts
1581
- import { useState as useState4, useEffect as useEffect7 } from "react";
1582
-
1583
- // lib/workers/spice-simulation.worker.blob.js
1584
- var b64 = "dmFyIGU9bnVsbCxzPWFzeW5jKCk9Pihhd2FpdCBpbXBvcnQoImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWVjaXJjdWl0LWVuZ2luZUAxLjUuMi8rZXNtIikpLlNpbXVsYXRpb24sYz1hc3luYygpPT57aWYoZSYmZS5pc0luaXRpYWxpemVkKCkpcmV0dXJuO2xldCBpPWF3YWl0IHMoKTtlPW5ldyBpLGF3YWl0IGUuc3RhcnQoKX07c2VsZi5vbm1lc3NhZ2U9YXN5bmMgaT0+e3RyeXtpZihhd2FpdCBjKCksIWUpdGhyb3cgbmV3IEVycm9yKCJTaW11bGF0aW9uIG5vdCBpbml0aWFsaXplZCIpO2xldCB0PWkuZGF0YS5zcGljZVN0cmluZyxhPXQubWF0Y2goL3dyZGF0YVxzKyhcUyspXHMrKC4qKS9pKTtpZihhKXtsZXQgbz1gLnByb2JlICR7YVsyXS50cmltKCkuc3BsaXQoL1xzKy8pLmpvaW4oIiAiKX1gO3Q9dC5yZXBsYWNlKC93cmRhdGEuKi9pLG8pfWVsc2UgaWYoIXQubWF0Y2goL1wucHJvYmUvaSkpdGhyb3cgdC5tYXRjaCgvcGxvdFxzKyguKikvaSk/bmV3IEVycm9yKCJUaGUgJ3Bsb3QnIGNvbW1hbmQgaXMgbm90IHN1cHBvcnRlZCBmb3IgZGF0YSBleHRyYWN0aW9uLiBQbGVhc2UgdXNlICd3cmRhdGEgPGZpbGVuYW1lPiA8dmFyMT4gLi4uJyBvciAnLnByb2JlIDx2YXIxPiAuLi4nIGluc3RlYWQuIik6bmV3IEVycm9yKCJObyAnLnByb2JlJyBvciAnd3JkYXRhJyBjb21tYW5kIGZvdW5kIGluIFNQSUNFIGZpbGUuIFVzZSAnd3JkYXRhIDxmaWxlbmFtZT4gPHZhcjE+IC4uLicgdG8gc3BlY2lmeSBvdXRwdXQuIik7ZS5zZXROZXRMaXN0KHQpO2xldCBuPWF3YWl0IGUucnVuU2ltKCk7c2VsZi5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixyZXN1bHQ6bn0pfWNhdGNoKHQpe3NlbGYucG9zdE1lc3NhZ2Uoe3R5cGU6ImVycm9yIixlcnJvcjp0Lm1lc3NhZ2V9KX19Owo=";
1585
- var blobUrl = null;
1586
- var getSpiceSimulationWorkerBlobUrl = () => {
1587
- if (typeof window === "undefined") return null;
1588
- if (blobUrl) return blobUrl;
1589
- try {
1590
- const blob = new Blob([atob(b64)], { type: "application/javascript" });
1591
- blobUrl = URL.createObjectURL(blob);
1592
- return blobUrl;
1593
- } catch (e) {
1594
- console.error("Failed to create blob URL for worker", e);
1595
- return null;
1596
- }
1597
- };
1598
-
1599
- // lib/hooks/useSpiceSimulation.ts
1600
- var parseEecEngineOutput = (result) => {
1601
- const columnData = {};
1602
- if (result.dataType === "real") {
1603
- result.data.forEach((col) => {
1604
- columnData[col.name] = col.values;
1605
- });
1606
- } else if (result.dataType === "complex") {
1607
- result.data.forEach((col) => {
1608
- columnData[col.name] = col.values.map((v) => v.real);
1609
- });
1610
- } else {
1611
- throw new Error("Unsupported data type in simulation result");
1612
- }
1613
- const timeKey = Object.keys(columnData).find(
1614
- (k) => k.toLowerCase() === "time" || k.toLowerCase() === "frequency"
1615
- );
1616
- if (!timeKey) {
1617
- throw new Error("No time or frequency data in simulation result");
1618
- }
1619
- const timeValues = columnData[timeKey];
1620
- const probedVariables = Object.keys(columnData).filter((k) => k !== timeKey);
1621
- const plotableNodes = probedVariables;
1622
- const plotData = timeValues.map((t, i) => {
1623
- const point = { name: t.toExponential(2) };
1624
- probedVariables.forEach((variable) => {
1625
- point[variable] = columnData[variable][i];
1626
- });
1627
- return point;
1628
- });
1629
- return { plotData, nodes: plotableNodes };
1630
- };
1631
- var useSpiceSimulation = (spiceString) => {
1632
- const [plotData, setPlotData] = useState4([]);
1633
- const [nodes, setNodes] = useState4([]);
1634
- const [isLoading, setIsLoading] = useState4(true);
1635
- const [error, setError] = useState4(null);
1636
- useEffect7(() => {
1637
- if (!spiceString) {
1638
- setIsLoading(false);
1639
- setPlotData([]);
1640
- setNodes([]);
1641
- setError(null);
1642
- return;
1643
- }
1644
- setIsLoading(true);
1645
- setError(null);
1646
- setPlotData([]);
1647
- setNodes([]);
1648
- const workerUrl = getSpiceSimulationWorkerBlobUrl();
1649
- if (!workerUrl) {
1650
- setError("Could not create SPICE simulation worker.");
1651
- setIsLoading(false);
1652
- return;
1653
- }
1654
- const worker = new Worker(workerUrl, { type: "module" });
1655
- worker.onmessage = (event) => {
1656
- if (event.data.type === "result") {
1657
- try {
1658
- const { plotData: parsedData, nodes: parsedNodes } = parseEecEngineOutput(event.data.result);
1659
- setPlotData(parsedData);
1660
- setNodes(parsedNodes);
1661
- } catch (e) {
1662
- setError(e.message || "Failed to parse simulation result");
1663
- console.error(e);
1664
- }
1665
- } else if (event.data.type === "error") {
1666
- setError(event.data.error);
1667
- }
1668
- setIsLoading(false);
1669
- };
1670
- worker.onerror = (err) => {
1671
- setError(err.message);
1672
- setIsLoading(false);
1673
- };
1674
- worker.postMessage({ spiceString });
1675
- return () => {
1676
- worker.terminate();
1677
- };
1678
- }, [spiceString]);
1679
- return { plotData, nodes, isLoading, error };
1680
- };
1681
-
1682
- // lib/utils/spice-utils.ts
1683
- import { circuitJsonToSpice } from "circuit-json-to-spice";
1684
- var formatSimTime = (seconds) => {
1685
- if (seconds === 0) return "0";
1686
- const absSeconds = Math.abs(seconds);
1687
- const precision = (v) => v.toPrecision(4);
1688
- if (absSeconds >= 1) return precision(seconds);
1689
- if (absSeconds >= 1e-3) return `${precision(seconds * 1e3)}m`;
1690
- if (absSeconds >= 1e-6) return `${precision(seconds * 1e6)}u`;
1691
- if (absSeconds >= 1e-9) return `${precision(seconds * 1e9)}n`;
1692
- if (absSeconds >= 1e-12) return `${precision(seconds * 1e12)}p`;
1693
- if (absSeconds >= 1e-15) return `${precision(seconds * 1e15)}f`;
1694
- return seconds.toExponential(3);
1695
- };
1696
- var getSpiceFromCircuitJson = (circuitJson, options) => {
1697
- const spiceNetlist = circuitJsonToSpice(circuitJson);
1698
- const baseSpiceString = spiceNetlist.toSpiceString();
1699
- const lines = baseSpiceString.split("\n").filter((l) => l.trim() !== "");
1700
- const componentLines = lines.filter(
1701
- (l) => !l.startsWith("*") && !l.startsWith(".") && l.trim() !== ""
1702
- );
1703
- const allNodes = /* @__PURE__ */ new Set();
1704
- const capacitorNodes = /* @__PURE__ */ new Set();
1705
- const componentNamesToProbeCurrent = /* @__PURE__ */ new Set();
1706
- for (const line of componentLines) {
1707
- const parts = line.trim().split(/\s+/);
1708
- if (parts.length < 3) continue;
1709
- const componentName = parts[0];
1710
- const componentType = componentName[0].toUpperCase();
1711
- let nodesOnLine = [];
1712
- if (["R", "C", "L", "V", "I", "D"].includes(componentType)) {
1713
- nodesOnLine = parts.slice(1, 3);
1714
- if (componentType === "V") {
1715
- componentNamesToProbeCurrent.add(componentName);
1716
- }
1717
- } else if (componentType === "Q" && parts.length >= 4) {
1718
- nodesOnLine = parts.slice(1, 4);
1719
- } else if (componentType === "M" && parts.length >= 5) {
1720
- nodesOnLine = parts.slice(1, 5);
1721
- } else if (componentType === "X") {
1722
- nodesOnLine = parts.slice(1, -1);
1723
- } else {
1724
- continue;
1725
- }
1726
- nodesOnLine.forEach((node) => allNodes.add(node));
1727
- if (componentType === "C") {
1728
- nodesOnLine.forEach((node) => capacitorNodes.add(node));
1729
- }
1730
- }
1731
- allNodes.delete("0");
1732
- capacitorNodes.delete("0");
1733
- const icLines = Array.from(capacitorNodes).map((node) => `.ic V(${node})=0`);
1734
- const probes = [];
1735
- const probeVoltages = Array.from(allNodes).map((node) => `V(${node})`);
1736
- probes.push(...probeVoltages);
1737
- const probeCurrents = Array.from(componentNamesToProbeCurrent).map(
1738
- (name) => `I(${name})`
1739
- );
1740
- probes.push(...probeCurrents);
1741
- const probeLine = probes.length > 0 ? `.probe ${probes.join(" ")}` : "";
1742
- const tstart_ms = options?.startTime ?? 0;
1743
- const duration_ms = options?.duration ?? 20;
1744
- const tstart = tstart_ms * 1e-3;
1745
- const duration = duration_ms * 1e-3;
1746
- const tstop = tstart + duration;
1747
- const tstep = duration / 50;
1748
- const tranLine = `.tran ${formatSimTime(tstep)} ${formatSimTime(
1749
- tstop
1750
- )} ${formatSimTime(tstart)} UIC`;
1751
- const endStatement = ".end";
1752
- const originalLines = baseSpiceString.split("\n");
1753
- let endIndex = -1;
1754
- for (let i = originalLines.length - 1; i >= 0; i--) {
1755
- if (originalLines[i].trim().toLowerCase().startsWith(endStatement)) {
1756
- endIndex = i;
1757
- break;
1758
- }
1759
- }
1760
- const injectionLines = [...icLines, probeLine, tranLine].filter(Boolean);
1761
- let finalLines;
1762
- if (endIndex !== -1) {
1763
- const beforeEnd = originalLines.slice(0, endIndex);
1764
- const endLineAndAfter = originalLines.slice(endIndex);
1765
- finalLines = [...beforeEnd, ...injectionLines, ...endLineAndAfter];
1766
- } else {
1767
- finalLines = [...originalLines, ...injectionLines, endStatement];
1768
- }
1769
- return finalLines.join("\n");
1770
- };
1771
-
1772
1177
  // lib/hooks/useLocalStorage.ts
1773
1178
  import { useCallback as useCallback2 } from "react";
1774
1179
  var STORAGE_KEYS = {
@@ -1812,11 +1217,11 @@ import {
1812
1217
  createContext,
1813
1218
  useCallback as useCallback3,
1814
1219
  useContext,
1815
- useEffect as useEffect8,
1816
- useMemo as useMemo3,
1220
+ useEffect as useEffect7,
1221
+ useMemo as useMemo2,
1817
1222
  useRef as useRef4
1818
1223
  } from "react";
1819
- import { Fragment, jsx as jsx9 } from "react/jsx-runtime";
1224
+ import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
1820
1225
  var MouseTrackerContext = createContext(null);
1821
1226
  var DRAG_THRESHOLD_PX = 5;
1822
1227
  var boundsAreEqual = (a, b) => {
@@ -1827,7 +1232,7 @@ var boundsAreEqual = (a, b) => {
1827
1232
  var MouseTracker = ({ children }) => {
1828
1233
  const existingContext = useContext(MouseTrackerContext);
1829
1234
  if (existingContext) {
1830
- return /* @__PURE__ */ jsx9(Fragment, { children });
1235
+ return /* @__PURE__ */ jsx5(Fragment, { children });
1831
1236
  }
1832
1237
  const storeRef = useRef4({
1833
1238
  pointer: null,
@@ -1896,7 +1301,7 @@ var MouseTracker = ({ children }) => {
1896
1301
  const isHovering = useCallback3((id) => {
1897
1302
  return storeRef.current.hoveringIds.has(id);
1898
1303
  }, []);
1899
- useEffect8(() => {
1304
+ useEffect7(() => {
1900
1305
  const handlePointerPosition = (event) => {
1901
1306
  const { clientX, clientY } = event;
1902
1307
  const pointer = storeRef.current.pointer;
@@ -1964,7 +1369,7 @@ var MouseTracker = ({ children }) => {
1964
1369
  window.removeEventListener("click", handleClick);
1965
1370
  };
1966
1371
  }, [updateHovering]);
1967
- const value = useMemo3(
1372
+ const value = useMemo2(
1968
1373
  () => ({
1969
1374
  registerBoundingBox,
1970
1375
  updateBoundingBox,
@@ -1980,18 +1385,18 @@ var MouseTracker = ({ children }) => {
1980
1385
  isHovering
1981
1386
  ]
1982
1387
  );
1983
- return /* @__PURE__ */ jsx9(MouseTrackerContext.Provider, { value, children });
1388
+ return /* @__PURE__ */ jsx5(MouseTrackerContext.Provider, { value, children });
1984
1389
  };
1985
1390
 
1986
1391
  // lib/components/SchematicComponentMouseTarget.tsx
1987
- import { useCallback as useCallback4, useEffect as useEffect10, useRef as useRef6, useState as useState5 } from "react";
1392
+ import { useCallback as useCallback4, useEffect as useEffect9, useRef as useRef6, useState as useState3 } from "react";
1988
1393
 
1989
1394
  // lib/hooks/useMouseEventsOverBoundingBox.ts
1990
1395
  import {
1991
1396
  useContext as useContext2,
1992
- useEffect as useEffect9,
1397
+ useEffect as useEffect8,
1993
1398
  useId,
1994
- useMemo as useMemo4,
1399
+ useMemo as useMemo3,
1995
1400
  useRef as useRef5,
1996
1401
  useSyncExternalStore
1997
1402
  } from "react";
@@ -2005,13 +1410,13 @@ var useMouseEventsOverBoundingBox = (options) => {
2005
1410
  const id = useId();
2006
1411
  const latestOptionsRef = useRef5(options);
2007
1412
  latestOptionsRef.current = options;
2008
- const handleClick = useMemo4(
1413
+ const handleClick = useMemo3(
2009
1414
  () => (event) => {
2010
1415
  latestOptionsRef.current.onClick?.(event);
2011
1416
  },
2012
1417
  []
2013
1418
  );
2014
- useEffect9(() => {
1419
+ useEffect8(() => {
2015
1420
  context.registerBoundingBox(id, {
2016
1421
  bounds: latestOptionsRef.current.bounds,
2017
1422
  onClick: latestOptionsRef.current.onClick ? handleClick : void 0
@@ -2020,7 +1425,7 @@ var useMouseEventsOverBoundingBox = (options) => {
2020
1425
  context.unregisterBoundingBox(id);
2021
1426
  };
2022
1427
  }, [context, handleClick, id]);
2023
- useEffect9(() => {
1428
+ useEffect8(() => {
2024
1429
  context.updateBoundingBox(id, {
2025
1430
  bounds: latestOptionsRef.current.bounds,
2026
1431
  onClick: latestOptionsRef.current.onClick ? handleClick : void 0
@@ -2044,7 +1449,7 @@ var useMouseEventsOverBoundingBox = (options) => {
2044
1449
  };
2045
1450
 
2046
1451
  // lib/components/SchematicComponentMouseTarget.tsx
2047
- import { jsx as jsx10 } from "react/jsx-runtime";
1452
+ import { jsx as jsx6 } from "react/jsx-runtime";
2048
1453
  var areMeasurementsEqual = (a, b) => {
2049
1454
  if (!a && !b) return true;
2050
1455
  if (!a || !b) return false;
@@ -2059,7 +1464,7 @@ var SchematicComponentMouseTarget = ({
2059
1464
  showOutline,
2060
1465
  circuitJsonKey
2061
1466
  }) => {
2062
- const [measurement, setMeasurement] = useState5(null);
1467
+ const [measurement, setMeasurement] = useState3(null);
2063
1468
  const frameRef = useRef6(null);
2064
1469
  const measure = useCallback4(() => {
2065
1470
  frameRef.current = null;
@@ -2100,10 +1505,10 @@ var SchematicComponentMouseTarget = ({
2100
1505
  if (frameRef.current !== null) return;
2101
1506
  frameRef.current = window.requestAnimationFrame(measure);
2102
1507
  }, [measure]);
2103
- useEffect10(() => {
1508
+ useEffect9(() => {
2104
1509
  scheduleMeasure();
2105
1510
  }, [scheduleMeasure, circuitJsonKey]);
2106
- useEffect10(() => {
1511
+ useEffect9(() => {
2107
1512
  scheduleMeasure();
2108
1513
  const svgDiv = svgDivRef.current;
2109
1514
  const container = containerRef.current;
@@ -2148,7 +1553,7 @@ var SchematicComponentMouseTarget = ({
2148
1553
  bounds,
2149
1554
  onClick: onComponentClick ? handleClick : void 0
2150
1555
  });
2151
- useEffect10(() => {
1556
+ useEffect9(() => {
2152
1557
  if (onHoverChange) {
2153
1558
  onHoverChange(componentId, hovering);
2154
1559
  }
@@ -2157,7 +1562,7 @@ var SchematicComponentMouseTarget = ({
2157
1562
  return null;
2158
1563
  }
2159
1564
  const rect = measurement.rect;
2160
- return /* @__PURE__ */ jsx10(
1565
+ return /* @__PURE__ */ jsx6(
2161
1566
  "div",
2162
1567
  {
2163
1568
  style: {
@@ -2175,8 +1580,8 @@ var SchematicComponentMouseTarget = ({
2175
1580
  };
2176
1581
 
2177
1582
  // lib/components/SchematicPortMouseTarget.tsx
2178
- import { useCallback as useCallback5, useEffect as useEffect11, useRef as useRef7, useState as useState6 } from "react";
2179
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1583
+ import { useCallback as useCallback5, useEffect as useEffect10, useRef as useRef7, useState as useState4 } from "react";
1584
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2180
1585
  var areMeasurementsEqual2 = (a, b) => {
2181
1586
  if (!a && !b) return true;
2182
1587
  if (!a || !b) return false;
@@ -2192,7 +1597,7 @@ var SchematicPortMouseTarget = ({
2192
1597
  showOutline,
2193
1598
  circuitJsonKey
2194
1599
  }) => {
2195
- const [measurement, setMeasurement] = useState6(null);
1600
+ const [measurement, setMeasurement] = useState4(null);
2196
1601
  const frameRef = useRef7(null);
2197
1602
  const measure = useCallback5(() => {
2198
1603
  frameRef.current = null;
@@ -2234,10 +1639,10 @@ var SchematicPortMouseTarget = ({
2234
1639
  if (frameRef.current !== null) return;
2235
1640
  frameRef.current = window.requestAnimationFrame(measure);
2236
1641
  }, [measure]);
2237
- useEffect11(() => {
1642
+ useEffect10(() => {
2238
1643
  scheduleMeasure();
2239
1644
  }, [scheduleMeasure, circuitJsonKey]);
2240
- useEffect11(() => {
1645
+ useEffect10(() => {
2241
1646
  scheduleMeasure();
2242
1647
  const svgDiv = svgDivRef.current;
2243
1648
  const container = containerRef.current;
@@ -2282,7 +1687,7 @@ var SchematicPortMouseTarget = ({
2282
1687
  bounds,
2283
1688
  onClick: onPortClick ? handleClick : void 0
2284
1689
  });
2285
- useEffect11(() => {
1690
+ useEffect10(() => {
2286
1691
  if (onHoverChange) {
2287
1692
  onHoverChange(portId, hovering);
2288
1693
  }
@@ -2291,8 +1696,8 @@ var SchematicPortMouseTarget = ({
2291
1696
  return null;
2292
1697
  }
2293
1698
  const rect = measurement.rect;
2294
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
2295
- /* @__PURE__ */ jsx11(
1699
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1700
+ /* @__PURE__ */ jsx7(
2296
1701
  "div",
2297
1702
  {
2298
1703
  style: {
@@ -2310,7 +1715,7 @@ var SchematicPortMouseTarget = ({
2310
1715
  }
2311
1716
  }
2312
1717
  ),
2313
- hovering && portLabel && /* @__PURE__ */ jsx11(
1718
+ hovering && portLabel && /* @__PURE__ */ jsx7(
2314
1719
  "div",
2315
1720
  {
2316
1721
  style: {
@@ -2335,9 +1740,9 @@ var SchematicPortMouseTarget = ({
2335
1740
  };
2336
1741
 
2337
1742
  // lib/components/SchematicSheetSelector.tsx
2338
- import { useState as useState7 } from "react";
1743
+ import { useState as useState5 } from "react";
2339
1744
  import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
2340
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1745
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2341
1746
  var FONT_FAMILY2 = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2342
1747
  var contentStyles2 = {
2343
1748
  backgroundColor: "#ffffff",
@@ -2387,7 +1792,7 @@ var MENU_CSS = `
2387
1792
  .sv-sheet-chevron { transition: transform 0.2s ease; }
2388
1793
  [data-state="open"] > .sv-sheet-chevron { transform: rotate(180deg); }
2389
1794
  `;
2390
- var CheckIcon2 = () => /* @__PURE__ */ jsx12(
1795
+ var CheckIcon2 = () => /* @__PURE__ */ jsx8(
2391
1796
  "svg",
2392
1797
  {
2393
1798
  width: "14",
@@ -2399,10 +1804,10 @@ var CheckIcon2 = () => /* @__PURE__ */ jsx12(
2399
1804
  strokeLinecap: "round",
2400
1805
  strokeLinejoin: "round",
2401
1806
  "aria-hidden": "true",
2402
- children: /* @__PURE__ */ jsx12("path", { d: "M20 6 9 17l-5-5" })
1807
+ children: /* @__PURE__ */ jsx8("path", { d: "M20 6 9 17l-5-5" })
2403
1808
  }
2404
1809
  );
2405
- var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsx12(
1810
+ var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsx8(
2406
1811
  "svg",
2407
1812
  {
2408
1813
  className,
@@ -2416,7 +1821,7 @@ var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsx12(
2416
1821
  strokeLinejoin: "round",
2417
1822
  style: { opacity: 0.6, flexShrink: 0 },
2418
1823
  "aria-hidden": "true",
2419
- children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" })
1824
+ children: /* @__PURE__ */ jsx8("path", { d: "m6 9 6 6 6-6" })
2420
1825
  }
2421
1826
  );
2422
1827
  var SchematicSheetSelector = ({
@@ -2424,16 +1829,16 @@ var SchematicSheetSelector = ({
2424
1829
  selectedSheetId,
2425
1830
  onSelectSheet
2426
1831
  }) => {
2427
- const [open, setOpen] = useState7(false);
1832
+ const [open, setOpen] = useState5(false);
2428
1833
  if (sheets.length <= 1) return null;
2429
1834
  const selectedSheet = sheets.find(
2430
1835
  (s) => s.schematic_sheet_id === selectedSheetId
2431
1836
  );
2432
1837
  const selectedLabel = selectedSheet?.name ?? "Select sheet";
2433
- return /* @__PURE__ */ jsxs7(Fragment3, { children: [
2434
- /* @__PURE__ */ jsx12("style", { children: MENU_CSS }),
2435
- /* @__PURE__ */ jsxs7(DropdownMenu2.Root, { open, onOpenChange: setOpen, modal: false, children: [
2436
- /* @__PURE__ */ jsx12(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs7(
1838
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
1839
+ /* @__PURE__ */ jsx8("style", { children: MENU_CSS }),
1840
+ /* @__PURE__ */ jsxs5(DropdownMenu2.Root, { open, onOpenChange: setOpen, modal: false, children: [
1841
+ /* @__PURE__ */ jsx8(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
2437
1842
  "button",
2438
1843
  {
2439
1844
  type: "button",
@@ -2460,13 +1865,13 @@ var SchematicSheetSelector = ({
2460
1865
  zIndex: zIndexMap.viewMenuIcon
2461
1866
  },
2462
1867
  children: [
2463
- /* @__PURE__ */ jsx12("span", { style: { color: "#888888", flexShrink: 0 }, children: "Sheet:" }),
2464
- /* @__PURE__ */ jsx12("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: selectedLabel }),
2465
- /* @__PURE__ */ jsx12(ChevronDownIcon, { className: "sv-sheet-chevron" })
1868
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888888", flexShrink: 0 }, children: "Sheet:" }),
1869
+ /* @__PURE__ */ jsx8("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: selectedLabel }),
1870
+ /* @__PURE__ */ jsx8(ChevronDownIcon, { className: "sv-sheet-chevron" })
2466
1871
  ]
2467
1872
  }
2468
1873
  ) }),
2469
- /* @__PURE__ */ jsx12(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsx12(
1874
+ /* @__PURE__ */ jsx8(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsx8(
2470
1875
  DropdownMenu2.Content,
2471
1876
  {
2472
1877
  style: contentStyles2,
@@ -2476,7 +1881,7 @@ var SchematicSheetSelector = ({
2476
1881
  collisionPadding: 10,
2477
1882
  children: sheets.map((sheet) => {
2478
1883
  const selected = sheet.schematic_sheet_id === selectedSheetId;
2479
- return /* @__PURE__ */ jsxs7(
1884
+ return /* @__PURE__ */ jsxs5(
2480
1885
  DropdownMenu2.Item,
2481
1886
  {
2482
1887
  className: "sv-sheet-item",
@@ -2488,8 +1893,8 @@ var SchematicSheetSelector = ({
2488
1893
  setOpen(false);
2489
1894
  },
2490
1895
  children: [
2491
- /* @__PURE__ */ jsx12("span", { style: iconSlotStyles2, children: selected && /* @__PURE__ */ jsx12(CheckIcon2, {}) }),
2492
- /* @__PURE__ */ jsx12("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: sheet.name })
1896
+ /* @__PURE__ */ jsx8("span", { style: iconSlotStyles2, children: selected && /* @__PURE__ */ jsx8(CheckIcon2, {}) }),
1897
+ /* @__PURE__ */ jsx8("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: sheet.name })
2493
1898
  ]
2494
1899
  },
2495
1900
  sheet.schematic_sheet_id
@@ -2502,7 +1907,7 @@ var SchematicSheetSelector = ({
2502
1907
  };
2503
1908
 
2504
1909
  // lib/components/SchematicViewer.tsx
2505
- import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1910
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2506
1911
  var SchematicViewer = ({
2507
1912
  circuitJson,
2508
1913
  containerStyle,
@@ -2514,8 +1919,8 @@ var SchematicViewer = ({
2514
1919
  debug: debug3 = false,
2515
1920
  clickToInteractEnabled = false,
2516
1921
  colorOverrides,
2517
- spiceSimulationEnabled = false,
2518
1922
  disableGroups = false,
1923
+ netHoverHighlightEnabled = true,
2519
1924
  onSchematicComponentClicked,
2520
1925
  showSchematicPorts = false,
2521
1926
  onSchematicPortClicked,
@@ -2526,23 +1931,14 @@ var SchematicViewer = ({
2526
1931
  if (debug3) {
2527
1932
  enableDebug();
2528
1933
  }
2529
- const [showSpiceOverlay, setShowSpiceOverlay] = useState8(false);
2530
- const [spiceSimOptions, setSpiceSimOptions] = useState8({
2531
- showVoltage: true,
2532
- showCurrent: false,
2533
- startTime: 0,
2534
- // in ms
2535
- duration: 20
2536
- // in ms
2537
- });
2538
1934
  const getCircuitHash = (circuitJson2) => {
2539
1935
  return `${circuitJson2?.length || 0}_${circuitJson2?.editCount || 0}`;
2540
1936
  };
2541
- const circuitJsonKey = useMemo5(
1937
+ const circuitJsonKey = useMemo4(
2542
1938
  () => getCircuitHash(circuitJson),
2543
1939
  [circuitJson]
2544
1940
  );
2545
- const schematicSheets = useMemo5(() => {
1941
+ const schematicSheets = useMemo4(() => {
2546
1942
  try {
2547
1943
  return circuitJson.filter((elm) => elm?.type === "schematic_sheet").slice().sort((a, b) => (a.sheet_index ?? 0) - (b.sheet_index ?? 0));
2548
1944
  } catch (err) {
@@ -2552,7 +1948,7 @@ var SchematicViewer = ({
2552
1948
  }, [circuitJsonKey]);
2553
1949
  const hasMultipleSheets = schematicSheets.length > 1;
2554
1950
  const defaultSheetId = schematicSheets[0]?.schematic_sheet_id;
2555
- const [selectedSheetId, setSelectedSheetId] = useState8(
1951
+ const [selectedSheetId, setSelectedSheetId] = useState6(
2556
1952
  () => {
2557
1953
  const stored = getStoredString(STORAGE_KEYS.SELECTED_SCHEMATIC_SHEET);
2558
1954
  if (stored && schematicSheets.some((s) => s.schematic_sheet_id === stored)) {
@@ -2561,7 +1957,7 @@ var SchematicViewer = ({
2561
1957
  return defaultSheetId;
2562
1958
  }
2563
1959
  );
2564
- useEffect12(() => {
1960
+ useEffect11(() => {
2565
1961
  const stillExists = selectedSheetId !== void 0 && schematicSheets.some((s) => s.schematic_sheet_id === selectedSheetId);
2566
1962
  if (!stillExists) {
2567
1963
  setSelectedSheetId(defaultSheetId);
@@ -2576,43 +1972,19 @@ var SchematicViewer = ({
2576
1972
  },
2577
1973
  [onSchematicSheetChange]
2578
1974
  );
2579
- const spiceString = useMemo5(() => {
2580
- if (!spiceSimulationEnabled) return null;
2581
- try {
2582
- return getSpiceFromCircuitJson(circuitJson, spiceSimOptions);
2583
- } catch (e) {
2584
- console.error("Failed to generate SPICE string", e);
2585
- return null;
2586
- }
2587
- }, [
2588
- circuitJsonKey,
2589
- spiceSimulationEnabled,
2590
- spiceSimOptions.startTime,
2591
- spiceSimOptions.duration
2592
- ]);
2593
- const [hasSpiceSimRun, setHasSpiceSimRun] = useState8(false);
2594
- useEffect12(() => {
2595
- setHasSpiceSimRun(false);
2596
- }, [circuitJsonKey]);
2597
- const {
2598
- plotData,
2599
- nodes,
2600
- isLoading: isSpiceSimLoading,
2601
- error: spiceSimError
2602
- } = useSpiceSimulation(hasSpiceSimRun ? spiceString : null);
2603
- const [editModeEnabled, setEditModeEnabled] = useState8(defaultEditMode);
2604
- const [snapToGrid, setSnapToGrid] = useState8(true);
2605
- const [showGridInternal, setShowGridInternal] = useState8(false);
1975
+ const [editModeEnabled, setEditModeEnabled] = useState6(defaultEditMode);
1976
+ const [snapToGrid, setSnapToGrid] = useState6(true);
1977
+ const [showGridInternal, setShowGridInternal] = useState6(false);
2606
1978
  const showGrid = debugGrid || showGridInternal;
2607
- const [isInteractionEnabled, setIsInteractionEnabled] = useState8(
1979
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState6(
2608
1980
  !clickToInteractEnabled
2609
1981
  );
2610
- const [showViewMenu, setShowViewMenu] = useState8(false);
2611
- const [showSchematicGroups, setShowSchematicGroups] = useState8(() => {
1982
+ const [showViewMenu, setShowViewMenu] = useState6(false);
1983
+ const [showSchematicGroups, setShowSchematicGroups] = useState6(() => {
2612
1984
  if (disableGroups) return false;
2613
1985
  return getStoredBoolean("schematic_viewer_show_groups", false);
2614
1986
  });
2615
- const [isHoveringClickableComponent, setIsHoveringClickableComponent] = useState8(false);
1987
+ const [isHoveringClickableComponent, setIsHoveringClickableComponent] = useState6(false);
2616
1988
  const hoveringComponentsRef = useRef8(/* @__PURE__ */ new Set());
2617
1989
  const handleComponentHoverChange = useCallback6(
2618
1990
  (componentId, isHovering) => {
@@ -2625,7 +1997,7 @@ var SchematicViewer = ({
2625
1997
  },
2626
1998
  []
2627
1999
  );
2628
- const [isHoveringClickablePort, setIsHoveringClickablePort] = useState8(false);
2000
+ const [isHoveringClickablePort, setIsHoveringClickablePort] = useState6(false);
2629
2001
  const hoveringPortsRef = useRef8(/* @__PURE__ */ new Set());
2630
2002
  const handlePortHoverChange = useCallback6(
2631
2003
  (portId, isHovering) => {
@@ -2640,9 +2012,9 @@ var SchematicViewer = ({
2640
2012
  );
2641
2013
  const svgDivRef = useRef8(null);
2642
2014
  const touchStartRef = useRef8(null);
2643
- const schematicComponentIds = useMemo5(() => {
2015
+ const schematicComponentIds = useMemo4(() => {
2644
2016
  try {
2645
- const components = su6(circuitJson).schematic_component?.list() ?? [];
2017
+ const components = su7(circuitJson).schematic_component?.list() ?? [];
2646
2018
  return components.filter(
2647
2019
  (component) => !activeSheetId || component.schematic_sheet_id === activeSheetId
2648
2020
  ).map((component) => component.schematic_component_id);
@@ -2651,15 +2023,15 @@ var SchematicViewer = ({
2651
2023
  return [];
2652
2024
  }
2653
2025
  }, [circuitJsonKey, circuitJson, activeSheetId]);
2654
- const schematicPortsInfo = useMemo5(() => {
2026
+ const schematicPortsInfo = useMemo4(() => {
2655
2027
  if (!showSchematicPorts) return [];
2656
2028
  try {
2657
- const ports = (su6(circuitJson).schematic_port?.list() ?? []).filter(
2029
+ const ports = (su7(circuitJson).schematic_port?.list() ?? []).filter(
2658
2030
  (port) => !activeSheetId || port.schematic_sheet_id === activeSheetId
2659
2031
  );
2660
2032
  return ports.map((port) => {
2661
- const sourcePort = su6(circuitJson).source_port.get(port.source_port_id);
2662
- const sourceComponent = sourcePort?.source_component_id ? su6(circuitJson).source_component.get(sourcePort.source_component_id) : null;
2033
+ const sourcePort = su7(circuitJson).source_port.get(port.source_port_id);
2034
+ const sourceComponent = sourcePort?.source_component_id ? su7(circuitJson).source_component.get(sourcePort.source_component_id) : null;
2663
2035
  const componentName = sourceComponent?.name ?? "?";
2664
2036
  const pinLabel = port.display_pin_label ?? sourcePort?.pin_number ?? sourcePort?.name ?? "?";
2665
2037
  return {
@@ -2691,9 +2063,9 @@ var SchematicViewer = ({
2691
2063
  }
2692
2064
  touchStartRef.current = null;
2693
2065
  };
2694
- const [internalEditEvents, setInternalEditEvents] = useState8([]);
2066
+ const [internalEditEvents, setInternalEditEvents] = useState6([]);
2695
2067
  const circuitJsonRef = useRef8(circuitJson);
2696
- useEffect12(() => {
2068
+ useEffect11(() => {
2697
2069
  const circuitHash = getCircuitHash(circuitJson);
2698
2070
  const circuitHashRef = getCircuitHash(circuitJsonRef.current);
2699
2071
  if (circuitHash !== circuitHashRef) {
@@ -2711,10 +2083,10 @@ var SchematicViewer = ({
2711
2083
  svgDivRef.current.style.transform = transformToString(transform);
2712
2084
  },
2713
2085
  // @ts-ignore disabled is a valid prop but not typed
2714
- enabled: isInteractionEnabled && !showSpiceOverlay
2086
+ enabled: isInteractionEnabled
2715
2087
  });
2716
2088
  const { containerWidth, containerHeight } = useResizeHandling(containerRef);
2717
- const svgString = useMemo5(() => {
2089
+ const svgString = useMemo4(() => {
2718
2090
  if (!containerWidth || !containerHeight) return "";
2719
2091
  return convertCircuitJsonToSchematicSvg(circuitJson, {
2720
2092
  width: containerWidth,
@@ -2737,13 +2109,13 @@ var SchematicViewer = ({
2737
2109
  showSchematicPorts,
2738
2110
  activeSheetId
2739
2111
  ]);
2740
- const containerBackgroundColor = useMemo5(() => {
2112
+ const containerBackgroundColor = useMemo4(() => {
2741
2113
  const match = svgString.match(
2742
2114
  /<svg[^>]*style="[^"]*background-color:\s*([^;\"]+)/i
2743
2115
  );
2744
2116
  return match?.[1] ?? "transparent";
2745
2117
  }, [svgString]);
2746
- const realToSvgProjection = useMemo5(() => {
2118
+ const realToSvgProjection = useMemo4(() => {
2747
2119
  if (!svgString) return identity();
2748
2120
  const transformString = svgString.match(
2749
2121
  /data-real-to-screen-transform="([^"]+)"/
@@ -2761,7 +2133,7 @@ var SchematicViewer = ({
2761
2133
  onEditEvent(event);
2762
2134
  }
2763
2135
  };
2764
- const editEventsWithUnappliedEditEvents = useMemo5(() => {
2136
+ const editEventsWithUnappliedEditEvents = useMemo4(() => {
2765
2137
  return [...unappliedEditEvents, ...internalEditEvents];
2766
2138
  }, [unappliedEditEvents, internalEditEvents]);
2767
2139
  const {
@@ -2776,7 +2148,7 @@ var SchematicViewer = ({
2776
2148
  svgToScreenProjection,
2777
2149
  circuitJson,
2778
2150
  editEvents: editEventsWithUnappliedEditEvents,
2779
- enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
2151
+ enabled: editModeEnabled && isInteractionEnabled,
2780
2152
  snapToGrid
2781
2153
  });
2782
2154
  useChangeSchematicComponentLocationsInSvg({
@@ -2798,12 +2170,18 @@ var SchematicViewer = ({
2798
2170
  circuitJsonKey: `${circuitJsonKey}_${activeSheetId ?? ""}`,
2799
2171
  showGroups: showSchematicGroups && !disableGroups
2800
2172
  });
2173
+ useSchematicNetHover({
2174
+ svgDivRef,
2175
+ circuitJson,
2176
+ circuitJsonKey: `${circuitJsonKey}_${activeSheetId ?? ""}`,
2177
+ enabled: netHoverHighlightEnabled
2178
+ });
2801
2179
  const handleComponentTouchStartRef = useRef8(handleComponentTouchStart);
2802
- useEffect12(() => {
2180
+ useEffect11(() => {
2803
2181
  handleComponentTouchStartRef.current = handleComponentTouchStart;
2804
2182
  }, [handleComponentTouchStart]);
2805
- const svgDiv = useMemo5(
2806
- () => /* @__PURE__ */ jsx13(
2183
+ const svgDiv = useMemo4(
2184
+ () => /* @__PURE__ */ jsx9(
2807
2185
  "div",
2808
2186
  {
2809
2187
  ref: svgDivRef,
@@ -2813,25 +2191,21 @@ var SchematicViewer = ({
2813
2191
  },
2814
2192
  className: onSchematicComponentClicked ? "schematic-component-clickable" : void 0,
2815
2193
  onTouchStart: (e) => {
2816
- if (editModeEnabled && isInteractionEnabled && !showSpiceOverlay) {
2194
+ if (editModeEnabled && isInteractionEnabled) {
2817
2195
  handleComponentTouchStartRef.current(e);
2818
2196
  }
2819
2197
  },
2820
2198
  dangerouslySetInnerHTML: { __html: svgString }
2821
2199
  }
2822
2200
  ),
2823
- [
2824
- svgString,
2825
- isInteractionEnabled,
2826
- clickToInteractEnabled,
2827
- editModeEnabled,
2828
- showSpiceOverlay
2829
- ]
2201
+ [svgString, isInteractionEnabled, clickToInteractEnabled, editModeEnabled]
2830
2202
  );
2831
- return /* @__PURE__ */ jsxs8(MouseTracker, { children: [
2832
- onSchematicComponentClicked && /* @__PURE__ */ jsx13("style", { children: `.schematic-component-clickable [data-schematic-component-id]:hover { cursor: pointer !important; }` }),
2833
- onSchematicPortClicked && /* @__PURE__ */ jsx13("style", { children: `[data-schematic-port-id]:hover { cursor: pointer !important; }` }),
2834
- /* @__PURE__ */ jsxs8(
2203
+ return /* @__PURE__ */ jsxs6(MouseTracker, { children: [
2204
+ netHoverHighlightEnabled && /* @__PURE__ */ jsx9("style", { children: `.sch-net-faded { opacity: 0.35; }
2205
+ svg :is(g.trace, g.trace-overlays, g[data-schematic-component-id], [data-schematic-net-label-id]) { transition: opacity 0.12s ease-in-out; }` }),
2206
+ onSchematicComponentClicked && /* @__PURE__ */ jsx9("style", { children: `.schematic-component-clickable [data-schematic-component-id]:hover { cursor: pointer !important; }` }),
2207
+ onSchematicPortClicked && /* @__PURE__ */ jsx9("style", { children: `[data-schematic-port-id]:hover { cursor: pointer !important; }` }),
2208
+ /* @__PURE__ */ jsxs6(
2835
2209
  "div",
2836
2210
  {
2837
2211
  ref: containerRef,
@@ -2839,15 +2213,10 @@ var SchematicViewer = ({
2839
2213
  position: "relative",
2840
2214
  backgroundColor: containerBackgroundColor,
2841
2215
  overflow: "hidden",
2842
- cursor: showSpiceOverlay ? "auto" : isDragging ? "grabbing" : clickToInteractEnabled && !isInteractionEnabled ? "pointer" : isHoveringClickableComponent && onSchematicComponentClicked ? "pointer" : isHoveringClickablePort && onSchematicPortClicked ? "pointer" : "grab",
2216
+ cursor: isDragging ? "grabbing" : clickToInteractEnabled && !isInteractionEnabled ? "pointer" : isHoveringClickableComponent && onSchematicComponentClicked ? "pointer" : isHoveringClickablePort && onSchematicPortClicked ? "pointer" : "grab",
2843
2217
  minHeight: "300px",
2844
2218
  ...containerStyle
2845
2219
  },
2846
- onWheelCapture: (e) => {
2847
- if (showSpiceOverlay) {
2848
- e.stopPropagation();
2849
- }
2850
- },
2851
2220
  onMouseDown: (e) => {
2852
2221
  if (clickToInteractEnabled && !isInteractionEnabled) {
2853
2222
  e.preventDefault();
@@ -2863,16 +2232,10 @@ var SchematicViewer = ({
2863
2232
  return;
2864
2233
  }
2865
2234
  },
2866
- onTouchStart: (e) => {
2867
- if (showSpiceOverlay) return;
2868
- handleTouchStart(e);
2869
- },
2870
- onTouchEnd: (e) => {
2871
- if (showSpiceOverlay) return;
2872
- handleTouchEnd(e);
2873
- },
2235
+ onTouchStart: handleTouchStart,
2236
+ onTouchEnd: handleTouchEnd,
2874
2237
  children: [
2875
- !isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx13(
2238
+ !isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx9(
2876
2239
  "div",
2877
2240
  {
2878
2241
  onClick: (e) => {
@@ -2891,7 +2254,7 @@ var SchematicViewer = ({
2891
2254
  pointerEvents: "all",
2892
2255
  touchAction: "pan-x pan-y pinch-zoom"
2893
2256
  },
2894
- children: /* @__PURE__ */ jsx13(
2257
+ children: /* @__PURE__ */ jsx9(
2895
2258
  "div",
2896
2259
  {
2897
2260
  style: {
@@ -2908,21 +2271,21 @@ var SchematicViewer = ({
2908
2271
  )
2909
2272
  }
2910
2273
  ),
2911
- editingEnabled && /* @__PURE__ */ jsx13(
2274
+ editingEnabled && /* @__PURE__ */ jsx9(
2912
2275
  EditIcon,
2913
2276
  {
2914
2277
  active: editModeEnabled,
2915
2278
  onClick: () => setEditModeEnabled(!editModeEnabled)
2916
2279
  }
2917
2280
  ),
2918
- editingEnabled && editModeEnabled && /* @__PURE__ */ jsx13(
2281
+ editingEnabled && editModeEnabled && /* @__PURE__ */ jsx9(
2919
2282
  GridIcon,
2920
2283
  {
2921
2284
  active: snapToGrid,
2922
2285
  onClick: () => setSnapToGrid(!snapToGrid)
2923
2286
  }
2924
2287
  ),
2925
- /* @__PURE__ */ jsx13(
2288
+ /* @__PURE__ */ jsx9(
2926
2289
  ViewMenu,
2927
2290
  {
2928
2291
  circuitJson,
@@ -2940,7 +2303,7 @@ var SchematicViewer = ({
2940
2303
  onToggleGrid: setShowGridInternal
2941
2304
  }
2942
2305
  ),
2943
- /* @__PURE__ */ jsx13(
2306
+ /* @__PURE__ */ jsx9(
2944
2307
  SchematicSheetSelector,
2945
2308
  {
2946
2309
  sheets: schematicSheets,
@@ -2948,25 +2311,7 @@ var SchematicViewer = ({
2948
2311
  onSelectSheet: handleSelectSheet
2949
2312
  }
2950
2313
  ),
2951
- spiceSimulationEnabled && /* @__PURE__ */ jsx13(SpiceSimulationIcon, { onClick: () => setShowSpiceOverlay(true) }),
2952
- showSpiceOverlay && /* @__PURE__ */ jsx13(
2953
- SpiceSimulationOverlay,
2954
- {
2955
- spiceString,
2956
- onClose: () => setShowSpiceOverlay(false),
2957
- plotData,
2958
- nodes,
2959
- isLoading: isSpiceSimLoading,
2960
- error: spiceSimError,
2961
- simOptions: spiceSimOptions,
2962
- onSimOptionsChange: (options) => {
2963
- setHasSpiceSimRun(true);
2964
- setSpiceSimOptions(options);
2965
- },
2966
- hasRun: hasSpiceSimRun
2967
- }
2968
- ),
2969
- onSchematicComponentClicked && schematicComponentIds.map((componentId) => /* @__PURE__ */ jsx13(
2314
+ onSchematicComponentClicked && schematicComponentIds.map((componentId) => /* @__PURE__ */ jsx9(
2970
2315
  SchematicComponentMouseTarget,
2971
2316
  {
2972
2317
  componentId,
@@ -2985,7 +2330,7 @@ var SchematicViewer = ({
2985
2330
  componentId
2986
2331
  )),
2987
2332
  svgDiv,
2988
- showSchematicPorts && schematicPortsInfo.map(({ portId, label }) => /* @__PURE__ */ jsx13(
2333
+ showSchematicPorts && schematicPortsInfo.map(({ portId, label }) => /* @__PURE__ */ jsx9(
2989
2334
  SchematicPortMouseTarget,
2990
2335
  {
2991
2336
  portId,
@@ -3014,10 +2359,10 @@ var SchematicViewer = ({
3014
2359
  import {
3015
2360
  convertCircuitJsonToSchematicSimulationSvg
3016
2361
  } from "circuit-to-svg";
3017
- import { useEffect as useEffect13, useState as useState9, useMemo as useMemo6, useRef as useRef9 } from "react";
2362
+ import { useEffect as useEffect12, useState as useState7, useMemo as useMemo5, useRef as useRef9 } from "react";
3018
2363
  import { useMouseMatrixTransform as useMouseMatrixTransform2 } from "use-mouse-matrix-transform";
3019
2364
  import { toString as transformToString2 } from "transformation-matrix";
3020
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
2365
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
3021
2366
  var DEFAULT_RENDER_WIDTH = 1200;
3022
2367
  var DEFAULT_RENDER_ASPECT_RATIO = 1;
3023
2368
  var AnalogSimulationViewer = ({
@@ -3028,16 +2373,16 @@ var AnalogSimulationViewer = ({
3028
2373
  height,
3029
2374
  className
3030
2375
  }) => {
3031
- const [circuitJson, setCircuitJson] = useState9(null);
3032
- const [isLoading, setIsLoading] = useState9(true);
3033
- const [error, setError] = useState9(null);
3034
- const [svgObjectUrl, setSvgObjectUrl] = useState9(null);
2376
+ const [circuitJson, setCircuitJson] = useState7(null);
2377
+ const [isLoading, setIsLoading] = useState7(true);
2378
+ const [error, setError] = useState7(null);
2379
+ const [svgObjectUrl, setSvgObjectUrl] = useState7(null);
3035
2380
  const containerRef = useRef9(null);
3036
2381
  const imgRef = useRef9(null);
3037
2382
  const { containerWidth } = useResizeHandling(
3038
2383
  containerRef
3039
2384
  );
3040
- const [isDragging, setIsDragging] = useState9(false);
2385
+ const [isDragging, setIsDragging] = useState7(false);
3041
2386
  const {
3042
2387
  ref: transformRef,
3043
2388
  cancelDrag: _cancelDrag,
@@ -3052,28 +2397,28 @@ var AnalogSimulationViewer = ({
3052
2397
  const renderAspectRatio = width && height ? width / height : DEFAULT_RENDER_ASPECT_RATIO;
3053
2398
  const effectiveWidth = width || (height ? height * renderAspectRatio : containerWidth) || DEFAULT_RENDER_WIDTH;
3054
2399
  const effectiveHeight = height || effectiveWidth / renderAspectRatio;
3055
- useEffect13(() => {
2400
+ useEffect12(() => {
3056
2401
  setIsLoading(true);
3057
2402
  setError(null);
3058
2403
  setCircuitJson(inputCircuitJson);
3059
2404
  setIsLoading(false);
3060
2405
  }, [inputCircuitJson]);
3061
- const simulationExperimentId = useMemo6(() => {
2406
+ const simulationExperimentId = useMemo5(() => {
3062
2407
  if (!circuitJson) return null;
3063
2408
  const simulationElement = circuitJson.find(
3064
2409
  (el) => el.type === "simulation_experiment"
3065
2410
  );
3066
2411
  return simulationElement?.simulation_experiment_id || null;
3067
2412
  }, [circuitJson]);
3068
- const simulationVoltageGraphIds = useMemo6(() => {
2413
+ const simulationVoltageGraphIds = useMemo5(() => {
3069
2414
  if (!circuitJson) return [];
3070
2415
  return circuitJson.filter((el) => el.type === "simulation_transient_voltage_graph").map((el) => el.simulation_transient_voltage_graph_id);
3071
2416
  }, [circuitJson]);
3072
- const simulationCurrentGraphIds = useMemo6(() => {
2417
+ const simulationCurrentGraphIds = useMemo5(() => {
3073
2418
  if (!circuitJson) return [];
3074
2419
  return circuitJson.filter((el) => el.type === "simulation_transient_current_graph").map((el) => el.simulation_transient_current_graph_id);
3075
2420
  }, [circuitJson]);
3076
- const simulationSvg = useMemo6(() => {
2421
+ const simulationSvg = useMemo5(() => {
3077
2422
  if (!circuitJson || !effectiveWidth || !effectiveHeight || !simulationExperimentId)
3078
2423
  return "";
3079
2424
  try {
@@ -3099,7 +2444,7 @@ var AnalogSimulationViewer = ({
3099
2444
  simulationCurrentGraphIds,
3100
2445
  simulationVoltageGraphIds
3101
2446
  ]);
3102
- useEffect13(() => {
2447
+ useEffect12(() => {
3103
2448
  if (!simulationSvg) {
3104
2449
  setSvgObjectUrl(null);
3105
2450
  return;
@@ -3116,7 +2461,7 @@ var AnalogSimulationViewer = ({
3116
2461
  setSvgObjectUrl(null);
3117
2462
  }
3118
2463
  }, [simulationSvg]);
3119
- const containerBackgroundColor = useMemo6(() => {
2464
+ const containerBackgroundColor = useMemo5(() => {
3120
2465
  if (!simulationSvg) return "transparent";
3121
2466
  const match = simulationSvg.match(
3122
2467
  /<svg[^>]*style="[^"]*background-color:\s*([^;\"]+)/i
@@ -3129,7 +2474,7 @@ var AnalogSimulationViewer = ({
3129
2474
  const handleTouchStart = (_e) => {
3130
2475
  setIsDragging(true);
3131
2476
  };
3132
- useEffect13(() => {
2477
+ useEffect12(() => {
3133
2478
  const handleMouseUp = () => {
3134
2479
  setIsDragging(false);
3135
2480
  };
@@ -3144,7 +2489,7 @@ var AnalogSimulationViewer = ({
3144
2489
  };
3145
2490
  }, []);
3146
2491
  if (isLoading) {
3147
- return /* @__PURE__ */ jsx14(
2492
+ return /* @__PURE__ */ jsx10(
3148
2493
  "div",
3149
2494
  {
3150
2495
  style: {
@@ -3164,7 +2509,7 @@ var AnalogSimulationViewer = ({
3164
2509
  );
3165
2510
  }
3166
2511
  if (error) {
3167
- return /* @__PURE__ */ jsx14(
2512
+ return /* @__PURE__ */ jsx10(
3168
2513
  "div",
3169
2514
  {
3170
2515
  style: {
@@ -3179,15 +2524,15 @@ var AnalogSimulationViewer = ({
3179
2524
  ...containerStyle
3180
2525
  },
3181
2526
  className,
3182
- children: /* @__PURE__ */ jsxs9("div", { style: { textAlign: "center", padding: "20px" }, children: [
3183
- /* @__PURE__ */ jsx14("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "Circuit Conversion Error" }),
3184
- /* @__PURE__ */ jsx14("div", { style: { fontSize: "14px" }, children: error })
2527
+ children: /* @__PURE__ */ jsxs7("div", { style: { textAlign: "center", padding: "20px" }, children: [
2528
+ /* @__PURE__ */ jsx10("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "Circuit Conversion Error" }),
2529
+ /* @__PURE__ */ jsx10("div", { style: { fontSize: "14px" }, children: error })
3185
2530
  ] })
3186
2531
  }
3187
2532
  );
3188
2533
  }
3189
2534
  if (!simulationSvg) {
3190
- return /* @__PURE__ */ jsxs9(
2535
+ return /* @__PURE__ */ jsxs7(
3191
2536
  "div",
3192
2537
  {
3193
2538
  style: {
@@ -3203,11 +2548,11 @@ var AnalogSimulationViewer = ({
3203
2548
  },
3204
2549
  className,
3205
2550
  children: [
3206
- /* @__PURE__ */ jsx14("div", { style: { fontSize: "16px", color: "#475569", fontWeight: 500 }, children: "No Simulation Found" }),
3207
- /* @__PURE__ */ jsxs9("div", { style: { fontSize: "14px", color: "#64748b" }, children: [
2551
+ /* @__PURE__ */ jsx10("div", { style: { fontSize: "16px", color: "#475569", fontWeight: 500 }, children: "No Simulation Found" }),
2552
+ /* @__PURE__ */ jsxs7("div", { style: { fontSize: "14px", color: "#64748b" }, children: [
3208
2553
  "Use",
3209
2554
  " ",
3210
- /* @__PURE__ */ jsx14(
2555
+ /* @__PURE__ */ jsx10(
3211
2556
  "code",
3212
2557
  {
3213
2558
  style: {
@@ -3227,7 +2572,7 @@ var AnalogSimulationViewer = ({
3227
2572
  }
3228
2573
  );
3229
2574
  }
3230
- return /* @__PURE__ */ jsx14(
2575
+ return /* @__PURE__ */ jsx10(
3231
2576
  "div",
3232
2577
  {
3233
2578
  ref: (node) => {
@@ -3245,7 +2590,7 @@ var AnalogSimulationViewer = ({
3245
2590
  className,
3246
2591
  onMouseDown: handleMouseDown,
3247
2592
  onTouchStart: handleTouchStart,
3248
- children: svgObjectUrl ? /* @__PURE__ */ jsx14(
2593
+ children: svgObjectUrl ? /* @__PURE__ */ jsx10(
3249
2594
  "img",
3250
2595
  {
3251
2596
  ref: imgRef,
@@ -3259,7 +2604,7 @@ var AnalogSimulationViewer = ({
3259
2604
  objectFit: "contain"
3260
2605
  }
3261
2606
  }
3262
- ) : /* @__PURE__ */ jsx14(
2607
+ ) : /* @__PURE__ */ jsx10(
3263
2608
  "div",
3264
2609
  {
3265
2610
  style: {