Skip to content

Commit

Permalink
feat(Video): stop method. To stop video and show the poster (if ava…
Browse files Browse the repository at this point in the history
…ilable) (#1035)

Co-authored-by: Pedro Ladaria <[email protected]>
  • Loading branch information
pladaria and Pedro Ladaria authored Mar 11, 2024
1 parent 062c0bd commit e21998f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 9 deletions.
13 changes: 10 additions & 3 deletions src/__stories__/video-story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ export const Default: StoryComponent<Args> = ({
<ButtonPrimary
small
onPress={() => {
if (videoRef.current) {
videoRef.current.play();
}
videoRef.current?.play();
}}
>
Play
Expand All @@ -115,10 +113,19 @@ export const Default: StoryComponent<Args> = ({
onPress={() => {
videoRef.current?.pause();
}}
>
Pause
</ButtonPrimary>
<ButtonPrimary
small
onPress={() => {
videoRef.current?.stop();
}}
>
Stop
</ButtonPrimary>
</Inline>

{video}
</Stack>
</Stack>
Expand Down
39 changes: 33 additions & 6 deletions src/video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import classNames from 'classnames';

import type {DataAttributes} from './utils/types';

type VideoState = 'loading' | 'loaded' | 'playing' | 'paused' | 'error';
type VideoState = 'loading' | 'loaded' | 'playing' | 'paused' | 'error' | 'stopped';

type VideoAction = 'play' | 'finishLoad' | 'pause' | 'fail' | 'reset';
type VideoAction = 'play' | 'finishLoad' | 'pause' | 'fail' | 'reset' | 'stop';

const transitions: Record<VideoState, Partial<Record<VideoAction, VideoState>>> = {
loading: {
Expand All @@ -36,20 +36,28 @@ const transitions: Record<VideoState, Partial<Record<VideoAction, VideoState>>>
playing: {
pause: 'paused',
reset: 'loading',
stop: 'stopped',
},

paused: {
play: 'playing',
reset: 'loading',
stop: 'stopped',
},

error: {
reset: 'loading',
},

stopped: {
play: 'playing',
reset: 'loading',
},
};

const videoReducer = (state: VideoState, action: VideoAction): VideoState =>
transitions[state][action] || state;
const videoReducer = (state: VideoState, action: VideoAction): VideoState => {
return transitions[state][action] || state;
};

export type AspectRatio = '1:1' | '16:9' | '4:3';

Expand Down Expand Up @@ -105,6 +113,8 @@ export interface VideoElement extends HTMLDivElement {
play: () => Promise<void>;
pause: () => void;
load: () => void;
/** Stops the video and shows the poster image (if available) */
stop: () => void;
setCurrentTime: (time: number) => void;
}

Expand Down Expand Up @@ -168,12 +178,17 @@ const Video = React.forwardRef<VideoElement, VideoProps>(

const handleLoadFinish = () => {
onLoad?.();
if (videoStatus === 'stopped') {
// the video was intentionally stopped
return;
}
const video = videoRef.current;
const shouldAutoPlay = autoPlay && !isRunningAcceptanceTest();

dispatch('finishLoad');
if (video && shouldAutoPlay && video.paused) {
video.play();
dispatch('play');
}
};

Expand All @@ -186,7 +201,7 @@ const Video = React.forwardRef<VideoElement, VideoProps>(
}
});

const showPoster = videoStatus === 'error' || videoStatus === 'loading' || videoStatus === 'loaded';
const showPoster = ['error', 'loading', 'loaded', 'stopped'].includes(videoStatus);

const video = (
<video
Expand All @@ -204,6 +219,7 @@ const Video = React.forwardRef<VideoElement, VideoProps>(
dispatch('pause');
}}
onTimeUpdate={() => {
// The state update is performed here instead of in "onPlay" to avoid flickering when hiding the poster
if (videoStatus !== 'playing' && videoRef.current?.currentTime !== 0) {
onPlay?.();
dispatch('play');
Expand Down Expand Up @@ -271,7 +287,11 @@ const Video = React.forwardRef<VideoElement, VideoProps>(
const containerElement = element ? (element as VideoElement) : null;

if (containerElement) {
containerElement.play = () => videoRef.current?.play() || Promise.resolve();
containerElement.play = () => {
// old browsers don't return a promise when calling play()
// see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play#browser_compatibility
return videoRef.current?.play() || Promise.resolve();
};
containerElement.pause = () => videoRef.current?.pause();
containerElement.load = () => {
/**
Expand Down Expand Up @@ -300,6 +320,13 @@ const Video = React.forwardRef<VideoElement, VideoProps>(
videoRef.current.currentTime = time;
}
};
containerElement.stop = () => {
if (videoRef.current) {
videoRef.current.pause();
videoRef.current.currentTime = 0;
dispatch('stop');
}
};
}

if (typeof ref === 'function') {
Expand Down

1 comment on commit e21998f

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for mistica-web ready!

✅ Preview
https://mistica-a7d60wqgs-tuentisre.vercel.app

Built with commit e21998f.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.