@react-three/fiber 8.0.0-alpha-05 → 8.0.0-alpha-09

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.
@@ -8,7 +8,6 @@ var constants = require('react-reconciler/constants');
8
8
  var create = require('zustand');
9
9
  var shallow = require('zustand/shallow');
10
10
  var Reconciler = require('react-reconciler');
11
- var scheduler = require('scheduler');
12
11
  var useAsset = require('use-asset');
13
12
  var mergeRefs = require('react-merge-refs');
14
13
  var useMeasure = require('react-use-measure');
@@ -47,6 +46,9 @@ var threeTypes = /*#__PURE__*/Object.freeze({
47
46
  __proto__: null
48
47
  });
49
48
 
49
+ const DEFAULT = '__default';
50
+ const isDiffSet = def => def && !!def.memoized && !!def.changes;
51
+ // A collection of compare functions
50
52
  const is = {
51
53
  obj: a => a === Object(a) && !is.arr(a) && typeof a !== 'function',
52
54
  fun: a => typeof a === 'function',
@@ -72,10 +74,181 @@ const is = {
72
74
  return is.und(i) ? a === b : true;
73
75
  }
74
76
 
75
- };
77
+ }; // Each object in the scene carries a small LocalState descriptor
78
+
79
+ function prepare(object, state) {
80
+ const instance = object;
81
+
82
+ if (state != null && state.primitive || !instance.__r3f) {
83
+ instance.__r3f = {
84
+ root: null,
85
+ memoizedProps: {},
86
+ handlers: {
87
+ count: 0
88
+ },
89
+ objects: [],
90
+ ...state
91
+ };
92
+ }
93
+
94
+ return object;
95
+ } // Shallow check arrays, but check objects atomically
96
+
97
+ function checkShallow(a, b) {
98
+ if (is.arr(a) && is.equ(a, b)) return true;
99
+ if (a === b) return true;
100
+ return false;
101
+ } // This function prepares a set of changes to be applied to the instance
102
+
103
+
104
+ function diffProps(instance, {
105
+ children: cN,
106
+ key: kN,
107
+ ref: rN,
108
+ ...props
109
+ }, {
110
+ children: cP,
111
+ key: kP,
112
+ ref: rP,
113
+ ...previous
114
+ } = {}, remove = false) {
115
+ var _instance$__r3f;
116
+
117
+ const localState = (_instance$__r3f = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f : {};
118
+ const entries = Object.entries(props);
119
+ const changes = []; // Catch removed props, prepend them so they can be reset or removed
120
+
121
+ if (remove) {
122
+ const previousKeys = Object.keys(previous);
123
+
124
+ for (let i = 0; i < previousKeys.length; i++) if (!props.hasOwnProperty(previousKeys[i])) entries.unshift([previousKeys[i], DEFAULT + 'remove']);
125
+ }
126
+
127
+ entries.forEach(([key, value]) => {
128
+ var _instance$__r3f2;
129
+
130
+ // Bail out on primitive object
131
+ if ((_instance$__r3f2 = instance.__r3f) != null && _instance$__r3f2.primitive && key === 'object') return; // When props match bail out
132
+
133
+ if (checkShallow(value, previous[key])) return;
134
+ let currentInstance = instance;
135
+ let targetProp = currentInstance[key]; // Collect handlers and bail out
136
+
137
+ if (/^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/.test(key)) return changes.push([key, value, true, currentInstance, targetProp]); // Revolve dashed props
138
+
139
+ if (key.includes('-')) {
140
+ const entries = key.split('-');
141
+ targetProp = entries.reduce((acc, key) => acc[key], instance); // If the target is atomic, it forces us to switch the root
142
+
143
+ if (!(targetProp && targetProp.set)) {
144
+ const [name, ...reverseEntries] = entries.reverse();
145
+ currentInstance = reverseEntries.reverse().reduce((acc, key) => acc[key], instance);
146
+ key = name;
147
+ }
148
+ }
149
+
150
+ changes.push([key, value, false, currentInstance, targetProp]);
151
+ });
152
+ const memoized = { ...props
153
+ };
154
+ if (localState.memoizedProps && localState.memoizedProps.args) memoized.args = localState.memoizedProps.args;
155
+ if (localState.memoizedProps && localState.memoizedProps.attach) memoized.attach = localState.memoizedProps.attach;
156
+ return {
157
+ memoized,
158
+ changes
159
+ };
160
+ } // This function applies a set of changes to the instance
161
+
162
+ function applyProps$1(instance, data) {
163
+ var _instance$__r3f3, _root$getState, _localState$handlers, _localState$handlers2;
164
+
165
+ // Filter equals, events and reserved props
166
+ const localState = (_instance$__r3f3 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f3 : {};
167
+ const root = localState.root;
168
+ const rootState = (_root$getState = root == null ? void 0 : root.getState == null ? void 0 : root.getState()) != null ? _root$getState : {};
169
+ const {
170
+ memoized,
171
+ changes
172
+ } = isDiffSet(data) ? data : diffProps(instance, data);
173
+ const prevHandlers = (_localState$handlers = localState.handlers) == null ? void 0 : _localState$handlers.count; // Prepare memoized props
174
+
175
+ if (instance.__r3f) instance.__r3f.memoizedProps = memoized;
176
+ changes.forEach(([key, value, isEvent, currentInstance, targetProp]) => {
177
+ // https://github.com/mrdoob/three.js/issues/21209
178
+ // HMR/fast-refresh relies on the ability to cancel out props, but threejs
179
+ // has no means to do this. Hence we curate a small collection of value-classes
180
+ // with their respective constructor/set arguments
181
+ // For removed props, try to set default values, if possible
182
+ if (value === DEFAULT + 'remove') {
183
+ if (targetProp && targetProp.constructor) {
184
+ // use the prop constructor to find the default it should be
185
+ value = new targetProp.constructor(memoized.args);
186
+ } else if (currentInstance.constructor) {
187
+ // create a blank slate of the instance and copy the particular parameter.
188
+ // @ts-ignore
189
+ const defaultClassCall = new currentInstance.constructor(currentInstance.__r3f.memoizedProps.args);
190
+ value = defaultClassCall[targetProp]; // destory the instance
191
+
192
+ if (defaultClassCall.dispose) defaultClassCall.dispose(); // instance does not have constructor, just set it to 0
193
+ } else value = 0;
194
+ } // Deal with pointer events ...
195
+
196
+
197
+ if (isEvent) {
198
+ if (value) localState.handlers[key] = value;else delete localState.handlers[key];
199
+ localState.handlers.count = Object.keys(localState.handlers).length;
200
+ } // Special treatment for objects with support for set/copy, and layers
201
+ else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE__namespace.Layers)) {
202
+ // If value is an array
203
+ if (Array.isArray(value)) {
204
+ if (targetProp.fromArray) targetProp.fromArray(value);else targetProp.set(...value);
205
+ } // Test again target.copy(class) next ...
206
+ 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
207
+ // https://github.com/react-spring/react-three-fiber/issues/274
208
+ else if (value !== undefined) {
209
+ const isColor = targetProp instanceof THREE__namespace.Color; // Allow setting array scalars
210
+
211
+ if (!isColor && targetProp.setScalar) targetProp.setScalar(value); // Layers have no copy function, we must therefore copy the mask property
212
+ else if (targetProp instanceof THREE__namespace.Layers && value instanceof THREE__namespace.Layers) targetProp.mask = value.mask; // Otherwise just set ...
213
+ else targetProp.set(value); // Auto-convert sRGB colors, for now ...
214
+ // https://github.com/react-spring/react-three-fiber/issues/344
215
+
216
+ if (!rootState.linear && isColor) targetProp.convertSRGBToLinear();
217
+ } // Else, just overwrite the value
218
+
219
+ } else {
220
+ currentInstance[key] = value; // Auto-convert sRGB textures, for now ...
221
+ // https://github.com/react-spring/react-three-fiber/issues/344
222
+
223
+ if (!rootState.linear && currentInstance[key] instanceof THREE__namespace.Texture) currentInstance[key].encoding = THREE__namespace.sRGBEncoding;
224
+ }
225
+
226
+ invalidateInstance(instance);
227
+ });
228
+
229
+ if (rootState.internal && instance.raycast && prevHandlers !== ((_localState$handlers2 = localState.handlers) == null ? void 0 : _localState$handlers2.count)) {
230
+ // Pre-emptively remove the instance from the interaction manager
231
+ const index = rootState.internal.interaction.indexOf(instance);
232
+ if (index > -1) rootState.internal.interaction.splice(index, 1); // Add the instance to the interaction manager only when it has handlers
233
+
234
+ if (localState.handlers.count) rootState.internal.interaction.push(instance);
235
+ } // Call the update lifecycle when it is being updated, but only when it is part of the scene
236
+
237
+
238
+ if (changes.length && instance.parent) updateInstance(instance);
239
+ }
240
+ function invalidateInstance(instance) {
241
+ var _instance$__r3f4, _instance$__r3f4$root;
242
+
243
+ const state = (_instance$__r3f4 = instance.__r3f) == null ? void 0 : (_instance$__r3f4$root = _instance$__r3f4.root) == null ? void 0 : _instance$__r3f4$root.getState == null ? void 0 : _instance$__r3f4$root.getState();
244
+ if (state && state.internal.frames === 0) state.invalidate();
245
+ }
246
+ function updateInstance(instance) {
247
+ instance.onUpdate == null ? void 0 : instance.onUpdate(instance);
248
+ }
76
249
 
77
250
  function makeId(event) {
78
- return (event.eventObject || event.object).uuid + '/' + event.index;
251
+ return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
79
252
  }
80
253
 
81
254
  function removeInteractivity(store, object) {
@@ -133,11 +306,7 @@ function createEvents(store) {
133
306
 
134
307
 
135
308
  function filterPointerEvents(objects) {
136
- return objects.filter(obj => ['Move', 'Over', 'Enter', 'Out', 'Leave'].some(name => {
137
- var _r3f$handlers;
138
-
139
- return (_r3f$handlers = obj.__r3f.handlers) == null ? void 0 : _r3f$handlers['onPointer' + name];
140
- }));
309
+ return objects.filter(obj => ['Move', 'Over', 'Enter', 'Out', 'Leave'].some(name => obj.__r3f.handlers['onPointer' + name]));
141
310
  }
142
311
 
143
312
  function intersect(filter) {
@@ -167,10 +336,7 @@ function createEvents(store) {
167
336
  let eventObject = intersect.object; // Bubble event up
168
337
 
169
338
  while (eventObject) {
170
- var _r3f;
171
-
172
- const handlers = (_r3f = eventObject.__r3f) == null ? void 0 : _r3f.handlers;
173
- if (handlers) intersections.push({ ...intersect,
339
+ if (eventObject.__r3f.handlers.count) intersections.push({ ...intersect,
174
340
  eventObject
175
341
  });
176
342
  eventObject = eventObject.parent;
@@ -307,12 +473,12 @@ function createEvents(store) {
307
473
  Array.from(internal.hovered.values()).forEach(hoveredObj => {
308
474
  // When no objects were hit or the the hovered object wasn't found underneath the cursor
309
475
  // we call onPointerOut and delete the object from the hovered-elements map
310
- if (!hits.length || !hits.find(hit => hit.object === hoveredObj.object && hit.index === hoveredObj.index)) {
476
+ if (!hits.length || !hits.find(hit => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId)) {
311
477
  const eventObject = hoveredObj.eventObject;
312
478
  const handlers = eventObject.__r3f.handlers;
313
479
  internal.hovered.delete(makeId(hoveredObj));
314
480
 
315
- if (handlers) {
481
+ if (handlers.count) {
316
482
  // Clear out intersects, they are outdated by now
317
483
  const data = { ...hoveredObj,
318
484
  intersections: hits || []
@@ -361,7 +527,7 @@ function createEvents(store) {
361
527
  const eventObject = data.eventObject;
362
528
  const handlers = eventObject.__r3f.handlers; // Check presence of handlers
363
529
 
364
- if (!handlers) return;
530
+ if (!handlers.count) return;
365
531
 
366
532
  if (isPointerMove) {
367
533
  // Move event ...
@@ -385,14 +551,14 @@ function createEvents(store) {
385
551
  handlers.onPointerMove == null ? void 0 : handlers.onPointerMove(data);
386
552
  } else {
387
553
  // All other events ...
388
- const handler = handlers == null ? void 0 : handlers[name];
554
+ const handler = handlers[name];
389
555
 
390
556
  if (handler) {
391
557
  // Forward all events back to their respective handlers with the exception of click events,
392
558
  // which must use the initial target
393
559
  if (name !== 'onClick' && name !== 'onContextMenu' && name !== 'onDoubleClick' || internal.initialHits.includes(eventObject)) {
394
560
  handler(data);
395
- pointerMissed(event, internal.interaction.filter(object => object !== eventObject));
561
+ pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object)));
396
562
  }
397
563
  }
398
564
  }
@@ -415,9 +581,9 @@ function createEvents(store) {
415
581
 
416
582
  function pointerMissed(event, objects) {
417
583
  objects.forEach(object => {
418
- var _r3f$handlers2;
584
+ var _r3f$handlers$onPoin, _r3f$handlers;
419
585
 
420
- return (_r3f$handlers2 = object.__r3f.handlers) == null ? void 0 : _r3f$handlers2.onPointerMissed == null ? void 0 : _r3f$handlers2.onPointerMissed(event);
586
+ return (_r3f$handlers$onPoin = (_r3f$handlers = object.__r3f.handlers).onPointerMissed) == null ? void 0 : _r3f$handlers$onPoin.call(_r3f$handlers, event);
421
587
  });
422
588
  }
423
589
 
@@ -443,226 +609,13 @@ const getContainer = (container, child) => {
443
609
  };
444
610
  };
445
611
 
446
- const DEFAULT = '__default';
447
- const EMPTY = {};
448
- const FILTER = ['children', 'key', 'ref'];
449
612
  let catalogue = {};
450
613
 
451
614
  let extend = objects => void (catalogue = { ...catalogue,
452
615
  ...objects
453
- }); // Each object in the scene carries a small LocalState descriptor
454
-
455
-
456
- function prepare(object, state) {
457
- const instance = object;
458
-
459
- if (state != null && state.instance || !instance.__r3f) {
460
- instance.__r3f = {
461
- root: null,
462
- memoizedProps: {},
463
- objects: [],
464
- ...state
465
- };
466
- }
467
-
468
- return object;
469
- }
470
-
471
- function createRenderer(roots) {
472
- function applyProps(instance, newProps, oldProps = {}, accumulative = false) {
473
- var _instance$__r3f, _root$getState, _instance$__r3f2;
474
-
475
- // Filter equals, events and reserved props
476
- const localState = (_instance$__r3f = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f : {};
477
- const root = localState.root;
478
- const rootState = (_root$getState = root == null ? void 0 : root.getState == null ? void 0 : root.getState()) != null ? _root$getState : {};
479
- const sameProps = [];
480
- const handlers = [];
481
- const newMemoizedProps = {};
482
- let i = 0;
483
- Object.entries(newProps).forEach(([key, entry]) => {
484
- // we don't want children, ref or key in the memoized props
485
- if (FILTER.indexOf(key) === -1) {
486
- newMemoizedProps[key] = entry;
487
- }
488
- });
489
-
490
- if (localState.memoizedProps && localState.memoizedProps.args) {
491
- newMemoizedProps.args = localState.memoizedProps.args;
492
- }
493
-
494
- if (localState.memoizedProps && localState.memoizedProps.attach) {
495
- newMemoizedProps.attach = localState.memoizedProps.attach;
496
- }
497
-
498
- if (instance.__r3f) {
499
- instance.__r3f.memoizedProps = newMemoizedProps;
500
- }
501
-
502
- let objectKeys = Object.keys(newProps);
503
-
504
- for (i = 0; i < objectKeys.length; i++) {
505
- if (is.equ(newProps[objectKeys[i]], oldProps[objectKeys[i]])) {
506
- sameProps.push(objectKeys[i]);
507
- } // Event-handlers ...
508
- // are functions, that
509
- // start with "on", and
510
- // contain the name "Pointer", "Click", "DoubleClick", "ContextMenu", or "Wheel"
511
-
512
-
513
- if (is.fun(newProps[objectKeys[i]]) && /^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/.test(objectKeys[i])) {
514
- handlers.push(objectKeys[i]);
515
- }
516
- } // Catch props that existed, but now exist no more ...
517
-
518
-
519
- const leftOvers = [];
520
-
521
- if (accumulative) {
522
- objectKeys = Object.keys(oldProps);
523
-
524
- for (i = 0; i < objectKeys.length; i++) {
525
- if (!newProps.hasOwnProperty(objectKeys[i])) {
526
- leftOvers.push(objectKeys[i]);
527
- }
528
- }
529
- }
530
-
531
- const toFilter = [...sameProps, ...FILTER]; // Instances use "object" as a reserved identifier
532
-
533
- if ((_instance$__r3f2 = instance.__r3f) != null && _instance$__r3f2.instance) toFilter.push('object');
534
- const filteredProps = { ...newProps
535
- }; // Removes sameProps and reserved props from newProps
536
-
537
- objectKeys = Object.keys(filteredProps);
538
-
539
- for (i = 0; i < objectKeys.length; i++) {
540
- if (toFilter.indexOf(objectKeys[i]) > -1) {
541
- delete filteredProps[objectKeys[i]];
542
- }
543
- } // Collect all new props
544
-
545
-
546
- const filteredPropsEntries = Object.entries(filteredProps); // Prepend left-overs so they can be reset or removed
547
- // Left-overs must come first!
548
-
549
- for (i = 0; i < leftOvers.length; i++) {
550
- if (leftOvers[i] !== 'children') {
551
- filteredPropsEntries.unshift([leftOvers[i], DEFAULT + 'remove']);
552
- }
553
- }
554
-
555
- if (filteredPropsEntries.length > 0) {
556
- filteredPropsEntries.forEach(([key, value]) => {
557
- if (!handlers.includes(key)) {
558
- let currentInstance = instance;
559
- let targetProp = currentInstance[key];
560
-
561
- if (key.includes('-')) {
562
- const entries = key.split('-');
563
- targetProp = entries.reduce((acc, key) => acc[key], instance); // If the target is atomic, it forces us to switch the root
564
-
565
- if (!(targetProp && targetProp.set)) {
566
- const [name, ...reverseEntries] = entries.reverse();
567
- currentInstance = reverseEntries.reverse().reduce((acc, key) => acc[key], instance);
568
- key = name;
569
- }
570
- } // https://github.com/mrdoob/three.js/issues/21209
571
- // HMR/fast-refresh relies on the ability to cancel out props, but threejs
572
- // has no means to do this. Hence we curate a small collection of value-classes
573
- // with their respective constructor/set arguments
574
- // For removed props, try to set default values, if possible
575
-
576
-
577
- if (value === DEFAULT + 'remove') {
578
- if (targetProp && targetProp.constructor) {
579
- // use the prop constructor to find the default it should be
580
- value = new targetProp.constructor(newMemoizedProps.args);
581
- } else if (currentInstance.constructor) {
582
- // create a blank slate of the instance and copy the particular parameter.
583
- // @ts-ignore
584
- const defaultClassCall = new currentInstance.constructor(currentInstance.__r3f.memoizedProps.args);
585
- value = defaultClassCall[targetProp]; // destory the instance
586
-
587
- if (defaultClassCall.dispose) {
588
- defaultClassCall.dispose();
589
- }
590
- } else {
591
- // instance does not have constructor, just set it to 0
592
- value = 0;
593
- }
594
- } // Special treatment for objects with support for set/copy, and layers
595
-
596
-
597
- if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE__namespace.Layers)) {
598
- // If value is an array
599
- if (Array.isArray(value)) {
600
- if (targetProp.fromArray) {
601
- targetProp.fromArray(value);
602
- } else {
603
- targetProp.set(...value);
604
- }
605
- } // Test again target.copy(class) next ...
606
- else if (targetProp.copy && value && value.constructor && targetProp.constructor.name === value.constructor.name) {
607
- targetProp.copy(value);
608
- } // If nothing else fits, just set the single value, ignore undefined
609
- // https://github.com/react-spring/react-three-fiber/issues/274
610
- else if (value !== undefined) {
611
- const isColor = targetProp instanceof THREE__namespace.Color; // Allow setting array scalars
612
-
613
- if (!isColor && targetProp.setScalar) targetProp.setScalar(value); // Layers have no copy function, we must therefore copy the mask property
614
- else if (targetProp instanceof THREE__namespace.Layers && value instanceof THREE__namespace.Layers) targetProp.mask = value.mask; // Otherwise just set ...
615
- else targetProp.set(value); // Auto-convert sRGB colors, for now ...
616
- // https://github.com/react-spring/react-three-fiber/issues/344
617
-
618
- if (!rootState.linear && isColor) targetProp.convertSRGBToLinear();
619
- } // Else, just overwrite the value
620
-
621
- } else {
622
- currentInstance[key] = value; // Auto-convert sRGB textures, for now ...
623
- // https://github.com/react-spring/react-three-fiber/issues/344
624
-
625
- if (!rootState.linear && currentInstance[key] instanceof THREE__namespace.Texture) currentInstance[key].encoding = THREE__namespace.sRGBEncoding;
626
- }
627
-
628
- invalidateInstance(instance);
629
- }
630
- }); // Preemptively delete the instance from the containers interaction
631
-
632
- if (accumulative && root && instance.raycast && localState.handlers) {
633
- localState.handlers = undefined;
634
- const index = rootState.internal.interaction.indexOf(instance);
635
- if (index > -1) rootState.internal.interaction.splice(index, 1);
636
- } // Prep interaction handlers
637
-
638
-
639
- if (handlers.length) {
640
- if (accumulative && root && instance.raycast) {
641
- rootState.internal.interaction.push(instance);
642
- } // Add handlers to the instances handler-map
643
-
644
-
645
- localState.handlers = handlers.reduce((acc, key) => ({ ...acc,
646
- [key]: newProps[key]
647
- }), {});
648
- } // Call the update lifecycle when it is being updated, but only when it is part of the scene
649
-
650
-
651
- if (instance.parent) updateInstance(instance);
652
- }
653
- }
654
-
655
- function invalidateInstance(instance) {
656
- var _instance$__r3f3, _instance$__r3f3$root;
657
-
658
- const state = (_instance$__r3f3 = instance.__r3f) == null ? void 0 : (_instance$__r3f3$root = _instance$__r3f3.root) == null ? void 0 : _instance$__r3f3$root.getState == null ? void 0 : _instance$__r3f3$root.getState();
659
- if (state && state.internal.frames === 0) state.invalidate();
660
- }
661
-
662
- function updateInstance(instance) {
663
- instance.onUpdate == null ? void 0 : instance.onUpdate(instance);
664
- }
616
+ });
665
617
 
618
+ function createRenderer(roots, getEventPriority) {
666
619
  function createInstance(type, {
667
620
  args = [],
668
621
  ...props
@@ -688,7 +641,7 @@ function createRenderer(roots) {
688
641
  const object = props.object;
689
642
  instance = prepare(object, {
690
643
  root,
691
- instance: true
644
+ primitive: true
692
645
  });
693
646
  } else {
694
647
  const target = catalogue[name] || THREE__namespace[name];
@@ -722,7 +675,7 @@ function createRenderer(roots) {
722
675
  // why it passes "true" here
723
676
 
724
677
 
725
- applyProps(instance, props, {});
678
+ applyProps$1(instance, props);
726
679
  return instance;
727
680
  }
728
681
 
@@ -845,18 +798,18 @@ function createRenderer(roots) {
845
798
  // Never dispose of primitives because their state may be kept outside of React!
846
799
  // In order for an object to be able to dispose it has to have
847
800
  // - a dispose method,
848
- // - it cannot be an <instance object={...} />
801
+ // - it cannot be a <primitive object={...} />
849
802
  // - it cannot be a THREE.Scene, because three has broken it's own api
850
803
  //
851
804
  // Since disposal is recursive, we can check the optional dispose arg, which will be undefined
852
805
  // when the reconciler calls it, but then carry our own check recursively
853
806
 
854
807
 
855
- const isInstance = (_child$__r3f2 = child.__r3f) == null ? void 0 : _child$__r3f2.instance;
856
- const shouldDispose = dispose === undefined ? child.dispose !== null && !isInstance : dispose; // Remove nested child objects. Primitives should not have objects and children that are
808
+ const isPrimitive = (_child$__r3f2 = child.__r3f) == null ? void 0 : _child$__r3f2.primitive;
809
+ const shouldDispose = dispose === undefined ? child.dispose !== null && !isPrimitive : dispose; // Remove nested child objects. Primitives should not have objects and children that are
857
810
  // attached to them declaratively ...
858
811
 
859
- if (!isInstance) {
812
+ if (!isPrimitive) {
860
813
  var _child$__r3f3;
861
814
 
862
815
  removeRecursive((_child$__r3f3 = child.__r3f) == null ? void 0 : _child$__r3f3.objects, child, shouldDispose);
@@ -869,12 +822,18 @@ function createRenderer(roots) {
869
822
  delete child.__r3f.objects;
870
823
  delete child.__r3f.handlers;
871
824
  delete child.__r3f.memoizedProps;
872
- if (!isInstance) delete child.__r3f;
825
+ if (!isPrimitive) delete child.__r3f;
873
826
  } // Dispose item whenever the reconciler feels like it
874
827
 
875
828
 
876
829
  if (shouldDispose && child.dispose && child.type !== 'Scene') {
877
- scheduler.unstable_runWithPriority(scheduler.unstable_IdlePriority, () => child.dispose());
830
+ reconciler.runWithPriority(constants.IdleEventPriority, () => {
831
+ try {
832
+ child.dispose();
833
+ } catch (e) {
834
+ /* ... */
835
+ }
836
+ });
878
837
  }
879
838
 
880
839
  invalidateInstance(parentInstance);
@@ -913,25 +872,6 @@ function createRenderer(roots) {
913
872
  }
914
873
 
915
874
  const reconciler = Reconciler__default['default']({
916
- now: scheduler.unstable_now,
917
- createInstance,
918
- removeChild,
919
- appendChild,
920
- appendInitialChild: appendChild,
921
- insertBefore,
922
- warnsIfNotActing: true,
923
- supportsMutation: true,
924
- isPrimaryRenderer: false,
925
- getCurrentEventPriority: () => constants.DefaultEventPriority,
926
- // @ts-ignore
927
- scheduleTimeout: is.fun(setTimeout) ? setTimeout : undefined,
928
- // @ts-ignore
929
- cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
930
- // @ts-ignore
931
- setTimeout: is.fun(setTimeout) ? setTimeout : undefined,
932
- // @ts-ignore
933
- clearTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
934
- noTimeout: -1,
935
875
  appendChildToContainer: (parentInstance, child) => {
936
876
  const {
937
877
  container,
@@ -941,46 +881,38 @@ function createRenderer(roots) {
941
881
  container.__r3f.root = root;
942
882
  appendChild(container, child);
943
883
  },
944
- removeChildFromContainer: (parentInstance, child) => {
945
- const {
946
- container
947
- } = getContainer(parentInstance, child);
948
- removeChild(container, child);
949
- },
950
- insertInContainerBefore: (parentInstance, child, beforeChild) => {
951
- const {
952
- container
953
- } = getContainer(parentInstance, child);
954
- insertBefore(container, child, beforeChild);
955
- },
884
+ removeChildFromContainer: (parentInstance, child) => removeChild(getContainer(parentInstance, child).container, child),
885
+ insertInContainerBefore: (parentInstance, child, beforeChild) => insertBefore(getContainer(parentInstance, child).container, child, beforeChild),
956
886
 
957
- commitUpdate(instance, updatePayload, type, oldProps, newProps, fiber) {
958
- if (instance.__r3f.instance && newProps.object && newProps.object !== instance) {
959
- // <instance object={...} /> where the object reference has changed
960
- switchInstance(instance, type, newProps, fiber);
961
- } else {
887
+ prepareUpdate(instance, type, oldProps, newProps) {
888
+ if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) return [true];else {
962
889
  // This is a data object, let's extract critical information about it
963
890
  const {
964
891
  args: argsNew = [],
892
+ children: cN,
965
893
  ...restNew
966
894
  } = newProps;
967
895
  const {
968
896
  args: argsOld = [],
897
+ children: cO,
969
898
  ...restOld
970
899
  } = oldProps; // If it has new props or arguments, then it needs to be re-instanciated
971
900
 
972
- const hasNewArgs = argsNew.some((value, index) => is.obj(value) ? Object.entries(value).some(([key, val]) => val !== argsOld[index][key]) : value !== argsOld[index]);
901
+ if (argsNew.some((value, index) => value !== argsOld[index])) return [true]; // Create a diff-set, flag if there are any changes
973
902
 
974
- if (hasNewArgs) {
975
- // Next we create a new instance and append it again
976
- switchInstance(instance, type, newProps, fiber);
977
- } else {
978
- // Otherwise just overwrite props
979
- applyProps(instance, restNew, restOld, true);
980
- }
903
+ const diff = diffProps(instance, restNew, restOld, true);
904
+ if (diff.changes.length) return [false, diff]; // Otherwise do not touch the instance
905
+
906
+ return null;
981
907
  }
982
908
  },
983
909
 
910
+ commitUpdate(instance, [reconstruct, diff], type, oldProps, newProps, fiber) {
911
+ // Reconstruct when args or <primitive object={...} have changes
912
+ if (reconstruct) switchInstance(instance, type, newProps, fiber); // Otherwise just overwrite props
913
+ else applyProps$1(instance, diff);
914
+ },
915
+
984
916
  hideInstance(instance) {
985
917
  if (instance.isObject3D) {
986
918
  instance.visible = false;
@@ -995,72 +927,45 @@ function createRenderer(roots) {
995
927
  }
996
928
  },
997
929
 
998
- hideTextInstance() {
930
+ createInstance,
931
+ removeChild,
932
+ appendChild,
933
+ appendInitialChild: appendChild,
934
+ insertBefore,
935
+ warnsIfNotActing: true,
936
+ supportsMutation: true,
937
+ isPrimaryRenderer: false,
938
+ getCurrentEventPriority: () => getEventPriority ? getEventPriority() : constants.DefaultEventPriority,
939
+ // @ts-ignore
940
+ now: is.fun(performance.now) ? performance.now : is.fun(Date.now) ? Date.now : undefined,
941
+ // @ts-ignore
942
+ scheduleTimeout: is.fun(setTimeout) ? setTimeout : undefined,
943
+ // @ts-ignore
944
+ cancelTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
945
+ setTimeout: is.fun(setTimeout) ? setTimeout : undefined,
946
+ clearTimeout: is.fun(clearTimeout) ? clearTimeout : undefined,
947
+ noTimeout: -1,
948
+ hideTextInstance: () => {
999
949
  throw new Error('Text is not allowed in the R3F tree.');
1000
950
  },
1001
-
1002
- getPublicInstance(instance) {
1003
- // TODO: might fix switchInstance (?)
1004
- return instance;
1005
- },
1006
-
1007
- getRootHostContext(rootContainer) {
1008
- return EMPTY;
1009
- },
1010
-
1011
- getChildHostContext(parentHostContext) {
1012
- return EMPTY;
1013
- },
1014
-
1015
- createTextInstance() {},
1016
-
1017
- finalizeInitialChildren(instance) {
1018
- // https://github.com/facebook/react/issues/20271
1019
- // Returning true will trigger commitMount
1020
- return !!instance.__r3f.handlers;
1021
- },
1022
-
1023
- commitMount(instance)
1024
- /*, type, props*/
1025
- {
1026
- // https://github.com/facebook/react/issues/20271
1027
- // This will make sure events are only added once to the central container
1028
- if (instance.raycast && instance.__r3f.handlers) instance.__r3f.root.getState().internal.interaction.push(instance);
1029
- },
1030
-
1031
- prepareUpdate() {
1032
- return EMPTY;
1033
- },
1034
-
1035
- shouldDeprioritizeSubtree() {
1036
- return false;
1037
- },
1038
-
1039
- prepareForCommit() {
1040
- return null;
1041
- },
1042
-
1043
- preparePortalMount(...args) {// noop
1044
- },
1045
-
1046
- resetAfterCommit() {// noop
1047
- },
1048
-
1049
- shouldSetTextContent() {
1050
- return false;
1051
- },
1052
-
1053
- clearContainer() {
1054
- return false;
1055
- },
1056
-
1057
- detachDeletedInstance() {// noop
1058
- }
1059
-
951
+ // prettier-ignore
952
+ getPublicInstance: instance => instance,
953
+ getRootHostContext: () => null,
954
+ getChildHostContext: parentHostContext => parentHostContext,
955
+ createTextInstance: () => {},
956
+ finalizeInitialChildren: () => false,
957
+ commitMount: () => {},
958
+ shouldDeprioritizeSubtree: () => false,
959
+ prepareForCommit: () => null,
960
+ preparePortalMount: containerInfo => prepare(containerInfo),
961
+ resetAfterCommit: () => {},
962
+ shouldSetTextContent: () => false,
963
+ clearContainer: () => false,
964
+ detachDeletedInstance: () => {}
1060
965
  });
1061
966
  return {
1062
967
  reconciler,
1063
- applyProps
968
+ applyProps: applyProps$1
1064
969
  };
1065
970
  }
1066
971
 
@@ -1113,14 +1018,14 @@ const createStore = (applyProps, invalidate, advance, props) => {
1113
1018
  params: { ...raycaster.params,
1114
1019
  ...params
1115
1020
  }
1116
- }, {}); // Create default camera
1021
+ }); // Create default camera
1117
1022
 
1118
1023
  const isCamera = cameraOptions instanceof THREE__namespace.Camera;
1119
1024
  const camera = isCamera ? cameraOptions : orthographic ? new THREE__namespace.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE__namespace.PerspectiveCamera(75, 0, 0.1, 1000);
1120
1025
 
1121
1026
  if (!isCamera) {
1122
1027
  camera.position.z = 5;
1123
- if (cameraOptions) applyProps(camera, cameraOptions, {}); // Always look at center by default
1028
+ if (cameraOptions) applyProps(camera, cameraOptions); // Always look at center by default
1124
1029
 
1125
1030
  camera.lookAt(0, 0, 0);
1126
1031
  }
@@ -1258,8 +1163,8 @@ const createStore = (applyProps, invalidate, advance, props) => {
1258
1163
  internal: { ...internal,
1259
1164
  // If this subscription was given a priority, it takes rendering into its own hands
1260
1165
  // For that reason we switch off automatic rendering and increase the manual flag
1261
- // As long as this flag is positive (there could be multiple render subscription)
1262
- // ..there can be no internal rendering at all
1166
+ // As long as this flag is positive there can be no internal rendering at all
1167
+ // because there could be multiple render subscriptions
1263
1168
  priority: internal.priority + (priority > 0 ? 1 : 0),
1264
1169
  // Register subscriber and sort layers from lowest to highest, meaning,
1265
1170
  // highest priority renders last (on top of the other frames)
@@ -1411,20 +1316,61 @@ function createLoop(roots) {
1411
1316
  };
1412
1317
  }
1413
1318
 
1319
+ // @ts-ignore
1320
+ const CLICK = 'click';
1321
+ const CONTEXTMENU = 'contextmenu';
1322
+ const DBLCLICK = 'dblclick';
1323
+ const POINTERCANCEL = 'pointercancel';
1324
+ const POINTERDOWN = 'pointerdown';
1325
+ const POINTERUP = 'pointerup';
1326
+ const POINTERMOVE = 'pointermove';
1327
+ const POINTEROUT = 'pointerout';
1328
+ const POINTEROVER = 'pointerover';
1329
+ const POINTERENTER = 'pointerenter';
1330
+ const POINTERLEAVE = 'pointerleave';
1331
+ const WHEEL = 'wheel'; // https://github.com/facebook/react/tree/main/packages/react-reconciler#getcurrenteventpriority
1332
+ // Gives React a clue as to how import the current interaction is
1333
+
1334
+ function getEventPriority() {
1335
+ var _window, _window$event;
1336
+
1337
+ let name = (_window = window) == null ? void 0 : (_window$event = _window.event) == null ? void 0 : _window$event.type;
1338
+
1339
+ switch (name) {
1340
+ case CLICK:
1341
+ case CONTEXTMENU:
1342
+ case DBLCLICK:
1343
+ case POINTERCANCEL:
1344
+ case POINTERDOWN:
1345
+ case POINTERUP:
1346
+ return constants.DiscreteEventPriority;
1347
+
1348
+ case POINTERMOVE:
1349
+ case POINTEROUT:
1350
+ case POINTEROVER:
1351
+ case POINTERENTER:
1352
+ case POINTERLEAVE:
1353
+ case WHEEL:
1354
+ return constants.ContinuousEventPriority;
1355
+
1356
+ default:
1357
+ return constants.DefaultEventPriority;
1358
+ }
1359
+ }
1414
1360
  function createPointerEvents(store) {
1415
1361
  const {
1416
1362
  handlePointer
1417
1363
  } = createEvents(store);
1418
1364
  const names = {
1419
- onClick: ['click', false],
1420
- onContextMenu: ['contextmenu', false],
1421
- onDoubleClick: ['dblclick', false],
1422
- onWheel: ['wheel', true],
1423
- onPointerDown: ['pointerdown', true],
1424
- onPointerUp: ['pointerup', true],
1425
- onPointerLeave: ['pointerleave', true],
1426
- onPointerMove: ['pointermove', true],
1427
- onPointerCancel: ['pointercancel', true],
1365
+ onClick: [CLICK, false],
1366
+ onContextMenu: [CONTEXTMENU, false],
1367
+ onDoubleClick: [DBLCLICK, false],
1368
+ onWheel: [WHEEL, true],
1369
+ onPointerDown: [POINTERDOWN, true],
1370
+ onPointerUp: [POINTERUP, true],
1371
+ onPointerLeave: [POINTERLEAVE, true],
1372
+ onPointerMove: [POINTERMOVE, true],
1373
+ onPointerCancel: [POINTERCANCEL, true],
1428
1374
  onLostPointerCapture: ['lostpointercapture', true]
1429
1375
  };
1430
1376
  return {
@@ -1588,17 +1534,12 @@ function useThree(selector = state => state, equalityFn) {
1588
1534
  return useStore()(selector, equalityFn);
1589
1535
  }
1590
1536
  function useFrame(callback, renderPriority = 0) {
1591
- const {
1592
- subscribe
1593
- } = useStore().getState().internal; // Update ref
1537
+ const subscribe = useStore().getState().internal.subscribe; // Update ref
1594
1538
 
1595
1539
  const ref = React__namespace.useRef(callback);
1596
- React__namespace.useLayoutEffect(() => void (ref.current = callback), [callback]); // Subscribe/unsub
1540
+ React__namespace.useLayoutEffect(() => void (ref.current = callback), [callback]); // Subscribe on mount, unsubscribe on unmount
1597
1541
 
1598
- React__namespace.useLayoutEffect(() => {
1599
- const unsubscribe = subscribe(ref, renderPriority);
1600
- return () => unsubscribe();
1601
- }, [renderPriority, subscribe]);
1542
+ React__namespace.useLayoutEffect(() => subscribe(ref, renderPriority), [renderPriority, subscribe]);
1602
1543
  return null;
1603
1544
  }
1604
1545
 
@@ -1666,7 +1607,7 @@ const {
1666
1607
  const {
1667
1608
  reconciler,
1668
1609
  applyProps
1669
- } = createRenderer();
1610
+ } = createRenderer(roots, getEventPriority);
1670
1611
 
1671
1612
  const createRendererInstance = (gl, canvas) => isRenderer(gl) ? gl : new THREE__namespace.WebGLRenderer({
1672
1613
  powerPreference: 'high-performance',
@@ -1819,17 +1760,9 @@ function dispose(obj) {
1819
1760
  }
1820
1761
 
1821
1762
  const act = reconciler.act;
1822
- const hasSymbol = is.fun(Symbol) && Symbol.for;
1823
- const REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
1824
1763
 
1825
- function createPortal(children, container, implementation, key = null) {
1826
- return {
1827
- $$typeof: REACT_PORTAL_TYPE,
1828
- key: key == null ? null : '' + key,
1829
- children,
1830
- containerInfo: prepare(container),
1831
- implementation
1832
- };
1764
+ function createPortal(children, container) {
1765
+ return reconciler.createPortal(children, container, null, null);
1833
1766
  }
1834
1767
 
1835
1768
  reconciler.injectIntoDevTools({