xref: /expo/docs/components/plugins/Video.tsx (revision c9f6a058)
18ce35da9SBartosz Kaszubowskiimport { css } from '@emotion/react';
2f4b1168bSBartosz Kaszubowskiimport { borderRadius, breakpoints } from '@expo/styleguide-base';
3234e070fSBartosz Kaszubowskiimport { PropsWithChildren, useState } from 'react';
40ef291b0SBartosz Kaszubowskiimport ReactPlayer from 'react-player';
5586106d6SBartłomiej Klocekimport VisibilitySensor from 'react-visibility-sensor';
6586106d6SBartłomiej Klocek
78ce35da9SBartosz Kaszubowskiconst PLAYER_WIDTH = '100%' as const;
88ce35da9SBartosz Kaszubowskiconst PLAYER_HEIGHT = 400 as const;
98ce35da9SBartosz Kaszubowskiconst YOUTUBE_DOMAINS = ['youtube.com', 'youtu.be'] as const;
10586106d6SBartłomiej Klocek
11234e070fSBartosz Kaszubowskitype VideoProps = PropsWithChildren<{
128ce35da9SBartosz Kaszubowski  controls?: any;
138ce35da9SBartosz Kaszubowski  spaceAfter?: boolean | number;
148ce35da9SBartosz Kaszubowski  url?: string;
158ce35da9SBartosz Kaszubowski  file?: string;
168ce35da9SBartosz Kaszubowski  loop?: boolean;
178ce35da9SBartosz Kaszubowski}>;
18586106d6SBartłomiej Klocek
198ce35da9SBartosz Kaszubowskiconst Video = ({ controls, spaceAfter, url, file, loop = true }: VideoProps) => {
208ce35da9SBartosz Kaszubowski  const [hover, setHover] = useState(false);
218ce35da9SBartosz Kaszubowski  const [forceShowControls, setForceShowControls] = useState(isYouTubeDomain(url));
228ce35da9SBartosz Kaszubowski
238ce35da9SBartosz Kaszubowski  return (
248ce35da9SBartosz Kaszubowski    <div
258ce35da9SBartosz Kaszubowski      onClick={() => {
268ce35da9SBartosz Kaszubowski        if (typeof controls === 'undefined' && !forceShowControls) {
278ce35da9SBartosz Kaszubowski          setForceShowControls(true);
288ce35da9SBartosz Kaszubowski        }
298ce35da9SBartosz Kaszubowski      }}
308ce35da9SBartosz Kaszubowski      style={hover ? { cursor: 'pointer' } : undefined}
318ce35da9SBartosz Kaszubowski      onMouseEnter={() => setHover(true)}
328ce35da9SBartosz Kaszubowski      onMouseLeave={() => setHover(false)}>
338ce35da9SBartosz Kaszubowski      <VisibilitySensor partialVisibility>
348ce35da9SBartosz Kaszubowski        {({ isVisible }: { isVisible: boolean }) => (
358ce35da9SBartosz Kaszubowski          <div css={[videoWrapperStyle, { marginBottom: getInitialMarginBottom(spaceAfter) }]}>
368ce35da9SBartosz Kaszubowski            <ReactPlayer
378ce35da9SBartosz Kaszubowski              url={isVisible ? url || `/static/videos/${file}` : undefined}
388ce35da9SBartosz Kaszubowski              className="react-player"
398ce35da9SBartosz Kaszubowski              width={PLAYER_WIDTH}
408ce35da9SBartosz Kaszubowski              height={PLAYER_HEIGHT}
418ce35da9SBartosz Kaszubowski              style={playerStyle}
428ce35da9SBartosz Kaszubowski              muted
43*c9f6a058SBartosz Kaszubowski              playing={isVisible && !!file}
448ce35da9SBartosz Kaszubowski              controls={typeof controls === 'undefined' ? forceShowControls : controls}
458ce35da9SBartosz Kaszubowski              playsinline
468ce35da9SBartosz Kaszubowski              loop={loop}
478ce35da9SBartosz Kaszubowski            />
488ce35da9SBartosz Kaszubowski            <div
498ce35da9SBartosz Kaszubowski              css={[
508ce35da9SBartosz Kaszubowski                videoWrapperStyle,
518ce35da9SBartosz Kaszubowski                dimmerStyle,
528ce35da9SBartosz Kaszubowski                {
538ce35da9SBartosz Kaszubowski                  opacity: isVisible ? 0 : 0.7,
548ce35da9SBartosz Kaszubowski                },
558ce35da9SBartosz Kaszubowski              ]}
568ce35da9SBartosz Kaszubowski            />
578ce35da9SBartosz Kaszubowski          </div>
588ce35da9SBartosz Kaszubowski        )}
598ce35da9SBartosz Kaszubowski      </VisibilitySensor>
608ce35da9SBartosz Kaszubowski    </div>
618ce35da9SBartosz Kaszubowski  );
628ce35da9SBartosz Kaszubowski};
63586106d6SBartłomiej Klocek
641f61a071SBartosz Kaszubowskiconst getInitialMarginBottom = (spaceAfter: VideoProps['spaceAfter']) => {
65c0e1ff16SBartosz Kaszubowski  if (typeof spaceAfter === 'undefined') {
66c0e1ff16SBartosz Kaszubowski    return 30;
67c0e1ff16SBartosz Kaszubowski  } else if (typeof spaceAfter === 'number') {
68c0e1ff16SBartosz Kaszubowski    return spaceAfter;
69c0e1ff16SBartosz Kaszubowski  } else if (spaceAfter) {
70c0e1ff16SBartosz Kaszubowski    return 50;
71c0e1ff16SBartosz Kaszubowski  }
72c0e1ff16SBartosz Kaszubowski  return 0;
73c0e1ff16SBartosz Kaszubowski};
74c0e1ff16SBartosz Kaszubowski
758ce35da9SBartosz Kaszubowskiconst isYouTubeDomain = (url?: string) => {
768ce35da9SBartosz Kaszubowski  return url ? YOUTUBE_DOMAINS.some(domain => url.includes(domain)) : false;
778ce35da9SBartosz Kaszubowski};
78586106d6SBartłomiej Klocek
798ce35da9SBartosz Kaszubowskiconst videoWrapperStyle = css({
80586106d6SBartłomiej Klocek  position: 'relative',
818ce35da9SBartosz Kaszubowski  width: PLAYER_WIDTH,
828ce35da9SBartosz Kaszubowski  height: PLAYER_HEIGHT,
83f1f9ca36SBrent Vatne  backgroundColor: '#000',
848ce35da9SBartosz Kaszubowski});
858ce35da9SBartosz Kaszubowski
868ce35da9SBartosz Kaszubowskiconst playerStyle = css({
87586106d6SBartłomiej Klocek  outline: 'none',
88f1f9ca36SBrent Vatne  backgroundColor: '#000',
8914c78e61SJon Samp  borderRadius: borderRadius.md,
908ce35da9SBartosz Kaszubowski});
918ce35da9SBartosz Kaszubowski
928ce35da9SBartosz Kaszubowskiconst dimmerStyle = css({
93586106d6SBartłomiej Klocek  pointerEvents: 'none',
94586106d6SBartłomiej Klocek  position: 'absolute',
95586106d6SBartłomiej Klocek  top: 0,
96586106d6SBartłomiej Klocek  left: 0,
97586106d6SBartłomiej Klocek  bottom: 0,
98586106d6SBartłomiej Klocek  right: 0,
99586106d6SBartłomiej Klocek  transition: 'opacity 0.5s ease-out',
1008ce35da9SBartosz Kaszubowski
1018ce35da9SBartosz Kaszubowski  [`@media screen and (max-width: ${breakpoints.medium + 124}px)`]: {
1028ce35da9SBartosz Kaszubowski    display: 'none',
1038ce35da9SBartosz Kaszubowski  },
1048ce35da9SBartosz Kaszubowski});
105c0e1ff16SBartosz Kaszubowski
106c0e1ff16SBartosz Kaszubowskiexport default Video;
107