@nevios/storefront-kit 0.1.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/dist/index.js ADDED
@@ -0,0 +1,2979 @@
1
+ import * as React10 from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { imageSrcSet } from '@nevios/storefront-js';
4
+
5
+ // src/provider.tsx
6
+ var StorefrontContext = React10.createContext(null);
7
+ function NeviosProvider({ client, children }) {
8
+ return /* @__PURE__ */ jsx(StorefrontContext.Provider, { value: client, children });
9
+ }
10
+ function useStorefront() {
11
+ const client = React10.useContext(StorefrontContext);
12
+ if (!client) {
13
+ throw new Error(
14
+ "useStorefront must be used inside <NeviosProvider>. Wrap your app root with it."
15
+ );
16
+ }
17
+ return client;
18
+ }
19
+ function useStorefrontOptional() {
20
+ return React10.useContext(StorefrontContext);
21
+ }
22
+ var DEFAULTS = {
23
+ brand: "#111111",
24
+ brandForeground: "#ffffff",
25
+ background: "#ffffff",
26
+ foreground: "#111111",
27
+ muted: "#6b7280",
28
+ border: "rgba(0,0,0,0.1)",
29
+ radius: "12px",
30
+ fontFamily: "system-ui, sans-serif"
31
+ };
32
+ var TOKEN_VAR = {
33
+ brand: "--nv-brand",
34
+ brandForeground: "--nv-brand-foreground",
35
+ background: "--nv-bg",
36
+ foreground: "--nv-fg",
37
+ muted: "--nv-muted",
38
+ border: "--nv-border",
39
+ radius: "--nv-radius",
40
+ fontFamily: "--nv-font"
41
+ };
42
+ function themeToCssVars(theme = {}) {
43
+ const merged = { ...DEFAULTS, ...theme };
44
+ const vars = {};
45
+ for (const key of Object.keys(TOKEN_VAR)) {
46
+ vars[TOKEN_VAR[key]] = merged[key];
47
+ }
48
+ return vars;
49
+ }
50
+ function ThemeProvider({
51
+ theme,
52
+ children,
53
+ as: Tag = "div"
54
+ }) {
55
+ const style = themeToCssVars(theme);
56
+ return React10.createElement(
57
+ Tag,
58
+ { "data-nevios-theme": "", style },
59
+ children
60
+ );
61
+ }
62
+
63
+ // src/i18n/en.ts
64
+ var en = {
65
+ // common
66
+ "common.free": "Free",
67
+ "common.close": "Close",
68
+ "common.loadingShort": "\u2026",
69
+ // catalog
70
+ "catalog.addToCart": "Add to cart",
71
+ "catalog.noProducts": "No products yet.",
72
+ "catalog.soldOut": "Sold out",
73
+ "catalog.addError": "Couldn't add to cart. Please try again.",
74
+ "catalog.inStock": "In stock",
75
+ "catalog.preorder": "Pre-order",
76
+ // catalog — filters + sort
77
+ "catalog.filters.sort": "Sort by",
78
+ "catalog.filters.sortNewest": "Newest",
79
+ "catalog.filters.sortOldest": "Oldest",
80
+ "catalog.filters.sortTitleAsc": "Name: A\u2013Z",
81
+ "catalog.filters.sortTitleDesc": "Name: Z\u2013A",
82
+ "catalog.filters.sortPriceAsc": "Price: low to high",
83
+ "catalog.filters.sortPriceDesc": "Price: high to low",
84
+ "catalog.filters.priceRange": "Price",
85
+ "catalog.filters.min": "Min",
86
+ "catalog.filters.max": "Max",
87
+ "catalog.filters.tags": "Tags",
88
+ "catalog.filters.inStockOnly": "In stock only",
89
+ "catalog.filters.clear": "Clear filters",
90
+ // catalog — back in stock
91
+ "catalog.backInStock.prompt": "Out of stock \u2014 we'll email you when it's back.",
92
+ "catalog.backInStock.email": "Email",
93
+ "catalog.backInStock.notify": "Notify me",
94
+ "catalog.backInStock.success": "Done \u2014 we'll email you when it's back in stock.",
95
+ "catalog.backInStock.error": "Couldn't subscribe. Please try again.",
96
+ // cart
97
+ "cart.title": "Cart",
98
+ "cart.empty": "Your cart is empty.",
99
+ "cart.remove": "Remove",
100
+ "cart.increaseQty": "Increase quantity",
101
+ "cart.decreaseQty": "Decrease quantity",
102
+ "cart.checkout": "Checkout",
103
+ "cart.subtotal": "Subtotal",
104
+ "cart.tax": "Tax",
105
+ "cart.total": "Total",
106
+ // shared totals (checkout + order)
107
+ "totals.subtotal": "Subtotal",
108
+ "totals.discount": "Discount",
109
+ "totals.shipping": "Shipping",
110
+ "totals.paymentFee": "Payment fee",
111
+ "totals.taxIncluded": "Tax included",
112
+ "totals.total": "Total",
113
+ // checkout — steps + states
114
+ "checkout.stepAddress": "Address",
115
+ "checkout.stepShipping": "Shipping",
116
+ "checkout.stepPayment": "Payment",
117
+ "checkout.loading": "Loading checkout\u2026",
118
+ "checkout.empty": "Your checkout is empty.",
119
+ // checkout — address form
120
+ "checkout.shippingAddress": "Shipping address",
121
+ "checkout.continueToShipping": "Continue to shipping",
122
+ "checkout.email": "Email",
123
+ "checkout.firstName": "First name",
124
+ "checkout.lastName": "Last name",
125
+ "checkout.company": "Company (optional)",
126
+ "checkout.address": "Address",
127
+ "checkout.apartment": "Apartment, suite, etc. (optional)",
128
+ "checkout.city": "City",
129
+ "checkout.postalCode": "Postal code",
130
+ "checkout.country": "Country",
131
+ "checkout.phone": "Phone (optional)",
132
+ // checkout — shipping
133
+ "checkout.shippingMethod": "Shipping method",
134
+ "checkout.continueToPayment": "Continue to payment",
135
+ "checkout.loadingShipping": "Loading shipping options\u2026",
136
+ "checkout.noShipping": "No shipping options for this address.",
137
+ // checkout — payment
138
+ "checkout.payment": "Payment",
139
+ "checkout.loadingPayment": "Loading payment options\u2026",
140
+ "checkout.noPayment": "No payment methods available.",
141
+ "checkout.payNow": "Pay now",
142
+ "checkout.placeOrder": "Place order",
143
+ "checkout.gatewayRedirectNote": "You'll be redirected to complete payment securely.",
144
+ // checkout — confirmation
145
+ "checkout.thankYou": "Thank you for your order!",
146
+ "checkout.orderPlacedBody": "Your order {order} has been placed. A confirmation has been sent to {email}.",
147
+ // shipping estimate (pluralized)
148
+ "shipping.days.one": "{count} day",
149
+ "shipping.days.few": "{count} days",
150
+ "shipping.days.many": "{count} days",
151
+ "shipping.days.other": "{count} days",
152
+ "shipping.daysRange": "{min}\u2013{max} days",
153
+ // order — status page + confirmation
154
+ "order.title": "Order {number}",
155
+ "order.placedOn": "Placed {date}",
156
+ "order.loading": "Loading order\u2026",
157
+ "order.loadError": "Couldn't load this order.",
158
+ "order.notFound": "Order not found.",
159
+ "order.confirmLoading": "Loading your order\u2026",
160
+ "order.confirmLoadError": "Couldn't load your order.",
161
+ "order.confirmed": "Order {number} is confirmed.",
162
+ "order.items": "Items",
163
+ "order.shipping": "Shipping",
164
+ "order.shipsTo": "Ships to",
165
+ "order.tracking": "Tracking",
166
+ "order.payment": "Payment",
167
+ "order.method": "Method",
168
+ "order.status": "Status",
169
+ "order.downloadInvoice": "Download invoice",
170
+ "order.contactSupport": "Contact support",
171
+ "order.trackOrder": "Track your order",
172
+ // order — happy-path milestones
173
+ "order.phase.placed": "Placed",
174
+ "order.phase.paid": "Paid",
175
+ "order.phase.fulfilled": "Fulfilled",
176
+ "order.phase.shipped": "Shipped",
177
+ "order.phase.delivered": "Delivered",
178
+ // order — terminal banners
179
+ "order.terminal.cancelled": "This order was cancelled.",
180
+ "order.terminal.refunded": "This order was refunded.",
181
+ "order.terminal.returned": "This order was returned.",
182
+ // error pages
183
+ "error.notFound.title": "Page not found",
184
+ "error.notFound.body": "This page doesn't exist or isn't available in your region.",
185
+ "error.generic.title": "Something went wrong",
186
+ "error.generic.body": "Please try again in a moment.",
187
+ "error.home": "Back to home",
188
+ // account
189
+ "account.title": "Your account",
190
+ "account.signIn": "Sign in",
191
+ "account.signInBlurb": "Enter your email and we'll send you a sign-in link.",
192
+ "account.email": "Email",
193
+ "account.sendLink": "Send sign-in link",
194
+ "account.checkEmail": "Check your email for a sign-in link.",
195
+ "account.signOut": "Sign out",
196
+ "account.greeting": "Signed in as {email}",
197
+ "account.orders": "Your orders",
198
+ "account.noOrders": "No orders yet.",
199
+ "account.addresses": "Saved addresses",
200
+ "account.noAddresses": "No saved addresses yet.",
201
+ "account.viewOrder": "View order",
202
+ "account.verifying": "Signing you in\u2026",
203
+ "account.verifyError": "This sign-in link is invalid or has expired.",
204
+ "account.openDevLink": "Open sign-in link (dev)",
205
+ // account — profile + address editing + reorder (write ops)
206
+ "account.profile": "Profile",
207
+ "account.editProfile": "Edit profile",
208
+ "account.firstName": "First name",
209
+ "account.lastName": "Last name",
210
+ "account.phone": "Phone",
211
+ "account.acceptsMarketing": "Email me about news and offers",
212
+ "account.save": "Save",
213
+ "account.cancel": "Cancel",
214
+ "account.saved": "Saved.",
215
+ "account.saveError": "Couldn't save. Please try again.",
216
+ "account.addAddress": "Add address",
217
+ "account.editAddress": "Edit",
218
+ "account.deleteAddress": "Delete",
219
+ "account.confirmDelete": "Delete this address?",
220
+ "account.setDefault": "Set as default",
221
+ "account.default": "Default",
222
+ "account.company": "Company",
223
+ "account.address": "Address",
224
+ "account.addressLine2": "Apartment, suite, etc.",
225
+ "account.city": "City",
226
+ "account.postalCode": "Postal code",
227
+ "account.country": "Country (2-letter code)",
228
+ "account.reorder": "Buy again",
229
+ "account.reorderDone": "Added {added} item(s) to your cart.",
230
+ "account.reorderPartial": "Added {added}, skipped {skipped} unavailable item(s).",
231
+ "account.reorderError": "Couldn't reorder. Please try again."
232
+ };
233
+
234
+ // src/i18n/cs.ts
235
+ var cs = {
236
+ "common.free": "Zdarma",
237
+ "common.close": "Zav\u0159\xEDt",
238
+ "common.loadingShort": "\u2026",
239
+ "catalog.addToCart": "P\u0159idat do ko\u0161\xEDku",
240
+ "catalog.noProducts": "Zat\xEDm \u017E\xE1dn\xE9 produkty.",
241
+ "catalog.soldOut": "Vyprod\xE1no",
242
+ "catalog.addError": "Nepoda\u0159ilo se p\u0159idat do ko\u0161\xEDku. Zkuste to znovu.",
243
+ "catalog.inStock": "Skladem",
244
+ "catalog.preorder": "P\u0159edobjedn\xE1vka",
245
+ "catalog.filters.sort": "\u0158adit podle",
246
+ "catalog.filters.sortNewest": "Nejnov\u011Bj\u0161\xED",
247
+ "catalog.filters.sortOldest": "Nejstar\u0161\xED",
248
+ "catalog.filters.sortTitleAsc": "N\xE1zev: A\u2013Z",
249
+ "catalog.filters.sortTitleDesc": "N\xE1zev: Z\u2013A",
250
+ "catalog.filters.sortPriceAsc": "Cena: od nejni\u017E\u0161\xED",
251
+ "catalog.filters.sortPriceDesc": "Cena: od nejvy\u0161\u0161\xED",
252
+ "catalog.filters.priceRange": "Cena",
253
+ "catalog.filters.min": "Od",
254
+ "catalog.filters.max": "Do",
255
+ "catalog.filters.tags": "\u0160t\xEDtky",
256
+ "catalog.filters.inStockOnly": "Pouze skladem",
257
+ "catalog.filters.clear": "Zru\u0161it filtry",
258
+ "catalog.backInStock.prompt": "Vyprod\xE1no \u2014 d\xE1me v\xE1m e-mailem v\u011Bd\u011Bt, a\u017E bude zp\u011Bt.",
259
+ "catalog.backInStock.email": "E-mail",
260
+ "catalog.backInStock.notify": "Upozornit m\u011B",
261
+ "catalog.backInStock.success": "Hotovo \u2014 d\xE1me v\xE1m v\u011Bd\u011Bt, a\u017E bude zbo\u017E\xED skladem.",
262
+ "catalog.backInStock.error": "P\u0159ihl\xE1\u0161en\xED se nezda\u0159ilo. Zkuste to znovu.",
263
+ "cart.title": "Ko\u0161\xEDk",
264
+ "cart.empty": "V\xE1\u0161 ko\u0161\xEDk je pr\xE1zdn\xFD.",
265
+ "cart.remove": "Odebrat",
266
+ "cart.increaseQty": "Zv\xFD\u0161it mno\u017Estv\xED",
267
+ "cart.decreaseQty": "Sn\xED\u017Eit mno\u017Estv\xED",
268
+ "cart.checkout": "K pokladn\u011B",
269
+ "cart.subtotal": "Mezisou\u010Det",
270
+ "cart.tax": "DPH",
271
+ "cart.total": "Celkem",
272
+ "totals.subtotal": "Mezisou\u010Det",
273
+ "totals.discount": "Sleva",
274
+ "totals.shipping": "Doprava",
275
+ "totals.paymentFee": "Poplatek za platbu",
276
+ "totals.taxIncluded": "V\u010Detn\u011B DPH",
277
+ "totals.total": "Celkem",
278
+ "checkout.stepAddress": "Adresa",
279
+ "checkout.stepShipping": "Doprava",
280
+ "checkout.stepPayment": "Platba",
281
+ "checkout.loading": "Na\u010D\xEDt\xE1n\xED pokladny\u2026",
282
+ "checkout.empty": "Va\u0161e pokladna je pr\xE1zdn\xE1.",
283
+ "checkout.shippingAddress": "Dodac\xED adresa",
284
+ "checkout.continueToShipping": "Pokra\u010Dovat k doprav\u011B",
285
+ "checkout.email": "E-mail",
286
+ "checkout.firstName": "Jm\xE9no",
287
+ "checkout.lastName": "P\u0159\xEDjmen\xED",
288
+ "checkout.company": "Firma (nepovinn\xE9)",
289
+ "checkout.address": "Adresa",
290
+ "checkout.apartment": "Byt, patro apod. (nepovinn\xE9)",
291
+ "checkout.city": "M\u011Bsto",
292
+ "checkout.postalCode": "PS\u010C",
293
+ "checkout.country": "Zem\u011B",
294
+ "checkout.phone": "Telefon (nepovinn\xE9)",
295
+ "checkout.shippingMethod": "Zp\u016Fsob dopravy",
296
+ "checkout.continueToPayment": "Pokra\u010Dovat k platb\u011B",
297
+ "checkout.loadingShipping": "Na\u010D\xEDt\xE1n\xED mo\u017Enost\xED dopravy\u2026",
298
+ "checkout.noShipping": "Pro tuto adresu nejsou \u017E\xE1dn\xE9 mo\u017Enosti dopravy.",
299
+ "checkout.payment": "Platba",
300
+ "checkout.loadingPayment": "Na\u010D\xEDt\xE1n\xED platebn\xEDch metod\u2026",
301
+ "checkout.noPayment": "\u017D\xE1dn\xE9 platebn\xED metody nejsou k dispozici.",
302
+ "checkout.payNow": "Zaplatit",
303
+ "checkout.placeOrder": "Odeslat objedn\xE1vku",
304
+ "checkout.gatewayRedirectNote": "Budete p\u0159esm\u011Brov\xE1ni k bezpe\u010Dn\xE9mu dokon\u010Den\xED platby.",
305
+ "checkout.thankYou": "D\u011Bkujeme za va\u0161i objedn\xE1vku!",
306
+ "checkout.orderPlacedBody": "Va\u0161e objedn\xE1vka {order} byla p\u0159ijata. Potvrzen\xED jsme odeslali na {email}.",
307
+ "shipping.days.one": "{count} den",
308
+ "shipping.days.few": "{count} dny",
309
+ "shipping.days.many": "{count} dne",
310
+ "shipping.days.other": "{count} dn\xED",
311
+ "shipping.daysRange": "{min}\u2013{max} dn\xED",
312
+ "order.title": "Objedn\xE1vka {number}",
313
+ "order.placedOn": "Vytvo\u0159eno {date}",
314
+ "order.loading": "Na\u010D\xEDt\xE1n\xED objedn\xE1vky\u2026",
315
+ "order.loadError": "Objedn\xE1vku se nepoda\u0159ilo na\u010D\xEDst.",
316
+ "order.notFound": "Objedn\xE1vka nenalezena.",
317
+ "order.confirmLoading": "Na\u010D\xEDt\xE1n\xED va\u0161\xED objedn\xE1vky\u2026",
318
+ "order.confirmLoadError": "Va\u0161i objedn\xE1vku se nepoda\u0159ilo na\u010D\xEDst.",
319
+ "order.confirmed": "Objedn\xE1vka {number} je potvrzena.",
320
+ "order.items": "Polo\u017Eky",
321
+ "order.shipping": "Doprava",
322
+ "order.shipsTo": "Doru\u010Den\xED do",
323
+ "order.tracking": "Sledov\xE1n\xED",
324
+ "order.payment": "Platba",
325
+ "order.method": "Metoda",
326
+ "order.status": "Stav",
327
+ "order.downloadInvoice": "St\xE1hnout fakturu",
328
+ "order.contactSupport": "Kontaktovat podporu",
329
+ "order.trackOrder": "Sledovat objedn\xE1vku",
330
+ "order.phase.placed": "P\u0159ijato",
331
+ "order.phase.paid": "Zaplaceno",
332
+ "order.phase.fulfilled": "P\u0159ipraveno",
333
+ "order.phase.shipped": "Odesl\xE1no",
334
+ "order.phase.delivered": "Doru\u010Deno",
335
+ "order.terminal.cancelled": "Tato objedn\xE1vka byla zru\u0161ena.",
336
+ "order.terminal.refunded": "Tato objedn\xE1vka byla refundov\xE1na.",
337
+ "order.terminal.returned": "Tato objedn\xE1vka byla vr\xE1cena.",
338
+ "error.notFound.title": "Str\xE1nka nenalezena",
339
+ "error.notFound.body": "Tato str\xE1nka neexistuje nebo nen\xED ve va\u0161em regionu dostupn\xE1.",
340
+ "error.generic.title": "N\u011Bco se pokazilo",
341
+ "error.generic.body": "Zkuste to pros\xEDm za chv\xEDli znovu.",
342
+ "error.home": "Zp\u011Bt na \xFAvod",
343
+ "account.title": "V\xE1\u0161 \xFA\u010Det",
344
+ "account.signIn": "P\u0159ihl\xE1sit se",
345
+ "account.signInBlurb": "Zadejte e-mail a po\u0161leme v\xE1m p\u0159ihla\u0161ovac\xED odkaz.",
346
+ "account.email": "E-mail",
347
+ "account.sendLink": "Poslat p\u0159ihla\u0161ovac\xED odkaz",
348
+ "account.checkEmail": "Zkontrolujte e-mail s p\u0159ihla\u0161ovac\xEDm odkazem.",
349
+ "account.signOut": "Odhl\xE1sit se",
350
+ "account.greeting": "P\u0159ihl\xE1\u0161en jako {email}",
351
+ "account.orders": "Va\u0161e objedn\xE1vky",
352
+ "account.noOrders": "Zat\xEDm \u017E\xE1dn\xE9 objedn\xE1vky.",
353
+ "account.addresses": "Ulo\u017Een\xE9 adresy",
354
+ "account.noAddresses": "Zat\xEDm \u017E\xE1dn\xE9 ulo\u017Een\xE9 adresy.",
355
+ "account.viewOrder": "Zobrazit objedn\xE1vku",
356
+ "account.verifying": "P\u0159ihla\u0161ov\xE1n\xED\u2026",
357
+ "account.verifyError": "P\u0159ihla\u0161ovac\xED odkaz je neplatn\xFD nebo vypr\u0161el.",
358
+ "account.openDevLink": "Otev\u0159\xEDt p\u0159ihla\u0161ovac\xED odkaz (dev)",
359
+ "account.profile": "Profil",
360
+ "account.editProfile": "Upravit profil",
361
+ "account.firstName": "Jm\xE9no",
362
+ "account.lastName": "P\u0159\xEDjmen\xED",
363
+ "account.phone": "Telefon",
364
+ "account.acceptsMarketing": "Pos\xEDlejte mi novinky a nab\xEDdky e-mailem",
365
+ "account.save": "Ulo\u017Eit",
366
+ "account.cancel": "Zru\u0161it",
367
+ "account.saved": "Ulo\u017Eeno.",
368
+ "account.saveError": "Nepoda\u0159ilo se ulo\u017Eit. Zkuste to znovu.",
369
+ "account.addAddress": "P\u0159idat adresu",
370
+ "account.editAddress": "Upravit",
371
+ "account.deleteAddress": "Smazat",
372
+ "account.confirmDelete": "Smazat tuto adresu?",
373
+ "account.setDefault": "Nastavit jako v\xFDchoz\xED",
374
+ "account.default": "V\xFDchoz\xED",
375
+ "account.company": "Spole\u010Dnost",
376
+ "account.address": "Adresa",
377
+ "account.addressLine2": "Byt, patro apod.",
378
+ "account.city": "M\u011Bsto",
379
+ "account.postalCode": "PS\u010C",
380
+ "account.country": "Zem\u011B (dvoup\xEDsmenn\xFD k\xF3d)",
381
+ "account.reorder": "Koupit znovu",
382
+ "account.reorderDone": "P\u0159id\xE1no {added} polo\u017Eek do ko\u0161\xEDku.",
383
+ "account.reorderPartial": "P\u0159id\xE1no {added}, p\u0159esko\u010Deno {skipped} nedostupn\xFDch polo\u017Eek.",
384
+ "account.reorderError": "Objedn\xE1vku se nepoda\u0159ilo zopakovat. Zkuste to znovu."
385
+ };
386
+ var BUNDLED = { en, cs };
387
+ function langOf(locale) {
388
+ return (locale ?? "en").toLowerCase().replace(/_/g, "-").split("-")[0] || "en";
389
+ }
390
+ function bundledMessages(locale) {
391
+ return BUNDLED[langOf(locale)] ?? en;
392
+ }
393
+ var warned = /* @__PURE__ */ new Set();
394
+ function devWarn(message) {
395
+ let dev = false;
396
+ try {
397
+ const proc = globalThis.process;
398
+ dev = !!proc?.env && proc.env.NODE_ENV !== "production";
399
+ } catch {
400
+ dev = false;
401
+ }
402
+ if (dev && !warned.has(message)) {
403
+ warned.add(message);
404
+ console.warn(`[nevios i18n] ${message}`);
405
+ }
406
+ }
407
+ function interpolate(template, vars) {
408
+ if (!vars) return template;
409
+ return template.replace(/\{(\w+)\}/g, (m, k) => k in vars ? String(vars[k]) : m);
410
+ }
411
+ function makeI18n(locale, messages) {
412
+ let plural;
413
+ try {
414
+ plural = new Intl.PluralRules(locale);
415
+ } catch {
416
+ plural = new Intl.PluralRules("en");
417
+ }
418
+ const dict = messages;
419
+ const t = (key, vars) => {
420
+ let template;
421
+ if (vars && typeof vars.count === "number") {
422
+ const cat = plural.select(vars.count);
423
+ template = dict[`${key}.${cat}`] ?? dict[`${key}.other`] ?? dict[key];
424
+ } else {
425
+ template = dict[key];
426
+ }
427
+ if (template == null) {
428
+ devWarn(`missing message key "${String(key)}"`);
429
+ return String(key);
430
+ }
431
+ return interpolate(template, vars);
432
+ };
433
+ return { locale, messages, t };
434
+ }
435
+ var DEFAULT_I18N = makeI18n("en", en);
436
+ var I18nContext = React10.createContext(null);
437
+ function I18nProvider({
438
+ locale,
439
+ messages,
440
+ children
441
+ }) {
442
+ const value = React10.useMemo(() => {
443
+ const lang = langOf(locale);
444
+ if (locale && !(lang in BUNDLED) && !messages) {
445
+ devWarn(
446
+ `no bundled pack for "${locale}" and no \`messages\` override \u2014 the UI falls back to English under <html lang="${locale}">. Pass messages={...}.`
447
+ );
448
+ }
449
+ const base = bundledMessages(locale);
450
+ const merged = messages ? { ...base, ...messages } : base;
451
+ return makeI18n(locale ?? "en", merged);
452
+ }, [locale, messages]);
453
+ return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
454
+ }
455
+ function useI18n() {
456
+ return React10.useContext(I18nContext) ?? DEFAULT_I18N;
457
+ }
458
+ function useT() {
459
+ return useI18n().t;
460
+ }
461
+ var defaultLabel = (m) => m.label ?? (m.name ? `${m.name}${m.currency ? ` (${m.currency})` : ""}` : m.handle);
462
+ function MarketSwitcher({
463
+ markets,
464
+ current,
465
+ hrefFor,
466
+ onSelect,
467
+ renderLabel = defaultLabel,
468
+ "aria-label": ariaLabel = "Market",
469
+ className,
470
+ style
471
+ }) {
472
+ if (!markets || markets.length <= 1) return null;
473
+ function handleChange(e) {
474
+ const m = markets.find((x) => x.handle === e.target.value);
475
+ if (!m) return;
476
+ if (onSelect) {
477
+ onSelect(m);
478
+ } else if (hrefFor && typeof window !== "undefined") {
479
+ window.location.assign(hrefFor(m));
480
+ }
481
+ }
482
+ return /* @__PURE__ */ jsxs(
483
+ "select",
484
+ {
485
+ "aria-label": ariaLabel,
486
+ value: current ?? "",
487
+ onChange: handleChange,
488
+ className,
489
+ style: {
490
+ font: "inherit",
491
+ color: "var(--nv-fg)",
492
+ background: "var(--nv-bg)",
493
+ border: "1px solid var(--nv-border)",
494
+ borderRadius: "var(--nv-radius)",
495
+ padding: "0.4rem 0.6rem",
496
+ cursor: "pointer",
497
+ ...style
498
+ },
499
+ children: [
500
+ current == null ? /* @__PURE__ */ jsx("option", { value: "", disabled: true }) : null,
501
+ markets.map((m) => /* @__PURE__ */ jsx("option", { value: m.handle, children: renderLabel(m) }, m.handle))
502
+ ]
503
+ }
504
+ );
505
+ }
506
+ function formatCents(cents, currency, locale) {
507
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(cents / 100);
508
+ }
509
+ function formatMoney(money, locale) {
510
+ return formatCents(money.amount_cents, money.currency, locale);
511
+ }
512
+ function useFormatLocale(locale) {
513
+ const { locale: ctxLocale } = useI18n();
514
+ return locale ?? ctxLocale;
515
+ }
516
+ function PriceMoney({
517
+ money,
518
+ showCompareAt = true,
519
+ locale
520
+ }) {
521
+ const loc = useFormatLocale(locale);
522
+ const onSale = showCompareAt && money.compare_at_cents != null && money.compare_at_cents > money.amount_cents;
523
+ return /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "baseline", gap: "0.5rem" }, children: [
524
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, color: onSale ? "var(--nv-brand)" : "inherit" }, children: formatMoney(money, loc) }),
525
+ onSale ? /* @__PURE__ */ jsx(
526
+ "span",
527
+ {
528
+ style: {
529
+ color: "var(--nv-muted)",
530
+ textDecoration: "line-through",
531
+ fontSize: "0.875em"
532
+ },
533
+ children: formatMoney({ ...money, amount_cents: money.compare_at_cents }, loc)
534
+ }
535
+ ) : null
536
+ ] });
537
+ }
538
+ var CARD_WIDTHS = [200, 400, 600];
539
+ var CARD_SIZES = "(min-width: 1024px) 25vw, (min-width: 640px) 33vw, 50vw";
540
+ function ProductCard({ product, href, locale }) {
541
+ const image = product.media[0];
542
+ const price = product.variants[0]?.price ?? null;
543
+ const imageBase = useStorefrontOptional()?.imageBase;
544
+ const responsive = image ? imageSrcSet(image, { base: imageBase, widths: CARD_WIDTHS }) : null;
545
+ const inner = /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
546
+ /* @__PURE__ */ jsx(
547
+ "div",
548
+ {
549
+ style: {
550
+ aspectRatio: "1 / 1",
551
+ overflow: "hidden",
552
+ borderRadius: "var(--nv-radius)",
553
+ background: "color-mix(in oklab, var(--nv-muted) 12%, transparent)"
554
+ },
555
+ children: image && responsive ? (
556
+ // eslint-disable-next-line @next/next/no-img-element
557
+ /* @__PURE__ */ jsx(
558
+ "img",
559
+ {
560
+ src: responsive.src || image.url,
561
+ srcSet: responsive.srcSet || void 0,
562
+ sizes: responsive.srcSet ? CARD_SIZES : void 0,
563
+ alt: image.alt ?? product.title,
564
+ loading: "lazy",
565
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
566
+ }
567
+ )
568
+ ) : null
569
+ }
570
+ ),
571
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, lineHeight: 1.3 }, children: product.title }),
572
+ price ? /* @__PURE__ */ jsx(PriceMoney, { money: price, locale }) : null
573
+ ] });
574
+ if (!href) return inner;
575
+ return /* @__PURE__ */ jsx("a", { href, style: { color: "inherit", textDecoration: "none", display: "block" }, children: inner });
576
+ }
577
+ var MAIN_WIDTHS = [600, 800, 1e3];
578
+ var THUMB_WIDTHS = [56, 112];
579
+ function ProductGallery({ media, alt }) {
580
+ const [active, setActive] = React10.useState(0);
581
+ const imageBase = useStorefrontOptional()?.imageBase;
582
+ if (media.length === 0) {
583
+ return /* @__PURE__ */ jsx(
584
+ "div",
585
+ {
586
+ style: {
587
+ aspectRatio: "1 / 1",
588
+ borderRadius: "var(--nv-radius)",
589
+ background: "color-mix(in oklab, var(--nv-muted) 12%, transparent)"
590
+ }
591
+ }
592
+ );
593
+ }
594
+ const main = media[Math.min(active, media.length - 1)];
595
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
596
+ /* @__PURE__ */ jsx(
597
+ "div",
598
+ {
599
+ style: {
600
+ aspectRatio: "1 / 1",
601
+ overflow: "hidden",
602
+ borderRadius: "var(--nv-radius)",
603
+ background: "color-mix(in oklab, var(--nv-muted) 12%, transparent)"
604
+ },
605
+ children: (() => {
606
+ const r = imageSrcSet(main, { base: imageBase, widths: MAIN_WIDTHS });
607
+ return (
608
+ // eslint-disable-next-line @next/next/no-img-element
609
+ /* @__PURE__ */ jsx(
610
+ "img",
611
+ {
612
+ src: r.src || main.url,
613
+ srcSet: r.srcSet || void 0,
614
+ sizes: r.srcSet ? "(min-width: 768px) 600px, 100vw" : void 0,
615
+ alt: main.alt ?? alt ?? "",
616
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
617
+ }
618
+ )
619
+ );
620
+ })()
621
+ }
622
+ ),
623
+ media.length > 1 ? /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "0.5rem", flexWrap: "wrap" }, children: media.map((m, i) => /* @__PURE__ */ jsx(
624
+ "button",
625
+ {
626
+ type: "button",
627
+ onClick: () => setActive(i),
628
+ "aria-label": `Image ${i + 1}`,
629
+ "aria-pressed": i === active,
630
+ style: {
631
+ width: 56,
632
+ height: 56,
633
+ padding: 0,
634
+ cursor: "pointer",
635
+ overflow: "hidden",
636
+ borderRadius: "calc(var(--nv-radius) - 4px)",
637
+ background: "transparent",
638
+ border: i === active ? "2px solid var(--nv-brand)" : "1px solid var(--nv-border)"
639
+ },
640
+ children: (() => {
641
+ const r = imageSrcSet(m, { base: imageBase, widths: THUMB_WIDTHS });
642
+ return (
643
+ // eslint-disable-next-line @next/next/no-img-element
644
+ /* @__PURE__ */ jsx(
645
+ "img",
646
+ {
647
+ src: r.src || m.url,
648
+ srcSet: r.srcSet || void 0,
649
+ sizes: r.srcSet ? "56px" : void 0,
650
+ alt: m.alt ?? "",
651
+ loading: "lazy",
652
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
653
+ }
654
+ )
655
+ );
656
+ })()
657
+ },
658
+ m.url + i
659
+ )) }) : null
660
+ ] });
661
+ }
662
+ function matchVariant(product, selected) {
663
+ return product.variants.find(
664
+ (v) => v.options.length === selected.length && v.options.every((o, i) => o === selected[i])
665
+ ) ?? null;
666
+ }
667
+ function VariantPicker({ product, onChange }) {
668
+ const [selected, setSelected] = React10.useState(
669
+ () => product.variants[0]?.options ?? []
670
+ );
671
+ React10.useEffect(() => {
672
+ onChange?.(matchVariant(product, selected));
673
+ }, [product, selected]);
674
+ if (product.options.length === 0) return null;
675
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: product.options.map((opt, optIndex) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
676
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, fontSize: "0.875em" }, children: opt.name }),
677
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "0.5rem", flexWrap: "wrap" }, children: opt.values.map((value) => {
678
+ const isActive = selected[optIndex] === value;
679
+ return /* @__PURE__ */ jsx(
680
+ "button",
681
+ {
682
+ type: "button",
683
+ "aria-pressed": isActive,
684
+ onClick: () => setSelected((prev) => {
685
+ const next = [...prev];
686
+ next[optIndex] = value;
687
+ return next;
688
+ }),
689
+ style: {
690
+ cursor: "pointer",
691
+ padding: "0.4rem 0.85rem",
692
+ borderRadius: "var(--nv-radius)",
693
+ font: "inherit",
694
+ background: isActive ? "var(--nv-brand)" : "transparent",
695
+ color: isActive ? "var(--nv-brand-foreground)" : "var(--nv-fg)",
696
+ border: isActive ? "1px solid var(--nv-brand)" : "1px solid var(--nv-border)"
697
+ },
698
+ children: value
699
+ },
700
+ value
701
+ );
702
+ }) })
703
+ ] }, opt.name)) });
704
+ }
705
+ function BackInStockForm({
706
+ variant,
707
+ defaultEmail = "",
708
+ onSuccess
709
+ }) {
710
+ const t = useT();
711
+ const client = useStorefront();
712
+ const [email, setEmail] = React10.useState(defaultEmail);
713
+ const [state, setState] = React10.useState("idle");
714
+ if (!variant || variant.availability?.status !== "out_of_stock") return null;
715
+ async function submit(e) {
716
+ e.preventDefault();
717
+ if (!variant || !email.trim()) return;
718
+ setState("submitting");
719
+ try {
720
+ await client.catalog.inventory.subscribe(variant.id, email.trim());
721
+ setState("success");
722
+ onSuccess?.();
723
+ } catch {
724
+ setState("error");
725
+ }
726
+ }
727
+ if (state === "success") {
728
+ return /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)", fontSize: "0.875rem" }, children: t("catalog.backInStock.success") });
729
+ }
730
+ return /* @__PURE__ */ jsxs("form", { onSubmit: submit, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
731
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)", fontSize: "0.875rem" }, children: t("catalog.backInStock.prompt") }),
732
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem", flexWrap: "wrap" }, children: [
733
+ /* @__PURE__ */ jsx(
734
+ "input",
735
+ {
736
+ type: "email",
737
+ required: true,
738
+ value: email,
739
+ onChange: (e) => setEmail(e.target.value),
740
+ placeholder: t("catalog.backInStock.email"),
741
+ "aria-label": t("catalog.backInStock.email"),
742
+ style: {
743
+ font: "inherit",
744
+ flex: 1,
745
+ minWidth: "12rem",
746
+ padding: "0.6rem 0.75rem",
747
+ borderRadius: "var(--nv-radius)",
748
+ border: "1px solid var(--nv-border)",
749
+ background: "var(--nv-bg)",
750
+ color: "var(--nv-fg)"
751
+ }
752
+ }
753
+ ),
754
+ /* @__PURE__ */ jsx(
755
+ "button",
756
+ {
757
+ type: "submit",
758
+ disabled: state === "submitting",
759
+ style: {
760
+ font: "inherit",
761
+ fontWeight: 500,
762
+ cursor: state === "submitting" ? "default" : "pointer",
763
+ padding: "0.6rem 1.1rem",
764
+ borderRadius: "var(--nv-radius)",
765
+ border: "1px solid var(--nv-border)",
766
+ background: "transparent",
767
+ color: "var(--nv-fg)",
768
+ opacity: state === "submitting" ? 0.6 : 1
769
+ },
770
+ children: state === "submitting" ? "\u2026" : t("catalog.backInStock.notify")
771
+ }
772
+ )
773
+ ] }),
774
+ state === "error" ? /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "#b3261e", fontSize: "0.8125rem" }, children: t("catalog.backInStock.error") }) : null
775
+ ] });
776
+ }
777
+ function StockBadge({ variant, hideInStock = false }) {
778
+ const t = useT();
779
+ const status = variant?.availability?.status;
780
+ if (!status) return null;
781
+ if (status === "in_stock" && hideInStock) return null;
782
+ const { key, color, bg } = {
783
+ in_stock: { key: "catalog.inStock", color: "#0a7c3a", bg: "rgba(10,124,58,0.12)" },
784
+ preorder: { key: "catalog.preorder", color: "var(--nv-fg)", bg: "color-mix(in oklab, var(--nv-muted) 16%, transparent)" },
785
+ out_of_stock: { key: "catalog.soldOut", color: "var(--nv-muted)", bg: "color-mix(in oklab, var(--nv-muted) 16%, transparent)" }
786
+ }[status];
787
+ return /* @__PURE__ */ jsxs(
788
+ "span",
789
+ {
790
+ style: {
791
+ display: "inline-flex",
792
+ alignItems: "center",
793
+ gap: "0.35rem",
794
+ fontSize: "0.75rem",
795
+ fontWeight: 600,
796
+ padding: "0.2rem 0.55rem",
797
+ borderRadius: "999px",
798
+ color,
799
+ background: bg
800
+ },
801
+ children: [
802
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: { width: 6, height: 6, borderRadius: "50%", background: "currentColor" } }),
803
+ t(key)
804
+ ]
805
+ }
806
+ );
807
+ }
808
+ function ProductDetailPage({
809
+ product,
810
+ locale,
811
+ addToCart
812
+ }) {
813
+ const [variant, setVariant] = React10.useState(
814
+ product.variants[0] ?? null
815
+ );
816
+ return /* @__PURE__ */ jsxs(
817
+ "div",
818
+ {
819
+ style: {
820
+ display: "grid",
821
+ gap: "2rem",
822
+ gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 320px), 1fr))",
823
+ fontFamily: "var(--nv-font)",
824
+ color: "var(--nv-fg)"
825
+ },
826
+ children: [
827
+ /* @__PURE__ */ jsx(ProductGallery, { media: product.media, alt: product.title }),
828
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1.25rem" }, children: [
829
+ /* @__PURE__ */ jsxs("div", { children: [
830
+ product.vendor ? /* @__PURE__ */ jsx("div", { style: { color: "var(--nv-muted)", fontSize: "0.875em" }, children: product.vendor }) : null,
831
+ /* @__PURE__ */ jsx("h1", { style: { margin: "0.25rem 0 0", fontSize: "1.6rem", fontWeight: 500 }, children: product.title })
832
+ ] }),
833
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", flexWrap: "wrap" }, children: [
834
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "1.25rem" }, children: variant ? /* @__PURE__ */ jsx(PriceMoney, { money: variant.price, locale }) : product.price_range ? /* @__PURE__ */ jsx(
835
+ PriceMoney,
836
+ {
837
+ money: {
838
+ amount_cents: product.price_range.min_cents,
839
+ with_tax_cents: product.price_range.min_cents,
840
+ without_tax_cents: product.price_range.min_cents,
841
+ compare_at_cents: null,
842
+ currency: product.price_range.currency,
843
+ includes_tax: product.market.prices_include_tax
844
+ },
845
+ locale
846
+ }
847
+ ) : null }),
848
+ /* @__PURE__ */ jsx(StockBadge, { variant, hideInStock: true })
849
+ ] }),
850
+ /* @__PURE__ */ jsx(VariantPicker, { product, onChange: setVariant }),
851
+ addToCart ? /* @__PURE__ */ jsx("div", { children: addToCart(variant) }) : null,
852
+ /* @__PURE__ */ jsx(BackInStockForm, { variant }),
853
+ product.description_html ? /* @__PURE__ */ jsx(
854
+ "div",
855
+ {
856
+ style: { lineHeight: 1.6 },
857
+ dangerouslySetInnerHTML: { __html: product.description_html }
858
+ }
859
+ ) : null
860
+ ] })
861
+ ]
862
+ }
863
+ );
864
+ }
865
+ function CollectionPage({
866
+ collection,
867
+ productHref,
868
+ locale
869
+ }) {
870
+ const t = useT();
871
+ return /* @__PURE__ */ jsxs("div", { style: { fontFamily: "var(--nv-font)", color: "var(--nv-fg)" }, children: [
872
+ /* @__PURE__ */ jsxs("header", { style: { marginBottom: "1.5rem" }, children: [
873
+ /* @__PURE__ */ jsx("h1", { style: { margin: 0, fontSize: "1.6rem", fontWeight: 500 }, children: collection.title }),
874
+ collection.description_html ? /* @__PURE__ */ jsx(
875
+ "div",
876
+ {
877
+ style: { marginTop: "0.5rem", color: "var(--nv-muted)", lineHeight: 1.6 },
878
+ dangerouslySetInnerHTML: { __html: collection.description_html }
879
+ }
880
+ ) : null
881
+ ] }),
882
+ collection.products.length === 0 ? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)" }, children: t("catalog.noProducts") }) : /* @__PURE__ */ jsx(
883
+ "div",
884
+ {
885
+ style: {
886
+ display: "grid",
887
+ gap: "1.5rem",
888
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 220px), 1fr))"
889
+ },
890
+ children: collection.products.map((product) => /* @__PURE__ */ jsx(
891
+ ProductCard,
892
+ {
893
+ product,
894
+ href: productHref?.(product),
895
+ locale
896
+ },
897
+ product.id
898
+ ))
899
+ }
900
+ )
901
+ ] });
902
+ }
903
+ var SORTS = [
904
+ "newest",
905
+ "oldest",
906
+ "title-asc",
907
+ "title-desc",
908
+ "price-asc",
909
+ "price-desc"
910
+ ];
911
+ var SORT_LABEL = {
912
+ newest: "catalog.filters.sortNewest",
913
+ oldest: "catalog.filters.sortOldest",
914
+ "title-asc": "catalog.filters.sortTitleAsc",
915
+ "title-desc": "catalog.filters.sortTitleDesc",
916
+ "price-asc": "catalog.filters.sortPriceAsc",
917
+ "price-desc": "catalog.filters.sortPriceDesc"
918
+ };
919
+ var inputStyle = {
920
+ font: "inherit",
921
+ padding: "0.45rem 0.6rem",
922
+ borderRadius: "var(--nv-radius)",
923
+ border: "1px solid var(--nv-border)",
924
+ background: "var(--nv-bg)",
925
+ color: "var(--nv-fg)"
926
+ };
927
+ var labelStyle = {
928
+ fontSize: "0.8125rem",
929
+ color: "var(--nv-muted)"
930
+ };
931
+ function SortSelect({ value = "newest", onChange }) {
932
+ const t = useT();
933
+ return /* @__PURE__ */ jsxs("label", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem", font: "inherit" }, children: [
934
+ /* @__PURE__ */ jsx("span", { style: labelStyle, children: t("catalog.filters.sort") }),
935
+ /* @__PURE__ */ jsx(
936
+ "select",
937
+ {
938
+ value,
939
+ onChange: (e) => onChange(e.target.value),
940
+ style: inputStyle,
941
+ children: SORTS.map((s) => /* @__PURE__ */ jsx("option", { value: s, children: t(SORT_LABEL[s]) }, s))
942
+ }
943
+ )
944
+ ] });
945
+ }
946
+ function AvailabilityFilter({
947
+ checked = false,
948
+ onChange
949
+ }) {
950
+ const t = useT();
951
+ return /* @__PURE__ */ jsxs("label", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem", cursor: "pointer", font: "inherit" }, children: [
952
+ /* @__PURE__ */ jsx("input", { type: "checkbox", checked, onChange: (e) => onChange(e.target.checked) }),
953
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem" }, children: t("catalog.filters.inStockOnly") })
954
+ ] });
955
+ }
956
+ function PriceRangeFilter({
957
+ minCents,
958
+ maxCents,
959
+ currency,
960
+ onChange,
961
+ locale
962
+ }) {
963
+ const t = useT();
964
+ const loc = useFormatLocale(locale);
965
+ const toMajor = (c) => c == null ? "" : String(Math.round(c / 100));
966
+ const fromMajor = (v) => {
967
+ const n = parseInt(v, 10);
968
+ return Number.isFinite(n) && v.trim() !== "" ? n * 100 : void 0;
969
+ };
970
+ return /* @__PURE__ */ jsxs("fieldset", { style: { border: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.35rem" }, children: [
971
+ /* @__PURE__ */ jsxs("span", { style: labelStyle, children: [
972
+ t("catalog.filters.priceRange"),
973
+ " (",
974
+ formatCents(0, currency, loc).replace(/[\d.,\s]/g, "").trim() || currency,
975
+ ")"
976
+ ] }),
977
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4rem" }, children: [
978
+ /* @__PURE__ */ jsx(
979
+ "input",
980
+ {
981
+ type: "number",
982
+ inputMode: "numeric",
983
+ min: 0,
984
+ placeholder: t("catalog.filters.min"),
985
+ "aria-label": t("catalog.filters.min"),
986
+ value: toMajor(minCents),
987
+ onChange: (e) => onChange(fromMajor(e.target.value), maxCents),
988
+ style: { ...inputStyle, width: "5.5rem" }
989
+ }
990
+ ),
991
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)" }, children: "\u2013" }),
992
+ /* @__PURE__ */ jsx(
993
+ "input",
994
+ {
995
+ type: "number",
996
+ inputMode: "numeric",
997
+ min: 0,
998
+ placeholder: t("catalog.filters.max"),
999
+ "aria-label": t("catalog.filters.max"),
1000
+ value: toMajor(maxCents),
1001
+ onChange: (e) => onChange(minCents, fromMajor(e.target.value)),
1002
+ style: { ...inputStyle, width: "5.5rem" }
1003
+ }
1004
+ )
1005
+ ] })
1006
+ ] });
1007
+ }
1008
+ function TagFilter({ tags, selected = [], onChange }) {
1009
+ const t = useT();
1010
+ if (tags.length === 0) return null;
1011
+ const set = new Set(selected);
1012
+ const toggle = (tag) => {
1013
+ const next = new Set(set);
1014
+ if (next.has(tag)) next.delete(tag);
1015
+ else next.add(tag);
1016
+ onChange([...next]);
1017
+ };
1018
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.35rem" }, children: [
1019
+ /* @__PURE__ */ jsx("span", { style: labelStyle, children: t("catalog.filters.tags") }),
1020
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "0.4rem", flexWrap: "wrap" }, children: tags.map((tag) => {
1021
+ const active = set.has(tag);
1022
+ return /* @__PURE__ */ jsx(
1023
+ "button",
1024
+ {
1025
+ type: "button",
1026
+ "aria-pressed": active,
1027
+ onClick: () => toggle(tag),
1028
+ style: {
1029
+ font: "inherit",
1030
+ fontSize: "0.8125rem",
1031
+ cursor: "pointer",
1032
+ padding: "0.3rem 0.7rem",
1033
+ borderRadius: "999px",
1034
+ background: active ? "var(--nv-brand)" : "transparent",
1035
+ color: active ? "var(--nv-brand-foreground)" : "var(--nv-fg)",
1036
+ border: active ? "1px solid var(--nv-brand)" : "1px solid var(--nv-border)"
1037
+ },
1038
+ children: tag
1039
+ },
1040
+ tag
1041
+ );
1042
+ }) })
1043
+ ] });
1044
+ }
1045
+ var CartContext = React10.createContext(null);
1046
+ function CartProvider({ children }) {
1047
+ const client = useStorefront();
1048
+ const [cart, setCart] = React10.useState(null);
1049
+ const [loading, setLoading] = React10.useState(false);
1050
+ const run = React10.useCallback(
1051
+ async (op) => {
1052
+ setLoading(true);
1053
+ try {
1054
+ const next = await op();
1055
+ setCart(next);
1056
+ return next;
1057
+ } finally {
1058
+ setLoading(false);
1059
+ }
1060
+ },
1061
+ []
1062
+ );
1063
+ const refresh = React10.useCallback(async () => {
1064
+ setLoading(true);
1065
+ try {
1066
+ setCart(await client.cart.get());
1067
+ } finally {
1068
+ setLoading(false);
1069
+ }
1070
+ }, [client]);
1071
+ React10.useEffect(() => {
1072
+ void refresh();
1073
+ }, [refresh]);
1074
+ const value = React10.useMemo(
1075
+ () => ({
1076
+ cart,
1077
+ loading,
1078
+ itemCount: cart?.totals.item_count ?? 0,
1079
+ addLine: (input) => run(() => client.cart.addLine(input)),
1080
+ updateLine: (lineId, quantity) => run(() => client.cart.updateLine(lineId, quantity)),
1081
+ removeLine: (lineId) => run(() => client.cart.removeLine(lineId)),
1082
+ refresh
1083
+ }),
1084
+ [cart, loading, client, run, refresh]
1085
+ );
1086
+ return /* @__PURE__ */ jsx(CartContext.Provider, { value, children });
1087
+ }
1088
+ function useCart() {
1089
+ const ctx = React10.useContext(CartContext);
1090
+ if (!ctx) {
1091
+ throw new Error("useCart must be used inside <CartProvider>.");
1092
+ }
1093
+ return ctx;
1094
+ }
1095
+ function AddToCart({
1096
+ variant,
1097
+ quantity = 1,
1098
+ children,
1099
+ onAdded
1100
+ }) {
1101
+ const t = useT();
1102
+ const { addLine } = useCart();
1103
+ const [busy, setBusy] = React10.useState(false);
1104
+ const [error, setError] = React10.useState(null);
1105
+ const disabled = variant == null || busy;
1106
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
1107
+ /* @__PURE__ */ jsx(
1108
+ "button",
1109
+ {
1110
+ type: "button",
1111
+ disabled,
1112
+ onClick: async () => {
1113
+ if (variant == null) return;
1114
+ setBusy(true);
1115
+ setError(null);
1116
+ try {
1117
+ await addLine({ variant_id: variant.id, quantity });
1118
+ onAdded?.();
1119
+ } catch (err) {
1120
+ const code = err?.code;
1121
+ setError(code === "variant_out_of_stock" ? t("catalog.soldOut") : t("catalog.addError"));
1122
+ } finally {
1123
+ setBusy(false);
1124
+ }
1125
+ },
1126
+ style: {
1127
+ font: "inherit",
1128
+ fontWeight: 500,
1129
+ cursor: disabled ? "default" : "pointer",
1130
+ padding: "0.7rem 1.5rem",
1131
+ borderRadius: "var(--nv-radius)",
1132
+ border: "none",
1133
+ background: "var(--nv-brand)",
1134
+ color: "var(--nv-brand-foreground)",
1135
+ opacity: disabled ? 0.55 : 1
1136
+ },
1137
+ children: busy ? t("common.loadingShort") : children ?? t("catalog.addToCart")
1138
+ }
1139
+ ),
1140
+ error ? /* @__PURE__ */ jsx("p", { role: "alert", style: { margin: 0, fontSize: "0.8125rem", color: "var(--nv-danger, #b91c1c)" }, children: error }) : null
1141
+ ] });
1142
+ }
1143
+ function CartLineItem({ line, locale }) {
1144
+ const t = useT();
1145
+ const { updateLine, removeLine } = useCart();
1146
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.85rem", alignItems: "flex-start", padding: "0.75rem 0" }, children: [
1147
+ /* @__PURE__ */ jsx(
1148
+ "div",
1149
+ {
1150
+ style: {
1151
+ width: 64,
1152
+ height: 64,
1153
+ flex: "0 0 auto",
1154
+ borderRadius: "calc(var(--nv-radius) - 4px)",
1155
+ overflow: "hidden",
1156
+ background: "color-mix(in oklab, var(--nv-muted) 12%, transparent)"
1157
+ },
1158
+ children: line.image_url ? (
1159
+ // eslint-disable-next-line @next/next/no-img-element
1160
+ /* @__PURE__ */ jsx(
1161
+ "img",
1162
+ {
1163
+ src: line.image_url,
1164
+ alt: line.title ?? "",
1165
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
1166
+ }
1167
+ )
1168
+ ) : null
1169
+ }
1170
+ ),
1171
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1172
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, lineHeight: 1.3 }, children: line.title }),
1173
+ line.variant_title ? /* @__PURE__ */ jsx("div", { style: { color: "var(--nv-muted)", fontSize: "0.875em" }, children: line.variant_title }) : null,
1174
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem", marginTop: "0.5rem" }, children: [
1175
+ /* @__PURE__ */ jsxs(
1176
+ "div",
1177
+ {
1178
+ style: {
1179
+ display: "inline-flex",
1180
+ alignItems: "center",
1181
+ border: "1px solid var(--nv-border)",
1182
+ borderRadius: "var(--nv-radius)"
1183
+ },
1184
+ children: [
1185
+ /* @__PURE__ */ jsx(
1186
+ StepBtn,
1187
+ {
1188
+ label: "\u2212",
1189
+ onClick: () => line.quantity <= 1 ? removeLine(line.id) : updateLine(line.id, line.quantity - 1)
1190
+ }
1191
+ ),
1192
+ /* @__PURE__ */ jsx("span", { style: { minWidth: 28, textAlign: "center", fontVariantNumeric: "tabular-nums" }, children: line.quantity }),
1193
+ /* @__PURE__ */ jsx(StepBtn, { label: "+", onClick: () => updateLine(line.id, line.quantity + 1) })
1194
+ ]
1195
+ }
1196
+ ),
1197
+ /* @__PURE__ */ jsx(
1198
+ "button",
1199
+ {
1200
+ type: "button",
1201
+ onClick: () => removeLine(line.id),
1202
+ style: {
1203
+ font: "inherit",
1204
+ fontSize: "0.8125em",
1205
+ background: "transparent",
1206
+ border: "none",
1207
+ color: "var(--nv-muted)",
1208
+ cursor: "pointer",
1209
+ padding: 0
1210
+ },
1211
+ children: t("cart.remove")
1212
+ }
1213
+ )
1214
+ ] })
1215
+ ] }),
1216
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, whiteSpace: "nowrap" }, children: formatCents(line.line_total_cents, line.unit_price.currency, locale) })
1217
+ ] });
1218
+ }
1219
+ function StepBtn({ label, onClick }) {
1220
+ const t = useT();
1221
+ return /* @__PURE__ */ jsx(
1222
+ "button",
1223
+ {
1224
+ type: "button",
1225
+ "aria-label": label === "+" ? t("cart.increaseQty") : t("cart.decreaseQty"),
1226
+ onClick,
1227
+ style: {
1228
+ font: "inherit",
1229
+ width: 30,
1230
+ height: 30,
1231
+ lineHeight: 1,
1232
+ background: "transparent",
1233
+ border: "none",
1234
+ cursor: "pointer",
1235
+ color: "var(--nv-fg)"
1236
+ },
1237
+ children: label
1238
+ }
1239
+ );
1240
+ }
1241
+ function CartSummary({
1242
+ checkoutLabel,
1243
+ checkoutHref,
1244
+ onCheckout,
1245
+ locale
1246
+ }) {
1247
+ const tr = useT();
1248
+ const { cart } = useCart();
1249
+ if (cart == null) return null;
1250
+ const t = cart.totals;
1251
+ const empty = t.item_count === 0;
1252
+ const cta = checkoutLabel ?? tr("cart.checkout");
1253
+ const ctaStyle = {
1254
+ display: "block",
1255
+ textAlign: "center",
1256
+ font: "inherit",
1257
+ fontWeight: 500,
1258
+ cursor: empty ? "default" : "pointer",
1259
+ padding: "0.75rem 1.5rem",
1260
+ borderRadius: "var(--nv-radius)",
1261
+ border: "none",
1262
+ background: "var(--nv-brand)",
1263
+ color: "var(--nv-brand-foreground)",
1264
+ textDecoration: "none",
1265
+ opacity: empty ? 0.55 : 1
1266
+ };
1267
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
1268
+ /* @__PURE__ */ jsx(Row, { label: tr("cart.subtotal"), value: formatCents(t.subtotal_with_tax_cents, t.currency, locale) }),
1269
+ t.tax_cents > 0 ? /* @__PURE__ */ jsx(Row, { label: tr("cart.tax"), value: formatCents(t.tax_cents, t.currency, locale), muted: true }) : null,
1270
+ /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
1271
+ /* @__PURE__ */ jsx(Row, { label: tr("cart.total"), value: formatCents(t.total_cents, t.currency, locale), strong: true }),
1272
+ checkoutHref && !empty ? /* @__PURE__ */ jsx("a", { href: checkoutHref, style: ctaStyle, children: cta }) : /* @__PURE__ */ jsx("button", { type: "button", disabled: empty, onClick: onCheckout, style: ctaStyle, children: cta })
1273
+ ] });
1274
+ }
1275
+ function Row({
1276
+ label,
1277
+ value,
1278
+ strong,
1279
+ muted
1280
+ }) {
1281
+ return /* @__PURE__ */ jsxs(
1282
+ "div",
1283
+ {
1284
+ style: {
1285
+ display: "flex",
1286
+ justifyContent: "space-between",
1287
+ fontWeight: strong ? 500 : 400,
1288
+ color: muted ? "var(--nv-muted)" : "inherit",
1289
+ fontSize: strong ? "1.05em" : "1em"
1290
+ },
1291
+ children: [
1292
+ /* @__PURE__ */ jsx("span", { children: label }),
1293
+ /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: value })
1294
+ ]
1295
+ }
1296
+ );
1297
+ }
1298
+ function CartDrawer({
1299
+ open,
1300
+ onClose,
1301
+ title,
1302
+ ...summary
1303
+ }) {
1304
+ const t = useT();
1305
+ const { cart, loading } = useCart();
1306
+ const heading = title ?? t("cart.title");
1307
+ if (!open) return null;
1308
+ const lines = cart?.line_items ?? [];
1309
+ return /* @__PURE__ */ jsx(
1310
+ "div",
1311
+ {
1312
+ role: "dialog",
1313
+ "aria-label": heading,
1314
+ onClick: onClose,
1315
+ style: {
1316
+ position: "fixed",
1317
+ inset: 0,
1318
+ zIndex: 1e3,
1319
+ background: "rgba(0,0,0,0.4)",
1320
+ display: "flex",
1321
+ justifyContent: "flex-end"
1322
+ },
1323
+ children: /* @__PURE__ */ jsxs(
1324
+ "div",
1325
+ {
1326
+ onClick: (e) => e.stopPropagation(),
1327
+ style: {
1328
+ width: "min(420px, 100%)",
1329
+ height: "100%",
1330
+ background: "var(--nv-bg)",
1331
+ color: "var(--nv-fg)",
1332
+ fontFamily: "var(--nv-font)",
1333
+ display: "flex",
1334
+ flexDirection: "column",
1335
+ boxShadow: "-8px 0 24px rgba(0,0,0,0.12)"
1336
+ },
1337
+ children: [
1338
+ /* @__PURE__ */ jsxs(
1339
+ "header",
1340
+ {
1341
+ style: {
1342
+ display: "flex",
1343
+ justifyContent: "space-between",
1344
+ alignItems: "center",
1345
+ padding: "1rem 1.25rem",
1346
+ borderBottom: "1px solid var(--nv-border)"
1347
+ },
1348
+ children: [
1349
+ /* @__PURE__ */ jsx("strong", { style: { fontWeight: 500 }, children: heading }),
1350
+ /* @__PURE__ */ jsx(
1351
+ "button",
1352
+ {
1353
+ type: "button",
1354
+ "aria-label": t("common.close"),
1355
+ onClick: onClose,
1356
+ style: { font: "inherit", background: "transparent", border: "none", cursor: "pointer", fontSize: "1.25rem" },
1357
+ children: "\xD7"
1358
+ }
1359
+ )
1360
+ ]
1361
+ }
1362
+ ),
1363
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto", padding: "0 1.25rem" }, children: lines.length === 0 ? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", padding: "2rem 0", textAlign: "center" }, children: loading ? t("common.loadingShort") : t("cart.empty") }) : lines.map((line, i) => /* @__PURE__ */ jsx(
1364
+ "div",
1365
+ {
1366
+ style: i > 0 ? { borderTop: "1px solid var(--nv-border)" } : void 0,
1367
+ children: /* @__PURE__ */ jsx(CartLineItem, { line, locale: summary.locale })
1368
+ },
1369
+ line.id
1370
+ )) }),
1371
+ lines.length > 0 ? /* @__PURE__ */ jsx("div", { style: { padding: "1.25rem", borderTop: "1px solid var(--nv-border)" }, children: /* @__PURE__ */ jsx(CartSummary, { ...summary }) }) : null
1372
+ ]
1373
+ }
1374
+ )
1375
+ }
1376
+ );
1377
+ }
1378
+ var CheckoutContext = React10.createContext(null);
1379
+ function CheckoutProvider({
1380
+ children
1381
+ }) {
1382
+ const client = useStorefront();
1383
+ const [checkout, setCheckout] = React10.useState(null);
1384
+ const [loading, setLoading] = React10.useState(false);
1385
+ const [error, setError] = React10.useState(null);
1386
+ const run = React10.useCallback(
1387
+ async (op, store) => {
1388
+ setLoading(true);
1389
+ try {
1390
+ const result = await op();
1391
+ const next = store(result);
1392
+ if (next) setCheckout(next);
1393
+ setError(null);
1394
+ return result;
1395
+ } catch (err) {
1396
+ setError(err instanceof Error ? err : new Error(String(err)));
1397
+ throw err;
1398
+ } finally {
1399
+ setLoading(false);
1400
+ }
1401
+ },
1402
+ []
1403
+ );
1404
+ const refresh = React10.useCallback(async () => {
1405
+ setLoading(true);
1406
+ try {
1407
+ setCheckout(await client.checkout.get());
1408
+ setError(null);
1409
+ } finally {
1410
+ setLoading(false);
1411
+ }
1412
+ }, [client]);
1413
+ React10.useEffect(() => {
1414
+ void refresh();
1415
+ }, [refresh]);
1416
+ const pay = React10.useCallback(
1417
+ async (opts = {}) => {
1418
+ const co = checkout;
1419
+ if (!co) throw new Error("pay() called before a checkout exists");
1420
+ const idempotencyKey = opts.idempotencyKey ?? co.token;
1421
+ if (co.payment_category === "gateway") {
1422
+ const start = await run(
1423
+ () => client.checkout.startPayment({ return_url: opts.returnUrl, cancel_url: opts.cancelUrl }),
1424
+ () => null
1425
+ );
1426
+ if (!start.redirect_url) throw new Error("gateway returned no redirect_url");
1427
+ const shouldRedirect = opts.redirect !== false && typeof window !== "undefined";
1428
+ if (shouldRedirect) window.location.assign(start.redirect_url);
1429
+ return { kind: "redirect", url: start.redirect_url };
1430
+ }
1431
+ const done = await run(
1432
+ () => client.checkout.complete({ idempotencyKey }),
1433
+ (r) => r
1434
+ );
1435
+ return { kind: "order", checkout: done };
1436
+ },
1437
+ [checkout, client, run]
1438
+ );
1439
+ const value = React10.useMemo(
1440
+ () => ({
1441
+ checkout,
1442
+ loading,
1443
+ error,
1444
+ create: (cartToken, input) => run(() => client.checkout.create(cartToken, input), (r) => r),
1445
+ setAddress: (input) => run(() => client.checkout.setAddress(input), (r) => r),
1446
+ shippingQuotes: () => run(() => client.checkout.shippingQuotes(), () => null),
1447
+ setShippingMethod: (methodId, rateId) => run(() => client.checkout.setShippingMethod(methodId, rateId), (r) => r),
1448
+ applyDiscount: (code) => run(() => client.checkout.applyDiscount(code), (r) => r),
1449
+ removeDiscount: (code) => run(() => client.checkout.removeDiscount(code), (r) => r),
1450
+ paymentMethods: () => run(() => client.checkout.paymentMethods(), () => null),
1451
+ setPaymentMethod: (method) => run(() => client.checkout.setPaymentMethod(method), (r) => r),
1452
+ pay,
1453
+ refresh,
1454
+ clear: () => {
1455
+ client.checkout.clear();
1456
+ setCheckout(null);
1457
+ }
1458
+ }),
1459
+ [checkout, loading, error, client, run, pay, refresh]
1460
+ );
1461
+ return /* @__PURE__ */ jsx(CheckoutContext.Provider, { value, children });
1462
+ }
1463
+ function useCheckout() {
1464
+ const ctx = React10.useContext(CheckoutContext);
1465
+ if (!ctx) {
1466
+ throw new Error("useCheckout must be used inside <CheckoutProvider>.");
1467
+ }
1468
+ return ctx;
1469
+ }
1470
+ function Field({ label, style, ...input }) {
1471
+ return /* @__PURE__ */ jsxs("label", { style: { display: "flex", flexDirection: "column", gap: "0.35rem", flex: 1 }, children: [
1472
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: label }),
1473
+ /* @__PURE__ */ jsx(
1474
+ "input",
1475
+ {
1476
+ ...input,
1477
+ style: {
1478
+ font: "inherit",
1479
+ padding: "0.6rem 0.75rem",
1480
+ borderRadius: "var(--nv-radius)",
1481
+ border: "1px solid var(--nv-border)",
1482
+ background: "var(--nv-bg)",
1483
+ color: "var(--nv-fg)",
1484
+ width: "100%",
1485
+ boxSizing: "border-box",
1486
+ ...style
1487
+ }
1488
+ }
1489
+ )
1490
+ ] });
1491
+ }
1492
+ function FieldRow({ children }) {
1493
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "0.75rem", flexWrap: "wrap" }, children });
1494
+ }
1495
+ function Button({
1496
+ busy,
1497
+ disabled,
1498
+ children,
1499
+ style,
1500
+ ...rest
1501
+ }) {
1502
+ const off = disabled || busy;
1503
+ return /* @__PURE__ */ jsx(
1504
+ "button",
1505
+ {
1506
+ type: "button",
1507
+ disabled: off,
1508
+ ...rest,
1509
+ style: {
1510
+ font: "inherit",
1511
+ fontWeight: 500,
1512
+ cursor: off ? "default" : "pointer",
1513
+ padding: "0.75rem 1.5rem",
1514
+ borderRadius: "var(--nv-radius)",
1515
+ border: "none",
1516
+ background: "var(--nv-brand)",
1517
+ color: "var(--nv-brand-foreground)",
1518
+ opacity: off ? 0.55 : 1,
1519
+ ...style
1520
+ },
1521
+ children: busy ? "\u2026" : children
1522
+ }
1523
+ );
1524
+ }
1525
+ function SelectRow({
1526
+ selected,
1527
+ onSelect,
1528
+ children,
1529
+ trailing,
1530
+ disabled
1531
+ }) {
1532
+ return /* @__PURE__ */ jsxs(
1533
+ "button",
1534
+ {
1535
+ type: "button",
1536
+ role: "radio",
1537
+ "aria-checked": selected,
1538
+ disabled,
1539
+ onClick: onSelect,
1540
+ style: {
1541
+ display: "flex",
1542
+ alignItems: "center",
1543
+ justifyContent: "space-between",
1544
+ gap: "0.75rem",
1545
+ width: "100%",
1546
+ textAlign: "left",
1547
+ font: "inherit",
1548
+ cursor: disabled ? "default" : "pointer",
1549
+ padding: "0.85rem 1rem",
1550
+ borderRadius: "var(--nv-radius)",
1551
+ border: `1px solid ${selected ? "var(--nv-brand)" : "var(--nv-border)"}`,
1552
+ boxShadow: selected ? "0 0 0 1px var(--nv-brand) inset" : "none",
1553
+ background: "var(--nv-bg)",
1554
+ color: "var(--nv-fg)",
1555
+ opacity: disabled ? 0.55 : 1
1556
+ },
1557
+ children: [
1558
+ /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.6rem" }, children: [
1559
+ /* @__PURE__ */ jsx(
1560
+ "span",
1561
+ {
1562
+ "aria-hidden": true,
1563
+ style: {
1564
+ width: "1rem",
1565
+ height: "1rem",
1566
+ borderRadius: "50%",
1567
+ border: `1px solid ${selected ? "var(--nv-brand)" : "var(--nv-border)"}`,
1568
+ background: selected ? "radial-gradient(var(--nv-brand) 0 45%, transparent 50%)" : "transparent",
1569
+ flexShrink: 0
1570
+ }
1571
+ }
1572
+ ),
1573
+ /* @__PURE__ */ jsx("span", { children })
1574
+ ] }),
1575
+ trailing != null ? /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: trailing }) : null
1576
+ ]
1577
+ }
1578
+ );
1579
+ }
1580
+ function Section({
1581
+ title,
1582
+ children
1583
+ }) {
1584
+ return /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "0.85rem" }, children: [
1585
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.05rem", fontWeight: 600 }, children: title }),
1586
+ children
1587
+ ] });
1588
+ }
1589
+ var EMPTY = {
1590
+ email: "",
1591
+ first_name: "",
1592
+ last_name: "",
1593
+ company: "",
1594
+ address1: "",
1595
+ address2: "",
1596
+ city: "",
1597
+ postal_code: "",
1598
+ country_code: "",
1599
+ phone: ""
1600
+ };
1601
+ function seed(email, addr) {
1602
+ return {
1603
+ ...EMPTY,
1604
+ email: email ?? "",
1605
+ first_name: addr?.first_name ?? "",
1606
+ last_name: addr?.last_name ?? "",
1607
+ company: addr?.company ?? "",
1608
+ address1: addr?.address1 ?? "",
1609
+ address2: addr?.address2 ?? "",
1610
+ city: addr?.city ?? "",
1611
+ postal_code: addr?.postal_code ?? "",
1612
+ country_code: addr?.country_code ?? "",
1613
+ phone: addr?.phone ?? ""
1614
+ };
1615
+ }
1616
+ function AddressForm({
1617
+ title,
1618
+ submitLabel,
1619
+ onComplete
1620
+ }) {
1621
+ const t = useT();
1622
+ const { checkout, setAddress, loading } = useCheckout();
1623
+ const [form, setForm] = React10.useState(
1624
+ () => seed(checkout?.email ?? null, checkout?.shipping_address ?? null)
1625
+ );
1626
+ const set = (key) => (e) => setForm((f) => ({ ...f, [key]: e.target.value }));
1627
+ async function submit(e) {
1628
+ e.preventDefault();
1629
+ const { email, ...rest } = form;
1630
+ await setAddress({
1631
+ email,
1632
+ shipping_address: rest,
1633
+ same_as_shipping: true
1634
+ });
1635
+ onComplete?.();
1636
+ }
1637
+ return /* @__PURE__ */ jsx("form", { onSubmit: submit, children: /* @__PURE__ */ jsxs(Section, { title: title ?? t("checkout.shippingAddress"), children: [
1638
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.email"), type: "email", required: true, value: form.email, onChange: set("email"), autoComplete: "email" }),
1639
+ /* @__PURE__ */ jsxs(FieldRow, { children: [
1640
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.firstName"), required: true, value: form.first_name, onChange: set("first_name"), autoComplete: "given-name" }),
1641
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.lastName"), required: true, value: form.last_name, onChange: set("last_name"), autoComplete: "family-name" })
1642
+ ] }),
1643
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.company"), value: form.company, onChange: set("company"), autoComplete: "organization" }),
1644
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.address"), required: true, value: form.address1, onChange: set("address1"), autoComplete: "address-line1" }),
1645
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.apartment"), value: form.address2, onChange: set("address2"), autoComplete: "address-line2" }),
1646
+ /* @__PURE__ */ jsxs(FieldRow, { children: [
1647
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.city"), required: true, value: form.city, onChange: set("city"), autoComplete: "address-level2" }),
1648
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.postalCode"), required: true, value: form.postal_code, onChange: set("postal_code"), autoComplete: "postal-code" }),
1649
+ /* @__PURE__ */ jsx(
1650
+ Field,
1651
+ {
1652
+ label: t("checkout.country"),
1653
+ required: true,
1654
+ value: form.country_code,
1655
+ onChange: set("country_code"),
1656
+ placeholder: "CZ",
1657
+ autoComplete: "country",
1658
+ maxLength: 2,
1659
+ style: { textTransform: "uppercase", maxWidth: "6rem" }
1660
+ }
1661
+ )
1662
+ ] }),
1663
+ /* @__PURE__ */ jsx(Field, { label: t("checkout.phone"), type: "tel", value: form.phone, onChange: set("phone"), autoComplete: "tel" }),
1664
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { type: "submit", busy: loading, children: submitLabel ?? t("checkout.continueToShipping") }) })
1665
+ ] }) });
1666
+ }
1667
+ function ShippingPicker({
1668
+ title,
1669
+ submitLabel,
1670
+ onComplete,
1671
+ locale
1672
+ }) {
1673
+ const t = useT();
1674
+ const { checkout, shippingQuotes, setShippingMethod, loading } = useCheckout();
1675
+ const heading = title ?? t("checkout.shippingMethod");
1676
+ const [quotes, setQuotes] = React10.useState(null);
1677
+ const [selected, setSelected] = React10.useState(null);
1678
+ const [fetching, setFetching] = React10.useState(true);
1679
+ const addressKey = checkout?.shipping_address ? `${checkout.shipping_address.country_code}:${checkout.shipping_address.postal_code}` : null;
1680
+ React10.useEffect(() => {
1681
+ let live = true;
1682
+ setFetching(true);
1683
+ shippingQuotes().then((qs) => {
1684
+ if (!live) return;
1685
+ setQuotes(qs);
1686
+ const savedLabel = checkout?.shipping_method?.rate_display_name;
1687
+ const match = savedLabel ? qs.find((q) => q.label === savedLabel) : void 0;
1688
+ setSelected(match?.rate_id ?? (qs.length === 1 ? qs[0].rate_id : null));
1689
+ }).catch(() => live && setQuotes([])).finally(() => live && setFetching(false));
1690
+ return () => {
1691
+ live = false;
1692
+ };
1693
+ }, [addressKey]);
1694
+ async function submit() {
1695
+ const q = quotes?.find((x) => x.rate_id === selected);
1696
+ if (!q) return;
1697
+ await setShippingMethod(q.method_id, q.rate_id);
1698
+ onComplete?.();
1699
+ }
1700
+ if (fetching && quotes == null) {
1701
+ return /* @__PURE__ */ jsx(Section, { title: heading, children: /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.loadingShipping") }) });
1702
+ }
1703
+ if (!quotes || quotes.length === 0) {
1704
+ return /* @__PURE__ */ jsx(Section, { title: heading, children: /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.noShipping") }) });
1705
+ }
1706
+ return /* @__PURE__ */ jsxs(Section, { title: heading, children: [
1707
+ /* @__PURE__ */ jsx("div", { role: "radiogroup", style: { display: "flex", flexDirection: "column", gap: "0.6rem" }, children: quotes.map((q) => {
1708
+ const days = estDays(q, t);
1709
+ return /* @__PURE__ */ jsx(
1710
+ SelectRow,
1711
+ {
1712
+ selected: selected === q.rate_id,
1713
+ onSelect: () => setSelected(q.rate_id),
1714
+ trailing: q.is_free ? t("common.free") : formatCents(q.price_cents, q.currency, locale),
1715
+ children: /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
1716
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: q.label }),
1717
+ days ? /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: days }) : null
1718
+ ] })
1719
+ },
1720
+ q.rate_id
1721
+ );
1722
+ }) }),
1723
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { onClick: submit, busy: loading, disabled: selected == null, children: submitLabel ?? t("checkout.continueToPayment") }) })
1724
+ ] });
1725
+ }
1726
+ function estDays(q, t) {
1727
+ const { estimated_days_min: lo, estimated_days_max: hi } = q;
1728
+ if (lo == null && hi == null) return null;
1729
+ if (lo != null && hi != null) {
1730
+ return lo === hi ? t("shipping.days", { count: lo }) : t("shipping.daysRange", { min: lo, max: hi });
1731
+ }
1732
+ const n = lo ?? hi;
1733
+ return t("shipping.days", { count: n });
1734
+ }
1735
+ function PaymentSection({
1736
+ title,
1737
+ returnUrl,
1738
+ cancelUrl,
1739
+ onOrderPlaced,
1740
+ locale
1741
+ }) {
1742
+ const t = useT();
1743
+ const heading = title ?? t("checkout.payment");
1744
+ const { checkout, paymentMethods, setPaymentMethod, pay, loading } = useCheckout();
1745
+ const [methods, setMethods] = React10.useState(null);
1746
+ const [fetching, setFetching] = React10.useState(true);
1747
+ const selected = checkout?.payment_method ?? null;
1748
+ React10.useEffect(() => {
1749
+ let live = true;
1750
+ setFetching(true);
1751
+ paymentMethods().then((ms) => {
1752
+ if (!live) return;
1753
+ setMethods(ms);
1754
+ if (ms.length === 1 && checkout?.payment_method == null) {
1755
+ void setPaymentMethod(ms[0].method);
1756
+ }
1757
+ }).catch(() => live && setMethods([])).finally(() => live && setFetching(false));
1758
+ return () => {
1759
+ live = false;
1760
+ };
1761
+ }, []);
1762
+ const selectedMethod = methods?.find((m) => m.method === selected) ?? null;
1763
+ const isGateway = selectedMethod?.category === "gateway";
1764
+ async function placeOrder() {
1765
+ const result = await pay({ returnUrl, cancelUrl });
1766
+ if (result.kind === "order") onOrderPlaced?.(result.checkout);
1767
+ }
1768
+ if (fetching && methods == null) {
1769
+ return /* @__PURE__ */ jsx(Section, { title: heading, children: /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.loadingPayment") }) });
1770
+ }
1771
+ if (!methods || methods.length === 0) {
1772
+ return /* @__PURE__ */ jsx(Section, { title: heading, children: /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("checkout.noPayment") }) });
1773
+ }
1774
+ return /* @__PURE__ */ jsxs(Section, { title: heading, children: [
1775
+ /* @__PURE__ */ jsx("div", { role: "radiogroup", style: { display: "flex", flexDirection: "column", gap: "0.6rem" }, children: methods.map((m) => /* @__PURE__ */ jsx(
1776
+ SelectRow,
1777
+ {
1778
+ selected: selected === m.method,
1779
+ onSelect: () => void setPaymentMethod(m.method),
1780
+ trailing: m.surcharge_cents > 0 && checkout ? `+${formatCents(m.surcharge_cents, checkout.totals.currency, locale)}` : void 0,
1781
+ children: /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
1782
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: m.display_label }),
1783
+ m.display_description ? /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: m.display_description }) : null
1784
+ ] })
1785
+ },
1786
+ m.method
1787
+ )) }),
1788
+ /* @__PURE__ */ jsxs("div", { children: [
1789
+ /* @__PURE__ */ jsx(Button, { onClick: placeOrder, busy: loading, disabled: selected == null, children: isGateway ? t("checkout.payNow") : t("checkout.placeOrder") }),
1790
+ isGateway ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)", marginTop: "0.6rem" }, children: t("checkout.gatewayRedirectNote") }) : null
1791
+ ] })
1792
+ ] });
1793
+ }
1794
+ function OrderSummary({
1795
+ checkout: override,
1796
+ totalsOnly = false,
1797
+ locale
1798
+ }) {
1799
+ const tr = useT();
1800
+ const ctx = useCheckout();
1801
+ const checkout = override ?? ctx.checkout;
1802
+ if (checkout == null) return null;
1803
+ const t = checkout.totals;
1804
+ const c = t.currency;
1805
+ const money = (cents) => formatCents(cents, c, locale);
1806
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
1807
+ !totalsOnly && checkout.line_items.length > 0 ? /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.75rem" }, children: checkout.line_items.map((li) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
1808
+ li.image_url ? /* @__PURE__ */ jsx(
1809
+ "img",
1810
+ {
1811
+ src: li.image_url,
1812
+ alt: "",
1813
+ width: 48,
1814
+ height: 48,
1815
+ style: { borderRadius: "var(--nv-radius)", objectFit: "cover", flexShrink: 0 }
1816
+ }
1817
+ ) : null,
1818
+ /* @__PURE__ */ jsxs("span", { style: { flex: 1, minWidth: 0 }, children: [
1819
+ /* @__PURE__ */ jsx("span", { style: { display: "block", fontWeight: 500 }, children: li.title }),
1820
+ li.variant_title ? /* @__PURE__ */ jsx("span", { style: { display: "block", fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: li.variant_title }) : null,
1821
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: [
1822
+ "\xD7",
1823
+ li.quantity
1824
+ ] })
1825
+ ] }),
1826
+ /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: money(li.line_total_cents) })
1827
+ ] }, li.id)) }) : null,
1828
+ !totalsOnly ? /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }) : null,
1829
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
1830
+ /* @__PURE__ */ jsx(Row2, { label: tr("totals.subtotal"), value: money(t.subtotal_with_tax_cents) }),
1831
+ t.discount_cents > 0 ? /* @__PURE__ */ jsx(Row2, { label: tr("totals.discount"), value: `\u2212${money(t.discount_cents)}`, muted: true }) : null,
1832
+ checkout.shipping_method != null || t.shipping_cents > 0 ? /* @__PURE__ */ jsx(Row2, { label: tr("totals.shipping"), value: t.shipping_cents > 0 ? money(t.shipping_cents) : tr("common.free"), muted: true }) : null,
1833
+ t.surcharge_cents > 0 ? /* @__PURE__ */ jsx(Row2, { label: tr("totals.paymentFee"), value: money(t.surcharge_cents), muted: true }) : null,
1834
+ t.tax_cents > 0 ? /* @__PURE__ */ jsx(Row2, { label: tr("totals.taxIncluded"), value: money(t.tax_cents), muted: true }) : null,
1835
+ /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
1836
+ /* @__PURE__ */ jsx(Row2, { label: tr("totals.total"), value: money(t.total_cents), strong: true })
1837
+ ] })
1838
+ ] });
1839
+ }
1840
+ function Row2({
1841
+ label,
1842
+ value,
1843
+ strong,
1844
+ muted
1845
+ }) {
1846
+ return /* @__PURE__ */ jsxs(
1847
+ "div",
1848
+ {
1849
+ style: {
1850
+ display: "flex",
1851
+ justifyContent: "space-between",
1852
+ fontWeight: strong ? 600 : 400,
1853
+ color: muted ? "var(--nv-muted)" : "inherit",
1854
+ fontSize: strong ? "1.1em" : "1em"
1855
+ },
1856
+ children: [
1857
+ /* @__PURE__ */ jsx("span", { children: label }),
1858
+ /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: value })
1859
+ ]
1860
+ }
1861
+ );
1862
+ }
1863
+ var STEPS = ["address", "shipping", "payment"];
1864
+ var STEP_KEY = {
1865
+ address: "checkout.stepAddress",
1866
+ shipping: "checkout.stepShipping",
1867
+ payment: "checkout.stepPayment"
1868
+ };
1869
+ function reachedStep(checkout) {
1870
+ if (!checkout) return "address";
1871
+ if (checkout.shipping_method != null) return "payment";
1872
+ if (checkout.shipping_address != null) return "shipping";
1873
+ return "address";
1874
+ }
1875
+ function CheckoutFlow({
1876
+ cartToken,
1877
+ onOrderPlaced,
1878
+ emptyState,
1879
+ renderConfirmation,
1880
+ returnUrl,
1881
+ cancelUrl,
1882
+ locale
1883
+ }) {
1884
+ const t = useT();
1885
+ const { checkout, loading, create } = useCheckout();
1886
+ const [step, setStep] = React10.useState("address");
1887
+ const [bootstrapped, setBootstrapped] = React10.useState(false);
1888
+ React10.useEffect(() => {
1889
+ if (checkout || !cartToken || bootstrapped) return;
1890
+ setBootstrapped(true);
1891
+ void create(cartToken).catch(() => {
1892
+ });
1893
+ }, [checkout, cartToken, bootstrapped, create]);
1894
+ const serverStep = reachedStep(checkout);
1895
+ React10.useEffect(() => {
1896
+ setStep((cur) => rank(serverStep) > rank(cur) ? serverStep : cur);
1897
+ }, [serverStep]);
1898
+ if (checkout?.order_id) {
1899
+ return /* @__PURE__ */ jsx(Shell, { summary: /* @__PURE__ */ jsx(OrderSummary, { locale }), children: renderConfirmation ? renderConfirmation(checkout) : /* @__PURE__ */ jsx(DefaultConfirmation, { checkout }) });
1900
+ }
1901
+ if (!checkout) {
1902
+ if (loading || cartToken && !bootstrapped) {
1903
+ return /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)" }, children: t("checkout.loading") });
1904
+ }
1905
+ return /* @__PURE__ */ jsx(Fragment, { children: emptyState ?? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)" }, children: t("checkout.empty") }) });
1906
+ }
1907
+ return /* @__PURE__ */ jsxs(Shell, { summary: /* @__PURE__ */ jsx(OrderSummary, { locale }), children: [
1908
+ /* @__PURE__ */ jsx(Steps, { current: step, reached: serverStep, onJump: setStep }),
1909
+ step === "address" ? /* @__PURE__ */ jsx(AddressForm, { onComplete: () => setStep("shipping") }) : step === "shipping" ? /* @__PURE__ */ jsx(ShippingPicker, { onComplete: () => setStep("payment"), locale }) : /* @__PURE__ */ jsx(
1910
+ PaymentSection,
1911
+ {
1912
+ returnUrl,
1913
+ cancelUrl,
1914
+ onOrderPlaced,
1915
+ locale
1916
+ }
1917
+ )
1918
+ ] });
1919
+ }
1920
+ function rank(step) {
1921
+ return STEPS.indexOf(step);
1922
+ }
1923
+ function Shell({
1924
+ children,
1925
+ summary
1926
+ }) {
1927
+ return /* @__PURE__ */ jsxs(
1928
+ "div",
1929
+ {
1930
+ style: {
1931
+ display: "grid",
1932
+ gridTemplateColumns: "minmax(0, 1fr) minmax(0, 22rem)",
1933
+ gap: "2.5rem",
1934
+ alignItems: "start",
1935
+ fontFamily: "var(--nv-font)",
1936
+ color: "var(--nv-fg)"
1937
+ },
1938
+ children: [
1939
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem", minWidth: 0 }, children }),
1940
+ /* @__PURE__ */ jsx(
1941
+ "aside",
1942
+ {
1943
+ style: {
1944
+ position: "sticky",
1945
+ top: "1.5rem",
1946
+ padding: "1.25rem",
1947
+ borderRadius: "var(--nv-radius)",
1948
+ border: "1px solid var(--nv-border)",
1949
+ background: "var(--nv-bg)"
1950
+ },
1951
+ children: summary
1952
+ }
1953
+ )
1954
+ ]
1955
+ }
1956
+ );
1957
+ }
1958
+ function Steps({
1959
+ current,
1960
+ reached,
1961
+ onJump
1962
+ }) {
1963
+ const t = useT();
1964
+ return /* @__PURE__ */ jsx(
1965
+ "ol",
1966
+ {
1967
+ style: {
1968
+ listStyle: "none",
1969
+ display: "flex",
1970
+ gap: "0.5rem",
1971
+ margin: 0,
1972
+ padding: 0,
1973
+ fontSize: "0.875rem"
1974
+ },
1975
+ children: STEPS.map((s, i) => {
1976
+ const active = s === current;
1977
+ const visitable = rank(s) <= rank(reached);
1978
+ return /* @__PURE__ */ jsxs("li", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1979
+ /* @__PURE__ */ jsxs(
1980
+ "button",
1981
+ {
1982
+ type: "button",
1983
+ disabled: !visitable,
1984
+ onClick: () => visitable && onJump(s),
1985
+ style: {
1986
+ font: "inherit",
1987
+ fontWeight: active ? 600 : 400,
1988
+ color: active ? "var(--nv-fg)" : "var(--nv-muted)",
1989
+ background: "none",
1990
+ border: "none",
1991
+ padding: 0,
1992
+ cursor: visitable && !active ? "pointer" : "default"
1993
+ },
1994
+ children: [
1995
+ i + 1,
1996
+ ". ",
1997
+ t(STEP_KEY[s])
1998
+ ]
1999
+ }
2000
+ ),
2001
+ i < STEPS.length - 1 ? /* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)" }, children: "\u2192" }) : null
2002
+ ] }, s);
2003
+ })
2004
+ }
2005
+ );
2006
+ }
2007
+ function DefaultConfirmation({ checkout }) {
2008
+ const t = useT();
2009
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2010
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.3rem", fontWeight: 600 }, children: t("checkout.thankYou") }),
2011
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: t("checkout.orderPlacedBody", { order: `#${checkout.order_id}`, email: checkout.email ?? "" }) })
2012
+ ] });
2013
+ }
2014
+ function useOrderStatus(statusToken, initial) {
2015
+ const client = useStorefront();
2016
+ const [order, setOrder] = React10.useState(initial ?? null);
2017
+ const [loading, setLoading] = React10.useState(false);
2018
+ const [error, setError] = React10.useState(null);
2019
+ const load = React10.useCallback(async () => {
2020
+ if (!statusToken) return;
2021
+ setLoading(true);
2022
+ try {
2023
+ setOrder(await client.order.byStatusToken(statusToken));
2024
+ setError(null);
2025
+ } catch (e) {
2026
+ setError(e instanceof Error ? e : new Error(String(e)));
2027
+ } finally {
2028
+ setLoading(false);
2029
+ }
2030
+ }, [client, statusToken]);
2031
+ React10.useEffect(() => {
2032
+ if (initial) return;
2033
+ void load();
2034
+ }, [load, initial]);
2035
+ return { order, loading, error, reload: () => void load() };
2036
+ }
2037
+ var PHASE_RANK = {
2038
+ placed: 0,
2039
+ paid: 1,
2040
+ fulfilled: 2,
2041
+ shipped: 3,
2042
+ out_for_delivery: 4,
2043
+ delivered: 5,
2044
+ // terminal — never reached on the timeline
2045
+ returned: -1,
2046
+ refunded: -1,
2047
+ cancelled: -1
2048
+ };
2049
+ var MILESTONES = [
2050
+ { key: "order.phase.placed", rank: 0 },
2051
+ { key: "order.phase.paid", rank: 1 },
2052
+ { key: "order.phase.fulfilled", rank: 2 },
2053
+ { key: "order.phase.shipped", rank: 3 },
2054
+ { key: "order.phase.delivered", rank: 5 }
2055
+ ];
2056
+ var TERMINAL = {
2057
+ cancelled: { key: "order.terminal.cancelled", tone: "var(--nv-muted)" },
2058
+ refunded: { key: "order.terminal.refunded", tone: "var(--nv-muted)" },
2059
+ returned: { key: "order.terminal.returned", tone: "var(--nv-muted)" }
2060
+ };
2061
+ function isTerminal(phase) {
2062
+ return phase in TERMINAL;
2063
+ }
2064
+ function PhaseTimeline({ phase }) {
2065
+ const t = useT();
2066
+ if (isTerminal(phase)) return null;
2067
+ const current = PHASE_RANK[phase];
2068
+ return /* @__PURE__ */ jsx(
2069
+ "ol",
2070
+ {
2071
+ style: {
2072
+ listStyle: "none",
2073
+ display: "flex",
2074
+ margin: 0,
2075
+ padding: 0,
2076
+ gap: "0.25rem"
2077
+ },
2078
+ children: MILESTONES.map((m, i) => {
2079
+ const done = current >= m.rank;
2080
+ const active = m.rank === current || i === MILESTONES.length - 1 && current >= m.rank;
2081
+ return /* @__PURE__ */ jsxs("li", { style: { flex: 1, display: "flex", flexDirection: "column", gap: "0.4rem" }, children: [
2082
+ /* @__PURE__ */ jsx(
2083
+ "span",
2084
+ {
2085
+ "aria-hidden": true,
2086
+ style: {
2087
+ height: "0.35rem",
2088
+ borderRadius: "999px",
2089
+ background: done ? "var(--nv-brand)" : "var(--nv-border)"
2090
+ }
2091
+ }
2092
+ ),
2093
+ /* @__PURE__ */ jsx(
2094
+ "span",
2095
+ {
2096
+ style: {
2097
+ fontSize: "0.8125rem",
2098
+ fontWeight: active ? 600 : 400,
2099
+ color: done ? "var(--nv-fg)" : "var(--nv-muted)"
2100
+ },
2101
+ children: t(m.key)
2102
+ }
2103
+ )
2104
+ ] }, m.key);
2105
+ })
2106
+ }
2107
+ );
2108
+ }
2109
+ function StatusBanner({ phase }) {
2110
+ const t = useT();
2111
+ const meta = TERMINAL[phase];
2112
+ if (!meta) return null;
2113
+ return /* @__PURE__ */ jsx(
2114
+ "div",
2115
+ {
2116
+ style: {
2117
+ padding: "0.85rem 1rem",
2118
+ borderRadius: "var(--nv-radius)",
2119
+ border: "1px solid var(--nv-border)",
2120
+ background: "var(--nv-bg)",
2121
+ color: meta.tone,
2122
+ fontWeight: 500
2123
+ },
2124
+ children: t(meta.key)
2125
+ }
2126
+ );
2127
+ }
2128
+ function OrderLines({
2129
+ order,
2130
+ locale
2131
+ }) {
2132
+ return /* @__PURE__ */ jsxs("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2133
+ order.line_items.map((li) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
2134
+ li.image_url ? /* @__PURE__ */ jsx(
2135
+ "img",
2136
+ {
2137
+ src: li.image_url,
2138
+ alt: "",
2139
+ width: 48,
2140
+ height: 48,
2141
+ style: { borderRadius: "var(--nv-radius)", objectFit: "cover", flexShrink: 0 }
2142
+ }
2143
+ ) : null,
2144
+ /* @__PURE__ */ jsxs("span", { style: { flex: 1, minWidth: 0 }, children: [
2145
+ /* @__PURE__ */ jsx("span", { style: { display: "block", fontWeight: 500 }, children: li.title }),
2146
+ li.variant_title ? /* @__PURE__ */ jsx("span", { style: { display: "block", fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: li.variant_title }) : null,
2147
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: [
2148
+ "\xD7",
2149
+ li.quantity
2150
+ ] })
2151
+ ] }),
2152
+ /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(li.total_with_tax_cents, order.currency, locale) })
2153
+ ] }, li.id)),
2154
+ order.fee_lines.map((f, i) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: "0.75rem", alignItems: "center" }, children: [
2155
+ /* @__PURE__ */ jsx("span", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx("span", { style: { display: "block", fontWeight: 500 }, children: f.title }) }),
2156
+ /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: formatCents(f.total_with_tax_cents, order.currency, locale) })
2157
+ ] }, `fee-${i}`))
2158
+ ] });
2159
+ }
2160
+ function OrderTotals({
2161
+ order,
2162
+ locale
2163
+ }) {
2164
+ const tr = useT();
2165
+ const t = order.totals;
2166
+ const c = order.currency;
2167
+ const money = (cents) => formatCents(cents, c, locale);
2168
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2169
+ /* @__PURE__ */ jsx(Row3, { label: tr("totals.subtotal"), value: money(t.subtotal_cents) }),
2170
+ t.discount_cents > 0 ? /* @__PURE__ */ jsx(Row3, { label: tr("totals.discount"), value: `\u2212${money(t.discount_cents)}`, muted: true }) : null,
2171
+ t.shipping_cents > 0 ? /* @__PURE__ */ jsx(Row3, { label: tr("totals.shipping"), value: money(t.shipping_cents), muted: true }) : null,
2172
+ t.surcharge_cents > 0 ? /* @__PURE__ */ jsx(Row3, { label: tr("totals.paymentFee"), value: money(t.surcharge_cents), muted: true }) : null,
2173
+ t.tax_cents > 0 ? /* @__PURE__ */ jsx(Row3, { label: tr("totals.taxIncluded"), value: money(t.tax_cents), muted: true }) : null,
2174
+ /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
2175
+ /* @__PURE__ */ jsx(Row3, { label: tr("totals.total"), value: money(t.total_cents), strong: true })
2176
+ ] });
2177
+ }
2178
+ function Row3({
2179
+ label,
2180
+ value,
2181
+ strong,
2182
+ muted
2183
+ }) {
2184
+ return /* @__PURE__ */ jsxs(
2185
+ "div",
2186
+ {
2187
+ style: {
2188
+ display: "flex",
2189
+ justifyContent: "space-between",
2190
+ fontWeight: strong ? 600 : 400,
2191
+ color: muted ? "var(--nv-muted)" : "inherit",
2192
+ fontSize: strong ? "1.1em" : "1em"
2193
+ },
2194
+ children: [
2195
+ /* @__PURE__ */ jsx("span", { children: label }),
2196
+ /* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: value })
2197
+ ]
2198
+ }
2199
+ );
2200
+ }
2201
+ function OrderConfirmation({
2202
+ statusToken,
2203
+ order: initial,
2204
+ statusHref,
2205
+ title,
2206
+ locale
2207
+ }) {
2208
+ const t = useT();
2209
+ const { order, loading, error } = useOrderStatus(statusToken ?? null, initial);
2210
+ if (!order) {
2211
+ return /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)" }, children: loading ? t("order.confirmLoading") : error ? t("order.confirmLoadError") : t("order.notFound") });
2212
+ }
2213
+ return /* @__PURE__ */ jsxs(
2214
+ "div",
2215
+ {
2216
+ style: {
2217
+ display: "flex",
2218
+ flexDirection: "column",
2219
+ gap: "1.25rem",
2220
+ fontFamily: "var(--nv-font)",
2221
+ color: "var(--nv-fg)",
2222
+ maxWidth: "34rem"
2223
+ },
2224
+ children: [
2225
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.4rem" }, children: [
2226
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.4rem", fontWeight: 600 }, children: title ?? t("checkout.thankYou") }),
2227
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: t("order.confirmed", { number: order.order_number }) })
2228
+ ] }),
2229
+ /* @__PURE__ */ jsxs(
2230
+ "div",
2231
+ {
2232
+ style: {
2233
+ display: "flex",
2234
+ flexDirection: "column",
2235
+ gap: "1rem",
2236
+ padding: "1.25rem",
2237
+ borderRadius: "var(--nv-radius)",
2238
+ border: "1px solid var(--nv-border)",
2239
+ background: "var(--nv-bg)"
2240
+ },
2241
+ children: [
2242
+ /* @__PURE__ */ jsx(OrderLines, { order, locale }),
2243
+ /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
2244
+ /* @__PURE__ */ jsx(OrderTotals, { order, locale })
2245
+ ]
2246
+ }
2247
+ ),
2248
+ statusHref ? /* @__PURE__ */ jsx(
2249
+ "a",
2250
+ {
2251
+ href: statusHref,
2252
+ style: {
2253
+ alignSelf: "flex-start",
2254
+ font: "inherit",
2255
+ fontWeight: 500,
2256
+ textDecoration: "none",
2257
+ padding: "0.7rem 1.4rem",
2258
+ borderRadius: "var(--nv-radius)",
2259
+ background: "var(--nv-brand)",
2260
+ color: "var(--nv-brand-foreground)"
2261
+ },
2262
+ children: t("order.trackOrder")
2263
+ }
2264
+ ) : null
2265
+ ]
2266
+ }
2267
+ );
2268
+ }
2269
+ function OrderStatusPage({
2270
+ statusToken,
2271
+ order: initial,
2272
+ onContactSupport,
2273
+ locale
2274
+ }) {
2275
+ const t = useT();
2276
+ const { order, loading, error } = useOrderStatus(statusToken ?? null, initial);
2277
+ if (!order) {
2278
+ return /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)" }, children: loading ? t("order.loading") : error ? t("order.loadError") : t("order.notFound") });
2279
+ }
2280
+ const placed = new Date(order.placed_at);
2281
+ const placedLabel = isNaN(placed.getTime()) ? order.placed_at : placed.toLocaleDateString(locale, { year: "numeric", month: "long", day: "numeric" });
2282
+ return /* @__PURE__ */ jsxs(
2283
+ "div",
2284
+ {
2285
+ style: {
2286
+ display: "flex",
2287
+ flexDirection: "column",
2288
+ gap: "1.5rem",
2289
+ fontFamily: "var(--nv-font)",
2290
+ color: "var(--nv-fg)",
2291
+ maxWidth: "40rem"
2292
+ },
2293
+ children: [
2294
+ /* @__PURE__ */ jsxs("header", { style: { display: "flex", flexDirection: "column", gap: "0.3rem" }, children: [
2295
+ /* @__PURE__ */ jsx("h1", { style: { margin: 0, fontSize: "1.5rem", fontWeight: 600 }, children: t("order.title", { number: order.order_number }) }),
2296
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: t("order.placedOn", { date: placedLabel }) })
2297
+ ] }),
2298
+ isTerminal(order.public_phase) ? /* @__PURE__ */ jsx(StatusBanner, { phase: order.public_phase }) : /* @__PURE__ */ jsx(PhaseTimeline, { phase: order.public_phase }),
2299
+ /* @__PURE__ */ jsxs(Card, { title: t("order.items"), children: [
2300
+ /* @__PURE__ */ jsx(OrderLines, { order, locale }),
2301
+ /* @__PURE__ */ jsx("div", { style: { height: 1, background: "var(--nv-border)" } }),
2302
+ /* @__PURE__ */ jsx(OrderTotals, { order, locale })
2303
+ ] }),
2304
+ order.shipping_method || order.tracking_numbers.length > 0 ? /* @__PURE__ */ jsxs(Card, { title: t("order.shipping"), children: [
2305
+ order.shipping_method ? /* @__PURE__ */ jsx(
2306
+ Line,
2307
+ {
2308
+ label: order.shipping_method.name ?? t("order.shipping"),
2309
+ value: order.shipping_method.pickup_point_name ?? order.shipping_method.carrier ?? ""
2310
+ }
2311
+ ) : null,
2312
+ /* @__PURE__ */ jsx(
2313
+ Line,
2314
+ {
2315
+ label: t("order.shipsTo"),
2316
+ value: [order.shipping_address_summary.city, order.shipping_address_summary.country].filter(Boolean).join(", ")
2317
+ }
2318
+ ),
2319
+ order.tracking_numbers.length > 0 ? /* @__PURE__ */ jsx(Line, { label: t("order.tracking"), value: order.tracking_numbers.join(", ") }) : null
2320
+ ] }) : null,
2321
+ /* @__PURE__ */ jsxs(Card, { title: t("order.payment"), children: [
2322
+ /* @__PURE__ */ jsx(Line, { label: t("order.method"), value: order.payment.method ?? "\u2014" }),
2323
+ /* @__PURE__ */ jsx(Line, { label: t("order.status"), value: order.payment.status }),
2324
+ order.payment.invoice_available && order.payment.invoice_url ? /* @__PURE__ */ jsx("a", { href: order.payment.invoice_url, style: { color: "var(--nv-brand)" }, children: t("order.downloadInvoice") }) : null
2325
+ ] }),
2326
+ order.actions.can_contact_support && onContactSupport ? /* @__PURE__ */ jsx(
2327
+ "button",
2328
+ {
2329
+ type: "button",
2330
+ onClick: onContactSupport,
2331
+ style: {
2332
+ alignSelf: "flex-start",
2333
+ font: "inherit",
2334
+ fontWeight: 500,
2335
+ cursor: "pointer",
2336
+ padding: "0.65rem 1.3rem",
2337
+ borderRadius: "var(--nv-radius)",
2338
+ border: "1px solid var(--nv-border)",
2339
+ background: "var(--nv-bg)",
2340
+ color: "var(--nv-fg)"
2341
+ },
2342
+ children: t("order.contactSupport")
2343
+ }
2344
+ ) : null
2345
+ ]
2346
+ }
2347
+ );
2348
+ }
2349
+ function Card({ title, children }) {
2350
+ return /* @__PURE__ */ jsxs(
2351
+ "section",
2352
+ {
2353
+ style: {
2354
+ display: "flex",
2355
+ flexDirection: "column",
2356
+ gap: "0.85rem",
2357
+ padding: "1.25rem",
2358
+ borderRadius: "var(--nv-radius)",
2359
+ border: "1px solid var(--nv-border)",
2360
+ background: "var(--nv-bg)"
2361
+ },
2362
+ children: [
2363
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1rem", fontWeight: 600 }, children: title }),
2364
+ children
2365
+ ]
2366
+ }
2367
+ );
2368
+ }
2369
+ function Line({ label, value }) {
2370
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", gap: "1rem" }, children: [
2371
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)" }, children: label }),
2372
+ /* @__PURE__ */ jsx("span", { style: { textAlign: "right" }, children: value })
2373
+ ] });
2374
+ }
2375
+ var AccountContext = React10.createContext(null);
2376
+ function AccountProvider({ children }) {
2377
+ const client = useStorefront();
2378
+ const [customer, setCustomer] = React10.useState(null);
2379
+ const [loading, setLoading] = React10.useState(true);
2380
+ const refresh = React10.useCallback(async () => {
2381
+ setLoading(true);
2382
+ try {
2383
+ setCustomer(await client.account.me());
2384
+ } finally {
2385
+ setLoading(false);
2386
+ }
2387
+ }, [client]);
2388
+ React10.useEffect(() => {
2389
+ void refresh();
2390
+ }, [refresh]);
2391
+ const value = React10.useMemo(
2392
+ () => ({
2393
+ customer,
2394
+ signedIn: customer != null,
2395
+ loading,
2396
+ requestMagicLink: (email) => client.account.requestMagicLink(email),
2397
+ verify: async (token) => {
2398
+ const c = await client.account.verify(token);
2399
+ setCustomer(c);
2400
+ return c;
2401
+ },
2402
+ logout: async () => {
2403
+ await client.account.logout();
2404
+ setCustomer(null);
2405
+ },
2406
+ refresh
2407
+ }),
2408
+ [customer, loading, client, refresh]
2409
+ );
2410
+ return /* @__PURE__ */ jsx(AccountContext.Provider, { value, children });
2411
+ }
2412
+ function useAccount() {
2413
+ const ctx = React10.useContext(AccountContext);
2414
+ if (!ctx) {
2415
+ throw new Error("useAccount must be used inside <AccountProvider>.");
2416
+ }
2417
+ return ctx;
2418
+ }
2419
+ function useMagicLinkVerify(token) {
2420
+ const { verify } = useAccount();
2421
+ const [status, setStatus] = React10.useState("idle");
2422
+ const done = React10.useRef(false);
2423
+ React10.useEffect(() => {
2424
+ if (!token || done.current) return;
2425
+ done.current = true;
2426
+ setStatus("verifying");
2427
+ verify(token).then(() => setStatus("success")).catch(() => setStatus("error"));
2428
+ }, [token, verify]);
2429
+ return { status };
2430
+ }
2431
+ function LoginForm({ verifyPath = "/account/verify", onSent }) {
2432
+ const t = useT();
2433
+ const { requestMagicLink } = useAccount();
2434
+ const [email, setEmail] = React10.useState("");
2435
+ const [busy, setBusy] = React10.useState(false);
2436
+ const [sent, setSent] = React10.useState(false);
2437
+ const [devLink, setDevLink] = React10.useState(null);
2438
+ async function submit(e) {
2439
+ e.preventDefault();
2440
+ setBusy(true);
2441
+ try {
2442
+ const r = await requestMagicLink(email);
2443
+ setSent(true);
2444
+ if (r.devToken) setDevLink(`${verifyPath}?token=${encodeURIComponent(r.devToken)}`);
2445
+ onSent?.(email);
2446
+ } finally {
2447
+ setBusy(false);
2448
+ }
2449
+ }
2450
+ if (sent) {
2451
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem", maxWidth: "24rem" }, children: [
2452
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-fg)" }, children: t("account.checkEmail") }),
2453
+ devLink ? /* @__PURE__ */ jsx("a", { href: devLink, style: { color: "var(--nv-brand)", fontSize: "0.875rem" }, children: t("account.openDevLink") }) : null
2454
+ ] });
2455
+ }
2456
+ return /* @__PURE__ */ jsxs(
2457
+ "form",
2458
+ {
2459
+ onSubmit: submit,
2460
+ style: { display: "flex", flexDirection: "column", gap: "0.75rem", maxWidth: "24rem", fontFamily: "var(--nv-font)" },
2461
+ children: [
2462
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "var(--nv-muted)" }, children: t("account.signInBlurb") }),
2463
+ /* @__PURE__ */ jsxs("label", { style: { display: "flex", flexDirection: "column", gap: "0.35rem", fontSize: "0.875rem" }, children: [
2464
+ /* @__PURE__ */ jsx("span", { children: t("account.email") }),
2465
+ /* @__PURE__ */ jsx(
2466
+ "input",
2467
+ {
2468
+ type: "email",
2469
+ required: true,
2470
+ value: email,
2471
+ onChange: (e) => setEmail(e.target.value),
2472
+ autoComplete: "email",
2473
+ style: {
2474
+ font: "inherit",
2475
+ padding: "0.6rem 0.75rem",
2476
+ borderRadius: "var(--nv-radius)",
2477
+ border: "1px solid var(--nv-border)",
2478
+ background: "var(--nv-bg)",
2479
+ color: "var(--nv-fg)"
2480
+ }
2481
+ }
2482
+ )
2483
+ ] }),
2484
+ /* @__PURE__ */ jsx(
2485
+ "button",
2486
+ {
2487
+ type: "submit",
2488
+ disabled: busy,
2489
+ style: {
2490
+ font: "inherit",
2491
+ fontWeight: 500,
2492
+ cursor: busy ? "default" : "pointer",
2493
+ padding: "0.65rem 1.3rem",
2494
+ borderRadius: "var(--nv-radius)",
2495
+ border: "none",
2496
+ background: "var(--nv-brand)",
2497
+ color: "var(--nv-brand-foreground)",
2498
+ opacity: busy ? 0.6 : 1
2499
+ },
2500
+ children: busy ? t("common.loadingShort") : t("account.sendLink")
2501
+ }
2502
+ )
2503
+ ]
2504
+ }
2505
+ );
2506
+ }
2507
+ function AccountDashboard({ children }) {
2508
+ const t = useT();
2509
+ const { customer, logout } = useAccount();
2510
+ if (customer == null) return null;
2511
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem", fontFamily: "var(--nv-font)", color: "var(--nv-fg)" }, children: [
2512
+ /* @__PURE__ */ jsxs("header", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", gap: "1rem" }, children: [
2513
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)" }, children: t("account.greeting", { email: customer.email }) }),
2514
+ /* @__PURE__ */ jsx(
2515
+ "button",
2516
+ {
2517
+ type: "button",
2518
+ onClick: () => void logout(),
2519
+ style: {
2520
+ font: "inherit",
2521
+ cursor: "pointer",
2522
+ padding: "0.45rem 1rem",
2523
+ borderRadius: "var(--nv-radius)",
2524
+ border: "1px solid var(--nv-border)",
2525
+ background: "var(--nv-bg)",
2526
+ color: "var(--nv-fg)"
2527
+ },
2528
+ children: t("account.signOut")
2529
+ }
2530
+ )
2531
+ ] }),
2532
+ children
2533
+ ] });
2534
+ }
2535
+ function OrderHistory({
2536
+ statusHref = (token) => `/order/${token}`,
2537
+ cartHref = "/cart",
2538
+ onReorder,
2539
+ locale
2540
+ }) {
2541
+ const t = useT();
2542
+ const loc = useFormatLocale(locale);
2543
+ const { signedIn } = useAccount();
2544
+ const client = useStorefront();
2545
+ const [orders, setOrders] = React10.useState(null);
2546
+ const [reordering, setReordering] = React10.useState(null);
2547
+ const [notice, setNotice] = React10.useState(null);
2548
+ React10.useEffect(() => {
2549
+ let live = true;
2550
+ if (!signedIn) {
2551
+ setOrders([]);
2552
+ return;
2553
+ }
2554
+ client.account.orders().then((o) => live && setOrders(o)).catch(() => live && setOrders([]));
2555
+ return () => {
2556
+ live = false;
2557
+ };
2558
+ }, [signedIn, client]);
2559
+ async function reorder(statusToken) {
2560
+ setReordering(statusToken);
2561
+ setNotice(null);
2562
+ try {
2563
+ const result = await client.account.reorder(statusToken);
2564
+ if (onReorder) {
2565
+ onReorder(result);
2566
+ } else {
2567
+ const text = result.skipped > 0 ? t("account.reorderPartial", { added: result.added, skipped: result.skipped }) : t("account.reorderDone", { added: result.added });
2568
+ setNotice({ token: statusToken, text });
2569
+ if (typeof window !== "undefined") window.location.assign(cartHref);
2570
+ }
2571
+ } catch {
2572
+ setNotice({ token: statusToken, text: t("account.reorderError"), error: true });
2573
+ } finally {
2574
+ setReordering(null);
2575
+ }
2576
+ }
2577
+ return /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2578
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.1rem", fontWeight: 600 }, children: t("account.orders") }),
2579
+ orders == null ? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("common.loadingShort") }) : orders.length === 0 ? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("account.noOrders") }) : /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.5rem" }, children: orders.map((o) => /* @__PURE__ */ jsxs(
2580
+ "li",
2581
+ {
2582
+ style: {
2583
+ display: "flex",
2584
+ flexDirection: "column",
2585
+ gap: "0.5rem",
2586
+ padding: "0.85rem 1rem",
2587
+ border: "1px solid var(--nv-border)",
2588
+ borderRadius: "var(--nv-radius)"
2589
+ },
2590
+ children: [
2591
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", gap: "1rem" }, children: [
2592
+ /* @__PURE__ */ jsxs("span", { style: { display: "flex", flexDirection: "column" }, children: [
2593
+ /* @__PURE__ */ jsx("strong", { style: { fontWeight: 600 }, children: o.number }),
2594
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "0.8125rem", color: "var(--nv-muted)" }, children: [
2595
+ formatCents(o.total_cents, o.currency, loc),
2596
+ o.placed_at ? ` \xB7 ${new Date(o.placed_at).toLocaleDateString(loc)}` : ""
2597
+ ] })
2598
+ ] }),
2599
+ /* @__PURE__ */ jsxs("span", { style: { display: "flex", gap: "1rem", alignItems: "center", whiteSpace: "nowrap" }, children: [
2600
+ /* @__PURE__ */ jsx(
2601
+ "button",
2602
+ {
2603
+ type: "button",
2604
+ onClick: () => void reorder(o.status_token),
2605
+ disabled: reordering === o.status_token,
2606
+ style: {
2607
+ font: "inherit",
2608
+ fontSize: "0.875rem",
2609
+ cursor: reordering === o.status_token ? "default" : "pointer",
2610
+ background: "none",
2611
+ border: "none",
2612
+ color: "var(--nv-brand)",
2613
+ padding: 0,
2614
+ opacity: reordering === o.status_token ? 0.6 : 1
2615
+ },
2616
+ children: reordering === o.status_token ? "\u2026" : t("account.reorder")
2617
+ }
2618
+ ),
2619
+ /* @__PURE__ */ jsx("a", { href: statusHref(o.status_token), style: { color: "var(--nv-brand)", fontSize: "0.875rem" }, children: t("account.viewOrder") })
2620
+ ] })
2621
+ ] }),
2622
+ notice && notice.token === o.status_token ? /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "0.8125rem", color: notice.error ? "#b3261e" : "var(--nv-muted)" }, children: notice.text }) : null
2623
+ ]
2624
+ },
2625
+ o.status_token
2626
+ )) })
2627
+ ] });
2628
+ }
2629
+ function AddressForm2({ initial, onSubmit, onCancel, busy }) {
2630
+ const t = useT();
2631
+ const [form, setForm] = React10.useState(() => ({
2632
+ first_name: initial?.first_name ?? "",
2633
+ last_name: initial?.last_name ?? "",
2634
+ company: initial?.company ?? "",
2635
+ address1: initial?.address1 ?? "",
2636
+ address2: initial?.address2 ?? "",
2637
+ city: initial?.city ?? "",
2638
+ zip: initial?.zip ?? "",
2639
+ country_code: initial?.country_code ?? "",
2640
+ phone: initial?.phone ?? "",
2641
+ is_default: Boolean(initial?.is_default)
2642
+ }));
2643
+ const set = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value }));
2644
+ return /* @__PURE__ */ jsxs(
2645
+ "form",
2646
+ {
2647
+ onSubmit: (e) => {
2648
+ e.preventDefault();
2649
+ void onSubmit(form);
2650
+ },
2651
+ style: { display: "flex", flexDirection: "column", gap: "0.75rem" },
2652
+ children: [
2653
+ /* @__PURE__ */ jsxs(FieldRow, { children: [
2654
+ /* @__PURE__ */ jsx(Field, { label: t("account.firstName"), value: form.first_name ?? "", onChange: set("first_name") }),
2655
+ /* @__PURE__ */ jsx(Field, { label: t("account.lastName"), value: form.last_name ?? "", onChange: set("last_name") })
2656
+ ] }),
2657
+ /* @__PURE__ */ jsx(Field, { label: t("account.company"), value: form.company ?? "", onChange: set("company") }),
2658
+ /* @__PURE__ */ jsx(Field, { label: t("account.address"), required: true, value: form.address1 ?? "", onChange: set("address1") }),
2659
+ /* @__PURE__ */ jsx(Field, { label: t("account.addressLine2"), value: form.address2 ?? "", onChange: set("address2") }),
2660
+ /* @__PURE__ */ jsxs(FieldRow, { children: [
2661
+ /* @__PURE__ */ jsx(Field, { label: t("account.city"), required: true, value: form.city ?? "", onChange: set("city") }),
2662
+ /* @__PURE__ */ jsx(Field, { label: t("account.postalCode"), required: true, value: form.zip ?? "", onChange: set("zip") }),
2663
+ /* @__PURE__ */ jsx(Field, { label: t("account.country"), required: true, value: form.country_code ?? "", onChange: set("country_code") })
2664
+ ] }),
2665
+ /* @__PURE__ */ jsx(Field, { label: t("account.phone"), value: form.phone ?? "", onChange: set("phone") }),
2666
+ /* @__PURE__ */ jsxs("label", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem", cursor: "pointer", fontSize: "0.875rem" }, children: [
2667
+ /* @__PURE__ */ jsx(
2668
+ "input",
2669
+ {
2670
+ type: "checkbox",
2671
+ checked: Boolean(form.is_default),
2672
+ onChange: (e) => setForm((f) => ({ ...f, is_default: e.target.checked }))
2673
+ }
2674
+ ),
2675
+ t("account.setDefault")
2676
+ ] }),
2677
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem" }, children: [
2678
+ /* @__PURE__ */ jsx(Button, { type: "submit", busy, children: t("account.save") }),
2679
+ onCancel ? /* @__PURE__ */ jsx(
2680
+ "button",
2681
+ {
2682
+ type: "button",
2683
+ onClick: onCancel,
2684
+ style: {
2685
+ font: "inherit",
2686
+ cursor: "pointer",
2687
+ padding: "0.75rem 1.25rem",
2688
+ borderRadius: "var(--nv-radius)",
2689
+ border: "1px solid var(--nv-border)",
2690
+ background: "transparent",
2691
+ color: "var(--nv-fg)"
2692
+ },
2693
+ children: t("account.cancel")
2694
+ }
2695
+ ) : null
2696
+ ] })
2697
+ ]
2698
+ }
2699
+ );
2700
+ }
2701
+ function formatAddress(a) {
2702
+ const name = [a.first_name, a.last_name].filter(Boolean).join(" ");
2703
+ const line = [a.address1, a.address2].filter(Boolean).join(", ");
2704
+ const place = [a.zip, a.city, a.country_code].filter(Boolean).join(" ");
2705
+ return [name, line, place].filter(Boolean).join(" \xB7 ");
2706
+ }
2707
+ var rowStyle = {
2708
+ padding: "0.85rem 1rem",
2709
+ border: "1px solid var(--nv-border)",
2710
+ borderRadius: "var(--nv-radius)",
2711
+ color: "var(--nv-fg)",
2712
+ display: "flex",
2713
+ flexDirection: "column",
2714
+ gap: "0.5rem"
2715
+ };
2716
+ var linkBtn = {
2717
+ font: "inherit",
2718
+ fontSize: "0.8125rem",
2719
+ cursor: "pointer",
2720
+ background: "none",
2721
+ border: "none",
2722
+ color: "var(--nv-brand)",
2723
+ padding: 0
2724
+ };
2725
+ function AddressBook() {
2726
+ const t = useT();
2727
+ const { signedIn } = useAccount();
2728
+ const client = useStorefront();
2729
+ const [addresses, setAddresses] = React10.useState(null);
2730
+ const [mode, setMode] = React10.useState({ kind: "list" });
2731
+ const [busy, setBusy] = React10.useState(false);
2732
+ const load = React10.useCallback(() => {
2733
+ if (!signedIn) {
2734
+ setAddresses([]);
2735
+ return;
2736
+ }
2737
+ client.account.addresses().then(setAddresses).catch(() => setAddresses([]));
2738
+ }, [signedIn, client]);
2739
+ React10.useEffect(() => {
2740
+ load();
2741
+ }, [load]);
2742
+ async function run(fn) {
2743
+ setBusy(true);
2744
+ try {
2745
+ await fn();
2746
+ setMode({ kind: "list" });
2747
+ load();
2748
+ } finally {
2749
+ setBusy(false);
2750
+ }
2751
+ }
2752
+ const create = (data) => run(() => client.account.addAddress(data));
2753
+ const update = (id, data) => run(() => client.account.updateAddress(id, data));
2754
+ const remove = (id) => {
2755
+ if (typeof window !== "undefined" && !window.confirm(t("account.confirmDelete"))) return;
2756
+ void run(() => client.account.deleteAddress(id));
2757
+ };
2758
+ return /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2759
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", gap: "1rem" }, children: [
2760
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.1rem", fontWeight: 600 }, children: t("account.addresses") }),
2761
+ mode.kind === "list" ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setMode({ kind: "add" }), style: { ...linkBtn, fontSize: "0.875rem" }, children: t("account.addAddress") }) : null
2762
+ ] }),
2763
+ mode.kind === "add" ? /* @__PURE__ */ jsx(AddressForm2, { onSubmit: create, onCancel: () => setMode({ kind: "list" }), busy }) : null,
2764
+ addresses == null ? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("common.loadingShort") }) : addresses.length === 0 && mode.kind === "list" ? /* @__PURE__ */ jsx("p", { style: { color: "var(--nv-muted)", margin: 0 }, children: t("account.noAddresses") }) : /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "0.5rem" }, children: addresses.map((a, i) => {
2765
+ const id = a.id ?? String(i);
2766
+ const isEditing = mode.kind === "edit" && mode.id === id;
2767
+ return /* @__PURE__ */ jsx("li", { style: rowStyle, children: isEditing ? /* @__PURE__ */ jsx(
2768
+ AddressForm2,
2769
+ {
2770
+ initial: a,
2771
+ onSubmit: (data) => update(id, data),
2772
+ onCancel: () => setMode({ kind: "list" }),
2773
+ busy
2774
+ }
2775
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2776
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", gap: "1rem", alignItems: "baseline" }, children: [
2777
+ /* @__PURE__ */ jsx("span", { children: formatAddress(a) }),
2778
+ a.is_default ? /* @__PURE__ */ jsx("span", { style: { fontSize: "0.7rem", fontWeight: 600, color: "var(--nv-muted)", textTransform: "uppercase" }, children: t("account.default") }) : null
2779
+ ] }),
2780
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "1rem" }, children: [
2781
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setMode({ kind: "edit", id }), style: linkBtn, children: t("account.editAddress") }),
2782
+ !a.is_default ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void update(id, { is_default: true }), style: linkBtn, children: t("account.setDefault") }) : null,
2783
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => remove(id), style: { ...linkBtn, color: "#b3261e" }, children: t("account.deleteAddress") })
2784
+ ] })
2785
+ ] }) }, id);
2786
+ }) })
2787
+ ] });
2788
+ }
2789
+ function ProfileEditor() {
2790
+ const t = useT();
2791
+ const client = useStorefront();
2792
+ const { customer, refresh } = useAccount();
2793
+ const [editing, setEditing] = React10.useState(false);
2794
+ const [busy, setBusy] = React10.useState(false);
2795
+ const [error, setError] = React10.useState(false);
2796
+ const [form, setForm] = React10.useState({});
2797
+ if (!customer) return null;
2798
+ function startEdit() {
2799
+ setForm({
2800
+ first_name: customer.first_name ?? "",
2801
+ last_name: customer.last_name ?? "",
2802
+ phone: customer.phone ?? "",
2803
+ accepts_marketing: customer.accepts_marketing
2804
+ });
2805
+ setError(false);
2806
+ setEditing(true);
2807
+ }
2808
+ async function save() {
2809
+ setBusy(true);
2810
+ setError(false);
2811
+ try {
2812
+ await client.account.updateProfile(form);
2813
+ await refresh();
2814
+ setEditing(false);
2815
+ } catch {
2816
+ setError(true);
2817
+ } finally {
2818
+ setBusy(false);
2819
+ }
2820
+ }
2821
+ const name = [customer.first_name, customer.last_name].filter(Boolean).join(" ");
2822
+ return /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2823
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", gap: "1rem" }, children: [
2824
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.1rem", fontWeight: 600 }, children: t("account.profile") }),
2825
+ !editing ? /* @__PURE__ */ jsx(
2826
+ "button",
2827
+ {
2828
+ type: "button",
2829
+ onClick: startEdit,
2830
+ style: { font: "inherit", cursor: "pointer", background: "none", border: "none", color: "var(--nv-brand)", fontSize: "0.875rem" },
2831
+ children: t("account.editProfile")
2832
+ }
2833
+ ) : null
2834
+ ] }),
2835
+ !editing ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem", color: "var(--nv-fg)" }, children: [
2836
+ name ? /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: name }) : null,
2837
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)", fontSize: "0.9rem" }, children: customer.email }),
2838
+ customer.phone ? /* @__PURE__ */ jsx("span", { style: { color: "var(--nv-muted)", fontSize: "0.9rem" }, children: customer.phone }) : null
2839
+ ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: (e) => {
2840
+ e.preventDefault();
2841
+ void save();
2842
+ }, style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2843
+ /* @__PURE__ */ jsx(Field, { label: t("account.firstName"), value: form.first_name ?? "", onChange: (e) => setForm((f) => ({ ...f, first_name: e.target.value })) }),
2844
+ /* @__PURE__ */ jsx(Field, { label: t("account.lastName"), value: form.last_name ?? "", onChange: (e) => setForm((f) => ({ ...f, last_name: e.target.value })) }),
2845
+ /* @__PURE__ */ jsx(Field, { label: t("account.phone"), value: form.phone ?? "", onChange: (e) => setForm((f) => ({ ...f, phone: e.target.value })) }),
2846
+ /* @__PURE__ */ jsxs("label", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem", cursor: "pointer", fontSize: "0.875rem" }, children: [
2847
+ /* @__PURE__ */ jsx(
2848
+ "input",
2849
+ {
2850
+ type: "checkbox",
2851
+ checked: Boolean(form.accepts_marketing),
2852
+ onChange: (e) => setForm((f) => ({ ...f, accepts_marketing: e.target.checked }))
2853
+ }
2854
+ ),
2855
+ t("account.acceptsMarketing")
2856
+ ] }),
2857
+ error ? /* @__PURE__ */ jsx("p", { style: { margin: 0, color: "#b3261e", fontSize: "0.8125rem" }, children: t("account.saveError") }) : null,
2858
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem" }, children: [
2859
+ /* @__PURE__ */ jsx(Button, { type: "submit", busy, children: t("account.save") }),
2860
+ /* @__PURE__ */ jsx(
2861
+ "button",
2862
+ {
2863
+ type: "button",
2864
+ onClick: () => setEditing(false),
2865
+ style: { font: "inherit", cursor: "pointer", padding: "0.75rem 1.25rem", borderRadius: "var(--nv-radius)", border: "1px solid var(--nv-border)", background: "transparent", color: "var(--nv-fg)" },
2866
+ children: t("account.cancel")
2867
+ }
2868
+ )
2869
+ ] })
2870
+ ] })
2871
+ ] });
2872
+ }
2873
+ function serializeJsonLd(data) {
2874
+ return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
2875
+ }
2876
+ function stripHtml(html) {
2877
+ if (!html) return void 0;
2878
+ const text = html.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
2879
+ return text || void 0;
2880
+ }
2881
+ function absoluteUrl(url, base) {
2882
+ if (!url) return url;
2883
+ if (/^https?:\/\//i.test(url) || url.startsWith("data:")) return url;
2884
+ if (!base) return url;
2885
+ return `${base.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}`;
2886
+ }
2887
+ function compact(obj) {
2888
+ const out = {};
2889
+ for (const [k, v] of Object.entries(obj)) {
2890
+ if (v !== null && v !== void 0) out[k] = v;
2891
+ }
2892
+ return out;
2893
+ }
2894
+ function JsonLd({ data }) {
2895
+ return /* @__PURE__ */ jsx(
2896
+ "script",
2897
+ {
2898
+ type: "application/ld+json",
2899
+ dangerouslySetInnerHTML: { __html: serializeJsonLd(data) }
2900
+ }
2901
+ );
2902
+ }
2903
+ var SCHEMA_AVAILABILITY = {
2904
+ in_stock: "https://schema.org/InStock",
2905
+ preorder: "https://schema.org/PreOrder",
2906
+ out_of_stock: "https://schema.org/OutOfStock"
2907
+ };
2908
+ function ProductJsonLd({
2909
+ product,
2910
+ url,
2911
+ baseUrl,
2912
+ brandName
2913
+ }) {
2914
+ const origin = baseUrl ?? safeOrigin(url);
2915
+ const images = product.media.map((m) => absoluteUrl(m.url, origin));
2916
+ const brand = brandName ?? product.vendor;
2917
+ const offers = product.variants.map(
2918
+ (v) => compact({
2919
+ "@type": "Offer",
2920
+ price: (v.price.amount_cents / 100).toFixed(2),
2921
+ priceCurrency: v.price.currency,
2922
+ availability: SCHEMA_AVAILABILITY[v.availability?.status ?? "in_stock"],
2923
+ sku: v.sku ?? void 0,
2924
+ url
2925
+ })
2926
+ );
2927
+ const data = compact({
2928
+ "@context": "https://schema.org",
2929
+ "@type": "Product",
2930
+ name: product.title,
2931
+ description: stripHtml(product.description_html),
2932
+ image: images.length ? images : void 0,
2933
+ sku: product.variants[0]?.sku ?? void 0,
2934
+ brand: brand ? { "@type": "Brand", name: brand } : void 0,
2935
+ offers: offers.length === 1 ? offers[0] : offers
2936
+ });
2937
+ return /* @__PURE__ */ jsx(JsonLd, { data });
2938
+ }
2939
+ function safeOrigin(url) {
2940
+ try {
2941
+ return new URL(url).origin;
2942
+ } catch {
2943
+ return void 0;
2944
+ }
2945
+ }
2946
+ function BreadcrumbJsonLd({ items }) {
2947
+ if (!items.length) return null;
2948
+ const data = {
2949
+ "@context": "https://schema.org",
2950
+ "@type": "BreadcrumbList",
2951
+ itemListElement: items.map((it, i) => ({
2952
+ "@type": "ListItem",
2953
+ position: i + 1,
2954
+ name: it.name,
2955
+ item: it.url
2956
+ }))
2957
+ };
2958
+ return /* @__PURE__ */ jsx(JsonLd, { data });
2959
+ }
2960
+ function OrganizationJsonLd({
2961
+ name,
2962
+ url,
2963
+ logo,
2964
+ sameAs
2965
+ }) {
2966
+ const data = compact({
2967
+ "@context": "https://schema.org",
2968
+ "@type": "Organization",
2969
+ name,
2970
+ url,
2971
+ logo,
2972
+ sameAs: sameAs && sameAs.length ? sameAs : void 0
2973
+ });
2974
+ return /* @__PURE__ */ jsx(JsonLd, { data });
2975
+ }
2976
+
2977
+ export { AccountDashboard, AccountProvider, AddToCart, AddressBook, AddressForm, AvailabilityFilter, BackInStockForm, BreadcrumbJsonLd, CartDrawer, CartLineItem, CartProvider, CartSummary, CheckoutFlow, CheckoutProvider, CollectionPage, I18nProvider, JsonLd, LoginForm, MarketSwitcher, NeviosProvider, OrderConfirmation, OrderHistory, OrderStatusPage, OrderSummary, OrganizationJsonLd, PaymentSection, PriceMoney, PriceRangeFilter, ProductCard, ProductDetailPage, ProductGallery, ProductJsonLd, ProfileEditor, ShippingPicker, SortSelect, StockBadge, TagFilter, ThemeProvider, VariantPicker, absoluteUrl, bundledMessages, cs, en, formatCents, formatMoney, serializeJsonLd, stripHtml, themeToCssVars, useAccount, useCart, useCheckout, useI18n, useMagicLinkVerify, useOrderStatus, useStorefront, useStorefrontOptional, useT };
2978
+ //# sourceMappingURL=index.js.map
2979
+ //# sourceMappingURL=index.js.map