@react-three/fiber 10.0.0-canary.98da52a → 10.0.0-canary.a1c1d93

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 (32) hide show
  1. package/dist/extension.d.cts +3 -3
  2. package/dist/extension.d.mts +3 -3
  3. package/dist/extension.d.ts +3 -3
  4. package/dist/extension.mjs +1 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.d.cts +5 -5
  7. package/dist/index.d.mts +5 -5
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.mjs +3 -3
  10. package/dist/legacy.cjs +1 -1
  11. package/dist/legacy.d.cts +4 -4
  12. package/dist/legacy.d.mts +4 -4
  13. package/dist/legacy.d.ts +4 -4
  14. package/dist/legacy.mjs +4 -4
  15. package/dist/shared/{fiber.DAl4H27x.d.cts → fiber.-1JhXWEC.d.cts} +1 -1
  16. package/dist/shared/{fiber.DNehrxK5.d.ts → fiber.Bkpap4yF.d.mts} +76 -1
  17. package/dist/shared/{fiber.TWXdbcWP.d.mts → fiber.BnIfHyTk.d.cts} +76 -1
  18. package/dist/shared/{fiber.I5Q4dVvl.d.cts → fiber.CLTHZhZp.d.cts} +30 -2
  19. package/dist/shared/{fiber.I5Q4dVvl.d.mts → fiber.CLTHZhZp.d.mts} +30 -2
  20. package/dist/shared/{fiber.I5Q4dVvl.d.ts → fiber.CLTHZhZp.d.ts} +30 -2
  21. package/dist/shared/{fiber.Cx-UAmMb.d.ts → fiber.CTEAJNmg.d.ts} +1 -1
  22. package/dist/shared/{fiber.B0oukOFO.mjs → fiber.CUKAa7Rv.mjs} +1 -1
  23. package/dist/shared/{fiber.BU0vBHc9.d.mts → fiber.CksZuiOV.d.mts} +1 -1
  24. package/dist/shared/{fiber.CT-cCVjA.mjs → fiber.Dl_2kSXg.mjs} +284 -88
  25. package/dist/shared/{fiber.11sXr8Eb.d.cts → fiber.NwhGYEh-.d.ts} +76 -1
  26. package/dist/shared/{fiber.Cn-vxHMl.cjs → fiber.nPYZB2AE.cjs} +284 -88
  27. package/dist/webgpu/index.cjs +1 -1
  28. package/dist/webgpu/index.d.cts +4 -4
  29. package/dist/webgpu/index.d.mts +4 -4
  30. package/dist/webgpu/index.d.ts +4 -4
  31. package/dist/webgpu/index.mjs +4 -4
  32. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { n as notifyDepreciated, a as useThree, u as useStore, h as unstageTextures, i as stageTextures, j as detachRootExtensions, k as attachRootExtensions, d as useIsomorphicLayoutEffect, e as useMutableCallback, c as context, b as useFrame, f as useBridge, l as notifyAlpha, E as ErrorBoundary, B as Block, m as notifyRootExtensionsHmr } from './fiber.B0oukOFO.mjs';
2
+ import { n as notifyDepreciated, a as useThree, u as useStore, h as unstageTextures, i as stageTextures, j as attachRootExtensions, k as detachRootExtensions, d as useIsomorphicLayoutEffect, e as useMutableCallback, c as context, b as useFrame, f as useBridge, l as notifyAlpha, E as ErrorBoundary, B as Block, m as notifyRootExtensionsHmr } from './fiber.CUKAa7Rv.mjs';
3
3
  import * as React from 'react';
4
4
  import React__default, { useRef, useMemo, useLayoutEffect, useEffect, useImperativeHandle, useCallback, useState } from 'react';
5
5
  import useMeasure from 'react-use-measure';
@@ -13997,6 +13997,7 @@ function disposeOnIdle(object) {
13997
13997
  }
13998
13998
  function removeChild(parent, child, dispose) {
13999
13999
  if (!child) return;
14000
+ const wasLinked = !!child.parent;
14000
14001
  child.parent = null;
14001
14002
  const childIndex = parent.children.indexOf(child);
14002
14003
  if (childIndex !== -1) parent.children.splice(childIndex, 1);
@@ -14016,7 +14017,10 @@ function removeChild(parent, child, dispose) {
14016
14017
  if (shouldDispose && child.type !== "primitive" && child.object.type !== "Scene") {
14017
14018
  disposeOnIdle(child.object);
14018
14019
  }
14019
- if (dispose === void 0) invalidateInstance(child);
14020
+ if (dispose === void 0 && wasLinked) {
14021
+ const state = findInitialRoot(child).getState();
14022
+ if (state.internal.active && state.internal.frames === 0) state.invalidate();
14023
+ }
14020
14024
  }
14021
14025
  function setFiberRef(fiber, publicInstance) {
14022
14026
  for (const _fiber of [fiber, fiber.alternate]) {
@@ -14765,6 +14769,69 @@ function getPrimaryIds() {
14765
14769
  return Array.from(primaryRegistry.keys());
14766
14770
  }
14767
14771
 
14772
+ const fulfilled = (value) => Object.assign(Promise.resolve(value), { status: "fulfilled", value });
14773
+ const tracked = (promise) => {
14774
+ const result = Promise.resolve(promise);
14775
+ result.status = "pending";
14776
+ result.then(
14777
+ (value) => {
14778
+ Object.assign(result, { status: "fulfilled", value });
14779
+ },
14780
+ (reason) => {
14781
+ Object.assign(result, { status: "rejected", reason });
14782
+ }
14783
+ );
14784
+ return result;
14785
+ };
14786
+
14787
+ const records = /* @__PURE__ */ new WeakMap();
14788
+ function take(renderer, record) {
14789
+ record.leases++;
14790
+ let released = false;
14791
+ return () => {
14792
+ if (released) return;
14793
+ released = true;
14794
+ if (--record.leases > 0) return;
14795
+ records.delete(renderer);
14796
+ if (record.owned) return disposeRenderer(renderer);
14797
+ };
14798
+ }
14799
+ function leaseRenderer(renderer, owned) {
14800
+ let record = records.get(renderer);
14801
+ if (!record) records.set(renderer, record = { owned, leases: 0 });
14802
+ return take(renderer, record);
14803
+ }
14804
+ function borrowRenderer(renderer) {
14805
+ const record = records.get(renderer);
14806
+ if (!record) throw new Error("R3F: cannot share a renderer whose canvas has already unmounted");
14807
+ return take(renderer, record);
14808
+ }
14809
+ function disposeRenderer(renderer) {
14810
+ if (renderer.hasInitialized?.() === false) return;
14811
+ const warn = (error) => console.warn("[R3F] Error disposing renderer", error);
14812
+ const loseContext = () => {
14813
+ try {
14814
+ ;
14815
+ renderer.forceContextLoss?.();
14816
+ } catch (error) {
14817
+ warn(error);
14818
+ }
14819
+ };
14820
+ let disposed;
14821
+ try {
14822
+ disposed = renderer.dispose();
14823
+ } catch (error) {
14824
+ warn(error);
14825
+ }
14826
+ if (typeof disposed?.then === "function") {
14827
+ return Promise.resolve(disposed).then(loseContext, (error) => {
14828
+ warn(error);
14829
+ loseContext();
14830
+ });
14831
+ }
14832
+ loseContext();
14833
+ }
14834
+
14768
14835
  const isRenderer = (def) => !!def?.render;
14769
14836
  const _roots = /* @__PURE__ */ new Map();
14770
14837
  function ensureStoreThreeObjects(store) {
@@ -14776,9 +14843,9 @@ function ensureStoreThreeObjects(store) {
14776
14843
  }
14777
14844
  const shallowLoose = { objects: "shallow", strict: false };
14778
14845
  async function resolveRenderer(config, defaultProps, RendererClass) {
14779
- if (typeof config === "function") return await config(defaultProps);
14780
- if (isRenderer(config)) return config;
14781
- return new RendererClass({ ...defaultProps, ...config });
14846
+ if (typeof config === "function") return { renderer: await config(defaultProps), owned: true };
14847
+ if (isRenderer(config)) return { renderer: config, owned: false };
14848
+ return { renderer: new RendererClass({ ...defaultProps, ...config }), owned: true };
14782
14849
  }
14783
14850
  function computeInitialSize(canvas, size) {
14784
14851
  if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
@@ -14794,6 +14861,47 @@ function computeInitialSize(canvas, size) {
14794
14861
  }
14795
14862
  return { width: 0, height: 0, top: 0, left: 0, ...size };
14796
14863
  }
14864
+ function watchDpr(onChange) {
14865
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function" || !window.devicePixelRatio) {
14866
+ return () => {
14867
+ };
14868
+ }
14869
+ let query;
14870
+ const listen = () => {
14871
+ try {
14872
+ query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
14873
+ if (typeof query?.addEventListener === "function") query.addEventListener("change", handleChange);
14874
+ else query?.addListener?.(handleChange);
14875
+ } catch {
14876
+ query = void 0;
14877
+ }
14878
+ };
14879
+ const unlisten = () => {
14880
+ if (typeof query?.removeEventListener === "function") query.removeEventListener("change", handleChange);
14881
+ else query?.removeListener?.(handleChange);
14882
+ query = void 0;
14883
+ };
14884
+ const handleChange = () => {
14885
+ unlisten();
14886
+ listen();
14887
+ onChange();
14888
+ };
14889
+ listen();
14890
+ return unlisten;
14891
+ }
14892
+ async function createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support) {
14893
+ const resolved = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
14894
+ const renderer = resolved.renderer;
14895
+ if (!renderer.hasInitialized?.()) {
14896
+ const size = computeInitialSize(canvas, propsSize);
14897
+ if (size.width > 0 && size.height > 0) {
14898
+ renderer.setPixelRatio(calculateDpr(dpr));
14899
+ renderer.setSize(size.width, size.height, false);
14900
+ }
14901
+ await renderer.init();
14902
+ }
14903
+ return { renderer, owned: resolved.owned };
14904
+ }
14797
14905
  function createRoot(canvas, provider) {
14798
14906
  const prevRoot = _roots.get(canvas);
14799
14907
  const prevFiber = prevRoot?.fiber;
@@ -14830,15 +14938,39 @@ function createRoot(canvas, provider) {
14830
14938
  null
14831
14939
  // transitionCallbacks
14832
14940
  );
14833
- if (!prevRoot) _roots.set(canvas, { fiber, store });
14941
+ const root = prevRoot || { fiber, store, unmountClaim: null, ready: fulfilled(void 0) };
14942
+ if (!prevRoot) _roots.set(canvas, root);
14834
14943
  let onCreated;
14835
14944
  let lastCamera;
14836
14945
  const lastConfiguredProps = {};
14946
+ let resolvedDpr = 0;
14947
+ let dprChangedInXR = false;
14948
+ let unwatchDpr;
14949
+ const resolveDpr = () => {
14950
+ if (_roots.get(canvas)?.store !== store) return unwatchDpr?.();
14951
+ const state = store.getState();
14952
+ const xr = state.internal.actualRenderer?.xr;
14953
+ if (xr?.isPresenting || xr?.getSession?.()) {
14954
+ dprChangedInXR = true;
14955
+ return;
14956
+ }
14957
+ dprChangedInXR = false;
14958
+ const dpr = lastConfiguredProps.dpr;
14959
+ if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
14960
+ state.setDpr(dpr);
14961
+ resolvedDpr = store.getState().viewport.dpr;
14962
+ };
14837
14963
  let configured = false;
14838
14964
  let pending = null;
14839
- let rendererSetup = null;
14965
+ const cancelUnmount = () => {
14966
+ if (!root.unmountClaim) return;
14967
+ root.unmountClaim = null;
14968
+ store.getState().internal.active = true;
14969
+ };
14840
14970
  return {
14841
14971
  async configure(props = {}) {
14972
+ if (_roots.get(canvas) !== root) throw new Error("R3F: cannot configure a root after it has unmounted");
14973
+ cancelUnmount();
14842
14974
  let resolve;
14843
14975
  pending = new Promise((_resolve) => resolve = _resolve);
14844
14976
  const {
@@ -14912,49 +15044,82 @@ function createRoot(canvas, provider) {
14912
15044
  );
14913
15045
  }
14914
15046
  if (!state.internal.actualRenderer) {
14915
- if (!rendererSetup) {
14916
- rendererSetup = (async () => {
15047
+ if (root.ready.status !== "pending") {
15048
+ const setup = (async () => {
14917
15049
  const support = wantsGL ? await webgl() : await webgpu();
14918
15050
  registerThree(support.three);
14919
15051
  state.internal.support = support;
14920
15052
  ensureStoreThreeObjects(store);
14921
15053
  if (support.kind === "webgl") {
14922
- renderer = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
15054
+ const resolved = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
15055
+ renderer = resolved.renderer;
14923
15056
  state.internal.actualRenderer = renderer;
15057
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
14924
15058
  state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14925
15059
  } else if (primaryCanvas) {
14926
15060
  const primary = await waitForPrimary(primaryCanvas);
14927
- renderer = primary.renderer;
14928
- state.internal.actualRenderer = renderer;
14929
- const canvasTarget = new support.CanvasTarget(canvas);
14930
- primary.store.setState((prev) => ({
14931
- internal: { ...prev.internal, isMultiCanvas: true }
14932
- }));
14933
- state.set((prev) => ({
14934
- webGPUSupported: primary.store.getState().webGPUSupported,
14935
- renderer,
14936
- primaryStore: primary.store,
14937
- internal: {
14938
- ...prev.internal,
14939
- canvasTarget,
14940
- isMultiCanvas: true,
14941
- isSecondary: true,
14942
- targetId: primaryCanvas
14943
- }
14944
- }));
14945
- } else {
14946
- renderer = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
14947
- if (!renderer.hasInitialized?.()) {
14948
- const size2 = computeInitialSize(canvas, propsSize);
14949
- if (size2.width > 0 && size2.height > 0) {
14950
- renderer.setPixelRatio(calculateDpr(dpr));
14951
- renderer.setSize(size2.width, size2.height, false);
14952
- }
14953
- await renderer.init();
15061
+ if (primary.store.getState().webGPUSupported) {
15062
+ renderer = primary.renderer;
15063
+ state.internal.actualRenderer = renderer;
15064
+ state.internal.releaseRenderer = borrowRenderer(renderer);
15065
+ const canvasTarget = new support.CanvasTarget(canvas);
15066
+ primary.store.setState((prev) => ({
15067
+ internal: { ...prev.internal, isMultiCanvas: true }
15068
+ }));
15069
+ state.set((prev) => ({
15070
+ webGPUSupported: primary.store.getState().webGPUSupported,
15071
+ renderer,
15072
+ primaryStore: primary.store,
15073
+ internal: {
15074
+ ...prev.internal,
15075
+ canvasTarget,
15076
+ isMultiCanvas: true,
15077
+ isSecondary: true,
15078
+ targetId: primaryCanvas
15079
+ }
15080
+ }));
15081
+ } else {
15082
+ const isPlainConfig = is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig);
15083
+ const { primaryCanvas: _peeled, ...rendererOptions } = isPlainConfig ? rendererConfig : {};
15084
+ const fallbackConfig = is.fun(rendererConfig) || isRenderer(rendererConfig) ? rendererConfig : { ...rendererOptions, forceWebGL: true };
15085
+ const resolved = await createOwnedWebGPURenderer(
15086
+ fallbackConfig,
15087
+ defaultGPUProps,
15088
+ canvas,
15089
+ propsSize,
15090
+ dpr,
15091
+ support
15092
+ );
15093
+ renderer = resolved.renderer;
15094
+ const backend = renderer.backend;
15095
+ const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
15096
+ state.internal.actualRenderer = renderer;
15097
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
15098
+ state.set((prev) => ({
15099
+ webGPUSupported: isWebGPUBackend,
15100
+ renderer,
15101
+ primaryStore: store,
15102
+ internal: {
15103
+ ...prev.internal,
15104
+ canvasTarget: renderer.getCanvasTarget?.(),
15105
+ sharedRendererFallback: true
15106
+ }
15107
+ }));
14954
15108
  }
15109
+ } else {
15110
+ const resolved = await createOwnedWebGPURenderer(
15111
+ rendererConfig,
15112
+ defaultGPUProps,
15113
+ canvas,
15114
+ propsSize,
15115
+ dpr,
15116
+ support
15117
+ );
15118
+ renderer = resolved.renderer;
14955
15119
  const backend = renderer.backend;
14956
15120
  const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14957
15121
  state.internal.actualRenderer = renderer;
15122
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
14958
15123
  state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
14959
15124
  if (canvasId && !state.internal.isSecondary) {
14960
15125
  const canvasTarget = renderer.getCanvasTarget?.();
@@ -14968,16 +15133,15 @@ function createRoot(canvas, provider) {
14968
15133
  }));
14969
15134
  }
14970
15135
  }
14971
- })().catch((err) => {
14972
- rendererSetup = null;
14973
- throw err;
14974
- });
15136
+ })();
15137
+ root.ready = tracked(setup);
14975
15138
  }
14976
- await rendererSetup;
15139
+ await root.ready;
14977
15140
  state = store.getState();
14978
15141
  renderer = state.internal.actualRenderer;
14979
15142
  }
14980
15143
  const three = getThree();
15144
+ const borrowsRenderer = state.internal.isSecondary === true;
14981
15145
  let raycaster = state.raycaster;
14982
15146
  if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
14983
15147
  const { params, ...options } = raycastOptions || {};
@@ -15052,6 +15216,12 @@ function createRoot(canvas, provider) {
15052
15216
  if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
15053
15217
  state.setDpr(dpr);
15054
15218
  lastConfiguredProps.dpr = dpr;
15219
+ resolvedDpr = store.getState().viewport.dpr;
15220
+ }
15221
+ const internal = store.getState().internal;
15222
+ if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
15223
+ internal.unwatchDpr?.();
15224
+ internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
15055
15225
  }
15056
15226
  if (frameloop !== void 0 && frameloop !== lastConfiguredProps.frameloop) {
15057
15227
  state.setFrameloop(frameloop);
@@ -15080,7 +15250,10 @@ function createRoot(canvas, provider) {
15080
15250
  const renderer2 = state2.internal.actualRenderer;
15081
15251
  actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
15082
15252
  renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
15083
- if (!renderer2.xr.isPresenting) invalidate(state2);
15253
+ if (!renderer2.xr.isPresenting) {
15254
+ if (dprChangedInXR) resolveDpr();
15255
+ invalidate(state2);
15256
+ }
15084
15257
  };
15085
15258
  const xr = {
15086
15259
  connect() {
@@ -15096,10 +15269,10 @@ function createRoot(canvas, provider) {
15096
15269
  xrManager.removeEventListener("sessionend", handleSessionChange);
15097
15270
  }
15098
15271
  };
15099
- if (typeof renderer.xr?.addEventListener === "function") xr.connect();
15272
+ if (!borrowsRenderer && typeof renderer.xr?.addEventListener === "function") xr.connect();
15100
15273
  state.set({ xr });
15101
15274
  }
15102
- if (renderer.shadowMap && !is.equ(shadows, lastConfiguredProps.shadows, shallowLoose)) {
15275
+ if (!borrowsRenderer && renderer.shadowMap && !is.equ(shadows, lastConfiguredProps.shadows, shallowLoose)) {
15103
15276
  lastConfiguredProps.shadows = shadows;
15104
15277
  const oldEnabled = renderer.shadowMap.enabled;
15105
15278
  const oldType = renderer.shadowMap.type;
@@ -15128,7 +15301,7 @@ function createRoot(canvas, provider) {
15128
15301
  renderer.shadowMap.needsUpdate = true;
15129
15302
  }
15130
15303
  }
15131
- if (!configured) {
15304
+ if (!configured && !borrowsRenderer) {
15132
15305
  renderer.outputColorSpace = three.SRGBColorSpace;
15133
15306
  renderer.toneMapping = three.ACESFilmicToneMapping;
15134
15307
  }
@@ -15137,7 +15310,7 @@ function createRoot(canvas, provider) {
15137
15310
  if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
15138
15311
  lastConfiguredProps.textureColorSpace = textureColorSpace;
15139
15312
  }
15140
- const r3fProps = ["textureColorSpace"];
15313
+ const r3fProps = ["textureColorSpace", "primaryCanvas", "scheduler"];
15141
15314
  const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
15142
15315
  const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
15143
15316
  if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
@@ -15147,7 +15320,7 @@ function createRoot(canvas, provider) {
15147
15320
  }
15148
15321
  applyProps(renderer, glProps);
15149
15322
  }
15150
- if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
15323
+ if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer && !borrowsRenderer) {
15151
15324
  const currentRenderer = state.renderer;
15152
15325
  if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
15153
15326
  const rendererProps = {};
@@ -15290,8 +15463,11 @@ function createRoot(canvas, provider) {
15290
15463
  return this;
15291
15464
  },
15292
15465
  render(children) {
15466
+ if (_roots.get(canvas) !== root) return store;
15467
+ cancelUnmount();
15293
15468
  if (!configured && !pending) this.configure();
15294
15469
  pending.then(() => {
15470
+ if (_roots.get(canvas) !== root || root.unmountClaim) return;
15295
15471
  reconciler.updateContainer(
15296
15472
  /* @__PURE__ */ jsx(Provider, { store, children, onCreated, rootElement: canvas }),
15297
15473
  fiber,
@@ -15302,7 +15478,7 @@ function createRoot(canvas, provider) {
15302
15478
  return store;
15303
15479
  },
15304
15480
  unmount() {
15305
- unmountComponentAtNode(canvas);
15481
+ if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
15306
15482
  }
15307
15483
  };
15308
15484
  }
@@ -15322,46 +15498,52 @@ function Provider({
15322
15498
  }
15323
15499
  function unmountComponentAtNode(canvas, callback) {
15324
15500
  const root = _roots.get(canvas);
15325
- const fiber = root?.fiber;
15326
- if (fiber) {
15327
- const state = root?.store.getState();
15328
- if (state) {
15329
- state.internal.active = false;
15330
- const unregisterRoot = state.internal.unregisterRoot;
15331
- if (unregisterRoot) {
15332
- unregisterRoot();
15333
- state.internal.unregisterRoot = void 0;
15501
+ if (!root) return;
15502
+ const claim = root.unmountClaim = Symbol("unmount");
15503
+ root.store.getState().internal.active = false;
15504
+ reconciler.updateContainer(null, root.fiber, null, () => {
15505
+ if (root.unmountClaim !== claim) return;
15506
+ reconciler.updateContainer(null, root.fiber, null, () => {
15507
+ if (root.unmountClaim !== claim) return;
15508
+ if (root.ready.status === "pending") root.ready.then(teardown, teardown);
15509
+ else teardown();
15510
+ });
15511
+ });
15512
+ function teardown() {
15513
+ if (root.unmountClaim !== claim) return;
15514
+ root.unmountClaim = null;
15515
+ _roots.delete(canvas);
15516
+ const state = root.store.getState();
15517
+ const internal = state.internal;
15518
+ internal.active = false;
15519
+ const attempt = (step) => {
15520
+ try {
15521
+ return step();
15522
+ } catch (error) {
15523
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15334
15524
  }
15335
- }
15336
- reconciler.updateContainer(null, fiber, null, () => {
15337
- if (root?.store) detachRootExtensions(root.store);
15338
- if (state) {
15339
- setTimeout(() => {
15340
- try {
15341
- const renderer = state.internal.actualRenderer;
15342
- const unregisterPrimary = state.internal.unregisterPrimary;
15343
- if (unregisterPrimary) unregisterPrimary();
15344
- const canvasTarget = state.internal.canvasTarget;
15345
- if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
15346
- state.events.disconnect?.();
15347
- cleanupHelperGroup(root.store);
15348
- if (state.isLegacy && renderer) {
15349
- ;
15350
- renderer.renderLists?.dispose?.();
15351
- renderer.forceContextLoss?.();
15352
- }
15353
- if (!state.internal.isSecondary) {
15354
- if (renderer?.xr) state.xr.disconnect();
15355
- }
15356
- dispose(state.scene);
15357
- _roots.delete(canvas);
15358
- if (callback) callback(canvas);
15359
- } catch (error) {
15360
- console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15361
- }
15362
- }, 500);
15525
+ };
15526
+ attempt(() => internal.unwatchDpr?.());
15527
+ internal.unwatchDpr = void 0;
15528
+ attempt(() => internal.unregisterRoot?.());
15529
+ internal.unregisterRoot = void 0;
15530
+ attempt(() => detachRootExtensions(root.store));
15531
+ attempt(() => internal.unregisterPrimary?.());
15532
+ attempt(() => state.events.disconnect?.());
15533
+ if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
15534
+ attempt(() => cleanupHelperGroup(root.store));
15535
+ if (state.scene) attempt(() => dispose(state.scene));
15536
+ const canvasTarget = internal.canvasTarget;
15537
+ if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
15538
+ const released = attempt(() => internal.releaseRenderer?.());
15539
+ internal.releaseRenderer = void 0;
15540
+ if (callback) {
15541
+ if (released) {
15542
+ released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
15543
+ } else {
15544
+ callback(canvas);
15363
15545
  }
15364
- });
15546
+ }
15365
15547
  }
15366
15548
  }
15367
15549
  function createPortal(children, container, state) {
@@ -15906,13 +16088,27 @@ function CanvasImpl({
15906
16088
  }
15907
16089
  };
15908
16090
  });
16091
+ const insertionMounted = React.useRef(false);
16092
+ React.useInsertionEffect(() => {
16093
+ insertionMounted.current = true;
16094
+ return () => {
16095
+ insertionMounted.current = false;
16096
+ queueMicrotask(() => {
16097
+ if (insertionMounted.current) return;
16098
+ const current = root.current;
16099
+ root.current = null;
16100
+ current?.unmount();
16101
+ });
16102
+ };
16103
+ }, []);
15909
16104
  React.useEffect(() => {
15910
16105
  const canvas = canvasRef.current;
15911
16106
  if (canvas) {
15912
16107
  return () => {
15913
16108
  if (canvas.isConnected) return;
15914
- unmountComponentAtNode(canvas);
16109
+ const current = root.current;
15915
16110
  root.current = null;
16111
+ current?.unmount();
15916
16112
  };
15917
16113
  }
15918
16114
  }, []);
@@ -3,7 +3,7 @@ import { ReactNode, Component, RefObject, JSX } from 'react';
3
3
  import { Options } from 'react-use-measure';
4
4
  import * as THREE from 'three';
5
5
  import { ColorRepresentation, Euler as Euler$1, Loader, RenderTargetOptions as RenderTargetOptions$1, ColorSpace, Texture as Texture$1, CubeTexture, Scene, Object3D } from 'three';
6
- import { J as Properties, c as Size, F as Frameloop, e as Performance, D as Dpr, g as RootStore, p as EventManager, f as RootState, n as ComputeFunction, C as ConstructorRepresentation, _ as ObjectMap, I as InternalState, M as Mutable, O as Overwrite, y as Args, l as EventHandlers, B as InstanceProps, k as DomEvent, G as Instance, x as Catalogue, v as Root, a6 as ThreeCore, W as Bridge, Z as UnblockProps, a0 as Disposable, Q as ThreeCamera, $ as EquConfig } from './fiber.I5Q4dVvl.cjs';
6
+ import { K as Properties, c as Size, F as Frameloop, e as Performance, D as Dpr, g as RootStore, p as EventManager, f as RootState, n as ComputeFunction, C as ConstructorRepresentation, $ as ObjectMap, I as InternalState, M as Mutable, O as Overwrite, z as Args, l as EventHandlers, G as InstanceProps, k as DomEvent, H as Instance, y as Catalogue, w as Root, a7 as ThreeCore, Y as Bridge, _ as UnblockProps, a1 as Disposable, U as ThreeCamera, a0 as EquConfig } from './fiber.CLTHZhZp.js';
7
7
  import { WebGPURenderer, WebGPURendererParameters } from 'three/webgpu';
8
8
 
9
9
  //* Base Renderer Types =====================================
@@ -2255,16 +2255,67 @@ declare namespace ReactReconciler {
2255
2255
  ): void;
2256
2256
  }
2257
2257
 
2258
+ /**
2259
+ * Registers constructors so they can be rendered as JSX elements.
2260
+ *
2261
+ * - `extend({ OrbitControls })` makes each constructor available under its camelCased key
2262
+ * (`<orbitControls />`). Values that are not constructors are skipped, so a whole module
2263
+ * namespace can be passed.
2264
+ * - `extend(MyClass)` registers one constructor and returns a component to render it with.
2265
+ *
2266
+ * Registrations are global, shared by every copy and entry of fiber, and are checked before the
2267
+ * three namespace of a root's renderer when an element name is resolved.
2268
+ *
2269
+ * @example
2270
+ * import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
2271
+ * extend({ OrbitControls })
2272
+ * // <orbitControls args={[camera, gl.domElement]} />
2273
+ *
2274
+ * @example
2275
+ * const Controls = extend(OrbitControls)
2276
+ * // <Controls args={[camera, gl.domElement]} />
2277
+ *
2278
+ * @see https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively
2279
+ */
2258
2280
  declare function extend<T extends ConstructorRepresentation>(objects: T): React$1.ExoticComponent<ThreeElement<T>>;
2281
+ /** Registers each constructor in `objects` under its key; see the first overload. */
2259
2282
  declare function extend<T extends Catalogue>(objects: T): void;
2283
+ /** Registers every constructor in a module namespace, skipping other exports; see the first overload. */
2260
2284
  declare function extend(objects: Record<string, unknown>): void;
2261
2285
 
2286
+ /**
2287
+ * R3F's React reconciler: a mutation-mode host config that turns JSX elements into three.js objects.
2288
+ * Each root's {@link RootStore} is its container, and children attach to `internal.container`
2289
+ * (a portal's target) or else the root's `scene`.
2290
+ *
2291
+ * - **Element names** resolve through `extend()` registrations first, then the three namespace of
2292
+ * the root's renderer. A `three` prefix (`<threeLine>`) is stripped when no element by the
2293
+ * prefixed name exists. `<primitive object={...}>` wraps an existing object.
2294
+ * - **Construction is deferred** until an instance is attached to a mounted parent, so a tree that
2295
+ * Suspense discards never creates three objects.
2296
+ * - **Updates** apply only changed props. Changing `args` (or a primitive's `object`) reconstructs
2297
+ * the object instead; the swap happens in `resetAfterCommit`, before layout effects, so refs
2298
+ * already point to the new object.
2299
+ * - **Removal** detaches the object and disposes it (at idle priority, or immediately in an `act`
2300
+ * test environment), unless it is a primitive, a `Scene`, or it or an ancestor has `dispose={null}`.
2301
+ * - **Priority**: not the primary renderer, so it runs alongside react-dom, and update priority
2302
+ * follows react-dom's event priorities. View-transition commits are flushed synchronously, since
2303
+ * three has nothing to animate between commits.
2304
+ *
2305
+ * `createRoot`, `createPortal` and `flushSync` drive it; app code rarely needs it directly.
2306
+ */
2262
2307
  declare const reconciler: ReactReconciler.Reconciler<RootStore, Instance<any>, void, Instance<any>, never, any>;
2263
2308
 
2264
2309
  declare const isRenderer: (def: any) => boolean;
2265
2310
  interface OffscreenCanvas extends EventTarget {
2266
2311
  }
2267
2312
  declare const _roots: Map<HTMLCanvasElement | OffscreenCanvas, Root>;
2313
+ /**
2314
+ * Unmount the root on `canvas`. The teardown runs once React has committed the unmount, and waits
2315
+ * for a renderer that is still being created. `callback` runs when the root is gone: after the
2316
+ * teardown, and when it disposed a renderer R3F created whose `dispose()` is async (WebGPURenderer
2317
+ * from three r186), after that dispose has settled.
2318
+ */
2268
2319
  declare function unmountComponentAtNode<TCanvas extends HTMLCanvasElement | OffscreenCanvas>(canvas: TCanvas, callback?: (canvas: TCanvas) => void): void;
2269
2320
  declare function createPortal(children: ReactNode, container: THREE.Object3D | RefObject<THREE.Object3D | null> | RefObject<THREE.Object3D>, state?: InjectState): JSX.Element;
2270
2321
  interface PortalProps {
@@ -2281,6 +2332,30 @@ declare function Portal({ children, container, state }: PortalProps): JSX.Elemen
2281
2332
  */
2282
2333
  declare function flushSync<R>(fn: () => R): R;
2283
2334
 
2335
+ /**
2336
+ * Creates the Zustand store that holds one root's {@link RootState}.
2337
+ *
2338
+ * The store starts unconfigured: the renderer, `camera`, `scene`, `raycaster`, `frustum` and `pointer`
2339
+ * are `null` placeholders until the root's renderer support has loaded and `configure()` in
2340
+ * `renderer.tsx` fills them in. Only core's part of `RootState` is created here; packages building on
2341
+ * fiber add their own fields through root extensions.
2342
+ *
2343
+ * Besides the initial state, the store wires up:
2344
+ * - `state.gl` and `state.renderer` as accessors over `internal.actualRenderer`. `gl` reports a
2345
+ * deprecation when user code reads it outside legacy mode.
2346
+ * - `rootScene` following `scene` whenever `scene` is set to a real `THREE.Scene`.
2347
+ * - On a size or DPR change: updating the camera and resizing the root's own canvas target (or the
2348
+ * renderer when there is none).
2349
+ * - On a camera change: adding an unparented camera to `rootScene`, then refreshing the viewport and
2350
+ * (when `autoUpdateFrustum` is set) the frustum.
2351
+ * - Calling `invalidate(state)` after every state change.
2352
+ *
2353
+ * `createRoot` calls this once per canvas.
2354
+ *
2355
+ * @param invalidate - Requests frames for a root. Bound into `state.invalidate` and called on every store change.
2356
+ * @param advance - Steps a root manually. Bound into `state.advance`.
2357
+ * @returns The root's store, which is also the reconciler container for that root.
2358
+ */
2284
2359
  declare const createStore: (invalidate: (state?: RootState, frames?: number, stackFrames?: boolean) => void, advance: (timestamp: number, runGlobalEffects?: boolean, state?: RootState, frame?: XRFrame) => void) => RootStore;
2285
2360
 
2286
2361
  /** Whether any root has loaded a renderer yet. */