@tscircuit/3d-viewer 0.0.433 → 0.0.435

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 (3) hide show
  1. package/dist/index.d.ts +50 -1
  2. package/dist/index.js +1280 -1034
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14228,11 +14228,12 @@ var require_browser = __commonJS({
14228
14228
  });
14229
14229
 
14230
14230
  // src/CadViewer.tsx
14231
- import { useState as useState33, useCallback as useCallback20, useRef as useRef23, useEffect as useEffect39 } from "react";
14231
+ import { useState as useState34, useCallback as useCallback22, useRef as useRef24, useEffect as useEffect40, useMemo as useMemo26 } from "react";
14232
+ import * as THREE29 from "three";
14232
14233
 
14233
14234
  // src/CadViewerJscad.tsx
14234
- import { su as su4 } from "@tscircuit/circuit-json-util";
14235
- import { forwardRef as forwardRef3, useMemo as useMemo19 } from "react";
14235
+ import { su as su6 } from "@tscircuit/circuit-json-util";
14236
+ import { forwardRef as forwardRef3, useMemo as useMemo18 } from "react";
14236
14237
 
14237
14238
  // src/AnyCadComponent.tsx
14238
14239
  import { su } from "@tscircuit/circuit-json-util";
@@ -28168,13 +28169,13 @@ var AnyCadComponent = ({
28168
28169
  };
28169
28170
 
28170
28171
  // src/CadViewerContainer.tsx
28171
- import { forwardRef as forwardRef2, useMemo as useMemo15, useRef as useRef6, useState as useState8 } from "react";
28172
- import * as THREE14 from "three";
28172
+ import { forwardRef as forwardRef2, useEffect as useEffect16, useMemo as useMemo13, useState as useState9 } from "react";
28173
+ import * as THREE15 from "three";
28173
28174
 
28174
28175
  // package.json
28175
28176
  var package_default = {
28176
28177
  name: "@tscircuit/3d-viewer",
28177
- version: "0.0.432",
28178
+ version: "0.0.434",
28178
28179
  main: "./dist/index.js",
28179
28180
  module: "./dist/index.js",
28180
28181
  type: "module",
@@ -28253,194 +28254,15 @@ var package_default = {
28253
28254
  }
28254
28255
  };
28255
28256
 
28256
- // src/three-components/cube-with-labeled-sides.tsx
28257
- import { useEffect as useEffect11, useMemo as useMemo9 } from "react";
28258
- import * as THREE8 from "three";
28259
-
28260
- // src/react-three/Text.tsx
28261
- import { useEffect as useEffect10, useMemo as useMemo8 } from "react";
28262
- import { Text as TroikaText } from "troika-three-text";
28263
- var Text = ({
28264
- children,
28265
- parent,
28266
- position,
28267
- rotation: rotation2,
28268
- scale: scale2,
28269
- color,
28270
- fontSize,
28271
- anchorX,
28272
- anchorY,
28273
- depthOffset
28274
- }) => {
28275
- const { rootObject } = useThree();
28276
- const mesh = useMemo8(() => {
28277
- const textMesh = new TroikaText();
28278
- textMesh.text = children;
28279
- if (position) textMesh.position.fromArray(position);
28280
- if (rotation2) textMesh.rotation.fromArray(rotation2);
28281
- if (scale2) textMesh.scale.fromArray(scale2);
28282
- textMesh.color = color || "white";
28283
- textMesh.fontSize = fontSize || 1;
28284
- textMesh.anchorX = anchorX || "center";
28285
- textMesh.anchorY = anchorY || "middle";
28286
- textMesh.depthOffset = depthOffset || 0;
28287
- textMesh.font = null;
28288
- textMesh.sync();
28289
- return textMesh;
28290
- }, [
28291
- children,
28292
- position,
28293
- rotation2,
28294
- scale2,
28295
- color,
28296
- fontSize,
28297
- anchorX,
28298
- anchorY,
28299
- depthOffset
28300
- ]);
28301
- useEffect10(() => {
28302
- const parentObject = parent || rootObject;
28303
- if (!parentObject || !mesh) return;
28304
- parentObject.add(mesh);
28305
- return () => {
28306
- parentObject.remove(mesh);
28307
- mesh.dispose();
28308
- };
28309
- }, [rootObject, parent, mesh]);
28310
- return null;
28311
- };
28312
-
28313
- // src/three-components/cube-with-labeled-sides.tsx
28314
- import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
28315
- if (typeof window !== "undefined") {
28316
- window.TSCI_MAIN_CAMERA_ROTATION = new THREE8.Euler(0, 0, 0);
28317
- }
28318
- function computePointInFront(rotationVector, distance2) {
28319
- const quaternion = new THREE8.Quaternion().setFromEuler(
28320
- new THREE8.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
28321
- );
28322
- const forwardVector = new THREE8.Vector3(0, 0, 1);
28323
- forwardVector.applyQuaternion(quaternion);
28324
- const result = forwardVector.multiplyScalar(distance2);
28325
- return result;
28326
- }
28327
- var CubeWithLabeledSides = ({}) => {
28328
- const { camera, scene } = useThree();
28329
- useEffect11(() => {
28330
- if (!scene) return;
28331
- const ambientLight = new THREE8.AmbientLight(16777215, Math.PI / 2);
28332
- scene.add(ambientLight);
28333
- return () => {
28334
- scene.remove(ambientLight);
28335
- };
28336
- }, [scene]);
28337
- useFrame(() => {
28338
- if (!camera) return;
28339
- const mainRot = window.TSCI_MAIN_CAMERA_ROTATION;
28340
- const cameraPosition = computePointInFront(mainRot, 2);
28341
- camera.position.copy(cameraPosition);
28342
- camera.lookAt(0, 0, 0);
28343
- });
28344
- const group = useMemo9(() => {
28345
- const g = new THREE8.Group();
28346
- g.rotation.fromArray([Math.PI / 2, 0, 0]);
28347
- const box = new THREE8.Mesh(
28348
- new THREE8.BoxGeometry(1, 1, 1),
28349
- new THREE8.MeshStandardMaterial({ color: "white" })
28350
- );
28351
- g.add(box);
28352
- const edges = new THREE8.LineSegments(
28353
- new THREE8.EdgesGeometry(new THREE8.BoxGeometry(1, 1, 1)),
28354
- new THREE8.LineBasicMaterial({ color: 0, linewidth: 2 })
28355
- );
28356
- g.add(edges);
28357
- return g;
28358
- }, []);
28359
- useEffect11(() => {
28360
- if (!scene) return;
28361
- scene.add(group);
28362
- return () => {
28363
- scene.remove(group);
28364
- };
28365
- }, [scene, group]);
28366
- return /* @__PURE__ */ jsxs3(Fragment4, { children: [
28367
- /* @__PURE__ */ jsx10(
28368
- Text,
28369
- {
28370
- parent: group,
28371
- position: [0, 0, 0.51],
28372
- fontSize: 0.25,
28373
- color: "black",
28374
- children: "Front"
28375
- }
28376
- ),
28377
- /* @__PURE__ */ jsx10(
28378
- Text,
28379
- {
28380
- parent: group,
28381
- position: [0, 0, -0.51],
28382
- fontSize: 0.25,
28383
- color: "black",
28384
- rotation: [0, Math.PI, 0],
28385
- children: "Back"
28386
- }
28387
- ),
28388
- /* @__PURE__ */ jsx10(
28389
- Text,
28390
- {
28391
- parent: group,
28392
- position: [0.51, 0, 0],
28393
- fontSize: 0.25,
28394
- color: "black",
28395
- rotation: [0, Math.PI / 2, 0],
28396
- children: "Right"
28397
- }
28398
- ),
28399
- /* @__PURE__ */ jsx10(
28400
- Text,
28401
- {
28402
- parent: group,
28403
- position: [-0.51, 0, 0],
28404
- fontSize: 0.25,
28405
- color: "black",
28406
- rotation: [0, -Math.PI / 2, 0],
28407
- children: "Left"
28408
- }
28409
- ),
28410
- /* @__PURE__ */ jsx10(
28411
- Text,
28412
- {
28413
- parent: group,
28414
- position: [0, 0.51, 0],
28415
- fontSize: 0.25,
28416
- color: "black",
28417
- rotation: [-Math.PI / 2, 0, 0],
28418
- children: "Top"
28419
- }
28420
- ),
28421
- /* @__PURE__ */ jsx10(
28422
- Text,
28423
- {
28424
- parent: group,
28425
- position: [0, -0.51, 0],
28426
- fontSize: 0.25,
28427
- color: "black",
28428
- rotation: [Math.PI / 2, 0, 0],
28429
- children: "Bottom"
28430
- }
28431
- )
28432
- ] });
28433
- };
28434
-
28435
28257
  // src/react-three/Canvas.tsx
28436
28258
  import {
28437
28259
  useRef as useRef4,
28438
- useEffect as useEffect12,
28439
- useState as useState7,
28440
- useCallback as useCallback4,
28260
+ useEffect as useEffect10,
28261
+ useState as useState8,
28262
+ useCallback as useCallback5,
28441
28263
  forwardRef,
28442
28264
  useImperativeHandle,
28443
- useMemo as useMemo10
28265
+ useMemo as useMemo9
28444
28266
  } from "react";
28445
28267
  import * as THREE10 from "three";
28446
28268
 
@@ -28450,158 +28272,388 @@ function removeExistingCanvases(container) {
28450
28272
  }
28451
28273
 
28452
28274
  // src/react-three/configure-renderer.ts
28453
- import * as THREE9 from "three";
28275
+ import * as THREE8 from "three";
28454
28276
  var configureRenderer = (renderer) => {
28455
- renderer.outputColorSpace = THREE9.SRGBColorSpace;
28456
- renderer.toneMapping = THREE9.ACESFilmicToneMapping;
28277
+ renderer.outputColorSpace = THREE8.SRGBColorSpace;
28278
+ renderer.toneMapping = THREE8.ACESFilmicToneMapping;
28457
28279
  renderer.toneMappingExposure = 1;
28458
28280
  };
28459
28281
 
28460
- // src/react-three/Canvas.tsx
28461
- import { jsx as jsx11 } from "react/jsx-runtime";
28462
- var Canvas = forwardRef(
28463
- ({ children, scene: sceneProps, camera: cameraProps, style, onCreated }, ref) => {
28464
- const mountRef = useRef4(null);
28465
- const [contextState, setContextState] = useState7(
28466
- null
28467
- );
28468
- const frameListeners = useRef4(
28469
- []
28470
- );
28471
- const onCreatedRef = useRef4(void 0);
28472
- onCreatedRef.current = onCreated;
28473
- const addFrameListener = useCallback4(
28474
- (listener) => {
28475
- frameListeners.current.push(listener);
28476
- },
28477
- []
28478
- );
28479
- const removeFrameListener = useCallback4(
28480
- (listener) => {
28481
- frameListeners.current = frameListeners.current.filter(
28482
- (l) => l !== listener
28483
- );
28484
- },
28485
- []
28486
- );
28487
- const scene = useMemo10(() => new THREE10.Scene(), []);
28488
- if (sceneProps?.up) {
28489
- scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
28282
+ // src/contexts/CameraControllerContext.tsx
28283
+ import {
28284
+ createContext as createContext4,
28285
+ useCallback as useCallback4,
28286
+ useContext as useContext4,
28287
+ useMemo as useMemo8,
28288
+ useRef as useRef3,
28289
+ useState as useState7
28290
+ } from "react";
28291
+ import * as THREE9 from "three";
28292
+ import { jsx as jsx10 } from "react/jsx-runtime";
28293
+ var CAMERA_KEY = "cadViewerCameraStateSession";
28294
+ var saveCameraToSession = (camera, controls) => {
28295
+ try {
28296
+ const savedCameraSession = {
28297
+ position: camera.position.toArray(),
28298
+ quaternion: camera.quaternion.toArray(),
28299
+ up: camera.up.toArray(),
28300
+ fov: camera.fov ?? 50,
28301
+ target: controls.target.toArray()
28302
+ };
28303
+ sessionStorage.setItem(CAMERA_KEY, JSON.stringify(savedCameraSession));
28304
+ } catch (err) {
28305
+ console.warn("Failed to save camera:", err);
28306
+ }
28307
+ };
28308
+ var loadCameraFromSession = (camera, controls) => {
28309
+ try {
28310
+ const raw = sessionStorage.getItem(CAMERA_KEY);
28311
+ if (!raw) return false;
28312
+ const state = JSON.parse(raw);
28313
+ camera.position.fromArray(state.position);
28314
+ camera.quaternion.fromArray(state.quaternion);
28315
+ camera.up.fromArray(state.up);
28316
+ if ("fov" in camera) {
28317
+ const persp = camera;
28318
+ persp.fov = state.fov;
28319
+ persp.updateProjectionMatrix?.();
28490
28320
  }
28491
- const rootObject = useRef4(new THREE10.Object3D());
28492
- useImperativeHandle(ref, () => rootObject.current);
28493
- useEffect12(() => {
28494
- if (!mountRef.current) return;
28495
- removeExistingCanvases(mountRef.current);
28496
- const renderer = new THREE10.WebGLRenderer({ antialias: true, alpha: true });
28497
- configureRenderer(renderer);
28498
- renderer.setSize(
28499
- mountRef.current.clientWidth,
28500
- mountRef.current.clientHeight
28501
- );
28502
- renderer.setPixelRatio(window.devicePixelRatio);
28503
- mountRef.current.appendChild(renderer.domElement);
28504
- const camera = new THREE10.PerspectiveCamera(
28505
- 75,
28506
- mountRef.current.clientWidth / mountRef.current.clientHeight,
28507
- 0.1,
28508
- 1e3
28509
- );
28510
- if (cameraProps?.up) {
28511
- camera.up.set(cameraProps.up[0], cameraProps.up[1], cameraProps.up[2]);
28512
- }
28513
- if (cameraProps?.position) {
28514
- camera.position.set(
28515
- cameraProps.position[0],
28516
- cameraProps.position[1],
28517
- cameraProps.position[2]
28518
- );
28519
- }
28520
- camera.lookAt(0, 0, 0);
28521
- scene.add(rootObject.current);
28522
- window.__TSCIRCUIT_THREE_OBJECT = rootObject.current;
28523
- setContextState({
28524
- scene,
28525
- camera,
28526
- renderer,
28527
- rootObject: rootObject.current,
28528
- addFrameListener,
28529
- removeFrameListener
28530
- });
28531
- onCreatedRef.current?.({ camera, renderer });
28532
- let animationFrameId;
28533
- const clock = new THREE10.Clock();
28534
- const animate = () => {
28535
- const time = clock.getElapsedTime();
28536
- const delta = clock.getDelta();
28537
- frameListeners.current.forEach((listener) => listener(time, delta));
28538
- renderer.render(scene, camera);
28539
- animationFrameId = requestAnimationFrame(animate);
28540
- };
28541
- animate();
28542
- const handleResize = () => {
28543
- if (mountRef.current) {
28544
- camera.aspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
28545
- camera.updateProjectionMatrix();
28546
- renderer.setSize(
28547
- mountRef.current.clientWidth,
28548
- mountRef.current.clientHeight
28549
- );
28550
- }
28551
- };
28552
- window.addEventListener("resize", handleResize);
28553
- return () => {
28554
- window.removeEventListener("resize", handleResize);
28555
- cancelAnimationFrame(animationFrameId);
28556
- if (mountRef.current && renderer.domElement) {
28557
- mountRef.current.removeChild(renderer.domElement);
28558
- }
28559
- renderer.dispose();
28560
- scene.remove(rootObject.current);
28561
- if (window.__TSCIRCUIT_THREE_OBJECT === rootObject.current) {
28562
- window.__TSCIRCUIT_THREE_OBJECT = void 0;
28563
- }
28564
- };
28565
- }, [scene, addFrameListener, removeFrameListener]);
28566
- return /* @__PURE__ */ jsx11("div", { ref: mountRef, style: { width: "100%", height: "100%", ...style }, children: contextState && /* @__PURE__ */ jsx11(ThreeContext.Provider, { value: contextState, children: /* @__PURE__ */ jsx11(HoverProvider, { children }) }) });
28321
+ controls.target.fromArray(state.target);
28322
+ controls.update();
28323
+ camera.updateMatrixWorld();
28324
+ return true;
28325
+ } catch (err) {
28326
+ console.warn("Failed to restore camera:", err);
28327
+ return false;
28567
28328
  }
28568
- );
28569
-
28570
- // src/react-three/OrbitControls.tsx
28571
- import { useEffect as useEffect13, useMemo as useMemo11 } from "react";
28572
- import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
28573
- var OrbitControls = ({
28574
- autoRotate,
28575
- autoRotateSpeed,
28576
- onStart,
28577
- panSpeed,
28578
- rotateSpeed,
28579
- zoomSpeed,
28580
- enableDamping,
28581
- dampingFactor,
28582
- target,
28583
- onControlsChange
28584
- }) => {
28585
- const { camera, renderer } = useThree();
28586
- const controls = useMemo11(() => {
28587
- if (!camera || !renderer) return null;
28588
- return new ThreeOrbitControls(camera, renderer.domElement);
28589
- }, [camera, renderer]);
28590
- useEffect13(() => {
28591
- onControlsChange?.(controls ?? null);
28592
- return () => onControlsChange?.(null);
28593
- }, [controls, onControlsChange]);
28594
- useEffect13(() => {
28595
- if (!controls) return;
28596
- const handleChange = () => {
28597
- onControlsChange?.(controls);
28329
+ };
28330
+ var CameraControllerContext = createContext4(void 0);
28331
+ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition }) => {
28332
+ const controlsRef = useRef3(null);
28333
+ const mainCameraRef = useRef3(null);
28334
+ const [controller, setController] = useState7(null);
28335
+ const [cameraType, setCameraType] = useState7(
28336
+ "perspective"
28337
+ );
28338
+ const [cameraPosition, setCameraPosition] = useState7(initialCameraPosition ?? null);
28339
+ const [cameraRotation, setCameraRotation] = useState7(
28340
+ new THREE9.Euler(0, 0, 0)
28341
+ );
28342
+ const baseDistance = useMemo8(() => {
28343
+ const [x, y, z133] = initialCameraPosition ?? [5, -5, 5];
28344
+ const distance2 = Math.hypot(
28345
+ x - defaultTarget.x,
28346
+ y - defaultTarget.y,
28347
+ z133 - defaultTarget.z
28348
+ );
28349
+ return distance2 > 0 ? distance2 : 5;
28350
+ }, [initialCameraPosition, defaultTarget]);
28351
+ const getPresetConfig = useCallback4(
28352
+ (preset) => {
28353
+ const targetVector = [
28354
+ defaultTarget.x,
28355
+ defaultTarget.y,
28356
+ defaultTarget.z
28357
+ ];
28358
+ const distance2 = baseDistance;
28359
+ const heightOffset = distance2 * 0.3;
28360
+ switch (preset) {
28361
+ case "Top Center Angled": {
28362
+ const angledOffset = distance2 / Math.sqrt(2);
28363
+ return {
28364
+ position: [
28365
+ defaultTarget.x,
28366
+ defaultTarget.y - angledOffset,
28367
+ defaultTarget.z + angledOffset
28368
+ ],
28369
+ target: targetVector,
28370
+ up: [0, 0, 1]
28371
+ };
28372
+ }
28373
+ case "Top Down":
28374
+ return {
28375
+ position: [
28376
+ defaultTarget.x,
28377
+ defaultTarget.y,
28378
+ defaultTarget.z + distance2
28379
+ ],
28380
+ target: targetVector,
28381
+ up: [0, 0, 1]
28382
+ };
28383
+ case "Top Left Corner":
28384
+ return {
28385
+ position: [
28386
+ defaultTarget.x - distance2 * 0.6,
28387
+ defaultTarget.y - distance2 * 0.6,
28388
+ defaultTarget.z + distance2 * 0.6
28389
+ ],
28390
+ target: targetVector,
28391
+ up: [0, 0, 1]
28392
+ };
28393
+ case "Top Right Corner":
28394
+ return {
28395
+ position: [
28396
+ defaultTarget.x + distance2 * 0.6,
28397
+ defaultTarget.y - distance2 * 0.6,
28398
+ defaultTarget.z + distance2 * 0.6
28399
+ ],
28400
+ target: targetVector,
28401
+ up: [0, 0, 1]
28402
+ };
28403
+ case "Left Sideview":
28404
+ return {
28405
+ position: [
28406
+ defaultTarget.x - distance2,
28407
+ defaultTarget.y,
28408
+ defaultTarget.z
28409
+ ],
28410
+ target: targetVector,
28411
+ up: [0, 0, 1]
28412
+ };
28413
+ case "Right Sideview":
28414
+ return {
28415
+ position: [
28416
+ defaultTarget.x + distance2,
28417
+ defaultTarget.y,
28418
+ defaultTarget.z
28419
+ ],
28420
+ target: targetVector,
28421
+ up: [0, 0, 1]
28422
+ };
28423
+ case "Front":
28424
+ return {
28425
+ position: [
28426
+ defaultTarget.x,
28427
+ defaultTarget.y - distance2,
28428
+ defaultTarget.z
28429
+ ],
28430
+ target: targetVector,
28431
+ up: [0, 0, 1]
28432
+ };
28433
+ case "Custom":
28434
+ default:
28435
+ return null;
28436
+ }
28437
+ },
28438
+ [baseDistance, defaultTarget]
28439
+ );
28440
+ const handleControlsChange = useCallback4(
28441
+ (controls) => {
28442
+ controlsRef.current = controls;
28443
+ },
28444
+ []
28445
+ );
28446
+ const cameraControllerContextValue = useMemo8(
28447
+ () => ({
28448
+ controlsRef,
28449
+ mainCameraRef,
28450
+ defaultTarget,
28451
+ baseDistance,
28452
+ controller,
28453
+ setController,
28454
+ getPresetConfig,
28455
+ handleControlsChange,
28456
+ cameraType,
28457
+ setCameraType,
28458
+ cameraPosition,
28459
+ setCameraPosition,
28460
+ cameraRotation,
28461
+ setCameraRotation,
28462
+ saveCameraToSession,
28463
+ loadCameraFromSession
28464
+ }),
28465
+ [
28466
+ defaultTarget,
28467
+ baseDistance,
28468
+ controller,
28469
+ getPresetConfig,
28470
+ handleControlsChange,
28471
+ cameraType,
28472
+ cameraPosition,
28473
+ cameraRotation
28474
+ ]
28475
+ );
28476
+ return /* @__PURE__ */ jsx10(CameraControllerContext.Provider, { value: cameraControllerContextValue, children });
28477
+ };
28478
+ var useCameraController = () => {
28479
+ const context = useContext4(CameraControllerContext);
28480
+ if (!context) {
28481
+ throw new Error(
28482
+ "useCameraController must be used within a CameraControllerProvider"
28483
+ );
28484
+ }
28485
+ return context;
28486
+ };
28487
+
28488
+ // src/react-three/Canvas.tsx
28489
+ import { jsx as jsx11 } from "react/jsx-runtime";
28490
+ var Canvas = forwardRef(
28491
+ ({ children, scene: sceneProps, camera: cameraProps, style, onCreated }, ref) => {
28492
+ const { cameraType } = useCameraController();
28493
+ const mountRef = useRef4(null);
28494
+ const [contextState, setContextState] = useState8(
28495
+ null
28496
+ );
28497
+ const frameListeners = useRef4(
28498
+ []
28499
+ );
28500
+ const onCreatedRef = useRef4(void 0);
28501
+ onCreatedRef.current = onCreated;
28502
+ const savedCameraStateRef = useRef4(null);
28503
+ const addFrameListener = useCallback5(
28504
+ (listener) => {
28505
+ frameListeners.current.push(listener);
28506
+ },
28507
+ []
28508
+ );
28509
+ const removeFrameListener = useCallback5(
28510
+ (listener) => {
28511
+ frameListeners.current = frameListeners.current.filter(
28512
+ (l) => l !== listener
28513
+ );
28514
+ },
28515
+ []
28516
+ );
28517
+ const scene = useMemo9(() => new THREE10.Scene(), []);
28518
+ if (sceneProps?.up) {
28519
+ scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
28520
+ }
28521
+ const rootObject = useRef4(new THREE10.Object3D());
28522
+ useImperativeHandle(ref, () => rootObject.current);
28523
+ useEffect10(() => {
28524
+ if (!mountRef.current) return;
28525
+ removeExistingCanvases(mountRef.current);
28526
+ const renderer = new THREE10.WebGLRenderer({ antialias: true, alpha: true });
28527
+ configureRenderer(renderer);
28528
+ renderer.setSize(
28529
+ mountRef.current.clientWidth,
28530
+ mountRef.current.clientHeight
28531
+ );
28532
+ renderer.setPixelRatio(window.devicePixelRatio);
28533
+ mountRef.current.appendChild(renderer.domElement);
28534
+ const aspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
28535
+ const camera = cameraType === "perspective" ? new THREE10.PerspectiveCamera(75, aspect, 0.1, 1e3) : new THREE10.OrthographicCamera(
28536
+ -10 * aspect,
28537
+ 10 * aspect,
28538
+ 10,
28539
+ -10,
28540
+ -1e3,
28541
+ 1e3
28542
+ );
28543
+ if (savedCameraStateRef.current) {
28544
+ camera.position.copy(savedCameraStateRef.current.position);
28545
+ camera.quaternion.copy(savedCameraStateRef.current.quaternion);
28546
+ camera.up.copy(savedCameraStateRef.current.up);
28547
+ } else {
28548
+ if (cameraProps?.up) {
28549
+ camera.up.set(cameraProps.up[0], cameraProps.up[1], cameraProps.up[2]);
28550
+ }
28551
+ if (cameraProps?.position) {
28552
+ camera.position.set(
28553
+ cameraProps.position[0],
28554
+ cameraProps.position[1],
28555
+ cameraProps.position[2]
28556
+ );
28557
+ }
28558
+ camera.lookAt(0, 0, 0);
28559
+ }
28560
+ scene.add(rootObject.current);
28561
+ window.__TSCIRCUIT_THREE_OBJECT = rootObject.current;
28562
+ setContextState({
28563
+ scene,
28564
+ camera,
28565
+ renderer,
28566
+ rootObject: rootObject.current,
28567
+ addFrameListener,
28568
+ removeFrameListener
28569
+ });
28570
+ onCreatedRef.current?.({ camera, renderer });
28571
+ let animationFrameId;
28572
+ const clock = new THREE10.Clock();
28573
+ const animate = () => {
28574
+ const time = clock.getElapsedTime();
28575
+ const delta = clock.getDelta();
28576
+ frameListeners.current.forEach((listener) => listener(time, delta));
28577
+ renderer.render(scene, camera);
28578
+ animationFrameId = requestAnimationFrame(animate);
28579
+ };
28580
+ animate();
28581
+ const handleResize = () => {
28582
+ if (mountRef.current) {
28583
+ const newAspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
28584
+ if (camera instanceof THREE10.PerspectiveCamera) {
28585
+ camera.aspect = newAspect;
28586
+ } else if (camera instanceof THREE10.OrthographicCamera) {
28587
+ camera.left = -10 * newAspect;
28588
+ camera.right = 10 * newAspect;
28589
+ camera.top = 10;
28590
+ camera.bottom = -10;
28591
+ }
28592
+ camera.updateProjectionMatrix();
28593
+ renderer.setSize(
28594
+ mountRef.current.clientWidth,
28595
+ mountRef.current.clientHeight
28596
+ );
28597
+ }
28598
+ };
28599
+ window.addEventListener("resize", handleResize);
28600
+ return () => {
28601
+ savedCameraStateRef.current = {
28602
+ position: camera.position.clone(),
28603
+ quaternion: camera.quaternion.clone(),
28604
+ up: camera.up.clone()
28605
+ };
28606
+ window.removeEventListener("resize", handleResize);
28607
+ cancelAnimationFrame(animationFrameId);
28608
+ if (mountRef.current && renderer.domElement) {
28609
+ mountRef.current.removeChild(renderer.domElement);
28610
+ }
28611
+ renderer.dispose();
28612
+ scene.remove(rootObject.current);
28613
+ if (window.__TSCIRCUIT_THREE_OBJECT === rootObject.current) {
28614
+ window.__TSCIRCUIT_THREE_OBJECT = void 0;
28615
+ }
28616
+ };
28617
+ }, [scene, addFrameListener, removeFrameListener, cameraType]);
28618
+ return /* @__PURE__ */ jsx11("div", { ref: mountRef, style: { width: "100%", height: "100%", ...style }, children: contextState && /* @__PURE__ */ jsx11(ThreeContext.Provider, { value: contextState, children: /* @__PURE__ */ jsx11(HoverProvider, { children }) }) });
28619
+ }
28620
+ );
28621
+
28622
+ // src/react-three/OrbitControls.tsx
28623
+ import { useEffect as useEffect11, useMemo as useMemo10 } from "react";
28624
+ import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
28625
+ var OrbitControls = ({
28626
+ autoRotate,
28627
+ autoRotateSpeed,
28628
+ onStart,
28629
+ panSpeed,
28630
+ rotateSpeed,
28631
+ zoomSpeed,
28632
+ enableDamping,
28633
+ dampingFactor,
28634
+ target,
28635
+ onControlsChange
28636
+ }) => {
28637
+ const { camera, renderer } = useThree();
28638
+ const controls = useMemo10(() => {
28639
+ if (!camera || !renderer) return null;
28640
+ return new ThreeOrbitControls(camera, renderer.domElement);
28641
+ }, [camera, renderer]);
28642
+ useEffect11(() => {
28643
+ onControlsChange?.(controls ?? null);
28644
+ return () => onControlsChange?.(null);
28645
+ }, [controls, onControlsChange]);
28646
+ useEffect11(() => {
28647
+ if (!controls) return;
28648
+ const handleChange = () => {
28649
+ onControlsChange?.(controls);
28598
28650
  };
28599
28651
  controls.addEventListener("change", handleChange);
28600
28652
  return () => {
28601
28653
  controls.removeEventListener("change", handleChange);
28602
28654
  };
28603
28655
  }, [controls, onControlsChange]);
28604
- useEffect13(() => {
28656
+ useEffect11(() => {
28605
28657
  if (!controls) return;
28606
28658
  controls.autoRotate = autoRotate || false;
28607
28659
  controls.autoRotateSpeed = autoRotateSpeed || 1;
@@ -28626,14 +28678,14 @@ var OrbitControls = ({
28626
28678
  dampingFactor,
28627
28679
  target
28628
28680
  ]);
28629
- useEffect13(() => {
28681
+ useEffect11(() => {
28630
28682
  if (!controls || !onStart) return;
28631
28683
  controls.addEventListener("start", onStart);
28632
28684
  return () => {
28633
28685
  controls.removeEventListener("start", onStart);
28634
28686
  };
28635
28687
  }, [controls, onStart]);
28636
- useEffect13(() => {
28688
+ useEffect11(() => {
28637
28689
  if (!controls) return;
28638
28690
  return () => {
28639
28691
  controls.dispose();
@@ -28646,7 +28698,7 @@ var OrbitControls = ({
28646
28698
  };
28647
28699
 
28648
28700
  // src/react-three/Grid.tsx
28649
- import { useEffect as useEffect14, useMemo as useMemo12 } from "react";
28701
+ import { useEffect as useEffect12, useMemo as useMemo11 } from "react";
28650
28702
  import * as THREE11 from "three";
28651
28703
  var vertexShader = `
28652
28704
  varying vec3 worldPosition;
@@ -28692,7 +28744,7 @@ var Grid = ({
28692
28744
  }) => {
28693
28745
  const { scene, camera } = useThree();
28694
28746
  const size5 = 1e3;
28695
- const gridMesh = useMemo12(() => {
28747
+ const gridMesh = useMemo11(() => {
28696
28748
  const geometry = new THREE11.PlaneGeometry(size5, size5);
28697
28749
  geometry.rotateX(-Math.PI / 2);
28698
28750
  const material = new THREE11.ShaderMaterial({
@@ -28721,7 +28773,7 @@ var Grid = ({
28721
28773
  gridMesh.position.set(camera.position.x, camera.position.y, 0);
28722
28774
  }
28723
28775
  });
28724
- useEffect14(() => {
28776
+ useEffect12(() => {
28725
28777
  if (!scene || !gridMesh) return;
28726
28778
  scene.add(gridMesh);
28727
28779
  return () => {
@@ -28738,21 +28790,21 @@ var Grid = ({
28738
28790
  };
28739
28791
 
28740
28792
  // src/react-three/Lights.tsx
28741
- import { useEffect as useEffect15, useMemo as useMemo13 } from "react";
28793
+ import { useEffect as useEffect13, useMemo as useMemo12 } from "react";
28742
28794
  import * as THREE12 from "three";
28743
28795
  var Lights = () => {
28744
28796
  const { scene } = useThree();
28745
- const ambientLight = useMemo13(
28797
+ const ambientLight = useMemo12(
28746
28798
  () => new THREE12.AmbientLight(16777215, Math.PI / 2),
28747
28799
  []
28748
28800
  );
28749
- const pointLight = useMemo13(() => {
28801
+ const pointLight = useMemo12(() => {
28750
28802
  const light = new THREE12.PointLight(16777215, Math.PI / 4);
28751
28803
  light.position.set(-10, -10, 10);
28752
28804
  light.decay = 0;
28753
28805
  return light;
28754
28806
  }, []);
28755
- useEffect15(() => {
28807
+ useEffect13(() => {
28756
28808
  if (!scene) return;
28757
28809
  scene.add(ambientLight);
28758
28810
  scene.add(pointLight);
@@ -28764,55 +28816,18 @@ var Lights = () => {
28764
28816
  return null;
28765
28817
  };
28766
28818
 
28767
- // src/hooks/useSessionCamera.ts
28768
- var CAMERA_KEY = "cadViewerCameraStateSession";
28769
- var saveCameraToSession = (camera, controls) => {
28770
- try {
28771
- const savedCameraSession = {
28772
- position: camera.position.toArray(),
28773
- quaternion: camera.quaternion.toArray(),
28774
- up: camera.up.toArray(),
28775
- fov: camera.fov ?? 50,
28776
- target: controls.target.toArray()
28777
- };
28778
- sessionStorage.setItem(CAMERA_KEY, JSON.stringify(savedCameraSession));
28779
- } catch (err) {
28780
- console.warn("Failed to save camera:", err);
28781
- }
28782
- };
28783
- var loadCameraFromSession = (camera, controls) => {
28784
- try {
28785
- const raw = sessionStorage.getItem(CAMERA_KEY);
28786
- if (!raw) return false;
28787
- const state = JSON.parse(raw);
28788
- camera.position.fromArray(state.position);
28789
- camera.quaternion.fromArray(state.quaternion);
28790
- camera.up.fromArray(state.up);
28791
- if ("fov" in camera) {
28792
- const persp = camera;
28793
- persp.fov = state.fov;
28794
- persp.updateProjectionMatrix?.();
28795
- }
28796
- controls.target.fromArray(state.target);
28797
- controls.update();
28798
- camera.updateMatrixWorld();
28799
- return true;
28800
- } catch (err) {
28801
- console.warn("Failed to restore camera:", err);
28802
- return false;
28803
- }
28804
- };
28805
-
28806
- // src/hooks/useCameraController.ts
28807
- import { useCallback as useCallback5, useEffect as useEffect16, useMemo as useMemo14, useRef as useRef5 } from "react";
28819
+ // src/hooks/cameraAnimation.ts
28820
+ import { useCallback as useCallback6, useEffect as useEffect14, useRef as useRef5 } from "react";
28808
28821
  import * as THREE13 from "three";
28809
28822
  var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
28810
- var CameraAnimator = ({
28811
- defaultTarget,
28812
- controlsRef,
28813
- onReady
28814
- }) => {
28815
- const { camera } = useThree();
28823
+ var CameraAnimatorWithContext = () => {
28824
+ const {
28825
+ controlsRef,
28826
+ mainCameraRef,
28827
+ defaultTarget,
28828
+ setController,
28829
+ getPresetConfig
28830
+ } = useCameraController();
28816
28831
  const animationRef = useRef5(null);
28817
28832
  const tempQuaternion = useRef5(new THREE13.Quaternion());
28818
28833
  const tempTarget = useRef5(new THREE13.Vector3());
@@ -28821,9 +28836,9 @@ var CameraAnimator = ({
28821
28836
  const tempRollTarget = useRef5(new THREE13.Quaternion());
28822
28837
  const baseOrientationHelper = useRef5(new THREE13.Object3D());
28823
28838
  const orientationHelper = useRef5(new THREE13.Object3D());
28824
- const animateTo = useCallback5(
28839
+ const animateTo = useCallback6(
28825
28840
  ({ position, target, up, durationMs = 600 }) => {
28826
- if (!camera) return;
28841
+ if (!mainCameraRef.current) return;
28827
28842
  const currentTarget = controlsRef.current?.target ?? defaultTarget;
28828
28843
  const toPosition = new THREE13.Vector3(
28829
28844
  position[0],
@@ -28837,8 +28852,8 @@ var CameraAnimator = ({
28837
28852
  toOrientationHelper.up.copy(resolvedUp);
28838
28853
  toOrientationHelper.lookAt(resolvedTarget);
28839
28854
  const toQuaternion = toOrientationHelper.quaternion.clone();
28840
- const fromQuaternion = camera.quaternion.clone();
28841
- const fromPosition = camera.position.clone();
28855
+ const fromQuaternion = mainCameraRef.current.quaternion.clone();
28856
+ const fromPosition = mainCameraRef.current.position.clone();
28842
28857
  const fromTarget = currentTarget.clone();
28843
28858
  const baseHelper = baseOrientationHelper.current;
28844
28859
  baseHelper.up.set(0, 0, 1);
@@ -28863,17 +28878,30 @@ var CameraAnimator = ({
28863
28878
  duration: durationMs
28864
28879
  };
28865
28880
  },
28866
- [camera, controlsRef, defaultTarget]
28881
+ [mainCameraRef, controlsRef, defaultTarget]
28867
28882
  );
28868
- useEffect16(() => {
28869
- if (!onReady || !camera) return;
28870
- onReady({ animateTo });
28883
+ const animateToPreset = useCallback6(
28884
+ (preset) => {
28885
+ if (preset === "Custom") return;
28886
+ const config = getPresetConfig(preset);
28887
+ if (!config) return;
28888
+ animateTo(config);
28889
+ },
28890
+ [animateTo, getPresetConfig]
28891
+ );
28892
+ useEffect14(() => {
28893
+ if (!mainCameraRef.current) return;
28894
+ const controller = {
28895
+ animateTo,
28896
+ animateToPreset
28897
+ };
28898
+ setController(controller);
28871
28899
  return () => {
28872
- onReady(null);
28900
+ setController(null);
28873
28901
  };
28874
- }, [animateTo, camera, onReady]);
28902
+ }, [animateTo, animateToPreset, mainCameraRef, setController]);
28875
28903
  useFrame(() => {
28876
- if (!camera || !animationRef.current) return;
28904
+ if (!mainCameraRef.current || !animationRef.current) return;
28877
28905
  const {
28878
28906
  fromPosition,
28879
28907
  toPosition,
@@ -28888,12 +28916,12 @@ var CameraAnimator = ({
28888
28916
  const elapsed = performance.now() - startTime;
28889
28917
  const progress = duration <= 0 ? 1 : Math.min(elapsed / duration, 1);
28890
28918
  const eased = easeInOutCubic(progress);
28891
- camera.position.lerpVectors(fromPosition, toPosition, eased);
28919
+ mainCameraRef.current.position.lerpVectors(fromPosition, toPosition, eased);
28892
28920
  const nextTarget = tempTarget.current;
28893
28921
  nextTarget.copy(fromTarget).lerp(toTarget, eased);
28894
28922
  const baseHelper = baseOrientationHelper.current;
28895
28923
  baseHelper.up.set(0, 0, 1);
28896
- baseHelper.position.copy(camera.position);
28924
+ baseHelper.position.copy(mainCameraRef.current.position);
28897
28925
  baseHelper.lookAt(nextTarget);
28898
28926
  const baseQuaternion = tempQuaternion.current;
28899
28927
  baseQuaternion.copy(baseHelper.quaternion);
@@ -28909,18 +28937,18 @@ var CameraAnimator = ({
28909
28937
  }
28910
28938
  rollTarget.normalize();
28911
28939
  interpolatedRoll.slerp(rollTarget, eased);
28912
- camera.quaternion.copy(baseQuaternion).multiply(interpolatedRoll).normalize();
28940
+ mainCameraRef.current.quaternion.copy(baseQuaternion).multiply(interpolatedRoll).normalize();
28913
28941
  const upVector = tempUp.current;
28914
- upVector.set(0, 1, 0).applyQuaternion(camera.quaternion).normalize();
28915
- camera.up.copy(upVector);
28942
+ upVector.set(0, 1, 0).applyQuaternion(mainCameraRef.current.quaternion).normalize();
28943
+ mainCameraRef.current.up.copy(upVector);
28916
28944
  controlsRef.current?.target.copy(nextTarget);
28917
- camera.updateMatrixWorld();
28945
+ mainCameraRef.current.updateMatrixWorld();
28918
28946
  controlsRef.current?.update();
28919
28947
  if (progress >= 1) {
28920
- camera.position.copy(toPosition);
28921
- camera.quaternion.copy(toQuaternion);
28922
- camera.up.set(0, 0, 1);
28923
- camera.updateMatrixWorld();
28948
+ mainCameraRef.current.position.copy(toPosition);
28949
+ mainCameraRef.current.quaternion.copy(toQuaternion);
28950
+ mainCameraRef.current.up.set(0, 0, 1);
28951
+ mainCameraRef.current.updateMatrixWorld();
28924
28952
  controlsRef.current?.target.copy(toTarget);
28925
28953
  controlsRef.current?.update();
28926
28954
  animationRef.current = null;
@@ -28928,154 +28956,216 @@ var CameraAnimator = ({
28928
28956
  });
28929
28957
  return null;
28930
28958
  };
28931
- var useCameraController = ({
28932
- defaultTarget,
28933
- initialCameraPosition,
28934
- onCameraControllerReady
28935
- }) => {
28936
- const controlsRef = useRef5(null);
28937
- const baseDistance = useMemo14(() => {
28938
- const [x, y, z133] = initialCameraPosition ?? [5, -5, 5];
28939
- const distance2 = Math.hypot(
28940
- x - defaultTarget.x,
28941
- y - defaultTarget.y,
28942
- z133 - defaultTarget.z
28943
- );
28944
- return distance2 > 0 ? distance2 : 5;
28945
- }, [initialCameraPosition, defaultTarget]);
28946
- const getPresetConfig = useCallback5(
28947
- (preset) => {
28948
- const targetVector = [
28949
- defaultTarget.x,
28950
- defaultTarget.y,
28951
- defaultTarget.z
28952
- ];
28953
- const distance2 = baseDistance;
28954
- const heightOffset = distance2 * 0.3;
28955
- switch (preset) {
28956
- case "Top Centered": {
28957
- const angledOffset = distance2 / Math.sqrt(2);
28958
- return {
28959
- position: [
28960
- defaultTarget.x,
28961
- defaultTarget.y - angledOffset,
28962
- defaultTarget.z + angledOffset
28963
- ],
28964
- target: targetVector,
28965
- up: [0, 0, 1]
28966
- };
28959
+
28960
+ // src/hooks/useCameraSession.ts
28961
+ import { useCallback as useCallback7, useRef as useRef6 } from "react";
28962
+ var useCameraSession = () => {
28963
+ const { controlsRef } = useCameraController();
28964
+ const cameraRef = useRef6(null);
28965
+ const cameraRestoredRef = useRef6(false);
28966
+ const saveTimeoutRef = useRef6(null);
28967
+ const handleCameraCreated = useCallback7(
28968
+ (camera) => {
28969
+ cameraRef.current = camera;
28970
+ if (!cameraRestoredRef.current && controlsRef.current) {
28971
+ const restored = loadCameraFromSession(camera, controlsRef.current);
28972
+ if (restored) {
28973
+ cameraRestoredRef.current = true;
28967
28974
  }
28968
- case "Top Down":
28969
- return {
28970
- position: [
28971
- defaultTarget.x,
28972
- defaultTarget.y,
28973
- defaultTarget.z + distance2
28974
- ],
28975
- target: targetVector,
28976
- up: [0, 0, 1]
28977
- };
28978
- case "Top Left Corner":
28979
- return {
28980
- position: [
28981
- defaultTarget.x - distance2 * 0.6,
28982
- defaultTarget.y - distance2 * 0.6,
28983
- defaultTarget.z + distance2 * 0.6
28984
- ],
28985
- target: targetVector,
28986
- up: [0, 0, 1]
28987
- };
28988
- case "Top Right Corner":
28989
- return {
28990
- position: [
28991
- defaultTarget.x + distance2 * 0.6,
28992
- defaultTarget.y - distance2 * 0.6,
28993
- defaultTarget.z + distance2 * 0.6
28994
- ],
28995
- target: targetVector,
28996
- up: [0, 0, 1]
28997
- };
28998
- case "Left Sideview":
28999
- return {
29000
- position: [
29001
- defaultTarget.x - distance2,
29002
- defaultTarget.y,
29003
- defaultTarget.z + heightOffset
29004
- ],
29005
- target: targetVector,
29006
- up: [0, 0, 1]
29007
- };
29008
- case "Right Sideview":
29009
- return {
29010
- position: [
29011
- defaultTarget.x + distance2,
29012
- defaultTarget.y,
29013
- defaultTarget.z + heightOffset
29014
- ],
29015
- target: targetVector,
29016
- up: [0, 0, 1]
29017
- };
29018
- case "Front":
29019
- return {
29020
- position: [
29021
- defaultTarget.x,
29022
- defaultTarget.y - distance2,
29023
- defaultTarget.z + heightOffset
29024
- ],
29025
- target: targetVector,
29026
- up: [0, 0, 1]
29027
- };
29028
- case "Custom":
29029
- default:
29030
- return null;
29031
28975
  }
29032
28976
  },
29033
- [baseDistance, defaultTarget]
28977
+ [controlsRef]
29034
28978
  );
29035
- const handleControllerReady = useCallback5(
29036
- (controller) => {
29037
- if (!onCameraControllerReady) return;
29038
- if (!controller) {
29039
- onCameraControllerReady(null);
28979
+ const handleControlsChange = useCallback7(() => {
28980
+ if (!cameraRef.current || !controlsRef.current) return;
28981
+ if (!cameraRestoredRef.current) {
28982
+ const restored = loadCameraFromSession(
28983
+ cameraRef.current,
28984
+ controlsRef.current
28985
+ );
28986
+ if (restored) {
28987
+ cameraRestoredRef.current = true;
29040
28988
  return;
29041
28989
  }
29042
- const enhancedController = {
29043
- animateTo: controller.animateTo,
29044
- animateToPreset: (preset) => {
29045
- if (preset === "Custom") return;
29046
- const config = getPresetConfig(preset);
29047
- if (!config) return;
29048
- controller.animateTo(config);
29049
- }
29050
- };
29051
- onCameraControllerReady(enhancedController);
29052
- },
29053
- [getPresetConfig, onCameraControllerReady]
29054
- );
29055
- const handleControlsChange = useCallback5(
29056
- (controls) => {
29057
- controlsRef.current = controls;
29058
- },
29059
- []
28990
+ }
28991
+ clearTimeout(saveTimeoutRef.current);
28992
+ saveTimeoutRef.current = setTimeout(() => {
28993
+ if (cameraRef.current && controlsRef.current) {
28994
+ saveCameraToSession(cameraRef.current, controlsRef.current);
28995
+ }
28996
+ }, 150);
28997
+ }, [controlsRef]);
28998
+ return {
28999
+ handleCameraCreated,
29000
+ handleControlsChange
29001
+ };
29002
+ };
29003
+
29004
+ // src/three-components/OrientationCubeCanvas.tsx
29005
+ import { useEffect as useEffect15, useRef as useRef7 } from "react";
29006
+ import * as THREE14 from "three";
29007
+ import { Text as TroikaText } from "troika-three-text";
29008
+ import { jsx as jsx12 } from "react/jsx-runtime";
29009
+ function computePointInFront(rotationVector, distance2) {
29010
+ const quaternion = new THREE14.Quaternion().setFromEuler(
29011
+ new THREE14.Euler(rotationVector.x, rotationVector.y, rotationVector.z)
29060
29012
  );
29061
- const cameraAnimatorProps = useMemo14(
29062
- () => ({
29063
- defaultTarget,
29064
- controlsRef,
29065
- onReady: handleControllerReady
29066
- }),
29067
- [defaultTarget, handleControllerReady]
29013
+ const forwardVector = new THREE14.Vector3(0, 0, 1);
29014
+ forwardVector.applyQuaternion(quaternion);
29015
+ const result = forwardVector.multiplyScalar(distance2);
29016
+ return result;
29017
+ }
29018
+ var OrientationCubeCanvas = () => {
29019
+ const { mainCameraRef } = useCameraController();
29020
+ const containerRef = useRef7(null);
29021
+ const canvasRef = useRef7(null);
29022
+ const rendererRef = useRef7(null);
29023
+ const sceneRef = useRef7(null);
29024
+ const cameraRef = useRef7(null);
29025
+ const animationFrameRef = useRef7(null);
29026
+ useEffect15(() => {
29027
+ if (!containerRef.current) return;
29028
+ const canvas = document.createElement("canvas");
29029
+ canvasRef.current = canvas;
29030
+ containerRef.current.appendChild(canvas);
29031
+ const renderer = new THREE14.WebGLRenderer({
29032
+ canvas,
29033
+ antialias: true,
29034
+ alpha: true
29035
+ });
29036
+ renderer.setSize(120, 120);
29037
+ renderer.setPixelRatio(window.devicePixelRatio);
29038
+ rendererRef.current = renderer;
29039
+ const scene = new THREE14.Scene();
29040
+ sceneRef.current = scene;
29041
+ const camera = new THREE14.PerspectiveCamera(75, 1, 0.1, 1e3);
29042
+ camera.up.set(0, 0, 1);
29043
+ cameraRef.current = camera;
29044
+ const ambientLight = new THREE14.AmbientLight(16777215, Math.PI / 2);
29045
+ scene.add(ambientLight);
29046
+ const group = new THREE14.Group();
29047
+ group.rotation.fromArray([Math.PI / 2, 0, 0]);
29048
+ const cubeSize = 1;
29049
+ const box = new THREE14.Mesh(
29050
+ new THREE14.BoxGeometry(cubeSize, cubeSize, cubeSize),
29051
+ new THREE14.MeshStandardMaterial({ color: "white" })
29052
+ );
29053
+ group.add(box);
29054
+ const edges = new THREE14.LineSegments(
29055
+ new THREE14.EdgesGeometry(
29056
+ new THREE14.BoxGeometry(cubeSize, cubeSize, cubeSize)
29057
+ ),
29058
+ new THREE14.LineBasicMaterial({ color: 0, linewidth: 2 })
29059
+ );
29060
+ group.add(edges);
29061
+ scene.add(group);
29062
+ const distanceFromCenter = 0.51;
29063
+ const createTextMesh = (text, position, rotation2) => {
29064
+ const textMesh = new TroikaText();
29065
+ textMesh.text = text;
29066
+ textMesh.position.fromArray(position);
29067
+ if (rotation2) textMesh.rotation.fromArray(rotation2);
29068
+ textMesh.color = "black";
29069
+ textMesh.fontSize = 0.25;
29070
+ textMesh.anchorX = "center";
29071
+ textMesh.anchorY = "middle";
29072
+ textMesh.depthOffset = 0;
29073
+ textMesh.font = null;
29074
+ textMesh.sync();
29075
+ return textMesh;
29076
+ };
29077
+ const frontText = createTextMesh("Front", [0, 0, distanceFromCenter]);
29078
+ const backText = createTextMesh(
29079
+ "Back",
29080
+ [0, 0, -distanceFromCenter],
29081
+ [0, Math.PI, 0]
29082
+ );
29083
+ const rightText = createTextMesh(
29084
+ "Right",
29085
+ [distanceFromCenter, 0, 0],
29086
+ [0, Math.PI / 2, 0]
29087
+ );
29088
+ const leftText = createTextMesh(
29089
+ "Left",
29090
+ [-distanceFromCenter, 0, 0],
29091
+ [0, -Math.PI / 2, 0]
29092
+ );
29093
+ const topText = createTextMesh(
29094
+ "Top",
29095
+ [0, distanceFromCenter, 0],
29096
+ [-Math.PI / 2, 0, 0]
29097
+ );
29098
+ const bottomText = createTextMesh(
29099
+ "Bottom",
29100
+ [0, -distanceFromCenter, 0],
29101
+ [Math.PI / 2, 0, 0]
29102
+ );
29103
+ group.add(frontText);
29104
+ group.add(backText);
29105
+ group.add(rightText);
29106
+ group.add(leftText);
29107
+ group.add(topText);
29108
+ group.add(bottomText);
29109
+ const animate = () => {
29110
+ if (mainCameraRef.current) {
29111
+ const cameraPosition = computePointInFront(
29112
+ mainCameraRef.current.rotation ?? new THREE14.Euler(0, 0, 0),
29113
+ 2
29114
+ );
29115
+ if (!cameraPosition.equals(camera.position)) {
29116
+ camera.position.copy(cameraPosition);
29117
+ camera.lookAt(0, 0, 0);
29118
+ }
29119
+ }
29120
+ renderer.render(scene, camera);
29121
+ animationFrameRef.current = requestAnimationFrame(animate);
29122
+ };
29123
+ animate();
29124
+ return () => {
29125
+ if (animationFrameRef.current) {
29126
+ cancelAnimationFrame(animationFrameRef.current);
29127
+ }
29128
+ frontText.dispose();
29129
+ backText.dispose();
29130
+ rightText.dispose();
29131
+ leftText.dispose();
29132
+ topText.dispose();
29133
+ bottomText.dispose();
29134
+ box.geometry.dispose();
29135
+ box.material.dispose();
29136
+ edges.geometry.dispose();
29137
+ edges.material.dispose();
29138
+ scene.clear();
29139
+ renderer.dispose();
29140
+ if (canvasRef.current && containerRef.current) {
29141
+ containerRef.current.removeChild(canvasRef.current);
29142
+ }
29143
+ };
29144
+ }, [mainCameraRef]);
29145
+ return /* @__PURE__ */ jsx12(
29146
+ "div",
29147
+ {
29148
+ ref: containerRef,
29149
+ style: {
29150
+ position: "absolute",
29151
+ top: 0,
29152
+ left: 0,
29153
+ width: 120,
29154
+ height: 120,
29155
+ zIndex: 1e3
29156
+ }
29157
+ }
29068
29158
  );
29069
- return { cameraAnimatorProps, handleControlsChange };
29070
29159
  };
29071
29160
 
29072
29161
  // src/CadViewerContainer.tsx
29073
- import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
29162
+ import { jsx as jsx13, jsxs as jsxs3 } from "react/jsx-runtime";
29074
29163
  var RotationTracker = () => {
29075
29164
  const { camera } = useThree();
29165
+ const { setCameraRotation } = useCameraController();
29076
29166
  useFrame(() => {
29077
29167
  if (camera) {
29078
- window.TSCI_MAIN_CAMERA_ROTATION = camera.rotation;
29168
+ setCameraRotation(camera.rotation);
29079
29169
  }
29080
29170
  });
29081
29171
  return null;
@@ -29091,14 +29181,20 @@ var CadViewerContainer = forwardRef2(
29091
29181
  onUserInteraction,
29092
29182
  onCameraControllerReady
29093
29183
  }, ref) => {
29094
- const [isInteractionEnabled, setIsInteractionEnabled] = useState8(
29184
+ const [isInteractionEnabled, setIsInteractionEnabled] = useState9(
29095
29185
  !clickToInteractEnabled
29096
29186
  );
29097
- const saveTimeoutRef = useRef6(null);
29098
- const controlsRef = useRef6(null);
29099
- const cameraRef = useRef6(null);
29100
- const restoredOnceRef = useRef6(false);
29101
- const gridSectionSize = useMemo15(() => {
29187
+ const { mainCameraRef, handleControlsChange, controller } = useCameraController();
29188
+ const {
29189
+ handleCameraCreated,
29190
+ handleControlsChange: handleSessionControlsChange
29191
+ } = useCameraSession();
29192
+ useEffect16(() => {
29193
+ if (onCameraControllerReady) {
29194
+ onCameraControllerReady(controller);
29195
+ }
29196
+ }, [controller, onCameraControllerReady]);
29197
+ const gridSectionSize = useMemo13(() => {
29102
29198
  if (!boardDimensions) return 10;
29103
29199
  const width10 = boardDimensions.width ?? 0;
29104
29200
  const height10 = boardDimensions.height ?? 0;
@@ -29106,72 +29202,26 @@ var CadViewerContainer = forwardRef2(
29106
29202
  const desired = largest * 1.5;
29107
29203
  return desired > 10 ? desired : 10;
29108
29204
  }, [boardDimensions]);
29109
- const orbitTarget = useMemo15(() => {
29205
+ const orbitTarget = useMemo13(() => {
29110
29206
  if (!boardCenter) return void 0;
29111
29207
  return [boardCenter.x, boardCenter.y, 0];
29112
29208
  }, [boardCenter]);
29113
- const defaultTarget = useMemo15(() => {
29114
- if (orbitTarget) {
29115
- return new THREE14.Vector3(orbitTarget[0], orbitTarget[1], orbitTarget[2]);
29116
- }
29117
- return new THREE14.Vector3(0, 0, 0);
29118
- }, [orbitTarget]);
29119
- const { cameraAnimatorProps, handleControlsChange } = useCameraController({
29120
- defaultTarget,
29121
- initialCameraPosition,
29122
- onCameraControllerReady
29123
- });
29124
- return /* @__PURE__ */ jsxs4("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
29125
- /* @__PURE__ */ jsx12(
29126
- "div",
29127
- {
29128
- style: {
29129
- position: "absolute",
29130
- top: 0,
29131
- left: 0,
29132
- width: 120,
29133
- height: 120
29134
- },
29135
- children: /* @__PURE__ */ jsx12(
29136
- Canvas,
29137
- {
29138
- camera: {
29139
- up: [0, 0, 1],
29140
- position: [1, 1, 1]
29141
- },
29142
- style: { zIndex: 10 },
29143
- children: /* @__PURE__ */ jsx12(CubeWithLabeledSides, {})
29144
- }
29145
- )
29146
- }
29147
- ),
29148
- /* @__PURE__ */ jsxs4(
29209
+ return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
29210
+ /* @__PURE__ */ jsx13(OrientationCubeCanvas, {}),
29211
+ /* @__PURE__ */ jsxs3(
29149
29212
  Canvas,
29150
29213
  {
29151
29214
  ref,
29152
- scene: { up: new THREE14.Vector3(0, 0, 1) },
29215
+ scene: { up: new THREE15.Vector3(0, 0, 1) },
29153
29216
  camera: { up: [0, 0, 1], position: initialCameraPosition },
29154
29217
  onCreated: ({ camera }) => {
29155
- cameraRef.current = camera;
29156
- if (!restoredOnceRef.current && controlsRef.current) {
29157
- const restored = loadCameraFromSession(
29158
- cameraRef.current,
29159
- controlsRef.current
29160
- );
29161
- if (restored) restoredOnceRef.current = true;
29162
- }
29163
- if (controlsRef.current && !restoredOnceRef.current) {
29164
- setTimeout(() => {
29165
- if (cameraRef.current && controlsRef.current) {
29166
- saveCameraToSession(cameraRef.current, controlsRef.current);
29167
- }
29168
- }, 0);
29169
- }
29218
+ mainCameraRef.current = camera;
29219
+ handleCameraCreated(camera);
29170
29220
  },
29171
29221
  children: [
29172
- /* @__PURE__ */ jsx12(CameraAnimator, { ...cameraAnimatorProps }),
29173
- /* @__PURE__ */ jsx12(RotationTracker, {}),
29174
- isInteractionEnabled && /* @__PURE__ */ jsx12(
29222
+ /* @__PURE__ */ jsx13(CameraAnimatorWithContext, {}),
29223
+ /* @__PURE__ */ jsx13(RotationTracker, {}),
29224
+ isInteractionEnabled && /* @__PURE__ */ jsx13(
29175
29225
  OrbitControls,
29176
29226
  {
29177
29227
  autoRotate: !autoRotateDisabled,
@@ -29185,28 +29235,12 @@ var CadViewerContainer = forwardRef2(
29185
29235
  target: orbitTarget,
29186
29236
  onControlsChange: (controls) => {
29187
29237
  handleControlsChange(controls);
29188
- controlsRef.current = controls;
29189
- if (cameraRef.current && controlsRef.current && !restoredOnceRef.current) {
29190
- const restored = loadCameraFromSession(
29191
- cameraRef.current,
29192
- controlsRef.current
29193
- );
29194
- if (restored) {
29195
- restoredOnceRef.current = true;
29196
- return;
29197
- }
29198
- }
29199
- clearTimeout(saveTimeoutRef.current);
29200
- saveTimeoutRef.current = setTimeout(() => {
29201
- if (cameraRef.current && controlsRef.current) {
29202
- saveCameraToSession(cameraRef.current, controlsRef.current);
29203
- }
29204
- }, 150);
29238
+ handleSessionControlsChange();
29205
29239
  }
29206
29240
  }
29207
29241
  ),
29208
- /* @__PURE__ */ jsx12(Lights, {}),
29209
- /* @__PURE__ */ jsx12(
29242
+ /* @__PURE__ */ jsx13(Lights, {}),
29243
+ /* @__PURE__ */ jsx13(
29210
29244
  Grid,
29211
29245
  {
29212
29246
  rotation: [Math.PI / 2, 0, 0],
@@ -29220,7 +29254,7 @@ var CadViewerContainer = forwardRef2(
29220
29254
  ]
29221
29255
  }
29222
29256
  ),
29223
- /* @__PURE__ */ jsxs4(
29257
+ /* @__PURE__ */ jsxs3(
29224
29258
  "div",
29225
29259
  {
29226
29260
  style: {
@@ -29238,7 +29272,7 @@ var CadViewerContainer = forwardRef2(
29238
29272
  ]
29239
29273
  }
29240
29274
  ),
29241
- clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx12(
29275
+ clickToInteractEnabled && !isInteractionEnabled && /* @__PURE__ */ jsx13(
29242
29276
  "button",
29243
29277
  {
29244
29278
  type: "button",
@@ -29257,7 +29291,7 @@ var CadViewerContainer = forwardRef2(
29257
29291
  alignItems: "center",
29258
29292
  justifyContent: "center"
29259
29293
  },
29260
- children: /* @__PURE__ */ jsx12(
29294
+ children: /* @__PURE__ */ jsx13(
29261
29295
  "div",
29262
29296
  {
29263
29297
  style: {
@@ -29280,9 +29314,9 @@ var CadViewerContainer = forwardRef2(
29280
29314
 
29281
29315
  // src/hooks/use-convert-children-to-soup.ts
29282
29316
  import { Circuit } from "@tscircuit/core";
29283
- import { useMemo as useMemo16 } from "react";
29317
+ import { useMemo as useMemo14 } from "react";
29284
29318
  var useConvertChildrenToCircuitJson = (children) => {
29285
- return useMemo16(() => {
29319
+ return useMemo14(() => {
29286
29320
  if (!children) return [];
29287
29321
  const circuit = new Circuit();
29288
29322
  circuit.add(children);
@@ -29292,11 +29326,11 @@ var useConvertChildrenToCircuitJson = (children) => {
29292
29326
  };
29293
29327
 
29294
29328
  // src/hooks/use-stls-from-geom.ts
29295
- import { useState as useState9, useEffect as useEffect17 } from "react";
29329
+ import { useState as useState10, useEffect as useEffect17 } from "react";
29296
29330
  import stlSerializer from "@jscad/stl-serializer";
29297
29331
  var useStlsFromGeom = (geom) => {
29298
- const [stls, setStls] = useState9([]);
29299
- const [loading, setLoading] = useState9(true);
29332
+ const [stls, setStls] = useState10([]);
29333
+ const [loading, setLoading] = useState10(true);
29300
29334
  useEffect17(() => {
29301
29335
  if (!geom) return;
29302
29336
  const generateStls = async () => {
@@ -29326,7 +29360,7 @@ var useStlsFromGeom = (geom) => {
29326
29360
  };
29327
29361
 
29328
29362
  // src/hooks/useBoardGeomBuilder.ts
29329
- import { useState as useState10, useEffect as useEffect18, useRef as useRef7 } from "react";
29363
+ import { useState as useState11, useEffect as useEffect18, useRef as useRef8 } from "react";
29330
29364
 
29331
29365
  // src/soup-to-3d/index.ts
29332
29366
  var import_primitives2 = __toESM(require_primitives(), 1);
@@ -31186,8 +31220,8 @@ var BoardGeomBuilder = class {
31186
31220
 
31187
31221
  // src/hooks/useBoardGeomBuilder.ts
31188
31222
  var useBoardGeomBuilder = (circuitJson) => {
31189
- const [boardGeom, setBoardGeom] = useState10(null);
31190
- const isProcessingRef = useRef7(false);
31223
+ const [boardGeom, setBoardGeom] = useState11(null);
31224
+ const isProcessingRef = useRef8(false);
31191
31225
  useEffect18(() => {
31192
31226
  let isCancelled = false;
31193
31227
  if (!circuitJson) {
@@ -31231,17 +31265,72 @@ var useBoardGeomBuilder = (circuitJson) => {
31231
31265
  };
31232
31266
 
31233
31267
  // src/three-components/Error3d.tsx
31234
- import { useState as useState11, useCallback as useCallback6, useEffect as useEffect19, useMemo as useMemo17 } from "react";
31235
- import * as THREE15 from "three";
31236
- import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
31268
+ import { useState as useState12, useCallback as useCallback8, useEffect as useEffect20, useMemo as useMemo16 } from "react";
31269
+
31270
+ // src/react-three/Text.tsx
31271
+ import { useEffect as useEffect19, useMemo as useMemo15 } from "react";
31272
+ import { Text as TroikaText2 } from "troika-three-text";
31273
+ var Text = ({
31274
+ children,
31275
+ parent,
31276
+ position,
31277
+ rotation: rotation2,
31278
+ scale: scale2,
31279
+ color,
31280
+ fontSize,
31281
+ anchorX,
31282
+ anchorY,
31283
+ depthOffset
31284
+ }) => {
31285
+ const { rootObject } = useThree();
31286
+ const mesh = useMemo15(() => {
31287
+ const textMesh = new TroikaText2();
31288
+ textMesh.text = children;
31289
+ if (position) textMesh.position.fromArray(position);
31290
+ if (rotation2) textMesh.rotation.fromArray(rotation2);
31291
+ if (scale2) textMesh.scale.fromArray(scale2);
31292
+ textMesh.color = color || "white";
31293
+ textMesh.fontSize = fontSize || 1;
31294
+ textMesh.anchorX = anchorX || "center";
31295
+ textMesh.anchorY = anchorY || "middle";
31296
+ textMesh.depthOffset = depthOffset || 0;
31297
+ textMesh.font = null;
31298
+ textMesh.sync();
31299
+ return textMesh;
31300
+ }, [
31301
+ children,
31302
+ position,
31303
+ rotation2,
31304
+ scale2,
31305
+ color,
31306
+ fontSize,
31307
+ anchorX,
31308
+ anchorY,
31309
+ depthOffset
31310
+ ]);
31311
+ useEffect19(() => {
31312
+ const parentObject = parent || rootObject;
31313
+ if (!parentObject || !mesh) return;
31314
+ parentObject.add(mesh);
31315
+ return () => {
31316
+ parentObject.remove(mesh);
31317
+ mesh.dispose();
31318
+ };
31319
+ }, [rootObject, parent, mesh]);
31320
+ return null;
31321
+ };
31322
+
31323
+ // src/three-components/Error3d.tsx
31324
+ import * as THREE16 from "three";
31325
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs4 } from "react/jsx-runtime";
31237
31326
  var Error3d = ({
31238
31327
  error,
31239
31328
  cad_component: cad_component2
31240
31329
  }) => {
31241
31330
  const { rootObject } = useThree();
31242
- const [isHovered, setIsHovered] = useState11(false);
31243
- const [hoverPosition, setHoverPosition] = useState11(null);
31244
- const handleHover = useCallback6((e) => {
31331
+ const [isHovered, setIsHovered] = useState12(false);
31332
+ const [hoverPosition, setHoverPosition] = useState12(null);
31333
+ const handleHover = useCallback8((e) => {
31245
31334
  if (e?.mousePosition) {
31246
31335
  setIsHovered(true);
31247
31336
  setHoverPosition(e.mousePosition);
@@ -31250,11 +31339,11 @@ var Error3d = ({
31250
31339
  setHoverPosition(null);
31251
31340
  }
31252
31341
  }, []);
31253
- const handleUnhover = useCallback6(() => {
31342
+ const handleUnhover = useCallback8(() => {
31254
31343
  setIsHovered(false);
31255
31344
  setHoverPosition(null);
31256
31345
  }, []);
31257
- const position = useMemo17(() => {
31346
+ const position = useMemo16(() => {
31258
31347
  if (cad_component2?.position) {
31259
31348
  const p = [
31260
31349
  cad_component2.position.x,
@@ -31265,20 +31354,20 @@ var Error3d = ({
31265
31354
  }
31266
31355
  return [0, 0, 0];
31267
31356
  }, [cad_component2]);
31268
- const group = useMemo17(() => {
31269
- const g = new THREE15.Group();
31357
+ const group = useMemo16(() => {
31358
+ const g = new THREE16.Group();
31270
31359
  g.position.fromArray(position);
31271
31360
  return g;
31272
31361
  }, [position]);
31273
- useEffect19(() => {
31362
+ useEffect20(() => {
31274
31363
  if (!rootObject) return;
31275
31364
  rootObject.add(group);
31276
31365
  return () => {
31277
31366
  rootObject.remove(group);
31278
31367
  };
31279
31368
  }, [rootObject, group]);
31280
- return /* @__PURE__ */ jsxs5(Fragment5, { children: [
31281
- /* @__PURE__ */ jsxs5(
31369
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
31370
+ /* @__PURE__ */ jsxs4(
31282
31371
  ContainerWithTooltip_default,
31283
31372
  {
31284
31373
  isHovered,
@@ -31286,8 +31375,8 @@ var Error3d = ({
31286
31375
  onUnhover: handleUnhover,
31287
31376
  object: group,
31288
31377
  children: [
31289
- /* @__PURE__ */ jsx13(ErrorBox, { parent: group }),
31290
- /* @__PURE__ */ jsx13(
31378
+ /* @__PURE__ */ jsx14(ErrorBox, { parent: group }),
31379
+ /* @__PURE__ */ jsx14(
31291
31380
  Text,
31292
31381
  {
31293
31382
  parent: group,
@@ -31302,7 +31391,7 @@ var Error3d = ({
31302
31391
  ]
31303
31392
  }
31304
31393
  ),
31305
- isHovered && hoverPosition ? /* @__PURE__ */ jsx13(
31394
+ isHovered && hoverPosition ? /* @__PURE__ */ jsx14(
31306
31395
  Html,
31307
31396
  {
31308
31397
  position: hoverPosition,
@@ -31325,10 +31414,10 @@ var Error3d = ({
31325
31414
  ] });
31326
31415
  };
31327
31416
  var ErrorBox = ({ parent }) => {
31328
- const mesh = useMemo17(() => {
31329
- const m = new THREE15.Mesh(
31330
- new THREE15.BoxGeometry(0.5, 0.5, 0.5),
31331
- new THREE15.MeshStandardMaterial({
31417
+ const mesh = useMemo16(() => {
31418
+ const m = new THREE16.Mesh(
31419
+ new THREE16.BoxGeometry(0.5, 0.5, 0.5),
31420
+ new THREE16.MeshStandardMaterial({
31332
31421
  depthTest: false,
31333
31422
  transparent: true,
31334
31423
  color: "red",
@@ -31339,7 +31428,7 @@ var ErrorBox = ({ parent }) => {
31339
31428
  m.rotation.fromArray([Math.PI / 4, Math.PI / 4, 0]);
31340
31429
  return m;
31341
31430
  }, []);
31342
- useEffect19(() => {
31431
+ useEffect20(() => {
31343
31432
  parent.add(mesh);
31344
31433
  return () => {
31345
31434
  parent.remove(mesh);
@@ -31349,8 +31438,8 @@ var ErrorBox = ({ parent }) => {
31349
31438
  };
31350
31439
 
31351
31440
  // src/three-components/STLModel.tsx
31352
- import { useState as useState12, useEffect as useEffect20, useMemo as useMemo18 } from "react";
31353
- import * as THREE16 from "three";
31441
+ import { useState as useState13, useEffect as useEffect21, useMemo as useMemo17 } from "react";
31442
+ import * as THREE17 from "three";
31354
31443
  import { STLLoader } from "three-stdlib";
31355
31444
  function STLModel({
31356
31445
  stlUrl,
@@ -31360,8 +31449,8 @@ function STLModel({
31360
31449
  opacity = 1
31361
31450
  }) {
31362
31451
  const { rootObject } = useThree();
31363
- const [geom, setGeom] = useState12(null);
31364
- useEffect20(() => {
31452
+ const [geom, setGeom] = useState13(null);
31453
+ useEffect21(() => {
31365
31454
  const loader = new STLLoader();
31366
31455
  if (stlData) {
31367
31456
  try {
@@ -31379,16 +31468,16 @@ function STLModel({
31379
31468
  });
31380
31469
  }
31381
31470
  }, [stlUrl, stlData]);
31382
- const mesh = useMemo18(() => {
31471
+ const mesh = useMemo17(() => {
31383
31472
  if (!geom) return null;
31384
- const material = new THREE16.MeshStandardMaterial({
31385
- color: Array.isArray(color) ? new THREE16.Color(color[0], color[1], color[2]) : color,
31473
+ const material = new THREE17.MeshStandardMaterial({
31474
+ color: Array.isArray(color) ? new THREE17.Color(color[0], color[1], color[2]) : color,
31386
31475
  transparent: opacity !== 1,
31387
31476
  opacity
31388
31477
  });
31389
- return new THREE16.Mesh(geom, material);
31478
+ return new THREE17.Mesh(geom, material);
31390
31479
  }, [geom, color, opacity]);
31391
- useEffect20(() => {
31480
+ useEffect21(() => {
31392
31481
  if (!rootObject || !mesh) return;
31393
31482
  rootObject.add(mesh);
31394
31483
  return () => {
@@ -31405,7 +31494,7 @@ function STLModel({
31405
31494
  }
31406
31495
 
31407
31496
  // src/three-components/VisibleSTLModel.tsx
31408
- import { jsx as jsx14 } from "react/jsx-runtime";
31497
+ import { jsx as jsx15 } from "react/jsx-runtime";
31409
31498
  function VisibleSTLModel({
31410
31499
  stlData,
31411
31500
  color,
@@ -31428,7 +31517,7 @@ function VisibleSTLModel({
31428
31517
  if (!shouldShow) {
31429
31518
  return null;
31430
31519
  }
31431
- return /* @__PURE__ */ jsx14(STLModel, { stlData, color, opacity });
31520
+ return /* @__PURE__ */ jsx15(STLModel, { stlData, color, opacity });
31432
31521
  }
31433
31522
 
31434
31523
  // src/three-components/ThreeErrorBoundary.tsx
@@ -31449,8 +31538,95 @@ var ThreeErrorBoundary = class extends React11.Component {
31449
31538
  }
31450
31539
  };
31451
31540
 
31541
+ // src/utils/preprocess-circuit-json.ts
31542
+ import { su as su5 } from "@tscircuit/circuit-json-util";
31543
+
31544
+ // src/utils/create-faux-board.ts
31545
+ import { su as su4, getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
31546
+ function createFauxBoard(circuitJson) {
31547
+ const cadComponents = su4(circuitJson).cad_component.list();
31548
+ const pads = su4(circuitJson).pcb_smtpad.list();
31549
+ const holes = su4(circuitJson).pcb_hole.list();
31550
+ const platedHoles = su4(circuitJson).pcb_plated_hole.list();
31551
+ const vias = su4(circuitJson).pcb_via.list();
31552
+ if (cadComponents.length === 0 && pads.length === 0 && holes.length === 0 && platedHoles.length === 0 && vias.length === 0) {
31553
+ return null;
31554
+ }
31555
+ const pcbElements = [...holes, ...platedHoles, ...vias, ...pads];
31556
+ const bounds = getBoundsOfPcbElements(pcbElements);
31557
+ let minX = bounds.minX;
31558
+ let maxX = bounds.maxX;
31559
+ let minY = bounds.minY;
31560
+ let maxY = bounds.maxY;
31561
+ for (const component of cadComponents) {
31562
+ if (component.position) {
31563
+ const x = component.position.x;
31564
+ const y = component.position.y;
31565
+ minX = Math.min(minX, x);
31566
+ maxX = Math.max(maxX, x);
31567
+ minY = Math.min(minY, y);
31568
+ maxY = Math.max(maxY, y);
31569
+ }
31570
+ }
31571
+ if (minX === Infinity) {
31572
+ minX = -10;
31573
+ maxX = 10;
31574
+ minY = -10;
31575
+ maxY = 10;
31576
+ }
31577
+ const padding = 2;
31578
+ const halfWidth = Math.max(Math.abs(minX), Math.abs(maxX)) + padding;
31579
+ const halfHeight = Math.max(Math.abs(minY), Math.abs(maxY)) + padding;
31580
+ const width10 = Math.max(2 * halfWidth, 10);
31581
+ const height10 = Math.max(2 * halfHeight, 10);
31582
+ const fauxBoard = {
31583
+ type: "pcb_board",
31584
+ pcb_board_id: "faux-board",
31585
+ center: { x: 0, y: 0 },
31586
+ // Always center at origin like real boards
31587
+ width: width10,
31588
+ height: height10,
31589
+ thickness: 1.6,
31590
+ // standard thickness
31591
+ material: "fr4",
31592
+ num_layers: 2
31593
+ // No outline - will use rectangular shape
31594
+ };
31595
+ return fauxBoard;
31596
+ }
31597
+
31598
+ // src/utils/preprocess-circuit-json.ts
31599
+ function addFauxBoardIfNeeded(circuitJson) {
31600
+ const boards = su5(circuitJson).pcb_board.list();
31601
+ if (boards.length > 0) {
31602
+ return circuitJson;
31603
+ }
31604
+ const fauxBoard = createFauxBoard(circuitJson);
31605
+ if (!fauxBoard) {
31606
+ return circuitJson;
31607
+ }
31608
+ const boardThickness = fauxBoard.thickness;
31609
+ const componentZ = boardThickness / 2;
31610
+ const processedCircuitJson = circuitJson.map((element) => {
31611
+ if (element.type === "cad_component") {
31612
+ const cadComponent = element;
31613
+ if (cadComponent.position) {
31614
+ return {
31615
+ ...cadComponent,
31616
+ position: {
31617
+ ...cadComponent.position,
31618
+ z: componentZ
31619
+ }
31620
+ };
31621
+ }
31622
+ }
31623
+ return element;
31624
+ });
31625
+ return [...processedCircuitJson, fauxBoard];
31626
+ }
31627
+
31452
31628
  // src/CadViewerJscad.tsx
31453
- import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
31629
+ import { jsx as jsx16, jsxs as jsxs5 } from "react/jsx-runtime";
31454
31630
  var CadViewerJscad = forwardRef3(
31455
31631
  ({
31456
31632
  soup,
@@ -31462,15 +31638,15 @@ var CadViewerJscad = forwardRef3(
31462
31638
  onCameraControllerReady
31463
31639
  }, ref) => {
31464
31640
  const childrenSoup = useConvertChildrenToCircuitJson(children);
31465
- const internalCircuitJson = useMemo19(() => {
31641
+ const internalCircuitJson = useMemo18(() => {
31466
31642
  const cj = soup ?? circuitJson;
31467
- return cj ?? childrenSoup;
31643
+ return addFauxBoardIfNeeded(cj ?? childrenSoup);
31468
31644
  }, [soup, circuitJson, childrenSoup]);
31469
31645
  const boardGeom = useBoardGeomBuilder(internalCircuitJson);
31470
- const initialCameraPosition = useMemo19(() => {
31646
+ const initialCameraPosition = useMemo18(() => {
31471
31647
  if (!internalCircuitJson) return [5, -5, 5];
31472
31648
  try {
31473
- const board = su4(internalCircuitJson).pcb_board.list()[0];
31649
+ const board = su6(internalCircuitJson).pcb_board.list()[0];
31474
31650
  if (!board) return [5, -5, 5];
31475
31651
  const { width: width10, height: height10 } = board;
31476
31652
  if (!width10 && !height10) {
@@ -31493,10 +31669,19 @@ var CadViewerJscad = forwardRef3(
31493
31669
  return [5, -5, 5];
31494
31670
  }
31495
31671
  }, [internalCircuitJson]);
31496
- const boardDimensions = useMemo19(() => {
31672
+ const isFauxBoard = useMemo18(() => {
31673
+ if (!internalCircuitJson) return false;
31674
+ try {
31675
+ const board = su6(internalCircuitJson).pcb_board.list()[0];
31676
+ return !!board && board.pcb_board_id === "faux-board";
31677
+ } catch (e) {
31678
+ return false;
31679
+ }
31680
+ }, [internalCircuitJson]);
31681
+ const boardDimensions = useMemo18(() => {
31497
31682
  if (!internalCircuitJson) return void 0;
31498
31683
  try {
31499
- const board = su4(internalCircuitJson).pcb_board.list()[0];
31684
+ const board = su6(internalCircuitJson).pcb_board.list()[0];
31500
31685
  if (!board) return void 0;
31501
31686
  return { width: board.width ?? 0, height: board.height ?? 0 };
31502
31687
  } catch (e) {
@@ -31504,10 +31689,10 @@ var CadViewerJscad = forwardRef3(
31504
31689
  return void 0;
31505
31690
  }
31506
31691
  }, [internalCircuitJson]);
31507
- const boardCenter = useMemo19(() => {
31692
+ const boardCenter = useMemo18(() => {
31508
31693
  if (!internalCircuitJson) return void 0;
31509
31694
  try {
31510
- const board = su4(internalCircuitJson).pcb_board.list()[0];
31695
+ const board = su6(internalCircuitJson).pcb_board.list()[0];
31511
31696
  if (!board || !board.center) return void 0;
31512
31697
  return { x: board.center.x, y: board.center.y };
31513
31698
  } catch (e) {
@@ -31516,8 +31701,8 @@ var CadViewerJscad = forwardRef3(
31516
31701
  }
31517
31702
  }, [internalCircuitJson]);
31518
31703
  const { stls: boardStls, loading } = useStlsFromGeom(boardGeom);
31519
- const cad_components = su4(internalCircuitJson).cad_component.list();
31520
- return /* @__PURE__ */ jsxs6(
31704
+ const cad_components = su6(internalCircuitJson).cad_component.list();
31705
+ return /* @__PURE__ */ jsxs5(
31521
31706
  CadViewerContainer,
31522
31707
  {
31523
31708
  ref,
@@ -31529,21 +31714,21 @@ var CadViewerJscad = forwardRef3(
31529
31714
  onUserInteraction,
31530
31715
  onCameraControllerReady,
31531
31716
  children: [
31532
- boardStls.map(({ stlData, color, layerType }, index2) => /* @__PURE__ */ jsx15(
31717
+ boardStls.map(({ stlData, color, layerType }, index2) => /* @__PURE__ */ jsx16(
31533
31718
  VisibleSTLModel,
31534
31719
  {
31535
31720
  stlData,
31536
31721
  color,
31537
- opacity: index2 === 0 ? 0.95 : 1,
31722
+ opacity: index2 === 0 ? isFauxBoard ? 0.8 : 0.95 : 1,
31538
31723
  layerType
31539
31724
  },
31540
31725
  `board-${index2}`
31541
31726
  )),
31542
- cad_components.map((cad_component2) => /* @__PURE__ */ jsx15(
31727
+ cad_components.map((cad_component2) => /* @__PURE__ */ jsx16(
31543
31728
  ThreeErrorBoundary,
31544
31729
  {
31545
- fallback: ({ error }) => /* @__PURE__ */ jsx15(Error3d, { cad_component: cad_component2, error }),
31546
- children: /* @__PURE__ */ jsx15(
31730
+ fallback: ({ error }) => /* @__PURE__ */ jsx16(Error3d, { cad_component: cad_component2, error }),
31731
+ children: /* @__PURE__ */ jsx16(
31547
31732
  AnyCadComponent,
31548
31733
  {
31549
31734
  cad_component: cad_component2,
@@ -31561,23 +31746,23 @@ var CadViewerJscad = forwardRef3(
31561
31746
  );
31562
31747
 
31563
31748
  // src/CadViewerManifold.tsx
31564
- import { su as su13 } from "@tscircuit/circuit-json-util";
31565
- import { useEffect as useEffect22, useMemo as useMemo21, useState as useState15 } from "react";
31749
+ import { su as su15 } from "@tscircuit/circuit-json-util";
31750
+ import { useEffect as useEffect23, useMemo as useMemo20, useState as useState16 } from "react";
31566
31751
 
31567
31752
  // src/hooks/useManifoldBoardBuilder.ts
31568
- import { useState as useState14, useEffect as useEffect21, useMemo as useMemo20, useRef as useRef8 } from "react";
31569
- import { su as su12 } from "@tscircuit/circuit-json-util";
31570
- import * as THREE24 from "three";
31753
+ import { useState as useState15, useEffect as useEffect22, useMemo as useMemo19, useRef as useRef9 } from "react";
31754
+ import { su as su14 } from "@tscircuit/circuit-json-util";
31755
+ import * as THREE25 from "three";
31571
31756
 
31572
31757
  // src/utils/manifold-mesh-to-three-geometry.ts
31573
- import * as THREE17 from "three";
31758
+ import * as THREE18 from "three";
31574
31759
  function manifoldMeshToThreeGeometry(manifoldMesh) {
31575
- const geometry = new THREE17.BufferGeometry();
31760
+ const geometry = new THREE18.BufferGeometry();
31576
31761
  geometry.setAttribute(
31577
31762
  "position",
31578
- new THREE17.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
31763
+ new THREE18.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
31579
31764
  );
31580
- geometry.setIndex(new THREE17.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
31765
+ geometry.setIndex(new THREE18.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
31581
31766
  if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
31582
31767
  for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
31583
31768
  const start = manifoldMesh.runIndex[i];
@@ -31591,8 +31776,8 @@ function manifoldMeshToThreeGeometry(manifoldMesh) {
31591
31776
  }
31592
31777
 
31593
31778
  // src/utils/trace-texture.ts
31594
- import * as THREE18 from "three";
31595
- import { su as su5 } from "@tscircuit/circuit-json-util";
31779
+ import * as THREE19 from "three";
31780
+ import { su as su7 } from "@tscircuit/circuit-json-util";
31596
31781
  function isWireRoutePoint(point2) {
31597
31782
  return point2 && point2.route_type === "wire" && typeof point2.layer === "string" && typeof point2.width === "number";
31598
31783
  }
@@ -31603,9 +31788,9 @@ function createTraceTextureForLayer({
31603
31788
  traceColor,
31604
31789
  traceTextureResolution
31605
31790
  }) {
31606
- const pcbTraces = su5(circuitJson).pcb_trace.list();
31607
- const allPcbVias = su5(circuitJson).pcb_via.list();
31608
- const allPcbPlatedHoles = su5(
31791
+ const pcbTraces = su7(circuitJson).pcb_trace.list();
31792
+ const allPcbVias = su7(circuitJson).pcb_via.list();
31793
+ const allPcbPlatedHoles = su7(
31609
31794
  circuitJson
31610
31795
  ).pcb_plated_hole.list();
31611
31796
  const tracesOnLayer = pcbTraces.filter(
@@ -31674,10 +31859,10 @@ function createTraceTextureForLayer({
31674
31859
  }
31675
31860
  });
31676
31861
  ctx.globalCompositeOperation = "source-over";
31677
- const texture = new THREE18.CanvasTexture(canvas);
31862
+ const texture = new THREE19.CanvasTexture(canvas);
31678
31863
  texture.generateMipmaps = true;
31679
- texture.minFilter = THREE18.LinearMipmapLinearFilter;
31680
- texture.magFilter = THREE18.LinearFilter;
31864
+ texture.minFilter = THREE19.LinearMipmapLinearFilter;
31865
+ texture.magFilter = THREE19.LinearFilter;
31681
31866
  texture.anisotropy = 16;
31682
31867
  texture.needsUpdate = true;
31683
31868
  return texture;
@@ -31685,8 +31870,8 @@ function createTraceTextureForLayer({
31685
31870
 
31686
31871
  // src/utils/silkscreen-texture.ts
31687
31872
  var import_text2 = __toESM(require_text(), 1);
31688
- import * as THREE19 from "three";
31689
- import { su as su6 } from "@tscircuit/circuit-json-util";
31873
+ import * as THREE20 from "three";
31874
+ import { su as su8 } from "@tscircuit/circuit-json-util";
31690
31875
  function createSilkscreenTextureForLayer({
31691
31876
  layer,
31692
31877
  circuitJson,
@@ -31694,11 +31879,11 @@ function createSilkscreenTextureForLayer({
31694
31879
  silkscreenColor = "rgb(255,255,255)",
31695
31880
  traceTextureResolution
31696
31881
  }) {
31697
- const pcbSilkscreenTexts = su6(circuitJson).pcb_silkscreen_text.list();
31698
- const pcbSilkscreenPaths = su6(circuitJson).pcb_silkscreen_path.list();
31699
- const pcbSilkscreenLines = su6(circuitJson).pcb_silkscreen_line.list();
31700
- const pcbSilkscreenRects = su6(circuitJson).pcb_silkscreen_rect.list();
31701
- const pcbSilkscreenCircles = su6(circuitJson).pcb_silkscreen_circle.list();
31882
+ const pcbSilkscreenTexts = su8(circuitJson).pcb_silkscreen_text.list();
31883
+ const pcbSilkscreenPaths = su8(circuitJson).pcb_silkscreen_path.list();
31884
+ const pcbSilkscreenLines = su8(circuitJson).pcb_silkscreen_line.list();
31885
+ const pcbSilkscreenRects = su8(circuitJson).pcb_silkscreen_rect.list();
31886
+ const pcbSilkscreenCircles = su8(circuitJson).pcb_silkscreen_circle.list();
31702
31887
  const textsOnLayer = pcbSilkscreenTexts.filter((t) => t.layer === layer);
31703
31888
  const pathsOnLayer = pcbSilkscreenPaths.filter((p) => p.layer === layer);
31704
31889
  const linesOnLayer = pcbSilkscreenLines.filter((l) => l.layer === layer);
@@ -31943,17 +32128,17 @@ function createSilkscreenTextureForLayer({
31943
32128
  ctx.stroke();
31944
32129
  });
31945
32130
  });
31946
- const texture = new THREE19.CanvasTexture(canvas);
32131
+ const texture = new THREE20.CanvasTexture(canvas);
31947
32132
  texture.generateMipmaps = true;
31948
- texture.minFilter = THREE19.LinearMipmapLinearFilter;
31949
- texture.magFilter = THREE19.LinearFilter;
32133
+ texture.minFilter = THREE20.LinearMipmapLinearFilter;
32134
+ texture.magFilter = THREE20.LinearFilter;
31950
32135
  texture.anisotropy = 16;
31951
32136
  texture.needsUpdate = true;
31952
32137
  return texture;
31953
32138
  }
31954
32139
 
31955
32140
  // src/utils/manifold/process-non-plated-holes.ts
31956
- import { su as su7 } from "@tscircuit/circuit-json-util";
32141
+ import { su as su9 } from "@tscircuit/circuit-json-util";
31957
32142
 
31958
32143
  // src/utils/hole-geoms.ts
31959
32144
  function createCircleHoleDrill({
@@ -32080,7 +32265,7 @@ function isRotatedPillHole(hole) {
32080
32265
  }
32081
32266
  function processNonPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
32082
32267
  const nonPlatedHoleBoardDrills = [];
32083
- const pcbHoles = su7(circuitJson).pcb_hole.list();
32268
+ const pcbHoles = su9(circuitJson).pcb_hole.list();
32084
32269
  const createPillOp = (width10, height10, depth) => {
32085
32270
  const pillOp = createRoundedRectPrism({
32086
32271
  Manifold,
@@ -32129,13 +32314,13 @@ function processNonPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, m
32129
32314
  }
32130
32315
 
32131
32316
  // src/utils/manifold/process-plated-holes.ts
32132
- import { su as su8 } from "@tscircuit/circuit-json-util";
32133
- import * as THREE20 from "three";
32134
- var COPPER_COLOR = new THREE20.Color(...colors.copper);
32317
+ import { su as su10 } from "@tscircuit/circuit-json-util";
32318
+ import * as THREE21 from "three";
32319
+ var COPPER_COLOR = new THREE21.Color(...colors.copper);
32135
32320
  var PLATED_HOLE_LIP_HEIGHT = 0.05;
32136
32321
  function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
32137
32322
  const platedHoleBoardDrills = [];
32138
- const pcbPlatedHoles = su8(circuitJson).pcb_plated_hole.list();
32323
+ const pcbPlatedHoles = su10(circuitJson).pcb_plated_hole.list();
32139
32324
  const platedHoleCopperGeoms = [];
32140
32325
  const platedHoleCopperOpsForSubtract = [];
32141
32326
  const createPillOp = (width10, height10, depth) => {
@@ -32448,8 +32633,8 @@ function processPlatedHolesForManifold(Manifold, circuitJson, pcbThickness, mani
32448
32633
  }
32449
32634
 
32450
32635
  // src/utils/manifold/process-vias.ts
32451
- import { su as su9 } from "@tscircuit/circuit-json-util";
32452
- import * as THREE21 from "three";
32636
+ import { su as su11 } from "@tscircuit/circuit-json-util";
32637
+ import * as THREE22 from "three";
32453
32638
 
32454
32639
  // src/utils/via-geoms.ts
32455
32640
  function createViaCopper({
@@ -32482,10 +32667,10 @@ function createViaCopper({
32482
32667
  }
32483
32668
 
32484
32669
  // src/utils/manifold/process-vias.ts
32485
- var COPPER_COLOR2 = new THREE21.Color(...colors.copper);
32670
+ var COPPER_COLOR2 = new THREE22.Color(...colors.copper);
32486
32671
  function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
32487
32672
  const viaBoardDrills = [];
32488
- const pcbVias = su9(circuitJson).pcb_via.list();
32673
+ const pcbVias = su11(circuitJson).pcb_via.list();
32489
32674
  const viaCopperGeoms = [];
32490
32675
  pcbVias.forEach((via, index2) => {
32491
32676
  if (typeof via.outer_diameter === "number") {
@@ -32534,12 +32719,12 @@ function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldIns
32534
32719
  }
32535
32720
 
32536
32721
  // src/utils/manifold/process-smt-pads.ts
32537
- import { su as su10 } from "@tscircuit/circuit-json-util";
32538
- import * as THREE22 from "three";
32539
- var COPPER_COLOR3 = new THREE22.Color(...colors.copper);
32722
+ import { su as su12 } from "@tscircuit/circuit-json-util";
32723
+ import * as THREE23 from "three";
32724
+ var COPPER_COLOR3 = new THREE23.Color(...colors.copper);
32540
32725
  function processSmtPadsForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, holeUnion, boardClipVolume) {
32541
32726
  const smtPadGeoms = [];
32542
- const smtPads = su10(circuitJson).pcb_smtpad.list();
32727
+ const smtPads = su12(circuitJson).pcb_smtpad.list();
32543
32728
  smtPads.forEach((pad2, index2) => {
32544
32729
  const padBaseThickness = DEFAULT_SMT_PAD_THICKNESS;
32545
32730
  const zPos = pad2.layer === "bottom" ? -pcbThickness / 2 - BOARD_SURFACE_OFFSET.copper : pcbThickness / 2 + BOARD_SURFACE_OFFSET.copper;
@@ -32632,7 +32817,7 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
32632
32817
  }
32633
32818
 
32634
32819
  // src/utils/manifold/process-copper-pours.ts
32635
- import * as THREE23 from "three";
32820
+ import * as THREE24 from "three";
32636
32821
  var arePointsClockwise4 = (points) => {
32637
32822
  let area = 0;
32638
32823
  for (let i = 0; i < points.length; i++) {
@@ -32792,7 +32977,7 @@ function processCopperPoursForManifold(Manifold, CrossSection, circuitJson, pcbT
32792
32977
  }
32793
32978
  const covered = pour.covered_with_solder_mask !== false;
32794
32979
  const pourColorArr = covered ? tracesMaterialColors[boardMaterial] ?? colors.fr4GreenSolderWithMask : colors.copper;
32795
- const pourColor = new THREE23.Color(...pourColorArr);
32980
+ const pourColor = new THREE24.Color(...pourColorArr);
32796
32981
  const threeGeom = manifoldMeshToThreeGeometry(pourOp.getMesh());
32797
32982
  copperPourGeoms.push({
32798
32983
  key: `coppour-${pour.pcb_copper_pour_id}`,
@@ -32805,7 +32990,7 @@ function processCopperPoursForManifold(Manifold, CrossSection, circuitJson, pcbT
32805
32990
  }
32806
32991
 
32807
32992
  // src/utils/manifold/process-cutouts.ts
32808
- import { su as su11 } from "@tscircuit/circuit-json-util";
32993
+ import { su as su13 } from "@tscircuit/circuit-json-util";
32809
32994
  var arePointsClockwise5 = (points) => {
32810
32995
  let area = 0;
32811
32996
  for (let i = 0; i < points.length; i++) {
@@ -32820,7 +33005,7 @@ var arePointsClockwise5 = (points) => {
32820
33005
  };
32821
33006
  function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
32822
33007
  const cutoutOps = [];
32823
- const pcbCutouts = su11(circuitJson).pcb_cutout.list();
33008
+ const pcbCutouts = su13(circuitJson).pcb_cutout.list();
32824
33009
  for (const cutout of pcbCutouts) {
32825
33010
  let cutoutOp;
32826
33011
  const cutoutHeight = pcbThickness * 1.5;
@@ -32905,20 +33090,21 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
32905
33090
 
32906
33091
  // src/hooks/useManifoldBoardBuilder.ts
32907
33092
  var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
32908
- const [geoms, setGeoms] = useState14(null);
32909
- const [textures, setTextures] = useState14(null);
32910
- const [pcbThickness, setPcbThickness] = useState14(null);
32911
- const [error, setError] = useState14(null);
32912
- const [isLoading, setIsLoading] = useState14(true);
32913
- const manifoldInstancesForCleanup = useRef8([]);
32914
- const boardData = useMemo20(() => {
32915
- const boards = su12(circuitJson).pcb_board.list();
32916
- if (boards.length === 0) {
32917
- return null;
32918
- }
32919
- return boards[0];
33093
+ const [geoms, setGeoms] = useState15(null);
33094
+ const [textures, setTextures] = useState15(null);
33095
+ const [pcbThickness, setPcbThickness] = useState15(null);
33096
+ const [error, setError] = useState15(null);
33097
+ const [isLoading, setIsLoading] = useState15(true);
33098
+ const manifoldInstancesForCleanup = useRef9([]);
33099
+ const boardData = useMemo19(() => {
33100
+ const boards = su14(circuitJson).pcb_board.list();
33101
+ return boards.length > 0 ? boards[0] : null;
32920
33102
  }, [circuitJson]);
32921
- useEffect21(() => {
33103
+ const isFauxBoard = useMemo19(() => {
33104
+ const boards = su14(circuitJson).pcb_board.list();
33105
+ return boards.length > 0 && boards[0].pcb_board_id === "faux-board";
33106
+ }, [circuitJson]);
33107
+ useEffect22(() => {
32922
33108
  if (!manifoldJSModule || !boardData) {
32923
33109
  setGeoms(null);
32924
33110
  setTextures(null);
@@ -33049,7 +33235,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
33049
33235
  {
33050
33236
  key: "plated-holes-union",
33051
33237
  geometry: cutPlatedGeom,
33052
- color: new THREE24.Color(
33238
+ color: new THREE25.Color(
33053
33239
  colors.copper[0],
33054
33240
  colors.copper[1],
33055
33241
  colors.copper[2]
@@ -33079,12 +33265,13 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
33079
33265
  const matColorArray = boardMaterialColors[boardData.material] ?? colors.fr4Green;
33080
33266
  currentGeoms.board = {
33081
33267
  geometry: finalBoardGeom,
33082
- color: new THREE24.Color(
33268
+ color: new THREE25.Color(
33083
33269
  matColorArray[0],
33084
33270
  matColorArray[1],
33085
33271
  matColorArray[2]
33086
33272
  ),
33087
- material: boardData.material
33273
+ material: boardData.material,
33274
+ isFaux: isFauxBoard
33088
33275
  };
33089
33276
  }
33090
33277
  const { smtPadGeoms } = processSmtPadsForManifold(
@@ -33161,23 +33348,25 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson) => {
33161
33348
  pcbThickness,
33162
33349
  error,
33163
33350
  isLoading,
33164
- boardData
33351
+ boardData,
33352
+ isFauxBoard
33165
33353
  };
33166
33354
  };
33167
33355
 
33168
33356
  // src/utils/manifold/create-three-geometry-meshes.ts
33169
- import * as THREE26 from "three";
33357
+ import * as THREE27 from "three";
33170
33358
 
33171
33359
  // src/utils/create-board-material.ts
33172
- import * as THREE25 from "three";
33173
- var DEFAULT_SIDE = THREE25.DoubleSide;
33360
+ import * as THREE26 from "three";
33361
+ var DEFAULT_SIDE = THREE26.DoubleSide;
33174
33362
  var createBoardMaterial = ({
33175
33363
  material,
33176
33364
  color,
33177
- side = DEFAULT_SIDE
33365
+ side = DEFAULT_SIDE,
33366
+ isFaux = false
33178
33367
  }) => {
33179
33368
  if (material === "fr4") {
33180
- return new THREE25.MeshPhysicalMaterial({
33369
+ return new THREE26.MeshPhysicalMaterial({
33181
33370
  color,
33182
33371
  side,
33183
33372
  metalness: 0,
@@ -33186,19 +33375,19 @@ var createBoardMaterial = ({
33186
33375
  ior: 1.45,
33187
33376
  sheen: 0,
33188
33377
  clearcoat: 0,
33189
- transparent: false,
33190
- opacity: 1,
33378
+ transparent: isFaux,
33379
+ opacity: isFaux ? 0.6 : 1,
33191
33380
  flatShading: true
33192
33381
  });
33193
33382
  }
33194
- return new THREE25.MeshStandardMaterial({
33383
+ return new THREE26.MeshStandardMaterial({
33195
33384
  color,
33196
33385
  side,
33197
33386
  flatShading: true,
33198
33387
  metalness: 0.1,
33199
33388
  roughness: 0.8,
33200
33389
  transparent: true,
33201
- opacity: 0.9
33390
+ opacity: isFaux ? 0.6 : 0.9
33202
33391
  });
33203
33392
  };
33204
33393
 
@@ -33207,12 +33396,13 @@ function createGeometryMeshes(geoms) {
33207
33396
  const meshes = [];
33208
33397
  if (!geoms) return meshes;
33209
33398
  if (geoms.board && geoms.board.geometry) {
33210
- const mesh = new THREE26.Mesh(
33399
+ const mesh = new THREE27.Mesh(
33211
33400
  geoms.board.geometry,
33212
33401
  createBoardMaterial({
33213
33402
  material: geoms.board.material,
33214
33403
  color: geoms.board.color,
33215
- side: THREE26.DoubleSide
33404
+ side: THREE27.DoubleSide,
33405
+ isFaux: geoms.board.isFaux
33216
33406
  })
33217
33407
  );
33218
33408
  mesh.name = "board-geom";
@@ -33221,11 +33411,11 @@ function createGeometryMeshes(geoms) {
33221
33411
  const createMeshesFromArray = (geomArray) => {
33222
33412
  if (geomArray) {
33223
33413
  geomArray.forEach((comp) => {
33224
- const mesh = new THREE26.Mesh(
33414
+ const mesh = new THREE27.Mesh(
33225
33415
  comp.geometry,
33226
- new THREE26.MeshStandardMaterial({
33416
+ new THREE27.MeshStandardMaterial({
33227
33417
  color: comp.color,
33228
- side: THREE26.DoubleSide,
33418
+ side: THREE27.DoubleSide,
33229
33419
  flatShading: true
33230
33420
  // Consistent with board
33231
33421
  })
@@ -33243,21 +33433,21 @@ function createGeometryMeshes(geoms) {
33243
33433
  }
33244
33434
 
33245
33435
  // src/utils/manifold/create-three-texture-meshes.ts
33246
- import * as THREE27 from "three";
33436
+ import * as THREE28 from "three";
33247
33437
  function createTextureMeshes(textures, boardData, pcbThickness) {
33248
33438
  const meshes = [];
33249
33439
  if (!textures || !boardData || pcbThickness === null) return meshes;
33250
33440
  const createTexturePlane = (texture, yOffset, isBottomLayer, keySuffix) => {
33251
33441
  if (!texture) return null;
33252
- const planeGeom = new THREE27.PlaneGeometry(boardData.width, boardData.height);
33253
- const material = new THREE27.MeshBasicMaterial({
33442
+ const planeGeom = new THREE28.PlaneGeometry(boardData.width, boardData.height);
33443
+ const material = new THREE28.MeshBasicMaterial({
33254
33444
  map: texture,
33255
33445
  transparent: true,
33256
- side: THREE27.DoubleSide,
33446
+ side: THREE28.DoubleSide,
33257
33447
  depthWrite: false
33258
33448
  // Important for layers to avoid z-fighting issues with board itself
33259
33449
  });
33260
- const mesh = new THREE27.Mesh(planeGeom, material);
33450
+ const mesh = new THREE28.Mesh(planeGeom, material);
33261
33451
  mesh.position.set(boardData.center.x, boardData.center.y, yOffset);
33262
33452
  if (isBottomLayer) {
33263
33453
  mesh.rotation.set(Math.PI, 0, 0);
@@ -33300,14 +33490,14 @@ function createTextureMeshes(textures, boardData, pcbThickness) {
33300
33490
  }
33301
33491
 
33302
33492
  // src/CadViewerManifold.tsx
33303
- import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
33493
+ import { jsx as jsx17, jsxs as jsxs6 } from "react/jsx-runtime";
33304
33494
  var BoardMeshes = ({
33305
33495
  geometryMeshes,
33306
33496
  textureMeshes
33307
33497
  }) => {
33308
33498
  const { rootObject } = useThree();
33309
33499
  const { visibility } = useLayerVisibility();
33310
- useEffect22(() => {
33500
+ useEffect23(() => {
33311
33501
  if (!rootObject) return;
33312
33502
  geometryMeshes.forEach((mesh) => {
33313
33503
  let shouldShow = true;
@@ -33370,12 +33560,13 @@ var CadViewerManifold = ({
33370
33560
  onCameraControllerReady
33371
33561
  }) => {
33372
33562
  const childrenCircuitJson = useConvertChildrenToCircuitJson(children);
33373
- const circuitJson = useMemo21(() => {
33374
- return circuitJsonProp ?? childrenCircuitJson;
33563
+ const circuitJson = useMemo20(() => {
33564
+ const rawCircuitJson = circuitJsonProp ?? childrenCircuitJson;
33565
+ return addFauxBoardIfNeeded(rawCircuitJson);
33375
33566
  }, [circuitJsonProp, childrenCircuitJson]);
33376
- const [manifoldJSModule, setManifoldJSModule] = useState15(null);
33377
- const [manifoldLoadingError, setManifoldLoadingError] = useState15(null);
33378
- useEffect22(() => {
33567
+ const [manifoldJSModule, setManifoldJSModule] = useState16(null);
33568
+ const [manifoldLoadingError, setManifoldLoadingError] = useState16(null);
33569
+ useEffect23(() => {
33379
33570
  if (window.ManifoldModule && typeof window.ManifoldModule === "object" && window.ManifoldModule.setup) {
33380
33571
  setManifoldJSModule(window.ManifoldModule);
33381
33572
  return;
@@ -33445,27 +33636,27 @@ try {
33445
33636
  isLoading: builderIsLoading,
33446
33637
  boardData
33447
33638
  } = useManifoldBoardBuilder(manifoldJSModule, circuitJson);
33448
- const geometryMeshes = useMemo21(() => createGeometryMeshes(geoms), [geoms]);
33449
- const textureMeshes = useMemo21(
33639
+ const geometryMeshes = useMemo20(() => createGeometryMeshes(geoms), [geoms]);
33640
+ const textureMeshes = useMemo20(
33450
33641
  () => createTextureMeshes(textures, boardData, pcbThickness),
33451
33642
  [textures, boardData, pcbThickness]
33452
33643
  );
33453
- const cadComponents = useMemo21(
33454
- () => su13(circuitJson).cad_component.list(),
33644
+ const cadComponents = useMemo20(
33645
+ () => su15(circuitJson).cad_component.list(),
33455
33646
  [circuitJson]
33456
33647
  );
33457
- const boardDimensions = useMemo21(() => {
33648
+ const boardDimensions = useMemo20(() => {
33458
33649
  if (!boardData) return void 0;
33459
33650
  const { width: width10 = 0, height: height10 = 0 } = boardData;
33460
33651
  return { width: width10, height: height10 };
33461
33652
  }, [boardData]);
33462
- const boardCenter = useMemo21(() => {
33653
+ const boardCenter = useMemo20(() => {
33463
33654
  if (!boardData) return void 0;
33464
33655
  const { center } = boardData;
33465
33656
  if (!center) return void 0;
33466
33657
  return { x: center.x, y: center.y };
33467
33658
  }, [boardData]);
33468
- const initialCameraPosition = useMemo21(() => {
33659
+ const initialCameraPosition = useMemo20(() => {
33469
33660
  if (!boardData) return [5, -5, 5];
33470
33661
  const { width: width10 = 0, height: height10 = 0 } = boardData;
33471
33662
  const safeWidth = Math.max(width10, 1);
@@ -33481,7 +33672,7 @@ try {
33481
33672
  ];
33482
33673
  }, [boardData]);
33483
33674
  if (manifoldLoadingError) {
33484
- return /* @__PURE__ */ jsxs7(
33675
+ return /* @__PURE__ */ jsxs6(
33485
33676
  "div",
33486
33677
  {
33487
33678
  style: {
@@ -33498,10 +33689,10 @@ try {
33498
33689
  );
33499
33690
  }
33500
33691
  if (!manifoldJSModule) {
33501
- return /* @__PURE__ */ jsx16("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
33692
+ return /* @__PURE__ */ jsx17("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
33502
33693
  }
33503
33694
  if (builderError) {
33504
- return /* @__PURE__ */ jsxs7(
33695
+ return /* @__PURE__ */ jsxs6(
33505
33696
  "div",
33506
33697
  {
33507
33698
  style: {
@@ -33518,9 +33709,9 @@ try {
33518
33709
  );
33519
33710
  }
33520
33711
  if (builderIsLoading) {
33521
- return /* @__PURE__ */ jsx16("div", { style: { padding: "1em" }, children: "Processing board geometry..." });
33712
+ return /* @__PURE__ */ jsx17("div", { style: { padding: "1em" }, children: "Processing board geometry..." });
33522
33713
  }
33523
- return /* @__PURE__ */ jsxs7(
33714
+ return /* @__PURE__ */ jsxs6(
33524
33715
  CadViewerContainer,
33525
33716
  {
33526
33717
  initialCameraPosition,
@@ -33531,18 +33722,18 @@ try {
33531
33722
  onUserInteraction,
33532
33723
  onCameraControllerReady,
33533
33724
  children: [
33534
- /* @__PURE__ */ jsx16(
33725
+ /* @__PURE__ */ jsx17(
33535
33726
  BoardMeshes,
33536
33727
  {
33537
33728
  geometryMeshes,
33538
33729
  textureMeshes
33539
33730
  }
33540
33731
  ),
33541
- cadComponents.map((cad_component2) => /* @__PURE__ */ jsx16(
33732
+ cadComponents.map((cad_component2) => /* @__PURE__ */ jsx17(
33542
33733
  ThreeErrorBoundary,
33543
33734
  {
33544
- fallback: ({ error }) => /* @__PURE__ */ jsx16(Error3d, { cad_component: cad_component2, error }),
33545
- children: /* @__PURE__ */ jsx16(
33735
+ fallback: ({ error }) => /* @__PURE__ */ jsx17(Error3d, { cad_component: cad_component2, error }),
33736
+ children: /* @__PURE__ */ jsx17(
33546
33737
  AnyCadComponent,
33547
33738
  {
33548
33739
  cad_component: cad_component2,
@@ -33559,24 +33750,24 @@ try {
33559
33750
  var CadViewerManifold_default = CadViewerManifold;
33560
33751
 
33561
33752
  // src/hooks/useContextMenu.ts
33562
- import { useState as useState16, useCallback as useCallback8, useRef as useRef9, useEffect as useEffect23 } from "react";
33753
+ import { useState as useState17, useCallback as useCallback10, useRef as useRef10, useEffect as useEffect24 } from "react";
33563
33754
  var useContextMenu = ({ containerRef }) => {
33564
- const [menuVisible, setMenuVisible] = useState16(false);
33565
- const [menuPos, setMenuPos] = useState16({
33755
+ const [menuVisible, setMenuVisible] = useState17(false);
33756
+ const [menuPos, setMenuPos] = useState17({
33566
33757
  x: 0,
33567
33758
  y: 0
33568
33759
  });
33569
- const menuRef = useRef9(null);
33570
- const interactionOriginPosRef = useRef9(null);
33571
- const longPressTimeoutRef = useRef9(null);
33572
- const ignoreNextContextMenuRef = useRef9(false);
33760
+ const menuRef = useRef10(null);
33761
+ const interactionOriginPosRef = useRef10(null);
33762
+ const longPressTimeoutRef = useRef10(null);
33763
+ const ignoreNextContextMenuRef = useRef10(false);
33573
33764
  const clearLongPressTimeout = () => {
33574
33765
  if (longPressTimeoutRef.current !== null) {
33575
33766
  clearTimeout(longPressTimeoutRef.current);
33576
33767
  longPressTimeoutRef.current = null;
33577
33768
  }
33578
33769
  };
33579
- const handleContextMenu = useCallback8(
33770
+ const handleContextMenu = useCallback10(
33580
33771
  (e) => {
33581
33772
  e.preventDefault();
33582
33773
  const eventX = typeof e.clientX === "number" ? e.clientX : 0;
@@ -33602,7 +33793,7 @@ var useContextMenu = ({ containerRef }) => {
33602
33793
  },
33603
33794
  [setMenuPos, setMenuVisible]
33604
33795
  );
33605
- const handleTouchStart = useCallback8(
33796
+ const handleTouchStart = useCallback10(
33606
33797
  (e) => {
33607
33798
  if (e.touches.length === 1) {
33608
33799
  const touch = e.touches[0];
@@ -33635,7 +33826,7 @@ var useContextMenu = ({ containerRef }) => {
33635
33826
  },
33636
33827
  [containerRef]
33637
33828
  );
33638
- const handleTouchMove = useCallback8((e) => {
33829
+ const handleTouchMove = useCallback10((e) => {
33639
33830
  if (!interactionOriginPosRef.current || e.touches.length !== 1) {
33640
33831
  return;
33641
33832
  }
@@ -33653,7 +33844,7 @@ var useContextMenu = ({ containerRef }) => {
33653
33844
  clearLongPressTimeout();
33654
33845
  }
33655
33846
  }, []);
33656
- const handleTouchEnd = useCallback8(() => {
33847
+ const handleTouchEnd = useCallback10(() => {
33657
33848
  clearLongPressTimeout();
33658
33849
  setTimeout(() => {
33659
33850
  if (interactionOriginPosRef.current) {
@@ -33661,7 +33852,7 @@ var useContextMenu = ({ containerRef }) => {
33661
33852
  }
33662
33853
  }, 0);
33663
33854
  }, []);
33664
- const handleClickAway = useCallback8((e) => {
33855
+ const handleClickAway = useCallback10((e) => {
33665
33856
  const target = e.target;
33666
33857
  if (menuRef.current && menuRef.current.contains(target)) {
33667
33858
  return;
@@ -33674,7 +33865,7 @@ var useContextMenu = ({ containerRef }) => {
33674
33865
  }
33675
33866
  setMenuVisible(false);
33676
33867
  }, []);
33677
- useEffect23(() => {
33868
+ useEffect24(() => {
33678
33869
  if (menuVisible) {
33679
33870
  document.addEventListener("mousedown", handleClickAway);
33680
33871
  document.addEventListener("touchstart", handleClickAway);
@@ -33708,7 +33899,7 @@ var useContextMenu = ({ containerRef }) => {
33708
33899
  };
33709
33900
 
33710
33901
  // src/hooks/useCameraPreset.ts
33711
- import { useCallback as useCallback9 } from "react";
33902
+ import { useCallback as useCallback11 } from "react";
33712
33903
  function useCameraPreset({
33713
33904
  setAutoRotate,
33714
33905
  setAutoRotateUserToggled,
@@ -33718,7 +33909,7 @@ function useCameraPreset({
33718
33909
  isAnimatingRef,
33719
33910
  lastPresetSelectTime
33720
33911
  }) {
33721
- const handleCameraPresetSelect = useCallback9(
33912
+ const handleCameraPresetSelect = useCallback11(
33722
33913
  (preset) => {
33723
33914
  setAutoRotate(false);
33724
33915
  setAutoRotateUserToggled(true);
@@ -33748,10 +33939,10 @@ function useCameraPreset({
33748
33939
  }
33749
33940
 
33750
33941
  // src/hooks/useGlobalDownloadGltf.ts
33751
- import { useCallback as useCallback10 } from "react";
33942
+ import { useCallback as useCallback12 } from "react";
33752
33943
  import { GLTFExporter } from "three-stdlib";
33753
33944
  var useGlobalDownloadGltf = () => {
33754
- return useCallback10(() => {
33945
+ return useCallback12(() => {
33755
33946
  const root = window.__TSCIRCUIT_THREE_OBJECT;
33756
33947
  if (!root) return;
33757
33948
  const exporter = new GLTFExporter();
@@ -33777,7 +33968,7 @@ var useGlobalDownloadGltf = () => {
33777
33968
  };
33778
33969
 
33779
33970
  // src/components/ContextMenu.tsx
33780
- import { useState as useState32 } from "react";
33971
+ import { useState as useState33 } from "react";
33781
33972
 
33782
33973
  // node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs
33783
33974
  import * as React43 from "react";
@@ -33832,7 +34023,7 @@ function useComposedRefs(...refs) {
33832
34023
 
33833
34024
  // node_modules/@radix-ui/react-context/dist/index.mjs
33834
34025
  import * as React13 from "react";
33835
- import { jsx as jsx17 } from "react/jsx-runtime";
34026
+ import { jsx as jsx18 } from "react/jsx-runtime";
33836
34027
  function createContextScope(scopeName, createContextScopeDeps = []) {
33837
34028
  let defaultContexts = [];
33838
34029
  function createContext32(rootComponentName, defaultContext) {
@@ -33843,7 +34034,7 @@ function createContextScope(scopeName, createContextScopeDeps = []) {
33843
34034
  const { scope, children, ...context } = props;
33844
34035
  const Context = scope?.[scopeName]?.[index2] || BaseContext;
33845
34036
  const value = React13.useMemo(() => context, Object.values(context));
33846
- return /* @__PURE__ */ jsx17(Context.Provider, { value, children });
34037
+ return /* @__PURE__ */ jsx18(Context.Provider, { value, children });
33847
34038
  };
33848
34039
  Provider.displayName = rootComponentName + "Provider";
33849
34040
  function useContext22(consumerName, scope) {
@@ -33973,7 +34164,7 @@ import * as ReactDOM2 from "react-dom";
33973
34164
 
33974
34165
  // node_modules/@radix-ui/react-slot/dist/index.mjs
33975
34166
  import * as React16 from "react";
33976
- import { Fragment as Fragment23, jsx as jsx18 } from "react/jsx-runtime";
34167
+ import { Fragment as Fragment23, jsx as jsx19 } from "react/jsx-runtime";
33977
34168
  // @__NO_SIDE_EFFECTS__
33978
34169
  function createSlot(ownerName) {
33979
34170
  const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);
@@ -33991,9 +34182,9 @@ function createSlot(ownerName) {
33991
34182
  return child;
33992
34183
  }
33993
34184
  });
33994
- return /* @__PURE__ */ jsx18(SlotClone, { ...slotProps, ref: forwardedRef, children: React16.isValidElement(newElement) ? React16.cloneElement(newElement, void 0, newChildren) : null });
34185
+ return /* @__PURE__ */ jsx19(SlotClone, { ...slotProps, ref: forwardedRef, children: React16.isValidElement(newElement) ? React16.cloneElement(newElement, void 0, newChildren) : null });
33995
34186
  }
33996
- return /* @__PURE__ */ jsx18(SlotClone, { ...slotProps, ref: forwardedRef, children });
34187
+ return /* @__PURE__ */ jsx19(SlotClone, { ...slotProps, ref: forwardedRef, children });
33997
34188
  });
33998
34189
  Slot2.displayName = `${ownerName}.Slot`;
33999
34190
  return Slot2;
@@ -34058,7 +34249,7 @@ function getElementRef(element) {
34058
34249
  }
34059
34250
 
34060
34251
  // node_modules/@radix-ui/react-primitive/dist/index.mjs
34061
- import { jsx as jsx19 } from "react/jsx-runtime";
34252
+ import { jsx as jsx20 } from "react/jsx-runtime";
34062
34253
  var NODES = [
34063
34254
  "a",
34064
34255
  "button",
@@ -34086,7 +34277,7 @@ var Primitive = NODES.reduce((primitive, node) => {
34086
34277
  if (typeof window !== "undefined") {
34087
34278
  window[Symbol.for("radix-ui")] = true;
34088
34279
  }
34089
- return /* @__PURE__ */ jsx19(Comp, { ...primitiveProps, ref: forwardedRef });
34280
+ return /* @__PURE__ */ jsx20(Comp, { ...primitiveProps, ref: forwardedRef });
34090
34281
  });
34091
34282
  Node2.displayName = `Primitive.${node}`;
34092
34283
  return { ...primitive, [node]: Node2 };
@@ -34100,7 +34291,7 @@ import * as React42 from "react";
34100
34291
 
34101
34292
  // node_modules/@radix-ui/react-collection/dist/index.mjs
34102
34293
  import React18 from "react";
34103
- import { jsx as jsx20 } from "react/jsx-runtime";
34294
+ import { jsx as jsx21 } from "react/jsx-runtime";
34104
34295
  import React23 from "react";
34105
34296
  import { jsx as jsx22 } from "react/jsx-runtime";
34106
34297
  function createCollection(name) {
@@ -34114,7 +34305,7 @@ function createCollection(name) {
34114
34305
  const { scope, children } = props;
34115
34306
  const ref = React18.useRef(null);
34116
34307
  const itemMap = React18.useRef(/* @__PURE__ */ new Map()).current;
34117
- return /* @__PURE__ */ jsx20(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
34308
+ return /* @__PURE__ */ jsx21(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
34118
34309
  };
34119
34310
  CollectionProvider.displayName = PROVIDER_NAME;
34120
34311
  const COLLECTION_SLOT_NAME = name + "CollectionSlot";
@@ -34124,7 +34315,7 @@ function createCollection(name) {
34124
34315
  const { scope, children } = props;
34125
34316
  const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
34126
34317
  const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
34127
- return /* @__PURE__ */ jsx20(CollectionSlotImpl, { ref: composedRefs, children });
34318
+ return /* @__PURE__ */ jsx21(CollectionSlotImpl, { ref: composedRefs, children });
34128
34319
  }
34129
34320
  );
34130
34321
  CollectionSlot.displayName = COLLECTION_SLOT_NAME;
@@ -34141,7 +34332,7 @@ function createCollection(name) {
34141
34332
  context.itemMap.set(ref, { ref, ...itemData });
34142
34333
  return () => void context.itemMap.delete(ref);
34143
34334
  });
34144
- return /* @__PURE__ */ jsx20(CollectionItemSlotImpl, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
34335
+ return /* @__PURE__ */ jsx21(CollectionItemSlotImpl, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
34145
34336
  }
34146
34337
  );
34147
34338
  CollectionItemSlot.displayName = ITEM_SLOT_NAME;
@@ -34168,7 +34359,7 @@ function createCollection(name) {
34168
34359
 
34169
34360
  // node_modules/@radix-ui/react-direction/dist/index.mjs
34170
34361
  import * as React19 from "react";
34171
- import { jsx as jsx21 } from "react/jsx-runtime";
34362
+ import { jsx as jsx23 } from "react/jsx-runtime";
34172
34363
  var DirectionContext = React19.createContext(void 0);
34173
34364
  function useDirection(localDir) {
34174
34365
  const globalDir = React19.useContext(DirectionContext);
@@ -34204,7 +34395,7 @@ function useEscapeKeydown(onEscapeKeyDownProp, ownerDocument = globalThis?.docum
34204
34395
  }
34205
34396
 
34206
34397
  // node_modules/@radix-ui/react-dismissable-layer/dist/index.mjs
34207
- import { jsx as jsx23 } from "react/jsx-runtime";
34398
+ import { jsx as jsx24 } from "react/jsx-runtime";
34208
34399
  var DISMISSABLE_LAYER_NAME = "DismissableLayer";
34209
34400
  var CONTEXT_UPDATE = "dismissableLayer.update";
34210
34401
  var POINTER_DOWN_OUTSIDE = "dismissableLayer.pointerDownOutside";
@@ -34292,7 +34483,7 @@ var DismissableLayer = React24.forwardRef(
34292
34483
  document.addEventListener(CONTEXT_UPDATE, handleUpdate);
34293
34484
  return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate);
34294
34485
  }, []);
34295
- return /* @__PURE__ */ jsx23(
34486
+ return /* @__PURE__ */ jsx24(
34296
34487
  Primitive.div,
34297
34488
  {
34298
34489
  ...layerProps,
@@ -34326,7 +34517,7 @@ var DismissableLayerBranch = React24.forwardRef((props, forwardedRef) => {
34326
34517
  };
34327
34518
  }
34328
34519
  }, [context.branches]);
34329
- return /* @__PURE__ */ jsx23(Primitive.div, { ...props, ref: composedRefs });
34520
+ return /* @__PURE__ */ jsx24(Primitive.div, { ...props, ref: composedRefs });
34330
34521
  });
34331
34522
  DismissableLayerBranch.displayName = BRANCH_NAME;
34332
34523
  function usePointerDownOutside(onPointerDownOutside, ownerDocument = globalThis?.document) {
@@ -34438,7 +34629,7 @@ function createFocusGuard() {
34438
34629
 
34439
34630
  // node_modules/@radix-ui/react-focus-scope/dist/index.mjs
34440
34631
  import * as React26 from "react";
34441
- import { jsx as jsx24 } from "react/jsx-runtime";
34632
+ import { jsx as jsx25 } from "react/jsx-runtime";
34442
34633
  var AUTOFOCUS_ON_MOUNT = "focusScope.autoFocusOnMount";
34443
34634
  var AUTOFOCUS_ON_UNMOUNT = "focusScope.autoFocusOnUnmount";
34444
34635
  var EVENT_OPTIONS = { bubbles: false, cancelable: true };
@@ -34557,7 +34748,7 @@ var FocusScope = React26.forwardRef((props, forwardedRef) => {
34557
34748
  },
34558
34749
  [loop, trapped, focusScope.paused]
34559
34750
  );
34560
- return /* @__PURE__ */ jsx24(Primitive.div, { tabIndex: -1, ...scopeProps, ref: composedRefs, onKeyDown: handleKeyDown });
34751
+ return /* @__PURE__ */ jsx25(Primitive.div, { tabIndex: -1, ...scopeProps, ref: composedRefs, onKeyDown: handleKeyDown });
34561
34752
  });
34562
34753
  FocusScope.displayName = FOCUS_SCOPE_NAME;
34563
34754
  function focusFirst(candidates, { select = false } = {}) {
@@ -36547,11 +36738,11 @@ var arrow3 = (options, deps) => ({
36547
36738
 
36548
36739
  // node_modules/@radix-ui/react-arrow/dist/index.mjs
36549
36740
  import * as React29 from "react";
36550
- import { jsx as jsx25 } from "react/jsx-runtime";
36741
+ import { jsx as jsx26 } from "react/jsx-runtime";
36551
36742
  var NAME = "Arrow";
36552
36743
  var Arrow = React29.forwardRef((props, forwardedRef) => {
36553
36744
  const { children, width: width10 = 10, height: height10 = 5, ...arrowProps } = props;
36554
- return /* @__PURE__ */ jsx25(
36745
+ return /* @__PURE__ */ jsx26(
36555
36746
  Primitive.svg,
36556
36747
  {
36557
36748
  ...arrowProps,
@@ -36560,7 +36751,7 @@ var Arrow = React29.forwardRef((props, forwardedRef) => {
36560
36751
  height: height10,
36561
36752
  viewBox: "0 0 30 10",
36562
36753
  preserveAspectRatio: "none",
36563
- children: props.asChild ? children : /* @__PURE__ */ jsx25("polygon", { points: "0,0 30,0 15,10" })
36754
+ children: props.asChild ? children : /* @__PURE__ */ jsx26("polygon", { points: "0,0 30,0 15,10" })
36564
36755
  }
36565
36756
  );
36566
36757
  });
@@ -36605,14 +36796,14 @@ function useSize(element) {
36605
36796
  }
36606
36797
 
36607
36798
  // node_modules/@radix-ui/react-popper/dist/index.mjs
36608
- import { jsx as jsx26 } from "react/jsx-runtime";
36799
+ import { jsx as jsx27 } from "react/jsx-runtime";
36609
36800
  var POPPER_NAME = "Popper";
36610
36801
  var [createPopperContext, createPopperScope] = createContextScope(POPPER_NAME);
36611
36802
  var [PopperProvider, usePopperContext] = createPopperContext(POPPER_NAME);
36612
36803
  var Popper = (props) => {
36613
36804
  const { __scopePopper, children } = props;
36614
36805
  const [anchor, setAnchor] = React31.useState(null);
36615
- return /* @__PURE__ */ jsx26(PopperProvider, { scope: __scopePopper, anchor, onAnchorChange: setAnchor, children });
36806
+ return /* @__PURE__ */ jsx27(PopperProvider, { scope: __scopePopper, anchor, onAnchorChange: setAnchor, children });
36616
36807
  };
36617
36808
  Popper.displayName = POPPER_NAME;
36618
36809
  var ANCHOR_NAME = "PopperAnchor";
@@ -36630,7 +36821,7 @@ var PopperAnchor = React31.forwardRef(
36630
36821
  context.onAnchorChange(anchorRef.current);
36631
36822
  }
36632
36823
  });
36633
- return virtualRef ? null : /* @__PURE__ */ jsx26(Primitive.div, { ...anchorProps, ref: composedRefs });
36824
+ return virtualRef ? null : /* @__PURE__ */ jsx27(Primitive.div, { ...anchorProps, ref: composedRefs });
36634
36825
  }
36635
36826
  );
36636
36827
  PopperAnchor.displayName = ANCHOR_NAME;
@@ -36723,7 +36914,7 @@ var PopperContent = React31.forwardRef(
36723
36914
  useLayoutEffect2(() => {
36724
36915
  if (content) setContentZIndex(window.getComputedStyle(content).zIndex);
36725
36916
  }, [content]);
36726
- return /* @__PURE__ */ jsx26(
36917
+ return /* @__PURE__ */ jsx27(
36727
36918
  "div",
36728
36919
  {
36729
36920
  ref: refs.setFloating,
@@ -36747,7 +36938,7 @@ var PopperContent = React31.forwardRef(
36747
36938
  }
36748
36939
  },
36749
36940
  dir: props.dir,
36750
- children: /* @__PURE__ */ jsx26(
36941
+ children: /* @__PURE__ */ jsx27(
36751
36942
  PopperContentProvider,
36752
36943
  {
36753
36944
  scope: __scopePopper,
@@ -36756,7 +36947,7 @@ var PopperContent = React31.forwardRef(
36756
36947
  arrowX,
36757
36948
  arrowY,
36758
36949
  shouldHideArrow: cannotCenterArrow,
36759
- children: /* @__PURE__ */ jsx26(
36950
+ children: /* @__PURE__ */ jsx27(
36760
36951
  Primitive.div,
36761
36952
  {
36762
36953
  "data-side": placedSide,
@@ -36793,7 +36984,7 @@ var PopperArrow = React31.forwardRef(function PopperArrow2(props, forwardedRef)
36793
36984
  // we have to use an extra wrapper because `ResizeObserver` (used by `useSize`)
36794
36985
  // doesn't report size as we'd expect on SVG elements.
36795
36986
  // it reports their bounding box which is effectively the largest path inside the SVG.
36796
- /* @__PURE__ */ jsx26(
36987
+ /* @__PURE__ */ jsx27(
36797
36988
  "span",
36798
36989
  {
36799
36990
  ref: contentContext.onArrowChange,
@@ -36816,7 +37007,7 @@ var PopperArrow = React31.forwardRef(function PopperArrow2(props, forwardedRef)
36816
37007
  }[contentContext.placedSide],
36817
37008
  visibility: contentContext.shouldHideArrow ? "hidden" : void 0
36818
37009
  },
36819
- children: /* @__PURE__ */ jsx26(
37010
+ children: /* @__PURE__ */ jsx27(
36820
37011
  Root,
36821
37012
  {
36822
37013
  ...arrowProps,
@@ -36879,14 +37070,14 @@ var Arrow2 = PopperArrow;
36879
37070
  // node_modules/@radix-ui/react-portal/dist/index.mjs
36880
37071
  import * as React32 from "react";
36881
37072
  import ReactDOM4 from "react-dom";
36882
- import { jsx as jsx27 } from "react/jsx-runtime";
37073
+ import { jsx as jsx28 } from "react/jsx-runtime";
36883
37074
  var PORTAL_NAME = "Portal";
36884
37075
  var Portal = React32.forwardRef((props, forwardedRef) => {
36885
37076
  const { container: containerProp, ...portalProps } = props;
36886
37077
  const [mounted, setMounted] = React32.useState(false);
36887
37078
  useLayoutEffect2(() => setMounted(true), []);
36888
37079
  const container = containerProp || mounted && globalThis?.document?.body;
36889
- return container ? ReactDOM4.createPortal(/* @__PURE__ */ jsx27(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
37080
+ return container ? ReactDOM4.createPortal(/* @__PURE__ */ jsx28(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
36890
37081
  });
36891
37082
  Portal.displayName = PORTAL_NAME;
36892
37083
 
@@ -37018,7 +37209,7 @@ function getElementRef2(element) {
37018
37209
 
37019
37210
  // node_modules/@radix-ui/react-roving-focus/dist/index.mjs
37020
37211
  import * as React34 from "react";
37021
- import { jsx as jsx28 } from "react/jsx-runtime";
37212
+ import { jsx as jsx29 } from "react/jsx-runtime";
37022
37213
  var ENTRY_FOCUS = "rovingFocusGroup.onEntryFocus";
37023
37214
  var EVENT_OPTIONS2 = { bubbles: false, cancelable: true };
37024
37215
  var GROUP_NAME = "RovingFocusGroup";
@@ -37030,7 +37221,7 @@ var [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContext
37030
37221
  var [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME);
37031
37222
  var RovingFocusGroup = React34.forwardRef(
37032
37223
  (props, forwardedRef) => {
37033
- return /* @__PURE__ */ jsx28(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx28(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx28(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });
37224
+ return /* @__PURE__ */ jsx29(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx29(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx29(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });
37034
37225
  }
37035
37226
  );
37036
37227
  RovingFocusGroup.displayName = GROUP_NAME;
@@ -37068,7 +37259,7 @@ var RovingFocusGroupImpl = React34.forwardRef((props, forwardedRef) => {
37068
37259
  return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);
37069
37260
  }
37070
37261
  }, [handleEntryFocus]);
37071
- return /* @__PURE__ */ jsx28(
37262
+ return /* @__PURE__ */ jsx29(
37072
37263
  RovingFocusProvider,
37073
37264
  {
37074
37265
  scope: __scopeRovingFocusGroup,
@@ -37089,7 +37280,7 @@ var RovingFocusGroupImpl = React34.forwardRef((props, forwardedRef) => {
37089
37280
  () => setFocusableItemsCount((prevCount) => prevCount - 1),
37090
37281
  []
37091
37282
  ),
37092
- children: /* @__PURE__ */ jsx28(
37283
+ children: /* @__PURE__ */ jsx29(
37093
37284
  Primitive.div,
37094
37285
  {
37095
37286
  tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,
@@ -37147,14 +37338,14 @@ var RovingFocusGroupItem = React34.forwardRef(
37147
37338
  return () => onFocusableItemRemove();
37148
37339
  }
37149
37340
  }, [focusable, onFocusableItemAdd, onFocusableItemRemove]);
37150
- return /* @__PURE__ */ jsx28(
37341
+ return /* @__PURE__ */ jsx29(
37151
37342
  Collection.ItemSlot,
37152
37343
  {
37153
37344
  scope: __scopeRovingFocusGroup,
37154
37345
  id,
37155
37346
  focusable,
37156
37347
  active,
37157
- children: /* @__PURE__ */ jsx28(
37348
+ children: /* @__PURE__ */ jsx29(
37158
37349
  Primitive.span,
37159
37350
  {
37160
37351
  tabIndex: isCurrentTabStop ? 0 : -1,
@@ -37405,9 +37596,9 @@ function assignRef(ref, value) {
37405
37596
  }
37406
37597
 
37407
37598
  // node_modules/use-callback-ref/dist/es2015/useRef.js
37408
- import { useState as useState27 } from "react";
37599
+ import { useState as useState28 } from "react";
37409
37600
  function useCallbackRef2(initialValue, callback) {
37410
- var ref = useState27(function() {
37601
+ var ref = useState28(function() {
37411
37602
  return {
37412
37603
  // value
37413
37604
  value: initialValue,
@@ -38065,7 +38256,7 @@ ReactRemoveScroll.classNames = RemoveScroll.classNames;
38065
38256
  var Combination_default = ReactRemoveScroll;
38066
38257
 
38067
38258
  // node_modules/@radix-ui/react-menu/dist/index.mjs
38068
- import { jsx as jsx29 } from "react/jsx-runtime";
38259
+ import { jsx as jsx30 } from "react/jsx-runtime";
38069
38260
  var SELECTION_KEYS = ["Enter", " "];
38070
38261
  var FIRST_KEYS = ["ArrowDown", "PageUp", "Home"];
38071
38262
  var LAST_KEYS = ["ArrowUp", "PageDown", "End"];
@@ -38110,7 +38301,7 @@ var Menu = (props) => {
38110
38301
  document.removeEventListener("pointermove", handlePointer, { capture: true });
38111
38302
  };
38112
38303
  }, []);
38113
- return /* @__PURE__ */ jsx29(Root2, { ...popperScope, children: /* @__PURE__ */ jsx29(
38304
+ return /* @__PURE__ */ jsx30(Root2, { ...popperScope, children: /* @__PURE__ */ jsx30(
38114
38305
  MenuProvider,
38115
38306
  {
38116
38307
  scope: __scopeMenu,
@@ -38118,7 +38309,7 @@ var Menu = (props) => {
38118
38309
  onOpenChange: handleOpenChange,
38119
38310
  content,
38120
38311
  onContentChange: setContent,
38121
- children: /* @__PURE__ */ jsx29(
38312
+ children: /* @__PURE__ */ jsx30(
38122
38313
  MenuRootProvider,
38123
38314
  {
38124
38315
  scope: __scopeMenu,
@@ -38138,7 +38329,7 @@ var MenuAnchor = React42.forwardRef(
38138
38329
  (props, forwardedRef) => {
38139
38330
  const { __scopeMenu, ...anchorProps } = props;
38140
38331
  const popperScope = usePopperScope(__scopeMenu);
38141
- return /* @__PURE__ */ jsx29(Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });
38332
+ return /* @__PURE__ */ jsx30(Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });
38142
38333
  }
38143
38334
  );
38144
38335
  MenuAnchor.displayName = ANCHOR_NAME2;
@@ -38149,7 +38340,7 @@ var [PortalProvider, usePortalContext] = createMenuContext(PORTAL_NAME2, {
38149
38340
  var MenuPortal = (props) => {
38150
38341
  const { __scopeMenu, forceMount, children, container } = props;
38151
38342
  const context = useMenuContext(PORTAL_NAME2, __scopeMenu);
38152
- return /* @__PURE__ */ jsx29(PortalProvider, { scope: __scopeMenu, forceMount, children: /* @__PURE__ */ jsx29(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx29(Portal, { asChild: true, container, children }) }) });
38343
+ return /* @__PURE__ */ jsx30(PortalProvider, { scope: __scopeMenu, forceMount, children: /* @__PURE__ */ jsx30(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx30(Portal, { asChild: true, container, children }) }) });
38153
38344
  };
38154
38345
  MenuPortal.displayName = PORTAL_NAME2;
38155
38346
  var CONTENT_NAME2 = "MenuContent";
@@ -38160,7 +38351,7 @@ var MenuContent = React42.forwardRef(
38160
38351
  const { forceMount = portalContext.forceMount, ...contentProps } = props;
38161
38352
  const context = useMenuContext(CONTENT_NAME2, props.__scopeMenu);
38162
38353
  const rootContext = useMenuRootContext(CONTENT_NAME2, props.__scopeMenu);
38163
- return /* @__PURE__ */ jsx29(Collection2.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx29(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx29(Collection2.Slot, { scope: props.__scopeMenu, children: rootContext.modal ? /* @__PURE__ */ jsx29(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx29(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) }) });
38354
+ return /* @__PURE__ */ jsx30(Collection2.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx30(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx30(Collection2.Slot, { scope: props.__scopeMenu, children: rootContext.modal ? /* @__PURE__ */ jsx30(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx30(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) }) });
38164
38355
  }
38165
38356
  );
38166
38357
  var MenuRootContentModal = React42.forwardRef(
@@ -38172,7 +38363,7 @@ var MenuRootContentModal = React42.forwardRef(
38172
38363
  const content = ref.current;
38173
38364
  if (content) return hideOthers(content);
38174
38365
  }, []);
38175
- return /* @__PURE__ */ jsx29(
38366
+ return /* @__PURE__ */ jsx30(
38176
38367
  MenuContentImpl,
38177
38368
  {
38178
38369
  ...props,
@@ -38192,7 +38383,7 @@ var MenuRootContentModal = React42.forwardRef(
38192
38383
  );
38193
38384
  var MenuRootContentNonModal = React42.forwardRef((props, forwardedRef) => {
38194
38385
  const context = useMenuContext(CONTENT_NAME2, props.__scopeMenu);
38195
- return /* @__PURE__ */ jsx29(
38386
+ return /* @__PURE__ */ jsx30(
38196
38387
  MenuContentImpl,
38197
38388
  {
38198
38389
  ...props,
@@ -38264,7 +38455,7 @@ var MenuContentImpl = React42.forwardRef(
38264
38455
  const isMovingTowards = pointerDirRef.current === pointerGraceIntentRef.current?.side;
38265
38456
  return isMovingTowards && isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
38266
38457
  }, []);
38267
- return /* @__PURE__ */ jsx29(
38458
+ return /* @__PURE__ */ jsx30(
38268
38459
  MenuContentProvider,
38269
38460
  {
38270
38461
  scope: __scopeMenu,
@@ -38293,7 +38484,7 @@ var MenuContentImpl = React42.forwardRef(
38293
38484
  onPointerGraceIntentChange: React42.useCallback((intent) => {
38294
38485
  pointerGraceIntentRef.current = intent;
38295
38486
  }, []),
38296
- children: /* @__PURE__ */ jsx29(ScrollLockWrapper, { ...scrollLockWrapperProps, children: /* @__PURE__ */ jsx29(
38487
+ children: /* @__PURE__ */ jsx30(ScrollLockWrapper, { ...scrollLockWrapperProps, children: /* @__PURE__ */ jsx30(
38297
38488
  FocusScope,
38298
38489
  {
38299
38490
  asChild: true,
@@ -38303,7 +38494,7 @@ var MenuContentImpl = React42.forwardRef(
38303
38494
  contentRef.current?.focus({ preventScroll: true });
38304
38495
  }),
38305
38496
  onUnmountAutoFocus: onCloseAutoFocus,
38306
- children: /* @__PURE__ */ jsx29(
38497
+ children: /* @__PURE__ */ jsx30(
38307
38498
  DismissableLayer,
38308
38499
  {
38309
38500
  asChild: true,
@@ -38313,7 +38504,7 @@ var MenuContentImpl = React42.forwardRef(
38313
38504
  onFocusOutside,
38314
38505
  onInteractOutside,
38315
38506
  onDismiss,
38316
- children: /* @__PURE__ */ jsx29(
38507
+ children: /* @__PURE__ */ jsx30(
38317
38508
  Root3,
38318
38509
  {
38319
38510
  asChild: true,
@@ -38327,7 +38518,7 @@ var MenuContentImpl = React42.forwardRef(
38327
38518
  if (!rootContext.isUsingKeyboardRef.current) event.preventDefault();
38328
38519
  }),
38329
38520
  preventScrollOnEntryFocus: true,
38330
- children: /* @__PURE__ */ jsx29(
38521
+ children: /* @__PURE__ */ jsx30(
38331
38522
  Content,
38332
38523
  {
38333
38524
  role: "menu",
@@ -38392,7 +38583,7 @@ var GROUP_NAME2 = "MenuGroup";
38392
38583
  var MenuGroup = React42.forwardRef(
38393
38584
  (props, forwardedRef) => {
38394
38585
  const { __scopeMenu, ...groupProps } = props;
38395
- return /* @__PURE__ */ jsx29(Primitive.div, { role: "group", ...groupProps, ref: forwardedRef });
38586
+ return /* @__PURE__ */ jsx30(Primitive.div, { role: "group", ...groupProps, ref: forwardedRef });
38396
38587
  }
38397
38588
  );
38398
38589
  MenuGroup.displayName = GROUP_NAME2;
@@ -38400,7 +38591,7 @@ var LABEL_NAME = "MenuLabel";
38400
38591
  var MenuLabel = React42.forwardRef(
38401
38592
  (props, forwardedRef) => {
38402
38593
  const { __scopeMenu, ...labelProps } = props;
38403
- return /* @__PURE__ */ jsx29(Primitive.div, { ...labelProps, ref: forwardedRef });
38594
+ return /* @__PURE__ */ jsx30(Primitive.div, { ...labelProps, ref: forwardedRef });
38404
38595
  }
38405
38596
  );
38406
38597
  MenuLabel.displayName = LABEL_NAME;
@@ -38427,7 +38618,7 @@ var MenuItem = React42.forwardRef(
38427
38618
  }
38428
38619
  }
38429
38620
  };
38430
- return /* @__PURE__ */ jsx29(
38621
+ return /* @__PURE__ */ jsx30(
38431
38622
  MenuItemImpl,
38432
38623
  {
38433
38624
  ...itemProps,
@@ -38469,13 +38660,13 @@ var MenuItemImpl = React42.forwardRef(
38469
38660
  setTextContent((menuItem.textContent ?? "").trim());
38470
38661
  }
38471
38662
  }, [itemProps.children]);
38472
- return /* @__PURE__ */ jsx29(
38663
+ return /* @__PURE__ */ jsx30(
38473
38664
  Collection2.ItemSlot,
38474
38665
  {
38475
38666
  scope: __scopeMenu,
38476
38667
  disabled,
38477
38668
  textValue: textValue ?? textContent,
38478
- children: /* @__PURE__ */ jsx29(Item, { asChild: true, ...rovingFocusGroupScope, focusable: !disabled, children: /* @__PURE__ */ jsx29(
38669
+ children: /* @__PURE__ */ jsx30(Item, { asChild: true, ...rovingFocusGroupScope, focusable: !disabled, children: /* @__PURE__ */ jsx30(
38479
38670
  Primitive.div,
38480
38671
  {
38481
38672
  role: "menuitem",
@@ -38514,7 +38705,7 @@ var CHECKBOX_ITEM_NAME = "MenuCheckboxItem";
38514
38705
  var MenuCheckboxItem = React42.forwardRef(
38515
38706
  (props, forwardedRef) => {
38516
38707
  const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
38517
- return /* @__PURE__ */ jsx29(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx29(
38708
+ return /* @__PURE__ */ jsx30(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx30(
38518
38709
  MenuItem,
38519
38710
  {
38520
38711
  role: "menuitemcheckbox",
@@ -38542,7 +38733,7 @@ var MenuRadioGroup = React42.forwardRef(
38542
38733
  (props, forwardedRef) => {
38543
38734
  const { value, onValueChange, ...groupProps } = props;
38544
38735
  const handleValueChange = useCallbackRef(onValueChange);
38545
- return /* @__PURE__ */ jsx29(RadioGroupProvider, { scope: props.__scopeMenu, value, onValueChange: handleValueChange, children: /* @__PURE__ */ jsx29(MenuGroup, { ...groupProps, ref: forwardedRef }) });
38736
+ return /* @__PURE__ */ jsx30(RadioGroupProvider, { scope: props.__scopeMenu, value, onValueChange: handleValueChange, children: /* @__PURE__ */ jsx30(MenuGroup, { ...groupProps, ref: forwardedRef }) });
38546
38737
  }
38547
38738
  );
38548
38739
  MenuRadioGroup.displayName = RADIO_GROUP_NAME;
@@ -38552,7 +38743,7 @@ var MenuRadioItem = React42.forwardRef(
38552
38743
  const { value, ...radioItemProps } = props;
38553
38744
  const context = useRadioGroupContext(RADIO_ITEM_NAME, props.__scopeMenu);
38554
38745
  const checked = value === context.value;
38555
- return /* @__PURE__ */ jsx29(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx29(
38746
+ return /* @__PURE__ */ jsx30(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx30(
38556
38747
  MenuItem,
38557
38748
  {
38558
38749
  role: "menuitemradio",
@@ -38579,11 +38770,11 @@ var MenuItemIndicator = React42.forwardRef(
38579
38770
  (props, forwardedRef) => {
38580
38771
  const { __scopeMenu, forceMount, ...itemIndicatorProps } = props;
38581
38772
  const indicatorContext = useItemIndicatorContext(ITEM_INDICATOR_NAME, __scopeMenu);
38582
- return /* @__PURE__ */ jsx29(
38773
+ return /* @__PURE__ */ jsx30(
38583
38774
  Presence,
38584
38775
  {
38585
38776
  present: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === true,
38586
- children: /* @__PURE__ */ jsx29(
38777
+ children: /* @__PURE__ */ jsx30(
38587
38778
  Primitive.span,
38588
38779
  {
38589
38780
  ...itemIndicatorProps,
@@ -38600,7 +38791,7 @@ var SEPARATOR_NAME = "MenuSeparator";
38600
38791
  var MenuSeparator = React42.forwardRef(
38601
38792
  (props, forwardedRef) => {
38602
38793
  const { __scopeMenu, ...separatorProps } = props;
38603
- return /* @__PURE__ */ jsx29(
38794
+ return /* @__PURE__ */ jsx30(
38604
38795
  Primitive.div,
38605
38796
  {
38606
38797
  role: "separator",
@@ -38617,7 +38808,7 @@ var MenuArrow = React42.forwardRef(
38617
38808
  (props, forwardedRef) => {
38618
38809
  const { __scopeMenu, ...arrowProps } = props;
38619
38810
  const popperScope = usePopperScope(__scopeMenu);
38620
- return /* @__PURE__ */ jsx29(Arrow2, { ...popperScope, ...arrowProps, ref: forwardedRef });
38811
+ return /* @__PURE__ */ jsx30(Arrow2, { ...popperScope, ...arrowProps, ref: forwardedRef });
38621
38812
  }
38622
38813
  );
38623
38814
  MenuArrow.displayName = ARROW_NAME2;
@@ -38634,7 +38825,7 @@ var MenuSub = (props) => {
38634
38825
  if (parentMenuContext.open === false) handleOpenChange(false);
38635
38826
  return () => handleOpenChange(false);
38636
38827
  }, [parentMenuContext.open, handleOpenChange]);
38637
- return /* @__PURE__ */ jsx29(Root2, { ...popperScope, children: /* @__PURE__ */ jsx29(
38828
+ return /* @__PURE__ */ jsx30(Root2, { ...popperScope, children: /* @__PURE__ */ jsx30(
38638
38829
  MenuProvider,
38639
38830
  {
38640
38831
  scope: __scopeMenu,
@@ -38642,7 +38833,7 @@ var MenuSub = (props) => {
38642
38833
  onOpenChange: handleOpenChange,
38643
38834
  content,
38644
38835
  onContentChange: setContent,
38645
- children: /* @__PURE__ */ jsx29(
38836
+ children: /* @__PURE__ */ jsx30(
38646
38837
  MenuSubProvider,
38647
38838
  {
38648
38839
  scope: __scopeMenu,
@@ -38679,7 +38870,7 @@ var MenuSubTrigger = React42.forwardRef(
38679
38870
  onPointerGraceIntentChange(null);
38680
38871
  };
38681
38872
  }, [pointerGraceTimerRef, onPointerGraceIntentChange]);
38682
- return /* @__PURE__ */ jsx29(MenuAnchor, { asChild: true, ...scope, children: /* @__PURE__ */ jsx29(
38873
+ return /* @__PURE__ */ jsx30(MenuAnchor, { asChild: true, ...scope, children: /* @__PURE__ */ jsx30(
38683
38874
  MenuItemImpl,
38684
38875
  {
38685
38876
  id: subContext.triggerId,
@@ -38768,7 +38959,7 @@ var MenuSubContent = React42.forwardRef(
38768
38959
  const subContext = useMenuSubContext(SUB_CONTENT_NAME, props.__scopeMenu);
38769
38960
  const ref = React42.useRef(null);
38770
38961
  const composedRefs = useComposedRefs(forwardedRef, ref);
38771
- return /* @__PURE__ */ jsx29(Collection2.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx29(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx29(Collection2.Slot, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx29(
38962
+ return /* @__PURE__ */ jsx30(Collection2.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx30(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx30(Collection2.Slot, { scope: props.__scopeMenu, children: /* @__PURE__ */ jsx30(
38772
38963
  MenuContentImpl,
38773
38964
  {
38774
38965
  id: subContext.contentId,
@@ -38879,7 +39070,7 @@ var SubTrigger = MenuSubTrigger;
38879
39070
  var SubContent = MenuSubContent;
38880
39071
 
38881
39072
  // node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs
38882
- import { jsx as jsx30 } from "react/jsx-runtime";
39073
+ import { jsx as jsx31 } from "react/jsx-runtime";
38883
39074
  var DROPDOWN_MENU_NAME = "DropdownMenu";
38884
39075
  var [createDropdownMenuContext, createDropdownMenuScope] = createContextScope(
38885
39076
  DROPDOWN_MENU_NAME,
@@ -38905,7 +39096,7 @@ var DropdownMenu = (props) => {
38905
39096
  onChange: onOpenChange,
38906
39097
  caller: DROPDOWN_MENU_NAME
38907
39098
  });
38908
- return /* @__PURE__ */ jsx30(
39099
+ return /* @__PURE__ */ jsx31(
38909
39100
  DropdownMenuProvider,
38910
39101
  {
38911
39102
  scope: __scopeDropdownMenu,
@@ -38916,7 +39107,7 @@ var DropdownMenu = (props) => {
38916
39107
  onOpenChange: setOpen,
38917
39108
  onOpenToggle: React43.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
38918
39109
  modal,
38919
- children: /* @__PURE__ */ jsx30(Root32, { ...menuScope, open, onOpenChange: setOpen, dir, modal, children })
39110
+ children: /* @__PURE__ */ jsx31(Root32, { ...menuScope, open, onOpenChange: setOpen, dir, modal, children })
38920
39111
  }
38921
39112
  );
38922
39113
  };
@@ -38927,7 +39118,7 @@ var DropdownMenuTrigger = React43.forwardRef(
38927
39118
  const { __scopeDropdownMenu, disabled = false, ...triggerProps } = props;
38928
39119
  const context = useDropdownMenuContext(TRIGGER_NAME, __scopeDropdownMenu);
38929
39120
  const menuScope = useMenuScope(__scopeDropdownMenu);
38930
- return /* @__PURE__ */ jsx30(Anchor2, { asChild: true, ...menuScope, children: /* @__PURE__ */ jsx30(
39121
+ return /* @__PURE__ */ jsx31(Anchor2, { asChild: true, ...menuScope, children: /* @__PURE__ */ jsx31(
38931
39122
  Primitive.button,
38932
39123
  {
38933
39124
  type: "button",
@@ -38961,7 +39152,7 @@ var PORTAL_NAME3 = "DropdownMenuPortal";
38961
39152
  var DropdownMenuPortal = (props) => {
38962
39153
  const { __scopeDropdownMenu, ...portalProps } = props;
38963
39154
  const menuScope = useMenuScope(__scopeDropdownMenu);
38964
- return /* @__PURE__ */ jsx30(Portal2, { ...menuScope, ...portalProps });
39155
+ return /* @__PURE__ */ jsx31(Portal2, { ...menuScope, ...portalProps });
38965
39156
  };
38966
39157
  DropdownMenuPortal.displayName = PORTAL_NAME3;
38967
39158
  var CONTENT_NAME3 = "DropdownMenuContent";
@@ -38971,7 +39162,7 @@ var DropdownMenuContent = React43.forwardRef(
38971
39162
  const context = useDropdownMenuContext(CONTENT_NAME3, __scopeDropdownMenu);
38972
39163
  const menuScope = useMenuScope(__scopeDropdownMenu);
38973
39164
  const hasInteractedOutsideRef = React43.useRef(false);
38974
- return /* @__PURE__ */ jsx30(
39165
+ return /* @__PURE__ */ jsx31(
38975
39166
  Content2,
38976
39167
  {
38977
39168
  id: context.contentId,
@@ -39011,7 +39202,7 @@ var DropdownMenuGroup = React43.forwardRef(
39011
39202
  (props, forwardedRef) => {
39012
39203
  const { __scopeDropdownMenu, ...groupProps } = props;
39013
39204
  const menuScope = useMenuScope(__scopeDropdownMenu);
39014
- return /* @__PURE__ */ jsx30(Group4, { ...menuScope, ...groupProps, ref: forwardedRef });
39205
+ return /* @__PURE__ */ jsx31(Group4, { ...menuScope, ...groupProps, ref: forwardedRef });
39015
39206
  }
39016
39207
  );
39017
39208
  DropdownMenuGroup.displayName = GROUP_NAME3;
@@ -39020,7 +39211,7 @@ var DropdownMenuLabel = React43.forwardRef(
39020
39211
  (props, forwardedRef) => {
39021
39212
  const { __scopeDropdownMenu, ...labelProps } = props;
39022
39213
  const menuScope = useMenuScope(__scopeDropdownMenu);
39023
- return /* @__PURE__ */ jsx30(Label, { ...menuScope, ...labelProps, ref: forwardedRef });
39214
+ return /* @__PURE__ */ jsx31(Label, { ...menuScope, ...labelProps, ref: forwardedRef });
39024
39215
  }
39025
39216
  );
39026
39217
  DropdownMenuLabel.displayName = LABEL_NAME2;
@@ -39029,7 +39220,7 @@ var DropdownMenuItem = React43.forwardRef(
39029
39220
  (props, forwardedRef) => {
39030
39221
  const { __scopeDropdownMenu, ...itemProps } = props;
39031
39222
  const menuScope = useMenuScope(__scopeDropdownMenu);
39032
- return /* @__PURE__ */ jsx30(Item2, { ...menuScope, ...itemProps, ref: forwardedRef });
39223
+ return /* @__PURE__ */ jsx31(Item2, { ...menuScope, ...itemProps, ref: forwardedRef });
39033
39224
  }
39034
39225
  );
39035
39226
  DropdownMenuItem.displayName = ITEM_NAME3;
@@ -39037,35 +39228,35 @@ var CHECKBOX_ITEM_NAME2 = "DropdownMenuCheckboxItem";
39037
39228
  var DropdownMenuCheckboxItem = React43.forwardRef((props, forwardedRef) => {
39038
39229
  const { __scopeDropdownMenu, ...checkboxItemProps } = props;
39039
39230
  const menuScope = useMenuScope(__scopeDropdownMenu);
39040
- return /* @__PURE__ */ jsx30(CheckboxItem, { ...menuScope, ...checkboxItemProps, ref: forwardedRef });
39231
+ return /* @__PURE__ */ jsx31(CheckboxItem, { ...menuScope, ...checkboxItemProps, ref: forwardedRef });
39041
39232
  });
39042
39233
  DropdownMenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME2;
39043
39234
  var RADIO_GROUP_NAME2 = "DropdownMenuRadioGroup";
39044
39235
  var DropdownMenuRadioGroup = React43.forwardRef((props, forwardedRef) => {
39045
39236
  const { __scopeDropdownMenu, ...radioGroupProps } = props;
39046
39237
  const menuScope = useMenuScope(__scopeDropdownMenu);
39047
- return /* @__PURE__ */ jsx30(RadioGroup, { ...menuScope, ...radioGroupProps, ref: forwardedRef });
39238
+ return /* @__PURE__ */ jsx31(RadioGroup, { ...menuScope, ...radioGroupProps, ref: forwardedRef });
39048
39239
  });
39049
39240
  DropdownMenuRadioGroup.displayName = RADIO_GROUP_NAME2;
39050
39241
  var RADIO_ITEM_NAME2 = "DropdownMenuRadioItem";
39051
39242
  var DropdownMenuRadioItem = React43.forwardRef((props, forwardedRef) => {
39052
39243
  const { __scopeDropdownMenu, ...radioItemProps } = props;
39053
39244
  const menuScope = useMenuScope(__scopeDropdownMenu);
39054
- return /* @__PURE__ */ jsx30(RadioItem, { ...menuScope, ...radioItemProps, ref: forwardedRef });
39245
+ return /* @__PURE__ */ jsx31(RadioItem, { ...menuScope, ...radioItemProps, ref: forwardedRef });
39055
39246
  });
39056
39247
  DropdownMenuRadioItem.displayName = RADIO_ITEM_NAME2;
39057
39248
  var INDICATOR_NAME = "DropdownMenuItemIndicator";
39058
39249
  var DropdownMenuItemIndicator = React43.forwardRef((props, forwardedRef) => {
39059
39250
  const { __scopeDropdownMenu, ...itemIndicatorProps } = props;
39060
39251
  const menuScope = useMenuScope(__scopeDropdownMenu);
39061
- return /* @__PURE__ */ jsx30(ItemIndicator, { ...menuScope, ...itemIndicatorProps, ref: forwardedRef });
39252
+ return /* @__PURE__ */ jsx31(ItemIndicator, { ...menuScope, ...itemIndicatorProps, ref: forwardedRef });
39062
39253
  });
39063
39254
  DropdownMenuItemIndicator.displayName = INDICATOR_NAME;
39064
39255
  var SEPARATOR_NAME2 = "DropdownMenuSeparator";
39065
39256
  var DropdownMenuSeparator = React43.forwardRef((props, forwardedRef) => {
39066
39257
  const { __scopeDropdownMenu, ...separatorProps } = props;
39067
39258
  const menuScope = useMenuScope(__scopeDropdownMenu);
39068
- return /* @__PURE__ */ jsx30(Separator, { ...menuScope, ...separatorProps, ref: forwardedRef });
39259
+ return /* @__PURE__ */ jsx31(Separator, { ...menuScope, ...separatorProps, ref: forwardedRef });
39069
39260
  });
39070
39261
  DropdownMenuSeparator.displayName = SEPARATOR_NAME2;
39071
39262
  var ARROW_NAME3 = "DropdownMenuArrow";
@@ -39073,7 +39264,7 @@ var DropdownMenuArrow = React43.forwardRef(
39073
39264
  (props, forwardedRef) => {
39074
39265
  const { __scopeDropdownMenu, ...arrowProps } = props;
39075
39266
  const menuScope = useMenuScope(__scopeDropdownMenu);
39076
- return /* @__PURE__ */ jsx30(Arrow22, { ...menuScope, ...arrowProps, ref: forwardedRef });
39267
+ return /* @__PURE__ */ jsx31(Arrow22, { ...menuScope, ...arrowProps, ref: forwardedRef });
39077
39268
  }
39078
39269
  );
39079
39270
  DropdownMenuArrow.displayName = ARROW_NAME3;
@@ -39086,20 +39277,20 @@ var DropdownMenuSub = (props) => {
39086
39277
  onChange: onOpenChange,
39087
39278
  caller: "DropdownMenuSub"
39088
39279
  });
39089
- return /* @__PURE__ */ jsx30(Sub, { ...menuScope, open, onOpenChange: setOpen, children });
39280
+ return /* @__PURE__ */ jsx31(Sub, { ...menuScope, open, onOpenChange: setOpen, children });
39090
39281
  };
39091
39282
  var SUB_TRIGGER_NAME2 = "DropdownMenuSubTrigger";
39092
39283
  var DropdownMenuSubTrigger = React43.forwardRef((props, forwardedRef) => {
39093
39284
  const { __scopeDropdownMenu, ...subTriggerProps } = props;
39094
39285
  const menuScope = useMenuScope(__scopeDropdownMenu);
39095
- return /* @__PURE__ */ jsx30(SubTrigger, { ...menuScope, ...subTriggerProps, ref: forwardedRef });
39286
+ return /* @__PURE__ */ jsx31(SubTrigger, { ...menuScope, ...subTriggerProps, ref: forwardedRef });
39096
39287
  });
39097
39288
  DropdownMenuSubTrigger.displayName = SUB_TRIGGER_NAME2;
39098
39289
  var SUB_CONTENT_NAME2 = "DropdownMenuSubContent";
39099
39290
  var DropdownMenuSubContent = React43.forwardRef((props, forwardedRef) => {
39100
39291
  const { __scopeDropdownMenu, ...subContentProps } = props;
39101
39292
  const menuScope = useMenuScope(__scopeDropdownMenu);
39102
- return /* @__PURE__ */ jsx30(
39293
+ return /* @__PURE__ */ jsx31(
39103
39294
  SubContent,
39104
39295
  {
39105
39296
  ...menuScope,
@@ -39131,11 +39322,11 @@ var SubTrigger2 = DropdownMenuSubTrigger;
39131
39322
  var SubContent2 = DropdownMenuSubContent;
39132
39323
 
39133
39324
  // src/components/AppearanceMenu.tsx
39134
- import { useState as useState31 } from "react";
39325
+ import { useState as useState32 } from "react";
39135
39326
 
39136
39327
  // src/components/Icons.tsx
39137
- import { jsx as jsx31 } from "react/jsx-runtime";
39138
- var CheckIcon = () => /* @__PURE__ */ jsx31(
39328
+ import { jsx as jsx32 } from "react/jsx-runtime";
39329
+ var CheckIcon = () => /* @__PURE__ */ jsx32(
39139
39330
  "svg",
39140
39331
  {
39141
39332
  xmlns: "http://www.w3.org/2000/svg",
@@ -39147,10 +39338,10 @@ var CheckIcon = () => /* @__PURE__ */ jsx31(
39147
39338
  strokeWidth: "2",
39148
39339
  strokeLinecap: "round",
39149
39340
  strokeLinejoin: "round",
39150
- children: /* @__PURE__ */ jsx31("path", { d: "M20 6 9 17l-5-5" })
39341
+ children: /* @__PURE__ */ jsx32("path", { d: "M20 6 9 17l-5-5" })
39151
39342
  }
39152
39343
  );
39153
- var ChevronRightIcon = ({ isOpen }) => /* @__PURE__ */ jsx31(
39344
+ var ChevronRightIcon = ({ isOpen }) => /* @__PURE__ */ jsx32(
39154
39345
  "svg",
39155
39346
  {
39156
39347
  xmlns: "http://www.w3.org/2000/svg",
@@ -39167,10 +39358,10 @@ var ChevronRightIcon = ({ isOpen }) => /* @__PURE__ */ jsx31(
39167
39358
  transform: isOpen ? "rotate(90deg)" : "rotate(0deg)",
39168
39359
  opacity: 0.6
39169
39360
  },
39170
- children: /* @__PURE__ */ jsx31("path", { d: "m9 18 6-6-6-6" })
39361
+ children: /* @__PURE__ */ jsx32("path", { d: "m9 18 6-6-6-6" })
39171
39362
  }
39172
39363
  );
39173
- var DotIcon = () => /* @__PURE__ */ jsx31(
39364
+ var DotIcon = () => /* @__PURE__ */ jsx32(
39174
39365
  "svg",
39175
39366
  {
39176
39367
  xmlns: "http://www.w3.org/2000/svg",
@@ -39183,12 +39374,12 @@ var DotIcon = () => /* @__PURE__ */ jsx31(
39183
39374
  strokeLinecap: "round",
39184
39375
  strokeLinejoin: "round",
39185
39376
  className: "lucide lucide-dot-icon lucide-dot",
39186
- children: /* @__PURE__ */ jsx31("circle", { cx: "12.1", cy: "12.1", r: "4.5", fill: "white" })
39377
+ children: /* @__PURE__ */ jsx32("circle", { cx: "12.1", cy: "12.1", r: "4.5", fill: "white" })
39187
39378
  }
39188
39379
  );
39189
39380
 
39190
39381
  // src/components/AppearanceMenu.tsx
39191
- import { Fragment as Fragment10, jsx as jsx32, jsxs as jsxs8 } from "react/jsx-runtime";
39382
+ import { Fragment as Fragment9, jsx as jsx33, jsxs as jsxs7 } from "react/jsx-runtime";
39192
39383
  var itemStyles = {
39193
39384
  padding: "6px 8px",
39194
39385
  borderRadius: 6,
@@ -39237,12 +39428,12 @@ var iconContainerStyles = {
39237
39428
  };
39238
39429
  var AppearanceMenu = () => {
39239
39430
  const { visibility, toggleLayer } = useLayerVisibility();
39240
- const [appearanceSubOpen, setAppearanceSubOpen] = useState31(false);
39241
- const [hoveredItem, setHoveredItem] = useState31(null);
39242
- return /* @__PURE__ */ jsxs8(Fragment10, { children: [
39243
- /* @__PURE__ */ jsx32(Separator2, { style: separatorStyles }),
39244
- /* @__PURE__ */ jsxs8(Sub2, { onOpenChange: setAppearanceSubOpen, children: [
39245
- /* @__PURE__ */ jsxs8(
39431
+ const [appearanceSubOpen, setAppearanceSubOpen] = useState32(false);
39432
+ const [hoveredItem, setHoveredItem] = useState32(null);
39433
+ return /* @__PURE__ */ jsxs7(Fragment9, { children: [
39434
+ /* @__PURE__ */ jsx33(Separator2, { style: separatorStyles }),
39435
+ /* @__PURE__ */ jsxs7(Sub2, { onOpenChange: setAppearanceSubOpen, children: [
39436
+ /* @__PURE__ */ jsxs7(
39246
39437
  SubTrigger2,
39247
39438
  {
39248
39439
  style: {
@@ -39254,8 +39445,8 @@ var AppearanceMenu = () => {
39254
39445
  onMouseLeave: () => setHoveredItem(null),
39255
39446
  onTouchStart: () => setHoveredItem("appearance"),
39256
39447
  children: [
39257
- /* @__PURE__ */ jsx32("span", { style: { flex: 1, display: "flex", alignItems: "center" }, children: "Appearance" }),
39258
- /* @__PURE__ */ jsx32(
39448
+ /* @__PURE__ */ jsx33("span", { style: { flex: 1, display: "flex", alignItems: "center" }, children: "Appearance" }),
39449
+ /* @__PURE__ */ jsx33(
39259
39450
  "div",
39260
39451
  {
39261
39452
  style: {
@@ -39264,20 +39455,20 @@ var AppearanceMenu = () => {
39264
39455
  alignItems: "flex-end",
39265
39456
  marginBottom: "-5px"
39266
39457
  },
39267
- children: /* @__PURE__ */ jsx32(ChevronRightIcon, { isOpen: appearanceSubOpen })
39458
+ children: /* @__PURE__ */ jsx33(ChevronRightIcon, { isOpen: appearanceSubOpen })
39268
39459
  }
39269
39460
  )
39270
39461
  ]
39271
39462
  }
39272
39463
  ),
39273
- /* @__PURE__ */ jsx32(Portal22, { children: /* @__PURE__ */ jsxs8(
39464
+ /* @__PURE__ */ jsx33(Portal22, { children: /* @__PURE__ */ jsxs7(
39274
39465
  SubContent2,
39275
39466
  {
39276
39467
  style: { ...contentStyles, marginLeft: -2 },
39277
39468
  collisionPadding: 10,
39278
39469
  avoidCollisions: true,
39279
39470
  children: [
39280
- /* @__PURE__ */ jsxs8(
39471
+ /* @__PURE__ */ jsxs7(
39281
39472
  Item22,
39282
39473
  {
39283
39474
  style: {
@@ -39293,12 +39484,12 @@ var AppearanceMenu = () => {
39293
39484
  onMouseLeave: () => setHoveredItem(null),
39294
39485
  onTouchStart: () => setHoveredItem("boardBody"),
39295
39486
  children: [
39296
- /* @__PURE__ */ jsx32("span", { style: iconContainerStyles, children: visibility.boardBody && /* @__PURE__ */ jsx32(CheckIcon, {}) }),
39297
- /* @__PURE__ */ jsx32("span", { style: { display: "flex", alignItems: "center" }, children: "Board Body" })
39487
+ /* @__PURE__ */ jsx33("span", { style: iconContainerStyles, children: visibility.boardBody && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39488
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Board Body" })
39298
39489
  ]
39299
39490
  }
39300
39491
  ),
39301
- /* @__PURE__ */ jsxs8(
39492
+ /* @__PURE__ */ jsxs7(
39302
39493
  Item22,
39303
39494
  {
39304
39495
  style: {
@@ -39314,12 +39505,12 @@ var AppearanceMenu = () => {
39314
39505
  onMouseLeave: () => setHoveredItem(null),
39315
39506
  onTouchStart: () => setHoveredItem("topCopper"),
39316
39507
  children: [
39317
- /* @__PURE__ */ jsx32("span", { style: iconContainerStyles, children: visibility.topCopper && /* @__PURE__ */ jsx32(CheckIcon, {}) }),
39318
- /* @__PURE__ */ jsx32("span", { style: { display: "flex", alignItems: "center" }, children: "Top Copper" })
39508
+ /* @__PURE__ */ jsx33("span", { style: iconContainerStyles, children: visibility.topCopper && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39509
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Top Copper" })
39319
39510
  ]
39320
39511
  }
39321
39512
  ),
39322
- /* @__PURE__ */ jsxs8(
39513
+ /* @__PURE__ */ jsxs7(
39323
39514
  Item22,
39324
39515
  {
39325
39516
  style: {
@@ -39335,12 +39526,12 @@ var AppearanceMenu = () => {
39335
39526
  onMouseLeave: () => setHoveredItem(null),
39336
39527
  onTouchStart: () => setHoveredItem("bottomCopper"),
39337
39528
  children: [
39338
- /* @__PURE__ */ jsx32("span", { style: iconContainerStyles, children: visibility.bottomCopper && /* @__PURE__ */ jsx32(CheckIcon, {}) }),
39339
- /* @__PURE__ */ jsx32("span", { style: { display: "flex", alignItems: "center" }, children: "Bottom Copper" })
39529
+ /* @__PURE__ */ jsx33("span", { style: iconContainerStyles, children: visibility.bottomCopper && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39530
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Bottom Copper" })
39340
39531
  ]
39341
39532
  }
39342
39533
  ),
39343
- /* @__PURE__ */ jsxs8(
39534
+ /* @__PURE__ */ jsxs7(
39344
39535
  Item22,
39345
39536
  {
39346
39537
  style: {
@@ -39356,12 +39547,12 @@ var AppearanceMenu = () => {
39356
39547
  onMouseLeave: () => setHoveredItem(null),
39357
39548
  onTouchStart: () => setHoveredItem("topSilkscreen"),
39358
39549
  children: [
39359
- /* @__PURE__ */ jsx32("span", { style: iconContainerStyles, children: visibility.topSilkscreen && /* @__PURE__ */ jsx32(CheckIcon, {}) }),
39360
- /* @__PURE__ */ jsx32("span", { style: { display: "flex", alignItems: "center" }, children: "Top Silkscreen" })
39550
+ /* @__PURE__ */ jsx33("span", { style: iconContainerStyles, children: visibility.topSilkscreen && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39551
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Top Silkscreen" })
39361
39552
  ]
39362
39553
  }
39363
39554
  ),
39364
- /* @__PURE__ */ jsxs8(
39555
+ /* @__PURE__ */ jsxs7(
39365
39556
  Item22,
39366
39557
  {
39367
39558
  style: {
@@ -39377,12 +39568,12 @@ var AppearanceMenu = () => {
39377
39568
  onMouseLeave: () => setHoveredItem(null),
39378
39569
  onTouchStart: () => setHoveredItem("bottomSilkscreen"),
39379
39570
  children: [
39380
- /* @__PURE__ */ jsx32("span", { style: iconContainerStyles, children: visibility.bottomSilkscreen && /* @__PURE__ */ jsx32(CheckIcon, {}) }),
39381
- /* @__PURE__ */ jsx32("span", { style: { display: "flex", alignItems: "center" }, children: "Bottom Silkscreen" })
39571
+ /* @__PURE__ */ jsx33("span", { style: iconContainerStyles, children: visibility.bottomSilkscreen && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39572
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Bottom Silkscreen" })
39382
39573
  ]
39383
39574
  }
39384
39575
  ),
39385
- /* @__PURE__ */ jsxs8(
39576
+ /* @__PURE__ */ jsxs7(
39386
39577
  Item22,
39387
39578
  {
39388
39579
  style: {
@@ -39398,8 +39589,8 @@ var AppearanceMenu = () => {
39398
39589
  onMouseLeave: () => setHoveredItem(null),
39399
39590
  onTouchStart: () => setHoveredItem("smtModels"),
39400
39591
  children: [
39401
- /* @__PURE__ */ jsx32("span", { style: iconContainerStyles, children: visibility.smtModels && /* @__PURE__ */ jsx32(CheckIcon, {}) }),
39402
- /* @__PURE__ */ jsx32("span", { style: { display: "flex", alignItems: "center" }, children: "CAD Models" })
39592
+ /* @__PURE__ */ jsx33("span", { style: iconContainerStyles, children: visibility.smtModels && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39593
+ /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "CAD Models" })
39403
39594
  ]
39404
39595
  }
39405
39596
  )
@@ -39411,10 +39602,10 @@ var AppearanceMenu = () => {
39411
39602
  };
39412
39603
 
39413
39604
  // src/components/ContextMenu.tsx
39414
- import { jsx as jsx33, jsxs as jsxs9 } from "react/jsx-runtime";
39605
+ import { jsx as jsx34, jsxs as jsxs8 } from "react/jsx-runtime";
39415
39606
  var cameraOptions = [
39416
39607
  "Custom",
39417
- "Top Centered",
39608
+ "Top Center Angled",
39418
39609
  "Top Down",
39419
39610
  "Top Left Corner",
39420
39611
  "Top Right Corner",
@@ -39491,9 +39682,10 @@ var ContextMenu = ({
39491
39682
  onAutoRotateToggle,
39492
39683
  onDownloadGltf
39493
39684
  }) => {
39494
- const [cameraSubOpen, setCameraSubOpen] = useState32(false);
39495
- const [hoveredItem, setHoveredItem] = useState32(null);
39496
- return /* @__PURE__ */ jsx33(
39685
+ const { cameraType, setCameraType } = useCameraController();
39686
+ const [cameraSubOpen, setCameraSubOpen] = useState33(false);
39687
+ const [hoveredItem, setHoveredItem] = useState33(null);
39688
+ return /* @__PURE__ */ jsx34(
39497
39689
  "div",
39498
39690
  {
39499
39691
  ref: menuRef,
@@ -39504,9 +39696,9 @@ var ContextMenu = ({
39504
39696
  width: 0,
39505
39697
  height: 0
39506
39698
  },
39507
- children: /* @__PURE__ */ jsxs9(Root22, { open: true, modal: false, children: [
39508
- /* @__PURE__ */ jsx33(Trigger, { asChild: true, children: /* @__PURE__ */ jsx33("div", { style: { position: "absolute", width: 1, height: 1 } }) }),
39509
- /* @__PURE__ */ jsx33(Portal22, { children: /* @__PURE__ */ jsxs9(
39699
+ children: /* @__PURE__ */ jsxs8(Root22, { open: true, modal: false, children: [
39700
+ /* @__PURE__ */ jsx34(Trigger, { asChild: true, children: /* @__PURE__ */ jsx34("div", { style: { position: "absolute", width: 1, height: 1 } }) }),
39701
+ /* @__PURE__ */ jsx34(Portal22, { children: /* @__PURE__ */ jsxs8(
39510
39702
  Content22,
39511
39703
  {
39512
39704
  style: contentStyles2,
@@ -39515,8 +39707,8 @@ var ContextMenu = ({
39515
39707
  sideOffset: 0,
39516
39708
  align: "start",
39517
39709
  children: [
39518
- /* @__PURE__ */ jsxs9(Sub2, { onOpenChange: setCameraSubOpen, children: [
39519
- /* @__PURE__ */ jsxs9(
39710
+ /* @__PURE__ */ jsxs8(Sub2, { onOpenChange: setCameraSubOpen, children: [
39711
+ /* @__PURE__ */ jsxs8(
39520
39712
  SubTrigger2,
39521
39713
  {
39522
39714
  style: {
@@ -39528,14 +39720,14 @@ var ContextMenu = ({
39528
39720
  onMouseLeave: () => setHoveredItem(null),
39529
39721
  onTouchStart: () => setHoveredItem("camera"),
39530
39722
  children: [
39531
- /* @__PURE__ */ jsx33(
39723
+ /* @__PURE__ */ jsx34(
39532
39724
  "span",
39533
39725
  {
39534
39726
  style: { flex: 1, display: "flex", alignItems: "center" },
39535
39727
  children: "Camera Position"
39536
39728
  }
39537
39729
  ),
39538
- /* @__PURE__ */ jsxs9(
39730
+ /* @__PURE__ */ jsxs8(
39539
39731
  "div",
39540
39732
  {
39541
39733
  style: {
@@ -39545,21 +39737,21 @@ var ContextMenu = ({
39545
39737
  marginLeft: "auto"
39546
39738
  },
39547
39739
  children: [
39548
- /* @__PURE__ */ jsx33("span", { style: { opacity: 0.55, fontSize: 13 }, children: cameraPreset }),
39549
- /* @__PURE__ */ jsx33(ChevronRightIcon, { isOpen: cameraSubOpen })
39740
+ /* @__PURE__ */ jsx34("span", { style: { opacity: 0.55, fontSize: 13 }, children: cameraPreset }),
39741
+ /* @__PURE__ */ jsx34(ChevronRightIcon, { isOpen: cameraSubOpen })
39550
39742
  ]
39551
39743
  }
39552
39744
  )
39553
39745
  ]
39554
39746
  }
39555
39747
  ),
39556
- /* @__PURE__ */ jsx33(Portal22, { children: /* @__PURE__ */ jsx33(
39748
+ /* @__PURE__ */ jsx34(Portal22, { children: /* @__PURE__ */ jsx34(
39557
39749
  SubContent2,
39558
39750
  {
39559
39751
  style: { ...contentStyles2, marginLeft: -2 },
39560
39752
  collisionPadding: 10,
39561
39753
  avoidCollisions: true,
39562
- children: cameraOptions.map((option) => /* @__PURE__ */ jsxs9(
39754
+ children: cameraOptions.map((option) => /* @__PURE__ */ jsxs8(
39563
39755
  Item22,
39564
39756
  {
39565
39757
  style: {
@@ -39575,8 +39767,8 @@ var ContextMenu = ({
39575
39767
  onMouseLeave: () => setHoveredItem(null),
39576
39768
  onTouchStart: () => setHoveredItem(option),
39577
39769
  children: [
39578
- /* @__PURE__ */ jsx33("span", { style: iconContainerStyles2, children: cameraPreset === option && /* @__PURE__ */ jsx33(DotIcon, {}) }),
39579
- /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: option })
39770
+ /* @__PURE__ */ jsx34("span", { style: iconContainerStyles2, children: cameraPreset === option && /* @__PURE__ */ jsx34(DotIcon, {}) }),
39771
+ /* @__PURE__ */ jsx34("span", { style: { display: "flex", alignItems: "center" }, children: option })
39580
39772
  ]
39581
39773
  },
39582
39774
  option
@@ -39584,7 +39776,7 @@ var ContextMenu = ({
39584
39776
  }
39585
39777
  ) })
39586
39778
  ] }),
39587
- /* @__PURE__ */ jsxs9(
39779
+ /* @__PURE__ */ jsxs8(
39588
39780
  Item22,
39589
39781
  {
39590
39782
  style: {
@@ -39601,14 +39793,38 @@ var ContextMenu = ({
39601
39793
  onMouseLeave: () => setHoveredItem(null),
39602
39794
  onTouchStart: () => setHoveredItem("autorotate"),
39603
39795
  children: [
39604
- /* @__PURE__ */ jsx33("span", { style: iconContainerStyles2, children: autoRotate && /* @__PURE__ */ jsx33(CheckIcon, {}) }),
39605
- /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Auto rotate" })
39796
+ /* @__PURE__ */ jsx34("span", { style: iconContainerStyles2, children: autoRotate && /* @__PURE__ */ jsx34(CheckIcon, {}) }),
39797
+ /* @__PURE__ */ jsx34("span", { style: { display: "flex", alignItems: "center" }, children: "Auto rotate" })
39798
+ ]
39799
+ }
39800
+ ),
39801
+ /* @__PURE__ */ jsxs8(
39802
+ Item22,
39803
+ {
39804
+ style: {
39805
+ ...itemStyles2,
39806
+ ...itemPaddingStyles2,
39807
+ backgroundColor: hoveredItem === "cameratype" ? "#404040" : "transparent"
39808
+ },
39809
+ onSelect: (e) => e.preventDefault(),
39810
+ onPointerDown: (e) => {
39811
+ e.preventDefault();
39812
+ setCameraType(
39813
+ cameraType === "perspective" ? "orthographic" : "perspective"
39814
+ );
39815
+ },
39816
+ onMouseEnter: () => setHoveredItem("cameratype"),
39817
+ onMouseLeave: () => setHoveredItem(null),
39818
+ onTouchStart: () => setHoveredItem("cameratype"),
39819
+ children: [
39820
+ /* @__PURE__ */ jsx34("span", { style: iconContainerStyles2, children: cameraType === "orthographic" && /* @__PURE__ */ jsx34(CheckIcon, {}) }),
39821
+ /* @__PURE__ */ jsx34("span", { style: { display: "flex", alignItems: "center" }, children: "Orthographic Camera" })
39606
39822
  ]
39607
39823
  }
39608
39824
  ),
39609
- /* @__PURE__ */ jsx33(AppearanceMenu, {}),
39610
- /* @__PURE__ */ jsx33(Separator2, { style: separatorStyles2 }),
39611
- /* @__PURE__ */ jsx33(
39825
+ /* @__PURE__ */ jsx34(AppearanceMenu, {}),
39826
+ /* @__PURE__ */ jsx34(Separator2, { style: separatorStyles2 }),
39827
+ /* @__PURE__ */ jsx34(
39612
39828
  Item22,
39613
39829
  {
39614
39830
  style: {
@@ -39620,11 +39836,11 @@ var ContextMenu = ({
39620
39836
  onMouseEnter: () => setHoveredItem("download"),
39621
39837
  onMouseLeave: () => setHoveredItem(null),
39622
39838
  onTouchStart: () => setHoveredItem("download"),
39623
- children: /* @__PURE__ */ jsx33("span", { style: { display: "flex", alignItems: "center" }, children: "Download GLTF" })
39839
+ children: /* @__PURE__ */ jsx34("span", { style: { display: "flex", alignItems: "center" }, children: "Download GLTF" })
39624
39840
  }
39625
39841
  ),
39626
- /* @__PURE__ */ jsx33(Separator2, { style: separatorStyles2 }),
39627
- /* @__PURE__ */ jsxs9(
39842
+ /* @__PURE__ */ jsx34(Separator2, { style: separatorStyles2 }),
39843
+ /* @__PURE__ */ jsxs8(
39628
39844
  Item22,
39629
39845
  {
39630
39846
  style: {
@@ -39641,12 +39857,12 @@ var ContextMenu = ({
39641
39857
  onMouseLeave: () => setHoveredItem(null),
39642
39858
  onTouchStart: () => setHoveredItem("engine"),
39643
39859
  children: [
39644
- /* @__PURE__ */ jsxs9("span", { style: { flex: 1, display: "flex", alignItems: "center" }, children: [
39860
+ /* @__PURE__ */ jsxs8("span", { style: { flex: 1, display: "flex", alignItems: "center" }, children: [
39645
39861
  "Switch to ",
39646
39862
  engine === "jscad" ? "Manifold" : "JSCAD",
39647
39863
  " Engine"
39648
39864
  ] }),
39649
- /* @__PURE__ */ jsx33(
39865
+ /* @__PURE__ */ jsx34(
39650
39866
  "div",
39651
39867
  {
39652
39868
  style: {
@@ -39660,8 +39876,8 @@ var ContextMenu = ({
39660
39876
  ]
39661
39877
  }
39662
39878
  ),
39663
- /* @__PURE__ */ jsx33(Separator2, { style: separatorStyles2 }),
39664
- /* @__PURE__ */ jsx33(
39879
+ /* @__PURE__ */ jsx34(Separator2, { style: separatorStyles2 }),
39880
+ /* @__PURE__ */ jsx34(
39665
39881
  "div",
39666
39882
  {
39667
39883
  style: {
@@ -39672,7 +39888,7 @@ var ContextMenu = ({
39672
39888
  paddingTop: 4,
39673
39889
  paddingBottom: 4
39674
39890
  },
39675
- children: /* @__PURE__ */ jsxs9(
39891
+ children: /* @__PURE__ */ jsxs8(
39676
39892
  "span",
39677
39893
  {
39678
39894
  style: {
@@ -39699,21 +39915,22 @@ var ContextMenu = ({
39699
39915
  };
39700
39916
 
39701
39917
  // src/CadViewer.tsx
39702
- import { jsx as jsx34, jsxs as jsxs10 } from "react/jsx-runtime";
39918
+ import { jsx as jsx35, jsxs as jsxs9 } from "react/jsx-runtime";
39703
39919
  var CadViewerInner = (props) => {
39704
- const [engine, setEngine] = useState33("manifold");
39705
- const containerRef = useRef23(null);
39706
- const [autoRotate, setAutoRotate] = useState33(() => {
39920
+ const [engine, setEngine] = useState34("manifold");
39921
+ const containerRef = useRef24(null);
39922
+ const [autoRotate, setAutoRotate] = useState34(() => {
39707
39923
  const stored = window.localStorage.getItem("cadViewerAutoRotate");
39708
39924
  return stored === "false" ? false : true;
39709
39925
  });
39710
- const [autoRotateUserToggled, setAutoRotateUserToggled] = useState33(() => {
39926
+ const [autoRotateUserToggled, setAutoRotateUserToggled] = useState34(() => {
39711
39927
  const stored = window.localStorage.getItem("cadViewerAutoRotateUserToggled");
39712
39928
  return stored === "true";
39713
39929
  });
39714
- const [cameraPreset, setCameraPreset] = useState33("Custom");
39930
+ const [cameraPreset, setCameraPreset] = useState34("Custom");
39931
+ const { cameraType, setCameraType } = useCameraController();
39715
39932
  const { visibility, toggleLayer } = useLayerVisibility();
39716
- const cameraControllerRef = useRef23(null);
39933
+ const cameraControllerRef = useRef24(null);
39717
39934
  const externalCameraControllerReady = props.onCameraControllerReady;
39718
39935
  const {
39719
39936
  menuVisible,
@@ -39722,12 +39939,12 @@ var CadViewerInner = (props) => {
39722
39939
  contextMenuEventHandlers,
39723
39940
  setMenuVisible
39724
39941
  } = useContextMenu({ containerRef });
39725
- const autoRotateUserToggledRef = useRef23(autoRotateUserToggled);
39942
+ const autoRotateUserToggledRef = useRef24(autoRotateUserToggled);
39726
39943
  autoRotateUserToggledRef.current = autoRotateUserToggled;
39727
- const isAnimatingRef = useRef23(false);
39728
- const lastPresetSelectTime = useRef23(0);
39944
+ const isAnimatingRef = useRef24(false);
39945
+ const lastPresetSelectTime = useRef24(0);
39729
39946
  const PRESET_COOLDOWN = 1e3;
39730
- const handleUserInteraction = useCallback20(() => {
39947
+ const handleUserInteraction = useCallback22(() => {
39731
39948
  if (isAnimatingRef.current || Date.now() - lastPresetSelectTime.current < PRESET_COOLDOWN) {
39732
39949
  return;
39733
39950
  }
@@ -39738,15 +39955,15 @@ var CadViewerInner = (props) => {
39738
39955
  setCameraPreset("Custom");
39739
39956
  }
39740
39957
  }, [menuVisible]);
39741
- const toggleAutoRotate = useCallback20(() => {
39958
+ const toggleAutoRotate = useCallback22(() => {
39742
39959
  setAutoRotate((prev) => !prev);
39743
39960
  setAutoRotateUserToggled(true);
39744
39961
  }, []);
39745
39962
  const downloadGltf = useGlobalDownloadGltf();
39746
- const closeMenu = useCallback20(() => {
39963
+ const closeMenu = useCallback22(() => {
39747
39964
  setMenuVisible(false);
39748
39965
  }, [setMenuVisible]);
39749
- const handleCameraControllerReady = useCallback20(
39966
+ const handleCameraControllerReady = useCallback22(
39750
39967
  (controller) => {
39751
39968
  cameraControllerRef.current = controller;
39752
39969
  externalCameraControllerReady?.(controller);
@@ -39765,26 +39982,35 @@ var CadViewerInner = (props) => {
39765
39982
  isAnimatingRef,
39766
39983
  lastPresetSelectTime
39767
39984
  });
39768
- useEffect39(() => {
39985
+ useEffect40(() => {
39769
39986
  const stored = window.localStorage.getItem("cadViewerEngine");
39770
39987
  if (stored === "jscad" || stored === "manifold") {
39771
39988
  setEngine(stored);
39772
39989
  }
39773
39990
  }, []);
39774
- useEffect39(() => {
39991
+ useEffect40(() => {
39775
39992
  window.localStorage.setItem("cadViewerEngine", engine);
39776
39993
  }, [engine]);
39777
- useEffect39(() => {
39994
+ useEffect40(() => {
39778
39995
  window.localStorage.setItem("cadViewerAutoRotate", String(autoRotate));
39779
39996
  }, [autoRotate]);
39780
- useEffect39(() => {
39997
+ useEffect40(() => {
39781
39998
  window.localStorage.setItem(
39782
39999
  "cadViewerAutoRotateUserToggled",
39783
40000
  String(autoRotateUserToggled)
39784
40001
  );
39785
40002
  }, [autoRotateUserToggled]);
40003
+ useEffect40(() => {
40004
+ const stored = window.localStorage.getItem("cadViewerCameraType");
40005
+ if (stored === "orthographic" || stored === "perspective") {
40006
+ setCameraType(stored);
40007
+ }
40008
+ }, [setCameraType]);
40009
+ useEffect40(() => {
40010
+ window.localStorage.setItem("cadViewerCameraType", cameraType);
40011
+ }, [cameraType]);
39786
40012
  const viewerKey = props.circuitJson ? JSON.stringify(props.circuitJson) : void 0;
39787
- return /* @__PURE__ */ jsxs10(
40013
+ return /* @__PURE__ */ jsxs9(
39788
40014
  "div",
39789
40015
  {
39790
40016
  ref: containerRef,
@@ -39800,24 +40026,26 @@ var CadViewerInner = (props) => {
39800
40026
  },
39801
40027
  ...contextMenuEventHandlers,
39802
40028
  children: [
39803
- engine === "jscad" ? /* @__PURE__ */ jsx34(
40029
+ engine === "jscad" ? /* @__PURE__ */ jsx35(
39804
40030
  CadViewerJscad,
39805
40031
  {
39806
40032
  ...props,
39807
40033
  autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
40034
+ cameraType,
39808
40035
  onUserInteraction: handleUserInteraction,
39809
40036
  onCameraControllerReady: handleCameraControllerReady
39810
40037
  }
39811
- ) : /* @__PURE__ */ jsx34(
40038
+ ) : /* @__PURE__ */ jsx35(
39812
40039
  CadViewerManifold_default,
39813
40040
  {
39814
40041
  ...props,
39815
40042
  autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
40043
+ cameraType,
39816
40044
  onUserInteraction: handleUserInteraction,
39817
40045
  onCameraControllerReady: handleCameraControllerReady
39818
40046
  }
39819
40047
  ),
39820
- /* @__PURE__ */ jsxs10(
40048
+ /* @__PURE__ */ jsxs9(
39821
40049
  "div",
39822
40050
  {
39823
40051
  style: {
@@ -39834,11 +40062,11 @@ var CadViewerInner = (props) => {
39834
40062
  },
39835
40063
  children: [
39836
40064
  "Engine: ",
39837
- /* @__PURE__ */ jsx34("b", { children: engine === "jscad" ? "JSCAD" : "Manifold" })
40065
+ /* @__PURE__ */ jsx35("b", { children: engine === "jscad" ? "JSCAD" : "Manifold" })
39838
40066
  ]
39839
40067
  }
39840
40068
  ),
39841
- menuVisible && /* @__PURE__ */ jsx34(
40069
+ menuVisible && /* @__PURE__ */ jsx35(
39842
40070
  ContextMenu,
39843
40071
  {
39844
40072
  menuRef,
@@ -39867,17 +40095,29 @@ var CadViewerInner = (props) => {
39867
40095
  );
39868
40096
  };
39869
40097
  var CadViewer = (props) => {
39870
- return /* @__PURE__ */ jsx34(LayerVisibilityProvider, { children: /* @__PURE__ */ jsx34(CadViewerInner, { ...props }) });
40098
+ const defaultTarget = useMemo26(() => new THREE29.Vector3(0, 0, 0), []);
40099
+ const initialCameraPosition = useMemo26(
40100
+ () => [5, -5, 5],
40101
+ []
40102
+ );
40103
+ return /* @__PURE__ */ jsx35(
40104
+ CameraControllerProvider,
40105
+ {
40106
+ defaultTarget,
40107
+ initialCameraPosition,
40108
+ children: /* @__PURE__ */ jsx35(LayerVisibilityProvider, { children: /* @__PURE__ */ jsx35(CadViewerInner, { ...props }) })
40109
+ }
40110
+ );
39871
40111
  };
39872
40112
 
39873
40113
  // src/convert-circuit-json-to-3d-svg.ts
39874
40114
  var import_debug = __toESM(require_browser(), 1);
39875
- import { su as su14 } from "@tscircuit/circuit-json-util";
39876
- import * as THREE31 from "three";
40115
+ import { su as su16 } from "@tscircuit/circuit-json-util";
40116
+ import * as THREE33 from "three";
39877
40117
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
39878
40118
 
39879
40119
  // src/utils/create-geometry-from-polygons.ts
39880
- import * as THREE28 from "three";
40120
+ import * as THREE30 from "three";
39881
40121
  import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute2 } from "three";
39882
40122
  function createGeometryFromPolygons(polygons) {
39883
40123
  const geometry = new BufferGeometry3();
@@ -39891,12 +40131,12 @@ function createGeometryFromPolygons(polygons) {
39891
40131
  ...polygon3.vertices[i + 1]
39892
40132
  // Third vertex
39893
40133
  );
39894
- const v1 = new THREE28.Vector3(...polygon3.vertices[0]);
39895
- const v2 = new THREE28.Vector3(...polygon3.vertices[i]);
39896
- const v3 = new THREE28.Vector3(...polygon3.vertices[i + 1]);
39897
- const normal = new THREE28.Vector3().crossVectors(
39898
- new THREE28.Vector3().subVectors(v2, v1),
39899
- new THREE28.Vector3().subVectors(v3, v1)
40134
+ const v1 = new THREE30.Vector3(...polygon3.vertices[0]);
40135
+ const v2 = new THREE30.Vector3(...polygon3.vertices[i]);
40136
+ const v3 = new THREE30.Vector3(...polygon3.vertices[i + 1]);
40137
+ const normal = new THREE30.Vector3().crossVectors(
40138
+ new THREE30.Vector3().subVectors(v2, v1),
40139
+ new THREE30.Vector3().subVectors(v3, v1)
39900
40140
  ).normalize();
39901
40141
  normals.push(
39902
40142
  normal.x,
@@ -39920,10 +40160,10 @@ function createGeometryFromPolygons(polygons) {
39920
40160
  var import_modeling2 = __toESM(require_src(), 1);
39921
40161
  var import_jscad_planner2 = __toESM(require_dist(), 1);
39922
40162
  var jscadModeling2 = __toESM(require_src(), 1);
39923
- import * as THREE30 from "three";
40163
+ import * as THREE32 from "three";
39924
40164
 
39925
40165
  // src/utils/load-model.ts
39926
- import * as THREE29 from "three";
40166
+ import * as THREE31 from "three";
39927
40167
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
39928
40168
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
39929
40169
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -39931,12 +40171,12 @@ async function load3DModel(url) {
39931
40171
  if (url.endsWith(".stl")) {
39932
40172
  const loader = new STLLoader2();
39933
40173
  const geometry = await loader.loadAsync(url);
39934
- const material = new THREE29.MeshStandardMaterial({
40174
+ const material = new THREE31.MeshStandardMaterial({
39935
40175
  color: 8947848,
39936
40176
  metalness: 0.5,
39937
40177
  roughness: 0.5
39938
40178
  });
39939
- return new THREE29.Mesh(geometry, material);
40179
+ return new THREE31.Mesh(geometry, material);
39940
40180
  }
39941
40181
  if (url.endsWith(".obj")) {
39942
40182
  const loader = new OBJLoader2();
@@ -39969,9 +40209,9 @@ async function renderComponent(component, scene) {
39969
40209
  }
39970
40210
  if (component.rotation) {
39971
40211
  model.rotation.set(
39972
- THREE30.MathUtils.degToRad(component.rotation.x ?? 0),
39973
- THREE30.MathUtils.degToRad(component.rotation.y ?? 0),
39974
- THREE30.MathUtils.degToRad(component.rotation.z ?? 0)
40212
+ THREE32.MathUtils.degToRad(component.rotation.x ?? 0),
40213
+ THREE32.MathUtils.degToRad(component.rotation.y ?? 0),
40214
+ THREE32.MathUtils.degToRad(component.rotation.z ?? 0)
39975
40215
  );
39976
40216
  }
39977
40217
  scene.add(model);
@@ -39985,13 +40225,13 @@ async function renderComponent(component, scene) {
39985
40225
  );
39986
40226
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
39987
40227
  const threeGeom = convertCSGToThreeGeom(jscadObject);
39988
- const material2 = new THREE30.MeshStandardMaterial({
40228
+ const material2 = new THREE32.MeshStandardMaterial({
39989
40229
  color: 8947848,
39990
40230
  metalness: 0.5,
39991
40231
  roughness: 0.5,
39992
- side: THREE30.DoubleSide
40232
+ side: THREE32.DoubleSide
39993
40233
  });
39994
- const mesh2 = new THREE30.Mesh(threeGeom, material2);
40234
+ const mesh2 = new THREE32.Mesh(threeGeom, material2);
39995
40235
  if (component.position) {
39996
40236
  mesh2.position.set(
39997
40237
  component.position.x ?? 0,
@@ -40001,9 +40241,9 @@ async function renderComponent(component, scene) {
40001
40241
  }
40002
40242
  if (component.rotation) {
40003
40243
  mesh2.rotation.set(
40004
- THREE30.MathUtils.degToRad(component.rotation.x ?? 0),
40005
- THREE30.MathUtils.degToRad(component.rotation.y ?? 0),
40006
- THREE30.MathUtils.degToRad(component.rotation.z ?? 0)
40244
+ THREE32.MathUtils.degToRad(component.rotation.x ?? 0),
40245
+ THREE32.MathUtils.degToRad(component.rotation.y ?? 0),
40246
+ THREE32.MathUtils.degToRad(component.rotation.z ?? 0)
40007
40247
  );
40008
40248
  }
40009
40249
  scene.add(mesh2);
@@ -40020,17 +40260,17 @@ async function renderComponent(component, scene) {
40020
40260
  if (!geom || !geom.polygons && !geom.sides) {
40021
40261
  continue;
40022
40262
  }
40023
- const color = new THREE30.Color(geomInfo.color);
40263
+ const color = new THREE32.Color(geomInfo.color);
40024
40264
  color.convertLinearToSRGB();
40025
40265
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
40026
40266
  const threeGeom = convertCSGToThreeGeom(geomWithColor);
40027
- const material2 = new THREE30.MeshStandardMaterial({
40267
+ const material2 = new THREE32.MeshStandardMaterial({
40028
40268
  vertexColors: true,
40029
40269
  metalness: 0.2,
40030
40270
  roughness: 0.8,
40031
- side: THREE30.DoubleSide
40271
+ side: THREE32.DoubleSide
40032
40272
  });
40033
- const mesh2 = new THREE30.Mesh(threeGeom, material2);
40273
+ const mesh2 = new THREE32.Mesh(threeGeom, material2);
40034
40274
  if (component.position) {
40035
40275
  mesh2.position.set(
40036
40276
  component.position.x ?? 0,
@@ -40040,22 +40280,22 @@ async function renderComponent(component, scene) {
40040
40280
  }
40041
40281
  if (component.rotation) {
40042
40282
  mesh2.rotation.set(
40043
- THREE30.MathUtils.degToRad(component.rotation.x ?? 0),
40044
- THREE30.MathUtils.degToRad(component.rotation.y ?? 0),
40045
- THREE30.MathUtils.degToRad(component.rotation.z ?? 0)
40283
+ THREE32.MathUtils.degToRad(component.rotation.x ?? 0),
40284
+ THREE32.MathUtils.degToRad(component.rotation.y ?? 0),
40285
+ THREE32.MathUtils.degToRad(component.rotation.z ?? 0)
40046
40286
  );
40047
40287
  }
40048
40288
  scene.add(mesh2);
40049
40289
  }
40050
40290
  return;
40051
40291
  }
40052
- const geometry = new THREE30.BoxGeometry(0.5, 0.5, 0.5);
40053
- const material = new THREE30.MeshStandardMaterial({
40292
+ const geometry = new THREE32.BoxGeometry(0.5, 0.5, 0.5);
40293
+ const material = new THREE32.MeshStandardMaterial({
40054
40294
  color: 16711680,
40055
40295
  transparent: true,
40056
40296
  opacity: 0.25
40057
40297
  });
40058
- const mesh = new THREE30.Mesh(geometry, material);
40298
+ const mesh = new THREE32.Mesh(geometry, material);
40059
40299
  if (component.position) {
40060
40300
  mesh.position.set(
40061
40301
  component.position.x ?? 0,
@@ -40076,11 +40316,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
40076
40316
  padding = 20,
40077
40317
  zoom = 1.5
40078
40318
  } = options;
40079
- const scene = new THREE31.Scene();
40319
+ const scene = new THREE33.Scene();
40080
40320
  const renderer = new SVGRenderer();
40081
40321
  renderer.setSize(width10, height10);
40082
- renderer.setClearColor(new THREE31.Color(backgroundColor), 1);
40083
- const camera = new THREE31.OrthographicCamera();
40322
+ renderer.setClearColor(new THREE33.Color(backgroundColor), 1);
40323
+ const camera = new THREE33.OrthographicCamera();
40084
40324
  const aspect = width10 / height10;
40085
40325
  const frustumSize = 100;
40086
40326
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -40094,25 +40334,25 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
40094
40334
  camera.position.set(position.x, position.y, position.z);
40095
40335
  camera.up.set(0, 1, 0);
40096
40336
  const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
40097
- camera.lookAt(new THREE31.Vector3(lookAt.x, lookAt.y, lookAt.z));
40337
+ camera.lookAt(new THREE33.Vector3(lookAt.x, lookAt.y, lookAt.z));
40098
40338
  camera.updateProjectionMatrix();
40099
- const ambientLight = new THREE31.AmbientLight(16777215, Math.PI / 2);
40339
+ const ambientLight = new THREE33.AmbientLight(16777215, Math.PI / 2);
40100
40340
  scene.add(ambientLight);
40101
- const pointLight = new THREE31.PointLight(16777215, Math.PI / 4);
40341
+ const pointLight = new THREE33.PointLight(16777215, Math.PI / 4);
40102
40342
  pointLight.position.set(-10, -10, 10);
40103
40343
  scene.add(pointLight);
40104
- const components = su14(circuitJson).cad_component.list();
40344
+ const components = su16(circuitJson).cad_component.list();
40105
40345
  for (const component of components) {
40106
40346
  await renderComponent(component, scene);
40107
40347
  }
40108
- const boardData = su14(circuitJson).pcb_board.list()[0];
40348
+ const boardData = su16(circuitJson).pcb_board.list()[0];
40109
40349
  const boardGeom = createBoardGeomFromCircuitJson(circuitJson);
40110
40350
  if (boardGeom) {
40111
40351
  for (const geom of boardGeom) {
40112
40352
  const g = geom;
40113
40353
  if (!g.polygons || g.polygons.length === 0) continue;
40114
40354
  const geometry = createGeometryFromPolygons(g.polygons);
40115
- const baseColor = new THREE31.Color(
40355
+ const baseColor = new THREE33.Color(
40116
40356
  g.color?.[0] ?? 0,
40117
40357
  g.color?.[1] ?? 0,
40118
40358
  g.color?.[2] ?? 0
@@ -40120,18 +40360,18 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
40120
40360
  const material = createBoardMaterial({
40121
40361
  material: boardData?.material,
40122
40362
  color: baseColor,
40123
- side: THREE31.DoubleSide
40363
+ side: THREE33.DoubleSide
40124
40364
  });
40125
- const mesh = new THREE31.Mesh(geometry, material);
40365
+ const mesh = new THREE33.Mesh(geometry, material);
40126
40366
  scene.add(mesh);
40127
40367
  }
40128
40368
  }
40129
- const gridHelper = new THREE31.GridHelper(100, 100);
40369
+ const gridHelper = new THREE33.GridHelper(100, 100);
40130
40370
  gridHelper.rotation.x = Math.PI / 2;
40131
40371
  scene.add(gridHelper);
40132
- const box = new THREE31.Box3().setFromObject(scene);
40133
- const center = box.getCenter(new THREE31.Vector3());
40134
- const size5 = box.getSize(new THREE31.Vector3());
40372
+ const box = new THREE33.Box3().setFromObject(scene);
40373
+ const center = box.getCenter(new THREE33.Vector3());
40374
+ const size5 = box.getSize(new THREE33.Vector3());
40135
40375
  scene.position.sub(center);
40136
40376
  const maxDim = Math.max(size5.x, size5.y, size5.z);
40137
40377
  if (maxDim > 0) {
@@ -40149,7 +40389,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
40149
40389
 
40150
40390
  // src/hooks/exporter/gltf.ts
40151
40391
  import { GLTFExporter as GLTFExporter2 } from "three-stdlib";
40152
- import { useEffect as useEffect40, useState as useState34, useMemo as useMemo27, useCallback as useCallback21 } from "react";
40392
+ import { useEffect as useEffect41, useState as useState35, useMemo as useMemo27, useCallback as useCallback23 } from "react";
40153
40393
  function useSaveGltfAs(options = {}) {
40154
40394
  const parse2 = useParser(options);
40155
40395
  const link = useMemo27(() => document.createElement("a"), []);
@@ -40162,7 +40402,7 @@ function useSaveGltfAs(options = {}) {
40162
40402
  link.dispatchEvent(new MouseEvent("click"));
40163
40403
  URL.revokeObjectURL(url);
40164
40404
  };
40165
- useEffect40(
40405
+ useEffect41(
40166
40406
  () => () => {
40167
40407
  link.remove();
40168
40408
  instance = null;
@@ -40170,20 +40410,20 @@ function useSaveGltfAs(options = {}) {
40170
40410
  []
40171
40411
  );
40172
40412
  let instance;
40173
- const ref = useCallback21((obj3D) => {
40413
+ const ref = useCallback23((obj3D) => {
40174
40414
  instance = obj3D;
40175
40415
  }, []);
40176
40416
  return [ref, saveAs];
40177
40417
  }
40178
40418
  function useExportGltfUrl(options = {}) {
40179
40419
  const parse2 = useParser(options);
40180
- const [url, setUrl] = useState34();
40181
- const [error, setError] = useState34();
40182
- const ref = useCallback21(
40420
+ const [url, setUrl] = useState35();
40421
+ const [error, setError] = useState35();
40422
+ const ref = useCallback23(
40183
40423
  (instance) => parse2(instance).then(setUrl).catch(setError),
40184
40424
  []
40185
40425
  );
40186
- useEffect40(() => () => URL.revokeObjectURL(url), [url]);
40426
+ useEffect41(() => () => URL.revokeObjectURL(url), [url]);
40187
40427
  return [ref, url, error];
40188
40428
  }
40189
40429
  function useParser(options = {}) {
@@ -40214,8 +40454,14 @@ function applyJsdomShim(jsdom) {
40214
40454
  }
40215
40455
  export {
40216
40456
  CadViewer,
40457
+ CameraAnimatorWithContext,
40458
+ CameraControllerProvider,
40217
40459
  applyJsdomShim,
40218
40460
  convertCircuitJsonTo3dSvg,
40461
+ loadCameraFromSession,
40462
+ saveCameraToSession,
40463
+ useCameraController,
40464
+ useCameraSession,
40219
40465
  useExportGltfUrl,
40220
40466
  useManifoldBoardBuilder,
40221
40467
  useSaveGltfAs