@react-three/fiber 10.0.0-canary.2b511a5 → 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/legacy.mjs
CHANGED
|
@@ -984,6 +984,9 @@ function applyProps(object, props) {
|
|
|
984
984
|
else target.set(value);
|
|
985
985
|
} else {
|
|
986
986
|
root[key] = value;
|
|
987
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
988
|
+
root.needsUpdate = true;
|
|
989
|
+
}
|
|
987
990
|
if (rootState && rootState.renderer?.outputColorSpace === SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
988
991
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
989
992
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1017,38 +1020,60 @@ function applyProps(object, props) {
|
|
|
1017
1020
|
return object;
|
|
1018
1021
|
}
|
|
1019
1022
|
|
|
1023
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1024
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1025
|
+
function getPointerState(internal, pointerId) {
|
|
1026
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1027
|
+
if (!state) {
|
|
1028
|
+
state = {
|
|
1029
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1030
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1031
|
+
initialClick: [0, 0],
|
|
1032
|
+
initialHits: []
|
|
1033
|
+
};
|
|
1034
|
+
internal.pointerMap.set(pointerId, state);
|
|
1035
|
+
}
|
|
1036
|
+
return state;
|
|
1037
|
+
}
|
|
1038
|
+
function getPointerId(event) {
|
|
1039
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1040
|
+
}
|
|
1020
1041
|
function makeId(event) {
|
|
1021
1042
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1022
1043
|
}
|
|
1023
|
-
function releaseInternalPointerCapture(
|
|
1024
|
-
const
|
|
1044
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1045
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1046
|
+
if (!pointerState) return;
|
|
1047
|
+
const captureData = pointerState.captured.get(obj);
|
|
1025
1048
|
if (captureData) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
capturedMap.delete(pointerId);
|
|
1029
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1030
|
-
}
|
|
1049
|
+
pointerState.captured.delete(obj);
|
|
1050
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1031
1051
|
}
|
|
1032
1052
|
}
|
|
1033
1053
|
function removeInteractivity(store, object) {
|
|
1034
1054
|
const { internal } = store.getState();
|
|
1035
1055
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1056
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1057
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1058
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1059
|
+
if (value.eventObject === object || value.object === object) {
|
|
1060
|
+
pointerState.hovered.delete(key);
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
if (pointerState.captured.has(object)) {
|
|
1064
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1040
1065
|
}
|
|
1041
|
-
}
|
|
1042
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1043
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1044
|
-
});
|
|
1066
|
+
}
|
|
1045
1067
|
unregisterVisibility(store, object);
|
|
1046
1068
|
}
|
|
1047
1069
|
function createEvents(store) {
|
|
1048
|
-
function calculateDistance(event) {
|
|
1070
|
+
function calculateDistance(event, pointerId) {
|
|
1049
1071
|
const { internal } = store.getState();
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1072
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1073
|
+
if (!pointerState) return 0;
|
|
1074
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1075
|
+
const dx = event.offsetX - initialX;
|
|
1076
|
+
const dy = event.offsetY - initialY;
|
|
1052
1077
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1053
1078
|
}
|
|
1054
1079
|
function filterPointerEvents(objects) {
|
|
@@ -1084,6 +1109,15 @@ function createEvents(store) {
|
|
|
1084
1109
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1085
1110
|
}
|
|
1086
1111
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1112
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1113
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1114
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1115
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1116
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1117
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1118
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1087
1121
|
const aState = getRootState(a.object);
|
|
1088
1122
|
const bState = getRootState(b.object);
|
|
1089
1123
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1105,9 +1139,13 @@ function createEvents(store) {
|
|
|
1105
1139
|
eventObject = eventObject.parent;
|
|
1106
1140
|
}
|
|
1107
1141
|
}
|
|
1108
|
-
if ("pointerId" in event
|
|
1109
|
-
|
|
1110
|
-
|
|
1142
|
+
if ("pointerId" in event) {
|
|
1143
|
+
const pointerId = event.pointerId;
|
|
1144
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1145
|
+
if (pointerState?.captured.size) {
|
|
1146
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1147
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1148
|
+
}
|
|
1111
1149
|
}
|
|
1112
1150
|
}
|
|
1113
1151
|
return intersections;
|
|
@@ -1120,27 +1158,25 @@ function createEvents(store) {
|
|
|
1120
1158
|
if (state) {
|
|
1121
1159
|
const { raycaster, pointer, camera, internal } = state;
|
|
1122
1160
|
const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1123
|
-
const hasPointerCapture = (id) =>
|
|
1161
|
+
const hasPointerCapture = (id) => {
|
|
1162
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1163
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1164
|
+
};
|
|
1124
1165
|
const setPointerCapture = (id) => {
|
|
1125
1166
|
const captureData = { intersection: hit, target: event.target };
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
} else {
|
|
1129
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1130
|
-
}
|
|
1167
|
+
const pointerState = getPointerState(internal, id);
|
|
1168
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1131
1169
|
event.target.setPointerCapture(id);
|
|
1132
1170
|
};
|
|
1133
1171
|
const releasePointerCapture = (id) => {
|
|
1134
|
-
|
|
1135
|
-
if (captures) {
|
|
1136
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1137
|
-
}
|
|
1172
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1138
1173
|
};
|
|
1139
1174
|
const extractEventProps = {};
|
|
1140
1175
|
for (const prop in event) {
|
|
1141
1176
|
const property = event[prop];
|
|
1142
1177
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1143
1178
|
}
|
|
1179
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1144
1180
|
const raycastEvent = {
|
|
1145
1181
|
...hit,
|
|
1146
1182
|
...extractEventProps,
|
|
@@ -1151,18 +1187,19 @@ function createEvents(store) {
|
|
|
1151
1187
|
unprojectedPoint,
|
|
1152
1188
|
ray: raycaster.ray,
|
|
1153
1189
|
camera,
|
|
1190
|
+
pointerId: eventPointerId,
|
|
1154
1191
|
// Hijack stopPropagation, which just sets a flag
|
|
1155
1192
|
stopPropagation() {
|
|
1156
|
-
const
|
|
1193
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1157
1194
|
if (
|
|
1158
1195
|
// ...if this pointer hasn't been captured
|
|
1159
|
-
!
|
|
1160
|
-
|
|
1196
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1197
|
+
pointerState.captured.has(hit.eventObject)
|
|
1161
1198
|
) {
|
|
1162
1199
|
raycastEvent.stopped = localState.stopped = true;
|
|
1163
|
-
if (
|
|
1200
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1164
1201
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1165
|
-
cancelPointer([...higher, hit]);
|
|
1202
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1166
1203
|
}
|
|
1167
1204
|
}
|
|
1168
1205
|
},
|
|
@@ -1178,15 +1215,18 @@ function createEvents(store) {
|
|
|
1178
1215
|
}
|
|
1179
1216
|
return intersections;
|
|
1180
1217
|
}
|
|
1181
|
-
function cancelPointer(intersections) {
|
|
1218
|
+
function cancelPointer(intersections, pointerId) {
|
|
1182
1219
|
const { internal } = store.getState();
|
|
1183
|
-
|
|
1220
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1221
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1222
|
+
if (!pointerState) return;
|
|
1223
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1184
1224
|
if (!intersections.length || !intersections.find(
|
|
1185
1225
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1186
1226
|
)) {
|
|
1187
1227
|
const eventObject = hoveredObj.eventObject;
|
|
1188
1228
|
const instance = eventObject.__r3f;
|
|
1189
|
-
|
|
1229
|
+
pointerState.hovered.delete(hoveredId);
|
|
1190
1230
|
if (instance?.eventCount) {
|
|
1191
1231
|
const handlers = instance.handlers;
|
|
1192
1232
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1215,41 +1255,118 @@ function createEvents(store) {
|
|
|
1215
1255
|
instance?.handlers.onDropMissed?.(event);
|
|
1216
1256
|
}
|
|
1217
1257
|
}
|
|
1258
|
+
function cleanupPointer(pointerId) {
|
|
1259
|
+
const { internal } = store.getState();
|
|
1260
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1261
|
+
if (pointerState) {
|
|
1262
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1263
|
+
const eventObject = hoveredObj.eventObject;
|
|
1264
|
+
const instance = eventObject.__r3f;
|
|
1265
|
+
if (instance?.eventCount) {
|
|
1266
|
+
const handlers = instance.handlers;
|
|
1267
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1268
|
+
handlers.onPointerOut?.(data);
|
|
1269
|
+
handlers.onPointerLeave?.(data);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
internal.pointerMap.delete(pointerId);
|
|
1273
|
+
}
|
|
1274
|
+
internal.pointerDirty.delete(pointerId);
|
|
1275
|
+
}
|
|
1276
|
+
function processDeferredPointer(event, pointerId) {
|
|
1277
|
+
const state = store.getState();
|
|
1278
|
+
const { onPointerMissed, onDragOverMissed, internal } = state;
|
|
1279
|
+
if (!state.events.enabled) return;
|
|
1280
|
+
const filter = filterPointerEvents;
|
|
1281
|
+
const hits = intersect(event, filter);
|
|
1282
|
+
cancelPointer(hits, pointerId);
|
|
1283
|
+
function onIntersect(data) {
|
|
1284
|
+
const eventObject = data.eventObject;
|
|
1285
|
+
const instance = eventObject.__r3f;
|
|
1286
|
+
if (!instance?.eventCount) return;
|
|
1287
|
+
const handlers = instance.handlers;
|
|
1288
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1289
|
+
const id = makeId(data);
|
|
1290
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1291
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1292
|
+
if (!hoveredItem) {
|
|
1293
|
+
pointerState.hovered.set(id, data);
|
|
1294
|
+
handlers.onPointerOver?.(data);
|
|
1295
|
+
handlers.onPointerEnter?.(data);
|
|
1296
|
+
} else if (hoveredItem.stopped) {
|
|
1297
|
+
data.stopPropagation();
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
handlers.onPointerMove?.(data);
|
|
1301
|
+
}
|
|
1302
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1303
|
+
}
|
|
1218
1304
|
function handlePointer(name) {
|
|
1219
1305
|
switch (name) {
|
|
1220
1306
|
case "onPointerLeave":
|
|
1221
|
-
case "onPointerCancel":
|
|
1222
1307
|
case "onDragLeave":
|
|
1223
1308
|
return () => cancelPointer([]);
|
|
1309
|
+
// Global cancel of these events
|
|
1310
|
+
case "onPointerCancel":
|
|
1311
|
+
return (event) => {
|
|
1312
|
+
const pointerId = getPointerId(event);
|
|
1313
|
+
cleanupPointer(pointerId);
|
|
1314
|
+
};
|
|
1224
1315
|
case "onLostPointerCapture":
|
|
1225
1316
|
return (event) => {
|
|
1226
1317
|
const { internal } = store.getState();
|
|
1227
|
-
|
|
1318
|
+
const pointerId = getPointerId(event);
|
|
1319
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1320
|
+
if (pointerState?.captured.size) {
|
|
1228
1321
|
requestAnimationFrame(() => {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1322
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1323
|
+
if (pointerState2?.captured.size) {
|
|
1324
|
+
pointerState2.captured.clear();
|
|
1232
1325
|
}
|
|
1326
|
+
cancelPointer([], pointerId);
|
|
1233
1327
|
});
|
|
1234
1328
|
}
|
|
1235
1329
|
};
|
|
1236
1330
|
}
|
|
1237
1331
|
return function handleEvent(event) {
|
|
1238
1332
|
const state = store.getState();
|
|
1239
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1333
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1334
|
+
const pointerId = getPointerId(event);
|
|
1240
1335
|
internal.lastEvent.current = event;
|
|
1241
|
-
if (!
|
|
1336
|
+
if (!events.enabled) return;
|
|
1242
1337
|
const isPointerMove = name === "onPointerMove";
|
|
1243
1338
|
const isDragOver = name === "onDragOver";
|
|
1244
1339
|
const isDrop = name === "onDrop";
|
|
1245
1340
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1341
|
+
const isPointerDown = name === "onPointerDown";
|
|
1342
|
+
const isPointerUp = name === "onPointerUp";
|
|
1343
|
+
const isWheel = name === "onWheel";
|
|
1344
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1345
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1346
|
+
events.compute?.(event, state);
|
|
1347
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1351
|
+
events.compute?.(event, state);
|
|
1352
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1356
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1357
|
+
internal.pointerDirty.delete(pointerId);
|
|
1358
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1359
|
+
}
|
|
1246
1360
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1247
1361
|
const hits = intersect(event, filter);
|
|
1248
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1249
|
-
if (
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1362
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1363
|
+
if (isPointerDown) {
|
|
1364
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1365
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1366
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1367
|
+
}
|
|
1368
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1369
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1253
1370
|
if (isClickEvent && !hits.length) {
|
|
1254
1371
|
if (delta <= 2) {
|
|
1255
1372
|
pointerMissed(event, internal.interaction);
|
|
@@ -1264,7 +1381,9 @@ function createEvents(store) {
|
|
|
1264
1381
|
dropMissed(event, internal.interaction);
|
|
1265
1382
|
if (onDropMissed) onDropMissed(event);
|
|
1266
1383
|
}
|
|
1267
|
-
if (isPointerMove || isDragOver)
|
|
1384
|
+
if (isPointerMove || isDragOver) {
|
|
1385
|
+
cancelPointer(hits, pointerId);
|
|
1386
|
+
}
|
|
1268
1387
|
function onIntersect(data) {
|
|
1269
1388
|
const eventObject = data.eventObject;
|
|
1270
1389
|
const instance = eventObject.__r3f;
|
|
@@ -1273,9 +1392,10 @@ function createEvents(store) {
|
|
|
1273
1392
|
if (isPointerMove) {
|
|
1274
1393
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1275
1394
|
const id = makeId(data);
|
|
1276
|
-
const
|
|
1395
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1396
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1277
1397
|
if (!hoveredItem) {
|
|
1278
|
-
|
|
1398
|
+
pointerState2.hovered.set(id, data);
|
|
1279
1399
|
handlers.onPointerOver?.(data);
|
|
1280
1400
|
handlers.onPointerEnter?.(data);
|
|
1281
1401
|
} else if (hoveredItem.stopped) {
|
|
@@ -1285,9 +1405,10 @@ function createEvents(store) {
|
|
|
1285
1405
|
handlers.onPointerMove?.(data);
|
|
1286
1406
|
} else if (isDragOver) {
|
|
1287
1407
|
const id = makeId(data);
|
|
1288
|
-
const
|
|
1408
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1409
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1289
1410
|
if (!hoveredItem) {
|
|
1290
|
-
|
|
1411
|
+
pointerState2.hovered.set(id, data);
|
|
1291
1412
|
handlers.onDragOverEnter?.(data);
|
|
1292
1413
|
} else if (hoveredItem.stopped) {
|
|
1293
1414
|
data.stopPropagation();
|
|
@@ -1298,18 +1419,18 @@ function createEvents(store) {
|
|
|
1298
1419
|
} else {
|
|
1299
1420
|
const handler = handlers[name];
|
|
1300
1421
|
if (handler) {
|
|
1301
|
-
if (!isClickEvent ||
|
|
1422
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1302
1423
|
pointerMissed(
|
|
1303
1424
|
event,
|
|
1304
|
-
internal.interaction.filter((object) => !
|
|
1425
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1305
1426
|
);
|
|
1306
1427
|
handler(data);
|
|
1307
1428
|
}
|
|
1308
1429
|
} else {
|
|
1309
|
-
if (isClickEvent &&
|
|
1430
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1310
1431
|
pointerMissed(
|
|
1311
1432
|
event,
|
|
1312
|
-
internal.interaction.filter((object) => !
|
|
1433
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1313
1434
|
);
|
|
1314
1435
|
}
|
|
1315
1436
|
}
|
|
@@ -1318,7 +1439,15 @@ function createEvents(store) {
|
|
|
1318
1439
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1319
1440
|
};
|
|
1320
1441
|
}
|
|
1321
|
-
|
|
1442
|
+
function flushDeferredPointers() {
|
|
1443
|
+
const { internal, events } = store.getState();
|
|
1444
|
+
if (!events.frameTimedRaycasts) return;
|
|
1445
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1446
|
+
processDeferredPointer(event, pointerId);
|
|
1447
|
+
}
|
|
1448
|
+
internal.pointerDirty.clear();
|
|
1449
|
+
}
|
|
1450
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1322
1451
|
}
|
|
1323
1452
|
const DOM_EVENTS = {
|
|
1324
1453
|
onClick: ["click", false],
|
|
@@ -1337,10 +1466,15 @@ const DOM_EVENTS = {
|
|
|
1337
1466
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1338
1467
|
};
|
|
1339
1468
|
function createPointerEvents(store) {
|
|
1340
|
-
const { handlePointer } = createEvents(store);
|
|
1469
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1470
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1471
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1341
1472
|
return {
|
|
1342
1473
|
priority: 1,
|
|
1343
1474
|
enabled: true,
|
|
1475
|
+
frameTimedRaycasts: true,
|
|
1476
|
+
alwaysFireOnScroll: true,
|
|
1477
|
+
updateOnFrame: false,
|
|
1344
1478
|
compute(event, state) {
|
|
1345
1479
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1346
1480
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1350,9 +1484,30 @@ function createPointerEvents(store) {
|
|
|
1350
1484
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1351
1485
|
{}
|
|
1352
1486
|
),
|
|
1353
|
-
update: () => {
|
|
1487
|
+
update: (pointerId) => {
|
|
1354
1488
|
const { events, internal } = store.getState();
|
|
1355
|
-
if (
|
|
1489
|
+
if (!events.handlers) return;
|
|
1490
|
+
if (pointerId !== void 0) {
|
|
1491
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1492
|
+
if (event) {
|
|
1493
|
+
internal.pointerDirty.delete(pointerId);
|
|
1494
|
+
processDeferredPointer(event, pointerId);
|
|
1495
|
+
} else if (internal.lastEvent?.current) {
|
|
1496
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1497
|
+
}
|
|
1498
|
+
} else {
|
|
1499
|
+
flushDeferredPointers();
|
|
1500
|
+
if (internal.lastEvent?.current) {
|
|
1501
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
},
|
|
1505
|
+
flush: () => {
|
|
1506
|
+
const { events, internal } = store.getState();
|
|
1507
|
+
flushDeferredPointers();
|
|
1508
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1509
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1510
|
+
}
|
|
1356
1511
|
},
|
|
1357
1512
|
connect: (target) => {
|
|
1358
1513
|
const { set, events } = store.getState();
|
|
@@ -1378,6 +1533,32 @@ function createPointerEvents(store) {
|
|
|
1378
1533
|
}
|
|
1379
1534
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1380
1535
|
}
|
|
1536
|
+
},
|
|
1537
|
+
registerPointer: (config) => {
|
|
1538
|
+
const pointerId = nextXRPointerId++;
|
|
1539
|
+
xrPointers.set(pointerId, config);
|
|
1540
|
+
const { internal } = store.getState();
|
|
1541
|
+
getPointerState(internal, pointerId);
|
|
1542
|
+
return pointerId;
|
|
1543
|
+
},
|
|
1544
|
+
unregisterPointer: (pointerId) => {
|
|
1545
|
+
xrPointers.delete(pointerId);
|
|
1546
|
+
const { internal } = store.getState();
|
|
1547
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1548
|
+
if (pointerState) {
|
|
1549
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1550
|
+
const eventObject = hoveredObj.eventObject;
|
|
1551
|
+
const instance = eventObject.__r3f;
|
|
1552
|
+
if (instance?.eventCount) {
|
|
1553
|
+
const handlers = instance.handlers;
|
|
1554
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1555
|
+
handlers.onPointerOut?.(data);
|
|
1556
|
+
handlers.onPointerLeave?.(data);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
internal.pointerMap.delete(pointerId);
|
|
1560
|
+
}
|
|
1561
|
+
internal.pointerDirty.delete(pointerId);
|
|
1381
1562
|
}
|
|
1382
1563
|
};
|
|
1383
1564
|
}
|
|
@@ -2508,7 +2689,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2508
2689
|
frustum: new Frustum(),
|
|
2509
2690
|
autoUpdateFrustum: true,
|
|
2510
2691
|
raycaster: null,
|
|
2511
|
-
events: {
|
|
2692
|
+
events: {
|
|
2693
|
+
priority: 1,
|
|
2694
|
+
enabled: true,
|
|
2695
|
+
connected: false,
|
|
2696
|
+
frameTimedRaycasts: true,
|
|
2697
|
+
alwaysFireOnScroll: true,
|
|
2698
|
+
updateOnFrame: false
|
|
2699
|
+
},
|
|
2512
2700
|
scene: null,
|
|
2513
2701
|
rootScene: null,
|
|
2514
2702
|
xr: null,
|
|
@@ -2599,11 +2787,13 @@ const createStore = (invalidate, advance) => {
|
|
|
2599
2787
|
},
|
|
2600
2788
|
setError: (error) => set(() => ({ error })),
|
|
2601
2789
|
error: null,
|
|
2602
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2790
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2603
2791
|
uniforms: {},
|
|
2604
2792
|
nodes: {},
|
|
2793
|
+
buffers: {},
|
|
2794
|
+
gpuStorage: {},
|
|
2605
2795
|
textures: /* @__PURE__ */ new Map(),
|
|
2606
|
-
|
|
2796
|
+
renderPipeline: null,
|
|
2607
2797
|
passes: {},
|
|
2608
2798
|
_hmrVersion: 0,
|
|
2609
2799
|
_sizeImperative: false,
|
|
@@ -2612,12 +2802,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2612
2802
|
internal: {
|
|
2613
2803
|
// Events
|
|
2614
2804
|
interaction: [],
|
|
2615
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2616
2805
|
subscribers: [],
|
|
2806
|
+
// Per-pointer state (new unified structure)
|
|
2807
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2808
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2809
|
+
lastEvent: React.createRef(),
|
|
2810
|
+
// Deprecated but kept for backwards compatibility
|
|
2811
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2617
2812
|
initialClick: [0, 0],
|
|
2618
2813
|
initialHits: [],
|
|
2619
2814
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2620
|
-
lastEvent: React.createRef(),
|
|
2621
2815
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2622
2816
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2623
2817
|
// Occlusion system (WebGPU only)
|
|
@@ -15227,6 +15421,18 @@ function createRoot(canvas) {
|
|
|
15227
15421
|
system: true
|
|
15228
15422
|
}
|
|
15229
15423
|
);
|
|
15424
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15425
|
+
() => {
|
|
15426
|
+
const state2 = store.getState();
|
|
15427
|
+
state2.events.flush?.();
|
|
15428
|
+
},
|
|
15429
|
+
{
|
|
15430
|
+
id: `${newRootId}_events`,
|
|
15431
|
+
rootId: newRootId,
|
|
15432
|
+
phase: "input",
|
|
15433
|
+
system: true
|
|
15434
|
+
}
|
|
15435
|
+
);
|
|
15230
15436
|
const unregisterFrustum = scheduler.register(
|
|
15231
15437
|
() => {
|
|
15232
15438
|
const state2 = store.getState();
|
|
@@ -15261,7 +15467,7 @@ function createRoot(canvas) {
|
|
|
15261
15467
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15262
15468
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15263
15469
|
try {
|
|
15264
|
-
if (state2.
|
|
15470
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15265
15471
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15266
15472
|
} catch (error) {
|
|
15267
15473
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15286,6 +15492,7 @@ function createRoot(canvas) {
|
|
|
15286
15492
|
unregisterRoot: () => {
|
|
15287
15493
|
unregisterRoot();
|
|
15288
15494
|
unregisterCanvasTarget();
|
|
15495
|
+
unregisterEventsFlush();
|
|
15289
15496
|
unregisterFrustum();
|
|
15290
15497
|
unregisterVisibility();
|
|
15291
15498
|
unregisterRender();
|
|
@@ -15451,9 +15658,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15451
15658
|
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15452
15659
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15453
15660
|
onMutate(previousRoot.getState());
|
|
15454
|
-
previousRoot.subscribe(onMutate);
|
|
15455
15661
|
return store;
|
|
15456
15662
|
}, [previousRoot, container]);
|
|
15663
|
+
useIsomorphicLayoutEffect(() => {
|
|
15664
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15665
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15666
|
+
return unsubscribe;
|
|
15667
|
+
}, [previousRoot, usePortalStore]);
|
|
15457
15668
|
return (
|
|
15458
15669
|
// @ts-ignore, reconciler types are not maintained
|
|
15459
15670
|
/* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
|
|
@@ -15674,6 +15885,7 @@ function CanvasImpl({
|
|
|
15674
15885
|
queueMicrotask(() => {
|
|
15675
15886
|
const rootEntry = _roots.get(canvas);
|
|
15676
15887
|
if (rootEntry?.store) {
|
|
15888
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15677
15889
|
rootEntry.store.setState((state) => ({
|
|
15678
15890
|
nodes: {},
|
|
15679
15891
|
uniforms: {},
|
|
@@ -15685,8 +15897,7 @@ function CanvasImpl({
|
|
|
15685
15897
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15686
15898
|
const hot = import.meta.hot;
|
|
15687
15899
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15688
|
-
return () => hot.
|
|
15689
|
-
});
|
|
15900
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15690
15901
|
}
|
|
15691
15902
|
if (typeof module !== "undefined" && module.hot) {
|
|
15692
15903
|
const hot = module.hot;
|