@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.
Files changed (68) hide show
  1. package/README.md +6 -0
  2. package/dist/cjs/index.cjs +1 -1
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/esm/index.js +1 -1
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/umd/encore.min.js +1 -1
  7. package/dist/umd/encore.min.js.map +1 -1
  8. package/package.json +1 -1
  9. package/types/api/APIClient.d.ts +18 -0
  10. package/types/api/APIClient.d.ts.map +1 -1
  11. package/types/api/generated/types.d.ts +177 -2
  12. package/types/api/generated/types.d.ts.map +1 -1
  13. package/types/api/models.d.ts +32 -0
  14. package/types/api/models.d.ts.map +1 -1
  15. package/types/core/Encore.d.ts.map +1 -1
  16. package/types/core/giftVariant.d.ts +67 -0
  17. package/types/core/giftVariant.d.ts.map +1 -0
  18. package/types/core/version.d.ts +1 -1
  19. package/types/types.d.ts +31 -3
  20. package/types/types.d.ts.map +1 -1
  21. package/types/ui/GiftHero.d.ts +75 -0
  22. package/types/ui/GiftHero.d.ts.map +1 -0
  23. package/types/ui/GiftList.d.ts +110 -0
  24. package/types/ui/GiftList.d.ts.map +1 -0
  25. package/types/ui/GiftReveal.d.ts +133 -0
  26. package/types/ui/GiftReveal.d.ts.map +1 -0
  27. package/types/ui/GiftSheet.d.ts +126 -0
  28. package/types/ui/GiftSheet.d.ts.map +1 -0
  29. package/types/ui/GiftUnwrap.d.ts +155 -0
  30. package/types/ui/GiftUnwrap.d.ts.map +1 -0
  31. package/types/ui/OfferCarousel.d.ts +10 -3
  32. package/types/ui/OfferCarousel.d.ts.map +1 -1
  33. package/types/ui/OfferModal.d.ts +7 -0
  34. package/types/ui/OfferModal.d.ts.map +1 -1
  35. package/types/ui/RewardActions.d.ts +88 -4
  36. package/types/ui/RewardActions.d.ts.map +1 -1
  37. package/types/ui/RewardCard.d.ts +16 -8
  38. package/types/ui/RewardCard.d.ts.map +1 -1
  39. package/types/ui/RewardConfetti.d.ts +23 -1
  40. package/types/ui/RewardConfetti.d.ts.map +1 -1
  41. package/types/ui/RewardLayout.d.ts +35 -0
  42. package/types/ui/RewardLayout.d.ts.map +1 -1
  43. package/types/ui/advertiserPreconnect.d.ts +90 -0
  44. package/types/ui/advertiserPreconnect.d.ts.map +1 -0
  45. package/types/ui/appearance.d.ts +27 -0
  46. package/types/ui/appearance.d.ts.map +1 -1
  47. package/types/ui/focusable.d.ts +41 -0
  48. package/types/ui/focusable.d.ts.map +1 -0
  49. package/types/ui/giftCategoryGroups.d.ts +21 -0
  50. package/types/ui/giftCategoryGroups.d.ts.map +1 -0
  51. package/types/ui/giftCopy.d.ts +215 -0
  52. package/types/ui/giftCopy.d.ts.map +1 -0
  53. package/types/ui/giftUnwrapArt.d.ts +55 -0
  54. package/types/ui/giftUnwrapArt.d.ts.map +1 -0
  55. package/types/ui/giftUnwrapCopy.d.ts +57 -0
  56. package/types/ui/giftUnwrapCopy.d.ts.map +1 -0
  57. package/types/ui/impressionGate.d.ts +63 -0
  58. package/types/ui/impressionGate.d.ts.map +1 -0
  59. package/types/ui/offerBadge.d.ts +56 -0
  60. package/types/ui/offerBadge.d.ts.map +1 -0
  61. package/types/ui/rewardSurface.d.ts +82 -0
  62. package/types/ui/rewardSurface.d.ts.map +1 -0
  63. package/types/ui/safeImageSrc.d.ts +10 -0
  64. package/types/ui/safeImageSrc.d.ts.map +1 -1
  65. package/types/ui/styles.d.ts +166 -0
  66. package/types/ui/styles.d.ts.map +1 -1
  67. package/types/ui/termsLine.d.ts +33 -0
  68. 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 stays deduped to
77
- * once-per-index-per-rest: this is the navigation itself, so a user paging
78
- * 0→1→0 produces three scrolls and two impressions. `axis` is a real dimension
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;AAQhD,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;CACzB;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;;gBAuEZ,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB;IAoBvF;;OAEG;IACH,MAAM,IAAI,WAAW;IA8PrB;;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;IA4nBhB;;OAEG;IACH,OAAO,IAAI,IAAI;CA2BhB"}
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"}
@@ -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;AAG/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;CACZ;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;;gBAsBT,KAAK,GAAE,cAAmB,EAAE,OAAO,GAAE,iBAAsB;IAavE;;OAEG;IACH,IAAI,IAAI,IAAI;IAqCZ;;OAEG;IACH,IAAI,IAAI,IAAI;IA4CZ;;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;IAmKb;;OAEG;IACH,OAAO,IAAI,IAAI;CAoBhB"}
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
- * `'none'` renders nothing. Only for `'next'` with a single offer, where the
54
- * button would be permanently inert.
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;AAElF,mFAAmF;AACnF,eAAO,MAAM,WAAW;;;;IAItB,wEAAwE;;CAEhE,CAAC;AAEX,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;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;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;;gBAwBZ,OAAO,EAAE,oBAAoB;IAIzC,MAAM,IAAI,WAAW;IA8DrB;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI;IAW/C,OAAO,IAAI,IAAI;CAWhB"}
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"}
@@ -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
- * The badge is SDK-owned rather than per-offer because no field carries it: the
31
- * contract has no badge/category on `Creative`, and the Figma's own cards disagree
32
- * with each other (a "Free 30 days trial" pill above a "50% discount for 3 month"
33
- * line). It is overridable for the same reason the trust line is — a publisher whose
34
- * reward is not a trial must not be stuck asserting one.
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;AAMzD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB;;CAEnB,CAAC;AAEX,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"}
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;IAmI9B,OAAO,IAAI,IAAI;CAWhB"}
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;AAE3D;;;;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,wGAAwG;IACxG,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,WAAW,EAC5B,OAAO,GAAE,mBAAwB,GAChC,WAAW,CA+Db"}
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"}
@@ -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
  *