@react-three/fiber 8.0.8 → 8.0.11

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>;
@@ -10,11 +10,17 @@ var threeTypes = /*#__PURE__*/Object.freeze({
10
10
  __proto__: null
11
11
  });
12
12
 
13
- // React currently throws a warning when using useLayoutEffect on the server.
13
+ const isOrthographicCamera = def => def && def.isOrthographicCamera; // React currently throws a warning when using useLayoutEffect on the server.
14
14
  // To get around it, we can conditionally useEffect on the server (no-op) and
15
15
  // useLayoutEffect on the client.
16
+
16
17
  const isSSR = typeof window === 'undefined' || !window.navigator || /ServerSideRendering|^Deno\//.test(window.navigator.userAgent);
17
18
  const useIsomorphicLayoutEffect = isSSR ? React.useEffect : React.useLayoutEffect;
19
+ function useMutableCallback(fn) {
20
+ const ref = React.useRef(fn);
21
+ useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
22
+ return ref;
23
+ }
18
24
  function Block({
19
25
  set
20
26
  }) {
@@ -46,11 +52,6 @@ ErrorBoundary.getDerivedStateFromError = () => ({
46
52
  error: true
47
53
  });
48
54
 
49
- function useMemoizedFn(fn) {
50
- const fnRef = React.useRef(fn);
51
- useIsomorphicLayoutEffect(() => void (fnRef.current = fn), [fn]);
52
- return (...args) => fnRef.current == null ? void 0 : fnRef.current(...args);
53
- }
54
55
  const DEFAULT = '__default';
55
56
  const isDiffSet = def => def && !!def.memoized && !!def.changes;
56
57
  function calculateDpr(dpr) {
@@ -65,29 +66,6 @@ const getRootState = obj => {
65
66
 
66
67
  return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
67
68
  };
68
- /**
69
- * Picks or omits keys from an object
70
- * `omit` will filter out keys, and otherwise cherry-pick them.
71
- */
72
-
73
- function filterKeys(obj, omit, ...keys) {
74
- const keysToSelect = new Set(keys);
75
- return Object.entries(obj).reduce((acc, [key, value]) => {
76
- const shouldInclude = !omit;
77
- if (keysToSelect.has(key) === shouldInclude) acc[key] = value;
78
- return acc;
79
- }, {});
80
- }
81
- /**
82
- * Clones an object and cherry-picks keys.
83
- */
84
-
85
- const pick = (obj, keys) => filterKeys(obj, false, ...keys);
86
- /**
87
- * Clones an object and prunes or omits keys.
88
- */
89
-
90
- const omit = (obj, keys) => filterKeys(obj, true, ...keys);
91
69
  // A collection of compare functions
92
70
  const is = {
93
71
  obj: a => a === Object(a) && !is.arr(a) && typeof a !== 'function',
@@ -313,12 +291,16 @@ function applyProps$1(instance, data) {
313
291
 
314
292
  if (value === DEFAULT + 'remove') {
315
293
  if (targetProp && targetProp.constructor) {
294
+ var _memoized$args;
295
+
316
296
  // use the prop constructor to find the default it should be
317
- value = new targetProp.constructor(...memoized.args);
297
+ value = new targetProp.constructor(...((_memoized$args = memoized.args) != null ? _memoized$args : []));
318
298
  } else if (currentInstance.constructor) {
299
+ var _currentInstance$__r;
300
+
319
301
  // create a blank slate of the instance and copy the particular parameter.
320
302
  // @ts-ignore
321
- const defaultClassCall = new currentInstance.constructor(...currentInstance.__r3f.memoizedProps.args);
303
+ const defaultClassCall = new currentInstance.constructor(...((_currentInstance$__r = currentInstance.__r3f.memoizedProps.args) != null ? _currentInstance$__r : []));
322
304
  value = defaultClassCall[targetProp]; // destory the instance
323
305
 
324
306
  if (defaultClassCall.dispose) defaultClassCall.dispose(); // instance does not have constructor, just set it to 0
@@ -387,6 +369,25 @@ function invalidateInstance(instance) {
387
369
  function updateInstance(instance) {
388
370
  instance.onUpdate == null ? void 0 : instance.onUpdate(instance);
389
371
  }
372
+ function updateCamera(camera, size) {
373
+ // https://github.com/pmndrs/react-three-fiber/issues/92
374
+ // Do not mess with the camera if it belongs to the user
375
+ if (!camera.manual) {
376
+ if (isOrthographicCamera(camera)) {
377
+ camera.left = size.width / -2;
378
+ camera.right = size.width / 2;
379
+ camera.top = size.height / 2;
380
+ camera.bottom = size.height / -2;
381
+ } else {
382
+ camera.aspect = size.width / size.height;
383
+ }
384
+
385
+ camera.updateProjectionMatrix(); // https://github.com/pmndrs/react-three-fiber/issues/178
386
+ // Update matrix world since the renderer is a frame late
387
+
388
+ camera.updateMatrixWorld();
389
+ }
390
+ }
390
391
 
391
392
  function makeId(event) {
392
393
  return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
@@ -1159,8 +1160,8 @@ function createRenderer(roots, getEventPriority) {
1159
1160
  };
1160
1161
  }
1161
1162
 
1163
+ const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'performance', 'internal', 'size', 'viewport'];
1162
1164
  const isRenderer = def => !!(def != null && def.render);
1163
- const isOrthographicCamera = def => def && def.isOrthographicCamera;
1164
1165
  const context = /*#__PURE__*/React.createContext(null);
1165
1166
 
1166
1167
  const createStore = (invalidate, advance) => {
@@ -1367,24 +1368,7 @@ const createStore = (invalidate, advance) => {
1367
1368
  } = rootState.getState();
1368
1369
 
1369
1370
  if (size !== oldSize || viewport.dpr !== oldDpr) {
1370
- // https://github.com/pmndrs/react-three-fiber/issues/92
1371
- // Do not mess with the camera if it belongs to the user
1372
- if (!camera.manual) {
1373
- if (isOrthographicCamera(camera)) {
1374
- camera.left = size.width / -2;
1375
- camera.right = size.width / 2;
1376
- camera.top = size.height / 2;
1377
- camera.bottom = size.height / -2;
1378
- } else {
1379
- camera.aspect = size.width / size.height;
1380
- }
1381
-
1382
- camera.updateProjectionMatrix(); // https://github.com/pmndrs/react-three-fiber/issues/178
1383
- // Update matrix world since the renderer is a frame late
1384
-
1385
- camera.updateMatrixWorld();
1386
- } // Update renderer
1387
-
1371
+ updateCamera(camera, size); // Update renderer
1388
1372
 
1389
1373
  gl.setPixelRatio(viewport.dpr);
1390
1374
  gl.setSize(size.width, size.height);
@@ -1551,12 +1535,11 @@ function useThree(selector = state => state, equalityFn) {
1551
1535
 
1552
1536
  function useFrame(callback, renderPriority = 0) {
1553
1537
  const store = useStore();
1554
- const subscribe = store.getState().internal.subscribe; // Update ref
1538
+ const subscribe = store.getState().internal.subscribe; // Memoize ref
1555
1539
 
1556
- const ref = React.useRef(callback);
1557
- React.useLayoutEffect(() => void (ref.current = callback), [callback]); // Subscribe on mount, unsubscribe on unmount
1540
+ const ref = useMutableCallback(callback); // Subscribe on mount, unsubscribe on unmount
1558
1541
 
1559
- React.useLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
1542
+ useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
1560
1543
  return null;
1561
1544
  }
1562
1545
  /**
@@ -1924,6 +1907,7 @@ function Portal({
1924
1907
  * {createPortal(...)} */
1925
1908
  const {
1926
1909
  events,
1910
+ size,
1927
1911
  ...rest
1928
1912
  } = state;
1929
1913
  const previousRoot = useStore();
@@ -1935,45 +1919,79 @@ function Portal({
1935
1919
 
1936
1920
  if (injectState) {
1937
1921
  // Only the fields of "state" that do not differ from injectState
1922
+ // Some props should be off-limits
1923
+ // Otherwise filter out the props that are different and let the inject layer take precedence
1938
1924
  Object.keys(state).forEach(key => {
1939
1925
  if ( // Some props should be off-limits
1940
- !['size', 'viewport', 'internal', 'performance'].includes(key) && // Otherwise filter out the props that are different and let the inject layer take precedence
1926
+ !privateKeys.includes(key) && // Otherwise filter out the props that are different and let the inject layer take precedence
1941
1927
  state[key] !== injectState[key]) delete intersect[key];
1942
1928
  });
1943
1929
  }
1944
1930
 
1945
- return { ...intersect,
1931
+ let viewport = undefined;
1932
+
1933
+ if (injectState && size) {
1934
+ const camera = injectState.camera; // Calculate the override viewport, if present
1935
+
1936
+ viewport = state.viewport.getCurrentViewport(camera, new THREE.Vector3(), size); // Update the portal camera, if it differs from the previous layer
1937
+
1938
+ if (camera !== state.camera) updateCamera(camera, size);
1939
+ }
1940
+
1941
+ return { // The intersect consists of the previous root state
1942
+ ...intersect,
1943
+ // Portals have their own scene, which forms the root, a raycaster and a pointer
1946
1944
  scene: container,
1947
- previousRoot,
1948
1945
  raycaster,
1946
+ pointer,
1947
+ mouse: pointer,
1948
+ // Their previous root is the layer before it
1949
+ previousRoot,
1950
+ // Events, size and viewport can be overridden by the inject layer
1949
1951
  events: { ...state.events,
1950
1952
  ...(injectState == null ? void 0 : injectState.events),
1951
- pointer,
1952
- mouse: pointer,
1953
1953
  ...events
1954
1954
  },
1955
+ size: { ...state.size,
1956
+ ...size
1957
+ },
1958
+ viewport: { ...state.viewport,
1959
+ ...viewport
1960
+ },
1955
1961
  ...rest
1956
1962
  };
1957
1963
  }, [state]);
1958
- const [useInjectStore] = React.useState(() => {
1959
- const store = create((set, get) => ({ ...inject(previousRoot.getState()),
1964
+ const [usePortalStore] = React.useState(() => {
1965
+ // Create a mirrored store, based on the previous root with a few overrides ...
1966
+ new THREE.Vector3();
1967
+ const previousState = previousRoot.getState();
1968
+ const store = create((set, get) => ({ ...inject(previousState),
1969
+ // Set and get refer to this root-state
1960
1970
  set,
1961
1971
  get,
1972
+ // Layers are allowed to override events
1962
1973
  setEvents: events => set(state => ({ ...state,
1963
1974
  events: { ...state.events,
1964
1975
  ...events
1965
1976
  }
1966
1977
  }))
1967
1978
  }));
1968
- previousRoot.subscribe(state => useInjectStore.setState(injectState => inject(state, injectState)));
1969
1979
  return store;
1970
1980
  });
1971
1981
  React.useEffect(() => {
1972
- useInjectStore.setState(injectState => inject(previousRoot.getState(), injectState));
1982
+ // Subscribe to previous root-state and copy changes over to the mirrored portal-state
1983
+ const unsub = previousRoot.subscribe(prev => usePortalStore.setState(state => inject(prev, state)));
1984
+ return () => {
1985
+ unsub();
1986
+ usePortalStore.destroy();
1987
+ };
1988
+ }, []);
1989
+ React.useEffect(() => {
1990
+ usePortalStore.setState(injectState => inject(previousRoot.getState(), injectState));
1973
1991
  }, [inject]);
1974
1992
  return /*#__PURE__*/React.createElement(React.Fragment, null, reconciler.createPortal( /*#__PURE__*/React.createElement(context.Provider, {
1975
- value: useInjectStore
1976
- }, children), useInjectStore, null));
1993
+ value: usePortalStore
1994
+ }, children), usePortalStore, null));
1977
1995
  }
1978
1996
 
1979
1997
  reconciler.injectIntoDevTools({
@@ -1983,4 +2001,4 @@ reconciler.injectIntoDevTools({
1983
2001
  });
1984
2002
  const act = React.unstable_act;
1985
2003
 
1986
- export { useGraph as A, Block as B, useLoader as C, ErrorBoundary as E, createRoot as a, useIsomorphicLayoutEffect as b, createEvents as c, unmountComponentAtNode as d, extend as e, context as f, createPortal as g, reconciler as h, applyProps as i, dispose as j, invalidate as k, advance as l, addEffect as m, addAfterEffect as n, omit as o, pick as p, addTail as q, render as r, getRootState as s, threeTypes as t, useMemoizedFn as u, act as v, roots as w, useStore as x, useThree as y, useFrame as z };
2004
+ export { Block as B, ErrorBoundary as E, createRoot as a, useIsomorphicLayoutEffect as b, createEvents as c, unmountComponentAtNode as d, extend as e, context as f, createPortal as g, reconciler as h, applyProps as i, dispose as j, invalidate as k, advance as l, addEffect as m, addAfterEffect as n, addTail as o, getRootState as p, act as q, render as r, roots as s, threeTypes as t, useMutableCallback as u, useStore as v, useThree as w, useFrame as x, useGraph as y, useLoader as z };
@@ -39,11 +39,17 @@ var threeTypes = /*#__PURE__*/Object.freeze({
39
39
  __proto__: null
40
40
  });
41
41
 
42
- // React currently throws a warning when using useLayoutEffect on the server.
42
+ const isOrthographicCamera = def => def && def.isOrthographicCamera; // React currently throws a warning when using useLayoutEffect on the server.
43
43
  // To get around it, we can conditionally useEffect on the server (no-op) and
44
44
  // useLayoutEffect on the client.
45
+
45
46
  const isSSR = typeof window === 'undefined' || !window.navigator || /ServerSideRendering|^Deno\//.test(window.navigator.userAgent);
46
47
  const useIsomorphicLayoutEffect = isSSR ? React__namespace.useEffect : React__namespace.useLayoutEffect;
48
+ function useMutableCallback(fn) {
49
+ const ref = React__namespace.useRef(fn);
50
+ useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
51
+ return ref;
52
+ }
47
53
  function Block({
48
54
  set
49
55
  }) {
@@ -75,11 +81,6 @@ ErrorBoundary.getDerivedStateFromError = () => ({
75
81
  error: true
76
82
  });
77
83
 
78
- function useMemoizedFn(fn) {
79
- const fnRef = React__namespace.useRef(fn);
80
- useIsomorphicLayoutEffect(() => void (fnRef.current = fn), [fn]);
81
- return (...args) => fnRef.current == null ? void 0 : fnRef.current(...args);
82
- }
83
84
  const DEFAULT = '__default';
84
85
  const isDiffSet = def => def && !!def.memoized && !!def.changes;
85
86
  function calculateDpr(dpr) {
@@ -94,29 +95,6 @@ const getRootState = obj => {
94
95
 
95
96
  return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
96
97
  };
97
- /**
98
- * Picks or omits keys from an object
99
- * `omit` will filter out keys, and otherwise cherry-pick them.
100
- */
101
-
102
- function filterKeys(obj, omit, ...keys) {
103
- const keysToSelect = new Set(keys);
104
- return Object.entries(obj).reduce((acc, [key, value]) => {
105
- const shouldInclude = !omit;
106
- if (keysToSelect.has(key) === shouldInclude) acc[key] = value;
107
- return acc;
108
- }, {});
109
- }
110
- /**
111
- * Clones an object and cherry-picks keys.
112
- */
113
-
114
- const pick = (obj, keys) => filterKeys(obj, false, ...keys);
115
- /**
116
- * Clones an object and prunes or omits keys.
117
- */
118
-
119
- const omit = (obj, keys) => filterKeys(obj, true, ...keys);
120
98
  // A collection of compare functions
121
99
  const is = {
122
100
  obj: a => a === Object(a) && !is.arr(a) && typeof a !== 'function',
@@ -342,12 +320,16 @@ function applyProps$1(instance, data) {
342
320
 
343
321
  if (value === DEFAULT + 'remove') {
344
322
  if (targetProp && targetProp.constructor) {
323
+ var _memoized$args;
324
+
345
325
  // use the prop constructor to find the default it should be
346
- value = new targetProp.constructor(...memoized.args);
326
+ value = new targetProp.constructor(...((_memoized$args = memoized.args) != null ? _memoized$args : []));
347
327
  } else if (currentInstance.constructor) {
328
+ var _currentInstance$__r;
329
+
348
330
  // create a blank slate of the instance and copy the particular parameter.
349
331
  // @ts-ignore
350
- const defaultClassCall = new currentInstance.constructor(...currentInstance.__r3f.memoizedProps.args);
332
+ const defaultClassCall = new currentInstance.constructor(...((_currentInstance$__r = currentInstance.__r3f.memoizedProps.args) != null ? _currentInstance$__r : []));
351
333
  value = defaultClassCall[targetProp]; // destory the instance
352
334
 
353
335
  if (defaultClassCall.dispose) defaultClassCall.dispose(); // instance does not have constructor, just set it to 0
@@ -416,6 +398,25 @@ function invalidateInstance(instance) {
416
398
  function updateInstance(instance) {
417
399
  instance.onUpdate == null ? void 0 : instance.onUpdate(instance);
418
400
  }
401
+ function updateCamera(camera, size) {
402
+ // https://github.com/pmndrs/react-three-fiber/issues/92
403
+ // Do not mess with the camera if it belongs to the user
404
+ if (!camera.manual) {
405
+ if (isOrthographicCamera(camera)) {
406
+ camera.left = size.width / -2;
407
+ camera.right = size.width / 2;
408
+ camera.top = size.height / 2;
409
+ camera.bottom = size.height / -2;
410
+ } else {
411
+ camera.aspect = size.width / size.height;
412
+ }
413
+
414
+ camera.updateProjectionMatrix(); // https://github.com/pmndrs/react-three-fiber/issues/178
415
+ // Update matrix world since the renderer is a frame late
416
+
417
+ camera.updateMatrixWorld();
418
+ }
419
+ }
419
420
 
420
421
  function makeId(event) {
421
422
  return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
@@ -1188,8 +1189,8 @@ function createRenderer(roots, getEventPriority) {
1188
1189
  };
1189
1190
  }
1190
1191
 
1192
+ const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'performance', 'internal', 'size', 'viewport'];
1191
1193
  const isRenderer = def => !!(def != null && def.render);
1192
- const isOrthographicCamera = def => def && def.isOrthographicCamera;
1193
1194
  const context = /*#__PURE__*/React__namespace.createContext(null);
1194
1195
 
1195
1196
  const createStore = (invalidate, advance) => {
@@ -1396,24 +1397,7 @@ const createStore = (invalidate, advance) => {
1396
1397
  } = rootState.getState();
1397
1398
 
1398
1399
  if (size !== oldSize || viewport.dpr !== oldDpr) {
1399
- // https://github.com/pmndrs/react-three-fiber/issues/92
1400
- // Do not mess with the camera if it belongs to the user
1401
- if (!camera.manual) {
1402
- if (isOrthographicCamera(camera)) {
1403
- camera.left = size.width / -2;
1404
- camera.right = size.width / 2;
1405
- camera.top = size.height / 2;
1406
- camera.bottom = size.height / -2;
1407
- } else {
1408
- camera.aspect = size.width / size.height;
1409
- }
1410
-
1411
- camera.updateProjectionMatrix(); // https://github.com/pmndrs/react-three-fiber/issues/178
1412
- // Update matrix world since the renderer is a frame late
1413
-
1414
- camera.updateMatrixWorld();
1415
- } // Update renderer
1416
-
1400
+ updateCamera(camera, size); // Update renderer
1417
1401
 
1418
1402
  gl.setPixelRatio(viewport.dpr);
1419
1403
  gl.setSize(size.width, size.height);
@@ -1580,12 +1564,11 @@ function useThree(selector = state => state, equalityFn) {
1580
1564
 
1581
1565
  function useFrame(callback, renderPriority = 0) {
1582
1566
  const store = useStore();
1583
- const subscribe = store.getState().internal.subscribe; // Update ref
1567
+ const subscribe = store.getState().internal.subscribe; // Memoize ref
1584
1568
 
1585
- const ref = React__namespace.useRef(callback);
1586
- React__namespace.useLayoutEffect(() => void (ref.current = callback), [callback]); // Subscribe on mount, unsubscribe on unmount
1569
+ const ref = useMutableCallback(callback); // Subscribe on mount, unsubscribe on unmount
1587
1570
 
1588
- React__namespace.useLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
1571
+ useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
1589
1572
  return null;
1590
1573
  }
1591
1574
  /**
@@ -1953,6 +1936,7 @@ function Portal({
1953
1936
  * {createPortal(...)} */
1954
1937
  const {
1955
1938
  events,
1939
+ size,
1956
1940
  ...rest
1957
1941
  } = state;
1958
1942
  const previousRoot = useStore();
@@ -1964,45 +1948,79 @@ function Portal({
1964
1948
 
1965
1949
  if (injectState) {
1966
1950
  // Only the fields of "state" that do not differ from injectState
1951
+ // Some props should be off-limits
1952
+ // Otherwise filter out the props that are different and let the inject layer take precedence
1967
1953
  Object.keys(state).forEach(key => {
1968
1954
  if ( // Some props should be off-limits
1969
- !['size', 'viewport', 'internal', 'performance'].includes(key) && // Otherwise filter out the props that are different and let the inject layer take precedence
1955
+ !privateKeys.includes(key) && // Otherwise filter out the props that are different and let the inject layer take precedence
1970
1956
  state[key] !== injectState[key]) delete intersect[key];
1971
1957
  });
1972
1958
  }
1973
1959
 
1974
- return { ...intersect,
1960
+ let viewport = undefined;
1961
+
1962
+ if (injectState && size) {
1963
+ const camera = injectState.camera; // Calculate the override viewport, if present
1964
+
1965
+ viewport = state.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size); // Update the portal camera, if it differs from the previous layer
1966
+
1967
+ if (camera !== state.camera) updateCamera(camera, size);
1968
+ }
1969
+
1970
+ return { // The intersect consists of the previous root state
1971
+ ...intersect,
1972
+ // Portals have their own scene, which forms the root, a raycaster and a pointer
1975
1973
  scene: container,
1976
- previousRoot,
1977
1974
  raycaster,
1975
+ pointer,
1976
+ mouse: pointer,
1977
+ // Their previous root is the layer before it
1978
+ previousRoot,
1979
+ // Events, size and viewport can be overridden by the inject layer
1978
1980
  events: { ...state.events,
1979
1981
  ...(injectState == null ? void 0 : injectState.events),
1980
- pointer,
1981
- mouse: pointer,
1982
1982
  ...events
1983
1983
  },
1984
+ size: { ...state.size,
1985
+ ...size
1986
+ },
1987
+ viewport: { ...state.viewport,
1988
+ ...viewport
1989
+ },
1984
1990
  ...rest
1985
1991
  };
1986
1992
  }, [state]);
1987
- const [useInjectStore] = React__namespace.useState(() => {
1988
- const store = create__default['default']((set, get) => ({ ...inject(previousRoot.getState()),
1993
+ const [usePortalStore] = React__namespace.useState(() => {
1994
+ // Create a mirrored store, based on the previous root with a few overrides ...
1995
+ new THREE__namespace.Vector3();
1996
+ const previousState = previousRoot.getState();
1997
+ const store = create__default['default']((set, get) => ({ ...inject(previousState),
1998
+ // Set and get refer to this root-state
1989
1999
  set,
1990
2000
  get,
2001
+ // Layers are allowed to override events
1991
2002
  setEvents: events => set(state => ({ ...state,
1992
2003
  events: { ...state.events,
1993
2004
  ...events
1994
2005
  }
1995
2006
  }))
1996
2007
  }));
1997
- previousRoot.subscribe(state => useInjectStore.setState(injectState => inject(state, injectState)));
1998
2008
  return store;
1999
2009
  });
2000
2010
  React__namespace.useEffect(() => {
2001
- useInjectStore.setState(injectState => inject(previousRoot.getState(), injectState));
2011
+ // Subscribe to previous root-state and copy changes over to the mirrored portal-state
2012
+ const unsub = previousRoot.subscribe(prev => usePortalStore.setState(state => inject(prev, state)));
2013
+ return () => {
2014
+ unsub();
2015
+ usePortalStore.destroy();
2016
+ };
2017
+ }, []);
2018
+ React__namespace.useEffect(() => {
2019
+ usePortalStore.setState(injectState => inject(previousRoot.getState(), injectState));
2002
2020
  }, [inject]);
2003
2021
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, reconciler.createPortal( /*#__PURE__*/React__namespace.createElement(context.Provider, {
2004
- value: useInjectStore
2005
- }, children), useInjectStore, null));
2022
+ value: usePortalStore
2023
+ }, children), usePortalStore, null));
2006
2024
  }
2007
2025
 
2008
2026
  reconciler.injectIntoDevTools({
@@ -2028,8 +2046,6 @@ exports.dispose = dispose;
2028
2046
  exports.extend = extend;
2029
2047
  exports.getRootState = getRootState;
2030
2048
  exports.invalidate = invalidate;
2031
- exports.omit = omit;
2032
- exports.pick = pick;
2033
2049
  exports.reconciler = reconciler;
2034
2050
  exports.render = render;
2035
2051
  exports.roots = roots;
@@ -2039,6 +2055,6 @@ exports.useFrame = useFrame;
2039
2055
  exports.useGraph = useGraph;
2040
2056
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
2041
2057
  exports.useLoader = useLoader;
2042
- exports.useMemoizedFn = useMemoizedFn;
2058
+ exports.useMutableCallback = useMutableCallback;
2043
2059
  exports.useStore = useStore;
2044
2060
  exports.useThree = useThree;