@react-three/fiber 9.0.0-rc.0 → 9.0.0-rc.10
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 +24 -0
- package/dist/declarations/src/core/events.d.ts +1 -0
- package/dist/declarations/src/core/hooks.d.ts +13 -12
- package/dist/declarations/src/core/index.d.ts +1 -1
- package/dist/declarations/src/core/reconciler.d.ts +0 -5
- package/dist/declarations/src/core/renderer.d.ts +5 -3
- package/dist/declarations/src/core/utils.d.ts +80 -31
- package/dist/declarations/src/native/Canvas.d.ts +2 -3
- package/dist/declarations/src/three-types.d.ts +5 -1
- package/dist/declarations/src/web/Canvas.d.ts +3 -4
- package/dist/{events-5a08b43f.esm.js → events-aba3c3d1.esm.js} +972 -979
- package/dist/{events-aef54ace.cjs.prod.js → events-b02714fc.cjs.dev.js} +970 -977
- package/dist/{events-fa0fb3db.cjs.dev.js → events-bd708dc8.cjs.prod.js} +970 -978
- package/dist/react-three-fiber.cjs.dev.js +60 -252
- package/dist/react-three-fiber.cjs.prod.js +60 -252
- package/dist/react-three-fiber.esm.js +59 -251
- package/native/dist/react-three-fiber-native.cjs.dev.js +63 -63
- package/native/dist/react-three-fiber-native.cjs.prod.js +63 -63
- package/native/dist/react-three-fiber-native.esm.js +64 -63
- package/package.json +11 -12
- package/dist/declarations/src/web/use-measure.d.ts +0 -34
|
@@ -1,867 +1,425 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { DefaultEventPriority, ContinuousEventPriority, DiscreteEventPriority, ConcurrentRoot } from 'react-reconciler/constants';
|
|
4
4
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
5
|
+
import Reconciler from 'react-reconciler';
|
|
6
|
+
import { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
|
|
5
7
|
import { suspend, preload, clear } from 'suspend-react';
|
|
6
8
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
7
9
|
import { useFiber, useContextBridge, traverseFiber } from 'its-fine';
|
|
8
|
-
import Reconciler from 'react-reconciler';
|
|
9
|
-
import { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
|
|
10
10
|
|
|
11
11
|
var threeTypes = /*#__PURE__*/Object.freeze({
|
|
12
12
|
__proto__: null
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// https://github.com/microsoft/TypeScript/issues/37079
|
|
23
|
-
|
|
24
|
-
const catalogue = {};
|
|
25
|
-
let i = 0;
|
|
26
|
-
const isConstructor$1 = object => typeof object === 'function';
|
|
27
|
-
function extend(objects) {
|
|
28
|
-
if (isConstructor$1(objects)) {
|
|
29
|
-
const Component = `${i++}`;
|
|
30
|
-
catalogue[Component] = objects;
|
|
31
|
-
return Component;
|
|
32
|
-
} else {
|
|
33
|
-
Object.assign(catalogue, objects);
|
|
34
|
-
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns the instance's initial (outmost) root.
|
|
17
|
+
*/
|
|
18
|
+
function findInitialRoot(instance) {
|
|
19
|
+
let root = instance.root;
|
|
20
|
+
while (root.getState().previousRoot) root = root.getState().previousRoot;
|
|
21
|
+
return root;
|
|
35
22
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Safely flush async effects when testing, simulating a legacy root.
|
|
25
|
+
*/
|
|
26
|
+
const act = React.act;
|
|
27
|
+
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
28
|
+
const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
29
|
+
const isColorRepresentation = value => value != null && (typeof value === 'string' || typeof value === 'number' || value.isColor);
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
/**
|
|
32
|
+
* An SSR-friendly useLayoutEffect.
|
|
33
|
+
*
|
|
34
|
+
* React currently throws a warning when using useLayoutEffect on the server.
|
|
35
|
+
* To get around it, we can conditionally useEffect on the server (no-op) and
|
|
36
|
+
* useLayoutEffect elsewhere.
|
|
37
|
+
*
|
|
38
|
+
* @see https://github.com/facebook/react/issues/14927
|
|
39
|
+
*/
|
|
40
|
+
const useIsomorphicLayoutEffect = /* @__PURE__ */((_window$document, _window$navigator) => typeof window !== 'undefined' && (((_window$document = window.document) == null ? void 0 : _window$document.createElement) || ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.product) === 'ReactNative'))() ? React.useLayoutEffect : React.useEffect;
|
|
41
|
+
function useMutableCallback(fn) {
|
|
42
|
+
const ref = React.useRef(fn);
|
|
43
|
+
useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
|
|
44
|
+
return ref;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Bridges renderer Context and StrictMode from a primary renderer.
|
|
48
|
+
*/
|
|
49
|
+
function useBridge() {
|
|
50
|
+
const fiber = useFiber();
|
|
51
|
+
const ContextBridge = useContextBridge();
|
|
52
|
+
return React.useMemo(() => ({
|
|
53
|
+
children
|
|
54
|
+
}) => {
|
|
55
|
+
const strict = !!traverseFiber(fiber, true, node => node.type === React.StrictMode);
|
|
56
|
+
const Root = strict ? React.StrictMode : React.Fragment;
|
|
57
|
+
return /*#__PURE__*/jsx(Root, {
|
|
58
|
+
children: /*#__PURE__*/jsx(ContextBridge, {
|
|
59
|
+
children: children
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
}, [fiber, ContextBridge]);
|
|
63
|
+
}
|
|
64
|
+
function Block({
|
|
65
|
+
set
|
|
66
|
+
}) {
|
|
67
|
+
useIsomorphicLayoutEffect(() => {
|
|
68
|
+
set(new Promise(() => null));
|
|
69
|
+
return () => set(false);
|
|
70
|
+
}, [set]);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
74
|
+
// NOTE: static members get down-level transpiled to mutations which break tree-shaking
|
|
75
|
+
const ErrorBoundary = /* @__PURE__ */(_ErrorBoundary => (_ErrorBoundary = class ErrorBoundary extends React.Component {
|
|
76
|
+
constructor(...args) {
|
|
77
|
+
super(...args);
|
|
78
|
+
this.state = {
|
|
79
|
+
error: false
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
componentDidCatch(err) {
|
|
83
|
+
this.props.set(err);
|
|
84
|
+
}
|
|
85
|
+
render() {
|
|
86
|
+
return this.state.error ? null : this.props.children;
|
|
87
|
+
}
|
|
88
|
+
}, _ErrorBoundary.getDerivedStateFromError = () => ({
|
|
89
|
+
error: true
|
|
90
|
+
}), _ErrorBoundary))();
|
|
91
|
+
function calculateDpr(dpr) {
|
|
92
|
+
var _window$devicePixelRa;
|
|
93
|
+
// Err on the side of progress by assuming 2x dpr if we can't detect it
|
|
94
|
+
// This will happen in workers where window is defined but dpr isn't.
|
|
95
|
+
const target = typeof window !== 'undefined' ? (_window$devicePixelRa = window.devicePixelRatio) != null ? _window$devicePixelRa : 2 : 1;
|
|
96
|
+
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
49
97
|
}
|
|
50
|
-
function createInstance(type, props, root) {
|
|
51
|
-
var _props$object;
|
|
52
|
-
validateInstance(type, props);
|
|
53
98
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Returns instance root state
|
|
101
|
+
*/
|
|
102
|
+
function getRootState(obj) {
|
|
103
|
+
var _r3f;
|
|
104
|
+
return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
|
|
57
105
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
106
|
+
// A collection of compare functions
|
|
107
|
+
const is = {
|
|
108
|
+
obj: a => a === Object(a) && !is.arr(a) && typeof a !== 'function',
|
|
109
|
+
fun: a => typeof a === 'function',
|
|
110
|
+
str: a => typeof a === 'string',
|
|
111
|
+
num: a => typeof a === 'number',
|
|
112
|
+
boo: a => typeof a === 'boolean',
|
|
113
|
+
und: a => a === void 0,
|
|
114
|
+
nul: a => a === null,
|
|
115
|
+
arr: a => Array.isArray(a),
|
|
116
|
+
equ(a, b, {
|
|
117
|
+
arrays = 'shallow',
|
|
118
|
+
objects = 'reference',
|
|
119
|
+
strict = true
|
|
120
|
+
} = {}) {
|
|
121
|
+
// Wrong type or one of the two undefined, doesn't match
|
|
122
|
+
if (typeof a !== typeof b || !!a !== !!b) return false;
|
|
123
|
+
// Atomic, just compare a against b
|
|
124
|
+
if (is.str(a) || is.num(a) || is.boo(a)) return a === b;
|
|
125
|
+
const isObj = is.obj(a);
|
|
126
|
+
if (isObj && objects === 'reference') return a === b;
|
|
127
|
+
const isArr = is.arr(a);
|
|
128
|
+
if (isArr && arrays === 'reference') return a === b;
|
|
129
|
+
// Array or Object, shallow compare first to see if it's a match
|
|
130
|
+
if ((isArr || isObj) && a === b) return true;
|
|
131
|
+
// Last resort, go through keys
|
|
132
|
+
let i;
|
|
133
|
+
// Check if a has all the keys of b
|
|
134
|
+
for (i in a) if (!(i in b)) return false;
|
|
135
|
+
// Check if values between keys match
|
|
136
|
+
if (isObj && arrays === 'shallow' && objects === 'shallow') {
|
|
137
|
+
for (i in strict ? b : a) if (!is.equ(a[i], b[i], {
|
|
138
|
+
strict,
|
|
139
|
+
objects: 'reference'
|
|
140
|
+
})) return false;
|
|
141
|
+
} else {
|
|
142
|
+
for (i in strict ? b : a) if (a[i] !== b[i]) return false;
|
|
65
143
|
}
|
|
66
|
-
|
|
67
|
-
|
|
144
|
+
// If i is undefined
|
|
145
|
+
if (is.und(i)) {
|
|
146
|
+
// If both arrays are empty we consider them equal
|
|
147
|
+
if (isArr && a.length === 0 && b.length === 0) return true;
|
|
148
|
+
// If both objects are empty we consider them equal
|
|
149
|
+
if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
|
|
150
|
+
// Otherwise match them by value
|
|
151
|
+
if (a !== b) return false;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Collects nodes and materials from a THREE.Object3D
|
|
158
|
+
function buildGraph(object) {
|
|
159
|
+
const data = {
|
|
160
|
+
nodes: {},
|
|
161
|
+
materials: {}
|
|
162
|
+
};
|
|
163
|
+
if (object) {
|
|
164
|
+
object.traverse(obj => {
|
|
165
|
+
if (obj.name) data.nodes[obj.name] = obj;
|
|
166
|
+
if (obj.material && !data.materials[obj.material.name]) data.materials[obj.material.name] = obj.material;
|
|
167
|
+
});
|
|
68
168
|
}
|
|
169
|
+
return data;
|
|
69
170
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
instance.object.visible = true;
|
|
77
|
-
}
|
|
78
|
-
instance.isHidden = false;
|
|
79
|
-
invalidateInstance(instance);
|
|
171
|
+
// Disposes an object and all its properties
|
|
172
|
+
function dispose(obj) {
|
|
173
|
+
if (obj.type !== 'Scene') obj.dispose == null ? void 0 : obj.dispose();
|
|
174
|
+
for (const p in obj) {
|
|
175
|
+
const prop = obj[p];
|
|
176
|
+
if ((prop == null ? void 0 : prop.type) !== 'Scene') prop == null ? void 0 : prop.dispose == null ? void 0 : prop.dispose();
|
|
80
177
|
}
|
|
81
178
|
}
|
|
179
|
+
const REACT_INTERNAL_PROPS = ['children', 'key', 'ref'];
|
|
82
180
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Create & link object on first run
|
|
92
|
-
if (!child.object) {
|
|
93
|
-
var _child$props$object, _child$props$args;
|
|
94
|
-
// Get target from catalogue
|
|
95
|
-
const name = `${child.type[0].toUpperCase()}${child.type.slice(1)}`;
|
|
96
|
-
const target = catalogue[name];
|
|
181
|
+
// Gets only instance props from reconciler fibers
|
|
182
|
+
function getInstanceProps(queue) {
|
|
183
|
+
const props = {};
|
|
184
|
+
for (const key in queue) {
|
|
185
|
+
if (!REACT_INTERNAL_PROPS.includes(key)) props[key] = queue[key];
|
|
186
|
+
}
|
|
187
|
+
return props;
|
|
188
|
+
}
|
|
97
189
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
190
|
+
// Each object in the scene carries a small LocalState descriptor
|
|
191
|
+
function prepare(target, root, type, props) {
|
|
192
|
+
const object = target;
|
|
101
193
|
|
|
102
|
-
|
|
103
|
-
|
|
194
|
+
// Create instance descriptor
|
|
195
|
+
let instance = object == null ? void 0 : object.__r3f;
|
|
196
|
+
if (!instance) {
|
|
197
|
+
instance = {
|
|
198
|
+
root,
|
|
199
|
+
type,
|
|
200
|
+
parent: null,
|
|
201
|
+
children: [],
|
|
202
|
+
props: getInstanceProps(props),
|
|
203
|
+
object,
|
|
204
|
+
eventCount: 0,
|
|
205
|
+
handlers: {},
|
|
206
|
+
isHidden: false
|
|
207
|
+
};
|
|
208
|
+
if (object) object.__r3f = instance;
|
|
104
209
|
}
|
|
210
|
+
return instance;
|
|
211
|
+
}
|
|
212
|
+
function resolve(root, key) {
|
|
213
|
+
var _target;
|
|
214
|
+
let target = root[key];
|
|
215
|
+
if (!key.includes('-')) return {
|
|
216
|
+
root,
|
|
217
|
+
key,
|
|
218
|
+
target
|
|
219
|
+
};
|
|
105
220
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const childIndex = parent.object.children.indexOf(beforeChild == null ? void 0 : beforeChild.object);
|
|
111
|
-
if (beforeChild && childIndex !== -1) {
|
|
112
|
-
child.object.parent = parent.object;
|
|
113
|
-
parent.object.children.splice(childIndex, 0, child.object);
|
|
114
|
-
child.object.dispatchEvent({
|
|
115
|
-
type: 'added'
|
|
116
|
-
});
|
|
117
|
-
parent.object.dispatchEvent({
|
|
118
|
-
type: 'childadded',
|
|
119
|
-
child: child.object
|
|
120
|
-
});
|
|
121
|
-
} else {
|
|
122
|
-
parent.object.add(child.object);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Link subtree
|
|
127
|
-
for (const childInstance of child.children) handleContainerEffects(child, childInstance);
|
|
221
|
+
// Resolve pierced target
|
|
222
|
+
const chain = key.split('-');
|
|
223
|
+
target = chain.reduce((acc, key) => acc[key], root);
|
|
224
|
+
key = chain.pop();
|
|
128
225
|
|
|
129
|
-
//
|
|
130
|
-
|
|
226
|
+
// Switch root if atomic
|
|
227
|
+
if (!((_target = target) != null && _target.set)) root = chain.reduce((acc, key) => acc[key], root);
|
|
228
|
+
return {
|
|
229
|
+
root,
|
|
230
|
+
key,
|
|
231
|
+
target
|
|
232
|
+
};
|
|
131
233
|
}
|
|
132
|
-
function appendChild(parent, child) {
|
|
133
|
-
if (!child) return;
|
|
134
|
-
|
|
135
|
-
// Link instances
|
|
136
|
-
child.parent = parent;
|
|
137
|
-
parent.children.push(child);
|
|
138
234
|
|
|
139
|
-
|
|
140
|
-
|
|
235
|
+
// Checks if a dash-cased string ends with an integer
|
|
236
|
+
const INDEX_REGEX = /-\d+$/;
|
|
237
|
+
function attach(parent, child) {
|
|
238
|
+
if (is.str(child.props.attach)) {
|
|
239
|
+
// If attaching into an array (foo-0), create one
|
|
240
|
+
if (INDEX_REGEX.test(child.props.attach)) {
|
|
241
|
+
const index = child.props.attach.replace(INDEX_REGEX, '');
|
|
242
|
+
const {
|
|
243
|
+
root,
|
|
244
|
+
key
|
|
245
|
+
} = resolve(parent.object, index);
|
|
246
|
+
if (!Array.isArray(root[key])) root[key] = [];
|
|
247
|
+
}
|
|
248
|
+
const {
|
|
249
|
+
root,
|
|
250
|
+
key
|
|
251
|
+
} = resolve(parent.object, child.props.attach);
|
|
252
|
+
child.previousAttach = root[key];
|
|
253
|
+
root[key] = child.object;
|
|
254
|
+
} else if (is.fun(child.props.attach)) {
|
|
255
|
+
child.previousAttach = child.props.attach(parent.object, child.object);
|
|
256
|
+
}
|
|
141
257
|
}
|
|
142
|
-
function
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
258
|
+
function detach(parent, child) {
|
|
259
|
+
if (is.str(child.props.attach)) {
|
|
260
|
+
const {
|
|
261
|
+
root,
|
|
262
|
+
key
|
|
263
|
+
} = resolve(parent.object, child.props.attach);
|
|
264
|
+
const previous = child.previousAttach;
|
|
265
|
+
// When the previous value was undefined, it means the value was never set to begin with
|
|
266
|
+
if (previous === undefined) delete root[key];
|
|
267
|
+
// Otherwise set the previous value
|
|
268
|
+
else root[key] = previous;
|
|
269
|
+
} else {
|
|
270
|
+
child.previousAttach == null ? void 0 : child.previousAttach(parent.object, child.object);
|
|
271
|
+
}
|
|
272
|
+
delete child.previousAttach;
|
|
152
273
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
274
|
+
const RESERVED_PROPS = [...REACT_INTERNAL_PROPS,
|
|
275
|
+
// Instance props
|
|
276
|
+
'args', 'dispose', 'attach', 'object', 'onUpdate',
|
|
277
|
+
// Behavior flags
|
|
278
|
+
'dispose'];
|
|
279
|
+
const MEMOIZED_PROTOTYPES = new Map();
|
|
280
|
+
function getMemoizedPrototype(root) {
|
|
281
|
+
let ctor = MEMOIZED_PROTOTYPES.get(root.constructor);
|
|
282
|
+
try {
|
|
283
|
+
if (!ctor) {
|
|
284
|
+
ctor = new root.constructor();
|
|
285
|
+
MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
|
|
286
|
+
}
|
|
287
|
+
} catch (e) {
|
|
288
|
+
// ...
|
|
167
289
|
}
|
|
290
|
+
return ctor;
|
|
168
291
|
}
|
|
169
|
-
function removeChild(parent, child, dispose) {
|
|
170
|
-
if (!child) return;
|
|
171
292
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
293
|
+
// This function prepares a set of changes to be applied to the instance
|
|
294
|
+
function diffProps(instance, newProps) {
|
|
295
|
+
const changedProps = {};
|
|
176
296
|
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
297
|
+
// Sort through props
|
|
298
|
+
for (const prop in newProps) {
|
|
299
|
+
// Skip reserved keys
|
|
300
|
+
if (RESERVED_PROPS.includes(prop)) continue;
|
|
301
|
+
// Skip if props match
|
|
302
|
+
if (is.equ(newProps[prop], instance.props[prop])) continue;
|
|
184
303
|
|
|
185
|
-
|
|
186
|
-
|
|
304
|
+
// Props changed, add them
|
|
305
|
+
changedProps[prop] = newProps[prop];
|
|
187
306
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
307
|
+
// Reset pierced props
|
|
308
|
+
for (const other in newProps) {
|
|
309
|
+
if (other.startsWith(`${prop}-`)) changedProps[other] = newProps[other];
|
|
310
|
+
}
|
|
192
311
|
}
|
|
193
|
-
child.children.length = 0;
|
|
194
312
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// - cannot be a <primitive object={...} />
|
|
203
|
-
// - cannot be a THREE.Scene, because three has broken its own API
|
|
204
|
-
if (shouldDispose && child.type !== 'primitive' && child.object.type !== 'Scene') {
|
|
205
|
-
disposeOnIdle(child.object);
|
|
206
|
-
}
|
|
313
|
+
// Reset removed props for HMR
|
|
314
|
+
for (const prop in instance.props) {
|
|
315
|
+
if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
|
|
316
|
+
const {
|
|
317
|
+
root,
|
|
318
|
+
key
|
|
319
|
+
} = resolve(instance.object, prop);
|
|
207
320
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
321
|
+
// https://github.com/mrdoob/three.js/issues/21209
|
|
322
|
+
// HMR/fast-refresh relies on the ability to cancel out props, but threejs
|
|
323
|
+
// has no means to do this. Hence we curate a small collection of value-classes
|
|
324
|
+
// with their respective constructor/set arguments
|
|
325
|
+
// For removed props, try to set default values, if possible
|
|
326
|
+
if (root.constructor && root.constructor.length === 0) {
|
|
327
|
+
// create a blank slate of the instance and copy the particular parameter.
|
|
328
|
+
const ctor = getMemoizedPrototype(root);
|
|
329
|
+
if (!is.und(ctor)) changedProps[key] = ctor[key];
|
|
330
|
+
} else {
|
|
331
|
+
// instance does not have constructor, just set it to 0
|
|
332
|
+
changedProps[key] = 0;
|
|
221
333
|
}
|
|
222
334
|
}
|
|
335
|
+
return changedProps;
|
|
223
336
|
}
|
|
224
|
-
const reconstructed = [];
|
|
225
|
-
function swapInstances() {
|
|
226
|
-
// Detach instance
|
|
227
|
-
for (const [instance] of reconstructed) {
|
|
228
|
-
const parent = instance.parent;
|
|
229
|
-
if (parent) {
|
|
230
|
-
if (instance.props.attach) {
|
|
231
|
-
detach(parent, instance);
|
|
232
|
-
} else if (isObject3D(instance.object) && isObject3D(parent.object)) {
|
|
233
|
-
parent.object.remove(instance.object);
|
|
234
|
-
}
|
|
235
|
-
for (const child of instance.children) {
|
|
236
|
-
if (child.props.attach) {
|
|
237
|
-
detach(instance, child);
|
|
238
|
-
} else if (isObject3D(child.object) && isObject3D(instance.object)) {
|
|
239
|
-
instance.object.remove(child.object);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
337
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
338
|
+
// https://github.com/mrdoob/three.js/pull/27042
|
|
339
|
+
// https://github.com/mrdoob/three.js/pull/22748
|
|
340
|
+
const colorMaps = ['map', 'emissiveMap', 'sheenColorMap', 'specularColorMap', 'envMap'];
|
|
341
|
+
const EVENT_REGEX = /^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/;
|
|
342
|
+
// This function applies a set of changes to the instance
|
|
343
|
+
function applyProps(object, props) {
|
|
344
|
+
var _instance$object;
|
|
345
|
+
const instance = object.__r3f;
|
|
346
|
+
const rootState = instance && findInitialRoot(instance).getState();
|
|
347
|
+
const prevHandlers = instance == null ? void 0 : instance.eventCount;
|
|
348
|
+
for (const prop in props) {
|
|
349
|
+
let value = props[prop];
|
|
249
350
|
|
|
250
|
-
//
|
|
251
|
-
if (
|
|
252
|
-
if (instance.type !== 'primitive') disposeOnIdle(instance.object);
|
|
253
|
-
}
|
|
351
|
+
// Don't mutate reserved keys
|
|
352
|
+
if (RESERVED_PROPS.includes(prop)) continue;
|
|
254
353
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// Get target from catalogue
|
|
262
|
-
const name = `${instance.type[0].toUpperCase()}${instance.type.slice(1)}`;
|
|
263
|
-
const target = catalogue[name];
|
|
354
|
+
// Deal with pointer events, including removing them if undefined
|
|
355
|
+
if (instance && EVENT_REGEX.test(prop)) {
|
|
356
|
+
if (typeof value === 'function') instance.handlers[prop] = value;else delete instance.handlers[prop];
|
|
357
|
+
instance.eventCount = Object.keys(instance.handlers).length;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
264
360
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
361
|
+
// Ignore setting undefined props
|
|
362
|
+
// https://github.com/pmndrs/react-three-fiber/issues/274
|
|
363
|
+
if (value === undefined) continue;
|
|
364
|
+
let {
|
|
365
|
+
root,
|
|
366
|
+
key,
|
|
367
|
+
target
|
|
368
|
+
} = resolve(object, prop);
|
|
269
369
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
parent.object.add(instance.object);
|
|
276
|
-
}
|
|
277
|
-
for (const child of instance.children) {
|
|
278
|
-
if (child.props.attach) {
|
|
279
|
-
attach(instance, child);
|
|
280
|
-
} else if (isObject3D(child.object) && isObject3D(instance.object)) {
|
|
281
|
-
instance.object.add(child.object);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Tree was updated, request a frame
|
|
286
|
-
invalidateInstance(instance);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
reconstructed.length = 0;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Don't handle text instances, make it no-op
|
|
293
|
-
const handleTextInstance = () => {};
|
|
294
|
-
const NO_CONTEXT = {};
|
|
295
|
-
let currentUpdatePriority = NoEventPriority;
|
|
296
|
-
|
|
297
|
-
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberFlags.js
|
|
298
|
-
const NoFlags = 0;
|
|
299
|
-
const Update = 4;
|
|
300
|
-
const reconciler = createReconciler({
|
|
301
|
-
isPrimaryRenderer: false,
|
|
302
|
-
warnsIfNotActing: false,
|
|
303
|
-
supportsMutation: true,
|
|
304
|
-
supportsPersistence: false,
|
|
305
|
-
supportsHydration: false,
|
|
306
|
-
createInstance,
|
|
307
|
-
removeChild,
|
|
308
|
-
appendChild,
|
|
309
|
-
appendInitialChild: appendChild,
|
|
310
|
-
insertBefore,
|
|
311
|
-
appendChildToContainer(container, child) {
|
|
312
|
-
const scene = container.getState().scene.__r3f;
|
|
313
|
-
if (!child || !scene) return;
|
|
314
|
-
appendChild(scene, child);
|
|
315
|
-
},
|
|
316
|
-
removeChildFromContainer(container, child) {
|
|
317
|
-
const scene = container.getState().scene.__r3f;
|
|
318
|
-
if (!child || !scene) return;
|
|
319
|
-
removeChild(scene, child);
|
|
320
|
-
},
|
|
321
|
-
insertInContainerBefore(container, child, beforeChild) {
|
|
322
|
-
const scene = container.getState().scene.__r3f;
|
|
323
|
-
if (!child || !beforeChild || !scene) return;
|
|
324
|
-
insertBefore(scene, child, beforeChild);
|
|
325
|
-
},
|
|
326
|
-
getRootHostContext: () => NO_CONTEXT,
|
|
327
|
-
getChildHostContext: () => NO_CONTEXT,
|
|
328
|
-
commitUpdate(instance, type, oldProps, newProps, fiber) {
|
|
329
|
-
var _newProps$args, _oldProps$args, _newProps$args2;
|
|
330
|
-
validateInstance(type, newProps);
|
|
331
|
-
let reconstruct = false;
|
|
332
|
-
|
|
333
|
-
// Reconstruct primitives if object prop changes
|
|
334
|
-
if (instance.type === 'primitive' && oldProps.object !== newProps.object) reconstruct = true;
|
|
335
|
-
// Reconstruct instance if args were added or removed
|
|
336
|
-
else if (((_newProps$args = newProps.args) == null ? void 0 : _newProps$args.length) !== ((_oldProps$args = oldProps.args) == null ? void 0 : _oldProps$args.length)) reconstruct = true;
|
|
337
|
-
// Reconstruct instance if args were changed
|
|
338
|
-
else if ((_newProps$args2 = newProps.args) != null && _newProps$args2.some((value, index) => {
|
|
339
|
-
var _oldProps$args2;
|
|
340
|
-
return value !== ((_oldProps$args2 = oldProps.args) == null ? void 0 : _oldProps$args2[index]);
|
|
341
|
-
})) reconstruct = true;
|
|
342
|
-
|
|
343
|
-
// Reconstruct when args or <primitive object={...} have changes
|
|
344
|
-
if (reconstruct) {
|
|
345
|
-
reconstructed.push([instance, {
|
|
346
|
-
...newProps
|
|
347
|
-
}, fiber]);
|
|
348
|
-
} else {
|
|
349
|
-
// Create a diff-set, flag if there are any changes
|
|
350
|
-
const changedProps = diffProps(instance, newProps);
|
|
351
|
-
if (Object.keys(changedProps).length) {
|
|
352
|
-
Object.assign(instance.props, changedProps);
|
|
353
|
-
applyProps(instance.object, changedProps);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Flush reconstructed siblings when we hit the last updated child in a sequence
|
|
358
|
-
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
359
|
-
if (isTailSibling) swapInstances();
|
|
360
|
-
},
|
|
361
|
-
finalizeInitialChildren: () => false,
|
|
362
|
-
commitMount() {},
|
|
363
|
-
getPublicInstance: instance => instance == null ? void 0 : instance.object,
|
|
364
|
-
prepareForCommit: () => null,
|
|
365
|
-
preparePortalMount: container => prepare(container.getState().scene, container, '', {}),
|
|
366
|
-
resetAfterCommit: () => {},
|
|
367
|
-
shouldSetTextContent: () => false,
|
|
368
|
-
clearContainer: () => false,
|
|
369
|
-
hideInstance,
|
|
370
|
-
unhideInstance,
|
|
371
|
-
createTextInstance: handleTextInstance,
|
|
372
|
-
hideTextInstance: handleTextInstance,
|
|
373
|
-
unhideTextInstance: handleTextInstance,
|
|
374
|
-
scheduleTimeout: typeof setTimeout === 'function' ? setTimeout : undefined,
|
|
375
|
-
cancelTimeout: typeof clearTimeout === 'function' ? clearTimeout : undefined,
|
|
376
|
-
noTimeout: -1,
|
|
377
|
-
getInstanceFromNode: () => null,
|
|
378
|
-
beforeActiveInstanceBlur() {},
|
|
379
|
-
afterActiveInstanceBlur() {},
|
|
380
|
-
detachDeletedInstance() {},
|
|
381
|
-
prepareScopeUpdate() {},
|
|
382
|
-
getInstanceFromScope: () => null,
|
|
383
|
-
shouldAttemptEagerTransition() {
|
|
384
|
-
return false;
|
|
385
|
-
},
|
|
386
|
-
requestPostPaintCallback() {},
|
|
387
|
-
maySuspendCommit() {
|
|
388
|
-
return false;
|
|
389
|
-
},
|
|
390
|
-
preloadInstance() {
|
|
391
|
-
return true; // true indicates already loaded
|
|
392
|
-
},
|
|
393
|
-
startSuspendingCommit() {},
|
|
394
|
-
suspendInstance() {},
|
|
395
|
-
waitForCommitToBeReady() {
|
|
396
|
-
return null;
|
|
397
|
-
},
|
|
398
|
-
NotPendingTransition: null,
|
|
399
|
-
setCurrentUpdatePriority(newPriority) {
|
|
400
|
-
currentUpdatePriority = newPriority;
|
|
401
|
-
},
|
|
402
|
-
getCurrentUpdatePriority() {
|
|
403
|
-
return currentUpdatePriority;
|
|
404
|
-
},
|
|
405
|
-
resolveUpdatePriority() {
|
|
406
|
-
var _window$event;
|
|
407
|
-
if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
|
|
408
|
-
switch (typeof window !== 'undefined' && ((_window$event = window.event) == null ? void 0 : _window$event.type)) {
|
|
409
|
-
case 'click':
|
|
410
|
-
case 'contextmenu':
|
|
411
|
-
case 'dblclick':
|
|
412
|
-
case 'pointercancel':
|
|
413
|
-
case 'pointerdown':
|
|
414
|
-
case 'pointerup':
|
|
415
|
-
return DiscreteEventPriority;
|
|
416
|
-
case 'pointermove':
|
|
417
|
-
case 'pointerout':
|
|
418
|
-
case 'pointerover':
|
|
419
|
-
case 'pointerenter':
|
|
420
|
-
case 'pointerleave':
|
|
421
|
-
case 'wheel':
|
|
422
|
-
return ContinuousEventPriority;
|
|
423
|
-
default:
|
|
424
|
-
return DefaultEventPriority;
|
|
425
|
-
}
|
|
426
|
-
},
|
|
427
|
-
resetFormInstance() {}
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
var _window$document, _window$navigator;
|
|
431
|
-
/**
|
|
432
|
-
* Returns the instance's initial (outmost) root.
|
|
433
|
-
*/
|
|
434
|
-
function findInitialRoot(instance) {
|
|
435
|
-
let root = instance.root;
|
|
436
|
-
while (root.getState().previousRoot) root = root.getState().previousRoot;
|
|
437
|
-
return root;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Returns `true` with correct TS type inference if an object has a configurable color space (since r152).
|
|
442
|
-
*/
|
|
443
|
-
const hasColorSpace = object => 'colorSpace' in object || 'outputColorSpace' in object;
|
|
444
|
-
/**
|
|
445
|
-
* The current THREE.ColorManagement instance, if present.
|
|
446
|
-
*/
|
|
447
|
-
const getColorManagement = () => {
|
|
448
|
-
var _ColorManagement;
|
|
449
|
-
return (_ColorManagement = catalogue.ColorManagement) != null ? _ColorManagement : null;
|
|
450
|
-
};
|
|
451
|
-
/**
|
|
452
|
-
* Safely flush async effects when testing, simulating a legacy root.
|
|
453
|
-
*/
|
|
454
|
-
const act = React.act;
|
|
455
|
-
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
456
|
-
const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* An SSR-friendly useLayoutEffect.
|
|
460
|
-
*
|
|
461
|
-
* React currently throws a warning when using useLayoutEffect on the server.
|
|
462
|
-
* To get around it, we can conditionally useEffect on the server (no-op) and
|
|
463
|
-
* useLayoutEffect elsewhere.
|
|
464
|
-
*
|
|
465
|
-
* @see https://github.com/facebook/react/issues/14927
|
|
466
|
-
*/
|
|
467
|
-
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;
|
|
468
|
-
function useMutableCallback(fn) {
|
|
469
|
-
const ref = React.useRef(fn);
|
|
470
|
-
useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
|
|
471
|
-
return ref;
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Bridges renderer Context and StrictMode from a primary renderer.
|
|
475
|
-
*/
|
|
476
|
-
function useBridge() {
|
|
477
|
-
const fiber = useFiber();
|
|
478
|
-
const ContextBridge = useContextBridge();
|
|
479
|
-
return React.useMemo(() => ({
|
|
480
|
-
children
|
|
481
|
-
}) => {
|
|
482
|
-
const strict = !!traverseFiber(fiber, true, node => node.type === React.StrictMode);
|
|
483
|
-
const Root = strict ? React.StrictMode : React.Fragment;
|
|
484
|
-
return /*#__PURE__*/jsx(Root, {
|
|
485
|
-
children: /*#__PURE__*/jsx(ContextBridge, {
|
|
486
|
-
children: children
|
|
487
|
-
})
|
|
488
|
-
});
|
|
489
|
-
}, [fiber, ContextBridge]);
|
|
490
|
-
}
|
|
491
|
-
function Block({
|
|
492
|
-
set
|
|
493
|
-
}) {
|
|
494
|
-
useIsomorphicLayoutEffect(() => {
|
|
495
|
-
set(new Promise(() => null));
|
|
496
|
-
return () => set(false);
|
|
497
|
-
}, [set]);
|
|
498
|
-
return null;
|
|
499
|
-
}
|
|
500
|
-
class ErrorBoundary extends React.Component {
|
|
501
|
-
constructor(...args) {
|
|
502
|
-
super(...args);
|
|
503
|
-
this.state = {
|
|
504
|
-
error: false
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
componentDidCatch(err) {
|
|
508
|
-
this.props.set(err);
|
|
509
|
-
}
|
|
510
|
-
render() {
|
|
511
|
-
return this.state.error ? null : this.props.children;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
ErrorBoundary.getDerivedStateFromError = () => ({
|
|
515
|
-
error: true
|
|
516
|
-
});
|
|
517
|
-
function calculateDpr(dpr) {
|
|
518
|
-
var _window$devicePixelRa;
|
|
519
|
-
// Err on the side of progress by assuming 2x dpr if we can't detect it
|
|
520
|
-
// This will happen in workers where window is defined but dpr isn't.
|
|
521
|
-
const target = typeof window !== 'undefined' ? (_window$devicePixelRa = window.devicePixelRatio) != null ? _window$devicePixelRa : 2 : 1;
|
|
522
|
-
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Returns instance root state
|
|
527
|
-
*/
|
|
528
|
-
function getRootState(obj) {
|
|
529
|
-
var _r3f;
|
|
530
|
-
return (_r3f = obj.__r3f) == null ? void 0 : _r3f.root.getState();
|
|
531
|
-
}
|
|
532
|
-
// A collection of compare functions
|
|
533
|
-
const is = {
|
|
534
|
-
obj: a => a === Object(a) && !is.arr(a) && typeof a !== 'function',
|
|
535
|
-
fun: a => typeof a === 'function',
|
|
536
|
-
str: a => typeof a === 'string',
|
|
537
|
-
num: a => typeof a === 'number',
|
|
538
|
-
boo: a => typeof a === 'boolean',
|
|
539
|
-
und: a => a === void 0,
|
|
540
|
-
arr: a => Array.isArray(a),
|
|
541
|
-
equ(a, b, {
|
|
542
|
-
arrays = 'shallow',
|
|
543
|
-
objects = 'reference',
|
|
544
|
-
strict = true
|
|
545
|
-
} = {}) {
|
|
546
|
-
// Wrong type or one of the two undefined, doesn't match
|
|
547
|
-
if (typeof a !== typeof b || !!a !== !!b) return false;
|
|
548
|
-
// Atomic, just compare a against b
|
|
549
|
-
if (is.str(a) || is.num(a) || is.boo(a)) return a === b;
|
|
550
|
-
const isObj = is.obj(a);
|
|
551
|
-
if (isObj && objects === 'reference') return a === b;
|
|
552
|
-
const isArr = is.arr(a);
|
|
553
|
-
if (isArr && arrays === 'reference') return a === b;
|
|
554
|
-
// Array or Object, shallow compare first to see if it's a match
|
|
555
|
-
if ((isArr || isObj) && a === b) return true;
|
|
556
|
-
// Last resort, go through keys
|
|
557
|
-
let i;
|
|
558
|
-
// Check if a has all the keys of b
|
|
559
|
-
for (i in a) if (!(i in b)) return false;
|
|
560
|
-
// Check if values between keys match
|
|
561
|
-
if (isObj && arrays === 'shallow' && objects === 'shallow') {
|
|
562
|
-
for (i in strict ? b : a) if (!is.equ(a[i], b[i], {
|
|
563
|
-
strict,
|
|
564
|
-
objects: 'reference'
|
|
565
|
-
})) return false;
|
|
566
|
-
} else {
|
|
567
|
-
for (i in strict ? b : a) if (a[i] !== b[i]) return false;
|
|
568
|
-
}
|
|
569
|
-
// If i is undefined
|
|
570
|
-
if (is.und(i)) {
|
|
571
|
-
// If both arrays are empty we consider them equal
|
|
572
|
-
if (isArr && a.length === 0 && b.length === 0) return true;
|
|
573
|
-
// If both objects are empty we consider them equal
|
|
574
|
-
if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
|
|
575
|
-
// Otherwise match them by value
|
|
576
|
-
if (a !== b) return false;
|
|
577
|
-
}
|
|
578
|
-
return true;
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
// Collects nodes and materials from a THREE.Object3D
|
|
583
|
-
function buildGraph(object) {
|
|
584
|
-
const data = {
|
|
585
|
-
nodes: {},
|
|
586
|
-
materials: {}
|
|
587
|
-
};
|
|
588
|
-
if (object) {
|
|
589
|
-
object.traverse(obj => {
|
|
590
|
-
if (obj.name) data.nodes[obj.name] = obj;
|
|
591
|
-
if (obj.material && !data.materials[obj.material.name]) data.materials[obj.material.name] = obj.material;
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
return data;
|
|
595
|
-
}
|
|
596
|
-
// Disposes an object and all its properties
|
|
597
|
-
function dispose(obj) {
|
|
598
|
-
if (obj.type !== 'Scene') obj.dispose == null ? void 0 : obj.dispose();
|
|
599
|
-
for (const p in obj) {
|
|
600
|
-
const prop = obj[p];
|
|
601
|
-
if ((prop == null ? void 0 : prop.type) !== 'Scene') prop == null ? void 0 : prop.dispose == null ? void 0 : prop.dispose();
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
const REACT_INTERNAL_PROPS = ['children', 'key', 'ref'];
|
|
605
|
-
|
|
606
|
-
// Gets only instance props from reconciler fibers
|
|
607
|
-
function getInstanceProps(queue) {
|
|
608
|
-
const props = {};
|
|
609
|
-
for (const key in queue) {
|
|
610
|
-
if (!REACT_INTERNAL_PROPS.includes(key)) props[key] = queue[key];
|
|
611
|
-
}
|
|
612
|
-
return props;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// Each object in the scene carries a small LocalState descriptor
|
|
616
|
-
function prepare(target, root, type, props) {
|
|
617
|
-
const object = target;
|
|
618
|
-
|
|
619
|
-
// Create instance descriptor
|
|
620
|
-
let instance = object == null ? void 0 : object.__r3f;
|
|
621
|
-
if (!instance) {
|
|
622
|
-
instance = {
|
|
623
|
-
root,
|
|
624
|
-
type,
|
|
625
|
-
parent: null,
|
|
626
|
-
children: [],
|
|
627
|
-
props: getInstanceProps(props),
|
|
628
|
-
object,
|
|
629
|
-
eventCount: 0,
|
|
630
|
-
handlers: {},
|
|
631
|
-
isHidden: false
|
|
632
|
-
};
|
|
633
|
-
if (object) {
|
|
634
|
-
object.__r3f = instance;
|
|
635
|
-
if (type) applyProps(object, instance.props);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
return instance;
|
|
639
|
-
}
|
|
640
|
-
function resolve(root, key) {
|
|
641
|
-
var _target;
|
|
642
|
-
let target = root[key];
|
|
643
|
-
if (!key.includes('-')) return {
|
|
644
|
-
root,
|
|
645
|
-
key,
|
|
646
|
-
target
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
// Resolve pierced target
|
|
650
|
-
const chain = key.split('-');
|
|
651
|
-
target = chain.reduce((acc, key) => acc[key], root);
|
|
652
|
-
key = chain.pop();
|
|
653
|
-
|
|
654
|
-
// Switch root if atomic
|
|
655
|
-
if (!((_target = target) != null && _target.set)) root = chain.reduce((acc, key) => acc[key], root);
|
|
656
|
-
return {
|
|
657
|
-
root,
|
|
658
|
-
key,
|
|
659
|
-
target
|
|
660
|
-
};
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
// Checks if a dash-cased string ends with an integer
|
|
664
|
-
const INDEX_REGEX = /-\d+$/;
|
|
665
|
-
function attach(parent, child) {
|
|
666
|
-
if (is.str(child.props.attach)) {
|
|
667
|
-
// If attaching into an array (foo-0), create one
|
|
668
|
-
if (INDEX_REGEX.test(child.props.attach)) {
|
|
669
|
-
const index = child.props.attach.replace(INDEX_REGEX, '');
|
|
670
|
-
const {
|
|
671
|
-
root,
|
|
672
|
-
key
|
|
673
|
-
} = resolve(parent.object, index);
|
|
674
|
-
if (!Array.isArray(root[key])) root[key] = [];
|
|
675
|
-
}
|
|
676
|
-
const {
|
|
677
|
-
root,
|
|
678
|
-
key
|
|
679
|
-
} = resolve(parent.object, child.props.attach);
|
|
680
|
-
child.previousAttach = root[key];
|
|
681
|
-
root[key] = child.object;
|
|
682
|
-
} else if (is.fun(child.props.attach)) {
|
|
683
|
-
child.previousAttach = child.props.attach(parent.object, child.object);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
function detach(parent, child) {
|
|
687
|
-
if (is.str(child.props.attach)) {
|
|
688
|
-
const {
|
|
689
|
-
root,
|
|
690
|
-
key
|
|
691
|
-
} = resolve(parent.object, child.props.attach);
|
|
692
|
-
const previous = child.previousAttach;
|
|
693
|
-
// When the previous value was undefined, it means the value was never set to begin with
|
|
694
|
-
if (previous === undefined) delete root[key];
|
|
695
|
-
// Otherwise set the previous value
|
|
696
|
-
else root[key] = previous;
|
|
697
|
-
} else {
|
|
698
|
-
child.previousAttach == null ? void 0 : child.previousAttach(parent.object, child.object);
|
|
699
|
-
}
|
|
700
|
-
delete child.previousAttach;
|
|
701
|
-
}
|
|
702
|
-
const RESERVED_PROPS = [...REACT_INTERNAL_PROPS,
|
|
703
|
-
// Instance props
|
|
704
|
-
'args', 'dispose', 'attach', 'object', 'onUpdate',
|
|
705
|
-
// Behavior flags
|
|
706
|
-
'dispose'];
|
|
707
|
-
const MEMOIZED_PROTOTYPES = new Map();
|
|
708
|
-
|
|
709
|
-
// This function prepares a set of changes to be applied to the instance
|
|
710
|
-
function diffProps(instance, newProps) {
|
|
711
|
-
const changedProps = {};
|
|
712
|
-
|
|
713
|
-
// Sort through props
|
|
714
|
-
for (const prop in newProps) {
|
|
715
|
-
// Skip reserved keys
|
|
716
|
-
if (RESERVED_PROPS.includes(prop)) continue;
|
|
717
|
-
// Skip if props match
|
|
718
|
-
if (is.equ(newProps[prop], instance.props[prop])) continue;
|
|
719
|
-
|
|
720
|
-
// Props changed, add them
|
|
721
|
-
changedProps[prop] = newProps[prop];
|
|
722
|
-
|
|
723
|
-
// Reset pierced props
|
|
724
|
-
for (const other in newProps) {
|
|
725
|
-
if (other.startsWith(`${prop}-`)) changedProps[other] = newProps[other];
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
// Reset removed props for HMR
|
|
730
|
-
for (const prop in instance.props) {
|
|
731
|
-
if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
|
|
732
|
-
const {
|
|
733
|
-
root,
|
|
734
|
-
key
|
|
735
|
-
} = resolve(instance.object, prop);
|
|
736
|
-
|
|
737
|
-
// https://github.com/mrdoob/three.js/issues/21209
|
|
738
|
-
// HMR/fast-refresh relies on the ability to cancel out props, but threejs
|
|
739
|
-
// has no means to do this. Hence we curate a small collection of value-classes
|
|
740
|
-
// with their respective constructor/set arguments
|
|
741
|
-
// For removed props, try to set default values, if possible
|
|
742
|
-
if (root.constructor && root.constructor.length === 0) {
|
|
743
|
-
// create a blank slate of the instance and copy the particular parameter.
|
|
744
|
-
let ctor = MEMOIZED_PROTOTYPES.get(root.constructor);
|
|
745
|
-
if (!ctor) {
|
|
746
|
-
ctor = new root.constructor();
|
|
747
|
-
MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
|
|
748
|
-
}
|
|
749
|
-
changedProps[key] = ctor[key];
|
|
750
|
-
} else {
|
|
751
|
-
// instance does not have constructor, just set it to 0
|
|
752
|
-
changedProps[key] = 0;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
return changedProps;
|
|
756
|
-
}
|
|
757
|
-
typeof process !== 'undefined' && process.env.NODE_ENV !== 'production';
|
|
758
|
-
|
|
759
|
-
// const LinearEncoding = 3000
|
|
760
|
-
const sRGBEncoding = 3001;
|
|
761
|
-
const SRGBColorSpace = 'srgb';
|
|
762
|
-
const LinearSRGBColorSpace = 'srgb-linear';
|
|
763
|
-
|
|
764
|
-
// https://github.com/mrdoob/three.js/pull/27042
|
|
765
|
-
// https://github.com/mrdoob/three.js/pull/22748
|
|
766
|
-
const colorMaps = ['map', 'emissiveMap', 'sheenTintMap',
|
|
767
|
-
// <r134
|
|
768
|
-
'sheenColorMap', 'specularTintMap',
|
|
769
|
-
// <r134
|
|
770
|
-
'specularColorMap', 'envMap'];
|
|
771
|
-
const EVENT_REGEX = /^on(Pointer|Click|DoubleClick|ContextMenu|Wheel)/;
|
|
772
|
-
|
|
773
|
-
// This function applies a set of changes to the instance
|
|
774
|
-
function applyProps(object, props) {
|
|
775
|
-
const instance = object.__r3f;
|
|
776
|
-
const rootState = instance && findInitialRoot(instance).getState();
|
|
777
|
-
const prevHandlers = instance == null ? void 0 : instance.eventCount;
|
|
778
|
-
for (const prop in props) {
|
|
779
|
-
let value = props[prop];
|
|
780
|
-
|
|
781
|
-
// Don't mutate reserved keys
|
|
782
|
-
if (RESERVED_PROPS.includes(prop)) continue;
|
|
783
|
-
|
|
784
|
-
// Deal with pointer events, including removing them if undefined
|
|
785
|
-
if (instance && EVENT_REGEX.test(prop)) {
|
|
786
|
-
if (typeof value === 'function') instance.handlers[prop] = value;else delete instance.handlers[prop];
|
|
787
|
-
instance.eventCount = Object.keys(instance.handlers).length;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Ignore setting undefined props
|
|
791
|
-
// https://github.com/pmndrs/react-three-fiber/issues/274
|
|
792
|
-
if (value === undefined) continue;
|
|
793
|
-
let {
|
|
794
|
-
root,
|
|
795
|
-
key,
|
|
796
|
-
target
|
|
797
|
-
} = resolve(object, prop);
|
|
798
|
-
|
|
799
|
-
// Alias (output)encoding => (output)colorSpace (since r152)
|
|
800
|
-
// https://github.com/pmndrs/react-three-fiber/pull/2829
|
|
801
|
-
if (hasColorSpace(root)) {
|
|
802
|
-
if (key === 'encoding') {
|
|
803
|
-
key = 'colorSpace';
|
|
804
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
805
|
-
} else if (key === 'outputEncoding') {
|
|
806
|
-
key = 'outputColorSpace';
|
|
807
|
-
value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
|
|
808
|
-
}
|
|
370
|
+
// Layers must be written to the mask property
|
|
371
|
+
if (target instanceof THREE.Layers && value instanceof THREE.Layers) {
|
|
372
|
+
target.mask = value.mask;
|
|
373
|
+
} else if (target instanceof THREE.Color && isColorRepresentation(value)) {
|
|
374
|
+
target.set(value);
|
|
809
375
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
if (typeof (target == null ? void 0 : target.copy) === 'function' && target.copy === value.copy) {
|
|
376
|
+
// Copy if properties match signatures and implement math interface (likely read-only)
|
|
377
|
+
else if (target && typeof target.set === 'function' && typeof target.copy === 'function' && value != null && value.constructor && target.constructor === value.constructor) {
|
|
813
378
|
target.copy(value);
|
|
814
379
|
}
|
|
815
|
-
// Layers have no copy function, we must therefore copy the mask property
|
|
816
|
-
else if (target instanceof THREE.Layers && value instanceof THREE.Layers) {
|
|
817
|
-
target.mask = value.mask;
|
|
818
|
-
}
|
|
819
380
|
// Set array types
|
|
820
|
-
else if (target
|
|
821
|
-
if (target.fromArray) target.fromArray(value);else target.set(...value);
|
|
381
|
+
else if (target && typeof target.set === 'function' && Array.isArray(value)) {
|
|
382
|
+
if (typeof target.fromArray === 'function') target.fromArray(value);else target.set(...value);
|
|
822
383
|
}
|
|
823
384
|
// Set literal types
|
|
824
|
-
else if (target
|
|
825
|
-
const isColor = target instanceof THREE.Color;
|
|
385
|
+
else if (target && typeof target.set === 'function' && typeof value === 'number') {
|
|
826
386
|
// Allow setting array scalars
|
|
827
|
-
if (
|
|
387
|
+
if (typeof target.setScalar === 'function') target.setScalar(value);
|
|
828
388
|
// Otherwise just set single value
|
|
829
389
|
else target.set(value);
|
|
830
|
-
|
|
831
|
-
// Emulate THREE.ColorManagement for older three.js versions
|
|
832
|
-
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
833
|
-
if (!getColorManagement() && !(rootState != null && rootState.linear) && isColor) target.convertSRGBToLinear();
|
|
834
390
|
}
|
|
835
391
|
// Else, just overwrite the value
|
|
836
392
|
else {
|
|
393
|
+
var _root$key;
|
|
837
394
|
root[key] = value;
|
|
838
395
|
|
|
839
396
|
// Auto-convert sRGB texture parameters for built-in materials
|
|
840
397
|
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
841
398
|
// https://github.com/mrdoob/three.js/pull/25857
|
|
842
|
-
if (rootState && !rootState.linear && colorMaps.includes(key) && root[key]
|
|
399
|
+
if (rootState && !rootState.linear && colorMaps.includes(key) && (_root$key = root[key]) != null && _root$key.isTexture &&
|
|
843
400
|
// sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
844
401
|
root[key].format === THREE.RGBAFormat && root[key].type === THREE.UnsignedByteType) {
|
|
845
402
|
// NOTE: this cannot be set from the renderer (e.g. sRGB source textures rendered to P3)
|
|
846
|
-
|
|
403
|
+
root[key].colorSpace = THREE.SRGBColorSpace;
|
|
847
404
|
}
|
|
848
405
|
}
|
|
849
406
|
}
|
|
850
407
|
|
|
851
408
|
// Register event handlers
|
|
852
|
-
if (instance != null && instance.parent && rootState != null && rootState.internal && instance.object
|
|
409
|
+
if (instance != null && instance.parent && rootState != null && rootState.internal && (_instance$object = instance.object) != null && _instance$object.isObject3D && prevHandlers !== instance.eventCount) {
|
|
410
|
+
const object = instance.object;
|
|
853
411
|
// Pre-emptively remove the instance from the interaction manager
|
|
854
|
-
const index = rootState.internal.interaction.indexOf(
|
|
412
|
+
const index = rootState.internal.interaction.indexOf(object);
|
|
855
413
|
if (index > -1) rootState.internal.interaction.splice(index, 1);
|
|
856
414
|
// Add the instance to the interaction manager only when it has handlers
|
|
857
|
-
if (instance.eventCount &&
|
|
858
|
-
rootState.internal.interaction.push(
|
|
415
|
+
if (instance.eventCount && object.raycast !== null) {
|
|
416
|
+
rootState.internal.interaction.push(object);
|
|
859
417
|
}
|
|
860
418
|
}
|
|
861
419
|
|
|
862
420
|
// Auto-attach geometries and materials
|
|
863
421
|
if (instance && instance.props.attach === undefined) {
|
|
864
|
-
if (instance.object
|
|
422
|
+
if (instance.object.isBufferGeometry) instance.props.attach = 'geometry';else if (instance.object.isMaterial) instance.props.attach = 'material';
|
|
865
423
|
}
|
|
866
424
|
|
|
867
425
|
// Instance was updated, request a frame
|
|
@@ -1033,7 +591,19 @@ function createEvents(store) {
|
|
|
1033
591
|
stopped: false
|
|
1034
592
|
};
|
|
1035
593
|
for (const hit of intersections) {
|
|
1036
|
-
|
|
594
|
+
let state = getRootState(hit.object);
|
|
595
|
+
|
|
596
|
+
// If the object is not managed by R3F, it might be parented to an element which is.
|
|
597
|
+
// Traverse upwards until we find a managed parent and use its state instead.
|
|
598
|
+
if (!state) {
|
|
599
|
+
hit.object.traverseAncestors(obj => {
|
|
600
|
+
const parentState = getRootState(obj);
|
|
601
|
+
if (parentState) {
|
|
602
|
+
state = parentState;
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
}
|
|
1037
607
|
if (state) {
|
|
1038
608
|
const {
|
|
1039
609
|
raycaster,
|
|
@@ -1294,7 +864,7 @@ function createEvents(store) {
|
|
|
1294
864
|
}
|
|
1295
865
|
|
|
1296
866
|
const isRenderer = def => !!(def != null && def.render);
|
|
1297
|
-
const context =
|
|
867
|
+
const context = /* @__PURE__ */React.createContext(null);
|
|
1298
868
|
const createStore = (invalidate, advance) => {
|
|
1299
869
|
const rootStore = createWithEqualityFn((set, get) => {
|
|
1300
870
|
const position = new THREE.Vector3();
|
|
@@ -1308,7 +878,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1308
878
|
left
|
|
1309
879
|
} = size;
|
|
1310
880
|
const aspect = width / height;
|
|
1311
|
-
if (target
|
|
881
|
+
if (target.isVector3) tempTarget.copy(target);else tempTarget.set(...target);
|
|
1312
882
|
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
1313
883
|
if (isOrthographicCamera(camera)) {
|
|
1314
884
|
return {
|
|
@@ -1510,161 +1080,576 @@ const createStore = (invalidate, advance) => {
|
|
|
1510
1080
|
oldDpr = viewport.dpr;
|
|
1511
1081
|
// Update camera & renderer
|
|
1512
1082
|
updateCamera(camera, size);
|
|
1513
|
-
gl.setPixelRatio(viewport.dpr);
|
|
1083
|
+
if (viewport.dpr > 0) gl.setPixelRatio(viewport.dpr);
|
|
1514
1084
|
const updateStyle = typeof HTMLCanvasElement !== 'undefined' && gl.domElement instanceof HTMLCanvasElement;
|
|
1515
1085
|
gl.setSize(size.width, size.height, updateStyle);
|
|
1516
1086
|
}
|
|
1517
1087
|
|
|
1518
|
-
// Update viewport once the camera changes
|
|
1519
|
-
if (camera !== oldCamera) {
|
|
1520
|
-
oldCamera = camera;
|
|
1521
|
-
// Update viewport
|
|
1522
|
-
set(state => ({
|
|
1523
|
-
viewport: {
|
|
1524
|
-
...state.viewport,
|
|
1525
|
-
...state.viewport.getCurrentViewport(camera)
|
|
1526
|
-
}
|
|
1527
|
-
}));
|
|
1088
|
+
// Update viewport once the camera changes
|
|
1089
|
+
if (camera !== oldCamera) {
|
|
1090
|
+
oldCamera = camera;
|
|
1091
|
+
// Update viewport
|
|
1092
|
+
set(state => ({
|
|
1093
|
+
viewport: {
|
|
1094
|
+
...state.viewport,
|
|
1095
|
+
...state.viewport.getCurrentViewport(camera)
|
|
1096
|
+
}
|
|
1097
|
+
}));
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
// Invalidate on any change
|
|
1102
|
+
rootStore.subscribe(state => invalidate(state));
|
|
1103
|
+
|
|
1104
|
+
// Return root state
|
|
1105
|
+
return rootStore;
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Exposes an object's {@link Instance}.
|
|
1110
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#useInstanceHandle
|
|
1111
|
+
*
|
|
1112
|
+
* **Note**: this is an escape hatch to react-internal fields. Expect this to change significantly between versions.
|
|
1113
|
+
*/
|
|
1114
|
+
function useInstanceHandle(ref) {
|
|
1115
|
+
const instance = React.useRef(null);
|
|
1116
|
+
React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
|
|
1117
|
+
return instance;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Returns the R3F Canvas' Zustand store. Useful for [transient updates](https://github.com/pmndrs/zustand#transient-updates-for-often-occurring-state-changes).
|
|
1122
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usestore
|
|
1123
|
+
*/
|
|
1124
|
+
function useStore() {
|
|
1125
|
+
const store = React.useContext(context);
|
|
1126
|
+
if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
|
|
1127
|
+
return store;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
/**
|
|
1131
|
+
* Accesses R3F's internal state, containing renderer, canvas, scene, etc.
|
|
1132
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usethree
|
|
1133
|
+
*/
|
|
1134
|
+
function useThree(selector = state => state, equalityFn) {
|
|
1135
|
+
return useStore()(selector, equalityFn);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Executes a callback before render in a shared frame loop.
|
|
1140
|
+
* Can order effects with render priority or manually render with a positive priority.
|
|
1141
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe
|
|
1142
|
+
*/
|
|
1143
|
+
function useFrame(callback, renderPriority = 0) {
|
|
1144
|
+
const store = useStore();
|
|
1145
|
+
const subscribe = store.getState().internal.subscribe;
|
|
1146
|
+
// Memoize ref
|
|
1147
|
+
const ref = useMutableCallback(callback);
|
|
1148
|
+
// Subscribe on mount, unsubscribe on unmount
|
|
1149
|
+
useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Returns a node graph of an object with named nodes & materials.
|
|
1155
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usegraph
|
|
1156
|
+
*/
|
|
1157
|
+
function useGraph(object) {
|
|
1158
|
+
return React.useMemo(() => buildGraph(object), [object]);
|
|
1159
|
+
}
|
|
1160
|
+
const memoizedLoaders = new WeakMap();
|
|
1161
|
+
const isConstructor$1 = value => {
|
|
1162
|
+
var _value$prototype;
|
|
1163
|
+
return typeof value === 'function' && (value == null ? void 0 : (_value$prototype = value.prototype) == null ? void 0 : _value$prototype.constructor) === value;
|
|
1164
|
+
};
|
|
1165
|
+
function loadingFn(extensions, onProgress) {
|
|
1166
|
+
return function (Proto, ...input) {
|
|
1167
|
+
let loader;
|
|
1168
|
+
|
|
1169
|
+
// Construct and cache loader if constructor was passed
|
|
1170
|
+
if (isConstructor$1(Proto)) {
|
|
1171
|
+
loader = memoizedLoaders.get(Proto);
|
|
1172
|
+
if (!loader) {
|
|
1173
|
+
loader = new Proto();
|
|
1174
|
+
memoizedLoaders.set(Proto, loader);
|
|
1175
|
+
}
|
|
1176
|
+
} else {
|
|
1177
|
+
loader = Proto;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// Apply loader extensions
|
|
1181
|
+
if (extensions) extensions(loader);
|
|
1182
|
+
|
|
1183
|
+
// Go through the urls and load them
|
|
1184
|
+
return Promise.all(input.map(input => new Promise((res, reject) => loader.load(input, data => {
|
|
1185
|
+
if (isObject3D(data == null ? void 0 : data.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1186
|
+
res(data);
|
|
1187
|
+
}, onProgress, error => reject(new Error(`Could not load ${input}: ${error == null ? void 0 : error.message}`))))));
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Synchronously loads and caches assets with a three loader.
|
|
1193
|
+
*
|
|
1194
|
+
* Note: this hook's caller must be wrapped with `React.Suspense`
|
|
1195
|
+
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useloader
|
|
1196
|
+
*/
|
|
1197
|
+
function useLoader(loader, input, extensions, onProgress) {
|
|
1198
|
+
// Use suspense to load async assets
|
|
1199
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
1200
|
+
const results = suspend(loadingFn(extensions, onProgress), [loader, ...keys], {
|
|
1201
|
+
equal: is.equ
|
|
1202
|
+
});
|
|
1203
|
+
// Return the object(s)
|
|
1204
|
+
return Array.isArray(input) ? results : results[0];
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Preloads an asset into cache as a side-effect.
|
|
1209
|
+
*/
|
|
1210
|
+
useLoader.preload = function (loader, input, extensions) {
|
|
1211
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
1212
|
+
return preload(loadingFn(extensions), [loader, ...keys]);
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Removes a loaded asset from cache.
|
|
1217
|
+
*/
|
|
1218
|
+
useLoader.clear = function (loader, input) {
|
|
1219
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
1220
|
+
return clear([loader, ...keys]);
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
// TODO: upstream to DefinitelyTyped for React 19
|
|
1224
|
+
// https://github.com/facebook/react/issues/28956
|
|
1225
|
+
|
|
1226
|
+
function createReconciler(config) {
|
|
1227
|
+
const reconciler = Reconciler(config);
|
|
1228
|
+
reconciler.injectIntoDevTools({
|
|
1229
|
+
bundleType: typeof process !== 'undefined' && process.env.NODE_ENV !== 'production' ? 1 : 0,
|
|
1230
|
+
rendererPackageName: '@react-three/fiber',
|
|
1231
|
+
version: React.version
|
|
1232
|
+
});
|
|
1233
|
+
return reconciler;
|
|
1234
|
+
}
|
|
1235
|
+
const NoEventPriority = 0;
|
|
1236
|
+
|
|
1237
|
+
// TODO: handle constructor overloads
|
|
1238
|
+
// https://github.com/pmndrs/react-three-fiber/pull/2931
|
|
1239
|
+
// https://github.com/microsoft/TypeScript/issues/37079
|
|
1240
|
+
|
|
1241
|
+
const catalogue = {};
|
|
1242
|
+
const PREFIX_REGEX = /^three(?=[A-Z])/;
|
|
1243
|
+
const toPascalCase = type => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
1244
|
+
let i = 0;
|
|
1245
|
+
const isConstructor = object => typeof object === 'function';
|
|
1246
|
+
function extend(objects) {
|
|
1247
|
+
if (isConstructor(objects)) {
|
|
1248
|
+
const Component = `${i++}`;
|
|
1249
|
+
catalogue[Component] = objects;
|
|
1250
|
+
return Component;
|
|
1251
|
+
} else {
|
|
1252
|
+
Object.assign(catalogue, objects);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
function validateInstance(type, props) {
|
|
1256
|
+
// Get target from catalogue
|
|
1257
|
+
const name = `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
1258
|
+
const target = catalogue[name];
|
|
1259
|
+
|
|
1260
|
+
// Validate element target
|
|
1261
|
+
if (type !== 'primitive' && !target) 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`);
|
|
1262
|
+
|
|
1263
|
+
// Validate primitives
|
|
1264
|
+
if (type === 'primitive' && !props.object) throw new Error(`R3F: Primitives without 'object' are invalid!`);
|
|
1265
|
+
|
|
1266
|
+
// Throw if an object or literal was passed for args
|
|
1267
|
+
if (props.args !== undefined && !Array.isArray(props.args)) throw new Error('R3F: The args prop must be an array!');
|
|
1268
|
+
}
|
|
1269
|
+
function createInstance(type, props, root) {
|
|
1270
|
+
var _props$object;
|
|
1271
|
+
// Remove three* prefix from elements
|
|
1272
|
+
type = type.replace(PREFIX_REGEX, '');
|
|
1273
|
+
validateInstance(type, props);
|
|
1274
|
+
|
|
1275
|
+
// Regenerate the R3F instance for primitives to simulate a new object
|
|
1276
|
+
if (type === 'primitive' && (_props$object = props.object) != null && _props$object.__r3f) delete props.object.__r3f;
|
|
1277
|
+
return prepare(props.object, root, type, props);
|
|
1278
|
+
}
|
|
1279
|
+
function hideInstance(instance) {
|
|
1280
|
+
if (!instance.isHidden) {
|
|
1281
|
+
var _instance$parent;
|
|
1282
|
+
if (instance.props.attach && (_instance$parent = instance.parent) != null && _instance$parent.object) {
|
|
1283
|
+
detach(instance.parent, instance);
|
|
1284
|
+
} else if (isObject3D(instance.object)) {
|
|
1285
|
+
instance.object.visible = false;
|
|
1528
1286
|
}
|
|
1529
|
-
|
|
1287
|
+
instance.isHidden = true;
|
|
1288
|
+
invalidateInstance(instance);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
function unhideInstance(instance) {
|
|
1292
|
+
if (instance.isHidden) {
|
|
1293
|
+
var _instance$parent2;
|
|
1294
|
+
if (instance.props.attach && (_instance$parent2 = instance.parent) != null && _instance$parent2.object) {
|
|
1295
|
+
attach(instance.parent, instance);
|
|
1296
|
+
} else if (isObject3D(instance.object) && instance.props.visible !== false) {
|
|
1297
|
+
instance.object.visible = true;
|
|
1298
|
+
}
|
|
1299
|
+
instance.isHidden = false;
|
|
1300
|
+
invalidateInstance(instance);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1530
1303
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1304
|
+
// https://github.com/facebook/react/issues/20271
|
|
1305
|
+
// This will make sure events and attach are only handled once when trees are complete
|
|
1306
|
+
function handleContainerEffects(parent, child, beforeChild) {
|
|
1307
|
+
// Bail if tree isn't mounted or parent is not a container.
|
|
1308
|
+
// This ensures that the tree is finalized and React won't discard results to Suspense
|
|
1309
|
+
const state = child.root.getState();
|
|
1310
|
+
if (!parent.parent && parent.object !== state.scene) return;
|
|
1533
1311
|
|
|
1534
|
-
//
|
|
1535
|
-
|
|
1536
|
-
|
|
1312
|
+
// Create & link object on first run
|
|
1313
|
+
if (!child.object) {
|
|
1314
|
+
var _child$props$object, _child$props$args;
|
|
1315
|
+
// Get target from catalogue
|
|
1316
|
+
const target = catalogue[toPascalCase(child.type)];
|
|
1537
1317
|
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1318
|
+
// Create object
|
|
1319
|
+
child.object = (_child$props$object = child.props.object) != null ? _child$props$object : new target(...((_child$props$args = child.props.args) != null ? _child$props$args : []));
|
|
1320
|
+
child.object.__r3f = child;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// Set initial props
|
|
1324
|
+
applyProps(child.object, child.props);
|
|
1325
|
+
|
|
1326
|
+
// Append instance
|
|
1327
|
+
if (child.props.attach) {
|
|
1328
|
+
attach(parent, child);
|
|
1329
|
+
} else if (isObject3D(child.object) && isObject3D(parent.object)) {
|
|
1330
|
+
const childIndex = parent.object.children.indexOf(beforeChild == null ? void 0 : beforeChild.object);
|
|
1331
|
+
if (beforeChild && childIndex !== -1) {
|
|
1332
|
+
child.object.parent = parent.object;
|
|
1333
|
+
parent.object.children.splice(childIndex, 0, child.object);
|
|
1334
|
+
child.object.dispatchEvent({
|
|
1335
|
+
type: 'added'
|
|
1336
|
+
});
|
|
1337
|
+
parent.object.dispatchEvent({
|
|
1338
|
+
type: 'childadded',
|
|
1339
|
+
child: child.object
|
|
1340
|
+
});
|
|
1341
|
+
} else {
|
|
1342
|
+
parent.object.add(child.object);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
// Link subtree
|
|
1347
|
+
for (const childInstance of child.children) handleContainerEffects(child, childInstance);
|
|
1348
|
+
|
|
1349
|
+
// Tree was updated, request a frame
|
|
1350
|
+
invalidateInstance(child);
|
|
1548
1351
|
}
|
|
1352
|
+
function appendChild(parent, child) {
|
|
1353
|
+
if (!child) return;
|
|
1549
1354
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
if (!store) throw new Error('R3F: Hooks can only be used within the Canvas component!');
|
|
1557
|
-
return store;
|
|
1355
|
+
// Link instances
|
|
1356
|
+
child.parent = parent;
|
|
1357
|
+
parent.children.push(child);
|
|
1358
|
+
|
|
1359
|
+
// Attach tree once complete
|
|
1360
|
+
handleContainerEffects(parent, child);
|
|
1558
1361
|
}
|
|
1362
|
+
function insertBefore(parent, child, beforeChild) {
|
|
1363
|
+
if (!child || !beforeChild) return;
|
|
1559
1364
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1365
|
+
// Link instances
|
|
1366
|
+
child.parent = parent;
|
|
1367
|
+
const childIndex = parent.children.indexOf(beforeChild);
|
|
1368
|
+
if (childIndex !== -1) parent.children.splice(childIndex, 0, child);else parent.children.push(child);
|
|
1369
|
+
|
|
1370
|
+
// Attach tree once complete
|
|
1371
|
+
handleContainerEffects(parent, child, beforeChild);
|
|
1566
1372
|
}
|
|
1373
|
+
function disposeOnIdle(object) {
|
|
1374
|
+
if (typeof object.dispose === 'function') {
|
|
1375
|
+
const handleDispose = () => {
|
|
1376
|
+
try {
|
|
1377
|
+
object.dispose();
|
|
1378
|
+
} catch {
|
|
1379
|
+
// no-op
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1567
1382
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
function useFrame(callback, renderPriority = 0) {
|
|
1574
|
-
const store = useStore();
|
|
1575
|
-
const subscribe = store.getState().internal.subscribe;
|
|
1576
|
-
// Memoize ref
|
|
1577
|
-
const ref = useMutableCallback(callback);
|
|
1578
|
-
// Subscribe on mount, unsubscribe on unmount
|
|
1579
|
-
useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
|
|
1580
|
-
return null;
|
|
1383
|
+
// In a testing environment, cleanup immediately
|
|
1384
|
+
if (typeof IS_REACT_ACT_ENVIRONMENT !== 'undefined') handleDispose();
|
|
1385
|
+
// Otherwise, using a real GPU so schedule cleanup to prevent stalls
|
|
1386
|
+
else unstable_scheduleCallback(unstable_IdlePriority, handleDispose);
|
|
1387
|
+
}
|
|
1581
1388
|
}
|
|
1389
|
+
function removeChild(parent, child, dispose) {
|
|
1390
|
+
if (!child) return;
|
|
1582
1391
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1392
|
+
// Unlink instances
|
|
1393
|
+
child.parent = null;
|
|
1394
|
+
const childIndex = parent.children.indexOf(child);
|
|
1395
|
+
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
1396
|
+
|
|
1397
|
+
// Eagerly tear down tree
|
|
1398
|
+
if (child.props.attach) {
|
|
1399
|
+
detach(parent, child);
|
|
1400
|
+
} else if (isObject3D(child.object) && isObject3D(parent.object)) {
|
|
1401
|
+
parent.object.remove(child.object);
|
|
1402
|
+
removeInteractivity(findInitialRoot(child), child.object);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// Allow objects to bail out of unmount disposal with dispose={null}
|
|
1406
|
+
const shouldDispose = child.props.dispose !== null && dispose !== false;
|
|
1407
|
+
|
|
1408
|
+
// Recursively remove instance children
|
|
1409
|
+
for (let i = child.children.length - 1; i >= 0; i--) {
|
|
1410
|
+
const node = child.children[i];
|
|
1411
|
+
removeChild(child, node, shouldDispose);
|
|
1412
|
+
}
|
|
1413
|
+
child.children.length = 0;
|
|
1414
|
+
|
|
1415
|
+
// Unlink instance object
|
|
1416
|
+
delete child.object.__r3f;
|
|
1417
|
+
|
|
1418
|
+
// Dispose object whenever the reconciler feels like it.
|
|
1419
|
+
// Never dispose of primitives because their state may be kept outside of React!
|
|
1420
|
+
// In order for an object to be able to dispose it
|
|
1421
|
+
// - has a dispose method
|
|
1422
|
+
// - cannot be a <primitive object={...} />
|
|
1423
|
+
// - cannot be a THREE.Scene, because three has broken its own API
|
|
1424
|
+
if (shouldDispose && child.type !== 'primitive' && child.object.type !== 'Scene') {
|
|
1425
|
+
disposeOnIdle(child.object);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// Tree was updated, request a frame for top-level instance
|
|
1429
|
+
if (dispose === undefined) invalidateInstance(child);
|
|
1589
1430
|
}
|
|
1590
|
-
|
|
1591
|
-
const
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1431
|
+
function setFiberRef(fiber, publicInstance) {
|
|
1432
|
+
for (const _fiber of [fiber, fiber.alternate]) {
|
|
1433
|
+
if (_fiber !== null) {
|
|
1434
|
+
if (typeof _fiber.ref === 'function') {
|
|
1435
|
+
_fiber.refCleanup == null ? void 0 : _fiber.refCleanup();
|
|
1436
|
+
const cleanup = _fiber.ref(publicInstance);
|
|
1437
|
+
if (typeof cleanup === 'function') _fiber.refCleanup = cleanup;
|
|
1438
|
+
} else if (_fiber.ref) {
|
|
1439
|
+
_fiber.ref.current = publicInstance;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
const reconstructed = [];
|
|
1445
|
+
function swapInstances() {
|
|
1446
|
+
// Detach instance
|
|
1447
|
+
for (const [instance] of reconstructed) {
|
|
1448
|
+
const parent = instance.parent;
|
|
1449
|
+
if (parent) {
|
|
1450
|
+
if (instance.props.attach) {
|
|
1451
|
+
detach(parent, instance);
|
|
1452
|
+
} else if (isObject3D(instance.object) && isObject3D(parent.object)) {
|
|
1453
|
+
parent.object.remove(instance.object);
|
|
1454
|
+
}
|
|
1455
|
+
for (const child of instance.children) {
|
|
1456
|
+
if (child.props.attach) {
|
|
1457
|
+
detach(instance, child);
|
|
1458
|
+
} else if (isObject3D(child.object) && isObject3D(instance.object)) {
|
|
1459
|
+
instance.object.remove(child.object);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
// If the old instance is hidden, we need to unhide it.
|
|
1465
|
+
// React assumes it can discard instances since they're pure for DOM.
|
|
1466
|
+
// This isn't true for us since our lifetimes are impure and longliving.
|
|
1467
|
+
// So, we manually check if an instance was hidden and unhide it.
|
|
1468
|
+
if (instance.isHidden) unhideInstance(instance);
|
|
1469
|
+
|
|
1470
|
+
// Dispose of old object if able
|
|
1471
|
+
if (instance.object.__r3f) delete instance.object.__r3f;
|
|
1472
|
+
if (instance.type !== 'primitive') disposeOnIdle(instance.object);
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// Update instance
|
|
1476
|
+
for (const [instance, props, fiber] of reconstructed) {
|
|
1477
|
+
instance.props = props;
|
|
1478
|
+
const parent = instance.parent;
|
|
1479
|
+
if (parent) {
|
|
1480
|
+
var _instance$props$objec, _instance$props$args;
|
|
1481
|
+
// Get target from catalogue
|
|
1482
|
+
const target = catalogue[toPascalCase(instance.type)];
|
|
1483
|
+
|
|
1484
|
+
// Create object
|
|
1485
|
+
instance.object = (_instance$props$objec = instance.props.object) != null ? _instance$props$objec : new target(...((_instance$props$args = instance.props.args) != null ? _instance$props$args : []));
|
|
1486
|
+
instance.object.__r3f = instance;
|
|
1487
|
+
setFiberRef(fiber, instance.object);
|
|
1598
1488
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1489
|
+
// Set initial props
|
|
1490
|
+
applyProps(instance.object, instance.props);
|
|
1491
|
+
if (instance.props.attach) {
|
|
1492
|
+
attach(parent, instance);
|
|
1493
|
+
} else if (isObject3D(instance.object) && isObject3D(parent.object)) {
|
|
1494
|
+
parent.object.add(instance.object);
|
|
1605
1495
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1496
|
+
for (const child of instance.children) {
|
|
1497
|
+
if (child.props.attach) {
|
|
1498
|
+
attach(instance, child);
|
|
1499
|
+
} else if (isObject3D(child.object) && isObject3D(instance.object)) {
|
|
1500
|
+
instance.object.add(child.object);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// Tree was updated, request a frame
|
|
1505
|
+
invalidateInstance(instance);
|
|
1608
1506
|
}
|
|
1507
|
+
}
|
|
1508
|
+
reconstructed.length = 0;
|
|
1509
|
+
}
|
|
1609
1510
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1511
|
+
// Don't handle text instances, make it no-op
|
|
1512
|
+
const handleTextInstance = () => {};
|
|
1513
|
+
const NO_CONTEXT = {};
|
|
1514
|
+
let currentUpdatePriority = NoEventPriority;
|
|
1612
1515
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1516
|
+
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberFlags.js
|
|
1517
|
+
const NoFlags = 0;
|
|
1518
|
+
const Update = 4;
|
|
1519
|
+
const reconciler = /* @__PURE__ */createReconciler({
|
|
1520
|
+
isPrimaryRenderer: false,
|
|
1521
|
+
warnsIfNotActing: false,
|
|
1522
|
+
supportsMutation: true,
|
|
1523
|
+
supportsPersistence: false,
|
|
1524
|
+
supportsHydration: false,
|
|
1525
|
+
createInstance,
|
|
1526
|
+
removeChild,
|
|
1527
|
+
appendChild,
|
|
1528
|
+
appendInitialChild: appendChild,
|
|
1529
|
+
insertBefore,
|
|
1530
|
+
appendChildToContainer(container, child) {
|
|
1531
|
+
const scene = container.getState().scene.__r3f;
|
|
1532
|
+
if (!child || !scene) return;
|
|
1533
|
+
appendChild(scene, child);
|
|
1534
|
+
},
|
|
1535
|
+
removeChildFromContainer(container, child) {
|
|
1536
|
+
const scene = container.getState().scene.__r3f;
|
|
1537
|
+
if (!child || !scene) return;
|
|
1538
|
+
removeChild(scene, child);
|
|
1539
|
+
},
|
|
1540
|
+
insertInContainerBefore(container, child, beforeChild) {
|
|
1541
|
+
const scene = container.getState().scene.__r3f;
|
|
1542
|
+
if (!child || !beforeChild || !scene) return;
|
|
1543
|
+
insertBefore(scene, child, beforeChild);
|
|
1544
|
+
},
|
|
1545
|
+
getRootHostContext: () => NO_CONTEXT,
|
|
1546
|
+
getChildHostContext: () => NO_CONTEXT,
|
|
1547
|
+
commitUpdate(instance, type, oldProps, newProps, fiber) {
|
|
1548
|
+
var _newProps$args, _oldProps$args, _newProps$args2;
|
|
1549
|
+
validateInstance(type, newProps);
|
|
1550
|
+
let reconstruct = false;
|
|
1617
1551
|
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
const results = suspend(loadingFn(extensions, onProgress), [loader, ...keys], {
|
|
1628
|
-
equal: is.equ
|
|
1629
|
-
});
|
|
1630
|
-
// Return the object(s)
|
|
1631
|
-
return Array.isArray(input) ? results : results[0];
|
|
1632
|
-
}
|
|
1552
|
+
// Reconstruct primitives if object prop changes
|
|
1553
|
+
if (instance.type === 'primitive' && oldProps.object !== newProps.object) reconstruct = true;
|
|
1554
|
+
// Reconstruct instance if args were added or removed
|
|
1555
|
+
else if (((_newProps$args = newProps.args) == null ? void 0 : _newProps$args.length) !== ((_oldProps$args = oldProps.args) == null ? void 0 : _oldProps$args.length)) reconstruct = true;
|
|
1556
|
+
// Reconstruct instance if args were changed
|
|
1557
|
+
else if ((_newProps$args2 = newProps.args) != null && _newProps$args2.some((value, index) => {
|
|
1558
|
+
var _oldProps$args2;
|
|
1559
|
+
return value !== ((_oldProps$args2 = oldProps.args) == null ? void 0 : _oldProps$args2[index]);
|
|
1560
|
+
})) reconstruct = true;
|
|
1633
1561
|
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1562
|
+
// Reconstruct when args or <primitive object={...} have changes
|
|
1563
|
+
if (reconstruct) {
|
|
1564
|
+
reconstructed.push([instance, {
|
|
1565
|
+
...newProps
|
|
1566
|
+
}, fiber]);
|
|
1567
|
+
} else {
|
|
1568
|
+
// Create a diff-set, flag if there are any changes
|
|
1569
|
+
const changedProps = diffProps(instance, newProps);
|
|
1570
|
+
if (Object.keys(changedProps).length) {
|
|
1571
|
+
Object.assign(instance.props, changedProps);
|
|
1572
|
+
applyProps(instance.object, changedProps);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1641
1575
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1576
|
+
// Flush reconstructed siblings when we hit the last updated child in a sequence
|
|
1577
|
+
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
1578
|
+
if (isTailSibling) swapInstances();
|
|
1579
|
+
},
|
|
1580
|
+
finalizeInitialChildren: () => false,
|
|
1581
|
+
commitMount() {},
|
|
1582
|
+
getPublicInstance: instance => instance == null ? void 0 : instance.object,
|
|
1583
|
+
prepareForCommit: () => null,
|
|
1584
|
+
preparePortalMount: container => prepare(container.getState().scene, container, '', {}),
|
|
1585
|
+
resetAfterCommit: () => {},
|
|
1586
|
+
shouldSetTextContent: () => false,
|
|
1587
|
+
clearContainer: () => false,
|
|
1588
|
+
hideInstance,
|
|
1589
|
+
unhideInstance,
|
|
1590
|
+
createTextInstance: handleTextInstance,
|
|
1591
|
+
hideTextInstance: handleTextInstance,
|
|
1592
|
+
unhideTextInstance: handleTextInstance,
|
|
1593
|
+
scheduleTimeout: typeof setTimeout === 'function' ? setTimeout : undefined,
|
|
1594
|
+
cancelTimeout: typeof clearTimeout === 'function' ? clearTimeout : undefined,
|
|
1595
|
+
noTimeout: -1,
|
|
1596
|
+
getInstanceFromNode: () => null,
|
|
1597
|
+
beforeActiveInstanceBlur() {},
|
|
1598
|
+
afterActiveInstanceBlur() {},
|
|
1599
|
+
detachDeletedInstance() {},
|
|
1600
|
+
prepareScopeUpdate() {},
|
|
1601
|
+
getInstanceFromScope: () => null,
|
|
1602
|
+
shouldAttemptEagerTransition: () => false,
|
|
1603
|
+
trackSchedulerEvent: () => {},
|
|
1604
|
+
resolveEventType: () => null,
|
|
1605
|
+
resolveEventTimeStamp: () => -1.1,
|
|
1606
|
+
requestPostPaintCallback() {},
|
|
1607
|
+
maySuspendCommit: () => false,
|
|
1608
|
+
preloadInstance: () => true,
|
|
1609
|
+
// true indicates already loaded
|
|
1610
|
+
startSuspendingCommit() {},
|
|
1611
|
+
suspendInstance() {},
|
|
1612
|
+
waitForCommitToBeReady: () => null,
|
|
1613
|
+
NotPendingTransition: null,
|
|
1614
|
+
HostTransitionContext: /* @__PURE__ */React.createContext(null),
|
|
1615
|
+
setCurrentUpdatePriority(newPriority) {
|
|
1616
|
+
currentUpdatePriority = newPriority;
|
|
1617
|
+
},
|
|
1618
|
+
getCurrentUpdatePriority() {
|
|
1619
|
+
return currentUpdatePriority;
|
|
1620
|
+
},
|
|
1621
|
+
resolveUpdatePriority() {
|
|
1622
|
+
var _window$event;
|
|
1623
|
+
if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
|
|
1624
|
+
switch (typeof window !== 'undefined' && ((_window$event = window.event) == null ? void 0 : _window$event.type)) {
|
|
1625
|
+
case 'click':
|
|
1626
|
+
case 'contextmenu':
|
|
1627
|
+
case 'dblclick':
|
|
1628
|
+
case 'pointercancel':
|
|
1629
|
+
case 'pointerdown':
|
|
1630
|
+
case 'pointerup':
|
|
1631
|
+
return DiscreteEventPriority;
|
|
1632
|
+
case 'pointermove':
|
|
1633
|
+
case 'pointerout':
|
|
1634
|
+
case 'pointerover':
|
|
1635
|
+
case 'pointerenter':
|
|
1636
|
+
case 'pointerleave':
|
|
1637
|
+
case 'wheel':
|
|
1638
|
+
return ContinuousEventPriority;
|
|
1639
|
+
default:
|
|
1640
|
+
return DefaultEventPriority;
|
|
1641
|
+
}
|
|
1642
|
+
},
|
|
1643
|
+
resetFormInstance() {}
|
|
1644
|
+
});
|
|
1649
1645
|
|
|
1650
1646
|
const _roots = new Map();
|
|
1651
1647
|
const shallowLoose = {
|
|
1652
1648
|
objects: 'shallow',
|
|
1653
1649
|
strict: false
|
|
1654
1650
|
};
|
|
1655
|
-
const createRendererInstance = (gl, canvas) => {
|
|
1656
|
-
const customRenderer = typeof gl === 'function' ? gl(canvas) : gl;
|
|
1657
|
-
if (isRenderer(customRenderer)) return customRenderer;
|
|
1658
|
-
return new THREE.WebGLRenderer({
|
|
1659
|
-
powerPreference: 'high-performance',
|
|
1660
|
-
canvas: canvas,
|
|
1661
|
-
antialias: true,
|
|
1662
|
-
alpha: true,
|
|
1663
|
-
...gl
|
|
1664
|
-
});
|
|
1665
|
-
};
|
|
1666
1651
|
function computeInitialSize(canvas, size) {
|
|
1667
|
-
if (!size && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1652
|
+
if (!size && typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1668
1653
|
const {
|
|
1669
1654
|
width,
|
|
1670
1655
|
height,
|
|
@@ -1740,10 +1725,13 @@ function createRoot(canvas) {
|
|
|
1740
1725
|
|
|
1741
1726
|
// Locals
|
|
1742
1727
|
let onCreated;
|
|
1743
|
-
let configured = false;
|
|
1744
1728
|
let lastCamera;
|
|
1729
|
+
let configured = false;
|
|
1730
|
+
let pending = null;
|
|
1745
1731
|
return {
|
|
1746
|
-
configure(props = {}) {
|
|
1732
|
+
async configure(props = {}) {
|
|
1733
|
+
let resolve;
|
|
1734
|
+
pending = new Promise(_resolve => resolve = _resolve);
|
|
1747
1735
|
let {
|
|
1748
1736
|
gl: glConfig,
|
|
1749
1737
|
size: propsSize,
|
|
@@ -1766,9 +1754,26 @@ function createRoot(canvas) {
|
|
|
1766
1754
|
|
|
1767
1755
|
// Set up renderer (one time only!)
|
|
1768
1756
|
let gl = state.gl;
|
|
1769
|
-
if (!state.gl)
|
|
1770
|
-
|
|
1771
|
-
|
|
1757
|
+
if (!state.gl) {
|
|
1758
|
+
const defaultProps = {
|
|
1759
|
+
canvas: canvas,
|
|
1760
|
+
powerPreference: 'high-performance',
|
|
1761
|
+
antialias: true,
|
|
1762
|
+
alpha: true
|
|
1763
|
+
};
|
|
1764
|
+
const customRenderer = typeof glConfig === 'function' ? await glConfig(defaultProps) : glConfig;
|
|
1765
|
+
if (isRenderer(customRenderer)) {
|
|
1766
|
+
gl = customRenderer;
|
|
1767
|
+
} else {
|
|
1768
|
+
gl = new THREE.WebGLRenderer({
|
|
1769
|
+
...defaultProps,
|
|
1770
|
+
...glConfig
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
state.set({
|
|
1774
|
+
gl
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1772
1777
|
|
|
1773
1778
|
// Set up raycaster (one time only!)
|
|
1774
1779
|
let raycaster = state.raycaster;
|
|
@@ -1794,7 +1799,7 @@ function createRoot(canvas) {
|
|
|
1794
1799
|
// Create default camera, don't overwrite any user-set state
|
|
1795
1800
|
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
1796
1801
|
lastCamera = cameraOptions;
|
|
1797
|
-
const isCamera = cameraOptions
|
|
1802
|
+
const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
|
|
1798
1803
|
const camera = isCamera ? cameraOptions : orthographic ? new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE.PerspectiveCamera(75, 0, 0.1, 1000);
|
|
1799
1804
|
if (!isCamera) {
|
|
1800
1805
|
camera.position.z = 5;
|
|
@@ -1824,7 +1829,7 @@ function createRoot(canvas) {
|
|
|
1824
1829
|
// Set up scene (one time only!)
|
|
1825
1830
|
if (!state.scene) {
|
|
1826
1831
|
let scene;
|
|
1827
|
-
if (sceneOptions
|
|
1832
|
+
if (sceneOptions != null && sceneOptions.isScene) {
|
|
1828
1833
|
scene = sceneOptions;
|
|
1829
1834
|
prepare(scene, store, '', {});
|
|
1830
1835
|
} else {
|
|
@@ -1837,8 +1842,34 @@ function createRoot(canvas) {
|
|
|
1837
1842
|
});
|
|
1838
1843
|
}
|
|
1839
1844
|
|
|
1845
|
+
// Store events internally
|
|
1846
|
+
if (events && !state.events.handlers) state.set({
|
|
1847
|
+
events: events(store)
|
|
1848
|
+
});
|
|
1849
|
+
// Check size, allow it to take on container bounds initially
|
|
1850
|
+
const size = computeInitialSize(canvas, propsSize);
|
|
1851
|
+
if (!is.equ(size, state.size, shallowLoose)) {
|
|
1852
|
+
state.setSize(size.width, size.height, size.top, size.left);
|
|
1853
|
+
}
|
|
1854
|
+
// Check pixelratio
|
|
1855
|
+
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1856
|
+
// Check frameloop
|
|
1857
|
+
if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
|
|
1858
|
+
// Check pointer missed
|
|
1859
|
+
if (!state.onPointerMissed) state.set({
|
|
1860
|
+
onPointerMissed
|
|
1861
|
+
});
|
|
1862
|
+
// Check performance
|
|
1863
|
+
if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
|
|
1864
|
+
performance: {
|
|
1865
|
+
...state.performance,
|
|
1866
|
+
...performance
|
|
1867
|
+
}
|
|
1868
|
+
}));
|
|
1869
|
+
|
|
1840
1870
|
// Set up XR (one time only!)
|
|
1841
1871
|
if (!state.xr) {
|
|
1872
|
+
var _gl$xr;
|
|
1842
1873
|
// Handle frame behavior in WebXR
|
|
1843
1874
|
const handleXRFrame = (timestamp, frame) => {
|
|
1844
1875
|
const state = store.getState();
|
|
@@ -1869,7 +1900,7 @@ function createRoot(canvas) {
|
|
|
1869
1900
|
};
|
|
1870
1901
|
|
|
1871
1902
|
// Subscribe to WebXR session events
|
|
1872
|
-
if (gl.xr) xr.connect();
|
|
1903
|
+
if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
|
|
1873
1904
|
state.set({
|
|
1874
1905
|
xr
|
|
1875
1906
|
});
|
|
@@ -1896,22 +1927,12 @@ function createRoot(canvas) {
|
|
|
1896
1927
|
}
|
|
1897
1928
|
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
1898
1929
|
}
|
|
1899
|
-
|
|
1900
|
-
// Safely set color management if available.
|
|
1901
|
-
// Avoid accessing THREE.ColorManagement to play nice with older versions
|
|
1902
|
-
const ColorManagement = getColorManagement();
|
|
1903
|
-
if (ColorManagement) {
|
|
1904
|
-
if ('enabled' in ColorManagement) ColorManagement.enabled = !legacy;else if ('legacyMode' in ColorManagement) ColorManagement.legacyMode = legacy;
|
|
1905
|
-
}
|
|
1930
|
+
THREE.ColorManagement.enabled = !legacy;
|
|
1906
1931
|
|
|
1907
1932
|
// Set color space and tonemapping preferences
|
|
1908
1933
|
if (!configured) {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
applyProps(gl, {
|
|
1912
|
-
outputEncoding: linear ? LinearEncoding : sRGBEncoding,
|
|
1913
|
-
toneMapping: flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping
|
|
1914
|
-
});
|
|
1934
|
+
gl.outputColorSpace = linear ? THREE.LinearSRGBColorSpace : THREE.SRGBColorSpace;
|
|
1935
|
+
gl.toneMapping = flat ? THREE.NoToneMapping : THREE.ACESFilmicToneMapping;
|
|
1915
1936
|
}
|
|
1916
1937
|
|
|
1917
1938
|
// Update color management state
|
|
@@ -1927,45 +1948,24 @@ function createRoot(canvas) {
|
|
|
1927
1948
|
|
|
1928
1949
|
// Set gl props
|
|
1929
1950
|
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig);
|
|
1930
|
-
// Store events internally
|
|
1931
|
-
if (events && !state.events.handlers) state.set({
|
|
1932
|
-
events: events(store)
|
|
1933
|
-
});
|
|
1934
|
-
// Check size, allow it to take on container bounds initially
|
|
1935
|
-
const size = computeInitialSize(canvas, propsSize);
|
|
1936
|
-
if (!is.equ(size, state.size, shallowLoose)) {
|
|
1937
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
1938
|
-
}
|
|
1939
|
-
// Check pixelratio
|
|
1940
|
-
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1941
|
-
// Check frameloop
|
|
1942
|
-
if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
|
|
1943
|
-
// Check pointer missed
|
|
1944
|
-
if (!state.onPointerMissed) state.set({
|
|
1945
|
-
onPointerMissed
|
|
1946
|
-
});
|
|
1947
|
-
// Check performance
|
|
1948
|
-
if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
|
|
1949
|
-
performance: {
|
|
1950
|
-
...state.performance,
|
|
1951
|
-
...performance
|
|
1952
|
-
}
|
|
1953
|
-
}));
|
|
1954
1951
|
|
|
1955
1952
|
// Set locals
|
|
1956
1953
|
onCreated = onCreatedCallback;
|
|
1957
1954
|
configured = true;
|
|
1955
|
+
resolve();
|
|
1958
1956
|
return this;
|
|
1959
1957
|
},
|
|
1960
1958
|
render(children) {
|
|
1961
1959
|
// The root has to be configured before it can be rendered
|
|
1962
|
-
if (!configured) this.configure();
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1960
|
+
if (!configured && !pending) this.configure();
|
|
1961
|
+
pending.then(() => {
|
|
1962
|
+
reconciler.updateContainer( /*#__PURE__*/jsx(Provider, {
|
|
1963
|
+
store: store,
|
|
1964
|
+
children: children,
|
|
1965
|
+
onCreated: onCreated,
|
|
1966
|
+
rootElement: canvas
|
|
1967
|
+
}), fiber, null, () => undefined);
|
|
1968
|
+
});
|
|
1969
1969
|
return store;
|
|
1970
1970
|
},
|
|
1971
1971
|
unmount() {
|
|
@@ -1973,12 +1973,6 @@ function createRoot(canvas) {
|
|
|
1973
1973
|
}
|
|
1974
1974
|
};
|
|
1975
1975
|
}
|
|
1976
|
-
function render(children, canvas, config) {
|
|
1977
|
-
console.warn('R3F.render is no longer supported in React 18. Use createRoot instead!');
|
|
1978
|
-
const root = createRoot(canvas);
|
|
1979
|
-
root.configure(config);
|
|
1980
|
-
return root.render(children);
|
|
1981
|
-
}
|
|
1982
1976
|
function Provider({
|
|
1983
1977
|
store,
|
|
1984
1978
|
children,
|
|
@@ -2116,18 +2110,17 @@ function Portal({
|
|
|
2116
2110
|
return store;
|
|
2117
2111
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2118
2112
|
}, [previousRoot, container]);
|
|
2119
|
-
return
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2113
|
+
return (
|
|
2114
|
+
/*#__PURE__*/
|
|
2115
|
+
// @ts-ignore, reconciler types are not maintained
|
|
2116
|
+
jsx(Fragment, {
|
|
2117
|
+
children: reconciler.createPortal( /*#__PURE__*/jsx(context.Provider, {
|
|
2118
|
+
value: usePortalStore,
|
|
2119
|
+
children: children
|
|
2120
|
+
}), usePortalStore, null)
|
|
2121
|
+
})
|
|
2122
|
+
);
|
|
2125
2123
|
}
|
|
2126
|
-
reconciler.injectIntoDevTools({
|
|
2127
|
-
bundleType: process.env.NODE_ENV === 'production' ? 0 : 1,
|
|
2128
|
-
rendererPackageName: '@react-three/fiber',
|
|
2129
|
-
version: React.version
|
|
2130
|
-
});
|
|
2131
2124
|
|
|
2132
2125
|
function createSubs(callback, subs) {
|
|
2133
2126
|
const sub = {
|
|
@@ -2226,7 +2219,7 @@ function loop(timestamp) {
|
|
|
2226
2219
|
repeat += update(timestamp, state);
|
|
2227
2220
|
}
|
|
2228
2221
|
}
|
|
2229
|
-
useFrameInProgress =
|
|
2222
|
+
useFrameInProgress = false;
|
|
2230
2223
|
|
|
2231
2224
|
// Run after-effects
|
|
2232
2225
|
flushGlobalEffects('after', timestamp);
|
|
@@ -2367,4 +2360,4 @@ function createPointerEvents(store) {
|
|
|
2367
2360
|
};
|
|
2368
2361
|
}
|
|
2369
2362
|
|
|
2370
|
-
export {
|
|
2363
|
+
export { useThree as A, Block as B, useFrame as C, useGraph as D, ErrorBoundary as E, useLoader as F, _roots as _, useMutableCallback as a, useIsomorphicLayoutEffect as b, createRoot as c, unmountComponentAtNode as d, extend as e, createPointerEvents as f, createEvents as g, flushGlobalEffects as h, isRef as i, addEffect as j, addAfterEffect as k, addTail as l, invalidate as m, advance as n, createPortal as o, context as p, applyProps as q, reconciler as r, getRootState as s, threeTypes as t, useBridge as u, dispose as v, act as w, buildGraph as x, useInstanceHandle as y, useStore as z };
|