@tscircuit/3d-viewer 0.0.641 → 0.0.643
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -1
- package/dist/index.js +139 -98
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -60,7 +60,10 @@ type CadViewerProps = Omit<React.ComponentProps<typeof CadViewerJscad>, "circuit
|
|
|
60
60
|
circuitJson?: any[];
|
|
61
61
|
/** Settled circuit retaining authored assembly.explosion stages. */
|
|
62
62
|
circuit?: RootCircuit;
|
|
63
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Pre-rendered circuit-json-to-gltf GLB URL. Bypasses geometry/model generation.
|
|
65
|
+
* Changing the GLB preserves the camera. Change the viewer key to frame a different board.
|
|
66
|
+
*/
|
|
64
67
|
glbUrl?: string;
|
|
65
68
|
/** In-memory alternative to glbUrl. Supply only one GLB source. */
|
|
66
69
|
glbData?: ArrayBuffer;
|
package/dist/index.js
CHANGED
|
@@ -19115,7 +19115,8 @@ function getGlbComponentMetadata(object) {
|
|
|
19115
19115
|
"cad_component_id",
|
|
19116
19116
|
"source_component_id",
|
|
19117
19117
|
"pcb_component_id",
|
|
19118
|
-
"componentName"
|
|
19118
|
+
"componentName",
|
|
19119
|
+
"pcb_board_id"
|
|
19119
19120
|
]) {
|
|
19120
19121
|
if (typeof metadata[key] === "string") result[key] = metadata[key];
|
|
19121
19122
|
}
|
|
@@ -22344,7 +22345,7 @@ import * as THREE31 from "three";
|
|
|
22344
22345
|
// package.json
|
|
22345
22346
|
var package_default = {
|
|
22346
22347
|
name: "@tscircuit/3d-viewer",
|
|
22347
|
-
version: "0.0.
|
|
22348
|
+
version: "0.0.642",
|
|
22348
22349
|
repository: {
|
|
22349
22350
|
type: "git",
|
|
22350
22351
|
url: "https://github.com/tscircuit/3d-viewer"
|
|
@@ -32042,33 +32043,51 @@ var CadViewerManifold = ({
|
|
|
32042
32043
|
var CadViewerManifold_default = CadViewerManifold;
|
|
32043
32044
|
|
|
32044
32045
|
// src/CadViewerGlb.tsx
|
|
32045
|
-
import {
|
|
32046
|
+
import {
|
|
32047
|
+
useEffect as useEffect37,
|
|
32048
|
+
useLayoutEffect as useLayoutEffect2,
|
|
32049
|
+
useState as useState23
|
|
32050
|
+
} from "react";
|
|
32046
32051
|
|
|
32047
32052
|
// src/hooks/useGlbModel.ts
|
|
32048
|
-
import { useEffect as useEffect36, useMemo as useMemo30, useState as useState22 } from "react";
|
|
32053
|
+
import { useEffect as useEffect36, useLayoutEffect, useMemo as useMemo30, useState as useState22 } from "react";
|
|
32049
32054
|
function useGlbModel(source) {
|
|
32050
32055
|
const request = useMemo30(() => ({ source }), [source]);
|
|
32051
32056
|
const [result, setResult] = useState22();
|
|
32057
|
+
const displayedGlb = result?.loadedGlb;
|
|
32052
32058
|
useEffect36(() => {
|
|
32053
32059
|
const controller = new AbortController();
|
|
32054
|
-
let
|
|
32055
|
-
loadGlbScene(request.source, controller.signal).then((
|
|
32056
|
-
|
|
32057
|
-
|
|
32058
|
-
|
|
32060
|
+
let loadedGlb;
|
|
32061
|
+
loadGlbScene(request.source, controller.signal).then((model) => {
|
|
32062
|
+
if (controller.signal.aborted) {
|
|
32063
|
+
disposeGlbScene(model);
|
|
32064
|
+
return;
|
|
32065
|
+
}
|
|
32066
|
+
loadedGlb = { model, wasDisplayed: false };
|
|
32067
|
+
setResult({ request, loadedGlb });
|
|
32059
32068
|
}).catch((error) => {
|
|
32060
|
-
if (
|
|
32061
|
-
|
|
32062
|
-
|
|
32063
|
-
|
|
32064
|
-
|
|
32069
|
+
if (controller.signal.aborted) return;
|
|
32070
|
+
setResult((previous) => ({
|
|
32071
|
+
request,
|
|
32072
|
+
loadedGlb: previous?.loadedGlb,
|
|
32073
|
+
error: error instanceof Error ? error.message : String(error)
|
|
32074
|
+
}));
|
|
32065
32075
|
});
|
|
32066
32076
|
return () => {
|
|
32067
32077
|
controller.abort();
|
|
32068
|
-
if (
|
|
32078
|
+
if (loadedGlb && !loadedGlb.wasDisplayed) disposeGlbScene(loadedGlb.model);
|
|
32069
32079
|
};
|
|
32070
32080
|
}, [request]);
|
|
32071
|
-
|
|
32081
|
+
useLayoutEffect(() => {
|
|
32082
|
+
if (!displayedGlb) return;
|
|
32083
|
+
displayedGlb.wasDisplayed = true;
|
|
32084
|
+
return () => disposeGlbScene(displayedGlb.model);
|
|
32085
|
+
}, [displayedGlb]);
|
|
32086
|
+
return {
|
|
32087
|
+
model: displayedGlb?.model,
|
|
32088
|
+
isLoading: result?.request !== request,
|
|
32089
|
+
error: result?.request === request ? result.error : void 0
|
|
32090
|
+
};
|
|
32072
32091
|
}
|
|
32073
32092
|
|
|
32074
32093
|
// src/CadViewerGlb.tsx
|
|
@@ -32081,19 +32100,7 @@ function GlbScene({
|
|
|
32081
32100
|
const { rootObject } = useThree();
|
|
32082
32101
|
const { addHoverable, removeHoverable } = useHover();
|
|
32083
32102
|
const [hover, setHover] = useState23();
|
|
32084
|
-
|
|
32085
|
-
const box = new THREE62.Box3().setFromObject(model);
|
|
32086
|
-
if (box.isEmpty()) return;
|
|
32087
|
-
return {
|
|
32088
|
-
minX: box.min.x,
|
|
32089
|
-
maxX: box.max.x,
|
|
32090
|
-
minY: box.min.y,
|
|
32091
|
-
maxY: box.max.y,
|
|
32092
|
-
minZ: box.min.z,
|
|
32093
|
-
maxZ: box.max.z
|
|
32094
|
-
};
|
|
32095
|
-
}, [model]);
|
|
32096
|
-
useEffect37(() => {
|
|
32103
|
+
useLayoutEffect2(() => {
|
|
32097
32104
|
rootObject.add(model);
|
|
32098
32105
|
return () => {
|
|
32099
32106
|
rootObject.remove(model);
|
|
@@ -32101,14 +32108,14 @@ function GlbScene({
|
|
|
32101
32108
|
}, [rootObject, model]);
|
|
32102
32109
|
useEffect37(() => {
|
|
32103
32110
|
setHover(void 0);
|
|
32104
|
-
const applyVisibility = (object,
|
|
32105
|
-
const id = object.userData.cad_component_id;
|
|
32111
|
+
const applyVisibility = (object, inObject) => {
|
|
32112
|
+
const id = object.userData.cad_component_id ?? object.userData.pcb_board_id;
|
|
32106
32113
|
if (typeof id === "string")
|
|
32107
32114
|
object.visible = !isObjectHidden(objectVisibility, id);
|
|
32108
|
-
else if (!
|
|
32115
|
+
else if (!inObject && object instanceof THREE62.Mesh)
|
|
32109
32116
|
object.visible = !isObjectHidden(objectVisibility, void 0);
|
|
32110
32117
|
for (const child of object.children)
|
|
32111
|
-
applyVisibility(child,
|
|
32118
|
+
applyVisibility(child, inObject || typeof id === "string");
|
|
32112
32119
|
};
|
|
32113
32120
|
applyVisibility(model, false);
|
|
32114
32121
|
}, [model, objectVisibility]);
|
|
@@ -32144,54 +32151,88 @@ function GlbScene({
|
|
|
32144
32151
|
for (const mesh of meshes) removeHoverable(mesh);
|
|
32145
32152
|
};
|
|
32146
32153
|
}, [model, objectVisibility, addHoverable, removeHoverable]);
|
|
32154
|
+
return /* @__PURE__ */ jsx24(Fragment5, { children: hover && /* @__PURE__ */ jsx24(
|
|
32155
|
+
Html,
|
|
32156
|
+
{
|
|
32157
|
+
position: hover.position,
|
|
32158
|
+
style: {
|
|
32159
|
+
background: "white",
|
|
32160
|
+
color: "black",
|
|
32161
|
+
padding: "5px",
|
|
32162
|
+
borderRadius: "3px",
|
|
32163
|
+
fontFamily: "sans-serif",
|
|
32164
|
+
transform: "translate(1rem, 1rem)"
|
|
32165
|
+
},
|
|
32166
|
+
children: hover.name
|
|
32167
|
+
}
|
|
32168
|
+
) });
|
|
32169
|
+
}
|
|
32170
|
+
function CadViewerGlb({
|
|
32171
|
+
source,
|
|
32172
|
+
objectVisibility,
|
|
32173
|
+
...containerProps
|
|
32174
|
+
}) {
|
|
32175
|
+
const { model, isLoading, error } = useGlbModel(source);
|
|
32176
|
+
const message = error ? `Unable to load 3D view: ${error}` : "Loading 3D view...";
|
|
32177
|
+
const role = error ? "alert" : "status";
|
|
32178
|
+
if (!model) return /* @__PURE__ */ jsx24("div", { role, children: message });
|
|
32147
32179
|
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
32148
|
-
|
|
32149
|
-
|
|
32150
|
-
Html,
|
|
32180
|
+
/* @__PURE__ */ jsx24(
|
|
32181
|
+
GlbViewport,
|
|
32151
32182
|
{
|
|
32152
|
-
|
|
32153
|
-
|
|
32154
|
-
|
|
32155
|
-
color: "black",
|
|
32156
|
-
padding: "5px",
|
|
32157
|
-
borderRadius: "3px",
|
|
32158
|
-
fontFamily: "sans-serif",
|
|
32159
|
-
transform: "translate(1rem, 1rem)"
|
|
32160
|
-
},
|
|
32161
|
-
children: hover.name
|
|
32183
|
+
model,
|
|
32184
|
+
objectVisibility,
|
|
32185
|
+
...containerProps
|
|
32162
32186
|
}
|
|
32163
|
-
)
|
|
32187
|
+
),
|
|
32188
|
+
(isLoading || error) && /* @__PURE__ */ jsx24("div", { role, style: { position: "absolute", top: 12, left: 12 }, children: message })
|
|
32164
32189
|
] });
|
|
32165
32190
|
}
|
|
32166
|
-
function
|
|
32167
|
-
|
|
32191
|
+
function GlbViewport({
|
|
32192
|
+
model,
|
|
32168
32193
|
objectVisibility,
|
|
32169
32194
|
...containerProps
|
|
32170
32195
|
}) {
|
|
32171
|
-
const
|
|
32172
|
-
|
|
32173
|
-
if (
|
|
32174
|
-
const
|
|
32175
|
-
if (
|
|
32176
|
-
|
|
32177
|
-
|
|
32178
|
-
|
|
32179
|
-
|
|
32180
|
-
|
|
32181
|
-
|
|
32182
|
-
|
|
32183
|
-
|
|
32184
|
-
|
|
32185
|
-
|
|
32186
|
-
|
|
32187
|
-
|
|
32188
|
-
|
|
32189
|
-
|
|
32190
|
-
|
|
32191
|
-
|
|
32192
|
-
|
|
32193
|
-
|
|
32194
|
-
|
|
32196
|
+
const [framing, setFraming] = useState23(() => getGlbFraming(model));
|
|
32197
|
+
useEffect37(() => {
|
|
32198
|
+
if (framing) return;
|
|
32199
|
+
const nextFraming = getGlbFraming(model);
|
|
32200
|
+
if (nextFraming) setFraming(nextFraming);
|
|
32201
|
+
}, [framing, model]);
|
|
32202
|
+
return /* @__PURE__ */ jsxs8(
|
|
32203
|
+
CadViewerContainer,
|
|
32204
|
+
{
|
|
32205
|
+
...containerProps,
|
|
32206
|
+
boardDimensions: framing?.boardDimensions,
|
|
32207
|
+
boardCenter: framing?.boardCenter,
|
|
32208
|
+
children: [
|
|
32209
|
+
framing && /* @__PURE__ */ jsx24(FitCameraToComparison, { bounds: framing.bounds }),
|
|
32210
|
+
/* @__PURE__ */ jsx24(GlbScene, { model, objectVisibility })
|
|
32211
|
+
]
|
|
32212
|
+
}
|
|
32213
|
+
);
|
|
32214
|
+
}
|
|
32215
|
+
function getGlbFraming(model) {
|
|
32216
|
+
const box = new THREE62.Box3().setFromObject(model);
|
|
32217
|
+
if (box.isEmpty()) return void 0;
|
|
32218
|
+
return {
|
|
32219
|
+
bounds: {
|
|
32220
|
+
minX: box.min.x,
|
|
32221
|
+
maxX: box.max.x,
|
|
32222
|
+
minY: box.min.y,
|
|
32223
|
+
maxY: box.max.y,
|
|
32224
|
+
minZ: box.min.z,
|
|
32225
|
+
maxZ: box.max.z
|
|
32226
|
+
},
|
|
32227
|
+
boardDimensions: {
|
|
32228
|
+
width: box.max.x - box.min.x,
|
|
32229
|
+
height: box.max.y - box.min.y
|
|
32230
|
+
},
|
|
32231
|
+
boardCenter: {
|
|
32232
|
+
x: (box.min.x + box.max.x) / 2,
|
|
32233
|
+
y: (box.min.y + box.max.y) / 2
|
|
32234
|
+
}
|
|
32235
|
+
};
|
|
32195
32236
|
}
|
|
32196
32237
|
|
|
32197
32238
|
// node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs
|
|
@@ -32392,7 +32433,7 @@ var IS_DEVELOPMENT = false;
|
|
|
32392
32433
|
|
|
32393
32434
|
// node_modules/@radix-ui/react-use-layout-effect/dist/index.mjs
|
|
32394
32435
|
import * as React13 from "react";
|
|
32395
|
-
var
|
|
32436
|
+
var useLayoutEffect22 = globalThis?.document ? React13.useLayoutEffect : () => {
|
|
32396
32437
|
};
|
|
32397
32438
|
|
|
32398
32439
|
// node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
|
|
@@ -32416,7 +32457,7 @@ function useEffectEvent(callback) {
|
|
|
32416
32457
|
ref.current = callback;
|
|
32417
32458
|
});
|
|
32418
32459
|
} else {
|
|
32419
|
-
|
|
32460
|
+
useLayoutEffect22(() => {
|
|
32420
32461
|
ref.current = callback;
|
|
32421
32462
|
});
|
|
32422
32463
|
}
|
|
@@ -32427,7 +32468,7 @@ __name4(useEffectEvent, "useEffectEvent");
|
|
|
32427
32468
|
// node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
|
|
32428
32469
|
var __defProp6 = Object.defineProperty;
|
|
32429
32470
|
var __name5 = (target, value) => __defProp6(target, "name", { value, configurable: true });
|
|
32430
|
-
var useInsertionEffect = React15[" useInsertionEffect ".trim().toString()] ||
|
|
32471
|
+
var useInsertionEffect = React15[" useInsertionEffect ".trim().toString()] || useLayoutEffect22;
|
|
32431
32472
|
function useControllableState({
|
|
32432
32473
|
prop,
|
|
32433
32474
|
defaultProp,
|
|
@@ -33267,7 +33308,7 @@ function createCollection2(name) {
|
|
|
33267
33308
|
[registryRef]
|
|
33268
33309
|
);
|
|
33269
33310
|
const composedRefs = useComposedRefs(forwardedRef, registerElement, ref);
|
|
33270
|
-
|
|
33311
|
+
useLayoutEffect22(() => {
|
|
33271
33312
|
const node = ref.current;
|
|
33272
33313
|
const registry = registryRef.current;
|
|
33273
33314
|
if (node && registry.has(node)) {
|
|
@@ -33420,7 +33461,7 @@ function useCallbackRef(callback) {
|
|
|
33420
33461
|
callbackRef.current = callback;
|
|
33421
33462
|
});
|
|
33422
33463
|
} else {
|
|
33423
|
-
|
|
33464
|
+
useLayoutEffect22(() => {
|
|
33424
33465
|
callbackRef.current = callback;
|
|
33425
33466
|
});
|
|
33426
33467
|
}
|
|
@@ -34089,7 +34130,7 @@ var useReactId = React26[" useId ".trim().toString()] || (() => void 0);
|
|
|
34089
34130
|
var count2 = 0;
|
|
34090
34131
|
function useId2(deterministicId) {
|
|
34091
34132
|
const [id, setId] = React26.useState(useReactId());
|
|
34092
|
-
|
|
34133
|
+
useLayoutEffect22(() => {
|
|
34093
34134
|
if (!deterministicId) setId((reactId) => reactId ?? String(count2++));
|
|
34094
34135
|
}, [deterministicId]);
|
|
34095
34136
|
return deterministicId || (id ? `radix-${id}` : "");
|
|
@@ -35693,12 +35734,12 @@ var computePosition2 = (reference, floating, options) => {
|
|
|
35693
35734
|
|
|
35694
35735
|
// node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.mjs
|
|
35695
35736
|
import * as React27 from "react";
|
|
35696
|
-
import { useLayoutEffect as
|
|
35737
|
+
import { useLayoutEffect as useLayoutEffect4 } from "react";
|
|
35697
35738
|
import * as ReactDOM3 from "react-dom";
|
|
35698
35739
|
var isClient = typeof document !== "undefined";
|
|
35699
35740
|
var noop = function noop2() {
|
|
35700
35741
|
};
|
|
35701
|
-
var index = isClient ?
|
|
35742
|
+
var index = isClient ? useLayoutEffect4 : noop;
|
|
35702
35743
|
function deepEqual(a, b) {
|
|
35703
35744
|
if (a === b) {
|
|
35704
35745
|
return true;
|
|
@@ -36008,7 +36049,7 @@ var __defProp16 = Object.defineProperty;
|
|
|
36008
36049
|
var __name15 = (target, value) => __defProp16(target, "name", { value, configurable: true });
|
|
36009
36050
|
function useSize(element) {
|
|
36010
36051
|
const [size4, setSize] = React28.useState(void 0);
|
|
36011
|
-
|
|
36052
|
+
useLayoutEffect22(() => {
|
|
36012
36053
|
if (element) {
|
|
36013
36054
|
setSize({ width: element.offsetWidth, height: element.offsetHeight });
|
|
36014
36055
|
let rAF = 0;
|
|
@@ -36215,7 +36256,7 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
|
|
|
36215
36256
|
]
|
|
36216
36257
|
});
|
|
36217
36258
|
const setPlacementState = context.setPlacementState;
|
|
36218
|
-
|
|
36259
|
+
useLayoutEffect22(() => {
|
|
36219
36260
|
setPlacementState(placement);
|
|
36220
36261
|
return () => {
|
|
36221
36262
|
setPlacementState(void 0);
|
|
@@ -36223,7 +36264,7 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
|
|
|
36223
36264
|
}, [placement, setPlacementState]);
|
|
36224
36265
|
const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);
|
|
36225
36266
|
const handlePlaced = useCallbackRef(onPlaced);
|
|
36226
|
-
|
|
36267
|
+
useLayoutEffect22(() => {
|
|
36227
36268
|
if (isPositioned) {
|
|
36228
36269
|
handlePlaced?.();
|
|
36229
36270
|
}
|
|
@@ -36232,7 +36273,7 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
|
|
|
36232
36273
|
const arrowY = middlewareData.arrow?.y;
|
|
36233
36274
|
const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;
|
|
36234
36275
|
const [contentZIndex, setContentZIndex] = React29.useState();
|
|
36235
|
-
|
|
36276
|
+
useLayoutEffect22(() => {
|
|
36236
36277
|
if (content) setContentZIndex(window.getComputedStyle(content).zIndex);
|
|
36237
36278
|
}, [content]);
|
|
36238
36279
|
return /* @__PURE__ */ jsx32(
|
|
@@ -36342,7 +36383,7 @@ var Portal = /* @__PURE__ */ React30.forwardRef(
|
|
|
36342
36383
|
/* @__PURE__ */ __name17(function Portal2(props, forwardedRef) {
|
|
36343
36384
|
const { container: containerProp, ...portalProps } = props;
|
|
36344
36385
|
const [mounted, setMounted] = React30.useState(false);
|
|
36345
|
-
|
|
36386
|
+
useLayoutEffect22(() => setMounted(true), []);
|
|
36346
36387
|
const container = containerProp || mounted && globalThis?.document?.body;
|
|
36347
36388
|
return container ? ReactDOM4.createPortal(/* @__PURE__ */ jsx33(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
|
|
36348
36389
|
}, "Portal")
|
|
@@ -36396,7 +36437,7 @@ function usePresence(present) {
|
|
|
36396
36437
|
prevAnimationNameRef.current = "none";
|
|
36397
36438
|
}
|
|
36398
36439
|
}, [state]);
|
|
36399
|
-
|
|
36440
|
+
useLayoutEffect22(() => {
|
|
36400
36441
|
const styles = stylesRef.current;
|
|
36401
36442
|
const wasPresent = prevPresentRef.current;
|
|
36402
36443
|
const hasPresentChanged = wasPresent !== present;
|
|
@@ -36419,7 +36460,7 @@ function usePresence(present) {
|
|
|
36419
36460
|
prevPresentRef.current = present;
|
|
36420
36461
|
}
|
|
36421
36462
|
}, [present, send]);
|
|
36422
|
-
|
|
36463
|
+
useLayoutEffect22(() => {
|
|
36423
36464
|
if (node) {
|
|
36424
36465
|
let timeoutId;
|
|
36425
36466
|
const ownerWindow = node.ownerDocument.defaultView ?? window;
|
|
@@ -36699,7 +36740,7 @@ var RovingFocusGroupItem = /* @__PURE__ */ React33.forwardRef(
|
|
|
36699
36740
|
const getItems = useCollection(__scopeRovingFocusGroup);
|
|
36700
36741
|
const { onFocusableItemAdd, onFocusableItemRemove, currentTabStopId } = context;
|
|
36701
36742
|
const isHydrated = useIsHydrated2();
|
|
36702
|
-
|
|
36743
|
+
useLayoutEffect22(() => {
|
|
36703
36744
|
if (!isHydrated || !focusable) {
|
|
36704
36745
|
return;
|
|
36705
36746
|
}
|
|
@@ -38593,12 +38634,12 @@ var DropdownMenuSubContent = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */
|
|
|
38593
38634
|
}, "DropdownMenuSubContent"));
|
|
38594
38635
|
|
|
38595
38636
|
// src/components/ViewportSubContent.tsx
|
|
38596
|
-
import { useLayoutEffect as
|
|
38637
|
+
import { useLayoutEffect as useLayoutEffect6, useState as useState40 } from "react";
|
|
38597
38638
|
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
38598
38639
|
var ViewportSubContent = (props) => {
|
|
38599
38640
|
const [content, setContent] = useState40(null);
|
|
38600
38641
|
const [overlapWidth, setOverlapWidth] = useState40();
|
|
38601
|
-
|
|
38642
|
+
useLayoutEffect6(() => {
|
|
38602
38643
|
if (!content) return;
|
|
38603
38644
|
const trigger = document.getElementById(
|
|
38604
38645
|
content.getAttribute("aria-labelledby") ?? ""
|
|
@@ -39741,10 +39782,10 @@ var ContextMenu = ({
|
|
|
39741
39782
|
};
|
|
39742
39783
|
|
|
39743
39784
|
// src/components/KeyboardShortcutsDialog.tsx
|
|
39744
|
-
import { useEffect as useEffect55, useMemo as
|
|
39785
|
+
import { useEffect as useEffect55, useMemo as useMemo40, useRef as useRef28, useState as useState44 } from "react";
|
|
39745
39786
|
|
|
39746
39787
|
// src/hooks/useRegisteredHotkey.ts
|
|
39747
|
-
import { useEffect as useEffect54, useMemo as
|
|
39788
|
+
import { useEffect as useEffect54, useMemo as useMemo39, useRef as useRef27, useState as useState43 } from "react";
|
|
39748
39789
|
var hotkeyRegistry = /* @__PURE__ */ new Map();
|
|
39749
39790
|
var subscribers = /* @__PURE__ */ new Set();
|
|
39750
39791
|
var isListenerAttached = false;
|
|
@@ -39868,7 +39909,7 @@ var subscribeToRegistry = (subscriber) => {
|
|
|
39868
39909
|
var useRegisteredHotkey = (id, handler, metadata) => {
|
|
39869
39910
|
const handlerRef = useRef27(handler);
|
|
39870
39911
|
handlerRef.current = handler;
|
|
39871
|
-
const normalizedMetadata =
|
|
39912
|
+
const normalizedMetadata = useMemo39(
|
|
39872
39913
|
() => ({
|
|
39873
39914
|
shortcut: metadata.shortcut,
|
|
39874
39915
|
description: metadata.description
|
|
@@ -39926,7 +39967,7 @@ var KeyboardShortcutsDialog = ({
|
|
|
39926
39967
|
}, 0);
|
|
39927
39968
|
}
|
|
39928
39969
|
}, [open]);
|
|
39929
|
-
const filteredHotkeys =
|
|
39970
|
+
const filteredHotkeys = useMemo40(() => {
|
|
39930
39971
|
const normalizedQuery = query.trim().toLowerCase();
|
|
39931
39972
|
if (!normalizedQuery) {
|
|
39932
39973
|
return hotkeys;
|
|
@@ -41153,10 +41194,10 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
41153
41194
|
import {
|
|
41154
41195
|
GLTFExporter as GLTFExporter3
|
|
41155
41196
|
} from "three/examples/jsm/exporters/GLTFExporter.js";
|
|
41156
|
-
import { useEffect as useEffect58, useState as useState47, useMemo as
|
|
41197
|
+
import { useEffect as useEffect58, useState as useState47, useMemo as useMemo41, useCallback as useCallback26 } from "react";
|
|
41157
41198
|
function useSaveGltfAs(options = {}) {
|
|
41158
41199
|
const parse2 = useParser(options);
|
|
41159
|
-
const link =
|
|
41200
|
+
const link = useMemo41(() => document.createElement("a"), []);
|
|
41160
41201
|
const saveAs = async (filename) => {
|
|
41161
41202
|
const name = filename ?? options.filename ?? "";
|
|
41162
41203
|
if (options.binary == null) options.binary = name.endsWith(".glb");
|
|
@@ -41191,7 +41232,7 @@ function useExportGltfUrl(options = {}) {
|
|
|
41191
41232
|
return [ref, url, error];
|
|
41192
41233
|
}
|
|
41193
41234
|
function useParser(options = {}) {
|
|
41194
|
-
const exporter =
|
|
41235
|
+
const exporter = useMemo41(() => new GLTFExporter3(), []);
|
|
41195
41236
|
return (instance) => {
|
|
41196
41237
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
41197
41238
|
exporter.parse(
|