@playruo/embed 1.2.9 → 1.2.10
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 +97 -17
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +97 -17
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -75,6 +75,7 @@ var PlayruoEmbed = ({
|
|
|
75
75
|
const internalIframeRef = (0, import_react.useRef)(null);
|
|
76
76
|
const iframeRef = externalIframeRef || internalIframeRef;
|
|
77
77
|
const wasEmbedFullscreenRef = (0, import_react.useRef)(false);
|
|
78
|
+
const wasEmbedPointerLockedRef = (0, import_react.useRef)(false);
|
|
78
79
|
const [isIframeLoaded, setIsIframeLoaded] = (0, import_react.useState)(false);
|
|
79
80
|
const [hasPlayedOnce, setHasPlayedOnce] = (0, import_react.useState)(false);
|
|
80
81
|
const [showGameIframe, setShowGameIframe] = (0, import_react.useState)(false);
|
|
@@ -144,30 +145,79 @@ var PlayruoEmbed = ({
|
|
|
144
145
|
console.warn("[PlayruoEmbed] Failed to release Escape key lock:", error);
|
|
145
146
|
}
|
|
146
147
|
}, [getKeyboardApi]);
|
|
147
|
-
const
|
|
148
|
+
const lockEscapeKey = (0, import_react.useCallback)(async () => {
|
|
149
|
+
const keyboard = getKeyboardApi();
|
|
150
|
+
if (!keyboard?.lock) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
await keyboard.lock(["Escape"]);
|
|
155
|
+
console.log("[PlayruoEmbed] Escape key locked during fullscreen");
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.warn("[PlayruoEmbed] Failed to lock Escape key:", error);
|
|
158
|
+
}
|
|
159
|
+
}, [getKeyboardApi]);
|
|
160
|
+
const getPointerLockElement = (0, import_react.useCallback)(() => {
|
|
161
|
+
const doc = document;
|
|
162
|
+
return doc.pointerLockElement || doc.mozPointerLockElement || doc.webkitPointerLockElement || null;
|
|
163
|
+
}, []);
|
|
164
|
+
const releasePointerLock = (0, import_react.useCallback)(() => {
|
|
165
|
+
const doc = document;
|
|
166
|
+
const exitPointerLock = doc.exitPointerLock?.bind(doc) || doc.mozExitPointerLock?.bind(doc) || doc.webkitExitPointerLock?.bind(doc);
|
|
167
|
+
try {
|
|
168
|
+
exitPointerLock?.();
|
|
169
|
+
wasEmbedPointerLockedRef.current = false;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.warn("[PlayruoEmbed] Failed to release pointer lock:", error);
|
|
172
|
+
}
|
|
173
|
+
}, []);
|
|
174
|
+
const requestImmersiveMode = (0, import_react.useCallback)(
|
|
148
175
|
async (iframe) => {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
176
|
+
const pointerTarget = iframe;
|
|
177
|
+
if (pointerTarget.requestPointerLock) {
|
|
178
|
+
try {
|
|
179
|
+
const pointerLockResult = pointerTarget.requestPointerLock({ unadjustedMovement: true });
|
|
180
|
+
if (pointerLockResult && typeof pointerLockResult.then === "function") {
|
|
181
|
+
void pointerLockResult.then(() => {
|
|
182
|
+
wasEmbedPointerLockedRef.current = true;
|
|
183
|
+
console.log("[PlayruoEmbed] Pointer locked on iframe");
|
|
184
|
+
}).catch(async (error) => {
|
|
185
|
+
if (error instanceof DOMException && error.name === "NotSupportedError") {
|
|
186
|
+
try {
|
|
187
|
+
const fallbackResult = pointerTarget.requestPointerLock?.();
|
|
188
|
+
if (fallbackResult && typeof fallbackResult.then === "function") {
|
|
189
|
+
await fallbackResult;
|
|
190
|
+
}
|
|
191
|
+
wasEmbedPointerLockedRef.current = true;
|
|
192
|
+
console.log("[PlayruoEmbed] Pointer locked on iframe without raw input");
|
|
193
|
+
return;
|
|
194
|
+
} catch (fallbackError) {
|
|
195
|
+
console.warn("[PlayruoEmbed] Failed to lock pointer without raw input:", fallbackError);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
console.warn("[PlayruoEmbed] Failed to lock pointer:", error);
|
|
200
|
+
});
|
|
201
|
+
} else {
|
|
202
|
+
wasEmbedPointerLockedRef.current = true;
|
|
203
|
+
console.log("[PlayruoEmbed] Pointer lock requested on iframe");
|
|
158
204
|
}
|
|
159
|
-
})
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.warn("[PlayruoEmbed] Failed to request pointer lock:", error);
|
|
207
|
+
}
|
|
160
208
|
}
|
|
209
|
+
const fullscreenPromise = iframe.requestFullscreen();
|
|
161
210
|
try {
|
|
162
211
|
await fullscreenPromise;
|
|
163
212
|
wasEmbedFullscreenRef.current = true;
|
|
164
213
|
console.log("[PlayruoEmbed] Fullscreen granted");
|
|
165
214
|
} catch (error) {
|
|
166
215
|
releaseEscapeKeyLock();
|
|
216
|
+
releasePointerLock();
|
|
167
217
|
throw error;
|
|
168
218
|
}
|
|
169
219
|
},
|
|
170
|
-
[
|
|
220
|
+
[releaseEscapeKeyLock, releasePointerLock]
|
|
171
221
|
);
|
|
172
222
|
const handleTryNow = (0, import_react.useCallback)(async () => {
|
|
173
223
|
if (!isCompatible) {
|
|
@@ -182,7 +232,7 @@ var PlayruoEmbed = ({
|
|
|
182
232
|
setShowGameIframe(true);
|
|
183
233
|
try {
|
|
184
234
|
try {
|
|
185
|
-
await
|
|
235
|
+
await requestImmersiveMode(iframe);
|
|
186
236
|
} catch (fsError) {
|
|
187
237
|
console.warn("[PlayruoEmbed] Fullscreen denied, continuing without:", fsError);
|
|
188
238
|
}
|
|
@@ -190,6 +240,8 @@ var PlayruoEmbed = ({
|
|
|
190
240
|
type: "playruo",
|
|
191
241
|
action: "tryNowClick",
|
|
192
242
|
fromEmbed: true,
|
|
243
|
+
isFullscreen: true,
|
|
244
|
+
parentWillHandleFullscreen: true,
|
|
193
245
|
isReplay: hasPlayedOnce
|
|
194
246
|
}, "*");
|
|
195
247
|
console.log("[PlayruoEmbed] Sent tryNowClick to game", hasPlayedOnce ? "(replay)" : "(first time)");
|
|
@@ -203,7 +255,7 @@ var PlayruoEmbed = ({
|
|
|
203
255
|
setErrorMessage("Failed to start game");
|
|
204
256
|
onError?.("Failed to start game");
|
|
205
257
|
}
|
|
206
|
-
}, [isCompatible, hasPlayedOnce, onError, iframeRef,
|
|
258
|
+
}, [isCompatible, hasPlayedOnce, onError, iframeRef, requestImmersiveMode]);
|
|
207
259
|
const handleBuyNow = (0, import_react.useCallback)(() => {
|
|
208
260
|
if (!storeUrl) {
|
|
209
261
|
console.warn("[PlayruoEmbed] No store URL provided");
|
|
@@ -337,6 +389,7 @@ var PlayruoEmbed = ({
|
|
|
337
389
|
const isEmbedFullscreen = Boolean(iframe && fullscreenElement === iframe);
|
|
338
390
|
if (isEmbedFullscreen) {
|
|
339
391
|
wasEmbedFullscreenRef.current = true;
|
|
392
|
+
void lockEscapeKey();
|
|
340
393
|
if (iframe) {
|
|
341
394
|
setTimeout(() => {
|
|
342
395
|
iframe.focus();
|
|
@@ -351,12 +404,18 @@ var PlayruoEmbed = ({
|
|
|
351
404
|
releaseEscapeKeyLock();
|
|
352
405
|
if (wasEmbedFullscreenRef.current) {
|
|
353
406
|
wasEmbedFullscreenRef.current = false;
|
|
407
|
+
const isEmbedPointerLocked = Boolean(iframe && getPointerLockElement() === iframe);
|
|
408
|
+
if (wasEmbedPointerLockedRef.current || isEmbedPointerLocked) {
|
|
409
|
+
releasePointerLock();
|
|
410
|
+
}
|
|
354
411
|
if (iframe) {
|
|
355
412
|
try {
|
|
356
413
|
iframe.contentWindow?.postMessage({
|
|
357
414
|
type: "playruo",
|
|
358
415
|
action: "exitFullscreen",
|
|
359
|
-
fromEmbed: true
|
|
416
|
+
fromEmbed: true,
|
|
417
|
+
isFullscreen: false,
|
|
418
|
+
parentWillHandleFullscreen: true
|
|
360
419
|
}, "*");
|
|
361
420
|
} catch {
|
|
362
421
|
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
@@ -380,12 +439,33 @@ var PlayruoEmbed = ({
|
|
|
380
439
|
document.removeEventListener("mozfullscreenchange", handleFullscreenChange);
|
|
381
440
|
document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
|
|
382
441
|
};
|
|
383
|
-
}, [storeUrl, onDemoCompleted, iframeRef, releaseEscapeKeyLock]);
|
|
442
|
+
}, [storeUrl, onDemoCompleted, iframeRef, getPointerLockElement, lockEscapeKey, releaseEscapeKeyLock, releasePointerLock]);
|
|
443
|
+
(0, import_react.useEffect)(() => {
|
|
444
|
+
const handlePointerLockChange = () => {
|
|
445
|
+
const iframe = iframeRef.current;
|
|
446
|
+
wasEmbedPointerLockedRef.current = Boolean(iframe && getPointerLockElement() === iframe);
|
|
447
|
+
};
|
|
448
|
+
const handlePointerLockError = () => {
|
|
449
|
+
wasEmbedPointerLockedRef.current = false;
|
|
450
|
+
console.warn("[PlayruoEmbed] Pointer lock request was rejected");
|
|
451
|
+
};
|
|
452
|
+
document.addEventListener("pointerlockchange", handlePointerLockChange);
|
|
453
|
+
document.addEventListener("pointerlockerror", handlePointerLockError);
|
|
454
|
+
return () => {
|
|
455
|
+
document.removeEventListener("pointerlockchange", handlePointerLockChange);
|
|
456
|
+
document.removeEventListener("pointerlockerror", handlePointerLockError);
|
|
457
|
+
};
|
|
458
|
+
}, [getPointerLockElement, iframeRef]);
|
|
384
459
|
(0, import_react.useEffect)(() => {
|
|
385
460
|
return () => {
|
|
386
461
|
releaseEscapeKeyLock();
|
|
462
|
+
const iframe = iframeRef.current;
|
|
463
|
+
const isEmbedPointerLocked = Boolean(iframe && getPointerLockElement() === iframe);
|
|
464
|
+
if (wasEmbedPointerLockedRef.current || isEmbedPointerLocked) {
|
|
465
|
+
releasePointerLock();
|
|
466
|
+
}
|
|
387
467
|
};
|
|
388
|
-
}, [releaseEscapeKeyLock]);
|
|
468
|
+
}, [getPointerLockElement, iframeRef, releaseEscapeKeyLock, releasePointerLock]);
|
|
389
469
|
(0, import_react.useEffect)(() => {
|
|
390
470
|
const logCrossOriginStatus = () => {
|
|
391
471
|
const isIsolated = self.crossOriginIsolated;
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ var PlayruoEmbed = ({
|
|
|
35
35
|
const internalIframeRef = useRef(null);
|
|
36
36
|
const iframeRef = externalIframeRef || internalIframeRef;
|
|
37
37
|
const wasEmbedFullscreenRef = useRef(false);
|
|
38
|
+
const wasEmbedPointerLockedRef = useRef(false);
|
|
38
39
|
const [isIframeLoaded, setIsIframeLoaded] = useState(false);
|
|
39
40
|
const [hasPlayedOnce, setHasPlayedOnce] = useState(false);
|
|
40
41
|
const [showGameIframe, setShowGameIframe] = useState(false);
|
|
@@ -104,30 +105,79 @@ var PlayruoEmbed = ({
|
|
|
104
105
|
console.warn("[PlayruoEmbed] Failed to release Escape key lock:", error);
|
|
105
106
|
}
|
|
106
107
|
}, [getKeyboardApi]);
|
|
107
|
-
const
|
|
108
|
+
const lockEscapeKey = useCallback(async () => {
|
|
109
|
+
const keyboard = getKeyboardApi();
|
|
110
|
+
if (!keyboard?.lock) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
await keyboard.lock(["Escape"]);
|
|
115
|
+
console.log("[PlayruoEmbed] Escape key locked during fullscreen");
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn("[PlayruoEmbed] Failed to lock Escape key:", error);
|
|
118
|
+
}
|
|
119
|
+
}, [getKeyboardApi]);
|
|
120
|
+
const getPointerLockElement = useCallback(() => {
|
|
121
|
+
const doc = document;
|
|
122
|
+
return doc.pointerLockElement || doc.mozPointerLockElement || doc.webkitPointerLockElement || null;
|
|
123
|
+
}, []);
|
|
124
|
+
const releasePointerLock = useCallback(() => {
|
|
125
|
+
const doc = document;
|
|
126
|
+
const exitPointerLock = doc.exitPointerLock?.bind(doc) || doc.mozExitPointerLock?.bind(doc) || doc.webkitExitPointerLock?.bind(doc);
|
|
127
|
+
try {
|
|
128
|
+
exitPointerLock?.();
|
|
129
|
+
wasEmbedPointerLockedRef.current = false;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.warn("[PlayruoEmbed] Failed to release pointer lock:", error);
|
|
132
|
+
}
|
|
133
|
+
}, []);
|
|
134
|
+
const requestImmersiveMode = useCallback(
|
|
108
135
|
async (iframe) => {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
136
|
+
const pointerTarget = iframe;
|
|
137
|
+
if (pointerTarget.requestPointerLock) {
|
|
138
|
+
try {
|
|
139
|
+
const pointerLockResult = pointerTarget.requestPointerLock({ unadjustedMovement: true });
|
|
140
|
+
if (pointerLockResult && typeof pointerLockResult.then === "function") {
|
|
141
|
+
void pointerLockResult.then(() => {
|
|
142
|
+
wasEmbedPointerLockedRef.current = true;
|
|
143
|
+
console.log("[PlayruoEmbed] Pointer locked on iframe");
|
|
144
|
+
}).catch(async (error) => {
|
|
145
|
+
if (error instanceof DOMException && error.name === "NotSupportedError") {
|
|
146
|
+
try {
|
|
147
|
+
const fallbackResult = pointerTarget.requestPointerLock?.();
|
|
148
|
+
if (fallbackResult && typeof fallbackResult.then === "function") {
|
|
149
|
+
await fallbackResult;
|
|
150
|
+
}
|
|
151
|
+
wasEmbedPointerLockedRef.current = true;
|
|
152
|
+
console.log("[PlayruoEmbed] Pointer locked on iframe without raw input");
|
|
153
|
+
return;
|
|
154
|
+
} catch (fallbackError) {
|
|
155
|
+
console.warn("[PlayruoEmbed] Failed to lock pointer without raw input:", fallbackError);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
console.warn("[PlayruoEmbed] Failed to lock pointer:", error);
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
wasEmbedPointerLockedRef.current = true;
|
|
163
|
+
console.log("[PlayruoEmbed] Pointer lock requested on iframe");
|
|
118
164
|
}
|
|
119
|
-
})
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.warn("[PlayruoEmbed] Failed to request pointer lock:", error);
|
|
167
|
+
}
|
|
120
168
|
}
|
|
169
|
+
const fullscreenPromise = iframe.requestFullscreen();
|
|
121
170
|
try {
|
|
122
171
|
await fullscreenPromise;
|
|
123
172
|
wasEmbedFullscreenRef.current = true;
|
|
124
173
|
console.log("[PlayruoEmbed] Fullscreen granted");
|
|
125
174
|
} catch (error) {
|
|
126
175
|
releaseEscapeKeyLock();
|
|
176
|
+
releasePointerLock();
|
|
127
177
|
throw error;
|
|
128
178
|
}
|
|
129
179
|
},
|
|
130
|
-
[
|
|
180
|
+
[releaseEscapeKeyLock, releasePointerLock]
|
|
131
181
|
);
|
|
132
182
|
const handleTryNow = useCallback(async () => {
|
|
133
183
|
if (!isCompatible) {
|
|
@@ -142,7 +192,7 @@ var PlayruoEmbed = ({
|
|
|
142
192
|
setShowGameIframe(true);
|
|
143
193
|
try {
|
|
144
194
|
try {
|
|
145
|
-
await
|
|
195
|
+
await requestImmersiveMode(iframe);
|
|
146
196
|
} catch (fsError) {
|
|
147
197
|
console.warn("[PlayruoEmbed] Fullscreen denied, continuing without:", fsError);
|
|
148
198
|
}
|
|
@@ -150,6 +200,8 @@ var PlayruoEmbed = ({
|
|
|
150
200
|
type: "playruo",
|
|
151
201
|
action: "tryNowClick",
|
|
152
202
|
fromEmbed: true,
|
|
203
|
+
isFullscreen: true,
|
|
204
|
+
parentWillHandleFullscreen: true,
|
|
153
205
|
isReplay: hasPlayedOnce
|
|
154
206
|
}, "*");
|
|
155
207
|
console.log("[PlayruoEmbed] Sent tryNowClick to game", hasPlayedOnce ? "(replay)" : "(first time)");
|
|
@@ -163,7 +215,7 @@ var PlayruoEmbed = ({
|
|
|
163
215
|
setErrorMessage("Failed to start game");
|
|
164
216
|
onError?.("Failed to start game");
|
|
165
217
|
}
|
|
166
|
-
}, [isCompatible, hasPlayedOnce, onError, iframeRef,
|
|
218
|
+
}, [isCompatible, hasPlayedOnce, onError, iframeRef, requestImmersiveMode]);
|
|
167
219
|
const handleBuyNow = useCallback(() => {
|
|
168
220
|
if (!storeUrl) {
|
|
169
221
|
console.warn("[PlayruoEmbed] No store URL provided");
|
|
@@ -297,6 +349,7 @@ var PlayruoEmbed = ({
|
|
|
297
349
|
const isEmbedFullscreen = Boolean(iframe && fullscreenElement === iframe);
|
|
298
350
|
if (isEmbedFullscreen) {
|
|
299
351
|
wasEmbedFullscreenRef.current = true;
|
|
352
|
+
void lockEscapeKey();
|
|
300
353
|
if (iframe) {
|
|
301
354
|
setTimeout(() => {
|
|
302
355
|
iframe.focus();
|
|
@@ -311,12 +364,18 @@ var PlayruoEmbed = ({
|
|
|
311
364
|
releaseEscapeKeyLock();
|
|
312
365
|
if (wasEmbedFullscreenRef.current) {
|
|
313
366
|
wasEmbedFullscreenRef.current = false;
|
|
367
|
+
const isEmbedPointerLocked = Boolean(iframe && getPointerLockElement() === iframe);
|
|
368
|
+
if (wasEmbedPointerLockedRef.current || isEmbedPointerLocked) {
|
|
369
|
+
releasePointerLock();
|
|
370
|
+
}
|
|
314
371
|
if (iframe) {
|
|
315
372
|
try {
|
|
316
373
|
iframe.contentWindow?.postMessage({
|
|
317
374
|
type: "playruo",
|
|
318
375
|
action: "exitFullscreen",
|
|
319
|
-
fromEmbed: true
|
|
376
|
+
fromEmbed: true,
|
|
377
|
+
isFullscreen: false,
|
|
378
|
+
parentWillHandleFullscreen: true
|
|
320
379
|
}, "*");
|
|
321
380
|
} catch {
|
|
322
381
|
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
@@ -340,12 +399,33 @@ var PlayruoEmbed = ({
|
|
|
340
399
|
document.removeEventListener("mozfullscreenchange", handleFullscreenChange);
|
|
341
400
|
document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
|
|
342
401
|
};
|
|
343
|
-
}, [storeUrl, onDemoCompleted, iframeRef, releaseEscapeKeyLock]);
|
|
402
|
+
}, [storeUrl, onDemoCompleted, iframeRef, getPointerLockElement, lockEscapeKey, releaseEscapeKeyLock, releasePointerLock]);
|
|
403
|
+
useEffect(() => {
|
|
404
|
+
const handlePointerLockChange = () => {
|
|
405
|
+
const iframe = iframeRef.current;
|
|
406
|
+
wasEmbedPointerLockedRef.current = Boolean(iframe && getPointerLockElement() === iframe);
|
|
407
|
+
};
|
|
408
|
+
const handlePointerLockError = () => {
|
|
409
|
+
wasEmbedPointerLockedRef.current = false;
|
|
410
|
+
console.warn("[PlayruoEmbed] Pointer lock request was rejected");
|
|
411
|
+
};
|
|
412
|
+
document.addEventListener("pointerlockchange", handlePointerLockChange);
|
|
413
|
+
document.addEventListener("pointerlockerror", handlePointerLockError);
|
|
414
|
+
return () => {
|
|
415
|
+
document.removeEventListener("pointerlockchange", handlePointerLockChange);
|
|
416
|
+
document.removeEventListener("pointerlockerror", handlePointerLockError);
|
|
417
|
+
};
|
|
418
|
+
}, [getPointerLockElement, iframeRef]);
|
|
344
419
|
useEffect(() => {
|
|
345
420
|
return () => {
|
|
346
421
|
releaseEscapeKeyLock();
|
|
422
|
+
const iframe = iframeRef.current;
|
|
423
|
+
const isEmbedPointerLocked = Boolean(iframe && getPointerLockElement() === iframe);
|
|
424
|
+
if (wasEmbedPointerLockedRef.current || isEmbedPointerLocked) {
|
|
425
|
+
releasePointerLock();
|
|
426
|
+
}
|
|
347
427
|
};
|
|
348
|
-
}, [releaseEscapeKeyLock]);
|
|
428
|
+
}, [getPointerLockElement, iframeRef, releaseEscapeKeyLock, releasePointerLock]);
|
|
349
429
|
useEffect(() => {
|
|
350
430
|
const logCrossOriginStatus = () => {
|
|
351
431
|
const isIsolated = self.crossOriginIsolated;
|