@shopify/shop-minis-react 0.2.3 → 0.2.6
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/_virtual/index10.js +2 -2
- package/dist/_virtual/index4.js +2 -3
- package/dist/_virtual/index4.js.map +1 -1
- package/dist/_virtual/index7.js +3 -2
- package/dist/_virtual/index7.js.map +1 -1
- package/dist/_virtual/index9.js +2 -2
- package/dist/components/atoms/touchable.js +31 -28
- package/dist/components/atoms/touchable.js.map +1 -1
- package/dist/components/commerce/product-card.js +61 -58
- package/dist/components/commerce/product-card.js.map +1 -1
- package/dist/components/commerce/product-link.js +144 -131
- package/dist/components/commerce/product-link.js.map +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.1.6_react@19.1.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
- 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
- package/eslint/rules/prefer-sdk-components.cjs +18 -8
- package/eslint/rules/validate-manifest.cjs +99 -1
- package/package.json +1 -1
- package/src/components/atoms/touchable.tsx +7 -4
- package/src/components/commerce/product-card.test.tsx +68 -0
- package/src/components/commerce/product-card.tsx +10 -2
- package/src/components/commerce/product-link.test.tsx +81 -0
- package/src/components/commerce/product-link.tsx +36 -10
package/dist/_virtual/index10.js
CHANGED
package/dist/_virtual/index4.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
var i = r();
|
|
1
|
+
var r = {};
|
|
3
2
|
export {
|
|
4
|
-
|
|
3
|
+
r as __exports
|
|
5
4
|
};
|
|
6
5
|
//# sourceMappingURL=index4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index4.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index4.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/_virtual/index7.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { __require as r } from "../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";
|
|
2
|
+
var i = r();
|
|
2
3
|
export {
|
|
3
|
-
|
|
4
|
+
i as s
|
|
4
5
|
};
|
|
5
6
|
//# sourceMappingURL=index7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index7.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index7.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/dist/_virtual/index9.js
CHANGED
|
@@ -1,53 +1,56 @@
|
|
|
1
1
|
import { jsx as d } from "react/jsx-runtime";
|
|
2
2
|
import * as i from "react";
|
|
3
3
|
import { useAnimationControls as f } 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/animation/hooks/use-animation.js";
|
|
4
|
-
import { motion as
|
|
4
|
+
import { motion as y } 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";
|
|
5
5
|
const L = ({
|
|
6
|
-
children:
|
|
6
|
+
children: u,
|
|
7
7
|
onClick: a,
|
|
8
|
-
stopPropagation:
|
|
9
|
-
...
|
|
8
|
+
stopPropagation: t = !1,
|
|
9
|
+
...l
|
|
10
10
|
}) => {
|
|
11
|
-
const r = i.useRef(null),
|
|
12
|
-
(
|
|
13
|
-
|
|
11
|
+
const r = i.useRef(null), o = f(), { ref: w, ...p } = l, m = i.useCallback(
|
|
12
|
+
(e) => {
|
|
13
|
+
t && e.stopPropagation(), a?.(e);
|
|
14
14
|
},
|
|
15
|
-
[
|
|
15
|
+
[t, a]
|
|
16
16
|
);
|
|
17
17
|
return i.useEffect(() => {
|
|
18
|
-
if (!
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
if (!t || !r.current) return;
|
|
19
|
+
const e = r.current, s = (n) => {
|
|
20
|
+
n.stopImmediatePropagation(), n.stopPropagation(), o.start({
|
|
21
|
+
opacity: 0.7,
|
|
22
|
+
transition: {
|
|
23
|
+
opacity: { type: "tween", duration: 0.08, ease: "linear" }
|
|
24
|
+
}
|
|
23
25
|
});
|
|
24
|
-
}, c = (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
}, c = (n) => {
|
|
27
|
+
n.stopImmediatePropagation(), n.stopPropagation(), o.start({
|
|
28
|
+
opacity: 1,
|
|
29
|
+
transition: {
|
|
30
|
+
opacity: { type: "tween", duration: 0.08, ease: "linear" }
|
|
31
|
+
}
|
|
28
32
|
});
|
|
29
33
|
};
|
|
30
|
-
return
|
|
31
|
-
|
|
34
|
+
return e.addEventListener("pointerdown", s, !0), e.addEventListener("pointerup", c, !0), () => {
|
|
35
|
+
e.removeEventListener("pointerdown", s, !0), e.removeEventListener("pointerup", c, !0);
|
|
32
36
|
};
|
|
33
|
-
}, [
|
|
34
|
-
|
|
37
|
+
}, [t, o]), /* @__PURE__ */ d(
|
|
38
|
+
y.div,
|
|
35
39
|
{
|
|
36
40
|
ref: r,
|
|
37
41
|
"data-touchable": "true",
|
|
38
42
|
className: "flex w-full",
|
|
39
|
-
animate:
|
|
40
|
-
whileTap:
|
|
43
|
+
animate: t ? o : void 0,
|
|
44
|
+
whileTap: t ? void 0 : { opacity: 0.7 },
|
|
41
45
|
transition: {
|
|
42
|
-
scale: { type: "tween", duration: 0.08, ease: "linear" },
|
|
43
46
|
opacity: { type: "tween", duration: 0.08, ease: "linear" }
|
|
44
47
|
},
|
|
45
|
-
onClick:
|
|
48
|
+
onClick: m,
|
|
46
49
|
style: {
|
|
47
|
-
touchAction:
|
|
50
|
+
touchAction: t ? "manipulation" : void 0
|
|
48
51
|
},
|
|
49
|
-
...
|
|
50
|
-
children:
|
|
52
|
+
...p,
|
|
53
|
+
children: u
|
|
51
54
|
}
|
|
52
55
|
);
|
|
53
56
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"touchable.js","sources":["../../../src/components/atoms/touchable.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {motion, HTMLMotionProps, useAnimationControls} from 'motion/react'\n\nexport const Touchable = ({\n children,\n onClick,\n stopPropagation = false,\n ...props\n}: HTMLMotionProps<'div'> & {\n onClick?: React.MouseEventHandler<HTMLDivElement>\n stopPropagation?: boolean\n}) => {\n const ref = React.useRef<HTMLDivElement>(null)\n const controls = useAnimationControls()\n\n // Filter out props that shouldn't be passed to motion.div\n // Any other custom props that get added to the component interface should be filtered here\n const {ref: _, ...motionProps} = props\n\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (stopPropagation) event.stopPropagation()\n onClick?.(event)\n },\n [stopPropagation, onClick]\n )\n\n // Handle animations manually when stopPropagation is true to prevent parent from receiving event\n React.useEffect(() => {\n if (!stopPropagation || !ref.current) return\n\n const element = ref.current\n\n const handlePointerDown = (event: PointerEvent) => {\n event.stopImmediatePropagation()\n event.stopPropagation()\n\n // Animate to pressed state\n controls.start({\n
|
|
1
|
+
{"version":3,"file":"touchable.js","sources":["../../../src/components/atoms/touchable.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {motion, HTMLMotionProps, useAnimationControls} from 'motion/react'\n\nexport const Touchable = ({\n children,\n onClick,\n stopPropagation = false,\n ...props\n}: HTMLMotionProps<'div'> & {\n onClick?: React.MouseEventHandler<HTMLDivElement>\n stopPropagation?: boolean\n}) => {\n const ref = React.useRef<HTMLDivElement>(null)\n const controls = useAnimationControls()\n\n // Filter out props that shouldn't be passed to motion.div\n // Any other custom props that get added to the component interface should be filtered here\n const {ref: _, ...motionProps} = props\n\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (stopPropagation) event.stopPropagation()\n onClick?.(event)\n },\n [stopPropagation, onClick]\n )\n\n // Handle animations manually when stopPropagation is true to prevent parent from receiving event\n React.useEffect(() => {\n if (!stopPropagation || !ref.current) return\n\n const element = ref.current\n\n const handlePointerDown = (event: PointerEvent) => {\n event.stopImmediatePropagation()\n event.stopPropagation()\n\n // Animate to pressed state\n controls.start({\n opacity: 0.7,\n transition: {\n opacity: {type: 'tween', duration: 0.08, ease: 'linear'},\n },\n })\n }\n\n const handlePointerUp = (event: PointerEvent) => {\n event.stopImmediatePropagation()\n event.stopPropagation()\n\n // Animate back to normal state\n controls.start({\n opacity: 1,\n transition: {\n opacity: {type: 'tween', duration: 0.08, ease: 'linear'},\n },\n })\n }\n\n // Capture pointer event before Motion\n element.addEventListener('pointerdown', handlePointerDown, true)\n element.addEventListener('pointerup', handlePointerUp, true)\n\n return () => {\n element.removeEventListener('pointerdown', handlePointerDown, true)\n element.removeEventListener('pointerup', handlePointerUp, true)\n }\n }, [stopPropagation, controls])\n\n return (\n <motion.div\n ref={ref}\n data-touchable=\"true\"\n className=\"flex w-full\"\n animate={stopPropagation ? controls : undefined}\n whileTap={stopPropagation ? undefined : {opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'linear'},\n }}\n onClick={handleClick}\n style={{\n touchAction: stopPropagation ? 'manipulation' : undefined,\n }}\n {...motionProps}\n >\n {children}\n </motion.div>\n )\n}\n"],"names":["Touchable","children","onClick","stopPropagation","props","ref","React","controls","useAnimationControls","_","motionProps","handleClick","event","element","handlePointerDown","handlePointerUp","jsx","motion"],"mappings":";;;;AAIO,MAAMA,IAAY,CAAC;AAAA,EACxB,UAAAC;AAAA,EACA,SAAAC;AAAA,EACA,iBAAAC,IAAkB;AAAA,EAClB,GAAGC;AACL,MAGM;AACE,QAAAC,IAAMC,EAAM,OAAuB,IAAI,GACvCC,IAAWC,EAAqB,GAIhC,EAAC,KAAKC,GAAG,GAAGC,EAAe,IAAAN,GAE3BO,IAAcL,EAAM;AAAA,IACxB,CAACM,MAA4C;AACvC,MAAAT,OAAuB,gBAAgB,GAC3CD,IAAUU,CAAK;AAAA,IACjB;AAAA,IACA,CAACT,GAAiBD,CAAO;AAAA,EAC3B;AAGA,SAAAI,EAAM,UAAU,MAAM;AACpB,QAAI,CAACH,KAAmB,CAACE,EAAI,QAAS;AAEtC,UAAMQ,IAAUR,EAAI,SAEdS,IAAoB,CAACF,MAAwB;AACjD,MAAAA,EAAM,yBAAyB,GAC/BA,EAAM,gBAAgB,GAGtBL,EAAS,MAAM;AAAA,QACb,SAAS;AAAA,QACT,YAAY;AAAA,UACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,SAAQ;AAAA,QAAA;AAAA,MACzD,CACD;AAAA,IACH,GAEMQ,IAAkB,CAACH,MAAwB;AAC/C,MAAAA,EAAM,yBAAyB,GAC/BA,EAAM,gBAAgB,GAGtBL,EAAS,MAAM;AAAA,QACb,SAAS;AAAA,QACT,YAAY;AAAA,UACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,SAAQ;AAAA,QAAA;AAAA,MACzD,CACD;AAAA,IACH;AAGQ,WAAAM,EAAA,iBAAiB,eAAeC,GAAmB,EAAI,GACvDD,EAAA,iBAAiB,aAAaE,GAAiB,EAAI,GAEpD,MAAM;AACH,MAAAF,EAAA,oBAAoB,eAAeC,GAAmB,EAAI,GAC1DD,EAAA,oBAAoB,aAAaE,GAAiB,EAAI;AAAA,IAChE;AAAA,EAAA,GACC,CAACZ,GAAiBI,CAAQ,CAAC,GAG5B,gBAAAS;AAAA,IAACC,EAAO;AAAA,IAAP;AAAA,MACC,KAAAZ;AAAA,MACA,kBAAe;AAAA,MACf,WAAU;AAAA,MACV,SAASF,IAAkBI,IAAW;AAAA,MACtC,UAAUJ,IAAkB,SAAY,EAAC,SAAS,IAAG;AAAA,MACrD,YAAY;AAAA,QACV,SAAS,EAAC,MAAM,SAAS,UAAU,MAAM,MAAM,SAAQ;AAAA,MACzD;AAAA,MACA,SAASQ;AAAA,MACT,OAAO;AAAA,QACL,aAAaR,IAAkB,iBAAiB;AAAA,MAClD;AAAA,MACC,GAAGO;AAAA,MAEH,UAAAT;AAAA,IAAA;AAAA,EACH;AAEJ;"}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { jsx as o, jsxs as v } from "react/jsx-runtime";
|
|
2
|
-
import * as
|
|
3
|
-
import { useState as
|
|
2
|
+
import * as F from "react";
|
|
3
|
+
import { useState as A, useCallback as C, useMemo as k, useContext as B } from "react";
|
|
4
4
|
import { useShopNavigation as V } from "../../hooks/navigation/useShopNavigation.js";
|
|
5
5
|
import { useSavedProductsActions as j } from "../../hooks/user/useSavedProductsActions.js";
|
|
6
6
|
import { formatMoney as z } from "../../lib/formatMoney.js";
|
|
7
7
|
import { cn as s } from "../../lib/utils.js";
|
|
8
|
-
import { Image as
|
|
9
|
-
import { ProductVariantPrice as
|
|
10
|
-
import { Touchable as
|
|
11
|
-
import { Badge as
|
|
12
|
-
import { FavoriteButton as
|
|
13
|
-
const
|
|
8
|
+
import { Image as T } from "../atoms/image.js";
|
|
9
|
+
import { ProductVariantPrice as E } from "../atoms/product-variant-price.js";
|
|
10
|
+
import { Touchable as O } from "../atoms/touchable.js";
|
|
11
|
+
import { Badge as S } from "../ui/badge.js";
|
|
12
|
+
import { FavoriteButton as L } from "./favorite-button.js";
|
|
13
|
+
const b = F.createContext(void 0);
|
|
14
14
|
function u() {
|
|
15
|
-
const t =
|
|
15
|
+
const t = B(b);
|
|
16
16
|
if (!t)
|
|
17
17
|
throw new Error(
|
|
18
18
|
"ProductCard components must be used within a ProductCard provider"
|
|
19
19
|
);
|
|
20
20
|
return t;
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function M({
|
|
23
23
|
className: t,
|
|
24
24
|
...e
|
|
25
25
|
}) {
|
|
@@ -34,7 +34,7 @@ function L({
|
|
|
34
34
|
}
|
|
35
35
|
);
|
|
36
36
|
return r && a ? /* @__PURE__ */ o(
|
|
37
|
-
|
|
37
|
+
O,
|
|
38
38
|
{
|
|
39
39
|
onClick: a,
|
|
40
40
|
whileTap: { opacity: 0.7 },
|
|
@@ -45,7 +45,7 @@ function L({
|
|
|
45
45
|
}
|
|
46
46
|
) : n;
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
function R({
|
|
49
49
|
className: t,
|
|
50
50
|
...e
|
|
51
51
|
}) {
|
|
@@ -66,10 +66,10 @@ function M({
|
|
|
66
66
|
}
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
|
-
function
|
|
69
|
+
function q({ className: t, ...e }) {
|
|
70
70
|
const { product: r, selectedProductVariant: a } = u(), n = a?.image || r.featuredImage, i = n?.url, d = n?.altText || r.title, c = r.featuredImage?.thumbhash, p = C(
|
|
71
71
|
(l) => c ? /* @__PURE__ */ o(
|
|
72
|
-
|
|
72
|
+
T,
|
|
73
73
|
{
|
|
74
74
|
"data-slot": "product-card-image",
|
|
75
75
|
src: l,
|
|
@@ -93,7 +93,7 @@ function R({ className: t, ...e }) {
|
|
|
93
93
|
);
|
|
94
94
|
return /* @__PURE__ */ o("div", { className: "bg-gray-100 flex items-center justify-center size-full", children: i ? p(i) : /* @__PURE__ */ o("div", { className: "text-gray-400 text-sm w-full text-center", children: "No Image" }) });
|
|
95
95
|
}
|
|
96
|
-
function
|
|
96
|
+
function w({
|
|
97
97
|
className: t,
|
|
98
98
|
position: e = "bottom-left",
|
|
99
99
|
variant: r,
|
|
@@ -109,7 +109,7 @@ function b({
|
|
|
109
109
|
e === "top-left" ? "top-3 left-3" : "bottom-2 left-2"
|
|
110
110
|
),
|
|
111
111
|
children: /* @__PURE__ */ o(
|
|
112
|
-
|
|
112
|
+
S,
|
|
113
113
|
{
|
|
114
114
|
variant: r ?? d ?? "none",
|
|
115
115
|
className: s(
|
|
@@ -124,14 +124,14 @@ function b({
|
|
|
124
124
|
}
|
|
125
125
|
) : null;
|
|
126
126
|
}
|
|
127
|
-
function
|
|
127
|
+
function D({
|
|
128
128
|
className: t,
|
|
129
129
|
...e
|
|
130
130
|
}) {
|
|
131
|
-
const { isFavorited: r,
|
|
132
|
-
return /* @__PURE__ */ o("div", { className: s("absolute bottom-3 right-3 z-10", t), ...e, children: /* @__PURE__ */ o(
|
|
131
|
+
const { isFavorited: r, isFavoriteButtonDisabled: a, onFavoriteToggle: n } = u();
|
|
132
|
+
return a ? null : /* @__PURE__ */ o("div", { className: s("absolute bottom-3 right-3 z-10", t), ...e, children: /* @__PURE__ */ o(L, { onClick: n, filled: r }) });
|
|
133
133
|
}
|
|
134
|
-
function
|
|
134
|
+
function G({ className: t, ...e }) {
|
|
135
135
|
const { variant: r } = u();
|
|
136
136
|
return r !== "default" ? null : /* @__PURE__ */ o(
|
|
137
137
|
"div",
|
|
@@ -142,7 +142,7 @@ function D({ className: t, ...e }) {
|
|
|
142
142
|
}
|
|
143
143
|
);
|
|
144
144
|
}
|
|
145
|
-
function
|
|
145
|
+
function H({
|
|
146
146
|
className: t,
|
|
147
147
|
children: e,
|
|
148
148
|
...r
|
|
@@ -162,10 +162,10 @@ function G({
|
|
|
162
162
|
}
|
|
163
163
|
);
|
|
164
164
|
}
|
|
165
|
-
function
|
|
165
|
+
function J({ className: t }) {
|
|
166
166
|
const { product: e, selectedProductVariant: r } = u(), a = r?.price || e?.price, n = r?.compareAtPrice || e?.compareAtPrice;
|
|
167
167
|
return /* @__PURE__ */ o(
|
|
168
|
-
|
|
168
|
+
E,
|
|
169
169
|
{
|
|
170
170
|
amount: a?.amount || "",
|
|
171
171
|
currencyCode: a?.currencyCode || "",
|
|
@@ -175,13 +175,13 @@ function H({ className: t }) {
|
|
|
175
175
|
}
|
|
176
176
|
);
|
|
177
177
|
}
|
|
178
|
-
function
|
|
178
|
+
function K() {
|
|
179
179
|
const { product: t, selectedProductVariant: e, variant: r } = u();
|
|
180
180
|
if (r !== "priceOverlay") return null;
|
|
181
181
|
const a = e?.price || t.price, n = a?.currencyCode, i = a?.amount;
|
|
182
|
-
return !n || !i ? null : /* @__PURE__ */ o(
|
|
182
|
+
return !n || !i ? null : /* @__PURE__ */ o(w, { position: "top-left", children: z(i, n) });
|
|
183
183
|
}
|
|
184
|
-
function
|
|
184
|
+
function at({
|
|
185
185
|
product: t,
|
|
186
186
|
selectedProductVariant: e,
|
|
187
187
|
variant: r = "default",
|
|
@@ -190,27 +190,28 @@ function ot({
|
|
|
190
190
|
badgeVariant: i,
|
|
191
191
|
onProductClick: d,
|
|
192
192
|
onFavoriteToggled: c,
|
|
193
|
-
children: p
|
|
193
|
+
children: p,
|
|
194
|
+
favoriteButtonDisabled: l = !1
|
|
194
195
|
}) {
|
|
195
|
-
const { navigateToProduct:
|
|
196
|
-
a && (d?.(),
|
|
196
|
+
const { navigateToProduct: h } = V(), { saveProduct: g, unsaveProduct: P } = j(), [f, y] = A(t.isFavorited), x = C(() => {
|
|
197
|
+
a && (d?.(), h({
|
|
197
198
|
productId: t.id
|
|
198
199
|
}));
|
|
199
|
-
}, [
|
|
200
|
+
}, [h, t.id, a, d]), I = C(async () => {
|
|
200
201
|
const m = f;
|
|
201
|
-
|
|
202
|
+
y(!m), c?.(!m);
|
|
202
203
|
try {
|
|
203
|
-
m ? await
|
|
204
|
+
m ? await P({
|
|
204
205
|
productId: t.id,
|
|
205
206
|
shopId: t.shop.id,
|
|
206
207
|
productVariantId: e?.id || t.defaultVariantId
|
|
207
|
-
}) : await
|
|
208
|
+
}) : await g({
|
|
208
209
|
productId: t.id,
|
|
209
210
|
shopId: t.shop.id,
|
|
210
211
|
productVariantId: e?.id || t.defaultVariantId
|
|
211
212
|
});
|
|
212
213
|
} catch {
|
|
213
|
-
|
|
214
|
+
y(m), c?.(m);
|
|
214
215
|
}
|
|
215
216
|
}, [
|
|
216
217
|
f,
|
|
@@ -218,10 +219,10 @@ function ot({
|
|
|
218
219
|
t.shop.id,
|
|
219
220
|
t.defaultVariantId,
|
|
220
221
|
e?.id,
|
|
221
|
-
h,
|
|
222
222
|
g,
|
|
223
|
+
P,
|
|
223
224
|
c
|
|
224
|
-
]),
|
|
225
|
+
]), N = k(
|
|
225
226
|
() => ({
|
|
226
227
|
// Core data
|
|
227
228
|
product: t,
|
|
@@ -233,9 +234,10 @@ function ot({
|
|
|
233
234
|
badgeVariant: i,
|
|
234
235
|
// State
|
|
235
236
|
isFavorited: f,
|
|
237
|
+
isFavoriteButtonDisabled: l,
|
|
236
238
|
// Actions
|
|
237
|
-
onClick:
|
|
238
|
-
onFavoriteToggle:
|
|
239
|
+
onClick: x,
|
|
240
|
+
onFavoriteToggle: I
|
|
239
241
|
}),
|
|
240
242
|
[
|
|
241
243
|
t,
|
|
@@ -245,32 +247,33 @@ function ot({
|
|
|
245
247
|
n,
|
|
246
248
|
i,
|
|
247
249
|
f,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
+
x,
|
|
251
|
+
I,
|
|
252
|
+
l
|
|
250
253
|
]
|
|
251
254
|
);
|
|
252
|
-
return /* @__PURE__ */ o(
|
|
253
|
-
/* @__PURE__ */ v(
|
|
254
|
-
/* @__PURE__ */ o(
|
|
255
|
-
r === "priceOverlay" && /* @__PURE__ */ o(
|
|
256
|
-
/* @__PURE__ */ o(
|
|
257
|
-
/* @__PURE__ */ o(
|
|
255
|
+
return /* @__PURE__ */ o(b.Provider, { value: N, children: p ?? /* @__PURE__ */ v(M, { children: [
|
|
256
|
+
/* @__PURE__ */ v(R, { children: [
|
|
257
|
+
/* @__PURE__ */ o(q, {}),
|
|
258
|
+
r === "priceOverlay" && /* @__PURE__ */ o(K, {}),
|
|
259
|
+
/* @__PURE__ */ o(w, {}),
|
|
260
|
+
/* @__PURE__ */ o(D, {})
|
|
258
261
|
] }),
|
|
259
|
-
r === "default" && /* @__PURE__ */ v(
|
|
260
|
-
/* @__PURE__ */ o(
|
|
261
|
-
/* @__PURE__ */ o(
|
|
262
|
+
r === "default" && /* @__PURE__ */ v(G, { children: [
|
|
263
|
+
/* @__PURE__ */ o(H, {}),
|
|
264
|
+
/* @__PURE__ */ o(J, {})
|
|
262
265
|
] })
|
|
263
266
|
] }) });
|
|
264
267
|
}
|
|
265
268
|
export {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
269
|
+
at as ProductCard,
|
|
270
|
+
w as ProductCardBadge,
|
|
271
|
+
M as ProductCardContainer,
|
|
272
|
+
D as ProductCardFavoriteButton,
|
|
273
|
+
q as ProductCardImage,
|
|
274
|
+
R as ProductCardImageContainer,
|
|
275
|
+
G as ProductCardInfo,
|
|
276
|
+
J as ProductCardPrice,
|
|
277
|
+
H as ProductCardTitle
|
|
275
278
|
};
|
|
276
279
|
//# sourceMappingURL=product-card.js.map
|
|
@@ -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 {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\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 w-full overflow-hidden rounded-xl border-0',\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 // Ensure the product image is stretched to the full size of the container (can't use width/height: 100% because of flex)\n 'flex justify-stretch items-stretch',\n 'relative overflow-hidden rounded-xl border border-gray-200',\n 'w-full 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 className={cn('size-full object-cover', className)}\n {...props}\n />\n ) : (\n <img\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n className={cn('size-full', 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, onFavoriteToggle} = useProductCardContext()\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-slot=\"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 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}\n\nfunction ProductCard({\n product,\n selectedProductVariant,\n variant = 'default',\n touchable = true,\n badgeText,\n badgeVariant,\n onProductClick,\n onFavoriteToggled,\n children,\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\n // State\n isFavorited: isFavoritedLocal,\n\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 ]\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 <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 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","onFavoriteToggle","FavoriteButton","ProductCardInfo","ProductCardTitle","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 {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\n // State\n isFavorited: boolean\n isFavoriteButtonDisabled: 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 w-full overflow-hidden rounded-xl border-0',\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 // Ensure the product image is stretched to the full size of the container (can't use width/height: 100% because of flex)\n 'flex justify-stretch items-stretch',\n 'relative overflow-hidden rounded-xl border border-gray-200',\n 'w-full 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 className={cn('size-full object-cover', className)}\n {...props}\n />\n ) : (\n <img\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n className={cn('size-full', 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, isFavoriteButtonDisabled, onFavoriteToggle} =\n useProductCardContext()\n if (isFavoriteButtonDisabled) 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-slot=\"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 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}\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}: 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\n // State\n isFavorited: isFavoritedLocal,\n isFavoriteButtonDisabled: favoriteButtonDisabled,\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 ]\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 <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 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","isFavoriteButtonDisabled","onFavoriteToggle","FavoriteButton","ProductCardInfo","ProductCardTitle","ProductCardPrice","displayPrice","displayCompareAtPrice","ProductVariantPrice","ProductCardPriceOverlayBadge","currencyCode","amount","formatMoney","ProductCard","onProductClick","onFavoriteToggled","favoriteButtonDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","isFavoritedLocal","setIsFavoritedLocal","useState","handleClick","handleFavoriteClick","previousState","contextValue","useMemo","jsxs"],"mappings":"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"}
|