@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.
- package/README.md +14 -10
- package/dist/_virtual/index2.js +3 -2
- package/dist/_virtual/index2.js.map +1 -1
- package/dist/_virtual/index3.js +2 -3
- package/dist/_virtual/index3.js.map +1 -1
- package/dist/components/atoms/button.js +28 -73
- package/dist/components/atoms/button.js.map +1 -1
- package/dist/components/atoms/favorite-button.js +21 -0
- package/dist/components/atoms/favorite-button.js.map +1 -0
- package/dist/components/atoms/icon-button.js +38 -0
- package/dist/components/atoms/icon-button.js.map +1 -0
- package/dist/components/atoms/touchable.js +14 -14
- package/dist/components/atoms/touchable.js.map +1 -1
- package/dist/components/commerce/merchant-card.js +1 -8
- package/dist/components/commerce/merchant-card.js.map +1 -1
- package/dist/components/commerce/product-card.js +79 -109
- package/dist/components/commerce/product-card.js.map +1 -1
- package/dist/components/commerce/product-link.js +36 -55
- package/dist/components/commerce/product-link.js.map +1 -1
- package/dist/components/ui/accordion.js.map +1 -0
- package/dist/components/{atoms → ui}/alert-dialog.js +1 -1
- package/dist/components/ui/alert-dialog.js.map +1 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/button.js +68 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/{atoms → ui}/carousel.js +23 -23
- package/dist/components/ui/carousel.js.map +1 -0
- package/dist/components/ui/checkbox.js.map +1 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/{atoms → ui}/drawer.js +25 -22
- package/dist/components/ui/drawer.js.map +1 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/label.js.map +1 -0
- package/dist/components/ui/progress.js.map +1 -0
- package/dist/components/ui/radio-group.js.map +1 -0
- package/dist/components/ui/resizable.js.map +1 -0
- package/dist/components/ui/scroll-area.js.map +1 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/separator.js.map +1 -0
- package/dist/components/ui/sheet.js.map +1 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/index.js +193 -218
- package/dist/index.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/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
- package/package.json +6 -9
- package/src/components/atoms/button.tsx +10 -66
- package/src/components/atoms/favorite-button.tsx +22 -0
- package/src/components/atoms/icon-button.tsx +42 -0
- package/src/components/atoms/touchable.tsx +5 -1
- package/src/components/commerce/merchant-card.tsx +1 -12
- package/src/components/commerce/product-card.tsx +4 -32
- package/src/components/commerce/product-link.tsx +9 -29
- package/src/components/index.ts +23 -20
- package/src/components/{atoms → ui}/alert-dialog.tsx +1 -1
- package/src/components/ui/button.tsx +77 -0
- package/src/components/{atoms → ui}/carousel.tsx +11 -11
- package/src/components/{atoms → ui}/drawer.tsx +2 -1
- package/src/index.css +8 -2
- package/src/styles/globals.css +41 -0
- package/src/styles/theme.css +102 -0
- package/dist/components/atoms/accordion.js.map +0 -1
- package/dist/components/atoms/alert-dialog.js.map +0 -1
- package/dist/components/atoms/alert.js.map +0 -1
- package/dist/components/atoms/avatar.js.map +0 -1
- package/dist/components/atoms/badge.js.map +0 -1
- package/dist/components/atoms/card.js.map +0 -1
- package/dist/components/atoms/carousel.js.map +0 -1
- package/dist/components/atoms/checkbox.js.map +0 -1
- package/dist/components/atoms/dialog.js.map +0 -1
- package/dist/components/atoms/drawer.js.map +0 -1
- package/dist/components/atoms/input.js.map +0 -1
- package/dist/components/atoms/label.js.map +0 -1
- package/dist/components/atoms/progress.js.map +0 -1
- package/dist/components/atoms/radio-group.js.map +0 -1
- package/dist/components/atoms/resizable.js.map +0 -1
- package/dist/components/atoms/scroll-area.js.map +0 -1
- package/dist/components/atoms/select.js.map +0 -1
- package/dist/components/atoms/separator.js.map +0 -1
- package/dist/components/atoms/sheet.js.map +0 -1
- package/dist/components/atoms/sonner.js.map +0 -1
- package/src/base.css +0 -273
- package/tailwind.config.js +0 -3
- /package/dist/components/{atoms → ui}/accordion.js +0 -0
- /package/dist/components/{atoms → ui}/alert.js +0 -0
- /package/dist/components/{atoms → ui}/avatar.js +0 -0
- /package/dist/components/{atoms → ui}/badge.js +0 -0
- /package/dist/components/{atoms → ui}/card.js +0 -0
- /package/dist/components/{atoms → ui}/checkbox.js +0 -0
- /package/dist/components/{atoms → ui}/dialog.js +0 -0
- /package/dist/components/{atoms → ui}/input.js +0 -0
- /package/dist/components/{atoms → ui}/label.js +0 -0
- /package/dist/components/{atoms → ui}/progress.js +0 -0
- /package/dist/components/{atoms → ui}/radio-group.js +0 -0
- /package/dist/components/{atoms → ui}/resizable.js +0 -0
- /package/dist/components/{atoms → ui}/scroll-area.js +0 -0
- /package/dist/components/{atoms → ui}/select.js +0 -0
- /package/dist/components/{atoms → ui}/separator.js +0 -0
- /package/dist/components/{atoms → ui}/sheet.js +0 -0
- /package/dist/components/{atoms → ui}/sonner.js +0 -0
- /package/src/components/{atoms → ui}/accordion.tsx +0 -0
- /package/src/components/{atoms → ui}/alert.tsx +0 -0
- /package/src/components/{atoms → ui}/avatar.tsx +0 -0
- /package/src/components/{atoms → ui}/badge.tsx +0 -0
- /package/src/components/{atoms → ui}/card.tsx +0 -0
- /package/src/components/{atoms → ui}/checkbox.tsx +0 -0
- /package/src/components/{atoms → ui}/dialog.tsx +0 -0
- /package/src/components/{atoms → ui}/input.tsx +0 -0
- /package/src/components/{atoms → ui}/label.tsx +0 -0
- /package/src/components/{atoms → ui}/progress.tsx +0 -0
- /package/src/components/{atoms → ui}/radio-group.tsx +0 -0
- /package/src/components/{atoms → ui}/resizable.tsx +0 -0
- /package/src/components/{atoms → ui}/scroll-area.tsx +0 -0
- /package/src/components/{atoms → ui}/select.tsx +0 -0
- /package/src/components/{atoms → ui}/separator.tsx +0 -0
- /package/src/components/{atoms → ui}/sheet.tsx +0 -0
- /package/src/components/{atoms → ui}/sonner.tsx +0 -0
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { jsxs as p, jsx as r, Fragment as
|
|
2
|
-
import * as
|
|
3
|
-
import { cva as
|
|
4
|
-
import { useShopNavigation as
|
|
5
|
-
import { useSavedProductsActions as
|
|
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
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import Q from "../../shop-minis-react/node_modules/.pnpm
|
|
12
|
-
|
|
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
|
|
32
|
+
function W({
|
|
34
33
|
className: e,
|
|
35
34
|
variant: t,
|
|
36
35
|
touchable: o = !0,
|
|
37
|
-
asChild:
|
|
36
|
+
asChild: a = !1,
|
|
38
37
|
onPress: i,
|
|
39
38
|
...h
|
|
40
39
|
}) {
|
|
41
40
|
const n = /* @__PURE__ */ r(
|
|
42
|
-
|
|
41
|
+
a ? Q : "div",
|
|
43
42
|
{
|
|
44
|
-
className:
|
|
45
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
84
|
+
function Y({
|
|
86
85
|
className: e,
|
|
87
86
|
src: t,
|
|
88
87
|
alt: o,
|
|
89
|
-
...
|
|
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:
|
|
98
|
-
...
|
|
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
|
|
101
|
+
function k({
|
|
103
102
|
className: e,
|
|
104
103
|
position: t = "bottom-left",
|
|
105
104
|
children: o,
|
|
106
|
-
...
|
|
105
|
+
...a
|
|
107
106
|
}) {
|
|
108
107
|
return /* @__PURE__ */ r(
|
|
109
108
|
"div",
|
|
110
109
|
{
|
|
111
|
-
className:
|
|
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
|
-
|
|
115
|
+
K,
|
|
117
116
|
{
|
|
118
|
-
className:
|
|
119
|
-
...
|
|
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
|
-
...
|
|
129
|
+
...a
|
|
131
130
|
}) {
|
|
132
|
-
return /* @__PURE__ */ r("div", { className:
|
|
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:
|
|
142
|
+
className: c("px-1 pt-2 pb-0 space-y-1", e),
|
|
163
143
|
...o
|
|
164
144
|
}
|
|
165
145
|
);
|
|
166
146
|
}
|
|
167
|
-
function
|
|
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:
|
|
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
|
|
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:
|
|
171
|
+
className: c("flex items-center gap-2", e),
|
|
192
172
|
...t
|
|
193
173
|
}
|
|
194
174
|
);
|
|
195
175
|
}
|
|
196
|
-
function
|
|
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:
|
|
184
|
+
className: c("text-sm font-semibold text-gray-900", e),
|
|
205
185
|
...t
|
|
206
186
|
}
|
|
207
187
|
);
|
|
208
188
|
}
|
|
209
|
-
function
|
|
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:
|
|
197
|
+
className: c("text-sm text-gray-500 line-through", e),
|
|
218
198
|
...t
|
|
219
199
|
}
|
|
220
200
|
);
|
|
221
201
|
}
|
|
222
|
-
function
|
|
202
|
+
function pt({
|
|
223
203
|
product: e,
|
|
224
204
|
selectedProductVariant: t,
|
|
225
205
|
variant: o = "default",
|
|
226
|
-
touchable:
|
|
206
|
+
touchable: a = !0,
|
|
227
207
|
badgeText: i,
|
|
228
208
|
badgeVariant: h = "secondary",
|
|
229
209
|
onFavoriteToggled: m
|
|
230
210
|
}) {
|
|
231
|
-
const { navigateToProduct: n } =
|
|
211
|
+
const { navigateToProduct: n } = E(), { saveProduct: P, unsaveProduct: b } = G(), {
|
|
232
212
|
id: d,
|
|
233
|
-
title:
|
|
234
|
-
featuredImage:
|
|
235
|
-
price:
|
|
213
|
+
title: I,
|
|
214
|
+
featuredImage: S,
|
|
215
|
+
price: B,
|
|
236
216
|
compareAtPrice: O,
|
|
237
|
-
isFavorited:
|
|
238
|
-
defaultVariantId:
|
|
239
|
-
shop:
|
|
240
|
-
} = e, N = t?.image ||
|
|
241
|
-
|
|
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,
|
|
224
|
+
}, [n, d, a]), D = x.useCallback(async () => {
|
|
245
225
|
const u = y;
|
|
246
|
-
|
|
226
|
+
j(!u), m?.(!u);
|
|
247
227
|
try {
|
|
248
|
-
u ? await
|
|
228
|
+
u ? await b({
|
|
249
229
|
productId: d,
|
|
250
|
-
shopId:
|
|
251
|
-
productVariantId: t?.id ||
|
|
252
|
-
}) : await
|
|
230
|
+
shopId: g.id,
|
|
231
|
+
productVariantId: t?.id || v
|
|
232
|
+
}) : await P({
|
|
253
233
|
productId: d,
|
|
254
|
-
shopId:
|
|
255
|
-
productVariantId: t?.id ||
|
|
234
|
+
shopId: g.id,
|
|
235
|
+
productVariantId: t?.id || v
|
|
256
236
|
});
|
|
257
237
|
} catch {
|
|
258
|
-
|
|
238
|
+
j(u), m?.(u);
|
|
259
239
|
}
|
|
260
240
|
}, [
|
|
261
241
|
y,
|
|
262
242
|
d,
|
|
263
|
-
|
|
243
|
+
g.id,
|
|
264
244
|
t?.id,
|
|
265
|
-
|
|
266
|
-
x,
|
|
245
|
+
v,
|
|
267
246
|
P,
|
|
247
|
+
b,
|
|
268
248
|
m
|
|
269
249
|
]);
|
|
270
250
|
return /* @__PURE__ */ p(
|
|
271
|
-
|
|
251
|
+
W,
|
|
272
252
|
{
|
|
273
253
|
variant: o,
|
|
274
|
-
touchable:
|
|
254
|
+
touchable: a,
|
|
275
255
|
onPress: q,
|
|
276
256
|
children: [
|
|
277
|
-
/* @__PURE__ */ p(
|
|
278
|
-
/* @__PURE__ */ r(
|
|
279
|
-
o === "priceOverlay" && s && l && /* @__PURE__ */ r(
|
|
280
|
-
i && /* @__PURE__ */ r(
|
|
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(
|
|
290
|
-
/* @__PURE__ */ r(
|
|
291
|
-
/* @__PURE__ */ r(
|
|
292
|
-
/* @__PURE__ */ r(
|
|
293
|
-
/* @__PURE__ */ r(
|
|
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(
|
|
277
|
+
] }) : /* @__PURE__ */ r(F, { children: f(l, s) }) })
|
|
298
278
|
] })
|
|
299
279
|
]
|
|
300
280
|
}
|
|
301
281
|
);
|
|
302
282
|
}
|
|
303
283
|
export {
|
|
304
|
-
|
|
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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"}
|