@economist/web-apple-pay 1.2.0 → 1.4.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.
@@ -142,3 +163,24 @@ Then in a consuming app:
142
163
  ```sh
143
164
  yalc add @economist/web-apple-pay
144
165
  ```
166
+
167
+ ## Storybook
168
+
169
+ Run Storybook locally:
170
+
171
+ ```sh
172
+ npm run storybook --workspace @economist/web-apple-pay
173
+ ```
174
+
175
+ Build static Storybook output:
176
+
177
+ ```sh
178
+ npm run build-storybook --workspace @economist/web-apple-pay
179
+ ```
180
+
181
+ Story coverage matrix:
182
+
183
+ - `ApplePayButton` docs page shows the stable default example.
184
+ - `ApplePayButton` behavior and state variants are available as individual canvas stories in Storybook.
185
+ - `ApplePayModal` docs page shows the stable default example.
186
+ - `ApplePayModal` behavior and state variants are available as individual canvas stories in Storybook.
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) {
@@ -11,5 +11,22 @@ export declare class ApplePayButton extends HTMLElement {
11
11
  set offer(value: Offer | null);
12
12
  get country(): string;
13
13
  set country(value: string);
14
+ /**
15
+ * Awaitable contract for the component's current render lifecycle.
16
+ *
17
+ * - If called **after** the element has been appended to the DOM, resolves
18
+ * once `connectedCallback` finishes — whether Apple Pay rendered
19
+ * successfully or was hidden (unavailable / suppressed by session).
20
+ * - If called **before** the element is appended (or if it has never been
21
+ * connected), resolves immediately to `undefined`. It does **not** wait
22
+ * for a future connection, so always `await whenReady()` after `appendChild`:
23
+ *
24
+ * ```ts
25
+ * container.appendChild(btn); // browser fires connectedCallback
26
+ * await btn.whenReady(); // waits for render to finish
27
+ * if (btn.style.display !== 'none') { /* available *\/ }
28
+ * ```
29
+ */
30
+ whenReady(): Promise<void>;
14
31
  connectedCallback(): Promise<void>;
15
32
  }
@@ -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) {