@graphcommerce/magento-product 9.0.0-canary.115 → 9.0.0-canary.117

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 (28) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/components/ProductAddToCart/index.ts +0 -1
  3. package/components/ProductFiltersPro/ProductFiltersProAllFiltersSidebar.tsx +1 -3
  4. package/components/ProductFiltersPro/ProductFiltersProChips.tsx +3 -1
  5. package/components/ProductFiltersPro/ProductFiltersProLayoutSidebar.tsx +5 -1
  6. package/components/ProductFiltersPro/ProductFiltersProNoResults.tsx +2 -2
  7. package/components/ProductList/ProductList.graphql +4 -3
  8. package/components/ProductListFilters/ProductFilters.graphql +2 -2
  9. package/components/ProductListItem/ProductListItem.tsx +45 -13
  10. package/components/ProductListItem/ProductListItemImage.tsx +4 -4
  11. package/components/ProductListItem/ProductListItemLinkOrDiv.tsx +9 -5
  12. package/components/ProductListItems/renderer.tsx +1 -0
  13. package/components/ProductListPrice/ProductListPrice.tsx +9 -5
  14. package/components/ProductListSuggestions/ProductListSearchSuggestion.graphql +3 -0
  15. package/components/ProductListSuggestions/ProductListSuggestions.graphql +1 -1
  16. package/components/ProductPage/ProductPageAddToCartRow.tsx +1 -1
  17. package/components/ProductPageBreadcrumb/ProductPageBreadcrumb.tsx +1 -0
  18. package/components/ProductPagePrice/ProductPagePrice.tsx +6 -6
  19. package/components/ProductPagePrice/ProductPagePriceTiers.tsx +3 -3
  20. package/components/ProductStaticPaths/getSitemapPaths.ts +1 -0
  21. package/components/ProductWeight/ProductWeight.tsx +1 -0
  22. package/components/index.ts +5 -0
  23. package/hooks/useProductLink.ts +1 -1
  24. package/hooks/useProductList.ts +4 -4
  25. package/package.json +13 -13
  26. package/components/ProductAddToCart/ProductAddToCart.tsx +0 -142
  27. package/components/ProductPageGallery/ProductImage.tsx +0 -10
  28. package/components/ProductPageGallery/ProductVideo.tsx +0 -10
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.117
4
+
5
+ ## 9.0.0-canary.116
6
+
7
+ ### Patch Changes
8
+
9
+ - [#2452](https://github.com/graphcommerce-org/graphcommerce/pull/2452) [`5dfd3b2`](https://github.com/graphcommerce-org/graphcommerce/commit/5dfd3b201255ef35263485d04153d37bb7e4fe67) - Renamed useInContextQuery to usePrivateQuery ([@paales](https://github.com/paales))
10
+
3
11
  ## 9.0.0-canary.115
4
12
 
5
13
  ## 9.0.0-canary.114
@@ -1,2 +1 @@
1
- export * from './ProductAddToCart'
2
1
  export * from './ProductAddToCart.gql'
@@ -17,9 +17,7 @@ export type ProductFiltersProAllFiltersSidebarProps = ProductFiltersProAggregati
17
17
 
18
18
  /**
19
19
  * @deprecated Not used anymore
20
- *
21
- * @param props
22
- * @returns
20
+ * @public
23
21
  */
24
22
  export function ProductFiltersProAllFiltersSidebar(props: ProductFiltersProAllFiltersSidebarProps) {
25
23
  const { sort_fields, total_count, renderer, sx = [], category, params } = props
@@ -5,7 +5,9 @@ import {
5
5
  } from './ProductFiltersProAggregations'
6
6
 
7
7
  /**
8
- * @deprecated Not used anymore, use `<ProductFiltersProAggregations renderer={productFiltersProChipRenderer}/>`
8
+ * @deprecated Not used anymore, use `<ProductFiltersProAggregations
9
+ * renderer={productFiltersProChipRenderer}/>`
10
+ * @public
9
11
  */
10
12
  export function ProductFiltersProFilterChips(props: ProductFiltersProAggregationsProps) {
11
13
  const { renderer } = props
@@ -1,5 +1,5 @@
1
1
  import { FormAutoSubmit } from '@graphcommerce/ecommerce-ui'
2
- import { StickyBelowHeader, extendableComponent } from '@graphcommerce/next-ui'
2
+ import { extendableComponent, StickyBelowHeader } from '@graphcommerce/next-ui'
3
3
  import type { Theme } from '@mui/material'
4
4
  // eslint-disable-next-line @typescript-eslint/no-restricted-imports
5
5
  import { Box, Container, useMediaQuery } from '@mui/material'
@@ -25,6 +25,10 @@ const name = 'ProductFiltersProLayoutSidebar'
25
25
  const parts = ['root', 'content'] as const
26
26
  const { withState } = extendableComponent<OwnerProps, typeof name, typeof parts>(name, parts)
27
27
 
28
+ /**
29
+ * @deprecated
30
+ * @public
31
+ */
28
32
  export function ProductFiltersProLayoutSidebar(props: ProductFiltersProLayoutSidebarProps) {
29
33
  const {
30
34
  items,
@@ -33,8 +33,8 @@ export function ProductFiltersProNoResults(props: ProductFitlersProNoResultProps
33
33
  >
34
34
  {term ? (
35
35
  <>
36
- <Typography variant='h5' align='center'>
37
- <Trans>We couldn&apos;t find any results for {term}</Trans>
36
+ <Typography variant='h5'>
37
+ <Trans>We couldnt find any results for {term}’</Trans>
38
38
  </Typography>
39
39
  <p>
40
40
  {hasFilters ? (
@@ -4,8 +4,9 @@ query ProductList(
4
4
  $filters: ProductAttributeFilterInput = {}
5
5
  $sort: ProductAttributeSortInput = {}
6
6
  $search: String = ""
7
- $context: InContextInput = { loggedIn: false }
7
+ $context: PrivateContext
8
8
  $onlyItems: Boolean = false
9
+ $quickSearch: Boolean = false
9
10
  ) {
10
11
  products(
11
12
  pageSize: $pageSize
@@ -13,10 +14,10 @@ query ProductList(
13
14
  filter: $filters
14
15
  sort: $sort
15
16
  search: $search
16
- ) @inContext(context: $context) {
17
+ ) @privateContext(context: $context) {
17
18
  ...ProductListSuggestions @skip(if: $onlyItems)
18
19
  ...ProductListFilters @skip(if: $onlyItems)
19
- ...ProductListCount @skip(if: $onlyItems)
20
+ ...ProductListCount @skip(if: $onlyItems) @include(if: $quickSearch)
20
21
  ...ProductListPagination @skip(if: $onlyItems)
21
22
  ...ProductListSort @skip(if: $onlyItems)
22
23
  ...ProductListItems
@@ -1,11 +1,11 @@
1
1
  query ProductFilters(
2
2
  $filters: ProductAttributeFilterInput = {}
3
3
  $search: String
4
- $context: InContextInput
4
+ $context: PrivateContext
5
5
  $pageSize: Int = 1
6
6
  ) {
7
7
  filters: products(filter: $filters, currentPage: 1, pageSize: $pageSize, search: $search)
8
- @inContext(context: $context) {
8
+ @privateContext(context: $context) {
9
9
  page_info {
10
10
  total_pages
11
11
  }
@@ -14,7 +14,7 @@ import type {
14
14
  ProductListsItemImageAreaProps,
15
15
  } from './ProductListItemImageContainer'
16
16
  import { ProductImageContainer, ProductListItemImageAreas } from './ProductListItemImageContainer'
17
- import { ProductListItemLinkOrDiv } from './ProductListItemLinkOrDiv'
17
+ import { ProductListItemLinkOrDiv, ProductListItemLinkOrDivProps } from './ProductListItemLinkOrDiv'
18
18
  import type { ProductListItemTitleAndPriceProps } from './ProductListItemTitleAndPrice'
19
19
  import { ProductListItemTitleAndPrice } from './ProductListItemTitleAndPrice'
20
20
 
@@ -44,21 +44,29 @@ export type BaseProps = {
44
44
  imageOnly?: boolean
45
45
  children?: React.ReactNode
46
46
  sx?: SxProps<Theme>
47
- // eslint-disable-next-line react/no-unused-prop-types
48
- onClick?: (event: React.MouseEvent<HTMLAnchorElement>, item: ProductListItemFragment) => void
47
+ onClick?: (
48
+ event: React.MouseEvent<HTMLAnchorElement | HTMLDivElement>,
49
+ item: ProductListItemFragment,
50
+ ) => void
51
+ slotProps?: {
52
+ root?: Partial<ProductListItemLinkOrDivProps>
53
+ image?: Partial<ProductListItemImageProps>
54
+ imageAreas?: Partial<ProductListsItemImageAreaProps>
55
+ titleAndPrice?: Partial<ProductListItemTitleAndPriceProps>
56
+ }
49
57
  } & StyleProps &
50
58
  Omit<ProductListItemTitleAndPriceProps, 'title' | 'classes' | 'children'> &
51
59
  Omit<ProductListItemImageProps, 'classes'> &
52
60
  Omit<ProductListsItemImageAreaProps, 'classes'> &
53
61
  Pick<ImageProps, 'loading' | 'sizes' | 'dontReportWronglySizedImages'>
54
62
 
55
- // eslint-disable-next-line react/no-unused-prop-types
56
63
  export type SkeletonProps = BaseProps & { __typename: 'Skeleton' }
57
64
 
58
65
  export type ProductProps = BaseProps & ProductListItemFragment
59
66
 
60
67
  export type ProductListItemProps = ProductProps | SkeletonProps
61
68
 
69
+ /** @public */
62
70
  export function ProductListItemReal(props: ProductProps) {
63
71
  const {
64
72
  subTitle,
@@ -78,18 +86,20 @@ export function ProductListItemReal(props: ProductProps) {
78
86
  titleComponent = 'h2',
79
87
  sx = [],
80
88
  onClick,
89
+ slotProps = {},
81
90
  } = props
82
91
 
83
- const handleClick = useEventCallback((e: React.MouseEvent<HTMLAnchorElement>) =>
84
- onClick?.(e, props),
85
- )
86
-
87
92
  return (
88
93
  <ProductListItemLinkOrDiv
89
94
  href={productLink(props)}
90
95
  className={classes.root}
91
- sx={sx}
92
- onClick={handleClick}
96
+ onClick={(e: React.MouseEvent<HTMLAnchorElement | HTMLDivElement>) => onClick?.(e, props)}
97
+ {...slotProps.root}
98
+ sx={[
99
+ ...(Array.isArray(sx) ? sx : [sx]),
100
+ ...(Array.isArray(slotProps.root?.sx) ? slotProps.root.sx : [slotProps.root?.sx]),
101
+ ]}
102
+ ref={slotProps.root?.ref as React.Ref<HTMLAnchorElement | HTMLDivElement>}
93
103
  >
94
104
  <ProductImageContainer className={classes.imageContainer}>
95
105
  <ProductListItemImage
@@ -100,6 +110,7 @@ export function ProductListItemReal(props: ProductProps) {
100
110
  loading={loading}
101
111
  sizes={sizes}
102
112
  dontReportWronglySizedImages={dontReportWronglySizedImages}
113
+ {...slotProps.image}
103
114
  />
104
115
 
105
116
  {!imageOnly && (
@@ -114,6 +125,7 @@ export function ProductListItemReal(props: ProductProps) {
114
125
  {topLeft}
115
126
  </>
116
127
  }
128
+ {...slotProps.imageAreas}
117
129
  />
118
130
  )}
119
131
  </ProductImageContainer>
@@ -125,6 +137,7 @@ export function ProductListItemReal(props: ProductProps) {
125
137
  titleComponent={titleComponent}
126
138
  title={name}
127
139
  subTitle={subTitle}
140
+ {...slotProps.titleAndPrice}
128
141
  >
129
142
  <ProductListPrice {...price_range.minimum_price} />
130
143
  </ProductListItemTitleAndPrice>
@@ -135,13 +148,30 @@ export function ProductListItemReal(props: ProductProps) {
135
148
  )
136
149
  }
137
150
 
151
+ /** @public */
138
152
  export function ProductListItemSkeleton(props: BaseProps) {
139
- const { children, imageOnly = false, aspectRatio, titleComponent = 'h2', sx = [] } = props
153
+ const {
154
+ children,
155
+ imageOnly = false,
156
+ aspectRatio,
157
+ titleComponent = 'h2',
158
+ sx = [],
159
+ slotProps = {},
160
+ } = props
140
161
 
141
162
  return (
142
- <ProductListItemLinkOrDiv sx={sx} className={classes.root}>
163
+ <ProductListItemLinkOrDiv
164
+ sx={sx}
165
+ className={classes.root}
166
+ {...slotProps.root}
167
+ ref={slotProps.root?.ref as React.Ref<HTMLAnchorElement | HTMLDivElement>}
168
+ >
143
169
  <ProductImageContainer className={classes.imageContainer}>
144
- <ProductListItemImageSkeleton classes={classes} aspectRatio={aspectRatio} />
170
+ <ProductListItemImageSkeleton
171
+ classes={classes}
172
+ aspectRatio={aspectRatio}
173
+ {...slotProps.image}
174
+ />
145
175
  </ProductImageContainer>
146
176
 
147
177
  {!imageOnly && (
@@ -151,6 +181,7 @@ export function ProductListItemSkeleton(props: BaseProps) {
151
181
  titleComponent={titleComponent}
152
182
  title={<Skeleton variant='text' sx={{ width: '100px' }} />}
153
183
  subTitle={<Skeleton variant='text' sx={{ width: '20px' }} />}
184
+ {...slotProps.titleAndPrice}
154
185
  >
155
186
  <Skeleton variant='text' sx={{ width: '20px' }} />
156
187
  </ProductListItemTitleAndPrice>
@@ -164,6 +195,7 @@ export function ProductListItemSkeleton(props: BaseProps) {
164
195
  function isSkeleton(props: ProductListItemProps): props is SkeletonProps {
165
196
  return props.__typename === 'Skeleton'
166
197
  }
198
+
167
199
  export function ProductListItem(props: ProductListItemProps) {
168
200
  return isSkeleton(props) ? (
169
201
  <ProductListItemSkeleton {...props} />
@@ -26,7 +26,7 @@ function PlaceHolderContainer(props: BoxProps) {
26
26
 
27
27
  export type ProductListItemImageProps = {
28
28
  aspectRatio?: [number, number]
29
- classes: {
29
+ classes?: {
30
30
  image?: string
31
31
  placeholder?: string
32
32
  }
@@ -35,7 +35,7 @@ export type ProductListItemImageProps = {
35
35
  export function ProductListItemImageSkeleton(props: ProductListItemImageProps) {
36
36
  const { aspectRatio = [4, 3], classes } = props
37
37
  return (
38
- <PlaceHolderContainer className={`${classes.placeholder} ${classes.image}`}>
38
+ <PlaceHolderContainer className={`${classes?.placeholder} ${classes?.image}`}>
39
39
  <Skeleton
40
40
  animation='wave'
41
41
  sx={{
@@ -66,7 +66,7 @@ export function ProductListItemImage(props: ImageOrPlaceholderProps) {
66
66
  src={src}
67
67
  alt={alt ?? ''}
68
68
  {...image}
69
- className={classes.image}
69
+ className={classes?.image}
70
70
  sx={[
71
71
  {
72
72
  objectFit: 'contain',
@@ -80,7 +80,7 @@ export function ProductListItemImage(props: ImageOrPlaceholderProps) {
80
80
  }
81
81
 
82
82
  return (
83
- <PlaceHolderContainer className={`${classes.placeholder} ${classes.image}`}>
83
+ <PlaceHolderContainer className={`${classes?.placeholder} ${classes?.image}`}>
84
84
  <Box
85
85
  sx={[
86
86
  {
@@ -1,6 +1,7 @@
1
- import { NextLink, breakpointVal } from '@graphcommerce/next-ui'
1
+ import { breakpointVal, NextLink } from '@graphcommerce/next-ui'
2
2
  import type { BoxProps, ButtonBaseProps, SxProps, Theme } from '@mui/material'
3
3
  import { Box, ButtonBase } from '@mui/material'
4
+ import React from 'react'
4
5
 
5
6
  export type ProductListItemLinkProps = ButtonBaseProps<typeof NextLink>
6
7
  export type ProductListItemLinkOrDivProps = ProductListItemLinkProps | BoxProps
@@ -9,7 +10,10 @@ function isLink(props: ProductListItemLinkOrDivProps): props is ProductListItemL
9
10
  return 'href' in props
10
11
  }
11
12
 
12
- export function ProductListItemLinkOrDiv(props: ProductListItemLinkOrDivProps) {
13
+ export const ProductListItemLinkOrDiv = React.forwardRef<
14
+ HTMLDivElement | HTMLAnchorElement,
15
+ ProductListItemLinkOrDivProps
16
+ >((props, ref) => {
13
17
  const { sx = [] } = props
14
18
 
15
19
  const sxProps: SxProps<Theme> = [
@@ -28,8 +32,8 @@ export function ProductListItemLinkOrDiv(props: ProductListItemLinkOrDivProps) {
28
32
  ]
29
33
 
30
34
  return isLink(props) ? (
31
- <ButtonBase component={NextLink} {...props} sx={sxProps} />
35
+ <ButtonBase ref={ref} component={NextLink} {...props} sx={sxProps} focusRipple />
32
36
  ) : (
33
- <Box {...props} sx={sxProps} />
37
+ <Box ref={ref} component='div' {...props} sx={sxProps} />
34
38
  )
35
- }
39
+ })
@@ -8,6 +8,7 @@ export type ProductListItemRenderer = TypeRenderer<ProductListItemFragment | Ske
8
8
 
9
9
  /**
10
10
  * @deprecated Please use productListRenderer from the example directory instead.
11
+ * @public
11
12
  */
12
13
  export const renderer: ProductListItemRenderer = {
13
14
  Skeleton: ProductListItem,
@@ -1,4 +1,4 @@
1
- import { InContextMask } from '@graphcommerce/graphql'
1
+ import { PrivateQueryMask } from '@graphcommerce/graphql'
2
2
  import { Money } from '@graphcommerce/magento-store'
3
3
  import { extendableComponent } from '@graphcommerce/next-ui'
4
4
  import type { TypographyProps } from '@mui/material'
@@ -21,7 +21,7 @@ export function ProductListPrice(props: ProductListPriceProps) {
21
21
  return (
22
22
  <Typography component='div' variant='body1' className={classes.root} sx={sx}>
23
23
  {regular_price.value !== final_price.value && (
24
- <InContextMask
24
+ <PrivateQueryMask
25
25
  component='span'
26
26
  sx={{
27
27
  textDecoration: 'line-through',
@@ -32,11 +32,15 @@ export function ProductListPrice(props: ProductListPriceProps) {
32
32
  className={classes.discountPrice}
33
33
  >
34
34
  <Money {...regular_price} />
35
- </InContextMask>
35
+ </PrivateQueryMask>
36
36
  )}
37
- <InContextMask className={classes.finalPrice} component='span' skeleton={{ width: '3.5em' }}>
37
+ <PrivateQueryMask
38
+ className={classes.finalPrice}
39
+ component='span'
40
+ skeleton={{ width: '3.5em' }}
41
+ >
38
42
  <Money {...final_price} />
39
- </InContextMask>
43
+ </PrivateQueryMask>
40
44
  </Typography>
41
45
  )
42
46
  }
@@ -0,0 +1,3 @@
1
+ fragment ProductListSearchSuggestion on SearchSuggestion {
2
+ search
3
+ }
@@ -1,5 +1,5 @@
1
1
  fragment ProductListSuggestions on Products {
2
2
  suggestions {
3
- search
3
+ ...ProductListSearchSuggestion
4
4
  }
5
5
  }
@@ -10,7 +10,7 @@ export type ProductPageAddToCartRowProps = {
10
10
  product: UseAddProductsToCartActionFragment
11
11
  }
12
12
 
13
- export function ProductPageAddToCartRow(props: ProductPageAddToCartRowProps) {
13
+ function ProductPageAddToCartRow(props: ProductPageAddToCartRowProps) {
14
14
  const { sx, children, after } = props
15
15
  return (
16
16
  <>
@@ -11,6 +11,7 @@ export type ProductPageBreadcrumbProps = ProductPageBreadcrumbFragment &
11
11
 
12
12
  /**
13
13
  * @deprecated Please use ProductPageBreadcrumbs
14
+ * @public
14
15
  */
15
16
  export function ProductPageBreadcrumb(props: ProductPageBreadcrumbProps) {
16
17
  const { categories, name, ...breadcrumbProps } = props
@@ -1,11 +1,11 @@
1
1
  import { useWatch } from '@graphcommerce/ecommerce-ui'
2
- import { InContextMask } from '@graphcommerce/graphql'
2
+ import { PrivateQueryMask } from '@graphcommerce/graphql'
3
3
  import { Money } from '@graphcommerce/magento-store'
4
4
  import { extendableComponent } from '@graphcommerce/next-ui'
5
5
  import type { AddToCartItemSelector } from '../AddProductsToCart'
6
6
  import { useFormAddProductsToCart } from '../AddProductsToCart'
7
- import type { ProductPagePriceFragment } from './ProductPagePrice.gql'
8
7
  import { getProductTierPrice } from './getProductTierPrice'
8
+ import type { ProductPagePriceFragment } from './ProductPagePrice.gql'
9
9
  import type { UseCustomizableOptionPriceProps } from './useCustomizableOptionPrice'
10
10
  import { useCustomizableOptionPrice } from './useCustomizableOptionPrice'
11
11
 
@@ -31,22 +31,22 @@ export function ProductPagePrice(props: ProductPagePriceProps) {
31
31
  return (
32
32
  <>
33
33
  {regularPrice.value !== price.value && (
34
- <InContextMask
34
+ <PrivateQueryMask
35
35
  component='span'
36
36
  className={classes.discountPrice}
37
37
  skeleton={{ variant: 'text', sx: { width: '3em', transform: 'none' } }}
38
38
  sx={[{ textDecoration: 'line-through', color: 'text.disabled', marginRight: '8px' }]}
39
39
  >
40
40
  <Money {...regularPrice} />
41
- </InContextMask>
41
+ </PrivateQueryMask>
42
42
  )}
43
- <InContextMask
43
+ <PrivateQueryMask
44
44
  component='span'
45
45
  skeleton={{ variant: 'text', sx: { width: '3em', transform: 'none' } }}
46
46
  className={classes.finalPrice}
47
47
  >
48
48
  <Money {...price} value={priceValue} />
49
- </InContextMask>
49
+ </PrivateQueryMask>
50
50
  </>
51
51
  )
52
52
  }
@@ -1,4 +1,4 @@
1
- import { InContextMask } from '@graphcommerce/graphql'
1
+ import { PrivateQueryMask } from '@graphcommerce/graphql'
2
2
  import { Money } from '@graphcommerce/magento-store'
3
3
  import { filterNonNullableKeys } from '@graphcommerce/next-ui'
4
4
  import { Trans } from '@lingui/react'
@@ -22,7 +22,7 @@ export function ProductPagePriceTiers(props: ProductPagePriceTiersProps) {
22
22
  if (!priceTiers.length) return null
23
23
 
24
24
  return (
25
- <InContextMask sx={sx} variant='rectangular'>
25
+ <PrivateQueryMask sx={sx} variant='rectangular'>
26
26
  {priceTiers.map(({ quantity, final_price, discount }) => (
27
27
  <div key={quantity}>
28
28
  <Trans
@@ -32,6 +32,6 @@ export function ProductPagePriceTiers(props: ProductPagePriceTiersProps) {
32
32
  />
33
33
  </div>
34
34
  ))}
35
- </InContextMask>
35
+ </PrivateQueryMask>
36
36
  )
37
37
  }
@@ -5,6 +5,7 @@ import { ProductStaticPathsDocument } from './ProductStaticPaths.gql'
5
5
 
6
6
  /**
7
7
  * @deprecated Not used anymore, use `getProductStaticPaths` instead.
8
+ * @public
8
9
  */
9
10
  export async function getSitemapPaths(
10
11
  client: ApolloClient<NormalizedCacheObject>,
@@ -6,6 +6,7 @@ import type { ProductWeightFragment } from './ProductWeight.gql'
6
6
 
7
7
  export type ProductWeightProps = Omit<UnitFormatProps, 'unit'> & { product: ProductWeightFragment }
8
8
 
9
+ /** @public */
9
10
  export function ProductWeight(props: ProductWeightProps) {
10
11
  const { product, ...rest } = props
11
12
 
@@ -8,6 +8,10 @@ export * from './ProductListCount/ProductListCount'
8
8
  export * from './ProductListFilters'
9
9
  export * from './ProductListFiltersContainer/ProductListFiltersContainer'
10
10
  export * from './ProductListItem/ProductListItem'
11
+ export * from './ProductListItem/ProductListItemImage'
12
+ export * from './ProductListItem/ProductListItemTitleAndPrice'
13
+ export * from './ProductListItem/ProductListItemImageContainer'
14
+ export * from './ProductListItem/ProductListItemLinkOrDiv'
11
15
  export * from './ProductListItems/filteredProductList'
12
16
  export * from './ProductListItems/filterTypes'
13
17
  export * from './ProductListItems/getFilterTypes'
@@ -43,3 +47,4 @@ export * from './ProductWeight/ProductWeight'
43
47
  export * from './ProductListPrice'
44
48
  export * from './ProductListSuggestions/ProductListSuggestions'
45
49
  export * from './ProductListSuggestions/ProductListSuggestions.gql'
50
+ export * from './ProductListSuggestions/ProductListSearchSuggestion.gql'
@@ -2,7 +2,7 @@ import type { ProductLinkFragment } from './ProductLink.gql'
2
2
 
3
3
  export type ProductLinkProps = Omit<ProductLinkFragment, 'uid'>
4
4
 
5
- export const productRoute = import.meta.graphCommerce.productRoute ?? '/p/'
5
+ const productRoute = import.meta.graphCommerce.productRoute ?? '/p/'
6
6
 
7
7
  export function productPath(urlKey: string) {
8
8
  return `${productRoute}${urlKey}`
@@ -1,6 +1,6 @@
1
1
  import { debounce } from '@graphcommerce/ecommerce-ui'
2
2
  import type { ApolloClient } from '@graphcommerce/graphql'
3
- import { getInContextInput, useInContextQuery, useQuery } from '@graphcommerce/graphql'
3
+ import { getPrivateQueryContext, usePrivateQuery, useQuery } from '@graphcommerce/graphql'
4
4
  import { StoreConfigDocument } from '@graphcommerce/magento-store'
5
5
  import { showPageLoadIndicator } from '@graphcommerce/next-ui'
6
6
  import { useEventCallback } from '@mui/material'
@@ -41,7 +41,7 @@ export const prefetchProductList = debounce(
41
41
 
42
42
  showPageLoadIndicator.set(true)
43
43
 
44
- const context = getInContextInput(client)
44
+ const context = getPrivateQueryContext(client)
45
45
  const productList = client.query({
46
46
  query: ProductListDocument,
47
47
  variables: { ...variables, context },
@@ -103,8 +103,8 @@ export function useProductList<
103
103
  const { params, shallow } = useRouterFilterParams(props)
104
104
  const variables = useProductListApplyCategoryDefaults(params, category)
105
105
 
106
- const result = useInContextQuery(ProductListDocument, { variables, skip: !shallow }, props)
107
- const filters = useInContextQuery(
106
+ const result = usePrivateQuery(ProductListDocument, { variables, skip: !shallow }, props)
107
+ const filters = usePrivateQuery(
108
108
  ProductFiltersDocument,
109
109
  { variables: categoryDefaultsToProductListFilters(variables), skip: !shallow },
110
110
  props,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-product",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "9.0.0-canary.115",
5
+ "version": "9.0.0-canary.117",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -18,18 +18,18 @@
18
18
  "typescript": "5.7.2"
19
19
  },
20
20
  "peerDependencies": {
21
- "@graphcommerce/ecommerce-ui": "^9.0.0-canary.115",
22
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.115",
23
- "@graphcommerce/framer-next-pages": "^9.0.0-canary.115",
24
- "@graphcommerce/framer-scroller": "^9.0.0-canary.115",
25
- "@graphcommerce/graphql": "^9.0.0-canary.115",
26
- "@graphcommerce/graphql-mesh": "^9.0.0-canary.115",
27
- "@graphcommerce/image": "^9.0.0-canary.115",
28
- "@graphcommerce/magento-cart": "^9.0.0-canary.115",
29
- "@graphcommerce/magento-store": "^9.0.0-canary.115",
30
- "@graphcommerce/next-ui": "^9.0.0-canary.115",
31
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.115",
32
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.115",
21
+ "@graphcommerce/ecommerce-ui": "^9.0.0-canary.117",
22
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.117",
23
+ "@graphcommerce/framer-next-pages": "^9.0.0-canary.117",
24
+ "@graphcommerce/framer-scroller": "^9.0.0-canary.117",
25
+ "@graphcommerce/graphql": "^9.0.0-canary.117",
26
+ "@graphcommerce/graphql-mesh": "^9.0.0-canary.117",
27
+ "@graphcommerce/image": "^9.0.0-canary.117",
28
+ "@graphcommerce/magento-cart": "^9.0.0-canary.117",
29
+ "@graphcommerce/magento-store": "^9.0.0-canary.117",
30
+ "@graphcommerce/next-ui": "^9.0.0-canary.117",
31
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.117",
32
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.117",
33
33
  "@lingui/core": "^4.2.1",
34
34
  "@lingui/macro": "^4.2.1",
35
35
  "@lingui/react": "^4.2.1",
@@ -1,142 +0,0 @@
1
- import { NumberFieldElement } from '@graphcommerce/ecommerce-ui'
2
- import type { ProductInterface } from '@graphcommerce/graphql-mesh'
3
- import { ApolloCartErrorAlert, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
4
- import type { MoneyProps } from '@graphcommerce/magento-store'
5
- import { Money } from '@graphcommerce/magento-store'
6
- import {
7
- Button,
8
- IconSvg,
9
- MessageSnackbar,
10
- extendableComponent,
11
- iconChevronRight,
12
- } from '@graphcommerce/next-ui'
13
- import { Trans } from '@lingui/macro'
14
- import type { ButtonProps } from '@mui/material'
15
- import { Alert, Box, Divider, Typography } from '@mui/material'
16
- import React from 'react'
17
- import type { ProductAddToCartMutationVariables } from './ProductAddToCart.gql'
18
- import { ProductAddToCartDocument } from './ProductAddToCart.gql'
19
-
20
- const { classes, selectors } = extendableComponent('ProductAddToCart', [
21
- 'root',
22
- 'button',
23
- 'price',
24
- 'divider',
25
- 'buttonWrapper',
26
- ] as const)
27
-
28
- export type AddToCartProps = React.ComponentProps<typeof ProductAddToCart>
29
-
30
- /** @deprecated Please us AddProductsToCartForm and it's components */
31
- export function ProductAddToCart(
32
- props: Pick<ProductInterface, 'name'> & {
33
- variables: Omit<ProductAddToCartMutationVariables, 'cartId'>
34
- name: string
35
- price: MoneyProps
36
- additionalButtons?: React.ReactNode
37
- children?: React.ReactNode
38
- } & Omit<ButtonProps, 'type' | 'name'>,
39
- ) {
40
- const { name, children, variables, price, sx, additionalButtons, ...buttonProps } = props
41
-
42
- const form = useFormGqlMutationCart(ProductAddToCartDocument, {
43
- defaultValues: { ...variables },
44
- })
45
-
46
- const { handleSubmit, formState, error, control, required, data } = form
47
- const submitHandler = handleSubmit(() => {})
48
-
49
- return (
50
- <Box component='form' onSubmit={submitHandler} noValidate className={classes.root} sx={sx}>
51
- <Divider className={classes.divider} sx={(theme) => ({ margin: `${theme.spacings.xs} 0` })} />
52
-
53
- <Typography
54
- variant='h4'
55
- className={classes.price}
56
- sx={(theme) => ({
57
- fontWeight: theme.typography.fontWeightBold,
58
- margin: `${theme.spacings.sm} 0`,
59
- })}
60
- >
61
- <Money {...price} />
62
- </Typography>
63
-
64
- <NumberFieldElement
65
- variant='outlined'
66
- error={formState.isSubmitted && !!formState.errors.quantity}
67
- required={required.quantity}
68
- inputProps={{ min: 1 }}
69
- name='quantity'
70
- rules={{ required: required.quantity }}
71
- helperText={formState.isSubmitted && formState.errors.quantity?.message}
72
- disabled={formState.isSubmitting}
73
- size='small'
74
- control={control}
75
- />
76
- {children}
77
- <Box
78
- sx={(theme) => ({
79
- display: 'flex',
80
- alignItems: 'center',
81
- columnGap: theme.spacings.xs,
82
- })}
83
- className={classes.buttonWrapper}
84
- >
85
- <Button
86
- type='submit'
87
- className={classes.button}
88
- loading={formState.isSubmitting}
89
- color='primary'
90
- variant='pill'
91
- size='large'
92
- sx={(theme) => ({
93
- marginTop: theme.spacings.sm,
94
- marginBottom: theme.spacings.sm,
95
- width: '100%',
96
- })}
97
- {...buttonProps}
98
- >
99
- <Trans>Add to Cart</Trans>
100
- </Button>
101
- {additionalButtons}
102
- </Box>
103
-
104
- <ApolloCartErrorAlert error={error} />
105
-
106
- {data?.addProductsToCart?.user_errors.map((e) => (
107
- <Box key={e?.code}>
108
- <Alert severity='error'>{e?.message}</Alert>
109
- </Box>
110
- ))}
111
-
112
- <MessageSnackbar
113
- open={
114
- !formState.isSubmitting &&
115
- formState.isSubmitSuccessful &&
116
- !error?.message &&
117
- !data?.addProductsToCart?.user_errors?.length
118
- }
119
- variant='pill'
120
- severity='success'
121
- autoHide
122
- action={
123
- <Button
124
- href='/cart'
125
- id='view-shopping-cart-button'
126
- size='medium'
127
- variant='pill'
128
- color='secondary'
129
- endIcon={<IconSvg src={iconChevronRight} />}
130
- >
131
- <Trans>View shopping cart</Trans>
132
- </Button>
133
- }
134
- >
135
- <Trans>
136
- <strong>{name}</strong> has been added to your shopping cart!
137
- </Trans>
138
- </MessageSnackbar>
139
- </Box>
140
- )
141
- }
142
- ProductAddToCart.selectors = selectors
@@ -1,10 +0,0 @@
1
- import { Image } from '@graphcommerce/image'
2
- import type { ProductImageFragment } from './ProductImage.gql'
3
-
4
- export function ProductImage(props: ProductImageFragment) {
5
- const { url, label } = props
6
-
7
- if (!url) return null
8
-
9
- return <Image src={url} width={328} height={328} alt={label ?? ''} dontReportWronglySizedImages />
10
- }
@@ -1,10 +0,0 @@
1
- import type { ProductVideoFragment } from './ProductVideo.gql'
2
-
3
- export function ProductVideo(props: ProductVideoFragment) {
4
- const { video_content } = props
5
-
6
- if (!video_content?.video_url) return null
7
-
8
- // eslint-disable-next-line jsx-a11y/media-has-caption
9
- return <video src={video_content.video_url} />
10
- }