add declaration

master
lgf 3 years ago
parent 38f9458ff3
commit eb5b02f4c2
  1. 26
      src/appComponent.tsx
  2. 2
      src/core/config/index.ts
  3. 41
      src/core/context/index.ts
  4. 11
      src/core/controls/multiple.tsx
  5. 15
      src/core/controls/volume.tsx
  6. 4
      src/core/index.scss
  7. 87
      src/core/index.tsx
  8. 12
      src/core/progress/index.tsx
  9. 22
      src/core/useVideo.ts
  10. 51
      src/core/useVideoCallback.ts
  11. 75
      src/interface/index.ts

@ -6,8 +6,11 @@ import '@/icons/';
const AppComponent = memo(function AppComponent(props) { const AppComponent = memo(function AppComponent(props) {
const videoRef = useRef<HTMLVideoElement>(null!); const videoRef = useRef<HTMLVideoElement>(null!);
const onProgressSlide = (val: any) => { const onProgressMouseDown = (val: any) => {
console.log(`val`, val); // console.log(`val`, val);
};
const onProgressMouseUp = (val: any) => {
console.log(`onProgressMouseUp`, val);
}; };
const onPlay = (val: any) => { const onPlay = (val: any) => {
console.log(`播放`, val); console.log(`播放`, val);
@ -16,20 +19,35 @@ const AppComponent = memo(function AppComponent(props) {
console.log(`暂停`, val); console.log(`暂停`, val);
}; };
const onTimeChange = (val: any) => { const onTimeChange = (val: any) => {
console.log(`onTimeChange`, val); // console.log(`onTimeChange`, val);
}; };
const onEndEd = (val: any) => { const onEndEd = (val: any) => {
console.log(`onEndEd`, val); console.log(`onEndEd`, val);
}; };
const onError = () => {
console.log(`onError`);
};
const onvolumechange = (val: any) => {
console.log(`onvolumechange`, val);
};
return ( return (
<> <>
<JoLPlayer <JoLPlayer
ref={videoRef} ref={videoRef}
onProgressSlide={onProgressSlide} option={{
videoSrc:
'https://gs-files.oss-cn-hongkong.aliyuncs.com/okr/test/file/2021/07/01/haiwang.mp4',
width: 750,
height: 420,
}}
onProgressMouseDown={onProgressMouseDown}
onPlay={onPlay} onPlay={onPlay}
onPause={onPause} onPause={onPause}
onTimeChange={onTimeChange} onTimeChange={onTimeChange}
onEndEd={onEndEd} onEndEd={onEndEd}
onProgressMouseUp={onProgressMouseUp}
onError={onError}
onvolumechange={onvolumechange}
/> />
{/* <JoLPlayer /> */} {/* <JoLPlayer /> */}
</> </>

@ -6,3 +6,5 @@ export const multipleList = [
{ id: 1.5, name: '1.5x' }, { id: 1.5, name: '1.5x' },
{ id: 2, name: '2.0x' }, { id: 2, name: '2.0x' },
]; ];
export const defaultTheme: string = 'blue';

@ -1,22 +1,18 @@
import React, { useReducer } from 'react'; import React, { useReducer } from 'react';
import { videoOption } from '@/interface';
export interface VideoStateType<K = boolean, T = number> { export interface VideoStateType<K = boolean, T = number> {
/** /**
* @description * @description
*/ */
isControl: K; isControl: K;
/** /**
* @description * @description onProgressMouseDown事件的变化数据onProgressMouseDown事件触发的
*/
currentTime: T;
/**
* @description
*/ */
isPlay: K; progressSliderChangeVal: T;
/** /**
* @description onProgressSlider事件的变化数据onProgressSlider事件触发的 * @description onProgressMouseUp事件的变化数据onProgressMouseUp事件触发的
*/ */
progressSliderChangeVal: T; progressMouseUpChangeVal: T;
} }
/** /**
* @description * @description
@ -27,15 +23,15 @@ export interface contextType {
lightOffMaskRef: HTMLElement | null; lightOffMaskRef: HTMLElement | null;
dispatch?: React.Dispatch<mergeAction>; dispatch?: React.Dispatch<mergeAction>;
videoFlow: VideoStateType; videoFlow: VideoStateType;
propsAttributes?: videoOption;
} }
/** /**
* @description * @description
*/ */
export const initialState = { export const initialState = {
isControl: false, isControl: false,
currentTime: 0,
isPlay: false,
progressSliderChangeVal: 0, progressSliderChangeVal: 0,
progressMouseUpChangeVal: 0,
}; };
export const defaultValue = { export const defaultValue = {
@ -50,35 +46,28 @@ export interface isControlActionType {
type: 'isControl'; type: 'isControl';
data: VideoStateType['isControl']; data: VideoStateType['isControl'];
} }
export interface currentTimeActionType {
type: 'currentTime';
data: VideoStateType['currentTime'];
}
export interface isPlayActionType {
type: 'isPlay';
data: VideoStateType['isPlay'];
}
export interface progressSliderChangeValActionType { export interface progressSliderChangeValActionType {
type: 'progressSliderChangeVal'; type: 'progressSliderChangeVal';
data: VideoStateType['progressSliderChangeVal']; data: VideoStateType['progressSliderChangeVal'];
} }
export interface progressMouseUpChangeValValActionType {
type: 'progressMouseUpChangeVal';
data: VideoStateType['progressMouseUpChangeVal'];
}
export type mergeAction = export type mergeAction =
| isControlActionType | isControlActionType
| currentTimeActionType | progressSliderChangeValActionType
| isPlayActionType | progressMouseUpChangeValValActionType;
| progressSliderChangeValActionType;
export const useVideoFlow = () => { export const useVideoFlow = () => {
const reducer = (state: VideoStateType, action: mergeAction) => { const reducer = (state: VideoStateType, action: mergeAction) => {
switch (action.type) { switch (action.type) {
case 'isControl': case 'isControl':
return { ...state, isControl: action.data }; return { ...state, isControl: action.data };
case 'currentTime':
return { ...state, currentTime: action.data };
case 'isPlay':
return { ...state, isPlay: action.data };
case 'progressSliderChangeVal': case 'progressSliderChangeVal':
return { ...state, progressSliderChangeVal: action.data }; return { ...state, progressSliderChangeVal: action.data };
case 'progressMouseUpChangeVal':
return { ...state, progressMouseUpChangeVal: action.data };
default: default:
return state; return state;
} }

@ -1,7 +1,8 @@
import React, { memo, FC, useState } from 'react'; import React, { memo, FC, useState, useContext } from 'react';
import { multipleList } from '@/core/config'; import { multipleList } from '@/core/config';
import { defaultTheme } from '@/core/config';
import { FlowContext } from '@/core/context';
import './index.scss'; import './index.scss';
export interface MultipleType { export interface MultipleType {
multipleText: string; multipleText: string;
selectPlayRate: Function; selectPlayRate: Function;
@ -13,6 +14,10 @@ const Multiple: FC<MultipleType> = memo(function Multiple({
selectPlayRate, selectPlayRate,
multiple, multiple,
}) { }) {
const reviceProps = useContext(FlowContext);
const { theme } = reviceProps.propsAttributes!;
const [isShow, setIsShow] = useState<boolean>(false); const [isShow, setIsShow] = useState<boolean>(false);
return ( return (
@ -31,7 +36,7 @@ const Multiple: FC<MultipleType> = memo(function Multiple({
<li <li
onClick={() => [selectPlayRate(item.id), setIsShow(false)]} onClick={() => [selectPlayRate(item.id), setIsShow(false)]}
key={index} key={index}
style={{ color: multiple === item.id ? 'red' : '#fff' }} style={{ color: multiple === item.id ? (theme ? theme : defaultTheme) : '#fff' }}
> >
{item.name} {item.name}
</li> </li>

@ -1,5 +1,7 @@
import React, { useImperativeHandle, useRef, forwardRef, useState } from 'react'; import React, { useImperativeHandle, useRef, forwardRef, useState, useContext } from 'react';
import Broadcast from '@/components/svgIcon'; import Broadcast from '@/components/svgIcon';
import { defaultTheme } from '@/core/config';
import { FlowContext } from '@/core/context';
import './index.scss'; import './index.scss';
export interface VolumeType { export interface VolumeType {
@ -15,6 +17,10 @@ const Volume = function Volume(
) { ) {
const volumeSliderMirror = useRef<HTMLDivElement>(null); const volumeSliderMirror = useRef<HTMLDivElement>(null);
const reviceProps = useContext(FlowContext);
const { theme } = reviceProps.propsAttributes!;
const [isShow, setIsShow] = useState<boolean>(false); const [isShow, setIsShow] = useState<boolean>(false);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
@ -49,10 +55,13 @@ const Volume = function Volume(
className="volume-slider-op" className="volume-slider-op"
style={{ style={{
height: `${volume}%`, height: `${volume}%`,
backgroundColor: `red`, backgroundColor: `${theme ? theme : defaultTheme}`,
}} }}
> >
<div className="volume-slider-op-circle" style={{ backgroundColor: `red` }}></div> <div
className="volume-slider-op-circle"
style={{ backgroundColor: `${theme ? theme : defaultTheme}` }}
></div>
</div> </div>
</div> </div>
</div> </div>

@ -3,8 +3,8 @@
-khtml-user-select: none; -khtml-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
user-select: none; user-select: none;
width: 740px; // width: 740px;
height: 420px; // height: 420px;
margin: 0; margin: 0;
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;

@ -13,28 +13,24 @@ import useMandatoryUpdate from '@/utils/useMandatoryUpdate';
import Broadcast from '@/components/svgIcon'; import Broadcast from '@/components/svgIcon';
import { useVideo } from '@/core/useVideo'; import { useVideo } from '@/core/useVideo';
import useVideoCallback from '@/core/useVideoCallback'; import useVideoCallback from '@/core/useVideoCallback';
import { defaultTheme } from '@/core/config';
// import videoUrl from '@/assets/haiwang.mp4'; // import videoUrl from '@/assets/haiwang.mp4';
import '@/assets/css/reset.scss'; import '@/assets/css/reset.scss';
import './index.scss'; import './index.scss';
const JoLPlayer = function JoLPlayer( const JoLPlayer = function JoLPlayer(props: videoparameter, ref: React.Ref<unknown> | undefined) {
{ const {
videoSrc = 'https://gs-files.oss-cn-hongkong.aliyuncs.com/okr/test/file/2021/07/01/haiwang.mp4', option,
onProgressSlide, onProgressMouseDown,
onPlay, onPlay,
onPause, onPause,
onTimeChange, onTimeChange,
onEndEd, onEndEd,
}: { onProgressMouseUp,
videoSrc?: string; onError,
onPause?: Function; onvolumechange,
onPlay?: Function; } = props;
onTimeChange?: Function; const { videoSrc, width, height, theme } = option;
onEndEd?: Function;
onProgressSlide?: Function;
},
ref: React.Ref<unknown> | undefined,
) {
/** /**
* @description * @description
*/ */
@ -76,20 +72,22 @@ const JoLPlayer = function JoLPlayer(
video: videoRef.current, video: videoRef.current,
})); }));
const { isPlay, handleChangePlayState, currentTime, duration, isPictureinpicture, isEndEd } = const { videoAttributes } = useVideo(
useVideo( {
{ videoElement: videoRef.current,
videoElement: videoRef.current, },
}, [videoRef.current],
[videoRef.current], );
);
const callBack = useVideoCallback({ isPlay, currentTime, isEndEd }, videoFlow, { useVideoCallback(videoAttributes, videoFlow, {
onProgressSlide, onProgressMouseDown,
onProgressMouseUp,
onPlay, onPlay,
onPause, onPause,
onTimeChange, onTimeChange,
onEndEd, onEndEd,
onError,
onvolumechange,
}); });
useEffect(() => { useEffect(() => {
@ -101,6 +99,8 @@ const JoLPlayer = function JoLPlayer(
* @description * @description
*/ */
const videoContainerElem = videoContainerRef.current; const videoContainerElem = videoContainerRef.current;
videoContainerElem.style.width = `${width}px`;
videoContainerElem.style.height = `${height}px`;
const videoElem = videoRef.current; const videoElem = videoRef.current;
// 设置定时器检测 3 秒后视频是否可用 // 设置定时器检测 3 秒后视频是否可用
timerToCheckVideoUseful.current = setTimeout(() => { timerToCheckVideoUseful.current = setTimeout(() => {
@ -120,7 +120,7 @@ const JoLPlayer = function JoLPlayer(
videoElem.removeEventListener('waiting', waitingListener); videoElem.removeEventListener('waiting', waitingListener);
videoElem.removeEventListener('playing', playingListener); videoElem.removeEventListener('playing', playingListener);
}; };
}, [videoRef.current]); }, [videoRef.current, option]);
const returnVideoSource = useMemo(() => { const returnVideoSource = useMemo(() => {
return ( return (
@ -132,32 +132,6 @@ const JoLPlayer = function JoLPlayer(
); );
}, [videoSrc]); }, [videoSrc]);
// useEffect(() => {
// if (videoFlow.progressSliderChangeVal) {
// onProgressSlide && onProgressSlide(videoFlow.progressSliderChangeVal);
// }
// }, [videoFlow.progressSliderChangeVal]);
// useEffect(() => {
// if (isPlay) {
// onPlay && onPlay(isPlay);
// } else {
// onPause && onPause(isPlay);
// }
// }, [isPlay]);
// useEffect(() => {
// if (currentTime) {
// onTimeChange && onTimeChange(currentTime);
// }
// }, [currentTime]);
// useEffect(() => {
// if (isEndEd) {
// onEndEd && onEndEd(isEndEd);
// }
// }, [isEndEd]);
const contextProps = useMemo(() => { const contextProps = useMemo(() => {
return Object.assign( return Object.assign(
{}, {},
@ -167,9 +141,10 @@ const JoLPlayer = function JoLPlayer(
lightOffMaskRef: lightOffMaskRef.current, lightOffMaskRef: lightOffMaskRef.current,
dispatch, dispatch,
videoFlow, videoFlow,
propsAttributes: option,
}, },
); );
}, [videoRef.current, videoFlow]); }, [videoRef.current, videoFlow, option]);
return ( return (
<figure className="JoL-player-container" ref={videoContainerRef}> <figure className="JoL-player-container" ref={videoContainerRef}>
@ -179,7 +154,12 @@ const JoLPlayer = function JoLPlayer(
</video> </video>
{!isVideoUseful && <p className="video-no-useful-tip"> ( ́︿ ̀)</p>} {!isVideoUseful && <p className="video-no-useful-tip"> ( ́︿ ̀)</p>}
{isBufferring && ( {isBufferring && (
<Broadcast iconClass="loading" fill="#ff0000" className="player-loading" fontSize="55px" /> <Broadcast
iconClass="loading"
fill={theme ? theme : defaultTheme}
className="player-loading"
fontSize="55px"
/>
)} )}
<FlowContext.Provider value={contextProps}> <FlowContext.Provider value={contextProps}>
<Controller /> <Controller />
@ -188,5 +168,6 @@ const JoLPlayer = function JoLPlayer(
); );
}; };
const JoLPlayerComponent = forwardRef<HTMLVideoElement, any>(JoLPlayer); const JoLPlayerComponent = forwardRef<HTMLVideoElement, videoparameter>(JoLPlayer);
export default JoLPlayerComponent; export default JoLPlayerComponent;

@ -5,6 +5,7 @@ import { percentToMinutesAndSeconds, percentToSeconds } from '@/utils';
import useWindowClient from '@/utils/useWindowClient'; import useWindowClient from '@/utils/useWindowClient';
import { useProgress } from './variable'; import { useProgress } from './variable';
import { hoverShowStyleType } from '@/interface'; import { hoverShowStyleType } from '@/interface';
import { defaultTheme } from '@/core/config';
import './index.scss'; import './index.scss';
const Index = memo(function Index(props) { const Index = memo(function Index(props) {
@ -29,6 +30,8 @@ const Index = memo(function Index(props) {
const reviceProps = useContext(FlowContext); const reviceProps = useContext(FlowContext);
const { theme } = reviceProps.propsAttributes!;
const { currentTime, duration, bufferedTime } = useVideo({ videoElement: reviceProps.videoRef }, [ const { currentTime, duration, bufferedTime } = useVideo({ videoElement: reviceProps.videoRef }, [
reviceProps.videoRef, reviceProps.videoRef,
]); ]);
@ -138,6 +141,7 @@ const Index = memo(function Index(props) {
*/ */
const clearIntervalFunc = () => { const clearIntervalFunc = () => {
whenMouseUpDo(); whenMouseUpDo();
reviceProps.dispatch!({ type: 'progressMouseUpChangeVal', data: Date.now() });
}; };
/** /**
* @description * @description
@ -176,12 +180,12 @@ const Index = memo(function Index(props) {
className="progress-played" className="progress-played"
style={{ style={{
width: `${calculateProcessPercent}%`, width: `${calculateProcessPercent}%`,
background: `red`, background: `${theme ? theme : defaultTheme}`,
}} }}
> >
<i <i
className="progress-scrubber" className="progress-scrubber"
style={{ background: `red` }} style={{ background: `${theme ? theme : defaultTheme}` }}
ref={progressScrubberRef} ref={progressScrubberRef}
></i> ></i>
</div> </div>
@ -200,13 +204,13 @@ const Index = memo(function Index(props) {
<div <div
className="top-triangle" className="top-triangle"
style={{ style={{
borderTop: `4px solid red`, borderTop: `4px solid ${theme ? theme : defaultTheme}`,
}} }}
></div> ></div>
<div <div
className="bottom-triangle" className="bottom-triangle"
style={{ style={{
borderBottom: `4px solid red`, borderBottom: `4px solid ${theme ? theme : defaultTheme}`,
}} }}
></div> ></div>
</div> </div>

@ -1,12 +1,18 @@
import { useRef, useMemo, useEffect, DependencyList } from 'react'; import { useRef, useMemo, useEffect, DependencyList } from 'react';
import useMandatoryUpdate from '@/utils/useMandatoryUpdate'; import useMandatoryUpdate from '@/utils/useMandatoryUpdate';
import { videoAttributes } from '@/interface';
export interface useVideoType extends videoAttributes {
handleChangePlayState: () => void;
videoAttributes: videoAttributes;
}
export const useVideo = (props: any, dep: DependencyList = []) => { export const useVideo = (props: any, dep: DependencyList = []) => {
const { videoElement } = props; const { videoElement } = props;
const forceUpdate = useMandatoryUpdate(); const forceUpdate = useMandatoryUpdate();
const videoParameter = useRef<any>({ const videoParameter = useRef<videoAttributes>({
isPlay: false, isPlay: false,
currentTime: 0, currentTime: 0,
duration: 0, duration: 0,
@ -15,6 +21,7 @@ export const useVideo = (props: any, dep: DependencyList = []) => {
volume: 0, volume: 0,
multiple: 1.0, multiple: 1.0,
isEndEd: false, isEndEd: false,
error: null,
}); });
const videoRef = useRef<HTMLVideoElement>(null!); const videoRef = useRef<HTMLVideoElement>(null!);
@ -24,10 +31,6 @@ export const useVideo = (props: any, dep: DependencyList = []) => {
videoRef.current = videoElement; videoRef.current = videoElement;
useEffect(() => { useEffect(() => {
/**
* @description
*/
// forceUpdate();
if (videoRef.current) { if (videoRef.current) {
/** /**
* @description * @description
@ -73,13 +76,14 @@ export const useVideo = (props: any, dep: DependencyList = []) => {
videoRef.current.addEventListener('play', playChange); videoRef.current.addEventListener('play', playChange);
videoRef.current.addEventListener('timeupdate', timeupdate); videoRef.current.addEventListener('timeupdate', timeupdate);
videoRef.current.addEventListener('ended', endedChange); videoRef.current.addEventListener('ended', endedChange);
videoRef.current.addEventListener('error', errorChange);
} }
return () => { return () => {
interval.current && clearInterval(interval.current); interval.current && clearInterval(interval.current);
}; };
}, dep); }, dep);
const torture = (val: any) => { const torture = <T extends Partial<videoAttributes>>(val: T) => {
videoParameter.current = { ...videoParameter.current, ...val }; videoParameter.current = { ...videoParameter.current, ...val };
}; };
const pauseChange = () => { const pauseChange = () => {
@ -94,6 +98,9 @@ export const useVideo = (props: any, dep: DependencyList = []) => {
const endedChange = () => { const endedChange = () => {
torture({ isEndEd: videoRef.current.ended ? true : false }); torture({ isEndEd: videoRef.current.ended ? true : false });
}; };
const errorChange = () => {
torture({ error: Date.now() });
};
const handleChangePlayState = () => { const handleChangePlayState = () => {
if (videoParameter.current.isPlay) { if (videoParameter.current.isPlay) {
videoRef.current.pause(); videoRef.current.pause();
@ -102,10 +109,11 @@ export const useVideo = (props: any, dep: DependencyList = []) => {
} }
}; };
return useMemo( return useMemo<useVideoType>(
() => ({ () => ({
handleChangePlayState, handleChangePlayState,
...videoParameter.current, ...videoParameter.current,
videoAttributes: videoParameter.current,
}), }),
[videoParameter.current], [videoParameter.current],
); );

@ -1,35 +1,68 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { videoAttributes, videoCallback } from '@/interface';
import { VideoStateType } from './context';
const useVideoCallback = (videoPr: any, videoFlow: any, handle: any) => { const useVideoCallback = (
const { isPlay, currentTime, isEndEd } = videoPr; videoPr: videoAttributes,
const { progressSliderChangeVal } = videoFlow; videoFlow: VideoStateType,
const { onProgressSlide, onPlay, onPause, onTimeChange, onEndEd } = handle; handle: Partial<videoCallback>,
) => {
const { isPlay, currentTime, isEndEd, error, volume } = videoPr;
const { progressSliderChangeVal, progressMouseUpChangeVal } = videoFlow;
const {
onProgressMouseDown,
onPlay,
onPause,
onTimeChange,
onEndEd,
onProgressMouseUp,
onError,
onvolumechange,
} = handle;
useEffect(() => { useEffect(() => {
if (videoFlow.progressSliderChangeVal) { if (videoFlow.progressSliderChangeVal) {
onProgressSlide && onProgressSlide(progressSliderChangeVal); onProgressMouseDown && onProgressMouseDown(videoPr);
} }
}, [progressSliderChangeVal]); }, [progressSliderChangeVal]);
useEffect(() => {
if (videoFlow.progressMouseUpChangeVal) {
onProgressMouseUp && onProgressMouseUp(videoPr);
}
}, [progressMouseUpChangeVal]);
useEffect(() => { useEffect(() => {
if (isPlay) { if (isPlay) {
onPlay && onPlay(isPlay); onPlay && onPlay(videoPr);
} else { } else {
onPause && onPause(isPlay); onPause && onPause(videoPr);
} }
}, [isPlay]); }, [isPlay]);
useEffect(() => { useEffect(() => {
if (currentTime) { if (currentTime) {
onTimeChange && onTimeChange(currentTime); onTimeChange && onTimeChange(videoPr);
} }
}, [currentTime]); }, [currentTime]);
useEffect(() => { useEffect(() => {
if (isEndEd) { if (isEndEd) {
onEndEd && onEndEd(isEndEd); onEndEd && onEndEd(videoPr);
} }
}, [isEndEd]); }, [isEndEd]);
useEffect(() => {
if (error) {
onError && onError();
}
}, [error]);
useEffect(() => {
if (volume) {
onvolumechange && onvolumechange(videoPr);
}
}, [volume]);
}; };
export default useVideoCallback; export default useVideoCallback;

@ -24,7 +24,80 @@ export interface videoOption {
*/ */
videoSrc: string; videoSrc: string;
} }
export interface videoparameter { export interface videoAttributes<T = number, K = boolean> {
/**
* @description
*/
isPlay: K;
/**
* @description /s
*/
currentTime: T;
/**
* @description
*/
duration: T;
/**
* @description /s
*/
bufferedTime: T;
/**
* @description
*/
isPictureinpicture: K;
/**
* @description
*/
volume: T;
/**
* @description
*/
multiple: T;
/**
* @description
*/
isEndEd: K;
/**
* @description
*/
error: null | T;
}
export type callBackType = (e: videoAttributes) => void;
export interface videoCallback<T = callBackType> {
/**
* @description
*/
onProgressMouseDown: T;
/**
* @description
*/
onPlay: T;
/**
* @description
*/
onPause: T;
/**
* @description
*/
onTimeChange: T;
/**
* @description
*/
onEndEd: T;
/**
* @description
*/
onProgressMouseUp: T;
/**
* @description
*/
onError: () => void;
/**
* @description
*/
onvolumechange: T;
}
export interface videoparameter extends Partial<videoCallback> {
style?: React.CSSProperties; style?: React.CSSProperties;
/** /**
* @description * @description

Loading…
Cancel
Save