File size: 3,024 Bytes
92189dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import Logger from '@/common/logger/Logger';
import stylex from '@stylexjs/stylex';
import {
  CSSProperties,
  MouseEventHandler,
  useCallback,
  useEffect,
  useRef,
} from 'react';

const styles = stylex.create({
  background: {
    backgroundRepeat: 'no-repeat',
    backgroundSize: 'cover',
    backgroundPosition: 'center',
    cursor: 'pointer',
  },
  video: {
    width: '100%',
    height: '100%',
  },
});

type Props = {
  onClick: MouseEventHandler<HTMLVideoElement> | undefined;
  src: string;
  poster: string;
  style: CSSProperties;
};

export default function VideoPhoto({src, poster, style, onClick}: Props) {
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const playPromiseRef = useRef<Promise<void> | null>(null);

  const play = useCallback(() => {
    const video = videoRef.current;
    // Only play video if it is not already playing
    if (video != null && video.paused) {
      // This quirky way of handling video play/pause in the browser is needed
      // due to the async nature of the video play API:
      // https://developer.chrome.com/blog/play-request-was-interrupted/
      const playPromise = video.play();
      playPromise.catch(error => {
        Logger.error('Failed to play video', error);
      });
      playPromiseRef.current = playPromise;
    }
  }, []);

  const pause = useCallback(() => {
    // Only pause video if it is playing
    const playPromise = playPromiseRef.current;
    if (playPromise != null) {
      playPromise
        .then(() => {
          videoRef.current?.pause();
        })
        .catch(error => {
          Logger.error('Failed to pause video', error);
        })
        .finally(() => {
          playPromiseRef.current = null;
        });
    }
  }, []);

  useEffect(() => {
    return () => {
      pause();
    };
  }, [pause]);

  return (
    <div
      style={{
        ...style,
        backgroundImage: `url(${poster})`,
      }}
      {...stylex.props(styles.background)}>
      <video
        ref={videoRef}
        {...stylex.props(styles.video)}
        preload="none"
        playsInline
        loop
        muted
        title="Gallery Video"
        poster={poster}
        onMouseEnter={play}
        onMouseLeave={pause}
        onClick={onClick}>
        <source src={src} type="video/mp4" />
        Sorry, your browser does not support embedded videos.
      </video>
    </div>
  );
}