@tscircuit/pcb-viewer 1.11.393 → 1.11.395

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
@@ -4,7 +4,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __commonJS = (cb, mod) => function __require2() {
8
14
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
15
  };
10
16
  var __copyProps = (to, from, except, desc) => {
@@ -918,6 +924,263 @@ var require_svgson_umd = __commonJS({
918
924
  }
919
925
  });
920
926
 
927
+ // node_modules/react-dom/cjs/react-dom.development.js
928
+ var require_react_dom_development = __commonJS({
929
+ "node_modules/react-dom/cjs/react-dom.development.js"(exports) {
930
+ "use strict";
931
+ (function() {
932
+ function noop2() {
933
+ }
934
+ function testStringCoercion(value) {
935
+ return "" + value;
936
+ }
937
+ function createPortal$1(children, containerInfo, implementation) {
938
+ var key = 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null;
939
+ try {
940
+ testStringCoercion(key);
941
+ var JSCompiler_inline_result = false;
942
+ } catch (e) {
943
+ JSCompiler_inline_result = true;
944
+ }
945
+ JSCompiler_inline_result && (console.error(
946
+ "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
947
+ "function" === typeof Symbol && Symbol.toStringTag && key[Symbol.toStringTag] || key.constructor.name || "Object"
948
+ ), testStringCoercion(key));
949
+ return {
950
+ $$typeof: REACT_PORTAL_TYPE,
951
+ key: null == key ? null : "" + key,
952
+ children,
953
+ containerInfo,
954
+ implementation
955
+ };
956
+ }
957
+ function getCrossOriginStringAs(as, input) {
958
+ if ("font" === as) return "";
959
+ if ("string" === typeof input)
960
+ return "use-credentials" === input ? input : "";
961
+ }
962
+ function getValueDescriptorExpectingObjectForWarning(thing) {
963
+ return null === thing ? "`null`" : void 0 === thing ? "`undefined`" : "" === thing ? "an empty string" : 'something with type "' + typeof thing + '"';
964
+ }
965
+ function getValueDescriptorExpectingEnumForWarning(thing) {
966
+ return null === thing ? "`null`" : void 0 === thing ? "`undefined`" : "" === thing ? "an empty string" : "string" === typeof thing ? JSON.stringify(thing) : "number" === typeof thing ? "`" + thing + "`" : 'something with type "' + typeof thing + '"';
967
+ }
968
+ function resolveDispatcher() {
969
+ var dispatcher = ReactSharedInternals.H;
970
+ null === dispatcher && console.error(
971
+ "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem."
972
+ );
973
+ return dispatcher;
974
+ }
975
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
976
+ var React4 = __require("react"), Internals = {
977
+ d: {
978
+ f: noop2,
979
+ r: function() {
980
+ throw Error(
981
+ "Invalid form element. requestFormReset must be passed a form that was rendered by React."
982
+ );
983
+ },
984
+ D: noop2,
985
+ C: noop2,
986
+ L: noop2,
987
+ m: noop2,
988
+ X: noop2,
989
+ S: noop2,
990
+ M: noop2
991
+ },
992
+ p: 0,
993
+ findDOMNode: null
994
+ }, REACT_PORTAL_TYPE = Symbol.for("react.portal"), ReactSharedInternals = React4.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
995
+ "function" === typeof Map && null != Map.prototype && "function" === typeof Map.prototype.forEach && "function" === typeof Set && null != Set.prototype && "function" === typeof Set.prototype.clear && "function" === typeof Set.prototype.forEach || console.error(
996
+ "React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"
997
+ );
998
+ exports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = Internals;
999
+ exports.createPortal = function(children, container) {
1000
+ var key = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null;
1001
+ if (!container || 1 !== container.nodeType && 9 !== container.nodeType && 11 !== container.nodeType)
1002
+ throw Error("Target container is not a DOM element.");
1003
+ return createPortal$1(children, container, null, key);
1004
+ };
1005
+ exports.flushSync = function(fn) {
1006
+ var previousTransition = ReactSharedInternals.T, previousUpdatePriority = Internals.p;
1007
+ try {
1008
+ if (ReactSharedInternals.T = null, Internals.p = 2, fn)
1009
+ return fn();
1010
+ } finally {
1011
+ ReactSharedInternals.T = previousTransition, Internals.p = previousUpdatePriority, Internals.d.f() && console.error(
1012
+ "flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task."
1013
+ );
1014
+ }
1015
+ };
1016
+ exports.preconnect = function(href, options) {
1017
+ "string" === typeof href && href ? null != options && "object" !== typeof options ? console.error(
1018
+ "ReactDOM.preconnect(): Expected the `options` argument (second) to be an object but encountered %s instead. The only supported option at this time is `crossOrigin` which accepts a string.",
1019
+ getValueDescriptorExpectingEnumForWarning(options)
1020
+ ) : null != options && "string" !== typeof options.crossOrigin && console.error(
1021
+ "ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered %s instead. Try removing this option or passing a string value instead.",
1022
+ getValueDescriptorExpectingObjectForWarning(options.crossOrigin)
1023
+ ) : console.error(
1024
+ "ReactDOM.preconnect(): Expected the `href` argument (first) to be a non-empty string but encountered %s instead.",
1025
+ getValueDescriptorExpectingObjectForWarning(href)
1026
+ );
1027
+ "string" === typeof href && (options ? (options = options.crossOrigin, options = "string" === typeof options ? "use-credentials" === options ? options : "" : void 0) : options = null, Internals.d.C(href, options));
1028
+ };
1029
+ exports.prefetchDNS = function(href) {
1030
+ if ("string" !== typeof href || !href)
1031
+ console.error(
1032
+ "ReactDOM.prefetchDNS(): Expected the `href` argument (first) to be a non-empty string but encountered %s instead.",
1033
+ getValueDescriptorExpectingObjectForWarning(href)
1034
+ );
1035
+ else if (1 < arguments.length) {
1036
+ var options = arguments[1];
1037
+ "object" === typeof options && options.hasOwnProperty("crossOrigin") ? console.error(
1038
+ "ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered %s as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.",
1039
+ getValueDescriptorExpectingEnumForWarning(options)
1040
+ ) : console.error(
1041
+ "ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered %s as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.",
1042
+ getValueDescriptorExpectingEnumForWarning(options)
1043
+ );
1044
+ }
1045
+ "string" === typeof href && Internals.d.D(href);
1046
+ };
1047
+ exports.preinit = function(href, options) {
1048
+ "string" === typeof href && href ? null == options || "object" !== typeof options ? console.error(
1049
+ "ReactDOM.preinit(): Expected the `options` argument (second) to be an object with an `as` property describing the type of resource to be preinitialized but encountered %s instead.",
1050
+ getValueDescriptorExpectingEnumForWarning(options)
1051
+ ) : "style" !== options.as && "script" !== options.as && console.error(
1052
+ 'ReactDOM.preinit(): Expected the `as` property in the `options` argument (second) to contain a valid value describing the type of resource to be preinitialized but encountered %s instead. Valid values for `as` are "style" and "script".',
1053
+ getValueDescriptorExpectingEnumForWarning(options.as)
1054
+ ) : console.error(
1055
+ "ReactDOM.preinit(): Expected the `href` argument (first) to be a non-empty string but encountered %s instead.",
1056
+ getValueDescriptorExpectingObjectForWarning(href)
1057
+ );
1058
+ if ("string" === typeof href && options && "string" === typeof options.as) {
1059
+ var as = options.as, crossOrigin = getCrossOriginStringAs(as, options.crossOrigin), integrity = "string" === typeof options.integrity ? options.integrity : void 0, fetchPriority = "string" === typeof options.fetchPriority ? options.fetchPriority : void 0;
1060
+ "style" === as ? Internals.d.S(
1061
+ href,
1062
+ "string" === typeof options.precedence ? options.precedence : void 0,
1063
+ {
1064
+ crossOrigin,
1065
+ integrity,
1066
+ fetchPriority
1067
+ }
1068
+ ) : "script" === as && Internals.d.X(href, {
1069
+ crossOrigin,
1070
+ integrity,
1071
+ fetchPriority,
1072
+ nonce: "string" === typeof options.nonce ? options.nonce : void 0
1073
+ });
1074
+ }
1075
+ };
1076
+ exports.preinitModule = function(href, options) {
1077
+ var encountered = "";
1078
+ "string" === typeof href && href || (encountered += " The `href` argument encountered was " + getValueDescriptorExpectingObjectForWarning(href) + ".");
1079
+ void 0 !== options && "object" !== typeof options ? encountered += " The `options` argument encountered was " + getValueDescriptorExpectingObjectForWarning(options) + "." : options && "as" in options && "script" !== options.as && (encountered += " The `as` option encountered was " + getValueDescriptorExpectingEnumForWarning(options.as) + ".");
1080
+ if (encountered)
1081
+ console.error(
1082
+ "ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property.%s",
1083
+ encountered
1084
+ );
1085
+ else
1086
+ switch (encountered = options && "string" === typeof options.as ? options.as : "script", encountered) {
1087
+ case "script":
1088
+ break;
1089
+ default:
1090
+ encountered = getValueDescriptorExpectingEnumForWarning(encountered), console.error(
1091
+ 'ReactDOM.preinitModule(): Currently the only supported "as" type for this function is "script" but received "%s" instead. This warning was generated for `href` "%s". In the future other module types will be supported, aligning with the import-attributes proposal. Learn more here: (https://github.com/tc39/proposal-import-attributes)',
1092
+ encountered,
1093
+ href
1094
+ );
1095
+ }
1096
+ if ("string" === typeof href)
1097
+ if ("object" === typeof options && null !== options) {
1098
+ if (null == options.as || "script" === options.as)
1099
+ encountered = getCrossOriginStringAs(
1100
+ options.as,
1101
+ options.crossOrigin
1102
+ ), Internals.d.M(href, {
1103
+ crossOrigin: encountered,
1104
+ integrity: "string" === typeof options.integrity ? options.integrity : void 0,
1105
+ nonce: "string" === typeof options.nonce ? options.nonce : void 0
1106
+ });
1107
+ } else null == options && Internals.d.M(href);
1108
+ };
1109
+ exports.preload = function(href, options) {
1110
+ var encountered = "";
1111
+ "string" === typeof href && href || (encountered += " The `href` argument encountered was " + getValueDescriptorExpectingObjectForWarning(href) + ".");
1112
+ null == options || "object" !== typeof options ? encountered += " The `options` argument encountered was " + getValueDescriptorExpectingObjectForWarning(options) + "." : "string" === typeof options.as && options.as || (encountered += " The `as` option encountered was " + getValueDescriptorExpectingObjectForWarning(options.as) + ".");
1113
+ encountered && console.error(
1114
+ 'ReactDOM.preload(): Expected two arguments, a non-empty `href` string and an `options` object with an `as` property valid for a `<link rel="preload" as="..." />` tag.%s',
1115
+ encountered
1116
+ );
1117
+ if ("string" === typeof href && "object" === typeof options && null !== options && "string" === typeof options.as) {
1118
+ encountered = options.as;
1119
+ var crossOrigin = getCrossOriginStringAs(
1120
+ encountered,
1121
+ options.crossOrigin
1122
+ );
1123
+ Internals.d.L(href, encountered, {
1124
+ crossOrigin,
1125
+ integrity: "string" === typeof options.integrity ? options.integrity : void 0,
1126
+ nonce: "string" === typeof options.nonce ? options.nonce : void 0,
1127
+ type: "string" === typeof options.type ? options.type : void 0,
1128
+ fetchPriority: "string" === typeof options.fetchPriority ? options.fetchPriority : void 0,
1129
+ referrerPolicy: "string" === typeof options.referrerPolicy ? options.referrerPolicy : void 0,
1130
+ imageSrcSet: "string" === typeof options.imageSrcSet ? options.imageSrcSet : void 0,
1131
+ imageSizes: "string" === typeof options.imageSizes ? options.imageSizes : void 0,
1132
+ media: "string" === typeof options.media ? options.media : void 0
1133
+ });
1134
+ }
1135
+ };
1136
+ exports.preloadModule = function(href, options) {
1137
+ var encountered = "";
1138
+ "string" === typeof href && href || (encountered += " The `href` argument encountered was " + getValueDescriptorExpectingObjectForWarning(href) + ".");
1139
+ void 0 !== options && "object" !== typeof options ? encountered += " The `options` argument encountered was " + getValueDescriptorExpectingObjectForWarning(options) + "." : options && "as" in options && "string" !== typeof options.as && (encountered += " The `as` option encountered was " + getValueDescriptorExpectingObjectForWarning(options.as) + ".");
1140
+ encountered && console.error(
1141
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag.%s',
1142
+ encountered
1143
+ );
1144
+ "string" === typeof href && (options ? (encountered = getCrossOriginStringAs(
1145
+ options.as,
1146
+ options.crossOrigin
1147
+ ), Internals.d.m(href, {
1148
+ as: "string" === typeof options.as && "script" !== options.as ? options.as : void 0,
1149
+ crossOrigin: encountered,
1150
+ integrity: "string" === typeof options.integrity ? options.integrity : void 0
1151
+ })) : Internals.d.m(href));
1152
+ };
1153
+ exports.requestFormReset = function(form) {
1154
+ Internals.d.r(form);
1155
+ };
1156
+ exports.unstable_batchedUpdates = function(fn, a) {
1157
+ return fn(a);
1158
+ };
1159
+ exports.useFormState = function(action, initialState, permalink) {
1160
+ return resolveDispatcher().useFormState(action, initialState, permalink);
1161
+ };
1162
+ exports.useFormStatus = function() {
1163
+ return resolveDispatcher().useHostTransitionStatus();
1164
+ };
1165
+ exports.version = "19.1.0";
1166
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
1167
+ })();
1168
+ }
1169
+ });
1170
+
1171
+ // node_modules/react-dom/index.js
1172
+ var require_react_dom = __commonJS({
1173
+ "node_modules/react-dom/index.js"(exports, module) {
1174
+ "use strict";
1175
+ if (false) {
1176
+ checkDCE();
1177
+ module.exports = null;
1178
+ } else {
1179
+ module.exports = require_react_dom_development();
1180
+ }
1181
+ }
1182
+ });
1183
+
921
1184
  // src/PCBViewer.tsx
922
1185
  import { applyEditEvents } from "@tscircuit/core";
923
1186
 
@@ -2233,6 +2496,8 @@ var setStoredString = (key, value) => {
2233
2496
  var DEFAULT_PCB_GROUP_VIEW_MODE = true ? "named_only" : "all";
2234
2497
  var createStore = (initialState = {}, disablePcbGroups = false) => createZustandStore(
2235
2498
  (set) => ({
2499
+ hidden_layer_opacity: 0.4,
2500
+ setHiddenLayerOpacity: (opacity) => set({ hidden_layer_opacity: Math.max(0, Math.min(1, opacity)) }),
2236
2501
  selected_layer: "top",
2237
2502
  pcb_viewer_id: `pcb_viewer_${Math.random().toString().slice(2, 10)}`,
2238
2503
  in_edit_mode: false,
@@ -2378,7 +2643,7 @@ var ToastContainer = () => {
2378
2643
  };
2379
2644
 
2380
2645
  // src/PCBViewer.tsx
2381
- import { useCallback as useCallback12, useEffect as useEffect18, useMemo as useMemo9, useRef as useRef15, useState as useState12 } from "react";
2646
+ import { useCallback as useCallback12, useEffect as useEffect19, useMemo as useMemo9, useRef as useRef16, useState as useState13 } from "react";
2382
2647
 
2383
2648
  // node_modules/react-use/esm/useMountedState.js
2384
2649
  import { useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
@@ -4182,7 +4447,7 @@ var animateTransform = ({
4182
4447
  };
4183
4448
 
4184
4449
  // src/components/CanvasElementsRenderer.tsx
4185
- import { useCallback as useCallback11, useEffect as useEffect17, useMemo as useMemo8, useRef as useRef14, useState as useState11 } from "react";
4450
+ import { useCallback as useCallback11, useEffect as useEffect18, useMemo as useMemo8, useRef as useRef15, useState as useState12 } from "react";
4186
4451
 
4187
4452
  // src/lib/Drawer.ts
4188
4453
  import colorParser from "color";
@@ -4516,6 +4781,7 @@ var Drawer = class {
4516
4781
  aperture;
4517
4782
  transform;
4518
4783
  foregroundLayer = "top";
4784
+ hiddenLayerOpacity = 0.4;
4519
4785
  lastPoint;
4520
4786
  constructor(canvasLayerMap) {
4521
4787
  this.canvasLayerMap = canvasLayerMap;
@@ -4790,11 +5056,19 @@ var Drawer = class {
4790
5056
  }
4791
5057
  return ctx;
4792
5058
  }
5059
+ getLayerOpacity(layer) {
5060
+ const side = this.foregroundLayer;
5061
+ const isSelectedSideDetail = (side === "top" || side === "bottom") && (layer.startsWith(`${side}_`) || layer.endsWith(`_${side}`));
5062
+ const isSharedLayer = ["board", "drill", "edge_cuts", "other"].includes(
5063
+ layer
5064
+ );
5065
+ return layer === side || isSelectedSideDetail || isSharedLayer ? 1 : this.hiddenLayerOpacity;
5066
+ }
4793
5067
  /**
4794
5068
  * Iterate over each canvas and set the z index based on the layer order, but
4795
5069
  * always render the foreground layer on top.
4796
5070
  *
4797
- * Also: Set the opacity of every non-foreground layer to 0.5
5071
+ * Fade inactive layers using the configured hidden-layer opacity.
4798
5072
  */
4799
5073
  orderAndFadeLayers() {
4800
5074
  const { canvasLayerMap, foregroundLayer } = this;
@@ -4811,18 +5085,6 @@ var Drawer = class {
4811
5085
  const associatedNotes = foregroundLayer === "top" ? "top_notes" : foregroundLayer === "bottom" ? "bottom_notes" : void 0;
4812
5086
  const associatedFabrication = foregroundLayer === "top" ? "top_fabrication" : foregroundLayer === "bottom" ? "bottom_fabrication" : void 0;
4813
5087
  const associatedCourtyard = foregroundLayer === "top" ? "top_courtyard" : foregroundLayer === "bottom" ? "bottom_courtyard" : void 0;
4814
- const opaqueLayers = /* @__PURE__ */ new Set([
4815
- foregroundLayer,
4816
- "drill",
4817
- "edge_cuts",
4818
- "other",
4819
- "board",
4820
- ...associatedSoldermask ? [associatedSoldermask] : [],
4821
- ...associatedSilkscreen ? [associatedSilkscreen] : [],
4822
- ...associatedNotes ? [associatedNotes] : [],
4823
- ...associatedFabrication ? [associatedFabrication] : [],
4824
- ...associatedCourtyard ? [associatedCourtyard] : []
4825
- ]);
4826
5088
  const layersToShiftToTop = [
4827
5089
  foregroundLayer,
4828
5090
  "edge_cuts",
@@ -4847,8 +5109,12 @@ var Drawer = class {
4847
5109
  const canvas = canvasLayerMap[layer];
4848
5110
  if (!canvas) return;
4849
5111
  canvas.style.zIndex = `${zIndexMap.topLayer - (order.length - i)}`;
4850
- canvas.style.opacity = opaqueLayers.has(layer) ? "1" : "0.5";
4851
5112
  });
5113
+ for (const [layer, canvas] of Object.entries(canvasLayerMap)) {
5114
+ const opacity = this.getLayerOpacity(layer);
5115
+ canvas.style.opacity = String(opacity);
5116
+ canvas.style.display = opacity === 0 ? "none" : "";
5117
+ }
4852
5118
  }
4853
5119
  applyAperture() {
4854
5120
  const { transform, aperture } = this;
@@ -5961,27 +6227,21 @@ function drawSoldermaskElementsForLayer({
5961
6227
  const drawer = new CircuitToCanvasDrawer15(canvas);
5962
6228
  drawer.realToCanvasMat = realToCanvasMat;
5963
6229
  const boards = elements.filter((element) => element.type === "pcb_board");
5964
- if (boards.length <= 1) {
5965
- drawer.drawElements(elements, {
5966
- layers,
5967
- drawSoldermask: true,
5968
- drawSoldermaskTop,
5969
- drawSoldermaskBottom,
5970
- drawBoardMaterial: false
6230
+ drawer.drawElements(elements, {
6231
+ layers,
6232
+ drawSoldermask: true,
6233
+ drawSoldermaskTop,
6234
+ drawSoldermaskBottom,
6235
+ drawBoardMaterial: false
6236
+ });
6237
+ if (boards.length > 1) {
6238
+ drawPcbBoardElements({
6239
+ canvas,
6240
+ elements: boards,
6241
+ layers: [],
6242
+ realToCanvasMat,
6243
+ drawSoldermask: false
5971
6244
  });
5972
- } else {
5973
- const nonBoardElements = elements.filter(
5974
- (element) => element.type !== "pcb_board"
5975
- );
5976
- for (const board of boards) {
5977
- drawer.drawElements([board, ...nonBoardElements], {
5978
- layers,
5979
- drawSoldermask: true,
5980
- drawSoldermaskTop,
5981
- drawSoldermaskBottom,
5982
- drawBoardMaterial: false
5983
- });
5984
- }
5985
6245
  }
5986
6246
  if (!primitives) return;
5987
6247
  const hoveredElementIds = /* @__PURE__ */ new Set();
@@ -6118,6 +6378,7 @@ var CanvasPrimitiveRenderer = ({
6118
6378
  height = 500
6119
6379
  }) => {
6120
6380
  const canvasRefs = useRef3({});
6381
+ const hiddenLayerOpacity = useGlobalStore((s) => s.hidden_layer_opacity);
6121
6382
  const selectedLayer = useGlobalStore((s) => s.selected_layer);
6122
6383
  const isShowingCopperPours = useGlobalStore((s) => s.is_showing_copper_pours);
6123
6384
  const isShowingSolderMask = useGlobalStore((s) => s.is_showing_solder_mask);
@@ -6141,16 +6402,27 @@ var CanvasPrimitiveRenderer = ({
6141
6402
  if (transform) drawer.transform = transform;
6142
6403
  drawer.clear();
6143
6404
  drawer.foregroundLayer = selectedLayer;
6405
+ drawer.hiddenLayerOpacity = hiddenLayerOpacity;
6406
+ const visibleCanvasRefs = Object.fromEntries(
6407
+ Object.entries(availableCanvasRefs).filter(
6408
+ ([layer]) => drawer.getLayerOpacity(layer) > 0
6409
+ )
6410
+ );
6144
6411
  const filteredPrimitives = getPrimitivesForDrawer({
6145
6412
  primitives,
6146
6413
  isShowingSolderMask,
6147
6414
  isShowingSilkscreen,
6148
6415
  isShowingFabricationNotes
6149
6416
  });
6150
- drawPrimitives(drawer, filteredPrimitives);
6417
+ drawPrimitives(
6418
+ drawer,
6419
+ filteredPrimitives.filter(
6420
+ (p) => drawer.getLayerOpacity(p.layer ?? "other") > 0
6421
+ )
6422
+ );
6151
6423
  if (transform) {
6152
6424
  const copperLayers = getCopperLayerRefsFromElements(elements).map((layer) => ({
6153
- canvas: canvasRefs.current[layer],
6425
+ canvas: visibleCanvasRefs[layer],
6154
6426
  layer,
6155
6427
  copperLayer: getCopperRenderLayer(layer)
6156
6428
  }));
@@ -6220,7 +6492,7 @@ var CanvasPrimitiveRenderer = ({
6220
6492
  const soldermaskLayer = selectedLayer === "bottom" ? "bottom" : "top";
6221
6493
  const drawSoldermaskTop = soldermaskLayer === "top";
6222
6494
  const drawSoldermaskBottom = soldermaskLayer === "bottom";
6223
- const topSoldermaskCanvas = canvasRefs.current.soldermask_top;
6495
+ const topSoldermaskCanvas = visibleCanvasRefs.soldermask_top;
6224
6496
  if (topSoldermaskCanvas && soldermaskLayer === "top") {
6225
6497
  drawSoldermaskElementsForLayer({
6226
6498
  canvas: topSoldermaskCanvas,
@@ -6232,7 +6504,7 @@ var CanvasPrimitiveRenderer = ({
6232
6504
  primitives
6233
6505
  });
6234
6506
  }
6235
- const bottomSoldermaskCanvas = canvasRefs.current.soldermask_bottom;
6507
+ const bottomSoldermaskCanvas = visibleCanvasRefs.soldermask_bottom;
6236
6508
  if (bottomSoldermaskCanvas && soldermaskLayer === "bottom") {
6237
6509
  drawSoldermaskElementsForLayer({
6238
6510
  canvas: bottomSoldermaskCanvas,
@@ -6245,7 +6517,7 @@ var CanvasPrimitiveRenderer = ({
6245
6517
  });
6246
6518
  }
6247
6519
  }
6248
- const drillCanvas = canvasRefs.current.drill;
6520
+ const drillCanvas = visibleCanvasRefs.drill;
6249
6521
  if (drillCanvas) {
6250
6522
  drawPcbHoleElementsForLayer({
6251
6523
  canvas: drillCanvas,
@@ -6255,7 +6527,7 @@ var CanvasPrimitiveRenderer = ({
6255
6527
  });
6256
6528
  }
6257
6529
  if (isShowingSilkscreen) {
6258
- const topSilkscreenCanvas = canvasRefs.current.top_silkscreen;
6530
+ const topSilkscreenCanvas = visibleCanvasRefs.top_silkscreen;
6259
6531
  if (topSilkscreenCanvas) {
6260
6532
  drawSilkscreenElementsForLayer({
6261
6533
  canvas: topSilkscreenCanvas,
@@ -6264,7 +6536,7 @@ var CanvasPrimitiveRenderer = ({
6264
6536
  realToCanvasMat: transform
6265
6537
  });
6266
6538
  }
6267
- const bottomSilkscreenCanvas = canvasRefs.current.bottom_silkscreen;
6539
+ const bottomSilkscreenCanvas = visibleCanvasRefs.bottom_silkscreen;
6268
6540
  if (bottomSilkscreenCanvas) {
6269
6541
  drawSilkscreenElementsForLayer({
6270
6542
  canvas: bottomSilkscreenCanvas,
@@ -6275,7 +6547,7 @@ var CanvasPrimitiveRenderer = ({
6275
6547
  }
6276
6548
  }
6277
6549
  if (isShowingFabricationNotes) {
6278
- const topFabCanvas = canvasRefs.current.top_fabrication;
6550
+ const topFabCanvas = visibleCanvasRefs.top_fabrication;
6279
6551
  if (topFabCanvas) {
6280
6552
  drawFabricationNoteElementsForLayer({
6281
6553
  canvas: topFabCanvas,
@@ -6284,7 +6556,7 @@ var CanvasPrimitiveRenderer = ({
6284
6556
  realToCanvasMat: transform
6285
6557
  });
6286
6558
  }
6287
- const bottomFabCanvas = canvasRefs.current.bottom_fabrication;
6559
+ const bottomFabCanvas = visibleCanvasRefs.bottom_fabrication;
6288
6560
  if (bottomFabCanvas) {
6289
6561
  drawFabricationNoteElementsForLayer({
6290
6562
  canvas: bottomFabCanvas,
@@ -6295,7 +6567,7 @@ var CanvasPrimitiveRenderer = ({
6295
6567
  }
6296
6568
  }
6297
6569
  if (isShowingPcbNotes) {
6298
- const bottomNotesCanvas = canvasRefs.current.bottom_notes;
6570
+ const bottomNotesCanvas = visibleCanvasRefs.bottom_notes;
6299
6571
  if (bottomNotesCanvas) {
6300
6572
  drawPcbNoteElementsForLayer({
6301
6573
  canvas: bottomNotesCanvas,
@@ -6304,7 +6576,7 @@ var CanvasPrimitiveRenderer = ({
6304
6576
  realToCanvasMat: transform
6305
6577
  });
6306
6578
  }
6307
- const topNotesCanvas = canvasRefs.current.top_notes;
6579
+ const topNotesCanvas = visibleCanvasRefs.top_notes;
6308
6580
  if (topNotesCanvas) {
6309
6581
  drawPcbNoteElementsForLayer({
6310
6582
  canvas: topNotesCanvas,
@@ -6315,7 +6587,7 @@ var CanvasPrimitiveRenderer = ({
6315
6587
  }
6316
6588
  }
6317
6589
  if (isShowingCourtyards) {
6318
- const topCourtyardCanvas = canvasRefs.current.top_courtyard;
6590
+ const topCourtyardCanvas = visibleCanvasRefs.top_courtyard;
6319
6591
  if (topCourtyardCanvas) {
6320
6592
  drawCourtyardElementsForLayer({
6321
6593
  canvas: topCourtyardCanvas,
@@ -6324,7 +6596,7 @@ var CanvasPrimitiveRenderer = ({
6324
6596
  realToCanvasMat: transform
6325
6597
  });
6326
6598
  }
6327
- const bottomCourtyardCanvas = canvasRefs.current.bottom_courtyard;
6599
+ const bottomCourtyardCanvas = visibleCanvasRefs.bottom_courtyard;
6328
6600
  if (bottomCourtyardCanvas) {
6329
6601
  drawCourtyardElementsForLayer({
6330
6602
  canvas: bottomCourtyardCanvas,
@@ -6334,7 +6606,7 @@ var CanvasPrimitiveRenderer = ({
6334
6606
  });
6335
6607
  }
6336
6608
  }
6337
- const boardCanvas = canvasRefs.current.board;
6609
+ const boardCanvas = visibleCanvasRefs.board;
6338
6610
  if (boardCanvas) {
6339
6611
  drawPcbPanelElements({
6340
6612
  canvas: boardCanvas,
@@ -6351,7 +6623,7 @@ var CanvasPrimitiveRenderer = ({
6351
6623
  drawSoldermask: isShowingSolderMask
6352
6624
  });
6353
6625
  }
6354
- const edgeCutsCanvas = canvasRefs.current.edge_cuts;
6626
+ const edgeCutsCanvas = visibleCanvasRefs.edge_cuts;
6355
6627
  if (edgeCutsCanvas) {
6356
6628
  drawPcbCutoutElementsForLayer({
6357
6629
  canvas: edgeCutsCanvas,
@@ -6376,6 +6648,7 @@ var CanvasPrimitiveRenderer = ({
6376
6648
  elements,
6377
6649
  transform,
6378
6650
  selectedLayer,
6651
+ hiddenLayerOpacity,
6379
6652
  isShowingCopperPours,
6380
6653
  isShowingSolderMask,
6381
6654
  isShowingFabricationNotes,
@@ -10625,18 +10898,18 @@ var RatsNestOverlay = ({ transform, soup, children }) => {
10625
10898
 
10626
10899
  // src/components/ToolbarOverlay.tsx
10627
10900
  import {
10628
- useEffect as useEffect15,
10629
- useState as useState10,
10901
+ useEffect as useEffect16,
10902
+ useState as useState11,
10630
10903
  useCallback as useCallback10,
10631
- useRef as useRef12,
10904
+ useRef as useRef13,
10632
10905
  useLayoutEffect as useLayoutEffect2
10633
10906
  } from "react";
10634
- import { css as css2 } from "@emotion/css";
10907
+ import { css as css3 } from "@emotion/css";
10635
10908
 
10636
10909
  // package.json
10637
10910
  var package_default = {
10638
10911
  name: "@tscircuit/pcb-viewer",
10639
- version: "1.11.392",
10912
+ version: "1.11.394",
10640
10913
  main: "dist/index.js",
10641
10914
  type: "module",
10642
10915
  repository: {
@@ -10669,6 +10942,7 @@ var package_default = {
10669
10942
  "@types/color": "^3.0.6",
10670
10943
  "@types/node": "18.7.23",
10671
10944
  "@types/react": "19",
10945
+ "@types/react-dom": "~19.1.0",
10672
10946
  "format-si-unit": "^0.0.12",
10673
10947
  next: "^14.1.4",
10674
10948
  "pixi.js": "^8.6.6",
@@ -10793,8 +11067,228 @@ var useMobileTouch = (onClick, options = { stopPropagation: true }) => {
10793
11067
  };
10794
11068
  };
10795
11069
 
11070
+ // src/components/VisibilityContextMenu.tsx
11071
+ var import_react_dom = __toESM(require_react_dom(), 1);
11072
+ import { css as css2 } from "@emotion/css";
11073
+ import { useEffect as useEffect14, useRef as useRef11, useState as useState9 } from "react";
11074
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
11075
+ var menuStyle = css2`
11076
+ background: #222;
11077
+ color: #eee;
11078
+ border: 1px solid #555;
11079
+ border-radius: 4px;
11080
+ padding: 4px;
11081
+ font: 12px sans-serif;
11082
+ box-shadow: 0 4px 16px #0008;
11083
+ `;
11084
+ var itemStyle = css2`
11085
+ display: block;
11086
+ width: 100%;
11087
+ padding: 8px;
11088
+ border: 0;
11089
+ border-radius: 2px;
11090
+ background: transparent;
11091
+ color: inherit;
11092
+ font: inherit;
11093
+ text-align: left;
11094
+ white-space: nowrap;
11095
+ cursor: pointer;
11096
+ &:hover, &:focus-visible { background: #444; }
11097
+ `;
11098
+ var VisibilityContextMenu = ({
11099
+ position,
11100
+ onClose
11101
+ }) => {
11102
+ const opacity = useGlobalStore((s) => s.hidden_layer_opacity);
11103
+ const setOpacity = useGlobalStore((s) => s.setHiddenLayerOpacity);
11104
+ const [visibilityOpen, setVisibilityOpen] = useState9(false);
11105
+ const [opacityOpen, setOpacityOpen] = useState9(false);
11106
+ const ref = useRef11(null);
11107
+ const stacked = window.innerWidth < 480;
11108
+ const openLeft = !stacked && position.x + 460 > window.innerWidth;
11109
+ const submenuStyle = stacked ? { position: "relative" } : {
11110
+ position: "absolute",
11111
+ top: 0,
11112
+ ...openLeft ? { right: "100%" } : { left: "100%" }
11113
+ };
11114
+ useEffect14(() => {
11115
+ const dismiss = (event) => {
11116
+ if (!ref.current?.contains(event.target)) onClose();
11117
+ };
11118
+ const onKeyDown = (event) => {
11119
+ if (event.key === "Escape") {
11120
+ event.preventDefault();
11121
+ onClose();
11122
+ }
11123
+ };
11124
+ ref.current?.querySelector("button")?.focus();
11125
+ window.addEventListener("pointerdown", dismiss, true);
11126
+ window.addEventListener("keydown", onKeyDown);
11127
+ window.addEventListener("resize", onClose);
11128
+ window.addEventListener("scroll", onClose, true);
11129
+ return () => {
11130
+ window.removeEventListener("pointerdown", dismiss, true);
11131
+ window.removeEventListener("keydown", onKeyDown);
11132
+ window.removeEventListener("resize", onClose);
11133
+ window.removeEventListener("scroll", onClose, true);
11134
+ };
11135
+ }, [onClose]);
11136
+ return (0, import_react_dom.createPortal)(
11137
+ /* @__PURE__ */ jsx18(
11138
+ "div",
11139
+ {
11140
+ ref,
11141
+ role: "menu",
11142
+ "aria-label": "PCB context menu",
11143
+ className: menuStyle,
11144
+ onContextMenu: (event) => {
11145
+ event.preventDefault();
11146
+ event.stopPropagation();
11147
+ },
11148
+ onPointerDown: (event) => event.stopPropagation(),
11149
+ onMouseDown: (event) => event.stopPropagation(),
11150
+ onClick: (event) => event.stopPropagation(),
11151
+ onKeyDown: (event) => {
11152
+ event.stopPropagation();
11153
+ const button = event.target.closest("button");
11154
+ if (!button) return;
11155
+ const menu = button.closest('[role="menu"]');
11156
+ const items = Array.from(menu.querySelectorAll("button")).filter(
11157
+ (item) => item.closest('[role="menu"]') === menu
11158
+ );
11159
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
11160
+ event.preventDefault();
11161
+ const step = event.key === "ArrowDown" ? 1 : -1;
11162
+ items[(items.indexOf(button) + step + items.length) % items.length]?.focus();
11163
+ } else if (event.key === "ArrowRight" && button.hasAttribute("aria-haspopup")) {
11164
+ event.preventDefault();
11165
+ button.click();
11166
+ requestAnimationFrame(
11167
+ () => button.parentElement?.querySelector('[role="menu"] button')?.focus()
11168
+ );
11169
+ } else if (event.key === "ArrowLeft") {
11170
+ event.preventDefault();
11171
+ menu.parentElement?.querySelector(":scope > button")?.focus();
11172
+ if (menu.getAttribute("aria-label") === "Hidden Layer Visibility")
11173
+ setOpacityOpen(false);
11174
+ else if (menu.getAttribute("aria-label") === "Visibility")
11175
+ setVisibilityOpen(false);
11176
+ } else if (event.key === "Escape") {
11177
+ event.preventDefault();
11178
+ onClose();
11179
+ }
11180
+ },
11181
+ style: {
11182
+ position: "fixed",
11183
+ zIndex: 1e4,
11184
+ left: Math.max(
11185
+ openLeft ? 310 : 4,
11186
+ Math.min(position.x, window.innerWidth - (stacked ? 248 : 148))
11187
+ ),
11188
+ top: Math.max(
11189
+ 4,
11190
+ Math.min(position.y, window.innerHeight - (stacked ? 340 : 260))
11191
+ ),
11192
+ width: stacked ? 230 : 130,
11193
+ maxHeight: window.innerHeight - 8,
11194
+ ...stacked ? { overflowY: "auto" } : {}
11195
+ },
11196
+ children: /* @__PURE__ */ jsxs13(
11197
+ "div",
11198
+ {
11199
+ style: { position: "relative" },
11200
+ onMouseEnter: () => setVisibilityOpen(true),
11201
+ children: [
11202
+ /* @__PURE__ */ jsx18(
11203
+ "button",
11204
+ {
11205
+ type: "button",
11206
+ role: "menuitem",
11207
+ "aria-haspopup": "menu",
11208
+ "aria-expanded": visibilityOpen,
11209
+ className: itemStyle,
11210
+ onClick: () => setVisibilityOpen(true),
11211
+ children: "Visibility \u25B8"
11212
+ }
11213
+ ),
11214
+ visibilityOpen && /* @__PURE__ */ jsx18(
11215
+ "div",
11216
+ {
11217
+ role: "menu",
11218
+ "aria-label": "Visibility",
11219
+ className: menuStyle,
11220
+ style: submenuStyle,
11221
+ children: /* @__PURE__ */ jsxs13(
11222
+ "div",
11223
+ {
11224
+ style: { position: "relative" },
11225
+ onMouseEnter: () => setOpacityOpen(true),
11226
+ children: [
11227
+ /* @__PURE__ */ jsx18(
11228
+ "button",
11229
+ {
11230
+ type: "button",
11231
+ role: "menuitem",
11232
+ "aria-haspopup": "menu",
11233
+ "aria-expanded": opacityOpen,
11234
+ className: itemStyle,
11235
+ onClick: () => setOpacityOpen(true),
11236
+ children: "Hidden Layer Visibility \u25B8"
11237
+ }
11238
+ ),
11239
+ opacityOpen && /* @__PURE__ */ jsx18(
11240
+ "div",
11241
+ {
11242
+ role: "menu",
11243
+ "aria-label": "Hidden Layer Visibility",
11244
+ className: menuStyle,
11245
+ style: {
11246
+ minWidth: 80,
11247
+ ...submenuStyle
11248
+ },
11249
+ children: [0, 0.1, 0.2, 0.4, 0.6, 0.8, 1].map((value) => /* @__PURE__ */ jsxs13(
11250
+ "button",
11251
+ {
11252
+ type: "button",
11253
+ role: "menuitemradio",
11254
+ "aria-checked": opacity === value,
11255
+ className: itemStyle,
11256
+ onClick: () => {
11257
+ setOpacity(value);
11258
+ onClose();
11259
+ },
11260
+ children: [
11261
+ /* @__PURE__ */ jsx18(
11262
+ "span",
11263
+ {
11264
+ "aria-hidden": "true",
11265
+ style: { display: "inline-block", width: 16 },
11266
+ children: opacity === value ? "\u2713" : ""
11267
+ }
11268
+ ),
11269
+ value === 0 ? "Hide" : `${value * 100}%`
11270
+ ]
11271
+ },
11272
+ value
11273
+ ))
11274
+ }
11275
+ )
11276
+ ]
11277
+ }
11278
+ )
11279
+ }
11280
+ )
11281
+ ]
11282
+ }
11283
+ )
11284
+ }
11285
+ ),
11286
+ document.body
11287
+ );
11288
+ };
11289
+
10796
11290
  // src/components/ToolbarButton.tsx
10797
- import { jsx as jsx18 } from "react/jsx-runtime";
11291
+ import { jsx as jsx19 } from "react/jsx-runtime";
10798
11292
  var ToolbarButton = ({
10799
11293
  children,
10800
11294
  isSmallScreen,
@@ -10802,7 +11296,7 @@ var ToolbarButton = ({
10802
11296
  ...props
10803
11297
  }) => {
10804
11298
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
10805
- return /* @__PURE__ */ jsx18(
11299
+ return /* @__PURE__ */ jsx19(
10806
11300
  "div",
10807
11301
  {
10808
11302
  ...props,
@@ -10830,7 +11324,7 @@ var ToolbarButton = ({
10830
11324
  };
10831
11325
 
10832
11326
  // src/components/ToolbarErrorDropdown.tsx
10833
- import { useCallback as useCallback9, useMemo as useMemo7, useState as useState9 } from "react";
11327
+ import { useCallback as useCallback9, useMemo as useMemo7, useState as useState10 } from "react";
10834
11328
 
10835
11329
  // src/lib/util/group-errors-by-type.ts
10836
11330
  var groupErrorsByType = (errors) => {
@@ -10852,16 +11346,16 @@ var groupErrorsByType = (errors) => {
10852
11346
  };
10853
11347
 
10854
11348
  // src/components/useToolbarErrorFocus.ts
10855
- import { useCallback as useCallback8, useEffect as useEffect14, useRef as useRef11 } from "react";
11349
+ import { useCallback as useCallback8, useEffect as useEffect15, useRef as useRef12 } from "react";
10856
11350
  var useToolbarErrorFocus = ({
10857
11351
  onClose,
10858
11352
  setHoveredErrorId,
10859
11353
  setFocusedErrorId,
10860
11354
  highlightDurationMs = 3e3
10861
11355
  }) => {
10862
- const clearHighlightTimeoutRef = useRef11(null);
10863
- const focusRequestRef = useRef11(null);
10864
- const selectedErrorIdRef = useRef11(null);
11356
+ const clearHighlightTimeoutRef = useRef12(null);
11357
+ const focusRequestRef = useRef12(null);
11358
+ const selectedErrorIdRef = useRef12(null);
10865
11359
  const clearPendingSelection = useCallback8(() => {
10866
11360
  if (clearHighlightTimeoutRef.current !== null) {
10867
11361
  window.clearTimeout(clearHighlightTimeoutRef.current);
@@ -10872,7 +11366,7 @@ var useToolbarErrorFocus = ({
10872
11366
  focusRequestRef.current = null;
10873
11367
  }
10874
11368
  }, []);
10875
- useEffect14(() => clearPendingSelection, [clearPendingSelection]);
11369
+ useEffect15(() => clearPendingSelection, [clearPendingSelection]);
10876
11370
  const handleErrorSelect = useCallback8(
10877
11371
  (errorId) => {
10878
11372
  clearPendingSelection();
@@ -10910,7 +11404,7 @@ var useToolbarErrorFocus = ({
10910
11404
  };
10911
11405
 
10912
11406
  // src/components/ToolbarErrorDropdown.tsx
10913
- import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
11407
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
10914
11408
  var CopyErrorButton = ({
10915
11409
  errorId,
10916
11410
  errorMessage,
@@ -10920,7 +11414,7 @@ var CopyErrorButton = ({
10920
11414
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(
10921
11415
  () => onCopy(errorMessage, errorId)
10922
11416
  );
10923
- return /* @__PURE__ */ jsx19(
11417
+ return /* @__PURE__ */ jsx20(
10924
11418
  "button",
10925
11419
  {
10926
11420
  type: "button",
@@ -10940,7 +11434,7 @@ var CopyErrorButton = ({
10940
11434
  ...touchStyle
10941
11435
  },
10942
11436
  ...touchHandlers,
10943
- children: copiedErrorId === errorId ? /* @__PURE__ */ jsx19("span", { style: { color: "#4caf50", fontSize: 12 }, children: "Copied!" }) : /* @__PURE__ */ jsx19("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx19("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" }) })
11437
+ children: copiedErrorId === errorId ? /* @__PURE__ */ jsx20("span", { style: { color: "#4caf50", fontSize: 12 }, children: "Copied!" }) : /* @__PURE__ */ jsx20("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx20("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" }) })
10944
11438
  }
10945
11439
  );
10946
11440
  };
@@ -10953,11 +11447,11 @@ var ToolbarErrorDropdown = ({
10953
11447
  setHoveredErrorId,
10954
11448
  setFocusedErrorId
10955
11449
  }) => {
10956
- const [copiedErrorId, setCopiedErrorId] = useState9(null);
10957
- const [collapsedErrorGroups, setCollapsedErrorGroups] = useState9(
11450
+ const [copiedErrorId, setCopiedErrorId] = useState10(null);
11451
+ const [collapsedErrorGroups, setCollapsedErrorGroups] = useState10(
10958
11452
  /* @__PURE__ */ new Set()
10959
11453
  );
10960
- const [expandedErrorIds, setExpandedErrorIds] = useState9(
11454
+ const [expandedErrorIds, setExpandedErrorIds] = useState10(
10961
11455
  /* @__PURE__ */ new Set()
10962
11456
  );
10963
11457
  const [, copyToClipboard] = useCopyToClipboard_default();
@@ -10999,20 +11493,20 @@ var ToolbarErrorDropdown = ({
10999
11493
  return next;
11000
11494
  });
11001
11495
  }, []);
11002
- return /* @__PURE__ */ jsxs13("div", { style: { position: "relative" }, children: [
11003
- /* @__PURE__ */ jsx19(
11496
+ return /* @__PURE__ */ jsxs14("div", { style: { position: "relative" }, children: [
11497
+ /* @__PURE__ */ jsx20(
11004
11498
  ToolbarButton,
11005
11499
  {
11006
11500
  isSmallScreen,
11007
11501
  style: errorCount > 0 ? { color: "red" } : void 0,
11008
11502
  onClick: onToggle,
11009
- children: /* @__PURE__ */ jsxs13("div", { children: [
11503
+ children: /* @__PURE__ */ jsxs14("div", { children: [
11010
11504
  errorCount,
11011
11505
  " errors"
11012
11506
  ] })
11013
11507
  }
11014
11508
  ),
11015
- isOpen && errorCount > 0 && /* @__PURE__ */ jsx19(
11509
+ isOpen && errorCount > 0 && /* @__PURE__ */ jsx20(
11016
11510
  "div",
11017
11511
  {
11018
11512
  style: {
@@ -11032,14 +11526,14 @@ var ToolbarErrorDropdown = ({
11032
11526
  },
11033
11527
  children: groupedErrorElements.map(({ errorType, errors }, groupIndex) => {
11034
11528
  const isGroupCollapsed = collapsedErrorGroups.has(errorType);
11035
- return /* @__PURE__ */ jsxs13(
11529
+ return /* @__PURE__ */ jsxs14(
11036
11530
  "div",
11037
11531
  {
11038
11532
  style: {
11039
11533
  borderBottom: groupIndex < groupedErrorElements.length - 1 ? "1px solid #444" : "none"
11040
11534
  },
11041
11535
  children: [
11042
- /* @__PURE__ */ jsxs13(
11536
+ /* @__PURE__ */ jsxs14(
11043
11537
  "div",
11044
11538
  {
11045
11539
  style: {
@@ -11076,7 +11570,7 @@ var ToolbarErrorDropdown = ({
11076
11570
  toggleErrorGroup(errorType);
11077
11571
  },
11078
11572
  children: [
11079
- /* @__PURE__ */ jsxs13(
11573
+ /* @__PURE__ */ jsxs14(
11080
11574
  "div",
11081
11575
  {
11082
11576
  style: {
@@ -11086,7 +11580,7 @@ var ToolbarErrorDropdown = ({
11086
11580
  color: "#ff6b6b"
11087
11581
  },
11088
11582
  children: [
11089
- /* @__PURE__ */ jsx19(
11583
+ /* @__PURE__ */ jsx20(
11090
11584
  "div",
11091
11585
  {
11092
11586
  style: {
@@ -11099,7 +11593,7 @@ var ToolbarErrorDropdown = ({
11099
11593
  children: "\u203A"
11100
11594
  }
11101
11595
  ),
11102
- /* @__PURE__ */ jsx19(
11596
+ /* @__PURE__ */ jsx20(
11103
11597
  "div",
11104
11598
  {
11105
11599
  style: {
@@ -11112,7 +11606,7 @@ var ToolbarErrorDropdown = ({
11112
11606
  ]
11113
11607
  }
11114
11608
  ),
11115
- /* @__PURE__ */ jsx19(
11609
+ /* @__PURE__ */ jsx20(
11116
11610
  "div",
11117
11611
  {
11118
11612
  style: {
@@ -11130,14 +11624,14 @@ var ToolbarErrorDropdown = ({
11130
11624
  !isGroupCollapsed && errors.map(({ error, index, errorId }) => {
11131
11625
  const isExpanded = expandedErrorIds.has(errorId);
11132
11626
  const errorMessage = error.message ?? "No error message";
11133
- return /* @__PURE__ */ jsxs13(
11627
+ return /* @__PURE__ */ jsxs14(
11134
11628
  "div",
11135
11629
  {
11136
11630
  style: {
11137
11631
  borderTop: "1px solid #3a3a3a"
11138
11632
  },
11139
11633
  children: [
11140
- /* @__PURE__ */ jsxs13(
11634
+ /* @__PURE__ */ jsxs14(
11141
11635
  "div",
11142
11636
  {
11143
11637
  style: {
@@ -11176,7 +11670,7 @@ var ToolbarErrorDropdown = ({
11176
11670
  handleErrorSelect(errorId);
11177
11671
  },
11178
11672
  children: [
11179
- /* @__PURE__ */ jsx19(
11673
+ /* @__PURE__ */ jsx20(
11180
11674
  "div",
11181
11675
  {
11182
11676
  style: {
@@ -11192,7 +11686,7 @@ var ToolbarErrorDropdown = ({
11192
11686
  children: errorMessage
11193
11687
  }
11194
11688
  ),
11195
- /* @__PURE__ */ jsx19(
11689
+ /* @__PURE__ */ jsx20(
11196
11690
  "button",
11197
11691
  {
11198
11692
  type: "button",
@@ -11224,7 +11718,7 @@ var ToolbarErrorDropdown = ({
11224
11718
  ]
11225
11719
  }
11226
11720
  ),
11227
- isExpanded && /* @__PURE__ */ jsxs13(
11721
+ isExpanded && /* @__PURE__ */ jsxs14(
11228
11722
  "div",
11229
11723
  {
11230
11724
  "data-error-id": index,
@@ -11236,7 +11730,7 @@ var ToolbarErrorDropdown = ({
11236
11730
  position: "relative"
11237
11731
  },
11238
11732
  children: [
11239
- /* @__PURE__ */ jsx19(
11733
+ /* @__PURE__ */ jsx20(
11240
11734
  "div",
11241
11735
  {
11242
11736
  style: {
@@ -11254,7 +11748,7 @@ var ToolbarErrorDropdown = ({
11254
11748
  children: errorMessage
11255
11749
  }
11256
11750
  ),
11257
- /* @__PURE__ */ jsx19(
11751
+ /* @__PURE__ */ jsx20(
11258
11752
  CopyErrorButton,
11259
11753
  {
11260
11754
  errorId,
@@ -11286,13 +11780,13 @@ var ToolbarErrorDropdown = ({
11286
11780
  };
11287
11781
 
11288
11782
  // src/components/ToolbarOverlay.tsx
11289
- import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
11783
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
11290
11784
  var LayerButton = ({ name, selected, onClick }) => {
11291
11785
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
11292
- return /* @__PURE__ */ jsxs14(
11786
+ return /* @__PURE__ */ jsxs15(
11293
11787
  "div",
11294
11788
  {
11295
- className: css2`
11789
+ className: css3`
11296
11790
  margin-top: 2px;
11297
11791
  padding: 4px;
11298
11792
  padding-left: 8px;
@@ -11306,8 +11800,8 @@ var LayerButton = ({ name, selected, onClick }) => {
11306
11800
  ...touchHandlers,
11307
11801
  style: touchStyle,
11308
11802
  children: [
11309
- /* @__PURE__ */ jsx20("span", { style: { marginRight: 2, opacity: selected ? 1 : 0 }, children: "\u2022" }),
11310
- /* @__PURE__ */ jsx20(
11803
+ /* @__PURE__ */ jsx21("span", { style: { marginRight: 2, opacity: selected ? 1 : 0 }, children: "\u2022" }),
11804
+ /* @__PURE__ */ jsx21(
11311
11805
  "span",
11312
11806
  {
11313
11807
  style: {
@@ -11328,10 +11822,10 @@ var CheckboxMenuItem = ({
11328
11822
  onClick
11329
11823
  }) => {
11330
11824
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
11331
- return /* @__PURE__ */ jsxs14(
11825
+ return /* @__PURE__ */ jsxs15(
11332
11826
  "div",
11333
11827
  {
11334
- className: css2`
11828
+ className: css3`
11335
11829
  margin-top: 2px;
11336
11830
  padding: 4px;
11337
11831
  padding-left: 8px;
@@ -11348,19 +11842,19 @@ var CheckboxMenuItem = ({
11348
11842
  ...touchHandlers,
11349
11843
  style: touchStyle,
11350
11844
  children: [
11351
- /* @__PURE__ */ jsx20("input", { type: "checkbox", checked, onChange: () => {
11845
+ /* @__PURE__ */ jsx21("input", { type: "checkbox", checked, onChange: () => {
11352
11846
  }, readOnly: true }),
11353
- /* @__PURE__ */ jsx20("span", { style: { color: "#eee" }, children: label })
11847
+ /* @__PURE__ */ jsx21("span", { style: { color: "#eee" }, children: label })
11354
11848
  ]
11355
11849
  }
11356
11850
  );
11357
11851
  };
11358
11852
  var RadioMenuItem = ({ label, checked, onClick }) => {
11359
11853
  const { style: touchStyle, ...touchHandlers } = useMobileTouch(onClick);
11360
- return /* @__PURE__ */ jsxs14(
11854
+ return /* @__PURE__ */ jsxs15(
11361
11855
  "div",
11362
11856
  {
11363
- className: css2`
11857
+ className: css3`
11364
11858
  margin-top: 2px;
11365
11859
  padding: 4px;
11366
11860
  padding-left: 8px;
@@ -11377,9 +11871,9 @@ var RadioMenuItem = ({ label, checked, onClick }) => {
11377
11871
  ...touchHandlers,
11378
11872
  style: touchStyle,
11379
11873
  children: [
11380
- /* @__PURE__ */ jsx20("input", { type: "radio", checked, onChange: () => {
11874
+ /* @__PURE__ */ jsx21("input", { type: "radio", checked, onChange: () => {
11381
11875
  }, readOnly: true }),
11382
- /* @__PURE__ */ jsx20("span", { style: { color: "#eee" }, children: label })
11876
+ /* @__PURE__ */ jsx21("span", { style: { color: "#eee" }, children: label })
11383
11877
  ]
11384
11878
  }
11385
11879
  );
@@ -11446,12 +11940,14 @@ var ToolbarOverlay = ({ children, elements }) => {
11446
11940
  setHoveredErrorId: s.setHoveredErrorId,
11447
11941
  setFocusedErrorId: s.setFocusedErrorId
11448
11942
  }));
11449
- const [isViewMenuOpen, setViewMenuOpen] = useState10(false);
11450
- const [isLayerMenuOpen, setLayerMenuOpen] = useState10(false);
11451
- const [isErrorsOpen, setErrorsOpen] = useState10(false);
11452
- const [measureToolArmed, setMeasureToolArmed] = useState10(false);
11453
- const [boundsToolArmed, setBoundsToolArmed] = useState10(false);
11454
- useEffect15(() => {
11943
+ const [contextMenuPosition, setContextMenuPosition] = useState11(null);
11944
+ const closeContextMenu = useCallback10(() => setContextMenuPosition(null), []);
11945
+ const [isViewMenuOpen, setViewMenuOpen] = useState11(false);
11946
+ const [isLayerMenuOpen, setLayerMenuOpen] = useState11(false);
11947
+ const [isErrorsOpen, setErrorsOpen] = useState11(false);
11948
+ const [measureToolArmed, setMeasureToolArmed] = useState11(false);
11949
+ const [boundsToolArmed, setBoundsToolArmed] = useState11(false);
11950
+ useEffect16(() => {
11455
11951
  const arm = () => setMeasureToolArmed(true);
11456
11952
  const disarm = () => setMeasureToolArmed(false);
11457
11953
  const armBounds = () => setBoundsToolArmed(true);
@@ -11469,8 +11965,8 @@ var ToolbarOverlay = ({ children, elements }) => {
11469
11965
  }, []);
11470
11966
  const availableLayers = getCopperLayerRefsFromElements(elements ?? []);
11471
11967
  const processedLayers = availableLayers;
11472
- const hasRunInitialMouseCheck = useRef12(false);
11473
- const hotkeyBoundaryRef = useRef12(null);
11968
+ const hasRunInitialMouseCheck = useRef13(false);
11969
+ const hotkeyBoundaryRef = useRef13(null);
11474
11970
  const hotKeyCallbacks = {
11475
11971
  "1": availableLayers[0] ? () => selectLayer(availableLayers[0]) : () => {
11476
11972
  },
@@ -11577,17 +12073,29 @@ var ToolbarOverlay = ({ children, elements }) => {
11577
12073
  },
11578
12074
  []
11579
12075
  );
11580
- return /* @__PURE__ */ jsxs14(
12076
+ return /* @__PURE__ */ jsxs15(
11581
12077
  "div",
11582
12078
  {
11583
12079
  ref: hotkeyBoundaryRef,
12080
+ onContextMenu: (event) => {
12081
+ event.preventDefault();
12082
+ event.stopPropagation();
12083
+ setContextMenuPosition({ x: event.clientX, y: event.clientY });
12084
+ },
11584
12085
  style: { position: "relative", zIndex: "999 !important" },
11585
12086
  onMouseEnter: handleMouseEnter,
11586
12087
  onMouseLeave: handleMouseLeave,
11587
12088
  onMouseMove: handleMouseMove,
11588
12089
  children: [
11589
12090
  children,
11590
- /* @__PURE__ */ jsxs14(
12091
+ contextMenuPosition && /* @__PURE__ */ jsx21(
12092
+ VisibilityContextMenu,
12093
+ {
12094
+ position: contextMenuPosition,
12095
+ onClose: closeContextMenu
12096
+ }
12097
+ ),
12098
+ /* @__PURE__ */ jsxs15(
11591
12099
  "div",
11592
12100
  {
11593
12101
  style: {
@@ -11608,7 +12116,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11608
12116
  ]
11609
12117
  }
11610
12118
  ),
11611
- /* @__PURE__ */ jsxs14(
12119
+ /* @__PURE__ */ jsxs15(
11612
12120
  "div",
11613
12121
  {
11614
12122
  "data-toolbar-overlay": true,
@@ -11639,7 +12147,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11639
12147
  fontFamily: "sans-serif"
11640
12148
  },
11641
12149
  children: [
11642
- /* @__PURE__ */ jsxs14(
12150
+ /* @__PURE__ */ jsxs15(
11643
12151
  ToolbarButton,
11644
12152
  {
11645
12153
  isSmallScreen,
@@ -11650,10 +12158,10 @@ var ToolbarOverlay = ({ children, elements }) => {
11650
12158
  }
11651
12159
  },
11652
12160
  children: [
11653
- /* @__PURE__ */ jsxs14("div", { children: [
12161
+ /* @__PURE__ */ jsxs15("div", { children: [
11654
12162
  "layer:",
11655
12163
  " ",
11656
- /* @__PURE__ */ jsx20(
12164
+ /* @__PURE__ */ jsx21(
11657
12165
  "span",
11658
12166
  {
11659
12167
  style: {
@@ -11665,7 +12173,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11665
12173
  }
11666
12174
  )
11667
12175
  ] }),
11668
- isLayerMenuOpen && /* @__PURE__ */ jsx20("div", { style: { marginTop: 4, minWidth: 120 }, children: processedLayers.map((layer) => /* @__PURE__ */ jsx20(
12176
+ isLayerMenuOpen && /* @__PURE__ */ jsx21("div", { style: { marginTop: 4, minWidth: 120 }, children: processedLayers.map((layer) => /* @__PURE__ */ jsx21(
11669
12177
  LayerButton,
11670
12178
  {
11671
12179
  name: layer,
@@ -11679,7 +12187,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11679
12187
  ]
11680
12188
  }
11681
12189
  ),
11682
- /* @__PURE__ */ jsx20(
12190
+ /* @__PURE__ */ jsx21(
11683
12191
  ToolbarErrorDropdown,
11684
12192
  {
11685
12193
  elements,
@@ -11691,43 +12199,43 @@ var ToolbarOverlay = ({ children, elements }) => {
11691
12199
  setFocusedErrorId
11692
12200
  }
11693
12201
  ),
11694
- /* @__PURE__ */ jsx20(
12202
+ /* @__PURE__ */ jsx21(
11695
12203
  ToolbarButton,
11696
12204
  {
11697
12205
  isSmallScreen,
11698
12206
  style: {},
11699
12207
  onClick: handleRatsNestToggle,
11700
- children: /* @__PURE__ */ jsxs14("div", { children: [
12208
+ children: /* @__PURE__ */ jsxs15("div", { children: [
11701
12209
  viewSettings.is_showing_rats_nest ? "\u2716 " : "",
11702
12210
  "Rats Nest"
11703
12211
  ] })
11704
12212
  }
11705
12213
  ),
11706
- /* @__PURE__ */ jsx20(
12214
+ /* @__PURE__ */ jsx21(
11707
12215
  ToolbarButton,
11708
12216
  {
11709
12217
  isSmallScreen,
11710
12218
  style: measureToolArmed ? { backgroundColor: "#444" } : {},
11711
12219
  onClick: handleMeasureToolClick,
11712
- children: /* @__PURE__ */ jsx20("div", { children: "\u{1F4CF}" })
12220
+ children: /* @__PURE__ */ jsx21("div", { children: "\u{1F4CF}" })
11713
12221
  }
11714
12222
  ),
11715
- /* @__PURE__ */ jsx20(
12223
+ /* @__PURE__ */ jsx21(
11716
12224
  ToolbarButton,
11717
12225
  {
11718
12226
  isSmallScreen,
11719
12227
  style: boundsToolArmed ? { backgroundColor: "#444" } : {},
11720
12228
  onClick: handleBoundsToolClick,
11721
- children: /* @__PURE__ */ jsx20("div", { children: "Bounds" })
12229
+ children: /* @__PURE__ */ jsx21("div", { children: "Bounds" })
11722
12230
  }
11723
12231
  ),
11724
- /* @__PURE__ */ jsx20(
12232
+ /* @__PURE__ */ jsx21(
11725
12233
  ToolbarButton,
11726
12234
  {
11727
12235
  isSmallScreen,
11728
12236
  onClick: handleViewMenuToggle,
11729
- children: /* @__PURE__ */ jsxs14("div", { children: [
11730
- /* @__PURE__ */ jsxs14(
12237
+ children: /* @__PURE__ */ jsxs15("div", { children: [
12238
+ /* @__PURE__ */ jsxs15(
11731
12239
  "div",
11732
12240
  {
11733
12241
  style: {
@@ -11737,7 +12245,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11737
12245
  },
11738
12246
  children: [
11739
12247
  "View",
11740
- /* @__PURE__ */ jsx20(
12248
+ /* @__PURE__ */ jsx21(
11741
12249
  "span",
11742
12250
  {
11743
12251
  style: {
@@ -11752,8 +12260,8 @@ var ToolbarOverlay = ({ children, elements }) => {
11752
12260
  ]
11753
12261
  }
11754
12262
  ),
11755
- isViewMenuOpen && /* @__PURE__ */ jsxs14("div", { style: { marginTop: 4, minWidth: 120 }, children: [
11756
- /* @__PURE__ */ jsx20(
12263
+ isViewMenuOpen && /* @__PURE__ */ jsxs15("div", { style: { marginTop: 4, minWidth: 120 }, children: [
12264
+ /* @__PURE__ */ jsx21(
11757
12265
  CheckboxMenuItem,
11758
12266
  {
11759
12267
  label: "Show All Trace Lengths",
@@ -11765,7 +12273,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11765
12273
  }
11766
12274
  }
11767
12275
  ),
11768
- /* @__PURE__ */ jsx20(
12276
+ /* @__PURE__ */ jsx21(
11769
12277
  CheckboxMenuItem,
11770
12278
  {
11771
12279
  label: "Show Autorouting Animation",
@@ -11777,7 +12285,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11777
12285
  }
11778
12286
  }
11779
12287
  ),
11780
- /* @__PURE__ */ jsx20(
12288
+ /* @__PURE__ */ jsx21(
11781
12289
  CheckboxMenuItem,
11782
12290
  {
11783
12291
  label: "Show DRC Errors",
@@ -11787,7 +12295,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11787
12295
  }
11788
12296
  }
11789
12297
  ),
11790
- /* @__PURE__ */ jsx20(
12298
+ /* @__PURE__ */ jsx21(
11791
12299
  CheckboxMenuItem,
11792
12300
  {
11793
12301
  label: "Show DRC Warnings",
@@ -11799,7 +12307,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11799
12307
  }
11800
12308
  }
11801
12309
  ),
11802
- /* @__PURE__ */ jsx20(
12310
+ /* @__PURE__ */ jsx21(
11803
12311
  CheckboxMenuItem,
11804
12312
  {
11805
12313
  label: "Show Copper Pours",
@@ -11811,7 +12319,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11811
12319
  }
11812
12320
  }
11813
12321
  ),
11814
- /* @__PURE__ */ jsx20(
12322
+ /* @__PURE__ */ jsx21(
11815
12323
  CheckboxMenuItem,
11816
12324
  {
11817
12325
  label: "Show Courtyards",
@@ -11821,7 +12329,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11821
12329
  }
11822
12330
  }
11823
12331
  ),
11824
- /* @__PURE__ */ jsx20(
12332
+ /* @__PURE__ */ jsx21(
11825
12333
  CheckboxMenuItem,
11826
12334
  {
11827
12335
  label: "Show Solder Mask",
@@ -11831,7 +12339,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11831
12339
  }
11832
12340
  }
11833
12341
  ),
11834
- /* @__PURE__ */ jsx20(
12342
+ /* @__PURE__ */ jsx21(
11835
12343
  CheckboxMenuItem,
11836
12344
  {
11837
12345
  label: "Show Silkscreen",
@@ -11841,7 +12349,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11841
12349
  }
11842
12350
  }
11843
12351
  ),
11844
- /* @__PURE__ */ jsx20(
12352
+ /* @__PURE__ */ jsx21(
11845
12353
  CheckboxMenuItem,
11846
12354
  {
11847
12355
  label: "Show Fabrication Notes",
@@ -11853,7 +12361,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11853
12361
  }
11854
12362
  }
11855
12363
  ),
11856
- /* @__PURE__ */ jsx20(
12364
+ /* @__PURE__ */ jsx21(
11857
12365
  CheckboxMenuItem,
11858
12366
  {
11859
12367
  label: "Show PCB Notes",
@@ -11863,7 +12371,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11863
12371
  }
11864
12372
  }
11865
12373
  ),
11866
- /* @__PURE__ */ jsx20(
12374
+ /* @__PURE__ */ jsx21(
11867
12375
  CheckboxMenuItem,
11868
12376
  {
11869
12377
  label: "Show Group Anchor Offsets",
@@ -11875,7 +12383,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11875
12383
  }
11876
12384
  }
11877
12385
  ),
11878
- /* @__PURE__ */ jsx20(
12386
+ /* @__PURE__ */ jsx21(
11879
12387
  CheckboxMenuItem,
11880
12388
  {
11881
12389
  label: "Show PCB Groups",
@@ -11885,8 +12393,8 @@ var ToolbarOverlay = ({ children, elements }) => {
11885
12393
  }
11886
12394
  }
11887
12395
  ),
11888
- viewSettings.is_showing_pcb_groups && /* @__PURE__ */ jsxs14("div", { style: { marginLeft: 16 }, children: [
11889
- /* @__PURE__ */ jsx20(
12396
+ viewSettings.is_showing_pcb_groups && /* @__PURE__ */ jsxs15("div", { style: { marginLeft: 16 }, children: [
12397
+ /* @__PURE__ */ jsx21(
11890
12398
  RadioMenuItem,
11891
12399
  {
11892
12400
  label: "Show All Groups",
@@ -11896,7 +12404,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11896
12404
  }
11897
12405
  }
11898
12406
  ),
11899
- /* @__PURE__ */ jsx20(
12407
+ /* @__PURE__ */ jsx21(
11900
12408
  RadioMenuItem,
11901
12409
  {
11902
12410
  label: "Show Named Groups",
@@ -11920,7 +12428,7 @@ var ToolbarOverlay = ({ children, elements }) => {
11920
12428
  };
11921
12429
 
11922
12430
  // src/components/WarningGraphicsOverlay.tsx
11923
- import { useEffect as useEffect16, useRef as useRef13 } from "react";
12431
+ import { useEffect as useEffect17, useRef as useRef14 } from "react";
11924
12432
  import { applyToPoint as applyToPoint18, identity as identity8 } from "transformation-matrix";
11925
12433
 
11926
12434
  // src/lib/util/get-pcb-warning-highlight.ts
@@ -11933,18 +12441,18 @@ var getPcbWarningHighlightLabel = (warning) => {
11933
12441
  };
11934
12442
 
11935
12443
  // src/components/WarningGraphicsOverlay.tsx
11936
- import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
12444
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
11937
12445
  var WarningGraphicsOverlay = ({
11938
12446
  children,
11939
12447
  transform = identity8(),
11940
12448
  elements = []
11941
12449
  }) => {
11942
12450
  const [containerRef, { width, height }] = useMeasure_default();
11943
- const canvasRef = useRef13(null);
12451
+ const canvasRef = useRef14(null);
11944
12452
  const isShowingDrcWarnings = useGlobalStore(
11945
12453
  (state) => state.is_showing_drc_warnings
11946
12454
  );
11947
- useEffect16(() => {
12455
+ useEffect17(() => {
11948
12456
  const canvas = canvasRef.current;
11949
12457
  if (!canvas || !width || !height) return;
11950
12458
  canvas.width = width;
@@ -11995,7 +12503,7 @@ var WarningGraphicsOverlay = ({
11995
12503
  });
11996
12504
  }, [elements, transform, width, height, isShowingDrcWarnings]);
11997
12505
  if (!isShowingDrcWarnings) {
11998
- return /* @__PURE__ */ jsx21(
12506
+ return /* @__PURE__ */ jsx22(
11999
12507
  "div",
12000
12508
  {
12001
12509
  ref: containerRef,
@@ -12004,14 +12512,14 @@ var WarningGraphicsOverlay = ({
12004
12512
  }
12005
12513
  );
12006
12514
  }
12007
- return /* @__PURE__ */ jsxs15(
12515
+ return /* @__PURE__ */ jsxs16(
12008
12516
  "div",
12009
12517
  {
12010
12518
  ref: containerRef,
12011
12519
  style: { position: "relative", width: "100%", height: "100%" },
12012
12520
  children: [
12013
12521
  children,
12014
- /* @__PURE__ */ jsx21(
12522
+ /* @__PURE__ */ jsx22(
12015
12523
  "canvas",
12016
12524
  {
12017
12525
  ref: canvasRef,
@@ -12030,7 +12538,7 @@ var WarningGraphicsOverlay = ({
12030
12538
  };
12031
12539
 
12032
12540
  // src/components/CanvasElementsRenderer.tsx
12033
- import { jsx as jsx22 } from "react/jsx-runtime";
12541
+ import { jsx as jsx23 } from "react/jsx-runtime";
12034
12542
  var CanvasElementsRenderer = (props) => {
12035
12543
  const { transform, elements } = props;
12036
12544
  const {
@@ -12058,13 +12566,13 @@ var CanvasElementsRenderer = (props) => {
12058
12566
  );
12059
12567
  return [primitivesWithoutInteractionMetadata2, connectivityMap2];
12060
12568
  }, [elementsToRender, props.elements]);
12061
- const [hoverState, setHoverState] = useState11({
12569
+ const [hoverState, setHoverState] = useState12({
12062
12570
  drawingObjectIdsWithMouseOver: /* @__PURE__ */ new Set(),
12063
12571
  primitiveIdsInMousedOverNet: []
12064
12572
  });
12065
- const [hoveredComponentIds, setHoveredComponentIds] = useState11([]);
12066
- const currentTransformRef = useRef14(transform ?? null);
12067
- const zoomAnimationFrameRef = useRef14(null);
12573
+ const [hoveredComponentIds, setHoveredComponentIds] = useState12([]);
12574
+ const currentTransformRef = useRef15(transform ?? null);
12575
+ const zoomAnimationFrameRef = useRef15(null);
12068
12576
  const elementIndexes = useMemo8(
12069
12577
  () => buildErrorPreviewElementIndexes(elements),
12070
12578
  [elements]
@@ -12080,17 +12588,17 @@ var CanvasElementsRenderer = (props) => {
12080
12588
  if (!activeError) return [];
12081
12589
  return getRelatedIdsForError(activeError);
12082
12590
  }, [activeErrorId, elements]);
12083
- useEffect17(() => {
12591
+ useEffect18(() => {
12084
12592
  if (transform) {
12085
12593
  currentTransformRef.current = transform;
12086
12594
  }
12087
12595
  }, [transform]);
12088
- useEffect17(() => {
12596
+ useEffect18(() => {
12089
12597
  return () => {
12090
12598
  cancelTransformAnimation(zoomAnimationFrameRef.current);
12091
12599
  };
12092
12600
  }, []);
12093
- useEffect17(() => {
12601
+ useEffect18(() => {
12094
12602
  if (!props.width || !props.height || !props.setTransform || !focusedErrorId)
12095
12603
  return;
12096
12604
  const focusedError = findErrorElementById(elements, focusedErrorId);
@@ -12172,7 +12680,7 @@ var CanvasElementsRenderer = (props) => {
12172
12680
  },
12173
12681
  [connectivityMap]
12174
12682
  );
12175
- return /* @__PURE__ */ jsx22(
12683
+ return /* @__PURE__ */ jsx23(
12176
12684
  MouseElementTracker,
12177
12685
  {
12178
12686
  elements: elementsToRender,
@@ -12180,7 +12688,7 @@ var CanvasElementsRenderer = (props) => {
12180
12688
  primitives: primitivesWithoutInteractionMetadata,
12181
12689
  selectedLayer,
12182
12690
  onMouseHoverOverPrimitives: onMouseOverPrimitives,
12183
- children: /* @__PURE__ */ jsx22(
12691
+ children: /* @__PURE__ */ jsx23(
12184
12692
  EditPlacementOverlay,
12185
12693
  {
12186
12694
  disabled: !props.allowEditing,
@@ -12189,7 +12697,7 @@ var CanvasElementsRenderer = (props) => {
12189
12697
  cancelPanDrag: props.cancelPanDrag,
12190
12698
  onCreateEditEvent: props.onCreateEditEvent,
12191
12699
  onModifyEditEvent: props.onModifyEditEvent,
12192
- children: /* @__PURE__ */ jsx22(
12700
+ children: /* @__PURE__ */ jsx23(
12193
12701
  DimensionOverlay,
12194
12702
  {
12195
12703
  transform,
@@ -12197,23 +12705,23 @@ var CanvasElementsRenderer = (props) => {
12197
12705
  primitives: primitivesWithoutInteractionMetadata,
12198
12706
  onBoundsSelected: props.onBoundsSelected,
12199
12707
  cancelPanDrag: props.cancelPanDrag,
12200
- children: /* @__PURE__ */ jsx22(ToolbarOverlay, { elements, children: /* @__PURE__ */ jsx22(ErrorOverlay, { transform, elements, children: /* @__PURE__ */ jsx22(RatsNestOverlay, { transform, soup: elements, children: /* @__PURE__ */ jsx22(
12708
+ children: /* @__PURE__ */ jsx23(ToolbarOverlay, { elements, children: /* @__PURE__ */ jsx23(ErrorOverlay, { transform, elements, children: /* @__PURE__ */ jsx23(RatsNestOverlay, { transform, soup: elements, children: /* @__PURE__ */ jsx23(
12201
12709
  PcbGroupOverlay,
12202
12710
  {
12203
12711
  transform,
12204
12712
  elements,
12205
12713
  hoveredComponentIds,
12206
- children: /* @__PURE__ */ jsx22(
12714
+ children: /* @__PURE__ */ jsx23(
12207
12715
  DebugGraphicsOverlay,
12208
12716
  {
12209
12717
  transform,
12210
12718
  debugGraphics: props.debugGraphics,
12211
- children: /* @__PURE__ */ jsx22(
12719
+ children: /* @__PURE__ */ jsx23(
12212
12720
  WarningGraphicsOverlay,
12213
12721
  {
12214
12722
  transform,
12215
12723
  elements,
12216
- children: /* @__PURE__ */ jsx22(
12724
+ children: /* @__PURE__ */ jsx23(
12217
12725
  CanvasPrimitiveRenderer,
12218
12726
  {
12219
12727
  transform,
@@ -12293,7 +12801,7 @@ var calculateBoardSizeKey = (circuitJson) => {
12293
12801
  };
12294
12802
 
12295
12803
  // src/PCBViewer.tsx
12296
- import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
12804
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
12297
12805
  var defaultTransform = compose8(translate12(400, 300), scale6(40, -40));
12298
12806
  var PCBViewer = ({
12299
12807
  circuitJson,
@@ -12308,11 +12816,11 @@ var PCBViewer = ({
12308
12816
  clickToInteractEnabled = false,
12309
12817
  disablePcbGroups = false
12310
12818
  }) => {
12311
- const [isInteractionEnabled, setIsInteractionEnabled] = useState12(
12819
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState13(
12312
12820
  !clickToInteractEnabled
12313
12821
  );
12314
12822
  const [ref, refDimensions] = useMeasure_default();
12315
- const [transform, setTransformInternal] = useState12(defaultTransform);
12823
+ const [transform, setTransformInternal] = useState13(defaultTransform);
12316
12824
  const shouldAllowCanvasInteraction = useCallback12(
12317
12825
  (event) => {
12318
12826
  const target = event.target;
@@ -12331,10 +12839,10 @@ var PCBViewer = ({
12331
12839
  enabled: isInteractionEnabled,
12332
12840
  shouldDrag: shouldAllowCanvasInteraction
12333
12841
  });
12334
- let [editEvents, setEditEvents] = useState12([]);
12842
+ let [editEvents, setEditEvents] = useState13([]);
12335
12843
  editEvents = editEventsProp ?? editEvents;
12336
- const initialRenderCompleted = useRef15(false);
12337
- const touchStartRef = useRef15(null);
12844
+ const initialRenderCompleted = useRef16(false);
12845
+ const touchStartRef = useRef16(null);
12338
12846
  const circuitJsonKey = useMemo9(
12339
12847
  () => calculateCircuitJsonKey(circuitJson),
12340
12848
  [circuitJson]
@@ -12360,7 +12868,7 @@ var PCBViewer = ({
12360
12868
  setTransform(targetTransform);
12361
12869
  return;
12362
12870
  };
12363
- useEffect18(() => {
12871
+ useEffect19(() => {
12364
12872
  if (!refDimensions?.width) return;
12365
12873
  if (!circuitJson) return;
12366
12874
  if (circuitJson.length === 0) return;
@@ -12369,7 +12877,7 @@ var PCBViewer = ({
12369
12877
  initialRenderCompleted.current = true;
12370
12878
  }
12371
12879
  }, [circuitJson, refDimensions]);
12372
- useEffect18(() => {
12880
+ useEffect19(() => {
12373
12881
  if (initialRenderCompleted.current === true) {
12374
12882
  resetTransform();
12375
12883
  }
@@ -12403,20 +12911,20 @@ var PCBViewer = ({
12403
12911
  }),
12404
12912
  [initialState, disablePcbGroups]
12405
12913
  );
12406
- return /* @__PURE__ */ jsxs16(
12914
+ return /* @__PURE__ */ jsxs17(
12407
12915
  "div",
12408
12916
  {
12409
12917
  ref: transformRef,
12410
12918
  style: { position: "relative" },
12411
12919
  onContextMenu: (event) => event.preventDefault(),
12412
12920
  children: [
12413
- /* @__PURE__ */ jsx23("div", { ref, children: /* @__PURE__ */ jsxs16(
12921
+ /* @__PURE__ */ jsx24("div", { ref, children: /* @__PURE__ */ jsxs17(
12414
12922
  ContextProviders,
12415
12923
  {
12416
12924
  initialState: mergedInitialState,
12417
12925
  disablePcbGroups,
12418
12926
  children: [
12419
- /* @__PURE__ */ jsx23(
12927
+ /* @__PURE__ */ jsx24(
12420
12928
  CanvasElementsRenderer,
12421
12929
  {
12422
12930
  transform,
@@ -12443,11 +12951,11 @@ var PCBViewer = ({
12443
12951
  },
12444
12952
  refDimensions.width
12445
12953
  ),
12446
- /* @__PURE__ */ jsx23(ToastContainer, {})
12954
+ /* @__PURE__ */ jsx24(ToastContainer, {})
12447
12955
  ]
12448
12956
  }
12449
12957
  ) }),
12450
- clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx23(
12958
+ clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx24(
12451
12959
  "div",
12452
12960
  {
12453
12961
  onClick: () => {
@@ -12484,7 +12992,7 @@ var PCBViewer = ({
12484
12992
  justifyContent: "center",
12485
12993
  touchAction: "pan-x pan-y pinch-zoom"
12486
12994
  },
12487
- children: /* @__PURE__ */ jsx23(
12995
+ children: /* @__PURE__ */ jsx24(
12488
12996
  "div",
12489
12997
  {
12490
12998
  style: {
@@ -12517,5 +13025,16 @@ svgson/dist/svgson.umd.js:
12517
13025
  * @author Feross Aboukhadijeh <https://feross.org>
12518
13026
  * @license MIT
12519
13027
  *)
13028
+
13029
+ react-dom/cjs/react-dom.development.js:
13030
+ (**
13031
+ * @license React
13032
+ * react-dom.development.js
13033
+ *
13034
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
13035
+ *
13036
+ * This source code is licensed under the MIT license found in the
13037
+ * LICENSE file in the root directory of this source tree.
13038
+ *)
12520
13039
  */
12521
13040
  //# sourceMappingURL=index.js.map