From 5eedb254dad06e3bf5ae89a8bc98667a6bc3c843 Mon Sep 17 00:00:00 2001 From: Taya Leutina Date: Tue, 23 Sep 2025 14:42:32 +0300 Subject: [PATCH] feat(Media): support ref for video element --- .storybook/stories/documentation/Types.mdx | 1 + memory-bank/usage/media.md | 35 +++++++++++++++++++++- src/components/Media/Video/Video.tsx | 2 ++ src/components/ReactPlayer/ReactPlayer.tsx | 2 +- src/models/constructor-items/common.ts | 1 + 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/.storybook/stories/documentation/Types.mdx b/.storybook/stories/documentation/Types.mdx index b62ac3085..c8a7501f0 100644 --- a/.storybook/stories/documentation/Types.mdx +++ b/.storybook/stories/documentation/Types.mdx @@ -57,6 +57,7 @@ import { Meta } from '@storybook/blocks'; - `ariaLabel?: string` — ARIA label for accessibility - `contain?: boolean` — Whether video should be contained within bounds - `onVideoEnd?: () => void` — Callback when video ends +- `ref?: React.Ref` — Ref for video element --- diff --git a/memory-bank/usage/media.md b/memory-bank/usage/media.md index 7528f8a70..40c5cb8c0 100644 --- a/memory-bank/usage/media.md +++ b/memory-bank/usage/media.md @@ -64,7 +64,7 @@ graph TD - `ImageObjectProps`: `{src: string, alt?: string, disableCompress?: boolean, hide?: boolean | Partial>, fetchPriority?: 'high' | 'low' | 'auto', loading?: 'eager' | 'lazy', 'aria-describedby'?: string}` - `ImageDeviceProps`: `{desktop: string, mobile: string, tablet?: string, alt?: string, disableCompress?: boolean, hide?: boolean | Partial>, fetchPriority?: 'high' | 'low' | 'auto', loading?: 'eager' | 'lazy', 'aria-describedby'?: string}` - `video`: MediaVideoProps - video configuration - - `{src: string[], type?: 'default' | 'player', loop?: boolean | {start: number, end?: number}, muted?: boolean, autoplay?: boolean, elapsedTime?: number, playButton?: PlayButtonProps, controls?: 'default' | 'custom', customControlsOptions?: CustomControlsOptions, ariaLabel?: string, contain?: boolean, onVideoEnd?: () => void}` + - `{src: string[], type?: 'default' | 'player', loop?: boolean | {start: number, end?: number}, muted?: boolean, autoplay?: boolean, elapsedTime?: number, playButton?: PlayButtonProps, controls?: 'default' | 'custom', customControlsOptions?: CustomControlsOptions, ariaLabel?: string, contain?: boolean, onVideoEnd?: () => void, ref?: React.Ref}` - `PlayButtonProps`: `{type?: 'default' | 'text', theme?: 'blue' | 'grey', text?: string, className?: string}` - `CustomControlsOptions`: `{type?: 'with-mute-button' | 'with-play-pause-button', muteButtonShown?: boolean, positioning?: 'left' | 'right' | 'center'}` - `youtube`: string - YouTube video ID @@ -593,6 +593,39 @@ The Media component integrates seamlessly with the page-constructor theme system /> ``` +### Video with Ref for Programmatic Control + +```tsx +const videoRef = React.useRef(null); + +const handlePlay = () => { + if (videoRef.current) { + videoRef.current.play(); + } +}; + +const handlePause = () => { + if (videoRef.current) { + videoRef.current.pause(); + } +}; + +const handleSeek = () => { + if (videoRef.current) { + videoRef.current.currentTime = 10; // Seek to 10 seconds + } +}; + +; +``` + ### Background Media with Parallax ```tsx diff --git a/src/components/Media/Video/Video.tsx b/src/components/Media/Video/Video.tsx index be2b0ac72..01ca2082e 100644 --- a/src/components/Media/Video/Video.tsx +++ b/src/components/Media/Video/Video.tsx @@ -46,6 +46,8 @@ const Video = (props: VideoAllProps) => { const ref = React.useRef(null); + React.useImperativeHandle(video.ref, () => ref.current, []); + React.useEffect(() => { if (ref && ref.current) { const {loop} = video; diff --git a/src/components/ReactPlayer/ReactPlayer.tsx b/src/components/ReactPlayer/ReactPlayer.tsx index 2185e6218..97f03c40b 100644 --- a/src/components/ReactPlayer/ReactPlayer.tsx +++ b/src/components/ReactPlayer/ReactPlayer.tsx @@ -41,7 +41,7 @@ const ReactPlayer = : _ReactPlayer; export interface ReactPlayerBlockProps - extends Omit, + extends Omit, ClassNameProps { src: string | string[]; previewImgUrl?: string; diff --git a/src/models/constructor-items/common.ts b/src/models/constructor-items/common.ts index c135241ad..8fad42078 100644 --- a/src/models/constructor-items/common.ts +++ b/src/models/constructor-items/common.ts @@ -190,6 +190,7 @@ export interface MediaVideoProps extends AnalyticsEventsBase { ariaLabel?: string; contain?: boolean; onVideoEnd?: () => void; + ref?: React.Ref; } // links