@encorekit/web-sdk 1.1.21 → 2.0.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 +190 -46
- 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 +4 -3
- package/types/analytics/AnalyticsClient.d.ts +11 -1
- package/types/analytics/AnalyticsClient.d.ts.map +1 -1
- package/types/analytics/events.d.ts +192 -19
- package/types/analytics/events.d.ts.map +1 -1
- package/types/analytics/transport.d.ts.map +1 -1
- package/types/api/APIClient.d.ts +36 -7
- package/types/api/APIClient.d.ts.map +1 -1
- package/types/api/generated/types.d.ts +548 -1
- package/types/api/generated/types.d.ts.map +1 -1
- package/types/api/models.d.ts +8 -3
- package/types/api/models.d.ts.map +1 -1
- package/types/core/Configuration.d.ts +0 -4
- package/types/core/Configuration.d.ts.map +1 -1
- package/types/core/Encore.d.ts +8 -33
- package/types/core/Encore.d.ts.map +1 -1
- package/types/core/OfferManager.d.ts +50 -9
- package/types/core/OfferManager.d.ts.map +1 -1
- package/types/core/PlacementBuilder.d.ts +11 -12
- package/types/core/PlacementBuilder.d.ts.map +1 -1
- package/types/core/useCase.d.ts +62 -0
- package/types/core/useCase.d.ts.map +1 -0
- package/types/core/version.d.ts +1 -1
- package/types/core/version.d.ts.map +1 -1
- package/types/types.d.ts +92 -223
- package/types/types.d.ts.map +1 -1
- package/types/ui/OfferCarousel.d.ts +81 -0
- package/types/ui/OfferCarousel.d.ts.map +1 -1
- package/types/ui/RewardActions.d.ts +60 -0
- package/types/ui/RewardActions.d.ts.map +1 -0
- package/types/ui/RewardCard.d.ts +49 -0
- package/types/ui/RewardCard.d.ts.map +1 -0
- package/types/ui/RewardConfetti.d.ts +46 -0
- package/types/ui/RewardConfetti.d.ts.map +1 -0
- package/types/ui/RewardLayout.d.ts +55 -0
- package/types/ui/RewardLayout.d.ts.map +1 -0
- package/types/ui/ThankYouLayout.d.ts +11 -0
- package/types/ui/ThankYouLayout.d.ts.map +1 -1
- package/types/ui/brandTint.d.ts +61 -0
- package/types/ui/brandTint.d.ts.map +1 -0
- package/types/ui/styles.d.ts +86 -0
- package/types/ui/styles.d.ts.map +1 -1
- package/types/utils/text.d.ts +24 -0
- package/types/utils/text.d.ts.map +1 -0
- package/examples/react/.env +0 -1
|
@@ -12,6 +12,39 @@ export interface OfferCarouselOptions {
|
|
|
12
12
|
* carousel at every breakpoint, with chevron nav bubbles.
|
|
13
13
|
*/
|
|
14
14
|
mode?: 'responsive' | 'paged';
|
|
15
|
+
/**
|
|
16
|
+
* Suppress the carousel's own title/subtitle header block entirely (reward
|
|
17
|
+
* composition — see Encore.ts's `#runOfferFlow`). The carousel's header exists to
|
|
18
|
+
* carry paywall-flavored copy (a titleText/customHeadline default, or the hardcoded
|
|
19
|
+
* "Unlock 10 free articles…" fallback when neither is configured) or the thankYou
|
|
20
|
+
* layout's offerContext priming pair — reward has neither: its own headline already
|
|
21
|
+
* renders in the reward chrome above this carousel, and the modal's
|
|
22
|
+
* accessible name is already pointed at THAT title (see THANKYOU_TITLE_ID), so
|
|
23
|
+
* hiding this header is a11y-safe, not just visually tidier.
|
|
24
|
+
*/
|
|
25
|
+
hideHeader?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* SELECTION MODE (reward composition). Turns the carousel from "N self-contained
|
|
28
|
+
* offer tiles, each with its own Claim" into "a list you pick ONE offer from",
|
|
29
|
+
* matching `streaksCarousel.json`'s `autoSelectFirstOffer` + `selectOffer` model
|
|
30
|
+
* that iOS and Android already render. Three things change:
|
|
31
|
+
*
|
|
32
|
+
* - Cards lose their per-card Claim button (see OfferCardOptions.selectable) and
|
|
33
|
+
* become selection targets. The host drives the claim via `claimSelected()`.
|
|
34
|
+
* - The prev/next chevrons are replaced by a compact dot page indicator, the
|
|
35
|
+
* variant's `compactPageIndicator`.
|
|
36
|
+
* - The cards container becomes a real `role="listbox"`.
|
|
37
|
+
*
|
|
38
|
+
* SELECTION HAS EXACTLY ONE SOURCE: `#currentIndex`. Paging IS selecting and
|
|
39
|
+
* selecting IS paging — the centered card is the selected card, always. This is
|
|
40
|
+
* deliberate: iOS shipped a version where the CTA's offer and the carousel's
|
|
41
|
+
* position were two independent pieces of state, they diverged, and `claimOffer`
|
|
42
|
+
* silently dropped a nil offer (EncoreKit/swift#106). One index cannot diverge
|
|
43
|
+
* from itself.
|
|
44
|
+
*
|
|
45
|
+
* Off by default, so the churn-intervention and thankYou carousels are untouched.
|
|
46
|
+
*/
|
|
47
|
+
selectable?: boolean;
|
|
15
48
|
}
|
|
16
49
|
interface CarouselEventMap extends Record<string, unknown> {
|
|
17
50
|
offerClaim: {
|
|
@@ -25,9 +58,31 @@ interface CarouselEventMap extends Record<string, unknown> {
|
|
|
25
58
|
offer: Offer;
|
|
26
59
|
index: number;
|
|
27
60
|
};
|
|
61
|
+
/**
|
|
62
|
+
* The user moved to a different card, by any means (gesture, arrows, keyboard).
|
|
63
|
+
* Distinct from `offerView`, which is an IMPRESSION and stays deduped to
|
|
64
|
+
* once-per-index-per-rest: this is the navigation itself, so a user paging
|
|
65
|
+
* 0→1→0 produces three scrolls and two impressions. `axis` is a real dimension
|
|
66
|
+
* on web — the same carousel is horizontal on desktop and a vertical list on
|
|
67
|
+
* mobile — and is what `sdk_sdui_scroll` reports.
|
|
68
|
+
*/
|
|
69
|
+
scroll: {
|
|
70
|
+
axis: 'horizontal' | 'vertical';
|
|
71
|
+
position: number;
|
|
72
|
+
};
|
|
28
73
|
complete: {
|
|
29
74
|
claimed: boolean;
|
|
30
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* The selected offer changed (selection mode only). A STATE notification, not an
|
|
78
|
+
* analytics event — it exists so the sheet's single CTA can name what it will
|
|
79
|
+
* claim. It fires once at mount for the auto-selected first offer, which is what
|
|
80
|
+
* makes the CTA correct before the user touches anything.
|
|
81
|
+
*/
|
|
82
|
+
offerSelect: {
|
|
83
|
+
offer: Offer;
|
|
84
|
+
index: number;
|
|
85
|
+
};
|
|
31
86
|
}
|
|
32
87
|
export declare class OfferCarousel {
|
|
33
88
|
#private;
|
|
@@ -54,6 +109,32 @@ export declare class OfferCarousel {
|
|
|
54
109
|
* scroll as an effect. The highlight is not touched — it follows the motion.
|
|
55
110
|
*/
|
|
56
111
|
next(): void;
|
|
112
|
+
/**
|
|
113
|
+
* The offer the sheet's single CTA acts on. In selection mode this is the
|
|
114
|
+
* centered/selected card; elsewhere it is simply the current one. Never
|
|
115
|
+
* undefined for a rendered carousel (the constructor rejects an empty list),
|
|
116
|
+
* but typed honestly so callers cannot assume.
|
|
117
|
+
*/
|
|
118
|
+
getSelectedOffer(): Offer | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Claim the SELECTED offer — the reward sheet's one bottom CTA (the variant's
|
|
121
|
+
* `claimOffer` action).
|
|
122
|
+
*
|
|
123
|
+
* It emits the SAME `offerClaim` event a per-card Claim button emits, on purpose:
|
|
124
|
+
* every downstream guarantee (transaction creation and its `transactionId`, the
|
|
125
|
+
* `use_case` stamp on claim analytics, the synchronous advertiser-window open that
|
|
126
|
+
* survives mobile popup blockers, the deferred/immediate branch) lives in that one
|
|
127
|
+
* handler in Encore.ts. Routing the new CTA through it means reward inherits all of
|
|
128
|
+
* it rather than growing a second, drifting claim path.
|
|
129
|
+
*/
|
|
130
|
+
claimSelected(): void;
|
|
131
|
+
/**
|
|
132
|
+
* Select the offer at `index` — the variant's `selectOffer` action, reached by
|
|
133
|
+
* tapping a card or by arrowing within the listbox. A user INTENT, so it follows
|
|
134
|
+
* exactly the same path as next()/previous(): commit domain state, render the
|
|
135
|
+
* semantic view, then run the scroll as an effect.
|
|
136
|
+
*/
|
|
137
|
+
selectOffer(index: number): void;
|
|
57
138
|
/**
|
|
58
139
|
* Navigate to previous offer — see next().
|
|
59
140
|
*/
|
|
@@ -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,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;CACtB;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;;gBAkEZ,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,oBAAoB;IAiBvF;;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;IAqnBhB;;OAEG;IACH,OAAO,IAAI,IAAI;CA2BhB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reward action block — the bottom of the post-action-reward sheet.
|
|
3
|
+
*
|
|
4
|
+
* Trust line, then a two-button CTA stack: ONE primary that claims the SELECTED
|
|
5
|
+
* offer, and a secondary that dismisses. This is the interaction model
|
|
6
|
+
* `streaksCarousel.json` describes and that iOS and Android already render; web
|
|
7
|
+
* previously put a Claim button on every card and offered no explicit decline.
|
|
8
|
+
*
|
|
9
|
+
* NOT a renderer. Every value below is read off the variant and hard-coded here —
|
|
10
|
+
* web has no SDUI engine, and the variant JSON is a design spec this file tracks by
|
|
11
|
+
* hand, never something the SDK parses:
|
|
12
|
+
*
|
|
13
|
+
* trust line 14 / regular, onBackground @ 0.55, 2-line clamp
|
|
14
|
+
* primary "Claim gift", 16 / bold, onAccent on accent, radius 12, 16px y-padding
|
|
15
|
+
* secondary "No thanks", 16 / medium, muted, 1px border, radius 12, 14px y-padding
|
|
16
|
+
* stack vStack spacing 8, inside a group of spacing 12, 20px gutters
|
|
17
|
+
*
|
|
18
|
+
* Callbacks rather than an EventEmitter: there are exactly two, both fire at most
|
|
19
|
+
* once per sheet, and neither has a second subscriber. The emitter would be
|
|
20
|
+
* ceremony around a pair of function calls.
|
|
21
|
+
*/
|
|
22
|
+
/** Copy the variant hard-codes. Named so the tests can assert parity by symbol. */
|
|
23
|
+
export declare const REWARD_COPY: {
|
|
24
|
+
readonly trust: "No charges until trial ends, cancel anytime.";
|
|
25
|
+
readonly primary: "Claim gift";
|
|
26
|
+
readonly secondary: "No thanks";
|
|
27
|
+
};
|
|
28
|
+
export interface RewardActionsOptions {
|
|
29
|
+
/** Claim the selected offer (the variant's `claimOffer` action). */
|
|
30
|
+
onClaim: () => void;
|
|
31
|
+
/** Dismiss the sheet (the variant's `close` action). */
|
|
32
|
+
onDecline: () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Overrides the default trust line. Present so a publisher whose reward is not a
|
|
35
|
+
* free trial is not stuck asserting "No charges until trial ends" — the default
|
|
36
|
+
* is the variant's copy, not a universal truth.
|
|
37
|
+
*/
|
|
38
|
+
trustText?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare class RewardActions {
|
|
41
|
+
#private;
|
|
42
|
+
constructor(options: RewardActionsOptions);
|
|
43
|
+
render(): HTMLElement;
|
|
44
|
+
/**
|
|
45
|
+
* Name the offer the CTA will claim.
|
|
46
|
+
*
|
|
47
|
+
* "Claim gift" alone is ambiguous the moment there is more than one card on
|
|
48
|
+
* screen and no per-card button left to disambiguate — a screen-reader user
|
|
49
|
+
* arrowing the listbox has no way to tell what the single bottom button now acts
|
|
50
|
+
* on. The visible label stays exactly "Claim gift" (the variant's copy, and what
|
|
51
|
+
* a sighted user reads), and the accessible name EXTENDS it rather than replacing
|
|
52
|
+
* it, which is what WCAG 2.5.3 Label in Name requires.
|
|
53
|
+
*
|
|
54
|
+
* Falls back to removing the label entirely — never to a half-built sentence —
|
|
55
|
+
* when the offer has no advertiser name, so the button is announced by its text.
|
|
56
|
+
*/
|
|
57
|
+
setSelectedOffer(advertiserName?: string): void;
|
|
58
|
+
destroy(): void;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=RewardActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RewardActions.d.ts","sourceRoot":"","sources":["../../src/ui/RewardActions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,mFAAmF;AACnF,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAEX,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,wDAAwD;IACxD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,aAAa;;gBAaZ,OAAO,EAAE,oBAAoB;IAIzC,MAAM,IAAI,WAAW;IAmCrB;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI;IAe/C,OAAO,IAAI,IAAI;CAKhB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reward offer card — the tile the Figma's `streaksCarousel` hero shows.
|
|
3
|
+
*
|
|
4
|
+
* A DIFFERENT card from `OfferCard`, not a variant of it. OfferCard is a wide banner
|
|
5
|
+
* image over a merchant row with its own Claim button; this is a 210×260 portrait
|
|
6
|
+
* tile — pill, icon, advertiser, offer line — centred on a wash of the advertiser's
|
|
7
|
+
* colour. They share no element, so expressing this as more flags on OfferCard would
|
|
8
|
+
* have meant a component that renders two unrelated layouts and a churn-intervention
|
|
9
|
+
* card one boolean away from the reward one. Separate file, separate class names:
|
|
10
|
+
* the churn path cannot reach a single line of this.
|
|
11
|
+
*
|
|
12
|
+
* NOT a renderer. Web has no SDUI engine; every value below is read off the Figma by
|
|
13
|
+
* hand (frame 18304:2399, node 18304:3383) and tracked here:
|
|
14
|
+
*
|
|
15
|
+
* card 210×260, radius 24, tint@10% over white
|
|
16
|
+
* shadow 0 4px 12px rgba(0,0,0,.09), 0 4px 12px rgba(0,0,0,.02),
|
|
17
|
+
* 0 4px 74px rgba(0,0,0,.06)
|
|
18
|
+
* pill top 43, white, radius 16, pad 4/10, 14 / medium
|
|
19
|
+
* icon top 84, 72×72, radius 18
|
|
20
|
+
* name top 176, 18 / semibold, tracking -0.18
|
|
21
|
+
* offer top 201, 14 / regular, tracking -0.28
|
|
22
|
+
*
|
|
23
|
+
* The Figma's Audible orange is NOT hardcoded — offers are remote and arbitrary. See
|
|
24
|
+
* `brandTint.ts` for how the wash is derived per offer.
|
|
25
|
+
*/
|
|
26
|
+
import type { OfferModel as Offer } from '../api/models';
|
|
27
|
+
/**
|
|
28
|
+
* Copy the card hard-codes, mirroring `RewardActions`' REWARD_COPY.
|
|
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.
|
|
35
|
+
*/
|
|
36
|
+
export declare const REWARD_CARD_COPY: {
|
|
37
|
+
readonly badge: "Free trial";
|
|
38
|
+
};
|
|
39
|
+
export interface RewardCardOptions {
|
|
40
|
+
/** Overrides the badge pill. Blank/absent keeps the variant's copy. */
|
|
41
|
+
badgeText?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare class RewardCard {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(options?: RewardCardOptions);
|
|
46
|
+
render(offer: Offer): HTMLElement;
|
|
47
|
+
destroy(): void;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=RewardCard.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reward confetti — the variant's celebration layer.
|
|
3
|
+
*
|
|
4
|
+
* `streaksCarousel.json` opens the sheet with a `confetti` burst that web never had:
|
|
5
|
+
*
|
|
6
|
+
* intensity 22 particle count
|
|
7
|
+
* duration 2.0 seconds, then the layer removes itself
|
|
8
|
+
* originY 0.0 emitted from the TOP edge, falling down
|
|
9
|
+
* scatter 46 horizontal spread, in points, around each particle's origin
|
|
10
|
+
* scatterHeight 0.3 origins spread over the top 30% of the sheet
|
|
11
|
+
* style maxWidth/maxHeight infinity, ignoresSafeArea — full-bleed
|
|
12
|
+
*
|
|
13
|
+
* Hand-rolled on a single 2D canvas: the SDK ships zero runtime dependencies, and a
|
|
14
|
+
* confetti library would be several KB for 22 rectangles falling for two seconds.
|
|
15
|
+
*
|
|
16
|
+
* Purely decorative and entirely optional. It is `aria-hidden`, it takes no pointer
|
|
17
|
+
* events, it is skipped outright under `prefers-reduced-motion`, and every entry
|
|
18
|
+
* point is guarded — an environment without a 2D context (jsdom, a locked-down
|
|
19
|
+
* browser) simply gets no confetti rather than an exception on a host page.
|
|
20
|
+
*/
|
|
21
|
+
/** The variant's values, named so tests can assert parity by symbol. */
|
|
22
|
+
export declare const CONFETTI_SPEC: {
|
|
23
|
+
readonly intensity: 22;
|
|
24
|
+
readonly durationMs: 2000;
|
|
25
|
+
readonly originY: 0;
|
|
26
|
+
readonly scatter: 46;
|
|
27
|
+
readonly scatterHeight: 0.3;
|
|
28
|
+
};
|
|
29
|
+
export declare class RewardConfetti {
|
|
30
|
+
#private;
|
|
31
|
+
/**
|
|
32
|
+
* True when the burst should be skipped entirely.
|
|
33
|
+
*
|
|
34
|
+
* `prefers-reduced-motion` is a hard skip, not a slowdown: falling confetti is
|
|
35
|
+
* exactly the large-area motion the setting exists to suppress, and the sheet
|
|
36
|
+
* loses nothing functional without it.
|
|
37
|
+
*/
|
|
38
|
+
static shouldSkip(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Mount the burst inside `host` and start it. Returns silently if confetti cannot
|
|
41
|
+
* run; the caller never has to branch.
|
|
42
|
+
*/
|
|
43
|
+
start(host: HTMLElement): void;
|
|
44
|
+
destroy(): void;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=RewardConfetti.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reward chrome — the composition `useCase: 'rewardUsers'` renders.
|
|
3
|
+
*
|
|
4
|
+
* Pure chrome around the unchanged OfferCarousel: a status block (success check +
|
|
5
|
+
* headline + subheadline) above the offers. A pure render function rather than a
|
|
6
|
+
* component class: the chrome is static content with no events, no listeners, and no
|
|
7
|
+
* state — the carousel keeps its own lifecycle and is passed in as a ready element.
|
|
8
|
+
*
|
|
9
|
+
* The `thankyou` class names are deliberately UNCHANGED from when this chrome was
|
|
10
|
+
* also reachable as a publisher-selectable `layout: 'thankYou'` (retired in 3.0.0).
|
|
11
|
+
* They are internal style hooks, not public API, and renaming them would churn the
|
|
12
|
+
* whole visual system — including the `--reward` parity rules that track the native
|
|
13
|
+
* SDKs' `streaksCarousel.json` type scale — for no behavioural gain.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* The id given to the status heading so the dialog's accessible name can point at
|
|
17
|
+
* the chrome's real primary heading (the carousel's own header is suppressed in this
|
|
18
|
+
* composition, so it is not available as a fallback `aria-labelledby` target).
|
|
19
|
+
*/
|
|
20
|
+
export declare const REWARD_TITLE_ID: string;
|
|
21
|
+
export interface RewardLayoutOptions {
|
|
22
|
+
/** Resolved headline. Required in practice — it is the dialog's accessible name. */
|
|
23
|
+
title?: string;
|
|
24
|
+
/** Resolved subheadline. Omitted (never `''`) when nothing resolved. */
|
|
25
|
+
subtitle?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Status icon above the headline. Defaults to `'none'`, matching the native
|
|
28
|
+
* variant — see `PlacementOptions.statusIcon`. `'success'` opts into a
|
|
29
|
+
* green-circle check.
|
|
30
|
+
*/
|
|
31
|
+
statusIcon?: 'success' | 'none';
|
|
32
|
+
/**
|
|
33
|
+
* A ready-built action block placed directly under the carousel — the trust line
|
|
34
|
+
* and the single bottom CTA pair (see RewardActions). The variant puts the CTA
|
|
35
|
+
* stack last in the sheet, and nothing renders below it there.
|
|
36
|
+
*
|
|
37
|
+
* An ELEMENT, not a config object, on purpose: this module is a pure render
|
|
38
|
+
* function with no events, no listeners and no state, and the action block is all
|
|
39
|
+
* three. Taking it pre-built keeps the ownership boundary — RewardActions owns its
|
|
40
|
+
* listeners and its teardown; this function only positions it.
|
|
41
|
+
*/
|
|
42
|
+
actions?: HTMLElement;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Compose the reward sheet: status (optional check → title → subtitle) → carousel.
|
|
46
|
+
*
|
|
47
|
+
* All host-supplied copy is set via textContent (text-only, injection-safe).
|
|
48
|
+
*
|
|
49
|
+
* The check is OPT-IN (`statusIcon: 'success'`) and off by default, matching the
|
|
50
|
+
* native reward variant, which renders no checkmark at all. It is `aria-hidden`
|
|
51
|
+
* either way, so its presence never affects the dialog's accessible name — that
|
|
52
|
+
* always comes from the title below.
|
|
53
|
+
*/
|
|
54
|
+
export declare function renderRewardLayout(carouselElement: HTMLElement, options?: RewardLayoutOptions): HTMLElement;
|
|
55
|
+
//# sourceMappingURL=RewardLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RewardLayout.d.ts","sourceRoot":"","sources":["../../src/ui/RewardLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;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;CACvB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,WAAW,EAC5B,OAAO,GAAE,mBAAwB,GAChC,WAAW,CA8Cb"}
|
|
@@ -26,6 +26,17 @@ export interface ThankYouLayoutOptions {
|
|
|
26
26
|
footer?: PlacementFooterConfig;
|
|
27
27
|
/** Per-transaction receipt — owns the subtitle slot when provided. */
|
|
28
28
|
receipt?: Receipt;
|
|
29
|
+
/**
|
|
30
|
+
* Marks this as the REWARD composition rather than the payment-status one, adding
|
|
31
|
+
* the `--reward` modifier so the parity styles can be scoped to it.
|
|
32
|
+
*
|
|
33
|
+
* The two share this chrome but are not the same screen. `thankYou` confirms a
|
|
34
|
+
* payment the user just made; reward celebrates an action and offers a gift, and
|
|
35
|
+
* on the native SDKs it is a full-screen surface with its own type scale (see
|
|
36
|
+
* `streaksCarousel.json`). Keeping the modifier off by default means every
|
|
37
|
+
* existing `thankYou` render stays byte-identical.
|
|
38
|
+
*/
|
|
39
|
+
reward?: boolean;
|
|
29
40
|
}
|
|
30
41
|
/**
|
|
31
42
|
* Compose the thankYou sheet: status (check → title → subtitle) → carousel → footer.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThankYouLayout.d.ts","sourceRoot":"","sources":["../../src/ui/ThankYouLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,OAAO,EACR,MAAM,UAAU,CAAC;AAOlB;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAO7D;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ThankYouLayout.d.ts","sourceRoot":"","sources":["../../src/ui/ThankYouLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,OAAO,EACR,MAAM,UAAU,CAAC;AAOlB;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAO7D;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAqCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,WAAW,EAC5B,OAAO,GAAE,qBAA0B,GAClC,WAAW,CAkDb"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-offer brand tint for the reward card.
|
|
3
|
+
*
|
|
4
|
+
* The Figma renders each card on a wash of the advertiser's own colour — Audible's
|
|
5
|
+
* card is `rgba(255,159,43,0.1)` over white. `streaksCarousel.json` binds that as
|
|
6
|
+
* `offerDominantColor`.
|
|
7
|
+
*
|
|
8
|
+
* THERE IS NO API FIELD BEHIND THAT BINDING, on any platform. iOS and Android compute
|
|
9
|
+
* it from the logo at render time; the contract carries no colour on `Creative`,
|
|
10
|
+
* `Organization` or `Campaign`. So sampling the icon is not a web workaround for a
|
|
11
|
+
* missing field — it IS the canonical implementation, and this module is web's copy
|
|
12
|
+
* of it. Native's rule, verbatim: *"the dominant color used in the icon that is not
|
|
13
|
+
* straight black or straight white."*
|
|
14
|
+
*
|
|
15
|
+
* Two tiers, and the first one always succeeds. Native is single-tier; web needs the
|
|
16
|
+
* extra one because it has a failure mode native does not — a cross-origin logo whose
|
|
17
|
+
* host sends no CORS headers can never be read into a canvas at all.
|
|
18
|
+
*
|
|
19
|
+
* 1. `fallbackTint` — synchronous, deterministic, from the offer's identity. Every
|
|
20
|
+
* card has a tint from its first frame; a card is never briefly untinted and
|
|
21
|
+
* never depends on the network.
|
|
22
|
+
* 2. `sampleLogoTint` — asynchronous, upgrades tier 1 to the real brand colour when
|
|
23
|
+
* the logo is readable. Resolves `null` on ANY failure and never throws.
|
|
24
|
+
*
|
|
25
|
+
* Tier 2 needs a CORS-clean image, and `crossOrigin = 'anonymous'` makes a
|
|
26
|
+
* non-CORS server fail the load OUTRIGHT rather than merely tainting the canvas.
|
|
27
|
+
* That is why this samples a SEPARATE `Image`, never the one on screen: the card's
|
|
28
|
+
* own <img> is loaded without `crossOrigin` so it always renders, and a sampling
|
|
29
|
+
* failure costs a tint upgrade rather than the logo itself.
|
|
30
|
+
*/
|
|
31
|
+
/** How much of the tint the card background gets — the Figma's 0.1 over white. */
|
|
32
|
+
export declare const CARD_TINT_ALPHA = 0.1;
|
|
33
|
+
/**
|
|
34
|
+
* The synchronous tier. Always returns a usable colour.
|
|
35
|
+
*
|
|
36
|
+
* Keyed on the advertiser NAME first so every creative from one advertiser tints
|
|
37
|
+
* identically — the card shows the advertiser, so two Audible offers reading as two
|
|
38
|
+
* different brands would be wrong. Falls back through title to id, which are never
|
|
39
|
+
* both empty.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fallbackTint(seed: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Reduce RGBA pixels to the dominant non-black, non-white colour, or `null` when the
|
|
44
|
+
* image has none.
|
|
45
|
+
*
|
|
46
|
+
* Split out from the canvas plumbing and exported so the rule that actually matters —
|
|
47
|
+
* paper and ink are excluded, greys lose to colour, a monochrome logo yields nothing —
|
|
48
|
+
* is unit-testable. jsdom has no 2D context, so it is unreachable through
|
|
49
|
+
* `extractDominantColor` in tests.
|
|
50
|
+
*
|
|
51
|
+
* @internal exported for tests only.
|
|
52
|
+
*/
|
|
53
|
+
export declare function dominantColorFromPixels(data: Uint8ClampedArray): string | null;
|
|
54
|
+
/**
|
|
55
|
+
* Try to read the advertiser's colour off its logo. Resolves `null` on every failure
|
|
56
|
+
* path — a missing URL, a CORS refusal, a decode error, a timeout, a greyscale logo,
|
|
57
|
+
* or an environment without canvas. Never rejects and never throws: a tint upgrade is
|
|
58
|
+
* the least important thing on the sheet, and an SDK must not crash a host page for it.
|
|
59
|
+
*/
|
|
60
|
+
export declare function sampleLogoTint(url: string | undefined): Promise<string | null>;
|
|
61
|
+
//# sourceMappingURL=brandTint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brandTint.d.ts","sourceRoot":"","sources":["../../src/ui/brandTint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,kFAAkF;AAClF,eAAO,MAAM,eAAe,MAAM,CAAC;AA2InC;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AA4BD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAuC9E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmC9E"}
|
package/types/ui/styles.d.ts
CHANGED
|
@@ -11,6 +11,92 @@ export declare const BREAKPOINTS: {
|
|
|
11
11
|
readonly TABLET: "1023px";
|
|
12
12
|
readonly DESKTOP: "1024px";
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* REWARD_VISUAL_NOTES — why the reward block in the stylesheet below looks the way
|
|
16
|
+
* it does. Deliberately a JS comment and NOT a CSS one.
|
|
17
|
+
*
|
|
18
|
+
* The stylesheet is one big template literal, so every `/* … *\/` inside it is STRING
|
|
19
|
+
* CONTENT that terser cannot strip and every user downloads. This file's house style
|
|
20
|
+
* is long prose; in the literal that prose is payload. Keep in-literal comments to a
|
|
21
|
+
* terse line or two and put the reasoning here, where it is free. (Trimming this
|
|
22
|
+
* block's CSS prose cut 3.9KB of raw bundle — it had been 46% of the whole
|
|
23
|
+
* stylesheet delta.)
|
|
24
|
+
*
|
|
25
|
+
* SOURCE OF TRUTH. The interaction model tracks `streaksCarousel.json`; the visuals
|
|
26
|
+
* track Figma frame 18304:2399 (393×852). Where they disagree the Figma wins — see
|
|
27
|
+
* the PR for the itemised list. Web has no SDUI engine, so every value is hand-tracked.
|
|
28
|
+
*
|
|
29
|
+
* SHEET BACKGROUND, three layers, top-most first:
|
|
30
|
+
* 1. The Figma's radial glow — a 346px circle of #B728F5 @ 12%, Gaussian-blurred
|
|
31
|
+
* (stdDeviation 102), centred at (189, −38), just above the top edge. Rendered
|
|
32
|
+
* as a soft radial rather than a real blur: a filter would cost a full-surface
|
|
33
|
+
* repaint for what is a completely static wash.
|
|
34
|
+
* 2. The variant's accent wash — its four stops, 0.14 → 0.05 → 0 → 0.
|
|
35
|
+
* 3. The variant's base canvas — surface → surface → background → background.
|
|
36
|
+
* Layers 2 and 3 are the variant's two stacked full-bleed gradients. Alpha is only
|
|
37
|
+
* ever composited against layer 3, never the host page's backdrop: an accent tint
|
|
38
|
+
* over an unknown ground is what rendered near-black in night mode (backend #426).
|
|
39
|
+
*
|
|
40
|
+
* TEXT COLOUR stays on theme tokens rather than the Figma's #292D32 / #051E34. The
|
|
41
|
+
* variant's own dark-mode note is explicit that every mode-derived colour must remain
|
|
42
|
+
* a token, and a hardcoded light-mode hex in a mode-reactive layer is exactly bug
|
|
43
|
+
* #426/#427. Figma hexes are used only for the brand wash, which is not mode-derived.
|
|
44
|
+
* The subheadline ships at 0.55 rather than the Figma's 0.50 because the variant
|
|
45
|
+
* specifies 0.55 for secondary copy to clear WCAG AA at this size — on a contrast
|
|
46
|
+
* question the variant wins.
|
|
47
|
+
*
|
|
48
|
+
* THE NEIGHBOUR TREATMENT IS MEASURED, NOT GUESSED. A neighbour's card body samples
|
|
49
|
+
* #F9F9F9 against a #F2F2F2 ground, and its icon matches at the same ratio — that is
|
|
50
|
+
* white at 55%. So it is opacity 0.55 + scale 0.95 + translateY(11px) with NO
|
|
51
|
+
* grayscale/saturate filter; the "desaturated" look is just opacity over a light
|
|
52
|
+
* ground. That is also the fast choice: opacity composites on the GPU and holds 60fps
|
|
53
|
+
* through a drag, where a filter repaints every card every frame.
|
|
54
|
+
*
|
|
55
|
+
* CARD BODY is tint@10% over white — measured #FFF5E9 against Audible's #FF9F2B,
|
|
56
|
+
* exactly white + 10%. The two radial layers add the deeper wash the Figma carries at
|
|
57
|
+
* the right and bottom edges (its decorative vector), derived from the same tint so
|
|
58
|
+
* any advertiser colour works. See `brandTint.ts` for where the tint comes from.
|
|
59
|
+
*
|
|
60
|
+
* DESKTOP WIDTH. The design is a 393-wide phone frame; on the desktop modal
|
|
61
|
+
* (max-width 800) the content column holds 393 and centres, so the hero keeps its
|
|
62
|
+
* proportions instead of stranding a 210px card in an 800px sheet. The background
|
|
63
|
+
* stays full-bleed — only the content column is constrained. Content sits at
|
|
64
|
+
* z-index 1 so it clears the confetti canvas, matching the variant's zStack order
|
|
65
|
+
* (gradients → confetti → content).
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* The reward sheet's brand pair, read off the Figma (frame 18304:2399).
|
|
69
|
+
*
|
|
70
|
+
* `#B728F5 → #6515ED` is the primary CTA's gradient (node 18304:2417, 98.22°), and
|
|
71
|
+
* `#B728F5` is also the active dot and the radial glow behind the header — one accent
|
|
72
|
+
* for the whole surface, which is why it is one variable rather than three literals.
|
|
73
|
+
*
|
|
74
|
+
* NOT `--encore-primary-color`. `streaksCarousel.json` fills this CTA with a FLAT
|
|
75
|
+
* `accent` (the publisher's brand colour) at `cornerRadius: 12`; the Figma shows this
|
|
76
|
+
* gradient at a full pill. The Figma is the target, so the gradient ships — see the
|
|
77
|
+
* PR for the divergence. Exposed as custom properties on the reward root so the pair
|
|
78
|
+
* stays overridable if that decision is revisited.
|
|
79
|
+
*/
|
|
80
|
+
export declare const REWARD_BRAND = "#B728F5";
|
|
81
|
+
export declare const REWARD_BRAND_DEEP = "#6515ED";
|
|
82
|
+
/** Inactive dot ink, Figma 18304:3072 — `#6A6D81` at 30%. */
|
|
83
|
+
export declare const REWARD_DOT_COLOR = "#6A6D81";
|
|
84
|
+
/**
|
|
85
|
+
* Reward hero carousel geometry (Figma: hero 210×260 centred in a 393 frame, ~10px
|
|
86
|
+
* between card edges, neighbours peeking at both edges).
|
|
87
|
+
*
|
|
88
|
+
* Shared as constants because three separate rules have to agree on them: the card
|
|
89
|
+
* itself, the scroll container's centring padding (`50% - CARD_WIDTH/2`), and the
|
|
90
|
+
* arrows' vertical offset (`CARDS_PAD_Y + CARD_HEIGHT/2`). Drifting any one of them
|
|
91
|
+
* apart silently de-centres the hero.
|
|
92
|
+
*/
|
|
93
|
+
export declare const REWARD_CARD_GEOMETRY: {
|
|
94
|
+
readonly width: 210;
|
|
95
|
+
readonly height: 260;
|
|
96
|
+
readonly gap: 10;
|
|
97
|
+
/** Vertical breathing room in the scroll container, so the card shadow is not clipped. */
|
|
98
|
+
readonly padY: 26;
|
|
99
|
+
};
|
|
14
100
|
/**
|
|
15
101
|
* CSS custom properties for theming
|
|
16
102
|
*/
|
package/types/ui/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,eAAO,MAAM,OAAO;;;CAGV,CAAC;AAGX,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,YAAY,CAAC;AACtC,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAC3C,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB;;;;IAI/B,0FAA0F;;CAElF,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA8qDD;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAE,cAAmB,GAAG,IAAI,CAgB7D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAMnC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAUvD;AAED;;GAEG;AACH,wBAAgB,EAAE,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small text helpers shared across the core and UI layers.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* First value that is a non-blank string once trimmed, else `undefined` —
|
|
6
|
+
* the copy-priority primitive for tiered overrides (per-call > backend > default).
|
|
7
|
+
*
|
|
8
|
+
* Exists because neither operator expresses this. `??` treats `' '` as a real
|
|
9
|
+
* value, so a whitespace-only override would win its slot and render an empty
|
|
10
|
+
* headline (taking `aria-labelledby` with it) or an empty subtitle. `||` behaves
|
|
11
|
+
* correctly but trips `prefer-nullish-coalescing`, whose autofix converts it to
|
|
12
|
+
* `??` and reintroduces precisely that bug — so the rule's suggested fix is
|
|
13
|
+
* actively wrong on this shape. A named helper states the rule once and keeps
|
|
14
|
+
* every call site honest.
|
|
15
|
+
*
|
|
16
|
+
* Returning `undefined` rather than `''` is what lets callers OMIT a slot instead
|
|
17
|
+
* of filling it with an empty value — for the header that is the difference
|
|
18
|
+
* between rendering no subtitle node and rendering a blank one that still takes
|
|
19
|
+
* layout space and is announced as an empty element. The reward CARD uses the same
|
|
20
|
+
* property to drop its offer line rather than render an empty node that would still
|
|
21
|
+
* consume its 4px gap.
|
|
22
|
+
*/
|
|
23
|
+
export declare function firstNonBlank(...values: (string | null | undefined)[]): string | undefined;
|
|
24
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,GAAG,SAAS,CAM1F"}
|
package/examples/react/.env
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VITE_ENCORE_API_KEY=pk_test_localdemoappkeytest00000
|