pb-sxp-ui 1.20.43 → 1.20.45
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/index.cjs +325 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +325 -89
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +7 -7
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.js +7 -7
- package/dist/index.min.js.map +1 -1
- package/dist/pb-ui.js +325 -89
- package/dist/pb-ui.js.map +1 -1
- package/dist/pb-ui.min.js +7 -7
- package/dist/pb-ui.min.js.map +1 -1
- package/es/core/components/StructurePage/index.js +247 -63
- package/es/core/hooks/useAdvancedOnScreen.d.ts +1 -0
- package/es/core/hooks/useAdvancedOnScreen.js +8 -8
- package/lib/core/components/StructurePage/index.js +247 -63
- package/lib/core/hooks/useAdvancedOnScreen.d.ts +1 -0
- package/lib/core/hooks/useAdvancedOnScreen.js +8 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2224,7 +2224,7 @@ const EditorCore = React.forwardRef(({ children, resolver, isSsr, schema, enable
|
|
|
2224
2224
|
* @returns isVisible 是否可见
|
|
2225
2225
|
*/
|
|
2226
2226
|
function useAdvancedOnScreen(ref, options = {}) {
|
|
2227
|
-
const { threshold = 0, delay = 0, onVisible, onHidden } = options;
|
|
2227
|
+
const { threshold = 0, delay = 0, onVisible, onHidden, name = 'unknown' } = options;
|
|
2228
2228
|
const observerRef = React.useRef(null);
|
|
2229
2229
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
2230
2230
|
const timerRef = React.useRef(null);
|
|
@@ -2250,7 +2250,7 @@ function useAdvancedOnScreen(ref, options = {}) {
|
|
|
2250
2250
|
var _a, _b;
|
|
2251
2251
|
const isIntersecting = entry.isIntersecting;
|
|
2252
2252
|
const intersectionRatio = entry.intersectionRatio;
|
|
2253
|
-
console.log(
|
|
2253
|
+
console.log(`[useAdvancedOnScreen ${name}] IntersectionObserver callback:`, {
|
|
2254
2254
|
isIntersecting,
|
|
2255
2255
|
threshold,
|
|
2256
2256
|
delay,
|
|
@@ -2262,18 +2262,18 @@ function useAdvancedOnScreen(ref, options = {}) {
|
|
|
2262
2262
|
if (isIntersecting && intersectionRatio >= threshold) {
|
|
2263
2263
|
// 元素进入可视区域且达到阈值
|
|
2264
2264
|
setIsVisible(true);
|
|
2265
|
-
//
|
|
2265
|
+
// 如果已经在等待中,清除旧的定时器,重新开始计时
|
|
2266
2266
|
if (isWaitingRef.current) {
|
|
2267
|
-
console.log(
|
|
2268
|
-
|
|
2267
|
+
console.log(`[useAdvancedOnScreen ${name}] 已在等待中,清除旧定时器并重新计时`);
|
|
2268
|
+
clearTimer();
|
|
2269
2269
|
}
|
|
2270
2270
|
// 如果设置了延迟时间
|
|
2271
2271
|
if (delay > 0) {
|
|
2272
|
-
console.log(`[useAdvancedOnScreen] 设置延迟定时器: ${delay}ms`);
|
|
2272
|
+
console.log(`[useAdvancedOnScreen ${name}] 设置延迟定时器: ${delay}ms`);
|
|
2273
2273
|
isWaitingRef.current = true;
|
|
2274
2274
|
timerRef.current = setTimeout(() => {
|
|
2275
2275
|
var _a;
|
|
2276
|
-
console.log(
|
|
2276
|
+
console.log(`[useAdvancedOnScreen ${name}] 延迟时间到,触发 onVisible`);
|
|
2277
2277
|
isWaitingRef.current = false;
|
|
2278
2278
|
timerRef.current = null;
|
|
2279
2279
|
(_a = onVisibleRef.current) === null || _a === void 0 ? void 0 : _a.call(onVisibleRef);
|
|
@@ -2281,13 +2281,13 @@ function useAdvancedOnScreen(ref, options = {}) {
|
|
|
2281
2281
|
}
|
|
2282
2282
|
else {
|
|
2283
2283
|
// 没有延迟,立即触发
|
|
2284
|
-
console.log(
|
|
2284
|
+
console.log(`[useAdvancedOnScreen ${name}] 无延迟,立即触发 onVisible`);
|
|
2285
2285
|
(_a = onVisibleRef.current) === null || _a === void 0 ? void 0 : _a.call(onVisibleRef);
|
|
2286
2286
|
}
|
|
2287
2287
|
}
|
|
2288
2288
|
else if (!isIntersecting || intersectionRatio < threshold) {
|
|
2289
2289
|
// 元素离开可视区域或未达到阈值
|
|
2290
|
-
console.log(
|
|
2290
|
+
console.log(`[useAdvancedOnScreen ${name}] 元素离开可视区域或未达到阈值,清除定时器`);
|
|
2291
2291
|
setIsVisible(false);
|
|
2292
2292
|
clearTimer();
|
|
2293
2293
|
(_b = onHiddenRef.current) === null || _b === void 0 ? void 0 : _b.call(onHiddenRef);
|
|
@@ -19611,45 +19611,71 @@ const CTAButton = ({ ctaData, style, onClick, onExposure }) => {
|
|
|
19611
19611
|
});
|
|
19612
19612
|
return (React.createElement("button", { ref: buttonRef, style: style, onClick: onClick }, ctaData.title));
|
|
19613
19613
|
};
|
|
19614
|
-
const ProductView = ({ children, onExposure }) => {
|
|
19614
|
+
const ProductView = ({ children, onExposure, onLeave }) => {
|
|
19615
19615
|
const productRef = React.useRef(null);
|
|
19616
19616
|
// 使用高级曝光检测:2/3区域 + 1000ms延迟
|
|
19617
19617
|
useAdvancedOnScreen(productRef, {
|
|
19618
19618
|
threshold: 0.67, // 2/3 区域可见才开始计时
|
|
19619
19619
|
delay: 1000,
|
|
19620
19620
|
onVisible: () => {
|
|
19621
|
-
// 每次进入2/3可视区域并停留1
|
|
19621
|
+
// 每次进入2/3可视区域并停留1秒后记录开始浏览时间
|
|
19622
19622
|
onExposure();
|
|
19623
|
+
},
|
|
19624
|
+
onHidden: () => {
|
|
19625
|
+
// 离开可视区域时上报productView事件
|
|
19626
|
+
onLeave === null || onLeave === void 0 ? void 0 : onLeave();
|
|
19623
19627
|
}
|
|
19624
19628
|
});
|
|
19625
19629
|
return (React.createElement("div", { ref: productRef, style: { width: '100%' } }, children));
|
|
19626
19630
|
};
|
|
19627
|
-
const PostView = ({ children, videoRef, isVideo, onExposure,
|
|
19631
|
+
const PostView = ({ children, videoRef, isVideo, onExposure, autoPlayTriggerRef, onVideoPlay, onVideoPause }) => {
|
|
19628
19632
|
const postRef = React.useRef(null);
|
|
19629
19633
|
// 使用高级曝光检测:2/3区域(threshold=0.67)+ 1000ms延迟
|
|
19630
19634
|
useAdvancedOnScreen(postRef, {
|
|
19631
19635
|
threshold: 0.67,
|
|
19632
19636
|
delay: 1000,
|
|
19633
19637
|
onVisible: () => {
|
|
19638
|
+
console.log('[PostView onVisible] 触发,isVideo:', isVideo, 'hasVideoRef:', !!(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current));
|
|
19634
19639
|
// 每次进入2/3区域并停留1秒后都触发曝光上报
|
|
19635
19640
|
if (onExposure) {
|
|
19636
19641
|
onExposure();
|
|
19637
19642
|
}
|
|
19638
19643
|
// 如果是视频,自动播放
|
|
19639
19644
|
if (isVideo && (videoRef === null || videoRef === void 0 ? void 0 : videoRef.current)) {
|
|
19640
|
-
|
|
19645
|
+
console.log('[PostView onVisible] 准备播放视频');
|
|
19646
|
+
// 标记这次播放是自动触发的
|
|
19647
|
+
if (autoPlayTriggerRef) {
|
|
19648
|
+
autoPlayTriggerRef.current = true;
|
|
19649
|
+
console.log('[PostView onVisible] 已设置自动播放标记');
|
|
19650
|
+
}
|
|
19651
|
+
videoRef.current.play().then(() => {
|
|
19652
|
+
console.log('[PostView onVisible] 视频 play() 成功');
|
|
19653
|
+
// 触发播放回调,更新暂停图标状态
|
|
19654
|
+
if (onVideoPlay) {
|
|
19655
|
+
onVideoPlay();
|
|
19656
|
+
}
|
|
19657
|
+
}).catch(err => {
|
|
19641
19658
|
console.warn('[PostView] Video autoplay failed:', err);
|
|
19659
|
+
// 播放失败时重置标记
|
|
19660
|
+
if (autoPlayTriggerRef) {
|
|
19661
|
+
autoPlayTriggerRef.current = false;
|
|
19662
|
+
}
|
|
19642
19663
|
});
|
|
19643
|
-
// 触发自动播放回调(用于上报 playVideo 事件)
|
|
19644
|
-
onVideoAutoPlay === null || onVideoAutoPlay === void 0 ? void 0 : onVideoAutoPlay();
|
|
19645
19664
|
}
|
|
19646
19665
|
},
|
|
19647
19666
|
onHidden: () => {
|
|
19667
|
+
console.log('[PostView onHidden] 触发,isVideo:', isVideo, 'hasVideoRef:', !!(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current));
|
|
19648
19668
|
// 如果是视频,离开2/3区域时自动暂停
|
|
19649
19669
|
if (isVideo && (videoRef === null || videoRef === void 0 ? void 0 : videoRef.current)) {
|
|
19670
|
+
console.log('[PostView onHidden] 暂停视频');
|
|
19650
19671
|
videoRef.current.pause();
|
|
19672
|
+
// 触发暂停回调,更新暂停图标状态
|
|
19673
|
+
if (onVideoPause) {
|
|
19674
|
+
onVideoPause();
|
|
19675
|
+
}
|
|
19651
19676
|
}
|
|
19652
|
-
}
|
|
19677
|
+
},
|
|
19678
|
+
name: 'PostView(Hero)'
|
|
19653
19679
|
});
|
|
19654
19680
|
return (React.createElement("div", { ref: postRef, style: { width: '100%', height: '100%' } }, children));
|
|
19655
19681
|
};
|
|
@@ -20015,6 +20041,12 @@ const StructurePage = (_a) => {
|
|
|
20015
20041
|
const isFirstPlay = React.useRef({});
|
|
20016
20042
|
const videoLoadTime = React.useRef({});
|
|
20017
20043
|
const videoAutoPlayReported = React.useRef(new Set()); // 追踪哪些视频已通过自动播放上报
|
|
20044
|
+
const videoPlayReportTime = React.useRef({}); // 追踪视频播放上报的时间戳,防止短时间内重复上报
|
|
20045
|
+
// 自动播放触发标记(用于区分自动播放和用户手动播放)
|
|
20046
|
+
const heroAutoPlayTrigger = React.useRef(false);
|
|
20047
|
+
const carouselAutoPlayTriggers = React.useRef({});
|
|
20048
|
+
// 追踪当前正在播放的 Carousel 视频索引(用于 onHidden 回调)
|
|
20049
|
+
const currentPlayingCarouselIndex = React.useRef(-1);
|
|
20018
20050
|
// 调试日志
|
|
20019
20051
|
console.log('[StructurePage] Props:', {
|
|
20020
20052
|
editorMode,
|
|
@@ -20251,17 +20283,45 @@ const StructurePage = (_a) => {
|
|
|
20251
20283
|
ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent(Object.assign({ eventSubject: 'ctaExposure', eventDescription: 'The cta was shown to the user' }, (viewPosition && { viewPosition })), rec, productData, sectionIndex !== undefined ? sectionIndex : 0);
|
|
20252
20284
|
}, [ctaEvent, data]);
|
|
20253
20285
|
// 视频播放事件处理
|
|
20254
|
-
const handleVideoPlay = React.useCallback((videoData, viewPosition, sectionIndex, videoRef
|
|
20255
|
-
|
|
20286
|
+
const handleVideoPlay = React.useCallback((videoData, viewPosition, sectionIndex, videoRef) => {
|
|
20287
|
+
console.log('[handleVideoPlay] 调用,viewPosition:', viewPosition, 'sectionIndex:', sectionIndex, 'hasDuration:', !!(videoRef === null || videoRef === void 0 ? void 0 : videoRef.duration));
|
|
20288
|
+
if (!videoRef || !videoRef.duration) {
|
|
20289
|
+
console.log('[handleVideoPlay] 返回:没有 videoRef 或 duration');
|
|
20256
20290
|
return;
|
|
20291
|
+
}
|
|
20257
20292
|
const videoId = `${videoData === null || videoData === void 0 ? void 0 : videoData.itemId}-${viewPosition}-${sectionIndex}`;
|
|
20258
|
-
|
|
20293
|
+
const now = Date.now();
|
|
20294
|
+
// 防止短时间内重复上报(play 和 playing 事件可能连续触发)
|
|
20295
|
+
// 如果距离上次上报不到500ms,则跳过
|
|
20296
|
+
const lastReportTime = videoPlayReportTime.current[videoId];
|
|
20297
|
+
if (lastReportTime && (now - lastReportTime) < 500) {
|
|
20298
|
+
console.log('[handleVideoPlay] 跳过上报:距离上次上报时间过短', {
|
|
20299
|
+
timeSinceLastReport: now - lastReportTime
|
|
20300
|
+
});
|
|
20301
|
+
return;
|
|
20302
|
+
}
|
|
20303
|
+
// 检查是否是自动播放触发的
|
|
20304
|
+
let isAutoPlay = false;
|
|
20305
|
+
if (viewPosition === 'heroSection' && heroAutoPlayTrigger.current) {
|
|
20306
|
+
isAutoPlay = true;
|
|
20307
|
+
console.log('[handleVideoPlay] Hero Section 自动播放标记为 true');
|
|
20308
|
+
heroAutoPlayTrigger.current = false; // 重置标记
|
|
20309
|
+
}
|
|
20310
|
+
else if (viewPosition === 'carouselSection' && sectionIndex !== undefined && carouselAutoPlayTriggers.current[sectionIndex]) {
|
|
20311
|
+
isAutoPlay = true;
|
|
20312
|
+
console.log('[handleVideoPlay] Carousel Section 自动播放标记为 true, index:', sectionIndex);
|
|
20313
|
+
carouselAutoPlayTriggers.current[sectionIndex] = false; // 重置标记
|
|
20314
|
+
}
|
|
20315
|
+
console.log('[handleVideoPlay] isAutoPlay:', isAutoPlay, 'videoId:', videoId);
|
|
20316
|
+
// 如果是自动播放,标记为已上报
|
|
20259
20317
|
if (isAutoPlay) {
|
|
20260
20318
|
videoAutoPlayReported.current.add(videoId);
|
|
20319
|
+
console.log('[handleVideoPlay] 标记为已通过自动播放上报');
|
|
20261
20320
|
}
|
|
20262
20321
|
else {
|
|
20263
20322
|
// 如果不是自动播放,但已经通过自动播放上报过,则跳过
|
|
20264
20323
|
if (videoAutoPlayReported.current.has(videoId)) {
|
|
20324
|
+
console.log('[handleVideoPlay] 跳过上报:已经通过自动播放上报过');
|
|
20265
20325
|
// 只记录播放时间,不上报
|
|
20266
20326
|
videoStartTime.current[videoId] = videoRef.currentTime || 0;
|
|
20267
20327
|
return;
|
|
@@ -20269,11 +20329,21 @@ const StructurePage = (_a) => {
|
|
|
20269
20329
|
}
|
|
20270
20330
|
// 记录视频开始播放时间
|
|
20271
20331
|
videoStartTime.current[videoId] = videoRef.currentTime || 0;
|
|
20332
|
+
// 记录本次上报时间
|
|
20333
|
+
videoPlayReportTime.current[videoId] = now;
|
|
20272
20334
|
// 判断是否首次播放
|
|
20273
20335
|
const playType = isFirstPlay.current[videoId] === false ? '1' : '0';
|
|
20274
20336
|
isFirstPlay.current[videoId] = false;
|
|
20275
20337
|
const videoDuration = videoRef.duration.toFixed(2);
|
|
20276
20338
|
const startTime = videoRef.currentTime.toFixed(2);
|
|
20339
|
+
console.log('[handleVideoPlay] 准备上报 playVideo 事件:', {
|
|
20340
|
+
videoId,
|
|
20341
|
+
isAutoPlay,
|
|
20342
|
+
playType,
|
|
20343
|
+
viewPosition,
|
|
20344
|
+
sectionIndex,
|
|
20345
|
+
duration: videoDuration
|
|
20346
|
+
});
|
|
20277
20347
|
bffEventReport === null || bffEventReport === void 0 ? void 0 : bffEventReport({
|
|
20278
20348
|
eventInfo: Object.assign({ eventSubject: 'playVideo', eventDescription: 'User played the video', sceneId: '', contentId: (videoData === null || videoData === void 0 ? void 0 : videoData.itemId) || '', contentName: (videoData === null || videoData === void 0 ? void 0 : videoData.title) || '', playType,
|
|
20279
20349
|
startTime,
|
|
@@ -20332,20 +20402,40 @@ const StructurePage = (_a) => {
|
|
|
20332
20402
|
}
|
|
20333
20403
|
});
|
|
20334
20404
|
}, [bffEventReport, data]);
|
|
20335
|
-
//
|
|
20405
|
+
// 产品进入可视区域时记录开始浏览时间
|
|
20336
20406
|
const handleProductViewExposure = React.useCallback((productData, viewPosition, sectionIndex) => {
|
|
20407
|
+
// 生成唯一标识
|
|
20408
|
+
const productId = `${productData === null || productData === void 0 ? void 0 : productData.itemId}-${viewPosition}-${sectionIndex}`;
|
|
20409
|
+
// 如果已经记录过开始时间,不再重复记录
|
|
20410
|
+
if (productViewStartTime.current[productId]) {
|
|
20411
|
+
return;
|
|
20412
|
+
}
|
|
20413
|
+
// 记录开始浏览时间
|
|
20414
|
+
productViewStartTime.current[productId] = Date.now();
|
|
20415
|
+
console.log('[handleProductViewExposure] 记录产品开始浏览时间:', {
|
|
20416
|
+
productId,
|
|
20417
|
+
startTime: productViewStartTime.current[productId]
|
|
20418
|
+
});
|
|
20419
|
+
}, []);
|
|
20420
|
+
// 产品离开可视区域时上报 productView 事件
|
|
20421
|
+
const handleProductViewLeave = React.useCallback((productData, viewPosition, sectionIndex) => {
|
|
20337
20422
|
var _a;
|
|
20338
|
-
//
|
|
20423
|
+
// 生成唯一标识
|
|
20339
20424
|
const productId = `${productData === null || productData === void 0 ? void 0 : productData.itemId}-${viewPosition}-${sectionIndex}`;
|
|
20340
|
-
//
|
|
20425
|
+
// 如果已经上报过,不再重复上报
|
|
20341
20426
|
if (exposedProductRefs.current.has(productId)) {
|
|
20342
20427
|
return;
|
|
20343
20428
|
}
|
|
20344
|
-
//
|
|
20429
|
+
// 获取开始浏览时间
|
|
20430
|
+
const startTime = productViewStartTime.current[productId];
|
|
20431
|
+
if (!startTime) {
|
|
20432
|
+
console.warn('[handleProductViewLeave] 未找到开始浏览时间,跳过上报:', productId);
|
|
20433
|
+
return;
|
|
20434
|
+
}
|
|
20435
|
+
// 计算停留时长(秒)
|
|
20436
|
+
const timeOnSite = Math.floor((Date.now() - startTime) / 1000);
|
|
20437
|
+
// 标记为已上报
|
|
20345
20438
|
exposedProductRefs.current.add(productId);
|
|
20346
|
-
productViewStartTime.current[productId] = Date.now();
|
|
20347
|
-
// 计算在页面停留时间(从产品出现到现在)
|
|
20348
|
-
const timeOnSite = 0; // 首次曝光时为0
|
|
20349
20439
|
// 根据 viewPosition 确定 fromKName
|
|
20350
20440
|
let fromKName = 'productPage';
|
|
20351
20441
|
if (viewPosition === 'heroSection') {
|
|
@@ -20360,6 +20450,11 @@ const StructurePage = (_a) => {
|
|
|
20360
20450
|
else if (viewPosition === 'footerSection') {
|
|
20361
20451
|
fromKName = 'pdpPage';
|
|
20362
20452
|
}
|
|
20453
|
+
console.log('[handleProductViewLeave] 上报 productView 事件:', {
|
|
20454
|
+
productId,
|
|
20455
|
+
timeOnSite,
|
|
20456
|
+
fromKName
|
|
20457
|
+
});
|
|
20363
20458
|
bffEventReport === null || bffEventReport === void 0 ? void 0 : bffEventReport({
|
|
20364
20459
|
eventInfo: {
|
|
20365
20460
|
eventSubject: 'productView',
|
|
@@ -20584,13 +20679,18 @@ const StructurePage = (_a) => {
|
|
|
20584
20679
|
// 2. propMultiCTAConfig 只是样式配置,不是数据源
|
|
20585
20680
|
// 3. 数据获取只应该在组件挂载时执行一次(除非 apiUrl/storyId 等关键参数变化)
|
|
20586
20681
|
// Hero Section 视频自动播放
|
|
20587
|
-
|
|
20588
|
-
|
|
20589
|
-
|
|
20590
|
-
|
|
20591
|
-
|
|
20592
|
-
|
|
20593
|
-
|
|
20682
|
+
// 注意:视频的自动播放逻辑由 PostView 组件处理(进入2/3可视区域并停留1秒后播放)
|
|
20683
|
+
// 移除了初始播放逻辑,避免与 PostView 冲突,确保视频加载完成后再播放
|
|
20684
|
+
// useEffect(() => {
|
|
20685
|
+
// if (heroVideoRef.current && data?.heroSection?.url) {
|
|
20686
|
+
// heroAutoPlayTrigger.current = true;
|
|
20687
|
+
// heroVideoRef.current.play().catch((err) => {
|
|
20688
|
+
// console.log('Video autoplay failed:', err);
|
|
20689
|
+
// heroAutoPlayTrigger.current = false;
|
|
20690
|
+
// });
|
|
20691
|
+
// setIsHeroVideoPaused(false);
|
|
20692
|
+
// }
|
|
20693
|
+
// }, [data?.heroSection]);
|
|
20594
20694
|
// 初始化 carousel 视频暂停状态
|
|
20595
20695
|
React.useEffect(() => {
|
|
20596
20696
|
if (data === null || data === void 0 ? void 0 : data.carouselSection) {
|
|
@@ -20635,7 +20735,7 @@ const StructurePage = (_a) => {
|
|
|
20635
20735
|
}, []);
|
|
20636
20736
|
// Post 图片/视频曝光上报(用于 Hero Section 等非轮播的 Post)
|
|
20637
20737
|
const postExposureReported = React.useRef(new Set());
|
|
20638
|
-
|
|
20738
|
+
React.useCallback((postData, viewPosition, sectionIndex) => {
|
|
20639
20739
|
var _a;
|
|
20640
20740
|
const postId = `${postData === null || postData === void 0 ? void 0 : postData.itemId}-${viewPosition}-${sectionIndex}`;
|
|
20641
20741
|
// 防止重复上报
|
|
@@ -20732,26 +20832,87 @@ const StructurePage = (_a) => {
|
|
|
20732
20832
|
// Carousel Section 的曝光检测 ref
|
|
20733
20833
|
const carouselSectionRef = React.useRef(null);
|
|
20734
20834
|
const hasCarouselReported = React.useRef(false);
|
|
20735
|
-
// Carousel Section
|
|
20835
|
+
// Carousel Section 进入可视区域时的回调
|
|
20836
|
+
const handleCarouselVisible = React.useCallback(() => {
|
|
20837
|
+
if (!(data === null || data === void 0 ? void 0 : data.carouselSection) || data.carouselSection.length === 0)
|
|
20838
|
+
return;
|
|
20839
|
+
const currentItem = data.carouselSection[carouselIndex];
|
|
20840
|
+
console.log('[Carousel onVisible] 当前索引:', carouselIndex, '是否是视频:', !!(currentItem === null || currentItem === void 0 ? void 0 : currentItem.url));
|
|
20841
|
+
// 只在首次进入可视区域时上报第一张图片
|
|
20842
|
+
if (!hasCarouselReported.current) {
|
|
20843
|
+
hasCarouselReported.current = true;
|
|
20844
|
+
// 只对图片类型上报(不包括视频)
|
|
20845
|
+
if (!currentItem.url) {
|
|
20846
|
+
handleCarouselImageStartEvent(carouselIndex);
|
|
20847
|
+
}
|
|
20848
|
+
}
|
|
20849
|
+
// 如果当前项是视频,自动播放
|
|
20850
|
+
if ((currentItem === null || currentItem === void 0 ? void 0 : currentItem.url) && carouselVideoRefs.current[carouselIndex]) {
|
|
20851
|
+
const currentVideo = carouselVideoRefs.current[carouselIndex];
|
|
20852
|
+
if (currentVideo) {
|
|
20853
|
+
console.log('[Carousel onVisible] 开始播放视频,索引:', carouselIndex);
|
|
20854
|
+
// 更新当前正在播放的视频索引
|
|
20855
|
+
currentPlayingCarouselIndex.current = carouselIndex;
|
|
20856
|
+
// 标记这次播放是自动触发的
|
|
20857
|
+
carouselAutoPlayTriggers.current[carouselIndex] = true;
|
|
20858
|
+
currentVideo.play().catch(err => {
|
|
20859
|
+
console.warn('[Carousel] Video autoplay failed (onVisible):', err);
|
|
20860
|
+
// 播放失败时重置标记
|
|
20861
|
+
carouselAutoPlayTriggers.current[carouselIndex] = false;
|
|
20862
|
+
});
|
|
20863
|
+
// 更新播放状态
|
|
20864
|
+
setCarouselVideoPausedStates(prev => {
|
|
20865
|
+
const newStates = [...prev];
|
|
20866
|
+
newStates[carouselIndex] = false;
|
|
20867
|
+
return newStates;
|
|
20868
|
+
});
|
|
20869
|
+
}
|
|
20870
|
+
}
|
|
20871
|
+
}, [data === null || data === void 0 ? void 0 : data.carouselSection, carouselIndex, handleCarouselImageStartEvent]);
|
|
20872
|
+
// Carousel Section 离开可视区域时的回调
|
|
20873
|
+
const handleCarouselHidden = React.useCallback(() => {
|
|
20874
|
+
// Carousel Section 离开可视区域时,暂停当前正在播放的视频
|
|
20875
|
+
// 使用 ref 来获取当前正在播放的视频索引,避免闭包问题
|
|
20876
|
+
const playingIndex = currentPlayingCarouselIndex.current;
|
|
20877
|
+
console.log('[Carousel onHidden] 被调用');
|
|
20878
|
+
console.log('[Carousel onHidden] 正在播放的视频索引:', playingIndex);
|
|
20879
|
+
console.log('[Carousel onHidden] carouselVideoRefs.current 长度:', carouselVideoRefs.current.length);
|
|
20880
|
+
console.log('[Carousel onHidden] carouselVideoRefs.current[playingIndex] 存在:', !!carouselVideoRefs.current[playingIndex]);
|
|
20881
|
+
if (playingIndex >= 0 && carouselVideoRefs.current[playingIndex]) {
|
|
20882
|
+
const currentVideo = carouselVideoRefs.current[playingIndex];
|
|
20883
|
+
if (currentVideo) {
|
|
20884
|
+
console.log('[Carousel onHidden] 准备暂停视频,索引:', playingIndex, '当前播放状态:', !currentVideo.paused);
|
|
20885
|
+
currentVideo.pause();
|
|
20886
|
+
console.log('[Carousel onHidden] 已调用 pause()');
|
|
20887
|
+
// 更新暂停状态
|
|
20888
|
+
setCarouselVideoPausedStates(prev => {
|
|
20889
|
+
const newStates = [...prev];
|
|
20890
|
+
newStates[playingIndex] = true;
|
|
20891
|
+
return newStates;
|
|
20892
|
+
});
|
|
20893
|
+
}
|
|
20894
|
+
else {
|
|
20895
|
+
console.log('[Carousel onHidden] currentVideo 为空');
|
|
20896
|
+
}
|
|
20897
|
+
}
|
|
20898
|
+
else {
|
|
20899
|
+
console.log('[Carousel onHidden] 条件不满足,不暂停视频');
|
|
20900
|
+
}
|
|
20901
|
+
}, []);
|
|
20902
|
+
// Carousel Section 进入可视区域时上报第一张图片的浏览事件,并自动播放视频
|
|
20736
20903
|
useAdvancedOnScreen(carouselSectionRef, {
|
|
20737
20904
|
threshold: 0.67,
|
|
20738
20905
|
delay: 1000,
|
|
20739
|
-
onVisible:
|
|
20740
|
-
|
|
20741
|
-
|
|
20742
|
-
hasCarouselReported.current = true;
|
|
20743
|
-
const currentItem = data.carouselSection[carouselIndex];
|
|
20744
|
-
// 只对图片类型上报(不包括视频)
|
|
20745
|
-
if (!currentItem.url) {
|
|
20746
|
-
handleCarouselImageStartEvent(carouselIndex);
|
|
20747
|
-
}
|
|
20748
|
-
}
|
|
20749
|
-
}
|
|
20906
|
+
onVisible: handleCarouselVisible,
|
|
20907
|
+
onHidden: handleCarouselHidden,
|
|
20908
|
+
name: 'Carousel'
|
|
20750
20909
|
});
|
|
20751
|
-
// Carousel
|
|
20910
|
+
// Carousel 切换时暂停其他视频
|
|
20911
|
+
// 注意:不再在切换时立即播放当前视频,而是由 PostView 组件处理(进入2/3可视区域并停留1秒后播放)
|
|
20752
20912
|
React.useEffect(() => {
|
|
20753
20913
|
if (!(data === null || data === void 0 ? void 0 : data.carouselSection) || data.carouselSection.length === 0)
|
|
20754
20914
|
return;
|
|
20915
|
+
console.log('[Carousel useEffect] 切换到索引:', carouselIndex);
|
|
20755
20916
|
// 暂停所有其他视频
|
|
20756
20917
|
carouselVideoRefs.current.forEach((videoRef, index) => {
|
|
20757
20918
|
if (videoRef && index !== carouselIndex) {
|
|
@@ -20764,22 +20925,6 @@ const StructurePage = (_a) => {
|
|
|
20764
20925
|
});
|
|
20765
20926
|
}
|
|
20766
20927
|
});
|
|
20767
|
-
// 如果当前项是视频,自动播放
|
|
20768
|
-
const currentItem = data.carouselSection[carouselIndex];
|
|
20769
|
-
if ((currentItem === null || currentItem === void 0 ? void 0 : currentItem.url) && carouselVideoRefs.current[carouselIndex]) {
|
|
20770
|
-
const currentVideo = carouselVideoRefs.current[carouselIndex];
|
|
20771
|
-
if (currentVideo) {
|
|
20772
|
-
currentVideo.play().catch(err => {
|
|
20773
|
-
console.warn('[Carousel] Video autoplay failed:', err);
|
|
20774
|
-
});
|
|
20775
|
-
// 更新播放状态
|
|
20776
|
-
setCarouselVideoPausedStates(prev => {
|
|
20777
|
-
const newStates = [...prev];
|
|
20778
|
-
newStates[carouselIndex] = false;
|
|
20779
|
-
return newStates;
|
|
20780
|
-
});
|
|
20781
|
-
}
|
|
20782
|
-
}
|
|
20783
20928
|
}, [carouselIndex, data]);
|
|
20784
20929
|
// 触摸滑动处理
|
|
20785
20930
|
const handleTouchStart = (e) => {
|
|
@@ -20904,27 +21049,41 @@ const StructurePage = (_a) => {
|
|
|
20904
21049
|
return textStyle;
|
|
20905
21050
|
})()) }, data.heroSection.text))),
|
|
20906
21051
|
React.createElement("div", { style: baseStyles.heroImageContainer },
|
|
20907
|
-
React.createElement(PostView, { videoRef: heroVideoRef, isVideo: !!data.heroSection.url,
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20915
|
-
|
|
20916
|
-
|
|
21052
|
+
React.createElement(PostView, { videoRef: heroVideoRef, isVideo: !!data.heroSection.url, autoPlayTriggerRef: heroAutoPlayTrigger }, data.heroSection.url ? (React.createElement("div", { style: { position: 'relative', width: '100%', height: '100%' }, onClick: handleHeroVideoClick },
|
|
21053
|
+
React.createElement("video", { ref: (el) => {
|
|
21054
|
+
if (heroVideoRef) {
|
|
21055
|
+
heroVideoRef.current = el;
|
|
21056
|
+
}
|
|
21057
|
+
// 添加 addEventListener 监听事件,确保网络慢时也能触发
|
|
21058
|
+
if (el && !el.dataset.playListenerAdded) {
|
|
21059
|
+
el.dataset.playListenerAdded = 'true';
|
|
21060
|
+
// play 事件:视频开始播放时触发(可能还在缓冲)
|
|
21061
|
+
el.addEventListener('play', (e) => {
|
|
21062
|
+
console.log('[Hero Video] play event triggered');
|
|
21063
|
+
handleVideoPlay(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
21064
|
+
});
|
|
21065
|
+
// playing 事件:视频真正开始播放时触发(已缓冲足够数据)
|
|
21066
|
+
// 这是网络慢时更可靠的事件
|
|
21067
|
+
el.addEventListener('playing', (e) => {
|
|
21068
|
+
console.log('[Hero Video] playing event triggered (backup)');
|
|
21069
|
+
// playing 也触发一次,防止 play 事件没触发
|
|
21070
|
+
handleVideoPlay(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
21071
|
+
});
|
|
21072
|
+
el.addEventListener('pause', (e) => {
|
|
21073
|
+
console.log('[Hero Video] pause event triggered');
|
|
21074
|
+
handleVideoPlayOver(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
21075
|
+
});
|
|
21076
|
+
el.addEventListener('ended', (e) => {
|
|
21077
|
+
console.log('[Hero Video] ended event triggered');
|
|
21078
|
+
handleVideoPlayOver(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
21079
|
+
});
|
|
21080
|
+
}
|
|
21081
|
+
}, src: data.heroSection.url, style: baseStyles.heroVideo, muted: true, loop: true, playsInline: true, controls: false, onLoadedMetadata: () => {
|
|
20917
21082
|
var _a;
|
|
20918
21083
|
const videoId = `${(_a = data.heroSection) === null || _a === void 0 ? void 0 : _a.itemId}-heroSection-0`;
|
|
20919
21084
|
const loadTime = Date.now();
|
|
20920
21085
|
const initTime = videoLoadTime.current[videoId] || loadTime;
|
|
20921
21086
|
videoLoadTime.current[videoId] = loadTime - initTime;
|
|
20922
|
-
}, onPlay: (e) => {
|
|
20923
|
-
handleVideoPlay(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
20924
|
-
}, onPause: (e) => {
|
|
20925
|
-
handleVideoPlayOver(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
20926
|
-
}, onEnded: (e) => {
|
|
20927
|
-
handleVideoPlayOver(data.heroSection, 'heroSection', 0, e.currentTarget);
|
|
20928
21087
|
} }),
|
|
20929
21088
|
isHeroVideoPaused && (React.createElement(FormatImage$1, { className: 'clc-pb-video-pause', src: videoPlayIcon, alt: 'play' })))) : ((_f = data.heroSection.imgUrls) === null || _f === void 0 ? void 0 : _f[0]) ? (React.createElement("img", { src: data.heroSection.imgUrls[0], alt: 'Hero', style: baseStyles.heroImage })) : null),
|
|
20930
21089
|
React.createElement("div", { style: baseStyles.heroOverlay }, renderCTA('heroButton', (_h = (_g = data.heroSection.bindProducts) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.bindCta, (_j = data.heroSection.bindProducts) === null || _j === void 0 ? void 0 : _j[0], baseStyles.heroButton, 'heroSection', 0))))),
|
|
@@ -20932,22 +21091,99 @@ const StructurePage = (_a) => {
|
|
|
20932
21091
|
React.createElement("div", { style: baseStyles.carouselImageContainer, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd },
|
|
20933
21092
|
React.createElement("div", { style: Object.assign(Object.assign({}, baseStyles.carouselContainer), { transform: `translateX(-${carouselIndex * 100}%)` }) }, data.carouselSection.map((item, index) => {
|
|
20934
21093
|
var _a;
|
|
20935
|
-
|
|
21094
|
+
// 只有当前显示的 slide 才应用曝光检测
|
|
21095
|
+
const isCurrentSlide = index === carouselIndex;
|
|
21096
|
+
return (React.createElement("div", { key: item.itemId, style: baseStyles.carouselSlide }, item.url ? (
|
|
21097
|
+
// 视频:使用 PostView 包裹,但只在当前显示时生效
|
|
21098
|
+
isCurrentSlide ? (React.createElement(PostView, { videoRef: { current: carouselVideoRefs.current[index] }, isVideo: true, autoPlayTriggerRef: {
|
|
21099
|
+
get current() {
|
|
21100
|
+
return carouselAutoPlayTriggers.current[index] || false;
|
|
21101
|
+
},
|
|
21102
|
+
set current(value) {
|
|
21103
|
+
carouselAutoPlayTriggers.current[index] = value;
|
|
21104
|
+
}
|
|
21105
|
+
}, onVideoPlay: () => {
|
|
21106
|
+
// 视频开始播放,隐藏暂停图标
|
|
21107
|
+
console.log('[Carousel PostView] onVideoPlay 回调,索引:', index);
|
|
21108
|
+
setCarouselVideoPausedStates(prev => {
|
|
21109
|
+
const newStates = [...prev];
|
|
21110
|
+
newStates[index] = false;
|
|
21111
|
+
return newStates;
|
|
21112
|
+
});
|
|
21113
|
+
}, onVideoPause: () => {
|
|
21114
|
+
// 视频暂停,显示暂停图标
|
|
21115
|
+
console.log('[Carousel PostView] onVideoPause 回调,索引:', index);
|
|
21116
|
+
setCarouselVideoPausedStates(prev => {
|
|
21117
|
+
const newStates = [...prev];
|
|
21118
|
+
newStates[index] = true;
|
|
21119
|
+
return newStates;
|
|
21120
|
+
});
|
|
21121
|
+
} },
|
|
21122
|
+
React.createElement("div", { style: { position: 'relative', width: '100%', height: '100%' }, onClick: () => handleCarouselVideoClick(index) },
|
|
21123
|
+
React.createElement("video", { ref: (el) => {
|
|
21124
|
+
carouselVideoRefs.current[index] = el;
|
|
21125
|
+
// 添加 addEventListener 监听事件,确保网络慢时也能触发
|
|
21126
|
+
if (el && !el.dataset.playListenerAdded) {
|
|
21127
|
+
el.dataset.playListenerAdded = 'true';
|
|
21128
|
+
// play 事件:视频开始播放时触发(可能还在缓冲)
|
|
21129
|
+
el.addEventListener('play', (e) => {
|
|
21130
|
+
console.log('[Carousel Video] play event triggered, index:', index);
|
|
21131
|
+
handleVideoPlay(item, 'carouselSection', index, e.currentTarget);
|
|
21132
|
+
});
|
|
21133
|
+
// playing 事件:视频真正开始播放时触发(已缓冲足够数据)
|
|
21134
|
+
el.addEventListener('playing', (e) => {
|
|
21135
|
+
console.log('[Carousel Video] playing event triggered (backup), index:', index);
|
|
21136
|
+
handleVideoPlay(item, 'carouselSection', index, e.currentTarget);
|
|
21137
|
+
});
|
|
21138
|
+
el.addEventListener('pause', (e) => {
|
|
21139
|
+
console.log('[Carousel Video] pause event triggered, index:', index);
|
|
21140
|
+
handleVideoPlayOver(item, 'carouselSection', index, e.currentTarget);
|
|
21141
|
+
});
|
|
21142
|
+
el.addEventListener('ended', (e) => {
|
|
21143
|
+
console.log('[Carousel Video] ended event triggered, index:', index);
|
|
21144
|
+
handleVideoPlayOver(item, 'carouselSection', index, e.currentTarget);
|
|
21145
|
+
});
|
|
21146
|
+
}
|
|
21147
|
+
}, src: item.url, style: baseStyles.carouselVideo, muted: true, loop: true, playsInline: true, controls: false, draggable: false, onDragStart: (e) => e.preventDefault(), onLoadedMetadata: () => {
|
|
21148
|
+
const videoId = `${item.itemId}-carouselSection-${index}`;
|
|
21149
|
+
const loadTime = Date.now();
|
|
21150
|
+
const initTime = videoLoadTime.current[videoId] || loadTime;
|
|
21151
|
+
videoLoadTime.current[videoId] = loadTime - initTime;
|
|
21152
|
+
} }),
|
|
21153
|
+
carouselVideoPausedStates[index] && (React.createElement(FormatImage$1, { className: 'clc-pb-video-pause', src: videoPlayIcon, alt: 'play' }))))) : (
|
|
21154
|
+
// 非当前 slide,不使用 PostView
|
|
21155
|
+
React.createElement("div", { style: { position: 'relative', width: '100%', height: '100%' }, onClick: () => handleCarouselVideoClick(index) },
|
|
20936
21156
|
React.createElement("video", { ref: (el) => {
|
|
20937
21157
|
carouselVideoRefs.current[index] = el;
|
|
21158
|
+
// 添加 addEventListener 监听事件,确保网络慢时也能触发
|
|
21159
|
+
if (el && !el.dataset.playListenerAdded) {
|
|
21160
|
+
el.dataset.playListenerAdded = 'true';
|
|
21161
|
+
// play 事件:视频开始播放时触发(可能还在缓冲)
|
|
21162
|
+
el.addEventListener('play', (e) => {
|
|
21163
|
+
console.log('[Carousel Video (non-current)] play event triggered, index:', index);
|
|
21164
|
+
handleVideoPlay(item, 'carouselSection', index, e.currentTarget);
|
|
21165
|
+
});
|
|
21166
|
+
// playing 事件:视频真正开始播放时触发(已缓冲足够数据)
|
|
21167
|
+
el.addEventListener('playing', (e) => {
|
|
21168
|
+
console.log('[Carousel Video (non-current)] playing event triggered (backup), index:', index);
|
|
21169
|
+
handleVideoPlay(item, 'carouselSection', index, e.currentTarget);
|
|
21170
|
+
});
|
|
21171
|
+
el.addEventListener('pause', (e) => {
|
|
21172
|
+
console.log('[Carousel Video (non-current)] pause event triggered, index:', index);
|
|
21173
|
+
handleVideoPlayOver(item, 'carouselSection', index, e.currentTarget);
|
|
21174
|
+
});
|
|
21175
|
+
el.addEventListener('ended', (e) => {
|
|
21176
|
+
console.log('[Carousel Video (non-current)] ended event triggered, index:', index);
|
|
21177
|
+
handleVideoPlayOver(item, 'carouselSection', index, e.currentTarget);
|
|
21178
|
+
});
|
|
21179
|
+
}
|
|
20938
21180
|
}, src: item.url, style: baseStyles.carouselVideo, muted: true, loop: true, playsInline: true, controls: false, draggable: false, onDragStart: (e) => e.preventDefault(), onLoadedMetadata: () => {
|
|
20939
21181
|
const videoId = `${item.itemId}-carouselSection-${index}`;
|
|
20940
21182
|
const loadTime = Date.now();
|
|
20941
21183
|
const initTime = videoLoadTime.current[videoId] || loadTime;
|
|
20942
21184
|
videoLoadTime.current[videoId] = loadTime - initTime;
|
|
20943
|
-
}, onPlay: (e) => {
|
|
20944
|
-
handleVideoPlay(item, 'carouselSection', index, e.currentTarget);
|
|
20945
|
-
}, onPause: (e) => {
|
|
20946
|
-
handleVideoPlayOver(item, 'carouselSection', index, e.currentTarget);
|
|
20947
|
-
}, onEnded: (e) => {
|
|
20948
|
-
handleVideoPlayOver(item, 'carouselSection', index, e.currentTarget);
|
|
20949
21185
|
} }),
|
|
20950
|
-
carouselVideoPausedStates[index] && (React.createElement(FormatImage$1, { className: 'clc-pb-video-pause', src: videoPlayIcon, alt: 'play' })))) : ((_a = item.imgUrls) === null || _a === void 0 ? void 0 : _a[0]) ? (React.createElement("img", { src: item.imgUrls[0], alt: item.text || 'Carousel', style: baseStyles.carouselImage, draggable: false, onDragStart: (e) => e.preventDefault(), onLoad: () => {
|
|
21186
|
+
carouselVideoPausedStates[index] && (React.createElement(FormatImage$1, { className: 'clc-pb-video-pause', src: videoPlayIcon, alt: 'play' }))))) : ((_a = item.imgUrls) === null || _a === void 0 ? void 0 : _a[0]) ? (React.createElement("img", { src: item.imgUrls[0], alt: item.text || 'Carousel', style: baseStyles.carouselImage, draggable: false, onDragStart: (e) => e.preventDefault(), onLoad: () => {
|
|
20951
21187
|
// 记录图片加载完成时间
|
|
20952
21188
|
if (!carouselImageLoadTime.current[index]) {
|
|
20953
21189
|
carouselImageLoadTime.current[index] = Date.now();
|
|
@@ -21001,7 +21237,7 @@ const StructurePage = (_a) => {
|
|
|
21001
21237
|
return textStyle;
|
|
21002
21238
|
})()) }, (_m = data.carouselSection[carouselIndex]) === null || _m === void 0 ? void 0 : _m.text))),
|
|
21003
21239
|
renderCTA('carouselButton', (_q = (_p = (_o = data.carouselSection[carouselIndex]) === null || _o === void 0 ? void 0 : _o.bindProducts) === null || _p === void 0 ? void 0 : _p[0]) === null || _q === void 0 ? void 0 : _q.bindCta, (_s = (_r = data.carouselSection[carouselIndex]) === null || _r === void 0 ? void 0 : _r.bindProducts) === null || _s === void 0 ? void 0 : _s[0], baseStyles.carouselButton, 'carouselSection', carouselIndex)))),
|
|
21004
|
-
data.highlightRevealSection && (React.createElement(ProductView, { onExposure: () => handleProductViewExposure(data.highlightRevealSection, 'highlightRevealSection', 0) },
|
|
21240
|
+
data.highlightRevealSection && (React.createElement(ProductView, { onExposure: () => handleProductViewExposure(data.highlightRevealSection, 'highlightRevealSection', 0), onLeave: () => handleProductViewLeave(data.highlightRevealSection, 'highlightRevealSection', 0) },
|
|
21005
21241
|
React.createElement("div", { style: mergeStyles(baseStyles.highlightSection, 'highlightSection', { excludeBorder: true }) },
|
|
21006
21242
|
React.createElement("div", { style: baseStyles.highlightImageContainer },
|
|
21007
21243
|
React.createElement("img", { src: data.highlightRevealSection.landingImageUrl || data.highlightRevealSection.cover, alt: data.highlightRevealSection.title, style: baseStyles.highlightImage })),
|
|
@@ -21087,7 +21323,7 @@ const StructurePage = (_a) => {
|
|
|
21087
21323
|
// 使用产品在数据数组中的实际索引来确定 buttonKey
|
|
21088
21324
|
const productDataIndex = productIndexMap[gridIndex];
|
|
21089
21325
|
const buttonKey = `productButton${productDataIndex || gridIndex + 1}`;
|
|
21090
|
-
return (React.createElement("div", { key: (product === null || product === void 0 ? void 0 : product.itemId) || `empty-${gridIndex}`, style: baseStyles.productItem }, product ? (React.createElement(ProductView, { onExposure: () => handleProductViewExposure(product, 'productGridSection', gridIndex) },
|
|
21326
|
+
return (React.createElement("div", { key: (product === null || product === void 0 ? void 0 : product.itemId) || `empty-${gridIndex}`, style: baseStyles.productItem }, product ? (React.createElement(ProductView, { onExposure: () => handleProductViewExposure(product, 'productGridSection', gridIndex), onLeave: () => handleProductViewLeave(product, 'productGridSection', gridIndex) },
|
|
21091
21327
|
React.createElement(React.Fragment, null,
|
|
21092
21328
|
React.createElement("div", { style: baseStyles.productImageContainer },
|
|
21093
21329
|
React.createElement("img", { src: product.landingImageUrl || product.cover,
|