@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.d.ts +3 -2
- package/dist/index.js +266 -921
- package/dist/index.js.map +1 -1
- package/package.json +5 -11
- package/dist/workers/spice-simulation.worker.js +0 -1
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
507
|
-
import { useCallback, useEffect as
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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.
|
|
923
|
+
version: "2.0.69",
|
|
806
924
|
main: "dist/index.js",
|
|
807
925
|
type: "module",
|
|
808
926
|
scripts: {
|
|
809
927
|
start: "cosmos",
|
|
810
|
-
|
|
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:
|
|
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.
|
|
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 =
|
|
1091
|
+
const sourceGroups = su6(circuitJson).source_group?.list() || [];
|
|
980
1092
|
if (sourceGroups.length > 0) return true;
|
|
981
|
-
const schematicComponents =
|
|
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 =
|
|
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
|
|
1816
|
-
useMemo as
|
|
1220
|
+
useEffect as useEffect7,
|
|
1221
|
+
useMemo as useMemo2,
|
|
1817
1222
|
useRef as useRef4
|
|
1818
1223
|
} from "react";
|
|
1819
|
-
import { Fragment, jsx as
|
|
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__ */
|
|
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
|
-
|
|
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 =
|
|
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__ */
|
|
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
|
|
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
|
|
1397
|
+
useEffect as useEffect8,
|
|
1993
1398
|
useId,
|
|
1994
|
-
useMemo as
|
|
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 =
|
|
1413
|
+
const handleClick = useMemo3(
|
|
2009
1414
|
() => (event) => {
|
|
2010
1415
|
latestOptionsRef.current.onClick?.(event);
|
|
2011
1416
|
},
|
|
2012
1417
|
[]
|
|
2013
1418
|
);
|
|
2014
|
-
|
|
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
|
-
|
|
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
|
|
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] =
|
|
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
|
-
|
|
1508
|
+
useEffect9(() => {
|
|
2104
1509
|
scheduleMeasure();
|
|
2105
1510
|
}, [scheduleMeasure, circuitJsonKey]);
|
|
2106
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
2179
|
-
import { Fragment as Fragment2, jsx as
|
|
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] =
|
|
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
|
-
|
|
1642
|
+
useEffect10(() => {
|
|
2238
1643
|
scheduleMeasure();
|
|
2239
1644
|
}, [scheduleMeasure, circuitJsonKey]);
|
|
2240
|
-
|
|
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
|
-
|
|
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__ */
|
|
2295
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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
|
|
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__ */
|
|
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__ */
|
|
1807
|
+
children: /* @__PURE__ */ jsx8("path", { d: "M20 6 9 17l-5-5" })
|
|
2403
1808
|
}
|
|
2404
1809
|
);
|
|
2405
|
-
var ChevronDownIcon = ({ className }) => /* @__PURE__ */
|
|
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__ */
|
|
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] =
|
|
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__ */
|
|
2434
|
-
/* @__PURE__ */
|
|
2435
|
-
/* @__PURE__ */
|
|
2436
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2464
|
-
/* @__PURE__ */
|
|
2465
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2492
|
-
/* @__PURE__ */
|
|
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
|
|
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 =
|
|
1937
|
+
const circuitJsonKey = useMemo4(
|
|
2542
1938
|
() => getCircuitHash(circuitJson),
|
|
2543
1939
|
[circuitJson]
|
|
2544
1940
|
);
|
|
2545
|
-
const schematicSheets =
|
|
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] =
|
|
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
|
-
|
|
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
|
|
2580
|
-
|
|
2581
|
-
|
|
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] =
|
|
1979
|
+
const [isInteractionEnabled, setIsInteractionEnabled] = useState6(
|
|
2608
1980
|
!clickToInteractEnabled
|
|
2609
1981
|
);
|
|
2610
|
-
const [showViewMenu, setShowViewMenu] =
|
|
2611
|
-
const [showSchematicGroups, setShowSchematicGroups] =
|
|
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] =
|
|
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] =
|
|
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 =
|
|
2015
|
+
const schematicComponentIds = useMemo4(() => {
|
|
2644
2016
|
try {
|
|
2645
|
-
const components =
|
|
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 =
|
|
2026
|
+
const schematicPortsInfo = useMemo4(() => {
|
|
2655
2027
|
if (!showSchematicPorts) return [];
|
|
2656
2028
|
try {
|
|
2657
|
-
const ports = (
|
|
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 =
|
|
2662
|
-
const sourceComponent = sourcePort?.source_component_id ?
|
|
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] =
|
|
2066
|
+
const [internalEditEvents, setInternalEditEvents] = useState6([]);
|
|
2695
2067
|
const circuitJsonRef = useRef8(circuitJson);
|
|
2696
|
-
|
|
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
|
|
2086
|
+
enabled: isInteractionEnabled
|
|
2715
2087
|
});
|
|
2716
2088
|
const { containerWidth, containerHeight } = useResizeHandling(containerRef);
|
|
2717
|
-
const svgString =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
2180
|
+
useEffect11(() => {
|
|
2803
2181
|
handleComponentTouchStartRef.current = handleComponentTouchStart;
|
|
2804
2182
|
}, [handleComponentTouchStart]);
|
|
2805
|
-
const svgDiv =
|
|
2806
|
-
() => /* @__PURE__ */
|
|
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
|
|
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__ */
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
/* @__PURE__ */
|
|
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:
|
|
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:
|
|
2867
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
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
|
|
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] =
|
|
3032
|
-
const [isLoading, setIsLoading] =
|
|
3033
|
-
const [error, setError] =
|
|
3034
|
-
const [svgObjectUrl, setSvgObjectUrl] =
|
|
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] =
|
|
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
|
-
|
|
2400
|
+
useEffect12(() => {
|
|
3056
2401
|
setIsLoading(true);
|
|
3057
2402
|
setError(null);
|
|
3058
2403
|
setCircuitJson(inputCircuitJson);
|
|
3059
2404
|
setIsLoading(false);
|
|
3060
2405
|
}, [inputCircuitJson]);
|
|
3061
|
-
const simulationExperimentId =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
3183
|
-
/* @__PURE__ */
|
|
3184
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
3207
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2607
|
+
) : /* @__PURE__ */ jsx10(
|
|
3263
2608
|
"div",
|
|
3264
2609
|
{
|
|
3265
2610
|
style: {
|