@react-three/fiber 9.8.0 → 9.8.1

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.
@@ -2,10 +2,10 @@
2
2
 
3
3
  var React = require('react');
4
4
  var THREE = require('three');
5
+ var jsxRuntime = require('react/jsx-runtime');
5
6
  var traditional = require('zustand/traditional');
6
7
  var suspendReact = require('suspend-react');
7
8
  var w1 = require('scheduler');
8
- var jsxRuntime = require('react/jsx-runtime');
9
9
  var itsFine = require('its-fine');
10
10
 
11
11
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
@@ -95,23 +95,29 @@ function useGate() {
95
95
  }) : null;
96
96
  return [gate, waitFor];
97
97
  }
98
+
99
+ // Activity is optional on React 19.0/19.1. A computed key also supports strict ESM bundlers.
100
+ const useActivityBridge = React__namespace['Activity' + ''] ? itsFine.useActivityBridge : () => React__namespace.Fragment;
98
101
  /**
99
- * Bridges renderer Context and StrictMode from a primary renderer.
102
+ * Bridges Context, StrictMode, and Activity visibility from a primary renderer.
100
103
  */
101
104
  function useBridge() {
102
105
  const fiber = itsFine.useFiber();
103
106
  const ContextBridge = itsFine.useContextBridge();
107
+ const ActivityBridge = useActivityBridge();
104
108
  return React__namespace.useMemo(() => ({
105
109
  children
106
110
  }) => {
107
111
  const strict = !!itsFine.traverseFiber(fiber, true, node => node.type === React__namespace.StrictMode);
108
112
  const Root = strict ? React__namespace.StrictMode : React__namespace.Fragment;
109
113
  return /*#__PURE__*/jsxRuntime.jsx(Root, {
110
- children: /*#__PURE__*/jsxRuntime.jsx(ContextBridge, {
111
- children: children
114
+ children: /*#__PURE__*/jsxRuntime.jsx(ActivityBridge, {
115
+ children: /*#__PURE__*/jsxRuntime.jsx(ContextBridge, {
116
+ children: children
117
+ })
112
118
  })
113
119
  });
114
- }, [fiber, ContextBridge]);
120
+ }, [fiber, ContextBridge, ActivityBridge]);
115
121
  }
116
122
  function Block({
117
123
  set
@@ -257,6 +263,7 @@ function prepare(target, root, type, props) {
257
263
  object,
258
264
  eventCount: 0,
259
265
  handlers: {},
266
+ previousVisible: undefined,
260
267
  isHidden: false
261
268
  };
262
269
  if (object) object.__r3f = instance;
@@ -440,6 +447,12 @@ function applyProps(object, props) {
440
447
  // Ignore setting undefined props
441
448
  // https://github.com/pmndrs/react-three-fiber/issues/274
442
449
  if (value === undefined) continue;
450
+
451
+ // Update the visibility to restore without revealing a hidden instance.
452
+ if (prop === 'visible' && instance != null && instance.isHidden && instance.previousVisible !== undefined) {
453
+ instance.previousVisible = value;
454
+ continue;
455
+ }
443
456
  let {
444
457
  root,
445
458
  key,
@@ -1364,9 +1377,326 @@ useLoader.clear = function (loader, input) {
1364
1377
  e = 2,
1365
1378
  i$1 = 268435456;
1366
1379
 
1380
+ // Shim for OffscreenCanvas since it was removed from DOM types
1381
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/54988
1382
+
1383
+ /** What a root has applied, so its next configuration applies only what changed */
1384
+
1385
+ const shallow = {
1386
+ objects: 'shallow'
1387
+ };
1388
+
1389
+ /** The renderer to configure, or a promise for one from an async factory */
1390
+ function createRenderer(canvas, gl) {
1391
+ const defaults = {
1392
+ canvas,
1393
+ powerPreference: 'high-performance',
1394
+ antialias: true,
1395
+ alpha: true
1396
+ };
1397
+ if (typeof gl === 'function') return gl(defaults);
1398
+ if (isRenderer(gl)) return gl;
1399
+ return new THREE__namespace.WebGLRenderer({
1400
+ ...defaults,
1401
+ ...gl
1402
+ });
1403
+ }
1404
+ function computeInitialSize(canvas, size) {
1405
+ if (!size && typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
1406
+ const {
1407
+ width,
1408
+ height,
1409
+ top,
1410
+ left
1411
+ } = canvas.parentElement.getBoundingClientRect();
1412
+ return {
1413
+ width,
1414
+ height,
1415
+ top,
1416
+ left
1417
+ };
1418
+ } else if (!size && typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
1419
+ return {
1420
+ width: canvas.width,
1421
+ height: canvas.height,
1422
+ top: 0,
1423
+ left: 0
1424
+ };
1425
+ }
1426
+ return {
1427
+ width: 0,
1428
+ height: 0,
1429
+ top: 0,
1430
+ left: 0,
1431
+ ...size
1432
+ };
1433
+ }
1434
+
1435
+ /**
1436
+ * Applies the inputs that changed since the last configuration applied in full, to a root whose
1437
+ * renderer is installed. A runtime change, such as setFrameloop or an edit to gl.shadowMap, lasts
1438
+ * until its input changes. The pixel ratio instead follows the device on every call. Objects and
1439
+ * arrays compare shallowly, so an equal inline value is unchanged.
1440
+ */
1441
+ function applyRootConfiguration({
1442
+ store,
1443
+ configuration
1444
+ }, canvas, props) {
1445
+ const {
1446
+ gl: glConfig,
1447
+ scene: sceneOptions,
1448
+ camera: cameraOptions,
1449
+ shadows = false,
1450
+ linear = false,
1451
+ flat = false,
1452
+ legacy = false,
1453
+ frameloop = 'always',
1454
+ dpr = [1, 2],
1455
+ performance,
1456
+ onPointerMissed
1457
+ } = props;
1458
+ const size = computeInitialSize(canvas, props.size);
1459
+ const next = {
1460
+ ...props,
1461
+ shadows,
1462
+ linear,
1463
+ flat,
1464
+ legacy,
1465
+ frameloop,
1466
+ size
1467
+ };
1468
+ const state = store.getState();
1469
+ const gl = state.gl;
1470
+ const last = configuration.previous;
1471
+ const changed = key => !last || !is.equ(next[key], last[key], shallow);
1472
+ // A failure can leave inputs partly applied, so the next configuration applies all of them
1473
+ configuration.previous = undefined;
1474
+
1475
+ // Set up raycaster (one time only!)
1476
+ let raycaster = state.raycaster;
1477
+ if (!raycaster) state.set({
1478
+ raycaster: raycaster = new THREE__namespace.Raycaster()
1479
+ });
1480
+ if (changed('raycaster')) {
1481
+ var _props$raycaster;
1482
+ const {
1483
+ params,
1484
+ ...options
1485
+ } = (_props$raycaster = props.raycaster) != null ? _props$raycaster : {};
1486
+ applyProps(raycaster, {
1487
+ ...options,
1488
+ params: {
1489
+ ...raycaster.params,
1490
+ ...params
1491
+ }
1492
+ });
1493
+ }
1494
+
1495
+ // Create default camera, don't overwrite any user-set state
1496
+ if (!state.camera || state.camera === configuration.camera && changed('camera')) {
1497
+ configuration.camera = cameraOptions;
1498
+ const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
1499
+ const camera = isCamera ? cameraOptions : props.orthographic ? new THREE__namespace.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE__namespace.PerspectiveCamera(75, 0, 0.1, 1000);
1500
+ if (!isCamera) {
1501
+ camera.position.z = 5;
1502
+ if (cameraOptions) {
1503
+ applyProps(camera, cameraOptions);
1504
+ // Preserve user-defined frustum if possible
1505
+ // https://github.com/pmndrs/react-three-fiber/issues/3160
1506
+ if (!camera.manual) {
1507
+ if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
1508
+ camera.manual = true;
1509
+ camera.updateProjectionMatrix();
1510
+ }
1511
+ }
1512
+ }
1513
+ // Always look at center by default
1514
+ if (!state.camera && !(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
1515
+ }
1516
+ state.set({
1517
+ camera
1518
+ });
1519
+
1520
+ // Configure raycaster
1521
+ // https://github.com/pmndrs/react-xr/issues/300
1522
+ raycaster.camera = camera;
1523
+ }
1524
+
1525
+ // Set up scene (one time only!)
1526
+ if (!state.scene) {
1527
+ let scene;
1528
+ if (sceneOptions != null && sceneOptions.isScene) {
1529
+ scene = sceneOptions;
1530
+ prepare(scene, store, '', {});
1531
+ } else {
1532
+ scene = new THREE__namespace.Scene();
1533
+ prepare(scene, store, '', {});
1534
+ if (sceneOptions) applyProps(scene, sceneOptions);
1535
+ }
1536
+ state.set({
1537
+ scene
1538
+ });
1539
+ }
1540
+
1541
+ // Store events internally
1542
+ if (props.events && !state.events.handlers) state.set({
1543
+ events: props.events(store)
1544
+ });
1545
+ if (changed('size')) state.setSize(size.width, size.height, size.top, size.left);
1546
+ // The ratio follows window.devicePixelRatio, which changes with browser zoom or another display
1547
+ if (state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
1548
+ if (changed('frameloop')) state.setFrameloop(frameloop);
1549
+ if (changed('onPointerMissed')) state.set({
1550
+ onPointerMissed
1551
+ });
1552
+ // Performance options merge, so removing them keeps the current settings
1553
+ if (performance && changed('performance')) {
1554
+ state.set(state => ({
1555
+ performance: {
1556
+ ...state.performance,
1557
+ ...performance
1558
+ }
1559
+ }));
1560
+ }
1561
+
1562
+ // Set up XR (one time only!)
1563
+ if (!state.xr) {
1564
+ var _gl$xr;
1565
+ // Handle frame behavior in WebXR
1566
+ const handleXRFrame = (timestamp, frame) => {
1567
+ const state = store.getState();
1568
+ if (state.frameloop === 'never') return;
1569
+ advance(timestamp, true, state, frame);
1570
+ };
1571
+
1572
+ // Toggle render switching on session
1573
+ const handleSessionChange = () => {
1574
+ const state = store.getState();
1575
+ state.gl.xr.enabled = state.gl.xr.isPresenting;
1576
+ state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
1577
+ if (!state.gl.xr.isPresenting) invalidate(state);
1578
+ };
1579
+
1580
+ // WebXR session manager
1581
+ const xr = {
1582
+ connect() {
1583
+ const gl = store.getState().gl;
1584
+ gl.xr.addEventListener('sessionstart', handleSessionChange);
1585
+ gl.xr.addEventListener('sessionend', handleSessionChange);
1586
+ },
1587
+ disconnect() {
1588
+ const gl = store.getState().gl;
1589
+ gl.xr.removeEventListener('sessionstart', handleSessionChange);
1590
+ gl.xr.removeEventListener('sessionend', handleSessionChange);
1591
+ }
1592
+ };
1593
+
1594
+ // Subscribe to WebXR session events
1595
+ if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
1596
+ state.set({
1597
+ xr
1598
+ });
1599
+ }
1600
+
1601
+ // Set shadowmap
1602
+ if (gl.shadowMap && changed('shadows')) {
1603
+ const oldEnabled = gl.shadowMap.enabled;
1604
+ const oldType = gl.shadowMap.type;
1605
+ gl.shadowMap.enabled = !!shadows;
1606
+ if (is.boo(shadows)) {
1607
+ gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
1608
+ } else if (is.str(shadows)) {
1609
+ var _types$shadows;
1610
+ const types = {
1611
+ basic: THREE__namespace.BasicShadowMap,
1612
+ percentage: THREE__namespace.PCFShadowMap,
1613
+ soft: THREE__namespace.PCFSoftShadowMap,
1614
+ variance: THREE__namespace.VSMShadowMap
1615
+ };
1616
+ gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE__namespace.PCFSoftShadowMap;
1617
+ } else if (is.obj(shadows)) {
1618
+ Object.assign(gl.shadowMap, shadows);
1619
+ }
1620
+ if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
1621
+ }
1622
+
1623
+ // Explicit renderer options take precedence over the color shorthands
1624
+ const glProps = glConfig && !is.fun(glConfig) && !isRenderer(glConfig) ? glConfig : undefined;
1625
+ if (changed('legacy')) {
1626
+ THREE__namespace.ColorManagement.enabled = !legacy;
1627
+ state.set({
1628
+ legacy
1629
+ });
1630
+ }
1631
+ if (changed('linear')) {
1632
+ if ((glProps == null ? void 0 : glProps.outputColorSpace) === undefined) {
1633
+ gl.outputColorSpace = linear ? THREE__namespace.LinearSRGBColorSpace : THREE__namespace.SRGBColorSpace;
1634
+ }
1635
+ state.set({
1636
+ linear
1637
+ });
1638
+ }
1639
+ if (changed('flat')) {
1640
+ if ((glProps == null ? void 0 : glProps.toneMapping) === undefined) gl.toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
1641
+ state.set({
1642
+ flat
1643
+ });
1644
+ }
1645
+
1646
+ // Set gl props
1647
+ if (glProps && changed('gl')) applyProps(gl, glProps);
1648
+ configuration.previous = next;
1649
+ }
1650
+
1651
+ const isPromiseLike = value => typeof (value == null ? void 0 : value.then) === 'function';
1652
+
1653
+ /** A promise tagged with its state, the protocol React's `use` reads */
1654
+
1655
+ const fulfilled = value => Object.assign(Promise.resolve(value), {
1656
+ status: 'fulfilled',
1657
+ value
1658
+ });
1659
+ const rejected = reason => {
1660
+ const promise = Promise.reject(reason);
1661
+ promise.catch(() => {}); // the reason is read from `status`
1662
+ return Object.assign(promise, {
1663
+ status: 'rejected',
1664
+ reason
1665
+ });
1666
+ };
1667
+
1668
+ /** A pending promise, settled once from outside. Its `status` updates the moment it settles */
1669
+ const deferred = () => {
1670
+ let resolve;
1671
+ let reject;
1672
+ const promise = new Promise((yes, no) => {
1673
+ resolve = value => {
1674
+ Object.assign(promise, {
1675
+ status: 'fulfilled',
1676
+ value
1677
+ });
1678
+ yes(value);
1679
+ };
1680
+ reject = reason => {
1681
+ Object.assign(promise, {
1682
+ status: 'rejected',
1683
+ reason
1684
+ });
1685
+ no(reason);
1686
+ };
1687
+ });
1688
+ promise.status = 'pending';
1689
+ promise.catch(() => {}); // the reason is read from `status`
1690
+ return {
1691
+ promise,
1692
+ resolve,
1693
+ reject
1694
+ };
1695
+ };
1696
+
1367
1697
  var packageData = {
1368
1698
  name: "@react-three/fiber",
1369
- version: "9.8.0",
1699
+ version: "9.8.1",
1370
1700
  description: "A React renderer for Threejs",
1371
1701
  keywords: [
1372
1702
  "react",
@@ -1417,7 +1747,7 @@ var packageData = {
1417
1747
  "@types/webxr": "*",
1418
1748
  "base64-js": "^1.5.1",
1419
1749
  buffer: "^6.0.3",
1420
- "its-fine": "^2.0.0",
1750
+ "its-fine": "^2.1.1",
1421
1751
  "react-use-measure": "^2.1.7",
1422
1752
  scheduler: "^0.28.0",
1423
1753
  "suspend-react": "^0.1.3",
@@ -7416,6 +7746,7 @@ function hideInstance(instance) {
7416
7746
  if (instance.props.attach && (_instance$parent = instance.parent) != null && _instance$parent.object) {
7417
7747
  detach(instance.parent, instance);
7418
7748
  } else if (isObject3D(instance.object)) {
7749
+ instance.previousVisible = instance.object.visible;
7419
7750
  instance.object.visible = false;
7420
7751
  }
7421
7752
  instance.isHidden = true;
@@ -7427,9 +7758,11 @@ function unhideInstance(instance) {
7427
7758
  var _instance$parent2;
7428
7759
  if (instance.props.attach && (_instance$parent2 = instance.parent) != null && _instance$parent2.object) {
7429
7760
  attach(instance.parent, instance);
7430
- } else if (isObject3D(instance.object) && instance.props.visible !== false) {
7431
- instance.object.visible = true;
7761
+ } else if (isObject3D(instance.object)) {
7762
+ var _instance$previousVis;
7763
+ instance.object.visible = (_instance$previousVis = instance.previousVisible) != null ? _instance$previousVis : true;
7432
7764
  }
7765
+ instance.previousVisible = undefined;
7433
7766
  instance.isHidden = false;
7434
7767
  invalidateInstance(instance);
7435
7768
  }
@@ -7974,76 +8307,49 @@ const reconciler = /* @__PURE__ */createReconciler({
7974
8307
  getSuspendedCommitReason: (_state, _rootContainer) => null
7975
8308
  });
7976
8309
 
7977
- const isPromiseLike = value => typeof (value == null ? void 0 : value.then) === 'function';
7978
-
7979
- /** A promise tagged with its state, the protocol React's `use` reads */
7980
-
7981
- const fulfilled = value => Object.assign(Promise.resolve(value), {
7982
- status: 'fulfilled',
7983
- value
7984
- });
7985
- const rejected = reason => {
7986
- const promise = Promise.reject(reason);
7987
- promise.catch(() => {}); // the reason is read from `status`
7988
- return Object.assign(promise, {
7989
- status: 'rejected',
7990
- reason
7991
- });
7992
- };
7993
-
7994
- /** Tags `promise` in place once it settles. */
7995
- const tracked = promise => {
7996
- const result = Promise.resolve(promise);
7997
- result.status = 'pending';
7998
- // Statement bodies: returning `result` would make this derived promise adopt its rejection
7999
- result.then(value => {
8000
- Object.assign(result, {
8001
- status: 'fulfilled',
8002
- value
8003
- });
8004
- }, reason => {
8005
- Object.assign(result, {
8006
- status: 'rejected',
8007
- reason
8008
- });
8009
- });
8010
- return result;
8011
- };
8310
+ /**
8311
+ * Force React to flush any updates inside the provided callback synchronously and immediately.
8312
+ * All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
8313
+ * Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
8314
+ * having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
8315
+ */
8316
+ function flushSync(fn) {
8317
+ // @ts-ignore - reconciler types are not maintained
8318
+ return reconciler.flushSyncFromReconciler(fn);
8319
+ }
8012
8320
 
8013
8321
  const _roots = new Map();
8014
- const shallowLoose = {
8015
- objects: 'shallow',
8016
- strict: false
8017
- };
8018
- function computeInitialSize(canvas, size) {
8019
- if (!size && typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
8020
- const {
8021
- width,
8022
- height,
8023
- top,
8024
- left
8025
- } = canvas.parentElement.getBoundingClientRect();
8026
- return {
8027
- width,
8028
- height,
8029
- top,
8030
- left
8031
- };
8032
- } else if (!size && typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
8033
- return {
8034
- width: canvas.width,
8035
- height: canvas.height,
8036
- top: 0,
8037
- left: 0
8038
- };
8322
+ /**
8323
+ * open -> closing -> disposed
8324
+ * | use
8325
+ * v
8326
+ * open
8327
+ *
8328
+ * Only closing can be cancelled. Each unmount carries a token, so only the latest one can dispose.
8329
+ */
8330
+ function transitionRoot(root, event) {
8331
+ const state = root.state;
8332
+ switch (event.type) {
8333
+ case 'use':
8334
+ if (state.status === 'disposed') return false;
8335
+ root.state = {
8336
+ status: 'open'
8337
+ };
8338
+ return true;
8339
+ case 'unmount':
8340
+ if (state.status === 'disposed') return false;
8341
+ root.state = {
8342
+ status: 'closing',
8343
+ token: event.token
8344
+ };
8345
+ return true;
8346
+ case 'dispose':
8347
+ if (state.status !== 'closing' || state.token !== event.token) return false;
8348
+ root.state = {
8349
+ status: 'disposed'
8350
+ };
8351
+ return true;
8039
8352
  }
8040
- return {
8041
- width: 0,
8042
- height: 0,
8043
- top: 0,
8044
- left: 0,
8045
- ...size
8046
- };
8047
8353
  }
8048
8354
  function createRoot(canvas) {
8049
8355
  // Check against mistaken use of createRoot
@@ -8088,286 +8394,84 @@ function createRoot(canvas) {
8088
8394
  const root = prevRoot || {
8089
8395
  fiber,
8090
8396
  store,
8091
- unmountClaim: null,
8092
- ready: fulfilled(undefined)
8397
+ state: {
8398
+ status: 'open'
8399
+ },
8400
+ ready: fulfilled(undefined),
8401
+ configuration: {},
8402
+ ownsRenderer: false
8093
8403
  };
8094
8404
  if (!prevRoot) _roots.set(canvas, root);
8095
-
8096
- // Locals
8097
- let onCreated;
8098
- let lastCamera;
8099
8405
  let mounted = false;
8100
8406
  return {
8101
8407
  get ready() {
8102
8408
  return root.ready;
8103
8409
  },
8104
8410
  configure(props = {}) {
8105
- root.unmountClaim = null;
8106
- const {
8107
- gl: glConfig,
8108
- size: propsSize,
8109
- scene: sceneOptions,
8110
- events,
8111
- onCreated: onCreatedCallback,
8112
- shadows = false,
8113
- linear = false,
8114
- flat = false,
8115
- legacy = false,
8116
- orthographic = false,
8117
- frameloop = 'always',
8118
- dpr = [1, 2],
8119
- performance,
8120
- raycaster: raycastOptions,
8121
- camera: cameraOptions,
8122
- onPointerMissed
8123
- } = props;
8124
- const defaultProps = {
8125
- canvas: canvas,
8126
- powerPreference: 'high-performance',
8127
- antialias: true,
8128
- alpha: true
8129
- };
8411
+ if (!transitionRoot(root, {
8412
+ type: 'use'
8413
+ })) {
8414
+ return rejected(new Error('R3F: Cannot configure a root after disposal has started.'));
8415
+ }
8130
8416
 
8131
- // Synchronous, and needs the renderer to exist
8132
- const apply = customRenderer => {
8417
+ // Configuration applies in call order. Publishing first queues calls made while this one runs
8418
+ const previous = root.ready;
8419
+ const {
8420
+ promise,
8421
+ resolve,
8422
+ reject
8423
+ } = deferred();
8424
+ root.ready = promise;
8425
+ const apply = gl => {
8133
8426
  const state = store.getState();
8134
-
8135
8427
  // Set up renderer (one time only!)
8136
- const first = !state.gl;
8137
- let gl = state.gl;
8138
- if (first) {
8139
- gl = isRenderer(customRenderer) ? customRenderer : new THREE__namespace.WebGLRenderer({
8140
- ...defaultProps,
8141
- ...glConfig
8142
- });
8143
- state.set({
8144
- gl
8145
- });
8146
- }
8147
-
8148
- // Set up raycaster (one time only!)
8149
- let raycaster = state.raycaster;
8150
- if (!raycaster) state.set({
8151
- raycaster: raycaster = new THREE__namespace.Raycaster()
8152
- });
8153
-
8154
- // Set raycaster options
8155
- const {
8156
- params,
8157
- ...options
8158
- } = raycastOptions || {};
8159
- if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
8160
- ...options
8161
- });
8162
- if (!is.equ(params, raycaster.params, shallowLoose)) applyProps(raycaster, {
8163
- params: {
8164
- ...raycaster.params,
8165
- ...params
8166
- }
8167
- });
8168
-
8169
- // Create default camera, don't overwrite any user-set state
8170
- if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
8171
- lastCamera = cameraOptions;
8172
- const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
8173
- const camera = isCamera ? cameraOptions : orthographic ? new THREE__namespace.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE__namespace.PerspectiveCamera(75, 0, 0.1, 1000);
8174
- if (!isCamera) {
8175
- camera.position.z = 5;
8176
- if (cameraOptions) {
8177
- applyProps(camera, cameraOptions);
8178
- // Preserve user-defined frustum if possible
8179
- // https://github.com/pmndrs/react-three-fiber/issues/3160
8180
- if (!camera.manual) {
8181
- if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
8182
- camera.manual = true;
8183
- camera.updateProjectionMatrix();
8184
- }
8185
- }
8186
- }
8187
- // Always look at center by default
8188
- if (!state.camera && !(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
8189
- }
8190
- state.set({
8191
- camera
8192
- });
8193
-
8194
- // Configure raycaster
8195
- // https://github.com/pmndrs/react-xr/issues/300
8196
- raycaster.camera = camera;
8197
- }
8198
-
8199
- // Set up scene (one time only!)
8200
- if (!state.scene) {
8201
- let scene;
8202
- if (sceneOptions != null && sceneOptions.isScene) {
8203
- scene = sceneOptions;
8204
- prepare(scene, store, '', {});
8205
- } else {
8206
- scene = new THREE__namespace.Scene();
8207
- prepare(scene, store, '', {});
8208
- if (sceneOptions) applyProps(scene, sceneOptions);
8209
- }
8428
+ if (!state.gl) {
8429
+ // R3F owns what it builds, a factory's result included, since it calls the factory
8430
+ // once per root. A renderer instance belongs to the caller
8431
+ root.ownsRenderer = !isRenderer(props.gl);
8210
8432
  state.set({
8211
- scene
8433
+ gl: gl
8212
8434
  });
8213
8435
  }
8214
-
8215
- // Store events internally
8216
- if (events && !state.events.handlers) state.set({
8217
- events: events(store)
8218
- });
8219
- // Check size, allow it to take on container bounds initially
8220
- const size = computeInitialSize(canvas, propsSize);
8221
- if (!is.equ(size, state.size, shallowLoose)) {
8222
- state.setSize(size.width, size.height, size.top, size.left);
8223
- }
8224
- // Check pixelratio
8225
- if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
8226
- // Check frameloop
8227
- if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
8228
- // Check pointer missed
8229
- if (!state.onPointerMissed) state.set({
8230
- onPointerMissed
8231
- });
8232
- // Check performance
8233
- if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
8234
- performance: {
8235
- ...state.performance,
8236
- ...performance
8237
- }
8238
- }));
8239
-
8240
- // Set up XR (one time only!)
8241
- if (!state.xr) {
8242
- var _gl$xr;
8243
- // Handle frame behavior in WebXR
8244
- const handleXRFrame = (timestamp, frame) => {
8245
- const state = store.getState();
8246
- if (state.frameloop === 'never') return;
8247
- advance(timestamp, true, state, frame);
8248
- };
8249
-
8250
- // Toggle render switching on session
8251
- const handleSessionChange = () => {
8252
- const state = store.getState();
8253
- state.gl.xr.enabled = state.gl.xr.isPresenting;
8254
- state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
8255
- if (!state.gl.xr.isPresenting) invalidate(state);
8256
- };
8257
-
8258
- // WebXR session manager
8259
- const xr = {
8260
- connect() {
8261
- const gl = store.getState().gl;
8262
- gl.xr.addEventListener('sessionstart', handleSessionChange);
8263
- gl.xr.addEventListener('sessionend', handleSessionChange);
8264
- },
8265
- disconnect() {
8266
- const gl = store.getState().gl;
8267
- gl.xr.removeEventListener('sessionstart', handleSessionChange);
8268
- gl.xr.removeEventListener('sessionend', handleSessionChange);
8269
- }
8270
- };
8271
-
8272
- // Subscribe to WebXR session events
8273
- if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
8274
- state.set({
8275
- xr
8276
- });
8277
- }
8278
-
8279
- // Set shadowmap
8280
- if (gl.shadowMap) {
8281
- const oldEnabled = gl.shadowMap.enabled;
8282
- const oldType = gl.shadowMap.type;
8283
- gl.shadowMap.enabled = !!shadows;
8284
- if (is.boo(shadows)) {
8285
- gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
8286
- } else if (is.str(shadows)) {
8287
- var _types$shadows;
8288
- const types = {
8289
- basic: THREE__namespace.BasicShadowMap,
8290
- percentage: THREE__namespace.PCFShadowMap,
8291
- soft: THREE__namespace.PCFSoftShadowMap,
8292
- variance: THREE__namespace.VSMShadowMap
8293
- };
8294
- gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE__namespace.PCFSoftShadowMap;
8295
- } else if (is.obj(shadows)) {
8296
- Object.assign(gl.shadowMap, shadows);
8297
- }
8298
- if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
8299
- }
8300
- THREE__namespace.ColorManagement.enabled = !legacy;
8301
-
8302
- // Set color space and tonemapping preferences
8303
- if (first) {
8304
- gl.outputColorSpace = linear ? THREE__namespace.LinearSRGBColorSpace : THREE__namespace.SRGBColorSpace;
8305
- gl.toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
8306
- }
8307
-
8308
- // Update color management state
8309
- if (state.legacy !== legacy) state.set(() => ({
8310
- legacy
8311
- }));
8312
- if (state.linear !== linear) state.set(() => ({
8313
- linear
8314
- }));
8315
- if (state.flat !== flat) state.set(() => ({
8316
- flat
8317
- }));
8318
-
8319
- // Set gl props
8320
- if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig);
8321
-
8322
- // Set locals
8323
- onCreated = onCreatedCallback;
8436
+ applyRootConfiguration(root, canvas, props);
8437
+ resolve(this);
8324
8438
  };
8325
- const fail = error => {
8326
- const failure = rejected(error);
8327
- root.ready = failure;
8328
- return failure;
8329
- };
8330
- const run = customRenderer => {
8439
+ const run = () => {
8331
8440
  try {
8332
- apply(customRenderer);
8333
- root.ready = fulfilled(undefined);
8334
- return fulfilled(this);
8441
+ var _store$getState$gl;
8442
+ const gl = (_store$getState$gl = store.getState().gl) != null ? _store$getState$gl : createRenderer(canvas, props.gl);
8443
+ // Only an async renderer factory makes configuration asynchronous
8444
+ if (isPromiseLike(gl)) Promise.resolve(gl).then(apply).catch(reject);else apply(gl);
8335
8445
  } catch (error) {
8336
- return fail(error);
8446
+ reject(error);
8337
8447
  }
8338
8448
  };
8339
-
8340
- // The renderer exists, so applying props is synchronous
8341
- if (store.getState().gl) return run();
8342
-
8343
- // Another configure is creating it. Chaining keeps them in call order
8344
- if (root.ready.status === 'pending') return tracked(root.ready.then(() => run()));
8345
-
8346
- // Only an async factory makes configure asynchronous
8347
- let customRenderer;
8348
- try {
8349
- customRenderer = typeof glConfig === 'function' ? glConfig(defaultProps) : glConfig;
8350
- } catch (error) {
8351
- return fail(error);
8352
- }
8353
- if (!isPromiseLike(customRenderer)) return run(customRenderer);
8354
- const configuring = tracked(customRenderer.then(run, fail));
8355
- root.ready = configuring;
8356
- return configuring;
8449
+ if (previous.status === 'pending') previous.then(run, reject);else run();
8450
+ return promise;
8357
8451
  },
8358
8452
  render(children) {
8359
- if (_roots.get(canvas) !== root) return store;
8360
- // Using the root cancels a teardown waiting on React
8361
- root.unmountClaim = null;
8362
- const element = /*#__PURE__*/jsxRuntime.jsx(Provider, {
8363
- store: store,
8364
- children: children,
8365
- onCreated: onCreated,
8366
- rootElement: canvas
8367
- });
8453
+ if (!transitionRoot(root, {
8454
+ type: 'use'
8455
+ })) return store;
8456
+
8457
+ // The root has to be configured before it can be rendered
8458
+ if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
8459
+ if (root.ready.status === 'rejected') throw root.ready.reason;
8368
8460
  const commit = () => {
8369
- // The root may have been unmounted or claimed while we waited
8370
- if (_roots.get(canvas) !== root || root.unmountClaim) return;
8461
+ var _root$configuration$p;
8462
+ if (root.state.status !== 'open' || root.ready.status === 'rejected') return;
8463
+ // Wait for all queued configuration, including any queued while waiting
8464
+ if (root.ready.status === 'pending') {
8465
+ root.ready.then(commit, logRecoverableError);
8466
+ return;
8467
+ }
8468
+ const onCreated = (_root$configuration$p = root.configuration.previous) == null ? void 0 : _root$configuration$p.onCreated;
8469
+ const element = /*#__PURE__*/jsxRuntime.jsx(Provider, {
8470
+ store: store,
8471
+ children: children,
8472
+ onCreated: onCreated,
8473
+ rootElement: canvas
8474
+ });
8371
8475
  if (mounted) {
8372
8476
  reconciler.updateContainer(element, fiber, null, noop);
8373
8477
  return;
@@ -8379,22 +8483,11 @@ function createRoot(canvas) {
8379
8483
  // @ts-ignore - reconciler types are not maintained
8380
8484
  reconciler.flushSyncWork();
8381
8485
  };
8382
-
8383
- // The root has to be configured before it can be rendered
8384
- if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
8385
- switch (root.ready.status) {
8386
- case 'pending':
8387
- root.ready.then(commit, logRecoverableError);
8388
- break;
8389
- case 'rejected':
8390
- throw root.ready.reason;
8391
- default:
8392
- commit();
8393
- }
8486
+ commit();
8394
8487
  return store;
8395
8488
  },
8396
8489
  unmount() {
8397
- unmountComponentAtNode(canvas);
8490
+ if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
8398
8491
  }
8399
8492
  };
8400
8493
  }
@@ -8425,147 +8518,81 @@ function Provider({
8425
8518
  children: children
8426
8519
  });
8427
8520
  }
8428
- function unmountComponentAtNode(canvas, callback) {
8429
- const root = _roots.get(canvas);
8430
- if (!root) return;
8431
8521
 
8432
- // Cleared by configure and render, which cancels the teardown
8433
- const claim = root.unmountClaim = Symbol('unmount');
8434
- reconciler.updateContainer(null, root.fiber, null, () => {
8435
- if (root.unmountClaim !== claim) return;
8436
-
8437
- // Effect cleanups flush before the next update
8438
- reconciler.updateContainer(null, root.fiber, null, () => {
8439
- if (root.unmountClaim !== claim) return;
8440
- const teardown = () => {
8441
- if (root.unmountClaim !== claim) return;
8442
- root.unmountClaim = null;
8443
- const state = root.store.getState();
8444
- state.internal.active = false;
8445
- try {
8446
- var _state$gl, _state$gl$renderLists, _state$gl2, _state$gl3;
8447
- state.events.disconnect == null ? void 0 : state.events.disconnect();
8448
- (_state$gl = state.gl) == null ? void 0 : (_state$gl$renderLists = _state$gl.renderLists) == null ? void 0 : _state$gl$renderLists.dispose == null ? void 0 : _state$gl$renderLists.dispose();
8449
- (_state$gl2 = state.gl) == null ? void 0 : _state$gl2.forceContextLoss == null ? void 0 : _state$gl2.forceContextLoss();
8450
- if ((_state$gl3 = state.gl) != null && _state$gl3.xr) state.xr.disconnect();
8451
- dispose(state.scene);
8452
- } catch (e) {
8453
- /* ... */
8454
- }
8455
- _roots.delete(canvas);
8456
- if (callback) callback(canvas);
8457
- };
8458
-
8459
- // A renderer still being created has to exist before it can be disposed
8460
- if (root.ready.status === 'pending') root.ready.then(teardown, teardown);else teardown();
8461
- });
8522
+ /**
8523
+ * Frees a renderer R3F built. WebGLRenderer.dispose() releases programs and caches but keeps its
8524
+ * context until garbage collection, and browsers cap live WebGL contexts, so the context is lost
8525
+ * after it. A WebGPURenderer (from a factory) releases its device and context inside dispose().
8526
+ */
8527
+ function disposeRenderer(gl) {
8528
+ // Avoid starting initialization through three's dispose(). A factory must await init()
8529
+ // before returning its renderer so readiness includes initialization and teardown can wait.
8530
+ if ((gl.hasInitialized == null ? void 0 : gl.hasInitialized()) === false) return;
8531
+ const disposed = attempt(() => {
8532
+ var _gl$renderLists;
8533
+ return gl.dispose ? gl.dispose() : (_gl$renderLists = gl.renderLists) == null ? void 0 : _gl$renderLists.dispose == null ? void 0 : _gl$renderLists.dispose();
8462
8534
  });
8535
+ // WebGPURenderer.dispose() is async from three r186
8536
+ if (isPromiseLike(disposed)) {
8537
+ return Promise.resolve(disposed).catch(error => console.warn('[R3F] Error disposing renderer', error)).then(() => attempt(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss()));
8538
+ }
8539
+ attempt(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss());
8463
8540
  }
8464
- function createPortal(children, container, state) {
8465
- return /*#__PURE__*/jsxRuntime.jsx(Portal, {
8466
- children: children,
8467
- container: container,
8468
- state: state
8469
- });
8541
+ function attempt(step) {
8542
+ try {
8543
+ return step();
8544
+ } catch (error) {
8545
+ console.warn('[R3F] Error while unmounting root; teardown may be incomplete:', error);
8546
+ }
8470
8547
  }
8471
- function Portal({
8472
- state = {},
8473
- children,
8474
- container
8475
- }) {
8476
- /** This has to be a component because it would not be able to call useThree/useStore otherwise since
8477
- * if this is our environment, then we are not in r3f's renderer but in react-dom, it would trigger
8478
- * the "R3F hooks can only be used within the Canvas component!" warning:
8479
- * <Canvas>
8480
- * {createPortal(...)} */
8481
- const {
8482
- events,
8483
- size,
8484
- ...rest
8485
- } = state;
8486
- const previousRoot = useStore();
8487
- const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
8488
- const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
8489
- const inject = useMutableCallback((rootState, injectState) => {
8490
- let viewport = undefined;
8491
- if (injectState.camera && size) {
8492
- const camera = injectState.camera;
8493
- // Calculate the override viewport, if present
8494
- viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
8495
- // Update the portal camera, if it differs from the previous layer
8496
- if (camera !== rootState.camera) updateCamera(camera, size);
8548
+ function unmountComponentAtNode(canvas, callback) {
8549
+ const root = _roots.get(canvas);
8550
+ const token = Symbol('unmount');
8551
+ if (!root || !transitionRoot(root, {
8552
+ type: 'unmount',
8553
+ token
8554
+ })) return;
8555
+ const teardown = () => {
8556
+ var _state$gl;
8557
+ // Configuration accepted before the unmount finishes first, so a renderer it creates is released too
8558
+ if (root.ready.status === 'pending') {
8559
+ root.ready.then(teardown, teardown);
8560
+ return;
8497
8561
  }
8498
- return {
8499
- // The intersect consists of the previous root state
8500
- ...rootState,
8501
- ...injectState,
8502
- // Portals have their own scene, which forms the root, a raycaster and a pointer
8503
- scene: container,
8504
- raycaster,
8505
- pointer,
8506
- mouse: pointer,
8507
- // Their previous root is the layer before it
8508
- previousRoot,
8509
- // Events, size and viewport can be overridden by the inject layer
8510
- events: {
8511
- ...rootState.events,
8512
- ...injectState.events,
8513
- ...events
8514
- },
8515
- size: {
8516
- ...rootState.size,
8517
- ...size
8518
- },
8519
- viewport: {
8520
- ...rootState.viewport,
8521
- ...viewport
8522
- },
8523
- // Layers are allowed to override events
8524
- setEvents: events => injectState.set(state => ({
8525
- ...state,
8526
- events: {
8527
- ...state.events,
8528
- ...events
8529
- }
8530
- }))
8531
- };
8562
+ // Refused when the root was used again since this unmount
8563
+ if (!transitionRoot(root, {
8564
+ type: 'dispose',
8565
+ token
8566
+ })) return;
8567
+ // Close the gates before invoking user cleanup code.
8568
+ _roots.delete(canvas);
8569
+ const state = root.store.getState();
8570
+ state.internal.active = false;
8571
+
8572
+ // Release what uses the renderer before the renderer itself
8573
+ attempt(() => state.events.disconnect == null ? void 0 : state.events.disconnect());
8574
+ if ((_state$gl = state.gl) != null && _state$gl.xr) attempt(() => state.xr.disconnect());
8575
+ if (state.scene) attempt(() => dispose(state.scene));
8576
+ const gl = state.gl;
8577
+ let disposal = undefined;
8578
+ if (gl && root.ownsRenderer) {
8579
+ disposal = attempt(() => disposeRenderer(gl));
8580
+ } else if (gl) {
8581
+ // A renderer passed in keeps its 9.x teardown: its context is lost but it is not disposed
8582
+ attempt(() => {
8583
+ var _gl$renderLists2;
8584
+ return (_gl$renderLists2 = gl.renderLists) == null ? void 0 : _gl$renderLists2.dispose == null ? void 0 : _gl$renderLists2.dispose();
8585
+ });
8586
+ attempt(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss());
8587
+ }
8588
+ if (isPromiseLike(disposal)) disposal.then(() => callback == null ? void 0 : callback(canvas));else callback == null ? void 0 : callback(canvas);
8589
+ };
8590
+ reconciler.updateContainer(null, root.fiber, null, () => {
8591
+ // A root used again since the unmount keeps its new children
8592
+ if (root.state.status !== 'closing' || root.state.token !== token) return;
8593
+ // Effect cleanups flush before the next update
8594
+ reconciler.updateContainer(null, root.fiber, null, teardown);
8532
8595
  });
8533
- const usePortalStore = React__namespace.useMemo(() => {
8534
- // Create a mirrored store, based on the previous root with a few overrides ...
8535
- const store = traditional.createWithEqualityFn((set, get) => ({
8536
- ...rest,
8537
- set,
8538
- get
8539
- }));
8540
-
8541
- // Subscribe to previous root-state and copy changes over to the mirrored portal-state
8542
- const onMutate = prev => store.setState(state => inject.current(prev, state));
8543
- onMutate(previousRoot.getState());
8544
- previousRoot.subscribe(onMutate);
8545
- return store;
8546
- // eslint-disable-next-line react-hooks/exhaustive-deps
8547
- }, [previousRoot, container]);
8548
- return (
8549
- /*#__PURE__*/
8550
- // @ts-ignore, reconciler types are not maintained
8551
- jsxRuntime.jsx(jsxRuntime.Fragment, {
8552
- children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
8553
- value: usePortalStore,
8554
- children: children
8555
- }), usePortalStore, null)
8556
- })
8557
- );
8558
- }
8559
-
8560
- /**
8561
- * Force React to flush any updates inside the provided callback synchronously and immediately.
8562
- * All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
8563
- * Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
8564
- * having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
8565
- */
8566
- function flushSync(fn) {
8567
- // @ts-ignore - reconciler types are not maintained
8568
- return reconciler.flushSyncFromReconciler(fn);
8569
8596
  }
8570
8597
 
8571
8598
  function createSubs(callback, subs) {
@@ -8720,6 +8747,102 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
8720
8747
  if (runGlobalEffects) flushGlobalEffects('after', timestamp);
8721
8748
  }
8722
8749
 
8750
+ function createPortal(children, container, state) {
8751
+ return /*#__PURE__*/jsxRuntime.jsx(Portal, {
8752
+ children: children,
8753
+ container: container,
8754
+ state: state
8755
+ });
8756
+ }
8757
+ function Portal({
8758
+ state = {},
8759
+ children,
8760
+ container
8761
+ }) {
8762
+ /** This has to be a component because it would not be able to call useThree/useStore otherwise since
8763
+ * if this is our environment, then we are not in r3f's renderer but in react-dom, it would trigger
8764
+ * the "R3F hooks can only be used within the Canvas component!" warning:
8765
+ * <Canvas>
8766
+ * {createPortal(...)} */
8767
+ const {
8768
+ events,
8769
+ size,
8770
+ ...rest
8771
+ } = state;
8772
+ const previousRoot = useStore();
8773
+ const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
8774
+ const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
8775
+ const inject = useMutableCallback((rootState, injectState) => {
8776
+ let viewport = undefined;
8777
+ if (injectState.camera && size) {
8778
+ const camera = injectState.camera;
8779
+ // Calculate the override viewport, if present
8780
+ viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
8781
+ // Update the portal camera, if it differs from the previous layer
8782
+ if (camera !== rootState.camera) updateCamera(camera, size);
8783
+ }
8784
+ return {
8785
+ // The intersect consists of the previous root state
8786
+ ...rootState,
8787
+ ...injectState,
8788
+ // Portals have their own scene, which forms the root, a raycaster and a pointer
8789
+ scene: container,
8790
+ raycaster,
8791
+ pointer,
8792
+ mouse: pointer,
8793
+ // Their previous root is the layer before it
8794
+ previousRoot,
8795
+ // Events, size and viewport can be overridden by the inject layer
8796
+ events: {
8797
+ ...rootState.events,
8798
+ ...injectState.events,
8799
+ ...events
8800
+ },
8801
+ size: {
8802
+ ...rootState.size,
8803
+ ...size
8804
+ },
8805
+ viewport: {
8806
+ ...rootState.viewport,
8807
+ ...viewport
8808
+ },
8809
+ // Layers are allowed to override events
8810
+ setEvents: events => injectState.set(state => ({
8811
+ ...state,
8812
+ events: {
8813
+ ...state.events,
8814
+ ...events
8815
+ }
8816
+ }))
8817
+ };
8818
+ });
8819
+ const usePortalStore = React__namespace.useMemo(() => {
8820
+ // Create a mirrored store, based on the previous root with a few overrides ...
8821
+ const store = traditional.createWithEqualityFn((set, get) => ({
8822
+ ...rest,
8823
+ set,
8824
+ get
8825
+ }));
8826
+
8827
+ // Subscribe to previous root-state and copy changes over to the mirrored portal-state
8828
+ const onMutate = prev => store.setState(state => inject.current(prev, state));
8829
+ onMutate(previousRoot.getState());
8830
+ previousRoot.subscribe(onMutate);
8831
+ return store;
8832
+ // eslint-disable-next-line react-hooks/exhaustive-deps
8833
+ }, [previousRoot, container]);
8834
+ return (
8835
+ /*#__PURE__*/
8836
+ // @ts-ignore, reconciler types are not maintained
8837
+ jsxRuntime.jsx(jsxRuntime.Fragment, {
8838
+ children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
8839
+ value: usePortalStore,
8840
+ children: children
8841
+ }), usePortalStore, null)
8842
+ })
8843
+ );
8844
+ }
8845
+
8723
8846
  const DOM_EVENTS = {
8724
8847
  onClick: ['click', false],
8725
8848
  onContextMenu: ['contextmenu', false],