@cntrl-site/sdk-nextjs 1.8.18 → 1.8.19

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.
Binary file
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlayIcon = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const PlayIcon = ({ className, onClick }) => {
6
+ return ((0, jsx_runtime_1.jsx)("svg", { height: "32px", version: "1.1", viewBox: "0 0 32 32", width: "32px", className: className, onClick: onClick, children: (0, jsx_runtime_1.jsx)("g", { id: "play_x5F_alt", children: (0, jsx_runtime_1.jsx)("path", { fill: "#4E4E50", d: "M16,0C7.164,0,0,7.164,0,16s7.164,16,16,16s16-7.164,16-16S24.836,0,16,0z M10,24V8l16.008,8L10,24z " }) }) }));
7
+ };
8
+ exports.PlayIcon = PlayIcon;
@@ -20,6 +20,7 @@ const getStyleFromItemStateAndParams_1 = require("../../../utils/getStyleFromIte
20
20
  const useVideoFx_1 = require("../../../utils/effects/useVideoFx");
21
21
  const useElementRect_1 = require("../../../utils/useElementRect");
22
22
  const useItemFXData_1 = require("../../../common/useItemFXData");
23
+ const PlayIcon_1 = require("./PlayIcon");
23
24
  const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
24
25
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
25
26
  const id = (0, react_1.useId)();
@@ -30,6 +31,8 @@ const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityCha
30
31
  const [ref, setRef] = (0, react_1.useState)(null);
31
32
  const videoRef = (0, react_1.useRef)(null);
32
33
  const fxCanvas = (0, react_1.useRef)(null);
34
+ const [isPlaying, setIsPlaying] = (0, react_1.useState)(false);
35
+ const [isEventTriggered, setIsEventTriggered] = (0, react_1.useState)(false);
33
36
  const { url, hasGLEffect } = item.commonParams;
34
37
  const isInitialRef = (0, react_1.useRef)(true);
35
38
  const area = layoutId ? item.area[layoutId] : null;
@@ -69,17 +72,45 @@ const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityCha
69
72
  (0, react_1.useEffect)(() => {
70
73
  onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(isInteractive);
71
74
  }, [isInteractive, onVisibilityChange]);
72
- 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.jsx)("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
73
- ? ((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}` }))
74
- : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: hasGLEffect && isFXAllowed
75
- ? ((0, jsx_runtime_1.jsx)("canvas", { style: inlineStyles, ref: fxCanvas, className: `video-canvas video-${item.id}`, width: rectWidth, height: rectHeight }))
76
- : ((0, jsx_runtime_1.jsx)("video", { poster: (_p = item.commonParams.coverUrl) !== null && _p !== void 0 ? _p : '', ref: videoRef, autoPlay: true, muted: true, onPlay: () => {
77
- console.log('play');
78
- }, onPause: () => {
79
- console.log('pause');
80
- }, onEnded: () => {
81
- console.log('ended');
82
- }, loop: true, playsInline: true, className: `video video-${item.id}`, style: inlineStyles, children: (0, jsx_runtime_1.jsx)("source", { src: item.commonParams.url }) })) })) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
75
+ const playVideo = () => {
76
+ if (videoRef.current) {
77
+ videoRef.current.play();
78
+ setIsEventTriggered(true);
79
+ }
80
+ };
81
+ (0, react_1.useEffect)(() => {
82
+ if (!isEventTriggered || !ref)
83
+ return;
84
+ const intersectionObserver = new IntersectionObserver((entries) => {
85
+ entries.forEach((entry) => {
86
+ if (!videoRef.current)
87
+ return;
88
+ if (entry.isIntersecting) {
89
+ videoRef.current.play();
90
+ }
91
+ else {
92
+ videoRef.current.pause();
93
+ }
94
+ });
95
+ });
96
+ intersectionObserver.observe(ref);
97
+ return () => {
98
+ intersectionObserver.disconnect();
99
+ };
100
+ }, [isEventTriggered, ref]);
101
+ 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: [!isPlaying && ((0, jsx_runtime_1.jsx)("div", { className: `play-btn-wrapper-${item.id}`, children: (0, jsx_runtime_1.jsx)(PlayIcon_1.PlayIcon, { className: `play-btn-${item.id}`, onClick: playVideo }) })), hasScrollPlayback
102
+ ? ((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}` }))
103
+ : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: hasGLEffect && isFXAllowed
104
+ ? ((0, jsx_runtime_1.jsx)("canvas", { style: inlineStyles, ref: fxCanvas, className: `video-canvas video-${item.id}`, width: rectWidth, height: rectHeight }))
105
+ : ((0, jsx_runtime_1.jsx)("video", { poster: (_p = item.commonParams.coverUrl) !== null && _p !== void 0 ? _p : '', ref: videoRef, controls: true, onPlay: () => {
106
+ setIsPlaying(true);
107
+ console.log('play');
108
+ }, onPause: () => {
109
+ setIsPlaying(false);
110
+ console.log('pause');
111
+ }, onEnded: () => {
112
+ console.log('ended');
113
+ }, loop: true, playsInline: true, className: `video video-${item.id}`, style: inlineStyles, children: (0, jsx_runtime_1.jsx)("source", { src: item.commonParams.url }) })) }))] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
83
114
  .video-wrapper-${item.id} {
84
115
  position: absolute;
85
116
  overflow: hidden;
@@ -88,6 +119,23 @@ const VideoItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityCha
88
119
  box-sizing: border-box;
89
120
  opacity: ${opacity};
90
121
  }
122
+ .play-btn-wrapper-${item.id} {
123
+ position: absolute;
124
+ top: 0;
125
+ left: 0;
126
+ width: 100%;
127
+ display: flex;
128
+ justify-content: center;
129
+ align-items: center;
130
+ height: 100%;
131
+ }
132
+ .play-btn-${item.id} {
133
+ width: 100px;
134
+ position: relative;
135
+ z-index: 1;
136
+ pointer-events: auto;
137
+ height: 100px;
138
+ }
91
139
  .video {
92
140
  width: 100%;
93
141
  height: 100%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "1.8.18",
3
+ "version": "1.8.19",
4
4
  "description": "SDK for Next.js",
5
5
  "author": "arsen@momdesign.nyc",
6
6
  "license": "MIT",
@@ -0,0 +1,17 @@
1
+ import { FC } from 'react';
2
+
3
+ interface Props {
4
+ className?: string;
5
+ onClick?: () => void;
6
+ }
7
+
8
+ export const PlayIcon: FC<Props> = ({ className, onClick }) => {
9
+ return (
10
+ <svg height="32px" version="1.1" viewBox="0 0 32 32" width="32px" className={className} onClick={onClick}>
11
+ <g id="play_x5F_alt">
12
+ <path fill="#4E4E50" d="M16,0C7.164,0,0,7.164,0,16s7.164,16,16,16s16-7.164,16-16S24.836,0,16,0z M10,24V8l16.008,8L10,24z " />
13
+ </g>
14
+ </svg>
15
+ );
16
+ };
17
+
@@ -14,6 +14,7 @@ import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemS
14
14
  import { useVideoFx } from '../../../utils/effects/useVideoFx';
15
15
  import { useElementRect } from '../../../utils/useElementRect';
16
16
  import { useItemFXData } from '../../../common/useItemFXData';
17
+ import { PlayIcon } from './PlayIcon';
17
18
 
18
19
  export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
19
20
  const id = useId();
@@ -30,6 +31,8 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
30
31
  const [ref, setRef] = useState<HTMLDivElement | null>(null);
31
32
  const videoRef = useRef<HTMLVideoElement | null>(null);
32
33
  const fxCanvas = useRef<HTMLCanvasElement | null>(null);
34
+ const [isPlaying, setIsPlaying] = useState(false);
35
+ const [isEventTriggered, setIsEventTriggered] = useState(false);
33
36
  const { url, hasGLEffect } = item.commonParams;
34
37
  const isInitialRef = useRef(true);
35
38
  const area = layoutId ? item.area[layoutId] : null;
@@ -80,6 +83,31 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
80
83
  onVisibilityChange?.(isInteractive);
81
84
  }, [isInteractive, onVisibilityChange]);
82
85
 
86
+ const playVideo = () => {
87
+ if (videoRef.current) {
88
+ videoRef.current.play();
89
+ setIsEventTriggered(true);
90
+ }
91
+ };
92
+
93
+ useEffect(() => {
94
+ if (!isEventTriggered || !ref) return;
95
+ const intersectionObserver = new IntersectionObserver((entries) => {
96
+ entries.forEach((entry) => {
97
+ if (!videoRef.current) return;
98
+ if (entry.isIntersecting) {
99
+ videoRef.current.play();
100
+ } else {
101
+ videoRef.current.pause();
102
+ }
103
+ });
104
+ });
105
+ intersectionObserver.observe(ref);
106
+ return () => {
107
+ intersectionObserver.disconnect();
108
+ };
109
+ }, [isEventTriggered, ref]);
110
+
83
111
  return (
84
112
  <LinkWrapper url={item.link?.url} target={item.link?.target}>
85
113
  <div
@@ -92,6 +120,11 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
92
120
  transition: wrapperStateParams?.transition ?? 'none'
93
121
  }}
94
122
  >
123
+ {!isPlaying && (
124
+ <div className={`play-btn-wrapper-${item.id}`}>
125
+ <PlayIcon className={`play-btn-${item.id}`} onClick={playVideo} />
126
+ </div>
127
+ )}
95
128
  {hasScrollPlayback
96
129
  ? (
97
130
  <ScrollPlaybackVideo
@@ -118,12 +151,13 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
118
151
  <video
119
152
  poster={item.commonParams.coverUrl ?? ''}
120
153
  ref={videoRef}
121
- autoPlay
122
- muted
154
+ controls={true}
123
155
  onPlay={() => {
156
+ setIsPlaying(true);
124
157
  console.log('play');
125
158
  }}
126
159
  onPause={() => {
160
+ setIsPlaying(false);
127
161
  console.log('pause');
128
162
  }}
129
163
  onEnded={() => {
@@ -150,6 +184,23 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, sectionId, onResize
150
184
  box-sizing: border-box;
151
185
  opacity: ${opacity};
152
186
  }
187
+ .play-btn-wrapper-${item.id} {
188
+ position: absolute;
189
+ top: 0;
190
+ left: 0;
191
+ width: 100%;
192
+ display: flex;
193
+ justify-content: center;
194
+ align-items: center;
195
+ height: 100%;
196
+ }
197
+ .play-btn-${item.id} {
198
+ width: 100px;
199
+ position: relative;
200
+ z-index: 1;
201
+ pointer-events: auto;
202
+ height: 100px;
203
+ }
153
204
  .video {
154
205
  width: 100%;
155
206
  height: 100%;