@nymbalhq/web-components 1.0.0 → 1.2.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.
Files changed (187) hide show
  1. package/astro/NymbalElement.astro +19 -0
  2. package/dist/base-element-CPMgAdyQ.d.ts +91 -0
  3. package/dist/chunk-2TPQNQYO.js +155 -0
  4. package/dist/chunk-2TPQNQYO.js.map +1 -0
  5. package/dist/chunk-2XXBQPDB.js +113 -0
  6. package/dist/chunk-2XXBQPDB.js.map +1 -0
  7. package/dist/chunk-42SSME5H.js +84 -0
  8. package/dist/chunk-42SSME5H.js.map +1 -0
  9. package/dist/chunk-4COVK727.js +204 -0
  10. package/dist/chunk-4COVK727.js.map +1 -0
  11. package/dist/chunk-5VWZ2U5K.js +149 -0
  12. package/dist/chunk-5VWZ2U5K.js.map +1 -0
  13. package/dist/chunk-6XCCAAMF.js +656 -0
  14. package/dist/chunk-6XCCAAMF.js.map +1 -0
  15. package/dist/chunk-7JAAOVCE.js +114 -0
  16. package/dist/chunk-7JAAOVCE.js.map +1 -0
  17. package/dist/chunk-B73QVSA5.js +206 -0
  18. package/dist/chunk-B73QVSA5.js.map +1 -0
  19. package/dist/chunk-DR5QB5VN.js +17 -0
  20. package/dist/chunk-DR5QB5VN.js.map +1 -0
  21. package/dist/chunk-DXWMNB5F.js +70 -0
  22. package/dist/chunk-DXWMNB5F.js.map +1 -0
  23. package/dist/chunk-EBMA7JGV.js +130 -0
  24. package/dist/chunk-EBMA7JGV.js.map +1 -0
  25. package/dist/chunk-EYDMJNNK.js +176 -0
  26. package/dist/chunk-EYDMJNNK.js.map +1 -0
  27. package/dist/chunk-FIF6GQ6U.js +141 -0
  28. package/dist/chunk-FIF6GQ6U.js.map +1 -0
  29. package/dist/chunk-GHXTJ2CF.js +109 -0
  30. package/dist/chunk-GHXTJ2CF.js.map +1 -0
  31. package/dist/chunk-H3ZBYNHV.js +153 -0
  32. package/dist/chunk-H3ZBYNHV.js.map +1 -0
  33. package/dist/chunk-HPBC3OG7.js +174 -0
  34. package/dist/chunk-HPBC3OG7.js.map +1 -0
  35. package/dist/chunk-IYT7VXFS.js +105 -0
  36. package/dist/chunk-IYT7VXFS.js.map +1 -0
  37. package/dist/chunk-LHYXNQWY.js +105 -0
  38. package/dist/chunk-LHYXNQWY.js.map +1 -0
  39. package/dist/chunk-LO2EW5YP.js +25 -0
  40. package/dist/chunk-LO2EW5YP.js.map +1 -0
  41. package/dist/chunk-LSQPUZK6.js +291 -0
  42. package/dist/chunk-LSQPUZK6.js.map +1 -0
  43. package/dist/chunk-N4Y5DI4X.js +82 -0
  44. package/dist/chunk-N4Y5DI4X.js.map +1 -0
  45. package/dist/chunk-NE6UHTOT.js +148 -0
  46. package/dist/chunk-NE6UHTOT.js.map +1 -0
  47. package/dist/chunk-NW47OJVN.js +138 -0
  48. package/dist/chunk-NW47OJVN.js.map +1 -0
  49. package/dist/chunk-O2YKCDR2.js +77 -0
  50. package/dist/chunk-O2YKCDR2.js.map +1 -0
  51. package/dist/chunk-PN6QKYE4.js +71 -0
  52. package/dist/chunk-PN6QKYE4.js.map +1 -0
  53. package/dist/chunk-RAOGZH3Z.js +188 -0
  54. package/dist/chunk-RAOGZH3Z.js.map +1 -0
  55. package/dist/chunk-RVSKX2RX.js +11 -0
  56. package/dist/chunk-RVSKX2RX.js.map +1 -0
  57. package/dist/chunk-RZVFA3N5.js +154 -0
  58. package/dist/chunk-RZVFA3N5.js.map +1 -0
  59. package/dist/chunk-SM7TASEW.js +135 -0
  60. package/dist/chunk-SM7TASEW.js.map +1 -0
  61. package/dist/chunk-U2PU4CWB.js +124 -0
  62. package/dist/chunk-U2PU4CWB.js.map +1 -0
  63. package/dist/chunk-UCEVCLQ7.js +5 -0
  64. package/dist/chunk-UCEVCLQ7.js.map +1 -0
  65. package/dist/chunk-UYSZOEOA.js +32 -0
  66. package/dist/chunk-UYSZOEOA.js.map +1 -0
  67. package/dist/chunk-V55K2CS5.js +126 -0
  68. package/dist/chunk-V55K2CS5.js.map +1 -0
  69. package/dist/chunk-VTQVGNVC.js +346 -0
  70. package/dist/chunk-VTQVGNVC.js.map +1 -0
  71. package/dist/chunk-W23P7SI4.js +239 -0
  72. package/dist/chunk-W23P7SI4.js.map +1 -0
  73. package/dist/chunk-W7D3STJH.js +279 -0
  74. package/dist/chunk-W7D3STJH.js.map +1 -0
  75. package/dist/chunk-WEEHXWM3.js +172 -0
  76. package/dist/chunk-WEEHXWM3.js.map +1 -0
  77. package/dist/chunk-WTEVTCIL.js +128 -0
  78. package/dist/chunk-WTEVTCIL.js.map +1 -0
  79. package/dist/chunk-XE6IWISA.js +137 -0
  80. package/dist/chunk-XE6IWISA.js.map +1 -0
  81. package/dist/elements/nymbal-add-to-cart.d.ts +14 -0
  82. package/dist/elements/nymbal-add-to-cart.js +10 -0
  83. package/dist/elements/nymbal-add-to-cart.js.map +1 -0
  84. package/dist/elements/nymbal-address-book.d.ts +30 -0
  85. package/dist/elements/nymbal-address-book.js +13 -0
  86. package/dist/elements/nymbal-address-book.js.map +1 -0
  87. package/dist/elements/nymbal-address-form.d.ts +29 -0
  88. package/dist/elements/nymbal-address-form.js +12 -0
  89. package/dist/elements/nymbal-address-form.js.map +1 -0
  90. package/dist/elements/nymbal-breadcrumb.d.ts +15 -0
  91. package/dist/elements/nymbal-breadcrumb.js +11 -0
  92. package/dist/elements/nymbal-breadcrumb.js.map +1 -0
  93. package/dist/elements/nymbal-cart-drawer.d.ts +24 -0
  94. package/dist/elements/nymbal-cart-drawer.js +11 -0
  95. package/dist/elements/nymbal-cart-drawer.js.map +1 -0
  96. package/dist/elements/nymbal-cart-page.d.ts +20 -0
  97. package/dist/elements/nymbal-cart-page.js +14 -0
  98. package/dist/elements/nymbal-cart-page.js.map +1 -0
  99. package/dist/elements/nymbal-category-nav.d.ts +15 -0
  100. package/dist/elements/nymbal-category-nav.js +11 -0
  101. package/dist/elements/nymbal-category-nav.js.map +1 -0
  102. package/dist/elements/nymbal-checkout.d.ts +77 -0
  103. package/dist/elements/nymbal-checkout.js +15 -0
  104. package/dist/elements/nymbal-checkout.js.map +1 -0
  105. package/dist/elements/nymbal-image-gallery.d.ts +19 -0
  106. package/dist/elements/nymbal-image-gallery.js +10 -0
  107. package/dist/elements/nymbal-image-gallery.js.map +1 -0
  108. package/dist/elements/nymbal-login-form.d.ts +17 -0
  109. package/dist/elements/nymbal-login-form.js +12 -0
  110. package/dist/elements/nymbal-login-form.js.map +1 -0
  111. package/dist/elements/nymbal-mini-cart.d.ts +17 -0
  112. package/dist/elements/nymbal-mini-cart.js +10 -0
  113. package/dist/elements/nymbal-mini-cart.js.map +1 -0
  114. package/dist/elements/nymbal-order-summary.d.ts +20 -0
  115. package/dist/elements/nymbal-order-summary.js +11 -0
  116. package/dist/elements/nymbal-order-summary.js.map +1 -0
  117. package/dist/elements/nymbal-payment-element.d.ts +4 -0
  118. package/dist/elements/nymbal-payment-element.js +10 -0
  119. package/dist/elements/nymbal-payment-element.js.map +1 -0
  120. package/dist/elements/nymbal-product-card.d.ts +4 -0
  121. package/dist/elements/nymbal-product-card.js +12 -0
  122. package/dist/elements/nymbal-product-card.js.map +1 -0
  123. package/dist/elements/nymbal-product-filter.d.ts +32 -0
  124. package/dist/elements/nymbal-product-filter.js +10 -0
  125. package/dist/elements/nymbal-product-filter.js.map +1 -0
  126. package/dist/elements/nymbal-product-grid.d.ts +24 -0
  127. package/dist/elements/nymbal-product-grid.js +14 -0
  128. package/dist/elements/nymbal-product-grid.js.map +1 -0
  129. package/dist/elements/nymbal-product-price.d.ts +18 -0
  130. package/dist/elements/nymbal-product-price.js +12 -0
  131. package/dist/elements/nymbal-product-price.js.map +1 -0
  132. package/dist/elements/nymbal-profile-form.d.ts +19 -0
  133. package/dist/elements/nymbal-profile-form.js +12 -0
  134. package/dist/elements/nymbal-profile-form.js.map +1 -0
  135. package/dist/elements/nymbal-quantity-selector.d.ts +20 -0
  136. package/dist/elements/nymbal-quantity-selector.js +10 -0
  137. package/dist/elements/nymbal-quantity-selector.js.map +1 -0
  138. package/dist/elements/nymbal-register-form.d.ts +17 -0
  139. package/dist/elements/nymbal-register-form.js +12 -0
  140. package/dist/elements/nymbal-register-form.js.map +1 -0
  141. package/dist/elements/nymbal-review-form.d.ts +17 -0
  142. package/dist/elements/nymbal-review-form.js +12 -0
  143. package/dist/elements/nymbal-review-form.js.map +1 -0
  144. package/dist/elements/nymbal-review-list.d.ts +14 -0
  145. package/dist/elements/nymbal-review-list.js +10 -0
  146. package/dist/elements/nymbal-review-list.js.map +1 -0
  147. package/dist/elements/nymbal-search-bar.d.ts +19 -0
  148. package/dist/elements/nymbal-search-bar.js +10 -0
  149. package/dist/elements/nymbal-search-bar.js.map +1 -0
  150. package/dist/elements/nymbal-search-results.d.ts +29 -0
  151. package/dist/elements/nymbal-search-results.js +14 -0
  152. package/dist/elements/nymbal-search-results.js.map +1 -0
  153. package/dist/elements/nymbal-site-footer.d.ts +15 -0
  154. package/dist/elements/nymbal-site-footer.js +11 -0
  155. package/dist/elements/nymbal-site-footer.js.map +1 -0
  156. package/dist/elements/nymbal-site-header.d.ts +19 -0
  157. package/dist/elements/nymbal-site-header.js +11 -0
  158. package/dist/elements/nymbal-site-header.js.map +1 -0
  159. package/dist/elements/nymbal-sort-dropdown.d.ts +28 -0
  160. package/dist/elements/nymbal-sort-dropdown.js +10 -0
  161. package/dist/elements/nymbal-sort-dropdown.js.map +1 -0
  162. package/dist/elements/nymbal-stock-badge.d.ts +16 -0
  163. package/dist/elements/nymbal-stock-badge.js +11 -0
  164. package/dist/elements/nymbal-stock-badge.js.map +1 -0
  165. package/dist/elements/nymbal-toast.d.ts +18 -0
  166. package/dist/elements/nymbal-toast.js +10 -0
  167. package/dist/elements/nymbal-toast.js.map +1 -0
  168. package/dist/elements/nymbal-variant-selector.d.ts +16 -0
  169. package/dist/elements/nymbal-variant-selector.js +10 -0
  170. package/dist/elements/nymbal-variant-selector.js.map +1 -0
  171. package/dist/form-element-C-qo3gpD.d.ts +25 -0
  172. package/dist/hydrate-support.d.ts +2 -0
  173. package/dist/hydrate-support.js +3 -0
  174. package/dist/hydrate-support.js.map +1 -0
  175. package/dist/index.d.ts +37 -105
  176. package/dist/index.js +130 -1098
  177. package/dist/index.js.map +1 -1
  178. package/dist/nymbal-payment-element-Bt8EF42T.d.ts +51 -0
  179. package/dist/nymbal-product-card-C8HkE_rG.d.ts +47 -0
  180. package/dist/register-components.d.ts +46 -0
  181. package/dist/register-components.js +48 -0
  182. package/dist/register-components.js.map +1 -0
  183. package/dist/selected-variant-Dym0shlJ.d.ts +23 -0
  184. package/dist/ssr/index.d.ts +30 -0
  185. package/dist/ssr/index.js +143 -0
  186. package/dist/ssr/index.js.map +1 -0
  187. package/package.json +33 -6
@@ -0,0 +1,656 @@
1
+ import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
2
+ import {
3
+ formatPrice
4
+ } from "./chunk-RVSKX2RX.js";
5
+ import {
6
+ NymbalAddressForm
7
+ } from "./chunk-V55K2CS5.js";
8
+ import {
9
+ renderField
10
+ } from "./chunk-PN6QKYE4.js";
11
+ import {
12
+ buttonStyles,
13
+ fieldStyles
14
+ } from "./chunk-GHXTJ2CF.js";
15
+ import {
16
+ shownCart
17
+ } from "./chunk-DR5QB5VN.js";
18
+ import {
19
+ NymbalElement,
20
+ baseStyles,
21
+ propertiesOf
22
+ } from "./chunk-EYDMJNNK.js";
23
+
24
+ // src/components/checkout.ts
25
+ import { css, html, nothing } from "lit";
26
+ var SCHEMA = {
27
+ tag: "nymbal-checkout",
28
+ reactName: "Checkout",
29
+ // The cart a server read (cart-projection.ts), shown in the summary until the cart store settles.
30
+ attributes: [{ name: "cart", prop: "cart", type: "json" }],
31
+ events: [
32
+ {
33
+ name: "nymbal:checkout:placed",
34
+ prop: "onPlaced",
35
+ detail: "{ orderNumber: string }"
36
+ }
37
+ ],
38
+ parts: [
39
+ "layout",
40
+ "main",
41
+ "title",
42
+ "steps",
43
+ "step",
44
+ "step-active",
45
+ "step-done",
46
+ "step-divider",
47
+ "step-divider-done",
48
+ "error",
49
+ "section",
50
+ "form",
51
+ "section-title",
52
+ "field",
53
+ "label",
54
+ "input",
55
+ "billing-same",
56
+ "billing",
57
+ "billing-title",
58
+ "payment",
59
+ "actions",
60
+ "back",
61
+ "submit",
62
+ "terms",
63
+ "summary",
64
+ "summary-title",
65
+ "items",
66
+ "item",
67
+ "item-name",
68
+ "item-variant",
69
+ "item-qty",
70
+ "item-price",
71
+ "summary-row",
72
+ "subtotal",
73
+ "total"
74
+ ],
75
+ slots: [
76
+ "payment",
77
+ "title",
78
+ "contact-continue-label",
79
+ "shipping-continue-label",
80
+ "place-order-label",
81
+ "terms",
82
+ "summary-title"
83
+ ],
84
+ children: true
85
+ };
86
+ var STEPS = ["contact", "shipping", "payment"];
87
+ var STEP_LABELS = {
88
+ contact: "Contact",
89
+ shipping: "Shipping",
90
+ payment: "Payment"
91
+ };
92
+ var STEP_HEIGHT_HOLD_MS = 600;
93
+ var PAYMENT_FAILED = "Payment failed. Please try again.";
94
+ var NO_PAYMENT_STEP = { ok: true, confirmed: false };
95
+ var NymbalCheckout = class extends NymbalElement {
96
+ static schema = SCHEMA;
97
+ static uses = [NymbalAddressForm];
98
+ static properties = propertiesOf(SCHEMA);
99
+ static styles = [
100
+ baseStyles,
101
+ buttonStyles,
102
+ fieldStyles,
103
+ css`
104
+ [hidden] {
105
+ display: none !important;
106
+ }
107
+ [part~='layout'] {
108
+ display: grid;
109
+ grid-template-columns: 1fr;
110
+ gap: var(--nymbal-spacing-xl, 2rem);
111
+ }
112
+ @media (min-width: 769px) {
113
+ [part~='layout'] {
114
+ grid-template-columns: 1fr 380px;
115
+ align-items: start;
116
+ }
117
+ }
118
+ [part~='title'] {
119
+ margin: 0 0 var(--nymbal-spacing-md, 1rem);
120
+ font-size: 1.75rem;
121
+ font-weight: var(--nymbal-font-weight-bold, 700);
122
+ }
123
+ [part~='steps'] {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ margin-bottom: var(--nymbal-spacing-xl, 2rem);
128
+ padding: var(--nymbal-spacing-md, 1rem) 0;
129
+ counter-reset: step;
130
+ }
131
+ [part~='step'] {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: var(--nymbal-spacing-sm, 0.5rem);
135
+ font-size: var(--nymbal-font-size-sm, 0.875rem);
136
+ color: var(--nymbal-color-text-muted, #71717a);
137
+ white-space: nowrap;
138
+ }
139
+ [part~='step']::before {
140
+ counter-increment: step;
141
+ content: counter(step);
142
+ display: flex;
143
+ align-items: center;
144
+ justify-content: center;
145
+ width: 28px;
146
+ height: 28px;
147
+ flex-shrink: 0;
148
+ border: 2px solid var(--nymbal-color-border, #e4e4e7);
149
+ border-radius: var(--nymbal-radius-full, 9999px);
150
+ font-size: var(--nymbal-font-size-xs, 0.75rem);
151
+ font-weight: var(--nymbal-font-weight-bold, 700);
152
+ }
153
+ [part~='step-active'] {
154
+ color: var(--nymbal-color-primary, #18181b);
155
+ font-weight: var(--nymbal-font-weight-medium, 500);
156
+ }
157
+ [part~='step-active']::before {
158
+ background-color: var(--nymbal-color-primary, #18181b);
159
+ border-color: var(--nymbal-color-primary, #18181b);
160
+ color: var(--nymbal-color-text-inverse, #fff);
161
+ }
162
+ [part~='step-done']::before {
163
+ content: '\\2713';
164
+ background-color: var(--nymbal-color-success, #16a34a);
165
+ border-color: var(--nymbal-color-success, #16a34a);
166
+ color: var(--nymbal-color-text-inverse, #fff);
167
+ }
168
+ [part~='step-divider'] {
169
+ width: 40px;
170
+ height: 2px;
171
+ flex-shrink: 0;
172
+ margin: 0 var(--nymbal-spacing-sm, 0.5rem);
173
+ background-color: var(--nymbal-color-border, #e4e4e7);
174
+ }
175
+ [part~='step-divider-done'] {
176
+ background-color: var(--nymbal-color-success, #16a34a);
177
+ }
178
+ @media (max-width: 640px) {
179
+ [part~='step'] span {
180
+ display: none;
181
+ }
182
+ [part~='step-divider'] {
183
+ width: 24px;
184
+ }
185
+ }
186
+ [part~='section-title'] {
187
+ margin: 0 0 var(--nymbal-spacing-md, 1rem);
188
+ font-size: var(--nymbal-font-size-lg, 1.125rem);
189
+ font-weight: var(--nymbal-font-weight-bold, 700);
190
+ color: var(--nymbal-color-primary, #18181b);
191
+ }
192
+ [part~='billing-same'] {
193
+ display: flex;
194
+ align-items: center;
195
+ gap: var(--nymbal-spacing-sm, 0.5rem);
196
+ margin-bottom: var(--nymbal-spacing-md, 1rem);
197
+ font-size: var(--nymbal-font-size-sm, 0.875rem);
198
+ cursor: pointer;
199
+ }
200
+ [part~='billing-title'] {
201
+ margin: 0 0 var(--nymbal-spacing-md, 1rem);
202
+ font-size: var(--nymbal-font-size-base, 1rem);
203
+ font-weight: var(--nymbal-font-weight-bold, 700);
204
+ }
205
+ [part~='payment'] {
206
+ margin-top: var(--nymbal-spacing-md, 1rem);
207
+ }
208
+ [part~='actions'] {
209
+ display: flex;
210
+ justify-content: space-between;
211
+ gap: var(--nymbal-spacing-sm, 0.5rem);
212
+ margin-top: var(--nymbal-spacing-lg, 1.5rem);
213
+ }
214
+ [part~='submit'] {
215
+ flex: 1;
216
+ padding: var(--nymbal-spacing-md, 1rem);
217
+ font-size: var(--nymbal-font-size-base, 1rem);
218
+ }
219
+ [part~='terms'] {
220
+ margin: var(--nymbal-spacing-sm, 0.5rem) 0 0;
221
+ font-size: var(--nymbal-font-size-xs, 0.75rem);
222
+ color: var(--nymbal-color-text-muted, #71717a);
223
+ text-align: center;
224
+ }
225
+ [part~='summary'] {
226
+ position: sticky;
227
+ top: 80px;
228
+ padding: var(--nymbal-spacing-lg, 1.5rem);
229
+ background-color: #fafafa;
230
+ border: 1px solid var(--nymbal-color-border, #e4e4e7);
231
+ border-radius: var(--nymbal-radius-lg, 0.75rem);
232
+ }
233
+ [part~='summary-title'] {
234
+ margin: 0 0 var(--nymbal-spacing-md, 1rem);
235
+ padding-bottom: var(--nymbal-spacing-md, 1rem);
236
+ font-size: var(--nymbal-font-size-lg, 1.125rem);
237
+ font-weight: var(--nymbal-font-weight-bold, 700);
238
+ color: var(--nymbal-color-primary, #18181b);
239
+ border-bottom: 1px solid var(--nymbal-color-border, #e4e4e7);
240
+ }
241
+ [part~='items'] {
242
+ display: flex;
243
+ flex-direction: column;
244
+ gap: var(--nymbal-spacing-sm, 0.5rem);
245
+ margin-bottom: var(--nymbal-spacing-md, 1rem);
246
+ }
247
+ [part~='item'] {
248
+ display: flex;
249
+ justify-content: space-between;
250
+ align-items: start;
251
+ gap: var(--nymbal-spacing-sm, 0.5rem);
252
+ font-size: var(--nymbal-font-size-sm, 0.875rem);
253
+ }
254
+ [part~='item-name'] {
255
+ flex: 1;
256
+ min-width: 0;
257
+ }
258
+ [part~='item-variant'],
259
+ [part~='item-qty'] {
260
+ flex-shrink: 0;
261
+ color: var(--nymbal-color-text-muted, #71717a);
262
+ }
263
+ [part~='item-price'] {
264
+ flex-shrink: 0;
265
+ font-weight: var(--nymbal-font-weight-medium, 500);
266
+ }
267
+ dl {
268
+ margin: 0;
269
+ }
270
+ dd {
271
+ margin: 0;
272
+ font-weight: var(--nymbal-font-weight-medium, 500);
273
+ }
274
+ [part~='summary-row'] {
275
+ display: flex;
276
+ justify-content: space-between;
277
+ padding: var(--nymbal-spacing-xs, 0.25rem) 0;
278
+ font-size: var(--nymbal-font-size-sm, 0.875rem);
279
+ }
280
+ [part~='summary-row'] dt {
281
+ color: var(--nymbal-color-text-muted, #71717a);
282
+ }
283
+ [part~='total'] {
284
+ display: flex;
285
+ justify-content: space-between;
286
+ margin-top: var(--nymbal-spacing-sm, 0.5rem);
287
+ padding-top: var(--nymbal-spacing-md, 1rem);
288
+ font-size: var(--nymbal-font-size-lg, 1.125rem);
289
+ font-weight: var(--nymbal-font-weight-bold, 700);
290
+ color: var(--nymbal-color-primary, #18181b);
291
+ border-top: 1px solid var(--nymbal-color-border, #e4e4e7);
292
+ }
293
+ `
294
+ ];
295
+ step = "contact";
296
+ error = null;
297
+ billingSame = true;
298
+ placing = false;
299
+ placed = false;
300
+ /** True from a step change until the next animation frame (Decision 4's multi-click rule). */
301
+ stepChanging = false;
302
+ stepTurn = 0;
303
+ heightRelease;
304
+ stores() {
305
+ return [this.client.cart];
306
+ }
307
+ storeSettled() {
308
+ this.cart = void 0;
309
+ }
310
+ connectedCallback() {
311
+ super.connectedCallback();
312
+ this.addEventListener("nymbal:payment:status", this.onPaymentStatus);
313
+ }
314
+ disconnectedCallback() {
315
+ super.disconnectedCallback();
316
+ this.removeEventListener("nymbal:payment:status", this.onPaymentStatus);
317
+ this.releaseMainHeight();
318
+ }
319
+ onPaymentStatus = () => this.requestUpdate();
320
+ paymentElement() {
321
+ return this.querySelector("nymbal-payment-element");
322
+ }
323
+ /**
324
+ * Read at each render, so a status the child reached during its own upgrade, before this listened, still holds.
325
+ * Without a client (a server render) there is no light DOM to read, and no order to place.
326
+ */
327
+ paymentBlocked() {
328
+ return this.readsStores && this.paymentElement()?.status === "error";
329
+ }
330
+ addressForm(prefix) {
331
+ return this.renderRoot.querySelector(
332
+ `nymbal-address-form[id-prefix="${prefix}"]`
333
+ );
334
+ }
335
+ go(step) {
336
+ this.holdMainHeight();
337
+ this.step = step;
338
+ this.error = null;
339
+ this.stepChanging = true;
340
+ const turn = ++this.stepTurn;
341
+ requestAnimationFrame(() => {
342
+ if (turn === this.stepTurn) this.stepChanging = false;
343
+ });
344
+ this.requestUpdate();
345
+ }
346
+ /**
347
+ * Keeps the main column at least as tall as the step it replaces until a double click is over. A shorter next step
348
+ * would shorten the page under a still cursor, and the second click would land on whatever rose there (a footer
349
+ * link), outside this element, where neither multi-click guard sees it. Released after 600 ms, past the 500 ms an OS
350
+ * allows between the two clicks of a double click, so the column then settles to the shown step's own height.
351
+ */
352
+ holdMainHeight() {
353
+ const main = this.renderRoot.querySelector("[part~='main']");
354
+ if (main === null) return;
355
+ const height = main.offsetHeight;
356
+ if (height > (Number.parseFloat(main.style.minHeight) || 0))
357
+ main.style.minHeight = `${height}px`;
358
+ clearTimeout(this.heightRelease);
359
+ this.heightRelease = setTimeout(() => this.releaseMainHeight(), STEP_HEIGHT_HOLD_MS);
360
+ }
361
+ releaseMainHeight() {
362
+ clearTimeout(this.heightRelease);
363
+ this.heightRelease = void 0;
364
+ const main = this.renderRoot.querySelector("[part~='main']");
365
+ if (main !== null) main.style.minHeight = "";
366
+ }
367
+ showError(message) {
368
+ this.error = message;
369
+ this.requestUpdate();
370
+ }
371
+ /**
372
+ * Whether a submit of `step`'s form goes ahead. The step setters are synchronous, so by a double click's second
373
+ * click the next step has rendered under the cursor: a submit in the frame of a step change is not the shopper's.
374
+ */
375
+ accepts(event, step) {
376
+ event.preventDefault();
377
+ return this.step === step && !this.stepChanging;
378
+ }
379
+ /** The second click of a multi-click is not a decision to continue or to pay; the first one already submitted. */
380
+ onSubmitClick = (event) => {
381
+ if (event.detail > 1) event.preventDefault();
382
+ };
383
+ onContact = (event) => {
384
+ if (!this.accepts(event, "contact")) return;
385
+ const email = this.renderRoot.querySelector("#contact-email")?.value.trim() ?? "";
386
+ if (email === "") return this.showError("Please enter your email address.");
387
+ this.client.checkout.setEmail(email);
388
+ this.go("shipping");
389
+ };
390
+ onShipping = (event) => {
391
+ if (!this.accepts(event, "shipping")) return;
392
+ const form = this.addressForm("shipping");
393
+ if (form === null || !form.reportValidity()) return;
394
+ this.client.checkout.setShippingAddress(form.value);
395
+ this.client.checkout.setShippingMethod({
396
+ carrier: "Standard",
397
+ service: "Standard Shipping",
398
+ amountMinor: 0,
399
+ currency: this.client.cart.getState().currency || "GBP",
400
+ estimatedDays: 5
401
+ });
402
+ this.go("payment");
403
+ };
404
+ billingAddress() {
405
+ if (this.billingSame) return this.client.checkout.getState().shippingAddress;
406
+ const form = this.addressForm("billing");
407
+ if (form === null || !form.reportValidity()) return null;
408
+ return form.value;
409
+ }
410
+ onPlace = (event) => {
411
+ if (!this.accepts(event, "payment")) return;
412
+ if (this.placing || this.placed || this.paymentBlocked()) return;
413
+ const billing = this.billingAddress();
414
+ if (billing === null) return;
415
+ this.placing = true;
416
+ this.error = null;
417
+ this.requestUpdate();
418
+ void this.place(billing);
419
+ };
420
+ /** Calls the SDK before its first `await`, so the in-flight flag set by the caller covers the order request. */
421
+ async place(billing) {
422
+ const checkout = this.client.checkout;
423
+ try {
424
+ checkout.setBillingAddress(billing);
425
+ const result = await checkout.submitPayment();
426
+ if (result === null) {
427
+ const { placedOrderNumber, error } = checkout.getState();
428
+ if (placedOrderNumber) return this.leaveFor(placedOrderNumber);
429
+ return this.stay(error ?? PAYMENT_FAILED);
430
+ }
431
+ if (result.payment.status === "failed") {
432
+ return this.stay(checkout.getState().error ?? PAYMENT_FAILED);
433
+ }
434
+ if (result.payment.status === "requires_action") {
435
+ const { email, billingAddress } = checkout.getState();
436
+ const confirmation = await this.confirm(result.paymentIntent.clientSecret, {
437
+ ...email !== "" && { email },
438
+ ...billingAddress !== null && { billing: billingAddress }
439
+ });
440
+ if (!confirmation.ok) return this.stay(confirmation.error);
441
+ if (confirmation.confirmed) checkout.markConfirmed();
442
+ }
443
+ this.leaveFor(result.orderNumber);
444
+ } catch (err) {
445
+ this.stay(err instanceof Error && err.message !== "" ? err.message : PAYMENT_FAILED);
446
+ }
447
+ }
448
+ confirm(clientSecret, context) {
449
+ return this.paymentElement()?.confirm(clientSecret, context) ?? Promise.resolve(NO_PAYMENT_STEP);
450
+ }
451
+ stay(message) {
452
+ this.placing = false;
453
+ this.showError(message);
454
+ }
455
+ /** Place Order stays disabled from here through the page's navigation. */
456
+ leaveFor(orderNumber) {
457
+ this.client.checkout.reset();
458
+ this.placing = false;
459
+ this.placed = true;
460
+ this.requestUpdate();
461
+ this.dispatchEvent(
462
+ new CustomEvent("nymbal:checkout:placed", {
463
+ bubbles: true,
464
+ composed: true,
465
+ detail: { orderNumber }
466
+ })
467
+ );
468
+ }
469
+ onBillingSame = (event) => {
470
+ this.billingSame = event.target.checked;
471
+ this.requestUpdate();
472
+ };
473
+ back(step) {
474
+ return () => {
475
+ if (!this.placing && !this.placed) this.go(step);
476
+ };
477
+ }
478
+ renderSteps() {
479
+ const current = STEPS.indexOf(this.step);
480
+ return html`
481
+ <div part="steps" data-testid="checkout-steps">
482
+ ${STEPS.map((step, index) => {
483
+ const state = index < current ? " step-done" : index === current ? " step-active" : "";
484
+ return html`
485
+ ${index > 0 ? html`<div
486
+ part="step-divider${index <= current ? " step-divider-done" : ""}"
487
+ aria-hidden="true"
488
+ ></div>` : nothing}
489
+ <div
490
+ part="step${state}"
491
+ data-testid="checkout-step-${step}"
492
+ aria-current=${index === current ? "step" : nothing}
493
+ >
494
+ <span>${STEP_LABELS[step]}</span>
495
+ </div>
496
+ `;
497
+ })}
498
+ </div>
499
+ `;
500
+ }
501
+ renderContact() {
502
+ return html`
503
+ <section part="section" data-testid="checkout-contact" ?hidden=${this.step !== "contact"}>
504
+ <form part="form" @submit=${this.onContact}>
505
+ <h2 part="section-title">Contact Information</h2>
506
+ ${renderField({
507
+ id: "contact-email",
508
+ name: "email",
509
+ label: "Email Address",
510
+ type: "email",
511
+ autocomplete: "email",
512
+ required: true,
513
+ placeholder: "you@example.com"
514
+ })}
515
+ <div part="actions">
516
+ <button
517
+ type="submit"
518
+ part="submit"
519
+ class="btn btn-primary"
520
+ data-testid="contact-continue"
521
+ @click=${this.onSubmitClick}
522
+ >
523
+ <slot name="contact-continue-label">Continue to Shipping</slot>
524
+ </button>
525
+ </div>
526
+ </form>
527
+ </section>
528
+ `;
529
+ }
530
+ renderShipping() {
531
+ return html`
532
+ <section part="section" data-testid="checkout-shipping" ?hidden=${this.step !== "shipping"}>
533
+ <form part="form" novalidate @submit=${this.onShipping}>
534
+ <h2 part="section-title">Shipping Address</h2>
535
+ <nymbal-address-form id-prefix="shipping" data-testid="shipping-form"></nymbal-address-form>
536
+ <div part="actions">
537
+ <button type="button" part="back" class="btn btn-secondary" @click=${this.back("contact")}>
538
+ Back
539
+ </button>
540
+ <button
541
+ type="submit"
542
+ part="submit"
543
+ class="btn btn-primary"
544
+ data-testid="shipping-continue"
545
+ @click=${this.onSubmitClick}
546
+ >
547
+ <slot name="shipping-continue-label">Continue to Payment</slot>
548
+ </button>
549
+ </div>
550
+ </form>
551
+ </section>
552
+ `;
553
+ }
554
+ renderPayment() {
555
+ const busy = this.placing || this.placed;
556
+ return html`
557
+ <section part="section" data-testid="checkout-payment" ?hidden=${this.step !== "payment"}>
558
+ <form part="form" novalidate @submit=${this.onPlace}>
559
+ <h2 part="section-title">Payment</h2>
560
+ <label part="billing-same">
561
+ <input
562
+ type="checkbox"
563
+ id="billing-same"
564
+ data-testid="billing-same"
565
+ .checked=${this.billingSame}
566
+ @change=${this.onBillingSame}
567
+ />
568
+ Billing address same as shipping
569
+ </label>
570
+ <div part="billing" data-testid="billing-address" ?hidden=${this.billingSame}>
571
+ <h3 part="billing-title">Billing Address</h3>
572
+ <nymbal-address-form id-prefix="billing"></nymbal-address-form>
573
+ </div>
574
+ <div part="payment"><slot name="payment"></slot></div>
575
+ <div part="actions">
576
+ <button
577
+ type="button"
578
+ part="back"
579
+ class="btn btn-secondary"
580
+ ?disabled=${busy}
581
+ @click=${this.back("shipping")}
582
+ >
583
+ Back
584
+ </button>
585
+ <button
586
+ type="submit"
587
+ part="submit"
588
+ class="btn btn-primary"
589
+ data-testid="place-order"
590
+ ?disabled=${busy || this.paymentBlocked()}
591
+ @click=${this.onSubmitClick}
592
+ >
593
+ ${this.placing ? "Processing..." : html`<slot name="place-order-label">Place Order</slot>`}
594
+ </button>
595
+ </div>
596
+ <p part="terms">
597
+ <slot name="terms">By placing your order, you agree to our terms and conditions.</slot>
598
+ </p>
599
+ </form>
600
+ </section>
601
+ `;
602
+ }
603
+ renderLine(item, currency) {
604
+ return html`
605
+ <div part="item">
606
+ <span part="item-name">${item.productName}</span>
607
+ ${item.variantName ? html`<span part="item-variant">${item.variantName}</span>` : nothing}
608
+ <span part="item-qty">x${item.qty}</span>
609
+ <span part="item-price">${formatPrice(item.priceMinor * item.qty, currency)}</span>
610
+ </div>
611
+ `;
612
+ }
613
+ renderSummary() {
614
+ const cart = shownCart(this, this.cart, this.readsStores ? this.client : null);
615
+ const currency = cart.currency || "GBP";
616
+ const subtotal = formatPrice(cart.subtotalMinor, currency);
617
+ return html`
618
+ <aside part="summary" data-testid="checkout-summary">
619
+ <h2 part="summary-title"><slot name="summary-title">Order Summary</slot></h2>
620
+ ${cart.items.length === 0 ? nothing : html`<div part="items">
621
+ ${cart.items.map((item) => this.renderLine(item, currency))}
622
+ </div>`}
623
+ <dl>
624
+ <div part="summary-row subtotal">
625
+ <dt>Subtotal</dt>
626
+ <dd data-testid="cart-subtotal">${subtotal}</dd>
627
+ </div>
628
+ <div part="summary-row">
629
+ <dt>Shipping</dt>
630
+ <dd>Standard, free</dd>
631
+ </div>
632
+ </dl>
633
+ <div part="total">
634
+ <span>Total</span>
635
+ <span>${subtotal}</span>
636
+ </div>
637
+ </aside>
638
+ `;
639
+ }
640
+ render() {
641
+ return html`
642
+ <h1 part="title"><slot name="title">Checkout</slot></h1>
643
+ ${this.renderSteps()}
644
+ ${this.error === null ? nothing : html`<div part="error" role="alert" data-testid="checkout-error">${this.error}</div>`}
645
+ <div part="layout">
646
+ <div part="main">${this.renderContact()} ${this.renderShipping()} ${this.renderPayment()}</div>
647
+ ${this.renderSummary()}
648
+ </div>
649
+ `;
650
+ }
651
+ };
652
+
653
+ export {
654
+ NymbalCheckout
655
+ };
656
+ //# sourceMappingURL=chunk-6XCCAAMF.js.map