@react-three/fiber 10.0.0-canary.604355a → 10.0.0-canary.aecbafb
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/dist/index.cjs +290 -73
- package/dist/index.d.cts +138 -21
- package/dist/index.d.mts +138 -21
- package/dist/index.d.ts +138 -21
- package/dist/index.mjs +290 -73
- package/dist/legacy.cjs +284 -73
- package/dist/legacy.d.cts +138 -21
- package/dist/legacy.d.mts +138 -21
- package/dist/legacy.d.ts +138 -21
- package/dist/legacy.mjs +284 -73
- package/dist/webgpu/index.cjs +665 -84
- package/dist/webgpu/index.d.cts +223 -34
- package/dist/webgpu/index.d.mts +223 -34
- package/dist/webgpu/index.d.ts +223 -34
- package/dist/webgpu/index.mjs +661 -84
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -996,6 +996,9 @@ function applyProps(object, props) {
|
|
|
996
996
|
else target.set(value);
|
|
997
997
|
} else {
|
|
998
998
|
root[key] = value;
|
|
999
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
1000
|
+
root.needsUpdate = true;
|
|
1001
|
+
}
|
|
999
1002
|
if (rootState && rootState.renderer?.outputColorSpace === webgpu.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
1000
1003
|
root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
|
|
1001
1004
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1029,38 +1032,60 @@ function applyProps(object, props) {
|
|
|
1029
1032
|
return object;
|
|
1030
1033
|
}
|
|
1031
1034
|
|
|
1035
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1036
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1037
|
+
function getPointerState(internal, pointerId) {
|
|
1038
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1039
|
+
if (!state) {
|
|
1040
|
+
state = {
|
|
1041
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1042
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1043
|
+
initialClick: [0, 0],
|
|
1044
|
+
initialHits: []
|
|
1045
|
+
};
|
|
1046
|
+
internal.pointerMap.set(pointerId, state);
|
|
1047
|
+
}
|
|
1048
|
+
return state;
|
|
1049
|
+
}
|
|
1050
|
+
function getPointerId(event) {
|
|
1051
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1052
|
+
}
|
|
1032
1053
|
function makeId(event) {
|
|
1033
1054
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1034
1055
|
}
|
|
1035
|
-
function releaseInternalPointerCapture(
|
|
1036
|
-
const
|
|
1056
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1057
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1058
|
+
if (!pointerState) return;
|
|
1059
|
+
const captureData = pointerState.captured.get(obj);
|
|
1037
1060
|
if (captureData) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
capturedMap.delete(pointerId);
|
|
1041
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1042
|
-
}
|
|
1061
|
+
pointerState.captured.delete(obj);
|
|
1062
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1043
1063
|
}
|
|
1044
1064
|
}
|
|
1045
1065
|
function removeInteractivity(store, object) {
|
|
1046
1066
|
const { internal } = store.getState();
|
|
1047
1067
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1068
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1069
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1070
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1071
|
+
if (value.eventObject === object || value.object === object) {
|
|
1072
|
+
pointerState.hovered.delete(key);
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
if (pointerState.captured.has(object)) {
|
|
1076
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1052
1077
|
}
|
|
1053
|
-
}
|
|
1054
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1055
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1056
|
-
});
|
|
1078
|
+
}
|
|
1057
1079
|
unregisterVisibility(store, object);
|
|
1058
1080
|
}
|
|
1059
1081
|
function createEvents(store) {
|
|
1060
|
-
function calculateDistance(event) {
|
|
1082
|
+
function calculateDistance(event, pointerId) {
|
|
1061
1083
|
const { internal } = store.getState();
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1084
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1085
|
+
if (!pointerState) return 0;
|
|
1086
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1087
|
+
const dx = event.offsetX - initialX;
|
|
1088
|
+
const dy = event.offsetY - initialY;
|
|
1064
1089
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1065
1090
|
}
|
|
1066
1091
|
function filterPointerEvents(objects) {
|
|
@@ -1096,6 +1121,15 @@ function createEvents(store) {
|
|
|
1096
1121
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1097
1122
|
}
|
|
1098
1123
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1124
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1125
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1126
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1127
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1128
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1129
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1130
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1099
1133
|
const aState = getRootState(a.object);
|
|
1100
1134
|
const bState = getRootState(b.object);
|
|
1101
1135
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1117,9 +1151,13 @@ function createEvents(store) {
|
|
|
1117
1151
|
eventObject = eventObject.parent;
|
|
1118
1152
|
}
|
|
1119
1153
|
}
|
|
1120
|
-
if ("pointerId" in event
|
|
1121
|
-
|
|
1122
|
-
|
|
1154
|
+
if ("pointerId" in event) {
|
|
1155
|
+
const pointerId = event.pointerId;
|
|
1156
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1157
|
+
if (pointerState?.captured.size) {
|
|
1158
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1159
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1160
|
+
}
|
|
1123
1161
|
}
|
|
1124
1162
|
}
|
|
1125
1163
|
return intersections;
|
|
@@ -1132,27 +1170,25 @@ function createEvents(store) {
|
|
|
1132
1170
|
if (state) {
|
|
1133
1171
|
const { raycaster, pointer, camera, internal } = state;
|
|
1134
1172
|
const unprojectedPoint = new webgpu.Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1135
|
-
const hasPointerCapture = (id) =>
|
|
1173
|
+
const hasPointerCapture = (id) => {
|
|
1174
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1175
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1176
|
+
};
|
|
1136
1177
|
const setPointerCapture = (id) => {
|
|
1137
1178
|
const captureData = { intersection: hit, target: event.target };
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
} else {
|
|
1141
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1142
|
-
}
|
|
1179
|
+
const pointerState = getPointerState(internal, id);
|
|
1180
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1143
1181
|
event.target.setPointerCapture(id);
|
|
1144
1182
|
};
|
|
1145
1183
|
const releasePointerCapture = (id) => {
|
|
1146
|
-
|
|
1147
|
-
if (captures) {
|
|
1148
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1149
|
-
}
|
|
1184
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1150
1185
|
};
|
|
1151
1186
|
const extractEventProps = {};
|
|
1152
1187
|
for (const prop in event) {
|
|
1153
1188
|
const property = event[prop];
|
|
1154
1189
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1155
1190
|
}
|
|
1191
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1156
1192
|
const raycastEvent = {
|
|
1157
1193
|
...hit,
|
|
1158
1194
|
...extractEventProps,
|
|
@@ -1163,18 +1199,19 @@ function createEvents(store) {
|
|
|
1163
1199
|
unprojectedPoint,
|
|
1164
1200
|
ray: raycaster.ray,
|
|
1165
1201
|
camera,
|
|
1202
|
+
pointerId: eventPointerId,
|
|
1166
1203
|
// Hijack stopPropagation, which just sets a flag
|
|
1167
1204
|
stopPropagation() {
|
|
1168
|
-
const
|
|
1205
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1169
1206
|
if (
|
|
1170
1207
|
// ...if this pointer hasn't been captured
|
|
1171
|
-
!
|
|
1172
|
-
|
|
1208
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1209
|
+
pointerState.captured.has(hit.eventObject)
|
|
1173
1210
|
) {
|
|
1174
1211
|
raycastEvent.stopped = localState.stopped = true;
|
|
1175
|
-
if (
|
|
1212
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1176
1213
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1177
|
-
cancelPointer([...higher, hit]);
|
|
1214
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1178
1215
|
}
|
|
1179
1216
|
}
|
|
1180
1217
|
},
|
|
@@ -1190,15 +1227,18 @@ function createEvents(store) {
|
|
|
1190
1227
|
}
|
|
1191
1228
|
return intersections;
|
|
1192
1229
|
}
|
|
1193
|
-
function cancelPointer(intersections) {
|
|
1230
|
+
function cancelPointer(intersections, pointerId) {
|
|
1194
1231
|
const { internal } = store.getState();
|
|
1195
|
-
|
|
1232
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1233
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1234
|
+
if (!pointerState) return;
|
|
1235
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1196
1236
|
if (!intersections.length || !intersections.find(
|
|
1197
1237
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1198
1238
|
)) {
|
|
1199
1239
|
const eventObject = hoveredObj.eventObject;
|
|
1200
1240
|
const instance = eventObject.__r3f;
|
|
1201
|
-
|
|
1241
|
+
pointerState.hovered.delete(hoveredId);
|
|
1202
1242
|
if (instance?.eventCount) {
|
|
1203
1243
|
const handlers = instance.handlers;
|
|
1204
1244
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1227,41 +1267,118 @@ function createEvents(store) {
|
|
|
1227
1267
|
instance?.handlers.onDropMissed?.(event);
|
|
1228
1268
|
}
|
|
1229
1269
|
}
|
|
1270
|
+
function cleanupPointer(pointerId) {
|
|
1271
|
+
const { internal } = store.getState();
|
|
1272
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1273
|
+
if (pointerState) {
|
|
1274
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1275
|
+
const eventObject = hoveredObj.eventObject;
|
|
1276
|
+
const instance = eventObject.__r3f;
|
|
1277
|
+
if (instance?.eventCount) {
|
|
1278
|
+
const handlers = instance.handlers;
|
|
1279
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1280
|
+
handlers.onPointerOut?.(data);
|
|
1281
|
+
handlers.onPointerLeave?.(data);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
internal.pointerMap.delete(pointerId);
|
|
1285
|
+
}
|
|
1286
|
+
internal.pointerDirty.delete(pointerId);
|
|
1287
|
+
}
|
|
1288
|
+
function processDeferredPointer(event, pointerId) {
|
|
1289
|
+
const state = store.getState();
|
|
1290
|
+
const { onPointerMissed, onDragOverMissed, internal } = state;
|
|
1291
|
+
if (!state.events.enabled) return;
|
|
1292
|
+
const filter = filterPointerEvents;
|
|
1293
|
+
const hits = intersect(event, filter);
|
|
1294
|
+
cancelPointer(hits, pointerId);
|
|
1295
|
+
function onIntersect(data) {
|
|
1296
|
+
const eventObject = data.eventObject;
|
|
1297
|
+
const instance = eventObject.__r3f;
|
|
1298
|
+
if (!instance?.eventCount) return;
|
|
1299
|
+
const handlers = instance.handlers;
|
|
1300
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1301
|
+
const id = makeId(data);
|
|
1302
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1303
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1304
|
+
if (!hoveredItem) {
|
|
1305
|
+
pointerState.hovered.set(id, data);
|
|
1306
|
+
handlers.onPointerOver?.(data);
|
|
1307
|
+
handlers.onPointerEnter?.(data);
|
|
1308
|
+
} else if (hoveredItem.stopped) {
|
|
1309
|
+
data.stopPropagation();
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
handlers.onPointerMove?.(data);
|
|
1313
|
+
}
|
|
1314
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1315
|
+
}
|
|
1230
1316
|
function handlePointer(name) {
|
|
1231
1317
|
switch (name) {
|
|
1232
1318
|
case "onPointerLeave":
|
|
1233
|
-
case "onPointerCancel":
|
|
1234
1319
|
case "onDragLeave":
|
|
1235
1320
|
return () => cancelPointer([]);
|
|
1321
|
+
// Global cancel of these events
|
|
1322
|
+
case "onPointerCancel":
|
|
1323
|
+
return (event) => {
|
|
1324
|
+
const pointerId = getPointerId(event);
|
|
1325
|
+
cleanupPointer(pointerId);
|
|
1326
|
+
};
|
|
1236
1327
|
case "onLostPointerCapture":
|
|
1237
1328
|
return (event) => {
|
|
1238
1329
|
const { internal } = store.getState();
|
|
1239
|
-
|
|
1330
|
+
const pointerId = getPointerId(event);
|
|
1331
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1332
|
+
if (pointerState?.captured.size) {
|
|
1240
1333
|
requestAnimationFrame(() => {
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1334
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1335
|
+
if (pointerState2?.captured.size) {
|
|
1336
|
+
pointerState2.captured.clear();
|
|
1244
1337
|
}
|
|
1338
|
+
cancelPointer([], pointerId);
|
|
1245
1339
|
});
|
|
1246
1340
|
}
|
|
1247
1341
|
};
|
|
1248
1342
|
}
|
|
1249
1343
|
return function handleEvent(event) {
|
|
1250
1344
|
const state = store.getState();
|
|
1251
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1345
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1346
|
+
const pointerId = getPointerId(event);
|
|
1252
1347
|
internal.lastEvent.current = event;
|
|
1253
|
-
if (!
|
|
1348
|
+
if (!events.enabled) return;
|
|
1254
1349
|
const isPointerMove = name === "onPointerMove";
|
|
1255
1350
|
const isDragOver = name === "onDragOver";
|
|
1256
1351
|
const isDrop = name === "onDrop";
|
|
1257
1352
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1353
|
+
const isPointerDown = name === "onPointerDown";
|
|
1354
|
+
const isPointerUp = name === "onPointerUp";
|
|
1355
|
+
const isWheel = name === "onWheel";
|
|
1356
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1357
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1358
|
+
events.compute?.(event, state);
|
|
1359
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1363
|
+
events.compute?.(event, state);
|
|
1364
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1368
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1369
|
+
internal.pointerDirty.delete(pointerId);
|
|
1370
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1371
|
+
}
|
|
1258
1372
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1259
1373
|
const hits = intersect(event, filter);
|
|
1260
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1374
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1375
|
+
if (isPointerDown) {
|
|
1376
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1377
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1378
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1379
|
+
}
|
|
1380
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1381
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1265
1382
|
if (isClickEvent && !hits.length) {
|
|
1266
1383
|
if (delta <= 2) {
|
|
1267
1384
|
pointerMissed(event, internal.interaction);
|
|
@@ -1276,7 +1393,9 @@ function createEvents(store) {
|
|
|
1276
1393
|
dropMissed(event, internal.interaction);
|
|
1277
1394
|
if (onDropMissed) onDropMissed(event);
|
|
1278
1395
|
}
|
|
1279
|
-
if (isPointerMove || isDragOver)
|
|
1396
|
+
if (isPointerMove || isDragOver) {
|
|
1397
|
+
cancelPointer(hits, pointerId);
|
|
1398
|
+
}
|
|
1280
1399
|
function onIntersect(data) {
|
|
1281
1400
|
const eventObject = data.eventObject;
|
|
1282
1401
|
const instance = eventObject.__r3f;
|
|
@@ -1285,9 +1404,10 @@ function createEvents(store) {
|
|
|
1285
1404
|
if (isPointerMove) {
|
|
1286
1405
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1287
1406
|
const id = makeId(data);
|
|
1288
|
-
const
|
|
1407
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1408
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1289
1409
|
if (!hoveredItem) {
|
|
1290
|
-
|
|
1410
|
+
pointerState2.hovered.set(id, data);
|
|
1291
1411
|
handlers.onPointerOver?.(data);
|
|
1292
1412
|
handlers.onPointerEnter?.(data);
|
|
1293
1413
|
} else if (hoveredItem.stopped) {
|
|
@@ -1297,9 +1417,10 @@ function createEvents(store) {
|
|
|
1297
1417
|
handlers.onPointerMove?.(data);
|
|
1298
1418
|
} else if (isDragOver) {
|
|
1299
1419
|
const id = makeId(data);
|
|
1300
|
-
const
|
|
1420
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1421
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1301
1422
|
if (!hoveredItem) {
|
|
1302
|
-
|
|
1423
|
+
pointerState2.hovered.set(id, data);
|
|
1303
1424
|
handlers.onDragOverEnter?.(data);
|
|
1304
1425
|
} else if (hoveredItem.stopped) {
|
|
1305
1426
|
data.stopPropagation();
|
|
@@ -1310,18 +1431,18 @@ function createEvents(store) {
|
|
|
1310
1431
|
} else {
|
|
1311
1432
|
const handler = handlers[name];
|
|
1312
1433
|
if (handler) {
|
|
1313
|
-
if (!isClickEvent ||
|
|
1434
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1314
1435
|
pointerMissed(
|
|
1315
1436
|
event,
|
|
1316
|
-
internal.interaction.filter((object) => !
|
|
1437
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1317
1438
|
);
|
|
1318
1439
|
handler(data);
|
|
1319
1440
|
}
|
|
1320
1441
|
} else {
|
|
1321
|
-
if (isClickEvent &&
|
|
1442
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1322
1443
|
pointerMissed(
|
|
1323
1444
|
event,
|
|
1324
|
-
internal.interaction.filter((object) => !
|
|
1445
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1325
1446
|
);
|
|
1326
1447
|
}
|
|
1327
1448
|
}
|
|
@@ -1330,7 +1451,15 @@ function createEvents(store) {
|
|
|
1330
1451
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1331
1452
|
};
|
|
1332
1453
|
}
|
|
1333
|
-
|
|
1454
|
+
function flushDeferredPointers() {
|
|
1455
|
+
const { internal, events } = store.getState();
|
|
1456
|
+
if (!events.frameTimedRaycasts) return;
|
|
1457
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1458
|
+
processDeferredPointer(event, pointerId);
|
|
1459
|
+
}
|
|
1460
|
+
internal.pointerDirty.clear();
|
|
1461
|
+
}
|
|
1462
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1334
1463
|
}
|
|
1335
1464
|
const DOM_EVENTS = {
|
|
1336
1465
|
onClick: ["click", false],
|
|
@@ -1349,10 +1478,15 @@ const DOM_EVENTS = {
|
|
|
1349
1478
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1350
1479
|
};
|
|
1351
1480
|
function createPointerEvents(store) {
|
|
1352
|
-
const { handlePointer } = createEvents(store);
|
|
1481
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1482
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1483
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1353
1484
|
return {
|
|
1354
1485
|
priority: 1,
|
|
1355
1486
|
enabled: true,
|
|
1487
|
+
frameTimedRaycasts: true,
|
|
1488
|
+
alwaysFireOnScroll: true,
|
|
1489
|
+
updateOnFrame: false,
|
|
1356
1490
|
compute(event, state) {
|
|
1357
1491
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1358
1492
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1362,9 +1496,30 @@ function createPointerEvents(store) {
|
|
|
1362
1496
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1363
1497
|
{}
|
|
1364
1498
|
),
|
|
1365
|
-
update: () => {
|
|
1499
|
+
update: (pointerId) => {
|
|
1500
|
+
const { events, internal } = store.getState();
|
|
1501
|
+
if (!events.handlers) return;
|
|
1502
|
+
if (pointerId !== void 0) {
|
|
1503
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1504
|
+
if (event) {
|
|
1505
|
+
internal.pointerDirty.delete(pointerId);
|
|
1506
|
+
processDeferredPointer(event, pointerId);
|
|
1507
|
+
} else if (internal.lastEvent?.current) {
|
|
1508
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1509
|
+
}
|
|
1510
|
+
} else {
|
|
1511
|
+
flushDeferredPointers();
|
|
1512
|
+
if (internal.lastEvent?.current) {
|
|
1513
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
},
|
|
1517
|
+
flush: () => {
|
|
1366
1518
|
const { events, internal } = store.getState();
|
|
1367
|
-
|
|
1519
|
+
flushDeferredPointers();
|
|
1520
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1521
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1522
|
+
}
|
|
1368
1523
|
},
|
|
1369
1524
|
connect: (target) => {
|
|
1370
1525
|
const { set, events } = store.getState();
|
|
@@ -1390,6 +1545,32 @@ function createPointerEvents(store) {
|
|
|
1390
1545
|
}
|
|
1391
1546
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1392
1547
|
}
|
|
1548
|
+
},
|
|
1549
|
+
registerPointer: (config) => {
|
|
1550
|
+
const pointerId = nextXRPointerId++;
|
|
1551
|
+
xrPointers.set(pointerId, config);
|
|
1552
|
+
const { internal } = store.getState();
|
|
1553
|
+
getPointerState(internal, pointerId);
|
|
1554
|
+
return pointerId;
|
|
1555
|
+
},
|
|
1556
|
+
unregisterPointer: (pointerId) => {
|
|
1557
|
+
xrPointers.delete(pointerId);
|
|
1558
|
+
const { internal } = store.getState();
|
|
1559
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1560
|
+
if (pointerState) {
|
|
1561
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1562
|
+
const eventObject = hoveredObj.eventObject;
|
|
1563
|
+
const instance = eventObject.__r3f;
|
|
1564
|
+
if (instance?.eventCount) {
|
|
1565
|
+
const handlers = instance.handlers;
|
|
1566
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1567
|
+
handlers.onPointerOut?.(data);
|
|
1568
|
+
handlers.onPointerLeave?.(data);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
internal.pointerMap.delete(pointerId);
|
|
1572
|
+
}
|
|
1573
|
+
internal.pointerDirty.delete(pointerId);
|
|
1393
1574
|
}
|
|
1394
1575
|
};
|
|
1395
1576
|
}
|
|
@@ -2520,7 +2701,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2520
2701
|
frustum: new webgpu.Frustum(),
|
|
2521
2702
|
autoUpdateFrustum: true,
|
|
2522
2703
|
raycaster: null,
|
|
2523
|
-
events: {
|
|
2704
|
+
events: {
|
|
2705
|
+
priority: 1,
|
|
2706
|
+
enabled: true,
|
|
2707
|
+
connected: false,
|
|
2708
|
+
frameTimedRaycasts: true,
|
|
2709
|
+
alwaysFireOnScroll: true,
|
|
2710
|
+
updateOnFrame: false
|
|
2711
|
+
},
|
|
2524
2712
|
scene: null,
|
|
2525
2713
|
rootScene: null,
|
|
2526
2714
|
xr: null,
|
|
@@ -2611,11 +2799,13 @@ const createStore = (invalidate, advance) => {
|
|
|
2611
2799
|
},
|
|
2612
2800
|
setError: (error) => set(() => ({ error })),
|
|
2613
2801
|
error: null,
|
|
2614
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2802
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2615
2803
|
uniforms: {},
|
|
2616
2804
|
nodes: {},
|
|
2805
|
+
buffers: {},
|
|
2806
|
+
gpuStorage: {},
|
|
2617
2807
|
textures: /* @__PURE__ */ new Map(),
|
|
2618
|
-
|
|
2808
|
+
renderPipeline: null,
|
|
2619
2809
|
passes: {},
|
|
2620
2810
|
_hmrVersion: 0,
|
|
2621
2811
|
_sizeImperative: false,
|
|
@@ -2624,12 +2814,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2624
2814
|
internal: {
|
|
2625
2815
|
// Events
|
|
2626
2816
|
interaction: [],
|
|
2627
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2628
2817
|
subscribers: [],
|
|
2818
|
+
// Per-pointer state (new unified structure)
|
|
2819
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2820
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2821
|
+
lastEvent: React__namespace.createRef(),
|
|
2822
|
+
// Deprecated but kept for backwards compatibility
|
|
2823
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2629
2824
|
initialClick: [0, 0],
|
|
2630
2825
|
initialHits: [],
|
|
2631
2826
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2632
|
-
lastEvent: React__namespace.createRef(),
|
|
2633
2827
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2634
2828
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2635
2829
|
// Occlusion system (WebGPU only)
|
|
@@ -15081,6 +15275,12 @@ function createRoot(canvas) {
|
|
|
15081
15275
|
} else if (!wantsGL && !state.internal.actualRenderer) {
|
|
15082
15276
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
|
|
15083
15277
|
if (!renderer.hasInitialized?.()) {
|
|
15278
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15279
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15280
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15281
|
+
canvas.width = size2.width * pixelRatio;
|
|
15282
|
+
canvas.height = size2.height * pixelRatio;
|
|
15283
|
+
}
|
|
15084
15284
|
await renderer.init();
|
|
15085
15285
|
}
|
|
15086
15286
|
const backend = renderer.backend;
|
|
@@ -15282,6 +15482,18 @@ function createRoot(canvas) {
|
|
|
15282
15482
|
system: true
|
|
15283
15483
|
}
|
|
15284
15484
|
);
|
|
15485
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15486
|
+
() => {
|
|
15487
|
+
const state2 = store.getState();
|
|
15488
|
+
state2.events.flush?.();
|
|
15489
|
+
},
|
|
15490
|
+
{
|
|
15491
|
+
id: `${newRootId}_events`,
|
|
15492
|
+
rootId: newRootId,
|
|
15493
|
+
phase: "input",
|
|
15494
|
+
system: true
|
|
15495
|
+
}
|
|
15496
|
+
);
|
|
15285
15497
|
const unregisterFrustum = scheduler.register(
|
|
15286
15498
|
() => {
|
|
15287
15499
|
const state2 = store.getState();
|
|
@@ -15316,7 +15528,7 @@ function createRoot(canvas) {
|
|
|
15316
15528
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15317
15529
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15318
15530
|
try {
|
|
15319
|
-
if (state2.
|
|
15531
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15320
15532
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15321
15533
|
} catch (error) {
|
|
15322
15534
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15341,6 +15553,7 @@ function createRoot(canvas) {
|
|
|
15341
15553
|
unregisterRoot: () => {
|
|
15342
15554
|
unregisterRoot();
|
|
15343
15555
|
unregisterCanvasTarget();
|
|
15556
|
+
unregisterEventsFlush();
|
|
15344
15557
|
unregisterFrustum();
|
|
15345
15558
|
unregisterVisibility();
|
|
15346
15559
|
unregisterRender();
|
|
@@ -15506,9 +15719,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15506
15719
|
const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15507
15720
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15508
15721
|
onMutate(previousRoot.getState());
|
|
15509
|
-
previousRoot.subscribe(onMutate);
|
|
15510
15722
|
return store;
|
|
15511
15723
|
}, [previousRoot, container]);
|
|
15724
|
+
useIsomorphicLayoutEffect(() => {
|
|
15725
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15726
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15727
|
+
return unsubscribe;
|
|
15728
|
+
}, [previousRoot, usePortalStore]);
|
|
15512
15729
|
return (
|
|
15513
15730
|
// @ts-ignore, reconciler types are not maintained
|
|
15514
15731
|
/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
|
|
@@ -15729,6 +15946,7 @@ function CanvasImpl({
|
|
|
15729
15946
|
queueMicrotask(() => {
|
|
15730
15947
|
const rootEntry = _roots.get(canvas);
|
|
15731
15948
|
if (rootEntry?.store) {
|
|
15949
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15732
15950
|
rootEntry.store.setState((state) => ({
|
|
15733
15951
|
nodes: {},
|
|
15734
15952
|
uniforms: {},
|
|
@@ -15740,8 +15958,7 @@ function CanvasImpl({
|
|
|
15740
15958
|
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
|
|
15741
15959
|
const hot = undefined;
|
|
15742
15960
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15743
|
-
return () => hot.
|
|
15744
|
-
});
|
|
15961
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15745
15962
|
}
|
|
15746
15963
|
if (typeof module !== "undefined" && module.hot) {
|
|
15747
15964
|
const hot = module.hot;
|