@shopify/shop-minis-react 0.0.0-snapshot.20251215165459 → 0.0.0-snapshot.20251216112959

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.
@@ -1,6 +1,6 @@
1
1
  import { jsx as n, jsxs as h, Fragment as d } from "react/jsx-runtime";
2
+ import { formatMoney as a } from "../../lib/formatMoney.js";
2
3
  import { cn as i } from "../../lib/utils.js";
3
- import { formatMoney as a } from "../../utils/formatMoney.js";
4
4
  function N({
5
5
  amount: r,
6
6
  currencyCode: t,
@@ -1 +1 @@
1
- {"version":3,"file":"product-variant-price.js","sources":["../../../src/components/atoms/product-variant-price.tsx"],"sourcesContent":["import {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\n\nexport interface ProductVariantPriceProps {\n amount: number | string\n currencyCode?: string\n compareAtPriceAmount?: number | string\n compareAtPriceCurrencyCode?: string\n currentPriceClassName?: string\n originalPriceClassName?: string\n className?: string\n}\n\nexport function ProductVariantPrice({\n amount,\n currencyCode,\n compareAtPriceAmount,\n compareAtPriceCurrencyCode,\n currentPriceClassName,\n originalPriceClassName,\n className,\n}: ProductVariantPriceProps) {\n if (!amount || !currencyCode) {\n return null\n }\n\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const amountStr = String(amount)\n const compareAtPriceAmountStr = compareAtPriceAmount\n ? String(compareAtPriceAmount)\n : undefined\n\n return (\n <div className={cn('flex items-center gap-2', className)}>\n {hasDiscount ? (\n <>\n <span\n className={cn(\n 'text-sm font-semibold text-gray-900',\n currentPriceClassName\n )}\n >\n {formatMoney(amountStr, currencyCode)}\n </span>\n <span\n className={cn(\n 'text-sm text-gray-500 line-through',\n originalPriceClassName\n )}\n >\n {formatMoney(\n compareAtPriceAmountStr!,\n compareAtPriceCurrencyCode || currencyCode\n )}\n </span>\n </>\n ) : (\n <span\n className={cn(\n 'text-sm font-semibold text-gray-900',\n currentPriceClassName\n )}\n >\n {formatMoney(amountStr, currencyCode)}\n </span>\n )}\n </div>\n )\n}\n"],"names":["ProductVariantPrice","amount","currencyCode","compareAtPriceAmount","compareAtPriceCurrencyCode","currentPriceClassName","originalPriceClassName","className","hasDiscount","amountStr","compareAtPriceAmountStr","jsx","cn","jsxs","Fragment","formatMoney"],"mappings":";;;AAaO,SAASA,EAAoB;AAAA,EAClC,QAAAC;AAAA,EACA,cAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,4BAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,WAAAC;AACF,GAA6B;AACvB,MAAA,CAACN,KAAU,CAACC;AACP,WAAA;AAGH,QAAAM,IAAcL,KAAwBA,MAAyBF,GAE/DQ,IAAY,OAAOR,CAAM,GACzBS,IAA0BP,IAC5B,OAAOA,CAAoB,IAC3B;AAGF,SAAA,gBAAAQ,EAAC,SAAI,WAAWC,EAAG,2BAA2BL,CAAS,GACpD,cAEG,gBAAAM,EAAAC,GAAA,EAAA,UAAA;AAAA,IAAA,gBAAAH;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC;AAAA,UACT;AAAA,UACAP;AAAA,QACF;AAAA,QAEC,UAAAU,EAAYN,GAAWP,CAAY;AAAA,MAAA;AAAA,IACtC;AAAA,IACA,gBAAAS;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC;AAAA,UACT;AAAA,UACAN;AAAA,QACF;AAAA,QAEC,UAAAS;AAAA,UACCL;AAAA,UACAN,KAA8BF;AAAA,QAAA;AAAA,MAChC;AAAA,IAAA;AAAA,EACF,EAAA,CACF,IAEA,gBAAAS;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACAP;AAAA,MACF;AAAA,MAEC,UAAAU,EAAYN,GAAWP,CAAY;AAAA,IAAA;AAAA,EAAA,GAG1C;AAEJ;"}
1
+ {"version":3,"file":"product-variant-price.js","sources":["../../../src/components/atoms/product-variant-price.tsx"],"sourcesContent":["import {formatMoney} from '../../lib/formatMoney'\nimport {cn} from '../../lib/utils'\n\nexport interface ProductVariantPriceProps {\n amount: number | string\n currencyCode?: string\n compareAtPriceAmount?: number | string\n compareAtPriceCurrencyCode?: string\n currentPriceClassName?: string\n originalPriceClassName?: string\n className?: string\n}\n\nexport function ProductVariantPrice({\n amount,\n currencyCode,\n compareAtPriceAmount,\n compareAtPriceCurrencyCode,\n currentPriceClassName,\n originalPriceClassName,\n className,\n}: ProductVariantPriceProps) {\n if (!amount || !currencyCode) {\n return null\n }\n\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const amountStr = String(amount)\n const compareAtPriceAmountStr = compareAtPriceAmount\n ? String(compareAtPriceAmount)\n : undefined\n\n return (\n <div className={cn('flex items-center gap-2', className)}>\n {hasDiscount ? (\n <>\n <span\n className={cn(\n 'text-sm font-semibold text-gray-900',\n currentPriceClassName\n )}\n >\n {formatMoney(amountStr, currencyCode)}\n </span>\n <span\n className={cn(\n 'text-sm text-gray-500 line-through',\n originalPriceClassName\n )}\n >\n {formatMoney(\n compareAtPriceAmountStr!,\n compareAtPriceCurrencyCode || currencyCode\n )}\n </span>\n </>\n ) : (\n <span\n className={cn(\n 'text-sm font-semibold text-gray-900',\n currentPriceClassName\n )}\n >\n {formatMoney(amountStr, currencyCode)}\n </span>\n )}\n </div>\n )\n}\n"],"names":["ProductVariantPrice","amount","currencyCode","compareAtPriceAmount","compareAtPriceCurrencyCode","currentPriceClassName","originalPriceClassName","className","hasDiscount","amountStr","compareAtPriceAmountStr","jsx","cn","jsxs","Fragment","formatMoney"],"mappings":";;;AAaO,SAASA,EAAoB;AAAA,EAClC,QAAAC;AAAA,EACA,cAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,4BAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,WAAAC;AACF,GAA6B;AACvB,MAAA,CAACN,KAAU,CAACC;AACP,WAAA;AAGH,QAAAM,IAAcL,KAAwBA,MAAyBF,GAE/DQ,IAAY,OAAOR,CAAM,GACzBS,IAA0BP,IAC5B,OAAOA,CAAoB,IAC3B;AAGF,SAAA,gBAAAQ,EAAC,SAAI,WAAWC,EAAG,2BAA2BL,CAAS,GACpD,cAEG,gBAAAM,EAAAC,GAAA,EAAA,UAAA;AAAA,IAAA,gBAAAH;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC;AAAA,UACT;AAAA,UACAP;AAAA,QACF;AAAA,QAEC,UAAAU,EAAYN,GAAWP,CAAY;AAAA,MAAA;AAAA,IACtC;AAAA,IACA,gBAAAS;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWC;AAAA,UACT;AAAA,UACAN;AAAA,QACF;AAAA,QAEC,UAAAS;AAAA,UACCL;AAAA,UACAN,KAA8BF;AAAA,QAAA;AAAA,MAChC;AAAA,IAAA;AAAA,EACF,EAAA,CACF,IAEA,gBAAAS;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACAP;AAAA,MACF;AAAA,MAEC,UAAAU,EAAYN,GAAWP,CAAY;AAAA,IAAA;AAAA,EAAA,GAG1C;AAEJ;"}
@@ -4,8 +4,8 @@ import { useState as R, useCallback as C, useMemo as k, useContext as z } from "
4
4
  import { useShopNavigation as S } from "../../hooks/navigation/useShopNavigation.js";
5
5
  import { useSavedProductsActions as V } from "../../hooks/user/useSavedProductsActions.js";
6
6
  import { ProductReviewStars as j } from "../../internal/components/product-review-stars.js";
7
+ import { formatMoney as B } from "../../lib/formatMoney.js";
7
8
  import { cn as d } from "../../lib/utils.js";
8
- import { formatMoney as B } from "../../utils/formatMoney.js";
9
9
  import { Image as T } from "../atoms/image.js";
10
10
  import { ProductVariantPrice as E } from "../atoms/product-variant-price.js";
11
11
  import { Touchable as O } from "../atoms/touchable.js";
@@ -1 +1 @@
1
- {"version":3,"file":"product-card.js","sources":["../../../src/components/commerce/product-card.tsx"],"sourcesContent":["import * as React from 'react'\nimport {useCallback, useContext, useMemo, useState} from 'react'\n\nimport {type Product, type ProductVariant} from '@shopify/shop-minis-platform'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\nimport {Image} from '../atoms/image'\nimport {ProductVariantPrice} from '../atoms/product-variant-price'\nimport {Touchable} from '../atoms/touchable'\nimport {Badge} from '../ui/badge'\n\nimport {FavoriteButton} from './favorite-button'\n\n// Context definition\ninterface ProductCardContextValue {\n // Core data\n product: Product\n selectedProductVariant?: ProductVariant\n\n // UI configuration\n variant: 'default' | 'priceOverlay' | 'compact'\n touchable: boolean\n badgeText?: string\n badgeVariant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'none'\n favoriteButtonDisabled: boolean\n reviewsDisabled: boolean\n\n // State\n isFavorited: boolean\n\n // Actions\n onClick: () => void\n onFavoriteToggle: () => void\n}\n\nconst ProductCardContext = React.createContext<\n ProductCardContextValue | undefined\n>(undefined)\n\nfunction useProductCardContext() {\n const context = useContext(ProductCardContext)\n if (!context) {\n throw new Error(\n 'ProductCard components must be used within a ProductCard provider'\n )\n }\n return context\n}\n\n// Primitive components (building blocks)\nfunction ProductCardContainer({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {touchable, onClick} = useProductCardContext()\n\n const content = (\n <div\n className={cn(\n 'relative size-full overflow-hidden rounded-xl border-0 isolate',\n className\n )}\n {...props}\n />\n )\n\n if (touchable && onClick) {\n return (\n <Touchable\n onClick={onClick}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {content}\n </Touchable>\n )\n }\n\n return content\n}\n\nfunction ProductCardImageContainer({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {variant} = useProductCardContext()\n\n return (\n <div\n data-slot=\"product-card-image-container\"\n className={cn(\n 'relative overflow-hidden rounded-xl border border-gray-200',\n 'aspect-square',\n variant === 'compact' ? 'min-h-[104px]' : 'min-h-[134px]',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductCardImage({className, ...props}: React.ComponentProps<'img'>) {\n const {product, selectedProductVariant} = useProductCardContext()\n\n // Derive display image locally\n const displayImage = selectedProductVariant?.image || product.featuredImage\n const src = displayImage?.url\n const alt = displayImage?.altText || product.title\n const thumbhash = product.featuredImage?.thumbhash\n\n const renderImageElement = useCallback(\n (src: string) => {\n const imageElement = thumbhash ? (\n <Image\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n aspectRatio={1}\n thumbhash={thumbhash}\n objectFit=\"cover\"\n className={cn('size-full', className)}\n {...props}\n />\n ) : (\n <img\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n className={cn('size-full object-cover', className)}\n {...props}\n />\n )\n\n return imageElement\n },\n [alt, className, props, thumbhash]\n )\n\n return (\n <div className=\"bg-gray-100 flex items-center justify-center size-full\">\n {src ? (\n renderImageElement(src)\n ) : (\n <div className=\"text-gray-400 text-sm w-full text-center\">No Image</div>\n )}\n </div>\n )\n}\n\nfunction ProductCardBadge({\n className,\n position = 'bottom-left',\n variant,\n children,\n ...props\n}: React.ComponentProps<typeof Badge> & {\n position?: 'top-left' | 'bottom-left'\n}) {\n const {badgeText, badgeVariant} = useProductCardContext()\n // If no children provided, use badgeText from context\n const content = children || badgeText\n\n if (!content) return null\n\n return (\n <div\n className={cn(\n 'absolute z-10',\n position === 'top-left' ? 'top-3 left-3' : 'bottom-2 left-2'\n )}\n >\n <Badge\n variant={variant ?? badgeVariant ?? 'none'}\n className={cn(\n !badgeVariant &&\n !variant &&\n 'bg-black/50 text-white border-transparent',\n 'rounded',\n className\n )}\n {...props}\n >\n {content}\n </Badge>\n </div>\n )\n}\n\nfunction ProductCardFavoriteButton({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {isFavorited, favoriteButtonDisabled, onFavoriteToggle} =\n useProductCardContext()\n if (favoriteButtonDisabled) return null\n\n return (\n <div className={cn('absolute bottom-3 right-3 z-10', className)} {...props}>\n <FavoriteButton onClick={onFavoriteToggle} filled={isFavorited} />\n </div>\n )\n}\n\nfunction ProductCardInfo({className, ...props}: React.ComponentProps<'div'>) {\n const {variant} = useProductCardContext()\n if (variant !== 'default') {\n return null\n }\n\n return (\n <div\n data-testid=\"product-card-info\"\n className={cn('px-1 pt-2 pb-0 space-y-1', className)}\n {...props}\n />\n )\n}\n\nfunction ProductCardTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n const {product} = useProductCardContext()\n return (\n <h3\n data-slot=\"product-card-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900',\n 'truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children || product.title}\n </h3>\n )\n}\n\nfunction ProductCardReviewStars({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {product, reviewsDisabled} = useProductCardContext()\n const reviewAnalytics = product.reviewAnalytics\n\n if (reviewsDisabled || !reviewAnalytics?.averageRating) {\n return null\n }\n\n return (\n <div\n data-slot=\"product-card-review-stars\"\n className={cn('', className)}\n {...props}\n >\n <ProductReviewStars\n averageRating={reviewAnalytics.averageRating}\n reviewCount={reviewAnalytics.reviewCount}\n />\n </div>\n )\n}\n\nfunction ProductCardPrice({className}: {className?: string}) {\n const {product, selectedProductVariant} = useProductCardContext()\n\n // Derive price data locally\n const displayPrice = selectedProductVariant?.price || product?.price\n const displayCompareAtPrice =\n selectedProductVariant?.compareAtPrice || product?.compareAtPrice\n\n return (\n <ProductVariantPrice\n amount={displayPrice?.amount || ''}\n currencyCode={displayPrice?.currencyCode || ''}\n compareAtPriceAmount={displayCompareAtPrice?.amount}\n compareAtPriceCurrencyCode={displayCompareAtPrice?.currencyCode}\n className={className}\n />\n )\n}\n\n// Special PriceOverlayBadge for price overlay variant\nfunction ProductCardPriceOverlayBadge() {\n const {product, selectedProductVariant, variant} = useProductCardContext()\n if (variant !== 'priceOverlay') return null\n const displayPrice = selectedProductVariant?.price || product.price\n const currencyCode = displayPrice?.currencyCode\n const amount = displayPrice?.amount\n\n if (!currencyCode || !amount) return null\n return (\n <ProductCardBadge position=\"top-left\">\n {formatMoney(amount, currencyCode)}\n </ProductCardBadge>\n )\n}\n\nexport interface ProductCardProps {\n /** The product to display in the card */\n product: Product\n /** Optional selected variant of the product to show specific variant data */\n selectedProductVariant?: ProductVariant\n /** Visual style variant of the card */\n variant?: 'default' | 'priceOverlay' | 'compact'\n /** Whether the card can be clicked/tapped to navigate to product details */\n touchable?: boolean\n /** Optional text to display in a badge on the card */\n badgeText?: string\n /** Visual style variant for the badge */\n badgeVariant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'none'\n /** Callback fired when the product is clicked */\n onProductClick?: () => void\n /** Callback fired when the favorite button is toggled */\n onFavoriteToggled?: (isFavorited: boolean) => void\n /** Custom layout via children */\n children?: React.ReactNode\n /** Whether the favorite button is disabled */\n favoriteButtonDisabled?: boolean\n /** Whether review stars are disabled */\n reviewsDisabled?: boolean\n}\n\nfunction ProductCard({\n product,\n selectedProductVariant,\n variant = 'default',\n touchable = true,\n badgeText,\n badgeVariant,\n onProductClick,\n onFavoriteToggled,\n children,\n favoriteButtonDisabled = false,\n reviewsDisabled = false,\n}: ProductCardProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = useState(product.isFavorited)\n\n const handleClick = useCallback(() => {\n if (!touchable) return\n\n onProductClick?.()\n\n navigateToProduct({\n productId: product.id,\n })\n }, [navigateToProduct, product.id, touchable, onProductClick])\n\n const handleFavoriteClick = useCallback(async () => {\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n onFavoriteToggled?.(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: product.id,\n shopId: product.shop.id,\n productVariantId:\n selectedProductVariant?.id || product.defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: product.id,\n shopId: product.shop.id,\n productVariantId:\n selectedProductVariant?.id || product.defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n onFavoriteToggled?.(previousState)\n }\n }, [\n isFavoritedLocal,\n product.id,\n product.shop.id,\n product.defaultVariantId,\n selectedProductVariant?.id,\n saveProduct,\n unsaveProduct,\n onFavoriteToggled,\n ])\n\n const contextValue = useMemo<ProductCardContextValue>(\n () => ({\n // Core data\n product,\n selectedProductVariant,\n\n // UI configuration\n variant,\n touchable,\n badgeText,\n badgeVariant,\n favoriteButtonDisabled,\n reviewsDisabled,\n\n // State\n isFavorited: isFavoritedLocal,\n // Actions\n onClick: handleClick,\n onFavoriteToggle: handleFavoriteClick,\n }),\n [\n product,\n selectedProductVariant,\n variant,\n touchable,\n badgeText,\n badgeVariant,\n isFavoritedLocal,\n handleClick,\n handleFavoriteClick,\n favoriteButtonDisabled,\n reviewsDisabled,\n ]\n )\n\n return (\n <ProductCardContext.Provider value={contextValue}>\n {children ?? (\n <ProductCardContainer>\n <ProductCardImageContainer>\n <ProductCardImage />\n {variant === 'priceOverlay' && <ProductCardPriceOverlayBadge />}\n <ProductCardBadge />\n <ProductCardFavoriteButton />\n </ProductCardImageContainer>\n {variant === 'default' && (\n <ProductCardInfo>\n <ProductCardTitle />\n <ProductCardReviewStars />\n <ProductCardPrice />\n </ProductCardInfo>\n )}\n </ProductCardContainer>\n )}\n </ProductCardContext.Provider>\n )\n}\n\nexport {\n ProductCard,\n ProductCardContainer,\n ProductCardImageContainer,\n ProductCardImage,\n ProductCardBadge,\n ProductCardFavoriteButton,\n ProductCardInfo,\n ProductCardTitle,\n ProductCardReviewStars,\n ProductCardPrice,\n}\n"],"names":["ProductCardContext","React","useProductCardContext","context","useContext","ProductCardContainer","className","props","touchable","onClick","content","jsx","cn","Touchable","ProductCardImageContainer","variant","ProductCardImage","product","selectedProductVariant","displayImage","src","alt","thumbhash","renderImageElement","useCallback","Image","ProductCardBadge","position","children","badgeText","badgeVariant","Badge","ProductCardFavoriteButton","isFavorited","favoriteButtonDisabled","onFavoriteToggle","FavoriteButton","ProductCardInfo","ProductCardTitle","ProductCardReviewStars","reviewsDisabled","reviewAnalytics","ProductReviewStars","ProductCardPrice","displayPrice","displayCompareAtPrice","ProductVariantPrice","ProductCardPriceOverlayBadge","currencyCode","amount","formatMoney","ProductCard","onProductClick","onFavoriteToggled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","isFavoritedLocal","setIsFavoritedLocal","useState","handleClick","handleFavoriteClick","previousState","contextValue","useMemo","jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"product-card.js","sources":["../../../src/components/commerce/product-card.tsx"],"sourcesContent":["import * as React from 'react'\nimport {useCallback, useContext, useMemo, useState} from 'react'\n\nimport {type Product, type ProductVariant} from '@shopify/shop-minis-platform'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {formatMoney} from '../../lib/formatMoney'\nimport {cn} from '../../lib/utils'\nimport {Image} from '../atoms/image'\nimport {ProductVariantPrice} from '../atoms/product-variant-price'\nimport {Touchable} from '../atoms/touchable'\nimport {Badge} from '../ui/badge'\n\nimport {FavoriteButton} from './favorite-button'\n\n// Context definition\ninterface ProductCardContextValue {\n // Core data\n product: Product\n selectedProductVariant?: ProductVariant\n\n // UI configuration\n variant: 'default' | 'priceOverlay' | 'compact'\n touchable: boolean\n badgeText?: string\n badgeVariant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'none'\n favoriteButtonDisabled: boolean\n reviewsDisabled: boolean\n\n // State\n isFavorited: boolean\n\n // Actions\n onClick: () => void\n onFavoriteToggle: () => void\n}\n\nconst ProductCardContext = React.createContext<\n ProductCardContextValue | undefined\n>(undefined)\n\nfunction useProductCardContext() {\n const context = useContext(ProductCardContext)\n if (!context) {\n throw new Error(\n 'ProductCard components must be used within a ProductCard provider'\n )\n }\n return context\n}\n\n// Primitive components (building blocks)\nfunction ProductCardContainer({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {touchable, onClick} = useProductCardContext()\n\n const content = (\n <div\n className={cn(\n 'relative size-full overflow-hidden rounded-xl border-0 isolate',\n className\n )}\n {...props}\n />\n )\n\n if (touchable && onClick) {\n return (\n <Touchable\n onClick={onClick}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {content}\n </Touchable>\n )\n }\n\n return content\n}\n\nfunction ProductCardImageContainer({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {variant} = useProductCardContext()\n\n return (\n <div\n data-slot=\"product-card-image-container\"\n className={cn(\n 'relative overflow-hidden rounded-xl border border-gray-200',\n 'aspect-square',\n variant === 'compact' ? 'min-h-[104px]' : 'min-h-[134px]',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductCardImage({className, ...props}: React.ComponentProps<'img'>) {\n const {product, selectedProductVariant} = useProductCardContext()\n\n // Derive display image locally\n const displayImage = selectedProductVariant?.image || product.featuredImage\n const src = displayImage?.url\n const alt = displayImage?.altText || product.title\n const thumbhash = product.featuredImage?.thumbhash\n\n const renderImageElement = useCallback(\n (src: string) => {\n const imageElement = thumbhash ? (\n <Image\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n aspectRatio={1}\n thumbhash={thumbhash}\n objectFit=\"cover\"\n className={cn('size-full', className)}\n {...props}\n />\n ) : (\n <img\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n className={cn('size-full object-cover', className)}\n {...props}\n />\n )\n\n return imageElement\n },\n [alt, className, props, thumbhash]\n )\n\n return (\n <div className=\"bg-gray-100 flex items-center justify-center size-full\">\n {src ? (\n renderImageElement(src)\n ) : (\n <div className=\"text-gray-400 text-sm w-full text-center\">No Image</div>\n )}\n </div>\n )\n}\n\nfunction ProductCardBadge({\n className,\n position = 'bottom-left',\n variant,\n children,\n ...props\n}: React.ComponentProps<typeof Badge> & {\n position?: 'top-left' | 'bottom-left'\n}) {\n const {badgeText, badgeVariant} = useProductCardContext()\n // If no children provided, use badgeText from context\n const content = children || badgeText\n\n if (!content) return null\n\n return (\n <div\n className={cn(\n 'absolute z-10',\n position === 'top-left' ? 'top-3 left-3' : 'bottom-2 left-2'\n )}\n >\n <Badge\n variant={variant ?? badgeVariant ?? 'none'}\n className={cn(\n !badgeVariant &&\n !variant &&\n 'bg-black/50 text-white border-transparent',\n 'rounded',\n className\n )}\n {...props}\n >\n {content}\n </Badge>\n </div>\n )\n}\n\nfunction ProductCardFavoriteButton({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {isFavorited, favoriteButtonDisabled, onFavoriteToggle} =\n useProductCardContext()\n if (favoriteButtonDisabled) return null\n\n return (\n <div className={cn('absolute bottom-3 right-3 z-10', className)} {...props}>\n <FavoriteButton onClick={onFavoriteToggle} filled={isFavorited} />\n </div>\n )\n}\n\nfunction ProductCardInfo({className, ...props}: React.ComponentProps<'div'>) {\n const {variant} = useProductCardContext()\n if (variant !== 'default') {\n return null\n }\n\n return (\n <div\n data-testid=\"product-card-info\"\n className={cn('px-1 pt-2 pb-0 space-y-1', className)}\n {...props}\n />\n )\n}\n\nfunction ProductCardTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n const {product} = useProductCardContext()\n return (\n <h3\n data-slot=\"product-card-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900',\n 'truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children || product.title}\n </h3>\n )\n}\n\nfunction ProductCardReviewStars({\n className,\n ...props\n}: React.ComponentProps<'div'>) {\n const {product, reviewsDisabled} = useProductCardContext()\n const reviewAnalytics = product.reviewAnalytics\n\n if (reviewsDisabled || !reviewAnalytics?.averageRating) {\n return null\n }\n\n return (\n <div\n data-slot=\"product-card-review-stars\"\n className={cn('', className)}\n {...props}\n >\n <ProductReviewStars\n averageRating={reviewAnalytics.averageRating}\n reviewCount={reviewAnalytics.reviewCount}\n />\n </div>\n )\n}\n\nfunction ProductCardPrice({className}: {className?: string}) {\n const {product, selectedProductVariant} = useProductCardContext()\n\n // Derive price data locally\n const displayPrice = selectedProductVariant?.price || product?.price\n const displayCompareAtPrice =\n selectedProductVariant?.compareAtPrice || product?.compareAtPrice\n\n return (\n <ProductVariantPrice\n amount={displayPrice?.amount || ''}\n currencyCode={displayPrice?.currencyCode || ''}\n compareAtPriceAmount={displayCompareAtPrice?.amount}\n compareAtPriceCurrencyCode={displayCompareAtPrice?.currencyCode}\n className={className}\n />\n )\n}\n\n// Special PriceOverlayBadge for price overlay variant\nfunction ProductCardPriceOverlayBadge() {\n const {product, selectedProductVariant, variant} = useProductCardContext()\n if (variant !== 'priceOverlay') return null\n const displayPrice = selectedProductVariant?.price || product.price\n const currencyCode = displayPrice?.currencyCode\n const amount = displayPrice?.amount\n\n if (!currencyCode || !amount) return null\n return (\n <ProductCardBadge position=\"top-left\">\n {formatMoney(amount, currencyCode)}\n </ProductCardBadge>\n )\n}\n\nexport interface ProductCardProps {\n /** The product to display in the card */\n product: Product\n /** Optional selected variant of the product to show specific variant data */\n selectedProductVariant?: ProductVariant\n /** Visual style variant of the card */\n variant?: 'default' | 'priceOverlay' | 'compact'\n /** Whether the card can be clicked/tapped to navigate to product details */\n touchable?: boolean\n /** Optional text to display in a badge on the card */\n badgeText?: string\n /** Visual style variant for the badge */\n badgeVariant?: 'primary' | 'secondary' | 'destructive' | 'outline' | 'none'\n /** Callback fired when the product is clicked */\n onProductClick?: () => void\n /** Callback fired when the favorite button is toggled */\n onFavoriteToggled?: (isFavorited: boolean) => void\n /** Custom layout via children */\n children?: React.ReactNode\n /** Whether the favorite button is disabled */\n favoriteButtonDisabled?: boolean\n /** Whether review stars are disabled */\n reviewsDisabled?: boolean\n}\n\nfunction ProductCard({\n product,\n selectedProductVariant,\n variant = 'default',\n touchable = true,\n badgeText,\n badgeVariant,\n onProductClick,\n onFavoriteToggled,\n children,\n favoriteButtonDisabled = false,\n reviewsDisabled = false,\n}: ProductCardProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = useState(product.isFavorited)\n\n const handleClick = useCallback(() => {\n if (!touchable) return\n\n onProductClick?.()\n\n navigateToProduct({\n productId: product.id,\n })\n }, [navigateToProduct, product.id, touchable, onProductClick])\n\n const handleFavoriteClick = useCallback(async () => {\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n onFavoriteToggled?.(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: product.id,\n shopId: product.shop.id,\n productVariantId:\n selectedProductVariant?.id || product.defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: product.id,\n shopId: product.shop.id,\n productVariantId:\n selectedProductVariant?.id || product.defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n onFavoriteToggled?.(previousState)\n }\n }, [\n isFavoritedLocal,\n product.id,\n product.shop.id,\n product.defaultVariantId,\n selectedProductVariant?.id,\n saveProduct,\n unsaveProduct,\n onFavoriteToggled,\n ])\n\n const contextValue = useMemo<ProductCardContextValue>(\n () => ({\n // Core data\n product,\n selectedProductVariant,\n\n // UI configuration\n variant,\n touchable,\n badgeText,\n badgeVariant,\n favoriteButtonDisabled,\n reviewsDisabled,\n\n // State\n isFavorited: isFavoritedLocal,\n // Actions\n onClick: handleClick,\n onFavoriteToggle: handleFavoriteClick,\n }),\n [\n product,\n selectedProductVariant,\n variant,\n touchable,\n badgeText,\n badgeVariant,\n isFavoritedLocal,\n handleClick,\n handleFavoriteClick,\n favoriteButtonDisabled,\n reviewsDisabled,\n ]\n )\n\n return (\n <ProductCardContext.Provider value={contextValue}>\n {children ?? (\n <ProductCardContainer>\n <ProductCardImageContainer>\n <ProductCardImage />\n {variant === 'priceOverlay' && <ProductCardPriceOverlayBadge />}\n <ProductCardBadge />\n <ProductCardFavoriteButton />\n </ProductCardImageContainer>\n {variant === 'default' && (\n <ProductCardInfo>\n <ProductCardTitle />\n <ProductCardReviewStars />\n <ProductCardPrice />\n </ProductCardInfo>\n )}\n </ProductCardContainer>\n )}\n </ProductCardContext.Provider>\n )\n}\n\nexport {\n ProductCard,\n ProductCardContainer,\n ProductCardImageContainer,\n ProductCardImage,\n ProductCardBadge,\n ProductCardFavoriteButton,\n ProductCardInfo,\n ProductCardTitle,\n ProductCardReviewStars,\n ProductCardPrice,\n}\n"],"names":["ProductCardContext","React","useProductCardContext","context","useContext","ProductCardContainer","className","props","touchable","onClick","content","jsx","cn","Touchable","ProductCardImageContainer","variant","ProductCardImage","product","selectedProductVariant","displayImage","src","alt","thumbhash","renderImageElement","useCallback","Image","ProductCardBadge","position","children","badgeText","badgeVariant","Badge","ProductCardFavoriteButton","isFavorited","favoriteButtonDisabled","onFavoriteToggle","FavoriteButton","ProductCardInfo","ProductCardTitle","ProductCardReviewStars","reviewsDisabled","reviewAnalytics","ProductReviewStars","ProductCardPrice","displayPrice","displayCompareAtPrice","ProductVariantPrice","ProductCardPriceOverlayBadge","currencyCode","amount","formatMoney","ProductCard","onProductClick","onFavoriteToggled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","isFavoritedLocal","setIsFavoritedLocal","useState","handleClick","handleFavoriteClick","previousState","contextValue","useMemo","jsxs"],"mappings":"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"}
@@ -4,8 +4,8 @@ import { cva as q } from "../../shop-minis-react/node_modules/.pnpm/class-varian
4
4
  import { useShopNavigation as B } from "../../hooks/navigation/useShopNavigation.js";
5
5
  import { useSavedProductsActions as M } from "../../hooks/user/useSavedProductsActions.js";
6
6
  import { ProductReviewStars as U } from "../../internal/components/product-review-stars.js";
7
+ import { formatMoney as T } from "../../lib/formatMoney.js";
7
8
  import { cn as n } from "../../lib/utils.js";
8
- import { formatMoney as T } from "../../utils/formatMoney.js";
9
9
  import { Touchable as V } from "../atoms/touchable.js";
10
10
  import { Card as E, CardContent as G, CardAction as H } from "../ui/card.js";
11
11
  import { FavoriteButton as J } from "./favorite-button.js";
@@ -1 +1 @@
1
- {"version":3,"file":"product-link.js","sources":["../../../src/components/commerce/product-link.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {type Product} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\nimport {Touchable} from '../atoms/touchable'\nimport {Card, CardContent, CardAction} from '../ui/card'\n\nimport {FavoriteButton} from './favorite-button'\n\nconst productLinkVariants = cva('', {\n variants: {\n layout: {\n horizontal: 'w-full !flex-row items-center gap-3 px-4 py-3',\n vertical: 'flex-col',\n },\n discount: {\n none: '',\n small: '',\n large: '',\n },\n },\n defaultVariants: {\n layout: 'horizontal',\n discount: 'none',\n },\n})\n\n// Primitive components (building blocks)\nexport interface ProductLinkRootProps\n extends React.ComponentProps<typeof Card>,\n VariantProps<typeof productLinkVariants> {\n layout?: 'horizontal' | 'vertical'\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductLinkRoot({\n className,\n layout,\n discount,\n asChild = false,\n onPress,\n ...props\n}: ProductLinkRootProps) {\n const Comp = asChild ? SlotPrimitive.Root : Card\n\n return (\n <Touchable\n onClick={onPress}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n <Comp\n className={cn(\n productLinkVariants({layout, discount}),\n 'border-0 bg-white rounded-xl shadow-lg shadow-black/10',\n className\n )}\n {...props}\n />\n </Touchable>\n )\n}\n\nfunction ProductLinkImage({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<'div'> & {layout?: 'horizontal' | 'vertical'}) {\n return (\n <div\n data-slot=\"product-link-image\"\n className={cn(\n 'overflow-hidden rounded-md bg-muted',\n layout === 'horizontal'\n ? 'h-16 w-16 flex-shrink-0'\n : 'aspect-square w-full',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkInfo({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<typeof CardContent> & {\n layout?: 'horizontal' | 'vertical'\n}) {\n return (\n <CardContent\n className={cn(\n layout === 'horizontal'\n ? 'flex-1 min-w-0 space-y-1 px-0 py-0'\n : 'space-y-2',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"product-link-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children}\n </h3>\n )\n}\n\nfunction ProductLinkPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkDiscountPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-discount-price\"\n className={cn('text-sm font-semibold text-red-600', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkRating({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-rating\"\n className={cn('', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkActions({\n className,\n hideFavoriteAction = false,\n onPress,\n filled = false,\n customAction,\n ...props\n}: React.ComponentProps<typeof CardAction> & {\n hideFavoriteAction?: boolean\n onPress?: () => void\n filled?: boolean\n customAction?: React.ReactNode\n}) {\n const favoriteAction = hideFavoriteAction ? null : (\n <FavoriteButton filled={filled} onClick={onPress} />\n )\n\n return (\n <CardAction\n className={cn('flex-shrink-0 self-center px-0 py-0', className)}\n {...props}\n >\n <Touchable\n stopPropagation\n onClick={onPress}\n whileTap={{opacity: 0.7, scale: 0.95}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n scale: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {customAction ? <>{customAction}</> : favoriteAction}\n </Touchable>\n </CardAction>\n )\n}\n\nexport type ProductLinkProps = {\n product: Product\n hideFavoriteAction?: boolean\n onClick?: (product: Product) => void\n reviewsDisabled?: boolean\n} & (\n | {\n customAction?: never\n onCustomActionClick?: never\n }\n | {\n customAction: React.ReactNode\n onCustomActionClick: () => void\n }\n)\n\n// Composed ProductLink component\nfunction ProductLink({\n product,\n hideFavoriteAction = false,\n onClick,\n customAction,\n onCustomActionClick,\n reviewsDisabled = false,\n}: ProductLinkProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n const {\n id,\n title,\n featuredImage,\n reviewAnalytics,\n price,\n compareAtPrice,\n isFavorited,\n selectedVariant,\n defaultVariantId,\n shop,\n } = product\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const averageRating = reviewAnalytics?.averageRating\n const reviewCount = reviewAnalytics?.reviewCount\n const amount = price?.amount\n ? formatMoney(price?.amount, price?.currencyCode)\n : undefined\n const imageUrl = featuredImage?.url\n const imageAltText = featuredImage?.altText || title\n const compareAtPriceAmount = compareAtPrice?.amount\n ? formatMoney(compareAtPrice?.amount, compareAtPrice?.currencyCode)\n : undefined\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n navigateToProduct({\n productId: id,\n })\n onClick?.(product)\n }, [navigateToProduct, id, onClick, product])\n\n const handleActionPress = React.useCallback(async () => {\n if (customAction || onCustomActionClick) {\n onCustomActionClick?.()\n return\n }\n\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n }\n }, [\n customAction,\n onCustomActionClick,\n isFavoritedLocal,\n unsaveProduct,\n id,\n shop.id,\n selectedVariant?.id,\n defaultVariantId,\n saveProduct,\n ])\n\n return (\n <ProductLinkRoot\n layout=\"horizontal\"\n discount={hasDiscount ? 'small' : 'none'}\n onPress={handlePress}\n >\n <ProductLinkImage layout=\"horizontal\">\n {imageUrl ? (\n <img\n src={imageUrl}\n alt={imageAltText}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs\">\n No Image\n </div>\n )}\n </ProductLinkImage>\n\n <ProductLinkInfo layout=\"horizontal\">\n <ProductLinkTitle>{title}</ProductLinkTitle>\n\n {averageRating && !reviewsDisabled ? (\n <ProductLinkRating>\n <ProductReviewStars\n averageRating={averageRating}\n reviewCount={reviewCount}\n />\n </ProductLinkRating>\n ) : null}\n\n <ProductLinkPrice>\n {hasDiscount ? (\n <>\n <ProductLinkDiscountPrice>{amount}</ProductLinkDiscountPrice>\n <ProductLinkOriginalPrice>\n {compareAtPriceAmount}\n </ProductLinkOriginalPrice>\n </>\n ) : (\n <ProductLinkCurrentPrice>{amount}</ProductLinkCurrentPrice>\n )}\n </ProductLinkPrice>\n </ProductLinkInfo>\n\n <ProductLinkActions\n filled={isFavoritedLocal}\n onPress={handleActionPress}\n customAction={customAction}\n hideFavoriteAction={hideFavoriteAction}\n />\n </ProductLinkRoot>\n )\n}\n\nexport {ProductLink}\n"],"names":["productLinkVariants","cva","ProductLinkRoot","className","layout","discount","asChild","onPress","props","jsx","Touchable","SlotPrimitive.Root","Card","cn","ProductLinkImage","ProductLinkInfo","CardContent","ProductLinkTitle","children","ProductLinkPrice","ProductLinkCurrentPrice","ProductLinkOriginalPrice","ProductLinkDiscountPrice","ProductLinkRating","ProductLinkActions","hideFavoriteAction","filled","customAction","favoriteAction","FavoriteButton","CardAction","Fragment","ProductLink","product","onClick","onCustomActionClick","reviewsDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","id","title","featuredImage","reviewAnalytics","price","compareAtPrice","isFavorited","selectedVariant","defaultVariantId","shop","isFavoritedLocal","setIsFavoritedLocal","React","averageRating","reviewCount","amount","formatMoney","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleActionPress","previousState","jsxs","ProductReviewStars"],"mappings":"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"}
1
+ {"version":3,"file":"product-link.js","sources":["../../../src/components/commerce/product-link.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {type Product} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {formatMoney} from '../../lib/formatMoney'\nimport {cn} from '../../lib/utils'\nimport {Touchable} from '../atoms/touchable'\nimport {Card, CardContent, CardAction} from '../ui/card'\n\nimport {FavoriteButton} from './favorite-button'\n\nconst productLinkVariants = cva('', {\n variants: {\n layout: {\n horizontal: 'w-full !flex-row items-center gap-3 px-4 py-3',\n vertical: 'flex-col',\n },\n discount: {\n none: '',\n small: '',\n large: '',\n },\n },\n defaultVariants: {\n layout: 'horizontal',\n discount: 'none',\n },\n})\n\n// Primitive components (building blocks)\nexport interface ProductLinkRootProps\n extends React.ComponentProps<typeof Card>,\n VariantProps<typeof productLinkVariants> {\n layout?: 'horizontal' | 'vertical'\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductLinkRoot({\n className,\n layout,\n discount,\n asChild = false,\n onPress,\n ...props\n}: ProductLinkRootProps) {\n const Comp = asChild ? SlotPrimitive.Root : Card\n\n return (\n <Touchable\n onClick={onPress}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n <Comp\n className={cn(\n productLinkVariants({layout, discount}),\n 'border-0 bg-white rounded-xl shadow-lg shadow-black/10',\n className\n )}\n {...props}\n />\n </Touchable>\n )\n}\n\nfunction ProductLinkImage({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<'div'> & {layout?: 'horizontal' | 'vertical'}) {\n return (\n <div\n data-slot=\"product-link-image\"\n className={cn(\n 'overflow-hidden rounded-md bg-muted',\n layout === 'horizontal'\n ? 'h-16 w-16 flex-shrink-0'\n : 'aspect-square w-full',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkInfo({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<typeof CardContent> & {\n layout?: 'horizontal' | 'vertical'\n}) {\n return (\n <CardContent\n className={cn(\n layout === 'horizontal'\n ? 'flex-1 min-w-0 space-y-1 px-0 py-0'\n : 'space-y-2',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"product-link-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children}\n </h3>\n )\n}\n\nfunction ProductLinkPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkDiscountPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-discount-price\"\n className={cn('text-sm font-semibold text-red-600', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkRating({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-rating\"\n className={cn('', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkActions({\n className,\n hideFavoriteAction = false,\n onPress,\n filled = false,\n customAction,\n ...props\n}: React.ComponentProps<typeof CardAction> & {\n hideFavoriteAction?: boolean\n onPress?: () => void\n filled?: boolean\n customAction?: React.ReactNode\n}) {\n const favoriteAction = hideFavoriteAction ? null : (\n <FavoriteButton filled={filled} onClick={onPress} />\n )\n\n return (\n <CardAction\n className={cn('flex-shrink-0 self-center px-0 py-0', className)}\n {...props}\n >\n <Touchable\n stopPropagation\n onClick={onPress}\n whileTap={{opacity: 0.7, scale: 0.95}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n scale: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {customAction ? <>{customAction}</> : favoriteAction}\n </Touchable>\n </CardAction>\n )\n}\n\nexport type ProductLinkProps = {\n product: Product\n hideFavoriteAction?: boolean\n onClick?: (product: Product) => void\n reviewsDisabled?: boolean\n} & (\n | {\n customAction?: never\n onCustomActionClick?: never\n }\n | {\n customAction: React.ReactNode\n onCustomActionClick: () => void\n }\n)\n\n// Composed ProductLink component\nfunction ProductLink({\n product,\n hideFavoriteAction = false,\n onClick,\n customAction,\n onCustomActionClick,\n reviewsDisabled = false,\n}: ProductLinkProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n const {\n id,\n title,\n featuredImage,\n reviewAnalytics,\n price,\n compareAtPrice,\n isFavorited,\n selectedVariant,\n defaultVariantId,\n shop,\n } = product\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const averageRating = reviewAnalytics?.averageRating\n const reviewCount = reviewAnalytics?.reviewCount\n const amount = price?.amount\n ? formatMoney(price?.amount, price?.currencyCode)\n : undefined\n const imageUrl = featuredImage?.url\n const imageAltText = featuredImage?.altText || title\n const compareAtPriceAmount = compareAtPrice?.amount\n ? formatMoney(compareAtPrice?.amount, compareAtPrice?.currencyCode)\n : undefined\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n navigateToProduct({\n productId: id,\n })\n onClick?.(product)\n }, [navigateToProduct, id, onClick, product])\n\n const handleActionPress = React.useCallback(async () => {\n if (customAction || onCustomActionClick) {\n onCustomActionClick?.()\n return\n }\n\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n }\n }, [\n customAction,\n onCustomActionClick,\n isFavoritedLocal,\n unsaveProduct,\n id,\n shop.id,\n selectedVariant?.id,\n defaultVariantId,\n saveProduct,\n ])\n\n return (\n <ProductLinkRoot\n layout=\"horizontal\"\n discount={hasDiscount ? 'small' : 'none'}\n onPress={handlePress}\n >\n <ProductLinkImage layout=\"horizontal\">\n {imageUrl ? (\n <img\n src={imageUrl}\n alt={imageAltText}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs\">\n No Image\n </div>\n )}\n </ProductLinkImage>\n\n <ProductLinkInfo layout=\"horizontal\">\n <ProductLinkTitle>{title}</ProductLinkTitle>\n\n {averageRating && !reviewsDisabled ? (\n <ProductLinkRating>\n <ProductReviewStars\n averageRating={averageRating}\n reviewCount={reviewCount}\n />\n </ProductLinkRating>\n ) : null}\n\n <ProductLinkPrice>\n {hasDiscount ? (\n <>\n <ProductLinkDiscountPrice>{amount}</ProductLinkDiscountPrice>\n <ProductLinkOriginalPrice>\n {compareAtPriceAmount}\n </ProductLinkOriginalPrice>\n </>\n ) : (\n <ProductLinkCurrentPrice>{amount}</ProductLinkCurrentPrice>\n )}\n </ProductLinkPrice>\n </ProductLinkInfo>\n\n <ProductLinkActions\n filled={isFavoritedLocal}\n onPress={handleActionPress}\n customAction={customAction}\n hideFavoriteAction={hideFavoriteAction}\n />\n </ProductLinkRoot>\n )\n}\n\nexport {ProductLink}\n"],"names":["productLinkVariants","cva","ProductLinkRoot","className","layout","discount","asChild","onPress","props","jsx","Touchable","SlotPrimitive.Root","Card","cn","ProductLinkImage","ProductLinkInfo","CardContent","ProductLinkTitle","children","ProductLinkPrice","ProductLinkCurrentPrice","ProductLinkOriginalPrice","ProductLinkDiscountPrice","ProductLinkRating","ProductLinkActions","hideFavoriteAction","filled","customAction","favoriteAction","FavoriteButton","CardAction","Fragment","ProductLink","product","onClick","onCustomActionClick","reviewsDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","id","title","featuredImage","reviewAnalytics","price","compareAtPrice","isFavorited","selectedVariant","defaultVariantId","shop","isFavoritedLocal","setIsFavoritedLocal","React","averageRating","reviewCount","amount","formatMoney","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleActionPress","previousState","jsxs","ProductReviewStars"],"mappings":";;;;;;;;;;;;AAgBA,MAAMA,IAAsBC,EAAI,IAAI;AAAA,EAClC,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,YAAY;AAAA,MACZ,UAAU;AAAA,IACZ;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,IAAA;AAAA,EAEX;AAAA,EACA,iBAAiB;AAAA,IACf,QAAQ;AAAA,IACR,UAAU;AAAA,EAAA;AAEd,CAAC;AAWD,SAASC,EAAgB;AAAA,EACvB,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,SAAAC;AAAA,EACA,GAAGC;AACL,GAAyB;AAIrB,SAAA,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAASH;AAAA,MACT,UAAU,EAAC,SAAS,IAAG;AAAA,MACvB,YAAY;AAAA,QACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,YAAW;AAAA,MAC5D;AAAA,MAEA,UAAA,gBAAAE;AAAA,QAVSH,IAAUK,IAAqBC;AAAA,QAUvC;AAAA,UACC,WAAWC;AAAA,YACTb,EAAoB,EAAC,QAAAI,GAAQ,UAAAC,GAAS;AAAA,YACtC;AAAA,YACAF;AAAA,UACF;AAAA,UACC,GAAGK;AAAA,QAAA;AAAA,MAAA;AAAA,IACN;AAAA,EACF;AAEJ;AAEA,SAASM,EAAiB;AAAA,EACxB,WAAAX;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,GAAGI;AACL,GAAuE;AAEnE,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI;AAAA,QACT;AAAA,QACAT,MAAW,eACP,4BACA;AAAA,QACJD;AAAA,MACF;AAAA,MACC,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASO,EAAgB;AAAA,EACvB,WAAAZ;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,GAAGI;AACL,GAEG;AAEC,SAAA,gBAAAC;AAAA,IAACO;AAAA,IAAA;AAAA,MACC,WAAWH;AAAA,QACTT,MAAW,eACP,uCACA;AAAA,QACJD;AAAA,MACF;AAAA,MACC,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASS,EAAiB;AAAA,EACxB,WAAAd;AAAA,EACA,UAAAe;AAAA,EACA,GAAGV;AACL,GAA+B;AAE3B,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI;AAAA,QACT;AAAA,QACAV;AAAA,MACF;AAAA,MACC,GAAGK;AAAA,MAEH,UAAAU;AAAA,IAAA;AAAA,EACH;AAEJ;AAEA,SAASC,EAAiB,EAAC,WAAAhB,GAAW,GAAGK,KAAqC;AAE1E,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI,EAAG,2BAA2BV,CAAS;AAAA,MACjD,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASY,EAAwB;AAAA,EAC/B,WAAAjB;AAAA,EACA,GAAGK;AACL,GAAiC;AAE7B,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI,EAAG,uCAAuCV,CAAS;AAAA,MAC7D,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASa,GAAyB;AAAA,EAChC,WAAAlB;AAAA,EACA,GAAGK;AACL,GAAiC;AAE7B,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI,EAAG,sCAAsCV,CAAS;AAAA,MAC5D,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASc,GAAyB;AAAA,EAChC,WAAAnB;AAAA,EACA,GAAGK;AACL,GAAiC;AAE7B,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI,EAAG,sCAAsCV,CAAS;AAAA,MAC5D,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASe,GAAkB,EAAC,WAAApB,GAAW,GAAGK,KAAqC;AAE3E,SAAA,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWI,EAAG,IAAIV,CAAS;AAAA,MAC1B,GAAGK;AAAA,IAAA;AAAA,EACN;AAEJ;AAEA,SAASgB,GAAmB;AAAA,EAC1B,WAAArB;AAAA,EACA,oBAAAsB,IAAqB;AAAA,EACrB,SAAAlB;AAAA,EACA,QAAAmB,IAAS;AAAA,EACT,cAAAC;AAAA,EACA,GAAGnB;AACL,GAKG;AACD,QAAMoB,IAAiBH,IAAqB,yBACzCI,GAAe,EAAA,QAAAH,GAAgB,SAASnB,GAAS;AAIlD,SAAA,gBAAAE;AAAA,IAACqB;AAAA,IAAA;AAAA,MACC,WAAWjB,EAAG,uCAAuCV,CAAS;AAAA,MAC7D,GAAGK;AAAA,MAEJ,UAAA,gBAAAC;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,iBAAe;AAAA,UACf,SAASH;AAAA,UACT,UAAU,EAAC,SAAS,KAAK,OAAO,KAAI;AAAA,UACpC,YAAY;AAAA,YACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,YAAW;AAAA,YAC1D,OAAO,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,YAAW;AAAA,UAC1D;AAAA,UAEC,UAAAoB,IAAkB,gBAAAlB,EAAAsB,GAAA,EAAA,UAAAJ,EAAA,CAAa,IAAMC;AAAA,QAAA;AAAA,MAAA;AAAA,IACxC;AAAA,EACF;AAEJ;AAmBA,SAASI,GAAY;AAAA,EACnB,SAAAC;AAAA,EACA,oBAAAR,IAAqB;AAAA,EACrB,SAAAS;AAAA,EACA,cAAAP;AAAA,EACA,qBAAAQ;AAAA,EACA,iBAAAC,IAAkB;AACpB,GAAqB;AACb,QAAA,EAAC,mBAAAC,EAAiB,IAAIC,EAAkB,GACxC,EAAC,aAAAC,GAAa,eAAAC,EAAa,IAAIC,EAAwB,GAEvD;AAAA,IACJ,IAAAC;AAAA,IACA,OAAAC;AAAA,IACA,eAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,OAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,aAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,kBAAAC;AAAA,IACA,MAAAC;AAAA,EAAA,IACElB,GAGE,CAACmB,GAAkBC,CAAmB,IAAIC,EAAM,SAASN,CAAW,GAEpEO,IAAgBV,GAAiB,eACjCW,IAAcX,GAAiB,aAC/BY,IAASX,GAAO,SAClBY,EAAYZ,GAAO,QAAQA,GAAO,YAAY,IAC9C,QACEa,IAAWf,GAAe,KAC1BgB,IAAehB,GAAe,WAAWD,GACzCkB,IAAuBd,GAAgB,SACzCW,EAAYX,GAAgB,QAAQA,GAAgB,YAAY,IAChE,QACEe,IAAcD,KAAwBA,MAAyBJ,GAE/DM,IAAcT,EAAM,YAAY,MAAM;AACxB,IAAAjB,EAAA;AAAA,MAChB,WAAWK;AAAA,IAAA,CACZ,GACDR,IAAUD,CAAO;AAAA,KAChB,CAACI,GAAmBK,GAAIR,GAASD,CAAO,CAAC,GAEtC+B,IAAoBV,EAAM,YAAY,YAAY;AACtD,QAAI3B,KAAgBQ,GAAqB;AACjB,MAAAA,IAAA;AACtB;AAAA,IAAA;AAGF,UAAM8B,IAAgBb;AAGtB,IAAAC,EAAoB,CAACY,CAAa;AAE9B,QAAA;AACF,MAAIA,IACF,MAAMzB,EAAc;AAAA,QAClB,WAAWE;AAAA,QACX,QAAQS,EAAK;AAAA,QACb,kBAAkBF,GAAiB,MAAMC;AAAA,MAAA,CAC1C,IAED,MAAMX,EAAY;AAAA,QAChB,WAAWG;AAAA,QACX,QAAQS,EAAK;AAAA,QACb,kBAAkBF,GAAiB,MAAMC;AAAA,MAAA,CAC1C;AAAA,YAEW;AAEd,MAAAG,EAAoBY,CAAa;AAAA,IAAA;AAAA,EACnC,GACC;AAAA,IACDtC;AAAA,IACAQ;AAAA,IACAiB;AAAA,IACAZ;AAAA,IACAE;AAAA,IACAS,EAAK;AAAA,IACLF,GAAiB;AAAA,IACjBC;AAAA,IACAX;AAAA,EAAA,CACD;AAGC,SAAA,gBAAA2B;AAAA,IAAChE;AAAA,IAAA;AAAA,MACC,QAAO;AAAA,MACP,UAAU4D,IAAc,UAAU;AAAA,MAClC,SAASC;AAAA,MAET,UAAA;AAAA,QAAC,gBAAAtD,EAAAK,GAAA,EAAiB,QAAO,cACtB,UACC6C,IAAA,gBAAAlD;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAKkD;AAAA,YACL,KAAKC;AAAA,YACL,WAAU;AAAA,UAAA;AAAA,QAAA,IAGX,gBAAAnD,EAAA,OAAA,EAAI,WAAU,yFAAwF,qBAEvG,CAAA,GAEJ;AAAA,QAEA,gBAAAyD,EAACnD,GAAgB,EAAA,QAAO,cACtB,UAAA;AAAA,UAAA,gBAAAN,EAACQ,KAAkB,UAAM0B,EAAA,CAAA;AAAA,UAExBY,KAAiB,CAACnB,IACjB,gBAAA3B,EAACc,IACC,EAAA,UAAA,gBAAAd;AAAA,YAAC0D;AAAA,YAAA;AAAA,cACC,eAAAZ;AAAA,cACA,aAAAC;AAAA,YAAA;AAAA,aAEJ,IACE;AAAA,UAEJ,gBAAA/C,EAACU,GACE,EAAA,UAAA2C,IAEG,gBAAAI,EAAAnC,GAAA,EAAA,UAAA;AAAA,YAAA,gBAAAtB,EAACa,MAA0B,UAAOmC,EAAA,CAAA;AAAA,YAClC,gBAAAhD,EAACY,MACE,UACHwC,EAAA,CAAA;AAAA,UAAA,EACF,CAAA,IAEA,gBAAApD,EAACW,GAAyB,EAAA,UAAAqC,EAAA,CAAO,EAErC,CAAA;AAAA,QAAA,GACF;AAAA,QAEA,gBAAAhD;AAAA,UAACe;AAAA,UAAA;AAAA,YACC,QAAQ4B;AAAA,YACR,SAASY;AAAA,YACT,cAAArC;AAAA,YACA,oBAAAF;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EACF;AAEJ;"}
@@ -1,31 +1,31 @@
1
- import { useCallback as c } from "react";
2
- import { useShopActions as m } from "../../internal/useShopActions.js";
3
- import { fileToDataUri as d } from "../../utils/image.js";
4
- const u = async (e) => {
5
- const o = await d(e), a = await (await fetch(o)).blob();
1
+ import { useCallback as m } from "react";
2
+ import { useShopActions as c } from "../../internal/useShopActions.js";
3
+ import { fileToDataUri as u } from "../../utils/image.js";
4
+ const d = async (e) => {
5
+ const r = await u(e), o = await (await fetch(r)).blob();
6
6
  return {
7
7
  mimeType: e.type,
8
- fileSize: e.size ?? a.size,
9
- fileBlob: a
8
+ fileSize: e.size ?? o.size,
9
+ fileBlob: o
10
10
  };
11
- }, f = async (e, o) => {
11
+ }, f = async (e, r) => {
12
12
  const t = new FormData();
13
- o.parameters.forEach(({ name: s, value: r }) => {
14
- t.append(s, r);
13
+ r.parameters.forEach(({ name: s, value: a }) => {
14
+ t.append(s, a);
15
15
  }), t.append("file", e.fileBlob);
16
- const a = await fetch(o.url, {
16
+ const o = await fetch(r.url, {
17
17
  method: "POST",
18
18
  body: t
19
19
  });
20
- return a.ok ? {} : (console.error("Failed to upload image", {
21
- response: await a.text()
20
+ return o.ok ? {} : (console.error("Failed to upload image", {
21
+ response: await o.text()
22
22
  }), { error: "Failed to upload image" });
23
23
  }, U = () => {
24
- const { createImageUploadLink: e, completeImageUpload: o } = m();
24
+ const { createImageUploadLink: e, completeImageUpload: r } = c();
25
25
  return {
26
- uploadImage: c(
27
- async (a) => {
28
- const s = await u(a), r = await e({
26
+ uploadImage: m(
27
+ async (o) => {
28
+ const s = await d(o), a = await e({
29
29
  input: [
30
30
  {
31
31
  mimeType: s.mimeType,
@@ -33,26 +33,18 @@ const u = async (e) => {
33
33
  }
34
34
  ]
35
35
  });
36
- if (!r.ok)
37
- throw new Error(r.error.message);
38
- if (r.mocked)
39
- return [
40
- {
41
- id: "uploaded-image-id",
42
- imageUrl: "https://cdn.shopify.com/s/files/1/0621/0463/3599/files/Mr._Bean_2007_800x800.jpg?v=1763126175",
43
- resourceUrl: "https://cdn.shopify.com/s/files/1/0621/0463/3599/files/Mr._Bean_2007_800x800.jpg?v=1763126175"
44
- }
45
- ];
36
+ if (!a.ok)
37
+ throw new Error(a.error.message);
46
38
  const { error: n } = await f(
47
39
  s,
48
- r?.data?.targets?.[0]
40
+ a?.data?.targets?.[0]
49
41
  );
50
42
  if (n)
51
43
  throw new Error(n);
52
44
  let p = 0;
53
45
  for (; p < 30; ) {
54
- const i = await o({
55
- resourceUrls: r?.data?.targets?.map((l) => l.resourceUrl) || []
46
+ const i = await r({
47
+ resourceUrls: a?.data?.targets?.map((l) => l.resourceUrl) || []
56
48
  });
57
49
  if (!i.ok)
58
50
  throw new Error(i.error.message);
@@ -61,14 +53,14 @@ const u = async (e) => {
61
53
  {
62
54
  id: i.data.files[0].id,
63
55
  imageUrl: i.data.files[0].image?.url,
64
- resourceUrl: r?.data?.targets?.[0]?.resourceUrl
56
+ resourceUrl: a?.data?.targets?.[0]?.resourceUrl
65
57
  }
66
58
  ];
67
59
  await new Promise((l) => setTimeout(l, 1e3)), p++;
68
60
  }
69
61
  throw new Error("Image upload completion timed out");
70
62
  },
71
- [e, o]
63
+ [e, r]
72
64
  )
73
65
  };
74
66
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useImageUpload.js","sources":["../../../src/hooks/storage/useImageUpload.ts"],"sourcesContent":["import {useCallback} from 'react'\n\nimport {useShopActions} from '../../internal/useShopActions'\nimport {fileToDataUri} from '../../utils'\n\nimport type {UploadTarget} from '@shopify/shop-minis-platform/actions'\n\nexport interface UploadImageParams {\n /**\n * The file to upload.\n */\n image: File\n}\n\ninterface ProcessedImage {\n /**\n * The MIME type of the image.\n */\n mimeType: string\n /**\n * The size of the image in bytes.\n */\n fileSize: number\n /**\n * The file blob of the image.\n */\n fileBlob: Blob\n}\n\nexport interface UploadedImage {\n /**\n * The ID of the uploaded image.\n */\n id: string\n /**\n * The URL of the uploaded image.\n */\n imageUrl?: string\n /**\n * The resource URL of the uploaded image.\n */\n resourceUrl?: string\n}\n\ninterface UseImageUploadReturns {\n /**\n * Upload an image which will be attached to the current user.\n */\n uploadImage: (image: File) => Promise<UploadedImage[]>\n}\n\n// Fetch file data and detect file sizes if not provided\n// Works with file://, data:, and http(s):// URIs\nconst processFileData = async (image: File): Promise<ProcessedImage> => {\n const uri = await fileToDataUri(image)\n\n const response = await fetch(uri)\n const blob = await response.blob()\n\n return {\n mimeType: image.type,\n fileSize: image.size ?? blob.size,\n fileBlob: blob,\n }\n}\n\nconst uploadFileToGCS = async (image: ProcessedImage, target: UploadTarget) => {\n const formData = new FormData()\n target.parameters.forEach(({name, value}: {name: string; value: string}) => {\n formData.append(name, value)\n })\n\n formData.append('file', image.fileBlob)\n\n const uploadResponse = await fetch(target.url, {\n method: 'POST',\n body: formData,\n })\n\n if (!uploadResponse.ok) {\n console.error('Failed to upload image', {\n response: await uploadResponse.text(),\n })\n return {error: 'Failed to upload image'}\n }\n\n return {}\n}\n\nexport const useImageUpload = (): UseImageUploadReturns => {\n const {createImageUploadLink, completeImageUpload} = useShopActions()\n\n const uploadImage = useCallback(\n async (image: File) => {\n const processedImageParams = await processFileData(image)\n\n const links = await createImageUploadLink({\n input: [\n {\n mimeType: processedImageParams.mimeType,\n fileSize: processedImageParams.fileSize,\n },\n ],\n })\n\n if (!links.ok) {\n throw new Error(links.error.message)\n }\n\n if (links.mocked) {\n // Skip upload and return mock data\n return [\n {\n id: 'uploaded-image-id',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0621/0463/3599/files/Mr._Bean_2007_800x800.jpg?v=1763126175',\n resourceUrl:\n 'https://cdn.shopify.com/s/files/1/0621/0463/3599/files/Mr._Bean_2007_800x800.jpg?v=1763126175',\n },\n ]\n }\n\n // Upload single file to GCS\n const {error: uploadError} = await uploadFileToGCS(\n processedImageParams,\n links?.data?.targets?.[0]!\n )\n\n if (uploadError) {\n throw new Error(uploadError)\n }\n\n // 10 second polling for image upload\n let count = 0\n while (count < 30) {\n const result = await completeImageUpload({\n resourceUrls:\n links?.data?.targets?.map(target => target.resourceUrl) || [],\n })\n\n if (!result.ok) {\n throw new Error(result.error.message)\n }\n\n if (result.data?.files?.[0]?.fileStatus === 'READY') {\n return [\n {\n id: result.data.files[0].id,\n imageUrl: result.data.files[0].image?.url,\n resourceUrl: links?.data?.targets?.[0]?.resourceUrl,\n },\n ]\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000))\n count++\n }\n\n throw new Error('Image upload completion timed out')\n },\n [createImageUploadLink, completeImageUpload]\n )\n\n return {\n uploadImage,\n }\n}\n"],"names":["processFileData","image","uri","fileToDataUri","blob","uploadFileToGCS","target","formData","name","value","uploadResponse","useImageUpload","createImageUploadLink","completeImageUpload","useShopActions","useCallback","processedImageParams","links","uploadError","count","result","resolve"],"mappings":";;;AAqDA,MAAMA,IAAkB,OAAOC,MAAyC;AAChE,QAAAC,IAAM,MAAMC,EAAcF,CAAK,GAG/BG,IAAO,OADI,MAAM,MAAMF,CAAG,GACJ,KAAK;AAE1B,SAAA;AAAA,IACL,UAAUD,EAAM;AAAA,IAChB,UAAUA,EAAM,QAAQG,EAAK;AAAA,IAC7B,UAAUA;AAAA,EACZ;AACF,GAEMC,IAAkB,OAAOJ,GAAuBK,MAAyB;AACvE,QAAAC,IAAW,IAAI,SAAS;AAC9B,EAAAD,EAAO,WAAW,QAAQ,CAAC,EAAC,MAAAE,GAAM,OAAAC,QAA0C;AACjE,IAAAF,EAAA,OAAOC,GAAMC,CAAK;AAAA,EAAA,CAC5B,GAEQF,EAAA,OAAO,QAAQN,EAAM,QAAQ;AAEtC,QAAMS,IAAiB,MAAM,MAAMJ,EAAO,KAAK;AAAA,IAC7C,QAAQ;AAAA,IACR,MAAMC;AAAA,EAAA,CACP;AAEG,SAACG,EAAe,KAOb,CAAC,KANN,QAAQ,MAAM,0BAA0B;AAAA,IACtC,UAAU,MAAMA,EAAe,KAAK;AAAA,EAAA,CACrC,GACM,EAAC,OAAO,yBAAwB;AAI3C,GAEaC,IAAiB,MAA6B;AACzD,QAAM,EAAC,uBAAAC,GAAuB,qBAAAC,EAAmB,IAAIC,EAAe;AAyE7D,SAAA;AAAA,IACL,aAxEkBC;AAAA,MAClB,OAAOd,MAAgB;AACf,cAAAe,IAAuB,MAAMhB,EAAgBC,CAAK,GAElDgB,IAAQ,MAAML,EAAsB;AAAA,UACxC,OAAO;AAAA,YACL;AAAA,cACE,UAAUI,EAAqB;AAAA,cAC/B,UAAUA,EAAqB;AAAA,YAAA;AAAA,UACjC;AAAA,QACF,CACD;AAEG,YAAA,CAACC,EAAM;AACT,gBAAM,IAAI,MAAMA,EAAM,MAAM,OAAO;AAGrC,YAAIA,EAAM;AAED,iBAAA;AAAA,YACL;AAAA,cACE,IAAI;AAAA,cACJ,UACE;AAAA,cACF,aACE;AAAA,YAAA;AAAA,UAEN;AAIF,cAAM,EAAC,OAAOC,EAAW,IAAI,MAAMb;AAAA,UACjCW;AAAA,UACAC,GAAO,MAAM,UAAU,CAAC;AAAA,QAC1B;AAEA,YAAIC;AACI,gBAAA,IAAI,MAAMA,CAAW;AAI7B,YAAIC,IAAQ;AACZ,eAAOA,IAAQ,MAAI;AACX,gBAAAC,IAAS,MAAMP,EAAoB;AAAA,YACvC,cACEI,GAAO,MAAM,SAAS,IAAI,CAAUX,MAAAA,EAAO,WAAW,KAAK,CAAA;AAAA,UAAC,CAC/D;AAEG,cAAA,CAACc,EAAO;AACV,kBAAM,IAAI,MAAMA,EAAO,MAAM,OAAO;AAGtC,cAAIA,EAAO,MAAM,QAAQ,CAAC,GAAG,eAAe;AACnC,mBAAA;AAAA,cACL;AAAA,gBACE,IAAIA,EAAO,KAAK,MAAM,CAAC,EAAE;AAAA,gBACzB,UAAUA,EAAO,KAAK,MAAM,CAAC,EAAE,OAAO;AAAA,gBACtC,aAAaH,GAAO,MAAM,UAAU,CAAC,GAAG;AAAA,cAAA;AAAA,YAE5C;AAGF,gBAAM,IAAI,QAAQ,CAAAI,MAAW,WAAWA,GAAS,GAAI,CAAC,GACtDF;AAAA,QAAA;AAGI,cAAA,IAAI,MAAM,mCAAmC;AAAA,MACrD;AAAA,MACA,CAACP,GAAuBC,CAAmB;AAAA,IAC7C;AAAA,EAIA;AACF;"}
1
+ {"version":3,"file":"useImageUpload.js","sources":["../../../src/hooks/storage/useImageUpload.ts"],"sourcesContent":["import {useCallback} from 'react'\n\nimport {useShopActions} from '../../internal/useShopActions'\nimport {fileToDataUri} from '../../utils'\n\nimport type {UploadTarget} from '@shopify/shop-minis-platform/actions'\n\nexport interface UploadImageParams {\n /**\n * The file to upload.\n */\n image: File\n}\n\ninterface ProcessedImage {\n /**\n * The MIME type of the image.\n */\n mimeType: string\n /**\n * The size of the image in bytes.\n */\n fileSize: number\n /**\n * The file blob of the image.\n */\n fileBlob: Blob\n}\n\nexport interface UploadedImage {\n /**\n * The ID of the uploaded image.\n */\n id: string\n /**\n * The URL of the uploaded image.\n */\n imageUrl?: string\n /**\n * The resource URL of the uploaded image.\n */\n resourceUrl?: string\n}\n\ninterface UseImageUploadReturns {\n /**\n * Upload an image which will be attached to the current user.\n */\n uploadImage: (image: File) => Promise<UploadedImage[]>\n}\n\n// Fetch file data and detect file sizes if not provided\n// Works with file://, data:, and http(s):// URIs\nconst processFileData = async (image: File): Promise<ProcessedImage> => {\n const uri = await fileToDataUri(image)\n\n const response = await fetch(uri)\n const blob = await response.blob()\n\n return {\n mimeType: image.type,\n fileSize: image.size ?? blob.size,\n fileBlob: blob,\n }\n}\n\nconst uploadFileToGCS = async (image: ProcessedImage, target: UploadTarget) => {\n const formData = new FormData()\n target.parameters.forEach(({name, value}: {name: string; value: string}) => {\n formData.append(name, value)\n })\n\n formData.append('file', image.fileBlob)\n\n const uploadResponse = await fetch(target.url, {\n method: 'POST',\n body: formData,\n })\n\n if (!uploadResponse.ok) {\n console.error('Failed to upload image', {\n response: await uploadResponse.text(),\n })\n return {error: 'Failed to upload image'}\n }\n\n return {}\n}\n\nexport const useImageUpload = (): UseImageUploadReturns => {\n const {createImageUploadLink, completeImageUpload} = useShopActions()\n\n const uploadImage = useCallback(\n async (image: File) => {\n const processedImageParams = await processFileData(image)\n\n const links = await createImageUploadLink({\n input: [\n {\n mimeType: processedImageParams.mimeType,\n fileSize: processedImageParams.fileSize,\n },\n ],\n })\n\n if (!links.ok) {\n throw new Error(links.error.message)\n }\n\n // Upload single file to GCS\n const {error: uploadError} = await uploadFileToGCS(\n processedImageParams,\n links?.data?.targets?.[0]!\n )\n\n if (uploadError) {\n throw new Error(uploadError)\n }\n\n // 10 second polling for image upload\n let count = 0\n while (count < 30) {\n const result = await completeImageUpload({\n resourceUrls:\n links?.data?.targets?.map(target => target.resourceUrl) || [],\n })\n\n if (!result.ok) {\n throw new Error(result.error.message)\n }\n\n if (result.data?.files?.[0]?.fileStatus === 'READY') {\n return [\n {\n id: result.data.files[0].id,\n imageUrl: result.data.files[0].image?.url,\n resourceUrl: links?.data?.targets?.[0]?.resourceUrl,\n },\n ]\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000))\n count++\n }\n\n throw new Error('Image upload completion timed out')\n },\n [createImageUploadLink, completeImageUpload]\n )\n\n return {\n uploadImage,\n }\n}\n"],"names":["processFileData","image","uri","fileToDataUri","blob","uploadFileToGCS","target","formData","name","value","uploadResponse","useImageUpload","createImageUploadLink","completeImageUpload","useShopActions","useCallback","processedImageParams","links","uploadError","count","result","resolve"],"mappings":";;;AAqDA,MAAMA,IAAkB,OAAOC,MAAyC;AAChE,QAAAC,IAAM,MAAMC,EAAcF,CAAK,GAG/BG,IAAO,OADI,MAAM,MAAMF,CAAG,GACJ,KAAK;AAE1B,SAAA;AAAA,IACL,UAAUD,EAAM;AAAA,IAChB,UAAUA,EAAM,QAAQG,EAAK;AAAA,IAC7B,UAAUA;AAAA,EACZ;AACF,GAEMC,IAAkB,OAAOJ,GAAuBK,MAAyB;AACvE,QAAAC,IAAW,IAAI,SAAS;AAC9B,EAAAD,EAAO,WAAW,QAAQ,CAAC,EAAC,MAAAE,GAAM,OAAAC,QAA0C;AACjE,IAAAF,EAAA,OAAOC,GAAMC,CAAK;AAAA,EAAA,CAC5B,GAEQF,EAAA,OAAO,QAAQN,EAAM,QAAQ;AAEtC,QAAMS,IAAiB,MAAM,MAAMJ,EAAO,KAAK;AAAA,IAC7C,QAAQ;AAAA,IACR,MAAMC;AAAA,EAAA,CACP;AAEG,SAACG,EAAe,KAOb,CAAC,KANN,QAAQ,MAAM,0BAA0B;AAAA,IACtC,UAAU,MAAMA,EAAe,KAAK;AAAA,EAAA,CACrC,GACM,EAAC,OAAO,yBAAwB;AAI3C,GAEaC,IAAiB,MAA6B;AACzD,QAAM,EAAC,uBAAAC,GAAuB,qBAAAC,EAAmB,IAAIC,EAAe;AA4D7D,SAAA;AAAA,IACL,aA3DkBC;AAAA,MAClB,OAAOd,MAAgB;AACf,cAAAe,IAAuB,MAAMhB,EAAgBC,CAAK,GAElDgB,IAAQ,MAAML,EAAsB;AAAA,UACxC,OAAO;AAAA,YACL;AAAA,cACE,UAAUI,EAAqB;AAAA,cAC/B,UAAUA,EAAqB;AAAA,YAAA;AAAA,UACjC;AAAA,QACF,CACD;AAEG,YAAA,CAACC,EAAM;AACT,gBAAM,IAAI,MAAMA,EAAM,MAAM,OAAO;AAIrC,cAAM,EAAC,OAAOC,EAAW,IAAI,MAAMb;AAAA,UACjCW;AAAA,UACAC,GAAO,MAAM,UAAU,CAAC;AAAA,QAC1B;AAEA,YAAIC;AACI,gBAAA,IAAI,MAAMA,CAAW;AAI7B,YAAIC,IAAQ;AACZ,eAAOA,IAAQ,MAAI;AACX,gBAAAC,IAAS,MAAMP,EAAoB;AAAA,YACvC,cACEI,GAAO,MAAM,SAAS,IAAI,CAAUX,MAAAA,EAAO,WAAW,KAAK,CAAA;AAAA,UAAC,CAC/D;AAEG,cAAA,CAACc,EAAO;AACV,kBAAM,IAAI,MAAMA,EAAO,MAAM,OAAO;AAGtC,cAAIA,EAAO,MAAM,QAAQ,CAAC,GAAG,eAAe;AACnC,mBAAA;AAAA,cACL;AAAA,gBACE,IAAIA,EAAO,KAAK,MAAM,CAAC,EAAE;AAAA,gBACzB,UAAUA,EAAO,KAAK,MAAM,CAAC,EAAE,OAAO;AAAA,gBACtC,aAAaH,GAAO,MAAM,UAAU,CAAC,GAAG;AAAA,cAAA;AAAA,YAE5C;AAGF,gBAAM,IAAI,QAAQ,CAAAI,MAAW,WAAWA,GAAS,GAAI,CAAC,GACtDF;AAAA,QAAA;AAGI,cAAA,IAAI,MAAM,mCAAmC;AAAA,MACrD;AAAA,MACA,CAACP,GAAuBC,CAAmB;AAAA,IAC7C;AAAA,EAIA;AACF;"}
package/dist/index.js CHANGED
@@ -4,11 +4,11 @@ import { AddToCartButton as n } from "./components/commerce/add-to-cart.js";
4
4
  import { BuyNowButton as s } from "./components/commerce/buy-now.js";
5
5
  import { ProductCard as u, ProductCardBadge as f, ProductCardContainer as x, ProductCardFavoriteButton as c, ProductCardImage as d, ProductCardImageContainer as C, ProductCardInfo as g, ProductCardPrice as S, ProductCardReviewStars as A, ProductCardTitle as D } from "./components/commerce/product-card.js";
6
6
  import { ProductLink as T } from "./components/commerce/product-link.js";
7
- import { MerchantCard as I, MerchantCardContainer as E, MerchantCardHeader as M, MerchantCardInfo as R, MerchantCardName as w, MerchantCardRating as F } from "./components/commerce/merchant-card.js";
7
+ import { MerchantCard as I, MerchantCardContainer as E, MerchantCardHeader as R, MerchantCardInfo as w, MerchantCardName as F, MerchantCardRating as M } from "./components/commerce/merchant-card.js";
8
8
  import { ProductCardSkeleton as B } from "./components/commerce/product-card-skeleton.js";
9
9
  import { MerchantCardSkeleton as L } from "./components/commerce/merchant-card-skeleton.js";
10
10
  import { QuantitySelector as b } from "./components/commerce/quantity-selector.js";
11
- import { Search as _, SearchInput as y, SearchProvider as G, SearchResultsList as O } from "./components/commerce/search.js";
11
+ import { Search as _, SearchInput as G, SearchProvider as O, SearchResultsList as y } from "./components/commerce/search.js";
12
12
  import { FavoriteButton as V } from "./components/commerce/favorite-button.js";
13
13
  import { ImageContentWrapper as W } from "./components/content/image-content-wrapper.js";
14
14
  import { MinisRouter as q } from "./components/navigation/minis-router.js";
@@ -26,19 +26,19 @@ import { ContentWrapper as cr } from "./components/atoms/content-wrapper.js";
26
26
  import { ProductVariantPrice as Cr } from "./components/atoms/product-variant-price.js";
27
27
  import { Accordion as Sr, AccordionContent as Ar, AccordionItem as Dr, AccordionTrigger as Pr } from "./components/ui/accordion.js";
28
28
  import { Alert as hr, AlertDescription as Ir, AlertTitle as Er } from "./components/ui/alert.js";
29
- import { AlertDialog as Rr, AlertDialogAction as wr, AlertDialogCancel as Fr, AlertDialogContent as vr, AlertDialogDescription as Br, AlertDialogFooter as Ur, AlertDialogHeader as Lr, AlertDialogOverlay as Nr, AlertDialogPortal as br, AlertDialogTitle as kr, AlertDialogTrigger as _r } from "./components/ui/alert-dialog.js";
30
- import { Avatar as Gr, AvatarFallback as Or, AvatarImage as Hr } from "./components/ui/avatar.js";
29
+ import { AlertDialog as wr, AlertDialogAction as Fr, AlertDialogCancel as Mr, AlertDialogContent as vr, AlertDialogDescription as Br, AlertDialogFooter as Ur, AlertDialogHeader as Lr, AlertDialogOverlay as Nr, AlertDialogPortal as br, AlertDialogTitle as kr, AlertDialogTrigger as _r } from "./components/ui/alert-dialog.js";
30
+ import { Avatar as Or, AvatarFallback as yr, AvatarImage as Hr } from "./components/ui/avatar.js";
31
31
  import { Badge as zr, badgeVariants as Wr } from "./components/ui/badge.js";
32
32
  import { Card as qr, CardAction as Kr, CardContent as Qr, CardDescription as Zr, CardFooter as jr, CardHeader as Jr, CardTitle as Xr } from "./components/ui/card.js";
33
33
  import { Carousel as re, CarouselContent as ee, CarouselItem as oe, CarouselNext as te, CarouselPrevious as ae } from "./components/ui/carousel.js";
34
34
  import { Checkbox as pe } from "./components/ui/checkbox.js";
35
35
  import { Dialog as me, DialogClose as se, DialogContent as le, DialogDescription as ue, DialogFooter as fe, DialogHeader as xe, DialogOverlay as ce, DialogPortal as de, DialogTitle as Ce, DialogTrigger as ge } from "./components/ui/dialog.js";
36
- import { Drawer as Ae, DrawerClose as De, DrawerContent as Pe, DrawerDescription as Te, DrawerFooter as he, DrawerHeader as Ie, DrawerOverlay as Ee, DrawerPortal as Me, DrawerTitle as Re, DrawerTrigger as we } from "./components/ui/drawer.js";
36
+ import { Drawer as Ae, DrawerClose as De, DrawerContent as Pe, DrawerDescription as Te, DrawerFooter as he, DrawerHeader as Ie, DrawerOverlay as Ee, DrawerPortal as Re, DrawerTitle as we, DrawerTrigger as Fe } from "./components/ui/drawer.js";
37
37
  import { Input as ve } from "./components/ui/input.js";
38
38
  import { Label as Ue } from "./components/ui/label.js";
39
39
  import { Progress as Ne } from "./components/ui/progress.js";
40
40
  import { RadioGroup as ke, RadioGroupItem as _e } from "./components/ui/radio-group.js";
41
- import { ResizableHandle as Ge, ResizablePanel as Oe, ResizablePanelGroup as He } from "./components/ui/resizable.js";
41
+ import { ResizableHandle as Oe, ResizablePanel as ye, ResizablePanelGroup as He } from "./components/ui/resizable.js";
42
42
  import { ScrollArea as ze, ScrollBar as We } from "./components/ui/scroll-area.js";
43
43
  import { Select as qe, SelectContent as Ke, SelectGroup as Qe, SelectItem as Ze, SelectLabel as je, SelectScrollDownButton as Je, SelectScrollUpButton as Xe, SelectSeparator as $e, SelectTrigger as ro, SelectValue as eo } from "./components/ui/select.js";
44
44
  import { Separator as to } from "./components/ui/separator.js";
@@ -49,13 +49,13 @@ import { Skeleton as Ao } from "./components/ui/skeleton.js";
49
49
  import { useRecentProducts as Po } from "./hooks/user/useRecentProducts.js";
50
50
  import { useRecentShops as ho } from "./hooks/user/useRecentShops.js";
51
51
  import { useSavedProducts as Eo } from "./hooks/user/useSavedProducts.js";
52
- import { useSavedProductsActions as Ro } from "./hooks/user/useSavedProductsActions.js";
53
- import { useFollowedShops as Fo } from "./hooks/user/useFollowedShops.js";
52
+ import { useSavedProductsActions as wo } from "./hooks/user/useSavedProductsActions.js";
53
+ import { useFollowedShops as Mo } from "./hooks/user/useFollowedShops.js";
54
54
  import { useFollowedShopsActions as Bo } from "./hooks/user/useFollowedShopsActions.js";
55
55
  import { useCurrentUser as Lo } from "./hooks/user/useCurrentUser.js";
56
56
  import { useOrders as bo } from "./hooks/user/useOrders.js";
57
57
  import { useBuyerAttributes as _o } from "./hooks/user/useBuyerAttributes.js";
58
- import { useGenerateUserToken as Go } from "./hooks/user/useGenerateUserToken.js";
58
+ import { useGenerateUserToken as Oo } from "./hooks/user/useGenerateUserToken.js";
59
59
  import { useProductListActions as Ho } from "./hooks/product/useProductListActions.js";
60
60
  import { useProductLists as zo } from "./hooks/product/useProductLists.js";
61
61
  import { useProductList as Yo } from "./hooks/product/useProductList.js";
@@ -76,13 +76,13 @@ import { useDeeplink as At } from "./hooks/navigation/useDeeplink.js";
76
76
  import { useNavigateWithTransition as Pt } from "./hooks/navigation/useNavigateWithTransition.js";
77
77
  import { useShop as ht } from "./hooks/shop/useShop.js";
78
78
  import { useRecommendedShops as Et } from "./hooks/shop/useRecommendedShops.js";
79
- import { useCreateImageContent as Rt } from "./hooks/content/useCreateImageContent.js";
80
- import { useErrorToast as Ft } from "./hooks/util/useErrorToast.js";
79
+ import { useCreateImageContent as wt } from "./hooks/content/useCreateImageContent.js";
80
+ import { useErrorToast as Mt } from "./hooks/util/useErrorToast.js";
81
81
  import { useErrorScreen as Bt } from "./hooks/util/useErrorScreen.js";
82
82
  import { useShare as Lt } from "./hooks/util/useShare.js";
83
83
  import { useImagePicker as bt } from "./hooks/util/useImagePicker.js";
84
84
  import { useKeyboardAvoidingView as _t } from "./hooks/util/useKeyboardAvoidingView.js";
85
- import { useRequestPermissions as Gt } from "./hooks/util/useRequestPermissions.js";
85
+ import { useRequestPermissions as Ot } from "./hooks/util/useRequestPermissions.js";
86
86
  import { useOnMiniFocus as Ht } from "./hooks/events/useOnMiniFocus.js";
87
87
  import { useOnMiniBlur as zt } from "./hooks/events/useOnMiniBlur.js";
88
88
  import { useOnMiniClose as Yt } from "./hooks/events/useOnMiniClose.js";
@@ -91,11 +91,10 @@ import { MiniEntityNotFoundError as Zt, MiniError as jt, MiniNetworkError as Jt,
91
91
  import { extractBrandTheme as ra, formatReviewCount as ea, getFeaturedImages as oa, normalizeRating as ta } from "./utils/merchant-card.js";
92
92
  import { parseUrl as ia } from "./utils/parseUrl.js";
93
93
  import { fileToDataUri as na, getResizedImageUrl as ma, getThumbhashDataURL as sa } from "./utils/image.js";
94
- import { formatMoney as ua } from "./utils/formatMoney.js";
95
- import { UserState as xa, UserTokenGenerateUserErrorCode as ca } from "./shop-minis-platform/src/types/user.js";
96
- import { ContentCreateUserErrorCode as Ca, MinisContentStatus as ga } from "./shop-minis-platform/src/types/content.js";
97
- import { Social as Aa } from "./shop-minis-platform/src/types/share.js";
98
- import { DATA_FETCHING_DEFAULT_FETCH_POLICY as Pa, DATA_FETCHING_DEFAULT_PAGE_SIZE as Ta } from "./shop-minis-platform/src/constants.js";
94
+ import { UserState as ua, UserTokenGenerateUserErrorCode as fa } from "./shop-minis-platform/src/types/user.js";
95
+ import { ContentCreateUserErrorCode as ca, MinisContentStatus as da } from "./shop-minis-platform/src/types/content.js";
96
+ import { Social as ga } from "./shop-minis-platform/src/types/share.js";
97
+ import { DATA_FETCHING_DEFAULT_FETCH_POLICY as Aa, DATA_FETCHING_DEFAULT_PAGE_SIZE as Da } from "./shop-minis-platform/src/constants.js";
99
98
  export {
100
99
  Sr as Accordion,
101
100
  Ar as AccordionContent,
@@ -104,10 +103,10 @@ export {
104
103
  n as AddToCartButton,
105
104
  hr as Alert,
106
105
  Ir as AlertDescription,
107
- Rr as AlertDialog,
108
- wr as AlertDialogAction,
106
+ wr as AlertDialog,
107
+ Fr as AlertDialogAction,
109
108
  pr as AlertDialogAtom,
110
- Fr as AlertDialogCancel,
109
+ Mr as AlertDialogCancel,
111
110
  vr as AlertDialogContent,
112
111
  Br as AlertDialogDescription,
113
112
  Ur as AlertDialogFooter,
@@ -117,8 +116,8 @@ export {
117
116
  kr as AlertDialogTitle,
118
117
  _r as AlertDialogTrigger,
119
118
  Er as AlertTitle,
120
- Gr as Avatar,
121
- Or as AvatarFallback,
119
+ Or as Avatar,
120
+ yr as AvatarFallback,
122
121
  Hr as AvatarImage,
123
122
  zr as Badge,
124
123
  j as Button,
@@ -136,10 +135,10 @@ export {
136
135
  te as CarouselNext,
137
136
  ae as CarouselPrevious,
138
137
  pe as Checkbox,
139
- Ca as ContentCreateUserErrorCode,
138
+ ca as ContentCreateUserErrorCode,
140
139
  cr as ContentWrapper,
141
- Pa as DATA_FETCHING_DEFAULT_FETCH_POLICY,
142
- Ta as DATA_FETCHING_DEFAULT_PAGE_SIZE,
140
+ Aa as DATA_FETCHING_DEFAULT_FETCH_POLICY,
141
+ Da as DATA_FETCHING_DEFAULT_PAGE_SIZE,
143
142
  o as DATA_NAVIGATION_TYPE_ATTRIBUTE,
144
143
  me as Dialog,
145
144
  se as DialogClose,
@@ -158,9 +157,9 @@ export {
158
157
  he as DrawerFooter,
159
158
  Ie as DrawerHeader,
160
159
  Ee as DrawerOverlay,
161
- Me as DrawerPortal,
162
- Re as DrawerTitle,
163
- we as DrawerTrigger,
160
+ Re as DrawerPortal,
161
+ we as DrawerTitle,
162
+ Fe as DrawerTrigger,
164
163
  V as FavoriteButton,
165
164
  X as IconButton,
166
165
  rr as Image,
@@ -171,16 +170,16 @@ export {
171
170
  ar as LongPressDetector,
172
171
  I as MerchantCard,
173
172
  E as MerchantCardContainer,
174
- M as MerchantCardHeader,
175
- R as MerchantCardInfo,
176
- w as MerchantCardName,
177
- F as MerchantCardRating,
173
+ R as MerchantCardHeader,
174
+ w as MerchantCardInfo,
175
+ F as MerchantCardName,
176
+ M as MerchantCardRating,
178
177
  L as MerchantCardSkeleton,
179
178
  Zt as MiniEntityNotFoundError,
180
179
  jt as MiniError,
181
180
  Jt as MiniNetworkError,
182
181
  i as MinisContainer,
183
- ga as MinisContentStatus,
182
+ da as MinisContentStatus,
184
183
  q as MinisRouter,
185
184
  t as NAVIGATION_TYPES,
186
185
  u as ProductCard,
@@ -200,15 +199,15 @@ export {
200
199
  b as QuantitySelector,
201
200
  ke as RadioGroup,
202
201
  _e as RadioGroupItem,
203
- Ge as ResizableHandle,
204
- Oe as ResizablePanel,
202
+ Oe as ResizableHandle,
203
+ ye as ResizablePanel,
205
204
  He as ResizablePanelGroup,
206
205
  ze as ScrollArea,
207
206
  We as ScrollBar,
208
207
  _ as Search,
209
- y as SearchInput,
210
- G as SearchProvider,
211
- O as SearchResultsList,
208
+ G as SearchInput,
209
+ O as SearchProvider,
210
+ y as SearchResultsList,
212
211
  qe as Select,
213
212
  Ke as SelectContent,
214
213
  Qe as SelectGroup,
@@ -229,19 +228,18 @@ export {
229
228
  uo as SheetTitle,
230
229
  fo as SheetTrigger,
231
230
  Ao as Skeleton,
232
- Aa as Social,
231
+ ga as Social,
233
232
  fr as TextInput,
234
233
  co as Toaster,
235
234
  or as Touchable,
236
235
  Q as TransitionLink,
237
- xa as UserState,
238
- ca as UserTokenGenerateUserErrorCode,
236
+ ua as UserState,
237
+ fa as UserTokenGenerateUserErrorCode,
239
238
  lr as VideoPlayer,
240
239
  Wr as badgeVariants,
241
240
  ra as extractBrandTheme,
242
241
  na as fileToDataUri,
243
242
  Xt as formatError,
244
- ua as formatMoney,
245
243
  ea as formatReviewCount,
246
244
  oa as getFeaturedImages,
247
245
  ma as getResizedImageUrl,
@@ -252,15 +250,15 @@ export {
252
250
  st as useAsyncStorage,
253
251
  _o as useBuyerAttributes,
254
252
  gt as useCloseMini,
255
- Rt as useCreateImageContent,
253
+ wt as useCreateImageContent,
256
254
  nt as useCuratedProducts,
257
255
  Lo as useCurrentUser,
258
256
  At as useDeeplink,
259
257
  Bt as useErrorScreen,
260
- Ft as useErrorToast,
261
- Fo as useFollowedShops,
258
+ Mt as useErrorToast,
259
+ Mo as useFollowedShops,
262
260
  Bo as useFollowedShopsActions,
263
- Go as useGenerateUserToken,
261
+ Oo as useGenerateUserToken,
264
262
  bt as useImagePicker,
265
263
  xt as useImageUpload,
266
264
  _t as useKeyboardAvoidingView,
@@ -283,9 +281,9 @@ export {
283
281
  ho as useRecentShops,
284
282
  tt as useRecommendedProducts,
285
283
  Et as useRecommendedShops,
286
- Gt as useRequestPermissions,
284
+ Ot as useRequestPermissions,
287
285
  Eo as useSavedProducts,
288
- Ro as useSavedProductsActions,
286
+ wo as useSavedProductsActions,
289
287
  ut as useSecureStorage,
290
288
  Lt as useShare,
291
289
  ht as useShop,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}