@tscircuit/schematic-viewer 2.0.33 → 2.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -15,7 +15,8 @@ interface Props {
15
15
  clickToInteractEnabled?: boolean;
16
16
  colorOverrides?: ColorOverrides;
17
17
  spiceSimulationEnabled?: boolean;
18
+ disableGroups?: boolean;
18
19
  }
19
- declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents: unappliedEditEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, debug, clickToInteractEnabled, colorOverrides, spiceSimulationEnabled, }: Props) => react_jsx_runtime.JSX.Element;
20
+ declare const SchematicViewer: ({ circuitJson, containerStyle, editEvents: unappliedEditEvents, onEditEvent, defaultEditMode, debugGrid, editingEnabled, debug, clickToInteractEnabled, colorOverrides, spiceSimulationEnabled, disableGroups, }: Props) => react_jsx_runtime.JSX.Element;
20
21
 
21
22
  export { SchematicViewer };
package/dist/index.js CHANGED
@@ -523,27 +523,23 @@ var useComponentDragging = ({
523
523
  }
524
524
  });
525
525
  }, [editEvents]);
526
- const handleMouseDown = useCallback(
527
- (e) => {
528
- if (!enabled) return;
529
- const target = e.target;
526
+ const startDrag = useCallback(
527
+ (clientX, clientY, target) => {
528
+ if (!enabled) return false;
530
529
  const componentGroup = target.closest(
531
530
  '[data-circuit-json-type="schematic_component"]'
532
531
  );
533
- if (!componentGroup) return;
532
+ if (!componentGroup) return false;
534
533
  const schematic_component_id = componentGroup.getAttribute(
535
534
  "data-schematic-component-id"
536
535
  );
537
- if (!schematic_component_id) return;
536
+ if (!schematic_component_id) return false;
538
537
  if (cancelDrag) cancelDrag();
539
538
  const schematic_component = su4(circuitJson).schematic_component.get(
540
539
  schematic_component_id
541
540
  );
542
- if (!schematic_component) return;
543
- dragStartPosRef.current = {
544
- x: e.clientX,
545
- y: e.clientY
546
- };
541
+ if (!schematic_component) return false;
542
+ dragStartPosRef.current = { x: clientX, y: clientY };
547
543
  let current_position;
548
544
  const trackedPosition = componentPositionsRef.current.get(
549
545
  schematic_component_id
@@ -575,15 +571,32 @@ var useComponentDragging = ({
575
571
  };
576
572
  activeEditEventRef.current = newEditEvent;
577
573
  setActiveEditEvent(newEditEvent);
574
+ return true;
578
575
  },
579
576
  [cancelDrag, enabled, circuitJson, editEvents]
580
577
  );
581
- const handleMouseMove = useCallback(
578
+ const handleMouseDown = useCallback(
579
+ (e) => {
580
+ startDrag(e.clientX, e.clientY, e.target);
581
+ },
582
+ [startDrag]
583
+ );
584
+ const handleTouchStart = useCallback(
582
585
  (e) => {
586
+ if (e.touches.length !== 1) return;
587
+ const touch = e.touches[0];
588
+ if (startDrag(touch.clientX, touch.clientY, e.target)) {
589
+ e.preventDefault();
590
+ }
591
+ },
592
+ [startDrag]
593
+ );
594
+ const updateDragPosition = useCallback(
595
+ (clientX, clientY) => {
583
596
  if (!activeEditEventRef.current || !dragStartPosRef.current) return;
584
597
  const screenDelta = {
585
- x: e.clientX - dragStartPosRef.current.x,
586
- y: e.clientY - dragStartPosRef.current.y
598
+ x: clientX - dragStartPosRef.current.x,
599
+ y: clientY - dragStartPosRef.current.y
587
600
  };
588
601
  const mmDelta = {
589
602
  x: screenDelta.x / realToScreenProjection.a,
@@ -606,7 +619,20 @@ var useComponentDragging = ({
606
619
  },
607
620
  [realToScreenProjection, snapToGrid]
608
621
  );
609
- const handleMouseUp = useCallback(() => {
622
+ const handleMouseMove = useCallback(
623
+ (e) => updateDragPosition(e.clientX, e.clientY),
624
+ [updateDragPosition]
625
+ );
626
+ const handleTouchMove = useCallback(
627
+ (e) => {
628
+ if (e.touches.length !== 1 || !activeEditEventRef.current) return;
629
+ e.preventDefault();
630
+ const touch = e.touches[0];
631
+ updateDragPosition(touch.clientX, touch.clientY);
632
+ },
633
+ [updateDragPosition]
634
+ );
635
+ const endDrag = useCallback(() => {
610
636
  if (!activeEditEventRef.current) return;
611
637
  const finalEvent = {
612
638
  ...activeEditEventRef.current,
@@ -615,7 +641,7 @@ var useComponentDragging = ({
615
641
  componentPositionsRef.current.set(finalEvent.schematic_component_id, {
616
642
  ...finalEvent.new_center
617
643
  });
618
- debug2("handleMouseUp calling onEditEvent with new edit event", {
644
+ debug2("endDrag calling onEditEvent with new edit event", {
619
645
  newEditEvent: finalEvent
620
646
  });
621
647
  if (onEditEvent) onEditEvent(finalEvent);
@@ -623,16 +649,23 @@ var useComponentDragging = ({
623
649
  dragStartPosRef.current = null;
624
650
  setActiveEditEvent(null);
625
651
  }, [onEditEvent]);
652
+ const handleMouseUp = useCallback(() => endDrag(), [endDrag]);
653
+ const handleTouchEnd = useCallback(() => endDrag(), [endDrag]);
626
654
  useEffect5(() => {
627
655
  window.addEventListener("mousemove", handleMouseMove);
628
656
  window.addEventListener("mouseup", handleMouseUp);
657
+ window.addEventListener("touchmove", handleTouchMove, { passive: false });
658
+ window.addEventListener("touchend", handleTouchEnd);
629
659
  return () => {
630
660
  window.removeEventListener("mousemove", handleMouseMove);
631
661
  window.removeEventListener("mouseup", handleMouseUp);
662
+ window.removeEventListener("touchmove", handleTouchMove);
663
+ window.removeEventListener("touchend", handleTouchEnd);
632
664
  };
633
- }, [handleMouseMove, handleMouseUp]);
665
+ }, [handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
634
666
  return {
635
667
  handleMouseDown,
668
+ handleTouchStart,
636
669
  isDragging: !!activeEditEventRef.current,
637
670
  activeEditEvent
638
671
  };
@@ -655,10 +688,15 @@ var EditIcon = ({
655
688
  onClick,
656
689
  active
657
690
  }) => {
691
+ const handleInteraction = (e) => {
692
+ e.preventDefault();
693
+ onClick();
694
+ };
658
695
  return /* @__PURE__ */ jsx(
659
696
  "div",
660
697
  {
661
- onClick,
698
+ onClick: handleInteraction,
699
+ onTouchEnd: handleInteraction,
662
700
  style: {
663
701
  position: "absolute",
664
702
  top: "16px",
@@ -699,10 +737,15 @@ var GridIcon = ({
699
737
  onClick,
700
738
  active
701
739
  }) => {
740
+ const handleInteraction = (e) => {
741
+ e.preventDefault();
742
+ onClick();
743
+ };
702
744
  return /* @__PURE__ */ jsx2(
703
745
  "div",
704
746
  {
705
- onClick,
747
+ onClick: handleInteraction,
748
+ onTouchEnd: handleInteraction,
706
749
  style: {
707
750
  position: "absolute",
708
751
  top: "56px",
@@ -1618,6 +1661,25 @@ var getSpiceFromCircuitJson = (circuitJson, options) => {
1618
1661
  return finalLines.join("\n");
1619
1662
  };
1620
1663
 
1664
+ // lib/hooks/useLocalStorage.ts
1665
+ import { useCallback as useCallback2 } from "react";
1666
+ var getStoredBoolean = (key, defaultValue) => {
1667
+ if (typeof window === "undefined") return defaultValue;
1668
+ try {
1669
+ const stored = localStorage.getItem(key);
1670
+ return stored !== null ? JSON.parse(stored) : defaultValue;
1671
+ } catch {
1672
+ return defaultValue;
1673
+ }
1674
+ };
1675
+ var setStoredBoolean = (key, value) => {
1676
+ if (typeof window === "undefined") return;
1677
+ try {
1678
+ localStorage.setItem(key, JSON.stringify(value));
1679
+ } catch {
1680
+ }
1681
+ };
1682
+
1621
1683
  // lib/components/SchematicViewer.tsx
1622
1684
  import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1623
1685
  var SchematicViewer = ({
@@ -1631,7 +1693,8 @@ var SchematicViewer = ({
1631
1693
  debug: debug3 = false,
1632
1694
  clickToInteractEnabled = false,
1633
1695
  colorOverrides,
1634
- spiceSimulationEnabled = false
1696
+ spiceSimulationEnabled = false,
1697
+ disableGroups = false
1635
1698
  }) => {
1636
1699
  if (debug3) {
1637
1700
  enableDebug();
@@ -1678,7 +1741,10 @@ var SchematicViewer = ({
1678
1741
  !clickToInteractEnabled
1679
1742
  );
1680
1743
  const [showViewMenu, setShowViewMenu] = useState5(false);
1681
- const [showSchematicGroups, setShowSchematicGroups] = useState5(false);
1744
+ const [showSchematicGroups, setShowSchematicGroups] = useState5(() => {
1745
+ if (disableGroups) return false;
1746
+ return getStoredBoolean("schematic_viewer_show_groups", false);
1747
+ });
1682
1748
  const svgDivRef = useRef4(null);
1683
1749
  const touchStartRef = useRef4(null);
1684
1750
  const handleTouchStart = (e) => {
@@ -1762,18 +1828,21 @@ var SchematicViewer = ({
1762
1828
  const editEventsWithUnappliedEditEvents = useMemo3(() => {
1763
1829
  return [...unappliedEditEvents, ...internalEditEvents];
1764
1830
  }, [unappliedEditEvents, internalEditEvents]);
1765
- const { handleMouseDown, isDragging, activeEditEvent } = useComponentDragging(
1766
- {
1767
- onEditEvent: handleEditEvent,
1768
- cancelDrag,
1769
- realToSvgProjection,
1770
- svgToScreenProjection,
1771
- circuitJson,
1772
- editEvents: editEventsWithUnappliedEditEvents,
1773
- enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
1774
- snapToGrid
1775
- }
1776
- );
1831
+ const {
1832
+ handleMouseDown,
1833
+ handleTouchStart: handleComponentTouchStart,
1834
+ isDragging,
1835
+ activeEditEvent
1836
+ } = useComponentDragging({
1837
+ onEditEvent: handleEditEvent,
1838
+ cancelDrag,
1839
+ realToSvgProjection,
1840
+ svgToScreenProjection,
1841
+ circuitJson,
1842
+ editEvents: editEventsWithUnappliedEditEvents,
1843
+ enabled: editModeEnabled && isInteractionEnabled && !showSpiceOverlay,
1844
+ snapToGrid
1845
+ });
1777
1846
  useChangeSchematicComponentLocationsInSvg({
1778
1847
  svgDivRef,
1779
1848
  editEvents: editEventsWithUnappliedEditEvents,
@@ -1791,7 +1860,7 @@ var SchematicViewer = ({
1791
1860
  svgDivRef,
1792
1861
  circuitJson,
1793
1862
  circuitJsonKey,
1794
- showGroups: showSchematicGroups
1863
+ showGroups: showSchematicGroups && !disableGroups
1795
1864
  });
1796
1865
  const svgDiv = useMemo3(
1797
1866
  () => /* @__PURE__ */ jsx9(
@@ -1802,10 +1871,22 @@ var SchematicViewer = ({
1802
1871
  pointerEvents: clickToInteractEnabled ? isInteractionEnabled ? "auto" : "none" : "auto",
1803
1872
  transformOrigin: "0 0"
1804
1873
  },
1874
+ onTouchStart: (e) => {
1875
+ if (editModeEnabled && isInteractionEnabled && !showSpiceOverlay) {
1876
+ handleComponentTouchStart(e);
1877
+ }
1878
+ },
1805
1879
  dangerouslySetInnerHTML: { __html: svgString }
1806
1880
  }
1807
1881
  ),
1808
- [svgString, isInteractionEnabled, clickToInteractEnabled]
1882
+ [
1883
+ svgString,
1884
+ isInteractionEnabled,
1885
+ clickToInteractEnabled,
1886
+ editModeEnabled,
1887
+ showSpiceOverlay,
1888
+ handleComponentTouchStart
1889
+ ]
1809
1890
  );
1810
1891
  return /* @__PURE__ */ jsxs6(
1811
1892
  "div",
@@ -1913,7 +1994,12 @@ var SchematicViewer = ({
1913
1994
  isVisible: showViewMenu,
1914
1995
  onClose: () => setShowViewMenu(false),
1915
1996
  showGroups: showSchematicGroups,
1916
- onToggleGroups: setShowSchematicGroups
1997
+ onToggleGroups: (value) => {
1998
+ if (!disableGroups) {
1999
+ setShowSchematicGroups(value);
2000
+ setStoredBoolean("schematic_viewer_show_groups", value);
2001
+ }
2002
+ }
1917
2003
  }
1918
2004
  ),
1919
2005
  spiceSimulationEnabled && /* @__PURE__ */ jsx9(SpiceSimulationIcon, { onClick: () => setShowSpiceOverlay(true) }),