@shopify/shop-minis-react 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,17 @@
1
- import { jsxs as y, jsx as t, Fragment as S } from "react/jsx-runtime";
1
+ import { jsx as t, jsxs as y, Fragment as V } from "react/jsx-runtime";
2
2
  import * as P from "react";
3
- import { cva as q } 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 B } from "../../hooks/navigation/useShopNavigation.js";
5
- import { useSavedProductsActions as M } from "../../hooks/user/useSavedProductsActions.js";
6
- import { ProductReviewStars as U } from "../../internal/components/product-review-stars.js";
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";
6
+ import { ProductReviewStars as G } from "../../internal/components/product-review-stars.js";
7
+ import { useProductImpression as H } from "../../internal/useProductImpression.js";
7
8
  import { cn as n } from "../../lib/utils.js";
8
- import { formatMoney as T } from "../../utils/formatMoney.js";
9
- import { Touchable as V } from "../atoms/touchable.js";
10
- import { Card as E, CardContent as G, CardAction as H } from "../ui/card.js";
11
- import { FavoriteButton as J } from "./favorite-button.js";
12
- import { Root as K } 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 Q = q("", {
9
+ import { formatMoney as S } from "../../utils/formatMoney.js";
10
+ import { Touchable as A } from "../atoms/touchable.js";
11
+ import { Card as J, CardContent as K, CardAction as Q } from "../ui/card.js";
12
+ import { FavoriteButton as W } from "./favorite-button.js";
13
+ import { Root as X } 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";
14
+ const Y = M("", {
14
15
  variants: {
15
16
  layout: {
16
17
  horizontal: "w-full !flex-row items-center gap-3 px-4 py-3",
@@ -27,16 +28,16 @@ const Q = q("", {
27
28
  discount: "none"
28
29
  }
29
30
  });
30
- function W({
31
+ function Z({
31
32
  className: e,
32
- layout: o,
33
- discount: r,
33
+ layout: r,
34
+ discount: o,
34
35
  asChild: i = !1,
35
36
  onPress: a,
36
37
  ...c
37
38
  }) {
38
39
  return /* @__PURE__ */ t(
39
- V,
40
+ A,
40
41
  {
41
42
  onClick: a,
42
43
  whileTap: { opacity: 0.7 },
@@ -44,10 +45,10 @@ function W({
44
45
  opacity: { type: "tween", duration: 0.08, ease: "easeInOut" }
45
46
  },
46
47
  children: /* @__PURE__ */ t(
47
- i ? K : E,
48
+ i ? X : J,
48
49
  {
49
50
  className: n(
50
- Q({ layout: o, discount: r }),
51
+ Y({ layout: r, discount: o }),
51
52
  "border-0 bg-white rounded-xl shadow-lg shadow-black/10",
52
53
  e
53
54
  ),
@@ -57,10 +58,10 @@ function W({
57
58
  }
58
59
  );
59
60
  }
60
- function X({
61
+ function _({
61
62
  className: e,
62
- layout: o = "horizontal",
63
- ...r
63
+ layout: r = "horizontal",
64
+ ...o
64
65
  }) {
65
66
  return /* @__PURE__ */ t(
66
67
  "div",
@@ -68,33 +69,33 @@ function X({
68
69
  "data-slot": "product-link-image",
69
70
  className: n(
70
71
  "overflow-hidden rounded-md bg-muted",
71
- o === "horizontal" ? "h-16 w-16 flex-shrink-0" : "aspect-square w-full",
72
+ r === "horizontal" ? "h-16 w-16 flex-shrink-0" : "aspect-square w-full",
72
73
  e
73
74
  ),
74
- ...r
75
+ ...o
75
76
  }
76
77
  );
77
78
  }
78
- function Y({
79
+ function $({
79
80
  className: e,
80
- layout: o = "horizontal",
81
- ...r
81
+ layout: r = "horizontal",
82
+ ...o
82
83
  }) {
83
84
  return /* @__PURE__ */ t(
84
- G,
85
+ K,
85
86
  {
86
87
  className: n(
87
- o === "horizontal" ? "flex-1 min-w-0 space-y-1 px-0 py-0" : "space-y-2",
88
+ r === "horizontal" ? "flex-1 min-w-0 space-y-1 px-0 py-0" : "space-y-2",
88
89
  e
89
90
  ),
90
- ...r
91
+ ...o
91
92
  }
92
93
  );
93
94
  }
94
- function Z({
95
+ function tt({
95
96
  className: e,
96
- children: o,
97
- ...r
97
+ children: r,
98
+ ...o
98
99
  }) {
99
100
  return /* @__PURE__ */ t(
100
101
  "h3",
@@ -104,132 +105,136 @@ function Z({
104
105
  "text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis",
105
106
  e
106
107
  ),
107
- ...r,
108
- children: o
108
+ ...o,
109
+ children: r
109
110
  }
110
111
  );
111
112
  }
112
- function _({ className: e, ...o }) {
113
+ function et({ className: e, ...r }) {
113
114
  return /* @__PURE__ */ t(
114
115
  "div",
115
116
  {
116
117
  "data-slot": "product-link-price",
117
118
  className: n("flex items-center gap-2", e),
118
- ...o
119
+ ...r
119
120
  }
120
121
  );
121
122
  }
122
- function $({
123
+ function rt({
123
124
  className: e,
124
- ...o
125
+ ...r
125
126
  }) {
126
127
  return /* @__PURE__ */ t(
127
128
  "span",
128
129
  {
129
130
  "data-slot": "product-link-current-price",
130
131
  className: n("text-sm font-semibold text-gray-900", e),
131
- ...o
132
+ ...r
132
133
  }
133
134
  );
134
135
  }
135
- function tt({
136
+ function ot({
136
137
  className: e,
137
- ...o
138
+ ...r
138
139
  }) {
139
140
  return /* @__PURE__ */ t(
140
141
  "span",
141
142
  {
142
143
  "data-slot": "product-link-original-price",
143
144
  className: n("text-sm text-gray-500 line-through", e),
144
- ...o
145
+ ...r
145
146
  }
146
147
  );
147
148
  }
148
- function et({
149
+ function nt({
149
150
  className: e,
150
- ...o
151
+ ...r
151
152
  }) {
152
153
  return /* @__PURE__ */ t(
153
154
  "span",
154
155
  {
155
156
  "data-slot": "product-link-discount-price",
156
157
  className: n("text-sm font-semibold text-red-600", e),
157
- ...o
158
+ ...r
158
159
  }
159
160
  );
160
161
  }
161
- function ot({ className: e, ...o }) {
162
+ function at({ className: e, ...r }) {
162
163
  return /* @__PURE__ */ t(
163
164
  "div",
164
165
  {
165
166
  "data-slot": "product-link-rating",
166
167
  className: n("", e),
167
- ...o
168
+ ...r
168
169
  }
169
170
  );
170
171
  }
171
- function rt({
172
+ function it({
172
173
  className: e,
173
- hideFavoriteAction: o = !1,
174
- onPress: r,
174
+ hideFavoriteAction: r = !1,
175
+ onPress: o,
175
176
  filled: i = !1,
176
177
  customAction: a,
177
178
  ...c
178
179
  }) {
179
- const l = o ? null : /* @__PURE__ */ t(J, { filled: i, onClick: r });
180
+ const l = r ? null : /* @__PURE__ */ t(W, { filled: i, onClick: o });
180
181
  return /* @__PURE__ */ t(
181
- H,
182
+ Q,
182
183
  {
183
184
  className: n("flex-shrink-0 self-center px-0 py-0", e),
184
185
  ...c,
185
186
  children: /* @__PURE__ */ t(
186
- V,
187
+ A,
187
188
  {
188
189
  stopPropagation: !0,
189
- onClick: r,
190
+ onClick: o,
190
191
  whileTap: { opacity: 0.7, scale: 0.95 },
191
192
  transition: {
192
193
  opacity: { type: "tween", duration: 0.08, ease: "easeInOut" },
193
194
  scale: { type: "tween", duration: 0.08, ease: "easeInOut" }
194
195
  },
195
- children: a ? /* @__PURE__ */ t(S, { children: a }) : l
196
+ children: a ? /* @__PURE__ */ t(V, { children: a }) : l
196
197
  }
197
198
  )
198
199
  }
199
200
  );
200
201
  }
201
- function gt({
202
+ function Pt({
202
203
  product: e,
203
- hideFavoriteAction: o = !1,
204
- onClick: r,
204
+ hideFavoriteAction: r = !1,
205
+ onClick: o,
205
206
  customAction: i,
206
207
  onCustomActionClick: a,
207
- reviewsDisabled: c = !1
208
+ reviewsDisabled: c = !1,
209
+ impressionTrackingDisabled: l = !1
208
210
  }) {
209
- const { navigateToProduct: l } = B(), { saveProduct: w, unsaveProduct: k } = M(), {
211
+ const { navigateToProduct: k } = U(), { saveProduct: w, unsaveProduct: I } = E(), { ref: F } = H({
212
+ productId: e.id,
213
+ skip: l
214
+ }), {
210
215
  id: s,
211
- title: I,
212
- featuredImage: L,
213
- reviewAnalytics: N,
216
+ title: L,
217
+ featuredImage: N,
218
+ reviewAnalytics: b,
214
219
  price: d,
215
220
  compareAtPrice: u,
216
- isFavorited: A,
221
+ isFavorited: j,
217
222
  selectedVariant: m,
218
223
  defaultVariantId: p,
219
224
  shop: f
220
- } = e, [h, b] = P.useState(A), C = N?.averageRating, F = N?.reviewCount, g = d?.amount ? T(d?.amount, d?.currencyCode) : void 0, z = L?.url, j = L?.altText || I, v = u?.amount ? T(u?.amount, u?.currencyCode) : void 0, R = v && v !== g, O = P.useCallback(() => {
221
- l({
225
+ } = e, [h, C] = P.useState(j), z = b?.averageRating, O = b?.reviewCount, g = d?.amount ? S(d?.amount, d?.currencyCode) : void 0, R = N?.url, D = N?.altText || L, v = u?.amount ? S(u?.amount, u?.currencyCode) : void 0, T = v && v !== g, q = P.useCallback(() => {
226
+ k({
222
227
  productId: s
223
- }), r?.(e);
224
- }, [l, s, r, e]), D = P.useCallback(async () => {
228
+ }), o?.(e);
229
+ }, [k, s, o, e]), B = P.useCallback(async () => {
225
230
  if (i || a) {
226
231
  a?.();
227
232
  return;
228
233
  }
229
234
  const x = h;
230
- b(!x);
235
+ C(!x);
231
236
  try {
232
- x ? await k({
237
+ x ? await I({
233
238
  productId: s,
234
239
  shopId: f.id,
235
240
  productVariantId: m?.id || p
@@ -239,62 +244,62 @@ function gt({
239
244
  productVariantId: m?.id || p
240
245
  });
241
246
  } catch {
242
- b(x);
247
+ C(x);
243
248
  }
244
249
  }, [
245
250
  i,
246
251
  a,
247
252
  h,
248
- k,
253
+ I,
249
254
  s,
250
255
  f.id,
251
256
  m?.id,
252
257
  p,
253
258
  w
254
259
  ]);
255
- return /* @__PURE__ */ y(
256
- W,
260
+ return /* @__PURE__ */ t("div", { ref: F, children: /* @__PURE__ */ y(
261
+ Z,
257
262
  {
258
263
  layout: "horizontal",
259
- discount: R ? "small" : "none",
260
- onPress: O,
264
+ discount: T ? "small" : "none",
265
+ onPress: q,
261
266
  children: [
262
- /* @__PURE__ */ t(X, { layout: "horizontal", children: z ? /* @__PURE__ */ t(
267
+ /* @__PURE__ */ t(_, { layout: "horizontal", children: R ? /* @__PURE__ */ t(
263
268
  "img",
264
269
  {
265
- src: z,
266
- alt: j,
270
+ src: R,
271
+ alt: D,
267
272
  className: "h-full w-full object-cover"
268
273
  }
269
274
  ) : /* @__PURE__ */ t("div", { className: "h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs", children: "No Image" }) }),
270
- /* @__PURE__ */ y(Y, { layout: "horizontal", children: [
271
- /* @__PURE__ */ t(Z, { children: I }),
272
- C && !c ? /* @__PURE__ */ t(ot, { children: /* @__PURE__ */ t(
273
- U,
275
+ /* @__PURE__ */ y($, { layout: "horizontal", children: [
276
+ /* @__PURE__ */ t(tt, { children: L }),
277
+ z && !c ? /* @__PURE__ */ t(at, { children: /* @__PURE__ */ t(
278
+ G,
274
279
  {
275
- averageRating: C,
276
- reviewCount: F
280
+ averageRating: z,
281
+ reviewCount: O
277
282
  }
278
283
  ) }) : null,
279
- /* @__PURE__ */ t(_, { children: R ? /* @__PURE__ */ y(S, { children: [
280
- /* @__PURE__ */ t(et, { children: g }),
281
- /* @__PURE__ */ t(tt, { children: v })
282
- ] }) : /* @__PURE__ */ t($, { children: g }) })
284
+ /* @__PURE__ */ t(et, { children: T ? /* @__PURE__ */ y(V, { children: [
285
+ /* @__PURE__ */ t(nt, { children: g }),
286
+ /* @__PURE__ */ t(ot, { children: v })
287
+ ] }) : /* @__PURE__ */ t(rt, { children: g }) })
283
288
  ] }),
284
289
  /* @__PURE__ */ t(
285
- rt,
290
+ it,
286
291
  {
287
292
  filled: h,
288
- onPress: D,
293
+ onPress: B,
289
294
  customAction: i,
290
- hideFavoriteAction: o
295
+ hideFavoriteAction: r
291
296
  }
292
297
  )
293
298
  ]
294
299
  }
295
- );
300
+ ) });
296
301
  }
297
302
  export {
298
- gt as ProductLink
303
+ Pt as ProductLink
299
304
  };
300
305
  //# sourceMappingURL=product-link.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"product-link.js","sources":["../../../src/components/commerce/product-link.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {type Product} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\nimport {Touchable} from '../atoms/touchable'\nimport {Card, CardContent, CardAction} from '../ui/card'\n\nimport {FavoriteButton} from './favorite-button'\n\nconst productLinkVariants = cva('', {\n variants: {\n layout: {\n horizontal: 'w-full !flex-row items-center gap-3 px-4 py-3',\n vertical: 'flex-col',\n },\n discount: {\n none: '',\n small: '',\n large: '',\n },\n },\n defaultVariants: {\n layout: 'horizontal',\n discount: 'none',\n },\n})\n\n// Primitive components (building blocks)\nexport interface ProductLinkRootProps\n extends React.ComponentProps<typeof Card>,\n VariantProps<typeof productLinkVariants> {\n layout?: 'horizontal' | 'vertical'\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductLinkRoot({\n className,\n layout,\n discount,\n asChild = false,\n onPress,\n ...props\n}: ProductLinkRootProps) {\n const Comp = asChild ? SlotPrimitive.Root : Card\n\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 <Comp\n className={cn(\n productLinkVariants({layout, discount}),\n 'border-0 bg-white rounded-xl shadow-lg shadow-black/10',\n className\n )}\n {...props}\n />\n </Touchable>\n )\n}\n\nfunction ProductLinkImage({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<'div'> & {layout?: 'horizontal' | 'vertical'}) {\n return (\n <div\n data-slot=\"product-link-image\"\n className={cn(\n 'overflow-hidden rounded-md bg-muted',\n layout === 'horizontal'\n ? 'h-16 w-16 flex-shrink-0'\n : 'aspect-square w-full',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkInfo({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<typeof CardContent> & {\n layout?: 'horizontal' | 'vertical'\n}) {\n return (\n <CardContent\n className={cn(\n layout === 'horizontal'\n ? 'flex-1 min-w-0 space-y-1 px-0 py-0'\n : 'space-y-2',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"product-link-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children}\n </h3>\n )\n}\n\nfunction ProductLinkPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkDiscountPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-discount-price\"\n className={cn('text-sm font-semibold text-red-600', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkRating({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-rating\"\n className={cn('', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkActions({\n className,\n hideFavoriteAction = false,\n onPress,\n filled = false,\n customAction,\n ...props\n}: React.ComponentProps<typeof CardAction> & {\n hideFavoriteAction?: boolean\n onPress?: () => void\n filled?: boolean\n customAction?: React.ReactNode\n}) {\n const favoriteAction = hideFavoriteAction ? null : (\n <FavoriteButton filled={filled} onClick={onPress} />\n )\n\n return (\n <CardAction\n className={cn('flex-shrink-0 self-center px-0 py-0', className)}\n {...props}\n >\n <Touchable\n stopPropagation\n onClick={onPress}\n whileTap={{opacity: 0.7, scale: 0.95}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n scale: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {customAction ? <>{customAction}</> : favoriteAction}\n </Touchable>\n </CardAction>\n )\n}\n\nexport interface ProductLinkDocProps {\n /** The product to display */\n product: Product\n /** Hide the favorite/save button */\n hideFavoriteAction?: boolean\n /** Callback when the product link is clicked */\n onClick?: (product: Product) => void\n /** Hide the review stars */\n reviewsDisabled?: boolean\n /** Custom action element to replace the favorite button. Must be provided with `onCustomActionClick`. */\n customAction?: React.ReactNode\n /** Callback when the custom action is clicked. Must be provided with `customAction`. */\n onCustomActionClick?: () => void\n}\n\nexport type ProductLinkProps = {\n product: Product\n hideFavoriteAction?: boolean\n onClick?: (product: Product) => void\n reviewsDisabled?: boolean\n} & (\n | {\n customAction?: never\n onCustomActionClick?: never\n }\n | {\n customAction: React.ReactNode\n onCustomActionClick: () => void\n }\n)\n\n// Composed ProductLink component\nfunction ProductLink({\n product,\n hideFavoriteAction = false,\n onClick,\n customAction,\n onCustomActionClick,\n reviewsDisabled = false,\n}: ProductLinkProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n\n const {\n id,\n title,\n featuredImage,\n reviewAnalytics,\n price,\n compareAtPrice,\n isFavorited,\n selectedVariant,\n defaultVariantId,\n shop,\n } = product\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const averageRating = reviewAnalytics?.averageRating\n const reviewCount = reviewAnalytics?.reviewCount\n const amount = price?.amount\n ? formatMoney(price?.amount, price?.currencyCode)\n : undefined\n const imageUrl = featuredImage?.url\n const imageAltText = featuredImage?.altText || title\n const compareAtPriceAmount = compareAtPrice?.amount\n ? formatMoney(compareAtPrice?.amount, compareAtPrice?.currencyCode)\n : undefined\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n navigateToProduct({\n productId: id,\n })\n onClick?.(product)\n }, [navigateToProduct, id, onClick, product])\n\n const handleActionPress = React.useCallback(async () => {\n if (customAction || onCustomActionClick) {\n onCustomActionClick?.()\n return\n }\n\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n }\n }, [\n customAction,\n onCustomActionClick,\n isFavoritedLocal,\n unsaveProduct,\n id,\n shop.id,\n selectedVariant?.id,\n defaultVariantId,\n saveProduct,\n ])\n\n return (\n <ProductLinkRoot\n layout=\"horizontal\"\n discount={hasDiscount ? 'small' : 'none'}\n onPress={handlePress}\n >\n <ProductLinkImage layout=\"horizontal\">\n {imageUrl ? (\n <img\n src={imageUrl}\n alt={imageAltText}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs\">\n No Image\n </div>\n )}\n </ProductLinkImage>\n\n <ProductLinkInfo layout=\"horizontal\">\n <ProductLinkTitle>{title}</ProductLinkTitle>\n\n {averageRating && !reviewsDisabled ? (\n <ProductLinkRating>\n <ProductReviewStars\n averageRating={averageRating}\n reviewCount={reviewCount}\n />\n </ProductLinkRating>\n ) : null}\n\n <ProductLinkPrice>\n {hasDiscount ? (\n <>\n <ProductLinkDiscountPrice>{amount}</ProductLinkDiscountPrice>\n <ProductLinkOriginalPrice>\n {compareAtPriceAmount}\n </ProductLinkOriginalPrice>\n </>\n ) : (\n <ProductLinkCurrentPrice>{amount}</ProductLinkCurrentPrice>\n )}\n </ProductLinkPrice>\n </ProductLinkInfo>\n\n <ProductLinkActions\n filled={isFavoritedLocal}\n onPress={handleActionPress}\n customAction={customAction}\n hideFavoriteAction={hideFavoriteAction}\n />\n </ProductLinkRoot>\n )\n}\n\nexport {ProductLink}\n"],"names":["productLinkVariants","cva","ProductLinkRoot","className","layout","discount","asChild","onPress","props","jsx","Touchable","SlotPrimitive.Root","Card","cn","ProductLinkImage","ProductLinkInfo","CardContent","ProductLinkTitle","children","ProductLinkPrice","ProductLinkCurrentPrice","ProductLinkOriginalPrice","ProductLinkDiscountPrice","ProductLinkRating","ProductLinkActions","hideFavoriteAction","filled","customAction","favoriteAction","FavoriteButton","CardAction","Fragment","ProductLink","product","onClick","onCustomActionClick","reviewsDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","id","title","featuredImage","reviewAnalytics","price","compareAtPrice","isFavorited","selectedVariant","defaultVariantId","shop","isFavoritedLocal","setIsFavoritedLocal","React","averageRating","reviewCount","amount","formatMoney","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleActionPress","previousState","jsxs","ProductReviewStars"],"mappings":"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"}
1
+ {"version":3,"file":"product-link.js","sources":["../../../src/components/commerce/product-link.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport {type Product} from '@shopify/shop-minis-platform'\nimport {cva, type VariantProps} from 'class-variance-authority'\nimport {Slot as SlotPrimitive} from 'radix-ui'\n\nimport {useShopNavigation} from '../../hooks/navigation/useShopNavigation'\nimport {useSavedProductsActions} from '../../hooks/user/useSavedProductsActions'\nimport {ProductReviewStars} from '../../internal/components/product-review-stars'\nimport {useProductImpression} from '../../internal/useProductImpression'\nimport {cn} from '../../lib/utils'\nimport {formatMoney} from '../../utils/formatMoney'\nimport {Touchable} from '../atoms/touchable'\nimport {Card, CardContent, CardAction} from '../ui/card'\n\nimport {FavoriteButton} from './favorite-button'\n\nconst productLinkVariants = cva('', {\n variants: {\n layout: {\n horizontal: 'w-full !flex-row items-center gap-3 px-4 py-3',\n vertical: 'flex-col',\n },\n discount: {\n none: '',\n small: '',\n large: '',\n },\n },\n defaultVariants: {\n layout: 'horizontal',\n discount: 'none',\n },\n})\n\n// Primitive components (building blocks)\nexport interface ProductLinkRootProps\n extends React.ComponentProps<typeof Card>,\n VariantProps<typeof productLinkVariants> {\n layout?: 'horizontal' | 'vertical'\n asChild?: boolean\n onPress?: () => void\n}\n\nfunction ProductLinkRoot({\n className,\n layout,\n discount,\n asChild = false,\n onPress,\n ...props\n}: ProductLinkRootProps) {\n const Comp = asChild ? SlotPrimitive.Root : Card\n\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 <Comp\n className={cn(\n productLinkVariants({layout, discount}),\n 'border-0 bg-white rounded-xl shadow-lg shadow-black/10',\n className\n )}\n {...props}\n />\n </Touchable>\n )\n}\n\nfunction ProductLinkImage({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<'div'> & {layout?: 'horizontal' | 'vertical'}) {\n return (\n <div\n data-slot=\"product-link-image\"\n className={cn(\n 'overflow-hidden rounded-md bg-muted',\n layout === 'horizontal'\n ? 'h-16 w-16 flex-shrink-0'\n : 'aspect-square w-full',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkInfo({\n className,\n layout = 'horizontal',\n ...props\n}: React.ComponentProps<typeof CardContent> & {\n layout?: 'horizontal' | 'vertical'\n}) {\n return (\n <CardContent\n className={cn(\n layout === 'horizontal'\n ? 'flex-1 min-w-0 space-y-1 px-0 py-0'\n : 'space-y-2',\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ProductLinkTitle({\n className,\n children,\n ...props\n}: React.ComponentProps<'h3'>) {\n return (\n <h3\n data-slot=\"product-link-title\"\n className={cn(\n 'text-sm font-medium leading-tight text-gray-900 truncate overflow-hidden whitespace-nowrap text-ellipsis',\n className\n )}\n {...props}\n >\n {children}\n </h3>\n )\n}\n\nfunction ProductLinkPrice({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-price\"\n className={cn('flex items-center gap-2', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkCurrentPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-current-price\"\n className={cn('text-sm font-semibold text-gray-900', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkOriginalPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-original-price\"\n className={cn('text-sm text-gray-500 line-through', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkDiscountPrice({\n className,\n ...props\n}: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"product-link-discount-price\"\n className={cn('text-sm font-semibold text-red-600', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkRating({className, ...props}: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"product-link-rating\"\n className={cn('', className)}\n {...props}\n />\n )\n}\n\nfunction ProductLinkActions({\n className,\n hideFavoriteAction = false,\n onPress,\n filled = false,\n customAction,\n ...props\n}: React.ComponentProps<typeof CardAction> & {\n hideFavoriteAction?: boolean\n onPress?: () => void\n filled?: boolean\n customAction?: React.ReactNode\n}) {\n const favoriteAction = hideFavoriteAction ? null : (\n <FavoriteButton filled={filled} onClick={onPress} />\n )\n\n return (\n <CardAction\n className={cn('flex-shrink-0 self-center px-0 py-0', className)}\n {...props}\n >\n <Touchable\n stopPropagation\n onClick={onPress}\n whileTap={{opacity: 0.7, scale: 0.95}}\n transition={{\n opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n scale: {type: 'tween', duration: 0.08, ease: 'easeInOut'},\n }}\n >\n {customAction ? <>{customAction}</> : favoriteAction}\n </Touchable>\n </CardAction>\n )\n}\n\nexport interface ProductLinkDocProps {\n /** The product to display */\n product: Product\n /** Hide the favorite/save button */\n hideFavoriteAction?: boolean\n /** Callback when the product link is clicked */\n onClick?: (product: Product) => void\n /** Hide the review stars */\n reviewsDisabled?: boolean\n /** Custom action element to replace the favorite button. Must be provided with `onCustomActionClick`. */\n customAction?: React.ReactNode\n /** Callback when the custom action is clicked. Must be provided with `customAction`. */\n onCustomActionClick?: () => void\n /** Whether to disable impression tracking */\n impressionTrackingDisabled?: boolean\n}\n\nexport type ProductLinkProps = {\n product: Product\n hideFavoriteAction?: boolean\n onClick?: (product: Product) => void\n reviewsDisabled?: boolean\n impressionTrackingDisabled?: boolean\n} & (\n | {\n customAction?: never\n onCustomActionClick?: never\n }\n | {\n customAction: React.ReactNode\n onCustomActionClick: () => void\n }\n)\n\n// Composed ProductLink component\nfunction ProductLink({\n product,\n hideFavoriteAction = false,\n onClick,\n customAction,\n onCustomActionClick,\n reviewsDisabled = false,\n impressionTrackingDisabled = false,\n}: ProductLinkProps) {\n const {navigateToProduct} = useShopNavigation()\n const {saveProduct, unsaveProduct} = useSavedProductsActions()\n const {ref: impressionRef} = useProductImpression({\n productId: product.id,\n skip: impressionTrackingDisabled,\n })\n\n const {\n id,\n title,\n featuredImage,\n reviewAnalytics,\n price,\n compareAtPrice,\n isFavorited,\n selectedVariant,\n defaultVariantId,\n shop,\n } = product\n\n // Local state for optimistic UI updates\n const [isFavoritedLocal, setIsFavoritedLocal] = React.useState(isFavorited)\n\n const averageRating = reviewAnalytics?.averageRating\n const reviewCount = reviewAnalytics?.reviewCount\n const amount = price?.amount\n ? formatMoney(price?.amount, price?.currencyCode)\n : undefined\n const imageUrl = featuredImage?.url\n const imageAltText = featuredImage?.altText || title\n const compareAtPriceAmount = compareAtPrice?.amount\n ? formatMoney(compareAtPrice?.amount, compareAtPrice?.currencyCode)\n : undefined\n const hasDiscount = compareAtPriceAmount && compareAtPriceAmount !== amount\n\n const handlePress = React.useCallback(() => {\n navigateToProduct({\n productId: id,\n })\n onClick?.(product)\n }, [navigateToProduct, id, onClick, product])\n\n const handleActionPress = React.useCallback(async () => {\n if (customAction || onCustomActionClick) {\n onCustomActionClick?.()\n return\n }\n\n const previousState = isFavoritedLocal\n\n // Optimistic update\n setIsFavoritedLocal(!previousState)\n\n try {\n if (previousState) {\n await unsaveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n } else {\n await saveProduct({\n productId: id,\n shopId: shop.id,\n productVariantId: selectedVariant?.id || defaultVariantId,\n })\n }\n } catch (error) {\n // Revert optimistic update on error\n setIsFavoritedLocal(previousState)\n }\n }, [\n customAction,\n onCustomActionClick,\n isFavoritedLocal,\n unsaveProduct,\n id,\n shop.id,\n selectedVariant?.id,\n defaultVariantId,\n saveProduct,\n ])\n\n return (\n <div ref={impressionRef}>\n <ProductLinkRoot\n layout=\"horizontal\"\n discount={hasDiscount ? 'small' : 'none'}\n onPress={handlePress}\n >\n <ProductLinkImage layout=\"horizontal\">\n {imageUrl ? (\n <img\n src={imageUrl}\n alt={imageAltText}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-muted flex items-center justify-center text-muted-foreground text-xs\">\n No Image\n </div>\n )}\n </ProductLinkImage>\n\n <ProductLinkInfo layout=\"horizontal\">\n <ProductLinkTitle>{title}</ProductLinkTitle>\n\n {averageRating && !reviewsDisabled ? (\n <ProductLinkRating>\n <ProductReviewStars\n averageRating={averageRating}\n reviewCount={reviewCount}\n />\n </ProductLinkRating>\n ) : null}\n\n <ProductLinkPrice>\n {hasDiscount ? (\n <>\n <ProductLinkDiscountPrice>{amount}</ProductLinkDiscountPrice>\n <ProductLinkOriginalPrice>\n {compareAtPriceAmount}\n </ProductLinkOriginalPrice>\n </>\n ) : (\n <ProductLinkCurrentPrice>{amount}</ProductLinkCurrentPrice>\n )}\n </ProductLinkPrice>\n </ProductLinkInfo>\n\n <ProductLinkActions\n filled={isFavoritedLocal}\n onPress={handleActionPress}\n customAction={customAction}\n hideFavoriteAction={hideFavoriteAction}\n />\n </ProductLinkRoot>\n </div>\n )\n}\n\nexport {ProductLink}\n"],"names":["productLinkVariants","cva","ProductLinkRoot","className","layout","discount","asChild","onPress","props","jsx","Touchable","SlotPrimitive.Root","Card","cn","ProductLinkImage","ProductLinkInfo","CardContent","ProductLinkTitle","children","ProductLinkPrice","ProductLinkCurrentPrice","ProductLinkOriginalPrice","ProductLinkDiscountPrice","ProductLinkRating","ProductLinkActions","hideFavoriteAction","filled","customAction","favoriteAction","FavoriteButton","CardAction","Fragment","ProductLink","product","onClick","onCustomActionClick","reviewsDisabled","impressionTrackingDisabled","navigateToProduct","useShopNavigation","saveProduct","unsaveProduct","useSavedProductsActions","impressionRef","useProductImpression","id","title","featuredImage","reviewAnalytics","price","compareAtPrice","isFavorited","selectedVariant","defaultVariantId","shop","isFavoritedLocal","setIsFavoritedLocal","React","averageRating","reviewCount","amount","formatMoney","imageUrl","imageAltText","compareAtPriceAmount","hasDiscount","handlePress","handleActionPress","previousState","jsxs","ProductReviewStars"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { useRef as u, useCallback as p, useEffect as f } from "react";
2
+ import { useHandleAction as h } from "./useHandleAction.js";
3
+ import { useShopActions as d } from "./useShopActions.js";
4
+ function C({
5
+ publicId: e,
6
+ skip: n = !1
7
+ }) {
8
+ const { reportContentImpression: i } = d(), s = h(i), t = u(null), r = u(!1), c = p(() => {
9
+ r.current || n || !e || (r.current = !0, s({ publicId: e, pageValue: window.location.pathname }));
10
+ }, [s, e, n]);
11
+ return f(() => {
12
+ r.current = !1;
13
+ }, [e]), f(() => {
14
+ if (n || !t.current)
15
+ return;
16
+ const a = t.current, o = new IntersectionObserver(
17
+ (m) => {
18
+ const [l] = m;
19
+ l?.isIntersecting && (c(), o.disconnect());
20
+ },
21
+ {
22
+ threshold: 0.5
23
+ }
24
+ );
25
+ return o.observe(a), () => {
26
+ o.disconnect();
27
+ };
28
+ }, [c, n]), { ref: t };
29
+ }
30
+ export {
31
+ C as useContentImpression
32
+ };
33
+ //# sourceMappingURL=useContentImpression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useContentImpression.js","sources":["../../src/internal/useContentImpression.ts"],"sourcesContent":["import {useCallback, useEffect, useRef} from 'react'\n\nimport {useHandleAction} from './useHandleAction'\nimport {useShopActions} from './useShopActions'\n\nexport interface UseContentImpressionParams {\n /**\n * The public ID of the content to report impressions for\n */\n publicId: string\n /**\n * Whether to skip reporting impressions\n */\n skip?: boolean\n}\n\nexport interface UseContentImpressionReturns {\n /**\n * Ref to attach to the content element for visibility tracking.\n * When the element becomes visible, an impression will be reported.\n */\n ref: {current: HTMLDivElement | null}\n}\n\nexport function useContentImpression({\n publicId,\n skip = false,\n}: UseContentImpressionParams): UseContentImpressionReturns {\n const {reportContentImpression} = useShopActions()\n const handleAction = useHandleAction(reportContentImpression)\n const ref = useRef<HTMLDivElement>(null)\n const hasReportedRef = useRef(false)\n\n const reportImpression = useCallback(() => {\n if (hasReportedRef.current || skip || !publicId) {\n return\n }\n\n hasReportedRef.current = true\n handleAction({publicId, pageValue: window.location.pathname})\n }, [handleAction, publicId, skip])\n\n useEffect(() => {\n hasReportedRef.current = false\n }, [publicId])\n\n useEffect(() => {\n if (skip || !ref.current) {\n return\n }\n\n const element = ref.current\n\n const observer = new IntersectionObserver(\n entries => {\n const [entry] = entries\n if (entry?.isIntersecting) {\n reportImpression()\n observer.disconnect()\n }\n },\n {\n threshold: 0.5,\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n }\n }, [reportImpression, skip])\n\n return {ref}\n}\n"],"names":["useContentImpression","publicId","skip","reportContentImpression","useShopActions","handleAction","useHandleAction","ref","useRef","hasReportedRef","reportImpression","useCallback","useEffect","element","observer","entries","entry"],"mappings":";;;AAwBO,SAASA,EAAqB;AAAA,EACnC,UAAAC;AAAA,EACA,MAAAC,IAAO;AACT,GAA4D;AACpD,QAAA,EAAC,yBAAAC,EAAuB,IAAIC,EAAe,GAC3CC,IAAeC,EAAgBH,CAAuB,GACtDI,IAAMC,EAAuB,IAAI,GACjCC,IAAiBD,EAAO,EAAK,GAE7BE,IAAmBC,EAAY,MAAM;AACzC,IAAIF,EAAe,WAAWP,KAAQ,CAACD,MAIvCQ,EAAe,UAAU,IACzBJ,EAAa,EAAC,UAAAJ,GAAU,WAAW,OAAO,SAAS,UAAS;AAAA,EAC3D,GAAA,CAACI,GAAcJ,GAAUC,CAAI,CAAC;AAEjC,SAAAU,EAAU,MAAM;AACd,IAAAH,EAAe,UAAU;AAAA,EAAA,GACxB,CAACR,CAAQ,CAAC,GAEbW,EAAU,MAAM;AACV,QAAAV,KAAQ,CAACK,EAAI;AACf;AAGF,UAAMM,IAAUN,EAAI,SAEdO,IAAW,IAAI;AAAA,MACnB,CAAWC,MAAA;AACH,cAAA,CAACC,CAAK,IAAID;AAChB,QAAIC,GAAO,mBACQN,EAAA,GACjBI,EAAS,WAAW;AAAA,MAExB;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MAAA;AAAA,IAEf;AAEA,WAAAA,EAAS,QAAQD,CAAO,GAEjB,MAAM;AACX,MAAAC,EAAS,WAAW;AAAA,IACtB;AAAA,EAAA,GACC,CAACJ,GAAkBR,CAAI,CAAC,GAEpB,EAAC,KAAAK,EAAG;AACb;"}
@@ -0,0 +1,34 @@
1
+ import { useRef as u, useCallback as h, useEffect as i } from "react";
2
+ import { useHandleAction as p } from "./useHandleAction.js";
3
+ import { useShopActions as b } from "./useShopActions.js";
4
+ function A({
5
+ productId: e,
6
+ skip: n = !1
7
+ }) {
8
+ const { productRecommendationImpression: f } = b(), s = p(f), r = u(null), t = u(!1), c = h(() => {
9
+ t.current || n || !e || (t.current = !0, s({ productId: e }));
10
+ }, [s, e, n]);
11
+ return i(() => {
12
+ t.current = !1;
13
+ }, [e]), i(() => {
14
+ if (n || !r.current)
15
+ return;
16
+ const m = r.current, o = new IntersectionObserver(
17
+ (l) => {
18
+ const [a] = l;
19
+ a?.isIntersecting && (c(), o.disconnect());
20
+ },
21
+ {
22
+ threshold: 0.5
23
+ // Report when 50% of the element is visible
24
+ }
25
+ );
26
+ return o.observe(m), () => {
27
+ o.disconnect();
28
+ };
29
+ }, [c, n]), { ref: r };
30
+ }
31
+ export {
32
+ A as useProductImpression
33
+ };
34
+ //# sourceMappingURL=useProductImpression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useProductImpression.js","sources":["../../src/internal/useProductImpression.ts"],"sourcesContent":["import {useCallback, useEffect, useRef} from 'react'\n\nimport {useHandleAction} from './useHandleAction'\nimport {useShopActions} from './useShopActions'\n\nexport interface UseProductImpressionParams {\n /**\n * The product GID string to report impressions for\n */\n productId: string\n /**\n * Whether to skip reporting impressions (e.g., when product data is loading)\n */\n skip?: boolean\n}\n\nexport interface UseProductImpressionReturns {\n /**\n * Ref to attach to the product element for visibility tracking.\n * When the element becomes visible, an impression will be reported.\n */\n ref: {current: HTMLDivElement | null}\n}\n\n/**\n * Hook to report product impressions when a product becomes visible.\n * Attach the returned ref to the product container element.\n *\n * @example\n * ```tsx\n * function ProductCard({ product }) {\n * const { ref } = useProductImpression({ productId: product.id });\n * return <div ref={ref}>...</div>;\n * }\n * ```\n */\nexport function useProductImpression({\n productId,\n skip = false,\n}: UseProductImpressionParams): UseProductImpressionReturns {\n const {productRecommendationImpression} = useShopActions()\n const handleAction = useHandleAction(productRecommendationImpression)\n const ref = useRef<HTMLDivElement>(null)\n const hasReportedRef = useRef(false)\n\n const reportImpression = useCallback(() => {\n if (hasReportedRef.current || skip || !productId) {\n return\n }\n\n hasReportedRef.current = true\n handleAction({productId})\n }, [handleAction, productId, skip])\n\n useEffect(() => {\n // Reset reported state when productId changes\n hasReportedRef.current = false\n }, [productId])\n\n useEffect(() => {\n if (skip || !ref.current) {\n return\n }\n\n const element = ref.current\n\n const observer = new IntersectionObserver(\n entries => {\n const [entry] = entries\n if (entry?.isIntersecting) {\n reportImpression()\n observer.disconnect()\n }\n },\n {\n threshold: 0.5, // Report when 50% of the element is visible\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n }\n }, [reportImpression, skip])\n\n return {ref}\n}\n"],"names":["useProductImpression","productId","skip","productRecommendationImpression","useShopActions","handleAction","useHandleAction","ref","useRef","hasReportedRef","reportImpression","useCallback","useEffect","element","observer","entries","entry"],"mappings":";;;AAoCO,SAASA,EAAqB;AAAA,EACnC,WAAAC;AAAA,EACA,MAAAC,IAAO;AACT,GAA4D;AACpD,QAAA,EAAC,iCAAAC,EAA+B,IAAIC,EAAe,GACnDC,IAAeC,EAAgBH,CAA+B,GAC9DI,IAAMC,EAAuB,IAAI,GACjCC,IAAiBD,EAAO,EAAK,GAE7BE,IAAmBC,EAAY,MAAM;AACzC,IAAIF,EAAe,WAAWP,KAAQ,CAACD,MAIvCQ,EAAe,UAAU,IACZJ,EAAA,EAAC,WAAAJ,GAAU;AAAA,EACvB,GAAA,CAACI,GAAcJ,GAAWC,CAAI,CAAC;AAElC,SAAAU,EAAU,MAAM;AAEd,IAAAH,EAAe,UAAU;AAAA,EAAA,GACxB,CAACR,CAAS,CAAC,GAEdW,EAAU,MAAM;AACV,QAAAV,KAAQ,CAACK,EAAI;AACf;AAGF,UAAMM,IAAUN,EAAI,SAEdO,IAAW,IAAI;AAAA,MACnB,CAAWC,MAAA;AACH,cAAA,CAACC,CAAK,IAAID;AAChB,QAAIC,GAAO,mBACQN,EAAA,GACjBI,EAAS,WAAW;AAAA,MAExB;AAAA,MACA;AAAA,QACE,WAAW;AAAA;AAAA,MAAA;AAAA,IAEf;AAEA,WAAAA,EAAS,QAAQD,CAAO,GAEjB,MAAM;AACX,MAAAC,EAAS,WAAW;AAAA,IACtB;AAAA,EAAA,GACC,CAACJ,GAAkBR,CAAI,CAAC,GAEpB,EAAC,KAAAK,EAAG;AACb;"}
@@ -1,4 +1,4 @@
1
- import { __module as t } from "../../../../../../_virtual/index10.js";
1
+ import { __module as t } from "../../../../../../_virtual/index11.js";
2
2
  import { __require as z } from "../../../is-arrayish@0.3.2/node_modules/is-arrayish/index.js";
3
3
  var l;
4
4
  function v() {
@@ -1,4 +1,4 @@
1
- import { __module as r } from "../../../../../../../_virtual/index11.js";
1
+ import { __module as r } from "../../../../../../../_virtual/index10.js";
2
2
  import { __require as o } from "../cjs/use-sync-external-store-shim.production.js";
3
3
  import { __require as i } from "../cjs/use-sync-external-store-shim.development.js";
4
4
  var e;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shopify/shop-minis-react",
3
3
  "license": "SEE LICENSE IN LICENSE.txt",
4
- "version": "0.11.0",
4
+ "version": "0.12.0",
5
5
  "sideEffects": false,
6
6
  "type": "module",
7
7
  "engines": {
@@ -46,7 +46,7 @@
46
46
  "typescript": ">=5.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "@shopify/shop-minis-platform": "0.12.0",
49
+ "@shopify/shop-minis-platform": "0.12.1",
50
50
  "@tailwindcss/vite": "4.1.8",
51
51
  "@tanstack/react-query": "5.86.0",
52
52
  "@types/color": "3.0.6",
@@ -1,3 +1,4 @@
1
+ import {useContentImpression} from '../../internal/useContentImpression'
1
2
  import {useShopActions} from '../../internal/useShopActions'
2
3
 
3
4
  import {LongPressDetector} from './long-press-detector'
@@ -10,16 +11,22 @@ export function ContentMonitor({
10
11
  children: React.ReactNode
11
12
  }) {
12
13
  const {showFeedbackSheet} = useShopActions()
14
+ const {ref} = useContentImpression({
15
+ publicId: publicId ?? '',
16
+ skip: !publicId,
17
+ })
13
18
 
14
19
  return (
15
- <LongPressDetector
16
- onLongPress={() => {
17
- if (!publicId) return
20
+ <div ref={ref}>
21
+ <LongPressDetector
22
+ onLongPress={() => {
23
+ if (!publicId) return
18
24
 
19
- showFeedbackSheet({publicId})
20
- }}
21
- >
22
- {children}
23
- </LongPressDetector>
25
+ showFeedbackSheet({publicId})
26
+ }}
27
+ >
28
+ {children}
29
+ </LongPressDetector>
30
+ </div>
24
31
  )
25
32
  }