Skip to content

Commit 13528be

Browse files
authored
feat: add videoIframe prop to media block and component (#999)
* feat: add videoIframe prop to media block and component * fix: review fixes
1 parent 9ddfac3 commit 13528be

File tree

6 files changed

+57
-47
lines changed

6 files changed

+57
-47
lines changed

.storybook/stories/documentation/Types.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import { Meta } from '@storybook/blocks';
5555
- `parallax?: boolean` — Enable/disable the parallax effect
5656
- [`video?: Video` — Video](#Video)
5757
- `youtube?: url` — Link to a video on YouTube
58+
- `videoIframe?: url` — Link to a video iframe
5859
- `height?: number` — Block height
5960
- `previewImg?: string`
6061
- `dataLens?: string |` [DataLens](#DataLens)

src/components/Media/Media.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, {ReactElement, useMemo, useState} from 'react';
22

33
import {MediaProps, QAProps} from '../../models';
44
import {block, getQaAttrubutes} from '../../utils';
5-
import YoutubeBlock from '../VideoBlock/VideoBlock';
5+
import IframeVideoBlock from '../VideoBlock/VideoBlock';
66

77
import DataLens from './DataLens/DataLens';
88
import FullscreenVideo from './FullscreenVideo/FullscreenVideo';
@@ -26,6 +26,7 @@ export const Media = (props: MediaAllProps) => {
2626
image,
2727
video,
2828
youtube,
29+
videoIframe,
2930
dataLens,
3031
color,
3132
height,
@@ -99,11 +100,12 @@ export const Media = (props: MediaAllProps) => {
99100
}
100101
}
101102

102-
if (youtube) {
103+
if (youtube || videoIframe) {
103104
result = (
104-
<YoutubeBlock
105+
<IframeVideoBlock
105106
className={b('youtube', youtubeClassName)}
106107
record={youtube}
108+
videoIframe={videoIframe}
107109
attributes={{color: 'white', rel: '0'}}
108110
previewImg={previewImg}
109111
height={height}
@@ -127,6 +129,7 @@ export const Media = (props: MediaAllProps) => {
127129
}, [
128130
image,
129131
video,
132+
videoIframe,
130133
youtube,
131134
dataLens,
132135
iframe,

src/components/VideoBlock/VideoBlock.tsx

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* eslint-disable jsx-a11y/click-events-have-key-events */
33
// TODO fix in https://github.com/gravity-ui/page-constructor/issues/965
44

5-
import React, {useCallback, useEffect, useRef, useState} from 'react';
5+
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
66

77
import {PlayFill} from '@gravity-ui/icons';
88
import {Icon} from '@gravity-ui/uikit';
@@ -28,10 +28,13 @@ export const AUTOPLAY_ATTRIBUTES = {
2828
autoplay: 1,
2929
mute: 1,
3030
};
31+
const NO_AUTOPLAY_ATTRIBUTES = {
32+
autoplay: 0,
33+
};
3134

3235
const b = block('VideoBlock');
3336

34-
function getVideoSrc(stream?: string, record?: string) {
37+
function getYoutubeVideoSrc(stream?: string, record?: string) {
3538
if (!stream && !record) {
3639
return null;
3740
}
@@ -57,6 +60,7 @@ export interface VideoBlockProps extends AnalyticsEventsBase {
5760
id?: string;
5861
stream?: string;
5962
record?: string;
63+
videoIframe?: string;
6064
attributes?: Record<string, string>;
6165
className?: string;
6266
previewImg?: string;
@@ -71,6 +75,7 @@ const VideoBlock = (props: VideoBlockProps) => {
7175
const {
7276
stream,
7377
record,
78+
videoIframe,
7479
attributes,
7580
className,
7681
id,
@@ -84,25 +89,29 @@ const VideoBlock = (props: VideoBlockProps) => {
8489
} = props;
8590
const handleAnalytics = useAnalytics(DefaultEventNames.VideoPreview);
8691

87-
const src = getVideoSrc(stream, record);
92+
const src = videoIframe ? videoIframe : getYoutubeVideoSrc(stream, record);
8893
const ref = useRef<HTMLDivElement>(null);
89-
const iframeRef = useRef<HTMLIFrameElement>();
9094
const [hidePreview, setHidePreview] = useState(false);
91-
const norender = (!stream && !record) || !src;
9295
const [currentHeight, setCurrentHeight] = useState(height || undefined);
93-
const fullId = id || uuidv4();
96+
const fullId = useMemo(() => id || uuidv4(), [id]);
97+
98+
const [isPlaying, setIsPlaying] = useState(!previewImg);
99+
100+
const iframeSrc =
101+
src && isPlaying
102+
? `${src}?${getPageSearchParams({
103+
...(attributes || {}),
104+
...(autoplay ? AUTOPLAY_ATTRIBUTES : NO_AUTOPLAY_ATTRIBUTES),
105+
})}`
106+
: undefined;
107+
94108
const onPreviewClick = useCallback(() => {
95109
handleAnalytics(analyticsEvents);
96110

97-
if (iframeRef.current) {
98-
iframeRef.current.src = `${src}?${getPageSearchParams({
99-
...AUTOPLAY_ATTRIBUTES,
100-
...(attributes || {}),
101-
})}`;
102-
}
111+
setIsPlaying(true);
103112

104113
setTimeout(() => setHidePreview(true), AUTOPLAY_DELAY);
105-
}, [handleAnalytics, analyticsEvents, src, attributes]);
114+
}, [handleAnalytics, analyticsEvents]);
106115

107116
useEffect(() => {
108117
const updateSize = debounce(() => {
@@ -118,44 +127,33 @@ const VideoBlock = (props: VideoBlockProps) => {
118127
};
119128
}, [height]);
120129

121-
useEffect(() => {
122-
if (norender) {
123-
return;
124-
}
125-
126-
if (ref.current && !iframeRef.current) {
127-
const iframe = document.createElement('iframe');
128-
iframe.id = fullId;
129-
130-
if (!previewImg) {
131-
iframe.src = `${src}?${getPageSearchParams({
132-
...(attributes || {}),
133-
...(autoplay ? AUTOPLAY_ATTRIBUTES : {}),
134-
})}`;
135-
}
136-
137-
iframe.width = '100%';
138-
iframe.height = '100%';
139-
iframe.title = i18n('iframe-title');
140-
iframe.frameBorder = '0';
141-
iframe.setAttribute('allowfullscreen', 'true');
142-
iframe.setAttribute('allow', 'autoplay');
143-
iframe.setAttribute('loading', 'lazy');
144-
ref.current.appendChild(iframe);
145-
iframeRef.current = iframe;
146-
}
147-
}, [stream, record, norender, src, fullId, attributes, iframeRef, previewImg, autoplay]);
130+
const iframeContent = useMemo(() => {
131+
return (
132+
<iframe
133+
id={fullId}
134+
src={iframeSrc}
135+
width="100%"
136+
height="100%"
137+
title={i18n('iframe-title')}
138+
frameBorder="0"
139+
allowFullScreen={true}
140+
allow="autoplay; fullscreen; encrypted-media; accelerometer; gyroscope; picture-in-picture; clipboard-write; web-share; screen-wake-lock"
141+
loading="lazy"
142+
/>
143+
);
144+
}, [fullId, iframeSrc]);
148145

149146
useEffect(() => {
150147
setHidePreview(false);
151-
}, [src, setHidePreview]);
148+
}, [src]);
152149

153-
if (norender) {
150+
if (!src) {
154151
return null;
155152
}
156153

157154
return (
158-
<div className={b(null, className)} ref={ref} style={{height: currentHeight}}>
155+
<div className={b(null, className)} style={{height: currentHeight}} ref={ref}>
156+
{iframeContent}
159157
{previewImg && !hidePreview && !fullscreen && (
160158
<div className={b('preview')} onClick={onPreviewClick}>
161159
<Image

src/models/constructor-items/common.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ export interface MediaComponentVideoProps extends AnalyticsEventsBase {
252252
previewImg?: string;
253253
}
254254

255+
export interface MediaComponentVideoIframeProps {
256+
videoIframe: string;
257+
}
258+
255259
export interface MediaComponentYoutubeProps {
256260
youtube: string;
257261
previewImg?: string;
@@ -279,6 +283,7 @@ export interface MediaProps
279283
extends Animatable,
280284
Partial<MediaComponentDataLensProps>,
281285
Partial<MediaComponentYoutubeProps>,
286+
Partial<MediaComponentVideoIframeProps>,
282287
Partial<MediaComponentImageProps>,
283288
Partial<MediaComponentIframeProps>,
284289
Partial<MediaComponentVideoProps> {

src/schema/validators/common.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@ export const MediaProps = {
604604
youtube: {
605605
type: 'string',
606606
},
607+
videoIframe: {
608+
type: 'string',
609+
},
607610
parallax: {
608611
type: 'boolean',
609612
},

src/sub-blocks/LayoutItem/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ export const hasFullscreen = ({dataLens, image}: MediaProps) => {
1111
return !(dataLens || Array.isArray(image));
1212
};
1313

14-
export const showFullscreenIcon = ({youtube}: MediaProps) => !youtube;
14+
export const showFullscreenIcon = ({youtube, videoIframe}: MediaProps) => !(youtube || videoIframe);

0 commit comments

Comments
 (0)