@tscircuit/schematic-viewer 2.0.49 → 2.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lockb +0 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.js +263 -3
- package/dist/index.js.map +1 -1
- package/examples/example15-analog-simulation-viewer.fixture.tsx +145 -0
- package/examples/example16-no-analog-simulation.fixture.tsx +13 -0
- package/lib/components/AnalogSimulationViewer.tsx +300 -0
- package/lib/components/SpicePlot.tsx +1 -1
- package/lib/components/ViewMenu.tsx +1 -1
- package/lib/hooks/useChangeSchematicTracesForMovedComponents.ts +2 -2
- package/lib/hooks/useSchematicGroupsOverlay.ts +1 -1
- package/lib/index.ts +1 -0
- package/package.json +3 -3
package/bun.lockb
CHANGED
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ManualEditEvent } from '@tscircuit/props';
|
|
|
4
4
|
import { CircuitJson } from 'circuit-json';
|
|
5
5
|
import { ReactNode } from 'react';
|
|
6
6
|
|
|
7
|
-
interface Props {
|
|
7
|
+
interface Props$1 {
|
|
8
8
|
circuitJson: CircuitJson;
|
|
9
9
|
containerStyle?: React.CSSProperties;
|
|
10
10
|
editEvents?: ManualEditEvent[];
|
|
@@ -22,7 +22,7 @@ interface Props {
|
|
|
22
22
|
event: MouseEvent;
|
|
23
23
|
}) => void;
|
|
24
24
|
}
|
|
25
|
-
declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents: unappliedEditEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, debug, clickToInteractEnabled, colorOverrides, spiceSimulationEnabled, disableGroups, onSchematicComponentClicked, }: Props) => react_jsx_runtime.JSX.Element;
|
|
25
|
+
declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents: unappliedEditEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, debug, clickToInteractEnabled, colorOverrides, spiceSimulationEnabled, disableGroups, onSchematicComponentClicked, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
26
26
|
|
|
27
27
|
interface BoundingBoxBounds {
|
|
28
28
|
minX: number;
|
|
@@ -42,4 +42,14 @@ declare const useMouseEventsOverBoundingBox: (options: UseMouseEventsOverBoundin
|
|
|
42
42
|
hovering: boolean;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
interface Props {
|
|
46
|
+
circuitJson: CircuitJson;
|
|
47
|
+
containerStyle?: React.CSSProperties;
|
|
48
|
+
colorOverrides?: ColorOverrides;
|
|
49
|
+
width?: number;
|
|
50
|
+
height?: number;
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
declare const AnalogSimulationViewer: ({ circuitJson: inputCircuitJson, containerStyle, colorOverrides, width, height, className, }: Props) => react_jsx_runtime.JSX.Element;
|
|
54
|
+
|
|
55
|
+
export { AnalogSimulationViewer, MouseTracker, SchematicViewer, useMouseEventsOverBoundingBox };
|
package/dist/index.js
CHANGED
|
@@ -851,7 +851,7 @@ import { su as su5 } from "@tscircuit/soup-util";
|
|
|
851
851
|
// package.json
|
|
852
852
|
var package_default = {
|
|
853
853
|
name: "@tscircuit/schematic-viewer",
|
|
854
|
-
version: "2.0.
|
|
854
|
+
version: "2.0.50",
|
|
855
855
|
main: "dist/index.js",
|
|
856
856
|
type: "module",
|
|
857
857
|
scripts: {
|
|
@@ -878,7 +878,7 @@ var package_default = {
|
|
|
878
878
|
"react-dom": "^19.1.0",
|
|
879
879
|
"react-reconciler": "^0.31.0",
|
|
880
880
|
semver: "^7.7.2",
|
|
881
|
-
tscircuit: "^0.0.
|
|
881
|
+
tscircuit: "^0.0.1037",
|
|
882
882
|
tsup: "^8.3.5",
|
|
883
883
|
vite: "^6.0.3"
|
|
884
884
|
},
|
|
@@ -888,7 +888,7 @@ var package_default = {
|
|
|
888
888
|
},
|
|
889
889
|
dependencies: {
|
|
890
890
|
"chart.js": "^4.5.0",
|
|
891
|
-
"circuit-json-to-spice": "^0.0.
|
|
891
|
+
"circuit-json-to-spice": "^0.0.30",
|
|
892
892
|
debug: "^4.4.0",
|
|
893
893
|
"performance-now": "^2.1.0",
|
|
894
894
|
"react-chartjs-2": "^5.3.0",
|
|
@@ -2545,7 +2545,267 @@ var SchematicViewer = ({
|
|
|
2545
2545
|
)
|
|
2546
2546
|
] });
|
|
2547
2547
|
};
|
|
2548
|
+
|
|
2549
|
+
// lib/components/AnalogSimulationViewer.tsx
|
|
2550
|
+
import {
|
|
2551
|
+
convertCircuitJsonToSchematicSimulationSvg
|
|
2552
|
+
} from "circuit-to-svg";
|
|
2553
|
+
import { useEffect as useEffect12, useState as useState7, useMemo as useMemo6, useRef as useRef8 } from "react";
|
|
2554
|
+
import { useMouseMatrixTransform as useMouseMatrixTransform2 } from "use-mouse-matrix-transform";
|
|
2555
|
+
import { toString as transformToString2 } from "transformation-matrix";
|
|
2556
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2557
|
+
var AnalogSimulationViewer = ({
|
|
2558
|
+
circuitJson: inputCircuitJson,
|
|
2559
|
+
containerStyle,
|
|
2560
|
+
colorOverrides,
|
|
2561
|
+
width,
|
|
2562
|
+
height,
|
|
2563
|
+
className
|
|
2564
|
+
}) => {
|
|
2565
|
+
const [circuitJson, setCircuitJson] = useState7(null);
|
|
2566
|
+
const [isLoading, setIsLoading] = useState7(true);
|
|
2567
|
+
const [error, setError] = useState7(null);
|
|
2568
|
+
const [svgObjectUrl, setSvgObjectUrl] = useState7(null);
|
|
2569
|
+
const containerRef = useRef8(null);
|
|
2570
|
+
const imgRef = useRef8(null);
|
|
2571
|
+
const { containerWidth, containerHeight } = useResizeHandling(
|
|
2572
|
+
containerRef
|
|
2573
|
+
);
|
|
2574
|
+
const [isDragging, setIsDragging] = useState7(false);
|
|
2575
|
+
const {
|
|
2576
|
+
ref: transformRef,
|
|
2577
|
+
cancelDrag: _cancelDrag,
|
|
2578
|
+
transform: _svgToScreenProjection
|
|
2579
|
+
} = useMouseMatrixTransform2({
|
|
2580
|
+
onSetTransform(transform) {
|
|
2581
|
+
if (imgRef.current) {
|
|
2582
|
+
imgRef.current.style.transform = transformToString2(transform);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
});
|
|
2586
|
+
const effectiveWidth = width || containerWidth || 1e3;
|
|
2587
|
+
const effectiveHeight = height || containerHeight || 600;
|
|
2588
|
+
useEffect12(() => {
|
|
2589
|
+
setIsLoading(true);
|
|
2590
|
+
setError(null);
|
|
2591
|
+
setCircuitJson(inputCircuitJson);
|
|
2592
|
+
setIsLoading(false);
|
|
2593
|
+
}, [inputCircuitJson]);
|
|
2594
|
+
const simulationExperimentId = useMemo6(() => {
|
|
2595
|
+
if (!circuitJson) return null;
|
|
2596
|
+
const simulationElement = circuitJson.find(
|
|
2597
|
+
(el) => el.type === "simulation_experiment"
|
|
2598
|
+
);
|
|
2599
|
+
return simulationElement?.simulation_experiment_id || null;
|
|
2600
|
+
}, [circuitJson]);
|
|
2601
|
+
const simulationGraphIds = useMemo6(() => {
|
|
2602
|
+
if (!circuitJson) return [];
|
|
2603
|
+
return circuitJson.filter((el) => el.type === "simulation_transient_voltage_graph").map((el) => el.simulation_transient_voltage_graph_id);
|
|
2604
|
+
}, [circuitJson]);
|
|
2605
|
+
const simulationSvg = useMemo6(() => {
|
|
2606
|
+
if (!circuitJson || !effectiveWidth || !effectiveHeight || !simulationExperimentId)
|
|
2607
|
+
return "";
|
|
2608
|
+
try {
|
|
2609
|
+
return convertCircuitJsonToSchematicSimulationSvg({
|
|
2610
|
+
circuitJson,
|
|
2611
|
+
simulation_experiment_id: simulationExperimentId,
|
|
2612
|
+
simulation_transient_voltage_graph_ids: simulationGraphIds,
|
|
2613
|
+
width: effectiveWidth,
|
|
2614
|
+
height: effectiveHeight,
|
|
2615
|
+
schematicOptions: { colorOverrides }
|
|
2616
|
+
});
|
|
2617
|
+
} catch (fallbackErr) {
|
|
2618
|
+
console.error("Failed to generate fallback schematic SVG:", fallbackErr);
|
|
2619
|
+
return "";
|
|
2620
|
+
}
|
|
2621
|
+
}, [
|
|
2622
|
+
circuitJson,
|
|
2623
|
+
effectiveWidth,
|
|
2624
|
+
effectiveHeight,
|
|
2625
|
+
colorOverrides,
|
|
2626
|
+
simulationExperimentId,
|
|
2627
|
+
simulationGraphIds
|
|
2628
|
+
]);
|
|
2629
|
+
useEffect12(() => {
|
|
2630
|
+
if (!simulationSvg) {
|
|
2631
|
+
setSvgObjectUrl(null);
|
|
2632
|
+
return;
|
|
2633
|
+
}
|
|
2634
|
+
try {
|
|
2635
|
+
const blob = new Blob([simulationSvg], { type: "image/svg+xml" });
|
|
2636
|
+
const url = URL.createObjectURL(blob);
|
|
2637
|
+
setSvgObjectUrl(url);
|
|
2638
|
+
return () => {
|
|
2639
|
+
URL.revokeObjectURL(url);
|
|
2640
|
+
};
|
|
2641
|
+
} catch (error2) {
|
|
2642
|
+
console.error("Failed to create SVG object URL:", error2);
|
|
2643
|
+
setSvgObjectUrl(null);
|
|
2644
|
+
}
|
|
2645
|
+
}, [simulationSvg]);
|
|
2646
|
+
const containerBackgroundColor = useMemo6(() => {
|
|
2647
|
+
if (!simulationSvg) return "transparent";
|
|
2648
|
+
const match = simulationSvg.match(
|
|
2649
|
+
/<svg[^>]*style="[^"]*background-color:\s*([^;\"]+)/i
|
|
2650
|
+
);
|
|
2651
|
+
return match?.[1] ?? "transparent";
|
|
2652
|
+
}, [simulationSvg]);
|
|
2653
|
+
const handleMouseDown = (_e) => {
|
|
2654
|
+
setIsDragging(true);
|
|
2655
|
+
};
|
|
2656
|
+
const handleTouchStart = (_e) => {
|
|
2657
|
+
setIsDragging(true);
|
|
2658
|
+
};
|
|
2659
|
+
useEffect12(() => {
|
|
2660
|
+
const handleMouseUp = () => {
|
|
2661
|
+
setIsDragging(false);
|
|
2662
|
+
};
|
|
2663
|
+
const handleTouchEnd = () => {
|
|
2664
|
+
setIsDragging(false);
|
|
2665
|
+
};
|
|
2666
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
2667
|
+
window.addEventListener("touchend", handleTouchEnd);
|
|
2668
|
+
return () => {
|
|
2669
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
2670
|
+
window.removeEventListener("touchend", handleTouchEnd);
|
|
2671
|
+
};
|
|
2672
|
+
}, []);
|
|
2673
|
+
if (isLoading) {
|
|
2674
|
+
return /* @__PURE__ */ jsx12(
|
|
2675
|
+
"div",
|
|
2676
|
+
{
|
|
2677
|
+
style: {
|
|
2678
|
+
display: "flex",
|
|
2679
|
+
alignItems: "center",
|
|
2680
|
+
justifyContent: "center",
|
|
2681
|
+
backgroundColor: "#f5f5f5",
|
|
2682
|
+
minHeight: "300px",
|
|
2683
|
+
fontFamily: "sans-serif",
|
|
2684
|
+
fontSize: "16px",
|
|
2685
|
+
color: "#666",
|
|
2686
|
+
...containerStyle
|
|
2687
|
+
},
|
|
2688
|
+
className,
|
|
2689
|
+
children: "Loading circuit..."
|
|
2690
|
+
}
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
if (error) {
|
|
2694
|
+
return /* @__PURE__ */ jsx12(
|
|
2695
|
+
"div",
|
|
2696
|
+
{
|
|
2697
|
+
style: {
|
|
2698
|
+
display: "flex",
|
|
2699
|
+
alignItems: "center",
|
|
2700
|
+
justifyContent: "center",
|
|
2701
|
+
backgroundColor: "#fef2f2",
|
|
2702
|
+
minHeight: "300px",
|
|
2703
|
+
fontFamily: "sans-serif",
|
|
2704
|
+
fontSize: "16px",
|
|
2705
|
+
color: "#dc2626",
|
|
2706
|
+
...containerStyle
|
|
2707
|
+
},
|
|
2708
|
+
className,
|
|
2709
|
+
children: /* @__PURE__ */ jsxs7("div", { style: { textAlign: "center", padding: "20px" }, children: [
|
|
2710
|
+
/* @__PURE__ */ jsx12("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "Circuit Conversion Error" }),
|
|
2711
|
+
/* @__PURE__ */ jsx12("div", { style: { fontSize: "14px" }, children: error })
|
|
2712
|
+
] })
|
|
2713
|
+
}
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2716
|
+
if (!simulationSvg) {
|
|
2717
|
+
return /* @__PURE__ */ jsxs7(
|
|
2718
|
+
"div",
|
|
2719
|
+
{
|
|
2720
|
+
style: {
|
|
2721
|
+
display: "flex",
|
|
2722
|
+
flexDirection: "column",
|
|
2723
|
+
alignItems: "center",
|
|
2724
|
+
justifyContent: "center",
|
|
2725
|
+
backgroundColor: "#f8fafc",
|
|
2726
|
+
minHeight: "300px",
|
|
2727
|
+
fontFamily: "sans-serif",
|
|
2728
|
+
gap: "12px",
|
|
2729
|
+
...containerStyle
|
|
2730
|
+
},
|
|
2731
|
+
className,
|
|
2732
|
+
children: [
|
|
2733
|
+
/* @__PURE__ */ jsx12("div", { style: { fontSize: "16px", color: "#475569", fontWeight: 500 }, children: "No Simulation Found" }),
|
|
2734
|
+
/* @__PURE__ */ jsxs7("div", { style: { fontSize: "14px", color: "#64748b" }, children: [
|
|
2735
|
+
"Use",
|
|
2736
|
+
" ",
|
|
2737
|
+
/* @__PURE__ */ jsx12(
|
|
2738
|
+
"code",
|
|
2739
|
+
{
|
|
2740
|
+
style: {
|
|
2741
|
+
backgroundColor: "#e2e8f0",
|
|
2742
|
+
padding: "2px 6px",
|
|
2743
|
+
borderRadius: "4px",
|
|
2744
|
+
fontFamily: "monospace",
|
|
2745
|
+
fontSize: "13px"
|
|
2746
|
+
},
|
|
2747
|
+
children: "<analogsimulation />"
|
|
2748
|
+
}
|
|
2749
|
+
),
|
|
2750
|
+
" ",
|
|
2751
|
+
"to create simulations"
|
|
2752
|
+
] })
|
|
2753
|
+
]
|
|
2754
|
+
}
|
|
2755
|
+
);
|
|
2756
|
+
}
|
|
2757
|
+
return /* @__PURE__ */ jsx12(
|
|
2758
|
+
"div",
|
|
2759
|
+
{
|
|
2760
|
+
ref: (node) => {
|
|
2761
|
+
containerRef.current = node;
|
|
2762
|
+
transformRef.current = node;
|
|
2763
|
+
},
|
|
2764
|
+
style: {
|
|
2765
|
+
position: "relative",
|
|
2766
|
+
backgroundColor: containerBackgroundColor,
|
|
2767
|
+
overflow: "hidden",
|
|
2768
|
+
minHeight: "300px",
|
|
2769
|
+
cursor: isDragging ? "grabbing" : "grab",
|
|
2770
|
+
...containerStyle
|
|
2771
|
+
},
|
|
2772
|
+
className,
|
|
2773
|
+
onMouseDown: handleMouseDown,
|
|
2774
|
+
onTouchStart: handleTouchStart,
|
|
2775
|
+
children: svgObjectUrl ? /* @__PURE__ */ jsx12(
|
|
2776
|
+
"img",
|
|
2777
|
+
{
|
|
2778
|
+
ref: imgRef,
|
|
2779
|
+
src: svgObjectUrl,
|
|
2780
|
+
alt: "Circuit Simulation",
|
|
2781
|
+
style: {
|
|
2782
|
+
transformOrigin: "0 0",
|
|
2783
|
+
width: "100%",
|
|
2784
|
+
height: "100%",
|
|
2785
|
+
display: "block",
|
|
2786
|
+
objectFit: "contain"
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
) : /* @__PURE__ */ jsx12(
|
|
2790
|
+
"div",
|
|
2791
|
+
{
|
|
2792
|
+
style: {
|
|
2793
|
+
display: "flex",
|
|
2794
|
+
alignItems: "center",
|
|
2795
|
+
justifyContent: "center",
|
|
2796
|
+
height: "100%",
|
|
2797
|
+
minHeight: "300px",
|
|
2798
|
+
color: "#666",
|
|
2799
|
+
fontFamily: "sans-serif"
|
|
2800
|
+
},
|
|
2801
|
+
children: "Failed to render SVG"
|
|
2802
|
+
}
|
|
2803
|
+
)
|
|
2804
|
+
}
|
|
2805
|
+
);
|
|
2806
|
+
};
|
|
2548
2807
|
export {
|
|
2808
|
+
AnalogSimulationViewer,
|
|
2549
2809
|
MouseTracker,
|
|
2550
2810
|
SchematicViewer,
|
|
2551
2811
|
useMouseEventsOverBoundingBox
|