@playruo/embed 1.2.0 → 1.2.2

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/README.md CHANGED
@@ -1,302 +1,3 @@
1
1
  # @playruo/embed
2
2
 
3
3
  React SDK to embed Playruo via iframe + postMessage.
4
-
5
- See the official docs: [Playruo Embed Documentation](https://playruo.notion.site/Playruo-Embed-Documentation-268a5e7d674180dd901ae0753187d7c1?pvs=74).
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm i @playruo/embed
11
- ```
12
-
13
- ## Quick start (Next.js / React)
14
-
15
- ```tsx
16
- "use client";
17
- import { PlayruoEmbed } from "@playruo/embed";
18
-
19
- export const Demo = () => (
20
- <PlayruoEmbed
21
- operation="iframe"
22
- storeUrl="https://store.steampowered.com/app/2751000/..."
23
- showIframe
24
- onReady={() => console.log("ready")}
25
- onStateChange={(state) => console.log("state", state)}
26
- onDemoCompleted={(data) => console.log("completed", data)}
27
- onPurchaseRequest={({ storeUrl }) => {
28
- // Example: open the store page in a new tab
29
- window.open(storeUrl, "_blank", "noopener,noreferrer");
30
- }}
31
- onError={(message) => console.error(message)}
32
- />
33
- );
34
- ```
35
-
36
- ## Headless mode (with renderState)
37
-
38
- ```tsx
39
- "use client";
40
- import { PlayruoEmbed } from "@playruo/embed";
41
- import { useState } from "react";
42
-
43
- export const Demo = () => {
44
- const [showIframe, setShowIframe] = useState(false);
45
-
46
- return (
47
- <PlayruoEmbed
48
- operation="iframe"
49
- storeUrl="https://store.steampowered.com/app/2751000/..."
50
- showIframe={showIframe}
51
- renderState={({ status, message, actions }) => {
52
- if (status === "loading") return <div>Loading demo…</div>;
53
- if (status === "error") return <div>Error: {message}</div>;
54
-
55
- if (status === "available") {
56
- return (
57
- <div className="flex gap-3">
58
- <button
59
- onClick={() => {
60
- setShowIframe(true);
61
- actions.tryNow();
62
- }}
63
- disabled={!actions.canTryNow}
64
- >
65
- Try Now
66
- </button>
67
- <button
68
- onClick={actions.buyNow}
69
- disabled={!actions.canBuyNow}
70
- >
71
- Buy Now
72
- </button>
73
- </div>
74
- );
75
- }
76
-
77
- // unavailable
78
- return (
79
- <div className="flex gap-3">
80
- <span>{message ?? "Unavailable"}</span>
81
- <button
82
- onClick={actions.buyNow}
83
- disabled={!actions.canBuyNow}
84
- >
85
- Buy Now
86
- </button>
87
- </div>
88
- );
89
- }}
90
- />
91
- );
92
- };
93
- ```
94
-
95
- ### Props
96
-
97
- - **operation**: string (optional, default: "iframe")
98
- - **storeUrl**: string (optional)
99
- - **showIframe**: boolean (optional)
100
- - **className**: string (optional)
101
- - **onReady()**: callback when the iframe signals readiness
102
- - **onStateChange(state)**: receives live availability state
103
- - **onDemoCompleted(data)**: fired when the demo session completes
104
- - **onPurchaseRequest({ storeUrl })**: fired when purchase is requested
105
- - **onError(message)**: fired on error
106
-
107
- #### Render API
108
-
109
- - **renderState({ status, message, actions })**: single render entry point
110
- - `status`: "loading" | "available" | "unavailable" | "error"
111
- - `message?`: optional status message (e.g. availability reason)
112
- - `actions`: object with `tryNow()`, `buyNow()`, `canTryNow`, `canBuyNow`
113
-
114
-
115
- ### Events
116
-
117
- - **onReady()**
118
- - **onStateChange(state)**
119
- - **onDemoCompleted(data)**
120
- - **onPurchaseRequest({ storeUrl })**
121
- - **onError(error)**
122
-
123
- ## State shape
124
-
125
- ```ts
126
- export interface PlayruoEmbedState {
127
- hasPlayedOnce: boolean;
128
- tryNow: { available: boolean; status?: string };
129
- buyNow: { available: boolean; status?: string };
130
- }
131
- ```
132
-
133
- ## Actions API
134
-
135
- The `renderState` callback receives an `actions` object with:
136
-
137
- - **`actions.tryNow()`** → sends `try_now` command to the iframe
138
- - **`actions.buyNow()`** → sends `buy_now` command to the iframe
139
- - **`actions.canTryNow`** → boolean indicating if try now is available
140
- - **`actions.canBuyNow`** → boolean indicating if buy now is available
141
-
142
- ```tsx
143
- renderState={({ actions }) => (
144
- <button onClick={actions.tryNow} disabled={!actions.canTryNow}>
145
- Try Now
146
- </button>
147
- )}
148
- ```
149
-
150
- ## Incoming messages (from iframe)
151
-
152
- The component listens to Playruo postMessage events and triggers the corresponding callbacks:
153
-
154
- - `"playruo_ready"` → `onReady()`
155
- - `"playruo_state_update"` → `onStateChange(state)`
156
- - `"playruo_demo_completed"` → `onDemoCompleted(data)`
157
- - `"playruo_purchase_request"` → `onPurchaseRequest({ storeUrl })`
158
- - `"playruo_error"` → `onError(message)`
159
-
160
- ## URL builder (Advanced)
161
-
162
- For advanced use cases, you can build the iframe URL manually:
163
-
164
- ```ts
165
- import { buildEmbedUrl } from "@playruo/embed";
166
-
167
- const url = buildEmbedUrl({
168
- baseUrl: "https://playruo.example.com",
169
- operation: "iframe", // optional, default: "iframe"
170
- storeUrl: "https://store.steampowered.com/app/2751000/...", // optional
171
- });
172
- ```
173
-
174
- The URL points to `{baseUrl}/embed` with query params:
175
- - `operation` (optional)
176
- - `storeUrl` (optional)
177
-
178
- ## Iframe behavior
179
-
180
- - The iframe is always present in the DOM. Set `showIframe` to control visibility.
181
- - The iframe has `allow="fullscreen *; autoplay *; gamepad *"`.
182
-
183
- ## TypeScript Types
184
-
185
- ### Component Types
186
-
187
- ```typescript
188
- import type {
189
- PlayruoEmbedProps,
190
- PlayruoEmbedState,
191
- PlayruoEmbedActions,
192
- PlayruoEmbedRenderState,
193
- DemoCompletedPayload,
194
- } from "@playruo/embed";
195
- ```
196
-
197
- ### PostMessage Communication Types
198
-
199
- For advanced use cases where you need to handle communication with the embed iframe directly:
200
-
201
- ```typescript
202
- import type {
203
- PlayruoEmbedMessage,
204
- PlayruoEmbedCommand,
205
- PlayruoReadyMessage,
206
- PlayruoStateUpdateMessage,
207
- PlayruoPurchaseRequestMessage,
208
- PlayruoDemoCompletedMessage,
209
- PlayruoErrorMessage,
210
- TryNowCommand,
211
- BuyNowCommand,
212
- GetStateCommand,
213
- } from "@playruo/embed";
214
- import { isPlayruoEmbedMessage, isPlayruoEmbedCommand } from "@playruo/embed";
215
- ```
216
-
217
- #### Example: Custom Message Handler
218
-
219
- ```typescript
220
- "use client";
221
- import { useEffect } from "react";
222
- import type { PlayruoEmbedMessage } from "@playruo/embed";
223
- import { isPlayruoEmbedMessage } from "@playruo/embed";
224
-
225
- export const MyComponent = () => {
226
- useEffect(() => {
227
- const handleMessage = (event: MessageEvent) => {
228
- if (isPlayruoEmbedMessage(event.data)) {
229
- const message = event.data as PlayruoEmbedMessage;
230
-
231
- switch (message.type) {
232
- case 'playruo_ready':
233
- console.log("Embed is ready!");
234
- break;
235
- case 'playruo_state_update':
236
- console.log("State updated:", message.data);
237
- break;
238
- case 'playruo_purchase_request':
239
- window.open(message.data.storeUrl, "_blank");
240
- break;
241
- case 'playruo_demo_completed':
242
- console.log("Demo completed:", message.data.reason);
243
- break;
244
- case 'playruo_error':
245
- console.error("Embed error:", message.data);
246
- break;
247
- }
248
- }
249
- };
250
-
251
- window.addEventListener('message', handleMessage);
252
- return () => window.removeEventListener('message', handleMessage);
253
- }, []);
254
-
255
- // ...
256
- };
257
- ```
258
-
259
- #### Example: Sending Commands
260
-
261
- ```typescript
262
- import type { PlayruoEmbedCommand } from "@playruo/embed";
263
-
264
- const sendCommandToEmbed = (command: PlayruoEmbedCommand) => {
265
- const iframe = document.querySelector('iframe');
266
- iframe?.contentWindow?.postMessage(command, '*');
267
- };
268
-
269
- // Send commands
270
- sendCommandToEmbed({ type: 'try_now' });
271
- sendCommandToEmbed({ type: 'buy_now' });
272
- sendCommandToEmbed({ type: 'get_state' });
273
- ```
274
-
275
- ### Exported Types
276
-
277
- **Component:**
278
- - `PlayruoEmbed` - Main React component
279
- - `PlayruoEmbedProps` - Component props
280
- - `PlayruoEmbedActions` - Actions API
281
- - `PlayruoEmbedRenderState` - Render state API
282
- - `PlayruoEmbedState` - Embed state
283
- - `DemoCompletedPayload` - Demo completion data
284
-
285
- **Messages (Embed → Host):**
286
- - `PlayruoEmbedMessage` - Union of all message types
287
- - `PlayruoReadyMessage`
288
- - `PlayruoStateUpdateMessage`
289
- - `PlayruoPurchaseRequestMessage`
290
- - `PlayruoDemoCompletedMessage`
291
- - `PlayruoErrorMessage`
292
-
293
- **Commands (Host → Embed):**
294
- - `PlayruoEmbedCommand` - Union of all command types
295
- - `TryNowCommand`
296
- - `BuyNowCommand`
297
- - `GetStateCommand`
298
-
299
- **Utilities:**
300
- - `buildEmbedUrl` - URL builder function
301
- - `isPlayruoEmbedMessage` - Type guard for messages
302
- - `isPlayruoEmbedCommand` - Type guard for commands