@playruo/embed 1.1.3 → 1.1.5
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 +68 -3
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +68 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -51,20 +51,84 @@ var PlayruoEmbed = ({
|
|
|
51
51
|
onDemoCompleted,
|
|
52
52
|
onPurchaseRequest,
|
|
53
53
|
onError,
|
|
54
|
-
renderState
|
|
54
|
+
renderState,
|
|
55
|
+
iframeRef: externalIframeRef
|
|
55
56
|
}) => {
|
|
56
|
-
const
|
|
57
|
+
const internalIframeRef = (0, import_react.useRef)(null);
|
|
58
|
+
const iframeRef = externalIframeRef || internalIframeRef;
|
|
57
59
|
const [isReady, setIsReady] = (0, import_react.useState)(false);
|
|
58
60
|
const [state, setState] = (0, import_react.useState)(null);
|
|
59
61
|
const [errorMessage, setErrorMessage] = (0, import_react.useState)(null);
|
|
60
62
|
const src = (0, import_react.useMemo)(() => buildEmbedUrl({ baseUrl, operation, storeUrl }), [baseUrl, operation, storeUrl]);
|
|
63
|
+
const checkKeyboardLockPermission = async () => {
|
|
64
|
+
if (!navigator.permissions) {
|
|
65
|
+
console.log("[PlayruoEmbed] Permissions API not supported");
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const { state: state2 } = await navigator.permissions.query({
|
|
70
|
+
name: "keyboard-lock"
|
|
71
|
+
});
|
|
72
|
+
if (state2 === "granted" || state2 === "prompt") {
|
|
73
|
+
console.log(`[PlayruoEmbed] Keyboard lock permission: ${state2}`);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
console.log("[PlayruoEmbed] Keyboard lock permission denied");
|
|
77
|
+
return false;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.warn("[PlayruoEmbed] Error checking keyboard lock permission:", error);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const requestFullscreenWithKeyboardLock = async () => {
|
|
84
|
+
const iframe = iframeRef.current;
|
|
85
|
+
if (!iframe?.requestFullscreen) {
|
|
86
|
+
console.log("[PlayruoEmbed] Fullscreen not supported on this browser");
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const fullscreenPromise = iframe.requestFullscreen();
|
|
91
|
+
if (navigator.keyboard) {
|
|
92
|
+
const permissionPromise = checkKeyboardLockPermission();
|
|
93
|
+
const keyboardLockPromise = navigator.keyboard.lock(["Escape"]);
|
|
94
|
+
void Promise.all([permissionPromise, keyboardLockPromise]).then(([hasPermission]) => {
|
|
95
|
+
if (hasPermission) {
|
|
96
|
+
console.log("[PlayruoEmbed] Keyboard locked successfully");
|
|
97
|
+
}
|
|
98
|
+
}).catch((err) => {
|
|
99
|
+
console.warn("[PlayruoEmbed] Keyboard lock failed:", err);
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
console.log("[PlayruoEmbed] Keyboard API not supported");
|
|
103
|
+
}
|
|
104
|
+
void fullscreenPromise.then(() => {
|
|
105
|
+
console.log("[PlayruoEmbed] Fullscreen activated successfully");
|
|
106
|
+
}).catch((err) => {
|
|
107
|
+
console.warn("[PlayruoEmbed] Fullscreen failed:", err);
|
|
108
|
+
});
|
|
109
|
+
return true;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error("[PlayruoEmbed] Error requesting fullscreen:", error);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
61
115
|
const sendCommand = (type) => {
|
|
62
116
|
if (!iframeRef.current?.contentWindow) {
|
|
63
117
|
console.warn(`PlayruoEmbed: Cannot send ${type} command, iframe not ready`);
|
|
64
118
|
return;
|
|
65
119
|
}
|
|
120
|
+
if (type === "try_now") {
|
|
121
|
+
requestFullscreenWithKeyboardLock();
|
|
122
|
+
}
|
|
66
123
|
iframeRef.current.contentWindow.postMessage({ type }, "*");
|
|
67
124
|
};
|
|
125
|
+
(0, import_react.useEffect)(() => {
|
|
126
|
+
if (!self.crossOriginIsolated) {
|
|
127
|
+
console.warn(
|
|
128
|
+
'[PlayruoEmbed] \u26A0\uFE0F Not in a cross-origin isolated context.\nSharedArrayBuffer and high-precision timers may not work.\n\nAdd these headers to your server:\n Cross-Origin-Opener-Policy: same-origin\n Cross-Origin-Embedder-Policy: credentialless\n\nAlternative (stricter, if not using credentialless iframes):\n Cross-Origin-Embedder-Policy: require-corp\n\nFor Next.js, add to next.config.js:\n async headers() {\n return [{\n source: "/:path*",\n headers: [\n { key: "Cross-Origin-Opener-Policy", value: "same-origin" },\n { key: "Cross-Origin-Embedder-Policy", value: "credentialless" }\n ]\n }];\n }'
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}, []);
|
|
68
132
|
(0, import_react.useEffect)(() => {
|
|
69
133
|
const handler = (event) => {
|
|
70
134
|
const msg = event?.data ?? {};
|
|
@@ -117,8 +181,9 @@ var PlayruoEmbed = ({
|
|
|
117
181
|
{
|
|
118
182
|
ref: iframeRef,
|
|
119
183
|
src,
|
|
120
|
-
allow: "fullscreen *; autoplay *; gamepad *",
|
|
184
|
+
allow: "fullscreen *; autoplay *; gamepad *; clipboard-write *; web-share *; encrypted-media *; accelerometer *; gyroscope *",
|
|
121
185
|
className: "w-full h-[70vh] rounded-lg border",
|
|
186
|
+
...{ credentialless: "true" },
|
|
122
187
|
title: "Playruo",
|
|
123
188
|
style: {
|
|
124
189
|
position: showIframe ? void 0 : "absolute",
|
package/dist/index.d.cts
CHANGED
|
@@ -16,6 +16,15 @@ interface DemoCompletedPayload {
|
|
|
16
16
|
storeUrl?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
interface Keyboard {
|
|
20
|
+
lock: (keys: string[]) => Promise<void>;
|
|
21
|
+
unlock: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare global {
|
|
24
|
+
interface Navigator {
|
|
25
|
+
keyboard?: Keyboard;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
19
28
|
interface PlayruoEmbedActions {
|
|
20
29
|
/** Start the demo session */
|
|
21
30
|
tryNow: () => void;
|
|
@@ -49,6 +58,10 @@ interface PlayruoEmbedProps {
|
|
|
49
58
|
* Provides status, message, and available actions based on current state.
|
|
50
59
|
*/
|
|
51
60
|
renderState?: (render: PlayruoEmbedRenderState) => ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Ref to access the iframe element for fullscreen requests
|
|
63
|
+
*/
|
|
64
|
+
iframeRef?: React.RefObject<HTMLIFrameElement>;
|
|
52
65
|
}
|
|
53
66
|
declare const PlayruoEmbed: FC<PlayruoEmbedProps>;
|
|
54
67
|
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,15 @@ interface DemoCompletedPayload {
|
|
|
16
16
|
storeUrl?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
interface Keyboard {
|
|
20
|
+
lock: (keys: string[]) => Promise<void>;
|
|
21
|
+
unlock: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare global {
|
|
24
|
+
interface Navigator {
|
|
25
|
+
keyboard?: Keyboard;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
19
28
|
interface PlayruoEmbedActions {
|
|
20
29
|
/** Start the demo session */
|
|
21
30
|
tryNow: () => void;
|
|
@@ -49,6 +58,10 @@ interface PlayruoEmbedProps {
|
|
|
49
58
|
* Provides status, message, and available actions based on current state.
|
|
50
59
|
*/
|
|
51
60
|
renderState?: (render: PlayruoEmbedRenderState) => ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Ref to access the iframe element for fullscreen requests
|
|
63
|
+
*/
|
|
64
|
+
iframeRef?: React.RefObject<HTMLIFrameElement>;
|
|
52
65
|
}
|
|
53
66
|
declare const PlayruoEmbed: FC<PlayruoEmbedProps>;
|
|
54
67
|
|
package/dist/index.js
CHANGED
|
@@ -22,20 +22,84 @@ var PlayruoEmbed = ({
|
|
|
22
22
|
onDemoCompleted,
|
|
23
23
|
onPurchaseRequest,
|
|
24
24
|
onError,
|
|
25
|
-
renderState
|
|
25
|
+
renderState,
|
|
26
|
+
iframeRef: externalIframeRef
|
|
26
27
|
}) => {
|
|
27
|
-
const
|
|
28
|
+
const internalIframeRef = useRef(null);
|
|
29
|
+
const iframeRef = externalIframeRef || internalIframeRef;
|
|
28
30
|
const [isReady, setIsReady] = useState(false);
|
|
29
31
|
const [state, setState] = useState(null);
|
|
30
32
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
31
33
|
const src = useMemo(() => buildEmbedUrl({ baseUrl, operation, storeUrl }), [baseUrl, operation, storeUrl]);
|
|
34
|
+
const checkKeyboardLockPermission = async () => {
|
|
35
|
+
if (!navigator.permissions) {
|
|
36
|
+
console.log("[PlayruoEmbed] Permissions API not supported");
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const { state: state2 } = await navigator.permissions.query({
|
|
41
|
+
name: "keyboard-lock"
|
|
42
|
+
});
|
|
43
|
+
if (state2 === "granted" || state2 === "prompt") {
|
|
44
|
+
console.log(`[PlayruoEmbed] Keyboard lock permission: ${state2}`);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
console.log("[PlayruoEmbed] Keyboard lock permission denied");
|
|
48
|
+
return false;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn("[PlayruoEmbed] Error checking keyboard lock permission:", error);
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const requestFullscreenWithKeyboardLock = async () => {
|
|
55
|
+
const iframe = iframeRef.current;
|
|
56
|
+
if (!iframe?.requestFullscreen) {
|
|
57
|
+
console.log("[PlayruoEmbed] Fullscreen not supported on this browser");
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const fullscreenPromise = iframe.requestFullscreen();
|
|
62
|
+
if (navigator.keyboard) {
|
|
63
|
+
const permissionPromise = checkKeyboardLockPermission();
|
|
64
|
+
const keyboardLockPromise = navigator.keyboard.lock(["Escape"]);
|
|
65
|
+
void Promise.all([permissionPromise, keyboardLockPromise]).then(([hasPermission]) => {
|
|
66
|
+
if (hasPermission) {
|
|
67
|
+
console.log("[PlayruoEmbed] Keyboard locked successfully");
|
|
68
|
+
}
|
|
69
|
+
}).catch((err) => {
|
|
70
|
+
console.warn("[PlayruoEmbed] Keyboard lock failed:", err);
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
console.log("[PlayruoEmbed] Keyboard API not supported");
|
|
74
|
+
}
|
|
75
|
+
void fullscreenPromise.then(() => {
|
|
76
|
+
console.log("[PlayruoEmbed] Fullscreen activated successfully");
|
|
77
|
+
}).catch((err) => {
|
|
78
|
+
console.warn("[PlayruoEmbed] Fullscreen failed:", err);
|
|
79
|
+
});
|
|
80
|
+
return true;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error("[PlayruoEmbed] Error requesting fullscreen:", error);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
32
86
|
const sendCommand = (type) => {
|
|
33
87
|
if (!iframeRef.current?.contentWindow) {
|
|
34
88
|
console.warn(`PlayruoEmbed: Cannot send ${type} command, iframe not ready`);
|
|
35
89
|
return;
|
|
36
90
|
}
|
|
91
|
+
if (type === "try_now") {
|
|
92
|
+
requestFullscreenWithKeyboardLock();
|
|
93
|
+
}
|
|
37
94
|
iframeRef.current.contentWindow.postMessage({ type }, "*");
|
|
38
95
|
};
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!self.crossOriginIsolated) {
|
|
98
|
+
console.warn(
|
|
99
|
+
'[PlayruoEmbed] \u26A0\uFE0F Not in a cross-origin isolated context.\nSharedArrayBuffer and high-precision timers may not work.\n\nAdd these headers to your server:\n Cross-Origin-Opener-Policy: same-origin\n Cross-Origin-Embedder-Policy: credentialless\n\nAlternative (stricter, if not using credentialless iframes):\n Cross-Origin-Embedder-Policy: require-corp\n\nFor Next.js, add to next.config.js:\n async headers() {\n return [{\n source: "/:path*",\n headers: [\n { key: "Cross-Origin-Opener-Policy", value: "same-origin" },\n { key: "Cross-Origin-Embedder-Policy", value: "credentialless" }\n ]\n }];\n }'
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}, []);
|
|
39
103
|
useEffect(() => {
|
|
40
104
|
const handler = (event) => {
|
|
41
105
|
const msg = event?.data ?? {};
|
|
@@ -88,8 +152,9 @@ var PlayruoEmbed = ({
|
|
|
88
152
|
{
|
|
89
153
|
ref: iframeRef,
|
|
90
154
|
src,
|
|
91
|
-
allow: "fullscreen *; autoplay *; gamepad *",
|
|
155
|
+
allow: "fullscreen *; autoplay *; gamepad *; clipboard-write *; web-share *; encrypted-media *; accelerometer *; gyroscope *",
|
|
92
156
|
className: "w-full h-[70vh] rounded-lg border",
|
|
157
|
+
...{ credentialless: "true" },
|
|
93
158
|
title: "Playruo",
|
|
94
159
|
style: {
|
|
95
160
|
position: showIframe ? void 0 : "absolute",
|