@wix/headless-stores 0.0.0

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 (150) hide show
  1. package/astro/actions/package.json +4 -0
  2. package/cjs/dist/astro/actions/custom-checkout.d.ts +50 -0
  3. package/cjs/dist/astro/actions/custom-checkout.js +53 -0
  4. package/cjs/dist/astro/actions/index.d.ts +1 -0
  5. package/cjs/dist/astro/actions/index.js +1 -0
  6. package/cjs/dist/data-component-tags.d.ts +8 -0
  7. package/cjs/dist/data-component-tags.js +9 -0
  8. package/cjs/dist/enums/index.d.ts +2 -0
  9. package/cjs/dist/enums/index.js +2 -0
  10. package/cjs/dist/enums/social-platform-enums.d.ts +25 -0
  11. package/cjs/dist/enums/social-platform-enums.js +27 -0
  12. package/cjs/dist/enums/sort-enums.d.ts +17 -0
  13. package/cjs/dist/enums/sort-enums.js +18 -0
  14. package/cjs/dist/react/Category.d.ts +242 -0
  15. package/cjs/dist/react/Category.js +235 -0
  16. package/cjs/dist/react/CategoryList.d.ts +107 -0
  17. package/cjs/dist/react/CategoryList.js +91 -0
  18. package/cjs/dist/react/Choice.d.ts +211 -0
  19. package/cjs/dist/react/Choice.js +213 -0
  20. package/cjs/dist/react/Option.d.ts +242 -0
  21. package/cjs/dist/react/Option.js +346 -0
  22. package/cjs/dist/react/Product.d.ts +1065 -0
  23. package/cjs/dist/react/Product.js +1157 -0
  24. package/cjs/dist/react/ProductList.d.ts +400 -0
  25. package/cjs/dist/react/ProductList.js +368 -0
  26. package/cjs/dist/react/core/CategoryList.d.ts +194 -0
  27. package/cjs/dist/react/core/CategoryList.js +180 -0
  28. package/cjs/dist/react/core/Product.d.ts +225 -0
  29. package/cjs/dist/react/core/Product.js +190 -0
  30. package/cjs/dist/react/core/ProductList.d.ts +235 -0
  31. package/cjs/dist/react/core/ProductList.js +217 -0
  32. package/cjs/dist/react/core/ProductListFilters.d.ts +138 -0
  33. package/cjs/dist/react/core/ProductListFilters.js +242 -0
  34. package/cjs/dist/react/core/ProductListPagination.d.ts +49 -0
  35. package/cjs/dist/react/core/ProductListPagination.js +41 -0
  36. package/cjs/dist/react/core/ProductListSort.d.ts +19 -0
  37. package/cjs/dist/react/core/ProductListSort.js +52 -0
  38. package/cjs/dist/react/core/ProductModifiers.d.ts +416 -0
  39. package/cjs/dist/react/core/ProductModifiers.js +413 -0
  40. package/cjs/dist/react/core/ProductVariantSelector.d.ts +313 -0
  41. package/cjs/dist/react/core/ProductVariantSelector.js +291 -0
  42. package/cjs/dist/react/core/SelectedVariant.d.ts +230 -0
  43. package/cjs/dist/react/core/SelectedVariant.js +269 -0
  44. package/cjs/dist/react/index.d.ts +6 -0
  45. package/cjs/dist/react/index.js +6 -0
  46. package/cjs/dist/react/types.d.ts +8 -0
  47. package/cjs/dist/react/types.js +9 -0
  48. package/cjs/dist/server-actions/custom-checkout-action.d.ts +49 -0
  49. package/cjs/dist/server-actions/custom-checkout-action.js +64 -0
  50. package/cjs/dist/server-actions/index.d.ts +1 -0
  51. package/cjs/dist/server-actions/index.js +1 -0
  52. package/cjs/dist/services/buy-now-service.d.ts +346 -0
  53. package/cjs/dist/services/buy-now-service.js +197 -0
  54. package/cjs/dist/services/categories-list-service.d.ts +164 -0
  55. package/cjs/dist/services/categories-list-service.js +148 -0
  56. package/cjs/dist/services/index.d.ts +5 -0
  57. package/cjs/dist/services/index.js +5 -0
  58. package/cjs/dist/services/pay-now-service.d.ts +214 -0
  59. package/cjs/dist/services/pay-now-service.js +156 -0
  60. package/cjs/dist/services/product-modifiers-service.d.ts +34 -0
  61. package/cjs/dist/services/product-modifiers-service.js +107 -0
  62. package/cjs/dist/services/product-service.d.ts +177 -0
  63. package/cjs/dist/services/product-service.js +190 -0
  64. package/cjs/dist/services/products-list-search-service.d.ts +1 -0
  65. package/cjs/dist/services/products-list-search-service.js +1 -0
  66. package/cjs/dist/services/products-list-service.d.ts +429 -0
  67. package/cjs/dist/services/products-list-service.js +893 -0
  68. package/cjs/dist/services/selected-variant-service.d.ts +66 -0
  69. package/cjs/dist/services/selected-variant-service.js +527 -0
  70. package/cjs/dist/utils/index.d.ts +1 -0
  71. package/cjs/dist/utils/index.js +30 -0
  72. package/cjs/dist/utils/url-params.d.ts +73 -0
  73. package/cjs/dist/utils/url-params.js +114 -0
  74. package/cjs/package.json +3 -0
  75. package/dist/astro/actions/custom-checkout.d.ts +50 -0
  76. package/dist/astro/actions/custom-checkout.js +53 -0
  77. package/dist/astro/actions/index.d.ts +1 -0
  78. package/dist/astro/actions/index.js +1 -0
  79. package/dist/data-component-tags.d.ts +8 -0
  80. package/dist/data-component-tags.js +9 -0
  81. package/dist/enums/index.d.ts +2 -0
  82. package/dist/enums/index.js +2 -0
  83. package/dist/enums/social-platform-enums.d.ts +25 -0
  84. package/dist/enums/social-platform-enums.js +27 -0
  85. package/dist/enums/sort-enums.d.ts +17 -0
  86. package/dist/enums/sort-enums.js +18 -0
  87. package/dist/react/Category.d.ts +242 -0
  88. package/dist/react/Category.js +235 -0
  89. package/dist/react/CategoryList.d.ts +107 -0
  90. package/dist/react/CategoryList.js +91 -0
  91. package/dist/react/Choice.d.ts +211 -0
  92. package/dist/react/Choice.js +213 -0
  93. package/dist/react/Option.d.ts +242 -0
  94. package/dist/react/Option.js +346 -0
  95. package/dist/react/Product.d.ts +1065 -0
  96. package/dist/react/Product.js +1157 -0
  97. package/dist/react/ProductList.d.ts +400 -0
  98. package/dist/react/ProductList.js +368 -0
  99. package/dist/react/core/CategoryList.d.ts +194 -0
  100. package/dist/react/core/CategoryList.js +180 -0
  101. package/dist/react/core/Product.d.ts +225 -0
  102. package/dist/react/core/Product.js +190 -0
  103. package/dist/react/core/ProductList.d.ts +235 -0
  104. package/dist/react/core/ProductList.js +217 -0
  105. package/dist/react/core/ProductListFilters.d.ts +138 -0
  106. package/dist/react/core/ProductListFilters.js +242 -0
  107. package/dist/react/core/ProductListPagination.d.ts +49 -0
  108. package/dist/react/core/ProductListPagination.js +41 -0
  109. package/dist/react/core/ProductListSort.d.ts +19 -0
  110. package/dist/react/core/ProductListSort.js +52 -0
  111. package/dist/react/core/ProductModifiers.d.ts +416 -0
  112. package/dist/react/core/ProductModifiers.js +413 -0
  113. package/dist/react/core/ProductVariantSelector.d.ts +313 -0
  114. package/dist/react/core/ProductVariantSelector.js +291 -0
  115. package/dist/react/core/SelectedVariant.d.ts +230 -0
  116. package/dist/react/core/SelectedVariant.js +269 -0
  117. package/dist/react/index.d.ts +6 -0
  118. package/dist/react/index.js +6 -0
  119. package/dist/react/types.d.ts +8 -0
  120. package/dist/react/types.js +9 -0
  121. package/dist/server-actions/custom-checkout-action.d.ts +49 -0
  122. package/dist/server-actions/custom-checkout-action.js +64 -0
  123. package/dist/server-actions/index.d.ts +1 -0
  124. package/dist/server-actions/index.js +1 -0
  125. package/dist/services/buy-now-service.d.ts +346 -0
  126. package/dist/services/buy-now-service.js +197 -0
  127. package/dist/services/categories-list-service.d.ts +164 -0
  128. package/dist/services/categories-list-service.js +148 -0
  129. package/dist/services/index.d.ts +5 -0
  130. package/dist/services/index.js +5 -0
  131. package/dist/services/pay-now-service.d.ts +214 -0
  132. package/dist/services/pay-now-service.js +156 -0
  133. package/dist/services/product-modifiers-service.d.ts +34 -0
  134. package/dist/services/product-modifiers-service.js +107 -0
  135. package/dist/services/product-service.d.ts +177 -0
  136. package/dist/services/product-service.js +190 -0
  137. package/dist/services/products-list-search-service.d.ts +0 -0
  138. package/dist/services/products-list-search-service.js +1 -0
  139. package/dist/services/products-list-service.d.ts +429 -0
  140. package/dist/services/products-list-service.js +893 -0
  141. package/dist/services/selected-variant-service.d.ts +66 -0
  142. package/dist/services/selected-variant-service.js +527 -0
  143. package/dist/utils/index.d.ts +1 -0
  144. package/dist/utils/index.js +30 -0
  145. package/dist/utils/url-params.d.ts +73 -0
  146. package/dist/utils/url-params.js +114 -0
  147. package/package.json +89 -0
  148. package/react/package.json +4 -0
  149. package/server-actions/package.json +4 -0
  150. package/services/package.json +4 -0
@@ -0,0 +1,1157 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { InventoryAvailabilityStatus } from '@wix/auto_sdk_stores_products-v-3';
3
+ import React from 'react';
4
+ import { Commerce } from '@wix/headless-ecom/react';
5
+ import { AsChildSlot } from '@wix/headless-utils/react';
6
+ import { MediaGallery } from '@wix/headless-media/react';
7
+ import { Quantity as QuantityComponent } from '@wix/headless-components/react';
8
+ import * as CoreProduct from './core/Product.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
+ import * as Option from './Option.js';
13
+ import { AsContent } from './types.js';
14
+ import { DataComponentTags } from '../data-component-tags.js';
15
+ const VariantsContext = React.createContext(null);
16
+ /**
17
+ * Hook to access variants context
18
+ */
19
+ export function useVariantsContext() {
20
+ const context = React.useContext(VariantsContext);
21
+ if (!context) {
22
+ throw new Error('useVariantsContext must be used within a Product.Variants component');
23
+ }
24
+ return context;
25
+ }
26
+ const ModifiersContext = React.createContext(null);
27
+ /**
28
+ * Hook to access modifiers context
29
+ */
30
+ export function useModifiersContext() {
31
+ const context = React.useContext(ModifiersContext);
32
+ if (!context) {
33
+ throw new Error('useModifiersContext must be used within a Product.Modifiers component');
34
+ }
35
+ return context;
36
+ }
37
+ var TestIds;
38
+ (function (TestIds) {
39
+ TestIds["productRoot"] = "product-root";
40
+ TestIds["productName"] = "product-name";
41
+ TestIds["productDescription"] = "product-description";
42
+ TestIds["productPrice"] = "product-price";
43
+ TestIds["productCompareAtPrice"] = "product-compare-at-price";
44
+ TestIds["productSlug"] = "product-slug";
45
+ TestIds["productRaw"] = "product-raw";
46
+ TestIds["productRibbon"] = "product-ribbon";
47
+ TestIds["productStock"] = "product-stock";
48
+ TestIds["productVariants"] = "product-variants";
49
+ TestIds["productVariantOptions"] = "product-variant-options";
50
+ TestIds["productVariantSelectorReset"] = "product-variant-selector-reset";
51
+ TestIds["productVariantOption"] = "product-variant-option";
52
+ TestIds["productVariant"] = "product-variant";
53
+ TestIds["productVariantSku"] = "product-variant-sku";
54
+ TestIds["productVariantWeight"] = "product-variant-weight";
55
+ TestIds["productVariantStock"] = "product-variant-stock";
56
+ TestIds["productModifiers"] = "product-modifiers";
57
+ TestIds["productModifierOptions"] = "product-modifier-options";
58
+ TestIds["productModifierOption"] = "product-modifier-option";
59
+ TestIds["productMediaGallery"] = "product-media-gallery";
60
+ TestIds["productAddToCart"] = "product-add-to-cart";
61
+ TestIds["productActionAddToCart"] = "product-action-add-to-cart";
62
+ TestIds["productActionBuyNow"] = "product-action-buy-now";
63
+ TestIds["productActionPreOrder"] = "product-action-can-pre-order";
64
+ TestIds["productQuantity"] = "product-quantity";
65
+ TestIds["productQuantityDecrement"] = "product-quantity-decrement";
66
+ TestIds["productQuantityInput"] = "product-quantity-input";
67
+ TestIds["productQuantityIncrement"] = "product-quantity-increment";
68
+ TestIds["productQuantityRaw"] = "product-quantity-raw";
69
+ })(TestIds || (TestIds = {}));
70
+ /**
71
+ * Root component that provides all necessary service contexts for a complete product experience.
72
+ * This composite component combines Product, ProductVariantSelector, ProductModifiers, and SelectedVariant
73
+ * functionality following the documented API patterns with proper data attributes.
74
+ *
75
+ * @order 1
76
+ * @component
77
+ * @example
78
+ * ```tsx
79
+ * import { Product } from '@wix/stores/components';
80
+ *
81
+ * function ProductPage({ product }) {
82
+ * return (
83
+ * <Product.Root product={product}>
84
+ * <Product.Name className="text-4xl font-bold" />
85
+ * </Product.Root>
86
+ * );
87
+ * }
88
+ * ```
89
+ */
90
+ export const Root = (props) => {
91
+ const { children, product, ...attrs } = props;
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
+ };
96
+ Root.displayName = 'Product.Root';
97
+ /**
98
+ * Displays the product name with customizable rendering following the documented API.
99
+ *
100
+ * @component
101
+ * @example
102
+ * ```tsx
103
+ * // Default usage
104
+ * <Product.Name className="text-4xl font-bold" />
105
+ *
106
+ * // asChild with primitive
107
+ * <Product.Name asChild>
108
+ * <h1 className="text-4xl font-bold" />
109
+ * </Product.Name>
110
+ *
111
+ * // asChild with react component
112
+ * <Product.Name asChild>
113
+ * {React.forwardRef(({name, ...props}, ref) => (
114
+ * <h1 ref={ref} {...props} className="text-4xl font-bold">
115
+ * {name}
116
+ * </h1>
117
+ * ))}
118
+ * </Product.Name>
119
+ * ```
120
+ */
121
+ export const Name = React.forwardRef((props, ref) => {
122
+ const { asChild, children, className, ...otherProps } = props;
123
+ return (_jsx(CoreProduct.Name, { children: ({ name }) => {
124
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productName, customElement: children, customElementProps: { name }, content: name, ...otherProps, children: _jsx("div", { children: name }) }));
125
+ } }));
126
+ });
127
+ /**
128
+ * Displays the product description with customizable rendering and format options following the documented API.
129
+ *
130
+ * @component
131
+ * @example
132
+ * ```tsx
133
+ * // Default usage (plain text)
134
+ * <Product.Description className="text-content-secondary" />
135
+ *
136
+ * // HTML content
137
+ * <Product.Description as="html" className="prose" />
138
+ *
139
+ * // asChild with custom rendering
140
+ * <Product.Description as="html" asChild>
141
+ * {({ description }) => (
142
+ * <div
143
+ * className="text-content-secondary"
144
+ * dangerouslySetInnerHTML={{ __html: description }}
145
+ * />
146
+ * )}
147
+ * </Product.Description>
148
+ * ```
149
+ */
150
+ export const Description = React.forwardRef((props, ref) => {
151
+ const { asChild, children, className, as = AsContent.Plain, ...otherProps } = props;
152
+ return (_jsx(CoreProduct.Description, { children: ({ description: richDescription, plainDescription }) => {
153
+ // Determine which description to use based on the 'as' prop
154
+ let description;
155
+ switch (as) {
156
+ case AsContent.Html:
157
+ description = plainDescription || '';
158
+ break;
159
+ case AsContent.Ricos:
160
+ description = JSON.stringify(richDescription) || '';
161
+ break;
162
+ case AsContent.Plain:
163
+ default:
164
+ // For plain text, we'll strip HTML tags from plainDescription
165
+ description = plainDescription
166
+ ? plainDescription.replace(/<[^>]*>/g, '')
167
+ : '';
168
+ break;
169
+ }
170
+ // Handle default rendering based on format
171
+ if (!asChild || !children) {
172
+ if (as === AsContent.Html) {
173
+ return (_jsx("div", { ref: ref, className: className, "data-testid": TestIds.productDescription, dangerouslySetInnerHTML: { __html: description } }));
174
+ }
175
+ }
176
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productDescription, customElement: children, customElementProps: { description }, content: description, ...otherProps, children: _jsx("div", { children: description }) }));
177
+ } }));
178
+ });
179
+ /**
180
+ * Displays the current product price with customizable rendering following the documented API.
181
+ *
182
+ * @component
183
+ * @example
184
+ * ```tsx
185
+ * // Default usage
186
+ * <Product.Price className="text-3xl font-bold text-content-primary data-[discounted]:text-brand-primary" />
187
+ *
188
+ * // asChild with primitive
189
+ * <Product.Price asChild>
190
+ * <span className="text-3xl font-bold text-content-primary" />
191
+ * </Product.Price>
192
+ *
193
+ * // asChild with react component
194
+ * <Product.Price asChild>
195
+ * {React.forwardRef(({price, formattedPrice, ...props}, ref) => (
196
+ * <span ref={ref} {...props} className="text-3xl font-bold text-content-primary">
197
+ * {formattedPrice}
198
+ * </span>
199
+ * ))}
200
+ * </Product.Price>
201
+ * ```
202
+ */
203
+ export const Price = React.forwardRef((props, ref) => {
204
+ const { asChild, children, className, ...otherProps } = props;
205
+ return (_jsx(CoreSelectedVariant.Price, { children: ({ price, compareAtPrice }) => {
206
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productPrice, "data-discounted": compareAtPrice !== null, customElement: children, customElementProps: {
207
+ price,
208
+ formattedPrice: price,
209
+ }, content: price, ...otherProps, children: _jsx("span", { children: price }) }));
210
+ } }));
211
+ });
212
+ /**
213
+ * Displays the compare-at (original) price when on sale with customizable rendering following the documented API.
214
+ *
215
+ * @component
216
+ * @example
217
+ * ```tsx
218
+ * // Default usage (only shows when on sale)
219
+ * <Product.CompareAtPrice className="text-lg text-content-faded line-through hidden data-[discounted]:inline" />
220
+ *
221
+ * // asChild with primitive
222
+ * <Product.CompareAtPrice asChild>
223
+ * <span className="text-lg text-content-faded line-through" />
224
+ * </Product.CompareAtPrice>
225
+ *
226
+ * // asChild with react component
227
+ * <Product.CompareAtPrice asChild>
228
+ * {React.forwardRef(({formattedPrice, ...props}, ref) => (
229
+ * <span
230
+ * ref={ref}
231
+ * {...props}
232
+ * className="hidden data-[discounted]:inline text-lg text-content-faded line-through"
233
+ * >
234
+ * Was: {formattedPrice}
235
+ * </span>
236
+ * ))}
237
+ * </Product.CompareAtPrice>
238
+ * ```
239
+ */
240
+ export const CompareAtPrice = React.forwardRef((props, ref) => {
241
+ const { asChild, children, className, ...otherProps } = props;
242
+ const testId = TestIds.productCompareAtPrice;
243
+ return (_jsx(CoreSelectedVariant.Price, { children: ({ compareAtPrice }) => {
244
+ // Don't render anything if there's no compare-at price
245
+ if (!compareAtPrice) {
246
+ return null;
247
+ }
248
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": testId, "data-discounted": compareAtPrice !== null, customElement: children, customElementProps: {
249
+ price: compareAtPrice,
250
+ formattedPrice: compareAtPrice,
251
+ }, content: compareAtPrice, ...otherProps, children: _jsx("span", { children: compareAtPrice }) }));
252
+ } }));
253
+ });
254
+ /**
255
+ * Product Slug component that displays the product's slug
256
+ *
257
+ * @component
258
+ * @order 6
259
+ * @example
260
+ * ```tsx
261
+ * import { Product } from '@wix/stores/components';
262
+ *
263
+ * function ProductSlugLink() {
264
+ * return (
265
+ * <Product.Slug>
266
+ * {({ slug }) => (
267
+ * <a href={`/product/${slug}`}>
268
+ * View Product Details
269
+ * </a>
270
+ * )}
271
+ * </Product.Slug>
272
+ * );
273
+ * }
274
+ * ```
275
+ */
276
+ export const Slug = React.forwardRef((props, ref) => {
277
+ const { asChild, children, className, ...otherProps } = props;
278
+ const testId = TestIds.productSlug;
279
+ return (_jsx(CoreProduct.Slug, { children: ({ slug }) => {
280
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": testId, customElement: children, customElementProps: { slug }, content: slug, ...otherProps, children: _jsx("span", { children: slug }) }));
281
+ } }));
282
+ });
283
+ /**
284
+ * Provides access to the raw product data for advanced use cases.
285
+ * Similar to Category.Raw, this should only be used when you need custom access to product data.
286
+ *
287
+ * @component
288
+ * @example
289
+ * ```tsx
290
+ * // Custom rendering with forwardRef
291
+ * <Product.Raw asChild>
292
+ * {React.forwardRef(({product, ...props}, ref) => (
293
+ * <div ref={ref} {...props} className="product-debug">
294
+ * <span>Product ID: {product._id}</span>
295
+ * <span>SKU: {product.sku}</span>
296
+ * <span>Inventory: {product.inventory?.quantity}</span>
297
+ * </div>
298
+ * ))}
299
+ * </Product.Raw>
300
+ * ```
301
+ */
302
+ export const Raw = React.forwardRef((props, ref) => {
303
+ const { asChild, children, className, ...otherProps } = props;
304
+ return (_jsx(CoreProduct.Content, { children: ({ product }) => {
305
+ // Raw component should not render anything by default when not using asChild
306
+ if (!asChild || !children) {
307
+ return null;
308
+ }
309
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productRaw, customElement: children, customElementProps: { product }, ...otherProps }));
310
+ } }));
311
+ });
312
+ /**
313
+ * Displays the product ribbon with customizable rendering following the documented API.
314
+ *
315
+ * @component
316
+ * @example
317
+ * ```tsx
318
+ * // Default usage
319
+ * <Product.Ribbon className="absolute top-2 left-2 bg-red-500 text-white px-2 py-1 text-xs rounded" />
320
+ *
321
+ * // asChild with primitive
322
+ * <Product.Ribbon asChild>
323
+ * <span className="ribbon-badge" />
324
+ * </Product.Ribbon>
325
+ *
326
+ * // asChild with react component
327
+ * <Product.Ribbon asChild>
328
+ * {React.forwardRef(({ribbon, ...props}, ref) => (
329
+ * <div ref={ref} {...props} className="ribbon-badge">
330
+ * {ribbon}
331
+ * </div>
332
+ * ))}
333
+ * </Product.Ribbon>
334
+ * ```
335
+ */
336
+ export const Ribbon = React.forwardRef((props, ref) => {
337
+ const { asChild, children, className } = props;
338
+ return (_jsx(CoreProduct.Ribbon, { children: ({ ribbon, hasRibbon }) => {
339
+ // Don't render anything if there's no ribbon
340
+ if (!hasRibbon) {
341
+ return null;
342
+ }
343
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productRibbon, customElement: children, customElementProps: { ribbon }, content: ribbon, children: _jsx("span", { children: ribbon }) }));
344
+ } }));
345
+ });
346
+ /**
347
+ * Displays the product stock status with customizable rendering and labels following the documented API.
348
+ *
349
+ * @component
350
+ * @example
351
+ * ```tsx
352
+ * // Default usage
353
+ * <Product.Stock
354
+ * className="stock-indicator"
355
+ * labels={{
356
+ * inStock: 'In Stock',
357
+ * limitedStock: 'Limited Stock',
358
+ * outOfStock: 'Out of Stock'
359
+ * }}
360
+ * />
361
+ *
362
+ * // asChild with primitive
363
+ * <Product.Stock asChild>
364
+ * <div className="stock-status" />
365
+ * </Product.Stock>
366
+ *
367
+ * // asChild with react component
368
+ * <Product.Stock
369
+ * labels={{
370
+ * inStock: 'Available',
371
+ * limitedStock: 'Low Stock',
372
+ * outOfStock: 'Sold Out'
373
+ * }}
374
+ * asChild
375
+ * >
376
+ * {React.forwardRef(({status, label, ...props}, ref) => (
377
+ * <div
378
+ * ref={ref}
379
+ * {...props}
380
+ * className="flex items-center gap-1 data-[state='in-stock']:text-green-600 data-[state='limited-stock']:text-yellow-600 data-[state='out-of-stock']:text-red-600"
381
+ * >
382
+ * <div className="w-2 h-2 rounded-full data-[state='in-stock']:bg-green-500 data-[state='limited-stock']:bg-yellow-500 data-[state='out-of-stock']:bg-red-500" />
383
+ * <span className="text-xs font-medium">
384
+ * {label}
385
+ * </span>
386
+ * </div>
387
+ * ))}
388
+ * </Product.Stock>
389
+ * ```
390
+ */
391
+ export const Stock = React.forwardRef((props, ref) => {
392
+ const { asChild, children, className, labels } = props;
393
+ return (_jsx(CoreProduct.Content, { children: ({ product }) => {
394
+ const availabilityStatus = product.inventory?.availabilityStatus;
395
+ // Default labels
396
+ const defaultLabels = {
397
+ inStock: 'In Stock',
398
+ limitedStock: 'Partially Out of Stock',
399
+ outOfStock: 'Out of Stock',
400
+ };
401
+ const finalLabels = { ...defaultLabels, ...labels };
402
+ // Determine status based on availabilityStatus
403
+ let status;
404
+ let label;
405
+ switch (availabilityStatus) {
406
+ case InventoryAvailabilityStatus.IN_STOCK:
407
+ status = 'in-stock';
408
+ label = finalLabels.inStock;
409
+ break;
410
+ case InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK:
411
+ status = 'limited-stock';
412
+ label = finalLabels.limitedStock;
413
+ break;
414
+ case InventoryAvailabilityStatus.OUT_OF_STOCK:
415
+ default:
416
+ status = 'out-of-stock';
417
+ label = finalLabels.outOfStock;
418
+ break;
419
+ }
420
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productStock, "data-state": status, customElement: children, customElementProps: {
421
+ status,
422
+ label,
423
+ }, content: label, children: _jsx("span", { children: label }) }));
424
+ } }));
425
+ });
426
+ /**
427
+ * Container for product variant selection system.
428
+ * Does not render when there are no variants.
429
+ *
430
+ * @component
431
+ * @example
432
+ * ```tsx
433
+ * // Default usage
434
+ * <Product.Variants>
435
+ * <Product.VariantOptions>
436
+ * <Product.VariantOptionRepeater>
437
+ * <Option.Name className="text-lg font-medium mb-3" />
438
+ * <Option.Choices>
439
+ * <Option.ChoiceRepeater>
440
+ * <Choice.Text className="px-4 py-2 border rounded-lg" />
441
+ * <Choice.Color className="w-10 h-10 rounded-full border-4" />
442
+ * </Option.ChoiceRepeater>
443
+ * </Option.Choices>
444
+ * </Product.VariantOptionRepeater>
445
+ * </Product.VariantOptions>
446
+ * </Product.Variants>
447
+ *
448
+ * // asChild with primitive
449
+ * <Product.Variants asChild>
450
+ * <section className="variant-section">
451
+ * <Product.VariantOptions>
452
+ * // variant options
453
+ * </Product.VariantOptions>
454
+ * </section>
455
+ * </Product.Variants>
456
+ *
457
+ * // asChild with react component
458
+ * <Product.Variants asChild>
459
+ * {React.forwardRef(({hasOptions, ...props}, ref) => (
460
+ * <section ref={ref} {...props} className="variant-section">
461
+ * {hasOptions && <h3>Choose Options</h3>}
462
+ * {props.children}
463
+ * </section>
464
+ * ))}
465
+ * </Product.Variants>
466
+ * ```
467
+ */
468
+ export const Variants = React.forwardRef((props, ref) => {
469
+ const { asChild, children, className, ...attributes } = props;
470
+ return (_jsx(CoreProductVariantSelector.Options, { children: ({ hasOptions, options }) => {
471
+ if (!hasOptions)
472
+ return null;
473
+ const contextValue = {
474
+ hasOptions,
475
+ options,
476
+ };
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
+ } }));
479
+ });
480
+ /**
481
+ * Component that provides access to variant options.
482
+ *
483
+ * @component
484
+ * @example
485
+ * ```tsx
486
+ * // Default usage
487
+ * <Product.VariantOptions emptyState={<div>No options available</div>}>
488
+ * <Product.VariantOptionRepeater>
489
+ * <Option.Name />
490
+ * <Option.Choices>
491
+ * <Option.ChoiceRepeater>
492
+ * <Choice.Text />
493
+ * </Option.ChoiceRepeater>
494
+ * </Option.Choices>
495
+ * </Product.VariantOptionRepeater>
496
+ * </Product.VariantOptions>
497
+ *
498
+ * // Simple container usage
499
+ * <Product.VariantOptions emptyState={<div>No options</div>}>
500
+ * <div className="options-container">
501
+ * <Product.VariantOptionRepeater>
502
+ * // option content
503
+ * </Product.VariantOptionRepeater>
504
+ * </div>
505
+ * </Product.VariantOptions>
506
+ * ```
507
+ */
508
+ export const VariantOptions = React.forwardRef((props, ref) => {
509
+ const { children, emptyState } = props;
510
+ const { hasOptions } = useVariantsContext();
511
+ if (!hasOptions) {
512
+ return emptyState || null;
513
+ }
514
+ const attributes = {
515
+ 'data-testid': TestIds.productVariantOptions,
516
+ };
517
+ return (_jsx("div", { ...attributes, ref: ref, children: children }));
518
+ });
519
+ /**
520
+ * Repeater component that renders children for each variant option.
521
+ *
522
+ * @component
523
+ */
524
+ export const VariantOptionRepeater = React.forwardRef((props, _ref) => {
525
+ const { children } = props;
526
+ const { hasOptions, options } = useVariantsContext();
527
+ if (!hasOptions)
528
+ return null;
529
+ return (_jsx(_Fragment, { children: options.map((option) => {
530
+ return (_jsx(CoreProductVariantSelector.Option, { option: option, children: (optionData) => (_jsx(Option.Root, { option: {
531
+ ...optionData,
532
+ mandatory: false,
533
+ }, children: children })) }, option._id));
534
+ }) }));
535
+ });
536
+ /**
537
+ * Container for product modifier system.
538
+ * Does not render when there are no modifiers.
539
+ *
540
+ * @component
541
+ * @example
542
+ * ```tsx
543
+ * // Default usage
544
+ * <Product.Modifiers>
545
+ * <Product.ModifierOptions>
546
+ * <Product.ModifierOptionRepeater>
547
+ * <Option.Name className="text-lg font-medium mb-3" />
548
+ * <Option.Choices>
549
+ * <Option.ChoiceRepeater>
550
+ * <Choice.Text className="px-4 py-2 border rounded-lg" />
551
+ * <Choice.Color className="w-10 h-10 rounded-full border-4" />
552
+ * <Choice.FreeText className="w-full p-3 border rounded-lg resize-none" />
553
+ * </Option.ChoiceRepeater>
554
+ * </Option.Choices>
555
+ * </Product.ModifierOptionRepeater>
556
+ * </Product.ModifierOptions>
557
+ * </Product.Modifiers>
558
+ *
559
+ * // asChild with primitive
560
+ * <Product.Modifiers asChild>
561
+ * <section className="modifier-section">
562
+ * <Product.ModifierOptions>
563
+ * // modifier options
564
+ * </Product.ModifierOptions>
565
+ * </section>
566
+ * </Product.Modifiers>
567
+ *
568
+ * // asChild with react component
569
+ * <Product.Modifiers asChild>
570
+ * {React.forwardRef(({hasModifiers, ...props}, ref) => (
571
+ * <section ref={ref} {...props} className="modifier-section">
572
+ * {hasModifiers && <h3>Customize Your Product</h3>}
573
+ * {props.children}
574
+ * </section>
575
+ * ))}
576
+ * </Product.Modifiers>
577
+ * ```
578
+ */
579
+ export const Modifiers = React.forwardRef((props, ref) => {
580
+ const { asChild, children, className, ...attributes } = props;
581
+ return (_jsx(CoreProductModifiers.Modifiers, { children: ({ hasModifiers, modifiers }) => {
582
+ if (!hasModifiers)
583
+ return null;
584
+ const contextValue = {
585
+ hasModifiers,
586
+ modifiers,
587
+ };
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
+ } }));
590
+ });
591
+ /**
592
+ * Component that provides access to modifier options.
593
+ *
594
+ * @component
595
+ * @example
596
+ * ```tsx
597
+ * // Default usage
598
+ * <Product.ModifierOptions emptyState={<div>No options available</div>}>
599
+ * <Product.ModifierOptionRepeater>
600
+ * <Option.Name />
601
+ * <Option.Choices>
602
+ * <Option.ChoiceRepeater>
603
+ * <Choice.Text />
604
+ * <Choice.Color />
605
+ * <Choice.FreeText />
606
+ * </Option.ChoiceRepeater>
607
+ * </Option.Choices>
608
+ * </Product.ModifierOptionRepeater>
609
+ * </Product.ModifierOptions>
610
+ *
611
+ * // Simple container usage
612
+ * <Product.ModifierOptions emptyState={<div>No options</div>}>
613
+ * <div className="options-container">
614
+ * <Product.ModifierOptionRepeater>
615
+ * // option content
616
+ * </Product.ModifierOptionRepeater>
617
+ * </div>
618
+ * </Product.ModifierOptions>
619
+ * ```
620
+ */
621
+ export const ModifierOptions = React.forwardRef((props, ref) => {
622
+ const { children, emptyState } = props;
623
+ const { hasModifiers } = useModifiersContext();
624
+ if (!hasModifiers) {
625
+ return emptyState || null;
626
+ }
627
+ const attributes = {
628
+ 'data-testid': TestIds.productModifierOptions,
629
+ };
630
+ return (_jsx("div", { ...attributes, ref: ref, children: children }));
631
+ });
632
+ /**
633
+ * Repeater component that renders children for each modifier option.
634
+ *
635
+ * @component
636
+ */
637
+ export const ModifierOptionRepeater = React.forwardRef((props, _ref) => {
638
+ const { children, allowedTypes = ['color', 'text', 'free-text'] } = props;
639
+ const { hasModifiers, modifiers } = useModifiersContext();
640
+ if (!hasModifiers)
641
+ return null;
642
+ return (_jsx(_Fragment, { children: modifiers.map((modifier) => {
643
+ return (_jsx(CoreProductModifiers.Modifier, { modifier: modifier, children: (modifierData) => (_jsx(Option.Root, { option: {
644
+ ...modifierData,
645
+ }, allowedTypes: allowedTypes, children: children })) }, modifier._id));
646
+ }) }));
647
+ });
648
+ /**
649
+ * Container for product media gallery.
650
+ * Renders a MediaGallery.Root with the product media items.
651
+ *
652
+ * @component
653
+ * @example
654
+ * ```tsx
655
+ * // Default usage
656
+ * <Product.MediaGallery
657
+ * infinite={true}
658
+ * autoPlay={{ direction: "forward", intervalMs: 5000 }}
659
+ * >
660
+ * <MediaGallery.Viewport />
661
+ * <MediaGallery.Previous />
662
+ * <MediaGallery.Next />
663
+ * <MediaGallery.Thumbnails>
664
+ * <MediaGallery.ThumbnailRepeater>
665
+ * <MediaGallery.ThumbnailItem />
666
+ * </MediaGallery.ThumbnailRepeater>
667
+ * </MediaGallery.Thumbnails>
668
+ * </Product.MediaGallery>
669
+ *
670
+ * // Simple usage
671
+ * <Product.MediaGallery>
672
+ * <MediaGallery.Viewport className="rounded-lg" />
673
+ * </Product.MediaGallery>
674
+ * ```
675
+ */
676
+ export const ProductMediaGallery = React.forwardRef((props, ref) => {
677
+ const { children, infinite, autoPlay, ...otherProps } = props;
678
+ return (_jsx(CoreProduct.Media, { children: ({ mediaItems, mainMedia }) => {
679
+ const media = mediaItems.length > 0 ? mediaItems : mainMedia ? [mainMedia] : [];
680
+ const mediaGalleryServiceConfig = {
681
+ media,
682
+ infinite,
683
+ autoPlay,
684
+ };
685
+ const attributes = {
686
+ 'data-testid': TestIds.productMediaGallery,
687
+ };
688
+ return (_jsx("div", { ...attributes, ref: ref, ...otherProps, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: mediaGalleryServiceConfig, children: children }) }));
689
+ } }));
690
+ });
691
+ /**
692
+ * Alias for ProductMediaGallery to match the documented API
693
+ */
694
+ export { ProductMediaGallery as MediaGallery };
695
+ /**
696
+ * Product quantity selector component that integrates with the selected variant.
697
+ * Provides quantity controls with stock validation and can-pre-order support.
698
+ * Uses a compound component pattern with Root, Decrement, Input, Increment, and Raw sub-components.
699
+ *
700
+ * @component
701
+ * @example
702
+ * ```tsx
703
+ * // Compound component usage (recommended)
704
+ * <Product.Quantity.Root className="flex items-center gap-3">
705
+ * <div className="flex items-center border border-brand-light rounded-lg">
706
+ * <Product.Quantity.Decrement className="px-3 py-1 hover:bg-surface-primary transition-colors" />
707
+ * <Product.Quantity.Input className="w-16 text-center py-1 border-x border-brand-light focus:outline-none focus:ring-2 focus:ring-brand-primary" />
708
+ * <Product.Quantity.Increment className="px-3 py-1 hover:bg-surface-primary transition-colors" />
709
+ * </div>
710
+ * <Product.Quantity.Raw asChild>
711
+ * {({ availableQuantity, inStock, isPreOrderEnabled }) => (
712
+ * <div>
713
+ * {!inStock && isPreOrderEnabled && availableQuantity && (
714
+ * <span className="text-content-muted text-sm">
715
+ * Max: {availableQuantity} Pre Order
716
+ * </span>
717
+ * )}
718
+ * {inStock && availableQuantity && availableQuantity < 10 && (
719
+ * <span className="text-content-muted text-sm">
720
+ * Only {availableQuantity} left in stock
721
+ * </span>
722
+ * )}
723
+ * </div>
724
+ * )}
725
+ * </Product.Quantity.Raw>
726
+ * </Product.Quantity.Root>
727
+ *
728
+ * // Legacy asChild usage (still supported)
729
+ * <Product.Quantity asChild>
730
+ * {({ selectedQuantity, availableQuantity, inStock, setSelectedQuantity }) => (
731
+ * <div className="flex items-center gap-3">
732
+ * <div className="flex items-center border border-brand-light rounded-lg">
733
+ * <button
734
+ * onClick={() => setSelectedQuantity(selectedQuantity - 1)}
735
+ * disabled={selectedQuantity <= 1 || (!inStock && !isPreOrderEnabled)}
736
+ * className="px-3 py-2 hover:bg-surface-primary disabled:opacity-50"
737
+ * >
738
+ * -
739
+ * </button>
740
+ * <span className="px-4 py-2 border-x border-brand-light min-w-[3rem] text-center">
741
+ * {selectedQuantity}
742
+ * </span>
743
+ * <button
744
+ * onClick={() => setSelectedQuantity(selectedQuantity + 1)}
745
+ * disabled={availableQuantity && selectedQuantity >= availableQuantity}
746
+ * className="px-3 py-2 hover:bg-surface-primary disabled:opacity-50"
747
+ * >
748
+ * +
749
+ * </button>
750
+ * </div>
751
+ * </div>
752
+ * )}
753
+ * </Product.Quantity>
754
+ * ```
755
+ */
756
+ export const ProductQuantity = React.forwardRef((props, ref) => {
757
+ const { asChild, children, className } = props;
758
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availableQuantity, selectedQuantity, setSelectedQuantity, }) => {
759
+ const renderProps = {
760
+ selectedQuantity,
761
+ availableQuantity,
762
+ inStock,
763
+ isPreOrderEnabled,
764
+ setSelectedQuantity,
765
+ };
766
+ if (asChild && children) {
767
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productQuantity, customElement: children, customElementProps: renderProps }));
768
+ }
769
+ return (_jsx(QuantityComponent.Root, { initialValue: selectedQuantity, onValueChange: setSelectedQuantity, className: className, ref: ref, "data-testid": TestIds.productQuantity, children: React.isValidElement(children) ? children : null }));
770
+ } }));
771
+ });
772
+ /**
773
+ * Product Quantity Decrement component.
774
+ * Automatically handles disabled state based on stock and can-pre-order settings.
775
+ * Must be used within Product.Quantity.Root.
776
+ *
777
+ * @component
778
+ * @example
779
+ * ```tsx
780
+ * <Product.Quantity.Decrement className="px-3 py-1 hover:bg-surface-primary transition-colors" />
781
+ * ```
782
+ */
783
+ export const ProductQuantityDecrement = React.forwardRef((props, ref) => {
784
+ const { asChild, children, className } = props;
785
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ selectedQuantity, inStock, isPreOrderEnabled }) => {
786
+ const disabled = selectedQuantity <= 1 || (!inStock && !isPreOrderEnabled);
787
+ if (asChild && children) {
788
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productQuantityDecrement, customElement: children, customElementProps: { disabled } }));
789
+ }
790
+ return (_jsx(QuantityComponent.Decrement, { className: className, ref: ref, "data-testid": TestIds.productQuantityDecrement, disabled }));
791
+ } }));
792
+ });
793
+ /**
794
+ * Product Quantity Input component.
795
+ * Displays the current quantity value. Must be used within Product.Quantity.Root.
796
+ *
797
+ * @component
798
+ * @example
799
+ * ```tsx
800
+ * <Product.Quantity.Input className="w-16 text-center py-1 border-x border-brand-light focus:outline-none focus:ring-2 focus:ring-brand-primary" />
801
+ * ```
802
+ */
803
+ export const ProductQuantityInput = React.forwardRef((props, ref) => {
804
+ const { asChild, children, className, disabled = true } = props;
805
+ return (_jsx(CoreProductVariantSelector.Stock, { children: () => {
806
+ if (asChild && children) {
807
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, disabled: disabled, "data-testid": TestIds.productQuantityInput, customElement: children, customElementProps: {} }));
808
+ }
809
+ return (_jsx(QuantityComponent.Input, { className: className, disabled: disabled, ref: ref, "data-testid": TestIds.productQuantityInput }));
810
+ } }));
811
+ });
812
+ /**
813
+ * Product Quantity Increment component.
814
+ * Automatically handles disabled state based on stock availability.
815
+ * Must be used within Product.Quantity.Root.
816
+ *
817
+ * @component
818
+ * @example
819
+ * ```tsx
820
+ * <Product.Quantity.Increment className="px-3 py-1 hover:bg-surface-primary transition-colors" />
821
+ * ```
822
+ */
823
+ export const ProductQuantityIncrement = React.forwardRef((props, ref) => {
824
+ const { asChild, children, className } = props;
825
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ selectedQuantity, availableQuantity, inStock, isPreOrderEnabled, }) => {
826
+ const disabled = (!!availableQuantity && selectedQuantity >= availableQuantity) ||
827
+ (!inStock && !isPreOrderEnabled);
828
+ if (asChild && children) {
829
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productQuantityIncrement, customElement: children, customElementProps: { disabled } }));
830
+ }
831
+ return (_jsx(QuantityComponent.Increment, { className: className, ref: ref, "data-testid": TestIds.productQuantityIncrement, disabled }));
832
+ } }));
833
+ });
834
+ /**
835
+ * Product Quantity Raw component.
836
+ * Provides access to raw quantity data for custom stock messages and advanced use cases.
837
+ * Must be used within Product.Quantity.Root.
838
+ *
839
+ * @component
840
+ * @example
841
+ * ```tsx
842
+ * <Product.Quantity.Raw asChild>
843
+ * {({ availableQuantity, inStock, isPreOrderEnabled }) => (
844
+ * <div>
845
+ * {!inStock && isPreOrderEnabled && availableQuantity && (
846
+ * <span className="text-content-muted text-sm">
847
+ * Max: {availableQuantity} Pre Order
848
+ * </span>
849
+ * )}
850
+ * {inStock && availableQuantity && availableQuantity < 10 && (
851
+ * <span className="text-content-muted text-sm">
852
+ * Only {availableQuantity} left in stock
853
+ * </span>
854
+ * )}
855
+ * </div>
856
+ * )}
857
+ * </Product.Quantity.Raw>
858
+ * ```
859
+ */
860
+ export const ProductQuantityRaw = React.forwardRef((props, ref) => {
861
+ const { asChild, children, className } = props;
862
+ return (_jsx(CoreProductVariantSelector.Stock, { children: (renderProps) => {
863
+ return (_jsx(AsChildSlot, { ref: ref, customElement: children, asChild: asChild, className: className, "data-testid": TestIds.productQuantityRaw, customElementProps: renderProps }));
864
+ } }));
865
+ });
866
+ export const ProductVariantSelectorReset = React.forwardRef((props, ref) => {
867
+ const { asChild, children, className } = props;
868
+ return (_jsx(CoreProductVariantSelector.Reset, { children: (renderProps) => {
869
+ if (!renderProps.hasSelections) {
870
+ return null;
871
+ }
872
+ const label = props.label || 'Reset Selections';
873
+ return (_jsx(AsChildSlot, { ref: ref, customElement: children, asChild: asChild, className: className, "data-testid": TestIds.productVariantSelectorReset, customElementProps: renderProps, children: _jsx("button", { onClick: renderProps.reset, children: label }) }));
874
+ } }));
875
+ });
876
+ /**
877
+ * Add to cart action button component following the documented API.
878
+ * Automatically integrates with the selected variant and handles loading states.
879
+ */
880
+ export const ProductActionAddToCart = React.forwardRef((props, ref) => {
881
+ const { asChild, children, className, label, loadingState } = props;
882
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, addToCart, isPreOrderEnabled, }) => {
883
+ if (isPreOrderEnabled) {
884
+ return null;
885
+ }
886
+ const onClick = addToCart;
887
+ const disabled = !canAddToCart || isLoading;
888
+ if (asChild && children) {
889
+ return (_jsx(Commerce.Actions.AddToCart, { lineItems: lineItems, asChild: asChild, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productActionAddToCart, "data-in-progress": isLoading, customElement: children, customElementProps: {
890
+ disabled,
891
+ isLoading,
892
+ onClick,
893
+ } }) }));
894
+ }
895
+ return (_jsx(Commerce.Actions.AddToCart, { ref: ref, label: label, lineItems: lineItems, className: className, disabled: disabled, loadingState: loadingState, "data-testid": TestIds.productActionAddToCart, "data-in-progress": isLoading }));
896
+ } }));
897
+ });
898
+ /**
899
+ * Buy Now action button component following the documented API.
900
+ * Bypasses the cart and redirects directly to checkout.
901
+ */
902
+ export const ProductActionBuyNow = React.forwardRef((props, ref) => {
903
+ const { asChild, children, className, label, loadingState } = props;
904
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, canAddToCart, isLoading, buyNow, inStock, isPreOrderEnabled, }) => {
905
+ if (!inStock || isPreOrderEnabled) {
906
+ return null;
907
+ }
908
+ const onClick = buyNow;
909
+ const disabled = !canAddToCart || isLoading;
910
+ if (asChild && children) {
911
+ return (_jsx(Commerce.Actions.BuyNow, { lineItems: lineItems, asChild: asChild, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productActionBuyNow, "data-in-progress": isLoading, customElement: children, customElementProps: {
912
+ disabled,
913
+ isLoading,
914
+ onClick,
915
+ } }) }));
916
+ }
917
+ return (_jsx(Commerce.Actions.BuyNow, { ref: ref, label: label, lineItems: lineItems, className: className, disabled: disabled, loadingState: loadingState, "data-testid": TestIds.productActionBuyNow, "data-in-progress": isLoading }));
918
+ } }));
919
+ });
920
+ /**
921
+ * Pre-Order action button component following the documented API.
922
+ * Handles can-pre-order functionality when products are not in stock.
923
+ */
924
+ export const ProductActionPreOrder = React.forwardRef((props, ref) => {
925
+ const { asChild, children, className, label, loadingState } = props;
926
+ return (_jsx(CoreSelectedVariant.Actions, { children: ({ lineItems, isLoading, addToCart, isPreOrderEnabled }) => {
927
+ if (!isPreOrderEnabled) {
928
+ return null;
929
+ }
930
+ const canPreOrder = !isLoading;
931
+ const onClick = addToCart;
932
+ const disabled = !canPreOrder;
933
+ if (asChild && children) {
934
+ return (_jsx(Commerce.Actions.AddToCart, { lineItems: lineItems, asChild: asChild, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productActionPreOrder, "data-in-progress": isLoading, customElement: children, customElementProps: {
935
+ disabled,
936
+ isLoading,
937
+ onClick,
938
+ } }) }));
939
+ }
940
+ return (_jsx(Commerce.Actions.AddToCart, { ref: ref, label: label, lineItems: lineItems, className: className, disabled: disabled, loadingState: loadingState, "data-testid": TestIds.productActionPreOrder, "data-in-progress": isLoading }));
941
+ } }));
942
+ });
943
+ /**
944
+ * Actions namespace containing all product action components
945
+ * following the documented API: Product.Action.AddToCart, Product.Action.BuyNow, Product.Action.PreOrder
946
+ */
947
+ export const Action = {
948
+ /** Add to cart action button */
949
+ AddToCart: ProductActionAddToCart,
950
+ /** Buy now action button */
951
+ BuyNow: ProductActionBuyNow,
952
+ /** Pre-order action button */
953
+ PreOrder: ProductActionPreOrder,
954
+ };
955
+ /**
956
+ * Helper function to determine stock status and label based on availability and can-pre-order settings
957
+ */
958
+ function getStockStatusMessage(inStock, isPreOrderEnabled, availabilityStatus, labels) {
959
+ // Pre-order takes precedence
960
+ if (isPreOrderEnabled && !inStock) {
961
+ return {
962
+ status: 'can-pre-order',
963
+ label: labels.preOrder,
964
+ };
965
+ }
966
+ // Handle stock status based on availability
967
+ if (inStock) {
968
+ switch (availabilityStatus) {
969
+ case InventoryAvailabilityStatus.IN_STOCK:
970
+ return {
971
+ status: 'in-stock',
972
+ label: labels.inStock,
973
+ };
974
+ case InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK:
975
+ return {
976
+ status: 'limited-stock',
977
+ label: labels.limitedStock,
978
+ };
979
+ default:
980
+ return {
981
+ status: 'in-stock',
982
+ label: labels.inStock,
983
+ };
984
+ }
985
+ }
986
+ return {
987
+ status: 'out-of-stock',
988
+ label: labels.outOfStock,
989
+ };
990
+ }
991
+ /**
992
+ * Displays the selected variant stock status with customizable rendering and labels,
993
+ * including can-pre-order support. Similar to Product.Stock but for the selected variant.
994
+ *
995
+ * @component
996
+ * @example
997
+ * ```tsx
998
+ * // Default usage
999
+ * <Product.ProductVariant.Stock
1000
+ * className="stock-indicator"
1001
+ * labels={{
1002
+ * inStock: 'In Stock',
1003
+ * limitedStock: 'Limited Stock',
1004
+ * outOfStock: 'Out of Stock',
1005
+ * preOrder: 'Available for Pre-order'
1006
+ * }}
1007
+ * />
1008
+ *
1009
+ * // asChild with primitive
1010
+ * <Product.ProductVariant.Stock asChild>
1011
+ * <div className="variant-stock-status" />
1012
+ * </Product.ProductVariant.Stock>
1013
+ *
1014
+ * // asChild with react component
1015
+ * <Product.ProductVariant.Stock
1016
+ * labels={{
1017
+ * inStock: 'Available',
1018
+ * limitedStock: 'Low Stock',
1019
+ * outOfStock: 'Sold Out',
1020
+ * preOrder: 'Pre-order Now'
1021
+ * }}
1022
+ * asChild
1023
+ * >
1024
+ * {React.forwardRef(({status, label, ...props}, ref) => (
1025
+ * <div
1026
+ * ref={ref}
1027
+ * {...props}
1028
+ * className="flex items-center gap-2 data-[state='in-stock']:text-green-600 data-[state='limited-stock']:text-yellow-600 data-[state='out-of-stock']:text-red-600 data-[state='can-pre-order']:text-blue-600"
1029
+ * >
1030
+ * <div className="w-3 h-3 rounded-full data-[state='in-stock']:bg-green-500 data-[state='limited-stock']:bg-yellow-500 data-[state='out-of-stock']:bg-red-500 data-[state='can-pre-order']:bg-blue-500" />
1031
+ * <span className="text-sm font-medium">
1032
+ * {label}
1033
+ * </span>
1034
+ * </div>
1035
+ * ))}
1036
+ * </Product.ProductVariant.Stock>
1037
+ * ```
1038
+ */
1039
+ export const ProductVariantStock = React.forwardRef((props, ref) => {
1040
+ const { asChild, children, className, labels } = props;
1041
+ return (_jsx(CoreProductVariantSelector.Stock, { children: ({ inStock, isPreOrderEnabled, availabilityStatus, currentVariantId, }) => {
1042
+ // Only render if we have a current variant selected
1043
+ if (!currentVariantId && !availabilityStatus) {
1044
+ return null;
1045
+ }
1046
+ // Default labels
1047
+ const defaultLabels = {
1048
+ inStock: 'In Stock',
1049
+ limitedStock: 'Limited Stock',
1050
+ outOfStock: 'Out of Stock',
1051
+ preOrder: 'Available for Pre-order',
1052
+ };
1053
+ const finalLabels = { ...defaultLabels, ...labels };
1054
+ // Get status and label using the helper function
1055
+ const { status, label } = getStockStatusMessage(inStock, isPreOrderEnabled, availabilityStatus, finalLabels);
1056
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariantStock, "data-state": status, customElement: children, customElementProps: {
1057
+ status,
1058
+ label,
1059
+ }, content: label, children: _jsx("span", { children: label }) }));
1060
+ } }));
1061
+ });
1062
+ /**
1063
+ * Displays the selected variant SKU with customizable rendering following the documented API.
1064
+ *
1065
+ * @component
1066
+ * @example
1067
+ * ```tsx
1068
+ * // Default usage
1069
+ * <Product.ProductVariant.SKU className="text-content-secondary" />
1070
+ *
1071
+ * // asChild with primitive
1072
+ * <Product.ProductVariant.SKU asChild>
1073
+ * <span className="sku-value" />
1074
+ * </Product.ProductVariant.SKU>
1075
+ *
1076
+ * // asChild with react component
1077
+ * <Product.ProductVariant.SKU asChild>
1078
+ * {React.forwardRef(({sku, ...props}, ref) => (
1079
+ * <span ref={ref} {...props}>
1080
+ * {sku}
1081
+ * </span>
1082
+ * ))}
1083
+ * </Product.ProductVariant.SKU>
1084
+ * ```
1085
+ */
1086
+ export const ProductVariantSKU = React.forwardRef((props, ref) => {
1087
+ const { asChild, children, className } = props;
1088
+ return (_jsx(CoreSelectedVariant.Details, { children: ({ sku }) => {
1089
+ // Don't render anything if there's no SKU
1090
+ if (!sku) {
1091
+ return null;
1092
+ }
1093
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariantSku, customElement: children, customElementProps: { sku }, content: sku, children: _jsx("span", { children: sku }) }));
1094
+ } }));
1095
+ });
1096
+ /**
1097
+ * Displays the selected variant weight with customizable rendering following the documented API.
1098
+ *
1099
+ * @component
1100
+ * @example
1101
+ * ```tsx
1102
+ * // Default usage
1103
+ * <Product.ProductVariant.Weight className="text-content-secondary" />
1104
+ *
1105
+ * // asChild with primitive
1106
+ * <Product.ProductVariant.Weight asChild>
1107
+ * <span className="weight-value" />
1108
+ * </Product.ProductVariant.Weight>
1109
+ *
1110
+ * // asChild with react component
1111
+ * <Product.ProductVariant.Weight asChild>
1112
+ * {React.forwardRef(({weight, ...props}, ref) => (
1113
+ * <span ref={ref} {...props}>
1114
+ * {weight}
1115
+ * </span>
1116
+ * ))}
1117
+ * </Product.ProductVariant.Weight>
1118
+ * ```
1119
+ */
1120
+ export const ProductVariantWeight = React.forwardRef((props, ref) => {
1121
+ const { asChild, children, className } = props;
1122
+ return (_jsx(CoreSelectedVariant.Details, { children: ({ weight }) => {
1123
+ // Don't render anything if there's no weight
1124
+ if (!weight) {
1125
+ return null;
1126
+ }
1127
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productVariantWeight, customElement: children, customElementProps: { weight }, content: weight, children: _jsx("span", { children: weight }) }));
1128
+ } }));
1129
+ });
1130
+ /**
1131
+ * ProductVariant namespace containing product variant components
1132
+ * following the compound component pattern: Product.ProductVariant.Stock, Product.ProductVariant.SKU, Product.ProductVariant.Weight
1133
+ */
1134
+ export const ProductVariant = {
1135
+ /** Product variant stock component */
1136
+ Stock: ProductVariantStock,
1137
+ /** Product variant SKU component */
1138
+ SKU: ProductVariantSKU,
1139
+ /** Product variant weight component */
1140
+ Weight: ProductVariantWeight,
1141
+ };
1142
+ /**
1143
+ * Quantity namespace containing all product quantity components
1144
+ * following the compound component pattern: Product.Quantity.Root, Product.Quantity.Decrement, etc.
1145
+ */
1146
+ export const Quantity = {
1147
+ /** Product quantity selector component */
1148
+ Root: ProductQuantity,
1149
+ /** Product quantity decrement component */
1150
+ Decrement: ProductQuantityDecrement,
1151
+ /** Product quantity input component */
1152
+ Input: ProductQuantityInput,
1153
+ /** Product quantity increment component */
1154
+ Increment: ProductQuantityIncrement,
1155
+ /** Product quantity raw component */
1156
+ Raw: ProductQuantityRaw,
1157
+ };