@tscircuit/3d-viewer 0.0.621 → 0.0.623

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 +529 -228
  2. package/package.json +2 -2
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,7 +18979,7 @@ 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";
18982
+ import { useCallback as useCallback25, useContext as useContext11, useEffect as useEffect50, useRef as useRef29, useState as useState42 } from "react";
18983
18983
  import * as THREE56 from "three";
18984
18984
 
18985
18985
  // src/hooks/use-convert-children-to-soup.ts
@@ -20951,7 +20951,7 @@ import * as THREE26 from "three";
20951
20951
  // package.json
20952
20952
  var package_default = {
20953
20953
  name: "@tscircuit/3d-viewer",
20954
- version: "0.0.620",
20954
+ version: "0.0.622",
20955
20955
  repository: {
20956
20956
  type: "git",
20957
20957
  url: "https://github.com/tscircuit/3d-viewer"
@@ -20990,7 +20990,7 @@ var package_default = {
20990
20990
  "@jscad/regl-renderer": "^2.6.12",
20991
20991
  "@jscad/stl-serializer": "^2.1.20",
20992
20992
  "@tscircuit/cableprinter": "^0.0.6",
20993
- "circuit-json": "^0.0.515",
20993
+ "circuit-json": "^0.0.525",
20994
20994
  "circuit-to-canvas": "^0.0.135",
20995
20995
  "jscad-electronics": "^0.0.213",
20996
20996
  "react-hot-toast": "^2.6.0",
@@ -23069,6 +23069,7 @@ var createSimplifiedBoardGeom = (circuitJson) => {
23069
23069
  // src/BoardGeomBuilder.ts
23070
23070
  var import_colors3 = __toESM(require_colors(), 1);
23071
23071
  var import_booleans4 = __toESM(require_booleans(), 1);
23072
+ var import_measurements = __toESM(require_measurements(), 1);
23072
23073
  var import_extrusions4 = __toESM(require_extrusions(), 1);
23073
23074
  var import_transforms6 = __toESM(require_transforms(), 1);
23074
23075
  var import_primitives6 = __toESM(require_primitives(), 1);
@@ -23800,6 +23801,9 @@ var BoardGeomBuilder = class {
23800
23801
  platedHoleGeoms = [];
23801
23802
  viaGeoms = [];
23802
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 = [];
23803
23807
  boardClipGeom = null;
23804
23808
  state = "initializing";
23805
23809
  currentIndex = 0;
@@ -24017,6 +24021,10 @@ var BoardGeomBuilder = class {
24017
24021
  }
24018
24022
  if (!opts.dontCutBoard) {
24019
24023
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, cyGeom);
24024
+ this.copperDrills.push({
24025
+ geom: cyGeom,
24026
+ platedHoleIndex: this.platedHoleGeoms.length
24027
+ });
24020
24028
  }
24021
24029
  const platedHoleGeom = platedHole(ph, this.ctx, {
24022
24030
  clipGeom: this.boardClipGeom
@@ -24054,6 +24062,10 @@ var BoardGeomBuilder = class {
24054
24062
  }
24055
24063
  if (!opts.dontCutBoard) {
24056
24064
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, pillHole);
24065
+ this.copperDrills.push({
24066
+ geom: pillHole,
24067
+ platedHoleIndex: this.platedHoleGeoms.length
24068
+ });
24057
24069
  }
24058
24070
  const platedHoleGeom = platedHole(ph, this.ctx, {
24059
24071
  clipGeom: this.boardClipGeom
@@ -24107,6 +24119,10 @@ var BoardGeomBuilder = class {
24107
24119
  );
24108
24120
  if (!opts.dontCutBoard) {
24109
24121
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, pillHole);
24122
+ this.copperDrills.push({
24123
+ geom: pillHole,
24124
+ platedHoleIndex: this.platedHoleGeoms.length
24125
+ });
24110
24126
  }
24111
24127
  const platedHoleGeom = platedHole(ph, this.ctx, {
24112
24128
  clipGeom: this.boardClipGeom
@@ -24151,6 +24167,10 @@ var BoardGeomBuilder = class {
24151
24167
  );
24152
24168
  if (!opts.dontCutBoard) {
24153
24169
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, pillHole);
24170
+ this.copperDrills.push({
24171
+ geom: pillHole,
24172
+ platedHoleIndex: this.platedHoleGeoms.length
24173
+ });
24154
24174
  }
24155
24175
  const platedHoleGeom = platedHole(ph, this.ctx, {
24156
24176
  clipGeom: this.boardClipGeom
@@ -24171,10 +24191,11 @@ var BoardGeomBuilder = class {
24171
24191
  if (!boardHole || !copperHole) return;
24172
24192
  if (!opts.dontCutBoard) {
24173
24193
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, boardHole);
24194
+ this.copperDrills.push({
24195
+ geom: boardHole,
24196
+ platedHoleIndex: this.platedHoleGeoms.length
24197
+ });
24174
24198
  }
24175
- this.platedHoleGeoms = this.platedHoleGeoms.map(
24176
- (phg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans4.subtract)(phg, copperHole))
24177
- );
24178
24199
  const platedHoleGeom = platedHole(ph, this.ctx, {
24179
24200
  clipGeom: this.boardClipGeom
24180
24201
  });
@@ -24196,9 +24217,7 @@ var BoardGeomBuilder = class {
24196
24217
  radius: hole.hole_diameter / 2 + M / 2,
24197
24218
  height: holeDepth
24198
24219
  });
24199
- this.platedHoleGeoms = this.platedHoleGeoms.map(
24200
- (phg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans4.subtract)(phg, copperCut))
24201
- );
24220
+ this.copperDrills.push({ geom: copperCut });
24202
24221
  } else if (hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill" || hole.hole_shape === "rect" || hole.hole_shape === "oval") {
24203
24222
  const holeWidth = hole.hole_width ?? hole.hole_diameter;
24204
24223
  const holeHeight = hole.hole_height ?? hole.hole_diameter;
@@ -24260,14 +24279,13 @@ var BoardGeomBuilder = class {
24260
24279
  }
24261
24280
  if (copperCut) {
24262
24281
  const positionedCopperCut = (0, import_transforms6.translate)([hole.x, hole.y, 0], copperCut);
24263
- this.platedHoleGeoms = this.platedHoleGeoms.map(
24264
- (phg) => (0, import_colors3.colorize)(colors.copper, (0, import_booleans4.subtract)(phg, positionedCopperCut))
24265
- );
24282
+ this.copperDrills.push({ geom: positionedCopperCut });
24266
24283
  }
24267
24284
  }
24268
24285
  }
24269
24286
  processVia(via) {
24270
24287
  if (!this.boardGeom) return;
24288
+ let viaCopperIndex;
24271
24289
  if (typeof via.outer_diameter === "number" && typeof via.hole_diameter === "number") {
24272
24290
  const viaCopperGeom = createViaCopper({
24273
24291
  x: via.x,
@@ -24281,6 +24299,7 @@ var BoardGeomBuilder = class {
24281
24299
  finalViaGeom = (0, import_booleans4.intersect)(this.boardClipGeom, viaCopperGeom);
24282
24300
  finalViaGeom = (0, import_colors3.colorize)(colors.copper, finalViaGeom);
24283
24301
  }
24302
+ viaCopperIndex = this.viaGeoms.length;
24284
24303
  this.viaGeoms.push(finalViaGeom);
24285
24304
  }
24286
24305
  if (typeof via.hole_diameter === "number") {
@@ -24291,10 +24310,36 @@ var BoardGeomBuilder = class {
24291
24310
  thickness: this.ctx.pcbThickness
24292
24311
  });
24293
24312
  this.boardGeom = (0, import_booleans4.subtract)(this.boardGeom, viaDrill);
24313
+ this.copperDrills.push({
24314
+ geom: viaDrill,
24315
+ viaIndex: viaCopperIndex
24316
+ });
24294
24317
  }
24295
24318
  }
24296
24319
  finalize() {
24297
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
+ );
24298
24343
  const boardEdgeColor = getBoardEdgeColor(this.board);
24299
24344
  this.boardGeom = (0, import_colors3.colorize)(
24300
24345
  [boardEdgeColor.r, boardEdgeColor.g, boardEdgeColor.b],
@@ -24542,8 +24587,8 @@ var ErrorBox = ({ parent }) => {
24542
24587
  import { su as su9 } from "@tscircuit/circuit-json-util";
24543
24588
  import { useEffect as useEffect26, useMemo as useMemo21 } from "react";
24544
24589
 
24545
- // src/textures/create-combined-board-textures.ts
24546
- import * as THREE42 from "three";
24590
+ // src/textures/open-via-holes-at-pads.ts
24591
+ import { CircuitToCanvasDrawer } from "circuit-to-canvas";
24547
24592
 
24548
24593
  // node_modules/@tscircuit/math-utils/dist/chunk-5N7UJNVK.js
24549
24594
  var getBoundsFromPoints = (points) => {
@@ -24595,9 +24640,111 @@ function calculateOutlineBounds(boardData) {
24595
24640
  };
24596
24641
  }
24597
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
+
24598
24745
  // src/utils/pad-texture.ts
24599
24746
  import { su as su6 } from "@tscircuit/circuit-json-util";
24600
- import { CircuitToCanvasDrawer } from "circuit-to-canvas";
24747
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
24601
24748
  import * as THREE30 from "three";
24602
24749
  function createPadTextureForLayer({
24603
24750
  layer,
@@ -24632,7 +24779,7 @@ function createPadTextureForLayer({
24632
24779
  ctx.scale(1, -1);
24633
24780
  }
24634
24781
  const transparent = "rgba(0,0,0,0)";
24635
- const drawer = new CircuitToCanvasDrawer(ctx);
24782
+ const drawer = new CircuitToCanvasDrawer2(ctx);
24636
24783
  drawer.configure({
24637
24784
  colorOverrides: {
24638
24785
  copper: {
@@ -24768,7 +24915,7 @@ function createPanelOutlineTextureForLayer({
24768
24915
 
24769
24916
  // src/utils/trace-texture.ts
24770
24917
  import * as THREE32 from "three";
24771
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
24918
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
24772
24919
  import { getElementRenderLayers, su as su8 } from "@tscircuit/circuit-json-util";
24773
24920
  function createTraceTextureForLayer({
24774
24921
  layer,
@@ -24806,7 +24953,7 @@ function createTraceTextureForLayer({
24806
24953
  ctx.scale(1, -1);
24807
24954
  }
24808
24955
  const transparent = "rgba(0,0,0,0)";
24809
- const drawer = new CircuitToCanvasDrawer2(ctx);
24956
+ const drawer = new CircuitToCanvasDrawer3(ctx);
24810
24957
  drawer.configure({
24811
24958
  colorOverrides: {
24812
24959
  copper: {
@@ -24863,7 +25010,7 @@ function createTraceTextureForLayer({
24863
25010
  }
24864
25011
 
24865
25012
  // src/textures/create-copper-pour-texture-for-layer.ts
24866
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer3 } from "circuit-to-canvas";
25013
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer4 } from "circuit-to-canvas";
24867
25014
  import * as THREE33 from "three";
24868
25015
  var toRgb = (colorArr) => {
24869
25016
  const [r = 0, g = 0, b = 0] = colorArr;
@@ -24920,7 +25067,7 @@ function createCopperPourTextureForLayer({
24920
25067
  const setColorAndDraw = (pours, copperPourColor) => {
24921
25068
  if (pours.length === 0) return;
24922
25069
  const elementsToDraw = [...pours, ...drillElements];
24923
- const drawer = new CircuitToCanvasDrawer3(ctx);
25070
+ const drawer = new CircuitToCanvasDrawer4(ctx);
24924
25071
  drawer.configure({
24925
25072
  colorOverrides: {
24926
25073
  copper: {
@@ -25001,7 +25148,7 @@ function createCopperPourTextureForLayer({
25001
25148
  import * as THREE34 from "three";
25002
25149
 
25003
25150
  // src/textures/copper-text/copper-text-drawing.ts
25004
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer4 } from "circuit-to-canvas";
25151
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer5 } from "circuit-to-canvas";
25005
25152
  var setDrawerBounds = (drawer, bounds) => {
25006
25153
  drawer.setCameraBounds({
25007
25154
  minX: bounds.minX,
@@ -25018,7 +25165,7 @@ var drawCopperTextLayer = ({
25018
25165
  copperColor
25019
25166
  }) => {
25020
25167
  const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25021
- const drawer = new CircuitToCanvasDrawer4(ctx);
25168
+ const drawer = new CircuitToCanvasDrawer5(ctx);
25022
25169
  drawer.configure({
25023
25170
  colorOverrides: {
25024
25171
  copper: {
@@ -25048,7 +25195,7 @@ var drawCopperTextLayer = ({
25048
25195
  maskCanvas.height = ctx.canvas.height;
25049
25196
  const maskCtx = maskCanvas.getContext("2d");
25050
25197
  if (!maskCtx) return;
25051
- const knockoutCutoutDrawer = new CircuitToCanvasDrawer4(maskCtx);
25198
+ const knockoutCutoutDrawer = new CircuitToCanvasDrawer5(maskCtx);
25052
25199
  knockoutCutoutDrawer.configure({
25053
25200
  colorOverrides: {
25054
25201
  copper: {
@@ -25126,7 +25273,7 @@ function createCopperTextTextureForLayer({
25126
25273
  import * as THREE35 from "three";
25127
25274
 
25128
25275
  // src/textures/fabrication-note/fabrication-note-drawing.ts
25129
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer5 } from "circuit-to-canvas";
25276
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
25130
25277
 
25131
25278
  // src/utils/units.ts
25132
25279
  var MM_PER_INCH = 25.4;
@@ -25224,7 +25371,7 @@ var drawFabricationNoteLayer = ({
25224
25371
  }) => {
25225
25372
  const renderLayer = `${layer}_fabrication_note`;
25226
25373
  const normalizedElements = elements.map(normalizeFabricationElement);
25227
- const drawer = new CircuitToCanvasDrawer5(ctx);
25374
+ const drawer = new CircuitToCanvasDrawer6(ctx);
25228
25375
  drawer.configure({
25229
25376
  colorOverrides: {
25230
25377
  copper: {
@@ -25366,7 +25513,7 @@ function createFabricationNoteTextureForLayer({
25366
25513
  import * as THREE36 from "three";
25367
25514
 
25368
25515
  // src/textures/keepout/keepout-drawing.ts
25369
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer6 } from "circuit-to-canvas";
25516
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer7 } from "circuit-to-canvas";
25370
25517
  var setDrawerBounds3 = (drawer, bounds) => {
25371
25518
  drawer.setCameraBounds({
25372
25519
  minX: bounds.minX,
@@ -25383,7 +25530,7 @@ var drawKeepoutLayer = ({
25383
25530
  keepoutColor
25384
25531
  }) => {
25385
25532
  const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25386
- const drawer = new CircuitToCanvasDrawer6(ctx);
25533
+ const drawer = new CircuitToCanvasDrawer7(ctx);
25387
25534
  drawer.configure({
25388
25535
  colorOverrides: {
25389
25536
  keepout: {
@@ -25451,7 +25598,7 @@ function createKeepoutTextureForLayer({
25451
25598
  import * as THREE37 from "three";
25452
25599
 
25453
25600
  // src/textures/pcb-note/pcb-note-drawing.ts
25454
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer7 } from "circuit-to-canvas";
25601
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer8 } from "circuit-to-canvas";
25455
25602
  var TRANSPARENT2 = "rgba(0,0,0,0)";
25456
25603
  var setDrawerBounds4 = (drawer, bounds) => {
25457
25604
  drawer.setCameraBounds({
@@ -25530,7 +25677,7 @@ var drawPcbNoteLayer = ({
25530
25677
  elements
25531
25678
  }) => {
25532
25679
  const normalizedElements = elements.map(normalizePcbNoteElement);
25533
- const drawer = new CircuitToCanvasDrawer7(ctx);
25680
+ const drawer = new CircuitToCanvasDrawer8(ctx);
25534
25681
  drawer.configure({
25535
25682
  colorOverrides: {
25536
25683
  copper: {
@@ -25615,7 +25762,7 @@ function createPcbNoteTextureForLayer({
25615
25762
  import * as THREE38 from "three";
25616
25763
 
25617
25764
  // src/textures/silkscreen/silkscreen-drawing.ts
25618
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer8 } from "circuit-to-canvas";
25765
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer9 } from "circuit-to-canvas";
25619
25766
  var FABRICATION_NOTE_COLOR2 = "rgb(255,243,204)";
25620
25767
  var TRANSPARENT3 = "rgba(0,0,0,0)";
25621
25768
  var isViaTented = (via, layer, board) => {
@@ -25652,7 +25799,7 @@ var drawSilkscreenLayer = ({
25652
25799
  soldermaskVisible
25653
25800
  }) => {
25654
25801
  const renderLayer = layer === "top" ? "top_silkscreen" : "bottom_silkscreen";
25655
- const drawer = new CircuitToCanvasDrawer8(ctx);
25802
+ const drawer = new CircuitToCanvasDrawer9(ctx);
25656
25803
  drawer.configure({
25657
25804
  colorOverrides: {
25658
25805
  copper: {
@@ -25776,7 +25923,7 @@ function createSilkscreenTextureForLayer({
25776
25923
  import * as THREE40 from "three";
25777
25924
 
25778
25925
  // src/textures/soldermask/soldermask-drawing.ts
25779
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer9 } from "circuit-to-canvas";
25926
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer10 } from "circuit-to-canvas";
25780
25927
  import * as THREE39 from "three";
25781
25928
  var toRgb2 = (colorArr) => {
25782
25929
  const [r = 0, g = 0, b = 0] = colorArr;
@@ -25839,7 +25986,7 @@ var drawSoldermaskLayer = ({
25839
25986
  }) => {
25840
25987
  const palette = getSoldermaskPalette(boardData);
25841
25988
  const copperRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25842
- const drawer = new CircuitToCanvasDrawer9(ctx);
25989
+ const drawer = new CircuitToCanvasDrawer10(ctx);
25843
25990
  drawer.configure({
25844
25991
  colorOverrides: {
25845
25992
  copper: {
@@ -25888,7 +26035,7 @@ var drawSoldermaskLayer = ({
25888
26035
  if (uncoveredPours.length > 0) {
25889
26036
  ctx.save();
25890
26037
  ctx.globalCompositeOperation = "destination-out";
25891
- const cutoutDrawer = new CircuitToCanvasDrawer9(ctx);
26038
+ const cutoutDrawer = new CircuitToCanvasDrawer10(ctx);
25892
26039
  cutoutDrawer.configure({
25893
26040
  colorOverrides: {
25894
26041
  copper: {
@@ -25952,7 +26099,7 @@ function createSoldermaskTextureForLayer({
25952
26099
  import * as THREE41 from "three";
25953
26100
 
25954
26101
  // src/textures/through-hole/through-hole-drawing.ts
25955
- import { CircuitToCanvasDrawer as CircuitToCanvasDrawer10 } from "circuit-to-canvas";
26102
+ import { CircuitToCanvasDrawer as CircuitToCanvasDrawer11 } from "circuit-to-canvas";
25956
26103
  var setDrawerBounds7 = (drawer, bounds) => {
25957
26104
  drawer.setCameraBounds({
25958
26105
  minX: bounds.minX,
@@ -25970,7 +26117,7 @@ var drawThroughHoleLayer = ({
25970
26117
  }) => {
25971
26118
  const renderLayer = layer === "top" ? "top_copper" : "bottom_copper";
25972
26119
  const transparent = "rgba(0,0,0,0)";
25973
- const drawer = new CircuitToCanvasDrawer10(ctx);
26120
+ const drawer = new CircuitToCanvasDrawer11(ctx);
25974
26121
  drawer.configure({
25975
26122
  colorOverrides: {
25976
26123
  copper: {
@@ -26110,7 +26257,8 @@ var createCombinedTexture = ({
26110
26257
  textures,
26111
26258
  boardData,
26112
26259
  traceTextureResolution,
26113
- layer
26260
+ layer,
26261
+ openViaHoles
26114
26262
  }) => {
26115
26263
  const hasImage = textures.some((texture) => texture?.image);
26116
26264
  if (!hasImage) return null;
@@ -26132,6 +26280,14 @@ var createCombinedTexture = ({
26132
26280
  const image = texture.image;
26133
26281
  ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
26134
26282
  }
26283
+ clearViaHolesFromSurface({
26284
+ ctx,
26285
+ vias: openViaHoles,
26286
+ boardData,
26287
+ layer,
26288
+ width: canvasWidth,
26289
+ height: canvasHeight
26290
+ });
26135
26291
  applySoldermaskSurfaceFilter(ctx, canvasWidth, canvasHeight, {
26136
26292
  includeReflection: layer === "top"
26137
26293
  });
@@ -26193,6 +26349,11 @@ function createCombinedBoardTextures({
26193
26349
  const silkscreenColor = "rgb(255,255,255)";
26194
26350
  const copperColor = toRgb3(colors.copper);
26195
26351
  const showBoardBody = visibility?.boardBody ?? true;
26352
+ const openViaHoles = getViaHolesAtExposedPads(
26353
+ circuitJson,
26354
+ boardData,
26355
+ traceTextureResolution
26356
+ );
26196
26357
  const buildForLayer = (layer) => {
26197
26358
  const showMask = (layer === "top" ? visibility?.topMask : visibility?.bottomMask) ?? true;
26198
26359
  const showCopper = (layer === "top" ? visibility?.topCopper : visibility?.bottomCopper) ?? true;
@@ -26281,6 +26442,7 @@ function createCombinedBoardTextures({
26281
26442
  traceTextureResolution
26282
26443
  }) : null;
26283
26444
  const boardTexture = createCombinedTexture({
26445
+ openViaHoles,
26284
26446
  textures: [
26285
26447
  copperPourTexture,
26286
26448
  traceTexture,
@@ -29546,11 +29708,13 @@ function createViaCopper2({
29546
29708
 
29547
29709
  // src/utils/manifold/process-vias.ts
29548
29710
  var COPPER_COLOR2 = new THREE51.Color(...colors.copper);
29549
- function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
29711
+ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume, otherHoleDrills = []) {
29550
29712
  const viaBoardDrills = [];
29551
29713
  const pcbVias = getPcbVias(circuitJson);
29552
29714
  const viaCopperGeoms = [];
29715
+ const copperOps = [];
29553
29716
  pcbVias.forEach((via, index2) => {
29717
+ let ownDrill;
29554
29718
  if (typeof via.hole_diameter === "number") {
29555
29719
  const translatedDrill = createPlatedHoleDrill({
29556
29720
  Manifold,
@@ -29563,6 +29727,7 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
29563
29727
  });
29564
29728
  manifoldInstancesForCleanup.push(translatedDrill);
29565
29729
  viaBoardDrills.push(translatedDrill);
29730
+ ownDrill = translatedDrill;
29566
29731
  }
29567
29732
  if (typeof via.outer_diameter === "number" && typeof via.hole_diameter === "number") {
29568
29733
  const translatedViaCopper = createViaCopper2({
@@ -29585,14 +29750,36 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
29585
29750
  manifoldInstancesForCleanup.push(clipped);
29586
29751
  finalCopperOp = clipped;
29587
29752
  }
29588
- const threeGeom = manifoldMeshToThreeGeometry(finalCopperOp.getMesh());
29589
- viaCopperGeoms.push({
29753
+ copperOps.push({
29590
29754
  key: `via-${via.pcb_via_id || index2}`,
29591
- geometry: threeGeom,
29592
- color: COPPER_COLOR2
29755
+ copper: finalCopperOp,
29756
+ ownDrill
29593
29757
  });
29594
29758
  }
29595
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
+ }
29596
29783
  return { viaBoardDrills, viaCopperGeoms };
29597
29784
  }
29598
29785
 
@@ -29746,7 +29933,8 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
29746
29933
  circuitJson,
29747
29934
  currentPcbThickness,
29748
29935
  manifoldInstancesForCleanup.current,
29749
- boardClipVolume
29936
+ boardClipVolume,
29937
+ allBoardDrills
29750
29938
  );
29751
29939
  allBoardDrills.push(...viaBoardDrills);
29752
29940
  currentGeoms.vias = viaCopperGeoms;
@@ -30612,15 +30800,13 @@ function createSlot(ownerName) {
30612
30800
  let slottableElement = null;
30613
30801
  let hasSlottable = false;
30614
30802
  const newChildren = [];
30615
- if (isLazyComponent(children) && typeof use === "function") {
30616
- children = use(children._payload);
30617
- }
30803
+ children = useUnwrappedLazy(children);
30618
30804
  React16.Children.forEach(children, (maybeSlottable) => {
30619
30805
  if (isSlottable(maybeSlottable)) {
30620
30806
  hasSlottable = true;
30621
30807
  const slottable = maybeSlottable;
30622
30808
  let child = "child" in slottable.props ? slottable.props.child : slottable.props.children;
30623
- if (isLazyComponent(child) && typeof use === "function") {
30809
+ while (isLazyComponent(child) && typeof use === "function") {
30624
30810
  child = use(child._payload);
30625
30811
  }
30626
30812
  slottableElement = getSlottableElementFromSlottable(slottable, child);
@@ -30671,9 +30857,8 @@ function createSlottable(ownerName) {
30671
30857
  __name6(createSlottable, "createSlottable");
30672
30858
  var getSlottableElementFromSlottable = /* @__PURE__ */ __name6((slottable, child) => {
30673
30859
  if ("child" in slottable.props) {
30674
- const child2 = slottable.props.child;
30675
- if (!React16.isValidElement(child2)) return null;
30676
- 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));
30677
30862
  }
30678
30863
  return React16.isValidElement(child) ? child : null;
30679
30864
  }, "getSlottableElementFromSlottable");
@@ -30731,6 +30916,14 @@ function isPromiseLike(value) {
30731
30916
  return typeof value === "object" && value !== null && "then" in value;
30732
30917
  }
30733
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");
30734
30927
  function concatAriaDescribedby(...values) {
30735
30928
  const ids = /* @__PURE__ */ new Set();
30736
30929
  for (const value of values) {
@@ -30878,54 +31071,37 @@ var OrderedDict = class _OrderedDict extends Map {
30878
31071
  __instanciated.set(this, true);
30879
31072
  }
30880
31073
  set(key, value) {
30881
- if (__instanciated.get(this)) {
30882
- if (this.has(key)) {
30883
- this.#keys[this.#keys.indexOf(key)] = key;
30884
- } else {
30885
- this.#keys.push(key);
30886
- }
31074
+ if (__instanciated.get(this) && !this.has(key)) {
31075
+ this.#keys.push(key);
30887
31076
  }
30888
31077
  super.set(key, value);
30889
31078
  return this;
30890
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
+ */
30891
31087
  insert(index2, key, value) {
30892
31088
  const has = this.has(key);
30893
- const length6 = this.#keys.length;
31089
+ const finalSize = has ? this.size : this.size + 1;
30894
31090
  const relativeIndex = toSafeInteger(index2);
30895
- let actualIndex = relativeIndex >= 0 ? relativeIndex : length6 + relativeIndex;
30896
- const safeIndex = actualIndex < 0 || actualIndex >= length6 ? -1 : actualIndex;
30897
- 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) {
30898
31093
  this.set(key, value);
30899
31094
  return this;
30900
31095
  }
30901
- const size4 = this.size + (has ? 0 : 1);
30902
- if (relativeIndex < 0) {
30903
- actualIndex++;
30904
- }
30905
- const keys = [...this.#keys];
30906
- let nextValue;
30907
- let shouldSkip = false;
30908
- for (let i = actualIndex; i < size4; i++) {
30909
- if (actualIndex === i) {
30910
- let nextKey = keys[i];
30911
- if (keys[i] === key) {
30912
- nextKey = keys[i + 1];
30913
- }
30914
- if (has) {
30915
- this.delete(key);
30916
- }
30917
- nextValue = this.get(nextKey);
30918
- this.set(key, value);
30919
- } else {
30920
- if (!shouldSkip && keys[i - 1] === key) {
30921
- shouldSkip = true;
30922
- }
30923
- const currentKey = keys[shouldSkip ? i : i - 1];
30924
- const currentValue = nextValue;
30925
- nextValue = this.get(currentKey);
30926
- this.delete(currentKey);
30927
- this.set(currentKey, currentValue);
30928
- }
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);
30929
31105
  }
30930
31106
  return this;
30931
31107
  }
@@ -30949,7 +31125,9 @@ var OrderedDict = class _OrderedDict extends Map {
30949
31125
  if (index2 === -1) {
30950
31126
  return this;
30951
31127
  }
30952
- 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);
30953
31131
  }
30954
31132
  after(key) {
30955
31133
  let index2 = this.#keys.indexOf(key);
@@ -30967,7 +31145,9 @@ var OrderedDict = class _OrderedDict extends Map {
30967
31145
  if (index2 === -1) {
30968
31146
  return this;
30969
31147
  }
30970
- 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);
30971
31151
  }
30972
31152
  first() {
30973
31153
  return this.entryAt(0);
@@ -31073,10 +31253,14 @@ var OrderedDict = class _OrderedDict extends Map {
31073
31253
  }
31074
31254
  reduce(...args) {
31075
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
+ }
31076
31260
  let index2 = 0;
31077
- let accumulator = initialValue ?? this.at(0);
31261
+ let accumulator = initialValue;
31078
31262
  for (const entry of this) {
31079
- if (index2 === 0 && args.length === 1) {
31263
+ if (index2 === 0 && !hasInitialValue) {
31080
31264
  accumulator = entry;
31081
31265
  } else {
31082
31266
  accumulator = Reflect.apply(callbackfn, this, [accumulator, entry, index2, this]);
@@ -31087,10 +31271,14 @@ var OrderedDict = class _OrderedDict extends Map {
31087
31271
  }
31088
31272
  reduceRight(...args) {
31089
31273
  const [callbackfn, initialValue] = args;
31090
- 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;
31091
31279
  for (let index2 = this.size - 1; index2 >= 0; index2--) {
31092
- const entry = this.at(index2);
31093
- if (index2 === this.size - 1 && args.length === 1) {
31280
+ const entry = this.entryAt(index2);
31281
+ if (index2 === this.size - 1 && !hasInitialValue) {
31094
31282
  accumulator = entry;
31095
31283
  } else {
31096
31284
  accumulator = Reflect.apply(callbackfn, this, [accumulator, entry, index2, this]);
@@ -31098,7 +31286,36 @@ var OrderedDict = class _OrderedDict extends Map {
31098
31286
  }
31099
31287
  return accumulator;
31100
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
+ */
31101
31315
  toSorted(compareFn) {
31316
+ if (typeof compareFn !== "function") {
31317
+ throw new TypeError(`OrderedDict.toSorted requires a compare function`);
31318
+ }
31102
31319
  const entries = [...this.entries()].sort(compareFn);
31103
31320
  return new _OrderedDict(entries);
31104
31321
  }
@@ -31118,20 +31335,8 @@ var OrderedDict = class _OrderedDict extends Map {
31118
31335
  }
31119
31336
  slice(start, end) {
31120
31337
  const result = new _OrderedDict();
31121
- let stop = this.size - 1;
31122
- if (start === void 0) {
31123
- return result;
31124
- }
31125
- if (start < 0) {
31126
- start = start + this.size;
31127
- }
31128
- if (end !== void 0 && end > 0) {
31129
- stop = end - 1;
31130
- }
31131
- for (let index2 = start; index2 <= stop; index2++) {
31132
- const key = this.keyAt(index2);
31133
- const element = this.get(key);
31134
- result.set(key, element);
31338
+ for (const key of this.#keys.slice(start, end)) {
31339
+ result.set(key, this.get(key));
31135
31340
  }
31136
31341
  return result;
31137
31342
  }
@@ -31179,16 +31384,10 @@ __name8(toSafeInteger, "toSafeInteger");
31179
31384
  function createCollection2(name) {
31180
31385
  const PROVIDER_NAME = name + "CollectionProvider";
31181
31386
  const [createCollectionContext, createCollectionScope3] = createContextScope(PROVIDER_NAME);
31182
- const [CollectionContextProvider, useCollectionContext] = createCollectionContext(
31183
- PROVIDER_NAME,
31184
- {
31185
- collectionElement: null,
31186
- collectionRef: { current: null },
31187
- collectionRefObject: { current: null },
31188
- itemMap: new OrderedDict(),
31189
- setItemMap: /* @__PURE__ */ __name8(() => void 0, "setItemMap")
31190
- }
31191
- );
31387
+ const [CollectionStableContextProvider, useStableCollectionContext] = createCollectionContext(PROVIDER_NAME);
31388
+ CollectionStableContextProvider.displayName = name + "CollectionStableContextProvider";
31389
+ const [CollectionStatefulContextProvider, useStatefulCollectionContext] = createCollectionContext(PROVIDER_NAME);
31390
+ CollectionStatefulContextProvider.displayName = name + "CollectionStatefulContextProvider";
31192
31391
  const CollectionProvider = /* @__PURE__ */ __name8(({ state, ...props }) => {
31193
31392
  return state ? /* @__PURE__ */ jsx23(CollectionProviderImpl, { ...props, state }) : /* @__PURE__ */ jsx23(CollectionInit, { ...props });
31194
31393
  }, "CollectionProvider");
@@ -31197,7 +31396,7 @@ function createCollection2(name) {
31197
31396
  const state = useInitCollection();
31198
31397
  return /* @__PURE__ */ jsx23(CollectionProviderImpl, { ...props, state });
31199
31398
  }, "CollectionInit");
31200
- CollectionInit.displayName = PROVIDER_NAME + "Init";
31399
+ CollectionInit.displayName = name + "CollectionInit";
31201
31400
  const CollectionProviderImpl = /* @__PURE__ */ __name8((props) => {
31202
31401
  const { scope, children, state } = props;
31203
31402
  const ref = React23.useRef(null);
@@ -31205,10 +31404,27 @@ function createCollection2(name) {
31205
31404
  null
31206
31405
  );
31207
31406
  const composeRefs2 = useComposedRefs(ref, setCollectionElement);
31208
- 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
+ }, []);
31209
31418
  React23.useEffect(() => {
31210
- if (!collectionElement) return;
31419
+ if (!collectionElement) {
31420
+ return;
31421
+ }
31211
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
+ });
31212
31428
  });
31213
31429
  observer.observe(collectionElement, {
31214
31430
  childList: true,
@@ -31217,28 +31433,36 @@ function createCollection2(name) {
31217
31433
  return () => {
31218
31434
  observer.disconnect();
31219
31435
  };
31220
- }, [collectionElement]);
31436
+ }, [collectionElement, setCollection]);
31221
31437
  return /* @__PURE__ */ jsx23(
31222
- CollectionContextProvider,
31438
+ CollectionStableContextProvider,
31223
31439
  {
31224
31440
  scope,
31225
- itemMap,
31226
- setItemMap,
31227
- collectionRef: composeRefs2,
31228
- collectionRefObject: ref,
31229
- collectionElement,
31230
- 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
+ )
31231
31455
  }
31232
31456
  );
31233
31457
  }, "CollectionProviderImpl");
31234
- CollectionProviderImpl.displayName = PROVIDER_NAME + "Impl";
31458
+ CollectionProviderImpl.displayName = name + "CollectionProviderImpl";
31235
31459
  const COLLECTION_SLOT_NAME = name + "CollectionSlot";
31236
31460
  const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
31237
31461
  const CollectionSlot = React23.forwardRef(
31238
31462
  (props, forwardedRef) => {
31239
31463
  const { scope, children } = props;
31240
- const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
31241
- const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
31464
+ const context = useStableCollectionContext(COLLECTION_SLOT_NAME, scope);
31465
+ const composedRefs = useComposedRefs(forwardedRef, context.collectionElementRef);
31242
31466
  return /* @__PURE__ */ jsx23(CollectionSlotImpl, { ref: composedRefs, children });
31243
31467
  }
31244
31468
  );
@@ -31250,37 +31474,71 @@ function createCollection2(name) {
31250
31474
  (props, forwardedRef) => {
31251
31475
  const { scope, children, ...itemData } = props;
31252
31476
  const ref = React23.useRef(null);
31253
- const [element, setElement] = React23.useState(null);
31254
- const composedRefs = useComposedRefs(forwardedRef, ref, setElement);
31255
- const context = useCollectionContext(ITEM_SLOT_NAME, scope);
31256
- const { setItemMap } = context;
31477
+ const context = useStableCollectionContext(ITEM_SLOT_NAME, scope);
31478
+ const { setCollection, registryRef } = context;
31257
31479
  const itemDataRef = React23.useRef(itemData);
31258
31480
  if (!shallowEqual(itemDataRef.current, itemData)) {
31259
31481
  itemDataRef.current = itemData;
31260
31482
  }
31261
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);
31262
31507
  React23.useEffect(() => {
31263
- const itemData2 = memoizedItemData;
31264
- setItemMap((map) => {
31265
- if (!element) {
31266
- 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);
31267
31518
  }
31268
- if (!map.has(element)) {
31269
- map.set(element, { ...itemData2, element });
31270
- return map.toSorted(sortByDocumentPosition);
31519
+ if (element) {
31520
+ next.set(element, { ...memoizedItemData, element });
31271
31521
  }
31272
- return map.set(element, { ...itemData2, element }).toSorted(sortByDocumentPosition);
31522
+ return next.sort(sortByDocumentPosition);
31273
31523
  });
31524
+ });
31525
+ React23.useEffect(() => {
31274
31526
  return () => {
31275
- setItemMap((map) => {
31276
- 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)) {
31277
31534
  return map;
31278
31535
  }
31279
- map.delete(element);
31280
- return new OrderedDict(map);
31536
+ const next = new OrderedDict(map);
31537
+ next.delete(registered.element);
31538
+ return next;
31281
31539
  });
31282
31540
  };
31283
- }, [element, memoizedItemData, setItemMap]);
31541
+ }, [setCollection]);
31284
31542
  return /* @__PURE__ */ jsx23(CollectionItemSlotImpl, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
31285
31543
  }
31286
31544
  );
@@ -31290,13 +31548,19 @@ function createCollection2(name) {
31290
31548
  }
31291
31549
  __name8(useInitCollection, "useInitCollection");
31292
31550
  function useCollection3(scope) {
31293
- const { itemMap } = useCollectionContext(name + "CollectionConsumer", scope);
31294
- return itemMap;
31551
+ const { collection } = useStatefulCollectionContext(name + "CollectionConsumer", scope);
31552
+ return collection;
31295
31553
  }
31296
31554
  __name8(useCollection3, "useCollection");
31555
+ function useGetCollection(scope) {
31556
+ const { getCollection } = useStableCollectionContext(name + "CollectionConsumer", scope);
31557
+ return getCollection;
31558
+ }
31559
+ __name8(useGetCollection, "useGetCollection");
31297
31560
  const functions = {
31298
31561
  createCollectionScope: createCollectionScope3,
31299
31562
  useCollection: useCollection3,
31563
+ useGetCollection,
31300
31564
  useInitCollection
31301
31565
  };
31302
31566
  return [
@@ -31323,6 +31587,20 @@ function isElementPreceding(a, b) {
31323
31587
  return !!(b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING);
31324
31588
  }
31325
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");
31326
31604
  function sortByDocumentPosition(a, b) {
31327
31605
  return !a[1].element || !b[1].element ? 0 : isElementPreceding(a[1].element, b[1].element) ? -1 : 1;
31328
31606
  }
@@ -31363,11 +31641,18 @@ import * as React21 from "react";
31363
31641
  import * as React20 from "react";
31364
31642
  var __defProp11 = Object.defineProperty;
31365
31643
  var __name10 = (target, value) => __defProp11(target, "name", { value, configurable: true });
31644
+ var useReactInsertionEffect2 = React20[" useInsertionEffect ".trim().toString()];
31366
31645
  function useCallbackRef(callback) {
31367
31646
  const callbackRef = React20.useRef(callback);
31368
- React20.useEffect(() => {
31369
- callbackRef.current = callback;
31370
- });
31647
+ if (typeof useReactInsertionEffect2 === "function") {
31648
+ useReactInsertionEffect2(() => {
31649
+ callbackRef.current = callback;
31650
+ });
31651
+ } else {
31652
+ useLayoutEffect2(() => {
31653
+ callbackRef.current = callback;
31654
+ });
31655
+ }
31371
31656
  return React20.useMemo(() => ((...args) => callbackRef.current?.(...args)), []);
31372
31657
  }
31373
31658
  __name10(useCallbackRef, "useCallbackRef");
@@ -31853,12 +32138,14 @@ var FocusScope = /* @__PURE__ */ React25.forwardRef(
31853
32138
  }
31854
32139
  return () => {
31855
32140
  container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
32141
+ const ownerDocument = container.ownerDocument;
32142
+ const UnmountEvent = CustomEvent;
31856
32143
  setTimeout(() => {
31857
- const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
32144
+ const unmountEvent = new UnmountEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
31858
32145
  container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
31859
32146
  container.dispatchEvent(unmountEvent);
31860
32147
  if (!unmountEvent.defaultPrevented) {
31861
- focus(previouslyFocusedElement ?? document.body, { select: true });
32148
+ focus(previouslyFocusedElement ?? ownerDocument.body, { select: true });
31862
32149
  }
31863
32150
  container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
31864
32151
  focusScopesStack.remove(focusScope);
@@ -31940,14 +32227,19 @@ function getTabbableEdges(container) {
31940
32227
  __name13(getTabbableEdges, "getTabbableEdges");
31941
32228
  function getTabbableCandidates(container) {
31942
32229
  const nodes = [];
31943
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
32230
+ const document2 = container.ownerDocument;
32231
+ const walker = document2.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
31944
32232
  acceptNode: /* @__PURE__ */ __name13((node) => {
31945
32233
  const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
31946
- if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
32234
+ if (node.disabled || node.hidden || isHiddenInput) {
32235
+ return NodeFilter.FILTER_SKIP;
32236
+ }
31947
32237
  return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
31948
32238
  }, "acceptNode")
31949
32239
  });
31950
- while (walker.nextNode()) nodes.push(walker.currentNode);
32240
+ while (walker.nextNode()) {
32241
+ nodes.push(walker.currentNode);
32242
+ }
31951
32243
  return nodes;
31952
32244
  }
31953
32245
  __name13(getTabbableCandidates, "getTabbableCandidates");
@@ -31972,12 +32264,13 @@ function isHidden(node, { upTo }) {
31972
32264
  }
31973
32265
  __name13(isHidden, "isHidden");
31974
32266
  function isSelectableInput(element) {
31975
- return element instanceof HTMLInputElement && "select" in element;
32267
+ return element.tagName === "INPUT" && typeof element.select === "function";
31976
32268
  }
31977
32269
  __name13(isSelectableInput, "isSelectableInput");
31978
32270
  function focus(element, { select = false } = {}) {
31979
32271
  if (element && element.focus) {
31980
- const previouslyFocusedElement = document.activeElement;
32272
+ const ownerDocument = element.ownerDocument ?? document;
32273
+ const previouslyFocusedElement = ownerDocument.activeElement;
31981
32274
  element.focus({ preventScroll: true });
31982
32275
  if (element !== previouslyFocusedElement && isSelectableInput(element) && select)
31983
32276
  element.select();
@@ -34113,7 +34406,9 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
34113
34406
  avoidCollisions && shift3({
34114
34407
  mainAxis: true,
34115
34408
  crossAxis: false,
34116
- 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() } : {},
34117
34412
  ...detectOverflowOptions
34118
34413
  }),
34119
34414
  avoidCollisions && flip3({ ...detectOverflowOptions }),
@@ -34130,18 +34425,22 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
34130
34425
  }),
34131
34426
  arrow4 && arrow3({ element: arrow4, padding: arrowPadding }),
34132
34427
  transformOrigin({ arrowWidth, arrowHeight }),
34133
- hideWhenDetached && hide3({
34134
- strategy: "referenceHidden",
34135
- ...detectOverflowOptions,
34136
- // `hide` detects whether the anchor (reference) is clipped, so when
34137
- // no explicit `collisionBoundary` is set we fall back to Floating
34138
- // UI's default clipping ancestors (e.g. a scrollable menu). This
34139
- // lets an occluded submenu hide once its anchor scrolls out of view
34140
- // (#3237). The collision/size middlewares deliberately keep the
34141
- // viewport-based default to avoid clamping content rendered inside
34142
- // transformed or overflow-clipping portal containers.
34143
- boundary: hasExplicitBoundaries ? detectOverflowOptions.boundary : void 0
34144
- })
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
+ )
34145
34444
  ]
34146
34445
  });
34147
34446
  const setPlacementState = context.setPlacementState;
@@ -35783,11 +36082,13 @@ var MenuContentImpl = /* @__PURE__ */ React41.forwardRef(
35783
36082
  const values = items.map((item) => item.textValue);
35784
36083
  const nextMatch = getNextMatch(values, search, currentMatch);
35785
36084
  const newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
35786
- (/* @__PURE__ */ __name21((function updateSearch(value) {
36085
+ function updateSearch(value) {
35787
36086
  searchRef.current = value;
35788
36087
  window.clearTimeout(timerRef.current);
35789
36088
  if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
35790
- }), "updateSearch"))(search);
36089
+ }
36090
+ __name21(updateSearch, "updateSearch");
36091
+ updateSearch(search);
35791
36092
  if (newItem) {
35792
36093
  setTimeout(() => newItem.focus());
35793
36094
  }
@@ -37570,10 +37871,10 @@ var ContextMenu = ({
37570
37871
  };
37571
37872
 
37572
37873
  // src/components/KeyboardShortcutsDialog.tsx
37573
- 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";
37574
37875
 
37575
37876
  // src/hooks/useRegisteredHotkey.ts
37576
- 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";
37577
37878
  var hotkeyRegistry = /* @__PURE__ */ new Map();
37578
37879
  var subscribers = /* @__PURE__ */ new Set();
37579
37880
  var isListenerAttached = false;
@@ -37704,7 +38005,7 @@ var useRegisteredHotkey = (id, handler, metadata) => {
37704
38005
  }),
37705
38006
  [metadata.shortcut, metadata.description]
37706
38007
  );
37707
- useEffect48(() => {
38008
+ useEffect47(() => {
37708
38009
  const registration = {
37709
38010
  id,
37710
38011
  ...normalizedMetadata,
@@ -37720,7 +38021,7 @@ var useHotkeyRegistry = () => {
37720
38021
  const [entries, setEntries] = useState39(
37721
38022
  () => Array.from(hotkeyRegistry.values())
37722
38023
  );
37723
- useEffect48(() => subscribeToRegistry(setEntries), []);
38024
+ useEffect47(() => subscribeToRegistry(setEntries), []);
37724
38025
  return entries;
37725
38026
  };
37726
38027
  var registerHotkeyViewer = (element) => {
@@ -37737,7 +38038,7 @@ var KeyboardShortcutsDialog = ({
37737
38038
  const [query, setQuery] = useState40("");
37738
38039
  const inputRef = useRef27(null);
37739
38040
  const hotkeys = useHotkeyRegistry();
37740
- useEffect49(() => {
38041
+ useEffect48(() => {
37741
38042
  if (!open) return void 0;
37742
38043
  const handleKeyDown = (event) => {
37743
38044
  if (event.key === "Escape") {
@@ -37748,7 +38049,7 @@ var KeyboardShortcutsDialog = ({
37748
38049
  window.addEventListener("keydown", handleKeyDown);
37749
38050
  return () => window.removeEventListener("keydown", handleKeyDown);
37750
38051
  }, [open, onClose]);
37751
- useEffect49(() => {
38052
+ useEffect48(() => {
37752
38053
  if (open) {
37753
38054
  setTimeout(() => {
37754
38055
  inputRef.current?.focus();
@@ -37937,7 +38238,7 @@ var ToastProvider = ({
37937
38238
  };
37938
38239
 
37939
38240
  // src/hooks/useCameraPreset.ts
37940
- import { useCallback as useCallback21 } from "react";
38241
+ import { useCallback as useCallback22 } from "react";
37941
38242
  function useCameraPreset({
37942
38243
  setAutoRotate,
37943
38244
  setAutoRotateUserToggled,
@@ -37947,7 +38248,7 @@ function useCameraPreset({
37947
38248
  isAnimatingRef,
37948
38249
  lastPresetSelectTime
37949
38250
  }) {
37950
- const handleCameraPresetSelect = useCallback21(
38251
+ const handleCameraPresetSelect = useCallback22(
37951
38252
  (preset) => {
37952
38253
  setAutoRotate(false);
37953
38254
  setAutoRotateUserToggled(true);
@@ -37977,7 +38278,7 @@ function useCameraPreset({
37977
38278
  }
37978
38279
 
37979
38280
  // src/hooks/useContextMenu.ts
37980
- 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";
37981
38282
  var useContextMenu = ({ containerRef, onOpen }) => {
37982
38283
  const [menuVisible, setMenuVisible] = useState41(false);
37983
38284
  const [menuPos, setMenuPos] = useState41({
@@ -37994,7 +38295,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
37994
38295
  longPressTimeoutRef.current = null;
37995
38296
  }
37996
38297
  };
37997
- const handleContextMenu = useCallback22(
38298
+ const handleContextMenu = useCallback23(
37998
38299
  (e) => {
37999
38300
  e.preventDefault();
38000
38301
  const eventX = typeof e.clientX === "number" ? e.clientX : 0;
@@ -38021,7 +38322,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38021
38322
  },
38022
38323
  [setMenuPos, setMenuVisible, onOpen]
38023
38324
  );
38024
- const handleTouchStart = useCallback22(
38325
+ const handleTouchStart = useCallback23(
38025
38326
  (e) => {
38026
38327
  if (e.touches.length === 1) {
38027
38328
  const touch = e.touches[0];
@@ -38055,7 +38356,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38055
38356
  },
38056
38357
  [containerRef, onOpen]
38057
38358
  );
38058
- const handleTouchMove = useCallback22((e) => {
38359
+ const handleTouchMove = useCallback23((e) => {
38059
38360
  if (!interactionOriginPosRef.current || e.touches.length !== 1) {
38060
38361
  return;
38061
38362
  }
@@ -38073,7 +38374,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38073
38374
  clearLongPressTimeout();
38074
38375
  }
38075
38376
  }, []);
38076
- const handleTouchEnd = useCallback22(() => {
38377
+ const handleTouchEnd = useCallback23(() => {
38077
38378
  clearLongPressTimeout();
38078
38379
  setTimeout(() => {
38079
38380
  if (interactionOriginPosRef.current) {
@@ -38081,7 +38382,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38081
38382
  }
38082
38383
  }, 0);
38083
38384
  }, []);
38084
- const handleClickAway = useCallback22((e) => {
38385
+ const handleClickAway = useCallback23((e) => {
38085
38386
  const target = e.target;
38086
38387
  if (menuRef.current && menuRef.current.contains(target)) {
38087
38388
  return;
@@ -38094,7 +38395,7 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38094
38395
  }
38095
38396
  setMenuVisible(false);
38096
38397
  }, []);
38097
- useEffect50(() => {
38398
+ useEffect49(() => {
38098
38399
  if (menuVisible) {
38099
38400
  document.addEventListener("mousedown", handleClickAway);
38100
38401
  document.addEventListener("touchstart", handleClickAway);
@@ -38128,10 +38429,10 @@ var useContextMenu = ({ containerRef, onOpen }) => {
38128
38429
  };
38129
38430
 
38130
38431
  // src/hooks/useGlobalDownloadGltf.ts
38131
- import { useCallback as useCallback23 } from "react";
38432
+ import { useCallback as useCallback24 } from "react";
38132
38433
  import { GLTFExporter as GLTFExporter2 } from "three-stdlib";
38133
38434
  var useGlobalDownloadGltf = () => {
38134
- return useCallback23(() => {
38435
+ return useCallback24(() => {
38135
38436
  const root = window.__TSCIRCUIT_THREE_OBJECT;
38136
38437
  if (!root) return;
38137
38438
  const exporter = new GLTFExporter2();
@@ -38209,7 +38510,7 @@ var CadViewerInner = (props) => {
38209
38510
  const sceneRef = useContext11(SchematicNavigationContext);
38210
38511
  const [selectedComponent, setSelectedComponent] = useState42();
38211
38512
  const [selectedCadComponent, setSelectedCadComponent] = useState42();
38212
- const handleMenuOpen = useCallback24(
38513
+ const handleMenuOpen = useCallback25(
38213
38514
  (position) => {
38214
38515
  setSelectedCadComponent(
38215
38516
  pickCadComponent(sceneRef.current, position, circuitJson)
@@ -38232,7 +38533,7 @@ var CadViewerInner = (props) => {
38232
38533
  const isAnimatingRef = useRef29(false);
38233
38534
  const lastPresetSelectTime = useRef29(0);
38234
38535
  const PRESET_COOLDOWN = 1e3;
38235
- const handleUserInteraction = useCallback24(() => {
38536
+ const handleUserInteraction = useCallback25(() => {
38236
38537
  if (isAnimatingRef.current || Date.now() - lastPresetSelectTime.current < PRESET_COOLDOWN) {
38237
38538
  return;
38238
38539
  }
@@ -38243,15 +38544,15 @@ var CadViewerInner = (props) => {
38243
38544
  setCameraPreset("Custom");
38244
38545
  }
38245
38546
  }, [menuVisible]);
38246
- const toggleAutoRotate = useCallback24(() => {
38547
+ const toggleAutoRotate = useCallback25(() => {
38247
38548
  setAutoRotate((prev) => !prev);
38248
38549
  setAutoRotateUserToggled(true);
38249
38550
  }, []);
38250
38551
  const downloadGltf = useGlobalDownloadGltf();
38251
- const closeMenu = useCallback24(() => {
38552
+ const closeMenu = useCallback25(() => {
38252
38553
  setMenuVisible(false);
38253
38554
  }, [setMenuVisible]);
38254
- const handleCameraControllerReady = useCallback24(
38555
+ const handleCameraControllerReady = useCallback25(
38255
38556
  (controller) => {
38256
38557
  cameraControllerRef.current = controller;
38257
38558
  externalCameraControllerReady?.(controller);
@@ -38325,24 +38626,24 @@ var CadViewerInner = (props) => {
38325
38626
  description: "Toggle translucent components"
38326
38627
  }
38327
38628
  );
38328
- useEffect51(() => {
38629
+ useEffect50(() => {
38329
38630
  if (containerRef.current) {
38330
38631
  registerHotkeyViewer(containerRef.current);
38331
38632
  }
38332
38633
  }, []);
38333
- useEffect51(() => {
38634
+ useEffect50(() => {
38334
38635
  window.localStorage.setItem("cadViewerEngine", engine);
38335
38636
  }, [engine]);
38336
- useEffect51(() => {
38637
+ useEffect50(() => {
38337
38638
  window.localStorage.setItem("cadViewerAutoRotate", String(autoRotate));
38338
38639
  }, [autoRotate]);
38339
- useEffect51(() => {
38640
+ useEffect50(() => {
38340
38641
  window.localStorage.setItem(
38341
38642
  "cadViewerAutoRotateUserToggled",
38342
38643
  String(autoRotateUserToggled)
38343
38644
  );
38344
38645
  }, [autoRotateUserToggled]);
38345
- useEffect51(() => {
38646
+ useEffect50(() => {
38346
38647
  window.localStorage.setItem("cadViewerCameraType", cameraType);
38347
38648
  }, [cameraType]);
38348
38649
  const viewerKey = props.circuitJson ? circuitKey : void 0;
@@ -38781,7 +39082,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
38781
39082
 
38782
39083
  // src/hooks/exporter/gltf.ts
38783
39084
  import { GLTFExporter as GLTFExporter3 } from "three-stdlib";
38784
- 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";
38785
39086
  function useSaveGltfAs(options = {}) {
38786
39087
  const parse2 = useParser(options);
38787
39088
  const link = useMemo37(() => document.createElement("a"), []);
@@ -38794,7 +39095,7 @@ function useSaveGltfAs(options = {}) {
38794
39095
  link.dispatchEvent(new MouseEvent("click"));
38795
39096
  URL.revokeObjectURL(url);
38796
39097
  };
38797
- useEffect52(
39098
+ useEffect51(
38798
39099
  () => () => {
38799
39100
  link.remove();
38800
39101
  instance = null;
@@ -38802,7 +39103,7 @@ function useSaveGltfAs(options = {}) {
38802
39103
  []
38803
39104
  );
38804
39105
  let instance;
38805
- const ref = useCallback25((obj3D) => {
39106
+ const ref = useCallback26((obj3D) => {
38806
39107
  instance = obj3D;
38807
39108
  }, []);
38808
39109
  return [ref, saveAs];
@@ -38811,11 +39112,11 @@ function useExportGltfUrl(options = {}) {
38811
39112
  const parse2 = useParser(options);
38812
39113
  const [url, setUrl] = useState43();
38813
39114
  const [error, setError] = useState43();
38814
- const ref = useCallback25(
39115
+ const ref = useCallback26(
38815
39116
  (instance) => parse2(instance).then(setUrl).catch(setError),
38816
39117
  []
38817
39118
  );
38818
- useEffect52(() => () => URL.revokeObjectURL(url), [url]);
39119
+ useEffect51(() => () => URL.revokeObjectURL(url), [url]);
38819
39120
  return [ref, url, error];
38820
39121
  }
38821
39122
  function useParser(options = {}) {