@tscircuit/pcb-viewer 1.11.280 → 1.11.282

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
@@ -10605,7 +10605,7 @@ function calculateDiagonalLabel(params) {
10605
10605
  } = params;
10606
10606
  const deltaX = dimensionEnd.x - dimensionStart.x;
10607
10607
  const deltaY = dimensionEnd.y - dimensionStart.y;
10608
- const distance4 = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
10608
+ const distance5 = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
10609
10609
  const screenDeltaX = screenDimensionEnd.x - screenDimensionStart.x;
10610
10610
  const screenDeltaY = screenDimensionEnd.y - screenDimensionStart.y;
10611
10611
  const screenDistance = Math.sqrt(
@@ -10647,11 +10647,11 @@ function calculateDiagonalLabel(params) {
10647
10647
  const x = midX + offsetX;
10648
10648
  const y = midY + offsetY;
10649
10649
  return {
10650
- distance: distance4,
10650
+ distance: distance5,
10651
10651
  screenDistance,
10652
10652
  x,
10653
10653
  y,
10654
- show: distance4 > 0.01 && screenDistance > 30 && isDiagonal
10654
+ show: distance5 > 0.01 && screenDistance > 30 && isDiagonal
10655
10655
  };
10656
10656
  }
10657
10657
 
@@ -10945,11 +10945,11 @@ var DimensionOverlay = ({
10945
10945
  for (const snap of snappingPointsWithScreen) {
10946
10946
  const dx = snap.screenPoint.x - screenPoint.x;
10947
10947
  const dy = snap.screenPoint.y - screenPoint.y;
10948
- const distance4 = Math.hypot(dx, dy);
10949
- if (distance4 > SNAP_THRESHOLD_PX) continue;
10950
- if (!bestMatch || distance4 < bestMatch.distance) {
10948
+ const distance5 = Math.hypot(dx, dy);
10949
+ if (distance5 > SNAP_THRESHOLD_PX) continue;
10950
+ if (!bestMatch || distance5 < bestMatch.distance) {
10951
10951
  bestMatch = {
10952
- distance: distance4,
10952
+ distance: distance5,
10953
10953
  id: snap.id,
10954
10954
  point: snap.point
10955
10955
  };
@@ -11548,10 +11548,10 @@ var isInsideOfSmtpad = (elm, point, padding = 0) => {
11548
11548
  };
11549
11549
  var isInsideOfPlatedHole = (hole, point, padding = 0) => {
11550
11550
  if (hole.shape === "circle") {
11551
- const distance4 = Math.sqrt(
11551
+ const distance5 = Math.sqrt(
11552
11552
  (point.x - hole.x) ** 2 + (point.y - hole.y) ** 2
11553
11553
  );
11554
- return distance4 <= hole.outer_diameter / 2 + padding;
11554
+ return distance5 <= hole.outer_diameter / 2 + padding;
11555
11555
  } else if (hole.shape === "circular_hole_with_rect_pad") {
11556
11556
  const dx = Math.abs(point.x - hole.x);
11557
11557
  const dy = Math.abs(point.y - hole.y);
@@ -12379,7 +12379,7 @@ var ErrorOverlay = ({
12379
12379
 
12380
12380
  // src/components/MouseElementTracker.tsx
12381
12381
  import { pointToSegmentDistance } from "@tscircuit/math-utils";
12382
- import { distance as distance3 } from "circuit-json";
12382
+ import { distance as distance4 } from "circuit-json";
12383
12383
 
12384
12384
  // src/lib/util/if-sets-match-exactly.ts
12385
12385
  function ifSetsMatchExactly(set1, set2) {
@@ -12389,7 +12389,7 @@ function ifSetsMatchExactly(set1, set2) {
12389
12389
 
12390
12390
  // src/components/MouseElementTracker.tsx
12391
12391
  import { useState as useState7, useMemo as useMemo5 } from "react";
12392
- import { applyToPoint as applyToPoint13, inverse as inverse5 } from "transformation-matrix";
12392
+ import { applyToPoint as applyToPoint14, inverse as inverse5 } from "transformation-matrix";
12393
12393
 
12394
12394
  // src/components/ElementOverlayBox.tsx
12395
12395
  import { useEffect as useEffect11, useState as useState6 } from "react";
@@ -12666,25 +12666,10 @@ var ElementOverlayBox = ({
12666
12666
  )) });
12667
12667
  };
12668
12668
 
12669
- // src/components/GroupAnchorOffsetOverlay/index.tsx
12669
+ // src/components/AnchorOffsetOverlay/Board/index.tsx
12670
12670
  import { applyToPoint as applyToPoint12 } from "transformation-matrix";
12671
12671
 
12672
- // src/components/GroupAnchorOffsetOverlay/calculateGroupBoundingBox.ts
12673
- var calculateGroupBoundingBox = (groupComponents) => {
12674
- const points = [];
12675
- for (const comp of groupComponents) {
12676
- if (!comp.center || typeof comp.width !== "number" || typeof comp.height !== "number") {
12677
- continue;
12678
- }
12679
- const halfWidth = comp.width / 2;
12680
- const halfHeight = comp.height / 2;
12681
- points.push({ x: comp.center.x - halfWidth, y: comp.center.y - halfHeight });
12682
- points.push({ x: comp.center.x + halfWidth, y: comp.center.y + halfHeight });
12683
- }
12684
- return getBoundsFromPoints(points);
12685
- };
12686
-
12687
- // src/components/GroupAnchorOffsetOverlay/constants.ts
12672
+ // src/components/AnchorOffsetOverlay/common/constants.ts
12688
12673
  var VISUAL_CONFIG = {
12689
12674
  GROUP_PADDING: 1,
12690
12675
  MIN_LINE_LENGTH_FOR_LABEL: 40,
@@ -12695,7 +12680,9 @@ var VISUAL_CONFIG = {
12695
12680
  LINE_STROKE_WIDTH: 1.5,
12696
12681
  LINE_DASH_PATTERN: "4,4",
12697
12682
  COMPONENT_MARKER_RADIUS: 3,
12698
- LABEL_FONT_SIZE: 11
12683
+ LABEL_FONT_SIZE: 11,
12684
+ ANCHOR_MARKER_SIZE: 6,
12685
+ ANCHOR_MARKER_STROKE_WIDTH: 1.5
12699
12686
  };
12700
12687
  var COLORS = {
12701
12688
  OFFSET_LINE: "white",
@@ -12704,73 +12691,281 @@ var COLORS = {
12704
12691
  LABEL_TEXT: "white"
12705
12692
  };
12706
12693
 
12707
- // src/components/GroupAnchorOffsetOverlay/findAnchorMarkerPosition.ts
12708
- var findAnchorMarkerPosition = (anchor, bounds) => {
12709
- const { minX, maxX, minY, maxY } = bounds;
12710
- const distToLeft = Math.abs(anchor.x - minX);
12711
- const distToRight = Math.abs(anchor.x - maxX);
12712
- const distToTop = Math.abs(anchor.y - maxY);
12713
- const distToBottom = Math.abs(anchor.y - minY);
12714
- const minDist = Math.min(distToLeft, distToRight, distToTop, distToBottom);
12715
- if (minDist === distToLeft) return { x: minX, y: anchor.y };
12716
- if (minDist === distToRight) return { x: maxX, y: anchor.y };
12717
- if (minDist === distToTop) return { x: anchor.x, y: maxY };
12718
- return { x: anchor.x, y: minY };
12719
- };
12694
+ // src/components/AnchorOffsetOverlay/common/guards.ts
12695
+ var isPcbComponent = (element) => element?.type === "pcb_component";
12696
+ var isPcbGroup = (element) => element?.type === "pcb_group";
12697
+ var isPcbBoard = (element) => element?.type === "pcb_board";
12720
12698
 
12721
- // src/components/GroupAnchorOffsetOverlay/index.tsx
12699
+ // src/components/AnchorOffsetOverlay/Board/index.tsx
12722
12700
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
12723
- var GroupAnchorOffsetOverlay = ({
12701
+ var BoardAnchorOffsetOverlay = ({
12724
12702
  elements,
12725
12703
  highlightedPrimitives,
12726
12704
  transform,
12727
12705
  containerWidth,
12728
- containerHeight,
12729
- children
12706
+ containerHeight
12730
12707
  }) => {
12731
- const is_showing_group_anchor_offsets = useGlobalStore(
12732
- (s) => s.is_showing_group_anchor_offsets
12708
+ const boards = elements.filter((el) => isPcbBoard(el));
12709
+ const components = elements.filter(
12710
+ (el) => isPcbComponent(el)
12711
+ );
12712
+ const hoveredComponentIds = highlightedPrimitives.map((primitive) => {
12713
+ if (isPcbComponent(primitive._parent_pcb_component)) {
12714
+ return primitive._parent_pcb_component.pcb_component_id;
12715
+ }
12716
+ if (isPcbComponent(primitive._element)) {
12717
+ return primitive._element.pcb_component_id;
12718
+ }
12719
+ return null;
12720
+ }).filter((id) => Boolean(id));
12721
+ const isShowingAnchorOffsets = useGlobalStore(
12722
+ (state) => state.is_showing_group_anchor_offsets
12733
12723
  );
12734
- if (!is_showing_group_anchor_offsets || highlightedPrimitives.length === 0) {
12724
+ if (!isShowingAnchorOffsets && hoveredComponentIds.length === 0) {
12735
12725
  return null;
12736
12726
  }
12737
- const hoveredPrimitive = highlightedPrimitives.find(
12738
- (p) => p._parent_pcb_component?.type === "pcb_component" || p._element?.type === "pcb_component"
12727
+ const targets = components.map((component) => {
12728
+ const boardId = component.positioned_relative_to_pcb_board_id;
12729
+ if (!boardId) return null;
12730
+ const board = boards.find((b) => b.pcb_board_id === boardId);
12731
+ return board ? { component, board } : null;
12732
+ }).filter(
12733
+ (target) => Boolean(target)
12739
12734
  );
12740
- if (!hoveredPrimitive) return null;
12741
- const pcbComponent = hoveredPrimitive._parent_pcb_component || hoveredPrimitive._element;
12742
- if (!pcbComponent?.pcb_group_id) return null;
12743
- const parentGroup = elements.filter((el) => el.type === "pcb_group").find((group) => group.pcb_group_id === pcbComponent.pcb_group_id);
12744
- if (!parentGroup?.anchor_position) return null;
12745
- const targetCenter = hoveredPrimitive._element?.type === "pcb_smtpad" ? { x: hoveredPrimitive.x, y: hoveredPrimitive.y } : pcbComponent.center || {
12746
- x: hoveredPrimitive.x,
12747
- y: hoveredPrimitive.y
12748
- };
12749
- const groupComponents = elements.filter((el) => el.type === "pcb_component").filter((comp) => comp.pcb_group_id === parentGroup.pcb_group_id);
12750
- const boundingBox = calculateGroupBoundingBox(groupComponents);
12751
- if (!boundingBox) return null;
12752
- const groupBounds = {
12753
- minX: boundingBox.minX - VISUAL_CONFIG.GROUP_PADDING,
12754
- maxX: boundingBox.maxX + VISUAL_CONFIG.GROUP_PADDING,
12755
- minY: boundingBox.minY - VISUAL_CONFIG.GROUP_PADDING,
12756
- maxY: boundingBox.maxY + VISUAL_CONFIG.GROUP_PADDING
12735
+ if (targets.length === 0) return null;
12736
+ const shouldShowAllTargets = hoveredComponentIds.length === 0;
12737
+ const labelStyle = {
12738
+ color: COLORS.LABEL_TEXT,
12739
+ mixBlendMode: "difference",
12740
+ pointerEvents: "none",
12741
+ fontSize: VISUAL_CONFIG.LABEL_FONT_SIZE,
12742
+ fontFamily: "monospace",
12743
+ fontWeight: "bold"
12757
12744
  };
12758
- const anchorMarkerPosition = findAnchorMarkerPosition(
12759
- parentGroup.anchor_position,
12760
- groupBounds
12745
+ const targetEntries = targets.filter(
12746
+ ({ component }) => shouldShowAllTargets || hoveredComponentIds.includes(component.pcb_component_id)
12761
12747
  );
12762
- const offsetX = targetCenter.x - anchorMarkerPosition.x;
12763
- const offsetY = targetCenter.y - anchorMarkerPosition.y;
12764
- const anchorMarkerScreen = applyToPoint12(transform, anchorMarkerPosition);
12765
- const componentScreen = applyToPoint12(transform, targetCenter);
12766
- const xLineLength = Math.abs(componentScreen.x - anchorMarkerScreen.x);
12767
- const yLineLength = Math.abs(componentScreen.y - anchorMarkerScreen.y);
12768
- const isComponentAboveAnchor = componentScreen.y < anchorMarkerScreen.y;
12769
- const isComponentRightOfAnchor = componentScreen.x > anchorMarkerScreen.x;
12770
- const xLabelOffset = isComponentAboveAnchor ? VISUAL_CONFIG.LABEL_OFFSET_ABOVE : VISUAL_CONFIG.LABEL_OFFSET_BELOW;
12771
- const yLabelOffset = isComponentRightOfAnchor ? VISUAL_CONFIG.LABEL_OFFSET_RIGHT : VISUAL_CONFIG.LABEL_OFFSET_LEFT;
12772
- const shouldShowXLabel = xLineLength > VISUAL_CONFIG.MIN_LINE_LENGTH_FOR_LABEL;
12773
- const shouldShowYLabel = yLineLength > VISUAL_CONFIG.MIN_LINE_LENGTH_FOR_LABEL;
12748
+ if (targetEntries.length === 0) return null;
12749
+ const boardAnchorScreens = /* @__PURE__ */ new Map();
12750
+ return /* @__PURE__ */ jsx12(
12751
+ "div",
12752
+ {
12753
+ style: {
12754
+ position: "absolute",
12755
+ left: 0,
12756
+ top: 0,
12757
+ width: containerWidth,
12758
+ height: containerHeight,
12759
+ overflow: "hidden",
12760
+ pointerEvents: "none",
12761
+ zIndex: zIndexMap.dimensionOverlay
12762
+ },
12763
+ children: /* @__PURE__ */ jsxs9(
12764
+ "svg",
12765
+ {
12766
+ style: {
12767
+ position: "absolute",
12768
+ left: 0,
12769
+ top: 0,
12770
+ pointerEvents: "none"
12771
+ },
12772
+ width: containerWidth,
12773
+ height: containerHeight,
12774
+ children: [
12775
+ targetEntries.map(({ component, board }) => {
12776
+ const anchorPosition = board.center;
12777
+ const componentCenter = component.center;
12778
+ const anchorKey = board.pcb_board_id;
12779
+ if (!boardAnchorScreens.has(anchorKey)) {
12780
+ const screenPoint = applyToPoint12(transform, anchorPosition);
12781
+ boardAnchorScreens.set(anchorKey, screenPoint);
12782
+ }
12783
+ const anchorMarkerScreen = boardAnchorScreens.get(anchorKey);
12784
+ const componentScreen = applyToPoint12(transform, componentCenter);
12785
+ const offsetX = componentCenter.x - anchorPosition.x;
12786
+ const offsetY = componentCenter.y - anchorPosition.y;
12787
+ const xLineLength = Math.abs(componentScreen.x - anchorMarkerScreen.x);
12788
+ const yLineLength = Math.abs(componentScreen.y - anchorMarkerScreen.y);
12789
+ const isComponentAboveAnchor = componentScreen.y < anchorMarkerScreen.y;
12790
+ const isComponentRightOfAnchor = componentScreen.x > anchorMarkerScreen.x;
12791
+ const xLabelOffset = isComponentAboveAnchor ? VISUAL_CONFIG.LABEL_OFFSET_ABOVE : VISUAL_CONFIG.LABEL_OFFSET_BELOW;
12792
+ const yLabelOffset = isComponentRightOfAnchor ? VISUAL_CONFIG.LABEL_OFFSET_RIGHT : VISUAL_CONFIG.LABEL_OFFSET_LEFT;
12793
+ const shouldShowXLabel = xLineLength > VISUAL_CONFIG.MIN_LINE_LENGTH_FOR_LABEL;
12794
+ const shouldShowYLabel = yLineLength > VISUAL_CONFIG.MIN_LINE_LENGTH_FOR_LABEL;
12795
+ const xLabelText = component.display_offset_x ?? `Board \u0394x: ${offsetX.toFixed(2)}mm`;
12796
+ const yLabelText = component.display_offset_y ?? `Board \u0394y: ${offsetY.toFixed(2)}mm`;
12797
+ return /* @__PURE__ */ jsxs9("g", { children: [
12798
+ /* @__PURE__ */ jsx12(
12799
+ "line",
12800
+ {
12801
+ x1: anchorMarkerScreen.x,
12802
+ y1: anchorMarkerScreen.y,
12803
+ x2: componentScreen.x,
12804
+ y2: anchorMarkerScreen.y,
12805
+ stroke: COLORS.OFFSET_LINE,
12806
+ strokeWidth: VISUAL_CONFIG.LINE_STROKE_WIDTH,
12807
+ strokeDasharray: VISUAL_CONFIG.LINE_DASH_PATTERN
12808
+ }
12809
+ ),
12810
+ /* @__PURE__ */ jsx12(
12811
+ "line",
12812
+ {
12813
+ x1: componentScreen.x,
12814
+ y1: anchorMarkerScreen.y,
12815
+ x2: componentScreen.x,
12816
+ y2: componentScreen.y,
12817
+ stroke: COLORS.OFFSET_LINE,
12818
+ strokeWidth: VISUAL_CONFIG.LINE_STROKE_WIDTH,
12819
+ strokeDasharray: VISUAL_CONFIG.LINE_DASH_PATTERN
12820
+ }
12821
+ ),
12822
+ /* @__PURE__ */ jsx12(
12823
+ "circle",
12824
+ {
12825
+ cx: componentScreen.x,
12826
+ cy: componentScreen.y,
12827
+ r: VISUAL_CONFIG.COMPONENT_MARKER_RADIUS,
12828
+ fill: COLORS.COMPONENT_MARKER_FILL,
12829
+ stroke: COLORS.COMPONENT_MARKER_STROKE,
12830
+ strokeWidth: 1
12831
+ }
12832
+ ),
12833
+ shouldShowXLabel && /* @__PURE__ */ jsx12(
12834
+ "foreignObject",
12835
+ {
12836
+ x: Math.min(anchorMarkerScreen.x, componentScreen.x),
12837
+ y: anchorMarkerScreen.y + xLabelOffset,
12838
+ width: Math.abs(componentScreen.x - anchorMarkerScreen.x),
12839
+ height: 20,
12840
+ style: { overflow: "visible" },
12841
+ children: /* @__PURE__ */ jsx12("div", { style: { ...labelStyle, textAlign: "center" }, children: xLabelText })
12842
+ }
12843
+ ),
12844
+ shouldShowYLabel && /* @__PURE__ */ jsx12(
12845
+ "foreignObject",
12846
+ {
12847
+ x: componentScreen.x + yLabelOffset,
12848
+ y: Math.min(anchorMarkerScreen.y, componentScreen.y),
12849
+ width: 20,
12850
+ height: Math.abs(componentScreen.y - anchorMarkerScreen.y),
12851
+ style: { overflow: "visible" },
12852
+ children: /* @__PURE__ */ jsx12(
12853
+ "div",
12854
+ {
12855
+ style: {
12856
+ ...labelStyle,
12857
+ display: "flex",
12858
+ alignItems: "center",
12859
+ height: "100%"
12860
+ },
12861
+ children: yLabelText
12862
+ }
12863
+ )
12864
+ }
12865
+ )
12866
+ ] }, `${board.pcb_board_id}-${component.pcb_component_id}`);
12867
+ }),
12868
+ Array.from(boardAnchorScreens.entries()).map(
12869
+ ([boardId, anchorScreen]) => /* @__PURE__ */ jsxs9("g", { children: [
12870
+ /* @__PURE__ */ jsx12(
12871
+ "line",
12872
+ {
12873
+ x1: anchorScreen.x - VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
12874
+ y1: anchorScreen.y,
12875
+ x2: anchorScreen.x + VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
12876
+ y2: anchorScreen.y,
12877
+ stroke: COLORS.OFFSET_LINE,
12878
+ strokeWidth: VISUAL_CONFIG.ANCHOR_MARKER_STROKE_WIDTH
12879
+ }
12880
+ ),
12881
+ /* @__PURE__ */ jsx12(
12882
+ "line",
12883
+ {
12884
+ x1: anchorScreen.x,
12885
+ y1: anchorScreen.y - VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
12886
+ x2: anchorScreen.x,
12887
+ y2: anchorScreen.y + VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
12888
+ stroke: COLORS.OFFSET_LINE,
12889
+ strokeWidth: VISUAL_CONFIG.ANCHOR_MARKER_STROKE_WIDTH
12890
+ }
12891
+ )
12892
+ ] }, `anchor-${boardId}`)
12893
+ )
12894
+ ]
12895
+ }
12896
+ )
12897
+ }
12898
+ );
12899
+ };
12900
+
12901
+ // src/components/AnchorOffsetOverlay/Group/index.tsx
12902
+ import { applyToPoint as applyToPoint13 } from "transformation-matrix";
12903
+
12904
+ // src/components/AnchorOffsetOverlay/Group/calculateGroupBoundingBox.ts
12905
+ import { distance as distance3 } from "circuit-json";
12906
+ var calculateGroupBoundingBox = (groupComponents) => {
12907
+ const points = [];
12908
+ for (const comp of groupComponents) {
12909
+ if (!comp.center) {
12910
+ continue;
12911
+ }
12912
+ const width = typeof comp.width === "number" ? comp.width : distance3.parse(comp.width);
12913
+ const height = typeof comp.height === "number" ? comp.height : distance3.parse(comp.height);
12914
+ const halfWidth = width / 2;
12915
+ const halfHeight = height / 2;
12916
+ points.push({ x: comp.center.x - halfWidth, y: comp.center.y - halfHeight });
12917
+ points.push({ x: comp.center.x + halfWidth, y: comp.center.y + halfHeight });
12918
+ }
12919
+ return getBoundsFromPoints(points);
12920
+ };
12921
+
12922
+ // src/components/AnchorOffsetOverlay/Group/index.tsx
12923
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
12924
+ var GroupAnchorOffsetOverlay = ({
12925
+ elements,
12926
+ highlightedPrimitives,
12927
+ transform,
12928
+ containerWidth,
12929
+ containerHeight
12930
+ }) => {
12931
+ const groups = elements.filter((el) => isPcbGroup(el));
12932
+ const components = elements.filter(
12933
+ (el) => isPcbComponent(el)
12934
+ );
12935
+ const hoveredComponentIds = highlightedPrimitives.map((primitive) => {
12936
+ if (isPcbComponent(primitive._parent_pcb_component)) {
12937
+ return primitive._parent_pcb_component.pcb_component_id;
12938
+ }
12939
+ if (isPcbComponent(primitive._element)) {
12940
+ return primitive._element.pcb_component_id;
12941
+ }
12942
+ return null;
12943
+ }).filter((id) => Boolean(id));
12944
+ const isShowingAnchorOffsets = useGlobalStore(
12945
+ (s) => s.is_showing_group_anchor_offsets
12946
+ );
12947
+ if (!isShowingAnchorOffsets && hoveredComponentIds.length === 0) {
12948
+ return null;
12949
+ }
12950
+ const targets = components.map((component) => {
12951
+ if (component.position_mode === "relative_to_group_anchor" && component.positioned_relative_to_pcb_group_id) {
12952
+ const parentGroup = groups.find(
12953
+ (group) => group.pcb_group_id === component.positioned_relative_to_pcb_group_id
12954
+ );
12955
+ return parentGroup && parentGroup.anchor_position ? { component, parentGroup } : null;
12956
+ }
12957
+ if (component.pcb_group_id) {
12958
+ const parentGroup = groups.find(
12959
+ (group) => group.pcb_group_id === component.pcb_group_id
12960
+ );
12961
+ return parentGroup && parentGroup.anchor_position ? { component, parentGroup } : null;
12962
+ }
12963
+ return null;
12964
+ }).filter(
12965
+ (target) => Boolean(target)
12966
+ );
12967
+ if (targets.length === 0) return null;
12968
+ const shouldShowAllTargets = hoveredComponentIds.length === 0;
12774
12969
  const labelStyle = {
12775
12970
  color: COLORS.LABEL_TEXT,
12776
12971
  mixBlendMode: "difference",
@@ -12779,7 +12974,17 @@ var GroupAnchorOffsetOverlay = ({
12779
12974
  fontFamily: "monospace",
12780
12975
  fontWeight: "bold"
12781
12976
  };
12782
- return /* @__PURE__ */ jsxs9(
12977
+ const targetEntries = targets.filter(
12978
+ ({ component }) => shouldShowAllTargets || hoveredComponentIds.includes(component.pcb_component_id)
12979
+ );
12980
+ if (targetEntries.length === 0) return null;
12981
+ const groupAnchorScreens = /* @__PURE__ */ new Map();
12982
+ targetEntries.forEach(({ parentGroup }) => {
12983
+ if (!parentGroup.anchor_position) return;
12984
+ const anchorScreen = applyToPoint13(transform, parentGroup.anchor_position);
12985
+ groupAnchorScreens.set(parentGroup.pcb_group_id, anchorScreen);
12986
+ });
12987
+ return /* @__PURE__ */ jsx13(
12783
12988
  "div",
12784
12989
  {
12785
12990
  style: {
@@ -12792,102 +12997,158 @@ var GroupAnchorOffsetOverlay = ({
12792
12997
  pointerEvents: "none",
12793
12998
  zIndex: zIndexMap.dimensionOverlay
12794
12999
  },
12795
- children: [
12796
- /* @__PURE__ */ jsxs9(
12797
- "svg",
12798
- {
12799
- style: {
12800
- position: "absolute",
12801
- left: 0,
12802
- top: 0,
12803
- pointerEvents: "none"
12804
- },
12805
- width: containerWidth,
12806
- height: containerHeight,
12807
- children: [
12808
- /* @__PURE__ */ jsx12(
12809
- "line",
12810
- {
12811
- x1: anchorMarkerScreen.x,
12812
- y1: anchorMarkerScreen.y,
12813
- x2: componentScreen.x,
12814
- y2: anchorMarkerScreen.y,
12815
- stroke: COLORS.OFFSET_LINE,
12816
- strokeWidth: VISUAL_CONFIG.LINE_STROKE_WIDTH,
12817
- strokeDasharray: VISUAL_CONFIG.LINE_DASH_PATTERN
12818
- }
12819
- ),
12820
- /* @__PURE__ */ jsx12(
12821
- "line",
12822
- {
12823
- x1: componentScreen.x,
12824
- y1: anchorMarkerScreen.y,
12825
- x2: componentScreen.x,
12826
- y2: componentScreen.y,
12827
- stroke: COLORS.OFFSET_LINE,
12828
- strokeWidth: VISUAL_CONFIG.LINE_STROKE_WIDTH,
12829
- strokeDasharray: VISUAL_CONFIG.LINE_DASH_PATTERN
12830
- }
12831
- ),
12832
- /* @__PURE__ */ jsx12(
12833
- "circle",
13000
+ children: /* @__PURE__ */ jsxs10(
13001
+ "svg",
13002
+ {
13003
+ style: {
13004
+ position: "absolute",
13005
+ left: 0,
13006
+ top: 0,
13007
+ pointerEvents: "none"
13008
+ },
13009
+ width: containerWidth,
13010
+ height: containerHeight,
13011
+ children: [
13012
+ targetEntries.map(({ component, parentGroup }) => {
13013
+ const anchor = parentGroup.anchor_position;
13014
+ const center = component.center;
13015
+ if (!anchor || !center) return null;
13016
+ const anchorMarkerPosition = { x: anchor.x, y: anchor.y };
13017
+ const targetCenter = { x: center.x, y: center.y };
13018
+ const groupComponents = components.filter(
13019
+ (comp) => comp.pcb_group_id === parentGroup.pcb_group_id
13020
+ );
13021
+ const boundingBox = calculateGroupBoundingBox(groupComponents);
13022
+ if (!boundingBox) return null;
13023
+ const offsetX = targetCenter.x - anchorMarkerPosition.x;
13024
+ const offsetY = targetCenter.y - anchorMarkerPosition.y;
13025
+ const anchorMarkerScreen = applyToPoint13(
13026
+ transform,
13027
+ anchorMarkerPosition
13028
+ );
13029
+ const componentScreen = applyToPoint13(transform, targetCenter);
13030
+ const xLineLength = Math.abs(componentScreen.x - anchorMarkerScreen.x);
13031
+ const yLineLength = Math.abs(componentScreen.y - anchorMarkerScreen.y);
13032
+ const isComponentAboveAnchor = componentScreen.y < anchorMarkerScreen.y;
13033
+ const isComponentRightOfAnchor = componentScreen.x > anchorMarkerScreen.x;
13034
+ const xLabelOffset = isComponentAboveAnchor ? VISUAL_CONFIG.LABEL_OFFSET_ABOVE : VISUAL_CONFIG.LABEL_OFFSET_BELOW;
13035
+ const yLabelOffset = isComponentRightOfAnchor ? VISUAL_CONFIG.LABEL_OFFSET_RIGHT : VISUAL_CONFIG.LABEL_OFFSET_LEFT;
13036
+ const shouldShowXLabel = xLineLength > VISUAL_CONFIG.MIN_LINE_LENGTH_FOR_LABEL;
13037
+ const shouldShowYLabel = yLineLength > VISUAL_CONFIG.MIN_LINE_LENGTH_FOR_LABEL;
13038
+ const xLabelText = component.display_offset_x ?? `\u0394x: ${offsetX.toFixed(2)}mm`;
13039
+ const yLabelText = component.display_offset_y ?? `\u0394y: ${offsetY.toFixed(2)}mm`;
13040
+ return /* @__PURE__ */ jsxs10(
13041
+ "g",
12834
13042
  {
12835
- cx: componentScreen.x,
12836
- cy: componentScreen.y,
12837
- r: VISUAL_CONFIG.COMPONENT_MARKER_RADIUS,
12838
- fill: COLORS.COMPONENT_MARKER_FILL,
12839
- stroke: COLORS.COMPONENT_MARKER_STROKE,
12840
- strokeWidth: 1
12841
- }
12842
- )
12843
- ]
12844
- }
12845
- ),
12846
- shouldShowXLabel && /* @__PURE__ */ jsxs9(
12847
- "div",
12848
- {
12849
- style: {
12850
- ...labelStyle,
12851
- position: "absolute",
12852
- left: Math.min(anchorMarkerScreen.x, componentScreen.x),
12853
- top: anchorMarkerScreen.y + xLabelOffset,
12854
- width: Math.abs(componentScreen.x - anchorMarkerScreen.x),
12855
- textAlign: "center"
12856
- },
12857
- children: [
12858
- "\u0394x: ",
12859
- offsetX.toFixed(2),
12860
- "mm"
12861
- ]
12862
- }
12863
- ),
12864
- shouldShowYLabel && /* @__PURE__ */ jsxs9(
12865
- "div",
12866
- {
12867
- style: {
12868
- ...labelStyle,
12869
- position: "absolute",
12870
- left: componentScreen.x + yLabelOffset,
12871
- top: Math.min(anchorMarkerScreen.y, componentScreen.y),
12872
- height: Math.abs(componentScreen.y - anchorMarkerScreen.y),
12873
- display: "flex",
12874
- flexDirection: "column",
12875
- justifyContent: "center"
12876
- },
12877
- children: [
12878
- "\u0394y: ",
12879
- offsetY.toFixed(2),
12880
- "mm"
12881
- ]
12882
- }
12883
- )
12884
- ]
13043
+ children: [
13044
+ /* @__PURE__ */ jsx13(
13045
+ "line",
13046
+ {
13047
+ x1: anchorMarkerScreen.x,
13048
+ y1: anchorMarkerScreen.y,
13049
+ x2: componentScreen.x,
13050
+ y2: anchorMarkerScreen.y,
13051
+ stroke: COLORS.OFFSET_LINE,
13052
+ strokeWidth: VISUAL_CONFIG.LINE_STROKE_WIDTH,
13053
+ strokeDasharray: VISUAL_CONFIG.LINE_DASH_PATTERN
13054
+ }
13055
+ ),
13056
+ /* @__PURE__ */ jsx13(
13057
+ "line",
13058
+ {
13059
+ x1: componentScreen.x,
13060
+ y1: anchorMarkerScreen.y,
13061
+ x2: componentScreen.x,
13062
+ y2: componentScreen.y,
13063
+ stroke: COLORS.OFFSET_LINE,
13064
+ strokeWidth: VISUAL_CONFIG.LINE_STROKE_WIDTH,
13065
+ strokeDasharray: VISUAL_CONFIG.LINE_DASH_PATTERN
13066
+ }
13067
+ ),
13068
+ /* @__PURE__ */ jsx13(
13069
+ "circle",
13070
+ {
13071
+ cx: componentScreen.x,
13072
+ cy: componentScreen.y,
13073
+ r: VISUAL_CONFIG.COMPONENT_MARKER_RADIUS,
13074
+ fill: COLORS.COMPONENT_MARKER_FILL,
13075
+ stroke: COLORS.COMPONENT_MARKER_STROKE,
13076
+ strokeWidth: 1
13077
+ }
13078
+ ),
13079
+ shouldShowXLabel && /* @__PURE__ */ jsx13(
13080
+ "foreignObject",
13081
+ {
13082
+ x: Math.min(anchorMarkerScreen.x, componentScreen.x),
13083
+ y: anchorMarkerScreen.y + xLabelOffset,
13084
+ width: Math.abs(componentScreen.x - anchorMarkerScreen.x),
13085
+ height: 20,
13086
+ style: { overflow: "visible" },
13087
+ children: /* @__PURE__ */ jsx13("div", { style: { ...labelStyle, textAlign: "center" }, children: xLabelText })
13088
+ }
13089
+ ),
13090
+ shouldShowYLabel && /* @__PURE__ */ jsx13(
13091
+ "foreignObject",
13092
+ {
13093
+ x: componentScreen.x + yLabelOffset,
13094
+ y: Math.min(anchorMarkerScreen.y, componentScreen.y),
13095
+ width: 20,
13096
+ height: Math.abs(componentScreen.y - anchorMarkerScreen.y),
13097
+ style: { overflow: "visible" },
13098
+ children: /* @__PURE__ */ jsx13(
13099
+ "div",
13100
+ {
13101
+ style: {
13102
+ ...labelStyle,
13103
+ display: "flex",
13104
+ alignItems: "center",
13105
+ height: "100%"
13106
+ },
13107
+ children: yLabelText
13108
+ }
13109
+ )
13110
+ }
13111
+ )
13112
+ ]
13113
+ },
13114
+ `${parentGroup.pcb_group_id}-${component.pcb_component_id}`
13115
+ );
13116
+ }),
13117
+ Array.from(groupAnchorScreens.entries()).map(
13118
+ ([groupId, anchorScreen]) => /* @__PURE__ */ jsxs10("g", { children: [
13119
+ /* @__PURE__ */ jsx13(
13120
+ "line",
13121
+ {
13122
+ x1: anchorScreen.x - VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
13123
+ y1: anchorScreen.y,
13124
+ x2: anchorScreen.x + VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
13125
+ y2: anchorScreen.y,
13126
+ stroke: COLORS.OFFSET_LINE,
13127
+ strokeWidth: VISUAL_CONFIG.ANCHOR_MARKER_STROKE_WIDTH
13128
+ }
13129
+ ),
13130
+ /* @__PURE__ */ jsx13(
13131
+ "line",
13132
+ {
13133
+ x1: anchorScreen.x,
13134
+ y1: anchorScreen.y - VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
13135
+ x2: anchorScreen.x,
13136
+ y2: anchorScreen.y + VISUAL_CONFIG.ANCHOR_MARKER_SIZE,
13137
+ stroke: COLORS.OFFSET_LINE,
13138
+ strokeWidth: VISUAL_CONFIG.ANCHOR_MARKER_STROKE_WIDTH
13139
+ }
13140
+ )
13141
+ ] }, `anchor-${groupId}`)
13142
+ )
13143
+ ]
13144
+ }
13145
+ )
12885
13146
  }
12886
13147
  );
12887
13148
  };
12888
13149
 
12889
13150
  // src/components/MouseElementTracker.tsx
12890
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
13151
+ import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
12891
13152
  var getPolygonBoundingBox = (points) => {
12892
13153
  if (points.length === 0) return null;
12893
13154
  let minX = points[0].x;
@@ -12929,22 +13190,22 @@ var getPrimitivesUnderPoint = (primitives, rwPoint, transform) => {
12929
13190
  for (const primitive of primitives) {
12930
13191
  if (!primitive._element) continue;
12931
13192
  if ("x1" in primitive && primitive._element?.type === "pcb_trace") {
12932
- const distance4 = pointToSegmentDistance(
13193
+ const distance5 = pointToSegmentDistance(
12933
13194
  { x: rwPoint.x, y: rwPoint.y },
12934
13195
  { x: primitive.x1, y: primitive.y1 },
12935
13196
  { x: primitive.x2, y: primitive.y2 }
12936
13197
  );
12937
13198
  const lineWidth = primitive.width || 0.5;
12938
13199
  const detectionThreshold = Math.max(lineWidth * 25, 2) / transform.a;
12939
- if (distance4 < detectionThreshold) {
13200
+ if (distance5 < detectionThreshold) {
12940
13201
  newMousedPrimitives.push(primitive);
12941
13202
  }
12942
13203
  continue;
12943
13204
  }
12944
13205
  if (primitive.pcb_drawing_type === "polygon") {
12945
13206
  const points = primitive.points.map((point) => ({
12946
- x: distance3.parse(point.x),
12947
- y: distance3.parse(point.y)
13207
+ x: distance4.parse(point.x),
13208
+ y: distance4.parse(point.y)
12948
13209
  }));
12949
13210
  const boundingBox = getPolygonBoundingBox(points);
12950
13211
  if (!boundingBox) continue;
@@ -12958,8 +13219,8 @@ var getPrimitivesUnderPoint = (primitives, rwPoint, transform) => {
12958
13219
  }
12959
13220
  if (primitive.pcb_drawing_type === "polygon_with_arcs") {
12960
13221
  const points = primitive.brep_shape.outer_ring.vertices.map((v) => ({
12961
- x: distance3.parse(v.x),
12962
- y: distance3.parse(v.y)
13222
+ x: distance4.parse(v.x),
13223
+ y: distance4.parse(v.y)
12963
13224
  }));
12964
13225
  const boundingBox = getPolygonBoundingBox(points);
12965
13226
  if (!boundingBox) continue;
@@ -13033,7 +13294,7 @@ var MouseElementTracker = ({
13033
13294
  h = "h" in primitive ? primitive.h : "r" in primitive ? primitive.r * 2 : "rX" in primitive && "rY" in primitive ? primitive.rY * 2 : 0;
13034
13295
  }
13035
13296
  if (!basePoint) continue;
13036
- const screenPos = applyToPoint13(transform, basePoint);
13297
+ const screenPos = applyToPoint14(transform, basePoint);
13037
13298
  const screenSize = {
13038
13299
  w: w * transform.a,
13039
13300
  h: h * transform.a
@@ -13058,7 +13319,7 @@ var MouseElementTracker = ({
13058
13319
  }, [mousedPrimitives, transform]);
13059
13320
  const handleInteraction = (x, y, transform2, primitives2) => {
13060
13321
  setMousePos({ x, y });
13061
- const rwPoint = applyToPoint13(inverse5(transform2), { x, y });
13322
+ const rwPoint = applyToPoint14(inverse5(transform2), { x, y });
13062
13323
  const newMousedPrimitives = getPrimitivesUnderPoint(
13063
13324
  primitives2,
13064
13325
  rwPoint,
@@ -13073,7 +13334,7 @@ var MouseElementTracker = ({
13073
13334
  setMousedPrimitives(newMousedPrimitives);
13074
13335
  onMouseHoverOverPrimitives(newMousedPrimitives);
13075
13336
  };
13076
- return /* @__PURE__ */ jsxs10(
13337
+ return /* @__PURE__ */ jsxs11(
13077
13338
  "div",
13078
13339
  {
13079
13340
  ref: containerRef,
@@ -13097,7 +13358,7 @@ var MouseElementTracker = ({
13097
13358
  },
13098
13359
  children: [
13099
13360
  children,
13100
- /* @__PURE__ */ jsx13(
13361
+ /* @__PURE__ */ jsx14(
13101
13362
  ElementOverlayBox,
13102
13363
  {
13103
13364
  elements,
@@ -13105,26 +13366,38 @@ var MouseElementTracker = ({
13105
13366
  highlightedPrimitives
13106
13367
  }
13107
13368
  ),
13108
- transform && /* @__PURE__ */ jsx13(
13109
- GroupAnchorOffsetOverlay,
13110
- {
13111
- elements,
13112
- highlightedPrimitives,
13113
- transform,
13114
- containerWidth: width,
13115
- containerHeight: height
13116
- }
13117
- )
13369
+ transform && /* @__PURE__ */ jsxs11(Fragment5, { children: [
13370
+ /* @__PURE__ */ jsx14(
13371
+ BoardAnchorOffsetOverlay,
13372
+ {
13373
+ elements,
13374
+ highlightedPrimitives,
13375
+ transform,
13376
+ containerWidth: width,
13377
+ containerHeight: height
13378
+ }
13379
+ ),
13380
+ /* @__PURE__ */ jsx14(
13381
+ GroupAnchorOffsetOverlay,
13382
+ {
13383
+ elements,
13384
+ highlightedPrimitives,
13385
+ transform,
13386
+ containerWidth: width,
13387
+ containerHeight: height
13388
+ }
13389
+ )
13390
+ ] })
13118
13391
  ]
13119
13392
  }
13120
13393
  );
13121
13394
  };
13122
13395
 
13123
13396
  // src/components/PcbGroupOverlay.tsx
13124
- import { applyToPoint as applyToPoint14 } from "transformation-matrix";
13397
+ import { applyToPoint as applyToPoint15 } from "transformation-matrix";
13125
13398
  import { identity as identity8 } from "transformation-matrix";
13126
13399
  import { useRef as useRef9, useEffect as useEffect12 } from "react";
13127
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
13400
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
13128
13401
  var GROUP_COLORS = [
13129
13402
  "rgb(255, 100, 100)",
13130
13403
  "rgb(100, 255, 100)",
@@ -13140,16 +13413,20 @@ var GROUP_COLORS = [
13140
13413
  var PcbGroupOverlay = ({
13141
13414
  children,
13142
13415
  transform = identity8(),
13143
- elements = []
13416
+ elements = [],
13417
+ hoveredComponentIds = []
13144
13418
  }) => {
13145
13419
  const [containerRef, { width, height }] = useMeasure_default();
13146
13420
  const canvasRef = useRef9(null);
13147
- const { is_showing_pcb_groups, pcb_group_view_mode } = useGlobalStore(
13148
- (s) => ({
13149
- is_showing_pcb_groups: s.is_showing_pcb_groups,
13150
- pcb_group_view_mode: s.pcb_group_view_mode
13151
- })
13152
- );
13421
+ const {
13422
+ is_showing_pcb_groups,
13423
+ pcb_group_view_mode,
13424
+ is_showing_group_anchor_offsets
13425
+ } = useGlobalStore((s) => ({
13426
+ is_showing_pcb_groups: s.is_showing_pcb_groups,
13427
+ pcb_group_view_mode: s.pcb_group_view_mode,
13428
+ is_showing_group_anchor_offsets: s.is_showing_group_anchor_offsets
13429
+ }));
13153
13430
  useEffect12(() => {
13154
13431
  const canvas = canvasRef.current;
13155
13432
  if (!canvas || !width || !height) return;
@@ -13208,6 +13485,14 @@ var PcbGroupOverlay = ({
13208
13485
  }
13209
13486
  return 1 + getGroupDepthLevel(groupWithParent.parent_source_group_id);
13210
13487
  };
13488
+ const hoveredGroupIds = /* @__PURE__ */ new Set();
13489
+ if (hoveredComponentIds.length > 0) {
13490
+ for (const comp of pcbComponents) {
13491
+ if (!hoveredComponentIds.includes(comp.pcb_component_id)) continue;
13492
+ const targetGroupId = comp.positioned_relative_to_pcb_group_id ?? comp.pcb_group_id;
13493
+ if (targetGroupId) hoveredGroupIds.add(targetGroupId);
13494
+ }
13495
+ }
13211
13496
  visiblePcbGroups.forEach((group, groupIndex) => {
13212
13497
  let groupComponents = pcbComponents.filter(
13213
13498
  (comp) => comp.pcb_group_id === group.pcb_group_id
@@ -13253,10 +13538,10 @@ var PcbGroupOverlay = ({
13253
13538
  maxX += totalPadding;
13254
13539
  minY -= totalPadding;
13255
13540
  maxY += totalPadding;
13256
- const topLeft = applyToPoint14(transform, { x: minX, y: maxY });
13257
- const topRight = applyToPoint14(transform, { x: maxX, y: maxY });
13258
- const bottomLeft = applyToPoint14(transform, { x: minX, y: minY });
13259
- const bottomRight = applyToPoint14(transform, { x: maxX, y: minY });
13541
+ const topLeft = applyToPoint15(transform, { x: minX, y: maxY });
13542
+ const topRight = applyToPoint15(transform, { x: maxX, y: maxY });
13543
+ const bottomLeft = applyToPoint15(transform, { x: minX, y: minY });
13544
+ const bottomRight = applyToPoint15(transform, { x: maxX, y: minY });
13260
13545
  const groupColor = GROUP_COLORS[groupIndex % GROUP_COLORS.length];
13261
13546
  ctx.strokeStyle = groupColor;
13262
13547
  ctx.lineWidth = 2;
@@ -13300,33 +13585,13 @@ var PcbGroupOverlay = ({
13300
13585
  ctx.textAlign = "left";
13301
13586
  ctx.textBaseline = "middle";
13302
13587
  ctx.fillText(labelText, labelX + labelPadding, labelY - labelHeight / 2);
13303
- if (group.anchor_position) {
13304
- const anchor = group.anchor_position;
13305
- const groupLeft = minX;
13306
- const groupRight = maxX;
13307
- const groupTop = maxY;
13308
- const groupBottom = minY;
13309
- let edgePoint = { x: anchor.x, y: anchor.y };
13310
- const distToLeft = Math.abs(anchor.x - groupLeft);
13311
- const distToRight = Math.abs(anchor.x - groupRight);
13312
- const distToTop = Math.abs(anchor.y - groupTop);
13313
- const distToBottom = Math.abs(anchor.y - groupBottom);
13314
- const minDist = Math.min(
13315
- distToLeft,
13316
- distToRight,
13317
- distToTop,
13318
- distToBottom
13319
- );
13320
- if (minDist === distToLeft) {
13321
- edgePoint = { x: groupLeft, y: anchor.y };
13322
- } else if (minDist === distToRight) {
13323
- edgePoint = { x: groupRight, y: anchor.y };
13324
- } else if (minDist === distToTop) {
13325
- edgePoint = { x: anchor.x, y: groupTop };
13326
- } else {
13327
- edgePoint = { x: anchor.x, y: groupBottom };
13328
- }
13329
- const anchorScreenPos = applyToPoint14(transform, edgePoint);
13588
+ const shouldShowAnchorMarker = is_showing_group_anchor_offsets && hoveredGroupIds.has(group.pcb_group_id) && Boolean(group.anchor_position);
13589
+ if (shouldShowAnchorMarker && group.anchor_position) {
13590
+ const anchorPositionValue = Array.isArray(group.anchor_position) ? {
13591
+ x: group.anchor_position[0] ?? 0,
13592
+ y: group.anchor_position[1] ?? 0
13593
+ } : { x: group.anchor_position.x, y: group.anchor_position.y };
13594
+ const anchorScreenPos = applyToPoint15(transform, anchorPositionValue);
13330
13595
  ctx.strokeStyle = "white";
13331
13596
  ctx.lineWidth = 1.5;
13332
13597
  ctx.setLineDash([]);
@@ -13347,16 +13612,18 @@ var PcbGroupOverlay = ({
13347
13612
  width,
13348
13613
  height,
13349
13614
  is_showing_pcb_groups,
13350
- pcb_group_view_mode
13615
+ pcb_group_view_mode,
13616
+ is_showing_group_anchor_offsets,
13617
+ hoveredComponentIds
13351
13618
  ]);
13352
- return /* @__PURE__ */ jsxs11(
13619
+ return /* @__PURE__ */ jsxs12(
13353
13620
  "div",
13354
13621
  {
13355
13622
  ref: containerRef,
13356
13623
  style: { position: "relative", width: "100%", height: "100%" },
13357
13624
  children: [
13358
13625
  children,
13359
- /* @__PURE__ */ jsx14(
13626
+ /* @__PURE__ */ jsx15(
13360
13627
  "canvas",
13361
13628
  {
13362
13629
  ref: canvasRef,
@@ -13376,9 +13643,9 @@ var PcbGroupOverlay = ({
13376
13643
  };
13377
13644
 
13378
13645
  // src/components/RatsNestOverlay.tsx
13379
- import { applyToPoint as applyToPoint15, identity as identity9 } from "transformation-matrix";
13646
+ import { applyToPoint as applyToPoint16, identity as identity9 } from "transformation-matrix";
13380
13647
  import { useMemo as useMemo6 } from "react";
13381
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
13648
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
13382
13649
  var RatsNestOverlay = ({ transform, soup, children }) => {
13383
13650
  const isShowingRatsNest = useGlobalStore((s) => s.is_showing_rats_nest);
13384
13651
  const { netMap, idToNetMap } = useMemo6(
@@ -13401,11 +13668,11 @@ var RatsNestOverlay = ({ transform, soup, children }) => {
13401
13668
  connectedIds.forEach((id) => {
13402
13669
  const pos = getElementPosition(id);
13403
13670
  if (pos) {
13404
- const distance4 = Math.sqrt(
13671
+ const distance5 = Math.sqrt(
13405
13672
  (sourcePoint.x - pos.x) ** 2 + (sourcePoint.y - pos.y) ** 2
13406
13673
  );
13407
- if (distance4 < minDistance && distance4 > 0) {
13408
- minDistance = distance4;
13674
+ if (distance5 < minDistance && distance5 > 0) {
13675
+ minDistance = distance5;
13409
13676
  nearestPoint = pos;
13410
13677
  }
13411
13678
  }
@@ -13441,9 +13708,9 @@ var RatsNestOverlay = ({ transform, soup, children }) => {
13441
13708
  }, [soup, netMap, idToNetMap, isShowingRatsNest]);
13442
13709
  if (!soup || !isShowingRatsNest) return children;
13443
13710
  if (!transform) transform = identity9();
13444
- return /* @__PURE__ */ jsxs12("div", { style: { position: "relative" }, children: [
13711
+ return /* @__PURE__ */ jsxs13("div", { style: { position: "relative" }, children: [
13445
13712
  children,
13446
- /* @__PURE__ */ jsx15(
13713
+ /* @__PURE__ */ jsx16(
13447
13714
  "svg",
13448
13715
  {
13449
13716
  style: {
@@ -13457,9 +13724,9 @@ var RatsNestOverlay = ({ transform, soup, children }) => {
13457
13724
  zIndex: zIndexMap.ratsNestOverlay
13458
13725
  },
13459
13726
  children: ratsNestLines.map(({ key, startPoint, endPoint, isInNet }) => {
13460
- const transformedStart = applyToPoint15(transform, startPoint);
13461
- const transformedEnd = applyToPoint15(transform, endPoint);
13462
- return /* @__PURE__ */ jsx15(
13727
+ const transformedStart = applyToPoint16(transform, startPoint);
13728
+ const transformedEnd = applyToPoint16(transform, endPoint);
13729
+ return /* @__PURE__ */ jsx16(
13463
13730
  "line",
13464
13731
  {
13465
13732
  x1: transformedStart.x,
@@ -13485,7 +13752,7 @@ import { css as css3 } from "@emotion/css";
13485
13752
  // package.json
13486
13753
  var package_default = {
13487
13754
  name: "@tscircuit/pcb-viewer",
13488
- version: "1.11.279",
13755
+ version: "1.11.281",
13489
13756
  main: "dist/index.js",
13490
13757
  type: "module",
13491
13758
  repository: "tscircuit/pcb-viewer",
@@ -13538,7 +13805,7 @@ var package_default = {
13538
13805
  "@tscircuit/alphabet": "^0.0.8",
13539
13806
  "@tscircuit/math-utils": "^0.0.29",
13540
13807
  "@vitejs/plugin-react": "^5.0.2",
13541
- "circuit-json": "^0.0.321",
13808
+ "circuit-json": "^0.0.333",
13542
13809
  "circuit-to-svg": "^0.0.271",
13543
13810
  color: "^4.2.3",
13544
13811
  "react-supergrid": "^1.0.10",
@@ -13591,9 +13858,9 @@ var useIsSmallScreen = () => {
13591
13858
  };
13592
13859
 
13593
13860
  // src/components/ToolbarOverlay.tsx
13594
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
13861
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
13595
13862
  var LayerButton = ({ name, selected, onClick }) => {
13596
- return /* @__PURE__ */ jsxs13(
13863
+ return /* @__PURE__ */ jsxs14(
13597
13864
  "div",
13598
13865
  {
13599
13866
  className: css3`
@@ -13609,8 +13876,8 @@ var LayerButton = ({ name, selected, onClick }) => {
13609
13876
  `,
13610
13877
  onClick,
13611
13878
  children: [
13612
- /* @__PURE__ */ jsx16("span", { style: { marginRight: 2, opacity: selected ? 1 : 0 }, children: "\u2022" }),
13613
- /* @__PURE__ */ jsx16(
13879
+ /* @__PURE__ */ jsx17("span", { style: { marginRight: 2, opacity: selected ? 1 : 0 }, children: "\u2022" }),
13880
+ /* @__PURE__ */ jsx17(
13614
13881
  "span",
13615
13882
  {
13616
13883
  style: {
@@ -13630,7 +13897,7 @@ var ToolbarButton = ({
13630
13897
  isSmallScreen,
13631
13898
  onClick,
13632
13899
  ...props
13633
- }) => /* @__PURE__ */ jsx16(
13900
+ }) => /* @__PURE__ */ jsx17(
13634
13901
  "div",
13635
13902
  {
13636
13903
  ...props,
@@ -13667,7 +13934,7 @@ var CheckboxMenuItem = ({
13667
13934
  checked,
13668
13935
  onClick
13669
13936
  }) => {
13670
- return /* @__PURE__ */ jsxs13(
13937
+ return /* @__PURE__ */ jsxs14(
13671
13938
  "div",
13672
13939
  {
13673
13940
  className: css3`
@@ -13694,15 +13961,15 @@ var CheckboxMenuItem = ({
13694
13961
  onClick();
13695
13962
  },
13696
13963
  children: [
13697
- /* @__PURE__ */ jsx16("input", { type: "checkbox", checked, onChange: () => {
13964
+ /* @__PURE__ */ jsx17("input", { type: "checkbox", checked, onChange: () => {
13698
13965
  }, readOnly: true }),
13699
- /* @__PURE__ */ jsx16("span", { style: { color: "#eee" }, children: label })
13966
+ /* @__PURE__ */ jsx17("span", { style: { color: "#eee" }, children: label })
13700
13967
  ]
13701
13968
  }
13702
13969
  );
13703
13970
  };
13704
13971
  var RadioMenuItem = ({ label, checked, onClick }) => {
13705
- return /* @__PURE__ */ jsxs13(
13972
+ return /* @__PURE__ */ jsxs14(
13706
13973
  "div",
13707
13974
  {
13708
13975
  className: css3`
@@ -13729,9 +13996,9 @@ var RadioMenuItem = ({ label, checked, onClick }) => {
13729
13996
  onClick();
13730
13997
  },
13731
13998
  children: [
13732
- /* @__PURE__ */ jsx16("input", { type: "radio", checked, onChange: () => {
13999
+ /* @__PURE__ */ jsx17("input", { type: "radio", checked, onChange: () => {
13733
14000
  }, readOnly: true }),
13734
- /* @__PURE__ */ jsx16("span", { style: { color: "#eee" }, children: label })
14001
+ /* @__PURE__ */ jsx17("span", { style: { color: "#eee" }, children: label })
13735
14002
  ]
13736
14003
  }
13737
14004
  );
@@ -13883,7 +14150,7 @@ var ToolbarOverlay = ({ children, elements }) => {
13883
14150
  setErrorsOpen(false);
13884
14151
  }
13885
14152
  }, [isViewMenuOpen]);
13886
- return /* @__PURE__ */ jsxs13(
14153
+ return /* @__PURE__ */ jsxs14(
13887
14154
  "div",
13888
14155
  {
13889
14156
  style: { position: "relative", zIndex: "999 !important" },
@@ -13891,7 +14158,7 @@ var ToolbarOverlay = ({ children, elements }) => {
13891
14158
  onMouseLeave: handleMouseLeave,
13892
14159
  children: [
13893
14160
  children,
13894
- /* @__PURE__ */ jsxs13(
14161
+ /* @__PURE__ */ jsxs14(
13895
14162
  "div",
13896
14163
  {
13897
14164
  style: {
@@ -13912,7 +14179,7 @@ var ToolbarOverlay = ({ children, elements }) => {
13912
14179
  ]
13913
14180
  }
13914
14181
  ),
13915
- /* @__PURE__ */ jsxs13(
14182
+ /* @__PURE__ */ jsxs14(
13916
14183
  "div",
13917
14184
  {
13918
14185
  "data-toolbar-overlay": true,
@@ -13935,7 +14202,7 @@ var ToolbarOverlay = ({ children, elements }) => {
13935
14202
  fontFamily: "sans-serif"
13936
14203
  },
13937
14204
  children: [
13938
- /* @__PURE__ */ jsxs13(
14205
+ /* @__PURE__ */ jsxs14(
13939
14206
  ToolbarButton,
13940
14207
  {
13941
14208
  isSmallScreen,
@@ -13946,10 +14213,10 @@ var ToolbarOverlay = ({ children, elements }) => {
13946
14213
  }
13947
14214
  },
13948
14215
  children: [
13949
- /* @__PURE__ */ jsxs13("div", { children: [
14216
+ /* @__PURE__ */ jsxs14("div", { children: [
13950
14217
  "layer:",
13951
14218
  " ",
13952
- /* @__PURE__ */ jsx16(
14219
+ /* @__PURE__ */ jsx17(
13953
14220
  "span",
13954
14221
  {
13955
14222
  style: {
@@ -13961,7 +14228,7 @@ var ToolbarOverlay = ({ children, elements }) => {
13961
14228
  }
13962
14229
  )
13963
14230
  ] }),
13964
- isLayerMenuOpen && /* @__PURE__ */ jsx16("div", { style: { marginTop: 4, minWidth: 120 }, children: processedLayers.map((layer) => /* @__PURE__ */ jsx16(
14231
+ isLayerMenuOpen && /* @__PURE__ */ jsx17("div", { style: { marginTop: 4, minWidth: 120 }, children: processedLayers.map((layer) => /* @__PURE__ */ jsx17(
13965
14232
  LayerButton,
13966
14233
  {
13967
14234
  name: layer,
@@ -13975,7 +14242,7 @@ var ToolbarOverlay = ({ children, elements }) => {
13975
14242
  ]
13976
14243
  }
13977
14244
  ),
13978
- /* @__PURE__ */ jsx16(
14245
+ /* @__PURE__ */ jsx17(
13979
14246
  ToolbarButton,
13980
14247
  {
13981
14248
  isSmallScreen,
@@ -13984,13 +14251,13 @@ var ToolbarOverlay = ({ children, elements }) => {
13984
14251
  ...errorCount > 0 ? { color: "red" } : {}
13985
14252
  },
13986
14253
  onClick: handleErrorsToggle,
13987
- children: /* @__PURE__ */ jsxs13("div", { children: [
14254
+ children: /* @__PURE__ */ jsxs14("div", { children: [
13988
14255
  errorCount,
13989
14256
  " errors"
13990
14257
  ] })
13991
14258
  }
13992
14259
  ),
13993
- isErrorsOpen && errorCount > 0 && /* @__PURE__ */ jsx16(
14260
+ isErrorsOpen && errorCount > 0 && /* @__PURE__ */ jsx17(
13994
14261
  "div",
13995
14262
  {
13996
14263
  style: {
@@ -14010,14 +14277,14 @@ var ToolbarOverlay = ({ children, elements }) => {
14010
14277
  },
14011
14278
  children: errorElements.map((e, i) => {
14012
14279
  const errorId = e.pcb_trace_error_id || `error_${i}_${e.error_type}_${e.message?.slice(0, 20)}`;
14013
- return /* @__PURE__ */ jsxs13(
14280
+ return /* @__PURE__ */ jsxs14(
14014
14281
  "div",
14015
14282
  {
14016
14283
  style: {
14017
14284
  borderBottom: i < errorElements.length - 1 ? "1px solid #444" : "none"
14018
14285
  },
14019
14286
  children: [
14020
- /* @__PURE__ */ jsxs13(
14287
+ /* @__PURE__ */ jsxs14(
14021
14288
  "div",
14022
14289
  {
14023
14290
  style: {
@@ -14068,7 +14335,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14068
14335
  }
14069
14336
  },
14070
14337
  children: [
14071
- /* @__PURE__ */ jsx16(
14338
+ /* @__PURE__ */ jsx17(
14072
14339
  "div",
14073
14340
  {
14074
14341
  style: {
@@ -14082,7 +14349,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14082
14349
  children: e.error_type
14083
14350
  }
14084
14351
  ),
14085
- /* @__PURE__ */ jsx16(
14352
+ /* @__PURE__ */ jsx17(
14086
14353
  "div",
14087
14354
  {
14088
14355
  style: {
@@ -14097,7 +14364,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14097
14364
  children: e.message
14098
14365
  }
14099
14366
  ),
14100
- /* @__PURE__ */ jsx16(
14367
+ /* @__PURE__ */ jsx17(
14101
14368
  "div",
14102
14369
  {
14103
14370
  ref: (el) => {
@@ -14117,7 +14384,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14117
14384
  ]
14118
14385
  }
14119
14386
  ),
14120
- /* @__PURE__ */ jsx16(
14387
+ /* @__PURE__ */ jsx17(
14121
14388
  "div",
14122
14389
  {
14123
14390
  ref: (el) => {
@@ -14130,7 +14397,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14130
14397
  backgroundColor: "#1a1a1a",
14131
14398
  borderTop: "1px solid #444"
14132
14399
  },
14133
- children: /* @__PURE__ */ jsx16(
14400
+ children: /* @__PURE__ */ jsx17(
14134
14401
  "div",
14135
14402
  {
14136
14403
  style: {
@@ -14153,58 +14420,58 @@ var ToolbarOverlay = ({ children, elements }) => {
14153
14420
  })
14154
14421
  }
14155
14422
  ),
14156
- /* @__PURE__ */ jsx16(
14423
+ /* @__PURE__ */ jsx17(
14157
14424
  ToolbarButton,
14158
14425
  {
14159
14426
  isSmallScreen,
14160
14427
  style: {},
14161
14428
  onClick: handleEditTraceToggle,
14162
- children: /* @__PURE__ */ jsxs13("div", { children: [
14429
+ children: /* @__PURE__ */ jsxs14("div", { children: [
14163
14430
  editModes.in_draw_trace_mode ? "\u2716 " : "",
14164
14431
  "Edit Traces"
14165
14432
  ] })
14166
14433
  }
14167
14434
  ),
14168
- /* @__PURE__ */ jsx16(
14435
+ /* @__PURE__ */ jsx17(
14169
14436
  ToolbarButton,
14170
14437
  {
14171
14438
  isSmallScreen,
14172
14439
  style: {},
14173
14440
  onClick: handleMoveComponentToggle,
14174
- children: /* @__PURE__ */ jsxs13("div", { children: [
14441
+ children: /* @__PURE__ */ jsxs14("div", { children: [
14175
14442
  editModes.in_move_footprint_mode ? "\u2716 " : "",
14176
14443
  "Move Components"
14177
14444
  ] })
14178
14445
  }
14179
14446
  ),
14180
- /* @__PURE__ */ jsx16(
14447
+ /* @__PURE__ */ jsx17(
14181
14448
  ToolbarButton,
14182
14449
  {
14183
14450
  isSmallScreen,
14184
14451
  style: {},
14185
14452
  onClick: handleRatsNestToggle,
14186
- children: /* @__PURE__ */ jsxs13("div", { children: [
14453
+ children: /* @__PURE__ */ jsxs14("div", { children: [
14187
14454
  viewSettings.is_showing_rats_nest ? "\u2716 " : "",
14188
14455
  "Rats Nest"
14189
14456
  ] })
14190
14457
  }
14191
14458
  ),
14192
- /* @__PURE__ */ jsx16(
14459
+ /* @__PURE__ */ jsx17(
14193
14460
  ToolbarButton,
14194
14461
  {
14195
14462
  isSmallScreen,
14196
14463
  style: measureToolArmed ? { backgroundColor: "#444" } : {},
14197
14464
  onClick: handleMeasureToolClick,
14198
- children: /* @__PURE__ */ jsx16("div", { children: "\u{1F4CF}" })
14465
+ children: /* @__PURE__ */ jsx17("div", { children: "\u{1F4CF}" })
14199
14466
  }
14200
14467
  ),
14201
- /* @__PURE__ */ jsx16(
14468
+ /* @__PURE__ */ jsx17(
14202
14469
  ToolbarButton,
14203
14470
  {
14204
14471
  isSmallScreen,
14205
14472
  onClick: handleViewMenuToggle,
14206
- children: /* @__PURE__ */ jsxs13("div", { children: [
14207
- /* @__PURE__ */ jsxs13(
14473
+ children: /* @__PURE__ */ jsxs14("div", { children: [
14474
+ /* @__PURE__ */ jsxs14(
14208
14475
  "div",
14209
14476
  {
14210
14477
  style: {
@@ -14214,7 +14481,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14214
14481
  },
14215
14482
  children: [
14216
14483
  "View",
14217
- /* @__PURE__ */ jsx16(
14484
+ /* @__PURE__ */ jsx17(
14218
14485
  "span",
14219
14486
  {
14220
14487
  style: {
@@ -14229,8 +14496,8 @@ var ToolbarOverlay = ({ children, elements }) => {
14229
14496
  ]
14230
14497
  }
14231
14498
  ),
14232
- isViewMenuOpen && /* @__PURE__ */ jsxs13("div", { style: { marginTop: 4, minWidth: 120 }, children: [
14233
- /* @__PURE__ */ jsx16(
14499
+ isViewMenuOpen && /* @__PURE__ */ jsxs14("div", { style: { marginTop: 4, minWidth: 120 }, children: [
14500
+ /* @__PURE__ */ jsx17(
14234
14501
  CheckboxMenuItem,
14235
14502
  {
14236
14503
  label: "Show All Trace Lengths",
@@ -14242,7 +14509,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14242
14509
  }
14243
14510
  }
14244
14511
  ),
14245
- /* @__PURE__ */ jsx16(
14512
+ /* @__PURE__ */ jsx17(
14246
14513
  CheckboxMenuItem,
14247
14514
  {
14248
14515
  label: "Show Autorouting Animation",
@@ -14254,7 +14521,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14254
14521
  }
14255
14522
  }
14256
14523
  ),
14257
- /* @__PURE__ */ jsx16(
14524
+ /* @__PURE__ */ jsx17(
14258
14525
  CheckboxMenuItem,
14259
14526
  {
14260
14527
  label: "Show DRC Errors",
@@ -14264,7 +14531,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14264
14531
  }
14265
14532
  }
14266
14533
  ),
14267
- /* @__PURE__ */ jsx16(
14534
+ /* @__PURE__ */ jsx17(
14268
14535
  CheckboxMenuItem,
14269
14536
  {
14270
14537
  label: "Show Copper Pours",
@@ -14276,7 +14543,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14276
14543
  }
14277
14544
  }
14278
14545
  ),
14279
- /* @__PURE__ */ jsx16(
14546
+ /* @__PURE__ */ jsx17(
14280
14547
  CheckboxMenuItem,
14281
14548
  {
14282
14549
  label: "Show Solder Mask",
@@ -14286,7 +14553,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14286
14553
  }
14287
14554
  }
14288
14555
  ),
14289
- /* @__PURE__ */ jsx16(
14556
+ /* @__PURE__ */ jsx17(
14290
14557
  CheckboxMenuItem,
14291
14558
  {
14292
14559
  label: "Show Group Anchor Offsets",
@@ -14298,7 +14565,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14298
14565
  }
14299
14566
  }
14300
14567
  ),
14301
- /* @__PURE__ */ jsx16(
14568
+ /* @__PURE__ */ jsx17(
14302
14569
  CheckboxMenuItem,
14303
14570
  {
14304
14571
  label: "Show PCB Groups",
@@ -14308,8 +14575,8 @@ var ToolbarOverlay = ({ children, elements }) => {
14308
14575
  }
14309
14576
  }
14310
14577
  ),
14311
- viewSettings.is_showing_pcb_groups && /* @__PURE__ */ jsxs13("div", { style: { marginLeft: 16 }, children: [
14312
- /* @__PURE__ */ jsx16(
14578
+ viewSettings.is_showing_pcb_groups && /* @__PURE__ */ jsxs14("div", { style: { marginLeft: 16 }, children: [
14579
+ /* @__PURE__ */ jsx17(
14313
14580
  RadioMenuItem,
14314
14581
  {
14315
14582
  label: "Show All Groups",
@@ -14319,7 +14586,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14319
14586
  }
14320
14587
  }
14321
14588
  ),
14322
- /* @__PURE__ */ jsx16(
14589
+ /* @__PURE__ */ jsx17(
14323
14590
  RadioMenuItem,
14324
14591
  {
14325
14592
  label: "Show Named Groups",
@@ -14343,7 +14610,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14343
14610
  };
14344
14611
 
14345
14612
  // src/components/CanvasElementsRenderer.tsx
14346
- import { jsx as jsx17 } from "react/jsx-runtime";
14613
+ import { jsx as jsx18 } from "react/jsx-runtime";
14347
14614
  var CanvasElementsRenderer = (props) => {
14348
14615
  const { transform, elements } = props;
14349
14616
  const hoveredErrorId = useGlobalStore((state) => state.hovered_error_id);
@@ -14367,6 +14634,7 @@ var CanvasElementsRenderer = (props) => {
14367
14634
  drawingObjectIdsWithMouseOver: /* @__PURE__ */ new Set(),
14368
14635
  primitiveIdsInMousedOverNet: []
14369
14636
  });
14637
+ const [hoveredComponentIds, setHoveredComponentIds] = useState10([]);
14370
14638
  const errorRelatedIds = useMemo7(() => {
14371
14639
  if (!hoveredErrorId) return [];
14372
14640
  const errorElements = elements.filter(
@@ -14417,17 +14685,27 @@ var CanvasElementsRenderer = (props) => {
14417
14685
  drawingObjectIdsWithMouseOver,
14418
14686
  primitiveIdsInMousedOverNet
14419
14687
  });
14688
+ const componentIds = primitivesHoveredOver.map((primitive) => {
14689
+ if (primitive._parent_pcb_component?.type === "pcb_component" && primitive._parent_pcb_component.pcb_component_id) {
14690
+ return primitive._parent_pcb_component.pcb_component_id;
14691
+ }
14692
+ if (primitive._element?.type === "pcb_component" && primitive._element.pcb_component_id) {
14693
+ return primitive._element.pcb_component_id;
14694
+ }
14695
+ return null;
14696
+ }).filter((id) => Boolean(id));
14697
+ setHoveredComponentIds(Array.from(new Set(componentIds)));
14420
14698
  },
14421
14699
  [connectivityMap]
14422
14700
  );
14423
- return /* @__PURE__ */ jsx17(
14701
+ return /* @__PURE__ */ jsx18(
14424
14702
  MouseElementTracker,
14425
14703
  {
14426
14704
  elements: elementsToRender,
14427
14705
  transform,
14428
14706
  primitives: primitivesWithoutInteractionMetadata,
14429
14707
  onMouseHoverOverPrimitives: onMouseOverPrimitives,
14430
- children: /* @__PURE__ */ jsx17(
14708
+ children: /* @__PURE__ */ jsx18(
14431
14709
  EditPlacementOverlay,
14432
14710
  {
14433
14711
  disabled: !props.allowEditing,
@@ -14436,7 +14714,7 @@ var CanvasElementsRenderer = (props) => {
14436
14714
  cancelPanDrag: props.cancelPanDrag,
14437
14715
  onCreateEditEvent: props.onCreateEditEvent,
14438
14716
  onModifyEditEvent: props.onModifyEditEvent,
14439
- children: /* @__PURE__ */ jsx17(
14717
+ children: /* @__PURE__ */ jsx18(
14440
14718
  EditTraceHintOverlay,
14441
14719
  {
14442
14720
  disabled: !props.allowEditing,
@@ -14445,36 +14723,44 @@ var CanvasElementsRenderer = (props) => {
14445
14723
  cancelPanDrag: props.cancelPanDrag,
14446
14724
  onCreateEditEvent: props.onCreateEditEvent,
14447
14725
  onModifyEditEvent: props.onModifyEditEvent,
14448
- children: /* @__PURE__ */ jsx17(
14726
+ children: /* @__PURE__ */ jsx18(
14449
14727
  DimensionOverlay,
14450
14728
  {
14451
14729
  transform,
14452
14730
  focusOnHover: props.focusOnHover,
14453
14731
  primitives: primitivesWithoutInteractionMetadata,
14454
- children: /* @__PURE__ */ jsx17(ToolbarOverlay, { elements, children: /* @__PURE__ */ jsx17(ErrorOverlay, { transform, elements, children: /* @__PURE__ */ jsx17(RatsNestOverlay, { transform, soup: elements, children: /* @__PURE__ */ jsx17(PcbGroupOverlay, { transform, elements, children: /* @__PURE__ */ jsx17(
14455
- DebugGraphicsOverlay,
14732
+ children: /* @__PURE__ */ jsx18(ToolbarOverlay, { elements, children: /* @__PURE__ */ jsx18(ErrorOverlay, { transform, elements, children: /* @__PURE__ */ jsx18(RatsNestOverlay, { transform, soup: elements, children: /* @__PURE__ */ jsx18(
14733
+ PcbGroupOverlay,
14456
14734
  {
14457
14735
  transform,
14458
- debugGraphics: props.debugGraphics,
14459
- children: /* @__PURE__ */ jsx17(
14460
- WarningGraphicsOverlay,
14736
+ elements,
14737
+ hoveredComponentIds,
14738
+ children: /* @__PURE__ */ jsx18(
14739
+ DebugGraphicsOverlay,
14461
14740
  {
14462
14741
  transform,
14463
- elements,
14464
- children: /* @__PURE__ */ jsx17(
14465
- CanvasPrimitiveRenderer,
14742
+ debugGraphics: props.debugGraphics,
14743
+ children: /* @__PURE__ */ jsx18(
14744
+ WarningGraphicsOverlay,
14466
14745
  {
14467
14746
  transform,
14468
- primitives,
14469
- width: props.width,
14470
- height: props.height,
14471
- grid: props.grid
14747
+ elements,
14748
+ children: /* @__PURE__ */ jsx18(
14749
+ CanvasPrimitiveRenderer,
14750
+ {
14751
+ transform,
14752
+ primitives,
14753
+ width: props.width,
14754
+ height: props.height,
14755
+ grid: props.grid
14756
+ }
14757
+ )
14472
14758
  }
14473
14759
  )
14474
14760
  }
14475
14761
  )
14476
14762
  }
14477
- ) }) }) }) })
14763
+ ) }) }) })
14478
14764
  }
14479
14765
  )
14480
14766
  }
@@ -14528,7 +14814,7 @@ var calculateCircuitJsonKey = (circuitJson) => {
14528
14814
  };
14529
14815
 
14530
14816
  // src/PCBViewer.tsx
14531
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
14817
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
14532
14818
  var defaultTransform = compose7(translate11(400, 300), scale5(40, -40));
14533
14819
  var PCBViewer = ({
14534
14820
  circuitJson,
@@ -14622,20 +14908,20 @@ var PCBViewer = ({
14622
14908
  }),
14623
14909
  [initialState, disablePcbGroups]
14624
14910
  );
14625
- return /* @__PURE__ */ jsxs14(
14911
+ return /* @__PURE__ */ jsxs15(
14626
14912
  "div",
14627
14913
  {
14628
14914
  ref: transformRef,
14629
14915
  style: { position: "relative" },
14630
14916
  onContextMenu: (event) => event.preventDefault(),
14631
14917
  children: [
14632
- /* @__PURE__ */ jsx18("div", { ref, children: /* @__PURE__ */ jsxs14(
14918
+ /* @__PURE__ */ jsx19("div", { ref, children: /* @__PURE__ */ jsxs15(
14633
14919
  ContextProviders,
14634
14920
  {
14635
14921
  initialState: mergedInitialState,
14636
14922
  disablePcbGroups,
14637
14923
  children: [
14638
- /* @__PURE__ */ jsx18(
14924
+ /* @__PURE__ */ jsx19(
14639
14925
  CanvasElementsRenderer,
14640
14926
  {
14641
14927
  transform,
@@ -14660,11 +14946,11 @@ var PCBViewer = ({
14660
14946
  },
14661
14947
  refDimensions.width
14662
14948
  ),
14663
- /* @__PURE__ */ jsx18(ToastContainer, {})
14949
+ /* @__PURE__ */ jsx19(ToastContainer, {})
14664
14950
  ]
14665
14951
  }
14666
14952
  ) }),
14667
- clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx18(
14953
+ clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx19(
14668
14954
  "div",
14669
14955
  {
14670
14956
  onClick: () => {
@@ -14701,7 +14987,7 @@ var PCBViewer = ({
14701
14987
  justifyContent: "center",
14702
14988
  touchAction: "pan-x pan-y pinch-zoom"
14703
14989
  },
14704
- children: /* @__PURE__ */ jsx18(
14990
+ children: /* @__PURE__ */ jsx19(
14705
14991
  "div",
14706
14992
  {
14707
14993
  style: {