@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.
- package/dist/components/atoms/content-wrapper.js.map +1 -1
- package/dist/components/atoms/video-player.js +28 -26
- package/dist/components/atoms/video-player.js.map +1 -1
- package/dist/components/commerce/product-card.js +106 -79
- package/dist/components/commerce/product-card.js.map +1 -1
- package/dist/components/commerce/product-link.js +124 -137
- package/dist/components/commerce/product-link.js.map +1 -1
- package/dist/components/commerce/search.js +20 -20
- package/dist/components/commerce/search.js.map +1 -1
- package/dist/components/ui/sonner.js +3 -1
- package/dist/components/ui/sonner.js.map +1 -1
- package/dist/hooks/navigation/useNavigateWithTransition.js +10 -11
- package/dist/hooks/navigation/useNavigateWithTransition.js.map +1 -1
- package/dist/index.js +269 -264
- package/dist/index.js.map +1 -1
- package/dist/internal/components/product-review-stars.js +78 -0
- package/dist/internal/components/product-review-stars.js.map +1 -0
- package/dist/mocks.js +178 -107
- package/dist/mocks.js.map +1 -1
- 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
- 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
- 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
- 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
- package/package.json +1 -1
- package/src/components/atoms/content-wrapper.tsx +1 -1
- package/src/components/atoms/video-player.tsx +7 -0
- package/src/components/commerce/product-card.test.tsx +135 -0
- package/src/components/commerce/product-card.tsx +39 -5
- package/src/components/commerce/product-link.test.tsx +15 -3
- package/src/components/commerce/product-link.tsx +9 -25
- package/src/components/commerce/search.tsx +2 -2
- package/src/components/index.ts +1 -0
- package/src/components/ui/sonner.tsx +2 -2
- package/src/hooks/navigation/useNavigateWithTransition.test.ts +46 -7
- package/src/hooks/navigation/useNavigateWithTransition.ts +4 -1
- package/src/internal/components/product-review-stars.test.tsx +90 -0
- package/src/internal/components/product-review-stars.tsx +113 -0
- package/src/mocks.ts +10 -2
- 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: [
|
|
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: {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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('')
|