@wix/headless-stores 0.0.95 → 0.0.97

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.
@@ -6,9 +6,9 @@ import { AsChildSlot } from '@wix/headless-utils/react';
6
6
  import { MediaGallery } from '@wix/headless-media/react';
7
7
  import { Quantity as QuantityComponent } from '@wix/headless-components/react';
8
8
  import * as CoreProduct from './core/Product.js';
9
- import * as ProductVariantSelector from './core/ProductVariantSelector.js';
10
- import * as ProductModifiers from './core/ProductModifiers.js';
11
- import * as SelectedVariant from './core/SelectedVariant.js';
9
+ import * as CoreProductVariantSelector from './core/ProductVariantSelector.js';
10
+ import * as CoreProductModifiers from './core/ProductModifiers.js';
11
+ import * as CoreSelectedVariant from './core/SelectedVariant.js';
12
12
  import * as Option from './Option.js';
13
13
  import { AsContent } from './types.js';
14
14
  import { DataComponentTags } from '../data-component-tags.js';
@@ -89,9 +89,9 @@ var TestIds;
89
89
  */
90
90
  export const Root = (props) => {
91
91
  const { children, product, ...attrs } = props;
92
- return (_jsx(AsChildSlot, { "data-testid": TestIds.productRoot, "data-component-tag": DataComponentTags.productRoot, children: _jsx(CoreProduct.Root, { productServiceConfig: { product: props.product }, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: {
93
- media: props.product.media?.itemsInfo?.items ?? [],
94
- }, children: _jsx(ProductVariantSelector.Root, { children: _jsx(ProductModifiers.Root, { children: _jsx(SelectedVariant.Root, { children: _jsx(AsChildSlot, { ...attrs, children: children }) }) }) }) }) }) }));
92
+ return (_jsx(CoreProduct.Root, { productServiceConfig: { product: props.product }, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: {
93
+ media: props.product.media?.itemsInfo?.items ?? [],
94
+ }, children: _jsx(CoreProductVariantSelector.Root, { children: _jsx(CoreProductModifiers.Root, { children: _jsx(CoreSelectedVariant.Root, { children: _jsx(AsChildSlot, { "data-testid": TestIds.productRoot, "data-component-tag": DataComponentTags.productRoot, ...attrs, children: children }) }) }) }) }) }));
95
95
  };
96
96
  Root.displayName = 'Product.Root';
97
97
  /**
@@ -202,7 +202,7 @@ export const Description = React.forwardRef((props, ref) => {
202
202
  */
203
203
  export const Price = React.forwardRef((props, ref) => {
204
204
  const { asChild, children, className, ...otherProps } = props;
205
- return (_jsx(SelectedVariant.Price, { children: ({ price, compareAtPrice }) => {
205
+ return (_jsx(CoreSelectedVariant.Price, { children: ({ price, compareAtPrice }) => {
206
206
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productPrice, "data-discounted": compareAtPrice !== null, customElement: children, customElementProps: {
207
207
  price,
208
208
  formattedPrice: price,
@@ -240,7 +240,7 @@ export const Price = React.forwardRef((props, ref) => {
240
240
  export const CompareAtPrice = React.forwardRef((props, ref) => {
241
241
  const { asChild, children, className, ...otherProps } = props;
242
242
  const testId = TestIds.productCompareAtPrice;
243
- return (_jsx(SelectedVariant.Price, { children: ({ compareAtPrice }) => {
243
+ return (_jsx(CoreSelectedVariant.Price, { children: ({ compareAtPrice }) => {
244
244
  // Don't render anything if there's no compare-at price
245
245
  if (!compareAtPrice) {
246
246
  return null;
@@ -466,15 +466,15 @@ export const Stock = React.forwardRef((props, ref) => {
466
466
  * ```
467
467
  */
468
468
  export const Variants = React.forwardRef((props, ref) => {
469
- const { asChild, children, className } = props;
470
- return (_jsx(ProductVariantSelector.Options, { children: ({ hasOptions, options }) => {
469
+ const { asChild, children, className, ...attributes } = props;
470
+ return (_jsx(CoreProductVariantSelector.Options, { children: ({ hasOptions, options }) => {
471
471
  if (!hasOptions)
472
472
  return null;
473
473
  const contextValue = {
474
474
  hasOptions,
475
475
  options,
476
476
  };
477
- return (_jsx(VariantsContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariants, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
477
+ return (_jsx(VariantsContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariants, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
478
478
  } }));
479
479
  });
480
480
  /**
@@ -527,7 +527,7 @@ export const VariantOptionRepeater = React.forwardRef((props, _ref) => {
527
527
  if (!hasOptions)
528
528
  return null;
529
529
  return (_jsx(_Fragment, { children: options.map((option) => {
530
- return (_jsx(ProductVariantSelector.Option, { option: option, children: (optionData) => (_jsx(Option.Root, { option: {
530
+ return (_jsx(CoreProductVariantSelector.Option, { option: option, children: (optionData) => (_jsx(Option.Root, { option: {
531
531
  ...optionData,
532
532
  mandatory: false,
533
533
  }, children: children })) }, option._id));
@@ -577,15 +577,15 @@ export const VariantOptionRepeater = React.forwardRef((props, _ref) => {
577
577
  * ```
578
578
  */
579
579
  export const Modifiers = React.forwardRef((props, ref) => {
580
- const { asChild, children, className } = props;
581
- return (_jsx(ProductModifiers.Modifiers, { children: ({ hasModifiers, modifiers }) => {
580
+ const { asChild, children, className, ...attributes } = props;
581
+ return (_jsx(CoreProductModifiers.Modifiers, { children: ({ hasModifiers, modifiers }) => {
582
582
  if (!hasModifiers)
583
583
  return null;
584
584
  const contextValue = {
585
585
  hasModifiers,
586
586
  modifiers,
587
587
  };
588
- return (_jsx(ModifiersContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productModifiers, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
588
+ return (_jsx(ModifiersContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productModifiers, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
589
589
  } }));
590
590
  });
591
591
  /**
@@ -640,7 +640,7 @@ export const ModifierOptionRepeater = React.forwardRef((props, _ref) => {
640
640
  if (!hasModifiers)
641
641
  return null;
642
642
  return (_jsx(_Fragment, { children: modifiers.map((modifier) => {
643
- return (_jsx(ProductModifiers.Modifier, { modifier: modifier, children: (modifierData) => (_jsx(Option.Root, { option: {
643
+ return (_jsx(CoreProductModifiers.Modifier, { modifier: modifier, children: (modifierData) => (_jsx(Option.Root, { option: {
644
644
  ...modifierData,
645
645
  }, allowedTypes: allowedTypes, children: children })) }, modifier._id));
646
646
  }) }));
@@ -755,7 +755,7 @@ export { ProductMediaGallery as MediaGallery };
755
755
  */
756
756
  export const ProductQuantity = React.forwardRef((props, ref) => {
757
757
  const { asChild, children, className } = props;
758
- return (_jsx(ProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availableQuantity, selectedQuantity, setSelectedQuantity, }) => {
758
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availableQuantity, selectedQuantity, setSelectedQuantity, }) => {
759
759
  const renderProps = {
760
760
  selectedQuantity,
761
761
  availableQuantity,
@@ -782,7 +782,7 @@ export const ProductQuantity = React.forwardRef((props, ref) => {
782
782
  */
783
783
  export const ProductQuantityDecrement = React.forwardRef((props, ref) => {
784
784
  const { asChild, children, className } = props;
785
- return (_jsx(ProductVariantSelector.Stock, { children: ({ selectedQuantity, inStock, isPreOrderEnabled }) => {
785
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ selectedQuantity, inStock, isPreOrderEnabled }) => {
786
786
  const disabled = selectedQuantity <= 1 || (!inStock && !isPreOrderEnabled);
787
787
  if (asChild && children) {
788
788
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productQuantityDecrement, customElement: children, customElementProps: { disabled } }));
@@ -802,7 +802,7 @@ export const ProductQuantityDecrement = React.forwardRef((props, ref) => {
802
802
  */
803
803
  export const ProductQuantityInput = React.forwardRef((props, ref) => {
804
804
  const { asChild, children, className, disabled = true } = props;
805
- return (_jsx(ProductVariantSelector.Stock, { children: () => {
805
+ return (_jsx(CoreProductVariantSelector.Stock, { children: () => {
806
806
  if (asChild && children) {
807
807
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, disabled: disabled, "data-testid": TestIds.productQuantityInput, customElement: children, customElementProps: {} }));
808
808
  }
@@ -822,7 +822,7 @@ export const ProductQuantityInput = React.forwardRef((props, ref) => {
822
822
  */
823
823
  export const ProductQuantityIncrement = React.forwardRef((props, ref) => {
824
824
  const { asChild, children, className } = props;
825
- return (_jsx(ProductVariantSelector.Stock, { children: ({ selectedQuantity, availableQuantity, inStock, isPreOrderEnabled, }) => {
825
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ selectedQuantity, availableQuantity, inStock, isPreOrderEnabled, }) => {
826
826
  const disabled = (!!availableQuantity && selectedQuantity >= availableQuantity) ||
827
827
  (!inStock && !isPreOrderEnabled);
828
828
  if (asChild && children) {
@@ -859,13 +859,13 @@ export const ProductQuantityIncrement = React.forwardRef((props, ref) => {
859
859
  */
860
860
  export const ProductQuantityRaw = React.forwardRef((props, ref) => {
861
861
  const { asChild, children, className } = props;
862
- return (_jsx(ProductVariantSelector.Stock, { children: (renderProps) => {
862
+ return (_jsx(CoreProductVariantSelector.Stock, { children: (renderProps) => {
863
863
  return (_jsx(AsChildSlot, { ref: ref, customElement: children, asChild: asChild, className: className, "data-testid": TestIds.productQuantityRaw, customElementProps: renderProps }));
864
864
  } }));
865
865
  });
866
866
  export const ProductVariantSelectorReset = React.forwardRef((props, ref) => {
867
867
  const { asChild, children, className } = props;
868
- return (_jsx(ProductVariantSelector.Reset, { children: (renderProps) => {
868
+ return (_jsx(CoreProductVariantSelector.Reset, { children: (renderProps) => {
869
869
  if (!renderProps.hasSelections) {
870
870
  return null;
871
871
  }
@@ -879,7 +879,7 @@ export const ProductVariantSelectorReset = React.forwardRef((props, ref) => {
879
879
  */
880
880
  export const ProductActionAddToCart = React.forwardRef((props, ref) => {
881
881
  const { asChild, children, className, label, loadingState } = props;
882
- return (_jsx(SelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, addToCart, isPreOrderEnabled, }) => {
882
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, addToCart, isPreOrderEnabled, }) => {
883
883
  if (isPreOrderEnabled) {
884
884
  return null;
885
885
  }
@@ -901,7 +901,7 @@ export const ProductActionAddToCart = React.forwardRef((props, ref) => {
901
901
  */
902
902
  export const ProductActionBuyNow = React.forwardRef((props, ref) => {
903
903
  const { asChild, children, className, label, loadingState } = props;
904
- return (_jsx(SelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, buyNow, inStock, isPreOrderEnabled, }) => {
904
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, buyNow, inStock, isPreOrderEnabled, }) => {
905
905
  if (!inStock || isPreOrderEnabled) {
906
906
  return null;
907
907
  }
@@ -923,7 +923,7 @@ export const ProductActionBuyNow = React.forwardRef((props, ref) => {
923
923
  */
924
924
  export const ProductActionPreOrder = React.forwardRef((props, ref) => {
925
925
  const { asChild, children, className, label, loadingState } = props;
926
- return (_jsx(SelectedVariant.Actions, { children: ({ lineItems, isLoading, addToCart, isPreOrderEnabled }) => {
926
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, isLoading, addToCart, isPreOrderEnabled }) => {
927
927
  if (!isPreOrderEnabled) {
928
928
  return null;
929
929
  }
@@ -1038,7 +1038,7 @@ function getStockStatusMessage(inStock, isPreOrderEnabled, availabilityStatus, l
1038
1038
  */
1039
1039
  export const ProductVariantStock = React.forwardRef((props, ref) => {
1040
1040
  const { asChild, children, className, labels } = props;
1041
- return (_jsx(ProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availabilityStatus, currentVariantId, }) => {
1041
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availabilityStatus, currentVariantId, }) => {
1042
1042
  // Only render if we have a current variant selected
1043
1043
  if (!currentVariantId && !availabilityStatus) {
1044
1044
  return null;
@@ -1085,7 +1085,7 @@ export const ProductVariantStock = React.forwardRef((props, ref) => {
1085
1085
  */
1086
1086
  export const ProductVariantSKU = React.forwardRef((props, ref) => {
1087
1087
  const { asChild, children, className } = props;
1088
- return (_jsx(SelectedVariant.Details, { children: ({ sku }) => {
1088
+ return (_jsx(CoreSelectedVariant.Details, { children: ({ sku }) => {
1089
1089
  // Don't render anything if there's no SKU
1090
1090
  if (!sku) {
1091
1091
  return null;
@@ -1119,7 +1119,7 @@ export const ProductVariantSKU = React.forwardRef((props, ref) => {
1119
1119
  */
1120
1120
  export const ProductVariantWeight = React.forwardRef((props, ref) => {
1121
1121
  const { asChild, children, className } = props;
1122
- return (_jsx(SelectedVariant.Details, { children: ({ weight }) => {
1122
+ return (_jsx(CoreSelectedVariant.Details, { children: ({ weight }) => {
1123
1123
  // Don't render anything if there's no weight
1124
1124
  if (!weight) {
1125
1125
  return null;
@@ -1,5 +1,5 @@
1
1
  import type { V3Product } from '@wix/auto_sdk_stores_products-v-3';
2
- import { Sort as SortPrimitive, GenericListTotalsRenderProps, GenericListLoadMoreRenderProps } from '@wix/headless-components/react';
2
+ import { Sort as SortPrimitive, GenericListTotalsRenderProps, GenericListLoadMoreRenderProps, ListVariant, GenericListRepeaterRenderProps } from '@wix/headless-components/react';
3
3
  import React from 'react';
4
4
  import type { ProductsListServiceConfig } from '../services/products-list-service.js';
5
5
  import { productsV3 } from '@wix/stores';
@@ -12,6 +12,7 @@ export interface ProductListRootProps {
12
12
  products?: V3Product[];
13
13
  productsListConfig?: ProductsListServiceConfig;
14
14
  className?: string;
15
+ variant?: ListVariant;
15
16
  }
16
17
  /**
17
18
  * Root component that provides the ProductList service context for rendering product lists.
@@ -91,26 +92,46 @@ export interface ProductsProps {
91
92
  * ```
92
93
  */
93
94
  export declare const Products: React.ForwardRefExoticComponent<ProductsProps & React.RefAttributes<HTMLElement>>;
95
+ /**
96
+ * Render props for ProductRepeater asChild pattern
97
+ */
98
+ export type ProductRepeaterRenderProps = GenericListRepeaterRenderProps<V3Product>;
94
99
  /**
95
100
  * Props for ProductList ProductRepeater component
96
101
  */
97
102
  export interface ProductRepeaterProps {
98
- children: React.ReactNode;
103
+ children: React.ReactNode | ((props: ProductRepeaterRenderProps, ref: React.Ref<HTMLElement>) => React.ReactNode);
104
+ /** Whether to render as child component (asChild pattern) */
105
+ asChild?: boolean;
99
106
  }
100
107
  /**
101
108
  * Repeater component that renders Product.Root for each product.
102
- * Follows Repeater Level pattern.
103
- * Note: Repeater components do NOT support asChild as per architecture rules.
109
+ * Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
110
+ * Supports asChild pattern for advanced layout components like GalleryWrapper.
104
111
  *
105
112
  * @component
106
113
  * @example
107
114
  * ```tsx
115
+ * // Standard usage
108
116
  * <ProductList.ProductRepeater>
109
117
  * <Product.Name />
110
118
  * <Product.Price />
111
- * <Product.MediaGallery>
112
- * <MediaGallery.Viewport />
113
- * </Product.MediaGallery>
119
+ * </ProductList.ProductRepeater>
120
+ *
121
+ * // AsChild usage with GalleryWrapper
122
+ * <ProductList.ProductRepeater asChild>
123
+ * {({ items, variant, itemWrapper }) => (
124
+ * <GalleryWrapper
125
+ * items={items}
126
+ * variant={variant}
127
+ * itemRenderer={(item, index) =>
128
+ * itemWrapper({ item, index, children: <>
129
+ * <Product.Name />
130
+ * <Product.Price />
131
+ * </> })
132
+ * }
133
+ * />
134
+ * )}
114
135
  * </ProductList.ProductRepeater>
115
136
  * ```
116
137
  */
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Sort as SortPrimitive, GenericList, } from '@wix/headless-components/react';
3
3
  import { useService } from '@wix/services-manager-react';
4
4
  import React from 'react';
@@ -45,7 +45,7 @@ var TestIds;
45
45
  * ```
46
46
  */
47
47
  export const Root = React.forwardRef((props, ref) => {
48
- const { children, products, productsListConfig, className } = props;
48
+ const { children, products, productsListConfig, className, variant } = props;
49
49
  const serviceConfig = productsListConfig || {
50
50
  products: products || [],
51
51
  searchOptions: {
@@ -59,20 +59,20 @@ export const Root = React.forwardRef((props, ref) => {
59
59
  }, // Empty aggregation data
60
60
  customizations: [],
61
61
  };
62
- return (_jsx(CoreProductList.Root, { productsListConfig: serviceConfig, children: _jsx(RootContent, { children: children, className: className, ref: ref }) }));
62
+ return (_jsx(CoreProductList.Root, { productsListConfig: serviceConfig, children: _jsx(RootContent, { children: children, className: className, ref: ref, variant: variant }) }));
63
63
  });
64
64
  Root.displayName = 'ProductList.Root';
65
65
  /**
66
66
  * Internal component to handle the Root content with service access
67
67
  */
68
68
  const RootContent = React.forwardRef((props, ref) => {
69
- const { children, className } = props;
69
+ const { children, className, variant } = props;
70
70
  const productsListService = useService(ProductsListServiceDefinition);
71
71
  const items = productsListService.products.get().map((product) => ({
72
72
  ...product,
73
73
  id: product._id,
74
74
  }));
75
- return (_jsx(GenericList.Root, { items: items, loadMore: () => productsListService.loadMore(10), hasMore: productsListService.hasMoreProducts.get(), isLoading: productsListService.isLoading.get(), className: className, ref: ref, "data-component-tag": DataComponentTags.productListRoot, "data-testid": TestIds.productListRoot, children: children }));
75
+ return (_jsx(GenericList.Root, { items: items, loadMore: () => productsListService.loadMore(10), hasMore: productsListService.hasMoreProducts.get(), isLoading: productsListService.isLoading.get(), className: className, ref: ref, "data-component-tag": DataComponentTags.productListRoot, "data-testid": TestIds.productListRoot, variant: variant, children: children }));
76
76
  });
77
77
  /**
78
78
  * Raw component that provides direct access to product list data.
@@ -124,29 +124,38 @@ export const Products = React.forwardRef((props, ref) => {
124
124
  });
125
125
  /**
126
126
  * Repeater component that renders Product.Root for each product.
127
- * Follows Repeater Level pattern.
128
- * Note: Repeater components do NOT support asChild as per architecture rules.
127
+ * Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
128
+ * Supports asChild pattern for advanced layout components like GalleryWrapper.
129
129
  *
130
130
  * @component
131
131
  * @example
132
132
  * ```tsx
133
+ * // Standard usage
133
134
  * <ProductList.ProductRepeater>
134
135
  * <Product.Name />
135
136
  * <Product.Price />
136
- * <Product.MediaGallery>
137
- * <MediaGallery.Viewport />
138
- * </Product.MediaGallery>
137
+ * </ProductList.ProductRepeater>
138
+ *
139
+ * // AsChild usage with GalleryWrapper
140
+ * <ProductList.ProductRepeater asChild>
141
+ * {({ items, variant, itemWrapper }) => (
142
+ * <GalleryWrapper
143
+ * items={items}
144
+ * variant={variant}
145
+ * itemRenderer={(item, index) =>
146
+ * itemWrapper({ item, index, children: <>
147
+ * <Product.Name />
148
+ * <Product.Price />
149
+ * </> })
150
+ * }
151
+ * />
152
+ * )}
139
153
  * </ProductList.ProductRepeater>
140
154
  * ```
141
155
  */
142
- export const ProductRepeater = React.forwardRef((props, _ref) => {
143
- const { children } = props;
144
- const productsListService = useService(ProductsListServiceDefinition);
145
- const products = productsListService.products.get();
146
- const hasProducts = products.length > 0;
147
- if (!hasProducts)
148
- return null;
149
- return (_jsx(_Fragment, { children: products.map((product) => (_jsx(Product.Root, { product: product, "data-testid": TestIds.productListItem, "data-product-id": product._id, "data-product-available": true, children: children }, product._id))) }));
156
+ export const ProductRepeater = React.forwardRef((props, ref) => {
157
+ const { children, asChild } = props;
158
+ return (_jsx(GenericList.Repeater, { ref: ref, asChild: asChild, itemWrapper: ({ item: product, children }) => (_jsx(Product.Root, { product: product, "data-testid": TestIds.productListItem, "data-product-id": product._id, "data-product-available": true, "data-item-id": product._id, children: children }, product._id)), children: children }));
150
159
  });
151
160
  /**
152
161
  * Displays a button to load more products. Not rendered if infiniteScroll is false or no products are left to load.
@@ -6,9 +6,9 @@ import { AsChildSlot } from '@wix/headless-utils/react';
6
6
  import { MediaGallery } from '@wix/headless-media/react';
7
7
  import { Quantity as QuantityComponent } from '@wix/headless-components/react';
8
8
  import * as CoreProduct from './core/Product.js';
9
- import * as ProductVariantSelector from './core/ProductVariantSelector.js';
10
- import * as ProductModifiers from './core/ProductModifiers.js';
11
- import * as SelectedVariant from './core/SelectedVariant.js';
9
+ import * as CoreProductVariantSelector from './core/ProductVariantSelector.js';
10
+ import * as CoreProductModifiers from './core/ProductModifiers.js';
11
+ import * as CoreSelectedVariant from './core/SelectedVariant.js';
12
12
  import * as Option from './Option.js';
13
13
  import { AsContent } from './types.js';
14
14
  import { DataComponentTags } from '../data-component-tags.js';
@@ -89,9 +89,9 @@ var TestIds;
89
89
  */
90
90
  export const Root = (props) => {
91
91
  const { children, product, ...attrs } = props;
92
- return (_jsx(AsChildSlot, { "data-testid": TestIds.productRoot, "data-component-tag": DataComponentTags.productRoot, children: _jsx(CoreProduct.Root, { productServiceConfig: { product: props.product }, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: {
93
- media: props.product.media?.itemsInfo?.items ?? [],
94
- }, children: _jsx(ProductVariantSelector.Root, { children: _jsx(ProductModifiers.Root, { children: _jsx(SelectedVariant.Root, { children: _jsx(AsChildSlot, { ...attrs, children: children }) }) }) }) }) }) }));
92
+ return (_jsx(CoreProduct.Root, { productServiceConfig: { product: props.product }, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: {
93
+ media: props.product.media?.itemsInfo?.items ?? [],
94
+ }, children: _jsx(CoreProductVariantSelector.Root, { children: _jsx(CoreProductModifiers.Root, { children: _jsx(CoreSelectedVariant.Root, { children: _jsx(AsChildSlot, { "data-testid": TestIds.productRoot, "data-component-tag": DataComponentTags.productRoot, ...attrs, children: children }) }) }) }) }) }));
95
95
  };
96
96
  Root.displayName = 'Product.Root';
97
97
  /**
@@ -202,7 +202,7 @@ export const Description = React.forwardRef((props, ref) => {
202
202
  */
203
203
  export const Price = React.forwardRef((props, ref) => {
204
204
  const { asChild, children, className, ...otherProps } = props;
205
- return (_jsx(SelectedVariant.Price, { children: ({ price, compareAtPrice }) => {
205
+ return (_jsx(CoreSelectedVariant.Price, { children: ({ price, compareAtPrice }) => {
206
206
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productPrice, "data-discounted": compareAtPrice !== null, customElement: children, customElementProps: {
207
207
  price,
208
208
  formattedPrice: price,
@@ -240,7 +240,7 @@ export const Price = React.forwardRef((props, ref) => {
240
240
  export const CompareAtPrice = React.forwardRef((props, ref) => {
241
241
  const { asChild, children, className, ...otherProps } = props;
242
242
  const testId = TestIds.productCompareAtPrice;
243
- return (_jsx(SelectedVariant.Price, { children: ({ compareAtPrice }) => {
243
+ return (_jsx(CoreSelectedVariant.Price, { children: ({ compareAtPrice }) => {
244
244
  // Don't render anything if there's no compare-at price
245
245
  if (!compareAtPrice) {
246
246
  return null;
@@ -466,15 +466,15 @@ export const Stock = React.forwardRef((props, ref) => {
466
466
  * ```
467
467
  */
468
468
  export const Variants = React.forwardRef((props, ref) => {
469
- const { asChild, children, className } = props;
470
- return (_jsx(ProductVariantSelector.Options, { children: ({ hasOptions, options }) => {
469
+ const { asChild, children, className, ...attributes } = props;
470
+ return (_jsx(CoreProductVariantSelector.Options, { children: ({ hasOptions, options }) => {
471
471
  if (!hasOptions)
472
472
  return null;
473
473
  const contextValue = {
474
474
  hasOptions,
475
475
  options,
476
476
  };
477
- return (_jsx(VariantsContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariants, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
477
+ return (_jsx(VariantsContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariants, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
478
478
  } }));
479
479
  });
480
480
  /**
@@ -527,7 +527,7 @@ export const VariantOptionRepeater = React.forwardRef((props, _ref) => {
527
527
  if (!hasOptions)
528
528
  return null;
529
529
  return (_jsx(_Fragment, { children: options.map((option) => {
530
- return (_jsx(ProductVariantSelector.Option, { option: option, children: (optionData) => (_jsx(Option.Root, { option: {
530
+ return (_jsx(CoreProductVariantSelector.Option, { option: option, children: (optionData) => (_jsx(Option.Root, { option: {
531
531
  ...optionData,
532
532
  mandatory: false,
533
533
  }, children: children })) }, option._id));
@@ -577,15 +577,15 @@ export const VariantOptionRepeater = React.forwardRef((props, _ref) => {
577
577
  * ```
578
578
  */
579
579
  export const Modifiers = React.forwardRef((props, ref) => {
580
- const { asChild, children, className } = props;
581
- return (_jsx(ProductModifiers.Modifiers, { children: ({ hasModifiers, modifiers }) => {
580
+ const { asChild, children, className, ...attributes } = props;
581
+ return (_jsx(CoreProductModifiers.Modifiers, { children: ({ hasModifiers, modifiers }) => {
582
582
  if (!hasModifiers)
583
583
  return null;
584
584
  const contextValue = {
585
585
  hasModifiers,
586
586
  modifiers,
587
587
  };
588
- return (_jsx(ModifiersContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productModifiers, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
588
+ return (_jsx(ModifiersContext.Provider, { value: contextValue, children: _jsx(AsChildSlot, { ...attributes, ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productModifiers, customElement: children, children: _jsx("div", { children: React.isValidElement(children) ? children : null }) }) }));
589
589
  } }));
590
590
  });
591
591
  /**
@@ -640,7 +640,7 @@ export const ModifierOptionRepeater = React.forwardRef((props, _ref) => {
640
640
  if (!hasModifiers)
641
641
  return null;
642
642
  return (_jsx(_Fragment, { children: modifiers.map((modifier) => {
643
- return (_jsx(ProductModifiers.Modifier, { modifier: modifier, children: (modifierData) => (_jsx(Option.Root, { option: {
643
+ return (_jsx(CoreProductModifiers.Modifier, { modifier: modifier, children: (modifierData) => (_jsx(Option.Root, { option: {
644
644
  ...modifierData,
645
645
  }, allowedTypes: allowedTypes, children: children })) }, modifier._id));
646
646
  }) }));
@@ -755,7 +755,7 @@ export { ProductMediaGallery as MediaGallery };
755
755
  */
756
756
  export const ProductQuantity = React.forwardRef((props, ref) => {
757
757
  const { asChild, children, className } = props;
758
- return (_jsx(ProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availableQuantity, selectedQuantity, setSelectedQuantity, }) => {
758
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availableQuantity, selectedQuantity, setSelectedQuantity, }) => {
759
759
  const renderProps = {
760
760
  selectedQuantity,
761
761
  availableQuantity,
@@ -782,7 +782,7 @@ export const ProductQuantity = React.forwardRef((props, ref) => {
782
782
  */
783
783
  export const ProductQuantityDecrement = React.forwardRef((props, ref) => {
784
784
  const { asChild, children, className } = props;
785
- return (_jsx(ProductVariantSelector.Stock, { children: ({ selectedQuantity, inStock, isPreOrderEnabled }) => {
785
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ selectedQuantity, inStock, isPreOrderEnabled }) => {
786
786
  const disabled = selectedQuantity <= 1 || (!inStock && !isPreOrderEnabled);
787
787
  if (asChild && children) {
788
788
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productQuantityDecrement, customElement: children, customElementProps: { disabled } }));
@@ -802,7 +802,7 @@ export const ProductQuantityDecrement = React.forwardRef((props, ref) => {
802
802
  */
803
803
  export const ProductQuantityInput = React.forwardRef((props, ref) => {
804
804
  const { asChild, children, className, disabled = true } = props;
805
- return (_jsx(ProductVariantSelector.Stock, { children: () => {
805
+ return (_jsx(CoreProductVariantSelector.Stock, { children: () => {
806
806
  if (asChild && children) {
807
807
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, disabled: disabled, "data-testid": TestIds.productQuantityInput, customElement: children, customElementProps: {} }));
808
808
  }
@@ -822,7 +822,7 @@ export const ProductQuantityInput = React.forwardRef((props, ref) => {
822
822
  */
823
823
  export const ProductQuantityIncrement = React.forwardRef((props, ref) => {
824
824
  const { asChild, children, className } = props;
825
- return (_jsx(ProductVariantSelector.Stock, { children: ({ selectedQuantity, availableQuantity, inStock, isPreOrderEnabled, }) => {
825
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ selectedQuantity, availableQuantity, inStock, isPreOrderEnabled, }) => {
826
826
  const disabled = (!!availableQuantity && selectedQuantity >= availableQuantity) ||
827
827
  (!inStock && !isPreOrderEnabled);
828
828
  if (asChild && children) {
@@ -859,13 +859,13 @@ export const ProductQuantityIncrement = React.forwardRef((props, ref) => {
859
859
  */
860
860
  export const ProductQuantityRaw = React.forwardRef((props, ref) => {
861
861
  const { asChild, children, className } = props;
862
- return (_jsx(ProductVariantSelector.Stock, { children: (renderProps) => {
862
+ return (_jsx(CoreProductVariantSelector.Stock, { children: (renderProps) => {
863
863
  return (_jsx(AsChildSlot, { ref: ref, customElement: children, asChild: asChild, className: className, "data-testid": TestIds.productQuantityRaw, customElementProps: renderProps }));
864
864
  } }));
865
865
  });
866
866
  export const ProductVariantSelectorReset = React.forwardRef((props, ref) => {
867
867
  const { asChild, children, className } = props;
868
- return (_jsx(ProductVariantSelector.Reset, { children: (renderProps) => {
868
+ return (_jsx(CoreProductVariantSelector.Reset, { children: (renderProps) => {
869
869
  if (!renderProps.hasSelections) {
870
870
  return null;
871
871
  }
@@ -879,7 +879,7 @@ export const ProductVariantSelectorReset = React.forwardRef((props, ref) => {
879
879
  */
880
880
  export const ProductActionAddToCart = React.forwardRef((props, ref) => {
881
881
  const { asChild, children, className, label, loadingState } = props;
882
- return (_jsx(SelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, addToCart, isPreOrderEnabled, }) => {
882
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, addToCart, isPreOrderEnabled, }) => {
883
883
  if (isPreOrderEnabled) {
884
884
  return null;
885
885
  }
@@ -901,7 +901,7 @@ export const ProductActionAddToCart = React.forwardRef((props, ref) => {
901
901
  */
902
902
  export const ProductActionBuyNow = React.forwardRef((props, ref) => {
903
903
  const { asChild, children, className, label, loadingState } = props;
904
- return (_jsx(SelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, buyNow, inStock, isPreOrderEnabled, }) => {
904
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, buyNow, inStock, isPreOrderEnabled, }) => {
905
905
  if (!inStock || isPreOrderEnabled) {
906
906
  return null;
907
907
  }
@@ -923,7 +923,7 @@ export const ProductActionBuyNow = React.forwardRef((props, ref) => {
923
923
  */
924
924
  export const ProductActionPreOrder = React.forwardRef((props, ref) => {
925
925
  const { asChild, children, className, label, loadingState } = props;
926
- return (_jsx(SelectedVariant.Actions, { children: ({ lineItems, isLoading, addToCart, isPreOrderEnabled }) => {
926
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, isLoading, addToCart, isPreOrderEnabled }) => {
927
927
  if (!isPreOrderEnabled) {
928
928
  return null;
929
929
  }
@@ -1038,7 +1038,7 @@ function getStockStatusMessage(inStock, isPreOrderEnabled, availabilityStatus, l
1038
1038
  */
1039
1039
  export const ProductVariantStock = React.forwardRef((props, ref) => {
1040
1040
  const { asChild, children, className, labels } = props;
1041
- return (_jsx(ProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availabilityStatus, currentVariantId, }) => {
1041
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availabilityStatus, currentVariantId, }) => {
1042
1042
  // Only render if we have a current variant selected
1043
1043
  if (!currentVariantId && !availabilityStatus) {
1044
1044
  return null;
@@ -1085,7 +1085,7 @@ export const ProductVariantStock = React.forwardRef((props, ref) => {
1085
1085
  */
1086
1086
  export const ProductVariantSKU = React.forwardRef((props, ref) => {
1087
1087
  const { asChild, children, className } = props;
1088
- return (_jsx(SelectedVariant.Details, { children: ({ sku }) => {
1088
+ return (_jsx(CoreSelectedVariant.Details, { children: ({ sku }) => {
1089
1089
  // Don't render anything if there's no SKU
1090
1090
  if (!sku) {
1091
1091
  return null;
@@ -1119,7 +1119,7 @@ export const ProductVariantSKU = React.forwardRef((props, ref) => {
1119
1119
  */
1120
1120
  export const ProductVariantWeight = React.forwardRef((props, ref) => {
1121
1121
  const { asChild, children, className } = props;
1122
- return (_jsx(SelectedVariant.Details, { children: ({ weight }) => {
1122
+ return (_jsx(CoreSelectedVariant.Details, { children: ({ weight }) => {
1123
1123
  // Don't render anything if there's no weight
1124
1124
  if (!weight) {
1125
1125
  return null;
@@ -1,5 +1,5 @@
1
1
  import type { V3Product } from '@wix/auto_sdk_stores_products-v-3';
2
- import { Sort as SortPrimitive, GenericListTotalsRenderProps, GenericListLoadMoreRenderProps } from '@wix/headless-components/react';
2
+ import { Sort as SortPrimitive, GenericListTotalsRenderProps, GenericListLoadMoreRenderProps, ListVariant, GenericListRepeaterRenderProps } from '@wix/headless-components/react';
3
3
  import React from 'react';
4
4
  import type { ProductsListServiceConfig } from '../services/products-list-service.js';
5
5
  import { productsV3 } from '@wix/stores';
@@ -12,6 +12,7 @@ export interface ProductListRootProps {
12
12
  products?: V3Product[];
13
13
  productsListConfig?: ProductsListServiceConfig;
14
14
  className?: string;
15
+ variant?: ListVariant;
15
16
  }
16
17
  /**
17
18
  * Root component that provides the ProductList service context for rendering product lists.
@@ -91,26 +92,46 @@ export interface ProductsProps {
91
92
  * ```
92
93
  */
93
94
  export declare const Products: React.ForwardRefExoticComponent<ProductsProps & React.RefAttributes<HTMLElement>>;
95
+ /**
96
+ * Render props for ProductRepeater asChild pattern
97
+ */
98
+ export type ProductRepeaterRenderProps = GenericListRepeaterRenderProps<V3Product>;
94
99
  /**
95
100
  * Props for ProductList ProductRepeater component
96
101
  */
97
102
  export interface ProductRepeaterProps {
98
- children: React.ReactNode;
103
+ children: React.ReactNode | ((props: ProductRepeaterRenderProps, ref: React.Ref<HTMLElement>) => React.ReactNode);
104
+ /** Whether to render as child component (asChild pattern) */
105
+ asChild?: boolean;
99
106
  }
100
107
  /**
101
108
  * Repeater component that renders Product.Root for each product.
102
- * Follows Repeater Level pattern.
103
- * Note: Repeater components do NOT support asChild as per architecture rules.
109
+ * Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
110
+ * Supports asChild pattern for advanced layout components like GalleryWrapper.
104
111
  *
105
112
  * @component
106
113
  * @example
107
114
  * ```tsx
115
+ * // Standard usage
108
116
  * <ProductList.ProductRepeater>
109
117
  * <Product.Name />
110
118
  * <Product.Price />
111
- * <Product.MediaGallery>
112
- * <MediaGallery.Viewport />
113
- * </Product.MediaGallery>
119
+ * </ProductList.ProductRepeater>
120
+ *
121
+ * // AsChild usage with GalleryWrapper
122
+ * <ProductList.ProductRepeater asChild>
123
+ * {({ items, variant, itemWrapper }) => (
124
+ * <GalleryWrapper
125
+ * items={items}
126
+ * variant={variant}
127
+ * itemRenderer={(item, index) =>
128
+ * itemWrapper({ item, index, children: <>
129
+ * <Product.Name />
130
+ * <Product.Price />
131
+ * </> })
132
+ * }
133
+ * />
134
+ * )}
114
135
  * </ProductList.ProductRepeater>
115
136
  * ```
116
137
  */
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Sort as SortPrimitive, GenericList, } from '@wix/headless-components/react';
3
3
  import { useService } from '@wix/services-manager-react';
4
4
  import React from 'react';
@@ -45,7 +45,7 @@ var TestIds;
45
45
  * ```
46
46
  */
47
47
  export const Root = React.forwardRef((props, ref) => {
48
- const { children, products, productsListConfig, className } = props;
48
+ const { children, products, productsListConfig, className, variant } = props;
49
49
  const serviceConfig = productsListConfig || {
50
50
  products: products || [],
51
51
  searchOptions: {
@@ -59,20 +59,20 @@ export const Root = React.forwardRef((props, ref) => {
59
59
  }, // Empty aggregation data
60
60
  customizations: [],
61
61
  };
62
- return (_jsx(CoreProductList.Root, { productsListConfig: serviceConfig, children: _jsx(RootContent, { children: children, className: className, ref: ref }) }));
62
+ return (_jsx(CoreProductList.Root, { productsListConfig: serviceConfig, children: _jsx(RootContent, { children: children, className: className, ref: ref, variant: variant }) }));
63
63
  });
64
64
  Root.displayName = 'ProductList.Root';
65
65
  /**
66
66
  * Internal component to handle the Root content with service access
67
67
  */
68
68
  const RootContent = React.forwardRef((props, ref) => {
69
- const { children, className } = props;
69
+ const { children, className, variant } = props;
70
70
  const productsListService = useService(ProductsListServiceDefinition);
71
71
  const items = productsListService.products.get().map((product) => ({
72
72
  ...product,
73
73
  id: product._id,
74
74
  }));
75
- return (_jsx(GenericList.Root, { items: items, loadMore: () => productsListService.loadMore(10), hasMore: productsListService.hasMoreProducts.get(), isLoading: productsListService.isLoading.get(), className: className, ref: ref, "data-component-tag": DataComponentTags.productListRoot, "data-testid": TestIds.productListRoot, children: children }));
75
+ return (_jsx(GenericList.Root, { items: items, loadMore: () => productsListService.loadMore(10), hasMore: productsListService.hasMoreProducts.get(), isLoading: productsListService.isLoading.get(), className: className, ref: ref, "data-component-tag": DataComponentTags.productListRoot, "data-testid": TestIds.productListRoot, variant: variant, children: children }));
76
76
  });
77
77
  /**
78
78
  * Raw component that provides direct access to product list data.
@@ -124,29 +124,38 @@ export const Products = React.forwardRef((props, ref) => {
124
124
  });
125
125
  /**
126
126
  * Repeater component that renders Product.Root for each product.
127
- * Follows Repeater Level pattern.
128
- * Note: Repeater components do NOT support asChild as per architecture rules.
127
+ * Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
128
+ * Supports asChild pattern for advanced layout components like GalleryWrapper.
129
129
  *
130
130
  * @component
131
131
  * @example
132
132
  * ```tsx
133
+ * // Standard usage
133
134
  * <ProductList.ProductRepeater>
134
135
  * <Product.Name />
135
136
  * <Product.Price />
136
- * <Product.MediaGallery>
137
- * <MediaGallery.Viewport />
138
- * </Product.MediaGallery>
137
+ * </ProductList.ProductRepeater>
138
+ *
139
+ * // AsChild usage with GalleryWrapper
140
+ * <ProductList.ProductRepeater asChild>
141
+ * {({ items, variant, itemWrapper }) => (
142
+ * <GalleryWrapper
143
+ * items={items}
144
+ * variant={variant}
145
+ * itemRenderer={(item, index) =>
146
+ * itemWrapper({ item, index, children: <>
147
+ * <Product.Name />
148
+ * <Product.Price />
149
+ * </> })
150
+ * }
151
+ * />
152
+ * )}
139
153
  * </ProductList.ProductRepeater>
140
154
  * ```
141
155
  */
142
- export const ProductRepeater = React.forwardRef((props, _ref) => {
143
- const { children } = props;
144
- const productsListService = useService(ProductsListServiceDefinition);
145
- const products = productsListService.products.get();
146
- const hasProducts = products.length > 0;
147
- if (!hasProducts)
148
- return null;
149
- return (_jsx(_Fragment, { children: products.map((product) => (_jsx(Product.Root, { product: product, "data-testid": TestIds.productListItem, "data-product-id": product._id, "data-product-available": true, children: children }, product._id))) }));
156
+ export const ProductRepeater = React.forwardRef((props, ref) => {
157
+ const { children, asChild } = props;
158
+ return (_jsx(GenericList.Repeater, { ref: ref, asChild: asChild, itemWrapper: ({ item: product, children }) => (_jsx(Product.Root, { product: product, "data-testid": TestIds.productListItem, "data-product-id": product._id, "data-product-available": true, "data-item-id": product._id, children: children }, product._id)), children: children }));
150
159
  });
151
160
  /**
152
161
  * Displays a button to load more products. Not rendered if infiniteScroll is false or no products are left to load.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-stores",
3
- "version": "0.0.95",
3
+ "version": "0.0.97",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "prebuild": "cd ../media && yarn build && cd ../ecom && yarn build",
@@ -62,7 +62,7 @@
62
62
  "@wix/auto_sdk_stores_read-only-variants-v-3": "^1.0.23",
63
63
  "@wix/ecom": "^1.0.1278",
64
64
  "@wix/essentials": "^0.1.24",
65
- "@wix/headless-ecom": "0.0.31",
65
+ "@wix/headless-ecom": "0.0.32",
66
66
  "@wix/headless-media": "0.0.15",
67
67
  "@wix/headless-utils": "0.0.4",
68
68
  "@wix/redirects": "^1.0.83",
@@ -70,6 +70,6 @@
70
70
  "@wix/services-manager-react": "^0.1.26"
71
71
  },
72
72
  "peerDependencies": {
73
- "@wix/headless-components": "0.0.16"
73
+ "@wix/headless-components": "0.0.18"
74
74
  }
75
75
  }