@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.mjs
CHANGED
|
@@ -975,6 +975,9 @@ function applyProps(object, props) {
|
|
|
975
975
|
else target.set(value);
|
|
976
976
|
} else {
|
|
977
977
|
root[key] = value;
|
|
978
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
979
|
+
root.needsUpdate = true;
|
|
980
|
+
}
|
|
978
981
|
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
|
|
979
982
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
980
983
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1008,38 +1011,60 @@ function applyProps(object, props) {
|
|
|
1008
1011
|
return object;
|
|
1009
1012
|
}
|
|
1010
1013
|
|
|
1014
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1015
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1016
|
+
function getPointerState(internal, pointerId) {
|
|
1017
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1018
|
+
if (!state) {
|
|
1019
|
+
state = {
|
|
1020
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1021
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1022
|
+
initialClick: [0, 0],
|
|
1023
|
+
initialHits: []
|
|
1024
|
+
};
|
|
1025
|
+
internal.pointerMap.set(pointerId, state);
|
|
1026
|
+
}
|
|
1027
|
+
return state;
|
|
1028
|
+
}
|
|
1029
|
+
function getPointerId(event) {
|
|
1030
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1031
|
+
}
|
|
1011
1032
|
function makeId(event) {
|
|
1012
1033
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1013
1034
|
}
|
|
1014
|
-
function releaseInternalPointerCapture(
|
|
1015
|
-
const
|
|
1035
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1036
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1037
|
+
if (!pointerState) return;
|
|
1038
|
+
const captureData = pointerState.captured.get(obj);
|
|
1016
1039
|
if (captureData) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
capturedMap.delete(pointerId);
|
|
1020
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1021
|
-
}
|
|
1040
|
+
pointerState.captured.delete(obj);
|
|
1041
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1022
1042
|
}
|
|
1023
1043
|
}
|
|
1024
1044
|
function removeInteractivity(store, object) {
|
|
1025
1045
|
const { internal } = store.getState();
|
|
1026
1046
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1047
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1048
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1049
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1050
|
+
if (value.eventObject === object || value.object === object) {
|
|
1051
|
+
pointerState.hovered.delete(key);
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
if (pointerState.captured.has(object)) {
|
|
1055
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1031
1056
|
}
|
|
1032
|
-
}
|
|
1033
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1034
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1035
|
-
});
|
|
1057
|
+
}
|
|
1036
1058
|
unregisterVisibility(store, object);
|
|
1037
1059
|
}
|
|
1038
1060
|
function createEvents(store) {
|
|
1039
|
-
function calculateDistance(event) {
|
|
1061
|
+
function calculateDistance(event, pointerId) {
|
|
1040
1062
|
const { internal } = store.getState();
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1063
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1064
|
+
if (!pointerState) return 0;
|
|
1065
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1066
|
+
const dx = event.offsetX - initialX;
|
|
1067
|
+
const dy = event.offsetY - initialY;
|
|
1043
1068
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1044
1069
|
}
|
|
1045
1070
|
function filterPointerEvents(objects) {
|
|
@@ -1075,6 +1100,15 @@ function createEvents(store) {
|
|
|
1075
1100
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1076
1101
|
}
|
|
1077
1102
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1103
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1104
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1105
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1106
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1107
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1108
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1109
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1078
1112
|
const aState = getRootState(a.object);
|
|
1079
1113
|
const bState = getRootState(b.object);
|
|
1080
1114
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1096,9 +1130,13 @@ function createEvents(store) {
|
|
|
1096
1130
|
eventObject = eventObject.parent;
|
|
1097
1131
|
}
|
|
1098
1132
|
}
|
|
1099
|
-
if ("pointerId" in event
|
|
1100
|
-
|
|
1101
|
-
|
|
1133
|
+
if ("pointerId" in event) {
|
|
1134
|
+
const pointerId = event.pointerId;
|
|
1135
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1136
|
+
if (pointerState?.captured.size) {
|
|
1137
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1138
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1139
|
+
}
|
|
1102
1140
|
}
|
|
1103
1141
|
}
|
|
1104
1142
|
return intersections;
|
|
@@ -1111,27 +1149,25 @@ function createEvents(store) {
|
|
|
1111
1149
|
if (state) {
|
|
1112
1150
|
const { raycaster, pointer, camera, internal } = state;
|
|
1113
1151
|
const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1114
|
-
const hasPointerCapture = (id) =>
|
|
1152
|
+
const hasPointerCapture = (id) => {
|
|
1153
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1154
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1155
|
+
};
|
|
1115
1156
|
const setPointerCapture = (id) => {
|
|
1116
1157
|
const captureData = { intersection: hit, target: event.target };
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
} else {
|
|
1120
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1121
|
-
}
|
|
1158
|
+
const pointerState = getPointerState(internal, id);
|
|
1159
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1122
1160
|
event.target.setPointerCapture(id);
|
|
1123
1161
|
};
|
|
1124
1162
|
const releasePointerCapture = (id) => {
|
|
1125
|
-
|
|
1126
|
-
if (captures) {
|
|
1127
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1128
|
-
}
|
|
1163
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1129
1164
|
};
|
|
1130
1165
|
const extractEventProps = {};
|
|
1131
1166
|
for (const prop in event) {
|
|
1132
1167
|
const property = event[prop];
|
|
1133
1168
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1134
1169
|
}
|
|
1170
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1135
1171
|
const raycastEvent = {
|
|
1136
1172
|
...hit,
|
|
1137
1173
|
...extractEventProps,
|
|
@@ -1142,18 +1178,19 @@ function createEvents(store) {
|
|
|
1142
1178
|
unprojectedPoint,
|
|
1143
1179
|
ray: raycaster.ray,
|
|
1144
1180
|
camera,
|
|
1181
|
+
pointerId: eventPointerId,
|
|
1145
1182
|
// Hijack stopPropagation, which just sets a flag
|
|
1146
1183
|
stopPropagation() {
|
|
1147
|
-
const
|
|
1184
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1148
1185
|
if (
|
|
1149
1186
|
// ...if this pointer hasn't been captured
|
|
1150
|
-
!
|
|
1151
|
-
|
|
1187
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1188
|
+
pointerState.captured.has(hit.eventObject)
|
|
1152
1189
|
) {
|
|
1153
1190
|
raycastEvent.stopped = localState.stopped = true;
|
|
1154
|
-
if (
|
|
1191
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1155
1192
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1156
|
-
cancelPointer([...higher, hit]);
|
|
1193
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1157
1194
|
}
|
|
1158
1195
|
}
|
|
1159
1196
|
},
|
|
@@ -1169,15 +1206,18 @@ function createEvents(store) {
|
|
|
1169
1206
|
}
|
|
1170
1207
|
return intersections;
|
|
1171
1208
|
}
|
|
1172
|
-
function cancelPointer(intersections) {
|
|
1209
|
+
function cancelPointer(intersections, pointerId) {
|
|
1173
1210
|
const { internal } = store.getState();
|
|
1174
|
-
|
|
1211
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1212
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1213
|
+
if (!pointerState) return;
|
|
1214
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1175
1215
|
if (!intersections.length || !intersections.find(
|
|
1176
1216
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1177
1217
|
)) {
|
|
1178
1218
|
const eventObject = hoveredObj.eventObject;
|
|
1179
1219
|
const instance = eventObject.__r3f;
|
|
1180
|
-
|
|
1220
|
+
pointerState.hovered.delete(hoveredId);
|
|
1181
1221
|
if (instance?.eventCount) {
|
|
1182
1222
|
const handlers = instance.handlers;
|
|
1183
1223
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1206,41 +1246,118 @@ function createEvents(store) {
|
|
|
1206
1246
|
instance?.handlers.onDropMissed?.(event);
|
|
1207
1247
|
}
|
|
1208
1248
|
}
|
|
1249
|
+
function cleanupPointer(pointerId) {
|
|
1250
|
+
const { internal } = store.getState();
|
|
1251
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1252
|
+
if (pointerState) {
|
|
1253
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1254
|
+
const eventObject = hoveredObj.eventObject;
|
|
1255
|
+
const instance = eventObject.__r3f;
|
|
1256
|
+
if (instance?.eventCount) {
|
|
1257
|
+
const handlers = instance.handlers;
|
|
1258
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1259
|
+
handlers.onPointerOut?.(data);
|
|
1260
|
+
handlers.onPointerLeave?.(data);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
internal.pointerMap.delete(pointerId);
|
|
1264
|
+
}
|
|
1265
|
+
internal.pointerDirty.delete(pointerId);
|
|
1266
|
+
}
|
|
1267
|
+
function processDeferredPointer(event, pointerId) {
|
|
1268
|
+
const state = store.getState();
|
|
1269
|
+
const { onPointerMissed, onDragOverMissed, internal } = state;
|
|
1270
|
+
if (!state.events.enabled) return;
|
|
1271
|
+
const filter = filterPointerEvents;
|
|
1272
|
+
const hits = intersect(event, filter);
|
|
1273
|
+
cancelPointer(hits, pointerId);
|
|
1274
|
+
function onIntersect(data) {
|
|
1275
|
+
const eventObject = data.eventObject;
|
|
1276
|
+
const instance = eventObject.__r3f;
|
|
1277
|
+
if (!instance?.eventCount) return;
|
|
1278
|
+
const handlers = instance.handlers;
|
|
1279
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1280
|
+
const id = makeId(data);
|
|
1281
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1282
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1283
|
+
if (!hoveredItem) {
|
|
1284
|
+
pointerState.hovered.set(id, data);
|
|
1285
|
+
handlers.onPointerOver?.(data);
|
|
1286
|
+
handlers.onPointerEnter?.(data);
|
|
1287
|
+
} else if (hoveredItem.stopped) {
|
|
1288
|
+
data.stopPropagation();
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
handlers.onPointerMove?.(data);
|
|
1292
|
+
}
|
|
1293
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1294
|
+
}
|
|
1209
1295
|
function handlePointer(name) {
|
|
1210
1296
|
switch (name) {
|
|
1211
1297
|
case "onPointerLeave":
|
|
1212
|
-
case "onPointerCancel":
|
|
1213
1298
|
case "onDragLeave":
|
|
1214
1299
|
return () => cancelPointer([]);
|
|
1300
|
+
// Global cancel of these events
|
|
1301
|
+
case "onPointerCancel":
|
|
1302
|
+
return (event) => {
|
|
1303
|
+
const pointerId = getPointerId(event);
|
|
1304
|
+
cleanupPointer(pointerId);
|
|
1305
|
+
};
|
|
1215
1306
|
case "onLostPointerCapture":
|
|
1216
1307
|
return (event) => {
|
|
1217
1308
|
const { internal } = store.getState();
|
|
1218
|
-
|
|
1309
|
+
const pointerId = getPointerId(event);
|
|
1310
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1311
|
+
if (pointerState?.captured.size) {
|
|
1219
1312
|
requestAnimationFrame(() => {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1313
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1314
|
+
if (pointerState2?.captured.size) {
|
|
1315
|
+
pointerState2.captured.clear();
|
|
1223
1316
|
}
|
|
1317
|
+
cancelPointer([], pointerId);
|
|
1224
1318
|
});
|
|
1225
1319
|
}
|
|
1226
1320
|
};
|
|
1227
1321
|
}
|
|
1228
1322
|
return function handleEvent(event) {
|
|
1229
1323
|
const state = store.getState();
|
|
1230
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1324
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1325
|
+
const pointerId = getPointerId(event);
|
|
1231
1326
|
internal.lastEvent.current = event;
|
|
1232
|
-
if (!
|
|
1327
|
+
if (!events.enabled) return;
|
|
1233
1328
|
const isPointerMove = name === "onPointerMove";
|
|
1234
1329
|
const isDragOver = name === "onDragOver";
|
|
1235
1330
|
const isDrop = name === "onDrop";
|
|
1236
1331
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1332
|
+
const isPointerDown = name === "onPointerDown";
|
|
1333
|
+
const isPointerUp = name === "onPointerUp";
|
|
1334
|
+
const isWheel = name === "onWheel";
|
|
1335
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1336
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1337
|
+
events.compute?.(event, state);
|
|
1338
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1342
|
+
events.compute?.(event, state);
|
|
1343
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1347
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1348
|
+
internal.pointerDirty.delete(pointerId);
|
|
1349
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1350
|
+
}
|
|
1237
1351
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1238
1352
|
const hits = intersect(event, filter);
|
|
1239
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1353
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1354
|
+
if (isPointerDown) {
|
|
1355
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1356
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1357
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1358
|
+
}
|
|
1359
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1360
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1244
1361
|
if (isClickEvent && !hits.length) {
|
|
1245
1362
|
if (delta <= 2) {
|
|
1246
1363
|
pointerMissed(event, internal.interaction);
|
|
@@ -1255,7 +1372,9 @@ function createEvents(store) {
|
|
|
1255
1372
|
dropMissed(event, internal.interaction);
|
|
1256
1373
|
if (onDropMissed) onDropMissed(event);
|
|
1257
1374
|
}
|
|
1258
|
-
if (isPointerMove || isDragOver)
|
|
1375
|
+
if (isPointerMove || isDragOver) {
|
|
1376
|
+
cancelPointer(hits, pointerId);
|
|
1377
|
+
}
|
|
1259
1378
|
function onIntersect(data) {
|
|
1260
1379
|
const eventObject = data.eventObject;
|
|
1261
1380
|
const instance = eventObject.__r3f;
|
|
@@ -1264,9 +1383,10 @@ function createEvents(store) {
|
|
|
1264
1383
|
if (isPointerMove) {
|
|
1265
1384
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1266
1385
|
const id = makeId(data);
|
|
1267
|
-
const
|
|
1386
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1387
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1268
1388
|
if (!hoveredItem) {
|
|
1269
|
-
|
|
1389
|
+
pointerState2.hovered.set(id, data);
|
|
1270
1390
|
handlers.onPointerOver?.(data);
|
|
1271
1391
|
handlers.onPointerEnter?.(data);
|
|
1272
1392
|
} else if (hoveredItem.stopped) {
|
|
@@ -1276,9 +1396,10 @@ function createEvents(store) {
|
|
|
1276
1396
|
handlers.onPointerMove?.(data);
|
|
1277
1397
|
} else if (isDragOver) {
|
|
1278
1398
|
const id = makeId(data);
|
|
1279
|
-
const
|
|
1399
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1400
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1280
1401
|
if (!hoveredItem) {
|
|
1281
|
-
|
|
1402
|
+
pointerState2.hovered.set(id, data);
|
|
1282
1403
|
handlers.onDragOverEnter?.(data);
|
|
1283
1404
|
} else if (hoveredItem.stopped) {
|
|
1284
1405
|
data.stopPropagation();
|
|
@@ -1289,18 +1410,18 @@ function createEvents(store) {
|
|
|
1289
1410
|
} else {
|
|
1290
1411
|
const handler = handlers[name];
|
|
1291
1412
|
if (handler) {
|
|
1292
|
-
if (!isClickEvent ||
|
|
1413
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1293
1414
|
pointerMissed(
|
|
1294
1415
|
event,
|
|
1295
|
-
internal.interaction.filter((object) => !
|
|
1416
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1296
1417
|
);
|
|
1297
1418
|
handler(data);
|
|
1298
1419
|
}
|
|
1299
1420
|
} else {
|
|
1300
|
-
if (isClickEvent &&
|
|
1421
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1301
1422
|
pointerMissed(
|
|
1302
1423
|
event,
|
|
1303
|
-
internal.interaction.filter((object) => !
|
|
1424
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1304
1425
|
);
|
|
1305
1426
|
}
|
|
1306
1427
|
}
|
|
@@ -1309,7 +1430,15 @@ function createEvents(store) {
|
|
|
1309
1430
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1310
1431
|
};
|
|
1311
1432
|
}
|
|
1312
|
-
|
|
1433
|
+
function flushDeferredPointers() {
|
|
1434
|
+
const { internal, events } = store.getState();
|
|
1435
|
+
if (!events.frameTimedRaycasts) return;
|
|
1436
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1437
|
+
processDeferredPointer(event, pointerId);
|
|
1438
|
+
}
|
|
1439
|
+
internal.pointerDirty.clear();
|
|
1440
|
+
}
|
|
1441
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1313
1442
|
}
|
|
1314
1443
|
const DOM_EVENTS = {
|
|
1315
1444
|
onClick: ["click", false],
|
|
@@ -1328,10 +1457,15 @@ const DOM_EVENTS = {
|
|
|
1328
1457
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1329
1458
|
};
|
|
1330
1459
|
function createPointerEvents(store) {
|
|
1331
|
-
const { handlePointer } = createEvents(store);
|
|
1460
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1461
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1462
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1332
1463
|
return {
|
|
1333
1464
|
priority: 1,
|
|
1334
1465
|
enabled: true,
|
|
1466
|
+
frameTimedRaycasts: true,
|
|
1467
|
+
alwaysFireOnScroll: true,
|
|
1468
|
+
updateOnFrame: false,
|
|
1335
1469
|
compute(event, state) {
|
|
1336
1470
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1337
1471
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1341,9 +1475,30 @@ function createPointerEvents(store) {
|
|
|
1341
1475
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1342
1476
|
{}
|
|
1343
1477
|
),
|
|
1344
|
-
update: () => {
|
|
1478
|
+
update: (pointerId) => {
|
|
1479
|
+
const { events, internal } = store.getState();
|
|
1480
|
+
if (!events.handlers) return;
|
|
1481
|
+
if (pointerId !== void 0) {
|
|
1482
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1483
|
+
if (event) {
|
|
1484
|
+
internal.pointerDirty.delete(pointerId);
|
|
1485
|
+
processDeferredPointer(event, pointerId);
|
|
1486
|
+
} else if (internal.lastEvent?.current) {
|
|
1487
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1488
|
+
}
|
|
1489
|
+
} else {
|
|
1490
|
+
flushDeferredPointers();
|
|
1491
|
+
if (internal.lastEvent?.current) {
|
|
1492
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
flush: () => {
|
|
1345
1497
|
const { events, internal } = store.getState();
|
|
1346
|
-
|
|
1498
|
+
flushDeferredPointers();
|
|
1499
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1500
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1501
|
+
}
|
|
1347
1502
|
},
|
|
1348
1503
|
connect: (target) => {
|
|
1349
1504
|
const { set, events } = store.getState();
|
|
@@ -1369,6 +1524,32 @@ function createPointerEvents(store) {
|
|
|
1369
1524
|
}
|
|
1370
1525
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1371
1526
|
}
|
|
1527
|
+
},
|
|
1528
|
+
registerPointer: (config) => {
|
|
1529
|
+
const pointerId = nextXRPointerId++;
|
|
1530
|
+
xrPointers.set(pointerId, config);
|
|
1531
|
+
const { internal } = store.getState();
|
|
1532
|
+
getPointerState(internal, pointerId);
|
|
1533
|
+
return pointerId;
|
|
1534
|
+
},
|
|
1535
|
+
unregisterPointer: (pointerId) => {
|
|
1536
|
+
xrPointers.delete(pointerId);
|
|
1537
|
+
const { internal } = store.getState();
|
|
1538
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1539
|
+
if (pointerState) {
|
|
1540
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1541
|
+
const eventObject = hoveredObj.eventObject;
|
|
1542
|
+
const instance = eventObject.__r3f;
|
|
1543
|
+
if (instance?.eventCount) {
|
|
1544
|
+
const handlers = instance.handlers;
|
|
1545
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1546
|
+
handlers.onPointerOut?.(data);
|
|
1547
|
+
handlers.onPointerLeave?.(data);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
internal.pointerMap.delete(pointerId);
|
|
1551
|
+
}
|
|
1552
|
+
internal.pointerDirty.delete(pointerId);
|
|
1372
1553
|
}
|
|
1373
1554
|
};
|
|
1374
1555
|
}
|
|
@@ -2499,7 +2680,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2499
2680
|
frustum: new Frustum(),
|
|
2500
2681
|
autoUpdateFrustum: true,
|
|
2501
2682
|
raycaster: null,
|
|
2502
|
-
events: {
|
|
2683
|
+
events: {
|
|
2684
|
+
priority: 1,
|
|
2685
|
+
enabled: true,
|
|
2686
|
+
connected: false,
|
|
2687
|
+
frameTimedRaycasts: true,
|
|
2688
|
+
alwaysFireOnScroll: true,
|
|
2689
|
+
updateOnFrame: false
|
|
2690
|
+
},
|
|
2503
2691
|
scene: null,
|
|
2504
2692
|
rootScene: null,
|
|
2505
2693
|
xr: null,
|
|
@@ -2590,11 +2778,13 @@ const createStore = (invalidate, advance) => {
|
|
|
2590
2778
|
},
|
|
2591
2779
|
setError: (error) => set(() => ({ error })),
|
|
2592
2780
|
error: null,
|
|
2593
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2781
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2594
2782
|
uniforms: {},
|
|
2595
2783
|
nodes: {},
|
|
2784
|
+
buffers: {},
|
|
2785
|
+
gpuStorage: {},
|
|
2596
2786
|
textures: /* @__PURE__ */ new Map(),
|
|
2597
|
-
|
|
2787
|
+
renderPipeline: null,
|
|
2598
2788
|
passes: {},
|
|
2599
2789
|
_hmrVersion: 0,
|
|
2600
2790
|
_sizeImperative: false,
|
|
@@ -2603,12 +2793,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2603
2793
|
internal: {
|
|
2604
2794
|
// Events
|
|
2605
2795
|
interaction: [],
|
|
2606
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2607
2796
|
subscribers: [],
|
|
2797
|
+
// Per-pointer state (new unified structure)
|
|
2798
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2799
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2800
|
+
lastEvent: React.createRef(),
|
|
2801
|
+
// Deprecated but kept for backwards compatibility
|
|
2802
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2608
2803
|
initialClick: [0, 0],
|
|
2609
2804
|
initialHits: [],
|
|
2610
2805
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2611
|
-
lastEvent: React.createRef(),
|
|
2612
2806
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2613
2807
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2614
2808
|
// Occlusion system (WebGPU only)
|
|
@@ -15060,6 +15254,12 @@ function createRoot(canvas) {
|
|
|
15060
15254
|
} else if (!wantsGL && !state.internal.actualRenderer) {
|
|
15061
15255
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
|
|
15062
15256
|
if (!renderer.hasInitialized?.()) {
|
|
15257
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15258
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15259
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15260
|
+
canvas.width = size2.width * pixelRatio;
|
|
15261
|
+
canvas.height = size2.height * pixelRatio;
|
|
15262
|
+
}
|
|
15063
15263
|
await renderer.init();
|
|
15064
15264
|
}
|
|
15065
15265
|
const backend = renderer.backend;
|
|
@@ -15261,6 +15461,18 @@ function createRoot(canvas) {
|
|
|
15261
15461
|
system: true
|
|
15262
15462
|
}
|
|
15263
15463
|
);
|
|
15464
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15465
|
+
() => {
|
|
15466
|
+
const state2 = store.getState();
|
|
15467
|
+
state2.events.flush?.();
|
|
15468
|
+
},
|
|
15469
|
+
{
|
|
15470
|
+
id: `${newRootId}_events`,
|
|
15471
|
+
rootId: newRootId,
|
|
15472
|
+
phase: "input",
|
|
15473
|
+
system: true
|
|
15474
|
+
}
|
|
15475
|
+
);
|
|
15264
15476
|
const unregisterFrustum = scheduler.register(
|
|
15265
15477
|
() => {
|
|
15266
15478
|
const state2 = store.getState();
|
|
@@ -15295,7 +15507,7 @@ function createRoot(canvas) {
|
|
|
15295
15507
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15296
15508
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15297
15509
|
try {
|
|
15298
|
-
if (state2.
|
|
15510
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15299
15511
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15300
15512
|
} catch (error) {
|
|
15301
15513
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15320,6 +15532,7 @@ function createRoot(canvas) {
|
|
|
15320
15532
|
unregisterRoot: () => {
|
|
15321
15533
|
unregisterRoot();
|
|
15322
15534
|
unregisterCanvasTarget();
|
|
15535
|
+
unregisterEventsFlush();
|
|
15323
15536
|
unregisterFrustum();
|
|
15324
15537
|
unregisterVisibility();
|
|
15325
15538
|
unregisterRender();
|
|
@@ -15485,9 +15698,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15485
15698
|
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15486
15699
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15487
15700
|
onMutate(previousRoot.getState());
|
|
15488
|
-
previousRoot.subscribe(onMutate);
|
|
15489
15701
|
return store;
|
|
15490
15702
|
}, [previousRoot, container]);
|
|
15703
|
+
useIsomorphicLayoutEffect(() => {
|
|
15704
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15705
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15706
|
+
return unsubscribe;
|
|
15707
|
+
}, [previousRoot, usePortalStore]);
|
|
15491
15708
|
return (
|
|
15492
15709
|
// @ts-ignore, reconciler types are not maintained
|
|
15493
15710
|
/* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
|
|
@@ -15708,6 +15925,7 @@ function CanvasImpl({
|
|
|
15708
15925
|
queueMicrotask(() => {
|
|
15709
15926
|
const rootEntry = _roots.get(canvas);
|
|
15710
15927
|
if (rootEntry?.store) {
|
|
15928
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15711
15929
|
rootEntry.store.setState((state) => ({
|
|
15712
15930
|
nodes: {},
|
|
15713
15931
|
uniforms: {},
|
|
@@ -15719,8 +15937,7 @@ function CanvasImpl({
|
|
|
15719
15937
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15720
15938
|
const hot = import.meta.hot;
|
|
15721
15939
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15722
|
-
return () => hot.
|
|
15723
|
-
});
|
|
15940
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15724
15941
|
}
|
|
15725
15942
|
if (typeof module !== "undefined" && module.hot) {
|
|
15726
15943
|
const hot = module.hot;
|