@react-three/fiber 8.10.0 → 8.10.2
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.
- package/CHANGELOG.md +12 -0
- package/dist/{index-d957aeb6.cjs.prod.js → index-661b9d11.cjs.prod.js} +408 -503
- package/dist/{index-4ea38fa1.cjs.dev.js → index-bf8a2906.cjs.dev.js} +408 -503
- package/dist/{index-27a1523b.esm.js → index-fb77d67d.esm.js} +408 -503
- package/dist/react-three-fiber.cjs.dev.js +20 -23
- package/dist/react-three-fiber.cjs.prod.js +20 -23
- package/dist/react-three-fiber.esm.js +21 -24
- package/native/dist/react-three-fiber-native.cjs.dev.js +36 -44
- package/native/dist/react-three-fiber-native.cjs.prod.js +36 -44
- package/native/dist/react-three-fiber-native.esm.js +37 -45
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ var threeTypes = /*#__PURE__*/Object.freeze({
|
|
|
13
13
|
var _window$document, _window$navigator;
|
|
14
14
|
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
15
15
|
const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
16
|
+
|
|
16
17
|
/**
|
|
17
18
|
* An SSR-friendly useLayoutEffect.
|
|
18
19
|
*
|
|
@@ -22,7 +23,6 @@ const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
|
22
23
|
*
|
|
23
24
|
* @see https://github.com/facebook/react/issues/14927
|
|
24
25
|
*/
|
|
25
|
-
|
|
26
26
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' && ((_window$document = window.document) != null && _window$document.createElement || ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.product) === 'ReactNative') ? React.useLayoutEffect : React.useEffect;
|
|
27
27
|
function useMutableCallback(fn) {
|
|
28
28
|
const ref = React.useRef(fn);
|
|
@@ -39,40 +39,31 @@ function Block({
|
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
class ErrorBoundary extends React.Component {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
42
|
+
state = {
|
|
43
|
+
error: false
|
|
44
|
+
};
|
|
45
|
+
static getDerivedStateFromError = () => ({
|
|
46
|
+
error: true
|
|
47
|
+
});
|
|
49
48
|
componentDidCatch(err) {
|
|
50
49
|
this.props.set(err);
|
|
51
50
|
}
|
|
52
|
-
|
|
53
51
|
render() {
|
|
54
52
|
return this.state.error ? null : this.props.children;
|
|
55
53
|
}
|
|
56
|
-
|
|
57
54
|
}
|
|
58
|
-
|
|
59
|
-
ErrorBoundary.getDerivedStateFromError = () => ({
|
|
60
|
-
error: true
|
|
61
|
-
});
|
|
62
|
-
|
|
63
55
|
const DEFAULT = '__default';
|
|
64
56
|
const isDiffSet = def => def && !!def.memoized && !!def.changes;
|
|
65
57
|
function calculateDpr(dpr) {
|
|
66
58
|
const target = typeof window !== 'undefined' ? window.devicePixelRatio : 1;
|
|
67
59
|
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
68
60
|
}
|
|
61
|
+
|
|
69
62
|
/**
|
|
70
63
|
* Returns instance root state
|
|
71
64
|
*/
|
|
72
|
-
|
|
73
65
|
const getRootState = obj => {
|
|
74
66
|
var _r3f;
|
|
75
|
-
|
|
76
67
|
return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
|
|
77
68
|
};
|
|
78
69
|
// A collection of compare functions
|
|
@@ -84,68 +75,61 @@ const is = {
|
|
|
84
75
|
boo: a => typeof a === 'boolean',
|
|
85
76
|
und: a => a === void 0,
|
|
86
77
|
arr: a => Array.isArray(a),
|
|
87
|
-
|
|
88
78
|
equ(a, b, {
|
|
89
79
|
arrays = 'shallow',
|
|
90
80
|
objects = 'reference',
|
|
91
81
|
strict = true
|
|
92
82
|
} = {}) {
|
|
93
83
|
// Wrong type or one of the two undefined, doesn't match
|
|
94
|
-
if (typeof a !== typeof b || !!a !== !!b) return false;
|
|
95
|
-
|
|
84
|
+
if (typeof a !== typeof b || !!a !== !!b) return false;
|
|
85
|
+
// Atomic, just compare a against b
|
|
96
86
|
if (is.str(a) || is.num(a)) return a === b;
|
|
97
87
|
const isObj = is.obj(a);
|
|
98
88
|
if (isObj && objects === 'reference') return a === b;
|
|
99
89
|
const isArr = is.arr(a);
|
|
100
|
-
if (isArr && arrays === 'reference') return a === b;
|
|
101
|
-
|
|
102
|
-
if ((isArr || isObj) && a === b) return true;
|
|
103
|
-
|
|
90
|
+
if (isArr && arrays === 'reference') return a === b;
|
|
91
|
+
// Array or Object, shallow compare first to see if it's a match
|
|
92
|
+
if ((isArr || isObj) && a === b) return true;
|
|
93
|
+
// Last resort, go through keys
|
|
104
94
|
let i;
|
|
105
|
-
|
|
106
95
|
for (i in a) if (!(i in b)) return false;
|
|
107
|
-
|
|
108
96
|
for (i in strict ? b : a) if (a[i] !== b[i]) return false;
|
|
109
|
-
|
|
110
97
|
if (is.und(i)) {
|
|
111
98
|
if (isArr && a.length === 0 && b.length === 0) return true;
|
|
112
99
|
if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
|
|
113
100
|
if (a !== b) return false;
|
|
114
101
|
}
|
|
115
|
-
|
|
116
102
|
return true;
|
|
117
103
|
}
|
|
104
|
+
};
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
// Collects nodes and materials from a THREE.Object3D
|
|
121
107
|
function buildGraph(object) {
|
|
122
108
|
const data = {
|
|
123
109
|
nodes: {},
|
|
124
110
|
materials: {}
|
|
125
111
|
};
|
|
126
|
-
|
|
127
112
|
if (object) {
|
|
128
113
|
object.traverse(obj => {
|
|
129
114
|
if (obj.name) data.nodes[obj.name] = obj;
|
|
130
115
|
if (obj.material && !data.materials[obj.material.name]) data.materials[obj.material.name] = obj.material;
|
|
131
116
|
});
|
|
132
117
|
}
|
|
133
|
-
|
|
134
118
|
return data;
|
|
135
|
-
}
|
|
119
|
+
}
|
|
136
120
|
|
|
121
|
+
// Disposes an object and all its properties
|
|
137
122
|
function dispose(obj) {
|
|
138
123
|
if (obj.dispose && obj.type !== 'Scene') obj.dispose();
|
|
139
|
-
|
|
140
124
|
for (const p in obj) {
|
|
141
125
|
p.dispose == null ? void 0 : p.dispose();
|
|
142
126
|
delete obj[p];
|
|
143
127
|
}
|
|
144
|
-
}
|
|
128
|
+
}
|
|
145
129
|
|
|
130
|
+
// Each object in the scene carries a small LocalState descriptor
|
|
146
131
|
function prepare(object, state) {
|
|
147
132
|
const instance = object;
|
|
148
|
-
|
|
149
133
|
if (state != null && state.primitive || !instance.__r3f) {
|
|
150
134
|
instance.__r3f = {
|
|
151
135
|
type: '',
|
|
@@ -159,13 +143,10 @@ function prepare(object, state) {
|
|
|
159
143
|
...state
|
|
160
144
|
};
|
|
161
145
|
}
|
|
162
|
-
|
|
163
146
|
return object;
|
|
164
147
|
}
|
|
165
|
-
|
|
166
148
|
function resolve(instance, key) {
|
|
167
149
|
let target = instance;
|
|
168
|
-
|
|
169
150
|
if (key.includes('-')) {
|
|
170
151
|
const entries = key.split('-');
|
|
171
152
|
const last = entries.pop();
|
|
@@ -178,9 +159,9 @@ function resolve(instance, key) {
|
|
|
178
159
|
target,
|
|
179
160
|
key
|
|
180
161
|
};
|
|
181
|
-
}
|
|
182
|
-
|
|
162
|
+
}
|
|
183
163
|
|
|
164
|
+
// Checks if a dash-cased string ends with an integer
|
|
184
165
|
const INDEX_REGEX = /-\d+$/;
|
|
185
166
|
function attach(parent, child, type) {
|
|
186
167
|
if (is.str(type)) {
|
|
@@ -193,7 +174,6 @@ function attach(parent, child, type) {
|
|
|
193
174
|
} = resolve(parent, root);
|
|
194
175
|
if (!Array.isArray(target[key])) target[key] = [];
|
|
195
176
|
}
|
|
196
|
-
|
|
197
177
|
const {
|
|
198
178
|
target,
|
|
199
179
|
key
|
|
@@ -204,21 +184,21 @@ function attach(parent, child, type) {
|
|
|
204
184
|
}
|
|
205
185
|
function detach(parent, child, type) {
|
|
206
186
|
var _child$__r3f, _child$__r3f2;
|
|
207
|
-
|
|
208
187
|
if (is.str(type)) {
|
|
209
188
|
const {
|
|
210
189
|
target,
|
|
211
190
|
key
|
|
212
191
|
} = resolve(parent, type);
|
|
213
|
-
const previous = child.__r3f.previousAttach;
|
|
214
|
-
|
|
215
|
-
if (previous === undefined) delete target[key];
|
|
192
|
+
const previous = child.__r3f.previousAttach;
|
|
193
|
+
// When the previous value was undefined, it means the value was never set to begin with
|
|
194
|
+
if (previous === undefined) delete target[key];
|
|
195
|
+
// Otherwise set the previous value
|
|
216
196
|
else target[key] = previous;
|
|
217
197
|
} else (_child$__r3f = child.__r3f) == null ? void 0 : _child$__r3f.previousAttach == null ? void 0 : _child$__r3f.previousAttach(parent, child);
|
|
218
|
-
|
|
219
198
|
(_child$__r3f2 = child.__r3f) == null ? true : delete _child$__r3f2.previousAttach;
|
|
220
|
-
}
|
|
199
|
+
}
|
|
221
200
|
|
|
201
|
+
// This function prepares a set of changes to be applied to the instance
|
|
222
202
|
function diffProps(instance, {
|
|
223
203
|
children: cN,
|
|
224
204
|
key: kN,
|
|
@@ -231,39 +211,38 @@ function diffProps(instance, {
|
|
|
231
211
|
...previous
|
|
232
212
|
} = {}, remove = false) {
|
|
233
213
|
var _instance$__r3f;
|
|
234
|
-
|
|
235
214
|
const localState = (_instance$__r3f = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f : {};
|
|
236
215
|
const entries = Object.entries(props);
|
|
237
|
-
const changes = [];
|
|
216
|
+
const changes = [];
|
|
238
217
|
|
|
218
|
+
// Catch removed props, prepend them so they can be reset or removed
|
|
239
219
|
if (remove) {
|
|
240
220
|
const previousKeys = Object.keys(previous);
|
|
241
|
-
|
|
242
221
|
for (let i = 0; i < previousKeys.length; i++) {
|
|
243
222
|
if (!props.hasOwnProperty(previousKeys[i])) entries.unshift([previousKeys[i], DEFAULT + 'remove']);
|
|
244
223
|
}
|
|
245
224
|
}
|
|
246
|
-
|
|
247
225
|
entries.forEach(([key, value]) => {
|
|
248
226
|
var _instance$__r3f2;
|
|
249
|
-
|
|
250
227
|
// Bail out on primitive object
|
|
251
|
-
if ((_instance$__r3f2 = instance.__r3f) != null && _instance$__r3f2.primitive && key === 'object') return;
|
|
252
|
-
|
|
253
|
-
if (is.equ(value, previous[key])) return;
|
|
254
|
-
|
|
255
|
-
if (/^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/.test(key)) return changes.push([key, value, true, []]);
|
|
256
|
-
|
|
228
|
+
if ((_instance$__r3f2 = instance.__r3f) != null && _instance$__r3f2.primitive && key === 'object') return;
|
|
229
|
+
// When props match bail out
|
|
230
|
+
if (is.equ(value, previous[key])) return;
|
|
231
|
+
// Collect handlers and bail out
|
|
232
|
+
if (/^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/.test(key)) return changes.push([key, value, true, []]);
|
|
233
|
+
// Split dashed props
|
|
257
234
|
let entries = [];
|
|
258
235
|
if (key.includes('-')) entries = key.split('-');
|
|
259
|
-
changes.push([key, value, false, entries]);
|
|
236
|
+
changes.push([key, value, false, entries]);
|
|
260
237
|
|
|
238
|
+
// Reset pierced props
|
|
261
239
|
for (const prop in props) {
|
|
262
240
|
const value = props[prop];
|
|
263
241
|
if (prop.startsWith(`${key}-`)) changes.push([prop, value, false, prop.split('-')]);
|
|
264
242
|
}
|
|
265
243
|
});
|
|
266
|
-
const memoized = {
|
|
244
|
+
const memoized = {
|
|
245
|
+
...props
|
|
267
246
|
};
|
|
268
247
|
if (localState.memoizedProps && localState.memoizedProps.args) memoized.args = localState.memoizedProps.args;
|
|
269
248
|
if (localState.memoizedProps && localState.memoizedProps.attach) memoized.attach = localState.memoizedProps.attach;
|
|
@@ -271,11 +250,11 @@ function diffProps(instance, {
|
|
|
271
250
|
memoized,
|
|
272
251
|
changes
|
|
273
252
|
};
|
|
274
|
-
}
|
|
253
|
+
}
|
|
275
254
|
|
|
255
|
+
// This function applies a set of changes to the instance
|
|
276
256
|
function applyProps$1(instance, data) {
|
|
277
257
|
var _instance$__r3f3, _root$getState, _instance$__r3f4;
|
|
278
|
-
|
|
279
258
|
// Filter equals, events and reserved props
|
|
280
259
|
const localState = (_instance$__r3f3 = instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
281
260
|
const root = localState.root;
|
|
@@ -284,104 +263,102 @@ function applyProps$1(instance, data) {
|
|
|
284
263
|
memoized,
|
|
285
264
|
changes
|
|
286
265
|
} = isDiffSet(data) ? data : diffProps(instance, data);
|
|
287
|
-
const prevHandlers = localState.eventCount;
|
|
266
|
+
const prevHandlers = localState.eventCount;
|
|
288
267
|
|
|
268
|
+
// Prepare memoized props
|
|
289
269
|
if (instance.__r3f) instance.__r3f.memoizedProps = memoized;
|
|
290
|
-
|
|
291
270
|
for (let i = 0; i < changes.length; i++) {
|
|
292
271
|
let [key, value, isEvent, keys] = changes[i];
|
|
293
272
|
let currentInstance = instance;
|
|
294
|
-
let targetProp = currentInstance[key];
|
|
273
|
+
let targetProp = currentInstance[key];
|
|
295
274
|
|
|
275
|
+
// Revolve dashed props
|
|
296
276
|
if (keys.length) {
|
|
297
|
-
targetProp = keys.reduce((acc, key) => acc[key], instance);
|
|
298
|
-
|
|
277
|
+
targetProp = keys.reduce((acc, key) => acc[key], instance);
|
|
278
|
+
// If the target is atomic, it forces us to switch the root
|
|
299
279
|
if (!(targetProp && targetProp.set)) {
|
|
300
280
|
const [name, ...reverseEntries] = keys.reverse();
|
|
301
281
|
currentInstance = reverseEntries.reverse().reduce((acc, key) => acc[key], instance);
|
|
302
282
|
key = name;
|
|
303
283
|
}
|
|
304
|
-
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// https://github.com/mrdoob/three.js/issues/21209
|
|
305
287
|
// HMR/fast-refresh relies on the ability to cancel out props, but threejs
|
|
306
288
|
// has no means to do this. Hence we curate a small collection of value-classes
|
|
307
289
|
// with their respective constructor/set arguments
|
|
308
290
|
// For removed props, try to set default values, if possible
|
|
309
|
-
|
|
310
|
-
|
|
311
291
|
if (value === DEFAULT + 'remove') {
|
|
312
|
-
if (
|
|
313
|
-
var _memoized$args;
|
|
314
|
-
|
|
315
|
-
// use the prop constructor to find the default it should be
|
|
316
|
-
value = new targetProp.constructor(...((_memoized$args = memoized.args) != null ? _memoized$args : []));
|
|
317
|
-
} else if (currentInstance.constructor) {
|
|
292
|
+
if (currentInstance.constructor) {
|
|
318
293
|
var _currentInstance$__r;
|
|
319
|
-
|
|
320
294
|
// create a blank slate of the instance and copy the particular parameter.
|
|
321
295
|
// @ts-ignore
|
|
322
296
|
const defaultClassCall = new currentInstance.constructor(...((_currentInstance$__r = currentInstance.__r3f.memoizedProps.args) != null ? _currentInstance$__r : []));
|
|
323
|
-
value = defaultClassCall[
|
|
324
|
-
|
|
325
|
-
if (defaultClassCall.dispose) defaultClassCall.dispose();
|
|
297
|
+
value = defaultClassCall[key];
|
|
298
|
+
// destroy the instance
|
|
299
|
+
if (defaultClassCall.dispose) defaultClassCall.dispose();
|
|
326
300
|
} else {
|
|
301
|
+
// instance does not have constructor, just set it to 0
|
|
327
302
|
value = 0;
|
|
328
303
|
}
|
|
329
|
-
}
|
|
330
|
-
|
|
304
|
+
}
|
|
331
305
|
|
|
306
|
+
// Deal with pointer events ...
|
|
332
307
|
if (isEvent) {
|
|
333
308
|
if (value) localState.handlers[key] = value;else delete localState.handlers[key];
|
|
334
309
|
localState.eventCount = Object.keys(localState.handlers).length;
|
|
335
|
-
}
|
|
310
|
+
}
|
|
311
|
+
// Special treatment for objects with support for set/copy, and layers
|
|
336
312
|
else if (targetProp && targetProp.set && (targetProp.copy || targetProp instanceof THREE.Layers)) {
|
|
337
313
|
// If value is an array
|
|
338
314
|
if (Array.isArray(value)) {
|
|
339
315
|
if (targetProp.fromArray) targetProp.fromArray(value);else targetProp.set(...value);
|
|
340
|
-
}
|
|
316
|
+
}
|
|
317
|
+
// Test again target.copy(class) next ...
|
|
341
318
|
else if (targetProp.copy && value && value.constructor && targetProp.constructor.name === value.constructor.name) {
|
|
342
319
|
targetProp.copy(value);
|
|
343
|
-
}
|
|
320
|
+
}
|
|
321
|
+
// If nothing else fits, just set the single value, ignore undefined
|
|
344
322
|
// https://github.com/pmndrs/react-three-fiber/issues/274
|
|
345
323
|
else if (value !== undefined) {
|
|
346
|
-
const isColor = targetProp instanceof THREE.Color;
|
|
347
|
-
|
|
348
|
-
if (!isColor && targetProp.setScalar) targetProp.setScalar(value);
|
|
349
|
-
|
|
350
|
-
else targetProp
|
|
324
|
+
const isColor = targetProp instanceof THREE.Color;
|
|
325
|
+
// Allow setting array scalars
|
|
326
|
+
if (!isColor && targetProp.setScalar) targetProp.setScalar(value);
|
|
327
|
+
// Layers have no copy function, we must therefore copy the mask property
|
|
328
|
+
else if (targetProp instanceof THREE.Layers && value instanceof THREE.Layers) targetProp.mask = value.mask;
|
|
329
|
+
// Otherwise just set ...
|
|
330
|
+
else targetProp.set(value);
|
|
331
|
+
// For versions of three which don't support THREE.ColorManagement,
|
|
351
332
|
// Auto-convert sRGB colors
|
|
352
333
|
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
353
|
-
|
|
354
334
|
const supportsColorManagement = ('ColorManagement' in THREE);
|
|
355
335
|
if (!supportsColorManagement && !rootState.linear && isColor) targetProp.convertSRGBToLinear();
|
|
356
|
-
}
|
|
357
|
-
|
|
336
|
+
}
|
|
337
|
+
// Else, just overwrite the value
|
|
358
338
|
} else {
|
|
359
|
-
currentInstance[key] = value;
|
|
339
|
+
currentInstance[key] = value;
|
|
340
|
+
// Auto-convert sRGB textures, for now ...
|
|
360
341
|
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
361
|
-
|
|
362
342
|
if (!rootState.linear && currentInstance[key] instanceof THREE.Texture) {
|
|
363
343
|
currentInstance[key].encoding = THREE.sRGBEncoding;
|
|
364
344
|
}
|
|
365
345
|
}
|
|
366
|
-
|
|
367
346
|
invalidateInstance(instance);
|
|
368
347
|
}
|
|
369
|
-
|
|
370
348
|
if (localState.parent && rootState.internal && instance.raycast && prevHandlers !== localState.eventCount) {
|
|
371
349
|
// Pre-emptively remove the instance from the interaction manager
|
|
372
350
|
const index = rootState.internal.interaction.indexOf(instance);
|
|
373
|
-
if (index > -1) rootState.internal.interaction.splice(index, 1);
|
|
374
|
-
|
|
351
|
+
if (index > -1) rootState.internal.interaction.splice(index, 1);
|
|
352
|
+
// Add the instance to the interaction manager only when it has handlers
|
|
375
353
|
if (localState.eventCount) rootState.internal.interaction.push(instance);
|
|
376
|
-
}
|
|
377
|
-
|
|
354
|
+
}
|
|
378
355
|
|
|
356
|
+
// Call the update lifecycle when it is being updated, but only when it is part of the scene
|
|
379
357
|
if (changes.length && (_instance$__r3f4 = instance.__r3f) != null && _instance$__r3f4.parent) updateInstance(instance);
|
|
380
358
|
return instance;
|
|
381
359
|
}
|
|
382
360
|
function invalidateInstance(instance) {
|
|
383
361
|
var _instance$__r3f5, _instance$__r3f5$root;
|
|
384
|
-
|
|
385
362
|
const state = (_instance$__r3f5 = instance.__r3f) == null ? void 0 : (_instance$__r3f5$root = _instance$__r3f5.root) == null ? void 0 : _instance$__r3f5$root.getState == null ? void 0 : _instance$__r3f5$root.getState();
|
|
386
363
|
if (state && state.internal.frames === 0) state.invalidate();
|
|
387
364
|
}
|
|
@@ -400,17 +377,16 @@ function updateCamera(camera, size) {
|
|
|
400
377
|
} else {
|
|
401
378
|
camera.aspect = size.width / size.height;
|
|
402
379
|
}
|
|
403
|
-
|
|
404
|
-
|
|
380
|
+
camera.updateProjectionMatrix();
|
|
381
|
+
// https://github.com/pmndrs/react-three-fiber/issues/178
|
|
405
382
|
// Update matrix world since the renderer is a frame late
|
|
406
|
-
|
|
407
383
|
camera.updateMatrixWorld();
|
|
408
384
|
}
|
|
409
385
|
}
|
|
386
|
+
|
|
410
387
|
/**
|
|
411
388
|
* Safely sets a deeply-nested value on an object.
|
|
412
389
|
*/
|
|
413
|
-
|
|
414
390
|
function setDeep(obj, value, keys) {
|
|
415
391
|
const key = keys.pop();
|
|
416
392
|
const target = keys.reduce((acc, key) => acc[key], obj);
|
|
@@ -419,19 +395,17 @@ function setDeep(obj, value, keys) {
|
|
|
419
395
|
|
|
420
396
|
function makeId(event) {
|
|
421
397
|
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
422
|
-
}
|
|
423
|
-
// Gives React a clue as to how import the current interaction is
|
|
424
|
-
|
|
398
|
+
}
|
|
425
399
|
|
|
400
|
+
// https://github.com/facebook/react/tree/main/packages/react-reconciler#getcurrenteventpriority
|
|
401
|
+
// Gives React a clue as to how import the current interaction is
|
|
426
402
|
function getEventPriority() {
|
|
427
403
|
var _globalScope$event;
|
|
428
|
-
|
|
429
404
|
// Get a handle to the current global scope in window and worker contexts if able
|
|
430
405
|
// https://github.com/pmndrs/react-three-fiber/pull/2493
|
|
431
406
|
const globalScope = typeof self !== 'undefined' && self || typeof window !== 'undefined' && window;
|
|
432
407
|
if (!globalScope) return DefaultEventPriority;
|
|
433
408
|
const name = (_globalScope$event = globalScope.event) == null ? void 0 : _globalScope$event.type;
|
|
434
|
-
|
|
435
409
|
switch (name) {
|
|
436
410
|
case 'click':
|
|
437
411
|
case 'contextmenu':
|
|
@@ -440,7 +414,6 @@ function getEventPriority() {
|
|
|
440
414
|
case 'pointerdown':
|
|
441
415
|
case 'pointerup':
|
|
442
416
|
return DiscreteEventPriority;
|
|
443
|
-
|
|
444
417
|
case 'pointermove':
|
|
445
418
|
case 'pointerout':
|
|
446
419
|
case 'pointerover':
|
|
@@ -448,34 +421,31 @@ function getEventPriority() {
|
|
|
448
421
|
case 'pointerleave':
|
|
449
422
|
case 'wheel':
|
|
450
423
|
return ContinuousEventPriority;
|
|
451
|
-
|
|
452
424
|
default:
|
|
453
425
|
return DefaultEventPriority;
|
|
454
426
|
}
|
|
455
427
|
}
|
|
428
|
+
|
|
456
429
|
/**
|
|
457
430
|
* Release pointer captures.
|
|
458
431
|
* This is called by releasePointerCapture in the API, and when an object is removed.
|
|
459
432
|
*/
|
|
460
|
-
|
|
461
433
|
function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
|
|
462
434
|
const captureData = captures.get(obj);
|
|
463
|
-
|
|
464
435
|
if (captureData) {
|
|
465
|
-
captures.delete(obj);
|
|
466
|
-
|
|
436
|
+
captures.delete(obj);
|
|
437
|
+
// If this was the last capturing object for this pointer
|
|
467
438
|
if (captures.size === 0) {
|
|
468
439
|
capturedMap.delete(pointerId);
|
|
469
440
|
captureData.target.releasePointerCapture(pointerId);
|
|
470
441
|
}
|
|
471
442
|
}
|
|
472
443
|
}
|
|
473
|
-
|
|
474
444
|
function removeInteractivity(store, object) {
|
|
475
445
|
const {
|
|
476
446
|
internal
|
|
477
|
-
} = store.getState();
|
|
478
|
-
|
|
447
|
+
} = store.getState();
|
|
448
|
+
// Removes every trace of an object from the data store
|
|
479
449
|
internal.interaction = internal.interaction.filter(o => o !== object);
|
|
480
450
|
internal.initialHits = internal.initialHits.filter(o => o !== object);
|
|
481
451
|
internal.hovered.forEach((value, key) => {
|
|
@@ -498,106 +468,103 @@ function createEvents(store) {
|
|
|
498
468
|
const dy = event.offsetY - internal.initialClick[1];
|
|
499
469
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
500
470
|
}
|
|
501
|
-
/** Returns true if an instance has a valid pointer-event registered, this excludes scroll, clicks etc */
|
|
502
|
-
|
|
503
471
|
|
|
472
|
+
/** Returns true if an instance has a valid pointer-event registered, this excludes scroll, clicks etc */
|
|
504
473
|
function filterPointerEvents(objects) {
|
|
505
474
|
return objects.filter(obj => ['Move', 'Over', 'Enter', 'Out', 'Leave'].some(name => {
|
|
506
475
|
var _r3f;
|
|
507
|
-
|
|
508
476
|
return (_r3f = obj.__r3f) == null ? void 0 : _r3f.handlers['onPointer' + name];
|
|
509
477
|
}));
|
|
510
478
|
}
|
|
511
|
-
|
|
512
479
|
function intersect(event, filter) {
|
|
513
480
|
const state = store.getState();
|
|
514
481
|
const duplicates = new Set();
|
|
515
|
-
const intersections = [];
|
|
516
|
-
|
|
517
|
-
const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
|
|
518
|
-
|
|
482
|
+
const intersections = [];
|
|
483
|
+
// Allow callers to eliminate event objects
|
|
484
|
+
const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
|
|
485
|
+
// Reset all raycaster cameras to undefined
|
|
519
486
|
for (let i = 0; i < eventsObjects.length; i++) {
|
|
520
487
|
const state = getRootState(eventsObjects[i]);
|
|
521
|
-
|
|
522
488
|
if (state) {
|
|
523
489
|
state.raycaster.camera = undefined;
|
|
524
490
|
}
|
|
525
491
|
}
|
|
526
|
-
|
|
527
492
|
if (!state.previousRoot) {
|
|
528
493
|
// Make sure root-level pointer and ray are set up
|
|
529
494
|
state.events.compute == null ? void 0 : state.events.compute(event, state);
|
|
530
495
|
}
|
|
531
|
-
|
|
532
496
|
function handleRaycast(obj) {
|
|
533
|
-
const state = getRootState(obj);
|
|
534
|
-
|
|
535
|
-
if (!state || !state.events.enabled || state.raycaster.camera === null) return [];
|
|
497
|
+
const state = getRootState(obj);
|
|
498
|
+
// Skip event handling when noEvents is set, or when the raycasters camera is null
|
|
499
|
+
if (!state || !state.events.enabled || state.raycaster.camera === null) return [];
|
|
536
500
|
|
|
501
|
+
// When the camera is undefined we have to call the event layers update function
|
|
537
502
|
if (state.raycaster.camera === undefined) {
|
|
538
503
|
var _state$previousRoot;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
504
|
+
state.events.compute == null ? void 0 : state.events.compute(event, state, (_state$previousRoot = state.previousRoot) == null ? void 0 : _state$previousRoot.getState());
|
|
505
|
+
// If the camera is still undefined we have to skip this layer entirely
|
|
542
506
|
if (state.raycaster.camera === undefined) state.raycaster.camera = null;
|
|
543
|
-
}
|
|
544
|
-
|
|
507
|
+
}
|
|
545
508
|
|
|
509
|
+
// Intersect object by object
|
|
546
510
|
return state.raycaster.camera ? state.raycaster.intersectObject(obj, true) : [];
|
|
547
|
-
}
|
|
548
|
-
|
|
511
|
+
}
|
|
549
512
|
|
|
550
|
-
|
|
551
|
-
|
|
513
|
+
// Collect events
|
|
514
|
+
let hits = eventsObjects
|
|
515
|
+
// Intersect objects
|
|
516
|
+
.flatMap(handleRaycast)
|
|
517
|
+
// Sort by event priority and distance
|
|
552
518
|
.sort((a, b) => {
|
|
553
519
|
const aState = getRootState(a.object);
|
|
554
520
|
const bState = getRootState(b.object);
|
|
555
521
|
if (!aState || !bState) return a.distance - b.distance;
|
|
556
522
|
return bState.events.priority - aState.events.priority || a.distance - b.distance;
|
|
557
|
-
})
|
|
523
|
+
})
|
|
524
|
+
// Filter out duplicates
|
|
558
525
|
.filter(item => {
|
|
559
526
|
const id = makeId(item);
|
|
560
527
|
if (duplicates.has(id)) return false;
|
|
561
528
|
duplicates.add(id);
|
|
562
529
|
return true;
|
|
563
|
-
});
|
|
564
|
-
// Allow custom userland intersect sort order, this likely only makes sense on the root filter
|
|
530
|
+
});
|
|
565
531
|
|
|
566
|
-
|
|
532
|
+
// https://github.com/mrdoob/three.js/issues/16031
|
|
533
|
+
// Allow custom userland intersect sort order, this likely only makes sense on the root filter
|
|
534
|
+
if (state.events.filter) hits = state.events.filter(hits, state);
|
|
567
535
|
|
|
536
|
+
// Bubble up the events, find the event source (eventObject)
|
|
568
537
|
for (const hit of hits) {
|
|
569
|
-
let eventObject = hit.object;
|
|
570
|
-
|
|
538
|
+
let eventObject = hit.object;
|
|
539
|
+
// Bubble event up
|
|
571
540
|
while (eventObject) {
|
|
572
541
|
var _r3f2;
|
|
573
|
-
|
|
574
|
-
|
|
542
|
+
if ((_r3f2 = eventObject.__r3f) != null && _r3f2.eventCount) intersections.push({
|
|
543
|
+
...hit,
|
|
575
544
|
eventObject
|
|
576
545
|
});
|
|
577
546
|
eventObject = eventObject.parent;
|
|
578
547
|
}
|
|
579
|
-
}
|
|
580
|
-
|
|
548
|
+
}
|
|
581
549
|
|
|
550
|
+
// If the interaction is captured, make all capturing targets part of the intersect.
|
|
582
551
|
if ('pointerId' in event && state.internal.capturedMap.has(event.pointerId)) {
|
|
583
552
|
for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
|
|
584
553
|
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
585
554
|
}
|
|
586
555
|
}
|
|
587
|
-
|
|
588
556
|
return intersections;
|
|
589
557
|
}
|
|
590
|
-
/** Handles intersections by forwarding them to handlers */
|
|
591
|
-
|
|
592
558
|
|
|
559
|
+
/** Handles intersections by forwarding them to handlers */
|
|
593
560
|
function handleIntersects(intersections, event, delta, callback) {
|
|
594
|
-
const rootState = store.getState();
|
|
561
|
+
const rootState = store.getState();
|
|
595
562
|
|
|
563
|
+
// If anything has been found, forward it to the event listeners
|
|
596
564
|
if (intersections.length) {
|
|
597
565
|
const localState = {
|
|
598
566
|
stopped: false
|
|
599
567
|
};
|
|
600
|
-
|
|
601
568
|
for (const hit of intersections) {
|
|
602
569
|
const state = getRootState(hit.object) || rootState;
|
|
603
570
|
const {
|
|
@@ -607,19 +574,15 @@ function createEvents(store) {
|
|
|
607
574
|
internal
|
|
608
575
|
} = state;
|
|
609
576
|
const unprojectedPoint = new THREE.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
610
|
-
|
|
611
577
|
const hasPointerCapture = id => {
|
|
612
578
|
var _internal$capturedMap, _internal$capturedMap2;
|
|
613
|
-
|
|
614
579
|
return (_internal$capturedMap = (_internal$capturedMap2 = internal.capturedMap.get(id)) == null ? void 0 : _internal$capturedMap2.has(hit.eventObject)) != null ? _internal$capturedMap : false;
|
|
615
580
|
};
|
|
616
|
-
|
|
617
581
|
const setPointerCapture = id => {
|
|
618
582
|
const captureData = {
|
|
619
583
|
intersection: hit,
|
|
620
584
|
target: event.target
|
|
621
585
|
};
|
|
622
|
-
|
|
623
586
|
if (internal.capturedMap.has(id)) {
|
|
624
587
|
// if the pointerId was previously captured, we add the hit to the
|
|
625
588
|
// event capturedMap.
|
|
@@ -629,29 +592,27 @@ function createEvents(store) {
|
|
|
629
592
|
// containing the hitObject, and the hit. hitObject is used for
|
|
630
593
|
// faster access.
|
|
631
594
|
internal.capturedMap.set(id, new Map([[hit.eventObject, captureData]]));
|
|
632
|
-
}
|
|
595
|
+
}
|
|
633
596
|
event.target.setPointerCapture(id);
|
|
634
597
|
};
|
|
635
|
-
|
|
636
598
|
const releasePointerCapture = id => {
|
|
637
599
|
const captures = internal.capturedMap.get(id);
|
|
638
|
-
|
|
639
600
|
if (captures) {
|
|
640
601
|
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
641
602
|
}
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
let extractEventProps = {}; // This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
|
|
603
|
+
};
|
|
646
604
|
|
|
605
|
+
// Add native event props
|
|
606
|
+
let extractEventProps = {};
|
|
607
|
+
// This iterates over the event's properties including the inherited ones. Native PointerEvents have most of their props as getters which are inherited, but polyfilled PointerEvents have them all as their own properties (i.e. not inherited). We can't use Object.keys() or Object.entries() as they only return "own" properties; nor Object.getPrototypeOf(event) as that *doesn't* return "own" properties, only inherited ones.
|
|
647
608
|
for (let prop in event) {
|
|
648
|
-
let property = event[prop];
|
|
609
|
+
let property = event[prop];
|
|
610
|
+
// Only copy over atomics, leave functions alone as these should be
|
|
649
611
|
// called as event.nativeEvent.fn()
|
|
650
|
-
|
|
651
612
|
if (typeof property !== 'function') extractEventProps[prop] = property;
|
|
652
613
|
}
|
|
653
|
-
|
|
654
|
-
|
|
614
|
+
let raycastEvent = {
|
|
615
|
+
...hit,
|
|
655
616
|
...extractEventProps,
|
|
656
617
|
pointer,
|
|
657
618
|
intersections,
|
|
@@ -660,19 +621,21 @@ function createEvents(store) {
|
|
|
660
621
|
unprojectedPoint,
|
|
661
622
|
ray: raycaster.ray,
|
|
662
623
|
camera: camera,
|
|
663
|
-
|
|
664
624
|
// Hijack stopPropagation, which just sets a flag
|
|
665
625
|
stopPropagation() {
|
|
666
626
|
// https://github.com/pmndrs/react-three-fiber/issues/596
|
|
667
627
|
// Events are not allowed to stop propagation if the pointer has been captured
|
|
668
|
-
const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId);
|
|
628
|
+
const capturesForPointer = 'pointerId' in event && internal.capturedMap.get(event.pointerId);
|
|
669
629
|
|
|
670
|
-
|
|
671
|
-
|
|
630
|
+
// We only authorize stopPropagation...
|
|
631
|
+
if (
|
|
632
|
+
// ...if this pointer hasn't been captured
|
|
633
|
+
!capturesForPointer ||
|
|
634
|
+
// ... or if the hit object is capturing the pointer
|
|
672
635
|
capturesForPointer.has(hit.eventObject)) {
|
|
673
|
-
raycastEvent.stopped = localState.stopped = true;
|
|
636
|
+
raycastEvent.stopped = localState.stopped = true;
|
|
637
|
+
// Propagation is stopped, remove all other hover records
|
|
674
638
|
// An event handler is only allowed to flush other handlers if it is hovered itself
|
|
675
|
-
|
|
676
639
|
if (internal.hovered.size && Array.from(internal.hovered.values()).find(i => i.eventObject === hit.eventObject)) {
|
|
677
640
|
// Objects cannot flush out higher up objects that have already caught the event
|
|
678
641
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
@@ -680,7 +643,6 @@ function createEvents(store) {
|
|
|
680
643
|
}
|
|
681
644
|
}
|
|
682
645
|
},
|
|
683
|
-
|
|
684
646
|
// there should be a distinction between target and currentTarget
|
|
685
647
|
target: {
|
|
686
648
|
hasPointerCapture,
|
|
@@ -693,22 +655,20 @@ function createEvents(store) {
|
|
|
693
655
|
releasePointerCapture
|
|
694
656
|
},
|
|
695
657
|
nativeEvent: event
|
|
696
|
-
};
|
|
697
|
-
|
|
698
|
-
callback(raycastEvent); // Event bubbling may be interrupted by stopPropagation
|
|
658
|
+
};
|
|
699
659
|
|
|
660
|
+
// Call subscribers
|
|
661
|
+
callback(raycastEvent);
|
|
662
|
+
// Event bubbling may be interrupted by stopPropagation
|
|
700
663
|
if (localState.stopped === true) break;
|
|
701
664
|
}
|
|
702
665
|
}
|
|
703
|
-
|
|
704
666
|
return intersections;
|
|
705
667
|
}
|
|
706
|
-
|
|
707
668
|
function cancelPointer(intersections) {
|
|
708
669
|
const {
|
|
709
670
|
internal
|
|
710
671
|
} = store.getState();
|
|
711
|
-
|
|
712
672
|
for (const hoveredObj of internal.hovered.values()) {
|
|
713
673
|
// When no objects were hit or the the hovered object wasn't found underneath the cursor
|
|
714
674
|
// we call onPointerOut and delete the object from the hovered-elements map
|
|
@@ -717,10 +677,10 @@ function createEvents(store) {
|
|
|
717
677
|
const instance = eventObject.__r3f;
|
|
718
678
|
const handlers = instance == null ? void 0 : instance.handlers;
|
|
719
679
|
internal.hovered.delete(makeId(hoveredObj));
|
|
720
|
-
|
|
721
680
|
if (instance != null && instance.eventCount) {
|
|
722
681
|
// Clear out intersects, they are outdated by now
|
|
723
|
-
const data = {
|
|
682
|
+
const data = {
|
|
683
|
+
...hoveredObj,
|
|
724
684
|
intersections
|
|
725
685
|
};
|
|
726
686
|
handlers.onPointerOut == null ? void 0 : handlers.onPointerOut(data);
|
|
@@ -729,27 +689,23 @@ function createEvents(store) {
|
|
|
729
689
|
}
|
|
730
690
|
}
|
|
731
691
|
}
|
|
732
|
-
|
|
733
692
|
function pointerMissed(event, objects) {
|
|
734
693
|
for (let i = 0; i < objects.length; i++) {
|
|
735
694
|
const instance = objects[i].__r3f;
|
|
736
695
|
instance == null ? void 0 : instance.handlers.onPointerMissed == null ? void 0 : instance.handlers.onPointerMissed(event);
|
|
737
696
|
}
|
|
738
697
|
}
|
|
739
|
-
|
|
740
698
|
function handlePointer(name) {
|
|
741
699
|
// Deal with cancelation
|
|
742
700
|
switch (name) {
|
|
743
701
|
case 'onPointerLeave':
|
|
744
702
|
case 'onPointerCancel':
|
|
745
703
|
return () => cancelPointer([]);
|
|
746
|
-
|
|
747
704
|
case 'onLostPointerCapture':
|
|
748
705
|
return event => {
|
|
749
706
|
const {
|
|
750
707
|
internal
|
|
751
708
|
} = store.getState();
|
|
752
|
-
|
|
753
709
|
if ('pointerId' in event && internal.capturedMap.has(event.pointerId)) {
|
|
754
710
|
// If the object event interface had onLostPointerCapture, we'd call it here on every
|
|
755
711
|
// object that's getting removed.
|
|
@@ -757,55 +713,54 @@ function createEvents(store) {
|
|
|
757
713
|
cancelPointer([]);
|
|
758
714
|
}
|
|
759
715
|
};
|
|
760
|
-
}
|
|
761
|
-
|
|
716
|
+
}
|
|
762
717
|
|
|
718
|
+
// Any other pointer goes here ...
|
|
763
719
|
return function handleEvent(event) {
|
|
764
720
|
const {
|
|
765
721
|
onPointerMissed,
|
|
766
722
|
internal
|
|
767
|
-
} = store.getState();
|
|
723
|
+
} = store.getState();
|
|
768
724
|
|
|
769
|
-
|
|
725
|
+
// prepareRay(event)
|
|
726
|
+
internal.lastEvent.current = event;
|
|
770
727
|
|
|
728
|
+
// Get fresh intersects
|
|
771
729
|
const isPointerMove = name === 'onPointerMove';
|
|
772
730
|
const isClickEvent = name === 'onClick' || name === 'onContextMenu' || name === 'onDoubleClick';
|
|
773
|
-
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
774
|
-
|
|
731
|
+
const filter = isPointerMove ? filterPointerEvents : undefined;
|
|
775
732
|
const hits = intersect(event, filter);
|
|
776
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
733
|
+
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
777
734
|
|
|
735
|
+
// Save initial coordinates on pointer-down
|
|
778
736
|
if (name === 'onPointerDown') {
|
|
779
737
|
internal.initialClick = [event.offsetX, event.offsetY];
|
|
780
738
|
internal.initialHits = hits.map(hit => hit.eventObject);
|
|
781
|
-
}
|
|
782
|
-
// Missed events have to come first in order to establish user-land side-effect clean up
|
|
783
|
-
|
|
739
|
+
}
|
|
784
740
|
|
|
741
|
+
// If a click yields no results, pass it back to the user as a miss
|
|
742
|
+
// Missed events have to come first in order to establish user-land side-effect clean up
|
|
785
743
|
if (isClickEvent && !hits.length) {
|
|
786
744
|
if (delta <= 2) {
|
|
787
745
|
pointerMissed(event, internal.interaction);
|
|
788
746
|
if (onPointerMissed) onPointerMissed(event);
|
|
789
747
|
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
748
|
+
}
|
|
749
|
+
// Take care of unhover
|
|
793
750
|
if (isPointerMove) cancelPointer(hits);
|
|
794
|
-
|
|
795
751
|
function onIntersect(data) {
|
|
796
752
|
const eventObject = data.eventObject;
|
|
797
753
|
const instance = eventObject.__r3f;
|
|
798
|
-
const handlers = instance == null ? void 0 : instance.handlers;
|
|
754
|
+
const handlers = instance == null ? void 0 : instance.handlers;
|
|
799
755
|
|
|
756
|
+
// Check presence of handlers
|
|
800
757
|
if (!(instance != null && instance.eventCount)) return;
|
|
801
|
-
|
|
802
758
|
if (isPointerMove) {
|
|
803
759
|
// Move event ...
|
|
804
760
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
805
761
|
// When enter or out is present take care of hover-state
|
|
806
762
|
const id = makeId(data);
|
|
807
763
|
const hoveredItem = internal.hovered.get(id);
|
|
808
|
-
|
|
809
764
|
if (!hoveredItem) {
|
|
810
765
|
// If the object wasn't previously hovered, book it and call its handler
|
|
811
766
|
internal.hovered.set(id, data);
|
|
@@ -815,21 +770,19 @@ function createEvents(store) {
|
|
|
815
770
|
// If the object was previously hovered and stopped, we shouldn't allow other items to proceed
|
|
816
771
|
data.stopPropagation();
|
|
817
772
|
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
|
|
773
|
+
}
|
|
774
|
+
// Call mouse move
|
|
821
775
|
handlers.onPointerMove == null ? void 0 : handlers.onPointerMove(data);
|
|
822
776
|
} else {
|
|
823
777
|
// All other events ...
|
|
824
778
|
const handler = handlers[name];
|
|
825
|
-
|
|
826
779
|
if (handler) {
|
|
827
780
|
// Forward all events back to their respective handlers with the exception of click events,
|
|
828
781
|
// which must use the initial target
|
|
829
782
|
if (!isClickEvent || internal.initialHits.includes(eventObject)) {
|
|
830
783
|
// Missed events have to come first
|
|
831
|
-
pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object)));
|
|
832
|
-
|
|
784
|
+
pointerMissed(event, internal.interaction.filter(object => !internal.initialHits.includes(object)));
|
|
785
|
+
// Now call the handler
|
|
833
786
|
handler(data);
|
|
834
787
|
}
|
|
835
788
|
} else {
|
|
@@ -840,22 +793,19 @@ function createEvents(store) {
|
|
|
840
793
|
}
|
|
841
794
|
}
|
|
842
795
|
}
|
|
843
|
-
|
|
844
796
|
handleIntersects(hits, event, delta, onIntersect);
|
|
845
797
|
};
|
|
846
798
|
}
|
|
847
|
-
|
|
848
799
|
return {
|
|
849
800
|
handlePointer
|
|
850
801
|
};
|
|
851
802
|
}
|
|
852
803
|
|
|
853
804
|
let catalogue = {};
|
|
854
|
-
|
|
855
|
-
|
|
805
|
+
let extend = objects => void (catalogue = {
|
|
806
|
+
...catalogue,
|
|
856
807
|
...objects
|
|
857
808
|
});
|
|
858
|
-
|
|
859
809
|
function createRenderer(_roots, _getEventPriority) {
|
|
860
810
|
function createInstance(type, {
|
|
861
811
|
args = [],
|
|
@@ -864,7 +814,6 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
864
814
|
}, root) {
|
|
865
815
|
let name = `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
866
816
|
let instance;
|
|
867
|
-
|
|
868
817
|
if (type === 'primitive') {
|
|
869
818
|
if (props.object === undefined) throw new Error("R3F: Primitives without 'object' are invalid!");
|
|
870
819
|
const object = props.object;
|
|
@@ -876,15 +825,15 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
876
825
|
});
|
|
877
826
|
} else {
|
|
878
827
|
const target = catalogue[name];
|
|
879
|
-
|
|
880
828
|
if (!target) {
|
|
881
829
|
throw new Error(`R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`);
|
|
882
|
-
}
|
|
830
|
+
}
|
|
883
831
|
|
|
832
|
+
// Throw if an object or literal was passed for args
|
|
833
|
+
if (!Array.isArray(args)) throw new Error('R3F: The args prop must be an array!');
|
|
884
834
|
|
|
885
|
-
|
|
835
|
+
// Instanciate new object, link it to the root
|
|
886
836
|
// Append memoized props with args so it's not forgotten
|
|
887
|
-
|
|
888
837
|
instance = prepare(new target(...args), {
|
|
889
838
|
type,
|
|
890
839
|
root,
|
|
@@ -894,27 +843,24 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
894
843
|
args
|
|
895
844
|
}
|
|
896
845
|
});
|
|
897
|
-
}
|
|
898
|
-
|
|
846
|
+
}
|
|
899
847
|
|
|
848
|
+
// Auto-attach geometries and materials
|
|
900
849
|
if (instance.__r3f.attach === undefined) {
|
|
901
850
|
if (instance instanceof THREE.BufferGeometry) instance.__r3f.attach = 'geometry';else if (instance instanceof THREE.Material) instance.__r3f.attach = 'material';
|
|
902
|
-
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// It should NOT call onUpdate on object instanciation, because it hasn't been added to the
|
|
903
854
|
// view yet. If the callback relies on references for instance, they won't be ready yet, this is
|
|
904
855
|
// why it passes "true" here
|
|
905
856
|
// There is no reason to apply props to injects
|
|
906
|
-
|
|
907
|
-
|
|
908
857
|
if (name !== 'inject') applyProps$1(instance, props);
|
|
909
858
|
return instance;
|
|
910
859
|
}
|
|
911
|
-
|
|
912
860
|
function appendChild(parentInstance, child) {
|
|
913
861
|
let added = false;
|
|
914
|
-
|
|
915
862
|
if (child) {
|
|
916
863
|
var _child$__r3f, _parentInstance$__r3f;
|
|
917
|
-
|
|
918
864
|
// The attach attribute implies that the object attaches itself on the parent
|
|
919
865
|
if ((_child$__r3f = child.__r3f) != null && _child$__r3f.attach) {
|
|
920
866
|
attach(parentInstance, child, child.__r3f.attach);
|
|
@@ -922,10 +868,9 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
922
868
|
// add in the usual parent-child way
|
|
923
869
|
parentInstance.add(child);
|
|
924
870
|
added = true;
|
|
925
|
-
}
|
|
871
|
+
}
|
|
872
|
+
// This is for anything that used attach, and for non-Object3Ds that don't get attached to props;
|
|
926
873
|
// that is, anything that's a child in React but not a child in the scenegraph.
|
|
927
|
-
|
|
928
|
-
|
|
929
874
|
if (!added) (_parentInstance$__r3f = parentInstance.__r3f) == null ? void 0 : _parentInstance$__r3f.objects.push(child);
|
|
930
875
|
if (!child.__r3f) prepare(child, {});
|
|
931
876
|
child.__r3f.parent = parentInstance;
|
|
@@ -933,13 +878,10 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
933
878
|
invalidateInstance(child);
|
|
934
879
|
}
|
|
935
880
|
}
|
|
936
|
-
|
|
937
881
|
function insertBefore(parentInstance, child, beforeChild) {
|
|
938
882
|
let added = false;
|
|
939
|
-
|
|
940
883
|
if (child) {
|
|
941
884
|
var _child$__r3f2, _parentInstance$__r3f2;
|
|
942
|
-
|
|
943
885
|
if ((_child$__r3f2 = child.__r3f) != null && _child$__r3f2.attach) {
|
|
944
886
|
attach(parentInstance, child, child.__r3f.attach);
|
|
945
887
|
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
@@ -952,7 +894,6 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
952
894
|
parentInstance.children = [...restSiblings.slice(0, index), child, ...restSiblings.slice(index)];
|
|
953
895
|
added = true;
|
|
954
896
|
}
|
|
955
|
-
|
|
956
897
|
if (!added) (_parentInstance$__r3f2 = parentInstance.__r3f) == null ? void 0 : _parentInstance$__r3f2.objects.push(child);
|
|
957
898
|
if (!child.__r3f) prepare(child, {});
|
|
958
899
|
child.__r3f.parent = parentInstance;
|
|
@@ -960,31 +901,29 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
960
901
|
invalidateInstance(child);
|
|
961
902
|
}
|
|
962
903
|
}
|
|
963
|
-
|
|
964
904
|
function removeRecursive(array, parent, dispose = false) {
|
|
965
905
|
if (array) [...array].forEach(child => removeChild(parent, child, dispose));
|
|
966
906
|
}
|
|
967
|
-
|
|
968
907
|
function removeChild(parentInstance, child, dispose) {
|
|
969
908
|
if (child) {
|
|
970
909
|
var _parentInstance$__r3f3, _child$__r3f3, _child$__r3f5;
|
|
971
|
-
|
|
972
910
|
// Clear the parent reference
|
|
973
|
-
if (child.__r3f) child.__r3f.parent = null;
|
|
974
|
-
|
|
975
|
-
if ((_parentInstance$__r3f3 = parentInstance.__r3f) != null && _parentInstance$__r3f3.objects) parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(x => x !== child);
|
|
976
|
-
|
|
911
|
+
if (child.__r3f) child.__r3f.parent = null;
|
|
912
|
+
// Remove child from the parents objects
|
|
913
|
+
if ((_parentInstance$__r3f3 = parentInstance.__r3f) != null && _parentInstance$__r3f3.objects) parentInstance.__r3f.objects = parentInstance.__r3f.objects.filter(x => x !== child);
|
|
914
|
+
// Remove attachment
|
|
977
915
|
if ((_child$__r3f3 = child.__r3f) != null && _child$__r3f3.attach) {
|
|
978
916
|
detach(parentInstance, child, child.__r3f.attach);
|
|
979
917
|
} else if (child.isObject3D && parentInstance.isObject3D) {
|
|
980
918
|
var _child$__r3f4;
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
919
|
+
parentInstance.remove(child);
|
|
920
|
+
// Remove interactivity
|
|
984
921
|
if ((_child$__r3f4 = child.__r3f) != null && _child$__r3f4.root) {
|
|
985
922
|
removeInteractivity(child.__r3f.root, child);
|
|
986
923
|
}
|
|
987
|
-
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Allow objects to bail out of recursive dispose altogether by passing dispose={null}
|
|
988
927
|
// Never dispose of primitives because their state may be kept outside of React!
|
|
989
928
|
// In order for an object to be able to dispose it has to have
|
|
990
929
|
// - a dispose method,
|
|
@@ -993,29 +932,27 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
993
932
|
//
|
|
994
933
|
// Since disposal is recursive, we can check the optional dispose arg, which will be undefined
|
|
995
934
|
// when the reconciler calls it, but then carry our own check recursively
|
|
996
|
-
|
|
997
|
-
|
|
998
935
|
const isPrimitive = (_child$__r3f5 = child.__r3f) == null ? void 0 : _child$__r3f5.primitive;
|
|
999
|
-
const shouldDispose = dispose === undefined ? child.dispose !== null && !isPrimitive : dispose;
|
|
1000
|
-
// attached to them declaratively ...
|
|
936
|
+
const shouldDispose = dispose === undefined ? child.dispose !== null && !isPrimitive : dispose;
|
|
1001
937
|
|
|
938
|
+
// Remove nested child objects. Primitives should not have objects and children that are
|
|
939
|
+
// attached to them declaratively ...
|
|
1002
940
|
if (!isPrimitive) {
|
|
1003
941
|
var _child$__r3f6;
|
|
1004
|
-
|
|
1005
942
|
removeRecursive((_child$__r3f6 = child.__r3f) == null ? void 0 : _child$__r3f6.objects, child, shouldDispose);
|
|
1006
943
|
removeRecursive(child.children, child, shouldDispose);
|
|
1007
|
-
}
|
|
1008
|
-
|
|
944
|
+
}
|
|
1009
945
|
|
|
946
|
+
// Remove references
|
|
1010
947
|
if (child.__r3f) {
|
|
1011
948
|
delete child.__r3f.root;
|
|
1012
949
|
delete child.__r3f.objects;
|
|
1013
950
|
delete child.__r3f.handlers;
|
|
1014
951
|
delete child.__r3f.memoizedProps;
|
|
1015
952
|
if (!isPrimitive) delete child.__r3f;
|
|
1016
|
-
}
|
|
1017
|
-
|
|
953
|
+
}
|
|
1018
954
|
|
|
955
|
+
// Dispose item whenever the reconciler feels like it
|
|
1019
956
|
if (shouldDispose && child.dispose && child.type !== 'Scene') {
|
|
1020
957
|
unstable_scheduleCallback(unstable_IdlePriority, () => {
|
|
1021
958
|
try {
|
|
@@ -1025,61 +962,51 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1025
962
|
}
|
|
1026
963
|
});
|
|
1027
964
|
}
|
|
1028
|
-
|
|
1029
965
|
invalidateInstance(parentInstance);
|
|
1030
966
|
}
|
|
1031
967
|
}
|
|
1032
|
-
|
|
1033
968
|
function switchInstance(instance, type, newProps, fiber) {
|
|
1034
969
|
var _instance$__r3f;
|
|
1035
|
-
|
|
1036
970
|
const parent = (_instance$__r3f = instance.__r3f) == null ? void 0 : _instance$__r3f.parent;
|
|
1037
971
|
if (!parent) return;
|
|
1038
|
-
const newInstance = createInstance(type, newProps, instance.__r3f.root);
|
|
972
|
+
const newInstance = createInstance(type, newProps, instance.__r3f.root);
|
|
973
|
+
|
|
974
|
+
// https://github.com/pmndrs/react-three-fiber/issues/1348
|
|
1039
975
|
// When args change the instance has to be re-constructed, which then
|
|
1040
976
|
// forces r3f to re-parent the children and non-scene objects
|
|
1041
|
-
|
|
1042
977
|
if (instance.children) {
|
|
1043
978
|
for (const child of instance.children) {
|
|
1044
979
|
if (child.__r3f) appendChild(newInstance, child);
|
|
1045
980
|
}
|
|
1046
|
-
|
|
1047
981
|
instance.children = instance.children.filter(child => !child.__r3f);
|
|
1048
982
|
}
|
|
1049
|
-
|
|
1050
983
|
instance.__r3f.objects.forEach(child => appendChild(newInstance, child));
|
|
1051
|
-
|
|
1052
984
|
instance.__r3f.objects = [];
|
|
1053
|
-
|
|
1054
985
|
if (!instance.__r3f.autoRemovedBeforeAppend) {
|
|
1055
986
|
removeChild(parent, instance);
|
|
1056
987
|
}
|
|
1057
|
-
|
|
1058
988
|
if (newInstance.parent) {
|
|
1059
989
|
newInstance.__r3f.autoRemovedBeforeAppend = true;
|
|
1060
990
|
}
|
|
991
|
+
appendChild(parent, newInstance);
|
|
1061
992
|
|
|
1062
|
-
|
|
1063
|
-
|
|
993
|
+
// Re-bind event handlers
|
|
1064
994
|
if (newInstance.raycast && newInstance.__r3f.eventCount) {
|
|
1065
995
|
const rootState = newInstance.__r3f.root.getState();
|
|
1066
|
-
|
|
1067
996
|
rootState.internal.interaction.push(newInstance);
|
|
1068
|
-
}
|
|
997
|
+
}
|
|
1069
998
|
[fiber, fiber.alternate].forEach(fiber => {
|
|
1070
999
|
if (fiber !== null) {
|
|
1071
1000
|
fiber.stateNode = newInstance;
|
|
1072
|
-
|
|
1073
1001
|
if (fiber.ref) {
|
|
1074
1002
|
if (typeof fiber.ref === 'function') fiber.ref(newInstance);else fiber.ref.current = newInstance;
|
|
1075
1003
|
}
|
|
1076
1004
|
}
|
|
1077
1005
|
});
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1006
|
+
}
|
|
1080
1007
|
|
|
1008
|
+
// Don't handle text instances, warn on undefined behavior
|
|
1081
1009
|
const handleTextInstance = () => console.warn('Text is not allowed in the R3F tree! This could be stray whitespace or characters.');
|
|
1082
|
-
|
|
1083
1010
|
const reconciler = Reconciler({
|
|
1084
1011
|
createInstance,
|
|
1085
1012
|
removeChild,
|
|
@@ -1092,11 +1019,13 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1092
1019
|
supportsHydration: false,
|
|
1093
1020
|
noTimeout: -1,
|
|
1094
1021
|
appendChildToContainer: (container, child) => {
|
|
1095
|
-
if (!child) return;
|
|
1022
|
+
if (!child) return;
|
|
1096
1023
|
|
|
1024
|
+
// Don't append to unmounted container
|
|
1097
1025
|
const scene = container.getState().scene;
|
|
1098
|
-
if (!scene.__r3f) return;
|
|
1026
|
+
if (!scene.__r3f) return;
|
|
1099
1027
|
|
|
1028
|
+
// Link current root to the default scene
|
|
1100
1029
|
scene.__r3f.root = container;
|
|
1101
1030
|
appendChild(scene, child);
|
|
1102
1031
|
},
|
|
@@ -1105,24 +1034,22 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1105
1034
|
removeChild(container.getState().scene, child);
|
|
1106
1035
|
},
|
|
1107
1036
|
insertInContainerBefore: (container, child, beforeChild) => {
|
|
1108
|
-
if (!child || !beforeChild) return;
|
|
1037
|
+
if (!child || !beforeChild) return;
|
|
1109
1038
|
|
|
1039
|
+
// Don't append to unmounted container
|
|
1110
1040
|
const scene = container.getState().scene;
|
|
1111
1041
|
if (!scene.__r3f) return;
|
|
1112
1042
|
insertBefore(scene, child, beforeChild);
|
|
1113
1043
|
},
|
|
1114
1044
|
getRootHostContext: () => null,
|
|
1115
1045
|
getChildHostContext: parentHostContext => parentHostContext,
|
|
1116
|
-
|
|
1117
1046
|
finalizeInitialChildren(instance) {
|
|
1118
1047
|
var _instance$__r3f2;
|
|
1119
|
-
|
|
1120
|
-
|
|
1048
|
+
const localState = (_instance$__r3f2 = instance == null ? void 0 : instance.__r3f) != null ? _instance$__r3f2 : {};
|
|
1049
|
+
// https://github.com/facebook/react/issues/20271
|
|
1121
1050
|
// Returning true will trigger commitMount
|
|
1122
|
-
|
|
1123
1051
|
return Boolean(localState.handlers);
|
|
1124
1052
|
},
|
|
1125
|
-
|
|
1126
1053
|
prepareUpdate(instance, _type, oldProps, newProps) {
|
|
1127
1054
|
// Create diff-sets
|
|
1128
1055
|
if (instance.__r3f.primitive && newProps.object && newProps.object !== instance) {
|
|
@@ -1138,47 +1065,44 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1138
1065
|
args: argsOld = [],
|
|
1139
1066
|
children: cO,
|
|
1140
1067
|
...restOld
|
|
1141
|
-
} = oldProps;
|
|
1142
|
-
|
|
1143
|
-
if (!Array.isArray(argsNew)) throw new Error('R3F: the args prop must be an array!'); // If it has new props or arguments, then it needs to be re-instantiated
|
|
1068
|
+
} = oldProps;
|
|
1144
1069
|
|
|
1145
|
-
|
|
1070
|
+
// Throw if an object or literal was passed for args
|
|
1071
|
+
if (!Array.isArray(argsNew)) throw new Error('R3F: the args prop must be an array!');
|
|
1146
1072
|
|
|
1073
|
+
// If it has new props or arguments, then it needs to be re-instantiated
|
|
1074
|
+
if (argsNew.some((value, index) => value !== argsOld[index])) return [true];
|
|
1075
|
+
// Create a diff-set, flag if there are any changes
|
|
1147
1076
|
const diff = diffProps(instance, restNew, restOld, true);
|
|
1148
|
-
if (diff.changes.length) return [false, diff];
|
|
1077
|
+
if (diff.changes.length) return [false, diff];
|
|
1149
1078
|
|
|
1079
|
+
// Otherwise do not touch the instance
|
|
1150
1080
|
return null;
|
|
1151
1081
|
}
|
|
1152
1082
|
},
|
|
1153
|
-
|
|
1154
1083
|
commitUpdate(instance, [reconstruct, diff], type, _oldProps, newProps, fiber) {
|
|
1155
1084
|
// Reconstruct when args or <primitive object={...} have changes
|
|
1156
|
-
if (reconstruct) switchInstance(instance, type, newProps, fiber);
|
|
1085
|
+
if (reconstruct) switchInstance(instance, type, newProps, fiber);
|
|
1086
|
+
// Otherwise just overwrite props
|
|
1157
1087
|
else applyProps$1(instance, diff);
|
|
1158
1088
|
},
|
|
1159
|
-
|
|
1160
1089
|
commitMount(instance, _type, _props, _int) {
|
|
1161
1090
|
var _instance$__r3f3;
|
|
1162
|
-
|
|
1163
1091
|
// https://github.com/facebook/react/issues/20271
|
|
1164
1092
|
// This will make sure events are only added once to the central container
|
|
1165
1093
|
const localState = (_instance$__r3f3 = instance.__r3f) != null ? _instance$__r3f3 : {};
|
|
1166
|
-
|
|
1167
1094
|
if (instance.raycast && localState.handlers && localState.eventCount) {
|
|
1168
1095
|
instance.__r3f.root.getState().internal.interaction.push(instance);
|
|
1169
1096
|
}
|
|
1170
1097
|
},
|
|
1171
|
-
|
|
1172
1098
|
getPublicInstance: instance => instance,
|
|
1173
1099
|
prepareForCommit: () => null,
|
|
1174
1100
|
preparePortalMount: container => prepare(container.getState().scene),
|
|
1175
1101
|
resetAfterCommit: () => {},
|
|
1176
1102
|
shouldSetTextContent: () => false,
|
|
1177
1103
|
clearContainer: () => false,
|
|
1178
|
-
|
|
1179
1104
|
hideInstance(instance) {
|
|
1180
1105
|
var _instance$__r3f4;
|
|
1181
|
-
|
|
1182
1106
|
// Detach while the instance is hidden
|
|
1183
1107
|
const {
|
|
1184
1108
|
attach: type,
|
|
@@ -1188,10 +1112,8 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1188
1112
|
if (instance.isObject3D) instance.visible = false;
|
|
1189
1113
|
invalidateInstance(instance);
|
|
1190
1114
|
},
|
|
1191
|
-
|
|
1192
1115
|
unhideInstance(instance, props) {
|
|
1193
1116
|
var _instance$__r3f5;
|
|
1194
|
-
|
|
1195
1117
|
// Re-attach when the instance is unhidden
|
|
1196
1118
|
const {
|
|
1197
1119
|
attach: type,
|
|
@@ -1201,7 +1123,6 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1201
1123
|
if (instance.isObject3D && props.visible == null || props.visible) instance.visible = true;
|
|
1202
1124
|
invalidateInstance(instance);
|
|
1203
1125
|
},
|
|
1204
|
-
|
|
1205
1126
|
createTextInstance: handleTextInstance,
|
|
1206
1127
|
hideTextInstance: handleTextInstance,
|
|
1207
1128
|
unhideTextInstance: handleTextInstance,
|
|
@@ -1222,16 +1143,15 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1222
1143
|
};
|
|
1223
1144
|
}
|
|
1224
1145
|
|
|
1146
|
+
// Keys that shouldn't be copied between R3F stores
|
|
1225
1147
|
const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'size', 'viewport'];
|
|
1226
1148
|
const isRenderer = def => !!(def != null && def.render);
|
|
1227
1149
|
const context = /*#__PURE__*/React.createContext(null);
|
|
1228
|
-
|
|
1229
1150
|
const createStore = (invalidate, advance) => {
|
|
1230
1151
|
const rootState = create((set, get) => {
|
|
1231
1152
|
const position = new THREE.Vector3();
|
|
1232
1153
|
const defaultTarget = new THREE.Vector3();
|
|
1233
1154
|
const tempTarget = new THREE.Vector3();
|
|
1234
|
-
|
|
1235
1155
|
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
1236
1156
|
const {
|
|
1237
1157
|
width,
|
|
@@ -1242,7 +1162,6 @@ const createStore = (invalidate, advance) => {
|
|
|
1242
1162
|
const aspect = width / height;
|
|
1243
1163
|
if (target instanceof THREE.Vector3) tempTarget.copy(target);else tempTarget.set(...target);
|
|
1244
1164
|
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
1245
|
-
|
|
1246
1165
|
if (isOrthographicCamera(camera)) {
|
|
1247
1166
|
return {
|
|
1248
1167
|
width: width / camera.zoom,
|
|
@@ -1255,9 +1174,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1255
1174
|
};
|
|
1256
1175
|
} else {
|
|
1257
1176
|
const fov = camera.fov * Math.PI / 180; // convert vertical fov to radians
|
|
1258
|
-
|
|
1259
1177
|
const h = 2 * Math.tan(fov / 2) * distance; // visible height
|
|
1260
|
-
|
|
1261
1178
|
const w = h * (width / height);
|
|
1262
1179
|
return {
|
|
1263
1180
|
width: w,
|
|
@@ -1270,15 +1187,13 @@ const createStore = (invalidate, advance) => {
|
|
|
1270
1187
|
};
|
|
1271
1188
|
}
|
|
1272
1189
|
}
|
|
1273
|
-
|
|
1274
1190
|
let performanceTimeout = undefined;
|
|
1275
|
-
|
|
1276
1191
|
const setPerformanceCurrent = current => set(state => ({
|
|
1277
|
-
performance: {
|
|
1192
|
+
performance: {
|
|
1193
|
+
...state.performance,
|
|
1278
1194
|
current
|
|
1279
1195
|
}
|
|
1280
1196
|
}));
|
|
1281
|
-
|
|
1282
1197
|
const pointer = new THREE.Vector2();
|
|
1283
1198
|
const rootState = {
|
|
1284
1199
|
set,
|
|
@@ -1311,12 +1226,12 @@ const createStore = (invalidate, advance) => {
|
|
|
1311
1226
|
max: 1,
|
|
1312
1227
|
debounce: 200,
|
|
1313
1228
|
regress: () => {
|
|
1314
|
-
const state = get();
|
|
1315
|
-
|
|
1316
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1317
|
-
|
|
1318
|
-
if (state.performance.current !== state.performance.min) setPerformanceCurrent(state.performance.min);
|
|
1319
|
-
|
|
1229
|
+
const state = get();
|
|
1230
|
+
// Clear timeout
|
|
1231
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1232
|
+
// Set lower bound performance
|
|
1233
|
+
if (state.performance.current !== state.performance.min) setPerformanceCurrent(state.performance.min);
|
|
1234
|
+
// Go back to upper bound performance after a while unless something regresses meanwhile
|
|
1320
1235
|
performanceTimeout = setTimeout(() => setPerformanceCurrent(get().performance.max), state.performance.debounce);
|
|
1321
1236
|
}
|
|
1322
1237
|
},
|
|
@@ -1339,8 +1254,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1339
1254
|
factor: 0,
|
|
1340
1255
|
getCurrentViewport
|
|
1341
1256
|
},
|
|
1342
|
-
setEvents: events => set(state => ({
|
|
1343
|
-
|
|
1257
|
+
setEvents: events => set(state => ({
|
|
1258
|
+
...state,
|
|
1259
|
+
events: {
|
|
1260
|
+
...state.events,
|
|
1344
1261
|
...events
|
|
1345
1262
|
}
|
|
1346
1263
|
})),
|
|
@@ -1355,7 +1272,8 @@ const createStore = (invalidate, advance) => {
|
|
|
1355
1272
|
};
|
|
1356
1273
|
set(state => ({
|
|
1357
1274
|
size,
|
|
1358
|
-
viewport: {
|
|
1275
|
+
viewport: {
|
|
1276
|
+
...state.viewport,
|
|
1359
1277
|
...getCurrentViewport(camera, defaultTarget, size)
|
|
1360
1278
|
}
|
|
1361
1279
|
}));
|
|
@@ -1363,23 +1281,23 @@ const createStore = (invalidate, advance) => {
|
|
|
1363
1281
|
setDpr: dpr => set(state => {
|
|
1364
1282
|
const resolved = calculateDpr(dpr);
|
|
1365
1283
|
return {
|
|
1366
|
-
viewport: {
|
|
1284
|
+
viewport: {
|
|
1285
|
+
...state.viewport,
|
|
1367
1286
|
dpr: resolved,
|
|
1368
1287
|
initialDpr: state.viewport.initialDpr || resolved
|
|
1369
1288
|
}
|
|
1370
1289
|
};
|
|
1371
1290
|
}),
|
|
1372
1291
|
setFrameloop: (frameloop = 'always') => {
|
|
1373
|
-
const clock = get().clock;
|
|
1292
|
+
const clock = get().clock;
|
|
1374
1293
|
|
|
1294
|
+
// if frameloop === "never" clock.elapsedTime is updated using advance(timestamp)
|
|
1375
1295
|
clock.stop();
|
|
1376
1296
|
clock.elapsedTime = 0;
|
|
1377
|
-
|
|
1378
1297
|
if (frameloop !== 'never') {
|
|
1379
1298
|
clock.start();
|
|
1380
1299
|
clock.elapsedTime = 0;
|
|
1381
1300
|
}
|
|
1382
|
-
|
|
1383
1301
|
set(() => ({
|
|
1384
1302
|
frameloop
|
|
1385
1303
|
}));
|
|
@@ -1397,27 +1315,26 @@ const createStore = (invalidate, advance) => {
|
|
|
1397
1315
|
initialHits: [],
|
|
1398
1316
|
capturedMap: new Map(),
|
|
1399
1317
|
subscribe: (ref, priority, store) => {
|
|
1400
|
-
const internal = get().internal;
|
|
1318
|
+
const internal = get().internal;
|
|
1319
|
+
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1401
1320
|
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1402
1321
|
// As long as this flag is positive there can be no internal rendering at all
|
|
1403
1322
|
// because there could be multiple render subscriptions
|
|
1404
|
-
|
|
1405
1323
|
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1406
1324
|
internal.subscribers.push({
|
|
1407
1325
|
ref,
|
|
1408
1326
|
priority,
|
|
1409
1327
|
store
|
|
1410
|
-
});
|
|
1328
|
+
});
|
|
1329
|
+
// Register subscriber and sort layers from lowest to highest, meaning,
|
|
1411
1330
|
// highest priority renders last (on top of the other frames)
|
|
1412
|
-
|
|
1413
1331
|
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1414
1332
|
return () => {
|
|
1415
1333
|
const internal = get().internal;
|
|
1416
|
-
|
|
1417
1334
|
if (internal != null && internal.subscribers) {
|
|
1418
1335
|
// Decrease manual flag if this subscription had a priority
|
|
1419
|
-
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1420
|
-
|
|
1336
|
+
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1337
|
+
// Remove subscriber from list
|
|
1421
1338
|
internal.subscribers = internal.subscribers.filter(s => s.ref !== ref);
|
|
1422
1339
|
}
|
|
1423
1340
|
};
|
|
@@ -1437,31 +1354,35 @@ const createStore = (invalidate, advance) => {
|
|
|
1437
1354
|
viewport,
|
|
1438
1355
|
gl,
|
|
1439
1356
|
set
|
|
1440
|
-
} = rootState.getState();
|
|
1357
|
+
} = rootState.getState();
|
|
1441
1358
|
|
|
1359
|
+
// Resize camera and renderer on changes to size and pixelratio
|
|
1442
1360
|
if (size !== oldSize || viewport.dpr !== oldDpr) {
|
|
1443
1361
|
oldSize = size;
|
|
1444
|
-
oldDpr = viewport.dpr;
|
|
1445
|
-
|
|
1362
|
+
oldDpr = viewport.dpr;
|
|
1363
|
+
// Update camera & renderer
|
|
1446
1364
|
updateCamera(camera, size);
|
|
1447
1365
|
gl.setPixelRatio(viewport.dpr);
|
|
1448
1366
|
gl.setSize(size.width, size.height, size.updateStyle);
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1367
|
+
}
|
|
1451
1368
|
|
|
1369
|
+
// Update viewport once the camera changes
|
|
1452
1370
|
if (camera !== oldCamera) {
|
|
1453
|
-
oldCamera = camera;
|
|
1454
|
-
|
|
1371
|
+
oldCamera = camera;
|
|
1372
|
+
// Update viewport
|
|
1455
1373
|
set(state => ({
|
|
1456
|
-
viewport: {
|
|
1374
|
+
viewport: {
|
|
1375
|
+
...state.viewport,
|
|
1457
1376
|
...state.viewport.getCurrentViewport(camera)
|
|
1458
1377
|
}
|
|
1459
1378
|
}));
|
|
1460
1379
|
}
|
|
1461
|
-
});
|
|
1380
|
+
});
|
|
1462
1381
|
|
|
1463
|
-
|
|
1382
|
+
// Invalidate on any change
|
|
1383
|
+
rootState.subscribe(state => invalidate(state));
|
|
1464
1384
|
|
|
1385
|
+
// Return root state
|
|
1465
1386
|
return rootState;
|
|
1466
1387
|
};
|
|
1467
1388
|
|
|
@@ -1472,144 +1393,129 @@ function createSubs(callback, subs) {
|
|
|
1472
1393
|
subs.add(sub);
|
|
1473
1394
|
return () => void subs.delete(sub);
|
|
1474
1395
|
}
|
|
1475
|
-
|
|
1476
1396
|
let i;
|
|
1477
1397
|
let globalEffects = new Set();
|
|
1478
1398
|
let globalAfterEffects = new Set();
|
|
1479
1399
|
let globalTailEffects = new Set();
|
|
1400
|
+
|
|
1480
1401
|
/**
|
|
1481
1402
|
* Adds a global render callback which is called each frame.
|
|
1482
1403
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addEffect
|
|
1483
1404
|
*/
|
|
1484
|
-
|
|
1485
1405
|
const addEffect = callback => createSubs(callback, globalEffects);
|
|
1406
|
+
|
|
1486
1407
|
/**
|
|
1487
1408
|
* Adds a global after-render callback which is called each frame.
|
|
1488
1409
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addAfterEffect
|
|
1489
1410
|
*/
|
|
1490
|
-
|
|
1491
1411
|
const addAfterEffect = callback => createSubs(callback, globalAfterEffects);
|
|
1412
|
+
|
|
1492
1413
|
/**
|
|
1493
1414
|
* Adds a global callback which is called when rendering stops.
|
|
1494
1415
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#addTail
|
|
1495
1416
|
*/
|
|
1496
|
-
|
|
1497
1417
|
const addTail = callback => createSubs(callback, globalTailEffects);
|
|
1498
|
-
|
|
1499
1418
|
function run(effects, timestamp) {
|
|
1500
1419
|
if (!effects.size) return;
|
|
1501
|
-
|
|
1502
1420
|
for (const {
|
|
1503
1421
|
callback
|
|
1504
1422
|
} of effects.values()) {
|
|
1505
1423
|
callback(timestamp);
|
|
1506
1424
|
}
|
|
1507
1425
|
}
|
|
1508
|
-
|
|
1509
1426
|
function flushGlobalEffects(type, timestamp) {
|
|
1510
1427
|
switch (type) {
|
|
1511
1428
|
case 'before':
|
|
1512
1429
|
return run(globalEffects, timestamp);
|
|
1513
|
-
|
|
1514
1430
|
case 'after':
|
|
1515
1431
|
return run(globalAfterEffects, timestamp);
|
|
1516
|
-
|
|
1517
1432
|
case 'tail':
|
|
1518
1433
|
return run(globalTailEffects, timestamp);
|
|
1519
1434
|
}
|
|
1520
1435
|
}
|
|
1521
1436
|
let subscribers;
|
|
1522
1437
|
let subscription;
|
|
1523
|
-
|
|
1524
1438
|
function render$1(timestamp, state, frame) {
|
|
1525
1439
|
// Run local effects
|
|
1526
|
-
let delta = state.clock.getDelta();
|
|
1527
|
-
|
|
1440
|
+
let delta = state.clock.getDelta();
|
|
1441
|
+
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
1528
1442
|
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
1529
1443
|
delta = timestamp - state.clock.elapsedTime;
|
|
1530
1444
|
state.clock.oldTime = state.clock.elapsedTime;
|
|
1531
1445
|
state.clock.elapsedTime = timestamp;
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1446
|
+
}
|
|
1447
|
+
// Call subscribers (useFrame)
|
|
1535
1448
|
subscribers = state.internal.subscribers;
|
|
1536
|
-
|
|
1537
1449
|
for (i = 0; i < subscribers.length; i++) {
|
|
1538
1450
|
subscription = subscribers[i];
|
|
1539
1451
|
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1452
|
+
}
|
|
1453
|
+
// Render content
|
|
1454
|
+
if (!state.internal.priority && state.gl.render) state.gl.render(state.scene, state.camera);
|
|
1455
|
+
// Decrease frame count
|
|
1545
1456
|
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
1546
1457
|
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
1547
1458
|
}
|
|
1548
|
-
|
|
1549
1459
|
function createLoop(roots) {
|
|
1550
1460
|
let running = false;
|
|
1551
1461
|
let repeat;
|
|
1552
1462
|
let frame;
|
|
1553
1463
|
let state;
|
|
1554
|
-
|
|
1555
1464
|
function loop(timestamp) {
|
|
1556
1465
|
frame = requestAnimationFrame(loop);
|
|
1557
1466
|
running = true;
|
|
1558
|
-
repeat = 0;
|
|
1467
|
+
repeat = 0;
|
|
1559
1468
|
|
|
1560
|
-
|
|
1469
|
+
// Run effects
|
|
1470
|
+
flushGlobalEffects('before', timestamp);
|
|
1561
1471
|
|
|
1472
|
+
// Render all roots
|
|
1562
1473
|
for (const root of roots.values()) {
|
|
1563
1474
|
var _state$gl$xr;
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1475
|
+
state = root.store.getState();
|
|
1476
|
+
// If the frameloop is invalidated, do not run another frame
|
|
1567
1477
|
if (state.internal.active && (state.frameloop === 'always' || state.internal.frames > 0) && !((_state$gl$xr = state.gl.xr) != null && _state$gl$xr.isPresenting)) {
|
|
1568
1478
|
repeat += render$1(timestamp, state);
|
|
1569
1479
|
}
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1480
|
+
}
|
|
1572
1481
|
|
|
1573
|
-
|
|
1482
|
+
// Run after-effects
|
|
1483
|
+
flushGlobalEffects('after', timestamp);
|
|
1574
1484
|
|
|
1485
|
+
// Stop the loop if nothing invalidates it
|
|
1575
1486
|
if (repeat === 0) {
|
|
1576
1487
|
// Tail call effects, they are called when rendering stops
|
|
1577
|
-
flushGlobalEffects('tail', timestamp);
|
|
1488
|
+
flushGlobalEffects('tail', timestamp);
|
|
1578
1489
|
|
|
1490
|
+
// Flag end of operation
|
|
1579
1491
|
running = false;
|
|
1580
1492
|
return cancelAnimationFrame(frame);
|
|
1581
1493
|
}
|
|
1582
1494
|
}
|
|
1583
|
-
|
|
1584
1495
|
function invalidate(state, frames = 1) {
|
|
1585
1496
|
var _state$gl$xr2;
|
|
1586
|
-
|
|
1587
1497
|
if (!state) return roots.forEach(root => invalidate(root.store.getState()), frames);
|
|
1588
|
-
if ((_state$gl$xr2 = state.gl.xr) != null && _state$gl$xr2.isPresenting || !state.internal.active || state.frameloop === 'never') return;
|
|
1589
|
-
|
|
1590
|
-
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
1591
|
-
|
|
1498
|
+
if ((_state$gl$xr2 = state.gl.xr) != null && _state$gl$xr2.isPresenting || !state.internal.active || state.frameloop === 'never') return;
|
|
1499
|
+
// Increase frames, do not go higher than 60
|
|
1500
|
+
state.internal.frames = Math.min(60, state.internal.frames + frames);
|
|
1501
|
+
// If the render-loop isn't active, start it
|
|
1592
1502
|
if (!running) {
|
|
1593
1503
|
running = true;
|
|
1594
1504
|
requestAnimationFrame(loop);
|
|
1595
1505
|
}
|
|
1596
1506
|
}
|
|
1597
|
-
|
|
1598
1507
|
function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
1599
1508
|
if (runGlobalEffects) flushGlobalEffects('before', timestamp);
|
|
1600
1509
|
if (!state) for (const root of roots.values()) render$1(timestamp, root.store.getState());else render$1(timestamp, state, frame);
|
|
1601
1510
|
if (runGlobalEffects) flushGlobalEffects('after', timestamp);
|
|
1602
1511
|
}
|
|
1603
|
-
|
|
1604
1512
|
return {
|
|
1605
1513
|
loop,
|
|
1606
|
-
|
|
1607
1514
|
/**
|
|
1608
1515
|
* Invalidates the view, requesting a frame to be rendered. Will globally invalidate unless passed a root's state.
|
|
1609
1516
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#invalidate
|
|
1610
1517
|
*/
|
|
1611
1518
|
invalidate,
|
|
1612
|
-
|
|
1613
1519
|
/**
|
|
1614
1520
|
* Advances the frameloop and runs render effects, useful for when manually rendering via `frameloop="never"`.
|
|
1615
1521
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#advance
|
|
@@ -1634,80 +1540,77 @@ function useStore() {
|
|
|
1634
1540
|
if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
|
|
1635
1541
|
return store;
|
|
1636
1542
|
}
|
|
1543
|
+
|
|
1637
1544
|
/**
|
|
1638
1545
|
* Accesses R3F's internal state, containing renderer, canvas, scene, etc.
|
|
1639
1546
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usethree
|
|
1640
1547
|
*/
|
|
1641
|
-
|
|
1642
1548
|
function useThree(selector = state => state, equalityFn) {
|
|
1643
1549
|
return useStore()(selector, equalityFn);
|
|
1644
1550
|
}
|
|
1551
|
+
|
|
1645
1552
|
/**
|
|
1646
1553
|
* Executes a callback before render in a shared frame loop.
|
|
1647
1554
|
* Can order effects with render priority or manually render with a positive priority.
|
|
1648
1555
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe
|
|
1649
1556
|
*/
|
|
1650
|
-
|
|
1651
1557
|
function useFrame(callback, renderPriority = 0) {
|
|
1652
1558
|
const store = useStore();
|
|
1653
|
-
const subscribe = store.getState().internal.subscribe;
|
|
1654
|
-
|
|
1655
|
-
const ref = useMutableCallback(callback);
|
|
1656
|
-
|
|
1559
|
+
const subscribe = store.getState().internal.subscribe;
|
|
1560
|
+
// Memoize ref
|
|
1561
|
+
const ref = useMutableCallback(callback);
|
|
1562
|
+
// Subscribe on mount, unsubscribe on unmount
|
|
1657
1563
|
useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
|
|
1658
1564
|
return null;
|
|
1659
1565
|
}
|
|
1566
|
+
|
|
1660
1567
|
/**
|
|
1661
1568
|
* Returns a node graph of an object with named nodes & materials.
|
|
1662
1569
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usegraph
|
|
1663
1570
|
*/
|
|
1664
|
-
|
|
1665
1571
|
function useGraph(object) {
|
|
1666
1572
|
return React.useMemo(() => buildGraph(object), [object]);
|
|
1667
1573
|
}
|
|
1668
|
-
|
|
1669
1574
|
function loadingFn(extensions, onProgress) {
|
|
1670
1575
|
return function (Proto, ...input) {
|
|
1671
1576
|
// Construct new loader and run extensions
|
|
1672
1577
|
const loader = new Proto();
|
|
1673
|
-
if (extensions) extensions(loader);
|
|
1674
|
-
|
|
1578
|
+
if (extensions) extensions(loader);
|
|
1579
|
+
// Go through the urls and load them
|
|
1675
1580
|
return Promise.all(input.map(input => new Promise((res, reject) => loader.load(input, data => {
|
|
1676
1581
|
if (data.scene) Object.assign(data, buildGraph(data.scene));
|
|
1677
1582
|
res(data);
|
|
1678
1583
|
}, onProgress, error => reject(new Error(`Could not load ${input}: ${error.message})`))))));
|
|
1679
1584
|
};
|
|
1680
1585
|
}
|
|
1586
|
+
|
|
1681
1587
|
/**
|
|
1682
1588
|
* Synchronously loads and caches assets with a three loader.
|
|
1683
1589
|
*
|
|
1684
1590
|
* Note: this hook's caller must be wrapped with `React.Suspense`
|
|
1685
1591
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useloader
|
|
1686
1592
|
*/
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
1593
|
function useLoader(Proto, input, extensions, onProgress) {
|
|
1690
1594
|
// Use suspense to load async assets
|
|
1691
1595
|
const keys = Array.isArray(input) ? input : [input];
|
|
1692
1596
|
const results = suspend(loadingFn(extensions, onProgress), [Proto, ...keys], {
|
|
1693
1597
|
equal: is.equ
|
|
1694
|
-
});
|
|
1695
|
-
|
|
1598
|
+
});
|
|
1599
|
+
// Return the object/s
|
|
1696
1600
|
return Array.isArray(input) ? results : results[0];
|
|
1697
1601
|
}
|
|
1602
|
+
|
|
1698
1603
|
/**
|
|
1699
1604
|
* Preloads an asset into cache as a side-effect.
|
|
1700
1605
|
*/
|
|
1701
|
-
|
|
1702
1606
|
useLoader.preload = function (Proto, input, extensions) {
|
|
1703
1607
|
const keys = Array.isArray(input) ? input : [input];
|
|
1704
1608
|
return preload(loadingFn(extensions), [Proto, ...keys]);
|
|
1705
1609
|
};
|
|
1610
|
+
|
|
1706
1611
|
/**
|
|
1707
1612
|
* Removes a loaded asset from cache.
|
|
1708
1613
|
*/
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
1614
|
useLoader.clear = function (Proto, input) {
|
|
1712
1615
|
const keys = Array.isArray(input) ? input : [input];
|
|
1713
1616
|
return clear([Proto, ...keys]);
|
|
@@ -1726,7 +1629,6 @@ const shallowLoose = {
|
|
|
1726
1629
|
objects: 'shallow',
|
|
1727
1630
|
strict: false
|
|
1728
1631
|
};
|
|
1729
|
-
|
|
1730
1632
|
const createRendererInstance = (gl, canvas) => {
|
|
1731
1633
|
const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
|
|
1732
1634
|
if (isRenderer(customRenderer)) return customRenderer;else return new THREE.WebGLRenderer({
|
|
@@ -1737,16 +1639,13 @@ const createRendererInstance = (gl, canvas) => {
|
|
|
1737
1639
|
...gl
|
|
1738
1640
|
});
|
|
1739
1641
|
};
|
|
1740
|
-
|
|
1741
1642
|
function isCanvas(maybeCanvas) {
|
|
1742
1643
|
return maybeCanvas instanceof HTMLCanvasElement;
|
|
1743
1644
|
}
|
|
1744
|
-
|
|
1745
1645
|
function computeInitialSize(canvas, defaultSize) {
|
|
1746
1646
|
if (defaultSize) {
|
|
1747
1647
|
return defaultSize;
|
|
1748
1648
|
}
|
|
1749
|
-
|
|
1750
1649
|
if (isCanvas(canvas) && canvas.parentElement) {
|
|
1751
1650
|
const {
|
|
1752
1651
|
width,
|
|
@@ -1761,7 +1660,6 @@ function computeInitialSize(canvas, defaultSize) {
|
|
|
1761
1660
|
left
|
|
1762
1661
|
};
|
|
1763
1662
|
}
|
|
1764
|
-
|
|
1765
1663
|
return {
|
|
1766
1664
|
width: 0,
|
|
1767
1665
|
height: 0,
|
|
@@ -1769,29 +1667,33 @@ function computeInitialSize(canvas, defaultSize) {
|
|
|
1769
1667
|
left: 0
|
|
1770
1668
|
};
|
|
1771
1669
|
}
|
|
1772
|
-
|
|
1773
1670
|
function createRoot(canvas) {
|
|
1774
1671
|
// Check against mistaken use of createRoot
|
|
1775
1672
|
const prevRoot = roots.get(canvas);
|
|
1776
1673
|
const prevFiber = prevRoot == null ? void 0 : prevRoot.fiber;
|
|
1777
1674
|
const prevStore = prevRoot == null ? void 0 : prevRoot.store;
|
|
1778
|
-
if (prevRoot) console.warn('R3F.createRoot should only be called once!');
|
|
1779
|
-
// https://github.com/pmndrs/react-three-fiber/pull/2261
|
|
1675
|
+
if (prevRoot) console.warn('R3F.createRoot should only be called once!');
|
|
1780
1676
|
|
|
1781
|
-
|
|
1677
|
+
// Report when an error was detected in a previous render
|
|
1678
|
+
// https://github.com/pmndrs/react-three-fiber/pull/2261
|
|
1679
|
+
const logRecoverableError = typeof reportError === 'function' ?
|
|
1680
|
+
// In modern browsers, reportError will dispatch an error event,
|
|
1782
1681
|
// emulating an uncaught JavaScript error.
|
|
1783
|
-
reportError :
|
|
1784
|
-
console.error
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
const
|
|
1789
|
-
|
|
1682
|
+
reportError :
|
|
1683
|
+
// In older browsers and test environments, fallback to console.error.
|
|
1684
|
+
console.error;
|
|
1685
|
+
|
|
1686
|
+
// Create store
|
|
1687
|
+
const store = prevStore || createStore(invalidate, advance);
|
|
1688
|
+
// Create renderer
|
|
1689
|
+
const fiber = prevFiber || reconciler.createContainer(store, ConcurrentRoot, null, false, null, '', logRecoverableError, null);
|
|
1690
|
+
// Map it
|
|
1790
1691
|
if (!prevRoot) roots.set(canvas, {
|
|
1791
1692
|
fiber,
|
|
1792
1693
|
store
|
|
1793
|
-
});
|
|
1694
|
+
});
|
|
1794
1695
|
|
|
1696
|
+
// Locals
|
|
1795
1697
|
let onCreated;
|
|
1796
1698
|
let configured = false;
|
|
1797
1699
|
return {
|
|
@@ -1813,96 +1715,97 @@ function createRoot(canvas) {
|
|
|
1813
1715
|
camera: cameraOptions,
|
|
1814
1716
|
onPointerMissed
|
|
1815
1717
|
} = props;
|
|
1816
|
-
let state = store.getState();
|
|
1718
|
+
let state = store.getState();
|
|
1817
1719
|
|
|
1720
|
+
// Set up renderer (one time only!)
|
|
1818
1721
|
let gl = state.gl;
|
|
1819
1722
|
if (!state.gl) state.set({
|
|
1820
1723
|
gl: gl = createRendererInstance(glConfig, canvas)
|
|
1821
|
-
});
|
|
1724
|
+
});
|
|
1822
1725
|
|
|
1726
|
+
// Set up raycaster (one time only!)
|
|
1823
1727
|
let raycaster = state.raycaster;
|
|
1824
1728
|
if (!raycaster) state.set({
|
|
1825
1729
|
raycaster: raycaster = new THREE.Raycaster()
|
|
1826
|
-
});
|
|
1730
|
+
});
|
|
1827
1731
|
|
|
1732
|
+
// Set raycaster options
|
|
1828
1733
|
const {
|
|
1829
1734
|
params,
|
|
1830
1735
|
...options
|
|
1831
1736
|
} = raycastOptions || {};
|
|
1832
|
-
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
|
|
1737
|
+
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
|
|
1738
|
+
...options
|
|
1833
1739
|
});
|
|
1834
1740
|
if (!is.equ(params, raycaster.params, shallowLoose)) applyProps(raycaster, {
|
|
1835
|
-
params: {
|
|
1741
|
+
params: {
|
|
1742
|
+
...raycaster.params,
|
|
1836
1743
|
...params
|
|
1837
1744
|
}
|
|
1838
|
-
});
|
|
1745
|
+
});
|
|
1839
1746
|
|
|
1747
|
+
// Create default camera (one time only!)
|
|
1840
1748
|
if (!state.camera) {
|
|
1841
1749
|
const isCamera = cameraOptions instanceof THREE.Camera;
|
|
1842
1750
|
const camera = isCamera ? cameraOptions : orthographic ? new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE.PerspectiveCamera(75, 0, 0.1, 1000);
|
|
1843
|
-
|
|
1844
1751
|
if (!isCamera) {
|
|
1845
1752
|
camera.position.z = 5;
|
|
1846
|
-
if (cameraOptions) applyProps(camera, cameraOptions);
|
|
1847
|
-
|
|
1753
|
+
if (cameraOptions) applyProps(camera, cameraOptions);
|
|
1754
|
+
// Always look at center by default
|
|
1848
1755
|
if (!(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
|
|
1849
1756
|
}
|
|
1850
|
-
|
|
1851
1757
|
state.set({
|
|
1852
1758
|
camera
|
|
1853
1759
|
});
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1760
|
+
}
|
|
1856
1761
|
|
|
1762
|
+
// Set up XR (one time only!)
|
|
1857
1763
|
if (!state.xr) {
|
|
1858
1764
|
// Handle frame behavior in WebXR
|
|
1859
1765
|
const handleXRFrame = (timestamp, frame) => {
|
|
1860
1766
|
const state = store.getState();
|
|
1861
1767
|
if (state.frameloop === 'never') return;
|
|
1862
1768
|
advance(timestamp, true, state, frame);
|
|
1863
|
-
};
|
|
1864
|
-
|
|
1769
|
+
};
|
|
1865
1770
|
|
|
1771
|
+
// Toggle render switching on session
|
|
1866
1772
|
const handleSessionChange = () => {
|
|
1867
1773
|
const state = store.getState();
|
|
1868
1774
|
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1869
1775
|
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1870
1776
|
if (!state.gl.xr.isPresenting) invalidate(state);
|
|
1871
|
-
};
|
|
1872
|
-
|
|
1777
|
+
};
|
|
1873
1778
|
|
|
1779
|
+
// WebXR session manager
|
|
1874
1780
|
const xr = {
|
|
1875
1781
|
connect() {
|
|
1876
1782
|
const gl = store.getState().gl;
|
|
1877
1783
|
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1878
1784
|
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1879
1785
|
},
|
|
1880
|
-
|
|
1881
1786
|
disconnect() {
|
|
1882
1787
|
const gl = store.getState().gl;
|
|
1883
1788
|
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1884
1789
|
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1885
1790
|
}
|
|
1791
|
+
};
|
|
1886
1792
|
|
|
1887
|
-
|
|
1888
|
-
|
|
1793
|
+
// Subscribe to WebXR session events
|
|
1889
1794
|
if (gl.xr) xr.connect();
|
|
1890
1795
|
state.set({
|
|
1891
1796
|
xr
|
|
1892
1797
|
});
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1798
|
+
}
|
|
1895
1799
|
|
|
1800
|
+
// Set shadowmap
|
|
1896
1801
|
if (gl.shadowMap) {
|
|
1897
1802
|
const oldEnabled = gl.shadowMap.enabled;
|
|
1898
1803
|
const oldType = gl.shadowMap.type;
|
|
1899
1804
|
gl.shadowMap.enabled = !!shadows;
|
|
1900
|
-
|
|
1901
1805
|
if (is.boo(shadows)) {
|
|
1902
1806
|
gl.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
1903
1807
|
} else if (is.str(shadows)) {
|
|
1904
1808
|
var _types$shadows;
|
|
1905
|
-
|
|
1906
1809
|
const types = {
|
|
1907
1810
|
basic: THREE.BasicShadowMap,
|
|
1908
1811
|
percentage: THREE.PCFShadowMap,
|
|
@@ -1913,21 +1816,20 @@ function createRoot(canvas) {
|
|
|
1913
1816
|
} else if (is.obj(shadows)) {
|
|
1914
1817
|
Object.assign(gl.shadowMap, shadows);
|
|
1915
1818
|
}
|
|
1916
|
-
|
|
1917
1819
|
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
1918
|
-
}
|
|
1919
|
-
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1920
|
-
|
|
1820
|
+
}
|
|
1921
1821
|
|
|
1822
|
+
// Safely set color management if available.
|
|
1823
|
+
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1922
1824
|
if ('ColorManagement' in THREE) {
|
|
1923
1825
|
setDeep(THREE, legacy, ['ColorManagement', 'legacyMode']);
|
|
1924
1826
|
}
|
|
1925
|
-
|
|
1926
1827
|
const outputEncoding = linear ? THREE.LinearEncoding : THREE.sRGBEncoding;
|
|
1927
1828
|
const toneMapping = flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping;
|
|
1928
1829
|
if (gl.outputEncoding !== outputEncoding) gl.outputEncoding = outputEncoding;
|
|
1929
|
-
if (gl.toneMapping !== toneMapping) gl.toneMapping = toneMapping;
|
|
1830
|
+
if (gl.toneMapping !== toneMapping) gl.toneMapping = toneMapping;
|
|
1930
1831
|
|
|
1832
|
+
// Update color management state
|
|
1931
1833
|
if (state.legacy !== legacy) state.set(() => ({
|
|
1932
1834
|
legacy
|
|
1933
1835
|
}));
|
|
@@ -1936,40 +1838,40 @@ function createRoot(canvas) {
|
|
|
1936
1838
|
}));
|
|
1937
1839
|
if (state.flat !== flat) state.set(() => ({
|
|
1938
1840
|
flat
|
|
1939
|
-
}));
|
|
1940
|
-
|
|
1941
|
-
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig); // Store events internally
|
|
1841
|
+
}));
|
|
1942
1842
|
|
|
1843
|
+
// Set gl props
|
|
1844
|
+
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig);
|
|
1845
|
+
// Store events internally
|
|
1943
1846
|
if (events && !state.events.handlers) state.set({
|
|
1944
1847
|
events: events(store)
|
|
1945
|
-
});
|
|
1946
|
-
|
|
1947
|
-
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1948
|
-
|
|
1848
|
+
});
|
|
1849
|
+
// Check pixelratio
|
|
1850
|
+
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1851
|
+
// Check size, allow it to take on container bounds initially
|
|
1949
1852
|
const size = computeInitialSize(canvas, propsSize);
|
|
1950
|
-
|
|
1951
1853
|
if (!is.equ(size, state.size, shallowLoose)) {
|
|
1952
1854
|
state.setSize(size.width, size.height, size.updateStyle, size.top, size.left);
|
|
1953
|
-
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1855
|
+
}
|
|
1856
|
+
// Check frameloop
|
|
1857
|
+
if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
|
|
1858
|
+
// Check pointer missed
|
|
1958
1859
|
if (!state.onPointerMissed) state.set({
|
|
1959
1860
|
onPointerMissed
|
|
1960
|
-
});
|
|
1961
|
-
|
|
1861
|
+
});
|
|
1862
|
+
// Check performance
|
|
1962
1863
|
if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
|
|
1963
|
-
performance: {
|
|
1864
|
+
performance: {
|
|
1865
|
+
...state.performance,
|
|
1964
1866
|
...performance
|
|
1965
1867
|
}
|
|
1966
|
-
}));
|
|
1868
|
+
}));
|
|
1967
1869
|
|
|
1870
|
+
// Set locals
|
|
1968
1871
|
onCreated = onCreatedCallback;
|
|
1969
1872
|
configured = true;
|
|
1970
1873
|
return this;
|
|
1971
1874
|
},
|
|
1972
|
-
|
|
1973
1875
|
render(children) {
|
|
1974
1876
|
// The root has to be configured before it can be rendered
|
|
1975
1877
|
if (!configured) this.configure();
|
|
@@ -1981,21 +1883,17 @@ function createRoot(canvas) {
|
|
|
1981
1883
|
}), fiber, null, () => undefined);
|
|
1982
1884
|
return store;
|
|
1983
1885
|
},
|
|
1984
|
-
|
|
1985
1886
|
unmount() {
|
|
1986
1887
|
unmountComponentAtNode(canvas);
|
|
1987
1888
|
}
|
|
1988
|
-
|
|
1989
1889
|
};
|
|
1990
1890
|
}
|
|
1991
|
-
|
|
1992
1891
|
function render(children, canvas, config) {
|
|
1993
1892
|
console.warn('R3F.render is no longer supported in React 18. Use createRoot instead!');
|
|
1994
1893
|
const root = createRoot(canvas);
|
|
1995
1894
|
root.configure(config);
|
|
1996
1895
|
return root.render(children);
|
|
1997
1896
|
}
|
|
1998
|
-
|
|
1999
1897
|
function Provider({
|
|
2000
1898
|
store,
|
|
2001
1899
|
children,
|
|
@@ -2003,28 +1901,28 @@ function Provider({
|
|
|
2003
1901
|
rootElement
|
|
2004
1902
|
}) {
|
|
2005
1903
|
useIsomorphicLayoutEffect(() => {
|
|
2006
|
-
const state = store.getState();
|
|
2007
|
-
|
|
1904
|
+
const state = store.getState();
|
|
1905
|
+
// Flag the canvas active, rendering will now begin
|
|
2008
1906
|
state.set(state => ({
|
|
2009
|
-
internal: {
|
|
1907
|
+
internal: {
|
|
1908
|
+
...state.internal,
|
|
2010
1909
|
active: true
|
|
2011
1910
|
}
|
|
2012
|
-
}));
|
|
2013
|
-
|
|
2014
|
-
if (onCreated) onCreated(state);
|
|
1911
|
+
}));
|
|
1912
|
+
// Notifiy that init is completed, the scene graph exists, but nothing has yet rendered
|
|
1913
|
+
if (onCreated) onCreated(state);
|
|
1914
|
+
// Connect events to the targets parent, this is done to ensure events are registered on
|
|
2015
1915
|
// a shared target, and not on the canvas itself
|
|
2016
|
-
|
|
2017
|
-
|
|
1916
|
+
if (!store.getState().events.connected) state.events.connect == null ? void 0 : state.events.connect(rootElement);
|
|
1917
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2018
1918
|
}, []);
|
|
2019
1919
|
return /*#__PURE__*/React.createElement(context.Provider, {
|
|
2020
1920
|
value: store
|
|
2021
1921
|
}, children);
|
|
2022
1922
|
}
|
|
2023
|
-
|
|
2024
1923
|
function unmountComponentAtNode(canvas, callback) {
|
|
2025
1924
|
const root = roots.get(canvas);
|
|
2026
1925
|
const fiber = root == null ? void 0 : root.fiber;
|
|
2027
|
-
|
|
2028
1926
|
if (fiber) {
|
|
2029
1927
|
const state = root == null ? void 0 : root.store.getState();
|
|
2030
1928
|
if (state) state.internal.active = false;
|
|
@@ -2033,7 +1931,6 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
2033
1931
|
setTimeout(() => {
|
|
2034
1932
|
try {
|
|
2035
1933
|
var _state$gl, _state$gl$renderLists, _state$gl2, _state$gl3;
|
|
2036
|
-
|
|
2037
1934
|
state.events.disconnect == null ? void 0 : state.events.disconnect();
|
|
2038
1935
|
(_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();
|
|
2039
1936
|
(_state$gl2 = state.gl) == null ? void 0 : _state$gl2.forceContextLoss == null ? void 0 : _state$gl2.forceContextLoss();
|
|
@@ -2049,7 +1946,6 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
2049
1946
|
});
|
|
2050
1947
|
}
|
|
2051
1948
|
}
|
|
2052
|
-
|
|
2053
1949
|
function createPortal(children, container, state) {
|
|
2054
1950
|
return /*#__PURE__*/React.createElement(Portal, {
|
|
2055
1951
|
key: container.uuid,
|
|
@@ -2058,7 +1954,6 @@ function createPortal(children, container, state) {
|
|
|
2058
1954
|
state: state
|
|
2059
1955
|
});
|
|
2060
1956
|
}
|
|
2061
|
-
|
|
2062
1957
|
function Portal({
|
|
2063
1958
|
state = {},
|
|
2064
1959
|
children,
|
|
@@ -2078,30 +1973,33 @@ function Portal({
|
|
|
2078
1973
|
const [raycaster] = React.useState(() => new THREE.Raycaster());
|
|
2079
1974
|
const [pointer] = React.useState(() => new THREE.Vector2());
|
|
2080
1975
|
const inject = React.useCallback((rootState, injectState) => {
|
|
2081
|
-
const intersect = {
|
|
1976
|
+
const intersect = {
|
|
1977
|
+
...rootState
|
|
2082
1978
|
}; // all prev state props
|
|
1979
|
+
|
|
2083
1980
|
// Only the fields of "rootState" that do not differ from injectState
|
|
2084
1981
|
// Some props should be off-limits
|
|
2085
1982
|
// Otherwise filter out the props that are different and let the inject layer take precedence
|
|
2086
|
-
|
|
2087
1983
|
Object.keys(rootState).forEach(key => {
|
|
2088
|
-
if (
|
|
2089
|
-
|
|
2090
|
-
|
|
1984
|
+
if (
|
|
1985
|
+
// Some props should be off-limits
|
|
1986
|
+
privateKeys.includes(key) ||
|
|
1987
|
+
// Otherwise filter out the props that are different and let the inject layer take precedence
|
|
1988
|
+
// Unless the inject layer props is undefined, then we keep the root layer
|
|
1989
|
+
rootState[key] !== injectState[key] && injectState[key]) {
|
|
2091
1990
|
delete intersect[key];
|
|
2092
1991
|
}
|
|
2093
1992
|
});
|
|
2094
1993
|
let viewport = undefined;
|
|
2095
|
-
|
|
2096
1994
|
if (injectState && size) {
|
|
2097
|
-
const camera = injectState.camera;
|
|
2098
|
-
|
|
2099
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new THREE.Vector3(), size);
|
|
2100
|
-
|
|
1995
|
+
const camera = injectState.camera;
|
|
1996
|
+
// Calculate the override viewport, if present
|
|
1997
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new THREE.Vector3(), size);
|
|
1998
|
+
// Update the portal camera, if it differs from the previous layer
|
|
2101
1999
|
if (camera !== rootState.camera) updateCamera(camera, size);
|
|
2102
2000
|
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2001
|
+
return {
|
|
2002
|
+
// The intersect consists of the previous root state
|
|
2105
2003
|
...intersect,
|
|
2106
2004
|
// Portals have their own scene, which forms the root, a raycaster and a pointer
|
|
2107
2005
|
scene: container,
|
|
@@ -2111,14 +2009,17 @@ function Portal({
|
|
|
2111
2009
|
// Their previous root is the layer before it
|
|
2112
2010
|
previousRoot,
|
|
2113
2011
|
// Events, size and viewport can be overridden by the inject layer
|
|
2114
|
-
events: {
|
|
2012
|
+
events: {
|
|
2013
|
+
...rootState.events,
|
|
2115
2014
|
...(injectState == null ? void 0 : injectState.events),
|
|
2116
2015
|
...events
|
|
2117
2016
|
},
|
|
2118
|
-
size: {
|
|
2017
|
+
size: {
|
|
2018
|
+
...rootState.size,
|
|
2119
2019
|
...size
|
|
2120
2020
|
},
|
|
2121
|
-
viewport: {
|
|
2021
|
+
viewport: {
|
|
2022
|
+
...rootState.viewport,
|
|
2122
2023
|
...viewport
|
|
2123
2024
|
},
|
|
2124
2025
|
...rest
|
|
@@ -2127,16 +2028,19 @@ function Portal({
|
|
|
2127
2028
|
const [usePortalStore] = React.useState(() => {
|
|
2128
2029
|
// Create a mirrored store, based on the previous root with a few overrides ...
|
|
2129
2030
|
const previousState = previousRoot.getState();
|
|
2130
|
-
const store = create((set, get) => ({
|
|
2031
|
+
const store = create((set, get) => ({
|
|
2032
|
+
...previousState,
|
|
2131
2033
|
scene: container,
|
|
2132
2034
|
raycaster,
|
|
2133
2035
|
pointer,
|
|
2134
2036
|
mouse: pointer,
|
|
2135
2037
|
previousRoot,
|
|
2136
|
-
events: {
|
|
2038
|
+
events: {
|
|
2039
|
+
...previousState.events,
|
|
2137
2040
|
...events
|
|
2138
2041
|
},
|
|
2139
|
-
size: {
|
|
2042
|
+
size: {
|
|
2043
|
+
...previousState.size,
|
|
2140
2044
|
...size
|
|
2141
2045
|
},
|
|
2142
2046
|
...rest,
|
|
@@ -2144,8 +2048,10 @@ function Portal({
|
|
|
2144
2048
|
set,
|
|
2145
2049
|
get,
|
|
2146
2050
|
// Layers are allowed to override events
|
|
2147
|
-
setEvents: events => set(state => ({
|
|
2148
|
-
|
|
2051
|
+
setEvents: events => set(state => ({
|
|
2052
|
+
...state,
|
|
2053
|
+
events: {
|
|
2054
|
+
...state.events,
|
|
2149
2055
|
...events
|
|
2150
2056
|
}
|
|
2151
2057
|
}))
|
|
@@ -2167,7 +2073,6 @@ function Portal({
|
|
|
2167
2073
|
value: usePortalStore
|
|
2168
2074
|
}, children), usePortalStore, null));
|
|
2169
2075
|
}
|
|
2170
|
-
|
|
2171
2076
|
reconciler.injectIntoDevTools({
|
|
2172
2077
|
bundleType: process.env.NODE_ENV === 'production' ? 0 : 1,
|
|
2173
2078
|
rendererPackageName: '@react-three/fiber',
|