@shopify/shop-minis-react 0.0.16 → 0.0.18

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 (120) hide show
  1. package/README.md +14 -10
  2. package/dist/_virtual/index2.js +3 -2
  3. package/dist/_virtual/index2.js.map +1 -1
  4. package/dist/_virtual/index3.js +2 -3
  5. package/dist/_virtual/index3.js.map +1 -1
  6. package/dist/components/atoms/button.js +28 -73
  7. package/dist/components/atoms/button.js.map +1 -1
  8. package/dist/components/atoms/favorite-button.js +21 -0
  9. package/dist/components/atoms/favorite-button.js.map +1 -0
  10. package/dist/components/atoms/icon-button.js +38 -0
  11. package/dist/components/atoms/icon-button.js.map +1 -0
  12. package/dist/components/atoms/touchable.js +14 -14
  13. package/dist/components/atoms/touchable.js.map +1 -1
  14. package/dist/components/commerce/merchant-card.js +1 -8
  15. package/dist/components/commerce/merchant-card.js.map +1 -1
  16. package/dist/components/commerce/product-card.js +79 -109
  17. package/dist/components/commerce/product-card.js.map +1 -1
  18. package/dist/components/commerce/product-link.js +36 -55
  19. package/dist/components/commerce/product-link.js.map +1 -1
  20. package/dist/components/ui/accordion.js.map +1 -0
  21. package/dist/components/{atoms → ui}/alert-dialog.js +1 -1
  22. package/dist/components/ui/alert-dialog.js.map +1 -0
  23. package/dist/components/ui/alert.js.map +1 -0
  24. package/dist/components/ui/avatar.js.map +1 -0
  25. package/dist/components/ui/badge.js.map +1 -0
  26. package/dist/components/ui/button.js +68 -0
  27. package/dist/components/ui/button.js.map +1 -0
  28. package/dist/components/ui/card.js.map +1 -0
  29. package/dist/components/{atoms → ui}/carousel.js +23 -23
  30. package/dist/components/ui/carousel.js.map +1 -0
  31. package/dist/components/ui/checkbox.js.map +1 -0
  32. package/dist/components/ui/dialog.js.map +1 -0
  33. package/dist/components/{atoms → ui}/drawer.js +25 -22
  34. package/dist/components/ui/drawer.js.map +1 -0
  35. package/dist/components/ui/input.js.map +1 -0
  36. package/dist/components/ui/label.js.map +1 -0
  37. package/dist/components/ui/progress.js.map +1 -0
  38. package/dist/components/ui/radio-group.js.map +1 -0
  39. package/dist/components/ui/resizable.js.map +1 -0
  40. package/dist/components/ui/scroll-area.js.map +1 -0
  41. package/dist/components/ui/select.js.map +1 -0
  42. package/dist/components/ui/separator.js.map +1 -0
  43. package/dist/components/ui/sheet.js.map +1 -0
  44. package/dist/components/ui/sonner.js.map +1 -0
  45. package/dist/index.js +193 -218
  46. package/dist/index.js.map +1 -1
  47. 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
  48. package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
  49. package/package.json +6 -9
  50. package/src/components/atoms/button.tsx +10 -66
  51. package/src/components/atoms/favorite-button.tsx +22 -0
  52. package/src/components/atoms/icon-button.tsx +42 -0
  53. package/src/components/atoms/touchable.tsx +5 -1
  54. package/src/components/commerce/merchant-card.tsx +1 -12
  55. package/src/components/commerce/product-card.tsx +4 -32
  56. package/src/components/commerce/product-link.tsx +9 -29
  57. package/src/components/index.ts +23 -20
  58. package/src/components/{atoms → ui}/alert-dialog.tsx +1 -1
  59. package/src/components/ui/button.tsx +77 -0
  60. package/src/components/{atoms → ui}/carousel.tsx +11 -11
  61. package/src/components/{atoms → ui}/drawer.tsx +2 -1
  62. package/src/index.css +8 -2
  63. package/src/styles/globals.css +41 -0
  64. package/src/styles/theme.css +102 -0
  65. package/dist/components/atoms/accordion.js.map +0 -1
  66. package/dist/components/atoms/alert-dialog.js.map +0 -1
  67. package/dist/components/atoms/alert.js.map +0 -1
  68. package/dist/components/atoms/avatar.js.map +0 -1
  69. package/dist/components/atoms/badge.js.map +0 -1
  70. package/dist/components/atoms/card.js.map +0 -1
  71. package/dist/components/atoms/carousel.js.map +0 -1
  72. package/dist/components/atoms/checkbox.js.map +0 -1
  73. package/dist/components/atoms/dialog.js.map +0 -1
  74. package/dist/components/atoms/drawer.js.map +0 -1
  75. package/dist/components/atoms/input.js.map +0 -1
  76. package/dist/components/atoms/label.js.map +0 -1
  77. package/dist/components/atoms/progress.js.map +0 -1
  78. package/dist/components/atoms/radio-group.js.map +0 -1
  79. package/dist/components/atoms/resizable.js.map +0 -1
  80. package/dist/components/atoms/scroll-area.js.map +0 -1
  81. package/dist/components/atoms/select.js.map +0 -1
  82. package/dist/components/atoms/separator.js.map +0 -1
  83. package/dist/components/atoms/sheet.js.map +0 -1
  84. package/dist/components/atoms/sonner.js.map +0 -1
  85. package/src/base.css +0 -273
  86. package/tailwind.config.js +0 -3
  87. /package/dist/components/{atoms → ui}/accordion.js +0 -0
  88. /package/dist/components/{atoms → ui}/alert.js +0 -0
  89. /package/dist/components/{atoms → ui}/avatar.js +0 -0
  90. /package/dist/components/{atoms → ui}/badge.js +0 -0
  91. /package/dist/components/{atoms → ui}/card.js +0 -0
  92. /package/dist/components/{atoms → ui}/checkbox.js +0 -0
  93. /package/dist/components/{atoms → ui}/dialog.js +0 -0
  94. /package/dist/components/{atoms → ui}/input.js +0 -0
  95. /package/dist/components/{atoms → ui}/label.js +0 -0
  96. /package/dist/components/{atoms → ui}/progress.js +0 -0
  97. /package/dist/components/{atoms → ui}/radio-group.js +0 -0
  98. /package/dist/components/{atoms → ui}/resizable.js +0 -0
  99. /package/dist/components/{atoms → ui}/scroll-area.js +0 -0
  100. /package/dist/components/{atoms → ui}/select.js +0 -0
  101. /package/dist/components/{atoms → ui}/separator.js +0 -0
  102. /package/dist/components/{atoms → ui}/sheet.js +0 -0
  103. /package/dist/components/{atoms → ui}/sonner.js +0 -0
  104. /package/src/components/{atoms → ui}/accordion.tsx +0 -0
  105. /package/src/components/{atoms → ui}/alert.tsx +0 -0
  106. /package/src/components/{atoms → ui}/avatar.tsx +0 -0
  107. /package/src/components/{atoms → ui}/badge.tsx +0 -0
  108. /package/src/components/{atoms → ui}/card.tsx +0 -0
  109. /package/src/components/{atoms → ui}/checkbox.tsx +0 -0
  110. /package/src/components/{atoms → ui}/dialog.tsx +0 -0
  111. /package/src/components/{atoms → ui}/input.tsx +0 -0
  112. /package/src/components/{atoms → ui}/label.tsx +0 -0
  113. /package/src/components/{atoms → ui}/progress.tsx +0 -0
  114. /package/src/components/{atoms → ui}/radio-group.tsx +0 -0
  115. /package/src/components/{atoms → ui}/resizable.tsx +0 -0
  116. /package/src/components/{atoms → ui}/scroll-area.tsx +0 -0
  117. /package/src/components/{atoms → ui}/select.tsx +0 -0
  118. /package/src/components/{atoms → ui}/separator.tsx +0 -0
  119. /package/src/components/{atoms → ui}/sheet.tsx +0 -0
  120. /package/src/components/{atoms → ui}/sonner.tsx +0 -0
@@ -1,16 +1,15 @@
1
- import { jsxs as p, jsx as r, Fragment as H } from "react/jsx-runtime";
2
- import * as b from "react";
3
- import { cva as M } from "../../shop-minis-react/node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js";
4
- import { useShopNavigation as U } from "../../hooks/navigation/useShopNavigation.js";
5
- import { useSavedProductsActions as E } from "../../hooks/user/useSavedProductsActions.js";
1
+ import { jsxs as p, jsx as r, Fragment as M } from "react/jsx-runtime";
2
+ import * as x from "react";
3
+ import { cva as U } from "../../shop-minis-react/node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js";
4
+ import { useShopNavigation as E } from "../../hooks/navigation/useShopNavigation.js";
5
+ import { useSavedProductsActions as G } from "../../hooks/user/useSavedProductsActions.js";
6
6
  import { formatMoney as f } from "../../lib/formatMoney.js";
7
- import { cn as a } from "../../lib/utils.js";
8
- import { Badge as G } from "../atoms/badge.js";
9
- import { Button as J } from "../atoms/button.js";
10
- import { Touchable as K } from "../atoms/touchable.js";
11
- import Q from "../../shop-minis-react/node_modules/.pnpm/lucide-react@0.513.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/heart.js";
12
- import { Root as V } from "../../shop-minis-react/node_modules/.pnpm/@radix-ui_react-slot@1.2.3_@types_react@19.1.6_react@19.1.0/node_modules/@radix-ui/react-slot/dist/index.js";
13
- const W = M(
7
+ import { cn as c } from "../../lib/utils.js";
8
+ import { FavoriteButton as H } from "../atoms/favorite-button.js";
9
+ import { Touchable as J } from "../atoms/touchable.js";
10
+ import { Badge as K } from "../ui/badge.js";
11
+ import { Root as Q } from "../../shop-minis-react/node_modules/.pnpm/@radix-ui_react-slot@1.2.3_@types_react@19.1.6_react@19.1.0/node_modules/@radix-ui/react-slot/dist/index.js";
12
+ const V = U(
14
13
  "relative w-full overflow-hidden rounded-xl border border-gray-200",
15
14
  {
16
15
  variants: {
@@ -30,19 +29,19 @@ const W = M(
30
29
  }
31
30
  }
32
31
  );
33
- function X({
32
+ function W({
34
33
  className: e,
35
34
  variant: t,
36
35
  touchable: o = !0,
37
- asChild: c = !1,
36
+ asChild: a = !1,
38
37
  onPress: i,
39
38
  ...h
40
39
  }) {
41
40
  const n = /* @__PURE__ */ r(
42
- c ? V : "div",
41
+ a ? Q : "div",
43
42
  {
44
- className: a(
45
- W({ variant: t, touchable: o }),
43
+ className: c(
44
+ V({ variant: t, touchable: o }),
46
45
  "border-0",
47
46
  e
48
47
  ),
@@ -50,7 +49,7 @@ function X({
50
49
  }
51
50
  );
52
51
  return o && i ? /* @__PURE__ */ r(
53
- K,
52
+ J,
54
53
  {
55
54
  onClick: i,
56
55
  whileTap: { opacity: 0.7 },
@@ -61,7 +60,7 @@ function X({
61
60
  }
62
61
  ) : n;
63
62
  }
64
- function Y({
63
+ function X({
65
64
  className: e,
66
65
  variant: t = "default",
67
66
  ...o
@@ -70,7 +69,7 @@ function Y({
70
69
  "div",
71
70
  {
72
71
  "data-slot": "product-card-image-container",
73
- className: a(
72
+ className: c(
74
73
  // Ensure the product image is stretched to the full size of the container (can't use width/height: 100% because of flex)
75
74
  "flex justify-stretch items-stretch",
76
75
  "relative overflow-hidden rounded-xl border border-gray-200",
@@ -82,11 +81,11 @@ function Y({
82
81
  }
83
82
  );
84
83
  }
85
- function Z({
84
+ function Y({
86
85
  className: e,
87
86
  src: t,
88
87
  alt: o,
89
- ...c
88
+ ...a
90
89
  }) {
91
90
  return /* @__PURE__ */ r("div", { className: "bg-gray-100 flex items-center justify-center", children: t ? /* @__PURE__ */ r(
92
91
  "img",
@@ -94,63 +93,44 @@ function Z({
94
93
  "data-slot": "product-card-image",
95
94
  src: t,
96
95
  alt: o,
97
- className: a("w-full h-full object-cover", e),
98
- ...c
96
+ className: c("w-full h-full object-cover", e),
97
+ ...a
99
98
  }
100
99
  ) : /* @__PURE__ */ r("div", { className: "text-gray-400 text-sm", children: "No Image" }) });
101
100
  }
102
- function j({
101
+ function k({
103
102
  className: e,
104
103
  position: t = "bottom-left",
105
104
  children: o,
106
- ...c
105
+ ...a
107
106
  }) {
108
107
  return /* @__PURE__ */ r(
109
108
  "div",
110
109
  {
111
- className: a(
110
+ className: c(
112
111
  "absolute z-10",
113
112
  t === "top-left" ? "top-3 left-3" : "bottom-2 left-2"
114
113
  ),
115
114
  children: /* @__PURE__ */ r(
116
- G,
115
+ K,
117
116
  {
118
- className: a("bg-black/50 text-white rounded", e),
119
- ...c,
117
+ className: c("bg-black/50 text-white rounded", e),
118
+ ...a,
120
119
  children: o
121
120
  }
122
121
  )
123
122
  }
124
123
  );
125
124
  }
126
- function _({
125
+ function Z({
127
126
  className: e,
128
127
  onPress: t,
129
128
  filled: o = !1,
130
- ...c
129
+ ...a
131
130
  }) {
132
- return /* @__PURE__ */ r("div", { className: a("absolute bottom-3 right-3 z-10", e), ...c, children: /* @__PURE__ */ r(
133
- J,
134
- {
135
- onClick: t,
136
- variant: "secondary",
137
- size: "icon",
138
- className: a(
139
- "h-8 w-8 rounded-full border-0 shadow-sm",
140
- o ? "bg-primary" : "bg-grayscale-l6/60 backdrop-blur-sm"
141
- ),
142
- stopPropagation: !0,
143
- children: /* @__PURE__ */ r(
144
- Q,
145
- {
146
- fill: o ? "currentColor" : "none",
147
- className: "h-4 w-4 text-white"
148
- }
149
- )
150
- }
151
- ) });
131
+ return /* @__PURE__ */ r("div", { className: c("absolute bottom-3 right-3 z-10", e), ...a, children: /* @__PURE__ */ r(H, { onClick: t, filled: o }) });
152
132
  }
153
- function $({
133
+ function _({
154
134
  className: e,
155
135
  variant: t = "default",
156
136
  ...o
@@ -159,12 +139,12 @@ function $({
159
139
  "div",
160
140
  {
161
141
  "data-slot": "product-card-info",
162
- className: a("px-1 pt-2 pb-0 space-y-1", e),
142
+ className: c("px-1 pt-2 pb-0 space-y-1", e),
163
143
  ...o
164
144
  }
165
145
  );
166
146
  }
167
- function tt({
147
+ function $({
168
148
  className: e,
169
149
  children: t,
170
150
  ...o
@@ -173,7 +153,7 @@ function tt({
173
153
  "h3",
174
154
  {
175
155
  "data-slot": "product-card-title",
176
- className: a(
156
+ className: c(
177
157
  "text-sm font-medium leading-tight text-gray-900",
178
158
  "truncate overflow-hidden whitespace-nowrap text-ellipsis",
179
159
  e
@@ -183,17 +163,17 @@ function tt({
183
163
  }
184
164
  );
185
165
  }
186
- function rt({ className: e, ...t }) {
166
+ function tt({ className: e, ...t }) {
187
167
  return /* @__PURE__ */ r(
188
168
  "div",
189
169
  {
190
170
  "data-slot": "product-card-price",
191
- className: a("flex items-center gap-2", e),
171
+ className: c("flex items-center gap-2", e),
192
172
  ...t
193
173
  }
194
174
  );
195
175
  }
196
- function S({
176
+ function F({
197
177
  className: e,
198
178
  ...t
199
179
  }) {
@@ -201,12 +181,12 @@ function S({
201
181
  "span",
202
182
  {
203
183
  "data-slot": "product-card-current-price",
204
- className: a("text-sm font-semibold text-gray-900", e),
184
+ className: c("text-sm font-semibold text-gray-900", e),
205
185
  ...t
206
186
  }
207
187
  );
208
188
  }
209
- function et({
189
+ function rt({
210
190
  className: e,
211
191
  ...t
212
192
  }) {
@@ -214,103 +194,93 @@ function et({
214
194
  "span",
215
195
  {
216
196
  "data-slot": "product-card-original-price",
217
- className: a("text-sm text-gray-500 line-through", e),
197
+ className: c("text-sm text-gray-500 line-through", e),
218
198
  ...t
219
199
  }
220
200
  );
221
201
  }
222
- function ht({
202
+ function pt({
223
203
  product: e,
224
204
  selectedProductVariant: t,
225
205
  variant: o = "default",
226
- touchable: c = !0,
206
+ touchable: a = !0,
227
207
  badgeText: i,
228
208
  badgeVariant: h = "secondary",
229
209
  onFavoriteToggled: m
230
210
  }) {
231
- const { navigateToProduct: n } = U(), { saveProduct: x, unsaveProduct: P } = E(), {
211
+ const { navigateToProduct: n } = E(), { saveProduct: P, unsaveProduct: b } = G(), {
232
212
  id: d,
233
- title: w,
234
- featuredImage: B,
235
- price: F,
213
+ title: I,
214
+ featuredImage: S,
215
+ price: B,
236
216
  compareAtPrice: O,
237
- isFavorited: z,
238
- defaultVariantId: g,
239
- shop: v
240
- } = e, N = t?.image || B, I = t?.price || F, A = t?.compareAtPrice || O, [y, k] = b.useState(z), s = I?.currencyCode, l = I?.amount, R = N?.url, T = N?.altText || w, C = A?.amount, L = C && C !== l, q = b.useCallback(() => {
241
- c && n({
217
+ isFavorited: R,
218
+ defaultVariantId: v,
219
+ shop: g
220
+ } = e, N = t?.image || S, w = t?.price || B, A = t?.compareAtPrice || O, [y, j] = x.useState(R), s = w?.currencyCode, l = w?.amount, T = N?.url, z = N?.altText || I, C = A?.amount, L = C && C !== l, q = x.useCallback(() => {
221
+ a && n({
242
222
  productId: d
243
223
  });
244
- }, [n, d, c]), D = b.useCallback(async () => {
224
+ }, [n, d, a]), D = x.useCallback(async () => {
245
225
  const u = y;
246
- k(!u), m?.(!u);
226
+ j(!u), m?.(!u);
247
227
  try {
248
- u ? await P({
228
+ u ? await b({
249
229
  productId: d,
250
- shopId: v.id,
251
- productVariantId: t?.id || g
252
- }) : await x({
230
+ shopId: g.id,
231
+ productVariantId: t?.id || v
232
+ }) : await P({
253
233
  productId: d,
254
- shopId: v.id,
255
- productVariantId: t?.id || g
234
+ shopId: g.id,
235
+ productVariantId: t?.id || v
256
236
  });
257
237
  } catch {
258
- k(u), m?.(u);
238
+ j(u), m?.(u);
259
239
  }
260
240
  }, [
261
241
  y,
262
242
  d,
263
- v.id,
243
+ g.id,
264
244
  t?.id,
265
- g,
266
- x,
245
+ v,
267
246
  P,
247
+ b,
268
248
  m
269
249
  ]);
270
250
  return /* @__PURE__ */ p(
271
- X,
251
+ W,
272
252
  {
273
253
  variant: o,
274
- touchable: c,
254
+ touchable: a,
275
255
  onPress: q,
276
256
  children: [
277
- /* @__PURE__ */ p(Y, { variant: o, children: [
278
- /* @__PURE__ */ r(Z, { src: R, alt: T }),
279
- o === "priceOverlay" && s && l && /* @__PURE__ */ r(j, { position: "top-left", children: f(l, s) }),
280
- i && /* @__PURE__ */ r(j, { position: "bottom-left", variant: h, children: i }),
257
+ /* @__PURE__ */ p(X, { variant: o, children: [
258
+ /* @__PURE__ */ r(Y, { src: T, alt: z }),
259
+ o === "priceOverlay" && s && l && /* @__PURE__ */ r(k, { position: "top-left", children: f(l, s) }),
260
+ i && /* @__PURE__ */ r(k, { position: "bottom-left", variant: h, children: i }),
281
261
  /* @__PURE__ */ r(
282
- _,
262
+ Z,
283
263
  {
284
264
  filled: y,
285
265
  onPress: D
286
266
  }
287
267
  )
288
268
  ] }),
289
- /* @__PURE__ */ p($, { variant: o, children: [
290
- /* @__PURE__ */ r(tt, { children: w }),
291
- /* @__PURE__ */ r(rt, { children: L ? /* @__PURE__ */ p(H, { children: [
292
- /* @__PURE__ */ r(S, { children: f(l, s) }),
293
- /* @__PURE__ */ r(et, { children: f(
269
+ /* @__PURE__ */ p(_, { variant: o, children: [
270
+ /* @__PURE__ */ r($, { children: I }),
271
+ /* @__PURE__ */ r(tt, { children: L ? /* @__PURE__ */ p(M, { children: [
272
+ /* @__PURE__ */ r(F, { children: f(l, s) }),
273
+ /* @__PURE__ */ r(rt, { children: f(
294
274
  C,
295
275
  A?.currencyCode || s
296
276
  ) })
297
- ] }) : /* @__PURE__ */ r(S, { children: f(l, s) }) })
277
+ ] }) : /* @__PURE__ */ r(F, { children: f(l, s) }) })
298
278
  ] })
299
279
  ]
300
280
  }
301
281
  );
302
282
  }
303
283
  export {
304
- ht as ProductCard,
305
- j as ProductCardBadge,
306
- S as ProductCardCurrentPrice,
307
- _ as ProductCardFavoriteButton,
308
- Z as ProductCardImage,
309
- Y as ProductCardImageContainer,
310
- $ as ProductCardInfo,
311
- et as ProductCardOriginalPrice,
312
- rt as ProductCardPrice,
313
- X as ProductCardRoot,
314
- tt as ProductCardTitle
284
+ pt as ProductCard
315
285
  };
316
286
  //# 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'\n\nimport {type Product, type ProductVariant} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Heart} from 'lucide-react'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {formatMoney} from '../../lib/formatMoney'\nimport {cn} from '../../lib/utils'\nimport {Badge} from '../atoms/badge'\nimport {Button} from '../atoms/button'\nimport {Touchable} from '../atoms/touchable'\n\nconst productCardVariants = cva(\n 'relative w-full overflow-hidden rounded-xl border border-gray-200',\n {\n variants: {\n variant: {\n default: '',\n priceOverlay: '',\n compact: '',\n },\n touchable: {\n true: 'cursor-pointer',\n false: '',\n },\n },\n defaultVariants: {\n variant: 'default',\n touchable: true,\n },\n }\n)\n\n// Primitive components (building blocks)\nexport interface ProductCardRootProps\n extends React.ComponentProps<'div'>,\n VariantProps<typeof productCardVariants> {\n variant?: 'default' | 'priceOverlay' | 'compact'\n touchable?: boolean\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductCardRoot({\n className,\n variant,\n touchable = true,\n asChild = false,\n onPress,\n ...props\n}: ProductCardRootProps) {\n const Comp = asChild ? SlotPrimitive.Slot : 'div'\n\n const content = (\n <Comp\n className={cn(\n productCardVariants({variant, touchable}),\n 'border-0',\n className\n )}\n {...props}\n />\n )\n\n if (touchable && onPress) {\n return (\n <Touchable\n onClick={onPress}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {content}\n </Touchable>\n )\n }\n\n return content\n}\n\nfunction ProductCardImageContainer({\n className,\n variant = 'default',\n ...props\n}: React.ComponentProps<'div'> & {\n variant?: 'default' | 'priceOverlay' | 'compact'\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({\n className,\n src,\n alt,\n ...props\n}: React.ComponentProps<'img'> & {\n src?: string\n alt?: string\n}) {\n return (\n <div className=\"bg-gray-100 flex items-center justify-center\">\n {src ? (\n <img\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n className={cn('w-full h-full object-cover', className)}\n {...props}\n />\n ) : (\n <div className=\"text-gray-400 text-sm\">No Image</div>\n )}\n </div>\n )\n}\n\nfunction ProductCardBadge({\n className,\n position = 'bottom-left',\n children,\n ...props\n}: React.ComponentProps<typeof Badge> & {\n position?: 'top-left' | 'bottom-left'\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 className={cn('bg-black/50 text-white rounded', className)}\n {...props}\n >\n {children}\n </Badge>\n </div>\n )\n}\n\nfunction ProductCardFavoriteButton({\n className,\n onPress,\n filled = false,\n ...props\n}: React.ComponentProps<'div'> & {\n onPress?: () => void\n filled?: boolean\n}) {\n return (\n <div className={cn('absolute bottom-3 right-3 z-10', className)} {...props}>\n <Button\n onClick={onPress}\n variant=\"secondary\"\n size=\"icon\"\n className={cn(\n 'h-8 w-8 rounded-full border-0 shadow-sm',\n filled ? 'bg-primary' : 'bg-grayscale-l6/60 backdrop-blur-sm'\n )}\n stopPropagation\n >\n <Heart\n fill={filled ? 'currentColor' : 'none'}\n className=\"h-4 w-4 text-white\"\n />\n </Button>\n </div>\n )\n}\n\nfunction ProductCardInfo({\n className,\n variant = 'default',\n ...props\n}: React.ComponentProps<'div'> & {\n variant?: 'default' | 'priceOverlay' | 'compact'\n}) {\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 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}\n </h3>\n )\n}\n\nfunction ProductCardPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-card-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductCardCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-card-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductCardOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-card-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nexport interface ProductCardProps {\n product: Product\n selectedProductVariant?: ProductVariant\n variant?: 'default' | 'priceOverlay' | 'compact'\n touchable?: boolean\n badgeText?: string\n badgeVariant?: 'default' | 'secondary' | 'destructive' | 'outline'\n onFavoriteToggled?: (isFavorited: boolean) => void\n sectionId?: string\n}\n\n// Composed ProductCard component\nfunction ProductCard({\n product,\n selectedProductVariant,\n variant = 'default',\n touchable = true,\n badgeText,\n badgeVariant = 'secondary',\n onFavoriteToggled,\n}: ProductCardProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n const {\n id,\n title,\n featuredImage,\n price,\n compareAtPrice,\n isFavorited,\n defaultVariantId,\n shop,\n } = product\n\n // Use selected variant data if available\n const displayImage = selectedProductVariant?.image || featuredImage\n const displayPrice = selectedProductVariant?.price || price\n const displayCompareAtPrice =\n selectedProductVariant?.compareAtPrice || compareAtPrice\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const currencyCode = displayPrice?.currencyCode\n const amount = displayPrice?.amount\n const imageUrl = displayImage?.url\n const imageAltText = displayImage?.altText || title\n const compareAtPriceAmount = displayCompareAtPrice?.amount\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n if (!touchable) return\n\n navigateToProduct({\n productId: id,\n })\n }, [navigateToProduct, id, touchable])\n\n const handleFavoritePress = React.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: id,\n shopId: shop.id,\n productVariantId: selectedProductVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedProductVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n onFavoriteToggled?.(previousState)\n }\n }, [\n isFavoritedLocal,\n id,\n shop.id,\n selectedProductVariant?.id,\n defaultVariantId,\n saveProduct,\n unsaveProduct,\n onFavoriteToggled,\n ])\n\n return (\n <ProductCardRoot\n variant={variant}\n touchable={touchable}\n onPress={handlePress}\n >\n <ProductCardImageContainer variant={variant}>\n <ProductCardImage src={imageUrl} alt={imageAltText} />\n\n {/* Price overlay badge for priceOverlay variant */}\n {variant === 'priceOverlay' && currencyCode && amount && (\n <ProductCardBadge position=\"top-left\">\n {formatMoney(amount, currencyCode)}\n </ProductCardBadge>\n )}\n\n {/* Custom badge */}\n {badgeText && (\n <ProductCardBadge position=\"bottom-left\" variant={badgeVariant}>\n {badgeText}\n </ProductCardBadge>\n )}\n\n {/* Favorite button */}\n <ProductCardFavoriteButton\n filled={isFavoritedLocal}\n onPress={handleFavoritePress}\n />\n </ProductCardImageContainer>\n\n {/* Product info for default variant */}\n <ProductCardInfo variant={variant}>\n <ProductCardTitle>{title}</ProductCardTitle>\n\n <ProductCardPrice>\n {hasDiscount ? (\n <>\n <ProductCardCurrentPrice>\n {formatMoney(amount, currencyCode)}\n </ProductCardCurrentPrice>\n <ProductCardOriginalPrice>\n {formatMoney(\n compareAtPriceAmount,\n displayCompareAtPrice?.currencyCode || currencyCode\n )}\n </ProductCardOriginalPrice>\n </>\n ) : (\n <ProductCardCurrentPrice>\n {formatMoney(amount, currencyCode)}\n </ProductCardCurrentPrice>\n )}\n </ProductCardPrice>\n </ProductCardInfo>\n </ProductCardRoot>\n )\n}\n\nexport {\n // Composed component\n ProductCard,\n // Primitive components for custom composition\n ProductCardRoot,\n ProductCardImageContainer,\n ProductCardImage,\n ProductCardBadge,\n ProductCardFavoriteButton,\n ProductCardInfo,\n ProductCardTitle,\n ProductCardPrice,\n ProductCardCurrentPrice,\n ProductCardOriginalPrice,\n}\n"],"names":["productCardVariants","cva","ProductCardRoot","className","variant","touchable","asChild","onPress","props","content","jsx","SlotPrimitive.Slot","cn","Touchable","ProductCardImageContainer","ProductCardImage","src","alt","ProductCardBadge","position","children","Badge","ProductCardFavoriteButton","filled","Button","Heart","ProductCardInfo","ProductCardTitle","ProductCardPrice","ProductCardCurrentPrice","ProductCardOriginalPrice","ProductCard","product","selectedProductVariant","badgeText","badgeVariant","onFavoriteToggled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","id","title","featuredImage","price","compareAtPrice","isFavorited","defaultVariantId","shop","displayImage","displayPrice","displayCompareAtPrice","isFavoritedLocal","setIsFavoritedLocal","React","currencyCode","amount","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleFavoritePress","previousState","jsxs","formatMoney","Fragment"],"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'\n\nimport {type Product, type ProductVariant} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Heart} from 'lucide-react'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {formatMoney} from '../../lib/formatMoney'\nimport {cn} from '../../lib/utils'\nimport {FavoriteButton} from '../atoms/favorite-button'\nimport {Touchable} from '../atoms/touchable'\nimport {Badge} from '../ui/badge'\n\nconst productCardVariants = cva(\n 'relative w-full overflow-hidden rounded-xl border border-gray-200',\n {\n variants: {\n variant: {\n default: '',\n priceOverlay: '',\n compact: '',\n },\n touchable: {\n true: 'cursor-pointer',\n false: '',\n },\n },\n defaultVariants: {\n variant: 'default',\n touchable: true,\n },\n }\n)\n\n// Primitive components (building blocks)\nexport interface ProductCardRootProps\n extends React.ComponentProps<'div'>,\n VariantProps<typeof productCardVariants> {\n variant?: 'default' | 'priceOverlay' | 'compact'\n touchable?: boolean\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductCardRoot({\n className,\n variant,\n touchable = true,\n asChild = false,\n onPress,\n ...props\n}: ProductCardRootProps) {\n const Comp = asChild ? SlotPrimitive.Slot : 'div'\n\n const content = (\n <Comp\n className={cn(\n productCardVariants({variant, touchable}),\n 'border-0',\n className\n )}\n {...props}\n />\n )\n\n if (touchable && onPress) {\n return (\n <Touchable\n onClick={onPress}\n whileTap={{opacity: 0.7}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {content}\n </Touchable>\n )\n }\n\n return content\n}\n\nfunction ProductCardImageContainer({\n className,\n variant = 'default',\n ...props\n}: React.ComponentProps<'div'> & {\n variant?: 'default' | 'priceOverlay' | 'compact'\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({\n className,\n src,\n alt,\n ...props\n}: React.ComponentProps<'img'> & {\n src?: string\n alt?: string\n}) {\n return (\n <div className=\"bg-gray-100 flex items-center justify-center\">\n {src ? (\n <img\n data-slot=\"product-card-image\"\n src={src}\n alt={alt}\n className={cn('w-full h-full object-cover', className)}\n {...props}\n />\n ) : (\n <div className=\"text-gray-400 text-sm\">No Image</div>\n )}\n </div>\n )\n}\n\nfunction ProductCardBadge({\n className,\n position = 'bottom-left',\n children,\n ...props\n}: React.ComponentProps<typeof Badge> & {\n position?: 'top-left' | 'bottom-left'\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 className={cn('bg-black/50 text-white rounded', className)}\n {...props}\n >\n {children}\n </Badge>\n </div>\n )\n}\n\nfunction ProductCardFavoriteButton({\n className,\n onPress,\n filled = false,\n ...props\n}: React.ComponentProps<'div'> & {\n onPress?: () => void\n filled?: boolean\n}) {\n return (\n <div className={cn('absolute bottom-3 right-3 z-10', className)} {...props}>\n <FavoriteButton onClick={onPress} filled={filled} />\n </div>\n )\n}\n\nfunction ProductCardInfo({\n className,\n variant = 'default',\n ...props\n}: React.ComponentProps<'div'> & {\n variant?: 'default' | 'priceOverlay' | 'compact'\n}) {\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 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}\n </h3>\n )\n}\n\nfunction ProductCardPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-card-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductCardCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-card-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductCardOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-card-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nexport interface ProductCardProps {\n product: Product\n selectedProductVariant?: ProductVariant\n variant?: 'default' | 'priceOverlay' | 'compact'\n touchable?: boolean\n badgeText?: string\n badgeVariant?: 'default' | 'secondary' | 'destructive' | 'outline'\n onFavoriteToggled?: (isFavorited: boolean) => void\n sectionId?: string\n}\n\n// Composed ProductCard component\nfunction ProductCard({\n product,\n selectedProductVariant,\n variant = 'default',\n touchable = true,\n badgeText,\n badgeVariant = 'secondary',\n onFavoriteToggled,\n}: ProductCardProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n const {\n id,\n title,\n featuredImage,\n price,\n compareAtPrice,\n isFavorited,\n defaultVariantId,\n shop,\n } = product\n\n // Use selected variant data if available\n const displayImage = selectedProductVariant?.image || featuredImage\n const displayPrice = selectedProductVariant?.price || price\n const displayCompareAtPrice =\n selectedProductVariant?.compareAtPrice || compareAtPrice\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const currencyCode = displayPrice?.currencyCode\n const amount = displayPrice?.amount\n const imageUrl = displayImage?.url\n const imageAltText = displayImage?.altText || title\n const compareAtPriceAmount = displayCompareAtPrice?.amount\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n if (!touchable) return\n\n navigateToProduct({\n productId: id,\n })\n }, [navigateToProduct, id, touchable])\n\n const handleFavoritePress = React.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: id,\n shopId: shop.id,\n productVariantId: selectedProductVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedProductVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n onFavoriteToggled?.(previousState)\n }\n }, [\n isFavoritedLocal,\n id,\n shop.id,\n selectedProductVariant?.id,\n defaultVariantId,\n saveProduct,\n unsaveProduct,\n onFavoriteToggled,\n ])\n\n return (\n <ProductCardRoot\n variant={variant}\n touchable={touchable}\n onPress={handlePress}\n >\n <ProductCardImageContainer variant={variant}>\n <ProductCardImage src={imageUrl} alt={imageAltText} />\n\n {/* Price overlay badge for priceOverlay variant */}\n {variant === 'priceOverlay' && currencyCode && amount && (\n <ProductCardBadge position=\"top-left\">\n {formatMoney(amount, currencyCode)}\n </ProductCardBadge>\n )}\n\n {/* Custom badge */}\n {badgeText && (\n <ProductCardBadge position=\"bottom-left\" variant={badgeVariant}>\n {badgeText}\n </ProductCardBadge>\n )}\n\n {/* Favorite button */}\n <ProductCardFavoriteButton\n filled={isFavoritedLocal}\n onPress={handleFavoritePress}\n />\n </ProductCardImageContainer>\n\n {/* Product info for default variant */}\n <ProductCardInfo variant={variant}>\n <ProductCardTitle>{title}</ProductCardTitle>\n\n <ProductCardPrice>\n {hasDiscount ? (\n <>\n <ProductCardCurrentPrice>\n {formatMoney(amount, currencyCode)}\n </ProductCardCurrentPrice>\n <ProductCardOriginalPrice>\n {formatMoney(\n compareAtPriceAmount,\n displayCompareAtPrice?.currencyCode || currencyCode\n )}\n </ProductCardOriginalPrice>\n </>\n ) : (\n <ProductCardCurrentPrice>\n {formatMoney(amount, currencyCode)}\n </ProductCardCurrentPrice>\n )}\n </ProductCardPrice>\n </ProductCardInfo>\n </ProductCardRoot>\n )\n}\n\nexport {ProductCard}\n"],"names":["productCardVariants","cva","ProductCardRoot","className","variant","touchable","asChild","onPress","props","content","jsx","SlotPrimitive.Slot","cn","Touchable","ProductCardImageContainer","ProductCardImage","src","alt","ProductCardBadge","position","children","Badge","ProductCardFavoriteButton","filled","FavoriteButton","ProductCardInfo","ProductCardTitle","ProductCardPrice","ProductCardCurrentPrice","ProductCardOriginalPrice","ProductCard","product","selectedProductVariant","badgeText","badgeVariant","onFavoriteToggled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","id","title","featuredImage","price","compareAtPrice","isFavorited","defaultVariantId","shop","displayImage","displayPrice","displayCompareAtPrice","isFavoritedLocal","setIsFavoritedLocal","React","currencyCode","amount","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleFavoritePress","previousState","jsxs","formatMoney","Fragment"],"mappings":"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"}