@anker-in/headless-ui 1.1.95 → 1.1.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/biz-components/PromotionalBar/index.js +1 -1
- package/dist/cjs/biz-components/PromotionalBar/index.js.map +3 -3
- package/dist/cjs/biz-components/SceneShelfV2/index.d.ts +4 -0
- package/dist/cjs/biz-components/SceneShelfV2/index.js +1 -1
- package/dist/cjs/biz-components/SceneShelfV2/index.js.map +2 -2
- package/dist/cjs/biz-components/Title/index.js +1 -1
- package/dist/cjs/biz-components/Title/index.js.map +2 -2
- package/dist/esm/biz-components/PromotionalBar/index.js +1 -1
- package/dist/esm/biz-components/PromotionalBar/index.js.map +3 -3
- package/dist/esm/biz-components/SceneShelfV2/index.d.ts +4 -0
- package/dist/esm/biz-components/SceneShelfV2/index.js +1 -1
- package/dist/esm/biz-components/SceneShelfV2/index.js.map +2 -2
- package/dist/esm/biz-components/Title/index.js +1 -1
- package/dist/esm/biz-components/Title/index.js.map +2 -2
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";"use client";var
|
|
1
|
+
"use strict";"use client";var N=Object.create;var g=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var R=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var L=(t,e)=>{for(var n in e)g(t,n,{get:e[n],enumerable:!0})},h=(t,e,n,p)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of y(e))!F.call(t,r)&&r!==n&&g(t,r,{get:()=>e[r],enumerable:!(p=D(e,r))||p.enumerable});return t};var U=(t,e,n)=>(n=t!=null?N(R(t)):{},h(e||!t||!t.__esModule?g(n,"default",{value:t,enumerable:!0}):n,t)),$=t=>h(g({},"__esModule",{value:!0}),t);var S={};L(S,{default:()=>z});module.exports=$(S);var i=require("react/jsx-runtime"),b=U(require("react")),m=require("../../helpers/index.js"),u=require("../../components/index.js"),v=require("../../shared/Styles.js"),B=require("../../helpers/index.js"),P=require("../AiuiProvider/index.js"),T=require("../../shared/trackUrlRef.js");const w="image",H="PromotionalBar",I=t=>{if(!t)return;const{mobile:e,tablet:n,laptop:p,desktop:r,lgDesktop:x}=t,o=[],s=M=>M?.url,a=s(x),l=s(r),c=s(p),d=s(n),f=s(e);return a?o.push(a):l?o.push(l):c?o.push(c):d?o.push(d):f&&o.push(f),l&&a&&o.push(`${l} 1920`),c&&(l||a)&&o.push(`${c} 1440`),d&&(c||l||a)&&o.push(`${d} 1024`),f&&(d||c||l||a)&&o.push(`${f} 768`),o.length>0?o.join(", "):void 0},k=b.forwardRef(({classNames:t,data:e,className:n,...p},r)=>{const{locale:x="us",pageHandle:o}=(0,P.useAiuiContext)(),{backgroundImage:s,theme:a="dark"}=e,l=b.useMemo(()=>I(s),[s]);return(0,i.jsx)("div",{ref:r,...p,className:(0,m.cn)("laptop:h-[192px] lg-desktop:h-[240px] h-[240px] text-[#080A0F]",{"text-[#F5F6F7]":a==="dark"},t?.root,n),children:(0,i.jsxs)("div",{className:"promotional-bar-content rounded-card relative h-full overflow-hidden",children:[(0,i.jsxs)("div",{className:(0,m.cn)("laptop:px-8 laptop:justify-center lg-desktop:max-w-[620px] laptop:max-w-[392px] desktop:max-w-[584px] laptop:py-0 tablet:px-8 laptop:pr-0 relative z-20 flex h-full flex-col p-4",t?.content),children:[e.contentTitle&&(0,i.jsx)(u.Heading,{className:(0,m.cn)("line-clamp-2 ",t?.title),html:e.contentTitle,size:3}),e.contentDesc&&(0,i.jsx)("p",{className:(0,m.cn)("laptop:text-[16px] laptop:mt-2 lg-desktop:text-[18px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] ",t?.description),dangerouslySetInnerHTML:{__html:e.contentDesc}}),(0,i.jsx)("div",{className:"laptop:mt-4 mt-2",children:e.buttonText&&(0,i.jsx)(u.Button,{as:"a",variant:"link",className:(0,m.cn)("!p-0 text-[#F5F6F7]",{"text-[#080A0F]":a==="light"},t?.button),href:(0,T.trackUrlRef)((0,B.getLocalizedPath)(e.buttonLink||"",x),`${o}_${w}_${H}`),iconClassName:"size-4",children:e.buttonText})})]}),(0,i.jsx)(u.Picture,{source:l,className:"absolute inset-0 z-10 ",imgClassName:"h-full object-cover transition-transform duration-300 ease-in-out hover:scale-[1.05]"})]})})});k.displayName="PromotionalBar";var z=(0,v.withLayout)(k);
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/PromotionalBar/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Heading, Button, Picture } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { Media, Theme } from '../../types/props.js'\nimport { getLocalizedPath } from '../../helpers/index.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\n\nexport interface PromotionalBarSemanticName {\n root: 'root'\n content: 'content'\n title: 'title'\n description: 'description'\n button: 'button'\n}\n\n/**\n * \u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u914D\u7F6E\n */\nexport interface ResponsiveBackgroundImage {\n /** \u79FB\u52A8\u7AEF\u56FE\u7247 (<768px) */\n mobile?: Media\n /** \u5E73\u677F\u56FE\u7247 (768-1440px) */\n tablet?: Media\n /** \u7B14\u8BB0\u672C\u56FE\u7247 (1025-1440px) */\n laptop?: Media\n /** \u684C\u9762\u56FE\u7247 (1441-1920px) */\n desktop?: Media\n /** \u8D85\u5927\u684C\u9762\u56FE\u7247 (\u22651921px) */\n lgDesktop?: Media\n}\n\n/**\n * PromotionalBar \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3\n */\nexport interface PromotionalBarData {\n theme: Theme\n /** \u7EC4\u4EF6\u5185\u5BB9\u6807\u9898 */\n contentTitle?: string\n /** \u7EC4\u4EF6\u5185\u5BB9\u63CF\u8FF0 */\n contentDesc?: string\n /** \u6309\u94AE\u6587\u672C */\n buttonText?: string\n /** \u6309\u94AE\u94FE\u63A5 */\n buttonLink?: string\n /** \u80CC\u666F\u56FE\u7247 - \u54CD\u5E94\u5F0F\u56FE\u7247\u5BF9\u8C61 */\n backgroundImage?: ResponsiveBackgroundImage\n}\n\nexport interface PromotionalBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: PromotionalBarData\n classNames?: Partial<Record<keyof PromotionalBarSemanticName, string>>\n}\n\n/**\n * \u5C06\u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u5BF9\u8C61\u8F6C\u6362\u4E3A Picture \u7EC4\u4EF6\u6240\u9700\u7684\u5B57\u7B26\u4E32\u683C\u5F0F\n */\nconst convertResponsiveImageToString = (backgroundImage: ResponsiveBackgroundImage | undefined): string | undefined => {\n if (!backgroundImage) return undefined\n\n const { mobile, tablet, laptop, desktop, lgDesktop } = backgroundImage\n const parts: string[] = []\n\n // \u8F85\u52A9\u51FD\u6570\uFF1A\u4ECE Media \u5BF9\u8C61\u4E2D\u63D0\u53D6 URL\n const getUrl = (media: Media | undefined): string | undefined => {\n return media?.url\n }\n\n // \u9ED8\u8BA4\u56FE\u7247\uFF08\u6700\u5927\u5C3A\u5BF8\uFF09\u653E\u5728\u6700\u524D\u9762\uFF0C\u4E0D\u9700\u8981\u65AD\u70B9\n const lgDesktopUrl = getUrl(lgDesktop)\n const desktopUrl = getUrl(desktop)\n const laptopUrl = getUrl(laptop)\n const tabletUrl = getUrl(tablet)\n const mobileUrl = getUrl(mobile)\n\n if (lgDesktopUrl) parts.push(lgDesktopUrl)\n else if (desktopUrl) parts.push(desktopUrl)\n else if (laptopUrl) parts.push(laptopUrl)\n else if (tabletUrl) parts.push(tabletUrl)\n else if (mobileUrl) parts.push(mobileUrl)\n\n // \u6309\u65AD\u70B9\u4ECE\u5927\u5230\u5C0F\u6DFB\u52A0\n if (desktopUrl && lgDesktopUrl) parts.push(`${desktopUrl} 1920`)\n if (laptopUrl && (desktopUrl || lgDesktopUrl)) parts.push(`${laptopUrl} 1440`)\n if (tabletUrl && (laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${tabletUrl} 1024`)\n if (mobileUrl && (tabletUrl || laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${mobileUrl} 768`)\n\n return parts.length > 0 ? parts.join(', ') : undefined\n}\n\n/**\n * PromotionalBar - \u63A8\u5E7F\u680F\n *\n * @description \u63A8\u5E7F\u680F\n */\nconst PromotionalBar = React.forwardRef<HTMLDivElement, PromotionalBarProps>(\n ({ classNames, data, className, ...rest }, ref) => {\n const { locale = 'us' } = useAiuiContext()\n const { backgroundImage, theme = 'dark' } = data\n const pictureSource = React.useMemo(() => {\n return convertResponsiveImageToString(backgroundImage)\n }, [backgroundImage])\n return (\n <div\n ref={ref}\n {...rest}\n className={cn(\n 'laptop:h-[192px] lg-desktop:h-[240px] h-[240px] text-[#080A0F]',\n {\n 'text-[#F5F6F7]': theme === 'dark',\n },\n classNames?.root,\n className\n )}\n >\n {/* \u63A8\u5E7F\u680F\u5185\u5BB9\u533A\u57DF - \u6839\u636E\u5177\u4F53\u4E1A\u52A1\u9700\u6C42\u5B9A\u5236 */}\n <div className=\"promotional-bar-content rounded-card relative h-full overflow-hidden\">\n <div\n className={cn(\n 'laptop:px-8 laptop:justify-center lg-desktop:max-w-[620px] laptop:max-w-[392px] desktop:max-w-[584px] laptop:py-0 tablet:px-8 laptop:pr-0 relative z-20 flex h-full flex-col p-4',\n classNames?.content\n )}\n >\n {data.contentTitle && (\n <Heading className={cn('line-clamp-2 ', classNames?.title)} html={data.contentTitle} size={3} />\n )}\n {data.contentDesc && (\n <p\n className={cn(\n 'laptop:text-[16px] laptop:mt-2 lg-desktop:text-[18px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] ',\n classNames?.description\n )}\n dangerouslySetInnerHTML={{ __html: data.contentDesc }}\n />\n )}\n <div className=\"laptop:mt-4 mt-2\">\n {data.buttonText && (\n <Button\n as=\"a\"\n variant=\"link\"\n className={cn(\n '!p-0 text-[#F5F6F7]',\n {\n 'text-[#080A0F]': theme === 'light',\n },\n classNames?.button\n )}\n href={getLocalizedPath(data.buttonLink || '', locale)}\n iconClassName=\"size-4\"\n >\n {data.buttonText}\n </Button>\n )}\n </div>\n </div>\n <Picture\n source={pictureSource}\n className=\"absolute inset-0 z-10 \"\n imgClassName=\"h-full object-cover transition-transform duration-300 ease-in-out hover:scale-[1.05]\"\n />\n </div>\n </div>\n )\n }\n)\n\nPromotionalBar.displayName = 'PromotionalBar'\nexport default withLayout(PromotionalBar)\n"],
|
|
5
|
-
"mappings": "ukBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,
|
|
6
|
-
"names": ["PromotionalBar_exports", "__export", "PromotionalBar_default", "__toCommonJS", "import_jsx_runtime", "React", "import_helpers", "import_components", "import_Styles", "import_AiuiProvider", "convertResponsiveImageToString", "backgroundImage", "mobile", "tablet", "laptop", "desktop", "lgDesktop", "parts", "getUrl", "media", "lgDesktopUrl", "desktopUrl", "laptopUrl", "tabletUrl", "mobileUrl", "PromotionalBar", "classNames", "data", "className", "rest", "ref", "locale", "theme", "pictureSource"]
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Heading, Button, Picture } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { Media, Theme } from '../../types/props.js'\nimport { getLocalizedPath } from '../../helpers/index.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\n\nexport interface PromotionalBarSemanticName {\n root: 'root'\n content: 'content'\n title: 'title'\n description: 'description'\n button: 'button'\n}\n\n/**\n * \u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u914D\u7F6E\n */\nexport interface ResponsiveBackgroundImage {\n /** \u79FB\u52A8\u7AEF\u56FE\u7247 (<768px) */\n mobile?: Media\n /** \u5E73\u677F\u56FE\u7247 (768-1440px) */\n tablet?: Media\n /** \u7B14\u8BB0\u672C\u56FE\u7247 (1025-1440px) */\n laptop?: Media\n /** \u684C\u9762\u56FE\u7247 (1441-1920px) */\n desktop?: Media\n /** \u8D85\u5927\u684C\u9762\u56FE\u7247 (\u22651921px) */\n lgDesktop?: Media\n}\n\n/**\n * PromotionalBar \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3\n */\nexport interface PromotionalBarData {\n theme: Theme\n /** \u7EC4\u4EF6\u5185\u5BB9\u6807\u9898 */\n contentTitle?: string\n /** \u7EC4\u4EF6\u5185\u5BB9\u63CF\u8FF0 */\n contentDesc?: string\n /** \u6309\u94AE\u6587\u672C */\n buttonText?: string\n /** \u6309\u94AE\u94FE\u63A5 */\n buttonLink?: string\n /** \u80CC\u666F\u56FE\u7247 - \u54CD\u5E94\u5F0F\u56FE\u7247\u5BF9\u8C61 */\n backgroundImage?: ResponsiveBackgroundImage\n}\n\nexport interface PromotionalBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: PromotionalBarData\n classNames?: Partial<Record<keyof PromotionalBarSemanticName, string>>\n}\n\nconst componentType = 'image'\nconst componentName = 'PromotionalBar'\n\n/**\n * \u5C06\u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u5BF9\u8C61\u8F6C\u6362\u4E3A Picture \u7EC4\u4EF6\u6240\u9700\u7684\u5B57\u7B26\u4E32\u683C\u5F0F\n */\nconst convertResponsiveImageToString = (backgroundImage: ResponsiveBackgroundImage | undefined): string | undefined => {\n if (!backgroundImage) return undefined\n\n const { mobile, tablet, laptop, desktop, lgDesktop } = backgroundImage\n const parts: string[] = []\n\n // \u8F85\u52A9\u51FD\u6570\uFF1A\u4ECE Media \u5BF9\u8C61\u4E2D\u63D0\u53D6 URL\n const getUrl = (media: Media | undefined): string | undefined => {\n return media?.url\n }\n\n // \u9ED8\u8BA4\u56FE\u7247\uFF08\u6700\u5927\u5C3A\u5BF8\uFF09\u653E\u5728\u6700\u524D\u9762\uFF0C\u4E0D\u9700\u8981\u65AD\u70B9\n const lgDesktopUrl = getUrl(lgDesktop)\n const desktopUrl = getUrl(desktop)\n const laptopUrl = getUrl(laptop)\n const tabletUrl = getUrl(tablet)\n const mobileUrl = getUrl(mobile)\n\n if (lgDesktopUrl) parts.push(lgDesktopUrl)\n else if (desktopUrl) parts.push(desktopUrl)\n else if (laptopUrl) parts.push(laptopUrl)\n else if (tabletUrl) parts.push(tabletUrl)\n else if (mobileUrl) parts.push(mobileUrl)\n\n // \u6309\u65AD\u70B9\u4ECE\u5927\u5230\u5C0F\u6DFB\u52A0\n if (desktopUrl && lgDesktopUrl) parts.push(`${desktopUrl} 1920`)\n if (laptopUrl && (desktopUrl || lgDesktopUrl)) parts.push(`${laptopUrl} 1440`)\n if (tabletUrl && (laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${tabletUrl} 1024`)\n if (mobileUrl && (tabletUrl || laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${mobileUrl} 768`)\n\n return parts.length > 0 ? parts.join(', ') : undefined\n}\n\n/**\n * PromotionalBar - \u63A8\u5E7F\u680F\n *\n * @description \u63A8\u5E7F\u680F\n */\nconst PromotionalBar = React.forwardRef<HTMLDivElement, PromotionalBarProps>(\n ({ classNames, data, className, ...rest }, ref) => {\n const { locale = 'us', pageHandle } = useAiuiContext()\n const { backgroundImage, theme = 'dark' } = data\n const pictureSource = React.useMemo(() => {\n return convertResponsiveImageToString(backgroundImage)\n }, [backgroundImage])\n return (\n <div\n ref={ref}\n {...rest}\n className={cn(\n 'laptop:h-[192px] lg-desktop:h-[240px] h-[240px] text-[#080A0F]',\n {\n 'text-[#F5F6F7]': theme === 'dark',\n },\n classNames?.root,\n className\n )}\n >\n {/* \u63A8\u5E7F\u680F\u5185\u5BB9\u533A\u57DF - \u6839\u636E\u5177\u4F53\u4E1A\u52A1\u9700\u6C42\u5B9A\u5236 */}\n <div className=\"promotional-bar-content rounded-card relative h-full overflow-hidden\">\n <div\n className={cn(\n 'laptop:px-8 laptop:justify-center lg-desktop:max-w-[620px] laptop:max-w-[392px] desktop:max-w-[584px] laptop:py-0 tablet:px-8 laptop:pr-0 relative z-20 flex h-full flex-col p-4',\n classNames?.content\n )}\n >\n {data.contentTitle && (\n <Heading className={cn('line-clamp-2 ', classNames?.title)} html={data.contentTitle} size={3} />\n )}\n {data.contentDesc && (\n <p\n className={cn(\n 'laptop:text-[16px] laptop:mt-2 lg-desktop:text-[18px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] ',\n classNames?.description\n )}\n dangerouslySetInnerHTML={{ __html: data.contentDesc }}\n />\n )}\n <div className=\"laptop:mt-4 mt-2\">\n {data.buttonText && (\n <Button\n as=\"a\"\n variant=\"link\"\n className={cn(\n '!p-0 text-[#F5F6F7]',\n {\n 'text-[#080A0F]': theme === 'light',\n },\n classNames?.button\n )}\n href={trackUrlRef(\n getLocalizedPath(data.buttonLink || '', locale),\n `${pageHandle}_${componentType}_${componentName}`\n )}\n iconClassName=\"size-4\"\n >\n {data.buttonText}\n </Button>\n )}\n </div>\n </div>\n <Picture\n source={pictureSource}\n className=\"absolute inset-0 z-10 \"\n imgClassName=\"h-full object-cover transition-transform duration-300 ease-in-out hover:scale-[1.05]\"\n />\n </div>\n </div>\n )\n }\n)\n\nPromotionalBar.displayName = 'PromotionalBar'\nexport default withLayout(PromotionalBar)\n"],
|
|
5
|
+
"mappings": "ukBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,GA4HU,IAAAI,EAAA,6BA1HVC,EAAuB,oBACvBC,EAAmB,kCACnBC,EAAyC,qCACzCC,EAA2B,kCAE3BF,EAAiC,kCACjCG,EAA+B,oCAC/BC,EAA4B,uCAiD5B,MAAMC,EAAgB,QAChBC,EAAgB,iBAKhBC,EAAkCC,GAA+E,CACrH,GAAI,CAACA,EAAiB,OAEtB,KAAM,CAAE,OAAAC,EAAQ,OAAAC,EAAQ,OAAAC,EAAQ,QAAAC,EAAS,UAAAC,CAAU,EAAIL,EACjDM,EAAkB,CAAC,EAGnBC,EAAUC,GACPA,GAAO,IAIVC,EAAeF,EAAOF,CAAS,EAC/BK,EAAaH,EAAOH,CAAO,EAC3BO,EAAYJ,EAAOJ,CAAM,EACzBS,EAAYL,EAAOL,CAAM,EACzBW,EAAYN,EAAON,CAAM,EAE/B,OAAIQ,EAAcH,EAAM,KAAKG,CAAY,EAChCC,EAAYJ,EAAM,KAAKI,CAAU,EACjCC,EAAWL,EAAM,KAAKK,CAAS,EAC/BC,EAAWN,EAAM,KAAKM,CAAS,EAC/BC,GAAWP,EAAM,KAAKO,CAAS,EAGpCH,GAAcD,GAAcH,EAAM,KAAK,GAAGI,CAAU,OAAO,EAC3DC,IAAcD,GAAcD,IAAeH,EAAM,KAAK,GAAGK,CAAS,OAAO,EACzEC,IAAcD,GAAaD,GAAcD,IAAeH,EAAM,KAAK,GAAGM,CAAS,OAAO,EACtFC,IAAcD,GAAaD,GAAaD,GAAcD,IAAeH,EAAM,KAAK,GAAGO,CAAS,MAAM,EAE/FP,EAAM,OAAS,EAAIA,EAAM,KAAK,IAAI,EAAI,MAC/C,EAOMQ,EAAiBvB,EAAM,WAC3B,CAAC,CAAE,WAAAwB,EAAY,KAAAC,EAAM,UAAAC,EAAW,GAAGC,CAAK,EAAGC,IAAQ,CACjD,KAAM,CAAE,OAAAC,EAAS,KAAM,WAAAC,CAAW,KAAI,kBAAe,EAC/C,CAAE,gBAAArB,EAAiB,MAAAsB,EAAQ,MAAO,EAAIN,EACtCO,EAAgBhC,EAAM,QAAQ,IAC3BQ,EAA+BC,CAAe,EACpD,CAACA,CAAe,CAAC,EACpB,SACE,OAAC,OACC,IAAKmB,EACJ,GAAGD,EACJ,aAAW,MACT,iEACA,CACE,iBAAkBI,IAAU,MAC9B,EACAP,GAAY,KACZE,CACF,EAGA,oBAAC,OAAI,UAAU,uEACb,qBAAC,OACC,aAAW,MACT,mLACAF,GAAY,OACd,EAEC,UAAAC,EAAK,iBACJ,OAAC,WAAQ,aAAW,MAAG,gBAAiBD,GAAY,KAAK,EAAG,KAAMC,EAAK,aAAc,KAAM,EAAG,EAE/FA,EAAK,gBACJ,OAAC,KACC,aAAW,MACT,+GACAD,GAAY,WACd,EACA,wBAAyB,CAAE,OAAQC,EAAK,WAAY,EACtD,KAEF,OAAC,OAAI,UAAU,mBACZ,SAAAA,EAAK,eACJ,OAAC,UACC,GAAG,IACH,QAAQ,OACR,aAAW,MACT,sBACA,CACE,iBAAkBM,IAAU,OAC9B,EACAP,GAAY,MACd,EACA,QAAM,kBACJ,oBAAiBC,EAAK,YAAc,GAAII,CAAM,EAC9C,GAAGC,CAAU,IAAIxB,CAAa,IAAIC,CAAa,EACjD,EACA,cAAc,SAEb,SAAAkB,EAAK,WACR,EAEJ,GACF,KACA,OAAC,WACC,OAAQO,EACR,UAAU,yBACV,aAAa,uFACf,GACF,EACF,CAEJ,CACF,EAEAT,EAAe,YAAc,iBAC7B,IAAO1B,KAAQ,cAAW0B,CAAc",
|
|
6
|
+
"names": ["PromotionalBar_exports", "__export", "PromotionalBar_default", "__toCommonJS", "import_jsx_runtime", "React", "import_helpers", "import_components", "import_Styles", "import_AiuiProvider", "import_trackUrlRef", "componentType", "componentName", "convertResponsiveImageToString", "backgroundImage", "mobile", "tablet", "laptop", "desktop", "lgDesktop", "parts", "getUrl", "media", "lgDesktopUrl", "desktopUrl", "laptopUrl", "tabletUrl", "mobileUrl", "PromotionalBar", "classNames", "data", "className", "rest", "ref", "locale", "pageHandle", "theme", "pictureSource"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";"use client";var te=Object.create;var H=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,re=Object.prototype.hasOwnProperty;var ne=(e,i)=>{for(var a in i)H(e,a,{get:i[a],enumerable:!0})},G=(e,i,a,m)=>{if(i&&typeof i=="object"||typeof i=="function")for(let u of oe(i))!re.call(e,u)&&u!==a&&H(e,u,{get:()=>i[u],enumerable:!(m=ie(i,u))||m.enumerable});return e};var U=(e,i,a)=>(a=e!=null?te(ae(e)):{},G(i||!e||!e.__esModule?H(a,"default",{value:e,enumerable:!0}):a,e)),se=e=>G(H({},"__esModule",{value:!0}),e);var me={};ne(me,{SceneShelfV2ProductCard:()=>V,default:()=>ue});module.exports=se(me);var t=require("react/jsx-runtime"),n=U(require("react")),r=require("../../helpers/index.js"),l=require("../../components/index.js"),K=U(require("../Media/index.js")),j=require("swiper/react"),$=require("swiper/modules"),ge=require("swiper/css"),ve=require("swiper/css/navigation"),Q=require("../../shared/Styles.js"),q=require("../../hooks/useGridRowCount.js"),J=require("../../hooks/useExposure.js"),X=require("../../hooks/useViewItemList.js"),Y=require("../../shared/trackUrlRef.js"),F=require("../AiuiProvider/index.js"),T=require("../../shared/track.js");const le="shelf",ce="scene_shelf_v2",de=()=>(0,t.jsx)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:(0,t.jsx)("path",{d:"M8 5.14v13.72L19 12 8 5.14z",fill:"white"})}),pe=()=>(0,t.jsxs)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[(0,t.jsx)("rect",{x:"6",y:"5",width:"4",height:"14",rx:"1",fill:"white"}),(0,t.jsx)("rect",{x:"14",y:"5",width:"4",height:"14",rx:"1",fill:"white"})]}),V=n.memo(({product:e,isShowTag:i=!0,onImageClick:a,onLearnMore:m,onShopNow:u,onAddToCart:S,secondaryButtonText:h,secondaryButtonFun:x,primaryButtonText:b,primaryButtonFun:P,classNames:c,className:s,theme:N,index:d})=>{const{locale:B="us",trackingData:L}=(0,F.useAiuiContext)(),[M,z]=n.useState(!1),[k,I]=n.useState(!1),f=L?.pageGroup,y=n.useCallback(async(p,_)=>{if(!p)return;const C=_==="primary"?z:I;C(!0);try{switch(p){case"buyNow":await u?.(e);break;case"addCart":await S?.(e);break;case"learnMore":await m?.(e?.href??"");break;default:break}}finally{C(!1)}},[m,u,S,e]),R=n.useCallback(()=>y(P,"primary"),[y,P]),E=n.useCallback(()=>y(x,"secondary"),[y,x]),g=n.useCallback(p=>{!e.href&&a&&p.preventDefault(),a?.(e),(0,T.gaTrack)({event:"ga4Event",event_name:"select_item",item_list_name:"Scene_Shelf_2_Products",page_group:f,items:[{item_id:e.sku,item_name:e.title,item_variant:e.variantId,price:e.currentPrice,index:d}]})},[d,a,f,e]);return(0,t.jsxs)("div",{className:(0,r.cn)("scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4",s,c?.productCard,{"bg-container-secondary-0":N==="dark"}),children:[e.href?(0,t.jsx)("a",{href:(0,r.getLocalizedPath)((0,Y.trackUrlRef)(e.href,f+"_"+le+"_"+ce),B),onClick:g,className:(0,r.cn)("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80",c?.productCardImage),"aria-label":`View ${e.title}`,children:(0,t.jsx)(l.Picture,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}):(0,t.jsx)("div",{className:(0,r.cn)("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ",a&&"cursor-pointer transition-opacity hover:opacity-80",c?.productCardImage),onClick:a?g:void 0,role:a?"button":void 0,tabIndex:a?0:void 0,"aria-label":a?`View ${e.title}`:void 0,children:(0,t.jsx)(l.Picture,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}),(0,t.jsxs)("div",{className:"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4",children:[(0,t.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,t.jsx)("div",{className:(0,r.cn)("scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1",c?.productCardTags),children:i&&e?.tags?.map((p,_)=>(0,t.jsx)(l.Badge,{variant:p.variant??"outline",size:"sm",className:"",children:p.label},_))}),(0,t.jsx)(l.Heading,{as:"h3",size:2,className:(0,r.cn)("scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]",c?.productCardTitle),children:e.title}),e.description&&(0,t.jsx)(l.Text,{as:"p",size:1,className:(0,r.cn)("scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1",c?.productCardDescription),children:e.description})]}),(0,t.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,t.jsxs)("div",{className:(0,r.cn)("scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1",c?.productCardPriceWrapper),children:[(0,t.jsx)(l.Heading,{as:"h6",size:2,className:(0,r.cn)("scene-shelf-v2-product-card-current-price text-info-primary",c?.productCardCurrentPrice),children:e.currentPrice}),e.originalPrice&&(0,t.jsx)(l.Heading,{as:"h6",size:2,className:(0,r.cn)("scene-shelf-v2-product-card-original-price text-info-tertiary line-through",c?.productCardOriginalPrice),children:e.originalPrice})]}),(h||b)&&(0,t.jsxs)("div",{className:(0,r.cn)("scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2",c?.productCardButtons),children:[h&&(0,t.jsx)(l.Button,{variant:"secondary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{E(),(0,T.gaTrack)({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:f||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:h,SKU:e.sku||"",position:d}})},disabled:e.soldOut&&x!=="learnMore",loading:k,children:h}),b&&(0,t.jsx)(l.Button,{variant:"primary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{R(),(0,T.gaTrack)({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:f||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:b,SKU:e.sku||"",position:d}})},disabled:e.soldOut&&P!=="learnMore",loading:M,children:b})]})]})]})]})});V.displayName="SceneShelfV2.ProductCard";const W=n.forwardRef(({className:e,classNames:i={},data:a,onPlayClick:m,onImageClick:u,onLearnMore:S,onShopNow:h,onAddToCart:x,...b},P)=>{const{theme:c="light",sceneImage:s,productsTitle:N,products:d,secondaryButtonText:B,secondaryButtonFun:L,primaryButtonText:M,primaryButtonFun:z,viewMoreLimit:k=2,copy:I}=a,f=n.useRef(null),y=n.useRef(null),R=n.useRef(null),[E,g]=n.useState(!1),[p,_]=n.useState(!1),{trackingData:C}=(0,F.useAiuiContext)();(0,J.useExposure)(y,{componentType:"image",componentName:"scene_shelf_banner"}),(0,X.useViewItemList)(R,{componentType:"video",componentName:"scene_shelf_banner",itemListName:"Scene_Shelf_2_Products",items:d.map((o,v)=>({item_id:o.sku??"",item_name:o.title,item_variant:o.variantId??"",price:o.currentPrice,index:v})),tabName:""});const A=(0,q.useGridRowCount)({rows:k??0,mobileCols:2}),O=n.useMemo(()=>[s?.pc,s?.desktop,s?.laptop,s?.pad,s?.mobile].some(o=>o?.mimeType==="video/mp4"),[s]),Z=n.useCallback(()=>{const o=f.current;o?o.paused?(o.play(),g(!0),m?.(!0)):(o.pause(),g(!1),m?.(!1)):m?.(!0),(0,T.gaTrack)({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:C?.pageGroup,component_type:"video",component_name:"scene_shelf_banner",position:1,creative_id:s?.pc?.id}})},[m,s?.pc?.id,C?.pageGroup]);return n.useEffect(()=>{const o=f.current;if(!o||!O)return;const v=new IntersectionObserver(w=>{w.forEach(D=>{D.isIntersecting?o.play().catch(ee=>{console.warn("Video autoplay failed:",ee)}):o.pause()})},{threshold:.5});return v.observe(o),()=>{v.disconnect()}},[]),(0,t.jsxs)("div",{...b,ref:P,className:(0,r.cn)("scene-shelf-v2-root w-full overflow-hidden",{"aiui-dark":c==="dark"},e,i?.root),children:[(0,t.jsxs)("div",{className:(0,r.cn)("scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden",i?.media),ref:y,children:[(0,t.jsx)(K.default,{pcImage:s?.pc,desktopImage:s?.desktop,laptopImage:s?.laptop,padImage:s?.pad,mobileImage:s?.mobile,className:"size-full",videoClassName:"absolute inset-0 size-full object-cover",videoRef:f,onVideoPlay:()=>g(!0),onVideoPause:()=>g(!1),onVideoEnded:()=>g(!1)}),(0,t.jsx)("div",{"aria-hidden":"true",className:(0,r.cn)("scene-shelf-v2-media-overlay pointer-events-none absolute inset-0",i?.mediaOverlay)}),O&&(0,t.jsx)("div",{className:"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6",children:(0,t.jsx)("button",{type:"button","aria-label":E?"Pause video":"Play video",onClick:Z,className:(0,r.cn)("scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80",i?.mediaPlayButton),children:E?(0,t.jsx)(pe,{}):(0,t.jsx)(de,{})})})]}),(0,t.jsxs)("div",{ref:R,className:(0,r.cn)("scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3",i?.products),children:[N&&(0,t.jsx)(l.Heading,{as:"h2",size:3,className:(0,r.cn)("scene-shelf-v2-products-title text-info-primary",i?.productsTitle),html:N}),(0,t.jsx)("div",{className:"tablet:hidden grid grid-cols-2 gap-3",children:(()=>{const o=k!==void 0&&k>0&&d.length>A,v=o&&!p?d.slice(0,A):d;return(0,t.jsxs)(t.Fragment,{children:[v.map((w,D)=>(0,t.jsx)(V,{isShowTag:a.isShowTag??!0,product:w,onImageClick:u,onLearnMore:S,onShopNow:h,onAddToCart:x,secondaryButtonText:B,secondaryButtonFun:L,primaryButtonText:M,primaryButtonFun:z,classNames:i,theme:c,index:D},w.productKey)),o&&(0,t.jsx)("div",{className:"col-span-2 mt-6 flex justify-center",children:(0,t.jsxs)("button",{type:"button",onClick:()=>_(w=>!w),className:"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors","aria-expanded":p,children:[p?I?.viewLessLabel??"View Less":I?.viewMoreLabel??"View More",(0,t.jsx)("svg",{className:(0,r.cn)("size-4 transition-transform",p&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]})})]})})()}),(0,t.jsx)("div",{className:"tablet:block hidden",children:(0,t.jsx)("div",{className:"relative",children:(0,t.jsx)(j.Swiper,{slidesPerView:"auto",observer:!0,observeParents:!0,modules:[$.Mousewheel],mousewheel:{enabled:!0,forceToAxis:!0,sensitivity:1},className:"!overflow-visible",breakpoints:{768:{spaceBetween:16,slidesPerView:d.length>3?2.3:2},1024:{spaceBetween:16,slidesPerView:d.length>3?2.8:3},1440:{spaceBetween:16,slidesPerView:d.length>4?3.8:4},1920:{spaceBetween:16,slidesPerView:d.length>4?3.8:4}},children:d.map((o,v)=>(0,t.jsx)(j.SwiperSlide,{className:(0,r.cn)("!h-auto ",i.productCardSlideWrapper),children:(0,t.jsx)(V,{product:o,isShowTag:a.isShowTag??!0,onImageClick:u,onLearnMore:S,onShopNow:h,onAddToCart:x,secondaryButtonText:B,secondaryButtonFun:L,primaryButtonText:M,primaryButtonFun:z,classNames:i,theme:c,index:v})},o.productKey))})})})]})]})});W.displayName="SceneShelfV2";var ue=(0,Q.withLayout)(W);
|
|
1
|
+
"use strict";"use client";var te=Object.create;var H=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty;var re=(e,i)=>{for(var a in i)H(e,a,{get:i[a],enumerable:!0})},G=(e,i,a,u)=>{if(i&&typeof i=="object"||typeof i=="function")for(let m of oe(i))!ne.call(e,m)&&m!==a&&H(e,m,{get:()=>i[m],enumerable:!(u=ie(i,m))||u.enumerable});return e};var U=(e,i,a)=>(a=e!=null?te(ae(e)):{},G(i||!e||!e.__esModule?H(a,"default",{value:e,enumerable:!0}):a,e)),se=e=>G(H({},"__esModule",{value:!0}),e);var ue={};re(ue,{SceneShelfV2ProductCard:()=>V,default:()=>me});module.exports=se(ue);var t=require("react/jsx-runtime"),r=U(require("react")),n=require("../../helpers/index.js"),l=require("../../components/index.js"),K=U(require("../Media/index.js")),j=require("swiper/react"),$=require("swiper/modules"),ge=require("swiper/css"),ve=require("swiper/css/navigation"),Q=require("../../shared/Styles.js"),q=require("../../hooks/useGridRowCount.js"),J=require("../../hooks/useExposure.js"),X=require("../../hooks/useViewItemList.js"),Y=require("../../shared/trackUrlRef.js"),F=require("../AiuiProvider/index.js"),T=require("../../shared/track.js");const le="shelf",ce="scene_shelf_v2",de=()=>(0,t.jsx)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:(0,t.jsx)("path",{d:"M8 5.14v13.72L19 12 8 5.14z",fill:"white"})}),pe=()=>(0,t.jsxs)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[(0,t.jsx)("rect",{x:"6",y:"5",width:"4",height:"14",rx:"1",fill:"white"}),(0,t.jsx)("rect",{x:"14",y:"5",width:"4",height:"14",rx:"1",fill:"white"})]}),V=r.memo(({product:e,isShowTag:i=!0,onImageClick:a,onLearnMore:u,onShopNow:m,onAddToCart:S,secondaryButtonText:h,secondaryButtonFun:x,primaryButtonText:b,primaryButtonFun:P,classNames:c,className:s,theme:N,index:d})=>{const{locale:B="us",trackingData:L}=(0,F.useAiuiContext)(),[M,z]=r.useState(!1),[_,I]=r.useState(!1),f=L?.pageGroup,y=r.useCallback(async(p,k)=>{if(!p)return;const C=k==="primary"?z:I;C(!0);try{switch(p){case"buyNow":await m?.(e);break;case"addCart":await S?.(e);break;case"learnMore":await u?.(e?.href??"");break;default:break}}finally{C(!1)}},[u,m,S,e]),R=r.useCallback(()=>y(P,"primary"),[y,P]),E=r.useCallback(()=>y(x,"secondary"),[y,x]),g=r.useCallback(p=>{!e.href&&a&&p.preventDefault(),a?.(e),(0,T.gaTrack)({event:"ga4Event",event_name:"select_item",item_list_name:"Scene_Shelf_2_Products",page_group:f,items:[{item_id:e.sku,item_name:e.custom_name||e.title,item_variant:e.variantId,price:e.currentPrice,index:d}]})},[d,a,f,e]);return(0,t.jsxs)("div",{className:(0,n.cn)("scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4",s,c?.productCard,{"bg-container-secondary-0":N==="dark"}),children:[e.href?(0,t.jsx)("a",{href:(0,n.getLocalizedPath)((0,Y.trackUrlRef)(e.href,f+"_"+le+"_"+ce),B),onClick:g,className:(0,n.cn)("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80",c?.productCardImage),"aria-label":`View ${e.title}`,children:(0,t.jsx)(l.Picture,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}):(0,t.jsx)("div",{className:(0,n.cn)("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ",a&&"cursor-pointer transition-opacity hover:opacity-80",c?.productCardImage),onClick:a?g:void 0,role:a?"button":void 0,tabIndex:a?0:void 0,"aria-label":a?`View ${e.title}`:void 0,children:(0,t.jsx)(l.Picture,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}),(0,t.jsxs)("div",{className:"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4",children:[(0,t.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,t.jsx)("div",{className:(0,n.cn)("scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1",c?.productCardTags),children:i&&e?.tags?.map((p,k)=>(0,t.jsx)(l.Badge,{variant:p.variant??"outline",size:"sm",className:"",children:p.label},k))}),(0,t.jsx)(l.Heading,{as:"h3",size:2,className:(0,n.cn)("scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]",c?.productCardTitle),children:e.custom_name||e.title}),(e.custom_description||e.description)&&(0,t.jsx)(l.Text,{as:"p",size:1,className:(0,n.cn)("scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1",c?.productCardDescription),children:e.custom_description||e.description})]}),(0,t.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,t.jsxs)("div",{className:(0,n.cn)("scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1",c?.productCardPriceWrapper),children:[(0,t.jsx)(l.Heading,{as:"h6",size:2,className:(0,n.cn)("scene-shelf-v2-product-card-current-price text-info-primary",c?.productCardCurrentPrice),children:e.currentPrice}),e.originalPrice&&(0,t.jsx)(l.Heading,{as:"h6",size:2,className:(0,n.cn)("scene-shelf-v2-product-card-original-price text-info-tertiary line-through",c?.productCardOriginalPrice),children:e.originalPrice})]}),(h||b)&&(0,t.jsxs)("div",{className:(0,n.cn)("scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2",c?.productCardButtons),children:[h&&(0,t.jsx)(l.Button,{variant:"secondary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{E(),(0,T.gaTrack)({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:f||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:h,SKU:e.sku||"",position:d}})},disabled:e.soldOut&&x!=="learnMore",loading:_,children:h}),b&&(0,t.jsx)(l.Button,{variant:"primary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{R(),(0,T.gaTrack)({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:f||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:b,SKU:e.sku||"",position:d}})},disabled:e.soldOut&&P!=="learnMore",loading:M,children:b})]})]})]})]})});V.displayName="SceneShelfV2.ProductCard";const W=r.forwardRef(({className:e,classNames:i={},data:a,onPlayClick:u,onImageClick:m,onLearnMore:S,onShopNow:h,onAddToCart:x,...b},P)=>{const{theme:c="light",sceneImage:s,productsTitle:N,products:d,secondaryButtonText:B,secondaryButtonFun:L,primaryButtonText:M,primaryButtonFun:z,viewMoreLimit:_=2,copy:I}=a,f=r.useRef(null),y=r.useRef(null),R=r.useRef(null),[E,g]=r.useState(!1),[p,k]=r.useState(!1),{trackingData:C}=(0,F.useAiuiContext)();(0,J.useExposure)(y,{componentType:"image",componentName:"scene_shelf_banner"}),(0,X.useViewItemList)(R,{componentType:"video",componentName:"scene_shelf_banner",itemListName:"Scene_Shelf_2_Products",items:d.map((o,v)=>({item_id:o.sku??"",item_name:o.title,item_variant:o.variantId??"",price:o.currentPrice,index:v})),tabName:""});const A=(0,q.useGridRowCount)({rows:_??0,mobileCols:2}),O=r.useMemo(()=>[s?.pc,s?.desktop,s?.laptop,s?.pad,s?.mobile].some(o=>o?.mimeType==="video/mp4"),[s]),Z=r.useCallback(()=>{const o=f.current;o?o.paused?(o.play(),g(!0),u?.(!0)):(o.pause(),g(!1),u?.(!1)):u?.(!0),(0,T.gaTrack)({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:C?.pageGroup,component_type:"video",component_name:"scene_shelf_banner",position:1,creative_id:s?.pc?.id}})},[u,s?.pc?.id,C?.pageGroup]);return r.useEffect(()=>{const o=f.current;if(!o||!O)return;const v=new IntersectionObserver(w=>{w.forEach(D=>{D.isIntersecting?o.play().catch(ee=>{console.warn("Video autoplay failed:",ee)}):o.pause()})},{threshold:.5});return v.observe(o),()=>{v.disconnect()}},[]),(0,t.jsxs)("div",{...b,ref:P,className:(0,n.cn)("scene-shelf-v2-root w-full overflow-hidden",{"aiui-dark":c==="dark"},e,i?.root),children:[(0,t.jsxs)("div",{className:(0,n.cn)("scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden",i?.media),ref:y,children:[(0,t.jsx)(K.default,{pcImage:s?.pc,desktopImage:s?.desktop,laptopImage:s?.laptop,padImage:s?.pad,mobileImage:s?.mobile,className:"size-full",videoClassName:"absolute inset-0 size-full object-cover",videoRef:f,onVideoPlay:()=>g(!0),onVideoPause:()=>g(!1),onVideoEnded:()=>g(!1)}),(0,t.jsx)("div",{"aria-hidden":"true",className:(0,n.cn)("scene-shelf-v2-media-overlay pointer-events-none absolute inset-0",i?.mediaOverlay)}),O&&(0,t.jsx)("div",{className:"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6",children:(0,t.jsx)("button",{type:"button","aria-label":E?"Pause video":"Play video",onClick:Z,className:(0,n.cn)("scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80",i?.mediaPlayButton),children:E?(0,t.jsx)(pe,{}):(0,t.jsx)(de,{})})})]}),(0,t.jsxs)("div",{ref:R,className:(0,n.cn)("scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3",i?.products),children:[N&&(0,t.jsx)(l.Heading,{as:"h2",size:3,className:(0,n.cn)("scene-shelf-v2-products-title text-info-primary",i?.productsTitle),html:N}),(0,t.jsx)("div",{className:"tablet:hidden grid grid-cols-2 gap-3",children:(()=>{const o=_!==void 0&&_>0&&d.length>A,v=o&&!p?d.slice(0,A):d;return(0,t.jsxs)(t.Fragment,{children:[v.map((w,D)=>(0,t.jsx)(V,{isShowTag:a.isShowTag??!0,product:w,onImageClick:m,onLearnMore:S,onShopNow:h,onAddToCart:x,secondaryButtonText:B,secondaryButtonFun:L,primaryButtonText:M,primaryButtonFun:z,classNames:i,theme:c,index:D},w.productKey)),o&&(0,t.jsx)("div",{className:"col-span-2 mt-6 flex justify-center",children:(0,t.jsxs)("button",{type:"button",onClick:()=>k(w=>!w),className:"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors","aria-expanded":p,children:[p?I?.viewLessLabel??"View Less":I?.viewMoreLabel??"View More",(0,t.jsx)("svg",{className:(0,n.cn)("size-4 transition-transform",p&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]})})]})})()}),(0,t.jsx)("div",{className:"tablet:block hidden",children:(0,t.jsx)("div",{className:"relative",children:(0,t.jsx)(j.Swiper,{slidesPerView:"auto",observer:!0,observeParents:!0,modules:[$.Mousewheel],mousewheel:{enabled:!0,forceToAxis:!0,sensitivity:1},className:"!overflow-visible",breakpoints:{768:{spaceBetween:16,slidesPerView:d.length>3?2.3:2},1024:{spaceBetween:16,slidesPerView:d.length>3?2.8:3},1440:{spaceBetween:16,slidesPerView:d.length>4?3.8:4},1920:{spaceBetween:16,slidesPerView:d.length>4?3.8:4}},children:d.map((o,v)=>(0,t.jsx)(j.SwiperSlide,{className:(0,n.cn)("!h-auto ",i.productCardSlideWrapper),children:(0,t.jsx)(V,{product:o,isShowTag:a.isShowTag??!0,onImageClick:m,onLearnMore:S,onShopNow:h,onAddToCart:x,secondaryButtonText:B,secondaryButtonFun:L,primaryButtonText:M,primaryButtonFun:z,classNames:i,theme:c,index:v})},o.productKey))})})})]})]})});W.displayName="SceneShelfV2";var me=(0,Q.withLayout)(W);
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/SceneShelfV2/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn, getLocalizedPath } from '../../helpers/index.js'\nimport { Heading, Text, Badge, Button, Picture } from '../../components/index.js'\nimport Media from '../Media/index.js'\nimport type { ResponsiveMedia, Theme } from '../../types/props.js'\nimport { Swiper, SwiperSlide } from 'swiper/react'\nimport { Mousewheel } from 'swiper/modules'\nimport 'swiper/css'\nimport 'swiper/css/navigation'\nimport { withLayout } from '../../shared/Styles.js'\nimport { useGridRowCount } from '../../hooks/useGridRowCount.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { useViewItemList } from '../../hooks/useViewItemList.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport { gaTrack } from '../../shared/track.js'\n\nconst componentType = 'shelf'\nconst componentName = 'scene_shelf_v2'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Types\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * \u6309\u94AE\u529F\u80FD\u7C7B\u578B\n */\nexport type ButtonFunctionType = 'buyNow' | 'addCart' | 'learnMore'\n\nexport type SceneShelfV2SemanticName =\n | 'root'\n | 'media'\n | 'mediaOverlay'\n | 'mediaQuote'\n | 'mediaPlayButton'\n | 'products'\n | 'productsTitle'\n | 'productGrid'\n | 'productCardSlideWrapper'\n | 'productCard'\n | 'productCardImage'\n | 'productCardTags'\n | 'productCardTitle'\n | 'productCardDescription'\n | 'productCardPriceWrapper'\n | 'productCardCurrentPrice'\n | 'productCardOriginalPrice'\n | 'productCardButtons'\n\nexport interface SceneShelfV2Tag {\n label: string\n variant?: 'outline' | 'fill'\n}\n\nexport interface SceneShelfV2Product {\n /** \u4EA7\u54C1\u552F\u4E00\u6807\u8BC6 */\n productKey: string\n /** \u4EA7\u54C1\u4E3B\u6807\u9898 */\n title: string\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u4EA7\u54C1\u56FE\u7247 */\n imageUrl: string\n imageAlt: string\n /**\n * \u4EA7\u54C1\u94FE\u63A5 URL\u3002\n */\n href?: string\n /** \u5F53\u524D\u4EF7\u683C\uFF08\u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u5982 \"$1,999.00\"\uFF09 */\n currentPrice: string\n /** \u539F\u4EF7\uFF08\u663E\u793A\u5220\u9664\u7EBF\uFF09 */\n originalPrice?: string\n /** \u6807\u7B7E\u5217\u8868 */\n tags?: SceneShelfV2Tag[]\n /** \u662F\u5426\u552E\u7F44 */\n soldOut?: boolean\n /**\n * sku\n */\n sku?: string\n /**\n * \u53D8\u4F53id\n */\n variantId?: string\n}\n\n/**\n * \u6587\u6848\u914D\u7F6E\n */\nexport interface SceneShelfV2CopyConfig {\n /** \u67E5\u770B\u66F4\u591A\u6807\u7B7E */\n viewMoreLabel?: string\n /** \u6536\u8D77\u6807\u7B7E */\n viewLessLabel?: string\n}\n\nexport interface SceneShelfV2Data {\n theme?: 'light' | 'dark'\n isShowTag?: boolean\n sceneImage: ResponsiveMedia\n /** \u4EA7\u54C1\u533A\u6807\u9898\uFF08\u53EF\u9009\uFF09 */\n productsTitle?: string\n /** \u4EA7\u54C1\u5217\u8868 */\n products: SceneShelfV2Product[]\n /** \u6B21\u8981\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u6B21\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n secondaryButtonFun?: ButtonFunctionType\n /** \u4E3B\u8981\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u4E3B\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n primaryButtonFun?: ButtonFunctionType\n /** \u67E5\u770B\u66F4\u591A\u9650\u5236\u6570\uFF08\u624B\u673A\u7AEF\u8D85\u8FC7\u4E24\u884C\u65F6\u663E\u793AviewMore\u6309\u94AE\uFF09 */\n viewMoreLimit?: number\n /** \u6587\u6848\u914D\u7F6E */\n copy?: SceneShelfV2CopyConfig\n}\n\nexport interface SceneShelfV2Props extends React.HTMLAttributes<HTMLDivElement> {\n data: SceneShelfV2Data\n /**\n * \u70B9\u51FB\u64AD\u653E/\u6682\u505C\u6309\u94AE\u56DE\u8C03\u3002\n * \u5F53\u5A92\u4F53\u533A\u4E3A\u89C6\u9891\u65F6\uFF0C\u7EC4\u4EF6\u5185\u90E8\u4F1A\u81EA\u52A8\u63A7\u5236\u64AD\u653E/\u6682\u505C,\u6B64\u56DE\u8C03\u4ECD\u4F1A\u89E6\u53D1\u3002\n */\n onPlayClick?: (isPlaying: boolean) => void\n /** \u70B9\u51FB\u4EA7\u54C1\u56FE\u7247\u56DE\u8C03 */\n onImageClick?: (product: SceneShelfV2Product) => void\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: SceneShelfV2Product) => void | Promise<void>\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Icons\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PlayIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 5.14v13.72L19 12 8 5.14z\" fill=\"white\" />\n </svg>\n)\n\nconst PauseIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n </svg>\n)\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Product Card\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface ProductCardInnerProps {\n product: SceneShelfV2Product\n isShowTag: boolean\n onImageClick?: (product: SceneShelfV2Product) => void\n onLearnMore?: (link: string) => void | Promise<void>\n onShopNow?: (product: SceneShelfV2Product) => void | Promise<void>\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n className?: string\n theme?: Theme\n index?: number\n}\n\nconst ProductCardInner = React.memo(\n ({\n product,\n isShowTag = true,\n onImageClick,\n onLearnMore,\n onShopNow,\n onAddToCart,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n classNames,\n className,\n theme,\n index,\n }: ProductCardInnerProps) => {\n const { locale = 'us', trackingData } = useAiuiContext()\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n\n const pageGroup = trackingData?.pageGroup\n\n // \u6839\u636E\u6309\u94AE\u529F\u80FD\u7C7B\u578B\u8C03\u7528\u76F8\u5E94\u7684\u56DE\u8C03\u51FD\u6570\n const handleButtonClick = React.useCallback(\n async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n\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 default:\n break\n }\n } finally {\n setLoading(false)\n }\n },\n [onLearnMore, onShopNow, onAddToCart, product]\n )\n\n const handlePrimary = React.useCallback(\n () => handleButtonClick(primaryButtonFun, 'primary'),\n [handleButtonClick, primaryButtonFun]\n )\n const handleSecondary = React.useCallback(\n () => handleButtonClick(secondaryButtonFun, 'secondary'),\n [handleButtonClick, secondaryButtonFun]\n )\n\n const handleImageClick = React.useCallback(\n (e: React.MouseEvent) => {\n // \u5982\u679C\u6CA1\u6709\u63D0\u4F9B href \u4E14\u6709\u70B9\u51FB\u56DE\u8C03\uFF0C\u963B\u6B62\u9ED8\u8BA4\u884C\u4E3A\n if (!product.href && onImageClick) {\n e.preventDefault()\n }\n onImageClick?.(product)\n gaTrack({\n event: 'ga4Event',\n event_name: 'select_item',\n item_list_name: 'Scene_Shelf_2_Products',\n page_group: pageGroup,\n items: [\n {\n item_id: product.sku,\n item_name: product.title,\n item_variant: product.variantId,\n price: product.currentPrice,\n index: index,\n },\n ],\n })\n },\n [index, onImageClick, pageGroup, product]\n )\n\n return (\n <div\n className={cn(\n 'scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4',\n className,\n classNames?.productCard,\n {\n 'bg-container-secondary-0': theme === 'dark',\n }\n )}\n >\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n {product.href ? (\n <a\n href={getLocalizedPath(\n trackUrlRef(product.href, pageGroup + '_' + componentType + '_' + componentName),\n locale\n )}\n onClick={handleImageClick}\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n aria-label={`View ${product.title}`}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </a>\n ) : (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ',\n onImageClick && 'cursor-pointer transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n onClick={onImageClick ? handleImageClick : undefined}\n role={onImageClick ? 'button' : undefined}\n tabIndex={onImageClick ? 0 : undefined}\n aria-label={onImageClick ? `View ${product.title}` : undefined}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </div>\n )}\n\n {/* \u4EA7\u54C1\u4FE1\u606F */}\n <div className=\"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4\">\n {/* \u6807\u7B7E + \u6807\u9898 + \u526F\u6807\u9898 */}\n <div className=\"flex flex-col gap-2\">\n <div\n className={cn(\n 'scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1',\n classNames?.productCardTags\n )}\n >\n {isShowTag &&\n product?.tags?.map((tag, idx) => (\n <Badge key={idx} variant={tag.variant ?? 'outline'} size=\"sm\" className=\"\">\n {tag.label}\n </Badge>\n ))}\n </div>\n\n <Heading\n as=\"h3\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]',\n classNames?.productCardTitle\n )}\n >\n {product.title}\n </Heading>\n\n {product.description && (\n <Text\n as=\"p\"\n size={1}\n className={cn(\n 'scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1',\n classNames?.productCardDescription\n )}\n >\n {product.description}\n </Text>\n )}\n </div>\n\n {/* \u4EF7\u683C + \u6309\u94AE */}\n <div className=\"flex flex-col gap-2\">\n {/* \u4EF7\u683C */}\n <div\n className={cn(\n 'scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1',\n classNames?.productCardPriceWrapper\n )}\n >\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-current-price text-info-primary',\n classNames?.productCardCurrentPrice\n )}\n >\n {product.currentPrice}\n </Heading>\n {product.originalPrice && (\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-original-price text-info-tertiary line-through',\n classNames?.productCardOriginalPrice\n )}\n >\n {product.originalPrice}\n </Heading>\n )}\n </div>\n\n {/* \u6309\u94AE\u7EC4 */}\n {(secondaryButtonText || primaryButtonText) && (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2',\n classNames?.productCardButtons\n )}\n >\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handleSecondary()\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.title,\n component_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 className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handlePrimary()\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.title,\n component_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 )}\n </div>\n </div>\n </div>\n )\n }\n)\n\nProductCardInner.displayName = 'SceneShelfV2.ProductCard'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Main Component\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst SceneShelfV2 = React.forwardRef<HTMLDivElement, SceneShelfV2Props>(\n (\n { className, classNames = {}, data, onPlayClick, onImageClick, onLearnMore, onShopNow, onAddToCart, ...props },\n ref\n ) => {\n const {\n theme = 'light',\n sceneImage,\n productsTitle,\n products,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n viewMoreLimit = 2,\n copy,\n } = data\n const videoRef = React.useRef<HTMLVideoElement>(null)\n const mediaRef = React.useRef<HTMLDivElement>(null)\n const productWrapperRef = React.useRef<HTMLDivElement>(null)\n const [isPlaying, setIsPlaying] = React.useState(false)\n const [isExpanded, setIsExpanded] = React.useState(false)\n const { trackingData } = useAiuiContext()\n\n useExposure(mediaRef, {\n componentType: 'image',\n componentName: 'scene_shelf_banner',\n })\n\n useViewItemList(productWrapperRef, {\n componentType: 'video',\n componentName: 'scene_shelf_banner',\n itemListName: 'Scene_Shelf_2_Products',\n items: products.map((item, index) => ({\n item_id: item.sku ?? '',\n item_name: item.title,\n item_variant: item.variantId ?? '',\n price: item.currentPrice,\n index: index,\n })),\n tabName: '',\n })\n\n const visibleLimit = useGridRowCount({\n rows: viewMoreLimit ?? 0,\n mobileCols: 2,\n })\n\n const hasVideo = React.useMemo(\n () =>\n [sceneImage?.pc, sceneImage?.desktop, sceneImage?.laptop, sceneImage?.pad, sceneImage?.mobile].some(\n media => media?.mimeType === 'video/mp4'\n ),\n [sceneImage]\n )\n\n const handlePlayButtonClick = React.useCallback(() => {\n const video = videoRef.current\n if (video) {\n if (video.paused) {\n video.play()\n setIsPlaying(true)\n onPlayClick?.(true)\n } else {\n video.pause()\n setIsPlaying(false)\n onPlayClick?.(false)\n }\n } else {\n onPlayClick?.(true)\n }\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: trackingData?.pageGroup,\n component_type: 'video',\n component_name: 'scene_shelf_banner',\n position: 1,\n creative_id: sceneImage?.pc?.id,\n },\n })\n }, [onPlayClick, sceneImage?.pc?.id, trackingData?.pageGroup])\n\n // \u8FDB\u5165\u89C6\u7A97\u81EA\u52A8\u64AD\u653E\n React.useEffect(() => {\n const video = videoRef.current\n if (!video || !hasVideo) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n // \u8FDB\u5165\u89C6\u7A97\uFF0C\u81EA\u52A8\u64AD\u653E\n video.play().catch(error => {\n // \u5904\u7406\u81EA\u52A8\u64AD\u653E\u5931\u8D25\uFF08\u6D4F\u89C8\u5668\u7B56\u7565\u53EF\u80FD\u963B\u6B62\u81EA\u52A8\u64AD\u653E\uFF09\n console.warn('Video autoplay failed:', error)\n })\n } else {\n // \u79BB\u5F00\u89C6\u7A97\uFF0C\u6682\u505C\u64AD\u653E\n video.pause()\n }\n })\n },\n {\n threshold: 0.5, // \u5F53\u89C6\u9891 50% \u53EF\u89C1\u65F6\u89E6\u53D1\n }\n )\n\n observer.observe(video)\n\n return () => {\n observer.disconnect()\n }\n }, [])\n\n return (\n <div\n {...props}\n ref={ref}\n className={cn(\n 'scene-shelf-v2-root w-full overflow-hidden',\n { 'aiui-dark': theme === 'dark' },\n className,\n classNames?.root\n )}\n >\n {/* \u2500\u2500 \u5A92\u4F53\u533A \u2500\u2500 */}\n <div\n className={cn(\n 'scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden',\n classNames?.media\n )}\n ref={mediaRef}\n >\n <Media\n pcImage={sceneImage?.pc}\n desktopImage={sceneImage?.desktop}\n laptopImage={sceneImage?.laptop}\n padImage={sceneImage?.pad}\n mobileImage={sceneImage?.mobile}\n className=\"size-full\"\n videoClassName=\"absolute inset-0 size-full object-cover\"\n videoRef={videoRef}\n onVideoPlay={() => setIsPlaying(true)}\n onVideoPause={() => setIsPlaying(false)}\n onVideoEnded={() => setIsPlaying(false)}\n />\n {/* \u6E10\u53D8\u906E\u7F69 */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'scene-shelf-v2-media-overlay pointer-events-none absolute inset-0',\n classNames?.mediaOverlay\n )}\n />\n\n {/* \u5F15\u8A00 + \u64AD\u653E/\u6682\u505C\u6309\u94AE */}\n {hasVideo && (\n <div className=\"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6\">\n <button\n type=\"button\"\n aria-label={isPlaying ? 'Pause video' : 'Play video'}\n onClick={handlePlayButtonClick}\n className={cn(\n 'scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80',\n classNames?.mediaPlayButton\n )}\n >\n {isPlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n </div>\n )}\n </div>\n\n {/* \u2500\u2500 \u4EA7\u54C1\u533A \u2500\u2500 */}\n <div\n ref={productWrapperRef}\n className={cn(\n 'scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3',\n classNames?.products\n )}\n >\n {productsTitle && (\n <Heading\n as=\"h2\"\n size={3}\n className={cn('scene-shelf-v2-products-title text-info-primary', classNames?.productsTitle)}\n html={productsTitle}\n />\n )}\n\n {/* Mobile\uFF1A2\u5217\u5E73\u94FA */}\n <div className=\"tablet:hidden grid grid-cols-2 gap-3\">\n {(() => {\n const shouldShowViewMore =\n viewMoreLimit !== undefined && viewMoreLimit > 0 && products.length > visibleLimit\n const displayedProducts = shouldShowViewMore && !isExpanded ? products.slice(0, visibleLimit) : products\n\n return (\n <>\n {displayedProducts.map((product, index) => (\n <ProductCardInner\n key={product.productKey}\n isShowTag={data.isShowTag ?? true}\n product={product}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n ))}\n {shouldShowViewMore && (\n <div className=\"col-span-2 mt-6 flex justify-center\">\n <button\n type=\"button\"\n onClick={() => setIsExpanded(prev => !prev)}\n className=\"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors\"\n aria-expanded={isExpanded}\n >\n {isExpanded ? (copy?.viewLessLabel ?? 'View Less') : (copy?.viewMoreLabel ?? 'View More')}\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 </div>\n\n {/* Tablet\uFF1ASwiper \u6A2A\u6ED1 */}\n <div className=\"tablet:block hidden\">\n <div className=\"relative\">\n <Swiper\n slidesPerView=\"auto\"\n observer\n observeParents\n modules={[Mousewheel]}\n mousewheel={{\n enabled: true,\n forceToAxis: true,\n sensitivity: 1,\n }}\n className=\"!overflow-visible\"\n breakpoints={{\n 768: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.3 : 2,\n },\n 1024: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.8 : 3,\n },\n 1440: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n 1920: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n }}\n >\n {products.map((product, index) => (\n <SwiperSlide key={product.productKey} className={cn('!h-auto ', classNames.productCardSlideWrapper)}>\n <ProductCardInner\n product={product}\n isShowTag={data.isShowTag ?? true}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n </SwiperSlide>\n ))}\n </Swiper>\n </div>\n </div>\n </div>\n </div>\n )\n }\n)\n\nSceneShelfV2.displayName = 'SceneShelfV2'\nexport default withLayout(SceneShelfV2)\nexport { ProductCardInner as SceneShelfV2ProductCard }\n"],
|
|
5
|
-
"mappings": "mlBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,6BAAAE,EAAA,YAAAC,KAAA,eAAAC,GAAAJ,
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn, getLocalizedPath } from '../../helpers/index.js'\nimport { Heading, Text, Badge, Button, Picture } from '../../components/index.js'\nimport Media from '../Media/index.js'\nimport type { ResponsiveMedia, Theme } from '../../types/props.js'\nimport { Swiper, SwiperSlide } from 'swiper/react'\nimport { Mousewheel } from 'swiper/modules'\nimport 'swiper/css'\nimport 'swiper/css/navigation'\nimport { withLayout } from '../../shared/Styles.js'\nimport { useGridRowCount } from '../../hooks/useGridRowCount.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { useViewItemList } from '../../hooks/useViewItemList.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport { gaTrack } from '../../shared/track.js'\n\nconst componentType = 'shelf'\nconst componentName = 'scene_shelf_v2'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Types\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * \u6309\u94AE\u529F\u80FD\u7C7B\u578B\n */\nexport type ButtonFunctionType = 'buyNow' | 'addCart' | 'learnMore'\n\nexport type SceneShelfV2SemanticName =\n | 'root'\n | 'media'\n | 'mediaOverlay'\n | 'mediaQuote'\n | 'mediaPlayButton'\n | 'products'\n | 'productsTitle'\n | 'productGrid'\n | 'productCardSlideWrapper'\n | 'productCard'\n | 'productCardImage'\n | 'productCardTags'\n | 'productCardTitle'\n | 'productCardDescription'\n | 'productCardPriceWrapper'\n | 'productCardCurrentPrice'\n | 'productCardOriginalPrice'\n | 'productCardButtons'\n\nexport interface SceneShelfV2Tag {\n label: string\n variant?: 'outline' | 'fill'\n}\n\nexport interface SceneShelfV2Product {\n /** \u4EA7\u54C1\u552F\u4E00\u6807\u8BC6 */\n productKey: string\n /** \u4EA7\u54C1\u4E3B\u6807\u9898 */\n title: string\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u4EA7\u54C1\u56FE\u7247 */\n imageUrl: string\n imageAlt: string\n /**\n * \u4EA7\u54C1\u94FE\u63A5 URL\u3002\n */\n href?: string\n /** \u5F53\u524D\u4EF7\u683C\uFF08\u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u5982 \"$1,999.00\"\uFF09 */\n currentPrice: string\n /** \u539F\u4EF7\uFF08\u663E\u793A\u5220\u9664\u7EBF\uFF09 */\n originalPrice?: string\n /** \u6807\u7B7E\u5217\u8868 */\n tags?: SceneShelfV2Tag[]\n /** \u662F\u5426\u552E\u7F44 */\n soldOut?: boolean\n /**\n * sku\n */\n sku?: string\n /**\n * \u53D8\u4F53id\n */\n variantId?: string\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}\n\n/**\n * \u6587\u6848\u914D\u7F6E\n */\nexport interface SceneShelfV2CopyConfig {\n /** \u67E5\u770B\u66F4\u591A\u6807\u7B7E */\n viewMoreLabel?: string\n /** \u6536\u8D77\u6807\u7B7E */\n viewLessLabel?: string\n}\n\nexport interface SceneShelfV2Data {\n theme?: 'light' | 'dark'\n isShowTag?: boolean\n sceneImage: ResponsiveMedia\n /** \u4EA7\u54C1\u533A\u6807\u9898\uFF08\u53EF\u9009\uFF09 */\n productsTitle?: string\n /** \u4EA7\u54C1\u5217\u8868 */\n products: SceneShelfV2Product[]\n /** \u6B21\u8981\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u6B21\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n secondaryButtonFun?: ButtonFunctionType\n /** \u4E3B\u8981\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u4E3B\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n primaryButtonFun?: ButtonFunctionType\n /** \u67E5\u770B\u66F4\u591A\u9650\u5236\u6570\uFF08\u624B\u673A\u7AEF\u8D85\u8FC7\u4E24\u884C\u65F6\u663E\u793AviewMore\u6309\u94AE\uFF09 */\n viewMoreLimit?: number\n /** \u6587\u6848\u914D\u7F6E */\n copy?: SceneShelfV2CopyConfig\n}\n\nexport interface SceneShelfV2Props extends React.HTMLAttributes<HTMLDivElement> {\n data: SceneShelfV2Data\n /**\n * \u70B9\u51FB\u64AD\u653E/\u6682\u505C\u6309\u94AE\u56DE\u8C03\u3002\n * \u5F53\u5A92\u4F53\u533A\u4E3A\u89C6\u9891\u65F6\uFF0C\u7EC4\u4EF6\u5185\u90E8\u4F1A\u81EA\u52A8\u63A7\u5236\u64AD\u653E/\u6682\u505C,\u6B64\u56DE\u8C03\u4ECD\u4F1A\u89E6\u53D1\u3002\n */\n onPlayClick?: (isPlaying: boolean) => void\n /** \u70B9\u51FB\u4EA7\u54C1\u56FE\u7247\u56DE\u8C03 */\n onImageClick?: (product: SceneShelfV2Product) => void\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: SceneShelfV2Product) => void | Promise<void>\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Icons\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PlayIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 5.14v13.72L19 12 8 5.14z\" fill=\"white\" />\n </svg>\n)\n\nconst PauseIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n </svg>\n)\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Product Card\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface ProductCardInnerProps {\n product: SceneShelfV2Product\n isShowTag: boolean\n onImageClick?: (product: SceneShelfV2Product) => void\n onLearnMore?: (link: string) => void | Promise<void>\n onShopNow?: (product: SceneShelfV2Product) => void | Promise<void>\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n className?: string\n theme?: Theme\n index?: number\n}\n\nconst ProductCardInner = React.memo(\n ({\n product,\n isShowTag = true,\n onImageClick,\n onLearnMore,\n onShopNow,\n onAddToCart,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n classNames,\n className,\n theme,\n index,\n }: ProductCardInnerProps) => {\n const { locale = 'us', trackingData } = useAiuiContext()\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n\n const pageGroup = trackingData?.pageGroup\n\n // \u6839\u636E\u6309\u94AE\u529F\u80FD\u7C7B\u578B\u8C03\u7528\u76F8\u5E94\u7684\u56DE\u8C03\u51FD\u6570\n const handleButtonClick = React.useCallback(\n async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n\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 default:\n break\n }\n } finally {\n setLoading(false)\n }\n },\n [onLearnMore, onShopNow, onAddToCart, product]\n )\n\n const handlePrimary = React.useCallback(\n () => handleButtonClick(primaryButtonFun, 'primary'),\n [handleButtonClick, primaryButtonFun]\n )\n const handleSecondary = React.useCallback(\n () => handleButtonClick(secondaryButtonFun, 'secondary'),\n [handleButtonClick, secondaryButtonFun]\n )\n\n const handleImageClick = React.useCallback(\n (e: React.MouseEvent) => {\n // \u5982\u679C\u6CA1\u6709\u63D0\u4F9B href \u4E14\u6709\u70B9\u51FB\u56DE\u8C03\uFF0C\u963B\u6B62\u9ED8\u8BA4\u884C\u4E3A\n if (!product.href && onImageClick) {\n e.preventDefault()\n }\n onImageClick?.(product)\n gaTrack({\n event: 'ga4Event',\n event_name: 'select_item',\n item_list_name: 'Scene_Shelf_2_Products',\n page_group: pageGroup,\n items: [\n {\n item_id: product.sku,\n item_name: product.custom_name || product.title,\n item_variant: product.variantId,\n price: product.currentPrice,\n index: index,\n },\n ],\n })\n },\n [index, onImageClick, pageGroup, product]\n )\n\n return (\n <div\n className={cn(\n 'scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4',\n className,\n classNames?.productCard,\n {\n 'bg-container-secondary-0': theme === 'dark',\n }\n )}\n >\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n {product.href ? (\n <a\n href={getLocalizedPath(\n trackUrlRef(product.href, pageGroup + '_' + componentType + '_' + componentName),\n locale\n )}\n onClick={handleImageClick}\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n aria-label={`View ${product.title}`}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </a>\n ) : (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ',\n onImageClick && 'cursor-pointer transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n onClick={onImageClick ? handleImageClick : undefined}\n role={onImageClick ? 'button' : undefined}\n tabIndex={onImageClick ? 0 : undefined}\n aria-label={onImageClick ? `View ${product.title}` : undefined}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </div>\n )}\n\n {/* \u4EA7\u54C1\u4FE1\u606F */}\n <div className=\"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4\">\n {/* \u6807\u7B7E + \u6807\u9898 + \u526F\u6807\u9898 */}\n <div className=\"flex flex-col gap-2\">\n <div\n className={cn(\n 'scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1',\n classNames?.productCardTags\n )}\n >\n {isShowTag &&\n product?.tags?.map((tag, idx) => (\n <Badge key={idx} variant={tag.variant ?? 'outline'} size=\"sm\" className=\"\">\n {tag.label}\n </Badge>\n ))}\n </div>\n\n <Heading\n as=\"h3\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]',\n classNames?.productCardTitle\n )}\n >\n {product.custom_name || product.title}\n </Heading>\n\n {(product.custom_description || product.description) && (\n <Text\n as=\"p\"\n size={1}\n className={cn(\n 'scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1',\n classNames?.productCardDescription\n )}\n >\n {product.custom_description || product.description}\n </Text>\n )}\n </div>\n\n {/* \u4EF7\u683C + \u6309\u94AE */}\n <div className=\"flex flex-col gap-2\">\n {/* \u4EF7\u683C */}\n <div\n className={cn(\n 'scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1',\n classNames?.productCardPriceWrapper\n )}\n >\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-current-price text-info-primary',\n classNames?.productCardCurrentPrice\n )}\n >\n {product.currentPrice}\n </Heading>\n {product.originalPrice && (\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-original-price text-info-tertiary line-through',\n classNames?.productCardOriginalPrice\n )}\n >\n {product.originalPrice}\n </Heading>\n )}\n </div>\n\n {/* \u6309\u94AE\u7EC4 */}\n {(secondaryButtonText || primaryButtonText) && (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2',\n classNames?.productCardButtons\n )}\n >\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handleSecondary()\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.title,\n component_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 className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handlePrimary()\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.title,\n component_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 )}\n </div>\n </div>\n </div>\n )\n }\n)\n\nProductCardInner.displayName = 'SceneShelfV2.ProductCard'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Main Component\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst SceneShelfV2 = React.forwardRef<HTMLDivElement, SceneShelfV2Props>(\n (\n { className, classNames = {}, data, onPlayClick, onImageClick, onLearnMore, onShopNow, onAddToCart, ...props },\n ref\n ) => {\n const {\n theme = 'light',\n sceneImage,\n productsTitle,\n products,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n viewMoreLimit = 2,\n copy,\n } = data\n const videoRef = React.useRef<HTMLVideoElement>(null)\n const mediaRef = React.useRef<HTMLDivElement>(null)\n const productWrapperRef = React.useRef<HTMLDivElement>(null)\n const [isPlaying, setIsPlaying] = React.useState(false)\n const [isExpanded, setIsExpanded] = React.useState(false)\n const { trackingData } = useAiuiContext()\n\n useExposure(mediaRef, {\n componentType: 'image',\n componentName: 'scene_shelf_banner',\n })\n\n useViewItemList(productWrapperRef, {\n componentType: 'video',\n componentName: 'scene_shelf_banner',\n itemListName: 'Scene_Shelf_2_Products',\n items: products.map((item, index) => ({\n item_id: item.sku ?? '',\n item_name: item.title,\n item_variant: item.variantId ?? '',\n price: item.currentPrice,\n index: index,\n })),\n tabName: '',\n })\n\n const visibleLimit = useGridRowCount({\n rows: viewMoreLimit ?? 0,\n mobileCols: 2,\n })\n\n const hasVideo = React.useMemo(\n () =>\n [sceneImage?.pc, sceneImage?.desktop, sceneImage?.laptop, sceneImage?.pad, sceneImage?.mobile].some(\n media => media?.mimeType === 'video/mp4'\n ),\n [sceneImage]\n )\n\n const handlePlayButtonClick = React.useCallback(() => {\n const video = videoRef.current\n if (video) {\n if (video.paused) {\n video.play()\n setIsPlaying(true)\n onPlayClick?.(true)\n } else {\n video.pause()\n setIsPlaying(false)\n onPlayClick?.(false)\n }\n } else {\n onPlayClick?.(true)\n }\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: trackingData?.pageGroup,\n component_type: 'video',\n component_name: 'scene_shelf_banner',\n position: 1,\n creative_id: sceneImage?.pc?.id,\n },\n })\n }, [onPlayClick, sceneImage?.pc?.id, trackingData?.pageGroup])\n\n // \u8FDB\u5165\u89C6\u7A97\u81EA\u52A8\u64AD\u653E\n React.useEffect(() => {\n const video = videoRef.current\n if (!video || !hasVideo) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n // \u8FDB\u5165\u89C6\u7A97\uFF0C\u81EA\u52A8\u64AD\u653E\n video.play().catch(error => {\n // \u5904\u7406\u81EA\u52A8\u64AD\u653E\u5931\u8D25\uFF08\u6D4F\u89C8\u5668\u7B56\u7565\u53EF\u80FD\u963B\u6B62\u81EA\u52A8\u64AD\u653E\uFF09\n console.warn('Video autoplay failed:', error)\n })\n } else {\n // \u79BB\u5F00\u89C6\u7A97\uFF0C\u6682\u505C\u64AD\u653E\n video.pause()\n }\n })\n },\n {\n threshold: 0.5, // \u5F53\u89C6\u9891 50% \u53EF\u89C1\u65F6\u89E6\u53D1\n }\n )\n\n observer.observe(video)\n\n return () => {\n observer.disconnect()\n }\n }, [])\n\n return (\n <div\n {...props}\n ref={ref}\n className={cn(\n 'scene-shelf-v2-root w-full overflow-hidden',\n { 'aiui-dark': theme === 'dark' },\n className,\n classNames?.root\n )}\n >\n {/* \u2500\u2500 \u5A92\u4F53\u533A \u2500\u2500 */}\n <div\n className={cn(\n 'scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden',\n classNames?.media\n )}\n ref={mediaRef}\n >\n <Media\n pcImage={sceneImage?.pc}\n desktopImage={sceneImage?.desktop}\n laptopImage={sceneImage?.laptop}\n padImage={sceneImage?.pad}\n mobileImage={sceneImage?.mobile}\n className=\"size-full\"\n videoClassName=\"absolute inset-0 size-full object-cover\"\n videoRef={videoRef}\n onVideoPlay={() => setIsPlaying(true)}\n onVideoPause={() => setIsPlaying(false)}\n onVideoEnded={() => setIsPlaying(false)}\n />\n {/* \u6E10\u53D8\u906E\u7F69 */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'scene-shelf-v2-media-overlay pointer-events-none absolute inset-0',\n classNames?.mediaOverlay\n )}\n />\n\n {/* \u5F15\u8A00 + \u64AD\u653E/\u6682\u505C\u6309\u94AE */}\n {hasVideo && (\n <div className=\"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6\">\n <button\n type=\"button\"\n aria-label={isPlaying ? 'Pause video' : 'Play video'}\n onClick={handlePlayButtonClick}\n className={cn(\n 'scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80',\n classNames?.mediaPlayButton\n )}\n >\n {isPlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n </div>\n )}\n </div>\n\n {/* \u2500\u2500 \u4EA7\u54C1\u533A \u2500\u2500 */}\n <div\n ref={productWrapperRef}\n className={cn(\n 'scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3',\n classNames?.products\n )}\n >\n {productsTitle && (\n <Heading\n as=\"h2\"\n size={3}\n className={cn('scene-shelf-v2-products-title text-info-primary', classNames?.productsTitle)}\n html={productsTitle}\n />\n )}\n\n {/* Mobile\uFF1A2\u5217\u5E73\u94FA */}\n <div className=\"tablet:hidden grid grid-cols-2 gap-3\">\n {(() => {\n const shouldShowViewMore =\n viewMoreLimit !== undefined && viewMoreLimit > 0 && products.length > visibleLimit\n const displayedProducts = shouldShowViewMore && !isExpanded ? products.slice(0, visibleLimit) : products\n\n return (\n <>\n {displayedProducts.map((product, index) => (\n <ProductCardInner\n key={product.productKey}\n isShowTag={data.isShowTag ?? true}\n product={product}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n ))}\n {shouldShowViewMore && (\n <div className=\"col-span-2 mt-6 flex justify-center\">\n <button\n type=\"button\"\n onClick={() => setIsExpanded(prev => !prev)}\n className=\"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors\"\n aria-expanded={isExpanded}\n >\n {isExpanded ? (copy?.viewLessLabel ?? 'View Less') : (copy?.viewMoreLabel ?? 'View More')}\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 </div>\n\n {/* Tablet\uFF1ASwiper \u6A2A\u6ED1 */}\n <div className=\"tablet:block hidden\">\n <div className=\"relative\">\n <Swiper\n slidesPerView=\"auto\"\n observer\n observeParents\n modules={[Mousewheel]}\n mousewheel={{\n enabled: true,\n forceToAxis: true,\n sensitivity: 1,\n }}\n className=\"!overflow-visible\"\n breakpoints={{\n 768: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.3 : 2,\n },\n 1024: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.8 : 3,\n },\n 1440: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n 1920: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n }}\n >\n {products.map((product, index) => (\n <SwiperSlide key={product.productKey} className={cn('!h-auto ', classNames.productCardSlideWrapper)}>\n <ProductCardInner\n product={product}\n isShowTag={data.isShowTag ?? true}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n </SwiperSlide>\n ))}\n </Swiper>\n </div>\n </div>\n </div>\n </div>\n )\n }\n)\n\nSceneShelfV2.displayName = 'SceneShelfV2'\nexport default withLayout(SceneShelfV2)\nexport { ProductCardInner as SceneShelfV2ProductCard }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["SceneShelfV2_exports", "__export", "ProductCardInner", "SceneShelfV2_default", "__toCommonJS", "import_jsx_runtime", "React", "import_helpers", "import_components", "import_Media", "import_react", "import_modules", "import_css", "import_navigation", "import_Styles", "import_useGridRowCount", "import_useExposure", "import_useViewItemList", "import_trackUrlRef", "import_AiuiProvider", "import_track", "componentType", "componentName", "PlayIcon", "PauseIcon", "product", "isShowTag", "onImageClick", "onLearnMore", "onShopNow", "onAddToCart", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "classNames", "className", "theme", "index", "locale", "trackingData", "primaryLoading", "setPrimaryLoading", "secondaryLoading", "setSecondaryLoading", "pageGroup", "handleButtonClick", "buttonFun", "buttonType", "setLoading", "handlePrimary", "handleSecondary", "handleImageClick", "e", "tag", "idx", "SceneShelfV2", "data", "onPlayClick", "props", "ref", "sceneImage", "productsTitle", "products", "viewMoreLimit", "copy", "videoRef", "mediaRef", "productWrapperRef", "isPlaying", "setIsPlaying", "isExpanded", "setIsExpanded", "item", "visibleLimit", "hasVideo", "media", "handlePlayButtonClick", "video", "observer", "entries", "entry", "error", "Media", "shouldShowViewMore", "displayedProducts", "prev"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";"use client";var dt=Object.create;var x=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var mt=Object.getPrototypeOf,pt=Object.prototype.hasOwnProperty;var ft=(t,n)=>{for(var e in n)x(t,e,{get:n[e],enumerable:!0})},S=(t,n,e,l)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of ut(n))!pt.call(t,s)&&s!==e&&x(t,s,{get:()=>n[s],enumerable:!(l=ct(n,s))||l.enumerable});return t};var ht=(t,n,e)=>(e=t!=null?dt(mt(t)):{},S(n||!t||!t.__esModule?x(e,"default",{value:t,enumerable:!0}):e,t)),gt=t=>S(x({},"__esModule",{value:!0}),t);var vt={};ft(vt,{default:()=>bt});module.exports=gt(vt);var i=require("react/jsx-runtime"),r=ht(require("react")),w=require("gsap"),F=require("gsap/dist/SplitText"),H=require("gsap/dist/ScrollTrigger"),a=require("../../helpers/utils.js"),L=require("class-variance-authority"),d=require("../../components/index.js"),_=require("../../shared/Styles.js"),I=require("../../shared/trackUrlRef.js"),j=require("react-intersection-observer");const V="link",$="title",xt=(0,L.cva)("",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),wt=(0,L.cva)("desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),A=({data:t,onClick:n,className:e})=>{const{theme:l="light",extensions:s,title:b,caption:v,align:h}=t;if(!s?.textLink)return null;const u=s?.link?(0,I.trackUrlRef)(s.link,`${V}_${$}`):void 0;return(0,i.jsxs)("a",{className:(0,a.cn)({"aiui-dark":l==="dark"},"hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]",{"text-[#080A0F]":l==="light"},{"text-[#F5F6F7]":l==="dark"},{"justify-center mt-4":h==="center"},{"mt-1 laptop:mt-0":h==="left"},e),...u?{href:u}:{},"data-headless-type-name":`${V}#${$}`,"data-headless-title-desc-button":`${b}#${v}`,...n?{onClick:n}:{},children:[(0,i.jsx)("div",{className:"truncate whitespace-nowrap",children:s?.textLink}),(0,i.jsx)("div",{className:"lg-desktop:size-5 size-4",children:(0,i.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"100%",height:"100%",viewBox:"0 0 16 16",fill:"none",children:(0,i.jsx)("path",{d:"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z",fill:l==="dark"?"#F5F6F7":"#080A0F",className:"transition-all duration-[0.4s]"})})})]})},B=r.default.forwardRef(({data:t,className:n,classNames:e,as:l="h2",weight:s="bold",onButtonClick:b,...v},h)=>{const{title:u,titleSize:O=4,caption:D,subtitle:M,content:C,countdown:o,showCountdown:U=!1,theme:g="light",extensions:W,align:m="left"}=t,E=(0,r.useRef)(null),p=(0,r.useRef)(null),c=(0,r.useRef)(null),f=(0,r.useRef)(null),[Z,q]=(0,r.useState)(!0),{ref:G,inView:z}=(0,j.useInView)();(0,r.useImperativeHandle)(h,()=>E.current);const J=()=>{q(!1)},K=o?.targetDateTime||o?.targetDate||"",Q=o?.targetDateTime_tz,X=o?.labels?{day:o.labels.days||"Day",hour:o.labels.hours||"Hours",minute:o.labels.minutes||"Mins",second:o.labels.seconds||"Secs"}:void 0;return(0,r.useEffect)(()=>{w.gsap.registerPlugin(F.SplitText,H.ScrollTrigger);function Y(){if(!p.current)return;const tt=p.current?.clientHeight||80;c.current&&c.current.revert(),f.current&&f.current.kill(),c.current=new F.SplitText(p.current,{type:"words",wordsClass:"word"});const k=c.current.words;w.gsap.set(k,{opacity:0}),f.current=H.ScrollTrigger.create({trigger:p.current,start:"bottom bottom-=4%",end:`bottom+=${tt*1.5+60}px bottom-=4%`,scrub:!0,invalidateOnRefresh:!0,onUpdate:et=>{const nt=et.progress,R=k.length||1,it=.5,T=1/R,N=T*(1-it),P=(R-1)*N+T,ot=Math.min(1,P>0?nt/P:0);k.forEach((rt,st)=>{const at=st*N,lt=T;let y=(ot-at)/lt;y=Math.max(0,Math.min(1,y)),w.gsap.set(rt,{opacity:y})})}})}return z&&Y(),()=>{c.current&&c.current.revert(),f.current&&f.current.kill()}},[z]),(0,i.jsxs)("div",{...v,id:W?.id,className:(0,a.cn)("titleBottom title-box flex items-end justify-between gap-2 pb-6",e?.wrapper),ref:E,children:[(0,i.jsxs)("div",{ref:G,className:(0,a.cn)("flex-1",
|
|
1
|
+
"use strict";"use client";var dt=Object.create;var x=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var mt=Object.getPrototypeOf,pt=Object.prototype.hasOwnProperty;var ft=(t,n)=>{for(var e in n)x(t,e,{get:n[e],enumerable:!0})},S=(t,n,e,l)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of ut(n))!pt.call(t,s)&&s!==e&&x(t,s,{get:()=>n[s],enumerable:!(l=ct(n,s))||l.enumerable});return t};var ht=(t,n,e)=>(e=t!=null?dt(mt(t)):{},S(n||!t||!t.__esModule?x(e,"default",{value:t,enumerable:!0}):e,t)),gt=t=>S(x({},"__esModule",{value:!0}),t);var vt={};ft(vt,{default:()=>bt});module.exports=gt(vt);var i=require("react/jsx-runtime"),r=ht(require("react")),w=require("gsap"),F=require("gsap/dist/SplitText"),H=require("gsap/dist/ScrollTrigger"),a=require("../../helpers/utils.js"),L=require("class-variance-authority"),d=require("../../components/index.js"),_=require("../../shared/Styles.js"),I=require("../../shared/trackUrlRef.js"),j=require("react-intersection-observer");const V="link",$="title",xt=(0,L.cva)("",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),wt=(0,L.cva)("desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),A=({data:t,onClick:n,className:e})=>{const{theme:l="light",extensions:s,title:b,caption:v,align:h}=t;if(!s?.textLink)return null;const u=s?.link?(0,I.trackUrlRef)(s.link,`${V}_${$}`):void 0;return(0,i.jsxs)("a",{className:(0,a.cn)({"aiui-dark":l==="dark"},"hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]",{"text-[#080A0F]":l==="light"},{"text-[#F5F6F7]":l==="dark"},{"justify-center mt-4":h==="center"},{"mt-1 laptop:mt-0":h==="left"},e),...u?{href:u}:{},"data-headless-type-name":`${V}#${$}`,"data-headless-title-desc-button":`${b}#${v}`,...n?{onClick:n}:{},children:[(0,i.jsx)("div",{className:"truncate whitespace-nowrap",children:s?.textLink}),(0,i.jsx)("div",{className:"lg-desktop:size-5 size-4",children:(0,i.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"100%",height:"100%",viewBox:"0 0 16 16",fill:"none",children:(0,i.jsx)("path",{d:"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z",fill:l==="dark"?"#F5F6F7":"#080A0F",className:"transition-all duration-[0.4s]"})})})]})},B=r.default.forwardRef(({data:t,className:n,classNames:e,as:l="h2",weight:s="bold",onButtonClick:b,...v},h)=>{const{title:u,titleSize:O=4,caption:D,subtitle:M,content:C,countdown:o,showCountdown:U=!1,theme:g="light",extensions:W,align:m="left"}=t,E=(0,r.useRef)(null),p=(0,r.useRef)(null),c=(0,r.useRef)(null),f=(0,r.useRef)(null),[Z,q]=(0,r.useState)(!0),{ref:G,inView:z}=(0,j.useInView)();(0,r.useImperativeHandle)(h,()=>E.current);const J=()=>{q(!1)},K=o?.targetDateTime||o?.targetDate||"",Q=o?.targetDateTime_tz,X=o?.labels?{day:o.labels.days||"Day",hour:o.labels.hours||"Hours",minute:o.labels.minutes||"Mins",second:o.labels.seconds||"Secs"}:void 0;return(0,r.useEffect)(()=>{w.gsap.registerPlugin(F.SplitText,H.ScrollTrigger);function Y(){if(!p.current)return;const tt=p.current?.clientHeight||80;c.current&&c.current.revert(),f.current&&f.current.kill(),c.current=new F.SplitText(p.current,{type:"words",wordsClass:"word"});const k=c.current.words;w.gsap.set(k,{opacity:0}),f.current=H.ScrollTrigger.create({trigger:p.current,start:"bottom bottom-=4%",end:`bottom+=${tt*1.5+60}px bottom-=4%`,scrub:!0,invalidateOnRefresh:!0,onUpdate:et=>{const nt=et.progress,R=k.length||1,it=.5,T=1/R,N=T*(1-it),P=(R-1)*N+T,ot=Math.min(1,P>0?nt/P:0);k.forEach((rt,st)=>{const at=st*N,lt=T;let y=(ot-at)/lt;y=Math.max(0,Math.min(1,y)),w.gsap.set(rt,{opacity:y})})}})}return z&&Y(),()=>{c.current&&c.current.revert(),f.current&&f.current.kill()}},[z]),(0,i.jsxs)("div",{...v,id:W?.id,className:(0,a.cn)("titleBottom title-box flex items-end justify-between gap-2 pb-6",n,e?.wrapper),ref:E,children:[(0,i.jsxs)("div",{ref:G,className:(0,a.cn)("flex-1",e?.container,{"aiui-dark":g==="dark","text-center":m==="center","text-left":m==="left"}),children:[(D||u)&&(0,i.jsx)(d.Heading,{ref:p,as:l,size:O,html:D||u,weight:s,className:(0,a.cn)(xt({theme:g}),e?.title)}),M&&(0,i.jsx)(d.Text,{html:M,as:"p",className:(0,a.cn)(wt({theme:g}),e?.subtitle)}),C&&(0,i.jsx)(d.Text,{html:C,as:"div",size:4,className:(0,a.cn)("title-content text-info-primary desktop:text-base desktop:mt-4 lg-desktop:text-[18px] mt-2 text-[14px] leading-[1.6]",e?.content)}),(0,i.jsx)(A,{data:t,className:(0,a.cn)({"laptop:hidden":m==="left"},e?.button)}),U&&o&&Z&&(0,i.jsx)(d.Countdown,{endDate:K,endDate_tz:Q,timeLabels:X,showDays:o?.showDays,showHours:o?.showHours,showMinutes:o?.showMinutes,showSeconds:o?.showSeconds,theme:g,onExpire:J,hideWhenExpired:!0,align:m==="center"?"center":"left",className:(0,a.cn)("mt-4",e?.countdown)})]}),(0,i.jsx)(A,{data:t,className:(0,a.cn)("hidden",{"laptop:flex":m==="left"},e?.button),onClick:b})]})});B.displayName="Title";var bt=(0,_.withLayout)(B);
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/Title/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\nimport React, { useEffect, useRef, useImperativeHandle, useState } from 'react'\nimport { gsap } from 'gsap'\nimport { SplitText } from 'gsap/dist/SplitText'\nimport { ScrollTrigger } from 'gsap/dist/ScrollTrigger'\nimport { cn } from '../../helpers/utils.js'\nimport { cva } from 'class-variance-authority'\nimport { Heading, Text, Countdown, type HeadingProps } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { TitlePropsBase } from './types.js'\n\nexport interface TitleProps extends TitlePropsBase, Omit<React.HTMLAttributes<HTMLDivElement>, 'className' | 'title'> {}\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useInView } from 'react-intersection-observer'\n\nconst componentType = 'link'\nconst componentName = 'title'\n\n/**\n * \u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst titleHeadingVariants = cva('', {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\n/**\n * \u526F\u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst subtitleVariants = cva(\n 'desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]',\n {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n }\n)\n\nconst TitleButton = ({\n data,\n onClick,\n className,\n}: {\n data: TitleProps['data']\n onClick?: () => void\n className?: string\n}) => {\n const { theme = 'light', extensions, title, caption, align } = data\n if (!extensions?.textLink) return null\n\n const href = extensions?.link ? trackUrlRef(extensions.link, `${componentType}_${componentName}`) : undefined\n\n return (\n <a\n className={cn(\n { 'aiui-dark': theme === 'dark' },\n 'hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]',\n { 'text-[#080A0F]': theme === 'light' },\n { 'text-[#F5F6F7]': theme === 'dark' },\n { 'justify-center mt-4': align === 'center' },\n { 'mt-1 laptop:mt-0': align === 'left' },\n className\n )}\n {...(href ? { href } : {})}\n data-headless-type-name={`${componentType}#${componentName}`}\n data-headless-title-desc-button={`${title}#${caption}`}\n {...(onClick ? { onClick } : {})}\n >\n <div className=\"truncate whitespace-nowrap\">{extensions?.textLink}</div>\n <div className=\"lg-desktop:size-5 size-4\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z\"\n fill={theme === 'dark' ? '#F5F6F7' : '#080A0F'}\n className=\"transition-all duration-[0.4s]\"\n />\n </svg>\n </div>\n </a>\n )\n}\n\nconst Title = React.forwardRef<HTMLDivElement, TitleProps>(\n ({ data, className, classNames, as = 'h2', weight = 'bold', onButtonClick, ...rest }, ref) => {\n const {\n title,\n titleSize = 4,\n caption,\n subtitle,\n content,\n countdown,\n showCountdown = false,\n theme = 'light',\n extensions,\n align = 'left',\n } = data\n const innerRef = useRef<HTMLDivElement>(null)\n const titleRef = useRef<HTMLHeadingElement>(null)\n const splitTextInstance = useRef<SplitText | null>(null)\n const scrollTriggerRef = useRef<ScrollTrigger | null>(null)\n\n // \u63A7\u5236\u5012\u8BA1\u65F6\u663E\u793A\u72B6\u6001\n const [isCountdownVisible, setIsCountdownVisible] = useState(true)\n\n const { ref: inViewRef, inView } = useInView()\n\n useImperativeHandle(ref, () => innerRef.current as HTMLDivElement)\n\n // \u5012\u8BA1\u65F6\u7ED3\u675F\u56DE\u8C03\n const handleCountdownEnd = () => {\n setIsCountdownVisible(false)\n }\n\n // CMS field mapping: new targetDateTime > legacy targetDate\n const countdownEndDate = countdown?.targetDateTime || countdown?.targetDate || ''\n const countdownTz = countdown?.targetDateTime_tz\n // Label mapping: plural keys (Title CMS format) \u2192 atomic Countdown format\n const countdownLabels = countdown?.labels\n ? {\n day: countdown.labels.days || 'Day',\n hour: countdown.labels.hours || 'Hours',\n minute: countdown.labels.minutes || 'Mins',\n second: countdown.labels.seconds || 'Secs',\n }\n : undefined\n\n useEffect(() => {\n gsap.registerPlugin(SplitText, ScrollTrigger)\n function gsapResize() {\n if (!titleRef.current) return\n const height = titleRef.current?.clientHeight || 80\n if (splitTextInstance.current) {\n splitTextInstance.current.revert()\n }\n if (scrollTriggerRef.current) {\n scrollTriggerRef.current.kill()\n }\n splitTextInstance.current = new SplitText(titleRef.current, {\n type: 'words',\n wordsClass: 'word',\n })\n const words = splitTextInstance.current.words\n gsap.set(words, { opacity: 0 })\n scrollTriggerRef.current = ScrollTrigger.create({\n trigger: titleRef.current,\n start: 'bottom bottom-=4%',\n end: `bottom+=${height * 1.5 + 60}px bottom-=4%`,\n scrub: true,\n invalidateOnRefresh: true,\n onUpdate: (self: any) => {\n const progress = self.progress\n const total = words.length || 1\n const overlap = 0.5\n const interval = 1 / total\n const step = interval * (1 - overlap)\n const lastEnd = (total - 1) * step + interval\n const normalizedProgress = Math.min(1, lastEnd > 0 ? progress / lastEnd : 0)\n words.forEach((word: any, i: number) => {\n const start = i * step\n const width = interval\n let opacity = (normalizedProgress - start) / width\n opacity = Math.max(0, Math.min(1, opacity))\n gsap.set(word, { opacity })\n })\n },\n })\n }\n\n if (inView) {\n gsapResize()\n }\n\n return () => {\n splitTextInstance.current && splitTextInstance.current.revert()\n // ScrollTrigger.getAll().forEach((t: { kill: () => any }) => t.kill())\n scrollTriggerRef.current && scrollTriggerRef.current.kill()\n }\n }, [inView])\n\n return (\n <div\n {...rest}\n id={extensions?.id}\n className={cn('titleBottom title-box flex items-end justify-between gap-2 pb-6'
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["'use client'\nimport React, { useEffect, useRef, useImperativeHandle, useState } from 'react'\nimport { gsap } from 'gsap'\nimport { SplitText } from 'gsap/dist/SplitText'\nimport { ScrollTrigger } from 'gsap/dist/ScrollTrigger'\nimport { cn } from '../../helpers/utils.js'\nimport { cva } from 'class-variance-authority'\nimport { Heading, Text, Countdown, type HeadingProps } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { TitlePropsBase } from './types.js'\n\nexport interface TitleProps extends TitlePropsBase, Omit<React.HTMLAttributes<HTMLDivElement>, 'className' | 'title'> {}\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useInView } from 'react-intersection-observer'\n\nconst componentType = 'link'\nconst componentName = 'title'\n\n/**\n * \u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst titleHeadingVariants = cva('', {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\n/**\n * \u526F\u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst subtitleVariants = cva(\n 'desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]',\n {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n }\n)\n\nconst TitleButton = ({\n data,\n onClick,\n className,\n}: {\n data: TitleProps['data']\n onClick?: () => void\n className?: string\n}) => {\n const { theme = 'light', extensions, title, caption, align } = data\n if (!extensions?.textLink) return null\n\n const href = extensions?.link ? trackUrlRef(extensions.link, `${componentType}_${componentName}`) : undefined\n\n return (\n <a\n className={cn(\n { 'aiui-dark': theme === 'dark' },\n 'hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]',\n { 'text-[#080A0F]': theme === 'light' },\n { 'text-[#F5F6F7]': theme === 'dark' },\n { 'justify-center mt-4': align === 'center' },\n { 'mt-1 laptop:mt-0': align === 'left' },\n className\n )}\n {...(href ? { href } : {})}\n data-headless-type-name={`${componentType}#${componentName}`}\n data-headless-title-desc-button={`${title}#${caption}`}\n {...(onClick ? { onClick } : {})}\n >\n <div className=\"truncate whitespace-nowrap\">{extensions?.textLink}</div>\n <div className=\"lg-desktop:size-5 size-4\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z\"\n fill={theme === 'dark' ? '#F5F6F7' : '#080A0F'}\n className=\"transition-all duration-[0.4s]\"\n />\n </svg>\n </div>\n </a>\n )\n}\n\nconst Title = React.forwardRef<HTMLDivElement, TitleProps>(\n ({ data, className, classNames, as = 'h2', weight = 'bold', onButtonClick, ...rest }, ref) => {\n const {\n title,\n titleSize = 4,\n caption,\n subtitle,\n content,\n countdown,\n showCountdown = false,\n theme = 'light',\n extensions,\n align = 'left',\n } = data\n const innerRef = useRef<HTMLDivElement>(null)\n const titleRef = useRef<HTMLHeadingElement>(null)\n const splitTextInstance = useRef<SplitText | null>(null)\n const scrollTriggerRef = useRef<ScrollTrigger | null>(null)\n\n // \u63A7\u5236\u5012\u8BA1\u65F6\u663E\u793A\u72B6\u6001\n const [isCountdownVisible, setIsCountdownVisible] = useState(true)\n\n const { ref: inViewRef, inView } = useInView()\n\n useImperativeHandle(ref, () => innerRef.current as HTMLDivElement)\n\n // \u5012\u8BA1\u65F6\u7ED3\u675F\u56DE\u8C03\n const handleCountdownEnd = () => {\n setIsCountdownVisible(false)\n }\n\n // CMS field mapping: new targetDateTime > legacy targetDate\n const countdownEndDate = countdown?.targetDateTime || countdown?.targetDate || ''\n const countdownTz = countdown?.targetDateTime_tz\n // Label mapping: plural keys (Title CMS format) \u2192 atomic Countdown format\n const countdownLabels = countdown?.labels\n ? {\n day: countdown.labels.days || 'Day',\n hour: countdown.labels.hours || 'Hours',\n minute: countdown.labels.minutes || 'Mins',\n second: countdown.labels.seconds || 'Secs',\n }\n : undefined\n\n useEffect(() => {\n gsap.registerPlugin(SplitText, ScrollTrigger)\n function gsapResize() {\n if (!titleRef.current) return\n const height = titleRef.current?.clientHeight || 80\n if (splitTextInstance.current) {\n splitTextInstance.current.revert()\n }\n if (scrollTriggerRef.current) {\n scrollTriggerRef.current.kill()\n }\n splitTextInstance.current = new SplitText(titleRef.current, {\n type: 'words',\n wordsClass: 'word',\n })\n const words = splitTextInstance.current.words\n gsap.set(words, { opacity: 0 })\n scrollTriggerRef.current = ScrollTrigger.create({\n trigger: titleRef.current,\n start: 'bottom bottom-=4%',\n end: `bottom+=${height * 1.5 + 60}px bottom-=4%`,\n scrub: true,\n invalidateOnRefresh: true,\n onUpdate: (self: any) => {\n const progress = self.progress\n const total = words.length || 1\n const overlap = 0.5\n const interval = 1 / total\n const step = interval * (1 - overlap)\n const lastEnd = (total - 1) * step + interval\n const normalizedProgress = Math.min(1, lastEnd > 0 ? progress / lastEnd : 0)\n words.forEach((word: any, i: number) => {\n const start = i * step\n const width = interval\n let opacity = (normalizedProgress - start) / width\n opacity = Math.max(0, Math.min(1, opacity))\n gsap.set(word, { opacity })\n })\n },\n })\n }\n\n if (inView) {\n gsapResize()\n }\n\n return () => {\n splitTextInstance.current && splitTextInstance.current.revert()\n // ScrollTrigger.getAll().forEach((t: { kill: () => any }) => t.kill())\n scrollTriggerRef.current && scrollTriggerRef.current.kill()\n }\n }, [inView])\n\n return (\n <div\n {...rest}\n id={extensions?.id}\n className={cn(\n 'titleBottom title-box flex items-end justify-between gap-2 pb-6',\n className,\n classNames?.wrapper\n )}\n ref={innerRef}\n >\n <div\n ref={inViewRef}\n className={cn('flex-1', classNames?.container, {\n 'aiui-dark': theme === 'dark',\n 'text-center': align === 'center',\n 'text-left': align === 'left',\n })}\n >\n {(caption || title) && (\n <Heading\n ref={titleRef}\n as={as}\n size={titleSize as HeadingProps['size']}\n html={caption || title}\n weight={weight}\n className={cn(titleHeadingVariants({ theme }), classNames?.title)}\n />\n )}\n {subtitle && (\n <Text html={subtitle} as=\"p\" className={cn(subtitleVariants({ theme }), classNames?.subtitle)} />\n )}\n {content && (\n <Text\n html={content}\n as=\"div\"\n size={4}\n className={cn(\n 'title-content text-info-primary desktop:text-base desktop:mt-4 lg-desktop:text-[18px] mt-2 text-[14px] leading-[1.6]',\n classNames?.content\n )}\n />\n )}\n <TitleButton data={data} className={cn({ 'laptop:hidden': align === 'left' }, classNames?.button)} />\n {showCountdown && countdown && isCountdownVisible && (\n <Countdown\n endDate={countdownEndDate}\n endDate_tz={countdownTz}\n timeLabels={countdownLabels}\n showDays={countdown?.showDays}\n showHours={countdown?.showHours}\n showMinutes={countdown?.showMinutes}\n showSeconds={countdown?.showSeconds}\n theme={theme}\n onExpire={handleCountdownEnd}\n hideWhenExpired={true}\n align={align === 'center' ? 'center' : 'left'}\n className={cn('mt-4', classNames?.countdown)}\n />\n )}\n </div>\n <TitleButton\n data={data}\n className={cn('hidden', { ['laptop:flex']: align === 'left' }, classNames?.button)}\n onClick={onButtonClick}\n />\n </div>\n )\n }\n)\n\nTitle.displayName = 'Title'\n\nexport default withLayout(Title)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Title_exports", "__export", "Title_default", "__toCommonJS", "import_jsx_runtime", "import_react", "import_gsap", "import_SplitText", "import_ScrollTrigger", "import_utils", "import_class_variance_authority", "import_components", "import_Styles", "import_trackUrlRef", "import_react_intersection_observer", "componentType", "componentName", "titleHeadingVariants", "subtitleVariants", "TitleButton", "data", "onClick", "className", "theme", "extensions", "title", "caption", "align", "href", "Title", "React", "classNames", "as", "weight", "onButtonClick", "rest", "ref", "titleSize", "subtitle", "content", "countdown", "showCountdown", "innerRef", "titleRef", "splitTextInstance", "scrollTriggerRef", "isCountdownVisible", "setIsCountdownVisible", "inViewRef", "inView", "handleCountdownEnd", "countdownEndDate", "countdownTz", "countdownLabels", "gsapResize", "height", "words", "self", "progress", "total", "overlap", "interval", "step", "lastEnd", "normalizedProgress", "word", "i", "start", "width", "opacity"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as l,jsxs as h}from"react/jsx-runtime";import*as g from"react";import{cn as p}from"../../helpers/index.js";import{Heading as k,Button as v,Picture as B}from"../../components/index.js";import{withLayout as P}from"../../shared/Styles.js";import{getLocalizedPath as T}from"../../helpers/index.js";import{useAiuiContext as M}from"../AiuiProvider/index.js";import{trackUrlRef as N}from"../../shared/trackUrlRef.js";const D="image",y="PromotionalBar",R=i=>{if(!i)return;const{mobile:e,tablet:m,laptop:u,desktop:d,lgDesktop:f}=i,t=[],r=b=>b?.url,o=r(f),n=r(d),a=r(u),s=r(m),c=r(e);return o?t.push(o):n?t.push(n):a?t.push(a):s?t.push(s):c&&t.push(c),n&&o&&t.push(`${n} 1920`),a&&(n||o)&&t.push(`${a} 1440`),s&&(a||n||o)&&t.push(`${s} 1024`),c&&(s||a||n||o)&&t.push(`${c} 768`),t.length>0?t.join(", "):void 0},x=g.forwardRef(({classNames:i,data:e,className:m,...u},d)=>{const{locale:f="us",pageHandle:t}=M(),{backgroundImage:r,theme:o="dark"}=e,n=g.useMemo(()=>R(r),[r]);return l("div",{ref:d,...u,className:p("laptop:h-[192px] lg-desktop:h-[240px] h-[240px] text-[#080A0F]",{"text-[#F5F6F7]":o==="dark"},i?.root,m),children:h("div",{className:"promotional-bar-content rounded-card relative h-full overflow-hidden",children:[h("div",{className:p("laptop:px-8 laptop:justify-center lg-desktop:max-w-[620px] laptop:max-w-[392px] desktop:max-w-[584px] laptop:py-0 tablet:px-8 laptop:pr-0 relative z-20 flex h-full flex-col p-4",i?.content),children:[e.contentTitle&&l(k,{className:p("line-clamp-2 ",i?.title),html:e.contentTitle,size:3}),e.contentDesc&&l("p",{className:p("laptop:text-[16px] laptop:mt-2 lg-desktop:text-[18px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] ",i?.description),dangerouslySetInnerHTML:{__html:e.contentDesc}}),l("div",{className:"laptop:mt-4 mt-2",children:e.buttonText&&l(v,{as:"a",variant:"link",className:p("!p-0 text-[#F5F6F7]",{"text-[#080A0F]":o==="light"},i?.button),href:N(T(e.buttonLink||"",f),`${t}_${D}_${y}`),iconClassName:"size-4",children:e.buttonText})})]}),l(B,{source:n,className:"absolute inset-0 z-10 ",imgClassName:"h-full object-cover transition-transform duration-300 ease-in-out hover:scale-[1.05]"})]})})});x.displayName="PromotionalBar";var I=P(x);export{I as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/PromotionalBar/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Heading, Button, Picture } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { Media, Theme } from '../../types/props.js'\nimport { getLocalizedPath } from '../../helpers/index.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\n\nexport interface PromotionalBarSemanticName {\n root: 'root'\n content: 'content'\n title: 'title'\n description: 'description'\n button: 'button'\n}\n\n/**\n * \u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u914D\u7F6E\n */\nexport interface ResponsiveBackgroundImage {\n /** \u79FB\u52A8\u7AEF\u56FE\u7247 (<768px) */\n mobile?: Media\n /** \u5E73\u677F\u56FE\u7247 (768-1440px) */\n tablet?: Media\n /** \u7B14\u8BB0\u672C\u56FE\u7247 (1025-1440px) */\n laptop?: Media\n /** \u684C\u9762\u56FE\u7247 (1441-1920px) */\n desktop?: Media\n /** \u8D85\u5927\u684C\u9762\u56FE\u7247 (\u22651921px) */\n lgDesktop?: Media\n}\n\n/**\n * PromotionalBar \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3\n */\nexport interface PromotionalBarData {\n theme: Theme\n /** \u7EC4\u4EF6\u5185\u5BB9\u6807\u9898 */\n contentTitle?: string\n /** \u7EC4\u4EF6\u5185\u5BB9\u63CF\u8FF0 */\n contentDesc?: string\n /** \u6309\u94AE\u6587\u672C */\n buttonText?: string\n /** \u6309\u94AE\u94FE\u63A5 */\n buttonLink?: string\n /** \u80CC\u666F\u56FE\u7247 - \u54CD\u5E94\u5F0F\u56FE\u7247\u5BF9\u8C61 */\n backgroundImage?: ResponsiveBackgroundImage\n}\n\nexport interface PromotionalBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: PromotionalBarData\n classNames?: Partial<Record<keyof PromotionalBarSemanticName, string>>\n}\n\n/**\n * \u5C06\u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u5BF9\u8C61\u8F6C\u6362\u4E3A Picture \u7EC4\u4EF6\u6240\u9700\u7684\u5B57\u7B26\u4E32\u683C\u5F0F\n */\nconst convertResponsiveImageToString = (backgroundImage: ResponsiveBackgroundImage | undefined): string | undefined => {\n if (!backgroundImage) return undefined\n\n const { mobile, tablet, laptop, desktop, lgDesktop } = backgroundImage\n const parts: string[] = []\n\n // \u8F85\u52A9\u51FD\u6570\uFF1A\u4ECE Media \u5BF9\u8C61\u4E2D\u63D0\u53D6 URL\n const getUrl = (media: Media | undefined): string | undefined => {\n return media?.url\n }\n\n // \u9ED8\u8BA4\u56FE\u7247\uFF08\u6700\u5927\u5C3A\u5BF8\uFF09\u653E\u5728\u6700\u524D\u9762\uFF0C\u4E0D\u9700\u8981\u65AD\u70B9\n const lgDesktopUrl = getUrl(lgDesktop)\n const desktopUrl = getUrl(desktop)\n const laptopUrl = getUrl(laptop)\n const tabletUrl = getUrl(tablet)\n const mobileUrl = getUrl(mobile)\n\n if (lgDesktopUrl) parts.push(lgDesktopUrl)\n else if (desktopUrl) parts.push(desktopUrl)\n else if (laptopUrl) parts.push(laptopUrl)\n else if (tabletUrl) parts.push(tabletUrl)\n else if (mobileUrl) parts.push(mobileUrl)\n\n // \u6309\u65AD\u70B9\u4ECE\u5927\u5230\u5C0F\u6DFB\u52A0\n if (desktopUrl && lgDesktopUrl) parts.push(`${desktopUrl} 1920`)\n if (laptopUrl && (desktopUrl || lgDesktopUrl)) parts.push(`${laptopUrl} 1440`)\n if (tabletUrl && (laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${tabletUrl} 1024`)\n if (mobileUrl && (tabletUrl || laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${mobileUrl} 768`)\n\n return parts.length > 0 ? parts.join(', ') : undefined\n}\n\n/**\n * PromotionalBar - \u63A8\u5E7F\u680F\n *\n * @description \u63A8\u5E7F\u680F\n */\nconst PromotionalBar = React.forwardRef<HTMLDivElement, PromotionalBarProps>(\n ({ classNames, data, className, ...rest }, ref) => {\n const { locale = 'us' } = useAiuiContext()\n const { backgroundImage, theme = 'dark' } = data\n const pictureSource = React.useMemo(() => {\n return convertResponsiveImageToString(backgroundImage)\n }, [backgroundImage])\n return (\n <div\n ref={ref}\n {...rest}\n className={cn(\n 'laptop:h-[192px] lg-desktop:h-[240px] h-[240px] text-[#080A0F]',\n {\n 'text-[#F5F6F7]': theme === 'dark',\n },\n classNames?.root,\n className\n )}\n >\n {/* \u63A8\u5E7F\u680F\u5185\u5BB9\u533A\u57DF - \u6839\u636E\u5177\u4F53\u4E1A\u52A1\u9700\u6C42\u5B9A\u5236 */}\n <div className=\"promotional-bar-content rounded-card relative h-full overflow-hidden\">\n <div\n className={cn(\n 'laptop:px-8 laptop:justify-center lg-desktop:max-w-[620px] laptop:max-w-[392px] desktop:max-w-[584px] laptop:py-0 tablet:px-8 laptop:pr-0 relative z-20 flex h-full flex-col p-4',\n classNames?.content\n )}\n >\n {data.contentTitle && (\n <Heading className={cn('line-clamp-2 ', classNames?.title)} html={data.contentTitle} size={3} />\n )}\n {data.contentDesc && (\n <p\n className={cn(\n 'laptop:text-[16px] laptop:mt-2 lg-desktop:text-[18px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] ',\n classNames?.description\n )}\n dangerouslySetInnerHTML={{ __html: data.contentDesc }}\n />\n )}\n <div className=\"laptop:mt-4 mt-2\">\n {data.buttonText && (\n <Button\n as=\"a\"\n variant=\"link\"\n className={cn(\n '!p-0 text-[#F5F6F7]',\n {\n 'text-[#080A0F]': theme === 'light',\n },\n classNames?.button\n )}\n href={getLocalizedPath(data.buttonLink || '', locale)}\n iconClassName=\"size-4\"\n >\n {data.buttonText}\n </Button>\n )}\n </div>\n </div>\n <Picture\n source={pictureSource}\n className=\"absolute inset-0 z-10 \"\n imgClassName=\"h-full object-cover transition-transform duration-300 ease-in-out hover:scale-[1.05]\"\n />\n </div>\n </div>\n )\n }\n)\n\nPromotionalBar.displayName = 'PromotionalBar'\nexport default withLayout(PromotionalBar)\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["jsx", "jsxs", "React", "cn", "Heading", "Button", "Picture", "withLayout", "getLocalizedPath", "useAiuiContext", "convertResponsiveImageToString", "backgroundImage", "mobile", "tablet", "laptop", "desktop", "lgDesktop", "parts", "getUrl", "media", "lgDesktopUrl", "desktopUrl", "laptopUrl", "tabletUrl", "mobileUrl", "PromotionalBar", "classNames", "data", "className", "rest", "ref", "locale", "theme", "pictureSource", "PromotionalBar_default"]
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Heading, Button, Picture } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { Media, Theme } from '../../types/props.js'\nimport { getLocalizedPath } from '../../helpers/index.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\n\nexport interface PromotionalBarSemanticName {\n root: 'root'\n content: 'content'\n title: 'title'\n description: 'description'\n button: 'button'\n}\n\n/**\n * \u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u914D\u7F6E\n */\nexport interface ResponsiveBackgroundImage {\n /** \u79FB\u52A8\u7AEF\u56FE\u7247 (<768px) */\n mobile?: Media\n /** \u5E73\u677F\u56FE\u7247 (768-1440px) */\n tablet?: Media\n /** \u7B14\u8BB0\u672C\u56FE\u7247 (1025-1440px) */\n laptop?: Media\n /** \u684C\u9762\u56FE\u7247 (1441-1920px) */\n desktop?: Media\n /** \u8D85\u5927\u684C\u9762\u56FE\u7247 (\u22651921px) */\n lgDesktop?: Media\n}\n\n/**\n * PromotionalBar \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3\n */\nexport interface PromotionalBarData {\n theme: Theme\n /** \u7EC4\u4EF6\u5185\u5BB9\u6807\u9898 */\n contentTitle?: string\n /** \u7EC4\u4EF6\u5185\u5BB9\u63CF\u8FF0 */\n contentDesc?: string\n /** \u6309\u94AE\u6587\u672C */\n buttonText?: string\n /** \u6309\u94AE\u94FE\u63A5 */\n buttonLink?: string\n /** \u80CC\u666F\u56FE\u7247 - \u54CD\u5E94\u5F0F\u56FE\u7247\u5BF9\u8C61 */\n backgroundImage?: ResponsiveBackgroundImage\n}\n\nexport interface PromotionalBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: PromotionalBarData\n classNames?: Partial<Record<keyof PromotionalBarSemanticName, string>>\n}\n\nconst componentType = 'image'\nconst componentName = 'PromotionalBar'\n\n/**\n * \u5C06\u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u5BF9\u8C61\u8F6C\u6362\u4E3A Picture \u7EC4\u4EF6\u6240\u9700\u7684\u5B57\u7B26\u4E32\u683C\u5F0F\n */\nconst convertResponsiveImageToString = (backgroundImage: ResponsiveBackgroundImage | undefined): string | undefined => {\n if (!backgroundImage) return undefined\n\n const { mobile, tablet, laptop, desktop, lgDesktop } = backgroundImage\n const parts: string[] = []\n\n // \u8F85\u52A9\u51FD\u6570\uFF1A\u4ECE Media \u5BF9\u8C61\u4E2D\u63D0\u53D6 URL\n const getUrl = (media: Media | undefined): string | undefined => {\n return media?.url\n }\n\n // \u9ED8\u8BA4\u56FE\u7247\uFF08\u6700\u5927\u5C3A\u5BF8\uFF09\u653E\u5728\u6700\u524D\u9762\uFF0C\u4E0D\u9700\u8981\u65AD\u70B9\n const lgDesktopUrl = getUrl(lgDesktop)\n const desktopUrl = getUrl(desktop)\n const laptopUrl = getUrl(laptop)\n const tabletUrl = getUrl(tablet)\n const mobileUrl = getUrl(mobile)\n\n if (lgDesktopUrl) parts.push(lgDesktopUrl)\n else if (desktopUrl) parts.push(desktopUrl)\n else if (laptopUrl) parts.push(laptopUrl)\n else if (tabletUrl) parts.push(tabletUrl)\n else if (mobileUrl) parts.push(mobileUrl)\n\n // \u6309\u65AD\u70B9\u4ECE\u5927\u5230\u5C0F\u6DFB\u52A0\n if (desktopUrl && lgDesktopUrl) parts.push(`${desktopUrl} 1920`)\n if (laptopUrl && (desktopUrl || lgDesktopUrl)) parts.push(`${laptopUrl} 1440`)\n if (tabletUrl && (laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${tabletUrl} 1024`)\n if (mobileUrl && (tabletUrl || laptopUrl || desktopUrl || lgDesktopUrl)) parts.push(`${mobileUrl} 768`)\n\n return parts.length > 0 ? parts.join(', ') : undefined\n}\n\n/**\n * PromotionalBar - \u63A8\u5E7F\u680F\n *\n * @description \u63A8\u5E7F\u680F\n */\nconst PromotionalBar = React.forwardRef<HTMLDivElement, PromotionalBarProps>(\n ({ classNames, data, className, ...rest }, ref) => {\n const { locale = 'us', pageHandle } = useAiuiContext()\n const { backgroundImage, theme = 'dark' } = data\n const pictureSource = React.useMemo(() => {\n return convertResponsiveImageToString(backgroundImage)\n }, [backgroundImage])\n return (\n <div\n ref={ref}\n {...rest}\n className={cn(\n 'laptop:h-[192px] lg-desktop:h-[240px] h-[240px] text-[#080A0F]',\n {\n 'text-[#F5F6F7]': theme === 'dark',\n },\n classNames?.root,\n className\n )}\n >\n {/* \u63A8\u5E7F\u680F\u5185\u5BB9\u533A\u57DF - \u6839\u636E\u5177\u4F53\u4E1A\u52A1\u9700\u6C42\u5B9A\u5236 */}\n <div className=\"promotional-bar-content rounded-card relative h-full overflow-hidden\">\n <div\n className={cn(\n 'laptop:px-8 laptop:justify-center lg-desktop:max-w-[620px] laptop:max-w-[392px] desktop:max-w-[584px] laptop:py-0 tablet:px-8 laptop:pr-0 relative z-20 flex h-full flex-col p-4',\n classNames?.content\n )}\n >\n {data.contentTitle && (\n <Heading className={cn('line-clamp-2 ', classNames?.title)} html={data.contentTitle} size={3} />\n )}\n {data.contentDesc && (\n <p\n className={cn(\n 'laptop:text-[16px] laptop:mt-2 lg-desktop:text-[18px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] ',\n classNames?.description\n )}\n dangerouslySetInnerHTML={{ __html: data.contentDesc }}\n />\n )}\n <div className=\"laptop:mt-4 mt-2\">\n {data.buttonText && (\n <Button\n as=\"a\"\n variant=\"link\"\n className={cn(\n '!p-0 text-[#F5F6F7]',\n {\n 'text-[#080A0F]': theme === 'light',\n },\n classNames?.button\n )}\n href={trackUrlRef(\n getLocalizedPath(data.buttonLink || '', locale),\n `${pageHandle}_${componentType}_${componentName}`\n )}\n iconClassName=\"size-4\"\n >\n {data.buttonText}\n </Button>\n )}\n </div>\n </div>\n <Picture\n source={pictureSource}\n className=\"absolute inset-0 z-10 \"\n imgClassName=\"h-full object-cover transition-transform duration-300 ease-in-out hover:scale-[1.05]\"\n />\n </div>\n </div>\n )\n }\n)\n\nPromotionalBar.displayName = 'PromotionalBar'\nexport default withLayout(PromotionalBar)\n"],
|
|
5
|
+
"mappings": "aA4HU,OAOI,OAAAA,EAPJ,QAAAC,MAAA,oBA1HV,UAAYC,MAAW,QACvB,OAAS,MAAAC,MAAU,yBACnB,OAAS,WAAAC,EAAS,UAAAC,EAAQ,WAAAC,MAAe,4BACzC,OAAS,cAAAC,MAAkB,yBAE3B,OAAS,oBAAAC,MAAwB,yBACjC,OAAS,kBAAAC,MAAsB,2BAC/B,OAAS,eAAAC,MAAmB,8BAiD5B,MAAMC,EAAgB,QAChBC,EAAgB,iBAKhBC,EAAkCC,GAA+E,CACrH,GAAI,CAACA,EAAiB,OAEtB,KAAM,CAAE,OAAAC,EAAQ,OAAAC,EAAQ,OAAAC,EAAQ,QAAAC,EAAS,UAAAC,CAAU,EAAIL,EACjDM,EAAkB,CAAC,EAGnBC,EAAUC,GACPA,GAAO,IAIVC,EAAeF,EAAOF,CAAS,EAC/BK,EAAaH,EAAOH,CAAO,EAC3BO,EAAYJ,EAAOJ,CAAM,EACzBS,EAAYL,EAAOL,CAAM,EACzBW,EAAYN,EAAON,CAAM,EAE/B,OAAIQ,EAAcH,EAAM,KAAKG,CAAY,EAChCC,EAAYJ,EAAM,KAAKI,CAAU,EACjCC,EAAWL,EAAM,KAAKK,CAAS,EAC/BC,EAAWN,EAAM,KAAKM,CAAS,EAC/BC,GAAWP,EAAM,KAAKO,CAAS,EAGpCH,GAAcD,GAAcH,EAAM,KAAK,GAAGI,CAAU,OAAO,EAC3DC,IAAcD,GAAcD,IAAeH,EAAM,KAAK,GAAGK,CAAS,OAAO,EACzEC,IAAcD,GAAaD,GAAcD,IAAeH,EAAM,KAAK,GAAGM,CAAS,OAAO,EACtFC,IAAcD,GAAaD,GAAaD,GAAcD,IAAeH,EAAM,KAAK,GAAGO,CAAS,MAAM,EAE/FP,EAAM,OAAS,EAAIA,EAAM,KAAK,IAAI,EAAI,MAC/C,EAOMQ,EAAiB1B,EAAM,WAC3B,CAAC,CAAE,WAAA2B,EAAY,KAAAC,EAAM,UAAAC,EAAW,GAAGC,CAAK,EAAGC,IAAQ,CACjD,KAAM,CAAE,OAAAC,EAAS,KAAM,WAAAC,CAAW,EAAI1B,EAAe,EAC/C,CAAE,gBAAAK,EAAiB,MAAAsB,EAAQ,MAAO,EAAIN,EACtCO,EAAgBnC,EAAM,QAAQ,IAC3BW,EAA+BC,CAAe,EACpD,CAACA,CAAe,CAAC,EACpB,OACEd,EAAC,OACC,IAAKiC,EACJ,GAAGD,EACJ,UAAW7B,EACT,iEACA,CACE,iBAAkBiC,IAAU,MAC9B,EACAP,GAAY,KACZE,CACF,EAGA,SAAA9B,EAAC,OAAI,UAAU,uEACb,UAAAA,EAAC,OACC,UAAWE,EACT,mLACA0B,GAAY,OACd,EAEC,UAAAC,EAAK,cACJ9B,EAACI,EAAA,CAAQ,UAAWD,EAAG,gBAAiB0B,GAAY,KAAK,EAAG,KAAMC,EAAK,aAAc,KAAM,EAAG,EAE/FA,EAAK,aACJ9B,EAAC,KACC,UAAWG,EACT,+GACA0B,GAAY,WACd,EACA,wBAAyB,CAAE,OAAQC,EAAK,WAAY,EACtD,EAEF9B,EAAC,OAAI,UAAU,mBACZ,SAAA8B,EAAK,YACJ9B,EAACK,EAAA,CACC,GAAG,IACH,QAAQ,OACR,UAAWF,EACT,sBACA,CACE,iBAAkBiC,IAAU,OAC9B,EACAP,GAAY,MACd,EACA,KAAMnB,EACJF,EAAiBsB,EAAK,YAAc,GAAII,CAAM,EAC9C,GAAGC,CAAU,IAAIxB,CAAa,IAAIC,CAAa,EACjD,EACA,cAAc,SAEb,SAAAkB,EAAK,WACR,EAEJ,GACF,EACA9B,EAACM,EAAA,CACC,OAAQ+B,EACR,UAAU,yBACV,aAAa,uFACf,GACF,EACF,CAEJ,CACF,EAEAT,EAAe,YAAc,iBAC7B,IAAOU,EAAQ/B,EAAWqB,CAAc",
|
|
6
|
+
"names": ["jsx", "jsxs", "React", "cn", "Heading", "Button", "Picture", "withLayout", "getLocalizedPath", "useAiuiContext", "trackUrlRef", "componentType", "componentName", "convertResponsiveImageToString", "backgroundImage", "mobile", "tablet", "laptop", "desktop", "lgDesktop", "parts", "getUrl", "media", "lgDesktopUrl", "desktopUrl", "laptopUrl", "tabletUrl", "mobileUrl", "PromotionalBar", "classNames", "data", "className", "rest", "ref", "locale", "pageHandle", "theme", "pictureSource", "PromotionalBar_default"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{Fragment as ce,jsx as t,jsxs as d}from"react/jsx-runtime";import*as a from"react";import{cn as o,getLocalizedPath as $}from"../../helpers/index.js";import{Heading as R,Text as Q,Badge as q,Button as A,Picture as O}from"../../components/index.js";import J from"../Media/index.js";import{Swiper as X,SwiperSlide as Y}from"swiper/react";import{Mousewheel as Z}from"swiper/modules";import"swiper/css";import"swiper/css/navigation";import{withLayout as ee}from"../../shared/Styles.js";import{useGridRowCount as te}from"../../hooks/useGridRowCount.js";import{useExposure as ie}from"../../hooks/useExposure.js";import{useViewItemList as oe}from"../../hooks/useViewItemList.js";import{trackUrlRef as ae}from"../../shared/trackUrlRef.js";import{useAiuiContext as G}from"../AiuiProvider/index.js";import{gaTrack as E}from"../../shared/track.js";const re="shelf",ne="scene_shelf_v2",se=()=>t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:t("path",{d:"M8 5.14v13.72L19 12 8 5.14z",fill:"white"})}),le=()=>d("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[t("rect",{x:"6",y:"5",width:"4",height:"14",rx:"1",fill:"white"}),t("rect",{x:"14",y:"5",width:"4",height:"14",rx:"1",fill:"white"})]}),H=a.memo(({product:e,isShowTag:p=!0,onImageClick:l,onLearnMore:g,onShopNow:w,onAddToCart:S,secondaryButtonText:v,secondaryButtonFun:y,primaryButtonText:x,primaryButtonFun:P,classNames:n,className:r,theme:T,index:s})=>{const{locale:V="us",trackingData:N}=G(),[B,L]=a.useState(!1),[k,M]=a.useState(!1),u=N?.pageGroup,h=a.useCallback(async(c,_)=>{if(!c)return;const C=_==="primary"?L:M;C(!0);try{switch(c){case"buyNow":await w?.(e);break;case"addCart":await S?.(e);break;case"learnMore":await g?.(e?.href??"");break;default:break}}finally{C(!1)}},[g,w,S,e]),z=a.useCallback(()=>h(P,"primary"),[h,P]),I=a.useCallback(()=>h(y,"secondary"),[h,y]),m=a.useCallback(c=>{!e.href&&l&&c.preventDefault(),l?.(e),E({event:"ga4Event",event_name:"select_item",item_list_name:"Scene_Shelf_2_Products",page_group:u,items:[{item_id:e.sku,item_name:e.title,item_variant:e.variantId,price:e.currentPrice,index:s}]})},[s,l,u,e]);return d("div",{className:o("scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4",r,n?.productCard,{"bg-container-secondary-0":T==="dark"}),children:[e.href?t("a",{href:$(ae(e.href,u+"_"+re+"_"+ne),V),onClick:m,className:o("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80",n?.productCardImage),"aria-label":`View ${e.title}`,children:t(O,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}):t("div",{className:o("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ",l&&"cursor-pointer transition-opacity hover:opacity-80",n?.productCardImage),onClick:l?m:void 0,role:l?"button":void 0,tabIndex:l?0:void 0,"aria-label":l?`View ${e.title}`:void 0,children:t(O,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}),d("div",{className:"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4",children:[d("div",{className:"flex flex-col gap-2",children:[t("div",{className:o("scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1",n?.productCardTags),children:p&&e?.tags?.map((c,_)=>t(q,{variant:c.variant??"outline",size:"sm",className:"",children:c.label},_))}),t(R,{as:"h3",size:2,className:o("scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]",n?.productCardTitle),children:e.title}),e.description&&t(Q,{as:"p",size:1,className:o("scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1",n?.productCardDescription),children:e.description})]}),d("div",{className:"flex flex-col gap-2",children:[d("div",{className:o("scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1",n?.productCardPriceWrapper),children:[t(R,{as:"h6",size:2,className:o("scene-shelf-v2-product-card-current-price text-info-primary",n?.productCardCurrentPrice),children:e.currentPrice}),e.originalPrice&&t(R,{as:"h6",size:2,className:o("scene-shelf-v2-product-card-original-price text-info-tertiary line-through",n?.productCardOriginalPrice),children:e.originalPrice})]}),(v||x)&&d("div",{className:o("scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2",n?.productCardButtons),children:[v&&t(A,{variant:"secondary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{I(),E({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:u||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:v,SKU:e.sku||"",position:s}})},disabled:e.soldOut&&y!=="learnMore",loading:k,children:v}),x&&t(A,{variant:"primary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{z(),E({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:u||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:x,SKU:e.sku||"",position:s}})},disabled:e.soldOut&&P!=="learnMore",loading:B,children:x})]})]})]})]})});H.displayName="SceneShelfV2.ProductCard";const U=a.forwardRef(({className:e,classNames:p={},data:l,onPlayClick:g,onImageClick:w,onLearnMore:S,onShopNow:v,onAddToCart:y,...x},P)=>{const{theme:n="light",sceneImage:r,productsTitle:T,products:s,secondaryButtonText:V,secondaryButtonFun:N,primaryButtonText:B,primaryButtonFun:L,viewMoreLimit:k=2,copy:M}=l,u=a.useRef(null),h=a.useRef(null),z=a.useRef(null),[I,m]=a.useState(!1),[c,_]=a.useState(!1),{trackingData:C}=G();ie(h,{componentType:"image",componentName:"scene_shelf_banner"}),oe(z,{componentType:"video",componentName:"scene_shelf_banner",itemListName:"Scene_Shelf_2_Products",items:s.map((i,f)=>({item_id:i.sku??"",item_name:i.title,item_variant:i.variantId??"",price:i.currentPrice,index:f})),tabName:""});const D=te({rows:k??0,mobileCols:2}),F=a.useMemo(()=>[r?.pc,r?.desktop,r?.laptop,r?.pad,r?.mobile].some(i=>i?.mimeType==="video/mp4"),[r]),W=a.useCallback(()=>{const i=u.current;i?i.paused?(i.play(),m(!0),g?.(!0)):(i.pause(),m(!1),g?.(!1)):g?.(!0),E({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:C?.pageGroup,component_type:"video",component_name:"scene_shelf_banner",position:1,creative_id:r?.pc?.id}})},[g,r?.pc?.id,C?.pageGroup]);return a.useEffect(()=>{const i=u.current;if(!i||!F)return;const f=new IntersectionObserver(b=>{b.forEach(j=>{j.isIntersecting?i.play().catch(K=>{console.warn("Video autoplay failed:",K)}):i.pause()})},{threshold:.5});return f.observe(i),()=>{f.disconnect()}},[]),d("div",{...x,ref:P,className:o("scene-shelf-v2-root w-full overflow-hidden",{"aiui-dark":n==="dark"},e,p?.root),children:[d("div",{className:o("scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden",p?.media),ref:h,children:[t(J,{pcImage:r?.pc,desktopImage:r?.desktop,laptopImage:r?.laptop,padImage:r?.pad,mobileImage:r?.mobile,className:"size-full",videoClassName:"absolute inset-0 size-full object-cover",videoRef:u,onVideoPlay:()=>m(!0),onVideoPause:()=>m(!1),onVideoEnded:()=>m(!1)}),t("div",{"aria-hidden":"true",className:o("scene-shelf-v2-media-overlay pointer-events-none absolute inset-0",p?.mediaOverlay)}),F&&t("div",{className:"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6",children:t("button",{type:"button","aria-label":I?"Pause video":"Play video",onClick:W,className:o("scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80",p?.mediaPlayButton),children:I?t(le,{}):t(se,{})})})]}),d("div",{ref:z,className:o("scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3",p?.products),children:[T&&t(R,{as:"h2",size:3,className:o("scene-shelf-v2-products-title text-info-primary",p?.productsTitle),html:T}),t("div",{className:"tablet:hidden grid grid-cols-2 gap-3",children:(()=>{const i=k!==void 0&&k>0&&s.length>D,f=i&&!c?s.slice(0,D):s;return d(ce,{children:[f.map((b,j)=>t(H,{isShowTag:l.isShowTag??!0,product:b,onImageClick:w,onLearnMore:S,onShopNow:v,onAddToCart:y,secondaryButtonText:V,secondaryButtonFun:N,primaryButtonText:B,primaryButtonFun:L,classNames:p,theme:n,index:j},b.productKey)),i&&t("div",{className:"col-span-2 mt-6 flex justify-center",children:d("button",{type:"button",onClick:()=>_(b=>!b),className:"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors","aria-expanded":c,children:[c?M?.viewLessLabel??"View Less":M?.viewMoreLabel??"View More",t("svg",{className:o("size-4 transition-transform",c&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]})})]})})()}),t("div",{className:"tablet:block hidden",children:t("div",{className:"relative",children:t(X,{slidesPerView:"auto",observer:!0,observeParents:!0,modules:[Z],mousewheel:{enabled:!0,forceToAxis:!0,sensitivity:1},className:"!overflow-visible",breakpoints:{768:{spaceBetween:16,slidesPerView:s.length>3?2.3:2},1024:{spaceBetween:16,slidesPerView:s.length>3?2.8:3},1440:{spaceBetween:16,slidesPerView:s.length>4?3.8:4},1920:{spaceBetween:16,slidesPerView:s.length>4?3.8:4}},children:s.map((i,f)=>t(Y,{className:o("!h-auto ",p.productCardSlideWrapper),children:t(H,{product:i,isShowTag:l.isShowTag??!0,onImageClick:w,onLearnMore:S,onShopNow:v,onAddToCart:y,secondaryButtonText:V,secondaryButtonFun:N,primaryButtonText:B,primaryButtonFun:L,classNames:p,theme:n,index:f})},i.productKey))})})})]})]})});U.displayName="SceneShelfV2";var ke=ee(U);export{H as SceneShelfV2ProductCard,ke as default};
|
|
1
|
+
"use client";import{Fragment as ce,jsx as t,jsxs as d}from"react/jsx-runtime";import*as a from"react";import{cn as o,getLocalizedPath as $}from"../../helpers/index.js";import{Heading as R,Text as Q,Badge as q,Button as A,Picture as O}from"../../components/index.js";import J from"../Media/index.js";import{Swiper as X,SwiperSlide as Y}from"swiper/react";import{Mousewheel as Z}from"swiper/modules";import"swiper/css";import"swiper/css/navigation";import{withLayout as ee}from"../../shared/Styles.js";import{useGridRowCount as te}from"../../hooks/useGridRowCount.js";import{useExposure as ie}from"../../hooks/useExposure.js";import{useViewItemList as oe}from"../../hooks/useViewItemList.js";import{trackUrlRef as ae}from"../../shared/trackUrlRef.js";import{useAiuiContext as G}from"../AiuiProvider/index.js";import{gaTrack as E}from"../../shared/track.js";const ne="shelf",re="scene_shelf_v2",se=()=>t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:t("path",{d:"M8 5.14v13.72L19 12 8 5.14z",fill:"white"})}),le=()=>d("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[t("rect",{x:"6",y:"5",width:"4",height:"14",rx:"1",fill:"white"}),t("rect",{x:"14",y:"5",width:"4",height:"14",rx:"1",fill:"white"})]}),H=a.memo(({product:e,isShowTag:p=!0,onImageClick:l,onLearnMore:g,onShopNow:w,onAddToCart:S,secondaryButtonText:v,secondaryButtonFun:y,primaryButtonText:x,primaryButtonFun:P,classNames:r,className:n,theme:T,index:s})=>{const{locale:V="us",trackingData:N}=G(),[B,L]=a.useState(!1),[_,M]=a.useState(!1),m=N?.pageGroup,h=a.useCallback(async(c,k)=>{if(!c)return;const C=k==="primary"?L:M;C(!0);try{switch(c){case"buyNow":await w?.(e);break;case"addCart":await S?.(e);break;case"learnMore":await g?.(e?.href??"");break;default:break}}finally{C(!1)}},[g,w,S,e]),z=a.useCallback(()=>h(P,"primary"),[h,P]),I=a.useCallback(()=>h(y,"secondary"),[h,y]),u=a.useCallback(c=>{!e.href&&l&&c.preventDefault(),l?.(e),E({event:"ga4Event",event_name:"select_item",item_list_name:"Scene_Shelf_2_Products",page_group:m,items:[{item_id:e.sku,item_name:e.custom_name||e.title,item_variant:e.variantId,price:e.currentPrice,index:s}]})},[s,l,m,e]);return d("div",{className:o("scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4",n,r?.productCard,{"bg-container-secondary-0":T==="dark"}),children:[e.href?t("a",{href:$(ae(e.href,m+"_"+ne+"_"+re),V),onClick:u,className:o("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80",r?.productCardImage),"aria-label":`View ${e.title}`,children:t(O,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}):t("div",{className:o("scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ",l&&"cursor-pointer transition-opacity hover:opacity-80",r?.productCardImage),onClick:l?u:void 0,role:l?"button":void 0,tabIndex:l?0:void 0,"aria-label":l?`View ${e.title}`:void 0,children:t(O,{source:e.imageUrl,alt:e.imageAlt,className:"size-full",imgClassName:"object-contain"})}),d("div",{className:"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4",children:[d("div",{className:"flex flex-col gap-2",children:[t("div",{className:o("scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1",r?.productCardTags),children:p&&e?.tags?.map((c,k)=>t(q,{variant:c.variant??"outline",size:"sm",className:"",children:c.label},k))}),t(R,{as:"h3",size:2,className:o("scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]",r?.productCardTitle),children:e.custom_name||e.title}),(e.custom_description||e.description)&&t(Q,{as:"p",size:1,className:o("scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1",r?.productCardDescription),children:e.custom_description||e.description})]}),d("div",{className:"flex flex-col gap-2",children:[d("div",{className:o("scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1",r?.productCardPriceWrapper),children:[t(R,{as:"h6",size:2,className:o("scene-shelf-v2-product-card-current-price text-info-primary",r?.productCardCurrentPrice),children:e.currentPrice}),e.originalPrice&&t(R,{as:"h6",size:2,className:o("scene-shelf-v2-product-card-original-price text-info-tertiary line-through",r?.productCardOriginalPrice),children:e.originalPrice})]}),(v||x)&&d("div",{className:o("scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2",r?.productCardButtons),children:[v&&t(A,{variant:"secondary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{I(),E({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:m||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:v,SKU:e.sku||"",position:s}})},disabled:e.soldOut&&y!=="learnMore",loading:_,children:v}),x&&t(A,{variant:"primary",className:"laptop:grow-0 flex-1 whitespace-nowrap",onClick:()=>{z(),E({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:m||"Home Page",component_type:"copy",component_name:"scene_shelf_product",component_title:e.title,component_description:"",button_name:x,SKU:e.sku||"",position:s}})},disabled:e.soldOut&&P!=="learnMore",loading:B,children:x})]})]})]})]})});H.displayName="SceneShelfV2.ProductCard";const U=a.forwardRef(({className:e,classNames:p={},data:l,onPlayClick:g,onImageClick:w,onLearnMore:S,onShopNow:v,onAddToCart:y,...x},P)=>{const{theme:r="light",sceneImage:n,productsTitle:T,products:s,secondaryButtonText:V,secondaryButtonFun:N,primaryButtonText:B,primaryButtonFun:L,viewMoreLimit:_=2,copy:M}=l,m=a.useRef(null),h=a.useRef(null),z=a.useRef(null),[I,u]=a.useState(!1),[c,k]=a.useState(!1),{trackingData:C}=G();ie(h,{componentType:"image",componentName:"scene_shelf_banner"}),oe(z,{componentType:"video",componentName:"scene_shelf_banner",itemListName:"Scene_Shelf_2_Products",items:s.map((i,f)=>({item_id:i.sku??"",item_name:i.title,item_variant:i.variantId??"",price:i.currentPrice,index:f})),tabName:""});const D=te({rows:_??0,mobileCols:2}),F=a.useMemo(()=>[n?.pc,n?.desktop,n?.laptop,n?.pad,n?.mobile].some(i=>i?.mimeType==="video/mp4"),[n]),W=a.useCallback(()=>{const i=m.current;i?i.paused?(i.play(),u(!0),g?.(!0)):(i.pause(),u(!1),g?.(!1)):g?.(!0),E({event:"ga4Event",event_name:"component_click",event_parameters:{page_group:C?.pageGroup,component_type:"video",component_name:"scene_shelf_banner",position:1,creative_id:n?.pc?.id}})},[g,n?.pc?.id,C?.pageGroup]);return a.useEffect(()=>{const i=m.current;if(!i||!F)return;const f=new IntersectionObserver(b=>{b.forEach(j=>{j.isIntersecting?i.play().catch(K=>{console.warn("Video autoplay failed:",K)}):i.pause()})},{threshold:.5});return f.observe(i),()=>{f.disconnect()}},[]),d("div",{...x,ref:P,className:o("scene-shelf-v2-root w-full overflow-hidden",{"aiui-dark":r==="dark"},e,p?.root),children:[d("div",{className:o("scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden",p?.media),ref:h,children:[t(J,{pcImage:n?.pc,desktopImage:n?.desktop,laptopImage:n?.laptop,padImage:n?.pad,mobileImage:n?.mobile,className:"size-full",videoClassName:"absolute inset-0 size-full object-cover",videoRef:m,onVideoPlay:()=>u(!0),onVideoPause:()=>u(!1),onVideoEnded:()=>u(!1)}),t("div",{"aria-hidden":"true",className:o("scene-shelf-v2-media-overlay pointer-events-none absolute inset-0",p?.mediaOverlay)}),F&&t("div",{className:"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6",children:t("button",{type:"button","aria-label":I?"Pause video":"Play video",onClick:W,className:o("scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80",p?.mediaPlayButton),children:I?t(le,{}):t(se,{})})})]}),d("div",{ref:z,className:o("scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3",p?.products),children:[T&&t(R,{as:"h2",size:3,className:o("scene-shelf-v2-products-title text-info-primary",p?.productsTitle),html:T}),t("div",{className:"tablet:hidden grid grid-cols-2 gap-3",children:(()=>{const i=_!==void 0&&_>0&&s.length>D,f=i&&!c?s.slice(0,D):s;return d(ce,{children:[f.map((b,j)=>t(H,{isShowTag:l.isShowTag??!0,product:b,onImageClick:w,onLearnMore:S,onShopNow:v,onAddToCart:y,secondaryButtonText:V,secondaryButtonFun:N,primaryButtonText:B,primaryButtonFun:L,classNames:p,theme:r,index:j},b.productKey)),i&&t("div",{className:"col-span-2 mt-6 flex justify-center",children:d("button",{type:"button",onClick:()=>k(b=>!b),className:"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors","aria-expanded":c,children:[c?M?.viewLessLabel??"View Less":M?.viewMoreLabel??"View More",t("svg",{className:o("size-4 transition-transform",c&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:t("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]})})]})})()}),t("div",{className:"tablet:block hidden",children:t("div",{className:"relative",children:t(X,{slidesPerView:"auto",observer:!0,observeParents:!0,modules:[Z],mousewheel:{enabled:!0,forceToAxis:!0,sensitivity:1},className:"!overflow-visible",breakpoints:{768:{spaceBetween:16,slidesPerView:s.length>3?2.3:2},1024:{spaceBetween:16,slidesPerView:s.length>3?2.8:3},1440:{spaceBetween:16,slidesPerView:s.length>4?3.8:4},1920:{spaceBetween:16,slidesPerView:s.length>4?3.8:4}},children:s.map((i,f)=>t(Y,{className:o("!h-auto ",p.productCardSlideWrapper),children:t(H,{product:i,isShowTag:l.isShowTag??!0,onImageClick:w,onLearnMore:S,onShopNow:v,onAddToCart:y,secondaryButtonText:V,secondaryButtonFun:N,primaryButtonText:B,primaryButtonFun:L,classNames:p,theme:r,index:f})},i.productKey))})})})]})]})});U.displayName="SceneShelfV2";var _e=ee(U);export{H as SceneShelfV2ProductCard,_e as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/SceneShelfV2/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn, getLocalizedPath } from '../../helpers/index.js'\nimport { Heading, Text, Badge, Button, Picture } from '../../components/index.js'\nimport Media from '../Media/index.js'\nimport type { ResponsiveMedia, Theme } from '../../types/props.js'\nimport { Swiper, SwiperSlide } from 'swiper/react'\nimport { Mousewheel } from 'swiper/modules'\nimport 'swiper/css'\nimport 'swiper/css/navigation'\nimport { withLayout } from '../../shared/Styles.js'\nimport { useGridRowCount } from '../../hooks/useGridRowCount.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { useViewItemList } from '../../hooks/useViewItemList.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport { gaTrack } from '../../shared/track.js'\n\nconst componentType = 'shelf'\nconst componentName = 'scene_shelf_v2'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Types\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * \u6309\u94AE\u529F\u80FD\u7C7B\u578B\n */\nexport type ButtonFunctionType = 'buyNow' | 'addCart' | 'learnMore'\n\nexport type SceneShelfV2SemanticName =\n | 'root'\n | 'media'\n | 'mediaOverlay'\n | 'mediaQuote'\n | 'mediaPlayButton'\n | 'products'\n | 'productsTitle'\n | 'productGrid'\n | 'productCardSlideWrapper'\n | 'productCard'\n | 'productCardImage'\n | 'productCardTags'\n | 'productCardTitle'\n | 'productCardDescription'\n | 'productCardPriceWrapper'\n | 'productCardCurrentPrice'\n | 'productCardOriginalPrice'\n | 'productCardButtons'\n\nexport interface SceneShelfV2Tag {\n label: string\n variant?: 'outline' | 'fill'\n}\n\nexport interface SceneShelfV2Product {\n /** \u4EA7\u54C1\u552F\u4E00\u6807\u8BC6 */\n productKey: string\n /** \u4EA7\u54C1\u4E3B\u6807\u9898 */\n title: string\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u4EA7\u54C1\u56FE\u7247 */\n imageUrl: string\n imageAlt: string\n /**\n * \u4EA7\u54C1\u94FE\u63A5 URL\u3002\n */\n href?: string\n /** \u5F53\u524D\u4EF7\u683C\uFF08\u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u5982 \"$1,999.00\"\uFF09 */\n currentPrice: string\n /** \u539F\u4EF7\uFF08\u663E\u793A\u5220\u9664\u7EBF\uFF09 */\n originalPrice?: string\n /** \u6807\u7B7E\u5217\u8868 */\n tags?: SceneShelfV2Tag[]\n /** \u662F\u5426\u552E\u7F44 */\n soldOut?: boolean\n /**\n * sku\n */\n sku?: string\n /**\n * \u53D8\u4F53id\n */\n variantId?: string\n}\n\n/**\n * \u6587\u6848\u914D\u7F6E\n */\nexport interface SceneShelfV2CopyConfig {\n /** \u67E5\u770B\u66F4\u591A\u6807\u7B7E */\n viewMoreLabel?: string\n /** \u6536\u8D77\u6807\u7B7E */\n viewLessLabel?: string\n}\n\nexport interface SceneShelfV2Data {\n theme?: 'light' | 'dark'\n isShowTag?: boolean\n sceneImage: ResponsiveMedia\n /** \u4EA7\u54C1\u533A\u6807\u9898\uFF08\u53EF\u9009\uFF09 */\n productsTitle?: string\n /** \u4EA7\u54C1\u5217\u8868 */\n products: SceneShelfV2Product[]\n /** \u6B21\u8981\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u6B21\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n secondaryButtonFun?: ButtonFunctionType\n /** \u4E3B\u8981\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u4E3B\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n primaryButtonFun?: ButtonFunctionType\n /** \u67E5\u770B\u66F4\u591A\u9650\u5236\u6570\uFF08\u624B\u673A\u7AEF\u8D85\u8FC7\u4E24\u884C\u65F6\u663E\u793AviewMore\u6309\u94AE\uFF09 */\n viewMoreLimit?: number\n /** \u6587\u6848\u914D\u7F6E */\n copy?: SceneShelfV2CopyConfig\n}\n\nexport interface SceneShelfV2Props extends React.HTMLAttributes<HTMLDivElement> {\n data: SceneShelfV2Data\n /**\n * \u70B9\u51FB\u64AD\u653E/\u6682\u505C\u6309\u94AE\u56DE\u8C03\u3002\n * \u5F53\u5A92\u4F53\u533A\u4E3A\u89C6\u9891\u65F6\uFF0C\u7EC4\u4EF6\u5185\u90E8\u4F1A\u81EA\u52A8\u63A7\u5236\u64AD\u653E/\u6682\u505C,\u6B64\u56DE\u8C03\u4ECD\u4F1A\u89E6\u53D1\u3002\n */\n onPlayClick?: (isPlaying: boolean) => void\n /** \u70B9\u51FB\u4EA7\u54C1\u56FE\u7247\u56DE\u8C03 */\n onImageClick?: (product: SceneShelfV2Product) => void\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: SceneShelfV2Product) => void | Promise<void>\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Icons\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PlayIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 5.14v13.72L19 12 8 5.14z\" fill=\"white\" />\n </svg>\n)\n\nconst PauseIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n </svg>\n)\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Product Card\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface ProductCardInnerProps {\n product: SceneShelfV2Product\n isShowTag: boolean\n onImageClick?: (product: SceneShelfV2Product) => void\n onLearnMore?: (link: string) => void | Promise<void>\n onShopNow?: (product: SceneShelfV2Product) => void | Promise<void>\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n className?: string\n theme?: Theme\n index?: number\n}\n\nconst ProductCardInner = React.memo(\n ({\n product,\n isShowTag = true,\n onImageClick,\n onLearnMore,\n onShopNow,\n onAddToCart,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n classNames,\n className,\n theme,\n index,\n }: ProductCardInnerProps) => {\n const { locale = 'us', trackingData } = useAiuiContext()\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n\n const pageGroup = trackingData?.pageGroup\n\n // \u6839\u636E\u6309\u94AE\u529F\u80FD\u7C7B\u578B\u8C03\u7528\u76F8\u5E94\u7684\u56DE\u8C03\u51FD\u6570\n const handleButtonClick = React.useCallback(\n async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n\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 default:\n break\n }\n } finally {\n setLoading(false)\n }\n },\n [onLearnMore, onShopNow, onAddToCart, product]\n )\n\n const handlePrimary = React.useCallback(\n () => handleButtonClick(primaryButtonFun, 'primary'),\n [handleButtonClick, primaryButtonFun]\n )\n const handleSecondary = React.useCallback(\n () => handleButtonClick(secondaryButtonFun, 'secondary'),\n [handleButtonClick, secondaryButtonFun]\n )\n\n const handleImageClick = React.useCallback(\n (e: React.MouseEvent) => {\n // \u5982\u679C\u6CA1\u6709\u63D0\u4F9B href \u4E14\u6709\u70B9\u51FB\u56DE\u8C03\uFF0C\u963B\u6B62\u9ED8\u8BA4\u884C\u4E3A\n if (!product.href && onImageClick) {\n e.preventDefault()\n }\n onImageClick?.(product)\n gaTrack({\n event: 'ga4Event',\n event_name: 'select_item',\n item_list_name: 'Scene_Shelf_2_Products',\n page_group: pageGroup,\n items: [\n {\n item_id: product.sku,\n item_name: product.title,\n item_variant: product.variantId,\n price: product.currentPrice,\n index: index,\n },\n ],\n })\n },\n [index, onImageClick, pageGroup, product]\n )\n\n return (\n <div\n className={cn(\n 'scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4',\n className,\n classNames?.productCard,\n {\n 'bg-container-secondary-0': theme === 'dark',\n }\n )}\n >\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n {product.href ? (\n <a\n href={getLocalizedPath(\n trackUrlRef(product.href, pageGroup + '_' + componentType + '_' + componentName),\n locale\n )}\n onClick={handleImageClick}\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n aria-label={`View ${product.title}`}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </a>\n ) : (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ',\n onImageClick && 'cursor-pointer transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n onClick={onImageClick ? handleImageClick : undefined}\n role={onImageClick ? 'button' : undefined}\n tabIndex={onImageClick ? 0 : undefined}\n aria-label={onImageClick ? `View ${product.title}` : undefined}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </div>\n )}\n\n {/* \u4EA7\u54C1\u4FE1\u606F */}\n <div className=\"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4\">\n {/* \u6807\u7B7E + \u6807\u9898 + \u526F\u6807\u9898 */}\n <div className=\"flex flex-col gap-2\">\n <div\n className={cn(\n 'scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1',\n classNames?.productCardTags\n )}\n >\n {isShowTag &&\n product?.tags?.map((tag, idx) => (\n <Badge key={idx} variant={tag.variant ?? 'outline'} size=\"sm\" className=\"\">\n {tag.label}\n </Badge>\n ))}\n </div>\n\n <Heading\n as=\"h3\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]',\n classNames?.productCardTitle\n )}\n >\n {product.title}\n </Heading>\n\n {product.description && (\n <Text\n as=\"p\"\n size={1}\n className={cn(\n 'scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1',\n classNames?.productCardDescription\n )}\n >\n {product.description}\n </Text>\n )}\n </div>\n\n {/* \u4EF7\u683C + \u6309\u94AE */}\n <div className=\"flex flex-col gap-2\">\n {/* \u4EF7\u683C */}\n <div\n className={cn(\n 'scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1',\n classNames?.productCardPriceWrapper\n )}\n >\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-current-price text-info-primary',\n classNames?.productCardCurrentPrice\n )}\n >\n {product.currentPrice}\n </Heading>\n {product.originalPrice && (\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-original-price text-info-tertiary line-through',\n classNames?.productCardOriginalPrice\n )}\n >\n {product.originalPrice}\n </Heading>\n )}\n </div>\n\n {/* \u6309\u94AE\u7EC4 */}\n {(secondaryButtonText || primaryButtonText) && (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2',\n classNames?.productCardButtons\n )}\n >\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handleSecondary()\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.title,\n component_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 className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handlePrimary()\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.title,\n component_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 )}\n </div>\n </div>\n </div>\n )\n }\n)\n\nProductCardInner.displayName = 'SceneShelfV2.ProductCard'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Main Component\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst SceneShelfV2 = React.forwardRef<HTMLDivElement, SceneShelfV2Props>(\n (\n { className, classNames = {}, data, onPlayClick, onImageClick, onLearnMore, onShopNow, onAddToCart, ...props },\n ref\n ) => {\n const {\n theme = 'light',\n sceneImage,\n productsTitle,\n products,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n viewMoreLimit = 2,\n copy,\n } = data\n const videoRef = React.useRef<HTMLVideoElement>(null)\n const mediaRef = React.useRef<HTMLDivElement>(null)\n const productWrapperRef = React.useRef<HTMLDivElement>(null)\n const [isPlaying, setIsPlaying] = React.useState(false)\n const [isExpanded, setIsExpanded] = React.useState(false)\n const { trackingData } = useAiuiContext()\n\n useExposure(mediaRef, {\n componentType: 'image',\n componentName: 'scene_shelf_banner',\n })\n\n useViewItemList(productWrapperRef, {\n componentType: 'video',\n componentName: 'scene_shelf_banner',\n itemListName: 'Scene_Shelf_2_Products',\n items: products.map((item, index) => ({\n item_id: item.sku ?? '',\n item_name: item.title,\n item_variant: item.variantId ?? '',\n price: item.currentPrice,\n index: index,\n })),\n tabName: '',\n })\n\n const visibleLimit = useGridRowCount({\n rows: viewMoreLimit ?? 0,\n mobileCols: 2,\n })\n\n const hasVideo = React.useMemo(\n () =>\n [sceneImage?.pc, sceneImage?.desktop, sceneImage?.laptop, sceneImage?.pad, sceneImage?.mobile].some(\n media => media?.mimeType === 'video/mp4'\n ),\n [sceneImage]\n )\n\n const handlePlayButtonClick = React.useCallback(() => {\n const video = videoRef.current\n if (video) {\n if (video.paused) {\n video.play()\n setIsPlaying(true)\n onPlayClick?.(true)\n } else {\n video.pause()\n setIsPlaying(false)\n onPlayClick?.(false)\n }\n } else {\n onPlayClick?.(true)\n }\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: trackingData?.pageGroup,\n component_type: 'video',\n component_name: 'scene_shelf_banner',\n position: 1,\n creative_id: sceneImage?.pc?.id,\n },\n })\n }, [onPlayClick, sceneImage?.pc?.id, trackingData?.pageGroup])\n\n // \u8FDB\u5165\u89C6\u7A97\u81EA\u52A8\u64AD\u653E\n React.useEffect(() => {\n const video = videoRef.current\n if (!video || !hasVideo) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n // \u8FDB\u5165\u89C6\u7A97\uFF0C\u81EA\u52A8\u64AD\u653E\n video.play().catch(error => {\n // \u5904\u7406\u81EA\u52A8\u64AD\u653E\u5931\u8D25\uFF08\u6D4F\u89C8\u5668\u7B56\u7565\u53EF\u80FD\u963B\u6B62\u81EA\u52A8\u64AD\u653E\uFF09\n console.warn('Video autoplay failed:', error)\n })\n } else {\n // \u79BB\u5F00\u89C6\u7A97\uFF0C\u6682\u505C\u64AD\u653E\n video.pause()\n }\n })\n },\n {\n threshold: 0.5, // \u5F53\u89C6\u9891 50% \u53EF\u89C1\u65F6\u89E6\u53D1\n }\n )\n\n observer.observe(video)\n\n return () => {\n observer.disconnect()\n }\n }, [])\n\n return (\n <div\n {...props}\n ref={ref}\n className={cn(\n 'scene-shelf-v2-root w-full overflow-hidden',\n { 'aiui-dark': theme === 'dark' },\n className,\n classNames?.root\n )}\n >\n {/* \u2500\u2500 \u5A92\u4F53\u533A \u2500\u2500 */}\n <div\n className={cn(\n 'scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden',\n classNames?.media\n )}\n ref={mediaRef}\n >\n <Media\n pcImage={sceneImage?.pc}\n desktopImage={sceneImage?.desktop}\n laptopImage={sceneImage?.laptop}\n padImage={sceneImage?.pad}\n mobileImage={sceneImage?.mobile}\n className=\"size-full\"\n videoClassName=\"absolute inset-0 size-full object-cover\"\n videoRef={videoRef}\n onVideoPlay={() => setIsPlaying(true)}\n onVideoPause={() => setIsPlaying(false)}\n onVideoEnded={() => setIsPlaying(false)}\n />\n {/* \u6E10\u53D8\u906E\u7F69 */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'scene-shelf-v2-media-overlay pointer-events-none absolute inset-0',\n classNames?.mediaOverlay\n )}\n />\n\n {/* \u5F15\u8A00 + \u64AD\u653E/\u6682\u505C\u6309\u94AE */}\n {hasVideo && (\n <div className=\"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6\">\n <button\n type=\"button\"\n aria-label={isPlaying ? 'Pause video' : 'Play video'}\n onClick={handlePlayButtonClick}\n className={cn(\n 'scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80',\n classNames?.mediaPlayButton\n )}\n >\n {isPlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n </div>\n )}\n </div>\n\n {/* \u2500\u2500 \u4EA7\u54C1\u533A \u2500\u2500 */}\n <div\n ref={productWrapperRef}\n className={cn(\n 'scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3',\n classNames?.products\n )}\n >\n {productsTitle && (\n <Heading\n as=\"h2\"\n size={3}\n className={cn('scene-shelf-v2-products-title text-info-primary', classNames?.productsTitle)}\n html={productsTitle}\n />\n )}\n\n {/* Mobile\uFF1A2\u5217\u5E73\u94FA */}\n <div className=\"tablet:hidden grid grid-cols-2 gap-3\">\n {(() => {\n const shouldShowViewMore =\n viewMoreLimit !== undefined && viewMoreLimit > 0 && products.length > visibleLimit\n const displayedProducts = shouldShowViewMore && !isExpanded ? products.slice(0, visibleLimit) : products\n\n return (\n <>\n {displayedProducts.map((product, index) => (\n <ProductCardInner\n key={product.productKey}\n isShowTag={data.isShowTag ?? true}\n product={product}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n ))}\n {shouldShowViewMore && (\n <div className=\"col-span-2 mt-6 flex justify-center\">\n <button\n type=\"button\"\n onClick={() => setIsExpanded(prev => !prev)}\n className=\"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors\"\n aria-expanded={isExpanded}\n >\n {isExpanded ? (copy?.viewLessLabel ?? 'View Less') : (copy?.viewMoreLabel ?? 'View More')}\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 </div>\n\n {/* Tablet\uFF1ASwiper \u6A2A\u6ED1 */}\n <div className=\"tablet:block hidden\">\n <div className=\"relative\">\n <Swiper\n slidesPerView=\"auto\"\n observer\n observeParents\n modules={[Mousewheel]}\n mousewheel={{\n enabled: true,\n forceToAxis: true,\n sensitivity: 1,\n }}\n className=\"!overflow-visible\"\n breakpoints={{\n 768: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.3 : 2,\n },\n 1024: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.8 : 3,\n },\n 1440: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n 1920: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n }}\n >\n {products.map((product, index) => (\n <SwiperSlide key={product.productKey} className={cn('!h-auto ', classNames.productCardSlideWrapper)}>\n <ProductCardInner\n product={product}\n isShowTag={data.isShowTag ?? true}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n </SwiperSlide>\n ))}\n </Swiper>\n </div>\n </div>\n </div>\n </div>\n )\n }\n)\n\nSceneShelfV2.displayName = 'SceneShelfV2'\nexport default withLayout(SceneShelfV2)\nexport { ProductCardInner as SceneShelfV2ProductCard }\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn, getLocalizedPath } from '../../helpers/index.js'\nimport { Heading, Text, Badge, Button, Picture } from '../../components/index.js'\nimport Media from '../Media/index.js'\nimport type { ResponsiveMedia, Theme } from '../../types/props.js'\nimport { Swiper, SwiperSlide } from 'swiper/react'\nimport { Mousewheel } from 'swiper/modules'\nimport 'swiper/css'\nimport 'swiper/css/navigation'\nimport { withLayout } from '../../shared/Styles.js'\nimport { useGridRowCount } from '../../hooks/useGridRowCount.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { useViewItemList } from '../../hooks/useViewItemList.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\nimport { gaTrack } from '../../shared/track.js'\n\nconst componentType = 'shelf'\nconst componentName = 'scene_shelf_v2'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Types\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * \u6309\u94AE\u529F\u80FD\u7C7B\u578B\n */\nexport type ButtonFunctionType = 'buyNow' | 'addCart' | 'learnMore'\n\nexport type SceneShelfV2SemanticName =\n | 'root'\n | 'media'\n | 'mediaOverlay'\n | 'mediaQuote'\n | 'mediaPlayButton'\n | 'products'\n | 'productsTitle'\n | 'productGrid'\n | 'productCardSlideWrapper'\n | 'productCard'\n | 'productCardImage'\n | 'productCardTags'\n | 'productCardTitle'\n | 'productCardDescription'\n | 'productCardPriceWrapper'\n | 'productCardCurrentPrice'\n | 'productCardOriginalPrice'\n | 'productCardButtons'\n\nexport interface SceneShelfV2Tag {\n label: string\n variant?: 'outline' | 'fill'\n}\n\nexport interface SceneShelfV2Product {\n /** \u4EA7\u54C1\u552F\u4E00\u6807\u8BC6 */\n productKey: string\n /** \u4EA7\u54C1\u4E3B\u6807\u9898 */\n title: string\n /** \u4EA7\u54C1\u63CF\u8FF0 */\n description?: string\n /** \u4EA7\u54C1\u56FE\u7247 */\n imageUrl: string\n imageAlt: string\n /**\n * \u4EA7\u54C1\u94FE\u63A5 URL\u3002\n */\n href?: string\n /** \u5F53\u524D\u4EF7\u683C\uFF08\u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u5982 \"$1,999.00\"\uFF09 */\n currentPrice: string\n /** \u539F\u4EF7\uFF08\u663E\u793A\u5220\u9664\u7EBF\uFF09 */\n originalPrice?: string\n /** \u6807\u7B7E\u5217\u8868 */\n tags?: SceneShelfV2Tag[]\n /** \u662F\u5426\u552E\u7F44 */\n soldOut?: boolean\n /**\n * sku\n */\n sku?: string\n /**\n * \u53D8\u4F53id\n */\n variantId?: string\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}\n\n/**\n * \u6587\u6848\u914D\u7F6E\n */\nexport interface SceneShelfV2CopyConfig {\n /** \u67E5\u770B\u66F4\u591A\u6807\u7B7E */\n viewMoreLabel?: string\n /** \u6536\u8D77\u6807\u7B7E */\n viewLessLabel?: string\n}\n\nexport interface SceneShelfV2Data {\n theme?: 'light' | 'dark'\n isShowTag?: boolean\n sceneImage: ResponsiveMedia\n /** \u4EA7\u54C1\u533A\u6807\u9898\uFF08\u53EF\u9009\uFF09 */\n productsTitle?: string\n /** \u4EA7\u54C1\u5217\u8868 */\n products: SceneShelfV2Product[]\n /** \u6B21\u8981\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u6B21\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n secondaryButtonFun?: ButtonFunctionType\n /** \u4E3B\u8981\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u4E3B\u8981\u6309\u94AE\u529F\u80FD\u7C7B\u578B */\n primaryButtonFun?: ButtonFunctionType\n /** \u67E5\u770B\u66F4\u591A\u9650\u5236\u6570\uFF08\u624B\u673A\u7AEF\u8D85\u8FC7\u4E24\u884C\u65F6\u663E\u793AviewMore\u6309\u94AE\uFF09 */\n viewMoreLimit?: number\n /** \u6587\u6848\u914D\u7F6E */\n copy?: SceneShelfV2CopyConfig\n}\n\nexport interface SceneShelfV2Props extends React.HTMLAttributes<HTMLDivElement> {\n data: SceneShelfV2Data\n /**\n * \u70B9\u51FB\u64AD\u653E/\u6682\u505C\u6309\u94AE\u56DE\u8C03\u3002\n * \u5F53\u5A92\u4F53\u533A\u4E3A\u89C6\u9891\u65F6\uFF0C\u7EC4\u4EF6\u5185\u90E8\u4F1A\u81EA\u52A8\u63A7\u5236\u64AD\u653E/\u6682\u505C,\u6B64\u56DE\u8C03\u4ECD\u4F1A\u89E6\u53D1\u3002\n */\n onPlayClick?: (isPlaying: boolean) => void\n /** \u70B9\u51FB\u4EA7\u54C1\u56FE\u7247\u56DE\u8C03 */\n onImageClick?: (product: SceneShelfV2Product) => void\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: SceneShelfV2Product) => void | Promise<void>\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03\uFF08\u652F\u6301\u5F02\u6B65\uFF09 */\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Icons\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PlayIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 5.14v13.72L19 12 8 5.14z\" fill=\"white\" />\n </svg>\n)\n\nconst PauseIcon = () => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"white\" />\n </svg>\n)\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Product Card\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface ProductCardInnerProps {\n product: SceneShelfV2Product\n isShowTag: boolean\n onImageClick?: (product: SceneShelfV2Product) => void\n onLearnMore?: (link: string) => void | Promise<void>\n onShopNow?: (product: SceneShelfV2Product) => void | Promise<void>\n onAddToCart?: (product: SceneShelfV2Product) => void | Promise<void>\n secondaryButtonText?: string\n secondaryButtonFun?: ButtonFunctionType\n primaryButtonText?: string\n primaryButtonFun?: ButtonFunctionType\n classNames?: Partial<Record<SceneShelfV2SemanticName, string>>\n className?: string\n theme?: Theme\n index?: number\n}\n\nconst ProductCardInner = React.memo(\n ({\n product,\n isShowTag = true,\n onImageClick,\n onLearnMore,\n onShopNow,\n onAddToCart,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n classNames,\n className,\n theme,\n index,\n }: ProductCardInnerProps) => {\n const { locale = 'us', trackingData } = useAiuiContext()\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n\n const pageGroup = trackingData?.pageGroup\n\n // \u6839\u636E\u6309\u94AE\u529F\u80FD\u7C7B\u578B\u8C03\u7528\u76F8\u5E94\u7684\u56DE\u8C03\u51FD\u6570\n const handleButtonClick = React.useCallback(\n async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n\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 default:\n break\n }\n } finally {\n setLoading(false)\n }\n },\n [onLearnMore, onShopNow, onAddToCart, product]\n )\n\n const handlePrimary = React.useCallback(\n () => handleButtonClick(primaryButtonFun, 'primary'),\n [handleButtonClick, primaryButtonFun]\n )\n const handleSecondary = React.useCallback(\n () => handleButtonClick(secondaryButtonFun, 'secondary'),\n [handleButtonClick, secondaryButtonFun]\n )\n\n const handleImageClick = React.useCallback(\n (e: React.MouseEvent) => {\n // \u5982\u679C\u6CA1\u6709\u63D0\u4F9B href \u4E14\u6709\u70B9\u51FB\u56DE\u8C03\uFF0C\u963B\u6B62\u9ED8\u8BA4\u884C\u4E3A\n if (!product.href && onImageClick) {\n e.preventDefault()\n }\n onImageClick?.(product)\n gaTrack({\n event: 'ga4Event',\n event_name: 'select_item',\n item_list_name: 'Scene_Shelf_2_Products',\n page_group: pageGroup,\n items: [\n {\n item_id: product.sku,\n item_name: product.custom_name || product.title,\n item_variant: product.variantId,\n price: product.currentPrice,\n index: index,\n },\n ],\n })\n },\n [index, onImageClick, pageGroup, product]\n )\n\n return (\n <div\n className={cn(\n 'scene-shelf-v2-product-card rounded-box bg-container-secondary-1 tablet:px-6 desktop:pb-6 desktop:px-6 box-border flex h-full flex-col items-center justify-between gap-3 overflow-hidden px-2 py-4',\n className,\n classNames?.productCard,\n {\n 'bg-container-secondary-0': theme === 'dark',\n }\n )}\n >\n {/* \u4EA7\u54C1\u56FE\u7247 */}\n {product.href ? (\n <a\n href={getLocalizedPath(\n trackUrlRef(product.href, pageGroup + '_' + componentType + '_' + componentName),\n locale\n )}\n onClick={handleImageClick}\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n aria-label={`View ${product.title}`}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </a>\n ) : (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-image desktop:size-[196px] tablet:size-[140px] lg-desktop:size-[196px] flex size-[128px] shrink-0 items-center justify-center ',\n onImageClick && 'cursor-pointer transition-opacity hover:opacity-80',\n classNames?.productCardImage\n )}\n onClick={onImageClick ? handleImageClick : undefined}\n role={onImageClick ? 'button' : undefined}\n tabIndex={onImageClick ? 0 : undefined}\n aria-label={onImageClick ? `View ${product.title}` : undefined}\n >\n <Picture\n source={product.imageUrl}\n alt={product.imageAlt}\n className=\"size-full\"\n imgClassName=\"object-contain\"\n />\n </div>\n )}\n\n {/* \u4EA7\u54C1\u4FE1\u606F */}\n <div className=\"desktop:gap-6 flex w-full flex-1 flex-col justify-between gap-4\">\n {/* \u6807\u7B7E + \u6807\u9898 + \u526F\u6807\u9898 */}\n <div className=\"flex flex-col gap-2\">\n <div\n className={cn(\n 'scene-shelf-v2-product-card-tags flex min-h-[24px] flex-wrap gap-1',\n classNames?.productCardTags\n )}\n >\n {isShowTag &&\n product?.tags?.map((tag, idx) => (\n <Badge key={idx} variant={tag.variant ?? 'outline'} size=\"sm\" className=\"\">\n {tag.label}\n </Badge>\n ))}\n </div>\n\n <Heading\n as=\"h3\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-title text-info-primary laptop:line-clamp-2 line-clamp-3 pr-[16%] text-[16px]',\n classNames?.productCardTitle\n )}\n >\n {product.custom_name || product.title}\n </Heading>\n\n {(product.custom_description || product.description) && (\n <Text\n as=\"p\"\n size={1}\n className={cn(\n 'scene-shelf-v2-product-card-description text-info-primary tablet:text-[14px] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-1',\n classNames?.productCardDescription\n )}\n >\n {product.custom_description || product.description}\n </Text>\n )}\n </div>\n\n {/* \u4EF7\u683C + \u6309\u94AE */}\n <div className=\"flex flex-col gap-2\">\n {/* \u4EF7\u683C */}\n <div\n className={cn(\n 'scene-shelf-v2-product-card-price flex flex-wrap items-center gap-1',\n classNames?.productCardPriceWrapper\n )}\n >\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-current-price text-info-primary',\n classNames?.productCardCurrentPrice\n )}\n >\n {product.currentPrice}\n </Heading>\n {product.originalPrice && (\n <Heading\n as=\"h6\"\n size={2}\n className={cn(\n 'scene-shelf-v2-product-card-original-price text-info-tertiary line-through',\n classNames?.productCardOriginalPrice\n )}\n >\n {product.originalPrice}\n </Heading>\n )}\n </div>\n\n {/* \u6309\u94AE\u7EC4 */}\n {(secondaryButtonText || primaryButtonText) && (\n <div\n className={cn(\n 'scene-shelf-v2-product-card-buttons laptop:flex-nowrap lg-desktop:gap-3 flex flex-wrap gap-2',\n classNames?.productCardButtons\n )}\n >\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handleSecondary()\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.title,\n component_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 className=\"laptop:grow-0 flex-1 whitespace-nowrap\"\n onClick={() => {\n handlePrimary()\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.title,\n component_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 )}\n </div>\n </div>\n </div>\n )\n }\n)\n\nProductCardInner.displayName = 'SceneShelfV2.ProductCard'\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Main Component\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst SceneShelfV2 = React.forwardRef<HTMLDivElement, SceneShelfV2Props>(\n (\n { className, classNames = {}, data, onPlayClick, onImageClick, onLearnMore, onShopNow, onAddToCart, ...props },\n ref\n ) => {\n const {\n theme = 'light',\n sceneImage,\n productsTitle,\n products,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n viewMoreLimit = 2,\n copy,\n } = data\n const videoRef = React.useRef<HTMLVideoElement>(null)\n const mediaRef = React.useRef<HTMLDivElement>(null)\n const productWrapperRef = React.useRef<HTMLDivElement>(null)\n const [isPlaying, setIsPlaying] = React.useState(false)\n const [isExpanded, setIsExpanded] = React.useState(false)\n const { trackingData } = useAiuiContext()\n\n useExposure(mediaRef, {\n componentType: 'image',\n componentName: 'scene_shelf_banner',\n })\n\n useViewItemList(productWrapperRef, {\n componentType: 'video',\n componentName: 'scene_shelf_banner',\n itemListName: 'Scene_Shelf_2_Products',\n items: products.map((item, index) => ({\n item_id: item.sku ?? '',\n item_name: item.title,\n item_variant: item.variantId ?? '',\n price: item.currentPrice,\n index: index,\n })),\n tabName: '',\n })\n\n const visibleLimit = useGridRowCount({\n rows: viewMoreLimit ?? 0,\n mobileCols: 2,\n })\n\n const hasVideo = React.useMemo(\n () =>\n [sceneImage?.pc, sceneImage?.desktop, sceneImage?.laptop, sceneImage?.pad, sceneImage?.mobile].some(\n media => media?.mimeType === 'video/mp4'\n ),\n [sceneImage]\n )\n\n const handlePlayButtonClick = React.useCallback(() => {\n const video = videoRef.current\n if (video) {\n if (video.paused) {\n video.play()\n setIsPlaying(true)\n onPlayClick?.(true)\n } else {\n video.pause()\n setIsPlaying(false)\n onPlayClick?.(false)\n }\n } else {\n onPlayClick?.(true)\n }\n gaTrack({\n event: 'ga4Event',\n event_name: 'component_click',\n event_parameters: {\n page_group: trackingData?.pageGroup,\n component_type: 'video',\n component_name: 'scene_shelf_banner',\n position: 1,\n creative_id: sceneImage?.pc?.id,\n },\n })\n }, [onPlayClick, sceneImage?.pc?.id, trackingData?.pageGroup])\n\n // \u8FDB\u5165\u89C6\u7A97\u81EA\u52A8\u64AD\u653E\n React.useEffect(() => {\n const video = videoRef.current\n if (!video || !hasVideo) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n // \u8FDB\u5165\u89C6\u7A97\uFF0C\u81EA\u52A8\u64AD\u653E\n video.play().catch(error => {\n // \u5904\u7406\u81EA\u52A8\u64AD\u653E\u5931\u8D25\uFF08\u6D4F\u89C8\u5668\u7B56\u7565\u53EF\u80FD\u963B\u6B62\u81EA\u52A8\u64AD\u653E\uFF09\n console.warn('Video autoplay failed:', error)\n })\n } else {\n // \u79BB\u5F00\u89C6\u7A97\uFF0C\u6682\u505C\u64AD\u653E\n video.pause()\n }\n })\n },\n {\n threshold: 0.5, // \u5F53\u89C6\u9891 50% \u53EF\u89C1\u65F6\u89E6\u53D1\n }\n )\n\n observer.observe(video)\n\n return () => {\n observer.disconnect()\n }\n }, [])\n\n return (\n <div\n {...props}\n ref={ref}\n className={cn(\n 'scene-shelf-v2-root w-full overflow-hidden',\n { 'aiui-dark': theme === 'dark' },\n className,\n classNames?.root\n )}\n >\n {/* \u2500\u2500 \u5A92\u4F53\u533A \u2500\u2500 */}\n <div\n className={cn(\n 'scene-shelf-v2-media laptop:h-[360px] tablet:h-[400px] desktop:h-[384px] rounded-box tablet:rounded-t-box tablet:rounded-b-none lg-desktop:h-[480px] relative h-[240px] overflow-hidden',\n classNames?.media\n )}\n ref={mediaRef}\n >\n <Media\n pcImage={sceneImage?.pc}\n desktopImage={sceneImage?.desktop}\n laptopImage={sceneImage?.laptop}\n padImage={sceneImage?.pad}\n mobileImage={sceneImage?.mobile}\n className=\"size-full\"\n videoClassName=\"absolute inset-0 size-full object-cover\"\n videoRef={videoRef}\n onVideoPlay={() => setIsPlaying(true)}\n onVideoPause={() => setIsPlaying(false)}\n onVideoEnded={() => setIsPlaying(false)}\n />\n {/* \u6E10\u53D8\u906E\u7F69 */}\n <div\n aria-hidden=\"true\"\n className={cn(\n 'scene-shelf-v2-media-overlay pointer-events-none absolute inset-0',\n classNames?.mediaOverlay\n )}\n />\n\n {/* \u5F15\u8A00 + \u64AD\u653E/\u6682\u505C\u6309\u94AE */}\n {hasVideo && (\n <div className=\"desktop:gap-16 desktop:p-8 absolute inset-0 flex items-end justify-end gap-4 p-6\">\n <button\n type=\"button\"\n aria-label={isPlaying ? 'Pause video' : 'Play video'}\n onClick={handlePlayButtonClick}\n className={cn(\n 'scene-shelf-v2-media-play-button flex size-14 shrink-0 items-center justify-center rounded-full bg-white/20 transition-opacity hover:opacity-80',\n classNames?.mediaPlayButton\n )}\n >\n {isPlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n </div>\n )}\n </div>\n\n {/* \u2500\u2500 \u4EA7\u54C1\u533A \u2500\u2500 */}\n <div\n ref={productWrapperRef}\n className={cn(\n 'scene-shelf-v2-products text-info-primary tablet:bg-container-primary laptop:p-6 desktop:p-8 rounded-b-box tablet:p-4 flex flex-col gap-4 bg-transparent p-0 pt-3',\n classNames?.products\n )}\n >\n {productsTitle && (\n <Heading\n as=\"h2\"\n size={3}\n className={cn('scene-shelf-v2-products-title text-info-primary', classNames?.productsTitle)}\n html={productsTitle}\n />\n )}\n\n {/* Mobile\uFF1A2\u5217\u5E73\u94FA */}\n <div className=\"tablet:hidden grid grid-cols-2 gap-3\">\n {(() => {\n const shouldShowViewMore =\n viewMoreLimit !== undefined && viewMoreLimit > 0 && products.length > visibleLimit\n const displayedProducts = shouldShowViewMore && !isExpanded ? products.slice(0, visibleLimit) : products\n\n return (\n <>\n {displayedProducts.map((product, index) => (\n <ProductCardInner\n key={product.productKey}\n isShowTag={data.isShowTag ?? true}\n product={product}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n ))}\n {shouldShowViewMore && (\n <div className=\"col-span-2 mt-6 flex justify-center\">\n <button\n type=\"button\"\n onClick={() => setIsExpanded(prev => !prev)}\n className=\"text-info-primary hover:text-brand-0 flex items-center gap-2 text-[14px] font-bold transition-colors\"\n aria-expanded={isExpanded}\n >\n {isExpanded ? (copy?.viewLessLabel ?? 'View Less') : (copy?.viewMoreLabel ?? 'View More')}\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 </div>\n\n {/* Tablet\uFF1ASwiper \u6A2A\u6ED1 */}\n <div className=\"tablet:block hidden\">\n <div className=\"relative\">\n <Swiper\n slidesPerView=\"auto\"\n observer\n observeParents\n modules={[Mousewheel]}\n mousewheel={{\n enabled: true,\n forceToAxis: true,\n sensitivity: 1,\n }}\n className=\"!overflow-visible\"\n breakpoints={{\n 768: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.3 : 2,\n },\n 1024: {\n spaceBetween: 16,\n slidesPerView: products.length > 3 ? 2.8 : 3,\n },\n 1440: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n 1920: {\n spaceBetween: 16,\n slidesPerView: products.length > 4 ? 3.8 : 4,\n },\n }}\n >\n {products.map((product, index) => (\n <SwiperSlide key={product.productKey} className={cn('!h-auto ', classNames.productCardSlideWrapper)}>\n <ProductCardInner\n product={product}\n isShowTag={data.isShowTag ?? true}\n onImageClick={onImageClick}\n onLearnMore={onLearnMore}\n onShopNow={onShopNow}\n onAddToCart={onAddToCart}\n secondaryButtonText={secondaryButtonText}\n secondaryButtonFun={secondaryButtonFun}\n primaryButtonText={primaryButtonText}\n primaryButtonFun={primaryButtonFun}\n classNames={classNames}\n theme={theme}\n index={index}\n />\n </SwiperSlide>\n ))}\n </Swiper>\n </div>\n </div>\n </div>\n </div>\n )\n }\n)\n\nSceneShelfV2.displayName = 'SceneShelfV2'\nexport default withLayout(SceneShelfV2)\nexport { ProductCardInner as SceneShelfV2ProductCard }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Fragment", "jsx", "jsxs", "React", "cn", "getLocalizedPath", "Heading", "Text", "Badge", "Button", "Picture", "Media", "Swiper", "SwiperSlide", "Mousewheel", "withLayout", "useGridRowCount", "useExposure", "useViewItemList", "trackUrlRef", "useAiuiContext", "gaTrack", "componentType", "componentName", "PlayIcon", "PauseIcon", "ProductCardInner", "product", "isShowTag", "onImageClick", "onLearnMore", "onShopNow", "onAddToCart", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "classNames", "className", "theme", "index", "locale", "trackingData", "primaryLoading", "setPrimaryLoading", "secondaryLoading", "setSecondaryLoading", "pageGroup", "handleButtonClick", "buttonFun", "buttonType", "setLoading", "handlePrimary", "handleSecondary", "handleImageClick", "e", "tag", "idx", "SceneShelfV2", "data", "onPlayClick", "props", "ref", "sceneImage", "productsTitle", "products", "viewMoreLimit", "copy", "videoRef", "mediaRef", "productWrapperRef", "isPlaying", "setIsPlaying", "isExpanded", "setIsExpanded", "item", "visibleLimit", "hasVideo", "media", "handlePlayButtonClick", "video", "observer", "entries", "entry", "error", "shouldShowViewMore", "displayedProducts", "prev", "SceneShelfV2_default"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as n,jsxs as T}from"react/jsx-runtime";import rt,{useEffect as st,useRef as h,useImperativeHandle as at,useState as lt}from"react";import{gsap as k}from"gsap";import{SplitText as z}from"gsap/dist/SplitText";import{ScrollTrigger as R}from"gsap/dist/ScrollTrigger";import{cn as i}from"../../helpers/utils.js";import{cva as N}from"class-variance-authority";import{Heading as dt,Text as P,Countdown as ct}from"../../components/index.js";import{withLayout as ut}from"../../shared/Styles.js";import{trackUrlRef as mt}from"../../shared/trackUrlRef.js";import{useInView as pt}from"react-intersection-observer";const S="link",V="title",ft=N("",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),ht=N("desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),$=({data:a,onClick:m,className:e})=>{const{theme:o="light",extensions:r,title:g,caption:x,align:p}=a;if(!r?.textLink)return null;const l=r?.link?mt(r.link,`${S}_${V}`):void 0;return T("a",{className:i({"aiui-dark":o==="dark"},"hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]",{"text-[#080A0F]":o==="light"},{"text-[#F5F6F7]":o==="dark"},{"justify-center mt-4":p==="center"},{"mt-1 laptop:mt-0":p==="left"},e),...l?{href:l}:{},"data-headless-type-name":`${S}#${V}`,"data-headless-title-desc-button":`${g}#${x}`,...m?{onClick:m}:{},children:[n("div",{className:"truncate whitespace-nowrap",children:r?.textLink}),n("div",{className:"lg-desktop:size-5 size-4",children:n("svg",{xmlns:"http://www.w3.org/2000/svg",width:"100%",height:"100%",viewBox:"0 0 16 16",fill:"none",children:n("path",{d:"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z",fill:o==="dark"?"#F5F6F7":"#080A0F",className:"transition-all duration-[0.4s]"})})})]})},A=rt.forwardRef(({data:a,className:m,classNames:e,as:o="h2",weight:r="bold",onButtonClick:g,...x},p)=>{const{title:l,titleSize:B=4,caption:y,subtitle:F,content:H,countdown:t,showCountdown:_=!1,theme:f="light",extensions:I,align:d="left"}=a,L=h(null),c=h(null),s=h(null),u=h(null),[j,O]=lt(!0),{ref:U,inView:D}=pt();at(p,()=>L.current);const W=()=>{O(!1)},Z=t?.targetDateTime||t?.targetDate||"",q=t?.targetDateTime_tz,G=t?.labels?{day:t.labels.days||"Day",hour:t.labels.hours||"Hours",minute:t.labels.minutes||"Mins",second:t.labels.seconds||"Secs"}:void 0;return st(()=>{k.registerPlugin(z,R);function J(){if(!c.current)return;const K=c.current?.clientHeight||80;s.current&&s.current.revert(),u.current&&u.current.kill(),s.current=new z(c.current,{type:"words",wordsClass:"word"});const w=s.current.words;k.set(w,{opacity:0}),u.current=R.create({trigger:c.current,start:"bottom bottom-=4%",end:`bottom+=${K*1.5+60}px bottom-=4%`,scrub:!0,invalidateOnRefresh:!0,onUpdate:Q=>{const X=Q.progress,M=w.length||1,Y=.5,b=1/M,C=b*(1-Y),E=(M-1)*C+b,tt=Math.min(1,E>0?X/E:0);w.forEach((et,nt)=>{const it=nt*C,ot=b;let v=(tt-it)/ot;v=Math.max(0,Math.min(1,v)),k.set(et,{opacity:v})})}})}return D&&J(),()=>{s.current&&s.current.revert(),u.current&&u.current.kill()}},[D]),T("div",{...x,id:I?.id,className:i("titleBottom title-box flex items-end justify-between gap-2 pb-6",e?.wrapper),ref:L,children:[T("div",{ref:U,className:i("flex-1",
|
|
1
|
+
"use client";import{jsx as n,jsxs as T}from"react/jsx-runtime";import rt,{useEffect as st,useRef as h,useImperativeHandle as at,useState as lt}from"react";import{gsap as k}from"gsap";import{SplitText as z}from"gsap/dist/SplitText";import{ScrollTrigger as R}from"gsap/dist/ScrollTrigger";import{cn as i}from"../../helpers/utils.js";import{cva as N}from"class-variance-authority";import{Heading as dt,Text as P,Countdown as ct}from"../../components/index.js";import{withLayout as ut}from"../../shared/Styles.js";import{trackUrlRef as mt}from"../../shared/trackUrlRef.js";import{useInView as pt}from"react-intersection-observer";const S="link",V="title",ft=N("",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),ht=N("desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]",{variants:{theme:{light:"text-[#080A0F]",dark:"text-[#F5F6F7]"}},defaultVariants:{theme:"light"}}),$=({data:a,onClick:m,className:e})=>{const{theme:o="light",extensions:r,title:g,caption:x,align:p}=a;if(!r?.textLink)return null;const l=r?.link?mt(r.link,`${S}_${V}`):void 0;return T("a",{className:i({"aiui-dark":o==="dark"},"hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]",{"text-[#080A0F]":o==="light"},{"text-[#F5F6F7]":o==="dark"},{"justify-center mt-4":p==="center"},{"mt-1 laptop:mt-0":p==="left"},e),...l?{href:l}:{},"data-headless-type-name":`${S}#${V}`,"data-headless-title-desc-button":`${g}#${x}`,...m?{onClick:m}:{},children:[n("div",{className:"truncate whitespace-nowrap",children:r?.textLink}),n("div",{className:"lg-desktop:size-5 size-4",children:n("svg",{xmlns:"http://www.w3.org/2000/svg",width:"100%",height:"100%",viewBox:"0 0 16 16",fill:"none",children:n("path",{d:"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z",fill:o==="dark"?"#F5F6F7":"#080A0F",className:"transition-all duration-[0.4s]"})})})]})},A=rt.forwardRef(({data:a,className:m,classNames:e,as:o="h2",weight:r="bold",onButtonClick:g,...x},p)=>{const{title:l,titleSize:B=4,caption:y,subtitle:F,content:H,countdown:t,showCountdown:_=!1,theme:f="light",extensions:I,align:d="left"}=a,L=h(null),c=h(null),s=h(null),u=h(null),[j,O]=lt(!0),{ref:U,inView:D}=pt();at(p,()=>L.current);const W=()=>{O(!1)},Z=t?.targetDateTime||t?.targetDate||"",q=t?.targetDateTime_tz,G=t?.labels?{day:t.labels.days||"Day",hour:t.labels.hours||"Hours",minute:t.labels.minutes||"Mins",second:t.labels.seconds||"Secs"}:void 0;return st(()=>{k.registerPlugin(z,R);function J(){if(!c.current)return;const K=c.current?.clientHeight||80;s.current&&s.current.revert(),u.current&&u.current.kill(),s.current=new z(c.current,{type:"words",wordsClass:"word"});const w=s.current.words;k.set(w,{opacity:0}),u.current=R.create({trigger:c.current,start:"bottom bottom-=4%",end:`bottom+=${K*1.5+60}px bottom-=4%`,scrub:!0,invalidateOnRefresh:!0,onUpdate:Q=>{const X=Q.progress,M=w.length||1,Y=.5,b=1/M,C=b*(1-Y),E=(M-1)*C+b,tt=Math.min(1,E>0?X/E:0);w.forEach((et,nt)=>{const it=nt*C,ot=b;let v=(tt-it)/ot;v=Math.max(0,Math.min(1,v)),k.set(et,{opacity:v})})}})}return D&&J(),()=>{s.current&&s.current.revert(),u.current&&u.current.kill()}},[D]),T("div",{...x,id:I?.id,className:i("titleBottom title-box flex items-end justify-between gap-2 pb-6",m,e?.wrapper),ref:L,children:[T("div",{ref:U,className:i("flex-1",e?.container,{"aiui-dark":f==="dark","text-center":d==="center","text-left":d==="left"}),children:[(y||l)&&n(dt,{ref:c,as:o,size:B,html:y||l,weight:r,className:i(ft({theme:f}),e?.title)}),F&&n(P,{html:F,as:"p",className:i(ht({theme:f}),e?.subtitle)}),H&&n(P,{html:H,as:"div",size:4,className:i("title-content text-info-primary desktop:text-base desktop:mt-4 lg-desktop:text-[18px] mt-2 text-[14px] leading-[1.6]",e?.content)}),n($,{data:a,className:i({"laptop:hidden":d==="left"},e?.button)}),_&&t&&j&&n(ct,{endDate:Z,endDate_tz:q,timeLabels:G,showDays:t?.showDays,showHours:t?.showHours,showMinutes:t?.showMinutes,showSeconds:t?.showSeconds,theme:f,onExpire:W,hideWhenExpired:!0,align:d==="center"?"center":"left",className:i("mt-4",e?.countdown)})]}),n($,{data:a,className:i("hidden",{"laptop:flex":d==="left"},e?.button),onClick:g})]})});A.displayName="Title";var Lt=ut(A);export{Lt as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/Title/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\nimport React, { useEffect, useRef, useImperativeHandle, useState } from 'react'\nimport { gsap } from 'gsap'\nimport { SplitText } from 'gsap/dist/SplitText'\nimport { ScrollTrigger } from 'gsap/dist/ScrollTrigger'\nimport { cn } from '../../helpers/utils.js'\nimport { cva } from 'class-variance-authority'\nimport { Heading, Text, Countdown, type HeadingProps } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { TitlePropsBase } from './types.js'\n\nexport interface TitleProps extends TitlePropsBase, Omit<React.HTMLAttributes<HTMLDivElement>, 'className' | 'title'> {}\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useInView } from 'react-intersection-observer'\n\nconst componentType = 'link'\nconst componentName = 'title'\n\n/**\n * \u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst titleHeadingVariants = cva('', {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\n/**\n * \u526F\u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst subtitleVariants = cva(\n 'desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]',\n {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n }\n)\n\nconst TitleButton = ({\n data,\n onClick,\n className,\n}: {\n data: TitleProps['data']\n onClick?: () => void\n className?: string\n}) => {\n const { theme = 'light', extensions, title, caption, align } = data\n if (!extensions?.textLink) return null\n\n const href = extensions?.link ? trackUrlRef(extensions.link, `${componentType}_${componentName}`) : undefined\n\n return (\n <a\n className={cn(\n { 'aiui-dark': theme === 'dark' },\n 'hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]',\n { 'text-[#080A0F]': theme === 'light' },\n { 'text-[#F5F6F7]': theme === 'dark' },\n { 'justify-center mt-4': align === 'center' },\n { 'mt-1 laptop:mt-0': align === 'left' },\n className\n )}\n {...(href ? { href } : {})}\n data-headless-type-name={`${componentType}#${componentName}`}\n data-headless-title-desc-button={`${title}#${caption}`}\n {...(onClick ? { onClick } : {})}\n >\n <div className=\"truncate whitespace-nowrap\">{extensions?.textLink}</div>\n <div className=\"lg-desktop:size-5 size-4\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z\"\n fill={theme === 'dark' ? '#F5F6F7' : '#080A0F'}\n className=\"transition-all duration-[0.4s]\"\n />\n </svg>\n </div>\n </a>\n )\n}\n\nconst Title = React.forwardRef<HTMLDivElement, TitleProps>(\n ({ data, className, classNames, as = 'h2', weight = 'bold', onButtonClick, ...rest }, ref) => {\n const {\n title,\n titleSize = 4,\n caption,\n subtitle,\n content,\n countdown,\n showCountdown = false,\n theme = 'light',\n extensions,\n align = 'left',\n } = data\n const innerRef = useRef<HTMLDivElement>(null)\n const titleRef = useRef<HTMLHeadingElement>(null)\n const splitTextInstance = useRef<SplitText | null>(null)\n const scrollTriggerRef = useRef<ScrollTrigger | null>(null)\n\n // \u63A7\u5236\u5012\u8BA1\u65F6\u663E\u793A\u72B6\u6001\n const [isCountdownVisible, setIsCountdownVisible] = useState(true)\n\n const { ref: inViewRef, inView } = useInView()\n\n useImperativeHandle(ref, () => innerRef.current as HTMLDivElement)\n\n // \u5012\u8BA1\u65F6\u7ED3\u675F\u56DE\u8C03\n const handleCountdownEnd = () => {\n setIsCountdownVisible(false)\n }\n\n // CMS field mapping: new targetDateTime > legacy targetDate\n const countdownEndDate = countdown?.targetDateTime || countdown?.targetDate || ''\n const countdownTz = countdown?.targetDateTime_tz\n // Label mapping: plural keys (Title CMS format) \u2192 atomic Countdown format\n const countdownLabels = countdown?.labels\n ? {\n day: countdown.labels.days || 'Day',\n hour: countdown.labels.hours || 'Hours',\n minute: countdown.labels.minutes || 'Mins',\n second: countdown.labels.seconds || 'Secs',\n }\n : undefined\n\n useEffect(() => {\n gsap.registerPlugin(SplitText, ScrollTrigger)\n function gsapResize() {\n if (!titleRef.current) return\n const height = titleRef.current?.clientHeight || 80\n if (splitTextInstance.current) {\n splitTextInstance.current.revert()\n }\n if (scrollTriggerRef.current) {\n scrollTriggerRef.current.kill()\n }\n splitTextInstance.current = new SplitText(titleRef.current, {\n type: 'words',\n wordsClass: 'word',\n })\n const words = splitTextInstance.current.words\n gsap.set(words, { opacity: 0 })\n scrollTriggerRef.current = ScrollTrigger.create({\n trigger: titleRef.current,\n start: 'bottom bottom-=4%',\n end: `bottom+=${height * 1.5 + 60}px bottom-=4%`,\n scrub: true,\n invalidateOnRefresh: true,\n onUpdate: (self: any) => {\n const progress = self.progress\n const total = words.length || 1\n const overlap = 0.5\n const interval = 1 / total\n const step = interval * (1 - overlap)\n const lastEnd = (total - 1) * step + interval\n const normalizedProgress = Math.min(1, lastEnd > 0 ? progress / lastEnd : 0)\n words.forEach((word: any, i: number) => {\n const start = i * step\n const width = interval\n let opacity = (normalizedProgress - start) / width\n opacity = Math.max(0, Math.min(1, opacity))\n gsap.set(word, { opacity })\n })\n },\n })\n }\n\n if (inView) {\n gsapResize()\n }\n\n return () => {\n splitTextInstance.current && splitTextInstance.current.revert()\n // ScrollTrigger.getAll().forEach((t: { kill: () => any }) => t.kill())\n scrollTriggerRef.current && scrollTriggerRef.current.kill()\n }\n }, [inView])\n\n return (\n <div\n {...rest}\n id={extensions?.id}\n className={cn('titleBottom title-box flex items-end justify-between gap-2 pb-6'
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["'use client'\nimport React, { useEffect, useRef, useImperativeHandle, useState } from 'react'\nimport { gsap } from 'gsap'\nimport { SplitText } from 'gsap/dist/SplitText'\nimport { ScrollTrigger } from 'gsap/dist/ScrollTrigger'\nimport { cn } from '../../helpers/utils.js'\nimport { cva } from 'class-variance-authority'\nimport { Heading, Text, Countdown, type HeadingProps } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type { TitlePropsBase } from './types.js'\n\nexport interface TitleProps extends TitlePropsBase, Omit<React.HTMLAttributes<HTMLDivElement>, 'className' | 'title'> {}\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { useInView } from 'react-intersection-observer'\n\nconst componentType = 'link'\nconst componentName = 'title'\n\n/**\n * \u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst titleHeadingVariants = cva('', {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\n/**\n * \u526F\u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst subtitleVariants = cva(\n 'desktop:text-base desktop:mt-2 lg-desktop:text-[18px] mt-1 text-[14px] font-bold leading-[1.4] tracking-[-0.36px]',\n {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-[#F5F6F7]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n }\n)\n\nconst TitleButton = ({\n data,\n onClick,\n className,\n}: {\n data: TitleProps['data']\n onClick?: () => void\n className?: string\n}) => {\n const { theme = 'light', extensions, title, caption, align } = data\n if (!extensions?.textLink) return null\n\n const href = extensions?.link ? trackUrlRef(extensions.link, `${componentType}_${componentName}`) : undefined\n\n return (\n <a\n className={cn(\n { 'aiui-dark': theme === 'dark' },\n 'hover:text-brand-0 [&_svg_path]:hover:fill-brand-0 lg-desktop:text-base flex cursor-pointer items-center overflow-hidden text-sm font-[700] leading-[1.4] transition-all duration-[0.4s]',\n { 'text-[#080A0F]': theme === 'light' },\n { 'text-[#F5F6F7]': theme === 'dark' },\n { 'justify-center mt-4': align === 'center' },\n { 'mt-1 laptop:mt-0': align === 'left' },\n className\n )}\n {...(href ? { href } : {})}\n data-headless-type-name={`${componentType}#${componentName}`}\n data-headless-title-desc-button={`${title}#${caption}`}\n {...(onClick ? { onClick } : {})}\n >\n <div className=\"truncate whitespace-nowrap\">{extensions?.textLink}</div>\n <div className=\"lg-desktop:size-5 size-4\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M5.52827 3.52864C5.78862 3.26829 6.21063 3.26829 6.47098 3.52864L10.471 7.52864C10.7313 7.78899 10.7313 8.21099 10.471 8.47134L6.47098 12.4713C6.21063 12.7317 5.78862 12.7317 5.52827 12.4713C5.26792 12.211 5.26792 11.789 5.52827 11.5286L9.05692 7.99999L5.52827 4.47134C5.26792 4.21099 5.26792 3.78899 5.52827 3.52864Z\"\n fill={theme === 'dark' ? '#F5F6F7' : '#080A0F'}\n className=\"transition-all duration-[0.4s]\"\n />\n </svg>\n </div>\n </a>\n )\n}\n\nconst Title = React.forwardRef<HTMLDivElement, TitleProps>(\n ({ data, className, classNames, as = 'h2', weight = 'bold', onButtonClick, ...rest }, ref) => {\n const {\n title,\n titleSize = 4,\n caption,\n subtitle,\n content,\n countdown,\n showCountdown = false,\n theme = 'light',\n extensions,\n align = 'left',\n } = data\n const innerRef = useRef<HTMLDivElement>(null)\n const titleRef = useRef<HTMLHeadingElement>(null)\n const splitTextInstance = useRef<SplitText | null>(null)\n const scrollTriggerRef = useRef<ScrollTrigger | null>(null)\n\n // \u63A7\u5236\u5012\u8BA1\u65F6\u663E\u793A\u72B6\u6001\n const [isCountdownVisible, setIsCountdownVisible] = useState(true)\n\n const { ref: inViewRef, inView } = useInView()\n\n useImperativeHandle(ref, () => innerRef.current as HTMLDivElement)\n\n // \u5012\u8BA1\u65F6\u7ED3\u675F\u56DE\u8C03\n const handleCountdownEnd = () => {\n setIsCountdownVisible(false)\n }\n\n // CMS field mapping: new targetDateTime > legacy targetDate\n const countdownEndDate = countdown?.targetDateTime || countdown?.targetDate || ''\n const countdownTz = countdown?.targetDateTime_tz\n // Label mapping: plural keys (Title CMS format) \u2192 atomic Countdown format\n const countdownLabels = countdown?.labels\n ? {\n day: countdown.labels.days || 'Day',\n hour: countdown.labels.hours || 'Hours',\n minute: countdown.labels.minutes || 'Mins',\n second: countdown.labels.seconds || 'Secs',\n }\n : undefined\n\n useEffect(() => {\n gsap.registerPlugin(SplitText, ScrollTrigger)\n function gsapResize() {\n if (!titleRef.current) return\n const height = titleRef.current?.clientHeight || 80\n if (splitTextInstance.current) {\n splitTextInstance.current.revert()\n }\n if (scrollTriggerRef.current) {\n scrollTriggerRef.current.kill()\n }\n splitTextInstance.current = new SplitText(titleRef.current, {\n type: 'words',\n wordsClass: 'word',\n })\n const words = splitTextInstance.current.words\n gsap.set(words, { opacity: 0 })\n scrollTriggerRef.current = ScrollTrigger.create({\n trigger: titleRef.current,\n start: 'bottom bottom-=4%',\n end: `bottom+=${height * 1.5 + 60}px bottom-=4%`,\n scrub: true,\n invalidateOnRefresh: true,\n onUpdate: (self: any) => {\n const progress = self.progress\n const total = words.length || 1\n const overlap = 0.5\n const interval = 1 / total\n const step = interval * (1 - overlap)\n const lastEnd = (total - 1) * step + interval\n const normalizedProgress = Math.min(1, lastEnd > 0 ? progress / lastEnd : 0)\n words.forEach((word: any, i: number) => {\n const start = i * step\n const width = interval\n let opacity = (normalizedProgress - start) / width\n opacity = Math.max(0, Math.min(1, opacity))\n gsap.set(word, { opacity })\n })\n },\n })\n }\n\n if (inView) {\n gsapResize()\n }\n\n return () => {\n splitTextInstance.current && splitTextInstance.current.revert()\n // ScrollTrigger.getAll().forEach((t: { kill: () => any }) => t.kill())\n scrollTriggerRef.current && scrollTriggerRef.current.kill()\n }\n }, [inView])\n\n return (\n <div\n {...rest}\n id={extensions?.id}\n className={cn(\n 'titleBottom title-box flex items-end justify-between gap-2 pb-6',\n className,\n classNames?.wrapper\n )}\n ref={innerRef}\n >\n <div\n ref={inViewRef}\n className={cn('flex-1', classNames?.container, {\n 'aiui-dark': theme === 'dark',\n 'text-center': align === 'center',\n 'text-left': align === 'left',\n })}\n >\n {(caption || title) && (\n <Heading\n ref={titleRef}\n as={as}\n size={titleSize as HeadingProps['size']}\n html={caption || title}\n weight={weight}\n className={cn(titleHeadingVariants({ theme }), classNames?.title)}\n />\n )}\n {subtitle && (\n <Text html={subtitle} as=\"p\" className={cn(subtitleVariants({ theme }), classNames?.subtitle)} />\n )}\n {content && (\n <Text\n html={content}\n as=\"div\"\n size={4}\n className={cn(\n 'title-content text-info-primary desktop:text-base desktop:mt-4 lg-desktop:text-[18px] mt-2 text-[14px] leading-[1.6]',\n classNames?.content\n )}\n />\n )}\n <TitleButton data={data} className={cn({ 'laptop:hidden': align === 'left' }, classNames?.button)} />\n {showCountdown && countdown && isCountdownVisible && (\n <Countdown\n endDate={countdownEndDate}\n endDate_tz={countdownTz}\n timeLabels={countdownLabels}\n showDays={countdown?.showDays}\n showHours={countdown?.showHours}\n showMinutes={countdown?.showMinutes}\n showSeconds={countdown?.showSeconds}\n theme={theme}\n onExpire={handleCountdownEnd}\n hideWhenExpired={true}\n align={align === 'center' ? 'center' : 'left'}\n className={cn('mt-4', classNames?.countdown)}\n />\n )}\n </div>\n <TitleButton\n data={data}\n className={cn('hidden', { ['laptop:flex']: align === 'left' }, classNames?.button)}\n onClick={onButtonClick}\n />\n </div>\n )\n }\n)\n\nTitle.displayName = 'Title'\n\nexport default withLayout(Title)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["jsx", "jsxs", "React", "useEffect", "useRef", "useImperativeHandle", "useState", "gsap", "SplitText", "ScrollTrigger", "cn", "cva", "Heading", "Text", "Countdown", "withLayout", "trackUrlRef", "useInView", "componentType", "componentName", "titleHeadingVariants", "subtitleVariants", "TitleButton", "data", "onClick", "className", "theme", "extensions", "title", "caption", "align", "href", "Title", "classNames", "as", "weight", "onButtonClick", "rest", "ref", "titleSize", "subtitle", "content", "countdown", "showCountdown", "innerRef", "titleRef", "splitTextInstance", "scrollTriggerRef", "isCountdownVisible", "setIsCountdownVisible", "inViewRef", "inView", "handleCountdownEnd", "countdownEndDate", "countdownTz", "countdownLabels", "gsapResize", "height", "words", "self", "progress", "total", "overlap", "interval", "step", "lastEnd", "normalizedProgress", "word", "i", "start", "width", "opacity", "Title_default"]
|
|
7
7
|
}
|