@shopify/shop-minis-react 0.3.2 → 0.3.4

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 (39) hide show
  1. package/dist/components/atoms/content-wrapper.js.map +1 -1
  2. package/dist/components/atoms/video-player.js +28 -26
  3. package/dist/components/atoms/video-player.js.map +1 -1
  4. package/dist/components/commerce/product-card.js +106 -79
  5. package/dist/components/commerce/product-card.js.map +1 -1
  6. package/dist/components/commerce/product-link.js +124 -137
  7. package/dist/components/commerce/product-link.js.map +1 -1
  8. package/dist/components/commerce/search.js +20 -20
  9. package/dist/components/commerce/search.js.map +1 -1
  10. package/dist/components/ui/sonner.js +3 -1
  11. package/dist/components/ui/sonner.js.map +1 -1
  12. package/dist/hooks/navigation/useNavigateWithTransition.js +10 -11
  13. package/dist/hooks/navigation/useNavigateWithTransition.js.map +1 -1
  14. package/dist/index.js +269 -264
  15. package/dist/index.js.map +1 -1
  16. package/dist/internal/components/product-review-stars.js +78 -0
  17. package/dist/internal/components/product-review-stars.js.map +1 -0
  18. package/dist/mocks.js +178 -107
  19. package/dist/mocks.js.map +1 -1
  20. package/dist/shop-minis-react/node_modules/.pnpm/lucide-react@0.513.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/star-half.js +21 -0
  21. package/dist/shop-minis-react/node_modules/.pnpm/lucide-react@0.513.0_react@19.1.0/node_modules/lucide-react/dist/esm/icons/star-half.js.map +1 -0
  22. package/dist/shop-minis-react/node_modules/.pnpm/sonner@2.0.5_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/sonner/dist/index.js +4 -4
  23. package/dist/shop-minis-react/node_modules/.pnpm/sonner@2.0.5_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/sonner/dist/index.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/atoms/content-wrapper.tsx +1 -1
  26. package/src/components/atoms/video-player.tsx +7 -0
  27. package/src/components/commerce/product-card.test.tsx +135 -0
  28. package/src/components/commerce/product-card.tsx +39 -5
  29. package/src/components/commerce/product-link.test.tsx +15 -3
  30. package/src/components/commerce/product-link.tsx +9 -25
  31. package/src/components/commerce/search.tsx +2 -2
  32. package/src/components/index.ts +1 -0
  33. package/src/components/ui/sonner.tsx +2 -2
  34. package/src/hooks/navigation/useNavigateWithTransition.test.ts +46 -7
  35. package/src/hooks/navigation/useNavigateWithTransition.ts +4 -1
  36. package/src/internal/components/product-review-stars.test.tsx +90 -0
  37. package/src/internal/components/product-review-stars.tsx +113 -0
  38. package/src/mocks.ts +10 -2
  39. package/src/providers/ImagePickerProvider.test.tsx +3 -9
@@ -0,0 +1,113 @@
1
+ import * as React from 'react'
2
+
3
+ import {Star, StarHalf} from 'lucide-react'
4
+
5
+ import {cn} from '../../lib/utils'
6
+ import {formatReviewCount, normalizeRating} from '../../utils/merchant-card'
7
+
8
+ const starSizeClasses = {
9
+ sm: 'h-3 w-3',
10
+ md: 'h-4 w-4',
11
+ lg: 'h-5 w-5',
12
+ } as const
13
+
14
+ const textSizeClasses = {
15
+ sm: 'text-xs',
16
+ md: 'text-sm',
17
+ lg: 'text-base',
18
+ } as const
19
+
20
+ export interface ProductReviewStarsProps
21
+ extends React.HTMLAttributes<HTMLDivElement> {
22
+ /**
23
+ * Average rating value (0-5)
24
+ */
25
+ averageRating: number
26
+ /**
27
+ * Total number of reviews
28
+ */
29
+ reviewCount?: number | null
30
+ /**
31
+ * Custom color for filled star
32
+ * @default 'var(--grayscale-d100)' (black)
33
+ */
34
+ filledStarColor?: string
35
+ /**
36
+ * Custom color for empty star
37
+ * @default 'var(--grayscale-l20)' (light gray)
38
+ */
39
+ emptyStarColor?: string
40
+ /**
41
+ * Size of the stars
42
+ * @default 'sm'
43
+ */
44
+ size?: 'sm' | 'md' | 'lg'
45
+ }
46
+
47
+ export const ProductReviewStars = React.forwardRef<
48
+ HTMLDivElement,
49
+ ProductReviewStarsProps
50
+ >(
51
+ (
52
+ {
53
+ averageRating,
54
+ reviewCount,
55
+ size = 'sm',
56
+ filledStarColor = 'var(--grayscale-d100)',
57
+ emptyStarColor = 'var(--grayscale-l20)',
58
+ className,
59
+ ...props
60
+ },
61
+ ref
62
+ ) => {
63
+ const normalizedRating = Math.min(5, normalizeRating(averageRating))
64
+ const filledStars = Math.floor(normalizedRating)
65
+ const remainder = normalizedRating % 1
66
+
67
+ return (
68
+ <div
69
+ ref={ref}
70
+ className={cn('flex items-center', className)}
71
+ data-slot="product-review-stars"
72
+ {...props}
73
+ >
74
+ <div className="relative">
75
+ <div className="flex">
76
+ {Array.from({length: 5}, (_, i) => (
77
+ <Star
78
+ key={i}
79
+ className={cn(starSizeClasses[size])}
80
+ style={{fill: emptyStarColor}}
81
+ strokeWidth={0}
82
+ />
83
+ ))}
84
+ </div>
85
+ <div className="flex absolute top-0 left-0">
86
+ {Array.from({length: filledStars}, (_, i) => (
87
+ <Star
88
+ key={i}
89
+ className={cn(starSizeClasses[size])}
90
+ style={{fill: filledStarColor}}
91
+ strokeWidth={0}
92
+ />
93
+ ))}
94
+ {remainder >= 0.5 && (
95
+ <StarHalf
96
+ className={cn(starSizeClasses[size])}
97
+ style={{fill: filledStarColor}}
98
+ strokeWidth={0}
99
+ />
100
+ )}
101
+ </div>
102
+ </div>
103
+ {reviewCount && (
104
+ <span className={cn(textSizeClasses[size], 'ml-1')}>
105
+ ({formatReviewCount(reviewCount)})
106
+ </span>
107
+ )}
108
+ </div>
109
+ )
110
+ }
111
+ )
112
+
113
+ ProductReviewStars.displayName = 'ProductReviewStars'
package/src/mocks.ts CHANGED
@@ -378,7 +378,13 @@ export function makeMockActions(): ShopActions {
378
378
  pageInfo: createPagination(),
379
379
  },
380
380
  getProductSearch: {
381
- data: [createProduct('search-3', 'Search Product 3', '39.99')],
381
+ data: [
382
+ createProduct('search-1', 'Search Product 1', '39.99'),
383
+ createProduct('search-2', 'Search Product 2', '19.99'),
384
+ createProduct('search-3', 'Search Product 3', '29.99'),
385
+ createProduct('search-4', 'Search Product 4', '49.99'),
386
+ createProduct('search-5', 'Search Product 5', '9.99'),
387
+ ],
382
388
  pageInfo: createPagination(),
383
389
  },
384
390
  getProducts: {data: [createProduct('prod-2', 'Product 2', '19.99')]},
@@ -407,7 +413,9 @@ export function makeMockActions(): ShopActions {
407
413
  ],
408
414
  pageInfo: createPagination(),
409
415
  },
410
- getShop: {data: createShop('shop-1', 'Sample Shop')},
416
+ getShop: {
417
+ data: createShop('shop-1', 'Sample Shop', {featuredImagesLimit: 4}),
418
+ },
411
419
  getRecentShops: {
412
420
  data: [createShop('recent-shop-1', 'Recent Shop 1')],
413
421
  pageInfo: createPagination(),
@@ -160,9 +160,7 @@ describe('ImagePickerProvider', () => {
160
160
  configurable: true,
161
161
  })
162
162
 
163
- await act(async () => {
164
- fireEvent.change(galleryInput)
165
- })
163
+ fireEvent.change(galleryInput)
166
164
 
167
165
  // Check that the promise resolved with the file
168
166
  await vi.waitFor(() => {
@@ -427,9 +425,7 @@ describe('ImagePickerProvider', () => {
427
425
  configurable: true,
428
426
  })
429
427
 
430
- await act(async () => {
431
- fireEvent.change(cameraInput)
432
- })
428
+ fireEvent.change(cameraInput)
433
429
 
434
430
  await vi.waitFor(() => {
435
431
  const cameraFile = document.querySelector('[data-testid="camera-file"]')
@@ -718,9 +714,7 @@ describe('ImagePickerProvider', () => {
718
714
  configurable: true,
719
715
  })
720
716
 
721
- await act(async () => {
722
- fireEvent.change(galleryInput)
723
- })
717
+ fireEvent.change(galleryInput)
724
718
 
725
719
  // Check that input value was cleared
726
720
  expect(galleryInput.value).toBe('')