@react-three/fiber 8.0.0-beta-01 → 8.0.0-beta-05

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,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var THREE = require('three');
4
- var Reconciler = require('react-reconciler');
5
- var constants = require('react-reconciler/constants');
6
3
  var React = require('react');
7
4
  var suspendReact = require('suspend-react');
5
+ var THREE = require('three');
6
+ var constants = require('react-reconciler/constants');
8
7
  var create = require('zustand');
8
+ var Reconciler = require('react-reconciler');
9
+ var scheduler = require('scheduler');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
11
12
 
@@ -18,19 +19,21 @@ function _interopNamespace(e) {
18
19
  var d = Object.getOwnPropertyDescriptor(e, k);
19
20
  Object.defineProperty(n, k, d.get ? d : {
20
21
  enumerable: true,
21
- get: function () { return e[k]; }
22
+ get: function () {
23
+ return e[k];
24
+ }
22
25
  });
23
26
  }
24
27
  });
25
28
  }
26
- n["default"] = e;
29
+ n['default'] = e;
27
30
  return Object.freeze(n);
28
31
  }
29
32
 
30
- var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
31
- var Reconciler__default = /*#__PURE__*/_interopDefault(Reconciler);
32
33
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
34
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
33
35
  var create__default = /*#__PURE__*/_interopDefault(create);
36
+ var Reconciler__default = /*#__PURE__*/_interopDefault(Reconciler);
34
37
 
35
38
  var threeTypes = /*#__PURE__*/Object.freeze({
36
39
  __proto__: null
@@ -40,7 +43,34 @@ const DEFAULT = '__default';
40
43
  const isDiffSet = def => def && !!def.memoized && !!def.changes;
41
44
  function calculateDpr(dpr) {
42
45
  return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], window.devicePixelRatio), dpr[1]) : dpr;
43
- } // A collection of compare functions
46
+ }
47
+ /**
48
+ * Picks or omits keys from an object
49
+ * `omit` will filter out keys, and otherwise cherry-pick them.
50
+ */
51
+
52
+ function filterKeys(obj, omit, ...keys) {
53
+ const keysToSelect = new Set(keys);
54
+ return Object.entries(obj).reduce((acc, [key, value]) => {
55
+ const shouldInclude = !omit;
56
+
57
+ if (keysToSelect.has(key) === shouldInclude) {
58
+ acc[key] = value;
59
+ }
60
+
61
+ return acc;
62
+ }, {});
63
+ }
64
+ /**
65
+ * Clones an object and cherry-picks keys.
66
+ */
67
+
68
+ const pick = (obj, keys) => filterKeys(obj, false, ...keys);
69
+ /**
70
+ * Clones an object and prunes or omits keys.
71
+ */
72
+
73
+ const omit = (obj, keys) => filterKeys(obj, true, ...keys); // A collection of compare functions
44
74
 
45
75
  const is = {
46
76
  obj: a => a === Object(a) && !is.arr(a) && typeof a !== 'function',
@@ -89,8 +119,7 @@ function dispose(obj) {
89
119
  if (obj.dispose && obj.type !== 'Scene') obj.dispose();
90
120
 
91
121
  for (const p in obj) {
92
- var _dispose, _ref;
93
- (_dispose = (_ref = p).dispose) == null ? void 0 : _dispose.call(_ref);
122
+ p.dispose == null ? void 0 : p.dispose();
94
123
  delete obj[p];
95
124
  }
96
125
  } // Each object in the scene carries a small LocalState descriptor
@@ -111,6 +140,49 @@ function prepare(object, state) {
111
140
  }
112
141
 
113
142
  return object;
143
+ }
144
+
145
+ function resolve(instance, key) {
146
+ let target = instance;
147
+
148
+ if (key.includes('-')) {
149
+ const entries = key.split('-');
150
+ const last = entries.pop();
151
+ target = entries.reduce((acc, key) => acc[key], instance);
152
+ return {
153
+ target,
154
+ key: last
155
+ };
156
+ } else return {
157
+ target,
158
+ key
159
+ };
160
+ }
161
+
162
+ function attach(parent, child, type) {
163
+ if (is.str(type)) {
164
+ const {
165
+ target,
166
+ key
167
+ } = resolve(parent, type);
168
+ parent.__r3f.previousAttach = target[key];
169
+ target[key] = child;
170
+ } else if (is.arr(type)) {
171
+ const [attach] = type;
172
+ if (is.str(attach)) parent[attach](child);else if (is.fun(attach)) attach(parent, child);
173
+ }
174
+ }
175
+ function detach(parent, child, type) {
176
+ if (is.str(type)) {
177
+ const {
178
+ target,
179
+ key
180
+ } = resolve(parent, type);
181
+ target[key] = parent.__r3f.previousAttach;
182
+ } else if (is.arr(type)) {
183
+ const [, detach] = type;
184
+ if (is.str(detach)) parent[detach](child);else if (is.fun(detach)) detach(parent, child);
185
+ }
114
186
  } // Shallow check arrays, but check objects atomically
115
187
 
116
188
  function checkShallow(a, b) {
@@ -140,7 +212,9 @@ function diffProps(instance, {
140
212
  if (remove) {
141
213
  const previousKeys = Object.keys(previous);
142
214
 
143
- for (let i = 0; i < previousKeys.length; i++) if (!props.hasOwnProperty(previousKeys[i])) entries.unshift([previousKeys[i], DEFAULT + 'remove']);
215
+ for (let i = 0; i < previousKeys.length; i++) {
216
+ if (!props.hasOwnProperty(previousKeys[i])) entries.unshift([previousKeys[i], DEFAULT + 'remove']);
217
+ }
144
218
  }
145
219
 
146
220
  entries.forEach(([key, value]) => {
@@ -167,7 +241,7 @@ function diffProps(instance, {
167
241
  };
168
242
  } // This function applies a set of changes to the instance
169
243
 
170
- function applyProps(instance, data) {
244
+ function applyProps$1(instance, data) {
171
245
  var _instance$__r3f3, _root$getState;
172
246
 
173
247
  // Filter equals, events and reserved props
@@ -211,7 +285,9 @@ function applyProps(instance, data) {
211
285
  value = defaultClassCall[targetProp]; // destory the instance
212
286
 
213
287
  if (defaultClassCall.dispose) defaultClassCall.dispose(); // instance does not have constructor, just set it to 0
214
- } else value = 0;
288
+ } else {
289
+ value = 0;
290
+ }
215
291
  } // Deal with pointer events ...
216
292
 
217
293
 
@@ -220,35 +296,39 @@ function applyProps(instance, data) {
220
296
  localState.eventCount = Object.keys(localState.handlers).length;
221
297
  } // Special treatment for objects with support for set/copy, and layers
222
298
  else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE__namespace.Layers)) {
223
- // If value is an array
224
- if (Array.isArray(value)) {
225
- if (targetProp.fromArray) targetProp.fromArray(value);else targetProp.set(...value);
226
- } // Test again target.copy(class) next ...
227
- else if (targetProp.copy && value && value.constructor && targetProp.constructor.name === value.constructor.name) targetProp.copy(value); // If nothing else fits, just set the single value, ignore undefined
228
- // https://github.com/react-spring/react-three-fiber/issues/274
229
- else if (value !== undefined) {
230
- const isColor = targetProp instanceof THREE__namespace.Color; // Allow setting array scalars
231
-
232
- if (!isColor && targetProp.setScalar) targetProp.setScalar(value); // Layers have no copy function, we must therefore copy the mask property
233
- else if (targetProp instanceof THREE__namespace.Layers && value instanceof THREE__namespace.Layers) targetProp.mask = value.mask; // Otherwise just set ...
234
- else targetProp.set(value); // Auto-convert sRGB colors, for now ...
235
- // https://github.com/react-spring/react-three-fiber/issues/344
236
-
237
- if (!rootState.linear && isColor) targetProp.convertSRGBToLinear();
238
- } // Else, just overwrite the value
299
+ // If value is an array
300
+ if (Array.isArray(value)) {
301
+ if (targetProp.fromArray) targetProp.fromArray(value);else targetProp.set(...value);
302
+ } // Test again target.copy(class) next ...
303
+ else if (targetProp.copy && value && value.constructor && targetProp.constructor.name === value.constructor.name) {
304
+ targetProp.copy(value);
305
+ } // If nothing else fits, just set the single value, ignore undefined
306
+ // https://github.com/pmndrs/react-three-fiber/issues/274
307
+ else if (value !== undefined) {
308
+ const isColor = targetProp instanceof THREE__namespace.Color; // Allow setting array scalars
309
+
310
+ if (!isColor && targetProp.setScalar) targetProp.setScalar(value); // Layers have no copy function, we must therefore copy the mask property
311
+ else if (targetProp instanceof THREE__namespace.Layers && value instanceof THREE__namespace.Layers) targetProp.mask = value.mask; // Otherwise just set ...
312
+ else targetProp.set(value); // Auto-convert sRGB colors, for now ...
313
+ // https://github.com/pmndrs/react-three-fiber/issues/344
314
+
315
+ if (!rootState.linear && isColor) targetProp.convertSRGBToLinear();
316
+ } // Else, just overwrite the value
239
317
 
240
- } else {
241
- currentInstance[key] = value; // Auto-convert sRGB textures, for now ...
242
- // https://github.com/react-spring/react-three-fiber/issues/344
318
+ } else {
319
+ currentInstance[key] = value; // Auto-convert sRGB textures, for now ...
320
+ // https://github.com/pmndrs/react-three-fiber/issues/344
243
321
 
244
- if (!rootState.linear && currentInstance[key] instanceof THREE__namespace.Texture) currentInstance[key].encoding = THREE__namespace.sRGBEncoding;
245
- }
322
+ if (!rootState.linear && currentInstance[key] instanceof THREE__namespace.Texture) {
323
+ currentInstance[key].encoding = THREE__namespace.sRGBEncoding;
324
+ }
325
+ }
246
326
 
247
327
  invalidateInstance(instance);
248
328
  return instance;
249
329
  });
250
330
 
251
- if (rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
331
+ if (localState.parent && rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
252
332
  // Pre-emptively remove the instance from the interaction manager
253
333
  const index = rootState.internal.interaction.indexOf(instance);
254
334
  if (index > -1) rootState.internal.interaction.splice(index, 1); // Add the instance to the interaction manager only when it has handlers
@@ -271,12 +351,41 @@ function updateInstance(instance) {
271
351
 
272
352
  function makeId(event) {
273
353
  return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
354
+ } // https://github.com/facebook/react/tree/main/packages/react-reconciler#getcurrenteventpriority
355
+ // Gives React a clue as to how import the current interaction is
356
+
357
+
358
+ function getEventPriority() {
359
+ var _window, _window$event;
360
+
361
+ let name = (_window = window) == null ? void 0 : (_window$event = _window.event) == null ? void 0 : _window$event.type;
362
+
363
+ switch (name) {
364
+ case 'click':
365
+ case 'contextmenu':
366
+ case 'dblclick':
367
+ case 'pointercancel':
368
+ case 'pointerdown':
369
+ case 'pointerup':
370
+ return constants.DiscreteEventPriority;
371
+
372
+ case 'pointermove':
373
+ case 'pointerout':
374
+ case 'pointerover':
375
+ case 'pointerenter':
376
+ case 'pointerleave':
377
+ case 'wheel':
378
+ return constants.ContinuousEventPriority;
379
+
380
+ default:
381
+ return constants.DefaultEventPriority;
382
+ }
274
383
  }
275
- /** Release pointer captures.
384
+ /**
385
+ * Release pointer captures.
276
386
  * This is called by releasePointerCapture in the API, and when an object is removed.
277
387
  */
278
388
 
279
-
280
389
  function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
281
390
  const captureData = captures.get(obj);
282
391
 
@@ -311,7 +420,7 @@ function createEvents(store) {
311
420
  /** Sets up defaultRaycaster */
312
421
 
313
422
  function prepareRay(event) {
314
- var _raycaster$computeOff;
423
+ var _customOffsets$offset, _customOffsets$offset2, _customOffsets$width, _customOffsets$height;
315
424
 
316
425
  const state = store.getState();
317
426
  const {
@@ -322,14 +431,11 @@ function createEvents(store) {
322
431
  } = state; // https://github.com/pmndrs/react-three-fiber/pull/782
323
432
  // Events trigger outside of canvas when moved
324
433
 
325
- const {
326
- offsetX,
327
- offsetY
328
- } = (_raycaster$computeOff = raycaster.computeOffsets == null ? void 0 : raycaster.computeOffsets(event, state)) != null ? _raycaster$computeOff : event;
329
- const {
330
- width,
331
- height
332
- } = size;
434
+ const customOffsets = raycaster.computeOffsets == null ? void 0 : raycaster.computeOffsets(event, state);
435
+ const offsetX = (_customOffsets$offset = customOffsets == null ? void 0 : customOffsets.offsetX) != null ? _customOffsets$offset : event.offsetX;
436
+ const offsetY = (_customOffsets$offset2 = customOffsets == null ? void 0 : customOffsets.offsetY) != null ? _customOffsets$offset2 : event.offsetY;
437
+ const width = (_customOffsets$width = customOffsets == null ? void 0 : customOffsets.width) != null ? _customOffsets$width : size.width;
438
+ const height = (_customOffsets$height = customOffsets == null ? void 0 : customOffsets.height) != null ? _customOffsets$height : size.height;
333
439
  mouse.set(offsetX / width * 2 - 1, -(offsetY / height) * 2 + 1);
334
440
  raycaster.setFromCamera(mouse, camera);
335
441
  }
@@ -559,13 +665,16 @@ function createEvents(store) {
559
665
 
560
666
  case 'onLostPointerCapture':
561
667
  return event => {
562
- if ('pointerId' in event) {
668
+ const {
669
+ internal
670
+ } = store.getState();
671
+
672
+ if ('pointerId' in event && !internal.capturedMap.has(event.pointerId)) {
563
673
  // If the object event interface had onLostPointerCapture, we'd call it here on every
564
674
  // object that's getting removed.
565
- store.getState().internal.capturedMap.delete(event.pointerId);
675
+ internal.capturedMap.delete(event.pointerId);
676
+ cancelPointer([]);
566
677
  }
567
-
568
- cancelPointer([]);
569
678
  };
570
679
  } // Any other pointer goes here ...
571
680
 
@@ -575,7 +684,8 @@ function createEvents(store) {
575
684
  onPointerMissed,
576
685
  internal
577
686
  } = store.getState();
578
- prepareRay(event); // Get fresh intersects
687
+ prepareRay(event);
688
+ internal.lastEvent.current = event; // Get fresh intersects
579
689
 
580
690
  const isPointerMove = name === 'onPointerMove';
581
691
  const isClickEvent = name === 'onClick' || name === 'onContextMenu' || name === 'onDoubleClick';
@@ -633,12 +743,17 @@ function createEvents(store) {
633
743
  if (handler) {
634
744
  // Forward all events back to their respective handlers with the exception of click events,
635
745
  // which must use the initial target
636
- if (name !== 'onClick' && name !== 'onContextMenu' && name !== 'onDoubleClick' || internal.initialHits.includes(eventObject)) {
746
+ if (!isClickEvent || internal.initialHits.includes(eventObject)) {
637
747
  // Missed events have to come first
638
748
  pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object))); // Now call the handler
639
749
 
640
750
  handler(data);
641
751
  }
752
+ } else {
753
+ // Trigger onPointerMissed on all elements that have pointer over/out handlers, but not click and weren't hit
754
+ if (isClickEvent && internal.initialHits.includes(eventObject)) {
755
+ pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object)));
756
+ }
642
757
  }
643
758
  }
644
759
  });
@@ -684,6 +799,7 @@ let extend = objects => void (catalogue = { ...catalogue,
684
799
  function createRenderer(roots, getEventPriority) {
685
800
  function createInstance(type, {
686
801
  args = [],
802
+ attach,
687
803
  ...props
688
804
  }, root, hostContext, internalInstanceHandle) {
689
805
  let name = `${type[0].toUpperCase()}${type.slice(1)}`;
@@ -700,87 +816,65 @@ function createRenderer(roots, getEventPriority) {
700
816
  } // Assert that by now we have a valid root
701
817
 
702
818
 
703
- if (!root || !isStore(root)) throw `No valid root for ${name}!`;
819
+ if (!root || !isStore(root)) throw `No valid root for ${name}!`; // Auto-attach geometries and materials
820
+
821
+ if (attach === undefined) {
822
+ if (name.endsWith('Geometry')) attach = 'geometry';else if (name.endsWith('Material')) attach = 'material';
823
+ }
704
824
 
705
825
  if (type === 'primitive') {
706
826
  if (props.object === undefined) throw `Primitives without 'object' are invalid!`;
707
827
  const object = props.object;
708
828
  instance = prepare(object, {
709
829
  root,
830
+ attach,
710
831
  primitive: true
711
832
  });
712
833
  } else {
713
- const target = catalogue[name] || THREE__namespace[name];
714
- if (!target) throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`; // Instanciate new object, link it to the root
834
+ const target = catalogue[name];
835
+
836
+ if (!target) {
837
+ throw `${name} is not part of the THREE namespace! Did you forget to extend? See: https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#using-3rd-party-objects-declaratively`;
838
+ } // Throw if an object or literal was passed for args
839
+
840
+
841
+ if (!Array.isArray(args)) throw 'The args prop must be an array!'; // Instanciate new object, link it to the root
715
842
  // Append memoized props with args so it's not forgotten
716
843
 
717
844
  instance = prepare(new target(...args), {
718
845
  root,
846
+ attach,
847
+ // TODO: Figure out what this is for
719
848
  memoizedProps: {
720
849
  args: args.length === 0 ? null : args
721
850
  }
722
851
  });
723
- } // Auto-attach geometries and materials
724
-
725
-
726
- if (!('attachFns' in props)) {
727
- if (name.endsWith('Geometry')) {
728
- props = {
729
- attach: 'geometry',
730
- ...props
731
- };
732
- } else if (name.endsWith('Material')) {
733
- props = {
734
- attach: 'material',
735
- ...props
736
- };
737
- }
738
852
  } // It should NOT call onUpdate on object instanciation, because it hasn't been added to the
739
853
  // view yet. If the callback relies on references for instance, they won't be ready yet, this is
740
854
  // why it passes "true" here
741
855
 
742
856
 
743
- applyProps(instance, props);
857
+ applyProps$1(instance, props);
744
858
  return instance;
745
859
  }
746
860
 
747
861
  function appendChild(parentInstance, child) {
748
- let addedAsChild = false;
862
+ let added = false;
749
863
 
750
864
  if (child) {
751
865
  // The attach attribute implies that the object attaches itself on the parent
752
- if (child.attachArray) {
753
- if (!is.arr(parentInstance[child.attachArray])) parentInstance[child.attachArray] = [];
754
- parentInstance[child.attachArray].push(child);
755
- } else if (child.attachObject) {
756
- if (!is.obj(parentInstance[child.attachObject[0]])) parentInstance[child.attachObject[0]] = {};
757
- parentInstance[child.attachObject[0]][child.attachObject[1]] = child;
758
- } else if (child.attach && !is.fun(child.attach)) {
759
- parentInstance[child.attach] = child;
760
- } else if (is.arr(child.attachFns)) {
761
- const [attachFn] = child.attachFns;
762
-
763
- if (is.str(attachFn) && is.fun(parentInstance[attachFn])) {
764
- parentInstance[attachFn](child);
765
- } else if (is.fun(attachFn)) {
766
- attachFn(child, parentInstance);
767
- }
866
+ if (child.__r3f.attach) {
867
+ attach(parentInstance, child, child.__r3f.attach);
768
868
  } else if (child.isObject3D && parentInstance.isObject3D) {
769
869
  // add in the usual parent-child way
770
870
  parentInstance.add(child);
771
- addedAsChild = true;
772
- }
773
-
774
- if (!addedAsChild) {
775
- // This is for anything that used attach, and for non-Object3Ds that don't get attached to props;
776
- // that is, anything that's a child in React but not a child in the scenegraph.
777
- parentInstance.__r3f.objects.push(child);
778
- }
871
+ added = true;
872
+ } // This is for anything that used attach, and for non-Object3Ds that don't get attached to props;
873
+ // that is, anything that's a child in React but not a child in the scenegraph.
779
874
 
780
- if (!child.__r3f) {
781
- prepare(child, {});
782
- }
783
875
 
876
+ if (!added) parentInstance.__r3f.objects.push(child);
877
+ if (!child.__r3f) prepare(child, {});
784
878
  child.__r3f.parent = parentInstance;
785
879
  updateInstance(child);
786
880
  invalidateInstance(child);
@@ -791,13 +885,8 @@ function createRenderer(roots, getEventPriority) {
791
885
  let added = false;
792
886
 
793
887
  if (child) {
794
- if (child.attachArray) {
795
- const array = parentInstance[child.attachArray];
796
- if (!is.arr(array)) parentInstance[child.attachArray] = [];
797
- array.splice(array.indexOf(beforeChild), 0, child);
798
- } else if (child.attachObject || child.attach && !is.fun(child.attach)) {
799
- // attach and attachObject don't have an order anyway, so just append
800
- return appendChild(parentInstance, child);
888
+ if (child.__r3f.attach) {
889
+ attach(parentInstance, child, child.__r3f.attach);
801
890
  } else if (child.isObject3D && parentInstance.isObject3D) {
802
891
  child.parent = parentInstance;
803
892
  child.dispatchEvent({
@@ -809,14 +898,8 @@ function createRenderer(roots, getEventPriority) {
809
898
  added = true;
810
899
  }
811
900
 
812
- if (!added) {
813
- parentInstance.__r3f.objects.push(child);
814
- }
815
-
816
- if (!child.__r3f) {
817
- prepare(child, {});
818
- }
819
-
901
+ if (!added) parentInstance.__r3f.objects.push(child);
902
+ if (!child.__r3f) prepare(child, {});
820
903
  child.__r3f.parent = parentInstance;
821
904
  updateInstance(child);
822
905
  invalidateInstance(child);
@@ -831,29 +914,13 @@ function createRenderer(roots, getEventPriority) {
831
914
  if (child) {
832
915
  var _parentInstance$__r3f, _child$__r3f2;
833
916
 
834
- if (child.__r3f) {
835
- child.__r3f.parent = null;
836
- }
917
+ // Clear the parent reference
918
+ if (child.__r3f) child.__r3f.parent = null; // Remove child from the parents objects
837
919
 
838
- if ((_parentInstance$__r3f = parentInstance.__r3f) != null && _parentInstance$__r3f.objects) {
839
- parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(x => x !== child);
840
- } // Remove attachment
920
+ if ((_parentInstance$__r3f = parentInstance.__r3f) != null && _parentInstance$__r3f.objects) parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(x => x !== child); // Remove attachment
841
921
 
842
-
843
- if (child.attachArray) {
844
- parentInstance[child.attachArray] = parentInstance[child.attachArray].filter(x => x !== child);
845
- } else if (child.attachObject) {
846
- delete parentInstance[child.attachObject[0]][child.attachObject[1]];
847
- } else if (child.attach && !is.fun(child.attach)) {
848
- parentInstance[child.attach] = null;
849
- } else if (is.arr(child.attachFns)) {
850
- const [, detachFn] = child.attachFns;
851
-
852
- if (is.str(detachFn) && is.fun(parentInstance[detachFn])) {
853
- parentInstance[detachFn](child);
854
- } else if (is.fun(detachFn)) {
855
- detachFn(child, parentInstance);
856
- }
922
+ if (child.__r3f.attach) {
923
+ detach(parentInstance, child, child.__r3f.attach);
857
924
  } else if (child.isObject3D && parentInstance.isObject3D) {
858
925
  var _child$__r3f;
859
926
 
@@ -895,7 +962,7 @@ function createRenderer(roots, getEventPriority) {
895
962
 
896
963
 
897
964
  if (shouldDispose && child.dispose && child.type !== 'Scene') {
898
- reconciler.runWithPriority(constants.IdleEventPriority, () => {
965
+ scheduler.unstable_scheduleCallback(scheduler.unstable_IdlePriority, () => {
899
966
  try {
900
967
  child.dispose();
901
968
  } catch (e) {
@@ -927,10 +994,13 @@ function createRenderer(roots, getEventPriority) {
927
994
 
928
995
  instance.__r3f.objects = [];
929
996
  removeChild(parent, instance);
930
- appendChild(parent, newInstance) // This evil hack switches the react-internal fiber node
931
- // https://github.com/facebook/react/issues/14983
932
- // https://github.com/facebook/react/pull/15021
933
- ;
997
+ appendChild(parent, newInstance); // Re-bind event handlers
998
+
999
+ if (newInstance.raycast && newInstance.__r3f.eventCount) {
1000
+ const rootState = newInstance.__r3f.root.getState();
1001
+
1002
+ rootState.internal.interaction.push(newInstance);
1003
+ } // This evil hack switches the react-internal fiber node
934
1004
  [fiber, fiber.alternate].forEach(fiber => {
935
1005
  if (fiber !== null) {
936
1006
  fiber.stateNode = newInstance;
@@ -942,7 +1012,7 @@ function createRenderer(roots, getEventPriority) {
942
1012
  });
943
1013
  }
944
1014
 
945
- const reconciler = Reconciler__default["default"]({
1015
+ const reconciler = Reconciler__default['default']({
946
1016
  appendChildToContainer: (parentInstance, child) => {
947
1017
  const {
948
1018
  container,
@@ -956,7 +1026,9 @@ function createRenderer(roots, getEventPriority) {
956
1026
  insertInContainerBefore: (parentInstance, child, beforeChild) => insertBefore(getContainer(parentInstance, child).container, child, beforeChild),
957
1027
 
958
1028
  prepareUpdate(instance, type, oldProps, newProps) {
959
- if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) return [true];else {
1029
+ if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
1030
+ return [true];
1031
+ } else {
960
1032
  // This is a data object, let's extract critical information about it
961
1033
  const {
962
1034
  args: argsNew = [],
@@ -967,7 +1039,9 @@ function createRenderer(roots, getEventPriority) {
967
1039
  args: argsOld = [],
968
1040
  children: cO,
969
1041
  ...restOld
970
- } = oldProps; // If it has new props or arguments, then it needs to be re-instanciated
1042
+ } = oldProps; // Throw if an object or literal was passed for args
1043
+
1044
+ 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
971
1045
 
972
1046
  if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
973
1047
 
@@ -981,21 +1055,33 @@ function createRenderer(roots, getEventPriority) {
981
1055
  commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
982
1056
  // Reconstruct when args or <primitive object={...} have changes
983
1057
  if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
984
- else applyProps(instance, diff);
1058
+ else applyProps$1(instance, diff);
985
1059
  },
986
1060
 
987
1061
  hideInstance(instance) {
988
- if (instance.isObject3D) {
989
- instance.visible = false;
990
- invalidateInstance(instance);
991
- }
1062
+ var _instance$__r3f2;
1063
+
1064
+ // Deatch while the instance is hidden
1065
+ const {
1066
+ attach: type,
1067
+ parent
1068
+ } = (_instance$__r3f2 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f2 : {};
1069
+ if (type && parent) detach(parent, instance, type);
1070
+ if (instance.isObject3D) instance.visible = false;
1071
+ invalidateInstance(instance);
992
1072
  },
993
1073
 
994
1074
  unhideInstance(instance, props) {
995
- if (instance.isObject3D && props.visible == null || props.visible) {
996
- instance.visible = true;
997
- invalidateInstance(instance);
998
- }
1075
+ var _instance$__r3f3;
1076
+
1077
+ // Re-attach when the instance is unhidden
1078
+ const {
1079
+ attach: type,
1080
+ parent
1081
+ } = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
1082
+ if (type && parent) attach(parent, instance, type);
1083
+ if (instance.isObject3D && props.visible == null || props.visible) instance.visible = true;
1084
+ invalidateInstance(instance);
999
1085
  },
1000
1086
 
1001
1087
  createInstance,
@@ -1008,7 +1094,7 @@ function createRenderer(roots, getEventPriority) {
1008
1094
  isPrimaryRenderer: false,
1009
1095
  getCurrentEventPriority: () => getEventPriority ? getEventPriority() : constants.DefaultEventPriority,
1010
1096
  // @ts-ignore
1011
- now: is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : undefined,
1097
+ now: typeof performance !== 'undefined' && is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : undefined,
1012
1098
  // @ts-ignore
1013
1099
  scheduleTimeout: is.fun(setTimeout) ? setTimeout : undefined,
1014
1100
  // @ts-ignore
@@ -1024,8 +1110,30 @@ function createRenderer(roots, getEventPriority) {
1024
1110
  getRootHostContext: () => null,
1025
1111
  getChildHostContext: parentHostContext => parentHostContext,
1026
1112
  createTextInstance: () => {},
1027
- finalizeInitialChildren: () => false,
1028
- commitMount: () => {},
1113
+
1114
+ finalizeInitialChildren(instance) {
1115
+ var _instance$__r3f4;
1116
+
1117
+ // https://github.com/facebook/react/issues/20271
1118
+ // Returning true will trigger commitMount
1119
+ const localState = (_instance$__r3f4 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f4 : {};
1120
+ return !!localState.handlers;
1121
+ },
1122
+
1123
+ commitMount(instance)
1124
+ /*, type, props*/
1125
+ {
1126
+ var _instance$__r3f5;
1127
+
1128
+ // https://github.com/facebook/react/issues/20271
1129
+ // This will make sure events are only added once to the central container
1130
+ const localState = (_instance$__r3f5 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f5 : {};
1131
+
1132
+ if (instance.raycast && localState.handlers && localState.eventCount) {
1133
+ instance.__r3f.root.getState().internal.interaction.push(instance);
1134
+ }
1135
+ },
1136
+
1029
1137
  shouldDeprioritizeSubtree: () => false,
1030
1138
  prepareForCommit: () => null,
1031
1139
  preparePortalMount: containerInfo => prepare(containerInfo),
@@ -1036,7 +1144,7 @@ function createRenderer(roots, getEventPriority) {
1036
1144
  });
1037
1145
  return {
1038
1146
  reconciler,
1039
- applyProps
1147
+ applyProps: applyProps$1
1040
1148
  };
1041
1149
  }
1042
1150
 
@@ -1075,7 +1183,7 @@ const createStore = (applyProps, invalidate, advance, props) => {
1075
1183
  clock.elapsedTime = 0;
1076
1184
  }
1077
1185
 
1078
- const rootState = create__default["default"]((set, get) => {
1186
+ const rootState = create__default['default']((set, get) => {
1079
1187
  // Create custom raycaster
1080
1188
  const raycaster = new THREE__namespace.Raycaster();
1081
1189
  const {
@@ -1147,18 +1255,19 @@ const createStore = (applyProps, invalidate, advance, props) => {
1147
1255
  })); // Handle frame behavior in WebXR
1148
1256
 
1149
1257
 
1150
- const handleXRFrame = timestamp => {
1258
+ const handleXRFrame = (timestamp, frame) => {
1151
1259
  const state = get();
1152
1260
  if (state.frameloop === 'never') return;
1153
- advance(timestamp, true);
1261
+ advance(timestamp, true, state, frame);
1154
1262
  }; // Toggle render switching on session
1155
1263
 
1156
1264
 
1157
1265
  const handleSessionChange = () => {
1158
- gl.xr.enabled = gl.xr.isPresenting;
1159
- gl.setAnimationLoop(gl.xr.isPresenting ? handleXRFrame : null); // If exiting session, request frame
1266
+ gl.xr.enabled = gl.xr.isPresenting; // @ts-expect-error
1267
+ // WebXRManager's signature is incorrect.
1268
+ // See: https://github.com/pmndrs/react-three-fiber/pull/2017#discussion_r790134505
1160
1269
 
1161
- if (!gl.xr.isPresenting) invalidate(get());
1270
+ gl.xr.setAnimationLoop(gl.xr.isPresenting ? handleXRFrame : null);
1162
1271
  }; // WebXR session manager
1163
1272
 
1164
1273
 
@@ -1239,6 +1348,9 @@ const createStore = (applyProps, invalidate, advance, props) => {
1239
1348
  dpr: calculateDpr(dpr)
1240
1349
  }
1241
1350
  })),
1351
+ setFrameloop: (frameloop = 'always') => set(() => ({
1352
+ frameloop
1353
+ })),
1242
1354
  events: {
1243
1355
  connected: false
1244
1356
  },
@@ -1247,6 +1359,7 @@ const createStore = (applyProps, invalidate, advance, props) => {
1247
1359
  priority: 0,
1248
1360
  frames: 0,
1249
1361
  lastProps: props,
1362
+ lastEvent: /*#__PURE__*/React__namespace.createRef(),
1250
1363
  interaction: [],
1251
1364
  hovered: new Map(),
1252
1365
  subscribers: [],
@@ -1303,7 +1416,7 @@ const createStore = (applyProps, invalidate, advance, props) => {
1303
1416
  if (size !== oldSize || viewport.dpr !== oldDpr) {
1304
1417
  // https://github.com/pmndrs/react-three-fiber/issues/92
1305
1418
  // Do not mess with the camera if it belongs to the user
1306
- if (!(internal.lastProps.camera instanceof THREE__namespace.Camera)) {
1419
+ if (!camera.manual && !(internal.lastProps.camera instanceof THREE__namespace.Camera)) {
1307
1420
  if (isOrthographicCamera(camera)) {
1308
1421
  camera.left = size.width / -2;
1309
1422
  camera.right = size.width / 2;
@@ -1352,7 +1465,7 @@ function run(effects, timestamp) {
1352
1465
  for (i = 0; i < effects.length; i++) effects[i](timestamp);
1353
1466
  }
1354
1467
 
1355
- function render(timestamp, state) {
1468
+ function render$1(timestamp, state, frame) {
1356
1469
  // Run local effects
1357
1470
  let delta = state.clock.getDelta(); // In frameloop='never' mode, clock times are updated using the provided timestamp
1358
1471
 
@@ -1363,7 +1476,7 @@ function render(timestamp, state) {
1363
1476
  } // Call subscribers (useFrame)
1364
1477
 
1365
1478
 
1366
- for (i = 0; i < state.internal.subscribers.length; i++) state.internal.subscribers[i].ref.current(state, delta); // Render content
1479
+ for (i = 0; i < state.internal.subscribers.length; i++) state.internal.subscribers[i].ref.current(state, delta, frame); // Render content
1367
1480
 
1368
1481
 
1369
1482
  if (!state.internal.priority && state.gl.render) state.gl.render(state.scene, state.camera); // Decrease frame count
@@ -1387,7 +1500,9 @@ function createLoop(roots) {
1387
1500
 
1388
1501
  const state = root.store.getState(); // If the frameloop is invalidated, do not run another frame
1389
1502
 
1390
- if (state.internal.active && (state.frameloop === 'always' || state.internal.frames > 0) && !((_state$gl$xr = state.gl.xr) != null && _state$gl$xr.isPresenting)) repeat += render(timestamp, state);
1503
+ if (state.internal.active && (state.frameloop === 'always' || state.internal.frames > 0) && !((_state$gl$xr = state.gl.xr) != null && _state$gl$xr.isPresenting)) {
1504
+ repeat += render$1(timestamp, state);
1505
+ }
1391
1506
  }); // Run after-effects
1392
1507
 
1393
1508
  run(globalAfterEffects, timestamp); // Keep on looping if anything invalidates the frameloop
@@ -1412,9 +1527,9 @@ function createLoop(roots) {
1412
1527
  }
1413
1528
  }
1414
1529
 
1415
- function advance(timestamp, runGlobalEffects = true, state) {
1530
+ function advance(timestamp, runGlobalEffects = true, state, frame) {
1416
1531
  if (runGlobalEffects) run(globalEffects, timestamp);
1417
- if (!state) roots.forEach(root => render(timestamp, root.store.getState()));else render(timestamp, state);
1532
+ if (!state) roots.forEach(root => render$1(timestamp, root.store.getState()));else render$1(timestamp, state, frame);
1418
1533
  if (runGlobalEffects) run(globalAfterEffects, timestamp);
1419
1534
  }
1420
1535
 
@@ -1479,21 +1594,209 @@ useLoader.clear = function (Proto, input) {
1479
1594
  return suspendReact.clear([Proto, ...keys]);
1480
1595
  };
1481
1596
 
1597
+ const roots = new Map();
1598
+ const {
1599
+ invalidate,
1600
+ advance
1601
+ } = createLoop(roots);
1602
+ const {
1603
+ reconciler,
1604
+ applyProps
1605
+ } = createRenderer(roots, getEventPriority);
1606
+
1607
+ const createRendererInstance = (gl, canvas) => {
1608
+ const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
1609
+ if (isRenderer(customRenderer)) return customRenderer;
1610
+ const renderer = new THREE__namespace.WebGLRenderer({
1611
+ powerPreference: 'high-performance',
1612
+ canvas: canvas,
1613
+ antialias: true,
1614
+ alpha: true,
1615
+ ...gl
1616
+ }); // Set color management
1617
+
1618
+ renderer.outputEncoding = THREE__namespace.sRGBEncoding;
1619
+ renderer.toneMapping = THREE__namespace.ACESFilmicToneMapping; // Set gl props
1620
+
1621
+ if (gl) applyProps(renderer, gl);
1622
+ return renderer;
1623
+ };
1624
+
1625
+ function createRoot(canvas, config) {
1626
+ return {
1627
+ render: element => {
1628
+ var _store;
1629
+
1630
+ let {
1631
+ gl,
1632
+ size,
1633
+ events,
1634
+ onCreated,
1635
+ ...props
1636
+ } = config || {}; // Allow size to take on container bounds initially
1637
+
1638
+ if (!size) {
1639
+ var _canvas$parentElement, _canvas$parentElement2, _canvas$parentElement3, _canvas$parentElement4;
1640
+
1641
+ size = {
1642
+ width: (_canvas$parentElement = (_canvas$parentElement2 = canvas.parentElement) == null ? void 0 : _canvas$parentElement2.clientWidth) != null ? _canvas$parentElement : 0,
1643
+ height: (_canvas$parentElement3 = (_canvas$parentElement4 = canvas.parentElement) == null ? void 0 : _canvas$parentElement4.clientHeight) != null ? _canvas$parentElement3 : 0
1644
+ };
1645
+ }
1646
+
1647
+ let root = roots.get(canvas);
1648
+ let fiber = root == null ? void 0 : root.fiber;
1649
+ let store = root == null ? void 0 : root.store;
1650
+ let state = (_store = store) == null ? void 0 : _store.getState();
1651
+
1652
+ if (fiber && state) {
1653
+ // When a root was found, see if any fundamental props must be changed or exchanged
1654
+ // Check pixelratio
1655
+ if (props.dpr !== undefined && state.viewport.dpr !== calculateDpr(props.dpr)) state.setDpr(props.dpr); // Check size
1656
+
1657
+ if (state.size.width !== size.width || state.size.height !== size.height) state.setSize(size.width, size.height); // Check frameloop
1658
+
1659
+ if (state.frameloop !== props.frameloop) state.setFrameloop(props.frameloop); // For some props we want to reset the entire root
1660
+ // Changes to the color-space
1661
+
1662
+ const linearChanged = props.linear !== state.internal.lastProps.linear;
1663
+
1664
+ if (linearChanged) {
1665
+ unmountComponentAtNode(canvas);
1666
+ fiber = undefined;
1667
+ }
1668
+ }
1669
+
1670
+ if (!fiber) {
1671
+ // If no root has been found, make one
1672
+ // Create gl
1673
+ const glRenderer = createRendererInstance(gl, canvas); // Create store
1674
+
1675
+ store = createStore(applyProps, invalidate, advance, {
1676
+ gl: glRenderer,
1677
+ size,
1678
+ ...props
1679
+ });
1680
+ const state = store.getState(); // Create renderer
1681
+
1682
+ fiber = reconciler.createContainer(store, constants.ConcurrentRoot, false, null); // Map it
1683
+
1684
+ roots.set(canvas, {
1685
+ fiber,
1686
+ store
1687
+ }); // Store events internally
1688
+
1689
+ if (events) state.set({
1690
+ events: events(store)
1691
+ });
1692
+ }
1693
+
1694
+ if (store && fiber) {
1695
+ reconciler.updateContainer( /*#__PURE__*/React__namespace.createElement(Provider, {
1696
+ store: store,
1697
+ element: element,
1698
+ onCreated: onCreated,
1699
+ target: canvas
1700
+ }), fiber, null, () => undefined);
1701
+ return store;
1702
+ } else {
1703
+ throw 'Error creating root!';
1704
+ }
1705
+ },
1706
+ unmount: () => unmountComponentAtNode(canvas)
1707
+ };
1708
+ }
1709
+
1710
+ function render(element, canvas, config = {}) {
1711
+ console.warn('R3F.render is no longer supported in React 18. Use createRoot instead!');
1712
+ return createRoot(canvas, config).render(element);
1713
+ }
1714
+
1715
+ function Provider({
1716
+ store,
1717
+ element,
1718
+ onCreated,
1719
+ target
1720
+ }) {
1721
+ React__namespace.useEffect(() => {
1722
+ const state = store.getState(); // Flag the canvas active, rendering will now begin
1723
+
1724
+ state.set(state => ({
1725
+ internal: { ...state.internal,
1726
+ active: true
1727
+ }
1728
+ })); // Connect events
1729
+
1730
+ state.events.connect == null ? void 0 : state.events.connect(target); // Notifiy that init is completed, the scene graph exists, but nothing has yet rendered
1731
+
1732
+ if (onCreated) onCreated(state); // eslint-disable-next-line react-hooks/exhaustive-deps
1733
+ }, []);
1734
+ return /*#__PURE__*/React__namespace.createElement(context.Provider, {
1735
+ value: store
1736
+ }, element);
1737
+ }
1738
+
1739
+ function unmountComponentAtNode(canvas, callback) {
1740
+ const root = roots.get(canvas);
1741
+ const fiber = root == null ? void 0 : root.fiber;
1742
+
1743
+ if (fiber) {
1744
+ const state = root == null ? void 0 : root.store.getState();
1745
+ if (state) state.internal.active = false;
1746
+ reconciler.updateContainer(null, fiber, null, () => {
1747
+ if (state) {
1748
+ setTimeout(() => {
1749
+ try {
1750
+ var _state$gl, _state$gl$renderLists, _state$gl2, _state$gl3;
1751
+
1752
+ state.events.disconnect == null ? void 0 : state.events.disconnect();
1753
+ (_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();
1754
+ (_state$gl2 = state.gl) == null ? void 0 : _state$gl2.forceContextLoss == null ? void 0 : _state$gl2.forceContextLoss();
1755
+ if ((_state$gl3 = state.gl) != null && _state$gl3.xr) state.internal.xr.disconnect();
1756
+ dispose(state);
1757
+ roots.delete(canvas);
1758
+ if (callback) callback(canvas);
1759
+ } catch (e) {
1760
+ /* ... */
1761
+ }
1762
+ }, 500);
1763
+ }
1764
+ });
1765
+ }
1766
+ }
1767
+
1768
+ const act = React__namespace.unstable_act;
1769
+
1770
+ function createPortal(children, container) {
1771
+ return reconciler.createPortal(children, container, null, null);
1772
+ }
1773
+
1774
+ reconciler.injectIntoDevTools({
1775
+ bundleType: process.env.NODE_ENV === 'production' ? 0 : 1,
1776
+ rendererPackageName: '@react-three/fiber',
1777
+ version: '18.0.0'
1778
+ });
1779
+
1780
+ exports.act = act;
1482
1781
  exports.addAfterEffect = addAfterEffect;
1483
1782
  exports.addEffect = addEffect;
1484
1783
  exports.addTail = addTail;
1485
- exports.buildGraph = buildGraph;
1486
- exports.calculateDpr = calculateDpr;
1784
+ exports.advance = advance;
1785
+ exports.applyProps = applyProps;
1487
1786
  exports.context = context;
1488
1787
  exports.createEvents = createEvents;
1489
- exports.createLoop = createLoop;
1490
- exports.createRenderer = createRenderer;
1491
- exports.createStore = createStore;
1788
+ exports.createPortal = createPortal;
1789
+ exports.createRoot = createRoot;
1492
1790
  exports.dispose = dispose;
1493
1791
  exports.extend = extend;
1494
- exports.is = is;
1495
- exports.isRenderer = isRenderer;
1792
+ exports.invalidate = invalidate;
1793
+ exports.omit = omit;
1794
+ exports.pick = pick;
1795
+ exports.reconciler = reconciler;
1796
+ exports.render = render;
1797
+ exports.roots = roots;
1496
1798
  exports.threeTypes = threeTypes;
1799
+ exports.unmountComponentAtNode = unmountComponentAtNode;
1497
1800
  exports.useFrame = useFrame;
1498
1801
  exports.useGraph = useGraph;
1499
1802
  exports.useLoader = useLoader;