@react-three/fiber 8.0.26 → 8.2.0

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.
@@ -1,9 +1,9 @@
1
- import * as React from 'react';
2
- import type { Options as ResizeOptions } from 'react-use-measure';
3
- import { RenderProps } from '../core';
4
- export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
5
- children: React.ReactNode;
6
- fallback?: React.ReactNode;
7
- resize?: ResizeOptions;
8
- }
9
- export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
1
+ import * as React from 'react';
2
+ import type { Options as ResizeOptions } from 'react-use-measure';
3
+ import { RenderProps } from '../core';
4
+ export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
5
+ children: React.ReactNode;
6
+ fallback?: React.ReactNode;
7
+ resize?: ResizeOptions;
8
+ }
9
+ export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
@@ -1,4 +1,4 @@
1
- import { UseBoundStore } from 'zustand';
2
- import { RootState } from '../core/store';
3
- import { EventManager } from '../core/events';
4
- export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
1
+ import { UseBoundStore } from 'zustand';
2
+ import { RootState } from '../core/store';
3
+ import { EventManager } from '../core/events';
4
+ export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
@@ -855,7 +855,7 @@ let extend = objects => void (catalogue = { ...catalogue,
855
855
  ...objects
856
856
  });
857
857
 
858
- function createRenderer(roots, getEventPriority) {
858
+ function createRenderer(_roots, _getEventPriority) {
859
859
  function createInstance(type, {
860
860
  args = [],
861
861
  attach,
@@ -1071,10 +1071,10 @@ function createRenderer(roots, getEventPriority) {
1071
1071
  appendChild,
1072
1072
  appendInitialChild: appendChild,
1073
1073
  insertBefore,
1074
- supportsMicrotask: true,
1075
- warnsIfNotActing: true,
1076
1074
  supportsMutation: true,
1077
1075
  isPrimaryRenderer: false,
1076
+ supportsPersistence: false,
1077
+ supportsHydration: false,
1078
1078
  noTimeout: -1,
1079
1079
  appendChildToContainer: (container, child) => {
1080
1080
  const scene = container.getState().scene; // Link current root to the default scene
@@ -1093,10 +1093,10 @@ function createRenderer(roots, getEventPriority) {
1093
1093
  const localState = (_instance$__r3f2 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f2 : {}; // https://github.com/facebook/react/issues/20271
1094
1094
  // Returning true will trigger commitMount
1095
1095
 
1096
- return !!localState.handlers;
1096
+ return Boolean(localState.handlers);
1097
1097
  },
1098
1098
 
1099
- prepareUpdate(instance, type, oldProps, newProps) {
1099
+ prepareUpdate(instance, _type, oldProps, newProps) {
1100
1100
  // Create diff-sets
1101
1101
  if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
1102
1102
  return [true];
@@ -1113,7 +1113,7 @@ function createRenderer(roots, getEventPriority) {
1113
1113
  ...restOld
1114
1114
  } = oldProps; // Throw if an object or literal was passed for args
1115
1115
 
1116
- if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instanciated
1116
+ if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instantiated
1117
1117
 
1118
1118
  if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
1119
1119
 
@@ -1124,13 +1124,13 @@ function createRenderer(roots, getEventPriority) {
1124
1124
  }
1125
1125
  },
1126
1126
 
1127
- commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
1127
+ commitUpdate(instance, [reconstruct, diff], type, _oldProps, newProps, fiber) {
1128
1128
  // Reconstruct when args or <primitive object={...} have changes
1129
1129
  if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
1130
1130
  else applyProps$1(instance, diff);
1131
1131
  },
1132
1132
 
1133
- commitMount(instance, type, props, int) {
1133
+ commitMount(instance, _type, _props, _int) {
1134
1134
  var _instance$__r3f3;
1135
1135
 
1136
1136
  // https://github.com/facebook/react/issues/20271
@@ -1143,13 +1143,11 @@ function createRenderer(roots, getEventPriority) {
1143
1143
  },
1144
1144
 
1145
1145
  getPublicInstance: instance => instance,
1146
- shouldDeprioritizeSubtree: () => false,
1147
1146
  prepareForCommit: () => null,
1148
1147
  preparePortalMount: container => prepare(container.getState().scene),
1149
1148
  resetAfterCommit: () => {},
1150
1149
  shouldSetTextContent: () => false,
1151
1150
  clearContainer: () => false,
1152
- detachDeletedInstance: () => {},
1153
1151
 
1154
1152
  hideInstance(instance) {
1155
1153
  var _instance$__r3f4;
@@ -1177,20 +1175,23 @@ function createRenderer(roots, getEventPriority) {
1177
1175
  invalidateInstance(instance);
1178
1176
  },
1179
1177
 
1180
- createTextInstance: () => {},
1178
+ createTextInstance: () => {
1179
+ throw new Error('Text is not allowed in the R3F tree.');
1180
+ },
1181
1181
  hideTextInstance: () => {
1182
1182
  throw new Error('Text is not allowed in the R3F tree.');
1183
1183
  },
1184
1184
  unhideTextInstance: () => {},
1185
- getCurrentEventPriority: () => getEventPriority ? getEventPriority() : constants.DefaultEventPriority,
1186
- // @ts-ignore
1187
- now: typeof performance !== 'undefined' && is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : undefined,
1185
+ // https://github.com/pmndrs/react-three-fiber/pull/2360#discussion_r916356874
1188
1186
  // @ts-ignore
1187
+ getCurrentEventPriority: () => _getEventPriority ? _getEventPriority() : constants.DefaultEventPriority,
1188
+ beforeActiveInstanceBlur: () => {},
1189
+ afterActiveInstanceBlur: () => {},
1190
+ detachDeletedInstance: () => {},
1191
+ now: typeof performance !== 'undefined' && is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : () => 0,
1192
+ // https://github.com/pmndrs/react-three-fiber/pull/2360#discussion_r920883503
1189
1193
  scheduleTimeout: is.fun(setTimeout) ? setTimeout : undefined,
1190
- // @ts-ignore
1191
- cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
1192
- setTimeout: is.fun(setTimeout) ? setTimeout : undefined,
1193
- clearTimeout: is.fun(clearTimeout) ? clearTimeout : undefined
1194
+ cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined
1194
1195
  });
1195
1196
  return {
1196
1197
  reconciler,
@@ -1211,7 +1212,9 @@ const createStore = (invalidate, advance) => {
1211
1212
  function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
1212
1213
  const {
1213
1214
  width,
1214
- height
1215
+ height,
1216
+ top,
1217
+ left
1215
1218
  } = size;
1216
1219
  const aspect = width / height;
1217
1220
  if (target instanceof THREE__namespace.Vector3) tempTarget.copy(target);else tempTarget.set(...target);
@@ -1221,6 +1224,8 @@ const createStore = (invalidate, advance) => {
1221
1224
  return {
1222
1225
  width: width / camera.zoom,
1223
1226
  height: height / camera.zoom,
1227
+ top,
1228
+ left,
1224
1229
  factor: 1,
1225
1230
  distance,
1226
1231
  aspect
@@ -1234,6 +1239,8 @@ const createStore = (invalidate, advance) => {
1234
1239
  return {
1235
1240
  width: w,
1236
1241
  height: h,
1242
+ top,
1243
+ left,
1237
1244
  factor: width / w,
1238
1245
  distance,
1239
1246
  aspect
@@ -1250,7 +1257,7 @@ const createStore = (invalidate, advance) => {
1250
1257
  }));
1251
1258
 
1252
1259
  const pointer = new THREE__namespace.Vector2();
1253
- return {
1260
+ const rootState = {
1254
1261
  set,
1255
1262
  get,
1256
1263
  // Mock objects that have to be configured
@@ -1293,6 +1300,8 @@ const createStore = (invalidate, advance) => {
1293
1300
  size: {
1294
1301
  width: 0,
1295
1302
  height: 0,
1303
+ top: 0,
1304
+ left: 0,
1296
1305
  updateStyle: false
1297
1306
  },
1298
1307
  viewport: {
@@ -1300,6 +1309,8 @@ const createStore = (invalidate, advance) => {
1300
1309
  dpr: 0,
1301
1310
  width: 0,
1302
1311
  height: 0,
1312
+ top: 0,
1313
+ left: 0,
1303
1314
  aspect: 0,
1304
1315
  distance: 0,
1305
1316
  factor: 0,
@@ -1310,11 +1321,13 @@ const createStore = (invalidate, advance) => {
1310
1321
  ...events
1311
1322
  }
1312
1323
  })),
1313
- setSize: (width, height, updateStyle) => {
1324
+ setSize: (width, height, updateStyle, top, left) => {
1314
1325
  const camera = get().camera;
1315
1326
  const size = {
1316
1327
  width,
1317
1328
  height,
1329
+ top: top || 0,
1330
+ left: left || 0,
1318
1331
  updateStyle
1319
1332
  };
1320
1333
  set(state => ({
@@ -1388,6 +1401,7 @@ const createStore = (invalidate, advance) => {
1388
1401
  }
1389
1402
  }
1390
1403
  };
1404
+ return rootState;
1391
1405
  });
1392
1406
  const state = rootState.getState();
1393
1407
  let oldSize = state.size;
@@ -1429,15 +1443,17 @@ const createStore = (invalidate, advance) => {
1429
1443
  };
1430
1444
 
1431
1445
  function createSubs(callback, subs) {
1432
- const index = subs.length;
1433
- subs.push(callback);
1434
- return () => void subs.splice(index, 1);
1446
+ const sub = {
1447
+ callback
1448
+ };
1449
+ subs.add(sub);
1450
+ return () => void subs.delete(sub);
1435
1451
  }
1436
1452
 
1437
1453
  let i;
1438
- let globalEffects = [];
1439
- let globalAfterEffects = [];
1440
- let globalTailEffects = [];
1454
+ let globalEffects = new Set();
1455
+ let globalAfterEffects = new Set();
1456
+ let globalTailEffects = new Set();
1441
1457
  /**
1442
1458
  * Adds a global render callback which is called each frame.
1443
1459
  * @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
@@ -1458,7 +1474,9 @@ const addAfterEffect = callback => createSubs(callback, globalAfterEffects);
1458
1474
  const addTail = callback => createSubs(callback, globalTailEffects);
1459
1475
 
1460
1476
  function run(effects, timestamp) {
1461
- for (i = 0; i < effects.length; i++) effects[i](timestamp);
1477
+ effects.forEach(({
1478
+ callback
1479
+ }) => callback(timestamp));
1462
1480
  }
1463
1481
 
1464
1482
  let subscribers;
@@ -1500,7 +1518,7 @@ function createLoop(roots) {
1500
1518
  running = true;
1501
1519
  repeat = 0; // Run effects
1502
1520
 
1503
- if (globalEffects.length) run(globalEffects, timestamp); // Render all roots
1521
+ if (globalEffects.size) run(globalEffects, timestamp); // Render all roots
1504
1522
 
1505
1523
  roots.forEach(root => {
1506
1524
  var _state$gl$xr;
@@ -1512,11 +1530,11 @@ function createLoop(roots) {
1512
1530
  }
1513
1531
  }); // Run after-effects
1514
1532
 
1515
- if (globalAfterEffects.length) run(globalAfterEffects, timestamp); // Stop the loop if nothing invalidates it
1533
+ if (globalAfterEffects.size) run(globalAfterEffects, timestamp); // Stop the loop if nothing invalidates it
1516
1534
 
1517
1535
  if (repeat === 0) {
1518
1536
  // Tail call effects, they are called when rendering stops
1519
- if (globalTailEffects.length) run(globalTailEffects, timestamp); // Flag end of operation
1537
+ if (globalTailEffects.size) run(globalTailEffects, timestamp); // Flag end of operation
1520
1538
 
1521
1539
  running = false;
1522
1540
  return cancelAnimationFrame(frame);
@@ -1695,8 +1713,6 @@ function createRoot(canvas) {
1695
1713
  let configured = false;
1696
1714
  return {
1697
1715
  configure(props = {}) {
1698
- var _canvas$parentElement, _canvas$parentElement2, _canvas$parentElement3, _canvas$parentElement4;
1699
-
1700
1716
  let {
1701
1717
  gl: glConfig,
1702
1718
  size,
@@ -1765,12 +1781,10 @@ function createRoot(canvas) {
1765
1781
 
1766
1782
 
1767
1783
  const handleSessionChange = () => {
1768
- const gl = store.getState().gl;
1769
- gl.xr.enabled = gl.xr.isPresenting; // @ts-ignore
1770
- // WebXRManager's signature is incorrect.
1771
- // See: https://github.com/pmndrs/react-three-fiber/pull/2017#discussion_r790134505
1772
-
1773
- gl.xr.setAnimationLoop(gl.xr.isPresenting ? handleXRFrame : null);
1784
+ const state = store.getState();
1785
+ state.gl.xr.enabled = state.gl.xr.isPresenting;
1786
+ state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
1787
+ if (!state.gl.xr.isPresenting) invalidate(state);
1774
1788
  }; // WebXR session manager
1775
1789
 
1776
1790
 
@@ -1836,11 +1850,22 @@ function createRoot(canvas) {
1836
1850
 
1837
1851
  if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr); // Check size, allow it to take on container bounds initially
1838
1852
 
1839
- size = size || {
1840
- width: (_canvas$parentElement = (_canvas$parentElement2 = canvas.parentElement) == null ? void 0 : _canvas$parentElement2.clientWidth) != null ? _canvas$parentElement : 0,
1841
- height: (_canvas$parentElement3 = (_canvas$parentElement4 = canvas.parentElement) == null ? void 0 : _canvas$parentElement4.clientHeight) != null ? _canvas$parentElement3 : 0
1842
- };
1843
- if (!is.equ(size, state.size, shallowLoose)) state.setSize(size.width, size.height, size.updateStyle); // Check frameloop
1853
+ size = size || (canvas.parentElement ? {
1854
+ width: canvas.parentElement.clientWidth,
1855
+ height: canvas.parentElement.clientHeight,
1856
+ top: canvas.parentElement.clientTop,
1857
+ left: canvas.parentElement.clientLeft
1858
+ } : {
1859
+ width: 0,
1860
+ height: 0,
1861
+ top: 0,
1862
+ left: 0
1863
+ });
1864
+
1865
+ if (!is.equ(size, state.size, shallowLoose)) {
1866
+ state.setSize(size.width, size.height, size.updateStyle, size.top, size.left);
1867
+ } // Check frameloop
1868
+
1844
1869
 
1845
1870
  if (state.frameloop !== frameloop) state.setFrameloop(frameloop); // Check pointer missed
1846
1871
 
@@ -828,7 +828,7 @@ let extend = objects => void (catalogue = { ...catalogue,
828
828
  ...objects
829
829
  });
830
830
 
831
- function createRenderer(roots, getEventPriority) {
831
+ function createRenderer(_roots, _getEventPriority) {
832
832
  function createInstance(type, {
833
833
  args = [],
834
834
  attach,
@@ -1044,10 +1044,10 @@ function createRenderer(roots, getEventPriority) {
1044
1044
  appendChild,
1045
1045
  appendInitialChild: appendChild,
1046
1046
  insertBefore,
1047
- supportsMicrotask: true,
1048
- warnsIfNotActing: true,
1049
1047
  supportsMutation: true,
1050
1048
  isPrimaryRenderer: false,
1049
+ supportsPersistence: false,
1050
+ supportsHydration: false,
1051
1051
  noTimeout: -1,
1052
1052
  appendChildToContainer: (container, child) => {
1053
1053
  const scene = container.getState().scene; // Link current root to the default scene
@@ -1066,10 +1066,10 @@ function createRenderer(roots, getEventPriority) {
1066
1066
  const localState = (_instance$__r3f2 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f2 : {}; // https://github.com/facebook/react/issues/20271
1067
1067
  // Returning true will trigger commitMount
1068
1068
 
1069
- return !!localState.handlers;
1069
+ return Boolean(localState.handlers);
1070
1070
  },
1071
1071
 
1072
- prepareUpdate(instance, type, oldProps, newProps) {
1072
+ prepareUpdate(instance, _type, oldProps, newProps) {
1073
1073
  // Create diff-sets
1074
1074
  if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
1075
1075
  return [true];
@@ -1086,7 +1086,7 @@ function createRenderer(roots, getEventPriority) {
1086
1086
  ...restOld
1087
1087
  } = oldProps; // Throw if an object or literal was passed for args
1088
1088
 
1089
- if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instanciated
1089
+ if (!Array.isArray(argsNew)) throw 'The args prop must be an array!'; // If it has new props or arguments, then it needs to be re-instantiated
1090
1090
 
1091
1091
  if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
1092
1092
 
@@ -1097,13 +1097,13 @@ function createRenderer(roots, getEventPriority) {
1097
1097
  }
1098
1098
  },
1099
1099
 
1100
- commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
1100
+ commitUpdate(instance, [reconstruct, diff], type, _oldProps, newProps, fiber) {
1101
1101
  // Reconstruct when args or <primitive object={...} have changes
1102
1102
  if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
1103
1103
  else applyProps$1(instance, diff);
1104
1104
  },
1105
1105
 
1106
- commitMount(instance, type, props, int) {
1106
+ commitMount(instance, _type, _props, _int) {
1107
1107
  var _instance$__r3f3;
1108
1108
 
1109
1109
  // https://github.com/facebook/react/issues/20271
@@ -1116,13 +1116,11 @@ function createRenderer(roots, getEventPriority) {
1116
1116
  },
1117
1117
 
1118
1118
  getPublicInstance: instance => instance,
1119
- shouldDeprioritizeSubtree: () => false,
1120
1119
  prepareForCommit: () => null,
1121
1120
  preparePortalMount: container => prepare(container.getState().scene),
1122
1121
  resetAfterCommit: () => {},
1123
1122
  shouldSetTextContent: () => false,
1124
1123
  clearContainer: () => false,
1125
- detachDeletedInstance: () => {},
1126
1124
 
1127
1125
  hideInstance(instance) {
1128
1126
  var _instance$__r3f4;
@@ -1150,20 +1148,23 @@ function createRenderer(roots, getEventPriority) {
1150
1148
  invalidateInstance(instance);
1151
1149
  },
1152
1150
 
1153
- createTextInstance: () => {},
1151
+ createTextInstance: () => {
1152
+ throw new Error('Text is not allowed in the R3F tree.');
1153
+ },
1154
1154
  hideTextInstance: () => {
1155
1155
  throw new Error('Text is not allowed in the R3F tree.');
1156
1156
  },
1157
1157
  unhideTextInstance: () => {},
1158
- getCurrentEventPriority: () => getEventPriority ? getEventPriority() : DefaultEventPriority,
1159
- // @ts-ignore
1160
- now: typeof performance !== 'undefined' && is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : undefined,
1158
+ // https://github.com/pmndrs/react-three-fiber/pull/2360#discussion_r916356874
1161
1159
  // @ts-ignore
1160
+ getCurrentEventPriority: () => _getEventPriority ? _getEventPriority() : DefaultEventPriority,
1161
+ beforeActiveInstanceBlur: () => {},
1162
+ afterActiveInstanceBlur: () => {},
1163
+ detachDeletedInstance: () => {},
1164
+ now: typeof performance !== 'undefined' && is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : () => 0,
1165
+ // https://github.com/pmndrs/react-three-fiber/pull/2360#discussion_r920883503
1162
1166
  scheduleTimeout: is.fun(setTimeout) ? setTimeout : undefined,
1163
- // @ts-ignore
1164
- cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
1165
- setTimeout: is.fun(setTimeout) ? setTimeout : undefined,
1166
- clearTimeout: is.fun(clearTimeout) ? clearTimeout : undefined
1167
+ cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined
1167
1168
  });
1168
1169
  return {
1169
1170
  reconciler,
@@ -1184,7 +1185,9 @@ const createStore = (invalidate, advance) => {
1184
1185
  function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
1185
1186
  const {
1186
1187
  width,
1187
- height
1188
+ height,
1189
+ top,
1190
+ left
1188
1191
  } = size;
1189
1192
  const aspect = width / height;
1190
1193
  if (target instanceof THREE.Vector3) tempTarget.copy(target);else tempTarget.set(...target);
@@ -1194,6 +1197,8 @@ const createStore = (invalidate, advance) => {
1194
1197
  return {
1195
1198
  width: width / camera.zoom,
1196
1199
  height: height / camera.zoom,
1200
+ top,
1201
+ left,
1197
1202
  factor: 1,
1198
1203
  distance,
1199
1204
  aspect
@@ -1207,6 +1212,8 @@ const createStore = (invalidate, advance) => {
1207
1212
  return {
1208
1213
  width: w,
1209
1214
  height: h,
1215
+ top,
1216
+ left,
1210
1217
  factor: width / w,
1211
1218
  distance,
1212
1219
  aspect
@@ -1223,7 +1230,7 @@ const createStore = (invalidate, advance) => {
1223
1230
  }));
1224
1231
 
1225
1232
  const pointer = new THREE.Vector2();
1226
- return {
1233
+ const rootState = {
1227
1234
  set,
1228
1235
  get,
1229
1236
  // Mock objects that have to be configured
@@ -1266,6 +1273,8 @@ const createStore = (invalidate, advance) => {
1266
1273
  size: {
1267
1274
  width: 0,
1268
1275
  height: 0,
1276
+ top: 0,
1277
+ left: 0,
1269
1278
  updateStyle: false
1270
1279
  },
1271
1280
  viewport: {
@@ -1273,6 +1282,8 @@ const createStore = (invalidate, advance) => {
1273
1282
  dpr: 0,
1274
1283
  width: 0,
1275
1284
  height: 0,
1285
+ top: 0,
1286
+ left: 0,
1276
1287
  aspect: 0,
1277
1288
  distance: 0,
1278
1289
  factor: 0,
@@ -1283,11 +1294,13 @@ const createStore = (invalidate, advance) => {
1283
1294
  ...events
1284
1295
  }
1285
1296
  })),
1286
- setSize: (width, height, updateStyle) => {
1297
+ setSize: (width, height, updateStyle, top, left) => {
1287
1298
  const camera = get().camera;
1288
1299
  const size = {
1289
1300
  width,
1290
1301
  height,
1302
+ top: top || 0,
1303
+ left: left || 0,
1291
1304
  updateStyle
1292
1305
  };
1293
1306
  set(state => ({
@@ -1361,6 +1374,7 @@ const createStore = (invalidate, advance) => {
1361
1374
  }
1362
1375
  }
1363
1376
  };
1377
+ return rootState;
1364
1378
  });
1365
1379
  const state = rootState.getState();
1366
1380
  let oldSize = state.size;
@@ -1402,15 +1416,17 @@ const createStore = (invalidate, advance) => {
1402
1416
  };
1403
1417
 
1404
1418
  function createSubs(callback, subs) {
1405
- const index = subs.length;
1406
- subs.push(callback);
1407
- return () => void subs.splice(index, 1);
1419
+ const sub = {
1420
+ callback
1421
+ };
1422
+ subs.add(sub);
1423
+ return () => void subs.delete(sub);
1408
1424
  }
1409
1425
 
1410
1426
  let i;
1411
- let globalEffects = [];
1412
- let globalAfterEffects = [];
1413
- let globalTailEffects = [];
1427
+ let globalEffects = new Set();
1428
+ let globalAfterEffects = new Set();
1429
+ let globalTailEffects = new Set();
1414
1430
  /**
1415
1431
  * Adds a global render callback which is called each frame.
1416
1432
  * @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
@@ -1431,7 +1447,9 @@ const addAfterEffect = callback => createSubs(callback, globalAfterEffects);
1431
1447
  const addTail = callback => createSubs(callback, globalTailEffects);
1432
1448
 
1433
1449
  function run(effects, timestamp) {
1434
- for (i = 0; i < effects.length; i++) effects[i](timestamp);
1450
+ effects.forEach(({
1451
+ callback
1452
+ }) => callback(timestamp));
1435
1453
  }
1436
1454
 
1437
1455
  let subscribers;
@@ -1473,7 +1491,7 @@ function createLoop(roots) {
1473
1491
  running = true;
1474
1492
  repeat = 0; // Run effects
1475
1493
 
1476
- if (globalEffects.length) run(globalEffects, timestamp); // Render all roots
1494
+ if (globalEffects.size) run(globalEffects, timestamp); // Render all roots
1477
1495
 
1478
1496
  roots.forEach(root => {
1479
1497
  var _state$gl$xr;
@@ -1485,11 +1503,11 @@ function createLoop(roots) {
1485
1503
  }
1486
1504
  }); // Run after-effects
1487
1505
 
1488
- if (globalAfterEffects.length) run(globalAfterEffects, timestamp); // Stop the loop if nothing invalidates it
1506
+ if (globalAfterEffects.size) run(globalAfterEffects, timestamp); // Stop the loop if nothing invalidates it
1489
1507
 
1490
1508
  if (repeat === 0) {
1491
1509
  // Tail call effects, they are called when rendering stops
1492
- if (globalTailEffects.length) run(globalTailEffects, timestamp); // Flag end of operation
1510
+ if (globalTailEffects.size) run(globalTailEffects, timestamp); // Flag end of operation
1493
1511
 
1494
1512
  running = false;
1495
1513
  return cancelAnimationFrame(frame);
@@ -1668,8 +1686,6 @@ function createRoot(canvas) {
1668
1686
  let configured = false;
1669
1687
  return {
1670
1688
  configure(props = {}) {
1671
- var _canvas$parentElement, _canvas$parentElement2, _canvas$parentElement3, _canvas$parentElement4;
1672
-
1673
1689
  let {
1674
1690
  gl: glConfig,
1675
1691
  size,
@@ -1738,12 +1754,10 @@ function createRoot(canvas) {
1738
1754
 
1739
1755
 
1740
1756
  const handleSessionChange = () => {
1741
- const gl = store.getState().gl;
1742
- gl.xr.enabled = gl.xr.isPresenting; // @ts-ignore
1743
- // WebXRManager's signature is incorrect.
1744
- // See: https://github.com/pmndrs/react-three-fiber/pull/2017#discussion_r790134505
1745
-
1746
- gl.xr.setAnimationLoop(gl.xr.isPresenting ? handleXRFrame : null);
1757
+ const state = store.getState();
1758
+ state.gl.xr.enabled = state.gl.xr.isPresenting;
1759
+ state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
1760
+ if (!state.gl.xr.isPresenting) invalidate(state);
1747
1761
  }; // WebXR session manager
1748
1762
 
1749
1763
 
@@ -1809,11 +1823,22 @@ function createRoot(canvas) {
1809
1823
 
1810
1824
  if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr); // Check size, allow it to take on container bounds initially
1811
1825
 
1812
- size = size || {
1813
- width: (_canvas$parentElement = (_canvas$parentElement2 = canvas.parentElement) == null ? void 0 : _canvas$parentElement2.clientWidth) != null ? _canvas$parentElement : 0,
1814
- height: (_canvas$parentElement3 = (_canvas$parentElement4 = canvas.parentElement) == null ? void 0 : _canvas$parentElement4.clientHeight) != null ? _canvas$parentElement3 : 0
1815
- };
1816
- if (!is.equ(size, state.size, shallowLoose)) state.setSize(size.width, size.height, size.updateStyle); // Check frameloop
1826
+ size = size || (canvas.parentElement ? {
1827
+ width: canvas.parentElement.clientWidth,
1828
+ height: canvas.parentElement.clientHeight,
1829
+ top: canvas.parentElement.clientTop,
1830
+ left: canvas.parentElement.clientLeft
1831
+ } : {
1832
+ width: 0,
1833
+ height: 0,
1834
+ top: 0,
1835
+ left: 0
1836
+ });
1837
+
1838
+ if (!is.equ(size, state.size, shallowLoose)) {
1839
+ state.setSize(size.width, size.height, size.updateStyle, size.top, size.left);
1840
+ } // Check frameloop
1841
+
1817
1842
 
1818
1843
  if (state.frameloop !== frameloop) state.setFrameloop(frameloop); // Check pointer missed
1819
1844