@oasiz/sdk 1.6.1 → 1.6.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 +79 -0
- package/dist/index.cjs +1479 -330
- package/dist/index.d.cts +79 -31
- package/dist/index.d.ts +79 -31
- package/dist/index.js +1478 -330
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,32 +1,1419 @@
|
|
|
1
|
+
// src/navigation.ts
|
|
2
|
+
var BACK_BUTTON_TEST_STATE_KEY = "__oasizBackButtonTest";
|
|
3
|
+
var activeBackListeners = 0;
|
|
4
|
+
var activeBackButtonTestingHandle;
|
|
5
|
+
function isDevelopment() {
|
|
6
|
+
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
7
|
+
return nodeEnv !== "production";
|
|
8
|
+
}
|
|
9
|
+
function getBridgeWindow() {
|
|
10
|
+
if (typeof window === "undefined") {
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
return window;
|
|
14
|
+
}
|
|
15
|
+
function warnMissingBridge(methodName) {
|
|
16
|
+
if (isDevelopment()) {
|
|
17
|
+
console.warn(
|
|
18
|
+
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function normalizeNavigationError(error) {
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
return error;
|
|
25
|
+
}
|
|
26
|
+
return new Error(
|
|
27
|
+
typeof error === "string" ? error : "Back button callback failed."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
function isRecord(value) {
|
|
31
|
+
return typeof value === "object" && value !== null;
|
|
32
|
+
}
|
|
33
|
+
function dispatchNavigationEvent(eventName) {
|
|
34
|
+
const bridge = getBridgeWindow();
|
|
35
|
+
if (!bridge || typeof bridge.dispatchEvent !== "function") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
bridge.dispatchEvent(new Event(eventName));
|
|
39
|
+
}
|
|
40
|
+
function addNavigationListener(eventName, callback) {
|
|
41
|
+
if (typeof window === "undefined") {
|
|
42
|
+
if (isDevelopment()) {
|
|
43
|
+
console.warn(
|
|
44
|
+
"[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return () => {
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const handler = () => callback();
|
|
51
|
+
window.addEventListener(eventName, handler);
|
|
52
|
+
return () => window.removeEventListener(eventName, handler);
|
|
53
|
+
}
|
|
54
|
+
function enableBackButtonTesting(options = {}) {
|
|
55
|
+
activeBackButtonTestingHandle?.destroy();
|
|
56
|
+
const bridge = getBridgeWindow();
|
|
57
|
+
if (!bridge) {
|
|
58
|
+
if (isDevelopment()) {
|
|
59
|
+
console.warn(
|
|
60
|
+
"[oasiz/sdk] enableBackButtonTesting requires a browser window."
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
destroy: () => {
|
|
65
|
+
},
|
|
66
|
+
isBackOverrideActive: () => false,
|
|
67
|
+
triggerBack: () => {
|
|
68
|
+
},
|
|
69
|
+
triggerLeave: () => {
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const bridgeWindow = bridge;
|
|
74
|
+
const keyboard = options.keyboard ?? true;
|
|
75
|
+
const browserHistory = options.browserHistory ?? true;
|
|
76
|
+
const log = options.log === true;
|
|
77
|
+
const previousSetBackOverride = bridgeWindow.__oasizSetBackOverride;
|
|
78
|
+
const previousLeaveGame = bridgeWindow.__oasizLeaveGame;
|
|
79
|
+
let destroyed = false;
|
|
80
|
+
let backOverrideActive = false;
|
|
81
|
+
let historyTrapArmed = false;
|
|
82
|
+
function maybeLog(message) {
|
|
83
|
+
if (log) {
|
|
84
|
+
console.info("[oasiz/sdk] " + message);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function canUseHistoryTrap() {
|
|
88
|
+
return browserHistory && typeof bridgeWindow.history?.pushState === "function" && typeof bridgeWindow.history?.replaceState === "function" && typeof bridgeWindow.location?.href === "string";
|
|
89
|
+
}
|
|
90
|
+
function ensureHistoryTrap() {
|
|
91
|
+
if (!backOverrideActive || historyTrapArmed || !canUseHistoryTrap()) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const currentState = isRecord(bridgeWindow.history.state) ? bridgeWindow.history.state : {};
|
|
96
|
+
bridgeWindow.history.replaceState(
|
|
97
|
+
{ ...currentState, [BACK_BUTTON_TEST_STATE_KEY]: "base" },
|
|
98
|
+
"",
|
|
99
|
+
bridgeWindow.location.href
|
|
100
|
+
);
|
|
101
|
+
bridgeWindow.history.pushState(
|
|
102
|
+
{ [BACK_BUTTON_TEST_STATE_KEY]: "trap" },
|
|
103
|
+
"",
|
|
104
|
+
bridgeWindow.location.href
|
|
105
|
+
);
|
|
106
|
+
historyTrapArmed = true;
|
|
107
|
+
maybeLog("Local browser Back testing is armed.");
|
|
108
|
+
} catch (error) {
|
|
109
|
+
historyTrapArmed = false;
|
|
110
|
+
if (log) {
|
|
111
|
+
console.warn("[oasiz/sdk] Failed to arm browser Back testing:", error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function triggerBack() {
|
|
116
|
+
dispatchNavigationEvent("oasiz:back");
|
|
117
|
+
}
|
|
118
|
+
function triggerLeave() {
|
|
119
|
+
dispatchNavigationEvent("oasiz:leave");
|
|
120
|
+
}
|
|
121
|
+
function setBackOverride(active) {
|
|
122
|
+
backOverrideActive = active;
|
|
123
|
+
if (active) {
|
|
124
|
+
ensureHistoryTrap();
|
|
125
|
+
}
|
|
126
|
+
if (typeof previousSetBackOverride === "function") {
|
|
127
|
+
previousSetBackOverride(active);
|
|
128
|
+
}
|
|
129
|
+
maybeLog("Back override " + (active ? "enabled" : "disabled") + ".");
|
|
130
|
+
}
|
|
131
|
+
function stopBackEvent(event) {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
event.stopPropagation();
|
|
134
|
+
event.stopImmediatePropagation?.();
|
|
135
|
+
}
|
|
136
|
+
const handleKeyDown = (event) => {
|
|
137
|
+
if (!backOverrideActive || event.key !== "Escape") {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
stopBackEvent(event);
|
|
141
|
+
triggerBack();
|
|
142
|
+
};
|
|
143
|
+
const handlePopState = (event) => {
|
|
144
|
+
if (!backOverrideActive) {
|
|
145
|
+
historyTrapArmed = false;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
stopBackEvent(event);
|
|
149
|
+
triggerBack();
|
|
150
|
+
historyTrapArmed = false;
|
|
151
|
+
ensureHistoryTrap();
|
|
152
|
+
};
|
|
153
|
+
const testLeaveGame = () => {
|
|
154
|
+
triggerLeave();
|
|
155
|
+
if (typeof previousLeaveGame === "function") {
|
|
156
|
+
previousLeaveGame();
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
bridgeWindow.__oasizSetBackOverride = setBackOverride;
|
|
160
|
+
bridgeWindow.__oasizLeaveGame = testLeaveGame;
|
|
161
|
+
if (keyboard) {
|
|
162
|
+
bridgeWindow.addEventListener("keydown", handleKeyDown);
|
|
163
|
+
}
|
|
164
|
+
if (browserHistory) {
|
|
165
|
+
bridgeWindow.addEventListener("popstate", handlePopState);
|
|
166
|
+
}
|
|
167
|
+
if (activeBackListeners > 0) {
|
|
168
|
+
setBackOverride(true);
|
|
169
|
+
}
|
|
170
|
+
maybeLog("Back button testing bridge installed.");
|
|
171
|
+
const handle = {
|
|
172
|
+
destroy: () => {
|
|
173
|
+
if (destroyed) return;
|
|
174
|
+
destroyed = true;
|
|
175
|
+
if (keyboard) {
|
|
176
|
+
bridgeWindow.removeEventListener("keydown", handleKeyDown);
|
|
177
|
+
}
|
|
178
|
+
if (browserHistory) {
|
|
179
|
+
bridgeWindow.removeEventListener("popstate", handlePopState);
|
|
180
|
+
}
|
|
181
|
+
if (bridgeWindow.__oasizSetBackOverride === setBackOverride) {
|
|
182
|
+
bridgeWindow.__oasizSetBackOverride = previousSetBackOverride;
|
|
183
|
+
}
|
|
184
|
+
if (bridgeWindow.__oasizLeaveGame === testLeaveGame) {
|
|
185
|
+
bridgeWindow.__oasizLeaveGame = previousLeaveGame;
|
|
186
|
+
}
|
|
187
|
+
if (activeBackButtonTestingHandle === handle) {
|
|
188
|
+
activeBackButtonTestingHandle = void 0;
|
|
189
|
+
}
|
|
190
|
+
maybeLog("Back button testing bridge removed.");
|
|
191
|
+
},
|
|
192
|
+
isBackOverrideActive: () => backOverrideActive,
|
|
193
|
+
triggerBack,
|
|
194
|
+
triggerLeave
|
|
195
|
+
};
|
|
196
|
+
activeBackButtonTestingHandle = handle;
|
|
197
|
+
return handle;
|
|
198
|
+
}
|
|
199
|
+
function onBackButton(callback) {
|
|
200
|
+
const off = addNavigationListener("oasiz:back", () => {
|
|
201
|
+
try {
|
|
202
|
+
callback();
|
|
203
|
+
} catch (error) {
|
|
204
|
+
leaveGame();
|
|
205
|
+
throw normalizeNavigationError(error);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const bridge = getBridgeWindow();
|
|
209
|
+
activeBackListeners += 1;
|
|
210
|
+
if (activeBackListeners === 1) {
|
|
211
|
+
if (typeof bridge?.__oasizSetBackOverride === "function") {
|
|
212
|
+
bridge.__oasizSetBackOverride(true);
|
|
213
|
+
} else {
|
|
214
|
+
warnMissingBridge("__oasizSetBackOverride");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return () => {
|
|
218
|
+
off();
|
|
219
|
+
activeBackListeners = Math.max(0, activeBackListeners - 1);
|
|
220
|
+
if (activeBackListeners === 0) {
|
|
221
|
+
const currentBridge = getBridgeWindow();
|
|
222
|
+
if (typeof currentBridge?.__oasizSetBackOverride === "function") {
|
|
223
|
+
currentBridge.__oasizSetBackOverride(false);
|
|
224
|
+
} else {
|
|
225
|
+
warnMissingBridge("__oasizSetBackOverride");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function onLeaveGame(callback) {
|
|
231
|
+
return addNavigationListener("oasiz:leave", callback);
|
|
232
|
+
}
|
|
233
|
+
function leaveGame() {
|
|
234
|
+
const bridge = getBridgeWindow();
|
|
235
|
+
if (typeof bridge?.__oasizLeaveGame === "function") {
|
|
236
|
+
bridge.__oasizLeaveGame();
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
warnMissingBridge("__oasizLeaveGame");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/app-simulator.ts
|
|
243
|
+
var DEVICE_PRESETS = {
|
|
244
|
+
"iphone-11": {
|
|
245
|
+
name: "iPhone 11",
|
|
246
|
+
width: 414,
|
|
247
|
+
height: 896,
|
|
248
|
+
safeArea: { top: 48, right: 0, bottom: 34, left: 0 }
|
|
249
|
+
},
|
|
250
|
+
"iphone-11-pro": {
|
|
251
|
+
name: "iPhone 11 Pro",
|
|
252
|
+
width: 375,
|
|
253
|
+
height: 812,
|
|
254
|
+
safeArea: { top: 44, right: 0, bottom: 34, left: 0 }
|
|
255
|
+
},
|
|
256
|
+
"iphone-11-pro-max": {
|
|
257
|
+
name: "iPhone 11 Pro Max",
|
|
258
|
+
width: 414,
|
|
259
|
+
height: 896,
|
|
260
|
+
safeArea: { top: 44, right: 0, bottom: 34, left: 0 }
|
|
261
|
+
},
|
|
262
|
+
"iphone-12-mini": {
|
|
263
|
+
name: "iPhone 12 mini",
|
|
264
|
+
width: 375,
|
|
265
|
+
height: 812,
|
|
266
|
+
safeArea: { top: 50, right: 0, bottom: 34, left: 0 }
|
|
267
|
+
},
|
|
268
|
+
"iphone-12": {
|
|
269
|
+
name: "iPhone 12",
|
|
270
|
+
width: 390,
|
|
271
|
+
height: 844,
|
|
272
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
273
|
+
},
|
|
274
|
+
"iphone-12-pro": {
|
|
275
|
+
name: "iPhone 12 Pro",
|
|
276
|
+
width: 390,
|
|
277
|
+
height: 844,
|
|
278
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
279
|
+
},
|
|
280
|
+
"iphone-12-pro-max": {
|
|
281
|
+
name: "iPhone 12 Pro Max",
|
|
282
|
+
width: 428,
|
|
283
|
+
height: 926,
|
|
284
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
285
|
+
},
|
|
286
|
+
"iphone-13-mini": {
|
|
287
|
+
name: "iPhone 13 mini",
|
|
288
|
+
width: 375,
|
|
289
|
+
height: 812,
|
|
290
|
+
safeArea: { top: 50, right: 0, bottom: 34, left: 0 }
|
|
291
|
+
},
|
|
292
|
+
"iphone-13": {
|
|
293
|
+
name: "iPhone 13",
|
|
294
|
+
width: 390,
|
|
295
|
+
height: 844,
|
|
296
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
297
|
+
},
|
|
298
|
+
"iphone-13-pro": {
|
|
299
|
+
name: "iPhone 13 Pro",
|
|
300
|
+
width: 390,
|
|
301
|
+
height: 844,
|
|
302
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
303
|
+
},
|
|
304
|
+
"iphone-13-pro-max": {
|
|
305
|
+
name: "iPhone 13 Pro Max",
|
|
306
|
+
width: 428,
|
|
307
|
+
height: 926,
|
|
308
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
309
|
+
},
|
|
310
|
+
"iphone-14": {
|
|
311
|
+
name: "iPhone 14",
|
|
312
|
+
width: 390,
|
|
313
|
+
height: 844,
|
|
314
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
315
|
+
},
|
|
316
|
+
"iphone-14-plus": {
|
|
317
|
+
name: "iPhone 14 Plus",
|
|
318
|
+
width: 428,
|
|
319
|
+
height: 926,
|
|
320
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
321
|
+
},
|
|
322
|
+
"iphone-14-pro": {
|
|
323
|
+
name: "iPhone 14 Pro",
|
|
324
|
+
width: 393,
|
|
325
|
+
height: 852,
|
|
326
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
327
|
+
},
|
|
328
|
+
"iphone-14-pro-max": {
|
|
329
|
+
name: "iPhone 14 Pro Max",
|
|
330
|
+
width: 430,
|
|
331
|
+
height: 932,
|
|
332
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
333
|
+
},
|
|
334
|
+
"iphone-15": {
|
|
335
|
+
name: "iPhone 15",
|
|
336
|
+
width: 393,
|
|
337
|
+
height: 852,
|
|
338
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
339
|
+
},
|
|
340
|
+
"iphone-15-plus": {
|
|
341
|
+
name: "iPhone 15 Plus",
|
|
342
|
+
width: 430,
|
|
343
|
+
height: 932,
|
|
344
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
345
|
+
},
|
|
346
|
+
"iphone-15-pro": {
|
|
347
|
+
name: "iPhone 15 Pro",
|
|
348
|
+
width: 393,
|
|
349
|
+
height: 852,
|
|
350
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
351
|
+
},
|
|
352
|
+
"iphone-15-pro-max": {
|
|
353
|
+
name: "iPhone 15 Pro Max",
|
|
354
|
+
width: 430,
|
|
355
|
+
height: 932,
|
|
356
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
357
|
+
},
|
|
358
|
+
"iphone-16": {
|
|
359
|
+
name: "iPhone 16",
|
|
360
|
+
width: 393,
|
|
361
|
+
height: 852,
|
|
362
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
363
|
+
},
|
|
364
|
+
"iphone-16-plus": {
|
|
365
|
+
name: "iPhone 16 Plus",
|
|
366
|
+
width: 430,
|
|
367
|
+
height: 932,
|
|
368
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
369
|
+
},
|
|
370
|
+
"iphone-16-pro": {
|
|
371
|
+
name: "iPhone 16 Pro",
|
|
372
|
+
width: 402,
|
|
373
|
+
height: 874,
|
|
374
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
375
|
+
},
|
|
376
|
+
"iphone-16-pro-max": {
|
|
377
|
+
name: "iPhone 16 Pro Max",
|
|
378
|
+
width: 440,
|
|
379
|
+
height: 956,
|
|
380
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
381
|
+
},
|
|
382
|
+
"iphone-16e": {
|
|
383
|
+
name: "iPhone 16e",
|
|
384
|
+
width: 390,
|
|
385
|
+
height: 844,
|
|
386
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
387
|
+
},
|
|
388
|
+
"iphone-17": {
|
|
389
|
+
name: "iPhone 17",
|
|
390
|
+
width: 402,
|
|
391
|
+
height: 874,
|
|
392
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
393
|
+
},
|
|
394
|
+
"iphone-17-pro": {
|
|
395
|
+
name: "iPhone 17 Pro",
|
|
396
|
+
width: 402,
|
|
397
|
+
height: 874,
|
|
398
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
399
|
+
},
|
|
400
|
+
"iphone-17-pro-max": {
|
|
401
|
+
name: "iPhone 17 Pro Max",
|
|
402
|
+
width: 440,
|
|
403
|
+
height: 956,
|
|
404
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
405
|
+
},
|
|
406
|
+
"iphone-17e": {
|
|
407
|
+
name: "iPhone 17e",
|
|
408
|
+
width: 390,
|
|
409
|
+
height: 844,
|
|
410
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
411
|
+
},
|
|
412
|
+
"iphone-air": {
|
|
413
|
+
name: "iPhone Air",
|
|
414
|
+
width: 420,
|
|
415
|
+
height: 912,
|
|
416
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
417
|
+
},
|
|
418
|
+
"iphone-se": {
|
|
419
|
+
name: "iPhone SE",
|
|
420
|
+
width: 375,
|
|
421
|
+
height: 667,
|
|
422
|
+
safeArea: { top: 20, right: 0, bottom: 0, left: 0 }
|
|
423
|
+
},
|
|
424
|
+
"pixel-8": {
|
|
425
|
+
name: "Pixel 8",
|
|
426
|
+
width: 412,
|
|
427
|
+
height: 915,
|
|
428
|
+
safeArea: { top: 32, right: 0, bottom: 24, left: 0 }
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
var DEFAULT_COUNTS = {
|
|
432
|
+
comments: 18,
|
|
433
|
+
likes: 128
|
|
434
|
+
};
|
|
435
|
+
var DEFAULT_SCORE = 12400;
|
|
436
|
+
var TOP_BAR_OFFSET = 12;
|
|
437
|
+
var TOP_CHROME_HEIGHT = 44;
|
|
438
|
+
var BODY_BACKGROUND = "#08090d";
|
|
439
|
+
var TEXT_PRIMARY = "#F6F9FB";
|
|
440
|
+
var TEXT_SECONDARY = "rgba(246,249,251,0.72)";
|
|
441
|
+
var TEXT_MUTED = "rgba(246,249,251,0.52)";
|
|
442
|
+
var BORDER = "rgba(255,255,255,0.14)";
|
|
443
|
+
var ACCENT = "#00A1E4";
|
|
444
|
+
var LIKE = "#ef4444";
|
|
445
|
+
var TROPHY = "#FBBF24";
|
|
446
|
+
var MAX_Z_INDEX = 2147483638;
|
|
447
|
+
var EMPTY_INSETS = {
|
|
448
|
+
top: 0,
|
|
449
|
+
right: 0,
|
|
450
|
+
bottom: 0,
|
|
451
|
+
left: 0
|
|
452
|
+
};
|
|
453
|
+
var BRIDGE_KEYS = [
|
|
454
|
+
"__OASIZ_SAFE_AREA_BOTTOM__",
|
|
455
|
+
"__OASIZ_SAFE_AREA_BOTTOM_PERCENT__",
|
|
456
|
+
"__OASIZ_SAFE_AREA_LEFT__",
|
|
457
|
+
"__OASIZ_SAFE_AREA_LEFT_PERCENT__",
|
|
458
|
+
"__OASIZ_SAFE_AREA_RIGHT__",
|
|
459
|
+
"__OASIZ_SAFE_AREA_RIGHT_PERCENT__",
|
|
460
|
+
"__OASIZ_SAFE_AREA_TOP__",
|
|
461
|
+
"__OASIZ_SAFE_AREA_TOP_PERCENT__",
|
|
462
|
+
"__OASIZ_VIEWPORT_INSETS__",
|
|
463
|
+
"__OASIZ_VIEWPORT_INSETS_PERCENT__",
|
|
464
|
+
"__oasizSetLeaderboardVisible",
|
|
465
|
+
"getSafeAreaBottom",
|
|
466
|
+
"getSafeAreaBottomPercent",
|
|
467
|
+
"getSafeAreaLeft",
|
|
468
|
+
"getSafeAreaLeftPercent",
|
|
469
|
+
"getSafeAreaRight",
|
|
470
|
+
"getSafeAreaRightPercent",
|
|
471
|
+
"getSafeAreaTop",
|
|
472
|
+
"getSafeAreaTopPercent",
|
|
473
|
+
"getViewportInsets",
|
|
474
|
+
"getViewportInsetsPercent"
|
|
475
|
+
];
|
|
476
|
+
var NOOP_HANDLE = {
|
|
477
|
+
closeSheet() {
|
|
478
|
+
},
|
|
479
|
+
destroy() {
|
|
480
|
+
},
|
|
481
|
+
getViewportInsets() {
|
|
482
|
+
return { pixels: { ...EMPTY_INSETS }, percent: { ...EMPTY_INSETS } };
|
|
483
|
+
},
|
|
484
|
+
hide() {
|
|
485
|
+
},
|
|
486
|
+
isVisible() {
|
|
487
|
+
return false;
|
|
488
|
+
},
|
|
489
|
+
openComments() {
|
|
490
|
+
},
|
|
491
|
+
openLeaderboard() {
|
|
492
|
+
},
|
|
493
|
+
setCounts() {
|
|
494
|
+
},
|
|
495
|
+
setLeaderboardVisible() {
|
|
496
|
+
},
|
|
497
|
+
setLiked() {
|
|
498
|
+
},
|
|
499
|
+
show() {
|
|
500
|
+
},
|
|
501
|
+
triggerBack() {
|
|
502
|
+
},
|
|
503
|
+
triggerLeave() {
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
function getBrowserWindow() {
|
|
507
|
+
if (typeof window === "undefined") {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
return window;
|
|
511
|
+
}
|
|
512
|
+
function getDocument() {
|
|
513
|
+
if (typeof document === "undefined") {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
return document;
|
|
517
|
+
}
|
|
518
|
+
function warn(message) {
|
|
519
|
+
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
520
|
+
if (nodeEnv !== "production") {
|
|
521
|
+
console.warn("[oasiz/sdk] " + message);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function normalizeCount(value, fallback) {
|
|
525
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
526
|
+
return fallback;
|
|
527
|
+
}
|
|
528
|
+
return Math.max(0, Math.floor(value));
|
|
529
|
+
}
|
|
530
|
+
function formatCompactCount(value) {
|
|
531
|
+
if (value >= 1e6) {
|
|
532
|
+
return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
|
|
533
|
+
}
|
|
534
|
+
if (value >= 1e3) {
|
|
535
|
+
return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "k";
|
|
536
|
+
}
|
|
537
|
+
return String(value);
|
|
538
|
+
}
|
|
539
|
+
function resolveDevice(device, orientation) {
|
|
540
|
+
const preset = typeof device === "string" ? DEVICE_PRESETS[device] : device ? {
|
|
541
|
+
name: device.name ?? "Custom phone",
|
|
542
|
+
width: device.width,
|
|
543
|
+
height: device.height,
|
|
544
|
+
safeArea: {
|
|
545
|
+
...EMPTY_INSETS,
|
|
546
|
+
...device.safeArea
|
|
547
|
+
}
|
|
548
|
+
} : DEVICE_PRESETS["iphone-17-pro-max"];
|
|
549
|
+
const normalized = {
|
|
550
|
+
name: preset.name,
|
|
551
|
+
width: Math.max(320, Math.floor(preset.width)),
|
|
552
|
+
height: Math.max(480, Math.floor(preset.height)),
|
|
553
|
+
safeArea: {
|
|
554
|
+
...EMPTY_INSETS,
|
|
555
|
+
...preset.safeArea
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
if (orientation === "landscape") {
|
|
559
|
+
return {
|
|
560
|
+
...normalized,
|
|
561
|
+
width: Math.max(normalized.width, normalized.height),
|
|
562
|
+
height: Math.min(normalized.width, normalized.height),
|
|
563
|
+
safeArea: {
|
|
564
|
+
top: 0,
|
|
565
|
+
right: normalized.safeArea.top,
|
|
566
|
+
bottom: 21,
|
|
567
|
+
left: normalized.safeArea.top
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
return normalized;
|
|
572
|
+
}
|
|
573
|
+
function shouldFrame(frame, browserWindow, device) {
|
|
574
|
+
if (frame === true) {
|
|
575
|
+
return true;
|
|
576
|
+
}
|
|
577
|
+
if (frame === false) {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
return browserWindow.innerWidth > device.width + 80 || browserWindow.innerHeight > device.height + 80;
|
|
581
|
+
}
|
|
582
|
+
function computeRect(browserWindow, device, frameEnabled) {
|
|
583
|
+
const viewportWidth = Math.max(320, browserWindow.innerWidth || device.width);
|
|
584
|
+
const viewportHeight = Math.max(480, browserWindow.innerHeight || device.height);
|
|
585
|
+
if (!frameEnabled) {
|
|
586
|
+
return {
|
|
587
|
+
left: 0,
|
|
588
|
+
top: 0,
|
|
589
|
+
width: viewportWidth,
|
|
590
|
+
height: viewportHeight,
|
|
591
|
+
scale: Math.min(viewportWidth / device.width, viewportHeight / device.height)
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
const margin = 24;
|
|
595
|
+
const scale = Math.min(
|
|
596
|
+
(viewportWidth - margin) / device.width,
|
|
597
|
+
(viewportHeight - margin) / device.height,
|
|
598
|
+
1
|
|
599
|
+
);
|
|
600
|
+
const width = Math.round(device.width * scale);
|
|
601
|
+
const height = Math.round(device.height * scale);
|
|
602
|
+
return {
|
|
603
|
+
left: Math.round((viewportWidth - width) / 2),
|
|
604
|
+
top: Math.round((viewportHeight - height) / 2),
|
|
605
|
+
width,
|
|
606
|
+
height,
|
|
607
|
+
scale
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function scaledInset(value, scale) {
|
|
611
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
612
|
+
return 0;
|
|
613
|
+
}
|
|
614
|
+
return Math.max(0, Math.round(value * scale));
|
|
615
|
+
}
|
|
616
|
+
function getSimulatorInsets(state) {
|
|
617
|
+
const safe = state.device.safeArea;
|
|
618
|
+
const top = scaledInset(safe.top, state.rect.scale) + Math.round((TOP_BAR_OFFSET + TOP_CHROME_HEIGHT) * state.rect.scale);
|
|
619
|
+
const pixels = {
|
|
620
|
+
top,
|
|
621
|
+
right: scaledInset(safe.right, state.rect.scale),
|
|
622
|
+
bottom: scaledInset(safe.bottom, state.rect.scale),
|
|
623
|
+
left: scaledInset(safe.left, state.rect.scale)
|
|
624
|
+
};
|
|
625
|
+
const percent = {
|
|
626
|
+
top: state.rect.height > 0 ? pixels.top / state.rect.height * 100 : 0,
|
|
627
|
+
right: state.rect.width > 0 ? pixels.right / state.rect.width * 100 : 0,
|
|
628
|
+
bottom: state.rect.height > 0 ? pixels.bottom / state.rect.height * 100 : 0,
|
|
629
|
+
left: state.rect.width > 0 ? pixels.left / state.rect.width * 100 : 0
|
|
630
|
+
};
|
|
631
|
+
return { pixels, percent };
|
|
632
|
+
}
|
|
633
|
+
function snapshotBridge(browserWindow) {
|
|
634
|
+
const globals = {};
|
|
635
|
+
for (const key of BRIDGE_KEYS) {
|
|
636
|
+
globals[key] = browserWindow[key];
|
|
637
|
+
}
|
|
638
|
+
return { globals };
|
|
639
|
+
}
|
|
640
|
+
function restoreBridge(browserWindow, snapshot) {
|
|
641
|
+
for (const key of BRIDGE_KEYS) {
|
|
642
|
+
const value = snapshot.globals[key];
|
|
643
|
+
if (typeof value === "undefined") {
|
|
644
|
+
delete browserWindow[key];
|
|
645
|
+
} else {
|
|
646
|
+
browserWindow[key] = value;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function installBridge(state) {
|
|
651
|
+
const browserWindow = getBrowserWindow();
|
|
652
|
+
if (!browserWindow) return;
|
|
653
|
+
const bridge = browserWindow;
|
|
654
|
+
function refreshInsets() {
|
|
655
|
+
const insets = getSimulatorInsets(state);
|
|
656
|
+
bridge.__OASIZ_VIEWPORT_INSETS__ = insets;
|
|
657
|
+
bridge.__OASIZ_VIEWPORT_INSETS_PERCENT__ = insets.percent;
|
|
658
|
+
bridge.__OASIZ_SAFE_AREA_TOP__ = insets.pixels.top;
|
|
659
|
+
bridge.__OASIZ_SAFE_AREA_RIGHT__ = insets.pixels.right;
|
|
660
|
+
bridge.__OASIZ_SAFE_AREA_BOTTOM__ = insets.pixels.bottom;
|
|
661
|
+
bridge.__OASIZ_SAFE_AREA_LEFT__ = insets.pixels.left;
|
|
662
|
+
bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__ = insets.percent.top;
|
|
663
|
+
bridge.__OASIZ_SAFE_AREA_RIGHT_PERCENT__ = insets.percent.right;
|
|
664
|
+
bridge.__OASIZ_SAFE_AREA_BOTTOM_PERCENT__ = insets.percent.bottom;
|
|
665
|
+
bridge.__OASIZ_SAFE_AREA_LEFT_PERCENT__ = insets.percent.left;
|
|
666
|
+
return insets;
|
|
667
|
+
}
|
|
668
|
+
bridge.getViewportInsets = () => refreshInsets();
|
|
669
|
+
bridge.getViewportInsetsPercent = () => refreshInsets().percent;
|
|
670
|
+
bridge.getSafeAreaTop = () => refreshInsets().pixels.top;
|
|
671
|
+
bridge.getSafeAreaRight = () => refreshInsets().pixels.right;
|
|
672
|
+
bridge.getSafeAreaBottom = () => refreshInsets().pixels.bottom;
|
|
673
|
+
bridge.getSafeAreaLeft = () => refreshInsets().pixels.left;
|
|
674
|
+
bridge.getSafeAreaTopPercent = () => refreshInsets().percent.top;
|
|
675
|
+
bridge.getSafeAreaRightPercent = () => refreshInsets().percent.right;
|
|
676
|
+
bridge.getSafeAreaBottomPercent = () => refreshInsets().percent.bottom;
|
|
677
|
+
bridge.getSafeAreaLeftPercent = () => refreshInsets().percent.left;
|
|
678
|
+
bridge.__oasizSetLeaderboardVisible = (visible) => {
|
|
679
|
+
state.leaderboard.visible = visible;
|
|
680
|
+
renderSimulator(state);
|
|
681
|
+
};
|
|
682
|
+
refreshInsets();
|
|
683
|
+
}
|
|
684
|
+
function createStyleElement() {
|
|
685
|
+
const style = document.createElement("style");
|
|
686
|
+
style.setAttribute("data-oasiz-app-simulator", "styles");
|
|
687
|
+
style.textContent = [
|
|
688
|
+
".oasiz-app-sim-button{appearance:none;border:0;margin:0;padding:0;font:inherit;color:inherit;background:transparent;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:manipulation}",
|
|
689
|
+
".oasiz-app-sim-button:active{transform:scale(0.97)}",
|
|
690
|
+
".oasiz-app-sim-glass{background:rgba(18,20,24,0.42);border:1px solid rgba(255,255,255,0.22);box-shadow:0 12px 30px rgba(0,0,0,0.28),inset 0 1px 0 rgba(255,255,255,0.18);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px)}",
|
|
691
|
+
".oasiz-app-sim-scroll::-webkit-scrollbar{width:0;height:0}"
|
|
692
|
+
].join("\n");
|
|
693
|
+
return style;
|
|
694
|
+
}
|
|
695
|
+
function applyTextStyle(element, size = 12, weight = 600) {
|
|
696
|
+
element.style.font = String(weight) + " " + String(size) + "px/1.2 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif";
|
|
697
|
+
}
|
|
698
|
+
function createDiv(className) {
|
|
699
|
+
const element = document.createElement("div");
|
|
700
|
+
if (className) {
|
|
701
|
+
element.className = className;
|
|
702
|
+
}
|
|
703
|
+
return element;
|
|
704
|
+
}
|
|
705
|
+
function createButton(label, title) {
|
|
706
|
+
const button = document.createElement("button");
|
|
707
|
+
button.type = "button";
|
|
708
|
+
button.className = "oasiz-app-sim-button";
|
|
709
|
+
button.setAttribute("aria-label", title);
|
|
710
|
+
button.title = title;
|
|
711
|
+
button.innerHTML = label;
|
|
712
|
+
return button;
|
|
713
|
+
}
|
|
714
|
+
function svgIcon(name, filled = false) {
|
|
715
|
+
if (name === "back") {
|
|
716
|
+
return '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5"/><path d="m12 19-7-7 7-7"/></svg>';
|
|
717
|
+
}
|
|
718
|
+
if (name === "heart") {
|
|
719
|
+
return filled ? '<svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor"><path d="M12 21s-7.4-4.4-9.7-9.1C.7 8.5 2.7 4.8 6.4 4.3c2-.3 3.8.7 5.6 2.8 1.8-2.1 3.6-3.1 5.6-2.8 3.7.5 5.7 4.2 4.1 7.6C19.4 16.6 12 21 12 21Z"/></svg>' : '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.8 4.6c-2-1.8-5.1-1.5-6.9.6L12 7.4l-1.9-2.2C8.3 3.1 5.2 2.8 3.2 4.6.8 6.8.7 10.5 3 12.9L12 21l9-8.1c2.3-2.4 2.2-6.1-.2-8.3Z"/></svg>';
|
|
720
|
+
}
|
|
721
|
+
if (name === "chat") {
|
|
722
|
+
return filled ? '<svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor"><path d="M4 5.5A3.5 3.5 0 0 1 7.5 2h9A3.5 3.5 0 0 1 20 5.5v7A3.5 3.5 0 0 1 16.5 16H9l-4.2 3.1A1.1 1.1 0 0 1 3 18.2V5.5Z"/></svg>' : '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5.5A3.5 3.5 0 0 1 7.5 2h9A3.5 3.5 0 0 1 20 5.5v7A3.5 3.5 0 0 1 16.5 16H9l-4.2 3.1A1.1 1.1 0 0 1 3 18.2V5.5Z"/></svg>';
|
|
723
|
+
}
|
|
724
|
+
if (name === "trophy") {
|
|
725
|
+
return '<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M7 3h10v3h3a1 1 0 0 1 1 1c0 3.2-1.8 5.5-4.6 6.1A5 5 0 0 1 13 15.9V19h3v2H8v-2h3v-3.1a5 5 0 0 1-3.4-2.8C4.8 12.5 3 10.2 3 7a1 1 0 0 1 1-1h3V3Zm10 5v2.8c1.1-.5 1.8-1.5 2-2.8h-2ZM5 8c.2 1.3.9 2.3 2 2.8V8H5Z"/></svg>';
|
|
726
|
+
}
|
|
727
|
+
if (name === "share") {
|
|
728
|
+
return '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"><path d="M12 16V4"/><path d="m7 9 5-5 5 5"/><path d="M5 14v5h14v-5"/></svg>';
|
|
729
|
+
}
|
|
730
|
+
return filled ? '<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M6 3h12a1 1 0 0 1 1 1v17l-7-4-7 4V4a1 1 0 0 1 1-1Z"/></svg>' : '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h12a1 1 0 0 1 1 1v17l-7-4-7 4V4a1 1 0 0 1 1-1Z"/></svg>';
|
|
731
|
+
}
|
|
732
|
+
function setBoxStyle(element, state) {
|
|
733
|
+
const { rect } = state;
|
|
734
|
+
element.style.left = rect.left + "px";
|
|
735
|
+
element.style.top = rect.top + "px";
|
|
736
|
+
element.style.width = rect.width + "px";
|
|
737
|
+
element.style.height = rect.height + "px";
|
|
738
|
+
}
|
|
739
|
+
function createCircleButton(icon, title, onClick) {
|
|
740
|
+
const button = createButton(icon, title);
|
|
741
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
742
|
+
button.style.cssText += [
|
|
743
|
+
"position:absolute",
|
|
744
|
+
"width:44px",
|
|
745
|
+
"height:44px",
|
|
746
|
+
"border-radius:999px",
|
|
747
|
+
"display:flex",
|
|
748
|
+
"align-items:center",
|
|
749
|
+
"justify-content:center",
|
|
750
|
+
"color:" + TEXT_PRIMARY,
|
|
751
|
+
"pointer-events:auto"
|
|
752
|
+
].join(";");
|
|
753
|
+
button.addEventListener("click", (event) => {
|
|
754
|
+
event.preventDefault();
|
|
755
|
+
event.stopPropagation();
|
|
756
|
+
onClick();
|
|
757
|
+
});
|
|
758
|
+
return button;
|
|
759
|
+
}
|
|
760
|
+
function createHubPill(state) {
|
|
761
|
+
const button = createButton("", "Open comments");
|
|
762
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
763
|
+
button.style.cssText += [
|
|
764
|
+
"position:absolute",
|
|
765
|
+
"right:16px",
|
|
766
|
+
"height:44px",
|
|
767
|
+
"min-width:94px",
|
|
768
|
+
"border-radius:999px",
|
|
769
|
+
"display:flex",
|
|
770
|
+
"align-items:center",
|
|
771
|
+
"justify-content:center",
|
|
772
|
+
"gap:10px",
|
|
773
|
+
"padding:0 14px",
|
|
774
|
+
"color:" + TEXT_PRIMARY,
|
|
775
|
+
"pointer-events:auto"
|
|
776
|
+
].join(";");
|
|
777
|
+
const likeColor = state.wasLiked ? LIKE : TEXT_PRIMARY;
|
|
778
|
+
button.innerHTML = '<span style="display:inline-flex;align-items:center;gap:4px;color:' + likeColor + '">' + svgIcon("heart", state.wasLiked) + "<span>" + formatCompactCount(state.counts.likes) + '</span></span><span style="display:inline-flex;align-items:center;gap:4px;color:' + ACCENT + '">' + svgIcon("chat", true) + "<span>" + formatCompactCount(state.counts.comments) + "</span></span>";
|
|
779
|
+
applyTextStyle(button, 12, 700);
|
|
780
|
+
button.addEventListener("click", (event) => {
|
|
781
|
+
event.preventDefault();
|
|
782
|
+
event.stopPropagation();
|
|
783
|
+
state.sheet = "comments";
|
|
784
|
+
renderSimulator(state);
|
|
785
|
+
});
|
|
786
|
+
return button;
|
|
787
|
+
}
|
|
788
|
+
function createLeaderboardPill(state) {
|
|
789
|
+
const button = createButton("", "Open leaderboard");
|
|
790
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
791
|
+
button.style.cssText += [
|
|
792
|
+
"position:absolute",
|
|
793
|
+
"left:50%",
|
|
794
|
+
"height:44px",
|
|
795
|
+
"min-width:118px",
|
|
796
|
+
"border-radius:999px",
|
|
797
|
+
"display:" + (state.leaderboard.visible ? "flex" : "none"),
|
|
798
|
+
"align-items:center",
|
|
799
|
+
"justify-content:center",
|
|
800
|
+
"gap:8px",
|
|
801
|
+
"padding:0 14px",
|
|
802
|
+
"color:" + TEXT_PRIMARY,
|
|
803
|
+
"pointer-events:auto",
|
|
804
|
+
"transform:translateX(-50%)"
|
|
805
|
+
].join(";");
|
|
806
|
+
button.innerHTML = '<span style="color:' + TROPHY + ';display:inline-flex">' + svgIcon("trophy", true) + '</span><span style="min-width:0">' + formatCompactCount(state.leaderboard.score) + "</span>";
|
|
807
|
+
applyTextStyle(button, 14, 800);
|
|
808
|
+
button.addEventListener("click", (event) => {
|
|
809
|
+
event.preventDefault();
|
|
810
|
+
event.stopPropagation();
|
|
811
|
+
state.sheet = "leaderboard";
|
|
812
|
+
renderSimulator(state);
|
|
813
|
+
});
|
|
814
|
+
return button;
|
|
815
|
+
}
|
|
816
|
+
function createToolbarButton(icon, count, color, title, onClick) {
|
|
817
|
+
const button = createButton("", title);
|
|
818
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
819
|
+
button.style.cssText += [
|
|
820
|
+
"height:42px",
|
|
821
|
+
"min-width:42px",
|
|
822
|
+
"border-radius:999px",
|
|
823
|
+
"display:flex",
|
|
824
|
+
"align-items:center",
|
|
825
|
+
"justify-content:center",
|
|
826
|
+
"gap:6px",
|
|
827
|
+
"padding:0 12px",
|
|
828
|
+
"color:" + color,
|
|
829
|
+
"pointer-events:auto"
|
|
830
|
+
].join(";");
|
|
831
|
+
button.innerHTML = icon + (count === null ? "" : '<span style="color:' + color + ';min-width:0">' + formatCompactCount(count) + "</span>");
|
|
832
|
+
applyTextStyle(button, 13, 700);
|
|
833
|
+
button.addEventListener("click", (event) => {
|
|
834
|
+
event.preventDefault();
|
|
835
|
+
event.stopPropagation();
|
|
836
|
+
onClick();
|
|
837
|
+
});
|
|
838
|
+
return button;
|
|
839
|
+
}
|
|
840
|
+
function createSheet(state) {
|
|
841
|
+
if (!state.sheet) {
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
const overlay = createDiv();
|
|
845
|
+
overlay.style.cssText = [
|
|
846
|
+
"position:absolute",
|
|
847
|
+
"left:0",
|
|
848
|
+
"top:0",
|
|
849
|
+
"right:0",
|
|
850
|
+
"bottom:0",
|
|
851
|
+
"display:flex",
|
|
852
|
+
"align-items:center",
|
|
853
|
+
"justify-content:center",
|
|
854
|
+
"padding:" + String(scaledInset(state.device.safeArea.top, state.rect.scale) + 72) + "px 12px " + String(Math.max(18, scaledInset(state.device.safeArea.bottom, state.rect.scale) + 18)) + "px",
|
|
855
|
+
"background:rgba(0,0,0,0.34)",
|
|
856
|
+
"pointer-events:auto"
|
|
857
|
+
].join(";");
|
|
858
|
+
overlay.addEventListener("click", () => {
|
|
859
|
+
state.sheet = null;
|
|
860
|
+
renderSimulator(state);
|
|
861
|
+
});
|
|
862
|
+
const sheet = createDiv();
|
|
863
|
+
sheet.style.cssText = [
|
|
864
|
+
"position:relative",
|
|
865
|
+
"width:min(100%, 408px)",
|
|
866
|
+
"max-height:100%",
|
|
867
|
+
"min-height:min(390px, 64%)",
|
|
868
|
+
"display:flex",
|
|
869
|
+
"flex-direction:column",
|
|
870
|
+
"border-radius:24px",
|
|
871
|
+
"border:1px solid " + BORDER,
|
|
872
|
+
"background:linear-gradient(180deg, rgba(18,20,24,0.97), rgba(9,11,15,0.98))",
|
|
873
|
+
"box-shadow:0 30px 80px rgba(0,0,0,0.52), inset 0 1px 0 rgba(255,255,255,0.10)",
|
|
874
|
+
"overflow:hidden",
|
|
875
|
+
"pointer-events:auto"
|
|
876
|
+
].join(";");
|
|
877
|
+
sheet.addEventListener("click", (event) => {
|
|
878
|
+
event.stopPropagation();
|
|
879
|
+
});
|
|
880
|
+
const handle = createDiv();
|
|
881
|
+
handle.style.cssText = [
|
|
882
|
+
"width:42px",
|
|
883
|
+
"height:5px",
|
|
884
|
+
"border-radius:999px",
|
|
885
|
+
"background:rgba(255,255,255,0.28)",
|
|
886
|
+
"align-self:center",
|
|
887
|
+
"margin:10px 0 2px"
|
|
888
|
+
].join(";");
|
|
889
|
+
const header = createDiv();
|
|
890
|
+
header.style.cssText = [
|
|
891
|
+
"display:flex",
|
|
892
|
+
"align-items:center",
|
|
893
|
+
"justify-content:space-between",
|
|
894
|
+
"gap:8px",
|
|
895
|
+
"min-height:62px",
|
|
896
|
+
"padding:6px 14px 10px",
|
|
897
|
+
"border-bottom:1px solid " + BORDER
|
|
898
|
+
].join(";");
|
|
899
|
+
const left = createDiv();
|
|
900
|
+
left.style.cssText = "display:flex;align-items:center;gap:8px;min-width:112px";
|
|
901
|
+
const title = createDiv();
|
|
902
|
+
title.textContent = state.sheet === "comments" ? String(state.counts.comments) + " comments" : "Leaderboard";
|
|
903
|
+
title.style.cssText = [
|
|
904
|
+
"flex:1",
|
|
905
|
+
"min-width:0",
|
|
906
|
+
"text-align:center",
|
|
907
|
+
"color:" + TEXT_PRIMARY
|
|
908
|
+
].join(";");
|
|
909
|
+
applyTextStyle(title, 14, 700);
|
|
910
|
+
const right = createDiv();
|
|
911
|
+
right.style.cssText = "display:flex;align-items:center;justify-content:flex-end;gap:8px;min-width:112px";
|
|
912
|
+
const back = createToolbarButton(svgIcon("back"), null, TEXT_PRIMARY, "Close", () => {
|
|
913
|
+
state.sheet = null;
|
|
914
|
+
renderSimulator(state);
|
|
915
|
+
});
|
|
916
|
+
back.style.width = "36px";
|
|
917
|
+
back.style.height = "36px";
|
|
918
|
+
back.style.padding = "0";
|
|
919
|
+
left.appendChild(back);
|
|
920
|
+
if (state.sheet === "comments") {
|
|
921
|
+
const like = createToolbarButton(
|
|
922
|
+
svgIcon("heart", state.wasLiked),
|
|
923
|
+
state.counts.likes,
|
|
924
|
+
state.wasLiked ? LIKE : TEXT_PRIMARY,
|
|
925
|
+
"Like game",
|
|
926
|
+
() => {
|
|
927
|
+
state.wasLiked = !state.wasLiked;
|
|
928
|
+
state.counts.likes = Math.max(0, state.counts.likes + (state.wasLiked ? 1 : -1));
|
|
929
|
+
renderSimulator(state);
|
|
930
|
+
}
|
|
931
|
+
);
|
|
932
|
+
left.appendChild(like);
|
|
933
|
+
} else {
|
|
934
|
+
const trophy = createToolbarButton(svgIcon("trophy", true), null, TROPHY, "Leaderboard", () => {
|
|
935
|
+
});
|
|
936
|
+
trophy.style.width = "36px";
|
|
937
|
+
trophy.style.height = "36px";
|
|
938
|
+
trophy.style.padding = "0";
|
|
939
|
+
left.appendChild(trophy);
|
|
940
|
+
}
|
|
941
|
+
const share2 = createToolbarButton(svgIcon("share"), null, TEXT_PRIMARY, "Share", () => {
|
|
942
|
+
});
|
|
943
|
+
const save = createToolbarButton(svgIcon("bookmark"), null, TEXT_PRIMARY, "Save", () => {
|
|
944
|
+
});
|
|
945
|
+
right.appendChild(share2);
|
|
946
|
+
right.appendChild(save);
|
|
947
|
+
header.appendChild(left);
|
|
948
|
+
header.appendChild(title);
|
|
949
|
+
header.appendChild(right);
|
|
950
|
+
const body = createDiv("oasiz-app-sim-scroll");
|
|
951
|
+
body.style.cssText = [
|
|
952
|
+
"display:flex",
|
|
953
|
+
"flex-direction:column",
|
|
954
|
+
"gap:10px",
|
|
955
|
+
"overflow:auto",
|
|
956
|
+
"padding:14px 16px calc(" + String(Math.max(16, scaledInset(state.device.safeArea.bottom, state.rect.scale))) + "px + 14px)",
|
|
957
|
+
"min-height:0"
|
|
958
|
+
].join(";");
|
|
959
|
+
if (state.sheet === "leaderboard") {
|
|
960
|
+
appendLeaderboardBody(body);
|
|
961
|
+
} else {
|
|
962
|
+
appendCommentsBody(body, state);
|
|
963
|
+
}
|
|
964
|
+
sheet.appendChild(handle);
|
|
965
|
+
sheet.appendChild(header);
|
|
966
|
+
sheet.appendChild(body);
|
|
967
|
+
overlay.appendChild(sheet);
|
|
968
|
+
return overlay;
|
|
969
|
+
}
|
|
970
|
+
function appendLeaderboardBody(body) {
|
|
971
|
+
const tabs = createDiv();
|
|
972
|
+
tabs.style.cssText = [
|
|
973
|
+
"display:grid",
|
|
974
|
+
"grid-template-columns:repeat(3,1fr)",
|
|
975
|
+
"gap:6px",
|
|
976
|
+
"padding:4px",
|
|
977
|
+
"border-radius:14px",
|
|
978
|
+
"background:rgba(255,255,255,0.07)"
|
|
979
|
+
].join(";");
|
|
980
|
+
for (const label of ["Weekly", "Global", "Friends"]) {
|
|
981
|
+
const tab = createDiv();
|
|
982
|
+
tab.textContent = label;
|
|
983
|
+
tab.style.cssText = [
|
|
984
|
+
"border-radius:10px",
|
|
985
|
+
"padding:8px 6px",
|
|
986
|
+
"text-align:center",
|
|
987
|
+
"color:" + (label === "Weekly" ? TEXT_PRIMARY : TEXT_MUTED),
|
|
988
|
+
"background:" + (label === "Weekly" ? "rgba(0,161,228,0.28)" : "transparent")
|
|
989
|
+
].join(";");
|
|
990
|
+
applyTextStyle(tab, 12, 700);
|
|
991
|
+
tabs.appendChild(tab);
|
|
992
|
+
}
|
|
993
|
+
body.appendChild(tabs);
|
|
994
|
+
const entries = [
|
|
995
|
+
["1", "Nova", "24.8k"],
|
|
996
|
+
["2", "You", "12.4k"],
|
|
997
|
+
["3", "Mika", "9.7k"],
|
|
998
|
+
["4", "Ari", "8.1k"]
|
|
999
|
+
];
|
|
1000
|
+
for (const [rank, name, score] of entries) {
|
|
1001
|
+
const row = createDiv();
|
|
1002
|
+
row.style.cssText = [
|
|
1003
|
+
"display:grid",
|
|
1004
|
+
"grid-template-columns:34px 1fr auto",
|
|
1005
|
+
"align-items:center",
|
|
1006
|
+
"gap:10px",
|
|
1007
|
+
"min-height:58px",
|
|
1008
|
+
"padding:10px 12px",
|
|
1009
|
+
"border-radius:14px",
|
|
1010
|
+
"background:" + (name === "You" ? "rgba(0,161,228,0.13)" : "rgba(255,255,255,0.06)"),
|
|
1011
|
+
"border:1px solid " + (name === "You" ? "rgba(0,161,228,0.28)" : "rgba(255,255,255,0.08)")
|
|
1012
|
+
].join(";");
|
|
1013
|
+
const rankEl = createDiv();
|
|
1014
|
+
rankEl.textContent = rank;
|
|
1015
|
+
rankEl.style.cssText = "color:" + (rank === "1" ? TROPHY : TEXT_MUTED) + ";text-align:center";
|
|
1016
|
+
applyTextStyle(rankEl, 14, 800);
|
|
1017
|
+
const nameEl = createDiv();
|
|
1018
|
+
nameEl.textContent = name;
|
|
1019
|
+
nameEl.style.cssText = "color:" + TEXT_PRIMARY + ";min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
1020
|
+
applyTextStyle(nameEl, 14, 700);
|
|
1021
|
+
const scoreEl = createDiv();
|
|
1022
|
+
scoreEl.textContent = score;
|
|
1023
|
+
scoreEl.style.cssText = "color:" + TEXT_SECONDARY;
|
|
1024
|
+
applyTextStyle(scoreEl, 13, 700);
|
|
1025
|
+
row.appendChild(rankEl);
|
|
1026
|
+
row.appendChild(nameEl);
|
|
1027
|
+
row.appendChild(scoreEl);
|
|
1028
|
+
body.appendChild(row);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
function appendCommentsBody(body, state) {
|
|
1032
|
+
const toolbar = createDiv();
|
|
1033
|
+
toolbar.style.cssText = [
|
|
1034
|
+
"display:flex",
|
|
1035
|
+
"align-items:center",
|
|
1036
|
+
"gap:8px",
|
|
1037
|
+
"height:48px"
|
|
1038
|
+
].join(";");
|
|
1039
|
+
toolbar.appendChild(
|
|
1040
|
+
createToolbarButton(
|
|
1041
|
+
svgIcon("heart", state.wasLiked),
|
|
1042
|
+
state.counts.likes,
|
|
1043
|
+
state.wasLiked ? LIKE : TEXT_PRIMARY,
|
|
1044
|
+
"Like game",
|
|
1045
|
+
() => {
|
|
1046
|
+
state.wasLiked = !state.wasLiked;
|
|
1047
|
+
state.counts.likes = Math.max(0, state.counts.likes + (state.wasLiked ? 1 : -1));
|
|
1048
|
+
renderSimulator(state);
|
|
1049
|
+
}
|
|
1050
|
+
)
|
|
1051
|
+
);
|
|
1052
|
+
toolbar.appendChild(
|
|
1053
|
+
createToolbarButton(svgIcon("chat", true), state.counts.comments, ACCENT, "Comments", () => {
|
|
1054
|
+
})
|
|
1055
|
+
);
|
|
1056
|
+
toolbar.appendChild(createToolbarButton(svgIcon("share"), null, TEXT_PRIMARY, "Share", () => {
|
|
1057
|
+
}));
|
|
1058
|
+
toolbar.appendChild(createToolbarButton(svgIcon("bookmark"), null, TEXT_PRIMARY, "Save", () => {
|
|
1059
|
+
}));
|
|
1060
|
+
body.appendChild(toolbar);
|
|
1061
|
+
const comments = [
|
|
1062
|
+
["You", "Can my score panel clear the top buttons?"],
|
|
1063
|
+
["Nova", "This is a good spot to check pause and menu spacing."],
|
|
1064
|
+
["Mika", "The app chrome stays above the game just like mobile."]
|
|
1065
|
+
];
|
|
1066
|
+
for (const [author, text] of comments) {
|
|
1067
|
+
const row = createDiv();
|
|
1068
|
+
row.style.cssText = [
|
|
1069
|
+
"display:grid",
|
|
1070
|
+
"grid-template-columns:34px 1fr",
|
|
1071
|
+
"gap:10px",
|
|
1072
|
+
"padding:10px 0"
|
|
1073
|
+
].join(";");
|
|
1074
|
+
const avatar = createDiv();
|
|
1075
|
+
avatar.textContent = author.charAt(0);
|
|
1076
|
+
avatar.style.cssText = [
|
|
1077
|
+
"width:34px",
|
|
1078
|
+
"height:34px",
|
|
1079
|
+
"border-radius:999px",
|
|
1080
|
+
"display:flex",
|
|
1081
|
+
"align-items:center",
|
|
1082
|
+
"justify-content:center",
|
|
1083
|
+
"background:rgba(0,161,228,0.28)",
|
|
1084
|
+
"color:" + TEXT_PRIMARY
|
|
1085
|
+
].join(";");
|
|
1086
|
+
applyTextStyle(avatar, 13, 800);
|
|
1087
|
+
const message = createDiv();
|
|
1088
|
+
message.innerHTML = '<div style="color:' + TEXT_PRIMARY + ';font-weight:700;margin-bottom:3px">' + author + '</div><div style="color:' + TEXT_SECONDARY + '">' + text + "</div>";
|
|
1089
|
+
applyTextStyle(message, 13, 500);
|
|
1090
|
+
row.appendChild(avatar);
|
|
1091
|
+
row.appendChild(message);
|
|
1092
|
+
body.appendChild(row);
|
|
1093
|
+
}
|
|
1094
|
+
const composer = createDiv();
|
|
1095
|
+
composer.textContent = "Add comment...";
|
|
1096
|
+
composer.style.cssText = [
|
|
1097
|
+
"height:44px",
|
|
1098
|
+
"border-radius:18px",
|
|
1099
|
+
"display:flex",
|
|
1100
|
+
"align-items:center",
|
|
1101
|
+
"padding:0 14px",
|
|
1102
|
+
"background:rgba(255,255,255,0.08)",
|
|
1103
|
+
"border:1px solid rgba(255,255,255,0.10)",
|
|
1104
|
+
"color:" + TEXT_MUTED
|
|
1105
|
+
].join(";");
|
|
1106
|
+
applyTextStyle(composer, 13, 600);
|
|
1107
|
+
body.appendChild(composer);
|
|
1108
|
+
}
|
|
1109
|
+
function renderSimulator(state) {
|
|
1110
|
+
if (state.wasDestroyed) {
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
const { root, stage, gameViewport } = state.elements;
|
|
1114
|
+
root.style.display = state.visible ? "block" : "none";
|
|
1115
|
+
setBoxStyle(stage, state);
|
|
1116
|
+
if (gameViewport) {
|
|
1117
|
+
setBoxStyle(gameViewport, state);
|
|
1118
|
+
}
|
|
1119
|
+
stage.replaceChildren();
|
|
1120
|
+
const top = scaledInset(state.device.safeArea.top, state.rect.scale) + Math.round(TOP_BAR_OFFSET * state.rect.scale);
|
|
1121
|
+
const back = createCircleButton(svgIcon("back"), "Back", () => {
|
|
1122
|
+
if (state.backHandle.isBackOverrideActive()) {
|
|
1123
|
+
state.backHandle.triggerBack();
|
|
1124
|
+
} else {
|
|
1125
|
+
state.backHandle.triggerLeave();
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
back.style.left = Math.round(16 * state.rect.scale) + "px";
|
|
1129
|
+
back.style.top = top + "px";
|
|
1130
|
+
const leaderboard = createLeaderboardPill(state);
|
|
1131
|
+
leaderboard.style.top = top + "px";
|
|
1132
|
+
const hub = createHubPill(state);
|
|
1133
|
+
hub.style.top = top + "px";
|
|
1134
|
+
hub.style.right = Math.round(16 * state.rect.scale) + "px";
|
|
1135
|
+
stage.appendChild(back);
|
|
1136
|
+
stage.appendChild(leaderboard);
|
|
1137
|
+
stage.appendChild(hub);
|
|
1138
|
+
const sheet = createSheet(state);
|
|
1139
|
+
if (sheet) {
|
|
1140
|
+
stage.appendChild(sheet);
|
|
1141
|
+
}
|
|
1142
|
+
if (state.options.log) {
|
|
1143
|
+
console.info("[oasiz/sdk] App simulator rendered.", {
|
|
1144
|
+
device: state.device.name,
|
|
1145
|
+
frame: state.frameEnabled,
|
|
1146
|
+
insets: getSimulatorInsets(state)
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
function installFrame(doc, state) {
|
|
1151
|
+
if (!state.frameEnabled || !doc.body) {
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
const body = doc.body;
|
|
1155
|
+
const html = doc.documentElement;
|
|
1156
|
+
const viewport = state.elements.gameViewport;
|
|
1157
|
+
if (!viewport) {
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
html.style.cssText = [
|
|
1161
|
+
state.previousDocumentElementStyle ?? "",
|
|
1162
|
+
"width:100%",
|
|
1163
|
+
"height:100%",
|
|
1164
|
+
"background:" + BODY_BACKGROUND,
|
|
1165
|
+
"overflow:hidden"
|
|
1166
|
+
].join(";");
|
|
1167
|
+
body.style.cssText = [
|
|
1168
|
+
state.previousBodyStyle ?? "",
|
|
1169
|
+
"width:100%",
|
|
1170
|
+
"height:100%",
|
|
1171
|
+
"margin:0",
|
|
1172
|
+
"background:" + BODY_BACKGROUND,
|
|
1173
|
+
"overflow:hidden"
|
|
1174
|
+
].join(";");
|
|
1175
|
+
const candidates = Array.from(body.children).filter(
|
|
1176
|
+
(node) => shouldMoveIntoGameViewport(node, state.elements)
|
|
1177
|
+
);
|
|
1178
|
+
for (const node of candidates) {
|
|
1179
|
+
state.movedNodes.push(node);
|
|
1180
|
+
viewport.appendChild(node);
|
|
1181
|
+
}
|
|
1182
|
+
body.appendChild(viewport);
|
|
1183
|
+
}
|
|
1184
|
+
function shouldMoveIntoGameViewport(node, elements) {
|
|
1185
|
+
if (node === elements.root || node === elements.style || node === elements.gameViewport) {
|
|
1186
|
+
return false;
|
|
1187
|
+
}
|
|
1188
|
+
const tagName = node.tagName.toUpperCase();
|
|
1189
|
+
if (tagName === "SCRIPT" || tagName === "STYLE" || tagName === "LINK" || tagName === "META" || tagName === "NOSCRIPT") {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
return node.getAttribute("data-oasiz-app-simulator") !== "true";
|
|
1193
|
+
}
|
|
1194
|
+
function restoreFrame(doc, state) {
|
|
1195
|
+
const body = doc.body;
|
|
1196
|
+
if (!body) {
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
for (const node of state.movedNodes) {
|
|
1200
|
+
body.appendChild(node);
|
|
1201
|
+
}
|
|
1202
|
+
state.movedNodes = [];
|
|
1203
|
+
state.elements.gameViewport?.remove();
|
|
1204
|
+
if (state.previousBodyStyle === null) {
|
|
1205
|
+
body.removeAttribute("style");
|
|
1206
|
+
} else {
|
|
1207
|
+
body.setAttribute("style", state.previousBodyStyle);
|
|
1208
|
+
}
|
|
1209
|
+
if (state.previousDocumentElementStyle === null) {
|
|
1210
|
+
doc.documentElement.removeAttribute("style");
|
|
1211
|
+
} else {
|
|
1212
|
+
doc.documentElement.setAttribute("style", state.previousDocumentElementStyle);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
function createElements(frameEnabled) {
|
|
1216
|
+
const root = document.createElement("div");
|
|
1217
|
+
root.setAttribute("data-oasiz-app-simulator", "true");
|
|
1218
|
+
root.style.cssText = [
|
|
1219
|
+
"position:fixed",
|
|
1220
|
+
"inset:0",
|
|
1221
|
+
"z-index:" + String(MAX_Z_INDEX),
|
|
1222
|
+
"pointer-events:none",
|
|
1223
|
+
"display:block",
|
|
1224
|
+
"font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif"
|
|
1225
|
+
].join(";");
|
|
1226
|
+
const stage = document.createElement("div");
|
|
1227
|
+
stage.setAttribute("data-oasiz-app-simulator", "stage");
|
|
1228
|
+
stage.style.cssText = [
|
|
1229
|
+
"position:absolute",
|
|
1230
|
+
"overflow:hidden",
|
|
1231
|
+
"pointer-events:none"
|
|
1232
|
+
].join(";");
|
|
1233
|
+
root.appendChild(stage);
|
|
1234
|
+
const gameViewport = frameEnabled ? document.createElement("div") : null;
|
|
1235
|
+
if (gameViewport) {
|
|
1236
|
+
gameViewport.setAttribute("data-oasiz-app-simulator", "game-viewport");
|
|
1237
|
+
gameViewport.style.cssText = [
|
|
1238
|
+
"position:fixed",
|
|
1239
|
+
"z-index:0",
|
|
1240
|
+
"overflow:hidden",
|
|
1241
|
+
"background:#000",
|
|
1242
|
+
"border-radius:28px",
|
|
1243
|
+
"outline:1px solid rgba(255,255,255,0.28)",
|
|
1244
|
+
"box-shadow:0 28px 90px rgba(0,0,0,0.48),0 0 0 8px rgba(255,255,255,0.06),0 0 0 10px rgba(0,0,0,0.58)"
|
|
1245
|
+
].join(";");
|
|
1246
|
+
}
|
|
1247
|
+
return {
|
|
1248
|
+
gameViewport,
|
|
1249
|
+
root,
|
|
1250
|
+
stage,
|
|
1251
|
+
style: createStyleElement()
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
function installResizeHandler(browserWindow, state) {
|
|
1255
|
+
const resize = () => {
|
|
1256
|
+
state.rect = computeRect(browserWindow, state.device, state.frameEnabled);
|
|
1257
|
+
installBridge(state);
|
|
1258
|
+
renderSimulator(state);
|
|
1259
|
+
};
|
|
1260
|
+
browserWindow.addEventListener("resize", resize);
|
|
1261
|
+
browserWindow.addEventListener("orientationchange", resize);
|
|
1262
|
+
return () => {
|
|
1263
|
+
browserWindow.removeEventListener("resize", resize);
|
|
1264
|
+
browserWindow.removeEventListener("orientationchange", resize);
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
function enableAppSimulator(options = {}) {
|
|
1268
|
+
if (options.enabled === false) {
|
|
1269
|
+
return NOOP_HANDLE;
|
|
1270
|
+
}
|
|
1271
|
+
const browserWindow = getBrowserWindow();
|
|
1272
|
+
const doc = getDocument();
|
|
1273
|
+
if (!browserWindow || !doc?.body || !doc.documentElement) {
|
|
1274
|
+
warn("enableAppSimulator requires a browser document.");
|
|
1275
|
+
return NOOP_HANDLE;
|
|
1276
|
+
}
|
|
1277
|
+
browserWindow.__oasizAppSimulatorHandle__?.destroy();
|
|
1278
|
+
const orientation = options.orientation ?? "portrait";
|
|
1279
|
+
const device = resolveDevice(options.device, orientation);
|
|
1280
|
+
const frameEnabled = shouldFrame(options.frame ?? true, browserWindow, device);
|
|
1281
|
+
const elements = createElements(frameEnabled);
|
|
1282
|
+
const rect = computeRect(browserWindow, device, frameEnabled);
|
|
1283
|
+
const backHandle = enableBackButtonTesting({
|
|
1284
|
+
browserHistory: options.browserHistoryBack ?? true,
|
|
1285
|
+
keyboard: options.keyboardBack ?? true,
|
|
1286
|
+
log: options.log === true
|
|
1287
|
+
});
|
|
1288
|
+
const state = {
|
|
1289
|
+
backHandle,
|
|
1290
|
+
bridgeSnapshot: snapshotBridge(browserWindow),
|
|
1291
|
+
cleanupResize: () => {
|
|
1292
|
+
},
|
|
1293
|
+
counts: {
|
|
1294
|
+
comments: normalizeCount(options.comments, DEFAULT_COUNTS.comments),
|
|
1295
|
+
likes: normalizeCount(options.likes, DEFAULT_COUNTS.likes)
|
|
1296
|
+
},
|
|
1297
|
+
device,
|
|
1298
|
+
elements,
|
|
1299
|
+
frameEnabled,
|
|
1300
|
+
leaderboard: {
|
|
1301
|
+
score: normalizeCount(options.score, DEFAULT_SCORE),
|
|
1302
|
+
visible: options.leaderboardVisible ?? true
|
|
1303
|
+
},
|
|
1304
|
+
movedNodes: [],
|
|
1305
|
+
options: {
|
|
1306
|
+
browserHistoryBack: options.browserHistoryBack ?? true,
|
|
1307
|
+
keyboardBack: options.keyboardBack ?? true,
|
|
1308
|
+
log: options.log === true,
|
|
1309
|
+
orientation,
|
|
1310
|
+
title: options.title ?? "Oasiz App Preview"
|
|
1311
|
+
},
|
|
1312
|
+
previousBodyStyle: doc.body.getAttribute("style"),
|
|
1313
|
+
previousDocumentElementStyle: doc.documentElement.getAttribute("style"),
|
|
1314
|
+
rect,
|
|
1315
|
+
sheet: null,
|
|
1316
|
+
visible: true,
|
|
1317
|
+
wasDestroyed: false,
|
|
1318
|
+
wasLiked: false
|
|
1319
|
+
};
|
|
1320
|
+
if (doc.head) {
|
|
1321
|
+
doc.head.appendChild(elements.style);
|
|
1322
|
+
} else {
|
|
1323
|
+
doc.body.appendChild(elements.style);
|
|
1324
|
+
}
|
|
1325
|
+
installFrame(doc, state);
|
|
1326
|
+
doc.body.appendChild(elements.root);
|
|
1327
|
+
installBridge(state);
|
|
1328
|
+
state.cleanupResize = installResizeHandler(browserWindow, state);
|
|
1329
|
+
const handle = {
|
|
1330
|
+
closeSheet: () => {
|
|
1331
|
+
state.sheet = null;
|
|
1332
|
+
renderSimulator(state);
|
|
1333
|
+
},
|
|
1334
|
+
destroy: () => {
|
|
1335
|
+
if (state.wasDestroyed) return;
|
|
1336
|
+
state.wasDestroyed = true;
|
|
1337
|
+
state.cleanupResize();
|
|
1338
|
+
state.backHandle.destroy();
|
|
1339
|
+
restoreBridge(browserWindow, state.bridgeSnapshot);
|
|
1340
|
+
delete browserWindow.__oasizAppSimulatorHandle__;
|
|
1341
|
+
elements.root.remove();
|
|
1342
|
+
elements.style.remove();
|
|
1343
|
+
restoreFrame(doc, state);
|
|
1344
|
+
},
|
|
1345
|
+
getViewportInsets: () => getSimulatorInsets(state),
|
|
1346
|
+
hide: () => {
|
|
1347
|
+
state.visible = false;
|
|
1348
|
+
renderSimulator(state);
|
|
1349
|
+
},
|
|
1350
|
+
isVisible: () => state.visible,
|
|
1351
|
+
openComments: () => {
|
|
1352
|
+
state.sheet = "comments";
|
|
1353
|
+
renderSimulator(state);
|
|
1354
|
+
},
|
|
1355
|
+
openLeaderboard: () => {
|
|
1356
|
+
state.sheet = "leaderboard";
|
|
1357
|
+
renderSimulator(state);
|
|
1358
|
+
},
|
|
1359
|
+
setCounts: (counts) => {
|
|
1360
|
+
state.counts.comments = normalizeCount(counts.comments, state.counts.comments);
|
|
1361
|
+
state.counts.likes = normalizeCount(counts.likes, state.counts.likes);
|
|
1362
|
+
renderSimulator(state);
|
|
1363
|
+
},
|
|
1364
|
+
setLeaderboardVisible: (visible) => {
|
|
1365
|
+
state.leaderboard.visible = visible;
|
|
1366
|
+
renderSimulator(state);
|
|
1367
|
+
},
|
|
1368
|
+
setLiked: (liked) => {
|
|
1369
|
+
if (state.wasLiked === liked) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
state.wasLiked = liked;
|
|
1373
|
+
state.counts.likes = Math.max(0, state.counts.likes + (liked ? 1 : -1));
|
|
1374
|
+
renderSimulator(state);
|
|
1375
|
+
},
|
|
1376
|
+
show: () => {
|
|
1377
|
+
state.visible = true;
|
|
1378
|
+
renderSimulator(state);
|
|
1379
|
+
},
|
|
1380
|
+
triggerBack: () => state.backHandle.triggerBack(),
|
|
1381
|
+
triggerLeave: () => state.backHandle.triggerLeave()
|
|
1382
|
+
};
|
|
1383
|
+
browserWindow.__oasizAppSimulatorHandle__ = handle;
|
|
1384
|
+
renderSimulator(state);
|
|
1385
|
+
return handle;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1
1388
|
// src/character.ts
|
|
2
|
-
function
|
|
1389
|
+
function isDevelopment2() {
|
|
3
1390
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
4
1391
|
return nodeEnv !== "production";
|
|
5
1392
|
}
|
|
6
|
-
function
|
|
1393
|
+
function getBridgeWindow2() {
|
|
7
1394
|
if (typeof window === "undefined") {
|
|
8
1395
|
return void 0;
|
|
9
1396
|
}
|
|
10
1397
|
return window;
|
|
11
1398
|
}
|
|
12
|
-
function
|
|
13
|
-
if (
|
|
1399
|
+
function warnMissingBridge2(methodName) {
|
|
1400
|
+
if (isDevelopment2()) {
|
|
14
1401
|
console.warn(
|
|
15
1402
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
16
1403
|
);
|
|
17
1404
|
}
|
|
18
1405
|
}
|
|
19
1406
|
async function getPlayerCharacter() {
|
|
20
|
-
const bridge =
|
|
1407
|
+
const bridge = getBridgeWindow2();
|
|
21
1408
|
if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
|
|
22
|
-
|
|
1409
|
+
warnMissingBridge2("getPlayerCharacter");
|
|
23
1410
|
return null;
|
|
24
1411
|
}
|
|
25
1412
|
try {
|
|
26
1413
|
const result = await bridge.__oasizGetPlayerCharacter();
|
|
27
1414
|
return result ?? null;
|
|
28
1415
|
} catch (error) {
|
|
29
|
-
if (
|
|
1416
|
+
if (isDevelopment2()) {
|
|
30
1417
|
console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
|
|
31
1418
|
}
|
|
32
1419
|
return null;
|
|
@@ -34,23 +1421,23 @@ async function getPlayerCharacter() {
|
|
|
34
1421
|
}
|
|
35
1422
|
|
|
36
1423
|
// src/haptics.ts
|
|
37
|
-
function
|
|
1424
|
+
function isDevelopment3() {
|
|
38
1425
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
39
1426
|
return nodeEnv !== "production";
|
|
40
1427
|
}
|
|
41
|
-
function
|
|
1428
|
+
function getBridgeWindow3() {
|
|
42
1429
|
if (typeof window === "undefined") {
|
|
43
1430
|
return void 0;
|
|
44
1431
|
}
|
|
45
1432
|
return window;
|
|
46
1433
|
}
|
|
47
1434
|
function triggerHaptic(type) {
|
|
48
|
-
const bridge =
|
|
1435
|
+
const bridge = getBridgeWindow3();
|
|
49
1436
|
if (typeof bridge?.triggerHaptic === "function") {
|
|
50
1437
|
bridge.triggerHaptic(type);
|
|
51
1438
|
return;
|
|
52
1439
|
}
|
|
53
|
-
if (
|
|
1440
|
+
if (isDevelopment3()) {
|
|
54
1441
|
console.warn(
|
|
55
1442
|
"[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
|
|
56
1443
|
);
|
|
@@ -77,7 +1464,7 @@ var MIN_EXPANDED_WIDTH = 160;
|
|
|
77
1464
|
var MIN_EXPANDED_HEIGHT = 110;
|
|
78
1465
|
var RESIZE_HOTSPOT_PX = 28;
|
|
79
1466
|
var TOP_DRAG_ZONE_PX = 44;
|
|
80
|
-
var
|
|
1467
|
+
var NOOP_HANDLE2 = {
|
|
81
1468
|
clear() {
|
|
82
1469
|
},
|
|
83
1470
|
destroy() {
|
|
@@ -90,13 +1477,13 @@ var NOOP_HANDLE = {
|
|
|
90
1477
|
show() {
|
|
91
1478
|
}
|
|
92
1479
|
};
|
|
93
|
-
function
|
|
1480
|
+
function getBrowserWindow2() {
|
|
94
1481
|
if (typeof window === "undefined") {
|
|
95
1482
|
return void 0;
|
|
96
1483
|
}
|
|
97
1484
|
return window;
|
|
98
1485
|
}
|
|
99
|
-
function
|
|
1486
|
+
function getDocument2() {
|
|
100
1487
|
if (typeof document === "undefined") {
|
|
101
1488
|
return void 0;
|
|
102
1489
|
}
|
|
@@ -182,7 +1569,7 @@ function createEntry(level, args, id) {
|
|
|
182
1569
|
timestamp: Date.now()
|
|
183
1570
|
};
|
|
184
1571
|
}
|
|
185
|
-
function
|
|
1572
|
+
function createButton2(label) {
|
|
186
1573
|
const button = document.createElement("button");
|
|
187
1574
|
button.type = "button";
|
|
188
1575
|
button.textContent = label;
|
|
@@ -224,7 +1611,7 @@ function getLevelAccent(level) {
|
|
|
224
1611
|
};
|
|
225
1612
|
}
|
|
226
1613
|
function getViewportSize() {
|
|
227
|
-
const browserWindow =
|
|
1614
|
+
const browserWindow = getBrowserWindow2();
|
|
228
1615
|
return {
|
|
229
1616
|
width: Math.max(320, browserWindow?.innerWidth ?? 1280),
|
|
230
1617
|
height: Math.max(240, browserWindow?.innerHeight ?? 720)
|
|
@@ -354,7 +1741,7 @@ function stopResizing(state) {
|
|
|
354
1741
|
state.removeResizeListeners = null;
|
|
355
1742
|
}
|
|
356
1743
|
function beginDragTracking(state, startPoint) {
|
|
357
|
-
const doc =
|
|
1744
|
+
const doc = getDocument2();
|
|
358
1745
|
if (!doc) {
|
|
359
1746
|
return;
|
|
360
1747
|
}
|
|
@@ -421,7 +1808,7 @@ function beginDragTracking(state, startPoint) {
|
|
|
421
1808
|
};
|
|
422
1809
|
}
|
|
423
1810
|
function startResizing(state, startPoint) {
|
|
424
|
-
const doc =
|
|
1811
|
+
const doc = getDocument2();
|
|
425
1812
|
if (!doc) {
|
|
426
1813
|
return;
|
|
427
1814
|
}
|
|
@@ -507,7 +1894,7 @@ function attachDragStartListeners(element, state, options = {}) {
|
|
|
507
1894
|
}
|
|
508
1895
|
function attachCollapsedToggleListeners(element, state) {
|
|
509
1896
|
const startToggleInteraction = (startPoint) => {
|
|
510
|
-
const doc =
|
|
1897
|
+
const doc = getDocument2();
|
|
511
1898
|
if (!doc) {
|
|
512
1899
|
return;
|
|
513
1900
|
}
|
|
@@ -583,7 +1970,7 @@ function createOverlayUi(state) {
|
|
|
583
1970
|
"width:min(565px, calc(100vw - 24px))",
|
|
584
1971
|
"pointer-events:none"
|
|
585
1972
|
].join(";");
|
|
586
|
-
const toggleButton =
|
|
1973
|
+
const toggleButton = createButton2("Logs");
|
|
587
1974
|
toggleButton.style.pointerEvents = "auto";
|
|
588
1975
|
toggleButton.style.alignSelf = "flex-end";
|
|
589
1976
|
toggleButton.style.display = "inline-flex";
|
|
@@ -637,7 +2024,7 @@ function createOverlayUi(state) {
|
|
|
637
2024
|
"gap:8px",
|
|
638
2025
|
"pointer-events:auto"
|
|
639
2026
|
].join(";");
|
|
640
|
-
const clearButton =
|
|
2027
|
+
const clearButton = createButton2("Clear");
|
|
641
2028
|
clearButton.style.background = "rgba(255,255,255,0.1)";
|
|
642
2029
|
clearButton.style.border = "1px solid rgba(255,255,255,0.16)";
|
|
643
2030
|
clearButton.style.color = "#eef6ff";
|
|
@@ -645,7 +2032,7 @@ function createOverlayUi(state) {
|
|
|
645
2032
|
clearButton.style.padding = "4px 9px";
|
|
646
2033
|
clearButton.style.fontSize = "11px";
|
|
647
2034
|
clearButton.style.backdropFilter = "blur(8px)";
|
|
648
|
-
const collapseButton =
|
|
2035
|
+
const collapseButton = createButton2("Hide");
|
|
649
2036
|
collapseButton.style.background = "rgba(113, 171, 255, 0.12)";
|
|
650
2037
|
collapseButton.style.border = "1px solid rgba(113, 171, 255, 0.2)";
|
|
651
2038
|
collapseButton.style.color = "#d9ebff";
|
|
@@ -771,7 +2158,7 @@ function renderOverlay(state) {
|
|
|
771
2158
|
applyOverlayPosition(state);
|
|
772
2159
|
}
|
|
773
2160
|
function mountOverlay(state) {
|
|
774
|
-
const doc =
|
|
2161
|
+
const doc = getDocument2();
|
|
775
2162
|
if (!doc?.body || state.ui) {
|
|
776
2163
|
return;
|
|
777
2164
|
}
|
|
@@ -811,7 +2198,7 @@ function cleanupOverlay(browserWindow, state) {
|
|
|
811
2198
|
stopResizing(state);
|
|
812
2199
|
stopDragging(state);
|
|
813
2200
|
if (state.domReadyHandler) {
|
|
814
|
-
|
|
2201
|
+
getDocument2()?.removeEventListener("DOMContentLoaded", state.domReadyHandler);
|
|
815
2202
|
state.domReadyHandler = void 0;
|
|
816
2203
|
}
|
|
817
2204
|
if (state.resizeHandler && typeof browserWindow.removeEventListener === "function") {
|
|
@@ -830,7 +2217,7 @@ function createController(browserWindow, state) {
|
|
|
830
2217
|
this.ensureMounted();
|
|
831
2218
|
},
|
|
832
2219
|
ensureMounted() {
|
|
833
|
-
const doc =
|
|
2220
|
+
const doc = getDocument2();
|
|
834
2221
|
if (!doc) {
|
|
835
2222
|
return;
|
|
836
2223
|
}
|
|
@@ -876,12 +2263,12 @@ function createController(browserWindow, state) {
|
|
|
876
2263
|
}
|
|
877
2264
|
function enableLogOverlay(options = {}) {
|
|
878
2265
|
if (options.enabled === false) {
|
|
879
|
-
return
|
|
2266
|
+
return NOOP_HANDLE2;
|
|
880
2267
|
}
|
|
881
|
-
const browserWindow =
|
|
882
|
-
const doc =
|
|
2268
|
+
const browserWindow = getBrowserWindow2();
|
|
2269
|
+
const doc = getDocument2();
|
|
883
2270
|
if (!browserWindow || !doc) {
|
|
884
|
-
return
|
|
2271
|
+
return NOOP_HANDLE2;
|
|
885
2272
|
}
|
|
886
2273
|
const existingController = browserWindow.__oasizLogOverlayController__;
|
|
887
2274
|
const existingState = browserWindow.__oasizLogOverlayState__;
|
|
@@ -949,74 +2336,74 @@ function enableLogOverlay(options = {}) {
|
|
|
949
2336
|
}
|
|
950
2337
|
|
|
951
2338
|
// src/multiplayer.ts
|
|
952
|
-
function
|
|
2339
|
+
function isDevelopment4() {
|
|
953
2340
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
954
2341
|
return nodeEnv !== "production";
|
|
955
2342
|
}
|
|
956
|
-
function
|
|
2343
|
+
function getBridgeWindow4() {
|
|
957
2344
|
if (typeof window === "undefined") {
|
|
958
2345
|
return void 0;
|
|
959
2346
|
}
|
|
960
2347
|
return window;
|
|
961
2348
|
}
|
|
962
2349
|
function shareRoomCode(roomCode, options) {
|
|
963
|
-
const bridge =
|
|
2350
|
+
const bridge = getBridgeWindow4();
|
|
964
2351
|
if (typeof bridge?.shareRoomCode === "function") {
|
|
965
2352
|
bridge.shareRoomCode(roomCode, options);
|
|
966
2353
|
return;
|
|
967
2354
|
}
|
|
968
|
-
if (
|
|
2355
|
+
if (isDevelopment4()) {
|
|
969
2356
|
console.warn(
|
|
970
2357
|
"[oasiz/sdk] shareRoomCode bridge is unavailable. This is expected in local development."
|
|
971
2358
|
);
|
|
972
2359
|
}
|
|
973
2360
|
}
|
|
974
2361
|
function openInviteModal() {
|
|
975
|
-
const bridge =
|
|
2362
|
+
const bridge = getBridgeWindow4();
|
|
976
2363
|
if (typeof bridge?.openInviteModal === "function") {
|
|
977
2364
|
bridge.openInviteModal();
|
|
978
2365
|
return;
|
|
979
2366
|
}
|
|
980
|
-
if (
|
|
2367
|
+
if (isDevelopment4()) {
|
|
981
2368
|
console.warn(
|
|
982
2369
|
"[oasiz/sdk] openInviteModal bridge is unavailable. This is expected in local development."
|
|
983
2370
|
);
|
|
984
2371
|
}
|
|
985
2372
|
}
|
|
986
2373
|
function getGameId() {
|
|
987
|
-
const bridge =
|
|
2374
|
+
const bridge = getBridgeWindow4();
|
|
988
2375
|
return bridge?.__GAME_ID__;
|
|
989
2376
|
}
|
|
990
2377
|
function getRoomCode() {
|
|
991
|
-
const bridge =
|
|
2378
|
+
const bridge = getBridgeWindow4();
|
|
992
2379
|
return bridge?.__ROOM_CODE__;
|
|
993
2380
|
}
|
|
994
2381
|
function getPlayerId() {
|
|
995
|
-
const bridge =
|
|
2382
|
+
const bridge = getBridgeWindow4();
|
|
996
2383
|
return bridge?.__PLAYER_ID__;
|
|
997
2384
|
}
|
|
998
2385
|
function getPlayerName() {
|
|
999
|
-
const bridge =
|
|
2386
|
+
const bridge = getBridgeWindow4();
|
|
1000
2387
|
return bridge?.__PLAYER_NAME__;
|
|
1001
2388
|
}
|
|
1002
2389
|
function getPlayerAvatar() {
|
|
1003
|
-
const bridge =
|
|
2390
|
+
const bridge = getBridgeWindow4();
|
|
1004
2391
|
return bridge?.__PLAYER_AVATAR__;
|
|
1005
2392
|
}
|
|
1006
2393
|
|
|
1007
2394
|
// src/score.ts
|
|
1008
|
-
function
|
|
2395
|
+
function isDevelopment5() {
|
|
1009
2396
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1010
2397
|
return nodeEnv !== "production";
|
|
1011
2398
|
}
|
|
1012
|
-
function
|
|
1013
|
-
if (
|
|
2399
|
+
function warnMissingBridge3(methodName) {
|
|
2400
|
+
if (isDevelopment5()) {
|
|
1014
2401
|
console.warn(
|
|
1015
2402
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1016
2403
|
);
|
|
1017
2404
|
}
|
|
1018
2405
|
}
|
|
1019
|
-
function
|
|
2406
|
+
function getBridgeWindow5() {
|
|
1020
2407
|
if (typeof window === "undefined") {
|
|
1021
2408
|
return void 0;
|
|
1022
2409
|
}
|
|
@@ -1024,49 +2411,49 @@ function getBridgeWindow4() {
|
|
|
1024
2411
|
}
|
|
1025
2412
|
function submitScore(score) {
|
|
1026
2413
|
if (!Number.isFinite(score)) {
|
|
1027
|
-
if (
|
|
2414
|
+
if (isDevelopment5()) {
|
|
1028
2415
|
console.warn("[oasiz/sdk] submitScore expected a finite number:", score);
|
|
1029
2416
|
}
|
|
1030
2417
|
return;
|
|
1031
2418
|
}
|
|
1032
|
-
const bridge =
|
|
2419
|
+
const bridge = getBridgeWindow5();
|
|
1033
2420
|
const normalizedScore = Math.max(0, Math.floor(score));
|
|
1034
2421
|
if (typeof bridge?.submitScore === "function") {
|
|
1035
2422
|
bridge.submitScore(normalizedScore);
|
|
1036
2423
|
return;
|
|
1037
2424
|
}
|
|
1038
|
-
|
|
2425
|
+
warnMissingBridge3("submitScore");
|
|
1039
2426
|
}
|
|
1040
2427
|
|
|
1041
2428
|
// src/score-edit.ts
|
|
1042
|
-
function
|
|
2429
|
+
function isDevelopment6() {
|
|
1043
2430
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1044
2431
|
return nodeEnv !== "production";
|
|
1045
2432
|
}
|
|
1046
|
-
function
|
|
2433
|
+
function getBridgeWindow6() {
|
|
1047
2434
|
if (typeof window === "undefined") {
|
|
1048
2435
|
return void 0;
|
|
1049
2436
|
}
|
|
1050
2437
|
return window;
|
|
1051
2438
|
}
|
|
1052
|
-
function
|
|
1053
|
-
if (
|
|
2439
|
+
function warnMissingBridge4(methodName) {
|
|
2440
|
+
if (isDevelopment6()) {
|
|
1054
2441
|
console.warn(
|
|
1055
2442
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1056
2443
|
);
|
|
1057
2444
|
}
|
|
1058
2445
|
}
|
|
1059
2446
|
async function editScore(payload, methodName) {
|
|
1060
|
-
const bridge =
|
|
2447
|
+
const bridge = getBridgeWindow6();
|
|
1061
2448
|
if (typeof bridge?.__oasizEditScore !== "function") {
|
|
1062
|
-
|
|
2449
|
+
warnMissingBridge4(methodName);
|
|
1063
2450
|
return null;
|
|
1064
2451
|
}
|
|
1065
2452
|
try {
|
|
1066
2453
|
const result = await bridge.__oasizEditScore(payload);
|
|
1067
2454
|
return result ?? null;
|
|
1068
2455
|
} catch (error) {
|
|
1069
|
-
if (
|
|
2456
|
+
if (isDevelopment6()) {
|
|
1070
2457
|
console.error("[oasiz/sdk] " + methodName + " failed:", error);
|
|
1071
2458
|
}
|
|
1072
2459
|
return null;
|
|
@@ -1074,7 +2461,7 @@ async function editScore(payload, methodName) {
|
|
|
1074
2461
|
}
|
|
1075
2462
|
async function addScore(delta) {
|
|
1076
2463
|
if (!Number.isInteger(delta)) {
|
|
1077
|
-
if (
|
|
2464
|
+
if (isDevelopment6()) {
|
|
1078
2465
|
console.warn("[oasiz/sdk] addScore expected an integer:", delta);
|
|
1079
2466
|
}
|
|
1080
2467
|
return null;
|
|
@@ -1086,7 +2473,7 @@ async function addScore(delta) {
|
|
|
1086
2473
|
}
|
|
1087
2474
|
async function setScore(score) {
|
|
1088
2475
|
if (!Number.isInteger(score) || score < 0) {
|
|
1089
|
-
if (
|
|
2476
|
+
if (isDevelopment6()) {
|
|
1090
2477
|
console.warn(
|
|
1091
2478
|
"[oasiz/sdk] setScore expected a non-negative integer:",
|
|
1092
2479
|
score
|
|
@@ -1098,18 +2485,18 @@ async function setScore(score) {
|
|
|
1098
2485
|
}
|
|
1099
2486
|
|
|
1100
2487
|
// src/share.ts
|
|
1101
|
-
function
|
|
2488
|
+
function isDevelopment7() {
|
|
1102
2489
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1103
2490
|
return nodeEnv !== "production";
|
|
1104
2491
|
}
|
|
1105
|
-
function
|
|
2492
|
+
function getBridgeWindow7() {
|
|
1106
2493
|
if (typeof window === "undefined") {
|
|
1107
2494
|
return void 0;
|
|
1108
2495
|
}
|
|
1109
2496
|
return window;
|
|
1110
2497
|
}
|
|
1111
|
-
function
|
|
1112
|
-
if (
|
|
2498
|
+
function warnMissingBridge5(methodName) {
|
|
2499
|
+
if (isDevelopment7()) {
|
|
1113
2500
|
console.warn(
|
|
1114
2501
|
"[oasiz/sdk] " + methodName + " share bridge is unavailable. This is expected in local development."
|
|
1115
2502
|
);
|
|
@@ -1152,20 +2539,20 @@ function validateRequest(options) {
|
|
|
1152
2539
|
}
|
|
1153
2540
|
async function share(options) {
|
|
1154
2541
|
const request = validateRequest(options);
|
|
1155
|
-
const bridge =
|
|
2542
|
+
const bridge = getBridgeWindow7();
|
|
1156
2543
|
if (typeof bridge?.__oasizShareRequest !== "function") {
|
|
1157
|
-
|
|
2544
|
+
warnMissingBridge5("__oasizShareRequest");
|
|
1158
2545
|
throw new Error("Share bridge unavailable");
|
|
1159
2546
|
}
|
|
1160
2547
|
await bridge.__oasizShareRequest(request);
|
|
1161
2548
|
}
|
|
1162
2549
|
|
|
1163
2550
|
// src/state.ts
|
|
1164
|
-
function
|
|
2551
|
+
function isDevelopment8() {
|
|
1165
2552
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1166
2553
|
return nodeEnv !== "production";
|
|
1167
2554
|
}
|
|
1168
|
-
function
|
|
2555
|
+
function getBridgeWindow8() {
|
|
1169
2556
|
if (typeof window === "undefined") {
|
|
1170
2557
|
return void 0;
|
|
1171
2558
|
}
|
|
@@ -1178,22 +2565,22 @@ function isPlainObject(value) {
|
|
|
1178
2565
|
const proto = Object.getPrototypeOf(value);
|
|
1179
2566
|
return proto === Object.prototype || proto === null;
|
|
1180
2567
|
}
|
|
1181
|
-
function
|
|
1182
|
-
if (
|
|
2568
|
+
function warnMissingBridge6(methodName) {
|
|
2569
|
+
if (isDevelopment8()) {
|
|
1183
2570
|
console.warn(
|
|
1184
2571
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1185
2572
|
);
|
|
1186
2573
|
}
|
|
1187
2574
|
}
|
|
1188
2575
|
function loadGameState() {
|
|
1189
|
-
const bridge =
|
|
2576
|
+
const bridge = getBridgeWindow8();
|
|
1190
2577
|
if (typeof bridge?.loadGameState !== "function") {
|
|
1191
|
-
|
|
2578
|
+
warnMissingBridge6("loadGameState");
|
|
1192
2579
|
return {};
|
|
1193
2580
|
}
|
|
1194
2581
|
const state = bridge.loadGameState();
|
|
1195
2582
|
if (!isPlainObject(state)) {
|
|
1196
|
-
if (
|
|
2583
|
+
if (isDevelopment8()) {
|
|
1197
2584
|
console.warn(
|
|
1198
2585
|
"[oasiz/sdk] loadGameState returned invalid data. Falling back to empty object."
|
|
1199
2586
|
);
|
|
@@ -1204,35 +2591,35 @@ function loadGameState() {
|
|
|
1204
2591
|
}
|
|
1205
2592
|
function saveGameState(state) {
|
|
1206
2593
|
if (!isPlainObject(state)) {
|
|
1207
|
-
if (
|
|
2594
|
+
if (isDevelopment8()) {
|
|
1208
2595
|
console.warn("[oasiz/sdk] saveGameState expected a plain object:", state);
|
|
1209
2596
|
}
|
|
1210
2597
|
return;
|
|
1211
2598
|
}
|
|
1212
|
-
const bridge =
|
|
2599
|
+
const bridge = getBridgeWindow8();
|
|
1213
2600
|
if (typeof bridge?.saveGameState === "function") {
|
|
1214
2601
|
bridge.saveGameState(state);
|
|
1215
2602
|
return;
|
|
1216
2603
|
}
|
|
1217
|
-
|
|
2604
|
+
warnMissingBridge6("saveGameState");
|
|
1218
2605
|
}
|
|
1219
2606
|
function flushGameState() {
|
|
1220
|
-
const bridge =
|
|
2607
|
+
const bridge = getBridgeWindow8();
|
|
1221
2608
|
if (typeof bridge?.flushGameState === "function") {
|
|
1222
2609
|
bridge.flushGameState();
|
|
1223
2610
|
return;
|
|
1224
2611
|
}
|
|
1225
|
-
|
|
2612
|
+
warnMissingBridge6("flushGameState");
|
|
1226
2613
|
}
|
|
1227
2614
|
|
|
1228
2615
|
// src/lifecycle.ts
|
|
1229
|
-
function
|
|
2616
|
+
function isDevelopment9() {
|
|
1230
2617
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1231
2618
|
return nodeEnv !== "production";
|
|
1232
2619
|
}
|
|
1233
2620
|
function addLifecycleListener(eventName, callback) {
|
|
1234
2621
|
if (typeof window === "undefined") {
|
|
1235
|
-
if (
|
|
2622
|
+
if (isDevelopment9()) {
|
|
1236
2623
|
console.warn(
|
|
1237
2624
|
"[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
|
|
1238
2625
|
);
|
|
@@ -1267,24 +2654,24 @@ function createInsetEdges(value) {
|
|
|
1267
2654
|
left: value
|
|
1268
2655
|
};
|
|
1269
2656
|
}
|
|
1270
|
-
function
|
|
2657
|
+
function isDevelopment10() {
|
|
1271
2658
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1272
2659
|
return nodeEnv !== "production";
|
|
1273
2660
|
}
|
|
1274
|
-
function
|
|
2661
|
+
function getBridgeWindow9() {
|
|
1275
2662
|
if (typeof window === "undefined") {
|
|
1276
2663
|
return void 0;
|
|
1277
2664
|
}
|
|
1278
2665
|
return window;
|
|
1279
2666
|
}
|
|
1280
|
-
function
|
|
1281
|
-
if (
|
|
2667
|
+
function warnMissingBridge7(methodName) {
|
|
2668
|
+
if (isDevelopment10()) {
|
|
1282
2669
|
console.warn(
|
|
1283
2670
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1284
2671
|
);
|
|
1285
2672
|
}
|
|
1286
2673
|
}
|
|
1287
|
-
function
|
|
2674
|
+
function isRecord2(value) {
|
|
1288
2675
|
return typeof value === "object" && value !== null;
|
|
1289
2676
|
}
|
|
1290
2677
|
function toFiniteNumber(value) {
|
|
@@ -1453,11 +2840,11 @@ function callBridgeFunction(bridge, name) {
|
|
|
1453
2840
|
}
|
|
1454
2841
|
}
|
|
1455
2842
|
function readInsetObjectValue(value, side, group) {
|
|
1456
|
-
if (!
|
|
2843
|
+
if (!isRecord2(value)) {
|
|
1457
2844
|
return void 0;
|
|
1458
2845
|
}
|
|
1459
2846
|
if (group) {
|
|
1460
|
-
return
|
|
2847
|
+
return isRecord2(value[group]) ? value[group][side] : void 0;
|
|
1461
2848
|
}
|
|
1462
2849
|
return value[side];
|
|
1463
2850
|
}
|
|
@@ -1530,7 +2917,7 @@ function resolveInsetSide(bridge, sources, side) {
|
|
|
1530
2917
|
};
|
|
1531
2918
|
}
|
|
1532
2919
|
function getViewportInsets() {
|
|
1533
|
-
const bridge =
|
|
2920
|
+
const bridge = getBridgeWindow9();
|
|
1534
2921
|
if (!bridge) {
|
|
1535
2922
|
return {
|
|
1536
2923
|
pixels: createInsetEdges(0),
|
|
@@ -1548,19 +2935,19 @@ function getViewportInsets() {
|
|
|
1548
2935
|
return { pixels, percent };
|
|
1549
2936
|
}
|
|
1550
2937
|
function getSafeAreaTop() {
|
|
1551
|
-
const bridge =
|
|
2938
|
+
const bridge = getBridgeWindow9();
|
|
1552
2939
|
if (!bridge) {
|
|
1553
2940
|
return 0;
|
|
1554
2941
|
}
|
|
1555
2942
|
const top = getViewportInsets().percent.top;
|
|
1556
2943
|
if (top <= 0) {
|
|
1557
|
-
|
|
2944
|
+
warnMissingBridge7("getSafeAreaTop");
|
|
1558
2945
|
}
|
|
1559
2946
|
return top;
|
|
1560
2947
|
}
|
|
1561
2948
|
function setLeaderboardVisible(visible) {
|
|
1562
2949
|
if (typeof visible !== "boolean") {
|
|
1563
|
-
if (
|
|
2950
|
+
if (isDevelopment10()) {
|
|
1564
2951
|
console.warn(
|
|
1565
2952
|
"[oasiz/sdk] setLeaderboardVisible expected a boolean:",
|
|
1566
2953
|
visible
|
|
@@ -1568,253 +2955,12 @@ function setLeaderboardVisible(visible) {
|
|
|
1568
2955
|
}
|
|
1569
2956
|
return;
|
|
1570
2957
|
}
|
|
1571
|
-
const bridge =
|
|
2958
|
+
const bridge = getBridgeWindow9();
|
|
1572
2959
|
if (typeof bridge?.__oasizSetLeaderboardVisible === "function") {
|
|
1573
2960
|
bridge.__oasizSetLeaderboardVisible(visible);
|
|
1574
2961
|
return;
|
|
1575
2962
|
}
|
|
1576
|
-
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
// src/navigation.ts
|
|
1580
|
-
var BACK_BUTTON_TEST_STATE_KEY = "__oasizBackButtonTest";
|
|
1581
|
-
var activeBackListeners = 0;
|
|
1582
|
-
var activeBackButtonTestingHandle;
|
|
1583
|
-
function isDevelopment10() {
|
|
1584
|
-
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1585
|
-
return nodeEnv !== "production";
|
|
1586
|
-
}
|
|
1587
|
-
function getBridgeWindow9() {
|
|
1588
|
-
if (typeof window === "undefined") {
|
|
1589
|
-
return void 0;
|
|
1590
|
-
}
|
|
1591
|
-
return window;
|
|
1592
|
-
}
|
|
1593
|
-
function warnMissingBridge7(methodName) {
|
|
1594
|
-
if (isDevelopment10()) {
|
|
1595
|
-
console.warn(
|
|
1596
|
-
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1597
|
-
);
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
function normalizeNavigationError(error) {
|
|
1601
|
-
if (error instanceof Error) {
|
|
1602
|
-
return error;
|
|
1603
|
-
}
|
|
1604
|
-
return new Error(
|
|
1605
|
-
typeof error === "string" ? error : "Back button callback failed."
|
|
1606
|
-
);
|
|
1607
|
-
}
|
|
1608
|
-
function isRecord2(value) {
|
|
1609
|
-
return typeof value === "object" && value !== null;
|
|
1610
|
-
}
|
|
1611
|
-
function dispatchNavigationEvent(eventName) {
|
|
1612
|
-
const bridge = getBridgeWindow9();
|
|
1613
|
-
if (!bridge || typeof bridge.dispatchEvent !== "function") {
|
|
1614
|
-
return;
|
|
1615
|
-
}
|
|
1616
|
-
bridge.dispatchEvent(new Event(eventName));
|
|
1617
|
-
}
|
|
1618
|
-
function addNavigationListener(eventName, callback) {
|
|
1619
|
-
if (typeof window === "undefined") {
|
|
1620
|
-
if (isDevelopment10()) {
|
|
1621
|
-
console.warn(
|
|
1622
|
-
"[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
|
|
1623
|
-
);
|
|
1624
|
-
}
|
|
1625
|
-
return () => {
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
const handler = () => callback();
|
|
1629
|
-
window.addEventListener(eventName, handler);
|
|
1630
|
-
return () => window.removeEventListener(eventName, handler);
|
|
1631
|
-
}
|
|
1632
|
-
function enableBackButtonTesting(options = {}) {
|
|
1633
|
-
activeBackButtonTestingHandle?.destroy();
|
|
1634
|
-
const bridge = getBridgeWindow9();
|
|
1635
|
-
if (!bridge) {
|
|
1636
|
-
if (isDevelopment10()) {
|
|
1637
|
-
console.warn(
|
|
1638
|
-
"[oasiz/sdk] enableBackButtonTesting requires a browser window."
|
|
1639
|
-
);
|
|
1640
|
-
}
|
|
1641
|
-
return {
|
|
1642
|
-
destroy: () => {
|
|
1643
|
-
},
|
|
1644
|
-
isBackOverrideActive: () => false,
|
|
1645
|
-
triggerBack: () => {
|
|
1646
|
-
},
|
|
1647
|
-
triggerLeave: () => {
|
|
1648
|
-
}
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
const bridgeWindow = bridge;
|
|
1652
|
-
const keyboard = options.keyboard ?? true;
|
|
1653
|
-
const browserHistory = options.browserHistory ?? true;
|
|
1654
|
-
const log = options.log === true;
|
|
1655
|
-
const previousSetBackOverride = bridgeWindow.__oasizSetBackOverride;
|
|
1656
|
-
const previousLeaveGame = bridgeWindow.__oasizLeaveGame;
|
|
1657
|
-
let destroyed = false;
|
|
1658
|
-
let backOverrideActive = false;
|
|
1659
|
-
let historyTrapArmed = false;
|
|
1660
|
-
function maybeLog(message) {
|
|
1661
|
-
if (log) {
|
|
1662
|
-
console.info("[oasiz/sdk] " + message);
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
function canUseHistoryTrap() {
|
|
1666
|
-
return browserHistory && typeof bridgeWindow.history?.pushState === "function" && typeof bridgeWindow.history?.replaceState === "function" && typeof bridgeWindow.location?.href === "string";
|
|
1667
|
-
}
|
|
1668
|
-
function ensureHistoryTrap() {
|
|
1669
|
-
if (!backOverrideActive || historyTrapArmed || !canUseHistoryTrap()) {
|
|
1670
|
-
return;
|
|
1671
|
-
}
|
|
1672
|
-
try {
|
|
1673
|
-
const currentState = isRecord2(bridgeWindow.history.state) ? bridgeWindow.history.state : {};
|
|
1674
|
-
bridgeWindow.history.replaceState(
|
|
1675
|
-
{ ...currentState, [BACK_BUTTON_TEST_STATE_KEY]: "base" },
|
|
1676
|
-
"",
|
|
1677
|
-
bridgeWindow.location.href
|
|
1678
|
-
);
|
|
1679
|
-
bridgeWindow.history.pushState(
|
|
1680
|
-
{ [BACK_BUTTON_TEST_STATE_KEY]: "trap" },
|
|
1681
|
-
"",
|
|
1682
|
-
bridgeWindow.location.href
|
|
1683
|
-
);
|
|
1684
|
-
historyTrapArmed = true;
|
|
1685
|
-
maybeLog("Local browser Back testing is armed.");
|
|
1686
|
-
} catch (error) {
|
|
1687
|
-
historyTrapArmed = false;
|
|
1688
|
-
if (log) {
|
|
1689
|
-
console.warn("[oasiz/sdk] Failed to arm browser Back testing:", error);
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
function triggerBack() {
|
|
1694
|
-
dispatchNavigationEvent("oasiz:back");
|
|
1695
|
-
}
|
|
1696
|
-
function triggerLeave() {
|
|
1697
|
-
dispatchNavigationEvent("oasiz:leave");
|
|
1698
|
-
}
|
|
1699
|
-
function setBackOverride(active) {
|
|
1700
|
-
backOverrideActive = active;
|
|
1701
|
-
if (active) {
|
|
1702
|
-
ensureHistoryTrap();
|
|
1703
|
-
}
|
|
1704
|
-
if (typeof previousSetBackOverride === "function") {
|
|
1705
|
-
previousSetBackOverride(active);
|
|
1706
|
-
}
|
|
1707
|
-
maybeLog("Back override " + (active ? "enabled" : "disabled") + ".");
|
|
1708
|
-
}
|
|
1709
|
-
function stopBackEvent(event) {
|
|
1710
|
-
event.preventDefault();
|
|
1711
|
-
event.stopPropagation();
|
|
1712
|
-
event.stopImmediatePropagation?.();
|
|
1713
|
-
}
|
|
1714
|
-
const handleKeyDown = (event) => {
|
|
1715
|
-
if (!backOverrideActive || event.key !== "Escape") {
|
|
1716
|
-
return;
|
|
1717
|
-
}
|
|
1718
|
-
stopBackEvent(event);
|
|
1719
|
-
triggerBack();
|
|
1720
|
-
};
|
|
1721
|
-
const handlePopState = (event) => {
|
|
1722
|
-
if (!backOverrideActive) {
|
|
1723
|
-
historyTrapArmed = false;
|
|
1724
|
-
return;
|
|
1725
|
-
}
|
|
1726
|
-
stopBackEvent(event);
|
|
1727
|
-
triggerBack();
|
|
1728
|
-
historyTrapArmed = false;
|
|
1729
|
-
ensureHistoryTrap();
|
|
1730
|
-
};
|
|
1731
|
-
const testLeaveGame = () => {
|
|
1732
|
-
triggerLeave();
|
|
1733
|
-
if (typeof previousLeaveGame === "function") {
|
|
1734
|
-
previousLeaveGame();
|
|
1735
|
-
}
|
|
1736
|
-
};
|
|
1737
|
-
bridgeWindow.__oasizSetBackOverride = setBackOverride;
|
|
1738
|
-
bridgeWindow.__oasizLeaveGame = testLeaveGame;
|
|
1739
|
-
if (keyboard) {
|
|
1740
|
-
bridgeWindow.addEventListener("keydown", handleKeyDown);
|
|
1741
|
-
}
|
|
1742
|
-
if (browserHistory) {
|
|
1743
|
-
bridgeWindow.addEventListener("popstate", handlePopState);
|
|
1744
|
-
}
|
|
1745
|
-
if (activeBackListeners > 0) {
|
|
1746
|
-
setBackOverride(true);
|
|
1747
|
-
}
|
|
1748
|
-
maybeLog("Back button testing bridge installed.");
|
|
1749
|
-
const handle = {
|
|
1750
|
-
destroy: () => {
|
|
1751
|
-
if (destroyed) return;
|
|
1752
|
-
destroyed = true;
|
|
1753
|
-
if (keyboard) {
|
|
1754
|
-
bridgeWindow.removeEventListener("keydown", handleKeyDown);
|
|
1755
|
-
}
|
|
1756
|
-
if (browserHistory) {
|
|
1757
|
-
bridgeWindow.removeEventListener("popstate", handlePopState);
|
|
1758
|
-
}
|
|
1759
|
-
if (bridgeWindow.__oasizSetBackOverride === setBackOverride) {
|
|
1760
|
-
bridgeWindow.__oasizSetBackOverride = previousSetBackOverride;
|
|
1761
|
-
}
|
|
1762
|
-
if (bridgeWindow.__oasizLeaveGame === testLeaveGame) {
|
|
1763
|
-
bridgeWindow.__oasizLeaveGame = previousLeaveGame;
|
|
1764
|
-
}
|
|
1765
|
-
if (activeBackButtonTestingHandle === handle) {
|
|
1766
|
-
activeBackButtonTestingHandle = void 0;
|
|
1767
|
-
}
|
|
1768
|
-
maybeLog("Back button testing bridge removed.");
|
|
1769
|
-
},
|
|
1770
|
-
isBackOverrideActive: () => backOverrideActive,
|
|
1771
|
-
triggerBack,
|
|
1772
|
-
triggerLeave
|
|
1773
|
-
};
|
|
1774
|
-
activeBackButtonTestingHandle = handle;
|
|
1775
|
-
return handle;
|
|
1776
|
-
}
|
|
1777
|
-
function onBackButton(callback) {
|
|
1778
|
-
const off = addNavigationListener("oasiz:back", () => {
|
|
1779
|
-
try {
|
|
1780
|
-
callback();
|
|
1781
|
-
} catch (error) {
|
|
1782
|
-
leaveGame();
|
|
1783
|
-
throw normalizeNavigationError(error);
|
|
1784
|
-
}
|
|
1785
|
-
});
|
|
1786
|
-
const bridge = getBridgeWindow9();
|
|
1787
|
-
activeBackListeners += 1;
|
|
1788
|
-
if (activeBackListeners === 1) {
|
|
1789
|
-
if (typeof bridge?.__oasizSetBackOverride === "function") {
|
|
1790
|
-
bridge.__oasizSetBackOverride(true);
|
|
1791
|
-
} else {
|
|
1792
|
-
warnMissingBridge7("__oasizSetBackOverride");
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
return () => {
|
|
1796
|
-
off();
|
|
1797
|
-
activeBackListeners = Math.max(0, activeBackListeners - 1);
|
|
1798
|
-
if (activeBackListeners === 0) {
|
|
1799
|
-
const currentBridge = getBridgeWindow9();
|
|
1800
|
-
if (typeof currentBridge?.__oasizSetBackOverride === "function") {
|
|
1801
|
-
currentBridge.__oasizSetBackOverride(false);
|
|
1802
|
-
} else {
|
|
1803
|
-
warnMissingBridge7("__oasizSetBackOverride");
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
};
|
|
1807
|
-
}
|
|
1808
|
-
function onLeaveGame(callback) {
|
|
1809
|
-
return addNavigationListener("oasiz:leave", callback);
|
|
1810
|
-
}
|
|
1811
|
-
function leaveGame() {
|
|
1812
|
-
const bridge = getBridgeWindow9();
|
|
1813
|
-
if (typeof bridge?.__oasizLeaveGame === "function") {
|
|
1814
|
-
bridge.__oasizLeaveGame();
|
|
1815
|
-
return;
|
|
1816
|
-
}
|
|
1817
|
-
warnMissingBridge7("__oasizLeaveGame");
|
|
2963
|
+
warnMissingBridge7("__oasizSetLeaderboardVisible");
|
|
1818
2964
|
}
|
|
1819
2965
|
|
|
1820
2966
|
// src/performance.ts
|
|
@@ -2143,6 +3289,7 @@ function getGraphicsPerformance() {
|
|
|
2143
3289
|
// src/index.ts
|
|
2144
3290
|
var oasiz = {
|
|
2145
3291
|
submitScore,
|
|
3292
|
+
enableAppSimulator,
|
|
2146
3293
|
addScore,
|
|
2147
3294
|
setScore,
|
|
2148
3295
|
getPlayerCharacter,
|
|
@@ -2191,6 +3338,7 @@ var oasiz = {
|
|
|
2191
3338
|
};
|
|
2192
3339
|
export {
|
|
2193
3340
|
addScore,
|
|
3341
|
+
enableAppSimulator,
|
|
2194
3342
|
enableBackButtonTesting,
|
|
2195
3343
|
enableLogOverlay,
|
|
2196
3344
|
flushGameState,
|