@oasiz/sdk 1.5.4 → 1.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -196,11 +196,11 @@ private onGameOver(): void {
196
196
 
197
197
  ### Layout
198
198
 
199
- Use the runtime safe-area value instead of hardcoded top offsets. The SDK returns the top inset as **a percentage of the viewport height (0–100)**. If the host exposes CSS pixels via `window.getSafeAreaTop()` or `window.__OASIZ_SAFE_AREA_TOP__`, the SDK converts using `window.innerHeight`. The host may instead set **`window.getSafeAreaTopPercent()`** or **`window.__OASIZ_SAFE_AREA_TOP_PERCENT__`** (0–100) and that value is used directly.
199
+ Use the runtime safe-area value instead of hardcoded top offsets. The SDK returns the top inset as **a percentage of the active viewport height (0–100)**. If the host exposes CSS pixels via `window.getSafeAreaTop()` or `window.__OASIZ_SAFE_AREA_TOP__`, the SDK converts using `window.visualViewport.height` when available, then `window.innerHeight`, then document height. The host may instead set **`window.getSafeAreaTopPercent()`** or **`window.__OASIZ_SAFE_AREA_TOP_PERCENT__`** (0–100) and that value is used directly. When no host bridge is available, the SDK falls back to CSS `env(safe-area-inset-top)` / `constant(safe-area-inset-top)`.
200
200
 
201
201
  #### `oasiz.getSafeAreaTop(): number`
202
202
 
203
- Returns the top inset as a percentage of viewport height (0–100). To get pixels in JavaScript, use `(getSafeAreaTop() / 100) * window.innerHeight`. In CSS, the same value matches **`vh`** units (for example `12.5vh` for 12.5% of the viewport height). Unsupported hosts return `0`.
203
+ Returns the top inset as a percentage of viewport height (0–100). To get pixels in JavaScript, multiply by `window.visualViewport?.height || window.innerHeight`. In CSS, the same value matches **`vh`** units (for example `12.5vh` for 12.5% of the viewport height). Unsupported hosts return `0`.
204
204
 
205
205
  ```ts
206
206
  const safeTopPct = oasiz.getSafeAreaTop();
package/dist/index.cjs CHANGED
@@ -1319,31 +1319,130 @@ function warnMissingBridge6(methodName) {
1319
1319
  );
1320
1320
  }
1321
1321
  }
1322
- function normalizeSafeAreaTopPixels(value) {
1322
+ function toFiniteNumber(value) {
1323
1323
  if (typeof value !== "number" || !Number.isFinite(value)) {
1324
+ if (typeof value !== "string") {
1325
+ return void 0;
1326
+ }
1327
+ const parsed = Number.parseFloat(value.trim());
1328
+ if (!Number.isFinite(parsed)) {
1329
+ return void 0;
1330
+ }
1331
+ return parsed;
1332
+ }
1333
+ return value;
1334
+ }
1335
+ function clampSafeAreaTopPixels(value) {
1336
+ const numeric = toFiniteNumber(value);
1337
+ if (typeof numeric === "undefined") {
1324
1338
  return 0;
1325
1339
  }
1326
- return Math.max(0, value);
1340
+ return Math.max(0, numeric);
1327
1341
  }
1328
1342
  function normalizeSafeAreaTopPercent(value) {
1329
- if (typeof value !== "number" || !Number.isFinite(value)) {
1330
- return 0;
1343
+ const numeric = toFiniteNumber(value);
1344
+ if (typeof numeric === "undefined") {
1345
+ return void 0;
1331
1346
  }
1332
- return Math.min(100, Math.max(0, value));
1347
+ return Math.min(100, Math.max(0, numeric));
1333
1348
  }
1334
- function viewportInnerHeight(bridge) {
1335
- const h = bridge.innerHeight;
1336
- if (typeof h !== "number" || !Number.isFinite(h) || h <= 0) {
1349
+ function getViewportHeight(bridge) {
1350
+ const visualViewportHeight = bridge.visualViewport?.height;
1351
+ if (typeof visualViewportHeight === "number" && Number.isFinite(visualViewportHeight) && visualViewportHeight > 0) {
1352
+ return visualViewportHeight;
1353
+ }
1354
+ const innerHeight = bridge.innerHeight;
1355
+ if (typeof innerHeight === "number" && Number.isFinite(innerHeight) && innerHeight > 0) {
1356
+ return innerHeight;
1357
+ }
1358
+ const documentHeight = bridge.document?.documentElement?.clientHeight;
1359
+ if (typeof documentHeight === "number" && Number.isFinite(documentHeight) && documentHeight > 0) {
1360
+ return documentHeight;
1361
+ }
1362
+ const bodyHeight = bridge.document?.body?.clientHeight;
1363
+ if (typeof bodyHeight === "number" && Number.isFinite(bodyHeight) && bodyHeight > 0) {
1364
+ return bodyHeight;
1365
+ }
1366
+ return 0;
1367
+ }
1368
+ function readCssSafeAreaValue(bridge, cssValue) {
1369
+ const doc = bridge.document;
1370
+ const root = doc?.body ?? doc?.documentElement;
1371
+ if (!doc || !root || typeof doc.createElement !== "function" || typeof root.appendChild !== "function" || typeof bridge.getComputedStyle !== "function") {
1337
1372
  return 0;
1338
1373
  }
1339
- return h;
1374
+ const probe = doc.createElement("div");
1375
+ probe.style.position = "fixed";
1376
+ probe.style.top = "0";
1377
+ probe.style.left = "0";
1378
+ probe.style.width = "0";
1379
+ probe.style.height = "0";
1380
+ probe.style.visibility = "hidden";
1381
+ probe.style.pointerEvents = "none";
1382
+ probe.style.paddingTop = cssValue;
1383
+ root.appendChild(probe);
1384
+ try {
1385
+ return clampSafeAreaTopPixels(bridge.getComputedStyle(probe).paddingTop);
1386
+ } finally {
1387
+ if (typeof probe.remove === "function") {
1388
+ probe.remove();
1389
+ } else {
1390
+ probe.parentNode?.removeChild(probe);
1391
+ }
1392
+ }
1393
+ }
1394
+ function readCssSafeAreaTopPixels(bridge) {
1395
+ const envPixels = readCssSafeAreaValue(bridge, "env(safe-area-inset-top)");
1396
+ if (envPixels > 0) {
1397
+ return envPixels;
1398
+ }
1399
+ return readCssSafeAreaValue(bridge, "constant(safe-area-inset-top)");
1400
+ }
1401
+ function getDevicePixelRatio(bridge) {
1402
+ const dpr = bridge.devicePixelRatio;
1403
+ if (typeof dpr !== "number" || !Number.isFinite(dpr) || dpr <= 0) {
1404
+ return 1;
1405
+ }
1406
+ return dpr;
1407
+ }
1408
+ function roughlyEqualPixels(a, b) {
1409
+ return Math.abs(a - b) <= 2;
1410
+ }
1411
+ function normalizeSafeAreaTopPixels(value, bridge) {
1412
+ const pixels = clampSafeAreaTopPixels(value);
1413
+ const cssEnvPixels = readCssSafeAreaTopPixels(bridge);
1414
+ if (pixels <= 0) {
1415
+ return cssEnvPixels;
1416
+ }
1417
+ const dpr = getDevicePixelRatio(bridge);
1418
+ if (cssEnvPixels > 0 && dpr > 1 && roughlyEqualPixels(pixels / dpr, cssEnvPixels)) {
1419
+ return cssEnvPixels;
1420
+ }
1421
+ return pixels;
1340
1422
  }
1341
1423
  function pixelsTopToPercentOfViewport(pixels, bridge) {
1342
- const h = viewportInnerHeight(bridge);
1424
+ const h = getViewportHeight(bridge);
1343
1425
  if (h <= 0) {
1344
1426
  return 0;
1345
1427
  }
1346
- return normalizeSafeAreaTopPercent(pixels / h * 100);
1428
+ return normalizeSafeAreaTopPercent(pixels / h * 100) ?? 0;
1429
+ }
1430
+ function cssSafeAreaTopPercent(bridge) {
1431
+ return pixelsTopToPercentOfViewport(readCssSafeAreaTopPixels(bridge), bridge);
1432
+ }
1433
+ function resolvePercentValue(value, bridge) {
1434
+ const percent = normalizeSafeAreaTopPercent(value);
1435
+ if (typeof percent === "undefined") {
1436
+ return void 0;
1437
+ }
1438
+ return percent > 0 ? percent : cssSafeAreaTopPercent(bridge);
1439
+ }
1440
+ function resolvePixelValue(value, bridge) {
1441
+ const numeric = toFiniteNumber(value);
1442
+ if (typeof numeric === "undefined") {
1443
+ return void 0;
1444
+ }
1445
+ return pixelsTopToPercentOfViewport(normalizeSafeAreaTopPixels(numeric, bridge), bridge);
1347
1446
  }
1348
1447
  function getSafeAreaTop() {
1349
1448
  const bridge = getBridgeWindow8();
@@ -1351,18 +1450,32 @@ function getSafeAreaTop() {
1351
1450
  return 0;
1352
1451
  }
1353
1452
  if (typeof bridge.getSafeAreaTopPercent === "function") {
1354
- return normalizeSafeAreaTopPercent(bridge.getSafeAreaTopPercent());
1453
+ const percent = resolvePercentValue(bridge.getSafeAreaTopPercent(), bridge);
1454
+ if (typeof percent !== "undefined") {
1455
+ return percent;
1456
+ }
1355
1457
  }
1356
1458
  if (typeof bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__ !== "undefined") {
1357
- return normalizeSafeAreaTopPercent(bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__);
1459
+ const percent = resolvePercentValue(bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__, bridge);
1460
+ if (typeof percent !== "undefined") {
1461
+ return percent;
1462
+ }
1358
1463
  }
1359
1464
  if (typeof bridge.getSafeAreaTop === "function") {
1360
- const px = normalizeSafeAreaTopPixels(bridge.getSafeAreaTop());
1361
- return pixelsTopToPercentOfViewport(px, bridge);
1465
+ const percent = resolvePixelValue(bridge.getSafeAreaTop(), bridge);
1466
+ if (typeof percent !== "undefined") {
1467
+ return percent;
1468
+ }
1362
1469
  }
1363
1470
  if (typeof bridge.__OASIZ_SAFE_AREA_TOP__ !== "undefined") {
1364
- const px = normalizeSafeAreaTopPixels(bridge.__OASIZ_SAFE_AREA_TOP__);
1365
- return pixelsTopToPercentOfViewport(px, bridge);
1471
+ const percent = resolvePixelValue(bridge.__OASIZ_SAFE_AREA_TOP__, bridge);
1472
+ if (typeof percent !== "undefined") {
1473
+ return percent;
1474
+ }
1475
+ }
1476
+ const cssPercent = cssSafeAreaTopPercent(bridge);
1477
+ if (cssPercent > 0) {
1478
+ return cssPercent;
1366
1479
  }
1367
1480
  warnMissingBridge6("getSafeAreaTop");
1368
1481
  return 0;
package/dist/index.js CHANGED
@@ -1269,31 +1269,130 @@ function warnMissingBridge6(methodName) {
1269
1269
  );
1270
1270
  }
1271
1271
  }
1272
- function normalizeSafeAreaTopPixels(value) {
1272
+ function toFiniteNumber(value) {
1273
1273
  if (typeof value !== "number" || !Number.isFinite(value)) {
1274
+ if (typeof value !== "string") {
1275
+ return void 0;
1276
+ }
1277
+ const parsed = Number.parseFloat(value.trim());
1278
+ if (!Number.isFinite(parsed)) {
1279
+ return void 0;
1280
+ }
1281
+ return parsed;
1282
+ }
1283
+ return value;
1284
+ }
1285
+ function clampSafeAreaTopPixels(value) {
1286
+ const numeric = toFiniteNumber(value);
1287
+ if (typeof numeric === "undefined") {
1274
1288
  return 0;
1275
1289
  }
1276
- return Math.max(0, value);
1290
+ return Math.max(0, numeric);
1277
1291
  }
1278
1292
  function normalizeSafeAreaTopPercent(value) {
1279
- if (typeof value !== "number" || !Number.isFinite(value)) {
1280
- return 0;
1293
+ const numeric = toFiniteNumber(value);
1294
+ if (typeof numeric === "undefined") {
1295
+ return void 0;
1281
1296
  }
1282
- return Math.min(100, Math.max(0, value));
1297
+ return Math.min(100, Math.max(0, numeric));
1283
1298
  }
1284
- function viewportInnerHeight(bridge) {
1285
- const h = bridge.innerHeight;
1286
- if (typeof h !== "number" || !Number.isFinite(h) || h <= 0) {
1299
+ function getViewportHeight(bridge) {
1300
+ const visualViewportHeight = bridge.visualViewport?.height;
1301
+ if (typeof visualViewportHeight === "number" && Number.isFinite(visualViewportHeight) && visualViewportHeight > 0) {
1302
+ return visualViewportHeight;
1303
+ }
1304
+ const innerHeight = bridge.innerHeight;
1305
+ if (typeof innerHeight === "number" && Number.isFinite(innerHeight) && innerHeight > 0) {
1306
+ return innerHeight;
1307
+ }
1308
+ const documentHeight = bridge.document?.documentElement?.clientHeight;
1309
+ if (typeof documentHeight === "number" && Number.isFinite(documentHeight) && documentHeight > 0) {
1310
+ return documentHeight;
1311
+ }
1312
+ const bodyHeight = bridge.document?.body?.clientHeight;
1313
+ if (typeof bodyHeight === "number" && Number.isFinite(bodyHeight) && bodyHeight > 0) {
1314
+ return bodyHeight;
1315
+ }
1316
+ return 0;
1317
+ }
1318
+ function readCssSafeAreaValue(bridge, cssValue) {
1319
+ const doc = bridge.document;
1320
+ const root = doc?.body ?? doc?.documentElement;
1321
+ if (!doc || !root || typeof doc.createElement !== "function" || typeof root.appendChild !== "function" || typeof bridge.getComputedStyle !== "function") {
1287
1322
  return 0;
1288
1323
  }
1289
- return h;
1324
+ const probe = doc.createElement("div");
1325
+ probe.style.position = "fixed";
1326
+ probe.style.top = "0";
1327
+ probe.style.left = "0";
1328
+ probe.style.width = "0";
1329
+ probe.style.height = "0";
1330
+ probe.style.visibility = "hidden";
1331
+ probe.style.pointerEvents = "none";
1332
+ probe.style.paddingTop = cssValue;
1333
+ root.appendChild(probe);
1334
+ try {
1335
+ return clampSafeAreaTopPixels(bridge.getComputedStyle(probe).paddingTop);
1336
+ } finally {
1337
+ if (typeof probe.remove === "function") {
1338
+ probe.remove();
1339
+ } else {
1340
+ probe.parentNode?.removeChild(probe);
1341
+ }
1342
+ }
1343
+ }
1344
+ function readCssSafeAreaTopPixels(bridge) {
1345
+ const envPixels = readCssSafeAreaValue(bridge, "env(safe-area-inset-top)");
1346
+ if (envPixels > 0) {
1347
+ return envPixels;
1348
+ }
1349
+ return readCssSafeAreaValue(bridge, "constant(safe-area-inset-top)");
1350
+ }
1351
+ function getDevicePixelRatio(bridge) {
1352
+ const dpr = bridge.devicePixelRatio;
1353
+ if (typeof dpr !== "number" || !Number.isFinite(dpr) || dpr <= 0) {
1354
+ return 1;
1355
+ }
1356
+ return dpr;
1357
+ }
1358
+ function roughlyEqualPixels(a, b) {
1359
+ return Math.abs(a - b) <= 2;
1360
+ }
1361
+ function normalizeSafeAreaTopPixels(value, bridge) {
1362
+ const pixels = clampSafeAreaTopPixels(value);
1363
+ const cssEnvPixels = readCssSafeAreaTopPixels(bridge);
1364
+ if (pixels <= 0) {
1365
+ return cssEnvPixels;
1366
+ }
1367
+ const dpr = getDevicePixelRatio(bridge);
1368
+ if (cssEnvPixels > 0 && dpr > 1 && roughlyEqualPixels(pixels / dpr, cssEnvPixels)) {
1369
+ return cssEnvPixels;
1370
+ }
1371
+ return pixels;
1290
1372
  }
1291
1373
  function pixelsTopToPercentOfViewport(pixels, bridge) {
1292
- const h = viewportInnerHeight(bridge);
1374
+ const h = getViewportHeight(bridge);
1293
1375
  if (h <= 0) {
1294
1376
  return 0;
1295
1377
  }
1296
- return normalizeSafeAreaTopPercent(pixels / h * 100);
1378
+ return normalizeSafeAreaTopPercent(pixels / h * 100) ?? 0;
1379
+ }
1380
+ function cssSafeAreaTopPercent(bridge) {
1381
+ return pixelsTopToPercentOfViewport(readCssSafeAreaTopPixels(bridge), bridge);
1382
+ }
1383
+ function resolvePercentValue(value, bridge) {
1384
+ const percent = normalizeSafeAreaTopPercent(value);
1385
+ if (typeof percent === "undefined") {
1386
+ return void 0;
1387
+ }
1388
+ return percent > 0 ? percent : cssSafeAreaTopPercent(bridge);
1389
+ }
1390
+ function resolvePixelValue(value, bridge) {
1391
+ const numeric = toFiniteNumber(value);
1392
+ if (typeof numeric === "undefined") {
1393
+ return void 0;
1394
+ }
1395
+ return pixelsTopToPercentOfViewport(normalizeSafeAreaTopPixels(numeric, bridge), bridge);
1297
1396
  }
1298
1397
  function getSafeAreaTop() {
1299
1398
  const bridge = getBridgeWindow8();
@@ -1301,18 +1400,32 @@ function getSafeAreaTop() {
1301
1400
  return 0;
1302
1401
  }
1303
1402
  if (typeof bridge.getSafeAreaTopPercent === "function") {
1304
- return normalizeSafeAreaTopPercent(bridge.getSafeAreaTopPercent());
1403
+ const percent = resolvePercentValue(bridge.getSafeAreaTopPercent(), bridge);
1404
+ if (typeof percent !== "undefined") {
1405
+ return percent;
1406
+ }
1305
1407
  }
1306
1408
  if (typeof bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__ !== "undefined") {
1307
- return normalizeSafeAreaTopPercent(bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__);
1409
+ const percent = resolvePercentValue(bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__, bridge);
1410
+ if (typeof percent !== "undefined") {
1411
+ return percent;
1412
+ }
1308
1413
  }
1309
1414
  if (typeof bridge.getSafeAreaTop === "function") {
1310
- const px = normalizeSafeAreaTopPixels(bridge.getSafeAreaTop());
1311
- return pixelsTopToPercentOfViewport(px, bridge);
1415
+ const percent = resolvePixelValue(bridge.getSafeAreaTop(), bridge);
1416
+ if (typeof percent !== "undefined") {
1417
+ return percent;
1418
+ }
1312
1419
  }
1313
1420
  if (typeof bridge.__OASIZ_SAFE_AREA_TOP__ !== "undefined") {
1314
- const px = normalizeSafeAreaTopPixels(bridge.__OASIZ_SAFE_AREA_TOP__);
1315
- return pixelsTopToPercentOfViewport(px, bridge);
1421
+ const percent = resolvePixelValue(bridge.__OASIZ_SAFE_AREA_TOP__, bridge);
1422
+ if (typeof percent !== "undefined") {
1423
+ return percent;
1424
+ }
1425
+ }
1426
+ const cssPercent = cssSafeAreaTopPercent(bridge);
1427
+ if (cssPercent > 0) {
1428
+ return cssPercent;
1316
1429
  }
1317
1430
  warnMissingBridge6("getSafeAreaTop");
1318
1431
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oasiz/sdk",
3
- "version": "1.5.4",
3
+ "version": "1.5.5",
4
4
  "description": "Typed SDK for Oasiz game platform bridge APIs.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",