@mpgd/target-config 0.15.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effective.d.ts +1 -0
- package/dist/effective.js +5 -1
- package/dist/index.js +117 -81
- package/dist/runtime.d.ts +11 -6
- package/dist/runtime.js +176 -40
- package/dist/viewport.d.ts +90 -0
- package/dist/viewport.js +171 -0
- package/package.json +5 -5
package/dist/runtime.js
CHANGED
|
@@ -5,10 +5,13 @@ const adPlacementFeatureByType = {
|
|
|
5
5
|
};
|
|
6
6
|
export const platformFeatures = [
|
|
7
7
|
'iap',
|
|
8
|
+
'subscriptions',
|
|
8
9
|
'bannerAds',
|
|
9
10
|
'rewardedAds',
|
|
10
11
|
'interstitialAds',
|
|
11
12
|
'leaderboard',
|
|
13
|
+
'nativeLeaderboard',
|
|
14
|
+
'remoteLeaderboard',
|
|
12
15
|
'localization',
|
|
13
16
|
];
|
|
14
17
|
export function adPlacementFeatureFor(type) {
|
|
@@ -55,7 +58,9 @@ const integrationAvailabilityStateValues = [
|
|
|
55
58
|
'available',
|
|
56
59
|
'disabled',
|
|
57
60
|
'approval-required',
|
|
61
|
+
'action-required',
|
|
58
62
|
'configuration-required',
|
|
63
|
+
'temporarily-unavailable',
|
|
59
64
|
'unsupported',
|
|
60
65
|
];
|
|
61
66
|
export const integrationAvailabilityStates = integrationAvailabilityStateValues;
|
|
@@ -129,7 +134,18 @@ export function getTargetConfig(matrix, target) {
|
|
|
129
134
|
return config;
|
|
130
135
|
}
|
|
131
136
|
export function isPlatformFeatureEnabled(config, feature) {
|
|
132
|
-
|
|
137
|
+
switch (feature) {
|
|
138
|
+
case 'subscriptions':
|
|
139
|
+
return config.features.iap && config.features.subscriptions === true;
|
|
140
|
+
case 'nativeLeaderboard':
|
|
141
|
+
return config.features.leaderboard
|
|
142
|
+
&& (config.features.nativeLeaderboard ?? config.leaderboard.native);
|
|
143
|
+
case 'remoteLeaderboard':
|
|
144
|
+
return config.features.leaderboard
|
|
145
|
+
&& (config.features.remoteLeaderboard ?? true);
|
|
146
|
+
default:
|
|
147
|
+
return config.features[feature] === true;
|
|
148
|
+
}
|
|
133
149
|
}
|
|
134
150
|
export function applyTargetConfigToCapabilities(capabilities, config) {
|
|
135
151
|
const bannerAds = capabilities.bannerAds === true && config.features.bannerAds === true;
|
|
@@ -138,46 +154,61 @@ export function applyTargetConfigToCapabilities(capabilities, config) {
|
|
|
138
154
|
return {
|
|
139
155
|
...capabilities,
|
|
140
156
|
nativeIap: capabilities.nativeIap && config.features.iap,
|
|
157
|
+
...(capabilities.subscriptionIap === undefined
|
|
158
|
+
? {}
|
|
159
|
+
: { subscriptionIap: capabilities.subscriptionIap && isPlatformFeatureEnabled(config, 'subscriptions') }),
|
|
141
160
|
nativeAds: capabilities.nativeAds &&
|
|
142
161
|
(bannerAds || rewardedAds || interstitialAds),
|
|
143
162
|
bannerAds,
|
|
144
163
|
rewardedAds,
|
|
145
164
|
interstitialAds,
|
|
146
|
-
nativeLeaderboard: capabilities.nativeLeaderboard && config
|
|
147
|
-
remoteLeaderboard: capabilities.remoteLeaderboard && config
|
|
165
|
+
nativeLeaderboard: capabilities.nativeLeaderboard && isPlatformFeatureEnabled(config, 'nativeLeaderboard'),
|
|
166
|
+
remoteLeaderboard: capabilities.remoteLeaderboard && isPlatformFeatureEnabled(config, 'remoteLeaderboard'),
|
|
148
167
|
localizedContent: capabilities.localizedContent && config.features.localization,
|
|
149
168
|
};
|
|
150
169
|
}
|
|
151
170
|
export function getFeatureAvailability(feature, config, capabilities) {
|
|
152
|
-
const targetEnabled = config
|
|
153
|
-
const capabilitySupported = isFeatureCapabilitySupported(feature, capabilities);
|
|
154
|
-
const
|
|
171
|
+
const targetEnabled = isPlatformFeatureEnabled(config, feature);
|
|
172
|
+
const capabilitySupported = isFeatureCapabilitySupported(feature, capabilities, config);
|
|
173
|
+
const providerState = getFeatureProviderAvailability(feature, capabilities, config);
|
|
174
|
+
const enabled = targetEnabled && capabilitySupported && (providerState === undefined || providerState === 'available');
|
|
155
175
|
return {
|
|
156
176
|
feature,
|
|
157
177
|
enabled,
|
|
158
178
|
targetEnabled,
|
|
159
179
|
capabilitySupported,
|
|
160
|
-
reason:
|
|
180
|
+
reason: !targetEnabled
|
|
181
|
+
? 'target-disabled'
|
|
182
|
+
: enabled
|
|
183
|
+
? 'available'
|
|
184
|
+
: providerState === 'configuration-required'
|
|
185
|
+
|| providerState === 'action-required'
|
|
186
|
+
|| providerState === 'temporarily-unavailable'
|
|
187
|
+
? providerState
|
|
188
|
+
: 'capability-unsupported',
|
|
161
189
|
};
|
|
162
190
|
}
|
|
163
|
-
export function getIntegrationAvailability(integration, config, gateway) {
|
|
191
|
+
export function getIntegrationAvailability(integration, config, gateway, capabilities) {
|
|
164
192
|
const integrations = normalizeTargetIntegrationConfig(config.integrations);
|
|
165
|
-
return createIntegrationAvailability(integration, integrations[integration], gateway);
|
|
193
|
+
return createIntegrationAvailability(integration, integrations[integration], gateway, capabilities);
|
|
166
194
|
}
|
|
167
195
|
export function createTargetRuntimeSnapshot(input) {
|
|
168
196
|
const configTarget = input.configTarget ?? targetConfigKeyForPlatform(input.target);
|
|
169
197
|
const availabilityConfig = resolveAvailabilityConfig(input.config, input.effectiveConfig);
|
|
170
198
|
const features = {
|
|
171
199
|
iap: getFeatureAvailability('iap', availabilityConfig, input.capabilities),
|
|
200
|
+
subscriptions: getFeatureAvailability('subscriptions', availabilityConfig, input.capabilities),
|
|
172
201
|
bannerAds: getFeatureAvailability('bannerAds', availabilityConfig, input.capabilities),
|
|
173
202
|
rewardedAds: getFeatureAvailability('rewardedAds', availabilityConfig, input.capabilities),
|
|
174
203
|
interstitialAds: getFeatureAvailability('interstitialAds', availabilityConfig, input.capabilities),
|
|
175
204
|
leaderboard: getFeatureAvailability('leaderboard', availabilityConfig, input.capabilities),
|
|
205
|
+
nativeLeaderboard: getFeatureAvailability('nativeLeaderboard', availabilityConfig, input.capabilities),
|
|
206
|
+
remoteLeaderboard: getFeatureAvailability('remoteLeaderboard', availabilityConfig, input.capabilities),
|
|
176
207
|
localization: getFeatureAvailability('localization', availabilityConfig, input.capabilities),
|
|
177
208
|
};
|
|
178
209
|
const integrationConfig = normalizeTargetIntegrationConfig(input.effectiveConfig?.integrations ?? input.config.integrations);
|
|
179
210
|
const integrationEntries = targetIntegrations.map((integration) => {
|
|
180
|
-
const availability = createIntegrationAvailability(integration, integrationConfig[integration], input.gateway);
|
|
211
|
+
const availability = createIntegrationAvailability(integration, integrationConfig[integration], input.gateway, input.capabilities);
|
|
181
212
|
return [integration, availability];
|
|
182
213
|
});
|
|
183
214
|
const integrations = Object.fromEntries(integrationEntries);
|
|
@@ -208,13 +239,16 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
208
239
|
const configTarget = options.configTarget ?? targetConfigKeyForPlatform(gateway.target);
|
|
209
240
|
const { identity: gatewayIdentity, presentation: gatewayPresentation, sharing: gatewaySharing, notifications: gatewayNotifications, ...gatewayWithoutIntegrations } = gateway;
|
|
210
241
|
const integrations = normalizeTargetIntegrationConfig(options.effectiveConfig?.integrations ?? config.integrations);
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
const
|
|
242
|
+
const isIntegrationCallable = (integration) => {
|
|
243
|
+
const state = createIntegrationAvailability(integration, integrations[integration], gateway).state;
|
|
244
|
+
return state === 'available' || (state === 'action-required'
|
|
245
|
+
&& (integration === 'identityUpgrade' || integration === 'notifications'));
|
|
246
|
+
};
|
|
247
|
+
const identityUpgradeAvailable = isIntegrationCallable('identityUpgrade');
|
|
248
|
+
const presentationAvailable = isIntegrationCallable('presentation');
|
|
249
|
+
const sharingAvailable = isIntegrationCallable('sharing');
|
|
250
|
+
const inboundShareAvailable = isIntegrationCallable('inboundShare');
|
|
251
|
+
const notificationsAvailable = isIntegrationCallable('notifications');
|
|
218
252
|
const getIdentitySession = gatewayIdentity.getSession?.bind(gatewayIdentity);
|
|
219
253
|
const requestIdentityUpgrade = gatewayIdentity.requestUpgrade?.bind(gatewayIdentity);
|
|
220
254
|
const shareOutbound = gatewaySharing?.share?.bind(gatewaySharing);
|
|
@@ -236,13 +270,32 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
236
270
|
...(exposeInboundShare ? { readInboundShare } : {}),
|
|
237
271
|
};
|
|
238
272
|
const notifications = notificationsAvailable ? gatewayNotifications : undefined;
|
|
239
|
-
const
|
|
240
|
-
|
|
273
|
+
const getIapAvailability = async () => {
|
|
274
|
+
const oneTimeEnabled = availabilityConfig.features.iap;
|
|
275
|
+
const subscriptionsEnabled = isPlatformFeatureEnabled(availabilityConfig, 'subscriptions');
|
|
276
|
+
if (!oneTimeEnabled && !subscriptionsEnabled) {
|
|
277
|
+
return { oneTime: false, subscriptions: false };
|
|
278
|
+
}
|
|
279
|
+
const capabilities = await getGatewayCapabilities();
|
|
280
|
+
return {
|
|
281
|
+
oneTime: oneTimeEnabled && capabilities.nativeIap,
|
|
282
|
+
subscriptions: subscriptionsEnabled && capabilities.subscriptionIap === true,
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
const getLeaderboardRoute = async () => {
|
|
241
286
|
if (!availabilityConfig.features.leaderboard) {
|
|
242
|
-
return
|
|
287
|
+
return null;
|
|
243
288
|
}
|
|
244
289
|
const capabilities = await getGatewayCapabilities();
|
|
245
|
-
|
|
290
|
+
if (capabilities.nativeLeaderboard
|
|
291
|
+
&& isPlatformFeatureEnabled(availabilityConfig, 'nativeLeaderboard')) {
|
|
292
|
+
return 'native';
|
|
293
|
+
}
|
|
294
|
+
if (capabilities.remoteLeaderboard
|
|
295
|
+
&& isPlatformFeatureEnabled(availabilityConfig, 'remoteLeaderboard')) {
|
|
296
|
+
return 'remote';
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
246
299
|
};
|
|
247
300
|
const isAdPlacementAllowed = (placementId, expectedType) => {
|
|
248
301
|
const actualType = options.resolveAdPlacementType?.(placementId);
|
|
@@ -251,14 +304,19 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
251
304
|
}
|
|
252
305
|
return availabilityConfig.features[adPlacementFeatureFor(expectedType)] === true;
|
|
253
306
|
};
|
|
254
|
-
const canPreloadAdPlacement = (placementId) => {
|
|
255
|
-
const
|
|
307
|
+
const canPreloadAdPlacement = (placementId, requestedFormat) => {
|
|
308
|
+
const resolvedType = options.resolveAdPlacementType?.(placementId);
|
|
309
|
+
if (resolvedType !== undefined && requestedFormat !== undefined
|
|
310
|
+
&& resolvedType !== requestedFormat) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
const actualType = resolvedType ?? requestedFormat;
|
|
256
314
|
if (actualType !== undefined) {
|
|
257
|
-
return
|
|
315
|
+
return actualType !== 'banner'
|
|
316
|
+
&& availabilityConfig.features[adPlacementFeatureFor(actualType)] === true;
|
|
258
317
|
}
|
|
259
318
|
return (availabilityConfig.features.rewardedAds ||
|
|
260
|
-
availabilityConfig.features.interstitialAds
|
|
261
|
-
availabilityConfig.features.bannerAds === true);
|
|
319
|
+
availabilityConfig.features.interstitialAds);
|
|
262
320
|
};
|
|
263
321
|
return {
|
|
264
322
|
...gatewayWithoutIntegrations,
|
|
@@ -289,10 +347,29 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
289
347
|
},
|
|
290
348
|
commerce: {
|
|
291
349
|
async getProducts() {
|
|
292
|
-
|
|
350
|
+
const available = await getIapAvailability();
|
|
351
|
+
if (!available.oneTime && !available.subscriptions) {
|
|
352
|
+
return [];
|
|
353
|
+
}
|
|
354
|
+
return (await gateway.commerce.getProducts()).filter((product) => product.type === 'subscription' ? available.subscriptions : available.oneTime);
|
|
293
355
|
},
|
|
294
356
|
async purchase(input) {
|
|
295
|
-
|
|
357
|
+
const available = await getIapAvailability();
|
|
358
|
+
const configuredProduct = options.effectiveConfig?.monetization.products.find((product) => product.id === input.productId);
|
|
359
|
+
let productType = configuredProduct?.type;
|
|
360
|
+
if (productType === undefined
|
|
361
|
+
&& options.effectiveConfig === undefined
|
|
362
|
+
&& available.oneTime !== available.subscriptions) {
|
|
363
|
+
productType = (await gateway.commerce.getProducts()).find((product) => product.id === input.productId)?.type;
|
|
364
|
+
}
|
|
365
|
+
// When only one purchase route is available, unknown product types
|
|
366
|
+
// must not fall through to that route. An effective catalog is binding.
|
|
367
|
+
const allowed = productType === 'subscription'
|
|
368
|
+
? available.subscriptions
|
|
369
|
+
: productType === undefined
|
|
370
|
+
? available.oneTime && available.subscriptions
|
|
371
|
+
: available.oneTime;
|
|
372
|
+
if (!allowed || (options.effectiveConfig !== undefined && configuredProduct?.enabled !== true)) {
|
|
296
373
|
return {
|
|
297
374
|
status: 'cancelled',
|
|
298
375
|
entitlementIds: [],
|
|
@@ -301,7 +378,8 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
301
378
|
return gateway.commerce.purchase(input);
|
|
302
379
|
},
|
|
303
380
|
async restore() {
|
|
304
|
-
|
|
381
|
+
const available = await getIapAvailability();
|
|
382
|
+
if ((!available.oneTime && !available.subscriptions) || gateway.commerce.restore === undefined) {
|
|
305
383
|
return {
|
|
306
384
|
restoredEntitlements: [],
|
|
307
385
|
};
|
|
@@ -309,13 +387,17 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
309
387
|
return gateway.commerce.restore();
|
|
310
388
|
},
|
|
311
389
|
async getEntitlements() {
|
|
312
|
-
|
|
390
|
+
const available = await getIapAvailability();
|
|
391
|
+
return available.oneTime || available.subscriptions
|
|
392
|
+
? gateway.commerce.getEntitlements()
|
|
393
|
+
: [];
|
|
313
394
|
},
|
|
314
395
|
},
|
|
315
396
|
ads: {
|
|
316
397
|
async preload(input) {
|
|
317
|
-
if (canPreloadAdPlacement(input.placementId)) {
|
|
318
|
-
|
|
398
|
+
if (canPreloadAdPlacement(input.placementId, input.format)) {
|
|
399
|
+
const format = options.resolveAdPlacementType?.(input.placementId) ?? input.format;
|
|
400
|
+
await gateway.ads.preload(format === undefined ? input : { ...input, format });
|
|
319
401
|
}
|
|
320
402
|
},
|
|
321
403
|
async showRewarded(input) {
|
|
@@ -351,16 +433,22 @@ export function withTargetAvailability(gateway, config, options = {}) {
|
|
|
351
433
|
},
|
|
352
434
|
leaderboard: {
|
|
353
435
|
async submitScore(input) {
|
|
354
|
-
|
|
436
|
+
const route = await getLeaderboardRoute();
|
|
437
|
+
if (route === null) {
|
|
355
438
|
return {
|
|
356
439
|
submitted: false,
|
|
357
440
|
};
|
|
358
441
|
}
|
|
359
|
-
return gateway.leaderboard.submitScore(
|
|
442
|
+
return gateway.leaderboard.submitScore(gateway.target === 'android' || gateway.target === 'ios'
|
|
443
|
+
? { ...input, route }
|
|
444
|
+
: input);
|
|
360
445
|
},
|
|
361
446
|
async open(input) {
|
|
362
|
-
|
|
363
|
-
|
|
447
|
+
const route = await getLeaderboardRoute();
|
|
448
|
+
if (route !== null) {
|
|
449
|
+
await gateway.leaderboard.open(gateway.target === 'android' || gateway.target === 'ios'
|
|
450
|
+
? { ...input, route }
|
|
451
|
+
: input);
|
|
364
452
|
}
|
|
365
453
|
},
|
|
366
454
|
},
|
|
@@ -377,10 +465,12 @@ function resolveAvailabilityConfig(config, effectiveConfig) {
|
|
|
377
465
|
export function isTargetConfiguredGateway(gateway) {
|
|
378
466
|
return typeof gateway.getTargetRuntime === 'function';
|
|
379
467
|
}
|
|
380
|
-
function isFeatureCapabilitySupported(feature, capabilities) {
|
|
468
|
+
function isFeatureCapabilitySupported(feature, capabilities, config) {
|
|
381
469
|
switch (feature) {
|
|
382
470
|
case 'iap':
|
|
383
471
|
return capabilities.nativeIap;
|
|
472
|
+
case 'subscriptions':
|
|
473
|
+
return capabilities.subscriptionIap === true;
|
|
384
474
|
case 'bannerAds':
|
|
385
475
|
return capabilities.bannerAds === true;
|
|
386
476
|
case 'rewardedAds':
|
|
@@ -388,11 +478,45 @@ function isFeatureCapabilitySupported(feature, capabilities) {
|
|
|
388
478
|
case 'interstitialAds':
|
|
389
479
|
return capabilities.interstitialAds;
|
|
390
480
|
case 'leaderboard':
|
|
391
|
-
return capabilities.nativeLeaderboard || capabilities.remoteLeaderboard;
|
|
481
|
+
return (capabilities.nativeLeaderboard && isPlatformFeatureEnabled(config, 'nativeLeaderboard')) || (capabilities.remoteLeaderboard && isPlatformFeatureEnabled(config, 'remoteLeaderboard'));
|
|
482
|
+
case 'nativeLeaderboard':
|
|
483
|
+
return capabilities.nativeLeaderboard;
|
|
484
|
+
case 'remoteLeaderboard':
|
|
485
|
+
return capabilities.remoteLeaderboard;
|
|
392
486
|
case 'localization':
|
|
393
487
|
return capabilities.localizedContent;
|
|
394
488
|
}
|
|
395
489
|
}
|
|
490
|
+
function getFeatureProviderAvailability(feature, capabilities, config) {
|
|
491
|
+
const states = capabilities.providerAvailability;
|
|
492
|
+
if (states === undefined) {
|
|
493
|
+
return undefined;
|
|
494
|
+
}
|
|
495
|
+
switch (feature) {
|
|
496
|
+
case 'iap':
|
|
497
|
+
return states.nativeIap;
|
|
498
|
+
case 'subscriptions':
|
|
499
|
+
return states.subscriptionIap;
|
|
500
|
+
case 'rewardedAds':
|
|
501
|
+
return states.rewardedAds;
|
|
502
|
+
case 'interstitialAds':
|
|
503
|
+
return states.interstitialAds;
|
|
504
|
+
case 'bannerAds':
|
|
505
|
+
return states.bannerAds;
|
|
506
|
+
case 'nativeLeaderboard':
|
|
507
|
+
return states.nativeLeaderboard;
|
|
508
|
+
case 'leaderboard':
|
|
509
|
+
// A game-owned remote leaderboard remains usable without a native provider.
|
|
510
|
+
return capabilities.remoteLeaderboard && isPlatformFeatureEnabled(config, 'remoteLeaderboard')
|
|
511
|
+
? 'available'
|
|
512
|
+
: isPlatformFeatureEnabled(config, 'nativeLeaderboard')
|
|
513
|
+
? states.nativeLeaderboard
|
|
514
|
+
: undefined;
|
|
515
|
+
case 'remoteLeaderboard':
|
|
516
|
+
case 'localization':
|
|
517
|
+
return undefined;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
396
520
|
function isIntegrationAdapterSupported(integration, gateway) {
|
|
397
521
|
if (gateway === undefined) {
|
|
398
522
|
return false;
|
|
@@ -412,11 +536,23 @@ function isIntegrationAdapterSupported(integration, gateway) {
|
|
|
412
536
|
&& typeof gateway.notifications?.requestSubscription === 'function');
|
|
413
537
|
}
|
|
414
538
|
}
|
|
415
|
-
function createIntegrationAvailability(integration, configuredState, gateway) {
|
|
539
|
+
function createIntegrationAvailability(integration, configuredState, gateway, capabilities) {
|
|
416
540
|
const adapterSupported = isIntegrationAdapterSupported(integration, gateway);
|
|
541
|
+
const providerState = integration === 'identityUpgrade'
|
|
542
|
+
? capabilities?.providerAvailability?.identityUpgrade
|
|
543
|
+
: integration === 'notifications'
|
|
544
|
+
? capabilities?.providerAvailability?.pushNotifications
|
|
545
|
+
: undefined;
|
|
546
|
+
const state = configuredState === 'disabled' || configuredState === 'unsupported'
|
|
547
|
+
? configuredState
|
|
548
|
+
: !adapterSupported || providerState === 'unsupported'
|
|
549
|
+
? 'unsupported'
|
|
550
|
+
: providerState !== undefined && providerState !== 'available'
|
|
551
|
+
? providerState
|
|
552
|
+
: configuredState;
|
|
417
553
|
return {
|
|
418
554
|
integration,
|
|
419
|
-
state
|
|
555
|
+
state,
|
|
420
556
|
configuredState,
|
|
421
557
|
adapterSupported,
|
|
422
558
|
};
|
package/dist/viewport.d.ts
CHANGED
|
@@ -106,6 +106,27 @@ export interface TargetViewportSafeArea {
|
|
|
106
106
|
readonly contentBounds: TargetViewportBounds;
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
|
+
* A named host-owned surface in full-viewport CSS-pixel coordinates. The
|
|
110
|
+
* effective inset extends from `edge` to the surface's far bound, so any gap
|
|
111
|
+
* between a floating surface and that edge is conservatively treated as used.
|
|
112
|
+
*/
|
|
113
|
+
export interface TargetViewportOccupiedSurface {
|
|
114
|
+
readonly surfaceId: string;
|
|
115
|
+
readonly edge: 'top' | 'right' | 'bottom' | 'left';
|
|
116
|
+
readonly bounds: TargetViewportBounds;
|
|
117
|
+
}
|
|
118
|
+
/** Independent occlusion measurements. Overlap is combined, never summed. */
|
|
119
|
+
export interface TargetViewportUsableAreaInput {
|
|
120
|
+
readonly safeAreaInsets?: Partial<TargetViewportSafeAreaInsets>;
|
|
121
|
+
readonly systemBarInsets?: Partial<TargetViewportSafeAreaInsets>;
|
|
122
|
+
readonly keyboardInsets?: Partial<TargetViewportSafeAreaInsets>;
|
|
123
|
+
readonly occupiedSurfaces?: readonly TargetViewportOccupiedSurface[];
|
|
124
|
+
}
|
|
125
|
+
/** Remaining geometry shared by a canvas and any DOM overlays. */
|
|
126
|
+
export interface TargetViewportUsableArea extends TargetViewportSafeArea {
|
|
127
|
+
readonly occupiedSurfaceIds: readonly string[];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
109
130
|
* A viewport plan enriched with concrete safe-area geometry. It is assignable
|
|
110
131
|
* to `TargetViewportPlan`, so existing scene code can adopt it incrementally.
|
|
111
132
|
*/
|
|
@@ -206,6 +227,67 @@ export declare function resolveTargetViewportPlan(input: TargetViewportInput, br
|
|
|
206
227
|
* render persistent DOM controls or position Phaser HUD elements themselves.
|
|
207
228
|
*/
|
|
208
229
|
export declare function resolveTargetViewportSnapshot(input: TargetViewportSnapshotInput, breakpoints?: TargetViewportBreakpoints): TargetViewportSnapshot;
|
|
230
|
+
/** A raw viewport size reported by a host surface, before a plan validates it. */
|
|
231
|
+
export interface TargetViewportMeasurement {
|
|
232
|
+
readonly width: number;
|
|
233
|
+
readonly height: number;
|
|
234
|
+
readonly source: TargetViewportMeasurementSource;
|
|
235
|
+
}
|
|
236
|
+
/** A surface that reports its layout box, such as the element that mounts the game. */
|
|
237
|
+
export interface TargetViewportMeasurableElement {
|
|
238
|
+
getBoundingClientRect(): {
|
|
239
|
+
readonly width: number;
|
|
240
|
+
readonly height: number;
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Host surfaces for {@link measureTargetViewport}. Structural types keep the helper usable in
|
|
245
|
+
* tests and non-DOM hosts; a browser passes the game container, `window.visualViewport` and
|
|
246
|
+
* `window`.
|
|
247
|
+
*/
|
|
248
|
+
export interface TargetViewportMeasurementSources {
|
|
249
|
+
readonly container?: TargetViewportMeasurableElement | null;
|
|
250
|
+
readonly visualViewport?: {
|
|
251
|
+
readonly width: number;
|
|
252
|
+
readonly height: number;
|
|
253
|
+
} | null;
|
|
254
|
+
readonly window?: {
|
|
255
|
+
readonly innerWidth: number;
|
|
256
|
+
readonly innerHeight: number;
|
|
257
|
+
} | null;
|
|
258
|
+
}
|
|
259
|
+
/** Inputs for {@link waitForTargetViewportMeasurement}. */
|
|
260
|
+
export interface TargetViewportMeasurementWait {
|
|
261
|
+
/** Returns a measurement, or `null` while the surface has no usable size. */
|
|
262
|
+
readonly measure: () => TargetViewportMeasurement | null;
|
|
263
|
+
/**
|
|
264
|
+
* Calls the listener whenever the surface may have resized or become visible and returns an
|
|
265
|
+
* unsubscribe function. Browsers typically combine window and `visualViewport` `resize`,
|
|
266
|
+
* document `visibilitychange` and a `ResizeObserver` on the game container.
|
|
267
|
+
*/
|
|
268
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
269
|
+
/** Stops waiting; the promise then rejects with the signal's reason. */
|
|
270
|
+
readonly signal?: AbortSignal;
|
|
271
|
+
}
|
|
272
|
+
/** Whether a size can produce a viewport plan: both sides finite and at least one CSS pixel. */
|
|
273
|
+
export declare function isMeasurableTargetViewport(size: {
|
|
274
|
+
readonly width: number;
|
|
275
|
+
readonly height: number;
|
|
276
|
+
}): boolean;
|
|
277
|
+
/**
|
|
278
|
+
* Measure the first host surface with a usable area: the game container, then the visual
|
|
279
|
+
* viewport, then the window. Returns `null` while every surface is still zero-sized, as in a
|
|
280
|
+
* hidden iframe, a collapsed embed or a background tab before layout. Resolve a viewport plan
|
|
281
|
+
* only from a measurement; {@link waitForTargetViewportMeasurement} waits for the first one.
|
|
282
|
+
*/
|
|
283
|
+
export declare function measureTargetViewport(sources: TargetViewportMeasurementSources): TargetViewportMeasurement | null;
|
|
284
|
+
/**
|
|
285
|
+
* Resolve with the first usable measurement, so a game that boots inside a zero-sized surface
|
|
286
|
+
* starts once the host lays it out instead of failing viewport validation. Resolves immediately
|
|
287
|
+
* when the surface is already measurable and unsubscribes as soon as it settles. A measurement
|
|
288
|
+
* that throws, including the first one, rejects the returned promise.
|
|
289
|
+
*/
|
|
290
|
+
export declare function waitForTargetViewportMeasurement(input: TargetViewportMeasurementWait): Promise<TargetViewportMeasurement>;
|
|
209
291
|
/**
|
|
210
292
|
* Resolve an adaptive game shell inside the snapshot's safe content bounds.
|
|
211
293
|
*
|
|
@@ -225,6 +307,14 @@ export declare function resolveTargetViewportComposition(input: TargetViewportCo
|
|
|
225
307
|
*/
|
|
226
308
|
export declare function resolveTargetViewportSafeArea(layout: Pick<TargetViewportLayout, 'width' | 'height'>, insets?: Partial<TargetViewportSafeAreaInsets>): TargetViewportSafeArea;
|
|
227
309
|
/**
|
|
310
|
+
* Resolve all edge occlusions in one CSS-pixel coordinate space. System bars
|
|
311
|
+
* and CSS safe-area measurements can describe the same pixels, as can a banner
|
|
312
|
+
* and the home-indicator inset. Taking the maximum intrusion per edge avoids
|
|
313
|
+
* subtracting those regions twice. A surface's bounds are absolute viewport
|
|
314
|
+
* coordinates, not a banner height to add to another inset.
|
|
315
|
+
*/
|
|
316
|
+
export declare function resolveTargetViewportUsableArea(layout: Pick<TargetViewportLayout, 'width' | 'height'>, input?: TargetViewportUsableAreaInput): TargetViewportUsableArea;
|
|
317
|
+
/**
|
|
228
318
|
* Read the starter's computed CSS variables. Unknown or non-pixel values are
|
|
229
319
|
* intentionally treated as zero so browser shells without CSS env support keep
|
|
230
320
|
* the same full-viewport layout as before.
|