@seatlayer/js 0.77.2 → 0.78.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/index.cjs +73 -104
- package/dist/index.d.cts +138 -4
- package/dist/index.d.ts +138 -4
- package/dist/index.js +72 -103
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -287,7 +287,9 @@ interface RealtimeSink {
|
|
|
287
287
|
* cannot be diffed against what we hold (first snapshot, or the scope's
|
|
288
288
|
* default itself changed, which redefines every unit we were never told
|
|
289
289
|
* about), and the sink cannot take a whole projection. */
|
|
290
|
-
resync(
|
|
290
|
+
resync(opts?: {
|
|
291
|
+
reason?: 'connect' | 'frame';
|
|
292
|
+
}): void | Promise<void>;
|
|
291
293
|
/** Section availability changed (channel-agnostic; identical for every scope). */
|
|
292
294
|
onSections?(hidden: string[], closed: string[]): void;
|
|
293
295
|
/** Scope-projected presence counters. */
|
|
@@ -395,13 +397,47 @@ interface PickerControllerLike {
|
|
|
395
397
|
label: string;
|
|
396
398
|
}>;
|
|
397
399
|
deselect(ids: string[]): void;
|
|
400
|
+
/** FORCED re-read. Reserved for "I just changed something, tell me the truth". */
|
|
398
401
|
refresh(): Promise<void>;
|
|
402
|
+
/**
|
|
403
|
+
* COALESCED re-read, and the one a socket should use.
|
|
404
|
+
*
|
|
405
|
+
* `refresh()` was this sink's only option, and it is the forced call: every
|
|
406
|
+
* connect and every section frame bypassed the controller's snapshot
|
|
407
|
+
* coalescer and issued its own `/objects?compact=1`. On the measured DesiPass
|
|
408
|
+
* open that was two redundant full snapshots landing ~1.5 s after the map was
|
|
409
|
+
* already painted from the bootstrap bundle.
|
|
410
|
+
*
|
|
411
|
+
* Optional so a host pinning an older `@seatlayer/core` still works — that
|
|
412
|
+
* engine simply keeps the forced behaviour it always had.
|
|
413
|
+
*/
|
|
414
|
+
resync?(opts?: {
|
|
415
|
+
reason?: 'connect' | 'frame';
|
|
416
|
+
}): Promise<void>;
|
|
417
|
+
/**
|
|
418
|
+
* Paint a whole authoritative projection with no round trip at all.
|
|
419
|
+
*
|
|
420
|
+
* Optional for the same reason: where the engine can take one, the socket's
|
|
421
|
+
* own connect frame IS the snapshot and the HTTP resync never happens.
|
|
422
|
+
*/
|
|
423
|
+
applyProjection?(projection: {
|
|
424
|
+
default: string;
|
|
425
|
+
exceptions: Record<string, string>;
|
|
426
|
+
}): void;
|
|
399
427
|
}
|
|
400
428
|
interface ControllerSinkOptions {
|
|
401
429
|
/** Pulse seats other buyers take, as the controller's own socket does. */
|
|
402
430
|
flashOnLiveChange?: boolean;
|
|
403
431
|
/** Selected-but-unheld units that stopped being selectable. */
|
|
404
432
|
onSelectedObjectUnavailable?: (labels: string[], reason: 'ineligible' | 'taken') => void;
|
|
433
|
+
/**
|
|
434
|
+
* Labels the buyer is holding RIGHT NOW — the hold request is in flight and
|
|
435
|
+
* `currentHold()` is still null. The server broadcasts `held` before the
|
|
436
|
+
* hold response lands, so without this the buyer's own echo reads as
|
|
437
|
+
* "someone else took your seat", the selection is evicted, and the winning
|
|
438
|
+
* hold is left with nobody attached to it.
|
|
439
|
+
*/
|
|
440
|
+
ownLabels?: () => Iterable<string>;
|
|
405
441
|
/** Section availability changed and the chart itself needs rebuilding. */
|
|
406
442
|
onSections?: (hidden: string[], closed: string[]) => void;
|
|
407
443
|
onStatusChange?: () => void;
|
|
@@ -1815,6 +1851,8 @@ declare class SeatingChart {
|
|
|
1815
1851
|
private readonly buyerAssetUrls;
|
|
1816
1852
|
private readonly immersive;
|
|
1817
1853
|
private realtime;
|
|
1854
|
+
/** Labels whose hold request is in flight — see ControllerSinkOptions.ownLabels. */
|
|
1855
|
+
private holdingLabels;
|
|
1818
1856
|
constructor(options: SeatingChartOptions);
|
|
1819
1857
|
/**
|
|
1820
1858
|
* Camera x/y/scale is renderer-local and deliberately absent from the native
|
|
@@ -2535,6 +2573,46 @@ declare class EmbeddedDesigner {
|
|
|
2535
2573
|
private handleMessage;
|
|
2536
2574
|
}
|
|
2537
2575
|
|
|
2576
|
+
/**
|
|
2577
|
+
* pickerConfirmCard — the card that stands between a tapped seat and the cart.
|
|
2578
|
+
*
|
|
2579
|
+
* It is one seat's whole story in one anchored popover: who the seat is (the
|
|
2580
|
+
* identity grid), what it costs (the category band), what can be seen from it
|
|
2581
|
+
* (the view thumbnail and the sightline line), and the two buttons that decide
|
|
2582
|
+
* the matter. Raising it, placing it against the seat, wiring its six controls,
|
|
2583
|
+
* committing it and taking it down are all here.
|
|
2584
|
+
*
|
|
2585
|
+
* Extracted from SeatPicker.ts (2026-09-03) so the widget has room to grow
|
|
2586
|
+
* under the app's file-size ratchet, which pins the vendored mirror. Bodies are
|
|
2587
|
+
* verbatim; the only edits are mechanical — the card's own two pieces of state
|
|
2588
|
+
* (`el`, `seat`) live on this class, and every other value the code read off
|
|
2589
|
+
* `this` now comes through {@link ConfirmCardHost}.
|
|
2590
|
+
*
|
|
2591
|
+
* THE HOST IS DELIBERATELY LATE-BOUND. Every member of it is a function the
|
|
2592
|
+
* widget implements by calling its own method, never a captured value: the
|
|
2593
|
+
* picker's tests replace `dismissConfirm`, `reducedMotion`, `scheduleMotion`,
|
|
2594
|
+
* `syncTray`, `canOffer3d`, `enter3d` and `buyerAssetUrls` on the instance, and
|
|
2595
|
+
* a card holding a bound reference from construction time would quietly ignore
|
|
2596
|
+
* all of them. That seam is the same one `SectionCard` keeps for
|
|
2597
|
+
* `sectionNeighbours`.
|
|
2598
|
+
*/
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* The two questions this one card asks.
|
|
2602
|
+
*
|
|
2603
|
+
* `add` is the original: a seat the buyer has tapped but not yet taken.
|
|
2604
|
+
* `remove` is the same card about a seat already in their cart, raised by a
|
|
2605
|
+
* SECOND tap on it — which used to drop the seat silently, with no card and no
|
|
2606
|
+
* notice (client report, 2026-09-04). Same layout, same identity, same price;
|
|
2607
|
+
* only the primary button changes, and Cancel keeps the seat rather than
|
|
2608
|
+
* dropping it.
|
|
2609
|
+
*
|
|
2610
|
+
* Deliberately not a separate card. A buyer taps a seat and expects the thing
|
|
2611
|
+
* that seat's tap always produces; two popovers for one gesture is a second
|
|
2612
|
+
* thing to learn for no gain.
|
|
2613
|
+
*/
|
|
2614
|
+
type ConfirmCardMode = 'add' | 'remove';
|
|
2615
|
+
|
|
2538
2616
|
/** What the saved-seat comparison chip needs from the widget around it. */
|
|
2539
2617
|
interface CompareChipHost {
|
|
2540
2618
|
/** The live 3D overlay the chip mounts into, or null when 3D is down. */
|
|
@@ -2740,6 +2818,10 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
2740
2818
|
private ro;
|
|
2741
2819
|
private holdTimer;
|
|
2742
2820
|
private toastTimer;
|
|
2821
|
+
/** The availability read every other caller joins. See refreshOfferAvailability. */
|
|
2822
|
+
private offerReadInFlight;
|
|
2823
|
+
/** When the last SUCCESSFUL availability read landed (0 = never). */
|
|
2824
|
+
private offerReadSettledAt;
|
|
2743
2825
|
private offerRefreshTimer;
|
|
2744
2826
|
/** Armed only when the offer schedule has a known future transition (or as a
|
|
2745
2827
|
* bounded retry after a failed read) — never a fixed-cadence poll. */
|
|
@@ -2970,6 +3052,32 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
2970
3052
|
private reportFramedHeight;
|
|
2971
3053
|
/** Full screen via the native API, falling back to a fixed-position overlay (iOS Safari). */
|
|
2972
3054
|
private toggleFullscreen;
|
|
3055
|
+
/**
|
|
3056
|
+
* Is the picker already as big as the screen it is on?
|
|
3057
|
+
*
|
|
3058
|
+
* Measured, not inferred. A host that opens the widget inside its own
|
|
3059
|
+
* full-height modal — DesiPass does exactly this on a phone — hands us a
|
|
3060
|
+
* root whose rect IS the viewport, and there is nothing left for "Full
|
|
3061
|
+
* screen" to give. The tolerance absorbs a hairline of host chrome, a
|
|
3062
|
+
* fractional device pixel ratio and a rubber-banding iOS toolbar; anything
|
|
3063
|
+
* larger than that is a real embed with page around it.
|
|
3064
|
+
*/
|
|
3065
|
+
private fillsViewport;
|
|
3066
|
+
/**
|
|
3067
|
+
* Show the "Full screen" pill only where pressing it can change something.
|
|
3068
|
+
*
|
|
3069
|
+
* On a phone inside a host's full-height modal the pill was a dead control
|
|
3070
|
+
* (client report on DesiPass, 2026-09-04): iOS Safari has no element
|
|
3071
|
+
* fullscreen, so the tap fell through to the fixed-position fallback — which
|
|
3072
|
+
* pins the widget to a viewport it was already filling. Nothing moved, and
|
|
3073
|
+
* an affordance that does nothing is worse than one that is not there.
|
|
3074
|
+
*
|
|
3075
|
+
* Narrow only. A desktop embed that happens to be viewport-sized is still
|
|
3076
|
+
* surrounded by browser chrome that native fullscreen removes, so the pill
|
|
3077
|
+
* has something to do there. And an ACTIVE fullscreen always keeps its pill:
|
|
3078
|
+
* that is the only way back out.
|
|
3079
|
+
*/
|
|
3080
|
+
private syncFullscreenAffordance;
|
|
2973
3081
|
private syncFullscreenButtons;
|
|
2974
3082
|
/**
|
|
2975
3083
|
* Native element-fullscreen was unavailable or rejected. When framed, a CSS
|
|
@@ -3247,7 +3355,6 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3247
3355
|
private renderSectionCard;
|
|
3248
3356
|
private collapseSectionCard;
|
|
3249
3357
|
private sectionCardOnView;
|
|
3250
|
-
private fitSectionStripCount;
|
|
3251
3358
|
/**
|
|
3252
3359
|
* Open sections next to the focused one, in authored order.
|
|
3253
3360
|
*
|
|
@@ -3280,7 +3387,7 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3280
3387
|
* `buyerAssetUrls` on the INSTANCE, and the card has to see those.
|
|
3281
3388
|
*/
|
|
3282
3389
|
private get confirmCard();
|
|
3283
|
-
/** @internal */ showConfirm(seat: ExpandedSeat): void;
|
|
3390
|
+
/** @internal */ showConfirm(seat: ExpandedSeat, mode?: ConfirmCardMode): void;
|
|
3284
3391
|
private reanchorConfirm;
|
|
3285
3392
|
private dismissConfirm;
|
|
3286
3393
|
/** @internal The card's own button calls the card; this is the seam the
|
|
@@ -3319,7 +3426,32 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3319
3426
|
* visibilitychange handler owns catching that tab up.
|
|
3320
3427
|
*/
|
|
3321
3428
|
private scheduleOfferBoundary;
|
|
3322
|
-
/**
|
|
3429
|
+
/**
|
|
3430
|
+
* Is the answer we hold current enough that asking again would learn nothing?
|
|
3431
|
+
*
|
|
3432
|
+
* True while a read is in flight (its answer is on its way) or while one that
|
|
3433
|
+
* just settled is inside the quiet window.
|
|
3434
|
+
*/
|
|
3435
|
+
private offerReadIsCurrent;
|
|
3436
|
+
/**
|
|
3437
|
+
* Debounce the no-store offer read behind a burst of seat-status frames.
|
|
3438
|
+
*
|
|
3439
|
+
* THE SKIP IS DECIDED HERE, WHEN THE REFRESH IS ASKED FOR — not 180 ms later
|
|
3440
|
+
* when the timer fires. Deciding at fire time made the dedupe a race between
|
|
3441
|
+
* this debounce and the quiet window, with 250 − 180 = 70 ms of margin: if
|
|
3442
|
+
* the timer ran even that little late, the window had lapsed and a second,
|
|
3443
|
+
* identical availability read went out. Seventy milliseconds of scheduler
|
|
3444
|
+
* jitter is nothing on a loaded machine, and this optimisation exists for
|
|
3445
|
+
* mid-range phones, where it is nothing on a good day.
|
|
3446
|
+
*
|
|
3447
|
+
* (Caught by the app's test/pickerOpenPathConcurrency.test.ts failing once in
|
|
3448
|
+
* a 462-file parallel run and passing in isolation — the flake was real, and
|
|
3449
|
+
* it was here rather than in the test.)
|
|
3450
|
+
*
|
|
3451
|
+
* The rule is unchanged, only the instant it is evaluated at: a refresh asked
|
|
3452
|
+
* for while the answer is still current is answered by the read that just
|
|
3453
|
+
* happened. A batch arriving past the window still schedules and still reads.
|
|
3454
|
+
*/
|
|
3323
3455
|
private scheduleOfferRefresh;
|
|
3324
3456
|
/**
|
|
3325
3457
|
* Pull the server's resolved answer. A failed refresh keeps the last truthful
|
|
@@ -3327,6 +3459,8 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3327
3459
|
* offer is worse than a temporarily stale remaining count.
|
|
3328
3460
|
*/
|
|
3329
3461
|
private refreshOfferAvailability;
|
|
3462
|
+
/** The read itself. Never rejects — see the catch. */
|
|
3463
|
+
private readOfferAvailability;
|
|
3330
3464
|
private offerPrice;
|
|
3331
3465
|
private applyChannelPricing;
|
|
3332
3466
|
private syncOffer;
|
package/dist/index.d.ts
CHANGED
|
@@ -287,7 +287,9 @@ interface RealtimeSink {
|
|
|
287
287
|
* cannot be diffed against what we hold (first snapshot, or the scope's
|
|
288
288
|
* default itself changed, which redefines every unit we were never told
|
|
289
289
|
* about), and the sink cannot take a whole projection. */
|
|
290
|
-
resync(
|
|
290
|
+
resync(opts?: {
|
|
291
|
+
reason?: 'connect' | 'frame';
|
|
292
|
+
}): void | Promise<void>;
|
|
291
293
|
/** Section availability changed (channel-agnostic; identical for every scope). */
|
|
292
294
|
onSections?(hidden: string[], closed: string[]): void;
|
|
293
295
|
/** Scope-projected presence counters. */
|
|
@@ -395,13 +397,47 @@ interface PickerControllerLike {
|
|
|
395
397
|
label: string;
|
|
396
398
|
}>;
|
|
397
399
|
deselect(ids: string[]): void;
|
|
400
|
+
/** FORCED re-read. Reserved for "I just changed something, tell me the truth". */
|
|
398
401
|
refresh(): Promise<void>;
|
|
402
|
+
/**
|
|
403
|
+
* COALESCED re-read, and the one a socket should use.
|
|
404
|
+
*
|
|
405
|
+
* `refresh()` was this sink's only option, and it is the forced call: every
|
|
406
|
+
* connect and every section frame bypassed the controller's snapshot
|
|
407
|
+
* coalescer and issued its own `/objects?compact=1`. On the measured DesiPass
|
|
408
|
+
* open that was two redundant full snapshots landing ~1.5 s after the map was
|
|
409
|
+
* already painted from the bootstrap bundle.
|
|
410
|
+
*
|
|
411
|
+
* Optional so a host pinning an older `@seatlayer/core` still works — that
|
|
412
|
+
* engine simply keeps the forced behaviour it always had.
|
|
413
|
+
*/
|
|
414
|
+
resync?(opts?: {
|
|
415
|
+
reason?: 'connect' | 'frame';
|
|
416
|
+
}): Promise<void>;
|
|
417
|
+
/**
|
|
418
|
+
* Paint a whole authoritative projection with no round trip at all.
|
|
419
|
+
*
|
|
420
|
+
* Optional for the same reason: where the engine can take one, the socket's
|
|
421
|
+
* own connect frame IS the snapshot and the HTTP resync never happens.
|
|
422
|
+
*/
|
|
423
|
+
applyProjection?(projection: {
|
|
424
|
+
default: string;
|
|
425
|
+
exceptions: Record<string, string>;
|
|
426
|
+
}): void;
|
|
399
427
|
}
|
|
400
428
|
interface ControllerSinkOptions {
|
|
401
429
|
/** Pulse seats other buyers take, as the controller's own socket does. */
|
|
402
430
|
flashOnLiveChange?: boolean;
|
|
403
431
|
/** Selected-but-unheld units that stopped being selectable. */
|
|
404
432
|
onSelectedObjectUnavailable?: (labels: string[], reason: 'ineligible' | 'taken') => void;
|
|
433
|
+
/**
|
|
434
|
+
* Labels the buyer is holding RIGHT NOW — the hold request is in flight and
|
|
435
|
+
* `currentHold()` is still null. The server broadcasts `held` before the
|
|
436
|
+
* hold response lands, so without this the buyer's own echo reads as
|
|
437
|
+
* "someone else took your seat", the selection is evicted, and the winning
|
|
438
|
+
* hold is left with nobody attached to it.
|
|
439
|
+
*/
|
|
440
|
+
ownLabels?: () => Iterable<string>;
|
|
405
441
|
/** Section availability changed and the chart itself needs rebuilding. */
|
|
406
442
|
onSections?: (hidden: string[], closed: string[]) => void;
|
|
407
443
|
onStatusChange?: () => void;
|
|
@@ -1815,6 +1851,8 @@ declare class SeatingChart {
|
|
|
1815
1851
|
private readonly buyerAssetUrls;
|
|
1816
1852
|
private readonly immersive;
|
|
1817
1853
|
private realtime;
|
|
1854
|
+
/** Labels whose hold request is in flight — see ControllerSinkOptions.ownLabels. */
|
|
1855
|
+
private holdingLabels;
|
|
1818
1856
|
constructor(options: SeatingChartOptions);
|
|
1819
1857
|
/**
|
|
1820
1858
|
* Camera x/y/scale is renderer-local and deliberately absent from the native
|
|
@@ -2535,6 +2573,46 @@ declare class EmbeddedDesigner {
|
|
|
2535
2573
|
private handleMessage;
|
|
2536
2574
|
}
|
|
2537
2575
|
|
|
2576
|
+
/**
|
|
2577
|
+
* pickerConfirmCard — the card that stands between a tapped seat and the cart.
|
|
2578
|
+
*
|
|
2579
|
+
* It is one seat's whole story in one anchored popover: who the seat is (the
|
|
2580
|
+
* identity grid), what it costs (the category band), what can be seen from it
|
|
2581
|
+
* (the view thumbnail and the sightline line), and the two buttons that decide
|
|
2582
|
+
* the matter. Raising it, placing it against the seat, wiring its six controls,
|
|
2583
|
+
* committing it and taking it down are all here.
|
|
2584
|
+
*
|
|
2585
|
+
* Extracted from SeatPicker.ts (2026-09-03) so the widget has room to grow
|
|
2586
|
+
* under the app's file-size ratchet, which pins the vendored mirror. Bodies are
|
|
2587
|
+
* verbatim; the only edits are mechanical — the card's own two pieces of state
|
|
2588
|
+
* (`el`, `seat`) live on this class, and every other value the code read off
|
|
2589
|
+
* `this` now comes through {@link ConfirmCardHost}.
|
|
2590
|
+
*
|
|
2591
|
+
* THE HOST IS DELIBERATELY LATE-BOUND. Every member of it is a function the
|
|
2592
|
+
* widget implements by calling its own method, never a captured value: the
|
|
2593
|
+
* picker's tests replace `dismissConfirm`, `reducedMotion`, `scheduleMotion`,
|
|
2594
|
+
* `syncTray`, `canOffer3d`, `enter3d` and `buyerAssetUrls` on the instance, and
|
|
2595
|
+
* a card holding a bound reference from construction time would quietly ignore
|
|
2596
|
+
* all of them. That seam is the same one `SectionCard` keeps for
|
|
2597
|
+
* `sectionNeighbours`.
|
|
2598
|
+
*/
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* The two questions this one card asks.
|
|
2602
|
+
*
|
|
2603
|
+
* `add` is the original: a seat the buyer has tapped but not yet taken.
|
|
2604
|
+
* `remove` is the same card about a seat already in their cart, raised by a
|
|
2605
|
+
* SECOND tap on it — which used to drop the seat silently, with no card and no
|
|
2606
|
+
* notice (client report, 2026-09-04). Same layout, same identity, same price;
|
|
2607
|
+
* only the primary button changes, and Cancel keeps the seat rather than
|
|
2608
|
+
* dropping it.
|
|
2609
|
+
*
|
|
2610
|
+
* Deliberately not a separate card. A buyer taps a seat and expects the thing
|
|
2611
|
+
* that seat's tap always produces; two popovers for one gesture is a second
|
|
2612
|
+
* thing to learn for no gain.
|
|
2613
|
+
*/
|
|
2614
|
+
type ConfirmCardMode = 'add' | 'remove';
|
|
2615
|
+
|
|
2538
2616
|
/** What the saved-seat comparison chip needs from the widget around it. */
|
|
2539
2617
|
interface CompareChipHost {
|
|
2540
2618
|
/** The live 3D overlay the chip mounts into, or null when 3D is down. */
|
|
@@ -2740,6 +2818,10 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
2740
2818
|
private ro;
|
|
2741
2819
|
private holdTimer;
|
|
2742
2820
|
private toastTimer;
|
|
2821
|
+
/** The availability read every other caller joins. See refreshOfferAvailability. */
|
|
2822
|
+
private offerReadInFlight;
|
|
2823
|
+
/** When the last SUCCESSFUL availability read landed (0 = never). */
|
|
2824
|
+
private offerReadSettledAt;
|
|
2743
2825
|
private offerRefreshTimer;
|
|
2744
2826
|
/** Armed only when the offer schedule has a known future transition (or as a
|
|
2745
2827
|
* bounded retry after a failed read) — never a fixed-cadence poll. */
|
|
@@ -2970,6 +3052,32 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
2970
3052
|
private reportFramedHeight;
|
|
2971
3053
|
/** Full screen via the native API, falling back to a fixed-position overlay (iOS Safari). */
|
|
2972
3054
|
private toggleFullscreen;
|
|
3055
|
+
/**
|
|
3056
|
+
* Is the picker already as big as the screen it is on?
|
|
3057
|
+
*
|
|
3058
|
+
* Measured, not inferred. A host that opens the widget inside its own
|
|
3059
|
+
* full-height modal — DesiPass does exactly this on a phone — hands us a
|
|
3060
|
+
* root whose rect IS the viewport, and there is nothing left for "Full
|
|
3061
|
+
* screen" to give. The tolerance absorbs a hairline of host chrome, a
|
|
3062
|
+
* fractional device pixel ratio and a rubber-banding iOS toolbar; anything
|
|
3063
|
+
* larger than that is a real embed with page around it.
|
|
3064
|
+
*/
|
|
3065
|
+
private fillsViewport;
|
|
3066
|
+
/**
|
|
3067
|
+
* Show the "Full screen" pill only where pressing it can change something.
|
|
3068
|
+
*
|
|
3069
|
+
* On a phone inside a host's full-height modal the pill was a dead control
|
|
3070
|
+
* (client report on DesiPass, 2026-09-04): iOS Safari has no element
|
|
3071
|
+
* fullscreen, so the tap fell through to the fixed-position fallback — which
|
|
3072
|
+
* pins the widget to a viewport it was already filling. Nothing moved, and
|
|
3073
|
+
* an affordance that does nothing is worse than one that is not there.
|
|
3074
|
+
*
|
|
3075
|
+
* Narrow only. A desktop embed that happens to be viewport-sized is still
|
|
3076
|
+
* surrounded by browser chrome that native fullscreen removes, so the pill
|
|
3077
|
+
* has something to do there. And an ACTIVE fullscreen always keeps its pill:
|
|
3078
|
+
* that is the only way back out.
|
|
3079
|
+
*/
|
|
3080
|
+
private syncFullscreenAffordance;
|
|
2973
3081
|
private syncFullscreenButtons;
|
|
2974
3082
|
/**
|
|
2975
3083
|
* Native element-fullscreen was unavailable or rejected. When framed, a CSS
|
|
@@ -3247,7 +3355,6 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3247
3355
|
private renderSectionCard;
|
|
3248
3356
|
private collapseSectionCard;
|
|
3249
3357
|
private sectionCardOnView;
|
|
3250
|
-
private fitSectionStripCount;
|
|
3251
3358
|
/**
|
|
3252
3359
|
* Open sections next to the focused one, in authored order.
|
|
3253
3360
|
*
|
|
@@ -3280,7 +3387,7 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3280
3387
|
* `buyerAssetUrls` on the INSTANCE, and the card has to see those.
|
|
3281
3388
|
*/
|
|
3282
3389
|
private get confirmCard();
|
|
3283
|
-
/** @internal */ showConfirm(seat: ExpandedSeat): void;
|
|
3390
|
+
/** @internal */ showConfirm(seat: ExpandedSeat, mode?: ConfirmCardMode): void;
|
|
3284
3391
|
private reanchorConfirm;
|
|
3285
3392
|
private dismissConfirm;
|
|
3286
3393
|
/** @internal The card's own button calls the card; this is the seam the
|
|
@@ -3319,7 +3426,32 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3319
3426
|
* visibilitychange handler owns catching that tab up.
|
|
3320
3427
|
*/
|
|
3321
3428
|
private scheduleOfferBoundary;
|
|
3322
|
-
/**
|
|
3429
|
+
/**
|
|
3430
|
+
* Is the answer we hold current enough that asking again would learn nothing?
|
|
3431
|
+
*
|
|
3432
|
+
* True while a read is in flight (its answer is on its way) or while one that
|
|
3433
|
+
* just settled is inside the quiet window.
|
|
3434
|
+
*/
|
|
3435
|
+
private offerReadIsCurrent;
|
|
3436
|
+
/**
|
|
3437
|
+
* Debounce the no-store offer read behind a burst of seat-status frames.
|
|
3438
|
+
*
|
|
3439
|
+
* THE SKIP IS DECIDED HERE, WHEN THE REFRESH IS ASKED FOR — not 180 ms later
|
|
3440
|
+
* when the timer fires. Deciding at fire time made the dedupe a race between
|
|
3441
|
+
* this debounce and the quiet window, with 250 − 180 = 70 ms of margin: if
|
|
3442
|
+
* the timer ran even that little late, the window had lapsed and a second,
|
|
3443
|
+
* identical availability read went out. Seventy milliseconds of scheduler
|
|
3444
|
+
* jitter is nothing on a loaded machine, and this optimisation exists for
|
|
3445
|
+
* mid-range phones, where it is nothing on a good day.
|
|
3446
|
+
*
|
|
3447
|
+
* (Caught by the app's test/pickerOpenPathConcurrency.test.ts failing once in
|
|
3448
|
+
* a 462-file parallel run and passing in isolation — the flake was real, and
|
|
3449
|
+
* it was here rather than in the test.)
|
|
3450
|
+
*
|
|
3451
|
+
* The rule is unchanged, only the instant it is evaluated at: a refresh asked
|
|
3452
|
+
* for while the answer is still current is answered by the read that just
|
|
3453
|
+
* happened. A batch arriving past the window still schedules and still reads.
|
|
3454
|
+
*/
|
|
3323
3455
|
private scheduleOfferRefresh;
|
|
3324
3456
|
/**
|
|
3325
3457
|
* Pull the server's resolved answer. A failed refresh keeps the last truthful
|
|
@@ -3327,6 +3459,8 @@ declare class SeatPicker implements GaPromptPicker {
|
|
|
3327
3459
|
* offer is worse than a temporarily stale remaining count.
|
|
3328
3460
|
*/
|
|
3329
3461
|
private refreshOfferAvailability;
|
|
3462
|
+
/** The read itself. Never rejects — see the catch. */
|
|
3463
|
+
private readOfferAvailability;
|
|
3330
3464
|
private offerPrice;
|
|
3331
3465
|
private applyChannelPricing;
|
|
3332
3466
|
private syncOffer;
|