@anker-in/headless-ui 1.3.61 → 1.3.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/dist/cjs/biz-components/ActiveShelf/ProductCard.d.ts +9 -0
- package/dist/cjs/biz-components/ActiveShelf/ProductCard.js +1 -1
- package/dist/cjs/biz-components/ActiveShelf/ProductCard.js.map +3 -3
- package/dist/cjs/biz-components/ActiveShelf/index.d.ts +9 -0
- package/dist/cjs/biz-components/ActiveShelf/index.js +1 -1
- package/dist/cjs/biz-components/ActiveShelf/index.js.map +3 -3
- package/dist/cjs/biz-components/BuyOneGetOneShelf/PriceAndActions.d.ts +6 -0
- package/dist/cjs/biz-components/BuyOneGetOneShelf/PriceAndActions.js +1 -1
- package/dist/cjs/biz-components/BuyOneGetOneShelf/PriceAndActions.js.map +3 -3
- package/dist/cjs/biz-components/BuyOneGetOneShelf/ProductCard.d.ts +6 -0
- package/dist/cjs/biz-components/BuyOneGetOneShelf/ProductCard.js +1 -1
- package/dist/cjs/biz-components/BuyOneGetOneShelf/ProductCard.js.map +3 -3
- package/dist/cjs/biz-components/BuyOneGetOneShelf/types.d.ts +6 -0
- package/dist/cjs/biz-components/BuyOneGetOneShelf/types.js +1 -1
- package/dist/cjs/biz-components/BuyOneGetOneShelf/types.js.map +1 -1
- package/dist/cjs/biz-components/SceneShelfV3/ProductCard.d.ts +9 -0
- package/dist/cjs/biz-components/SceneShelfV3/ProductCard.js +1 -1
- package/dist/cjs/biz-components/SceneShelfV3/ProductCard.js.map +3 -3
- package/dist/cjs/biz-components/SceneShelfV3/index.d.ts +9 -0
- package/dist/cjs/biz-components/SceneShelfV3/index.js +1 -1
- package/dist/cjs/biz-components/SceneShelfV3/index.js.map +3 -3
- package/dist/cjs/biz-components/ShelfDisplay/shelfDisplay.d.ts +32 -18
- package/dist/cjs/biz-components/ShelfDisplay/shelfDisplay.js +1 -1
- package/dist/cjs/biz-components/ShelfDisplay/shelfDisplay.js.map +1 -1
- package/dist/cjs/biz-components/ShelfDisplay/shelfDisplayItem.js +1 -1
- package/dist/cjs/biz-components/ShelfDisplay/shelfDisplayItem.js.map +2 -2
- package/dist/cjs/biz-components/ShelfDisplayHorizontal/shelfDisplayHorizontalItem.js +1 -1
- package/dist/cjs/biz-components/ShelfDisplayHorizontal/shelfDisplayHorizontalItem.js.map +2 -2
- package/dist/esm/biz-components/ActiveShelf/ProductCard.d.ts +9 -0
- package/dist/esm/biz-components/ActiveShelf/ProductCard.js +1 -1
- package/dist/esm/biz-components/ActiveShelf/ProductCard.js.map +3 -3
- package/dist/esm/biz-components/ActiveShelf/index.d.ts +9 -0
- package/dist/esm/biz-components/ActiveShelf/index.js +1 -1
- package/dist/esm/biz-components/ActiveShelf/index.js.map +3 -3
- package/dist/esm/biz-components/BuyOneGetOneShelf/PriceAndActions.d.ts +6 -0
- package/dist/esm/biz-components/BuyOneGetOneShelf/PriceAndActions.js +1 -1
- package/dist/esm/biz-components/BuyOneGetOneShelf/PriceAndActions.js.map +3 -3
- package/dist/esm/biz-components/BuyOneGetOneShelf/ProductCard.d.ts +6 -0
- package/dist/esm/biz-components/BuyOneGetOneShelf/ProductCard.js +1 -1
- package/dist/esm/biz-components/BuyOneGetOneShelf/ProductCard.js.map +3 -3
- package/dist/esm/biz-components/BuyOneGetOneShelf/types.d.ts +6 -0
- package/dist/esm/biz-components/BuyOneGetOneShelf/types.js.map +1 -1
- package/dist/esm/biz-components/SceneShelfV3/ProductCard.d.ts +9 -0
- package/dist/esm/biz-components/SceneShelfV3/ProductCard.js +1 -1
- package/dist/esm/biz-components/SceneShelfV3/ProductCard.js.map +3 -3
- package/dist/esm/biz-components/SceneShelfV3/index.d.ts +9 -0
- package/dist/esm/biz-components/SceneShelfV3/index.js +1 -1
- package/dist/esm/biz-components/SceneShelfV3/index.js.map +3 -3
- package/dist/esm/biz-components/ShelfDisplay/shelfDisplay.d.ts +32 -18
- package/dist/esm/biz-components/ShelfDisplay/shelfDisplay.js +1 -1
- package/dist/esm/biz-components/ShelfDisplay/shelfDisplay.js.map +1 -1
- package/dist/esm/biz-components/ShelfDisplay/shelfDisplayItem.js +1 -1
- package/dist/esm/biz-components/ShelfDisplay/shelfDisplayItem.js.map +2 -2
- package/dist/esm/biz-components/ShelfDisplayHorizontal/shelfDisplayHorizontalItem.js +1 -1
- package/dist/esm/biz-components/ShelfDisplayHorizontal/shelfDisplayHorizontalItem.js.map +2 -2
- package/package.json +1 -1
|
@@ -221,6 +221,12 @@ export interface BuyOneGetOneShelfCardProps extends Omit<React.HTMLAttributes<HT
|
|
|
221
221
|
onGiftSelectionChange?: (selectedGifts: FreeGift[], product: ProductCardData) => void;
|
|
222
222
|
/** 选中赠品SKU变化回调(受控组件) */
|
|
223
223
|
onSelectedGiftSkuChange?: (selectedSku: string | null) => void;
|
|
224
|
+
/**
|
|
225
|
+
* 原价区域渲染函数,用于在原价位置展示自定义内容(如 Save 金额文案)。
|
|
226
|
+
* 不传时使用默认的原价渲染(划线价)。
|
|
227
|
+
* @param originalPrice - 格式化后的原价文本
|
|
228
|
+
*/
|
|
229
|
+
renderOriginalPrice?: (originalPrice: string | undefined) => React.ReactNode;
|
|
224
230
|
}
|
|
225
231
|
export interface BuyOneGetOneShelfLegacyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
226
232
|
/** 业务数据 */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/BuyOneGetOneShelf/types.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport type { Theme } from '../../types/props'\n\n/**\n * \u514D\u8D39\u8D60\u54C1\u63A5\u53E3\n */\nexport interface FreeGift {\n /** \u8D60\u54C1ID */\n id: string\n /** \u8D60\u54C1\u56FE\u7247URL */\n image: string\n /** \u8D60\u54C1\u540D\u79F0 */\n name: string\n /** \u539F\u4EF7 */\n originalPrice: string\n /** \u73B0\u4EF7\uFF08\u901A\u5E38\u4E3AFree\uFF09 */\n currentPrice: string\n /** \u6570\u91CF */\n quantity: number\n /** \u53D8\u4F53ID */\n variantId: string\n /** SKU */\n sku: string\n /** \u53E5\u67C4 */\n handle: string\n /** \u8D60\u54C1tag */\n tag?: string\n}\n\n/**\n * \u5E26\u9009\u62E9\u72B6\u6001\u7684\u514D\u8D39\u8D60\u54C1\u63A5\u53E3\n */\nexport interface FreeGiftWithSelection extends FreeGift {\n /** \u662F\u5426\u5DF2\u9009\u4E2D */\n selected?: boolean\n}\n\n/**\n * \u4EA7\u54C1\u6807\u7B7E\u63A5\u53E3\n */\nexport interface ProductTag {\n /** \u6807\u7B7E\u6587\u672C */\n label: string\n /** \u6807\u7B7E\u6837\u5F0F\u53D8\u4F53 */\n variant: 'outline' | 'fill' | 'promotional'\n /** \u4FC3\u9500\u7C7B\u578B\uFF08\u4EC5\u5F53 variant \u4E3A 'promotional' \u65F6\u6709\u6548\uFF09 */\n promotionalType?: 'plus-member' | 'regular-member' | 'regular-discount' | 'time-limited-discount'\n}\n\n// Root \u7EC4\u4EF6\u76F8\u5173\u7684\u8BED\u4E49\u7C7B\u540D\nexport type BuyOneGetOneShelfRootSemanticName = 'root' | 'title' | 'description' | 'content' | 'viewMoreBtn'\n\n// ProductCard \u7EC4\u4EF6\u76F8\u5173\u7684\u8BED\u4E49\u7C7B\u540D\nexport type BuyOneGetOneShelfProductCardSemanticName =\n | 'productCard'\n | 'productCardImage'\n | 'productCardTitle'\n | 'productCardDescription'\n | 'productCardPriceLabel'\n | 'productCardPrice'\n | 'productCardOriginalPrice'\n | 'productCardGiftsContainer'\n | 'productCardBtnGroup'\n\n// \u5B8C\u6574\u7684\u8BED\u4E49\u7C7B\u540D\uFF08\u5411\u540E\u517C\u5BB9\uFF09\nexport type BuyOneGetOneShelfSemanticName = BuyOneGetOneShelfRootSemanticName | BuyOneGetOneShelfProductCardSemanticName\n\n/**\n * \u54CD\u5E94\u5F0F\u56FE\u7247\u63A5\u53E3\n */\nexport interface ResponsiveImage {\n id: number\n baseUrl?: string\n url: string\n thumbnailURL?: string\n filename?: string\n mimeType?: string\n width?: number\n height?: number\n}\n\n/**\n * \u54CD\u5E94\u5F0F\u56FE\u7247\u96C6\u5408\u63A5\u53E3\n */\nexport interface ResponsiveImages {\n laptop?: ResponsiveImage\n mobile?: ResponsiveImage\n tablet?: ResponsiveImage\n desktop?: ResponsiveImage\n lgDesktop?: ResponsiveImage\n}\n\n/**\n * \u4EA7\u54C1\u57FA\u7840\u6570\u636E\u63A5\u53E3\n */\nexport interface BaseProductData {\n sku: string\n name: string\n image: string\n value: string\n handle: string\n shopify_id: string\n}\n\nexport interface WithGiftData {\n /**\n * \u8D60\u54C1\n */\n gifts: FreeGift[]\n /**\n * \u8D60\u54C1\u7C7B\u578B 1-> \u8D60\u9001\u5176\u4E2D\u4E00\u4E2A\u8D60\u54C1\uFF0C 2 -> \u8D60\u9001\u6240\u6709\u8D60\u54C1\n */\n gift_type: 1 | 2\n}\n\n/**\n * \u7EAF\u4EA7\u54C1\u6570\u636E\u63A5\u53E3\uFF08\u4E0D\u5305\u542B\u8D60\u54C1\u4FE1\u606F\uFF09\n */\nexport interface PureProductData extends BaseProductData {\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u5F53\u524D\u4EF7\u683C */\n currentPrice?: string\n /** \u539F\u4EF7 */\n originalPrice?: string\n /** \u4EF7\u683C\u6807\u7B7E\u6587\u672C\uFF08\u5982 \"Plus Member Price\"\uFF09 */\n priceLabel?: string\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u6587\u672C */\n learnMoreText?: string\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u6587\u672C */\n shopNowText?: string\n /** \u8D60\u54C1\u6807\u7B7E\u6587\u672C */\n freeGiftLabel?: string\n /** \u4EA7\u54C1\u6807\u7B7E */\n tags?: ProductTag[]\n /** \u8D60\u54C1\u9009\u62E9\u6A21\u5F0F */\n giftSelectionMode?: 'single' | 'multiple'\n availableForSale: boolean\n}\n\nexport interface ProductData extends BaseProductData, WithGiftData {\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u5F53\u524D\u4EF7\u683C */\n currentPrice?: string\n /** \u539F\u4EF7 */\n originalPrice?: string\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u6587\u672C */\n learnMoreText?: string\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u6587\u672C */\n shopNowText?: string\n /** \u8D60\u54C1\u6807\u7B7E\u6587\u672C */\n freeGiftLabel?: string\n /** \u8D60\u54C1\u9009\u62E9\u6A21\u5F0F */\n giftSelectionMode?: 'single' | 'multiple'\n}\n\n// Alias for consistency with other components\nexport type ProductCardData = ProductData\n\n/**\n * \u6587\u6848\u914D\u7F6E\u63A5\u53E3\n */\nexport interface CopyConfig {\n shopNowText: string\n freeGiftLabel: string\n learnMoreText: string\n freeGiftHeading: string\n soldOutText?: string\n}\n\n/**\n * \u4E70\u8D60\u9879\u76EE\u63A5\u53E3\n */\nexport interface BogoItem {\n id: string\n data: ProductData[]\n images: ResponsiveImages\n shopNowFun: string\n shopNowText: string\n learnMoreText: string\n layout?: 'horizontal' | 'vertical'\n}\n\n/**\n * BuyOneGetOneShelf \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3 - \u65B0\u683C\u5F0F\n */\nexport interface BuyOneGetOneShelfData {\n copy: CopyConfig\n theme: string\n title: string\n subtitle: string\n bogoItems: BogoItem[]\n /** \u8D85\u8FC7\u6B64\u6570\u91CF\u7684\u5546\u54C1\u65F6\u663E\u793A\"View More/View Less\"\u6309\u94AE\uFF0C\u9ED8\u8BA4 4 */\n viewMoreThreshold?: number\n /** View More \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View More' */\n viewMoreText?: string\n /** View Less \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View Less' */\n viewLessText?: string\n}\n\n// Root \u7EC4\u4EF6 Props\uFF08\u65B0\u7684\u7EC4\u5408\u5F0F\u8BBE\u8BA1\uFF09\nexport interface BuyOneGetOneShelfProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u6807\u9898 */\n title?: string\n /** \u526F\u6807\u9898 */\n subtitle?: string\n theme?: Theme\n /** \u5B50\u7EC4\u4EF6 */\n children: React.ReactNode\n /** Root \u7EC4\u4EF6\u7684\u81EA\u5B9A\u4E49\u7C7B\u540D */\n classNames?: Partial<Record<BuyOneGetOneShelfRootSemanticName, string>>\n /** \u8D85\u8FC7\u6B64\u6570\u91CF\u7684\u5546\u54C1\u65F6\u663E\u793A\"View More/View Less\"\u6309\u94AE\uFF0C\u9ED8\u8BA4 4 */\n viewMoreThreshold?: number\n /** View More \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View More' */\n viewMoreText?: string\n /** View Less \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View Less' */\n viewLessText?: string\n}\n\n// \u5361\u7247\u7EC4\u4EF6Props - \u57FA\u4E8EProductCardProps\u4F46\u7B80\u5316\nexport interface BuyOneGetOneShelfCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick'> {\n /** \u4EA7\u54C1\u6570\u636E */\n productData: BaseProductData & {\n description?: string\n currentPrice?: string\n originalPrice?: string\n learnMoreText?: string\n shopNowText?: string\n freeGiftLabel?: string\n }\n /** \u8D60\u54C1\u5217\u8868 */\n gifts?: FreeGift[]\n /** \u8D60\u54C1\u7C7B\u578B 1-> \u8D60\u9001\u5176\u4E2D\u4E00\u4E2A\u8D60\u54C1\uFF0C 2 -> \u8D60\u9001\u6240\u6709\u8D60\u54C1 */\n giftType?: 1 | 2\n soldOutText?: string\n /** \u573A\u666F\u56FE\u7247 */\n sceneImages?: ResponsiveImages\n /** @deprecated Layout is now automatically inferred by Root based on children count. */\n layout?: 'horizontal' | 'vertical'\n /** ProductCard \u7EC4\u4EF6\u7684\u81EA\u5B9A\u4E49\u7C7B\u540D */\n classNames?: Partial<Record<BuyOneGetOneShelfProductCardSemanticName, string>>\n /** @deprecated Use `onProductImageClick` instead. */\n onProductClick?: (product: ProductCardData) => void\n /** \u4EA7\u54C1\u56FE\u7247\u70B9\u51FB\u56DE\u8C03 */\n onProductImageClick?: (product: ProductCardData) => void\n /** Learn More \u70B9\u51FB\u56DE\u8C03 */\n onLearnMore?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n /** Shop Now \u70B9\u51FB\u56DE\u8C03 */\n onShopNow?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n /** \u8D60\u54C1\u70B9\u51FB\u56DE\u8C03 */\n onGiftClick?: (gift: FreeGift, selectedGifts: FreeGift[]) => void\n /** \u8D60\u54C1\u9009\u62E9\u53D8\u5316\u56DE\u8C03 */\n onGiftSelectionChange?: (selectedGifts: FreeGift[], product: ProductCardData) => void\n /** \u9009\u4E2D\u8D60\u54C1SKU\u53D8\u5316\u56DE\u8C03\uFF08\u53D7\u63A7\u7EC4\u4EF6\uFF09 */\n onSelectedGiftSkuChange?: (selectedSku: string | null) => void\n}\n\n// \u4FDD\u6301\u5411\u540E\u517C\u5BB9\u7684\u4F20\u7EDFProps\nexport interface BuyOneGetOneShelfLegacyProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: BuyOneGetOneShelfData\n /** @deprecated Use `onProductImageClick` instead. */\n onProductClick?: (product: ProductCardData) => void\n /** \u4EA7\u54C1\u56FE\u7247\u70B9\u51FB\u56DE\u8C03 */\n onProductImageClick?: (product: ProductCardData) => void\n /** Learn More\u6309\u94AE\u70B9\u51FB\u4E8B\u4EF6 */\n onLearnMore?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n /** Shop Now\u6309\u94AE\u70B9\u51FB\u4E8B\u4EF6 */\n onShopNow?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n onAddToCart?: (product: ProductCardData) => void\n /** \u8D60\u54C1\u70B9\u51FB\u4E8B\u4EF6 */\n onGiftClick?: (gift: FreeGift, selectedGifts: FreeGift[]) => void\n /** \u8D60\u54C1\u9009\u62E9\u53D8\u5316\u4E8B\u4EF6 */\n onGiftSelectionChange?: (selectedGifts: FreeGift[], product: ProductCardData) => void\n classNames?: Partial<Record<BuyOneGetOneShelfSemanticName, string>>\n}\n"],
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport type { Theme } from '../../types/props'\n\n/**\n * \u514D\u8D39\u8D60\u54C1\u63A5\u53E3\n */\nexport interface FreeGift {\n /** \u8D60\u54C1ID */\n id: string\n /** \u8D60\u54C1\u56FE\u7247URL */\n image: string\n /** \u8D60\u54C1\u540D\u79F0 */\n name: string\n /** \u539F\u4EF7 */\n originalPrice: string\n /** \u73B0\u4EF7\uFF08\u901A\u5E38\u4E3AFree\uFF09 */\n currentPrice: string\n /** \u6570\u91CF */\n quantity: number\n /** \u53D8\u4F53ID */\n variantId: string\n /** SKU */\n sku: string\n /** \u53E5\u67C4 */\n handle: string\n /** \u8D60\u54C1tag */\n tag?: string\n}\n\n/**\n * \u5E26\u9009\u62E9\u72B6\u6001\u7684\u514D\u8D39\u8D60\u54C1\u63A5\u53E3\n */\nexport interface FreeGiftWithSelection extends FreeGift {\n /** \u662F\u5426\u5DF2\u9009\u4E2D */\n selected?: boolean\n}\n\n/**\n * \u4EA7\u54C1\u6807\u7B7E\u63A5\u53E3\n */\nexport interface ProductTag {\n /** \u6807\u7B7E\u6587\u672C */\n label: string\n /** \u6807\u7B7E\u6837\u5F0F\u53D8\u4F53 */\n variant: 'outline' | 'fill' | 'promotional'\n /** \u4FC3\u9500\u7C7B\u578B\uFF08\u4EC5\u5F53 variant \u4E3A 'promotional' \u65F6\u6709\u6548\uFF09 */\n promotionalType?: 'plus-member' | 'regular-member' | 'regular-discount' | 'time-limited-discount'\n}\n\n// Root \u7EC4\u4EF6\u76F8\u5173\u7684\u8BED\u4E49\u7C7B\u540D\nexport type BuyOneGetOneShelfRootSemanticName = 'root' | 'title' | 'description' | 'content' | 'viewMoreBtn'\n\n// ProductCard \u7EC4\u4EF6\u76F8\u5173\u7684\u8BED\u4E49\u7C7B\u540D\nexport type BuyOneGetOneShelfProductCardSemanticName =\n | 'productCard'\n | 'productCardImage'\n | 'productCardTitle'\n | 'productCardDescription'\n | 'productCardPriceLabel'\n | 'productCardPrice'\n | 'productCardOriginalPrice'\n | 'productCardGiftsContainer'\n | 'productCardBtnGroup'\n\n// \u5B8C\u6574\u7684\u8BED\u4E49\u7C7B\u540D\uFF08\u5411\u540E\u517C\u5BB9\uFF09\nexport type BuyOneGetOneShelfSemanticName = BuyOneGetOneShelfRootSemanticName | BuyOneGetOneShelfProductCardSemanticName\n\n/**\n * \u54CD\u5E94\u5F0F\u56FE\u7247\u63A5\u53E3\n */\nexport interface ResponsiveImage {\n id: number\n baseUrl?: string\n url: string\n thumbnailURL?: string\n filename?: string\n mimeType?: string\n width?: number\n height?: number\n}\n\n/**\n * \u54CD\u5E94\u5F0F\u56FE\u7247\u96C6\u5408\u63A5\u53E3\n */\nexport interface ResponsiveImages {\n laptop?: ResponsiveImage\n mobile?: ResponsiveImage\n tablet?: ResponsiveImage\n desktop?: ResponsiveImage\n lgDesktop?: ResponsiveImage\n}\n\n/**\n * \u4EA7\u54C1\u57FA\u7840\u6570\u636E\u63A5\u53E3\n */\nexport interface BaseProductData {\n sku: string\n name: string\n image: string\n value: string\n handle: string\n shopify_id: string\n}\n\nexport interface WithGiftData {\n /**\n * \u8D60\u54C1\n */\n gifts: FreeGift[]\n /**\n * \u8D60\u54C1\u7C7B\u578B 1-> \u8D60\u9001\u5176\u4E2D\u4E00\u4E2A\u8D60\u54C1\uFF0C 2 -> \u8D60\u9001\u6240\u6709\u8D60\u54C1\n */\n gift_type: 1 | 2\n}\n\n/**\n * \u7EAF\u4EA7\u54C1\u6570\u636E\u63A5\u53E3\uFF08\u4E0D\u5305\u542B\u8D60\u54C1\u4FE1\u606F\uFF09\n */\nexport interface PureProductData extends BaseProductData {\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u5F53\u524D\u4EF7\u683C */\n currentPrice?: string\n /** \u539F\u4EF7 */\n originalPrice?: string\n /** \u4EF7\u683C\u6807\u7B7E\u6587\u672C\uFF08\u5982 \"Plus Member Price\"\uFF09 */\n priceLabel?: string\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u6587\u672C */\n learnMoreText?: string\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u6587\u672C */\n shopNowText?: string\n /** \u8D60\u54C1\u6807\u7B7E\u6587\u672C */\n freeGiftLabel?: string\n /** \u4EA7\u54C1\u6807\u7B7E */\n tags?: ProductTag[]\n /** \u8D60\u54C1\u9009\u62E9\u6A21\u5F0F */\n giftSelectionMode?: 'single' | 'multiple'\n availableForSale: boolean\n}\n\nexport interface ProductData extends BaseProductData, WithGiftData {\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u5F53\u524D\u4EF7\u683C */\n currentPrice?: string\n /** \u539F\u4EF7 */\n originalPrice?: string\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u6587\u672C */\n learnMoreText?: string\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u6587\u672C */\n shopNowText?: string\n /** \u8D60\u54C1\u6807\u7B7E\u6587\u672C */\n freeGiftLabel?: string\n /** \u8D60\u54C1\u9009\u62E9\u6A21\u5F0F */\n giftSelectionMode?: 'single' | 'multiple'\n}\n\n// Alias for consistency with other components\nexport type ProductCardData = ProductData\n\n/**\n * \u6587\u6848\u914D\u7F6E\u63A5\u53E3\n */\nexport interface CopyConfig {\n shopNowText: string\n freeGiftLabel: string\n learnMoreText: string\n freeGiftHeading: string\n soldOutText?: string\n}\n\n/**\n * \u4E70\u8D60\u9879\u76EE\u63A5\u53E3\n */\nexport interface BogoItem {\n id: string\n data: ProductData[]\n images: ResponsiveImages\n shopNowFun: string\n shopNowText: string\n learnMoreText: string\n layout?: 'horizontal' | 'vertical'\n}\n\n/**\n * BuyOneGetOneShelf \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3 - \u65B0\u683C\u5F0F\n */\nexport interface BuyOneGetOneShelfData {\n copy: CopyConfig\n theme: string\n title: string\n subtitle: string\n bogoItems: BogoItem[]\n /** \u8D85\u8FC7\u6B64\u6570\u91CF\u7684\u5546\u54C1\u65F6\u663E\u793A\"View More/View Less\"\u6309\u94AE\uFF0C\u9ED8\u8BA4 4 */\n viewMoreThreshold?: number\n /** View More \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View More' */\n viewMoreText?: string\n /** View Less \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View Less' */\n viewLessText?: string\n}\n\n// Root \u7EC4\u4EF6 Props\uFF08\u65B0\u7684\u7EC4\u5408\u5F0F\u8BBE\u8BA1\uFF09\nexport interface BuyOneGetOneShelfProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u6807\u9898 */\n title?: string\n /** \u526F\u6807\u9898 */\n subtitle?: string\n theme?: Theme\n /** \u5B50\u7EC4\u4EF6 */\n children: React.ReactNode\n /** Root \u7EC4\u4EF6\u7684\u81EA\u5B9A\u4E49\u7C7B\u540D */\n classNames?: Partial<Record<BuyOneGetOneShelfRootSemanticName, string>>\n /** \u8D85\u8FC7\u6B64\u6570\u91CF\u7684\u5546\u54C1\u65F6\u663E\u793A\"View More/View Less\"\u6309\u94AE\uFF0C\u9ED8\u8BA4 4 */\n viewMoreThreshold?: number\n /** View More \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View More' */\n viewMoreText?: string\n /** View Less \u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'View Less' */\n viewLessText?: string\n}\n\n// \u5361\u7247\u7EC4\u4EF6Props - \u57FA\u4E8EProductCardProps\u4F46\u7B80\u5316\nexport interface BuyOneGetOneShelfCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick'> {\n /** \u4EA7\u54C1\u6570\u636E */\n productData: BaseProductData & {\n description?: string\n currentPrice?: string\n originalPrice?: string\n learnMoreText?: string\n shopNowText?: string\n freeGiftLabel?: string\n }\n /** \u8D60\u54C1\u5217\u8868 */\n gifts?: FreeGift[]\n /** \u8D60\u54C1\u7C7B\u578B 1-> \u8D60\u9001\u5176\u4E2D\u4E00\u4E2A\u8D60\u54C1\uFF0C 2 -> \u8D60\u9001\u6240\u6709\u8D60\u54C1 */\n giftType?: 1 | 2\n soldOutText?: string\n /** \u573A\u666F\u56FE\u7247 */\n sceneImages?: ResponsiveImages\n /** @deprecated Layout is now automatically inferred by Root based on children count. */\n layout?: 'horizontal' | 'vertical'\n /** ProductCard \u7EC4\u4EF6\u7684\u81EA\u5B9A\u4E49\u7C7B\u540D */\n classNames?: Partial<Record<BuyOneGetOneShelfProductCardSemanticName, string>>\n /** @deprecated Use `onProductImageClick` instead. */\n onProductClick?: (product: ProductCardData) => void\n /** \u4EA7\u54C1\u56FE\u7247\u70B9\u51FB\u56DE\u8C03 */\n onProductImageClick?: (product: ProductCardData) => void\n /** Learn More \u70B9\u51FB\u56DE\u8C03 */\n onLearnMore?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n /** Shop Now \u70B9\u51FB\u56DE\u8C03 */\n onShopNow?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n /** \u8D60\u54C1\u70B9\u51FB\u56DE\u8C03 */\n onGiftClick?: (gift: FreeGift, selectedGifts: FreeGift[]) => void\n /** \u8D60\u54C1\u9009\u62E9\u53D8\u5316\u56DE\u8C03 */\n onGiftSelectionChange?: (selectedGifts: FreeGift[], product: ProductCardData) => void\n /** \u9009\u4E2D\u8D60\u54C1SKU\u53D8\u5316\u56DE\u8C03\uFF08\u53D7\u63A7\u7EC4\u4EF6\uFF09 */\n onSelectedGiftSkuChange?: (selectedSku: string | null) => void\n /**\n * \u539F\u4EF7\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5728\u539F\u4EF7\u4F4D\u7F6E\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\uFF08\u5982 Save \u91D1\u989D\u6587\u6848\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u539F\u4EF7\u6E32\u67D3\uFF08\u5212\u7EBF\u4EF7\uFF09\u3002\n * @param originalPrice - \u683C\u5F0F\u5316\u540E\u7684\u539F\u4EF7\u6587\u672C\n */\n renderOriginalPrice?: (originalPrice: string | undefined) => React.ReactNode\n}\n\n// \u4FDD\u6301\u5411\u540E\u517C\u5BB9\u7684\u4F20\u7EDFProps\nexport interface BuyOneGetOneShelfLegacyProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: BuyOneGetOneShelfData\n /** @deprecated Use `onProductImageClick` instead. */\n onProductClick?: (product: ProductCardData) => void\n /** \u4EA7\u54C1\u56FE\u7247\u70B9\u51FB\u56DE\u8C03 */\n onProductImageClick?: (product: ProductCardData) => void\n /** Learn More\u6309\u94AE\u70B9\u51FB\u4E8B\u4EF6 */\n onLearnMore?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n /** Shop Now\u6309\u94AE\u70B9\u51FB\u4E8B\u4EF6 */\n onShopNow?: (product: ProductCardData, selectedGifts: FreeGift[]) => void\n onAddToCart?: (product: ProductCardData) => void\n /** \u8D60\u54C1\u70B9\u51FB\u4E8B\u4EF6 */\n onGiftClick?: (gift: FreeGift, selectedGifts: FreeGift[]) => void\n /** \u8D60\u54C1\u9009\u62E9\u53D8\u5316\u4E8B\u4EF6 */\n onGiftSelectionChange?: (selectedGifts: FreeGift[], product: ProductCardData) => void\n classNames?: Partial<Record<BuyOneGetOneShelfSemanticName, string>>\n}\n"],
|
|
5
5
|
"mappings": "AAAA,MAAuB",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -71,6 +71,15 @@ export interface ProductCardProps {
|
|
|
71
71
|
primaryButtonText?: string;
|
|
72
72
|
primaryButtonFun?: ButtonFunctionType;
|
|
73
73
|
showOriginalPrice?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* 原价区域渲染函数,用于在原价位置展示自定义内容(如 Save 金额文案)。
|
|
76
|
+
* 不传时使用默认的原价渲染(划线价)。
|
|
77
|
+
* @param product - 当前产品数据
|
|
78
|
+
* @param context - 渲染上下文(含 showOriginalPrice)
|
|
79
|
+
*/
|
|
80
|
+
renderOriginalPrice?: (product: ProductCardData, context: {
|
|
81
|
+
showOriginalPrice?: boolean;
|
|
82
|
+
}) => React.ReactNode;
|
|
74
83
|
copy?: CopyConfig;
|
|
75
84
|
onProductImageClick?: (product: ProductCardData) => void;
|
|
76
85
|
/** 主题 */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{Fragment as
|
|
1
|
+
"use client";import{Fragment as Q,jsx as t,jsxs as l}from"react/jsx-runtime";import*as n from"react";import{cn as a,getLocalizedPath as F}from"../../helpers/index.js";import{Button as N,Badge as V,Card as q,CardContent as K,Picture as W,Text as T,Heading as p}from"../../components/index.js";import{trackUrlRef as I}from"../../shared/trackUrlRef.js";import{gaTrack as u}from"../../shared/track.js";import{useAiuiContext as J}from"../AiuiProvider/index.js";const B=n.forwardRef(({product:e,className:L,showTags:z=!0,onLearnMore:f,onShopNow:y,onAddToCart:v,classNames:o,secondaryButtonText:c,secondaryButtonFun:b,primaryButtonText:m,primaryButtonFun:x,showOriginalPrice:_,renderOriginalPrice:h,copy:D,onProductImageClick:d,theme:M="light",locale:P="us",index:s=0,tabName:k},H)=>{const[O,j]=n.useState(!1),[R,A]=n.useState(!1),{trackingData:G}=J(),r=G?.pageGroup,w=!e.soldOut,C=n.useCallback(async(i,g)=>{if(!i)return;const S=g==="primary"?j:A;S(!0);try{switch(i){case"buyNow":await y?.(e);break;case"addCart":await v?.(e);break;case"learnMore":await f?.(e.href);break}}finally{S(!1)}},[e,y,v,f]),U=n.useMemo(()=>F(I(e.href,r+"_shelf_scene_shelf_v3"),P),[e.href,r,P]),E=n.useCallback(()=>{d?.(e),u({event:"ga4Event",event_name:"select_item",item_list_name:"Scene_Shelf_3_Products",page_group:r,items:[{item_id:e.sku,item_name:e.title,item_variant:e.id,price:e.currentPrice,index:s}],tab_name:k,position:s})},[d,e,r,s,k]);return t(q,{ref:H,className:a("bg-container-primary flex h-full flex-col overflow-hidden border-none hover:bg-white",L,o?.productCard,{"hover:bg-container-secondary-0 ":M==="dark"}),children:l(K,{className:"desktop:p-6 relative flex flex-1 flex-col justify-between p-4",children:[t("div",{className:"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden",children:t("a",{onClick:E,...!d&&{href:U},rel:"noreferrer",children:t(W,{source:e.imageUrl,alt:e.imageAlt,className:"aspect-square size-full object-contain",imgClassName:"w-full h-full object-contain"})})}),t("div",{className:"lg-desktop:h-[28px] mb-1 flex h-[24px] gap-1",children:z&&e.tags?.map((i,g)=>t(V,{size:"sm",variant:i.variant||"outline",className:a(i.variant==="promotional"?"ml-2":""),promotionalType:i.promotionalType,children:i.label},g))}),l("div",{className:"flex h-full flex-1 grow flex-col justify-between",children:[l("div",{className:"mb-4",children:[t(p,{as:"h3",size:2,className:a("text-info-primary laptop:line-clamp-2 mb-2 line-clamp-3 min-h-[2.4em]",o?.productTitle),html:e.custom_name||e.title}),(e?.custom_description||e?.description)&&t(T,{size:2,className:a("text-info-secondary desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1 text-[14px]",o?.productDescription),html:e.custom_description||e.description})]}),l("div",{children:[t("div",{className:a("mb-2",o?.productPrice),children:t("div",{className:a("flex items-baseline gap-2",o?.priceWrapper),children:w?l(Q,{children:[t(p,{size:2,className:"text-info-primary",as:"h6",children:e.currentPrice}),h?h(e,{showOriginalPrice:_}):_&&e.originalPrice&&t(p,{size:2,className:a("text-info-tertiary line-through",o?.originalPrice),as:"h6",children:e.originalPrice})]}):t(p,{size:2,className:"text-info-tertiary",children:D?.outOfStockLabel??"Sold Out"})})}),e?.priceLabel&&w&&t(T,{size:4,className:a("text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]",o?.productPriceLabel),children:e.priceLabel}),l("div",{className:a("lg-desktop:gap-3 laptop:flex-row laptop:flex-nowrap flex flex-col flex-wrap gap-2",o?.buttonGroup),children:[c&&t(N,{variant:"secondary",size:"base",className:a("laptop:flex-1 laptop:min-w-0 laptop:whitespace-normal laptop:text-center w-full min-w-0 whitespace-normal text-center",o?.secondaryButton),onClick:()=>{C(b,"secondary"),u({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:r||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.custom_name||e.title,component_description:e.custom_description||"",button_name:c,SKU:e.sku||"",position:s}})},disabled:e.soldOut&&b!=="learnMore",loading:R,children:c}),m&&t(N,{variant:"primary",size:"base",className:a("laptop:flex-1 laptop:min-w-0 laptop:whitespace-normal laptop:text-center w-full min-w-0 whitespace-normal text-center",o?.primaryButton),onClick:()=>{C(x,"primary"),u({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:r||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.custom_name||e.title,component_description:e.custom_description||"",button_name:m,SKU:e.sku||"",position:s}})},disabled:e.soldOut&&x!=="learnMore",loading:O,children:m})]})]})]})]})})});B.displayName="SceneShelfV3.ProductCard";var te=B;export{B as ProductCard,te as default};
|
|
2
2
|
//# sourceMappingURL=ProductCard.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/SceneShelfV3/ProductCard.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn, getLocalizedPath } from '../../helpers/index.js'\nimport { Button, Badge, Card, CardContent, Picture, Text, Heading } from '../../components/index.js'\nimport type { BadgeProps } from '../../components/badge.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport type { ButtonFunctionType, CopyConfig } from './types.js'\nimport type { Theme } from '../../types/props.js'\nimport { gaTrack } from '../../shared/track.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\n\n/**\n * \u8BED\u4E49\u5316\u7C7B\u540D\n */\nexport type SceneShelfV3SemanticName =\n | 'root'\n | 'title'\n | 'description'\n | 'tabsList'\n | 'promotionalBar'\n | 'productGrid'\n | 'viewMore'\n | 'productCard'\n | 'productTitle'\n | 'productDescription'\n | 'productPriceLabel'\n | 'productPrice'\n | 'priceWrapper'\n | 'originalPrice'\n | 'buttonGroup'\n | 'secondaryButton'\n | 'primaryButton'\n\n/**\n * \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\n */\nexport type StockDisplayMode = 'always' | 'never' | 'below-quantity' | 'below-percentage'\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u6570\u636E\u63A5\u53E3\uFF08\u76F4\u63A5\u5339\u914D mock.json \u7ED3\u6784\uFF09\n */\nexport interface ProductCardData {\n sku?: string\n id: string\n /** \u4EA7\u54C1\u6807\u9898 */\n title: string\n /**\n * \u4EA7\u54C1\u63CF\u8FF0\n */\n description?: string\n /** \u4EA7\u54C1\u56FE\u7247 URL */\n imageUrl: string\n /** \u4EA7\u54C1\u56FE\u7247 alt \u6587\u672C */\n imageAlt: string\n /** \u5F53\u524D\u4EF7\u683C */\n currentPrice: string\n /** \u539F\u4EF7\uFF08\u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u5982 \"$129.99\"\uFF0C\u7528\u4E8E\u663E\u793A\u5220\u9664\u7EBF\u4EF7\u683C\uFF09 */\n originalPrice?: string\n /** \u6807\u7B7E\u5217\u8868 */\n tags: Array<{\n label: string\n variant?: 'outline' | 'fill' | 'promotional'\n promotionalType?: BadgeProps['promotionalType']\n }>\n /** \u4EA7\u54C1\u8BE6\u60C5\u9875\u94FE\u63A5 */\n href: string\n /** \u662F\u5426\u552E\u7F44 */\n soldOut: boolean\n\n // ===== \u53EF\u9009\u5B57\u6BB5\uFF08CMS \u53EF\u80FD\u914D\u7F6E\uFF09 =====\n /** \u81EA\u5B9A\u4E49\u4EA7\u54C1\u540D\u79F0 */\n custom_name?: string\n /** \u81EA\u5B9A\u4E49\u4EA7\u54C1\u63CF\u8FF0 */\n custom_description?: string\n /** \u4EF7\u683C\u6807\u7B7E\uFF08\u5982 \"Member Price\"\uFF09 */\n priceLabel?: string\n /** \u5E93\u5B58\u4FE1\u606F\uFF08\u5982\u679C\u540E\u7AEF\u63D0\u4F9B\uFF09 */\n totalInventory?: number\n quantityAvailable?: number\n}\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6 Props\n */\nexport interface ProductCardProps {\n product: ProductCardData\n className?: string\n showTags?: boolean\n stockDisplayMode?: StockDisplayMode\n stockThresholdValue?: number\n /** \u70B9\u51FB\u4E86\u89E3\u66F4\u591A\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onLearnMore?: (link: string) => void | Promise<void>\n /** \u70B9\u51FB\u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onShopNow?: (product: ProductCardData) => void | Promise<void>\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onAddToCart?: (product: ProductCardData) => void | Promise<void>\n classNames?: Partial<Record<SceneShelfV3SemanticName, string>>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n showOriginalPrice?: boolean\n copy?: CopyConfig\n onProductImageClick?: (product: ProductCardData) => void\n /** \u4E3B\u9898 */\n theme?: Theme\n /** \u8BED\u8A00\u73AF\u5883 */\n locale?: string\n /** \u5F53\u524D\u4E0B\u6807 */\n index?: number\n /** tabName */\n tabName?: string\n}\n\n/**\n * SceneShelfV3 \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6\n */\nexport const ProductCard = React.forwardRef<HTMLDivElement, ProductCardProps>(\n (\n {\n product,\n className,\n showTags = true,\n onLearnMore,\n onShopNow,\n onAddToCart,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n copy,\n onProductImageClick,\n theme = 'light',\n locale = 'us',\n index = 0,\n tabName,\n },\n ref\n ) => {\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n const { trackingData } = useAiuiContext()\n\n const pageGroup = trackingData?.pageGroup\n\n const availableForSale = !product.soldOut\n\n const handleButtonClick = React.useCallback(\n async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n const setLoading = buttonType === 'primary' ? setPrimaryLoading : setSecondaryLoading\n setLoading(true)\n try {\n switch (buttonFun) {\n case 'buyNow':\n await onShopNow?.(product)\n break\n case 'addCart':\n await onAddToCart?.(product)\n break\n case 'learnMore':\n await onLearnMore?.(product.href)\n break\n }\n } finally {\n setLoading(false)\n }\n },\n [product, onShopNow, onAddToCart, onLearnMore]\n )\n\n const trackedHref = React.useMemo(\n () => getLocalizedPath(trackUrlRef(product.href, pageGroup + '_' + 'shelf' + '_' + 'scene_shelf_v3'), locale),\n [product.href, pageGroup, locale]\n )\n\n const onProductClick = React.useCallback(() => {\n onProductImageClick?.(product)\n gaTrack({\n event: 'ga4Event',\n event_name: 'select_item',\n item_list_name: 'Scene_Shelf_3_Products',\n page_group: pageGroup,\n items: [\n {\n item_id: product.sku,\n item_name: product.title,\n item_variant: product.id,\n price: product.currentPrice,\n index: index,\n },\n ],\n tab_name: tabName,\n position: index,\n })\n }, [onProductImageClick, product, pageGroup, index, tabName])\n\n return (\n <Card\n ref={ref}\n className={cn(\n 'bg-container-primary flex h-full flex-col overflow-hidden border-none hover:bg-white',\n className,\n classNames?.productCard,\n {\n 'hover:bg-container-secondary-0 ': theme === 'dark',\n }\n )}\n >\n <CardContent className=\"desktop:p-6 relative flex flex-1 flex-col justify-between p-4\">\n <div className=\"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden\">\n <a\n onClick={onProductClick}\n {...(!onProductImageClick && {\n href: trackedHref,\n })}\n rel=\"noreferrer\"\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"aspect-square size-full object-contain\"\n imgClassName=\"w-full h-full object-contain\"\n />\n </a>\n </div>\n\n {/* \u6807\u7B7E */}\n <div className=\"lg-desktop:h-[28px] mb-1 flex h-[24px] gap-1\">\n {showTags &&\n product.tags?.map((tag, index) => (\n <Badge\n key={index}\n size=\"sm\"\n variant={tag.variant || 'outline'}\n className={cn(tag.variant === 'promotional' ? 'ml-2' : '')}\n promotionalType={tag.promotionalType}\n >\n {tag.label}\n </Badge>\n ))}\n </div>\n\n {/* \u5185\u5BB9\u533A\u57DF */}\n <div className=\"flex h-full flex-1 grow flex-col justify-between\">\n <div className=\"mb-4\">\n <Heading\n as=\"h3\"\n size={2}\n className={cn(\n 'text-info-primary laptop:line-clamp-2 mb-2 line-clamp-3 min-h-[2.4em]',\n classNames?.productTitle\n )}\n html={product.custom_name || product.title}\n />\n {(product?.custom_description || product?.description) && (\n <Text\n size={2}\n className={cn(\n 'text-info-secondary desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1 text-[14px]',\n classNames?.productDescription\n )}\n html={product.custom_description || product.description}\n />\n )}\n </div>\n\n {/* \u4EF7\u683C\u533A\u57DF */}\n <div>\n <div className={cn('mb-2', classNames?.productPrice)}>\n <div className={cn('flex items-baseline gap-2', classNames?.priceWrapper)}>\n {availableForSale ? (\n <>\n <Heading size={2} className=\"text-info-primary\" as=\"h6\">\n {product.currentPrice}\n </Heading>\n {showOriginalPrice && product.originalPrice && (\n <Heading\n size={2}\n className={cn('text-info-tertiary line-through', classNames?.originalPrice)}\n as=\"h6\"\n >\n {product.originalPrice}\n </Heading>\n )}\n </>\n ) : (\n <Heading size={2} className=\"text-info-tertiary\">\n {copy?.outOfStockLabel ?? 'Sold Out'}\n </Heading>\n )}\n </div>\n </div>\n\n {product?.priceLabel && availableForSale && (\n <Text\n size={4}\n className={cn(\n 'text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]',\n classNames?.productPriceLabel\n )}\n >\n {product.priceLabel}\n </Text>\n )}\n\n {/* \u6309\u94AE\u533A\u57DF */}\n <div\n className={cn(\n 'lg-desktop:gap-3 laptop:flex-row laptop:flex-nowrap flex flex-col flex-wrap gap-2',\n classNames?.buttonGroup\n )}\n >\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n size=\"base\"\n className={cn(\n 'laptop:flex-1 laptop:min-w-0 laptop:whitespace-normal laptop:text-center w-full min-w-0 whitespace-normal text-center',\n classNames?.secondaryButton\n )}\n onClick={() => {\n handleButtonClick(secondaryButtonFun, 'secondary')\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: pageGroup || 'Home Page',\n component_type: 'copy',\n component_name: 'scene_shelf_product',\n component_title: product.custom_name || product.title,\n component_description: product.custom_description || '',\n button_name: secondaryButtonText,\n SKU: product.sku || '',\n position: index,\n },\n })\n }}\n disabled={product.soldOut && secondaryButtonFun !== 'learnMore'}\n loading={secondaryLoading}\n >\n {secondaryButtonText}\n </Button>\n )}\n {primaryButtonText && (\n <Button\n variant=\"primary\"\n size=\"base\"\n className={cn(\n 'laptop:flex-1 laptop:min-w-0 laptop:whitespace-normal laptop:text-center w-full min-w-0 whitespace-normal text-center',\n classNames?.primaryButton\n )}\n onClick={() => {\n handleButtonClick(primaryButtonFun, 'primary')\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: pageGroup || 'Home Page',\n component_type: 'copy',\n component_name: 'scene_shelf_product',\n component_title: product.custom_name || product.title,\n component_description: product.custom_description || '',\n button_name: primaryButtonText,\n SKU: product.sku || '',\n position: index,\n },\n })\n }}\n disabled={product.soldOut && primaryButtonFun !== 'learnMore'}\n loading={primaryLoading}\n >\n {primaryButtonText}\n </Button>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n }\n)\n\nProductCard.displayName = 'SceneShelfV3.ProductCard'\n\nexport default ProductCard\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["Fragment", "jsx", "jsxs", "React", "cn", "getLocalizedPath", "Button", "Badge", "Card", "CardContent", "Picture", "Text", "Heading", "trackUrlRef", "gaTrack", "useAiuiContext", "ProductCard", "product", "className", "showTags", "onLearnMore", "onShopNow", "onAddToCart", "classNames", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "showOriginalPrice", "copy", "onProductImageClick", "theme", "locale", "index", "tabName", "ref", "primaryLoading", "setPrimaryLoading", "secondaryLoading", "setSecondaryLoading", "trackingData", "pageGroup", "availableForSale", "handleButtonClick", "buttonFun", "buttonType", "setLoading", "trackedHref", "onProductClick", "tag", "ProductCard_default"]
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn, getLocalizedPath } from '../../helpers/index.js'\nimport { Button, Badge, Card, CardContent, Picture, Text, Heading } from '../../components/index.js'\nimport type { BadgeProps } from '../../components/badge.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport type { ButtonFunctionType, CopyConfig } from './types.js'\nimport type { Theme } from '../../types/props.js'\nimport { gaTrack } from '../../shared/track.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\n\n/**\n * \u8BED\u4E49\u5316\u7C7B\u540D\n */\nexport type SceneShelfV3SemanticName =\n | 'root'\n | 'title'\n | 'description'\n | 'tabsList'\n | 'promotionalBar'\n | 'productGrid'\n | 'viewMore'\n | 'productCard'\n | 'productTitle'\n | 'productDescription'\n | 'productPriceLabel'\n | 'productPrice'\n | 'priceWrapper'\n | 'originalPrice'\n | 'buttonGroup'\n | 'secondaryButton'\n | 'primaryButton'\n\n/**\n * \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\n */\nexport type StockDisplayMode = 'always' | 'never' | 'below-quantity' | 'below-percentage'\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u6570\u636E\u63A5\u53E3\uFF08\u76F4\u63A5\u5339\u914D mock.json \u7ED3\u6784\uFF09\n */\nexport interface ProductCardData {\n sku?: string\n id: string\n /** \u4EA7\u54C1\u6807\u9898 */\n title: string\n /**\n * \u4EA7\u54C1\u63CF\u8FF0\n */\n description?: string\n /** \u4EA7\u54C1\u56FE\u7247 URL */\n imageUrl: string\n /** \u4EA7\u54C1\u56FE\u7247 alt \u6587\u672C */\n imageAlt: string\n /** \u5F53\u524D\u4EF7\u683C */\n currentPrice: string\n /** \u539F\u4EF7\uFF08\u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u5982 \"$129.99\"\uFF0C\u7528\u4E8E\u663E\u793A\u5220\u9664\u7EBF\u4EF7\u683C\uFF09 */\n originalPrice?: string\n /** \u6807\u7B7E\u5217\u8868 */\n tags: Array<{\n label: string\n variant?: 'outline' | 'fill' | 'promotional'\n promotionalType?: BadgeProps['promotionalType']\n }>\n /** \u4EA7\u54C1\u8BE6\u60C5\u9875\u94FE\u63A5 */\n href: string\n /** \u662F\u5426\u552E\u7F44 */\n soldOut: boolean\n\n // ===== \u53EF\u9009\u5B57\u6BB5\uFF08CMS \u53EF\u80FD\u914D\u7F6E\uFF09 =====\n /** \u81EA\u5B9A\u4E49\u4EA7\u54C1\u540D\u79F0 */\n custom_name?: string\n /** \u81EA\u5B9A\u4E49\u4EA7\u54C1\u63CF\u8FF0 */\n custom_description?: string\n /** \u4EF7\u683C\u6807\u7B7E\uFF08\u5982 \"Member Price\"\uFF09 */\n priceLabel?: string\n /** \u5E93\u5B58\u4FE1\u606F\uFF08\u5982\u679C\u540E\u7AEF\u63D0\u4F9B\uFF09 */\n totalInventory?: number\n quantityAvailable?: number\n}\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6 Props\n */\nexport interface ProductCardProps {\n product: ProductCardData\n className?: string\n showTags?: boolean\n stockDisplayMode?: StockDisplayMode\n stockThresholdValue?: number\n /** \u70B9\u51FB\u4E86\u89E3\u66F4\u591A\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onLearnMore?: (link: string) => void | Promise<void>\n /** \u70B9\u51FB\u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onShopNow?: (product: ProductCardData) => void | Promise<void>\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onAddToCart?: (product: ProductCardData) => void | Promise<void>\n classNames?: Partial<Record<SceneShelfV3SemanticName, string>>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n showOriginalPrice?: boolean\n /**\n * \u539F\u4EF7\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5728\u539F\u4EF7\u4F4D\u7F6E\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\uFF08\u5982 Save \u91D1\u989D\u6587\u6848\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u539F\u4EF7\u6E32\u67D3\uFF08\u5212\u7EBF\u4EF7\uFF09\u3002\n * @param product - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param context - \u6E32\u67D3\u4E0A\u4E0B\u6587\uFF08\u542B showOriginalPrice\uFF09\n */\n renderOriginalPrice?: (product: ProductCardData, context: { showOriginalPrice?: boolean }) => React.ReactNode\n copy?: CopyConfig\n onProductImageClick?: (product: ProductCardData) => void\n /** \u4E3B\u9898 */\n theme?: Theme\n /** \u8BED\u8A00\u73AF\u5883 */\n locale?: string\n /** \u5F53\u524D\u4E0B\u6807 */\n index?: number\n /** tabName */\n tabName?: string\n}\n\n/**\n * SceneShelfV3 \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6\n */\nexport const ProductCard = React.forwardRef<HTMLDivElement, ProductCardProps>(\n (\n {\n product,\n className,\n showTags = true,\n onLearnMore,\n onShopNow,\n onAddToCart,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n renderOriginalPrice,\n copy,\n onProductImageClick,\n theme = 'light',\n locale = 'us',\n index = 0,\n tabName,\n },\n ref\n ) => {\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n const { trackingData } = useAiuiContext()\n\n const pageGroup = trackingData?.pageGroup\n\n const availableForSale = !product.soldOut\n\n const handleButtonClick = React.useCallback(\n async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n const setLoading = buttonType === 'primary' ? setPrimaryLoading : setSecondaryLoading\n setLoading(true)\n try {\n switch (buttonFun) {\n case 'buyNow':\n await onShopNow?.(product)\n break\n case 'addCart':\n await onAddToCart?.(product)\n break\n case 'learnMore':\n await onLearnMore?.(product.href)\n break\n }\n } finally {\n setLoading(false)\n }\n },\n [product, onShopNow, onAddToCart, onLearnMore]\n )\n\n const trackedHref = React.useMemo(\n () => getLocalizedPath(trackUrlRef(product.href, pageGroup + '_' + 'shelf' + '_' + 'scene_shelf_v3'), locale),\n [product.href, pageGroup, locale]\n )\n\n const onProductClick = React.useCallback(() => {\n onProductImageClick?.(product)\n gaTrack({\n event: 'ga4Event',\n event_name: 'select_item',\n item_list_name: 'Scene_Shelf_3_Products',\n page_group: pageGroup,\n items: [\n {\n item_id: product.sku,\n item_name: product.title,\n item_variant: product.id,\n price: product.currentPrice,\n index: index,\n },\n ],\n tab_name: tabName,\n position: index,\n })\n }, [onProductImageClick, product, pageGroup, index, tabName])\n\n return (\n <Card\n ref={ref}\n className={cn(\n 'bg-container-primary flex h-full flex-col overflow-hidden border-none hover:bg-white',\n className,\n classNames?.productCard,\n {\n 'hover:bg-container-secondary-0 ': theme === 'dark',\n }\n )}\n >\n <CardContent className=\"desktop:p-6 relative flex flex-1 flex-col justify-between p-4\">\n <div className=\"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden\">\n <a\n onClick={onProductClick}\n {...(!onProductImageClick && {\n href: trackedHref,\n })}\n rel=\"noreferrer\"\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"aspect-square size-full object-contain\"\n imgClassName=\"w-full h-full object-contain\"\n />\n </a>\n </div>\n\n {/* \u6807\u7B7E */}\n <div className=\"lg-desktop:h-[28px] mb-1 flex h-[24px] gap-1\">\n {showTags &&\n product.tags?.map((tag, index) => (\n <Badge\n key={index}\n size=\"sm\"\n variant={tag.variant || 'outline'}\n className={cn(tag.variant === 'promotional' ? 'ml-2' : '')}\n promotionalType={tag.promotionalType}\n >\n {tag.label}\n </Badge>\n ))}\n </div>\n\n {/* \u5185\u5BB9\u533A\u57DF */}\n <div className=\"flex h-full flex-1 grow flex-col justify-between\">\n <div className=\"mb-4\">\n <Heading\n as=\"h3\"\n size={2}\n className={cn(\n 'text-info-primary laptop:line-clamp-2 mb-2 line-clamp-3 min-h-[2.4em]',\n classNames?.productTitle\n )}\n html={product.custom_name || product.title}\n />\n {(product?.custom_description || product?.description) && (\n <Text\n size={2}\n className={cn(\n 'text-info-secondary desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1 text-[14px]',\n classNames?.productDescription\n )}\n html={product.custom_description || product.description}\n />\n )}\n </div>\n\n {/* \u4EF7\u683C\u533A\u57DF */}\n <div>\n <div className={cn('mb-2', classNames?.productPrice)}>\n <div className={cn('flex items-baseline gap-2', classNames?.priceWrapper)}>\n {availableForSale ? (\n <>\n <Heading size={2} className=\"text-info-primary\" as=\"h6\">\n {product.currentPrice}\n </Heading>\n {renderOriginalPrice\n ? renderOriginalPrice(product, { showOriginalPrice })\n : showOriginalPrice &&\n product.originalPrice && (\n <Heading\n size={2}\n className={cn('text-info-tertiary line-through', classNames?.originalPrice)}\n as=\"h6\"\n >\n {product.originalPrice}\n </Heading>\n )}\n </>\n ) : (\n <Heading size={2} className=\"text-info-tertiary\">\n {copy?.outOfStockLabel ?? 'Sold Out'}\n </Heading>\n )}\n </div>\n </div>\n\n {product?.priceLabel && availableForSale && (\n <Text\n size={4}\n className={cn(\n 'text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]',\n classNames?.productPriceLabel\n )}\n >\n {product.priceLabel}\n </Text>\n )}\n\n {/* \u6309\u94AE\u533A\u57DF */}\n <div\n className={cn(\n 'lg-desktop:gap-3 laptop:flex-row laptop:flex-nowrap flex flex-col flex-wrap gap-2',\n classNames?.buttonGroup\n )}\n >\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n size=\"base\"\n className={cn(\n 'laptop:flex-1 laptop:min-w-0 laptop:whitespace-normal laptop:text-center w-full min-w-0 whitespace-normal text-center',\n classNames?.secondaryButton\n )}\n onClick={() => {\n handleButtonClick(secondaryButtonFun, 'secondary')\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: pageGroup || 'Home Page',\n component_type: 'copy',\n component_name: 'scene_shelf_product',\n component_title: product.custom_name || product.title,\n component_description: product.custom_description || '',\n button_name: secondaryButtonText,\n SKU: product.sku || '',\n position: index,\n },\n })\n }}\n disabled={product.soldOut && secondaryButtonFun !== 'learnMore'}\n loading={secondaryLoading}\n >\n {secondaryButtonText}\n </Button>\n )}\n {primaryButtonText && (\n <Button\n variant=\"primary\"\n size=\"base\"\n className={cn(\n 'laptop:flex-1 laptop:min-w-0 laptop:whitespace-normal laptop:text-center w-full min-w-0 whitespace-normal text-center',\n classNames?.primaryButton\n )}\n onClick={() => {\n handleButtonClick(primaryButtonFun, 'primary')\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: pageGroup || 'Home Page',\n component_type: 'copy',\n component_name: 'scene_shelf_product',\n component_title: product.custom_name || product.title,\n component_description: product.custom_description || '',\n button_name: primaryButtonText,\n SKU: product.sku || '',\n position: index,\n },\n })\n }}\n disabled={product.soldOut && primaryButtonFun !== 'learnMore'}\n loading={primaryLoading}\n >\n {primaryButtonText}\n </Button>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n }\n)\n\nProductCard.displayName = 'SceneShelfV3.ProductCard'\n\nexport default ProductCard\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Fragment", "jsx", "jsxs", "React", "cn", "getLocalizedPath", "Button", "Badge", "Card", "CardContent", "Picture", "Text", "Heading", "trackUrlRef", "gaTrack", "useAiuiContext", "ProductCard", "product", "className", "showTags", "onLearnMore", "onShopNow", "onAddToCart", "classNames", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "showOriginalPrice", "renderOriginalPrice", "copy", "onProductImageClick", "theme", "locale", "index", "tabName", "ref", "primaryLoading", "setPrimaryLoading", "secondaryLoading", "setSecondaryLoading", "trackingData", "pageGroup", "availableForSale", "handleButtonClick", "buttonFun", "buttonType", "setLoading", "trackedHref", "onProductClick", "tag", "ProductCard_default"]
|
|
7
7
|
}
|
|
@@ -69,6 +69,15 @@ export interface SceneShelfV3Props extends React.HTMLAttributes<HTMLDivElement>
|
|
|
69
69
|
onProductImageClick?: (product: ProductCardData) => void;
|
|
70
70
|
/** 语义化类名 */
|
|
71
71
|
classNames?: Partial<Record<SceneShelfV3SemanticName, string>>;
|
|
72
|
+
/**
|
|
73
|
+
* 原价区域渲染函数,用于在原价位置展示自定义内容(如 Save 金额文案)。
|
|
74
|
+
* 不传时使用默认的原价渲染(划线价)。
|
|
75
|
+
* @param product - 当前产品数据
|
|
76
|
+
* @param context - 渲染上下文(含 showOriginalPrice)
|
|
77
|
+
*/
|
|
78
|
+
renderOriginalPrice?: (product: ProductCardData, context: {
|
|
79
|
+
showOriginalPrice?: boolean;
|
|
80
|
+
}) => React.ReactNode;
|
|
72
81
|
}
|
|
73
82
|
export interface SceneShelfV3Component extends React.ForwardRefExoticComponent<SceneShelfV3Props & React.RefAttributes<HTMLDivElement>> {
|
|
74
83
|
ProductCard: typeof ProductCard;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{Fragment as
|
|
1
|
+
"use client";import{Fragment as Z,jsx as o,jsxs as g}from"react/jsx-runtime";import*as l from"react";import{cn as a}from"../../helpers/index.js";import{Text as O,Heading as H,Tabs as G,TabsList as A,TabsTrigger as I,TabsContent as z}from"../../components/index.js";import W from"../PromotionalBar/index.js";import{useExposure as j}from"../../hooks/useExposure.js";import{useViewItemList as q}from"../../hooks/useViewItemList.js";import{useGridRowCount as J}from"../../hooks/useGridRowCount.js";import{useAiuiContext as K}from"../AiuiProvider/index.js";import{ProductCard as R}from"./ProductCard.js";import{withLayout as Q}from"../../shared/Styles.js";const U="shelf",X="Scene_Shelf_3_Products";function Y({products:i,copy:r,showTags:b,stockDisplayMode:S,stockThresholdValue:C,onLearnMore:k,onShopNow:n,onAddToCart:x,onProductImageClick:v,classNames:p,secondaryButtonText:u,secondaryButtonFun:B,primaryButtonText:m,primaryButtonFun:c,showOriginalPrice:w,renderOriginalPrice:D,viewMoreLimit:f,theme:M="light",locale:L="us",tabName:h=""}){const[d,N]=l.useState(!1),y=l.useRef(null);q(y,{componentType:U,componentName:X,itemListName:"Scene_Shelf_3_Products",items:i.map((e,s)=>({item_id:e.sku??"",item_name:e.title,item_variant:e.id??"",price:e.currentPrice,index:s})),tabName:h});const P=J({rows:f??0,mobileCols:2,tabletCols:3,desktopCols:4});if(!i?.length)return null;const T=f!==void 0&&f>0&&i.length>P,V=T&&!d?i.slice(0,P):i,t=()=>{N(e=>!e)};return g(Z,{children:[o("div",{ref:y,className:a("lg-desktop:gap-4 tablet:grid-cols-3 text-info-primary laptop:grid-cols-3 desktop:grid-cols-4 laptop:gap-3 grid grid-cols-2 gap-3",p?.productGrid),children:V.map((e,s)=>o(R,{product:e,showTags:b,stockDisplayMode:S,stockThresholdValue:C,onLearnMore:k,onShopNow:n,onAddToCart:x,onProductImageClick:v,classNames:p,secondaryButtonText:u,secondaryButtonFun:B,primaryButtonText:m,primaryButtonFun:c,showOriginalPrice:w,renderOriginalPrice:D,copy:r,theme:M,locale:L,index:s,tabName:h},e.sku||s))}),T&&o("div",{className:a("laptop:mt-4 mt-3 flex justify-center",p?.viewMore),children:g("button",{onClick:t,className:"text-info-primary hover:text-brand-0 lg-desktop:text-[16px] flex items-center gap-2 text-[14px] font-bold transition-colors","aria-expanded":d,children:[d?r?.viewLessLabel:r?.viewMoreLabel,o("svg",{className:a("size-4 transition-transform",d&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:o("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]})})]})}const F=l.memo(Y);F.displayName="SceneShelfV3.ProductsGrid";const E=l.forwardRef(({className:i,data:r,onLearnMore:b,onShopNow:S,onAddToCart:C,onProductImageClick:k,classNames:n,renderOriginalPrice:x,...v},p)=>{const u=l.useRef(null),{locale:B="us"}=K();j(u,{componentType:"image",componentName:"scene_shelf_banner"}),l.useImperativeHandle(p,()=>u.current);const{theme:m="light",sceneTabs:c=[],showTags:w=!0,stockDisplayMode:D,stockThresholdValue:f,showOriginalPrice:M=!0,secondaryButtonText:L,primaryButtonText:h,secondaryButtonFun:d="learnMore",primaryButtonFun:N="buyNow",copy:y,viewMoreLimit:P}=r,T=c.length>1,V={copy:y,showTags:w,stockDisplayMode:D,stockThresholdValue:f,onLearnMore:b,onShopNow:S,onAddToCart:C,onProductImageClick:k,classNames:n,secondaryButtonText:L,secondaryButtonFun:d,primaryButtonText:h,primaryButtonFun:N,showOriginalPrice:M,renderOriginalPrice:x,viewMoreLimit:P,theme:m,locale:B};return g("div",{ref:u,className:a("w-full",{"aiui-dark":m==="dark"},i,n?.root),style:{"--progress-track-bg":m==="dark"?"rgba(255, 255, 255, 0.2)":"rgba(0, 0, 0, 0.2)"},...v,children:[r.title&&o(H,{as:"h2",html:r.title,size:4,className:a("text-info-primary mb-4",n?.title)}),r.description&&o(O,{size:3,as:"p",html:r.description,className:a("text-info-primary mb-6",n?.description)}),g(G,{defaultValue:c[0]?.id,className:"w-full",children:[T&&o(A,{className:a("mb-6",n?.tabsList),children:c.map(t=>o(I,{value:t.id,children:t.label},t.id))}),c.map(t=>{const e=t.resourceBlocks?.find(s=>s.blockType==="PromotionalBar"&&s.display==="visible");return g(z,{value:t.id,children:[e&&o(W,{data:e,className:a("laptop:mb-4 mb-3",n?.promotionalBar)}),o(F,{products:t.products,...V,tabName:t.label})]},t.id)})]})]})});E.displayName="SceneShelfV3";const _=E;_.ProductCard=R;var ce=Q(_);export{ce as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/SceneShelfV3/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Text, Heading, Tabs, TabsList, TabsTrigger, TabsContent } from '../../components/index.js'\nimport PromotionalBar, { type PromotionalBarProps } from '../PromotionalBar/index.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { useViewItemList } from '../../hooks/useViewItemList.js'\nimport { useGridRowCount } from '../../hooks/useGridRowCount.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport {\n ProductCard,\n type ProductCardData,\n type SceneShelfV3SemanticName,\n type StockDisplayMode,\n} from './ProductCard.js'\nimport type { ButtonFunctionType, CopyConfig } from './types.js'\nimport { withLayout } from '../../shared/Styles.js'\n\nconst componentType = 'shelf'\nconst componentName = 'Scene_Shelf_3_Products'\n\n/**\n * \u573A\u666F Tab \u6570\u636E\u63A5\u53E3\uFF08\u5339\u914D mock.json.sceneTabs \u7ED3\u6784\uFF09\n */\nexport interface ProductTab {\n /** Tab \u552F\u4E00 ID */\n id: string\n /** Tab \u6807\u7B7E\u6587\u672C */\n label: string\n /** \u4EA7\u54C1\u5217\u8868 */\n products: ProductCardData[]\n /** \u8D44\u6E90\u5757\uFF08\u5982 PromotionalBar\uFF09 */\n resourceBlocks?: Array<PromotionalBarProps['data'] & { blockType: string; display: 'visible' | 'hidden' }>\n}\n\n/**\n * SceneShelfV3 \u6570\u636E\u63A5\u53E3\uFF08\u76F4\u63A5\u5339\u914D mock.json \u7ED3\u6784\uFF09\n */\nexport interface SceneShelfV3Data {\n // ===== \u9876\u5C42\u914D\u7F6E\u5B57\u6BB5 =====\n /** \u7EC4\u4EF6\u5B9E\u4F8B ID */\n id: string\n /** \u4E3B\u9898 */\n theme?: 'light' | 'dark'\n /** \u663E\u793A\u72B6\u6001 */\n display?: 'visible' | 'hidden'\n /** \u7EC4\u4EF6\u7C7B\u578B\u6807\u8BC6 */\n blockType: 'ipc-scene-shelf-v3'\n\n // ===== \u573A\u666F Tab \u5217\u8868 =====\n /** \u573A\u666F Tab \u5217\u8868\uFF08\u6BCF\u4E2A Tab \u5305\u542B\u4EA7\u54C1\u548C resourceBlocks\uFF09 */\n sceneTabs: ProductTab[]\n\n // ===== \u6587\u6848\u914D\u7F6E =====\n copy?: CopyConfig\n\n // ===== \u663E\u793A\u914D\u7F6E =====\n /** \u662F\u5426\u663E\u793A\u6807\u7B7E */\n showTags?: boolean\n /** \u67E5\u770B\u66F4\u591A\u9650\u5236\u6570 */\n viewMoreLimit?: number\n\n // ===== \u6309\u94AE\u914D\u7F6E =====\n /** \u4E3B\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u4E3B\u6309\u94AE\u529F\u80FD */\n primaryButtonFun?: ButtonFunctionType\n /** \u6B21\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u6B21\u6309\u94AE\u529F\u80FD */\n secondaryButtonFun?: ButtonFunctionType\n\n // ===== \u53EF\u9009\u5B57\u6BB5\uFF08\u7EC4\u4EF6\u5185\u90E8\u53EF\u80FD\u4F7F\u7528\uFF09 =====\n /** \u7EC4\u4EF6\u6807\u9898\uFF08\u53EF\u9009\uFF0C\u975E mock \u5FC5\u9700\uFF09 */\n title?: string\n /** \u7EC4\u4EF6\u63CF\u8FF0\uFF08\u53EF\u9009\uFF0C\u975E mock \u5FC5\u9700\uFF09 */\n description?: string\n /** \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\uFF08\u53EF\u9009\uFF09 */\n stockDisplayMode?: StockDisplayMode\n /** \u5E93\u5B58\u9608\u503C\uFF08\u53EF\u9009\uFF09 */\n stockThresholdValue?: number\n /** \u662F\u5426\u663E\u793A\u539F\u4EF7\uFF08\u53EF\u9009\uFF09 */\n showOriginalPrice?: boolean\n}\n\nexport interface SceneShelfV3Props extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: SceneShelfV3Data\n /** \u70B9\u51FB\u4E86\u89E3\u66F4\u591A\u56DE\u8C03 */\n onLearnMore?: (link: string) => void\n /** \u70B9\u51FB\u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03 */\n onShopNow?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03 */\n onAddToCart?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u4EA7\u54C1\u56FE\u7247\u56DE\u8C03 */\n onProductImageClick?: (product: ProductCardData) => void\n /** \u8BED\u4E49\u5316\u7C7B\u540D */\n classNames?: Partial<Record<SceneShelfV3SemanticName, string>>\n}\n\nexport interface SceneShelfV3Component extends React.ForwardRefExoticComponent<\n SceneShelfV3Props & React.RefAttributes<HTMLDivElement>\n> {\n ProductCard: typeof ProductCard\n}\n\n/**\n * \u4EA7\u54C1\u7F51\u683C\u7EC4\u4EF6 Props\n */\ninterface ProductsGridProps {\n products: ProductCardData[]\n copy?: CopyConfig\n showTags?: boolean\n stockDisplayMode?: StockDisplayMode\n stockThresholdValue?: number\n onLearnMore?: (link: string) => void\n onShopNow?: (product: ProductCardData) => void\n onAddToCart?: (product: ProductCardData) => void\n onProductImageClick?: (product: ProductCardData) => void\n classNames?: Partial<Record<SceneShelfV3SemanticName, string>>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n showOriginalPrice?: boolean\n viewMoreLimit?: number\n theme?: 'light' | 'dark'\n locale?: string\n tabName?: string\n}\n\n/**\n * \u4EA7\u54C1\u7F51\u683C\u7EC4\u4EF6 - \u4EC5\u652F\u6301\u5E73\u94FA\u7F51\u683C\u5E03\u5C40\uFF08\u65E0\u8F6E\u64AD\uFF09\n */\nfunction ProductsGridComponent({\n products,\n copy,\n showTags,\n stockDisplayMode,\n stockThresholdValue,\n onLearnMore,\n onShopNow,\n onAddToCart,\n onProductImageClick,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n viewMoreLimit,\n theme = 'light',\n locale = 'us',\n tabName = '',\n}: ProductsGridProps) {\n const [isExpanded, setIsExpanded] = React.useState(false)\n const productWrapperRef = React.useRef<HTMLDivElement>(null)\n\n useViewItemList(productWrapperRef, {\n componentType,\n componentName,\n itemListName: 'Scene_Shelf_3_Products',\n items: products.map((item, index) => ({\n item_id: item.sku ?? '',\n item_name: item.title,\n item_variant: item.id ?? '',\n price: item.currentPrice,\n index: index,\n })),\n tabName,\n })\n\n const visibleLimit = useGridRowCount({\n rows: viewMoreLimit ?? 0,\n mobileCols: 2,\n tabletCols: 3,\n desktopCols: 4,\n })\n\n if (!products?.length) return null\n\n const shouldShowViewMore = viewMoreLimit !== undefined && viewMoreLimit > 0 && products.length > visibleLimit\n\n const displayedProducts = shouldShowViewMore && !isExpanded ? products.slice(0, visibleLimit) : products\n\n // \u5207\u6362\u5C55\u5F00\u72B6\u6001\n const toggleExpanded = () => {\n setIsExpanded(prev => !prev)\n }\n\n return (\n <>\n <div\n ref={productWrapperRef}\n className={cn(\n 'lg-desktop:gap-4 tablet:grid-cols-3 text-info-primary laptop:grid-cols-3 desktop:grid-cols-4 laptop:gap-3 grid grid-cols-2 gap-3',\n classNames?.productGrid\n )}\n >\n {displayedProducts.map((product, index) => (\n <ProductCard\n key={product.sku || index}\n product={product}\n showTags={showTags}\n stockDisplayMode={stockDisplayMode}\n stockThresholdValue={stockThresholdValue}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n onProductImageClick={onProductImageClick}\n classNames={classNames}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n showOriginalPrice={showOriginalPrice}\n copy={copy}\n theme={theme}\n locale={locale}\n index={index}\n tabName={tabName}\n />\n ))}\n </div>\n\n {/* \u67E5\u770B\u66F4\u591A\u6309\u94AE */}\n {shouldShowViewMore && (\n <div className={cn('laptop:mt-4 mt-3 flex justify-center', classNames?.viewMore)}>\n <button\n onClick={toggleExpanded}\n className=\"text-info-primary hover:text-brand-0 lg-desktop:text-[16px] flex items-center gap-2 text-[14px] font-bold transition-colors\"\n aria-expanded={isExpanded}\n >\n {isExpanded ? copy?.viewLessLabel : copy?.viewMoreLabel}\n <svg\n className={cn('size-4 transition-transform', isExpanded && 'rotate-180')}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n </div>\n )}\n </>\n )\n}\n\nconst ProductsGrid = React.memo(ProductsGridComponent)\nProductsGrid.displayName = 'SceneShelfV3.ProductsGrid'\n\n/**\n * SceneShelfV3 - \u573A\u666F\u63A8\u8350\u8D27\u67B6 V3\n *\n * @description \u5E73\u94FA\u7F51\u683C\u5E03\u5C40\u7684\u8D27\u67B6\u7EC4\u4EF6\uFF0C\u652F\u6301 Tab \u5206\u7EC4\u3001\u6BCF\u4E2A Tab \u72EC\u7ACB\u914D\u7F6E PromotionalBar \u548C\u67E5\u770B\u66F4\u591A\u529F\u80FD\n */\nconst SceneShelfV3 = React.forwardRef<HTMLDivElement, SceneShelfV3Props>(\n ({ className, data, onLearnMore, onShopNow, onAddToCart, onProductImageClick, classNames, ...props }, ref) => {\n const boxRef = React.useRef<HTMLDivElement>(null)\n const { locale = 'us' } = useAiuiContext()\n\n useExposure(boxRef, {\n componentType: 'image',\n componentName: 'scene_shelf_banner',\n })\n\n React.useImperativeHandle(ref, () => boxRef.current as HTMLDivElement)\n\n const {\n theme = 'light',\n sceneTabs = [],\n showTags = true,\n stockDisplayMode,\n stockThresholdValue,\n showOriginalPrice = true,\n secondaryButtonText,\n primaryButtonText,\n secondaryButtonFun = 'learnMore',\n primaryButtonFun = 'buyNow',\n copy,\n viewMoreLimit,\n } = data\n\n // \u5224\u65AD\u662F\u5426\u663E\u793A Tab\uFF08\u591A\u4E8E 1 \u4E2A Tab \u65F6\u663E\u793A\uFF09\n const shouldShowTab = sceneTabs.length > 1\n\n const gridProps: Omit<ProductsGridProps, 'products'> = {\n copy,\n showTags,\n stockDisplayMode,\n stockThresholdValue,\n onLearnMore,\n onShopNow,\n onAddToCart,\n onProductImageClick,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n viewMoreLimit,\n theme,\n locale,\n }\n\n return (\n <div\n ref={boxRef}\n className={cn('w-full', { 'aiui-dark': theme === 'dark' }, className, classNames?.root)}\n style={\n {\n '--progress-track-bg': theme === 'dark' ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)',\n } as React.CSSProperties\n }\n {...props}\n >\n {/* \u6807\u9898\u533A\u57DF */}\n {data.title && (\n <Heading as=\"h2\" html={data.title} size={4} className={cn('text-info-primary mb-4', classNames?.title)} />\n )}\n {data.description && (\n <Text\n size={3}\n as=\"p\"\n html={data.description}\n className={cn('text-info-primary mb-6', classNames?.description)}\n />\n )}\n\n {/* \u4EA7\u54C1\u5C55\u793A\u533A\u57DF */}\n <Tabs defaultValue={sceneTabs[0]?.id} className=\"w-full\">\n {/* Tab \u5217\u8868 */}\n {shouldShowTab && (\n <TabsList className={cn('mb-6', classNames?.tabsList)}>\n {sceneTabs.map(tab => (\n <TabsTrigger key={tab.id} value={tab.id}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n )}\n\n {/* \u4EA7\u54C1\u5185\u5BB9\u533A\u57DF */}\n {sceneTabs.map(tab => {\n // \u4ECE resourceBlocks \u4E2D\u63D0\u53D6 PromotionalBar \u6570\u636E\n const promotionalBarBlock: any = tab.resourceBlocks?.find(\n block => block.blockType === 'PromotionalBar' && block.display === 'visible'\n )\n\n return (\n <TabsContent key={tab.id} value={tab.id}>\n {/* \u6BCF\u4E2A Tab \u72EC\u7ACB\u7684 PromotionalBar\uFF08\u53EF\u9009\uFF09 */}\n {promotionalBarBlock && (\n <PromotionalBar\n data={promotionalBarBlock}\n className={cn('laptop:mb-4 mb-3', classNames?.promotionalBar)}\n />\n )}\n <ProductsGrid products={tab.products} {...gridProps} tabName={tab.label} />\n </TabsContent>\n )\n })}\n </Tabs>\n </div>\n )\n }\n)\n\nSceneShelfV3.displayName = 'SceneShelfV3'\n\n// \u521B\u5EFA\u590D\u5408\u7EC4\u4EF6\nconst SceneShelfV3WithProductCard = SceneShelfV3 as SceneShelfV3Component\nSceneShelfV3WithProductCard.ProductCard = ProductCard\n\nexport default withLayout(SceneShelfV3WithProductCard)\nexport type { StockDisplayMode, SceneShelfV3SemanticName, ProductCardData }\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["Fragment", "jsx", "jsxs", "React", "cn", "Text", "Heading", "Tabs", "TabsList", "TabsTrigger", "TabsContent", "PromotionalBar", "useExposure", "useViewItemList", "useGridRowCount", "useAiuiContext", "ProductCard", "withLayout", "componentType", "componentName", "ProductsGridComponent", "products", "copy", "showTags", "stockDisplayMode", "stockThresholdValue", "onLearnMore", "onShopNow", "onAddToCart", "onProductImageClick", "classNames", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "showOriginalPrice", "viewMoreLimit", "theme", "locale", "tabName", "isExpanded", "setIsExpanded", "productWrapperRef", "item", "index", "visibleLimit", "shouldShowViewMore", "displayedProducts", "toggleExpanded", "prev", "product", "ProductsGrid", "SceneShelfV3", "className", "data", "props", "ref", "boxRef", "sceneTabs", "shouldShowTab", "gridProps", "tab", "promotionalBarBlock", "block", "SceneShelfV3WithProductCard", "SceneShelfV3_default"]
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Text, Heading, Tabs, TabsList, TabsTrigger, TabsContent } from '../../components/index.js'\nimport PromotionalBar, { type PromotionalBarProps } from '../PromotionalBar/index.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { useViewItemList } from '../../hooks/useViewItemList.js'\nimport { useGridRowCount } from '../../hooks/useGridRowCount.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport {\n ProductCard,\n type ProductCardData,\n type SceneShelfV3SemanticName,\n type StockDisplayMode,\n} from './ProductCard.js'\nimport type { ButtonFunctionType, CopyConfig } from './types.js'\nimport { withLayout } from '../../shared/Styles.js'\n\nconst componentType = 'shelf'\nconst componentName = 'Scene_Shelf_3_Products'\n\n/**\n * \u573A\u666F Tab \u6570\u636E\u63A5\u53E3\uFF08\u5339\u914D mock.json.sceneTabs \u7ED3\u6784\uFF09\n */\nexport interface ProductTab {\n /** Tab \u552F\u4E00 ID */\n id: string\n /** Tab \u6807\u7B7E\u6587\u672C */\n label: string\n /** \u4EA7\u54C1\u5217\u8868 */\n products: ProductCardData[]\n /** \u8D44\u6E90\u5757\uFF08\u5982 PromotionalBar\uFF09 */\n resourceBlocks?: Array<PromotionalBarProps['data'] & { blockType: string; display: 'visible' | 'hidden' }>\n}\n\n/**\n * SceneShelfV3 \u6570\u636E\u63A5\u53E3\uFF08\u76F4\u63A5\u5339\u914D mock.json \u7ED3\u6784\uFF09\n */\nexport interface SceneShelfV3Data {\n // ===== \u9876\u5C42\u914D\u7F6E\u5B57\u6BB5 =====\n /** \u7EC4\u4EF6\u5B9E\u4F8B ID */\n id: string\n /** \u4E3B\u9898 */\n theme?: 'light' | 'dark'\n /** \u663E\u793A\u72B6\u6001 */\n display?: 'visible' | 'hidden'\n /** \u7EC4\u4EF6\u7C7B\u578B\u6807\u8BC6 */\n blockType: 'ipc-scene-shelf-v3'\n\n // ===== \u573A\u666F Tab \u5217\u8868 =====\n /** \u573A\u666F Tab \u5217\u8868\uFF08\u6BCF\u4E2A Tab \u5305\u542B\u4EA7\u54C1\u548C resourceBlocks\uFF09 */\n sceneTabs: ProductTab[]\n\n // ===== \u6587\u6848\u914D\u7F6E =====\n copy?: CopyConfig\n\n // ===== \u663E\u793A\u914D\u7F6E =====\n /** \u662F\u5426\u663E\u793A\u6807\u7B7E */\n showTags?: boolean\n /** \u67E5\u770B\u66F4\u591A\u9650\u5236\u6570 */\n viewMoreLimit?: number\n\n // ===== \u6309\u94AE\u914D\u7F6E =====\n /** \u4E3B\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u4E3B\u6309\u94AE\u529F\u80FD */\n primaryButtonFun?: ButtonFunctionType\n /** \u6B21\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u6B21\u6309\u94AE\u529F\u80FD */\n secondaryButtonFun?: ButtonFunctionType\n\n // ===== \u53EF\u9009\u5B57\u6BB5\uFF08\u7EC4\u4EF6\u5185\u90E8\u53EF\u80FD\u4F7F\u7528\uFF09 =====\n /** \u7EC4\u4EF6\u6807\u9898\uFF08\u53EF\u9009\uFF0C\u975E mock \u5FC5\u9700\uFF09 */\n title?: string\n /** \u7EC4\u4EF6\u63CF\u8FF0\uFF08\u53EF\u9009\uFF0C\u975E mock \u5FC5\u9700\uFF09 */\n description?: string\n /** \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\uFF08\u53EF\u9009\uFF09 */\n stockDisplayMode?: StockDisplayMode\n /** \u5E93\u5B58\u9608\u503C\uFF08\u53EF\u9009\uFF09 */\n stockThresholdValue?: number\n /** \u662F\u5426\u663E\u793A\u539F\u4EF7\uFF08\u53EF\u9009\uFF09 */\n showOriginalPrice?: boolean\n}\n\nexport interface SceneShelfV3Props extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: SceneShelfV3Data\n /** \u70B9\u51FB\u4E86\u89E3\u66F4\u591A\u56DE\u8C03 */\n onLearnMore?: (link: string) => void\n /** \u70B9\u51FB\u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03 */\n onShopNow?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03 */\n onAddToCart?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u4EA7\u54C1\u56FE\u7247\u56DE\u8C03 */\n onProductImageClick?: (product: ProductCardData) => void\n /** \u8BED\u4E49\u5316\u7C7B\u540D */\n classNames?: Partial<Record<SceneShelfV3SemanticName, string>>\n /**\n * \u539F\u4EF7\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5728\u539F\u4EF7\u4F4D\u7F6E\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\uFF08\u5982 Save \u91D1\u989D\u6587\u6848\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u539F\u4EF7\u6E32\u67D3\uFF08\u5212\u7EBF\u4EF7\uFF09\u3002\n * @param product - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param context - \u6E32\u67D3\u4E0A\u4E0B\u6587\uFF08\u542B showOriginalPrice\uFF09\n */\n renderOriginalPrice?: (product: ProductCardData, context: { showOriginalPrice?: boolean }) => React.ReactNode\n}\n\nexport interface SceneShelfV3Component extends React.ForwardRefExoticComponent<\n SceneShelfV3Props & React.RefAttributes<HTMLDivElement>\n> {\n ProductCard: typeof ProductCard\n}\n\n/**\n * \u4EA7\u54C1\u7F51\u683C\u7EC4\u4EF6 Props\n */\ninterface ProductsGridProps {\n products: ProductCardData[]\n copy?: CopyConfig\n showTags?: boolean\n stockDisplayMode?: StockDisplayMode\n stockThresholdValue?: number\n onLearnMore?: (link: string) => void\n onShopNow?: (product: ProductCardData) => void\n onAddToCart?: (product: ProductCardData) => void\n onProductImageClick?: (product: ProductCardData) => void\n classNames?: Partial<Record<SceneShelfV3SemanticName, string>>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n showOriginalPrice?: boolean\n renderOriginalPrice?: (product: ProductCardData, context: { showOriginalPrice?: boolean }) => React.ReactNode\n viewMoreLimit?: number\n theme?: 'light' | 'dark'\n locale?: string\n tabName?: string\n}\n\n/**\n * \u4EA7\u54C1\u7F51\u683C\u7EC4\u4EF6 - \u4EC5\u652F\u6301\u5E73\u94FA\u7F51\u683C\u5E03\u5C40\uFF08\u65E0\u8F6E\u64AD\uFF09\n */\nfunction ProductsGridComponent({\n products,\n copy,\n showTags,\n stockDisplayMode,\n stockThresholdValue,\n onLearnMore,\n onShopNow,\n onAddToCart,\n onProductImageClick,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n renderOriginalPrice,\n viewMoreLimit,\n theme = 'light',\n locale = 'us',\n tabName = '',\n}: ProductsGridProps) {\n const [isExpanded, setIsExpanded] = React.useState(false)\n const productWrapperRef = React.useRef<HTMLDivElement>(null)\n\n useViewItemList(productWrapperRef, {\n componentType,\n componentName,\n itemListName: 'Scene_Shelf_3_Products',\n items: products.map((item, index) => ({\n item_id: item.sku ?? '',\n item_name: item.title,\n item_variant: item.id ?? '',\n price: item.currentPrice,\n index: index,\n })),\n tabName,\n })\n\n const visibleLimit = useGridRowCount({\n rows: viewMoreLimit ?? 0,\n mobileCols: 2,\n tabletCols: 3,\n desktopCols: 4,\n })\n\n if (!products?.length) return null\n\n const shouldShowViewMore = viewMoreLimit !== undefined && viewMoreLimit > 0 && products.length > visibleLimit\n\n const displayedProducts = shouldShowViewMore && !isExpanded ? products.slice(0, visibleLimit) : products\n\n // \u5207\u6362\u5C55\u5F00\u72B6\u6001\n const toggleExpanded = () => {\n setIsExpanded(prev => !prev)\n }\n\n return (\n <>\n <div\n ref={productWrapperRef}\n className={cn(\n 'lg-desktop:gap-4 tablet:grid-cols-3 text-info-primary laptop:grid-cols-3 desktop:grid-cols-4 laptop:gap-3 grid grid-cols-2 gap-3',\n classNames?.productGrid\n )}\n >\n {displayedProducts.map((product, index) => (\n <ProductCard\n key={product.sku || index}\n product={product}\n showTags={showTags}\n stockDisplayMode={stockDisplayMode}\n stockThresholdValue={stockThresholdValue}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n onProductImageClick={onProductImageClick}\n classNames={classNames}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n showOriginalPrice={showOriginalPrice}\n renderOriginalPrice={renderOriginalPrice}\n copy={copy}\n theme={theme}\n locale={locale}\n index={index}\n tabName={tabName}\n />\n ))}\n </div>\n\n {/* \u67E5\u770B\u66F4\u591A\u6309\u94AE */}\n {shouldShowViewMore && (\n <div className={cn('laptop:mt-4 mt-3 flex justify-center', classNames?.viewMore)}>\n <button\n onClick={toggleExpanded}\n className=\"text-info-primary hover:text-brand-0 lg-desktop:text-[16px] flex items-center gap-2 text-[14px] font-bold transition-colors\"\n aria-expanded={isExpanded}\n >\n {isExpanded ? copy?.viewLessLabel : copy?.viewMoreLabel}\n <svg\n className={cn('size-4 transition-transform', isExpanded && 'rotate-180')}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n </div>\n )}\n </>\n )\n}\n\nconst ProductsGrid = React.memo(ProductsGridComponent)\nProductsGrid.displayName = 'SceneShelfV3.ProductsGrid'\n\n/**\n * SceneShelfV3 - \u573A\u666F\u63A8\u8350\u8D27\u67B6 V3\n *\n * @description \u5E73\u94FA\u7F51\u683C\u5E03\u5C40\u7684\u8D27\u67B6\u7EC4\u4EF6\uFF0C\u652F\u6301 Tab \u5206\u7EC4\u3001\u6BCF\u4E2A Tab \u72EC\u7ACB\u914D\u7F6E PromotionalBar \u548C\u67E5\u770B\u66F4\u591A\u529F\u80FD\n */\nconst SceneShelfV3 = React.forwardRef<HTMLDivElement, SceneShelfV3Props>(\n (\n {\n className,\n data,\n onLearnMore,\n onShopNow,\n onAddToCart,\n onProductImageClick,\n classNames,\n renderOriginalPrice,\n ...props\n },\n ref\n ) => {\n const boxRef = React.useRef<HTMLDivElement>(null)\n const { locale = 'us' } = useAiuiContext()\n\n useExposure(boxRef, {\n componentType: 'image',\n componentName: 'scene_shelf_banner',\n })\n\n React.useImperativeHandle(ref, () => boxRef.current as HTMLDivElement)\n\n const {\n theme = 'light',\n sceneTabs = [],\n showTags = true,\n stockDisplayMode,\n stockThresholdValue,\n showOriginalPrice = true,\n secondaryButtonText,\n primaryButtonText,\n secondaryButtonFun = 'learnMore',\n primaryButtonFun = 'buyNow',\n copy,\n viewMoreLimit,\n } = data\n\n // \u5224\u65AD\u662F\u5426\u663E\u793A Tab\uFF08\u591A\u4E8E 1 \u4E2A Tab \u65F6\u663E\u793A\uFF09\n const shouldShowTab = sceneTabs.length > 1\n\n const gridProps: Omit<ProductsGridProps, 'products'> = {\n copy,\n showTags,\n stockDisplayMode,\n stockThresholdValue,\n onLearnMore,\n onShopNow,\n onAddToCart,\n onProductImageClick,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n renderOriginalPrice,\n viewMoreLimit,\n theme,\n locale,\n }\n\n return (\n <div\n ref={boxRef}\n className={cn('w-full', { 'aiui-dark': theme === 'dark' }, className, classNames?.root)}\n style={\n {\n '--progress-track-bg': theme === 'dark' ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)',\n } as React.CSSProperties\n }\n {...props}\n >\n {/* \u6807\u9898\u533A\u57DF */}\n {data.title && (\n <Heading as=\"h2\" html={data.title} size={4} className={cn('text-info-primary mb-4', classNames?.title)} />\n )}\n {data.description && (\n <Text\n size={3}\n as=\"p\"\n html={data.description}\n className={cn('text-info-primary mb-6', classNames?.description)}\n />\n )}\n\n {/* \u4EA7\u54C1\u5C55\u793A\u533A\u57DF */}\n <Tabs defaultValue={sceneTabs[0]?.id} className=\"w-full\">\n {/* Tab \u5217\u8868 */}\n {shouldShowTab && (\n <TabsList className={cn('mb-6', classNames?.tabsList)}>\n {sceneTabs.map(tab => (\n <TabsTrigger key={tab.id} value={tab.id}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n )}\n\n {/* \u4EA7\u54C1\u5185\u5BB9\u533A\u57DF */}\n {sceneTabs.map(tab => {\n // \u4ECE resourceBlocks \u4E2D\u63D0\u53D6 PromotionalBar \u6570\u636E\n const promotionalBarBlock: any = tab.resourceBlocks?.find(\n block => block.blockType === 'PromotionalBar' && block.display === 'visible'\n )\n\n return (\n <TabsContent key={tab.id} value={tab.id}>\n {/* \u6BCF\u4E2A Tab \u72EC\u7ACB\u7684 PromotionalBar\uFF08\u53EF\u9009\uFF09 */}\n {promotionalBarBlock && (\n <PromotionalBar\n data={promotionalBarBlock}\n className={cn('laptop:mb-4 mb-3', classNames?.promotionalBar)}\n />\n )}\n <ProductsGrid products={tab.products} {...gridProps} tabName={tab.label} />\n </TabsContent>\n )\n })}\n </Tabs>\n </div>\n )\n }\n)\n\nSceneShelfV3.displayName = 'SceneShelfV3'\n\n// \u521B\u5EFA\u590D\u5408\u7EC4\u4EF6\nconst SceneShelfV3WithProductCard = SceneShelfV3 as SceneShelfV3Component\nSceneShelfV3WithProductCard.ProductCard = ProductCard\n\nexport default withLayout(SceneShelfV3WithProductCard)\nexport type { StockDisplayMode, SceneShelfV3SemanticName, ProductCardData }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Fragment", "jsx", "jsxs", "React", "cn", "Text", "Heading", "Tabs", "TabsList", "TabsTrigger", "TabsContent", "PromotionalBar", "useExposure", "useViewItemList", "useGridRowCount", "useAiuiContext", "ProductCard", "withLayout", "componentType", "componentName", "ProductsGridComponent", "products", "copy", "showTags", "stockDisplayMode", "stockThresholdValue", "onLearnMore", "onShopNow", "onAddToCart", "onProductImageClick", "classNames", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "showOriginalPrice", "renderOriginalPrice", "viewMoreLimit", "theme", "locale", "tabName", "isExpanded", "setIsExpanded", "productWrapperRef", "item", "index", "visibleLimit", "shouldShowViewMore", "displayedProducts", "toggleExpanded", "prev", "product", "ProductsGrid", "SceneShelfV3", "className", "data", "props", "ref", "boxRef", "sceneTabs", "shouldShowTab", "gridProps", "tab", "promotionalBarBlock", "block", "SceneShelfV3WithProductCard", "SceneShelfV3_default"]
|
|
7
7
|
}
|
|
@@ -106,6 +106,32 @@ export type ShelfDisplayType = {
|
|
|
106
106
|
/** shelf-items-tag 背景颜色,设置后会覆盖默认的品牌渐变背景并隐藏默认品牌色描边。仅作用于纵向卡片 ShelfDisplayWrapItem */
|
|
107
107
|
itemsTagBgColor?: string;
|
|
108
108
|
};
|
|
109
|
+
/**
|
|
110
|
+
* 价格渲染上下文:renderOriginalPrice / renderPrice 等渲染函数共享的格式化价格信息。
|
|
111
|
+
* 后续如需向渲染函数抛出更多参数,直接在本类型中追加字段即可(向后兼容)。
|
|
112
|
+
*/
|
|
113
|
+
export interface ShelfDisplayPriceInfo {
|
|
114
|
+
price: string;
|
|
115
|
+
basePrice: string | undefined;
|
|
116
|
+
discount: string | null;
|
|
117
|
+
discountAmount: string | undefined;
|
|
118
|
+
/** 是否显示原价(来源 data.isShowOriginalPrice,默认 true) */
|
|
119
|
+
isShowOriginalPrice: boolean;
|
|
120
|
+
}
|
|
121
|
+
/** renderPrice 完整上下文:在价格信息基础上追加变体 / 优惠券 / 售罄状态。 */
|
|
122
|
+
export interface ShelfDisplayPriceRenderInfo extends ShelfDisplayPriceInfo {
|
|
123
|
+
variant: any;
|
|
124
|
+
coupon: any;
|
|
125
|
+
isSoldOut: boolean;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* renderPriceLabel 上下文:用于向价格标签渲染函数抛出配置信息。
|
|
129
|
+
* 后续扩展时在此追加字段即可(向后兼容)。
|
|
130
|
+
*/
|
|
131
|
+
export interface ShelfDisplayPriceLabelContext {
|
|
132
|
+
/** 是否显示原价(来源 data.isShowOriginalPrice,默认 true) */
|
|
133
|
+
isShowOriginalPrice: boolean;
|
|
134
|
+
}
|
|
109
135
|
export interface ShelfDisplayProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
110
136
|
data: ShelfDisplayType;
|
|
111
137
|
buildData?: {
|
|
@@ -143,35 +169,23 @@ export interface ShelfDisplayProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
143
169
|
* 原价区域渲染函数,用于在原价位置展示自定义内容(如折扣信息)。
|
|
144
170
|
* 不传时使用默认的原价渲染(划线价)。
|
|
145
171
|
* @param item - 当前产品数据
|
|
146
|
-
* @param priceInfo -
|
|
172
|
+
* @param priceInfo - 格式化后的价格信息(含 isShowOriginalPrice)
|
|
147
173
|
*/
|
|
148
|
-
renderOriginalPrice?: (item: ShelfDisplayItem, priceInfo:
|
|
149
|
-
price: string;
|
|
150
|
-
basePrice: string | undefined;
|
|
151
|
-
discount: string | null;
|
|
152
|
-
discountAmount: string | undefined;
|
|
153
|
-
}) => React.ReactNode;
|
|
174
|
+
renderOriginalPrice?: (item: ShelfDisplayItem, priceInfo: ShelfDisplayPriceInfo) => React.ReactNode;
|
|
154
175
|
/**
|
|
155
176
|
* 价格标签渲染函数,在价格下方展示自定义内容。
|
|
156
177
|
* 不传时不展示。
|
|
157
178
|
* @param item - 当前产品数据
|
|
158
179
|
* @param variant - 当前匹配的变体数据
|
|
180
|
+
* @param context - 渲染上下文(含 isShowOriginalPrice,后续可扩展更多字段)
|
|
159
181
|
*/
|
|
160
|
-
renderPriceLabel?: (item: ShelfDisplayItem, variant: any) => React.ReactNode;
|
|
182
|
+
renderPriceLabel?: (item: ShelfDisplayItem, variant: any, context?: ShelfDisplayPriceLabelContext) => React.ReactNode;
|
|
161
183
|
/**
|
|
162
184
|
* 价格区域渲染函数,用于完全自定义价格区域(包括最终价格、原价、售罄状态等)。
|
|
163
185
|
* 不传时使用默认的价格渲染逻辑。
|
|
164
186
|
* @param item - 当前产品数据
|
|
165
|
-
* @param priceInfo -
|
|
187
|
+
* @param priceInfo - 格式化后的价格信息及上下文(含 isShowOriginalPrice)
|
|
166
188
|
*/
|
|
167
|
-
renderPrice?: (item: ShelfDisplayItem, priceInfo:
|
|
168
|
-
price: string;
|
|
169
|
-
basePrice: string | undefined;
|
|
170
|
-
discount: string | null;
|
|
171
|
-
discountAmount: string | undefined;
|
|
172
|
-
variant: any;
|
|
173
|
-
coupon: any;
|
|
174
|
-
isSoldOut: boolean;
|
|
175
|
-
}) => React.ReactNode;
|
|
189
|
+
renderPrice?: (item: ShelfDisplayItem, priceInfo: ShelfDisplayPriceRenderInfo) => React.ReactNode;
|
|
176
190
|
}
|
|
177
191
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import h from"decimal.js";import{PRICE_SYMBOL as l,formatPrice as p,languageTerritory as D}from"../../helpers/index.js";function x({amount:
|
|
1
|
+
import h from"decimal.js";import{PRICE_SYMBOL as l,formatPrice as p,languageTerritory as D}from"../../helpers/index.js";function x({amount:n,baseAmount:i,currencyCode:a,currencyDisplay:o,locale:e,maximumFractionDigits:u,minimumFractionDigits:g,removeTrailingZeros:c,customFormatPrice:t}){if(typeof Intl>"u")return{price:`${l[e]}${n}`,basePrice:`${l[e]}${i}`,discount:`${l[e]}${i-n||0}`};const s=i>n;let d=null;const m=D(e);if(m){const r=new Intl.NumberFormat(m,{style:"percent"});d=s?r.format((i-n)/i):null}let y;if(s){const r=new h(i).sub(n||0).toNumber();y=t?t({amount:r,locale:e}):p({amount:r,currencyDisplay:o,currencyCode:a||"USD",locale:e,maximumFractionDigits:2})}const f=t?t({amount:n,locale:e}):p({amount:n,currencyCode:a,currencyDisplay:o,locale:e,removeTrailingZeros:c}),b=s?t?t({amount:i,locale:e}):p({amount:i,currencyCode:a,currencyDisplay:o,locale:e,maximumFractionDigits:u,minimumFractionDigits:g,removeTrailingZeros:c}):void 0;return{price:f,basePrice:b,discount:d,discountAmount:y}}export{x as formatVariantPrice};
|
|
2
2
|
//# sourceMappingURL=shelfDisplay.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/ShelfDisplay/shelfDisplay.ts"],
|
|
4
|
-
"sourcesContent": ["import Decimal from 'decimal.js'\nimport type { ContainerProps, CurrencyDisplayType } from '../../types/props.js'\n/* eslint-disable no-useless-escape */\nimport { PRICE_SYMBOL, formatPrice, languageTerritory } from '../../helpers/index.js'\n\nexport type FormattedPriceFunc = (params: {\n amount: number\n isDigits?: boolean\n withOutSymbol?: boolean\n locale?: string\n forceFormat?: boolean\n}) => string\n\nexport function formatVariantPrice({\n amount,\n baseAmount,\n currencyCode,\n currencyDisplay,\n locale,\n maximumFractionDigits,\n minimumFractionDigits,\n removeTrailingZeros,\n customFormatPrice,\n}: {\n baseAmount: number\n amount: number\n currencyCode: string\n currencyDisplay?: CurrencyDisplayType\n locale: string\n maximumFractionDigits?: number\n minimumFractionDigits?: number\n removeTrailingZeros?: boolean\n customFormatPrice?: FormattedPriceFunc\n}) {\n if (typeof Intl === 'undefined') {\n return {\n price: `${PRICE_SYMBOL[locale]}${amount}`,\n basePrice: `${PRICE_SYMBOL[locale]}${baseAmount}`,\n discount: `${PRICE_SYMBOL[locale]}${baseAmount - amount || 0}`,\n }\n }\n\n const hasDiscount = baseAmount > amount\n let discount = null\n const currentLocale = languageTerritory(locale)\n if (currentLocale) {\n const formatDiscount = new Intl.NumberFormat(currentLocale, {\n style: 'percent',\n })\n discount = hasDiscount ? formatDiscount.format((baseAmount - amount) / baseAmount) : null\n }\n // \u6298\u6263\u91D1\u989D\n let discountAmount\n if (hasDiscount) {\n const savePriceAmount = new Decimal(baseAmount).sub(amount || 0).toNumber()\n discountAmount = customFormatPrice\n ? customFormatPrice({ amount: savePriceAmount, locale })\n : formatPrice({\n amount: savePriceAmount,\n currencyDisplay,\n currencyCode: currencyCode || 'USD',\n locale,\n maximumFractionDigits: 2,\n })\n }\n\n const price = customFormatPrice\n ? customFormatPrice({ amount, locale })\n : formatPrice({ amount, currencyCode, currencyDisplay, locale, removeTrailingZeros })\n const basePrice = hasDiscount\n ? customFormatPrice\n ? customFormatPrice({ amount: baseAmount, locale })\n : formatPrice({\n amount: baseAmount,\n currencyCode,\n currencyDisplay,\n locale,\n maximumFractionDigits,\n minimumFractionDigits,\n removeTrailingZeros,\n })\n : undefined\n\n return { price, basePrice, discount, discountAmount }\n}\n\ntype EventType = {\n primaryButton?: (v: any, index: number, data: ShelfDisplayType, coupon: any) => void\n secondaryButton?: (v: any, index: number, data: ShelfDisplayType, coupon: any) => void\n}\n\nexport interface ShelfDisplayItem {\n custom_primary_link?: string\n custom_secondary_link?: string\n id?: string\n /** \u4EA7\u54C1\u56FE\u7247*/\n img?: {\n url: string\n }\n handle?: string\n sku?: string\n /** \u6298\u6263\u540E\u4EF7\u683C*/\n price?: string\n title?: string\n /** \u6298\u6263\u524D\u4EF7\u683C*/\n basePrice?: string\n subTitle?: string\n /** \u6807\u7B7E*/\n tagItems?: string[]\n tab?: string\n data?: ShelfDisplayItem[]\n custom_name?: string\n custom_description?: string\n custom_image?: string\n custom_theme?: string\n custom_bg_image?: string\n}\n\nexport interface SocialEndorsementItem {\n /** \u56FE\u6807\uFF1A\u56FE\u7247 URL \u5B57\u7B26\u4E32\uFF0C\u6216 SVG React \u8282\u70B9 */\n icon: string | React.ReactNode\n /** \u65E0\u969C\u788D\u6807\u7B7E */\n label?: string\n}\n\nexport type ShelfDisplayType = {\n title?: string\n isShowTab?: boolean\n isShowTag?: boolean\n isShowRecommendedCard?: boolean\n isShowOriginalPrice?: boolean\n direction?: 'horizontal' | 'vertical'\n align?: 'left' | 'center' | 'right'\n productsTab?: any[]\n productsCard?: any[]\n /** \u5361\u7247\u5F62\u72B6 */\n itemShape?: 'round' | 'square'\n /** \u6309\u94AE\u5F62\u72B6 */\n shape?: 'round' | 'square'\n /** \u6807\u7B7E\u9875\u5F62\u72B6*/\n tabShape?: 'rounded' | 'square'\n /** \u4E3B\u6309\u94AE\u914D\u7F6E */\n primaryButton?: string\n primaryFun?: 'AddCart' | 'BuyNow' | 'LearnMore'\n /** \u526F\u6309\u94AE\u914D\u7F6E */\n secondaryButton?: string\n secondaryFun?: 'AddCart' | 'BuyNow' | 'LearnMore'\n theme?: 'light' | 'dark'\n containerProps?: ContainerProps\n /** \u662F\u5426\u5E73\u94FA\u7F51\u683C\u5E03\u5C40\uFF08\u22651025px \u751F\u6548\uFF0C\u4E00\u884C 3 \u4E2A\uFF0C\u22651440px \u4E00\u884C 4 \u4E2A\uFF0C\u22641024px \u4ECD\u4E3A\u8F6E\u64AD\uFF09 */\n isTile?: boolean\n /** \u5E73\u94FA\u5E03\u5C40\u4E0B\u6700\u591A\u5C55\u793A\u7684\u884C\u6570\uFF0C\u8D85\u8FC7\u8BE5\u884C\u6570\u65F6\u6298\u53E0\u6536\u8D77\uFF0C\u9700\u70B9\u51FB\u300C\u5C55\u5F00\u300D\u67E5\u770B\u66F4\u591A\u3002\u672A\u8BBE\u7F6E\u5219\u4E0D\u6298\u53E0 */\n tileMaxRows?: number\n /** \u5E73\u94FA\u5E03\u5C40\u6298\u53E0\u65F6\u300C\u5C55\u5F00\u300D\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'Show more' */\n tileExpandText?: string\n /** \u5E73\u94FA\u5E03\u5C40\u5C55\u5F00\u540E\u300C\u6536\u8D77\u300D\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'Show less' */\n tileCollapseText?: string\n /** shelf-prices-tag\uFF08\u6298\u6263\u4EF7\u683C\u6807\u7B7E\uFF09\u662F\u5426\u663E\u793A\uFF0C\u9ED8\u8BA4 false\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n isShowPricesTag?: boolean\n /** shelf-prices-tag \u6587\u6848\u989C\u8272\uFF0C\u5EFA\u8BAE\u4F7F\u7528 Design Token CSS \u53D8\u91CF\uFF0C\u5982 var(--info-primary-color)\u3002\u8BBE\u7F6E\u540E\u4F1A\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n pricesTagTextColor?: string\n /** shelf-prices-tag \u80CC\u666F\u989C\u8272\uFF0C\u8BBE\u7F6E\u540E\u4F1A\u8986\u76D6\u9ED8\u8BA4\u7684\u54C1\u724C\u6E10\u53D8\u80CC\u666F\u5E76\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n pricesTagBgColor?: string\n /** shelf-items-tag\uFF08\u81EA\u5B9A\u4E49\u6807\u7B7E\uFF09\u6587\u6848\u989C\u8272\u3002\u8BBE\u7F6E\u540E\u4F1A\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n itemsTagTextColor?: string\n /** shelf-items-tag \u80CC\u666F\u989C\u8272\uFF0C\u8BBE\u7F6E\u540E\u4F1A\u8986\u76D6\u9ED8\u8BA4\u7684\u54C1\u724C\u6E10\u53D8\u80CC\u666F\u5E76\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n itemsTagBgColor?: string\n}\n\nexport interface ShelfDisplayProps extends React.HTMLAttributes<HTMLDivElement> {\n data: ShelfDisplayType\n buildData?: {\n categories: any[]\n products: any[]\n }\n recommendedData?: any[]\n /**\n * \u6309\u94AE\u4E8B\u4EF6\n * @deprecated \u8BF7\u4F7F\u7528 onAddCart / onBuyNow / onLearnMore \u914D\u5408 primaryFun / secondaryFun \u66FF\u4EE3\n */\n event?: EventType\n key?: string\n target?: '_self' | '_blank'\n breakpoints?: {\n [key: number]: {\n spaceBetween: number\n freeMode: boolean\n slidesPerView: number\n }\n }\n /** \u5143\u6570\u636E\uFF1A\u6298\u6263\u6587\u6848\uFF08discounts.off / discountsCopy.off\uFF09\u53CA\u793E\u5A92\u80CC\u4E66\u56FE\u6807\uFF08socialEndorsements: SocialEndorsementItem[]\uFF09 */\n metafields?: any\n isDisplayGudgments?: boolean\n isDisplayBackImage?: boolean\n\n /** \u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03 */\n onAddCart?: (params: ShelfDisplayItem, index: number, data: ShelfDisplayType, coupon: any) => void\n /** \u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03 */\n onBuyNow?: (params: ShelfDisplayItem, index: number, data: ShelfDisplayType, coupon: any) => void\n /** \u4E86\u89E3\u66F4\u591A\u56DE\u8C03 */\n onLearnMore?: (params: ShelfDisplayItem, index: number, data: ShelfDisplayType, coupon: any) => void\n /** \u81EA\u5B9A\u4E49\u4EF7\u683C\u683C\u5F0F\u5316\u51FD\u6570\uFF0C\u672A\u4F20\u5219\u4F7F\u7528\u9ED8\u8BA4\u683C\u5F0F\u5316\u903B\u8F91 */\n formatPrice?: FormattedPriceFunc\n /**\n * \u539F\u4EF7\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5728\u539F\u4EF7\u4F4D\u7F6E\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\uFF08\u5982\u6298\u6263\u4FE1\u606F\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u539F\u4EF7\u6E32\u67D3\uFF08\u5212\u7EBF\u4EF7\uFF09\u3002\n * @param item - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param priceInfo - \u683C\u5F0F\u5316\u540E\u7684\u4EF7\u683C\u4FE1\u606F\n */\n renderOriginalPrice?: (\n item: ShelfDisplayItem,\n priceInfo: {\n price: string\n basePrice: string | undefined\n discount: string | null\n discountAmount: string | undefined\n }\n ) => React.ReactNode\n /**\n * \u4EF7\u683C\u6807\u7B7E\u6E32\u67D3\u51FD\u6570\uFF0C\u5728\u4EF7\u683C\u4E0B\u65B9\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\u3002\n * \u4E0D\u4F20\u65F6\u4E0D\u5C55\u793A\u3002\n * @param item - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param variant - \u5F53\u524D\u5339\u914D\u7684\u53D8\u4F53\u6570\u636E\n */\n renderPriceLabel?: (item: ShelfDisplayItem, variant: any) => React.ReactNode\n /**\n * \u4EF7\u683C\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5B8C\u5168\u81EA\u5B9A\u4E49\u4EF7\u683C\u533A\u57DF\uFF08\u5305\u62EC\u6700\u7EC8\u4EF7\u683C\u3001\u539F\u4EF7\u3001\u552E\u7F44\u72B6\u6001\u7B49\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u4EF7\u683C\u6E32\u67D3\u903B\u8F91\u3002\n * @param item - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param priceInfo - \u683C\u5F0F\u5316\u540E\u7684\u4EF7\u683C\u4FE1\u606F\u53CA\u4E0A\u4E0B\u6587\n */\n renderPrice?: (\n item: ShelfDisplayItem,\n priceInfo: {\n price: string\n basePrice: string | undefined\n discount: string | null\n discountAmount: string | undefined\n variant: any\n coupon: any\n isSoldOut: boolean\n }\n ) => React.ReactNode\n}\n"],
|
|
4
|
+
"sourcesContent": ["import Decimal from 'decimal.js'\nimport type { ContainerProps, CurrencyDisplayType } from '../../types/props.js'\n/* eslint-disable no-useless-escape */\nimport { PRICE_SYMBOL, formatPrice, languageTerritory } from '../../helpers/index.js'\n\nexport type FormattedPriceFunc = (params: {\n amount: number\n isDigits?: boolean\n withOutSymbol?: boolean\n locale?: string\n forceFormat?: boolean\n}) => string\n\nexport function formatVariantPrice({\n amount,\n baseAmount,\n currencyCode,\n currencyDisplay,\n locale,\n maximumFractionDigits,\n minimumFractionDigits,\n removeTrailingZeros,\n customFormatPrice,\n}: {\n baseAmount: number\n amount: number\n currencyCode: string\n currencyDisplay?: CurrencyDisplayType\n locale: string\n maximumFractionDigits?: number\n minimumFractionDigits?: number\n removeTrailingZeros?: boolean\n customFormatPrice?: FormattedPriceFunc\n}) {\n if (typeof Intl === 'undefined') {\n return {\n price: `${PRICE_SYMBOL[locale]}${amount}`,\n basePrice: `${PRICE_SYMBOL[locale]}${baseAmount}`,\n discount: `${PRICE_SYMBOL[locale]}${baseAmount - amount || 0}`,\n }\n }\n\n const hasDiscount = baseAmount > amount\n let discount = null\n const currentLocale = languageTerritory(locale)\n if (currentLocale) {\n const formatDiscount = new Intl.NumberFormat(currentLocale, {\n style: 'percent',\n })\n discount = hasDiscount ? formatDiscount.format((baseAmount - amount) / baseAmount) : null\n }\n // \u6298\u6263\u91D1\u989D\n let discountAmount\n if (hasDiscount) {\n const savePriceAmount = new Decimal(baseAmount).sub(amount || 0).toNumber()\n discountAmount = customFormatPrice\n ? customFormatPrice({ amount: savePriceAmount, locale })\n : formatPrice({\n amount: savePriceAmount,\n currencyDisplay,\n currencyCode: currencyCode || 'USD',\n locale,\n maximumFractionDigits: 2,\n })\n }\n\n const price = customFormatPrice\n ? customFormatPrice({ amount, locale })\n : formatPrice({ amount, currencyCode, currencyDisplay, locale, removeTrailingZeros })\n const basePrice = hasDiscount\n ? customFormatPrice\n ? customFormatPrice({ amount: baseAmount, locale })\n : formatPrice({\n amount: baseAmount,\n currencyCode,\n currencyDisplay,\n locale,\n maximumFractionDigits,\n minimumFractionDigits,\n removeTrailingZeros,\n })\n : undefined\n\n return { price, basePrice, discount, discountAmount }\n}\n\ntype EventType = {\n primaryButton?: (v: any, index: number, data: ShelfDisplayType, coupon: any) => void\n secondaryButton?: (v: any, index: number, data: ShelfDisplayType, coupon: any) => void\n}\n\nexport interface ShelfDisplayItem {\n custom_primary_link?: string\n custom_secondary_link?: string\n id?: string\n /** \u4EA7\u54C1\u56FE\u7247*/\n img?: {\n url: string\n }\n handle?: string\n sku?: string\n /** \u6298\u6263\u540E\u4EF7\u683C*/\n price?: string\n title?: string\n /** \u6298\u6263\u524D\u4EF7\u683C*/\n basePrice?: string\n subTitle?: string\n /** \u6807\u7B7E*/\n tagItems?: string[]\n tab?: string\n data?: ShelfDisplayItem[]\n custom_name?: string\n custom_description?: string\n custom_image?: string\n custom_theme?: string\n custom_bg_image?: string\n}\n\nexport interface SocialEndorsementItem {\n /** \u56FE\u6807\uFF1A\u56FE\u7247 URL \u5B57\u7B26\u4E32\uFF0C\u6216 SVG React \u8282\u70B9 */\n icon: string | React.ReactNode\n /** \u65E0\u969C\u788D\u6807\u7B7E */\n label?: string\n}\n\nexport type ShelfDisplayType = {\n title?: string\n isShowTab?: boolean\n isShowTag?: boolean\n isShowRecommendedCard?: boolean\n isShowOriginalPrice?: boolean\n direction?: 'horizontal' | 'vertical'\n align?: 'left' | 'center' | 'right'\n productsTab?: any[]\n productsCard?: any[]\n /** \u5361\u7247\u5F62\u72B6 */\n itemShape?: 'round' | 'square'\n /** \u6309\u94AE\u5F62\u72B6 */\n shape?: 'round' | 'square'\n /** \u6807\u7B7E\u9875\u5F62\u72B6*/\n tabShape?: 'rounded' | 'square'\n /** \u4E3B\u6309\u94AE\u914D\u7F6E */\n primaryButton?: string\n primaryFun?: 'AddCart' | 'BuyNow' | 'LearnMore'\n /** \u526F\u6309\u94AE\u914D\u7F6E */\n secondaryButton?: string\n secondaryFun?: 'AddCart' | 'BuyNow' | 'LearnMore'\n theme?: 'light' | 'dark'\n containerProps?: ContainerProps\n /** \u662F\u5426\u5E73\u94FA\u7F51\u683C\u5E03\u5C40\uFF08\u22651025px \u751F\u6548\uFF0C\u4E00\u884C 3 \u4E2A\uFF0C\u22651440px \u4E00\u884C 4 \u4E2A\uFF0C\u22641024px \u4ECD\u4E3A\u8F6E\u64AD\uFF09 */\n isTile?: boolean\n /** \u5E73\u94FA\u5E03\u5C40\u4E0B\u6700\u591A\u5C55\u793A\u7684\u884C\u6570\uFF0C\u8D85\u8FC7\u8BE5\u884C\u6570\u65F6\u6298\u53E0\u6536\u8D77\uFF0C\u9700\u70B9\u51FB\u300C\u5C55\u5F00\u300D\u67E5\u770B\u66F4\u591A\u3002\u672A\u8BBE\u7F6E\u5219\u4E0D\u6298\u53E0 */\n tileMaxRows?: number\n /** \u5E73\u94FA\u5E03\u5C40\u6298\u53E0\u65F6\u300C\u5C55\u5F00\u300D\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'Show more' */\n tileExpandText?: string\n /** \u5E73\u94FA\u5E03\u5C40\u5C55\u5F00\u540E\u300C\u6536\u8D77\u300D\u6309\u94AE\u6587\u6848\uFF0C\u9ED8\u8BA4 'Show less' */\n tileCollapseText?: string\n /** shelf-prices-tag\uFF08\u6298\u6263\u4EF7\u683C\u6807\u7B7E\uFF09\u662F\u5426\u663E\u793A\uFF0C\u9ED8\u8BA4 false\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n isShowPricesTag?: boolean\n /** shelf-prices-tag \u6587\u6848\u989C\u8272\uFF0C\u5EFA\u8BAE\u4F7F\u7528 Design Token CSS \u53D8\u91CF\uFF0C\u5982 var(--info-primary-color)\u3002\u8BBE\u7F6E\u540E\u4F1A\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n pricesTagTextColor?: string\n /** shelf-prices-tag \u80CC\u666F\u989C\u8272\uFF0C\u8BBE\u7F6E\u540E\u4F1A\u8986\u76D6\u9ED8\u8BA4\u7684\u54C1\u724C\u6E10\u53D8\u80CC\u666F\u5E76\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n pricesTagBgColor?: string\n /** shelf-items-tag\uFF08\u81EA\u5B9A\u4E49\u6807\u7B7E\uFF09\u6587\u6848\u989C\u8272\u3002\u8BBE\u7F6E\u540E\u4F1A\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n itemsTagTextColor?: string\n /** shelf-items-tag \u80CC\u666F\u989C\u8272\uFF0C\u8BBE\u7F6E\u540E\u4F1A\u8986\u76D6\u9ED8\u8BA4\u7684\u54C1\u724C\u6E10\u53D8\u80CC\u666F\u5E76\u9690\u85CF\u9ED8\u8BA4\u54C1\u724C\u8272\u63CF\u8FB9\u3002\u4EC5\u4F5C\u7528\u4E8E\u7EB5\u5411\u5361\u7247 ShelfDisplayWrapItem */\n itemsTagBgColor?: string\n}\n\n/**\n * \u4EF7\u683C\u6E32\u67D3\u4E0A\u4E0B\u6587\uFF1ArenderOriginalPrice / renderPrice \u7B49\u6E32\u67D3\u51FD\u6570\u5171\u4EAB\u7684\u683C\u5F0F\u5316\u4EF7\u683C\u4FE1\u606F\u3002\n * \u540E\u7EED\u5982\u9700\u5411\u6E32\u67D3\u51FD\u6570\u629B\u51FA\u66F4\u591A\u53C2\u6570\uFF0C\u76F4\u63A5\u5728\u672C\u7C7B\u578B\u4E2D\u8FFD\u52A0\u5B57\u6BB5\u5373\u53EF\uFF08\u5411\u540E\u517C\u5BB9\uFF09\u3002\n */\nexport interface ShelfDisplayPriceInfo {\n price: string\n basePrice: string | undefined\n discount: string | null\n discountAmount: string | undefined\n /** \u662F\u5426\u663E\u793A\u539F\u4EF7\uFF08\u6765\u6E90 data.isShowOriginalPrice\uFF0C\u9ED8\u8BA4 true\uFF09 */\n isShowOriginalPrice: boolean\n}\n\n/** renderPrice \u5B8C\u6574\u4E0A\u4E0B\u6587\uFF1A\u5728\u4EF7\u683C\u4FE1\u606F\u57FA\u7840\u4E0A\u8FFD\u52A0\u53D8\u4F53 / \u4F18\u60E0\u5238 / \u552E\u7F44\u72B6\u6001\u3002 */\nexport interface ShelfDisplayPriceRenderInfo extends ShelfDisplayPriceInfo {\n variant: any\n coupon: any\n isSoldOut: boolean\n}\n\n/**\n * renderPriceLabel \u4E0A\u4E0B\u6587\uFF1A\u7528\u4E8E\u5411\u4EF7\u683C\u6807\u7B7E\u6E32\u67D3\u51FD\u6570\u629B\u51FA\u914D\u7F6E\u4FE1\u606F\u3002\n * \u540E\u7EED\u6269\u5C55\u65F6\u5728\u6B64\u8FFD\u52A0\u5B57\u6BB5\u5373\u53EF\uFF08\u5411\u540E\u517C\u5BB9\uFF09\u3002\n */\nexport interface ShelfDisplayPriceLabelContext {\n /** \u662F\u5426\u663E\u793A\u539F\u4EF7\uFF08\u6765\u6E90 data.isShowOriginalPrice\uFF0C\u9ED8\u8BA4 true\uFF09 */\n isShowOriginalPrice: boolean\n}\n\nexport interface ShelfDisplayProps extends React.HTMLAttributes<HTMLDivElement> {\n data: ShelfDisplayType\n buildData?: {\n categories: any[]\n products: any[]\n }\n recommendedData?: any[]\n /**\n * \u6309\u94AE\u4E8B\u4EF6\n * @deprecated \u8BF7\u4F7F\u7528 onAddCart / onBuyNow / onLearnMore \u914D\u5408 primaryFun / secondaryFun \u66FF\u4EE3\n */\n event?: EventType\n key?: string\n target?: '_self' | '_blank'\n breakpoints?: {\n [key: number]: {\n spaceBetween: number\n freeMode: boolean\n slidesPerView: number\n }\n }\n /** \u5143\u6570\u636E\uFF1A\u6298\u6263\u6587\u6848\uFF08discounts.off / discountsCopy.off\uFF09\u53CA\u793E\u5A92\u80CC\u4E66\u56FE\u6807\uFF08socialEndorsements: SocialEndorsementItem[]\uFF09 */\n metafields?: any\n isDisplayGudgments?: boolean\n isDisplayBackImage?: boolean\n\n /** \u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03 */\n onAddCart?: (params: ShelfDisplayItem, index: number, data: ShelfDisplayType, coupon: any) => void\n /** \u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03 */\n onBuyNow?: (params: ShelfDisplayItem, index: number, data: ShelfDisplayType, coupon: any) => void\n /** \u4E86\u89E3\u66F4\u591A\u56DE\u8C03 */\n onLearnMore?: (params: ShelfDisplayItem, index: number, data: ShelfDisplayType, coupon: any) => void\n /** \u81EA\u5B9A\u4E49\u4EF7\u683C\u683C\u5F0F\u5316\u51FD\u6570\uFF0C\u672A\u4F20\u5219\u4F7F\u7528\u9ED8\u8BA4\u683C\u5F0F\u5316\u903B\u8F91 */\n formatPrice?: FormattedPriceFunc\n /**\n * \u539F\u4EF7\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5728\u539F\u4EF7\u4F4D\u7F6E\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\uFF08\u5982\u6298\u6263\u4FE1\u606F\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u539F\u4EF7\u6E32\u67D3\uFF08\u5212\u7EBF\u4EF7\uFF09\u3002\n * @param item - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param priceInfo - \u683C\u5F0F\u5316\u540E\u7684\u4EF7\u683C\u4FE1\u606F\uFF08\u542B isShowOriginalPrice\uFF09\n */\n renderOriginalPrice?: (item: ShelfDisplayItem, priceInfo: ShelfDisplayPriceInfo) => React.ReactNode\n /**\n * \u4EF7\u683C\u6807\u7B7E\u6E32\u67D3\u51FD\u6570\uFF0C\u5728\u4EF7\u683C\u4E0B\u65B9\u5C55\u793A\u81EA\u5B9A\u4E49\u5185\u5BB9\u3002\n * \u4E0D\u4F20\u65F6\u4E0D\u5C55\u793A\u3002\n * @param item - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param variant - \u5F53\u524D\u5339\u914D\u7684\u53D8\u4F53\u6570\u636E\n * @param context - \u6E32\u67D3\u4E0A\u4E0B\u6587\uFF08\u542B isShowOriginalPrice\uFF0C\u540E\u7EED\u53EF\u6269\u5C55\u66F4\u591A\u5B57\u6BB5\uFF09\n */\n renderPriceLabel?: (item: ShelfDisplayItem, variant: any, context?: ShelfDisplayPriceLabelContext) => React.ReactNode\n /**\n * \u4EF7\u683C\u533A\u57DF\u6E32\u67D3\u51FD\u6570\uFF0C\u7528\u4E8E\u5B8C\u5168\u81EA\u5B9A\u4E49\u4EF7\u683C\u533A\u57DF\uFF08\u5305\u62EC\u6700\u7EC8\u4EF7\u683C\u3001\u539F\u4EF7\u3001\u552E\u7F44\u72B6\u6001\u7B49\uFF09\u3002\n * \u4E0D\u4F20\u65F6\u4F7F\u7528\u9ED8\u8BA4\u7684\u4EF7\u683C\u6E32\u67D3\u903B\u8F91\u3002\n * @param item - \u5F53\u524D\u4EA7\u54C1\u6570\u636E\n * @param priceInfo - \u683C\u5F0F\u5316\u540E\u7684\u4EF7\u683C\u4FE1\u606F\u53CA\u4E0A\u4E0B\u6587\uFF08\u542B isShowOriginalPrice\uFF09\n */\n renderPrice?: (item: ShelfDisplayItem, priceInfo: ShelfDisplayPriceRenderInfo) => React.ReactNode\n}\n"],
|
|
5
5
|
"mappings": "AAAA,OAAOA,MAAa,aAGpB,OAAS,gBAAAC,EAAc,eAAAC,EAAa,qBAAAC,MAAyB,yBAUtD,SAASC,EAAmB,CACjC,OAAAC,EACA,WAAAC,EACA,aAAAC,EACA,gBAAAC,EACA,OAAAC,EACA,sBAAAC,EACA,sBAAAC,EACA,oBAAAC,EACA,kBAAAC,CACF,EAUG,CACD,GAAI,OAAO,KAAS,IAClB,MAAO,CACL,MAAO,GAAGZ,EAAaQ,CAAM,CAAC,GAAGJ,CAAM,GACvC,UAAW,GAAGJ,EAAaQ,CAAM,CAAC,GAAGH,CAAU,GAC/C,SAAU,GAAGL,EAAaQ,CAAM,CAAC,GAAGH,EAAaD,GAAU,CAAC,EAC9D,EAGF,MAAMS,EAAcR,EAAaD,EACjC,IAAIU,EAAW,KACf,MAAMC,EAAgBb,EAAkBM,CAAM,EAC9C,GAAIO,EAAe,CACjB,MAAMC,EAAiB,IAAI,KAAK,aAAaD,EAAe,CAC1D,MAAO,SACT,CAAC,EACDD,EAAWD,EAAcG,EAAe,QAAQX,EAAaD,GAAUC,CAAU,EAAI,IACvF,CAEA,IAAIY,EACJ,GAAIJ,EAAa,CACf,MAAMK,EAAkB,IAAInB,EAAQM,CAAU,EAAE,IAAID,GAAU,CAAC,EAAE,SAAS,EAC1Ea,EAAiBL,EACbA,EAAkB,CAAE,OAAQM,EAAiB,OAAAV,CAAO,CAAC,EACrDP,EAAY,CACV,OAAQiB,EACR,gBAAAX,EACA,aAAcD,GAAgB,MAC9B,OAAAE,EACA,sBAAuB,CACzB,CAAC,CACP,CAEA,MAAMW,EAAQP,EACVA,EAAkB,CAAE,OAAAR,EAAQ,OAAAI,CAAO,CAAC,EACpCP,EAAY,CAAE,OAAAG,EAAQ,aAAAE,EAAc,gBAAAC,EAAiB,OAAAC,EAAQ,oBAAAG,CAAoB,CAAC,EAChFS,EAAYP,EACdD,EACEA,EAAkB,CAAE,OAAQP,EAAY,OAAAG,CAAO,CAAC,EAChDP,EAAY,CACV,OAAQI,EACR,aAAAC,EACA,gBAAAC,EACA,OAAAC,EACA,sBAAAC,EACA,sBAAAC,EACA,oBAAAC,CACF,CAAC,EACH,OAEJ,MAAO,CAAE,MAAAQ,EAAO,UAAAC,EAAW,SAAAN,EAAU,eAAAG,CAAe,CACtD",
|
|
6
6
|
"names": ["Decimal", "PRICE_SYMBOL", "formatPrice", "languageTerritory", "formatVariantPrice", "amount", "baseAmount", "currencyCode", "currencyDisplay", "locale", "maximumFractionDigits", "minimumFractionDigits", "removeTrailingZeros", "customFormatPrice", "hasDiscount", "discount", "currentLocale", "formatDiscount", "discountAmount", "savePriceAmount", "price", "basePrice"]
|
|
7
7
|
}
|