@react-three/fiber 8.0.0-beta.4 → 8.0.0-beta.7

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,10 +1,10 @@
1
- import * as React from 'react';
2
- import { suspend, preload, clear } from 'suspend-react';
3
1
  import * as THREE from 'three';
2
+ import * as React from 'react';
4
3
  import { DefaultEventPriority, ContinuousEventPriority, DiscreteEventPriority, ConcurrentRoot } from 'react-reconciler/constants';
5
4
  import create from 'zustand';
6
5
  import Reconciler from 'react-reconciler';
7
6
  import { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
7
+ import { suspend, preload, clear } from 'suspend-react';
8
8
 
9
9
  var threeTypes = /*#__PURE__*/Object.freeze({
10
10
  __proto__: null
@@ -15,6 +15,15 @@ const isDiffSet = def => def && !!def.memoized && !!def.changes;
15
15
  function calculateDpr(dpr) {
16
16
  return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], window.devicePixelRatio), dpr[1]) : dpr;
17
17
  }
18
+ /**
19
+ * Returns instance root state
20
+ */
21
+
22
+ const getRootState = obj => {
23
+ var _r3f;
24
+
25
+ return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
26
+ };
18
27
  /**
19
28
  * Picks or omits keys from an object
20
29
  * `omit` will filter out keys, and otherwise cherry-pick them.
@@ -24,11 +33,7 @@ function filterKeys(obj, omit, ...keys) {
24
33
  const keysToSelect = new Set(keys);
25
34
  return Object.entries(obj).reduce((acc, [key, value]) => {
26
35
  const shouldInclude = !omit;
27
-
28
- if (keysToSelect.has(key) === shouldInclude) {
29
- acc[key] = value;
30
- }
31
-
36
+ if (keysToSelect.has(key) === shouldInclude) acc[key] = value;
32
37
  return acc;
33
38
  }, {});
34
39
  }
@@ -66,7 +71,7 @@ const is = {
66
71
  const isArr = is.arr(a);
67
72
  if (isArr && arrays === 'reference') return a === b; // Array or Object, shallow compare first to see if it's a match
68
73
 
69
- if ((isArr || isObj) && a == b) return true; // Last resort, go through keys
74
+ if ((isArr || isObj) && a === b) return true; // Last resort, go through keys
70
75
 
71
76
  let i;
72
77
 
@@ -74,7 +79,13 @@ const is = {
74
79
 
75
80
  for (i in strict ? b : a) if (a[i] !== b[i]) return false;
76
81
 
77
- return is.und(i) ? a === b : true;
82
+ if (is.und(i)) {
83
+ if (isArr && a.length === 0 && b.length === 0) return true;
84
+ if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
85
+ if (a !== b) return false;
86
+ }
87
+
88
+ return true;
78
89
  }
79
90
 
80
91
  }; // Collects nodes and materials from a THREE.Object3D
@@ -110,30 +121,8 @@ function prepare(object, state) {
110
121
  if (state != null && state.primitive || !instance.__r3f) {
111
122
  instance.__r3f = {
112
123
  type: '',
113
- context: {
114
- current: null
115
- },
116
- getContext: () => {
117
- const injects = [];
118
- let inject = instance.__r3f.context.current;
119
-
120
- while (inject) {
121
- var _inject$memoizedProps, _inject, _inject$context;
122
-
123
- const {
124
- children,
125
- args,
126
- ...props
127
- } = (_inject$memoizedProps = (_inject = inject) == null ? void 0 : _inject.memoizedProps) != null ? _inject$memoizedProps : {};
128
- injects.push(props);
129
- inject = (_inject$context = inject.context) == null ? void 0 : _inject$context.current;
130
- }
131
-
132
- return injects.reverse().reduce((prev, cur) => ({ ...prev,
133
- ...cur
134
- }), {});
135
- },
136
124
  root: null,
125
+ previousAttach: null,
137
126
  memoizedProps: {},
138
127
  eventCount: 0,
139
128
  handlers: {},
@@ -161,32 +150,42 @@ function resolve(instance, key) {
161
150
  target,
162
151
  key
163
152
  };
164
- }
153
+ } // Checks if a dash-cased string ends with an integer
165
154
 
155
+
156
+ const INDEX_REGEX = /-\d+$/;
166
157
  function attach(parent, child, type) {
167
158
  if (is.str(type)) {
159
+ // If attaching into an array (foo-0), create one
160
+ if (INDEX_REGEX.test(type)) {
161
+ const root = type.replace(INDEX_REGEX, '');
162
+ const {
163
+ target,
164
+ key
165
+ } = resolve(parent, root);
166
+ if (!Array.isArray(target[key])) target[key] = [];
167
+ }
168
+
168
169
  const {
169
170
  target,
170
171
  key
171
172
  } = resolve(parent, type);
172
- parent.__r3f.previousAttach = target[key];
173
+ child.__r3f.previousAttach = target[key];
173
174
  target[key] = child;
174
- } else if (is.arr(type)) {
175
- const [attach] = type;
176
- if (is.str(attach)) parent[attach](child);else if (is.fun(attach)) attach(parent, child);
177
- }
175
+ } else child.__r3f.previousAttach = type(parent, child);
178
176
  }
179
177
  function detach(parent, child, type) {
178
+ var _child$__r3f, _child$__r3f2;
179
+
180
180
  if (is.str(type)) {
181
181
  const {
182
182
  target,
183
183
  key
184
184
  } = resolve(parent, type);
185
- target[key] = parent.__r3f.previousAttach;
186
- } else if (is.arr(type)) {
187
- const [, detach] = type;
188
- if (is.str(detach)) parent[detach](child);else if (is.fun(detach)) detach(parent, child);
189
- }
185
+ target[key] = child.__r3f.previousAttach;
186
+ } else (_child$__r3f = child.__r3f) == null ? void 0 : _child$__r3f.previousAttach == null ? void 0 : _child$__r3f.previousAttach(parent, child);
187
+
188
+ (_child$__r3f2 = child.__r3f) == null ? true : delete _child$__r3f2.previousAttach;
190
189
  } // This function prepares a set of changes to be applied to the instance
191
190
 
192
191
  function diffProps(instance, {
@@ -306,20 +305,10 @@ function applyProps$1(instance, data) {
306
305
 
307
306
  if (!isColor && targetProp.setScalar) targetProp.setScalar(value); // Layers have no copy function, we must therefore copy the mask property
308
307
  else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers) targetProp.mask = value.mask; // Otherwise just set ...
309
- else targetProp.set(value); // Auto-convert sRGB colors, for now ...
310
- // https://github.com/pmndrs/react-three-fiber/issues/344
311
-
312
- if (!rootState.linear && isColor) targetProp.convertSRGBToLinear();
308
+ else targetProp.set(value);
313
309
  } // Else, just overwrite the value
314
310
 
315
- } else {
316
- currentInstance[key] = value; // Auto-convert sRGB textures, for now ...
317
- // https://github.com/pmndrs/react-three-fiber/issues/344
318
-
319
- if (!rootState.linear && currentInstance[key] instanceof THREE.Texture) {
320
- currentInstance[key].encoding = THREE.sRGBEncoding;
321
- }
322
- }
311
+ } else currentInstance[key] = value;
323
312
 
324
313
  invalidateInstance(instance);
325
314
  return instance;
@@ -398,6 +387,7 @@ function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
398
387
 
399
388
  function removeInteractivity(store, object) {
400
389
  const {
390
+ events,
401
391
  internal
402
392
  } = store.getState(); // Removes every trace of an object from the data store
403
393
 
@@ -405,6 +395,7 @@ function removeInteractivity(store, object) {
405
395
  internal.initialHits = internal.initialHits.filter(o => o !== object);
406
396
  internal.hovered.forEach((value, key) => {
407
397
  if (value.eventObject === object || value.object === object) {
398
+ // Clear out intersects, they are outdated by now
408
399
  internal.hovered.delete(key);
409
400
  }
410
401
  });
@@ -414,31 +405,8 @@ function removeInteractivity(store, object) {
414
405
  }
415
406
  function createEvents(store) {
416
407
  const temp = new THREE.Vector3();
417
- /** Sets up defaultRaycaster */
418
-
419
- function prepareRay(event) {
420
- var _customOffsets$offset, _customOffsets$offset2, _customOffsets$width, _customOffsets$height;
421
-
422
- const state = store.getState();
423
- const {
424
- raycaster,
425
- mouse,
426
- camera,
427
- size
428
- } = state; // https://github.com/pmndrs/react-three-fiber/pull/782
429
- // Events trigger outside of canvas when moved
430
-
431
- const customOffsets = raycaster.computeOffsets == null ? void 0 : raycaster.computeOffsets(event, state);
432
- const offsetX = (_customOffsets$offset = customOffsets == null ? void 0 : customOffsets.offsetX) != null ? _customOffsets$offset : event.offsetX;
433
- const offsetY = (_customOffsets$offset2 = customOffsets == null ? void 0 : customOffsets.offsetY) != null ? _customOffsets$offset2 : event.offsetY;
434
- const width = (_customOffsets$width = customOffsets == null ? void 0 : customOffsets.width) != null ? _customOffsets$width : size.width;
435
- const height = (_customOffsets$height = customOffsets == null ? void 0 : customOffsets.height) != null ? _customOffsets$height : size.height;
436
- mouse.set(offsetX / width * 2 - 1, -(offsetY / height) * 2 + 1);
437
- raycaster.setFromCamera(mouse, camera);
438
- }
439
408
  /** Calculates delta */
440
409
 
441
-
442
410
  function calculateDistance(event) {
443
411
  const {
444
412
  internal
@@ -458,55 +426,70 @@ function createEvents(store) {
458
426
  }));
459
427
  }
460
428
 
461
- function intersect(filter) {
429
+ function intersect(event, filter) {
462
430
  const state = store.getState();
463
- const {
464
- raycaster,
465
- internal
466
- } = state; // Skip event handling when noEvents is set
467
-
468
- if (!raycaster.enabled) return [];
469
- const seen = new Set();
431
+ const duplicates = new Set();
470
432
  const intersections = []; // Allow callers to eliminate event objects
471
433
 
472
- const eventsObjects = filter ? filter(internal.interaction) : internal.interaction; // Intersect known handler objects and filter against duplicates
434
+ const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction; // Reset all raycaster cameras to undefined
435
+
436
+ eventsObjects.forEach(obj => {
437
+ const state = getRootState(obj);
438
+
439
+ if (state) {
440
+ state.raycaster.camera = undefined;
441
+ }
442
+ }); // Collect events
443
+
444
+ let hits = eventsObjects // Intersect objects
445
+ .flatMap(obj => {
446
+ const state = getRootState(obj); // Skip event handling when noEvents is set, or when the raycasters camera is null
447
+
448
+ if (!state || !state.events.enabled || state.raycaster.camera === null) return []; // When the camera is undefined we have to call the event layers update function
449
+
450
+ if (state.raycaster.camera === undefined) {
451
+ var _state$previousRoot;
473
452
 
474
- let intersects = raycaster.intersectObjects(eventsObjects, true).filter(item => {
453
+ state.events.compute == null ? void 0 : state.events.compute(event, state, (_state$previousRoot = state.previousRoot) == null ? void 0 : _state$previousRoot.getState()); // If the camera is still undefined we have to skip this layer entirely
454
+
455
+ if (state.raycaster.camera === undefined) state.raycaster.camera = null;
456
+ } // Intersect object by object
457
+
458
+
459
+ return state.raycaster.camera ? state.raycaster.intersectObject(obj, true) : [];
460
+ }) // Sort by event priority and distance
461
+ .sort((a, b) => {
462
+ const aState = getRootState(a.object);
463
+ const bState = getRootState(b.object);
464
+ if (!aState || !bState) return 0;
465
+ return bState.events.priority - aState.events.priority || a.distance - b.distance;
466
+ }) // Filter out duplicates
467
+ .filter(item => {
475
468
  const id = makeId(item);
476
- if (seen.has(id)) return false;
477
- seen.add(id);
469
+ if (duplicates.has(id)) return false;
470
+ duplicates.add(id);
478
471
  return true;
479
472
  }); // https://github.com/mrdoob/three.js/issues/16031
480
- // Allow custom userland intersect sort order
473
+ // Allow custom userland intersect sort order, this likely only makes sense on the root filter
481
474
 
482
- if (raycaster.filter) intersects = raycaster.filter(intersects, state);
475
+ if (state.events.filter) hits = state.events.filter(hits, state); // Bubble up the events, find the event source (eventObject)
483
476
 
484
- for (const intersect of intersects) {
485
- let eventObject = intersect.object; // Bubble event up
477
+ for (const hit of hits) {
478
+ let eventObject = hit.object; // Bubble event up
486
479
 
487
480
  while (eventObject) {
488
481
  var _r3f2;
489
482
 
490
- if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({ ...intersect,
483
+ if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({ ...hit,
491
484
  eventObject
492
485
  });
493
486
  eventObject = eventObject.parent;
494
487
  }
495
- }
496
-
497
- return intersections;
498
- }
499
- /** Creates filtered intersects and returns an array of positive hits */
488
+ } // If the interaction is captured, make all capturing targets part of the intersect.
500
489
 
501
490
 
502
- function patchIntersects(intersections, event) {
503
- const {
504
- internal
505
- } = store.getState(); // If the interaction is captured, make all capturing targets part of the
506
- // intersect.
507
-
508
- if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
509
- for (let captureData of internal.capturedMap.get(event.pointerId).values()) {
491
+ if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
492
+ for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
510
493
  intersections.push(captureData.intersection);
511
494
  }
512
495
  }
@@ -519,13 +502,13 @@ function createEvents(store) {
519
502
  function handleIntersects(intersections, event, delta, callback) {
520
503
  const {
521
504
  raycaster,
522
- mouse,
505
+ pointer,
523
506
  camera,
524
507
  internal
525
508
  } = store.getState(); // If anything has been found, forward it to the event listeners
526
509
 
527
510
  if (intersections.length) {
528
- const unprojectedPoint = temp.set(mouse.x, mouse.y, 0).unproject(camera);
511
+ const unprojectedPoint = temp.set(pointer.x, pointer.y, 0).unproject(camera);
529
512
  const localState = {
530
513
  stopped: false
531
514
  };
@@ -576,8 +559,7 @@ function createEvents(store) {
576
559
 
577
560
  let raycastEvent = { ...hit,
578
561
  ...extractEventProps,
579
- spaceX: mouse.x,
580
- spaceY: mouse.y,
562
+ pointer,
581
563
  intersections,
582
564
  stopped: localState.stopped,
583
565
  delta,
@@ -614,8 +596,6 @@ function createEvents(store) {
614
596
  setPointerCapture,
615
597
  releasePointerCapture
616
598
  },
617
- sourceEvent: event,
618
- // deprecated
619
599
  nativeEvent: event
620
600
  }; // Call subscribers
621
601
 
@@ -680,14 +660,15 @@ function createEvents(store) {
680
660
  const {
681
661
  onPointerMissed,
682
662
  internal
683
- } = store.getState();
684
- prepareRay(event);
663
+ } = store.getState(); //prepareRay(event)
664
+
685
665
  internal.lastEvent.current = event; // Get fresh intersects
686
666
 
687
667
  const isPointerMove = name === 'onPointerMove';
688
668
  const isClickEvent = name === 'onClick' || name === 'onContextMenu' || name === 'onDoubleClick';
689
- const filter = isPointerMove ? filterPointerEvents : undefined;
690
- const hits = patchIntersects(intersect(filter), event);
669
+ const filter = isPointerMove ? filterPointerEvents : undefined; //const hits = patchIntersects(intersect(filter), event)
670
+
671
+ const hits = intersect(event, filter);
691
672
  const delta = isClickEvent ? calculateDistance(event) : 0; // Save initial coordinates on pointer-down
692
673
 
693
674
  if (name === 'onPointerDown') {
@@ -770,54 +751,20 @@ function createEvents(store) {
770
751
  };
771
752
  }
772
753
 
773
- // Type guard to tell a store from a portal
774
- const isStore = def => def && !!def.getState;
775
-
776
- const getContainer = (container, child) => {
777
- var _container$__r3f$root, _container$__r3f;
778
-
779
- return {
780
- // If the container is not a root-store then it must be a THREE.Object3D into which part of the
781
- // scene is portalled into. Now there can be two variants of this, either that object is part of
782
- // the regular jsx tree, in which case it already has __r3f with a valid root attached, or it lies
783
- // outside react, in which case we must take the root of the child that is about to be attached to it.
784
- root: isStore(container) ? container : (_container$__r3f$root = (_container$__r3f = container.__r3f) == null ? void 0 : _container$__r3f.root) != null ? _container$__r3f$root : child.__r3f.root,
785
- // The container is the eventual target into which objects are mounted, it has to be a THREE.Object3D
786
- container: isStore(container) ? container.getState().scene : container
787
- };
788
- };
789
-
790
754
  let catalogue = {};
791
755
 
792
756
  let extend = objects => void (catalogue = { ...catalogue,
793
757
  ...objects
794
758
  });
795
759
 
796
- extend({
797
- Inject: THREE.Group
798
- });
799
-
800
760
  function createRenderer(roots, getEventPriority) {
801
761
  function createInstance(type, {
802
762
  args = [],
803
763
  attach,
804
764
  ...props
805
- }, root, context, internalInstanceHandle) {
765
+ }, root) {
806
766
  let name = `${type[0].toUpperCase()}${type.slice(1)}`;
807
- let instance; // https://github.com/facebook/react/issues/17147
808
- // Portals do not give us a root, they are themselves treated as a root by the reconciler
809
- // In order to figure out the actual root we have to climb through fiber internals :(
810
-
811
- if (!isStore(root) && internalInstanceHandle) {
812
- const fn = node => {
813
- if (!node.return) return node.stateNode && node.stateNode.containerInfo;else return fn(node.return);
814
- };
815
-
816
- root = fn(internalInstanceHandle);
817
- } // Assert that by now we have a valid root
818
-
819
-
820
- if (!root || !isStore(root)) throw `No valid root for ${name}!`; // Auto-attach geometries and materials
767
+ let instance; // Auto-attach geometries and materials
821
768
 
822
769
  if (attach === undefined) {
823
770
  if (name.endsWith('Geometry')) attach = 'geometry';else if (name.endsWith('Material')) attach = 'material';
@@ -829,7 +776,6 @@ function createRenderer(roots, getEventPriority) {
829
776
  instance = prepare(object, {
830
777
  type,
831
778
  root,
832
- context,
833
779
  attach,
834
780
  primitive: true
835
781
  });
@@ -847,7 +793,6 @@ function createRenderer(roots, getEventPriority) {
847
793
  instance = prepare(new target(...args), {
848
794
  type,
849
795
  root,
850
- context,
851
796
  attach,
852
797
  // TODO: Figure out what this is for
853
798
  memoizedProps: {
@@ -865,15 +810,6 @@ function createRenderer(roots, getEventPriority) {
865
810
  }
866
811
 
867
812
  function appendChild(parentInstance, child) {
868
- // https://github.com/facebook/react/issues/24138
869
- // Injects are special purpose "onion layers" that inject contextual information into the scene graph.
870
- // Since react-reconciler does not allow us to access the current host context we trick it by leading
871
- // back to it from the first child that is added to it. We just connect the inject to it's own host context.
872
- if ((parentInstance == null ? void 0 : parentInstance.__r3f.type) === 'inject') {
873
- const context = child == null ? void 0 : child.__r3f.context;
874
- if (context) context.current = parentInstance.__r3f;
875
- }
876
-
877
813
  let added = false;
878
814
 
879
815
  if (child) {
@@ -969,7 +905,6 @@ function createRenderer(roots, getEventPriority) {
969
905
 
970
906
  if (child.__r3f) {
971
907
  delete child.__r3f.root;
972
- delete child.__r3f.context;
973
908
  delete child.__r3f.objects;
974
909
  delete child.__r3f.handlers;
975
910
  delete child.__r3f.memoizedProps;
@@ -992,11 +927,11 @@ function createRenderer(roots, getEventPriority) {
992
927
  }
993
928
 
994
929
  function switchInstance(instance, type, newProps, fiber) {
995
- var _instance$__r3f;
930
+ var _instance$__r3f, _instance$__r3f2;
996
931
 
997
932
  const parent = (_instance$__r3f = instance.__r3f) == null ? void 0 : _instance$__r3f.parent;
998
933
  if (!parent) return;
999
- const newInstance = createInstance(type, newProps, instance.__r3f.root); // https://github.com/pmndrs/react-three-fiber/issues/1348
934
+ const newInstance = createInstance(type, newProps, (_instance$__r3f2 = instance.__r3f) == null ? void 0 : _instance$__r3f2.root); // https://github.com/pmndrs/react-three-fiber/issues/1348
1000
935
  // When args change the instance has to be re-constructed, which then
1001
936
  // forces r3f to re-parent the children and non-scene objects
1002
937
  // This can not include primitives, which should not have declarative children
@@ -1039,46 +974,28 @@ function createRenderer(roots, getEventPriority) {
1039
974
  supportsMutation: true,
1040
975
  isPrimaryRenderer: false,
1041
976
  noTimeout: -1,
1042
- appendChildToContainer: (parentInstance, child) => {
1043
- const {
1044
- container,
1045
- root
1046
- } = getContainer(parentInstance, child); // Link current root to the default scene
977
+ appendChildToContainer: (container, child) => {
978
+ const scene = container.getState().scene; // Link current root to the default scene
1047
979
 
1048
- container.__r3f.root = root;
1049
- appendChild(container, child);
1050
- },
1051
- removeChildFromContainer: (parentInstance, child) => removeChild(getContainer(parentInstance, child).container, child),
1052
- insertInContainerBefore: (parentInstance, child, beforeChild) => insertBefore(getContainer(parentInstance, child).container, child, beforeChild),
1053
- getRootHostContext: () => ({
1054
- current: null
1055
- }),
1056
- getChildHostContext: (parentHostContext, type) => {
1057
- // This is a little misleading, this function does not determine the host context for the element at hand,
1058
- // but rather for all the children of it. The context for an inject is and will be the scene, everything
1059
- // within an inject is contextual to it.
1060
- if (type === 'inject') return {
1061
- current: null
1062
- };
1063
- return parentHostContext;
980
+ scene.__r3f.root = container;
981
+ appendChild(scene, child);
1064
982
  },
983
+ removeChildFromContainer: (container, child) => removeChild(container.getState().scene, child),
984
+ insertInContainerBefore: (container, child, beforeChild) => insertBefore(container.getState().scene, child, beforeChild),
985
+ getRootHostContext: () => null,
986
+ getChildHostContext: parentHostContext => parentHostContext,
1065
987
 
1066
988
  finalizeInitialChildren(instance) {
1067
- var _instance$__r3f2;
989
+ var _instance$__r3f3;
1068
990
 
1069
- const localState = (_instance$__r3f2 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f2 : {}; // https://github.com/facebook/react/issues/20271
991
+ const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {}; // https://github.com/facebook/react/issues/20271
1070
992
  // Returning true will trigger commitMount
1071
993
 
1072
994
  return !!localState.handlers;
1073
995
  },
1074
996
 
1075
997
  prepareUpdate(instance, type, oldProps, newProps) {
1076
- // Injects are special purpose "onion layers" that inject contextual information into the scene graph
1077
- // Because the context of an inject is still the scene we have to rely on children to give us the inject-context
1078
- // so that we can set up props.
1079
- if (type === 'inject' && instance.children.length) ; // Create diff-sets
1080
-
1081
-
998
+ // Create diff-sets
1082
999
  if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
1083
1000
  return [true];
1084
1001
  } else {
@@ -1112,11 +1029,11 @@ function createRenderer(roots, getEventPriority) {
1112
1029
  },
1113
1030
 
1114
1031
  commitMount(instance, type, props, int) {
1115
- var _instance$__r3f3;
1032
+ var _instance$__r3f4;
1116
1033
 
1117
1034
  // https://github.com/facebook/react/issues/20271
1118
1035
  // This will make sure events are only added once to the central container
1119
- const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
1036
+ const localState = (_instance$__r3f4 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f4 : {};
1120
1037
 
1121
1038
  if (instance.raycast && localState.handlers && localState.eventCount) {
1122
1039
  instance.__r3f.root.getState().internal.interaction.push(instance);
@@ -1126,7 +1043,7 @@ function createRenderer(roots, getEventPriority) {
1126
1043
  getPublicInstance: instance => instance,
1127
1044
  shouldDeprioritizeSubtree: () => false,
1128
1045
  prepareForCommit: () => null,
1129
- preparePortalMount: containerInfo => prepare(containerInfo),
1046
+ preparePortalMount: container => prepare(container.getState().scene),
1130
1047
  resetAfterCommit: () => {},
1131
1048
  shouldSetTextContent: () => false,
1132
1049
  clearContainer: () => false,
@@ -1134,26 +1051,26 @@ function createRenderer(roots, getEventPriority) {
1134
1051
  createTextInstance: () => {},
1135
1052
 
1136
1053
  hideInstance(instance) {
1137
- var _instance$__r3f4;
1054
+ var _instance$__r3f5;
1138
1055
 
1139
1056
  // Deatch while the instance is hidden
1140
1057
  const {
1141
1058
  attach: type,
1142
1059
  parent
1143
- } = (_instance$__r3f4 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f4 : {};
1060
+ } = (_instance$__r3f5 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f5 : {};
1144
1061
  if (type && parent) detach(parent, instance, type);
1145
1062
  if (instance.isObject3D) instance.visible = false;
1146
1063
  invalidateInstance(instance);
1147
1064
  },
1148
1065
 
1149
1066
  unhideInstance(instance, props) {
1150
- var _instance$__r3f5;
1067
+ var _instance$__r3f6;
1151
1068
 
1152
1069
  // Re-attach when the instance is unhidden
1153
1070
  const {
1154
1071
  attach: type,
1155
1072
  parent
1156
- } = (_instance$__r3f5 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f5 : {};
1073
+ } = (_instance$__r3f6 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f6 : {};
1157
1074
  if (type && parent) attach(parent, instance, type);
1158
1075
  if (instance.isObject3D && props.visible == null || props.visible) instance.visible = true;
1159
1076
  invalidateInstance(instance);
@@ -1231,16 +1148,18 @@ const createStore = (invalidate, advance) => {
1231
1148
  }));
1232
1149
 
1233
1150
  return {
1151
+ set,
1152
+ get,
1234
1153
  // Mock objects that have to be configured
1235
1154
  gl: null,
1236
1155
  camera: null,
1237
1156
  raycaster: null,
1238
1157
  events: {
1158
+ priority: 1,
1159
+ enabled: true,
1239
1160
  connected: false
1240
1161
  },
1241
1162
  xr: null,
1242
- set,
1243
- get,
1244
1163
  invalidate: () => invalidate(get()),
1245
1164
  advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
1246
1165
  linear: false,
@@ -1248,7 +1167,7 @@ const createStore = (invalidate, advance) => {
1248
1167
  scene: prepare(new THREE.Scene()),
1249
1168
  controls: null,
1250
1169
  clock: new THREE.Clock(),
1251
- mouse: new THREE.Vector2(),
1170
+ pointer: new THREE.Vector2(),
1252
1171
  frameloop: 'always',
1253
1172
  onPointerMissed: undefined,
1254
1173
  performance: {
@@ -1317,6 +1236,7 @@ const createStore = (invalidate, advance) => {
1317
1236
  frameloop
1318
1237
  }));
1319
1238
  },
1239
+ previousRoot: undefined,
1320
1240
  internal: {
1321
1241
  active: false,
1322
1242
  priority: 0,
@@ -1544,6 +1464,11 @@ function loadingFn(extensions, onProgress) {
1544
1464
  };
1545
1465
  }
1546
1466
 
1467
+ function useMemoizedFn(fn) {
1468
+ const fnRef = React.useRef(fn);
1469
+ React.useLayoutEffect(() => void (fnRef.current = fn), [fn]);
1470
+ return (...args) => fnRef.current == null ? void 0 : fnRef.current(...args);
1471
+ }
1547
1472
  function useLoader(Proto, input, extensions, onProgress) {
1548
1473
  // Use suspense to load async assets
1549
1474
  const keys = Array.isArray(input) ? input : [input];
@@ -1643,9 +1568,7 @@ function createRoot(canvas) {
1643
1568
  params,
1644
1569
  ...options
1645
1570
  } = raycastOptions || {};
1646
- if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
1647
- enabled: true,
1648
- ...options
1571
+ if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options
1649
1572
  });
1650
1573
  if (!is.equ(params, raycaster.params, shallowLoose)) applyProps(raycaster, {
1651
1574
  params: { ...raycaster.params,
@@ -1681,7 +1604,7 @@ function createRoot(canvas) {
1681
1604
 
1682
1605
  const handleSessionChange = () => {
1683
1606
  const gl = store.getState().gl;
1684
- gl.xr.enabled = gl.xr.isPresenting; // @ts-expect-error
1607
+ gl.xr.enabled = gl.xr.isPresenting; // @ts-ignore
1685
1608
  // WebXRManager's signature is incorrect.
1686
1609
  // See: https://github.com/pmndrs/react-three-fiber/pull/2017#discussion_r790134505
1687
1610
 
@@ -1723,6 +1646,7 @@ function createRoot(canvas) {
1723
1646
  } // Set color management
1724
1647
 
1725
1648
 
1649
+ if (THREE.ColorManagement) THREE.ColorManagement.legacyMode = false;
1726
1650
  const outputEncoding = linear ? THREE.LinearEncoding : THREE.sRGBEncoding;
1727
1651
  const toneMapping = flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping;
1728
1652
  if (gl.outputEncoding !== outputEncoding) gl.outputEncoding = outputEncoding;
@@ -1759,14 +1683,14 @@ function createRoot(canvas) {
1759
1683
  return this;
1760
1684
  },
1761
1685
 
1762
- render(element) {
1686
+ render(children) {
1763
1687
  // The root has to be configured before it can be rendered
1764
1688
  if (!configured) this.configure();
1765
1689
  reconciler.updateContainer( /*#__PURE__*/React.createElement(Provider, {
1766
1690
  store: store,
1767
- element: element,
1691
+ children: children,
1768
1692
  onCreated: onCreated,
1769
- target: canvas
1693
+ rootElement: canvas
1770
1694
  }), fiber, null, () => undefined);
1771
1695
  return store;
1772
1696
  },
@@ -1778,35 +1702,36 @@ function createRoot(canvas) {
1778
1702
  };
1779
1703
  }
1780
1704
 
1781
- function render(element, canvas, config = {}) {
1705
+ function render(children, canvas, config) {
1782
1706
  console.warn('R3F.render is no longer supported in React 18. Use createRoot instead!');
1783
1707
  const root = createRoot(canvas);
1784
1708
  root.configure(config);
1785
- return root.render(element);
1709
+ return root.render(children);
1786
1710
  }
1787
1711
 
1788
1712
  function Provider({
1789
1713
  store,
1790
- element,
1714
+ children,
1791
1715
  onCreated,
1792
- target
1716
+ rootElement
1793
1717
  }) {
1794
- React.useEffect(() => {
1718
+ React.useLayoutEffect(() => {
1795
1719
  const state = store.getState(); // Flag the canvas active, rendering will now begin
1796
1720
 
1797
1721
  state.set(state => ({
1798
1722
  internal: { ...state.internal,
1799
1723
  active: true
1800
1724
  }
1801
- })); // Connect events
1725
+ })); // Notifiy that init is completed, the scene graph exists, but nothing has yet rendered
1802
1726
 
1803
- state.events.connect == null ? void 0 : state.events.connect(target); // Notifiy that init is completed, the scene graph exists, but nothing has yet rendered
1727
+ if (onCreated) onCreated(state); // Connect events to the targets parent, this is done to ensure events are registered on
1728
+ // a shared target, and not on the canvas itself
1804
1729
 
1805
- if (onCreated) onCreated(state); // eslint-disable-next-line react-hooks/exhaustive-deps
1730
+ if (!store.getState().events.connected) state.events.connect == null ? void 0 : state.events.connect(rootElement); // eslint-disable-next-line react-hooks/exhaustive-deps
1806
1731
  }, []);
1807
1732
  return /*#__PURE__*/React.createElement(context.Provider, {
1808
1733
  value: store
1809
- }, element);
1734
+ }, children);
1810
1735
  }
1811
1736
 
1812
1737
  function unmountComponentAtNode(canvas, callback) {
@@ -1838,10 +1763,67 @@ function unmountComponentAtNode(canvas, callback) {
1838
1763
  }
1839
1764
  }
1840
1765
 
1841
- const act = React.unstable_act;
1766
+ function createPortal(children, container, state) {
1767
+ return /*#__PURE__*/React.createElement(Portal, {
1768
+ children: children,
1769
+ container: container,
1770
+ state: state
1771
+ });
1772
+ }
1842
1773
 
1843
- function createPortal(children, container) {
1844
- return reconciler.createPortal(children, container, null, null);
1774
+ function Portal({
1775
+ state = {},
1776
+ children,
1777
+ container
1778
+ }) {
1779
+ /** This has to be a component because it would not be able to call useThree/useStore otherwise since
1780
+ * if this is our environment, then we are not in r3f's renderer but in react-dom, it would trigger
1781
+ * the "R3F hooks can only be used within the Canvas component!" warning:
1782
+ * <Canvas>
1783
+ * {createPortal(...)} */
1784
+ const {
1785
+ events,
1786
+ ...rest
1787
+ } = state;
1788
+ const previousRoot = useStore();
1789
+ const [raycaster] = React.useState(() => new THREE.Raycaster());
1790
+ const inject = React.useCallback((state, injectState) => {
1791
+ const intersect = { ...state
1792
+ };
1793
+
1794
+ if (injectState) {
1795
+ // Only the fields of "state" that do not differ from injectState
1796
+ Object.keys(state).forEach(key => {
1797
+ if ( // Some props should be off-limits
1798
+ !['size', 'viewport', 'internal', 'performance'].includes(key) && // Otherwise filter out the props that are different and let the inject layer take precedence
1799
+ state[key] !== injectState[key]) delete intersect[key];
1800
+ });
1801
+ }
1802
+
1803
+ return { ...intersect,
1804
+ scene: container,
1805
+ previousRoot,
1806
+ raycaster,
1807
+ events: { ...state.events,
1808
+ ...events
1809
+ },
1810
+ ...rest
1811
+ };
1812
+ }, [state]);
1813
+ const [useInjectStore] = React.useState(() => {
1814
+ const store = create((set, get) => ({ ...inject(previousRoot.getState()),
1815
+ set,
1816
+ get
1817
+ }));
1818
+ previousRoot.subscribe(state => useInjectStore.setState(injectState => inject(state, injectState)));
1819
+ return store;
1820
+ });
1821
+ React.useEffect(() => {
1822
+ useInjectStore.setState(injectState => inject(previousRoot.getState(), injectState));
1823
+ }, [inject]);
1824
+ return /*#__PURE__*/React.createElement(React.Fragment, null, reconciler.createPortal( /*#__PURE__*/React.createElement(context.Provider, {
1825
+ value: useInjectStore
1826
+ }, children), useInjectStore, null));
1845
1827
  }
1846
1828
 
1847
1829
  reconciler.injectIntoDevTools({
@@ -1849,5 +1831,6 @@ reconciler.injectIntoDevTools({
1849
1831
  rendererPackageName: '@react-three/fiber',
1850
1832
  version: '18.0.0'
1851
1833
  });
1834
+ const act = React.unstable_act;
1852
1835
 
1853
- export { createRoot as a, context as b, createEvents as c, createPortal as d, extend as e, reconciler as f, applyProps as g, dispose as h, invalidate as i, advance as j, addEffect as k, addAfterEffect as l, addTail as m, act as n, omit as o, pick as p, roots as q, render as r, useStore as s, threeTypes as t, unmountComponentAtNode as u, useThree as v, useFrame as w, useGraph as x, useLoader as y };
1836
+ export { useLoader as A, createRoot as a, unmountComponentAtNode as b, createEvents as c, context as d, extend as e, createPortal as f, reconciler as g, applyProps as h, dispose as i, invalidate as j, advance as k, addEffect as l, addAfterEffect as m, addTail as n, omit as o, pick as p, getRootState as q, render as r, act as s, threeTypes as t, useMemoizedFn as u, roots as v, useStore as w, useThree as x, useFrame as y, useGraph as z };