@tscircuit/pcb-viewer 1.11.402 → 1.11.404

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
@@ -4258,6 +4258,52 @@ var animateTransform = ({
4258
4258
  import { useCallback as useCallback11, useEffect as useEffect19, useMemo as useMemo10, useRef as useRef16, useState as useState13 } from "react";
4259
4259
  import { applyToPoint as applyToPoint19, inverse as inverse6 } from "transformation-matrix";
4260
4260
 
4261
+ // src/lib/get-trace-overlay-text.ts
4262
+ var getNonEmptyName = (name) => name?.trim() || null;
4263
+ function getAssociatedTraceName({
4264
+ primitiveElement,
4265
+ elements
4266
+ }) {
4267
+ const sourceElementId = primitiveElement.source_trace_id;
4268
+ if (!sourceElementId) return null;
4269
+ const circuitJson = su(elements);
4270
+ const sourceTrace = circuitJson.source_trace.get(sourceElementId);
4271
+ const sourceTraceName = getNonEmptyName(sourceTrace?.name);
4272
+ if (sourceTraceName) return sourceTraceName;
4273
+ const sourceNet = circuitJson.source_net.get(sourceElementId);
4274
+ const sourceNetName = getNonEmptyName(sourceNet?.name);
4275
+ if (sourceNetName) return sourceNetName;
4276
+ for (const sourceNetId of sourceTrace?.connected_source_net_ids ?? []) {
4277
+ const connectedSourceNetName = getNonEmptyName(
4278
+ circuitJson.source_net.get(sourceNetId)?.name
4279
+ );
4280
+ if (connectedSourceNetName) return connectedSourceNetName;
4281
+ }
4282
+ return null;
4283
+ }
4284
+ function getTraceOverlayInfo({
4285
+ primitiveElement,
4286
+ elements
4287
+ }) {
4288
+ const trace = su(elements).source_trace.get(
4289
+ primitiveElement?.source_trace_id
4290
+ );
4291
+ const traceLength = primitiveElement.trace_length;
4292
+ const hasTraceLength = typeof traceLength === "number";
4293
+ const maxLength = trace?.max_length;
4294
+ const text = hasTraceLength ? `${traceLength.toFixed(3)}${typeof maxLength === "number" ? ` / ${maxLength}` : ""} mm` : "";
4295
+ const name = getAssociatedTraceName({ primitiveElement, elements }) ?? getNonEmptyName(trace?.display_name);
4296
+ if (!text && !name) return null;
4297
+ const isOverLength = Boolean(
4298
+ hasTraceLength && typeof maxLength === "number" && traceLength > maxLength
4299
+ );
4300
+ return {
4301
+ text,
4302
+ name,
4303
+ isOverLength
4304
+ };
4305
+ }
4306
+
4261
4307
  // src/lib/x-ray-net.ts
4262
4308
  function getElementNetId(element, connectivityMap) {
4263
4309
  if (!element) return;
@@ -4282,6 +4328,53 @@ function isXRayCopper(element) {
4282
4328
  element.type
4283
4329
  );
4284
4330
  }
4331
+ function getXRayDisplayName(element, elements, connectivityMap) {
4332
+ const directName = element.type === "pcb_trace" ? getAssociatedTraceName({ primitiveElement: element, elements }) : null;
4333
+ if (directName) return directName;
4334
+ const netId = getElementNetId(element, connectivityMap);
4335
+ const connected = netId ? elements.filter(
4336
+ (candidate) => getElementNetId(candidate, connectivityMap) === netId
4337
+ ) : [];
4338
+ for (const type of ["source_net", "source_trace"]) {
4339
+ for (const candidate of connected) {
4340
+ if (candidate.type === type && "name" in candidate && typeof candidate.name === "string" && candidate.name.trim())
4341
+ return candidate.name.trim();
4342
+ }
4343
+ }
4344
+ if (element.type === "pcb_trace") {
4345
+ const label = getTraceOverlayInfo({
4346
+ primitiveElement: element,
4347
+ elements
4348
+ })?.name;
4349
+ if (label) return label;
4350
+ }
4351
+ for (const candidate of connected) {
4352
+ if (candidate.type === "source_trace" && candidate.display_name?.trim())
4353
+ return candidate.display_name.trim();
4354
+ }
4355
+ return "Net";
4356
+ }
4357
+ function getXRayGroups(netId, elements, connectivityMap) {
4358
+ return elements.flatMap((element) => {
4359
+ if (element.type !== "source_bus") return [];
4360
+ const netIds = [
4361
+ ...new Set(
4362
+ element.source_trace_ids.flatMap((id) => {
4363
+ const net = connectivityMap.getNetConnectedToId(id);
4364
+ return net ? [net] : [];
4365
+ })
4366
+ )
4367
+ ];
4368
+ if (!netIds.includes(netId)) return [];
4369
+ return [
4370
+ {
4371
+ id: element.source_bus_id,
4372
+ name: element.name?.trim() || "Bus",
4373
+ netIds
4374
+ }
4375
+ ];
4376
+ });
4377
+ }
4285
4378
 
4286
4379
  // src/lib/webgpu/create-worker.ts
4287
4380
  var createWebGpuWorker = async () => {
@@ -10073,52 +10166,6 @@ var PanelAnchorOffsetOverlay = ({
10073
10166
  );
10074
10167
  };
10075
10168
 
10076
- // src/lib/get-trace-overlay-text.ts
10077
- var getNonEmptyName = (name) => name?.trim() || null;
10078
- function getAssociatedTraceName({
10079
- primitiveElement,
10080
- elements
10081
- }) {
10082
- const sourceElementId = primitiveElement.source_trace_id;
10083
- if (!sourceElementId) return null;
10084
- const circuitJson = su(elements);
10085
- const sourceTrace = circuitJson.source_trace.get(sourceElementId);
10086
- const sourceTraceName = getNonEmptyName(sourceTrace?.name);
10087
- if (sourceTraceName) return sourceTraceName;
10088
- const sourceNet = circuitJson.source_net.get(sourceElementId);
10089
- const sourceNetName = getNonEmptyName(sourceNet?.name);
10090
- if (sourceNetName) return sourceNetName;
10091
- for (const sourceNetId of sourceTrace?.connected_source_net_ids ?? []) {
10092
- const connectedSourceNetName = getNonEmptyName(
10093
- circuitJson.source_net.get(sourceNetId)?.name
10094
- );
10095
- if (connectedSourceNetName) return connectedSourceNetName;
10096
- }
10097
- return null;
10098
- }
10099
- function getTraceOverlayInfo({
10100
- primitiveElement,
10101
- elements
10102
- }) {
10103
- const trace = su(elements).source_trace.get(
10104
- primitiveElement?.source_trace_id
10105
- );
10106
- const traceLength = primitiveElement.trace_length;
10107
- const hasTraceLength = typeof traceLength === "number";
10108
- const maxLength = trace?.max_length;
10109
- const text = hasTraceLength ? `${traceLength.toFixed(3)}${typeof maxLength === "number" ? ` / ${maxLength}` : ""} mm` : "";
10110
- const name = getAssociatedTraceName({ primitiveElement, elements }) ?? getNonEmptyName(trace?.display_name);
10111
- if (!text && !name) return null;
10112
- const isOverLength = Boolean(
10113
- hasTraceLength && typeof maxLength === "number" && traceLength > maxLength
10114
- );
10115
- return {
10116
- text,
10117
- name,
10118
- isOverLength
10119
- };
10120
- }
10121
-
10122
10169
  // src/lib/filter-traces-if-multiple.ts
10123
10170
  function filterTracesIfMultiple(filterTraces) {
10124
10171
  const { primitives, is_showing_multiple_traces_length, elements } = filterTraces;
@@ -11047,7 +11094,7 @@ import { css as css3 } from "@emotion/css";
11047
11094
  // package.json
11048
11095
  var package_default = {
11049
11096
  name: "@tscircuit/pcb-viewer",
11050
- version: "1.11.401",
11097
+ version: "1.11.403",
11051
11098
  main: "dist/index.js",
11052
11099
  type: "module",
11053
11100
  repository: {
@@ -11244,6 +11291,9 @@ var VisibilityContextMenu = ({
11244
11291
  position,
11245
11292
  onClose,
11246
11293
  onXRayNet,
11294
+ xRayGroups = [],
11295
+ onXRayGroup,
11296
+ xRayDisplayName = "Net",
11247
11297
  onExitXRayNet
11248
11298
  }) => {
11249
11299
  const engine = useRenderingEngine();
@@ -11348,19 +11398,41 @@ var VisibilityContextMenu = ({
11348
11398
  ...stacked ? { overflowY: "auto" } : {}
11349
11399
  },
11350
11400
  children: [
11351
- onXRayNet && /* @__PURE__ */ jsx20(
11401
+ onXRayNet && /* @__PURE__ */ jsxs15(
11352
11402
  "button",
11353
11403
  {
11354
11404
  type: "button",
11355
11405
  role: "menuitem",
11356
11406
  className: itemStyle,
11407
+ style: { whiteSpace: "normal", overflowWrap: "anywhere" },
11357
11408
  onClick: () => {
11358
11409
  onXRayNet();
11359
11410
  onClose();
11360
11411
  },
11361
- children: "X-Ray Net"
11412
+ children: [
11413
+ "X-Ray ",
11414
+ xRayDisplayName
11415
+ ]
11362
11416
  }
11363
11417
  ),
11418
+ onXRayGroup && xRayGroups.map((group) => /* @__PURE__ */ jsxs15(
11419
+ "button",
11420
+ {
11421
+ type: "button",
11422
+ role: "menuitem",
11423
+ className: itemStyle,
11424
+ style: { whiteSpace: "normal", overflowWrap: "anywhere" },
11425
+ onClick: () => {
11426
+ onXRayGroup(group);
11427
+ onClose();
11428
+ },
11429
+ children: [
11430
+ "X-Ray ",
11431
+ group.name
11432
+ ]
11433
+ },
11434
+ group.id
11435
+ )),
11364
11436
  onExitXRayNet && /* @__PURE__ */ jsx20(
11365
11437
  "button",
11366
11438
  {
@@ -12197,7 +12269,9 @@ var ToolbarOverlay = ({
12197
12269
  setFocusedErrorId: s.setFocusedErrorId
12198
12270
  }));
12199
12271
  const [contextMenuPosition, setContextMenuPosition] = useState12(null);
12272
+ const [contextGroups, setContextGroups] = useState12([]);
12200
12273
  const [contextNetId, setContextNetId] = useState12();
12274
+ const [contextNetDisplayName, setContextNetDisplayName] = useState12("Net");
12201
12275
  const pointerStart = useRef14(null);
12202
12276
  const inEditMode = useGlobalStore((s) => s.in_edit_mode);
12203
12277
  const netAtEvent = (event) => {
@@ -12357,13 +12431,16 @@ var ToolbarOverlay = ({
12357
12431
  const start = pointerStart.current;
12358
12432
  if (!start || Math.hypot(event.clientX - start.x, event.clientY - start.y) > 4)
12359
12433
  return;
12360
- const net = netAtEvent(event);
12361
- if (!net) return;
12434
+ const hit = netAtEvent(event);
12435
+ if (!hit) return;
12436
+ const net = hit.netId;
12362
12437
  if (xRayNetIds.includes(net)) {
12363
12438
  onXRayNetsChange?.(xRayNetIds.filter((id) => id !== net));
12364
12439
  closeContextMenu();
12365
12440
  } else {
12366
12441
  setContextNetId(net);
12442
+ setContextNetDisplayName(hit.displayName);
12443
+ setContextGroups(hit.groups);
12367
12444
  onContextMenuOpenChange?.(true);
12368
12445
  setContextMenuPosition({ x: event.clientX, y: event.clientY });
12369
12446
  }
@@ -12375,7 +12452,10 @@ var ToolbarOverlay = ({
12375
12452
  onContextMenu: (event) => {
12376
12453
  event.preventDefault();
12377
12454
  event.stopPropagation();
12378
- setContextNetId(netAtEvent(event));
12455
+ const hit = netAtEvent(event);
12456
+ setContextNetId(hit?.netId);
12457
+ setContextNetDisplayName(hit?.displayName ?? "Net");
12458
+ setContextGroups(hit?.groups ?? []);
12379
12459
  onContextMenuOpenChange?.(true);
12380
12460
  setContextMenuPosition({ x: event.clientX, y: event.clientY });
12381
12461
  },
@@ -12390,6 +12470,11 @@ var ToolbarOverlay = ({
12390
12470
  {
12391
12471
  position: contextMenuPosition,
12392
12472
  onClose: closeContextMenu,
12473
+ xRayDisplayName: contextNetDisplayName,
12474
+ xRayGroups: contextGroups.filter(
12475
+ (group) => group.netIds.some((id) => !xRayNetIds.includes(id))
12476
+ ),
12477
+ onXRayGroup: (group) => onXRayNetsChange?.([.../* @__PURE__ */ new Set([...xRayNetIds, ...group.netIds])]),
12393
12478
  onXRayNet: contextNetId && !xRayNetIds.includes(contextNetId) ? () => onXRayNetsChange?.([...xRayNetIds, contextNetId]) : void 0,
12394
12479
  onExitXRayNet: xRayNetIds.length > 0 ? () => onXRayNetsChange?.([]) : void 0
12395
12480
  }
@@ -12878,6 +12963,11 @@ var CanvasElementsRenderer = (props) => {
12878
12963
  );
12879
12964
  const getNetAtPoint = (point) => {
12880
12965
  if (!transform) return void 0;
12966
+ const describeNet = (netId, element) => ({
12967
+ netId,
12968
+ displayName: getXRayDisplayName(element, elements, connectivityMap),
12969
+ groups: getXRayGroups(netId, elements, connectivityMap)
12970
+ });
12881
12971
  const hits = getPrimitivesUnderPoint(
12882
12972
  primitivesWithoutInteractionMetadata,
12883
12973
  applyToPoint19(inverse6(transform), point),
@@ -12893,11 +12983,12 @@ var CanvasElementsRenderer = (props) => {
12893
12983
  );
12894
12984
  for (const primitive of copper) {
12895
12985
  const net = getElementNetId(primitive._element, connectivityMap);
12896
- if (net && xRayNetIds.includes(net)) return net;
12986
+ if (net && xRayNetIds.includes(net))
12987
+ return describeNet(net, primitive._element);
12897
12988
  }
12898
12989
  for (const primitive of copper) {
12899
12990
  const net = getElementNetId(primitive._element, connectivityMap);
12900
- if (net) return net;
12991
+ if (net) return describeNet(net, primitive._element);
12901
12992
  }
12902
12993
  };
12903
12994
  const [hoverState, setHoverState] = useState13({