@lime-bundles/react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useCart.cjs +84 -0
- package/dist/hooks/useCart.cjs.map +1 -0
- package/dist/hooks/useCart.d.cts +19 -0
- package/dist/hooks/useCart.d.ts +19 -0
- package/dist/hooks/useCart.js +64 -0
- package/dist/hooks/useCart.js.map +1 -0
- package/dist/index.cjs +689 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +60 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +677 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/FixedBundle.tsx","../src/hooks/useBundleData.ts","../src/hooks/useCart.ts","../src/hooks/useAnalytics.ts","../src/components/MixMatchBundle.tsx","../src/components/VolumeBundle.tsx"],"sourcesContent":["/**\n * Fixed bundle component — displays pre-selected products with discount.\n */\nimport { useCallback } from \"react\";\nimport { formatMoney, calculateDiscount, type CartLineItem } from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useCart } from \"../hooks/useCart\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport type { BundleComponentProps } from \"./types\";\n\nexport function FixedBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n cartId,\n cartApi,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const { bundle, loading, error: loadError } = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { addToCart, loading: cartLoading, error: cartError } = useCart({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n bundleType: \"fixed\",\n cartId,\n cartApi,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"fixed\",\n enabled: analyticsEnabled !== false,\n });\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle) return;\n\n const items: CartLineItem[] = bundle.products\n .filter((p) => p.variants.nodes.some((v) => v.availableForSale))\n .map((p) => {\n const variant = p.variants.nodes.find((v) => v.availableForSale)!;\n return { variantId: variant.id, quantity: 1 };\n });\n\n if (items.length === 0) return;\n\n const result = await addToCart(items);\n\n if (result.success) {\n const totalPrice = bundle.products.reduce((sum, p) => {\n const price = parseFloat(p.priceRange.minVariantPrice.amount);\n return sum + calculateDiscount(price, bundle.discountConfig.discountType, bundle.discountConfig.discountValue);\n }, 0);\n\n trackAddToCart({\n productId: bundle.products[0]?.id ?? \"\",\n quantity: 1,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n\n onAddToCart?.(items);\n }\n }, [bundle, addToCart, trackAddToCart, onAddToCart]);\n\n if (loading) {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (loadError || !bundle) {\n if (onError) onError(loadError ?? \"Bundle not found\");\n return null;\n }\n\n const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n return (\n <div\n ref={elementRef}\n className={`lb-bundle lb-bundle--fixed ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <h3 className=\"lb-bundle__title\">{bundle.title}</h3>\n\n {bundle.discountLabel && (\n <span className=\"lb-bundle__discount-badge\">\n {bundle.discountLabel}\n </span>\n )}\n\n <div className=\"lb-bundle__products\">\n {bundle.products.map((product) => (\n <div key={product.id} className=\"lb-bundle__product\" part=\"product\">\n {product.featuredImage && (\n <img\n src={product.featuredImage.url}\n alt={product.featuredImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n <p className=\"lb-bundle__product-price\">\n {formatMoney(product.priceRange.minVariantPrice.amount, currency)}\n </p>\n </div>\n </div>\n ))}\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">{cartError}</p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={cartLoading}\n aria-busy={cartLoading}\n >\n {cartLoading\n ? \"Adding...\"\n : bundle.widgetConfig.ctaText ?? \"Add Bundle to Cart\"}\n </button>\n </div>\n );\n}\n","/**\n * Hook to fetch and parse bundle data from the Storefront API.\n */\nimport { useState, useEffect, useRef } from \"react\";\nimport {\n createStorefrontClient,\n BUNDLE_METAOBJECT_QUERY,\n parseMetaobjectBundle,\n type ParsedBundle,\n type BundleMetaobjectResponse,\n} from \"@lime-bundles/core\";\n\nexport interface UseBundleDataOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n bundleGid: string;\n}\n\nexport interface UseBundleDataResult {\n bundle: ParsedBundle | null;\n loading: boolean;\n error: string | null;\n}\n\nexport function useBundleData(\n options: UseBundleDataOptions,\n): UseBundleDataResult {\n const [bundle, setBundle] = useState<ParsedBundle | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => {\n // Cancel previous request\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setLoading(true);\n setError(null);\n\n const client = createStorefrontClient({\n shopDomain: options.shopDomain,\n accessToken: options.storefrontAccessToken,\n });\n\n client\n .query<BundleMetaobjectResponse>(BUNDLE_METAOBJECT_QUERY, {\n id: options.bundleGid,\n })\n .then((data) => {\n if (controller.signal.aborted) return;\n\n if (!data.metaobject) {\n setError(\"Bundle not found\");\n setBundle(null);\n } else {\n const parsed = parseMetaobjectBundle(\n data.metaobject.id,\n data.metaobject.fields,\n );\n if (parsed) {\n setBundle(parsed);\n } else {\n setError(\"Bundle is not active or has expired\");\n setBundle(null);\n }\n }\n setLoading(false);\n })\n .catch((err) => {\n if (controller.signal.aborted) return;\n setError(err instanceof Error ? err.message : \"Failed to load bundle\");\n setLoading(false);\n });\n\n return () => {\n controller.abort();\n };\n }, [options.shopDomain, options.storefrontAccessToken, options.bundleGid]);\n\n return { bundle, loading, error };\n}\n","/**\n * Hook for cart API operations.\n * Auto-detects AJAX vs Storefront Cart API.\n */\nimport { useState, useCallback, useMemo } from \"react\";\nimport {\n detectCartApi,\n createAjaxCartApi,\n createStorefrontCartApi,\n createStorefrontClient,\n type CartApi,\n type CartLineItem,\n type AddToCartResult,\n} from \"@lime-bundles/core\";\n\nexport interface UseCartOptions {\n shopDomain: string;\n storefrontAccessToken: string;\n bundleGid: string;\n bundleType: string;\n cartId?: string;\n cartApi?: \"ajax\" | \"storefront\"; // Manual override\n}\n\nexport interface UseCartResult {\n addToCart: (items: CartLineItem[]) => Promise<AddToCartResult>;\n loading: boolean;\n error: string | null;\n lastResult: AddToCartResult | null;\n}\n\nexport function useCart(options: UseCartOptions): UseCartResult {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [lastResult, setLastResult] = useState<AddToCartResult | null>(null);\n\n const cart: CartApi = useMemo(() => {\n const apiType = options.cartApi ?? detectCartApi();\n\n if (apiType === \"ajax\") {\n return createAjaxCartApi(options.bundleGid, options.bundleType);\n }\n\n const client = createStorefrontClient({\n shopDomain: options.shopDomain,\n accessToken: options.storefrontAccessToken,\n });\n return createStorefrontCartApi(\n client,\n options.bundleGid,\n options.bundleType,\n options.cartId,\n );\n }, [\n options.shopDomain,\n options.storefrontAccessToken,\n options.bundleGid,\n options.bundleType,\n options.cartId,\n options.cartApi,\n ]);\n\n const addToCart = useCallback(\n async (items: CartLineItem[]): Promise<AddToCartResult> => {\n setLoading(true);\n setError(null);\n try {\n const result = await cart.addLines(items);\n setLastResult(result);\n if (!result.success) {\n setError(result.error ?? \"Failed to add to cart\");\n }\n return result;\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Failed to add to cart\";\n setError(message);\n const result: AddToCartResult = { success: false, error: message };\n setLastResult(result);\n return result;\n } finally {\n setLoading(false);\n }\n },\n [cart],\n );\n\n return { addToCart, loading, error, lastResult };\n}\n","/**\n * Hook for analytics event reporting (impressions + add-to-cart).\n * Impressions fire once per mount using IntersectionObserver.\n */\nimport { useEffect, useMemo, useRef, useCallback, useState } from \"react\";\nimport {\n reportImpression,\n reportAddToCart,\n observeImpression,\n type AnalyticsConfig,\n} from \"@lime-bundles/core\";\n\nexport interface UseAnalyticsOptions {\n shopDomain: string;\n appUrl: string;\n bundleGid: string;\n bundleType: string;\n enabled?: boolean;\n abTestId?: string;\n abVariant?: string;\n}\n\nexport function useAnalytics(options: UseAnalyticsOptions) {\n const impressionFiredRef = useRef(false);\n // Callback ref + state so the observer effect re-runs when the host element\n // is attached (e.g. after a `loading` branch swaps in the real DOM node).\n const [element, setElement] = useState<HTMLElement | null>(null);\n const elementRef = useCallback((el: HTMLElement | null) => {\n setElement(el);\n }, []);\n\n const config: AnalyticsConfig = useMemo(\n () => ({ shopDomain: options.shopDomain, appUrl: options.appUrl }),\n [options.shopDomain, options.appUrl],\n );\n\n // Reset the fired flag when bundle identity changes so a reused component\n // (e.g. via navigation) can report a fresh impression.\n useEffect(() => {\n impressionFiredRef.current = false;\n }, [options.bundleGid, options.abVariant]);\n\n // Set up impression observer once the element is attached\n useEffect(() => {\n if (options.enabled === false) return;\n if (impressionFiredRef.current) return;\n if (!element) return;\n\n const cleanup = observeImpression(element, () => {\n if (impressionFiredRef.current) return;\n impressionFiredRef.current = true;\n\n reportImpression(config, {\n bundleGid: options.bundleGid,\n bundleType: options.bundleType,\n abTestId: options.abTestId,\n abVariant: options.abVariant,\n });\n });\n\n return cleanup;\n }, [\n element,\n config,\n options.enabled,\n options.bundleGid,\n options.bundleType,\n options.abTestId,\n options.abVariant,\n ]);\n\n const trackAddToCart = useCallback(\n (event: {\n productId: string;\n quantity: number;\n totalPrice: number;\n }) => {\n if (options.enabled === false) return;\n\n reportAddToCart(config, {\n bundleGid: options.bundleGid,\n bundleType: options.bundleType,\n productId: event.productId,\n quantity: event.quantity,\n totalPrice: event.totalPrice,\n abTestId: options.abTestId,\n abVariant: options.abVariant,\n });\n },\n [\n config,\n options.enabled,\n options.bundleGid,\n options.bundleType,\n options.abTestId,\n options.abVariant,\n ],\n );\n\n return { elementRef, trackAddToCart };\n}\n","/**\n * Mix-and-match bundle component — customer picks products from a pool.\n */\nimport { useState, useCallback } from \"react\";\nimport {\n formatMoney,\n validateQuantity,\n type CartLineItem,\n type ProductVariant,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useCart } from \"../hooks/useCart\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport type { BundleComponentProps } from \"./types\";\n\ninterface SelectedItem {\n productId: string;\n variantId: string;\n quantity: number;\n}\n\nexport function MixMatchBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n cartId,\n cartApi,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const { bundle, loading, error: loadError } = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { addToCart, loading: cartLoading, error: cartError } = useCart({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n bundleType: \"mix_match\",\n cartId,\n cartApi,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"mix_match\",\n enabled: analyticsEnabled !== false,\n });\n\n const [selections, setSelections] = useState<Map<string, SelectedItem>>(new Map());\n\n const totalQuantity = Array.from(selections.values()).reduce(\n (sum, s) => sum + s.quantity,\n 0,\n );\n\n const validation = bundle\n ? validateQuantity(totalQuantity, bundle.minQuantity, bundle.maxQuantity)\n : { valid: false, totalQuantity: 0, message: null };\n\n const toggleProduct = useCallback(\n (productId: string, variant: ProductVariant) => {\n setSelections((prev) => {\n const next = new Map(prev);\n const key = `${productId}:${variant.id}`;\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.set(key, { productId, variantId: variant.id, quantity: 1 });\n }\n return next;\n });\n },\n [],\n );\n\n const updateQuantity = useCallback(\n (productId: string, variantId: string, quantity: number) => {\n setSelections((prev) => {\n const next = new Map(prev);\n const key = `${productId}:${variantId}`;\n if (quantity <= 0) {\n next.delete(key);\n } else {\n next.set(key, { productId, variantId, quantity });\n }\n return next;\n });\n },\n [],\n );\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !validation.valid) return;\n\n const items: CartLineItem[] = Array.from(selections.values()).map((s) => ({\n variantId: s.variantId,\n quantity: s.quantity,\n }));\n\n const result = await addToCart(items);\n\n if (result.success) {\n const totalPrice = items.reduce((sum, item) => {\n const product = bundle.products.find((p) =>\n p.variants.nodes.some((v) => v.id === item.variantId),\n );\n const variant = product?.variants.nodes.find(\n (v) => v.id === item.variantId,\n );\n return sum + (parseFloat(variant?.price.amount ?? \"0\") * item.quantity);\n }, 0);\n\n trackAddToCart({\n productId: bundle.products[0]?.id ?? \"\",\n quantity: totalQuantity,\n totalPrice: Math.round(totalPrice * 100) / 100,\n });\n\n onAddToCart?.(items);\n setSelections(new Map());\n }\n }, [bundle, selections, validation.valid, addToCart, trackAddToCart, totalQuantity, onAddToCart]);\n\n if (loading) {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--products\" />\n </div>\n );\n }\n\n if (loadError || !bundle) {\n if (onError) onError(loadError ?? \"Bundle not found\");\n return null;\n }\n\n const currency = bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n return (\n <div\n ref={elementRef}\n className={`lb-bundle lb-bundle--mix-match ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <h3 className=\"lb-bundle__title\">{bundle.title}</h3>\n\n {bundle.discountLabel && (\n <span className=\"lb-bundle__discount-badge\">{bundle.discountLabel}</span>\n )}\n\n <p className=\"lb-bundle__instructions\">\n {bundle.minQuantity && bundle.maxQuantity\n ? `Select ${bundle.minQuantity}–${bundle.maxQuantity} items`\n : bundle.minQuantity\n ? `Select at least ${bundle.minQuantity} items`\n : bundle.maxQuantity\n ? `Select up to ${bundle.maxQuantity} items`\n : \"Select your items\"}\n </p>\n\n <div className=\"lb-bundle__products lb-bundle__products--selectable\">\n {bundle.products.map((product) => {\n const defaultVariant = product.variants.nodes.find((v) => v.availableForSale) ?? product.variants.nodes[0];\n if (!defaultVariant) return null;\n\n const key = `${product.id}:${defaultVariant.id}`;\n const selected = selections.get(key);\n\n return (\n <div\n key={product.id}\n className={`lb-bundle__product lb-bundle__product--selectable ${selected ? \"lb-bundle__product--selected\" : \"\"}`}\n >\n {product.featuredImage && (\n <img\n src={product.featuredImage.url}\n alt={product.featuredImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n <p className=\"lb-bundle__product-price\">\n {formatMoney(defaultVariant.price.amount, currency)}\n </p>\n </div>\n <div className=\"lb-bundle__product-actions\">\n {selected ? (\n <div className=\"lb-bundle__quantity-control\">\n <button\n aria-label={`Decrease ${product.title}`}\n onClick={() => updateQuantity(product.id, defaultVariant.id, selected.quantity - 1)}\n >\n −\n </button>\n <span>{selected.quantity}</span>\n <button\n aria-label={`Increase ${product.title}`}\n onClick={() => updateQuantity(product.id, defaultVariant.id, selected.quantity + 1)}\n >\n +\n </button>\n </div>\n ) : (\n <button\n className=\"lb-bundle__select-btn\"\n onClick={() => toggleProduct(product.id, defaultVariant)}\n disabled={!defaultVariant.availableForSale}\n >\n {defaultVariant.availableForSale ? \"Select\" : \"Sold out\"}\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n\n {validation.message && (\n <p className=\"lb-bundle__validation\" role=\"status\">{validation.message}</p>\n )}\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">{cartError}</p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={cartLoading || !validation.valid}\n aria-busy={cartLoading}\n >\n {cartLoading\n ? \"Adding...\"\n : bundle.widgetConfig.ctaText ?? `Add ${totalQuantity} Items to Cart`}\n </button>\n </div>\n );\n}\n","/**\n * Volume bundle component — quantity selector with tier calculator.\n */\nimport { useState, useCallback } from \"react\";\nimport {\n formatMoney,\n calculateTierSavings,\n getActiveTier,\n type CartLineItem,\n} from \"@lime-bundles/core\";\nimport { useBundleData } from \"../hooks/useBundleData\";\nimport { useCart } from \"../hooks/useCart\";\nimport { useAnalytics } from \"../hooks/useAnalytics\";\nimport type { BundleComponentProps } from \"./types\";\n\nexport function VolumeBundle(props: BundleComponentProps) {\n const {\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n cartId,\n cartApi,\n appUrl,\n analyticsEnabled,\n onAddToCart,\n onError,\n className,\n } = props;\n\n const { bundle, loading, error: loadError } = useBundleData({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n });\n\n const { addToCart, loading: cartLoading, error: cartError } = useCart({\n shopDomain,\n storefrontAccessToken,\n bundleGid,\n bundleType: \"volume\",\n cartId,\n cartApi,\n });\n\n const { elementRef, trackAddToCart } = useAnalytics({\n shopDomain,\n appUrl: appUrl ?? `https://${shopDomain}`,\n bundleGid,\n bundleType: \"volume\",\n enabled: analyticsEnabled !== false,\n });\n\n const [quantity, setQuantity] = useState(1);\n\n const product = bundle?.products[0];\n const basePrice = product\n ? parseFloat(product.priceRange.minVariantPrice.amount)\n : 0;\n const currency = product?.priceRange.minVariantPrice.currencyCode ?? \"USD\";\n\n const tierSavings = bundle\n ? calculateTierSavings(bundle.volumeTiers, basePrice, quantity)\n : [];\n const activeTier = bundle\n ? getActiveTier(bundle.volumeTiers, quantity)\n : null;\n\n const handleAddToCart = useCallback(async () => {\n if (!bundle || !product) return;\n\n const variant = product.variants.nodes.find((v) => v.availableForSale);\n if (!variant) return;\n\n const items: CartLineItem[] = [\n { variantId: variant.id, quantity },\n ];\n\n const result = await addToCart(items);\n\n if (result.success) {\n const unitPrice = activeTier\n ? basePrice * (1 - activeTier.discountValue / 100)\n : basePrice;\n\n trackAddToCart({\n productId: product.id,\n quantity,\n totalPrice: Math.round(unitPrice * quantity * 100) / 100,\n });\n\n onAddToCart?.(items);\n }\n }, [bundle, product, quantity, activeTier, basePrice, addToCart, trackAddToCart, onAddToCart]);\n\n if (loading) {\n return (\n <div className={`lb-bundle lb-bundle--loading ${className ?? \"\"}`}>\n <div className=\"lb-skeleton lb-skeleton--title\" />\n <div className=\"lb-skeleton lb-skeleton--tiers\" />\n </div>\n );\n }\n\n if (loadError || !bundle || !product) {\n if (onError) onError(loadError ?? \"Bundle not found\");\n return null;\n }\n\n return (\n <div\n ref={elementRef}\n className={`lb-bundle lb-bundle--volume ${className ?? \"\"}`}\n role=\"region\"\n aria-label={bundle.title}\n >\n <h3 className=\"lb-bundle__title\">{bundle.title}</h3>\n\n {/* Product display */}\n <div className=\"lb-bundle__product lb-bundle__product--volume\">\n {product.featuredImage && (\n <img\n src={product.featuredImage.url}\n alt={product.featuredImage.altText ?? product.title}\n className=\"lb-bundle__product-image\"\n loading=\"lazy\"\n />\n )}\n <div className=\"lb-bundle__product-info\">\n <p className=\"lb-bundle__product-title\">{product.title}</p>\n <p className=\"lb-bundle__product-price\">\n {formatMoney(basePrice, currency)} each\n </p>\n </div>\n </div>\n\n {/* Tier calculator */}\n <div className=\"lb-bundle__tiers\" role=\"table\" aria-label=\"Volume discounts\">\n {tierSavings.map((ts) => (\n <div\n key={ts.tier.minQuantity}\n className={`lb-bundle__tier ${ts.isActive ? \"lb-bundle__tier--active\" : \"\"}`}\n role=\"row\"\n >\n <span className=\"lb-bundle__tier-quantity\" role=\"cell\">\n {ts.tier.minQuantity}+ items\n </span>\n <span className=\"lb-bundle__tier-price\" role=\"cell\">\n {formatMoney(ts.unitPrice, currency)} each\n </span>\n <span className=\"lb-bundle__tier-savings\" role=\"cell\">\n Save {ts.savingsPercent.toFixed(0)}%\n </span>\n {ts.tier.label && (\n <span className=\"lb-bundle__tier-label\" role=\"cell\">\n {ts.tier.label}\n </span>\n )}\n </div>\n ))}\n </div>\n\n {/* Quantity selector */}\n <div className=\"lb-bundle__quantity-selector\">\n <label htmlFor={`lb-qty-${bundle.id}`}>Quantity</label>\n <div className=\"lb-bundle__quantity-control\">\n <button\n aria-label=\"Decrease quantity\"\n onClick={() => setQuantity((q) => Math.max(1, q - 1))}\n >\n −\n </button>\n <input\n id={`lb-qty-${bundle.id}`}\n type=\"number\"\n min={1}\n value={quantity}\n onChange={(e) => {\n const val = parseInt(e.target.value, 10);\n if (!isNaN(val) && val > 0) setQuantity(val);\n }}\n className=\"lb-bundle__quantity-input\"\n />\n <button\n aria-label=\"Increase quantity\"\n onClick={() => setQuantity((q) => q + 1)}\n >\n +\n </button>\n </div>\n </div>\n\n {cartError && (\n <p className=\"lb-bundle__error\" role=\"alert\">{cartError}</p>\n )}\n\n <button\n className=\"lb-bundle__cta\"\n onClick={handleAddToCart}\n disabled={cartLoading}\n aria-busy={cartLoading}\n >\n {cartLoading\n ? \"Adding...\"\n : bundle.widgetConfig.ctaText ?? `Add ${quantity} to Cart`}\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useState","createStorefrontClient","useEffect","useMemo","useRef","useCallback","useState","useCallback","useState","useCallback","formatMoney","jsx","jsxs","useState","useCallback","formatMoney","useState","useCallback","formatMoney","jsx","jsxs","useState","useCallback","formatMoney"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lime-bundles/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React components and hooks for Lime Bundles headless storefronts — Hydrogen, Next.js, Vite, and any React renderer.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./useCart": {
|
|
16
|
+
"types": "./dist/hooks/useCart.d.ts",
|
|
17
|
+
"import": "./dist/hooks/useCart.js",
|
|
18
|
+
"require": "./dist/hooks/useCart.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./styles.css": "./dist/styles.css",
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/lime-app-dev/lime-bundles-app.git",
|
|
33
|
+
"directory": "packages/react"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/lime-app-dev/lime-bundles-app/tree/main/packages/react#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/lime-app-dev/lime-bundles-app/issues"
|
|
38
|
+
},
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"author": "lime-app-dev",
|
|
41
|
+
"keywords": [
|
|
42
|
+
"shopify",
|
|
43
|
+
"bundles",
|
|
44
|
+
"headless",
|
|
45
|
+
"storefront",
|
|
46
|
+
"hydrogen",
|
|
47
|
+
"nextjs",
|
|
48
|
+
"react"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"dev": "tsup --watch",
|
|
53
|
+
"typecheck": "tsc --noEmit"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"react": ">=18.0.0",
|
|
57
|
+
"react-dom": ">=18.0.0"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@lime-bundles/core": "^0.1.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"react": "^18.0.0",
|
|
64
|
+
"react-dom": "^18.0.0",
|
|
65
|
+
"tsup": "^8.0.0",
|
|
66
|
+
"typescript": "^5.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|