@tscircuit/pcb-viewer 1.11.424 → 1.11.426

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
@@ -11766,11 +11766,16 @@ function getElementNetId(element, connectivityMap) {
11766
11766
  const net = connectivityMap.getNetConnectedToId(id);
11767
11767
  if (net) return net;
11768
11768
  }
11769
+ if ("source_net_id" in element) return element.source_net_id;
11769
11770
  }
11770
11771
  function isXRayCopper(element) {
11771
- return element && ["pcb_trace", "pcb_smtpad", "pcb_plated_hole", "pcb_via"].includes(
11772
- element.type
11773
- );
11772
+ return element && [
11773
+ "pcb_trace",
11774
+ "pcb_smtpad",
11775
+ "pcb_plated_hole",
11776
+ "pcb_via",
11777
+ "pcb_copper_pour"
11778
+ ].includes(element.type);
11774
11779
  }
11775
11780
  function getXRayDisplayName(element, elements, connectivityMap) {
11776
11781
  const directName = element.type === "pcb_trace" ? getAssociatedTraceName({ primitiveElement: element, elements }) : null;
@@ -11820,6 +11825,61 @@ function getXRayGroups(netId, elements, connectivityMap) {
11820
11825
  });
11821
11826
  }
11822
11827
 
11828
+ // src/lib/draw-copper-pour.ts
11829
+ import {
11830
+ CircuitToCanvasDrawer,
11831
+ DEFAULT_PCB_COLOR_MAP,
11832
+ drawPcbCopperPour
11833
+ } from "circuit-to-canvas";
11834
+ import color from "color";
11835
+ import { identity as identity2 } from "transformation-matrix";
11836
+ function getCopperPoursUnderPoint(elements, point2, selectedLayer) {
11837
+ const canvas = document.createElement("canvas");
11838
+ canvas.width = canvas.height = 1;
11839
+ const ctx = canvas.getContext("2d");
11840
+ return elements.filter((element) => {
11841
+ if (element.type !== "pcb_copper_pour" || element.layer !== selectedLayer)
11842
+ return false;
11843
+ drawPcbCopperPour({
11844
+ ctx,
11845
+ pour: element,
11846
+ realToCanvasMat: identity2(),
11847
+ colorMap: DEFAULT_PCB_COLOR_MAP
11848
+ });
11849
+ return ctx.isPointInPath(
11850
+ point2.x,
11851
+ point2.y,
11852
+ element.shape === "brep" ? "evenodd" : "nonzero"
11853
+ );
11854
+ });
11855
+ }
11856
+ function isCopperPourElement(element) {
11857
+ return element.type === "pcb_copper_pour";
11858
+ }
11859
+ function drawCopperPourElementsForLayer({
11860
+ canvas,
11861
+ elements,
11862
+ layers,
11863
+ realToCanvasMat,
11864
+ opacity = 1
11865
+ }) {
11866
+ const copperPourElements = elements.filter(isCopperPourElement);
11867
+ if (copperPourElements.length === 0 || opacity <= 0) return;
11868
+ const drawer = new CircuitToCanvasDrawer(canvas);
11869
+ drawer.configure({
11870
+ colorOverrides: {
11871
+ copper: Object.fromEntries(
11872
+ Object.entries(DEFAULT_PCB_COLOR_MAP.copper).map(([layer, value]) => [
11873
+ layer,
11874
+ color(value).alpha(opacity).rgb().string()
11875
+ ])
11876
+ )
11877
+ }
11878
+ });
11879
+ drawer.realToCanvasMat = realToCanvasMat;
11880
+ drawer.drawElements(copperPourElements, { layers });
11881
+ }
11882
+
11823
11883
  // src/lib/webgpu/create-worker.ts
11824
11884
  var createWebGpuWorker = async () => {
11825
11885
  const { default: WorkerConstructor } = await Promise.resolve().then(() => (init_pcb_webgpu_worker(), pcb_webgpu_worker_exports));
@@ -12083,7 +12143,7 @@ import colorParser from "color";
12083
12143
  import {
12084
12144
  applyToPoint as applyToPoint3,
12085
12145
  compose as compose6,
12086
- identity as identity2,
12146
+ identity as identity3,
12087
12147
  inverse,
12088
12148
  translate as translate9
12089
12149
  } from "transformation-matrix";
@@ -12421,7 +12481,7 @@ var Drawer = class {
12421
12481
  canvas.getContext("2d")
12422
12482
  ])
12423
12483
  );
12424
- this.transform = identity2();
12484
+ this.transform = identity3();
12425
12485
  this.transform.d *= -1;
12426
12486
  this.transform = compose6(this.transform, translate9(0, -500));
12427
12487
  this.lastPoint = { x: 0, y: 0 };
@@ -12930,39 +12990,6 @@ var getCopperLayerDrawOrder = (elements, selectedLayer) => {
12930
12990
  ];
12931
12991
  };
12932
12992
 
12933
- // src/lib/draw-copper-pour.ts
12934
- import {
12935
- CircuitToCanvasDrawer,
12936
- DEFAULT_PCB_COLOR_MAP
12937
- } from "circuit-to-canvas";
12938
- import color from "color";
12939
- function isCopperPourElement(element) {
12940
- return element.type === "pcb_copper_pour";
12941
- }
12942
- function drawCopperPourElementsForLayer({
12943
- canvas,
12944
- elements,
12945
- layers,
12946
- realToCanvasMat,
12947
- opacity = 1
12948
- }) {
12949
- const copperPourElements = elements.filter(isCopperPourElement);
12950
- if (copperPourElements.length === 0 || opacity <= 0) return;
12951
- const drawer = new CircuitToCanvasDrawer(canvas);
12952
- drawer.configure({
12953
- colorOverrides: {
12954
- copper: Object.fromEntries(
12955
- Object.entries(DEFAULT_PCB_COLOR_MAP.copper).map(([layer, value]) => [
12956
- layer,
12957
- color(value).alpha(opacity).rgb().string()
12958
- ])
12959
- )
12960
- }
12961
- });
12962
- drawer.realToCanvasMat = realToCanvasMat;
12963
- drawer.drawElements(copperPourElements, { layers });
12964
- }
12965
-
12966
12993
  // src/lib/draw-courtyard.ts
12967
12994
  import {
12968
12995
  CircuitToCanvasDrawer as CircuitToCanvasDrawer2,
@@ -14333,6 +14360,12 @@ var CanvasPrimitiveRenderer = ({
14333
14360
  realToCanvasMat: transform,
14334
14361
  drawSoldermask: false
14335
14362
  };
14363
+ if (isShowingCopperPours) {
14364
+ drawCopperPourElementsForLayer({
14365
+ ...args,
14366
+ opacity: copperPourOpacity
14367
+ });
14368
+ }
14336
14369
  drawPcbTraceElementsForLayer({ ...args, showCopperPours: false });
14337
14370
  drawPcbSmtPadElementsForLayer(args);
14338
14371
  drawPlatedHolePads(args);
@@ -15308,7 +15341,7 @@ var DebugGraphicsOverlay = ({
15308
15341
 
15309
15342
  // src/components/DimensionOverlay.tsx
15310
15343
  import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo6, useRef as useRef6, useState as useState5 } from "react";
15311
- import { applyToPoint as applyToPoint10, identity as identity3, inverse as inverse3 } from "transformation-matrix";
15344
+ import { applyToPoint as applyToPoint10, identity as identity4, inverse as inverse3 } from "transformation-matrix";
15312
15345
 
15313
15346
  // src/lib/util/get-primitive-bounding-box.ts
15314
15347
  var mergeNumber = (a, b, fn) => fn(a, b);
@@ -15730,7 +15763,7 @@ var DimensionSnapGuides = memo(function DimensionSnapGuides2({
15730
15763
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
15731
15764
  var SNAP_THRESHOLD_PX = 16;
15732
15765
  var EMPTY_PRIMITIVES = [];
15733
- var DEFAULT_TRANSFORM = identity3();
15766
+ var DEFAULT_TRANSFORM = identity4();
15734
15767
  var shouldExcludePrimitiveFromSnapping = (primitive) => {
15735
15768
  if (primitive.pcb_drawing_type === "text") return true;
15736
15769
  const element = primitive._element;
@@ -16357,7 +16390,7 @@ var DimensionOverlay = ({
16357
16390
 
16358
16391
  // src/components/EditPlacementOverlay.tsx
16359
16392
  import { useRef as useRef7, useState as useState6 } from "react";
16360
- import { applyToPoint as applyToPoint11, identity as identity4, inverse as inverse4 } from "transformation-matrix";
16393
+ import { applyToPoint as applyToPoint11, identity as identity5, inverse as inverse4 } from "transformation-matrix";
16361
16394
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
16362
16395
  var isInsideOf = (pcb_component, point2, padding = 0) => {
16363
16396
  const halfWidth = pcb_component.width / 2;
@@ -16377,7 +16410,7 @@ var EditPlacementOverlay = ({
16377
16410
  onCreateEditEvent,
16378
16411
  onModifyEditEvent
16379
16412
  }) => {
16380
- if (!transform) transform = identity4();
16413
+ if (!transform) transform = identity5();
16381
16414
  const containerRef = useRef7(null);
16382
16415
  const [activePcbComponentId, setActivePcbComponent] = useState6(
16383
16416
  null
@@ -16500,7 +16533,7 @@ var EditPlacementOverlay = ({
16500
16533
  // src/components/ErrorOverlay.tsx
16501
16534
  import { useRef as useRef8, Fragment as Fragment3 } from "react";
16502
16535
  import { css } from "@emotion/css";
16503
- import { applyToPoint as applyToPoint12, identity as identity5 } from "transformation-matrix";
16536
+ import { applyToPoint as applyToPoint12, identity as identity6 } from "transformation-matrix";
16504
16537
 
16505
16538
  // src/lib/util/getPopupPosition.ts
16506
16539
  var getPopupPosition = (errorCenter, containerRef) => {
@@ -16664,7 +16697,7 @@ var errorMessageStyles = css`
16664
16697
  `;
16665
16698
  var ErrorOverlay = ({
16666
16699
  children,
16667
- transform = identity5(),
16700
+ transform = identity6(),
16668
16701
  elements
16669
16702
  }) => {
16670
16703
  const containerRef = useRef8(null);
@@ -18239,7 +18272,7 @@ var MouseElementTracker = ({
18239
18272
 
18240
18273
  // src/components/PcbGroupOverlay.tsx
18241
18274
  import { applyToPoint as applyToPoint16 } from "transformation-matrix";
18242
- import { identity as identity6 } from "transformation-matrix";
18275
+ import { identity as identity7 } from "transformation-matrix";
18243
18276
  import { useRef as useRef9, useEffect as useEffect12 } from "react";
18244
18277
  import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
18245
18278
  var GROUP_COLORS = [
@@ -18256,7 +18289,7 @@ var GROUP_COLORS = [
18256
18289
  ];
18257
18290
  var PcbGroupOverlay = ({
18258
18291
  children,
18259
- transform = identity6(),
18292
+ transform = identity7(),
18260
18293
  elements = [],
18261
18294
  hoveredComponentIds = []
18262
18295
  }) => {
@@ -18504,7 +18537,7 @@ var PcbGroupOverlay = ({
18504
18537
  };
18505
18538
 
18506
18539
  // src/components/RatsNestOverlay.tsx
18507
- import { applyToPoint as applyToPoint17, identity as identity7 } from "transformation-matrix";
18540
+ import { applyToPoint as applyToPoint17, identity as identity8 } from "transformation-matrix";
18508
18541
  import { useMemo as useMemo8 } from "react";
18509
18542
  import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
18510
18543
  var RatsNestOverlay = ({ transform, soup, children }) => {
@@ -18568,7 +18601,7 @@ var RatsNestOverlay = ({ transform, soup, children }) => {
18568
18601
  return lines;
18569
18602
  }, [soup, netMap, idToNetMap, isShowingRatsNest]);
18570
18603
  if (!soup || !isShowingRatsNest) return children;
18571
- if (!transform) transform = identity7();
18604
+ if (!transform) transform = identity8();
18572
18605
  return /* @__PURE__ */ jsxs14("div", { style: { position: "relative" }, children: [
18573
18606
  children,
18574
18607
  /* @__PURE__ */ jsx19(
@@ -18619,7 +18652,7 @@ import { css as css3 } from "@emotion/css";
18619
18652
  // package.json
18620
18653
  var package_default = {
18621
18654
  name: "@tscircuit/pcb-viewer",
18622
- version: "1.11.423",
18655
+ version: "1.11.425",
18623
18656
  main: "dist/index.js",
18624
18657
  type: "module",
18625
18658
  repository: {
@@ -18635,6 +18668,7 @@ var package_default = {
18635
18668
  "format:check": "biome format .",
18636
18669
  cosmos: "cosmos",
18637
18670
  "cosmos-export": "cosmos-export",
18671
+ "test:copper-pour-x-ray": "bun run build && bun tests/copper-pour-x-ray/run.ts",
18638
18672
  "test:x-ray-net": "bun run build && bun tests/x-ray-net/run.ts",
18639
18673
  "test:component-focus": "bun run build && bun tests/component-focus/run.ts",
18640
18674
  "test:measurement-context-menu": "bun run build && bun tests/measurement-context-menu/run.ts",
@@ -18800,6 +18834,7 @@ var menuStyle = css2`
18800
18834
  padding: 4px;
18801
18835
  font: 12px sans-serif;
18802
18836
  box-shadow: 0 4px 16px #0008;
18837
+ outline: none;
18803
18838
  `;
18804
18839
  var itemStyle = css2`
18805
18840
  display: block;
@@ -18859,7 +18894,7 @@ var VisibilityContextMenu = ({
18859
18894
  onClose();
18860
18895
  }
18861
18896
  };
18862
- ref.current?.querySelector("button")?.focus();
18897
+ ref.current?.focus();
18863
18898
  window.addEventListener("pointerdown", dismiss, true);
18864
18899
  window.addEventListener("keydown", onKeyDown);
18865
18900
  window.addEventListener("resize", onClose);
@@ -18877,6 +18912,7 @@ var VisibilityContextMenu = ({
18877
18912
  {
18878
18913
  ref,
18879
18914
  role: "menu",
18915
+ tabIndex: -1,
18880
18916
  "aria-label": "PCB context menu",
18881
18917
  className: menuStyle,
18882
18918
  onContextMenu: (event) => {
@@ -18889,16 +18925,17 @@ var VisibilityContextMenu = ({
18889
18925
  onKeyDown: (event) => {
18890
18926
  event.stopPropagation();
18891
18927
  const button = event.target.closest("button");
18892
- if (!button) return;
18893
- const menu = button.closest('[role="menu"]');
18928
+ const menu = button?.closest('[role="menu"]') ?? ref.current;
18929
+ if (!menu) return;
18894
18930
  const items = Array.from(
18895
18931
  menu.querySelectorAll("button:not(:disabled)")
18896
18932
  ).filter((item) => item.closest('[role="menu"]') === menu);
18897
18933
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
18898
18934
  event.preventDefault();
18899
18935
  const step = event.key === "ArrowDown" ? 1 : -1;
18900
- items[(items.indexOf(button) + step + items.length) % items.length]?.focus();
18901
- } else if (event.key === "ArrowRight" && button.hasAttribute("aria-haspopup")) {
18936
+ const index = button ? items.indexOf(button) : step === 1 ? -1 : 0;
18937
+ items[(index + step + items.length) % items.length]?.focus();
18938
+ } else if (event.key === "ArrowRight" && button?.hasAttribute("aria-haspopup")) {
18902
18939
  event.preventDefault();
18903
18940
  button.click();
18904
18941
  requestAnimationFrame(
@@ -20501,7 +20538,7 @@ var ToolbarOverlay = ({
20501
20538
 
20502
20539
  // src/components/WarningGraphicsOverlay.tsx
20503
20540
  import { useEffect as useEffect18, useRef as useRef15 } from "react";
20504
- import { applyToPoint as applyToPoint18, identity as identity8 } from "transformation-matrix";
20541
+ import { applyToPoint as applyToPoint18, identity as identity9 } from "transformation-matrix";
20505
20542
 
20506
20543
  // src/lib/util/get-pcb-warning-highlight.ts
20507
20544
  var isHighlightablePcbWarning = (element) => element.type === "pcb_manual_edit_conflict_warning" || element.type === "pcb_connector_not_in_accessible_orientation_warning";
@@ -20516,7 +20553,7 @@ var getPcbWarningHighlightLabel = (warning) => {
20516
20553
  import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
20517
20554
  var WarningGraphicsOverlay = ({
20518
20555
  children,
20519
- transform = identity8(),
20556
+ transform = identity9(),
20520
20557
  elements = []
20521
20558
  }) => {
20522
20559
  const [containerRef, { width, height }] = useMeasure_default();
@@ -20675,11 +20712,13 @@ var CanvasElementsRenderer = (props) => {
20675
20712
  hoveredErrorId,
20676
20713
  focusedErrorId,
20677
20714
  isShowingCopperPours,
20715
+ copperPourOpacity,
20678
20716
  selectedLayer
20679
20717
  } = useGlobalStore((state) => ({
20680
20718
  hoveredErrorId: state.hovered_error_id,
20681
20719
  focusedErrorId: state.focused_error_id,
20682
20720
  isShowingCopperPours: state.is_showing_copper_pours,
20721
+ copperPourOpacity: state.copper_pour_opacity,
20683
20722
  selectedLayer: state.selected_layer
20684
20723
  }));
20685
20724
  const activeErrorId = focusedErrorId ?? hoveredErrorId;
@@ -20709,11 +20748,11 @@ var CanvasElementsRenderer = (props) => {
20709
20748
  }, [xRayNetIds.length]);
20710
20749
  const xRayElements = useMemo10(
20711
20750
  () => xRayNetIds.length > 0 ? elementsToRender.filter(
20712
- (element) => isXRayCopper(element) && xRayNetIds.includes(
20751
+ (element) => isXRayCopper(element) && (element.type !== "pcb_copper_pour" || copperPourOpacity > 0) && xRayNetIds.includes(
20713
20752
  getElementNetId(element, connectivityMap) ?? ""
20714
20753
  )
20715
20754
  ) : void 0,
20716
- [elementsToRender, connectivityMap, xRayNetIds]
20755
+ [elementsToRender, connectivityMap, xRayNetIds, copperPourOpacity]
20717
20756
  );
20718
20757
  const hoverPrimitives = useMemo10(() => {
20719
20758
  if (!xRayElements) return primitivesWithoutInteractionMetadata;
@@ -20744,6 +20783,16 @@ var CanvasElementsRenderer = (props) => {
20744
20783
  displayName: getXRayDisplayName(element, elements, connectivityMap),
20745
20784
  groups: getXRayGroups(netId, elements, connectivityMap)
20746
20785
  });
20786
+ if (isShowingCopperPours && copperPourOpacity > 0) {
20787
+ for (const pour of getCopperPoursUnderPoint(
20788
+ elementsToRender,
20789
+ applyToPoint20(inverse6(transform), point2),
20790
+ selectedLayer
20791
+ ).reverse()) {
20792
+ const net = getElementNetId(pour, connectivityMap);
20793
+ if (net) return describeNet(net, pour);
20794
+ }
20795
+ }
20747
20796
  const hits = getPrimitivesUnderPoint(
20748
20797
  primitivesWithoutInteractionMetadata,
20749
20798
  applyToPoint20(inverse6(transform), point2),