@shopify/shop-minis-react 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/_virtual/index4.js +2 -2
  2. package/dist/_virtual/index5.js +2 -3
  3. package/dist/_virtual/index5.js.map +1 -1
  4. package/dist/_virtual/index6.js +3 -2
  5. package/dist/_virtual/index6.js.map +1 -1
  6. package/dist/components/MinisContainer.js +10 -10
  7. package/dist/components/MinisContainer.js.map +1 -1
  8. package/dist/components/atoms/product-variant-price.js +36 -43
  9. package/dist/components/atoms/product-variant-price.js.map +1 -1
  10. package/dist/components/commerce/add-to-cart.js +70 -53
  11. package/dist/components/commerce/add-to-cart.js.map +1 -1
  12. package/dist/components/commerce/buy-now.js +75 -0
  13. package/dist/components/commerce/buy-now.js.map +1 -0
  14. package/dist/components/commerce/product-card.js +16 -17
  15. package/dist/components/commerce/product-card.js.map +1 -1
  16. package/dist/index.js +230 -230
  17. package/dist/{hooks/shop → internal}/useShopCartActions.js +2 -2
  18. package/dist/internal/useShopCartActions.js.map +1 -0
  19. package/dist/shop-minis-react/node_modules/.pnpm/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js +1 -1
  20. package/dist/shop-minis-react/node_modules/.pnpm/mpd-parser@1.3.1/node_modules/mpd-parser/dist/mpd-parser.es.js +1 -1
  21. package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
  22. package/dist/shop-minis-react/node_modules/.pnpm/simple-swizzle@0.2.2/node_modules/simple-swizzle/index.js +1 -1
  23. package/dist/shop-minis-react/node_modules/.pnpm/use-sync-external-store@1.5.0_react@19.1.0/node_modules/use-sync-external-store/shim/index.js +1 -1
  24. package/generated-hook-maps/hook-actions-map.json +0 -4
  25. package/package.json +2 -2
  26. package/src/components/MinisContainer.tsx +5 -3
  27. package/src/components/atoms/product-variant-price.tsx +1 -5
  28. package/src/components/commerce/add-to-cart.test.tsx +218 -3
  29. package/src/components/commerce/add-to-cart.tsx +40 -16
  30. package/src/components/commerce/buy-now.test.tsx +272 -0
  31. package/src/components/commerce/buy-now.tsx +108 -0
  32. package/src/components/commerce/product-card.tsx +5 -6
  33. package/src/components/index.ts +1 -0
  34. package/src/hooks/index.ts +0 -1
  35. package/src/{hooks/shop → internal}/useShopCartActions.ts +2 -2
  36. package/src/stories/AddToCart.stories.tsx +75 -10
  37. package/src/stories/ProductVariantPrice.stories.tsx +1 -4
  38. package/dist/hooks/shop/useShopCartActions.js.map +0 -1
@@ -1,5 +1,5 @@
1
- var e = { exports: {} };
1
+ var r = {};
2
2
  export {
3
- e as __module
3
+ r as __exports
4
4
  };
5
5
  //# sourceMappingURL=index4.js.map
@@ -1,6 +1,5 @@
1
- import { __require as r } from "../shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js";
2
- var i = r();
1
+ var e = { exports: {} };
3
2
  export {
4
- i as l
3
+ e as __module
5
4
  };
6
5
  //# sourceMappingURL=index5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index5.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index5.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,5 +1,6 @@
1
- var r = {};
1
+ import { __require as r } from "../shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js";
2
+ var i = r();
2
3
  export {
3
- r as __exports
4
+ i as l
4
5
  };
5
6
  //# sourceMappingURL=index6.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index6.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
1
+ {"version":3,"file":"index6.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -3,35 +3,35 @@ import { useState as u, useCallback as f, useEffect as p } from "react";
3
3
  import { useShopActions as v } from "../internal/useShopActions.js";
4
4
  import { injectMocks as y } from "../mocks.js";
5
5
  import { ImagePickerProvider as h } from "../providers/ImagePickerProvider.js";
6
- import { ErrorBoundary as g } from "./ErrorBoundary.js";
6
+ import { ErrorBoundary as E } from "./ErrorBoundary.js";
7
7
  y();
8
8
  function b({ children: a }) {
9
- const [i, n] = u(!1), { reportError: o } = v(), c = f(
10
- async (t) => {
9
+ const [i, o] = u(!1), t = v(), c = f(
10
+ async (n) => {
11
11
  try {
12
- await o(t);
12
+ t && t.reportError && await t.reportError(n);
13
13
  } catch (e) {
14
14
  console.error("Failed to report error to app:", e);
15
15
  }
16
16
  },
17
- [o]
17
+ [t]
18
18
  );
19
19
  return p(() => {
20
- const t = () => window.minisSDK ? (n(!0), !0) : !1;
21
- if (t())
20
+ const n = () => window.minisSDK ? (o(!0), !0) : !1;
21
+ if (n())
22
22
  return;
23
23
  const e = (d) => {
24
24
  const { type: m } = JSON.parse(d.data);
25
- m === "MINIS_SDK_READY" && n(!0);
25
+ m === "MINIS_SDK_READY" && o(!0);
26
26
  };
27
27
  window.addEventListener("message", e), document.addEventListener("message", e);
28
28
  const s = setInterval(() => {
29
- t() && clearInterval(s);
29
+ n() && clearInterval(s);
30
30
  }, 100);
31
31
  return () => {
32
32
  clearInterval(s), window.removeEventListener("message", e), document.removeEventListener("message", e);
33
33
  };
34
- }, []), i ? /* @__PURE__ */ r(g, { onError: c, children: /* @__PURE__ */ r(h, { children: a }) }) : /* @__PURE__ */ r("div", { className: "h-screen bg-gray-50 flex items-center justify-center", children: /* @__PURE__ */ l("div", { className: "text-center", children: [
34
+ }, []), i ? /* @__PURE__ */ r(E, { onError: c, children: /* @__PURE__ */ r(h, { children: a }) }) : /* @__PURE__ */ r("div", { className: "h-screen bg-gray-50 flex items-center justify-center", children: /* @__PURE__ */ l("div", { className: "text-center", children: [
35
35
  /* @__PURE__ */ r("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 mx-auto mb-4" }),
36
36
  /* @__PURE__ */ r("p", { className: "text-gray-600", children: "Loading..." })
37
37
  ] }) });
@@ -1 +1 @@
1
- {"version":3,"file":"MinisContainer.js","sources":["../../src/components/MinisContainer.tsx"],"sourcesContent":["import React, {useCallback, useEffect, useState} from 'react'\n\nimport {ReportErrorParams} from '@shopify/shop-minis-platform/actions'\n\nimport {useShopActions} from '../internal/useShopActions'\nimport {injectMocks} from '../mocks'\nimport {ImagePickerProvider} from '../providers/ImagePickerProvider'\n\nimport {ErrorBoundary} from './ErrorBoundary'\n\ninjectMocks()\n\nexport function MinisContainer({children}: {children: React.ReactNode}) {\n const [isSDKReady, setIsSDKReady] = useState(false)\n const {reportError} = useShopActions()\n\n const handleError = useCallback(\n async (params: ReportErrorParams) => {\n try {\n await reportError(params)\n } catch (error) {\n // If reporting fails, at least log to console\n console.error('Failed to report error to app:', error)\n }\n },\n [reportError]\n )\n\n useEffect(() => {\n // Function to check if SDK is ready\n const checkSDKReady = () => {\n if (window.minisSDK) {\n setIsSDKReady(true)\n return true\n }\n return false\n }\n\n // Check immediately\n if (checkSDKReady()) {\n return\n }\n\n // If not ready, set up a listener for the MINIS_SDK_READY event\n const handleSDKReady = (event: any) => {\n const {type} = JSON.parse(event.data)\n\n if (type === 'MINIS_SDK_READY') {\n setIsSDKReady(true)\n }\n }\n\n // Listen for the MINIS_SDK_READY event\n window.addEventListener('message', handleSDKReady)\n document.addEventListener('message', handleSDKReady)\n\n // Also poll for SDK availability as a fallback\n const pollInterval = setInterval(() => {\n if (checkSDKReady()) {\n clearInterval(pollInterval)\n }\n }, 100)\n\n // Cleanup\n return () => {\n clearInterval(pollInterval)\n window.removeEventListener('message', handleSDKReady)\n document.removeEventListener('message', handleSDKReady)\n }\n }, [])\n\n // Don't render anything until SDK is ready\n if (!isSDKReady) {\n return (\n <div className=\"h-screen bg-gray-50 flex items-center justify-center\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 mx-auto mb-4\" />\n <p className=\"text-gray-600\">Loading...</p>\n </div>\n </div>\n )\n }\n\n return (\n <ErrorBoundary onError={handleError}>\n <ImagePickerProvider>{children}</ImagePickerProvider>\n </ErrorBoundary>\n )\n}\n"],"names":["injectMocks","MinisContainer","children","isSDKReady","setIsSDKReady","useState","reportError","useShopActions","handleError","useCallback","params","error","useEffect","checkSDKReady","handleSDKReady","event","type","pollInterval","ErrorBoundary","jsx","ImagePickerProvider","jsxs"],"mappings":";;;;;;AAUAA,EAAY;AAEI,SAAAC,EAAe,EAAC,UAAAC,KAAwC;AACtE,QAAM,CAACC,GAAYC,CAAa,IAAIC,EAAS,EAAK,GAC5C,EAAC,aAAAC,EAAW,IAAIC,EAAe,GAE/BC,IAAcC;AAAA,IAClB,OAAOC,MAA8B;AAC/B,UAAA;AACF,cAAMJ,EAAYI,CAAM;AAAA,eACjBC,GAAO;AAEN,gBAAA,MAAM,kCAAkCA,CAAK;AAAA,MAAA;AAAA,IAEzD;AAAA,IACA,CAACL,CAAW;AAAA,EACd;AA8CA,SA5CAM,EAAU,MAAM;AAEd,UAAMC,IAAgB,MAChB,OAAO,YACTT,EAAc,EAAI,GACX,MAEF;AAIT,QAAIS;AACF;AAII,UAAAC,IAAiB,CAACC,MAAe;AACrC,YAAM,EAAC,MAAAC,EAAI,IAAI,KAAK,MAAMD,EAAM,IAAI;AAEpC,MAAIC,MAAS,qBACXZ,EAAc,EAAI;AAAA,IAEtB;AAGO,WAAA,iBAAiB,WAAWU,CAAc,GACxC,SAAA,iBAAiB,WAAWA,CAAc;AAG7C,UAAAG,IAAe,YAAY,MAAM;AACrC,MAAIJ,OACF,cAAcI,CAAY;AAAA,OAE3B,GAAG;AAGN,WAAO,MAAM;AACX,oBAAcA,CAAY,GACnB,OAAA,oBAAoB,WAAWH,CAAc,GAC3C,SAAA,oBAAoB,WAAWA,CAAc;AAAA,IACxD;AAAA,EACF,GAAG,EAAE,GAGAX,sBAYFe,GAAc,EAAA,SAASV,GACtB,UAAC,gBAAAW,EAAAC,GAAA,EAAqB,UAAAlB,GAAS,EACjC,CAAA,sBAZG,OAAI,EAAA,WAAU,wDACb,UAAC,gBAAAmB,EAAA,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,IAAC,gBAAAF,EAAA,OAAA,EAAI,WAAU,4EAA4E,CAAA;AAAA,IAC1F,gBAAAA,EAAA,KAAA,EAAE,WAAU,iBAAgB,UAAU,aAAA,CAAA;AAAA,EAAA,EAAA,CACzC,EACF,CAAA;AASN;"}
1
+ {"version":3,"file":"MinisContainer.js","sources":["../../src/components/MinisContainer.tsx"],"sourcesContent":["import React, {useCallback, useEffect, useState} from 'react'\n\nimport {ReportErrorParams} from '@shopify/shop-minis-platform/actions'\n\nimport {useShopActions} from '../internal/useShopActions'\nimport {injectMocks} from '../mocks'\nimport {ImagePickerProvider} from '../providers/ImagePickerProvider'\n\nimport {ErrorBoundary} from './ErrorBoundary'\n\ninjectMocks()\n\nexport function MinisContainer({children}: {children: React.ReactNode}) {\n const [isSDKReady, setIsSDKReady] = useState(false)\n const actions = useShopActions()\n\n const handleError = useCallback(\n async (params: ReportErrorParams) => {\n try {\n if (actions && actions.reportError) {\n await actions.reportError(params)\n }\n } catch (error) {\n // If reporting fails, at least log to console\n console.error('Failed to report error to app:', error)\n }\n },\n [actions]\n )\n\n useEffect(() => {\n // Function to check if SDK is ready\n const checkSDKReady = () => {\n if (window.minisSDK) {\n setIsSDKReady(true)\n return true\n }\n return false\n }\n\n // Check immediately\n if (checkSDKReady()) {\n return\n }\n\n // If not ready, set up a listener for the MINIS_SDK_READY event\n const handleSDKReady = (event: any) => {\n const {type} = JSON.parse(event.data)\n\n if (type === 'MINIS_SDK_READY') {\n setIsSDKReady(true)\n }\n }\n\n // Listen for the MINIS_SDK_READY event\n window.addEventListener('message', handleSDKReady)\n document.addEventListener('message', handleSDKReady)\n\n // Also poll for SDK availability as a fallback\n const pollInterval = setInterval(() => {\n if (checkSDKReady()) {\n clearInterval(pollInterval)\n }\n }, 100)\n\n // Cleanup\n return () => {\n clearInterval(pollInterval)\n window.removeEventListener('message', handleSDKReady)\n document.removeEventListener('message', handleSDKReady)\n }\n }, [])\n\n // Don't render anything until SDK is ready\n if (!isSDKReady) {\n return (\n <div className=\"h-screen bg-gray-50 flex items-center justify-center\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 mx-auto mb-4\" />\n <p className=\"text-gray-600\">Loading...</p>\n </div>\n </div>\n )\n }\n\n return (\n <ErrorBoundary onError={handleError}>\n <ImagePickerProvider>{children}</ImagePickerProvider>\n </ErrorBoundary>\n )\n}\n"],"names":["injectMocks","MinisContainer","children","isSDKReady","setIsSDKReady","useState","actions","useShopActions","handleError","useCallback","params","error","useEffect","checkSDKReady","handleSDKReady","event","type","pollInterval","ErrorBoundary","jsx","ImagePickerProvider","jsxs"],"mappings":";;;;;;AAUAA,EAAY;AAEI,SAAAC,EAAe,EAAC,UAAAC,KAAwC;AACtE,QAAM,CAACC,GAAYC,CAAa,IAAIC,EAAS,EAAK,GAC5CC,IAAUC,EAAe,GAEzBC,IAAcC;AAAA,IAClB,OAAOC,MAA8B;AAC/B,UAAA;AACE,QAAAJ,KAAWA,EAAQ,eACf,MAAAA,EAAQ,YAAYI,CAAM;AAAA,eAE3BC,GAAO;AAEN,gBAAA,MAAM,kCAAkCA,CAAK;AAAA,MAAA;AAAA,IAEzD;AAAA,IACA,CAACL,CAAO;AAAA,EACV;AA8CA,SA5CAM,EAAU,MAAM;AAEd,UAAMC,IAAgB,MAChB,OAAO,YACTT,EAAc,EAAI,GACX,MAEF;AAIT,QAAIS;AACF;AAII,UAAAC,IAAiB,CAACC,MAAe;AACrC,YAAM,EAAC,MAAAC,EAAI,IAAI,KAAK,MAAMD,EAAM,IAAI;AAEpC,MAAIC,MAAS,qBACXZ,EAAc,EAAI;AAAA,IAEtB;AAGO,WAAA,iBAAiB,WAAWU,CAAc,GACxC,SAAA,iBAAiB,WAAWA,CAAc;AAG7C,UAAAG,IAAe,YAAY,MAAM;AACrC,MAAIJ,OACF,cAAcI,CAAY;AAAA,OAE3B,GAAG;AAGN,WAAO,MAAM;AACX,oBAAcA,CAAY,GACnB,OAAA,oBAAoB,WAAWH,CAAc,GAC3C,SAAA,oBAAoB,WAAWA,CAAc;AAAA,IACxD;AAAA,EACF,GAAG,EAAE,GAGAX,sBAYFe,GAAc,EAAA,SAASV,GACtB,UAAC,gBAAAW,EAAAC,GAAA,EAAqB,UAAAlB,GAAS,EACjC,CAAA,sBAZG,OAAI,EAAA,WAAU,wDACb,UAAC,gBAAAmB,EAAA,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,IAAC,gBAAAF,EAAA,OAAA,EAAI,WAAU,4EAA4E,CAAA;AAAA,IAC1F,gBAAAA,EAAA,KAAA,EAAE,WAAU,iBAAgB,UAAU,aAAA,CAAA;AAAA,EAAA,EAAA,CACzC,EACF,CAAA;AASN;"}
@@ -1,61 +1,54 @@
1
- import { jsx as n, jsxs as d, Fragment as c } from "react/jsx-runtime";
1
+ import { jsx as n, jsxs as h, Fragment as d } from "react/jsx-runtime";
2
2
  import { formatMoney as a } from "../../lib/formatMoney.js";
3
3
  import { cn as i } from "../../lib/utils.js";
4
- function b({
4
+ function N({
5
5
  amount: r,
6
6
  currencyCode: t,
7
7
  compareAtPriceAmount: s,
8
8
  compareAtPriceCurrencyCode: o,
9
9
  currentPriceClassName: e,
10
10
  originalPriceClassName: m,
11
- containerClassName: x,
12
- className: f
11
+ className: x
13
12
  }) {
14
13
  if (!r || !t)
15
14
  return null;
16
- const g = s && s !== r, l = String(r), h = s ? String(s) : void 0;
17
- return /* @__PURE__ */ n(
18
- "div",
19
- {
20
- className: i("flex items-center gap-2", x, f),
21
- children: g ? /* @__PURE__ */ d(c, { children: [
22
- /* @__PURE__ */ n(
23
- "span",
24
- {
25
- className: i(
26
- "text-sm font-semibold text-gray-900",
27
- e
28
- ),
29
- children: a(l, t)
30
- }
15
+ const f = s && s !== r, l = String(r), g = s ? String(s) : void 0;
16
+ return /* @__PURE__ */ n("div", { className: i("flex items-center gap-2", x), children: f ? /* @__PURE__ */ h(d, { children: [
17
+ /* @__PURE__ */ n(
18
+ "span",
19
+ {
20
+ className: i(
21
+ "text-sm font-semibold text-gray-900",
22
+ e
23
+ ),
24
+ children: a(l, t)
25
+ }
26
+ ),
27
+ /* @__PURE__ */ n(
28
+ "span",
29
+ {
30
+ className: i(
31
+ "text-sm text-gray-500 line-through",
32
+ m
31
33
  ),
32
- /* @__PURE__ */ n(
33
- "span",
34
- {
35
- className: i(
36
- "text-sm text-gray-500 line-through",
37
- m
38
- ),
39
- children: a(
40
- h,
41
- o || t
42
- )
43
- }
34
+ children: a(
35
+ g,
36
+ o || t
44
37
  )
45
- ] }) : /* @__PURE__ */ n(
46
- "span",
47
- {
48
- className: i(
49
- "text-sm font-semibold text-gray-900",
50
- e
51
- ),
52
- children: a(l, t)
53
- }
54
- )
38
+ }
39
+ )
40
+ ] }) : /* @__PURE__ */ n(
41
+ "span",
42
+ {
43
+ className: i(
44
+ "text-sm font-semibold text-gray-900",
45
+ e
46
+ ),
47
+ children: a(l, t)
55
48
  }
56
- );
49
+ ) });
57
50
  }
58
51
  export {
59
- b as ProductVariantPrice
52
+ N as ProductVariantPrice
60
53
  };
61
54
  //# sourceMappingURL=product-variant-price.js.map
@@ -1 +1 @@
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 containerClassName?: string\n className?: string\n}\n\nexport function ProductVariantPrice({\n amount,\n currencyCode,\n compareAtPriceAmount,\n compareAtPriceCurrencyCode,\n currentPriceClassName,\n originalPriceClassName,\n containerClassName,\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\n className={cn('flex items-center gap-2', containerClassName, className)}\n >\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","containerClassName","className","hasDiscount","amountStr","compareAtPriceAmountStr","jsx","cn","jsxs","Fragment","formatMoney"],"mappings":";;;AAcO,SAASA,EAAoB;AAAA,EAClC,QAAAC;AAAA,EACA,cAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,4BAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,WAAAC;AACF,GAA6B;AACvB,MAAA,CAACP,KAAU,CAACC;AACP,WAAA;AAGH,QAAAO,IAAcN,KAAwBA,MAAyBF,GAE/DS,IAAY,OAAOT,CAAM,GACzBU,IAA0BR,IAC5B,OAAOA,CAAoB,IAC3B;AAGF,SAAA,gBAAAS;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,EAAG,2BAA2BN,GAAoBC,CAAS;AAAA,MAErE,cAEG,gBAAAM,EAAAC,GAAA,EAAA,UAAA;AAAA,QAAA,gBAAAH;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWC;AAAA,cACT;AAAA,cACAR;AAAA,YACF;AAAA,YAEC,UAAAW,EAAYN,GAAWR,CAAY;AAAA,UAAA;AAAA,QACtC;AAAA,QACA,gBAAAU;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWC;AAAA,cACT;AAAA,cACAP;AAAA,YACF;AAAA,YAEC,UAAAU;AAAA,cACCL;AAAA,cACAP,KAA8BF;AAAA,YAAA;AAAA,UAChC;AAAA,QAAA;AAAA,MACF,EAAA,CACF,IAEA,gBAAAU;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAWC;AAAA,YACT;AAAA,YACAR;AAAA,UACF;AAAA,UAEC,UAAAW,EAAYN,GAAWR,CAAY;AAAA,QAAA;AAAA,MAAA;AAAA,IACtC;AAAA,EAEJ;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;"}
@@ -1,62 +1,79 @@
1
- import { jsx as r, jsxs as A } from "react/jsx-runtime";
2
- import * as m from "react";
3
- import { useState as T, useCallback as v } from "react";
4
- import { cn as f } from "../../lib/utils.js";
5
- import { Button as x } from "../atoms/button.js";
6
- import { useShopCartActions as C } from "../../hooks/shop/useShopCartActions.js";
7
- import { useErrorToast as y } from "../../hooks/util/useErrorToast.js";
8
- import { AnimatePresence as N } from "../../shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/index.js";
9
- import { motion as k } from "../../shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/render/components/motion/proxy.js";
10
- import w from "../../shop-minis-react/node_modules/.pnpm/lucide-react@0.513.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/check.js";
11
- function P({
12
- disabled: o = !1,
13
- className: u,
14
- size: d = "default",
15
- productId: a,
16
- productVariantId: i,
17
- discountCodes: n
1
+ import { jsx as o, jsxs as g } from "react/jsx-runtime";
2
+ import * as p from "react";
3
+ import { useState as w, useCallback as y } from "react";
4
+ import { useShopCartActions as k } from "../../internal/useShopCartActions.js";
5
+ import { cn as h } from "../../lib/utils.js";
6
+ import { Button as j } from "../atoms/button.js";
7
+ import { useShopNavigation as E } from "../../hooks/navigation/useShopNavigation.js";
8
+ import { useErrorToast as R } from "../../hooks/util/useErrorToast.js";
9
+ import { AnimatePresence as S } from "../../shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/index.js";
10
+ import { motion as B } from "../../shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/render/components/motion/proxy.js";
11
+ import F from "../../shop-minis-react/node_modules/.pnpm/lucide-react@0.513.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/check.js";
12
+ function L({
13
+ disabled: i = !1,
14
+ className: T,
15
+ size: v = "default",
16
+ productVariantId: a,
17
+ discountCodes: l,
18
+ product: x
18
19
  }) {
19
- const { addToCart: c } = C(), [t, s] = T(!1), e = m.useRef(void 0), { showErrorToast: l } = y(), h = v(async () => {
20
- if (!(t || o))
21
- try {
22
- a && i && c({
23
- productId: a,
24
- productVariantId: i,
25
- quantity: 1,
26
- discountCodes: n
27
- }).then(() => {
28
- }).catch(() => {
29
- l({ message: "Failed to add to cart" });
30
- }), s(!0), e.current && clearTimeout(e.current), e.current = window.setTimeout(() => {
31
- s(!1);
32
- }, 2e3);
33
- } catch (p) {
34
- s(!1), console.error("Failed to add to cart:", p);
20
+ const { addToCart: d } = k(), { navigateToProduct: m } = E(), [t, n] = w(!1), e = p.useRef(void 0), { id: r, referral: s, variants: C } = x ?? {}, u = C?.find(
21
+ (c) => c.id === a
22
+ )?.image?.url, { showErrorToast: f } = R(), A = y(async () => {
23
+ if (!i) {
24
+ if (r && s) {
25
+ m({
26
+ productId: r
27
+ });
28
+ return;
35
29
  }
30
+ if (!t)
31
+ try {
32
+ r && a && d({
33
+ productId: r,
34
+ productVariantId: a,
35
+ quantity: 1,
36
+ discountCodes: l,
37
+ variantImageUrl: u
38
+ }).then(() => {
39
+ }).catch(() => {
40
+ f({ message: "Failed to add to cart" });
41
+ }), n(!0), e.current && clearTimeout(e.current), e.current = window.setTimeout(() => {
42
+ n(!1);
43
+ }, 2e3);
44
+ } catch (c) {
45
+ n(!1), console.error("Failed to add to cart:", c);
46
+ }
47
+ }
36
48
  }, [
49
+ i,
50
+ r,
51
+ s,
37
52
  t,
38
- o,
39
- c,
53
+ m,
40
54
  a,
41
- i,
42
- n,
43
- l
55
+ d,
56
+ l,
57
+ u,
58
+ f
44
59
  ]);
45
- return m.useEffect(() => () => {
60
+ p.useEffect(() => () => {
46
61
  e.current && clearTimeout(e.current);
47
- }, []), /* @__PURE__ */ r(
48
- x,
62
+ }, []);
63
+ const N = s ? "View product" : t ? "Added to cart" : "Add to cart";
64
+ return /* @__PURE__ */ o(
65
+ j,
49
66
  {
50
- onClick: h,
51
- disabled: o,
52
- className: f(
67
+ onClick: A,
68
+ disabled: i,
69
+ className: h(
53
70
  "relative overflow-hidden transition-all duration-300",
54
- u
71
+ T
55
72
  ),
56
- size: d,
57
- children: /* @__PURE__ */ A("div", { className: "relative flex items-center justify-center", children: [
58
- /* @__PURE__ */ r(N, { children: t && /* @__PURE__ */ r(
59
- k.div,
73
+ size: v,
74
+ children: /* @__PURE__ */ g("div", { className: "relative flex items-center justify-center", children: [
75
+ /* @__PURE__ */ o(S, { children: t && /* @__PURE__ */ o(
76
+ B.div,
60
77
  {
61
78
  initial: { scale: 0, rotate: -180 },
62
79
  animate: { scale: 1, rotate: 0 },
@@ -66,17 +83,17 @@ function P({
66
83
  ease: [0.175, 0.885, 0.32, 1.275]
67
84
  // bounce effect
68
85
  },
69
- className: "absolute left-0",
86
+ className: "absolute left-2",
70
87
  style: { x: -8 },
71
- children: /* @__PURE__ */ r(w, { className: "size-4" })
88
+ children: /* @__PURE__ */ o(F, { className: "size-4" })
72
89
  }
73
90
  ) }),
74
- /* @__PURE__ */ r("span", { className: f(t && "pl-5", "transition-all duration-300"), children: t ? "Added to cart" : "Add to cart" })
91
+ /* @__PURE__ */ o("span", { className: h(t && "pl-5", "transition-all duration-300"), children: N })
75
92
  ] })
76
93
  }
77
94
  );
78
95
  }
79
96
  export {
80
- P as AddToCartButton
97
+ L as AddToCartButton
81
98
  };
82
99
  //# sourceMappingURL=add-to-cart.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"add-to-cart.js","sources":["../../../src/components/commerce/add-to-cart.tsx"],"sourcesContent":["import * as React from 'react'\nimport {useState, useCallback} from 'react'\n\nimport {CheckIcon} from 'lucide-react'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopCartActions} from '../../hooks'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\ninterface AddToCartButtonProps {\n disabled?: boolean\n className?: string\n size?: 'default' | 'sm' | 'lg'\n /**\n * The discount codes to apply to the cart.\n */\n discountCodes?: string[]\n /**\n * The GID of the product. E.g. `gid://shopify/Product/123`.\n */\n productId: string\n /**\n * The GID of the product variant. E.g. `gid://shopify/ProductVariant/456`.\n */\n productVariantId: string\n}\n\nexport function AddToCartButton({\n disabled = false,\n className,\n size = 'default',\n productId,\n productVariantId,\n discountCodes,\n}: AddToCartButtonProps) {\n const {addToCart} = useShopCartActions()\n const [isAdded, setIsAdded] = useState(false)\n const timeoutRef = React.useRef<number | undefined>(undefined)\n\n const {showErrorToast} = useErrorToast()\n\n const handleClick = useCallback(async () => {\n if (isAdded || disabled) return\n\n try {\n // Call the callback if provided\n if (productId && productVariantId) {\n // Optimistic update with error toast\n addToCart({\n productId,\n productVariantId,\n quantity: 1,\n discountCodes,\n })\n .then(() => {})\n .catch(() => {\n showErrorToast({message: 'Failed to add to cart'})\n })\n }\n\n // Show success state\n setIsAdded(true)\n\n // Clear any existing timeout\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n\n // Reset to initial state after delay\n timeoutRef.current = window.setTimeout(() => {\n setIsAdded(false)\n }, 2000)\n } catch (error) {\n // Handle error - reset to initial state\n setIsAdded(false)\n console.error('Failed to add to cart:', error)\n }\n }, [\n isAdded,\n disabled,\n addToCart,\n productId,\n productVariantId,\n discountCodes,\n showErrorToast,\n ])\n\n // Cleanup timeout on unmount\n React.useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n }\n }, [])\n\n return (\n <Button\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'relative overflow-hidden transition-all duration-300',\n className\n )}\n size={size}\n >\n <div className=\"relative flex items-center justify-center\">\n <AnimatePresence>\n {isAdded && (\n <motion.div\n initial={{scale: 0, rotate: -180}}\n animate={{scale: 1, rotate: 0}}\n exit={{scale: 0, rotate: 180}}\n transition={{\n duration: 0.4,\n ease: [0.175, 0.885, 0.32, 1.275], // bounce effect\n }}\n className=\"absolute left-0\"\n style={{x: -8}}\n >\n <CheckIcon className=\"size-4\" />\n </motion.div>\n )}\n </AnimatePresence>\n <span className={cn(isAdded && 'pl-5', 'transition-all duration-300')}>\n {isAdded ? 'Added to cart' : 'Add to cart'}\n </span>\n </div>\n </Button>\n )\n}\n"],"names":["AddToCartButton","disabled","className","size","productId","productVariantId","discountCodes","addToCart","useShopCartActions","isAdded","setIsAdded","useState","timeoutRef","React","showErrorToast","useErrorToast","handleClick","useCallback","error","jsx","Button","cn","jsxs","AnimatePresence","motion","CheckIcon"],"mappings":";;;;;;;;;;AA4BO,SAASA,EAAgB;AAAA,EAC9B,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,WAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,eAAAC;AACF,GAAyB;AACjB,QAAA,EAAC,WAAAC,EAAS,IAAIC,EAAmB,GACjC,CAACC,GAASC,CAAU,IAAIC,EAAS,EAAK,GACtCC,IAAaC,EAAM,OAA2B,MAAS,GAEvD,EAAC,gBAAAC,EAAc,IAAIC,EAAc,GAEjCC,IAAcC,EAAY,YAAY;AAC1C,QAAI,EAAAR,KAAWR;AAEX,UAAA;AAEF,QAAIG,KAAaC,KAELE,EAAA;AAAA,UACR,WAAAH;AAAA,UACA,kBAAAC;AAAA,UACA,UAAU;AAAA,UACV,eAAAC;AAAA,QAAA,CACD,EACE,KAAK,MAAM;AAAA,QAAA,CAAE,EACb,MAAM,MAAM;AACI,UAAAQ,EAAA,EAAC,SAAS,yBAAwB;AAAA,QAAA,CAClD,GAILJ,EAAW,EAAI,GAGXE,EAAW,WACb,aAAaA,EAAW,OAAO,GAItBA,EAAA,UAAU,OAAO,WAAW,MAAM;AAC3C,UAAAF,EAAW,EAAK;AAAA,WACf,GAAI;AAAA,eACAQ,GAAO;AAEd,QAAAR,EAAW,EAAK,GACR,QAAA,MAAM,0BAA0BQ,CAAK;AAAA,MAAA;AAAA,EAC/C,GACC;AAAA,IACDT;AAAA,IACAR;AAAA,IACAM;AAAA,IACAH;AAAA,IACAC;AAAA,IACAC;AAAA,IACAQ;AAAA,EAAA,CACD;AAGD,SAAAD,EAAM,UAAU,MACP,MAAM;AACX,IAAID,EAAW,WACb,aAAaA,EAAW,OAAO;AAAA,EAEnC,GACC,EAAE,GAGH,gBAAAO;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAASJ;AAAA,MACT,UAAAf;AAAA,MACA,WAAWoB;AAAA,QACT;AAAA,QACAnB;AAAA,MACF;AAAA,MACA,MAAAC;AAAA,MAEA,UAAA,gBAAAmB,EAAC,OAAI,EAAA,WAAU,6CACb,UAAA;AAAA,QAAA,gBAAAH,EAACI,KACE,UACCd,KAAA,gBAAAU;AAAA,UAACK,EAAO;AAAA,UAAP;AAAA,YACC,SAAS,EAAC,OAAO,GAAG,QAAQ,KAAI;AAAA,YAChC,SAAS,EAAC,OAAO,GAAG,QAAQ,EAAC;AAAA,YAC7B,MAAM,EAAC,OAAO,GAAG,QAAQ,IAAG;AAAA,YAC5B,YAAY;AAAA,cACV,UAAU;AAAA,cACV,MAAM,CAAC,OAAO,OAAO,MAAM,KAAK;AAAA;AAAA,YAClC;AAAA,YACA,WAAU;AAAA,YACV,OAAO,EAAC,GAAG,GAAE;AAAA,YAEb,UAAA,gBAAAL,EAACM,GAAU,EAAA,WAAU,SAAS,CAAA;AAAA,UAAA;AAAA,QAAA,GAGpC;AAAA,QACA,gBAAAN,EAAC,QAAK,EAAA,WAAWE,EAAGZ,KAAW,QAAQ,6BAA6B,GACjE,UAAUA,IAAA,kBAAkB,cAC/B,CAAA;AAAA,MAAA,EACF,CAAA;AAAA,IAAA;AAAA,EACF;AAEJ;"}
1
+ {"version":3,"file":"add-to-cart.js","sources":["../../../src/components/commerce/add-to-cart.tsx"],"sourcesContent":["import * as React from 'react'\nimport {useState, useCallback} from 'react'\n\nimport {Product} from '@shopify/shop-minis-platform'\nimport {CheckIcon} from 'lucide-react'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopNavigation} from '../../hooks'\nimport {useShopCartActions} from '../../internal/useShopCartActions'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\ninterface AddToCartButtonProps {\n disabled?: boolean\n className?: string\n size?: 'default' | 'sm' | 'lg'\n /**\n * The discount codes to apply to the cart.\n */\n discountCodes?: string[]\n /**\n * The GID of the product variant. E.g. `gid://shopify/ProductVariant/456`.\n */\n productVariantId: string\n\n /**\n * The product to add to the cart.\n */\n product?: Product\n}\n\nexport function AddToCartButton({\n disabled = false,\n className,\n size = 'default',\n productVariantId,\n discountCodes,\n product,\n}: AddToCartButtonProps) {\n const {addToCart} = useShopCartActions()\n const {navigateToProduct} = useShopNavigation()\n const [isAdded, setIsAdded] = useState(false)\n const timeoutRef = React.useRef<number | undefined>(undefined)\n const {id, referral, variants} = product ?? {}\n\n const variantImageUrl = variants?.find(\n variant => variant.id === productVariantId\n )?.image?.url\n\n const {showErrorToast} = useErrorToast()\n\n const handleClick = useCallback(async () => {\n if (disabled) return\n\n if (id && referral) {\n navigateToProduct({\n productId: id,\n })\n\n return\n }\n\n if (isAdded) return\n\n try {\n if (id && productVariantId) {\n addToCart({\n productId: id,\n productVariantId,\n quantity: 1,\n discountCodes,\n variantImageUrl,\n })\n .then(() => {})\n .catch(() => {\n showErrorToast({message: 'Failed to add to cart'})\n })\n }\n\n // Show success state\n setIsAdded(true)\n\n // Clear any existing timeout\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n\n // Reset to initial state after delay\n timeoutRef.current = window.setTimeout(() => {\n setIsAdded(false)\n }, 2000)\n } catch (error) {\n // Handle error - reset to initial state\n setIsAdded(false)\n console.error('Failed to add to cart:', error)\n }\n }, [\n disabled,\n id,\n referral,\n isAdded,\n navigateToProduct,\n productVariantId,\n addToCart,\n discountCodes,\n variantImageUrl,\n showErrorToast,\n ])\n\n // Cleanup timeout on unmount\n React.useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n }\n }\n }, [])\n\n const addToCartText = isAdded ? 'Added to cart' : 'Add to cart'\n const buttonText = referral ? 'View product' : addToCartText\n\n return (\n <Button\n onClick={handleClick}\n disabled={disabled}\n className={cn(\n 'relative overflow-hidden transition-all duration-300',\n className\n )}\n size={size}\n >\n <div className=\"relative flex items-center justify-center\">\n <AnimatePresence>\n {isAdded && (\n <motion.div\n initial={{scale: 0, rotate: -180}}\n animate={{scale: 1, rotate: 0}}\n exit={{scale: 0, rotate: 180}}\n transition={{\n duration: 0.4,\n ease: [0.175, 0.885, 0.32, 1.275], // bounce effect\n }}\n className=\"absolute left-2\"\n style={{x: -8}}\n >\n <CheckIcon className=\"size-4\" />\n </motion.div>\n )}\n </AnimatePresence>\n <span className={cn(isAdded && 'pl-5', 'transition-all duration-300')}>\n {buttonText}\n </span>\n </div>\n </Button>\n )\n}\n"],"names":["AddToCartButton","disabled","className","size","productVariantId","discountCodes","product","addToCart","useShopCartActions","navigateToProduct","useShopNavigation","isAdded","setIsAdded","useState","timeoutRef","React","id","referral","variants","variantImageUrl","variant","showErrorToast","useErrorToast","handleClick","useCallback","error","buttonText","jsx","Button","cn","jsxs","AnimatePresence","motion","CheckIcon"],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { jsx as n } from "react/jsx-runtime";
2
+ import { useState as h, useCallback as d } from "react";
3
+ import { useShopCartActions as w } from "../../internal/useShopCartActions.js";
4
+ import { cn as g } from "../../lib/utils.js";
5
+ import { Button as v } from "../atoms/button.js";
6
+ import { AnimatePresence as P } from "../../shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/index.js";
7
+ import { motion as x } from "../../shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/render/components/motion/proxy.js";
8
+ import { useShopNavigation as B } from "../../hooks/navigation/useShopNavigation.js";
9
+ import { useErrorToast as k } from "../../hooks/util/useErrorToast.js";
10
+ function I({
11
+ disabled: r = !1,
12
+ className: f,
13
+ size: l = "default",
14
+ productVariantId: i,
15
+ discountCode: s,
16
+ product: p
17
+ }) {
18
+ const { buyProduct: c } = w(), { navigateToProduct: m } = B(), [o, e] = h(!1), { id: t, referral: a } = p ?? {}, { showErrorToast: u } = k(), y = d(async () => {
19
+ if (!r) {
20
+ if (t && a) {
21
+ m({
22
+ productId: t
23
+ });
24
+ return;
25
+ }
26
+ if (!o)
27
+ try {
28
+ t && i && (e(!0), await c({
29
+ productId: t,
30
+ productVariantId: i,
31
+ quantity: 1,
32
+ discountCode: s
33
+ }), e(!1));
34
+ } catch {
35
+ u({ message: "Failed to complete purchase" }), e(!1);
36
+ }
37
+ }
38
+ }, [
39
+ r,
40
+ t,
41
+ a,
42
+ o,
43
+ m,
44
+ i,
45
+ c,
46
+ s,
47
+ u
48
+ ]);
49
+ return /* @__PURE__ */ n(
50
+ v,
51
+ {
52
+ onClick: y,
53
+ disabled: r || o,
54
+ className: g("relative overflow-hidden", f),
55
+ size: l,
56
+ "aria-live": "polite",
57
+ "aria-busy": o,
58
+ children: /* @__PURE__ */ n(P, { mode: "wait", children: /* @__PURE__ */ n(
59
+ x.span,
60
+ {
61
+ initial: { opacity: 0, y: 10 },
62
+ animate: { opacity: 1, y: 0 },
63
+ exit: { opacity: 0, y: -10 },
64
+ transition: { duration: 0.2 },
65
+ children: a ? "View product" : "Buy now"
66
+ },
67
+ "text"
68
+ ) })
69
+ }
70
+ );
71
+ }
72
+ export {
73
+ I as BuyNowButton
74
+ };
75
+ //# sourceMappingURL=buy-now.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buy-now.js","sources":["../../../src/components/commerce/buy-now.tsx"],"sourcesContent":["import {useState, useCallback} from 'react'\n\nimport {Product} from '@shopify/shop-minis-platform'\nimport {motion, AnimatePresence} from 'motion/react'\n\nimport {useErrorToast, useShopNavigation} from '../../hooks'\nimport {useShopCartActions} from '../../internal/useShopCartActions'\nimport {cn} from '../../lib/utils'\nimport {Button} from '../atoms/button'\n\ninterface BuyNowButtonProps {\n disabled?: boolean\n className?: string\n size?: 'default' | 'sm' | 'lg'\n /**\n * The discount code to apply to the purchase.\n */\n discountCode?: string\n /**\n * The GID of the product variant. E.g. `gid://shopify/ProductVariant/456`.\n */\n productVariantId: string\n /**\n * The product to buy now.\n */\n product?: Product\n}\n\nexport function BuyNowButton({\n disabled = false,\n className,\n size = 'default',\n productVariantId,\n discountCode,\n product,\n}: BuyNowButtonProps) {\n const {buyProduct} = useShopCartActions()\n const {navigateToProduct} = useShopNavigation()\n const [isPurchasing, setIsPurchasing] = useState(false)\n const {id, referral} = product ?? {}\n\n const {showErrorToast} = useErrorToast()\n\n const handleClick = useCallback(async () => {\n if (disabled) return\n\n if (id && referral) {\n navigateToProduct({\n productId: id,\n })\n\n return\n }\n\n if (isPurchasing) return\n\n try {\n if (id && productVariantId) {\n setIsPurchasing(true)\n\n await buyProduct({\n productId: id,\n productVariantId,\n quantity: 1,\n discountCode,\n })\n\n setIsPurchasing(false)\n }\n } catch (error) {\n showErrorToast({message: 'Failed to complete purchase'})\n setIsPurchasing(false)\n }\n }, [\n disabled,\n id,\n referral,\n isPurchasing,\n navigateToProduct,\n productVariantId,\n buyProduct,\n discountCode,\n showErrorToast,\n ])\n\n return (\n <Button\n onClick={handleClick}\n disabled={disabled || isPurchasing}\n className={cn('relative overflow-hidden', className)}\n size={size}\n aria-live=\"polite\"\n aria-busy={isPurchasing}\n >\n <AnimatePresence mode=\"wait\">\n <motion.span\n key=\"text\"\n initial={{opacity: 0, y: 10}}\n animate={{opacity: 1, y: 0}}\n exit={{opacity: 0, y: -10}}\n transition={{duration: 0.2}}\n >\n {referral ? 'View product' : 'Buy now'}\n </motion.span>\n </AnimatePresence>\n </Button>\n )\n}\n"],"names":["BuyNowButton","disabled","className","size","productVariantId","discountCode","product","buyProduct","useShopCartActions","navigateToProduct","useShopNavigation","isPurchasing","setIsPurchasing","useState","id","referral","showErrorToast","useErrorToast","handleClick","useCallback","jsx","Button","cn","AnimatePresence","motion"],"mappings":";;;;;;;;;AA4BO,SAASA,EAAa;AAAA,EAC3B,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,kBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,SAAAC;AACF,GAAsB;AACd,QAAA,EAAC,YAAAC,EAAU,IAAIC,EAAmB,GAClC,EAAC,mBAAAC,EAAiB,IAAIC,EAAkB,GACxC,CAACC,GAAcC,CAAe,IAAIC,EAAS,EAAK,GAChD,EAAC,IAAAC,GAAI,UAAAC,EAAQ,IAAIT,KAAW,CAAC,GAE7B,EAAC,gBAAAU,EAAc,IAAIC,EAAc,GAEjCC,IAAcC,EAAY,YAAY;AAC1C,QAAI,CAAAlB,GAEJ;AAAA,UAAIa,KAAMC,GAAU;AACA,QAAAN,EAAA;AAAA,UAChB,WAAWK;AAAA,QAAA,CACZ;AAED;AAAA,MAAA;AAGF,UAAI,CAAAH;AAEA,YAAA;AACF,UAAIG,KAAMV,MACRQ,EAAgB,EAAI,GAEpB,MAAML,EAAW;AAAA,YACf,WAAWO;AAAA,YACX,kBAAAV;AAAA,YACA,UAAU;AAAA,YACV,cAAAC;AAAA,UAAA,CACD,GAEDO,EAAgB,EAAK;AAAA,gBAET;AACC,UAAAI,EAAA,EAAC,SAAS,+BAA8B,GACvDJ,EAAgB,EAAK;AAAA,QAAA;AAAA;AAAA,EACvB,GACC;AAAA,IACDX;AAAA,IACAa;AAAA,IACAC;AAAA,IACAJ;AAAA,IACAF;AAAA,IACAL;AAAA,IACAG;AAAA,IACAF;AAAA,IACAW;AAAA,EAAA,CACD;AAGC,SAAA,gBAAAI;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAASH;AAAA,MACT,UAAUjB,KAAYU;AAAA,MACtB,WAAWW,EAAG,4BAA4BpB,CAAS;AAAA,MACnD,MAAAC;AAAA,MACA,aAAU;AAAA,MACV,aAAWQ;AAAA,MAEX,UAAA,gBAAAS,EAACG,GAAgB,EAAA,MAAK,QACpB,UAAA,gBAAAH;AAAA,QAACI,EAAO;AAAA,QAAP;AAAA,UAEC,SAAS,EAAC,SAAS,GAAG,GAAG,GAAE;AAAA,UAC3B,SAAS,EAAC,SAAS,GAAG,GAAG,EAAC;AAAA,UAC1B,MAAM,EAAC,SAAS,GAAG,GAAG,IAAG;AAAA,UACzB,YAAY,EAAC,UAAU,IAAG;AAAA,UAEzB,cAAW,iBAAiB;AAAA,QAAA;AAAA,QANzB;AAAA,MAAA,EAQR,CAAA;AAAA,IAAA;AAAA,EACF;AAEJ;"}
@@ -1,18 +1,18 @@
1
1
  import { jsx as o, jsxs as v } from "react/jsx-runtime";
2
- import * as F from "react";
3
- import { useState as A, useCallback as C, useMemo as k, useContext as B } from "react";
4
- import { useShopNavigation as V } from "../../hooks/navigation/useShopNavigation.js";
5
- import { useSavedProductsActions as j } from "../../hooks/user/useSavedProductsActions.js";
6
- import { formatMoney as z } from "../../lib/formatMoney.js";
2
+ import * as N from "react";
3
+ import { useState as A, useCallback as C, useMemo as k, useContext as z } from "react";
4
+ import { useShopNavigation as B } from "../../hooks/navigation/useShopNavigation.js";
5
+ import { useSavedProductsActions as V } from "../../hooks/user/useSavedProductsActions.js";
6
+ import { formatMoney as j } from "../../lib/formatMoney.js";
7
7
  import { cn as s } from "../../lib/utils.js";
8
8
  import { Image as T } from "../atoms/image.js";
9
9
  import { ProductVariantPrice as E } from "../atoms/product-variant-price.js";
10
10
  import { Touchable as O } from "../atoms/touchable.js";
11
11
  import { Badge as S } from "../ui/badge.js";
12
12
  import { FavoriteButton as L } from "./favorite-button.js";
13
- const b = F.createContext(void 0);
13
+ const b = N.createContext(void 0);
14
14
  function u() {
15
- const t = B(b);
15
+ const t = z(b);
16
16
  if (!t)
17
17
  throw new Error(
18
18
  "ProductCard components must be used within a ProductCard provider"
@@ -27,7 +27,7 @@ function M({
27
27
  "div",
28
28
  {
29
29
  className: s(
30
- "relative w-full overflow-hidden rounded-xl border-0",
30
+ "relative size-full overflow-hidden rounded-xl border-0",
31
31
  t
32
32
  ),
33
33
  ...e
@@ -55,10 +55,8 @@ function R({
55
55
  {
56
56
  "data-slot": "product-card-image-container",
57
57
  className: s(
58
- // Ensure the product image is stretched to the full size of the container (can't use width/height: 100% because of flex)
59
- "flex justify-stretch items-stretch",
60
58
  "relative overflow-hidden rounded-xl border border-gray-200",
61
- "w-full aspect-square",
59
+ "aspect-square",
62
60
  r === "compact" ? "min-h-[104px]" : "min-h-[134px]",
63
61
  t
64
62
  ),
@@ -76,7 +74,8 @@ function q({ className: t, ...e }) {
76
74
  alt: d,
77
75
  aspectRatio: 1,
78
76
  thumbhash: c,
79
- className: s("size-full object-cover", t),
77
+ objectFit: "cover",
78
+ className: s("size-full", t),
80
79
  ...e
81
80
  }
82
81
  ) : /* @__PURE__ */ o(
@@ -85,7 +84,7 @@ function q({ className: t, ...e }) {
85
84
  "data-slot": "product-card-image",
86
85
  src: l,
87
86
  alt: d,
88
- className: s("size-full", t),
87
+ className: s("size-full object-cover", t),
89
88
  ...e
90
89
  }
91
90
  ),
@@ -179,7 +178,7 @@ function K() {
179
178
  const { product: t, selectedProductVariant: e, variant: r } = u();
180
179
  if (r !== "priceOverlay") return null;
181
180
  const a = e?.price || t.price, n = a?.currencyCode, i = a?.amount;
182
- return !n || !i ? null : /* @__PURE__ */ o(w, { position: "top-left", children: z(i, n) });
181
+ return !n || !i ? null : /* @__PURE__ */ o(w, { position: "top-left", children: j(i, n) });
183
182
  }
184
183
  function at({
185
184
  product: t,
@@ -193,7 +192,7 @@ function at({
193
192
  children: p,
194
193
  favoriteButtonDisabled: l = !1
195
194
  }) {
196
- const { navigateToProduct: h } = V(), { saveProduct: g, unsaveProduct: P } = j(), [f, y] = A(t.isFavorited), x = C(() => {
195
+ const { navigateToProduct: h } = B(), { saveProduct: g, unsaveProduct: P } = V(), [f, y] = A(t.isFavorited), x = C(() => {
197
196
  a && (d?.(), h({
198
197
  productId: t.id
199
198
  }));
@@ -222,7 +221,7 @@ function at({
222
221
  g,
223
222
  P,
224
223
  c
225
- ]), N = k(
224
+ ]), F = k(
226
225
  () => ({
227
226
  // Core data
228
227
  product: t,
@@ -252,7 +251,7 @@ function at({
252
251
  l
253
252
  ]
254
253
  );
255
- return /* @__PURE__ */ o(b.Provider, { value: N, children: p ?? /* @__PURE__ */ v(M, { children: [
254
+ return /* @__PURE__ */ o(b.Provider, { value: F, children: p ?? /* @__PURE__ */ v(M, { children: [
256
255
  /* @__PURE__ */ v(R, { children: [
257
256
  /* @__PURE__ */ o(q, {}),
258
257
  r === "priceOverlay" && /* @__PURE__ */ o(K, {}),