@tscircuit/pcb-viewer 1.11.437 → 1.11.438

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
@@ -9609,6 +9609,113 @@ var PIN1_LOCATION_PARTS = {
9609
9609
  bottomside_right: { side: "bottomside", alignment: "right" }
9610
9610
  };
9611
9611
  var PIN1_LOCATIONS = Object.keys(PIN1_LOCATION_PARTS);
9612
+ var placePolygon = (polygon2, center, degrees = 0) => {
9613
+ const { a, b, c, d, e, f } = compose2(
9614
+ translate5(center.x, center.y),
9615
+ rotate(degrees * Math.PI / 180)
9616
+ );
9617
+ return polygon2.transform(new Matrix(a, b, c, d, e, f));
9618
+ };
9619
+ var ccw = (polygon2) => polygon2.orientation() === ORIENTATION.CCW ? polygon2 : polygon2.reverse();
9620
+ var circlePolygon = (center, radius) => ccw(new Polygon$1(new Circle$1(new Point$2(center.x, center.y), radius)));
9621
+ var roundedRectangle = (center, width, height, radius = 0, degrees = 0) => {
9622
+ const x = width / 2;
9623
+ const y = height / 2;
9624
+ const r = Math.max(0, Math.min(radius, x, y));
9625
+ if (r === 0)
9626
+ return placePolygon(
9627
+ ccw(new Polygon$1(new Box(-x, -y, x, y))),
9628
+ center,
9629
+ degrees
9630
+ );
9631
+ const arcs = [
9632
+ new Arc(new Point$2(x - r, -y + r), r, -Math.PI / 2, 0, true),
9633
+ new Arc(new Point$2(x - r, y - r), r, 0, Math.PI / 2, true),
9634
+ new Arc(new Point$2(-x + r, y - r), r, Math.PI / 2, Math.PI, true),
9635
+ new Arc(new Point$2(-x + r, -y + r), r, Math.PI, Math.PI * 1.5, true)
9636
+ ];
9637
+ const edges = [];
9638
+ for (let i = 0; i < arcs.length; i++) {
9639
+ const arc2 = arcs[i];
9640
+ const next = arcs[(i + 1) % arcs.length];
9641
+ edges.push(arc2);
9642
+ if (arc2.end.distanceTo(next.start)[0] > 1e-12)
9643
+ edges.push(new Segment$1(arc2.end, next.start));
9644
+ }
9645
+ return placePolygon(ccw(new Polygon$1(edges)), center, degrees);
9646
+ };
9647
+ var subtractHole = (outer, hole) => {
9648
+ for (const face of hole.reverse().faces) outer.addFace(face.shapes);
9649
+ return outer;
9650
+ };
9651
+ var getSmtPadPolygon = (pad) => {
9652
+ if (pad.shape === "polygon")
9653
+ return ccw(new Polygon$1(pad.points.map((p) => new Point$2(p.x, p.y))));
9654
+ if (pad.shape === "circle") return circlePolygon(pad, pad.radius);
9655
+ const radius = pad.shape === "pill" || pad.shape === "rotated_pill" ? pad.radius : pad.corner_radius ?? pad.rect_border_radius ?? 0;
9656
+ return roundedRectangle(
9657
+ pad,
9658
+ pad.width,
9659
+ pad.height,
9660
+ radius,
9661
+ "ccw_rotation" in pad ? pad.ccw_rotation : 0
9662
+ );
9663
+ };
9664
+ var getViaPolygon = (center, outerDiameter, holeDiameter) => subtractHole(
9665
+ circlePolygon(center, outerDiameter / 2),
9666
+ circlePolygon(center, holeDiameter / 2)
9667
+ );
9668
+ var getPlatedHolePolygon = (pad, componentRotation = 0) => {
9669
+ if (pad.shape === "circle")
9670
+ return getViaPolygon(pad, pad.outer_diameter, pad.hole_diameter);
9671
+ if ("outer_width" in pad) {
9672
+ return subtractHole(
9673
+ roundedRectangle(
9674
+ pad,
9675
+ pad.outer_width,
9676
+ pad.outer_height,
9677
+ Math.min(pad.outer_width, pad.outer_height) / 2,
9678
+ pad.ccw_rotation
9679
+ ),
9680
+ roundedRectangle(
9681
+ pad,
9682
+ pad.hole_width,
9683
+ pad.hole_height,
9684
+ Math.min(pad.hole_width, pad.hole_height) / 2,
9685
+ pad.ccw_rotation
9686
+ )
9687
+ );
9688
+ }
9689
+ const center = { x: pad.x + pad.hole_offset_x, y: pad.y + pad.hole_offset_y };
9690
+ const outer = pad.shape === "hole_with_polygon_pad" ? placePolygon(
9691
+ ccw(new Polygon$1(pad.pad_outline.map((p) => new Point$2(p.x, p.y)))),
9692
+ pad,
9693
+ pad.ccw_rotation ?? componentRotation
9694
+ ) : roundedRectangle(
9695
+ pad,
9696
+ pad.rect_pad_width,
9697
+ pad.rect_pad_height,
9698
+ pad.rect_border_radius,
9699
+ "rect_ccw_rotation" in pad ? pad.rect_ccw_rotation : 0
9700
+ );
9701
+ if (pad.shape === "circular_hole_with_rect_pad" || pad.shape === "hole_with_polygon_pad" && pad.hole_shape === "circle") {
9702
+ if (pad.hole_diameter === void 0)
9703
+ throw new Error("Circular plated hole requires hole_diameter");
9704
+ return subtractHole(outer, circlePolygon(center, pad.hole_diameter / 2));
9705
+ }
9706
+ if (!("hole_width" in pad) || pad.hole_width === void 0 || pad.hole_height === void 0)
9707
+ throw new Error("Slotted plated hole requires hole_width and hole_height");
9708
+ return subtractHole(
9709
+ outer,
9710
+ roundedRectangle(
9711
+ center,
9712
+ pad.hole_width,
9713
+ pad.hole_height,
9714
+ Math.min(pad.hole_width, pad.hole_height) / 2,
9715
+ "hole_ccw_rotation" in pad ? pad.hole_ccw_rotation : pad.shape === "hole_with_polygon_pad" ? pad.ccw_rotation ?? componentRotation : 0
9716
+ )
9717
+ );
9718
+ };
9612
9719
 
9613
9720
  // src/lib/apply-edit-events.ts
9614
9721
  import { translate as translate6 } from "transformation-matrix";
@@ -9993,7 +10100,7 @@ var zIndexMap = {
9993
10100
  };
9994
10101
 
9995
10102
  // src/PCBViewer.tsx
9996
- import { useCallback as useCallback13, useEffect as useEffect22, useMemo as useMemo16, useRef as useRef18, useState as useState15 } from "react";
10103
+ import { useCallback as useCallback14, useEffect as useEffect24, useMemo as useMemo17, useRef as useRef20, useState as useState16 } from "react";
9997
10104
 
9998
10105
  // node_modules/react-use/esm/useMountedState.js
9999
10106
  import { useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
@@ -10132,7 +10239,7 @@ var useMeasure_default = isBrowser && typeof window.ResizeObserver !== "undefine
10132
10239
  };
10133
10240
 
10134
10241
  // src/PCBViewer.tsx
10135
- import { compose as compose11, scale as scale6, translate as translate15 } from "transformation-matrix";
10242
+ import { compose as compose13, scale as scale7, translate as translate16 } from "transformation-matrix";
10136
10243
 
10137
10244
  // node_modules/use-mouse-matrix-transform/dist/chunk-TGYMZPTI.js
10138
10245
  import { compose as compose3, translate as translate7, scale } from "transformation-matrix";
@@ -10701,16 +10808,16 @@ function getExpandedStroke(strokeInput, defaultWidth) {
10701
10808
  addPoint(current, normalPrev, -1, currentWidth);
10702
10809
  addPoint(current, normalNext, -1, currentWidth);
10703
10810
  } else {
10704
- const scale7 = 1 / miterLength;
10811
+ const scale8 = 1 / miterLength;
10705
10812
  addPoint(
10706
10813
  current,
10707
- { x: miterX * scale7, y: miterY * scale7 },
10814
+ { x: miterX * scale8, y: miterY * scale8 },
10708
10815
  1,
10709
10816
  currentWidth
10710
10817
  );
10711
10818
  addPoint(
10712
10819
  current,
10713
- { x: miterX * scale7, y: miterY * scale7 },
10820
+ { x: miterX * scale8, y: miterY * scale8 },
10714
10821
  -1,
10715
10822
  currentWidth
10716
10823
  );
@@ -11876,8 +11983,8 @@ function getPrimitivesNearPoint({
11876
11983
  realToScreenScale,
11877
11984
  spatialIndex
11878
11985
  }) {
11879
- const scale7 = Math.max(Math.abs(realToScreenScale), Number.EPSILON);
11880
- const queryRadius = Math.max(spatialIndex.maxTraceWidth * 25, 2) / scale7;
11986
+ const scale8 = Math.max(Math.abs(realToScreenScale), Number.EPSILON);
11987
+ const queryRadius = Math.max(spatialIndex.maxTraceWidth * 25, 2) / scale8;
11881
11988
  const minCellX = Math.floor((point2.x - queryRadius) / spatialIndex.cellSize);
11882
11989
  const maxCellX = Math.floor((point2.x + queryRadius) / spatialIndex.cellSize);
11883
11990
  const minCellY = Math.floor((point2.y - queryRadius) / spatialIndex.cellSize);
@@ -12320,8 +12427,8 @@ var animateTransform = ({
12320
12427
  };
12321
12428
 
12322
12429
  // src/components/CanvasElementsRenderer.tsx
12323
- import { useCallback as useCallback11, useEffect as useEffect20, useMemo as useMemo15, useRef as useRef16, useState as useState13 } from "react";
12324
- import { applyToPoint as applyToPoint22, inverse as inverse6 } from "transformation-matrix";
12430
+ import { useCallback as useCallback11, useEffect as useEffect21, useMemo as useMemo16, useRef as useRef17, useState as useState14 } from "react";
12431
+ import { applyToPoint as applyToPoint23, inverse as inverse6 } from "transformation-matrix";
12325
12432
 
12326
12433
  // src/lib/get-pad-component.ts
12327
12434
  var getPadComponent = (pad, elements) => {
@@ -12769,10 +12876,10 @@ var Drawer = class {
12769
12876
  }
12770
12877
  if (is_stroke_dashed) {
12771
12878
  let dashPattern = [];
12772
- const scale7 = Math.abs(this.transform.a);
12773
- if (scale7 > 0) {
12879
+ const scale8 = Math.abs(this.transform.a);
12880
+ if (scale8 > 0) {
12774
12881
  const SEGMENT_LENGTH = 0.1;
12775
- const dash = SEGMENT_LENGTH * scale7;
12882
+ const dash = SEGMENT_LENGTH * scale8;
12776
12883
  const gap = dash * 1.3;
12777
12884
  if (dash > 0.5) {
12778
12885
  dashPattern = [dash, gap];
@@ -16158,7 +16265,9 @@ var DimensionOverlay = ({
16158
16265
  containerRef.current.blur();
16159
16266
  }
16160
16267
  },
16161
- onClick: () => {
16268
+ onClick: (event) => {
16269
+ if (event.target.closest("[data-toolbar-overlay]"))
16270
+ return;
16162
16271
  if (containerRef.current) {
16163
16272
  containerRef.current.focus();
16164
16273
  }
@@ -17058,13 +17167,13 @@ var ErrorOverlay = ({
17058
17167
  const screenCenter = applyToPoint14(transform, center);
17059
17168
  if (Number.isNaN(screenCenter.x) || Number.isNaN(screenCenter.y))
17060
17169
  return null;
17061
- const scale7 = Math.abs(transform.a);
17170
+ const scale8 = Math.abs(transform.a);
17062
17171
  const baseRadius = 0.5;
17063
17172
  const minRadius = 8;
17064
17173
  const maxRadius = 30;
17065
17174
  const scaledRadius = Math.max(
17066
17175
  minRadius,
17067
- Math.min(maxRadius, baseRadius * scale7)
17176
+ Math.min(maxRadius, baseRadius * scale8)
17068
17177
  );
17069
17178
  const popupPosition = getPopupPosition(screenCenter, containerRef);
17070
17179
  return /* @__PURE__ */ jsxs7(
@@ -17182,19 +17291,59 @@ var ErrorOverlay = ({
17182
17291
 
17183
17292
  // src/components/FocusedPcbComponentOverlay.tsx
17184
17293
  import { useEffect as useEffect9 } from "react";
17185
- import { applyToPoint as applyToPoint15 } from "transformation-matrix";
17294
+ import {
17295
+ applyToPoint as applyToPoint16,
17296
+ compose as compose11,
17297
+ rotateDEG as rotateDEG4
17298
+ } from "transformation-matrix";
17186
17299
 
17187
17300
  // src/lib/get-pcb-component-focus.ts
17301
+ import { applyToPoint as applyToPoint15, rotateDEG as rotateDEG3 } from "transformation-matrix";
17188
17302
  var getPcbComponentFocus = (elements, pcbComponentId, width, height) => {
17189
17303
  if (width <= 0 || height <= 0) return;
17190
17304
  const component = elements.find(
17191
17305
  (element) => element.type === "pcb_component" && element.pcb_component_id === pcbComponentId
17192
17306
  );
17193
17307
  if (component?.type !== "pcb_component") return;
17194
- const bounds = getPcbElementBounds(component);
17195
- if (!bounds) return;
17308
+ const rotation = component.rotation ?? 0;
17309
+ const polygons = elements.flatMap((element) => {
17310
+ if (!("pcb_component_id" in element) || element.pcb_component_id !== pcbComponentId)
17311
+ return [];
17312
+ if (element.type === "pcb_smtpad") return [getSmtPadPolygon(element)];
17313
+ if (element.type === "pcb_plated_hole")
17314
+ return [getPlatedHolePolygon(element, rotation)];
17315
+ return [];
17316
+ });
17317
+ const boxes = polygons.map((polygon2) => polygon2.rotate(-rotation * Math.PI / 180).box).filter(
17318
+ (box2) => [box2.xmin, box2.xmax, box2.ymin, box2.ymax].every(Number.isFinite)
17319
+ );
17320
+ const fallbackBounds = getPcbElementBounds({ ...component, rotation: 0 });
17321
+ if (!fallbackBounds) return;
17322
+ const localBounds = boxes.length ? {
17323
+ minX: Math.min(...boxes.map((box2) => box2.xmin)),
17324
+ maxX: Math.max(...boxes.map((box2) => box2.xmax)),
17325
+ minY: Math.min(...boxes.map((box2) => box2.ymin)),
17326
+ maxY: Math.max(...boxes.map((box2) => box2.ymax))
17327
+ } : fallbackBounds;
17328
+ const outlineRotation = boxes.length ? rotation : 0;
17329
+ const outline = {
17330
+ center: applyToPoint15(rotateDEG3(outlineRotation), {
17331
+ x: (localBounds.minX + localBounds.maxX) / 2,
17332
+ y: (localBounds.minY + localBounds.maxY) / 2
17333
+ }),
17334
+ width: localBounds.maxX - localBounds.minX,
17335
+ height: localBounds.maxY - localBounds.minY,
17336
+ rotation: outlineRotation
17337
+ };
17338
+ const bounds = boxes.length ? {
17339
+ minX: Math.min(...polygons.map((polygon2) => polygon2.box.xmin)),
17340
+ maxX: Math.max(...polygons.map((polygon2) => polygon2.box.xmax)),
17341
+ minY: Math.min(...polygons.map((polygon2) => polygon2.box.ymin)),
17342
+ maxY: Math.max(...polygons.map((polygon2) => polygon2.box.ymax))
17343
+ } : fallbackBounds;
17196
17344
  return {
17197
17345
  component,
17346
+ outline,
17198
17347
  bounds,
17199
17348
  transform: createTransformForBounds({ bounds, width, height })
17200
17349
  };
@@ -17215,19 +17364,24 @@ var FocusedPcbComponentOverlay = ({
17215
17364
  if (layer) selectLayer(layer);
17216
17365
  }, [focusRequest, layer, selectLayer]);
17217
17366
  if (!focus || !transform) return null;
17218
- const { bounds } = focus;
17219
- const a = applyToPoint15(transform, { x: bounds.minX, y: bounds.minY });
17220
- const b = applyToPoint15(transform, { x: bounds.maxX, y: bounds.maxY });
17367
+ const { outline } = focus;
17368
+ const center = applyToPoint16(transform, outline.center);
17369
+ const rotatedTransform = compose11(transform, rotateDEG4(outline.rotation ?? 0));
17370
+ const width = outline.width * Math.hypot(rotatedTransform.a, rotatedTransform.b) + 8;
17371
+ const height = outline.height * Math.hypot(rotatedTransform.c, rotatedTransform.d) + 8;
17372
+ const rotation = Math.atan2(rotatedTransform.b, rotatedTransform.a);
17221
17373
  return /* @__PURE__ */ jsx10(
17222
17374
  "div",
17223
17375
  {
17224
17376
  "data-focused-pcb-component-id": componentId,
17225
17377
  style: {
17226
17378
  position: "absolute",
17227
- left: Math.min(a.x, b.x) - 4,
17228
- top: Math.min(a.y, b.y) - 4,
17229
- width: Math.abs(b.x - a.x) + 8,
17230
- height: Math.abs(b.y - a.y) + 8,
17379
+ left: center.x - width / 2,
17380
+ top: center.y - height / 2,
17381
+ width,
17382
+ height,
17383
+ transform: `rotate(${rotation}rad)`,
17384
+ transformOrigin: "center",
17231
17385
  border: "2px solid #3399ff",
17232
17386
  borderRadius: 4,
17233
17387
  boxSizing: "border-box",
@@ -17250,10 +17404,10 @@ function ifSetsMatchExactly(set1, set2) {
17250
17404
 
17251
17405
  // src/components/MouseElementTracker.tsx
17252
17406
  import { useEffect as useEffect11, useMemo as useMemo8, useState as useState7 } from "react";
17253
- import { applyToPoint as applyToPoint18, inverse as inverse5 } from "transformation-matrix";
17407
+ import { applyToPoint as applyToPoint19, inverse as inverse5 } from "transformation-matrix";
17254
17408
 
17255
17409
  // src/components/AnchorOffsetOverlay/AnchorOffsetOverlay.tsx
17256
- import { applyToPoint as applyToPoint16 } from "transformation-matrix";
17410
+ import { applyToPoint as applyToPoint17 } from "transformation-matrix";
17257
17411
 
17258
17412
  // src/components/AnchorOffsetOverlay/common/constants.ts
17259
17413
  var VISUAL_CONFIG = {
@@ -17298,7 +17452,7 @@ var AnchorOffsetOverlay = ({
17298
17452
  const anchorScreens = /* @__PURE__ */ new Map();
17299
17453
  targets.forEach((target) => {
17300
17454
  if (!anchorScreens.has(target.anchor_id)) {
17301
- const screenPoint = applyToPoint16(transform, target.anchor);
17455
+ const screenPoint = applyToPoint17(transform, target.anchor);
17302
17456
  anchorScreens.set(target.anchor_id, screenPoint);
17303
17457
  }
17304
17458
  });
@@ -17332,7 +17486,7 @@ var AnchorOffsetOverlay = ({
17332
17486
  const anchorKey = target.anchor_id;
17333
17487
  const targetCenter = target.target;
17334
17488
  const anchorMarkerScreen = anchorScreens.get(anchorKey);
17335
- const targetScreen = applyToPoint16(transform, targetCenter);
17489
+ const targetScreen = applyToPoint17(transform, targetCenter);
17336
17490
  const offsetX = targetCenter.x - anchorPosition.x;
17337
17491
  const offsetY = targetCenter.y - anchorPosition.y;
17338
17492
  const xLineLength = Math.abs(targetScreen.x - anchorMarkerScreen.x);
@@ -17710,7 +17864,7 @@ var GroupAnchorOffsetOverlay = ({
17710
17864
  };
17711
17865
 
17712
17866
  // src/components/AnchorOffsetOverlay/ComponentBoundingBoxOverlay.tsx
17713
- import { applyToPoint as applyToPoint17 } from "transformation-matrix";
17867
+ import { applyToPoint as applyToPoint18 } from "transformation-matrix";
17714
17868
  import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
17715
17869
  var calculateComponentBoundingBox = (component, elements) => {
17716
17870
  const componentId = component.pcb_component_id;
@@ -17774,11 +17928,11 @@ var ComponentBoundingBoxOverlay = ({
17774
17928
  width: containerWidth,
17775
17929
  height: containerHeight,
17776
17930
  children: renderData.map(({ component, bbox, group }) => {
17777
- const topLeft = applyToPoint17(transform, {
17931
+ const topLeft = applyToPoint18(transform, {
17778
17932
  x: bbox.minX,
17779
17933
  y: bbox.maxY
17780
17934
  });
17781
- const bottomRight = applyToPoint17(transform, {
17935
+ const bottomRight = applyToPoint18(transform, {
17782
17936
  x: bbox.maxX,
17783
17937
  y: bbox.minY
17784
17938
  });
@@ -17792,7 +17946,7 @@ var ComponentBoundingBoxOverlay = ({
17792
17946
  x: (bbox.minX + bbox.maxX) / 2,
17793
17947
  y: (bbox.minY + bbox.maxY) / 2
17794
17948
  };
17795
- const componentCenterScreen = applyToPoint17(transform, componentCenter);
17949
+ const componentCenterScreen = applyToPoint18(transform, componentCenter);
17796
17950
  return /* @__PURE__ */ jsxs9("g", { children: [
17797
17951
  /* @__PURE__ */ jsx14(
17798
17952
  "rect",
@@ -18352,7 +18506,7 @@ var MouseElementTracker = ({
18352
18506
  h = "h" in primitive ? primitive.h : "r" in primitive ? primitive.r * 2 : "rX" in primitive && "rY" in primitive ? primitive.rY * 2 : 0;
18353
18507
  }
18354
18508
  if (!basePoint) continue;
18355
- const screenPos = applyToPoint18(transform, basePoint);
18509
+ const screenPos = applyToPoint19(transform, basePoint);
18356
18510
  const screenSize = {
18357
18511
  w: w * transform.a,
18358
18512
  h: h * transform.a
@@ -18381,7 +18535,7 @@ var MouseElementTracker = ({
18381
18535
  }) => {
18382
18536
  const { x, y } = screenPoint;
18383
18537
  setMousePos({ x, y });
18384
- const rwPoint = applyToPoint18(inverse5(transform2), { x, y });
18538
+ const rwPoint = applyToPoint19(inverse5(transform2), { x, y });
18385
18539
  const nearbyPrimitives = getPrimitivesNearPoint({
18386
18540
  point: rwPoint,
18387
18541
  realToScreenScale: transform2.a,
@@ -18484,7 +18638,7 @@ var MouseElementTracker = ({
18484
18638
 
18485
18639
  // src/components/PcbGroupOverlay.tsx
18486
18640
  import { useEffect as useEffect12, useMemo as useMemo9, useRef as useRef8 } from "react";
18487
- import { applyToPoint as applyToPoint19 } from "transformation-matrix";
18641
+ import { applyToPoint as applyToPoint20 } from "transformation-matrix";
18488
18642
  import { identity as identity7 } from "transformation-matrix";
18489
18643
  import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
18490
18644
  var GROUP_COLORS = [
@@ -18654,10 +18808,10 @@ var PcbGroupOverlay = ({
18654
18808
  minY -= totalPadding;
18655
18809
  maxY += totalPadding;
18656
18810
  }
18657
- const topLeft = applyToPoint19(transform, { x: minX, y: maxY });
18658
- const topRight = applyToPoint19(transform, { x: maxX, y: maxY });
18659
- const bottomLeft = applyToPoint19(transform, { x: minX, y: minY });
18660
- const bottomRight = applyToPoint19(transform, { x: maxX, y: minY });
18811
+ const topLeft = applyToPoint20(transform, { x: minX, y: maxY });
18812
+ const topRight = applyToPoint20(transform, { x: maxX, y: maxY });
18813
+ const bottomLeft = applyToPoint20(transform, { x: minX, y: minY });
18814
+ const bottomRight = applyToPoint20(transform, { x: maxX, y: minY });
18661
18815
  const groupColor = GROUP_COLORS[groupIndex % GROUP_COLORS.length];
18662
18816
  ctx.strokeStyle = groupColor;
18663
18817
  ctx.lineWidth = 2;
@@ -18707,7 +18861,7 @@ var PcbGroupOverlay = ({
18707
18861
  x: group.anchor_position[0] ?? 0,
18708
18862
  y: group.anchor_position[1] ?? 0
18709
18863
  } : { x: group.anchor_position.x, y: group.anchor_position.y };
18710
- const anchorScreenPos = applyToPoint19(transform, anchorPositionValue);
18864
+ const anchorScreenPos = applyToPoint20(transform, anchorPositionValue);
18711
18865
  ctx.strokeStyle = "white";
18712
18866
  ctx.lineWidth = 1.5;
18713
18867
  ctx.setLineDash([]);
@@ -18761,7 +18915,7 @@ var PcbGroupOverlay = ({
18761
18915
  };
18762
18916
 
18763
18917
  // src/components/RatsNestOverlay.tsx
18764
- import { applyToPoint as applyToPoint20, identity as identity8 } from "transformation-matrix";
18918
+ import { applyToPoint as applyToPoint21, identity as identity8 } from "transformation-matrix";
18765
18919
  import { useMemo as useMemo10 } from "react";
18766
18920
  import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
18767
18921
  var RatsNestOverlay = ({
@@ -18844,8 +18998,8 @@ var RatsNestOverlay = ({
18844
18998
  zIndex: zIndexMap.ratsNestOverlay
18845
18999
  },
18846
19000
  children: ratsNestLines.map(({ key, startPoint, endPoint, isInNet }) => {
18847
- const transformedStart = applyToPoint20(transform, startPoint);
18848
- const transformedEnd = applyToPoint20(transform, endPoint);
19001
+ const transformedStart = applyToPoint21(transform, startPoint);
19002
+ const transformedEnd = applyToPoint21(transform, endPoint);
18849
19003
  return /* @__PURE__ */ jsx19(
18850
19004
  "line",
18851
19005
  {
@@ -18866,7 +19020,7 @@ var RatsNestOverlay = ({
18866
19020
  };
18867
19021
 
18868
19022
  // src/components/ToolbarOverlay.tsx
18869
- import { css as css3 } from "@emotion/css";
19023
+ import { css as css4 } from "@emotion/css";
18870
19024
 
18871
19025
  // src/hooks/useHotKey.ts
18872
19026
  import { useEffect as useEffect13, useRef as useRef9 } from "react";
@@ -18961,17 +19115,17 @@ var useMobileTouch = (onClick, options = { stopPropagation: true }) => {
18961
19115
  // src/components/ToolbarOverlay.tsx
18962
19116
  import {
18963
19117
  useCallback as useCallback10,
18964
- useEffect as useEffect17,
19118
+ useEffect as useEffect18,
18965
19119
  useLayoutEffect as useLayoutEffect2,
18966
- useMemo as useMemo12,
18967
- useRef as useRef13,
18968
- useState as useState11
19120
+ useMemo as useMemo13,
19121
+ useRef as useRef14,
19122
+ useState as useState12
18969
19123
  } from "react";
18970
19124
 
18971
19125
  // package.json
18972
19126
  var package_default = {
18973
19127
  name: "@tscircuit/pcb-viewer",
18974
- version: "1.11.436",
19128
+ version: "1.11.437",
18975
19129
  main: "dist/index.js",
18976
19130
  type: "module",
18977
19131
  repository: {
@@ -19053,8 +19207,233 @@ var package_default = {
19053
19207
  }
19054
19208
  };
19055
19209
 
19210
+ // src/components/ComponentSearch.tsx
19211
+ import { css as css2 } from "@emotion/css";
19212
+ import { useEffect as useEffect15, useId, useMemo as useMemo11, useRef as useRef11, useState as useState9 } from "react";
19213
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
19214
+ var buttonClass = css2`
19215
+ background: #1f1f1f;
19216
+ border: 1px solid #666;
19217
+ border-radius: 2px;
19218
+ color: #eee;
19219
+ padding: 4px 8px;
19220
+ font: inherit;
19221
+ cursor: pointer;
19222
+ &:hover, &:focus-visible { background: #444; }
19223
+ `;
19224
+ var ComponentSearch = ({
19225
+ elements,
19226
+ onSelect
19227
+ }) => {
19228
+ const [open, setOpen] = useState9(false);
19229
+ const [query, setQuery] = useState9("");
19230
+ const [activeComponentId, setActiveComponentId] = useState9(
19231
+ null
19232
+ );
19233
+ const container = useRef11(null);
19234
+ const toggle = useRef11(null);
19235
+ const input = useRef11(null);
19236
+ const panelId = useId();
19237
+ const components = useMemo11(() => {
19238
+ const names = new Map(
19239
+ elements.flatMap(
19240
+ (element) => element.type === "source_component" ? [[element.source_component_id, element.name]] : []
19241
+ )
19242
+ );
19243
+ return elements.flatMap((element) => {
19244
+ if (element.type !== "pcb_component") return [];
19245
+ const name = names.get(element.source_component_id);
19246
+ return name ? [{ id: element.pcb_component_id, name, layer: element.layer }] : [];
19247
+ }).sort(
19248
+ (a, b) => a.name.localeCompare(b.name, void 0, { numeric: true })
19249
+ );
19250
+ }, [elements]);
19251
+ const normalizedQuery = query.trim().toLowerCase();
19252
+ const matches = components.filter(
19253
+ (component) => component.name.toLowerCase().includes(normalizedQuery)
19254
+ );
19255
+ const activeIndex = matches.findIndex(
19256
+ (component) => component.id === activeComponentId
19257
+ );
19258
+ const activeOptionId = activeIndex >= 0 ? `${panelId}-option-${activeIndex}` : void 0;
19259
+ useEffect15(() => {
19260
+ if (open && activeOptionId)
19261
+ document.getElementById(activeOptionId)?.scrollIntoView({ block: "nearest" });
19262
+ }, [open, activeOptionId]);
19263
+ useEffect15(() => {
19264
+ if (!open) return;
19265
+ setActiveComponentId(null);
19266
+ input.current?.focus();
19267
+ const closeOutside = (event) => {
19268
+ if (!container.current?.contains(event.target)) setOpen(false);
19269
+ };
19270
+ document.addEventListener("pointerdown", closeOutside);
19271
+ return () => document.removeEventListener("pointerdown", closeOutside);
19272
+ }, [open]);
19273
+ const select = (id) => {
19274
+ onSelect(id);
19275
+ setOpen(false);
19276
+ toggle.current?.focus();
19277
+ };
19278
+ return /* @__PURE__ */ jsxs14(
19279
+ "div",
19280
+ {
19281
+ ref: container,
19282
+ style: { position: "relative", height: "fit-content" },
19283
+ onKeyDown: (event) => {
19284
+ if ((event.key === "ArrowDown" || event.key === "ArrowUp") && open && normalizedQuery && matches.length) {
19285
+ event.preventDefault();
19286
+ event.stopPropagation();
19287
+ const nextIndex = activeIndex < 0 ? event.key === "ArrowDown" ? 0 : matches.length - 1 : (activeIndex + (event.key === "ArrowDown" ? 1 : -1) + matches.length) % matches.length;
19288
+ const component = matches[nextIndex];
19289
+ setActiveComponentId(component.id);
19290
+ onSelect(component.id);
19291
+ input.current?.focus();
19292
+ }
19293
+ if (event.key === "Escape") {
19294
+ event.stopPropagation();
19295
+ setOpen(false);
19296
+ toggle.current?.focus();
19297
+ }
19298
+ },
19299
+ children: [
19300
+ /* @__PURE__ */ jsx20(
19301
+ "button",
19302
+ {
19303
+ ref: toggle,
19304
+ type: "button",
19305
+ className: buttonClass,
19306
+ "aria-label": "Search components",
19307
+ title: "Search components",
19308
+ style: { display: "flex", alignItems: "center", padding: "4px 6px" },
19309
+ "aria-expanded": open,
19310
+ "aria-controls": panelId,
19311
+ onClick: () => setOpen(!open),
19312
+ children: /* @__PURE__ */ jsxs14(
19313
+ "svg",
19314
+ {
19315
+ width: "14",
19316
+ height: "14",
19317
+ viewBox: "0 0 24 24",
19318
+ fill: "none",
19319
+ stroke: "currentColor",
19320
+ strokeWidth: "2",
19321
+ strokeLinecap: "round",
19322
+ "aria-hidden": "true",
19323
+ children: [
19324
+ /* @__PURE__ */ jsx20("circle", { cx: "10.5", cy: "10.5", r: "6.5" }),
19325
+ /* @__PURE__ */ jsx20("path", { d: "m16 16 5 5" })
19326
+ ]
19327
+ }
19328
+ )
19329
+ }
19330
+ ),
19331
+ open && /* @__PURE__ */ jsxs14(
19332
+ "div",
19333
+ {
19334
+ id: panelId,
19335
+ style: {
19336
+ position: "absolute",
19337
+ top: "100%",
19338
+ left: 0,
19339
+ marginTop: 4,
19340
+ width: "min(260px, calc(100vw - 140px))",
19341
+ padding: 8,
19342
+ border: "1px solid #666",
19343
+ borderRadius: 4,
19344
+ background: "#1f1f1f",
19345
+ color: "#eee",
19346
+ boxSizing: "border-box"
19347
+ },
19348
+ children: [
19349
+ /* @__PURE__ */ jsx20(
19350
+ "input",
19351
+ {
19352
+ ref: input,
19353
+ role: "combobox",
19354
+ "aria-autocomplete": "list",
19355
+ "aria-expanded": open,
19356
+ "aria-controls": `${panelId}-results`,
19357
+ "aria-activedescendant": activeOptionId,
19358
+ "aria-label": "Component name",
19359
+ placeholder: "Search component name\u2026",
19360
+ value: query,
19361
+ onChange: (event) => {
19362
+ setQuery(event.target.value);
19363
+ setActiveComponentId(null);
19364
+ },
19365
+ onKeyDown: (event) => {
19366
+ if (event.key === "Enter" && normalizedQuery && matches[0]) {
19367
+ event.preventDefault();
19368
+ select(matches[activeIndex >= 0 ? activeIndex : 0].id);
19369
+ }
19370
+ },
19371
+ style: {
19372
+ width: "100%",
19373
+ boxSizing: "border-box",
19374
+ padding: 6,
19375
+ background: "#111",
19376
+ color: "#eee",
19377
+ border: "1px solid #666",
19378
+ borderRadius: 2
19379
+ }
19380
+ }
19381
+ ),
19382
+ !normalizedQuery ? /* @__PURE__ */ jsx20("output", { style: { display: "block", marginTop: 8 }, children: "Type a component name." }) : matches.length === 0 ? /* @__PURE__ */ jsx20("output", { style: { display: "block", marginTop: 8 }, children: "No matching components." }) : /* @__PURE__ */ jsx20(
19383
+ "div",
19384
+ {
19385
+ id: `${panelId}-results`,
19386
+ role: "listbox",
19387
+ tabIndex: -1,
19388
+ "aria-label": "Matching components",
19389
+ style: {
19390
+ listStyle: "none",
19391
+ padding: "0 12px 0 0",
19392
+ scrollbarGutter: "stable",
19393
+ overflowX: "hidden",
19394
+ margin: "8px 0 0",
19395
+ maxHeight: 220,
19396
+ overflowY: "auto"
19397
+ },
19398
+ children: matches.map((component, index) => /* @__PURE__ */ jsx20("div", { role: "presentation", children: /* @__PURE__ */ jsxs14(
19399
+ "button",
19400
+ {
19401
+ type: "button",
19402
+ role: "option",
19403
+ id: `${panelId}-option-${index}`,
19404
+ "aria-selected": component.id === activeComponentId,
19405
+ tabIndex: -1,
19406
+ className: buttonClass,
19407
+ style: {
19408
+ width: "100%",
19409
+ boxSizing: "border-box",
19410
+ display: "flex",
19411
+ justifyContent: "space-between",
19412
+ border: "none",
19413
+ borderTop: index > 0 ? "1px solid #444" : "0",
19414
+ borderRadius: 0,
19415
+ padding: "8px 6px",
19416
+ backgroundColor: component.id === activeComponentId ? "#34506e" : void 0
19417
+ },
19418
+ onClick: () => select(component.id),
19419
+ children: [
19420
+ /* @__PURE__ */ jsx20("span", { children: component.name }),
19421
+ /* @__PURE__ */ jsx20("span", { style: { color: "#aaa" }, children: component.layer })
19422
+ ]
19423
+ }
19424
+ ) }, component.id))
19425
+ }
19426
+ )
19427
+ ]
19428
+ }
19429
+ )
19430
+ ]
19431
+ }
19432
+ );
19433
+ };
19434
+
19056
19435
  // src/components/ToolbarButton.tsx
19057
- import { jsx as jsx20 } from "react/jsx-runtime";
19436
+ import { jsx as jsx21 } from "react/jsx-runtime";
19058
19437
  var ToolbarButton = ({
19059
19438
  children,
19060
19439
  isSmallScreen,
@@ -19062,7 +19441,7 @@ var ToolbarButton = ({
19062
19441
  ...props
19063
19442
  }) => {
19064
19443
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
19065
- return /* @__PURE__ */ jsx20(
19444
+ return /* @__PURE__ */ jsx21(
19066
19445
  "div",
19067
19446
  {
19068
19447
  ...props,
@@ -19090,7 +19469,7 @@ var ToolbarButton = ({
19090
19469
  };
19091
19470
 
19092
19471
  // src/components/ToolbarErrorDropdown.tsx
19093
- import { useCallback as useCallback9, useMemo as useMemo11, useState as useState9 } from "react";
19472
+ import { useCallback as useCallback9, useMemo as useMemo12, useState as useState10 } from "react";
19094
19473
 
19095
19474
  // src/lib/util/group-errors-by-type.ts
19096
19475
  var groupErrorsByType = (errors) => {
@@ -19112,16 +19491,16 @@ var groupErrorsByType = (errors) => {
19112
19491
  };
19113
19492
 
19114
19493
  // src/components/useToolbarErrorFocus.ts
19115
- import { useCallback as useCallback8, useEffect as useEffect15, useRef as useRef11 } from "react";
19494
+ import { useCallback as useCallback8, useEffect as useEffect16, useRef as useRef12 } from "react";
19116
19495
  var useToolbarErrorFocus = ({
19117
19496
  onClose,
19118
19497
  setHoveredErrorId,
19119
19498
  setFocusedErrorId,
19120
19499
  highlightDurationMs = 3e3
19121
19500
  }) => {
19122
- const clearHighlightTimeoutRef = useRef11(null);
19123
- const focusRequestRef = useRef11(null);
19124
- const selectedErrorIdRef = useRef11(null);
19501
+ const clearHighlightTimeoutRef = useRef12(null);
19502
+ const focusRequestRef = useRef12(null);
19503
+ const selectedErrorIdRef = useRef12(null);
19125
19504
  const clearPendingSelection = useCallback8(() => {
19126
19505
  if (clearHighlightTimeoutRef.current !== null) {
19127
19506
  window.clearTimeout(clearHighlightTimeoutRef.current);
@@ -19132,7 +19511,7 @@ var useToolbarErrorFocus = ({
19132
19511
  focusRequestRef.current = null;
19133
19512
  }
19134
19513
  }, []);
19135
- useEffect15(() => clearPendingSelection, [clearPendingSelection]);
19514
+ useEffect16(() => clearPendingSelection, [clearPendingSelection]);
19136
19515
  const handleErrorSelect = useCallback8(
19137
19516
  (errorId) => {
19138
19517
  clearPendingSelection();
@@ -19170,7 +19549,7 @@ var useToolbarErrorFocus = ({
19170
19549
  };
19171
19550
 
19172
19551
  // src/components/ToolbarErrorDropdown.tsx
19173
- import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
19552
+ import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
19174
19553
  var CopyErrorButton = ({
19175
19554
  errorId,
19176
19555
  errorMessage,
@@ -19180,7 +19559,7 @@ var CopyErrorButton = ({
19180
19559
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(
19181
19560
  () => onCopy(errorMessage, errorId)
19182
19561
  );
19183
- return /* @__PURE__ */ jsx21(
19562
+ return /* @__PURE__ */ jsx22(
19184
19563
  "button",
19185
19564
  {
19186
19565
  type: "button",
@@ -19200,7 +19579,7 @@ var CopyErrorButton = ({
19200
19579
  ...touchStyle
19201
19580
  },
19202
19581
  ...touchHandlers,
19203
- children: copiedErrorId === errorId ? /* @__PURE__ */ jsx21("span", { style: { color: "#4caf50", fontSize: 12 }, children: "Copied!" }) : /* @__PURE__ */ jsx21("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx21("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }) })
19582
+ children: copiedErrorId === errorId ? /* @__PURE__ */ jsx22("span", { style: { color: "#4caf50", fontSize: 12 }, children: "Copied!" }) : /* @__PURE__ */ jsx22("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx22("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }) })
19204
19583
  }
19205
19584
  );
19206
19585
  };
@@ -19213,11 +19592,11 @@ var ToolbarErrorDropdown = ({
19213
19592
  setHoveredErrorId,
19214
19593
  setFocusedErrorId
19215
19594
  }) => {
19216
- const [copiedErrorId, setCopiedErrorId] = useState9(null);
19217
- const [collapsedErrorGroups, setCollapsedErrorGroups] = useState9(
19595
+ const [copiedErrorId, setCopiedErrorId] = useState10(null);
19596
+ const [collapsedErrorGroups, setCollapsedErrorGroups] = useState10(
19218
19597
  /* @__PURE__ */ new Set()
19219
19598
  );
19220
- const [expandedErrorIds, setExpandedErrorIds] = useState9(
19599
+ const [expandedErrorIds, setExpandedErrorIds] = useState10(
19221
19600
  /* @__PURE__ */ new Set()
19222
19601
  );
19223
19602
  const [, copyToClipboard] = useCopyToClipboard_default();
@@ -19226,14 +19605,14 @@ var ToolbarErrorDropdown = ({
19226
19605
  setHoveredErrorId,
19227
19606
  setFocusedErrorId
19228
19607
  });
19229
- const errorElements = useMemo11(
19608
+ const errorElements = useMemo12(
19230
19609
  () => elements?.filter(
19231
19610
  (el) => el.type.includes("error")
19232
19611
  ) ?? [],
19233
19612
  [elements]
19234
19613
  );
19235
19614
  const errorCount = errorElements.length;
19236
- const groupedErrorElements = useMemo11(
19615
+ const groupedErrorElements = useMemo12(
19237
19616
  () => groupErrorsByType(errorElements),
19238
19617
  [errorElements]
19239
19618
  );
@@ -19259,20 +19638,20 @@ var ToolbarErrorDropdown = ({
19259
19638
  return next;
19260
19639
  });
19261
19640
  }, []);
19262
- return /* @__PURE__ */ jsxs14("div", { style: { position: "relative" }, children: [
19263
- /* @__PURE__ */ jsx21(
19641
+ return /* @__PURE__ */ jsxs15("div", { style: { position: "relative" }, children: [
19642
+ /* @__PURE__ */ jsx22(
19264
19643
  ToolbarButton,
19265
19644
  {
19266
19645
  isSmallScreen,
19267
19646
  style: errorCount > 0 ? { color: "red" } : void 0,
19268
19647
  onClick: onToggle,
19269
- children: /* @__PURE__ */ jsxs14("div", { children: [
19648
+ children: /* @__PURE__ */ jsxs15("div", { children: [
19270
19649
  errorCount,
19271
19650
  " errors"
19272
19651
  ] })
19273
19652
  }
19274
19653
  ),
19275
- isOpen && errorCount > 0 && /* @__PURE__ */ jsx21(
19654
+ isOpen && errorCount > 0 && /* @__PURE__ */ jsx22(
19276
19655
  "div",
19277
19656
  {
19278
19657
  style: {
@@ -19292,14 +19671,14 @@ var ToolbarErrorDropdown = ({
19292
19671
  },
19293
19672
  children: groupedErrorElements.map(({ errorType, errors }, groupIndex) => {
19294
19673
  const isGroupCollapsed = collapsedErrorGroups.has(errorType);
19295
- return /* @__PURE__ */ jsxs14(
19674
+ return /* @__PURE__ */ jsxs15(
19296
19675
  "div",
19297
19676
  {
19298
19677
  style: {
19299
19678
  borderBottom: groupIndex < groupedErrorElements.length - 1 ? "1px solid #444" : "none"
19300
19679
  },
19301
19680
  children: [
19302
- /* @__PURE__ */ jsxs14(
19681
+ /* @__PURE__ */ jsxs15(
19303
19682
  "div",
19304
19683
  {
19305
19684
  style: {
@@ -19336,7 +19715,7 @@ var ToolbarErrorDropdown = ({
19336
19715
  toggleErrorGroup(errorType);
19337
19716
  },
19338
19717
  children: [
19339
- /* @__PURE__ */ jsxs14(
19718
+ /* @__PURE__ */ jsxs15(
19340
19719
  "div",
19341
19720
  {
19342
19721
  style: {
@@ -19346,7 +19725,7 @@ var ToolbarErrorDropdown = ({
19346
19725
  color: "#ff6b6b"
19347
19726
  },
19348
19727
  children: [
19349
- /* @__PURE__ */ jsx21(
19728
+ /* @__PURE__ */ jsx22(
19350
19729
  "div",
19351
19730
  {
19352
19731
  style: {
@@ -19359,7 +19738,7 @@ var ToolbarErrorDropdown = ({
19359
19738
  children: "\u203A"
19360
19739
  }
19361
19740
  ),
19362
- /* @__PURE__ */ jsx21(
19741
+ /* @__PURE__ */ jsx22(
19363
19742
  "div",
19364
19743
  {
19365
19744
  style: {
@@ -19372,7 +19751,7 @@ var ToolbarErrorDropdown = ({
19372
19751
  ]
19373
19752
  }
19374
19753
  ),
19375
- /* @__PURE__ */ jsx21(
19754
+ /* @__PURE__ */ jsx22(
19376
19755
  "div",
19377
19756
  {
19378
19757
  style: {
@@ -19390,14 +19769,14 @@ var ToolbarErrorDropdown = ({
19390
19769
  !isGroupCollapsed && errors.map(({ error, index, errorId }) => {
19391
19770
  const isExpanded = expandedErrorIds.has(errorId);
19392
19771
  const errorMessage = error.message ?? "No error message";
19393
- return /* @__PURE__ */ jsxs14(
19772
+ return /* @__PURE__ */ jsxs15(
19394
19773
  "div",
19395
19774
  {
19396
19775
  style: {
19397
19776
  borderTop: "1px solid #3a3a3a"
19398
19777
  },
19399
19778
  children: [
19400
- /* @__PURE__ */ jsxs14(
19779
+ /* @__PURE__ */ jsxs15(
19401
19780
  "div",
19402
19781
  {
19403
19782
  style: {
@@ -19436,7 +19815,7 @@ var ToolbarErrorDropdown = ({
19436
19815
  handleErrorSelect(errorId);
19437
19816
  },
19438
19817
  children: [
19439
- /* @__PURE__ */ jsx21(
19818
+ /* @__PURE__ */ jsx22(
19440
19819
  "div",
19441
19820
  {
19442
19821
  style: {
@@ -19452,7 +19831,7 @@ var ToolbarErrorDropdown = ({
19452
19831
  children: errorMessage
19453
19832
  }
19454
19833
  ),
19455
- /* @__PURE__ */ jsx21(
19834
+ /* @__PURE__ */ jsx22(
19456
19835
  "button",
19457
19836
  {
19458
19837
  type: "button",
@@ -19484,7 +19863,7 @@ var ToolbarErrorDropdown = ({
19484
19863
  ]
19485
19864
  }
19486
19865
  ),
19487
- isExpanded && /* @__PURE__ */ jsxs14(
19866
+ isExpanded && /* @__PURE__ */ jsxs15(
19488
19867
  "div",
19489
19868
  {
19490
19869
  "data-error-id": index,
@@ -19496,7 +19875,7 @@ var ToolbarErrorDropdown = ({
19496
19875
  position: "relative"
19497
19876
  },
19498
19877
  children: [
19499
- /* @__PURE__ */ jsx21(
19878
+ /* @__PURE__ */ jsx22(
19500
19879
  "div",
19501
19880
  {
19502
19881
  style: {
@@ -19514,7 +19893,7 @@ var ToolbarErrorDropdown = ({
19514
19893
  children: errorMessage
19515
19894
  }
19516
19895
  ),
19517
- /* @__PURE__ */ jsx21(
19896
+ /* @__PURE__ */ jsx22(
19518
19897
  CopyErrorButton,
19519
19898
  {
19520
19899
  errorId,
@@ -19551,11 +19930,11 @@ var RenderingEngineContext = createContext2(null);
19551
19930
  var useRenderingEngine = () => useContext3(RenderingEngineContext);
19552
19931
 
19553
19932
  // src/components/VisibilityContextMenu.tsx
19554
- import { css as css2 } from "@emotion/css";
19555
- import { useEffect as useEffect16, useRef as useRef12, useState as useState10 } from "react";
19933
+ import { css as css3 } from "@emotion/css";
19934
+ import { useEffect as useEffect17, useRef as useRef13, useState as useState11 } from "react";
19556
19935
  import { createPortal } from "react-dom";
19557
- import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
19558
- var menuStyle = css2`
19936
+ import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
19937
+ var menuStyle = css3`
19559
19938
  background: #222;
19560
19939
  color: #eee;
19561
19940
  border: 1px solid #555;
@@ -19565,7 +19944,7 @@ var menuStyle = css2`
19565
19944
  box-shadow: 0 4px 16px #0008;
19566
19945
  outline: none;
19567
19946
  `;
19568
- var itemStyle = css2`
19947
+ var itemStyle = css3`
19569
19948
  display: block;
19570
19949
  width: 100%;
19571
19950
  padding: 8px;
@@ -19591,18 +19970,18 @@ var VisibilityContextMenu = ({
19591
19970
  onExitXRayNet
19592
19971
  }) => {
19593
19972
  const engine = useRenderingEngine();
19594
- const [rendererOpen, setRendererOpen] = useState10(false);
19973
+ const [rendererOpen, setRendererOpen] = useState11(false);
19595
19974
  const opacity = useGlobalStore((s) => s.hidden_layer_opacity);
19596
19975
  const setOpacity = useGlobalStore((s) => s.setHiddenLayerOpacity);
19597
19976
  const copperPourOpacity = useGlobalStore((s) => s.copper_pour_opacity);
19598
19977
  const setCopperPourOpacity = useGlobalStore((s) => s.setCopperPourOpacity);
19599
19978
  const showCopperPours = useGlobalStore((s) => s.is_showing_copper_pours);
19600
19979
  const setShowCopperPours = useGlobalStore((s) => s.setIsShowingCopperPours);
19601
- const [copperPourOpacityOpen, setCopperPourOpacityOpen] = useState10(false);
19980
+ const [copperPourOpacityOpen, setCopperPourOpacityOpen] = useState11(false);
19602
19981
  const effectiveCopperPourOpacity = showCopperPours ? copperPourOpacity : 0;
19603
- const [visibilityOpen, setVisibilityOpen] = useState10(false);
19604
- const [opacityOpen, setOpacityOpen] = useState10(false);
19605
- const ref = useRef12(null);
19982
+ const [visibilityOpen, setVisibilityOpen] = useState11(false);
19983
+ const [opacityOpen, setOpacityOpen] = useState11(false);
19984
+ const ref = useRef13(null);
19606
19985
  const stacked = window.innerWidth < 480;
19607
19986
  const openLeft = !stacked && position.x + 460 > window.innerWidth;
19608
19987
  const submenuStyle = stacked ? { position: "relative" } : {
@@ -19610,7 +19989,7 @@ var VisibilityContextMenu = ({
19610
19989
  top: 0,
19611
19990
  ...openLeft ? { right: "100%" } : { left: "100%" }
19612
19991
  };
19613
- useEffect16(() => {
19992
+ useEffect17(() => {
19614
19993
  const dismiss = (event) => {
19615
19994
  if (!ref.current?.contains(event.target)) {
19616
19995
  event.preventDefault();
@@ -19636,7 +20015,7 @@ var VisibilityContextMenu = ({
19636
20015
  };
19637
20016
  }, [onClose]);
19638
20017
  return createPortal(
19639
- /* @__PURE__ */ jsxs15(
20018
+ /* @__PURE__ */ jsxs16(
19640
20019
  "div",
19641
20020
  {
19642
20021
  ref,
@@ -19702,7 +20081,7 @@ var VisibilityContextMenu = ({
19702
20081
  ...stacked ? { overflowY: "auto" } : {}
19703
20082
  },
19704
20083
  children: [
19705
- onXRayNet && /* @__PURE__ */ jsxs15(
20084
+ onXRayNet && /* @__PURE__ */ jsxs16(
19706
20085
  "button",
19707
20086
  {
19708
20087
  type: "button",
@@ -19719,7 +20098,7 @@ var VisibilityContextMenu = ({
19719
20098
  ]
19720
20099
  }
19721
20100
  ),
19722
- onXRayGroup && xRayGroups.map((group) => /* @__PURE__ */ jsxs15(
20101
+ onXRayGroup && xRayGroups.map((group) => /* @__PURE__ */ jsxs16(
19723
20102
  "button",
19724
20103
  {
19725
20104
  type: "button",
@@ -19737,7 +20116,7 @@ var VisibilityContextMenu = ({
19737
20116
  },
19738
20117
  group.id
19739
20118
  )),
19740
- onExitXRayNet && /* @__PURE__ */ jsx22(
20119
+ onExitXRayNet && /* @__PURE__ */ jsx23(
19741
20120
  "button",
19742
20121
  {
19743
20122
  type: "button",
@@ -19750,7 +20129,7 @@ var VisibilityContextMenu = ({
19750
20129
  children: "Exit X-Ray Net"
19751
20130
  }
19752
20131
  ),
19753
- /* @__PURE__ */ jsxs15(
20132
+ /* @__PURE__ */ jsxs16(
19754
20133
  "div",
19755
20134
  {
19756
20135
  style: { position: "relative" },
@@ -19759,7 +20138,7 @@ var VisibilityContextMenu = ({
19759
20138
  setRendererOpen(false);
19760
20139
  },
19761
20140
  children: [
19762
- /* @__PURE__ */ jsx22(
20141
+ /* @__PURE__ */ jsx23(
19763
20142
  "button",
19764
20143
  {
19765
20144
  type: "button",
@@ -19774,7 +20153,7 @@ var VisibilityContextMenu = ({
19774
20153
  children: "Visibility \u25B8"
19775
20154
  }
19776
20155
  ),
19777
- visibilityOpen && /* @__PURE__ */ jsxs15(
20156
+ visibilityOpen && /* @__PURE__ */ jsxs16(
19778
20157
  "div",
19779
20158
  {
19780
20159
  role: "menu",
@@ -19782,7 +20161,7 @@ var VisibilityContextMenu = ({
19782
20161
  className: menuStyle,
19783
20162
  style: submenuStyle,
19784
20163
  children: [
19785
- /* @__PURE__ */ jsxs15(
20164
+ /* @__PURE__ */ jsxs16(
19786
20165
  "div",
19787
20166
  {
19788
20167
  style: { position: "relative" },
@@ -19791,7 +20170,7 @@ var VisibilityContextMenu = ({
19791
20170
  setCopperPourOpacityOpen(false);
19792
20171
  },
19793
20172
  children: [
19794
- /* @__PURE__ */ jsx22(
20173
+ /* @__PURE__ */ jsx23(
19795
20174
  "button",
19796
20175
  {
19797
20176
  type: "button",
@@ -19806,7 +20185,7 @@ var VisibilityContextMenu = ({
19806
20185
  children: "Hidden Layer Visibility \u25B8"
19807
20186
  }
19808
20187
  ),
19809
- opacityOpen && /* @__PURE__ */ jsx22(
20188
+ opacityOpen && /* @__PURE__ */ jsx23(
19810
20189
  "div",
19811
20190
  {
19812
20191
  role: "menu",
@@ -19816,7 +20195,7 @@ var VisibilityContextMenu = ({
19816
20195
  minWidth: 80,
19817
20196
  ...submenuStyle
19818
20197
  },
19819
- children: [0, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1].map((value) => /* @__PURE__ */ jsxs15(
20198
+ children: [0, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1].map((value) => /* @__PURE__ */ jsxs16(
19820
20199
  "button",
19821
20200
  {
19822
20201
  type: "button",
@@ -19828,7 +20207,7 @@ var VisibilityContextMenu = ({
19828
20207
  onClose();
19829
20208
  },
19830
20209
  children: [
19831
- /* @__PURE__ */ jsx22(
20210
+ /* @__PURE__ */ jsx23(
19832
20211
  "span",
19833
20212
  {
19834
20213
  "aria-hidden": "true",
@@ -19846,7 +20225,7 @@ var VisibilityContextMenu = ({
19846
20225
  ]
19847
20226
  }
19848
20227
  ),
19849
- /* @__PURE__ */ jsxs15(
20228
+ /* @__PURE__ */ jsxs16(
19850
20229
  "div",
19851
20230
  {
19852
20231
  style: { position: "relative" },
@@ -19855,7 +20234,7 @@ var VisibilityContextMenu = ({
19855
20234
  setOpacityOpen(false);
19856
20235
  },
19857
20236
  children: [
19858
- /* @__PURE__ */ jsx22(
20237
+ /* @__PURE__ */ jsx23(
19859
20238
  "button",
19860
20239
  {
19861
20240
  type: "button",
@@ -19870,14 +20249,14 @@ var VisibilityContextMenu = ({
19870
20249
  children: "Copper Pour Visibility \u25B8"
19871
20250
  }
19872
20251
  ),
19873
- copperPourOpacityOpen && /* @__PURE__ */ jsx22(
20252
+ copperPourOpacityOpen && /* @__PURE__ */ jsx23(
19874
20253
  "div",
19875
20254
  {
19876
20255
  role: "menu",
19877
20256
  "aria-label": "Copper Pour Visibility",
19878
20257
  className: menuStyle,
19879
20258
  style: { minWidth: 80, ...submenuStyle },
19880
- children: [0, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1].map((value) => /* @__PURE__ */ jsxs15(
20259
+ children: [0, 0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 1].map((value) => /* @__PURE__ */ jsxs16(
19881
20260
  "button",
19882
20261
  {
19883
20262
  type: "button",
@@ -19890,7 +20269,7 @@ var VisibilityContextMenu = ({
19890
20269
  onClose();
19891
20270
  },
19892
20271
  children: [
19893
- /* @__PURE__ */ jsx22(
20272
+ /* @__PURE__ */ jsx23(
19894
20273
  "span",
19895
20274
  {
19896
20275
  "aria-hidden": "true",
@@ -19914,7 +20293,7 @@ var VisibilityContextMenu = ({
19914
20293
  ]
19915
20294
  }
19916
20295
  ),
19917
- engine && /* @__PURE__ */ jsxs15(
20296
+ engine && /* @__PURE__ */ jsxs16(
19918
20297
  "div",
19919
20298
  {
19920
20299
  style: { position: "relative" },
@@ -19923,7 +20302,7 @@ var VisibilityContextMenu = ({
19923
20302
  setVisibilityOpen(false);
19924
20303
  },
19925
20304
  children: [
19926
- /* @__PURE__ */ jsx22(
20305
+ /* @__PURE__ */ jsx23(
19927
20306
  "button",
19928
20307
  {
19929
20308
  type: "button",
@@ -19938,14 +20317,14 @@ var VisibilityContextMenu = ({
19938
20317
  children: "Rendering Engine \u25B8"
19939
20318
  }
19940
20319
  ),
19941
- rendererOpen && /* @__PURE__ */ jsx22(
20320
+ rendererOpen && /* @__PURE__ */ jsx23(
19942
20321
  "div",
19943
20322
  {
19944
20323
  role: "menu",
19945
20324
  "aria-label": "Rendering Engine",
19946
20325
  className: menuStyle,
19947
20326
  style: submenuStyle,
19948
- children: ["canvas", "webgpu"].map((renderer) => /* @__PURE__ */ jsxs15(
20327
+ children: ["canvas", "webgpu"].map((renderer) => /* @__PURE__ */ jsxs16(
19949
20328
  "button",
19950
20329
  {
19951
20330
  type: "button",
@@ -19957,7 +20336,7 @@ var VisibilityContextMenu = ({
19957
20336
  onClose();
19958
20337
  },
19959
20338
  children: [
19960
- /* @__PURE__ */ jsx22(
20339
+ /* @__PURE__ */ jsx23(
19961
20340
  "span",
19962
20341
  {
19963
20342
  "aria-hidden": "true",
@@ -19975,7 +20354,7 @@ var VisibilityContextMenu = ({
19975
20354
  ]
19976
20355
  }
19977
20356
  ),
19978
- component && onViewSchematicComponent && /* @__PURE__ */ jsxs15(
20357
+ component && onViewSchematicComponent && /* @__PURE__ */ jsxs16(
19979
20358
  "button",
19980
20359
  {
19981
20360
  type: "button",
@@ -19991,7 +20370,7 @@ var VisibilityContextMenu = ({
19991
20370
  });
19992
20371
  },
19993
20372
  children: [
19994
- /* @__PURE__ */ jsx22(
20373
+ /* @__PURE__ */ jsx23(
19995
20374
  "svg",
19996
20375
  {
19997
20376
  "aria-hidden": "true",
@@ -20004,7 +20383,7 @@ var VisibilityContextMenu = ({
20004
20383
  strokeLinecap: "round",
20005
20384
  strokeLinejoin: "round",
20006
20385
  style: { verticalAlign: "-1px", marginRight: 5 },
20007
- children: /* @__PURE__ */ jsx22("path", { d: "M5 11 11 5M5 5h6v6" })
20386
+ children: /* @__PURE__ */ jsx23("path", { d: "M5 11 11 5M5 5h6v6" })
20008
20387
  }
20009
20388
  ),
20010
20389
  component.refdes,
@@ -20012,7 +20391,7 @@ var VisibilityContextMenu = ({
20012
20391
  ]
20013
20392
  }
20014
20393
  ),
20015
- component?.manufacturer_part_number && /* @__PURE__ */ jsxs15(
20394
+ component?.manufacturer_part_number && /* @__PURE__ */ jsxs16(
20016
20395
  "button",
20017
20396
  {
20018
20397
  type: "button",
@@ -20042,13 +20421,13 @@ var VisibilityContextMenu = ({
20042
20421
  };
20043
20422
 
20044
20423
  // src/components/ToolbarOverlay.tsx
20045
- import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
20424
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
20046
20425
  var LayerButton = ({ name, selected, onClick }) => {
20047
20426
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
20048
- return /* @__PURE__ */ jsxs16(
20427
+ return /* @__PURE__ */ jsxs17(
20049
20428
  "div",
20050
20429
  {
20051
- className: css3`
20430
+ className: css4`
20052
20431
  margin-top: 2px;
20053
20432
  padding: 4px;
20054
20433
  padding-left: 8px;
@@ -20062,8 +20441,8 @@ var LayerButton = ({ name, selected, onClick }) => {
20062
20441
  ...touchHandlers,
20063
20442
  style: touchStyle,
20064
20443
  children: [
20065
- /* @__PURE__ */ jsx23("span", { style: { marginRight: 2, opacity: selected ? 1 : 0 }, children: "\u2022" }),
20066
- /* @__PURE__ */ jsx23(
20444
+ /* @__PURE__ */ jsx24("span", { style: { marginRight: 2, opacity: selected ? 1 : 0 }, children: "\u2022" }),
20445
+ /* @__PURE__ */ jsx24(
20067
20446
  "span",
20068
20447
  {
20069
20448
  style: {
@@ -20084,10 +20463,10 @@ var CheckboxMenuItem = ({
20084
20463
  onClick
20085
20464
  }) => {
20086
20465
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
20087
- return /* @__PURE__ */ jsxs16(
20466
+ return /* @__PURE__ */ jsxs17(
20088
20467
  "div",
20089
20468
  {
20090
- className: css3`
20469
+ className: css4`
20091
20470
  margin-top: 2px;
20092
20471
  padding: 4px;
20093
20472
  padding-left: 8px;
@@ -20104,19 +20483,19 @@ var CheckboxMenuItem = ({
20104
20483
  ...touchHandlers,
20105
20484
  style: touchStyle,
20106
20485
  children: [
20107
- /* @__PURE__ */ jsx23("input", { type: "checkbox", checked, onChange: () => {
20486
+ /* @__PURE__ */ jsx24("input", { type: "checkbox", checked, onChange: () => {
20108
20487
  }, readOnly: true }),
20109
- /* @__PURE__ */ jsx23("span", { style: { color: "#eee" }, children: label })
20488
+ /* @__PURE__ */ jsx24("span", { style: { color: "#eee" }, children: label })
20110
20489
  ]
20111
20490
  }
20112
20491
  );
20113
20492
  };
20114
20493
  var RadioMenuItem = ({ label, checked, onClick }) => {
20115
20494
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
20116
- return /* @__PURE__ */ jsxs16(
20495
+ return /* @__PURE__ */ jsxs17(
20117
20496
  "div",
20118
20497
  {
20119
- className: css3`
20498
+ className: css4`
20120
20499
  margin-top: 2px;
20121
20500
  padding: 4px;
20122
20501
  padding-left: 8px;
@@ -20133,9 +20512,9 @@ var RadioMenuItem = ({ label, checked, onClick }) => {
20133
20512
  ...touchHandlers,
20134
20513
  style: touchStyle,
20135
20514
  children: [
20136
- /* @__PURE__ */ jsx23("input", { type: "radio", checked, onChange: () => {
20515
+ /* @__PURE__ */ jsx24("input", { type: "radio", checked, onChange: () => {
20137
20516
  }, readOnly: true }),
20138
- /* @__PURE__ */ jsx23("span", { style: { color: "#eee" }, children: label })
20517
+ /* @__PURE__ */ jsx24("span", { style: { color: "#eee" }, children: label })
20139
20518
  ]
20140
20519
  }
20141
20520
  );
@@ -20143,6 +20522,7 @@ var RadioMenuItem = ({ label, checked, onClick }) => {
20143
20522
  var ToolbarOverlay = ({
20144
20523
  children,
20145
20524
  elements,
20525
+ onSearchComponent,
20146
20526
  onContextMenuOpenChange,
20147
20527
  getNetAtPoint,
20148
20528
  getComponentAtPoint,
@@ -20211,11 +20591,11 @@ var ToolbarOverlay = ({
20211
20591
  setHoveredErrorId: s.setHoveredErrorId,
20212
20592
  setFocusedErrorId: s.setFocusedErrorId
20213
20593
  }));
20214
- const [contextMenuPosition, setContextMenuPosition] = useState11(null);
20215
- const [contextGroups, setContextGroups] = useState11([]);
20216
- const [contextNetId, setContextNetId] = useState11();
20217
- const [contextNetDisplayName, setContextNetDisplayName] = useState11("Net");
20218
- const [contextComponent, setContextComponent] = useState11();
20594
+ const [contextMenuPosition, setContextMenuPosition] = useState12(null);
20595
+ const [contextGroups, setContextGroups] = useState12([]);
20596
+ const [contextNetId, setContextNetId] = useState12();
20597
+ const [contextNetDisplayName, setContextNetDisplayName] = useState12("Net");
20598
+ const [contextComponent, setContextComponent] = useState12();
20219
20599
  const componentAtEvent = (event) => {
20220
20600
  const rect = event.currentTarget.getBoundingClientRect();
20221
20601
  return getComponentAtPoint?.({
@@ -20223,7 +20603,7 @@ var ToolbarOverlay = ({
20223
20603
  y: event.clientY - rect.top
20224
20604
  });
20225
20605
  };
20226
- const pointerStart = useRef13(null);
20606
+ const pointerStart = useRef14(null);
20227
20607
  const inEditMode = useGlobalStore((s) => s.in_edit_mode);
20228
20608
  const netAtEvent = (event) => {
20229
20609
  const rect = event.currentTarget.getBoundingClientRect();
@@ -20236,12 +20616,12 @@ var ToolbarOverlay = ({
20236
20616
  setContextMenuPosition(null);
20237
20617
  onContextMenuOpenChange?.(false);
20238
20618
  }, [onContextMenuOpenChange]);
20239
- const [isViewMenuOpen, setViewMenuOpen] = useState11(false);
20240
- const [isLayerMenuOpen, setLayerMenuOpen] = useState11(false);
20241
- const [isErrorsOpen, setErrorsOpen] = useState11(false);
20242
- const [measureToolArmed, setMeasureToolArmed] = useState11(false);
20243
- const [boundsToolArmed, setBoundsToolArmed] = useState11(false);
20244
- useEffect17(() => {
20619
+ const [isViewMenuOpen, setViewMenuOpen] = useState12(false);
20620
+ const [isLayerMenuOpen, setLayerMenuOpen] = useState12(false);
20621
+ const [isErrorsOpen, setErrorsOpen] = useState12(false);
20622
+ const [measureToolArmed, setMeasureToolArmed] = useState12(false);
20623
+ const [boundsToolArmed, setBoundsToolArmed] = useState12(false);
20624
+ useEffect18(() => {
20245
20625
  const arm = () => setMeasureToolArmed(true);
20246
20626
  const disarm = () => setMeasureToolArmed(false);
20247
20627
  const armBounds = () => setBoundsToolArmed(true);
@@ -20257,13 +20637,13 @@ var ToolbarOverlay = ({
20257
20637
  window.removeEventListener("disarm-bounds-tool", disarmBounds);
20258
20638
  };
20259
20639
  }, []);
20260
- const availableLayers = useMemo12(
20640
+ const availableLayers = useMemo13(
20261
20641
  () => getCopperLayerRefsFromElements(elements ?? []),
20262
20642
  [elements]
20263
20643
  );
20264
20644
  const processedLayers = availableLayers;
20265
- const hasRunInitialMouseCheck = useRef13(false);
20266
- const hotkeyBoundaryRef = useRef13(null);
20645
+ const hasRunInitialMouseCheck = useRef14(false);
20646
+ const hotkeyBoundaryRef = useRef14(null);
20267
20647
  const hotKeyCallbacks = {
20268
20648
  "1": availableLayers[0] ? () => selectLayer(availableLayers[0]) : () => {
20269
20649
  },
@@ -20370,7 +20750,7 @@ var ToolbarOverlay = ({
20370
20750
  },
20371
20751
  []
20372
20752
  );
20373
- return /* @__PURE__ */ jsxs16(
20753
+ return /* @__PURE__ */ jsxs17(
20374
20754
  "div",
20375
20755
  {
20376
20756
  ref: hotkeyBoundaryRef,
@@ -20427,7 +20807,7 @@ var ToolbarOverlay = ({
20427
20807
  onMouseMove: handleMouseMove,
20428
20808
  children: [
20429
20809
  children,
20430
- contextMenuPosition && /* @__PURE__ */ jsx23(
20810
+ contextMenuPosition && /* @__PURE__ */ jsx24(
20431
20811
  VisibilityContextMenu,
20432
20812
  {
20433
20813
  position: contextMenuPosition,
@@ -20443,7 +20823,7 @@ var ToolbarOverlay = ({
20443
20823
  onExitXRayNet: xRayNetIds.length > 0 ? () => onXRayNetsChange?.([]) : void 0
20444
20824
  }
20445
20825
  ),
20446
- /* @__PURE__ */ jsxs16(
20826
+ /* @__PURE__ */ jsxs17(
20447
20827
  "div",
20448
20828
  {
20449
20829
  style: {
@@ -20464,10 +20844,11 @@ var ToolbarOverlay = ({
20464
20844
  ]
20465
20845
  }
20466
20846
  ),
20467
- /* @__PURE__ */ jsxs16(
20847
+ /* @__PURE__ */ jsxs17(
20468
20848
  "div",
20469
20849
  {
20470
20850
  "data-toolbar-overlay": true,
20851
+ className: css4`&:focus-within { opacity: 1 !important; }`,
20471
20852
  onTouchStart: (e) => e.stopPropagation(),
20472
20853
  onTouchEnd: (e) => e.stopPropagation(),
20473
20854
  onTouchMove: (e) => e.stopPropagation(),
@@ -20495,7 +20876,7 @@ var ToolbarOverlay = ({
20495
20876
  fontFamily: "sans-serif"
20496
20877
  },
20497
20878
  children: [
20498
- /* @__PURE__ */ jsxs16(
20879
+ /* @__PURE__ */ jsxs17(
20499
20880
  ToolbarButton,
20500
20881
  {
20501
20882
  isSmallScreen,
@@ -20506,10 +20887,10 @@ var ToolbarOverlay = ({
20506
20887
  }
20507
20888
  },
20508
20889
  children: [
20509
- /* @__PURE__ */ jsxs16("div", { children: [
20890
+ /* @__PURE__ */ jsxs17("div", { children: [
20510
20891
  "layer:",
20511
20892
  " ",
20512
- /* @__PURE__ */ jsx23(
20893
+ /* @__PURE__ */ jsx24(
20513
20894
  "span",
20514
20895
  {
20515
20896
  style: {
@@ -20521,7 +20902,7 @@ var ToolbarOverlay = ({
20521
20902
  }
20522
20903
  )
20523
20904
  ] }),
20524
- isLayerMenuOpen && /* @__PURE__ */ jsx23("div", { style: { marginTop: 4, minWidth: 120 }, children: processedLayers.map((layer) => /* @__PURE__ */ jsx23(
20905
+ isLayerMenuOpen && /* @__PURE__ */ jsx24("div", { style: { marginTop: 4, minWidth: 120 }, children: processedLayers.map((layer) => /* @__PURE__ */ jsx24(
20525
20906
  LayerButton,
20526
20907
  {
20527
20908
  name: layer,
@@ -20535,7 +20916,14 @@ var ToolbarOverlay = ({
20535
20916
  ]
20536
20917
  }
20537
20918
  ),
20538
- /* @__PURE__ */ jsx23(
20919
+ onSearchComponent && /* @__PURE__ */ jsx24(
20920
+ ComponentSearch,
20921
+ {
20922
+ elements: elements ?? [],
20923
+ onSelect: onSearchComponent
20924
+ }
20925
+ ),
20926
+ /* @__PURE__ */ jsx24(
20539
20927
  ToolbarErrorDropdown,
20540
20928
  {
20541
20929
  elements,
@@ -20547,44 +20935,44 @@ var ToolbarOverlay = ({
20547
20935
  setFocusedErrorId
20548
20936
  }
20549
20937
  ),
20550
- /* @__PURE__ */ jsx23(
20938
+ /* @__PURE__ */ jsx24(
20551
20939
  ToolbarButton,
20552
20940
  {
20553
20941
  isSmallScreen,
20554
20942
  style: {},
20555
20943
  onClick: handleRatsNestToggle,
20556
- children: /* @__PURE__ */ jsxs16("div", { children: [
20944
+ children: /* @__PURE__ */ jsxs17("div", { children: [
20557
20945
  viewSettings.is_showing_rats_nest ? "\u2716 " : "",
20558
20946
  "Rats Nest"
20559
20947
  ] })
20560
20948
  }
20561
20949
  ),
20562
- /* @__PURE__ */ jsx23(
20950
+ /* @__PURE__ */ jsx24(
20563
20951
  ToolbarButton,
20564
20952
  {
20565
20953
  isSmallScreen,
20566
20954
  style: measureToolArmed ? { backgroundColor: "#444" } : {},
20567
20955
  onClick: handleMeasureToolClick,
20568
- children: /* @__PURE__ */ jsx23("div", { children: "\u{1F4CF}" })
20956
+ children: /* @__PURE__ */ jsx24("div", { children: "\u{1F4CF}" })
20569
20957
  }
20570
20958
  ),
20571
- /* @__PURE__ */ jsx23(
20959
+ /* @__PURE__ */ jsx24(
20572
20960
  ToolbarButton,
20573
20961
  {
20574
20962
  isSmallScreen,
20575
20963
  style: boundsToolArmed ? { backgroundColor: "#444" } : {},
20576
20964
  onClick: handleBoundsToolClick,
20577
- children: /* @__PURE__ */ jsx23("div", { children: "Bounds" })
20965
+ children: /* @__PURE__ */ jsx24("div", { children: "Bounds" })
20578
20966
  }
20579
20967
  ),
20580
- /* @__PURE__ */ jsx23(
20968
+ /* @__PURE__ */ jsx24(
20581
20969
  ToolbarButton,
20582
20970
  {
20583
20971
  "data-view-menu": true,
20584
20972
  isSmallScreen,
20585
20973
  onClick: handleViewMenuToggle,
20586
- children: /* @__PURE__ */ jsxs16("div", { children: [
20587
- /* @__PURE__ */ jsxs16(
20974
+ children: /* @__PURE__ */ jsxs17("div", { children: [
20975
+ /* @__PURE__ */ jsxs17(
20588
20976
  "div",
20589
20977
  {
20590
20978
  style: {
@@ -20594,7 +20982,7 @@ var ToolbarOverlay = ({
20594
20982
  },
20595
20983
  children: [
20596
20984
  "View",
20597
- /* @__PURE__ */ jsx23(
20985
+ /* @__PURE__ */ jsx24(
20598
20986
  "span",
20599
20987
  {
20600
20988
  style: {
@@ -20609,8 +20997,8 @@ var ToolbarOverlay = ({
20609
20997
  ]
20610
20998
  }
20611
20999
  ),
20612
- isViewMenuOpen && /* @__PURE__ */ jsxs16("div", { style: { marginTop: 4, minWidth: 120 }, children: [
20613
- /* @__PURE__ */ jsx23(
21000
+ isViewMenuOpen && /* @__PURE__ */ jsxs17("div", { style: { marginTop: 4, minWidth: 120 }, children: [
21001
+ /* @__PURE__ */ jsx24(
20614
21002
  CheckboxMenuItem,
20615
21003
  {
20616
21004
  label: "Show All Trace Lengths",
@@ -20622,7 +21010,7 @@ var ToolbarOverlay = ({
20622
21010
  }
20623
21011
  }
20624
21012
  ),
20625
- /* @__PURE__ */ jsx23(
21013
+ /* @__PURE__ */ jsx24(
20626
21014
  CheckboxMenuItem,
20627
21015
  {
20628
21016
  label: "Show Autorouting Animation",
@@ -20634,7 +21022,7 @@ var ToolbarOverlay = ({
20634
21022
  }
20635
21023
  }
20636
21024
  ),
20637
- /* @__PURE__ */ jsx23(
21025
+ /* @__PURE__ */ jsx24(
20638
21026
  CheckboxMenuItem,
20639
21027
  {
20640
21028
  label: "Show DRC Errors",
@@ -20644,7 +21032,7 @@ var ToolbarOverlay = ({
20644
21032
  }
20645
21033
  }
20646
21034
  ),
20647
- /* @__PURE__ */ jsx23(
21035
+ /* @__PURE__ */ jsx24(
20648
21036
  CheckboxMenuItem,
20649
21037
  {
20650
21038
  label: "Show DRC Warnings",
@@ -20656,7 +21044,7 @@ var ToolbarOverlay = ({
20656
21044
  }
20657
21045
  }
20658
21046
  ),
20659
- /* @__PURE__ */ jsx23(
21047
+ /* @__PURE__ */ jsx24(
20660
21048
  CheckboxMenuItem,
20661
21049
  {
20662
21050
  label: "Show Copper Pours",
@@ -20668,7 +21056,7 @@ var ToolbarOverlay = ({
20668
21056
  }
20669
21057
  }
20670
21058
  ),
20671
- /* @__PURE__ */ jsx23(
21059
+ /* @__PURE__ */ jsx24(
20672
21060
  CheckboxMenuItem,
20673
21061
  {
20674
21062
  label: "Show Courtyards",
@@ -20678,7 +21066,7 @@ var ToolbarOverlay = ({
20678
21066
  }
20679
21067
  }
20680
21068
  ),
20681
- /* @__PURE__ */ jsx23(
21069
+ /* @__PURE__ */ jsx24(
20682
21070
  CheckboxMenuItem,
20683
21071
  {
20684
21072
  label: "Show Solder Mask",
@@ -20688,7 +21076,7 @@ var ToolbarOverlay = ({
20688
21076
  }
20689
21077
  }
20690
21078
  ),
20691
- /* @__PURE__ */ jsx23(
21079
+ /* @__PURE__ */ jsx24(
20692
21080
  CheckboxMenuItem,
20693
21081
  {
20694
21082
  label: "Show Silkscreen",
@@ -20698,7 +21086,7 @@ var ToolbarOverlay = ({
20698
21086
  }
20699
21087
  }
20700
21088
  ),
20701
- /* @__PURE__ */ jsx23(
21089
+ /* @__PURE__ */ jsx24(
20702
21090
  CheckboxMenuItem,
20703
21091
  {
20704
21092
  label: "Show Fabrication Notes",
@@ -20710,7 +21098,7 @@ var ToolbarOverlay = ({
20710
21098
  }
20711
21099
  }
20712
21100
  ),
20713
- /* @__PURE__ */ jsx23(
21101
+ /* @__PURE__ */ jsx24(
20714
21102
  CheckboxMenuItem,
20715
21103
  {
20716
21104
  label: "Show PCB Notes",
@@ -20720,7 +21108,7 @@ var ToolbarOverlay = ({
20720
21108
  }
20721
21109
  }
20722
21110
  ),
20723
- /* @__PURE__ */ jsx23(
21111
+ /* @__PURE__ */ jsx24(
20724
21112
  CheckboxMenuItem,
20725
21113
  {
20726
21114
  label: "Show Group Anchor Offsets",
@@ -20732,7 +21120,7 @@ var ToolbarOverlay = ({
20732
21120
  }
20733
21121
  }
20734
21122
  ),
20735
- /* @__PURE__ */ jsx23(
21123
+ /* @__PURE__ */ jsx24(
20736
21124
  CheckboxMenuItem,
20737
21125
  {
20738
21126
  label: "Show PCB Groups",
@@ -20742,8 +21130,8 @@ var ToolbarOverlay = ({
20742
21130
  }
20743
21131
  }
20744
21132
  ),
20745
- viewSettings.is_showing_pcb_groups && /* @__PURE__ */ jsxs16("div", { style: { marginLeft: 16 }, children: [
20746
- /* @__PURE__ */ jsx23(
21133
+ viewSettings.is_showing_pcb_groups && /* @__PURE__ */ jsxs17("div", { style: { marginLeft: 16 }, children: [
21134
+ /* @__PURE__ */ jsx24(
20747
21135
  RadioMenuItem,
20748
21136
  {
20749
21137
  label: "Show All Groups",
@@ -20753,7 +21141,7 @@ var ToolbarOverlay = ({
20753
21141
  }
20754
21142
  }
20755
21143
  ),
20756
- /* @__PURE__ */ jsx23(
21144
+ /* @__PURE__ */ jsx24(
20757
21145
  RadioMenuItem,
20758
21146
  {
20759
21147
  label: "Show Named Groups",
@@ -20786,20 +21174,20 @@ var getPcbWarningHighlightLabel = (warning) => {
20786
21174
  };
20787
21175
 
20788
21176
  // src/components/WarningGraphicsOverlay.tsx
20789
- import { useEffect as useEffect18, useMemo as useMemo13, useRef as useRef14 } from "react";
20790
- import { applyToPoint as applyToPoint21, identity as identity9 } from "transformation-matrix";
20791
- import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
21177
+ import { useEffect as useEffect19, useMemo as useMemo14, useRef as useRef15 } from "react";
21178
+ import { applyToPoint as applyToPoint22, identity as identity9 } from "transformation-matrix";
21179
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
20792
21180
  var WarningGraphicsOverlay = ({
20793
21181
  children,
20794
21182
  transform = identity9(),
20795
21183
  elements = []
20796
21184
  }) => {
20797
21185
  const [containerRef, { width, height }] = useMeasure_default();
20798
- const canvasRef = useRef14(null);
21186
+ const canvasRef = useRef15(null);
20799
21187
  const isShowingDrcWarnings = useGlobalStore(
20800
21188
  (state) => state.is_showing_drc_warnings
20801
21189
  );
20802
- const { pcbComponentById, warnings } = useMemo13(() => {
21190
+ const { pcbComponentById, warnings } = useMemo14(() => {
20803
21191
  const pcbComponentById2 = /* @__PURE__ */ new Map();
20804
21192
  const warnings2 = [];
20805
21193
  for (const element of elements) {
@@ -20811,7 +21199,7 @@ var WarningGraphicsOverlay = ({
20811
21199
  }
20812
21200
  return { pcbComponentById: pcbComponentById2, warnings: warnings2 };
20813
21201
  }, [elements]);
20814
- useEffect18(() => {
21202
+ useEffect19(() => {
20815
21203
  const canvas = canvasRef.current;
20816
21204
  if (!canvas || !width || !height) return;
20817
21205
  canvas.width = width;
@@ -20825,7 +21213,7 @@ var WarningGraphicsOverlay = ({
20825
21213
  const component = pcbComponentById.get(warning.pcb_component_id);
20826
21214
  if (!component) return;
20827
21215
  const { width: width2, height: height2, center } = component;
20828
- const transformedCenter = applyToPoint21(transform, center);
21216
+ const transformedCenter = applyToPoint22(transform, center);
20829
21217
  const scaledWidth = width2 * Math.abs(transform.a);
20830
21218
  const scaledHeight = height2 * Math.abs(transform.d);
20831
21219
  const boxPadding = 0.1 * Math.abs(transform.a);
@@ -20863,7 +21251,7 @@ var WarningGraphicsOverlay = ({
20863
21251
  width
20864
21252
  ]);
20865
21253
  if (!isShowingDrcWarnings) {
20866
- return /* @__PURE__ */ jsx24(
21254
+ return /* @__PURE__ */ jsx25(
20867
21255
  "div",
20868
21256
  {
20869
21257
  ref: containerRef,
@@ -20872,14 +21260,14 @@ var WarningGraphicsOverlay = ({
20872
21260
  }
20873
21261
  );
20874
21262
  }
20875
- return /* @__PURE__ */ jsxs17(
21263
+ return /* @__PURE__ */ jsxs18(
20876
21264
  "div",
20877
21265
  {
20878
21266
  ref: containerRef,
20879
21267
  style: { position: "relative", width: "100%", height: "100%" },
20880
21268
  children: [
20881
21269
  children,
20882
- /* @__PURE__ */ jsx24(
21270
+ /* @__PURE__ */ jsx25(
20883
21271
  "canvas",
20884
21272
  {
20885
21273
  ref: canvasRef,
@@ -20904,20 +21292,20 @@ var createWebGpuWorker = async () => {
20904
21292
  };
20905
21293
 
20906
21294
  // src/components/WebGpuElementsRenderer.tsx
20907
- import { useEffect as useEffect19, useLayoutEffect as useLayoutEffect3, useMemo as useMemo14, useRef as useRef15, useState as useState12 } from "react";
21295
+ import { useEffect as useEffect20, useLayoutEffect as useLayoutEffect3, useMemo as useMemo15, useRef as useRef16, useState as useState13 } from "react";
20908
21296
  import { SuperGrid as SuperGrid2, toMMSI as toMMSI2 } from "react-supergrid";
20909
- import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
21297
+ import { Fragment as Fragment5, jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
20910
21298
  function WebGpuElementsRenderer(props) {
20911
21299
  const { elements, primitives, transform, width = 500, height = 500 } = props;
20912
- const holder = useRef15(null);
20913
- const workerRef = useRef15(void 0);
20914
- const onRenderCompleteRef = useRef15(props.onRenderComplete);
20915
- const sceneRef = useRef15({ elements, sceneGeneration: 0 });
20916
- const latestSubmittedSceneGenerationRef = useRef15(0);
20917
- const completedSceneGenerationRef = useRef15(0);
20918
- const ready = useRef15(false);
20919
- const [supportsXRayNet, setSupportsXRayNet] = useState12(null);
20920
- const [failure, setFailure] = useState12();
21300
+ const holder = useRef16(null);
21301
+ const workerRef = useRef16(void 0);
21302
+ const onRenderCompleteRef = useRef16(props.onRenderComplete);
21303
+ const sceneRef = useRef16({ elements, sceneGeneration: 0 });
21304
+ const latestSubmittedSceneGenerationRef = useRef16(0);
21305
+ const completedSceneGenerationRef = useRef16(0);
21306
+ const ready = useRef16(false);
21307
+ const [supportsXRayNet, setSupportsXRayNet] = useState13(null);
21308
+ const [failure, setFailure] = useState13();
20921
21309
  const selectedLayer = useGlobalStore((s) => s.selected_layer);
20922
21310
  const hiddenLayerOpacity = useGlobalStore((s) => s.hidden_layer_opacity);
20923
21311
  const copperPourOpacity = useGlobalStore((s) => s.copper_pour_opacity);
@@ -20929,7 +21317,7 @@ function WebGpuElementsRenderer(props) {
20929
21317
  );
20930
21318
  const showPcbNotes = useGlobalStore((s) => s.is_showing_pcb_notes);
20931
21319
  const showCourtyards = useGlobalStore((s) => s.is_showing_courtyards);
20932
- const highlightedElementIds = useMemo14(
21320
+ const highlightedElementIds = useMemo15(
20933
21321
  () => [
20934
21322
  .../* @__PURE__ */ new Set([
20935
21323
  ...props.highlightedCopperPourIds ?? [],
@@ -20943,13 +21331,13 @@ function WebGpuElementsRenderer(props) {
20943
21331
  ],
20944
21332
  [primitives, props.highlightedCopperPourIds]
20945
21333
  );
20946
- const xRayElementIds = useMemo14(
21334
+ const xRayElementIds = useMemo15(
20947
21335
  () => (props.xRayElements ?? []).map(
20948
21336
  (element) => element[`${element.type}_id`]
20949
21337
  ),
20950
21338
  [props.xRayElements]
20951
21339
  );
20952
- const options = useMemo14(
21340
+ const options = useMemo15(
20953
21341
  () => ({
20954
21342
  selectedLayer,
20955
21343
  hiddenLayerOpacity,
@@ -20977,7 +21365,7 @@ function WebGpuElementsRenderer(props) {
20977
21365
  xRayElementIds
20978
21366
  ]
20979
21367
  );
20980
- const viewRef = useRef15(void 0);
21368
+ const viewRef = useRef16(void 0);
20981
21369
  if (transform) {
20982
21370
  const ratio = typeof window === "undefined" ? 1 : window.devicePixelRatio || 1;
20983
21371
  viewRef.current = {
@@ -21009,7 +21397,7 @@ function WebGpuElementsRenderer(props) {
21009
21397
  sceneGeneration
21010
21398
  });
21011
21399
  }, [elements]);
21012
- useEffect19(() => {
21400
+ useEffect20(() => {
21013
21401
  let disposed = false, failed = false, worker;
21014
21402
  const canvas = document.createElement("canvas");
21015
21403
  canvas.className = "pcb-webgpu-canvas";
@@ -21096,14 +21484,14 @@ function WebGpuElementsRenderer(props) {
21096
21484
  canvas.remove();
21097
21485
  };
21098
21486
  }, []);
21099
- useEffect19(() => {
21487
+ useEffect20(() => {
21100
21488
  if (ready.current && viewRef.current)
21101
21489
  workerRef.current?.postMessage(viewRef.current);
21102
21490
  }, [transform, width, height, options]);
21103
21491
  const xRayUnavailable = Boolean(
21104
21492
  props.xRayElements && supportsXRayNet === false
21105
21493
  );
21106
- return /* @__PURE__ */ jsx25(
21494
+ return /* @__PURE__ */ jsx26(
21107
21495
  "div",
21108
21496
  {
21109
21497
  ref: holder,
@@ -21116,18 +21504,18 @@ function WebGpuElementsRenderer(props) {
21116
21504
  position: "relative",
21117
21505
  overflow: "hidden"
21118
21506
  },
21119
- children: failure ? /* @__PURE__ */ jsxs18(
21507
+ children: failure ? /* @__PURE__ */ jsxs19(
21120
21508
  "div",
21121
21509
  {
21122
21510
  role: "alert",
21123
21511
  style: { padding: 16, color: "white", position: "relative" },
21124
21512
  children: [
21125
- /* @__PURE__ */ jsx25("strong", { children: "WebGPU rendering failed" }),
21126
- /* @__PURE__ */ jsx25("div", { children: failure })
21513
+ /* @__PURE__ */ jsx26("strong", { children: "WebGPU rendering failed" }),
21514
+ /* @__PURE__ */ jsx26("div", { children: failure })
21127
21515
  ]
21128
21516
  }
21129
- ) : /* @__PURE__ */ jsxs18(Fragment5, { children: [
21130
- /* @__PURE__ */ jsx25(
21517
+ ) : /* @__PURE__ */ jsxs19(Fragment5, { children: [
21518
+ /* @__PURE__ */ jsx26(
21131
21519
  SuperGrid2,
21132
21520
  {
21133
21521
  textColor: "rgba(0,255,0,0.8)",
@@ -21140,7 +21528,7 @@ function WebGpuElementsRenderer(props) {
21140
21528
  stringifyCoord: (x, y, z) => `${toMMSI2(x, z)}, ${toMMSI2(y, z)}`
21141
21529
  }
21142
21530
  ),
21143
- xRayUnavailable && /* @__PURE__ */ jsx25(
21531
+ xRayUnavailable && /* @__PURE__ */ jsx26(
21144
21532
  "div",
21145
21533
  {
21146
21534
  role: "status",
@@ -21154,14 +21542,14 @@ function WebGpuElementsRenderer(props) {
21154
21542
  }
21155
21543
 
21156
21544
  // src/components/CanvasElementsRenderer.tsx
21157
- import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
21545
+ import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
21158
21546
  function getHitTestCandidates({
21159
21547
  primitiveSpatialIndex,
21160
21548
  screenPoint,
21161
21549
  transform
21162
21550
  }) {
21163
21551
  if (!transform) return null;
21164
- const realWorldPoint = applyToPoint22(inverse6(transform), screenPoint);
21552
+ const realWorldPoint = applyToPoint23(inverse6(transform), screenPoint);
21165
21553
  return {
21166
21554
  primitives: getPrimitivesNearPoint({
21167
21555
  point: realWorldPoint,
@@ -21187,23 +21575,23 @@ var CanvasElementsRenderer = (props) => {
21187
21575
  selectedLayer: state.selected_layer
21188
21576
  }));
21189
21577
  const activeErrorId = focusedErrorId ?? hoveredErrorId;
21190
- const elementsToRender = useMemo15(
21578
+ const elementsToRender = useMemo16(
21191
21579
  () => isShowingCopperPours ? elements : elements.filter((elm) => elm.type !== "pcb_copper_pour"),
21192
21580
  [elements, isShowingCopperPours]
21193
21581
  );
21194
- const primitivesWithoutInteractionMetadata = useMemo15(() => {
21582
+ const primitivesWithoutInteractionMetadata = useMemo16(() => {
21195
21583
  const metadataIndex = createPrimitiveMetadataIndex(elements);
21196
21584
  return elementsToRender.flatMap(
21197
21585
  (element) => convertElementToPrimitives(element, elements, metadataIndex)
21198
21586
  );
21199
21587
  }, [elementsToRender, elements]);
21200
- const connectivityMap = useMemo15(
21588
+ const connectivityMap = useMemo16(
21201
21589
  () => getFullConnectivityMapFromCircuitJson(elements),
21202
21590
  [elements]
21203
21591
  );
21204
- const [xRayNetIds, setXRayNetIds] = useState13([]);
21205
- useEffect20(() => setXRayNetIds([]), [connectivityMap]);
21206
- useEffect20(() => {
21592
+ const [xRayNetIds, setXRayNetIds] = useState14([]);
21593
+ useEffect21(() => setXRayNetIds([]), [connectivityMap]);
21594
+ useEffect21(() => {
21207
21595
  if (xRayNetIds.length === 0) return;
21208
21596
  const onKeyDown = (event) => {
21209
21597
  if (event.key === "Escape") setXRayNetIds([]);
@@ -21211,7 +21599,7 @@ var CanvasElementsRenderer = (props) => {
21211
21599
  window.addEventListener("keydown", onKeyDown, true);
21212
21600
  return () => window.removeEventListener("keydown", onKeyDown, true);
21213
21601
  }, [xRayNetIds.length]);
21214
- const xRayElements = useMemo15(
21602
+ const xRayElements = useMemo16(
21215
21603
  () => xRayNetIds.length > 0 ? elementsToRender.filter(
21216
21604
  (element) => isXRayCopper(element) && (element.type !== "pcb_copper_pour" || copperPourOpacity > 0) && xRayNetIds.includes(
21217
21605
  getElementNetId(element, connectivityMap) ?? ""
@@ -21219,14 +21607,14 @@ var CanvasElementsRenderer = (props) => {
21219
21607
  ) : void 0,
21220
21608
  [elementsToRender, connectivityMap, xRayNetIds, copperPourOpacity]
21221
21609
  );
21222
- const hoverPrimitives = useMemo15(() => {
21610
+ const hoverPrimitives = useMemo16(() => {
21223
21611
  if (!xRayElements) return primitivesWithoutInteractionMetadata;
21224
21612
  const selectedElements = new Set(xRayElements);
21225
21613
  return primitivesWithoutInteractionMetadata.filter(
21226
21614
  (primitive) => (primitive._element?.type === "pcb_smtpad" || primitive._element?.type === "pcb_plated_hole") && selectedElements.has(primitive._element)
21227
21615
  );
21228
21616
  }, [primitivesWithoutInteractionMetadata, xRayElements]);
21229
- const primitiveSpatialIndex = useMemo15(
21617
+ const primitiveSpatialIndex = useMemo16(
21230
21618
  () => createPrimitiveSpatialIndex(primitivesWithoutInteractionMetadata),
21231
21619
  [primitivesWithoutInteractionMetadata]
21232
21620
  );
@@ -21265,7 +21653,7 @@ var CanvasElementsRenderer = (props) => {
21265
21653
  if (isShowingCopperPours && copperPourOpacity > 0) {
21266
21654
  for (const pour of getCopperPoursUnderPoint(
21267
21655
  elementsToRender,
21268
- applyToPoint22(inverse6(transform), point2),
21656
+ applyToPoint23(inverse6(transform), point2),
21269
21657
  selectedLayer
21270
21658
  ).reverse()) {
21271
21659
  const net = getElementNetId(pour, connectivityMap);
@@ -21295,11 +21683,11 @@ var CanvasElementsRenderer = (props) => {
21295
21683
  if (net) return describeNet(net, primitive._element);
21296
21684
  }
21297
21685
  };
21298
- const [hoverState, setHoverState] = useState13({
21686
+ const [hoverState, setHoverState] = useState14({
21299
21687
  drawingObjectIdsWithMouseOver: /* @__PURE__ */ new Set(),
21300
21688
  primitiveIdsInMousedOverNet: []
21301
21689
  });
21302
- const highlightedCopperPourIds = useMemo15(
21690
+ const highlightedCopperPourIds = useMemo16(
21303
21691
  () => xRayNetIds.length > 0 ? [] : getHighlightedCopperPourIds(
21304
21692
  elementsToRender,
21305
21693
  hoverState.primitiveIdsInMousedOverNet,
@@ -21307,14 +21695,14 @@ var CanvasElementsRenderer = (props) => {
21307
21695
  ),
21308
21696
  [elementsToRender, hoverState, connectivityMap, xRayNetIds]
21309
21697
  );
21310
- const [hoveredComponentIds, setHoveredComponentIds] = useState13([]);
21311
- const currentTransformRef = useRef16(transform ?? null);
21312
- const zoomAnimationFrameRef = useRef16(null);
21313
- const elementIndexes = useMemo15(
21698
+ const [hoveredComponentIds, setHoveredComponentIds] = useState14([]);
21699
+ const currentTransformRef = useRef17(transform ?? null);
21700
+ const zoomAnimationFrameRef = useRef17(null);
21701
+ const elementIndexes = useMemo16(
21314
21702
  () => buildErrorPreviewElementIndexes(elements),
21315
21703
  [elements]
21316
21704
  );
21317
- const errorRelatedIds = useMemo15(() => {
21705
+ const errorRelatedIds = useMemo16(() => {
21318
21706
  if (!activeErrorId) return [];
21319
21707
  const errorElements = elements.filter(
21320
21708
  (el) => el.type.includes("error")
@@ -21325,17 +21713,17 @@ var CanvasElementsRenderer = (props) => {
21325
21713
  if (!activeError) return [];
21326
21714
  return getRelatedIdsForError(activeError);
21327
21715
  }, [activeErrorId, elements]);
21328
- useEffect20(() => {
21716
+ useEffect21(() => {
21329
21717
  if (transform) {
21330
21718
  currentTransformRef.current = transform;
21331
21719
  }
21332
21720
  }, [transform]);
21333
- useEffect20(() => {
21721
+ useEffect21(() => {
21334
21722
  return () => {
21335
21723
  cancelTransformAnimation(zoomAnimationFrameRef.current);
21336
21724
  };
21337
21725
  }, []);
21338
- useEffect20(() => {
21726
+ useEffect21(() => {
21339
21727
  if (!props.width || !props.height || !props.setTransform || !focusedErrorId)
21340
21728
  return;
21341
21729
  const focusedError = findErrorElementById(elements, focusedErrorId);
@@ -21373,7 +21761,7 @@ var CanvasElementsRenderer = (props) => {
21373
21761
  props.setTransform,
21374
21762
  props.width
21375
21763
  ]);
21376
- const primitives = useMemo15(() => {
21764
+ const primitives = useMemo16(() => {
21377
21765
  if (xRayNetIds.length > 0) return primitivesWithoutInteractionMetadata;
21378
21766
  const combinedPrimitiveIds = [
21379
21767
  ...hoverState.primitiveIdsInMousedOverNet,
@@ -21423,7 +21811,7 @@ var CanvasElementsRenderer = (props) => {
21423
21811
  },
21424
21812
  [connectivityMap]
21425
21813
  );
21426
- return /* @__PURE__ */ jsxs19(
21814
+ return /* @__PURE__ */ jsxs20(
21427
21815
  MouseElementTracker,
21428
21816
  {
21429
21817
  elements: elementsToRender,
@@ -21432,7 +21820,7 @@ var CanvasElementsRenderer = (props) => {
21432
21820
  selectedLayer,
21433
21821
  onMouseHoverOverPrimitives: onMouseOverPrimitives,
21434
21822
  children: [
21435
- /* @__PURE__ */ jsx26(
21823
+ /* @__PURE__ */ jsx27(
21436
21824
  FocusedPcbComponentOverlay,
21437
21825
  {
21438
21826
  focusRequest: props.focusedPcbComponent,
@@ -21440,7 +21828,7 @@ var CanvasElementsRenderer = (props) => {
21440
21828
  transform
21441
21829
  }
21442
21830
  ),
21443
- /* @__PURE__ */ jsx26(
21831
+ /* @__PURE__ */ jsx27(
21444
21832
  EditPlacementOverlay,
21445
21833
  {
21446
21834
  disabled: !props.allowEditing,
@@ -21449,7 +21837,7 @@ var CanvasElementsRenderer = (props) => {
21449
21837
  cancelPanDrag: props.cancelPanDrag,
21450
21838
  onCreateEditEvent: props.onCreateEditEvent,
21451
21839
  onModifyEditEvent: props.onModifyEditEvent,
21452
- children: /* @__PURE__ */ jsx26(
21840
+ children: /* @__PURE__ */ jsx27(
21453
21841
  DimensionOverlay,
21454
21842
  {
21455
21843
  transform,
@@ -21457,39 +21845,40 @@ var CanvasElementsRenderer = (props) => {
21457
21845
  primitives: primitivesWithoutInteractionMetadata,
21458
21846
  onBoundsSelected: props.onBoundsSelected,
21459
21847
  cancelPanDrag: props.cancelPanDrag,
21460
- children: /* @__PURE__ */ jsx26(
21848
+ children: /* @__PURE__ */ jsx27(
21461
21849
  ToolbarOverlay,
21462
21850
  {
21463
21851
  elements,
21852
+ onSearchComponent: props.onSearchComponent,
21464
21853
  getNetAtPoint,
21465
21854
  xRayNetIds,
21466
21855
  onXRayNetsChange: setXRayNetIds,
21467
21856
  onContextMenuOpenChange: props.onContextMenuOpenChange,
21468
21857
  getComponentAtPoint,
21469
21858
  onViewSchematicComponent: props.onViewSchematicComponent,
21470
- children: /* @__PURE__ */ jsx26(ErrorOverlay, { transform, elements, children: /* @__PURE__ */ jsx26(
21859
+ children: /* @__PURE__ */ jsx27(ErrorOverlay, { transform, elements, children: /* @__PURE__ */ jsx27(
21471
21860
  RatsNestOverlay,
21472
21861
  {
21473
21862
  transform,
21474
21863
  soup: elements,
21475
21864
  connectivityMap,
21476
- children: /* @__PURE__ */ jsx26(
21865
+ children: /* @__PURE__ */ jsx27(
21477
21866
  PcbGroupOverlay,
21478
21867
  {
21479
21868
  transform,
21480
21869
  elements,
21481
21870
  hoveredComponentIds,
21482
- children: /* @__PURE__ */ jsx26(
21871
+ children: /* @__PURE__ */ jsx27(
21483
21872
  DebugGraphicsOverlay,
21484
21873
  {
21485
21874
  transform,
21486
21875
  debugGraphics: props.debugGraphics,
21487
- children: /* @__PURE__ */ jsx26(
21876
+ children: /* @__PURE__ */ jsx27(
21488
21877
  WarningGraphicsOverlay,
21489
21878
  {
21490
21879
  transform,
21491
21880
  elements,
21492
- children: props.renderer === "canvas" ? /* @__PURE__ */ jsx26(
21881
+ children: props.renderer === "canvas" ? /* @__PURE__ */ jsx27(
21493
21882
  CanvasPrimitiveRenderer,
21494
21883
  {
21495
21884
  transform,
@@ -21502,7 +21891,7 @@ var CanvasElementsRenderer = (props) => {
21502
21891
  grid: props.grid,
21503
21892
  onRenderComplete: props.onRenderComplete
21504
21893
  }
21505
- ) : /* @__PURE__ */ jsx26(
21894
+ ) : /* @__PURE__ */ jsx27(
21506
21895
  WebGpuElementsRenderer,
21507
21896
  {
21508
21897
  highlightedCopperPourIds,
@@ -21536,11 +21925,11 @@ var CanvasElementsRenderer = (props) => {
21536
21925
  };
21537
21926
 
21538
21927
  // src/hooks/useAnimationFrameTransformState.ts
21539
- import { useCallback as useCallback12, useEffect as useEffect21, useRef as useRef17, useState as useState14 } from "react";
21928
+ import { useCallback as useCallback12, useEffect as useEffect22, useRef as useRef18, useState as useState15 } from "react";
21540
21929
  function useAnimationFrameTransformState(initialTransform) {
21541
- const [transform, setTransformState] = useState14(initialTransform);
21542
- const animationFrameIdRef = useRef17(null);
21543
- const pendingTransformRef = useRef17(null);
21930
+ const [transform, setTransformState] = useState15(initialTransform);
21931
+ const animationFrameIdRef = useRef18(null);
21932
+ const pendingTransformRef = useRef18(null);
21544
21933
  const setTransform = useCallback12((nextTransform) => {
21545
21934
  pendingTransformRef.current = nextTransform;
21546
21935
  if (animationFrameIdRef.current !== null) return;
@@ -21551,7 +21940,7 @@ function useAnimationFrameTransformState(initialTransform) {
21551
21940
  pendingTransformRef.current = null;
21552
21941
  });
21553
21942
  }, []);
21554
- useEffect21(
21943
+ useEffect22(
21555
21944
  () => () => {
21556
21945
  if (animationFrameIdRef.current !== null) {
21557
21946
  cancelAnimationFrame(animationFrameIdRef.current);
@@ -21562,9 +21951,66 @@ function useAnimationFrameTransformState(initialTransform) {
21562
21951
  return { setTransform, transform };
21563
21952
  }
21564
21953
 
21954
+ // src/hooks/usePcbComponentSearchFocus.ts
21955
+ import { useCallback as useCallback13, useEffect as useEffect23, useRef as useRef19 } from "react";
21956
+ import { compose as compose12, scale as scale6, translate as translate15 } from "transformation-matrix";
21957
+ var usePcbComponentSearchFocus = ({
21958
+ transform,
21959
+ setTransform,
21960
+ focusedPcbComponent,
21961
+ setFocusedPcbComponent,
21962
+ circuitJson
21963
+ }) => {
21964
+ const animationFrameRef = useRef19(null);
21965
+ const searchRequestRef = useRef19(null);
21966
+ const cancelSearchAnimation = useCallback13(() => {
21967
+ cancelTransformAnimation(animationFrameRef.current);
21968
+ animationFrameRef.current = null;
21969
+ }, []);
21970
+ useEffect23(() => cancelSearchAnimation, [cancelSearchAnimation]);
21971
+ useEffect23(() => {
21972
+ cancelSearchAnimation();
21973
+ }, [circuitJson, cancelSearchAnimation]);
21974
+ useEffect23(() => {
21975
+ if (!focusedPcbComponent || focusedPcbComponent !== searchRequestRef.current)
21976
+ return;
21977
+ const timeout = window.setTimeout(() => setFocusedPcbComponent(null), 3e3);
21978
+ return () => window.clearTimeout(timeout);
21979
+ }, [focusedPcbComponent, setFocusedPcbComponent]);
21980
+ const focusComponent = useCallback13(
21981
+ (focus, width, height) => {
21982
+ const target = compose12(
21983
+ translate15(width / 2, height / 2),
21984
+ scale6(0.5, 0.5),
21985
+ translate15(-width / 2, -height / 2),
21986
+ focus.transform
21987
+ );
21988
+ cancelSearchAnimation();
21989
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
21990
+ setTransform(target);
21991
+ } else {
21992
+ animateTransform({
21993
+ startTransform: transform,
21994
+ endTransform: target,
21995
+ durationMs: 450,
21996
+ onUpdate: setTransform,
21997
+ setAnimationFrameId: (id) => {
21998
+ animationFrameRef.current = id;
21999
+ }
22000
+ });
22001
+ }
22002
+ const request = { pcbComponentId: focus.component.pcb_component_id };
22003
+ searchRequestRef.current = request;
22004
+ setFocusedPcbComponent(request);
22005
+ },
22006
+ [transform, setTransform, cancelSearchAnimation, setFocusedPcbComponent]
22007
+ );
22008
+ return { focusComponent, cancelSearchAnimation };
22009
+ };
22010
+
21565
22011
  // src/PCBViewer.tsx
21566
- import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
21567
- var defaultTransform = compose11(translate15(400, 300), scale6(40, -40));
22012
+ import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
22013
+ var defaultTransform = compose13(translate16(400, 300), scale7(40, -40));
21568
22014
  var getPreferredRenderer = () => {
21569
22015
  const stored = getStoredString(STORAGE_KEYS.RENDERING_ENGINE, "webgpu");
21570
22016
  return stored === "canvas" || stored === "webgpu" ? stored : "webgpu";
@@ -21586,30 +22032,30 @@ var PCBViewer = ({
21586
22032
  disablePcbGroups = false,
21587
22033
  controller
21588
22034
  }) => {
21589
- const [activeRenderer, setActiveRenderer] = useState15(
22035
+ const [activeRenderer, setActiveRenderer] = useState16(
21590
22036
  () => renderer ?? getPreferredRenderer()
21591
22037
  );
21592
- const [focusedPcbComponent, setFocusedPcbComponent] = useState15(null);
21593
- useEffect22(
22038
+ const [focusedPcbComponent, setFocusedPcbComponent] = useState16(null);
22039
+ useEffect24(
21594
22040
  () => setActiveRenderer(renderer ?? getPreferredRenderer()),
21595
22041
  [renderer]
21596
22042
  );
21597
- const setPreferredRenderer = useCallback13((engine) => {
22043
+ const setPreferredRenderer = useCallback14((engine) => {
21598
22044
  setActiveRenderer(engine);
21599
22045
  setStoredString(STORAGE_KEYS.RENDERING_ENGINE, engine);
21600
22046
  }, []);
21601
- const renderingEngine = useMemo16(
22047
+ const renderingEngine = useMemo17(
21602
22048
  () => ({ renderer: activeRenderer, setRenderer: setPreferredRenderer }),
21603
22049
  [activeRenderer, setPreferredRenderer]
21604
22050
  );
21605
- const [isInteractionEnabled, setIsInteractionEnabled] = useState15(
22051
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState16(
21606
22052
  !clickToInteractEnabled
21607
22053
  );
21608
- const [isContextMenuOpen, setIsContextMenuOpen] = useState15(false);
21609
- const contextMenuOpenRef = useRef18(false);
22054
+ const [isContextMenuOpen, setIsContextMenuOpen] = useState16(false);
22055
+ const contextMenuOpenRef = useRef20(false);
21610
22056
  const [ref, refDimensions] = useMeasure_default();
21611
22057
  const { transform, setTransform: setTransformOnAnimationFrame } = useAnimationFrameTransformState(defaultTransform);
21612
- const shouldAllowCanvasInteraction = useCallback13(
22058
+ const shouldAllowCanvasInteraction = useCallback14(
21613
22059
  (event) => {
21614
22060
  if (contextMenuOpenRef.current) return false;
21615
22061
  if (event instanceof MouseEvent && (event.button === 2 || (event.buttons & 2) !== 0))
@@ -21622,7 +22068,7 @@ var PCBViewer = ({
21622
22068
  );
21623
22069
  const {
21624
22070
  ref: transformRef,
21625
- setTransform,
22071
+ setTransform: setMouseTransform,
21626
22072
  cancelDrag: cancelPanDrag
21627
22073
  } = src_default({
21628
22074
  transform,
@@ -21630,7 +22076,21 @@ var PCBViewer = ({
21630
22076
  enabled: isInteractionEnabled && !isContextMenuOpen,
21631
22077
  shouldDrag: shouldAllowCanvasInteraction
21632
22078
  });
21633
- const onContextMenuOpenChange = useCallback13(
22079
+ const { focusComponent, cancelSearchAnimation } = usePcbComponentSearchFocus({
22080
+ transform,
22081
+ setTransform: setMouseTransform,
22082
+ focusedPcbComponent,
22083
+ setFocusedPcbComponent,
22084
+ circuitJson
22085
+ });
22086
+ const setTransform = useCallback14(
22087
+ (next) => {
22088
+ cancelSearchAnimation();
22089
+ setMouseTransform(next);
22090
+ },
22091
+ [cancelSearchAnimation, setMouseTransform]
22092
+ );
22093
+ const onContextMenuOpenChange = useCallback14(
21634
22094
  (open) => {
21635
22095
  contextMenuOpenRef.current = open;
21636
22096
  if (open) cancelPanDrag();
@@ -21638,11 +22098,11 @@ var PCBViewer = ({
21638
22098
  },
21639
22099
  [cancelPanDrag]
21640
22100
  );
21641
- let [editEvents, setEditEvents] = useState15([]);
22101
+ let [editEvents, setEditEvents] = useState16([]);
21642
22102
  editEvents = editEventsProp ?? editEvents;
21643
- const initialRenderCompleted = useRef18(false);
21644
- const touchStartRef = useRef18(null);
21645
- const circuitJsonKey = useMemo16(
22103
+ const initialRenderCompleted = useRef20(false);
22104
+ const touchStartRef = useRef20(null);
22105
+ const circuitJsonKey = useMemo17(
21646
22106
  () => calculateCircuitJsonKey(circuitJson),
21647
22107
  [circuitJson]
21648
22108
  );
@@ -21659,15 +22119,15 @@ var PCBViewer = ({
21659
22119
  (elmBounds.height ?? 0) / height2,
21660
22120
  100
21661
22121
  ) * 0.75;
21662
- const targetTransform = compose11(
21663
- translate15((elmBounds.width ?? 0) / 2, (elmBounds.height ?? 0) / 2),
21664
- scale6(scaleFactor, -scaleFactor, 0, 0),
21665
- translate15(-center.x, -center.y)
22122
+ const targetTransform = compose13(
22123
+ translate16((elmBounds.width ?? 0) / 2, (elmBounds.height ?? 0) / 2),
22124
+ scale7(scaleFactor, -scaleFactor, 0, 0),
22125
+ translate16(-center.x, -center.y)
21666
22126
  );
21667
22127
  setTransform(targetTransform);
21668
22128
  return;
21669
22129
  };
21670
- useEffect22(() => {
22130
+ useEffect24(() => {
21671
22131
  if (!refDimensions?.width) return;
21672
22132
  if (!circuitJson) return;
21673
22133
  if (circuitJson.length === 0) return;
@@ -21676,23 +22136,23 @@ var PCBViewer = ({
21676
22136
  initialRenderCompleted.current = true;
21677
22137
  }
21678
22138
  }, [circuitJson, refDimensions]);
21679
- useEffect22(() => {
22139
+ useEffect24(() => {
21680
22140
  if (initialRenderCompleted.current === true) {
21681
22141
  resetTransform();
21682
22142
  }
21683
22143
  }, [boardSizeKey]);
21684
- const pcbElmsPreEdit = useMemo16(() => {
22144
+ const pcbElmsPreEdit = useMemo17(() => {
21685
22145
  return circuitJson?.filter(
21686
22146
  (e) => e.type.startsWith("pcb_") || e.type.startsWith("source_")
21687
22147
  ) ?? [];
21688
- }, [circuitJsonKey]);
21689
- const elements = useMemo16(() => {
22148
+ }, [circuitJson, circuitJsonKey]);
22149
+ const elements = useMemo17(() => {
21690
22150
  return applyEditEvents({
21691
22151
  circuitJson: pcbElmsPreEdit,
21692
22152
  editEvents
21693
22153
  });
21694
22154
  }, [pcbElmsPreEdit, editEvents]);
21695
- useEffect22(() => {
22155
+ useEffect24(() => {
21696
22156
  const request = controller?.focusRequest;
21697
22157
  if (!request || !refDimensions.width || !height || !elements.length) return;
21698
22158
  const focus = getPcbComponentFocus(
@@ -21715,6 +22175,21 @@ var PCBViewer = ({
21715
22175
  cancelPanDrag,
21716
22176
  setTransform
21717
22177
  ]);
22178
+ const focusSearchComponent = useCallback14(
22179
+ (pcbComponentId) => {
22180
+ const width = refDimensions.width;
22181
+ const focus = getPcbComponentFocus(
22182
+ elements,
22183
+ pcbComponentId,
22184
+ width,
22185
+ height
22186
+ );
22187
+ if (!focus) return;
22188
+ cancelPanDrag();
22189
+ focusComponent(focus, width, height);
22190
+ },
22191
+ [elements, refDimensions.width, height, cancelPanDrag, focusComponent]
22192
+ );
21718
22193
  const onCreateEditEvent = (event) => {
21719
22194
  setEditEvents([...editEvents, event]);
21720
22195
  onEditEventsChanged?.([...editEvents, event]);
@@ -21726,27 +22201,35 @@ var PCBViewer = ({
21726
22201
  setEditEvents(newEditEvents);
21727
22202
  onEditEventsChanged?.(newEditEvents);
21728
22203
  };
21729
- const mergedInitialState = useMemo16(
22204
+ const mergedInitialState = useMemo17(
21730
22205
  () => ({
21731
22206
  ...initialState,
21732
22207
  ...disablePcbGroups && { is_showing_pcb_groups: false }
21733
22208
  }),
21734
22209
  [initialState, disablePcbGroups]
21735
22210
  );
21736
- return /* @__PURE__ */ jsx27(RenderingEngineContext.Provider, { value: renderingEngine, children: /* @__PURE__ */ jsxs20(
22211
+ return /* @__PURE__ */ jsx28(RenderingEngineContext.Provider, { value: renderingEngine, children: /* @__PURE__ */ jsxs21(
21737
22212
  "div",
21738
22213
  {
21739
22214
  ref: transformRef,
21740
22215
  style: { position: "relative" },
22216
+ onPointerDownCapture: (event) => {
22217
+ if (!event.target.closest("[data-toolbar-overlay]"))
22218
+ cancelSearchAnimation();
22219
+ },
22220
+ onWheelCapture: (event) => {
22221
+ if (!event.target.closest("[data-toolbar-overlay]"))
22222
+ cancelSearchAnimation();
22223
+ },
21741
22224
  onContextMenu: (event) => event.preventDefault(),
21742
22225
  children: [
21743
- /* @__PURE__ */ jsx27("div", { ref, children: /* @__PURE__ */ jsxs20(
22226
+ /* @__PURE__ */ jsx28("div", { ref, children: /* @__PURE__ */ jsxs21(
21744
22227
  ContextProviders,
21745
22228
  {
21746
22229
  initialState: mergedInitialState,
21747
22230
  disablePcbGroups,
21748
22231
  children: [
21749
- /* @__PURE__ */ jsx27(
22232
+ /* @__PURE__ */ jsx28(
21750
22233
  CanvasElementsRenderer,
21751
22234
  {
21752
22235
  renderer: activeRenderer,
@@ -21759,6 +22242,7 @@ var PCBViewer = ({
21759
22242
  onBoundsSelected,
21760
22243
  onViewSchematicComponent,
21761
22244
  focusedPcbComponent,
22245
+ onSearchComponent: focusSearchComponent,
21762
22246
  cancelPanDrag,
21763
22247
  onContextMenuOpenChange,
21764
22248
  onCreateEditEvent,
@@ -21777,11 +22261,11 @@ var PCBViewer = ({
21777
22261
  debugGraphics
21778
22262
  }
21779
22263
  ),
21780
- /* @__PURE__ */ jsx27(ToastContainer, {})
22264
+ /* @__PURE__ */ jsx28(ToastContainer, {})
21781
22265
  ]
21782
22266
  }
21783
22267
  ) }),
21784
- clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx27(
22268
+ clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx28(
21785
22269
  "div",
21786
22270
  {
21787
22271
  onClick: () => {
@@ -21818,7 +22302,7 @@ var PCBViewer = ({
21818
22302
  justifyContent: "center",
21819
22303
  touchAction: "pan-x pan-y pinch-zoom"
21820
22304
  },
21821
- children: /* @__PURE__ */ jsx27(
22305
+ children: /* @__PURE__ */ jsx28(
21822
22306
  "div",
21823
22307
  {
21824
22308
  style: {
@@ -21840,19 +22324,19 @@ var PCBViewer = ({
21840
22324
  };
21841
22325
 
21842
22326
  // src/hooks/usePcbViewerController.ts
21843
- import { useCallback as useCallback14, useMemo as useMemo17, useState as useState16 } from "react";
22327
+ import { useCallback as useCallback15, useMemo as useMemo18, useState as useState17 } from "react";
21844
22328
  var usePcbViewerController = () => {
21845
- const [focusRequest, setFocusRequest] = useState16(null);
21846
- const focusPcbComponent = useCallback14((pcbComponentId) => {
22329
+ const [focusRequest, setFocusRequest] = useState17(null);
22330
+ const focusPcbComponent = useCallback15((pcbComponentId) => {
21847
22331
  setFocusRequest({ pcbComponentId });
21848
22332
  }, []);
21849
- const onFocusRequestHandled = useCallback14(
22333
+ const onFocusRequestHandled = useCallback15(
21850
22334
  (request) => {
21851
22335
  setFocusRequest((current) => current === request ? null : current);
21852
22336
  },
21853
22337
  []
21854
22338
  );
21855
- const controller = useMemo17(
22339
+ const controller = useMemo18(
21856
22340
  () => ({ focusRequest, onFocusRequestHandled }),
21857
22341
  [focusRequest, onFocusRequestHandled]
21858
22342
  );