@encorekit/web-sdk 2.0.7 → 2.1.1
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 +6 -0
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/umd/encore.min.js +1 -1
- package/dist/umd/encore.min.js.map +1 -1
- package/package.json +1 -1
- package/types/api/APIClient.d.ts +18 -0
- package/types/api/APIClient.d.ts.map +1 -1
- package/types/api/generated/types.d.ts +177 -2
- package/types/api/generated/types.d.ts.map +1 -1
- package/types/api/models.d.ts +32 -0
- package/types/api/models.d.ts.map +1 -1
- package/types/core/Encore.d.ts.map +1 -1
- package/types/core/giftVariant.d.ts +67 -0
- package/types/core/giftVariant.d.ts.map +1 -0
- package/types/core/version.d.ts +1 -1
- package/types/types.d.ts +31 -3
- package/types/types.d.ts.map +1 -1
- package/types/ui/GiftHero.d.ts +75 -0
- package/types/ui/GiftHero.d.ts.map +1 -0
- package/types/ui/GiftList.d.ts +110 -0
- package/types/ui/GiftList.d.ts.map +1 -0
- package/types/ui/GiftReveal.d.ts +133 -0
- package/types/ui/GiftReveal.d.ts.map +1 -0
- package/types/ui/GiftSheet.d.ts +126 -0
- package/types/ui/GiftSheet.d.ts.map +1 -0
- package/types/ui/GiftUnwrap.d.ts +155 -0
- package/types/ui/GiftUnwrap.d.ts.map +1 -0
- package/types/ui/OfferCarousel.d.ts +10 -3
- package/types/ui/OfferCarousel.d.ts.map +1 -1
- package/types/ui/OfferModal.d.ts +7 -0
- package/types/ui/OfferModal.d.ts.map +1 -1
- package/types/ui/RewardActions.d.ts +88 -4
- package/types/ui/RewardActions.d.ts.map +1 -1
- package/types/ui/RewardCard.d.ts +16 -8
- package/types/ui/RewardCard.d.ts.map +1 -1
- package/types/ui/RewardConfetti.d.ts +23 -1
- package/types/ui/RewardConfetti.d.ts.map +1 -1
- package/types/ui/RewardLayout.d.ts +35 -0
- package/types/ui/RewardLayout.d.ts.map +1 -1
- package/types/ui/advertiserPreconnect.d.ts +90 -0
- package/types/ui/advertiserPreconnect.d.ts.map +1 -0
- package/types/ui/appearance.d.ts +27 -0
- package/types/ui/appearance.d.ts.map +1 -1
- package/types/ui/focusable.d.ts +41 -0
- package/types/ui/focusable.d.ts.map +1 -0
- package/types/ui/giftCategoryGroups.d.ts +21 -0
- package/types/ui/giftCategoryGroups.d.ts.map +1 -0
- package/types/ui/giftCopy.d.ts +215 -0
- package/types/ui/giftCopy.d.ts.map +1 -0
- package/types/ui/giftUnwrapArt.d.ts +55 -0
- package/types/ui/giftUnwrapArt.d.ts.map +1 -0
- package/types/ui/giftUnwrapCopy.d.ts +57 -0
- package/types/ui/giftUnwrapCopy.d.ts.map +1 -0
- package/types/ui/impressionGate.d.ts +63 -0
- package/types/ui/impressionGate.d.ts.map +1 -0
- package/types/ui/offerBadge.d.ts +56 -0
- package/types/ui/offerBadge.d.ts.map +1 -0
- package/types/ui/rewardSurface.d.ts +82 -0
- package/types/ui/rewardSurface.d.ts.map +1 -0
- package/types/ui/safeImageSrc.d.ts +10 -0
- package/types/ui/safeImageSrc.d.ts.map +1 -1
- package/types/ui/styles.d.ts +166 -0
- package/types/ui/styles.d.ts.map +1 -1
- package/types/ui/termsLine.d.ts +33 -0
- package/types/ui/termsLine.d.ts.map +1 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gift unwrap — the `giftUnwrap` reward surface (Figma "hypothesis 5").
|
|
3
|
+
*
|
|
4
|
+
* Two screens in one surface:
|
|
5
|
+
*
|
|
6
|
+
* 1. PICK. A closed gift box under a falling confetti pass, the headline, up to three
|
|
7
|
+
* gift rows, "Show more gifts" for the rest, a plain "Continue" and the terms line.
|
|
8
|
+
* 2. READY. "‹ Back", the box opening with the picked gift's logo rising out of it,
|
|
9
|
+
* "Your gift is ready", what happens next as check bullets, and "Continue to
|
|
10
|
+
* {advertiser}" — which is the claim.
|
|
11
|
+
*
|
|
12
|
+
* Screen 1 is the ordinary reward composition, built the same way `giftList`'s is:
|
|
13
|
+
* `Encore` resolves the headline chain and `RewardLayout` renders it (the dialog's
|
|
14
|
+
* labelled heading, FREE accented only for the gift default); `RewardActions` renders
|
|
15
|
+
* "Continue" with the shared terms line under it and no trust line. This class supplies
|
|
16
|
+
* three pieces and joins them: `renderHero()` (the closed box), `render()` (rows and the
|
|
17
|
+
* sheet), and `compose(pickScreen)`, which takes the laid-out screen 1 and returns the
|
|
18
|
+
* two-screen root with screen 2 beside it.
|
|
19
|
+
*
|
|
20
|
+
* ## What is a claim
|
|
21
|
+
*
|
|
22
|
+
* 🔴 ONLY SCREEN 2's CTA CLAIMS. Screen 1's "Continue" (wired by Encore to
|
|
23
|
+
* `showReady()`) and the sheet's CTA are navigation: they move to the ready screen and
|
|
24
|
+
* emit nothing. `claimSelected()` is the one path to `offerClaim`, the single claim
|
|
25
|
+
* path every surface feeds (see `rewardSurface.ts`), and it is reached from a click on
|
|
26
|
+
* screen 2 so the advertiser window still opens inside the user's gesture.
|
|
27
|
+
*
|
|
28
|
+
* ## Selection has exactly one source
|
|
29
|
+
*
|
|
30
|
+
* `#selectedIndex`, an index into the FULL offer array, as in `GiftReveal` and
|
|
31
|
+
* `GiftList`. A gift picked in the sheet is PROMOTED into the rows rather than tracked
|
|
32
|
+
* beside them, so the row the user sees checked, the logo that rises out of the box,
|
|
33
|
+
* and the offer the CTA claims can never disagree. Back keeps it intact.
|
|
34
|
+
*
|
|
35
|
+
* ## Events
|
|
36
|
+
*
|
|
37
|
+
* `offerView` once per offer the impression gate judges shown (a row, a promoted gift,
|
|
38
|
+
* a sheet card while the sheet is open), `offerSelect` on every selection change including
|
|
39
|
+
* the initial auto-selection during `render()` (Encore subscribes first, for the
|
|
40
|
+
* advertiser preconnect), and `offerClaim` from screen 2 only. All carry
|
|
41
|
+
* `{ offer, index }` with `index` into the array Encore passed in.
|
|
42
|
+
*
|
|
43
|
+
* ## Not built, deliberately
|
|
44
|
+
*
|
|
45
|
+
* The design's "Most claimed" pill and the sheet variant with "Watch & listen" /
|
|
46
|
+
* "Everyday" chips need a popularity count and a category, and the offer model has
|
|
47
|
+
* neither (see `api/models.ts`). Inventing either from list order or brand names would
|
|
48
|
+
* be a guess that looks like data, so both wait on a real field.
|
|
49
|
+
*
|
|
50
|
+
* ## The reveal (see giftUnwrapStyles in styles.ts)
|
|
51
|
+
*
|
|
52
|
+
* Four elements, four tracks, one 1752ms timeline with the design's keyframe stops on
|
|
53
|
+
* the individual `translate` / `scale` / `rotate` properties plus `opacity`. The base
|
|
54
|
+
* rules ARE the end state, so any entry where the animation never runs still shows the
|
|
55
|
+
* open box and the logo. The play class is re-added across a reflow on every entry.
|
|
56
|
+
*/
|
|
57
|
+
import type { OfferModel as Offer } from '../api/models';
|
|
58
|
+
import { type ButtonSlot } from './appearance';
|
|
59
|
+
import type { RewardSurface, RewardSurfaceEventMap } from './rewardSurface';
|
|
60
|
+
import { ImpressionGate } from './impressionGate';
|
|
61
|
+
/** How many gifts screen 1 shows as rows. The rest go behind "Show more gifts". */
|
|
62
|
+
export declare const UNWRAP_ROW_LIMIT = 3;
|
|
63
|
+
/**
|
|
64
|
+
* The reveal's length: all four tracks (closed box, open box, logo tile, glow) share
|
|
65
|
+
* it. The stylesheet carries the same number; exported so a test can pin the two.
|
|
66
|
+
*/
|
|
67
|
+
export declare const UNWRAP_REVEAL_MS = 1752;
|
|
68
|
+
export type UnwrapScreen = 'pick' | 'ready';
|
|
69
|
+
/** The id on "Your gift is ready", which names the dialog while screen 2 is showing. */
|
|
70
|
+
export declare const UNWRAP_READY_TITLE_ID: string;
|
|
71
|
+
export interface GiftUnwrapComposeOptions {
|
|
72
|
+
/**
|
|
73
|
+
* Point the dialog's `aria-labelledby` at `id`. Called with the ready heading's id on
|
|
74
|
+
* entering screen 2 and with `REWARD_TITLE_ID` on Back: screen 1's headline is
|
|
75
|
+
* `hidden` while screen 2 shows, and a dialog named by a hidden heading announces a
|
|
76
|
+
* screen the user is no longer on. A callback because the modal is Encore's.
|
|
77
|
+
*/
|
|
78
|
+
setLabelledBy?: (id: string) => void;
|
|
79
|
+
}
|
|
80
|
+
export interface GiftUnwrapOptions {
|
|
81
|
+
/**
|
|
82
|
+
* Whether claiming is switched on (`Encore.isClaimEnabled`). `false` disables every
|
|
83
|
+
* control that leads to a claim: screen 2's CTA, and the sheet's CTA like on the
|
|
84
|
+
* other gift surfaces. Screen 1's "Continue" is gated the same way by `RewardActions`.
|
|
85
|
+
*/
|
|
86
|
+
claimEnabled?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* The publisher's `appearance.claimButton`. It styles screen 2's CTA, because that is
|
|
89
|
+
* the button that claims; screen 1's "Continue" only navigates and keeps the
|
|
90
|
+
* surface's own styling. Appearance only: the action stays `claimSelected()`, and
|
|
91
|
+
* the claim switch still gates it (see `createActionSlot`).
|
|
92
|
+
*/
|
|
93
|
+
claimSlot?: ButtonSlot;
|
|
94
|
+
/**
|
|
95
|
+
* The presentation's impression gate (see `impressionGate.ts`): rows and sheet cards
|
|
96
|
+
* report `offerView` only once it judges them shown. Without one the surface owns an
|
|
97
|
+
* unarmed gate, which never fires.
|
|
98
|
+
*/
|
|
99
|
+
impressions?: ImpressionGate;
|
|
100
|
+
}
|
|
101
|
+
export declare class GiftUnwrap implements RewardSurface {
|
|
102
|
+
#private;
|
|
103
|
+
constructor(offers: readonly Offer[], options?: GiftUnwrapOptions);
|
|
104
|
+
on<E extends keyof RewardSurfaceEventMap>(event: E, handler: (payload: RewardSurfaceEventMap[E]) => void): () => void;
|
|
105
|
+
getTotalOffers(): number;
|
|
106
|
+
getCurrentIndex(): number;
|
|
107
|
+
getSelectedOffer(): Offer | undefined;
|
|
108
|
+
/** True when some gift did not fit in the rows. */
|
|
109
|
+
hasMoreGifts(): boolean;
|
|
110
|
+
getScreen(): UnwrapScreen;
|
|
111
|
+
/**
|
|
112
|
+
* The closed box, placed by `RewardLayout` above the headline. `aria-hidden`: it is
|
|
113
|
+
* decoration, and the copy under it says everything it depicts.
|
|
114
|
+
*/
|
|
115
|
+
renderHero(): HTMLElement;
|
|
116
|
+
/**
|
|
117
|
+
* Screen 1's body: the rows, then "Show more gifts" with its sheet. Announces the
|
|
118
|
+
* auto-selected first gift and reports the rows as seen.
|
|
119
|
+
*/
|
|
120
|
+
render(): HTMLElement;
|
|
121
|
+
/**
|
|
122
|
+
* Join the laid-out screen 1 with screen 2, and start screen 1's confetti.
|
|
123
|
+
*
|
|
124
|
+
* `pickScreen` is what `RewardLayout` built around {@link renderHero},
|
|
125
|
+
* {@link render} and the action block.
|
|
126
|
+
*/
|
|
127
|
+
compose(pickScreen: HTMLElement, options?: GiftUnwrapComposeOptions): HTMLElement;
|
|
128
|
+
/**
|
|
129
|
+
* Select the offer at `index` into the full array. Out of range is IGNORED rather
|
|
130
|
+
* than clamped: claiming a neighbouring advertiser would hide a caller's bug behind a
|
|
131
|
+
* real transaction.
|
|
132
|
+
*/
|
|
133
|
+
selectOffer(index: number): void;
|
|
134
|
+
next(): void;
|
|
135
|
+
/**
|
|
136
|
+
* Claim the SELECTED offer. The only emitter of `offerClaim`, and wired only to
|
|
137
|
+
* screen 2's CTA. Honours the host's claim switch here as well as on the button, so
|
|
138
|
+
* a programmatic call cannot claim what the disabled control could not.
|
|
139
|
+
*/
|
|
140
|
+
claimSelected(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Go to "Your gift is ready" for the current selection, and replay the reveal.
|
|
143
|
+
*
|
|
144
|
+
* Each entry is a fresh reveal: the tile and bullets are rebuilt for whatever is
|
|
145
|
+
* selected now, and the play class is removed and re-added across a reflow so the
|
|
146
|
+
* keyframes start again from 0%.
|
|
147
|
+
*/
|
|
148
|
+
showReady(): void;
|
|
149
|
+
/** Back to the list, selection intact. The confetti does not replay. */
|
|
150
|
+
showPick(): void;
|
|
151
|
+
openSheet(opener?: HTMLElement): void;
|
|
152
|
+
closeSheet(): void;
|
|
153
|
+
destroy(): void;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=GiftUnwrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GiftUnwrap.d.ts","sourceRoot":"","sources":["../../src/ui/GiftUnwrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,KAAK,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,eAAe,CAAC;AASzD,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAUlF,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAC;AAEnE,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AASrC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;AAE5C,wFAAwF;AACxF,eAAO,MAAM,qBAAqB,QAA4B,CAAC;AAE/D,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED,qBAAa,UAAW,YAAW,aAAa;;gBAyClC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,OAAO,GAAE,iBAAsB;IASrE,EAAE,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACtC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,GACnD,MAAM,IAAI;IAIb,cAAc,IAAI,MAAM;IAIxB,eAAe,IAAI,MAAM;IAIzB,gBAAgB,IAAI,KAAK,GAAG,SAAS;IAIrC,mDAAmD;IACnD,YAAY,IAAI,OAAO;IAIvB,SAAS,IAAI,YAAY;IAMzB;;;OAGG;IACH,UAAU,IAAI,WAAW;IAazB;;;OAGG;IACH,MAAM,IAAI,WAAW;IA2BrB;;;;;OAKG;IACH,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,GAAE,wBAA6B,GAAG,WAAW;IAgErF;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAahC,IAAI,IAAI,IAAI;IA4CZ;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAerB;;;;;;OAMG;IACH,SAAS,IAAI,IAAI;IA8BjB,wEAAwE;IACxE,QAAQ,IAAI,IAAI;IAuLhB,SAAS,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI;IAKrC,UAAU,IAAI,IAAI;IAyDlB,OAAO,IAAI,IAAI;CA8BhB"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { OfferModel as Offer } from '../api/models';
|
|
6
6
|
import type { UIConfiguration } from '../types';
|
|
7
|
+
import { ImpressionGate } from './impressionGate';
|
|
7
8
|
export interface OfferCarouselOptions {
|
|
8
9
|
/**
|
|
9
10
|
* 'responsive' (default): today's behavior — horizontal carousel on desktop, vertical
|
|
@@ -58,6 +59,12 @@ export interface OfferCarouselOptions {
|
|
|
58
59
|
*/
|
|
59
60
|
dotColor?: string;
|
|
60
61
|
dotActiveColor?: string;
|
|
62
|
+
/**
|
|
63
|
+
* The presentation's impression gate (see `impressionGate.ts`). Cards report
|
|
64
|
+
* `offerView` once it judges them shown and, in horizontal mode, only once the scroll
|
|
65
|
+
* is at rest. Without one the carousel owns an unarmed gate, which never fires.
|
|
66
|
+
*/
|
|
67
|
+
impressions?: ImpressionGate;
|
|
61
68
|
}
|
|
62
69
|
interface CarouselEventMap extends Record<string, unknown> {
|
|
63
70
|
offerClaim: {
|
|
@@ -73,9 +80,9 @@ interface CarouselEventMap extends Record<string, unknown> {
|
|
|
73
80
|
};
|
|
74
81
|
/**
|
|
75
82
|
* The user moved to a different card, by any means (gesture, arrows, keyboard).
|
|
76
|
-
* Distinct from `offerView`, which is an IMPRESSION and
|
|
77
|
-
*
|
|
78
|
-
*
|
|
83
|
+
* Distinct from `offerView`, which is an IMPRESSION and fires once per offer per
|
|
84
|
+
* presentation: this is the navigation itself, so a user paging 0→1→0 produces
|
|
85
|
+
* three scrolls and two impressions. `axis` is a real dimension
|
|
79
86
|
* on web — the same carousel is horizontal on desktop and a vertical list on
|
|
80
87
|
* mobile — and is what `sdk_sdui_scroll` reports.
|
|
81
88
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OfferCarousel.d.ts","sourceRoot":"","sources":["../../src/ui/OfferCarousel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"OfferCarousel.d.ts","sourceRoot":"","sources":["../../src/ui/OfferCarousel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAOhD,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IAC9B;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAQD,UAAU,gBAAiB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,UAAU,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,SAAS,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C;;;;;;;OAOG;IACH,MAAM,EAAE;QAAE,IAAI,EAAE,YAAY,GAAG,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,QAAQ,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/B;;;;;OAKG;IACH,WAAW,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,qBAAa,aAAa;;gBA0EZ,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB;IAuBvF;;OAEG;IACH,MAAM,IAAI,WAAW;IA8QrB;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,gBAAgB,EACjC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,GAC9C,MAAM,IAAI;IAIb;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAUZ;;;;;OAKG;IACH,gBAAgB,IAAI,KAAK,GAAG,SAAS;IAIrC;;;;;;;;;;OAUG;IACH,aAAa,IAAI,IAAI;IASrB;;;;;OAKG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAiBhC;;OAEG;IACH,QAAQ,IAAI,IAAI;IA4qBhB;;OAEG;IACH,OAAO,IAAI,IAAI;CA6BhB"}
|
package/types/ui/OfferModal.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ interface ModalEventMap extends Record<string, unknown> {
|
|
|
8
8
|
backdropClick: void;
|
|
9
9
|
show: void;
|
|
10
10
|
hide: void;
|
|
11
|
+
visibility: boolean;
|
|
11
12
|
}
|
|
12
13
|
export interface OfferModalOptions {
|
|
13
14
|
/**
|
|
@@ -64,6 +65,12 @@ export declare class OfferModal {
|
|
|
64
65
|
* Hide and remove the modal
|
|
65
66
|
*/
|
|
66
67
|
hide(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Subscribe to whether the sheet is on screen: `true` on the frame its show transition
|
|
70
|
+
* starts (never at `show()`, which is still opacity 0), `false` when `hide()` begins.
|
|
71
|
+
* Called at once with `true` when subscribing to a sheet that is already on screen.
|
|
72
|
+
*/
|
|
73
|
+
onVisibilityChange(handler: (visible: boolean) => void): () => void;
|
|
67
74
|
/**
|
|
68
75
|
* Check if modal is currently visible
|
|
69
76
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OfferModal.d.ts","sourceRoot":"","sources":["../../src/ui/OfferModal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"OfferModal.d.ts","sourceRoot":"","sources":["../../src/ui/OfferModal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAI/C,UAAU,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACrD,KAAK,EAAE,IAAI,CAAC;IACZ,aAAa,EAAE,IAAI,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;;;;;;;;;;;;OAkBG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,UAAU;;gBAwBT,KAAK,GAAE,cAAmB,EAAE,OAAO,GAAE,iBAAsB;IAavE;;OAEG;IACH,IAAI,IAAI,IAAI;IAwCZ;;OAEG;IACH,IAAI,IAAI,IAAI;IA8CZ;;;;OAIG;IACH,kBAAkB,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAYnE;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IA4BtC;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,aAAa,EAC9B,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,GAC3C,MAAM,IAAI;IAuKb;;OAEG;IACH,OAAO,IAAI,IAAI;CAoBhB"}
|
|
@@ -23,11 +23,28 @@ import type { UseCase } from '../types';
|
|
|
23
23
|
import { type ButtonSlot } from './appearance';
|
|
24
24
|
/** Copy the variant hard-codes. Named so the tests can assert parity by symbol. */
|
|
25
25
|
export declare const REWARD_COPY: {
|
|
26
|
+
/**
|
|
27
|
+
* ⚠️ ASSERTS A FREE TRIAL, so it is only correct under an offer that IS one. Used
|
|
28
|
+
* when `badgeLabel` says `free_trial`; otherwise `trustUnknown` below. It stays the
|
|
29
|
+
* shipped wording for that case because it is the variant's own line.
|
|
30
|
+
*/
|
|
26
31
|
readonly trust: "No charges until trial ends, cancel anytime.";
|
|
32
|
+
/**
|
|
33
|
+
* The line for every offer that is not a KNOWN free trial — a discount, or the
|
|
34
|
+
* common case where the campaign carries no badge at all.
|
|
35
|
+
*
|
|
36
|
+
* It has to be true without knowing the terms, so it claims nothing about price,
|
|
37
|
+
* trials or cancellation. The old default asserted "no charges until trial ends"
|
|
38
|
+
* over live inventory that charges on day one (Disney+ at $4.99/mo), which is the
|
|
39
|
+
* bigger half of the same false claim the card pill was making.
|
|
40
|
+
*/
|
|
41
|
+
readonly trustUnknown: "Terms apply. See the offer for details.";
|
|
27
42
|
readonly primary: "Claim gift";
|
|
28
43
|
readonly secondary: "No thanks";
|
|
29
44
|
/** The secondary's other job — see `RewardActionsOptions.secondary`. */
|
|
30
45
|
readonly next: "Next offer";
|
|
46
|
+
/** The secondary's third job: open the gift flow's "other gifts" sheet. */
|
|
47
|
+
readonly more: "Other gifts";
|
|
31
48
|
};
|
|
32
49
|
export interface RewardActionsOptions {
|
|
33
50
|
/** Claim the selected offer (the variant's `claimOffer` action). */
|
|
@@ -39,6 +56,10 @@ export interface RewardActionsOptions {
|
|
|
39
56
|
* ignored otherwise, so a decline-mode caller need not supply one.
|
|
40
57
|
*/
|
|
41
58
|
onNext?: () => void;
|
|
59
|
+
/**
|
|
60
|
+
* Open the "other gifts" sheet. Required only for `secondary: 'more'`.
|
|
61
|
+
*/
|
|
62
|
+
onMore?: () => void;
|
|
42
63
|
/**
|
|
43
64
|
* WHAT THE SECONDARY BUTTON DOES. Defaults to `'decline'`, which is the
|
|
44
65
|
* "No thanks" every integration has today.
|
|
@@ -50,20 +71,55 @@ export interface RewardActionsOptions {
|
|
|
50
71
|
* lies about what it does, and the slot is better spent on the thing they
|
|
51
72
|
* actually want, which is to see the other offers.
|
|
52
73
|
*
|
|
53
|
-
* `'
|
|
54
|
-
*
|
|
74
|
+
* `'more'` makes it "Other gifts": it opens the gift flow's sheet of the offers
|
|
75
|
+
* that did not fit in the box. The gift composition uses it INSTEAD of "No
|
|
76
|
+
* thanks" and restores the modal's × in exchange, matching the design — the
|
|
77
|
+
* user still has a way out, it is just the × rather than a second CTA, and the
|
|
78
|
+
* slot goes to the thing they are far more likely to want.
|
|
79
|
+
*
|
|
80
|
+
* `'none'` renders nothing. Only for `'next'` with a single offer, or `'more'`
|
|
81
|
+
* with nothing left to show, where the button would be permanently inert.
|
|
55
82
|
*
|
|
56
83
|
* ⚠️ A publisher's own site keeps `'decline'`. `enabled` below can switch
|
|
57
84
|
* CLAIMING off and the decline stays live precisely so a user can always
|
|
58
|
-
* leave; anything but `'decline'` is for a host that leaves for them
|
|
85
|
+
* leave; anything but `'decline'` is for a host that leaves for them, or — for
|
|
86
|
+
* `'more'` — a composition that has restored the ×.
|
|
59
87
|
*/
|
|
60
|
-
secondary?: 'decline' | 'next' | 'none';
|
|
88
|
+
secondary?: 'decline' | 'next' | 'none' | 'more';
|
|
61
89
|
/**
|
|
62
90
|
* Overrides the default trust line. Present so a publisher whose reward is not a
|
|
63
91
|
* free trial is not stuck asserting "No charges until trial ends" — the default
|
|
64
92
|
* is the variant's copy, not a universal truth.
|
|
65
93
|
*/
|
|
66
94
|
trustText?: string;
|
|
95
|
+
/**
|
|
96
|
+
* The gift flow's terms line, rendered UNDER the primary CTA ("One gift per
|
|
97
|
+
* person"). Absent for every other composition, which has no such line.
|
|
98
|
+
*/
|
|
99
|
+
termsText?: string;
|
|
100
|
+
/**
|
|
101
|
+
* A ready-built terms element rendered where `termsText` would be, under the primary
|
|
102
|
+
* CTA. The `giftList` and `giftUnwrap` compositions pass the shared terms line (`ui/termsLine.ts`), whose
|
|
103
|
+
* underlined "offer terms" run is markup a plain string cannot carry. Takes
|
|
104
|
+
* precedence over `termsText` when both are given.
|
|
105
|
+
*/
|
|
106
|
+
termsElement?: HTMLElement;
|
|
107
|
+
/**
|
|
108
|
+
* Whether to render the trust line above the CTA stack. Defaults to `true`.
|
|
109
|
+
*
|
|
110
|
+
* `false` only for a composition whose terms line REPLACES the per-offer fine print
|
|
111
|
+
* (`giftList` and `giftUnwrap`): there the design has nothing above the CTA, and `setTrustText` becomes
|
|
112
|
+
* a no-op because there is no line to write.
|
|
113
|
+
*/
|
|
114
|
+
showTrust?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* The primary CTA's copy, replacing "Claim gift".
|
|
117
|
+
*
|
|
118
|
+
* The gift flow names the selected gift here, and re-words it on every selection
|
|
119
|
+
* change via {@link RewardActions.setPrimaryLabel}. A publisher's own copy still
|
|
120
|
+
* wins — see `ActionSlot.setLabel`.
|
|
121
|
+
*/
|
|
122
|
+
primaryLabel?: string;
|
|
67
123
|
/**
|
|
68
124
|
* When false the primary CTA renders disabled — the host has switched claiming
|
|
69
125
|
* off via `Encore.isClaimEnabled`. "No thanks" stays live: a user must always be
|
|
@@ -105,6 +161,34 @@ export declare class RewardActions {
|
|
|
105
161
|
* when the offer has no advertiser name, so the button is announced by its text.
|
|
106
162
|
*/
|
|
107
163
|
setSelectedOffer(advertiserName?: string): void;
|
|
164
|
+
/**
|
|
165
|
+
* The secondary control's element, or `undefined` when the mode renders none.
|
|
166
|
+
*
|
|
167
|
+
* Exists so a caller that opens something over the sheet can hand focus BACK to the
|
|
168
|
+
* control the user pressed. Read-only by intent: callers position and focus it, they
|
|
169
|
+
* do not rewire it — the behaviour stays owned here.
|
|
170
|
+
*/
|
|
171
|
+
getSecondaryElement(): HTMLElement | undefined;
|
|
172
|
+
/**
|
|
173
|
+
* Replace the trust line, because WHICH LINE IS TRUE depends on the selected offer.
|
|
174
|
+
*
|
|
175
|
+
* Called on every selection change: one sheet can hold a free trial and a paid
|
|
176
|
+
* discount, so a line chosen once at render is wrong as soon as the user moves. A
|
|
177
|
+
* blank or absent value falls back to the shipped default rather than blanking the
|
|
178
|
+
* line, matching how `setPrimaryLabel` treats an empty label.
|
|
179
|
+
*/
|
|
180
|
+
setTrustText(text: string | undefined): void;
|
|
181
|
+
/**
|
|
182
|
+
* Re-word the primary CTA — the gift flow naming the currently selected gift.
|
|
183
|
+
*
|
|
184
|
+
* Held as STATE for the same reason `#selectedAdvertiser` is: the selection is
|
|
185
|
+
* announced during the gift rows' own render, which runs before this block exists,
|
|
186
|
+
* so the first call always lands on a button that has not been built yet.
|
|
187
|
+
*
|
|
188
|
+
* Blank input is ignored rather than blanking the button: an offer that produced no
|
|
189
|
+
* name keeps whatever the CTA already said, which is at worst the shipped default.
|
|
190
|
+
*/
|
|
191
|
+
setPrimaryLabel(label: string | undefined): void;
|
|
108
192
|
destroy(): void;
|
|
109
193
|
}
|
|
110
194
|
//# sourceMappingURL=RewardActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RewardActions.d.ts","sourceRoot":"","sources":["../../src/ui/RewardActions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"RewardActions.d.ts","sourceRoot":"","sources":["../../src/ui/RewardActions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAIlF,mFAAmF;AACnF,eAAO,MAAM,WAAW;IACtB;;;;OAIG;;IAEH;;;;;;;;OAQG;;;;IAIH,wEAAwE;;IAExE,2EAA2E;;CAEnE,CAAC;AAYX,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,wDAAwD;IACxD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjD;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,aAAa;;gBAkCZ,OAAO,EAAE,oBAAoB;IAyBzC,MAAM,IAAI,WAAW;IAyFrB;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI;IAK/C;;;;;;OAMG;IACH,mBAAmB,IAAI,WAAW,GAAG,SAAS;IAI9C;;;;;;;OAOG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAW5C;;;;;;;;;OASG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IA0BhD,OAAO,IAAI,IAAI;CAWhB"}
|
package/types/ui/RewardCard.d.ts
CHANGED
|
@@ -27,15 +27,23 @@ import type { OfferModel as Offer } from '../api/models';
|
|
|
27
27
|
/**
|
|
28
28
|
* Copy the card hard-codes, mirroring `RewardActions`' REWARD_COPY.
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
* contract has no badge/category on
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
30
|
+
* THE BADGE IS PER-OFFER, and this comment used to say the opposite — "no field
|
|
31
|
+
* carries it: the contract has no badge/category on Creative". That was wrong about
|
|
32
|
+
* where to look: `badgeLabel` is on the CAMPAIGN, a constrained enum the contract
|
|
33
|
+
* explicitly tells clients to map to display text. The SDK simply never read it, so
|
|
34
|
+
* every card asserted "Free trial" including for offers that charge on day one.
|
|
35
|
+
*
|
|
36
|
+
* The mapping lives in `ui/offerBadge.ts`; absent or unrecognised reads as
|
|
37
|
+
* "Exclusive", which promises nothing.
|
|
38
|
+
*
|
|
39
|
+
* ⚠️ `badgeText` IS NOT A PUBLISHER ESCAPE HATCH, despite reading like one. Nothing
|
|
40
|
+
* passes it: `OfferCarousel` constructs `new RewardCard()` with no options, and it is
|
|
41
|
+
* absent from `types.ts`, so it is not reachable through `appearance`. The same is
|
|
42
|
+
* true of `RewardActionsOptions.trustText`, whose only caller is the SDK itself. So
|
|
43
|
+
* every reward publisher gets the derived badge and the derived fine print — there is
|
|
44
|
+
* no per-publisher override of either today, and any claim that there is should be
|
|
45
|
+
* checked against these two call sites before it is repeated.
|
|
35
46
|
*/
|
|
36
|
-
export declare const REWARD_CARD_COPY: {
|
|
37
|
-
readonly badge: "Free trial";
|
|
38
|
-
};
|
|
39
47
|
export interface RewardCardOptions {
|
|
40
48
|
/** Overrides the badge pill. Blank/absent keeps the variant's copy. */
|
|
41
49
|
badgeText?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RewardCard.d.ts","sourceRoot":"","sources":["../../src/ui/RewardCard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"RewardCard.d.ts","sourceRoot":"","sources":["../../src/ui/RewardCard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,eAAe,CAAC;AAOzD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;;gBAMT,OAAO,GAAE,iBAAsB;IAI3C,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,WAAW;IA2GjC,OAAO,IAAI,IAAI;CAKhB"}
|
|
@@ -26,6 +26,28 @@ export declare const CONFETTI_SPEC: {
|
|
|
26
26
|
readonly scatter: 46;
|
|
27
27
|
readonly scatterHeight: 0.3;
|
|
28
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* A point inside the host, in CSS pixels from its top-left, that particles fire OUT
|
|
31
|
+
* of — see {@link ConfettiOptions.origin}.
|
|
32
|
+
*/
|
|
33
|
+
export interface ConfettiOrigin {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
}
|
|
37
|
+
export interface ConfettiOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Emit as a BURST from this point instead of the variant's default rain.
|
|
40
|
+
*
|
|
41
|
+
* The reward sheet's own confetti falls from the top edge (`originY: 0.0`), which is
|
|
42
|
+
* what `streaksCarousel.json` specifies and what iOS and Android render. The gift
|
|
43
|
+
* hero needs the other shape: everything leaves the mouth of the box at once and
|
|
44
|
+
* arcs outward. That is a different set of initial conditions for the SAME particle
|
|
45
|
+
* system, not a different particle system — same canvas, same gravity, same drag,
|
|
46
|
+
* same fade, same reduced-motion skip — so it is an option here rather than a second
|
|
47
|
+
* confetti implementation.
|
|
48
|
+
*/
|
|
49
|
+
origin?: ConfettiOrigin;
|
|
50
|
+
}
|
|
29
51
|
export declare class RewardConfetti {
|
|
30
52
|
#private;
|
|
31
53
|
/**
|
|
@@ -40,7 +62,7 @@ export declare class RewardConfetti {
|
|
|
40
62
|
* Mount the burst inside `host` and start it. Returns silently if confetti cannot
|
|
41
63
|
* run; the caller never has to branch.
|
|
42
64
|
*/
|
|
43
|
-
start(host: HTMLElement): void;
|
|
65
|
+
start(host: HTMLElement, options?: ConfettiOptions): void;
|
|
44
66
|
destroy(): void;
|
|
45
67
|
}
|
|
46
68
|
//# sourceMappingURL=RewardConfetti.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RewardConfetti.d.ts","sourceRoot":"","sources":["../../src/ui/RewardConfetti.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,wEAAwE;AACxE,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAkCX,qBAAa,cAAc;;IASzB;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,IAAI,OAAO;IAU5B;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"RewardConfetti.d.ts","sourceRoot":"","sources":["../../src/ui/RewardConfetti.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,wEAAwE;AACxE,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAkCX;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAMD,qBAAa,cAAc;;IASzB;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,IAAI,OAAO;IAU5B;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,GAAE,eAAoB,GAAG,IAAI;IAwK7D,OAAO,IAAI,IAAI;CAWhB"}
|
|
@@ -54,6 +54,41 @@ export interface RewardLayoutOptions {
|
|
|
54
54
|
*/
|
|
55
55
|
headlineSlot?: TextSlot;
|
|
56
56
|
subheadlineSlot?: TextSlot;
|
|
57
|
+
/**
|
|
58
|
+
* A ready-built visual placed ABOVE the status block — the gift flow's opening box.
|
|
59
|
+
*
|
|
60
|
+
* An ELEMENT for the same reason `actions` is: the hero owns an animation, a
|
|
61
|
+
* confetti canvas and a teardown, all three of which this pure render function must
|
|
62
|
+
* not acquire. It only positions it.
|
|
63
|
+
*
|
|
64
|
+
* Above the headline rather than below it because the hero IS the headline's
|
|
65
|
+
* subject: the copy reads "here is a gift for you" and the box has to have opened
|
|
66
|
+
* before that sentence means anything.
|
|
67
|
+
*/
|
|
68
|
+
hero?: HTMLElement;
|
|
69
|
+
/**
|
|
70
|
+
* Marks this as the GIFT composition, which pins the artifact's own palette and copy
|
|
71
|
+
* instead of following the publisher/variant theme.
|
|
72
|
+
*
|
|
73
|
+
* A class on the root rather than a prop threaded into every child: the override is
|
|
74
|
+
* entirely a matter of which colours win, and scoping it to one ancestor keeps every
|
|
75
|
+
* other composition — `reduceChurn`, and any future reward surface — reading the
|
|
76
|
+
* theme exactly as before. See the gift block in styles.ts.
|
|
77
|
+
*/
|
|
78
|
+
giftMode?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* An extra BEM modifier on the root, as `thankyou--{rootModifier}` — how a bespoke
|
|
81
|
+
* reward surface scopes its own palette and composition rules (`gift-list`) without
|
|
82
|
+
* borrowing another surface's. Same reasoning as `giftMode`: one ancestor class, so
|
|
83
|
+
* every other composition keeps reading the theme exactly as before.
|
|
84
|
+
*/
|
|
85
|
+
rootModifier?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Set FREE in the accent colour in the headline, independently of `giftMode`.
|
|
88
|
+
* Defaults to `giftMode`, so the `giftReveal` composition is unchanged. The caller
|
|
89
|
+
* decides it because only the caller knows which tier of the copy chain won.
|
|
90
|
+
*/
|
|
91
|
+
emphasizeFree?: boolean;
|
|
57
92
|
/** Passed to the slot renderers as context. Defaults to the only use case that composes this chrome. */
|
|
58
93
|
useCase?: UseCase;
|
|
59
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RewardLayout.d.ts","sourceRoot":"","sources":["../../src/ui/RewardLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"RewardLayout.d.ts","sourceRoot":"","sources":["../../src/ui/RewardLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG3D;;;;GAIG;AACH,eAAO,MAAM,eAAe,QAAwB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAChC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAC;IACxB,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wGAAwG;IACxG,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,WAAW,EAC5B,OAAO,GAAE,mBAAwB,GAChC,WAAW,CAwFb"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warm the connection to the SELECTED offer's advertiser origin while the user is
|
|
3
|
+
* still deciding, so the tap pays for the navigation rather than for DNS + TCP + TLS.
|
|
4
|
+
*
|
|
5
|
+
* The origin is known as soon as the surface renders — `advertiserUrl` arrives with
|
|
6
|
+
* `offers/search` — while only the transaction id is missing until the claim resolves.
|
|
7
|
+
* So there is a whole deliberation window in which the handshake can already be done.
|
|
8
|
+
*
|
|
9
|
+
* Measured in a WKWebView on an iPhone 16 Pro against the real brokered origin the
|
|
10
|
+
* captured production payload ships (`https://www.searchcactus.com`), one cold sample
|
|
11
|
+
* per app launch, six launches per arm:
|
|
12
|
+
*
|
|
13
|
+
* no preconnect 372 408 418 357 359 383 median 378ms
|
|
14
|
+
* preconnect 97 89 104 128 99 114 median 102ms
|
|
15
|
+
* preconnect crossorigin 87 92 102 99 91 92 median 92ms
|
|
16
|
+
*
|
|
17
|
+
* ~276ms of the pre-navigation cost, for one handshake.
|
|
18
|
+
*
|
|
19
|
+
* 🔴 THE ORIGIN ONLY, NEVER THE URL — and this is a money-pipeline rule, not a
|
|
20
|
+
* performance trade-off to weigh. The final advertiser URL is the ATTRIBUTED CLICK:
|
|
21
|
+
* requesting it records a click against a transaction. Speculatively fetching it would
|
|
22
|
+
* book attribution for users who never tapped and corrupt the conversion data. So
|
|
23
|
+
* nothing here may ever become `rel=prefetch`, `rel=prerender`, `rel=preload`, a
|
|
24
|
+
* `fetch()`, or an image against the advertiser URL. `preconnect` and `dns-prefetch`
|
|
25
|
+
* open a socket and resolve a name; they send no request and no path.
|
|
26
|
+
*
|
|
27
|
+
* NO `crossorigin`, deliberately, and the brief that asked for this suggested it. The
|
|
28
|
+
* crossorigin form warms the ANONYMOUS connection pool (fonts, CORS `fetch`), while the
|
|
29
|
+
* thing that follows is a TOP-LEVEL NAVIGATION, which uses the ordinary one. Measured
|
|
30
|
+
* above, the two are indistinguishable in this webview — so `crossorigin` buys nothing
|
|
31
|
+
* here and the plain form is the one that can definitely serve a navigation. The
|
|
32
|
+
* `dns-prefetch` sibling stays as the fallback for engines that ignore preconnect.
|
|
33
|
+
*
|
|
34
|
+
* ONCE PER PRESENTATION, ON THE FIRST SELECTION — Junaid's call, and it is a privacy
|
|
35
|
+
* decision rather than a performance one. A preconnect is a TLS handshake from the
|
|
36
|
+
* user's IP, so an advertiser learns a user is there before the user has engaged with
|
|
37
|
+
* that offer; today they learn nothing until the click. Warming on every selection
|
|
38
|
+
* change would disclose one advertiser per row the user browses. Warming once
|
|
39
|
+
* discloses exactly one per presentation and keeps most of the ~276ms, because the
|
|
40
|
+
* first selection is the auto-selected offer and therefore the one most likely to be
|
|
41
|
+
* claimed. The same instinct as `no-referrer` on the hosted offer page.
|
|
42
|
+
*
|
|
43
|
+
* So `point()` is a LATCH: the first warmable origin wins and later calls are ignored.
|
|
44
|
+
* That also makes the concurrent-preconnect cap (~6) a non-issue and costs the user
|
|
45
|
+
* exactly one handshake.
|
|
46
|
+
*
|
|
47
|
+
* NOT WIRED AT ALL WHEN CLAIMING IS OFF. With `claimEnabled: false` the CTA is
|
|
48
|
+
* disabled and no navigation to the advertiser can happen, so a handshake there is
|
|
49
|
+
* cost with no possible benefit — and, given the disclosure question this raises, it
|
|
50
|
+
* would be telling an advertiser about a user in a flow that cannot convert.
|
|
51
|
+
*
|
|
52
|
+
* For a BROKERED campaign `advertiserUrl` is the tracking network's host rather than
|
|
53
|
+
* the advertiser's own — that is still the right thing to warm, because it is the first
|
|
54
|
+
* hop the browser actually makes. The redirect to `expectedDomain` happens afterwards,
|
|
55
|
+
* so warming that instead would warm a host this navigation never contacts first.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* The origin to warm, or `null` when there is nothing safe to warm.
|
|
59
|
+
*
|
|
60
|
+
* Exported for the tests, which is worth it: the parsing is the part that must never
|
|
61
|
+
* throw, and it is far easier to prove that against a list of hostile strings than
|
|
62
|
+
* through the DOM.
|
|
63
|
+
*/
|
|
64
|
+
export declare function warmableOrigin(advertiserUrl: string | undefined | null): string | null;
|
|
65
|
+
export declare class AdvertiserPreconnect {
|
|
66
|
+
#private;
|
|
67
|
+
/**
|
|
68
|
+
* @param doc The document to hang the hints on. `null` means "there is no DOM here",
|
|
69
|
+
* which must degrade to doing nothing rather than throwing. It is `null` and not
|
|
70
|
+
* `undefined` on purpose: `undefined` is what a caller passes when it wants the
|
|
71
|
+
* default, so it cannot also mean "none" — a parameter default is applied to
|
|
72
|
+
* `undefined`, which made the no-DOM case impossible to express or to test.
|
|
73
|
+
*/
|
|
74
|
+
constructor(doc?: Document | null);
|
|
75
|
+
/** The origin currently being warmed, or `null`. Exposed for assertions. */
|
|
76
|
+
get origin(): string | null;
|
|
77
|
+
/**
|
|
78
|
+
* Warm this offer's advertiser origin, if nothing has been warmed yet.
|
|
79
|
+
*
|
|
80
|
+
* Safe to call on every selection change, and deliberately DOES NOTHING after the
|
|
81
|
+
* first success: this is a latch, not a follower. See the header — warming per
|
|
82
|
+
* selection would disclose the user to one advertiser per row they browse.
|
|
83
|
+
*
|
|
84
|
+
* A call that resolves no warmable origin does not spend the latch, so a first
|
|
85
|
+
* selection with a malformed `advertiserUrl` still lets the next one warm.
|
|
86
|
+
*/
|
|
87
|
+
point(advertiserUrl: string | undefined | null): void;
|
|
88
|
+
destroy(): void;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=advertiserPreconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advertiserPreconnect.d.ts","sourceRoot":"","sources":["../../src/ui/advertiserPreconnect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAKH;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAoBtF;AAED,qBAAa,oBAAoB;;IAM/B;;;;;;OAMG;gBACS,GAAG,GAAE,QAAQ,GAAG,IAAwD;IAIpF,4EAA4E;IAC5E,IAAI,MAAM,IAAI,MAAM,GAAG,IAAI,CAE1B;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI;IA6BrD,OAAO,IAAI,IAAI;CAWhB"}
|
package/types/ui/appearance.d.ts
CHANGED
|
@@ -136,6 +136,33 @@ export interface ActionSlotOptions {
|
|
|
136
136
|
export interface ActionSlot {
|
|
137
137
|
element: HTMLElement;
|
|
138
138
|
setAccessibleName: (name: string | undefined) => void;
|
|
139
|
+
/**
|
|
140
|
+
* Re-word the control's VISIBLE label.
|
|
141
|
+
*
|
|
142
|
+
* For the gift flow's CTA, which names the gift the user has currently selected and
|
|
143
|
+
* therefore changes as they move through the radio group. Distinct from
|
|
144
|
+
* `setAccessibleName`, which EXTENDS the label for screen readers without altering
|
|
145
|
+
* what is drawn (WCAG 2.5.3); this replaces the drawn text outright.
|
|
146
|
+
*
|
|
147
|
+
* 🔴 A NO-OP WHENEVER THE PUBLISHER OWNS THE TEXT. If they supplied their own element
|
|
148
|
+
* or overrode the copy through a style config, that copy stands — the appearance API
|
|
149
|
+
* is theirs, and silently rewriting a button they worded is exactly the boundary
|
|
150
|
+
* violation `createActionSlot` exists to prevent. A custom element with no text of
|
|
151
|
+
* its own (an icon, an image) still gets its accessible-name fallback updated, since
|
|
152
|
+
* the SDK owns that string in the first place.
|
|
153
|
+
*/
|
|
154
|
+
setLabel: (text: string) => void;
|
|
155
|
+
/**
|
|
156
|
+
* The control's EFFECTIVE VISIBLE label — the publisher's copy when they supplied
|
|
157
|
+
* any, the SDK's otherwise.
|
|
158
|
+
*
|
|
159
|
+
* Exists because WCAG 2.5.3 (Label in Name) constrains the accessible name to CONTAIN
|
|
160
|
+
* the visible one, so anything that extends the name has to extend what is actually
|
|
161
|
+
* drawn rather than what the SDK would have drawn. Reading it back from the control
|
|
162
|
+
* is the only way to be right in the two cases where those differ: a style config
|
|
163
|
+
* that replaced the copy, and a publisher element carrying its own text.
|
|
164
|
+
*/
|
|
165
|
+
getLabel: () => string;
|
|
139
166
|
/**
|
|
140
167
|
* Detach the SDK's listeners and release the publisher's element.
|
|
141
168
|
*
|