@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",
|
|
@@ -16138,6 +16599,27 @@ function G1() {
|
|
|
16138
16599
|
var J1 = G1();
|
|
16139
16600
|
const Z1 = $1(J1);
|
|
16140
16601
|
|
|
16602
|
+
/** Constructor registration and lookup for JSX elements. */
|
|
16603
|
+
|
|
16604
|
+
const catalogue = {};
|
|
16605
|
+
let i = 0;
|
|
16606
|
+
const toPascalCase = type => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
16607
|
+
function hasConstructor(name) {
|
|
16608
|
+
return name in catalogue;
|
|
16609
|
+
}
|
|
16610
|
+
function resolveConstructor(name) {
|
|
16611
|
+
return catalogue[name];
|
|
16612
|
+
}
|
|
16613
|
+
function extend(objects) {
|
|
16614
|
+
if (typeof objects === 'function') {
|
|
16615
|
+
const Component = `${i++}`;
|
|
16616
|
+
catalogue[Component] = objects;
|
|
16617
|
+
return Component;
|
|
16618
|
+
} else {
|
|
16619
|
+
Object.assign(catalogue, objects);
|
|
16620
|
+
}
|
|
16621
|
+
}
|
|
16622
|
+
|
|
16141
16623
|
function createReconciler(config) {
|
|
16142
16624
|
const reconciler = Z1(config);
|
|
16143
16625
|
|
|
@@ -16151,24 +16633,11 @@ const NoEventPriority = 0;
|
|
|
16151
16633
|
// https://github.com/pmndrs/react-three-fiber/pull/2931
|
|
16152
16634
|
// https://github.com/microsoft/TypeScript/issues/37079
|
|
16153
16635
|
|
|
16154
|
-
const catalogue = {};
|
|
16155
16636
|
const PREFIX_REGEX = /^three(?=[A-Z])/;
|
|
16156
|
-
const toPascalCase = type => `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
16157
|
-
let i = 0;
|
|
16158
|
-
const isConstructor = object => typeof object === 'function';
|
|
16159
|
-
function extend(objects) {
|
|
16160
|
-
if (isConstructor(objects)) {
|
|
16161
|
-
const Component = `${i++}`;
|
|
16162
|
-
catalogue[Component] = objects;
|
|
16163
|
-
return Component;
|
|
16164
|
-
} else {
|
|
16165
|
-
Object.assign(catalogue, objects);
|
|
16166
|
-
}
|
|
16167
|
-
}
|
|
16168
16637
|
function validateInstance(type, props) {
|
|
16169
16638
|
// Get target from catalogue
|
|
16170
16639
|
const name = toPascalCase(type);
|
|
16171
|
-
const target =
|
|
16640
|
+
const target = resolveConstructor(name);
|
|
16172
16641
|
|
|
16173
16642
|
// Validate element target
|
|
16174
16643
|
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`);
|
|
@@ -16182,7 +16651,7 @@ function validateInstance(type, props) {
|
|
|
16182
16651
|
function createInstance(type, props, root) {
|
|
16183
16652
|
var _props$object;
|
|
16184
16653
|
// Remove three* prefix from elements if native element not present
|
|
16185
|
-
type = toPascalCase(type)
|
|
16654
|
+
type = hasConstructor(toPascalCase(type)) ? type : type.replace(PREFIX_REGEX, '');
|
|
16186
16655
|
validateInstance(type, props);
|
|
16187
16656
|
|
|
16188
16657
|
// Regenerate the R3F instance for primitives to simulate a new object
|
|
@@ -16195,6 +16664,7 @@ function hideInstance(instance) {
|
|
|
16195
16664
|
if (instance.props.attach && (_instance$parent = instance.parent) != null && _instance$parent.object) {
|
|
16196
16665
|
detach(instance.parent, instance);
|
|
16197
16666
|
} else if (isObject3D(instance.object)) {
|
|
16667
|
+
instance.previousVisible = instance.object.visible;
|
|
16198
16668
|
instance.object.visible = false;
|
|
16199
16669
|
}
|
|
16200
16670
|
instance.isHidden = true;
|
|
@@ -16206,9 +16676,11 @@ function unhideInstance(instance) {
|
|
|
16206
16676
|
var _instance$parent2;
|
|
16207
16677
|
if (instance.props.attach && (_instance$parent2 = instance.parent) != null && _instance$parent2.object) {
|
|
16208
16678
|
attach(instance.parent, instance);
|
|
16209
|
-
} else if (isObject3D(instance.object)
|
|
16210
|
-
|
|
16679
|
+
} else if (isObject3D(instance.object)) {
|
|
16680
|
+
var _instance$previousVis;
|
|
16681
|
+
instance.object.visible = (_instance$previousVis = instance.previousVisible) != null ? _instance$previousVis : true;
|
|
16211
16682
|
}
|
|
16683
|
+
instance.previousVisible = undefined;
|
|
16212
16684
|
instance.isHidden = false;
|
|
16213
16685
|
invalidateInstance(instance);
|
|
16214
16686
|
}
|
|
@@ -16226,7 +16698,7 @@ function handleContainerEffects(parent, child, beforeChild) {
|
|
|
16226
16698
|
if (!child.object) {
|
|
16227
16699
|
var _child$props$object, _child$props$args;
|
|
16228
16700
|
// Get target from catalogue
|
|
16229
|
-
const target =
|
|
16701
|
+
const target = resolveConstructor(toPascalCase(child.type));
|
|
16230
16702
|
|
|
16231
16703
|
// Create object
|
|
16232
16704
|
child.object = (_child$props$object = child.props.object) != null ? _child$props$object : new target(...((_child$props$args = child.props.args) != null ? _child$props$args : []));
|
|
@@ -16323,6 +16795,9 @@ function disposeOnIdle(object) {
|
|
|
16323
16795
|
function removeChild(parent, child, dispose) {
|
|
16324
16796
|
if (!child) return;
|
|
16325
16797
|
|
|
16798
|
+
// Unlinking clears the parent, which invalidateInstance checks, so remember it
|
|
16799
|
+
const wasLinked = !!child.parent;
|
|
16800
|
+
|
|
16326
16801
|
// Unlink instances
|
|
16327
16802
|
child.parent = null;
|
|
16328
16803
|
const childIndex = parent.children.indexOf(child);
|
|
@@ -16360,7 +16835,11 @@ function removeChild(parent, child, dispose) {
|
|
|
16360
16835
|
}
|
|
16361
16836
|
|
|
16362
16837
|
// Tree was updated, request a frame for top-level instance
|
|
16363
|
-
if (dispose === undefined)
|
|
16838
|
+
if (dispose === undefined && wasLinked) {
|
|
16839
|
+
var _child$root;
|
|
16840
|
+
const state = (_child$root = child.root) == null ? void 0 : _child$root.getState == null ? void 0 : _child$root.getState();
|
|
16841
|
+
if (state && state.internal.frames === 0) state.invalidate();
|
|
16842
|
+
}
|
|
16364
16843
|
}
|
|
16365
16844
|
function setFiberRef(fiber, publicInstance) {
|
|
16366
16845
|
for (const _fiber of [fiber, fiber.alternate]) {
|
|
@@ -16421,7 +16900,7 @@ function swapReconstructedInstances() {
|
|
|
16421
16900
|
if (parent) {
|
|
16422
16901
|
var _instance$props$objec, _instance$props$args;
|
|
16423
16902
|
// Get target from catalogue
|
|
16424
|
-
const target =
|
|
16903
|
+
const target = resolveConstructor(toPascalCase(instance.type));
|
|
16425
16904
|
|
|
16426
16905
|
// Create object
|
|
16427
16906
|
const prevObject = instance.object;
|
|
@@ -16753,76 +17232,49 @@ const reconciler = /* @__PURE__ */createReconciler({
|
|
|
16753
17232
|
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
16754
17233
|
});
|
|
16755
17234
|
|
|
16756
|
-
|
|
16757
|
-
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
promise.catch(() => {}); // the reason is read from `status`
|
|
16767
|
-
return Object.assign(promise, {
|
|
16768
|
-
status: 'rejected',
|
|
16769
|
-
reason
|
|
16770
|
-
});
|
|
16771
|
-
};
|
|
16772
|
-
|
|
16773
|
-
/** Tags `promise` in place once it settles. */
|
|
16774
|
-
const tracked = promise => {
|
|
16775
|
-
const result = Promise.resolve(promise);
|
|
16776
|
-
result.status = 'pending';
|
|
16777
|
-
// Statement bodies: returning `result` would make this derived promise adopt its rejection
|
|
16778
|
-
result.then(value => {
|
|
16779
|
-
Object.assign(result, {
|
|
16780
|
-
status: 'fulfilled',
|
|
16781
|
-
value
|
|
16782
|
-
});
|
|
16783
|
-
}, reason => {
|
|
16784
|
-
Object.assign(result, {
|
|
16785
|
-
status: 'rejected',
|
|
16786
|
-
reason
|
|
16787
|
-
});
|
|
16788
|
-
});
|
|
16789
|
-
return result;
|
|
16790
|
-
};
|
|
17235
|
+
/**
|
|
17236
|
+
* Force React to flush any updates inside the provided callback synchronously and immediately.
|
|
17237
|
+
* All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
|
|
17238
|
+
* Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
|
|
17239
|
+
* having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
|
|
17240
|
+
*/
|
|
17241
|
+
function flushSync(fn) {
|
|
17242
|
+
// @ts-ignore - reconciler types are not maintained
|
|
17243
|
+
return reconciler.flushSyncFromReconciler(fn);
|
|
17244
|
+
}
|
|
16791
17245
|
|
|
16792
17246
|
const _roots = new Map();
|
|
16793
|
-
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
17247
|
+
/**
|
|
17248
|
+
* open -> closing -> disposed
|
|
17249
|
+
* | use
|
|
17250
|
+
* v
|
|
17251
|
+
* open
|
|
17252
|
+
*
|
|
17253
|
+
* Only closing can be cancelled. Each unmount carries a token, so only the latest one can dispose.
|
|
17254
|
+
*/
|
|
17255
|
+
function transitionRoot(root, event) {
|
|
17256
|
+
const state = root.state;
|
|
17257
|
+
switch (event.type) {
|
|
17258
|
+
case 'use':
|
|
17259
|
+
if (state.status === 'disposed') return false;
|
|
17260
|
+
root.state = {
|
|
17261
|
+
status: 'open'
|
|
17262
|
+
};
|
|
17263
|
+
return true;
|
|
17264
|
+
case 'unmount':
|
|
17265
|
+
if (state.status === 'disposed') return false;
|
|
17266
|
+
root.state = {
|
|
17267
|
+
status: 'closing',
|
|
17268
|
+
token: event.token
|
|
17269
|
+
};
|
|
17270
|
+
return true;
|
|
17271
|
+
case 'dispose':
|
|
17272
|
+
if (state.status !== 'closing' || state.token !== event.token) return false;
|
|
17273
|
+
root.state = {
|
|
17274
|
+
status: 'disposed'
|
|
17275
|
+
};
|
|
17276
|
+
return true;
|
|
16818
17277
|
}
|
|
16819
|
-
return {
|
|
16820
|
-
width: 0,
|
|
16821
|
-
height: 0,
|
|
16822
|
-
top: 0,
|
|
16823
|
-
left: 0,
|
|
16824
|
-
...size
|
|
16825
|
-
};
|
|
16826
17278
|
}
|
|
16827
17279
|
function createRoot(canvas) {
|
|
16828
17280
|
// Check against mistaken use of createRoot
|
|
@@ -16867,286 +17319,86 @@ function createRoot(canvas) {
|
|
|
16867
17319
|
const root = prevRoot || {
|
|
16868
17320
|
fiber,
|
|
16869
17321
|
store,
|
|
16870
|
-
|
|
16871
|
-
|
|
17322
|
+
state: {
|
|
17323
|
+
status: 'open'
|
|
17324
|
+
},
|
|
17325
|
+
ready: fulfilled(undefined),
|
|
17326
|
+
configuration: {},
|
|
17327
|
+
ownsRenderer: false
|
|
16872
17328
|
};
|
|
16873
17329
|
if (!prevRoot) _roots.set(canvas, root);
|
|
16874
|
-
|
|
16875
|
-
// Locals
|
|
16876
|
-
let onCreated;
|
|
16877
|
-
let lastCamera;
|
|
16878
17330
|
let mounted = false;
|
|
16879
17331
|
return {
|
|
16880
17332
|
get ready() {
|
|
16881
17333
|
return root.ready;
|
|
16882
17334
|
},
|
|
16883
17335
|
configure(props = {}) {
|
|
16884
|
-
root
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
events,
|
|
16890
|
-
onCreated: onCreatedCallback,
|
|
16891
|
-
shadows = false,
|
|
16892
|
-
linear = false,
|
|
16893
|
-
flat = false,
|
|
16894
|
-
legacy = false,
|
|
16895
|
-
orthographic = false,
|
|
16896
|
-
frameloop = 'always',
|
|
16897
|
-
dpr = [1, 2],
|
|
16898
|
-
performance,
|
|
16899
|
-
raycaster: raycastOptions,
|
|
16900
|
-
camera: cameraOptions,
|
|
16901
|
-
onPointerMissed
|
|
16902
|
-
} = props;
|
|
16903
|
-
const defaultProps = {
|
|
16904
|
-
canvas: canvas,
|
|
16905
|
-
powerPreference: 'high-performance',
|
|
16906
|
-
antialias: true,
|
|
16907
|
-
alpha: true
|
|
16908
|
-
};
|
|
17336
|
+
if (!transitionRoot(root, {
|
|
17337
|
+
type: 'use'
|
|
17338
|
+
})) {
|
|
17339
|
+
return rejected(new Error('R3F: Cannot configure a root after disposal has started.'));
|
|
17340
|
+
}
|
|
16909
17341
|
|
|
16910
|
-
//
|
|
16911
|
-
const
|
|
17342
|
+
// Configuration applies in call order. Publishing first queues calls made while this one runs
|
|
17343
|
+
const previous = root.ready;
|
|
17344
|
+
const {
|
|
17345
|
+
promise,
|
|
17346
|
+
resolve,
|
|
17347
|
+
reject
|
|
17348
|
+
} = deferred();
|
|
17349
|
+
root.ready = promise;
|
|
17350
|
+
const apply = gl => {
|
|
16912
17351
|
const state = store.getState();
|
|
16913
|
-
|
|
16914
17352
|
// Set up renderer (one time only!)
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
...defaultProps,
|
|
16920
|
-
...glConfig
|
|
16921
|
-
});
|
|
16922
|
-
state.set({
|
|
16923
|
-
gl
|
|
16924
|
-
});
|
|
16925
|
-
}
|
|
16926
|
-
|
|
16927
|
-
// Set up raycaster (one time only!)
|
|
16928
|
-
let raycaster = state.raycaster;
|
|
16929
|
-
if (!raycaster) state.set({
|
|
16930
|
-
raycaster: raycaster = new THREE__namespace.Raycaster()
|
|
16931
|
-
});
|
|
16932
|
-
|
|
16933
|
-
// Set raycaster options
|
|
16934
|
-
const {
|
|
16935
|
-
params,
|
|
16936
|
-
...options
|
|
16937
|
-
} = raycastOptions || {};
|
|
16938
|
-
if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, {
|
|
16939
|
-
...options
|
|
16940
|
-
});
|
|
16941
|
-
if (!is.equ(params, raycaster.params, shallowLoose)) applyProps(raycaster, {
|
|
16942
|
-
params: {
|
|
16943
|
-
...raycaster.params,
|
|
16944
|
-
...params
|
|
16945
|
-
}
|
|
16946
|
-
});
|
|
16947
|
-
|
|
16948
|
-
// Create default camera, don't overwrite any user-set state
|
|
16949
|
-
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
16950
|
-
lastCamera = cameraOptions;
|
|
16951
|
-
const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
|
|
16952
|
-
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);
|
|
16953
|
-
if (!isCamera) {
|
|
16954
|
-
camera.position.z = 5;
|
|
16955
|
-
if (cameraOptions) {
|
|
16956
|
-
applyProps(camera, cameraOptions);
|
|
16957
|
-
// Preserve user-defined frustum if possible
|
|
16958
|
-
// https://github.com/pmndrs/react-three-fiber/issues/3160
|
|
16959
|
-
if (!camera.manual) {
|
|
16960
|
-
if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
|
|
16961
|
-
camera.manual = true;
|
|
16962
|
-
camera.updateProjectionMatrix();
|
|
16963
|
-
}
|
|
16964
|
-
}
|
|
16965
|
-
}
|
|
16966
|
-
// Always look at center by default
|
|
16967
|
-
if (!state.camera && !(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
|
|
16968
|
-
}
|
|
16969
|
-
state.set({
|
|
16970
|
-
camera
|
|
16971
|
-
});
|
|
16972
|
-
|
|
16973
|
-
// Configure raycaster
|
|
16974
|
-
// https://github.com/pmndrs/react-xr/issues/300
|
|
16975
|
-
raycaster.camera = camera;
|
|
16976
|
-
}
|
|
16977
|
-
|
|
16978
|
-
// Set up scene (one time only!)
|
|
16979
|
-
if (!state.scene) {
|
|
16980
|
-
let scene;
|
|
16981
|
-
if (sceneOptions != null && sceneOptions.isScene) {
|
|
16982
|
-
scene = sceneOptions;
|
|
16983
|
-
prepare(scene, store, '', {});
|
|
16984
|
-
} else {
|
|
16985
|
-
scene = new THREE__namespace.Scene();
|
|
16986
|
-
prepare(scene, store, '', {});
|
|
16987
|
-
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
16988
|
-
}
|
|
16989
|
-
state.set({
|
|
16990
|
-
scene
|
|
16991
|
-
});
|
|
16992
|
-
}
|
|
16993
|
-
|
|
16994
|
-
// Store events internally
|
|
16995
|
-
if (events && !state.events.handlers) state.set({
|
|
16996
|
-
events: events(store)
|
|
16997
|
-
});
|
|
16998
|
-
// Check size, allow it to take on container bounds initially
|
|
16999
|
-
const size = computeInitialSize(canvas, propsSize);
|
|
17000
|
-
if (!is.equ(size, state.size, shallowLoose)) {
|
|
17001
|
-
state.setSize(size.width, size.height, size.top, size.left);
|
|
17002
|
-
}
|
|
17003
|
-
// Check pixelratio
|
|
17004
|
-
if (dpr && state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
17005
|
-
// Check frameloop
|
|
17006
|
-
if (state.frameloop !== frameloop) state.setFrameloop(frameloop);
|
|
17007
|
-
// Check pointer missed
|
|
17008
|
-
if (!state.onPointerMissed) state.set({
|
|
17009
|
-
onPointerMissed
|
|
17010
|
-
});
|
|
17011
|
-
// Check performance
|
|
17012
|
-
if (performance && !is.equ(performance, state.performance, shallowLoose)) state.set(state => ({
|
|
17013
|
-
performance: {
|
|
17014
|
-
...state.performance,
|
|
17015
|
-
...performance
|
|
17016
|
-
}
|
|
17017
|
-
}));
|
|
17018
|
-
|
|
17019
|
-
// Set up XR (one time only!)
|
|
17020
|
-
if (!state.xr) {
|
|
17021
|
-
var _gl$xr;
|
|
17022
|
-
// Handle frame behavior in WebXR
|
|
17023
|
-
const handleXRFrame = (timestamp, frame) => {
|
|
17024
|
-
const state = store.getState();
|
|
17025
|
-
if (state.frameloop === 'never') return;
|
|
17026
|
-
advance(timestamp, true, state, frame);
|
|
17027
|
-
};
|
|
17028
|
-
|
|
17029
|
-
// Toggle render switching on session
|
|
17030
|
-
const handleSessionChange = () => {
|
|
17031
|
-
const state = store.getState();
|
|
17032
|
-
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
17033
|
-
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
17034
|
-
if (!state.gl.xr.isPresenting) invalidate(state);
|
|
17035
|
-
};
|
|
17036
|
-
|
|
17037
|
-
// WebXR session manager
|
|
17038
|
-
const xr = {
|
|
17039
|
-
connect() {
|
|
17040
|
-
const gl = store.getState().gl;
|
|
17041
|
-
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
17042
|
-
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
17043
|
-
},
|
|
17044
|
-
disconnect() {
|
|
17045
|
-
const gl = store.getState().gl;
|
|
17046
|
-
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
17047
|
-
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
17048
|
-
}
|
|
17049
|
-
};
|
|
17050
|
-
|
|
17051
|
-
// Subscribe to WebXR session events
|
|
17052
|
-
if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
|
|
17353
|
+
if (!state.gl) {
|
|
17354
|
+
// R3F owns what it builds, a factory's result included, since it calls the factory
|
|
17355
|
+
// once per root. A renderer instance belongs to the caller
|
|
17356
|
+
root.ownsRenderer = !isRenderer(props.gl);
|
|
17053
17357
|
state.set({
|
|
17054
|
-
|
|
17358
|
+
gl: gl
|
|
17055
17359
|
});
|
|
17056
17360
|
}
|
|
17057
|
-
|
|
17058
|
-
//
|
|
17059
|
-
if (
|
|
17060
|
-
|
|
17061
|
-
const oldType = gl.shadowMap.type;
|
|
17062
|
-
gl.shadowMap.enabled = !!shadows;
|
|
17063
|
-
if (is.boo(shadows)) {
|
|
17064
|
-
gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
17065
|
-
} else if (is.str(shadows)) {
|
|
17066
|
-
var _types$shadows;
|
|
17067
|
-
const types = {
|
|
17068
|
-
basic: THREE__namespace.BasicShadowMap,
|
|
17069
|
-
percentage: THREE__namespace.PCFShadowMap,
|
|
17070
|
-
soft: THREE__namespace.PCFSoftShadowMap,
|
|
17071
|
-
variance: THREE__namespace.VSMShadowMap
|
|
17072
|
-
};
|
|
17073
|
-
gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE__namespace.PCFSoftShadowMap;
|
|
17074
|
-
} else if (is.obj(shadows)) {
|
|
17075
|
-
Object.assign(gl.shadowMap, shadows);
|
|
17076
|
-
}
|
|
17077
|
-
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
17078
|
-
}
|
|
17079
|
-
THREE__namespace.ColorManagement.enabled = !legacy;
|
|
17080
|
-
|
|
17081
|
-
// Set color space and tonemapping preferences
|
|
17082
|
-
if (first) {
|
|
17083
|
-
gl.outputColorSpace = linear ? THREE__namespace.LinearSRGBColorSpace : THREE__namespace.SRGBColorSpace;
|
|
17084
|
-
gl.toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
|
|
17085
|
-
}
|
|
17086
|
-
|
|
17087
|
-
// Update color management state
|
|
17088
|
-
if (state.legacy !== legacy) state.set(() => ({
|
|
17089
|
-
legacy
|
|
17090
|
-
}));
|
|
17091
|
-
if (state.linear !== linear) state.set(() => ({
|
|
17092
|
-
linear
|
|
17093
|
-
}));
|
|
17094
|
-
if (state.flat !== flat) state.set(() => ({
|
|
17095
|
-
flat
|
|
17096
|
-
}));
|
|
17097
|
-
|
|
17098
|
-
// Set gl props
|
|
17099
|
-
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, gl, shallowLoose)) applyProps(gl, glConfig);
|
|
17100
|
-
|
|
17101
|
-
// Set locals
|
|
17102
|
-
onCreated = onCreatedCallback;
|
|
17361
|
+
applyRootConfiguration(root, canvas, props);
|
|
17362
|
+
// Only a range, including the default one, follows the display: a fixed dpr never touches matchMedia
|
|
17363
|
+
if (!root.unwatchDpr && (props.dpr === undefined || Array.isArray(props.dpr))) root.unwatchDpr = followDpr(root);
|
|
17364
|
+
resolve(this);
|
|
17103
17365
|
};
|
|
17104
|
-
const
|
|
17105
|
-
const failure = rejected(error);
|
|
17106
|
-
root.ready = failure;
|
|
17107
|
-
return failure;
|
|
17108
|
-
};
|
|
17109
|
-
const run = customRenderer => {
|
|
17366
|
+
const run = () => {
|
|
17110
17367
|
try {
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17368
|
+
var _store$getState$gl;
|
|
17369
|
+
const gl = (_store$getState$gl = store.getState().gl) != null ? _store$getState$gl : createRenderer(canvas, props.gl);
|
|
17370
|
+
// Only an async renderer factory makes configuration asynchronous
|
|
17371
|
+
if (isPromiseLike(gl)) Promise.resolve(gl).then(apply).catch(reject);else apply(gl);
|
|
17114
17372
|
} catch (error) {
|
|
17115
|
-
|
|
17373
|
+
reject(error);
|
|
17116
17374
|
}
|
|
17117
17375
|
};
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
if (store.getState().gl) return run();
|
|
17121
|
-
|
|
17122
|
-
// Another configure is creating it. Chaining keeps them in call order
|
|
17123
|
-
if (root.ready.status === 'pending') return tracked(root.ready.then(() => run()));
|
|
17124
|
-
|
|
17125
|
-
// Only an async factory makes configure asynchronous
|
|
17126
|
-
let customRenderer;
|
|
17127
|
-
try {
|
|
17128
|
-
customRenderer = typeof glConfig === 'function' ? glConfig(defaultProps) : glConfig;
|
|
17129
|
-
} catch (error) {
|
|
17130
|
-
return fail(error);
|
|
17131
|
-
}
|
|
17132
|
-
if (!isPromiseLike(customRenderer)) return run(customRenderer);
|
|
17133
|
-
const configuring = tracked(customRenderer.then(run, fail));
|
|
17134
|
-
root.ready = configuring;
|
|
17135
|
-
return configuring;
|
|
17376
|
+
if (previous.status === 'pending') previous.then(run, reject);else run();
|
|
17377
|
+
return promise;
|
|
17136
17378
|
},
|
|
17137
17379
|
render(children) {
|
|
17138
|
-
if (
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
rootElement: canvas
|
|
17146
|
-
});
|
|
17380
|
+
if (!transitionRoot(root, {
|
|
17381
|
+
type: 'use'
|
|
17382
|
+
})) return store;
|
|
17383
|
+
|
|
17384
|
+
// The root has to be configured before it can be rendered
|
|
17385
|
+
if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
|
|
17386
|
+
if (root.ready.status === 'rejected') throw root.ready.reason;
|
|
17147
17387
|
const commit = () => {
|
|
17148
|
-
|
|
17149
|
-
if (
|
|
17388
|
+
var _root$configuration$p;
|
|
17389
|
+
if (root.state.status !== 'open' || root.ready.status === 'rejected') return;
|
|
17390
|
+
// Wait for all queued configuration, including any queued while waiting
|
|
17391
|
+
if (root.ready.status === 'pending') {
|
|
17392
|
+
root.ready.then(commit, logRecoverableError);
|
|
17393
|
+
return;
|
|
17394
|
+
}
|
|
17395
|
+
const onCreated = (_root$configuration$p = root.configuration.previous) == null ? void 0 : _root$configuration$p.onCreated;
|
|
17396
|
+
const element = /*#__PURE__*/jsxRuntime.jsx(Provider, {
|
|
17397
|
+
store: store,
|
|
17398
|
+
children: children,
|
|
17399
|
+
onCreated: onCreated,
|
|
17400
|
+
rootElement: canvas
|
|
17401
|
+
});
|
|
17150
17402
|
if (mounted) {
|
|
17151
17403
|
reconciler.updateContainer(element, fiber, null, noop);
|
|
17152
17404
|
return;
|
|
@@ -17158,22 +17410,11 @@ function createRoot(canvas) {
|
|
|
17158
17410
|
// @ts-ignore - reconciler types are not maintained
|
|
17159
17411
|
reconciler.flushSyncWork();
|
|
17160
17412
|
};
|
|
17161
|
-
|
|
17162
|
-
// The root has to be configured before it can be rendered
|
|
17163
|
-
if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
|
|
17164
|
-
switch (root.ready.status) {
|
|
17165
|
-
case 'pending':
|
|
17166
|
-
root.ready.then(commit, logRecoverableError);
|
|
17167
|
-
break;
|
|
17168
|
-
case 'rejected':
|
|
17169
|
-
throw root.ready.reason;
|
|
17170
|
-
default:
|
|
17171
|
-
commit();
|
|
17172
|
-
}
|
|
17413
|
+
commit();
|
|
17173
17414
|
return store;
|
|
17174
17415
|
},
|
|
17175
17416
|
unmount() {
|
|
17176
|
-
unmountComponentAtNode(canvas);
|
|
17417
|
+
if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
|
|
17177
17418
|
}
|
|
17178
17419
|
};
|
|
17179
17420
|
}
|
|
@@ -17204,147 +17445,51 @@ function Provider({
|
|
|
17204
17445
|
children: children
|
|
17205
17446
|
});
|
|
17206
17447
|
}
|
|
17448
|
+
function attempt(step) {
|
|
17449
|
+
try {
|
|
17450
|
+
return step();
|
|
17451
|
+
} catch (error) {
|
|
17452
|
+
console.warn('[R3F] Error while unmounting root; teardown may be incomplete:', error);
|
|
17453
|
+
}
|
|
17454
|
+
}
|
|
17207
17455
|
function unmountComponentAtNode(canvas, callback) {
|
|
17208
17456
|
const root = _roots.get(canvas);
|
|
17209
|
-
|
|
17457
|
+
const token = Symbol('unmount');
|
|
17458
|
+
if (!root || !transitionRoot(root, {
|
|
17459
|
+
type: 'unmount',
|
|
17460
|
+
token
|
|
17461
|
+
})) return;
|
|
17462
|
+
const teardown = () => {
|
|
17463
|
+
var _state$gl;
|
|
17464
|
+
// Configuration accepted before the unmount finishes first, so a renderer it creates is released too
|
|
17465
|
+
if (root.ready.status === 'pending') {
|
|
17466
|
+
root.ready.then(teardown, teardown);
|
|
17467
|
+
return;
|
|
17468
|
+
}
|
|
17469
|
+
// Refused when the root was used again since this unmount
|
|
17470
|
+
if (!transitionRoot(root, {
|
|
17471
|
+
type: 'dispose',
|
|
17472
|
+
token
|
|
17473
|
+
})) return;
|
|
17474
|
+
// Close the gates before invoking user cleanup code.
|
|
17475
|
+
_roots.delete(canvas);
|
|
17476
|
+
const state = root.store.getState();
|
|
17477
|
+
state.internal.active = false;
|
|
17210
17478
|
|
|
17211
|
-
|
|
17212
|
-
|
|
17479
|
+
// Release what uses the renderer before the renderer itself
|
|
17480
|
+
attempt(() => root.unwatchDpr == null ? void 0 : root.unwatchDpr());
|
|
17481
|
+
attempt(() => state.events.disconnect == null ? void 0 : state.events.disconnect());
|
|
17482
|
+
if ((_state$gl = state.gl) != null && _state$gl.xr) attempt(() => state.xr.disconnect());
|
|
17483
|
+
if (state.scene) attempt(() => dispose(state.scene));
|
|
17484
|
+
const disposal = attempt(() => releaseRenderer(state.gl, root.ownsRenderer));
|
|
17485
|
+
if (isPromiseLike(disposal)) disposal.then(() => callback == null ? void 0 : callback(canvas));else callback == null ? void 0 : callback(canvas);
|
|
17486
|
+
};
|
|
17213
17487
|
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
17214
|
-
|
|
17215
|
-
|
|
17488
|
+
// A root used again since the unmount keeps its new children
|
|
17489
|
+
if (root.state.status !== 'closing' || root.state.token !== token) return;
|
|
17216
17490
|
// Effect cleanups flush before the next update
|
|
17217
|
-
reconciler.updateContainer(null, root.fiber, null,
|
|
17218
|
-
if (root.unmountClaim !== claim) return;
|
|
17219
|
-
const teardown = () => {
|
|
17220
|
-
if (root.unmountClaim !== claim) return;
|
|
17221
|
-
root.unmountClaim = null;
|
|
17222
|
-
const state = root.store.getState();
|
|
17223
|
-
state.internal.active = false;
|
|
17224
|
-
try {
|
|
17225
|
-
var _state$gl, _state$gl$renderLists, _state$gl2, _state$gl3;
|
|
17226
|
-
state.events.disconnect == null ? void 0 : state.events.disconnect();
|
|
17227
|
-
(_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();
|
|
17228
|
-
(_state$gl2 = state.gl) == null ? void 0 : _state$gl2.forceContextLoss == null ? void 0 : _state$gl2.forceContextLoss();
|
|
17229
|
-
if ((_state$gl3 = state.gl) != null && _state$gl3.xr) state.xr.disconnect();
|
|
17230
|
-
dispose(state.scene);
|
|
17231
|
-
} catch (e) {
|
|
17232
|
-
/* ... */
|
|
17233
|
-
}
|
|
17234
|
-
_roots.delete(canvas);
|
|
17235
|
-
if (callback) callback(canvas);
|
|
17236
|
-
};
|
|
17237
|
-
|
|
17238
|
-
// A renderer still being created has to exist before it can be disposed
|
|
17239
|
-
if (root.ready.status === 'pending') root.ready.then(teardown, teardown);else teardown();
|
|
17240
|
-
});
|
|
17241
|
-
});
|
|
17242
|
-
}
|
|
17243
|
-
function createPortal(children, container, state) {
|
|
17244
|
-
return /*#__PURE__*/jsxRuntime.jsx(Portal, {
|
|
17245
|
-
children: children,
|
|
17246
|
-
container: container,
|
|
17247
|
-
state: state
|
|
17248
|
-
});
|
|
17249
|
-
}
|
|
17250
|
-
function Portal({
|
|
17251
|
-
state = {},
|
|
17252
|
-
children,
|
|
17253
|
-
container
|
|
17254
|
-
}) {
|
|
17255
|
-
/** This has to be a component because it would not be able to call useThree/useStore otherwise since
|
|
17256
|
-
* if this is our environment, then we are not in r3f's renderer but in react-dom, it would trigger
|
|
17257
|
-
* the "R3F hooks can only be used within the Canvas component!" warning:
|
|
17258
|
-
* <Canvas>
|
|
17259
|
-
* {createPortal(...)} */
|
|
17260
|
-
const {
|
|
17261
|
-
events,
|
|
17262
|
-
size,
|
|
17263
|
-
...rest
|
|
17264
|
-
} = state;
|
|
17265
|
-
const previousRoot = useStore();
|
|
17266
|
-
const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
|
|
17267
|
-
const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
|
|
17268
|
-
const inject = useMutableCallback((rootState, injectState) => {
|
|
17269
|
-
let viewport = undefined;
|
|
17270
|
-
if (injectState.camera && size) {
|
|
17271
|
-
const camera = injectState.camera;
|
|
17272
|
-
// Calculate the override viewport, if present
|
|
17273
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
|
|
17274
|
-
// Update the portal camera, if it differs from the previous layer
|
|
17275
|
-
if (camera !== rootState.camera) updateCamera(camera, size);
|
|
17276
|
-
}
|
|
17277
|
-
return {
|
|
17278
|
-
// The intersect consists of the previous root state
|
|
17279
|
-
...rootState,
|
|
17280
|
-
...injectState,
|
|
17281
|
-
// Portals have their own scene, which forms the root, a raycaster and a pointer
|
|
17282
|
-
scene: container,
|
|
17283
|
-
raycaster,
|
|
17284
|
-
pointer,
|
|
17285
|
-
mouse: pointer,
|
|
17286
|
-
// Their previous root is the layer before it
|
|
17287
|
-
previousRoot,
|
|
17288
|
-
// Events, size and viewport can be overridden by the inject layer
|
|
17289
|
-
events: {
|
|
17290
|
-
...rootState.events,
|
|
17291
|
-
...injectState.events,
|
|
17292
|
-
...events
|
|
17293
|
-
},
|
|
17294
|
-
size: {
|
|
17295
|
-
...rootState.size,
|
|
17296
|
-
...size
|
|
17297
|
-
},
|
|
17298
|
-
viewport: {
|
|
17299
|
-
...rootState.viewport,
|
|
17300
|
-
...viewport
|
|
17301
|
-
},
|
|
17302
|
-
// Layers are allowed to override events
|
|
17303
|
-
setEvents: events => injectState.set(state => ({
|
|
17304
|
-
...state,
|
|
17305
|
-
events: {
|
|
17306
|
-
...state.events,
|
|
17307
|
-
...events
|
|
17308
|
-
}
|
|
17309
|
-
}))
|
|
17310
|
-
};
|
|
17491
|
+
reconciler.updateContainer(null, root.fiber, null, teardown);
|
|
17311
17492
|
});
|
|
17312
|
-
const usePortalStore = React__namespace.useMemo(() => {
|
|
17313
|
-
// Create a mirrored store, based on the previous root with a few overrides ...
|
|
17314
|
-
const store = traditional.createWithEqualityFn((set, get) => ({
|
|
17315
|
-
...rest,
|
|
17316
|
-
set,
|
|
17317
|
-
get
|
|
17318
|
-
}));
|
|
17319
|
-
|
|
17320
|
-
// Subscribe to previous root-state and copy changes over to the mirrored portal-state
|
|
17321
|
-
const onMutate = prev => store.setState(state => inject.current(prev, state));
|
|
17322
|
-
onMutate(previousRoot.getState());
|
|
17323
|
-
previousRoot.subscribe(onMutate);
|
|
17324
|
-
return store;
|
|
17325
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17326
|
-
}, [previousRoot, container]);
|
|
17327
|
-
return (
|
|
17328
|
-
/*#__PURE__*/
|
|
17329
|
-
// @ts-ignore, reconciler types are not maintained
|
|
17330
|
-
jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
17331
|
-
children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
|
|
17332
|
-
value: usePortalStore,
|
|
17333
|
-
children: children
|
|
17334
|
-
}), usePortalStore, null)
|
|
17335
|
-
})
|
|
17336
|
-
);
|
|
17337
|
-
}
|
|
17338
|
-
|
|
17339
|
-
/**
|
|
17340
|
-
* Force React to flush any updates inside the provided callback synchronously and immediately.
|
|
17341
|
-
* All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
|
|
17342
|
-
* Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
|
|
17343
|
-
* having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
|
|
17344
|
-
*/
|
|
17345
|
-
function flushSync(fn) {
|
|
17346
|
-
// @ts-ignore - reconciler types are not maintained
|
|
17347
|
-
return reconciler.flushSyncFromReconciler(fn);
|
|
17348
17493
|
}
|
|
17349
17494
|
|
|
17350
17495
|
function createSubs(callback, subs) {
|
|
@@ -17499,6 +17644,141 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
|
17499
17644
|
if (runGlobalEffects) flushGlobalEffects('after', timestamp);
|
|
17500
17645
|
}
|
|
17501
17646
|
|
|
17647
|
+
function createPortal(children, container, state) {
|
|
17648
|
+
return /*#__PURE__*/jsxRuntime.jsx(Portal, {
|
|
17649
|
+
children: children,
|
|
17650
|
+
container: container,
|
|
17651
|
+
state: state
|
|
17652
|
+
});
|
|
17653
|
+
}
|
|
17654
|
+
function initializePortal(options, initialState) {
|
|
17655
|
+
const {
|
|
17656
|
+
parentStore,
|
|
17657
|
+
container
|
|
17658
|
+
} = options;
|
|
17659
|
+
const portalStore = traditional.createWithEqualityFn((set, get) => ({
|
|
17660
|
+
...initialState,
|
|
17661
|
+
set,
|
|
17662
|
+
get,
|
|
17663
|
+
// Create once with the store's setter, without retaining a state snapshot.
|
|
17664
|
+
setEvents: events => set(state => ({
|
|
17665
|
+
...state,
|
|
17666
|
+
events: {
|
|
17667
|
+
...state.events,
|
|
17668
|
+
...events
|
|
17669
|
+
}
|
|
17670
|
+
}))
|
|
17671
|
+
}));
|
|
17672
|
+
const parentStateRef = {
|
|
17673
|
+
current: parentStore.getState()
|
|
17674
|
+
};
|
|
17675
|
+
portalStore.setState(portalState => inject(parentStateRef.current, portalState, options));
|
|
17676
|
+
return {
|
|
17677
|
+
parentStore,
|
|
17678
|
+
container,
|
|
17679
|
+
portalStore,
|
|
17680
|
+
parentStateRef
|
|
17681
|
+
};
|
|
17682
|
+
}
|
|
17683
|
+
function Portal({
|
|
17684
|
+
state = {},
|
|
17685
|
+
children,
|
|
17686
|
+
container
|
|
17687
|
+
}) {
|
|
17688
|
+
const parentStore = useStore();
|
|
17689
|
+
const {
|
|
17690
|
+
events,
|
|
17691
|
+
size,
|
|
17692
|
+
...rest
|
|
17693
|
+
} = state;
|
|
17694
|
+
const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
|
|
17695
|
+
const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
|
|
17696
|
+
const options = {
|
|
17697
|
+
parentStore,
|
|
17698
|
+
container,
|
|
17699
|
+
raycaster,
|
|
17700
|
+
pointer,
|
|
17701
|
+
events,
|
|
17702
|
+
size
|
|
17703
|
+
};
|
|
17704
|
+
const injectRef = useMutableCallback((parentState, portalState) => inject(parentState, portalState, options));
|
|
17705
|
+
|
|
17706
|
+
// Initialize during render. Keep the store in state so Activity can preserve it.
|
|
17707
|
+
const [portal, setPortal] = React__namespace.useState(() => initializePortal(options, rest));
|
|
17708
|
+
if (portal.parentStore !== parentStore || portal.container !== container) {
|
|
17709
|
+
setPortal(initializePortal(options, rest));
|
|
17710
|
+
}
|
|
17711
|
+
const {
|
|
17712
|
+
portalStore,
|
|
17713
|
+
parentStateRef
|
|
17714
|
+
} = portal;
|
|
17715
|
+
|
|
17716
|
+
// Subscribe after commit and update the portal on each parent change.
|
|
17717
|
+
useIsomorphicLayoutEffect(() => {
|
|
17718
|
+
const update = parentState => {
|
|
17719
|
+
parentStateRef.current = parentState;
|
|
17720
|
+
portalStore.setState(portalState => injectRef.current(parentState, portalState));
|
|
17721
|
+
};
|
|
17722
|
+
const unsubscribe = parentStore.subscribe(update);
|
|
17723
|
+
|
|
17724
|
+
// Catch up on changes made before subscribing or while Activity was hidden.
|
|
17725
|
+
const parentState = parentStore.getState();
|
|
17726
|
+
if (parentState !== parentStateRef.current) update(parentState);
|
|
17727
|
+
|
|
17728
|
+
// Clean up when hidden, unmounted or switching stores.
|
|
17729
|
+
return unsubscribe;
|
|
17730
|
+
}, [parentStore, portalStore, parentStateRef]);
|
|
17731
|
+
return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
17732
|
+
children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
|
|
17733
|
+
value: portalStore,
|
|
17734
|
+
children: children
|
|
17735
|
+
}), portalStore, null)
|
|
17736
|
+
});
|
|
17737
|
+
}
|
|
17738
|
+
function inject(parentState, portalState, options) {
|
|
17739
|
+
const {
|
|
17740
|
+
parentStore,
|
|
17741
|
+
container,
|
|
17742
|
+
raycaster,
|
|
17743
|
+
pointer,
|
|
17744
|
+
events,
|
|
17745
|
+
size
|
|
17746
|
+
} = options;
|
|
17747
|
+
let viewport = undefined;
|
|
17748
|
+
if (portalState.camera && size) {
|
|
17749
|
+
const camera = portalState.camera;
|
|
17750
|
+
// Calculate the override viewport, if present
|
|
17751
|
+
viewport = parentState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
|
|
17752
|
+
// Update the portal camera, if it differs from the previous layer
|
|
17753
|
+
if (camera !== parentState.camera) updateCamera(camera, size);
|
|
17754
|
+
}
|
|
17755
|
+
return {
|
|
17756
|
+
// Inherit parent values and preserve the portal's own state.
|
|
17757
|
+
...parentState,
|
|
17758
|
+
...portalState,
|
|
17759
|
+
// Portals have their own scene, raycaster and pointer.
|
|
17760
|
+
scene: container,
|
|
17761
|
+
raycaster,
|
|
17762
|
+
pointer,
|
|
17763
|
+
mouse: pointer,
|
|
17764
|
+
previousRoot: parentStore,
|
|
17765
|
+
// Apply the portal's event, size and viewport overrides.
|
|
17766
|
+
events: {
|
|
17767
|
+
...parentState.events,
|
|
17768
|
+
...portalState.events,
|
|
17769
|
+
...events
|
|
17770
|
+
},
|
|
17771
|
+
size: {
|
|
17772
|
+
...parentState.size,
|
|
17773
|
+
...size
|
|
17774
|
+
},
|
|
17775
|
+
viewport: {
|
|
17776
|
+
...parentState.viewport,
|
|
17777
|
+
...viewport
|
|
17778
|
+
}
|
|
17779
|
+
};
|
|
17780
|
+
}
|
|
17781
|
+
|
|
17502
17782
|
const DOM_EVENTS = {
|
|
17503
17783
|
onClick: ['click', false],
|
|
17504
17784
|
onContextMenu: ['contextmenu', false],
|