@tscircuit/schematic-viewer 2.0.44 → 2.0.46

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
@@ -470,7 +470,7 @@ var enableDebug = () => {
470
470
  var debug_default = debug;
471
471
 
472
472
  // lib/components/SchematicViewer.tsx
473
- import { useEffect as useEffect11, useMemo as useMemo5, useRef as useRef7, useState as useState6 } from "react";
473
+ import { useCallback as useCallback5, useEffect as useEffect11, useMemo as useMemo5, useRef as useRef7, useState as useState6 } from "react";
474
474
  import {
475
475
  fromString,
476
476
  identity,
@@ -848,7 +848,7 @@ import { su as su5 } from "@tscircuit/soup-util";
848
848
  // package.json
849
849
  var package_default = {
850
850
  name: "@tscircuit/schematic-viewer",
851
- version: "2.0.43",
851
+ version: "2.0.45",
852
852
  main: "dist/index.js",
853
853
  type: "module",
854
854
  scripts: {
@@ -1789,6 +1789,7 @@ import {
1789
1789
  } from "react";
1790
1790
  import { Fragment as Fragment2, jsx as jsx9 } from "react/jsx-runtime";
1791
1791
  var MouseTrackerContext = createContext(null);
1792
+ var DRAG_THRESHOLD_PX = 5;
1792
1793
  var boundsAreEqual = (a, b) => {
1793
1794
  if (!a && !b) return true;
1794
1795
  if (!a || !b) return false;
@@ -1803,7 +1804,8 @@ var MouseTracker = ({ children }) => {
1803
1804
  pointer: null,
1804
1805
  boundingBoxes: /* @__PURE__ */ new Map(),
1805
1806
  hoveringIds: /* @__PURE__ */ new Set(),
1806
- subscribers: /* @__PURE__ */ new Set()
1807
+ subscribers: /* @__PURE__ */ new Set(),
1808
+ mouseDownPosition: null
1807
1809
  });
1808
1810
  const notifySubscribers = useCallback3(() => {
1809
1811
  for (const callback of storeRef.current.subscribers) {
@@ -1878,10 +1880,28 @@ var MouseTracker = ({ children }) => {
1878
1880
  const handlePointerLeave = () => {
1879
1881
  if (storeRef.current.pointer === null) return;
1880
1882
  storeRef.current.pointer = null;
1883
+ storeRef.current.mouseDownPosition = null;
1881
1884
  updateHovering();
1882
1885
  };
1886
+ const handleMouseDown = (event) => {
1887
+ storeRef.current.mouseDownPosition = {
1888
+ x: event.clientX,
1889
+ y: event.clientY
1890
+ };
1891
+ };
1883
1892
  const handleClick = (event) => {
1884
1893
  const { clientX, clientY } = event;
1894
+ const mouseDownPos = storeRef.current.mouseDownPosition;
1895
+ if (mouseDownPos) {
1896
+ const distance = Math.sqrt(
1897
+ Math.pow(clientX - mouseDownPos.x, 2) + Math.pow(clientY - mouseDownPos.y, 2)
1898
+ );
1899
+ if (distance > DRAG_THRESHOLD_PX) {
1900
+ storeRef.current.mouseDownPosition = null;
1901
+ return;
1902
+ }
1903
+ }
1904
+ storeRef.current.mouseDownPosition = null;
1885
1905
  for (const registration of storeRef.current.boundingBoxes.values()) {
1886
1906
  const bounds = registration.bounds;
1887
1907
  if (!bounds) continue;
@@ -1902,6 +1922,7 @@ var MouseTracker = ({ children }) => {
1902
1922
  window.addEventListener("pointerleave", handlePointerLeave);
1903
1923
  window.addEventListener("pointercancel", handlePointerLeave);
1904
1924
  window.addEventListener("blur", handlePointerLeave);
1925
+ window.addEventListener("mousedown", handleMouseDown, { passive: true });
1905
1926
  window.addEventListener("click", handleClick, { passive: true });
1906
1927
  return () => {
1907
1928
  window.removeEventListener("pointermove", handlePointerPosition);
@@ -1910,6 +1931,7 @@ var MouseTracker = ({ children }) => {
1910
1931
  window.removeEventListener("pointerleave", handlePointerLeave);
1911
1932
  window.removeEventListener("pointercancel", handlePointerLeave);
1912
1933
  window.removeEventListener("blur", handlePointerLeave);
1934
+ window.removeEventListener("mousedown", handleMouseDown);
1913
1935
  window.removeEventListener("click", handleClick);
1914
1936
  };
1915
1937
  }, [updateHovering]);
@@ -2004,6 +2026,7 @@ var SchematicComponentMouseTarget = ({
2004
2026
  svgDivRef,
2005
2027
  containerRef,
2006
2028
  onComponentClick,
2029
+ onHoverChange,
2007
2030
  showOutline,
2008
2031
  circuitJsonKey
2009
2032
  }) => {
@@ -2096,6 +2119,11 @@ var SchematicComponentMouseTarget = ({
2096
2119
  bounds,
2097
2120
  onClick: onComponentClick ? handleClick : void 0
2098
2121
  });
2122
+ useEffect10(() => {
2123
+ if (onHoverChange) {
2124
+ onHoverChange(componentId, hovering);
2125
+ }
2126
+ }, [hovering, componentId, onHoverChange]);
2099
2127
  if (!measurement || !hovering || !showOutline) {
2100
2128
  return null;
2101
2129
  }
@@ -2110,10 +2138,8 @@ var SchematicComponentMouseTarget = ({
2110
2138
  width: rect.width,
2111
2139
  height: rect.height,
2112
2140
  border: "1.5px solid rgba(51, 153, 255, 0.9)",
2113
- borderRadius: "6px",
2114
2141
  pointerEvents: "none",
2115
- zIndex: zIndexMap.schematicComponentHoverOutline,
2116
- boxShadow: "0 0 6px rgba(51, 153, 255, 0.35)"
2142
+ zIndex: zIndexMap.schematicComponentHoverOutline
2117
2143
  }
2118
2144
  }
2119
2145
  );
@@ -2189,6 +2215,19 @@ var SchematicViewer = ({
2189
2215
  if (disableGroups) return false;
2190
2216
  return getStoredBoolean("schematic_viewer_show_groups", false);
2191
2217
  });
2218
+ const [isHoveringClickableComponent, setIsHoveringClickableComponent] = useState6(false);
2219
+ const hoveringComponentsRef = useRef7(/* @__PURE__ */ new Set());
2220
+ const handleComponentHoverChange = useCallback5(
2221
+ (componentId, isHovering) => {
2222
+ if (isHovering) {
2223
+ hoveringComponentsRef.current.add(componentId);
2224
+ } else {
2225
+ hoveringComponentsRef.current.delete(componentId);
2226
+ }
2227
+ setIsHoveringClickableComponent(hoveringComponentsRef.current.size > 0);
2228
+ },
2229
+ []
2230
+ );
2192
2231
  const svgDivRef = useRef7(null);
2193
2232
  const touchStartRef = useRef7(null);
2194
2233
  const schematicComponentIds = useMemo5(() => {
@@ -2327,6 +2366,7 @@ var SchematicViewer = ({
2327
2366
  pointerEvents: clickToInteractEnabled ? isInteractionEnabled ? "auto" : "none" : "auto",
2328
2367
  transformOrigin: "0 0"
2329
2368
  },
2369
+ className: onSchematicComponentClicked ? "schematic-component-clickable" : void 0,
2330
2370
  onTouchStart: (e) => {
2331
2371
  if (editModeEnabled && isInteractionEnabled && !showSpiceOverlay) {
2332
2372
  handleComponentTouchStartRef.current(e);
@@ -2343,159 +2383,163 @@ var SchematicViewer = ({
2343
2383
  showSpiceOverlay
2344
2384
  ]
2345
2385
  );
2346
- return /* @__PURE__ */ jsx11(MouseTracker, { children: /* @__PURE__ */ jsxs6(
2347
- "div",
2348
- {
2349
- ref: containerRef,
2350
- style: {
2351
- position: "relative",
2352
- backgroundColor: containerBackgroundColor,
2353
- overflow: "hidden",
2354
- cursor: showSpiceOverlay ? "auto" : isDragging ? "grabbing" : clickToInteractEnabled && !isInteractionEnabled ? "pointer" : "grab",
2355
- minHeight: "300px",
2356
- ...containerStyle
2357
- },
2358
- onWheelCapture: (e) => {
2359
- if (showSpiceOverlay) {
2360
- e.stopPropagation();
2361
- }
2362
- },
2363
- onMouseDown: (e) => {
2364
- if (clickToInteractEnabled && !isInteractionEnabled) {
2365
- e.preventDefault();
2366
- e.stopPropagation();
2367
- return;
2368
- }
2369
- handleMouseDown(e);
2370
- },
2371
- onMouseDownCapture: (e) => {
2372
- if (clickToInteractEnabled && !isInteractionEnabled) {
2373
- e.preventDefault();
2374
- e.stopPropagation();
2375
- return;
2376
- }
2377
- },
2378
- onTouchStart: (e) => {
2379
- if (showSpiceOverlay) return;
2380
- handleTouchStart(e);
2381
- },
2382
- onTouchEnd: (e) => {
2383
- if (showSpiceOverlay) return;
2384
- handleTouchEnd(e);
2385
- },
2386
- children: [
2387
- !isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx11(
2388
- "div",
2389
- {
2390
- onClick: (e) => {
2391
- e.preventDefault();
2392
- e.stopPropagation();
2393
- setIsInteractionEnabled(true);
2394
- },
2395
- style: {
2396
- position: "absolute",
2397
- inset: 0,
2398
- cursor: "pointer",
2399
- zIndex: zIndexMap.clickToInteractOverlay,
2400
- display: "flex",
2401
- alignItems: "center",
2402
- justifyContent: "center",
2403
- pointerEvents: "all",
2404
- touchAction: "pan-x pan-y pinch-zoom"
2405
- },
2406
- children: /* @__PURE__ */ jsx11(
2407
- "div",
2408
- {
2409
- style: {
2410
- backgroundColor: "rgba(0, 0, 0, 0.8)",
2411
- color: "white",
2412
- padding: "12px 24px",
2413
- borderRadius: "8px",
2414
- fontSize: "16px",
2415
- fontFamily: "sans-serif",
2416
- pointerEvents: "none"
2417
- },
2418
- children: typeof window !== "undefined" && ("ontouchstart" in window || navigator.maxTouchPoints > 0) ? "Touch to Interact" : "Click to Interact"
2419
- }
2420
- )
2421
- }
2422
- ),
2423
- /* @__PURE__ */ jsx11(
2424
- ViewMenuIcon,
2425
- {
2426
- active: showViewMenu,
2427
- onClick: () => setShowViewMenu(!showViewMenu)
2386
+ return /* @__PURE__ */ jsxs6(MouseTracker, { children: [
2387
+ onSchematicComponentClicked && /* @__PURE__ */ jsx11("style", { children: `.schematic-component-clickable [data-schematic-component-id]:hover { cursor: pointer !important; }` }),
2388
+ /* @__PURE__ */ jsxs6(
2389
+ "div",
2390
+ {
2391
+ ref: containerRef,
2392
+ style: {
2393
+ position: "relative",
2394
+ backgroundColor: containerBackgroundColor,
2395
+ overflow: "hidden",
2396
+ cursor: showSpiceOverlay ? "auto" : isDragging ? "grabbing" : clickToInteractEnabled && !isInteractionEnabled ? "pointer" : isHoveringClickableComponent && onSchematicComponentClicked ? "pointer" : "grab",
2397
+ minHeight: "300px",
2398
+ ...containerStyle
2399
+ },
2400
+ onWheelCapture: (e) => {
2401
+ if (showSpiceOverlay) {
2402
+ e.stopPropagation();
2428
2403
  }
2429
- ),
2430
- editingEnabled && /* @__PURE__ */ jsx11(
2431
- EditIcon,
2432
- {
2433
- active: editModeEnabled,
2434
- onClick: () => setEditModeEnabled(!editModeEnabled)
2404
+ },
2405
+ onMouseDown: (e) => {
2406
+ if (clickToInteractEnabled && !isInteractionEnabled) {
2407
+ e.preventDefault();
2408
+ e.stopPropagation();
2409
+ return;
2435
2410
  }
2436
- ),
2437
- editingEnabled && editModeEnabled && /* @__PURE__ */ jsx11(
2438
- GridIcon,
2439
- {
2440
- active: snapToGrid,
2441
- onClick: () => setSnapToGrid(!snapToGrid)
2411
+ handleMouseDown(e);
2412
+ },
2413
+ onMouseDownCapture: (e) => {
2414
+ if (clickToInteractEnabled && !isInteractionEnabled) {
2415
+ e.preventDefault();
2416
+ e.stopPropagation();
2417
+ return;
2442
2418
  }
2443
- ),
2444
- /* @__PURE__ */ jsx11(
2445
- ViewMenu,
2446
- {
2447
- circuitJson,
2448
- circuitJsonKey,
2449
- isVisible: showViewMenu,
2450
- onClose: () => setShowViewMenu(false),
2451
- showGroups: showSchematicGroups,
2452
- onToggleGroups: (value) => {
2453
- if (!disableGroups) {
2454
- setShowSchematicGroups(value);
2455
- setStoredBoolean("schematic_viewer_show_groups", value);
2419
+ },
2420
+ onTouchStart: (e) => {
2421
+ if (showSpiceOverlay) return;
2422
+ handleTouchStart(e);
2423
+ },
2424
+ onTouchEnd: (e) => {
2425
+ if (showSpiceOverlay) return;
2426
+ handleTouchEnd(e);
2427
+ },
2428
+ children: [
2429
+ !isInteractionEnabled && clickToInteractEnabled && /* @__PURE__ */ jsx11(
2430
+ "div",
2431
+ {
2432
+ onClick: (e) => {
2433
+ e.preventDefault();
2434
+ e.stopPropagation();
2435
+ setIsInteractionEnabled(true);
2436
+ },
2437
+ style: {
2438
+ position: "absolute",
2439
+ inset: 0,
2440
+ cursor: "pointer",
2441
+ zIndex: zIndexMap.clickToInteractOverlay,
2442
+ display: "flex",
2443
+ alignItems: "center",
2444
+ justifyContent: "center",
2445
+ pointerEvents: "all",
2446
+ touchAction: "pan-x pan-y pinch-zoom"
2447
+ },
2448
+ children: /* @__PURE__ */ jsx11(
2449
+ "div",
2450
+ {
2451
+ style: {
2452
+ backgroundColor: "rgba(0, 0, 0, 0.8)",
2453
+ color: "white",
2454
+ padding: "12px 24px",
2455
+ borderRadius: "8px",
2456
+ fontSize: "16px",
2457
+ fontFamily: "sans-serif",
2458
+ pointerEvents: "none"
2459
+ },
2460
+ children: typeof window !== "undefined" && ("ontouchstart" in window || navigator.maxTouchPoints > 0) ? "Touch to Interact" : "Click to Interact"
2461
+ }
2462
+ )
2463
+ }
2464
+ ),
2465
+ /* @__PURE__ */ jsx11(
2466
+ ViewMenuIcon,
2467
+ {
2468
+ active: showViewMenu,
2469
+ onClick: () => setShowViewMenu(!showViewMenu)
2470
+ }
2471
+ ),
2472
+ editingEnabled && /* @__PURE__ */ jsx11(
2473
+ EditIcon,
2474
+ {
2475
+ active: editModeEnabled,
2476
+ onClick: () => setEditModeEnabled(!editModeEnabled)
2477
+ }
2478
+ ),
2479
+ editingEnabled && editModeEnabled && /* @__PURE__ */ jsx11(
2480
+ GridIcon,
2481
+ {
2482
+ active: snapToGrid,
2483
+ onClick: () => setSnapToGrid(!snapToGrid)
2484
+ }
2485
+ ),
2486
+ /* @__PURE__ */ jsx11(
2487
+ ViewMenu,
2488
+ {
2489
+ circuitJson,
2490
+ circuitJsonKey,
2491
+ isVisible: showViewMenu,
2492
+ onClose: () => setShowViewMenu(false),
2493
+ showGroups: showSchematicGroups,
2494
+ onToggleGroups: (value) => {
2495
+ if (!disableGroups) {
2496
+ setShowSchematicGroups(value);
2497
+ setStoredBoolean("schematic_viewer_show_groups", value);
2498
+ }
2456
2499
  }
2457
2500
  }
2458
- }
2459
- ),
2460
- spiceSimulationEnabled && /* @__PURE__ */ jsx11(SpiceSimulationIcon, { onClick: () => setShowSpiceOverlay(true) }),
2461
- showSpiceOverlay && /* @__PURE__ */ jsx11(
2462
- SpiceSimulationOverlay,
2463
- {
2464
- spiceString,
2465
- onClose: () => setShowSpiceOverlay(false),
2466
- plotData,
2467
- nodes,
2468
- isLoading: isSpiceSimLoading,
2469
- error: spiceSimError,
2470
- simOptions: spiceSimOptions,
2471
- onSimOptionsChange: (options) => {
2472
- setHasSpiceSimRun(true);
2473
- setSpiceSimOptions(options);
2474
- },
2475
- hasRun: hasSpiceSimRun
2476
- }
2477
- ),
2478
- onSchematicComponentClicked && schematicComponentIds.map((componentId) => /* @__PURE__ */ jsx11(
2479
- SchematicComponentMouseTarget,
2480
- {
2481
- componentId,
2482
- svgDivRef,
2483
- containerRef,
2484
- showOutline: true,
2485
- circuitJsonKey,
2486
- onComponentClick: (id, event) => {
2487
- onSchematicComponentClicked?.({
2488
- schematicComponentId: id,
2489
- event
2490
- });
2501
+ ),
2502
+ spiceSimulationEnabled && /* @__PURE__ */ jsx11(SpiceSimulationIcon, { onClick: () => setShowSpiceOverlay(true) }),
2503
+ showSpiceOverlay && /* @__PURE__ */ jsx11(
2504
+ SpiceSimulationOverlay,
2505
+ {
2506
+ spiceString,
2507
+ onClose: () => setShowSpiceOverlay(false),
2508
+ plotData,
2509
+ nodes,
2510
+ isLoading: isSpiceSimLoading,
2511
+ error: spiceSimError,
2512
+ simOptions: spiceSimOptions,
2513
+ onSimOptionsChange: (options) => {
2514
+ setHasSpiceSimRun(true);
2515
+ setSpiceSimOptions(options);
2516
+ },
2517
+ hasRun: hasSpiceSimRun
2491
2518
  }
2492
- },
2493
- componentId
2494
- )),
2495
- svgDiv
2496
- ]
2497
- }
2498
- ) });
2519
+ ),
2520
+ onSchematicComponentClicked && schematicComponentIds.map((componentId) => /* @__PURE__ */ jsx11(
2521
+ SchematicComponentMouseTarget,
2522
+ {
2523
+ componentId,
2524
+ svgDivRef,
2525
+ containerRef,
2526
+ showOutline: true,
2527
+ circuitJsonKey,
2528
+ onHoverChange: handleComponentHoverChange,
2529
+ onComponentClick: (id, event) => {
2530
+ onSchematicComponentClicked?.({
2531
+ schematicComponentId: id,
2532
+ event
2533
+ });
2534
+ }
2535
+ },
2536
+ componentId
2537
+ )),
2538
+ svgDiv
2539
+ ]
2540
+ }
2541
+ )
2542
+ ] });
2499
2543
  };
2500
2544
  export {
2501
2545
  MouseTracker,