@tscircuit/schematic-viewer 2.0.26 → 2.0.27
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 +426 -51
- package/dist/index.js.map +1 -1
- package/examples/example10-groups-view-schematic-groups.fixture.tsx +90 -0
- package/examples/example11-automatic-grouping-view-schematic-groups.fixture.tsx +99 -0
- package/lib/components/EditIcon.tsx +1 -1
- package/lib/components/GridIcon.tsx +1 -1
- package/lib/components/SchematicViewer.tsx +20 -0
- package/lib/components/SpiceSimulationIcon.tsx +1 -1
- package/lib/components/ViewMenu.tsx +147 -0
- package/lib/components/ViewMenuIcon.tsx +40 -0
- package/lib/hooks/useSchematicGroupsOverlay.ts +217 -0
- package/lib/utils/z-index-map.ts +3 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -192,6 +192,176 @@ var useChangeSchematicTracesForMovedComponents = ({
|
|
|
192
192
|
}, [svgDivRef, activeEditEvent, circuitJson, editEvents]);
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
+
// lib/hooks/useSchematicGroupsOverlay.ts
|
|
196
|
+
import { useEffect as useEffect3 } from "react";
|
|
197
|
+
import { su as su3 } from "@tscircuit/soup-util";
|
|
198
|
+
var useSchematicGroupsOverlay = (svgDivRef, circuitJson, circuitJsonKey, showGroups) => {
|
|
199
|
+
useEffect3(() => {
|
|
200
|
+
if (!svgDivRef.current || !showGroups || !circuitJson || circuitJson.length === 0) {
|
|
201
|
+
if (svgDivRef.current) {
|
|
202
|
+
const existingOverlays2 = svgDivRef.current.querySelectorAll(
|
|
203
|
+
".schematic-group-overlay"
|
|
204
|
+
);
|
|
205
|
+
existingOverlays2.forEach((overlay) => overlay.remove());
|
|
206
|
+
}
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const svg = svgDivRef.current.querySelector("svg");
|
|
210
|
+
if (!svg) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const existingOverlays = svg.querySelectorAll(".schematic-group-overlay");
|
|
214
|
+
existingOverlays.forEach((overlay) => overlay.remove());
|
|
215
|
+
try {
|
|
216
|
+
const sourceGroups = su3(circuitJson).source_group?.list() || [];
|
|
217
|
+
const schematicComponents = su3(circuitJson).schematic_component?.list() || [];
|
|
218
|
+
let groupsToRender = [];
|
|
219
|
+
const hasMeaningfulGroups = sourceGroups.length > 0 && sourceGroups.some((group) => group.name && group.name !== "default" && group.name !== "");
|
|
220
|
+
if (hasMeaningfulGroups) {
|
|
221
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
222
|
+
for (const comp of schematicComponents) {
|
|
223
|
+
const sourceComp = su3(circuitJson).source_component.get(
|
|
224
|
+
comp.source_component_id
|
|
225
|
+
);
|
|
226
|
+
if (sourceComp?.source_group_id) {
|
|
227
|
+
if (!groupMap.has(sourceComp.source_group_id)) {
|
|
228
|
+
groupMap.set(sourceComp.source_group_id, []);
|
|
229
|
+
}
|
|
230
|
+
groupMap.get(sourceComp.source_group_id).push(comp);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
groupsToRender = Array.from(groupMap.entries()).map(
|
|
234
|
+
([groupId, components], index) => {
|
|
235
|
+
const group = sourceGroups.find(
|
|
236
|
+
(g) => g.source_group_id === groupId
|
|
237
|
+
);
|
|
238
|
+
return {
|
|
239
|
+
id: groupId,
|
|
240
|
+
name: group?.name || `Group ${index + 1}`,
|
|
241
|
+
components,
|
|
242
|
+
color: getGroupColor(index)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
} else {
|
|
247
|
+
const componentTypeGroups = /* @__PURE__ */ new Map();
|
|
248
|
+
for (const comp of schematicComponents) {
|
|
249
|
+
const sourceComp = su3(circuitJson).source_component.get(
|
|
250
|
+
comp.source_component_id
|
|
251
|
+
);
|
|
252
|
+
if (sourceComp) {
|
|
253
|
+
const componentType = sourceComp.ftype || "other";
|
|
254
|
+
if (!componentTypeGroups.has(componentType)) {
|
|
255
|
+
componentTypeGroups.set(componentType, []);
|
|
256
|
+
}
|
|
257
|
+
componentTypeGroups.get(componentType).push(comp);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
groupsToRender = Array.from(componentTypeGroups.entries()).map(
|
|
261
|
+
([type, components], index) => ({
|
|
262
|
+
id: `type_${type}`,
|
|
263
|
+
name: `${type.charAt(0).toUpperCase() + type.slice(1)}s`,
|
|
264
|
+
components,
|
|
265
|
+
color: getGroupColor(index)
|
|
266
|
+
})
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
groupsToRender.forEach((group, groupIndex) => {
|
|
270
|
+
if (group.components.length === 0) return;
|
|
271
|
+
const groupBounds = calculateGroupBounds(group.components, svg);
|
|
272
|
+
if (!groupBounds) return;
|
|
273
|
+
const groupOverlay = document.createElementNS(
|
|
274
|
+
"http://www.w3.org/2000/svg",
|
|
275
|
+
"rect"
|
|
276
|
+
);
|
|
277
|
+
groupOverlay.setAttribute("class", "schematic-group-overlay");
|
|
278
|
+
groupOverlay.setAttribute("x", (groupBounds.minX - 25).toString());
|
|
279
|
+
groupOverlay.setAttribute("y", (groupBounds.minY - 25).toString());
|
|
280
|
+
groupOverlay.setAttribute(
|
|
281
|
+
"width",
|
|
282
|
+
(groupBounds.maxX - groupBounds.minX + 50).toString()
|
|
283
|
+
);
|
|
284
|
+
groupOverlay.setAttribute(
|
|
285
|
+
"height",
|
|
286
|
+
(groupBounds.maxY - groupBounds.minY + 50).toString()
|
|
287
|
+
);
|
|
288
|
+
groupOverlay.setAttribute("fill", "none");
|
|
289
|
+
groupOverlay.setAttribute("stroke", group.color);
|
|
290
|
+
groupOverlay.setAttribute("stroke-width", "3");
|
|
291
|
+
groupOverlay.setAttribute("stroke-dasharray", "8,4");
|
|
292
|
+
groupOverlay.setAttribute("opacity", "0.8");
|
|
293
|
+
groupOverlay.setAttribute("rx", "4");
|
|
294
|
+
groupOverlay.setAttribute("ry", "4");
|
|
295
|
+
const groupLabel = document.createElementNS(
|
|
296
|
+
"http://www.w3.org/2000/svg",
|
|
297
|
+
"text"
|
|
298
|
+
);
|
|
299
|
+
groupLabel.setAttribute("class", "schematic-group-overlay");
|
|
300
|
+
groupLabel.setAttribute("x", (groupBounds.minX - 10).toString());
|
|
301
|
+
groupLabel.setAttribute("y", (groupBounds.minY - 8).toString());
|
|
302
|
+
groupLabel.setAttribute("fill", group.color);
|
|
303
|
+
groupLabel.setAttribute("font-size", "14");
|
|
304
|
+
groupLabel.setAttribute("font-family", "Arial, sans-serif");
|
|
305
|
+
groupLabel.setAttribute("font-weight", "bold");
|
|
306
|
+
groupLabel.setAttribute("stroke", "#fff");
|
|
307
|
+
groupLabel.setAttribute("stroke-width", "0.5");
|
|
308
|
+
groupLabel.setAttribute("paint-order", "stroke fill");
|
|
309
|
+
groupLabel.textContent = group.name;
|
|
310
|
+
svg.appendChild(groupOverlay);
|
|
311
|
+
svg.appendChild(groupLabel);
|
|
312
|
+
});
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error("Error creating group overlays:", error);
|
|
315
|
+
}
|
|
316
|
+
}, [svgDivRef, circuitJsonKey, showGroups]);
|
|
317
|
+
};
|
|
318
|
+
function getGroupColor(index) {
|
|
319
|
+
const colors2 = [
|
|
320
|
+
"#FF6B6B",
|
|
321
|
+
// Red
|
|
322
|
+
"#4ECDC4",
|
|
323
|
+
// Teal
|
|
324
|
+
"#45B7D1",
|
|
325
|
+
// Blue
|
|
326
|
+
"#96CEB4",
|
|
327
|
+
// Green
|
|
328
|
+
"#FF8C42",
|
|
329
|
+
// Orange
|
|
330
|
+
"#DDA0DD",
|
|
331
|
+
// Plum
|
|
332
|
+
"#98D8C8",
|
|
333
|
+
// Mint
|
|
334
|
+
"#F7DC6F"
|
|
335
|
+
// Light Yellow
|
|
336
|
+
];
|
|
337
|
+
return colors2[index % colors2.length];
|
|
338
|
+
}
|
|
339
|
+
function calculateGroupBounds(components, svg) {
|
|
340
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
341
|
+
for (const component of components) {
|
|
342
|
+
let componentElement = svg.querySelector(
|
|
343
|
+
`g[data-schematic-component-id="${component.schematic_component_id}"]`
|
|
344
|
+
);
|
|
345
|
+
if (!componentElement) {
|
|
346
|
+
componentElement = svg.querySelector(
|
|
347
|
+
`[data-schematic-component-id="${component.schematic_component_id}"]`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
if (componentElement) {
|
|
351
|
+
const bbox = componentElement.getBBox();
|
|
352
|
+
minX = Math.min(minX, bbox.x);
|
|
353
|
+
minY = Math.min(minY, bbox.y);
|
|
354
|
+
maxX = Math.max(maxX, bbox.x + bbox.width);
|
|
355
|
+
maxY = Math.max(maxY, bbox.y + bbox.height);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (minX === Infinity) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
const bounds = { minX, minY, maxX, maxY };
|
|
362
|
+
return bounds;
|
|
363
|
+
}
|
|
364
|
+
|
|
195
365
|
// lib/utils/debug.ts
|
|
196
366
|
import Debug from "debug";
|
|
197
367
|
var debug = Debug("schematic-viewer");
|
|
@@ -201,7 +371,7 @@ var enableDebug = () => {
|
|
|
201
371
|
var debug_default = debug;
|
|
202
372
|
|
|
203
373
|
// lib/components/SchematicViewer.tsx
|
|
204
|
-
import { useEffect as
|
|
374
|
+
import { useEffect as useEffect7, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
205
375
|
import {
|
|
206
376
|
fromString,
|
|
207
377
|
identity,
|
|
@@ -210,11 +380,11 @@ import {
|
|
|
210
380
|
import { useMouseMatrixTransform } from "use-mouse-matrix-transform";
|
|
211
381
|
|
|
212
382
|
// lib/hooks/use-resize-handling.ts
|
|
213
|
-
import { useEffect as
|
|
383
|
+
import { useEffect as useEffect4, useState } from "react";
|
|
214
384
|
var useResizeHandling = (containerRef) => {
|
|
215
385
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
216
386
|
const [containerHeight, setContainerHeight] = useState(0);
|
|
217
|
-
|
|
387
|
+
useEffect4(() => {
|
|
218
388
|
if (!containerRef.current) return;
|
|
219
389
|
const updateDimensions = () => {
|
|
220
390
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
@@ -234,8 +404,8 @@ var useResizeHandling = (containerRef) => {
|
|
|
234
404
|
};
|
|
235
405
|
|
|
236
406
|
// lib/hooks/useComponentDragging.ts
|
|
237
|
-
import { su as
|
|
238
|
-
import { useCallback, useEffect as
|
|
407
|
+
import { su as su4 } from "@tscircuit/soup-util";
|
|
408
|
+
import { useCallback, useEffect as useEffect5, useRef as useRef3, useState as useState2 } from "react";
|
|
239
409
|
import { compose as compose2 } from "transformation-matrix";
|
|
240
410
|
var debug2 = debug_default.extend("useComponentDragging");
|
|
241
411
|
var useComponentDragging = ({
|
|
@@ -258,7 +428,7 @@ var useComponentDragging = ({
|
|
|
258
428
|
const componentPositionsRef = useRef3(
|
|
259
429
|
/* @__PURE__ */ new Map()
|
|
260
430
|
);
|
|
261
|
-
|
|
431
|
+
useEffect5(() => {
|
|
262
432
|
editEvents.forEach((event) => {
|
|
263
433
|
if ("edit_event_type" in event && event.edit_event_type === "edit_schematic_component_location" && !event.in_progress) {
|
|
264
434
|
componentPositionsRef.current.set(event.schematic_component_id, {
|
|
@@ -280,7 +450,7 @@ var useComponentDragging = ({
|
|
|
280
450
|
);
|
|
281
451
|
if (!schematic_component_id) return;
|
|
282
452
|
if (cancelDrag) cancelDrag();
|
|
283
|
-
const schematic_component =
|
|
453
|
+
const schematic_component = su4(circuitJson).schematic_component.get(
|
|
284
454
|
schematic_component_id
|
|
285
455
|
);
|
|
286
456
|
if (!schematic_component) return;
|
|
@@ -367,7 +537,7 @@ var useComponentDragging = ({
|
|
|
367
537
|
dragStartPosRef.current = null;
|
|
368
538
|
setActiveEditEvent(null);
|
|
369
539
|
}, [onEditEvent]);
|
|
370
|
-
|
|
540
|
+
useEffect5(() => {
|
|
371
541
|
window.addEventListener("mousemove", handleMouseMove);
|
|
372
542
|
window.addEventListener("mouseup", handleMouseUp);
|
|
373
543
|
return () => {
|
|
@@ -387,6 +557,9 @@ var zIndexMap = {
|
|
|
387
557
|
schematicEditIcon: 50,
|
|
388
558
|
schematicGridIcon: 49,
|
|
389
559
|
spiceSimulationIcon: 51,
|
|
560
|
+
viewMenuIcon: 48,
|
|
561
|
+
viewMenu: 55,
|
|
562
|
+
viewMenuBackdrop: 54,
|
|
390
563
|
clickToInteractOverlay: 100
|
|
391
564
|
};
|
|
392
565
|
|
|
@@ -403,7 +576,7 @@ var EditIcon = ({
|
|
|
403
576
|
style: {
|
|
404
577
|
position: "absolute",
|
|
405
578
|
top: "16px",
|
|
406
|
-
right: "
|
|
579
|
+
right: "64px",
|
|
407
580
|
backgroundColor: active ? "#4CAF50" : "#fff",
|
|
408
581
|
color: active ? "#fff" : "#000",
|
|
409
582
|
padding: "8px",
|
|
@@ -447,7 +620,7 @@ var GridIcon = ({
|
|
|
447
620
|
style: {
|
|
448
621
|
position: "absolute",
|
|
449
622
|
top: "56px",
|
|
450
|
-
right: "
|
|
623
|
+
right: "64px",
|
|
451
624
|
backgroundColor: active ? "#4CAF50" : "#fff",
|
|
452
625
|
color: active ? "#fff" : "#000",
|
|
453
626
|
padding: "8px",
|
|
@@ -475,9 +648,190 @@ var GridIcon = ({
|
|
|
475
648
|
);
|
|
476
649
|
};
|
|
477
650
|
|
|
651
|
+
// lib/components/ViewMenuIcon.tsx
|
|
652
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
653
|
+
var ViewMenuIcon = ({
|
|
654
|
+
onClick,
|
|
655
|
+
active
|
|
656
|
+
}) => {
|
|
657
|
+
return /* @__PURE__ */ jsx3(
|
|
658
|
+
"div",
|
|
659
|
+
{
|
|
660
|
+
onClick,
|
|
661
|
+
style: {
|
|
662
|
+
position: "absolute",
|
|
663
|
+
top: "16px",
|
|
664
|
+
right: "16px",
|
|
665
|
+
backgroundColor: active ? "#4CAF50" : "#fff",
|
|
666
|
+
color: active ? "#fff" : "#000",
|
|
667
|
+
padding: "8px",
|
|
668
|
+
borderRadius: "4px",
|
|
669
|
+
cursor: "pointer",
|
|
670
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
|
|
671
|
+
display: "flex",
|
|
672
|
+
alignItems: "center",
|
|
673
|
+
gap: "4px",
|
|
674
|
+
zIndex: zIndexMap.viewMenuIcon
|
|
675
|
+
},
|
|
676
|
+
children: /* @__PURE__ */ jsxs2(
|
|
677
|
+
"svg",
|
|
678
|
+
{
|
|
679
|
+
width: "16",
|
|
680
|
+
height: "16",
|
|
681
|
+
viewBox: "0 0 24 24",
|
|
682
|
+
fill: "none",
|
|
683
|
+
stroke: "currentColor",
|
|
684
|
+
strokeWidth: "2",
|
|
685
|
+
children: [
|
|
686
|
+
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "1" }),
|
|
687
|
+
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "5", r: "1" }),
|
|
688
|
+
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "19", r: "1" })
|
|
689
|
+
]
|
|
690
|
+
}
|
|
691
|
+
)
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// lib/components/ViewMenu.tsx
|
|
697
|
+
import { useMemo } from "react";
|
|
698
|
+
import { su as su5 } from "@tscircuit/soup-util";
|
|
699
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
700
|
+
var ViewMenu = ({
|
|
701
|
+
circuitJson,
|
|
702
|
+
circuitJsonKey,
|
|
703
|
+
isVisible,
|
|
704
|
+
onClose,
|
|
705
|
+
showGroups,
|
|
706
|
+
onToggleGroups
|
|
707
|
+
}) => {
|
|
708
|
+
const hasGroups = useMemo(() => {
|
|
709
|
+
if (!circuitJson || circuitJson.length === 0) return false;
|
|
710
|
+
try {
|
|
711
|
+
const sourceGroups = su5(circuitJson).source_group?.list() || [];
|
|
712
|
+
if (sourceGroups.length > 0) return true;
|
|
713
|
+
const schematicComponents = su5(circuitJson).schematic_component?.list() || [];
|
|
714
|
+
if (schematicComponents.length > 1) {
|
|
715
|
+
const componentTypes = /* @__PURE__ */ new Set();
|
|
716
|
+
for (const comp of schematicComponents) {
|
|
717
|
+
const sourceComp = su5(circuitJson).source_component.get(
|
|
718
|
+
comp.source_component_id
|
|
719
|
+
);
|
|
720
|
+
if (sourceComp?.ftype) {
|
|
721
|
+
componentTypes.add(sourceComp.ftype);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return componentTypes.size > 1;
|
|
725
|
+
}
|
|
726
|
+
return false;
|
|
727
|
+
} catch (error) {
|
|
728
|
+
console.error("Error checking for groups:", error);
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
}, [circuitJsonKey]);
|
|
732
|
+
if (!isVisible) return null;
|
|
733
|
+
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
734
|
+
/* @__PURE__ */ jsx4(
|
|
735
|
+
"div",
|
|
736
|
+
{
|
|
737
|
+
onClick: onClose,
|
|
738
|
+
style: {
|
|
739
|
+
position: "absolute",
|
|
740
|
+
inset: 0,
|
|
741
|
+
backgroundColor: "transparent",
|
|
742
|
+
zIndex: zIndexMap.viewMenuBackdrop
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
),
|
|
746
|
+
/* @__PURE__ */ jsxs3(
|
|
747
|
+
"div",
|
|
748
|
+
{
|
|
749
|
+
style: {
|
|
750
|
+
position: "absolute",
|
|
751
|
+
top: "56px",
|
|
752
|
+
right: "16px",
|
|
753
|
+
backgroundColor: "#ffffff",
|
|
754
|
+
color: "#000000",
|
|
755
|
+
border: "1px solid #ccc",
|
|
756
|
+
borderRadius: "4px",
|
|
757
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
|
|
758
|
+
minWidth: "200px",
|
|
759
|
+
zIndex: zIndexMap.viewMenu
|
|
760
|
+
},
|
|
761
|
+
children: [
|
|
762
|
+
/* @__PURE__ */ jsxs3(
|
|
763
|
+
"div",
|
|
764
|
+
{
|
|
765
|
+
onClick: () => {
|
|
766
|
+
if (hasGroups) {
|
|
767
|
+
onToggleGroups(!showGroups);
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
style: {
|
|
771
|
+
padding: "8px 12px",
|
|
772
|
+
cursor: hasGroups ? "pointer" : "not-allowed",
|
|
773
|
+
opacity: hasGroups ? 1 : 0.5,
|
|
774
|
+
fontSize: "13px",
|
|
775
|
+
color: "#000000",
|
|
776
|
+
fontFamily: "sans-serif",
|
|
777
|
+
display: "flex",
|
|
778
|
+
alignItems: "center",
|
|
779
|
+
gap: "8px"
|
|
780
|
+
},
|
|
781
|
+
onMouseEnter: (e) => {
|
|
782
|
+
if (hasGroups) {
|
|
783
|
+
e.currentTarget.style.backgroundColor = "#f0f0f0";
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
onMouseLeave: (e) => {
|
|
787
|
+
if (hasGroups) {
|
|
788
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
children: [
|
|
792
|
+
/* @__PURE__ */ jsx4(
|
|
793
|
+
"div",
|
|
794
|
+
{
|
|
795
|
+
style: {
|
|
796
|
+
width: "16px",
|
|
797
|
+
height: "16px",
|
|
798
|
+
border: "2px solid #000",
|
|
799
|
+
borderRadius: "2px",
|
|
800
|
+
backgroundColor: "transparent",
|
|
801
|
+
display: "flex",
|
|
802
|
+
alignItems: "center",
|
|
803
|
+
justifyContent: "center",
|
|
804
|
+
fontSize: "10px",
|
|
805
|
+
fontWeight: "bold"
|
|
806
|
+
},
|
|
807
|
+
children: showGroups && "\u2713"
|
|
808
|
+
}
|
|
809
|
+
),
|
|
810
|
+
"View Schematic Groups"
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
),
|
|
814
|
+
!hasGroups && /* @__PURE__ */ jsx4(
|
|
815
|
+
"div",
|
|
816
|
+
{
|
|
817
|
+
style: {
|
|
818
|
+
padding: "8px 12px",
|
|
819
|
+
fontSize: "11px",
|
|
820
|
+
color: "#666",
|
|
821
|
+
fontStyle: "italic"
|
|
822
|
+
},
|
|
823
|
+
children: "No groups found in this schematic"
|
|
824
|
+
}
|
|
825
|
+
)
|
|
826
|
+
]
|
|
827
|
+
}
|
|
828
|
+
)
|
|
829
|
+
] });
|
|
830
|
+
};
|
|
831
|
+
|
|
478
832
|
// lib/components/SpiceIcon.tsx
|
|
479
|
-
import { jsx as
|
|
480
|
-
var SpiceIcon = () => /* @__PURE__ */
|
|
833
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
834
|
+
var SpiceIcon = () => /* @__PURE__ */ jsx5(
|
|
481
835
|
"svg",
|
|
482
836
|
{
|
|
483
837
|
width: "16",
|
|
@@ -488,23 +842,23 @@ var SpiceIcon = () => /* @__PURE__ */ jsx3(
|
|
|
488
842
|
strokeWidth: "2",
|
|
489
843
|
strokeLinecap: "round",
|
|
490
844
|
strokeLinejoin: "round",
|
|
491
|
-
children: /* @__PURE__ */
|
|
845
|
+
children: /* @__PURE__ */ jsx5("path", { d: "M3 12h2.5l2.5-9 4 18 4-9h5.5" })
|
|
492
846
|
}
|
|
493
847
|
);
|
|
494
848
|
|
|
495
849
|
// lib/components/SpiceSimulationIcon.tsx
|
|
496
|
-
import { jsx as
|
|
850
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
497
851
|
var SpiceSimulationIcon = ({
|
|
498
852
|
onClick
|
|
499
853
|
}) => {
|
|
500
|
-
return /* @__PURE__ */
|
|
854
|
+
return /* @__PURE__ */ jsx6(
|
|
501
855
|
"div",
|
|
502
856
|
{
|
|
503
857
|
onClick,
|
|
504
858
|
style: {
|
|
505
859
|
position: "absolute",
|
|
506
860
|
top: "16px",
|
|
507
|
-
right: "
|
|
861
|
+
right: "112px",
|
|
508
862
|
backgroundColor: "#fff",
|
|
509
863
|
color: "#000",
|
|
510
864
|
padding: "8px",
|
|
@@ -516,7 +870,7 @@ var SpiceSimulationIcon = ({
|
|
|
516
870
|
gap: "4px",
|
|
517
871
|
zIndex: zIndexMap.spiceSimulationIcon
|
|
518
872
|
},
|
|
519
|
-
children: /* @__PURE__ */
|
|
873
|
+
children: /* @__PURE__ */ jsx6(SpiceIcon, {})
|
|
520
874
|
}
|
|
521
875
|
);
|
|
522
876
|
};
|
|
@@ -533,7 +887,7 @@ import {
|
|
|
533
887
|
Legend
|
|
534
888
|
} from "chart.js";
|
|
535
889
|
import { Line } from "react-chartjs-2";
|
|
536
|
-
import { jsx as
|
|
890
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
537
891
|
ChartJS.register(
|
|
538
892
|
CategoryScale,
|
|
539
893
|
LinearScale,
|
|
@@ -574,7 +928,7 @@ var SpicePlot = ({
|
|
|
574
928
|
error
|
|
575
929
|
}) => {
|
|
576
930
|
if (isLoading) {
|
|
577
|
-
return /* @__PURE__ */
|
|
931
|
+
return /* @__PURE__ */ jsx7(
|
|
578
932
|
"div",
|
|
579
933
|
{
|
|
580
934
|
style: {
|
|
@@ -589,7 +943,7 @@ var SpicePlot = ({
|
|
|
589
943
|
);
|
|
590
944
|
}
|
|
591
945
|
if (error) {
|
|
592
|
-
return /* @__PURE__ */
|
|
946
|
+
return /* @__PURE__ */ jsxs4(
|
|
593
947
|
"div",
|
|
594
948
|
{
|
|
595
949
|
style: {
|
|
@@ -608,7 +962,7 @@ var SpicePlot = ({
|
|
|
608
962
|
);
|
|
609
963
|
}
|
|
610
964
|
if (plotData.length === 0) {
|
|
611
|
-
return /* @__PURE__ */
|
|
965
|
+
return /* @__PURE__ */ jsx7(
|
|
612
966
|
"div",
|
|
613
967
|
{
|
|
614
968
|
style: {
|
|
@@ -695,11 +1049,11 @@ var SpicePlot = ({
|
|
|
695
1049
|
}
|
|
696
1050
|
}
|
|
697
1051
|
};
|
|
698
|
-
return /* @__PURE__ */
|
|
1052
|
+
return /* @__PURE__ */ jsx7("div", { style: { position: "relative", height: "300px", width: "100%" }, children: /* @__PURE__ */ jsx7(Line, { options, data: chartData }) });
|
|
699
1053
|
};
|
|
700
1054
|
|
|
701
1055
|
// lib/components/SpiceSimulationOverlay.tsx
|
|
702
|
-
import { jsx as
|
|
1056
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
703
1057
|
var SpiceSimulationOverlay = ({
|
|
704
1058
|
spiceString,
|
|
705
1059
|
onClose,
|
|
@@ -708,7 +1062,7 @@ var SpiceSimulationOverlay = ({
|
|
|
708
1062
|
isLoading,
|
|
709
1063
|
error
|
|
710
1064
|
}) => {
|
|
711
|
-
return /* @__PURE__ */
|
|
1065
|
+
return /* @__PURE__ */ jsx8(
|
|
712
1066
|
"div",
|
|
713
1067
|
{
|
|
714
1068
|
style: {
|
|
@@ -724,7 +1078,7 @@ var SpiceSimulationOverlay = ({
|
|
|
724
1078
|
zIndex: 1002,
|
|
725
1079
|
fontFamily: "sans-serif"
|
|
726
1080
|
},
|
|
727
|
-
children: /* @__PURE__ */
|
|
1081
|
+
children: /* @__PURE__ */ jsxs5(
|
|
728
1082
|
"div",
|
|
729
1083
|
{
|
|
730
1084
|
style: {
|
|
@@ -736,7 +1090,7 @@ var SpiceSimulationOverlay = ({
|
|
|
736
1090
|
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.15)"
|
|
737
1091
|
},
|
|
738
1092
|
children: [
|
|
739
|
-
/* @__PURE__ */
|
|
1093
|
+
/* @__PURE__ */ jsxs5(
|
|
740
1094
|
"div",
|
|
741
1095
|
{
|
|
742
1096
|
style: {
|
|
@@ -748,7 +1102,7 @@ var SpiceSimulationOverlay = ({
|
|
|
748
1102
|
paddingBottom: "16px"
|
|
749
1103
|
},
|
|
750
1104
|
children: [
|
|
751
|
-
/* @__PURE__ */
|
|
1105
|
+
/* @__PURE__ */ jsx8(
|
|
752
1106
|
"h2",
|
|
753
1107
|
{
|
|
754
1108
|
style: {
|
|
@@ -760,7 +1114,7 @@ var SpiceSimulationOverlay = ({
|
|
|
760
1114
|
children: "SPICE Simulation"
|
|
761
1115
|
}
|
|
762
1116
|
),
|
|
763
|
-
/* @__PURE__ */
|
|
1117
|
+
/* @__PURE__ */ jsx8(
|
|
764
1118
|
"button",
|
|
765
1119
|
{
|
|
766
1120
|
onClick: onClose,
|
|
@@ -779,7 +1133,7 @@ var SpiceSimulationOverlay = ({
|
|
|
779
1133
|
]
|
|
780
1134
|
}
|
|
781
1135
|
),
|
|
782
|
-
/* @__PURE__ */
|
|
1136
|
+
/* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsx8(
|
|
783
1137
|
SpicePlot,
|
|
784
1138
|
{
|
|
785
1139
|
plotData,
|
|
@@ -788,8 +1142,8 @@ var SpiceSimulationOverlay = ({
|
|
|
788
1142
|
error
|
|
789
1143
|
}
|
|
790
1144
|
) }),
|
|
791
|
-
/* @__PURE__ */
|
|
792
|
-
/* @__PURE__ */
|
|
1145
|
+
/* @__PURE__ */ jsxs5("div", { style: { marginTop: "24px" }, children: [
|
|
1146
|
+
/* @__PURE__ */ jsx8(
|
|
793
1147
|
"h3",
|
|
794
1148
|
{
|
|
795
1149
|
style: {
|
|
@@ -802,7 +1156,7 @@ var SpiceSimulationOverlay = ({
|
|
|
802
1156
|
children: "SPICE Netlist"
|
|
803
1157
|
}
|
|
804
1158
|
),
|
|
805
|
-
/* @__PURE__ */
|
|
1159
|
+
/* @__PURE__ */ jsx8(
|
|
806
1160
|
"pre",
|
|
807
1161
|
{
|
|
808
1162
|
style: {
|
|
@@ -828,7 +1182,7 @@ var SpiceSimulationOverlay = ({
|
|
|
828
1182
|
};
|
|
829
1183
|
|
|
830
1184
|
// lib/hooks/useSpiceSimulation.ts
|
|
831
|
-
import { useState as useState3, useEffect as
|
|
1185
|
+
import { useState as useState3, useEffect as useEffect6 } from "react";
|
|
832
1186
|
|
|
833
1187
|
// lib/workers/spice-simulation.worker.blob.js
|
|
834
1188
|
var b64 = "dmFyIGU9bnVsbCxzPWFzeW5jKCk9Pihhd2FpdCBpbXBvcnQoImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vZWVjaXJjdWl0LWVuZ2luZUAxLjUuMi8rZXNtIikpLlNpbXVsYXRpb24sYz1hc3luYygpPT57aWYoZSYmZS5pc0luaXRpYWxpemVkKCkpcmV0dXJuO2xldCBpPWF3YWl0IHMoKTtlPW5ldyBpLGF3YWl0IGUuc3RhcnQoKX07c2VsZi5vbm1lc3NhZ2U9YXN5bmMgaT0+e3RyeXtpZihhd2FpdCBjKCksIWUpdGhyb3cgbmV3IEVycm9yKCJTaW11bGF0aW9uIG5vdCBpbml0aWFsaXplZCIpO2xldCB0PWkuZGF0YS5zcGljZVN0cmluZyxhPXQubWF0Y2goL3dyZGF0YVxzKyhcUyspXHMrKC4qKS9pKTtpZihhKXtsZXQgbz1gLnByb2JlICR7YVsyXS50cmltKCkuc3BsaXQoL1xzKy8pLmpvaW4oIiAiKX1gO3Q9dC5yZXBsYWNlKC93cmRhdGEuKi9pLG8pfWVsc2UgaWYoIXQubWF0Y2goL1wucHJvYmUvaSkpdGhyb3cgdC5tYXRjaCgvcGxvdFxzKyguKikvaSk/bmV3IEVycm9yKCJUaGUgJ3Bsb3QnIGNvbW1hbmQgaXMgbm90IHN1cHBvcnRlZCBmb3IgZGF0YSBleHRyYWN0aW9uLiBQbGVhc2UgdXNlICd3cmRhdGEgPGZpbGVuYW1lPiA8dmFyMT4gLi4uJyBvciAnLnByb2JlIDx2YXIxPiAuLi4nIGluc3RlYWQuIik6bmV3IEVycm9yKCJObyAnLnByb2JlJyBvciAnd3JkYXRhJyBjb21tYW5kIGZvdW5kIGluIFNQSUNFIGZpbGUuIFVzZSAnd3JkYXRhIDxmaWxlbmFtZT4gPHZhcjE+IC4uLicgdG8gc3BlY2lmeSBvdXRwdXQuIik7ZS5zZXROZXRMaXN0KHQpO2xldCBuPWF3YWl0IGUucnVuU2ltKCk7c2VsZi5wb3N0TWVzc2FnZSh7dHlwZToicmVzdWx0IixyZXN1bHQ6bn0pfWNhdGNoKHQpe3NlbGYucG9zdE1lc3NhZ2Uoe3R5cGU6ImVycm9yIixlcnJvcjp0Lm1lc3NhZ2V9KX19Owo=";
|
|
@@ -885,7 +1239,7 @@ var useSpiceSimulation = (spiceString) => {
|
|
|
885
1239
|
const [nodes, setNodes] = useState3([]);
|
|
886
1240
|
const [isLoading, setIsLoading] = useState3(true);
|
|
887
1241
|
const [error, setError] = useState3(null);
|
|
888
|
-
|
|
1242
|
+
useEffect6(() => {
|
|
889
1243
|
if (!spiceString) {
|
|
890
1244
|
setIsLoading(false);
|
|
891
1245
|
setPlotData([]);
|
|
@@ -991,7 +1345,7 @@ var getSpiceFromCircuitJson = (circuitJson) => {
|
|
|
991
1345
|
};
|
|
992
1346
|
|
|
993
1347
|
// lib/components/SchematicViewer.tsx
|
|
994
|
-
import { jsx as
|
|
1348
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
995
1349
|
var SchematicViewer = ({
|
|
996
1350
|
circuitJson,
|
|
997
1351
|
containerStyle,
|
|
@@ -1012,11 +1366,11 @@ var SchematicViewer = ({
|
|
|
1012
1366
|
const getCircuitHash = (circuitJson2) => {
|
|
1013
1367
|
return `${circuitJson2?.length || 0}_${circuitJson2?.editCount || 0}`;
|
|
1014
1368
|
};
|
|
1015
|
-
const circuitJsonKey =
|
|
1369
|
+
const circuitJsonKey = useMemo2(
|
|
1016
1370
|
() => getCircuitHash(circuitJson),
|
|
1017
1371
|
[circuitJson]
|
|
1018
1372
|
);
|
|
1019
|
-
const spiceString =
|
|
1373
|
+
const spiceString = useMemo2(() => {
|
|
1020
1374
|
if (!spiceSimulationEnabled) return null;
|
|
1021
1375
|
try {
|
|
1022
1376
|
return getSpiceFromCircuitJson(circuitJson);
|
|
@@ -1036,6 +1390,8 @@ var SchematicViewer = ({
|
|
|
1036
1390
|
const [isInteractionEnabled, setIsInteractionEnabled] = useState4(
|
|
1037
1391
|
!clickToInteractEnabled
|
|
1038
1392
|
);
|
|
1393
|
+
const [showViewMenu, setShowViewMenu] = useState4(false);
|
|
1394
|
+
const [showSchematicGroups, setShowSchematicGroups] = useState4(false);
|
|
1039
1395
|
const svgDivRef = useRef4(null);
|
|
1040
1396
|
const touchStartRef = useRef4(null);
|
|
1041
1397
|
const handleTouchStart = (e) => {
|
|
@@ -1059,7 +1415,7 @@ var SchematicViewer = ({
|
|
|
1059
1415
|
};
|
|
1060
1416
|
const [internalEditEvents, setInternalEditEvents] = useState4([]);
|
|
1061
1417
|
const circuitJsonRef = useRef4(circuitJson);
|
|
1062
|
-
|
|
1418
|
+
useEffect7(() => {
|
|
1063
1419
|
const circuitHash = getCircuitHash(circuitJson);
|
|
1064
1420
|
const circuitHashRef = getCircuitHash(circuitJsonRef.current);
|
|
1065
1421
|
if (circuitHash !== circuitHashRef) {
|
|
@@ -1080,7 +1436,7 @@ var SchematicViewer = ({
|
|
|
1080
1436
|
enabled: isInteractionEnabled && !showSpiceOverlay
|
|
1081
1437
|
});
|
|
1082
1438
|
const { containerWidth, containerHeight } = useResizeHandling(containerRef);
|
|
1083
|
-
const svgString =
|
|
1439
|
+
const svgString = useMemo2(() => {
|
|
1084
1440
|
if (!containerWidth || !containerHeight) return "";
|
|
1085
1441
|
return convertCircuitJsonToSchematicSvg(circuitJson, {
|
|
1086
1442
|
width: containerWidth,
|
|
@@ -1092,13 +1448,13 @@ var SchematicViewer = ({
|
|
|
1092
1448
|
colorOverrides
|
|
1093
1449
|
});
|
|
1094
1450
|
}, [circuitJson, containerWidth, containerHeight]);
|
|
1095
|
-
const containerBackgroundColor =
|
|
1451
|
+
const containerBackgroundColor = useMemo2(() => {
|
|
1096
1452
|
const match = svgString.match(
|
|
1097
1453
|
/<svg[^>]*style="[^"]*background-color:\s*([^;\"]+)/i
|
|
1098
1454
|
);
|
|
1099
1455
|
return match?.[1] ?? "transparent";
|
|
1100
1456
|
}, [svgString]);
|
|
1101
|
-
const realToSvgProjection =
|
|
1457
|
+
const realToSvgProjection = useMemo2(() => {
|
|
1102
1458
|
if (!svgString) return identity();
|
|
1103
1459
|
const transformString = svgString.match(
|
|
1104
1460
|
/data-real-to-screen-transform="([^"]+)"/
|
|
@@ -1116,7 +1472,7 @@ var SchematicViewer = ({
|
|
|
1116
1472
|
onEditEvent(event);
|
|
1117
1473
|
}
|
|
1118
1474
|
};
|
|
1119
|
-
const editEventsWithUnappliedEditEvents =
|
|
1475
|
+
const editEventsWithUnappliedEditEvents = useMemo2(() => {
|
|
1120
1476
|
return [...unappliedEditEvents, ...internalEditEvents];
|
|
1121
1477
|
}, [unappliedEditEvents, internalEditEvents]);
|
|
1122
1478
|
const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
|
|
@@ -1144,8 +1500,9 @@ var SchematicViewer = ({
|
|
|
1144
1500
|
activeEditEvent,
|
|
1145
1501
|
editEvents: editEventsWithUnappliedEditEvents
|
|
1146
1502
|
});
|
|
1147
|
-
|
|
1148
|
-
|
|
1503
|
+
useSchematicGroupsOverlay(svgDivRef, circuitJson, circuitJsonKey, showSchematicGroups);
|
|
1504
|
+
const svgDiv = useMemo2(
|
|
1505
|
+
() => /* @__PURE__ */ jsx9(
|
|
1149
1506
|
"div",
|
|
1150
1507
|
{
|
|
1151
1508
|
ref: svgDivRef,
|
|
@@ -1158,7 +1515,7 @@ var SchematicViewer = ({
|
|
|
1158
1515
|
),
|
|
1159
1516
|
[svgString, isInteractionEnabled, clickToInteractEnabled]
|
|
1160
1517
|
);
|
|
1161
|
-
return /* @__PURE__ */
|
|
1518
|
+
return /* @__PURE__ */ jsxs6(
|
|
1162
1519
|
"div",
|
|
1163
1520
|
{
|
|
1164
1521
|
ref: containerRef,
|
|
@@ -1199,7 +1556,7 @@ var SchematicViewer = ({
|
|
|
1199
1556
|
handleTouchEnd(e);
|
|
1200
1557
|
},
|
|
1201
1558
|
children: [
|
|
1202
|
-
!isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */
|
|
1559
|
+
!isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx9(
|
|
1203
1560
|
"div",
|
|
1204
1561
|
{
|
|
1205
1562
|
onClick: (e) => {
|
|
@@ -1218,7 +1575,7 @@ var SchematicViewer = ({
|
|
|
1218
1575
|
pointerEvents: "all",
|
|
1219
1576
|
touchAction: "pan-x pan-y pinch-zoom"
|
|
1220
1577
|
},
|
|
1221
|
-
children: /* @__PURE__ */
|
|
1578
|
+
children: /* @__PURE__ */ jsx9(
|
|
1222
1579
|
"div",
|
|
1223
1580
|
{
|
|
1224
1581
|
style: {
|
|
@@ -1235,22 +1592,40 @@ var SchematicViewer = ({
|
|
|
1235
1592
|
)
|
|
1236
1593
|
}
|
|
1237
1594
|
),
|
|
1238
|
-
|
|
1595
|
+
/* @__PURE__ */ jsx9(
|
|
1596
|
+
ViewMenuIcon,
|
|
1597
|
+
{
|
|
1598
|
+
active: showViewMenu,
|
|
1599
|
+
onClick: () => setShowViewMenu(!showViewMenu)
|
|
1600
|
+
}
|
|
1601
|
+
),
|
|
1602
|
+
editingEnabled && /* @__PURE__ */ jsx9(
|
|
1239
1603
|
EditIcon,
|
|
1240
1604
|
{
|
|
1241
1605
|
active: editModeEnabled,
|
|
1242
1606
|
onClick: () => setEditModeEnabled(!editModeEnabled)
|
|
1243
1607
|
}
|
|
1244
1608
|
),
|
|
1245
|
-
editingEnabled && editModeEnabled && /* @__PURE__ */
|
|
1609
|
+
editingEnabled && editModeEnabled && /* @__PURE__ */ jsx9(
|
|
1246
1610
|
GridIcon,
|
|
1247
1611
|
{
|
|
1248
1612
|
active: snapToGrid,
|
|
1249
1613
|
onClick: () => setSnapToGrid(!snapToGrid)
|
|
1250
1614
|
}
|
|
1251
1615
|
),
|
|
1252
|
-
|
|
1253
|
-
|
|
1616
|
+
/* @__PURE__ */ jsx9(
|
|
1617
|
+
ViewMenu,
|
|
1618
|
+
{
|
|
1619
|
+
circuitJson,
|
|
1620
|
+
circuitJsonKey,
|
|
1621
|
+
isVisible: showViewMenu,
|
|
1622
|
+
onClose: () => setShowViewMenu(false),
|
|
1623
|
+
showGroups: showSchematicGroups,
|
|
1624
|
+
onToggleGroups: setShowSchematicGroups
|
|
1625
|
+
}
|
|
1626
|
+
),
|
|
1627
|
+
spiceSimulationEnabled && /* @__PURE__ */ jsx9(SpiceSimulationIcon, { onClick: () => setShowSpiceOverlay(true) }),
|
|
1628
|
+
showSpiceOverlay && /* @__PURE__ */ jsx9(
|
|
1254
1629
|
SpiceSimulationOverlay,
|
|
1255
1630
|
{
|
|
1256
1631
|
spiceString,
|