@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.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
addScore: () => addScore,
|
|
24
|
+
enableAppSimulator: () => enableAppSimulator,
|
|
24
25
|
enableBackButtonTesting: () => enableBackButtonTesting,
|
|
25
26
|
enableLogOverlay: () => enableLogOverlay,
|
|
26
27
|
flushGameState: () => flushGameState,
|
|
@@ -51,35 +52,1422 @@ __export(index_exports, {
|
|
|
51
52
|
});
|
|
52
53
|
module.exports = __toCommonJS(index_exports);
|
|
53
54
|
|
|
55
|
+
// src/navigation.ts
|
|
56
|
+
var BACK_BUTTON_TEST_STATE_KEY = "__oasizBackButtonTest";
|
|
57
|
+
var activeBackListeners = 0;
|
|
58
|
+
var activeBackButtonTestingHandle;
|
|
59
|
+
function isDevelopment() {
|
|
60
|
+
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
61
|
+
return nodeEnv !== "production";
|
|
62
|
+
}
|
|
63
|
+
function getBridgeWindow() {
|
|
64
|
+
if (typeof window === "undefined") {
|
|
65
|
+
return void 0;
|
|
66
|
+
}
|
|
67
|
+
return window;
|
|
68
|
+
}
|
|
69
|
+
function warnMissingBridge(methodName) {
|
|
70
|
+
if (isDevelopment()) {
|
|
71
|
+
console.warn(
|
|
72
|
+
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function normalizeNavigationError(error) {
|
|
77
|
+
if (error instanceof Error) {
|
|
78
|
+
return error;
|
|
79
|
+
}
|
|
80
|
+
return new Error(
|
|
81
|
+
typeof error === "string" ? error : "Back button callback failed."
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function isRecord(value) {
|
|
85
|
+
return typeof value === "object" && value !== null;
|
|
86
|
+
}
|
|
87
|
+
function dispatchNavigationEvent(eventName) {
|
|
88
|
+
const bridge = getBridgeWindow();
|
|
89
|
+
if (!bridge || typeof bridge.dispatchEvent !== "function") {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
bridge.dispatchEvent(new Event(eventName));
|
|
93
|
+
}
|
|
94
|
+
function addNavigationListener(eventName, callback) {
|
|
95
|
+
if (typeof window === "undefined") {
|
|
96
|
+
if (isDevelopment()) {
|
|
97
|
+
console.warn(
|
|
98
|
+
"[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return () => {
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const handler = () => callback();
|
|
105
|
+
window.addEventListener(eventName, handler);
|
|
106
|
+
return () => window.removeEventListener(eventName, handler);
|
|
107
|
+
}
|
|
108
|
+
function enableBackButtonTesting(options = {}) {
|
|
109
|
+
activeBackButtonTestingHandle?.destroy();
|
|
110
|
+
const bridge = getBridgeWindow();
|
|
111
|
+
if (!bridge) {
|
|
112
|
+
if (isDevelopment()) {
|
|
113
|
+
console.warn(
|
|
114
|
+
"[oasiz/sdk] enableBackButtonTesting requires a browser window."
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
destroy: () => {
|
|
119
|
+
},
|
|
120
|
+
isBackOverrideActive: () => false,
|
|
121
|
+
triggerBack: () => {
|
|
122
|
+
},
|
|
123
|
+
triggerLeave: () => {
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const bridgeWindow = bridge;
|
|
128
|
+
const keyboard = options.keyboard ?? true;
|
|
129
|
+
const browserHistory = options.browserHistory ?? true;
|
|
130
|
+
const log = options.log === true;
|
|
131
|
+
const previousSetBackOverride = bridgeWindow.__oasizSetBackOverride;
|
|
132
|
+
const previousLeaveGame = bridgeWindow.__oasizLeaveGame;
|
|
133
|
+
let destroyed = false;
|
|
134
|
+
let backOverrideActive = false;
|
|
135
|
+
let historyTrapArmed = false;
|
|
136
|
+
function maybeLog(message) {
|
|
137
|
+
if (log) {
|
|
138
|
+
console.info("[oasiz/sdk] " + message);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function canUseHistoryTrap() {
|
|
142
|
+
return browserHistory && typeof bridgeWindow.history?.pushState === "function" && typeof bridgeWindow.history?.replaceState === "function" && typeof bridgeWindow.location?.href === "string";
|
|
143
|
+
}
|
|
144
|
+
function ensureHistoryTrap() {
|
|
145
|
+
if (!backOverrideActive || historyTrapArmed || !canUseHistoryTrap()) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const currentState = isRecord(bridgeWindow.history.state) ? bridgeWindow.history.state : {};
|
|
150
|
+
bridgeWindow.history.replaceState(
|
|
151
|
+
{ ...currentState, [BACK_BUTTON_TEST_STATE_KEY]: "base" },
|
|
152
|
+
"",
|
|
153
|
+
bridgeWindow.location.href
|
|
154
|
+
);
|
|
155
|
+
bridgeWindow.history.pushState(
|
|
156
|
+
{ [BACK_BUTTON_TEST_STATE_KEY]: "trap" },
|
|
157
|
+
"",
|
|
158
|
+
bridgeWindow.location.href
|
|
159
|
+
);
|
|
160
|
+
historyTrapArmed = true;
|
|
161
|
+
maybeLog("Local browser Back testing is armed.");
|
|
162
|
+
} catch (error) {
|
|
163
|
+
historyTrapArmed = false;
|
|
164
|
+
if (log) {
|
|
165
|
+
console.warn("[oasiz/sdk] Failed to arm browser Back testing:", error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function triggerBack() {
|
|
170
|
+
dispatchNavigationEvent("oasiz:back");
|
|
171
|
+
}
|
|
172
|
+
function triggerLeave() {
|
|
173
|
+
dispatchNavigationEvent("oasiz:leave");
|
|
174
|
+
}
|
|
175
|
+
function setBackOverride(active) {
|
|
176
|
+
backOverrideActive = active;
|
|
177
|
+
if (active) {
|
|
178
|
+
ensureHistoryTrap();
|
|
179
|
+
}
|
|
180
|
+
if (typeof previousSetBackOverride === "function") {
|
|
181
|
+
previousSetBackOverride(active);
|
|
182
|
+
}
|
|
183
|
+
maybeLog("Back override " + (active ? "enabled" : "disabled") + ".");
|
|
184
|
+
}
|
|
185
|
+
function stopBackEvent(event) {
|
|
186
|
+
event.preventDefault();
|
|
187
|
+
event.stopPropagation();
|
|
188
|
+
event.stopImmediatePropagation?.();
|
|
189
|
+
}
|
|
190
|
+
const handleKeyDown = (event) => {
|
|
191
|
+
if (!backOverrideActive || event.key !== "Escape") {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
stopBackEvent(event);
|
|
195
|
+
triggerBack();
|
|
196
|
+
};
|
|
197
|
+
const handlePopState = (event) => {
|
|
198
|
+
if (!backOverrideActive) {
|
|
199
|
+
historyTrapArmed = false;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
stopBackEvent(event);
|
|
203
|
+
triggerBack();
|
|
204
|
+
historyTrapArmed = false;
|
|
205
|
+
ensureHistoryTrap();
|
|
206
|
+
};
|
|
207
|
+
const testLeaveGame = () => {
|
|
208
|
+
triggerLeave();
|
|
209
|
+
if (typeof previousLeaveGame === "function") {
|
|
210
|
+
previousLeaveGame();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
bridgeWindow.__oasizSetBackOverride = setBackOverride;
|
|
214
|
+
bridgeWindow.__oasizLeaveGame = testLeaveGame;
|
|
215
|
+
if (keyboard) {
|
|
216
|
+
bridgeWindow.addEventListener("keydown", handleKeyDown);
|
|
217
|
+
}
|
|
218
|
+
if (browserHistory) {
|
|
219
|
+
bridgeWindow.addEventListener("popstate", handlePopState);
|
|
220
|
+
}
|
|
221
|
+
if (activeBackListeners > 0) {
|
|
222
|
+
setBackOverride(true);
|
|
223
|
+
}
|
|
224
|
+
maybeLog("Back button testing bridge installed.");
|
|
225
|
+
const handle = {
|
|
226
|
+
destroy: () => {
|
|
227
|
+
if (destroyed) return;
|
|
228
|
+
destroyed = true;
|
|
229
|
+
if (keyboard) {
|
|
230
|
+
bridgeWindow.removeEventListener("keydown", handleKeyDown);
|
|
231
|
+
}
|
|
232
|
+
if (browserHistory) {
|
|
233
|
+
bridgeWindow.removeEventListener("popstate", handlePopState);
|
|
234
|
+
}
|
|
235
|
+
if (bridgeWindow.__oasizSetBackOverride === setBackOverride) {
|
|
236
|
+
bridgeWindow.__oasizSetBackOverride = previousSetBackOverride;
|
|
237
|
+
}
|
|
238
|
+
if (bridgeWindow.__oasizLeaveGame === testLeaveGame) {
|
|
239
|
+
bridgeWindow.__oasizLeaveGame = previousLeaveGame;
|
|
240
|
+
}
|
|
241
|
+
if (activeBackButtonTestingHandle === handle) {
|
|
242
|
+
activeBackButtonTestingHandle = void 0;
|
|
243
|
+
}
|
|
244
|
+
maybeLog("Back button testing bridge removed.");
|
|
245
|
+
},
|
|
246
|
+
isBackOverrideActive: () => backOverrideActive,
|
|
247
|
+
triggerBack,
|
|
248
|
+
triggerLeave
|
|
249
|
+
};
|
|
250
|
+
activeBackButtonTestingHandle = handle;
|
|
251
|
+
return handle;
|
|
252
|
+
}
|
|
253
|
+
function onBackButton(callback) {
|
|
254
|
+
const off = addNavigationListener("oasiz:back", () => {
|
|
255
|
+
try {
|
|
256
|
+
callback();
|
|
257
|
+
} catch (error) {
|
|
258
|
+
leaveGame();
|
|
259
|
+
throw normalizeNavigationError(error);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const bridge = getBridgeWindow();
|
|
263
|
+
activeBackListeners += 1;
|
|
264
|
+
if (activeBackListeners === 1) {
|
|
265
|
+
if (typeof bridge?.__oasizSetBackOverride === "function") {
|
|
266
|
+
bridge.__oasizSetBackOverride(true);
|
|
267
|
+
} else {
|
|
268
|
+
warnMissingBridge("__oasizSetBackOverride");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return () => {
|
|
272
|
+
off();
|
|
273
|
+
activeBackListeners = Math.max(0, activeBackListeners - 1);
|
|
274
|
+
if (activeBackListeners === 0) {
|
|
275
|
+
const currentBridge = getBridgeWindow();
|
|
276
|
+
if (typeof currentBridge?.__oasizSetBackOverride === "function") {
|
|
277
|
+
currentBridge.__oasizSetBackOverride(false);
|
|
278
|
+
} else {
|
|
279
|
+
warnMissingBridge("__oasizSetBackOverride");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function onLeaveGame(callback) {
|
|
285
|
+
return addNavigationListener("oasiz:leave", callback);
|
|
286
|
+
}
|
|
287
|
+
function leaveGame() {
|
|
288
|
+
const bridge = getBridgeWindow();
|
|
289
|
+
if (typeof bridge?.__oasizLeaveGame === "function") {
|
|
290
|
+
bridge.__oasizLeaveGame();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
warnMissingBridge("__oasizLeaveGame");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/app-simulator.ts
|
|
297
|
+
var DEVICE_PRESETS = {
|
|
298
|
+
"iphone-11": {
|
|
299
|
+
name: "iPhone 11",
|
|
300
|
+
width: 414,
|
|
301
|
+
height: 896,
|
|
302
|
+
safeArea: { top: 48, right: 0, bottom: 34, left: 0 }
|
|
303
|
+
},
|
|
304
|
+
"iphone-11-pro": {
|
|
305
|
+
name: "iPhone 11 Pro",
|
|
306
|
+
width: 375,
|
|
307
|
+
height: 812,
|
|
308
|
+
safeArea: { top: 44, right: 0, bottom: 34, left: 0 }
|
|
309
|
+
},
|
|
310
|
+
"iphone-11-pro-max": {
|
|
311
|
+
name: "iPhone 11 Pro Max",
|
|
312
|
+
width: 414,
|
|
313
|
+
height: 896,
|
|
314
|
+
safeArea: { top: 44, right: 0, bottom: 34, left: 0 }
|
|
315
|
+
},
|
|
316
|
+
"iphone-12-mini": {
|
|
317
|
+
name: "iPhone 12 mini",
|
|
318
|
+
width: 375,
|
|
319
|
+
height: 812,
|
|
320
|
+
safeArea: { top: 50, right: 0, bottom: 34, left: 0 }
|
|
321
|
+
},
|
|
322
|
+
"iphone-12": {
|
|
323
|
+
name: "iPhone 12",
|
|
324
|
+
width: 390,
|
|
325
|
+
height: 844,
|
|
326
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
327
|
+
},
|
|
328
|
+
"iphone-12-pro": {
|
|
329
|
+
name: "iPhone 12 Pro",
|
|
330
|
+
width: 390,
|
|
331
|
+
height: 844,
|
|
332
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
333
|
+
},
|
|
334
|
+
"iphone-12-pro-max": {
|
|
335
|
+
name: "iPhone 12 Pro Max",
|
|
336
|
+
width: 428,
|
|
337
|
+
height: 926,
|
|
338
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
339
|
+
},
|
|
340
|
+
"iphone-13-mini": {
|
|
341
|
+
name: "iPhone 13 mini",
|
|
342
|
+
width: 375,
|
|
343
|
+
height: 812,
|
|
344
|
+
safeArea: { top: 50, right: 0, bottom: 34, left: 0 }
|
|
345
|
+
},
|
|
346
|
+
"iphone-13": {
|
|
347
|
+
name: "iPhone 13",
|
|
348
|
+
width: 390,
|
|
349
|
+
height: 844,
|
|
350
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
351
|
+
},
|
|
352
|
+
"iphone-13-pro": {
|
|
353
|
+
name: "iPhone 13 Pro",
|
|
354
|
+
width: 390,
|
|
355
|
+
height: 844,
|
|
356
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
357
|
+
},
|
|
358
|
+
"iphone-13-pro-max": {
|
|
359
|
+
name: "iPhone 13 Pro Max",
|
|
360
|
+
width: 428,
|
|
361
|
+
height: 926,
|
|
362
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
363
|
+
},
|
|
364
|
+
"iphone-14": {
|
|
365
|
+
name: "iPhone 14",
|
|
366
|
+
width: 390,
|
|
367
|
+
height: 844,
|
|
368
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
369
|
+
},
|
|
370
|
+
"iphone-14-plus": {
|
|
371
|
+
name: "iPhone 14 Plus",
|
|
372
|
+
width: 428,
|
|
373
|
+
height: 926,
|
|
374
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
375
|
+
},
|
|
376
|
+
"iphone-14-pro": {
|
|
377
|
+
name: "iPhone 14 Pro",
|
|
378
|
+
width: 393,
|
|
379
|
+
height: 852,
|
|
380
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
381
|
+
},
|
|
382
|
+
"iphone-14-pro-max": {
|
|
383
|
+
name: "iPhone 14 Pro Max",
|
|
384
|
+
width: 430,
|
|
385
|
+
height: 932,
|
|
386
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
387
|
+
},
|
|
388
|
+
"iphone-15": {
|
|
389
|
+
name: "iPhone 15",
|
|
390
|
+
width: 393,
|
|
391
|
+
height: 852,
|
|
392
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
393
|
+
},
|
|
394
|
+
"iphone-15-plus": {
|
|
395
|
+
name: "iPhone 15 Plus",
|
|
396
|
+
width: 430,
|
|
397
|
+
height: 932,
|
|
398
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
399
|
+
},
|
|
400
|
+
"iphone-15-pro": {
|
|
401
|
+
name: "iPhone 15 Pro",
|
|
402
|
+
width: 393,
|
|
403
|
+
height: 852,
|
|
404
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
405
|
+
},
|
|
406
|
+
"iphone-15-pro-max": {
|
|
407
|
+
name: "iPhone 15 Pro Max",
|
|
408
|
+
width: 430,
|
|
409
|
+
height: 932,
|
|
410
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
411
|
+
},
|
|
412
|
+
"iphone-16": {
|
|
413
|
+
name: "iPhone 16",
|
|
414
|
+
width: 393,
|
|
415
|
+
height: 852,
|
|
416
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
417
|
+
},
|
|
418
|
+
"iphone-16-plus": {
|
|
419
|
+
name: "iPhone 16 Plus",
|
|
420
|
+
width: 430,
|
|
421
|
+
height: 932,
|
|
422
|
+
safeArea: { top: 59, right: 0, bottom: 34, left: 0 }
|
|
423
|
+
},
|
|
424
|
+
"iphone-16-pro": {
|
|
425
|
+
name: "iPhone 16 Pro",
|
|
426
|
+
width: 402,
|
|
427
|
+
height: 874,
|
|
428
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
429
|
+
},
|
|
430
|
+
"iphone-16-pro-max": {
|
|
431
|
+
name: "iPhone 16 Pro Max",
|
|
432
|
+
width: 440,
|
|
433
|
+
height: 956,
|
|
434
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
435
|
+
},
|
|
436
|
+
"iphone-16e": {
|
|
437
|
+
name: "iPhone 16e",
|
|
438
|
+
width: 390,
|
|
439
|
+
height: 844,
|
|
440
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
441
|
+
},
|
|
442
|
+
"iphone-17": {
|
|
443
|
+
name: "iPhone 17",
|
|
444
|
+
width: 402,
|
|
445
|
+
height: 874,
|
|
446
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
447
|
+
},
|
|
448
|
+
"iphone-17-pro": {
|
|
449
|
+
name: "iPhone 17 Pro",
|
|
450
|
+
width: 402,
|
|
451
|
+
height: 874,
|
|
452
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
453
|
+
},
|
|
454
|
+
"iphone-17-pro-max": {
|
|
455
|
+
name: "iPhone 17 Pro Max",
|
|
456
|
+
width: 440,
|
|
457
|
+
height: 956,
|
|
458
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
459
|
+
},
|
|
460
|
+
"iphone-17e": {
|
|
461
|
+
name: "iPhone 17e",
|
|
462
|
+
width: 390,
|
|
463
|
+
height: 844,
|
|
464
|
+
safeArea: { top: 47, right: 0, bottom: 34, left: 0 }
|
|
465
|
+
},
|
|
466
|
+
"iphone-air": {
|
|
467
|
+
name: "iPhone Air",
|
|
468
|
+
width: 420,
|
|
469
|
+
height: 912,
|
|
470
|
+
safeArea: { top: 62, right: 0, bottom: 34, left: 0 }
|
|
471
|
+
},
|
|
472
|
+
"iphone-se": {
|
|
473
|
+
name: "iPhone SE",
|
|
474
|
+
width: 375,
|
|
475
|
+
height: 667,
|
|
476
|
+
safeArea: { top: 20, right: 0, bottom: 0, left: 0 }
|
|
477
|
+
},
|
|
478
|
+
"pixel-8": {
|
|
479
|
+
name: "Pixel 8",
|
|
480
|
+
width: 412,
|
|
481
|
+
height: 915,
|
|
482
|
+
safeArea: { top: 32, right: 0, bottom: 24, left: 0 }
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
var DEFAULT_COUNTS = {
|
|
486
|
+
comments: 18,
|
|
487
|
+
likes: 128
|
|
488
|
+
};
|
|
489
|
+
var DEFAULT_SCORE = 12400;
|
|
490
|
+
var TOP_BAR_OFFSET = 12;
|
|
491
|
+
var TOP_CHROME_HEIGHT = 44;
|
|
492
|
+
var BODY_BACKGROUND = "#08090d";
|
|
493
|
+
var TEXT_PRIMARY = "#F6F9FB";
|
|
494
|
+
var TEXT_SECONDARY = "rgba(246,249,251,0.72)";
|
|
495
|
+
var TEXT_MUTED = "rgba(246,249,251,0.52)";
|
|
496
|
+
var BORDER = "rgba(255,255,255,0.14)";
|
|
497
|
+
var ACCENT = "#00A1E4";
|
|
498
|
+
var LIKE = "#ef4444";
|
|
499
|
+
var TROPHY = "#FBBF24";
|
|
500
|
+
var MAX_Z_INDEX = 2147483638;
|
|
501
|
+
var EMPTY_INSETS = {
|
|
502
|
+
top: 0,
|
|
503
|
+
right: 0,
|
|
504
|
+
bottom: 0,
|
|
505
|
+
left: 0
|
|
506
|
+
};
|
|
507
|
+
var BRIDGE_KEYS = [
|
|
508
|
+
"__OASIZ_SAFE_AREA_BOTTOM__",
|
|
509
|
+
"__OASIZ_SAFE_AREA_BOTTOM_PERCENT__",
|
|
510
|
+
"__OASIZ_SAFE_AREA_LEFT__",
|
|
511
|
+
"__OASIZ_SAFE_AREA_LEFT_PERCENT__",
|
|
512
|
+
"__OASIZ_SAFE_AREA_RIGHT__",
|
|
513
|
+
"__OASIZ_SAFE_AREA_RIGHT_PERCENT__",
|
|
514
|
+
"__OASIZ_SAFE_AREA_TOP__",
|
|
515
|
+
"__OASIZ_SAFE_AREA_TOP_PERCENT__",
|
|
516
|
+
"__OASIZ_VIEWPORT_INSETS__",
|
|
517
|
+
"__OASIZ_VIEWPORT_INSETS_PERCENT__",
|
|
518
|
+
"__oasizSetLeaderboardVisible",
|
|
519
|
+
"getSafeAreaBottom",
|
|
520
|
+
"getSafeAreaBottomPercent",
|
|
521
|
+
"getSafeAreaLeft",
|
|
522
|
+
"getSafeAreaLeftPercent",
|
|
523
|
+
"getSafeAreaRight",
|
|
524
|
+
"getSafeAreaRightPercent",
|
|
525
|
+
"getSafeAreaTop",
|
|
526
|
+
"getSafeAreaTopPercent",
|
|
527
|
+
"getViewportInsets",
|
|
528
|
+
"getViewportInsetsPercent"
|
|
529
|
+
];
|
|
530
|
+
var NOOP_HANDLE = {
|
|
531
|
+
closeSheet() {
|
|
532
|
+
},
|
|
533
|
+
destroy() {
|
|
534
|
+
},
|
|
535
|
+
getViewportInsets() {
|
|
536
|
+
return { pixels: { ...EMPTY_INSETS }, percent: { ...EMPTY_INSETS } };
|
|
537
|
+
},
|
|
538
|
+
hide() {
|
|
539
|
+
},
|
|
540
|
+
isVisible() {
|
|
541
|
+
return false;
|
|
542
|
+
},
|
|
543
|
+
openComments() {
|
|
544
|
+
},
|
|
545
|
+
openLeaderboard() {
|
|
546
|
+
},
|
|
547
|
+
setCounts() {
|
|
548
|
+
},
|
|
549
|
+
setLeaderboardVisible() {
|
|
550
|
+
},
|
|
551
|
+
setLiked() {
|
|
552
|
+
},
|
|
553
|
+
show() {
|
|
554
|
+
},
|
|
555
|
+
triggerBack() {
|
|
556
|
+
},
|
|
557
|
+
triggerLeave() {
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
function getBrowserWindow() {
|
|
561
|
+
if (typeof window === "undefined") {
|
|
562
|
+
return void 0;
|
|
563
|
+
}
|
|
564
|
+
return window;
|
|
565
|
+
}
|
|
566
|
+
function getDocument() {
|
|
567
|
+
if (typeof document === "undefined") {
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
return document;
|
|
571
|
+
}
|
|
572
|
+
function warn(message) {
|
|
573
|
+
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
574
|
+
if (nodeEnv !== "production") {
|
|
575
|
+
console.warn("[oasiz/sdk] " + message);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function normalizeCount(value, fallback) {
|
|
579
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
580
|
+
return fallback;
|
|
581
|
+
}
|
|
582
|
+
return Math.max(0, Math.floor(value));
|
|
583
|
+
}
|
|
584
|
+
function formatCompactCount(value) {
|
|
585
|
+
if (value >= 1e6) {
|
|
586
|
+
return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
|
|
587
|
+
}
|
|
588
|
+
if (value >= 1e3) {
|
|
589
|
+
return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "k";
|
|
590
|
+
}
|
|
591
|
+
return String(value);
|
|
592
|
+
}
|
|
593
|
+
function resolveDevice(device, orientation) {
|
|
594
|
+
const preset = typeof device === "string" ? DEVICE_PRESETS[device] : device ? {
|
|
595
|
+
name: device.name ?? "Custom phone",
|
|
596
|
+
width: device.width,
|
|
597
|
+
height: device.height,
|
|
598
|
+
safeArea: {
|
|
599
|
+
...EMPTY_INSETS,
|
|
600
|
+
...device.safeArea
|
|
601
|
+
}
|
|
602
|
+
} : DEVICE_PRESETS["iphone-17-pro-max"];
|
|
603
|
+
const normalized = {
|
|
604
|
+
name: preset.name,
|
|
605
|
+
width: Math.max(320, Math.floor(preset.width)),
|
|
606
|
+
height: Math.max(480, Math.floor(preset.height)),
|
|
607
|
+
safeArea: {
|
|
608
|
+
...EMPTY_INSETS,
|
|
609
|
+
...preset.safeArea
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
if (orientation === "landscape") {
|
|
613
|
+
return {
|
|
614
|
+
...normalized,
|
|
615
|
+
width: Math.max(normalized.width, normalized.height),
|
|
616
|
+
height: Math.min(normalized.width, normalized.height),
|
|
617
|
+
safeArea: {
|
|
618
|
+
top: 0,
|
|
619
|
+
right: normalized.safeArea.top,
|
|
620
|
+
bottom: 21,
|
|
621
|
+
left: normalized.safeArea.top
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
return normalized;
|
|
626
|
+
}
|
|
627
|
+
function shouldFrame(frame, browserWindow, device) {
|
|
628
|
+
if (frame === true) {
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
if (frame === false) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
return browserWindow.innerWidth > device.width + 80 || browserWindow.innerHeight > device.height + 80;
|
|
635
|
+
}
|
|
636
|
+
function computeRect(browserWindow, device, frameEnabled) {
|
|
637
|
+
const viewportWidth = Math.max(320, browserWindow.innerWidth || device.width);
|
|
638
|
+
const viewportHeight = Math.max(480, browserWindow.innerHeight || device.height);
|
|
639
|
+
if (!frameEnabled) {
|
|
640
|
+
return {
|
|
641
|
+
left: 0,
|
|
642
|
+
top: 0,
|
|
643
|
+
width: viewportWidth,
|
|
644
|
+
height: viewportHeight,
|
|
645
|
+
scale: Math.min(viewportWidth / device.width, viewportHeight / device.height)
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
const margin = 24;
|
|
649
|
+
const scale = Math.min(
|
|
650
|
+
(viewportWidth - margin) / device.width,
|
|
651
|
+
(viewportHeight - margin) / device.height,
|
|
652
|
+
1
|
|
653
|
+
);
|
|
654
|
+
const width = Math.round(device.width * scale);
|
|
655
|
+
const height = Math.round(device.height * scale);
|
|
656
|
+
return {
|
|
657
|
+
left: Math.round((viewportWidth - width) / 2),
|
|
658
|
+
top: Math.round((viewportHeight - height) / 2),
|
|
659
|
+
width,
|
|
660
|
+
height,
|
|
661
|
+
scale
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function scaledInset(value, scale) {
|
|
665
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
666
|
+
return 0;
|
|
667
|
+
}
|
|
668
|
+
return Math.max(0, Math.round(value * scale));
|
|
669
|
+
}
|
|
670
|
+
function getSimulatorInsets(state) {
|
|
671
|
+
const safe = state.device.safeArea;
|
|
672
|
+
const top = scaledInset(safe.top, state.rect.scale) + Math.round((TOP_BAR_OFFSET + TOP_CHROME_HEIGHT) * state.rect.scale);
|
|
673
|
+
const pixels = {
|
|
674
|
+
top,
|
|
675
|
+
right: scaledInset(safe.right, state.rect.scale),
|
|
676
|
+
bottom: scaledInset(safe.bottom, state.rect.scale),
|
|
677
|
+
left: scaledInset(safe.left, state.rect.scale)
|
|
678
|
+
};
|
|
679
|
+
const percent = {
|
|
680
|
+
top: state.rect.height > 0 ? pixels.top / state.rect.height * 100 : 0,
|
|
681
|
+
right: state.rect.width > 0 ? pixels.right / state.rect.width * 100 : 0,
|
|
682
|
+
bottom: state.rect.height > 0 ? pixels.bottom / state.rect.height * 100 : 0,
|
|
683
|
+
left: state.rect.width > 0 ? pixels.left / state.rect.width * 100 : 0
|
|
684
|
+
};
|
|
685
|
+
return { pixels, percent };
|
|
686
|
+
}
|
|
687
|
+
function snapshotBridge(browserWindow) {
|
|
688
|
+
const globals = {};
|
|
689
|
+
for (const key of BRIDGE_KEYS) {
|
|
690
|
+
globals[key] = browserWindow[key];
|
|
691
|
+
}
|
|
692
|
+
return { globals };
|
|
693
|
+
}
|
|
694
|
+
function restoreBridge(browserWindow, snapshot) {
|
|
695
|
+
for (const key of BRIDGE_KEYS) {
|
|
696
|
+
const value = snapshot.globals[key];
|
|
697
|
+
if (typeof value === "undefined") {
|
|
698
|
+
delete browserWindow[key];
|
|
699
|
+
} else {
|
|
700
|
+
browserWindow[key] = value;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function installBridge(state) {
|
|
705
|
+
const browserWindow = getBrowserWindow();
|
|
706
|
+
if (!browserWindow) return;
|
|
707
|
+
const bridge = browserWindow;
|
|
708
|
+
function refreshInsets() {
|
|
709
|
+
const insets = getSimulatorInsets(state);
|
|
710
|
+
bridge.__OASIZ_VIEWPORT_INSETS__ = insets;
|
|
711
|
+
bridge.__OASIZ_VIEWPORT_INSETS_PERCENT__ = insets.percent;
|
|
712
|
+
bridge.__OASIZ_SAFE_AREA_TOP__ = insets.pixels.top;
|
|
713
|
+
bridge.__OASIZ_SAFE_AREA_RIGHT__ = insets.pixels.right;
|
|
714
|
+
bridge.__OASIZ_SAFE_AREA_BOTTOM__ = insets.pixels.bottom;
|
|
715
|
+
bridge.__OASIZ_SAFE_AREA_LEFT__ = insets.pixels.left;
|
|
716
|
+
bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__ = insets.percent.top;
|
|
717
|
+
bridge.__OASIZ_SAFE_AREA_RIGHT_PERCENT__ = insets.percent.right;
|
|
718
|
+
bridge.__OASIZ_SAFE_AREA_BOTTOM_PERCENT__ = insets.percent.bottom;
|
|
719
|
+
bridge.__OASIZ_SAFE_AREA_LEFT_PERCENT__ = insets.percent.left;
|
|
720
|
+
return insets;
|
|
721
|
+
}
|
|
722
|
+
bridge.getViewportInsets = () => refreshInsets();
|
|
723
|
+
bridge.getViewportInsetsPercent = () => refreshInsets().percent;
|
|
724
|
+
bridge.getSafeAreaTop = () => refreshInsets().pixels.top;
|
|
725
|
+
bridge.getSafeAreaRight = () => refreshInsets().pixels.right;
|
|
726
|
+
bridge.getSafeAreaBottom = () => refreshInsets().pixels.bottom;
|
|
727
|
+
bridge.getSafeAreaLeft = () => refreshInsets().pixels.left;
|
|
728
|
+
bridge.getSafeAreaTopPercent = () => refreshInsets().percent.top;
|
|
729
|
+
bridge.getSafeAreaRightPercent = () => refreshInsets().percent.right;
|
|
730
|
+
bridge.getSafeAreaBottomPercent = () => refreshInsets().percent.bottom;
|
|
731
|
+
bridge.getSafeAreaLeftPercent = () => refreshInsets().percent.left;
|
|
732
|
+
bridge.__oasizSetLeaderboardVisible = (visible) => {
|
|
733
|
+
state.leaderboard.visible = visible;
|
|
734
|
+
renderSimulator(state);
|
|
735
|
+
};
|
|
736
|
+
refreshInsets();
|
|
737
|
+
}
|
|
738
|
+
function createStyleElement() {
|
|
739
|
+
const style = document.createElement("style");
|
|
740
|
+
style.setAttribute("data-oasiz-app-simulator", "styles");
|
|
741
|
+
style.textContent = [
|
|
742
|
+
".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}",
|
|
743
|
+
".oasiz-app-sim-button:active{transform:scale(0.97)}",
|
|
744
|
+
".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)}",
|
|
745
|
+
".oasiz-app-sim-scroll::-webkit-scrollbar{width:0;height:0}"
|
|
746
|
+
].join("\n");
|
|
747
|
+
return style;
|
|
748
|
+
}
|
|
749
|
+
function applyTextStyle(element, size = 12, weight = 600) {
|
|
750
|
+
element.style.font = String(weight) + " " + String(size) + "px/1.2 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif";
|
|
751
|
+
}
|
|
752
|
+
function createDiv(className) {
|
|
753
|
+
const element = document.createElement("div");
|
|
754
|
+
if (className) {
|
|
755
|
+
element.className = className;
|
|
756
|
+
}
|
|
757
|
+
return element;
|
|
758
|
+
}
|
|
759
|
+
function createButton(label, title) {
|
|
760
|
+
const button = document.createElement("button");
|
|
761
|
+
button.type = "button";
|
|
762
|
+
button.className = "oasiz-app-sim-button";
|
|
763
|
+
button.setAttribute("aria-label", title);
|
|
764
|
+
button.title = title;
|
|
765
|
+
button.innerHTML = label;
|
|
766
|
+
return button;
|
|
767
|
+
}
|
|
768
|
+
function svgIcon(name, filled = false) {
|
|
769
|
+
if (name === "back") {
|
|
770
|
+
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>';
|
|
771
|
+
}
|
|
772
|
+
if (name === "heart") {
|
|
773
|
+
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>';
|
|
774
|
+
}
|
|
775
|
+
if (name === "chat") {
|
|
776
|
+
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>';
|
|
777
|
+
}
|
|
778
|
+
if (name === "trophy") {
|
|
779
|
+
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>';
|
|
780
|
+
}
|
|
781
|
+
if (name === "share") {
|
|
782
|
+
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>';
|
|
783
|
+
}
|
|
784
|
+
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>';
|
|
785
|
+
}
|
|
786
|
+
function setBoxStyle(element, state) {
|
|
787
|
+
const { rect } = state;
|
|
788
|
+
element.style.left = rect.left + "px";
|
|
789
|
+
element.style.top = rect.top + "px";
|
|
790
|
+
element.style.width = rect.width + "px";
|
|
791
|
+
element.style.height = rect.height + "px";
|
|
792
|
+
}
|
|
793
|
+
function createCircleButton(icon, title, onClick) {
|
|
794
|
+
const button = createButton(icon, title);
|
|
795
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
796
|
+
button.style.cssText += [
|
|
797
|
+
"position:absolute",
|
|
798
|
+
"width:44px",
|
|
799
|
+
"height:44px",
|
|
800
|
+
"border-radius:999px",
|
|
801
|
+
"display:flex",
|
|
802
|
+
"align-items:center",
|
|
803
|
+
"justify-content:center",
|
|
804
|
+
"color:" + TEXT_PRIMARY,
|
|
805
|
+
"pointer-events:auto"
|
|
806
|
+
].join(";");
|
|
807
|
+
button.addEventListener("click", (event) => {
|
|
808
|
+
event.preventDefault();
|
|
809
|
+
event.stopPropagation();
|
|
810
|
+
onClick();
|
|
811
|
+
});
|
|
812
|
+
return button;
|
|
813
|
+
}
|
|
814
|
+
function createHubPill(state) {
|
|
815
|
+
const button = createButton("", "Open comments");
|
|
816
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
817
|
+
button.style.cssText += [
|
|
818
|
+
"position:absolute",
|
|
819
|
+
"right:16px",
|
|
820
|
+
"height:44px",
|
|
821
|
+
"min-width:94px",
|
|
822
|
+
"border-radius:999px",
|
|
823
|
+
"display:flex",
|
|
824
|
+
"align-items:center",
|
|
825
|
+
"justify-content:center",
|
|
826
|
+
"gap:10px",
|
|
827
|
+
"padding:0 14px",
|
|
828
|
+
"color:" + TEXT_PRIMARY,
|
|
829
|
+
"pointer-events:auto"
|
|
830
|
+
].join(";");
|
|
831
|
+
const likeColor = state.wasLiked ? LIKE : TEXT_PRIMARY;
|
|
832
|
+
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>";
|
|
833
|
+
applyTextStyle(button, 12, 700);
|
|
834
|
+
button.addEventListener("click", (event) => {
|
|
835
|
+
event.preventDefault();
|
|
836
|
+
event.stopPropagation();
|
|
837
|
+
state.sheet = "comments";
|
|
838
|
+
renderSimulator(state);
|
|
839
|
+
});
|
|
840
|
+
return button;
|
|
841
|
+
}
|
|
842
|
+
function createLeaderboardPill(state) {
|
|
843
|
+
const button = createButton("", "Open leaderboard");
|
|
844
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
845
|
+
button.style.cssText += [
|
|
846
|
+
"position:absolute",
|
|
847
|
+
"left:50%",
|
|
848
|
+
"height:44px",
|
|
849
|
+
"min-width:118px",
|
|
850
|
+
"border-radius:999px",
|
|
851
|
+
"display:" + (state.leaderboard.visible ? "flex" : "none"),
|
|
852
|
+
"align-items:center",
|
|
853
|
+
"justify-content:center",
|
|
854
|
+
"gap:8px",
|
|
855
|
+
"padding:0 14px",
|
|
856
|
+
"color:" + TEXT_PRIMARY,
|
|
857
|
+
"pointer-events:auto",
|
|
858
|
+
"transform:translateX(-50%)"
|
|
859
|
+
].join(";");
|
|
860
|
+
button.innerHTML = '<span style="color:' + TROPHY + ';display:inline-flex">' + svgIcon("trophy", true) + '</span><span style="min-width:0">' + formatCompactCount(state.leaderboard.score) + "</span>";
|
|
861
|
+
applyTextStyle(button, 14, 800);
|
|
862
|
+
button.addEventListener("click", (event) => {
|
|
863
|
+
event.preventDefault();
|
|
864
|
+
event.stopPropagation();
|
|
865
|
+
state.sheet = "leaderboard";
|
|
866
|
+
renderSimulator(state);
|
|
867
|
+
});
|
|
868
|
+
return button;
|
|
869
|
+
}
|
|
870
|
+
function createToolbarButton(icon, count, color, title, onClick) {
|
|
871
|
+
const button = createButton("", title);
|
|
872
|
+
button.classList.add("oasiz-app-sim-glass");
|
|
873
|
+
button.style.cssText += [
|
|
874
|
+
"height:42px",
|
|
875
|
+
"min-width:42px",
|
|
876
|
+
"border-radius:999px",
|
|
877
|
+
"display:flex",
|
|
878
|
+
"align-items:center",
|
|
879
|
+
"justify-content:center",
|
|
880
|
+
"gap:6px",
|
|
881
|
+
"padding:0 12px",
|
|
882
|
+
"color:" + color,
|
|
883
|
+
"pointer-events:auto"
|
|
884
|
+
].join(";");
|
|
885
|
+
button.innerHTML = icon + (count === null ? "" : '<span style="color:' + color + ';min-width:0">' + formatCompactCount(count) + "</span>");
|
|
886
|
+
applyTextStyle(button, 13, 700);
|
|
887
|
+
button.addEventListener("click", (event) => {
|
|
888
|
+
event.preventDefault();
|
|
889
|
+
event.stopPropagation();
|
|
890
|
+
onClick();
|
|
891
|
+
});
|
|
892
|
+
return button;
|
|
893
|
+
}
|
|
894
|
+
function createSheet(state) {
|
|
895
|
+
if (!state.sheet) {
|
|
896
|
+
return null;
|
|
897
|
+
}
|
|
898
|
+
const overlay = createDiv();
|
|
899
|
+
overlay.style.cssText = [
|
|
900
|
+
"position:absolute",
|
|
901
|
+
"left:0",
|
|
902
|
+
"top:0",
|
|
903
|
+
"right:0",
|
|
904
|
+
"bottom:0",
|
|
905
|
+
"display:flex",
|
|
906
|
+
"align-items:center",
|
|
907
|
+
"justify-content:center",
|
|
908
|
+
"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",
|
|
909
|
+
"background:rgba(0,0,0,0.34)",
|
|
910
|
+
"pointer-events:auto"
|
|
911
|
+
].join(";");
|
|
912
|
+
overlay.addEventListener("click", () => {
|
|
913
|
+
state.sheet = null;
|
|
914
|
+
renderSimulator(state);
|
|
915
|
+
});
|
|
916
|
+
const sheet = createDiv();
|
|
917
|
+
sheet.style.cssText = [
|
|
918
|
+
"position:relative",
|
|
919
|
+
"width:min(100%, 408px)",
|
|
920
|
+
"max-height:100%",
|
|
921
|
+
"min-height:min(390px, 64%)",
|
|
922
|
+
"display:flex",
|
|
923
|
+
"flex-direction:column",
|
|
924
|
+
"border-radius:24px",
|
|
925
|
+
"border:1px solid " + BORDER,
|
|
926
|
+
"background:linear-gradient(180deg, rgba(18,20,24,0.97), rgba(9,11,15,0.98))",
|
|
927
|
+
"box-shadow:0 30px 80px rgba(0,0,0,0.52), inset 0 1px 0 rgba(255,255,255,0.10)",
|
|
928
|
+
"overflow:hidden",
|
|
929
|
+
"pointer-events:auto"
|
|
930
|
+
].join(";");
|
|
931
|
+
sheet.addEventListener("click", (event) => {
|
|
932
|
+
event.stopPropagation();
|
|
933
|
+
});
|
|
934
|
+
const handle = createDiv();
|
|
935
|
+
handle.style.cssText = [
|
|
936
|
+
"width:42px",
|
|
937
|
+
"height:5px",
|
|
938
|
+
"border-radius:999px",
|
|
939
|
+
"background:rgba(255,255,255,0.28)",
|
|
940
|
+
"align-self:center",
|
|
941
|
+
"margin:10px 0 2px"
|
|
942
|
+
].join(";");
|
|
943
|
+
const header = createDiv();
|
|
944
|
+
header.style.cssText = [
|
|
945
|
+
"display:flex",
|
|
946
|
+
"align-items:center",
|
|
947
|
+
"justify-content:space-between",
|
|
948
|
+
"gap:8px",
|
|
949
|
+
"min-height:62px",
|
|
950
|
+
"padding:6px 14px 10px",
|
|
951
|
+
"border-bottom:1px solid " + BORDER
|
|
952
|
+
].join(";");
|
|
953
|
+
const left = createDiv();
|
|
954
|
+
left.style.cssText = "display:flex;align-items:center;gap:8px;min-width:112px";
|
|
955
|
+
const title = createDiv();
|
|
956
|
+
title.textContent = state.sheet === "comments" ? String(state.counts.comments) + " comments" : "Leaderboard";
|
|
957
|
+
title.style.cssText = [
|
|
958
|
+
"flex:1",
|
|
959
|
+
"min-width:0",
|
|
960
|
+
"text-align:center",
|
|
961
|
+
"color:" + TEXT_PRIMARY
|
|
962
|
+
].join(";");
|
|
963
|
+
applyTextStyle(title, 14, 700);
|
|
964
|
+
const right = createDiv();
|
|
965
|
+
right.style.cssText = "display:flex;align-items:center;justify-content:flex-end;gap:8px;min-width:112px";
|
|
966
|
+
const back = createToolbarButton(svgIcon("back"), null, TEXT_PRIMARY, "Close", () => {
|
|
967
|
+
state.sheet = null;
|
|
968
|
+
renderSimulator(state);
|
|
969
|
+
});
|
|
970
|
+
back.style.width = "36px";
|
|
971
|
+
back.style.height = "36px";
|
|
972
|
+
back.style.padding = "0";
|
|
973
|
+
left.appendChild(back);
|
|
974
|
+
if (state.sheet === "comments") {
|
|
975
|
+
const like = createToolbarButton(
|
|
976
|
+
svgIcon("heart", state.wasLiked),
|
|
977
|
+
state.counts.likes,
|
|
978
|
+
state.wasLiked ? LIKE : TEXT_PRIMARY,
|
|
979
|
+
"Like game",
|
|
980
|
+
() => {
|
|
981
|
+
state.wasLiked = !state.wasLiked;
|
|
982
|
+
state.counts.likes = Math.max(0, state.counts.likes + (state.wasLiked ? 1 : -1));
|
|
983
|
+
renderSimulator(state);
|
|
984
|
+
}
|
|
985
|
+
);
|
|
986
|
+
left.appendChild(like);
|
|
987
|
+
} else {
|
|
988
|
+
const trophy = createToolbarButton(svgIcon("trophy", true), null, TROPHY, "Leaderboard", () => {
|
|
989
|
+
});
|
|
990
|
+
trophy.style.width = "36px";
|
|
991
|
+
trophy.style.height = "36px";
|
|
992
|
+
trophy.style.padding = "0";
|
|
993
|
+
left.appendChild(trophy);
|
|
994
|
+
}
|
|
995
|
+
const share2 = createToolbarButton(svgIcon("share"), null, TEXT_PRIMARY, "Share", () => {
|
|
996
|
+
});
|
|
997
|
+
const save = createToolbarButton(svgIcon("bookmark"), null, TEXT_PRIMARY, "Save", () => {
|
|
998
|
+
});
|
|
999
|
+
right.appendChild(share2);
|
|
1000
|
+
right.appendChild(save);
|
|
1001
|
+
header.appendChild(left);
|
|
1002
|
+
header.appendChild(title);
|
|
1003
|
+
header.appendChild(right);
|
|
1004
|
+
const body = createDiv("oasiz-app-sim-scroll");
|
|
1005
|
+
body.style.cssText = [
|
|
1006
|
+
"display:flex",
|
|
1007
|
+
"flex-direction:column",
|
|
1008
|
+
"gap:10px",
|
|
1009
|
+
"overflow:auto",
|
|
1010
|
+
"padding:14px 16px calc(" + String(Math.max(16, scaledInset(state.device.safeArea.bottom, state.rect.scale))) + "px + 14px)",
|
|
1011
|
+
"min-height:0"
|
|
1012
|
+
].join(";");
|
|
1013
|
+
if (state.sheet === "leaderboard") {
|
|
1014
|
+
appendLeaderboardBody(body);
|
|
1015
|
+
} else {
|
|
1016
|
+
appendCommentsBody(body, state);
|
|
1017
|
+
}
|
|
1018
|
+
sheet.appendChild(handle);
|
|
1019
|
+
sheet.appendChild(header);
|
|
1020
|
+
sheet.appendChild(body);
|
|
1021
|
+
overlay.appendChild(sheet);
|
|
1022
|
+
return overlay;
|
|
1023
|
+
}
|
|
1024
|
+
function appendLeaderboardBody(body) {
|
|
1025
|
+
const tabs = createDiv();
|
|
1026
|
+
tabs.style.cssText = [
|
|
1027
|
+
"display:grid",
|
|
1028
|
+
"grid-template-columns:repeat(3,1fr)",
|
|
1029
|
+
"gap:6px",
|
|
1030
|
+
"padding:4px",
|
|
1031
|
+
"border-radius:14px",
|
|
1032
|
+
"background:rgba(255,255,255,0.07)"
|
|
1033
|
+
].join(";");
|
|
1034
|
+
for (const label of ["Weekly", "Global", "Friends"]) {
|
|
1035
|
+
const tab = createDiv();
|
|
1036
|
+
tab.textContent = label;
|
|
1037
|
+
tab.style.cssText = [
|
|
1038
|
+
"border-radius:10px",
|
|
1039
|
+
"padding:8px 6px",
|
|
1040
|
+
"text-align:center",
|
|
1041
|
+
"color:" + (label === "Weekly" ? TEXT_PRIMARY : TEXT_MUTED),
|
|
1042
|
+
"background:" + (label === "Weekly" ? "rgba(0,161,228,0.28)" : "transparent")
|
|
1043
|
+
].join(";");
|
|
1044
|
+
applyTextStyle(tab, 12, 700);
|
|
1045
|
+
tabs.appendChild(tab);
|
|
1046
|
+
}
|
|
1047
|
+
body.appendChild(tabs);
|
|
1048
|
+
const entries = [
|
|
1049
|
+
["1", "Nova", "24.8k"],
|
|
1050
|
+
["2", "You", "12.4k"],
|
|
1051
|
+
["3", "Mika", "9.7k"],
|
|
1052
|
+
["4", "Ari", "8.1k"]
|
|
1053
|
+
];
|
|
1054
|
+
for (const [rank, name, score] of entries) {
|
|
1055
|
+
const row = createDiv();
|
|
1056
|
+
row.style.cssText = [
|
|
1057
|
+
"display:grid",
|
|
1058
|
+
"grid-template-columns:34px 1fr auto",
|
|
1059
|
+
"align-items:center",
|
|
1060
|
+
"gap:10px",
|
|
1061
|
+
"min-height:58px",
|
|
1062
|
+
"padding:10px 12px",
|
|
1063
|
+
"border-radius:14px",
|
|
1064
|
+
"background:" + (name === "You" ? "rgba(0,161,228,0.13)" : "rgba(255,255,255,0.06)"),
|
|
1065
|
+
"border:1px solid " + (name === "You" ? "rgba(0,161,228,0.28)" : "rgba(255,255,255,0.08)")
|
|
1066
|
+
].join(";");
|
|
1067
|
+
const rankEl = createDiv();
|
|
1068
|
+
rankEl.textContent = rank;
|
|
1069
|
+
rankEl.style.cssText = "color:" + (rank === "1" ? TROPHY : TEXT_MUTED) + ";text-align:center";
|
|
1070
|
+
applyTextStyle(rankEl, 14, 800);
|
|
1071
|
+
const nameEl = createDiv();
|
|
1072
|
+
nameEl.textContent = name;
|
|
1073
|
+
nameEl.style.cssText = "color:" + TEXT_PRIMARY + ";min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
1074
|
+
applyTextStyle(nameEl, 14, 700);
|
|
1075
|
+
const scoreEl = createDiv();
|
|
1076
|
+
scoreEl.textContent = score;
|
|
1077
|
+
scoreEl.style.cssText = "color:" + TEXT_SECONDARY;
|
|
1078
|
+
applyTextStyle(scoreEl, 13, 700);
|
|
1079
|
+
row.appendChild(rankEl);
|
|
1080
|
+
row.appendChild(nameEl);
|
|
1081
|
+
row.appendChild(scoreEl);
|
|
1082
|
+
body.appendChild(row);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
function appendCommentsBody(body, state) {
|
|
1086
|
+
const toolbar = createDiv();
|
|
1087
|
+
toolbar.style.cssText = [
|
|
1088
|
+
"display:flex",
|
|
1089
|
+
"align-items:center",
|
|
1090
|
+
"gap:8px",
|
|
1091
|
+
"height:48px"
|
|
1092
|
+
].join(";");
|
|
1093
|
+
toolbar.appendChild(
|
|
1094
|
+
createToolbarButton(
|
|
1095
|
+
svgIcon("heart", state.wasLiked),
|
|
1096
|
+
state.counts.likes,
|
|
1097
|
+
state.wasLiked ? LIKE : TEXT_PRIMARY,
|
|
1098
|
+
"Like game",
|
|
1099
|
+
() => {
|
|
1100
|
+
state.wasLiked = !state.wasLiked;
|
|
1101
|
+
state.counts.likes = Math.max(0, state.counts.likes + (state.wasLiked ? 1 : -1));
|
|
1102
|
+
renderSimulator(state);
|
|
1103
|
+
}
|
|
1104
|
+
)
|
|
1105
|
+
);
|
|
1106
|
+
toolbar.appendChild(
|
|
1107
|
+
createToolbarButton(svgIcon("chat", true), state.counts.comments, ACCENT, "Comments", () => {
|
|
1108
|
+
})
|
|
1109
|
+
);
|
|
1110
|
+
toolbar.appendChild(createToolbarButton(svgIcon("share"), null, TEXT_PRIMARY, "Share", () => {
|
|
1111
|
+
}));
|
|
1112
|
+
toolbar.appendChild(createToolbarButton(svgIcon("bookmark"), null, TEXT_PRIMARY, "Save", () => {
|
|
1113
|
+
}));
|
|
1114
|
+
body.appendChild(toolbar);
|
|
1115
|
+
const comments = [
|
|
1116
|
+
["You", "Can my score panel clear the top buttons?"],
|
|
1117
|
+
["Nova", "This is a good spot to check pause and menu spacing."],
|
|
1118
|
+
["Mika", "The app chrome stays above the game just like mobile."]
|
|
1119
|
+
];
|
|
1120
|
+
for (const [author, text] of comments) {
|
|
1121
|
+
const row = createDiv();
|
|
1122
|
+
row.style.cssText = [
|
|
1123
|
+
"display:grid",
|
|
1124
|
+
"grid-template-columns:34px 1fr",
|
|
1125
|
+
"gap:10px",
|
|
1126
|
+
"padding:10px 0"
|
|
1127
|
+
].join(";");
|
|
1128
|
+
const avatar = createDiv();
|
|
1129
|
+
avatar.textContent = author.charAt(0);
|
|
1130
|
+
avatar.style.cssText = [
|
|
1131
|
+
"width:34px",
|
|
1132
|
+
"height:34px",
|
|
1133
|
+
"border-radius:999px",
|
|
1134
|
+
"display:flex",
|
|
1135
|
+
"align-items:center",
|
|
1136
|
+
"justify-content:center",
|
|
1137
|
+
"background:rgba(0,161,228,0.28)",
|
|
1138
|
+
"color:" + TEXT_PRIMARY
|
|
1139
|
+
].join(";");
|
|
1140
|
+
applyTextStyle(avatar, 13, 800);
|
|
1141
|
+
const message = createDiv();
|
|
1142
|
+
message.innerHTML = '<div style="color:' + TEXT_PRIMARY + ';font-weight:700;margin-bottom:3px">' + author + '</div><div style="color:' + TEXT_SECONDARY + '">' + text + "</div>";
|
|
1143
|
+
applyTextStyle(message, 13, 500);
|
|
1144
|
+
row.appendChild(avatar);
|
|
1145
|
+
row.appendChild(message);
|
|
1146
|
+
body.appendChild(row);
|
|
1147
|
+
}
|
|
1148
|
+
const composer = createDiv();
|
|
1149
|
+
composer.textContent = "Add comment...";
|
|
1150
|
+
composer.style.cssText = [
|
|
1151
|
+
"height:44px",
|
|
1152
|
+
"border-radius:18px",
|
|
1153
|
+
"display:flex",
|
|
1154
|
+
"align-items:center",
|
|
1155
|
+
"padding:0 14px",
|
|
1156
|
+
"background:rgba(255,255,255,0.08)",
|
|
1157
|
+
"border:1px solid rgba(255,255,255,0.10)",
|
|
1158
|
+
"color:" + TEXT_MUTED
|
|
1159
|
+
].join(";");
|
|
1160
|
+
applyTextStyle(composer, 13, 600);
|
|
1161
|
+
body.appendChild(composer);
|
|
1162
|
+
}
|
|
1163
|
+
function renderSimulator(state) {
|
|
1164
|
+
if (state.wasDestroyed) {
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
const { root, stage, gameViewport } = state.elements;
|
|
1168
|
+
root.style.display = state.visible ? "block" : "none";
|
|
1169
|
+
setBoxStyle(stage, state);
|
|
1170
|
+
if (gameViewport) {
|
|
1171
|
+
setBoxStyle(gameViewport, state);
|
|
1172
|
+
}
|
|
1173
|
+
stage.replaceChildren();
|
|
1174
|
+
const top = scaledInset(state.device.safeArea.top, state.rect.scale) + Math.round(TOP_BAR_OFFSET * state.rect.scale);
|
|
1175
|
+
const back = createCircleButton(svgIcon("back"), "Back", () => {
|
|
1176
|
+
if (state.backHandle.isBackOverrideActive()) {
|
|
1177
|
+
state.backHandle.triggerBack();
|
|
1178
|
+
} else {
|
|
1179
|
+
state.backHandle.triggerLeave();
|
|
1180
|
+
}
|
|
1181
|
+
});
|
|
1182
|
+
back.style.left = Math.round(16 * state.rect.scale) + "px";
|
|
1183
|
+
back.style.top = top + "px";
|
|
1184
|
+
const leaderboard = createLeaderboardPill(state);
|
|
1185
|
+
leaderboard.style.top = top + "px";
|
|
1186
|
+
const hub = createHubPill(state);
|
|
1187
|
+
hub.style.top = top + "px";
|
|
1188
|
+
hub.style.right = Math.round(16 * state.rect.scale) + "px";
|
|
1189
|
+
stage.appendChild(back);
|
|
1190
|
+
stage.appendChild(leaderboard);
|
|
1191
|
+
stage.appendChild(hub);
|
|
1192
|
+
const sheet = createSheet(state);
|
|
1193
|
+
if (sheet) {
|
|
1194
|
+
stage.appendChild(sheet);
|
|
1195
|
+
}
|
|
1196
|
+
if (state.options.log) {
|
|
1197
|
+
console.info("[oasiz/sdk] App simulator rendered.", {
|
|
1198
|
+
device: state.device.name,
|
|
1199
|
+
frame: state.frameEnabled,
|
|
1200
|
+
insets: getSimulatorInsets(state)
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
function installFrame(doc, state) {
|
|
1205
|
+
if (!state.frameEnabled || !doc.body) {
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
const body = doc.body;
|
|
1209
|
+
const html = doc.documentElement;
|
|
1210
|
+
const viewport = state.elements.gameViewport;
|
|
1211
|
+
if (!viewport) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
html.style.cssText = [
|
|
1215
|
+
state.previousDocumentElementStyle ?? "",
|
|
1216
|
+
"width:100%",
|
|
1217
|
+
"height:100%",
|
|
1218
|
+
"background:" + BODY_BACKGROUND,
|
|
1219
|
+
"overflow:hidden"
|
|
1220
|
+
].join(";");
|
|
1221
|
+
body.style.cssText = [
|
|
1222
|
+
state.previousBodyStyle ?? "",
|
|
1223
|
+
"width:100%",
|
|
1224
|
+
"height:100%",
|
|
1225
|
+
"margin:0",
|
|
1226
|
+
"background:" + BODY_BACKGROUND,
|
|
1227
|
+
"overflow:hidden"
|
|
1228
|
+
].join(";");
|
|
1229
|
+
const candidates = Array.from(body.children).filter(
|
|
1230
|
+
(node) => shouldMoveIntoGameViewport(node, state.elements)
|
|
1231
|
+
);
|
|
1232
|
+
for (const node of candidates) {
|
|
1233
|
+
state.movedNodes.push(node);
|
|
1234
|
+
viewport.appendChild(node);
|
|
1235
|
+
}
|
|
1236
|
+
body.appendChild(viewport);
|
|
1237
|
+
}
|
|
1238
|
+
function shouldMoveIntoGameViewport(node, elements) {
|
|
1239
|
+
if (node === elements.root || node === elements.style || node === elements.gameViewport) {
|
|
1240
|
+
return false;
|
|
1241
|
+
}
|
|
1242
|
+
const tagName = node.tagName.toUpperCase();
|
|
1243
|
+
if (tagName === "SCRIPT" || tagName === "STYLE" || tagName === "LINK" || tagName === "META" || tagName === "NOSCRIPT") {
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
return node.getAttribute("data-oasiz-app-simulator") !== "true";
|
|
1247
|
+
}
|
|
1248
|
+
function restoreFrame(doc, state) {
|
|
1249
|
+
const body = doc.body;
|
|
1250
|
+
if (!body) {
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
for (const node of state.movedNodes) {
|
|
1254
|
+
body.appendChild(node);
|
|
1255
|
+
}
|
|
1256
|
+
state.movedNodes = [];
|
|
1257
|
+
state.elements.gameViewport?.remove();
|
|
1258
|
+
if (state.previousBodyStyle === null) {
|
|
1259
|
+
body.removeAttribute("style");
|
|
1260
|
+
} else {
|
|
1261
|
+
body.setAttribute("style", state.previousBodyStyle);
|
|
1262
|
+
}
|
|
1263
|
+
if (state.previousDocumentElementStyle === null) {
|
|
1264
|
+
doc.documentElement.removeAttribute("style");
|
|
1265
|
+
} else {
|
|
1266
|
+
doc.documentElement.setAttribute("style", state.previousDocumentElementStyle);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function createElements(frameEnabled) {
|
|
1270
|
+
const root = document.createElement("div");
|
|
1271
|
+
root.setAttribute("data-oasiz-app-simulator", "true");
|
|
1272
|
+
root.style.cssText = [
|
|
1273
|
+
"position:fixed",
|
|
1274
|
+
"inset:0",
|
|
1275
|
+
"z-index:" + String(MAX_Z_INDEX),
|
|
1276
|
+
"pointer-events:none",
|
|
1277
|
+
"display:block",
|
|
1278
|
+
"font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif"
|
|
1279
|
+
].join(";");
|
|
1280
|
+
const stage = document.createElement("div");
|
|
1281
|
+
stage.setAttribute("data-oasiz-app-simulator", "stage");
|
|
1282
|
+
stage.style.cssText = [
|
|
1283
|
+
"position:absolute",
|
|
1284
|
+
"overflow:hidden",
|
|
1285
|
+
"pointer-events:none"
|
|
1286
|
+
].join(";");
|
|
1287
|
+
root.appendChild(stage);
|
|
1288
|
+
const gameViewport = frameEnabled ? document.createElement("div") : null;
|
|
1289
|
+
if (gameViewport) {
|
|
1290
|
+
gameViewport.setAttribute("data-oasiz-app-simulator", "game-viewport");
|
|
1291
|
+
gameViewport.style.cssText = [
|
|
1292
|
+
"position:fixed",
|
|
1293
|
+
"z-index:0",
|
|
1294
|
+
"overflow:hidden",
|
|
1295
|
+
"background:#000",
|
|
1296
|
+
"border-radius:28px",
|
|
1297
|
+
"outline:1px solid rgba(255,255,255,0.28)",
|
|
1298
|
+
"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)"
|
|
1299
|
+
].join(";");
|
|
1300
|
+
}
|
|
1301
|
+
return {
|
|
1302
|
+
gameViewport,
|
|
1303
|
+
root,
|
|
1304
|
+
stage,
|
|
1305
|
+
style: createStyleElement()
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
function installResizeHandler(browserWindow, state) {
|
|
1309
|
+
const resize = () => {
|
|
1310
|
+
state.rect = computeRect(browserWindow, state.device, state.frameEnabled);
|
|
1311
|
+
installBridge(state);
|
|
1312
|
+
renderSimulator(state);
|
|
1313
|
+
};
|
|
1314
|
+
browserWindow.addEventListener("resize", resize);
|
|
1315
|
+
browserWindow.addEventListener("orientationchange", resize);
|
|
1316
|
+
return () => {
|
|
1317
|
+
browserWindow.removeEventListener("resize", resize);
|
|
1318
|
+
browserWindow.removeEventListener("orientationchange", resize);
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
function enableAppSimulator(options = {}) {
|
|
1322
|
+
if (options.enabled === false) {
|
|
1323
|
+
return NOOP_HANDLE;
|
|
1324
|
+
}
|
|
1325
|
+
const browserWindow = getBrowserWindow();
|
|
1326
|
+
const doc = getDocument();
|
|
1327
|
+
if (!browserWindow || !doc?.body || !doc.documentElement) {
|
|
1328
|
+
warn("enableAppSimulator requires a browser document.");
|
|
1329
|
+
return NOOP_HANDLE;
|
|
1330
|
+
}
|
|
1331
|
+
browserWindow.__oasizAppSimulatorHandle__?.destroy();
|
|
1332
|
+
const orientation = options.orientation ?? "portrait";
|
|
1333
|
+
const device = resolveDevice(options.device, orientation);
|
|
1334
|
+
const frameEnabled = shouldFrame(options.frame ?? true, browserWindow, device);
|
|
1335
|
+
const elements = createElements(frameEnabled);
|
|
1336
|
+
const rect = computeRect(browserWindow, device, frameEnabled);
|
|
1337
|
+
const backHandle = enableBackButtonTesting({
|
|
1338
|
+
browserHistory: options.browserHistoryBack ?? true,
|
|
1339
|
+
keyboard: options.keyboardBack ?? true,
|
|
1340
|
+
log: options.log === true
|
|
1341
|
+
});
|
|
1342
|
+
const state = {
|
|
1343
|
+
backHandle,
|
|
1344
|
+
bridgeSnapshot: snapshotBridge(browserWindow),
|
|
1345
|
+
cleanupResize: () => {
|
|
1346
|
+
},
|
|
1347
|
+
counts: {
|
|
1348
|
+
comments: normalizeCount(options.comments, DEFAULT_COUNTS.comments),
|
|
1349
|
+
likes: normalizeCount(options.likes, DEFAULT_COUNTS.likes)
|
|
1350
|
+
},
|
|
1351
|
+
device,
|
|
1352
|
+
elements,
|
|
1353
|
+
frameEnabled,
|
|
1354
|
+
leaderboard: {
|
|
1355
|
+
score: normalizeCount(options.score, DEFAULT_SCORE),
|
|
1356
|
+
visible: options.leaderboardVisible ?? true
|
|
1357
|
+
},
|
|
1358
|
+
movedNodes: [],
|
|
1359
|
+
options: {
|
|
1360
|
+
browserHistoryBack: options.browserHistoryBack ?? true,
|
|
1361
|
+
keyboardBack: options.keyboardBack ?? true,
|
|
1362
|
+
log: options.log === true,
|
|
1363
|
+
orientation,
|
|
1364
|
+
title: options.title ?? "Oasiz App Preview"
|
|
1365
|
+
},
|
|
1366
|
+
previousBodyStyle: doc.body.getAttribute("style"),
|
|
1367
|
+
previousDocumentElementStyle: doc.documentElement.getAttribute("style"),
|
|
1368
|
+
rect,
|
|
1369
|
+
sheet: null,
|
|
1370
|
+
visible: true,
|
|
1371
|
+
wasDestroyed: false,
|
|
1372
|
+
wasLiked: false
|
|
1373
|
+
};
|
|
1374
|
+
if (doc.head) {
|
|
1375
|
+
doc.head.appendChild(elements.style);
|
|
1376
|
+
} else {
|
|
1377
|
+
doc.body.appendChild(elements.style);
|
|
1378
|
+
}
|
|
1379
|
+
installFrame(doc, state);
|
|
1380
|
+
doc.body.appendChild(elements.root);
|
|
1381
|
+
installBridge(state);
|
|
1382
|
+
state.cleanupResize = installResizeHandler(browserWindow, state);
|
|
1383
|
+
const handle = {
|
|
1384
|
+
closeSheet: () => {
|
|
1385
|
+
state.sheet = null;
|
|
1386
|
+
renderSimulator(state);
|
|
1387
|
+
},
|
|
1388
|
+
destroy: () => {
|
|
1389
|
+
if (state.wasDestroyed) return;
|
|
1390
|
+
state.wasDestroyed = true;
|
|
1391
|
+
state.cleanupResize();
|
|
1392
|
+
state.backHandle.destroy();
|
|
1393
|
+
restoreBridge(browserWindow, state.bridgeSnapshot);
|
|
1394
|
+
delete browserWindow.__oasizAppSimulatorHandle__;
|
|
1395
|
+
elements.root.remove();
|
|
1396
|
+
elements.style.remove();
|
|
1397
|
+
restoreFrame(doc, state);
|
|
1398
|
+
},
|
|
1399
|
+
getViewportInsets: () => getSimulatorInsets(state),
|
|
1400
|
+
hide: () => {
|
|
1401
|
+
state.visible = false;
|
|
1402
|
+
renderSimulator(state);
|
|
1403
|
+
},
|
|
1404
|
+
isVisible: () => state.visible,
|
|
1405
|
+
openComments: () => {
|
|
1406
|
+
state.sheet = "comments";
|
|
1407
|
+
renderSimulator(state);
|
|
1408
|
+
},
|
|
1409
|
+
openLeaderboard: () => {
|
|
1410
|
+
state.sheet = "leaderboard";
|
|
1411
|
+
renderSimulator(state);
|
|
1412
|
+
},
|
|
1413
|
+
setCounts: (counts) => {
|
|
1414
|
+
state.counts.comments = normalizeCount(counts.comments, state.counts.comments);
|
|
1415
|
+
state.counts.likes = normalizeCount(counts.likes, state.counts.likes);
|
|
1416
|
+
renderSimulator(state);
|
|
1417
|
+
},
|
|
1418
|
+
setLeaderboardVisible: (visible) => {
|
|
1419
|
+
state.leaderboard.visible = visible;
|
|
1420
|
+
renderSimulator(state);
|
|
1421
|
+
},
|
|
1422
|
+
setLiked: (liked) => {
|
|
1423
|
+
if (state.wasLiked === liked) {
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
state.wasLiked = liked;
|
|
1427
|
+
state.counts.likes = Math.max(0, state.counts.likes + (liked ? 1 : -1));
|
|
1428
|
+
renderSimulator(state);
|
|
1429
|
+
},
|
|
1430
|
+
show: () => {
|
|
1431
|
+
state.visible = true;
|
|
1432
|
+
renderSimulator(state);
|
|
1433
|
+
},
|
|
1434
|
+
triggerBack: () => state.backHandle.triggerBack(),
|
|
1435
|
+
triggerLeave: () => state.backHandle.triggerLeave()
|
|
1436
|
+
};
|
|
1437
|
+
browserWindow.__oasizAppSimulatorHandle__ = handle;
|
|
1438
|
+
renderSimulator(state);
|
|
1439
|
+
return handle;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
54
1442
|
// src/character.ts
|
|
55
|
-
function
|
|
1443
|
+
function isDevelopment2() {
|
|
56
1444
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
57
1445
|
return nodeEnv !== "production";
|
|
58
1446
|
}
|
|
59
|
-
function
|
|
1447
|
+
function getBridgeWindow2() {
|
|
60
1448
|
if (typeof window === "undefined") {
|
|
61
1449
|
return void 0;
|
|
62
1450
|
}
|
|
63
1451
|
return window;
|
|
64
1452
|
}
|
|
65
|
-
function
|
|
66
|
-
if (
|
|
1453
|
+
function warnMissingBridge2(methodName) {
|
|
1454
|
+
if (isDevelopment2()) {
|
|
67
1455
|
console.warn(
|
|
68
1456
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
69
1457
|
);
|
|
70
1458
|
}
|
|
71
1459
|
}
|
|
72
1460
|
async function getPlayerCharacter() {
|
|
73
|
-
const bridge =
|
|
1461
|
+
const bridge = getBridgeWindow2();
|
|
74
1462
|
if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
|
|
75
|
-
|
|
1463
|
+
warnMissingBridge2("getPlayerCharacter");
|
|
76
1464
|
return null;
|
|
77
1465
|
}
|
|
78
1466
|
try {
|
|
79
1467
|
const result = await bridge.__oasizGetPlayerCharacter();
|
|
80
1468
|
return result ?? null;
|
|
81
1469
|
} catch (error) {
|
|
82
|
-
if (
|
|
1470
|
+
if (isDevelopment2()) {
|
|
83
1471
|
console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
|
|
84
1472
|
}
|
|
85
1473
|
return null;
|
|
@@ -87,23 +1475,23 @@ async function getPlayerCharacter() {
|
|
|
87
1475
|
}
|
|
88
1476
|
|
|
89
1477
|
// src/haptics.ts
|
|
90
|
-
function
|
|
1478
|
+
function isDevelopment3() {
|
|
91
1479
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
92
1480
|
return nodeEnv !== "production";
|
|
93
1481
|
}
|
|
94
|
-
function
|
|
1482
|
+
function getBridgeWindow3() {
|
|
95
1483
|
if (typeof window === "undefined") {
|
|
96
1484
|
return void 0;
|
|
97
1485
|
}
|
|
98
1486
|
return window;
|
|
99
1487
|
}
|
|
100
1488
|
function triggerHaptic(type) {
|
|
101
|
-
const bridge =
|
|
1489
|
+
const bridge = getBridgeWindow3();
|
|
102
1490
|
if (typeof bridge?.triggerHaptic === "function") {
|
|
103
1491
|
bridge.triggerHaptic(type);
|
|
104
1492
|
return;
|
|
105
1493
|
}
|
|
106
|
-
if (
|
|
1494
|
+
if (isDevelopment3()) {
|
|
107
1495
|
console.warn(
|
|
108
1496
|
"[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
|
|
109
1497
|
);
|
|
@@ -130,7 +1518,7 @@ var MIN_EXPANDED_WIDTH = 160;
|
|
|
130
1518
|
var MIN_EXPANDED_HEIGHT = 110;
|
|
131
1519
|
var RESIZE_HOTSPOT_PX = 28;
|
|
132
1520
|
var TOP_DRAG_ZONE_PX = 44;
|
|
133
|
-
var
|
|
1521
|
+
var NOOP_HANDLE2 = {
|
|
134
1522
|
clear() {
|
|
135
1523
|
},
|
|
136
1524
|
destroy() {
|
|
@@ -143,13 +1531,13 @@ var NOOP_HANDLE = {
|
|
|
143
1531
|
show() {
|
|
144
1532
|
}
|
|
145
1533
|
};
|
|
146
|
-
function
|
|
1534
|
+
function getBrowserWindow2() {
|
|
147
1535
|
if (typeof window === "undefined") {
|
|
148
1536
|
return void 0;
|
|
149
1537
|
}
|
|
150
1538
|
return window;
|
|
151
1539
|
}
|
|
152
|
-
function
|
|
1540
|
+
function getDocument2() {
|
|
153
1541
|
if (typeof document === "undefined") {
|
|
154
1542
|
return void 0;
|
|
155
1543
|
}
|
|
@@ -235,7 +1623,7 @@ function createEntry(level, args, id) {
|
|
|
235
1623
|
timestamp: Date.now()
|
|
236
1624
|
};
|
|
237
1625
|
}
|
|
238
|
-
function
|
|
1626
|
+
function createButton2(label) {
|
|
239
1627
|
const button = document.createElement("button");
|
|
240
1628
|
button.type = "button";
|
|
241
1629
|
button.textContent = label;
|
|
@@ -277,7 +1665,7 @@ function getLevelAccent(level) {
|
|
|
277
1665
|
};
|
|
278
1666
|
}
|
|
279
1667
|
function getViewportSize() {
|
|
280
|
-
const browserWindow =
|
|
1668
|
+
const browserWindow = getBrowserWindow2();
|
|
281
1669
|
return {
|
|
282
1670
|
width: Math.max(320, browserWindow?.innerWidth ?? 1280),
|
|
283
1671
|
height: Math.max(240, browserWindow?.innerHeight ?? 720)
|
|
@@ -407,7 +1795,7 @@ function stopResizing(state) {
|
|
|
407
1795
|
state.removeResizeListeners = null;
|
|
408
1796
|
}
|
|
409
1797
|
function beginDragTracking(state, startPoint) {
|
|
410
|
-
const doc =
|
|
1798
|
+
const doc = getDocument2();
|
|
411
1799
|
if (!doc) {
|
|
412
1800
|
return;
|
|
413
1801
|
}
|
|
@@ -474,7 +1862,7 @@ function beginDragTracking(state, startPoint) {
|
|
|
474
1862
|
};
|
|
475
1863
|
}
|
|
476
1864
|
function startResizing(state, startPoint) {
|
|
477
|
-
const doc =
|
|
1865
|
+
const doc = getDocument2();
|
|
478
1866
|
if (!doc) {
|
|
479
1867
|
return;
|
|
480
1868
|
}
|
|
@@ -560,7 +1948,7 @@ function attachDragStartListeners(element, state, options = {}) {
|
|
|
560
1948
|
}
|
|
561
1949
|
function attachCollapsedToggleListeners(element, state) {
|
|
562
1950
|
const startToggleInteraction = (startPoint) => {
|
|
563
|
-
const doc =
|
|
1951
|
+
const doc = getDocument2();
|
|
564
1952
|
if (!doc) {
|
|
565
1953
|
return;
|
|
566
1954
|
}
|
|
@@ -636,7 +2024,7 @@ function createOverlayUi(state) {
|
|
|
636
2024
|
"width:min(565px, calc(100vw - 24px))",
|
|
637
2025
|
"pointer-events:none"
|
|
638
2026
|
].join(";");
|
|
639
|
-
const toggleButton =
|
|
2027
|
+
const toggleButton = createButton2("Logs");
|
|
640
2028
|
toggleButton.style.pointerEvents = "auto";
|
|
641
2029
|
toggleButton.style.alignSelf = "flex-end";
|
|
642
2030
|
toggleButton.style.display = "inline-flex";
|
|
@@ -690,7 +2078,7 @@ function createOverlayUi(state) {
|
|
|
690
2078
|
"gap:8px",
|
|
691
2079
|
"pointer-events:auto"
|
|
692
2080
|
].join(";");
|
|
693
|
-
const clearButton =
|
|
2081
|
+
const clearButton = createButton2("Clear");
|
|
694
2082
|
clearButton.style.background = "rgba(255,255,255,0.1)";
|
|
695
2083
|
clearButton.style.border = "1px solid rgba(255,255,255,0.16)";
|
|
696
2084
|
clearButton.style.color = "#eef6ff";
|
|
@@ -698,7 +2086,7 @@ function createOverlayUi(state) {
|
|
|
698
2086
|
clearButton.style.padding = "4px 9px";
|
|
699
2087
|
clearButton.style.fontSize = "11px";
|
|
700
2088
|
clearButton.style.backdropFilter = "blur(8px)";
|
|
701
|
-
const collapseButton =
|
|
2089
|
+
const collapseButton = createButton2("Hide");
|
|
702
2090
|
collapseButton.style.background = "rgba(113, 171, 255, 0.12)";
|
|
703
2091
|
collapseButton.style.border = "1px solid rgba(113, 171, 255, 0.2)";
|
|
704
2092
|
collapseButton.style.color = "#d9ebff";
|
|
@@ -824,7 +2212,7 @@ function renderOverlay(state) {
|
|
|
824
2212
|
applyOverlayPosition(state);
|
|
825
2213
|
}
|
|
826
2214
|
function mountOverlay(state) {
|
|
827
|
-
const doc =
|
|
2215
|
+
const doc = getDocument2();
|
|
828
2216
|
if (!doc?.body || state.ui) {
|
|
829
2217
|
return;
|
|
830
2218
|
}
|
|
@@ -864,7 +2252,7 @@ function cleanupOverlay(browserWindow, state) {
|
|
|
864
2252
|
stopResizing(state);
|
|
865
2253
|
stopDragging(state);
|
|
866
2254
|
if (state.domReadyHandler) {
|
|
867
|
-
|
|
2255
|
+
getDocument2()?.removeEventListener("DOMContentLoaded", state.domReadyHandler);
|
|
868
2256
|
state.domReadyHandler = void 0;
|
|
869
2257
|
}
|
|
870
2258
|
if (state.resizeHandler && typeof browserWindow.removeEventListener === "function") {
|
|
@@ -883,7 +2271,7 @@ function createController(browserWindow, state) {
|
|
|
883
2271
|
this.ensureMounted();
|
|
884
2272
|
},
|
|
885
2273
|
ensureMounted() {
|
|
886
|
-
const doc =
|
|
2274
|
+
const doc = getDocument2();
|
|
887
2275
|
if (!doc) {
|
|
888
2276
|
return;
|
|
889
2277
|
}
|
|
@@ -929,12 +2317,12 @@ function createController(browserWindow, state) {
|
|
|
929
2317
|
}
|
|
930
2318
|
function enableLogOverlay(options = {}) {
|
|
931
2319
|
if (options.enabled === false) {
|
|
932
|
-
return
|
|
2320
|
+
return NOOP_HANDLE2;
|
|
933
2321
|
}
|
|
934
|
-
const browserWindow =
|
|
935
|
-
const doc =
|
|
2322
|
+
const browserWindow = getBrowserWindow2();
|
|
2323
|
+
const doc = getDocument2();
|
|
936
2324
|
if (!browserWindow || !doc) {
|
|
937
|
-
return
|
|
2325
|
+
return NOOP_HANDLE2;
|
|
938
2326
|
}
|
|
939
2327
|
const existingController = browserWindow.__oasizLogOverlayController__;
|
|
940
2328
|
const existingState = browserWindow.__oasizLogOverlayState__;
|
|
@@ -1002,74 +2390,74 @@ function enableLogOverlay(options = {}) {
|
|
|
1002
2390
|
}
|
|
1003
2391
|
|
|
1004
2392
|
// src/multiplayer.ts
|
|
1005
|
-
function
|
|
2393
|
+
function isDevelopment4() {
|
|
1006
2394
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1007
2395
|
return nodeEnv !== "production";
|
|
1008
2396
|
}
|
|
1009
|
-
function
|
|
2397
|
+
function getBridgeWindow4() {
|
|
1010
2398
|
if (typeof window === "undefined") {
|
|
1011
2399
|
return void 0;
|
|
1012
2400
|
}
|
|
1013
2401
|
return window;
|
|
1014
2402
|
}
|
|
1015
2403
|
function shareRoomCode(roomCode, options) {
|
|
1016
|
-
const bridge =
|
|
2404
|
+
const bridge = getBridgeWindow4();
|
|
1017
2405
|
if (typeof bridge?.shareRoomCode === "function") {
|
|
1018
2406
|
bridge.shareRoomCode(roomCode, options);
|
|
1019
2407
|
return;
|
|
1020
2408
|
}
|
|
1021
|
-
if (
|
|
2409
|
+
if (isDevelopment4()) {
|
|
1022
2410
|
console.warn(
|
|
1023
2411
|
"[oasiz/sdk] shareRoomCode bridge is unavailable. This is expected in local development."
|
|
1024
2412
|
);
|
|
1025
2413
|
}
|
|
1026
2414
|
}
|
|
1027
2415
|
function openInviteModal() {
|
|
1028
|
-
const bridge =
|
|
2416
|
+
const bridge = getBridgeWindow4();
|
|
1029
2417
|
if (typeof bridge?.openInviteModal === "function") {
|
|
1030
2418
|
bridge.openInviteModal();
|
|
1031
2419
|
return;
|
|
1032
2420
|
}
|
|
1033
|
-
if (
|
|
2421
|
+
if (isDevelopment4()) {
|
|
1034
2422
|
console.warn(
|
|
1035
2423
|
"[oasiz/sdk] openInviteModal bridge is unavailable. This is expected in local development."
|
|
1036
2424
|
);
|
|
1037
2425
|
}
|
|
1038
2426
|
}
|
|
1039
2427
|
function getGameId() {
|
|
1040
|
-
const bridge =
|
|
2428
|
+
const bridge = getBridgeWindow4();
|
|
1041
2429
|
return bridge?.__GAME_ID__;
|
|
1042
2430
|
}
|
|
1043
2431
|
function getRoomCode() {
|
|
1044
|
-
const bridge =
|
|
2432
|
+
const bridge = getBridgeWindow4();
|
|
1045
2433
|
return bridge?.__ROOM_CODE__;
|
|
1046
2434
|
}
|
|
1047
2435
|
function getPlayerId() {
|
|
1048
|
-
const bridge =
|
|
2436
|
+
const bridge = getBridgeWindow4();
|
|
1049
2437
|
return bridge?.__PLAYER_ID__;
|
|
1050
2438
|
}
|
|
1051
2439
|
function getPlayerName() {
|
|
1052
|
-
const bridge =
|
|
2440
|
+
const bridge = getBridgeWindow4();
|
|
1053
2441
|
return bridge?.__PLAYER_NAME__;
|
|
1054
2442
|
}
|
|
1055
2443
|
function getPlayerAvatar() {
|
|
1056
|
-
const bridge =
|
|
2444
|
+
const bridge = getBridgeWindow4();
|
|
1057
2445
|
return bridge?.__PLAYER_AVATAR__;
|
|
1058
2446
|
}
|
|
1059
2447
|
|
|
1060
2448
|
// src/score.ts
|
|
1061
|
-
function
|
|
2449
|
+
function isDevelopment5() {
|
|
1062
2450
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1063
2451
|
return nodeEnv !== "production";
|
|
1064
2452
|
}
|
|
1065
|
-
function
|
|
1066
|
-
if (
|
|
2453
|
+
function warnMissingBridge3(methodName) {
|
|
2454
|
+
if (isDevelopment5()) {
|
|
1067
2455
|
console.warn(
|
|
1068
2456
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1069
2457
|
);
|
|
1070
2458
|
}
|
|
1071
2459
|
}
|
|
1072
|
-
function
|
|
2460
|
+
function getBridgeWindow5() {
|
|
1073
2461
|
if (typeof window === "undefined") {
|
|
1074
2462
|
return void 0;
|
|
1075
2463
|
}
|
|
@@ -1077,49 +2465,49 @@ function getBridgeWindow4() {
|
|
|
1077
2465
|
}
|
|
1078
2466
|
function submitScore(score) {
|
|
1079
2467
|
if (!Number.isFinite(score)) {
|
|
1080
|
-
if (
|
|
2468
|
+
if (isDevelopment5()) {
|
|
1081
2469
|
console.warn("[oasiz/sdk] submitScore expected a finite number:", score);
|
|
1082
2470
|
}
|
|
1083
2471
|
return;
|
|
1084
2472
|
}
|
|
1085
|
-
const bridge =
|
|
2473
|
+
const bridge = getBridgeWindow5();
|
|
1086
2474
|
const normalizedScore = Math.max(0, Math.floor(score));
|
|
1087
2475
|
if (typeof bridge?.submitScore === "function") {
|
|
1088
2476
|
bridge.submitScore(normalizedScore);
|
|
1089
2477
|
return;
|
|
1090
2478
|
}
|
|
1091
|
-
|
|
2479
|
+
warnMissingBridge3("submitScore");
|
|
1092
2480
|
}
|
|
1093
2481
|
|
|
1094
2482
|
// src/score-edit.ts
|
|
1095
|
-
function
|
|
2483
|
+
function isDevelopment6() {
|
|
1096
2484
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1097
2485
|
return nodeEnv !== "production";
|
|
1098
2486
|
}
|
|
1099
|
-
function
|
|
2487
|
+
function getBridgeWindow6() {
|
|
1100
2488
|
if (typeof window === "undefined") {
|
|
1101
2489
|
return void 0;
|
|
1102
2490
|
}
|
|
1103
2491
|
return window;
|
|
1104
2492
|
}
|
|
1105
|
-
function
|
|
1106
|
-
if (
|
|
2493
|
+
function warnMissingBridge4(methodName) {
|
|
2494
|
+
if (isDevelopment6()) {
|
|
1107
2495
|
console.warn(
|
|
1108
2496
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1109
2497
|
);
|
|
1110
2498
|
}
|
|
1111
2499
|
}
|
|
1112
2500
|
async function editScore(payload, methodName) {
|
|
1113
|
-
const bridge =
|
|
2501
|
+
const bridge = getBridgeWindow6();
|
|
1114
2502
|
if (typeof bridge?.__oasizEditScore !== "function") {
|
|
1115
|
-
|
|
2503
|
+
warnMissingBridge4(methodName);
|
|
1116
2504
|
return null;
|
|
1117
2505
|
}
|
|
1118
2506
|
try {
|
|
1119
2507
|
const result = await bridge.__oasizEditScore(payload);
|
|
1120
2508
|
return result ?? null;
|
|
1121
2509
|
} catch (error) {
|
|
1122
|
-
if (
|
|
2510
|
+
if (isDevelopment6()) {
|
|
1123
2511
|
console.error("[oasiz/sdk] " + methodName + " failed:", error);
|
|
1124
2512
|
}
|
|
1125
2513
|
return null;
|
|
@@ -1127,7 +2515,7 @@ async function editScore(payload, methodName) {
|
|
|
1127
2515
|
}
|
|
1128
2516
|
async function addScore(delta) {
|
|
1129
2517
|
if (!Number.isInteger(delta)) {
|
|
1130
|
-
if (
|
|
2518
|
+
if (isDevelopment6()) {
|
|
1131
2519
|
console.warn("[oasiz/sdk] addScore expected an integer:", delta);
|
|
1132
2520
|
}
|
|
1133
2521
|
return null;
|
|
@@ -1139,7 +2527,7 @@ async function addScore(delta) {
|
|
|
1139
2527
|
}
|
|
1140
2528
|
async function setScore(score) {
|
|
1141
2529
|
if (!Number.isInteger(score) || score < 0) {
|
|
1142
|
-
if (
|
|
2530
|
+
if (isDevelopment6()) {
|
|
1143
2531
|
console.warn(
|
|
1144
2532
|
"[oasiz/sdk] setScore expected a non-negative integer:",
|
|
1145
2533
|
score
|
|
@@ -1151,18 +2539,18 @@ async function setScore(score) {
|
|
|
1151
2539
|
}
|
|
1152
2540
|
|
|
1153
2541
|
// src/share.ts
|
|
1154
|
-
function
|
|
2542
|
+
function isDevelopment7() {
|
|
1155
2543
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1156
2544
|
return nodeEnv !== "production";
|
|
1157
2545
|
}
|
|
1158
|
-
function
|
|
2546
|
+
function getBridgeWindow7() {
|
|
1159
2547
|
if (typeof window === "undefined") {
|
|
1160
2548
|
return void 0;
|
|
1161
2549
|
}
|
|
1162
2550
|
return window;
|
|
1163
2551
|
}
|
|
1164
|
-
function
|
|
1165
|
-
if (
|
|
2552
|
+
function warnMissingBridge5(methodName) {
|
|
2553
|
+
if (isDevelopment7()) {
|
|
1166
2554
|
console.warn(
|
|
1167
2555
|
"[oasiz/sdk] " + methodName + " share bridge is unavailable. This is expected in local development."
|
|
1168
2556
|
);
|
|
@@ -1205,20 +2593,20 @@ function validateRequest(options) {
|
|
|
1205
2593
|
}
|
|
1206
2594
|
async function share(options) {
|
|
1207
2595
|
const request = validateRequest(options);
|
|
1208
|
-
const bridge =
|
|
2596
|
+
const bridge = getBridgeWindow7();
|
|
1209
2597
|
if (typeof bridge?.__oasizShareRequest !== "function") {
|
|
1210
|
-
|
|
2598
|
+
warnMissingBridge5("__oasizShareRequest");
|
|
1211
2599
|
throw new Error("Share bridge unavailable");
|
|
1212
2600
|
}
|
|
1213
2601
|
await bridge.__oasizShareRequest(request);
|
|
1214
2602
|
}
|
|
1215
2603
|
|
|
1216
2604
|
// src/state.ts
|
|
1217
|
-
function
|
|
2605
|
+
function isDevelopment8() {
|
|
1218
2606
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1219
2607
|
return nodeEnv !== "production";
|
|
1220
2608
|
}
|
|
1221
|
-
function
|
|
2609
|
+
function getBridgeWindow8() {
|
|
1222
2610
|
if (typeof window === "undefined") {
|
|
1223
2611
|
return void 0;
|
|
1224
2612
|
}
|
|
@@ -1231,22 +2619,22 @@ function isPlainObject(value) {
|
|
|
1231
2619
|
const proto = Object.getPrototypeOf(value);
|
|
1232
2620
|
return proto === Object.prototype || proto === null;
|
|
1233
2621
|
}
|
|
1234
|
-
function
|
|
1235
|
-
if (
|
|
2622
|
+
function warnMissingBridge6(methodName) {
|
|
2623
|
+
if (isDevelopment8()) {
|
|
1236
2624
|
console.warn(
|
|
1237
2625
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1238
2626
|
);
|
|
1239
2627
|
}
|
|
1240
2628
|
}
|
|
1241
2629
|
function loadGameState() {
|
|
1242
|
-
const bridge =
|
|
2630
|
+
const bridge = getBridgeWindow8();
|
|
1243
2631
|
if (typeof bridge?.loadGameState !== "function") {
|
|
1244
|
-
|
|
2632
|
+
warnMissingBridge6("loadGameState");
|
|
1245
2633
|
return {};
|
|
1246
2634
|
}
|
|
1247
2635
|
const state = bridge.loadGameState();
|
|
1248
2636
|
if (!isPlainObject(state)) {
|
|
1249
|
-
if (
|
|
2637
|
+
if (isDevelopment8()) {
|
|
1250
2638
|
console.warn(
|
|
1251
2639
|
"[oasiz/sdk] loadGameState returned invalid data. Falling back to empty object."
|
|
1252
2640
|
);
|
|
@@ -1257,35 +2645,35 @@ function loadGameState() {
|
|
|
1257
2645
|
}
|
|
1258
2646
|
function saveGameState(state) {
|
|
1259
2647
|
if (!isPlainObject(state)) {
|
|
1260
|
-
if (
|
|
2648
|
+
if (isDevelopment8()) {
|
|
1261
2649
|
console.warn("[oasiz/sdk] saveGameState expected a plain object:", state);
|
|
1262
2650
|
}
|
|
1263
2651
|
return;
|
|
1264
2652
|
}
|
|
1265
|
-
const bridge =
|
|
2653
|
+
const bridge = getBridgeWindow8();
|
|
1266
2654
|
if (typeof bridge?.saveGameState === "function") {
|
|
1267
2655
|
bridge.saveGameState(state);
|
|
1268
2656
|
return;
|
|
1269
2657
|
}
|
|
1270
|
-
|
|
2658
|
+
warnMissingBridge6("saveGameState");
|
|
1271
2659
|
}
|
|
1272
2660
|
function flushGameState() {
|
|
1273
|
-
const bridge =
|
|
2661
|
+
const bridge = getBridgeWindow8();
|
|
1274
2662
|
if (typeof bridge?.flushGameState === "function") {
|
|
1275
2663
|
bridge.flushGameState();
|
|
1276
2664
|
return;
|
|
1277
2665
|
}
|
|
1278
|
-
|
|
2666
|
+
warnMissingBridge6("flushGameState");
|
|
1279
2667
|
}
|
|
1280
2668
|
|
|
1281
2669
|
// src/lifecycle.ts
|
|
1282
|
-
function
|
|
2670
|
+
function isDevelopment9() {
|
|
1283
2671
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1284
2672
|
return nodeEnv !== "production";
|
|
1285
2673
|
}
|
|
1286
2674
|
function addLifecycleListener(eventName, callback) {
|
|
1287
2675
|
if (typeof window === "undefined") {
|
|
1288
|
-
if (
|
|
2676
|
+
if (isDevelopment9()) {
|
|
1289
2677
|
console.warn(
|
|
1290
2678
|
"[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
|
|
1291
2679
|
);
|
|
@@ -1320,24 +2708,24 @@ function createInsetEdges(value) {
|
|
|
1320
2708
|
left: value
|
|
1321
2709
|
};
|
|
1322
2710
|
}
|
|
1323
|
-
function
|
|
2711
|
+
function isDevelopment10() {
|
|
1324
2712
|
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1325
2713
|
return nodeEnv !== "production";
|
|
1326
2714
|
}
|
|
1327
|
-
function
|
|
2715
|
+
function getBridgeWindow9() {
|
|
1328
2716
|
if (typeof window === "undefined") {
|
|
1329
2717
|
return void 0;
|
|
1330
2718
|
}
|
|
1331
2719
|
return window;
|
|
1332
2720
|
}
|
|
1333
|
-
function
|
|
1334
|
-
if (
|
|
2721
|
+
function warnMissingBridge7(methodName) {
|
|
2722
|
+
if (isDevelopment10()) {
|
|
1335
2723
|
console.warn(
|
|
1336
2724
|
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1337
2725
|
);
|
|
1338
2726
|
}
|
|
1339
2727
|
}
|
|
1340
|
-
function
|
|
2728
|
+
function isRecord2(value) {
|
|
1341
2729
|
return typeof value === "object" && value !== null;
|
|
1342
2730
|
}
|
|
1343
2731
|
function toFiniteNumber(value) {
|
|
@@ -1506,11 +2894,11 @@ function callBridgeFunction(bridge, name) {
|
|
|
1506
2894
|
}
|
|
1507
2895
|
}
|
|
1508
2896
|
function readInsetObjectValue(value, side, group) {
|
|
1509
|
-
if (!
|
|
2897
|
+
if (!isRecord2(value)) {
|
|
1510
2898
|
return void 0;
|
|
1511
2899
|
}
|
|
1512
2900
|
if (group) {
|
|
1513
|
-
return
|
|
2901
|
+
return isRecord2(value[group]) ? value[group][side] : void 0;
|
|
1514
2902
|
}
|
|
1515
2903
|
return value[side];
|
|
1516
2904
|
}
|
|
@@ -1583,7 +2971,7 @@ function resolveInsetSide(bridge, sources, side) {
|
|
|
1583
2971
|
};
|
|
1584
2972
|
}
|
|
1585
2973
|
function getViewportInsets() {
|
|
1586
|
-
const bridge =
|
|
2974
|
+
const bridge = getBridgeWindow9();
|
|
1587
2975
|
if (!bridge) {
|
|
1588
2976
|
return {
|
|
1589
2977
|
pixels: createInsetEdges(0),
|
|
@@ -1601,19 +2989,19 @@ function getViewportInsets() {
|
|
|
1601
2989
|
return { pixels, percent };
|
|
1602
2990
|
}
|
|
1603
2991
|
function getSafeAreaTop() {
|
|
1604
|
-
const bridge =
|
|
2992
|
+
const bridge = getBridgeWindow9();
|
|
1605
2993
|
if (!bridge) {
|
|
1606
2994
|
return 0;
|
|
1607
2995
|
}
|
|
1608
2996
|
const top = getViewportInsets().percent.top;
|
|
1609
2997
|
if (top <= 0) {
|
|
1610
|
-
|
|
2998
|
+
warnMissingBridge7("getSafeAreaTop");
|
|
1611
2999
|
}
|
|
1612
3000
|
return top;
|
|
1613
3001
|
}
|
|
1614
3002
|
function setLeaderboardVisible(visible) {
|
|
1615
3003
|
if (typeof visible !== "boolean") {
|
|
1616
|
-
if (
|
|
3004
|
+
if (isDevelopment10()) {
|
|
1617
3005
|
console.warn(
|
|
1618
3006
|
"[oasiz/sdk] setLeaderboardVisible expected a boolean:",
|
|
1619
3007
|
visible
|
|
@@ -1621,253 +3009,12 @@ function setLeaderboardVisible(visible) {
|
|
|
1621
3009
|
}
|
|
1622
3010
|
return;
|
|
1623
3011
|
}
|
|
1624
|
-
const bridge =
|
|
3012
|
+
const bridge = getBridgeWindow9();
|
|
1625
3013
|
if (typeof bridge?.__oasizSetLeaderboardVisible === "function") {
|
|
1626
3014
|
bridge.__oasizSetLeaderboardVisible(visible);
|
|
1627
3015
|
return;
|
|
1628
3016
|
}
|
|
1629
|
-
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
// src/navigation.ts
|
|
1633
|
-
var BACK_BUTTON_TEST_STATE_KEY = "__oasizBackButtonTest";
|
|
1634
|
-
var activeBackListeners = 0;
|
|
1635
|
-
var activeBackButtonTestingHandle;
|
|
1636
|
-
function isDevelopment10() {
|
|
1637
|
-
const nodeEnv = globalThis.process?.env?.NODE_ENV;
|
|
1638
|
-
return nodeEnv !== "production";
|
|
1639
|
-
}
|
|
1640
|
-
function getBridgeWindow9() {
|
|
1641
|
-
if (typeof window === "undefined") {
|
|
1642
|
-
return void 0;
|
|
1643
|
-
}
|
|
1644
|
-
return window;
|
|
1645
|
-
}
|
|
1646
|
-
function warnMissingBridge7(methodName) {
|
|
1647
|
-
if (isDevelopment10()) {
|
|
1648
|
-
console.warn(
|
|
1649
|
-
"[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
|
|
1650
|
-
);
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
function normalizeNavigationError(error) {
|
|
1654
|
-
if (error instanceof Error) {
|
|
1655
|
-
return error;
|
|
1656
|
-
}
|
|
1657
|
-
return new Error(
|
|
1658
|
-
typeof error === "string" ? error : "Back button callback failed."
|
|
1659
|
-
);
|
|
1660
|
-
}
|
|
1661
|
-
function isRecord2(value) {
|
|
1662
|
-
return typeof value === "object" && value !== null;
|
|
1663
|
-
}
|
|
1664
|
-
function dispatchNavigationEvent(eventName) {
|
|
1665
|
-
const bridge = getBridgeWindow9();
|
|
1666
|
-
if (!bridge || typeof bridge.dispatchEvent !== "function") {
|
|
1667
|
-
return;
|
|
1668
|
-
}
|
|
1669
|
-
bridge.dispatchEvent(new Event(eventName));
|
|
1670
|
-
}
|
|
1671
|
-
function addNavigationListener(eventName, callback) {
|
|
1672
|
-
if (typeof window === "undefined") {
|
|
1673
|
-
if (isDevelopment10()) {
|
|
1674
|
-
console.warn(
|
|
1675
|
-
"[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
|
|
1676
|
-
);
|
|
1677
|
-
}
|
|
1678
|
-
return () => {
|
|
1679
|
-
};
|
|
1680
|
-
}
|
|
1681
|
-
const handler = () => callback();
|
|
1682
|
-
window.addEventListener(eventName, handler);
|
|
1683
|
-
return () => window.removeEventListener(eventName, handler);
|
|
1684
|
-
}
|
|
1685
|
-
function enableBackButtonTesting(options = {}) {
|
|
1686
|
-
activeBackButtonTestingHandle?.destroy();
|
|
1687
|
-
const bridge = getBridgeWindow9();
|
|
1688
|
-
if (!bridge) {
|
|
1689
|
-
if (isDevelopment10()) {
|
|
1690
|
-
console.warn(
|
|
1691
|
-
"[oasiz/sdk] enableBackButtonTesting requires a browser window."
|
|
1692
|
-
);
|
|
1693
|
-
}
|
|
1694
|
-
return {
|
|
1695
|
-
destroy: () => {
|
|
1696
|
-
},
|
|
1697
|
-
isBackOverrideActive: () => false,
|
|
1698
|
-
triggerBack: () => {
|
|
1699
|
-
},
|
|
1700
|
-
triggerLeave: () => {
|
|
1701
|
-
}
|
|
1702
|
-
};
|
|
1703
|
-
}
|
|
1704
|
-
const bridgeWindow = bridge;
|
|
1705
|
-
const keyboard = options.keyboard ?? true;
|
|
1706
|
-
const browserHistory = options.browserHistory ?? true;
|
|
1707
|
-
const log = options.log === true;
|
|
1708
|
-
const previousSetBackOverride = bridgeWindow.__oasizSetBackOverride;
|
|
1709
|
-
const previousLeaveGame = bridgeWindow.__oasizLeaveGame;
|
|
1710
|
-
let destroyed = false;
|
|
1711
|
-
let backOverrideActive = false;
|
|
1712
|
-
let historyTrapArmed = false;
|
|
1713
|
-
function maybeLog(message) {
|
|
1714
|
-
if (log) {
|
|
1715
|
-
console.info("[oasiz/sdk] " + message);
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
function canUseHistoryTrap() {
|
|
1719
|
-
return browserHistory && typeof bridgeWindow.history?.pushState === "function" && typeof bridgeWindow.history?.replaceState === "function" && typeof bridgeWindow.location?.href === "string";
|
|
1720
|
-
}
|
|
1721
|
-
function ensureHistoryTrap() {
|
|
1722
|
-
if (!backOverrideActive || historyTrapArmed || !canUseHistoryTrap()) {
|
|
1723
|
-
return;
|
|
1724
|
-
}
|
|
1725
|
-
try {
|
|
1726
|
-
const currentState = isRecord2(bridgeWindow.history.state) ? bridgeWindow.history.state : {};
|
|
1727
|
-
bridgeWindow.history.replaceState(
|
|
1728
|
-
{ ...currentState, [BACK_BUTTON_TEST_STATE_KEY]: "base" },
|
|
1729
|
-
"",
|
|
1730
|
-
bridgeWindow.location.href
|
|
1731
|
-
);
|
|
1732
|
-
bridgeWindow.history.pushState(
|
|
1733
|
-
{ [BACK_BUTTON_TEST_STATE_KEY]: "trap" },
|
|
1734
|
-
"",
|
|
1735
|
-
bridgeWindow.location.href
|
|
1736
|
-
);
|
|
1737
|
-
historyTrapArmed = true;
|
|
1738
|
-
maybeLog("Local browser Back testing is armed.");
|
|
1739
|
-
} catch (error) {
|
|
1740
|
-
historyTrapArmed = false;
|
|
1741
|
-
if (log) {
|
|
1742
|
-
console.warn("[oasiz/sdk] Failed to arm browser Back testing:", error);
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
function triggerBack() {
|
|
1747
|
-
dispatchNavigationEvent("oasiz:back");
|
|
1748
|
-
}
|
|
1749
|
-
function triggerLeave() {
|
|
1750
|
-
dispatchNavigationEvent("oasiz:leave");
|
|
1751
|
-
}
|
|
1752
|
-
function setBackOverride(active) {
|
|
1753
|
-
backOverrideActive = active;
|
|
1754
|
-
if (active) {
|
|
1755
|
-
ensureHistoryTrap();
|
|
1756
|
-
}
|
|
1757
|
-
if (typeof previousSetBackOverride === "function") {
|
|
1758
|
-
previousSetBackOverride(active);
|
|
1759
|
-
}
|
|
1760
|
-
maybeLog("Back override " + (active ? "enabled" : "disabled") + ".");
|
|
1761
|
-
}
|
|
1762
|
-
function stopBackEvent(event) {
|
|
1763
|
-
event.preventDefault();
|
|
1764
|
-
event.stopPropagation();
|
|
1765
|
-
event.stopImmediatePropagation?.();
|
|
1766
|
-
}
|
|
1767
|
-
const handleKeyDown = (event) => {
|
|
1768
|
-
if (!backOverrideActive || event.key !== "Escape") {
|
|
1769
|
-
return;
|
|
1770
|
-
}
|
|
1771
|
-
stopBackEvent(event);
|
|
1772
|
-
triggerBack();
|
|
1773
|
-
};
|
|
1774
|
-
const handlePopState = (event) => {
|
|
1775
|
-
if (!backOverrideActive) {
|
|
1776
|
-
historyTrapArmed = false;
|
|
1777
|
-
return;
|
|
1778
|
-
}
|
|
1779
|
-
stopBackEvent(event);
|
|
1780
|
-
triggerBack();
|
|
1781
|
-
historyTrapArmed = false;
|
|
1782
|
-
ensureHistoryTrap();
|
|
1783
|
-
};
|
|
1784
|
-
const testLeaveGame = () => {
|
|
1785
|
-
triggerLeave();
|
|
1786
|
-
if (typeof previousLeaveGame === "function") {
|
|
1787
|
-
previousLeaveGame();
|
|
1788
|
-
}
|
|
1789
|
-
};
|
|
1790
|
-
bridgeWindow.__oasizSetBackOverride = setBackOverride;
|
|
1791
|
-
bridgeWindow.__oasizLeaveGame = testLeaveGame;
|
|
1792
|
-
if (keyboard) {
|
|
1793
|
-
bridgeWindow.addEventListener("keydown", handleKeyDown);
|
|
1794
|
-
}
|
|
1795
|
-
if (browserHistory) {
|
|
1796
|
-
bridgeWindow.addEventListener("popstate", handlePopState);
|
|
1797
|
-
}
|
|
1798
|
-
if (activeBackListeners > 0) {
|
|
1799
|
-
setBackOverride(true);
|
|
1800
|
-
}
|
|
1801
|
-
maybeLog("Back button testing bridge installed.");
|
|
1802
|
-
const handle = {
|
|
1803
|
-
destroy: () => {
|
|
1804
|
-
if (destroyed) return;
|
|
1805
|
-
destroyed = true;
|
|
1806
|
-
if (keyboard) {
|
|
1807
|
-
bridgeWindow.removeEventListener("keydown", handleKeyDown);
|
|
1808
|
-
}
|
|
1809
|
-
if (browserHistory) {
|
|
1810
|
-
bridgeWindow.removeEventListener("popstate", handlePopState);
|
|
1811
|
-
}
|
|
1812
|
-
if (bridgeWindow.__oasizSetBackOverride === setBackOverride) {
|
|
1813
|
-
bridgeWindow.__oasizSetBackOverride = previousSetBackOverride;
|
|
1814
|
-
}
|
|
1815
|
-
if (bridgeWindow.__oasizLeaveGame === testLeaveGame) {
|
|
1816
|
-
bridgeWindow.__oasizLeaveGame = previousLeaveGame;
|
|
1817
|
-
}
|
|
1818
|
-
if (activeBackButtonTestingHandle === handle) {
|
|
1819
|
-
activeBackButtonTestingHandle = void 0;
|
|
1820
|
-
}
|
|
1821
|
-
maybeLog("Back button testing bridge removed.");
|
|
1822
|
-
},
|
|
1823
|
-
isBackOverrideActive: () => backOverrideActive,
|
|
1824
|
-
triggerBack,
|
|
1825
|
-
triggerLeave
|
|
1826
|
-
};
|
|
1827
|
-
activeBackButtonTestingHandle = handle;
|
|
1828
|
-
return handle;
|
|
1829
|
-
}
|
|
1830
|
-
function onBackButton(callback) {
|
|
1831
|
-
const off = addNavigationListener("oasiz:back", () => {
|
|
1832
|
-
try {
|
|
1833
|
-
callback();
|
|
1834
|
-
} catch (error) {
|
|
1835
|
-
leaveGame();
|
|
1836
|
-
throw normalizeNavigationError(error);
|
|
1837
|
-
}
|
|
1838
|
-
});
|
|
1839
|
-
const bridge = getBridgeWindow9();
|
|
1840
|
-
activeBackListeners += 1;
|
|
1841
|
-
if (activeBackListeners === 1) {
|
|
1842
|
-
if (typeof bridge?.__oasizSetBackOverride === "function") {
|
|
1843
|
-
bridge.__oasizSetBackOverride(true);
|
|
1844
|
-
} else {
|
|
1845
|
-
warnMissingBridge7("__oasizSetBackOverride");
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
return () => {
|
|
1849
|
-
off();
|
|
1850
|
-
activeBackListeners = Math.max(0, activeBackListeners - 1);
|
|
1851
|
-
if (activeBackListeners === 0) {
|
|
1852
|
-
const currentBridge = getBridgeWindow9();
|
|
1853
|
-
if (typeof currentBridge?.__oasizSetBackOverride === "function") {
|
|
1854
|
-
currentBridge.__oasizSetBackOverride(false);
|
|
1855
|
-
} else {
|
|
1856
|
-
warnMissingBridge7("__oasizSetBackOverride");
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
};
|
|
1860
|
-
}
|
|
1861
|
-
function onLeaveGame(callback) {
|
|
1862
|
-
return addNavigationListener("oasiz:leave", callback);
|
|
1863
|
-
}
|
|
1864
|
-
function leaveGame() {
|
|
1865
|
-
const bridge = getBridgeWindow9();
|
|
1866
|
-
if (typeof bridge?.__oasizLeaveGame === "function") {
|
|
1867
|
-
bridge.__oasizLeaveGame();
|
|
1868
|
-
return;
|
|
1869
|
-
}
|
|
1870
|
-
warnMissingBridge7("__oasizLeaveGame");
|
|
3017
|
+
warnMissingBridge7("__oasizSetLeaderboardVisible");
|
|
1871
3018
|
}
|
|
1872
3019
|
|
|
1873
3020
|
// src/performance.ts
|
|
@@ -2196,6 +3343,7 @@ function getGraphicsPerformance() {
|
|
|
2196
3343
|
// src/index.ts
|
|
2197
3344
|
var oasiz = {
|
|
2198
3345
|
submitScore,
|
|
3346
|
+
enableAppSimulator,
|
|
2199
3347
|
addScore,
|
|
2200
3348
|
setScore,
|
|
2201
3349
|
getPlayerCharacter,
|
|
@@ -2245,6 +3393,7 @@ var oasiz = {
|
|
|
2245
3393
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2246
3394
|
0 && (module.exports = {
|
|
2247
3395
|
addScore,
|
|
3396
|
+
enableAppSimulator,
|
|
2248
3397
|
enableBackButtonTesting,
|
|
2249
3398
|
enableLogOverlay,
|
|
2250
3399
|
flushGameState,
|