@react-three/fiber 10.0.0-canary.ba354c7 → 10.0.0-canary.c385e9f
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.cjs +105 -53
- package/dist/index.d.cts +173 -24
- package/dist/index.d.mts +173 -24
- package/dist/index.d.ts +173 -24
- package/dist/index.mjs +105 -53
- package/dist/legacy.cjs +104 -57
- package/dist/legacy.d.cts +172 -27
- package/dist/legacy.d.mts +172 -27
- package/dist/legacy.d.ts +172 -27
- package/dist/legacy.mjs +104 -57
- package/dist/webgpu/index.cjs +168 -90
- package/dist/webgpu/index.d.cts +197 -88
- package/dist/webgpu/index.d.mts +197 -88
- package/dist/webgpu/index.d.ts +197 -88
- package/dist/webgpu/index.mjs +168 -90
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as webgpu from 'three/webgpu';
|
|
2
2
|
import { CubeRenderTarget, RenderTarget, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, ShaderMaterial, Uniform, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, Scene, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer, HalfFloatType, Color } from 'three/webgpu';
|
|
3
3
|
import { WebGLCubeRenderTarget, WebGLRenderTarget, WebGLRenderer } from 'three';
|
|
4
|
-
import { Inspector } from 'three/addons/inspector/Inspector.js';
|
|
5
4
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
6
5
|
import * as React from 'react';
|
|
7
6
|
import React__default, { useRef, useMemo, useLayoutEffect, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
|
|
@@ -32,18 +31,22 @@ function _mergeNamespaces(n, m) {
|
|
|
32
31
|
|
|
33
32
|
const R3F_BUILD_LEGACY = true;
|
|
34
33
|
const R3F_BUILD_WEBGPU = true;
|
|
34
|
+
async function loadInspector() {
|
|
35
|
+
const { Inspector } = await import('three/addons/inspector/Inspector.js');
|
|
36
|
+
return Inspector;
|
|
37
|
+
}
|
|
35
38
|
|
|
36
39
|
const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
37
40
|
__proto__: null,
|
|
38
41
|
CubeRenderTarget: CubeRenderTarget,
|
|
39
42
|
CubeRenderTargetCompat: CubeRenderTarget,
|
|
40
|
-
Inspector: Inspector,
|
|
41
43
|
R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
|
|
42
44
|
R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
|
|
43
45
|
RenderTargetCompat: RenderTarget,
|
|
44
46
|
WebGLCubeRenderTarget: WebGLCubeRenderTarget,
|
|
45
47
|
WebGLRenderTarget: WebGLRenderTarget,
|
|
46
|
-
WebGLRenderer: WebGLRenderer
|
|
48
|
+
WebGLRenderer: WebGLRenderer,
|
|
49
|
+
loadInspector: loadInspector
|
|
47
50
|
}, [webgpu]);
|
|
48
51
|
|
|
49
52
|
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
@@ -902,7 +905,7 @@ const createStore = (invalidate, advance) => {
|
|
|
902
905
|
size: newSize,
|
|
903
906
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
904
907
|
}));
|
|
905
|
-
|
|
908
|
+
get().invalidate();
|
|
906
909
|
}
|
|
907
910
|
}
|
|
908
911
|
return;
|
|
@@ -917,15 +920,16 @@ const createStore = (invalidate, advance) => {
|
|
|
917
920
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
918
921
|
_sizeImperative: true
|
|
919
922
|
}));
|
|
920
|
-
|
|
923
|
+
get().invalidate();
|
|
921
924
|
},
|
|
922
925
|
setDpr: (dpr) => set((state2) => {
|
|
923
926
|
const resolved = calculateDpr(dpr);
|
|
924
927
|
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
925
928
|
}),
|
|
926
929
|
setFrameloop: (frameloop = "always") => {
|
|
930
|
+
const rootId = get().internal.rootId;
|
|
931
|
+
if (rootId) getScheduler().setRootFrameloop(rootId, frameloop);
|
|
927
932
|
set(() => ({ frameloop }));
|
|
928
|
-
getScheduler().frameloop = frameloop;
|
|
929
933
|
},
|
|
930
934
|
setError: (error) => set(() => ({ error })),
|
|
931
935
|
error: null,
|
|
@@ -1041,17 +1045,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1041
1045
|
oldSize = size;
|
|
1042
1046
|
oldDpr = viewport.dpr;
|
|
1043
1047
|
updateCamera(camera, size);
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1049
|
-
actualRenderer.setSize(size.width, size.height, false);
|
|
1050
|
-
if (canvasTarget) {
|
|
1051
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1052
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1048
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
1049
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
1050
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
1051
|
+
internal.canvasTargetSizeDirty = true;
|
|
1055
1052
|
}
|
|
1056
1053
|
if (camera !== oldCamera) {
|
|
1057
1054
|
oldCamera = camera;
|
|
@@ -1113,7 +1110,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
|
1113
1110
|
const results = cacheKeys.map(
|
|
1114
1111
|
(key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
1115
1112
|
);
|
|
1116
|
-
|
|
1113
|
+
const stableRef = useRef(null);
|
|
1114
|
+
const previous = stableRef.current;
|
|
1115
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
1116
|
+
stableRef.current = stable;
|
|
1117
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
1117
1118
|
}
|
|
1118
1119
|
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
1119
1120
|
const inputs = Array.isArray(input) ? input : [input];
|
|
@@ -1233,6 +1234,13 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1233
1234
|
* Use for controlling the entire frame loop, adding phases, etc.
|
|
1234
1235
|
*/
|
|
1235
1236
|
scheduler: scheduler2,
|
|
1237
|
+
/**
|
|
1238
|
+
* The root that currently owns this job. Resolve on access because ambient
|
|
1239
|
+
* jobs can be adopted by a Canvas after the controls object is created.
|
|
1240
|
+
*/
|
|
1241
|
+
get rootId() {
|
|
1242
|
+
return getScheduler().getJobRootId(id);
|
|
1243
|
+
},
|
|
1236
1244
|
/**
|
|
1237
1245
|
* Manually step this job only.
|
|
1238
1246
|
* Bypasses FPS limiting - always runs.
|
|
@@ -1249,6 +1257,14 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1249
1257
|
stepAll: (timestamp) => {
|
|
1250
1258
|
getScheduler().step(timestamp);
|
|
1251
1259
|
},
|
|
1260
|
+
/**
|
|
1261
|
+
* Request frames for this job's owning root without waking sibling roots.
|
|
1262
|
+
*/
|
|
1263
|
+
invalidate: (frames, stackFrames) => {
|
|
1264
|
+
const scheduler3 = getScheduler();
|
|
1265
|
+
const rootId = scheduler3.getJobRootId(id);
|
|
1266
|
+
if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
|
|
1267
|
+
},
|
|
1252
1268
|
/**
|
|
1253
1269
|
* Pause this job (set enabled=false).
|
|
1254
1270
|
* Job remains registered but won't run.
|
|
@@ -1278,6 +1294,11 @@ function getUrls(input) {
|
|
|
1278
1294
|
if (Array.isArray(input)) return input;
|
|
1279
1295
|
return Object.values(input);
|
|
1280
1296
|
}
|
|
1297
|
+
function inputSignature(input) {
|
|
1298
|
+
if (typeof input === "string") return input;
|
|
1299
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
1300
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
1301
|
+
}
|
|
1281
1302
|
function allUrlsCached(urls, textureCache) {
|
|
1282
1303
|
return urls.every((url) => textureCache.has(url));
|
|
1283
1304
|
}
|
|
@@ -1303,18 +1324,19 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1303
1324
|
const onLoadRef = useRef(onLoad);
|
|
1304
1325
|
onLoadRef.current = onLoad;
|
|
1305
1326
|
const onLoadCalledForRef = useRef(null);
|
|
1306
|
-
const
|
|
1327
|
+
const inputKey = useMemo(() => inputSignature(input), [input]);
|
|
1328
|
+
const stableInput = useMemo(() => input, [inputKey]);
|
|
1329
|
+
const urls = useMemo(() => getUrls(stableInput), [stableInput]);
|
|
1307
1330
|
const cachedResult = useMemo(() => {
|
|
1308
1331
|
if (!cache) return null;
|
|
1309
1332
|
const textures = store.getState().textures;
|
|
1310
1333
|
if (!allUrlsCached(urls, textures)) return null;
|
|
1311
|
-
return buildFromCache(
|
|
1312
|
-
}, [cache, urls,
|
|
1334
|
+
return buildFromCache(stableInput, textures);
|
|
1335
|
+
}, [cache, urls, stableInput, store]);
|
|
1313
1336
|
const loadedTextures = useLoader(
|
|
1314
1337
|
TextureLoader,
|
|
1315
|
-
IsObject(
|
|
1338
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
1316
1339
|
);
|
|
1317
|
-
const inputKey = urls.join("\0");
|
|
1318
1340
|
useLayoutEffect(() => {
|
|
1319
1341
|
if (cachedResult) return;
|
|
1320
1342
|
if (onLoadCalledForRef.current === inputKey) return;
|
|
@@ -1341,28 +1363,28 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1341
1363
|
}, [renderer, loadedTextures, cachedResult]);
|
|
1342
1364
|
const mappedTextures = useMemo(() => {
|
|
1343
1365
|
if (cachedResult) return cachedResult;
|
|
1344
|
-
if (IsObject(
|
|
1366
|
+
if (IsObject(stableInput)) {
|
|
1345
1367
|
const keyed = {};
|
|
1346
1368
|
const textureArray = loadedTextures;
|
|
1347
1369
|
let i = 0;
|
|
1348
|
-
for (const key in
|
|
1370
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
1349
1371
|
return keyed;
|
|
1350
1372
|
} else {
|
|
1351
1373
|
return loadedTextures;
|
|
1352
1374
|
}
|
|
1353
|
-
}, [
|
|
1375
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
1354
1376
|
useEffect(() => {
|
|
1355
1377
|
if (!cache) return;
|
|
1356
1378
|
const urlTextureMap = [];
|
|
1357
|
-
if (typeof
|
|
1358
|
-
urlTextureMap.push([
|
|
1359
|
-
} else if (Array.isArray(
|
|
1379
|
+
if (typeof stableInput === "string") {
|
|
1380
|
+
urlTextureMap.push([stableInput, mappedTextures]);
|
|
1381
|
+
} else if (Array.isArray(stableInput)) {
|
|
1360
1382
|
const textureArray = mappedTextures;
|
|
1361
|
-
|
|
1362
|
-
} else if (IsObject(
|
|
1383
|
+
stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1384
|
+
} else if (IsObject(stableInput)) {
|
|
1363
1385
|
const textureRecord = mappedTextures;
|
|
1364
|
-
for (const key in
|
|
1365
|
-
const url =
|
|
1386
|
+
for (const key in stableInput) {
|
|
1387
|
+
const url = stableInput[key];
|
|
1366
1388
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
1367
1389
|
}
|
|
1368
1390
|
}
|
|
@@ -1391,7 +1413,7 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1391
1413
|
}
|
|
1392
1414
|
return { _textureRefs: refs };
|
|
1393
1415
|
});
|
|
1394
|
-
}, [cache,
|
|
1416
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
1395
1417
|
return mappedTextures;
|
|
1396
1418
|
}
|
|
1397
1419
|
useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
|
|
@@ -1662,13 +1684,19 @@ function addTail(callback) {
|
|
|
1662
1684
|
return getScheduler().onIdle(callback);
|
|
1663
1685
|
}
|
|
1664
1686
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
1665
|
-
|
|
1687
|
+
const rootId = state?.internal?.rootId;
|
|
1688
|
+
const scheduler = getScheduler();
|
|
1689
|
+
if (rootId) scheduler.invalidateRoot(rootId, frames, stackFrames);
|
|
1690
|
+
else scheduler.invalidate(frames, stackFrames);
|
|
1666
1691
|
}
|
|
1667
|
-
function advance(timestamp) {
|
|
1668
|
-
|
|
1692
|
+
function advance(timestamp, runGlobalEffects, state) {
|
|
1693
|
+
const rootId = state?.internal?.rootId;
|
|
1694
|
+
const scheduler = getScheduler();
|
|
1695
|
+
if (rootId) scheduler.stepRoot(rootId, timestamp);
|
|
1696
|
+
else scheduler.step(timestamp);
|
|
1669
1697
|
}
|
|
1670
1698
|
|
|
1671
|
-
const version = "10.0.0-alpha.
|
|
1699
|
+
const version = "10.0.0-alpha.4";
|
|
1672
1700
|
const packageData = {
|
|
1673
1701
|
version: version};
|
|
1674
1702
|
|
|
@@ -14327,7 +14355,7 @@ function createRoot(canvas) {
|
|
|
14327
14355
|
const handleXRFrame = (timestamp, _frame) => {
|
|
14328
14356
|
const state2 = store.getState();
|
|
14329
14357
|
if (state2.frameloop === "never") return;
|
|
14330
|
-
advance(timestamp);
|
|
14358
|
+
advance(timestamp, true, state2);
|
|
14331
14359
|
};
|
|
14332
14360
|
const actualRenderer = state.internal.actualRenderer;
|
|
14333
14361
|
const handleSessionChange = () => {
|
|
@@ -14335,7 +14363,7 @@ function createRoot(canvas) {
|
|
|
14335
14363
|
const renderer2 = state2.internal.actualRenderer;
|
|
14336
14364
|
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
14337
14365
|
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
14338
|
-
if (!renderer2.xr.isPresenting) invalidate();
|
|
14366
|
+
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
14339
14367
|
};
|
|
14340
14368
|
const xr = {
|
|
14341
14369
|
connect() {
|
|
@@ -14417,7 +14445,11 @@ function createRoot(canvas) {
|
|
|
14417
14445
|
const newRootId = canvasId || scheduler.generateRootId();
|
|
14418
14446
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14419
14447
|
getState: () => store.getState(),
|
|
14420
|
-
onError: (err) => store.getState().setError(err)
|
|
14448
|
+
onError: (err) => store.getState().setError(err),
|
|
14449
|
+
frameloop: store.getState().frameloop,
|
|
14450
|
+
before: schedulerConfig?.before,
|
|
14451
|
+
after: schedulerConfig?.after,
|
|
14452
|
+
order: schedulerConfig?.order
|
|
14421
14453
|
});
|
|
14422
14454
|
const unregisterCanvasTarget = scheduler.register(
|
|
14423
14455
|
() => {
|
|
@@ -14425,6 +14457,10 @@ function createRoot(canvas) {
|
|
|
14425
14457
|
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
14426
14458
|
const renderer2 = state2.internal.actualRenderer;
|
|
14427
14459
|
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
14460
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
14461
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
14462
|
+
renderer2.backend?.updateSize?.();
|
|
14463
|
+
}
|
|
14428
14464
|
}
|
|
14429
14465
|
},
|
|
14430
14466
|
{
|
|
@@ -14493,8 +14529,7 @@ function createRoot(canvas) {
|
|
|
14493
14529
|
phase: "render",
|
|
14494
14530
|
system: true,
|
|
14495
14531
|
// Internal flag: this is a system job, not user-controlled
|
|
14496
|
-
//
|
|
14497
|
-
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
14532
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
14498
14533
|
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14499
14534
|
}
|
|
14500
14535
|
);
|
|
@@ -14513,8 +14548,21 @@ function createRoot(canvas) {
|
|
|
14513
14548
|
scheduler
|
|
14514
14549
|
}
|
|
14515
14550
|
}));
|
|
14551
|
+
} else {
|
|
14552
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
|
|
14553
|
+
if (constraintsChanged) {
|
|
14554
|
+
scheduler.setRootConstraints(rootId, {
|
|
14555
|
+
before: schedulerConfig?.before,
|
|
14556
|
+
after: schedulerConfig?.after
|
|
14557
|
+
});
|
|
14558
|
+
}
|
|
14559
|
+
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
14560
|
+
scheduler.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
14561
|
+
}
|
|
14516
14562
|
}
|
|
14517
|
-
|
|
14563
|
+
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
14564
|
+
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
14565
|
+
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
14518
14566
|
onCreated = onCreatedCallback;
|
|
14519
14567
|
configured = true;
|
|
14520
14568
|
resolve();
|
|
@@ -14556,14 +14604,19 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14556
14604
|
const fiber = root?.fiber;
|
|
14557
14605
|
if (fiber) {
|
|
14558
14606
|
const state = root?.store.getState();
|
|
14559
|
-
if (state)
|
|
14607
|
+
if (state) {
|
|
14608
|
+
state.internal.active = false;
|
|
14609
|
+
const unregisterRoot = state.internal.unregisterRoot;
|
|
14610
|
+
if (unregisterRoot) {
|
|
14611
|
+
unregisterRoot();
|
|
14612
|
+
state.internal.unregisterRoot = void 0;
|
|
14613
|
+
}
|
|
14614
|
+
}
|
|
14560
14615
|
reconciler.updateContainer(null, fiber, null, () => {
|
|
14561
14616
|
if (state) {
|
|
14562
14617
|
setTimeout(() => {
|
|
14563
14618
|
try {
|
|
14564
14619
|
const renderer = state.internal.actualRenderer;
|
|
14565
|
-
const unregisterRoot = state.internal.unregisterRoot;
|
|
14566
|
-
if (unregisterRoot) unregisterRoot();
|
|
14567
14620
|
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
14568
14621
|
if (unregisterPrimary) unregisterPrimary();
|
|
14569
14622
|
const canvasTarget = state.internal.canvasTarget;
|
|
@@ -15011,9 +15064,9 @@ function CanvasImpl({
|
|
|
15011
15064
|
React.useMemo(() => extend(THREE), []);
|
|
15012
15065
|
const Bridge = useBridge();
|
|
15013
15066
|
const backgroundProps = React.useMemo(() => parseBackground(background), [background]);
|
|
15014
|
-
const
|
|
15067
|
+
const [hasInitialSize, setHasInitialSize] = React.useState(false);
|
|
15015
15068
|
const measureConfig = React.useMemo(() => {
|
|
15016
|
-
if (!
|
|
15069
|
+
if (!hasInitialSize) {
|
|
15017
15070
|
return {
|
|
15018
15071
|
...resize,
|
|
15019
15072
|
scroll: resize?.scroll ?? true,
|
|
@@ -15025,7 +15078,7 @@ function CanvasImpl({
|
|
|
15025
15078
|
debounce: { scroll: 50, resize: 0 },
|
|
15026
15079
|
...resize
|
|
15027
15080
|
};
|
|
15028
|
-
}, [
|
|
15081
|
+
}, [hasInitialSize, resize]);
|
|
15029
15082
|
const [containerRef, containerRect] = useMeasure(measureConfig);
|
|
15030
15083
|
const effectiveSize = React.useMemo(() => {
|
|
15031
15084
|
let w = width ?? containerRect.width;
|
|
@@ -15041,9 +15094,7 @@ function CanvasImpl({
|
|
|
15041
15094
|
left: containerRect.left
|
|
15042
15095
|
};
|
|
15043
15096
|
}, [width, height, containerRect, forceEven]);
|
|
15044
|
-
if (!
|
|
15045
|
-
hasInitialSizeRef.current = true;
|
|
15046
|
-
}
|
|
15097
|
+
if (!hasInitialSize && effectiveSize.width > 0 && effectiveSize.height > 0) setHasInitialSize(true);
|
|
15047
15098
|
const canvasRef = React.useRef(null);
|
|
15048
15099
|
const divRef = React.useRef(null);
|
|
15049
15100
|
React.useImperativeHandle(ref, () => canvasRef.current);
|
|
@@ -15157,6 +15208,7 @@ function CanvasImpl({
|
|
|
15157
15208
|
const canvas = canvasRef.current;
|
|
15158
15209
|
if (canvas) {
|
|
15159
15210
|
return () => {
|
|
15211
|
+
if (canvas.isConnected) return;
|
|
15160
15212
|
unmountComponentAtNode(canvas);
|
|
15161
15213
|
root.current = null;
|
|
15162
15214
|
};
|