@economist/web-apple-pay 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -78,6 +78,26 @@ If `merchantId` is not configured, Apple Pay availability checks return `false`
78
78
  - Skips rendering for excluded variants (`bundle`, `insider_print`).
79
79
  - Forwards `data-logged-in` from button to modal (`modal.dataset.loggedIn`).
80
80
 
81
+ #### Awaiting render completion — `whenReady()`
82
+
83
+ Use `whenReady()` to await the component's render lifecycle after appending it
84
+ to the DOM. This is the supported, stable way to know whether Apple Pay is
85
+ available without touching lifecycle internals.
86
+
87
+ ```ts
88
+ container.appendChild(btn); // spec-compliant — browser fires connectedCallback naturally
89
+ await btn.whenReady(); // resolves when rendering is complete
90
+ if (btn.style.display !== 'none') {
91
+ // Apple Pay rendered successfully
92
+ } else {
93
+ btn.remove(); // unavailable or suppressed
94
+ }
95
+ ```
96
+
97
+ > **Important:** calling `whenReady()` _before_ `appendChild` resolves
98
+ > immediately to `undefined` — it does not wait for a future connection.
99
+ > Always call it after appending the element.
100
+
81
101
  ### `ApplePayModal`
82
102
 
83
103
  - Opened by `ApplePayButton` click.
@@ -100,6 +120,7 @@ Consumers should listen for this event and continue payment orchestration.
100
120
  - `defineApplePayElements()`: registers both custom elements.
101
121
  - `configureApplePay(config)`: sets required runtime config (merchant ID and wallet API base URL, with optional debug bypass).
102
122
  - `ApplePayButton`: button component class.
123
+ - `whenReady(): Promise<void>` — resolves when the current render lifecycle completes (available or hidden). Resolves immediately if called before the element is connected.
103
124
  - `ApplePayModal`: modal component class.
104
125
  - `ensureApplePayLogoSymbol()`: logo symbol injection helper.
105
126
  - `Offer`: offer contract type used by component props.
package/dist/index.js CHANGED
@@ -881,6 +881,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
881
881
  #offer = null;
882
882
  #country = "";
883
883
  #rendering = false;
884
+ #readyPromise = null;
884
885
  get offer() {
885
886
  return this.#offer;
886
887
  }
@@ -894,11 +895,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
894
895
  set country(value) {
895
896
  this.#country = value;
896
897
  }
898
+ /**
899
+ * Awaitable contract for the component's current render lifecycle.
900
+ *
901
+ * - If called **after** the element has been appended to the DOM, resolves
902
+ * once `connectedCallback` finishes — whether Apple Pay rendered
903
+ * successfully or was hidden (unavailable / suppressed by session).
904
+ * - If called **before** the element is appended (or if it has never been
905
+ * connected), resolves immediately to `undefined`. It does **not** wait
906
+ * for a future connection, so always `await whenReady()` after `appendChild`:
907
+ *
908
+ * ```ts
909
+ * container.appendChild(btn); // browser fires connectedCallback
910
+ * await btn.whenReady(); // waits for render to finish
911
+ * if (btn.style.display !== 'none') { /* available *\/ }
912
+ * ```
913
+ */
914
+ whenReady() {
915
+ return this.#readyPromise ?? Promise.resolve();
916
+ }
897
917
  async connectedCallback() {
898
918
  if (this.#rendering || this.querySelector(".apple-pay-container")) {
899
919
  return;
900
920
  }
901
921
  this.#rendering = true;
922
+ this.#readyPromise = this.#run();
923
+ await this.#readyPromise;
924
+ }
925
+ async #run() {
902
926
  try {
903
927
  const available = await isApplePayAvailable();
904
928
  if (!available) {
@@ -967,6 +991,7 @@ function defineApplePayElements() {
967
991
  ApplePayModal.define();
968
992
  }
969
993
  export {
994
+ APPLE_PAY_EXCLUDED_VARIANTS,
970
995
  ApplePayButton,
971
996
  ApplePayModal,
972
997
  configureApplePay,
@@ -1,4 +1,5 @@
1
- import type { Offer } from './types/offer.types';
1
+ import type { Offer, ProductVariant } from './types/offer.types';
2
+ export declare const APPLE_PAY_EXCLUDED_VARIANTS: readonly ProductVariant[];
2
3
  export declare class ApplePayButton extends HTMLElement {
3
4
  #private;
4
5
  static readonly tag = "teg-apple-pay-button";
@@ -11,5 +12,22 @@ export declare class ApplePayButton extends HTMLElement {
11
12
  set offer(value: Offer | null);
12
13
  get country(): string;
13
14
  set country(value: string);
15
+ /**
16
+ * Awaitable contract for the component's current render lifecycle.
17
+ *
18
+ * - If called **after** the element has been appended to the DOM, resolves
19
+ * once `connectedCallback` finishes — whether Apple Pay rendered
20
+ * successfully or was hidden (unavailable / suppressed by session).
21
+ * - If called **before** the element is appended (or if it has never been
22
+ * connected), resolves immediately to `undefined`. It does **not** wait
23
+ * for a future connection, so always `await whenReady()` after `appendChild`:
24
+ *
25
+ * ```ts
26
+ * container.appendChild(btn); // browser fires connectedCallback
27
+ * await btn.whenReady(); // waits for render to finish
28
+ * if (btn.style.display !== 'none') { /* available *\/ }
29
+ * ```
30
+ */
31
+ whenReady(): Promise<void>;
14
32
  connectedCallback(): Promise<void>;
15
33
  }
@@ -876,6 +876,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
876
876
  #offer = null;
877
877
  #country = "";
878
878
  #rendering = false;
879
+ #readyPromise = null;
879
880
  get offer() {
880
881
  return this.#offer;
881
882
  }
@@ -889,11 +890,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
889
890
  set country(value) {
890
891
  this.#country = value;
891
892
  }
893
+ /**
894
+ * Awaitable contract for the component's current render lifecycle.
895
+ *
896
+ * - If called **after** the element has been appended to the DOM, resolves
897
+ * once `connectedCallback` finishes — whether Apple Pay rendered
898
+ * successfully or was hidden (unavailable / suppressed by session).
899
+ * - If called **before** the element is appended (or if it has never been
900
+ * connected), resolves immediately to `undefined`. It does **not** wait
901
+ * for a future connection, so always `await whenReady()` after `appendChild`:
902
+ *
903
+ * ```ts
904
+ * container.appendChild(btn); // browser fires connectedCallback
905
+ * await btn.whenReady(); // waits for render to finish
906
+ * if (btn.style.display !== 'none') { /* available *\/ }
907
+ * ```
908
+ */
909
+ whenReady() {
910
+ return this.#readyPromise ?? Promise.resolve();
911
+ }
892
912
  async connectedCallback() {
893
913
  if (this.#rendering || this.querySelector(".apple-pay-container")) {
894
914
  return;
895
915
  }
896
916
  this.#rendering = true;
917
+ this.#readyPromise = this.#run();
918
+ await this.#readyPromise;
919
+ }
920
+ async #run() {
897
921
  try {
898
922
  const available = await isApplePayAvailable();
899
923
  if (!available) {
@@ -956,5 +980,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
956
980
  }
957
981
  };
958
982
  export {
983
+ APPLE_PAY_EXCLUDED_VARIANTS,
959
984
  ApplePayButton
960
985
  };
@@ -884,6 +884,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
884
884
  #offer = null;
885
885
  #country = "";
886
886
  #rendering = false;
887
+ #readyPromise = null;
887
888
  get offer() {
888
889
  return this.#offer;
889
890
  }
@@ -897,11 +898,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
897
898
  set country(value) {
898
899
  this.#country = value;
899
900
  }
901
+ /**
902
+ * Awaitable contract for the component's current render lifecycle.
903
+ *
904
+ * - If called **after** the element has been appended to the DOM, resolves
905
+ * once `connectedCallback` finishes — whether Apple Pay rendered
906
+ * successfully or was hidden (unavailable / suppressed by session).
907
+ * - If called **before** the element is appended (or if it has never been
908
+ * connected), resolves immediately to `undefined`. It does **not** wait
909
+ * for a future connection, so always `await whenReady()` after `appendChild`:
910
+ *
911
+ * ```ts
912
+ * container.appendChild(btn); // browser fires connectedCallback
913
+ * await btn.whenReady(); // waits for render to finish
914
+ * if (btn.style.display !== 'none') { /* available *\/ }
915
+ * ```
916
+ */
917
+ whenReady() {
918
+ return this.#readyPromise ?? Promise.resolve();
919
+ }
900
920
  async connectedCallback() {
901
921
  if (this.#rendering || this.querySelector(".apple-pay-container")) {
902
922
  return;
903
923
  }
904
924
  this.#rendering = true;
925
+ this.#readyPromise = this.#run();
926
+ await this.#readyPromise;
927
+ }
928
+ async #run() {
905
929
  try {
906
930
  const available = await isApplePayAvailable();
907
931
  if (!available) {
@@ -876,6 +876,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
876
876
  #offer = null;
877
877
  #country = "";
878
878
  #rendering = false;
879
+ #readyPromise = null;
879
880
  get offer() {
880
881
  return this.#offer;
881
882
  }
@@ -889,11 +890,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
889
890
  set country(value) {
890
891
  this.#country = value;
891
892
  }
893
+ /**
894
+ * Awaitable contract for the component's current render lifecycle.
895
+ *
896
+ * - If called **after** the element has been appended to the DOM, resolves
897
+ * once `connectedCallback` finishes — whether Apple Pay rendered
898
+ * successfully or was hidden (unavailable / suppressed by session).
899
+ * - If called **before** the element is appended (or if it has never been
900
+ * connected), resolves immediately to `undefined`. It does **not** wait
901
+ * for a future connection, so always `await whenReady()` after `appendChild`:
902
+ *
903
+ * ```ts
904
+ * container.appendChild(btn); // browser fires connectedCallback
905
+ * await btn.whenReady(); // waits for render to finish
906
+ * if (btn.style.display !== 'none') { /* available *\/ }
907
+ * ```
908
+ */
909
+ whenReady() {
910
+ return this.#readyPromise ?? Promise.resolve();
911
+ }
892
912
  async connectedCallback() {
893
913
  if (this.#rendering || this.querySelector(".apple-pay-container")) {
894
914
  return;
895
915
  }
896
916
  this.#rendering = true;
917
+ this.#readyPromise = this.#run();
918
+ await this.#readyPromise;
919
+ }
920
+ async #run() {
897
921
  try {
898
922
  const available = await isApplePayAvailable();
899
923
  if (!available) {
@@ -1,4 +1,4 @@
1
- export { ApplePayButton } from './apple-pay-button';
1
+ export { ApplePayButton, APPLE_PAY_EXCLUDED_VARIANTS } from './apple-pay-button';
2
2
  export { ApplePayModal } from './apple-pay-modal';
3
3
  export { ensureApplePayLogoSymbol } from './apple-pay-logo';
4
4
  export { configureApplePay } from './clients/payment-checkout/config';
package/dist/src/index.js CHANGED
@@ -881,6 +881,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
881
881
  #offer = null;
882
882
  #country = "";
883
883
  #rendering = false;
884
+ #readyPromise = null;
884
885
  get offer() {
885
886
  return this.#offer;
886
887
  }
@@ -894,11 +895,34 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
894
895
  set country(value) {
895
896
  this.#country = value;
896
897
  }
898
+ /**
899
+ * Awaitable contract for the component's current render lifecycle.
900
+ *
901
+ * - If called **after** the element has been appended to the DOM, resolves
902
+ * once `connectedCallback` finishes — whether Apple Pay rendered
903
+ * successfully or was hidden (unavailable / suppressed by session).
904
+ * - If called **before** the element is appended (or if it has never been
905
+ * connected), resolves immediately to `undefined`. It does **not** wait
906
+ * for a future connection, so always `await whenReady()` after `appendChild`:
907
+ *
908
+ * ```ts
909
+ * container.appendChild(btn); // browser fires connectedCallback
910
+ * await btn.whenReady(); // waits for render to finish
911
+ * if (btn.style.display !== 'none') { /* available *\/ }
912
+ * ```
913
+ */
914
+ whenReady() {
915
+ return this.#readyPromise ?? Promise.resolve();
916
+ }
897
917
  async connectedCallback() {
898
918
  if (this.#rendering || this.querySelector(".apple-pay-container")) {
899
919
  return;
900
920
  }
901
921
  this.#rendering = true;
922
+ this.#readyPromise = this.#run();
923
+ await this.#readyPromise;
924
+ }
925
+ async #run() {
902
926
  try {
903
927
  const available = await isApplePayAvailable();
904
928
  if (!available) {
@@ -967,6 +991,7 @@ function defineApplePayElements() {
967
991
  ApplePayModal.define();
968
992
  }
969
993
  export {
994
+ APPLE_PAY_EXCLUDED_VARIANTS,
970
995
  ApplePayButton,
971
996
  ApplePayModal,
972
997
  configureApplePay,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@economist/web-apple-pay",
3
3
  "description": "Web component package for Apple Pay checkout UI",
4
- "version": "1.3.0",
4
+ "version": "1.5.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",