@asteby/storefront-react 0.20.0 → 0.21.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/checkout.css CHANGED
@@ -328,3 +328,145 @@
328
328
  zoom: 0.78;
329
329
  }
330
330
  }
331
+
332
+ /*
333
+ * <ProductThumb>, <ProductPreview>, <ProductThumbStack>: la foto del producto y la línea de producto de la tienda.
334
+ * CSS plano sobre los tokens de la tienda (--foreground, --background, --border, --muted-foreground, --radius); en tema
335
+ * oscuro la superficie y el brillo salen de color-mix, sin colores escritos aquí. Va incluido en cart.css, checkout.css,
336
+ * account.css y ui.css (misma regla, un solo origen: src/ui/product-preview.css).
337
+ */
338
+ [data-sf-thumb] {
339
+ --_surface: color-mix(in srgb, var(--foreground, #111) 5%, var(--background, #fff));
340
+ position: relative;
341
+ display: inline-block;
342
+ flex: none;
343
+ box-sizing: border-box;
344
+ width: var(--sf-preview-size, 3.5rem);
345
+ aspect-ratio: var(--sf-preview-ratio, 1 / 1);
346
+ overflow: hidden;
347
+ border-radius: calc(var(--radius, 0.5rem) * 1.25);
348
+ background: var(--_surface);
349
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground, #111) 9%, transparent);
350
+ vertical-align: middle;
351
+ }
352
+ :root[data-theme="dark"] [data-sf-thumb] { --_surface: color-mix(in srgb, var(--foreground, #fff) 9%, var(--background, #111)); }
353
+ [data-sf-thumb] > img {
354
+ display: block;
355
+ width: 100%;
356
+ height: 100%;
357
+ box-sizing: border-box;
358
+ object-fit: contain;
359
+ padding: 6%;
360
+ transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1), opacity 180ms;
361
+ }
362
+ [data-sf-thumb][data-fit="cover"] > img { object-fit: cover; padding: 0; }
363
+ /* Fotos sobre fondo blanco: se funden con la superficie en tema claro (no hay caja blanca dentro del marco). */
364
+ [data-sf-thumb][data-fit="contain"] > img { mix-blend-mode: multiply; }
365
+ :root[data-theme="dark"] [data-sf-thumb] > img { mix-blend-mode: normal; }
366
+ [data-sf-thumb][data-state="loading"]::before {
367
+ content: "";
368
+ position: absolute;
369
+ inset: 0;
370
+ background: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--foreground, #111) 8%, transparent) 50%, transparent 80%);
371
+ background-size: 200% 100%;
372
+ animation: sf-thumb-shimmer 1.4s linear infinite;
373
+ pointer-events: none;
374
+ }
375
+ @keyframes sf-thumb-shimmer { from { background-position: 150% 0; } to { background-position: -50% 0; } }
376
+ [data-sf-thumb][data-zoom]:hover > img { transform: scale(1.07); }
377
+ @media (prefers-reduced-motion: reduce) {
378
+ [data-sf-thumb][data-state="loading"]::before { animation: none; }
379
+ [data-sf-thumb] > img { transition: none; }
380
+ [data-sf-thumb][data-zoom]:hover > img { transform: none; }
381
+ }
382
+
383
+ [data-sf-thumb-fallback] {
384
+ position: absolute;
385
+ inset: 0;
386
+ display: grid;
387
+ place-items: center;
388
+ color: color-mix(in srgb, var(--foreground, #111) 42%, transparent);
389
+ background: linear-gradient(145deg, color-mix(in srgb, var(--foreground, #111) 3%, transparent), color-mix(in srgb, var(--foreground, #111) 9%, transparent));
390
+ }
391
+ [data-sf-thumb-initial] {
392
+ font-size: calc(var(--sf-preview-size, 3.5rem) * 0.36);
393
+ font-weight: 600;
394
+ letter-spacing: 0.02em;
395
+ line-height: 1;
396
+ }
397
+
398
+ [data-sf-thumb-qty] {
399
+ position: absolute;
400
+ top: 0.2rem;
401
+ right: 0.2rem;
402
+ min-width: 1.25rem;
403
+ height: 1.25rem;
404
+ padding: 0 0.3rem;
405
+ box-sizing: border-box;
406
+ display: inline-grid;
407
+ place-items: center;
408
+ border-radius: 999px;
409
+ font-size: 0.7rem;
410
+ font-weight: 700;
411
+ font-variant-numeric: tabular-nums;
412
+ background: var(--sf-summary-qty-bg, color-mix(in srgb, var(--foreground, #111) 78%, transparent));
413
+ color: var(--sf-summary-qty-fg, var(--background, #fff));
414
+ }
415
+
416
+ /* Línea de producto: foto | texto | importe. */
417
+ [data-sf-preview] {
418
+ display: flex;
419
+ align-items: center;
420
+ gap: 0.875rem;
421
+ min-width: 0;
422
+ }
423
+ [data-sf-preview][data-missing] [data-sf-preview-name] { font-style: italic; color: var(--muted-foreground, color-mix(in srgb, currentColor 60%, transparent)); }
424
+ [data-sf-preview-media] { flex: none; display: inline-flex; }
425
+ [data-sf-preview-body] { display: grid; flex: 1 1 auto; gap: 0.125rem; min-width: 0; }
426
+ [data-sf-preview-name] {
427
+ display: -webkit-box;
428
+ -webkit-line-clamp: 2;
429
+ -webkit-box-orient: vertical;
430
+ overflow: hidden;
431
+ overflow-wrap: anywhere;
432
+ font-size: 0.9375rem;
433
+ font-weight: 600;
434
+ line-height: 1.3;
435
+ }
436
+ [data-sf-preview-name] a { color: inherit; text-decoration: none; }
437
+ [data-sf-preview-name] a:hover { text-decoration: underline; }
438
+ [data-sf-preview-variant],
439
+ [data-sf-preview-sku],
440
+ [data-sf-preview-meta] {
441
+ font-size: 0.8125rem;
442
+ line-height: 1.35;
443
+ color: var(--muted-foreground, color-mix(in srgb, currentColor 66%, transparent));
444
+ }
445
+ [data-sf-preview-sku] { font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
446
+ [data-sf-preview-total] {
447
+ flex: none;
448
+ align-self: flex-start;
449
+ font-size: 0.9375rem;
450
+ font-weight: 700;
451
+ font-variant-numeric: tabular-nums;
452
+ text-align: right;
453
+ }
454
+
455
+ /* Fotos apiladas (tarjeta de pedido). */
456
+ [data-sf-thumb-stack] { display: inline-flex; align-items: center; }
457
+ [data-sf-thumb-stack] > * { box-shadow: 0 0 0 2px var(--card, var(--background, #fff)), inset 0 0 0 1px color-mix(in srgb, var(--foreground, #111) 9%, transparent); }
458
+ [data-sf-thumb-stack] > * + * { margin-inline-start: -0.625rem; }
459
+ [data-sf-thumb-more] {
460
+ display: inline-grid;
461
+ place-items: center;
462
+ flex: none;
463
+ box-sizing: border-box;
464
+ width: var(--sf-preview-size, 2.75rem);
465
+ aspect-ratio: 1 / 1;
466
+ border-radius: calc(var(--radius, 0.5rem) * 1.25);
467
+ font-size: 0.8125rem;
468
+ font-weight: 600;
469
+ font-variant-numeric: tabular-nums;
470
+ color: var(--muted-foreground, color-mix(in srgb, currentColor 66%, transparent));
471
+ background: color-mix(in srgb, var(--foreground, #111) 7%, var(--background, #fff));
472
+ }
@@ -131,8 +131,10 @@ type OrderSummaryProps = {
131
131
  cost: CartCost;
132
132
  /** The delivery is being saved and the cart re-read: shipping and total say so (`aria-busy`). */
133
133
  updating?: boolean;
134
- /** Picture of a line (e.g. `<ProductImage>`), 48-64 px. The quantity badge sits on it. */
134
+ /** Picture of a line (e.g. `<ProductImage>`), 48-64 px. The quantity badge sits on it. Default: `<ProductThumb>` of the line's image (fallback initial when it has none). */
135
135
  renderLineMedia?: (line: CartLine) => ReactNode;
136
+ /** Show the default picture of each line. Default true; `false` gives the text-only "2 × Name" list. */
137
+ media?: boolean;
136
138
  renderAmount?: (amount: Money) => ReactNode;
137
139
  /** Heading. `false` hides it (the disclosure already names the block). */
138
140
  title?: ReactNode | false;
@@ -131,8 +131,10 @@ type OrderSummaryProps = {
131
131
  cost: CartCost;
132
132
  /** The delivery is being saved and the cart re-read: shipping and total say so (`aria-busy`). */
133
133
  updating?: boolean;
134
- /** Picture of a line (e.g. `<ProductImage>`), 48-64 px. The quantity badge sits on it. */
134
+ /** Picture of a line (e.g. `<ProductImage>`), 48-64 px. The quantity badge sits on it. Default: `<ProductThumb>` of the line's image (fallback initial when it has none). */
135
135
  renderLineMedia?: (line: CartLine) => ReactNode;
136
+ /** Show the default picture of each line. Default true; `false` gives the text-only "2 × Name" list. */
137
+ media?: boolean;
136
138
  renderAmount?: (amount: Money) => ReactNode;
137
139
  /** Heading. `false` hides it (the disclosure already names the block). */
138
140
  title?: ReactNode | false;
package/dist/checkout.js CHANGED
@@ -2,6 +2,8 @@ import { brandName, BrandMark, brandKey } from './chunk-JNUJGPJC.js';
2
2
  export { BrandMark, brandKey, brandLogo, brandName, findBrand, listBrands } from './chunk-JNUJGPJC.js';
3
3
  import { CheckoutField } from './chunk-DFGLCIEG.js';
4
4
  export { CheckoutField, ErrorSummary, fieldMessages, useFieldErrors, validationMessage } from './chunk-DFGLCIEG.js';
5
+ import { ProductThumb } from './chunk-VHEY5AU3.js';
6
+ import './chunk-6CVKW7F3.js';
5
7
  import { useResolvedLocale } from './chunk-T52H5HL3.js';
6
8
  import './chunk-DQBL2DFJ.js';
7
9
  import { useId, useState, useRef, useEffect, useMemo, useSyncExternalStore } from 'react';
@@ -302,13 +304,18 @@ function orderSummaryMessages(locale, overrides) {
302
304
  const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN2 : ES2;
303
305
  return overrides ? { ...base, ...overrides } : base;
304
306
  }
307
+ function defaultLineMedia(l) {
308
+ const img = l.merchandise.image ?? l.merchandise.product.featured_image ?? null;
309
+ return /* @__PURE__ */ jsx(ProductThumb, { image: img, name: l.merchandise.product.title, size: 56, decorative: true, zoom: false });
310
+ }
305
311
  var isZero = (m) => !!m && Number(m.amount) === 0;
306
312
  var positive = (m) => !!m && Number(m.amount) > 0;
307
313
  function OrderSummary(props) {
308
- const { lines, cost, updating = false, renderLineMedia, renderAmount, title, headingLevel = 2, classNames: cx = {}, children } = props;
314
+ const { lines, cost, updating = false, media = true, renderAmount, title, headingLevel = 2, classNames: cx = {}, children } = props;
309
315
  const locale = useResolvedLocale(props.locale);
310
316
  const m = orderSummaryMessages(locale, props.messages);
311
317
  const money = (v) => renderAmount ? renderAmount(v) : formatMoney(v, locale);
318
+ const renderLineMedia = props.renderLineMedia ?? (media ? defaultLineMedia : void 0);
312
319
  const H = headingLevel === 3 ? "h3" : "h2";
313
320
  const discounts = cost.discounts?.filter((d) => positive(d.amount)) ?? [];
314
321
  return /* @__PURE__ */ jsxs("div", { className: cx.root, "data-sf-summary": true, children: [