UNPKG

@shopify/shop-minis-react

Version:

React component library for Shopify Shop Minis with Tailwind CSS v4 support (source-only, requires TypeScript)

306 lines (305 loc) 7.76 kB
import { jsx as o, jsxs as h } from "react/jsx-runtime"; import * as F from "react"; import { useState as R, useCallback as C, useMemo as k, useContext as z } from "react"; import { useShopNavigation as S } from "../../hooks/navigation/useShopNavigation.js"; import { useSavedProductsActions as V } from "../../hooks/user/useSavedProductsActions.js"; import { ProductReviewStars as j } from "../../internal/components/product-review-stars.js"; import { cn as d } from "../../lib/utils.js"; import { formatMoney as B } from "../../utils/formatMoney.js"; import { Image as T } from "../atoms/image.js"; import { ProductVariantPrice as E } from "../atoms/product-variant-price.js"; import { Touchable as O } from "../atoms/touchable.js"; import { Badge as L } from "../ui/badge.js"; import { FavoriteButton as M } from "./favorite-button.js"; const b = F.createContext(void 0); function s() { const t = z(b); if (!t) throw new Error( "ProductCard components must be used within a ProductCard provider" ); return t; } function q({ className: t, ...e }) { const { touchable: r, onClick: a } = s(), n = /* @__PURE__ */ o( "div", { className: d( "relative size-full overflow-hidden rounded-xl border-0 isolate", t ), ...e } ); return r && a ? /* @__PURE__ */ o( O, { onClick: a, whileTap: { opacity: 0.7 }, transition: { opacity: { type: "tween", duration: 0.08, ease: "easeInOut" } }, children: n } ) : n; } function D({ className: t, ...e }) { const { variant: r } = s(); return /* @__PURE__ */ o( "div", { "data-slot": "product-card-image-container", className: d( "relative overflow-hidden rounded-xl border border-gray-200", "aspect-square", r === "compact" ? "min-h-[104px]" : "min-h-[134px]", t ), ...e } ); } function G({ className: t, ...e }) { const { product: r, selectedProductVariant: a } = s(), n = a?.image || r.featuredImage, i = n?.url, u = n?.altText || r.title, c = r.featuredImage?.thumbhash, p = C( (l) => c ? /* @__PURE__ */ o( T, { "data-slot": "product-card-image", src: l, alt: u, aspectRatio: 1, thumbhash: c, objectFit: "cover", className: d("size-full", t), ...e } ) : /* @__PURE__ */ o( "img", { "data-slot": "product-card-image", src: l, alt: u, className: d("size-full object-cover", t), ...e } ), [u, t, e, c] ); return /* @__PURE__ */ o("div", { className: "bg-gray-100 flex items-center justify-center size-full", children: i ? p(i) : /* @__PURE__ */ o("div", { className: "text-gray-400 text-sm w-full text-center", children: "No Image" }) }); } function N({ className: t, position: e = "bottom-left", variant: r, children: a, ...n }) { const { badgeText: i, badgeVariant: u } = s(), c = a || i; return c ? /* @__PURE__ */ o( "div", { className: d( "absolute z-10", e === "top-left" ? "top-3 left-3" : "bottom-2 left-2" ), children: /* @__PURE__ */ o( L, { variant: r ?? u ?? "none", className: d( !u && !r && "bg-black/50 text-white border-transparent", "rounded", t ), ...n, children: c } ) } ) : null; } function H({ className: t, ...e }) { const { isFavorited: r, favoriteButtonDisabled: a, onFavoriteToggle: n } = s(); return a ? null : /* @__PURE__ */ o("div", { className: d("absolute bottom-3 right-3 z-10", t), ...e, children: /* @__PURE__ */ o(M, { onClick: n, filled: r }) }); } function J({ className: t, ...e }) { const { variant: r } = s(); return r !== "default" ? null : /* @__PURE__ */ o( "div", { "data-testid": "product-card-info", className: d("px-1 pt-2 pb-0 space-y-1", t), ...e } ); } function K({ className: t, children: e, ...r }) { const { product: a } = s(); return /* @__PURE__ */ o( "h3", { "data-slot": "product-card-title", className: d( "text-sm font-medium leading-tight text-gray-900", "truncate overflow-hidden whitespace-nowrap text-ellipsis", t ), ...r, children: e || a.title } ); } function Q({ className: t, ...e }) { const { product: r, reviewsDisabled: a } = s(), n = r.reviewAnalytics; return a || !n?.averageRating ? null : /* @__PURE__ */ o( "div", { "data-slot": "product-card-review-stars", className: d("", t), ...e, children: /* @__PURE__ */ o( j, { averageRating: n.averageRating, reviewCount: n.reviewCount } ) } ); } function U({ className: t }) { const { product: e, selectedProductVariant: r } = s(), a = r?.price || e?.price, n = r?.compareAtPrice || e?.compareAtPrice; return /* @__PURE__ */ o( E, { amount: a?.amount || "", currencyCode: a?.currencyCode || "", compareAtPriceAmount: n?.amount, compareAtPriceCurrencyCode: n?.currencyCode, className: t } ); } function W() { const { product: t, selectedProductVariant: e, variant: r } = s(); if (r !== "priceOverlay") return null; const a = e?.price || t.price, n = a?.currencyCode, i = a?.amount; return !n || !i ? null : /* @__PURE__ */ o(N, { position: "top-left", children: B(i, n) }); } function dt({ product: t, selectedProductVariant: e, variant: r = "default", touchable: a = !0, badgeText: n, badgeVariant: i, onProductClick: u, onFavoriteToggled: c, children: p, favoriteButtonDisabled: l = !1, reviewsDisabled: v = !1 }) { const { navigateToProduct: g } = S(), { saveProduct: P, unsaveProduct: y } = V(), [f, x] = R(t.isFavorited), w = C(() => { a && (u?.(), g({ productId: t.id })); }, [g, t.id, a, u]), I = C(async () => { const m = f; x(!m), c?.(!m); try { m ? await y({ productId: t.id, shopId: t.shop.id, productVariantId: e?.id || t.defaultVariantId }) : await P({ productId: t.id, shopId: t.shop.id, productVariantId: e?.id || t.defaultVariantId }); } catch { x(m), c?.(m); } }, [ f, t.id, t.shop.id, t.defaultVariantId, e?.id, P, y, c ]), A = k( () => ({ // Core data product: t, selectedProductVariant: e, // UI configuration variant: r, touchable: a, badgeText: n, badgeVariant: i, favoriteButtonDisabled: l, reviewsDisabled: v, // State isFavorited: f, // Actions onClick: w, onFavoriteToggle: I }), [ t, e, r, a, n, i, f, w, I, l, v ] ); return /* @__PURE__ */ o(b.Provider, { value: A, children: p ?? /* @__PURE__ */ h(q, { children: [ /* @__PURE__ */ h(D, { children: [ /* @__PURE__ */ o(G, {}), r === "priceOverlay" && /* @__PURE__ */ o(W, {}), /* @__PURE__ */ o(N, {}), /* @__PURE__ */ o(H, {}) ] }), r === "default" && /* @__PURE__ */ h(J, { children: [ /* @__PURE__ */ o(K, {}), /* @__PURE__ */ o(Q, {}), /* @__PURE__ */ o(U, {}) ] }) ] }) }); } export { dt as ProductCard, N as ProductCardBadge, q as ProductCardContainer, H as ProductCardFavoriteButton, G as ProductCardImage, D as ProductCardImageContainer, J as ProductCardInfo, U as ProductCardPrice, Q as ProductCardReviewStars, K as ProductCardTitle }; //# sourceMappingURL=product-card.js.map