@cntrl-site/sdk-nextjs 1.8.30-alpha.1 → 1.8.30
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/cntrl-site-sdk-nextjs-1.8.28.tgz +0 -0
- package/lib/components/items/CodeEmbedItem/CodeEmbedItem.js +5 -11
- package/lib/components/items/EmbedVideoItem/VimeoEmbed.js +18 -14
- package/lib/components/items/EmbedVideoItem/YoutubeEmbed.js +11 -7
- package/lib/components/items/FileItem/VideoItem.js +82 -8
- package/package.json +2 -2
- package/src/components/items/CodeEmbedItem/CodeEmbedItem.tsx +4 -10
- package/src/components/items/EmbedVideoItem/VimeoEmbed.tsx +19 -17
- package/src/components/items/EmbedVideoItem/YoutubeEmbed.tsx +18 -14
- package/src/components/items/FileItem/VideoItem.tsx +127 -39
|
Binary file
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.CodeEmbedItem = void 0;
|
|
7
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
8
|
const sdk_1 = require("@cntrl-site/sdk");
|
|
9
9
|
const react_1 = require("react");
|
|
@@ -33,7 +33,7 @@ const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilit
|
|
|
33
33
|
const fontCustomTags = new sdk_1.FontFaceGenerator((_a = fonts === null || fonts === void 0 ? void 0 : fonts.custom) !== null && _a !== void 0 ? _a : []).generate();
|
|
34
34
|
const { anchor, blur: itemBlur, opacity: itemOpacity } = (0, useCodeEmbedItem_1.useCodeEmbedItem)(item, sectionId);
|
|
35
35
|
const itemAngle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
|
|
36
|
-
const html =
|
|
36
|
+
const { html } = item.commonParams;
|
|
37
37
|
const [ref, setRef] = (0, react_1.useState)(null);
|
|
38
38
|
(0, useRegisterResize_1.useRegisterResize)(ref, onResize);
|
|
39
39
|
const pos = stylesMap[anchor];
|
|
@@ -55,7 +55,7 @@ const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilit
|
|
|
55
55
|
script.parentNode.removeChild(script);
|
|
56
56
|
ref.appendChild(newScript);
|
|
57
57
|
}
|
|
58
|
-
}, [html]);
|
|
58
|
+
}, [item.commonParams.html]);
|
|
59
59
|
(0, react_1.useEffect)(() => {
|
|
60
60
|
if (!ref)
|
|
61
61
|
return;
|
|
@@ -73,10 +73,10 @@ const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilit
|
|
|
73
73
|
padding: 0 !important;
|
|
74
74
|
}
|
|
75
75
|
</style>
|
|
76
|
-
${html}
|
|
76
|
+
${item.commonParams.html}
|
|
77
77
|
`;
|
|
78
78
|
iframe.srcdoc = htmlWithStyles;
|
|
79
|
-
}, [html, item.commonParams.iframe, ref]);
|
|
79
|
+
}, [item.commonParams.html, item.commonParams.iframe, ref]);
|
|
80
80
|
const isInteractive = opacity !== 0;
|
|
81
81
|
(0, react_1.useEffect)(() => {
|
|
82
82
|
onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(isInteractive);
|
|
@@ -109,9 +109,3 @@ const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilit
|
|
|
109
109
|
` })] }));
|
|
110
110
|
};
|
|
111
111
|
exports.CodeEmbedItem = CodeEmbedItem;
|
|
112
|
-
function decodeBase64(str) {
|
|
113
|
-
const binary = atob(str);
|
|
114
|
-
const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
|
|
115
|
-
return new TextDecoder().decode(bytes);
|
|
116
|
-
}
|
|
117
|
-
exports.decodeBase64 = decodeBase64;
|
|
@@ -24,15 +24,18 @@ const useRegisterResize_1 = require("../../../common/useRegisterResize");
|
|
|
24
24
|
const getStyleFromItemStateAndParams_1 = require("../../../utils/getStyleFromItemStateAndParams");
|
|
25
25
|
const useEmbedVideoItem_1 = require("./useEmbedVideoItem");
|
|
26
26
|
const LinkWrapper_1 = require("../LinkWrapper");
|
|
27
|
+
const useLayoutContext_1 = require("../../useLayoutContext");
|
|
27
28
|
const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
28
29
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
29
30
|
const id = (0, react_1.useId)();
|
|
30
31
|
const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
|
|
31
32
|
const { radius: itemRadius, blur: itemBlur, opacity: itemOpacity } = (0, useEmbedVideoItem_1.useEmbedVideoItem)(item, sectionId);
|
|
33
|
+
const layoutId = (0, useLayoutContext_1.useLayoutContext)();
|
|
32
34
|
const [iframeRef, setIframeRef] = (0, react_1.useState)(null);
|
|
33
35
|
const vimeoPlayer = (0, react_1.useMemo)(() => iframeRef ? new player_1.default(iframeRef) : undefined, [iframeRef]);
|
|
34
36
|
const itemAngle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
|
|
35
|
-
const {
|
|
37
|
+
const { url } = item.commonParams;
|
|
38
|
+
const layoutParams = layoutId ? item.layoutParams[layoutId] : null;
|
|
36
39
|
const [ref, setRef] = (0, react_1.useState)(null);
|
|
37
40
|
const [imgRef, setImgRef] = (0, react_1.useState)(null);
|
|
38
41
|
const [isCoverVisible, setIsCoverVisible] = (0, react_1.useState)(false);
|
|
@@ -44,24 +47,25 @@ const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibili
|
|
|
44
47
|
const opacity = (0, getStyleFromItemStateAndParams_1.getStyleFromItemStateAndParams)((_c = wrapperStateParams === null || wrapperStateParams === void 0 ? void 0 : wrapperStateParams.styles) === null || _c === void 0 ? void 0 : _c.opacity, itemOpacity);
|
|
45
48
|
const radius = (0, getStyleFromItemStateAndParams_1.getStyleFromItemStateAndParams)((_d = frameStateParams === null || frameStateParams === void 0 ? void 0 : frameStateParams.styles) === null || _d === void 0 ? void 0 : _d.radius, itemRadius);
|
|
46
49
|
(0, useRegisterResize_1.useRegisterResize)(ref, onResize);
|
|
47
|
-
const
|
|
50
|
+
const validUrl = (0, react_1.useMemo)(() => {
|
|
51
|
+
if (!layoutParams)
|
|
52
|
+
return url;
|
|
48
53
|
const validURL = new URL(url);
|
|
49
|
-
validURL.searchParams.append('controls', String(controls));
|
|
50
|
-
validURL.searchParams.append('autoplay', String(play === 'auto'));
|
|
51
|
-
validURL.searchParams.append('muted', String(muted));
|
|
52
|
-
validURL.searchParams.append('loop', String(loop));
|
|
53
|
-
validURL.searchParams.append('pip', String(pictureInPicture));
|
|
54
|
+
validURL.searchParams.append('controls', String(layoutParams.controls));
|
|
55
|
+
validURL.searchParams.append('autoplay', String(layoutParams.play === 'auto'));
|
|
56
|
+
validURL.searchParams.append('muted', String(layoutParams.muted));
|
|
57
|
+
validURL.searchParams.append('loop', String(layoutParams.loop));
|
|
58
|
+
validURL.searchParams.append('pip', String(layoutParams.pictureInPicture));
|
|
54
59
|
validURL.searchParams.append('title', '0');
|
|
55
60
|
validURL.searchParams.append('byline', '0');
|
|
56
61
|
validURL.searchParams.append('portrait', '0');
|
|
57
62
|
validURL.searchParams.append('autopause', 'false');
|
|
58
63
|
return validURL.href;
|
|
59
|
-
};
|
|
60
|
-
const validUrl = getValidVimeoUrl(url);
|
|
64
|
+
}, [url, layoutParams]);
|
|
61
65
|
(0, react_1.useEffect)(() => {
|
|
62
|
-
if (!vimeoPlayer || !imgRef)
|
|
66
|
+
if (!vimeoPlayer || !imgRef || !layoutParams)
|
|
63
67
|
return;
|
|
64
|
-
if (play === 'on-click') {
|
|
68
|
+
if (layoutParams.play === 'on-click') {
|
|
65
69
|
setIsCoverVisible(true);
|
|
66
70
|
}
|
|
67
71
|
vimeoPlayer.on('pause', (e) => {
|
|
@@ -113,11 +117,11 @@ const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibili
|
|
|
113
117
|
});
|
|
114
118
|
}, [interactionCtrl, vimeoPlayer]);
|
|
115
119
|
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (_e = item.link) === null || _e === void 0 ? void 0 : _e.url, target: (_f = item.link) === null || _f === void 0 ? void 0 : _f.target, children: [(0, jsx_runtime_1.jsxs)("div", { className: `embed-video-wrapper-${item.id}`, ref: setRef, style: Object.assign(Object.assign(Object.assign(Object.assign({}, (opacity !== undefined ? { opacity } : {})), (angle !== undefined ? { transform: `rotate(${angle}deg) translateZ(0)` } : {})), (blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {})), { transition: (_g = wrapperStateParams === null || wrapperStateParams === void 0 ? void 0 : wrapperStateParams.transition) !== null && _g !== void 0 ? _g : 'none' }), onMouseEnter: () => {
|
|
116
|
-
if (!vimeoPlayer || play !== 'on-hover')
|
|
120
|
+
if (!vimeoPlayer || !layoutParams || layoutParams.play !== 'on-hover')
|
|
117
121
|
return;
|
|
118
122
|
vimeoPlayer.play();
|
|
119
123
|
}, onMouseLeave: () => {
|
|
120
|
-
if (!vimeoPlayer || play !== 'on-hover')
|
|
124
|
+
if (!vimeoPlayer || !layoutParams || layoutParams.play !== 'on-hover')
|
|
121
125
|
return;
|
|
122
126
|
vimeoPlayer.pause();
|
|
123
127
|
}, children: [item.commonParams.coverUrl && ((0, jsx_runtime_1.jsx)("img", { ref: setImgRef, onClick: () => onCoverClick(), src: (_h = item.commonParams.coverUrl) !== null && _h !== void 0 ? _h : '', style: {
|
|
@@ -129,7 +133,7 @@ const VimeoEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibili
|
|
|
129
133
|
width: '100%',
|
|
130
134
|
top: '0',
|
|
131
135
|
left: '0'
|
|
132
|
-
}, alt: "Cover img" })), (!
|
|
136
|
+
}, alt: "Cover img" })), layoutParams && (!layoutParams.controls && (layoutParams.play === 'on-click' || layoutParams.play === 'auto')) && ((0, jsx_runtime_1.jsx)("div", { onClick: handleClick, style: {
|
|
133
137
|
position: 'absolute',
|
|
134
138
|
height: '100%',
|
|
135
139
|
width: '100%',
|
|
@@ -16,11 +16,14 @@ const useCntrlContext_1 = require("../../../provider/useCntrlContext");
|
|
|
16
16
|
const useYouTubeIframeApi_1 = require("../../../utils/Youtube/useYouTubeIframeApi");
|
|
17
17
|
const useRegisterResize_1 = require("../../../common/useRegisterResize");
|
|
18
18
|
const getStyleFromItemStateAndParams_1 = require("../../../utils/getStyleFromItemStateAndParams");
|
|
19
|
+
const useLayoutContext_1 = require("../../useLayoutContext");
|
|
19
20
|
const YoutubeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
20
21
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
21
22
|
const id = (0, react_1.useId)();
|
|
22
23
|
const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
|
|
23
|
-
const {
|
|
24
|
+
const { url } = item.commonParams;
|
|
25
|
+
const layoutId = (0, useLayoutContext_1.useLayoutContext)();
|
|
26
|
+
const layoutParams = layoutId ? item.layoutParams[layoutId] : null;
|
|
24
27
|
const { radius: itemRadius, blur: itemBlur, opacity: itemOpacity } = (0, useEmbedVideoItem_1.useEmbedVideoItem)(item, sectionId);
|
|
25
28
|
const itemAngle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
|
|
26
29
|
const YT = (0, useYouTubeIframeApi_1.useYouTubeIframeApi)();
|
|
@@ -43,8 +46,9 @@ const YoutubeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibi
|
|
|
43
46
|
(0, react_1.useEffect)(() => {
|
|
44
47
|
const newUrl = new URL(url);
|
|
45
48
|
const videoId = (0, getValidYoutubeUrl_1.getYoutubeId)(newUrl);
|
|
46
|
-
if (!YT || !videoId || !div)
|
|
49
|
+
if (!YT || !videoId || !div || !layoutParams)
|
|
47
50
|
return;
|
|
51
|
+
const { play, controls } = layoutParams;
|
|
48
52
|
const placeholder = document.createElement('div');
|
|
49
53
|
div.appendChild(placeholder);
|
|
50
54
|
const player = new YT.Player(placeholder, {
|
|
@@ -78,7 +82,7 @@ const YoutubeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibi
|
|
|
78
82
|
player.destroy();
|
|
79
83
|
(_a = placeholder.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(placeholder);
|
|
80
84
|
};
|
|
81
|
-
}, [YT, div]);
|
|
85
|
+
}, [YT, div, layoutParams]);
|
|
82
86
|
const onCoverClick = () => {
|
|
83
87
|
if (!player || !imgRef)
|
|
84
88
|
return;
|
|
@@ -86,10 +90,10 @@ const YoutubeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibi
|
|
|
86
90
|
setIsCoverVisible(false);
|
|
87
91
|
};
|
|
88
92
|
(0, react_1.useEffect)(() => {
|
|
89
|
-
if (play === 'on-click' && !controls) {
|
|
93
|
+
if (layoutParams && layoutParams.play === 'on-click' && !layoutParams.controls) {
|
|
90
94
|
setIsCoverVisible(true);
|
|
91
95
|
}
|
|
92
|
-
}, []);
|
|
96
|
+
}, [layoutParams]);
|
|
93
97
|
(0, react_1.useEffect)(() => {
|
|
94
98
|
onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(isInteractive);
|
|
95
99
|
if (!isInteractive && player) {
|
|
@@ -111,11 +115,11 @@ const YoutubeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibi
|
|
|
111
115
|
});
|
|
112
116
|
}, [interactionCtrl, player]);
|
|
113
117
|
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (_e = item.link) === null || _e === void 0 ? void 0 : _e.url, target: (_f = item.link) === null || _f === void 0 ? void 0 : _f.target, children: [(0, jsx_runtime_1.jsxs)("div", { className: `embed-youtube-video-wrapper-${item.id}`, onMouseEnter: () => {
|
|
114
|
-
if (!player || play !== 'on-hover')
|
|
118
|
+
if (!player || !layoutParams || layoutParams.play !== 'on-hover')
|
|
115
119
|
return;
|
|
116
120
|
player.playVideo();
|
|
117
121
|
}, onMouseLeave: () => {
|
|
118
|
-
if (!player || play !== 'on-hover')
|
|
122
|
+
if (!player || !layoutParams || layoutParams.play !== 'on-hover')
|
|
119
123
|
return;
|
|
120
124
|
player.pauseVideo();
|
|
121
125
|
}, style: Object.assign(Object.assign(Object.assign(Object.assign({}, (opacity !== undefined ? { opacity } : {})), (angle !== undefined ? { transform: `rotate(${angle}deg) translateZ(0)` } : {})), (blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {})), { transition: (_g = wrapperStateParams === null || wrapperStateParams === void 0 ? void 0 : wrapperStateParams.transition) !== null && _g !== void 0 ? _g : 'none' }), children: [item.commonParams.coverUrl && ((0, jsx_runtime_1.jsx)("img", { ref: setImgRef, onClick: () => onCoverClick(), src: (_h = item.commonParams.coverUrl) !== null && _h !== void 0 ? _h : '', style: {
|
|
@@ -21,18 +21,23 @@ const useVideoFx_1 = require("../../../utils/effects/useVideoFx");
|
|
|
21
21
|
const useElementRect_1 = require("../../../utils/useElementRect");
|
|
22
22
|
const useItemFXData_1 = require("../../../common/useItemFXData");
|
|
23
23
|
const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
24
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
24
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
25
25
|
const id = (0, react_1.useId)();
|
|
26
26
|
const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
|
|
27
27
|
const layoutId = (0, useLayoutContext_1.useLayoutContext)();
|
|
28
28
|
const { radius: itemRadius, strokeWidth: itemStrokeWidth, strokeColor: itemStrokeColor, opacity: itemOpacity, blur: itemBlur } = (0, useFileItem_1.useFileItem)(item, sectionId);
|
|
29
|
+
const [isVideoPlaying, setIsVideoPlaying] = (0, react_1.useState)(false);
|
|
30
|
+
const isScrollPausedRef = (0, react_1.useRef)(false);
|
|
31
|
+
const [userPaused, setUserPaused] = (0, react_1.useState)(false);
|
|
32
|
+
const [isVideoInteracted, setIsVideoInteracted] = (0, react_1.useState)(false);
|
|
29
33
|
const itemAngle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
|
|
30
34
|
const [ref, setRef] = (0, react_1.useState)(null);
|
|
31
|
-
const videoRef = (0, react_1.
|
|
35
|
+
const [videoRef, setVideoRef] = (0, react_1.useState)(null);
|
|
32
36
|
const fxCanvas = (0, react_1.useRef)(null);
|
|
33
37
|
const { url, hasGLEffect } = item.commonParams;
|
|
34
38
|
const isInitialRef = (0, react_1.useRef)(true);
|
|
35
39
|
const area = layoutId ? item.area[layoutId] : null;
|
|
40
|
+
const layoutParams = layoutId ? item.layoutParams[layoutId] : null;
|
|
36
41
|
const exemplary = (_a = layouts === null || layouts === void 0 ? void 0 : layouts.find(l => l.id === layoutId)) === null || _a === void 0 ? void 0 : _a.exemplary;
|
|
37
42
|
const width = area && exemplary ? area.width * exemplary : 0;
|
|
38
43
|
const height = area && exemplary ? area.height * exemplary : 0;
|
|
@@ -40,7 +45,7 @@ const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityCha
|
|
|
40
45
|
const rect = (0, useElementRect_1.useElementRect)(ref);
|
|
41
46
|
const rectWidth = Math.floor((_b = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _b !== void 0 ? _b : 0);
|
|
42
47
|
const rectHeight = Math.floor((_c = rect === null || rect === void 0 ? void 0 : rect.height) !== null && _c !== void 0 ? _c : 0);
|
|
43
|
-
const scrollPlayback =
|
|
48
|
+
const scrollPlayback = layoutParams ? layoutParams.scrollPlayback : null;
|
|
44
49
|
const layoutValues = [item.area, item.layoutParams];
|
|
45
50
|
const hasScrollPlayback = scrollPlayback !== null;
|
|
46
51
|
const wrapperStateParams = interactionCtrl === null || interactionCtrl === void 0 ? void 0 : interactionCtrl.getState(['angle', 'opacity', 'blur']);
|
|
@@ -69,11 +74,63 @@ const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityCha
|
|
|
69
74
|
(0, react_1.useEffect)(() => {
|
|
70
75
|
onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(isInteractive);
|
|
71
76
|
}, [isInteractive, onVisibilityChange]);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
(0, react_1.useEffect)(() => {
|
|
78
|
+
if (!layoutParams || !videoRef || layoutParams.play !== 'on-click' || !ref)
|
|
79
|
+
return;
|
|
80
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
81
|
+
if (userPaused || !isVideoInteracted)
|
|
82
|
+
return;
|
|
83
|
+
if (entry.isIntersecting) {
|
|
84
|
+
isScrollPausedRef.current = false;
|
|
85
|
+
videoRef.play();
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
isScrollPausedRef.current = true;
|
|
89
|
+
videoRef.pause();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
observer.observe(ref);
|
|
93
|
+
return () => observer.disconnect();
|
|
94
|
+
}, [layoutParams, videoRef, ref, userPaused, isVideoInteracted]);
|
|
95
|
+
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (_l = item.link) === null || _l === void 0 ? void 0 : _l.url, target: (_m = item.link) === null || _m === void 0 ? void 0 : _m.target, children: [(0, jsx_runtime_1.jsxs)("div", { className: `video-wrapper-${item.id}`, ref: setRef, style: Object.assign(Object.assign(Object.assign(Object.assign({}, (opacity !== undefined ? { opacity } : {})), (angle !== undefined ? { transform: `rotate(${angle}deg) translateZ(0)` } : {})), (blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {})), { transition: (_o = wrapperStateParams === null || wrapperStateParams === void 0 ? void 0 : wrapperStateParams.transition) !== null && _o !== void 0 ? _o : 'none' }), children: [hasScrollPlayback && ((0, jsx_runtime_1.jsx)(ScrollPlaybackVideo_1.ScrollPlaybackVideo, { sectionId: sectionId, src: item.commonParams.url, playbackParams: scrollPlayback, style: inlineStyles, className: `video video-playback-wrapper video-${item.id}` })), hasGLEffect && isFXAllowed && ((0, jsx_runtime_1.jsx)("canvas", { style: inlineStyles, ref: fxCanvas, className: `video-canvas video-${item.id}`, width: rectWidth, height: rectHeight })), !hasScrollPlayback && !hasGLEffect && layoutParams && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("video", { poster: (_p = item.commonParams.coverUrl) !== null && _p !== void 0 ? _p : '', ref: setVideoRef, autoPlay: layoutParams.play === 'auto', preload: "auto", onClick: () => {
|
|
96
|
+
setIsVideoInteracted(true);
|
|
97
|
+
}, muted: layoutParams.muted, onPlay: () => {
|
|
98
|
+
setIsVideoPlaying(true);
|
|
99
|
+
setUserPaused(false);
|
|
100
|
+
}, onPause: () => {
|
|
101
|
+
if (!isScrollPausedRef.current) {
|
|
102
|
+
setUserPaused(true);
|
|
103
|
+
}
|
|
104
|
+
setIsVideoPlaying(false);
|
|
105
|
+
}, onMouseEnter: () => {
|
|
106
|
+
if (!videoRef || layoutParams.play !== 'on-hover')
|
|
107
|
+
return;
|
|
108
|
+
videoRef.play();
|
|
109
|
+
}, onMouseLeave: () => {
|
|
110
|
+
if (!videoRef || layoutParams.play !== 'on-hover')
|
|
111
|
+
return;
|
|
112
|
+
videoRef.pause();
|
|
113
|
+
}, loop: true, controls: layoutParams.controls, playsInline: true, className: `video video-${item.id}`, style: inlineStyles, children: (0, jsx_runtime_1.jsx)("source", { src: item.commonParams.url }) }), (layoutParams.play === 'on-click' || layoutParams.play === 'on-hover') && item.commonParams.coverUrl && !isVideoInteracted && ((0, jsx_runtime_1.jsx)("img", { onMouseEnter: () => {
|
|
114
|
+
if (!videoRef || layoutParams.play !== 'on-hover')
|
|
115
|
+
return;
|
|
116
|
+
setIsVideoInteracted(true);
|
|
117
|
+
videoRef.play();
|
|
118
|
+
}, src: (_q = item.commonParams.coverUrl) !== null && _q !== void 0 ? _q : '', className: `video-cover-${item.id}`, onClick: () => {
|
|
119
|
+
if (!videoRef)
|
|
120
|
+
return;
|
|
121
|
+
setIsVideoInteracted(true);
|
|
122
|
+
videoRef.play();
|
|
123
|
+
} })), (layoutParams.play === 'on-click' && !layoutParams.controls && ((0, jsx_runtime_1.jsx)("div", { className: `video-overlay-${item.id}`, onClick: () => {
|
|
124
|
+
if (!videoRef)
|
|
125
|
+
return;
|
|
126
|
+
setIsVideoInteracted(true);
|
|
127
|
+
if (isVideoPlaying) {
|
|
128
|
+
videoRef.pause();
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
videoRef.play();
|
|
132
|
+
}
|
|
133
|
+
} })))] }))] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
|
|
77
134
|
.video-wrapper-${item.id} {
|
|
78
135
|
position: absolute;
|
|
79
136
|
overflow: hidden;
|
|
@@ -82,6 +139,23 @@ const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityCha
|
|
|
82
139
|
box-sizing: border-box;
|
|
83
140
|
opacity: ${opacity};
|
|
84
141
|
}
|
|
142
|
+
.video-overlay-${item.id} {
|
|
143
|
+
position: absolute;
|
|
144
|
+
top: 0;
|
|
145
|
+
left: 0;
|
|
146
|
+
cursor: pointer;
|
|
147
|
+
width: 100%;
|
|
148
|
+
height: 100%;
|
|
149
|
+
}
|
|
150
|
+
.video-cover-${item.id} {
|
|
151
|
+
position: absolute;
|
|
152
|
+
top: 0;
|
|
153
|
+
left: 0;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
width: 100%;
|
|
156
|
+
height: 100%;
|
|
157
|
+
object-fit: cover;
|
|
158
|
+
}
|
|
85
159
|
.video {
|
|
86
160
|
width: 100%;
|
|
87
161
|
height: 100%;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cntrl-site/sdk-nextjs",
|
|
3
|
-
"version": "1.8.30
|
|
3
|
+
"version": "1.8.30",
|
|
4
4
|
"description": "SDK for Next.js",
|
|
5
5
|
"author": "arsen@momdesign.nyc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@antfu/eslint-config": "^3.8.0",
|
|
32
32
|
"@cntrl-site/color": "^1.0.0",
|
|
33
33
|
"@cntrl-site/effects": "^1.4.0",
|
|
34
|
-
"@cntrl-site/sdk": "^1.22.
|
|
34
|
+
"@cntrl-site/sdk": "^1.22.19",
|
|
35
35
|
"@types/vimeo__player": "^2.18.0",
|
|
36
36
|
"@vimeo/player": "^2.25.0",
|
|
37
37
|
"html-react-parser": "^3.0.1",
|
|
@@ -28,7 +28,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
28
28
|
const fontCustomTags = new FontFaceGenerator(fonts?.custom ?? []).generate();
|
|
29
29
|
const { anchor, blur: itemBlur, opacity: itemOpacity } = useCodeEmbedItem(item, sectionId);
|
|
30
30
|
const itemAngle = useItemAngle(item, sectionId);
|
|
31
|
-
const html =
|
|
31
|
+
const { html } = item.commonParams;
|
|
32
32
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
33
33
|
useRegisterResize(ref, onResize);
|
|
34
34
|
const pos = stylesMap[anchor];
|
|
@@ -50,7 +50,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
50
50
|
script.parentNode!.removeChild(script);
|
|
51
51
|
ref.appendChild(newScript);
|
|
52
52
|
}
|
|
53
|
-
}, [html]);
|
|
53
|
+
}, [item.commonParams.html]);
|
|
54
54
|
|
|
55
55
|
useEffect(() => {
|
|
56
56
|
if (!ref) return;
|
|
@@ -67,10 +67,10 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
67
67
|
padding: 0 !important;
|
|
68
68
|
}
|
|
69
69
|
</style>
|
|
70
|
-
${html}
|
|
70
|
+
${item.commonParams.html}
|
|
71
71
|
`;
|
|
72
72
|
iframe.srcdoc = htmlWithStyles;
|
|
73
|
-
}, [html, item.commonParams.iframe, ref]);
|
|
73
|
+
}, [item.commonParams.html, item.commonParams.iframe, ref]);
|
|
74
74
|
|
|
75
75
|
const isInteractive = opacity !== 0;
|
|
76
76
|
useEffect(() => {
|
|
@@ -135,9 +135,3 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
135
135
|
</LinkWrapper>
|
|
136
136
|
);
|
|
137
137
|
};
|
|
138
|
-
|
|
139
|
-
export function decodeBase64(str: string): string {
|
|
140
|
-
const binary = atob(str);
|
|
141
|
-
const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
|
|
142
|
-
return new TextDecoder().decode(bytes);
|
|
143
|
-
}
|
|
@@ -7,10 +7,11 @@ import { useEffect, useId, useMemo, useState } from 'react';
|
|
|
7
7
|
import JSXStyle from 'styled-jsx/style';
|
|
8
8
|
import { useItemAngle } from '../useItemAngle';
|
|
9
9
|
import { useCntrlContext } from '../../../provider/useCntrlContext';
|
|
10
|
-
import { useRegisterResize } from
|
|
10
|
+
import { useRegisterResize } from '../../../common/useRegisterResize';
|
|
11
11
|
import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
|
|
12
12
|
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
13
13
|
import { LinkWrapper } from '../LinkWrapper';
|
|
14
|
+
import { useLayoutContext } from '../../useLayoutContext';
|
|
14
15
|
|
|
15
16
|
export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
16
17
|
const id = useId();
|
|
@@ -20,10 +21,12 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
20
21
|
blur: itemBlur,
|
|
21
22
|
opacity: itemOpacity
|
|
22
23
|
} = useEmbedVideoItem(item, sectionId);
|
|
24
|
+
const layoutId = useLayoutContext();
|
|
23
25
|
const [iframeRef, setIframeRef] = useState<HTMLIFrameElement | null>(null);
|
|
24
26
|
const vimeoPlayer = useMemo(() => iframeRef ? new Player(iframeRef) : undefined, [iframeRef]);
|
|
25
27
|
const itemAngle = useItemAngle(item, sectionId);
|
|
26
|
-
const {
|
|
28
|
+
const { url } = item.commonParams;
|
|
29
|
+
const layoutParams = layoutId ? item.layoutParams[layoutId] : null;
|
|
27
30
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
28
31
|
const [imgRef, setImgRef] = useState<HTMLImageElement | null>(null);
|
|
29
32
|
const [isCoverVisible, setIsCoverVisible] = useState(false);
|
|
@@ -35,25 +38,24 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
35
38
|
const opacity = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.opacity, itemOpacity);
|
|
36
39
|
const radius = getStyleFromItemStateAndParams(frameStateParams?.styles?.radius, itemRadius);
|
|
37
40
|
useRegisterResize(ref, onResize);
|
|
38
|
-
const
|
|
41
|
+
const validUrl = useMemo(() => {
|
|
42
|
+
if (!layoutParams) return url;
|
|
39
43
|
const validURL = new URL(url);
|
|
40
|
-
validURL.searchParams.append('controls', String(controls));
|
|
41
|
-
validURL.searchParams.append('autoplay', String(play === 'auto'));
|
|
42
|
-
validURL.searchParams.append('muted', String(muted));
|
|
43
|
-
validURL.searchParams.append('loop', String(loop));
|
|
44
|
-
validURL.searchParams.append('pip', String(pictureInPicture));
|
|
44
|
+
validURL.searchParams.append('controls', String(layoutParams.controls));
|
|
45
|
+
validURL.searchParams.append('autoplay', String(layoutParams.play === 'auto'));
|
|
46
|
+
validURL.searchParams.append('muted', String(layoutParams.muted));
|
|
47
|
+
validURL.searchParams.append('loop', String(layoutParams.loop));
|
|
48
|
+
validURL.searchParams.append('pip', String(layoutParams.pictureInPicture));
|
|
45
49
|
validURL.searchParams.append('title', '0');
|
|
46
50
|
validURL.searchParams.append('byline', '0');
|
|
47
51
|
validURL.searchParams.append('portrait', '0');
|
|
48
52
|
validURL.searchParams.append('autopause', 'false');
|
|
49
|
-
|
|
50
53
|
return validURL.href;
|
|
51
|
-
};
|
|
52
|
-
const validUrl = getValidVimeoUrl(url);
|
|
54
|
+
}, [url, layoutParams]);
|
|
53
55
|
|
|
54
56
|
useEffect(() => {
|
|
55
|
-
if (!vimeoPlayer || !imgRef) return;
|
|
56
|
-
if (play === 'on-click') {
|
|
57
|
+
if (!vimeoPlayer || !imgRef || !layoutParams) return;
|
|
58
|
+
if (layoutParams.play === 'on-click') {
|
|
57
59
|
setIsCoverVisible(true);
|
|
58
60
|
}
|
|
59
61
|
vimeoPlayer.on('pause', (e) => {
|
|
@@ -95,7 +97,7 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
95
97
|
useEffect(() => {
|
|
96
98
|
if (!vimeoPlayer || !interactionCtrl) return;
|
|
97
99
|
interactionCtrl.setActionReceiver((type) => {
|
|
98
|
-
switch(type) {
|
|
100
|
+
switch (type) {
|
|
99
101
|
case 'play':
|
|
100
102
|
vimeoPlayer.play();
|
|
101
103
|
break;
|
|
@@ -118,11 +120,11 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
118
120
|
transition: wrapperStateParams?.transition ?? 'none'
|
|
119
121
|
}}
|
|
120
122
|
onMouseEnter={() => {
|
|
121
|
-
if (!vimeoPlayer || play !== 'on-hover') return;
|
|
123
|
+
if (!vimeoPlayer || !layoutParams || layoutParams.play !== 'on-hover') return;
|
|
122
124
|
vimeoPlayer.play();
|
|
123
125
|
}}
|
|
124
126
|
onMouseLeave={() => {
|
|
125
|
-
if (!vimeoPlayer || play !== 'on-hover') return;
|
|
127
|
+
if (!vimeoPlayer || !layoutParams || layoutParams.play !== 'on-hover') return;
|
|
126
128
|
vimeoPlayer.pause();
|
|
127
129
|
}}
|
|
128
130
|
>
|
|
@@ -145,7 +147,7 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, sectionId
|
|
|
145
147
|
/>
|
|
146
148
|
)}
|
|
147
149
|
{/* ↓ This is necessary to track clicks on an iframe. */}
|
|
148
|
-
{(!
|
|
150
|
+
{layoutParams && (!layoutParams.controls && (layoutParams.play === 'on-click' || layoutParams.play === 'auto')) && (
|
|
149
151
|
<div
|
|
150
152
|
onClick={handleClick}
|
|
151
153
|
style={{
|
|
@@ -9,13 +9,16 @@ import { getLayoutStyles, YoutubeEmbedItem as TYoutubeEmbedItem } from '@cntrl-s
|
|
|
9
9
|
import { useCntrlContext } from '../../../provider/useCntrlContext';
|
|
10
10
|
import { useYouTubeIframeApi } from '../../../utils/Youtube/useYouTubeIframeApi';
|
|
11
11
|
import { YTPlayer } from '../../../utils/Youtube/YoutubeIframeApi';
|
|
12
|
-
import { useRegisterResize } from
|
|
12
|
+
import { useRegisterResize } from '../../../common/useRegisterResize';
|
|
13
13
|
import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams';
|
|
14
|
+
import { useLayoutContext } from '../../useLayoutContext';
|
|
14
15
|
|
|
15
16
|
export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
16
17
|
const id = useId();
|
|
17
18
|
const { layouts } = useCntrlContext();
|
|
18
|
-
const {
|
|
19
|
+
const { url } = item.commonParams;
|
|
20
|
+
const layoutId = useLayoutContext();
|
|
21
|
+
const layoutParams = layoutId ? item.layoutParams[layoutId] : null;
|
|
19
22
|
const { radius: itemRadius, blur: itemBlur, opacity: itemOpacity } = useEmbedVideoItem(item, sectionId);
|
|
20
23
|
const itemAngle = useItemAngle(item, sectionId);
|
|
21
24
|
const YT = useYouTubeIframeApi();
|
|
@@ -38,7 +41,8 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
38
41
|
useEffect(() => {
|
|
39
42
|
const newUrl = new URL(url);
|
|
40
43
|
const videoId = getYoutubeId(newUrl);
|
|
41
|
-
if (!YT || !videoId || !div) return;
|
|
44
|
+
if (!YT || !videoId || !div || !layoutParams) return;
|
|
45
|
+
const { play, controls } = layoutParams;
|
|
42
46
|
const placeholder = document.createElement('div');
|
|
43
47
|
div.appendChild(placeholder);
|
|
44
48
|
const player = new YT.Player(placeholder, {
|
|
@@ -53,7 +57,7 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
53
57
|
if (event.data === 1) {
|
|
54
58
|
setIsCoverVisible(false);
|
|
55
59
|
}
|
|
56
|
-
if (event.data === 2 || event.data === -1
|
|
60
|
+
if (event.data === 2 || event.data === -1) {
|
|
57
61
|
setIsCoverVisible(true);
|
|
58
62
|
}
|
|
59
63
|
},
|
|
@@ -70,7 +74,7 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
70
74
|
player.destroy();
|
|
71
75
|
placeholder.parentElement?.removeChild(placeholder);
|
|
72
76
|
};
|
|
73
|
-
}, [YT, div]);
|
|
77
|
+
}, [YT, div, layoutParams]);
|
|
74
78
|
|
|
75
79
|
const onCoverClick = () => {
|
|
76
80
|
if (!player || !imgRef) return;
|
|
@@ -79,10 +83,10 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
useEffect(() => {
|
|
82
|
-
if (play === 'on-click' && !controls) {
|
|
86
|
+
if (layoutParams && layoutParams.play === 'on-click' && !layoutParams.controls) {
|
|
83
87
|
setIsCoverVisible(true);
|
|
84
88
|
}
|
|
85
|
-
}, []);
|
|
89
|
+
}, [layoutParams]);
|
|
86
90
|
|
|
87
91
|
useEffect(() => {
|
|
88
92
|
onVisibilityChange?.(isInteractive);
|
|
@@ -94,7 +98,7 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
94
98
|
useEffect(() => {
|
|
95
99
|
if (!player || !interactionCtrl) return;
|
|
96
100
|
interactionCtrl.setActionReceiver((type) => {
|
|
97
|
-
switch(type) {
|
|
101
|
+
switch (type) {
|
|
98
102
|
case 'play':
|
|
99
103
|
player.playVideo();
|
|
100
104
|
break;
|
|
@@ -110,11 +114,11 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
110
114
|
<div
|
|
111
115
|
className={`embed-youtube-video-wrapper-${item.id}`}
|
|
112
116
|
onMouseEnter={() => {
|
|
113
|
-
if (!player || play !== 'on-hover') return;
|
|
117
|
+
if (!player || !layoutParams || layoutParams.play !== 'on-hover') return;
|
|
114
118
|
player.playVideo();
|
|
115
119
|
}}
|
|
116
120
|
onMouseLeave={() => {
|
|
117
|
-
if (!player || play !== 'on-hover') return;
|
|
121
|
+
if (!player || !layoutParams || layoutParams.play !== 'on-hover') return;
|
|
118
122
|
player.pauseVideo();
|
|
119
123
|
}}
|
|
120
124
|
style={{
|
|
@@ -179,9 +183,9 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, secti
|
|
|
179
183
|
border-radius: ${layoutParams.radius * 100}vw;
|
|
180
184
|
}
|
|
181
185
|
`);
|
|
182
|
-
|
|
183
|
-
`}
|
|
186
|
+
})}
|
|
187
|
+
`}
|
|
188
|
+
</JSXStyle>
|
|
184
189
|
</LinkWrapper>
|
|
185
|
-
)
|
|
190
|
+
);
|
|
186
191
|
};
|
|
187
|
-
|
|
@@ -26,13 +26,18 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
26
26
|
opacity: itemOpacity,
|
|
27
27
|
blur: itemBlur
|
|
28
28
|
} = useFileItem(item, sectionId);
|
|
29
|
+
const [isVideoPlaying, setIsVideoPlaying] = useState(false);
|
|
30
|
+
const isScrollPausedRef = useRef(false);
|
|
31
|
+
const [userPaused, setUserPaused] = useState(false);
|
|
32
|
+
const [isVideoInteracted, setIsVideoInteracted] = useState(false);
|
|
29
33
|
const itemAngle = useItemAngle(item, sectionId);
|
|
30
34
|
const [ref, setRef] = useState<HTMLDivElement | null>(null);
|
|
31
|
-
const videoRef =
|
|
35
|
+
const [videoRef, setVideoRef] = useState<HTMLVideoElement | null>(null);
|
|
32
36
|
const fxCanvas = useRef<HTMLCanvasElement | null>(null);
|
|
33
37
|
const { url, hasGLEffect } = item.commonParams;
|
|
34
38
|
const isInitialRef = useRef(true);
|
|
35
39
|
const area = layoutId ? item.area[layoutId] : null;
|
|
40
|
+
const layoutParams = layoutId ? item.layoutParams[layoutId] : null;
|
|
36
41
|
const exemplary = layouts?.find(l => l.id === layoutId)?.exemplary;
|
|
37
42
|
const width = area && exemplary ? area.width * exemplary : 0;
|
|
38
43
|
const height = area && exemplary ? area.height * exemplary : 0;
|
|
@@ -40,7 +45,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
40
45
|
const rect = useElementRect(ref);
|
|
41
46
|
const rectWidth = Math.floor(rect?.width ?? 0);
|
|
42
47
|
const rectHeight = Math.floor(rect?.height ?? 0);
|
|
43
|
-
const scrollPlayback =
|
|
48
|
+
const scrollPlayback = layoutParams ? layoutParams.scrollPlayback : null;
|
|
44
49
|
const layoutValues: Record<string, any>[] = [item.area, item.layoutParams];
|
|
45
50
|
const hasScrollPlayback = scrollPlayback !== null;
|
|
46
51
|
const wrapperStateParams = interactionCtrl?.getState(['angle', 'opacity', 'blur']);
|
|
@@ -80,6 +85,24 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
80
85
|
onVisibilityChange?.(isInteractive);
|
|
81
86
|
}, [isInteractive, onVisibilityChange]);
|
|
82
87
|
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (!layoutParams || !videoRef || layoutParams.play !== 'on-click' || !ref) return;
|
|
90
|
+
const observer = new IntersectionObserver(
|
|
91
|
+
([entry]) => {
|
|
92
|
+
if (userPaused || !isVideoInteracted) return;
|
|
93
|
+
if (entry.isIntersecting) {
|
|
94
|
+
isScrollPausedRef.current = false;
|
|
95
|
+
videoRef.play();
|
|
96
|
+
} else {
|
|
97
|
+
isScrollPausedRef.current = true;
|
|
98
|
+
videoRef.pause();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
observer.observe(ref);
|
|
103
|
+
return () => observer.disconnect();
|
|
104
|
+
}, [layoutParams, videoRef, ref, userPaused, isVideoInteracted]);
|
|
105
|
+
|
|
83
106
|
return (
|
|
84
107
|
<LinkWrapper url={item.link?.url} target={item.link?.target}>
|
|
85
108
|
<div
|
|
@@ -92,45 +115,93 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
92
115
|
transition: wrapperStateParams?.transition ?? 'none'
|
|
93
116
|
}}
|
|
94
117
|
>
|
|
95
|
-
{hasScrollPlayback
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
118
|
+
{hasScrollPlayback && (
|
|
119
|
+
<ScrollPlaybackVideo
|
|
120
|
+
sectionId={sectionId}
|
|
121
|
+
src={item.commonParams.url}
|
|
122
|
+
playbackParams={scrollPlayback}
|
|
123
|
+
style={inlineStyles}
|
|
124
|
+
className={`video video-playback-wrapper video-${item.id}`}
|
|
125
|
+
/>
|
|
126
|
+
)}
|
|
127
|
+
{hasGLEffect && isFXAllowed && (
|
|
128
|
+
<canvas
|
|
129
|
+
style={inlineStyles}
|
|
130
|
+
ref={fxCanvas}
|
|
131
|
+
className={`video-canvas video-${item.id}`}
|
|
132
|
+
width={rectWidth}
|
|
133
|
+
height={rectHeight}
|
|
134
|
+
/>
|
|
135
|
+
)}
|
|
136
|
+
{!hasScrollPlayback && !hasGLEffect && layoutParams && (
|
|
137
|
+
<>
|
|
138
|
+
<video
|
|
139
|
+
poster={item.commonParams.coverUrl ?? ''}
|
|
140
|
+
ref={setVideoRef}
|
|
141
|
+
autoPlay={layoutParams.play === 'auto'}
|
|
142
|
+
preload="auto"
|
|
143
|
+
onClick={() => {
|
|
144
|
+
setIsVideoInteracted(true);
|
|
145
|
+
}}
|
|
146
|
+
muted={layoutParams.muted}
|
|
147
|
+
onPlay={() => {
|
|
148
|
+
setIsVideoPlaying(true);
|
|
149
|
+
setUserPaused(false);
|
|
150
|
+
}}
|
|
151
|
+
onPause={() => {
|
|
152
|
+
if (!isScrollPausedRef.current) {
|
|
153
|
+
setUserPaused(true);
|
|
154
|
+
}
|
|
155
|
+
setIsVideoPlaying(false);
|
|
156
|
+
}}
|
|
157
|
+
onMouseEnter={() => {
|
|
158
|
+
if (!videoRef || layoutParams.play !== 'on-hover') return;
|
|
159
|
+
videoRef.play();
|
|
160
|
+
}}
|
|
161
|
+
onMouseLeave={() => {
|
|
162
|
+
if (!videoRef || layoutParams.play !== 'on-hover') return;
|
|
163
|
+
videoRef.pause();
|
|
164
|
+
}}
|
|
165
|
+
loop
|
|
166
|
+
controls={layoutParams.controls}
|
|
167
|
+
playsInline
|
|
168
|
+
className={`video video-${item.id}`}
|
|
169
|
+
style={inlineStyles}
|
|
170
|
+
>
|
|
171
|
+
<source src={item.commonParams.url} />
|
|
172
|
+
</video>
|
|
173
|
+
{(layoutParams.play === 'on-click' || layoutParams.play === 'on-hover') && item.commonParams.coverUrl && !isVideoInteracted && (
|
|
174
|
+
<img
|
|
175
|
+
onMouseEnter={() => {
|
|
176
|
+
if (!videoRef || layoutParams.play !== 'on-hover') return;
|
|
177
|
+
setIsVideoInteracted(true);
|
|
178
|
+
videoRef.play();
|
|
179
|
+
}}
|
|
180
|
+
src={item.commonParams.coverUrl ?? ''}
|
|
181
|
+
className={`video-cover-${item.id}`}
|
|
182
|
+
onClick={() => {
|
|
183
|
+
if (!videoRef) return;
|
|
184
|
+
setIsVideoInteracted(true);
|
|
185
|
+
videoRef.play();
|
|
186
|
+
}}
|
|
103
187
|
/>
|
|
104
|
-
)
|
|
105
|
-
: (
|
|
106
|
-
<>
|
|
107
|
-
{hasGLEffect && isFXAllowed
|
|
108
|
-
? (
|
|
109
|
-
<canvas
|
|
110
|
-
style={inlineStyles}
|
|
111
|
-
ref={fxCanvas}
|
|
112
|
-
className={`video-canvas video-${item.id}`}
|
|
113
|
-
width={rectWidth}
|
|
114
|
-
height={rectHeight}
|
|
115
|
-
/>
|
|
116
|
-
)
|
|
117
|
-
: (
|
|
118
|
-
<video
|
|
119
|
-
poster={item.commonParams.coverUrl ?? ''}
|
|
120
|
-
ref={videoRef}
|
|
121
|
-
autoPlay
|
|
122
|
-
muted
|
|
123
|
-
loop
|
|
124
|
-
playsInline
|
|
125
|
-
className={`video video-${item.id}`}
|
|
126
|
-
style={inlineStyles}
|
|
127
|
-
>
|
|
128
|
-
<source src={item.commonParams.url} />
|
|
129
|
-
</video>
|
|
130
|
-
)}
|
|
131
|
-
|
|
132
|
-
</>
|
|
133
188
|
)}
|
|
189
|
+
{(layoutParams.play === 'on-click' && !layoutParams.controls && (
|
|
190
|
+
<div
|
|
191
|
+
className={`video-overlay-${item.id}`}
|
|
192
|
+
onClick={() => {
|
|
193
|
+
if (!videoRef) return;
|
|
194
|
+
setIsVideoInteracted(true);
|
|
195
|
+
if (isVideoPlaying) {
|
|
196
|
+
videoRef.pause();
|
|
197
|
+
} else {
|
|
198
|
+
videoRef.play();
|
|
199
|
+
}
|
|
200
|
+
}}
|
|
201
|
+
/>
|
|
202
|
+
))}
|
|
203
|
+
</>
|
|
204
|
+
)}
|
|
134
205
|
</div>
|
|
135
206
|
<JSXStyle id={id}>{`
|
|
136
207
|
.video-wrapper-${item.id} {
|
|
@@ -141,6 +212,23 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
|
|
|
141
212
|
box-sizing: border-box;
|
|
142
213
|
opacity: ${opacity};
|
|
143
214
|
}
|
|
215
|
+
.video-overlay-${item.id} {
|
|
216
|
+
position: absolute;
|
|
217
|
+
top: 0;
|
|
218
|
+
left: 0;
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
width: 100%;
|
|
221
|
+
height: 100%;
|
|
222
|
+
}
|
|
223
|
+
.video-cover-${item.id} {
|
|
224
|
+
position: absolute;
|
|
225
|
+
top: 0;
|
|
226
|
+
left: 0;
|
|
227
|
+
cursor: pointer;
|
|
228
|
+
width: 100%;
|
|
229
|
+
height: 100%;
|
|
230
|
+
object-fit: cover;
|
|
231
|
+
}
|
|
144
232
|
.video {
|
|
145
233
|
width: 100%;
|
|
146
234
|
height: 100%;
|