@economist/web-apple-pay 1.10.0 → 1.10.2-beta.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 +55 -1
- package/dist/index.js +48 -30
- package/dist/src/apple-pay-button.d.ts +3 -2
- package/dist/src/apple-pay-button.js +47 -30
- package/dist/src/apple-pay-button.stories.js +47 -30
- package/dist/src/apple-pay-modal.stories.js +47 -30
- package/dist/src/constants.d.ts +3 -1
- package/dist/src/constants.js +1 -0
- package/dist/src/index.js +48 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,56 @@ container.appendChild(button);
|
|
|
54
54
|
|
|
55
55
|
When clicked, the button creates and opens `teg-apple-pay-modal` automatically.
|
|
56
56
|
|
|
57
|
+
### 3) Gated creation — `createIfEnabled`
|
|
58
|
+
|
|
59
|
+
Hosts that mount Apple Pay on a wall, banner, or popup should use
|
|
60
|
+
`ApplePayButton.createIfEnabled(offer, country, entryPoint)` instead of
|
|
61
|
+
`document.createElement`. It applies Amplitude experiment and placement rules
|
|
62
|
+
per entry point, then returns a configured button or `null`.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import {
|
|
66
|
+
ApplePayButton,
|
|
67
|
+
ApplePayEntryPoint,
|
|
68
|
+
} from '@economist/web-apple-pay';
|
|
69
|
+
|
|
70
|
+
const button = ApplePayButton.createIfEnabled(
|
|
71
|
+
offer,
|
|
72
|
+
'US',
|
|
73
|
+
ApplePayEntryPoint.FREE_TRIAL_POPUP,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (button) {
|
|
77
|
+
container.appendChild(button);
|
|
78
|
+
await button.whenReady();
|
|
79
|
+
if (button.style.display === 'none') {
|
|
80
|
+
button.remove();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### Entry points
|
|
86
|
+
|
|
87
|
+
| `ApplePayEntryPoint` | Value | Amplitude flag | Placement eligibility |
|
|
88
|
+
| --- | --- | --- | --- |
|
|
89
|
+
| `PAYWALL` | `article_paywall` | `apple-pay-express-checkout-on-paywalls` | Safari / Apple device |
|
|
90
|
+
| `REGWALL` | `article_regwall` | `apple-pay-express-checkout-on-banners` | none |
|
|
91
|
+
| `DUAL_OFFER_BANNER` (default if omitted) | `dual_offer_banner` | `apple-pay-express-checkout-on-banners` | homepage + Safari / iPhone |
|
|
92
|
+
| `FREE_TRIAL_POPUP` | `free_trial_popup` | **none** — always shown | none |
|
|
93
|
+
|
|
94
|
+
`FREE_TRIAL_POPUP` does not read `window.experimentIntegration` and does not
|
|
95
|
+
emit `$exposure`. The button is created whenever the offer is valid (excluded
|
|
96
|
+
variants still suppress it). The component still hides itself after mount if
|
|
97
|
+
Apple Pay is unavailable on the device.
|
|
98
|
+
|
|
99
|
+
For every other entry point:
|
|
100
|
+
|
|
101
|
+
- Host must set `window.experimentIntegration.getVariant` before calling
|
|
102
|
+
`createIfEnabled`.
|
|
103
|
+
- `treatment` → button created; `control` / missing / anything else → `null`.
|
|
104
|
+
- QA override: `?FEATURE_APPLE_PAY_EXPRESS_CHECKOUT` shows the button without
|
|
105
|
+
emitting `$exposure`.
|
|
106
|
+
|
|
57
107
|
## Runtime configuration
|
|
58
108
|
|
|
59
109
|
### `configureApplePay(config)`
|
|
@@ -120,7 +170,9 @@ Consumers should listen for this event and continue payment orchestration.
|
|
|
120
170
|
- `defineApplePayElements()`: registers both custom elements.
|
|
121
171
|
- `configureApplePay(config)`: sets required runtime config (merchant ID and wallet API base URL, with optional debug bypass).
|
|
122
172
|
- `ApplePayButton`: button component class.
|
|
173
|
+
- `createIfEnabled(offer, country, entryPoint?)`: returns a configured button or `null` after applying Amplitude / placement rules for the entry point. `FREE_TRIAL_POPUP` is not experiment-gated.
|
|
123
174
|
- `whenReady(): Promise<void>` — resolves when the current render lifecycle completes (available or hidden). Resolves immediately if called before the element is connected.
|
|
175
|
+
- `ApplePayEntryPoint`: where the button is mounted (`PAYWALL`, `REGWALL`, `DUAL_OFFER_BANNER`, `FREE_TRIAL_POPUP`).
|
|
124
176
|
- `ApplePayModal`: modal component class.
|
|
125
177
|
- `ensureApplePayLogoSymbol()`: logo symbol injection helper.
|
|
126
178
|
- `Offer`: offer contract type used by component props.
|
|
@@ -133,7 +185,8 @@ Check:
|
|
|
133
185
|
|
|
134
186
|
- `configureApplePay(...)` was called before rendering (with a valid `merchantId` and `walletApiBaseUrl`)
|
|
135
187
|
- device/browser supports Apple Pay (Safari on Apple device required)
|
|
136
|
-
-
|
|
188
|
+
- for paywall / regwall / dual-offer banner: Amplitude variant is `treatment`, or the `FEATURE_APPLE_PAY_EXPRESS_CHECKOUT` QA param is present
|
|
189
|
+
- `FREE_TRIAL_POPUP` is not Amplitude-gated — if the button is missing, check offer variant and device support instead
|
|
137
190
|
- offer variant is not excluded (`bundle`, `insider_print`)
|
|
138
191
|
|
|
139
192
|
### Logged-in checkbox copy looks wrong
|
|
@@ -184,3 +237,4 @@ Story coverage matrix:
|
|
|
184
237
|
- `ApplePayButton` behavior and state variants are available as individual canvas stories in Storybook.
|
|
185
238
|
- `ApplePayModal` docs page shows the stable default example.
|
|
186
239
|
- `ApplePayModal` behavior and state variants are available as individual canvas stories in Storybook.
|
|
240
|
+
|
package/dist/index.js
CHANGED
|
@@ -1308,6 +1308,7 @@ var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint2) => {
|
|
|
1308
1308
|
ApplePayEntryPoint2["PAYWALL"] = "article_paywall";
|
|
1309
1309
|
ApplePayEntryPoint2["REGWALL"] = "article_regwall";
|
|
1310
1310
|
ApplePayEntryPoint2["DUAL_OFFER_BANNER"] = "dual_offer_banner";
|
|
1311
|
+
ApplePayEntryPoint2["FREE_TRIAL_POPUP"] = "free_trial_popup";
|
|
1311
1312
|
return ApplePayEntryPoint2;
|
|
1312
1313
|
})(ApplePayEntryPoint || {});
|
|
1313
1314
|
var APPLE_PAY_EXPRESS_EXPERIMENT_KEY = "apple-pay-express-checkout-on-banners";
|
|
@@ -2022,6 +2023,9 @@ var ENTRY_POINT_CONFIG = {
|
|
|
2022
2023
|
["article_regwall" /* REGWALL */]: {
|
|
2023
2024
|
isEligible: () => true,
|
|
2024
2025
|
experimentFlagKey: APPLE_PAY_EXPRESS_EXPERIMENT_KEY
|
|
2026
|
+
},
|
|
2027
|
+
["free_trial_popup" /* FREE_TRIAL_POPUP */]: {
|
|
2028
|
+
isEligible: () => true
|
|
2025
2029
|
}
|
|
2026
2030
|
};
|
|
2027
2031
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
@@ -2045,9 +2049,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2045
2049
|
* Reads the experiment variant from `window.experimentIntegration.getVariant`:
|
|
2046
2050
|
* - {@link APPLE_PAY_EXPRESS_PAYWALLS_EXPERIMENT_KEY} for `PAYWALL`
|
|
2047
2051
|
* - {@link APPLE_PAY_EXPRESS_EXPERIMENT_KEY} for `REGWALL` / `DUAL_OFFER_BANNER`
|
|
2052
|
+
* - no Amplitude gate for `FREE_TRIAL_POPUP` (always shown)
|
|
2048
2053
|
*
|
|
2049
2054
|
* The host page is responsible for setting up `window.experimentIntegration`
|
|
2050
|
-
* before calling this method.
|
|
2055
|
+
* before calling this method (except `FREE_TRIAL_POPUP`).
|
|
2051
2056
|
*
|
|
2052
2057
|
* - `treatment` → button created and returned
|
|
2053
2058
|
* - `control` / missing / anything else → returns null (button suppressed)
|
|
@@ -2060,7 +2065,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2060
2065
|
* **Eligibility:**
|
|
2061
2066
|
* - `DUAL_OFFER_BANNER` (or omitted): homepage + Safari/iPhone (SMA-3301)
|
|
2062
2067
|
* - `PAYWALL`: Safari/Apple device only (no homepage) — article paywalls
|
|
2063
|
-
* - `REGWALL`: no host-side placement gate
|
|
2068
|
+
* - `REGWALL` / `FREE_TRIAL_POPUP`: no host-side placement gate
|
|
2064
2069
|
*
|
|
2065
2070
|
* @param offer - The offer to display in the Apple Pay flow.
|
|
2066
2071
|
* @param country - The user's country code.
|
|
@@ -2086,24 +2091,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2086
2091
|
if (!hasUrlParamFlag && !bypassApplePayChecks() && !isEligible) {
|
|
2087
2092
|
return null;
|
|
2088
2093
|
}
|
|
2089
|
-
|
|
2090
|
-
experimentFlagKey
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2094
|
+
if (experimentFlagKey) {
|
|
2095
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(experimentFlagKey);
|
|
2096
|
+
const isExperimentVariant = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.CONTROL || experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2097
|
+
if (isExperimentVariant && isEligible && !bypassApplePayChecks() && !hasUrlParamFlag) {
|
|
2098
|
+
void isApplePayAvailable().then((available) => {
|
|
2099
|
+
if (available) {
|
|
2100
|
+
trackApplePayExperimentExposure(
|
|
2101
|
+
experimentValue,
|
|
2102
|
+
getExperimentKeyFromNextData(experimentFlagKey),
|
|
2103
|
+
experimentFlagKey
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2109
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
2110
|
+
return null;
|
|
2111
|
+
}
|
|
2107
2112
|
}
|
|
2108
2113
|
_ApplePayButton.define();
|
|
2109
2114
|
const button = document.createElement(_ApplePayButton.tag);
|
|
@@ -2211,18 +2216,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2211
2216
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2212
2217
|
this.#finishLoading();
|
|
2213
2218
|
} catch {
|
|
2214
|
-
this
|
|
2215
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2219
|
+
this.#hide();
|
|
2216
2220
|
} finally {
|
|
2217
2221
|
this.#rendering = false;
|
|
2218
2222
|
}
|
|
2219
2223
|
}
|
|
2224
|
+
/**
|
|
2225
|
+
* Stop the loading spinner before tear-down so Safari does not leave a GPU
|
|
2226
|
+
* ghost of `.apple-pay-btn.wap-loading::before` after the container is removed.
|
|
2227
|
+
*/
|
|
2228
|
+
#hide() {
|
|
2229
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2230
|
+
if (button) {
|
|
2231
|
+
button.classList.remove("wap-loading");
|
|
2232
|
+
button.removeAttribute("aria-busy");
|
|
2233
|
+
button.getAnimations?.({ subtree: true }).forEach((animation) => animation.cancel());
|
|
2234
|
+
}
|
|
2235
|
+
this.getAnimations?.({ subtree: true }).forEach(
|
|
2236
|
+
(animation) => animation.cancel()
|
|
2237
|
+
);
|
|
2238
|
+
void this.offsetHeight;
|
|
2239
|
+
this.style.display = "none";
|
|
2240
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2241
|
+
}
|
|
2220
2242
|
/** Returns `true` (hide) when Apple Pay is unavailable on this device/browser. */
|
|
2221
2243
|
async #checkAvailability() {
|
|
2222
2244
|
const available = await isApplePayAvailable();
|
|
2223
2245
|
if (!available) {
|
|
2224
|
-
this
|
|
2225
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2246
|
+
this.#hide();
|
|
2226
2247
|
return true;
|
|
2227
2248
|
}
|
|
2228
2249
|
return false;
|
|
@@ -2234,8 +2255,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2234
2255
|
async #checkSession() {
|
|
2235
2256
|
this.#sessionData = await this.#fetchSession();
|
|
2236
2257
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2237
|
-
this
|
|
2238
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2258
|
+
this.#hide();
|
|
2239
2259
|
return true;
|
|
2240
2260
|
}
|
|
2241
2261
|
return false;
|
|
@@ -2243,8 +2263,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2243
2263
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2244
2264
|
#checkOffer() {
|
|
2245
2265
|
if (!this.#offer) {
|
|
2246
|
-
this
|
|
2247
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2266
|
+
this.#hide();
|
|
2248
2267
|
return true;
|
|
2249
2268
|
}
|
|
2250
2269
|
return false;
|
|
@@ -2271,8 +2290,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2271
2290
|
async #fetchAndCacheOptions() {
|
|
2272
2291
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2273
2292
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2274
|
-
this
|
|
2275
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2293
|
+
this.#hide();
|
|
2276
2294
|
return true;
|
|
2277
2295
|
}
|
|
2278
2296
|
return false;
|
|
@@ -11,9 +11,10 @@ export declare class ApplePayButton extends HTMLElement {
|
|
|
11
11
|
* Reads the experiment variant from `window.experimentIntegration.getVariant`:
|
|
12
12
|
* - {@link APPLE_PAY_EXPRESS_PAYWALLS_EXPERIMENT_KEY} for `PAYWALL`
|
|
13
13
|
* - {@link APPLE_PAY_EXPRESS_EXPERIMENT_KEY} for `REGWALL` / `DUAL_OFFER_BANNER`
|
|
14
|
+
* - no Amplitude gate for `FREE_TRIAL_POPUP` (always shown)
|
|
14
15
|
*
|
|
15
16
|
* The host page is responsible for setting up `window.experimentIntegration`
|
|
16
|
-
* before calling this method.
|
|
17
|
+
* before calling this method (except `FREE_TRIAL_POPUP`).
|
|
17
18
|
*
|
|
18
19
|
* - `treatment` → button created and returned
|
|
19
20
|
* - `control` / missing / anything else → returns null (button suppressed)
|
|
@@ -26,7 +27,7 @@ export declare class ApplePayButton extends HTMLElement {
|
|
|
26
27
|
* **Eligibility:**
|
|
27
28
|
* - `DUAL_OFFER_BANNER` (or omitted): homepage + Safari/iPhone (SMA-3301)
|
|
28
29
|
* - `PAYWALL`: Safari/Apple device only (no homepage) — article paywalls
|
|
29
|
-
* - `REGWALL`: no host-side placement gate
|
|
30
|
+
* - `REGWALL` / `FREE_TRIAL_POPUP`: no host-side placement gate
|
|
30
31
|
*
|
|
31
32
|
* @param offer - The offer to display in the Apple Pay flow.
|
|
32
33
|
* @param country - The user's country code.
|
|
@@ -2011,6 +2011,9 @@ var ENTRY_POINT_CONFIG = {
|
|
|
2011
2011
|
["article_regwall" /* REGWALL */]: {
|
|
2012
2012
|
isEligible: () => true,
|
|
2013
2013
|
experimentFlagKey: APPLE_PAY_EXPRESS_EXPERIMENT_KEY
|
|
2014
|
+
},
|
|
2015
|
+
["free_trial_popup" /* FREE_TRIAL_POPUP */]: {
|
|
2016
|
+
isEligible: () => true
|
|
2014
2017
|
}
|
|
2015
2018
|
};
|
|
2016
2019
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
@@ -2034,9 +2037,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2034
2037
|
* Reads the experiment variant from `window.experimentIntegration.getVariant`:
|
|
2035
2038
|
* - {@link APPLE_PAY_EXPRESS_PAYWALLS_EXPERIMENT_KEY} for `PAYWALL`
|
|
2036
2039
|
* - {@link APPLE_PAY_EXPRESS_EXPERIMENT_KEY} for `REGWALL` / `DUAL_OFFER_BANNER`
|
|
2040
|
+
* - no Amplitude gate for `FREE_TRIAL_POPUP` (always shown)
|
|
2037
2041
|
*
|
|
2038
2042
|
* The host page is responsible for setting up `window.experimentIntegration`
|
|
2039
|
-
* before calling this method.
|
|
2043
|
+
* before calling this method (except `FREE_TRIAL_POPUP`).
|
|
2040
2044
|
*
|
|
2041
2045
|
* - `treatment` → button created and returned
|
|
2042
2046
|
* - `control` / missing / anything else → returns null (button suppressed)
|
|
@@ -2049,7 +2053,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2049
2053
|
* **Eligibility:**
|
|
2050
2054
|
* - `DUAL_OFFER_BANNER` (or omitted): homepage + Safari/iPhone (SMA-3301)
|
|
2051
2055
|
* - `PAYWALL`: Safari/Apple device only (no homepage) — article paywalls
|
|
2052
|
-
* - `REGWALL`: no host-side placement gate
|
|
2056
|
+
* - `REGWALL` / `FREE_TRIAL_POPUP`: no host-side placement gate
|
|
2053
2057
|
*
|
|
2054
2058
|
* @param offer - The offer to display in the Apple Pay flow.
|
|
2055
2059
|
* @param country - The user's country code.
|
|
@@ -2075,24 +2079,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2075
2079
|
if (!hasUrlParamFlag && !bypassApplePayChecks() && !isEligible) {
|
|
2076
2080
|
return null;
|
|
2077
2081
|
}
|
|
2078
|
-
|
|
2079
|
-
experimentFlagKey
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2082
|
+
if (experimentFlagKey) {
|
|
2083
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(experimentFlagKey);
|
|
2084
|
+
const isExperimentVariant = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.CONTROL || experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2085
|
+
if (isExperimentVariant && isEligible && !bypassApplePayChecks() && !hasUrlParamFlag) {
|
|
2086
|
+
void isApplePayAvailable().then((available) => {
|
|
2087
|
+
if (available) {
|
|
2088
|
+
trackApplePayExperimentExposure(
|
|
2089
|
+
experimentValue,
|
|
2090
|
+
getExperimentKeyFromNextData(experimentFlagKey),
|
|
2091
|
+
experimentFlagKey
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
});
|
|
2095
|
+
}
|
|
2096
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2097
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2096
2100
|
}
|
|
2097
2101
|
_ApplePayButton.define();
|
|
2098
2102
|
const button = document.createElement(_ApplePayButton.tag);
|
|
@@ -2200,18 +2204,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2200
2204
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2201
2205
|
this.#finishLoading();
|
|
2202
2206
|
} catch {
|
|
2203
|
-
this
|
|
2204
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2207
|
+
this.#hide();
|
|
2205
2208
|
} finally {
|
|
2206
2209
|
this.#rendering = false;
|
|
2207
2210
|
}
|
|
2208
2211
|
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Stop the loading spinner before tear-down so Safari does not leave a GPU
|
|
2214
|
+
* ghost of `.apple-pay-btn.wap-loading::before` after the container is removed.
|
|
2215
|
+
*/
|
|
2216
|
+
#hide() {
|
|
2217
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2218
|
+
if (button) {
|
|
2219
|
+
button.classList.remove("wap-loading");
|
|
2220
|
+
button.removeAttribute("aria-busy");
|
|
2221
|
+
button.getAnimations?.({ subtree: true }).forEach((animation) => animation.cancel());
|
|
2222
|
+
}
|
|
2223
|
+
this.getAnimations?.({ subtree: true }).forEach(
|
|
2224
|
+
(animation) => animation.cancel()
|
|
2225
|
+
);
|
|
2226
|
+
void this.offsetHeight;
|
|
2227
|
+
this.style.display = "none";
|
|
2228
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2229
|
+
}
|
|
2209
2230
|
/** Returns `true` (hide) when Apple Pay is unavailable on this device/browser. */
|
|
2210
2231
|
async #checkAvailability() {
|
|
2211
2232
|
const available = await isApplePayAvailable();
|
|
2212
2233
|
if (!available) {
|
|
2213
|
-
this
|
|
2214
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2234
|
+
this.#hide();
|
|
2215
2235
|
return true;
|
|
2216
2236
|
}
|
|
2217
2237
|
return false;
|
|
@@ -2223,8 +2243,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2223
2243
|
async #checkSession() {
|
|
2224
2244
|
this.#sessionData = await this.#fetchSession();
|
|
2225
2245
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2226
|
-
this
|
|
2227
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2246
|
+
this.#hide();
|
|
2228
2247
|
return true;
|
|
2229
2248
|
}
|
|
2230
2249
|
return false;
|
|
@@ -2232,8 +2251,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2232
2251
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2233
2252
|
#checkOffer() {
|
|
2234
2253
|
if (!this.#offer) {
|
|
2235
|
-
this
|
|
2236
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2254
|
+
this.#hide();
|
|
2237
2255
|
return true;
|
|
2238
2256
|
}
|
|
2239
2257
|
return false;
|
|
@@ -2260,8 +2278,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2260
2278
|
async #fetchAndCacheOptions() {
|
|
2261
2279
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2262
2280
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2263
|
-
this
|
|
2264
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2281
|
+
this.#hide();
|
|
2265
2282
|
return true;
|
|
2266
2283
|
}
|
|
2267
2284
|
return false;
|
|
@@ -2019,6 +2019,9 @@ var ENTRY_POINT_CONFIG = {
|
|
|
2019
2019
|
["article_regwall" /* REGWALL */]: {
|
|
2020
2020
|
isEligible: () => true,
|
|
2021
2021
|
experimentFlagKey: APPLE_PAY_EXPRESS_EXPERIMENT_KEY
|
|
2022
|
+
},
|
|
2023
|
+
["free_trial_popup" /* FREE_TRIAL_POPUP */]: {
|
|
2024
|
+
isEligible: () => true
|
|
2022
2025
|
}
|
|
2023
2026
|
};
|
|
2024
2027
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
@@ -2042,9 +2045,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2042
2045
|
* Reads the experiment variant from `window.experimentIntegration.getVariant`:
|
|
2043
2046
|
* - {@link APPLE_PAY_EXPRESS_PAYWALLS_EXPERIMENT_KEY} for `PAYWALL`
|
|
2044
2047
|
* - {@link APPLE_PAY_EXPRESS_EXPERIMENT_KEY} for `REGWALL` / `DUAL_OFFER_BANNER`
|
|
2048
|
+
* - no Amplitude gate for `FREE_TRIAL_POPUP` (always shown)
|
|
2045
2049
|
*
|
|
2046
2050
|
* The host page is responsible for setting up `window.experimentIntegration`
|
|
2047
|
-
* before calling this method.
|
|
2051
|
+
* before calling this method (except `FREE_TRIAL_POPUP`).
|
|
2048
2052
|
*
|
|
2049
2053
|
* - `treatment` → button created and returned
|
|
2050
2054
|
* - `control` / missing / anything else → returns null (button suppressed)
|
|
@@ -2057,7 +2061,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2057
2061
|
* **Eligibility:**
|
|
2058
2062
|
* - `DUAL_OFFER_BANNER` (or omitted): homepage + Safari/iPhone (SMA-3301)
|
|
2059
2063
|
* - `PAYWALL`: Safari/Apple device only (no homepage) — article paywalls
|
|
2060
|
-
* - `REGWALL`: no host-side placement gate
|
|
2064
|
+
* - `REGWALL` / `FREE_TRIAL_POPUP`: no host-side placement gate
|
|
2061
2065
|
*
|
|
2062
2066
|
* @param offer - The offer to display in the Apple Pay flow.
|
|
2063
2067
|
* @param country - The user's country code.
|
|
@@ -2083,24 +2087,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2083
2087
|
if (!hasUrlParamFlag && !bypassApplePayChecks() && !isEligible) {
|
|
2084
2088
|
return null;
|
|
2085
2089
|
}
|
|
2086
|
-
|
|
2087
|
-
experimentFlagKey
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2090
|
+
if (experimentFlagKey) {
|
|
2091
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(experimentFlagKey);
|
|
2092
|
+
const isExperimentVariant = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.CONTROL || experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2093
|
+
if (isExperimentVariant && isEligible && !bypassApplePayChecks() && !hasUrlParamFlag) {
|
|
2094
|
+
void isApplePayAvailable().then((available) => {
|
|
2095
|
+
if (available) {
|
|
2096
|
+
trackApplePayExperimentExposure(
|
|
2097
|
+
experimentValue,
|
|
2098
|
+
getExperimentKeyFromNextData(experimentFlagKey),
|
|
2099
|
+
experimentFlagKey
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2104
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2105
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
2106
|
+
return null;
|
|
2107
|
+
}
|
|
2104
2108
|
}
|
|
2105
2109
|
_ApplePayButton.define();
|
|
2106
2110
|
const button = document.createElement(_ApplePayButton.tag);
|
|
@@ -2208,18 +2212,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2208
2212
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2209
2213
|
this.#finishLoading();
|
|
2210
2214
|
} catch {
|
|
2211
|
-
this
|
|
2212
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2215
|
+
this.#hide();
|
|
2213
2216
|
} finally {
|
|
2214
2217
|
this.#rendering = false;
|
|
2215
2218
|
}
|
|
2216
2219
|
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Stop the loading spinner before tear-down so Safari does not leave a GPU
|
|
2222
|
+
* ghost of `.apple-pay-btn.wap-loading::before` after the container is removed.
|
|
2223
|
+
*/
|
|
2224
|
+
#hide() {
|
|
2225
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2226
|
+
if (button) {
|
|
2227
|
+
button.classList.remove("wap-loading");
|
|
2228
|
+
button.removeAttribute("aria-busy");
|
|
2229
|
+
button.getAnimations?.({ subtree: true }).forEach((animation) => animation.cancel());
|
|
2230
|
+
}
|
|
2231
|
+
this.getAnimations?.({ subtree: true }).forEach(
|
|
2232
|
+
(animation) => animation.cancel()
|
|
2233
|
+
);
|
|
2234
|
+
void this.offsetHeight;
|
|
2235
|
+
this.style.display = "none";
|
|
2236
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2237
|
+
}
|
|
2217
2238
|
/** Returns `true` (hide) when Apple Pay is unavailable on this device/browser. */
|
|
2218
2239
|
async #checkAvailability() {
|
|
2219
2240
|
const available = await isApplePayAvailable();
|
|
2220
2241
|
if (!available) {
|
|
2221
|
-
this
|
|
2222
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2242
|
+
this.#hide();
|
|
2223
2243
|
return true;
|
|
2224
2244
|
}
|
|
2225
2245
|
return false;
|
|
@@ -2231,8 +2251,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2231
2251
|
async #checkSession() {
|
|
2232
2252
|
this.#sessionData = await this.#fetchSession();
|
|
2233
2253
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2234
|
-
this
|
|
2235
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2254
|
+
this.#hide();
|
|
2236
2255
|
return true;
|
|
2237
2256
|
}
|
|
2238
2257
|
return false;
|
|
@@ -2240,8 +2259,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2240
2259
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2241
2260
|
#checkOffer() {
|
|
2242
2261
|
if (!this.#offer) {
|
|
2243
|
-
this
|
|
2244
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2262
|
+
this.#hide();
|
|
2245
2263
|
return true;
|
|
2246
2264
|
}
|
|
2247
2265
|
return false;
|
|
@@ -2268,8 +2286,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2268
2286
|
async #fetchAndCacheOptions() {
|
|
2269
2287
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2270
2288
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2271
|
-
this
|
|
2272
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2289
|
+
this.#hide();
|
|
2273
2290
|
return true;
|
|
2274
2291
|
}
|
|
2275
2292
|
return false;
|
|
@@ -2011,6 +2011,9 @@ var ENTRY_POINT_CONFIG = {
|
|
|
2011
2011
|
["article_regwall" /* REGWALL */]: {
|
|
2012
2012
|
isEligible: () => true,
|
|
2013
2013
|
experimentFlagKey: APPLE_PAY_EXPRESS_EXPERIMENT_KEY
|
|
2014
|
+
},
|
|
2015
|
+
["free_trial_popup" /* FREE_TRIAL_POPUP */]: {
|
|
2016
|
+
isEligible: () => true
|
|
2014
2017
|
}
|
|
2015
2018
|
};
|
|
2016
2019
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
@@ -2034,9 +2037,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2034
2037
|
* Reads the experiment variant from `window.experimentIntegration.getVariant`:
|
|
2035
2038
|
* - {@link APPLE_PAY_EXPRESS_PAYWALLS_EXPERIMENT_KEY} for `PAYWALL`
|
|
2036
2039
|
* - {@link APPLE_PAY_EXPRESS_EXPERIMENT_KEY} for `REGWALL` / `DUAL_OFFER_BANNER`
|
|
2040
|
+
* - no Amplitude gate for `FREE_TRIAL_POPUP` (always shown)
|
|
2037
2041
|
*
|
|
2038
2042
|
* The host page is responsible for setting up `window.experimentIntegration`
|
|
2039
|
-
* before calling this method.
|
|
2043
|
+
* before calling this method (except `FREE_TRIAL_POPUP`).
|
|
2040
2044
|
*
|
|
2041
2045
|
* - `treatment` → button created and returned
|
|
2042
2046
|
* - `control` / missing / anything else → returns null (button suppressed)
|
|
@@ -2049,7 +2053,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2049
2053
|
* **Eligibility:**
|
|
2050
2054
|
* - `DUAL_OFFER_BANNER` (or omitted): homepage + Safari/iPhone (SMA-3301)
|
|
2051
2055
|
* - `PAYWALL`: Safari/Apple device only (no homepage) — article paywalls
|
|
2052
|
-
* - `REGWALL`: no host-side placement gate
|
|
2056
|
+
* - `REGWALL` / `FREE_TRIAL_POPUP`: no host-side placement gate
|
|
2053
2057
|
*
|
|
2054
2058
|
* @param offer - The offer to display in the Apple Pay flow.
|
|
2055
2059
|
* @param country - The user's country code.
|
|
@@ -2075,24 +2079,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2075
2079
|
if (!hasUrlParamFlag && !bypassApplePayChecks() && !isEligible) {
|
|
2076
2080
|
return null;
|
|
2077
2081
|
}
|
|
2078
|
-
|
|
2079
|
-
experimentFlagKey
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2082
|
+
if (experimentFlagKey) {
|
|
2083
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(experimentFlagKey);
|
|
2084
|
+
const isExperimentVariant = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.CONTROL || experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2085
|
+
if (isExperimentVariant && isEligible && !bypassApplePayChecks() && !hasUrlParamFlag) {
|
|
2086
|
+
void isApplePayAvailable().then((available) => {
|
|
2087
|
+
if (available) {
|
|
2088
|
+
trackApplePayExperimentExposure(
|
|
2089
|
+
experimentValue,
|
|
2090
|
+
getExperimentKeyFromNextData(experimentFlagKey),
|
|
2091
|
+
experimentFlagKey
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
});
|
|
2095
|
+
}
|
|
2096
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2097
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2096
2100
|
}
|
|
2097
2101
|
_ApplePayButton.define();
|
|
2098
2102
|
const button = document.createElement(_ApplePayButton.tag);
|
|
@@ -2200,18 +2204,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2200
2204
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2201
2205
|
this.#finishLoading();
|
|
2202
2206
|
} catch {
|
|
2203
|
-
this
|
|
2204
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2207
|
+
this.#hide();
|
|
2205
2208
|
} finally {
|
|
2206
2209
|
this.#rendering = false;
|
|
2207
2210
|
}
|
|
2208
2211
|
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Stop the loading spinner before tear-down so Safari does not leave a GPU
|
|
2214
|
+
* ghost of `.apple-pay-btn.wap-loading::before` after the container is removed.
|
|
2215
|
+
*/
|
|
2216
|
+
#hide() {
|
|
2217
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2218
|
+
if (button) {
|
|
2219
|
+
button.classList.remove("wap-loading");
|
|
2220
|
+
button.removeAttribute("aria-busy");
|
|
2221
|
+
button.getAnimations?.({ subtree: true }).forEach((animation) => animation.cancel());
|
|
2222
|
+
}
|
|
2223
|
+
this.getAnimations?.({ subtree: true }).forEach(
|
|
2224
|
+
(animation) => animation.cancel()
|
|
2225
|
+
);
|
|
2226
|
+
void this.offsetHeight;
|
|
2227
|
+
this.style.display = "none";
|
|
2228
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2229
|
+
}
|
|
2209
2230
|
/** Returns `true` (hide) when Apple Pay is unavailable on this device/browser. */
|
|
2210
2231
|
async #checkAvailability() {
|
|
2211
2232
|
const available = await isApplePayAvailable();
|
|
2212
2233
|
if (!available) {
|
|
2213
|
-
this
|
|
2214
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2234
|
+
this.#hide();
|
|
2215
2235
|
return true;
|
|
2216
2236
|
}
|
|
2217
2237
|
return false;
|
|
@@ -2223,8 +2243,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2223
2243
|
async #checkSession() {
|
|
2224
2244
|
this.#sessionData = await this.#fetchSession();
|
|
2225
2245
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2226
|
-
this
|
|
2227
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2246
|
+
this.#hide();
|
|
2228
2247
|
return true;
|
|
2229
2248
|
}
|
|
2230
2249
|
return false;
|
|
@@ -2232,8 +2251,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2232
2251
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2233
2252
|
#checkOffer() {
|
|
2234
2253
|
if (!this.#offer) {
|
|
2235
|
-
this
|
|
2236
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2254
|
+
this.#hide();
|
|
2237
2255
|
return true;
|
|
2238
2256
|
}
|
|
2239
2257
|
return false;
|
|
@@ -2260,8 +2278,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2260
2278
|
async #fetchAndCacheOptions() {
|
|
2261
2279
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2262
2280
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2263
|
-
this
|
|
2264
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2281
|
+
this.#hide();
|
|
2265
2282
|
return true;
|
|
2266
2283
|
}
|
|
2267
2284
|
return false;
|
package/dist/src/constants.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export declare enum ApplePayEntryPoint {
|
|
2
2
|
PAYWALL = "article_paywall",
|
|
3
3
|
REGWALL = "article_regwall",
|
|
4
|
-
DUAL_OFFER_BANNER = "dual_offer_banner"
|
|
4
|
+
DUAL_OFFER_BANNER = "dual_offer_banner",
|
|
5
|
+
/** Post-registration free-trial popup. Not Amplitude-gated. */
|
|
6
|
+
FREE_TRIAL_POPUP = "free_trial_popup"
|
|
5
7
|
}
|
|
6
8
|
/**
|
|
7
9
|
* Amplitude experiment key for Apple Pay Express Checkout on homepage banners
|
package/dist/src/constants.js
CHANGED
|
@@ -3,6 +3,7 @@ var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint2) => {
|
|
|
3
3
|
ApplePayEntryPoint2["PAYWALL"] = "article_paywall";
|
|
4
4
|
ApplePayEntryPoint2["REGWALL"] = "article_regwall";
|
|
5
5
|
ApplePayEntryPoint2["DUAL_OFFER_BANNER"] = "dual_offer_banner";
|
|
6
|
+
ApplePayEntryPoint2["FREE_TRIAL_POPUP"] = "free_trial_popup";
|
|
6
7
|
return ApplePayEntryPoint2;
|
|
7
8
|
})(ApplePayEntryPoint || {});
|
|
8
9
|
var APPLE_PAY_EXPRESS_EXPERIMENT_KEY = "apple-pay-express-checkout-on-banners";
|
package/dist/src/index.js
CHANGED
|
@@ -1308,6 +1308,7 @@ var ApplePayEntryPoint = /* @__PURE__ */ ((ApplePayEntryPoint2) => {
|
|
|
1308
1308
|
ApplePayEntryPoint2["PAYWALL"] = "article_paywall";
|
|
1309
1309
|
ApplePayEntryPoint2["REGWALL"] = "article_regwall";
|
|
1310
1310
|
ApplePayEntryPoint2["DUAL_OFFER_BANNER"] = "dual_offer_banner";
|
|
1311
|
+
ApplePayEntryPoint2["FREE_TRIAL_POPUP"] = "free_trial_popup";
|
|
1311
1312
|
return ApplePayEntryPoint2;
|
|
1312
1313
|
})(ApplePayEntryPoint || {});
|
|
1313
1314
|
var APPLE_PAY_EXPRESS_EXPERIMENT_KEY = "apple-pay-express-checkout-on-banners";
|
|
@@ -2022,6 +2023,9 @@ var ENTRY_POINT_CONFIG = {
|
|
|
2022
2023
|
["article_regwall" /* REGWALL */]: {
|
|
2023
2024
|
isEligible: () => true,
|
|
2024
2025
|
experimentFlagKey: APPLE_PAY_EXPRESS_EXPERIMENT_KEY
|
|
2026
|
+
},
|
|
2027
|
+
["free_trial_popup" /* FREE_TRIAL_POPUP */]: {
|
|
2028
|
+
isEligible: () => true
|
|
2025
2029
|
}
|
|
2026
2030
|
};
|
|
2027
2031
|
var FEATURE_APPLE_PAY_EXPRESS_CHECKOUT = "FEATURE_APPLE_PAY_EXPRESS_CHECKOUT";
|
|
@@ -2045,9 +2049,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2045
2049
|
* Reads the experiment variant from `window.experimentIntegration.getVariant`:
|
|
2046
2050
|
* - {@link APPLE_PAY_EXPRESS_PAYWALLS_EXPERIMENT_KEY} for `PAYWALL`
|
|
2047
2051
|
* - {@link APPLE_PAY_EXPRESS_EXPERIMENT_KEY} for `REGWALL` / `DUAL_OFFER_BANNER`
|
|
2052
|
+
* - no Amplitude gate for `FREE_TRIAL_POPUP` (always shown)
|
|
2048
2053
|
*
|
|
2049
2054
|
* The host page is responsible for setting up `window.experimentIntegration`
|
|
2050
|
-
* before calling this method.
|
|
2055
|
+
* before calling this method (except `FREE_TRIAL_POPUP`).
|
|
2051
2056
|
*
|
|
2052
2057
|
* - `treatment` → button created and returned
|
|
2053
2058
|
* - `control` / missing / anything else → returns null (button suppressed)
|
|
@@ -2060,7 +2065,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2060
2065
|
* **Eligibility:**
|
|
2061
2066
|
* - `DUAL_OFFER_BANNER` (or omitted): homepage + Safari/iPhone (SMA-3301)
|
|
2062
2067
|
* - `PAYWALL`: Safari/Apple device only (no homepage) — article paywalls
|
|
2063
|
-
* - `REGWALL`: no host-side placement gate
|
|
2068
|
+
* - `REGWALL` / `FREE_TRIAL_POPUP`: no host-side placement gate
|
|
2064
2069
|
*
|
|
2065
2070
|
* @param offer - The offer to display in the Apple Pay flow.
|
|
2066
2071
|
* @param country - The user's country code.
|
|
@@ -2086,24 +2091,24 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2086
2091
|
if (!hasUrlParamFlag && !bypassApplePayChecks() && !isEligible) {
|
|
2087
2092
|
return null;
|
|
2088
2093
|
}
|
|
2089
|
-
|
|
2090
|
-
experimentFlagKey
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2094
|
+
if (experimentFlagKey) {
|
|
2095
|
+
const experimentValue = window.experimentIntegration?.getVariant?.(experimentFlagKey);
|
|
2096
|
+
const isExperimentVariant = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.CONTROL || experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2097
|
+
if (isExperimentVariant && isEligible && !bypassApplePayChecks() && !hasUrlParamFlag) {
|
|
2098
|
+
void isApplePayAvailable().then((available) => {
|
|
2099
|
+
if (available) {
|
|
2100
|
+
trackApplePayExperimentExposure(
|
|
2101
|
+
experimentValue,
|
|
2102
|
+
getExperimentKeyFromNextData(experimentFlagKey),
|
|
2103
|
+
experimentFlagKey
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
const isTreatment = experimentValue === APPLE_PAY_EXPRESS_VARIANTS.TREATMENT;
|
|
2109
|
+
if (!isTreatment && !hasUrlParamFlag) {
|
|
2110
|
+
return null;
|
|
2111
|
+
}
|
|
2107
2112
|
}
|
|
2108
2113
|
_ApplePayButton.define();
|
|
2109
2114
|
const button = document.createElement(_ApplePayButton.tag);
|
|
@@ -2211,18 +2216,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2211
2216
|
if (await this.#fetchAndCacheOptions()) return;
|
|
2212
2217
|
this.#finishLoading();
|
|
2213
2218
|
} catch {
|
|
2214
|
-
this
|
|
2215
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2219
|
+
this.#hide();
|
|
2216
2220
|
} finally {
|
|
2217
2221
|
this.#rendering = false;
|
|
2218
2222
|
}
|
|
2219
2223
|
}
|
|
2224
|
+
/**
|
|
2225
|
+
* Stop the loading spinner before tear-down so Safari does not leave a GPU
|
|
2226
|
+
* ghost of `.apple-pay-btn.wap-loading::before` after the container is removed.
|
|
2227
|
+
*/
|
|
2228
|
+
#hide() {
|
|
2229
|
+
const button = this.querySelector(SEL_BUTTON);
|
|
2230
|
+
if (button) {
|
|
2231
|
+
button.classList.remove("wap-loading");
|
|
2232
|
+
button.removeAttribute("aria-busy");
|
|
2233
|
+
button.getAnimations?.({ subtree: true }).forEach((animation) => animation.cancel());
|
|
2234
|
+
}
|
|
2235
|
+
this.getAnimations?.({ subtree: true }).forEach(
|
|
2236
|
+
(animation) => animation.cancel()
|
|
2237
|
+
);
|
|
2238
|
+
void this.offsetHeight;
|
|
2239
|
+
this.style.display = "none";
|
|
2240
|
+
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2241
|
+
}
|
|
2220
2242
|
/** Returns `true` (hide) when Apple Pay is unavailable on this device/browser. */
|
|
2221
2243
|
async #checkAvailability() {
|
|
2222
2244
|
const available = await isApplePayAvailable();
|
|
2223
2245
|
if (!available) {
|
|
2224
|
-
this
|
|
2225
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2246
|
+
this.#hide();
|
|
2226
2247
|
return true;
|
|
2227
2248
|
}
|
|
2228
2249
|
return false;
|
|
@@ -2234,8 +2255,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2234
2255
|
async #checkSession() {
|
|
2235
2256
|
this.#sessionData = await this.#fetchSession();
|
|
2236
2257
|
if (this.#sessionData?.loggedIn && (this.#sessionData.userType === "active-subscription" || this.#sessionData.userType === "b2b-user")) {
|
|
2237
|
-
this
|
|
2238
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2258
|
+
this.#hide();
|
|
2239
2259
|
return true;
|
|
2240
2260
|
}
|
|
2241
2261
|
return false;
|
|
@@ -2243,8 +2263,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2243
2263
|
/** Returns `true` (hide) when no offer has been set before mount. */
|
|
2244
2264
|
#checkOffer() {
|
|
2245
2265
|
if (!this.#offer) {
|
|
2246
|
-
this
|
|
2247
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2266
|
+
this.#hide();
|
|
2248
2267
|
return true;
|
|
2249
2268
|
}
|
|
2250
2269
|
return false;
|
|
@@ -2271,8 +2290,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
|
|
|
2271
2290
|
async #fetchAndCacheOptions() {
|
|
2272
2291
|
this.#paymentOptions = await this.#fetchPaymentOptions();
|
|
2273
2292
|
if (!this.#paymentOptions?.options?.apple_pay) {
|
|
2274
|
-
this
|
|
2275
|
-
this.querySelector(SEL_CONTAINER)?.remove();
|
|
2293
|
+
this.#hide();
|
|
2276
2294
|
return true;
|
|
2277
2295
|
}
|
|
2278
2296
|
return false;
|
package/package.json
CHANGED