@wix/headless-stores 0.0.60 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/dist/react/Product.d.ts +107 -0
- package/cjs/dist/react/Product.js +120 -2
- package/cjs/dist/react/core/Product.d.ts +40 -0
- package/cjs/dist/react/core/Product.js +33 -0
- package/dist/react/Product.d.ts +107 -0
- package/dist/react/Product.js +120 -2
- package/dist/react/core/Product.d.ts +40 -0
- package/dist/react/core/Product.js +33 -0
- package/package.json +2 -2
|
@@ -282,6 +282,113 @@ export interface RawProps {
|
|
|
282
282
|
* ```
|
|
283
283
|
*/
|
|
284
284
|
export declare const Raw: React.ForwardRefExoticComponent<RawProps & React.RefAttributes<HTMLElement>>;
|
|
285
|
+
/**
|
|
286
|
+
* Props for Product Ribbon component
|
|
287
|
+
*/
|
|
288
|
+
export interface RibbonProps {
|
|
289
|
+
/** Whether to render as a child component */
|
|
290
|
+
asChild?: boolean;
|
|
291
|
+
/** Custom render function when using asChild */
|
|
292
|
+
children?: React.ReactNode | React.ForwardRefRenderFunction<HTMLElement, {
|
|
293
|
+
ribbon: string | null;
|
|
294
|
+
}> | React.ForwardRefExoticComponent<any>;
|
|
295
|
+
/** CSS classes to apply to the default element */
|
|
296
|
+
className?: string;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Displays the product ribbon with customizable rendering following the documented API.
|
|
300
|
+
*
|
|
301
|
+
* @component
|
|
302
|
+
* @example
|
|
303
|
+
* ```tsx
|
|
304
|
+
* // Default usage
|
|
305
|
+
* <Product.Ribbon className="absolute top-2 left-2 bg-red-500 text-white px-2 py-1 text-xs rounded" />
|
|
306
|
+
*
|
|
307
|
+
* // asChild with primitive
|
|
308
|
+
* <Product.Ribbon asChild>
|
|
309
|
+
* <span className="ribbon-badge" />
|
|
310
|
+
* </Product.Ribbon>
|
|
311
|
+
*
|
|
312
|
+
* // asChild with react component
|
|
313
|
+
* <Product.Ribbon asChild>
|
|
314
|
+
* {React.forwardRef(({ribbon, ...props}, ref) => (
|
|
315
|
+
* <div ref={ref} {...props} className="ribbon-badge">
|
|
316
|
+
* {ribbon}
|
|
317
|
+
* </div>
|
|
318
|
+
* ))}
|
|
319
|
+
* </Product.Ribbon>
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
export declare const Ribbon: React.ForwardRefExoticComponent<RibbonProps & React.RefAttributes<HTMLElement>>;
|
|
323
|
+
/**
|
|
324
|
+
* Props for Product Stock component
|
|
325
|
+
*/
|
|
326
|
+
export interface StockProps {
|
|
327
|
+
/** Whether to render as a child component */
|
|
328
|
+
asChild?: boolean;
|
|
329
|
+
/** Custom render function when using asChild */
|
|
330
|
+
children?: React.ReactNode | React.ForwardRefRenderFunction<HTMLElement, {
|
|
331
|
+
status: 'in-stock' | 'limited-stock' | 'out-of-stock';
|
|
332
|
+
label: string;
|
|
333
|
+
}> | React.ForwardRefExoticComponent<any>;
|
|
334
|
+
/** CSS classes to apply to the default element */
|
|
335
|
+
className?: string;
|
|
336
|
+
/** Custom labels for different stock states */
|
|
337
|
+
labels?: {
|
|
338
|
+
/** Label for in stock state */
|
|
339
|
+
inStock?: string;
|
|
340
|
+
/** Label for limited stock state (when quantity is low) */
|
|
341
|
+
limitedStock?: string;
|
|
342
|
+
/** Label for out of stock state */
|
|
343
|
+
outOfStock?: string;
|
|
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 declare const Stock: React.ForwardRefExoticComponent<StockProps & React.RefAttributes<HTMLElement>>;
|
|
285
392
|
/**
|
|
286
393
|
* Props for Product Variants container
|
|
287
394
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { InventoryAvailabilityStatus } from '@wix/auto_sdk_stores_products-v-3';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
4
5
|
import { MediaGallery } from '@wix/headless-media/react';
|
|
@@ -39,6 +40,8 @@ var TestIds;
|
|
|
39
40
|
TestIds["productCompareAtPrice"] = "product-compare-at-price";
|
|
40
41
|
TestIds["productSlug"] = "product-slug";
|
|
41
42
|
TestIds["productRaw"] = "product-raw";
|
|
43
|
+
TestIds["productRibbon"] = "product-ribbon";
|
|
44
|
+
TestIds["productStock"] = "product-stock";
|
|
42
45
|
TestIds["productVariants"] = "product-variants";
|
|
43
46
|
TestIds["productVariantOptions"] = "product-variant-options";
|
|
44
47
|
TestIds["productVariantOption"] = "product-variant-option";
|
|
@@ -68,9 +71,10 @@ var TestIds;
|
|
|
68
71
|
* ```
|
|
69
72
|
*/
|
|
70
73
|
export function Root(props) {
|
|
71
|
-
|
|
74
|
+
const { children, product, ...attrs } = props;
|
|
75
|
+
return (_jsx(CoreProduct.Root, { productServiceConfig: { product: props.product }, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: {
|
|
72
76
|
media: props.product.media?.itemsInfo?.items ?? [],
|
|
73
|
-
}, children: _jsx(ProductVariantSelector.Root, { children: _jsx(ProductModifiers.Root, { children: _jsx(SelectedVariant.Root, { children:
|
|
77
|
+
}, children: _jsx(ProductVariantSelector.Root, { children: _jsx(ProductModifiers.Root, { children: _jsx(SelectedVariant.Root, { children: _jsx(AsChildSlot, { ...attrs, children: children }) }) }) }) }) }));
|
|
74
78
|
}
|
|
75
79
|
/**
|
|
76
80
|
* Displays the product name with customizable rendering following the documented API.
|
|
@@ -287,6 +291,120 @@ export const Raw = React.forwardRef((props, ref) => {
|
|
|
287
291
|
return (_jsx(AsChildSlot, { ref: ref, className: className, "data-testid": TestIds.productRaw, customElement: children, customElementProps: { product } }));
|
|
288
292
|
} }));
|
|
289
293
|
});
|
|
294
|
+
/**
|
|
295
|
+
* Displays the product ribbon with customizable rendering following the documented API.
|
|
296
|
+
*
|
|
297
|
+
* @component
|
|
298
|
+
* @example
|
|
299
|
+
* ```tsx
|
|
300
|
+
* // Default usage
|
|
301
|
+
* <Product.Ribbon className="absolute top-2 left-2 bg-red-500 text-white px-2 py-1 text-xs rounded" />
|
|
302
|
+
*
|
|
303
|
+
* // asChild with primitive
|
|
304
|
+
* <Product.Ribbon asChild>
|
|
305
|
+
* <span className="ribbon-badge" />
|
|
306
|
+
* </Product.Ribbon>
|
|
307
|
+
*
|
|
308
|
+
* // asChild with react component
|
|
309
|
+
* <Product.Ribbon asChild>
|
|
310
|
+
* {React.forwardRef(({ribbon, ...props}, ref) => (
|
|
311
|
+
* <div ref={ref} {...props} className="ribbon-badge">
|
|
312
|
+
* {ribbon}
|
|
313
|
+
* </div>
|
|
314
|
+
* ))}
|
|
315
|
+
* </Product.Ribbon>
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
export const Ribbon = React.forwardRef((props, ref) => {
|
|
319
|
+
const { asChild, children, className } = props;
|
|
320
|
+
return (_jsx(CoreProduct.Ribbon, { children: ({ ribbon, hasRibbon }) => {
|
|
321
|
+
// Don't render anything if there's no ribbon
|
|
322
|
+
if (!hasRibbon) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productRibbon, customElement: children, customElementProps: { ribbon }, content: ribbon, children: _jsx("span", { children: ribbon }) }));
|
|
326
|
+
} }));
|
|
327
|
+
});
|
|
328
|
+
/**
|
|
329
|
+
* Displays the product stock status with customizable rendering and labels following the documented API.
|
|
330
|
+
*
|
|
331
|
+
* @component
|
|
332
|
+
* @example
|
|
333
|
+
* ```tsx
|
|
334
|
+
* // Default usage
|
|
335
|
+
* <Product.Stock
|
|
336
|
+
* className="stock-indicator"
|
|
337
|
+
* labels={{
|
|
338
|
+
* inStock: 'In Stock',
|
|
339
|
+
* limitedStock: 'Limited Stock',
|
|
340
|
+
* outOfStock: 'Out of Stock'
|
|
341
|
+
* }}
|
|
342
|
+
* />
|
|
343
|
+
*
|
|
344
|
+
* // asChild with primitive
|
|
345
|
+
* <Product.Stock asChild>
|
|
346
|
+
* <div className="stock-status" />
|
|
347
|
+
* </Product.Stock>
|
|
348
|
+
*
|
|
349
|
+
* // asChild with react component
|
|
350
|
+
* <Product.Stock
|
|
351
|
+
* labels={{
|
|
352
|
+
* inStock: 'Available',
|
|
353
|
+
* limitedStock: 'Low Stock',
|
|
354
|
+
* outOfStock: 'Sold Out'
|
|
355
|
+
* }}
|
|
356
|
+
* asChild
|
|
357
|
+
* >
|
|
358
|
+
* {React.forwardRef(({status, label, ...props}, ref) => (
|
|
359
|
+
* <div
|
|
360
|
+
* ref={ref}
|
|
361
|
+
* {...props}
|
|
362
|
+
* 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"
|
|
363
|
+
* >
|
|
364
|
+
* <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" />
|
|
365
|
+
* <span className="text-xs font-medium">
|
|
366
|
+
* {label}
|
|
367
|
+
* </span>
|
|
368
|
+
* </div>
|
|
369
|
+
* ))}
|
|
370
|
+
* </Product.Stock>
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
export const Stock = React.forwardRef((props, ref) => {
|
|
374
|
+
const { asChild, children, className, labels } = props;
|
|
375
|
+
return (_jsx(CoreProduct.Content, { children: ({ product }) => {
|
|
376
|
+
const availabilityStatus = product.inventory?.availabilityStatus;
|
|
377
|
+
// Default labels
|
|
378
|
+
const defaultLabels = {
|
|
379
|
+
inStock: 'In Stock',
|
|
380
|
+
limitedStock: 'Partially Out of Stock',
|
|
381
|
+
outOfStock: 'Out of Stock',
|
|
382
|
+
};
|
|
383
|
+
const finalLabels = { ...defaultLabels, ...labels };
|
|
384
|
+
// Determine status based on availabilityStatus
|
|
385
|
+
let status;
|
|
386
|
+
let label;
|
|
387
|
+
switch (availabilityStatus) {
|
|
388
|
+
case InventoryAvailabilityStatus.IN_STOCK:
|
|
389
|
+
status = 'in-stock';
|
|
390
|
+
label = finalLabels.inStock;
|
|
391
|
+
break;
|
|
392
|
+
case InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK:
|
|
393
|
+
status = 'limited-stock';
|
|
394
|
+
label = finalLabels.limitedStock;
|
|
395
|
+
break;
|
|
396
|
+
case InventoryAvailabilityStatus.OUT_OF_STOCK:
|
|
397
|
+
default:
|
|
398
|
+
status = 'out-of-stock';
|
|
399
|
+
label = finalLabels.outOfStock;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productStock, "data-state": status, customElement: children, customElementProps: {
|
|
403
|
+
status,
|
|
404
|
+
label,
|
|
405
|
+
}, content: label, children: _jsx("span", { children: label }) }));
|
|
406
|
+
} }));
|
|
407
|
+
});
|
|
290
408
|
/**
|
|
291
409
|
* Container for product variant selection system.
|
|
292
410
|
* Does not render when there are no variants.
|
|
@@ -183,3 +183,43 @@ export interface ProductSlugRenderProps {
|
|
|
183
183
|
* ```
|
|
184
184
|
*/
|
|
185
185
|
export declare function Slug(props: ProductSlugProps): import("react").ReactNode;
|
|
186
|
+
/**
|
|
187
|
+
* Props for ProductRibbon headless component
|
|
188
|
+
*/
|
|
189
|
+
export interface ProductRibbonProps {
|
|
190
|
+
/** Render prop function that receives product ribbon data */
|
|
191
|
+
children: (props: ProductRibbonRenderProps) => React.ReactNode;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Render props for ProductRibbon component
|
|
195
|
+
*/
|
|
196
|
+
export interface ProductRibbonRenderProps {
|
|
197
|
+
/** Product ribbon text */
|
|
198
|
+
ribbon: string | null;
|
|
199
|
+
/** Whether the product has a ribbon */
|
|
200
|
+
hasRibbon: boolean;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Headless component for product ribbon display
|
|
204
|
+
*
|
|
205
|
+
* @component
|
|
206
|
+
* @example
|
|
207
|
+
* ```tsx
|
|
208
|
+
* import { Product } from '@wix/stores/components';
|
|
209
|
+
*
|
|
210
|
+
* function ProductRibbonDisplay() {
|
|
211
|
+
* return (
|
|
212
|
+
* <Product.Ribbon>
|
|
213
|
+
* {({ ribbon, hasRibbon }) => (
|
|
214
|
+
* hasRibbon ? (
|
|
215
|
+
* <span className="ribbon-badge">
|
|
216
|
+
* {ribbon}
|
|
217
|
+
* </span>
|
|
218
|
+
* ) : null
|
|
219
|
+
* )}
|
|
220
|
+
* </Product.Ribbon>
|
|
221
|
+
* );
|
|
222
|
+
* }
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
export declare function Ribbon(props: ProductRibbonProps): import("react").ReactNode;
|
|
@@ -155,3 +155,36 @@ export function Slug(props) {
|
|
|
155
155
|
slug,
|
|
156
156
|
});
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Headless component for product ribbon display
|
|
160
|
+
*
|
|
161
|
+
* @component
|
|
162
|
+
* @example
|
|
163
|
+
* ```tsx
|
|
164
|
+
* import { Product } from '@wix/stores/components';
|
|
165
|
+
*
|
|
166
|
+
* function ProductRibbonDisplay() {
|
|
167
|
+
* return (
|
|
168
|
+
* <Product.Ribbon>
|
|
169
|
+
* {({ ribbon, hasRibbon }) => (
|
|
170
|
+
* hasRibbon ? (
|
|
171
|
+
* <span className="ribbon-badge">
|
|
172
|
+
* {ribbon}
|
|
173
|
+
* </span>
|
|
174
|
+
* ) : null
|
|
175
|
+
* )}
|
|
176
|
+
* </Product.Ribbon>
|
|
177
|
+
* );
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export function Ribbon(props) {
|
|
182
|
+
const service = useService(ProductServiceDefinition);
|
|
183
|
+
const product = service.product.get();
|
|
184
|
+
const ribbon = product.ribbon?.name || null;
|
|
185
|
+
const hasRibbon = !!ribbon;
|
|
186
|
+
return props.children({
|
|
187
|
+
ribbon,
|
|
188
|
+
hasRibbon,
|
|
189
|
+
});
|
|
190
|
+
}
|
package/dist/react/Product.d.ts
CHANGED
|
@@ -282,6 +282,113 @@ export interface RawProps {
|
|
|
282
282
|
* ```
|
|
283
283
|
*/
|
|
284
284
|
export declare const Raw: React.ForwardRefExoticComponent<RawProps & React.RefAttributes<HTMLElement>>;
|
|
285
|
+
/**
|
|
286
|
+
* Props for Product Ribbon component
|
|
287
|
+
*/
|
|
288
|
+
export interface RibbonProps {
|
|
289
|
+
/** Whether to render as a child component */
|
|
290
|
+
asChild?: boolean;
|
|
291
|
+
/** Custom render function when using asChild */
|
|
292
|
+
children?: React.ReactNode | React.ForwardRefRenderFunction<HTMLElement, {
|
|
293
|
+
ribbon: string | null;
|
|
294
|
+
}> | React.ForwardRefExoticComponent<any>;
|
|
295
|
+
/** CSS classes to apply to the default element */
|
|
296
|
+
className?: string;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Displays the product ribbon with customizable rendering following the documented API.
|
|
300
|
+
*
|
|
301
|
+
* @component
|
|
302
|
+
* @example
|
|
303
|
+
* ```tsx
|
|
304
|
+
* // Default usage
|
|
305
|
+
* <Product.Ribbon className="absolute top-2 left-2 bg-red-500 text-white px-2 py-1 text-xs rounded" />
|
|
306
|
+
*
|
|
307
|
+
* // asChild with primitive
|
|
308
|
+
* <Product.Ribbon asChild>
|
|
309
|
+
* <span className="ribbon-badge" />
|
|
310
|
+
* </Product.Ribbon>
|
|
311
|
+
*
|
|
312
|
+
* // asChild with react component
|
|
313
|
+
* <Product.Ribbon asChild>
|
|
314
|
+
* {React.forwardRef(({ribbon, ...props}, ref) => (
|
|
315
|
+
* <div ref={ref} {...props} className="ribbon-badge">
|
|
316
|
+
* {ribbon}
|
|
317
|
+
* </div>
|
|
318
|
+
* ))}
|
|
319
|
+
* </Product.Ribbon>
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
export declare const Ribbon: React.ForwardRefExoticComponent<RibbonProps & React.RefAttributes<HTMLElement>>;
|
|
323
|
+
/**
|
|
324
|
+
* Props for Product Stock component
|
|
325
|
+
*/
|
|
326
|
+
export interface StockProps {
|
|
327
|
+
/** Whether to render as a child component */
|
|
328
|
+
asChild?: boolean;
|
|
329
|
+
/** Custom render function when using asChild */
|
|
330
|
+
children?: React.ReactNode | React.ForwardRefRenderFunction<HTMLElement, {
|
|
331
|
+
status: 'in-stock' | 'limited-stock' | 'out-of-stock';
|
|
332
|
+
label: string;
|
|
333
|
+
}> | React.ForwardRefExoticComponent<any>;
|
|
334
|
+
/** CSS classes to apply to the default element */
|
|
335
|
+
className?: string;
|
|
336
|
+
/** Custom labels for different stock states */
|
|
337
|
+
labels?: {
|
|
338
|
+
/** Label for in stock state */
|
|
339
|
+
inStock?: string;
|
|
340
|
+
/** Label for limited stock state (when quantity is low) */
|
|
341
|
+
limitedStock?: string;
|
|
342
|
+
/** Label for out of stock state */
|
|
343
|
+
outOfStock?: string;
|
|
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 declare const Stock: React.ForwardRefExoticComponent<StockProps & React.RefAttributes<HTMLElement>>;
|
|
285
392
|
/**
|
|
286
393
|
* Props for Product Variants container
|
|
287
394
|
*/
|
package/dist/react/Product.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { InventoryAvailabilityStatus } from '@wix/auto_sdk_stores_products-v-3';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
4
5
|
import { MediaGallery } from '@wix/headless-media/react';
|
|
@@ -39,6 +40,8 @@ var TestIds;
|
|
|
39
40
|
TestIds["productCompareAtPrice"] = "product-compare-at-price";
|
|
40
41
|
TestIds["productSlug"] = "product-slug";
|
|
41
42
|
TestIds["productRaw"] = "product-raw";
|
|
43
|
+
TestIds["productRibbon"] = "product-ribbon";
|
|
44
|
+
TestIds["productStock"] = "product-stock";
|
|
42
45
|
TestIds["productVariants"] = "product-variants";
|
|
43
46
|
TestIds["productVariantOptions"] = "product-variant-options";
|
|
44
47
|
TestIds["productVariantOption"] = "product-variant-option";
|
|
@@ -68,9 +71,10 @@ var TestIds;
|
|
|
68
71
|
* ```
|
|
69
72
|
*/
|
|
70
73
|
export function Root(props) {
|
|
71
|
-
|
|
74
|
+
const { children, product, ...attrs } = props;
|
|
75
|
+
return (_jsx(CoreProduct.Root, { productServiceConfig: { product: props.product }, children: _jsx(MediaGallery.Root, { mediaGalleryServiceConfig: {
|
|
72
76
|
media: props.product.media?.itemsInfo?.items ?? [],
|
|
73
|
-
}, children: _jsx(ProductVariantSelector.Root, { children: _jsx(ProductModifiers.Root, { children: _jsx(SelectedVariant.Root, { children:
|
|
77
|
+
}, children: _jsx(ProductVariantSelector.Root, { children: _jsx(ProductModifiers.Root, { children: _jsx(SelectedVariant.Root, { children: _jsx(AsChildSlot, { ...attrs, children: children }) }) }) }) }) }));
|
|
74
78
|
}
|
|
75
79
|
/**
|
|
76
80
|
* Displays the product name with customizable rendering following the documented API.
|
|
@@ -287,6 +291,120 @@ export const Raw = React.forwardRef((props, ref) => {
|
|
|
287
291
|
return (_jsx(AsChildSlot, { ref: ref, className: className, "data-testid": TestIds.productRaw, customElement: children, customElementProps: { product } }));
|
|
288
292
|
} }));
|
|
289
293
|
});
|
|
294
|
+
/**
|
|
295
|
+
* Displays the product ribbon with customizable rendering following the documented API.
|
|
296
|
+
*
|
|
297
|
+
* @component
|
|
298
|
+
* @example
|
|
299
|
+
* ```tsx
|
|
300
|
+
* // Default usage
|
|
301
|
+
* <Product.Ribbon className="absolute top-2 left-2 bg-red-500 text-white px-2 py-1 text-xs rounded" />
|
|
302
|
+
*
|
|
303
|
+
* // asChild with primitive
|
|
304
|
+
* <Product.Ribbon asChild>
|
|
305
|
+
* <span className="ribbon-badge" />
|
|
306
|
+
* </Product.Ribbon>
|
|
307
|
+
*
|
|
308
|
+
* // asChild with react component
|
|
309
|
+
* <Product.Ribbon asChild>
|
|
310
|
+
* {React.forwardRef(({ribbon, ...props}, ref) => (
|
|
311
|
+
* <div ref={ref} {...props} className="ribbon-badge">
|
|
312
|
+
* {ribbon}
|
|
313
|
+
* </div>
|
|
314
|
+
* ))}
|
|
315
|
+
* </Product.Ribbon>
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
export const Ribbon = React.forwardRef((props, ref) => {
|
|
319
|
+
const { asChild, children, className } = props;
|
|
320
|
+
return (_jsx(CoreProduct.Ribbon, { children: ({ ribbon, hasRibbon }) => {
|
|
321
|
+
// Don't render anything if there's no ribbon
|
|
322
|
+
if (!hasRibbon) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productRibbon, customElement: children, customElementProps: { ribbon }, content: ribbon, children: _jsx("span", { children: ribbon }) }));
|
|
326
|
+
} }));
|
|
327
|
+
});
|
|
328
|
+
/**
|
|
329
|
+
* Displays the product stock status with customizable rendering and labels following the documented API.
|
|
330
|
+
*
|
|
331
|
+
* @component
|
|
332
|
+
* @example
|
|
333
|
+
* ```tsx
|
|
334
|
+
* // Default usage
|
|
335
|
+
* <Product.Stock
|
|
336
|
+
* className="stock-indicator"
|
|
337
|
+
* labels={{
|
|
338
|
+
* inStock: 'In Stock',
|
|
339
|
+
* limitedStock: 'Limited Stock',
|
|
340
|
+
* outOfStock: 'Out of Stock'
|
|
341
|
+
* }}
|
|
342
|
+
* />
|
|
343
|
+
*
|
|
344
|
+
* // asChild with primitive
|
|
345
|
+
* <Product.Stock asChild>
|
|
346
|
+
* <div className="stock-status" />
|
|
347
|
+
* </Product.Stock>
|
|
348
|
+
*
|
|
349
|
+
* // asChild with react component
|
|
350
|
+
* <Product.Stock
|
|
351
|
+
* labels={{
|
|
352
|
+
* inStock: 'Available',
|
|
353
|
+
* limitedStock: 'Low Stock',
|
|
354
|
+
* outOfStock: 'Sold Out'
|
|
355
|
+
* }}
|
|
356
|
+
* asChild
|
|
357
|
+
* >
|
|
358
|
+
* {React.forwardRef(({status, label, ...props}, ref) => (
|
|
359
|
+
* <div
|
|
360
|
+
* ref={ref}
|
|
361
|
+
* {...props}
|
|
362
|
+
* 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"
|
|
363
|
+
* >
|
|
364
|
+
* <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" />
|
|
365
|
+
* <span className="text-xs font-medium">
|
|
366
|
+
* {label}
|
|
367
|
+
* </span>
|
|
368
|
+
* </div>
|
|
369
|
+
* ))}
|
|
370
|
+
* </Product.Stock>
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
export const Stock = React.forwardRef((props, ref) => {
|
|
374
|
+
const { asChild, children, className, labels } = props;
|
|
375
|
+
return (_jsx(CoreProduct.Content, { children: ({ product }) => {
|
|
376
|
+
const availabilityStatus = product.inventory?.availabilityStatus;
|
|
377
|
+
// Default labels
|
|
378
|
+
const defaultLabels = {
|
|
379
|
+
inStock: 'In Stock',
|
|
380
|
+
limitedStock: 'Partially Out of Stock',
|
|
381
|
+
outOfStock: 'Out of Stock',
|
|
382
|
+
};
|
|
383
|
+
const finalLabels = { ...defaultLabels, ...labels };
|
|
384
|
+
// Determine status based on availabilityStatus
|
|
385
|
+
let status;
|
|
386
|
+
let label;
|
|
387
|
+
switch (availabilityStatus) {
|
|
388
|
+
case InventoryAvailabilityStatus.IN_STOCK:
|
|
389
|
+
status = 'in-stock';
|
|
390
|
+
label = finalLabels.inStock;
|
|
391
|
+
break;
|
|
392
|
+
case InventoryAvailabilityStatus.PARTIALLY_OUT_OF_STOCK:
|
|
393
|
+
status = 'limited-stock';
|
|
394
|
+
label = finalLabels.limitedStock;
|
|
395
|
+
break;
|
|
396
|
+
case InventoryAvailabilityStatus.OUT_OF_STOCK:
|
|
397
|
+
default:
|
|
398
|
+
status = 'out-of-stock';
|
|
399
|
+
label = finalLabels.outOfStock;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.productStock, "data-state": status, customElement: children, customElementProps: {
|
|
403
|
+
status,
|
|
404
|
+
label,
|
|
405
|
+
}, content: label, children: _jsx("span", { children: label }) }));
|
|
406
|
+
} }));
|
|
407
|
+
});
|
|
290
408
|
/**
|
|
291
409
|
* Container for product variant selection system.
|
|
292
410
|
* Does not render when there are no variants.
|
|
@@ -183,3 +183,43 @@ export interface ProductSlugRenderProps {
|
|
|
183
183
|
* ```
|
|
184
184
|
*/
|
|
185
185
|
export declare function Slug(props: ProductSlugProps): import("react").ReactNode;
|
|
186
|
+
/**
|
|
187
|
+
* Props for ProductRibbon headless component
|
|
188
|
+
*/
|
|
189
|
+
export interface ProductRibbonProps {
|
|
190
|
+
/** Render prop function that receives product ribbon data */
|
|
191
|
+
children: (props: ProductRibbonRenderProps) => React.ReactNode;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Render props for ProductRibbon component
|
|
195
|
+
*/
|
|
196
|
+
export interface ProductRibbonRenderProps {
|
|
197
|
+
/** Product ribbon text */
|
|
198
|
+
ribbon: string | null;
|
|
199
|
+
/** Whether the product has a ribbon */
|
|
200
|
+
hasRibbon: boolean;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Headless component for product ribbon display
|
|
204
|
+
*
|
|
205
|
+
* @component
|
|
206
|
+
* @example
|
|
207
|
+
* ```tsx
|
|
208
|
+
* import { Product } from '@wix/stores/components';
|
|
209
|
+
*
|
|
210
|
+
* function ProductRibbonDisplay() {
|
|
211
|
+
* return (
|
|
212
|
+
* <Product.Ribbon>
|
|
213
|
+
* {({ ribbon, hasRibbon }) => (
|
|
214
|
+
* hasRibbon ? (
|
|
215
|
+
* <span className="ribbon-badge">
|
|
216
|
+
* {ribbon}
|
|
217
|
+
* </span>
|
|
218
|
+
* ) : null
|
|
219
|
+
* )}
|
|
220
|
+
* </Product.Ribbon>
|
|
221
|
+
* );
|
|
222
|
+
* }
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
export declare function Ribbon(props: ProductRibbonProps): import("react").ReactNode;
|
|
@@ -155,3 +155,36 @@ export function Slug(props) {
|
|
|
155
155
|
slug,
|
|
156
156
|
});
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Headless component for product ribbon display
|
|
160
|
+
*
|
|
161
|
+
* @component
|
|
162
|
+
* @example
|
|
163
|
+
* ```tsx
|
|
164
|
+
* import { Product } from '@wix/stores/components';
|
|
165
|
+
*
|
|
166
|
+
* function ProductRibbonDisplay() {
|
|
167
|
+
* return (
|
|
168
|
+
* <Product.Ribbon>
|
|
169
|
+
* {({ ribbon, hasRibbon }) => (
|
|
170
|
+
* hasRibbon ? (
|
|
171
|
+
* <span className="ribbon-badge">
|
|
172
|
+
* {ribbon}
|
|
173
|
+
* </span>
|
|
174
|
+
* ) : null
|
|
175
|
+
* )}
|
|
176
|
+
* </Product.Ribbon>
|
|
177
|
+
* );
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export function Ribbon(props) {
|
|
182
|
+
const service = useService(ProductServiceDefinition);
|
|
183
|
+
const product = service.product.get();
|
|
184
|
+
const ribbon = product.ribbon?.name || null;
|
|
185
|
+
const hasRibbon = !!ribbon;
|
|
186
|
+
return props.children({
|
|
187
|
+
ribbon,
|
|
188
|
+
hasRibbon,
|
|
189
|
+
});
|
|
190
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-stores",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.62",
|
|
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-components": "0.0.
|
|
65
|
+
"@wix/headless-components": "0.0.3",
|
|
66
66
|
"@wix/headless-ecom": "0.0.17",
|
|
67
67
|
"@wix/headless-media": "^0.0.11",
|
|
68
68
|
"@wix/headless-utils": "^0.0.2",
|