@tscircuit/schematic-viewer 2.0.78 → 2.0.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,47 @@
1
1
  // lib/components/SchematicViewer.tsx
2
+ import { su as su4 } from "@tscircuit/soup-util";
2
3
  import {
3
4
  convertCircuitJsonToSchematicSvg
4
5
  } from "circuit-to-svg";
5
- import { su as su4 } from "@tscircuit/soup-util";
6
+
7
+ // lib/hooks/useLocalStorage.ts
8
+ import { useCallback } from "react";
9
+ var STORAGE_KEYS = {
10
+ IS_SHOWING_SCHEMATIC_GROUPS: "schematic_viewer_show_groups",
11
+ IS_SHOWING_SCHEMATIC_PORTS: "schematic_viewer_show_ports",
12
+ SELECTED_SCHEMATIC_SHEET: "schematic_viewer_selected_sheet"
13
+ };
14
+ var getStoredBoolean = (key, defaultValue) => {
15
+ if (typeof window === "undefined") return defaultValue;
16
+ try {
17
+ const stored = localStorage.getItem(key);
18
+ return stored !== null ? JSON.parse(stored) : defaultValue;
19
+ } catch {
20
+ return defaultValue;
21
+ }
22
+ };
23
+ var setStoredBoolean = (key, value) => {
24
+ if (typeof window === "undefined") return;
25
+ try {
26
+ localStorage.setItem(key, JSON.stringify(value));
27
+ } catch {
28
+ }
29
+ };
30
+ var getStoredString = (key) => {
31
+ if (typeof window === "undefined") return null;
32
+ try {
33
+ return localStorage.getItem(key);
34
+ } catch {
35
+ return null;
36
+ }
37
+ };
38
+ var setStoredString = (key, value) => {
39
+ if (typeof window === "undefined") return;
40
+ try {
41
+ localStorage.setItem(key, value);
42
+ } catch {
43
+ }
44
+ };
6
45
 
7
46
  // lib/hooks/useSchematicGroupsOverlay.ts
8
47
  import { useEffect } from "react";
@@ -399,7 +438,7 @@ var enableDebug = () => {
399
438
  };
400
439
 
401
440
  // lib/components/SchematicViewer.tsx
402
- import { useCallback as useCallback5, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
441
+ import { useCallback as useCallback6, useEffect as useEffect9, useMemo as useMemo4, useRef as useRef6, useState as useState6 } from "react";
403
442
  import { toString as transformToString } from "transformation-matrix";
404
443
  import { useMouseMatrixTransform } from "use-mouse-matrix-transform";
405
444
 
@@ -427,328 +466,135 @@ var useResizeHandling = (containerRef) => {
427
466
  return { containerWidth, containerHeight };
428
467
  };
429
468
 
430
- // lib/components/ViewMenu.tsx
431
- import { useMemo } from "react";
432
- import { su as su3 } from "@tscircuit/soup-util";
433
- import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
469
+ // lib/hooks/useContextMenu.ts
470
+ import { useCallback as useCallback2, useEffect as useEffect4, useRef, useState as useState2 } from "react";
471
+ var LONG_PRESS_DURATION_MS = 600;
472
+ var MOVEMENT_THRESHOLD_PX = 10;
473
+ var useContextMenu = ({ containerRef }) => {
474
+ const [menuVisible, setMenuVisible] = useState2(false);
475
+ const [menuPos, setMenuPos] = useState2({ x: 0, y: 0 });
476
+ const menuRef = useRef(null);
477
+ const interactionOriginRef = useRef(null);
478
+ const longPressTimeoutRef = useRef(null);
479
+ const ignoreContextMenuUntilRef = useRef(0);
480
+ const clearLongPressTimeout = useCallback2(() => {
481
+ if (longPressTimeoutRef.current === null) return;
482
+ window.clearTimeout(longPressTimeoutRef.current);
483
+ longPressTimeoutRef.current = null;
484
+ }, []);
485
+ const handleContextMenu = useCallback2((event) => {
486
+ event.preventDefault();
487
+ if (Date.now() < ignoreContextMenuUntilRef.current) return;
488
+ const origin = interactionOriginRef.current;
489
+ if (!origin) return;
490
+ const movedTooFar = Math.abs(event.clientX - origin.x) > MOVEMENT_THRESHOLD_PX || Math.abs(event.clientY - origin.y) > MOVEMENT_THRESHOLD_PX;
491
+ interactionOriginRef.current = null;
492
+ if (movedTooFar) return;
493
+ setMenuPos({ x: event.clientX, y: event.clientY });
494
+ setMenuVisible(true);
495
+ }, []);
496
+ const handleTouchStart = useCallback2(
497
+ (event) => {
498
+ clearLongPressTimeout();
499
+ if (event.touches.length !== 1) {
500
+ interactionOriginRef.current = null;
501
+ return;
502
+ }
503
+ const touch = event.touches[0];
504
+ if (!touch) return;
505
+ interactionOriginRef.current = {
506
+ x: touch.clientX,
507
+ y: touch.clientY
508
+ };
509
+ longPressTimeoutRef.current = window.setTimeout(() => {
510
+ const container = containerRef.current;
511
+ if (!container || !interactionOriginRef.current) return;
512
+ const rect = container.getBoundingClientRect();
513
+ setMenuPos({
514
+ x: rect.left + rect.width / 2,
515
+ y: rect.top + rect.height / 2
516
+ });
517
+ setMenuVisible(true);
518
+ ignoreContextMenuUntilRef.current = Date.now() + 1e3;
519
+ interactionOriginRef.current = null;
520
+ }, LONG_PRESS_DURATION_MS);
521
+ },
522
+ [clearLongPressTimeout, containerRef]
523
+ );
524
+ const handleTouchMove = useCallback2(
525
+ (event) => {
526
+ const origin = interactionOriginRef.current;
527
+ if (!origin || event.touches.length !== 1) return;
528
+ const touch = event.touches[0];
529
+ const movedTooFar = !touch || Math.abs(touch.clientX - origin.x) > MOVEMENT_THRESHOLD_PX || Math.abs(touch.clientY - origin.y) > MOVEMENT_THRESHOLD_PX;
530
+ if (movedTooFar) {
531
+ interactionOriginRef.current = null;
532
+ clearLongPressTimeout();
533
+ }
534
+ },
535
+ [clearLongPressTimeout]
536
+ );
537
+ const handleTouchEnd = useCallback2(() => {
538
+ clearLongPressTimeout();
539
+ interactionOriginRef.current = null;
540
+ }, [clearLongPressTimeout]);
541
+ const handleClickAway = useCallback2((event) => {
542
+ const target = event.target;
543
+ if (menuRef.current?.contains(target)) return;
544
+ const isInRadixPortal = target.closest?.(
545
+ "[data-radix-popper-content-wrapper], [data-radix-dropdown-menu-content]"
546
+ );
547
+ if (isInRadixPortal) return;
548
+ setMenuVisible(false);
549
+ }, []);
550
+ useEffect4(() => {
551
+ if (!menuVisible) return;
552
+ document.addEventListener("mousedown", handleClickAway);
553
+ document.addEventListener("touchstart", handleClickAway);
554
+ return () => {
555
+ document.removeEventListener("mousedown", handleClickAway);
556
+ document.removeEventListener("touchstart", handleClickAway);
557
+ };
558
+ }, [handleClickAway, menuVisible]);
559
+ useEffect4(() => clearLongPressTimeout, [clearLongPressTimeout]);
560
+ return {
561
+ menuVisible,
562
+ menuPos,
563
+ menuRef,
564
+ setMenuVisible,
565
+ contextMenuEventHandlers: {
566
+ onMouseDown: (event) => {
567
+ interactionOriginRef.current = event.button === 2 || event.button === 0 && event.ctrlKey ? { x: event.clientX, y: event.clientY } : null;
568
+ },
569
+ onContextMenu: handleContextMenu,
570
+ onTouchStart: handleTouchStart,
571
+ onTouchMove: handleTouchMove,
572
+ onTouchEnd: handleTouchEnd,
573
+ onTouchCancel: handleTouchEnd
574
+ }
575
+ };
576
+ };
434
577
 
435
578
  // lib/utils/z-index-map.ts
436
579
  var zIndexMap = {
437
- viewMenuIcon: 48,
580
+ contextMenu: 110,
438
581
  viewMenu: 55,
439
- viewMenuBackdrop: 54,
582
+ viewMenuIcon: 48,
440
583
  clickToInteractOverlay: 100,
441
584
  schematicComponentHoverOutline: 47,
442
585
  schematicPortHoverOutline: 48
443
586
  };
444
587
 
445
- // package.json
446
- var package_default = {
447
- name: "@tscircuit/schematic-viewer",
448
- version: "2.0.77",
449
- main: "dist/index.js",
450
- type: "module",
451
- scripts: {
452
- start: "cosmos",
453
- build: "tsup-node ./lib/index.ts --dts --format esm --sourcemap",
454
- "build:site": "cosmos-export",
455
- "vercel-build": "bun run build:site",
456
- format: "biome format --write .",
457
- "format:check": "biome format ."
458
- },
459
- files: [
460
- "dist"
461
- ],
462
- devDependencies: {
463
- "@biomejs/biome": "^1.9.4",
464
- "@types/bun": "latest",
465
- "@types/debug": "^4.1.12",
466
- "@types/react": "^19.0.1",
467
- "@types/react-dom": "^19.0.2",
468
- "@vitejs/plugin-react": "^4.3.4",
469
- react: "^19.1.0",
470
- "react-cosmos": "^6.2.1",
471
- "react-cosmos-plugin-vite": "^6.2.0",
472
- "react-dom": "^19.1.0",
473
- "react-reconciler": "^0.31.0",
474
- semver: "^7.7.2",
475
- tscircuit: "^0.0.2112",
476
- tsup: "^8.3.5",
477
- vite: "^6.0.3"
478
- },
479
- peerDependencies: {
480
- typescript: "^5.0.0",
481
- tscircuit: "*"
482
- },
483
- dependencies: {
484
- "@radix-ui/react-dropdown-menu": "^2.1.16",
485
- "circuit-json": "^0.0.465",
486
- "circuit-to-svg": "^0.0.393",
487
- debug: "^4.4.0",
488
- "performance-now": "^2.1.0",
489
- "use-mouse-matrix-transform": "^1.2.2"
490
- }
491
- };
492
-
493
- // lib/components/ViewMenuIcon.tsx
494
- import { jsx, jsxs } from "react/jsx-runtime";
495
- var ViewMenuIcon = ({
496
- active = false,
497
- ...props
498
- }) => {
499
- return /* @__PURE__ */ jsx(
500
- "button",
501
- {
502
- type: "button",
503
- title: active ? "Hide view menu" : "Show view menu",
504
- ...props,
505
- style: {
506
- position: "absolute",
507
- top: "16px",
508
- right: "16px",
509
- backgroundColor: active ? "#4CAF50" : "#fff",
510
- color: active ? "#fff" : "#000",
511
- padding: "8px",
512
- border: "none",
513
- borderRadius: "4px",
514
- cursor: "pointer",
515
- outline: "none",
516
- boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
517
- display: "flex",
518
- alignItems: "center",
519
- gap: "4px",
520
- zIndex: zIndexMap.viewMenuIcon
521
- },
522
- children: /* @__PURE__ */ jsxs(
523
- "svg",
524
- {
525
- width: "16",
526
- height: "16",
527
- viewBox: "0 0 24 24",
528
- fill: "none",
529
- stroke: "currentColor",
530
- strokeWidth: "2",
531
- children: [
532
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1" }),
533
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1" }),
534
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1" })
535
- ]
536
- }
537
- )
538
- }
539
- );
540
- };
541
-
542
- // lib/components/ViewMenu.tsx
543
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
544
- var FONT_FAMILY = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
545
- var contentStyles = {
546
- backgroundColor: "#ffffff",
547
- color: "#111111",
548
- borderRadius: 8,
549
- boxShadow: "0 6px 24px rgba(0,0,0,0.12), 0 1px 3px rgba(0,0,0,0.08)",
550
- border: "1px solid #e5e7eb",
551
- padding: 4,
552
- minWidth: 224,
553
- fontSize: 13,
554
- fontFamily: FONT_FAMILY,
555
- outline: "none",
556
- zIndex: zIndexMap.viewMenu
557
- };
558
- var itemStyles = {
559
- display: "flex",
560
- alignItems: "center",
561
- gap: 8,
562
- padding: "7px 10px 7px 8px",
563
- borderRadius: 6,
564
- cursor: "pointer",
565
- outline: "none",
566
- userSelect: "none",
567
- color: "#111111",
568
- fontSize: 13,
569
- fontFamily: FONT_FAMILY
570
- };
571
- var iconSlotStyles = {
572
- width: 16,
573
- height: 16,
574
- flexShrink: 0,
575
- display: "inline-flex",
576
- alignItems: "center",
577
- justifyContent: "center",
578
- color: "#111111"
579
- };
580
- var separatorStyles = {
581
- height: 1,
582
- backgroundColor: "#ececec",
583
- margin: "4px 0"
584
- };
585
- var HIGHLIGHT_CSS = `
586
- .sv-vm-item[data-highlighted]:not([data-disabled]),
587
- .sv-vm-item:hover:not([data-disabled]) { background-color: #f1f3f5; }
588
- .sv-vm-item[data-disabled] { opacity: 0.45; cursor: not-allowed; }
589
- `;
590
- var CheckIcon = () => /* @__PURE__ */ jsx2(
591
- "svg",
592
- {
593
- width: "14",
594
- height: "14",
595
- viewBox: "0 0 24 24",
596
- fill: "none",
597
- stroke: "currentColor",
598
- strokeWidth: "2.5",
599
- strokeLinecap: "round",
600
- strokeLinejoin: "round",
601
- "aria-hidden": "true",
602
- children: /* @__PURE__ */ jsx2("path", { d: "M20 6 9 17l-5-5" })
603
- }
604
- );
605
- var ViewMenu = ({
606
- circuitJson,
607
- circuitJsonKey,
608
- open,
609
- onOpenChange,
610
- showGroups,
611
- onToggleGroups,
612
- showGrid,
613
- onToggleGrid
614
- }) => {
615
- const hasGroups = useMemo(() => {
616
- if (!circuitJson || circuitJson.length === 0) return false;
617
- try {
618
- const sourceGroups = su3(circuitJson).source_group?.list() || [];
619
- if (sourceGroups.length > 0) return true;
620
- const schematicComponents = su3(circuitJson).schematic_component?.list() || [];
621
- if (schematicComponents.length > 1) {
622
- const componentTypes = /* @__PURE__ */ new Set();
623
- for (const comp of schematicComponents) {
624
- const sourceComp = su3(circuitJson).source_component.get(
625
- comp.source_component_id
626
- );
627
- if (sourceComp?.ftype) {
628
- componentTypes.add(sourceComp.ftype);
629
- }
630
- }
631
- return componentTypes.size > 1;
632
- }
633
- return false;
634
- } catch (error) {
635
- console.error("Error checking for groups:", error);
636
- return false;
637
- }
638
- }, [circuitJsonKey]);
639
- return /* @__PURE__ */ jsxs2(DropdownMenu.Root, { open, onOpenChange, modal: false, children: [
640
- /* @__PURE__ */ jsx2(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx2(ViewMenuIcon, { active: open }) }),
641
- /* @__PURE__ */ jsx2(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs2(
642
- DropdownMenu.Content,
643
- {
644
- style: contentStyles,
645
- side: "bottom",
646
- align: "end",
647
- sideOffset: 8,
648
- collisionPadding: 10,
649
- children: [
650
- /* @__PURE__ */ jsx2("style", { children: HIGHLIGHT_CSS }),
651
- /* @__PURE__ */ jsxs2(
652
- DropdownMenu.Item,
653
- {
654
- className: "sv-vm-item",
655
- style: itemStyles,
656
- disabled: !hasGroups,
657
- title: hasGroups ? void 0 : "No groups found in this schematic",
658
- onSelect: (e) => e.preventDefault(),
659
- onPointerUp: () => {
660
- if (hasGroups) onToggleGroups(!showGroups);
661
- },
662
- children: [
663
- /* @__PURE__ */ jsx2("span", { style: iconSlotStyles, children: showGroups && /* @__PURE__ */ jsx2(CheckIcon, {}) }),
664
- /* @__PURE__ */ jsx2("span", { children: "View Schematic Groups" })
665
- ]
666
- }
667
- ),
668
- /* @__PURE__ */ jsxs2(
669
- DropdownMenu.Item,
670
- {
671
- className: "sv-vm-item",
672
- style: itemStyles,
673
- onSelect: (e) => e.preventDefault(),
674
- onPointerUp: () => onToggleGrid(!showGrid),
675
- children: [
676
- /* @__PURE__ */ jsx2("span", { style: iconSlotStyles, children: showGrid && /* @__PURE__ */ jsx2(CheckIcon, {}) }),
677
- /* @__PURE__ */ jsx2("span", { children: "Show Grid" })
678
- ]
679
- }
680
- ),
681
- /* @__PURE__ */ jsx2(DropdownMenu.Separator, { style: separatorStyles }),
682
- /* @__PURE__ */ jsxs2(
683
- "div",
684
- {
685
- style: {
686
- padding: "4px 8px",
687
- fontSize: 12,
688
- color: "#9ca3af",
689
- textAlign: "center",
690
- fontFamily: FONT_FAMILY
691
- },
692
- children: [
693
- "v",
694
- String(package_default?.version)
695
- ]
696
- }
697
- )
698
- ]
699
- }
700
- ) })
701
- ] });
702
- };
703
-
704
- // lib/hooks/useLocalStorage.ts
705
- import { useCallback } from "react";
706
- var STORAGE_KEYS = {
707
- IS_SHOWING_SCHEMATIC_GROUPS: "schematic_viewer_show_groups",
708
- SELECTED_SCHEMATIC_SHEET: "schematic_viewer_selected_sheet"
709
- };
710
- var getStoredBoolean = (key, defaultValue) => {
711
- if (typeof window === "undefined") return defaultValue;
712
- try {
713
- const stored = localStorage.getItem(key);
714
- return stored !== null ? JSON.parse(stored) : defaultValue;
715
- } catch {
716
- return defaultValue;
717
- }
718
- };
719
- var setStoredBoolean = (key, value) => {
720
- if (typeof window === "undefined") return;
721
- try {
722
- localStorage.setItem(key, JSON.stringify(value));
723
- } catch {
724
- }
725
- };
726
- var getStoredString = (key) => {
727
- if (typeof window === "undefined") return null;
728
- try {
729
- return localStorage.getItem(key);
730
- } catch {
731
- return null;
732
- }
733
- };
734
- var setStoredString = (key, value) => {
735
- if (typeof window === "undefined") return;
736
- try {
737
- localStorage.setItem(key, value);
738
- } catch {
739
- }
740
- };
741
-
742
588
  // lib/components/MouseTracker.tsx
743
589
  import {
744
590
  createContext,
745
- useCallback as useCallback2,
591
+ useCallback as useCallback3,
746
592
  useContext,
747
- useEffect as useEffect4,
748
- useMemo as useMemo2,
749
- useRef
593
+ useEffect as useEffect5,
594
+ useMemo,
595
+ useRef as useRef2
750
596
  } from "react";
751
- import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
597
+ import { Fragment, jsx } from "react/jsx-runtime";
752
598
  var MouseTrackerContext = createContext(null);
753
599
  var DRAG_THRESHOLD_PX = 5;
754
600
  var boundsAreEqual = (a, b) => {
@@ -759,24 +605,24 @@ var boundsAreEqual = (a, b) => {
759
605
  var MouseTracker = ({ children }) => {
760
606
  const existingContext = useContext(MouseTrackerContext);
761
607
  if (existingContext) {
762
- return /* @__PURE__ */ jsx3(Fragment, { children });
608
+ return /* @__PURE__ */ jsx(Fragment, { children });
763
609
  }
764
- return /* @__PURE__ */ jsx3(MouseTrackerProvider, { children });
610
+ return /* @__PURE__ */ jsx(MouseTrackerProvider, { children });
765
611
  };
766
612
  var MouseTrackerProvider = ({ children }) => {
767
- const storeRef = useRef({
613
+ const storeRef = useRef2({
768
614
  pointer: null,
769
615
  boundingBoxes: /* @__PURE__ */ new Map(),
770
616
  hoveringIds: /* @__PURE__ */ new Set(),
771
617
  subscribers: /* @__PURE__ */ new Set(),
772
618
  mouseDownPosition: null
773
619
  });
774
- const notifySubscribers = useCallback2(() => {
620
+ const notifySubscribers = useCallback3(() => {
775
621
  for (const callback of storeRef.current.subscribers) {
776
622
  callback();
777
623
  }
778
624
  }, []);
779
- const updateHovering = useCallback2(() => {
625
+ const updateHovering = useCallback3(() => {
780
626
  const pointer = storeRef.current.pointer;
781
627
  const newHovering = /* @__PURE__ */ new Set();
782
628
  if (pointer) {
@@ -795,14 +641,14 @@ var MouseTrackerProvider = ({ children }) => {
795
641
  storeRef.current.hoveringIds = newHovering;
796
642
  notifySubscribers();
797
643
  }, [notifySubscribers]);
798
- const registerBoundingBox = useCallback2(
644
+ const registerBoundingBox = useCallback3(
799
645
  (id, registration) => {
800
646
  storeRef.current.boundingBoxes.set(id, registration);
801
647
  updateHovering();
802
648
  },
803
649
  [updateHovering]
804
650
  );
805
- const updateBoundingBox = useCallback2(
651
+ const updateBoundingBox = useCallback3(
806
652
  (id, registration) => {
807
653
  const existing = storeRef.current.boundingBoxes.get(id);
808
654
  if (existing && boundsAreEqual(existing.bounds, registration.bounds) && existing.onClick === registration.onClick) {
@@ -813,7 +659,7 @@ var MouseTrackerProvider = ({ children }) => {
813
659
  },
814
660
  [updateHovering]
815
661
  );
816
- const unregisterBoundingBox = useCallback2(
662
+ const unregisterBoundingBox = useCallback3(
817
663
  (id) => {
818
664
  const removed = storeRef.current.boundingBoxes.delete(id);
819
665
  if (removed) {
@@ -822,16 +668,16 @@ var MouseTrackerProvider = ({ children }) => {
822
668
  },
823
669
  [updateHovering]
824
670
  );
825
- const subscribe = useCallback2((listener) => {
671
+ const subscribe = useCallback3((listener) => {
826
672
  storeRef.current.subscribers.add(listener);
827
673
  return () => {
828
674
  storeRef.current.subscribers.delete(listener);
829
675
  };
830
676
  }, []);
831
- const isHovering = useCallback2((id) => {
677
+ const isHovering = useCallback3((id) => {
832
678
  return storeRef.current.hoveringIds.has(id);
833
679
  }, []);
834
- useEffect4(() => {
680
+ useEffect5(() => {
835
681
  const handlePointerPosition = (event) => {
836
682
  const { clientX, clientY } = event;
837
683
  const pointer = storeRef.current.pointer;
@@ -899,7 +745,7 @@ var MouseTrackerProvider = ({ children }) => {
899
745
  window.removeEventListener("click", handleClick);
900
746
  };
901
747
  }, [updateHovering]);
902
- const value = useMemo2(
748
+ const value = useMemo(
903
749
  () => ({
904
750
  registerBoundingBox,
905
751
  updateBoundingBox,
@@ -915,19 +761,19 @@ var MouseTrackerProvider = ({ children }) => {
915
761
  isHovering
916
762
  ]
917
763
  );
918
- return /* @__PURE__ */ jsx3(MouseTrackerContext.Provider, { value, children });
764
+ return /* @__PURE__ */ jsx(MouseTrackerContext.Provider, { value, children });
919
765
  };
920
766
 
921
767
  // lib/components/SchematicComponentMouseTarget.tsx
922
- import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef3, useState as useState2 } from "react";
768
+ import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef4, useState as useState3 } from "react";
923
769
 
924
770
  // lib/hooks/useMouseEventsOverBoundingBox.ts
925
771
  import {
926
772
  useContext as useContext2,
927
- useEffect as useEffect5,
773
+ useEffect as useEffect6,
928
774
  useId,
929
- useMemo as useMemo3,
930
- useRef as useRef2,
775
+ useMemo as useMemo2,
776
+ useRef as useRef3,
931
777
  useSyncExternalStore
932
778
  } from "react";
933
779
  var useMouseEventsOverBoundingBox = (options) => {
@@ -938,15 +784,15 @@ var useMouseEventsOverBoundingBox = (options) => {
938
784
  );
939
785
  }
940
786
  const id = useId();
941
- const latestOptionsRef = useRef2(options);
787
+ const latestOptionsRef = useRef3(options);
942
788
  latestOptionsRef.current = options;
943
- const handleClick = useMemo3(
789
+ const handleClick = useMemo2(
944
790
  () => (event) => {
945
791
  latestOptionsRef.current.onClick?.(event);
946
792
  },
947
793
  []
948
794
  );
949
- useEffect5(() => {
795
+ useEffect6(() => {
950
796
  context.registerBoundingBox(id, {
951
797
  bounds: latestOptionsRef.current.bounds,
952
798
  onClick: latestOptionsRef.current.onClick ? handleClick : void 0
@@ -955,7 +801,7 @@ var useMouseEventsOverBoundingBox = (options) => {
955
801
  context.unregisterBoundingBox(id);
956
802
  };
957
803
  }, [context, handleClick, id]);
958
- useEffect5(() => {
804
+ useEffect6(() => {
959
805
  context.updateBoundingBox(id, {
960
806
  bounds: latestOptionsRef.current.bounds,
961
807
  onClick: latestOptionsRef.current.onClick ? handleClick : void 0
@@ -979,7 +825,7 @@ var useMouseEventsOverBoundingBox = (options) => {
979
825
  };
980
826
 
981
827
  // lib/components/SchematicComponentMouseTarget.tsx
982
- import { jsx as jsx4 } from "react/jsx-runtime";
828
+ import { jsx as jsx2 } from "react/jsx-runtime";
983
829
  var areMeasurementsEqual = (a, b) => {
984
830
  if (!a && !b) return true;
985
831
  if (!a || !b) return false;
@@ -994,9 +840,9 @@ var SchematicComponentMouseTarget = ({
994
840
  showOutline,
995
841
  circuitJsonKey
996
842
  }) => {
997
- const [measurement, setMeasurement] = useState2(null);
998
- const frameRef = useRef3(null);
999
- const measure = useCallback3(() => {
843
+ const [measurement, setMeasurement] = useState3(null);
844
+ const frameRef = useRef4(null);
845
+ const measure = useCallback4(() => {
1000
846
  frameRef.current = null;
1001
847
  const svgDiv = svgDivRef.current;
1002
848
  const container = containerRef.current;
@@ -1031,14 +877,14 @@ var SchematicComponentMouseTarget = ({
1031
877
  (prev) => areMeasurementsEqual(prev, nextMeasurement) ? prev : nextMeasurement
1032
878
  );
1033
879
  }, [componentId, containerRef, svgDivRef]);
1034
- const scheduleMeasure = useCallback3(() => {
880
+ const scheduleMeasure = useCallback4(() => {
1035
881
  if (frameRef.current !== null) return;
1036
882
  frameRef.current = window.requestAnimationFrame(measure);
1037
883
  }, [measure]);
1038
- useEffect6(() => {
884
+ useEffect7(() => {
1039
885
  scheduleMeasure();
1040
886
  }, [scheduleMeasure, circuitJsonKey]);
1041
- useEffect6(() => {
887
+ useEffect7(() => {
1042
888
  scheduleMeasure();
1043
889
  const svgDiv = svgDivRef.current;
1044
890
  const container = containerRef.current;
@@ -1070,7 +916,7 @@ var SchematicComponentMouseTarget = ({
1070
916
  }
1071
917
  };
1072
918
  }, [scheduleMeasure, svgDivRef, containerRef]);
1073
- const handleClick = useCallback3(
919
+ const handleClick = useCallback4(
1074
920
  (event) => {
1075
921
  if (onComponentClick) {
1076
922
  onComponentClick(componentId, event);
@@ -1083,7 +929,7 @@ var SchematicComponentMouseTarget = ({
1083
929
  bounds,
1084
930
  onClick: onComponentClick ? handleClick : void 0
1085
931
  });
1086
- useEffect6(() => {
932
+ useEffect7(() => {
1087
933
  if (onHoverChange) {
1088
934
  onHoverChange(componentId, hovering);
1089
935
  }
@@ -1092,7 +938,7 @@ var SchematicComponentMouseTarget = ({
1092
938
  return null;
1093
939
  }
1094
940
  const rect = measurement.rect;
1095
- return /* @__PURE__ */ jsx4(
941
+ return /* @__PURE__ */ jsx2(
1096
942
  "div",
1097
943
  {
1098
944
  style: {
@@ -1110,8 +956,8 @@ var SchematicComponentMouseTarget = ({
1110
956
  };
1111
957
 
1112
958
  // lib/components/SchematicPortMouseTarget.tsx
1113
- import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef4, useState as useState3 } from "react";
1114
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
959
+ import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef5, useState as useState4 } from "react";
960
+ import { Fragment as Fragment2, jsx as jsx3, jsxs } from "react/jsx-runtime";
1115
961
  var areMeasurementsEqual2 = (a, b) => {
1116
962
  if (!a && !b) return true;
1117
963
  if (!a || !b) return false;
@@ -1127,9 +973,9 @@ var SchematicPortMouseTarget = ({
1127
973
  showOutline,
1128
974
  circuitJsonKey
1129
975
  }) => {
1130
- const [measurement, setMeasurement] = useState3(null);
1131
- const frameRef = useRef4(null);
1132
- const measure = useCallback4(() => {
976
+ const [measurement, setMeasurement] = useState4(null);
977
+ const frameRef = useRef5(null);
978
+ const measure = useCallback5(() => {
1133
979
  frameRef.current = null;
1134
980
  const svgDiv = svgDivRef.current;
1135
981
  const container = containerRef.current;
@@ -1165,14 +1011,14 @@ var SchematicPortMouseTarget = ({
1165
1011
  (prev) => areMeasurementsEqual2(prev, nextMeasurement) ? prev : nextMeasurement
1166
1012
  );
1167
1013
  }, [portId, containerRef, svgDivRef]);
1168
- const scheduleMeasure = useCallback4(() => {
1014
+ const scheduleMeasure = useCallback5(() => {
1169
1015
  if (frameRef.current !== null) return;
1170
1016
  frameRef.current = window.requestAnimationFrame(measure);
1171
1017
  }, [measure]);
1172
- useEffect7(() => {
1018
+ useEffect8(() => {
1173
1019
  scheduleMeasure();
1174
1020
  }, [scheduleMeasure, circuitJsonKey]);
1175
- useEffect7(() => {
1021
+ useEffect8(() => {
1176
1022
  scheduleMeasure();
1177
1023
  const svgDiv = svgDivRef.current;
1178
1024
  const container = containerRef.current;
@@ -1204,7 +1050,7 @@ var SchematicPortMouseTarget = ({
1204
1050
  }
1205
1051
  };
1206
1052
  }, [scheduleMeasure, svgDivRef, containerRef]);
1207
- const handleClick = useCallback4(
1053
+ const handleClick = useCallback5(
1208
1054
  (event) => {
1209
1055
  if (onPortClick) {
1210
1056
  onPortClick(portId, event);
@@ -1217,7 +1063,7 @@ var SchematicPortMouseTarget = ({
1217
1063
  bounds,
1218
1064
  onClick: onPortClick ? handleClick : void 0
1219
1065
  });
1220
- useEffect7(() => {
1066
+ useEffect8(() => {
1221
1067
  if (onHoverChange) {
1222
1068
  onHoverChange(portId, hovering);
1223
1069
  }
@@ -1226,8 +1072,8 @@ var SchematicPortMouseTarget = ({
1226
1072
  return null;
1227
1073
  }
1228
1074
  const rect = measurement.rect;
1229
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1230
- /* @__PURE__ */ jsx5(
1075
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
1076
+ /* @__PURE__ */ jsx3(
1231
1077
  "div",
1232
1078
  {
1233
1079
  style: {
@@ -1245,7 +1091,7 @@ var SchematicPortMouseTarget = ({
1245
1091
  }
1246
1092
  }
1247
1093
  ),
1248
- hovering && portLabel && /* @__PURE__ */ jsx5(
1094
+ hovering && portLabel && /* @__PURE__ */ jsx3(
1249
1095
  "div",
1250
1096
  {
1251
1097
  style: {
@@ -1270,11 +1116,11 @@ var SchematicPortMouseTarget = ({
1270
1116
  };
1271
1117
 
1272
1118
  // lib/components/SchematicSheetSelector.tsx
1273
- import { useState as useState4 } from "react";
1274
- import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
1275
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1276
- var FONT_FAMILY2 = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1277
- var contentStyles2 = {
1119
+ import { useState as useState5 } from "react";
1120
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
1121
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1122
+ var FONT_FAMILY = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1123
+ var contentStyles = {
1278
1124
  backgroundColor: "#ffffff",
1279
1125
  color: "#111111",
1280
1126
  borderRadius: 8,
@@ -1286,11 +1132,11 @@ var contentStyles2 = {
1286
1132
  maxHeight: 320,
1287
1133
  overflowY: "auto",
1288
1134
  fontSize: 13,
1289
- fontFamily: FONT_FAMILY2,
1135
+ fontFamily: FONT_FAMILY,
1290
1136
  outline: "none",
1291
1137
  zIndex: zIndexMap.viewMenu
1292
1138
  };
1293
- var itemStyles2 = {
1139
+ var itemStyles = {
1294
1140
  display: "flex",
1295
1141
  alignItems: "center",
1296
1142
  gap: 8,
@@ -1301,9 +1147,9 @@ var itemStyles2 = {
1301
1147
  userSelect: "none",
1302
1148
  color: "#111111",
1303
1149
  fontSize: 13,
1304
- fontFamily: FONT_FAMILY2
1150
+ fontFamily: FONT_FAMILY
1305
1151
  };
1306
- var iconSlotStyles2 = {
1152
+ var iconSlotStyles = {
1307
1153
  width: 16,
1308
1154
  height: 16,
1309
1155
  flexShrink: 0,
@@ -1322,7 +1168,7 @@ var MENU_CSS = `
1322
1168
  .sv-sheet-chevron { transition: transform 0.2s ease; }
1323
1169
  [data-state="open"] > .sv-sheet-chevron { transform: rotate(180deg); }
1324
1170
  `;
1325
- var CheckIcon2 = () => /* @__PURE__ */ jsx6(
1171
+ var CheckIcon = () => /* @__PURE__ */ jsx4(
1326
1172
  "svg",
1327
1173
  {
1328
1174
  width: "14",
@@ -1334,10 +1180,10 @@ var CheckIcon2 = () => /* @__PURE__ */ jsx6(
1334
1180
  strokeLinecap: "round",
1335
1181
  strokeLinejoin: "round",
1336
1182
  "aria-hidden": "true",
1337
- children: /* @__PURE__ */ jsx6("path", { d: "M20 6 9 17l-5-5" })
1183
+ children: /* @__PURE__ */ jsx4("path", { d: "M20 6 9 17l-5-5" })
1338
1184
  }
1339
1185
  );
1340
- var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsx6(
1186
+ var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsx4(
1341
1187
  "svg",
1342
1188
  {
1343
1189
  className,
@@ -1351,7 +1197,7 @@ var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsx6(
1351
1197
  strokeLinejoin: "round",
1352
1198
  style: { opacity: 0.6, flexShrink: 0 },
1353
1199
  "aria-hidden": "true",
1354
- children: /* @__PURE__ */ jsx6("path", { d: "m6 9 6 6 6-6" })
1200
+ children: /* @__PURE__ */ jsx4("path", { d: "m6 9 6 6 6-6" })
1355
1201
  }
1356
1202
  );
1357
1203
  var SchematicSheetSelector = ({
@@ -1359,16 +1205,16 @@ var SchematicSheetSelector = ({
1359
1205
  selectedSheetId,
1360
1206
  onSelectSheet
1361
1207
  }) => {
1362
- const [open, setOpen] = useState4(false);
1208
+ const [open, setOpen] = useState5(false);
1363
1209
  if (sheets.length <= 1) return null;
1364
1210
  const selectedSheet = sheets.find(
1365
1211
  (s) => s.schematic_sheet_id === selectedSheetId
1366
1212
  );
1367
1213
  const selectedLabel = selectedSheet?.name ?? "Select sheet";
1368
- return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1369
- /* @__PURE__ */ jsx6("style", { children: MENU_CSS }),
1370
- /* @__PURE__ */ jsxs4(DropdownMenu2.Root, { open, onOpenChange: setOpen, modal: false, children: [
1371
- /* @__PURE__ */ jsx6(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
1214
+ return /* @__PURE__ */ jsxs2(Fragment3, { children: [
1215
+ /* @__PURE__ */ jsx4("style", { children: MENU_CSS }),
1216
+ /* @__PURE__ */ jsxs2(DropdownMenu.Root, { open, onOpenChange: setOpen, modal: false, children: [
1217
+ /* @__PURE__ */ jsx4(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
1372
1218
  "button",
1373
1219
  {
1374
1220
  type: "button",
@@ -1391,31 +1237,31 @@ var SchematicSheetSelector = ({
1391
1237
  cursor: "pointer",
1392
1238
  boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
1393
1239
  fontSize: "13px",
1394
- fontFamily: FONT_FAMILY2,
1240
+ fontFamily: FONT_FAMILY,
1395
1241
  zIndex: zIndexMap.viewMenuIcon
1396
1242
  },
1397
1243
  children: [
1398
- /* @__PURE__ */ jsx6("span", { style: { color: "#888888", flexShrink: 0 }, children: "Sheet:" }),
1399
- /* @__PURE__ */ jsx6("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: selectedLabel }),
1400
- /* @__PURE__ */ jsx6(ChevronDownIcon, { className: "sv-sheet-chevron" })
1244
+ /* @__PURE__ */ jsx4("span", { style: { color: "#888888", flexShrink: 0 }, children: "Sheet:" }),
1245
+ /* @__PURE__ */ jsx4("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: selectedLabel }),
1246
+ /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "sv-sheet-chevron" })
1401
1247
  ]
1402
1248
  }
1403
1249
  ) }),
1404
- /* @__PURE__ */ jsx6(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsx6(
1405
- DropdownMenu2.Content,
1250
+ /* @__PURE__ */ jsx4(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx4(
1251
+ DropdownMenu.Content,
1406
1252
  {
1407
- style: contentStyles2,
1253
+ style: contentStyles,
1408
1254
  side: "bottom",
1409
1255
  align: "start",
1410
1256
  sideOffset: 8,
1411
1257
  collisionPadding: 10,
1412
1258
  children: sheets.map((sheet) => {
1413
1259
  const selected = sheet.schematic_sheet_id === selectedSheetId;
1414
- return /* @__PURE__ */ jsxs4(
1415
- DropdownMenu2.Item,
1260
+ return /* @__PURE__ */ jsxs2(
1261
+ DropdownMenu.Item,
1416
1262
  {
1417
1263
  className: "sv-sheet-item",
1418
- style: itemStyles2,
1264
+ style: itemStyles,
1419
1265
  title: sheet.name,
1420
1266
  onSelect: (e) => e.preventDefault(),
1421
1267
  onPointerUp: () => {
@@ -1423,8 +1269,8 @@ var SchematicSheetSelector = ({
1423
1269
  setOpen(false);
1424
1270
  },
1425
1271
  children: [
1426
- /* @__PURE__ */ jsx6("span", { style: iconSlotStyles2, children: selected && /* @__PURE__ */ jsx6(CheckIcon2, {}) }),
1427
- /* @__PURE__ */ jsx6("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: sheet.name })
1272
+ /* @__PURE__ */ jsx4("span", { style: iconSlotStyles, children: selected && /* @__PURE__ */ jsx4(CheckIcon, {}) }),
1273
+ /* @__PURE__ */ jsx4("span", { style: { ...ellipsisStyles, minWidth: 0 }, children: sheet.name })
1428
1274
  ]
1429
1275
  },
1430
1276
  sheet.schematic_sheet_id
@@ -1436,8 +1282,275 @@ var SchematicSheetSelector = ({
1436
1282
  ] });
1437
1283
  };
1438
1284
 
1285
+ // lib/components/ViewMenu.tsx
1286
+ import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
1287
+ import { su as su3 } from "@tscircuit/soup-util";
1288
+ import { useMemo as useMemo3 } from "react";
1289
+
1290
+ // package.json
1291
+ var package_default = {
1292
+ name: "@tscircuit/schematic-viewer",
1293
+ version: "2.0.78",
1294
+ main: "dist/index.js",
1295
+ type: "module",
1296
+ scripts: {
1297
+ start: "cosmos",
1298
+ build: "tsup-node ./lib/index.ts --dts --format esm --sourcemap",
1299
+ "build:site": "cosmos-export",
1300
+ "vercel-build": "bun run build:site",
1301
+ format: "biome format --write .",
1302
+ "format:check": "biome format ."
1303
+ },
1304
+ files: [
1305
+ "dist"
1306
+ ],
1307
+ devDependencies: {
1308
+ "@biomejs/biome": "^1.9.4",
1309
+ "@types/bun": "latest",
1310
+ "@types/debug": "^4.1.12",
1311
+ "@types/jsdom": "^21.1.7",
1312
+ "@types/react": "^19.0.1",
1313
+ "@types/react-dom": "^19.0.2",
1314
+ "@vitejs/plugin-react": "^4.3.4",
1315
+ jsdom: "^26.0.0",
1316
+ react: "^19.1.0",
1317
+ "react-cosmos": "^6.2.1",
1318
+ "react-cosmos-plugin-vite": "^6.2.0",
1319
+ "react-dom": "^19.1.0",
1320
+ "react-reconciler": "^0.31.0",
1321
+ semver: "^7.7.2",
1322
+ tscircuit: "^0.0.2112",
1323
+ tsup: "^8.3.5",
1324
+ vite: "^6.0.3"
1325
+ },
1326
+ peerDependencies: {
1327
+ typescript: "^5.0.0",
1328
+ tscircuit: "*"
1329
+ },
1330
+ dependencies: {
1331
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
1332
+ "circuit-json": "^0.0.465",
1333
+ "circuit-to-svg": "^0.0.393",
1334
+ debug: "^4.4.0",
1335
+ "performance-now": "^2.1.0",
1336
+ "use-mouse-matrix-transform": "^1.2.2"
1337
+ }
1338
+ };
1339
+
1340
+ // lib/components/ViewMenu.tsx
1341
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1342
+ var FONT_FAMILY2 = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1343
+ var contentStyles2 = {
1344
+ backgroundColor: "#262626",
1345
+ color: "#fafafa",
1346
+ borderRadius: 6,
1347
+ boxShadow: "0px 12px 48px -12px rgba(0, 0, 0, 0.5), 0px 8px 24px -8px rgba(0, 0, 0, 0.3)",
1348
+ border: "1px solid #333333",
1349
+ padding: 4,
1350
+ minWidth: 208,
1351
+ fontSize: 14,
1352
+ fontWeight: 400,
1353
+ fontFamily: FONT_FAMILY2,
1354
+ outline: "none",
1355
+ zIndex: zIndexMap.contextMenu
1356
+ };
1357
+ var itemStyles2 = {
1358
+ display: "flex",
1359
+ alignItems: "center",
1360
+ gap: 8,
1361
+ padding: "6px 8px",
1362
+ borderRadius: 6,
1363
+ cursor: "default",
1364
+ outline: "none",
1365
+ userSelect: "none",
1366
+ color: "#fafafa",
1367
+ fontSize: 14,
1368
+ fontWeight: 400,
1369
+ fontFamily: FONT_FAMILY2
1370
+ };
1371
+ var iconSlotStyles2 = {
1372
+ width: 16,
1373
+ height: 16,
1374
+ flexShrink: 0,
1375
+ display: "inline-flex",
1376
+ alignItems: "center",
1377
+ justifyContent: "center",
1378
+ color: "#fafafa"
1379
+ };
1380
+ var separatorStyles = {
1381
+ height: 1,
1382
+ backgroundColor: "#ffffff1a",
1383
+ margin: "4px 0"
1384
+ };
1385
+ var HIGHLIGHT_CSS = `
1386
+ .sv-vm-item[data-highlighted]:not([data-disabled]),
1387
+ .sv-vm-item:hover:not([data-disabled]) { background-color: #404040; }
1388
+ .sv-vm-item[data-disabled] { opacity: 0.45; cursor: not-allowed; }
1389
+ `;
1390
+ var CheckIcon2 = () => /* @__PURE__ */ jsx5(
1391
+ "svg",
1392
+ {
1393
+ width: "14",
1394
+ height: "14",
1395
+ viewBox: "0 0 24 24",
1396
+ fill: "none",
1397
+ stroke: "currentColor",
1398
+ strokeWidth: "2.5",
1399
+ strokeLinecap: "round",
1400
+ strokeLinejoin: "round",
1401
+ "aria-hidden": "true",
1402
+ children: /* @__PURE__ */ jsx5("path", { d: "M20 6 9 17l-5-5" })
1403
+ }
1404
+ );
1405
+ var ViewMenu = ({
1406
+ circuitJson,
1407
+ circuitJsonKey,
1408
+ menuRef,
1409
+ menuPos,
1410
+ onOpenChange,
1411
+ showGroups,
1412
+ onToggleGroups,
1413
+ showGrid,
1414
+ onToggleGrid,
1415
+ showPorts,
1416
+ onTogglePorts
1417
+ }) => {
1418
+ const hasGroups = useMemo3(() => {
1419
+ if (!circuitJson || circuitJson.length === 0) return false;
1420
+ try {
1421
+ const sourceGroups = su3(circuitJson).source_group?.list() || [];
1422
+ if (sourceGroups.length > 0) return true;
1423
+ const schematicComponents = su3(circuitJson).schematic_component?.list() || [];
1424
+ if (schematicComponents.length > 1) {
1425
+ const componentTypes = /* @__PURE__ */ new Set();
1426
+ for (const comp of schematicComponents) {
1427
+ const sourceComp = su3(circuitJson).source_component.get(
1428
+ comp.source_component_id
1429
+ );
1430
+ if (sourceComp?.ftype) {
1431
+ componentTypes.add(sourceComp.ftype);
1432
+ }
1433
+ }
1434
+ return componentTypes.size > 1;
1435
+ }
1436
+ return false;
1437
+ } catch (error) {
1438
+ console.error("Error checking for groups:", error);
1439
+ return false;
1440
+ }
1441
+ }, [circuitJsonKey]);
1442
+ const hasPorts = useMemo3(() => {
1443
+ if (!circuitJson || circuitJson.length === 0) return false;
1444
+ try {
1445
+ return (su3(circuitJson).schematic_port?.list() || []).length > 0;
1446
+ } catch (error) {
1447
+ console.error("Error checking for schematic ports:", error);
1448
+ return false;
1449
+ }
1450
+ }, [circuitJsonKey]);
1451
+ return /* @__PURE__ */ jsx5(
1452
+ "div",
1453
+ {
1454
+ ref: menuRef,
1455
+ style: {
1456
+ position: "fixed",
1457
+ left: menuPos.x,
1458
+ top: menuPos.y,
1459
+ width: 0,
1460
+ height: 0
1461
+ },
1462
+ children: /* @__PURE__ */ jsxs3(DropdownMenu2.Root, { open: true, onOpenChange, modal: false, children: [
1463
+ /* @__PURE__ */ jsx5(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx5("div", { style: { position: "absolute", width: 1, height: 1 } }) }),
1464
+ /* @__PURE__ */ jsx5(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsxs3(
1465
+ DropdownMenu2.Content,
1466
+ {
1467
+ style: contentStyles2,
1468
+ align: "start",
1469
+ sideOffset: 0,
1470
+ collisionPadding: 10,
1471
+ avoidCollisions: true,
1472
+ children: [
1473
+ /* @__PURE__ */ jsx5("style", { children: HIGHLIGHT_CSS }),
1474
+ /* @__PURE__ */ jsxs3(
1475
+ DropdownMenu2.Item,
1476
+ {
1477
+ className: "sv-vm-item",
1478
+ style: itemStyles2,
1479
+ disabled: !hasPorts,
1480
+ title: hasPorts ? void 0 : "No ports found in this schematic",
1481
+ onSelect: (event) => event.preventDefault(),
1482
+ onPointerDown: (event) => {
1483
+ event.preventDefault();
1484
+ if (hasPorts) onTogglePorts(!showPorts);
1485
+ },
1486
+ children: [
1487
+ /* @__PURE__ */ jsx5("span", { style: iconSlotStyles2, children: showPorts && /* @__PURE__ */ jsx5(CheckIcon2, {}) }),
1488
+ /* @__PURE__ */ jsx5("span", { children: "Show Schematic Ports" })
1489
+ ]
1490
+ }
1491
+ ),
1492
+ /* @__PURE__ */ jsxs3(
1493
+ DropdownMenu2.Item,
1494
+ {
1495
+ className: "sv-vm-item",
1496
+ style: itemStyles2,
1497
+ disabled: !hasGroups,
1498
+ title: hasGroups ? void 0 : "No groups found in this schematic",
1499
+ onSelect: (event) => event.preventDefault(),
1500
+ onPointerDown: (event) => {
1501
+ event.preventDefault();
1502
+ if (hasGroups) onToggleGroups(!showGroups);
1503
+ },
1504
+ children: [
1505
+ /* @__PURE__ */ jsx5("span", { style: iconSlotStyles2, children: showGroups && /* @__PURE__ */ jsx5(CheckIcon2, {}) }),
1506
+ /* @__PURE__ */ jsx5("span", { children: "View Schematic Groups" })
1507
+ ]
1508
+ }
1509
+ ),
1510
+ /* @__PURE__ */ jsxs3(
1511
+ DropdownMenu2.Item,
1512
+ {
1513
+ className: "sv-vm-item",
1514
+ style: itemStyles2,
1515
+ onSelect: (event) => event.preventDefault(),
1516
+ onPointerDown: (event) => {
1517
+ event.preventDefault();
1518
+ onToggleGrid(!showGrid);
1519
+ },
1520
+ children: [
1521
+ /* @__PURE__ */ jsx5("span", { style: iconSlotStyles2, children: showGrid && /* @__PURE__ */ jsx5(CheckIcon2, {}) }),
1522
+ /* @__PURE__ */ jsx5("span", { children: "Show Grid" })
1523
+ ]
1524
+ }
1525
+ ),
1526
+ /* @__PURE__ */ jsx5(DropdownMenu2.Separator, { style: separatorStyles }),
1527
+ /* @__PURE__ */ jsxs3(
1528
+ "div",
1529
+ {
1530
+ style: {
1531
+ padding: "4px 8px 4px 32px",
1532
+ fontSize: 11,
1533
+ opacity: 0.35,
1534
+ color: "#a1a1aa",
1535
+ letterSpacing: "0.2px",
1536
+ fontFamily: FONT_FAMILY2
1537
+ },
1538
+ children: [
1539
+ "@tscircuit/schematic-viewer@",
1540
+ String(package_default?.version)
1541
+ ]
1542
+ }
1543
+ )
1544
+ ]
1545
+ }
1546
+ ) })
1547
+ ] })
1548
+ }
1549
+ );
1550
+ };
1551
+
1439
1552
  // lib/components/SchematicViewer.tsx
1440
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1553
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1441
1554
  var SchematicViewer = ({
1442
1555
  circuitJson,
1443
1556
  containerStyle,
@@ -1448,7 +1561,7 @@ var SchematicViewer = ({
1448
1561
  disableGroups = false,
1449
1562
  netHoverHighlightEnabled = true,
1450
1563
  onSchematicComponentClicked,
1451
- showSchematicPorts = false,
1564
+ showSchematicPorts,
1452
1565
  onSchematicPortClicked,
1453
1566
  onSchematicSheetChange,
1454
1567
  css,
@@ -1474,7 +1587,7 @@ var SchematicViewer = ({
1474
1587
  }, [circuitJsonKey]);
1475
1588
  const hasMultipleSheets = schematicSheets.length > 1;
1476
1589
  const defaultSheetId = schematicSheets[0]?.schematic_sheet_id;
1477
- const [selectedSheetId, setSelectedSheetId] = useState5(
1590
+ const [selectedSheetId, setSelectedSheetId] = useState6(
1478
1591
  () => {
1479
1592
  const stored = getStoredString(STORAGE_KEYS.SELECTED_SCHEMATIC_SHEET);
1480
1593
  if (stored && schematicSheets.some((s) => s.schematic_sheet_id === stored)) {
@@ -1483,14 +1596,14 @@ var SchematicViewer = ({
1483
1596
  return defaultSheetId;
1484
1597
  }
1485
1598
  );
1486
- useEffect8(() => {
1599
+ useEffect9(() => {
1487
1600
  const stillExists = selectedSheetId !== void 0 && schematicSheets.some((s) => s.schematic_sheet_id === selectedSheetId);
1488
1601
  if (!stillExists) {
1489
1602
  setSelectedSheetId(defaultSheetId);
1490
1603
  }
1491
1604
  }, [circuitJsonKey]);
1492
1605
  const activeSheetId = hasMultipleSheets ? selectedSheetId ?? defaultSheetId : void 0;
1493
- const handleSelectSheet = useCallback5(
1606
+ const handleSelectSheet = useCallback6(
1494
1607
  (sheetId) => {
1495
1608
  setSelectedSheetId(sheetId);
1496
1609
  setStoredString(STORAGE_KEYS.SELECTED_SCHEMATIC_SHEET, sheetId);
@@ -1498,19 +1611,26 @@ var SchematicViewer = ({
1498
1611
  },
1499
1612
  [onSchematicSheetChange]
1500
1613
  );
1501
- const [showGridInternal, setShowGridInternal] = useState5(false);
1614
+ const [showGridInternal, setShowGridInternal] = useState6(false);
1502
1615
  const showGrid = debugGrid || showGridInternal;
1503
- const [isInteractionEnabled, setIsInteractionEnabled] = useState5(
1616
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState6(
1504
1617
  !clickToInteractEnabled
1505
1618
  );
1506
- const [showViewMenu, setShowViewMenu] = useState5(false);
1507
- const [showSchematicGroups, setShowSchematicGroups] = useState5(() => {
1619
+ const [showSchematicGroups, setShowSchematicGroups] = useState6(() => {
1508
1620
  if (disableGroups) return false;
1509
- return getStoredBoolean("schematic_viewer_show_groups", false);
1621
+ return getStoredBoolean(STORAGE_KEYS.IS_SHOWING_SCHEMATIC_GROUPS, false);
1510
1622
  });
1511
- const [isHoveringClickableComponent, setIsHoveringClickableComponent] = useState5(false);
1512
- const hoveringComponentsRef = useRef5(/* @__PURE__ */ new Set());
1513
- const handleComponentHoverChange = useCallback5(
1623
+ const [showSchematicPortsInternal, setShowSchematicPortsInternal] = useState6(
1624
+ () => showSchematicPorts ?? getStoredBoolean(STORAGE_KEYS.IS_SHOWING_SCHEMATIC_PORTS, false)
1625
+ );
1626
+ useEffect9(() => {
1627
+ if (showSchematicPorts !== void 0) {
1628
+ setShowSchematicPortsInternal(showSchematicPorts);
1629
+ }
1630
+ }, [showSchematicPorts]);
1631
+ const [isHoveringClickableComponent, setIsHoveringClickableComponent] = useState6(false);
1632
+ const hoveringComponentsRef = useRef6(/* @__PURE__ */ new Set());
1633
+ const handleComponentHoverChange = useCallback6(
1514
1634
  (componentId, isHovering) => {
1515
1635
  if (isHovering) {
1516
1636
  hoveringComponentsRef.current.add(componentId);
@@ -1521,9 +1641,9 @@ var SchematicViewer = ({
1521
1641
  },
1522
1642
  []
1523
1643
  );
1524
- const [isHoveringClickablePort, setIsHoveringClickablePort] = useState5(false);
1525
- const hoveringPortsRef = useRef5(/* @__PURE__ */ new Set());
1526
- const handlePortHoverChange = useCallback5(
1644
+ const [isHoveringClickablePort, setIsHoveringClickablePort] = useState6(false);
1645
+ const hoveringPortsRef = useRef6(/* @__PURE__ */ new Set());
1646
+ const handlePortHoverChange = useCallback6(
1527
1647
  (portId, isHovering) => {
1528
1648
  if (isHovering) {
1529
1649
  hoveringPortsRef.current.add(portId);
@@ -1534,8 +1654,8 @@ var SchematicViewer = ({
1534
1654
  },
1535
1655
  []
1536
1656
  );
1537
- const svgDivRef = useRef5(null);
1538
- const touchStartRef = useRef5(null);
1657
+ const svgDivRef = useRef6(null);
1658
+ const touchStartRef = useRef6(null);
1539
1659
  const schematicComponentIds = useMemo4(() => {
1540
1660
  try {
1541
1661
  const components = su4(circuitJson).schematic_component?.list() ?? [];
@@ -1548,7 +1668,7 @@ var SchematicViewer = ({
1548
1668
  }
1549
1669
  }, [circuitJsonKey, circuitJson, activeSheetId]);
1550
1670
  const schematicPortsInfo = useMemo4(() => {
1551
- if (!showSchematicPorts) return [];
1671
+ if (!showSchematicPortsInternal) return [];
1552
1672
  try {
1553
1673
  const ports = (su4(circuitJson).schematic_port?.list() ?? []).filter(
1554
1674
  (port) => !activeSheetId || port.schematic_sheet_id === activeSheetId
@@ -1567,7 +1687,7 @@ var SchematicViewer = ({
1567
1687
  console.error("Failed to derive schematic port info", err);
1568
1688
  return [];
1569
1689
  }
1570
- }, [circuitJsonKey, circuitJson, showSchematicPorts, activeSheetId]);
1690
+ }, [circuitJsonKey, circuitJson, showSchematicPortsInternal, activeSheetId]);
1571
1691
  const handleTouchStart = (e) => {
1572
1692
  const touch = e.touches[0];
1573
1693
  touchStartRef.current = {
@@ -1587,21 +1707,36 @@ var SchematicViewer = ({
1587
1707
  }
1588
1708
  touchStartRef.current = null;
1589
1709
  };
1710
+ const shouldPanSchematic = useCallback6(
1711
+ (event) => {
1712
+ if (event.type !== "mousedown" || !("button" in event)) return true;
1713
+ return event.button !== 2 && !(event.button === 0 && event.ctrlKey);
1714
+ },
1715
+ []
1716
+ );
1590
1717
  const { ref: containerRef } = useMouseMatrixTransform({
1591
1718
  onSetTransform(transform) {
1592
1719
  if (!svgDivRef.current) return;
1593
1720
  svgDivRef.current.style.transform = transformToString(transform);
1594
1721
  },
1595
1722
  // @ts-ignore disabled is a valid prop but not typed
1596
- enabled: isInteractionEnabled
1723
+ enabled: isInteractionEnabled,
1724
+ shouldDrag: shouldPanSchematic
1597
1725
  });
1726
+ const {
1727
+ menuVisible,
1728
+ menuPos,
1729
+ menuRef,
1730
+ setMenuVisible,
1731
+ contextMenuEventHandlers
1732
+ } = useContextMenu({ containerRef });
1598
1733
  const { containerWidth, containerHeight } = useResizeHandling(containerRef);
1599
1734
  const svgString = useMemo4(() => {
1600
1735
  if (!containerWidth || !containerHeight) return "";
1601
1736
  return convertCircuitJsonToSchematicSvg(circuitJson, {
1602
1737
  width: containerWidth,
1603
1738
  height: containerHeight || 720,
1604
- drawPorts: showSchematicPorts,
1739
+ drawPorts: showSchematicPortsInternal,
1605
1740
  schematicSheetId: activeSheetId,
1606
1741
  grid: !showGrid ? void 0 : {
1607
1742
  cellSize: 1,
@@ -1616,7 +1751,7 @@ var SchematicViewer = ({
1616
1751
  containerWidth,
1617
1752
  containerHeight,
1618
1753
  showGrid,
1619
- showSchematicPorts,
1754
+ showSchematicPortsInternal,
1620
1755
  activeSheetId
1621
1756
  ]);
1622
1757
  const containerBackgroundColor = useMemo4(() => {
@@ -1638,7 +1773,7 @@ var SchematicViewer = ({
1638
1773
  enabled: netHoverHighlightEnabled
1639
1774
  });
1640
1775
  const svgDiv = useMemo4(
1641
- () => /* @__PURE__ */ jsx7(
1776
+ () => /* @__PURE__ */ jsx6(
1642
1777
  "div",
1643
1778
  {
1644
1779
  ref: svgDivRef,
@@ -1652,12 +1787,12 @@ var SchematicViewer = ({
1652
1787
  ),
1653
1788
  [svgString, isInteractionEnabled, clickToInteractEnabled]
1654
1789
  );
1655
- return /* @__PURE__ */ jsxs5(MouseTracker, { children: [
1656
- netHoverHighlightEnabled && /* @__PURE__ */ jsx7("style", { children: `.sch-net-faded { opacity: 0.35; }
1790
+ return /* @__PURE__ */ jsxs4(MouseTracker, { children: [
1791
+ netHoverHighlightEnabled && /* @__PURE__ */ jsx6("style", { children: `.sch-net-faded { opacity: 0.35; }
1657
1792
  svg :is(g.trace, g.trace-overlays, g[data-schematic-component-id], [data-schematic-net-label-id]) { transition: opacity 0.12s ease-in-out; }` }),
1658
- onSchematicComponentClicked && /* @__PURE__ */ jsx7("style", { children: `.schematic-component-clickable [data-schematic-component-id]:hover { cursor: pointer !important; }` }),
1659
- onSchematicPortClicked && /* @__PURE__ */ jsx7("style", { children: `[data-schematic-port-id]:hover { cursor: pointer !important; }` }),
1660
- /* @__PURE__ */ jsxs5(
1793
+ onSchematicComponentClicked && /* @__PURE__ */ jsx6("style", { children: ".schematic-component-clickable [data-schematic-component-id]:hover { cursor: pointer !important; }" }),
1794
+ onSchematicPortClicked && /* @__PURE__ */ jsx6("style", { children: "[data-schematic-port-id]:hover { cursor: pointer !important; }" }),
1795
+ /* @__PURE__ */ jsxs4(
1661
1796
  "div",
1662
1797
  {
1663
1798
  ref: containerRef,
@@ -1667,19 +1802,32 @@ var SchematicViewer = ({
1667
1802
  overflow: "hidden",
1668
1803
  cursor: clickToInteractEnabled && !isInteractionEnabled ? "pointer" : isHoveringClickableComponent && onSchematicComponentClicked ? "pointer" : isHoveringClickablePort && onSchematicPortClicked ? "pointer" : "grab",
1669
1804
  minHeight: "300px",
1805
+ userSelect: "none",
1806
+ WebkitUserSelect: "none",
1807
+ WebkitTouchCallout: "none",
1670
1808
  ...containerStyle
1671
1809
  },
1672
1810
  onMouseDownCapture: (e) => {
1811
+ contextMenuEventHandlers.onMouseDown(e);
1673
1812
  if (clickToInteractEnabled && !isInteractionEnabled) {
1674
1813
  e.preventDefault();
1675
1814
  e.stopPropagation();
1676
1815
  return;
1677
1816
  }
1678
1817
  },
1679
- onTouchStart: handleTouchStart,
1680
- onTouchEnd: handleTouchEnd,
1818
+ onContextMenu: contextMenuEventHandlers.onContextMenu,
1819
+ onTouchStart: (event) => {
1820
+ handleTouchStart(event);
1821
+ contextMenuEventHandlers.onTouchStart(event);
1822
+ },
1823
+ onTouchMove: contextMenuEventHandlers.onTouchMove,
1824
+ onTouchEnd: (event) => {
1825
+ handleTouchEnd(event);
1826
+ contextMenuEventHandlers.onTouchEnd();
1827
+ },
1828
+ onTouchCancel: contextMenuEventHandlers.onTouchCancel,
1681
1829
  children: [
1682
- !isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx7(
1830
+ !isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx6(
1683
1831
  "div",
1684
1832
  {
1685
1833
  onClick: (e) => {
@@ -1698,7 +1846,7 @@ var SchematicViewer = ({
1698
1846
  pointerEvents: "all",
1699
1847
  touchAction: "pan-x pan-y pinch-zoom"
1700
1848
  },
1701
- children: /* @__PURE__ */ jsx7(
1849
+ children: /* @__PURE__ */ jsx6(
1702
1850
  "div",
1703
1851
  {
1704
1852
  style: {
@@ -1715,25 +1863,34 @@ var SchematicViewer = ({
1715
1863
  )
1716
1864
  }
1717
1865
  ),
1718
- /* @__PURE__ */ jsx7(
1866
+ menuVisible && /* @__PURE__ */ jsx6(
1719
1867
  ViewMenu,
1720
1868
  {
1721
1869
  circuitJson,
1722
1870
  circuitJsonKey,
1723
- open: showViewMenu,
1724
- onOpenChange: setShowViewMenu,
1871
+ menuRef,
1872
+ menuPos,
1873
+ onOpenChange: setMenuVisible,
1874
+ showPorts: showSchematicPortsInternal,
1875
+ onTogglePorts: (value) => {
1876
+ setShowSchematicPortsInternal(value);
1877
+ setStoredBoolean(STORAGE_KEYS.IS_SHOWING_SCHEMATIC_PORTS, value);
1878
+ },
1725
1879
  showGroups: showSchematicGroups,
1726
1880
  onToggleGroups: (value) => {
1727
1881
  if (!disableGroups) {
1728
1882
  setShowSchematicGroups(value);
1729
- setStoredBoolean("schematic_viewer_show_groups", value);
1883
+ setStoredBoolean(
1884
+ STORAGE_KEYS.IS_SHOWING_SCHEMATIC_GROUPS,
1885
+ value
1886
+ );
1730
1887
  }
1731
1888
  },
1732
1889
  showGrid,
1733
1890
  onToggleGrid: setShowGridInternal
1734
1891
  }
1735
1892
  ),
1736
- /* @__PURE__ */ jsx7(
1893
+ /* @__PURE__ */ jsx6(
1737
1894
  SchematicSheetSelector,
1738
1895
  {
1739
1896
  sheets: schematicSheets,
@@ -1741,7 +1898,7 @@ var SchematicViewer = ({
1741
1898
  onSelectSheet: handleSelectSheet
1742
1899
  }
1743
1900
  ),
1744
- onSchematicComponentClicked && schematicComponentIds.map((componentId) => /* @__PURE__ */ jsx7(
1901
+ onSchematicComponentClicked && schematicComponentIds.map((componentId) => /* @__PURE__ */ jsx6(
1745
1902
  SchematicComponentMouseTarget,
1746
1903
  {
1747
1904
  componentId,
@@ -1760,7 +1917,7 @@ var SchematicViewer = ({
1760
1917
  componentId
1761
1918
  )),
1762
1919
  svgDiv,
1763
- showSchematicPorts && schematicPortsInfo.map(({ portId, label }) => /* @__PURE__ */ jsx7(
1920
+ showSchematicPortsInternal && schematicPortsInfo.map(({ portId, label }) => /* @__PURE__ */ jsx6(
1764
1921
  SchematicPortMouseTarget,
1765
1922
  {
1766
1923
  portId,
@@ -1790,7 +1947,7 @@ import {
1790
1947
  convertCircuitJsonToSchematicSimulationSvg,
1791
1948
  convertCircuitJsonToSimulationGraphSvg
1792
1949
  } from "circuit-to-svg";
1793
- import { useEffect as useEffect9, useMemo as useMemo5, useRef as useRef6, useState as useState7 } from "react";
1950
+ import { useEffect as useEffect10, useMemo as useMemo5, useRef as useRef7, useState as useState8 } from "react";
1794
1951
  import { toString as transformToString2 } from "transformation-matrix";
1795
1952
  import { useMouseMatrixTransform as useMouseMatrixTransform2 } from "use-mouse-matrix-transform";
1796
1953
 
@@ -1808,8 +1965,8 @@ var getAnalogSimulationBackgroundColor = (simulationSvg, colorOverrides) => getR
1808
1965
 
1809
1966
  // lib/components/AnalogSimulationSelector.tsx
1810
1967
  import * as DropdownMenu3 from "@radix-ui/react-dropdown-menu";
1811
- import { useState as useState6 } from "react";
1812
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1968
+ import { useState as useState7 } from "react";
1969
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1813
1970
  var FONT_FAMILY3 = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1814
1971
  var contentStyles3 = {
1815
1972
  backgroundColor: "#ffffff",
@@ -1859,7 +2016,7 @@ var MENU_CSS2 = `
1859
2016
  .sv-simulation-chevron { transition: transform 0.2s ease; }
1860
2017
  [data-state="open"] > .sv-simulation-chevron { transform: rotate(180deg); }
1861
2018
  `;
1862
- var CheckIcon3 = () => /* @__PURE__ */ jsx8(
2019
+ var CheckIcon3 = () => /* @__PURE__ */ jsx7(
1863
2020
  "svg",
1864
2021
  {
1865
2022
  width: "14",
@@ -1871,10 +2028,10 @@ var CheckIcon3 = () => /* @__PURE__ */ jsx8(
1871
2028
  strokeLinecap: "round",
1872
2029
  strokeLinejoin: "round",
1873
2030
  "aria-hidden": "true",
1874
- children: /* @__PURE__ */ jsx8("path", { d: "M20 6 9 17l-5-5" })
2031
+ children: /* @__PURE__ */ jsx7("path", { d: "M20 6 9 17l-5-5" })
1875
2032
  }
1876
2033
  );
1877
- var ChevronDownIcon2 = ({ className }) => /* @__PURE__ */ jsx8(
2034
+ var ChevronDownIcon2 = ({ className }) => /* @__PURE__ */ jsx7(
1878
2035
  "svg",
1879
2036
  {
1880
2037
  className,
@@ -1888,7 +2045,7 @@ var ChevronDownIcon2 = ({ className }) => /* @__PURE__ */ jsx8(
1888
2045
  strokeLinejoin: "round",
1889
2046
  style: { opacity: 0.6, flexShrink: 0 },
1890
2047
  "aria-hidden": "true",
1891
- children: /* @__PURE__ */ jsx8("path", { d: "m6 9 6 6 6-6" })
2048
+ children: /* @__PURE__ */ jsx7("path", { d: "m6 9 6 6 6-6" })
1892
2049
  }
1893
2050
  );
1894
2051
  var getSimulationLabels = (simulations) => {
@@ -1907,17 +2064,17 @@ var AnalogSimulationSelector = ({
1907
2064
  selectedSimulationExperimentId,
1908
2065
  onSelectSimulation
1909
2066
  }) => {
1910
- const [open, setOpen] = useState6(false);
2067
+ const [open, setOpen] = useState7(false);
1911
2068
  if (simulations.length <= 1) return null;
1912
2069
  const simulationLabels = getSimulationLabels(simulations);
1913
2070
  const selectedSimulation = simulationLabels.find(
1914
2071
  ({ simulation }) => simulation.simulation_experiment_id === selectedSimulationExperimentId
1915
2072
  );
1916
2073
  const selectedLabel = selectedSimulation?.label ?? "Select simulation";
1917
- return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1918
- /* @__PURE__ */ jsx8("style", { children: MENU_CSS2 }),
1919
- /* @__PURE__ */ jsxs6(DropdownMenu3.Root, { open, onOpenChange: setOpen, modal: false, children: [
1920
- /* @__PURE__ */ jsx8(DropdownMenu3.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
2074
+ return /* @__PURE__ */ jsxs5(Fragment4, { children: [
2075
+ /* @__PURE__ */ jsx7("style", { children: MENU_CSS2 }),
2076
+ /* @__PURE__ */ jsxs5(DropdownMenu3.Root, { open, onOpenChange: setOpen, modal: false, children: [
2077
+ /* @__PURE__ */ jsx7(DropdownMenu3.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
1921
2078
  "button",
1922
2079
  {
1923
2080
  type: "button",
@@ -1944,13 +2101,13 @@ var AnalogSimulationSelector = ({
1944
2101
  zIndex: zIndexMap.viewMenuIcon
1945
2102
  },
1946
2103
  children: [
1947
- /* @__PURE__ */ jsx8("span", { style: { color: "#888888", flexShrink: 0 }, children: "Simulation:" }),
1948
- /* @__PURE__ */ jsx8("span", { style: { ...ellipsisStyles2, minWidth: 0 }, children: selectedLabel }),
1949
- /* @__PURE__ */ jsx8(ChevronDownIcon2, { className: "sv-simulation-chevron" })
2104
+ /* @__PURE__ */ jsx7("span", { style: { color: "#888888", flexShrink: 0 }, children: "Simulation:" }),
2105
+ /* @__PURE__ */ jsx7("span", { style: { ...ellipsisStyles2, minWidth: 0 }, children: selectedLabel }),
2106
+ /* @__PURE__ */ jsx7(ChevronDownIcon2, { className: "sv-simulation-chevron" })
1950
2107
  ]
1951
2108
  }
1952
2109
  ) }),
1953
- /* @__PURE__ */ jsx8(DropdownMenu3.Portal, { children: /* @__PURE__ */ jsx8(
2110
+ /* @__PURE__ */ jsx7(DropdownMenu3.Portal, { children: /* @__PURE__ */ jsx7(
1954
2111
  DropdownMenu3.Content,
1955
2112
  {
1956
2113
  style: contentStyles3,
@@ -1960,7 +2117,7 @@ var AnalogSimulationSelector = ({
1960
2117
  collisionPadding: 10,
1961
2118
  children: simulationLabels.map(({ simulation, label }) => {
1962
2119
  const selected = simulation.simulation_experiment_id === selectedSimulationExperimentId;
1963
- return /* @__PURE__ */ jsxs6(
2120
+ return /* @__PURE__ */ jsxs5(
1964
2121
  DropdownMenu3.Item,
1965
2122
  {
1966
2123
  className: "sv-simulation-item",
@@ -1972,8 +2129,8 @@ var AnalogSimulationSelector = ({
1972
2129
  setOpen(false);
1973
2130
  },
1974
2131
  children: [
1975
- /* @__PURE__ */ jsx8("span", { style: iconSlotStyles3, children: selected && /* @__PURE__ */ jsx8(CheckIcon3, {}) }),
1976
- /* @__PURE__ */ jsx8("span", { style: { ...ellipsisStyles2, minWidth: 0 }, children: label })
2132
+ /* @__PURE__ */ jsx7("span", { style: iconSlotStyles3, children: selected && /* @__PURE__ */ jsx7(CheckIcon3, {}) }),
2133
+ /* @__PURE__ */ jsx7("span", { style: { ...ellipsisStyles2, minWidth: 0 }, children: label })
1977
2134
  ]
1978
2135
  },
1979
2136
  simulation.simulation_experiment_id
@@ -1986,7 +2143,7 @@ var AnalogSimulationSelector = ({
1986
2143
  };
1987
2144
 
1988
2145
  // lib/components/AnalogSimulationViewer.tsx
1989
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2146
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1990
2147
  var DEFAULT_RENDER_WIDTH = 1200;
1991
2148
  var DEFAULT_COMBINED_RENDER_ASPECT_RATIO = 1;
1992
2149
  var DEFAULT_GRAPH_ONLY_RENDER_ASPECT_RATIO = 2;
@@ -2001,16 +2158,16 @@ var AnalogSimulationViewer = ({
2001
2158
  onSimulationChange,
2002
2159
  acSweepView = "magnitude"
2003
2160
  }) => {
2004
- const [circuitJson, setCircuitJson] = useState7(null);
2005
- const [isLoading, setIsLoading] = useState7(true);
2006
- const [error, setError] = useState7(null);
2007
- const [svgObjectUrl, setSvgObjectUrl] = useState7(null);
2008
- const containerRef = useRef6(null);
2009
- const imgRef = useRef6(null);
2161
+ const [circuitJson, setCircuitJson] = useState8(null);
2162
+ const [isLoading, setIsLoading] = useState8(true);
2163
+ const [error, setError] = useState8(null);
2164
+ const [svgObjectUrl, setSvgObjectUrl] = useState8(null);
2165
+ const containerRef = useRef7(null);
2166
+ const imgRef = useRef7(null);
2010
2167
  const { containerWidth } = useResizeHandling(
2011
2168
  containerRef
2012
2169
  );
2013
- const [isDragging, setIsDragging] = useState7(false);
2170
+ const [isDragging, setIsDragging] = useState8(false);
2014
2171
  const {
2015
2172
  ref: transformRef,
2016
2173
  cancelDrag: _cancelDrag,
@@ -2026,7 +2183,7 @@ var AnalogSimulationViewer = ({
2026
2183
  const renderAspectRatio = width && height ? width / height : defaultRenderAspectRatio;
2027
2184
  const effectiveWidth = width || (height ? height * renderAspectRatio : containerWidth) || DEFAULT_RENDER_WIDTH;
2028
2185
  const effectiveHeight = height || effectiveWidth / renderAspectRatio;
2029
- useEffect9(() => {
2186
+ useEffect10(() => {
2030
2187
  setIsLoading(true);
2031
2188
  setError(null);
2032
2189
  setCircuitJson(inputCircuitJson);
@@ -2038,11 +2195,11 @@ var AnalogSimulationViewer = ({
2038
2195
  (element) => element.type === "simulation_experiment"
2039
2196
  );
2040
2197
  }, [circuitJson]);
2041
- const [selectedSimulationExperimentId, setSelectedSimulationExperimentId] = useState7(null);
2198
+ const [selectedSimulationExperimentId, setSelectedSimulationExperimentId] = useState8(null);
2042
2199
  const simulationExperimentId = (selectedSimulationExperimentId && simulationExperiments.some(
2043
2200
  (simulation) => simulation.simulation_experiment_id === selectedSimulationExperimentId
2044
2201
  ) ? selectedSimulationExperimentId : simulationExperiments[0]?.simulation_experiment_id) ?? null;
2045
- useEffect9(() => {
2202
+ useEffect10(() => {
2046
2203
  if (simulationExperimentId !== selectedSimulationExperimentId) {
2047
2204
  setSelectedSimulationExperimentId(simulationExperimentId);
2048
2205
  }
@@ -2079,7 +2236,7 @@ var AnalogSimulationViewer = ({
2079
2236
  simulationExperimentId,
2080
2237
  acSweepView
2081
2238
  ]);
2082
- useEffect9(() => {
2239
+ useEffect10(() => {
2083
2240
  if (!simulationSvg) {
2084
2241
  setSvgObjectUrl(null);
2085
2242
  return;
@@ -2105,7 +2262,7 @@ var AnalogSimulationViewer = ({
2105
2262
  const handleTouchStart = (_e) => {
2106
2263
  setIsDragging(true);
2107
2264
  };
2108
- useEffect9(() => {
2265
+ useEffect10(() => {
2109
2266
  const handleMouseUp = () => {
2110
2267
  setIsDragging(false);
2111
2268
  };
@@ -2120,7 +2277,7 @@ var AnalogSimulationViewer = ({
2120
2277
  };
2121
2278
  }, []);
2122
2279
  if (isLoading) {
2123
- return /* @__PURE__ */ jsx9(
2280
+ return /* @__PURE__ */ jsx8(
2124
2281
  "div",
2125
2282
  {
2126
2283
  style: {
@@ -2140,7 +2297,7 @@ var AnalogSimulationViewer = ({
2140
2297
  );
2141
2298
  }
2142
2299
  if (error) {
2143
- return /* @__PURE__ */ jsx9(
2300
+ return /* @__PURE__ */ jsx8(
2144
2301
  "div",
2145
2302
  {
2146
2303
  style: {
@@ -2155,15 +2312,15 @@ var AnalogSimulationViewer = ({
2155
2312
  ...containerStyle
2156
2313
  },
2157
2314
  className,
2158
- children: /* @__PURE__ */ jsxs7("div", { style: { textAlign: "center", padding: "20px" }, children: [
2159
- /* @__PURE__ */ jsx9("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "Circuit Conversion Error" }),
2160
- /* @__PURE__ */ jsx9("div", { style: { fontSize: "14px" }, children: error })
2315
+ children: /* @__PURE__ */ jsxs6("div", { style: { textAlign: "center", padding: "20px" }, children: [
2316
+ /* @__PURE__ */ jsx8("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "Circuit Conversion Error" }),
2317
+ /* @__PURE__ */ jsx8("div", { style: { fontSize: "14px" }, children: error })
2161
2318
  ] })
2162
2319
  }
2163
2320
  );
2164
2321
  }
2165
2322
  if (!simulationSvg) {
2166
- return /* @__PURE__ */ jsxs7(
2323
+ return /* @__PURE__ */ jsxs6(
2167
2324
  "div",
2168
2325
  {
2169
2326
  style: {
@@ -2179,11 +2336,11 @@ var AnalogSimulationViewer = ({
2179
2336
  },
2180
2337
  className,
2181
2338
  children: [
2182
- /* @__PURE__ */ jsx9("div", { style: { fontSize: "16px", color: "#475569", fontWeight: 500 }, children: "No Simulation Found" }),
2183
- /* @__PURE__ */ jsxs7("div", { style: { fontSize: "14px", color: "#64748b" }, children: [
2339
+ /* @__PURE__ */ jsx8("div", { style: { fontSize: "16px", color: "#475569", fontWeight: 500 }, children: "No Simulation Found" }),
2340
+ /* @__PURE__ */ jsxs6("div", { style: { fontSize: "14px", color: "#64748b" }, children: [
2184
2341
  "Use",
2185
2342
  " ",
2186
- /* @__PURE__ */ jsx9(
2343
+ /* @__PURE__ */ jsx8(
2187
2344
  "code",
2188
2345
  {
2189
2346
  style: {
@@ -2203,7 +2360,7 @@ var AnalogSimulationViewer = ({
2203
2360
  }
2204
2361
  );
2205
2362
  }
2206
- return /* @__PURE__ */ jsxs7(
2363
+ return /* @__PURE__ */ jsxs6(
2207
2364
  "div",
2208
2365
  {
2209
2366
  ref: (node) => {
@@ -2222,7 +2379,7 @@ var AnalogSimulationViewer = ({
2222
2379
  onMouseDown: handleMouseDown,
2223
2380
  onTouchStart: handleTouchStart,
2224
2381
  children: [
2225
- /* @__PURE__ */ jsx9(
2382
+ /* @__PURE__ */ jsx8(
2226
2383
  AnalogSimulationSelector,
2227
2384
  {
2228
2385
  simulations: simulationExperiments,
@@ -2230,7 +2387,7 @@ var AnalogSimulationViewer = ({
2230
2387
  onSelectSimulation: handleSelectSimulation
2231
2388
  }
2232
2389
  ),
2233
- svgObjectUrl ? /* @__PURE__ */ jsx9(
2390
+ svgObjectUrl ? /* @__PURE__ */ jsx8(
2234
2391
  "img",
2235
2392
  {
2236
2393
  ref: imgRef,
@@ -2244,7 +2401,7 @@ var AnalogSimulationViewer = ({
2244
2401
  objectFit: "contain"
2245
2402
  }
2246
2403
  }
2247
- ) : /* @__PURE__ */ jsx9(
2404
+ ) : /* @__PURE__ */ jsx8(
2248
2405
  "div",
2249
2406
  {
2250
2407
  style: {