@asteby/storefront-react 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +78 -0
  2. package/dist/account-server.cjs +41 -8
  3. package/dist/account-server.cjs.map +1 -1
  4. package/dist/account-server.d.cts +2 -2
  5. package/dist/account-server.d.ts +2 -2
  6. package/dist/account-server.js +42 -9
  7. package/dist/account-server.js.map +1 -1
  8. package/dist/account.cjs +3 -1
  9. package/dist/account.cjs.map +1 -1
  10. package/dist/account.d.cts +2 -2
  11. package/dist/account.d.ts +2 -2
  12. package/dist/account.js +3 -1
  13. package/dist/account.js.map +1 -1
  14. package/dist/cart.cjs +266 -10
  15. package/dist/cart.cjs.map +1 -1
  16. package/dist/cart.css +14 -0
  17. package/dist/cart.d.cts +125 -2
  18. package/dist/cart.d.ts +125 -2
  19. package/dist/cart.js +260 -11
  20. package/dist/cart.js.map +1 -1
  21. package/dist/checkout.cjs +24 -3
  22. package/dist/checkout.cjs.map +1 -1
  23. package/dist/checkout.d.cts +7 -5
  24. package/dist/checkout.d.ts +7 -5
  25. package/dist/checkout.js +24 -3
  26. package/dist/checkout.js.map +1 -1
  27. package/dist/chunk-Q7UTJIKY.js +122 -0
  28. package/dist/chunk-Q7UTJIKY.js.map +1 -0
  29. package/dist/fiscal-server.cjs +288 -0
  30. package/dist/fiscal-server.cjs.map +1 -0
  31. package/dist/fiscal-server.d.cts +97 -0
  32. package/dist/fiscal-server.d.ts +97 -0
  33. package/dist/fiscal-server.js +241 -0
  34. package/dist/fiscal-server.js.map +1 -0
  35. package/dist/fiscal.cjs +1345 -0
  36. package/dist/fiscal.cjs.map +1 -0
  37. package/dist/fiscal.css +343 -0
  38. package/dist/fiscal.d.cts +313 -0
  39. package/dist/fiscal.d.ts +313 -0
  40. package/dist/fiscal.js +1106 -0
  41. package/dist/fiscal.js.map +1 -0
  42. package/dist/types-BnvSbV6t.d.cts +68 -0
  43. package/dist/types-BnvSbV6t.d.ts +68 -0
  44. package/dist/{types-HcEUd9hW.d.cts → types-D7pVK0GK.d.cts} +5 -0
  45. package/dist/{types-HcEUd9hW.d.ts → types-D7pVK0GK.d.ts} +5 -0
  46. package/package.json +23 -2
package/dist/cart.cjs CHANGED
@@ -72,9 +72,17 @@ function useResolvedLocale(locale) {
72
72
  }
73
73
  var isOpen = false;
74
74
  var listeners = /* @__PURE__ */ new Set();
75
+ var quietOpen = false;
76
+ function setQuietOpen(next) {
77
+ quietOpen = next;
78
+ }
79
+ function isQuietOpen() {
80
+ return quietOpen;
81
+ }
75
82
  function set(next) {
76
83
  if (isOpen === next) return;
77
84
  isOpen = next;
85
+ if (!next) quietOpen = false;
78
86
  for (const l of [...listeners]) l();
79
87
  }
80
88
  var subscribe = (l) => {
@@ -114,6 +122,191 @@ function handleCartLinkClick(e) {
114
122
  e.preventDefault();
115
123
  openCartDrawer();
116
124
  }
125
+ var DEFAULT_TIMEOUT_MS = 3e4;
126
+ var actions = [];
127
+ var notices = [];
128
+ var announcement = { kind: null, n: 0 };
129
+ var seq = 0;
130
+ var timers = /* @__PURE__ */ new Map();
131
+ var listeners2 = /* @__PURE__ */ new Set();
132
+ var snapshot = compute();
133
+ function compute() {
134
+ const byVariant = /* @__PURE__ */ new Map();
135
+ for (const a of actions) {
136
+ const row = byVariant.get(a.variantId);
137
+ if (row) {
138
+ row.quantity += a.quantity;
139
+ row.actionIds.push(a.id);
140
+ } else {
141
+ byVariant.set(a.variantId, {
142
+ variantId: a.variantId,
143
+ title: a.title,
144
+ variantTitle: a.variantTitle,
145
+ productHandle: a.productHandle,
146
+ image: a.image,
147
+ price: a.price,
148
+ quantity: a.quantity,
149
+ actionIds: [a.id]
150
+ });
151
+ }
152
+ }
153
+ const rows = [...byVariant.values()];
154
+ return { rows, quantity: rows.reduce((n, r) => n + r.quantity, 0), notices, announcement };
155
+ }
156
+ function emit() {
157
+ snapshot = compute();
158
+ for (const l of [...listeners2]) l();
159
+ }
160
+ var subscribe2 = (l) => {
161
+ listeners2.add(l);
162
+ return () => {
163
+ listeners2.delete(l);
164
+ };
165
+ };
166
+ var EMPTY = { rows: [], quantity: 0, notices: [], announcement: { kind: null, n: 0 } };
167
+ function drop(id) {
168
+ const a = actions.find((x) => x.id === id);
169
+ if (!a) return void 0;
170
+ actions = actions.filter((x) => x.id !== id);
171
+ const t = timers.get(id);
172
+ if (t) clearTimeout(t);
173
+ timers.delete(id);
174
+ return a;
175
+ }
176
+ function announce() {
177
+ announcement = { kind: "added", n: announcement.n + 1 };
178
+ }
179
+ var cartOptimistic = {
180
+ /**
181
+ * Inserta YA la fila provisional, sube el contador y abre el cajón sin robar el foco. Devuelve el id de la acción
182
+ * para `confirm` / `rollback`. Una acción por clic: la misma variante suma cantidad en una sola fila.
183
+ */
184
+ add(input, options = {}) {
185
+ if (input.key) {
186
+ const live = actions.find((a) => a.key === input.key);
187
+ if (live) return live.id;
188
+ }
189
+ const id = `opt-${++seq}`;
190
+ const quantity = Math.max(1, Math.floor(input.quantity ?? 1));
191
+ actions = [...actions, { ...input, id, quantity }];
192
+ const ms = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
193
+ if (ms > 0 && typeof setTimeout === "function") {
194
+ timers.set(id, setTimeout(() => cartOptimistic.rollback(id, describeAddFailure({ code: "timeout" })), ms));
195
+ }
196
+ announce();
197
+ if (options.open !== false) {
198
+ setQuietOpen(true);
199
+ openCartDrawer();
200
+ }
201
+ emit();
202
+ return id;
203
+ },
204
+ /** OPS confirmó: la fila provisional sale y el carrito real (ya en `cart`) ocupa su lugar. */
205
+ confirm(id) {
206
+ if (!drop(id)) return;
207
+ announce();
208
+ emit();
209
+ },
210
+ /** Falló: se quita la acción (y su cantidad) y se avisa «No pudimos agregar X: motivo». */
211
+ rollback(id, reason = "unknown") {
212
+ const a = drop(id);
213
+ if (!a) return;
214
+ notices = [...notices, { id: `n-${++seq}`, title: a.title, reason }];
215
+ emit();
216
+ },
217
+ /** Quita la acción sin avisar (el componente que la lanzó se desmontó). */
218
+ discard(id) {
219
+ if (drop(id)) emit();
220
+ },
221
+ dismissNotice(id) {
222
+ notices = notices.filter((n) => n.id !== id);
223
+ emit();
224
+ },
225
+ /** Limpia todo (pruebas, cierre de sesión). */
226
+ reset() {
227
+ for (const t of timers.values()) clearTimeout(t);
228
+ timers.clear();
229
+ actions = [];
230
+ notices = [];
231
+ announcement = { kind: null, n: 0 };
232
+ setQuietOpen(false);
233
+ emit();
234
+ },
235
+ getSnapshot: () => snapshot
236
+ };
237
+ function useOptimisticCart() {
238
+ return react.useSyncExternalStore(subscribe2, () => snapshot, () => EMPTY);
239
+ }
240
+ function useOptimisticCartCount(base) {
241
+ return base + useOptimisticCart().quantity;
242
+ }
243
+ function describeAddFailure(error) {
244
+ const code = error?.code;
245
+ const status = error?.status;
246
+ if (code === "store_not_ready") return "la tienda est\xE1 cerrada por ahora";
247
+ if (code === "timeout") return "tard\xF3 demasiado, intenta de nuevo";
248
+ if (status === 409 || code === "out_of_stock" || code === "insufficient_stock") return "sin existencias suficientes";
249
+ if (status === 0 || code === "network" || !status && !code) return "revisa tu conexi\xF3n";
250
+ if (status && status >= 500) return "hubo un problema, intenta de nuevo";
251
+ if (status === 404) return "el producto ya no est\xE1 disponible";
252
+ return error?.message?.trim() || "intenta de nuevo";
253
+ }
254
+ function defaultAddOutcome(data) {
255
+ if (!data || typeof data !== "object") return { ok: true };
256
+ const d = data;
257
+ const status = typeof d.status === "number" ? d.status : void 0;
258
+ const err = d.error && typeof d.error === "object" ? d.error : d;
259
+ const code = typeof err.code === "string" ? err.code : void 0;
260
+ const failed = d.error != null || d.ok === false || d.success === false || status !== void 0 && status >= 400;
261
+ if (!failed) return { ok: true };
262
+ return { ok: false, reason: describeAddFailure({ status: status ?? (typeof err.status === "number" ? err.status : void 0), code, message: typeof err.message === "string" ? err.message : void 0 }) };
263
+ }
264
+ function useOptimisticAdd(fetcher, options = {}) {
265
+ const current = react.useRef(null);
266
+ const was = react.useRef(false);
267
+ const settleRef = react.useRef(options.settle);
268
+ settleRef.current = options.settle;
269
+ react.useEffect(() => {
270
+ const busy = fetcher.state !== "idle";
271
+ const id = current.current;
272
+ if (was.current && !busy && id) {
273
+ current.current = null;
274
+ const out = (settleRef.current ?? defaultAddOutcome)(fetcher.data);
275
+ if (out.ok) cartOptimistic.confirm(id);
276
+ else cartOptimistic.rollback(id, out.reason);
277
+ }
278
+ was.current = busy;
279
+ }, [fetcher.state, fetcher.data]);
280
+ react.useEffect(
281
+ () => () => {
282
+ if (current.current) cartOptimistic.discard(current.current);
283
+ current.current = null;
284
+ },
285
+ []
286
+ );
287
+ return {
288
+ add(input, submit) {
289
+ const prev = current.current;
290
+ const id = cartOptimistic.add(input);
291
+ if (prev && prev !== id) cartOptimistic.confirm(prev);
292
+ current.current = id;
293
+ try {
294
+ submit();
295
+ } catch (e) {
296
+ current.current = null;
297
+ cartOptimistic.rollback(id, describeAddFailure({ message: e instanceof Error ? e.message : void 0 }));
298
+ }
299
+ return id;
300
+ }
301
+ };
302
+ }
303
+ var DEFAULT_OPTIMISTIC_LABELS = {
304
+ adding: "Agregando\u2026",
305
+ added: "Agregado al carrito",
306
+ calculating: "calculando\u2026",
307
+ failed: (title, reason) => `No pudimos agregar ${title}: ${reason}`,
308
+ dismiss: "Descartar aviso"
309
+ };
117
310
  var DEFAULT_FORM = {
118
311
  intentField: "intent",
119
312
  lineField: "line_id",
@@ -138,6 +331,9 @@ function CartDrawer(props) {
138
331
  const { cart, labels, paths, shipping, notice, upsell, upsellTitle, icons, classNames: cx = {}, onOpenChange } = props;
139
332
  const locale = useResolvedLocale(props.locale);
140
333
  const { open } = useCartDrawer();
334
+ const opt = useOptimisticCart();
335
+ const ol = { ...DEFAULT_OPTIMISTIC_LABELS, ...props.optimisticLabels };
336
+ const quiet = open && isQuietOpen();
141
337
  const titleId = react.useId();
142
338
  const upsellId = react.useId();
143
339
  const { ref, onBackdropClick } = useModalDialog({ open, onClose: () => closeCartDrawer() });
@@ -145,12 +341,20 @@ function CartDrawer(props) {
145
341
  react.useEffect(() => {
146
342
  onOpenChange?.(open);
147
343
  }, [open]);
148
- if (!open) return null;
344
+ const realLines = cart?.lines.length ?? 0;
345
+ const rollbackEmpty = open && quiet && realLines === 0 && opt.rows.length === 0 && opt.notices.length > 0;
346
+ react.useEffect(() => {
347
+ if (rollbackEmpty) closeCartDrawer();
348
+ }, [rollbackEmpty]);
349
+ if (!open) return opt.notices.length ? /* @__PURE__ */ jsxRuntime.jsx(OptimisticNotices, { notices: opt.notices, labels: ol, classNames: cx }) : null;
149
350
  const money = props.renderMoney ?? ((m) => storefront.formatMoney(m, locale));
150
351
  const link = props.renderLink ?? (({ href, className, children, onClick }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, onClick, children }));
151
- const count = cart?.total_quantity ?? 0;
352
+ const pendingByVariant = new Map(opt.rows.map((r) => [r.variantId, r]));
353
+ const count = (cart?.total_quantity ?? 0) + opt.quantity;
152
354
  const lines = cart?.lines ?? [];
153
- const empty = !cart || lines.length === 0;
355
+ const extraRows = opt.rows.filter((r) => !lines.some((l) => l.merchandise.id === r.variantId));
356
+ const pending = opt.rows.length > 0;
357
+ const empty = lines.length === 0 && extraRows.length === 0;
154
358
  const close = () => closeCartDrawer();
155
359
  return /* @__PURE__ */ jsxRuntime.jsx(
156
360
  "dialog",
@@ -169,8 +373,10 @@ function CartDrawer(props) {
169
373
  labels.title,
170
374
  count > 0 ? ` (${count})` : ""
171
375
  ] }),
172
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: close, "aria-label": labels.close, className: cx.close, "data-sf-cart-close": "", "data-sf-autofocus": "", children: icons?.close ?? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2715" }) })
376
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: close, "aria-label": labels.close, className: cx.close, "data-sf-cart-close": "", "data-sf-autofocus": quiet ? void 0 : "", children: icons?.close ?? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2715" }) })
173
377
  ] }),
378
+ /* @__PURE__ */ jsxRuntime.jsx(OptimisticNotices, { notices: opt.notices, labels: ol, classNames: cx }),
379
+ /* @__PURE__ */ jsxRuntime.jsx(OptimisticStatus, { kind: opt.announcement.kind, n: opt.announcement.n, text: ol.added }),
174
380
  empty ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.empty, "data-sf-cart-empty": "", children: [
175
381
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx.emptyTitle, "data-sf-cart-empty-title": "", children: labels.empty }),
176
382
  labels.emptyHint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx.emptyHint, "data-sf-cart-empty-hint": "", children: labels.emptyHint }) : null,
@@ -199,16 +405,25 @@ function CartDrawer(props) {
199
405
  icons?.shippingReached,
200
406
  notice
201
407
  ] }) : null,
202
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cx.lines, "data-sf-cart-lines": "", children: lines.map((line) => /* @__PURE__ */ jsxRuntime.jsx(DrawerLine, { line, props, money, link, close }, line.id)) }),
408
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: cx.lines, "data-sf-cart-lines": "", children: [
409
+ lines.map((line) => /* @__PURE__ */ jsxRuntime.jsx(DrawerLine, { line, props, money, link, close, pending: pendingByVariant.get(line.merchandise.id), pendingLabel: ol.adding }, line.id)),
410
+ extraRows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(PendingLine, { row, props, money, label: ol.adding }, `pending-${row.variantId}`))
411
+ ] }),
203
412
  upsell ? /* @__PURE__ */ jsxRuntime.jsxs("section", { className: cx.upsell, "data-sf-cart-upsell": "", "aria-labelledby": upsellTitle ? upsellId : void 0, children: [
204
413
  upsellTitle ? /* @__PURE__ */ jsxRuntime.jsx("h3", { id: upsellId, className: cx.upsellTitle, children: upsellTitle }) : null,
205
414
  upsell
206
415
  ] }) : null
207
416
  ] }),
208
417
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.footer, "data-sf-cart-footer": "", children: [
209
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.subtotal, "data-sf-cart-subtotal": "", children: [
418
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.subtotal, "data-sf-cart-subtotal": "", "aria-busy": pending || void 0, children: [
210
419
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.subtotalLabel, children: labels.subtotal }),
211
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.subtotalValue, "data-sf-cart-subtotal-value": "", children: cart ? money(cart.cost.subtotal) : null })
420
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cx.subtotalValue, "data-sf-cart-subtotal-value": "", children: [
421
+ cart ? money(cart.cost.subtotal) : null,
422
+ pending ? /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-sf-cart-calculating": "", children: [
423
+ cart ? " " : "",
424
+ ol.calculating
425
+ ] }) : null
426
+ ] })
212
427
  ] }),
213
428
  labels.note ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx.note, "data-sf-cart-note": "", children: labels.note }) : null,
214
429
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.actions, "data-sf-cart-actions": "", children: [
@@ -226,12 +441,14 @@ function DrawerLine({
226
441
  props,
227
442
  money,
228
443
  link,
229
- close
444
+ close,
445
+ pending,
446
+ pendingLabel
230
447
  }) {
231
448
  const { labels, paths, icons, classNames: cx = {} } = props;
232
449
  const f = { ...DEFAULT_FORM, ...props.form };
233
450
  const { Form, formData } = (props.useLineForm ?? useNativeForm)();
234
- const quantity = formData ? Number(formData.get(f.quantityField) ?? 0) : line.quantity;
451
+ const quantity = formData ? Number(formData.get(f.quantityField) ?? 0) : line.quantity + (pending?.quantity ?? 0);
235
452
  if (formData && (formData.get(f.intentField) === f.removeIntent || quantity === 0)) return null;
236
453
  const merch = line.merchandise;
237
454
  const isDefault = props.isDefaultVariantTitle ?? defaultIsDefaultVariant;
@@ -266,18 +483,57 @@ function DrawerLine({
266
483
  ] }),
267
484
  price
268
485
  ] }),
269
- controls
486
+ controls,
487
+ pending ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx.variant, "data-sf-cart-pending-label": "", children: pendingLabel }) : null
270
488
  ] })
271
489
  ] });
272
490
  }
491
+ function PendingLine({ row, props, money, label }) {
492
+ const { classNames: cx = {} } = props;
493
+ const isDefault = props.isDefaultVariantTitle ?? defaultIsDefaultVariant;
494
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cx.line, "data-sf-cart-line": "", "data-sf-cart-line-pending": "", "aria-busy": "true", children: [
495
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.image, "data-sf-cart-image": "", children: row.image ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: row.image.url, alt: row.image.alt ?? "", width: 80, height: 80, decoding: "async" }) : null }),
496
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.lineMain, "data-sf-cart-line-main": "", children: [
497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.lineHead, "data-sf-cart-line-head": "", children: [
498
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx.lineText, "data-sf-cart-line-text": "", children: [
499
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.lineTitle, "data-sf-cart-line-title": "", children: row.title }),
500
+ row.variantTitle && !isDefault(row.variantTitle) ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx.variant, "data-sf-cart-variant": "", children: row.variantTitle }) : null
501
+ ] }),
502
+ row.price ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx.price, "data-sf-cart-price": "", children: money(row.price) }) : null
503
+ ] }),
504
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: cx.variant, "data-sf-cart-pending-label": "", children: [
505
+ label,
506
+ " \xB7 \xD7",
507
+ row.quantity
508
+ ] })
509
+ ] })
510
+ ] });
511
+ }
512
+ function OptimisticStatus({ kind, n, text }) {
513
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "data-sf-cart-status": "", style: VISUALLY_HIDDEN, children: kind === "added" ? `${text}${n % 2 ? "" : "\u200B"}` : "" });
514
+ }
515
+ var VISUALLY_HIDDEN = { position: "absolute", width: 1, height: 1, margin: -1, padding: 0, overflow: "hidden", clip: "rect(0 0 0 0)", whiteSpace: "nowrap", border: 0 };
516
+ function OptimisticNotices({ notices: notices2, labels, classNames: cx }) {
517
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", "aria-live": "assertive", "data-sf-cart-notices": "", className: cx.notices, children: notices2.map((n) => /* @__PURE__ */ jsxRuntime.jsxs("p", { "data-sf-cart-notice": "", children: [
518
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.failed(n.title, n.reason) }),
519
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => cartOptimistic.dismissNotice(n.id), "aria-label": labels.dismiss, "data-sf-cart-notice-dismiss": "", children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2715" }) })
520
+ ] }, n.id)) });
521
+ }
273
522
 
274
523
  exports.CartDrawer = CartDrawer;
524
+ exports.DEFAULT_OPTIMISTIC_LABELS = DEFAULT_OPTIMISTIC_LABELS;
525
+ exports.cartOptimistic = cartOptimistic;
275
526
  exports.closeCartDrawer = closeCartDrawer;
527
+ exports.defaultAddOutcome = defaultAddOutcome;
528
+ exports.describeAddFailure = describeAddFailure;
276
529
  exports.handleCartLinkClick = handleCartLinkClick;
277
530
  exports.isCartDrawerOpen = isCartDrawerOpen;
278
531
  exports.openCartDrawer = openCartDrawer;
279
532
  exports.toggleCartDrawer = toggleCartDrawer;
280
533
  exports.useCartDrawer = useCartDrawer;
281
534
  exports.useOpenCartDrawerWhenDone = useOpenCartDrawerWhenDone;
535
+ exports.useOptimisticAdd = useOptimisticAdd;
536
+ exports.useOptimisticCart = useOptimisticCart;
537
+ exports.useOptimisticCartCount = useOptimisticCartCount;
282
538
  //# sourceMappingURL=cart.cjs.map
283
539
  //# sourceMappingURL=cart.cjs.map
package/dist/cart.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dialog.tsx","../src/context.tsx","../src/locale.ts","../src/cart-drawer/store.ts","../src/cart-drawer/cart-drawer.tsx"],"names":["useRef","useEffect","useCallback","createContext","useContext","useSyncExternalStore","useId","formatMoney","jsx","jsxs","Fragment"],"mappings":"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","file":"cart.cjs","sourcesContent":["import { useCallback, useEffect, useRef, type RefObject } from 'react'\n\nexport type DialogCloseReason = 'esc' | 'x' | 'backdrop' | 'action'\n\ntype UseModalDialogOptions = {\n open: boolean\n /** Called for Esc and backdrop clicks. The owner decides whether to close. */\n onClose: (reason: DialogCloseReason) => void\n /** Element focused when the dialog opens. Default: the element marked `data-sf-autofocus`, else the dialog itself. */\n initialFocus?: RefObject<HTMLElement | null>\n}\n\n/**\n * Native `<dialog>` wiring: `showModal()` (focus trap and inert background come from the browser),\n * Esc and backdrop clicks routed to `onClose`, and focus restored to the opener on close.\n * Falls back to the `open` attribute where `showModal` does not exist (old browsers, some test DOMs)\n * with an Esc key handler.\n */\nexport function useModalDialog({ open, onClose, initialFocus }: UseModalDialogOptions) {\n const ref = useRef<HTMLDialogElement | null>(null)\n const opener = useRef<Element | null>(null)\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n\n useEffect(() => {\n const el = ref.current\n if (!el || !open) return\n opener.current = typeof document !== 'undefined' ? document.activeElement : null\n const hasModal = typeof el.showModal === 'function'\n if (!el.open) {\n if (hasModal) {\n try {\n el.showModal()\n } catch {\n el.setAttribute('open', '')\n }\n } else el.setAttribute('open', '')\n }\n const target = initialFocus?.current ?? el.querySelector<HTMLElement>('[data-sf-autofocus]') ?? el\n if (!target.hasAttribute('tabindex') && target === el) el.setAttribute('tabindex', '-1')\n target.focus({ preventScroll: true })\n\n const onCancel = (e: Event) => {\n e.preventDefault() // we close through state so the owner can navigate/track first\n onCloseRef.current('esc')\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n onCloseRef.current('esc')\n }\n }\n el.addEventListener('cancel', onCancel)\n if (!hasModal) el.addEventListener('keydown', onKey)\n return () => {\n el.removeEventListener('cancel', onCancel)\n el.removeEventListener('keydown', onKey)\n if (el.open) {\n if (typeof el.close === 'function') {\n try {\n el.close()\n } catch {\n el.removeAttribute('open')\n }\n } else el.removeAttribute('open')\n }\n const back = opener.current\n if (back instanceof HTMLElement && back.isConnected) back.focus({ preventScroll: true })\n }\n }, [open])\n\n /** Click on the backdrop (the dialog element itself, outside its content box). */\n const onBackdropClick = useCallback((e: { target: EventTarget; currentTarget: EventTarget }) => {\n if (e.target === e.currentTarget) onCloseRef.current('backdrop')\n }, [])\n\n return { ref, onBackdropClick }\n}\n\n/** `prefers-reduced-motion: reduce`, read after hydration (false on the server). */\nexport function prefersReducedMotion(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n}\n","import { createContext, useContext, useMemo, type ReactNode } from 'react'\nimport { createStorefrontClient, type Shop, type StorefrontClient, type StorefrontClientOptions } from '@asteby/storefront'\n\nexport type StorefrontContextValue = {\n /** Client for browser-side calls (use a public `pk_` token). */\n client: StorefrontClient | null\n shop: Shop | null\n /** BCP 47 locale used for formatting (defaults to `shop.locale`, then `es-MX`). */\n locale: string\n /** ISO 4217 currency (defaults to `shop.currency_code`, then `MXN`). */\n currency: string\n}\n\nconst StorefrontContext = createContext<StorefrontContextValue | null>(null)\n\nexport type StorefrontProviderProps = {\n /** A ready client. Takes precedence over `config`. */\n client?: StorefrontClient\n /** Options to create the browser client (use a `pk_` token). */\n config?: StorefrontClientOptions\n /** Shop info loaded on the server (root loader). */\n shop?: Shop | null\n locale?: string\n currency?: string\n children?: ReactNode\n}\n\n/**\n * Makes the storefront client, shop, locale and currency available to the\n * tree. SSR-safe: creating the client does not touch `window`.\n */\nexport function StorefrontProvider({ client, config, shop = null, locale, currency, children }: StorefrontProviderProps) {\n const configKey = config ? `${config.baseUrl}|${config.token}|${config.locale ?? ''}|${config.customerToken ?? ''}` : ''\n const resolvedClient = useMemo(\n () => client ?? (config ? createStorefrontClient(config) : null),\n [client, configKey],\n )\n const value = useMemo<StorefrontContextValue>(\n () => ({\n client: resolvedClient,\n shop,\n locale: locale ?? config?.locale ?? shop?.locale ?? 'es-MX',\n currency: currency ?? shop?.currency_code ?? 'MXN',\n }),\n [resolvedClient, shop, locale, currency, config?.locale],\n )\n return <StorefrontContext.Provider value={value}>{children}</StorefrontContext.Provider>\n}\n\n/** Storefront context. Throws outside `<StorefrontProvider>`. */\nexport function useStorefront(): StorefrontContextValue {\n const ctx = useContext(StorefrontContext)\n if (!ctx) throw new Error('useStorefront must be used inside <StorefrontProvider>')\n return ctx\n}\n\n/** Storefront context or `null` outside a provider (for components that work standalone). */\nexport function useOptionalStorefront(): StorefrontContextValue | null {\n return useContext(StorefrontContext)\n}\n\n/** The client from context; throws when the provider has none. */\nexport function useStorefrontClient(): StorefrontClient {\n const { client } = useStorefront()\n if (!client) throw new Error('<StorefrontProvider> needs a `client` or `config` for browser-side calls')\n return client\n}\n","import { useOptionalStorefront } from './context.js'\n\n/** Locale of a component: its own prop, else the `StorefrontProvider`'s, else `es-MX`. */\nexport function useResolvedLocale(locale?: string | null): string {\n const sf = useOptionalStorefront()\n return locale ?? sf?.locale ?? 'es-MX'\n}\n","import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\n// Estado mínimo del cajón del carrito, fuera de React: cualquier parte de la tienda (cabecera, tarjeta, ficha)\n// lo abre sin pasar props. Es del navegador; en el servidor siempre está cerrado.\n\nlet isOpen = false\nconst listeners = new Set<() => void>()\n\nfunction set(next: boolean) {\n if (isOpen === next) return\n isOpen = next\n for (const l of [...listeners]) l()\n}\n\nconst subscribe = (l: () => void) => {\n listeners.add(l)\n return () => {\n listeners.delete(l)\n }\n}\n\n/** Abre el cajón del carrito desde cualquier parte. */\nexport function openCartDrawer() {\n set(true)\n}\n\n/** Cierra el cajón del carrito. */\nexport function closeCartDrawer() {\n set(false)\n}\n\nexport function toggleCartDrawer() {\n set(!isOpen)\n}\n\nexport function isCartDrawerOpen() {\n return isOpen\n}\n\n/** Estado y acciones del cajón. `open` es `false` en el servidor y en la primera pintura. */\nexport function useCartDrawer() {\n const open = useSyncExternalStore(subscribe, () => isOpen, () => false)\n const toggle = useCallback(() => toggleCartDrawer(), [])\n return { open, openDrawer: openCartDrawer, closeDrawer: closeCartDrawer, toggle }\n}\n\n/**\n * Abre el cajón cuando termina un \"agregar al carrito\". `busy` es verdadero mientras hay un agregado en vuelo\n * (en React Router: algún fetcher con la acción del carrito e intención de agregar). Con `skip` verdadero al\n * terminar (error, agregado silencioso) no se abre.\n */\nexport function useOpenCartDrawerWhenDone(busy: boolean, options: { skip?: boolean } = {}) {\n const was = useRef(false)\n const skip = useRef(false)\n skip.current = !!options.skip\n useEffect(() => {\n if (was.current && !busy && !skip.current) openCartDrawer()\n was.current = busy\n }, [busy])\n}\n\ntype ClickLike = {\n defaultPrevented: boolean\n button: number\n metaKey: boolean\n ctrlKey: boolean\n shiftKey: boolean\n altKey: boolean\n preventDefault: () => void\n}\n\n/**\n * `onClick` para el enlace \"Mi carrito\" de la cabecera: con un clic normal abre el cajón; con clic con\n * modificador, clic central o sin JavaScript el `href` (la página del carrito) sigue funcionando.\n */\nexport function handleCartLinkClick(e: ClickLike) {\n if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return\n e.preventDefault()\n openCartDrawer()\n}\n","import { useEffect, useId, type ElementType, type ReactNode } from 'react'\nimport { formatMoney, type Cart, type CartLine, type Money } from '@asteby/storefront'\nimport { useModalDialog } from '../dialog.js'\nimport { useResolvedLocale } from '../locale.js'\nimport { closeCartDrawer, useCartDrawer } from './store.js'\n\nexport type CartDrawerLabels = {\n /** Título; el cajón agrega \" (N)\" con la cantidad de unidades. */\n title: string\n /** Texto accesible del botón de cierre. */\n close: string\n empty: string\n emptyHint?: string\n /** Texto del enlace \"seguir comprando\" del estado vacío (se muestra con `paths.browse`). */\n browse?: string\n subtotal: string\n /** Nota bajo el subtotal. */\n note?: string\n checkout: string\n viewCart: string\n remove: string\n increase: string\n decrease: string\n}\n\nexport type CartDrawerPaths = {\n /** Página del carrito: acción de las mutaciones y destino de \"ver carrito\". */\n cart: string\n checkout: string\n browse?: string\n /** Enlace de la línea al producto; sin esto el título no es enlace. */\n product?: (handle: string, variantId: string) => string\n}\n\n/** Contrato de la acción de ruta del carrito de la tienda (nombres de campo e intenciones). */\nexport type CartDrawerFormContract = {\n intentField?: string\n lineField?: string\n quantityField?: string\n updateIntent?: string\n removeIntent?: string\n}\n\nexport type CartDrawerShipping = {\n /** Mensaje ya calculado por la tienda con lo que manda OPS. */\n message: ReactNode\n /** 0..100 */\n percent: number\n reached?: boolean\n progressLabel: string\n}\n\nexport type CartDrawerLineForm = {\n /** Componente de formulario (`'form'`, o `fetcher.Form` del router para mejorar sin recargar). */\n Form: ElementType\n /** Datos en vuelo del formulario, para pintar la cantidad de forma optimista. */\n formData?: FormData | null | undefined\n}\n\nexport type CartDrawerLinkProps = { href: string; className?: string | undefined; children: ReactNode; onClick?: () => void }\n\nexport type CartDrawerSlot =\n | 'dialog' | 'panel' | 'header' | 'title' | 'close' | 'empty' | 'body' | 'shipping' | 'bar' | 'barFill' | 'lines' | 'line'\n | 'image' | 'lineTitle' | 'variant' | 'price' | 'qty' | 'qtyButton' | 'qtyValue' | 'remove' | 'upsell' | 'footer' | 'subtotal'\n | 'note' | 'actions' | 'checkout' | 'viewCart' | 'browse' | 'emptyTitle' | 'emptyHint' | 'shippingMessage' | 'lineMain'\n | 'lineHead' | 'lineText' | 'controls' | 'upsellTitle' | 'subtotalLabel' | 'subtotalValue'\n\nexport type CartDrawerIcons = { close?: ReactNode; decrease?: ReactNode; increase?: ReactNode; shipping?: ReactNode; shippingReached?: ReactNode }\n\nexport type CartDrawerProps = {\n /** `cart.cost` y cada línea vienen de OPS; el cajón no calcula nada. */\n cart: Cart | null | undefined\n labels: CartDrawerLabels\n paths: CartDrawerPaths\n form?: CartDrawerFormContract\n /** Hook que da el formulario de cada línea. Por omisión `<form method=\"post\">` (funciona sin JavaScript). */\n useLineForm?: () => CartDrawerLineForm\n shipping?: CartDrawerShipping | null\n /** Aviso fijo cuando no hay barra de envío (p. ej. \"Envío gratis\"). */\n notice?: ReactNode\n /** Sección \"podría interesarte\" (la tienda decide qué mostrar). */\n upsell?: ReactNode\n upsellTitle?: string\n renderLine?: (line: CartLine, defaults: { controls: ReactNode; price: ReactNode; image: ReactNode }) => ReactNode\n renderImage?: (line: CartLine) => ReactNode\n renderMoney?: (money: Money) => ReactNode\n renderLink?: (props: CartDrawerLinkProps) => ReactNode\n /** Omite el variante cuando es el valor por defecto de OPS (\"Default Title\"). */\n isDefaultVariantTitle?: (title: string) => boolean\n icons?: CartDrawerIcons\n /** Clases por pieza (además de los `data-sf-cart-*`), para tiendas con Tailwind. */\n classNames?: Partial<Record<CartDrawerSlot, string>>\n locale?: string\n /** Se llama al abrir/cerrar por cualquier vía. */\n onOpenChange?: (open: boolean) => void\n}\n\nconst DEFAULT_FORM: Required<CartDrawerFormContract> = {\n intentField: 'intent',\n lineField: 'line_id',\n quantityField: 'quantity',\n updateIntent: 'update',\n removeIntent: 'remove',\n}\n\nconst useNativeForm = (): CartDrawerLineForm => ({ Form: 'form' })\n\nconst defaultIsDefaultVariant = (t: string) => /^default title$/i.test(t.trim())\n\nfunction useBodyScrollLock(locked: boolean) {\n useEffect(() => {\n if (!locked || typeof document === 'undefined') return\n const el = document.documentElement\n const prev = el.style.overflow\n el.style.overflow = 'hidden'\n return () => {\n el.style.overflow = prev\n }\n }, [locked])\n}\n\n/**\n * Cajón lateral del carrito (\"Tu carrito (N)\"). Sin textos ni marca: todo llega por props.\n * Se monta una vez (en la raíz) y se abre con `openCartDrawer()` / `useCartDrawer()`.\n * `<dialog>` modal: `role=\"dialog\"`, `aria-modal`, foco atrapado y devuelto al abridor, Esc y clic fuera cierran,\n * el fondo no hace scroll. Las mutaciones usan la acción de ruta de la tienda (formularios nativos que\n * funcionan sin JavaScript, o el `Form` de un fetcher con `useLineForm`). Estilos: `@asteby/storefront-react/cart.css`\n * (tokens de la tienda) y/o `classNames`.\n */\nexport function CartDrawer(props: CartDrawerProps) {\n const { cart, labels, paths, shipping, notice, upsell, upsellTitle, icons, classNames: cx = {}, onOpenChange } = props\n const locale = useResolvedLocale(props.locale)\n const { open } = useCartDrawer()\n const titleId = useId()\n const upsellId = useId()\n const { ref, onBackdropClick } = useModalDialog({ open, onClose: () => closeCartDrawer() })\n useBodyScrollLock(open)\n useEffect(() => {\n onOpenChange?.(open)\n }, [open]) // eslint-disable-line react-hooks/exhaustive-deps\n\n if (!open) return null\n\n const money = props.renderMoney ?? ((m: Money) => formatMoney(m, locale))\n const link = props.renderLink ?? (({ href, className, children, onClick }: CartDrawerLinkProps) => (\n <a href={href} className={className} onClick={onClick}>{children}</a>\n ))\n const count = cart?.total_quantity ?? 0\n const lines = cart?.lines ?? []\n const empty = !cart || lines.length === 0\n const close = () => closeCartDrawer()\n\n return (\n <dialog\n ref={ref}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n onClick={onBackdropClick}\n onClose={close}\n className={cx.dialog}\n data-sf-cart-drawer=\"\"\n >\n <div className={cx.panel} data-sf-cart-panel=\"\">\n <div className={cx.header} data-sf-cart-header=\"\">\n <h2 id={titleId} tabIndex={-1} className={cx.title} data-sf-cart-title=\"\">\n {labels.title}{count > 0 ? ` (${count})` : ''}\n </h2>\n <button type=\"button\" onClick={close} aria-label={labels.close} className={cx.close} data-sf-cart-close=\"\" data-sf-autofocus=\"\">\n {icons?.close ?? <span aria-hidden=\"true\">✕</span>}\n </button>\n </div>\n\n {empty ? (\n <div className={cx.empty} data-sf-cart-empty=\"\">\n <p className={cx.emptyTitle} data-sf-cart-empty-title=\"\">{labels.empty}</p>\n {labels.emptyHint ? <p className={cx.emptyHint} data-sf-cart-empty-hint=\"\">{labels.emptyHint}</p> : null}\n {paths.browse && labels.browse ? link({ href: paths.browse, className: cx.browse, children: labels.browse, onClick: close }) : null}\n </div>\n ) : (\n <>\n <div className={cx.body} data-sf-cart-body=\"\">\n {shipping ? (\n <div className={cx.shipping} data-sf-cart-shipping=\"\" data-reached={shipping.reached || undefined}>\n <p className={cx.shippingMessage}>\n {shipping.reached ? icons?.shippingReached : icons?.shipping}\n {shipping.message}\n </p>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(shipping.percent)}\n aria-label={shipping.progressLabel}\n className={cx.bar}\n data-sf-cart-bar=\"\"\n >\n <div className={cx.barFill} data-sf-cart-bar-fill=\"\" style={{ width: `${Math.max(0, Math.min(100, shipping.percent))}%` }} />\n </div>\n </div>\n ) : notice ? (\n <p className={[cx.shipping, cx.shippingMessage].filter(Boolean).join(\" \") || undefined} data-sf-cart-shipping=\"\" data-notice=\"\">{icons?.shippingReached}{notice}</p>\n ) : null}\n\n <ul className={cx.lines} data-sf-cart-lines=\"\">\n {lines.map((line) => (\n <DrawerLine key={line.id} line={line} props={props} money={money} link={link} close={close} />\n ))}\n </ul>\n\n {upsell ? (\n <section className={cx.upsell} data-sf-cart-upsell=\"\" aria-labelledby={upsellTitle ? upsellId : undefined}>\n {upsellTitle ? <h3 id={upsellId} className={cx.upsellTitle}>{upsellTitle}</h3> : null}\n {upsell}\n </section>\n ) : null}\n </div>\n\n <div className={cx.footer} data-sf-cart-footer=\"\">\n <div className={cx.subtotal} data-sf-cart-subtotal=\"\">\n <span className={cx.subtotalLabel}>{labels.subtotal}</span>\n <span className={cx.subtotalValue} data-sf-cart-subtotal-value=\"\">{cart ? money(cart.cost.subtotal) : null}</span>\n </div>\n {labels.note ? <p className={cx.note} data-sf-cart-note=\"\">{labels.note}</p> : null}\n <div className={cx.actions} data-sf-cart-actions=\"\">\n {link({ href: paths.checkout, className: cx.checkout, children: labels.checkout, onClick: close })}\n {link({ href: paths.cart, className: cx.viewCart, children: labels.viewCart, onClick: close })}\n </div>\n </div>\n </>\n )}\n </div>\n </dialog>\n )\n}\n\nfunction DrawerLine({\n line,\n props,\n money,\n link,\n close,\n}: {\n line: CartLine\n props: CartDrawerProps\n money: (m: Money) => ReactNode\n link: (p: CartDrawerLinkProps) => ReactNode\n close: () => void\n}) {\n const { labels, paths, icons, classNames: cx = {} } = props\n const f = { ...DEFAULT_FORM, ...props.form }\n const { Form, formData } = (props.useLineForm ?? useNativeForm)()\n const quantity = formData ? Number(formData.get(f.quantityField) ?? 0) : line.quantity\n if (formData && (formData.get(f.intentField) === f.removeIntent || quantity === 0)) return null\n\n const merch = line.merchandise\n const isDefault = props.isDefaultVariantTitle ?? defaultIsDefaultVariant\n const title = merch.product.title\n const href = paths.product?.(merch.product.handle, merch.id)\n const img = merch.image ?? merch.product.featured_image\n const image = props.renderImage ? props.renderImage(line) : img ? (\n <img src={img.url} alt={img.alt ?? ''} width={80} height={80} loading=\"lazy\" decoding=\"async\" />\n ) : null\n\n const imageNode = <span className={cx.image} data-sf-cart-image=\"\">{image}</span>\n const price = <span className={cx.price} data-sf-cart-price=\"\">{money(line.cost.total)}</span>\n const controls = (\n <div className={cx.controls} data-sf-cart-controls=\"\">\n <Form method=\"post\" action={paths.cart} className={cx.qty} data-sf-cart-qty=\"\">\n <input type=\"hidden\" name={f.intentField} value={f.updateIntent} />\n <input type=\"hidden\" name={f.lineField} value={line.id} />\n <button type=\"submit\" name={f.quantityField} value={quantity - 1} aria-label={labels.decrease} className={cx.qtyButton} data-sf-cart-qty-button=\"\">\n {icons?.decrease ?? <span aria-hidden=\"true\">−</span>}\n </button>\n <span className={cx.qtyValue} aria-live=\"polite\" data-sf-cart-qty-value=\"\">{quantity}</span>\n <button type=\"submit\" name={f.quantityField} value={quantity + 1} aria-label={labels.increase} className={cx.qtyButton} data-sf-cart-qty-button=\"\">\n {icons?.increase ?? <span aria-hidden=\"true\">+</span>}\n </button>\n </Form>\n <Form method=\"post\" action={paths.cart} data-sf-cart-remove-form=\"\">\n <input type=\"hidden\" name={f.intentField} value={f.removeIntent} />\n <input type=\"hidden\" name={f.lineField} value={line.id} />\n <button type=\"submit\" className={cx.remove} data-sf-cart-remove=\"\">{labels.remove}</button>\n </Form>\n </div>\n )\n\n if (props.renderLine) return <li key={line.id} className={cx.line} data-sf-cart-line=\"\">{props.renderLine(line, { controls, price, image: imageNode })}</li>\n\n return (\n <li className={cx.line} data-sf-cart-line=\"\">\n {imageNode}\n <div className={cx.lineMain} data-sf-cart-line-main=\"\">\n <div className={cx.lineHead} data-sf-cart-line-head=\"\">\n <div className={cx.lineText} data-sf-cart-line-text=\"\">\n {href ? link({ href, className: cx.lineTitle, children: title, onClick: close }) : <span className={cx.lineTitle} data-sf-cart-line-title=\"\">{title}</span>}\n {!isDefault(merch.title) ? <p className={cx.variant} data-sf-cart-variant=\"\">{merch.title}</p> : null}\n </div>\n {price}\n </div>\n {controls}\n </div>\n </li>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/dialog.tsx","../src/context.tsx","../src/locale.ts","../src/cart-drawer/store.ts","../src/cart-drawer/optimistic.ts","../src/cart-drawer/cart-drawer.tsx"],"names":["useRef","useEffect","useCallback","createContext","useContext","useSyncExternalStore","listeners","subscribe","useId","jsx","formatMoney","jsxs","Fragment","notices"],"mappings":"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","file":"cart.cjs","sourcesContent":["import { useCallback, useEffect, useRef, type RefObject } from 'react'\n\nexport type DialogCloseReason = 'esc' | 'x' | 'backdrop' | 'action'\n\ntype UseModalDialogOptions = {\n open: boolean\n /** Called for Esc and backdrop clicks. The owner decides whether to close. */\n onClose: (reason: DialogCloseReason) => void\n /** Element focused when the dialog opens. Default: the element marked `data-sf-autofocus`, else the dialog itself. */\n initialFocus?: RefObject<HTMLElement | null>\n}\n\n/**\n * Native `<dialog>` wiring: `showModal()` (focus trap and inert background come from the browser),\n * Esc and backdrop clicks routed to `onClose`, and focus restored to the opener on close.\n * Falls back to the `open` attribute where `showModal` does not exist (old browsers, some test DOMs)\n * with an Esc key handler.\n */\nexport function useModalDialog({ open, onClose, initialFocus }: UseModalDialogOptions) {\n const ref = useRef<HTMLDialogElement | null>(null)\n const opener = useRef<Element | null>(null)\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n\n useEffect(() => {\n const el = ref.current\n if (!el || !open) return\n opener.current = typeof document !== 'undefined' ? document.activeElement : null\n const hasModal = typeof el.showModal === 'function'\n if (!el.open) {\n if (hasModal) {\n try {\n el.showModal()\n } catch {\n el.setAttribute('open', '')\n }\n } else el.setAttribute('open', '')\n }\n const target = initialFocus?.current ?? el.querySelector<HTMLElement>('[data-sf-autofocus]') ?? el\n if (!target.hasAttribute('tabindex') && target === el) el.setAttribute('tabindex', '-1')\n target.focus({ preventScroll: true })\n\n const onCancel = (e: Event) => {\n e.preventDefault() // we close through state so the owner can navigate/track first\n onCloseRef.current('esc')\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault()\n onCloseRef.current('esc')\n }\n }\n el.addEventListener('cancel', onCancel)\n if (!hasModal) el.addEventListener('keydown', onKey)\n return () => {\n el.removeEventListener('cancel', onCancel)\n el.removeEventListener('keydown', onKey)\n if (el.open) {\n if (typeof el.close === 'function') {\n try {\n el.close()\n } catch {\n el.removeAttribute('open')\n }\n } else el.removeAttribute('open')\n }\n const back = opener.current\n if (back instanceof HTMLElement && back.isConnected) back.focus({ preventScroll: true })\n }\n }, [open])\n\n /** Click on the backdrop (the dialog element itself, outside its content box). */\n const onBackdropClick = useCallback((e: { target: EventTarget; currentTarget: EventTarget }) => {\n if (e.target === e.currentTarget) onCloseRef.current('backdrop')\n }, [])\n\n return { ref, onBackdropClick }\n}\n\n/** `prefers-reduced-motion: reduce`, read after hydration (false on the server). */\nexport function prefersReducedMotion(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n}\n","import { createContext, useContext, useMemo, type ReactNode } from 'react'\nimport { createStorefrontClient, type Shop, type StorefrontClient, type StorefrontClientOptions } from '@asteby/storefront'\n\nexport type StorefrontContextValue = {\n /** Client for browser-side calls (use a public `pk_` token). */\n client: StorefrontClient | null\n shop: Shop | null\n /** BCP 47 locale used for formatting (defaults to `shop.locale`, then `es-MX`). */\n locale: string\n /** ISO 4217 currency (defaults to `shop.currency_code`, then `MXN`). */\n currency: string\n}\n\nconst StorefrontContext = createContext<StorefrontContextValue | null>(null)\n\nexport type StorefrontProviderProps = {\n /** A ready client. Takes precedence over `config`. */\n client?: StorefrontClient\n /** Options to create the browser client (use a `pk_` token). */\n config?: StorefrontClientOptions\n /** Shop info loaded on the server (root loader). */\n shop?: Shop | null\n locale?: string\n currency?: string\n children?: ReactNode\n}\n\n/**\n * Makes the storefront client, shop, locale and currency available to the\n * tree. SSR-safe: creating the client does not touch `window`.\n */\nexport function StorefrontProvider({ client, config, shop = null, locale, currency, children }: StorefrontProviderProps) {\n const configKey = config ? `${config.baseUrl}|${config.token}|${config.locale ?? ''}|${config.customerToken ?? ''}` : ''\n const resolvedClient = useMemo(\n () => client ?? (config ? createStorefrontClient(config) : null),\n [client, configKey],\n )\n const value = useMemo<StorefrontContextValue>(\n () => ({\n client: resolvedClient,\n shop,\n locale: locale ?? config?.locale ?? shop?.locale ?? 'es-MX',\n currency: currency ?? shop?.currency_code ?? 'MXN',\n }),\n [resolvedClient, shop, locale, currency, config?.locale],\n )\n return <StorefrontContext.Provider value={value}>{children}</StorefrontContext.Provider>\n}\n\n/** Storefront context. Throws outside `<StorefrontProvider>`. */\nexport function useStorefront(): StorefrontContextValue {\n const ctx = useContext(StorefrontContext)\n if (!ctx) throw new Error('useStorefront must be used inside <StorefrontProvider>')\n return ctx\n}\n\n/** Storefront context or `null` outside a provider (for components that work standalone). */\nexport function useOptionalStorefront(): StorefrontContextValue | null {\n return useContext(StorefrontContext)\n}\n\n/** The client from context; throws when the provider has none. */\nexport function useStorefrontClient(): StorefrontClient {\n const { client } = useStorefront()\n if (!client) throw new Error('<StorefrontProvider> needs a `client` or `config` for browser-side calls')\n return client\n}\n","import { useOptionalStorefront } from './context.js'\n\n/** Locale of a component: its own prop, else the `StorefrontProvider`'s, else `es-MX`. */\nexport function useResolvedLocale(locale?: string | null): string {\n const sf = useOptionalStorefront()\n return locale ?? sf?.locale ?? 'es-MX'\n}\n","import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\n// Estado mínimo del cajón del carrito, fuera de React: cualquier parte de la tienda (cabecera, tarjeta, ficha)\n// lo abre sin pasar props. Es del navegador; en el servidor siempre está cerrado.\n\nlet isOpen = false\nconst listeners = new Set<() => void>()\n\nlet quietOpen = false\n\n/** Marca que el cajón lo abrió una acción optimista (la apertura no mueve el foco al botón de cierre). */\nexport function setQuietOpen(next: boolean) {\n quietOpen = next\n}\n\nexport function isQuietOpen() {\n return quietOpen\n}\n\nfunction set(next: boolean) {\n if (isOpen === next) return\n isOpen = next\n if (!next) quietOpen = false\n for (const l of [...listeners]) l()\n}\n\nconst subscribe = (l: () => void) => {\n listeners.add(l)\n return () => {\n listeners.delete(l)\n }\n}\n\n/** Abre el cajón del carrito desde cualquier parte. */\nexport function openCartDrawer() {\n set(true)\n}\n\n/** Cierra el cajón del carrito. */\nexport function closeCartDrawer() {\n set(false)\n}\n\nexport function toggleCartDrawer() {\n set(!isOpen)\n}\n\nexport function isCartDrawerOpen() {\n return isOpen\n}\n\n/** Estado y acciones del cajón. `open` es `false` en el servidor y en la primera pintura. */\nexport function useCartDrawer() {\n const open = useSyncExternalStore(subscribe, () => isOpen, () => false)\n const toggle = useCallback(() => toggleCartDrawer(), [])\n return { open, openDrawer: openCartDrawer, closeDrawer: closeCartDrawer, toggle }\n}\n\n/**\n * Abre el cajón cuando termina un \"agregar al carrito\". `busy` es verdadero mientras hay un agregado en vuelo\n * (en React Router: algún fetcher con la acción del carrito e intención de agregar). Con `skip` verdadero al\n * terminar (error, agregado silencioso) no se abre.\n */\nexport function useOpenCartDrawerWhenDone(busy: boolean, options: { skip?: boolean } = {}) {\n const was = useRef(false)\n const skip = useRef(false)\n skip.current = !!options.skip\n useEffect(() => {\n if (was.current && !busy && !skip.current) openCartDrawer()\n was.current = busy\n }, [busy])\n}\n\ntype ClickLike = {\n defaultPrevented: boolean\n button: number\n metaKey: boolean\n ctrlKey: boolean\n shiftKey: boolean\n altKey: boolean\n preventDefault: () => void\n}\n\n/**\n * `onClick` para el enlace \"Mi carrito\" de la cabecera: con un clic normal abre el cajón; con clic con\n * modificador, clic central o sin JavaScript el `href` (la página del carrito) sigue funcionando.\n */\nexport function handleCartLinkClick(e: ClickLike) {\n if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return\n e.preventDefault()\n openCartDrawer()\n}\n","import { useEffect, useRef, useSyncExternalStore } from 'react'\nimport type { Money } from '@asteby/storefront'\nimport { openCartDrawer, setQuietOpen } from './store.js'\n\n// Estado optimista del cajón del carrito. Solo guarda FILAS provisionales (producto, imagen, título, precio mostrado\n// y cantidad) mientras OPS responde. Nunca calcula dinero: precios, totales, impuestos y envío los dicta OPS cuando\n// llega el carrito real. Vive fuera de React, como el estado de apertura del cajón.\n\n/** Lo que la tienda sabe del producto al pulsar «Agregar». `price` es el precio unitario ya mostrado en la ficha. */\nexport type OptimisticLineInput = {\n /** Variante agregada; dos acciones con la misma variante comparten una sola fila. */\n variantId: string\n title: string\n variantTitle?: string | null | undefined\n productHandle?: string | undefined\n image?: { url: string; alt?: string | null | undefined } | null | undefined\n /** Precio unitario mostrado (solo se pinta, no se multiplica ni se suma). */\n price?: Money | null | undefined\n /** Unidades de ESTA acción (por omisión 1). */\n quantity?: number | undefined\n /** Clave de idempotencia: repetir `add` con una clave viva devuelve la misma acción sin sumar otra vez. */\n key?: string | undefined\n}\n\nexport type OptimisticAction = Required<Pick<OptimisticLineInput, 'variantId' | 'title'>> &\n Omit<OptimisticLineInput, 'quantity' | 'key'> & { id: string; quantity: number; key?: string | undefined }\n\n/** Fila provisional: todas las acciones en vuelo de una misma variante. */\nexport type OptimisticRow = {\n variantId: string\n title: string\n variantTitle?: string | null | undefined\n productHandle?: string | undefined\n image?: { url: string; alt?: string | null | undefined } | null | undefined\n price?: Money | null | undefined\n /** Unidades agregadas que OPS aún no confirma. */\n quantity: number\n actionIds: string[]\n}\n\nexport type OptimisticNotice = { id: string; title: string; reason: string }\n\nexport type OptimisticSnapshot = {\n rows: readonly OptimisticRow[]\n /** Unidades provisionales en total (para el contador). */\n quantity: number\n notices: readonly OptimisticNotice[]\n /** Último evento a anunciar en la región `aria-live=\"polite\"`; `n` cambia en cada evento. */\n announcement: { kind: 'added' | null; n: number }\n}\n\nexport type AddOutcome = { ok: true } | { ok: false; reason: string }\n\nconst DEFAULT_TIMEOUT_MS = 30_000\n\nlet actions: OptimisticAction[] = []\nlet notices: OptimisticNotice[] = []\nlet announcement: OptimisticSnapshot['announcement'] = { kind: null, n: 0 }\nlet seq = 0\nconst timers = new Map<string, ReturnType<typeof setTimeout>>()\nconst listeners = new Set<() => void>()\nlet snapshot: OptimisticSnapshot = compute()\n\nfunction compute(): OptimisticSnapshot {\n const byVariant = new Map<string, OptimisticRow>()\n for (const a of actions) {\n const row = byVariant.get(a.variantId)\n if (row) {\n row.quantity += a.quantity\n row.actionIds.push(a.id)\n } else {\n byVariant.set(a.variantId, {\n variantId: a.variantId, title: a.title, variantTitle: a.variantTitle, productHandle: a.productHandle,\n image: a.image, price: a.price, quantity: a.quantity, actionIds: [a.id],\n })\n }\n }\n const rows = [...byVariant.values()]\n return { rows, quantity: rows.reduce((n, r) => n + r.quantity, 0), notices, announcement }\n}\n\nfunction emit() {\n snapshot = compute()\n for (const l of [...listeners]) l()\n}\n\nconst subscribe = (l: () => void) => {\n listeners.add(l)\n return () => {\n listeners.delete(l)\n }\n}\nconst EMPTY: OptimisticSnapshot = { rows: [], quantity: 0, notices: [], announcement: { kind: null, n: 0 } }\n\nfunction drop(id: string): OptimisticAction | undefined {\n const a = actions.find((x) => x.id === id)\n if (!a) return undefined\n actions = actions.filter((x) => x.id !== id)\n const t = timers.get(id)\n if (t) clearTimeout(t)\n timers.delete(id)\n return a\n}\n\nfunction announce() {\n announcement = { kind: 'added', n: announcement.n + 1 }\n}\n\nexport const cartOptimistic = {\n /**\n * Inserta YA la fila provisional, sube el contador y abre el cajón sin robar el foco. Devuelve el id de la acción\n * para `confirm` / `rollback`. Una acción por clic: la misma variante suma cantidad en una sola fila.\n */\n add(input: OptimisticLineInput, options: { open?: boolean; timeoutMs?: number } = {}): string {\n if (input.key) {\n const live = actions.find((a) => a.key === input.key)\n if (live) return live.id\n }\n const id = `opt-${++seq}`\n const quantity = Math.max(1, Math.floor(input.quantity ?? 1))\n actions = [...actions, { ...input, id, quantity }]\n const ms = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n if (ms > 0 && typeof setTimeout === 'function') {\n timers.set(id, setTimeout(() => cartOptimistic.rollback(id, describeAddFailure({ code: 'timeout' })), ms))\n }\n announce()\n if (options.open !== false) {\n setQuietOpen(true)\n openCartDrawer()\n }\n emit()\n return id\n },\n\n /** OPS confirmó: la fila provisional sale y el carrito real (ya en `cart`) ocupa su lugar. */\n confirm(id: string) {\n if (!drop(id)) return\n announce()\n emit()\n },\n\n /** Falló: se quita la acción (y su cantidad) y se avisa «No pudimos agregar X: motivo». */\n rollback(id: string, reason = 'unknown') {\n const a = drop(id)\n if (!a) return\n notices = [...notices, { id: `n-${++seq}`, title: a.title, reason }]\n emit()\n },\n\n /** Quita la acción sin avisar (el componente que la lanzó se desmontó). */\n discard(id: string) {\n if (drop(id)) emit()\n },\n\n dismissNotice(id: string) {\n notices = notices.filter((n) => n.id !== id)\n emit()\n },\n\n /** Limpia todo (pruebas, cierre de sesión). */\n reset() {\n for (const t of timers.values()) clearTimeout(t)\n timers.clear()\n actions = []\n notices = []\n announcement = { kind: null, n: 0 }\n setQuietOpen(false)\n emit()\n },\n\n getSnapshot: (): OptimisticSnapshot => snapshot,\n}\n\n/** Estado optimista (filas, contador, avisos). En el servidor siempre vacío. */\nexport function useOptimisticCart(): OptimisticSnapshot {\n return useSyncExternalStore(subscribe, () => snapshot, () => EMPTY)\n}\n\n/** Contador para la cabecera: unidades del carrito de OPS más las que están en vuelo. */\nexport function useOptimisticCartCount(base: number): number {\n return base + useOptimisticCart().quantity\n}\n\n/** Motivo corto en es-MX a partir de un error de la acción (HTTP, código de OPS o red). */\nexport function describeAddFailure(error: { status?: number | undefined; code?: string | undefined; message?: string | undefined } | null | undefined): string {\n const code = error?.code\n const status = error?.status\n if (code === 'store_not_ready') return 'la tienda está cerrada por ahora'\n if (code === 'timeout') return 'tardó demasiado, intenta de nuevo'\n if (status === 409 || code === 'out_of_stock' || code === 'insufficient_stock') return 'sin existencias suficientes'\n if (status === 0 || code === 'network' || (!status && !code)) return 'revisa tu conexión'\n if (status && status >= 500) return 'hubo un problema, intenta de nuevo'\n if (status === 404) return 'el producto ya no está disponible'\n return error?.message?.trim() || 'intenta de nuevo'\n}\n\ntype FetcherLike = { state: string; data?: unknown }\n\n/** Interpreta `fetcher.data` de la acción de ruta: `{ error }`, `{ success:false }`, `{ ok:false }` o `status >= 400` fallan. */\nexport function defaultAddOutcome(data: unknown): AddOutcome {\n if (!data || typeof data !== 'object') return { ok: true }\n const d = data as Record<string, unknown>\n const status = typeof d.status === 'number' ? d.status : undefined\n const err = (d.error && typeof d.error === 'object' ? d.error : d) as Record<string, unknown>\n const code = typeof err.code === 'string' ? err.code : undefined\n const failed = d.error != null || d.ok === false || d.success === false || (status !== undefined && status >= 400)\n if (!failed) return { ok: true }\n return { ok: false, reason: describeAddFailure({ status: status ?? (typeof err.status === 'number' ? err.status : undefined), code, message: typeof err.message === 'string' ? err.message : undefined }) }\n}\n\n/**\n * Conecta un `useFetcher()` de React Router con el estado optimista. `add(input, submit)` inserta la fila, abre el\n * cajón y llama a `submit()` (el `fetcher.submit(...)` de la tienda); al terminar el fetcher confirma o revierte.\n * Un nuevo `add` con el mismo fetcher antes de terminar da por entregado el anterior (el router lo reemplaza y el\n * carrito real que llega con la revalidación manda). Si el componente se desmonta, las filas se descartan sin aviso.\n */\nexport function useOptimisticAdd(fetcher: FetcherLike, options: { settle?: (data: unknown) => AddOutcome } = {}) {\n const current = useRef<string | null>(null)\n const was = useRef(false)\n const settleRef = useRef(options.settle)\n settleRef.current = options.settle\n\n useEffect(() => {\n const busy = fetcher.state !== 'idle'\n const id = current.current\n if (was.current && !busy && id) {\n current.current = null\n const out = (settleRef.current ?? defaultAddOutcome)(fetcher.data)\n if (out.ok) cartOptimistic.confirm(id)\n else cartOptimistic.rollback(id, out.reason)\n }\n was.current = busy\n }, [fetcher.state, fetcher.data])\n\n useEffect(\n () => () => {\n if (current.current) cartOptimistic.discard(current.current)\n current.current = null\n },\n [],\n )\n\n return {\n add(input: OptimisticLineInput, submit: () => void): string {\n const prev = current.current\n const id = cartOptimistic.add(input)\n if (prev && prev !== id) cartOptimistic.confirm(prev)\n current.current = id\n try {\n submit()\n } catch (e) {\n current.current = null\n cartOptimistic.rollback(id, describeAddFailure({ message: e instanceof Error ? e.message : undefined }))\n }\n return id\n },\n }\n}\n","import { useEffect, useId, type ElementType, type ReactNode } from 'react'\nimport { formatMoney, type Cart, type CartLine, type Money } from '@asteby/storefront'\nimport { useModalDialog } from '../dialog.js'\nimport { useResolvedLocale } from '../locale.js'\nimport { closeCartDrawer, isQuietOpen, useCartDrawer } from './store.js'\nimport { cartOptimistic, useOptimisticCart, type OptimisticNotice, type OptimisticRow } from './optimistic.js'\n\n/** Textos del estado optimista. Por omisión es-MX; la tienda puede traducirlos o cambiarlos. */\nexport type CartDrawerOptimisticLabels = {\n /** Estado discreto en la fila provisional. */\n adding: string\n /** Anuncio `aria-live=\"polite\"` al mostrar/confirmar la fila. */\n added: string\n /** Junto al subtotal mientras OPS no confirma. */\n calculating: string\n /** Aviso de error: «No pudimos agregar X: motivo». */\n failed: (title: string, reason: string) => string\n dismiss: string\n}\n\nexport const DEFAULT_OPTIMISTIC_LABELS: CartDrawerOptimisticLabels = {\n adding: 'Agregando…',\n added: 'Agregado al carrito',\n calculating: 'calculando…',\n failed: (title, reason) => `No pudimos agregar ${title}: ${reason}`,\n dismiss: 'Descartar aviso',\n}\n\nexport type CartDrawerLabels = {\n /** Título; el cajón agrega \" (N)\" con la cantidad de unidades. */\n title: string\n /** Texto accesible del botón de cierre. */\n close: string\n empty: string\n emptyHint?: string\n /** Texto del enlace \"seguir comprando\" del estado vacío (se muestra con `paths.browse`). */\n browse?: string\n subtotal: string\n /** Nota bajo el subtotal. */\n note?: string\n checkout: string\n viewCart: string\n remove: string\n increase: string\n decrease: string\n}\n\nexport type CartDrawerPaths = {\n /** Página del carrito: acción de las mutaciones y destino de \"ver carrito\". */\n cart: string\n checkout: string\n browse?: string\n /** Enlace de la línea al producto; sin esto el título no es enlace. */\n product?: (handle: string, variantId: string) => string\n}\n\n/** Contrato de la acción de ruta del carrito de la tienda (nombres de campo e intenciones). */\nexport type CartDrawerFormContract = {\n intentField?: string\n lineField?: string\n quantityField?: string\n updateIntent?: string\n removeIntent?: string\n}\n\nexport type CartDrawerShipping = {\n /** Mensaje ya calculado por la tienda con lo que manda OPS. */\n message: ReactNode\n /** 0..100 */\n percent: number\n reached?: boolean\n progressLabel: string\n}\n\nexport type CartDrawerLineForm = {\n /** Componente de formulario (`'form'`, o `fetcher.Form` del router para mejorar sin recargar). */\n Form: ElementType\n /** Datos en vuelo del formulario, para pintar la cantidad de forma optimista. */\n formData?: FormData | null | undefined\n}\n\nexport type CartDrawerLinkProps = { href: string; className?: string | undefined; children: ReactNode; onClick?: () => void }\n\nexport type CartDrawerSlot =\n | 'dialog' | 'panel' | 'header' | 'title' | 'close' | 'empty' | 'body' | 'shipping' | 'bar' | 'barFill' | 'lines' | 'line'\n | 'image' | 'lineTitle' | 'variant' | 'price' | 'qty' | 'qtyButton' | 'qtyValue' | 'remove' | 'upsell' | 'footer' | 'subtotal'\n | 'note' | 'actions' | 'checkout' | 'viewCart' | 'browse' | 'emptyTitle' | 'emptyHint' | 'shippingMessage' | 'lineMain'\n | 'notices' | 'lineHead' | 'lineText' | 'controls' | 'upsellTitle' | 'subtotalLabel' | 'subtotalValue'\n\nexport type CartDrawerIcons = { close?: ReactNode; decrease?: ReactNode; increase?: ReactNode; shipping?: ReactNode; shippingReached?: ReactNode }\n\nexport type CartDrawerProps = {\n /** `cart.cost` y cada línea vienen de OPS; el cajón no calcula nada. */\n cart: Cart | null | undefined\n labels: CartDrawerLabels\n paths: CartDrawerPaths\n form?: CartDrawerFormContract\n /** Hook que da el formulario de cada línea. Por omisión `<form method=\"post\">` (funciona sin JavaScript). */\n useLineForm?: () => CartDrawerLineForm\n shipping?: CartDrawerShipping | null\n /** Aviso fijo cuando no hay barra de envío (p. ej. \"Envío gratis\"). */\n notice?: ReactNode\n /** Sección \"podría interesarte\" (la tienda decide qué mostrar). */\n upsell?: ReactNode\n upsellTitle?: string\n renderLine?: (line: CartLine, defaults: { controls: ReactNode; price: ReactNode; image: ReactNode }) => ReactNode\n renderImage?: (line: CartLine) => ReactNode\n renderMoney?: (money: Money) => ReactNode\n renderLink?: (props: CartDrawerLinkProps) => ReactNode\n /** Omite el variante cuando es el valor por defecto de OPS (\"Default Title\"). */\n isDefaultVariantTitle?: (title: string) => boolean\n icons?: CartDrawerIcons\n /** Clases por pieza (además de los `data-sf-cart-*`), para tiendas con Tailwind. */\n classNames?: Partial<Record<CartDrawerSlot, string>>\n /** Textos de las filas provisionales y de los avisos (por omisión es-MX). */\n optimisticLabels?: Partial<CartDrawerOptimisticLabels>\n locale?: string\n /** Se llama al abrir/cerrar por cualquier vía. */\n onOpenChange?: (open: boolean) => void\n}\n\nconst DEFAULT_FORM: Required<CartDrawerFormContract> = {\n intentField: 'intent',\n lineField: 'line_id',\n quantityField: 'quantity',\n updateIntent: 'update',\n removeIntent: 'remove',\n}\n\nconst useNativeForm = (): CartDrawerLineForm => ({ Form: 'form' })\n\nconst defaultIsDefaultVariant = (t: string) => /^default title$/i.test(t.trim())\n\nfunction useBodyScrollLock(locked: boolean) {\n useEffect(() => {\n if (!locked || typeof document === 'undefined') return\n const el = document.documentElement\n const prev = el.style.overflow\n el.style.overflow = 'hidden'\n return () => {\n el.style.overflow = prev\n }\n }, [locked])\n}\n\n/**\n * Cajón lateral del carrito (\"Tu carrito (N)\"). Sin textos ni marca: todo llega por props.\n * Se monta una vez (en la raíz) y se abre con `openCartDrawer()` / `useCartDrawer()`.\n * `<dialog>` modal: `role=\"dialog\"`, `aria-modal`, foco atrapado y devuelto al abridor, Esc y clic fuera cierran,\n * el fondo no hace scroll. Las mutaciones usan la acción de ruta de la tienda (formularios nativos que\n * funcionan sin JavaScript, o el `Form` de un fetcher con `useLineForm`). Estilos: `@asteby/storefront-react/cart.css`\n * (tokens de la tienda) y/o `classNames`.\n */\nexport function CartDrawer(props: CartDrawerProps) {\n const { cart, labels, paths, shipping, notice, upsell, upsellTitle, icons, classNames: cx = {}, onOpenChange } = props\n const locale = useResolvedLocale(props.locale)\n const { open } = useCartDrawer()\n const opt = useOptimisticCart()\n const ol = { ...DEFAULT_OPTIMISTIC_LABELS, ...props.optimisticLabels }\n const quiet = open && isQuietOpen()\n const titleId = useId()\n const upsellId = useId()\n const { ref, onBackdropClick } = useModalDialog({ open, onClose: () => closeCartDrawer() })\n useBodyScrollLock(open)\n useEffect(() => {\n onOpenChange?.(open)\n }, [open]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const realLines = cart?.lines.length ?? 0\n const rollbackEmpty = open && quiet && realLines === 0 && opt.rows.length === 0 && opt.notices.length > 0\n useEffect(() => {\n // Sin filas y con un aviso de fallo, un cajón vacío abierto por la acción sería engañoso: se cierra.\n if (rollbackEmpty) closeCartDrawer()\n }, [rollbackEmpty])\n\n if (!open) return opt.notices.length ? <OptimisticNotices notices={opt.notices} labels={ol} classNames={cx} /> : null\n\n const money = props.renderMoney ?? ((m: Money) => formatMoney(m, locale))\n const link = props.renderLink ?? (({ href, className, children, onClick }: CartDrawerLinkProps) => (\n <a href={href} className={className} onClick={onClick}>{children}</a>\n ))\n const pendingByVariant = new Map(opt.rows.map((r) => [r.variantId, r]))\n const count = (cart?.total_quantity ?? 0) + opt.quantity\n const lines = cart?.lines ?? []\n const extraRows = opt.rows.filter((r) => !lines.some((l) => l.merchandise.id === r.variantId))\n const pending = opt.rows.length > 0\n const empty = lines.length === 0 && extraRows.length === 0\n const close = () => closeCartDrawer()\n\n return (\n <dialog\n ref={ref}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n onClick={onBackdropClick}\n onClose={close}\n className={cx.dialog}\n data-sf-cart-drawer=\"\"\n >\n <div className={cx.panel} data-sf-cart-panel=\"\">\n <div className={cx.header} data-sf-cart-header=\"\">\n <h2 id={titleId} tabIndex={-1} className={cx.title} data-sf-cart-title=\"\">\n {labels.title}{count > 0 ? ` (${count})` : ''}\n </h2>\n <button type=\"button\" onClick={close} aria-label={labels.close} className={cx.close} data-sf-cart-close=\"\" data-sf-autofocus={quiet ? undefined : ''}>\n {icons?.close ?? <span aria-hidden=\"true\">✕</span>}\n </button>\n </div>\n\n <OptimisticNotices notices={opt.notices} labels={ol} classNames={cx} />\n <OptimisticStatus kind={opt.announcement.kind} n={opt.announcement.n} text={ol.added} />\n\n {empty ? (\n <div className={cx.empty} data-sf-cart-empty=\"\">\n <p className={cx.emptyTitle} data-sf-cart-empty-title=\"\">{labels.empty}</p>\n {labels.emptyHint ? <p className={cx.emptyHint} data-sf-cart-empty-hint=\"\">{labels.emptyHint}</p> : null}\n {paths.browse && labels.browse ? link({ href: paths.browse, className: cx.browse, children: labels.browse, onClick: close }) : null}\n </div>\n ) : (\n <>\n <div className={cx.body} data-sf-cart-body=\"\">\n {shipping ? (\n <div className={cx.shipping} data-sf-cart-shipping=\"\" data-reached={shipping.reached || undefined}>\n <p className={cx.shippingMessage}>\n {shipping.reached ? icons?.shippingReached : icons?.shipping}\n {shipping.message}\n </p>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(shipping.percent)}\n aria-label={shipping.progressLabel}\n className={cx.bar}\n data-sf-cart-bar=\"\"\n >\n <div className={cx.barFill} data-sf-cart-bar-fill=\"\" style={{ width: `${Math.max(0, Math.min(100, shipping.percent))}%` }} />\n </div>\n </div>\n ) : notice ? (\n <p className={[cx.shipping, cx.shippingMessage].filter(Boolean).join(\" \") || undefined} data-sf-cart-shipping=\"\" data-notice=\"\">{icons?.shippingReached}{notice}</p>\n ) : null}\n\n <ul className={cx.lines} data-sf-cart-lines=\"\">\n {lines.map((line) => (\n <DrawerLine key={line.id} line={line} props={props} money={money} link={link} close={close} pending={pendingByVariant.get(line.merchandise.id)} pendingLabel={ol.adding} />\n ))}\n {extraRows.map((row) => (\n <PendingLine key={`pending-${row.variantId}`} row={row} props={props} money={money} label={ol.adding} />\n ))}\n </ul>\n\n {upsell ? (\n <section className={cx.upsell} data-sf-cart-upsell=\"\" aria-labelledby={upsellTitle ? upsellId : undefined}>\n {upsellTitle ? <h3 id={upsellId} className={cx.upsellTitle}>{upsellTitle}</h3> : null}\n {upsell}\n </section>\n ) : null}\n </div>\n\n <div className={cx.footer} data-sf-cart-footer=\"\">\n <div className={cx.subtotal} data-sf-cart-subtotal=\"\" aria-busy={pending || undefined}>\n <span className={cx.subtotalLabel}>{labels.subtotal}</span>\n <span className={cx.subtotalValue} data-sf-cart-subtotal-value=\"\">{cart ? money(cart.cost.subtotal) : null}{pending ? <span data-sf-cart-calculating=\"\">{cart ? ' ' : ''}{ol.calculating}</span> : null}</span>\n </div>\n {labels.note ? <p className={cx.note} data-sf-cart-note=\"\">{labels.note}</p> : null}\n <div className={cx.actions} data-sf-cart-actions=\"\">\n {link({ href: paths.checkout, className: cx.checkout, children: labels.checkout, onClick: close })}\n {link({ href: paths.cart, className: cx.viewCart, children: labels.viewCart, onClick: close })}\n </div>\n </div>\n </>\n )}\n </div>\n </dialog>\n )\n}\n\nfunction DrawerLine({\n line,\n props,\n money,\n link,\n close,\n pending,\n pendingLabel,\n}: {\n pending?: OptimisticRow | undefined\n pendingLabel: string\n line: CartLine\n props: CartDrawerProps\n money: (m: Money) => ReactNode\n link: (p: CartDrawerLinkProps) => ReactNode\n close: () => void\n}) {\n const { labels, paths, icons, classNames: cx = {} } = props\n const f = { ...DEFAULT_FORM, ...props.form }\n const { Form, formData } = (props.useLineForm ?? useNativeForm)()\n const quantity = formData ? Number(formData.get(f.quantityField) ?? 0) : line.quantity + (pending?.quantity ?? 0)\n if (formData && (formData.get(f.intentField) === f.removeIntent || quantity === 0)) return null\n\n const merch = line.merchandise\n const isDefault = props.isDefaultVariantTitle ?? defaultIsDefaultVariant\n const title = merch.product.title\n const href = paths.product?.(merch.product.handle, merch.id)\n const img = merch.image ?? merch.product.featured_image\n const image = props.renderImage ? props.renderImage(line) : img ? (\n <img src={img.url} alt={img.alt ?? ''} width={80} height={80} loading=\"lazy\" decoding=\"async\" />\n ) : null\n\n const imageNode = <span className={cx.image} data-sf-cart-image=\"\">{image}</span>\n const price = <span className={cx.price} data-sf-cart-price=\"\">{money(line.cost.total)}</span>\n const controls = (\n <div className={cx.controls} data-sf-cart-controls=\"\">\n <Form method=\"post\" action={paths.cart} className={cx.qty} data-sf-cart-qty=\"\">\n <input type=\"hidden\" name={f.intentField} value={f.updateIntent} />\n <input type=\"hidden\" name={f.lineField} value={line.id} />\n <button type=\"submit\" name={f.quantityField} value={quantity - 1} aria-label={labels.decrease} className={cx.qtyButton} data-sf-cart-qty-button=\"\">\n {icons?.decrease ?? <span aria-hidden=\"true\">−</span>}\n </button>\n <span className={cx.qtyValue} aria-live=\"polite\" data-sf-cart-qty-value=\"\">{quantity}</span>\n <button type=\"submit\" name={f.quantityField} value={quantity + 1} aria-label={labels.increase} className={cx.qtyButton} data-sf-cart-qty-button=\"\">\n {icons?.increase ?? <span aria-hidden=\"true\">+</span>}\n </button>\n </Form>\n <Form method=\"post\" action={paths.cart} data-sf-cart-remove-form=\"\">\n <input type=\"hidden\" name={f.intentField} value={f.removeIntent} />\n <input type=\"hidden\" name={f.lineField} value={line.id} />\n <button type=\"submit\" className={cx.remove} data-sf-cart-remove=\"\">{labels.remove}</button>\n </Form>\n </div>\n )\n\n if (props.renderLine) return <li key={line.id} className={cx.line} data-sf-cart-line=\"\">{props.renderLine(line, { controls, price, image: imageNode })}</li>\n\n return (\n <li className={cx.line} data-sf-cart-line=\"\">\n {imageNode}\n <div className={cx.lineMain} data-sf-cart-line-main=\"\">\n <div className={cx.lineHead} data-sf-cart-line-head=\"\">\n <div className={cx.lineText} data-sf-cart-line-text=\"\">\n {href ? link({ href, className: cx.lineTitle, children: title, onClick: close }) : <span className={cx.lineTitle} data-sf-cart-line-title=\"\">{title}</span>}\n {!isDefault(merch.title) ? <p className={cx.variant} data-sf-cart-variant=\"\">{merch.title}</p> : null}\n </div>\n {price}\n </div>\n {controls}\n {pending ? <p className={cx.variant} data-sf-cart-pending-label=\"\">{pendingLabel}</p> : null}\n </div>\n </li>\n )\n}\n\n/** Fila que existe solo en el navegador hasta que OPS la confirma: sin controles, con el precio unitario mostrado. */\nfunction PendingLine({ row, props, money, label }: { row: OptimisticRow; props: CartDrawerProps; money: (m: Money) => ReactNode; label: string }) {\n const { classNames: cx = {} } = props\n const isDefault = props.isDefaultVariantTitle ?? defaultIsDefaultVariant\n return (\n <li className={cx.line} data-sf-cart-line=\"\" data-sf-cart-line-pending=\"\" aria-busy=\"true\">\n <span className={cx.image} data-sf-cart-image=\"\">\n {row.image ? <img src={row.image.url} alt={row.image.alt ?? ''} width={80} height={80} decoding=\"async\" /> : null}\n </span>\n <div className={cx.lineMain} data-sf-cart-line-main=\"\">\n <div className={cx.lineHead} data-sf-cart-line-head=\"\">\n <div className={cx.lineText} data-sf-cart-line-text=\"\">\n <span className={cx.lineTitle} data-sf-cart-line-title=\"\">{row.title}</span>\n {row.variantTitle && !isDefault(row.variantTitle) ? <p className={cx.variant} data-sf-cart-variant=\"\">{row.variantTitle}</p> : null}\n </div>\n {row.price ? <span className={cx.price} data-sf-cart-price=\"\">{money(row.price)}</span> : null}\n </div>\n <p className={cx.variant} data-sf-cart-pending-label=\"\">{label} · ×{row.quantity}</p>\n </div>\n </li>\n )\n}\n\n/** Región `aria-live=\"polite\"`: anuncia «Agregado al carrito». Alterna un espacio fino para repetir el mismo texto. */\nfunction OptimisticStatus({ kind, n, text }: { kind: 'added' | null; n: number; text: string }) {\n return (\n <div role=\"status\" aria-live=\"polite\" data-sf-cart-status=\"\" style={VISUALLY_HIDDEN}>\n {kind === 'added' ? `${text}${n % 2 ? '' : '\\u200B'}` : ''}\n </div>\n )\n}\n\nconst VISUALLY_HIDDEN = { position: 'absolute', width: 1, height: 1, margin: -1, padding: 0, overflow: 'hidden', clip: 'rect(0 0 0 0)', whiteSpace: 'nowrap', border: 0 } as const\n\n/** Avisos de fallo (`role=\"alert\"`, assertive), descartables. Se pintan dentro del cajón abierto o, si está cerrado, sueltos. */\nfunction OptimisticNotices({ notices, labels, classNames: cx }: { notices: readonly OptimisticNotice[]; labels: CartDrawerOptimisticLabels; classNames: Partial<Record<CartDrawerSlot, string>> }) {\n return (\n <div role=\"alert\" aria-live=\"assertive\" data-sf-cart-notices=\"\" className={cx.notices}>\n {notices.map((n) => (\n <p key={n.id} data-sf-cart-notice=\"\">\n <span>{labels.failed(n.title, n.reason)}</span>\n <button type=\"button\" onClick={() => cartOptimistic.dismissNotice(n.id)} aria-label={labels.dismiss} data-sf-cart-notice-dismiss=\"\">\n <span aria-hidden=\"true\">✕</span>\n </button>\n </p>\n ))}\n </div>\n )\n}\n"]}
package/dist/cart.css CHANGED
@@ -68,3 +68,17 @@
68
68
  @keyframes sf-cart-in { from { transform: translateX(100%); } }
69
69
  @keyframes sf-cart-fade { from { opacity: 0; } }
70
70
  @media (prefers-reduced-motion: reduce) { [data-sf-cart-bar-fill] { transition: none; } }
71
+
72
+ /* Estado optimista: fila provisional, «calculando…» y avisos de fallo. */
73
+ [data-sf-cart-line-pending] { opacity: .85; }
74
+ [data-sf-cart-pending-label] { margin: .25rem 0 0; font-size: .75rem; color: var(--muted-foreground); }
75
+ [data-sf-cart-calculating] { font-size: .75rem; font-weight: 400; color: var(--muted-foreground); }
76
+ [data-sf-cart-notices]:not(:empty) { display: grid; gap: .5rem; padding: .75rem 1.25rem; }
77
+ [data-sf-cart-notices]:empty { display: none; }
78
+ [data-sf-cart-notice] { display: flex; align-items: center; justify-content: space-between; gap: .75rem; margin: 0; padding: .5rem .75rem; font-size: .875rem; border: 1px solid var(--destructive, var(--border)); border-radius: var(--radius, .375rem); background: color-mix(in srgb, var(--destructive, var(--foreground)) 8%, var(--background)); }
79
+ [data-sf-cart-notice-dismiss] { display: grid; place-items: center; width: 2rem; height: 2rem; padding: 0; font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
80
+ @media (prefers-reduced-motion: no-preference) {
81
+ [data-sf-cart-line-pending] { animation: sf-cart-pulse 1.4s ease-in-out infinite; }
82
+ }
83
+ @keyframes sf-cart-pulse { 50% { opacity: .65; } }
84
+ [data-sf-cart-notices]:not([data-sf-cart-drawer] *):not(:empty) { position: fixed; inset: auto 1rem 1rem auto; z-index: 60; max-width: 24rem; background: var(--card, var(--background)); color: var(--foreground); }