@react-three/fiber 9.8.0 → 9.8.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 +36 -0
- package/dist/declarations/src/core/configuration.d.ts +91 -0
- package/dist/declarations/src/core/extend.d.ts +12 -0
- package/dist/declarations/src/core/hooks.d.ts +2 -1
- package/dist/declarations/src/core/index.d.ts +10 -5
- package/dist/declarations/src/core/portal.d.ts +13 -0
- package/dist/declarations/src/core/reconciler.d.ts +11 -17
- package/dist/declarations/src/core/renderer.d.ts +8 -90
- package/dist/declarations/src/core/root.d.ts +37 -0
- package/dist/declarations/src/core/store.d.ts +1 -1
- package/dist/declarations/src/core/{promise.d.ts → utils/promise.d.ts} +7 -3
- package/dist/declarations/src/core/utils/react.d.ts +184 -0
- package/dist/declarations/src/core/utils.d.ts +9 -184
- package/dist/declarations/src/three-types.d.ts +1 -1
- package/dist/{events-ce5e34e8.cjs.dev.js → events-0dab3c53.cjs.dev.js} +800 -520
- package/dist/{events-a79ef12b.cjs.prod.js → events-98e95d43.cjs.prod.js} +801 -521
- package/dist/{events-803f4abc.esm.js → events-e51d7528.esm.js} +801 -521
- package/dist/react-three-fiber.cjs.dev.js +21 -4
- package/dist/react-three-fiber.cjs.prod.js +21 -4
- package/dist/react-three-fiber.esm.js +22 -5
- package/native/dist/react-three-fiber-native.cjs.dev.js +4 -3
- package/native/dist/react-three-fiber-native.cjs.prod.js +4 -3
- package/native/dist/react-three-fiber-native.esm.js +5 -4
- package/package.json +8 -2
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
var THREE = require('three');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
6
|
var traditional = require('zustand/traditional');
|
|
6
7
|
var suspendReact = require('suspend-react');
|
|
7
|
-
var w1 = require('scheduler');
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
9
8
|
var itsFine = require('its-fine');
|
|
9
|
+
var w1 = require('scheduler');
|
|
10
10
|
|
|
11
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
12
12
|
|
|
@@ -36,14 +36,6 @@ var threeTypes = /*#__PURE__*/Object.freeze({
|
|
|
36
36
|
__proto__: null
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
/**
|
|
40
|
-
* Returns the instance's initial (outmost) root.
|
|
41
|
-
*/
|
|
42
|
-
function findInitialRoot(instance) {
|
|
43
|
-
let root = instance.root;
|
|
44
|
-
while (root.getState().previousRoot) root = root.getState().previousRoot;
|
|
45
|
-
return root;
|
|
46
|
-
}
|
|
47
39
|
/**
|
|
48
40
|
* Safely flush async effects when testing, simulating a legacy root.
|
|
49
41
|
* @deprecated Import from React instead. import { act } from 'react'
|
|
@@ -51,9 +43,6 @@ function findInitialRoot(instance) {
|
|
|
51
43
|
// Reference with computed key to break Webpack static analysis
|
|
52
44
|
// https://github.com/webpack/webpack/issues/14814
|
|
53
45
|
const act = React__namespace['act' + ''];
|
|
54
|
-
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
55
|
-
const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
56
|
-
const isColorRepresentation = value => value != null && (typeof value === 'string' || typeof value === 'number' || value.isColor);
|
|
57
46
|
|
|
58
47
|
/**
|
|
59
48
|
* An SSR-friendly useLayoutEffect.
|
|
@@ -70,7 +59,6 @@ function useMutableCallback(fn) {
|
|
|
70
59
|
useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
|
|
71
60
|
return ref;
|
|
72
61
|
}
|
|
73
|
-
const noop = () => {};
|
|
74
62
|
function Gate({
|
|
75
63
|
promise,
|
|
76
64
|
onSettled
|
|
@@ -85,7 +73,7 @@ function useGate() {
|
|
|
85
73
|
const [promise, setPromise] = React__namespace.useState(null);
|
|
86
74
|
const onSettled = React__namespace.useCallback(() => setPromise(null), []);
|
|
87
75
|
// Keep the first promise, or a repeated call would loop
|
|
88
|
-
const waitFor = React__namespace.useCallback(next => setPromise(current => current != null ? current : Promise.resolve(next).then(
|
|
76
|
+
const waitFor = React__namespace.useCallback(next => setPromise(current => current != null ? current : Promise.resolve(next).then(() => {}, () => {})), []);
|
|
89
77
|
const gate = promise ? /*#__PURE__*/jsxRuntime.jsx(React__namespace.Suspense, {
|
|
90
78
|
fallback: null,
|
|
91
79
|
children: /*#__PURE__*/jsxRuntime.jsx(Gate, {
|
|
@@ -95,23 +83,29 @@ function useGate() {
|
|
|
95
83
|
}) : null;
|
|
96
84
|
return [gate, waitFor];
|
|
97
85
|
}
|
|
86
|
+
|
|
87
|
+
// Activity is optional on React 19.0/19.1. A computed key also supports strict ESM bundlers.
|
|
88
|
+
const useActivityBridge = React__namespace['Activity' + ''] ? itsFine.useActivityBridge : () => React__namespace.Fragment;
|
|
98
89
|
/**
|
|
99
|
-
* Bridges
|
|
90
|
+
* Bridges Context, StrictMode, and Activity visibility from a primary renderer.
|
|
100
91
|
*/
|
|
101
92
|
function useBridge() {
|
|
102
93
|
const fiber = itsFine.useFiber();
|
|
103
94
|
const ContextBridge = itsFine.useContextBridge();
|
|
95
|
+
const ActivityBridge = useActivityBridge();
|
|
104
96
|
return React__namespace.useMemo(() => ({
|
|
105
97
|
children
|
|
106
98
|
}) => {
|
|
107
99
|
const strict = !!itsFine.traverseFiber(fiber, true, node => node.type === React__namespace.StrictMode);
|
|
108
100
|
const Root = strict ? React__namespace.StrictMode : React__namespace.Fragment;
|
|
109
101
|
return /*#__PURE__*/jsxRuntime.jsx(Root, {
|
|
110
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
111
|
-
children:
|
|
102
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ActivityBridge, {
|
|
103
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ContextBridge, {
|
|
104
|
+
children: children
|
|
105
|
+
})
|
|
112
106
|
})
|
|
113
107
|
});
|
|
114
|
-
}, [fiber, ContextBridge]);
|
|
108
|
+
}, [fiber, ContextBridge, ActivityBridge]);
|
|
115
109
|
}
|
|
116
110
|
function Block({
|
|
117
111
|
set
|
|
@@ -140,6 +134,19 @@ const ErrorBoundary = /* @__PURE__ */(_ErrorBoundary => (_ErrorBoundary = class
|
|
|
140
134
|
}, _ErrorBoundary.getDerivedStateFromError = () => ({
|
|
141
135
|
error: true
|
|
142
136
|
}), _ErrorBoundary))();
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Returns the instance's initial (outmost) root.
|
|
140
|
+
*/
|
|
141
|
+
function findInitialRoot(instance) {
|
|
142
|
+
let root = instance.root;
|
|
143
|
+
while (root.getState().previousRoot) root = root.getState().previousRoot;
|
|
144
|
+
return root;
|
|
145
|
+
}
|
|
146
|
+
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
147
|
+
const isRef = obj => obj && obj.hasOwnProperty('current');
|
|
148
|
+
const isColorRepresentation = value => value != null && (typeof value === 'string' || typeof value === 'number' || value.isColor);
|
|
149
|
+
const noop = () => {};
|
|
143
150
|
function calculateDpr(dpr) {
|
|
144
151
|
var _window$devicePixelRa;
|
|
145
152
|
// Err on the side of progress by assuming 2x dpr if we can't detect it
|
|
@@ -148,6 +155,43 @@ function calculateDpr(dpr) {
|
|
|
148
155
|
return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
|
|
149
156
|
}
|
|
150
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Calls `onChange` whenever window.devicePixelRatio changes: moving to another display or zooming.
|
|
160
|
+
* Neither resizes the canvas, so resize observers won't see it. A resolution query only matches the
|
|
161
|
+
* current ratio, so it is re-created after every change. Returns the unsubscribe function.
|
|
162
|
+
*/
|
|
163
|
+
function watchDpr(onChange) {
|
|
164
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function' || !window.devicePixelRatio) {
|
|
165
|
+
return () => {};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Partial matchMedia polyfills (test setups, older environments) may return no listener methods,
|
|
169
|
+
// or throw on a query they can't parse. Following the ratio is best-effort: it runs inside
|
|
170
|
+
// configuration, which must not fail because of it
|
|
171
|
+
let query;
|
|
172
|
+
const listen = () => {
|
|
173
|
+
try {
|
|
174
|
+
var _query, _query2;
|
|
175
|
+
query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
|
176
|
+
if (typeof ((_query = query) == null ? void 0 : _query.addEventListener) === 'function') query.addEventListener('change', handleChange);else (_query2 = query) == null ? void 0 : _query2.addListener == null ? void 0 : _query2.addListener(handleChange);
|
|
177
|
+
} catch {
|
|
178
|
+
query = undefined;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const unlisten = () => {
|
|
182
|
+
var _query3, _query4;
|
|
183
|
+
if (typeof ((_query3 = query) == null ? void 0 : _query3.removeEventListener) === 'function') query.removeEventListener('change', handleChange);else (_query4 = query) == null ? void 0 : _query4.removeListener == null ? void 0 : _query4.removeListener(handleChange);
|
|
184
|
+
query = undefined;
|
|
185
|
+
};
|
|
186
|
+
const handleChange = () => {
|
|
187
|
+
unlisten();
|
|
188
|
+
listen();
|
|
189
|
+
onChange();
|
|
190
|
+
};
|
|
191
|
+
listen();
|
|
192
|
+
return unlisten;
|
|
193
|
+
}
|
|
194
|
+
|
|
151
195
|
/**
|
|
152
196
|
* Returns instance root state
|
|
153
197
|
*/
|
|
@@ -257,6 +301,7 @@ function prepare(target, root, type, props) {
|
|
|
257
301
|
object,
|
|
258
302
|
eventCount: 0,
|
|
259
303
|
handlers: {},
|
|
304
|
+
previousVisible: undefined,
|
|
260
305
|
isHidden: false
|
|
261
306
|
};
|
|
262
307
|
if (object) object.__r3f = instance;
|
|
@@ -440,6 +485,12 @@ function applyProps(object, props) {
|
|
|
440
485
|
// Ignore setting undefined props
|
|
441
486
|
// https://github.com/pmndrs/react-three-fiber/issues/274
|
|
442
487
|
if (value === undefined) continue;
|
|
488
|
+
|
|
489
|
+
// Update the visibility to restore without revealing a hidden instance.
|
|
490
|
+
if (prop === 'visible' && instance != null && instance.isHidden && instance.previousVisible !== undefined) {
|
|
491
|
+
instance.previousVisible = value;
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
443
494
|
let {
|
|
444
495
|
root,
|
|
445
496
|
key,
|
|
@@ -590,11 +641,24 @@ function swapInteractivity(store, object, newObject) {
|
|
|
590
641
|
internal.hovered.set(makeId(next), next);
|
|
591
642
|
}
|
|
592
643
|
});
|
|
644
|
+
|
|
645
|
+
// A capture is keyed by its eventObject, but it also carries the intersection that is replayed into
|
|
646
|
+
// every subsequent event. Both must follow the new instance, or the capture resolves to the discarded object.
|
|
593
647
|
internal.capturedMap.forEach(captures => {
|
|
594
|
-
const captureData
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
648
|
+
for (const [key, captureData] of Array.from(captures)) {
|
|
649
|
+
const {
|
|
650
|
+
intersection
|
|
651
|
+
} = captureData;
|
|
652
|
+
if (key !== object && intersection.object !== object && intersection.eventObject !== object) continue;
|
|
653
|
+
if (key === object) captures.delete(key);
|
|
654
|
+
captures.set(key === object ? newObject : key, {
|
|
655
|
+
...captureData,
|
|
656
|
+
intersection: {
|
|
657
|
+
...intersection,
|
|
658
|
+
object: intersection.object === object ? newObject : intersection.object,
|
|
659
|
+
eventObject: intersection.eventObject === object ? newObject : intersection.eventObject
|
|
660
|
+
}
|
|
661
|
+
});
|
|
598
662
|
}
|
|
599
663
|
});
|
|
600
664
|
}
|
|
@@ -993,7 +1057,109 @@ function createEvents(store) {
|
|
|
993
1057
|
};
|
|
994
1058
|
}
|
|
995
1059
|
|
|
1060
|
+
const isPromiseLike = value => typeof (value == null ? void 0 : value.then) === 'function';
|
|
1061
|
+
|
|
1062
|
+
/** A promise tagged with its state, the protocol React's `use` reads */
|
|
1063
|
+
|
|
1064
|
+
const fulfilled = value => Object.assign(Promise.resolve(value), {
|
|
1065
|
+
status: 'fulfilled',
|
|
1066
|
+
value
|
|
1067
|
+
});
|
|
1068
|
+
const rejected = reason => {
|
|
1069
|
+
const promise = Promise.reject(reason);
|
|
1070
|
+
promise.catch(() => {}); // the reason is read from `status`
|
|
1071
|
+
return Object.assign(promise, {
|
|
1072
|
+
status: 'rejected',
|
|
1073
|
+
reason
|
|
1074
|
+
});
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
/** A pending promise, settled once from outside. Its `status` updates the moment it settles */
|
|
1078
|
+
const deferred = () => {
|
|
1079
|
+
let resolve;
|
|
1080
|
+
let reject;
|
|
1081
|
+
const promise = new Promise((yes, no) => {
|
|
1082
|
+
resolve = value => {
|
|
1083
|
+
Object.assign(promise, {
|
|
1084
|
+
status: 'fulfilled',
|
|
1085
|
+
value
|
|
1086
|
+
});
|
|
1087
|
+
yes(value);
|
|
1088
|
+
};
|
|
1089
|
+
reject = reason => {
|
|
1090
|
+
Object.assign(promise, {
|
|
1091
|
+
status: 'rejected',
|
|
1092
|
+
reason
|
|
1093
|
+
});
|
|
1094
|
+
no(reason);
|
|
1095
|
+
};
|
|
1096
|
+
});
|
|
1097
|
+
promise.status = 'pending';
|
|
1098
|
+
promise.catch(() => {}); // the reason is read from `status`
|
|
1099
|
+
return {
|
|
1100
|
+
promise,
|
|
1101
|
+
resolve,
|
|
1102
|
+
reject
|
|
1103
|
+
};
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
/** Renderer creation and resource release. Root lifetime decides when release is safe. */
|
|
996
1107
|
const isRenderer = def => !!(def != null && def.render);
|
|
1108
|
+
|
|
1109
|
+
/** The renderer to configure, or a promise for one from an async factory */
|
|
1110
|
+
function createRenderer(canvas, gl) {
|
|
1111
|
+
const defaults = {
|
|
1112
|
+
canvas,
|
|
1113
|
+
powerPreference: 'high-performance',
|
|
1114
|
+
antialias: true,
|
|
1115
|
+
alpha: true
|
|
1116
|
+
};
|
|
1117
|
+
if (typeof gl === 'function') return gl(defaults);
|
|
1118
|
+
if (isRenderer(gl)) return gl;
|
|
1119
|
+
return new THREE__namespace.WebGLRenderer({
|
|
1120
|
+
...defaults,
|
|
1121
|
+
...gl
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Frees a renderer R3F built. WebGLRenderer.dispose() releases programs and caches but keeps its
|
|
1127
|
+
* context until garbage collection, and browsers cap live WebGL contexts, so the context is lost
|
|
1128
|
+
* after it. A WebGPURenderer (from a factory) releases its device and context inside dispose().
|
|
1129
|
+
*/
|
|
1130
|
+
function disposeRenderer(gl) {
|
|
1131
|
+
// Avoid starting initialization through three's dispose(). A factory must await init()
|
|
1132
|
+
// before returning its renderer so readiness includes initialization and teardown can wait.
|
|
1133
|
+
if ((gl.hasInitialized == null ? void 0 : gl.hasInitialized()) === false) return;
|
|
1134
|
+
const disposed = attempt$1(() => {
|
|
1135
|
+
var _gl$renderLists;
|
|
1136
|
+
return gl.dispose ? gl.dispose() : (_gl$renderLists = gl.renderLists) == null ? void 0 : _gl$renderLists.dispose == null ? void 0 : _gl$renderLists.dispose();
|
|
1137
|
+
});
|
|
1138
|
+
// WebGPURenderer.dispose() is async from three r186
|
|
1139
|
+
if (isPromiseLike(disposed)) {
|
|
1140
|
+
return Promise.resolve(disposed).catch(error => console.warn('[R3F] Error disposing renderer', error)).then(() => attempt$1(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss()));
|
|
1141
|
+
}
|
|
1142
|
+
attempt$1(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss());
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/** Owned renderers are disposed. Caller-provided renderers release caches and their context. */
|
|
1146
|
+
function releaseRenderer(gl, owned) {
|
|
1147
|
+
if (!gl) return;
|
|
1148
|
+
if (owned) return disposeRenderer(gl);
|
|
1149
|
+
attempt$1(() => {
|
|
1150
|
+
var _gl$renderLists2;
|
|
1151
|
+
return (_gl$renderLists2 = gl.renderLists) == null ? void 0 : _gl$renderLists2.dispose == null ? void 0 : _gl$renderLists2.dispose();
|
|
1152
|
+
});
|
|
1153
|
+
attempt$1(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss());
|
|
1154
|
+
}
|
|
1155
|
+
function attempt$1(step) {
|
|
1156
|
+
try {
|
|
1157
|
+
return step();
|
|
1158
|
+
} catch (error) {
|
|
1159
|
+
console.warn('[R3F] Error while unmounting root; teardown may be incomplete:', error);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
997
1163
|
const context = /* @__PURE__ */React__namespace.createContext(null);
|
|
998
1164
|
const createStore = (invalidate, advance) => {
|
|
999
1165
|
const rootStore = traditional.createWithEqualityFn((set, get) => {
|
|
@@ -1288,7 +1454,7 @@ function useGraph(object) {
|
|
|
1288
1454
|
return React__namespace.useMemo(() => buildGraph(object), [object]);
|
|
1289
1455
|
}
|
|
1290
1456
|
const memoizedLoaders = new WeakMap();
|
|
1291
|
-
const isConstructor
|
|
1457
|
+
const isConstructor = value => {
|
|
1292
1458
|
var _value$prototype;
|
|
1293
1459
|
return typeof value === 'function' && (value == null ? void 0 : (_value$prototype = value.prototype) == null ? void 0 : _value$prototype.constructor) === value;
|
|
1294
1460
|
};
|
|
@@ -1297,7 +1463,7 @@ function loadingFn(extensions, onProgress) {
|
|
|
1297
1463
|
let loader;
|
|
1298
1464
|
|
|
1299
1465
|
// Construct and cache loader if constructor was passed
|
|
1300
|
-
if (isConstructor
|
|
1466
|
+
if (isConstructor(Proto)) {
|
|
1301
1467
|
loader = memoizedLoaders.get(Proto);
|
|
1302
1468
|
if (!loader) {
|
|
1303
1469
|
loader = new Proto();
|
|
@@ -1364,9 +1530,298 @@ useLoader.clear = function (loader, input) {
|
|
|
1364
1530
|
e = 2,
|
|
1365
1531
|
i$1 = 268435456;
|
|
1366
1532
|
|
|
1533
|
+
// Shim for OffscreenCanvas since it was removed from DOM types
|
|
1534
|
+
// https://github.com/DefinitelyTyped/DefinitelyTyped/pull/54988
|
|
1535
|
+
|
|
1536
|
+
/** What a root has applied, so its next configuration applies only what changed */
|
|
1537
|
+
|
|
1538
|
+
const shallow = {
|
|
1539
|
+
objects: 'shallow'
|
|
1540
|
+
};
|
|
1541
|
+
function computeInitialSize(canvas, size) {
|
|
1542
|
+
if (!size && typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1543
|
+
const {
|
|
1544
|
+
width,
|
|
1545
|
+
height,
|
|
1546
|
+
top,
|
|
1547
|
+
left
|
|
1548
|
+
} = canvas.parentElement.getBoundingClientRect();
|
|
1549
|
+
return {
|
|
1550
|
+
width,
|
|
1551
|
+
height,
|
|
1552
|
+
top,
|
|
1553
|
+
left
|
|
1554
|
+
};
|
|
1555
|
+
} else if (!size && typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
|
|
1556
|
+
return {
|
|
1557
|
+
width: canvas.width,
|
|
1558
|
+
height: canvas.height,
|
|
1559
|
+
top: 0,
|
|
1560
|
+
left: 0
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
return {
|
|
1564
|
+
width: 0,
|
|
1565
|
+
height: 0,
|
|
1566
|
+
top: 0,
|
|
1567
|
+
left: 0,
|
|
1568
|
+
...size
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* Applies the inputs that changed since the last configuration applied in full, to a root whose
|
|
1574
|
+
* renderer is installed. A runtime change, such as setFrameloop or an edit to gl.shadowMap, lasts
|
|
1575
|
+
* until its input changes. The pixel ratio instead follows the device on every call. Objects and
|
|
1576
|
+
* arrays compare shallowly, so an equal inline value is unchanged.
|
|
1577
|
+
*/
|
|
1578
|
+
function applyRootConfiguration({
|
|
1579
|
+
store,
|
|
1580
|
+
configuration
|
|
1581
|
+
}, canvas, props) {
|
|
1582
|
+
const {
|
|
1583
|
+
gl: glConfig,
|
|
1584
|
+
scene: sceneOptions,
|
|
1585
|
+
camera: cameraOptions,
|
|
1586
|
+
shadows = false,
|
|
1587
|
+
linear = false,
|
|
1588
|
+
flat = false,
|
|
1589
|
+
legacy = false,
|
|
1590
|
+
frameloop = 'always',
|
|
1591
|
+
dpr = [1, 2],
|
|
1592
|
+
performance,
|
|
1593
|
+
onPointerMissed
|
|
1594
|
+
} = props;
|
|
1595
|
+
const size = computeInitialSize(canvas, props.size);
|
|
1596
|
+
const next = {
|
|
1597
|
+
...props,
|
|
1598
|
+
shadows,
|
|
1599
|
+
linear,
|
|
1600
|
+
flat,
|
|
1601
|
+
legacy,
|
|
1602
|
+
frameloop,
|
|
1603
|
+
size
|
|
1604
|
+
};
|
|
1605
|
+
const state = store.getState();
|
|
1606
|
+
const gl = state.gl;
|
|
1607
|
+
const last = configuration.previous;
|
|
1608
|
+
const changed = key => !last || !is.equ(next[key], last[key], shallow);
|
|
1609
|
+
// A failure can leave inputs partly applied, so the next configuration applies all of them
|
|
1610
|
+
configuration.previous = undefined;
|
|
1611
|
+
|
|
1612
|
+
// Set up raycaster (one time only!)
|
|
1613
|
+
let raycaster = state.raycaster;
|
|
1614
|
+
if (!raycaster) state.set({
|
|
1615
|
+
raycaster: raycaster = new THREE__namespace.Raycaster()
|
|
1616
|
+
});
|
|
1617
|
+
if (changed('raycaster')) {
|
|
1618
|
+
var _props$raycaster;
|
|
1619
|
+
const {
|
|
1620
|
+
params,
|
|
1621
|
+
...options
|
|
1622
|
+
} = (_props$raycaster = props.raycaster) != null ? _props$raycaster : {};
|
|
1623
|
+
applyProps(raycaster, {
|
|
1624
|
+
...options,
|
|
1625
|
+
params: {
|
|
1626
|
+
...raycaster.params,
|
|
1627
|
+
...params
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// Create default camera, don't overwrite any user-set state
|
|
1633
|
+
if (!state.camera || state.camera === configuration.camera && changed('camera')) {
|
|
1634
|
+
configuration.camera = cameraOptions;
|
|
1635
|
+
const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
|
|
1636
|
+
const camera = isCamera ? cameraOptions : props.orthographic ? new THREE__namespace.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE__namespace.PerspectiveCamera(75, 0, 0.1, 1000);
|
|
1637
|
+
if (!isCamera) {
|
|
1638
|
+
camera.position.z = 5;
|
|
1639
|
+
if (cameraOptions) {
|
|
1640
|
+
applyProps(camera, cameraOptions);
|
|
1641
|
+
// Preserve user-defined frustum if possible
|
|
1642
|
+
// https://github.com/pmndrs/react-three-fiber/issues/3160
|
|
1643
|
+
if (!camera.manual) {
|
|
1644
|
+
if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
|
|
1645
|
+
camera.manual = true;
|
|
1646
|
+
camera.updateProjectionMatrix();
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
// Always look at center by default
|
|
1651
|
+
if (!state.camera && !(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
|
|
1652
|
+
}
|
|
1653
|
+
state.set({
|
|
1654
|
+
camera
|
|
1655
|
+
});
|
|
1656
|
+
|
|
1657
|
+
// Configure raycaster
|
|
1658
|
+
// https://github.com/pmndrs/react-xr/issues/300
|
|
1659
|
+
raycaster.camera = camera;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
// Set up scene (one time only!)
|
|
1663
|
+
if (!state.scene) {
|
|
1664
|
+
let scene;
|
|
1665
|
+
if (sceneOptions != null && sceneOptions.isScene) {
|
|
1666
|
+
scene = sceneOptions;
|
|
1667
|
+
prepare(scene, store, '', {});
|
|
1668
|
+
} else {
|
|
1669
|
+
scene = new THREE__namespace.Scene();
|
|
1670
|
+
prepare(scene, store, '', {});
|
|
1671
|
+
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
1672
|
+
}
|
|
1673
|
+
state.set({
|
|
1674
|
+
scene
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// Store events internally
|
|
1679
|
+
if (props.events && !state.events.handlers) state.set({
|
|
1680
|
+
events: props.events(store)
|
|
1681
|
+
});
|
|
1682
|
+
if (changed('size')) state.setSize(size.width, size.height, size.top, size.left);
|
|
1683
|
+
// The ratio follows window.devicePixelRatio, which changes with browser zoom or another display
|
|
1684
|
+
if (state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1685
|
+
if (changed('frameloop')) state.setFrameloop(frameloop);
|
|
1686
|
+
if (changed('onPointerMissed')) state.set({
|
|
1687
|
+
onPointerMissed
|
|
1688
|
+
});
|
|
1689
|
+
// Performance options merge, so removing them keeps the current settings
|
|
1690
|
+
if (performance && changed('performance')) {
|
|
1691
|
+
state.set(state => ({
|
|
1692
|
+
performance: {
|
|
1693
|
+
...state.performance,
|
|
1694
|
+
...performance
|
|
1695
|
+
}
|
|
1696
|
+
}));
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// Set up XR (one time only!)
|
|
1700
|
+
if (!state.xr) {
|
|
1701
|
+
var _gl$xr;
|
|
1702
|
+
// Handle frame behavior in WebXR
|
|
1703
|
+
const handleXRFrame = (timestamp, frame) => {
|
|
1704
|
+
const state = store.getState();
|
|
1705
|
+
if (state.frameloop === 'never') return;
|
|
1706
|
+
advance(timestamp, true, state, frame);
|
|
1707
|
+
};
|
|
1708
|
+
|
|
1709
|
+
// Toggle render switching on session
|
|
1710
|
+
const handleSessionChange = () => {
|
|
1711
|
+
const state = store.getState();
|
|
1712
|
+
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1713
|
+
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1714
|
+
if (!state.gl.xr.isPresenting) invalidate(state);
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1717
|
+
// WebXR session manager
|
|
1718
|
+
const xr = {
|
|
1719
|
+
connect() {
|
|
1720
|
+
const gl = store.getState().gl;
|
|
1721
|
+
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1722
|
+
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1723
|
+
},
|
|
1724
|
+
disconnect() {
|
|
1725
|
+
const gl = store.getState().gl;
|
|
1726
|
+
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1727
|
+
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1731
|
+
// Subscribe to WebXR session events
|
|
1732
|
+
if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
|
|
1733
|
+
state.set({
|
|
1734
|
+
xr
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// Set shadowmap
|
|
1739
|
+
if (gl.shadowMap && changed('shadows')) {
|
|
1740
|
+
const oldEnabled = gl.shadowMap.enabled;
|
|
1741
|
+
const oldType = gl.shadowMap.type;
|
|
1742
|
+
gl.shadowMap.enabled = !!shadows;
|
|
1743
|
+
if (is.boo(shadows)) {
|
|
1744
|
+
gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
1745
|
+
} else if (is.str(shadows)) {
|
|
1746
|
+
var _types$shadows;
|
|
1747
|
+
const types = {
|
|
1748
|
+
basic: THREE__namespace.BasicShadowMap,
|
|
1749
|
+
percentage: THREE__namespace.PCFShadowMap,
|
|
1750
|
+
soft: THREE__namespace.PCFSoftShadowMap,
|
|
1751
|
+
variance: THREE__namespace.VSMShadowMap
|
|
1752
|
+
};
|
|
1753
|
+
gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE__namespace.PCFSoftShadowMap;
|
|
1754
|
+
} else if (is.obj(shadows)) {
|
|
1755
|
+
Object.assign(gl.shadowMap, shadows);
|
|
1756
|
+
}
|
|
1757
|
+
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// Explicit renderer options take precedence over the color shorthands
|
|
1761
|
+
const glProps = glConfig && !is.fun(glConfig) && !isRenderer(glConfig) ? glConfig : undefined;
|
|
1762
|
+
if (changed('legacy')) {
|
|
1763
|
+
THREE__namespace.ColorManagement.enabled = !legacy;
|
|
1764
|
+
state.set({
|
|
1765
|
+
legacy
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
if (changed('linear')) {
|
|
1769
|
+
if ((glProps == null ? void 0 : glProps.outputColorSpace) === undefined) {
|
|
1770
|
+
gl.outputColorSpace = linear ? THREE__namespace.LinearSRGBColorSpace : THREE__namespace.SRGBColorSpace;
|
|
1771
|
+
}
|
|
1772
|
+
state.set({
|
|
1773
|
+
linear
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
if (changed('flat')) {
|
|
1777
|
+
if ((glProps == null ? void 0 : glProps.toneMapping) === undefined) gl.toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
|
|
1778
|
+
state.set({
|
|
1779
|
+
flat
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
// Set gl props
|
|
1784
|
+
if (glProps && changed('gl')) applyProps(gl, glProps);
|
|
1785
|
+
configuration.previous = next;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* Moving to another display or zooming changes window.devicePixelRatio without resizing the canvas,
|
|
1790
|
+
* so nothing configures the root again. Resolves the ratio the way configuration does, from the last
|
|
1791
|
+
* applied dpr. Returns the function that stops following.
|
|
1792
|
+
*/
|
|
1793
|
+
function followDpr(root) {
|
|
1794
|
+
const xr = () => {
|
|
1795
|
+
var _root$store$getState$;
|
|
1796
|
+
return (_root$store$getState$ = root.store.getState().gl) == null ? void 0 : _root$store$getState$.xr;
|
|
1797
|
+
};
|
|
1798
|
+
const follow = () => {
|
|
1799
|
+
var _xr, _xr2, _xr3, _last$dpr;
|
|
1800
|
+
const state = root.store.getState();
|
|
1801
|
+
// three doesn't resize during XR and restores its own pixel ratio once the session ends. It holds
|
|
1802
|
+
// the session before it sets isPresenting. Listeners are deduplicated, so this waits once
|
|
1803
|
+
if ((_xr = xr()) != null && _xr.isPresenting || (_xr2 = xr()) != null && _xr2.getSession != null && _xr2.getSession()) {
|
|
1804
|
+
xr().addEventListener('sessionend', follow);
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
(_xr3 = xr()) == null ? void 0 : _xr3.removeEventListener == null ? void 0 : _xr3.removeEventListener('sessionend', follow);
|
|
1808
|
+
// A failed configuration applies everything on the next one
|
|
1809
|
+
const last = root.configuration.previous;
|
|
1810
|
+
if (!last) return;
|
|
1811
|
+
const dpr = (_last$dpr = last.dpr) != null ? _last$dpr : [1, 2];
|
|
1812
|
+
if (state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1813
|
+
};
|
|
1814
|
+
const unwatch = watchDpr(follow);
|
|
1815
|
+
return () => {
|
|
1816
|
+
var _xr4;
|
|
1817
|
+
unwatch();
|
|
1818
|
+
(_xr4 = xr()) == null ? void 0 : _xr4.removeEventListener == null ? void 0 : _xr4.removeEventListener('sessionend', follow);
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1367
1822
|
var packageData = {
|
|
1368
1823
|
name: "@react-three/fiber",
|
|
1369
|
-
version: "9.8.
|
|
1824
|
+
version: "9.8.2",
|
|
1370
1825
|
description: "A React renderer for Threejs",
|
|
1371
1826
|
keywords: [
|
|
1372
1827
|
"react",
|
|
@@ -1398,6 +1853,12 @@ var packageData = {
|
|
|
1398
1853
|
module: "dist/react-three-fiber.esm.js",
|
|
1399
1854
|
types: "dist/react-three-fiber.cjs.d.ts",
|
|
1400
1855
|
"react-native": "native/dist/react-three-fiber-native.cjs.js",
|
|
1856
|
+
files: [
|
|
1857
|
+
"dist",
|
|
1858
|
+
"native",
|
|
1859
|
+
"react-reconciler",
|
|
1860
|
+
"CHANGELOG.md"
|
|
1861
|
+
],
|
|
1401
1862
|
sideEffects: false,
|
|
1402
1863
|
preconstruct: {
|
|
1403
1864
|
entrypoints: [
|
|
@@ -1417,7 +1878,7 @@ var packageData = {
|
|
|
1417
1878
|
"@types/webxr": "*",
|
|
1418
1879
|
"base64-js": "^1.5.1",
|
|
1419
1880
|
buffer: "^6.0.3",
|
|
1420
|
-
"its-fine": "^2.
|
|
1881
|
+
"its-fine": "^2.1.1",
|
|
1421
1882
|
"react-use-measure": "^2.1.7",
|
|
1422
1883
|
scheduler: "^0.28.0",
|
|
1423
1884
|
"suspend-react": "^0.1.3",
|
|
@@ -7359,6 +7820,27 @@ function G1() {
|
|
|
7359
7820
|
var J1 = G1();
|
|
7360
7821
|
const Z1 = $1(J1);
|
|
7361
7822
|
|
|
7823
|
+
/** Constructor registration and lookup for JSX elements. */
|
|
7824
|
+
|
|
7825
|
+
const catalogue = {};
|
|
7826
|
+
let i = 0;
|
|
7827
|
+
const toPascalCase = type => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
7828
|
+
function hasConstructor(name) {
|
|
7829
|
+
return name in catalogue;
|
|
7830
|
+
}
|
|
7831
|
+
function resolveConstructor(name) {
|
|
7832
|
+
return catalogue[name];
|
|
7833
|
+
}
|
|
7834
|
+
function extend(objects) {
|
|
7835
|
+
if (typeof objects === 'function') {
|
|
7836
|
+
const Component = `${i++}`;
|
|
7837
|
+
catalogue[Component] = objects;
|
|
7838
|
+
return Component;
|
|
7839
|
+
} else {
|
|
7840
|
+
Object.assign(catalogue, objects);
|
|
7841
|
+
}
|
|
7842
|
+
}
|
|
7843
|
+
|
|
7362
7844
|
function createReconciler(config) {
|
|
7363
7845
|
const reconciler = Z1(config);
|
|
7364
7846
|
|
|
@@ -7372,24 +7854,11 @@ const NoEventPriority = 0;
|
|
|
7372
7854
|
// https://github.com/pmndrs/react-three-fiber/pull/2931
|
|
7373
7855
|
// https://github.com/microsoft/TypeScript/issues/37079
|
|
7374
7856
|
|
|
7375
|
-
const catalogue = {};
|
|
7376
7857
|
const PREFIX_REGEX = /^three(?=[A-Z])/;
|
|
7377
|
-
const toPascalCase = type => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
7378
|
-
let i = 0;
|
|
7379
|
-
const isConstructor = object => typeof object === 'function';
|
|
7380
|
-
function extend(objects) {
|
|
7381
|
-
if (isConstructor(objects)) {
|
|
7382
|
-
const Component = `${i++}`;
|
|
7383
|
-
catalogue[Component] = objects;
|
|
7384
|
-
return Component;
|
|
7385
|
-
} else {
|
|
7386
|
-
Object.assign(catalogue, objects);
|
|
7387
|
-
}
|
|
7388
|
-
}
|
|
7389
7858
|
function validateInstance(type, props) {
|
|
7390
7859
|
// Get target from catalogue
|
|
7391
7860
|
const name = toPascalCase(type);
|
|
7392
|
-
const target =
|
|
7861
|
+
const target = resolveConstructor(name);
|
|
7393
7862
|
|
|
7394
7863
|
// Validate element target
|
|
7395
7864
|
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`);
|
|
@@ -7403,7 +7872,7 @@ function validateInstance(type, props) {
|
|
|
7403
7872
|
function createInstance(type, props, root) {
|
|
7404
7873
|
var _props$object;
|
|
7405
7874
|
// Remove three* prefix from elements if native element not present
|
|
7406
|
-
type = toPascalCase(type)
|
|
7875
|
+
type = hasConstructor(toPascalCase(type)) ? type : type.replace(PREFIX_REGEX, '');
|
|
7407
7876
|
validateInstance(type, props);
|
|
7408
7877
|
|
|
7409
7878
|
// Regenerate the R3F instance for primitives to simulate a new object
|
|
@@ -7416,6 +7885,7 @@ function hideInstance(instance) {
|
|
|
7416
7885
|
if (instance.props.attach && (_instance$parent = instance.parent) != null && _instance$parent.object) {
|
|
7417
7886
|
detach(instance.parent, instance);
|
|
7418
7887
|
} else if (isObject3D(instance.object)) {
|
|
7888
|
+
instance.previousVisible = instance.object.visible;
|
|
7419
7889
|
instance.object.visible = false;
|
|
7420
7890
|
}
|
|
7421
7891
|
instance.isHidden = true;
|
|
@@ -7427,9 +7897,11 @@ function unhideInstance(instance) {
|
|
|
7427
7897
|
var _instance$parent2;
|
|
7428
7898
|
if (instance.props.attach && (_instance$parent2 = instance.parent) != null && _instance$parent2.object) {
|
|
7429
7899
|
attach(instance.parent, instance);
|
|
7430
|
-
} else if (isObject3D(instance.object)
|
|
7431
|
-
|
|
7900
|
+
} else if (isObject3D(instance.object)) {
|
|
7901
|
+
var _instance$previousVis;
|
|
7902
|
+
instance.object.visible = (_instance$previousVis = instance.previousVisible) != null ? _instance$previousVis : true;
|
|
7432
7903
|
}
|
|
7904
|
+
instance.previousVisible = undefined;
|
|
7433
7905
|
instance.isHidden = false;
|
|
7434
7906
|
invalidateInstance(instance);
|
|
7435
7907
|
}
|
|
@@ -7447,7 +7919,7 @@ function handleContainerEffects(parent, child, beforeChild) {
|
|
|
7447
7919
|
if (!child.object) {
|
|
7448
7920
|
var _child$props$object, _child$props$args;
|
|
7449
7921
|
// Get target from catalogue
|
|
7450
|
-
const target =
|
|
7922
|
+
const target = resolveConstructor(toPascalCase(child.type));
|
|
7451
7923
|
|
|
7452
7924
|
// Create object
|
|
7453
7925
|
child.object = (_child$props$object = child.props.object) != null ? _child$props$object : new target(...((_child$props$args = child.props.args) != null ? _child$props$args : []));
|
|
@@ -7544,6 +8016,9 @@ function disposeOnIdle(object) {
|
|
|
7544
8016
|
function removeChild(parent, child, dispose) {
|
|
7545
8017
|
if (!child) return;
|
|
7546
8018
|
|
|
8019
|
+
// Unlinking clears the parent, which invalidateInstance checks, so remember it
|
|
8020
|
+
const wasLinked = !!child.parent;
|
|
8021
|
+
|
|
7547
8022
|
// Unlink instances
|
|
7548
8023
|
child.parent = null;
|
|
7549
8024
|
const childIndex = parent.children.indexOf(child);
|
|
@@ -7581,7 +8056,11 @@ function removeChild(parent, child, dispose) {
|
|
|
7581
8056
|
}
|
|
7582
8057
|
|
|
7583
8058
|
// Tree was updated, request a frame for top-level instance
|
|
7584
|
-
if (dispose === undefined)
|
|
8059
|
+
if (dispose === undefined && wasLinked) {
|
|
8060
|
+
var _child$root;
|
|
8061
|
+
const state = (_child$root = child.root) == null ? void 0 : _child$root.getState == null ? void 0 : _child$root.getState();
|
|
8062
|
+
if (state && state.internal.frames === 0) state.invalidate();
|
|
8063
|
+
}
|
|
7585
8064
|
}
|
|
7586
8065
|
function setFiberRef(fiber, publicInstance) {
|
|
7587
8066
|
for (const _fiber of [fiber, fiber.alternate]) {
|
|
@@ -7642,7 +8121,7 @@ function swapReconstructedInstances() {
|
|
|
7642
8121
|
if (parent) {
|
|
7643
8122
|
var _instance$props$objec, _instance$props$args;
|
|
7644
8123
|
// Get target from catalogue
|
|
7645
|
-
const target =
|
|
8124
|
+
const target = resolveConstructor(toPascalCase(instance.type));
|
|
7646
8125
|
|
|
7647
8126
|
// Create object
|
|
7648
8127
|
const prevObject = instance.object;
|
|
@@ -7974,76 +8453,49 @@ const reconciler = /* @__PURE__ */createReconciler({
|
|
|
7974
8453
|
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
7975
8454
|
});
|
|
7976
8455
|
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
promise.catch(() => {}); // the reason is read from `status`
|
|
7988
|
-
return Object.assign(promise, {
|
|
7989
|
-
status: 'rejected',
|
|
7990
|
-
reason
|
|
7991
|
-
});
|
|
7992
|
-
};
|
|
7993
|
-
|
|
7994
|
-
/** Tags `promise` in place once it settles. */
|
|
7995
|
-
const tracked = promise => {
|
|
7996
|
-
const result = Promise.resolve(promise);
|
|
7997
|
-
result.status = 'pending';
|
|
7998
|
-
// Statement bodies: returning `result` would make this derived promise adopt its rejection
|
|
7999
|
-
result.then(value => {
|
|
8000
|
-
Object.assign(result, {
|
|
8001
|
-
status: 'fulfilled',
|
|
8002
|
-
value
|
|
8003
|
-
});
|
|
8004
|
-
}, reason => {
|
|
8005
|
-
Object.assign(result, {
|
|
8006
|
-
status: 'rejected',
|
|
8007
|
-
reason
|
|
8008
|
-
});
|
|
8009
|
-
});
|
|
8010
|
-
return result;
|
|
8011
|
-
};
|
|
8456
|
+
/**
|
|
8457
|
+
* Force React to flush any updates inside the provided callback synchronously and immediately.
|
|
8458
|
+
* All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
|
|
8459
|
+
* Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
|
|
8460
|
+
* having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
|
|
8461
|
+
*/
|
|
8462
|
+
function flushSync(fn) {
|
|
8463
|
+
// @ts-ignore - reconciler types are not maintained
|
|
8464
|
+
return reconciler.flushSyncFromReconciler(fn);
|
|
8465
|
+
}
|
|
8012
8466
|
|
|
8013
8467
|
const _roots = new Map();
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8468
|
+
/**
|
|
8469
|
+
* open -> closing -> disposed
|
|
8470
|
+
* | use
|
|
8471
|
+
* v
|
|
8472
|
+
* open
|
|
8473
|
+
*
|
|
8474
|
+
* Only closing can be cancelled. Each unmount carries a token, so only the latest one can dispose.
|
|
8475
|
+
*/
|
|
8476
|
+
function transitionRoot(root, event) {
|
|
8477
|
+
const state = root.state;
|
|
8478
|
+
switch (event.type) {
|
|
8479
|
+
case 'use':
|
|
8480
|
+
if (state.status === 'disposed') return false;
|
|
8481
|
+
root.state = {
|
|
8482
|
+
status: 'open'
|
|
8483
|
+
};
|
|
8484
|
+
return true;
|
|
8485
|
+
case 'unmount':
|
|
8486
|
+
if (state.status === 'disposed') return false;
|
|
8487
|
+
root.state = {
|
|
8488
|
+
status: 'closing',
|
|
8489
|
+
token: event.token
|
|
8490
|
+
};
|
|
8491
|
+
return true;
|
|
8492
|
+
case 'dispose':
|
|
8493
|
+
if (state.status !== 'closing' || state.token !== event.token) return false;
|
|
8494
|
+
root.state = {
|
|
8495
|
+
status: 'disposed'
|
|
8496
|
+
};
|
|
8497
|
+
return true;
|
|
8039
8498
|
}
|
|
8040
|
-
return {
|
|
8041
|
-
width: 0,
|
|
8042
|
-
height: 0,
|
|
8043
|
-
top: 0,
|
|
8044
|
-
left: 0,
|
|
8045
|
-
...size
|
|
8046
|
-
};
|
|
8047
8499
|
}
|
|
8048
8500
|
function createRoot(canvas) {
|
|
8049
8501
|
// Check against mistaken use of createRoot
|
|
@@ -8088,286 +8540,86 @@ function createRoot(canvas) {
|
|
|
8088
8540
|
const root = prevRoot || {
|
|
8089
8541
|
fiber,
|
|
8090
8542
|
store,
|
|
8091
|
-
|
|
8092
|
-
|
|
8543
|
+
state: {
|
|
8544
|
+
status: 'open'
|
|
8545
|
+
},
|
|
8546
|
+
ready: fulfilled(undefined),
|
|
8547
|
+
configuration: {},
|
|
8548
|
+
ownsRenderer: false
|
|
8093
8549
|
};
|
|
8094
8550
|
if (!prevRoot) _roots.set(canvas, root);
|
|
8095
|
-
|
|
8096
|
-
// Locals
|
|
8097
|
-
let onCreated;
|
|
8098
|
-
let lastCamera;
|
|
8099
8551
|
let mounted = false;
|
|
8100
8552
|
return {
|
|
8101
8553
|
get ready() {
|
|
8102
8554
|
return root.ready;
|
|
8103
8555
|
},
|
|
8104
8556
|
configure(props = {}) {
|
|
8105
|
-
root
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
events,
|
|
8111
|
-
onCreated: onCreatedCallback,
|
|
8112
|
-
shadows = false,
|
|
8113
|
-
linear = false,
|
|
8114
|
-
flat = false,
|
|
8115
|
-
legacy = false,
|
|
8116
|
-
orthographic = false,
|
|
8117
|
-
frameloop = 'always',
|
|
8118
|
-
dpr = [1, 2],
|
|
8119
|
-
performance,
|
|
8120
|
-
raycaster: raycastOptions,
|
|
8121
|
-
camera: cameraOptions,
|
|
8122
|
-
onPointerMissed
|
|
8123
|
-
} = props;
|
|
8124
|
-
const defaultProps = {
|
|
8125
|
-
canvas: canvas,
|
|
8126
|
-
powerPreference: 'high-performance',
|
|
8127
|
-
antialias: true,
|
|
8128
|
-
alpha: true
|
|
8129
|
-
};
|
|
8557
|
+
if (!transitionRoot(root, {
|
|
8558
|
+
type: 'use'
|
|
8559
|
+
})) {
|
|
8560
|
+
return rejected(new Error('R3F: Cannot configure a root after disposal has started.'));
|
|
8561
|
+
}
|
|
8130
8562
|
|
|
8131
|
-
//
|
|
8132
|
-
const
|
|
8563
|
+
// Configuration applies in call order. Publishing first queues calls made while this one runs
|
|
8564
|
+
const previous = root.ready;
|
|
8565
|
+
const {
|
|
8566
|
+
promise,
|
|
8567
|
+
resolve,
|
|
8568
|
+
reject
|
|
8569
|
+
} = deferred();
|
|
8570
|
+
root.ready = promise;
|
|
8571
|
+
const apply = gl => {
|
|
8133
8572
|
const state = store.getState();
|
|
8134
|
-
|
|
8135
8573
|
// Set up renderer (one time only!)
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
...defaultProps,
|
|
8141
|
-
...glConfig
|
|
8142
|
-
});
|
|
8143
|
-
state.set({
|
|
8144
|
-
gl
|
|
8145
|
-
});
|
|
8146
|
-
}
|
|
8147
|
-
|
|
8148
|
-
// Set up raycaster (one time only!)
|
|
8149
|
-
let raycaster = state.raycaster;
|
|
8150
|
-
if (!raycaster) state.set({
|
|
8151
|
-
raycaster: raycaster = new THREE__namespace.Raycaster()
|
|
8152
|
-
});
|
|
8153
|
-
|
|
8154
|
-
// Set raycaster options
|
|
8155
|
-
const {
|
|
8156
|
-
params,
|
|
8157
|
-
...options
|
|
8158
|
-
} = raycastOptions || {};
|
|
8159
|
-
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
|
|
8160
|
-
...options
|
|
8161
|
-
});
|
|
8162
|
-
if (!is.equ(params, raycaster.params, shallowLoose)) applyProps(raycaster, {
|
|
8163
|
-
params: {
|
|
8164
|
-
...raycaster.params,
|
|
8165
|
-
...params
|
|
8166
|
-
}
|
|
8167
|
-
});
|
|
8168
|
-
|
|
8169
|
-
// Create default camera, don't overwrite any user-set state
|
|
8170
|
-
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
8171
|
-
lastCamera = cameraOptions;
|
|
8172
|
-
const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
|
|
8173
|
-
const camera = isCamera ? cameraOptions : orthographic ? new THREE__namespace.OrthographicCamera(0, 0, 0, 0, 0.1, 1000) : new THREE__namespace.PerspectiveCamera(75, 0, 0.1, 1000);
|
|
8174
|
-
if (!isCamera) {
|
|
8175
|
-
camera.position.z = 5;
|
|
8176
|
-
if (cameraOptions) {
|
|
8177
|
-
applyProps(camera, cameraOptions);
|
|
8178
|
-
// Preserve user-defined frustum if possible
|
|
8179
|
-
// https://github.com/pmndrs/react-three-fiber/issues/3160
|
|
8180
|
-
if (!camera.manual) {
|
|
8181
|
-
if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
|
|
8182
|
-
camera.manual = true;
|
|
8183
|
-
camera.updateProjectionMatrix();
|
|
8184
|
-
}
|
|
8185
|
-
}
|
|
8186
|
-
}
|
|
8187
|
-
// Always look at center by default
|
|
8188
|
-
if (!state.camera && !(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
|
|
8189
|
-
}
|
|
8190
|
-
state.set({
|
|
8191
|
-
camera
|
|
8192
|
-
});
|
|
8193
|
-
|
|
8194
|
-
// Configure raycaster
|
|
8195
|
-
// https://github.com/pmndrs/react-xr/issues/300
|
|
8196
|
-
raycaster.camera = camera;
|
|
8197
|
-
}
|
|
8198
|
-
|
|
8199
|
-
// Set up scene (one time only!)
|
|
8200
|
-
if (!state.scene) {
|
|
8201
|
-
let scene;
|
|
8202
|
-
if (sceneOptions != null && sceneOptions.isScene) {
|
|
8203
|
-
scene = sceneOptions;
|
|
8204
|
-
prepare(scene, store, '', {});
|
|
8205
|
-
} else {
|
|
8206
|
-
scene = new THREE__namespace.Scene();
|
|
8207
|
-
prepare(scene, store, '', {});
|
|
8208
|
-
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
8209
|
-
}
|
|
8210
|
-
state.set({
|
|
8211
|
-
scene
|
|
8212
|
-
});
|
|
8213
|
-
}
|
|
8214
|
-
|
|
8215
|
-
// Store events internally
|
|
8216
|
-
if (events && !state.events.handlers) state.set({
|
|
8217
|
-
events: events(store)
|
|
8218
|
-
});
|
|
8219
|
-
// Check size, allow it to take on container bounds initially
|
|
8220
|
-
const size = computeInitialSize(canvas, propsSize);
|
|
8221
|
-
if (!is.equ(size, state.size, shallowLoose)) {
|
|
8222
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
8223
|
-
}
|
|
8224
|
-
// Check pixelratio
|
|
8225
|
-
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
8226
|
-
// Check frameloop
|
|
8227
|
-
if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
|
|
8228
|
-
// Check pointer missed
|
|
8229
|
-
if (!state.onPointerMissed) state.set({
|
|
8230
|
-
onPointerMissed
|
|
8231
|
-
});
|
|
8232
|
-
// Check performance
|
|
8233
|
-
if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
|
|
8234
|
-
performance: {
|
|
8235
|
-
...state.performance,
|
|
8236
|
-
...performance
|
|
8237
|
-
}
|
|
8238
|
-
}));
|
|
8239
|
-
|
|
8240
|
-
// Set up XR (one time only!)
|
|
8241
|
-
if (!state.xr) {
|
|
8242
|
-
var _gl$xr;
|
|
8243
|
-
// Handle frame behavior in WebXR
|
|
8244
|
-
const handleXRFrame = (timestamp, frame) => {
|
|
8245
|
-
const state = store.getState();
|
|
8246
|
-
if (state.frameloop === 'never') return;
|
|
8247
|
-
advance(timestamp, true, state, frame);
|
|
8248
|
-
};
|
|
8249
|
-
|
|
8250
|
-
// Toggle render switching on session
|
|
8251
|
-
const handleSessionChange = () => {
|
|
8252
|
-
const state = store.getState();
|
|
8253
|
-
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
8254
|
-
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
8255
|
-
if (!state.gl.xr.isPresenting) invalidate(state);
|
|
8256
|
-
};
|
|
8257
|
-
|
|
8258
|
-
// WebXR session manager
|
|
8259
|
-
const xr = {
|
|
8260
|
-
connect() {
|
|
8261
|
-
const gl = store.getState().gl;
|
|
8262
|
-
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
8263
|
-
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
8264
|
-
},
|
|
8265
|
-
disconnect() {
|
|
8266
|
-
const gl = store.getState().gl;
|
|
8267
|
-
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
8268
|
-
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
8269
|
-
}
|
|
8270
|
-
};
|
|
8271
|
-
|
|
8272
|
-
// Subscribe to WebXR session events
|
|
8273
|
-
if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
|
|
8574
|
+
if (!state.gl) {
|
|
8575
|
+
// R3F owns what it builds, a factory's result included, since it calls the factory
|
|
8576
|
+
// once per root. A renderer instance belongs to the caller
|
|
8577
|
+
root.ownsRenderer = !isRenderer(props.gl);
|
|
8274
8578
|
state.set({
|
|
8275
|
-
|
|
8579
|
+
gl: gl
|
|
8276
8580
|
});
|
|
8277
8581
|
}
|
|
8278
|
-
|
|
8279
|
-
//
|
|
8280
|
-
if (
|
|
8281
|
-
|
|
8282
|
-
const oldType = gl.shadowMap.type;
|
|
8283
|
-
gl.shadowMap.enabled = !!shadows;
|
|
8284
|
-
if (is.boo(shadows)) {
|
|
8285
|
-
gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
8286
|
-
} else if (is.str(shadows)) {
|
|
8287
|
-
var _types$shadows;
|
|
8288
|
-
const types = {
|
|
8289
|
-
basic: THREE__namespace.BasicShadowMap,
|
|
8290
|
-
percentage: THREE__namespace.PCFShadowMap,
|
|
8291
|
-
soft: THREE__namespace.PCFSoftShadowMap,
|
|
8292
|
-
variance: THREE__namespace.VSMShadowMap
|
|
8293
|
-
};
|
|
8294
|
-
gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE__namespace.PCFSoftShadowMap;
|
|
8295
|
-
} else if (is.obj(shadows)) {
|
|
8296
|
-
Object.assign(gl.shadowMap, shadows);
|
|
8297
|
-
}
|
|
8298
|
-
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
8299
|
-
}
|
|
8300
|
-
THREE__namespace.ColorManagement.enabled = !legacy;
|
|
8301
|
-
|
|
8302
|
-
// Set color space and tonemapping preferences
|
|
8303
|
-
if (first) {
|
|
8304
|
-
gl.outputColorSpace = linear ? THREE__namespace.LinearSRGBColorSpace : THREE__namespace.SRGBColorSpace;
|
|
8305
|
-
gl.toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
|
|
8306
|
-
}
|
|
8307
|
-
|
|
8308
|
-
// Update color management state
|
|
8309
|
-
if (state.legacy !== legacy) state.set(() => ({
|
|
8310
|
-
legacy
|
|
8311
|
-
}));
|
|
8312
|
-
if (state.linear !== linear) state.set(() => ({
|
|
8313
|
-
linear
|
|
8314
|
-
}));
|
|
8315
|
-
if (state.flat !== flat) state.set(() => ({
|
|
8316
|
-
flat
|
|
8317
|
-
}));
|
|
8318
|
-
|
|
8319
|
-
// Set gl props
|
|
8320
|
-
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig);
|
|
8321
|
-
|
|
8322
|
-
// Set locals
|
|
8323
|
-
onCreated = onCreatedCallback;
|
|
8324
|
-
};
|
|
8325
|
-
const fail = error => {
|
|
8326
|
-
const failure = rejected(error);
|
|
8327
|
-
root.ready = failure;
|
|
8328
|
-
return failure;
|
|
8582
|
+
applyRootConfiguration(root, canvas, props);
|
|
8583
|
+
// Only a range, including the default one, follows the display: a fixed dpr never touches matchMedia
|
|
8584
|
+
if (!root.unwatchDpr && (props.dpr === undefined || Array.isArray(props.dpr))) root.unwatchDpr = followDpr(root);
|
|
8585
|
+
resolve(this);
|
|
8329
8586
|
};
|
|
8330
|
-
const run =
|
|
8587
|
+
const run = () => {
|
|
8331
8588
|
try {
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8589
|
+
var _store$getState$gl;
|
|
8590
|
+
const gl = (_store$getState$gl = store.getState().gl) != null ? _store$getState$gl : createRenderer(canvas, props.gl);
|
|
8591
|
+
// Only an async renderer factory makes configuration asynchronous
|
|
8592
|
+
if (isPromiseLike(gl)) Promise.resolve(gl).then(apply).catch(reject);else apply(gl);
|
|
8335
8593
|
} catch (error) {
|
|
8336
|
-
|
|
8594
|
+
reject(error);
|
|
8337
8595
|
}
|
|
8338
8596
|
};
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
if (store.getState().gl) return run();
|
|
8342
|
-
|
|
8343
|
-
// Another configure is creating it. Chaining keeps them in call order
|
|
8344
|
-
if (root.ready.status === 'pending') return tracked(root.ready.then(() => run()));
|
|
8345
|
-
|
|
8346
|
-
// Only an async factory makes configure asynchronous
|
|
8347
|
-
let customRenderer;
|
|
8348
|
-
try {
|
|
8349
|
-
customRenderer = typeof glConfig === 'function' ? glConfig(defaultProps) : glConfig;
|
|
8350
|
-
} catch (error) {
|
|
8351
|
-
return fail(error);
|
|
8352
|
-
}
|
|
8353
|
-
if (!isPromiseLike(customRenderer)) return run(customRenderer);
|
|
8354
|
-
const configuring = tracked(customRenderer.then(run, fail));
|
|
8355
|
-
root.ready = configuring;
|
|
8356
|
-
return configuring;
|
|
8597
|
+
if (previous.status === 'pending') previous.then(run, reject);else run();
|
|
8598
|
+
return promise;
|
|
8357
8599
|
},
|
|
8358
8600
|
render(children) {
|
|
8359
|
-
if (
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
rootElement: canvas
|
|
8367
|
-
});
|
|
8601
|
+
if (!transitionRoot(root, {
|
|
8602
|
+
type: 'use'
|
|
8603
|
+
})) return store;
|
|
8604
|
+
|
|
8605
|
+
// The root has to be configured before it can be rendered
|
|
8606
|
+
if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
|
|
8607
|
+
if (root.ready.status === 'rejected') throw root.ready.reason;
|
|
8368
8608
|
const commit = () => {
|
|
8369
|
-
|
|
8370
|
-
if (
|
|
8609
|
+
var _root$configuration$p;
|
|
8610
|
+
if (root.state.status !== 'open' || root.ready.status === 'rejected') return;
|
|
8611
|
+
// Wait for all queued configuration, including any queued while waiting
|
|
8612
|
+
if (root.ready.status === 'pending') {
|
|
8613
|
+
root.ready.then(commit, logRecoverableError);
|
|
8614
|
+
return;
|
|
8615
|
+
}
|
|
8616
|
+
const onCreated = (_root$configuration$p = root.configuration.previous) == null ? void 0 : _root$configuration$p.onCreated;
|
|
8617
|
+
const element = /*#__PURE__*/jsxRuntime.jsx(Provider, {
|
|
8618
|
+
store: store,
|
|
8619
|
+
children: children,
|
|
8620
|
+
onCreated: onCreated,
|
|
8621
|
+
rootElement: canvas
|
|
8622
|
+
});
|
|
8371
8623
|
if (mounted) {
|
|
8372
8624
|
reconciler.updateContainer(element, fiber, null, noop);
|
|
8373
8625
|
return;
|
|
@@ -8379,22 +8631,11 @@ function createRoot(canvas) {
|
|
|
8379
8631
|
// @ts-ignore - reconciler types are not maintained
|
|
8380
8632
|
reconciler.flushSyncWork();
|
|
8381
8633
|
};
|
|
8382
|
-
|
|
8383
|
-
// The root has to be configured before it can be rendered
|
|
8384
|
-
if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
|
|
8385
|
-
switch (root.ready.status) {
|
|
8386
|
-
case 'pending':
|
|
8387
|
-
root.ready.then(commit, logRecoverableError);
|
|
8388
|
-
break;
|
|
8389
|
-
case 'rejected':
|
|
8390
|
-
throw root.ready.reason;
|
|
8391
|
-
default:
|
|
8392
|
-
commit();
|
|
8393
|
-
}
|
|
8634
|
+
commit();
|
|
8394
8635
|
return store;
|
|
8395
8636
|
},
|
|
8396
8637
|
unmount() {
|
|
8397
|
-
unmountComponentAtNode(canvas);
|
|
8638
|
+
if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
|
|
8398
8639
|
}
|
|
8399
8640
|
};
|
|
8400
8641
|
}
|
|
@@ -8425,147 +8666,51 @@ function Provider({
|
|
|
8425
8666
|
children: children
|
|
8426
8667
|
});
|
|
8427
8668
|
}
|
|
8669
|
+
function attempt(step) {
|
|
8670
|
+
try {
|
|
8671
|
+
return step();
|
|
8672
|
+
} catch (error) {
|
|
8673
|
+
console.warn('[R3F] Error while unmounting root; teardown may be incomplete:', error);
|
|
8674
|
+
}
|
|
8675
|
+
}
|
|
8428
8676
|
function unmountComponentAtNode(canvas, callback) {
|
|
8429
8677
|
const root = _roots.get(canvas);
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8678
|
+
const token = Symbol('unmount');
|
|
8679
|
+
if (!root || !transitionRoot(root, {
|
|
8680
|
+
type: 'unmount',
|
|
8681
|
+
token
|
|
8682
|
+
})) return;
|
|
8683
|
+
const teardown = () => {
|
|
8684
|
+
var _state$gl;
|
|
8685
|
+
// Configuration accepted before the unmount finishes first, so a renderer it creates is released too
|
|
8686
|
+
if (root.ready.status === 'pending') {
|
|
8687
|
+
root.ready.then(teardown, teardown);
|
|
8688
|
+
return;
|
|
8689
|
+
}
|
|
8690
|
+
// Refused when the root was used again since this unmount
|
|
8691
|
+
if (!transitionRoot(root, {
|
|
8692
|
+
type: 'dispose',
|
|
8693
|
+
token
|
|
8694
|
+
})) return;
|
|
8695
|
+
// Close the gates before invoking user cleanup code.
|
|
8696
|
+
_roots.delete(canvas);
|
|
8697
|
+
const state = root.store.getState();
|
|
8698
|
+
state.internal.active = false;
|
|
8699
|
+
|
|
8700
|
+
// Release what uses the renderer before the renderer itself
|
|
8701
|
+
attempt(() => root.unwatchDpr == null ? void 0 : root.unwatchDpr());
|
|
8702
|
+
attempt(() => state.events.disconnect == null ? void 0 : state.events.disconnect());
|
|
8703
|
+
if ((_state$gl = state.gl) != null && _state$gl.xr) attempt(() => state.xr.disconnect());
|
|
8704
|
+
if (state.scene) attempt(() => dispose(state.scene));
|
|
8705
|
+
const disposal = attempt(() => releaseRenderer(state.gl, root.ownsRenderer));
|
|
8706
|
+
if (isPromiseLike(disposal)) disposal.then(() => callback == null ? void 0 : callback(canvas));else callback == null ? void 0 : callback(canvas);
|
|
8707
|
+
};
|
|
8434
8708
|
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
8435
|
-
|
|
8436
|
-
|
|
8709
|
+
// A root used again since the unmount keeps its new children
|
|
8710
|
+
if (root.state.status !== 'closing' || root.state.token !== token) return;
|
|
8437
8711
|
// Effect cleanups flush before the next update
|
|
8438
|
-
reconciler.updateContainer(null, root.fiber, null,
|
|
8439
|
-
if (root.unmountClaim !== claim) return;
|
|
8440
|
-
const teardown = () => {
|
|
8441
|
-
if (root.unmountClaim !== claim) return;
|
|
8442
|
-
root.unmountClaim = null;
|
|
8443
|
-
const state = root.store.getState();
|
|
8444
|
-
state.internal.active = false;
|
|
8445
|
-
try {
|
|
8446
|
-
var _state$gl, _state$gl$renderLists, _state$gl2, _state$gl3;
|
|
8447
|
-
state.events.disconnect == null ? void 0 : state.events.disconnect();
|
|
8448
|
-
(_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();
|
|
8449
|
-
(_state$gl2 = state.gl) == null ? void 0 : _state$gl2.forceContextLoss == null ? void 0 : _state$gl2.forceContextLoss();
|
|
8450
|
-
if ((_state$gl3 = state.gl) != null && _state$gl3.xr) state.xr.disconnect();
|
|
8451
|
-
dispose(state.scene);
|
|
8452
|
-
} catch (e) {
|
|
8453
|
-
/* ... */
|
|
8454
|
-
}
|
|
8455
|
-
_roots.delete(canvas);
|
|
8456
|
-
if (callback) callback(canvas);
|
|
8457
|
-
};
|
|
8458
|
-
|
|
8459
|
-
// A renderer still being created has to exist before it can be disposed
|
|
8460
|
-
if (root.ready.status === 'pending') root.ready.then(teardown, teardown);else teardown();
|
|
8461
|
-
});
|
|
8462
|
-
});
|
|
8463
|
-
}
|
|
8464
|
-
function createPortal(children, container, state) {
|
|
8465
|
-
return /*#__PURE__*/jsxRuntime.jsx(Portal, {
|
|
8466
|
-
children: children,
|
|
8467
|
-
container: container,
|
|
8468
|
-
state: state
|
|
8469
|
-
});
|
|
8470
|
-
}
|
|
8471
|
-
function Portal({
|
|
8472
|
-
state = {},
|
|
8473
|
-
children,
|
|
8474
|
-
container
|
|
8475
|
-
}) {
|
|
8476
|
-
/** This has to be a component because it would not be able to call useThree/useStore otherwise since
|
|
8477
|
-
* if this is our environment, then we are not in r3f's renderer but in react-dom, it would trigger
|
|
8478
|
-
* the "R3F hooks can only be used within the Canvas component!" warning:
|
|
8479
|
-
* <Canvas>
|
|
8480
|
-
* {createPortal(...)} */
|
|
8481
|
-
const {
|
|
8482
|
-
events,
|
|
8483
|
-
size,
|
|
8484
|
-
...rest
|
|
8485
|
-
} = state;
|
|
8486
|
-
const previousRoot = useStore();
|
|
8487
|
-
const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
|
|
8488
|
-
const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
|
|
8489
|
-
const inject = useMutableCallback((rootState, injectState) => {
|
|
8490
|
-
let viewport = undefined;
|
|
8491
|
-
if (injectState.camera && size) {
|
|
8492
|
-
const camera = injectState.camera;
|
|
8493
|
-
// Calculate the override viewport, if present
|
|
8494
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
|
|
8495
|
-
// Update the portal camera, if it differs from the previous layer
|
|
8496
|
-
if (camera !== rootState.camera) updateCamera(camera, size);
|
|
8497
|
-
}
|
|
8498
|
-
return {
|
|
8499
|
-
// The intersect consists of the previous root state
|
|
8500
|
-
...rootState,
|
|
8501
|
-
...injectState,
|
|
8502
|
-
// Portals have their own scene, which forms the root, a raycaster and a pointer
|
|
8503
|
-
scene: container,
|
|
8504
|
-
raycaster,
|
|
8505
|
-
pointer,
|
|
8506
|
-
mouse: pointer,
|
|
8507
|
-
// Their previous root is the layer before it
|
|
8508
|
-
previousRoot,
|
|
8509
|
-
// Events, size and viewport can be overridden by the inject layer
|
|
8510
|
-
events: {
|
|
8511
|
-
...rootState.events,
|
|
8512
|
-
...injectState.events,
|
|
8513
|
-
...events
|
|
8514
|
-
},
|
|
8515
|
-
size: {
|
|
8516
|
-
...rootState.size,
|
|
8517
|
-
...size
|
|
8518
|
-
},
|
|
8519
|
-
viewport: {
|
|
8520
|
-
...rootState.viewport,
|
|
8521
|
-
...viewport
|
|
8522
|
-
},
|
|
8523
|
-
// Layers are allowed to override events
|
|
8524
|
-
setEvents: events => injectState.set(state => ({
|
|
8525
|
-
...state,
|
|
8526
|
-
events: {
|
|
8527
|
-
...state.events,
|
|
8528
|
-
...events
|
|
8529
|
-
}
|
|
8530
|
-
}))
|
|
8531
|
-
};
|
|
8712
|
+
reconciler.updateContainer(null, root.fiber, null, teardown);
|
|
8532
8713
|
});
|
|
8533
|
-
const usePortalStore = React__namespace.useMemo(() => {
|
|
8534
|
-
// Create a mirrored store, based on the previous root with a few overrides ...
|
|
8535
|
-
const store = traditional.createWithEqualityFn((set, get) => ({
|
|
8536
|
-
...rest,
|
|
8537
|
-
set,
|
|
8538
|
-
get
|
|
8539
|
-
}));
|
|
8540
|
-
|
|
8541
|
-
// Subscribe to previous root-state and copy changes over to the mirrored portal-state
|
|
8542
|
-
const onMutate = prev => store.setState(state => inject.current(prev, state));
|
|
8543
|
-
onMutate(previousRoot.getState());
|
|
8544
|
-
previousRoot.subscribe(onMutate);
|
|
8545
|
-
return store;
|
|
8546
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8547
|
-
}, [previousRoot, container]);
|
|
8548
|
-
return (
|
|
8549
|
-
/*#__PURE__*/
|
|
8550
|
-
// @ts-ignore, reconciler types are not maintained
|
|
8551
|
-
jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
8552
|
-
children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
|
|
8553
|
-
value: usePortalStore,
|
|
8554
|
-
children: children
|
|
8555
|
-
}), usePortalStore, null)
|
|
8556
|
-
})
|
|
8557
|
-
);
|
|
8558
|
-
}
|
|
8559
|
-
|
|
8560
|
-
/**
|
|
8561
|
-
* Force React to flush any updates inside the provided callback synchronously and immediately.
|
|
8562
|
-
* All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
|
|
8563
|
-
* Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
|
|
8564
|
-
* having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
|
|
8565
|
-
*/
|
|
8566
|
-
function flushSync(fn) {
|
|
8567
|
-
// @ts-ignore - reconciler types are not maintained
|
|
8568
|
-
return reconciler.flushSyncFromReconciler(fn);
|
|
8569
8714
|
}
|
|
8570
8715
|
|
|
8571
8716
|
function createSubs(callback, subs) {
|
|
@@ -8720,6 +8865,141 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
|
8720
8865
|
if (runGlobalEffects) flushGlobalEffects('after', timestamp);
|
|
8721
8866
|
}
|
|
8722
8867
|
|
|
8868
|
+
function createPortal(children, container, state) {
|
|
8869
|
+
return /*#__PURE__*/jsxRuntime.jsx(Portal, {
|
|
8870
|
+
children: children,
|
|
8871
|
+
container: container,
|
|
8872
|
+
state: state
|
|
8873
|
+
});
|
|
8874
|
+
}
|
|
8875
|
+
function initializePortal(options, initialState) {
|
|
8876
|
+
const {
|
|
8877
|
+
parentStore,
|
|
8878
|
+
container
|
|
8879
|
+
} = options;
|
|
8880
|
+
const portalStore = traditional.createWithEqualityFn((set, get) => ({
|
|
8881
|
+
...initialState,
|
|
8882
|
+
set,
|
|
8883
|
+
get,
|
|
8884
|
+
// Create once with the store's setter, without retaining a state snapshot.
|
|
8885
|
+
setEvents: events => set(state => ({
|
|
8886
|
+
...state,
|
|
8887
|
+
events: {
|
|
8888
|
+
...state.events,
|
|
8889
|
+
...events
|
|
8890
|
+
}
|
|
8891
|
+
}))
|
|
8892
|
+
}));
|
|
8893
|
+
const parentStateRef = {
|
|
8894
|
+
current: parentStore.getState()
|
|
8895
|
+
};
|
|
8896
|
+
portalStore.setState(portalState => inject(parentStateRef.current, portalState, options));
|
|
8897
|
+
return {
|
|
8898
|
+
parentStore,
|
|
8899
|
+
container,
|
|
8900
|
+
portalStore,
|
|
8901
|
+
parentStateRef
|
|
8902
|
+
};
|
|
8903
|
+
}
|
|
8904
|
+
function Portal({
|
|
8905
|
+
state = {},
|
|
8906
|
+
children,
|
|
8907
|
+
container
|
|
8908
|
+
}) {
|
|
8909
|
+
const parentStore = useStore();
|
|
8910
|
+
const {
|
|
8911
|
+
events,
|
|
8912
|
+
size,
|
|
8913
|
+
...rest
|
|
8914
|
+
} = state;
|
|
8915
|
+
const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
|
|
8916
|
+
const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
|
|
8917
|
+
const options = {
|
|
8918
|
+
parentStore,
|
|
8919
|
+
container,
|
|
8920
|
+
raycaster,
|
|
8921
|
+
pointer,
|
|
8922
|
+
events,
|
|
8923
|
+
size
|
|
8924
|
+
};
|
|
8925
|
+
const injectRef = useMutableCallback((parentState, portalState) => inject(parentState, portalState, options));
|
|
8926
|
+
|
|
8927
|
+
// Initialize during render. Keep the store in state so Activity can preserve it.
|
|
8928
|
+
const [portal, setPortal] = React__namespace.useState(() => initializePortal(options, rest));
|
|
8929
|
+
if (portal.parentStore !== parentStore || portal.container !== container) {
|
|
8930
|
+
setPortal(initializePortal(options, rest));
|
|
8931
|
+
}
|
|
8932
|
+
const {
|
|
8933
|
+
portalStore,
|
|
8934
|
+
parentStateRef
|
|
8935
|
+
} = portal;
|
|
8936
|
+
|
|
8937
|
+
// Subscribe after commit and update the portal on each parent change.
|
|
8938
|
+
useIsomorphicLayoutEffect(() => {
|
|
8939
|
+
const update = parentState => {
|
|
8940
|
+
parentStateRef.current = parentState;
|
|
8941
|
+
portalStore.setState(portalState => injectRef.current(parentState, portalState));
|
|
8942
|
+
};
|
|
8943
|
+
const unsubscribe = parentStore.subscribe(update);
|
|
8944
|
+
|
|
8945
|
+
// Catch up on changes made before subscribing or while Activity was hidden.
|
|
8946
|
+
const parentState = parentStore.getState();
|
|
8947
|
+
if (parentState !== parentStateRef.current) update(parentState);
|
|
8948
|
+
|
|
8949
|
+
// Clean up when hidden, unmounted or switching stores.
|
|
8950
|
+
return unsubscribe;
|
|
8951
|
+
}, [parentStore, portalStore, parentStateRef]);
|
|
8952
|
+
return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
8953
|
+
children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
|
|
8954
|
+
value: portalStore,
|
|
8955
|
+
children: children
|
|
8956
|
+
}), portalStore, null)
|
|
8957
|
+
});
|
|
8958
|
+
}
|
|
8959
|
+
function inject(parentState, portalState, options) {
|
|
8960
|
+
const {
|
|
8961
|
+
parentStore,
|
|
8962
|
+
container,
|
|
8963
|
+
raycaster,
|
|
8964
|
+
pointer,
|
|
8965
|
+
events,
|
|
8966
|
+
size
|
|
8967
|
+
} = options;
|
|
8968
|
+
let viewport = undefined;
|
|
8969
|
+
if (portalState.camera && size) {
|
|
8970
|
+
const camera = portalState.camera;
|
|
8971
|
+
// Calculate the override viewport, if present
|
|
8972
|
+
viewport = parentState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
|
|
8973
|
+
// Update the portal camera, if it differs from the previous layer
|
|
8974
|
+
if (camera !== parentState.camera) updateCamera(camera, size);
|
|
8975
|
+
}
|
|
8976
|
+
return {
|
|
8977
|
+
// Inherit parent values and preserve the portal's own state.
|
|
8978
|
+
...parentState,
|
|
8979
|
+
...portalState,
|
|
8980
|
+
// Portals have their own scene, raycaster and pointer.
|
|
8981
|
+
scene: container,
|
|
8982
|
+
raycaster,
|
|
8983
|
+
pointer,
|
|
8984
|
+
mouse: pointer,
|
|
8985
|
+
previousRoot: parentStore,
|
|
8986
|
+
// Apply the portal's event, size and viewport overrides.
|
|
8987
|
+
events: {
|
|
8988
|
+
...parentState.events,
|
|
8989
|
+
...portalState.events,
|
|
8990
|
+
...events
|
|
8991
|
+
},
|
|
8992
|
+
size: {
|
|
8993
|
+
...parentState.size,
|
|
8994
|
+
...size
|
|
8995
|
+
},
|
|
8996
|
+
viewport: {
|
|
8997
|
+
...parentState.viewport,
|
|
8998
|
+
...viewport
|
|
8999
|
+
}
|
|
9000
|
+
};
|
|
9001
|
+
}
|
|
9002
|
+
|
|
8723
9003
|
const DOM_EVENTS = {
|
|
8724
9004
|
onClick: ['click', false],
|
|
8725
9005
|
onContextMenu: ['contextmenu', false],
|