pb-sxp-ui 1.15.13-alpha.1 → 1.15.13-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/index.cjs +333 -24
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +333 -24
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.cjs +6 -6
  6. package/dist/index.min.cjs.map +1 -1
  7. package/dist/index.min.js +6 -6
  8. package/dist/index.min.js.map +1 -1
  9. package/dist/pb-ui.js +333 -24
  10. package/dist/pb-ui.js.map +1 -1
  11. package/dist/pb-ui.min.js +6 -6
  12. package/dist/pb-ui.min.js.map +1 -1
  13. package/es/core/components/DiyStoryPreview/VideoWidget.js +5 -2
  14. package/es/core/components/DiyStoryPreview/index.d.ts +2 -0
  15. package/es/core/components/DiyStoryPreview/index.js +277 -18
  16. package/es/core/components/SxpPageRender/ExpandableText.js +10 -2
  17. package/es/core/components/SxpPageRender/RenderCard.js +4 -4
  18. package/es/materials/sxp/template/MultiCommodity/index.js +1 -1
  19. package/es/materials/sxp/template/MultiCommodityDiro/index.js +2 -1
  20. package/es/materials/sxp/template/MultiCommodityDiroNew/index.js +2 -1
  21. package/es/materials/sxp/template/components/EventProvider.js +2 -2
  22. package/lib/core/components/DiyStoryPreview/VideoWidget.js +5 -2
  23. package/lib/core/components/DiyStoryPreview/index.d.ts +2 -0
  24. package/lib/core/components/DiyStoryPreview/index.js +277 -18
  25. package/lib/core/components/SxpPageRender/ExpandableText.js +10 -2
  26. package/lib/core/components/SxpPageRender/RenderCard.js +4 -4
  27. package/lib/materials/sxp/template/MultiCommodity/index.js +1 -1
  28. package/lib/materials/sxp/template/MultiCommodityDiro/index.js +2 -1
  29. package/lib/materials/sxp/template/MultiCommodityDiroNew/index.js +2 -1
  30. package/lib/materials/sxp/template/components/EventProvider.js +2 -2
  31. package/package.json +1 -1
@@ -39,6 +39,7 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
39
39
  }, [bffEventReport, data, index, isFirstPlay]);
40
40
  const handleLoadedMetadata = useCallback(() => {
41
41
  var _a;
42
+ videoRef.current.currentTime = rec === null || rec === void 0 ? void 0 : rec.startTime;
42
43
  (_a = videoRef === null || videoRef === void 0 ? void 0 : videoRef.current) === null || _a === void 0 ? void 0 : _a.play();
43
44
  setIsLoadFinish(true);
44
45
  }, []);
@@ -112,6 +113,8 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
112
113
  }, []);
113
114
  const handlePause = () => {
114
115
  var _a, _b, _c, _d, _e, _f;
116
+ if (!videoRef.current || !isActive)
117
+ return;
115
118
  if (!loopPlay)
116
119
  return;
117
120
  if (index === (data === null || data === void 0 ? void 0 : data.length) - 1) {
@@ -134,7 +137,6 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
134
137
  if (!videoPlayerWrapperNode)
135
138
  return;
136
139
  videoRef.current = mountVideoPlayerAtNode === null || mountVideoPlayerAtNode === void 0 ? void 0 : mountVideoPlayerAtNode(videoPlayerWrapperNode);
137
- videoRef.current.currentTime = rec === null || rec === void 0 ? void 0 : rec.startTime;
138
140
  if (!(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current))
139
141
  return;
140
142
  const Hls = window === null || window === void 0 ? void 0 : window.Hls;
@@ -145,6 +147,7 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
145
147
  hls === null || hls === void 0 ? void 0 : hls.attachMedia(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current);
146
148
  hls === null || hls === void 0 ? void 0 : hls.on(Hls.Events.MANIFEST_PARSED, function () {
147
149
  var _a;
150
+ videoRef.current.currentTime = rec === null || rec === void 0 ? void 0 : rec.startTime;
148
151
  (_a = videoRef === null || videoRef === void 0 ? void 0 : videoRef.current) === null || _a === void 0 ? void 0 : _a.play();
149
152
  });
150
153
  }
@@ -163,7 +166,7 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
163
166
  (_c = videoRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener('pause', handlePause);
164
167
  (_d = videoRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener('timeupdate', handleTimeUpload);
165
168
  };
166
- }, [handleLoadedMetadata, handlePlaying, rec, handLoadeddata, isActive]);
169
+ }, [handleLoadedMetadata, handlePlaying, rec, handLoadeddata, isActive, loopPlay]);
167
170
  const renderPoster = useMemo(() => {
168
171
  if (!(sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.placeholder_image) || isLoadFinish) {
169
172
  return null;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ISxpPageRenderProps } from '../SxpPageRender';
3
+ import '../SxpPageRender/index.less';
3
4
  export interface IScene {
4
5
  blueprintStep: number;
5
6
  endTime: number;
@@ -13,6 +14,7 @@ export interface IScene {
13
14
  sceneTag: string;
14
15
  startTime: number;
15
16
  traceInfo: string;
17
+ bindProducts?: any[];
16
18
  }
17
19
  export type ScenesType = IScene[];
18
20
  export type DiyStoryPreviewType = ISxpPageRenderProps & {
@@ -1,20 +1,199 @@
1
1
  import React, { memo, useEffect, useMemo, useRef } from 'react';
2
2
  import { Swiper, SwiperSlide } from 'swiper/react';
3
- import Nudge from '../SxpPageRender/Nudge';
3
+ import { cloneDeep } from 'lodash';
4
4
  import RenderCard from '../SxpPageRender/RenderCard';
5
5
  import ExpandableText from '../SxpPageRender/ExpandableText';
6
- import Hashtag from '../SxpPageRender/Hashtag';
7
6
  import LikeButton from '../SxpPageRender/LikeButton';
8
7
  import { useIconLink } from '../SxpPageRender/useIconLink';
8
+ import ToggleButton from '../SxpPageRender/ToggleButton';
9
9
  import PictureGroup from './PictureGroup';
10
10
  import VideoWidget from './VideoWidget';
11
11
  import * as _materials_ from '../../../materials';
12
+ import '../SxpPageRender/index.less';
12
13
  const RESOLVER = {};
13
14
  Object.values(_materials_).forEach((v) => {
14
15
  RESOLVER[v.extend.type] = v;
15
16
  });
16
17
  const defaultUnLikeIconPath = '/pb_static/f71266d2c64446c5ae6a5a7f5489cc0a.png';
17
18
  const defaultLikeIconPath = '/pb_static/f07900fe3f0f4ae188ea1611d4801a44.png';
19
+ const recData = {
20
+ position: 0,
21
+ isCollected: false,
22
+ product: null,
23
+ video: {
24
+ appId: null,
25
+ itemId: 'VIDEOSsRgI1695278974368',
26
+ title: '8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片8张尺寸不一样的图片',
27
+ enTitle: null,
28
+ icon: null,
29
+ cover: 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20231017/fsJFWmW1dGyW7XmDspbJPTn5esL3U1697538777398.png',
30
+ link: null,
31
+ linkTitle: null,
32
+ linkType: null,
33
+ menuCategoryId: null,
34
+ remark: null,
35
+ tags: [
36
+ 'Gift-Giving',
37
+ 'Daily Wear',
38
+ 'Business Formal',
39
+ 'Sports/Casual',
40
+ 'Anniversary Gifts',
41
+ 'Wedding/Engagement',
42
+ 'Formal Dinner/Party'
43
+ ],
44
+ traceInfo: ':VIDEO:VIDEOSsRgI1695278974368:regular:1:VPRHSkRS1697701789894:main::0:EXPMW20250305155940:COMBTh20250305160047:',
45
+ value: 385,
46
+ weight: null,
47
+ bindCta: null,
48
+ bindProduct: null,
49
+ bindProducts: [
50
+ {
51
+ appId: 'wx448578f8851f3dce',
52
+ itemId: 'test02178888',
53
+ title: 'christian dior小包包 新CDN',
54
+ enTitle: null,
55
+ icon: null,
56
+ cover: 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20240913/fs2jqiurjftpoaba67iiwr9jt5sc31726213277754.avif',
57
+ link: '/pages/details/index?spu_id=1702262707659534338',
58
+ linkTitle: '',
59
+ linkType: 'MP',
60
+ menuCategoryId: null,
61
+ remark: null,
62
+ tags: [],
63
+ traceInfo: ':PRODUCT:test02178888:regular:1:VPRHSkRS1697701789894:main::0:EXPMW20250305155940:COMBTh20250305160047:',
64
+ value: null,
65
+ weight: null,
66
+ bindCta: {
67
+ appId: 'wx448578f8851f3dce',
68
+ itemId: 'CTA3KofE1716186622249',
69
+ title: 'SHOP NOW 立即购买',
70
+ enTitle: 'BUY NOW立即购买,选择你所喜爱的;',
71
+ icon: 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20240520/fssfxbmiwghixmgblz9uriwennd2r1716186615574.avif',
72
+ cover: null,
73
+ link: '/pages/details/index?spu_id=1702262707659534338',
74
+ linkTitle: '',
75
+ linkType: 'MP',
76
+ menuCategoryId: '64b60b202caf0e1c1ce1e17d',
77
+ remark: null,
78
+ tags: [
79
+ "Woman's Perfumes",
80
+ 'Plates & Bowls',
81
+ 'Glasses',
82
+ 'Multicolor',
83
+ 'Carafes',
84
+ 'Tea & Coffee',
85
+ 'Green',
86
+ 'Grey',
87
+ 'Cutlery'
88
+ ],
89
+ traceInfo: ':CTA:CTA3KofE1716186622249:regular:1:VPRHSkRS1697701789894:main::0:EXPMW20250305155940:COMBTh20250305160047:',
90
+ value: null,
91
+ weight: null
92
+ },
93
+ collection: 'Ricco',
94
+ currency: 'INR-₹',
95
+ homePage: [
96
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20240913/fs2jqiurjftpoaba67iiwr9jt5sc31726213277754.avif',
97
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20240913/fsr9ttuzuljs85smqi6lsidovnyoy1726213285994.avif',
98
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20240913/fsknmfhx2lxukxews05guwwxr8rju1726213281108.avif',
99
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20240913/fs0acnua4f1clamdpwdsrh0v5dgc61726213289247.avif'
100
+ ],
101
+ info: 'test',
102
+ price: 53200,
103
+ shippingInfo: null,
104
+ taxInfo: null
105
+ },
106
+ {
107
+ appId: null,
108
+ itemId: '113J631A0684_C520',
109
+ title: 'Sweatshirt à capuche Dior Oblique, coupe relax',
110
+ enTitle: null,
111
+ icon: null,
112
+ cover: 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20241115/fsaf0xq8vx8gkkl30y1h1swpinmbt1731661943891.avif',
113
+ link: 'https://www.dior.com/fr_fr/fashion/products/113J631A0684_C520',
114
+ linkTitle: null,
115
+ linkType: 'WEB',
116
+ menuCategoryId: null,
117
+ remark: null,
118
+ tags: [],
119
+ traceInfo: ':PRODUCT:113J631A0684_C520:regular:1:VPRHSkRS1697701789894:main::0:EXPMW20250305155940:COMBTh20250305160047:',
120
+ value: null,
121
+ weight: null,
122
+ bindCta: {
123
+ appId: null,
124
+ itemId: 'CTAAfaKf1730796437032',
125
+ title: 'test',
126
+ enTitle: 'test',
127
+ icon: 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20241105/fsjblxoud2tmehpiqqomh0oktwqrd1730796431496.avif',
128
+ cover: null,
129
+ link: null,
130
+ linkTitle: null,
131
+ linkType: null,
132
+ menuCategoryId: '64b60b202caf0e1c1ce1e17d',
133
+ remark: '',
134
+ tags: [],
135
+ traceInfo: ':CTA:CTAAfaKf1730796437032:regular:1:VPRHSkRS1697701789894:main::0:EXPMW20250305155940:COMBTh20250305160047:',
136
+ value: null,
137
+ weight: null
138
+ },
139
+ collection: 'Jacquard de coton éponge bleu',
140
+ currency: 'EUR-€',
141
+ homePage: [
142
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20241115/fsaf0xq8vx8gkkl30y1h1swpinmbt1731661943891.avif',
143
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20241115/fszxkdcjfjql2oiy90ffbal5tsfd81731661964913.avif',
144
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20241115/fs1jhd9jwxvfqmrbjwy5abfzb0fde1731661994996.avif'
145
+ ],
146
+ info: "Le sweatshirt à capuche bleu met à l'honneur l'emblématique motif dior oblique. Confectionné en jacquard de coton éponge bleu, il présente une coupe relax très confortable. Doté de poches latérales fendues, ce sweatshirt à capuche s'associera à tous vos jeans ou pantalons de survêtement pour un look décontracté.. Sweatshirt à capuche dior oblique, coupe relax Jacquard de coton éponge bleu",
147
+ price: 1800,
148
+ shippingInfo: null,
149
+ taxInfo: null
150
+ },
151
+ {
152
+ appId: null,
153
+ itemId: 'S5573CRIW_M928',
154
+ title: 'Mini Dior Book Tote',
155
+ enTitle: null,
156
+ icon: null,
157
+ cover: 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20250213/fsvewk9etrawxrzznmvvewgt1bctu1739415576729.avif',
158
+ link: 'https://www.dior.com/en_gb/fashion/products/S5573CRIW_M928',
159
+ linkTitle: null,
160
+ linkType: 'WEB',
161
+ menuCategoryId: null,
162
+ remark: null,
163
+ tags: ['ダイヤモンド'],
164
+ traceInfo: ':PRODUCT:S5573CRIW_M928:regular:1:VPRHSkRS1697701789894:main::0:EXPMW20250305155940:COMBTh20250305160047:',
165
+ value: null,
166
+ weight: null,
167
+ bindCta: null,
168
+ collection: null,
169
+ currency: 'GBP-£',
170
+ homePage: [
171
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20250213/fsvewk9etrawxrzznmvvewgt1bctu1739415576729.avif',
172
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20250213/fsngtlvhid7xwt5if0viw7vqanm831739415582147.avif',
173
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20250213/fs4hotdvyzjtnqb9vszlynuzplddc1739415586910.avif',
174
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20250213/fswffx9kwexf3z3vcnxisut1qxtez1739415591629.avif',
175
+ 'https://graff-cdn.chatlabs.net/dev/img/8922b5b8-a954-4a61-9ffc-80edebdf02b4/sxp-portal/20250213/fsbfsi7tttx1hnzldoiw7eoea7fvh1739415597388.avif'
176
+ ],
177
+ info: "The Dior Book Tote is a House classic and original design by Maria Grazia Chiuri, Creative Director of Christian Dior. The style is fully embroidered with the House's hallmark blue Dior Oblique motif and showcases the Christian Dior Paris signature. Exemplifying House savoir-faire, the miniature style features an adjustable and removable strap that allows it to be carried by hand, worn over the shoulder or crossbody.",
178
+ price: 1950,
179
+ shippingInfo: null,
180
+ taxInfo: null
181
+ }
182
+ ],
183
+ url: null,
184
+ blockCta: 1,
185
+ blockProduct: 1,
186
+ hashTags: [
187
+ 'Sports/Casual',
188
+ 'Formal Dinner/Party',
189
+ 'Business Formal',
190
+ 'Wedding/Engagement',
191
+ 'Gift-Giving',
192
+ 'Daily Wear',
193
+ 'Anniversary Gifts'
194
+ ]
195
+ }
196
+ };
18
197
  const DiyStoryPreview = ({ data = [], globalConfig, tipText, nudge, tempMap, descStyle, hashTagStyle, containerHeight = 664, containerWidth = 375, appDomain, tagList = [], scenes, onActiveChange, activeIndex, loopPlay = false }) => {
19
198
  const swiperRef = useRef(null);
20
199
  const height = useMemo(() => {
@@ -55,22 +234,52 @@ const DiyStoryPreview = ({ data = [], globalConfig, tipText, nudge, tempMap, des
55
234
  }, [globalConfig]);
56
235
  const CTA = (rec, index) => {
57
236
  if ((globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isShowCTA) === undefined || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isShowCTA)) {
237
+ console.log(globalConfig, rec, '111');
58
238
  return (React.createElement("div", { className: 'clc-sxp-bottom-card' },
59
239
  React.createElement(RenderCard, { rec: rec, index: index, tempMap: tempMap, resolver: RESOLVER })));
60
240
  }
61
241
  return null;
62
242
  };
63
243
  const renderBottom = (rec, index) => {
64
- var _a, _b, _c, _d, _e, _f, _g;
244
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
65
245
  if (rec === null || rec === void 0 ? void 0 : rec.video) {
246
+ let cta = null;
247
+ if ((_b = (_a = rec === null || rec === void 0 ? void 0 : rec.video) === null || _a === void 0 ? void 0 : _a.bindProducts) === null || _b === void 0 ? void 0 : _b.length) {
248
+ cta = '多商品CTA';
249
+ }
250
+ else if ((_c = rec === null || rec === void 0 ? void 0 : rec.video) === null || _c === void 0 ? void 0 : _c.bindProduct) {
251
+ cta = '商品CTA';
252
+ }
253
+ else {
254
+ cta = (_e = (_d = rec === null || rec === void 0 ? void 0 : rec.video) === null || _d === void 0 ? void 0 : _d.bindCta) === null || _e === void 0 ? void 0 : _e.itemId;
255
+ }
256
+ const value = tempMap === null || tempMap === void 0 ? void 0 : tempMap[cta];
66
257
  return (React.createElement(React.Fragment, null,
67
- ((_a = rec === null || rec === void 0 ? void 0 : rec.video) === null || _a === void 0 ? void 0 : _a.title) && React.createElement("div", { className: 'clc-sxp-bottom-shadow' }),
68
- React.createElement("div", { className: 'clc-sxp-bottom' },
69
- React.createElement(Nudge, { nudge: nudge }),
70
- CTA(rec, index),
258
+ ((_f = rec === null || rec === void 0 ? void 0 : rec.video) === null || _f === void 0 ? void 0 : _f.title) && (React.createElement("div", { style: {
259
+ background: 'repeating-linear-gradient(0deg, rgba(26, 26, 25, 0.7), hsla(0, 0%, 100%, 0))',
260
+ height: '130px',
261
+ position: 'absolute',
262
+ bottom: 0,
263
+ width: '100%',
264
+ willChange: 'transform',
265
+ zIndex: 2,
266
+ pointerEvents: 'none'
267
+ } })),
268
+ React.createElement("div", { style: {
269
+ marginBottom: `${(_g = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.bottomInfoDist) !== null && _g !== void 0 ? _g : 40}px`,
270
+ zIndex: 999,
271
+ position: 'absolute',
272
+ bottom: 0,
273
+ left: 0,
274
+ right: 0,
275
+ paddingTop: '20px'
276
+ } },
277
+ (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isShowCTA) === undefined || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isShowCTA) ? (React.createElement("div", { style: {} },
278
+ React.createElement(RenderCard, { rec: rec, index: index, tempMap: tempMap, resolver: RESOLVER, isActive: index === activeIndex, value: value }))) : null,
71
279
  React.createElement("div", null,
72
- React.createElement(ExpandableText, { className: 'clc-sxp-bottom-text', isPost: true, foldText: tipText === null || tipText === void 0 ? void 0 : tipText.foldText, unfoldText: tipText === null || tipText === void 0 ? void 0 : tipText.unfoldText, text: (_c = (_b = rec === null || rec === void 0 ? void 0 : rec.video) === null || _b === void 0 ? void 0 : _b.title) !== null && _c !== void 0 ? _c : '', style: Object.assign(Object.assign({}, descStyle), { textShadow: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isOpenTextShadow) ? '2px 2px 4px rgba(0, 0, 0, 0.5)' : 'none' }) })),
73
- React.createElement(Hashtag, { index: index, tags: (_e = (_d = rec === null || rec === void 0 ? void 0 : rec.video) === null || _d === void 0 ? void 0 : _d.hashTags) !== null && _e !== void 0 ? _e : [], itemId: (_f = rec === null || rec === void 0 ? void 0 : rec.video) === null || _f === void 0 ? void 0 : _f.itemId, itemType: ((_g = rec === null || rec === void 0 ? void 0 : rec.video) === null || _g === void 0 ? void 0 : _g.itemId) ? 'VIDEO' : null, rec: rec, hashTagStyle: hashTagStyle }))));
280
+ React.createElement(ExpandableText, { isPost: true, foldText: tipText === null || tipText === void 0 ? void 0 : tipText.foldText, unfoldText: tipText === null || tipText === void 0 ? void 0 : tipText.unfoldText, text: (_j = (_h = rec === null || rec === void 0 ? void 0 : rec.video) === null || _h === void 0 ? void 0 : _h.title) !== null && _j !== void 0 ? _j : '', style: Object.assign(Object.assign({}, descStyle), { textShadow: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isOpenTextShadow) ? '2px 2px 4px rgba(0, 0, 0, 0.5)' : 'none', padding: '0 20px', fontSize: '12px' }) }),
281
+ React.createElement(RenderCard, { rec: rec, index: index, tempMap: tempMap, resolver: RESOLVER, includesCtaType: ['AniLink'], isActive: index === activeIndex, value: value }))),
282
+ React.createElement(RenderCard, { rec: rec, index: index, tempMap: tempMap, resolver: RESOLVER, includesCtaType: ['AniLinkPopup'], isActive: index === activeIndex, value: value })));
74
283
  }
75
284
  return null;
76
285
  };
@@ -85,17 +294,66 @@ const DiyStoryPreview = ({ data = [], globalConfig, tipText, nudge, tempMap, des
85
294
  top += 40;
86
295
  }
87
296
  if (rec === null || rec === void 0 ? void 0 : rec.video) {
88
- return (React.createElement(LikeButton, { key: rec.position, activeIcon: (_b = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.likeIcon) !== null && _b !== void 0 ? _b : likeIcon, unActicveIcon: (_c = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.unlikeIcon) !== null && _c !== void 0 ? _c : unlikeIcon, position: index, active: rec.isCollected, recData: rec, className: 'clc-sxp-like-button', style: {
297
+ return (React.createElement(LikeButton, { key: rec.position, activeIcon: (_b = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.likeIcon) !== null && _b !== void 0 ? _b : likeIcon, unActicveIcon: (_c = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.unlikeIcon) !== null && _c !== void 0 ? _c : unlikeIcon, position: index, active: rec.isCollected, recData: rec, style: {
89
298
  top,
90
- right: (_d = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.likeIconX) !== null && _d !== void 0 ? _d : 0
299
+ right: (_d = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.likeIconX) !== null && _d !== void 0 ? _d : 0,
300
+ position: 'absolute',
301
+ zIndex: 999,
302
+ backgroundColor: 'transparent',
303
+ width: '50px',
304
+ height: '50px',
305
+ outline: 'none',
306
+ border: 'none',
307
+ boxSizing: 'content-box',
308
+ padding: 0,
309
+ transform: 'translate3d(0px, 0px, 0px)'
91
310
  } }));
92
311
  }
93
312
  return null;
94
313
  };
95
314
  const mutedIcon = useIconLink('/pb_static/5beaaa5ce7f3477b99db3838619cc471.png', appDomain);
96
315
  const unmutedIcon = useIconLink('/pb_static/fea8668a8a894e4aa3a86bcc775e895e.png', appDomain);
97
- const renderView = (rec, index) => {
98
- return (React.createElement(SwiperSlide, { key: index, virtualIndex: index, style: { overflow: 'hidden', position: 'relative' } }, renderContent(rec, index)));
316
+ const renderToggleButton = (visible) => {
317
+ var _a, _b, _c, _d;
318
+ if (!visible)
319
+ return;
320
+ let top = (_a = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconY) !== null && _a !== void 0 ? _a : 23;
321
+ if ((globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconYPosit) === 'top') {
322
+ top += 45;
323
+ }
324
+ return (((globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isShowMute) === undefined || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.isShowMute) === true) && (React.createElement(ToggleButton, { style: {
325
+ position: 'absolute',
326
+ visibility: 'visible',
327
+ zIndex: 999,
328
+ transform: 'translate3d(0px,0px,0px)',
329
+ [(_b = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconXPosit) !== null && _b !== void 0 ? _b : 'right']: (_c = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconX) !== null && _c !== void 0 ? _c : 0,
330
+ [(_d = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconYPosit) !== null && _d !== void 0 ? _d : 'bottom']: top,
331
+ backgroundColor: 'transparent',
332
+ width: '50px',
333
+ height: '50px',
334
+ outline: 'none',
335
+ border: 'none',
336
+ boxSizing: 'content-box',
337
+ padding: 0
338
+ }, defaultValue: true, activeIcon: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.unMuteIcon) ? globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.unMuteIcon : mutedIcon, unactiveIcon: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIcon) ? globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIcon : unmutedIcon })));
339
+ };
340
+ const renderView = (item, index) => {
341
+ var _a, _b, _c, _d;
342
+ const rec = cloneDeep(recData);
343
+ rec.video.bindProducts = item === null || item === void 0 ? void 0 : item.bindProducts;
344
+ return (React.createElement("div", { style: { position: 'relative' } },
345
+ React.createElement(SwiperSlide, { key: index, virtualIndex: index, style: { overflow: 'hidden', position: 'relative' } },
346
+ renderBottom(rec, index),
347
+ renderLikeButton(rec, index),
348
+ renderToggleButton(!(globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconFixed)),
349
+ React.createElement(ToggleButton, { style: {
350
+ position: 'absolute',
351
+ right: (_a = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconX) !== null && _a !== void 0 ? _a : 0,
352
+ visibility: ((_c = (_b = data === null || data === void 0 ? void 0 : data[index]) === null || _b === void 0 ? void 0 : _b.video) === null || _c === void 0 ? void 0 : _c.url) ? 'visible' : 'hidden',
353
+ bottom: (_d = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIconY) !== null && _d !== void 0 ? _d : 23,
354
+ zIndex: 999
355
+ }, defaultValue: true, activeIcon: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.unMuteIcon) ? globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.unMuteIcon : mutedIcon, unactiveIcon: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIcon) ? globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.muteIcon : unmutedIcon }),
356
+ renderContent(item, index))));
99
357
  };
100
358
  useEffect(() => {
101
359
  var _a, _b;
@@ -109,10 +367,11 @@ const DiyStoryPreview = ({ data = [], globalConfig, tipText, nudge, tempMap, des
109
367
  return;
110
368
  (_b = (_a = swiperRef === null || swiperRef === void 0 ? void 0 : swiperRef.current) === null || _a === void 0 ? void 0 : _a.swiper) === null || _b === void 0 ? void 0 : _b.slideTo(0);
111
369
  }, [loopPlay]);
112
- return (React.createElement(Swiper, { ref: swiperRef, allowTouchMove: false, onActiveIndexChange: (swiper) => {
113
- onActiveChange === null || onActiveChange === void 0 ? void 0 : onActiveChange(swiper.activeIndex);
114
- }, direction: 'vertical', style: { overflow: 'hidden', height: containerHeight } }, scenes === null || scenes === void 0 ? void 0 : scenes.map((rec, index) => {
115
- return renderView(rec, index);
116
- })));
370
+ return (React.createElement("div", { id: 'sxp-render', style: { height: containerHeight, position: 'relative', pointerEvents: 'none' } },
371
+ React.createElement(Swiper, { ref: swiperRef, allowTouchMove: false, onActiveIndexChange: (swiper) => {
372
+ onActiveChange === null || onActiveChange === void 0 ? void 0 : onActiveChange(swiper.activeIndex);
373
+ }, direction: 'vertical', style: { overflow: 'hidden', height: containerHeight }, height: containerHeight }, scenes === null || scenes === void 0 ? void 0 : scenes.map((rec, index) => {
374
+ return renderView(rec, index);
375
+ }))));
117
376
  };
118
377
  export default memo(DiyStoryPreview);
@@ -1,5 +1,5 @@
1
- import { setFontForText } from '../../../core/utils/tool';
2
1
  import React, { memo, useMemo, useState, useCallback, useRef, useEffect } from 'react';
2
+ import { setFontForText } from '../../../core/utils/tool';
3
3
  const limitTextLastWholeWord = (originalText = '', limit) => {
4
4
  const chineseRegex = /[\u4e00-\u9fa5]+/;
5
5
  if (chineseRegex.test(originalText)) {
@@ -50,7 +50,15 @@ const ExpandableText = ({ text, maxStr = 108, style, className, onClick, foldTex
50
50
  wordBreak: 'break-word'
51
51
  }, dangerouslySetInnerHTML: { __html: setFontForText(text === null || text === void 0 ? void 0 : text.replace(/\n/g, '</br>'), style) } }),
52
52
  React.createElement("div", { ref: multiRowCopy, dangerouslySetInnerHTML: { __html: setFontForText(text === null || text === void 0 ? void 0 : text.replace(/\n/g, '</br>'), style) } }),
53
- text && isPost && isShow && (React.createElement("button", { "aria-label": isShowMore ? unfoldText || 'show less' : foldText || 'show more', style: { textDecoration: 'underline', cursor: 'pointer' }, onClick: onClick !== null && onClick !== void 0 ? onClick : handleClick, dangerouslySetInnerHTML: {
53
+ text && isPost && isShow && (React.createElement("button", { "aria-label": isShowMore ? unfoldText || 'show less' : foldText || 'show more', style: {
54
+ textDecoration: 'underline',
55
+ cursor: 'pointer',
56
+ outline: 'none',
57
+ border: 'none',
58
+ boxSizing: 'content-box',
59
+ padding: 0,
60
+ background: 'transparent'
61
+ }, onClick: onClick !== null && onClick !== void 0 ? onClick : handleClick, dangerouslySetInnerHTML: {
54
62
  __html: setFontForText(isShowMore ? unfoldText || 'show less' : foldText || 'show more', style)
55
63
  } }))));
56
64
  };
@@ -1,8 +1,8 @@
1
1
  import React, { memo, useMemo } from 'react';
2
2
  import './index.less';
3
+ import { cloneDeep } from 'lodash';
3
4
  import withBindDataSource from '../../../core/hoc/withBindDataSource';
4
5
  import { useEditor } from '../../../core/hooks';
5
- import { cloneDeep } from 'lodash';
6
6
  const RenderCard = ({ rec, index, tempMap, resolver, includesCtaType, isActive, value }) => {
7
7
  const { schema } = useEditor();
8
8
  if (!(rec === null || rec === void 0 ? void 0 : rec.video))
@@ -26,10 +26,10 @@ const RenderCard = ({ rec, index, tempMap, resolver, includesCtaType, isActive,
26
26
  const Component = withBindDataSource(t);
27
27
  const defaulSetting = (_u = t === null || t === void 0 ? void 0 : t.extend) === null || _u === void 0 ? void 0 : _u.defaulSetting;
28
28
  const isExternalLink = ((_x = (_w = (_v = value === null || value === void 0 ? void 0 : value.item) === null || _v === void 0 ? void 0 : _v.event) === null || _w === void 0 ? void 0 : _w.onClick) === null || _x === void 0 ? void 0 : _x.linkType) === 'externalLink';
29
- let style = cloneDeep((_y = value === null || value === void 0 ? void 0 : value.item) === null || _y === void 0 ? void 0 : _y.style);
29
+ const style = cloneDeep((_y = value === null || value === void 0 ? void 0 : value.item) === null || _y === void 0 ? void 0 : _y.style);
30
30
  if (style.hasOwnProperty('backdropFilter')) {
31
- let sbf = style['backdropFilter'];
32
- style['backdropFilter'] = `blur(${sbf !== null && sbf !== void 0 ? sbf : 0}px)`;
31
+ const sbf = style.backdropFilter;
32
+ style.backdropFilter = `blur(${sbf !== null && sbf !== void 0 ? sbf : 0}px)`;
33
33
  }
34
34
  return (React.createElement(Component, Object.assign({ style: Object.assign(Object.assign(Object.assign({}, defaulSetting === null || defaulSetting === void 0 ? void 0 : defaulSetting.style), style), { zIndex: 50, marginLeft: '20px', boxSizing: 'border-box', transform: 'translate3d(0px, 0px, 0px)' }), textStyle: Object.assign(Object.assign({}, defaulSetting === null || defaulSetting === void 0 ? void 0 : defaulSetting.textStyle), (_z = value === null || value === void 0 ? void 0 : value.item) === null || _z === void 0 ? void 0 : _z.textStyle), bindDatas: (_1 = (_0 = value === null || value === void 0 ? void 0 : value.item) === null || _0 === void 0 ? void 0 : _0.bindDatas) !== null && _1 !== void 0 ? _1 : [] }, defaulSetting === null || defaulSetting === void 0 ? void 0 : defaulSetting.props, (_2 = value === null || value === void 0 ? void 0 : value.item) === null || _2 === void 0 ? void 0 : _2.props, { event: ((_3 = value === null || value === void 0 ? void 0 : value.item) === null || _3 === void 0 ? void 0 : _3.event) || {}, schema: schema, id: value === null || value === void 0 ? void 0 : value.id, key: value === null || value === void 0 ? void 0 : value.id, recData: rec, isExternalLink: isExternalLink, index: index, isActive: isActive })));
35
35
  }
@@ -4,10 +4,10 @@ import React, { memo, useState } from 'react';
4
4
  import { SwiperSlide } from 'swiper/react';
5
5
  import Img from '../components/Img';
6
6
  import Scroll from '../components/Scroll';
7
+ import EventProvider from '../components/EventProvider';
7
8
  import styles from './index.module.less';
8
9
  import { useSxpDataSource } from '../../../../core/hooks';
9
10
  import { setFontForText } from '../../../../core/utils/tool';
10
- import EventProvider from '../components/EventProvider';
11
11
  const MultiCommodity = (_a) => {
12
12
  var _b, _c;
13
13
  var { content, style, bgImg, recData, bottom_image, ctaTempStyles, translateY = 0, isActive, index } = _a, props = __rest(_a, ["content", "style", "bgImg", "recData", "bottom_image", "ctaTempStyles", "translateY", "isActive", "index"]);
@@ -4,15 +4,16 @@ import React, { memo, useState } from 'react';
4
4
  import { SwiperSlide } from 'swiper/react';
5
5
  import Scroll from '../components/Scroll';
6
6
  import Img from '../components/Img';
7
+ import EventProvider from '../components/EventProvider';
7
8
  import styles from './index.module.less';
8
9
  import { useSxpDataSource } from '../../../../core/hooks';
9
10
  import { setFontForText } from '../../../../core/utils/tool';
10
- import EventProvider from '../components/EventProvider';
11
11
  const MultiCommodityDiro = (_a) => {
12
12
  var _b, _c;
13
13
  var { content, style, bgImg, recData, bottom_image, ctaTempStyles, translateY = 0, isActive, index } = _a, props = __rest(_a, ["content", "style", "bgImg", "recData", "bottom_image", "ctaTempStyles", "translateY", "isActive", "index"]);
14
14
  const { sxpParameter } = useSxpDataSource();
15
15
  const [products] = useState((_c = (_b = recData === null || recData === void 0 ? void 0 : recData.video) === null || _b === void 0 ? void 0 : _b.bindProducts) !== null && _c !== void 0 ? _c : [1, 2]);
16
+ console.log(recData, '222');
16
17
  return (React.createElement(Scroll, { isPadding: !!recData }, products === null || products === void 0 ? void 0 : products.map((item, itemIndex) => {
17
18
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
18
19
  return (React.createElement(React.Fragment, null, recData && !(item === null || item === void 0 ? void 0 : item.bindCta) ? null : (React.createElement(SwiperSlide, { key: itemIndex, className: css(Object.assign(Object.assign({}, style), { flexShrink: 0, marginLeft: 0, marginRight: '8px' })), tag: 'li', role: 'listitem' },
@@ -4,15 +4,16 @@ import React, { memo, useState } from 'react';
4
4
  import { SwiperSlide } from 'swiper/react';
5
5
  import Scroll from '../components/Scroll';
6
6
  import Img from '../components/Img';
7
+ import EventProvider from '../components/EventProvider';
7
8
  import styles from './index.module.less';
8
9
  import { useSxpDataSource } from '../../../../core/hooks';
9
10
  import { setFontForText } from '../../../../core/utils/tool';
10
- import EventProvider from '../components/EventProvider';
11
11
  const MultiCommodityDiroNew = (_a) => {
12
12
  var _b, _c;
13
13
  var { content, style, bgImg, recData, bottom_image, ctaTempStyles, translateY = 0, isActive, index } = _a, props = __rest(_a, ["content", "style", "bgImg", "recData", "bottom_image", "ctaTempStyles", "translateY", "isActive", "index"]);
14
14
  const { sxpParameter } = useSxpDataSource();
15
15
  const [products] = useState((_c = (_b = recData === null || recData === void 0 ? void 0 : recData.video) === null || _b === void 0 ? void 0 : _b.bindProducts) !== null && _c !== void 0 ? _c : [1, 2]);
16
+ console.log(recData, '333');
16
17
  return (React.createElement(Scroll, { isPadding: !!recData }, products === null || products === void 0 ? void 0 : products.map((item, itemIndex) => {
17
18
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
18
19
  return (React.createElement(React.Fragment, null, recData && !(item === null || item === void 0 ? void 0 : item.bindCta) ? null : (React.createElement(SwiperSlide, { key: itemIndex, className: css(Object.assign(Object.assign({}, style), { flexShrink: 0, marginLeft: 0, marginRight: '8px' })), tag: 'li', role: 'listitem' },
@@ -13,7 +13,7 @@ const EventProvider = (_a) => {
13
13
  const handleClick = throttle((e) => {
14
14
  var _a, _b, _c, _d, _e, _f;
15
15
  e.preventDefault();
16
- const item = multItem ? multItem : (_b = (_a = rec === null || rec === void 0 ? void 0 : rec.video) === null || _a === void 0 ? void 0 : _a.bindProduct) !== null && _b !== void 0 ? _b : rec === null || rec === void 0 ? void 0 : rec.video;
16
+ const item = multItem || ((_b = (_a = rec === null || rec === void 0 ? void 0 : rec.video) === null || _a === void 0 ? void 0 : _a.bindProduct) !== null && _b !== void 0 ? _b : rec === null || rec === void 0 ? void 0 : rec.video);
17
17
  ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
18
18
  eventSubject: 'clickCta',
19
19
  eventDescription: 'User clicked the CTA'
@@ -40,6 +40,6 @@ const EventProvider = (_a) => {
40
40
  setElement(null);
41
41
  }
42
42
  }, [element, popup]);
43
- return (React.createElement("button", { ref: ref, className: className, style: Object.assign({ display: 'flex', alignItems: 'normal' }, style), onClick: handleClick, role: 'button', "aria-label": 'CTA', tabIndex: 0 }, children));
43
+ return (React.createElement("button", { ref: ref, className: className, style: Object.assign({ outline: 'none', border: 'none', boxSizing: 'content-box', padding: 0, background: 'transparent', display: 'flex', alignItems: 'normal' }, style), onClick: handleClick, role: 'button', "aria-label": 'CTA', tabIndex: 0 }, children));
44
44
  };
45
45
  export default memo(EventProvider);
@@ -42,6 +42,7 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
42
42
  }, [bffEventReport, data, index, isFirstPlay]);
43
43
  const handleLoadedMetadata = (0, react_1.useCallback)(() => {
44
44
  var _a;
45
+ videoRef.current.currentTime = rec === null || rec === void 0 ? void 0 : rec.startTime;
45
46
  (_a = videoRef === null || videoRef === void 0 ? void 0 : videoRef.current) === null || _a === void 0 ? void 0 : _a.play();
46
47
  setIsLoadFinish(true);
47
48
  }, []);
@@ -115,6 +116,8 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
115
116
  }, []);
116
117
  const handlePause = () => {
117
118
  var _a, _b, _c, _d, _e, _f;
119
+ if (!videoRef.current || !isActive)
120
+ return;
118
121
  if (!loopPlay)
119
122
  return;
120
123
  if (index === (data === null || data === void 0 ? void 0 : data.length) - 1) {
@@ -137,7 +140,6 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
137
140
  if (!videoPlayerWrapperNode)
138
141
  return;
139
142
  videoRef.current = VideoPlayer_1.mountVideoPlayerAtNode === null || VideoPlayer_1.mountVideoPlayerAtNode === void 0 ? void 0 : (0, VideoPlayer_1.mountVideoPlayerAtNode)(videoPlayerWrapperNode);
140
- videoRef.current.currentTime = rec === null || rec === void 0 ? void 0 : rec.startTime;
141
143
  if (!(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current))
142
144
  return;
143
145
  const Hls = window === null || window === void 0 ? void 0 : window.Hls;
@@ -148,6 +150,7 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
148
150
  hls === null || hls === void 0 ? void 0 : hls.attachMedia(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current);
149
151
  hls === null || hls === void 0 ? void 0 : hls.on(Hls.Events.MANIFEST_PARSED, function () {
150
152
  var _a;
153
+ videoRef.current.currentTime = rec === null || rec === void 0 ? void 0 : rec.startTime;
151
154
  (_a = videoRef === null || videoRef === void 0 ? void 0 : videoRef.current) === null || _a === void 0 ? void 0 : _a.play();
152
155
  });
153
156
  }
@@ -166,7 +169,7 @@ const VideoWidget = ({ rec, index, height, data, muted, activeIndex, videoPostCo
166
169
  (_c = videoRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener('pause', handlePause);
167
170
  (_d = videoRef.current) === null || _d === void 0 ? void 0 : _d.removeEventListener('timeupdate', handleTimeUpload);
168
171
  };
169
- }, [handleLoadedMetadata, handlePlaying, rec, handLoadeddata, isActive]);
172
+ }, [handleLoadedMetadata, handlePlaying, rec, handLoadeddata, isActive, loopPlay]);
170
173
  const renderPoster = (0, react_1.useMemo)(() => {
171
174
  if (!(sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.placeholder_image) || isLoadFinish) {
172
175
  return null;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ISxpPageRenderProps } from '../SxpPageRender';
3
+ import '../SxpPageRender/index.less';
3
4
  export interface IScene {
4
5
  blueprintStep: number;
5
6
  endTime: number;
@@ -13,6 +14,7 @@ export interface IScene {
13
14
  sceneTag: string;
14
15
  startTime: number;
15
16
  traceInfo: string;
17
+ bindProducts?: any[];
16
18
  }
17
19
  export type ScenesType = IScene[];
18
20
  export type DiyStoryPreviewType = ISxpPageRenderProps & {