@shopify/shop-minis-react 0.0.28 → 0.0.30
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/_virtual/index10.js +2 -2
- package/dist/_virtual/index2.js +4 -4
- package/dist/_virtual/index3.js +4 -4
- package/dist/_virtual/index5.js +3 -2
- package/dist/_virtual/index5.js.map +1 -1
- package/dist/_virtual/index6.js +2 -3
- package/dist/_virtual/index6.js.map +1 -1
- package/dist/_virtual/index7.js +2 -2
- package/dist/_virtual/index9.js +2 -2
- package/dist/components/atoms/list.js +37 -31
- package/dist/components/atoms/list.js.map +1 -1
- package/dist/components/commerce/product-link.js +117 -113
- package/dist/components/commerce/product-link.js.map +1 -1
- package/dist/components/commerce/search.js +26 -17
- package/dist/components/commerce/search.js.map +1 -1
- package/dist/components/navigation/minis-router.js +14 -0
- package/dist/components/navigation/minis-router.js.map +1 -0
- package/dist/hooks/navigation/useNavigateWithTransition.js.map +1 -1
- package/dist/hooks/navigation/useShopNavigation.js.map +1 -1
- package/dist/hooks/user/useCurrentUser.js.map +1 -1
- package/dist/hooks/user/useFollowedShopsActions.js.map +1 -1
- package/dist/hooks/util/useImagePicker.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/mocks.js +9 -9
- package/dist/mocks.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/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/mpd-parser@1.3.1/node_modules/mpd-parser/dist/mpd-parser.es.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/react-router@7.7.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-router/dist/development/chunk-EF7DTUVF.js +764 -567
- package/dist/shop-minis-react/node_modules/.pnpm/react-router@7.7.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-router/dist/development/chunk-EF7DTUVF.js.map +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/use-sync-external-store@1.5.0_react@19.1.0/node_modules/use-sync-external-store/shim/index.js +1 -1
- package/dist/shop-minis-react/node_modules/.pnpm/video.js@8.23.3/node_modules/video.js/dist/video.es.js +1 -1
- package/dist/utils/colors.js +1 -1
- package/package.json +1 -1
- package/src/components/atoms/list.tsx +24 -4
- package/src/components/commerce/product-link.tsx +10 -4
- package/src/components/commerce/search.tsx +9 -2
- package/src/components/index.ts +1 -1
- package/src/components/navigation/minis-router.tsx +23 -0
- package/src/hooks/navigation/useNavigateWithTransition.ts +6 -1
- package/src/hooks/navigation/useShopNavigation.ts +3 -1
- package/src/hooks/user/useCurrentUser.ts +3 -0
- package/src/hooks/user/useFollowedShopsActions.ts +2 -2
- package/src/hooks/util/{useImagePicker.tsx → useImagePicker.ts} +8 -2
- package/src/index.css +1 -0
- package/src/mocks.ts +3 -3
- package/src/stories/ImageContentWrapper.stories.tsx +68 -0
- package/src/stories/MerchantCard.stories.tsx +21 -0
- package/src/stories/ProductCard.stories.tsx +10 -3
- package/src/stories/ProductLink.stories.tsx +3 -3
- package/src/stories/QuantitySelector.stories.tsx +78 -0
- package/src/stories/Search.stories.tsx +37 -0
- package/src/stories/VideoPlayer.stories.tsx +129 -0
- package/src/styles/fonts.css +26 -0
- package/src/styles/theme.css +26 -0
- package/src/hooks/util/useImagePicker.doc.tsx +0 -41
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __module as r } from "../../../../../../../_virtual/
|
|
1
|
+
import { __module as r } from "../../../../../../../_virtual/index9.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;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import S from "../../../../../../../_virtual/window.js";
|
|
2
2
|
import B from "../../../../../../../_virtual/document.js";
|
|
3
|
-
import il from "../../../../../../../_virtual/
|
|
3
|
+
import il from "../../../../../../../_virtual/index3.js";
|
|
4
4
|
import ao from "../../../../../../../_virtual/browser-index.js";
|
|
5
5
|
import xe from "../../../../@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/extends.js";
|
|
6
6
|
import Kc from "../../../../@videojs_vhs-utils@4.1.1/node_modules/@videojs/vhs-utils/es/resolve-url.js";
|
package/dist/utils/colors.js
CHANGED
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {ComponentType, useCallback} from 'react'
|
|
1
|
+
import {ComponentType, useCallback, useRef} from 'react'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
VariableSizeList as _VariableSizeList,
|
|
@@ -24,7 +24,7 @@ interface Props<T = any>
|
|
|
24
24
|
showScrollbar?: boolean
|
|
25
25
|
header?: React.ReactNode
|
|
26
26
|
headerHeight?: number
|
|
27
|
-
fetchMore?: () => void
|
|
27
|
+
fetchMore?: () => Promise<void>
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function List<T = any>({
|
|
@@ -40,6 +40,26 @@ export function List<T = any>({
|
|
|
40
40
|
overscanCount,
|
|
41
41
|
...listProps
|
|
42
42
|
}: Props<T>) {
|
|
43
|
+
const inFlightFetchMoreRef = useRef<Promise<void> | null>(null)
|
|
44
|
+
|
|
45
|
+
// This is workaround to prevent multiple calls to fetchMore
|
|
46
|
+
// react-window re-renders the rows while scrolling,
|
|
47
|
+
// and the TrackingPixel could be triggered multiple times
|
|
48
|
+
|
|
49
|
+
const _fetchMore = useCallback(() => {
|
|
50
|
+
// Dedupe concurrent calls by returning the same in-flight promise
|
|
51
|
+
if (inFlightFetchMoreRef.current) return
|
|
52
|
+
|
|
53
|
+
const current = Promise.resolve(fetchMore?.()).finally(() => {
|
|
54
|
+
// Only clear if this is still the most recent promise
|
|
55
|
+
if (inFlightFetchMoreRef.current === current) {
|
|
56
|
+
inFlightFetchMoreRef.current = null
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
inFlightFetchMoreRef.current = current
|
|
61
|
+
}, [fetchMore])
|
|
62
|
+
|
|
43
63
|
const rowRenderer = useCallback(
|
|
44
64
|
({index, style}: {index: number; style: React.CSSProperties}) => {
|
|
45
65
|
// prepend the header to the first row if it exists
|
|
@@ -58,7 +78,7 @@ export function List<T = any>({
|
|
|
58
78
|
<div style={style}>
|
|
59
79
|
{renderItem(items[index], index)}
|
|
60
80
|
<div style={{bottom: 0}}>
|
|
61
|
-
<Pagination fetchMore={
|
|
81
|
+
<Pagination fetchMore={_fetchMore} />
|
|
62
82
|
</div>
|
|
63
83
|
</div>
|
|
64
84
|
)
|
|
@@ -66,7 +86,7 @@ export function List<T = any>({
|
|
|
66
86
|
|
|
67
87
|
return <div style={style}>{renderItem(items[index], index)}</div>
|
|
68
88
|
},
|
|
69
|
-
[items, renderItem, header,
|
|
89
|
+
[items, renderItem, header, headerHeight, _fetchMore, fetchMore]
|
|
70
90
|
)
|
|
71
91
|
|
|
72
92
|
const getItemSize = useCallback(
|
|
@@ -223,10 +223,15 @@ function ProductLinkActions({
|
|
|
223
223
|
export interface ProductLinkProps {
|
|
224
224
|
product: Product
|
|
225
225
|
hideFavoriteAction?: boolean
|
|
226
|
+
onClick?: (product: Product) => void
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
// Composed ProductLink component
|
|
229
|
-
function ProductLink({
|
|
230
|
+
function ProductLink({
|
|
231
|
+
product,
|
|
232
|
+
hideFavoriteAction = false,
|
|
233
|
+
onClick,
|
|
234
|
+
}: ProductLinkProps) {
|
|
230
235
|
const {navigateToProduct} = useShopNavigation()
|
|
231
236
|
const {saveProduct, unsaveProduct} = useSavedProductsActions()
|
|
232
237
|
|
|
@@ -262,7 +267,8 @@ function ProductLink({product, hideFavoriteAction = false}: ProductLinkProps) {
|
|
|
262
267
|
navigateToProduct({
|
|
263
268
|
productId: id,
|
|
264
269
|
})
|
|
265
|
-
|
|
270
|
+
onClick?.(product)
|
|
271
|
+
}, [navigateToProduct, id, onClick, product])
|
|
266
272
|
|
|
267
273
|
const handleActionPress = React.useCallback(async () => {
|
|
268
274
|
const previousState = isFavoritedLocal
|
|
@@ -321,7 +327,7 @@ function ProductLink({product, hideFavoriteAction = false}: ProductLinkProps) {
|
|
|
321
327
|
<ProductLinkInfo layout="horizontal">
|
|
322
328
|
<ProductLinkTitle>{title}</ProductLinkTitle>
|
|
323
329
|
|
|
324
|
-
{reviewCount && averageRating
|
|
330
|
+
{reviewCount && averageRating ? (
|
|
325
331
|
<ProductLinkRating>
|
|
326
332
|
<div className="flex items-center gap-1">
|
|
327
333
|
{Array.from({length: 5}, (_, i) => (
|
|
@@ -343,7 +349,7 @@ function ProductLink({product, hideFavoriteAction = false}: ProductLinkProps) {
|
|
|
343
349
|
</span>
|
|
344
350
|
</div>
|
|
345
351
|
</ProductLinkRating>
|
|
346
|
-
)}
|
|
352
|
+
) : null}
|
|
347
353
|
|
|
348
354
|
<ProductLinkPrice>
|
|
349
355
|
{hasDiscount ? (
|
|
@@ -21,7 +21,7 @@ interface SearchContextValue {
|
|
|
21
21
|
products: Product[] | null
|
|
22
22
|
loading: boolean
|
|
23
23
|
error: Error | null
|
|
24
|
-
fetchMore?: () => void
|
|
24
|
+
fetchMore?: () => Promise<void>
|
|
25
25
|
hasNextPage: boolean
|
|
26
26
|
isTyping: boolean
|
|
27
27
|
}
|
|
@@ -220,6 +220,7 @@ export interface SearchResultsProps
|
|
|
220
220
|
SearchInputProps,
|
|
221
221
|
SearchResultsListProps {
|
|
222
222
|
showSearchInput?: boolean
|
|
223
|
+
onProductClick?: (product: Product) => void
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
function Search({
|
|
@@ -230,6 +231,7 @@ function Search({
|
|
|
230
231
|
className,
|
|
231
232
|
renderItem,
|
|
232
233
|
itemHeight,
|
|
234
|
+
onProductClick,
|
|
233
235
|
}: SearchResultsProps) {
|
|
234
236
|
const _renderItem = (product: Product, index: number) => {
|
|
235
237
|
if (renderItem) {
|
|
@@ -238,7 +240,12 @@ function Search({
|
|
|
238
240
|
|
|
239
241
|
return (
|
|
240
242
|
<div className="p-2">
|
|
241
|
-
<ProductLink
|
|
243
|
+
<ProductLink
|
|
244
|
+
key={product.id}
|
|
245
|
+
product={product}
|
|
246
|
+
hideFavoriteAction
|
|
247
|
+
onClick={onProductClick}
|
|
248
|
+
/>
|
|
242
249
|
</div>
|
|
243
250
|
)
|
|
244
251
|
}
|
package/src/components/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export * from './commerce/search'
|
|
|
10
10
|
|
|
11
11
|
export * from './content/image-content-wrapper'
|
|
12
12
|
|
|
13
|
-
export * from './navigation/
|
|
13
|
+
export * from './navigation/minis-router'
|
|
14
14
|
export * from './navigation/transition-link'
|
|
15
15
|
|
|
16
16
|
export * from './atoms/button'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {BrowserRouter, BrowserRouterProps} from 'react-router'
|
|
2
|
+
|
|
3
|
+
import {TransitionContainer} from './transition-container'
|
|
4
|
+
|
|
5
|
+
type ShopMinisRouterProps = BrowserRouterProps & {
|
|
6
|
+
viewTransitions?: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function MinisRouter({
|
|
10
|
+
children,
|
|
11
|
+
viewTransitions = false,
|
|
12
|
+
...props
|
|
13
|
+
}: ShopMinisRouterProps) {
|
|
14
|
+
if (viewTransitions) {
|
|
15
|
+
return (
|
|
16
|
+
<BrowserRouter {...props}>
|
|
17
|
+
<TransitionContainer>{children}</TransitionContainer>
|
|
18
|
+
</BrowserRouter>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return <BrowserRouter {...props}>{children}</BrowserRouter>
|
|
23
|
+
}
|
|
@@ -2,7 +2,12 @@ import {useLocation, useNavigate, NavigateOptions} from 'react-router'
|
|
|
2
2
|
|
|
3
3
|
import {DATA_NAVIGATION_TYPE_ATTRIBUTE} from '../../types'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type UseNavigateWithTransitionReturns = (
|
|
6
|
+
to: string | number,
|
|
7
|
+
options?: NavigateOptions
|
|
8
|
+
) => void | Promise<void>
|
|
9
|
+
|
|
10
|
+
export function useNavigateWithTransition(): UseNavigateWithTransitionReturns {
|
|
6
11
|
const navigate = useNavigate()
|
|
7
12
|
const location = useLocation()
|
|
8
13
|
|
|
@@ -21,7 +21,9 @@ interface UseShopNavigationReturns {
|
|
|
21
21
|
* Navigates to an order.
|
|
22
22
|
*/
|
|
23
23
|
navigateToOrder: (params: NavigateToOrderParams) => Promise<void>
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Navigates to a checkout.
|
|
26
|
+
*/
|
|
25
27
|
navigateToCheckout: (params: NavigateToCheckoutParams) => Promise<void>
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -8,11 +8,11 @@ import {useShopActions} from '../../internal/useShopActions'
|
|
|
8
8
|
|
|
9
9
|
interface UseFollowedShopsActionsReturns {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Follows a shop.
|
|
12
12
|
*/
|
|
13
13
|
followShop: (params: FollowShopParams) => Promise<boolean>
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Unfollows a shop.
|
|
16
16
|
*/
|
|
17
17
|
unfollowShop: (params: UnfollowShopParams) => Promise<boolean>
|
|
18
18
|
}
|
|
@@ -3,12 +3,18 @@ import {
|
|
|
3
3
|
useImagePickerContext,
|
|
4
4
|
} from '../../providers/ImagePickerProvider'
|
|
5
5
|
|
|
6
|
-
interface
|
|
6
|
+
interface UseImagePickerReturns {
|
|
7
|
+
/**
|
|
8
|
+
* Opens the camera to take a photo.
|
|
9
|
+
*/
|
|
7
10
|
openCamera: (cameraFacing?: CameraFacing) => Promise<File>
|
|
11
|
+
/**
|
|
12
|
+
* Opens the gallery to select an image.
|
|
13
|
+
*/
|
|
8
14
|
openGallery: () => Promise<File>
|
|
9
15
|
}
|
|
10
16
|
|
|
11
|
-
export function useImagePicker():
|
|
17
|
+
export function useImagePicker(): UseImagePickerReturns {
|
|
12
18
|
const {openCamera, openGallery} = useImagePickerContext()
|
|
13
19
|
|
|
14
20
|
return {
|
package/src/index.css
CHANGED
package/src/mocks.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const createProduct = (
|
|
|
19
19
|
defaultVariantId: `variant-${id}`,
|
|
20
20
|
isFavorited: false,
|
|
21
21
|
featuredImage: {
|
|
22
|
-
url: `https://cdn.shopify.com/
|
|
22
|
+
url: `https://cdn.shopify.com/static/sample-images/teapot.jpg`,
|
|
23
23
|
altText: title,
|
|
24
24
|
},
|
|
25
25
|
})
|
|
@@ -411,7 +411,7 @@ function makeMockActions(): ShopActions {
|
|
|
411
411
|
externalId: null,
|
|
412
412
|
image: {
|
|
413
413
|
id: 'img-123',
|
|
414
|
-
url: 'https://
|
|
414
|
+
url: 'https://cdn.shopify.com/s/files/1/0633/6574/2742/files/Namnlosdesign-47.png?v=1740438079',
|
|
415
415
|
width: 800,
|
|
416
416
|
height: 600,
|
|
417
417
|
},
|
|
@@ -428,7 +428,7 @@ function makeMockActions(): ShopActions {
|
|
|
428
428
|
publicId: 'content-123',
|
|
429
429
|
image: {
|
|
430
430
|
id: 'img-123',
|
|
431
|
-
url: 'https://
|
|
431
|
+
url: 'https://cdn.shopify.com/s/files/1/0633/6574/2742/files/Namnlosdesign-47.png?v=1740438079',
|
|
432
432
|
width: 800,
|
|
433
433
|
height: 600,
|
|
434
434
|
},
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {fn} from 'storybook/test'
|
|
2
|
+
|
|
3
|
+
import {ImageContentWrapper} from '../components/content/image-content-wrapper'
|
|
4
|
+
import {injectMocks} from '../mocks'
|
|
5
|
+
|
|
6
|
+
import type {Meta, StoryObj} from '@storybook/react-vite'
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Content/ImageContentWrapper',
|
|
10
|
+
component: ImageContentWrapper,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'padded',
|
|
13
|
+
},
|
|
14
|
+
args: {
|
|
15
|
+
onLoad: fn(),
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
publicId: {
|
|
19
|
+
control: 'text',
|
|
20
|
+
},
|
|
21
|
+
externalId: {
|
|
22
|
+
control: 'text',
|
|
23
|
+
},
|
|
24
|
+
width: {
|
|
25
|
+
control: 'number',
|
|
26
|
+
},
|
|
27
|
+
height: {
|
|
28
|
+
control: 'number',
|
|
29
|
+
},
|
|
30
|
+
className: {
|
|
31
|
+
control: 'text',
|
|
32
|
+
},
|
|
33
|
+
Loader: {
|
|
34
|
+
control: 'text',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
tags: ['autodocs'],
|
|
38
|
+
} satisfies Meta<typeof ImageContentWrapper>
|
|
39
|
+
|
|
40
|
+
export default meta
|
|
41
|
+
type Story = StoryObj<typeof meta>
|
|
42
|
+
|
|
43
|
+
injectMocks()
|
|
44
|
+
|
|
45
|
+
export const WithPublicId: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
publicId: 'content-123',
|
|
48
|
+
width: 400,
|
|
49
|
+
height: 300,
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const WithExternalId: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
externalId: 'external-123',
|
|
56
|
+
width: 400,
|
|
57
|
+
height: 300,
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const WithCustomLoader: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
publicId: 'content-123',
|
|
64
|
+
width: 400,
|
|
65
|
+
height: 300,
|
|
66
|
+
Loader: 'Loading image...',
|
|
67
|
+
},
|
|
68
|
+
}
|
|
@@ -31,6 +31,13 @@ type Story = StoryObj<typeof meta>
|
|
|
31
31
|
injectMocks()
|
|
32
32
|
|
|
33
33
|
export const Default: Story = {
|
|
34
|
+
decorators: [
|
|
35
|
+
Story => (
|
|
36
|
+
<div style={{maxWidth: 200}}>
|
|
37
|
+
<Story />
|
|
38
|
+
</div>
|
|
39
|
+
),
|
|
40
|
+
],
|
|
34
41
|
args: {
|
|
35
42
|
shop: {
|
|
36
43
|
...createShop('shop1', 'Amazing Store'),
|
|
@@ -40,6 +47,13 @@ export const Default: Story = {
|
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
export const CoverImageDark: Story = {
|
|
50
|
+
decorators: [
|
|
51
|
+
Story => (
|
|
52
|
+
<div style={{maxWidth: 200}}>
|
|
53
|
+
<Story />
|
|
54
|
+
</div>
|
|
55
|
+
),
|
|
56
|
+
],
|
|
43
57
|
name: 'Cover Image',
|
|
44
58
|
args: {
|
|
45
59
|
shop: createShop('cover3', 'Midnight Store', {
|
|
@@ -50,6 +64,13 @@ export const CoverImageDark: Story = {
|
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
export const BrandColorWordmark: Story = {
|
|
67
|
+
decorators: [
|
|
68
|
+
Story => (
|
|
69
|
+
<div style={{maxWidth: 200}}>
|
|
70
|
+
<Story />
|
|
71
|
+
</div>
|
|
72
|
+
),
|
|
73
|
+
],
|
|
53
74
|
name: 'Brand Color + Wordmark',
|
|
54
75
|
args: {
|
|
55
76
|
shop: createShop('brand2', 'Amazing Store', {
|
|
@@ -34,10 +34,17 @@ type Story = StoryObj<typeof meta>
|
|
|
34
34
|
injectMocks()
|
|
35
35
|
|
|
36
36
|
export const Single: Story = {
|
|
37
|
+
decorators: [
|
|
38
|
+
Story => (
|
|
39
|
+
<div style={{maxWidth: 200}}>
|
|
40
|
+
<Story />
|
|
41
|
+
</div>
|
|
42
|
+
),
|
|
43
|
+
],
|
|
37
44
|
args: {
|
|
38
45
|
product: {
|
|
39
46
|
id: '1',
|
|
40
|
-
title: '
|
|
47
|
+
title: 'Teapot',
|
|
41
48
|
|
|
42
49
|
price: {
|
|
43
50
|
amount: '100',
|
|
@@ -61,7 +68,7 @@ export const Single: Story = {
|
|
|
61
68
|
isFavorited: true,
|
|
62
69
|
|
|
63
70
|
featuredImage: {
|
|
64
|
-
url: 'https://
|
|
71
|
+
url: 'https://cdn.shopify.com/static/sample-images/teapot.jpg',
|
|
65
72
|
altText: 'Product 1',
|
|
66
73
|
},
|
|
67
74
|
},
|
|
@@ -80,6 +87,6 @@ export const Grid: Story = {
|
|
|
80
87
|
),
|
|
81
88
|
],
|
|
82
89
|
args: {
|
|
83
|
-
product: createProduct('1', '
|
|
90
|
+
product: createProduct('1', 'Teapot', '100', '120'),
|
|
84
91
|
},
|
|
85
92
|
}
|
|
@@ -20,13 +20,13 @@ injectMocks()
|
|
|
20
20
|
|
|
21
21
|
export const Default: Story = {
|
|
22
22
|
args: {
|
|
23
|
-
product: createProduct('1', '
|
|
23
|
+
product: createProduct('1', 'Teapot', '100', '120'),
|
|
24
24
|
},
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const WithDiscount: Story = {
|
|
28
28
|
args: {
|
|
29
|
-
product: createProduct('2', '
|
|
29
|
+
product: createProduct('2', 'Discounted Teapot', '80', '120'),
|
|
30
30
|
},
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -41,6 +41,6 @@ export const List: Story = {
|
|
|
41
41
|
),
|
|
42
42
|
],
|
|
43
43
|
args: {
|
|
44
|
-
product: createProduct('1', '
|
|
44
|
+
product: createProduct('1', 'Teapot', '100', '120'),
|
|
45
45
|
},
|
|
46
46
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {fn} from 'storybook/test'
|
|
2
|
+
|
|
3
|
+
import {QuantitySelector} from '../components/commerce/quantity-selector'
|
|
4
|
+
|
|
5
|
+
import type {Meta, StoryObj} from '@storybook/react-vite'
|
|
6
|
+
|
|
7
|
+
type QuantitySelectorProps = React.ComponentProps<typeof QuantitySelector>
|
|
8
|
+
|
|
9
|
+
const meta: Meta<QuantitySelectorProps> = {
|
|
10
|
+
title: 'Commerce/QuantitySelector',
|
|
11
|
+
component: QuantitySelector,
|
|
12
|
+
parameters: {},
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
argTypes: {
|
|
15
|
+
quantity: {
|
|
16
|
+
control: 'number',
|
|
17
|
+
description: 'Current quantity value',
|
|
18
|
+
},
|
|
19
|
+
onQuantityChange: {
|
|
20
|
+
action: 'quantity changed',
|
|
21
|
+
description: 'Callback fired when quantity changes',
|
|
22
|
+
},
|
|
23
|
+
maxQuantity: {
|
|
24
|
+
control: 'number',
|
|
25
|
+
description: 'Maximum allowed quantity',
|
|
26
|
+
},
|
|
27
|
+
minQuantity: {
|
|
28
|
+
control: 'number',
|
|
29
|
+
description: 'Minimum allowed quantity',
|
|
30
|
+
},
|
|
31
|
+
disabled: {
|
|
32
|
+
control: 'boolean',
|
|
33
|
+
description: 'Whether the selector is disabled',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
args: {
|
|
37
|
+
onQuantityChange: fn(),
|
|
38
|
+
},
|
|
39
|
+
} satisfies Meta<QuantitySelectorProps>
|
|
40
|
+
|
|
41
|
+
export default meta
|
|
42
|
+
type Story = StoryObj<typeof meta>
|
|
43
|
+
|
|
44
|
+
export const Default: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
quantity: 2,
|
|
47
|
+
maxQuantity: 10,
|
|
48
|
+
minQuantity: 1,
|
|
49
|
+
disabled: false,
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const AtMinimum: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
quantity: 1,
|
|
56
|
+
maxQuantity: 10,
|
|
57
|
+
minQuantity: 1,
|
|
58
|
+
disabled: false,
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const AtMaximum: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
quantity: 10,
|
|
65
|
+
maxQuantity: 10,
|
|
66
|
+
minQuantity: 1,
|
|
67
|
+
disabled: false,
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const Disabled: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
quantity: 3,
|
|
74
|
+
maxQuantity: 10,
|
|
75
|
+
minQuantity: 1,
|
|
76
|
+
disabled: true,
|
|
77
|
+
},
|
|
78
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {fn} from 'storybook/test'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Search,
|
|
5
|
+
SearchInput,
|
|
6
|
+
SearchProvider,
|
|
7
|
+
SearchResultsList,
|
|
8
|
+
} from '../components'
|
|
9
|
+
|
|
10
|
+
import type {Meta, StoryObj} from '@storybook/react-vite'
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
title: 'Commerce/Search',
|
|
14
|
+
component: Search,
|
|
15
|
+
parameters: {
|
|
16
|
+
layout: 'padded',
|
|
17
|
+
},
|
|
18
|
+
tags: ['autodocs'],
|
|
19
|
+
} satisfies Meta<typeof Search>
|
|
20
|
+
|
|
21
|
+
export default meta
|
|
22
|
+
type Story = StoryObj<typeof meta>
|
|
23
|
+
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
onProductClick: fn(),
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const Composite: Story = {
|
|
31
|
+
render: args => (
|
|
32
|
+
<SearchProvider {...args}>
|
|
33
|
+
<SearchInput placeholder="Search..." />
|
|
34
|
+
<SearchResultsList />
|
|
35
|
+
</SearchProvider>
|
|
36
|
+
),
|
|
37
|
+
}
|