@react-three/fiber 9.8.0 → 9.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/declarations/src/core/{renderer.d.ts → configuration.d.ts} +21 -28
- package/dist/declarations/src/core/index.d.ts +6 -3
- package/dist/declarations/src/core/portal.d.ts +13 -0
- package/dist/declarations/src/core/promise.d.ts +7 -3
- package/dist/declarations/src/core/reconciler.d.ts +8 -8
- package/dist/declarations/src/core/root.d.ts +35 -0
- package/dist/declarations/src/core/utils.d.ts +1 -1
- package/dist/{events-ce5e34e8.cjs.dev.js → events-21d8cd92.cjs.dev.js} +605 -482
- package/dist/{events-803f4abc.esm.js → events-9ce18a08.esm.js} +607 -484
- package/dist/{events-a79ef12b.cjs.prod.js → events-a816cbab.cjs.prod.js} +605 -482
- 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 +2 -2
|
@@ -2,10 +2,10 @@
|
|
|
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
8
|
var w1 = require('scheduler');
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
var itsFine = require('its-fine');
|
|
10
10
|
|
|
11
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
@@ -95,23 +95,29 @@ function useGate() {
|
|
|
95
95
|
}) : null;
|
|
96
96
|
return [gate, waitFor];
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
// Activity is optional on React 19.0/19.1. A computed key also supports strict ESM bundlers.
|
|
100
|
+
const useActivityBridge = React__namespace['Activity' + ''] ? itsFine.useActivityBridge : () => React__namespace.Fragment;
|
|
98
101
|
/**
|
|
99
|
-
* Bridges
|
|
102
|
+
* Bridges Context, StrictMode, and Activity visibility from a primary renderer.
|
|
100
103
|
*/
|
|
101
104
|
function useBridge() {
|
|
102
105
|
const fiber = itsFine.useFiber();
|
|
103
106
|
const ContextBridge = itsFine.useContextBridge();
|
|
107
|
+
const ActivityBridge = useActivityBridge();
|
|
104
108
|
return React__namespace.useMemo(() => ({
|
|
105
109
|
children
|
|
106
110
|
}) => {
|
|
107
111
|
const strict = !!itsFine.traverseFiber(fiber, true, node => node.type === React__namespace.StrictMode);
|
|
108
112
|
const Root = strict ? React__namespace.StrictMode : React__namespace.Fragment;
|
|
109
113
|
return /*#__PURE__*/jsxRuntime.jsx(Root, {
|
|
110
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
111
|
-
children:
|
|
114
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ActivityBridge, {
|
|
115
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ContextBridge, {
|
|
116
|
+
children: children
|
|
117
|
+
})
|
|
112
118
|
})
|
|
113
119
|
});
|
|
114
|
-
}, [fiber, ContextBridge]);
|
|
120
|
+
}, [fiber, ContextBridge, ActivityBridge]);
|
|
115
121
|
}
|
|
116
122
|
function Block({
|
|
117
123
|
set
|
|
@@ -257,6 +263,7 @@ function prepare(target, root, type, props) {
|
|
|
257
263
|
object,
|
|
258
264
|
eventCount: 0,
|
|
259
265
|
handlers: {},
|
|
266
|
+
previousVisible: undefined,
|
|
260
267
|
isHidden: false
|
|
261
268
|
};
|
|
262
269
|
if (object) object.__r3f = instance;
|
|
@@ -440,6 +447,12 @@ function applyProps(object, props) {
|
|
|
440
447
|
// Ignore setting undefined props
|
|
441
448
|
// https://github.com/pmndrs/react-three-fiber/issues/274
|
|
442
449
|
if (value === undefined) continue;
|
|
450
|
+
|
|
451
|
+
// Update the visibility to restore without revealing a hidden instance.
|
|
452
|
+
if (prop === 'visible' && instance != null && instance.isHidden && instance.previousVisible !== undefined) {
|
|
453
|
+
instance.previousVisible = value;
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
443
456
|
let {
|
|
444
457
|
root,
|
|
445
458
|
key,
|
|
@@ -1364,9 +1377,326 @@ useLoader.clear = function (loader, input) {
|
|
|
1364
1377
|
e = 2,
|
|
1365
1378
|
i$1 = 268435456;
|
|
1366
1379
|
|
|
1380
|
+
// Shim for OffscreenCanvas since it was removed from DOM types
|
|
1381
|
+
// https://github.com/DefinitelyTyped/DefinitelyTyped/pull/54988
|
|
1382
|
+
|
|
1383
|
+
/** What a root has applied, so its next configuration applies only what changed */
|
|
1384
|
+
|
|
1385
|
+
const shallow = {
|
|
1386
|
+
objects: 'shallow'
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
/** The renderer to configure, or a promise for one from an async factory */
|
|
1390
|
+
function createRenderer(canvas, gl) {
|
|
1391
|
+
const defaults = {
|
|
1392
|
+
canvas,
|
|
1393
|
+
powerPreference: 'high-performance',
|
|
1394
|
+
antialias: true,
|
|
1395
|
+
alpha: true
|
|
1396
|
+
};
|
|
1397
|
+
if (typeof gl === 'function') return gl(defaults);
|
|
1398
|
+
if (isRenderer(gl)) return gl;
|
|
1399
|
+
return new THREE__namespace.WebGLRenderer({
|
|
1400
|
+
...defaults,
|
|
1401
|
+
...gl
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
function computeInitialSize(canvas, size) {
|
|
1405
|
+
if (!size && typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1406
|
+
const {
|
|
1407
|
+
width,
|
|
1408
|
+
height,
|
|
1409
|
+
top,
|
|
1410
|
+
left
|
|
1411
|
+
} = canvas.parentElement.getBoundingClientRect();
|
|
1412
|
+
return {
|
|
1413
|
+
width,
|
|
1414
|
+
height,
|
|
1415
|
+
top,
|
|
1416
|
+
left
|
|
1417
|
+
};
|
|
1418
|
+
} else if (!size && typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {
|
|
1419
|
+
return {
|
|
1420
|
+
width: canvas.width,
|
|
1421
|
+
height: canvas.height,
|
|
1422
|
+
top: 0,
|
|
1423
|
+
left: 0
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
return {
|
|
1427
|
+
width: 0,
|
|
1428
|
+
height: 0,
|
|
1429
|
+
top: 0,
|
|
1430
|
+
left: 0,
|
|
1431
|
+
...size
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/**
|
|
1436
|
+
* Applies the inputs that changed since the last configuration applied in full, to a root whose
|
|
1437
|
+
* renderer is installed. A runtime change, such as setFrameloop or an edit to gl.shadowMap, lasts
|
|
1438
|
+
* until its input changes. The pixel ratio instead follows the device on every call. Objects and
|
|
1439
|
+
* arrays compare shallowly, so an equal inline value is unchanged.
|
|
1440
|
+
*/
|
|
1441
|
+
function applyRootConfiguration({
|
|
1442
|
+
store,
|
|
1443
|
+
configuration
|
|
1444
|
+
}, canvas, props) {
|
|
1445
|
+
const {
|
|
1446
|
+
gl: glConfig,
|
|
1447
|
+
scene: sceneOptions,
|
|
1448
|
+
camera: cameraOptions,
|
|
1449
|
+
shadows = false,
|
|
1450
|
+
linear = false,
|
|
1451
|
+
flat = false,
|
|
1452
|
+
legacy = false,
|
|
1453
|
+
frameloop = 'always',
|
|
1454
|
+
dpr = [1, 2],
|
|
1455
|
+
performance,
|
|
1456
|
+
onPointerMissed
|
|
1457
|
+
} = props;
|
|
1458
|
+
const size = computeInitialSize(canvas, props.size);
|
|
1459
|
+
const next = {
|
|
1460
|
+
...props,
|
|
1461
|
+
shadows,
|
|
1462
|
+
linear,
|
|
1463
|
+
flat,
|
|
1464
|
+
legacy,
|
|
1465
|
+
frameloop,
|
|
1466
|
+
size
|
|
1467
|
+
};
|
|
1468
|
+
const state = store.getState();
|
|
1469
|
+
const gl = state.gl;
|
|
1470
|
+
const last = configuration.previous;
|
|
1471
|
+
const changed = key => !last || !is.equ(next[key], last[key], shallow);
|
|
1472
|
+
// A failure can leave inputs partly applied, so the next configuration applies all of them
|
|
1473
|
+
configuration.previous = undefined;
|
|
1474
|
+
|
|
1475
|
+
// Set up raycaster (one time only!)
|
|
1476
|
+
let raycaster = state.raycaster;
|
|
1477
|
+
if (!raycaster) state.set({
|
|
1478
|
+
raycaster: raycaster = new THREE__namespace.Raycaster()
|
|
1479
|
+
});
|
|
1480
|
+
if (changed('raycaster')) {
|
|
1481
|
+
var _props$raycaster;
|
|
1482
|
+
const {
|
|
1483
|
+
params,
|
|
1484
|
+
...options
|
|
1485
|
+
} = (_props$raycaster = props.raycaster) != null ? _props$raycaster : {};
|
|
1486
|
+
applyProps(raycaster, {
|
|
1487
|
+
...options,
|
|
1488
|
+
params: {
|
|
1489
|
+
...raycaster.params,
|
|
1490
|
+
...params
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// Create default camera, don't overwrite any user-set state
|
|
1496
|
+
if (!state.camera || state.camera === configuration.camera && changed('camera')) {
|
|
1497
|
+
configuration.camera = cameraOptions;
|
|
1498
|
+
const isCamera = cameraOptions == null ? void 0 : cameraOptions.isCamera;
|
|
1499
|
+
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);
|
|
1500
|
+
if (!isCamera) {
|
|
1501
|
+
camera.position.z = 5;
|
|
1502
|
+
if (cameraOptions) {
|
|
1503
|
+
applyProps(camera, cameraOptions);
|
|
1504
|
+
// Preserve user-defined frustum if possible
|
|
1505
|
+
// https://github.com/pmndrs/react-three-fiber/issues/3160
|
|
1506
|
+
if (!camera.manual) {
|
|
1507
|
+
if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
|
|
1508
|
+
camera.manual = true;
|
|
1509
|
+
camera.updateProjectionMatrix();
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
// Always look at center by default
|
|
1514
|
+
if (!state.camera && !(cameraOptions != null && cameraOptions.rotation)) camera.lookAt(0, 0, 0);
|
|
1515
|
+
}
|
|
1516
|
+
state.set({
|
|
1517
|
+
camera
|
|
1518
|
+
});
|
|
1519
|
+
|
|
1520
|
+
// Configure raycaster
|
|
1521
|
+
// https://github.com/pmndrs/react-xr/issues/300
|
|
1522
|
+
raycaster.camera = camera;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
// Set up scene (one time only!)
|
|
1526
|
+
if (!state.scene) {
|
|
1527
|
+
let scene;
|
|
1528
|
+
if (sceneOptions != null && sceneOptions.isScene) {
|
|
1529
|
+
scene = sceneOptions;
|
|
1530
|
+
prepare(scene, store, '', {});
|
|
1531
|
+
} else {
|
|
1532
|
+
scene = new THREE__namespace.Scene();
|
|
1533
|
+
prepare(scene, store, '', {});
|
|
1534
|
+
if (sceneOptions) applyProps(scene, sceneOptions);
|
|
1535
|
+
}
|
|
1536
|
+
state.set({
|
|
1537
|
+
scene
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// Store events internally
|
|
1542
|
+
if (props.events && !state.events.handlers) state.set({
|
|
1543
|
+
events: props.events(store)
|
|
1544
|
+
});
|
|
1545
|
+
if (changed('size')) state.setSize(size.width, size.height, size.top, size.left);
|
|
1546
|
+
// The ratio follows window.devicePixelRatio, which changes with browser zoom or another display
|
|
1547
|
+
if (state.viewport.dpr !== calculateDpr(dpr)) state.setDpr(dpr);
|
|
1548
|
+
if (changed('frameloop')) state.setFrameloop(frameloop);
|
|
1549
|
+
if (changed('onPointerMissed')) state.set({
|
|
1550
|
+
onPointerMissed
|
|
1551
|
+
});
|
|
1552
|
+
// Performance options merge, so removing them keeps the current settings
|
|
1553
|
+
if (performance && changed('performance')) {
|
|
1554
|
+
state.set(state => ({
|
|
1555
|
+
performance: {
|
|
1556
|
+
...state.performance,
|
|
1557
|
+
...performance
|
|
1558
|
+
}
|
|
1559
|
+
}));
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// Set up XR (one time only!)
|
|
1563
|
+
if (!state.xr) {
|
|
1564
|
+
var _gl$xr;
|
|
1565
|
+
// Handle frame behavior in WebXR
|
|
1566
|
+
const handleXRFrame = (timestamp, frame) => {
|
|
1567
|
+
const state = store.getState();
|
|
1568
|
+
if (state.frameloop === 'never') return;
|
|
1569
|
+
advance(timestamp, true, state, frame);
|
|
1570
|
+
};
|
|
1571
|
+
|
|
1572
|
+
// Toggle render switching on session
|
|
1573
|
+
const handleSessionChange = () => {
|
|
1574
|
+
const state = store.getState();
|
|
1575
|
+
state.gl.xr.enabled = state.gl.xr.isPresenting;
|
|
1576
|
+
state.gl.xr.setAnimationLoop(state.gl.xr.isPresenting ? handleXRFrame : null);
|
|
1577
|
+
if (!state.gl.xr.isPresenting) invalidate(state);
|
|
1578
|
+
};
|
|
1579
|
+
|
|
1580
|
+
// WebXR session manager
|
|
1581
|
+
const xr = {
|
|
1582
|
+
connect() {
|
|
1583
|
+
const gl = store.getState().gl;
|
|
1584
|
+
gl.xr.addEventListener('sessionstart', handleSessionChange);
|
|
1585
|
+
gl.xr.addEventListener('sessionend', handleSessionChange);
|
|
1586
|
+
},
|
|
1587
|
+
disconnect() {
|
|
1588
|
+
const gl = store.getState().gl;
|
|
1589
|
+
gl.xr.removeEventListener('sessionstart', handleSessionChange);
|
|
1590
|
+
gl.xr.removeEventListener('sessionend', handleSessionChange);
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
|
|
1594
|
+
// Subscribe to WebXR session events
|
|
1595
|
+
if (typeof ((_gl$xr = gl.xr) == null ? void 0 : _gl$xr.addEventListener) === 'function') xr.connect();
|
|
1596
|
+
state.set({
|
|
1597
|
+
xr
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// Set shadowmap
|
|
1602
|
+
if (gl.shadowMap && changed('shadows')) {
|
|
1603
|
+
const oldEnabled = gl.shadowMap.enabled;
|
|
1604
|
+
const oldType = gl.shadowMap.type;
|
|
1605
|
+
gl.shadowMap.enabled = !!shadows;
|
|
1606
|
+
if (is.boo(shadows)) {
|
|
1607
|
+
gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
1608
|
+
} else if (is.str(shadows)) {
|
|
1609
|
+
var _types$shadows;
|
|
1610
|
+
const types = {
|
|
1611
|
+
basic: THREE__namespace.BasicShadowMap,
|
|
1612
|
+
percentage: THREE__namespace.PCFShadowMap,
|
|
1613
|
+
soft: THREE__namespace.PCFSoftShadowMap,
|
|
1614
|
+
variance: THREE__namespace.VSMShadowMap
|
|
1615
|
+
};
|
|
1616
|
+
gl.shadowMap.type = (_types$shadows = types[shadows]) != null ? _types$shadows : THREE__namespace.PCFSoftShadowMap;
|
|
1617
|
+
} else if (is.obj(shadows)) {
|
|
1618
|
+
Object.assign(gl.shadowMap, shadows);
|
|
1619
|
+
}
|
|
1620
|
+
if (oldEnabled !== gl.shadowMap.enabled || oldType !== gl.shadowMap.type) gl.shadowMap.needsUpdate = true;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// Explicit renderer options take precedence over the color shorthands
|
|
1624
|
+
const glProps = glConfig && !is.fun(glConfig) && !isRenderer(glConfig) ? glConfig : undefined;
|
|
1625
|
+
if (changed('legacy')) {
|
|
1626
|
+
THREE__namespace.ColorManagement.enabled = !legacy;
|
|
1627
|
+
state.set({
|
|
1628
|
+
legacy
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
if (changed('linear')) {
|
|
1632
|
+
if ((glProps == null ? void 0 : glProps.outputColorSpace) === undefined) {
|
|
1633
|
+
gl.outputColorSpace = linear ? THREE__namespace.LinearSRGBColorSpace : THREE__namespace.SRGBColorSpace;
|
|
1634
|
+
}
|
|
1635
|
+
state.set({
|
|
1636
|
+
linear
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
if (changed('flat')) {
|
|
1640
|
+
if ((glProps == null ? void 0 : glProps.toneMapping) === undefined) gl.toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
|
|
1641
|
+
state.set({
|
|
1642
|
+
flat
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// Set gl props
|
|
1647
|
+
if (glProps && changed('gl')) applyProps(gl, glProps);
|
|
1648
|
+
configuration.previous = next;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
const isPromiseLike = value => typeof (value == null ? void 0 : value.then) === 'function';
|
|
1652
|
+
|
|
1653
|
+
/** A promise tagged with its state, the protocol React's `use` reads */
|
|
1654
|
+
|
|
1655
|
+
const fulfilled = value => Object.assign(Promise.resolve(value), {
|
|
1656
|
+
status: 'fulfilled',
|
|
1657
|
+
value
|
|
1658
|
+
});
|
|
1659
|
+
const rejected = reason => {
|
|
1660
|
+
const promise = Promise.reject(reason);
|
|
1661
|
+
promise.catch(() => {}); // the reason is read from `status`
|
|
1662
|
+
return Object.assign(promise, {
|
|
1663
|
+
status: 'rejected',
|
|
1664
|
+
reason
|
|
1665
|
+
});
|
|
1666
|
+
};
|
|
1667
|
+
|
|
1668
|
+
/** A pending promise, settled once from outside. Its `status` updates the moment it settles */
|
|
1669
|
+
const deferred = () => {
|
|
1670
|
+
let resolve;
|
|
1671
|
+
let reject;
|
|
1672
|
+
const promise = new Promise((yes, no) => {
|
|
1673
|
+
resolve = value => {
|
|
1674
|
+
Object.assign(promise, {
|
|
1675
|
+
status: 'fulfilled',
|
|
1676
|
+
value
|
|
1677
|
+
});
|
|
1678
|
+
yes(value);
|
|
1679
|
+
};
|
|
1680
|
+
reject = reason => {
|
|
1681
|
+
Object.assign(promise, {
|
|
1682
|
+
status: 'rejected',
|
|
1683
|
+
reason
|
|
1684
|
+
});
|
|
1685
|
+
no(reason);
|
|
1686
|
+
};
|
|
1687
|
+
});
|
|
1688
|
+
promise.status = 'pending';
|
|
1689
|
+
promise.catch(() => {}); // the reason is read from `status`
|
|
1690
|
+
return {
|
|
1691
|
+
promise,
|
|
1692
|
+
resolve,
|
|
1693
|
+
reject
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1367
1697
|
var packageData = {
|
|
1368
1698
|
name: "@react-three/fiber",
|
|
1369
|
-
version: "9.8.
|
|
1699
|
+
version: "9.8.1",
|
|
1370
1700
|
description: "A React renderer for Threejs",
|
|
1371
1701
|
keywords: [
|
|
1372
1702
|
"react",
|
|
@@ -1417,7 +1747,7 @@ var packageData = {
|
|
|
1417
1747
|
"@types/webxr": "*",
|
|
1418
1748
|
"base64-js": "^1.5.1",
|
|
1419
1749
|
buffer: "^6.0.3",
|
|
1420
|
-
"its-fine": "^2.
|
|
1750
|
+
"its-fine": "^2.1.1",
|
|
1421
1751
|
"react-use-measure": "^2.1.7",
|
|
1422
1752
|
scheduler: "^0.28.0",
|
|
1423
1753
|
"suspend-react": "^0.1.3",
|
|
@@ -7416,6 +7746,7 @@ function hideInstance(instance) {
|
|
|
7416
7746
|
if (instance.props.attach && (_instance$parent = instance.parent) != null && _instance$parent.object) {
|
|
7417
7747
|
detach(instance.parent, instance);
|
|
7418
7748
|
} else if (isObject3D(instance.object)) {
|
|
7749
|
+
instance.previousVisible = instance.object.visible;
|
|
7419
7750
|
instance.object.visible = false;
|
|
7420
7751
|
}
|
|
7421
7752
|
instance.isHidden = true;
|
|
@@ -7427,9 +7758,11 @@ function unhideInstance(instance) {
|
|
|
7427
7758
|
var _instance$parent2;
|
|
7428
7759
|
if (instance.props.attach && (_instance$parent2 = instance.parent) != null && _instance$parent2.object) {
|
|
7429
7760
|
attach(instance.parent, instance);
|
|
7430
|
-
} else if (isObject3D(instance.object)
|
|
7431
|
-
|
|
7761
|
+
} else if (isObject3D(instance.object)) {
|
|
7762
|
+
var _instance$previousVis;
|
|
7763
|
+
instance.object.visible = (_instance$previousVis = instance.previousVisible) != null ? _instance$previousVis : true;
|
|
7432
7764
|
}
|
|
7765
|
+
instance.previousVisible = undefined;
|
|
7433
7766
|
instance.isHidden = false;
|
|
7434
7767
|
invalidateInstance(instance);
|
|
7435
7768
|
}
|
|
@@ -7974,76 +8307,49 @@ const reconciler = /* @__PURE__ */createReconciler({
|
|
|
7974
8307
|
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
7975
8308
|
});
|
|
7976
8309
|
|
|
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
|
-
};
|
|
8310
|
+
/**
|
|
8311
|
+
* Force React to flush any updates inside the provided callback synchronously and immediately.
|
|
8312
|
+
* All the same caveats documented for react-dom's `flushSync` apply here (see https://react.dev/reference/react-dom/flushSync).
|
|
8313
|
+
* Nevertheless, sometimes one needs to render synchronously, for example to keep DOM and 3D changes in lock-step without
|
|
8314
|
+
* having to revert to a non-React solution. Note: this will only flush updates within the `Canvas` root.
|
|
8315
|
+
*/
|
|
8316
|
+
function flushSync(fn) {
|
|
8317
|
+
// @ts-ignore - reconciler types are not maintained
|
|
8318
|
+
return reconciler.flushSyncFromReconciler(fn);
|
|
8319
|
+
}
|
|
8012
8320
|
|
|
8013
8321
|
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
|
-
|
|
8322
|
+
/**
|
|
8323
|
+
* open -> closing -> disposed
|
|
8324
|
+
* | use
|
|
8325
|
+
* v
|
|
8326
|
+
* open
|
|
8327
|
+
*
|
|
8328
|
+
* Only closing can be cancelled. Each unmount carries a token, so only the latest one can dispose.
|
|
8329
|
+
*/
|
|
8330
|
+
function transitionRoot(root, event) {
|
|
8331
|
+
const state = root.state;
|
|
8332
|
+
switch (event.type) {
|
|
8333
|
+
case 'use':
|
|
8334
|
+
if (state.status === 'disposed') return false;
|
|
8335
|
+
root.state = {
|
|
8336
|
+
status: 'open'
|
|
8337
|
+
};
|
|
8338
|
+
return true;
|
|
8339
|
+
case 'unmount':
|
|
8340
|
+
if (state.status === 'disposed') return false;
|
|
8341
|
+
root.state = {
|
|
8342
|
+
status: 'closing',
|
|
8343
|
+
token: event.token
|
|
8344
|
+
};
|
|
8345
|
+
return true;
|
|
8346
|
+
case 'dispose':
|
|
8347
|
+
if (state.status !== 'closing' || state.token !== event.token) return false;
|
|
8348
|
+
root.state = {
|
|
8349
|
+
status: 'disposed'
|
|
8350
|
+
};
|
|
8351
|
+
return true;
|
|
8039
8352
|
}
|
|
8040
|
-
return {
|
|
8041
|
-
width: 0,
|
|
8042
|
-
height: 0,
|
|
8043
|
-
top: 0,
|
|
8044
|
-
left: 0,
|
|
8045
|
-
...size
|
|
8046
|
-
};
|
|
8047
8353
|
}
|
|
8048
8354
|
function createRoot(canvas) {
|
|
8049
8355
|
// Check against mistaken use of createRoot
|
|
@@ -8088,286 +8394,84 @@ function createRoot(canvas) {
|
|
|
8088
8394
|
const root = prevRoot || {
|
|
8089
8395
|
fiber,
|
|
8090
8396
|
store,
|
|
8091
|
-
|
|
8092
|
-
|
|
8397
|
+
state: {
|
|
8398
|
+
status: 'open'
|
|
8399
|
+
},
|
|
8400
|
+
ready: fulfilled(undefined),
|
|
8401
|
+
configuration: {},
|
|
8402
|
+
ownsRenderer: false
|
|
8093
8403
|
};
|
|
8094
8404
|
if (!prevRoot) _roots.set(canvas, root);
|
|
8095
|
-
|
|
8096
|
-
// Locals
|
|
8097
|
-
let onCreated;
|
|
8098
|
-
let lastCamera;
|
|
8099
8405
|
let mounted = false;
|
|
8100
8406
|
return {
|
|
8101
8407
|
get ready() {
|
|
8102
8408
|
return root.ready;
|
|
8103
8409
|
},
|
|
8104
8410
|
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
|
-
};
|
|
8411
|
+
if (!transitionRoot(root, {
|
|
8412
|
+
type: 'use'
|
|
8413
|
+
})) {
|
|
8414
|
+
return rejected(new Error('R3F: Cannot configure a root after disposal has started.'));
|
|
8415
|
+
}
|
|
8130
8416
|
|
|
8131
|
-
//
|
|
8132
|
-
const
|
|
8417
|
+
// Configuration applies in call order. Publishing first queues calls made while this one runs
|
|
8418
|
+
const previous = root.ready;
|
|
8419
|
+
const {
|
|
8420
|
+
promise,
|
|
8421
|
+
resolve,
|
|
8422
|
+
reject
|
|
8423
|
+
} = deferred();
|
|
8424
|
+
root.ready = promise;
|
|
8425
|
+
const apply = gl => {
|
|
8133
8426
|
const state = store.getState();
|
|
8134
|
-
|
|
8135
8427
|
// 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
|
-
}
|
|
8428
|
+
if (!state.gl) {
|
|
8429
|
+
// R3F owns what it builds, a factory's result included, since it calls the factory
|
|
8430
|
+
// once per root. A renderer instance belongs to the caller
|
|
8431
|
+
root.ownsRenderer = !isRenderer(props.gl);
|
|
8210
8432
|
state.set({
|
|
8211
|
-
|
|
8433
|
+
gl: gl
|
|
8212
8434
|
});
|
|
8213
8435
|
}
|
|
8214
|
-
|
|
8215
|
-
|
|
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();
|
|
8274
|
-
state.set({
|
|
8275
|
-
xr
|
|
8276
|
-
});
|
|
8277
|
-
}
|
|
8278
|
-
|
|
8279
|
-
// Set shadowmap
|
|
8280
|
-
if (gl.shadowMap) {
|
|
8281
|
-
const oldEnabled = gl.shadowMap.enabled;
|
|
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;
|
|
8436
|
+
applyRootConfiguration(root, canvas, props);
|
|
8437
|
+
resolve(this);
|
|
8324
8438
|
};
|
|
8325
|
-
const
|
|
8326
|
-
const failure = rejected(error);
|
|
8327
|
-
root.ready = failure;
|
|
8328
|
-
return failure;
|
|
8329
|
-
};
|
|
8330
|
-
const run = customRenderer => {
|
|
8439
|
+
const run = () => {
|
|
8331
8440
|
try {
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8441
|
+
var _store$getState$gl;
|
|
8442
|
+
const gl = (_store$getState$gl = store.getState().gl) != null ? _store$getState$gl : createRenderer(canvas, props.gl);
|
|
8443
|
+
// Only an async renderer factory makes configuration asynchronous
|
|
8444
|
+
if (isPromiseLike(gl)) Promise.resolve(gl).then(apply).catch(reject);else apply(gl);
|
|
8335
8445
|
} catch (error) {
|
|
8336
|
-
|
|
8446
|
+
reject(error);
|
|
8337
8447
|
}
|
|
8338
8448
|
};
|
|
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;
|
|
8449
|
+
if (previous.status === 'pending') previous.then(run, reject);else run();
|
|
8450
|
+
return promise;
|
|
8357
8451
|
},
|
|
8358
8452
|
render(children) {
|
|
8359
|
-
if (
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
rootElement: canvas
|
|
8367
|
-
});
|
|
8453
|
+
if (!transitionRoot(root, {
|
|
8454
|
+
type: 'use'
|
|
8455
|
+
})) return store;
|
|
8456
|
+
|
|
8457
|
+
// The root has to be configured before it can be rendered
|
|
8458
|
+
if (!store.getState().gl && root.ready.status === 'fulfilled') this.configure();
|
|
8459
|
+
if (root.ready.status === 'rejected') throw root.ready.reason;
|
|
8368
8460
|
const commit = () => {
|
|
8369
|
-
|
|
8370
|
-
if (
|
|
8461
|
+
var _root$configuration$p;
|
|
8462
|
+
if (root.state.status !== 'open' || root.ready.status === 'rejected') return;
|
|
8463
|
+
// Wait for all queued configuration, including any queued while waiting
|
|
8464
|
+
if (root.ready.status === 'pending') {
|
|
8465
|
+
root.ready.then(commit, logRecoverableError);
|
|
8466
|
+
return;
|
|
8467
|
+
}
|
|
8468
|
+
const onCreated = (_root$configuration$p = root.configuration.previous) == null ? void 0 : _root$configuration$p.onCreated;
|
|
8469
|
+
const element = /*#__PURE__*/jsxRuntime.jsx(Provider, {
|
|
8470
|
+
store: store,
|
|
8471
|
+
children: children,
|
|
8472
|
+
onCreated: onCreated,
|
|
8473
|
+
rootElement: canvas
|
|
8474
|
+
});
|
|
8371
8475
|
if (mounted) {
|
|
8372
8476
|
reconciler.updateContainer(element, fiber, null, noop);
|
|
8373
8477
|
return;
|
|
@@ -8379,22 +8483,11 @@ function createRoot(canvas) {
|
|
|
8379
8483
|
// @ts-ignore - reconciler types are not maintained
|
|
8380
8484
|
reconciler.flushSyncWork();
|
|
8381
8485
|
};
|
|
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
|
-
}
|
|
8486
|
+
commit();
|
|
8394
8487
|
return store;
|
|
8395
8488
|
},
|
|
8396
8489
|
unmount() {
|
|
8397
|
-
unmountComponentAtNode(canvas);
|
|
8490
|
+
if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
|
|
8398
8491
|
}
|
|
8399
8492
|
};
|
|
8400
8493
|
}
|
|
@@ -8425,147 +8518,81 @@ function Provider({
|
|
|
8425
8518
|
children: children
|
|
8426
8519
|
});
|
|
8427
8520
|
}
|
|
8428
|
-
function unmountComponentAtNode(canvas, callback) {
|
|
8429
|
-
const root = _roots.get(canvas);
|
|
8430
|
-
if (!root) return;
|
|
8431
8521
|
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
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
|
-
});
|
|
8522
|
+
/**
|
|
8523
|
+
* Frees a renderer R3F built. WebGLRenderer.dispose() releases programs and caches but keeps its
|
|
8524
|
+
* context until garbage collection, and browsers cap live WebGL contexts, so the context is lost
|
|
8525
|
+
* after it. A WebGPURenderer (from a factory) releases its device and context inside dispose().
|
|
8526
|
+
*/
|
|
8527
|
+
function disposeRenderer(gl) {
|
|
8528
|
+
// Avoid starting initialization through three's dispose(). A factory must await init()
|
|
8529
|
+
// before returning its renderer so readiness includes initialization and teardown can wait.
|
|
8530
|
+
if ((gl.hasInitialized == null ? void 0 : gl.hasInitialized()) === false) return;
|
|
8531
|
+
const disposed = attempt(() => {
|
|
8532
|
+
var _gl$renderLists;
|
|
8533
|
+
return gl.dispose ? gl.dispose() : (_gl$renderLists = gl.renderLists) == null ? void 0 : _gl$renderLists.dispose == null ? void 0 : _gl$renderLists.dispose();
|
|
8462
8534
|
});
|
|
8535
|
+
// WebGPURenderer.dispose() is async from three r186
|
|
8536
|
+
if (isPromiseLike(disposed)) {
|
|
8537
|
+
return Promise.resolve(disposed).catch(error => console.warn('[R3F] Error disposing renderer', error)).then(() => attempt(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss()));
|
|
8538
|
+
}
|
|
8539
|
+
attempt(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss());
|
|
8463
8540
|
}
|
|
8464
|
-
function
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
}
|
|
8541
|
+
function attempt(step) {
|
|
8542
|
+
try {
|
|
8543
|
+
return step();
|
|
8544
|
+
} catch (error) {
|
|
8545
|
+
console.warn('[R3F] Error while unmounting root; teardown may be incomplete:', error);
|
|
8546
|
+
}
|
|
8470
8547
|
}
|
|
8471
|
-
function
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
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);
|
|
8548
|
+
function unmountComponentAtNode(canvas, callback) {
|
|
8549
|
+
const root = _roots.get(canvas);
|
|
8550
|
+
const token = Symbol('unmount');
|
|
8551
|
+
if (!root || !transitionRoot(root, {
|
|
8552
|
+
type: 'unmount',
|
|
8553
|
+
token
|
|
8554
|
+
})) return;
|
|
8555
|
+
const teardown = () => {
|
|
8556
|
+
var _state$gl;
|
|
8557
|
+
// Configuration accepted before the unmount finishes first, so a renderer it creates is released too
|
|
8558
|
+
if (root.ready.status === 'pending') {
|
|
8559
|
+
root.ready.then(teardown, teardown);
|
|
8560
|
+
return;
|
|
8497
8561
|
}
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
};
|
|
8562
|
+
// Refused when the root was used again since this unmount
|
|
8563
|
+
if (!transitionRoot(root, {
|
|
8564
|
+
type: 'dispose',
|
|
8565
|
+
token
|
|
8566
|
+
})) return;
|
|
8567
|
+
// Close the gates before invoking user cleanup code.
|
|
8568
|
+
_roots.delete(canvas);
|
|
8569
|
+
const state = root.store.getState();
|
|
8570
|
+
state.internal.active = false;
|
|
8571
|
+
|
|
8572
|
+
// Release what uses the renderer before the renderer itself
|
|
8573
|
+
attempt(() => state.events.disconnect == null ? void 0 : state.events.disconnect());
|
|
8574
|
+
if ((_state$gl = state.gl) != null && _state$gl.xr) attempt(() => state.xr.disconnect());
|
|
8575
|
+
if (state.scene) attempt(() => dispose(state.scene));
|
|
8576
|
+
const gl = state.gl;
|
|
8577
|
+
let disposal = undefined;
|
|
8578
|
+
if (gl && root.ownsRenderer) {
|
|
8579
|
+
disposal = attempt(() => disposeRenderer(gl));
|
|
8580
|
+
} else if (gl) {
|
|
8581
|
+
// A renderer passed in keeps its 9.x teardown: its context is lost but it is not disposed
|
|
8582
|
+
attempt(() => {
|
|
8583
|
+
var _gl$renderLists2;
|
|
8584
|
+
return (_gl$renderLists2 = gl.renderLists) == null ? void 0 : _gl$renderLists2.dispose == null ? void 0 : _gl$renderLists2.dispose();
|
|
8585
|
+
});
|
|
8586
|
+
attempt(() => gl.forceContextLoss == null ? void 0 : gl.forceContextLoss());
|
|
8587
|
+
}
|
|
8588
|
+
if (isPromiseLike(disposal)) disposal.then(() => callback == null ? void 0 : callback(canvas));else callback == null ? void 0 : callback(canvas);
|
|
8589
|
+
};
|
|
8590
|
+
reconciler.updateContainer(null, root.fiber, null, () => {
|
|
8591
|
+
// A root used again since the unmount keeps its new children
|
|
8592
|
+
if (root.state.status !== 'closing' || root.state.token !== token) return;
|
|
8593
|
+
// Effect cleanups flush before the next update
|
|
8594
|
+
reconciler.updateContainer(null, root.fiber, null, teardown);
|
|
8532
8595
|
});
|
|
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
8596
|
}
|
|
8570
8597
|
|
|
8571
8598
|
function createSubs(callback, subs) {
|
|
@@ -8720,6 +8747,102 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
|
8720
8747
|
if (runGlobalEffects) flushGlobalEffects('after', timestamp);
|
|
8721
8748
|
}
|
|
8722
8749
|
|
|
8750
|
+
function createPortal(children, container, state) {
|
|
8751
|
+
return /*#__PURE__*/jsxRuntime.jsx(Portal, {
|
|
8752
|
+
children: children,
|
|
8753
|
+
container: container,
|
|
8754
|
+
state: state
|
|
8755
|
+
});
|
|
8756
|
+
}
|
|
8757
|
+
function Portal({
|
|
8758
|
+
state = {},
|
|
8759
|
+
children,
|
|
8760
|
+
container
|
|
8761
|
+
}) {
|
|
8762
|
+
/** This has to be a component because it would not be able to call useThree/useStore otherwise since
|
|
8763
|
+
* if this is our environment, then we are not in r3f's renderer but in react-dom, it would trigger
|
|
8764
|
+
* the "R3F hooks can only be used within the Canvas component!" warning:
|
|
8765
|
+
* <Canvas>
|
|
8766
|
+
* {createPortal(...)} */
|
|
8767
|
+
const {
|
|
8768
|
+
events,
|
|
8769
|
+
size,
|
|
8770
|
+
...rest
|
|
8771
|
+
} = state;
|
|
8772
|
+
const previousRoot = useStore();
|
|
8773
|
+
const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
|
|
8774
|
+
const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
|
|
8775
|
+
const inject = useMutableCallback((rootState, injectState) => {
|
|
8776
|
+
let viewport = undefined;
|
|
8777
|
+
if (injectState.camera && size) {
|
|
8778
|
+
const camera = injectState.camera;
|
|
8779
|
+
// Calculate the override viewport, if present
|
|
8780
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new THREE__namespace.Vector3(), size);
|
|
8781
|
+
// Update the portal camera, if it differs from the previous layer
|
|
8782
|
+
if (camera !== rootState.camera) updateCamera(camera, size);
|
|
8783
|
+
}
|
|
8784
|
+
return {
|
|
8785
|
+
// The intersect consists of the previous root state
|
|
8786
|
+
...rootState,
|
|
8787
|
+
...injectState,
|
|
8788
|
+
// Portals have their own scene, which forms the root, a raycaster and a pointer
|
|
8789
|
+
scene: container,
|
|
8790
|
+
raycaster,
|
|
8791
|
+
pointer,
|
|
8792
|
+
mouse: pointer,
|
|
8793
|
+
// Their previous root is the layer before it
|
|
8794
|
+
previousRoot,
|
|
8795
|
+
// Events, size and viewport can be overridden by the inject layer
|
|
8796
|
+
events: {
|
|
8797
|
+
...rootState.events,
|
|
8798
|
+
...injectState.events,
|
|
8799
|
+
...events
|
|
8800
|
+
},
|
|
8801
|
+
size: {
|
|
8802
|
+
...rootState.size,
|
|
8803
|
+
...size
|
|
8804
|
+
},
|
|
8805
|
+
viewport: {
|
|
8806
|
+
...rootState.viewport,
|
|
8807
|
+
...viewport
|
|
8808
|
+
},
|
|
8809
|
+
// Layers are allowed to override events
|
|
8810
|
+
setEvents: events => injectState.set(state => ({
|
|
8811
|
+
...state,
|
|
8812
|
+
events: {
|
|
8813
|
+
...state.events,
|
|
8814
|
+
...events
|
|
8815
|
+
}
|
|
8816
|
+
}))
|
|
8817
|
+
};
|
|
8818
|
+
});
|
|
8819
|
+
const usePortalStore = React__namespace.useMemo(() => {
|
|
8820
|
+
// Create a mirrored store, based on the previous root with a few overrides ...
|
|
8821
|
+
const store = traditional.createWithEqualityFn((set, get) => ({
|
|
8822
|
+
...rest,
|
|
8823
|
+
set,
|
|
8824
|
+
get
|
|
8825
|
+
}));
|
|
8826
|
+
|
|
8827
|
+
// Subscribe to previous root-state and copy changes over to the mirrored portal-state
|
|
8828
|
+
const onMutate = prev => store.setState(state => inject.current(prev, state));
|
|
8829
|
+
onMutate(previousRoot.getState());
|
|
8830
|
+
previousRoot.subscribe(onMutate);
|
|
8831
|
+
return store;
|
|
8832
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
8833
|
+
}, [previousRoot, container]);
|
|
8834
|
+
return (
|
|
8835
|
+
/*#__PURE__*/
|
|
8836
|
+
// @ts-ignore, reconciler types are not maintained
|
|
8837
|
+
jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
8838
|
+
children: reconciler.createPortal( /*#__PURE__*/jsxRuntime.jsx(context.Provider, {
|
|
8839
|
+
value: usePortalStore,
|
|
8840
|
+
children: children
|
|
8841
|
+
}), usePortalStore, null)
|
|
8842
|
+
})
|
|
8843
|
+
);
|
|
8844
|
+
}
|
|
8845
|
+
|
|
8723
8846
|
const DOM_EVENTS = {
|
|
8724
8847
|
onClick: ['click', false],
|
|
8725
8848
|
onContextMenu: ['contextmenu', false],
|