@tscircuit/3d-viewer 0.0.620 → 0.0.622

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.
Files changed (2) hide show
  1. package/dist/index.js +846 -504
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4014,7 +4014,7 @@ var require_measureBoundingBox = __commonJS({
4014
4014
  "node_modules/@jscad/modeling/src/geometries/poly3/measureBoundingBox.js"(exports, module) {
4015
4015
  "use strict";
4016
4016
  var vec3 = require_vec3();
4017
- var measureBoundingBox = (polygon2) => {
4017
+ var measureBoundingBox2 = (polygon2) => {
4018
4018
  const vertices = polygon2.vertices;
4019
4019
  const numvertices = vertices.length;
4020
4020
  const min5 = numvertices === 0 ? vec3.create() : vec3.clone(vertices[0]);
@@ -4025,7 +4025,7 @@ var require_measureBoundingBox = __commonJS({
4025
4025
  }
4026
4026
  return [min5, max5];
4027
4027
  };
4028
- module.exports = measureBoundingBox;
4028
+ module.exports = measureBoundingBox2;
4029
4029
  }
4030
4030
  });
4031
4031
 
@@ -6819,7 +6819,7 @@ var require_measureBoundingBox2 = __commonJS({
6819
6819
  cache.set(geometry, boundingBox);
6820
6820
  return boundingBox;
6821
6821
  };
6822
- var measureBoundingBox = (...geometries) => {
6822
+ var measureBoundingBox2 = (...geometries) => {
6823
6823
  geometries = flatten(geometries);
6824
6824
  if (geometries.length === 0) throw new Error("wrong number of arguments");
6825
6825
  const results = geometries.map((geometry) => {
@@ -6830,7 +6830,7 @@ var require_measureBoundingBox2 = __commonJS({
6830
6830
  });
6831
6831
  return results.length === 1 ? results[0] : results;
6832
6832
  };
6833
- module.exports = measureBoundingBox;
6833
+ module.exports = measureBoundingBox2;
6834
6834
  }
6835
6835
  });
6836
6836
 
@@ -6841,11 +6841,11 @@ var require_measureAggregateBoundingBox = __commonJS({
6841
6841
  var flatten = require_flatten();
6842
6842
  var vec3min = require_min();
6843
6843
  var vec3max = require_max();
6844
- var measureBoundingBox = require_measureBoundingBox2();
6844
+ var measureBoundingBox2 = require_measureBoundingBox2();
6845
6845
  var measureAggregateBoundingBox = (...geometries) => {
6846
6846
  geometries = flatten(geometries);
6847
6847
  if (geometries.length === 0) throw new Error("measureAggregateBoundingBox: no geometries supplied");
6848
- const bounds = measureBoundingBox(geometries);
6848
+ const bounds = measureBoundingBox2(geometries);
6849
6849
  if (geometries.length === 1) {
6850
6850
  return bounds;
6851
6851
  }
@@ -7057,11 +7057,11 @@ var require_measureCenter = __commonJS({
7057
7057
  "node_modules/@jscad/modeling/src/measurements/measureCenter.js"(exports, module) {
7058
7058
  "use strict";
7059
7059
  var flatten = require_flatten();
7060
- var measureBoundingBox = require_measureBoundingBox2();
7060
+ var measureBoundingBox2 = require_measureBoundingBox2();
7061
7061
  var measureCenter = (...geometries) => {
7062
7062
  geometries = flatten(geometries);
7063
7063
  const results = geometries.map((geometry) => {
7064
- const bounds = measureBoundingBox(geometry);
7064
+ const bounds = measureBoundingBox2(geometry);
7065
7065
  return [
7066
7066
  bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2,
7067
7067
  bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2,
@@ -7150,11 +7150,11 @@ var require_measureDimensions = __commonJS({
7150
7150
  "node_modules/@jscad/modeling/src/measurements/measureDimensions.js"(exports, module) {
7151
7151
  "use strict";
7152
7152
  var flatten = require_flatten();
7153
- var measureBoundingBox = require_measureBoundingBox2();
7153
+ var measureBoundingBox2 = require_measureBoundingBox2();
7154
7154
  var measureDimensions = (...geometries) => {
7155
7155
  geometries = flatten(geometries);
7156
7156
  const results = geometries.map((geometry) => {
7157
- const boundingBox = measureBoundingBox(geometry);
7157
+ const boundingBox = measureBoundingBox2(geometry);
7158
7158
  return [
7159
7159
  boundingBox[1][0] - boundingBox[0][0],
7160
7160
  boundingBox[1][1] - boundingBox[0][1],
@@ -7174,10 +7174,10 @@ var require_measureEpsilon = __commonJS({
7174
7174
  var flatten = require_flatten();
7175
7175
  var { geom2, geom3, path2 } = require_geometries();
7176
7176
  var calculateEpsilonFromBounds = require_calculateEpsilonFromBounds();
7177
- var measureBoundingBox = require_measureBoundingBox2();
7178
- var measureEpsilonOfPath2 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox(geometry), 2);
7179
- var measureEpsilonOfGeom2 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox(geometry), 2);
7180
- var measureEpsilonOfGeom3 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox(geometry), 3);
7177
+ var measureBoundingBox2 = require_measureBoundingBox2();
7178
+ var measureEpsilonOfPath2 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox2(geometry), 2);
7179
+ var measureEpsilonOfGeom2 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox2(geometry), 2);
7180
+ var measureEpsilonOfGeom3 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox2(geometry), 3);
7181
7181
  var measureEpsilon = (...geometries) => {
7182
7182
  geometries = flatten(geometries);
7183
7183
  if (geometries.length === 0) throw new Error("wrong number of arguments");
@@ -10672,15 +10672,15 @@ var require_mayOverlap = __commonJS({
10672
10672
  "node_modules/@jscad/modeling/src/operations/booleans/mayOverlap.js"(exports, module) {
10673
10673
  "use strict";
10674
10674
  var { EPS: EPS3 } = require_constants();
10675
- var measureBoundingBox = require_measureBoundingBox2();
10675
+ var measureBoundingBox2 = require_measureBoundingBox2();
10676
10676
  var mayOverlap = (geometry1, geometry2) => {
10677
10677
  if (geometry1.polygons.length === 0 || geometry2.polygons.length === 0) {
10678
10678
  return false;
10679
10679
  }
10680
- const bounds1 = measureBoundingBox(geometry1);
10680
+ const bounds1 = measureBoundingBox2(geometry1);
10681
10681
  const min1 = bounds1[0];
10682
10682
  const max1 = bounds1[1];
10683
- const bounds2 = measureBoundingBox(geometry2);
10683
+ const bounds2 = measureBoundingBox2(geometry2);
10684
10684
  const min22 = bounds2[0];
10685
10685
  const max22 = bounds2[1];
10686
10686
  if (min22[0] - max1[0] > EPS3) return false;
@@ -13564,7 +13564,7 @@ var require_center = __commonJS({
13564
13564
  var geom2 = require_geom2();
13565
13565
  var geom3 = require_geom3();
13566
13566
  var path2 = require_path2();
13567
- var measureBoundingBox = require_measureBoundingBox2();
13567
+ var measureBoundingBox2 = require_measureBoundingBox2();
13568
13568
  var { translate: translate10 } = require_translate2();
13569
13569
  var centerGeometry = (options, object) => {
13570
13570
  const defaults = {
@@ -13572,7 +13572,7 @@ var require_center = __commonJS({
13572
13572
  relativeTo: [0, 0, 0]
13573
13573
  };
13574
13574
  const { axes: axes2, relativeTo } = Object.assign({}, defaults, options);
13575
- const bounds = measureBoundingBox(object);
13575
+ const bounds = measureBoundingBox2(object);
13576
13576
  const offset4 = [0, 0, 0];
13577
13577
  if (axes2[0]) offset4[0] = relativeTo[0] - (bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2);
13578
13578
  if (axes2[1]) offset4[1] = relativeTo[1] - (bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2);
@@ -18979,8 +18979,8 @@ var useHiddenCadComponents = (circuitKey) => {
18979
18979
  };
18980
18980
 
18981
18981
  // src/CadViewer.tsx
18982
- import { useCallback as useCallback24, useContext as useContext11, useEffect as useEffect51, useRef as useRef29, useState as useState42 } from "react";
18983
- import * as THREE55 from "three";
18982
+ import { useCallback as useCallback25, useContext as useContext11, useEffect as useEffect50, useRef as useRef29, useState as useState42 } from "react";
18983
+ import * as THREE56 from "three";
18984
18984
 
18985
18985
  // src/hooks/use-convert-children-to-soup.ts
18986
18986
  import { Circuit } from "@tscircuit/core";
@@ -20946,12 +20946,12 @@ var AnyCadComponent = ({
20946
20946
 
20947
20947
  // src/CadViewerContainer.tsx
20948
20948
  import { forwardRef as forwardRef2, useEffect as useEffect21, useMemo as useMemo17, useState as useState13 } from "react";
20949
- import * as THREE25 from "three";
20949
+ import * as THREE26 from "three";
20950
20950
 
20951
20951
  // package.json
20952
20952
  var package_default = {
20953
20953
  name: "@tscircuit/3d-viewer",
20954
- version: "0.0.619",
20954
+ version: "0.0.621",
20955
20955
  repository: {
20956
20956
  type: "git",
20957
20957
  url: "https://github.com/tscircuit/3d-viewer"
@@ -21879,8 +21879,36 @@ var Lights = ({
21879
21879
 
21880
21880
  // src/react-three/OrbitControls.tsx
21881
21881
  import { useEffect as useEffect18, useMemo as useMemo15 } from "react";
21882
- import * as THREE21 from "three";
21882
+ import * as THREE22 from "three";
21883
21883
  import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
21884
+
21885
+ // src/react-three/infinite-dolly.ts
21886
+ import * as THREE21 from "three";
21887
+ var MINIMUM_DOLLY_DISTANCE_RATIO = 0.05;
21888
+ var getMinimumDollyDistance = ({
21889
+ camera,
21890
+ initialOrbitDistance
21891
+ }) => {
21892
+ const scaledInitialOrbitDistance = Number.isFinite(initialOrbitDistance) ? initialOrbitDistance * MINIMUM_DOLLY_DISTANCE_RATIO : 0;
21893
+ return Math.max(scaledInitialOrbitDistance, camera.near, Number.EPSILON);
21894
+ };
21895
+ var applyInfiniteDolly = ({
21896
+ camera,
21897
+ controls,
21898
+ minimumDollyDistance
21899
+ }) => {
21900
+ if (!(camera instanceof THREE21.PerspectiveCamera)) return false;
21901
+ const orbitDistance = controls.getDistance();
21902
+ if (Number.isFinite(orbitDistance) && orbitDistance >= minimumDollyDistance) {
21903
+ return false;
21904
+ }
21905
+ const viewDirection = new THREE21.Vector3();
21906
+ camera.getWorldDirection(viewDirection);
21907
+ controls.target.copy(camera.position).addScaledVector(viewDirection, minimumDollyDistance);
21908
+ return true;
21909
+ };
21910
+
21911
+ // src/react-three/OrbitControls.tsx
21884
21912
  var OrbitControls = ({
21885
21913
  autoRotate,
21886
21914
  autoRotateSpeed,
@@ -21898,6 +21926,17 @@ var OrbitControls = ({
21898
21926
  if (!camera || !renderer) return null;
21899
21927
  return new ThreeOrbitControls(camera, renderer.domElement);
21900
21928
  }, [camera, renderer]);
21929
+ const minimumDollyDistance = useMemo15(() => {
21930
+ if (!controls || !(camera instanceof THREE22.PerspectiveCamera)) {
21931
+ return Number.EPSILON;
21932
+ }
21933
+ const initialOrbitDistance = target ? Math.hypot(
21934
+ camera.position.x - target[0],
21935
+ camera.position.y - target[1],
21936
+ camera.position.z - target[2]
21937
+ ) : controls.getDistance();
21938
+ return getMinimumDollyDistance({ camera, initialOrbitDistance });
21939
+ }, [camera, controls, target]);
21901
21940
  useEffect18(() => {
21902
21941
  onControlsChange?.(controls ?? null);
21903
21942
  return () => onControlsChange?.(null);
@@ -21923,9 +21962,9 @@ var OrbitControls = ({
21923
21962
  if (dampingFactor !== void 0) controls.dampingFactor = dampingFactor;
21924
21963
  controls.zoomToCursor = true;
21925
21964
  controls.mouseButtons = {
21926
- LEFT: THREE21.MOUSE.ROTATE,
21965
+ LEFT: THREE22.MOUSE.ROTATE,
21927
21966
  // Left click to rotate
21928
- MIDDLE: THREE21.MOUSE.PAN,
21967
+ MIDDLE: THREE22.MOUSE.PAN,
21929
21968
  // Middle click to pan
21930
21969
  RIGHT: null
21931
21970
  // Right-click always disabled - only context menu
@@ -21959,8 +21998,10 @@ var OrbitControls = ({
21959
21998
  };
21960
21999
  }, [controls]);
21961
22000
  useFrame(() => {
21962
- controls?.update();
21963
- }, [controls]);
22001
+ if (!controls) return;
22002
+ applyInfiniteDolly({ camera, controls, minimumDollyDistance });
22003
+ controls.update();
22004
+ }, [camera, controls, minimumDollyDistance]);
21964
22005
  return null;
21965
22006
  };
21966
22007
 
@@ -22047,14 +22088,14 @@ var getComparisonBounds = (type, boardDimensions, boardCenter) => {
22047
22088
 
22048
22089
  // src/three-components/OrientationCubeCanvas.tsx
22049
22090
  import { useEffect as useEffect19, useRef as useRef7 } from "react";
22050
- import * as THREE22 from "three";
22091
+ import * as THREE23 from "three";
22051
22092
  import { Text as TroikaText } from "troika-three-text";
22052
22093
  import { jsx as jsx14 } from "react/jsx-runtime";
22053
22094
  function computePointInFront(rotationVector, distance5) {
22054
- const quaternion = new THREE22.Quaternion().setFromEuler(
22055
- new THREE22.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
22095
+ const quaternion = new THREE23.Quaternion().setFromEuler(
22096
+ new THREE23.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
22056
22097
  );
22057
- const forwardVector = new THREE22.Vector3(0, 0, 1);
22098
+ const forwardVector = new THREE23.Vector3(0, 0, 1);
22058
22099
  forwardVector.applyQuaternion(quaternion);
22059
22100
  const result = forwardVector.multiplyScalar(distance5);
22060
22101
  return result;
@@ -22067,31 +22108,31 @@ var OrientationCubeCanvas = () => {
22067
22108
  const container = containerRef.current;
22068
22109
  const canvas = document.createElement("canvas");
22069
22110
  container.appendChild(canvas);
22070
- const renderer = new THREE22.WebGLRenderer({
22111
+ const renderer = new THREE23.WebGLRenderer({
22071
22112
  canvas,
22072
22113
  antialias: true,
22073
22114
  alpha: true
22074
22115
  });
22075
22116
  renderer.setSize(120, 120);
22076
22117
  renderer.setPixelRatio(window.devicePixelRatio);
22077
- const scene = new THREE22.Scene();
22078
- const camera = new THREE22.PerspectiveCamera(75, 1, 0.1, 1e3);
22118
+ const scene = new THREE23.Scene();
22119
+ const camera = new THREE23.PerspectiveCamera(75, 1, 0.1, 1e3);
22079
22120
  camera.up.set(0, 0, 1);
22080
- const ambientLight = new THREE22.AmbientLight(16777215, Math.PI / 2);
22121
+ const ambientLight = new THREE23.AmbientLight(16777215, Math.PI / 2);
22081
22122
  scene.add(ambientLight);
22082
- const group = new THREE22.Group();
22123
+ const group = new THREE23.Group();
22083
22124
  group.rotation.fromArray([Math.PI / 2, 0, 0]);
22084
22125
  const cubeSize = 1;
22085
- const box = new THREE22.Mesh(
22086
- new THREE22.BoxGeometry(cubeSize, cubeSize, cubeSize),
22087
- new THREE22.MeshStandardMaterial({ color: "white" })
22126
+ const box = new THREE23.Mesh(
22127
+ new THREE23.BoxGeometry(cubeSize, cubeSize, cubeSize),
22128
+ new THREE23.MeshStandardMaterial({ color: "white" })
22088
22129
  );
22089
22130
  group.add(box);
22090
- const edges = new THREE22.LineSegments(
22091
- new THREE22.EdgesGeometry(
22092
- new THREE22.BoxGeometry(cubeSize, cubeSize, cubeSize)
22131
+ const edges = new THREE23.LineSegments(
22132
+ new THREE23.EdgesGeometry(
22133
+ new THREE23.BoxGeometry(cubeSize, cubeSize, cubeSize)
22093
22134
  ),
22094
- new THREE22.LineBasicMaterial({ color: 0, linewidth: 2 })
22135
+ new THREE23.LineBasicMaterial({ color: 0, linewidth: 2 })
22095
22136
  );
22096
22137
  group.add(edges);
22097
22138
  scene.add(group);
@@ -22153,7 +22194,7 @@ var OrientationCubeCanvas = () => {
22153
22194
  if (!isVisible) return;
22154
22195
  if (mainCameraRef.current) {
22155
22196
  const cameraPosition = computePointInFront(
22156
- mainCameraRef.current.rotation ?? new THREE22.Euler(0, 0, 0),
22197
+ mainCameraRef.current.rotation ?? new THREE23.Euler(0, 0, 0),
22157
22198
  2
22158
22199
  );
22159
22200
  if (!cameraPosition.equals(camera.position)) {
@@ -22205,12 +22246,12 @@ var OrientationCubeCanvas = () => {
22205
22246
  import { useEffect as useEffect20, useMemo as useMemo16 } from "react";
22206
22247
 
22207
22248
  // src/reference-objects/create-reference-object.ts
22208
- import * as THREE23 from "three";
22249
+ import * as THREE24 from "three";
22209
22250
  var createRoundedRectangleShape = (width, height, radius) => {
22210
22251
  const halfWidth = width / 2;
22211
22252
  const halfHeight = height / 2;
22212
22253
  const safeRadius = Math.min(radius, halfWidth, halfHeight);
22213
- const shape = new THREE23.Shape();
22254
+ const shape = new THREE24.Shape();
22214
22255
  shape.moveTo(-halfWidth + safeRadius, -halfHeight);
22215
22256
  shape.lineTo(halfWidth - safeRadius, -halfHeight);
22216
22257
  shape.quadraticCurveTo(
@@ -22249,7 +22290,7 @@ var createRoundedPrismGeometry = (width, height, depth, radius) => {
22249
22290
  );
22250
22291
  };
22251
22292
  var createPrismGeometryFromShape = (shape, depth) => {
22252
- const geometry = new THREE23.ExtrudeGeometry(shape, {
22293
+ const geometry = new THREE24.ExtrudeGeometry(shape, {
22253
22294
  depth,
22254
22295
  bevelEnabled: false,
22255
22296
  curveSegments: 24
@@ -22261,16 +22302,16 @@ var createPrismGeometryFromShape = (shape, depth) => {
22261
22302
  var normalizeObjectToSpec = (object, type) => {
22262
22303
  const spec = REFERENCE_OBJECT_SPECS[type];
22263
22304
  object.updateMatrixWorld(true);
22264
- const initialBounds = new THREE23.Box3().setFromObject(object);
22265
- const initialSize = initialBounds.getSize(new THREE23.Vector3());
22305
+ const initialBounds = new THREE24.Box3().setFromObject(object);
22306
+ const initialSize = initialBounds.getSize(new THREE24.Vector3());
22266
22307
  object.scale.set(
22267
22308
  spec.width / initialSize.x,
22268
22309
  spec.height / initialSize.y,
22269
22310
  spec.depth / initialSize.z
22270
22311
  );
22271
22312
  object.updateMatrixWorld(true);
22272
- const scaledBounds = new THREE23.Box3().setFromObject(object);
22273
- const scaledCenter = scaledBounds.getCenter(new THREE23.Vector3());
22313
+ const scaledBounds = new THREE24.Box3().setFromObject(object);
22314
+ const scaledCenter = scaledBounds.getCenter(new THREE24.Vector3());
22274
22315
  object.position.set(
22275
22316
  -scaledCenter.x,
22276
22317
  -scaledCenter.y,
@@ -22279,15 +22320,15 @@ var normalizeObjectToSpec = (object, type) => {
22279
22320
  object.updateMatrixWorld(true);
22280
22321
  };
22281
22322
  var createBananaGeometry = () => {
22282
- const curve = new THREE23.CatmullRomCurve3([
22283
- new THREE23.Vector3(-82, 18, 16),
22284
- new THREE23.Vector3(-67, 7, 15),
22285
- new THREE23.Vector3(-43, -9, 14),
22286
- new THREE23.Vector3(-15, -18, 14),
22287
- new THREE23.Vector3(16, -18, 14),
22288
- new THREE23.Vector3(47, -8, 14.5),
22289
- new THREE23.Vector3(72, 8, 16),
22290
- new THREE23.Vector3(84, 19, 17)
22323
+ const curve = new THREE24.CatmullRomCurve3([
22324
+ new THREE24.Vector3(-82, 18, 16),
22325
+ new THREE24.Vector3(-67, 7, 15),
22326
+ new THREE24.Vector3(-43, -9, 14),
22327
+ new THREE24.Vector3(-15, -18, 14),
22328
+ new THREE24.Vector3(16, -18, 14),
22329
+ new THREE24.Vector3(47, -8, 14.5),
22330
+ new THREE24.Vector3(72, 8, 16),
22331
+ new THREE24.Vector3(84, 19, 17)
22291
22332
  ]);
22292
22333
  const tubularSegments = 84;
22293
22334
  const radialSegments = 30;
@@ -22297,8 +22338,8 @@ var createBananaGeometry = () => {
22297
22338
  const colors2 = [];
22298
22339
  const uvs = [];
22299
22340
  const indices = [];
22300
- const ripeYellow = new THREE23.Color(16766023);
22301
- const stemGreen = new THREE23.Color(12038965);
22341
+ const ripeYellow = new THREE24.Color(16766023);
22342
+ const stemGreen = new THREE24.Color(12038965);
22302
22343
  for (let segment = 0; segment <= tubularSegments; segment++) {
22303
22344
  const t = segment / tubularSegments;
22304
22345
  const point = curve.getPointAt(t);
@@ -22313,7 +22354,7 @@ var createBananaGeometry = () => {
22313
22354
  const sin = Math.sin(angle3);
22314
22355
  const cos = Math.cos(angle3);
22315
22356
  const ridgeScale = 1 + Math.cos(angle3 * 5 + 0.35) * 0.035;
22316
- const radialNormal = new THREE23.Vector3().addScaledVector(normal, cos).addScaledVector(binormal, sin * 0.9).normalize();
22357
+ const radialNormal = new THREE24.Vector3().addScaledVector(normal, cos).addScaledVector(binormal, sin * 0.9).normalize();
22317
22358
  const vertex = point.clone().addScaledVector(normal, cos * radius * ridgeScale).addScaledVector(binormal, sin * radius * 0.9 * ridgeScale);
22318
22359
  positions.push(vertex.x, vertex.y, vertex.z);
22319
22360
  normals.push(radialNormal.x, radialNormal.y, radialNormal.z);
@@ -22331,26 +22372,26 @@ var createBananaGeometry = () => {
22331
22372
  indices.push(a, d, b, b, d, c);
22332
22373
  }
22333
22374
  }
22334
- const geometry = new THREE23.BufferGeometry();
22375
+ const geometry = new THREE24.BufferGeometry();
22335
22376
  geometry.setIndex(indices);
22336
22377
  geometry.setAttribute(
22337
22378
  "position",
22338
- new THREE23.Float32BufferAttribute(positions, 3)
22379
+ new THREE24.Float32BufferAttribute(positions, 3)
22339
22380
  );
22340
- geometry.setAttribute("normal", new THREE23.Float32BufferAttribute(normals, 3));
22341
- geometry.setAttribute("color", new THREE23.Float32BufferAttribute(colors2, 3));
22342
- geometry.setAttribute("uv", new THREE23.Float32BufferAttribute(uvs, 2));
22381
+ geometry.setAttribute("normal", new THREE24.Float32BufferAttribute(normals, 3));
22382
+ geometry.setAttribute("color", new THREE24.Float32BufferAttribute(colors2, 3));
22383
+ geometry.setAttribute("uv", new THREE24.Float32BufferAttribute(uvs, 2));
22343
22384
  geometry.computeBoundingBox();
22344
22385
  geometry.computeBoundingSphere();
22345
22386
  return { geometry, curve };
22346
22387
  };
22347
22388
  var createBanana = () => {
22348
- const group = new THREE23.Group();
22349
- const banana = new THREE23.Group();
22389
+ const group = new THREE24.Group();
22390
+ const banana = new THREE24.Group();
22350
22391
  const { geometry, curve } = createBananaGeometry();
22351
- const peel = new THREE23.Mesh(
22392
+ const peel = new THREE24.Mesh(
22352
22393
  geometry,
22353
- new THREE23.MeshStandardMaterial({
22394
+ new THREE24.MeshStandardMaterial({
22354
22395
  color: 16777215,
22355
22396
  roughness: 0.72,
22356
22397
  metalness: 0,
@@ -22359,9 +22400,9 @@ var createBanana = () => {
22359
22400
  );
22360
22401
  peel.name = "banana-peel";
22361
22402
  banana.add(peel);
22362
- const blossomTip = new THREE23.Mesh(
22363
- new THREE23.SphereGeometry(3.4, 20, 12),
22364
- new THREE23.MeshStandardMaterial({
22403
+ const blossomTip = new THREE24.Mesh(
22404
+ new THREE24.SphereGeometry(3.4, 20, 12),
22405
+ new THREE24.MeshStandardMaterial({
22365
22406
  color: 6242844,
22366
22407
  roughness: 0.92
22367
22408
  })
@@ -22372,20 +22413,20 @@ var createBanana = () => {
22372
22413
  banana.add(blossomTip);
22373
22414
  const stemLength = 11;
22374
22415
  const stemTangent = curve.getTangentAt(1).normalize();
22375
- const stem = new THREE23.Mesh(
22376
- new THREE23.CylinderGeometry(2.5, 4.1, stemLength, 18),
22377
- new THREE23.MeshStandardMaterial({
22416
+ const stem = new THREE24.Mesh(
22417
+ new THREE24.CylinderGeometry(2.5, 4.1, stemLength, 18),
22418
+ new THREE24.MeshStandardMaterial({
22378
22419
  color: 8483625,
22379
22420
  roughness: 0.82
22380
22421
  })
22381
22422
  );
22382
- stem.quaternion.setFromUnitVectors(new THREE23.Vector3(0, 1, 0), stemTangent);
22423
+ stem.quaternion.setFromUnitVectors(new THREE24.Vector3(0, 1, 0), stemTangent);
22383
22424
  stem.position.copy(curve.getPointAt(1)).addScaledVector(stemTangent, stemLength / 2);
22384
22425
  stem.name = "banana-stem";
22385
22426
  banana.add(stem);
22386
- const stemTip = new THREE23.Mesh(
22387
- new THREE23.SphereGeometry(2.55, 18, 10),
22388
- new THREE23.MeshStandardMaterial({
22427
+ const stemTip = new THREE24.Mesh(
22428
+ new THREE24.SphereGeometry(2.55, 18, 10),
22429
+ new THREE24.MeshStandardMaterial({
22389
22430
  color: 5981470,
22390
22431
  roughness: 0.9
22391
22432
  })
@@ -22399,7 +22440,7 @@ var createBanana = () => {
22399
22440
  };
22400
22441
  var createMacbookLidGeometry = (width, height, depth, radius, indentRadius) => {
22401
22442
  const lidShape = createRoundedRectangleShape(width, height, radius);
22402
- const indent = new THREE23.Path();
22443
+ const indent = new THREE24.Path();
22403
22444
  indent.absarc(0, 0, indentRadius, 0, Math.PI * 2, true);
22404
22445
  lidShape.holes.push(indent);
22405
22446
  return createPrismGeometryFromShape(lidShape, depth);
@@ -22407,9 +22448,9 @@ var createMacbookLidGeometry = (width, height, depth, radius, indentRadius) => {
22407
22448
  var createMacbookIndent = (topZ, radius) => {
22408
22449
  const indentDepth = 0.35;
22409
22450
  const diskDepth = 0.25;
22410
- const disk = new THREE23.Mesh(
22411
- new THREE23.CylinderGeometry(radius - 0.15, radius - 0.15, diskDepth, 48),
22412
- new THREE23.MeshStandardMaterial({
22451
+ const disk = new THREE24.Mesh(
22452
+ new THREE24.CylinderGeometry(radius - 0.15, radius - 0.15, diskDepth, 48),
22453
+ new THREE24.MeshStandardMaterial({
22413
22454
  color: 10199202,
22414
22455
  roughness: 0.48,
22415
22456
  metalness: 0.28
@@ -22422,10 +22463,10 @@ var createMacbookIndent = (topZ, radius) => {
22422
22463
  };
22423
22464
  var createCreditCard = () => {
22424
22465
  const spec = REFERENCE_OBJECT_SPECS["credit-card"];
22425
- const group = new THREE23.Group();
22426
- const body = new THREE23.Mesh(
22466
+ const group = new THREE24.Group();
22467
+ const body = new THREE24.Mesh(
22427
22468
  createRoundedPrismGeometry(spec.width, spec.height, spec.depth, 3.18),
22428
- new THREE23.MeshStandardMaterial({
22469
+ new THREE24.MeshStandardMaterial({
22429
22470
  color: 2383272,
22430
22471
  roughness: 0.38,
22431
22472
  metalness: 0.08
@@ -22434,9 +22475,9 @@ var createCreditCard = () => {
22434
22475
  body.name = "credit-card-body";
22435
22476
  group.add(body);
22436
22477
  const surfaceZ = spec.depth / 2 + 0.08;
22437
- const chip = new THREE23.Mesh(
22478
+ const chip = new THREE24.Mesh(
22438
22479
  createRoundedPrismGeometry(12, 9, 0.14, 1.2),
22439
- new THREE23.MeshStandardMaterial({
22480
+ new THREE24.MeshStandardMaterial({
22440
22481
  color: 14003525,
22441
22482
  roughness: 0.3,
22442
22483
  metalness: 0.62
@@ -22445,14 +22486,14 @@ var createCreditCard = () => {
22445
22486
  chip.position.set(-21, 3, surfaceZ);
22446
22487
  chip.name = "credit-card-chip";
22447
22488
  group.add(chip);
22448
- const stripeMaterial = new THREE23.MeshStandardMaterial({
22489
+ const stripeMaterial = new THREE24.MeshStandardMaterial({
22449
22490
  color: 15331061,
22450
22491
  roughness: 0.45,
22451
22492
  metalness: 0.05
22452
22493
  });
22453
22494
  for (let index2 = 0; index2 < 4; index2++) {
22454
- const stripe = new THREE23.Mesh(
22455
- new THREE23.BoxGeometry(index2 === 3 ? 8 : 12, 0.8, 0.1),
22495
+ const stripe = new THREE24.Mesh(
22496
+ new THREE24.BoxGeometry(index2 === 3 ? 8 : 12, 0.8, 0.1),
22456
22497
  stripeMaterial
22457
22498
  );
22458
22499
  stripe.position.set(-20 + index2 * 14, -14, surfaceZ + 0.08);
@@ -22463,13 +22504,13 @@ var createCreditCard = () => {
22463
22504
  };
22464
22505
  var createMacbook = () => {
22465
22506
  const spec = REFERENCE_OBJECT_SPECS["14in-macbook"];
22466
- const group = new THREE23.Group();
22467
- const aluminumMaterial = new THREE23.MeshStandardMaterial({
22507
+ const group = new THREE24.Group();
22508
+ const aluminumMaterial = new THREE24.MeshStandardMaterial({
22468
22509
  color: 12896201,
22469
22510
  roughness: 0.3,
22470
22511
  metalness: 0.38
22471
22512
  });
22472
- const body = new THREE23.Mesh(
22513
+ const body = new THREE24.Mesh(
22473
22514
  createRoundedPrismGeometry(spec.width, spec.height, 13.5, 9),
22474
22515
  aluminumMaterial
22475
22516
  );
@@ -22480,7 +22521,7 @@ var createMacbook = () => {
22480
22521
  const lidCenterZ = 6.75;
22481
22522
  const lidTopZ = lidCenterZ + lidDepth / 2;
22482
22523
  const indentRadius = 12;
22483
- const lid = new THREE23.Mesh(
22524
+ const lid = new THREE24.Mesh(
22484
22525
  createMacbookLidGeometry(
22485
22526
  spec.width - 1.8,
22486
22527
  spec.height - 1.8,
@@ -22493,9 +22534,9 @@ var createMacbook = () => {
22493
22534
  lid.position.z = lidCenterZ;
22494
22535
  lid.name = "macbook-lid";
22495
22536
  group.add(lid);
22496
- const hinge = new THREE23.Mesh(
22497
- new THREE23.BoxGeometry(spec.width - 42, 3.2, 1.2),
22498
- new THREE23.MeshStandardMaterial({
22537
+ const hinge = new THREE24.Mesh(
22538
+ new THREE24.BoxGeometry(spec.width - 42, 3.2, 1.2),
22539
+ new THREE24.MeshStandardMaterial({
22499
22540
  color: 3158838,
22500
22541
  roughness: 0.55,
22501
22542
  metalness: 0.45
@@ -22505,9 +22546,9 @@ var createMacbook = () => {
22505
22546
  hinge.name = "macbook-hinge";
22506
22547
  group.add(hinge);
22507
22548
  group.add(createMacbookIndent(lidTopZ, indentRadius));
22508
- const frontNotch = new THREE23.Mesh(
22509
- new THREE23.BoxGeometry(54, 1.2, 0.8),
22510
- new THREE23.MeshStandardMaterial({
22549
+ const frontNotch = new THREE24.Mesh(
22550
+ new THREE24.BoxGeometry(54, 1.2, 0.8),
22551
+ new THREE24.MeshStandardMaterial({
22511
22552
  color: 6712174,
22512
22553
  roughness: 0.45,
22513
22554
  metalness: 0.5
@@ -22530,7 +22571,7 @@ var disposeReferenceObject = (object) => {
22530
22571
  const geometries = /* @__PURE__ */ new Set();
22531
22572
  const materials = /* @__PURE__ */ new Set();
22532
22573
  object.traverse((child) => {
22533
- if (!(child instanceof THREE23.Mesh)) return;
22574
+ if (!(child instanceof THREE24.Mesh)) return;
22534
22575
  geometries.add(child.geometry);
22535
22576
  const childMaterials = Array.isArray(child.material) ? child.material : [child.material];
22536
22577
  for (const material of childMaterials) materials.add(material);
@@ -22540,28 +22581,28 @@ var disposeReferenceObject = (object) => {
22540
22581
  };
22541
22582
 
22542
22583
  // src/reference-objects/fit-camera-to-bounds.ts
22543
- import * as THREE24 from "three";
22584
+ import * as THREE25 from "three";
22544
22585
  var fitCameraToBounds = (camera, controls, bounds, padding = 1.18) => {
22545
22586
  const width = Math.max(bounds.maxX - bounds.minX, 0);
22546
22587
  const height = Math.max(bounds.maxY - bounds.minY, 0);
22547
22588
  const depth = Math.max(bounds.maxZ - bounds.minZ, 0);
22548
- const center = new THREE24.Vector3(
22589
+ const center = new THREE25.Vector3(
22549
22590
  (bounds.minX + bounds.maxX) / 2,
22550
22591
  (bounds.minY + bounds.maxY) / 2,
22551
22592
  (bounds.minZ + bounds.maxZ) / 2
22552
22593
  );
22553
22594
  const radius = Math.max(Math.hypot(width, height, depth) / 2, 1);
22554
- const previousTarget = controls?.target ?? new THREE24.Vector3();
22555
- const direction = new THREE24.Vector3(0, -0.75, 0.9).normalize();
22595
+ const previousTarget = controls?.target ?? new THREE25.Vector3();
22596
+ const direction = new THREE25.Vector3(0, -0.75, 0.9).normalize();
22556
22597
  let distance5 = Math.max(camera.position.distanceTo(previousTarget), 5);
22557
- if (camera instanceof THREE24.PerspectiveCamera) {
22558
- const verticalFov = THREE24.MathUtils.degToRad(camera.fov);
22598
+ if (camera instanceof THREE25.PerspectiveCamera) {
22599
+ const verticalFov = THREE25.MathUtils.degToRad(camera.fov);
22559
22600
  const horizontalFov = 2 * Math.atan(Math.tan(verticalFov / 2) * camera.aspect);
22560
22601
  const limitingFov = Math.min(verticalFov, horizontalFov);
22561
22602
  distance5 = radius * padding / Math.sin(limitingFov / 2);
22562
22603
  camera.far = Math.max(camera.far, distance5 + radius * padding * 3);
22563
22604
  camera.updateProjectionMatrix();
22564
- } else if (camera instanceof THREE24.OrthographicCamera) {
22605
+ } else if (camera instanceof THREE25.OrthographicCamera) {
22565
22606
  const halfViewWidth = Math.abs(camera.right - camera.left) / 2;
22566
22607
  const halfViewHeight = Math.abs(camera.top - camera.bottom) / 2;
22567
22608
  camera.zoom = Math.min(
@@ -22681,7 +22722,7 @@ var CadViewerContainer = forwardRef2(
22681
22722
  Canvas,
22682
22723
  {
22683
22724
  ref,
22684
- scene: { up: new THREE25.Vector3(0, 0, 1) },
22725
+ scene: { up: new THREE26.Vector3(0, 0, 1) },
22685
22726
  camera: { up: [0, 0, 1], position: initialCameraPosition },
22686
22727
  onCreated: ({ camera }) => {
22687
22728
  mainCameraRef.current = camera;
@@ -22872,7 +22913,7 @@ var createBoardGeomWithOutline = (board, depth = 1.2, options = {}) => {
22872
22913
  };
22873
22914
 
22874
22915
  // src/utils/get-board-edge-color.ts
22875
- import * as THREE27 from "three";
22916
+ import * as THREE28 from "three";
22876
22917
 
22877
22918
  // src/geoms/constants.ts
22878
22919
  var M = 0.01;
@@ -22905,7 +22946,7 @@ var soldermaskColors = {
22905
22946
  };
22906
22947
 
22907
22948
  // src/utils/soldermask-color.ts
22908
- import * as THREE26 from "three";
22949
+ import * as THREE27 from "three";
22909
22950
  var SOLDERMASK_PRESET_HEX = {
22910
22951
  red: "#650202",
22911
22952
  blue: "#003f7d",
@@ -22936,9 +22977,9 @@ var resolveSoldermaskColor = (requestedColor) => {
22936
22977
  }
22937
22978
  const presetName = lowercaseColor;
22938
22979
  const presetColor = SOLDERMASK_PRESET_HEX[presetName];
22939
- if (presetColor) return new THREE26.Color(presetColor);
22940
- const isCssColor = Object.hasOwn(THREE26.Color.NAMES, lowercaseColor) || CSS_HEX_COLOR_PATTERN.test(normalizedColor) || CSS_RGB_INTEGER_PATTERN.test(normalizedColor) || CSS_RGB_PERCENT_PATTERN.test(normalizedColor) || CSS_HSL_PATTERN.test(normalizedColor);
22941
- return isCssColor ? new THREE26.Color(lowercaseColor) : null;
22980
+ if (presetColor) return new THREE27.Color(presetColor);
22981
+ const isCssColor = Object.hasOwn(THREE27.Color.NAMES, lowercaseColor) || CSS_HEX_COLOR_PATTERN.test(normalizedColor) || CSS_RGB_INTEGER_PATTERN.test(normalizedColor) || CSS_RGB_PERCENT_PATTERN.test(normalizedColor) || CSS_HSL_PATTERN.test(normalizedColor);
22982
+ return isCssColor ? new THREE27.Color(lowercaseColor) : null;
22942
22983
  };
22943
22984
  var resolveSoldermaskOpacity = (requestedColor) => {
22944
22985
  const presetName = requestedColor?.trim().toLowerCase();
@@ -22965,7 +23006,7 @@ var soldermaskColorToCss = (color) => {
22965
23006
  };
22966
23007
 
22967
23008
  // src/utils/get-board-edge-color.ts
22968
- var LEGACY_FR4_EDGE_COLOR = new THREE27.Color(1063462);
23009
+ var LEGACY_FR4_EDGE_COLOR = new THREE28.Color(1063462);
22969
23010
  var getBoardEdgeColor = ({
22970
23011
  material,
22971
23012
  solder_mask_color
@@ -22974,7 +23015,7 @@ var getBoardEdgeColor = ({
22974
23015
  if (soldermaskColor) return soldermaskColor;
22975
23016
  if (material === "fr4") return LEGACY_FR4_EDGE_COLOR.clone();
22976
23017
  const materialColor = boardMaterialColors[material] ?? colors.fr4Tan;
22977
- return new THREE27.Color(materialColor[0], materialColor[1], materialColor[2]);
23018
+ return new THREE28.Color(materialColor[0], materialColor[1], materialColor[2]);
22978
23019
  };
22979
23020
 
22980
23021
  // src/soup-to-3d/index.ts
@@ -23028,6 +23069,7 @@ var createSimplifiedBoardGeom = (circuitJson) => {
23028
23069
  // src/BoardGeomBuilder.ts
23029
23070
  var import_colors3 = __toESM(require_colors(), 1);
23030
23071
  var import_booleans4 = __toESM(require_booleans(), 1);
23072
+ var import_measurements = __toESM(require_measurements(), 1);
23031
23073
  var import_extrusions4 = __toESM(require_extrusions(), 1);
23032
23074
  var import_transforms6 = __toESM(require_transforms(), 1);
23033
23075
  var import_primitives6 = __toESM(require_primitives(), 1);
@@ -23759,6 +23801,9 @@ var BoardGeomBuilder = class {
23759
23801
  platedHoleGeoms = [];
23760
23802
  viaGeoms = [];
23761
23803
  // Combined with platedHoleGeoms
23804
+ // Drills are in board space (mm, +Z up). Apply them after all copper exists,
23805
+ // excluding each barrel's own drill so its thin plating is preserved.
23806
+ copperDrills = [];
23762
23807
  boardClipGeom = null;
23763
23808
  state = "initializing";
23764
23809
  currentIndex = 0;
@@ -23976,6 +24021,10 @@ var BoardGeomBuilder = class {
23976
24021
  }
23977
24022
  if (!opts.dontCutBoard) {
23978
24023
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, cyGeom);
24024
+ this.copperDrills.push({
24025
+ geom: cyGeom,
24026
+ platedHoleIndex: this.platedHoleGeoms.length
24027
+ });
23979
24028
  }
23980
24029
  const platedHoleGeom = platedHole(ph, this.ctx, {
23981
24030
  clipGeom: this.boardClipGeom
@@ -24013,6 +24062,10 @@ var BoardGeomBuilder = class {
24013
24062
  }
24014
24063
  if (!opts.dontCutBoard) {
24015
24064
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, pillHole);
24065
+ this.copperDrills.push({
24066
+ geom: pillHole,
24067
+ platedHoleIndex: this.platedHoleGeoms.length
24068
+ });
24016
24069
  }
24017
24070
  const platedHoleGeom = platedHole(ph, this.ctx, {
24018
24071
  clipGeom: this.boardClipGeom
@@ -24066,6 +24119,10 @@ var BoardGeomBuilder = class {
24066
24119
  );
24067
24120
  if (!opts.dontCutBoard) {
24068
24121
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, pillHole);
24122
+ this.copperDrills.push({
24123
+ geom: pillHole,
24124
+ platedHoleIndex: this.platedHoleGeoms.length
24125
+ });
24069
24126
  }
24070
24127
  const platedHoleGeom = platedHole(ph, this.ctx, {
24071
24128
  clipGeom: this.boardClipGeom
@@ -24110,6 +24167,10 @@ var BoardGeomBuilder = class {
24110
24167
  );
24111
24168
  if (!opts.dontCutBoard) {
24112
24169
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, pillHole);
24170
+ this.copperDrills.push({
24171
+ geom: pillHole,
24172
+ platedHoleIndex: this.platedHoleGeoms.length
24173
+ });
24113
24174
  }
24114
24175
  const platedHoleGeom = platedHole(ph, this.ctx, {
24115
24176
  clipGeom: this.boardClipGeom
@@ -24130,10 +24191,11 @@ var BoardGeomBuilder = class {
24130
24191
  if (!boardHole || !copperHole) return;
24131
24192
  if (!opts.dontCutBoard) {
24132
24193
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, boardHole);
24194
+ this.copperDrills.push({
24195
+ geom: boardHole,
24196
+ platedHoleIndex: this.platedHoleGeoms.length
24197
+ });
24133
24198
  }
24134
- this.platedHoleGeoms = this.platedHoleGeoms.map(
24135
- (phg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans4.subtract)(phg, copperHole))
24136
- );
24137
24199
  const platedHoleGeom = platedHole(ph, this.ctx, {
24138
24200
  clipGeom: this.boardClipGeom
24139
24201
  });
@@ -24155,9 +24217,7 @@ var BoardGeomBuilder = class {
24155
24217
  radius: hole.hole_diameter / 2 + M / 2,
24156
24218
  height: holeDepth
24157
24219
  });
24158
- this.platedHoleGeoms = this.platedHoleGeoms.map(
24159
- (phg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans4.subtract)(phg, copperCut))
24160
- );
24220
+ this.copperDrills.push({ geom: copperCut });
24161
24221
  } else if (hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill" || hole.hole_shape === "rect" || hole.hole_shape === "oval") {
24162
24222
  const holeWidth = hole.hole_width ?? hole.hole_diameter;
24163
24223
  const holeHeight = hole.hole_height ?? hole.hole_diameter;
@@ -24219,14 +24279,13 @@ var BoardGeomBuilder = class {
24219
24279
  }
24220
24280
  if (copperCut) {
24221
24281
  const positionedCopperCut = (0, import_transforms6.translate)([hole.x, hole.y, 0], copperCut);
24222
- this.platedHoleGeoms = this.platedHoleGeoms.map(
24223
- (phg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans4.subtract)(phg, positionedCopperCut))
24224
- );
24282
+ this.copperDrills.push({ geom: positionedCopperCut });
24225
24283
  }
24226
24284
  }
24227
24285
  }
24228
24286
  processVia(via) {
24229
24287
  if (!this.boardGeom) return;
24288
+ let viaCopperIndex;
24230
24289
  if (typeof via.outer_diameter === "number" && typeof via.hole_diameter === "number") {
24231
24290
  const viaCopperGeom = createViaCopper({
24232
24291
  x: via.x,
@@ -24240,6 +24299,7 @@ var BoardGeomBuilder = class {
24240
24299
  finalViaGeom = (0, import_booleans4.intersect)(this.boardClipGeom, viaCopperGeom);
24241
24300
  finalViaGeom = (0, import_colors3.colorize)(colors.copper, finalViaGeom);
24242
24301
  }
24302
+ viaCopperIndex = this.viaGeoms.length;
24243
24303
  this.viaGeoms.push(finalViaGeom);
24244
24304
  }
24245
24305
  if (typeof via.hole_diameter === "number") {
@@ -24250,10 +24310,36 @@ var BoardGeomBuilder = class {
24250
24310
  thickness: this.ctx.pcbThickness
24251
24311
  });
24252
24312
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, viaDrill);
24313
+ this.copperDrills.push({
24314
+ geom: viaDrill,
24315
+ viaIndex: viaCopperIndex
24316
+ });
24253
24317
  }
24254
24318
  }
24255
24319
  finalize() {
24256
24320
  if (!this.boardGeom) return;
24321
+ const drillBounds = this.copperDrills.map((drill) => ({
24322
+ ...drill,
24323
+ bounds: (0, import_measurements.measureBoundingBox)(drill.geom)
24324
+ }));
24325
+ const cutCopper = (geom, index2, kind) => {
24326
+ const bounds = (0, import_measurements.measureBoundingBox)(geom);
24327
+ const drills = drillBounds.filter(
24328
+ (drill) => drill[kind] !== index2 && [0, 1, 2].every(
24329
+ (axis) => drill.bounds[0][axis] <= bounds[1][axis] && drill.bounds[1][axis] >= bounds[0][axis]
24330
+ )
24331
+ ).map((drill) => drill.geom);
24332
+ return (0, import_colors3.colorize)(
24333
+ colors.copper,
24334
+ drills.length ? (0, import_booleans4.subtract)(geom, (0, import_booleans4.union)(...drills)) : geom
24335
+ );
24336
+ };
24337
+ this.platedHoleGeoms = this.platedHoleGeoms.map(
24338
+ (geom, index2) => cutCopper(geom, index2, "platedHoleIndex")
24339
+ );
24340
+ this.viaGeoms = this.viaGeoms.map(
24341
+ (geom, index2) => cutCopper(geom, index2, "viaIndex")
24342
+ );
24257
24343
  const boardEdgeColor = getBoardEdgeColor(this.board);
24258
24344
  this.boardGeom = (0, import_colors3.colorize)(
24259
24345
  [boardEdgeColor.r, boardEdgeColor.g, boardEdgeColor.b],
@@ -24379,7 +24465,7 @@ var Text = ({
24379
24465
  };
24380
24466
 
24381
24467
  // src/three-components/Error3d.tsx
24382
- import * as THREE28 from "three";
24468
+ import * as THREE29 from "three";
24383
24469
  import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs3 } from "react/jsx-runtime";
24384
24470
  var Error3d = ({
24385
24471
  error,
@@ -24413,7 +24499,7 @@ var Error3d = ({
24413
24499
  return [0, 0, 0];
24414
24500
  }, [cad_component]);
24415
24501
  const group = useMemo19(() => {
24416
- const g = new THREE28.Group();
24502
+ const g = new THREE29.Group();
24417
24503
  g.position.fromArray(position);
24418
24504
  return g;
24419
24505
  }, [position]);
@@ -24475,9 +24561,9 @@ var Error3d = ({
24475
24561
  };
24476
24562
  var ErrorBox = ({ parent }) => {
24477
24563
  const mesh = useMemo19(() => {
24478
- const m = new THREE28.Mesh(
24479
- new THREE28.BoxGeometry(0.5, 0.5, 0.5),
24480
- new THREE28.MeshStandardMaterial({
24564
+ const m = new THREE29.Mesh(
24565
+ new THREE29.BoxGeometry(0.5, 0.5, 0.5),
24566
+ new THREE29.MeshStandardMaterial({
24481
24567
  depthTest: false,
24482
24568
  transparent: true,
24483
24569
  color: "red",
@@ -24501,8 +24587,8 @@ var ErrorBox = ({ parent }) => {
24501
24587
  import { su as su9 } from "@tscircuit/circuit-json-util";
24502
24588
  import { useEffect as useEffect26, useMemo as useMemo21 } from "react";
24503
24589
 
24504
- // src/textures/create-combined-board-textures.ts
24505
- import * as THREE41 from "three";
24590
+ // src/textures/open-via-holes-at-pads.ts
24591
+ import { CircuitToCanvasDrawer } from "circuit-to-canvas";
24506
24592
 
24507
24593
  // node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
24508
24594
  var getBoundsFromPoints = (points) => {
@@ -24554,10 +24640,112 @@ function calculateOutlineBounds(boardData) {
24554
24640
  };
24555
24641
  }
24556
24642
 
24643
+ // src/textures/open-via-holes-at-pads.ts
24644
+ function getViaHolesAtExposedPads(circuitJson, boardData, resolution) {
24645
+ const vias = getPcbVias(circuitJson);
24646
+ if (!vias.length) return [];
24647
+ const bounds = calculateOutlineBounds(boardData);
24648
+ const width = Math.floor(bounds.width * resolution);
24649
+ const height = Math.floor(bounds.height * resolution);
24650
+ if (width <= 0 || height <= 0) return [];
24651
+ const opened = /* @__PURE__ */ new Set();
24652
+ for (const layer of ["top", "bottom"]) {
24653
+ const pads = circuitJson.filter(
24654
+ (element) => (element.type === "pcb_smtpad" && element.layer === layer || element.type === "pcb_plated_hole" && (!Array.isArray(element.layers) || element.layers.includes(layer))) && element.is_covered_with_solder_mask !== true
24655
+ );
24656
+ if (!pads.length) continue;
24657
+ const canvas = document.createElement("canvas");
24658
+ canvas.width = width;
24659
+ canvas.height = height;
24660
+ const ctx = canvas.getContext("2d");
24661
+ if (!ctx) continue;
24662
+ const drawer = new CircuitToCanvasDrawer(ctx);
24663
+ drawer.configure({
24664
+ colorOverrides: {
24665
+ copper: {
24666
+ top: "white",
24667
+ bottom: "white",
24668
+ inner1: "white",
24669
+ inner2: "white",
24670
+ inner3: "white",
24671
+ inner4: "white",
24672
+ inner5: "white",
24673
+ inner6: "white",
24674
+ inner7: "white",
24675
+ inner8: "white"
24676
+ },
24677
+ drill: "rgba(0,0,0,0)"
24678
+ }
24679
+ });
24680
+ drawer.setCameraBounds(bounds);
24681
+ drawer.drawElements(pads, {
24682
+ layers: [layer === "top" ? "top_copper" : "bottom_copper"],
24683
+ drawSoldermask: false
24684
+ });
24685
+ const pixels = ctx.getImageData(0, 0, width, height).data;
24686
+ for (const via of vias) {
24687
+ if (opened.has(via) || !via.layers.includes(layer)) continue;
24688
+ const radius = via.outer_diameter / 2;
24689
+ const cx = (via.x - bounds.minX) * width / bounds.width;
24690
+ const cy = (bounds.maxY - via.y) * height / bounds.height;
24691
+ const rx = radius * width / bounds.width;
24692
+ const ry = radius * height / bounds.height;
24693
+ if (rx <= 0 || ry <= 0) continue;
24694
+ const minX = Math.max(0, Math.floor(cx - rx)), maxX = Math.min(width - 1, Math.ceil(cx + rx));
24695
+ const minY = Math.max(0, Math.floor(cy - ry)), maxY = Math.min(height - 1, Math.ceil(cy + ry));
24696
+ let overlaps = false;
24697
+ for (let y = minY; y <= maxY && !overlaps; y++) {
24698
+ for (let x = minX; x <= maxX; x++) {
24699
+ if (pixels[(y * width + x) * 4 + 3] >= 128 && ((x + 0.5 - cx) / rx) ** 2 + ((y + 0.5 - cy) / ry) ** 2 <= 1) {
24700
+ overlaps = true;
24701
+ break;
24702
+ }
24703
+ }
24704
+ }
24705
+ if (overlaps) opened.add(via);
24706
+ }
24707
+ }
24708
+ return [...opened];
24709
+ }
24710
+ function clearViaHolesFromSurface({
24711
+ ctx,
24712
+ vias,
24713
+ boardData,
24714
+ layer,
24715
+ width,
24716
+ height
24717
+ }) {
24718
+ if (!vias.length) return;
24719
+ const bounds = calculateOutlineBounds(boardData);
24720
+ ctx.save();
24721
+ ctx.globalCompositeOperation = "destination-out";
24722
+ ctx.fillStyle = "black";
24723
+ for (const via of vias) {
24724
+ if (!via.layers.includes(layer)) continue;
24725
+ const x = (via.x - bounds.minX) * width / bounds.width;
24726
+ const y = (layer === "top" ? bounds.maxY - via.y : via.y - bounds.minY) * height / bounds.height;
24727
+ ctx.beginPath();
24728
+ ctx.ellipse(
24729
+ x,
24730
+ y,
24731
+ via.hole_diameter / 2 * width / bounds.width,
24732
+ via.hole_diameter / 2 * height / bounds.height,
24733
+ 0,
24734
+ 0,
24735
+ Math.PI * 2
24736
+ );
24737
+ ctx.fill();
24738
+ }
24739
+ ctx.restore();
24740
+ }
24741
+
24742
+ // src/textures/create-combined-board-textures.ts
24743
+ import * as THREE42 from "three";
24744
+
24557
24745
  // src/utils/pad-texture.ts
24558
24746
  import { su as su6 } from "@tscircuit/circuit-json-util";
24559
- import { CircuitToCanvasDrawer } from "circuit-to-canvas";
24560
- import * as THREE29 from "three";
24747
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
24748
+ import * as THREE30 from "three";
24561
24749
  function createPadTextureForLayer({
24562
24750
  layer,
24563
24751
  circuitJson,
@@ -24591,7 +24779,7 @@ function createPadTextureForLayer({
24591
24779
  ctx.scale(1, -1);
24592
24780
  }
24593
24781
  const transparent = "rgba(0,0,0,0)";
24594
- const drawer = new CircuitToCanvasDrawer(ctx);
24782
+ const drawer = new CircuitToCanvasDrawer2(ctx);
24595
24783
  drawer.configure({
24596
24784
  colorOverrides: {
24597
24785
  copper: {
@@ -24637,10 +24825,10 @@ function createPadTextureForLayer({
24637
24825
  drawSoldermaskTop: false,
24638
24826
  drawSoldermaskBottom: false
24639
24827
  });
24640
- const texture = new THREE29.CanvasTexture(canvas);
24828
+ const texture = new THREE30.CanvasTexture(canvas);
24641
24829
  texture.generateMipmaps = true;
24642
- texture.minFilter = THREE29.LinearMipmapLinearFilter;
24643
- texture.magFilter = THREE29.LinearFilter;
24830
+ texture.minFilter = THREE30.LinearMipmapLinearFilter;
24831
+ texture.magFilter = THREE30.LinearFilter;
24644
24832
  texture.anisotropy = 16;
24645
24833
  texture.needsUpdate = true;
24646
24834
  return texture;
@@ -24648,7 +24836,7 @@ function createPadTextureForLayer({
24648
24836
 
24649
24837
  // src/utils/panel-outline-texture.ts
24650
24838
  import { su as su7 } from "@tscircuit/circuit-json-util";
24651
- import * as THREE30 from "three";
24839
+ import * as THREE31 from "three";
24652
24840
  var resolvePanelIdForTexture = (circuitJson) => {
24653
24841
  const panels = circuitJson.filter(
24654
24842
  (e) => e.type === "pcb_panel"
@@ -24716,18 +24904,18 @@ function createPanelOutlineTextureForLayer({
24716
24904
  );
24717
24905
  }
24718
24906
  });
24719
- const texture = new THREE30.CanvasTexture(canvas);
24907
+ const texture = new THREE31.CanvasTexture(canvas);
24720
24908
  texture.generateMipmaps = true;
24721
- texture.minFilter = THREE30.LinearMipmapLinearFilter;
24722
- texture.magFilter = THREE30.LinearFilter;
24909
+ texture.minFilter = THREE31.LinearMipmapLinearFilter;
24910
+ texture.magFilter = THREE31.LinearFilter;
24723
24911
  texture.anisotropy = 16;
24724
24912
  texture.needsUpdate = true;
24725
24913
  return texture;
24726
24914
  }
24727
24915
 
24728
24916
  // src/utils/trace-texture.ts
24729
- import * as THREE31 from "three";
24730
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
24917
+ import * as THREE32 from "three";
24918
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
24731
24919
  import { getElementRenderLayers, su as su8 } from "@tscircuit/circuit-json-util";
24732
24920
  function createTraceTextureForLayer({
24733
24921
  layer,
@@ -24765,7 +24953,7 @@ function createTraceTextureForLayer({
24765
24953
  ctx.scale(1, -1);
24766
24954
  }
24767
24955
  const transparent = "rgba(0,0,0,0)";
24768
- const drawer = new CircuitToCanvasDrawer2(ctx);
24956
+ const drawer = new CircuitToCanvasDrawer3(ctx);
24769
24957
  drawer.configure({
24770
24958
  colorOverrides: {
24771
24959
  copper: {
@@ -24812,18 +25000,18 @@ function createTraceTextureForLayer({
24812
25000
  drawSoldermaskTop: false,
24813
25001
  drawSoldermaskBottom: false
24814
25002
  });
24815
- const texture = new THREE31.CanvasTexture(canvas);
25003
+ const texture = new THREE32.CanvasTexture(canvas);
24816
25004
  texture.generateMipmaps = true;
24817
- texture.minFilter = THREE31.LinearMipmapLinearFilter;
24818
- texture.magFilter = THREE31.LinearFilter;
25005
+ texture.minFilter = THREE32.LinearMipmapLinearFilter;
25006
+ texture.magFilter = THREE32.LinearFilter;
24819
25007
  texture.anisotropy = 16;
24820
25008
  texture.needsUpdate = true;
24821
25009
  return texture;
24822
25010
  }
24823
25011
 
24824
25012
  // src/textures/create-copper-pour-texture-for-layer.ts
24825
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
24826
- import * as THREE32 from "three";
25013
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer4 } from "circuit-to-canvas";
25014
+ import * as THREE33 from "three";
24827
25015
  var toRgb = (colorArr) => {
24828
25016
  const [r = 0, g = 0, b = 0] = colorArr;
24829
25017
  return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
@@ -24879,7 +25067,7 @@ function createCopperPourTextureForLayer({
24879
25067
  const setColorAndDraw = (pours, copperPourColor) => {
24880
25068
  if (pours.length === 0) return;
24881
25069
  const elementsToDraw = [...pours, ...drillElements];
24882
- const drawer = new CircuitToCanvasDrawer3(ctx);
25070
+ const drawer = new CircuitToCanvasDrawer4(ctx);
24883
25071
  drawer.configure({
24884
25072
  colorOverrides: {
24885
25073
  copper: {
@@ -24947,20 +25135,20 @@ function createCopperPourTextureForLayer({
24947
25135
  if (!onlyCoveredBySoldermask) {
24948
25136
  setColorAndDraw(uncoveredPours, uncoveredColor);
24949
25137
  }
24950
- const texture = new THREE32.CanvasTexture(canvas);
25138
+ const texture = new THREE33.CanvasTexture(canvas);
24951
25139
  texture.generateMipmaps = true;
24952
- texture.minFilter = THREE32.LinearMipmapLinearFilter;
24953
- texture.magFilter = THREE32.LinearFilter;
25140
+ texture.minFilter = THREE33.LinearMipmapLinearFilter;
25141
+ texture.magFilter = THREE33.LinearFilter;
24954
25142
  texture.anisotropy = 16;
24955
25143
  texture.needsUpdate = true;
24956
25144
  return texture;
24957
25145
  }
24958
25146
 
24959
25147
  // src/textures/create-copper-text-texture-for-layer.ts
24960
- import * as THREE33 from "three";
25148
+ import * as THREE34 from "three";
24961
25149
 
24962
25150
  // src/textures/copper-text/copper-text-drawing.ts
24963
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer4 } from "circuit-to-canvas";
25151
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer5 } from "circuit-to-canvas";
24964
25152
  var setDrawerBounds = (drawer, bounds) => {
24965
25153
  drawer.setCameraBounds({
24966
25154
  minX: bounds.minX,
@@ -24977,7 +25165,7 @@ var drawCopperTextLayer = ({
24977
25165
  copperColor
24978
25166
  }) => {
24979
25167
  const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
24980
- const drawer = new CircuitToCanvasDrawer4(ctx);
25168
+ const drawer = new CircuitToCanvasDrawer5(ctx);
24981
25169
  drawer.configure({
24982
25170
  colorOverrides: {
24983
25171
  copper: {
@@ -25007,7 +25195,7 @@ var drawCopperTextLayer = ({
25007
25195
  maskCanvas.height = ctx.canvas.height;
25008
25196
  const maskCtx = maskCanvas.getContext("2d");
25009
25197
  if (!maskCtx) return;
25010
- const knockoutCutoutDrawer = new CircuitToCanvasDrawer4(maskCtx);
25198
+ const knockoutCutoutDrawer = new CircuitToCanvasDrawer5(maskCtx);
25011
25199
  knockoutCutoutDrawer.configure({
25012
25200
  colorOverrides: {
25013
25201
  copper: {
@@ -25072,20 +25260,20 @@ function createCopperTextTextureForLayer({
25072
25260
  elements,
25073
25261
  copperColor
25074
25262
  });
25075
- const texture = new THREE33.CanvasTexture(canvas);
25263
+ const texture = new THREE34.CanvasTexture(canvas);
25076
25264
  texture.generateMipmaps = true;
25077
- texture.minFilter = THREE33.LinearMipmapLinearFilter;
25078
- texture.magFilter = THREE33.LinearFilter;
25265
+ texture.minFilter = THREE34.LinearMipmapLinearFilter;
25266
+ texture.magFilter = THREE34.LinearFilter;
25079
25267
  texture.anisotropy = 16;
25080
25268
  texture.needsUpdate = true;
25081
25269
  return texture;
25082
25270
  }
25083
25271
 
25084
25272
  // src/textures/create-fabrication-note-texture-for-layer.ts
25085
- import * as THREE34 from "three";
25273
+ import * as THREE35 from "three";
25086
25274
 
25087
25275
  // src/textures/fabrication-note/fabrication-note-drawing.ts
25088
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer5 } from "circuit-to-canvas";
25276
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
25089
25277
 
25090
25278
  // src/utils/units.ts
25091
25279
  var MM_PER_INCH = 25.4;
@@ -25183,7 +25371,7 @@ var drawFabricationNoteLayer = ({
25183
25371
  }) => {
25184
25372
  const renderLayer = `${layer}_fabrication_note`;
25185
25373
  const normalizedElements = elements.map(normalizeFabricationElement);
25186
- const drawer = new CircuitToCanvasDrawer5(ctx);
25374
+ const drawer = new CircuitToCanvasDrawer6(ctx);
25187
25375
  drawer.configure({
25188
25376
  colorOverrides: {
25189
25377
  copper: {
@@ -25312,20 +25500,20 @@ function createFabricationNoteTextureForLayer({
25312
25500
  bounds,
25313
25501
  elements
25314
25502
  });
25315
- const texture = new THREE34.CanvasTexture(canvas);
25503
+ const texture = new THREE35.CanvasTexture(canvas);
25316
25504
  texture.generateMipmaps = true;
25317
- texture.minFilter = THREE34.LinearMipmapLinearFilter;
25318
- texture.magFilter = THREE34.LinearFilter;
25505
+ texture.minFilter = THREE35.LinearMipmapLinearFilter;
25506
+ texture.magFilter = THREE35.LinearFilter;
25319
25507
  texture.anisotropy = 16;
25320
25508
  texture.needsUpdate = true;
25321
25509
  return texture;
25322
25510
  }
25323
25511
 
25324
25512
  // src/textures/create-keepout-texture-for-layer.ts
25325
- import * as THREE35 from "three";
25513
+ import * as THREE36 from "three";
25326
25514
 
25327
25515
  // src/textures/keepout/keepout-drawing.ts
25328
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
25516
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer7 } from "circuit-to-canvas";
25329
25517
  var setDrawerBounds3 = (drawer, bounds) => {
25330
25518
  drawer.setCameraBounds({
25331
25519
  minX: bounds.minX,
@@ -25342,7 +25530,7 @@ var drawKeepoutLayer = ({
25342
25530
  keepoutColor
25343
25531
  }) => {
25344
25532
  const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25345
- const drawer = new CircuitToCanvasDrawer6(ctx);
25533
+ const drawer = new CircuitToCanvasDrawer7(ctx);
25346
25534
  drawer.configure({
25347
25535
  colorOverrides: {
25348
25536
  keepout: {
@@ -25397,20 +25585,20 @@ function createKeepoutTextureForLayer({
25397
25585
  elements,
25398
25586
  keepoutColor
25399
25587
  });
25400
- const texture = new THREE35.CanvasTexture(canvas);
25588
+ const texture = new THREE36.CanvasTexture(canvas);
25401
25589
  texture.generateMipmaps = true;
25402
- texture.minFilter = THREE35.LinearMipmapLinearFilter;
25403
- texture.magFilter = THREE35.LinearFilter;
25590
+ texture.minFilter = THREE36.LinearMipmapLinearFilter;
25591
+ texture.magFilter = THREE36.LinearFilter;
25404
25592
  texture.anisotropy = 16;
25405
25593
  texture.needsUpdate = true;
25406
25594
  return texture;
25407
25595
  }
25408
25596
 
25409
25597
  // src/textures/create-pcb-note-texture-for-layer.ts
25410
- import * as THREE36 from "three";
25598
+ import * as THREE37 from "three";
25411
25599
 
25412
25600
  // src/textures/pcb-note/pcb-note-drawing.ts
25413
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer7 } from "circuit-to-canvas";
25601
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer8 } from "circuit-to-canvas";
25414
25602
  var TRANSPARENT2 = "rgba(0,0,0,0)";
25415
25603
  var setDrawerBounds4 = (drawer, bounds) => {
25416
25604
  drawer.setCameraBounds({
@@ -25489,7 +25677,7 @@ var drawPcbNoteLayer = ({
25489
25677
  elements
25490
25678
  }) => {
25491
25679
  const normalizedElements = elements.map(normalizePcbNoteElement);
25492
- const drawer = new CircuitToCanvasDrawer7(ctx);
25680
+ const drawer = new CircuitToCanvasDrawer8(ctx);
25493
25681
  drawer.configure({
25494
25682
  colorOverrides: {
25495
25683
  copper: {
@@ -25561,20 +25749,20 @@ function createPcbNoteTextureForLayer({
25561
25749
  bounds,
25562
25750
  elements
25563
25751
  });
25564
- const texture = new THREE36.CanvasTexture(canvas);
25752
+ const texture = new THREE37.CanvasTexture(canvas);
25565
25753
  texture.generateMipmaps = true;
25566
- texture.minFilter = THREE36.LinearMipmapLinearFilter;
25567
- texture.magFilter = THREE36.LinearFilter;
25754
+ texture.minFilter = THREE37.LinearMipmapLinearFilter;
25755
+ texture.magFilter = THREE37.LinearFilter;
25568
25756
  texture.anisotropy = 16;
25569
25757
  texture.needsUpdate = true;
25570
25758
  return texture;
25571
25759
  }
25572
25760
 
25573
25761
  // src/textures/create-silkscreen-texture-for-layer.ts
25574
- import * as THREE37 from "three";
25762
+ import * as THREE38 from "three";
25575
25763
 
25576
25764
  // src/textures/silkscreen/silkscreen-drawing.ts
25577
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer8 } from "circuit-to-canvas";
25765
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer9 } from "circuit-to-canvas";
25578
25766
  var FABRICATION_NOTE_COLOR2 = "rgb(255,243,204)";
25579
25767
  var TRANSPARENT3 = "rgba(0,0,0,0)";
25580
25768
  var isViaTented = (via, layer, board) => {
@@ -25611,7 +25799,7 @@ var drawSilkscreenLayer = ({
25611
25799
  soldermaskVisible
25612
25800
  }) => {
25613
25801
  const renderLayer = layer === "top" ? "top_silkscreen" : "bottom_silkscreen";
25614
- const drawer = new CircuitToCanvasDrawer8(ctx);
25802
+ const drawer = new CircuitToCanvasDrawer9(ctx);
25615
25803
  drawer.configure({
25616
25804
  colorOverrides: {
25617
25805
  copper: {
@@ -25722,21 +25910,21 @@ function createSilkscreenTextureForLayer({
25722
25910
  silkscreenColor,
25723
25911
  soldermaskVisible
25724
25912
  });
25725
- const texture = new THREE37.CanvasTexture(canvas);
25913
+ const texture = new THREE38.CanvasTexture(canvas);
25726
25914
  texture.generateMipmaps = true;
25727
- texture.minFilter = THREE37.LinearMipmapLinearFilter;
25728
- texture.magFilter = THREE37.LinearFilter;
25915
+ texture.minFilter = THREE38.LinearMipmapLinearFilter;
25916
+ texture.magFilter = THREE38.LinearFilter;
25729
25917
  texture.anisotropy = 16;
25730
25918
  texture.needsUpdate = true;
25731
25919
  return texture;
25732
25920
  }
25733
25921
 
25734
25922
  // src/textures/create-soldermask-texture-for-layer.ts
25735
- import * as THREE39 from "three";
25923
+ import * as THREE40 from "three";
25736
25924
 
25737
25925
  // src/textures/soldermask/soldermask-drawing.ts
25738
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer9 } from "circuit-to-canvas";
25739
- import * as THREE38 from "three";
25926
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer10 } from "circuit-to-canvas";
25927
+ import * as THREE39 from "three";
25740
25928
  var toRgb2 = (colorArr) => {
25741
25929
  const [r = 0, g = 0, b = 0] = colorArr;
25742
25930
  return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(
@@ -25759,11 +25947,11 @@ var getSoldermaskPalette = (boardData) => {
25759
25947
  transparent: "rgba(0,0,0,0)"
25760
25948
  };
25761
25949
  }
25762
- const copperColor = new THREE38.Color().setRGB(
25950
+ const copperColor = new THREE39.Color().setRGB(
25763
25951
  colors.copper[0],
25764
25952
  colors.copper[1],
25765
25953
  colors.copper[2],
25766
- THREE38.SRGBColorSpace
25954
+ THREE39.SRGBColorSpace
25767
25955
  );
25768
25956
  return {
25769
25957
  soldermask: soldermaskColorToCss(requestedSoldermaskColor),
@@ -25798,7 +25986,7 @@ var drawSoldermaskLayer = ({
25798
25986
  }) => {
25799
25987
  const palette = getSoldermaskPalette(boardData);
25800
25988
  const copperRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25801
- const drawer = new CircuitToCanvasDrawer9(ctx);
25989
+ const drawer = new CircuitToCanvasDrawer10(ctx);
25802
25990
  drawer.configure({
25803
25991
  colorOverrides: {
25804
25992
  copper: {
@@ -25847,7 +26035,7 @@ var drawSoldermaskLayer = ({
25847
26035
  if (uncoveredPours.length > 0) {
25848
26036
  ctx.save();
25849
26037
  ctx.globalCompositeOperation = "destination-out";
25850
- const cutoutDrawer = new CircuitToCanvasDrawer9(ctx);
26038
+ const cutoutDrawer = new CircuitToCanvasDrawer10(ctx);
25851
26039
  cutoutDrawer.configure({
25852
26040
  colorOverrides: {
25853
26041
  copper: {
@@ -25898,20 +26086,20 @@ function createSoldermaskTextureForLayer({
25898
26086
  elements,
25899
26087
  boardData
25900
26088
  });
25901
- const texture = new THREE39.CanvasTexture(canvas);
26089
+ const texture = new THREE40.CanvasTexture(canvas);
25902
26090
  texture.generateMipmaps = true;
25903
- texture.minFilter = THREE39.LinearMipmapLinearFilter;
25904
- texture.magFilter = THREE39.LinearFilter;
26091
+ texture.minFilter = THREE40.LinearMipmapLinearFilter;
26092
+ texture.magFilter = THREE40.LinearFilter;
25905
26093
  texture.anisotropy = 16;
25906
26094
  texture.needsUpdate = true;
25907
26095
  return texture;
25908
26096
  }
25909
26097
 
25910
26098
  // src/textures/create-through-hole-texture-for-layer.ts
25911
- import * as THREE40 from "three";
26099
+ import * as THREE41 from "three";
25912
26100
 
25913
26101
  // src/textures/through-hole/through-hole-drawing.ts
25914
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer10 } from "circuit-to-canvas";
26102
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer11 } from "circuit-to-canvas";
25915
26103
  var setDrawerBounds7 = (drawer, bounds) => {
25916
26104
  drawer.setCameraBounds({
25917
26105
  minX: bounds.minX,
@@ -25929,7 +26117,7 @@ var drawThroughHoleLayer = ({
25929
26117
  }) => {
25930
26118
  const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25931
26119
  const transparent = "rgba(0,0,0,0)";
25932
- const drawer = new CircuitToCanvasDrawer10(ctx);
26120
+ const drawer = new CircuitToCanvasDrawer11(ctx);
25933
26121
  drawer.configure({
25934
26122
  colorOverrides: {
25935
26123
  copper: {
@@ -26003,10 +26191,10 @@ function createThroughHoleTextureForLayer({
26003
26191
  elements,
26004
26192
  copperColor
26005
26193
  });
26006
- const texture = new THREE40.CanvasTexture(canvas);
26194
+ const texture = new THREE41.CanvasTexture(canvas);
26007
26195
  texture.generateMipmaps = true;
26008
- texture.minFilter = THREE40.LinearMipmapLinearFilter;
26009
- texture.magFilter = THREE40.LinearFilter;
26196
+ texture.minFilter = THREE41.LinearMipmapLinearFilter;
26197
+ texture.magFilter = THREE41.LinearFilter;
26010
26198
  texture.anisotropy = 16;
26011
26199
  texture.needsUpdate = true;
26012
26200
  return texture;
@@ -26069,7 +26257,8 @@ var createCombinedTexture = ({
26069
26257
  textures,
26070
26258
  boardData,
26071
26259
  traceTextureResolution,
26072
- layer
26260
+ layer,
26261
+ openViaHoles
26073
26262
  }) => {
26074
26263
  const hasImage = textures.some((texture) => texture?.image);
26075
26264
  if (!hasImage) return null;
@@ -26091,13 +26280,21 @@ var createCombinedTexture = ({
26091
26280
  const image = texture.image;
26092
26281
  ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
26093
26282
  }
26283
+ clearViaHolesFromSurface({
26284
+ ctx,
26285
+ vias: openViaHoles,
26286
+ boardData,
26287
+ layer,
26288
+ width: canvasWidth,
26289
+ height: canvasHeight
26290
+ });
26094
26291
  applySoldermaskSurfaceFilter(ctx, canvasWidth, canvasHeight, {
26095
26292
  includeReflection: layer === "top"
26096
26293
  });
26097
- const combinedTexture = new THREE41.CanvasTexture(canvas);
26294
+ const combinedTexture = new THREE42.CanvasTexture(canvas);
26098
26295
  combinedTexture.generateMipmaps = false;
26099
- combinedTexture.minFilter = THREE41.LinearFilter;
26100
- combinedTexture.magFilter = THREE41.LinearFilter;
26296
+ combinedTexture.minFilter = THREE42.LinearFilter;
26297
+ combinedTexture.magFilter = THREE42.LinearFilter;
26101
26298
  combinedTexture.premultiplyAlpha = true;
26102
26299
  combinedTexture.anisotropy = 16;
26103
26300
  combinedTexture.needsUpdate = true;
@@ -26133,11 +26330,11 @@ var createMaskedCopperMask = ({
26133
26330
  height
26134
26331
  );
26135
26332
  ctx.globalCompositeOperation = "source-over";
26136
- const maskTexture = new THREE41.CanvasTexture(canvas);
26137
- maskTexture.colorSpace = THREE41.NoColorSpace;
26333
+ const maskTexture = new THREE42.CanvasTexture(canvas);
26334
+ maskTexture.colorSpace = THREE42.NoColorSpace;
26138
26335
  maskTexture.generateMipmaps = false;
26139
- maskTexture.minFilter = THREE41.LinearFilter;
26140
- maskTexture.magFilter = THREE41.LinearFilter;
26336
+ maskTexture.minFilter = THREE42.LinearFilter;
26337
+ maskTexture.magFilter = THREE42.LinearFilter;
26141
26338
  maskTexture.premultiplyAlpha = false;
26142
26339
  maskTexture.needsUpdate = true;
26143
26340
  return maskTexture;
@@ -26152,6 +26349,11 @@ function createCombinedBoardTextures({
26152
26349
  const silkscreenColor = "rgb(255,255,255)";
26153
26350
  const copperColor = toRgb3(colors.copper);
26154
26351
  const showBoardBody = visibility?.boardBody ?? true;
26352
+ const openViaHoles = getViaHolesAtExposedPads(
26353
+ circuitJson,
26354
+ boardData,
26355
+ traceTextureResolution
26356
+ );
26155
26357
  const buildForLayer = (layer) => {
26156
26358
  const showMask = (layer === "top" ? visibility?.topMask : visibility?.bottomMask) ?? true;
26157
26359
  const showCopper = (layer === "top" ? visibility?.topCopper : visibility?.bottomCopper) ?? true;
@@ -26240,6 +26442,7 @@ function createCombinedBoardTextures({
26240
26442
  traceTextureResolution
26241
26443
  }) : null;
26242
26444
  const boardTexture = createCombinedTexture({
26445
+ openViaHoles,
26243
26446
  textures: [
26244
26447
  copperPourTexture,
26245
26448
  traceTexture,
@@ -26277,7 +26480,7 @@ function createCombinedBoardTextures({
26277
26480
  }
26278
26481
 
26279
26482
  // src/textures/create-three-texture-meshes.ts
26280
- import * as THREE43 from "three";
26483
+ import * as THREE44 from "three";
26281
26484
 
26282
26485
  // src/board-surface-textures.ts
26283
26486
  var REALISTIC_BOARD_SURFACE_MATERIAL = {
@@ -26300,7 +26503,7 @@ var PAD_COPPER_TEXTURE_MATERIAL = {
26300
26503
  };
26301
26504
 
26302
26505
  // src/utils/create-board-relief-textures.ts
26303
- import * as THREE42 from "three";
26506
+ import * as THREE43 from "three";
26304
26507
  var PLAIN_SOLDERMASK_HEIGHT = 0.22;
26305
26508
  var MASKED_COPPER_HEIGHT = 0.7;
26306
26509
  var EXPOSED_COPPER_HEIGHT = 0.86;
@@ -26395,13 +26598,13 @@ var getBoardSurfaceProfile = (r, g, b, hasMaskedCopper) => {
26395
26598
  return PLAIN_SOLDERMASK_PROFILE;
26396
26599
  };
26397
26600
  var createDataTexture = (canvas) => {
26398
- const texture = new THREE42.CanvasTexture(canvas);
26399
- texture.colorSpace = THREE42.NoColorSpace;
26601
+ const texture = new THREE43.CanvasTexture(canvas);
26602
+ texture.colorSpace = THREE43.NoColorSpace;
26400
26603
  texture.generateMipmaps = false;
26401
- texture.minFilter = THREE42.LinearFilter;
26402
- texture.magFilter = THREE42.LinearFilter;
26403
- texture.wrapS = THREE42.ClampToEdgeWrapping;
26404
- texture.wrapT = THREE42.ClampToEdgeWrapping;
26604
+ texture.minFilter = THREE43.LinearFilter;
26605
+ texture.magFilter = THREE43.LinearFilter;
26606
+ texture.wrapS = THREE43.ClampToEdgeWrapping;
26607
+ texture.wrapT = THREE43.ClampToEdgeWrapping;
26405
26608
  texture.needsUpdate = true;
26406
26609
  return texture;
26407
26610
  };
@@ -26525,16 +26728,16 @@ function createTexturePlane(config, boardData) {
26525
26728
  } = config;
26526
26729
  if (!texture) return null;
26527
26730
  const boardOutlineBounds = calculateOutlineBounds(boardData);
26528
- const planeGeom = new THREE43.PlaneGeometry(
26731
+ const planeGeom = new THREE44.PlaneGeometry(
26529
26732
  boardOutlineBounds.width,
26530
26733
  boardOutlineBounds.height
26531
26734
  );
26532
- texture.colorSpace = THREE43.SRGBColorSpace;
26735
+ texture.colorSpace = THREE44.SRGBColorSpace;
26533
26736
  const sharedMaterialOptions = {
26534
26737
  map: texture,
26535
26738
  transparent: true,
26536
26739
  alphaTest: 0.08,
26537
- side: THREE43.FrontSide,
26740
+ side: THREE44.FrontSide,
26538
26741
  depthWrite: true,
26539
26742
  polygonOffset: usePolygonOffset,
26540
26743
  polygonOffsetFactor: usePolygonOffset ? -4 : 0,
@@ -26543,12 +26746,12 @@ function createTexturePlane(config, boardData) {
26543
26746
  opacity: isFaux ? FAUX_BOARD_OPACITY : 1
26544
26747
  };
26545
26748
  const reliefTextures = createBoardReliefTextures(texture, maskedCopperMask);
26546
- const material = new THREE43.MeshPhysicalMaterial({
26749
+ const material = new THREE44.MeshPhysicalMaterial({
26547
26750
  ...sharedMaterialOptions,
26548
26751
  bumpMap: reliefTextures?.bumpMap ?? null,
26549
26752
  bumpScale: REALISTIC_BOARD_SURFACE_MATERIAL.bumpScale,
26550
26753
  normalMap: reliefTextures?.normalMap ?? null,
26551
- normalScale: new THREE43.Vector2(
26754
+ normalScale: new THREE44.Vector2(
26552
26755
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale,
26553
26756
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale
26554
26757
  ),
@@ -26562,7 +26765,7 @@ function createTexturePlane(config, boardData) {
26562
26765
  clearcoatRoughness: REALISTIC_BOARD_SURFACE_MATERIAL.clearcoatRoughness,
26563
26766
  envMapIntensity: 0.18
26564
26767
  });
26565
- const mesh = new THREE43.Mesh(planeGeom, material);
26768
+ const mesh = new THREE44.Mesh(planeGeom, material);
26566
26769
  mesh.position.set(
26567
26770
  boardOutlineBounds.centerX,
26568
26771
  boardOutlineBounds.centerY,
@@ -26610,7 +26813,7 @@ function createTextureMeshes(textures, boardData, pcbThickness, isFaux = false)
26610
26813
  }
26611
26814
 
26612
26815
  // src/three-components/JscadBoardTextures.tsx
26613
- import * as THREE44 from "three";
26816
+ import * as THREE45 from "three";
26614
26817
 
26615
26818
  // src/hooks/useBoardTextureVisibility.ts
26616
26819
  import { useMemo as useMemo20 } from "react";
@@ -26748,7 +26951,7 @@ function JscadBoardTextures({
26748
26951
  const typedMaterial = material;
26749
26952
  for (const prop of textureProps) {
26750
26953
  const texture = typedMaterial[prop];
26751
- if (texture && texture instanceof THREE44.Texture) {
26954
+ if (texture && texture instanceof THREE45.Texture) {
26752
26955
  texture.dispose();
26753
26956
  typedMaterial[prop] = null;
26754
26957
  }
@@ -26767,16 +26970,16 @@ function JscadBoardTextures({
26767
26970
  }) => {
26768
26971
  if (!texture) return null;
26769
26972
  const boardOutlineBounds = calculateOutlineBounds(boardData);
26770
- const planeGeom = new THREE44.PlaneGeometry(
26973
+ const planeGeom = new THREE45.PlaneGeometry(
26771
26974
  boardOutlineBounds.width,
26772
26975
  boardOutlineBounds.height
26773
26976
  );
26774
- texture.colorSpace = THREE44.SRGBColorSpace;
26977
+ texture.colorSpace = THREE45.SRGBColorSpace;
26775
26978
  const sharedMaterialOptions = {
26776
26979
  map: texture,
26777
26980
  transparent: true,
26778
26981
  alphaTest: 0.08,
26779
- side: THREE44.FrontSide,
26982
+ side: THREE45.FrontSide,
26780
26983
  depthWrite,
26781
26984
  polygonOffset: usePolygonOffset,
26782
26985
  polygonOffsetFactor: usePolygonOffset ? -4 : 0,
@@ -26787,12 +26990,12 @@ function JscadBoardTextures({
26787
26990
  texture,
26788
26991
  maskedCopperMask
26789
26992
  );
26790
- const material = new THREE44.MeshPhysicalMaterial({
26993
+ const material = new THREE45.MeshPhysicalMaterial({
26791
26994
  ...sharedMaterialOptions,
26792
26995
  bumpMap: reliefTextures?.bumpMap ?? null,
26793
26996
  bumpScale: REALISTIC_BOARD_SURFACE_MATERIAL.bumpScale,
26794
26997
  normalMap: reliefTextures?.normalMap ?? null,
26795
- normalScale: new THREE44.Vector2(
26998
+ normalScale: new THREE45.Vector2(
26796
26999
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale,
26797
27000
  REALISTIC_BOARD_SURFACE_MATERIAL.normalScale
26798
27001
  ),
@@ -26804,7 +27007,7 @@ function JscadBoardTextures({
26804
27007
  clearcoatRoughness: REALISTIC_BOARD_SURFACE_MATERIAL.clearcoatRoughness,
26805
27008
  envMapIntensity: 0.18
26806
27009
  });
26807
- const mesh = new THREE44.Mesh(planeGeom, material);
27010
+ const mesh = new THREE45.Mesh(planeGeom, material);
26808
27011
  mesh.position.set(
26809
27012
  boardOutlineBounds.centerX,
26810
27013
  boardOutlineBounds.centerY,
@@ -26854,7 +27057,7 @@ function JscadBoardTextures({
26854
27057
  for (const material of mesh.material) {
26855
27058
  disposeTextureMaterial(material);
26856
27059
  }
26857
- } else if (mesh.material instanceof THREE44.Material) {
27060
+ } else if (mesh.material instanceof THREE45.Material) {
26858
27061
  disposeTextureMaterial(mesh.material);
26859
27062
  }
26860
27063
  }
@@ -26867,7 +27070,7 @@ function JscadBoardTextures({
26867
27070
 
26868
27071
  // src/three-components/STLModel.tsx
26869
27072
  import { useState as useState17, useEffect as useEffect27, useMemo as useMemo22 } from "react";
26870
- import * as THREE45 from "three";
27073
+ import * as THREE46 from "three";
26871
27074
  import { STLLoader } from "three-stdlib";
26872
27075
  function STLModel({
26873
27076
  stlUrl,
@@ -26900,15 +27103,15 @@ function STLModel({
26900
27103
  const mesh = useMemo22(() => {
26901
27104
  if (!geom) return null;
26902
27105
  const isBoardLayer = layerType === "board";
26903
- const material = new THREE45.MeshStandardMaterial({
26904
- color: Array.isArray(color) ? new THREE45.Color(color[0], color[1], color[2]) : color,
27106
+ const material = new THREE46.MeshStandardMaterial({
27107
+ color: Array.isArray(color) ? new THREE46.Color(color[0], color[1], color[2]) : color,
26905
27108
  transparent: opacity !== 1,
26906
27109
  opacity,
26907
27110
  polygonOffset: isBoardLayer,
26908
27111
  polygonOffsetFactor: isBoardLayer ? 6 : 0,
26909
27112
  polygonOffsetUnits: isBoardLayer ? 6 : 0
26910
27113
  });
26911
- const createdMesh = new THREE45.Mesh(geom, material);
27114
+ const createdMesh = new THREE46.Mesh(geom, material);
26912
27115
  createdMesh.renderOrder = isBoardLayer ? -1 : 1;
26913
27116
  configureObjectShadows(createdMesh, {
26914
27117
  castShadow: !isBoardLayer && opacity === 1,
@@ -26971,7 +27174,7 @@ function VisibleSTLModel({
26971
27174
  import { parseCableString } from "@tscircuit/cableprinter";
26972
27175
  import { createCableMeshes } from "jscad-electronics/cables";
26973
27176
  import { useEffect as useEffect28, useMemo as useMemo23 } from "react";
26974
- import * as THREE46 from "three";
27177
+ import * as THREE47 from "three";
26975
27178
  var isCadCableElement = (element) => {
26976
27179
  if (!element || typeof element !== "object") return false;
26977
27180
  const candidate = element;
@@ -26988,14 +27191,14 @@ var getConnectorPin1Side = ({
26988
27191
  const endpoint = end === "start" ? path[0] : path[path.length - 1];
26989
27192
  const adjacent = end === "start" ? path[1] : path[path.length - 2];
26990
27193
  if (!endpoint || !adjacent) return void 0;
26991
- const cableAxis = new THREE46.Vector3(
27194
+ const cableAxis = new THREE47.Vector3(
26992
27195
  adjacent.x - endpoint.x,
26993
27196
  adjacent.y - endpoint.y,
26994
27197
  adjacent.z - endpoint.z
26995
27198
  );
26996
27199
  if (cableAxis.lengthSq() < 1e-12) return void 0;
26997
27200
  cableAxis.normalize();
26998
- const pin1Side = new THREE46.Vector3(
27201
+ const pin1Side = new THREE47.Vector3(
26999
27202
  pin1Position.x - endpoint.x,
27000
27203
  pin1Position.y - endpoint.y,
27001
27204
  pin1Position.z - endpoint.z
@@ -27021,28 +27224,28 @@ var createCadCableObject = (cable) => {
27021
27224
  end: "end"
27022
27225
  })
27023
27226
  });
27024
- const group = new THREE46.Group();
27227
+ const group = new THREE47.Group();
27025
27228
  group.name = `cad-cable-${cable.cad_cable_id}`;
27026
27229
  group.userData = { cadCableId: cable.cad_cable_id, name: cable.name };
27027
27230
  for (const cableMesh of cableMeshes) {
27028
- let geometry = new THREE46.BufferGeometry();
27231
+ let geometry = new THREE47.BufferGeometry();
27029
27232
  geometry.setAttribute(
27030
27233
  "position",
27031
- new THREE46.Float32BufferAttribute(cableMesh.positions, 3)
27234
+ new THREE47.Float32BufferAttribute(cableMesh.positions, 3)
27032
27235
  );
27033
27236
  geometry.setIndex(cableMesh.indices);
27034
27237
  if (!cableMesh.smooth) geometry = geometry.toNonIndexed();
27035
27238
  geometry.computeVertexNormals();
27036
27239
  const [red, green, blue, alpha] = cableMesh.color;
27037
- const material = new THREE46.MeshStandardMaterial({
27038
- color: new THREE46.Color(red, green, blue),
27240
+ const material = new THREE47.MeshStandardMaterial({
27241
+ color: new THREE47.Color(red, green, blue),
27039
27242
  metalness: cableMesh.material?.metalness ?? 0,
27040
27243
  roughness: cableMesh.material?.roughness ?? 0.7,
27041
27244
  opacity: alpha,
27042
27245
  transparent: alpha < 1,
27043
- side: THREE46.DoubleSide
27246
+ side: THREE47.DoubleSide
27044
27247
  });
27045
- const mesh = new THREE46.Mesh(geometry, material);
27248
+ const mesh = new THREE47.Mesh(geometry, material);
27046
27249
  mesh.name = `${group.name}:${cableMesh.name}`;
27047
27250
  configureObjectShadows(mesh, { castShadow: true, receiveShadow: true });
27048
27251
  group.add(mesh);
@@ -27051,7 +27254,7 @@ var createCadCableObject = (cable) => {
27051
27254
  };
27052
27255
  var disposeCadCableObject = (group) => {
27053
27256
  group.traverse((object) => {
27054
- if (!(object instanceof THREE46.Mesh)) return;
27257
+ if (!(object instanceof THREE47.Mesh)) return;
27055
27258
  object.geometry.dispose();
27056
27259
  const materials = Array.isArray(object.material) ? object.material : [object.material];
27057
27260
  for (const material of materials) material.dispose();
@@ -28291,7 +28494,7 @@ function createStiffenerMesh({
28291
28494
  }
28292
28495
 
28293
28496
  // src/utils/flex-meshes.ts
28294
- import * as THREE47 from "three";
28497
+ import * as THREE48 from "three";
28295
28498
  function meshToSurface(mesh, center) {
28296
28499
  mesh.updateMatrix();
28297
28500
  const geometry = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry;
@@ -28299,11 +28502,11 @@ function meshToSurface(mesh, center) {
28299
28502
  const triangles = [];
28300
28503
  for (let i = 0; i < position.count; i += 3) {
28301
28504
  const vertices = [0, 1, 2].map((j) => {
28302
- const v = new THREE47.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
28505
+ const v = new THREE48.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
28303
28506
  return { x: v.x - center.x, y: v.y - center.y, z: v.z };
28304
28507
  });
28305
28508
  const [a, b, c] = vertices;
28306
- const n = new THREE47.Vector3(b.x - a.x, b.y - a.y, b.z - a.z).cross(new THREE47.Vector3(c.x - a.x, c.y - a.y, c.z - a.z)).normalize();
28509
+ const n = new THREE48.Vector3(b.x - a.x, b.y - a.y, b.z - a.z).cross(new THREE48.Vector3(c.x - a.x, c.y - a.y, c.z - a.z)).normalize();
28307
28510
  triangles.push({
28308
28511
  vertices,
28309
28512
  normal: { x: n.x, y: n.y, z: n.z },
@@ -28326,13 +28529,13 @@ function surfaceToGeometry(surface, center) {
28326
28529
  normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
28327
28530
  uvs.push(triangle.uvs?.[i]?.u ?? 0, triangle.uvs?.[i]?.v ?? 0);
28328
28531
  });
28329
- const geometry = new THREE47.BufferGeometry();
28532
+ const geometry = new THREE48.BufferGeometry();
28330
28533
  geometry.setAttribute(
28331
28534
  "position",
28332
- new THREE47.Float32BufferAttribute(positions, 3)
28535
+ new THREE48.Float32BufferAttribute(positions, 3)
28333
28536
  );
28334
- geometry.setAttribute("normal", new THREE47.Float32BufferAttribute(normals, 3));
28335
- geometry.setAttribute("uv", new THREE47.Float32BufferAttribute(uvs, 2));
28537
+ geometry.setAttribute("normal", new THREE48.Float32BufferAttribute(normals, 3));
28538
+ geometry.setAttribute("uv", new THREE48.Float32BufferAttribute(uvs, 2));
28336
28539
  geometry.computeBoundingBox();
28337
28540
  geometry.computeBoundingSphere();
28338
28541
  return geometry;
@@ -28377,7 +28580,7 @@ function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
28377
28580
  z: mesh.position.z
28378
28581
  }));
28379
28582
  const uvs = vertices.map((p) => {
28380
- const local = new THREE47.Vector3(
28583
+ const local = new THREE48.Vector3(
28381
28584
  p.x + board.center.x,
28382
28585
  p.y + board.center.y,
28383
28586
  p.z
@@ -28401,7 +28604,7 @@ function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
28401
28604
  return result;
28402
28605
  }) : textureMeshes;
28403
28606
  for (const stiffener of stiffeners) {
28404
- const mesh = new THREE47.Mesh(
28607
+ const mesh = new THREE48.Mesh(
28405
28608
  surfaceToGeometry(
28406
28609
  createStiffenerMesh({
28407
28610
  stiffener,
@@ -28410,16 +28613,16 @@ function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
28410
28613
  }),
28411
28614
  board.center
28412
28615
  ),
28413
- new THREE47.MeshStandardMaterial({
28616
+ new THREE48.MeshStandardMaterial({
28414
28617
  color: stiffener.material === "fr4" ? "#879568" : stiffener.material === "polyimide" ? "#bd7f27" : "#b8bdc4",
28415
- side: THREE47.DoubleSide
28618
+ side: THREE48.DoubleSide
28416
28619
  })
28417
28620
  );
28418
28621
  mesh.name = "board-stiffener";
28419
28622
  configureObjectShadows(mesh);
28420
28623
  geometry.push(mesh);
28421
28624
  }
28422
- const bounds = new THREE47.Box3();
28625
+ const bounds = new THREE48.Box3();
28423
28626
  for (const mesh of [...geometry, ...textures]) bounds.expandByObject(mesh);
28424
28627
  return {
28425
28628
  geometryMeshes: geometry,
@@ -28438,12 +28641,12 @@ function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
28438
28641
  // src/CadViewerManifold.tsx
28439
28642
  import { su as su17 } from "@tscircuit/circuit-json-util";
28440
28643
  import { useEffect as useEffect30, useMemo as useMemo26, useState as useState19 } from "react";
28441
- import * as THREE54 from "three";
28644
+ import * as THREE55 from "three";
28442
28645
 
28443
28646
  // src/hooks/useManifoldBoardBuilder.ts
28444
28647
  import { su as su16 } from "@tscircuit/circuit-json-util";
28445
28648
  import { useEffect as useEffect29, useMemo as useMemo25, useRef as useRef9, useState as useState18 } from "react";
28446
- import * as THREE51 from "three";
28649
+ import * as THREE52 from "three";
28447
28650
 
28448
28651
  // src/utils/manifold/create-manifold-board.ts
28449
28652
  var arePointsClockwise2 = (points) => {
@@ -28792,17 +28995,17 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
28792
28995
 
28793
28996
  // src/utils/manifold/process-plated-holes.ts
28794
28997
  import { su as su15 } from "@tscircuit/circuit-json-util";
28795
- import * as THREE49 from "three";
28998
+ import * as THREE50 from "three";
28796
28999
 
28797
29000
  // src/utils/manifold-mesh-to-three-geometry.ts
28798
- import * as THREE48 from "three";
29001
+ import * as THREE49 from "three";
28799
29002
  function manifoldMeshToThreeGeometry(manifoldMesh) {
28800
- const geometry = new THREE48.BufferGeometry();
29003
+ const geometry = new THREE49.BufferGeometry();
28801
29004
  geometry.setAttribute(
28802
29005
  "position",
28803
- new THREE48.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
29006
+ new THREE49.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
28804
29007
  );
28805
- geometry.setIndex(new THREE48.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
29008
+ geometry.setIndex(new THREE49.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
28806
29009
  if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
28807
29010
  for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
28808
29011
  const start = manifoldMesh.runIndex[i];
@@ -28836,7 +29039,7 @@ var createEllipsePoints = (width, height, segments) => {
28836
29039
  }
28837
29040
  return points;
28838
29041
  };
28839
- var COPPER_COLOR = new THREE49.Color(...colors.copper);
29042
+ var COPPER_COLOR = new THREE50.Color(...colors.copper);
28840
29043
  var PLATED_HOLE_LIP_HEIGHT = 0.05;
28841
29044
  var PLATED_HOLE_PAD_THICKNESS = 3e-3;
28842
29045
  var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
@@ -29466,7 +29669,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
29466
29669
  }
29467
29670
 
29468
29671
  // src/utils/manifold/process-vias.ts
29469
- import * as THREE50 from "three";
29672
+ import * as THREE51 from "three";
29470
29673
 
29471
29674
  // src/utils/via-geoms.ts
29472
29675
  function createViaCopper2({
@@ -29504,12 +29707,14 @@ function createViaCopper2({
29504
29707
  }
29505
29708
 
29506
29709
  // src/utils/manifold/process-vias.ts
29507
- var COPPER_COLOR2 = new THREE50.Color(...colors.copper);
29508
- function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
29710
+ var COPPER_COLOR2 = new THREE51.Color(...colors.copper);
29711
+ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume, otherHoleDrills = []) {
29509
29712
  const viaBoardDrills = [];
29510
29713
  const pcbVias = getPcbVias(circuitJson);
29511
29714
  const viaCopperGeoms = [];
29715
+ const copperOps = [];
29512
29716
  pcbVias.forEach((via, index2) => {
29717
+ let ownDrill;
29513
29718
  if (typeof via.hole_diameter === "number") {
29514
29719
  const translatedDrill = createPlatedHoleDrill({
29515
29720
  Manifold,
@@ -29522,6 +29727,7 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
29522
29727
  });
29523
29728
  manifoldInstancesForCleanup.push(translatedDrill);
29524
29729
  viaBoardDrills.push(translatedDrill);
29730
+ ownDrill = translatedDrill;
29525
29731
  }
29526
29732
  if (typeof via.outer_diameter === "number" && typeof via.hole_diameter === "number") {
29527
29733
  const translatedViaCopper = createViaCopper2({
@@ -29544,14 +29750,36 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
29544
29750
  manifoldInstancesForCleanup.push(clipped);
29545
29751
  finalCopperOp = clipped;
29546
29752
  }
29547
- const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
29548
- viaCopperGeoms.push({
29753
+ copperOps.push({
29549
29754
  key: `via-${via.pcb_via_id || index2}`,
29550
- geometry: threeGeom,
29551
- color: COPPER_COLOR2
29755
+ copper: finalCopperOp,
29756
+ ownDrill
29552
29757
  });
29553
29758
  }
29554
29759
  });
29760
+ const drillBounds = [...otherHoleDrills, ...viaBoardDrills].map((drill) => ({
29761
+ drill,
29762
+ bounds: drill.boundingBox()
29763
+ }));
29764
+ for (const { key, copper, ownDrill } of copperOps) {
29765
+ const bounds = copper.boundingBox();
29766
+ const drills = drillBounds.filter(
29767
+ ({ drill, bounds: drillBounds2 }) => drill !== ownDrill && [0, 1, 2].every(
29768
+ (axis) => drillBounds2.min[axis] <= bounds.max[axis] && drillBounds2.max[axis] >= bounds.min[axis]
29769
+ )
29770
+ ).map(({ drill }) => drill);
29771
+ let cutCopper = copper;
29772
+ if (drills.length) {
29773
+ const drillUnion = Manifold.union(drills);
29774
+ cutCopper = copper.subtract(drillUnion);
29775
+ manifoldInstancesForCleanup.push(drillUnion, cutCopper);
29776
+ }
29777
+ viaCopperGeoms.push({
29778
+ key,
29779
+ geometry: manifoldMeshToThreeGeometry(cutCopper.getMesh()),
29780
+ color: COPPER_COLOR2
29781
+ });
29782
+ }
29555
29783
  return { viaBoardDrills, viaCopperGeoms };
29556
29784
  }
29557
29785
 
@@ -29705,7 +29933,8 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
29705
29933
  circuitJson,
29706
29934
  currentPcbThickness,
29707
29935
  manifoldInstancesForCleanup.current,
29708
- boardClipVolume
29936
+ boardClipVolume,
29937
+ allBoardDrills
29709
29938
  );
29710
29939
  allBoardDrills.push(...viaBoardDrills);
29711
29940
  currentGeoms.vias = viaCopperGeoms;
@@ -29726,7 +29955,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
29726
29955
  {
29727
29956
  key: "plated-holes-union",
29728
29957
  geometry: cutPlatedGeom,
29729
- color: new THREE51.Color(
29958
+ color: new THREE52.Color(
29730
29959
  colors.copper[0],
29731
29960
  colors.copper[1],
29732
29961
  colors.copper[2]
@@ -29796,11 +30025,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
29796
30025
  };
29797
30026
 
29798
30027
  // src/utils/manifold/create-three-geometry-meshes.ts
29799
- import * as THREE53 from "three";
30028
+ import * as THREE54 from "three";
29800
30029
 
29801
30030
  // src/utils/create-board-material.ts
29802
- import * as THREE52 from "three";
29803
- var DEFAULT_SIDE = THREE52.DoubleSide;
30031
+ import * as THREE53 from "three";
30032
+ var DEFAULT_SIDE = THREE53.DoubleSide;
29804
30033
  var createBoardMaterial = ({
29805
30034
  material,
29806
30035
  color,
@@ -29808,7 +30037,7 @@ var createBoardMaterial = ({
29808
30037
  isFaux = false
29809
30038
  }) => {
29810
30039
  if (material === "fr4") {
29811
- return new THREE52.MeshPhysicalMaterial({
30040
+ return new THREE53.MeshPhysicalMaterial({
29812
30041
  color,
29813
30042
  side,
29814
30043
  metalness: 0,
@@ -29826,7 +30055,7 @@ var createBoardMaterial = ({
29826
30055
  polygonOffsetUnits: 1
29827
30056
  });
29828
30057
  }
29829
- return new THREE52.MeshStandardMaterial({
30058
+ return new THREE53.MeshStandardMaterial({
29830
30059
  color,
29831
30060
  side,
29832
30061
  flatShading: true,
@@ -29845,12 +30074,12 @@ function createGeometryMeshes(geoms) {
29845
30074
  const meshes = [];
29846
30075
  if (!geoms) return meshes;
29847
30076
  if (geoms.board?.geometry) {
29848
- const mesh = new THREE53.Mesh(
30077
+ const mesh = new THREE54.Mesh(
29849
30078
  geoms.board.geometry,
29850
30079
  createBoardMaterial({
29851
30080
  material: geoms.board.material,
29852
30081
  color: geoms.board.color,
29853
- side: THREE53.DoubleSide,
30082
+ side: THREE54.DoubleSide,
29854
30083
  isFaux: geoms.board.isFaux
29855
30084
  })
29856
30085
  );
@@ -29861,11 +30090,11 @@ function createGeometryMeshes(geoms) {
29861
30090
  const createMeshesFromArray = (geomArray) => {
29862
30091
  if (geomArray) {
29863
30092
  for (const comp of geomArray) {
29864
- const mesh = new THREE53.Mesh(
30093
+ const mesh = new THREE54.Mesh(
29865
30094
  comp.geometry,
29866
- new THREE53.MeshStandardMaterial({
30095
+ new THREE54.MeshStandardMaterial({
29867
30096
  color: comp.color,
29868
- side: THREE53.DoubleSide,
30097
+ side: THREE54.DoubleSide,
29869
30098
  flatShading: true
29870
30099
  // Consistent with board
29871
30100
  })
@@ -29910,7 +30139,7 @@ var BoardMeshes = ({
29910
30139
  const typedMaterial = material;
29911
30140
  for (const prop of textureProps) {
29912
30141
  const texture = typedMaterial[prop];
29913
- if (texture && texture instanceof THREE54.Texture) {
30142
+ if (texture && texture instanceof THREE55.Texture) {
29914
30143
  texture.dispose();
29915
30144
  }
29916
30145
  }
@@ -30571,15 +30800,13 @@ function createSlot(ownerName) {
30571
30800
  let slottableElement = null;
30572
30801
  let hasSlottable = false;
30573
30802
  const newChildren = [];
30574
- if (isLazyComponent(children) && typeof use === "function") {
30575
- children = use(children._payload);
30576
- }
30803
+ children = useUnwrappedLazy(children);
30577
30804
  React16.Children.forEach(children, (maybeSlottable) => {
30578
30805
  if (isSlottable(maybeSlottable)) {
30579
30806
  hasSlottable = true;
30580
30807
  const slottable = maybeSlottable;
30581
30808
  let child = "child" in slottable.props ? slottable.props.child : slottable.props.children;
30582
- if (isLazyComponent(child) && typeof use === "function") {
30809
+ while (isLazyComponent(child) && typeof use === "function") {
30583
30810
  child = use(child._payload);
30584
30811
  }
30585
30812
  slottableElement = getSlottableElementFromSlottable(slottable, child);
@@ -30630,9 +30857,8 @@ function createSlottable(ownerName) {
30630
30857
  __name6(createSlottable, "createSlottable");
30631
30858
  var getSlottableElementFromSlottable = /* @__PURE__ */ __name6((slottable, child) => {
30632
30859
  if ("child" in slottable.props) {
30633
- const child2 = slottable.props.child;
30634
- if (!React16.isValidElement(child2)) return null;
30635
- return React16.cloneElement(child2, void 0, slottable.props.children(child2.props.children));
30860
+ if (!React16.isValidElement(child)) return null;
30861
+ return React16.cloneElement(child, void 0, slottable.props.children(child.props.children));
30636
30862
  }
30637
30863
  return React16.isValidElement(child) ? child : null;
30638
30864
  }, "getSlottableElementFromSlottable");
@@ -30690,6 +30916,14 @@ function isPromiseLike(value) {
30690
30916
  return typeof value === "object" && value !== null && "then" in value;
30691
30917
  }
30692
30918
  __name6(isPromiseLike, "isPromiseLike");
30919
+ function useUnwrappedLazy(value) {
30920
+ let unwrapped = value;
30921
+ while (isLazyComponent(unwrapped) && typeof use === "function") {
30922
+ unwrapped = use(unwrapped._payload);
30923
+ }
30924
+ return unwrapped;
30925
+ }
30926
+ __name6(useUnwrappedLazy, "useUnwrappedLazy");
30693
30927
  function concatAriaDescribedby(...values) {
30694
30928
  const ids = /* @__PURE__ */ new Set();
30695
30929
  for (const value of values) {
@@ -30837,54 +31071,37 @@ var OrderedDict = class _OrderedDict extends Map {
30837
31071
  __instanciated.set(this, true);
30838
31072
  }
30839
31073
  set(key, value) {
30840
- if (__instanciated.get(this)) {
30841
- if (this.has(key)) {
30842
- this.#keys[this.#keys.indexOf(key)] = key;
30843
- } else {
30844
- this.#keys.push(key);
30845
- }
31074
+ if (__instanciated.get(this) && !this.has(key)) {
31075
+ this.#keys.push(key);
30846
31076
  }
30847
31077
  super.set(key, value);
30848
31078
  return this;
30849
31079
  }
31080
+ /**
31081
+ * Sets a key-value pair so that it ends up at the given index.
31082
+ * - Existing keys are moved
31083
+ * - Negative indices count from the end of the resulting dictionary, so
31084
+ * inserting at -1 makes the item the last one, -2 the second to last, etc.
31085
+ * - Out-of-range indices are clamped
31086
+ */
30850
31087
  insert(index2, key, value) {
30851
31088
  const has = this.has(key);
30852
- const length6 = this.#keys.length;
31089
+ const finalSize = has ? this.size : this.size + 1;
30853
31090
  const relativeIndex = toSafeInteger(index2);
30854
- let actualIndex = relativeIndex >= 0 ? relativeIndex : length6 + relativeIndex;
30855
- const safeIndex = actualIndex < 0 || actualIndex >= length6 ? -1 : actualIndex;
30856
- if (safeIndex === this.size || has && safeIndex === this.size - 1 || safeIndex === -1) {
31091
+ const targetIndex = relativeIndex >= 0 ? Math.min(relativeIndex, finalSize - 1) : Math.max(finalSize + relativeIndex, 0);
31092
+ if (has ? this.#keys.indexOf(key) === targetIndex : targetIndex === this.size) {
30857
31093
  this.set(key, value);
30858
31094
  return this;
30859
31095
  }
30860
- const size4 = this.size + (has ? 0 : 1);
30861
- if (relativeIndex < 0) {
30862
- actualIndex++;
30863
- }
30864
- const keys = [...this.#keys];
30865
- let nextValue;
30866
- let shouldSkip = false;
30867
- for (let i = actualIndex; i < size4; i++) {
30868
- if (actualIndex === i) {
30869
- let nextKey = keys[i];
30870
- if (keys[i] === key) {
30871
- nextKey = keys[i + 1];
30872
- }
30873
- if (has) {
30874
- this.delete(key);
30875
- }
30876
- nextValue = this.get(nextKey);
30877
- this.set(key, value);
30878
- } else {
30879
- if (!shouldSkip && keys[i - 1] === key) {
30880
- shouldSkip = true;
30881
- }
30882
- const currentKey = keys[shouldSkip ? i : i - 1];
30883
- const currentValue = nextValue;
30884
- nextValue = this.get(currentKey);
30885
- this.delete(currentKey);
30886
- this.set(currentKey, currentValue);
30887
- }
31096
+ const keys = this.#keys.filter((existingKey) => existingKey !== key);
31097
+ keys.splice(targetIndex, 0, key);
31098
+ const entries = keys.map((entryKey) => [
31099
+ entryKey,
31100
+ entryKey === key ? value : this.get(entryKey)
31101
+ ]);
31102
+ this.clear();
31103
+ for (const [entryKey, entryValue] of entries) {
31104
+ this.set(entryKey, entryValue);
30888
31105
  }
30889
31106
  return this;
30890
31107
  }
@@ -30908,7 +31125,9 @@ var OrderedDict = class _OrderedDict extends Map {
30908
31125
  if (index2 === -1) {
30909
31126
  return this;
30910
31127
  }
30911
- return this.insert(index2, newKey, value);
31128
+ const currentIndex = this.#keys.indexOf(newKey);
31129
+ const targetIndex = currentIndex !== -1 && currentIndex < index2 ? index2 - 1 : index2;
31130
+ return this.insert(targetIndex, newKey, value);
30912
31131
  }
30913
31132
  after(key) {
30914
31133
  let index2 = this.#keys.indexOf(key);
@@ -30926,7 +31145,9 @@ var OrderedDict = class _OrderedDict extends Map {
30926
31145
  if (index2 === -1) {
30927
31146
  return this;
30928
31147
  }
30929
- return this.insert(index2 + 1, newKey, value);
31148
+ const currentIndex = this.#keys.indexOf(newKey);
31149
+ const targetIndex = currentIndex !== -1 && currentIndex <= index2 ? index2 : index2 + 1;
31150
+ return this.insert(targetIndex, newKey, value);
30930
31151
  }
30931
31152
  first() {
30932
31153
  return this.entryAt(0);
@@ -31032,10 +31253,14 @@ var OrderedDict = class _OrderedDict extends Map {
31032
31253
  }
31033
31254
  reduce(...args) {
31034
31255
  const [callbackfn, initialValue] = args;
31256
+ const hasInitialValue = args.length > 1;
31257
+ if (!hasInitialValue && this.size === 0) {
31258
+ throw new TypeError("Reduce of empty OrderedDict with no initial value");
31259
+ }
31035
31260
  let index2 = 0;
31036
- let accumulator = initialValue ?? this.at(0);
31261
+ let accumulator = initialValue;
31037
31262
  for (const entry of this) {
31038
- if (index2 === 0 && args.length === 1) {
31263
+ if (index2 === 0 && !hasInitialValue) {
31039
31264
  accumulator = entry;
31040
31265
  } else {
31041
31266
  accumulator = Reflect.apply(callbackfn, this, [accumulator, entry, index2, this]);
@@ -31046,10 +31271,14 @@ var OrderedDict = class _OrderedDict extends Map {
31046
31271
  }
31047
31272
  reduceRight(...args) {
31048
31273
  const [callbackfn, initialValue] = args;
31049
- let accumulator = initialValue ?? this.at(-1);
31274
+ const hasInitialValue = args.length > 1;
31275
+ if (!hasInitialValue && this.size === 0) {
31276
+ throw new TypeError("Reduce of empty OrderedDict with no initial value");
31277
+ }
31278
+ let accumulator = initialValue;
31050
31279
  for (let index2 = this.size - 1; index2 >= 0; index2--) {
31051
- const entry = this.at(index2);
31052
- if (index2 === this.size - 1 && args.length === 1) {
31280
+ const entry = this.entryAt(index2);
31281
+ if (index2 === this.size - 1 && !hasInitialValue) {
31053
31282
  accumulator = entry;
31054
31283
  } else {
31055
31284
  accumulator = Reflect.apply(callbackfn, this, [accumulator, entry, index2, this]);
@@ -31057,7 +31286,36 @@ var OrderedDict = class _OrderedDict extends Map {
31057
31286
  }
31058
31287
  return accumulator;
31059
31288
  }
31289
+ /**
31290
+ * Sorts the dictionary in place. This method mutates the dictionary and
31291
+ * returns a reference to the same object
31292
+ *
31293
+ * @param compareFn Function used to determine the order of the elements. It
31294
+ * is expected to return a negative value if the first argument is less than
31295
+ * the second argument, zero if they're equal, and a positive value otherwise.
31296
+ */
31297
+ sort(compareFn) {
31298
+ if (typeof compareFn !== "function") {
31299
+ throw new TypeError(`OrderedDict.sort requires a compare function`);
31300
+ }
31301
+ const entries = [...this.entries()].sort(compareFn);
31302
+ this.clear();
31303
+ for (const [key, value] of entries) {
31304
+ this.set(key, value);
31305
+ }
31306
+ return this;
31307
+ }
31308
+ /**
31309
+ * Returns a copy of the dictionary with its elements sorted.
31310
+ *
31311
+ * @param compareFn Function used to determine the order of the elements. It
31312
+ * is expected to return a negative value if the first argument is less than
31313
+ * the second argument, zero if they're equal, and a positive value otherwise.
31314
+ */
31060
31315
  toSorted(compareFn) {
31316
+ if (typeof compareFn !== "function") {
31317
+ throw new TypeError(`OrderedDict.toSorted requires a compare function`);
31318
+ }
31061
31319
  const entries = [...this.entries()].sort(compareFn);
31062
31320
  return new _OrderedDict(entries);
31063
31321
  }
@@ -31077,20 +31335,8 @@ var OrderedDict = class _OrderedDict extends Map {
31077
31335
  }
31078
31336
  slice(start, end) {
31079
31337
  const result = new _OrderedDict();
31080
- let stop = this.size - 1;
31081
- if (start === void 0) {
31082
- return result;
31083
- }
31084
- if (start < 0) {
31085
- start = start + this.size;
31086
- }
31087
- if (end !== void 0 && end > 0) {
31088
- stop = end - 1;
31089
- }
31090
- for (let index2 = start; index2 <= stop; index2++) {
31091
- const key = this.keyAt(index2);
31092
- const element = this.get(key);
31093
- result.set(key, element);
31338
+ for (const key of this.#keys.slice(start, end)) {
31339
+ result.set(key, this.get(key));
31094
31340
  }
31095
31341
  return result;
31096
31342
  }
@@ -31138,16 +31384,10 @@ __name8(toSafeInteger, "toSafeInteger");
31138
31384
  function createCollection2(name) {
31139
31385
  const PROVIDER_NAME = name + "CollectionProvider";
31140
31386
  const [createCollectionContext, createCollectionScope3] = createContextScope(PROVIDER_NAME);
31141
- const [CollectionContextProvider, useCollectionContext] = createCollectionContext(
31142
- PROVIDER_NAME,
31143
- {
31144
- collectionElement: null,
31145
- collectionRef: { current: null },
31146
- collectionRefObject: { current: null },
31147
- itemMap: new OrderedDict(),
31148
- setItemMap: /* @__PURE__ */ __name8(() => void 0, "setItemMap")
31149
- }
31150
- );
31387
+ const [CollectionStableContextProvider, useStableCollectionContext] = createCollectionContext(PROVIDER_NAME);
31388
+ CollectionStableContextProvider.displayName = name + "CollectionStableContextProvider";
31389
+ const [CollectionStatefulContextProvider, useStatefulCollectionContext] = createCollectionContext(PROVIDER_NAME);
31390
+ CollectionStatefulContextProvider.displayName = name + "CollectionStatefulContextProvider";
31151
31391
  const CollectionProvider = /* @__PURE__ */ __name8(({ state, ...props }) => {
31152
31392
  return state ? /* @__PURE__ */ jsx23(CollectionProviderImpl, { ...props, state }) : /* @__PURE__ */ jsx23(CollectionInit, { ...props });
31153
31393
  }, "CollectionProvider");
@@ -31156,7 +31396,7 @@ function createCollection2(name) {
31156
31396
  const state = useInitCollection();
31157
31397
  return /* @__PURE__ */ jsx23(CollectionProviderImpl, { ...props, state });
31158
31398
  }, "CollectionInit");
31159
- CollectionInit.displayName = PROVIDER_NAME + "Init";
31399
+ CollectionInit.displayName = name + "CollectionInit";
31160
31400
  const CollectionProviderImpl = /* @__PURE__ */ __name8((props) => {
31161
31401
  const { scope, children, state } = props;
31162
31402
  const ref = React23.useRef(null);
@@ -31164,10 +31404,27 @@ function createCollection2(name) {
31164
31404
  null
31165
31405
  );
31166
31406
  const composeRefs2 = useComposedRefs(ref, setCollectionElement);
31167
- const [itemMap, setItemMap] = state;
31407
+ const [collection, setCollection] = state;
31408
+ const registryRef = React23.useRef(
31409
+ new OrderedDict()
31410
+ );
31411
+ const getCollection = React23.useCallback(() => {
31412
+ const registry = registryRef.current;
31413
+ if (!isInDocumentOrder(registry)) {
31414
+ registry.sort(sortByDocumentPosition);
31415
+ }
31416
+ return registry;
31417
+ }, []);
31168
31418
  React23.useEffect(() => {
31169
- if (!collectionElement) return;
31419
+ if (!collectionElement) {
31420
+ return;
31421
+ }
31170
31422
  const observer = getChildListObserver(() => {
31423
+ setCollection((map) => {
31424
+ const sorted = map.toSorted(sortByDocumentPosition);
31425
+ const orderChanged = sorted.some(([key], index2) => map.keyAt(index2) !== key);
31426
+ return orderChanged ? sorted : map;
31427
+ });
31171
31428
  });
31172
31429
  observer.observe(collectionElement, {
31173
31430
  childList: true,
@@ -31176,28 +31433,36 @@ function createCollection2(name) {
31176
31433
  return () => {
31177
31434
  observer.disconnect();
31178
31435
  };
31179
- }, [collectionElement]);
31436
+ }, [collectionElement, setCollection]);
31180
31437
  return /* @__PURE__ */ jsx23(
31181
- CollectionContextProvider,
31438
+ CollectionStableContextProvider,
31182
31439
  {
31183
31440
  scope,
31184
- itemMap,
31185
- setItemMap,
31186
- collectionRef: composeRefs2,
31187
- collectionRefObject: ref,
31188
- collectionElement,
31189
- children
31441
+ collectionElementRef: composeRefs2,
31442
+ collectionElementRefObject: ref,
31443
+ getCollection,
31444
+ setCollection,
31445
+ registryRef,
31446
+ children: /* @__PURE__ */ jsx23(
31447
+ CollectionStatefulContextProvider,
31448
+ {
31449
+ scope,
31450
+ collectionElement,
31451
+ collection,
31452
+ children
31453
+ }
31454
+ )
31190
31455
  }
31191
31456
  );
31192
31457
  }, "CollectionProviderImpl");
31193
- CollectionProviderImpl.displayName = PROVIDER_NAME + "Impl";
31458
+ CollectionProviderImpl.displayName = name + "CollectionProviderImpl";
31194
31459
  const COLLECTION_SLOT_NAME = name + "CollectionSlot";
31195
31460
  const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
31196
31461
  const CollectionSlot = React23.forwardRef(
31197
31462
  (props, forwardedRef) => {
31198
31463
  const { scope, children } = props;
31199
- const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
31200
- const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
31464
+ const context = useStableCollectionContext(COLLECTION_SLOT_NAME, scope);
31465
+ const composedRefs = useComposedRefs(forwardedRef, context.collectionElementRef);
31201
31466
  return /* @__PURE__ */ jsx23(CollectionSlotImpl, { ref: composedRefs, children });
31202
31467
  }
31203
31468
  );
@@ -31209,37 +31474,71 @@ function createCollection2(name) {
31209
31474
  (props, forwardedRef) => {
31210
31475
  const { scope, children, ...itemData } = props;
31211
31476
  const ref = React23.useRef(null);
31212
- const [element, setElement] = React23.useState(null);
31213
- const composedRefs = useComposedRefs(forwardedRef, ref, setElement);
31214
- const context = useCollectionContext(ITEM_SLOT_NAME, scope);
31215
- const { setItemMap } = context;
31477
+ const context = useStableCollectionContext(ITEM_SLOT_NAME, scope);
31478
+ const { setCollection, registryRef } = context;
31216
31479
  const itemDataRef = React23.useRef(itemData);
31217
31480
  if (!shallowEqual(itemDataRef.current, itemData)) {
31218
31481
  itemDataRef.current = itemData;
31219
31482
  }
31220
31483
  const memoizedItemData = itemDataRef.current;
31484
+ const registerElement = React23.useCallback(
31485
+ (node) => {
31486
+ const registry = registryRef.current;
31487
+ if (node) {
31488
+ registry.set(node, {
31489
+ ...itemDataRef.current,
31490
+ element: node
31491
+ });
31492
+ } else if (ref.current) {
31493
+ registry.delete(ref.current);
31494
+ }
31495
+ },
31496
+ [registryRef]
31497
+ );
31498
+ const composedRefs = useComposedRefs(forwardedRef, registerElement, ref);
31499
+ useLayoutEffect2(() => {
31500
+ const node = ref.current;
31501
+ const registry = registryRef.current;
31502
+ if (node && registry.has(node)) {
31503
+ registry.set(node, { ...memoizedItemData, element: node });
31504
+ }
31505
+ }, [memoizedItemData, registryRef]);
31506
+ const registeredRef = React23.useRef(null);
31221
31507
  React23.useEffect(() => {
31222
- const itemData2 = memoizedItemData;
31223
- setItemMap((map) => {
31224
- if (!element) {
31225
- return map;
31508
+ const element = ref.current;
31509
+ const registered = registeredRef.current;
31510
+ if ((registered?.element ?? null) === element && (!element || registered?.itemData === memoizedItemData)) {
31511
+ return;
31512
+ }
31513
+ registeredRef.current = element ? { element, itemData: memoizedItemData } : null;
31514
+ setCollection((map) => {
31515
+ const next = new OrderedDict(map);
31516
+ if (registered && registered.element !== element) {
31517
+ next.delete(registered.element);
31226
31518
  }
31227
- if (!map.has(element)) {
31228
- map.set(element, { ...itemData2, element });
31229
- return map.toSorted(sortByDocumentPosition);
31519
+ if (element) {
31520
+ next.set(element, { ...memoizedItemData, element });
31230
31521
  }
31231
- return map.set(element, { ...itemData2, element }).toSorted(sortByDocumentPosition);
31522
+ return next.sort(sortByDocumentPosition);
31232
31523
  });
31524
+ });
31525
+ React23.useEffect(() => {
31233
31526
  return () => {
31234
- setItemMap((map) => {
31235
- if (!element || !map.has(element)) {
31527
+ const registered = registeredRef.current;
31528
+ registeredRef.current = null;
31529
+ if (!registered) {
31530
+ return;
31531
+ }
31532
+ setCollection((map) => {
31533
+ if (!map.has(registered.element)) {
31236
31534
  return map;
31237
31535
  }
31238
- map.delete(element);
31239
- return new OrderedDict(map);
31536
+ const next = new OrderedDict(map);
31537
+ next.delete(registered.element);
31538
+ return next;
31240
31539
  });
31241
31540
  };
31242
- }, [element, memoizedItemData, setItemMap]);
31541
+ }, [setCollection]);
31243
31542
  return /* @__PURE__ */ jsx23(CollectionItemSlotImpl, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
31244
31543
  }
31245
31544
  );
@@ -31249,13 +31548,19 @@ function createCollection2(name) {
31249
31548
  }
31250
31549
  __name8(useInitCollection, "useInitCollection");
31251
31550
  function useCollection3(scope) {
31252
- const { itemMap } = useCollectionContext(name + "CollectionConsumer", scope);
31253
- return itemMap;
31551
+ const { collection } = useStatefulCollectionContext(name + "CollectionConsumer", scope);
31552
+ return collection;
31254
31553
  }
31255
31554
  __name8(useCollection3, "useCollection");
31555
+ function useGetCollection(scope) {
31556
+ const { getCollection } = useStableCollectionContext(name + "CollectionConsumer", scope);
31557
+ return getCollection;
31558
+ }
31559
+ __name8(useGetCollection, "useGetCollection");
31256
31560
  const functions = {
31257
31561
  createCollectionScope: createCollectionScope3,
31258
31562
  useCollection: useCollection3,
31563
+ useGetCollection,
31259
31564
  useInitCollection
31260
31565
  };
31261
31566
  return [
@@ -31282,6 +31587,20 @@ function isElementPreceding(a, b) {
31282
31587
  return !!(b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING);
31283
31588
  }
31284
31589
  __name8(isElementPreceding, "isElementPreceding");
31590
+ function isInDocumentOrder(dict) {
31591
+ let previous;
31592
+ for (const element of dict.keys()) {
31593
+ if (previous) {
31594
+ const position = previous.compareDocumentPosition(element);
31595
+ if (!(position & Node.DOCUMENT_POSITION_DISCONNECTED) && position & Node.DOCUMENT_POSITION_PRECEDING) {
31596
+ return false;
31597
+ }
31598
+ }
31599
+ previous = element;
31600
+ }
31601
+ return true;
31602
+ }
31603
+ __name8(isInDocumentOrder, "isInDocumentOrder");
31285
31604
  function sortByDocumentPosition(a, b) {
31286
31605
  return !a[1].element || !b[1].element ? 0 : isElementPreceding(a[1].element, b[1].element) ? -1 : 1;
31287
31606
  }
@@ -31322,11 +31641,18 @@ import * as React21 from "react";
31322
31641
  import * as React20 from "react";
31323
31642
  var __defProp11 = Object.defineProperty;
31324
31643
  var __name10 = (target, value) => __defProp11(target, "name", { value, configurable: true });
31644
+ var useReactInsertionEffect2 = React20[" useInsertionEffect ".trim().toString()];
31325
31645
  function useCallbackRef(callback) {
31326
31646
  const callbackRef = React20.useRef(callback);
31327
- React20.useEffect(() => {
31328
- callbackRef.current = callback;
31329
- });
31647
+ if (typeof useReactInsertionEffect2 === "function") {
31648
+ useReactInsertionEffect2(() => {
31649
+ callbackRef.current = callback;
31650
+ });
31651
+ } else {
31652
+ useLayoutEffect2(() => {
31653
+ callbackRef.current = callback;
31654
+ });
31655
+ }
31330
31656
  return React20.useMemo(() => ((...args) => callbackRef.current?.(...args)), []);
31331
31657
  }
31332
31658
  __name10(useCallbackRef, "useCallbackRef");
@@ -31812,12 +32138,14 @@ var FocusScope = /* @__PURE__ */ React25.forwardRef(
31812
32138
  }
31813
32139
  return () => {
31814
32140
  container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
32141
+ const ownerDocument = container.ownerDocument;
32142
+ const UnmountEvent = CustomEvent;
31815
32143
  setTimeout(() => {
31816
- const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
32144
+ const unmountEvent = new UnmountEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
31817
32145
  container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
31818
32146
  container.dispatchEvent(unmountEvent);
31819
32147
  if (!unmountEvent.defaultPrevented) {
31820
- focus(previouslyFocusedElement ?? document.body, { select: true });
32148
+ focus(previouslyFocusedElement ?? ownerDocument.body, { select: true });
31821
32149
  }
31822
32150
  container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
31823
32151
  focusScopesStack.remove(focusScope);
@@ -31899,14 +32227,19 @@ function getTabbableEdges(container) {
31899
32227
  __name13(getTabbableEdges, "getTabbableEdges");
31900
32228
  function getTabbableCandidates(container) {
31901
32229
  const nodes = [];
31902
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
32230
+ const document2 = container.ownerDocument;
32231
+ const walker = document2.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
31903
32232
  acceptNode: /* @__PURE__ */ __name13((node) => {
31904
32233
  const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
31905
- if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
32234
+ if (node.disabled || node.hidden || isHiddenInput) {
32235
+ return NodeFilter.FILTER_SKIP;
32236
+ }
31906
32237
  return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
31907
32238
  }, "acceptNode")
31908
32239
  });
31909
- while (walker.nextNode()) nodes.push(walker.currentNode);
32240
+ while (walker.nextNode()) {
32241
+ nodes.push(walker.currentNode);
32242
+ }
31910
32243
  return nodes;
31911
32244
  }
31912
32245
  __name13(getTabbableCandidates, "getTabbableCandidates");
@@ -31931,12 +32264,13 @@ function isHidden(node, { upTo }) {
31931
32264
  }
31932
32265
  __name13(isHidden, "isHidden");
31933
32266
  function isSelectableInput(element) {
31934
- return element instanceof HTMLInputElement && "select" in element;
32267
+ return element.tagName === "INPUT" && typeof element.select === "function";
31935
32268
  }
31936
32269
  __name13(isSelectableInput, "isSelectableInput");
31937
32270
  function focus(element, { select = false } = {}) {
31938
32271
  if (element && element.focus) {
31939
- const previouslyFocusedElement = document.activeElement;
32272
+ const ownerDocument = element.ownerDocument ?? document;
32273
+ const previouslyFocusedElement = ownerDocument.activeElement;
31940
32274
  element.focus({ preventScroll: true });
31941
32275
  if (element !== previouslyFocusedElement && isSelectableInput(element) && select)
31942
32276
  element.select();
@@ -34072,7 +34406,9 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
34072
34406
  avoidCollisions && shift3({
34073
34407
  mainAxis: true,
34074
34408
  crossAxis: false,
34075
- limiter: sticky === Sticky.Partial ? limitShift3() : void 0,
34409
+ // Spread rather than passing `limiter: undefined`, which
34410
+ // `exactOptionalPropertyTypes` rejects for Floating UI's optional option.
34411
+ ...sticky === Sticky.Partial ? { limiter: limitShift3() } : {},
34076
34412
  ...detectOverflowOptions
34077
34413
  }),
34078
34414
  avoidCollisions && flip3({ ...detectOverflowOptions }),
@@ -34089,18 +34425,22 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
34089
34425
  }),
34090
34426
  arrow4 && arrow3({ element: arrow4, padding: arrowPadding }),
34091
34427
  transformOrigin({ arrowWidth, arrowHeight }),
34092
- hideWhenDetached && hide3({
34093
- strategy: "referenceHidden",
34094
- ...detectOverflowOptions,
34095
- // `hide` detects whether the anchor (reference) is clipped, so when
34096
- // no explicit `collisionBoundary` is set we fall back to Floating
34097
- // UI's default clipping ancestors (e.g. a scrollable menu). This
34098
- // lets an occluded submenu hide once its anchor scrolls out of view
34099
- // (#3237). The collision/size middlewares deliberately keep the
34100
- // viewport-based default to avoid clamping content rendered inside
34101
- // transformed or overflow-clipping portal containers.
34102
- boundary: hasExplicitBoundaries ? detectOverflowOptions.boundary : void 0
34103
- })
34428
+ hideWhenDetached && // `hide` detects whether the anchor (reference) is clipped, so when
34429
+ // no explicit `collisionBoundary` is set we omit `boundary` entirely
34430
+ // and fall back to Floating UI's default clipping ancestors (e.g. a
34431
+ // scrollable menu). This lets an occluded submenu hide once its anchor
34432
+ // scrolls out of view (#3237). The collision/size middlewares
34433
+ // deliberately keep the viewport-based default to avoid clamping
34434
+ // content rendered inside transformed or overflow-clipping portal
34435
+ // containers. The key is omitted rather than set to `undefined`
34436
+ // because `exactOptionalPropertyTypes` rejects the explicit value.
34437
+ hide3(
34438
+ hasExplicitBoundaries ? { strategy: "referenceHidden", ...detectOverflowOptions } : {
34439
+ strategy: "referenceHidden",
34440
+ padding: detectOverflowOptions.padding,
34441
+ altBoundary: detectOverflowOptions.altBoundary
34442
+ }
34443
+ )
34104
34444
  ]
34105
34445
  });
34106
34446
  const setPlacementState = context.setPlacementState;
@@ -35742,11 +36082,13 @@ var MenuContentImpl = /* @__PURE__ */ React41.forwardRef(
35742
36082
  const values = items.map((item) => item.textValue);
35743
36083
  const nextMatch = getNextMatch(values, search, currentMatch);
35744
36084
  const newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
35745
- (/* @__PURE__ */ __name21((function updateSearch(value) {
36085
+ function updateSearch(value) {
35746
36086
  searchRef.current = value;
35747
36087
  window.clearTimeout(timerRef.current);
35748
36088
  if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
35749
- }), "updateSearch"))(search);
36089
+ }
36090
+ __name21(updateSearch, "updateSearch");
36091
+ updateSearch(search);
35750
36092
  if (newItem) {
35751
36093
  setTimeout(() => newItem.focus());
35752
36094
  }
@@ -37529,10 +37871,10 @@ var ContextMenu = ({
37529
37871
  };
37530
37872
 
37531
37873
  // src/components/KeyboardShortcutsDialog.tsx
37532
- import { useEffect as useEffect49, useMemo as useMemo36, useRef as useRef27, useState as useState40 } from "react";
37874
+ import { useEffect as useEffect48, useMemo as useMemo36, useRef as useRef27, useState as useState40 } from "react";
37533
37875
 
37534
37876
  // src/hooks/useRegisteredHotkey.ts
37535
- import { useEffect as useEffect48, useMemo as useMemo35, useRef as useRef26, useState as useState39 } from "react";
37877
+ import { useEffect as useEffect47, useMemo as useMemo35, useRef as useRef26, useState as useState39 } from "react";
37536
37878
  var hotkeyRegistry = /* @__PURE__ */ new Map();
37537
37879
  var subscribers = /* @__PURE__ */ new Set();
37538
37880
  var isListenerAttached = false;
@@ -37663,7 +38005,7 @@ var useRegisteredHotkey = (id, handler, metadata) => {
37663
38005
  }),
37664
38006
  [metadata.shortcut, metadata.description]
37665
38007
  );
37666
- useEffect48(() => {
38008
+ useEffect47(() => {
37667
38009
  const registration = {
37668
38010
  id,
37669
38011
  ...normalizedMetadata,
@@ -37679,7 +38021,7 @@ var useHotkeyRegistry = () => {
37679
38021
  const [entries, setEntries] = useState39(
37680
38022
  () => Array.from(hotkeyRegistry.values())
37681
38023
  );
37682
- useEffect48(() => subscribeToRegistry(setEntries), []);
38024
+ useEffect47(() => subscribeToRegistry(setEntries), []);
37683
38025
  return entries;
37684
38026
  };
37685
38027
  var registerHotkeyViewer = (element) => {
@@ -37696,7 +38038,7 @@ var KeyboardShortcutsDialog = ({
37696
38038
  const [query, setQuery] = useState40("");
37697
38039
  const inputRef = useRef27(null);
37698
38040
  const hotkeys = useHotkeyRegistry();
37699
- useEffect49(() => {
38041
+ useEffect48(() => {
37700
38042
  if (!open) return void 0;
37701
38043
  const handleKeyDown = (event) => {
37702
38044
  if (event.key === "Escape") {
@@ -37707,7 +38049,7 @@ var KeyboardShortcutsDialog = ({
37707
38049
  window.addEventListener("keydown", handleKeyDown);
37708
38050
  return () => window.removeEventListener("keydown", handleKeyDown);
37709
38051
  }, [open, onClose]);
37710
- useEffect49(() => {
38052
+ useEffect48(() => {
37711
38053
  if (open) {
37712
38054
  setTimeout(() => {
37713
38055
  inputRef.current?.focus();
@@ -37896,7 +38238,7 @@ var ToastProvider = ({
37896
38238
  };
37897
38239
 
37898
38240
  // src/hooks/useCameraPreset.ts
37899
- import { useCallback as useCallback21 } from "react";
38241
+ import { useCallback as useCallback22 } from "react";
37900
38242
  function useCameraPreset({
37901
38243
  setAutoRotate,
37902
38244
  setAutoRotateUserToggled,
@@ -37906,7 +38248,7 @@ function useCameraPreset({
37906
38248
  isAnimatingRef,
37907
38249
  lastPresetSelectTime
37908
38250
  }) {
37909
- const handleCameraPresetSelect = useCallback21(
38251
+ const handleCameraPresetSelect = useCallback22(
37910
38252
  (preset) => {
37911
38253
  setAutoRotate(false);
37912
38254
  setAutoRotateUserToggled(true);
@@ -37936,7 +38278,7 @@ function useCameraPreset({
37936
38278
  }
37937
38279
 
37938
38280
  // src/hooks/useContextMenu.ts
37939
- import { useState as useState41, useCallback as useCallback22, useRef as useRef28, useEffect as useEffect50 } from "react";
38281
+ import { useState as useState41, useCallback as useCallback23, useRef as useRef28, useEffect as useEffect49 } from "react";
37940
38282
  var useContextMenu = ({ containerRef, onOpen }) => {
37941
38283
  const [menuVisible, setMenuVisible] = useState41(false);
37942
38284
  const [menuPos, setMenuPos] = useState41({
@@ -37953,7 +38295,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
37953
38295
  longPressTimeoutRef.current = null;
37954
38296
  }
37955
38297
  };
37956
- const handleContextMenu = useCallback22(
38298
+ const handleContextMenu = useCallback23(
37957
38299
  (e) => {
37958
38300
  e.preventDefault();
37959
38301
  const eventX = typeof e.clientX === "number" ? e.clientX : 0;
@@ -37980,7 +38322,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
37980
38322
  },
37981
38323
  [setMenuPos, setMenuVisible, onOpen]
37982
38324
  );
37983
- const handleTouchStart = useCallback22(
38325
+ const handleTouchStart = useCallback23(
37984
38326
  (e) => {
37985
38327
  if (e.touches.length === 1) {
37986
38328
  const touch = e.touches[0];
@@ -38014,7 +38356,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38014
38356
  },
38015
38357
  [containerRef, onOpen]
38016
38358
  );
38017
- const handleTouchMove = useCallback22((e) => {
38359
+ const handleTouchMove = useCallback23((e) => {
38018
38360
  if (!interactionOriginPosRef.current || e.touches.length !== 1) {
38019
38361
  return;
38020
38362
  }
@@ -38032,7 +38374,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38032
38374
  clearLongPressTimeout();
38033
38375
  }
38034
38376
  }, []);
38035
- const handleTouchEnd = useCallback22(() => {
38377
+ const handleTouchEnd = useCallback23(() => {
38036
38378
  clearLongPressTimeout();
38037
38379
  setTimeout(() => {
38038
38380
  if (interactionOriginPosRef.current) {
@@ -38040,7 +38382,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38040
38382
  }
38041
38383
  }, 0);
38042
38384
  }, []);
38043
- const handleClickAway = useCallback22((e) => {
38385
+ const handleClickAway = useCallback23((e) => {
38044
38386
  const target = e.target;
38045
38387
  if (menuRef.current && menuRef.current.contains(target)) {
38046
38388
  return;
@@ -38053,7 +38395,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38053
38395
  }
38054
38396
  setMenuVisible(false);
38055
38397
  }, []);
38056
- useEffect50(() => {
38398
+ useEffect49(() => {
38057
38399
  if (menuVisible) {
38058
38400
  document.addEventListener("mousedown", handleClickAway);
38059
38401
  document.addEventListener("touchstart", handleClickAway);
@@ -38087,10 +38429,10 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38087
38429
  };
38088
38430
 
38089
38431
  // src/hooks/useGlobalDownloadGltf.ts
38090
- import { useCallback as useCallback23 } from "react";
38432
+ import { useCallback as useCallback24 } from "react";
38091
38433
  import { GLTFExporter as GLTFExporter2 } from "three-stdlib";
38092
38434
  var useGlobalDownloadGltf = () => {
38093
- return useCallback23(() => {
38435
+ return useCallback24(() => {
38094
38436
  const root = window.__TSCIRCUIT_THREE_OBJECT;
38095
38437
  if (!root) return;
38096
38438
  const exporter = new GLTFExporter2();
@@ -38117,7 +38459,7 @@ var useGlobalDownloadGltf = () => {
38117
38459
 
38118
38460
  // src/CadViewer.tsx
38119
38461
  import { jsx as jsx38, jsxs as jsxs10 } from "react/jsx-runtime";
38120
- var DEFAULT_TARGET = new THREE55.Vector3(0, 0, 0);
38462
+ var DEFAULT_TARGET = new THREE56.Vector3(0, 0, 0);
38121
38463
  var INITIAL_CAMERA_POSITION = [5, -5, 5];
38122
38464
  var readStoredCameraType = () => {
38123
38465
  if (typeof window === "undefined") return void 0;
@@ -38168,7 +38510,7 @@ var CadViewerInner = (props) => {
38168
38510
  const sceneRef = useContext11(SchematicNavigationContext);
38169
38511
  const [selectedComponent, setSelectedComponent] = useState42();
38170
38512
  const [selectedCadComponent, setSelectedCadComponent] = useState42();
38171
- const handleMenuOpen = useCallback24(
38513
+ const handleMenuOpen = useCallback25(
38172
38514
  (position) => {
38173
38515
  setSelectedCadComponent(
38174
38516
  pickCadComponent(sceneRef.current, position, circuitJson)
@@ -38191,7 +38533,7 @@ var CadViewerInner = (props) => {
38191
38533
  const isAnimatingRef = useRef29(false);
38192
38534
  const lastPresetSelectTime = useRef29(0);
38193
38535
  const PRESET_COOLDOWN = 1e3;
38194
- const handleUserInteraction = useCallback24(() => {
38536
+ const handleUserInteraction = useCallback25(() => {
38195
38537
  if (isAnimatingRef.current || Date.now() - lastPresetSelectTime.current < PRESET_COOLDOWN) {
38196
38538
  return;
38197
38539
  }
@@ -38202,15 +38544,15 @@ var CadViewerInner = (props) => {
38202
38544
  setCameraPreset("Custom");
38203
38545
  }
38204
38546
  }, [menuVisible]);
38205
- const toggleAutoRotate = useCallback24(() => {
38547
+ const toggleAutoRotate = useCallback25(() => {
38206
38548
  setAutoRotate((prev) => !prev);
38207
38549
  setAutoRotateUserToggled(true);
38208
38550
  }, []);
38209
38551
  const downloadGltf = useGlobalDownloadGltf();
38210
- const closeMenu = useCallback24(() => {
38552
+ const closeMenu = useCallback25(() => {
38211
38553
  setMenuVisible(false);
38212
38554
  }, [setMenuVisible]);
38213
- const handleCameraControllerReady = useCallback24(
38555
+ const handleCameraControllerReady = useCallback25(
38214
38556
  (controller) => {
38215
38557
  cameraControllerRef.current = controller;
38216
38558
  externalCameraControllerReady?.(controller);
@@ -38284,24 +38626,24 @@ var CadViewerInner = (props) => {
38284
38626
  description: "Toggle translucent components"
38285
38627
  }
38286
38628
  );
38287
- useEffect51(() => {
38629
+ useEffect50(() => {
38288
38630
  if (containerRef.current) {
38289
38631
  registerHotkeyViewer(containerRef.current);
38290
38632
  }
38291
38633
  }, []);
38292
- useEffect51(() => {
38634
+ useEffect50(() => {
38293
38635
  window.localStorage.setItem("cadViewerEngine", engine);
38294
38636
  }, [engine]);
38295
- useEffect51(() => {
38637
+ useEffect50(() => {
38296
38638
  window.localStorage.setItem("cadViewerAutoRotate", String(autoRotate));
38297
38639
  }, [autoRotate]);
38298
- useEffect51(() => {
38640
+ useEffect50(() => {
38299
38641
  window.localStorage.setItem(
38300
38642
  "cadViewerAutoRotateUserToggled",
38301
38643
  String(autoRotateUserToggled)
38302
38644
  );
38303
38645
  }, [autoRotateUserToggled]);
38304
- useEffect51(() => {
38646
+ useEffect50(() => {
38305
38647
  window.localStorage.setItem("cadViewerCameraType", cameraType);
38306
38648
  }, [cameraType]);
38307
38649
  const viewerKey = props.circuitJson ? circuitKey : void 0;
@@ -38440,11 +38782,11 @@ var CadViewer = (props) => {
38440
38782
  // src/convert-circuit-json-to-3d-svg.ts
38441
38783
  var import_debug = __toESM(require_browser(), 1);
38442
38784
  import { su as su18 } from "@tscircuit/circuit-json-util";
38443
- import * as THREE59 from "three";
38785
+ import * as THREE60 from "three";
38444
38786
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
38445
38787
 
38446
38788
  // src/utils/create-geometry-from-polygons.ts
38447
- import * as THREE56 from "three";
38789
+ import * as THREE57 from "three";
38448
38790
  import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6 } from "three";
38449
38791
  function createGeometryFromPolygons(polygons) {
38450
38792
  const geometry = new BufferGeometry6();
@@ -38458,12 +38800,12 @@ function createGeometryFromPolygons(polygons) {
38458
38800
  ...polygon2.vertices[i + 1]
38459
38801
  // Third vertex
38460
38802
  );
38461
- const v1 = new THREE56.Vector3(...polygon2.vertices[0]);
38462
- const v2 = new THREE56.Vector3(...polygon2.vertices[i]);
38463
- const v3 = new THREE56.Vector3(...polygon2.vertices[i + 1]);
38464
- const normal = new THREE56.Vector3().crossVectors(
38465
- new THREE56.Vector3().subVectors(v2, v1),
38466
- new THREE56.Vector3().subVectors(v3, v1)
38803
+ const v1 = new THREE57.Vector3(...polygon2.vertices[0]);
38804
+ const v2 = new THREE57.Vector3(...polygon2.vertices[i]);
38805
+ const v3 = new THREE57.Vector3(...polygon2.vertices[i + 1]);
38806
+ const normal = new THREE57.Vector3().crossVectors(
38807
+ new THREE57.Vector3().subVectors(v2, v1),
38808
+ new THREE57.Vector3().subVectors(v3, v1)
38467
38809
  ).normalize();
38468
38810
  normals.push(
38469
38811
  normal.x,
@@ -38491,10 +38833,10 @@ import {
38491
38833
  convertCSGToThreeGeom as convertCSGToThreeGeom3,
38492
38834
  getJscadModelForFootprint as getJscadModelForFootprint2
38493
38835
  } from "jscad-electronics/vanilla";
38494
- import * as THREE58 from "three";
38836
+ import * as THREE59 from "three";
38495
38837
 
38496
38838
  // src/utils/load-model.ts
38497
- import * as THREE57 from "three";
38839
+ import * as THREE58 from "three";
38498
38840
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
38499
38841
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
38500
38842
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -38502,12 +38844,12 @@ async function load3DModel(url) {
38502
38844
  if (url.endsWith(".stl")) {
38503
38845
  const loader = new STLLoader2();
38504
38846
  const geometry = await loader.loadAsync(url);
38505
- const material = new THREE57.MeshStandardMaterial({
38847
+ const material = new THREE58.MeshStandardMaterial({
38506
38848
  color: 8947848,
38507
38849
  metalness: 0.5,
38508
38850
  roughness: 0.5
38509
38851
  });
38510
- return new THREE57.Mesh(geometry, material);
38852
+ return new THREE58.Mesh(geometry, material);
38511
38853
  }
38512
38854
  if (url.endsWith(".obj")) {
38513
38855
  const loader = new OBJLoader2();
@@ -38540,9 +38882,9 @@ async function renderComponent(component, scene) {
38540
38882
  }
38541
38883
  if (component.rotation) {
38542
38884
  model.rotation.set(
38543
- THREE58.MathUtils.degToRad(component.rotation.x ?? 0),
38544
- THREE58.MathUtils.degToRad(component.rotation.y ?? 0),
38545
- THREE58.MathUtils.degToRad(component.rotation.z ?? 0)
38885
+ THREE59.MathUtils.degToRad(component.rotation.x ?? 0),
38886
+ THREE59.MathUtils.degToRad(component.rotation.y ?? 0),
38887
+ THREE59.MathUtils.degToRad(component.rotation.z ?? 0)
38546
38888
  );
38547
38889
  }
38548
38890
  scene.add(model);
@@ -38556,13 +38898,13 @@ async function renderComponent(component, scene) {
38556
38898
  );
38557
38899
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
38558
38900
  const threeGeom = convertCSGToThreeGeom3(jscadObject);
38559
- const material2 = new THREE58.MeshStandardMaterial({
38901
+ const material2 = new THREE59.MeshStandardMaterial({
38560
38902
  color: 8947848,
38561
38903
  metalness: 0.5,
38562
38904
  roughness: 0.5,
38563
- side: THREE58.DoubleSide
38905
+ side: THREE59.DoubleSide
38564
38906
  });
38565
- const mesh2 = new THREE58.Mesh(threeGeom, material2);
38907
+ const mesh2 = new THREE59.Mesh(threeGeom, material2);
38566
38908
  if (component.position) {
38567
38909
  mesh2.position.set(
38568
38910
  component.position.x ?? 0,
@@ -38572,9 +38914,9 @@ async function renderComponent(component, scene) {
38572
38914
  }
38573
38915
  if (component.rotation) {
38574
38916
  mesh2.rotation.set(
38575
- THREE58.MathUtils.degToRad(component.rotation.x ?? 0),
38576
- THREE58.MathUtils.degToRad(component.rotation.y ?? 0),
38577
- THREE58.MathUtils.degToRad(component.rotation.z ?? 0)
38917
+ THREE59.MathUtils.degToRad(component.rotation.x ?? 0),
38918
+ THREE59.MathUtils.degToRad(component.rotation.y ?? 0),
38919
+ THREE59.MathUtils.degToRad(component.rotation.z ?? 0)
38578
38920
  );
38579
38921
  }
38580
38922
  scene.add(mesh2);
@@ -38591,17 +38933,17 @@ async function renderComponent(component, scene) {
38591
38933
  if (!geom || !geom.polygons && !geom.sides) {
38592
38934
  continue;
38593
38935
  }
38594
- const color = new THREE58.Color(geomInfo.color);
38936
+ const color = new THREE59.Color(geomInfo.color);
38595
38937
  color.convertLinearToSRGB();
38596
38938
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
38597
38939
  const threeGeom = convertCSGToThreeGeom3(geomWithColor);
38598
- const material2 = new THREE58.MeshStandardMaterial({
38940
+ const material2 = new THREE59.MeshStandardMaterial({
38599
38941
  vertexColors: true,
38600
38942
  metalness: 0.2,
38601
38943
  roughness: 0.8,
38602
- side: THREE58.DoubleSide
38944
+ side: THREE59.DoubleSide
38603
38945
  });
38604
- const mesh2 = new THREE58.Mesh(threeGeom, material2);
38946
+ const mesh2 = new THREE59.Mesh(threeGeom, material2);
38605
38947
  if (component.position) {
38606
38948
  mesh2.position.set(
38607
38949
  component.position.x ?? 0,
@@ -38611,22 +38953,22 @@ async function renderComponent(component, scene) {
38611
38953
  }
38612
38954
  if (component.rotation) {
38613
38955
  mesh2.rotation.set(
38614
- THREE58.MathUtils.degToRad(component.rotation.x ?? 0),
38615
- THREE58.MathUtils.degToRad(component.rotation.y ?? 0),
38616
- THREE58.MathUtils.degToRad(component.rotation.z ?? 0)
38956
+ THREE59.MathUtils.degToRad(component.rotation.x ?? 0),
38957
+ THREE59.MathUtils.degToRad(component.rotation.y ?? 0),
38958
+ THREE59.MathUtils.degToRad(component.rotation.z ?? 0)
38617
38959
  );
38618
38960
  }
38619
38961
  scene.add(mesh2);
38620
38962
  }
38621
38963
  return;
38622
38964
  }
38623
- const geometry = new THREE58.BoxGeometry(0.5, 0.5, 0.5);
38624
- const material = new THREE58.MeshStandardMaterial({
38965
+ const geometry = new THREE59.BoxGeometry(0.5, 0.5, 0.5);
38966
+ const material = new THREE59.MeshStandardMaterial({
38625
38967
  color: 16711680,
38626
38968
  transparent: true,
38627
38969
  opacity: 0.25
38628
38970
  });
38629
- const mesh = new THREE58.Mesh(geometry, material);
38971
+ const mesh = new THREE59.Mesh(geometry, material);
38630
38972
  if (component.position) {
38631
38973
  mesh.position.set(
38632
38974
  component.position.x ?? 0,
@@ -38647,11 +38989,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
38647
38989
  padding = 20,
38648
38990
  zoom = 1.5
38649
38991
  } = options;
38650
- const scene = new THREE59.Scene();
38992
+ const scene = new THREE60.Scene();
38651
38993
  const renderer = new SVGRenderer();
38652
38994
  renderer.setSize(width, height);
38653
- renderer.setClearColor(new THREE59.Color(backgroundColor), 1);
38654
- const camera = new THREE59.OrthographicCamera();
38995
+ renderer.setClearColor(new THREE60.Color(backgroundColor), 1);
38996
+ const camera = new THREE60.OrthographicCamera();
38655
38997
  const aspect = width / height;
38656
38998
  const frustumSize = 100;
38657
38999
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -38665,11 +39007,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
38665
39007
  camera.position.set(position.x, position.y, position.z);
38666
39008
  camera.up.set(0, 1, 0);
38667
39009
  const lookAt2 = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
38668
- camera.lookAt(new THREE59.Vector3(lookAt2.x, lookAt2.y, lookAt2.z));
39010
+ camera.lookAt(new THREE60.Vector3(lookAt2.x, lookAt2.y, lookAt2.z));
38669
39011
  camera.updateProjectionMatrix();
38670
- const ambientLight = new THREE59.AmbientLight(16777215, Math.PI / 2);
39012
+ const ambientLight = new THREE60.AmbientLight(16777215, Math.PI / 2);
38671
39013
  scene.add(ambientLight);
38672
- const pointLight = new THREE59.PointLight(16777215, Math.PI / 4);
39014
+ const pointLight = new THREE60.PointLight(16777215, Math.PI / 4);
38673
39015
  pointLight.position.set(-10, -10, 10);
38674
39016
  scene.add(pointLight);
38675
39017
  const components = su18(circuitJson).cad_component.list();
@@ -38701,28 +39043,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
38701
39043
  const material = createBoardMaterial({
38702
39044
  material: boardData?.material,
38703
39045
  color: edgeColor,
38704
- side: THREE59.DoubleSide
39046
+ side: THREE60.DoubleSide
38705
39047
  });
38706
- const mesh = new THREE59.Mesh(geometry, material);
39048
+ const mesh = new THREE60.Mesh(geometry, material);
38707
39049
  scene.add(mesh);
38708
39050
  }
38709
39051
  }
38710
- const gridColor = new THREE59.Color(8947848);
38711
- const gridHelper = new THREE59.GridHelper(100, 100, gridColor, gridColor);
39052
+ const gridColor = new THREE60.Color(8947848);
39053
+ const gridHelper = new THREE60.GridHelper(100, 100, gridColor, gridColor);
38712
39054
  gridHelper.rotation.x = Math.PI / 2;
38713
39055
  const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
38714
39056
  for (const mat of materials) {
38715
39057
  mat.transparent = true;
38716
39058
  mat.opacity = 0.3;
38717
- if (mat instanceof THREE59.LineBasicMaterial) {
39059
+ if (mat instanceof THREE60.LineBasicMaterial) {
38718
39060
  mat.color = gridColor;
38719
39061
  mat.vertexColors = false;
38720
39062
  }
38721
39063
  }
38722
39064
  scene.add(gridHelper);
38723
- const box = new THREE59.Box3().setFromObject(scene);
38724
- const center = box.getCenter(new THREE59.Vector3());
38725
- const size4 = box.getSize(new THREE59.Vector3());
39065
+ const box = new THREE60.Box3().setFromObject(scene);
39066
+ const center = box.getCenter(new THREE60.Vector3());
39067
+ const size4 = box.getSize(new THREE60.Vector3());
38726
39068
  scene.position.sub(center);
38727
39069
  const maxDim = Math.max(size4.x, size4.y, size4.z);
38728
39070
  if (maxDim > 0) {
@@ -38740,7 +39082,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
38740
39082
 
38741
39083
  // src/hooks/exporter/gltf.ts
38742
39084
  import { GLTFExporter as GLTFExporter3 } from "three-stdlib";
38743
- import { useEffect as useEffect52, useState as useState43, useMemo as useMemo37, useCallback as useCallback25 } from "react";
39085
+ import { useEffect as useEffect51, useState as useState43, useMemo as useMemo37, useCallback as useCallback26 } from "react";
38744
39086
  function useSaveGltfAs(options = {}) {
38745
39087
  const parse2 = useParser(options);
38746
39088
  const link = useMemo37(() => document.createElement("a"), []);
@@ -38753,7 +39095,7 @@ function useSaveGltfAs(options = {}) {
38753
39095
  link.dispatchEvent(new MouseEvent("click"));
38754
39096
  URL.revokeObjectURL(url);
38755
39097
  };
38756
- useEffect52(
39098
+ useEffect51(
38757
39099
  () => () => {
38758
39100
  link.remove();
38759
39101
  instance = null;
@@ -38761,7 +39103,7 @@ function useSaveGltfAs(options = {}) {
38761
39103
  []
38762
39104
  );
38763
39105
  let instance;
38764
- const ref = useCallback25((obj3D) => {
39106
+ const ref = useCallback26((obj3D) => {
38765
39107
  instance = obj3D;
38766
39108
  }, []);
38767
39109
  return [ref, saveAs];
@@ -38770,11 +39112,11 @@ function useExportGltfUrl(options = {}) {
38770
39112
  const parse2 = useParser(options);
38771
39113
  const [url, setUrl] = useState43();
38772
39114
  const [error, setError] = useState43();
38773
- const ref = useCallback25(
39115
+ const ref = useCallback26(
38774
39116
  (instance) => parse2(instance).then(setUrl).catch(setError),
38775
39117
  []
38776
39118
  );
38777
- useEffect52(() => () => URL.revokeObjectURL(url), [url]);
39119
+ useEffect51(() => () => URL.revokeObjectURL(url), [url]);
38778
39120
  return [ref, url, error];
38779
39121
  }
38780
39122
  function useParser(options = {}) {