@tscircuit/3d-viewer 0.0.233 → 0.0.234

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +113 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13980,7 +13980,7 @@ var require_browser = __commonJS({
13980
13980
  });
13981
13981
 
13982
13982
  // src/CadViewer.tsx
13983
- import { useState as useState9, useCallback as useCallback4, useRef as useRef7, useEffect as useEffect7 } from "react";
13983
+ import { useState as useState10, useRef as useRef8, useEffect as useEffect8 } from "react";
13984
13984
 
13985
13985
  // src/hooks/use-convert-children-to-soup.ts
13986
13986
  import { Circuit } from "@tscircuit/core";
@@ -16985,7 +16985,7 @@ import { Canvas, useFrame as useFrame2 } from "@react-three/fiber";
16985
16985
  // package.json
16986
16986
  var package_default = {
16987
16987
  name: "@tscircuit/3d-viewer",
16988
- version: "0.0.232",
16988
+ version: "0.0.233",
16989
16989
  main: "./dist/index.js",
16990
16990
  module: "./dist/index.js",
16991
16991
  type: "module",
@@ -17313,7 +17313,7 @@ var colors = {
17313
17313
  var MANIFOLD_Z_OFFSET = 1e-3;
17314
17314
  var SMOOTH_CIRCLE_SEGMENTS = 32;
17315
17315
  var DEFAULT_SMT_PAD_THICKNESS = 0.035;
17316
- var TRACE_TEXTURE_RESOLUTION = 200;
17316
+ var TRACE_TEXTURE_RESOLUTION = 50;
17317
17317
  var boardMaterialColors = {
17318
17318
  fr1: colors.fr1Copper,
17319
17319
  fr4: colors.fr4Green
@@ -19905,29 +19905,76 @@ var CadViewerManifold = ({
19905
19905
  };
19906
19906
  var CadViewerManifold_default = CadViewerManifold;
19907
19907
 
19908
- // src/CadViewer.tsx
19909
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
19910
- var CadViewer = (props) => {
19911
- const [engine, setEngine] = useState9("jscad");
19908
+ // src/hooks/useContextMenu.ts
19909
+ import { useState as useState9, useCallback as useCallback4, useRef as useRef7, useEffect as useEffect7 } from "react";
19910
+ var useContextMenu = ({ containerRef }) => {
19912
19911
  const [menuVisible, setMenuVisible] = useState9(false);
19913
19912
  const [menuPos, setMenuPos] = useState9({
19914
19913
  x: 0,
19915
19914
  y: 0
19916
19915
  });
19917
- const containerRef = useRef7(null);
19918
19916
  const menuRef = useRef7(null);
19919
- const handleContextMenu = useCallback4((e) => {
19920
- e.preventDefault();
19921
- setMenuPos({ x: e.clientX, y: e.clientY });
19922
- setMenuVisible(true);
19917
+ const interactionOriginPosRef = useRef7(null);
19918
+ const handleContextMenu = useCallback4(
19919
+ (e) => {
19920
+ e.preventDefault();
19921
+ const eventX = typeof e.clientX === "number" ? e.clientX : 0;
19922
+ const eventY = typeof e.clientY === "number" ? e.clientY : 0;
19923
+ if (!interactionOriginPosRef.current) {
19924
+ return;
19925
+ }
19926
+ const { x: originX, y: originY } = interactionOriginPosRef.current;
19927
+ const dx = Math.abs(eventX - originX);
19928
+ const dy = Math.abs(eventY - originY);
19929
+ const swipeThreshold = 10;
19930
+ if (dx > swipeThreshold || dy > swipeThreshold) {
19931
+ interactionOriginPosRef.current = null;
19932
+ return;
19933
+ }
19934
+ setMenuPos({ x: eventX, y: eventY });
19935
+ setMenuVisible(true);
19936
+ interactionOriginPosRef.current = null;
19937
+ },
19938
+ [setMenuPos, setMenuVisible]
19939
+ );
19940
+ const handleTouchStart = useCallback4((e) => {
19941
+ if (e.touches.length === 1) {
19942
+ const touch = e.touches[0];
19943
+ if (touch) {
19944
+ interactionOriginPosRef.current = { x: touch.clientX, y: touch.clientY };
19945
+ } else {
19946
+ interactionOriginPosRef.current = null;
19947
+ }
19948
+ } else {
19949
+ interactionOriginPosRef.current = null;
19950
+ }
19951
+ }, []);
19952
+ const handleTouchMove = useCallback4((e) => {
19953
+ if (!interactionOriginPosRef.current || e.touches.length !== 1) {
19954
+ return;
19955
+ }
19956
+ const touch = e.touches[0];
19957
+ if (touch) {
19958
+ const dx = Math.abs(touch.clientX - interactionOriginPosRef.current.x);
19959
+ const dy = Math.abs(touch.clientY - interactionOriginPosRef.current.y);
19960
+ const swipeThreshold = 10;
19961
+ if (dx > swipeThreshold || dy > swipeThreshold) {
19962
+ interactionOriginPosRef.current = null;
19963
+ }
19964
+ } else {
19965
+ interactionOriginPosRef.current = null;
19966
+ }
19967
+ }, []);
19968
+ const handleTouchEnd = useCallback4(() => {
19969
+ setTimeout(() => {
19970
+ if (interactionOriginPosRef.current) {
19971
+ interactionOriginPosRef.current = null;
19972
+ }
19973
+ }, 0);
19923
19974
  }, []);
19924
- const handleMenuClick = (newEngine) => {
19925
- setEngine(newEngine);
19926
- setMenuVisible(false);
19927
- };
19928
19975
  const handleClickAway = useCallback4((e) => {
19929
19976
  const target = e.target;
19930
- if (!menuRef.current || !menuRef.current.contains(target)) {
19977
+ if (menuRef.current && !menuRef.current.contains(target)) {
19931
19978
  setMenuVisible(false);
19932
19979
  }
19933
19980
  }, []);
@@ -19937,13 +19984,52 @@ var CadViewer = (props) => {
19937
19984
  return () => document.removeEventListener("mousedown", handleClickAway);
19938
19985
  }
19939
19986
  }, [menuVisible, handleClickAway]);
19940
- useEffect7(() => {
19987
+ const contextMenuEventHandlers = {
19988
+ onMouseDown: (e) => {
19989
+ if (e.button === 2) {
19990
+ interactionOriginPosRef.current = { x: e.clientX, y: e.clientY };
19991
+ } else {
19992
+ interactionOriginPosRef.current = null;
19993
+ }
19994
+ },
19995
+ onContextMenu: handleContextMenu,
19996
+ onTouchStart: handleTouchStart,
19997
+ onTouchMove: handleTouchMove,
19998
+ onTouchEnd: handleTouchEnd
19999
+ };
20000
+ return {
20001
+ menuVisible,
20002
+ menuPos,
20003
+ menuRef,
20004
+ contextMenuEventHandlers,
20005
+ setMenuVisible
20006
+ // Expose setMenuVisible for direct control if needed
20007
+ };
20008
+ };
20009
+
20010
+ // src/CadViewer.tsx
20011
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
20012
+ var CadViewer = (props) => {
20013
+ const [engine, setEngine] = useState10("jscad");
20014
+ const containerRef = useRef8(null);
20015
+ const {
20016
+ menuVisible,
20017
+ menuPos,
20018
+ menuRef,
20019
+ contextMenuEventHandlers,
20020
+ setMenuVisible
20021
+ } = useContextMenu({ containerRef });
20022
+ const handleMenuClick = (newEngine) => {
20023
+ setEngine(newEngine);
20024
+ setMenuVisible(false);
20025
+ };
20026
+ useEffect8(() => {
19941
20027
  const stored = window.localStorage.getItem("cadViewerEngine");
19942
20028
  if (stored === "jscad" || stored === "manifold") {
19943
20029
  setEngine(stored);
19944
20030
  }
19945
20031
  }, []);
19946
- useEffect7(() => {
20032
+ useEffect8(() => {
19947
20033
  window.localStorage.setItem("cadViewerEngine", engine);
19948
20034
  }, [engine]);
19949
20035
  const viewerKey = props.circuitJson ? JSON.stringify(props.circuitJson) : void 0;
@@ -19952,7 +20038,7 @@ var CadViewer = (props) => {
19952
20038
  {
19953
20039
  ref: containerRef,
19954
20040
  style: { width: "100%", height: "100%", position: "relative" },
19955
- onContextMenu: handleContextMenu,
20041
+ ...contextMenuEventHandlers,
19956
20042
  children: [
19957
20043
  engine === "jscad" ? /* @__PURE__ */ jsx12(CadViewerJscad, { ...props }) : /* @__PURE__ */ jsx12(CadViewerManifold_default, { ...props }),
19958
20044
  /* @__PURE__ */ jsxs9(
@@ -19970,11 +20056,6 @@ var CadViewer = (props) => {
19970
20056
  opacity: 0.7,
19971
20057
  userSelect: "none"
19972
20058
  },
19973
- onClick: () => {
19974
- if ("ontouchstart" in window) {
19975
- setEngine(engine === "jscad" ? "manifold" : "jscad");
19976
- }
19977
- },
19978
20059
  children: [
19979
20060
  "Engine: ",
19980
20061
  /* @__PURE__ */ jsx12("b", { children: engine === "jscad" ? "JSCAD" : "Manifold" })
@@ -20308,7 +20389,7 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
20308
20389
  }
20309
20390
 
20310
20391
  // src/hooks/exporter/gltf.ts
20311
- import { useEffect as useEffect8, useState as useState10, useMemo as useMemo8, useCallback as useCallback5 } from "react";
20392
+ import { useEffect as useEffect9, useState as useState11, useMemo as useMemo8, useCallback as useCallback6 } from "react";
20312
20393
  function useSaveGltfAs(options = {}) {
20313
20394
  const parse = useParser(options);
20314
20395
  const link = useMemo8(() => document.createElement("a"), []);
@@ -20321,7 +20402,7 @@ function useSaveGltfAs(options = {}) {
20321
20402
  link.dispatchEvent(new MouseEvent("click"));
20322
20403
  URL.revokeObjectURL(url);
20323
20404
  };
20324
- useEffect8(
20405
+ useEffect9(
20325
20406
  () => () => {
20326
20407
  link.remove();
20327
20408
  instance = null;
@@ -20329,20 +20410,20 @@ function useSaveGltfAs(options = {}) {
20329
20410
  []
20330
20411
  );
20331
20412
  let instance;
20332
- const ref = useCallback5((obj3D) => {
20413
+ const ref = useCallback6((obj3D) => {
20333
20414
  instance = obj3D;
20334
20415
  }, []);
20335
20416
  return [ref, saveAs];
20336
20417
  }
20337
20418
  function useExportGltfUrl(options = {}) {
20338
20419
  const parse = useParser(options);
20339
- const [url, setUrl] = useState10();
20340
- const [error, setError] = useState10();
20341
- const ref = useCallback5(
20420
+ const [url, setUrl] = useState11();
20421
+ const [error, setError] = useState11();
20422
+ const ref = useCallback6(
20342
20423
  (instance) => parse(instance).then(setUrl).catch(setError),
20343
20424
  []
20344
20425
  );
20345
- useEffect8(() => () => URL.revokeObjectURL(url), [url]);
20426
+ useEffect9(() => () => URL.revokeObjectURL(url), [url]);
20346
20427
  return [ref, url, error];
20347
20428
  }
20348
20429
  function useParser(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.233",
3
+ "version": "0.0.234",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",