@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.
Files changed (57) hide show
  1. package/dist/_virtual/index10.js +2 -2
  2. package/dist/_virtual/index2.js +4 -4
  3. package/dist/_virtual/index3.js +4 -4
  4. package/dist/_virtual/index5.js +3 -2
  5. package/dist/_virtual/index5.js.map +1 -1
  6. package/dist/_virtual/index6.js +2 -3
  7. package/dist/_virtual/index6.js.map +1 -1
  8. package/dist/_virtual/index7.js +2 -2
  9. package/dist/_virtual/index9.js +2 -2
  10. package/dist/components/atoms/list.js +37 -31
  11. package/dist/components/atoms/list.js.map +1 -1
  12. package/dist/components/commerce/product-link.js +117 -113
  13. package/dist/components/commerce/product-link.js.map +1 -1
  14. package/dist/components/commerce/search.js +26 -17
  15. package/dist/components/commerce/search.js.map +1 -1
  16. package/dist/components/navigation/minis-router.js +14 -0
  17. package/dist/components/navigation/minis-router.js.map +1 -0
  18. package/dist/hooks/navigation/useNavigateWithTransition.js.map +1 -1
  19. package/dist/hooks/navigation/useShopNavigation.js.map +1 -1
  20. package/dist/hooks/user/useCurrentUser.js.map +1 -1
  21. package/dist/hooks/user/useFollowedShopsActions.js.map +1 -1
  22. package/dist/hooks/util/useImagePicker.js.map +1 -1
  23. package/dist/index.js +2 -2
  24. package/dist/mocks.js +9 -9
  25. package/dist/mocks.js.map +1 -1
  26. 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
  27. package/dist/shop-minis-react/node_modules/.pnpm/@videojs_xhr@2.7.0/node_modules/@videojs/xhr/lib/index.js +1 -1
  28. package/dist/shop-minis-react/node_modules/.pnpm/@xmldom_xmldom@0.8.10/node_modules/@xmldom/xmldom/lib/index.js +1 -1
  29. package/dist/shop-minis-react/node_modules/.pnpm/mpd-parser@1.3.1/node_modules/mpd-parser/dist/mpd-parser.es.js +1 -1
  30. 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
  31. 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
  32. 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
  33. package/dist/shop-minis-react/node_modules/.pnpm/video.js@8.23.3/node_modules/video.js/dist/video.es.js +1 -1
  34. package/dist/utils/colors.js +1 -1
  35. package/package.json +1 -1
  36. package/src/components/atoms/list.tsx +24 -4
  37. package/src/components/commerce/product-link.tsx +10 -4
  38. package/src/components/commerce/search.tsx +9 -2
  39. package/src/components/index.ts +1 -1
  40. package/src/components/navigation/minis-router.tsx +23 -0
  41. package/src/hooks/navigation/useNavigateWithTransition.ts +6 -1
  42. package/src/hooks/navigation/useShopNavigation.ts +3 -1
  43. package/src/hooks/user/useCurrentUser.ts +3 -0
  44. package/src/hooks/user/useFollowedShopsActions.ts +2 -2
  45. package/src/hooks/util/{useImagePicker.tsx → useImagePicker.ts} +8 -2
  46. package/src/index.css +1 -0
  47. package/src/mocks.ts +3 -3
  48. package/src/stories/ImageContentWrapper.stories.tsx +68 -0
  49. package/src/stories/MerchantCard.stories.tsx +21 -0
  50. package/src/stories/ProductCard.stories.tsx +10 -3
  51. package/src/stories/ProductLink.stories.tsx +3 -3
  52. package/src/stories/QuantitySelector.stories.tsx +78 -0
  53. package/src/stories/Search.stories.tsx +37 -0
  54. package/src/stories/VideoPlayer.stories.tsx +129 -0
  55. package/src/styles/fonts.css +26 -0
  56. package/src/styles/theme.css +26 -0
  57. package/src/hooks/util/useImagePicker.doc.tsx +0 -41
@@ -1,4 +1,4 @@
1
- import { __module as r } from "../../../../../../../_virtual/index10.js";
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/index2.js";
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";
@@ -1,4 +1,4 @@
1
- import o from "../_virtual/index3.js";
1
+ import o from "../_virtual/index2.js";
2
2
  const a = (r) => o(r).darken(0.2).isDark();
3
3
  export {
4
4
  a as isDarkColor
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.0.28",
4
+ "version": "0.0.30",
5
5
  "sideEffects": false,
6
6
  "type": "module",
7
7
  "engines": {
@@ -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={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, fetchMore, headerHeight]
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({product, hideFavoriteAction = false}: ProductLinkProps) {
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
- }, [navigateToProduct, id])
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 key={product.id} product={product} hideFavoriteAction />
243
+ <ProductLink
244
+ key={product.id}
245
+ product={product}
246
+ hideFavoriteAction
247
+ onClick={onProductClick}
248
+ />
242
249
  </div>
243
250
  )
244
251
  }
@@ -10,7 +10,7 @@ export * from './commerce/search'
10
10
 
11
11
  export * from './content/image-content-wrapper'
12
12
 
13
- export * from './navigation/transition-container'
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
- export function useNavigateWithTransition() {
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
 
@@ -9,6 +9,9 @@ import {
9
9
  export interface UseCurrentUserParams extends DataHookOptionsBase {}
10
10
 
11
11
  export interface UseCurrentUserReturns extends DataHookReturnsBase {
12
+ /**
13
+ * The current user logged into Shop.
14
+ */
12
15
  currentUser: UserProfile | null
13
16
  }
14
17
 
@@ -8,11 +8,11 @@ import {useShopActions} from '../../internal/useShopActions'
8
8
 
9
9
  interface UseFollowedShopsActionsReturns {
10
10
  /**
11
- * Follow a shop.
11
+ * Follows a shop.
12
12
  */
13
13
  followShop: (params: FollowShopParams) => Promise<boolean>
14
14
  /**
15
- * Unfollow a shop.
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 UseImagePickerReturn {
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(): UseImagePickerReturn {
17
+ export function useImagePicker(): UseImagePickerReturns {
12
18
  const {openCamera, openGallery} = useImagePickerContext()
13
19
 
14
20
  return {
package/src/index.css CHANGED
@@ -1,6 +1,7 @@
1
1
  @import 'tailwindcss';
2
2
  @import 'tw-animate-css';
3
3
 
4
+ @import './styles/fonts.css';
4
5
  @import './styles/theme.css';
5
6
  @import './styles/globals.css';
6
7
  @import './styles/animations.css';
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/s/files/1/0621/0463/3599/files/61ChhrRjK9L._AC_SL1000_1639abe8-4cd3-4bee-9867-73f26b0acf0a.jpg?v=1702559955`,
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://example.com/content-image.jpg',
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://example.com/content-image.jpg',
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: 'Product 1',
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://picsum.photos/400/400',
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', 'Product 1', '100', '120'),
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', 'Product 1', '100', '120'),
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', 'Product with Discount', '80', '120'),
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', 'Product 1', '100', '120'),
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
+ }