@react-three/fiber 10.0.0-canary.b86abaa → 10.0.0-canary.b9d5979

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.tsM9NKZ9.mjs → fiber.5Q8N6Hhq.mjs} +226 -57
  16. package/dist/shared/{fiber.Cx-UAmMb.d.ts → fiber.B_GGVI86.d.ts} +1 -1
  17. package/dist/shared/{fiber.DXw-SLsH.d.ts → fiber.BcNm6NAg.d.cts} +88 -4
  18. package/dist/shared/{fiber.oKEFddXj.cjs → fiber.BegWBc5_.cjs} +226 -57
  19. package/dist/shared/{fiber.BY6Yf1h-.d.cts → fiber.CQDCACCJ.d.mts} +88 -4
  20. package/dist/shared/{fiber.B0oukOFO.mjs → fiber.CUKAa7Rv.mjs} +1 -1
  21. package/dist/shared/{fiber.I5Q4dVvl.d.cts → fiber.CZLeHcML.d.cts} +24 -2
  22. package/dist/shared/{fiber.I5Q4dVvl.d.mts → fiber.CZLeHcML.d.mts} +24 -2
  23. package/dist/shared/{fiber.I5Q4dVvl.d.ts → fiber.CZLeHcML.d.ts} +24 -2
  24. package/dist/shared/{fiber.BU0vBHc9.d.mts → fiber.ColkapKS.d.mts} +1 -1
  25. package/dist/shared/{fiber.DAl4H27x.d.cts → fiber.DRfTw2kk.d.cts} +1 -1
  26. package/dist/shared/{fiber.Cu2hX1IM.d.mts → fiber.DeBIf2pk.d.ts} +88 -4
  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';
@@ -396,6 +396,15 @@ function isOnce(value) {
396
396
  return value !== null && typeof value === "object" && ONCE in value;
397
397
  }
398
398
 
399
+ function assertNodeMaterialSupported(state, value) {
400
+ if (!state?.isLegacy) return;
401
+ const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isNodeMaterial);
402
+ if (!material) return;
403
+ throw new Error(
404
+ `R3F: ${material.type ?? "Node material"} requires WebGPURenderer (it falls back to WebGL2 automatically). Pass \`renderer\` to <Canvas> from @react-three/fiber, or import from @react-three/fiber/webgpu.`
405
+ );
406
+ }
407
+
399
408
  const RESERVED_PROPS = [
400
409
  "children",
401
410
  "key",
@@ -566,6 +575,7 @@ function applyProps(object, props) {
566
575
  }
567
576
  }
568
577
  } else {
578
+ if (key === "material") assertNodeMaterialSupported(rootState, value);
569
579
  root[key] = value;
570
580
  if (key.endsWith("Node") && root.isMaterial) {
571
581
  root.needsUpdate = true;
@@ -13879,11 +13889,16 @@ function validateInstance(type, props, root) {
13879
13889
  const name = toPascalCase(type);
13880
13890
  const target = resolveConstructor(name, root);
13881
13891
  if (type !== "primitive" && !target) {
13892
+ if (name.endsWith("NodeMaterial")) {
13893
+ assertNodeMaterialSupported(root.getState(), { isNodeMaterial: true, type: name });
13894
+ }
13882
13895
  throw new Error(
13883
13896
  `R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`
13884
13897
  );
13885
13898
  }
13886
13899
  if (type === "primitive" && !props.object) throw new Error(`R3F: Primitives without 'object' are invalid!`);
13900
+ assertNodeMaterialSupported(root.getState(), props.object);
13901
+ assertNodeMaterialSupported(root.getState(), props.material);
13887
13902
  if (props.args !== void 0 && !Array.isArray(props.args)) throw new Error("R3F: The args prop must be an array!");
13888
13903
  }
13889
13904
  function createInstance(type, props, root) {
@@ -13982,6 +13997,7 @@ function disposeOnIdle(object) {
13982
13997
  }
13983
13998
  function removeChild(parent, child, dispose) {
13984
13999
  if (!child) return;
14000
+ const wasLinked = !!child.parent;
13985
14001
  child.parent = null;
13986
14002
  const childIndex = parent.children.indexOf(child);
13987
14003
  if (childIndex !== -1) parent.children.splice(childIndex, 1);
@@ -14001,7 +14017,10 @@ function removeChild(parent, child, dispose) {
14001
14017
  if (shouldDispose && child.type !== "primitive" && child.object.type !== "Scene") {
14002
14018
  disposeOnIdle(child.object);
14003
14019
  }
14004
- 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
+ }
14005
14024
  }
14006
14025
  function setFiberRef(fiber, publicInstance) {
14007
14026
  for (const _fiber of [fiber, fiber.alternate]) {
@@ -14750,6 +14769,69 @@ function getPrimaryIds() {
14750
14769
  return Array.from(primaryRegistry.keys());
14751
14770
  }
14752
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
+
14753
14835
  const isRenderer = (def) => !!def?.render;
14754
14836
  const _roots = /* @__PURE__ */ new Map();
14755
14837
  function ensureStoreThreeObjects(store) {
@@ -14761,9 +14843,9 @@ function ensureStoreThreeObjects(store) {
14761
14843
  }
14762
14844
  const shallowLoose = { objects: "shallow", strict: false };
14763
14845
  async function resolveRenderer(config, defaultProps, RendererClass) {
14764
- if (typeof config === "function") return await config(defaultProps);
14765
- if (isRenderer(config)) return config;
14766
- 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 };
14767
14849
  }
14768
14850
  function computeInitialSize(canvas, size) {
14769
14851
  if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
@@ -14779,6 +14861,34 @@ function computeInitialSize(canvas, size) {
14779
14861
  }
14780
14862
  return { width: 0, height: 0, top: 0, left: 0, ...size };
14781
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
+ }
14782
14892
  function createRoot(canvas, provider) {
14783
14893
  const prevRoot = _roots.get(canvas);
14784
14894
  const prevFiber = prevRoot?.fiber;
@@ -14815,15 +14925,39 @@ function createRoot(canvas, provider) {
14815
14925
  null
14816
14926
  // transitionCallbacks
14817
14927
  );
14818
- if (!prevRoot) _roots.set(canvas, { fiber, store });
14928
+ const root = prevRoot || { fiber, store, unmountClaim: null, ready: fulfilled(void 0) };
14929
+ if (!prevRoot) _roots.set(canvas, root);
14819
14930
  let onCreated;
14820
14931
  let lastCamera;
14821
14932
  const lastConfiguredProps = {};
14933
+ let resolvedDpr = 0;
14934
+ let dprChangedInXR = false;
14935
+ let unwatchDpr;
14936
+ const resolveDpr = () => {
14937
+ if (_roots.get(canvas)?.store !== store) return unwatchDpr?.();
14938
+ const state = store.getState();
14939
+ const xr = state.internal.actualRenderer?.xr;
14940
+ if (xr?.isPresenting || xr?.getSession?.()) {
14941
+ dprChangedInXR = true;
14942
+ return;
14943
+ }
14944
+ dprChangedInXR = false;
14945
+ const dpr = lastConfiguredProps.dpr;
14946
+ if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
14947
+ state.setDpr(dpr);
14948
+ resolvedDpr = store.getState().viewport.dpr;
14949
+ };
14822
14950
  let configured = false;
14823
14951
  let pending = null;
14824
- let rendererSetup = null;
14952
+ const cancelUnmount = () => {
14953
+ if (!root.unmountClaim) return;
14954
+ root.unmountClaim = null;
14955
+ store.getState().internal.active = true;
14956
+ };
14825
14957
  return {
14826
14958
  async configure(props = {}) {
14959
+ if (_roots.get(canvas) !== root) throw new Error("R3F: cannot configure a root after it has unmounted");
14960
+ cancelUnmount();
14827
14961
  let resolve;
14828
14962
  pending = new Promise((_resolve) => resolve = _resolve);
14829
14963
  const {
@@ -14897,20 +15031,23 @@ function createRoot(canvas, provider) {
14897
15031
  );
14898
15032
  }
14899
15033
  if (!state.internal.actualRenderer) {
14900
- if (!rendererSetup) {
14901
- rendererSetup = (async () => {
15034
+ if (root.ready.status !== "pending") {
15035
+ const setup = (async () => {
14902
15036
  const support = wantsGL ? await webgl() : await webgpu();
14903
15037
  registerThree(support.three);
14904
15038
  state.internal.support = support;
14905
15039
  ensureStoreThreeObjects(store);
14906
15040
  if (support.kind === "webgl") {
14907
- renderer = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
15041
+ const resolved = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
15042
+ renderer = resolved.renderer;
14908
15043
  state.internal.actualRenderer = renderer;
15044
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
14909
15045
  state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14910
15046
  } else if (primaryCanvas) {
14911
15047
  const primary = await waitForPrimary(primaryCanvas);
14912
15048
  renderer = primary.renderer;
14913
15049
  state.internal.actualRenderer = renderer;
15050
+ state.internal.releaseRenderer = borrowRenderer(renderer);
14914
15051
  const canvasTarget = new support.CanvasTarget(canvas);
14915
15052
  primary.store.setState((prev) => ({
14916
15053
  internal: { ...prev.internal, isMultiCanvas: true }
@@ -14928,7 +15065,8 @@ function createRoot(canvas, provider) {
14928
15065
  }
14929
15066
  }));
14930
15067
  } else {
14931
- renderer = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
15068
+ const resolved = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
15069
+ renderer = resolved.renderer;
14932
15070
  if (!renderer.hasInitialized?.()) {
14933
15071
  const size2 = computeInitialSize(canvas, propsSize);
14934
15072
  if (size2.width > 0 && size2.height > 0) {
@@ -14940,6 +15078,7 @@ function createRoot(canvas, provider) {
14940
15078
  const backend = renderer.backend;
14941
15079
  const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14942
15080
  state.internal.actualRenderer = renderer;
15081
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
14943
15082
  state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
14944
15083
  if (canvasId && !state.internal.isSecondary) {
14945
15084
  const canvasTarget = renderer.getCanvasTarget?.();
@@ -14953,12 +15092,10 @@ function createRoot(canvas, provider) {
14953
15092
  }));
14954
15093
  }
14955
15094
  }
14956
- })().catch((err) => {
14957
- rendererSetup = null;
14958
- throw err;
14959
- });
15095
+ })();
15096
+ root.ready = tracked(setup);
14960
15097
  }
14961
- await rendererSetup;
15098
+ await root.ready;
14962
15099
  state = store.getState();
14963
15100
  renderer = state.internal.actualRenderer;
14964
15101
  }
@@ -15037,6 +15174,12 @@ function createRoot(canvas, provider) {
15037
15174
  if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
15038
15175
  state.setDpr(dpr);
15039
15176
  lastConfiguredProps.dpr = dpr;
15177
+ resolvedDpr = store.getState().viewport.dpr;
15178
+ }
15179
+ const internal = store.getState().internal;
15180
+ if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
15181
+ internal.unwatchDpr?.();
15182
+ internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
15040
15183
  }
15041
15184
  if (frameloop !== void 0 && frameloop !== lastConfiguredProps.frameloop) {
15042
15185
  state.setFrameloop(frameloop);
@@ -15065,7 +15208,10 @@ function createRoot(canvas, provider) {
15065
15208
  const renderer2 = state2.internal.actualRenderer;
15066
15209
  actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
15067
15210
  renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
15068
- if (!renderer2.xr.isPresenting) invalidate(state2);
15211
+ if (!renderer2.xr.isPresenting) {
15212
+ if (dprChangedInXR) resolveDpr();
15213
+ invalidate(state2);
15214
+ }
15069
15215
  };
15070
15216
  const xr = {
15071
15217
  connect() {
@@ -15275,8 +15421,11 @@ function createRoot(canvas, provider) {
15275
15421
  return this;
15276
15422
  },
15277
15423
  render(children) {
15424
+ if (_roots.get(canvas) !== root) return store;
15425
+ cancelUnmount();
15278
15426
  if (!configured && !pending) this.configure();
15279
15427
  pending.then(() => {
15428
+ if (_roots.get(canvas) !== root || root.unmountClaim) return;
15280
15429
  reconciler.updateContainer(
15281
15430
  /* @__PURE__ */ jsx(Provider, { store, children, onCreated, rootElement: canvas }),
15282
15431
  fiber,
@@ -15287,7 +15436,7 @@ function createRoot(canvas, provider) {
15287
15436
  return store;
15288
15437
  },
15289
15438
  unmount() {
15290
- unmountComponentAtNode(canvas);
15439
+ if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
15291
15440
  }
15292
15441
  };
15293
15442
  }
@@ -15307,46 +15456,52 @@ function Provider({
15307
15456
  }
15308
15457
  function unmountComponentAtNode(canvas, callback) {
15309
15458
  const root = _roots.get(canvas);
15310
- const fiber = root?.fiber;
15311
- if (fiber) {
15312
- const state = root?.store.getState();
15313
- if (state) {
15314
- state.internal.active = false;
15315
- const unregisterRoot = state.internal.unregisterRoot;
15316
- if (unregisterRoot) {
15317
- unregisterRoot();
15318
- state.internal.unregisterRoot = void 0;
15459
+ if (!root) return;
15460
+ const claim = root.unmountClaim = Symbol("unmount");
15461
+ root.store.getState().internal.active = false;
15462
+ reconciler.updateContainer(null, root.fiber, null, () => {
15463
+ if (root.unmountClaim !== claim) return;
15464
+ reconciler.updateContainer(null, root.fiber, null, () => {
15465
+ if (root.unmountClaim !== claim) return;
15466
+ if (root.ready.status === "pending") root.ready.then(teardown, teardown);
15467
+ else teardown();
15468
+ });
15469
+ });
15470
+ function teardown() {
15471
+ if (root.unmountClaim !== claim) return;
15472
+ root.unmountClaim = null;
15473
+ _roots.delete(canvas);
15474
+ const state = root.store.getState();
15475
+ const internal = state.internal;
15476
+ internal.active = false;
15477
+ const attempt = (step) => {
15478
+ try {
15479
+ return step();
15480
+ } catch (error) {
15481
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15319
15482
  }
15320
- }
15321
- reconciler.updateContainer(null, fiber, null, () => {
15322
- if (root?.store) detachRootExtensions(root.store);
15323
- if (state) {
15324
- setTimeout(() => {
15325
- try {
15326
- const renderer = state.internal.actualRenderer;
15327
- const unregisterPrimary = state.internal.unregisterPrimary;
15328
- if (unregisterPrimary) unregisterPrimary();
15329
- const canvasTarget = state.internal.canvasTarget;
15330
- if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
15331
- state.events.disconnect?.();
15332
- cleanupHelperGroup(root.store);
15333
- if (state.isLegacy && renderer) {
15334
- ;
15335
- renderer.renderLists?.dispose?.();
15336
- renderer.forceContextLoss?.();
15337
- }
15338
- if (!state.internal.isSecondary) {
15339
- if (renderer?.xr) state.xr.disconnect();
15340
- }
15341
- dispose(state.scene);
15342
- _roots.delete(canvas);
15343
- if (callback) callback(canvas);
15344
- } catch (error) {
15345
- console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15346
- }
15347
- }, 500);
15483
+ };
15484
+ attempt(() => internal.unwatchDpr?.());
15485
+ internal.unwatchDpr = void 0;
15486
+ attempt(() => internal.unregisterRoot?.());
15487
+ internal.unregisterRoot = void 0;
15488
+ attempt(() => detachRootExtensions(root.store));
15489
+ attempt(() => internal.unregisterPrimary?.());
15490
+ attempt(() => state.events.disconnect?.());
15491
+ if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
15492
+ attempt(() => cleanupHelperGroup(root.store));
15493
+ if (state.scene) attempt(() => dispose(state.scene));
15494
+ const canvasTarget = internal.canvasTarget;
15495
+ if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
15496
+ const released = attempt(() => internal.releaseRenderer?.());
15497
+ internal.releaseRenderer = void 0;
15498
+ if (callback) {
15499
+ if (released) {
15500
+ released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
15501
+ } else {
15502
+ callback(canvas);
15348
15503
  }
15349
- });
15504
+ }
15350
15505
  }
15351
15506
  }
15352
15507
  function createPortal(children, container, state) {
@@ -15891,13 +16046,27 @@ function CanvasImpl({
15891
16046
  }
15892
16047
  };
15893
16048
  });
16049
+ const insertionMounted = React.useRef(false);
16050
+ React.useInsertionEffect(() => {
16051
+ insertionMounted.current = true;
16052
+ return () => {
16053
+ insertionMounted.current = false;
16054
+ queueMicrotask(() => {
16055
+ if (insertionMounted.current) return;
16056
+ const current = root.current;
16057
+ root.current = null;
16058
+ current?.unmount();
16059
+ });
16060
+ };
16061
+ }, []);
15894
16062
  React.useEffect(() => {
15895
16063
  const canvas = canvasRef.current;
15896
16064
  if (canvas) {
15897
16065
  return () => {
15898
16066
  if (canvas.isConnected) return;
15899
- unmountComponentAtNode(canvas);
16067
+ const current = root.current;
15900
16068
  root.current = null;
16069
+ current?.unmount();
15901
16070
  };
15902
16071
  }
15903
16072
  }, []);
@@ -1,4 +1,4 @@
1
- import { a3 as FrameNextCallback } from './fiber.I5Q4dVvl.js';
1
+ import { a4 as FrameNextCallback } from './fiber.CZLeHcML.js';
2
2
  import { UseFrameNextOptions, FrameNextControls } from '@pmndrs/scheduler';
3
3
 
4
4
  /**
@@ -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.js';
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.CZLeHcML.cjs';
7
7
  import { WebGPURenderer, WebGPURendererParameters } from 'three/webgpu';
8
8
 
9
9
  //* Base Renderer Types =====================================
@@ -155,8 +155,11 @@ interface RenderProps<TCanvas extends HTMLCanvasElement | OffscreenCanvas$1> {
155
155
  /** Dimensions to fit the renderer to. Will measure canvas dimensions if omitted */
156
156
  size?: Size
157
157
  /**
158
- * Enables shadows (by default PCFsoft). Can accept `gl.shadowMap` options for fine-tuning,
159
- * but also strings: 'basic' | 'percentage' | 'soft' | 'variance'.
158
+ * Enables shadows (`true` uses `THREE.PCFShadowMap`). Can accept `renderer.shadowMap` options for
159
+ * fine-tuning, but also strings: 'basic' | 'percentage' | 'soft' | 'variance'.
160
+ *
161
+ * `'soft'` is a deprecated alias of `'percentage'`: both map to `THREE.PCFShadowMap`, because three.js
162
+ * deprecated `PCFSoftShadowMap` and made `PCFShadowMap` soft. Using `'soft'` logs a deprecation notice.
160
163
  * @see https://threejs.org/docs/#api/en/renderers/WebGLRenderer.shadowMap
161
164
  */
162
165
  shadows?: boolean | 'basic' | 'percentage' | 'soft' | 'variance' | Partial<THREE.WebGLShadowMap>
@@ -540,8 +543,14 @@ type ThreeElement<T extends ConstructorRepresentation> = Mutable<
540
543
  Overwrite<ElementProps<T>, Omit<InstanceProps<InstanceType<T>, T>, 'object'>>
541
544
  >
542
545
 
546
+ /**
547
+ * Every constructor export of a three namespace as an uncapitalized JSX element. Non-constructor
548
+ * exports (constants, functions, nested namespaces) are dropped from the keys rather than mapped
549
+ * to `never`: a single `never`-valued key in `JSX.IntrinsicElements` collapses the props of any
550
+ * tag typed `React.ElementType` (#3898).
551
+ */
543
552
  type ThreeToJSXElements<T extends Record<string, any>> = {
544
- [K in keyof T & string as Uncapitalize<K>]: T[K] extends ConstructorRepresentation ? ThreeElement<T[K]> : never
553
+ [K in keyof T & string as T[K] extends ConstructorRepresentation ? Uncapitalize<K> : never]: ThreeElement<T[K]>
545
554
  }
546
555
 
547
556
  /** Method names of Object3D, excluded from the `primitive` element's typed props. */
@@ -2246,16 +2255,67 @@ declare namespace ReactReconciler {
2246
2255
  ): void;
2247
2256
  }
2248
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
+ */
2249
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. */
2250
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. */
2251
2284
  declare function extend(objects: Record<string, unknown>): void;
2252
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
+ */
2253
2307
  declare const reconciler: ReactReconciler.Reconciler<RootStore, Instance<any>, void, Instance<any>, never, any>;
2254
2308
 
2255
2309
  declare const isRenderer: (def: any) => boolean;
2256
2310
  interface OffscreenCanvas extends EventTarget {
2257
2311
  }
2258
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
+ */
2259
2319
  declare function unmountComponentAtNode<TCanvas extends HTMLCanvasElement | OffscreenCanvas>(canvas: TCanvas, callback?: (canvas: TCanvas) => void): void;
2260
2320
  declare function createPortal(children: ReactNode, container: THREE.Object3D | RefObject<THREE.Object3D | null> | RefObject<THREE.Object3D>, state?: InjectState): JSX.Element;
2261
2321
  interface PortalProps {
@@ -2272,6 +2332,30 @@ declare function Portal({ children, container, state }: PortalProps): JSX.Elemen
2272
2332
  */
2273
2333
  declare function flushSync<R>(fn: () => R): R;
2274
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
+ */
2275
2359
  declare const createStore: (invalidate: (state?: RootState, frames?: number, stackFrames?: boolean) => void, advance: (timestamp: number, runGlobalEffects?: boolean, state?: RootState, frame?: XRFrame) => void) => RootStore;
2276
2360
 
2277
2361
  /** Whether any root has loaded a renderer yet. */