koval-ui
Version:
React components collection with minimalistic design. Supports theming, layout, and input validation.
1 lines • 18.6 kB
Source Map (JSON)
{"version":3,"file":"Video.cjs","sources":["../../../../src/lib/Video/Video.tsx"],"sourcesContent":["import type {SyntheticEvent} from 'react';\nimport {useState, useCallback, forwardRef, useMemo} from 'react';\nimport classNames from 'classnames';\nimport {useLocalTheme} from 'css-vars-hook';\n\nimport type {DataAttributes, LibraryProps} from '@/internal/LibraryAPI';\nimport {\n IconPause,\n IconPlay,\n IconVolume,\n IconVolumeOff,\n IconFullscreen,\n IconPictureInPicture,\n IconDownloadVideo,\n IconVideo,\n} from '@/internal/Icons';\nimport {useInternalRef} from '@/internal/hooks/useInternalRef.ts';\nimport type {Source} from '@/internal/MediaEmbeds';\nimport {\n getFileName,\n usePlay,\n PlayModes,\n useLoadingState,\n useTime,\n useSound,\n} from '@/internal/MediaEmbeds';\nimport rangeInputClasses from '@/internal/MediaEmbeds/RangeInput.module.css';\n\nimport classes from './Video.module.css';\nimport {useFullscreen} from './useFullscreen.ts';\n\nenum PreloadModes {\n none = 'none',\n metadata = 'metadata',\n auto = 'auto',\n}\n\nexport type Props = DataAttributes &\n LibraryProps & {\n /**\n * Set the width of the video file\n */\n width?: number | '100%';\n /**\n * Set the height of the video file\n */\n height?: number;\n /**\n * A URL for an image to be shown while the video is downloading.\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#poster\n */\n poster?: string;\n /**\n * Enable to automatically seek back to the start upon reaching the end of the video\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#loop\n */\n loop?: boolean;\n /**\n * Enable to silence the audio during playback\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#muted\n */\n muted?: boolean;\n /**\n * Select loading mode\n * `none` – video shouldn't be preloaded.\n * `metadata` – only video metadata (for example, length) is fetched.\n * `auto` – whole video file can be downloaded.\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#preload\n */\n preload?: keyof typeof PreloadModes;\n /**\n * Enable to play video automatically when it loads\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#autoplay\n */\n autoPlay?: boolean;\n /**\n * Enable Picture-in-picture mode\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#disablepictureinpicture\n */\n enablePictureInPicture?: boolean;\n /**\n * Display the download video button\n */\n showDownload?: boolean;\n /**\n * Show the fullscreen mode button\n */\n enableFullscreen?: boolean;\n /**\n * Show video play controls\n */\n showControls?: boolean;\n /**\n * Show video title\n */\n showTitle?: boolean;\n /**\n * Provide a title for the video\n */\n title?: string;\n /**\n * Set a callback to run when the video is buffered enough to play on the user side\n */\n onReady?: (event: SyntheticEvent<HTMLVideoElement>) => void;\n /**\n * Set a callback to capture video errors\n */\n onError?: (event: SyntheticEvent<HTMLVideoElement>) => void;\n /**\n * Set a callback to run when the user plays the video\n */\n onPlay?: (event: SyntheticEvent<HTMLVideoElement>) => void;\n /**\n * Set a callback to run when the user pauses the video\n */\n onPause?: (event: SyntheticEvent<HTMLVideoElement>) => void;\n /**\n * Provide video url\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#src\n */\n src?: string;\n /**\n * Provide video sources configs array. An advanced alternative to `src` prop\n * @see SourceDensity\n * @see SourceWidth\n */\n sources?: Source[];\n };\n\nconst getFormattedTime = (totalSeconds = 0) => {\n const minutes = new Intl.NumberFormat(undefined, {minimumIntegerDigits: 2}).format(\n Math.floor(totalSeconds / 60)\n );\n const seconds = new Intl.NumberFormat(undefined, {minimumIntegerDigits: 2}).format(\n Math.floor(totalSeconds % 60)\n );\n return `${minutes}:${seconds}`;\n};\n\nconst normalizeSize = (size?: number | string) => {\n if (typeof size === 'string') {\n return size;\n } else {\n return `${size}px`;\n }\n};\n\nexport const Video = forwardRef<HTMLVideoElement, Props>(\n (\n {\n className,\n width = '100%',\n height,\n poster,\n src,\n sources = [],\n loop = false,\n muted: mutedProp = false,\n preload = PreloadModes.auto,\n autoPlay = false,\n enablePictureInPicture = true,\n showDownload = true,\n enableFullscreen = true,\n showControls = true,\n showTitle = true,\n title,\n onReady = () => {},\n onError = () => {},\n onPlay = () => {},\n onPause = () => {},\n ...nativeProps\n },\n ref\n ) => {\n const embedRef = useInternalRef(ref);\n\n const {playMode, handleTogglePlay, handlePlay, handlePause} = usePlay<HTMLVideoElement>({\n embedRef,\n onPlay,\n onPause,\n });\n\n const [duration, setDuration] = useState(0);\n\n const {handleLoadedMetaData, handleError, handleCanPlay, readyToPlay} = useLoadingState({\n embedRef,\n onError,\n onReady,\n setDuration,\n });\n\n const {isFullScreen, handleFullscreen} = useFullscreen(embedRef);\n\n const {volume, handleSetVolume, muted, handleToggleMuted} = useSound({embedRef, mutedProp});\n\n const {handleSetTime, currentTime} = useTime({embedRef, playMode});\n\n const IconTogglePlay = useMemo(() => {\n return playMode === PlayModes.pause || playMode === PlayModes.pristine\n ? IconPlay\n : IconPause;\n }, [playMode]);\n\n const IconToggleVolume = useMemo(() => {\n return muted ? IconVolumeOff : IconVolume;\n }, [muted]);\n\n const handlePip = useCallback(() => {\n embedRef.current?.requestPictureInPicture?.();\n }, [embedRef]);\n\n const {LocalRoot} = useLocalTheme();\n\n const theme = useMemo(\n () => ({width: normalizeSize(width), height: normalizeSize(height)}),\n [height, width]\n );\n\n return (\n <LocalRoot theme={theme} className={classes.container}>\n <video\n {...nativeProps}\n title={title}\n src={src}\n poster={poster}\n className={classNames(classes.video, className)}\n controls={isFullScreen}\n width={width}\n loop={loop}\n muted={muted}\n preload={preload}\n autoPlay={autoPlay}\n disablePictureInPicture={!enablePictureInPicture}\n onCanPlay={handleCanPlay}\n onError={handleError}\n onLoadedMetadata={handleLoadedMetaData}\n onPause={handlePause}\n onPlay={handlePlay}\n ref={embedRef}>\n {sources.map(({src, type, mediaCondition}) => {\n return <source key={src} src={src} type={type} media={mediaCondition} />;\n })}\n </video>\n {playMode === PlayModes.pristine && (\n <div className={classes.overlayButton}>\n <button\n onClick={handleTogglePlay}\n className={classNames({[classes.loading]: !readyToPlay})}>\n <IconPlay className={classes.icon} />\n </button>\n </div>\n )}\n {playMode !== PlayModes.pristine && showTitle && (\n <div className={classes.overlayTitle}>\n <IconVideo className={classes.icon} />\n <span className={classes.title}>\n {title || getFileName(embedRef.current?.currentSrc)}\n </span>\n {showDownload && (\n <a\n href={embedRef.current?.currentSrc}\n download={getFileName(embedRef.current?.currentSrc)}\n className={classes.button}>\n <IconDownloadVideo className={classes.icon} />\n </a>\n )}\n </div>\n )}\n {playMode !== PlayModes.pristine && showControls && (\n <div className={classes.overlayControls}>\n <div className={classes.timelineContainer}>\n <input\n className={classNames(rangeInputClasses.range, classes.range)}\n type=\"range\"\n onChange={handleSetTime}\n value={currentTime}\n name=\"seek\"\n min={0}\n max={duration}\n step={1}\n />\n </div>\n <div className={classes.buttonsContainer}>\n <div className={classes.left}>\n <button className={classes.buttonBig} onClick={handleTogglePlay}>\n <IconTogglePlay className={classes.icon} />\n </button>\n <div className={classes.timeStamp}>\n <span className={classes.time}>\n {getFormattedTime(currentTime)}\n </span>\n <span className={classes.spacer}>/</span>\n <span className={classes.time}>\n {getFormattedTime(duration)}\n </span>\n </div>\n </div>\n\n <div className={classes.right}>\n <fieldset className={classes.volume}>\n <button className={classes.button} onClick={handleToggleMuted}>\n <IconToggleVolume className={classes.icon} />\n </button>\n <input\n type=\"range\"\n name=\"volume\"\n min={0}\n max={1}\n step={0.01}\n value={muted ? 0 : volume}\n onChange={handleSetVolume}\n className={classNames(\n rangeInputClasses.range,\n classes.range\n )}\n />\n </fieldset>\n {enablePictureInPicture && (\n <button className={classes.button} onClick={handlePip}>\n <IconPictureInPicture className={classes.icon} />\n </button>\n )}\n {enableFullscreen && (\n <button className={classes.button} onClick={handleFullscreen}>\n <IconFullscreen className={classes.icon} />\n </button>\n )}\n </div>\n </div>\n </div>\n )}\n </LocalRoot>\n );\n }\n);\n\nVideo.displayName = 'Video';\n"],"names":["getFormattedTime","totalSeconds","minutes","seconds","normalizeSize","size","Video","forwardRef","className","width","height","poster","src","sources","loop","mutedProp","preload","autoPlay","enablePictureInPicture","showDownload","enableFullscreen","showControls","showTitle","title","onReady","onError","onPlay","onPause","nativeProps","ref","embedRef","useInternalRef","playMode","handleTogglePlay","handlePlay","handlePause","usePlay","duration","setDuration","useState","handleLoadedMetaData","handleError","handleCanPlay","readyToPlay","useLoadingState","isFullScreen","handleFullscreen","useFullscreen","volume","handleSetVolume","muted","handleToggleMuted","useSound","handleSetTime","currentTime","useTime","IconTogglePlay","useMemo","PlayModes","IconPlay","IconPause","IconToggleVolume","IconVolumeOff","IconVolume","handlePip","useCallback","LocalRoot","useLocalTheme","theme","jsxs","classes","jsx","classNames","type","mediaCondition","IconVideo","getFileName","IconDownloadVideo","rangeInputClasses","IconPictureInPicture","IconFullscreen"],"mappings":"inCAiIMA,EAAmB,CAACC,EAAe,IAAM,CAC3C,MAAMC,EAAU,IAAI,KAAK,aAAa,OAAW,CAAC,qBAAsB,CAAA,CAAE,EAAE,OACxE,KAAK,MAAMD,EAAe,EAAE,CAAA,EAE1BE,EAAU,IAAI,KAAK,aAAa,OAAW,CAAC,qBAAsB,CAAA,CAAE,EAAE,OACxE,KAAK,MAAMF,EAAe,EAAE,CAAA,EAEhC,MAAO,GAAGC,CAAO,IAAIC,CAAO,EAChC,EAEMC,EAAiBC,GACf,OAAOA,GAAS,SACTA,EAEA,GAAGA,CAAI,KAITC,EAAQC,EAAAA,WACjB,CACI,CACI,UAAAC,EACA,MAAAC,EAAQ,OACR,OAAAC,EACA,OAAAC,EACA,IAAAC,EACA,QAAAC,EAAU,CAAA,EACV,KAAAC,EAAO,GACP,MAAOC,EAAY,GACnB,QAAAC,EAAU,OACV,SAAAC,EAAW,GACX,uBAAAC,EAAyB,GACzB,aAAAC,EAAe,GACf,iBAAAC,EAAmB,GACnB,aAAAC,EAAe,GACf,UAAAC,EAAY,GACZ,MAAAC,EACA,QAAAC,EAAU,IAAM,CAAC,EACjB,QAAAC,EAAU,IAAM,CAAC,EACjB,OAAAC,EAAS,IAAM,CAAC,EAChB,QAAAC,EAAU,IAAM,CAAC,EACjB,GAAGC,CAAA,EAEPC,IACC,CACD,MAAMC,EAAWC,GAAAA,eAAeF,CAAG,EAE7B,CAAC,SAAAG,EAAU,iBAAAC,EAAkB,WAAAC,EAAY,YAAAC,CAAA,EAAeC,GAAAA,QAA0B,CACpF,SAAAN,EACA,OAAAJ,EACA,QAAAC,CAAA,CACH,EAEK,CAACU,EAAUC,CAAW,EAAIC,EAAAA,SAAS,CAAC,EAEpC,CAAC,qBAAAC,EAAsB,YAAAC,EAAa,cAAAC,EAAe,YAAAC,CAAA,EAAeC,GAAAA,gBAAgB,CACpF,SAAAd,EACA,QAAAL,EACA,QAAAD,EACA,YAAAc,CAAA,CACH,EAEK,CAAC,aAAAO,EAAc,iBAAAC,GAAoBC,GAAAA,cAAcjB,CAAQ,EAEzD,CAAC,OAAAkB,EAAQ,gBAAAC,EAAiB,MAAAC,EAAO,kBAAAC,CAAA,EAAqBC,YAAS,CAAC,SAAAtB,EAAU,UAAAf,EAAU,EAEpF,CAAC,cAAAsC,EAAe,YAAAC,CAAA,EAAeC,GAAAA,QAAQ,CAAC,SAAAzB,EAAU,SAAAE,EAAS,EAE3DwB,EAAiBC,EAAAA,QAAQ,IACpBzB,IAAa0B,EAAAA,UAAU,OAAS1B,IAAa0B,YAAU,SACxDC,EAAAA,SACAC,GAAAA,UACP,CAAC5B,CAAQ,CAAC,EAEP6B,GAAmBJ,EAAAA,QAAQ,IACtBP,EAAQY,GAAAA,cAAgBC,GAAAA,WAChC,CAACb,CAAK,CAAC,EAEJc,GAAYC,EAAAA,YAAY,IAAM,CAChCnC,EAAS,SAAS,0BAAA,CACtB,EAAG,CAACA,CAAQ,CAAC,EAEP,CAAC,UAAAoC,EAAA,EAAaC,iBAAA,EAEdC,GAAQX,EAAAA,QACV,KAAO,CAAC,MAAOrD,EAAcK,CAAK,EAAG,OAAQL,EAAcM,CAAM,IACjE,CAACA,EAAQD,CAAK,CAAA,EAGlB,OACI4D,EAAAA,KAACH,GAAA,CAAU,MAAAE,GAAc,UAAWE,EAAAA,QAAQ,UACxC,SAAA,CAAAC,EAAAA,IAAC,QAAA,CACI,GAAG3C,EACJ,MAAAL,EACA,IAAAX,EACA,OAAAD,EACA,UAAW6D,EAAWF,UAAQ,MAAO9D,CAAS,EAC9C,SAAUqC,EACV,MAAApC,EACA,KAAAK,EACA,MAAAoC,EACA,QAAAlC,EACA,SAAAC,EACA,wBAAyB,CAACC,EAC1B,UAAWwB,EACX,QAASD,EACT,iBAAkBD,EAClB,QAASL,EACT,OAAQD,EACR,IAAKJ,EACJ,SAAAjB,EAAQ,IAAI,CAAC,CAAC,IAAAD,EAAK,KAAA6D,GAAM,eAAAC,YACd,SAAA,CAAiB,IAAK9D,EAAK,KAAA6D,GAAY,MAAOC,IAAlC9D,CAAkD,CACzE,CAAA,CAAA,EAEJoB,IAAa0B,EAAAA,UAAU,gBACnB,MAAA,CAAI,UAAWY,EAAAA,QAAQ,cACpB,SAAAC,EAAAA,IAAC,SAAA,CACG,QAAStC,EACT,UAAWuC,EAAW,CAAC,CAACF,EAAAA,QAAQ,OAAO,EAAG,CAAC3B,EAAY,EACvD,SAAA4B,EAAAA,IAACZ,EAAAA,SAAA,CAAS,UAAWW,EAAAA,QAAQ,IAAA,CAAM,CAAA,CAAA,EAE3C,EAEHtC,IAAa0B,EAAAA,UAAU,UAAYpC,UAC/B,MAAA,CAAI,UAAWgD,EAAAA,QAAQ,aACpB,SAAA,CAAAC,EAAAA,IAACI,GAAAA,UAAA,CAAU,UAAWL,EAAAA,QAAQ,IAAA,CAAM,EACpCC,EAAAA,IAAC,OAAA,CAAK,UAAWD,EAAAA,QAAQ,MACpB,YAASM,EAAAA,YAAY9C,EAAS,SAAS,UAAU,CAAA,CACtD,EACCX,GACGoD,EAAAA,IAAC,IAAA,CACG,KAAMzC,EAAS,SAAS,WACxB,SAAU8C,EAAAA,YAAY9C,EAAS,SAAS,UAAU,EAClD,UAAWwC,EAAAA,QAAQ,OACnB,SAAAC,EAAAA,IAACM,GAAAA,kBAAA,CAAkB,UAAWP,EAAAA,QAAQ,IAAA,CAAM,CAAA,CAAA,CAChD,EAER,EAEHtC,IAAa0B,EAAAA,UAAU,UAAYrC,UAC/B,MAAA,CAAI,UAAWiD,EAAAA,QAAQ,gBACpB,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAWD,EAAAA,QAAQ,kBACpB,SAAAC,EAAAA,IAAC,QAAA,CACG,UAAWC,EAAWM,EAAAA,QAAkB,MAAOR,EAAAA,QAAQ,KAAK,EAC5D,KAAK,QACL,SAAUjB,EACV,MAAOC,EACP,KAAK,OACL,IAAK,EACL,IAAKjB,EACL,KAAM,CAAA,CAAA,EAEd,EACAgC,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAAA,QAAQ,iBACpB,SAAA,CAAAD,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAAA,QAAQ,KACpB,SAAA,CAAAC,EAAAA,IAAC,SAAA,CAAO,UAAWD,EAAAA,QAAQ,UAAW,QAASrC,EAC3C,SAAAsC,EAAAA,IAACf,EAAA,CAAe,UAAWc,EAAAA,QAAQ,IAAA,CAAM,EAC7C,EACAD,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAAA,QAAQ,UACpB,SAAA,CAAAC,MAAC,QAAK,UAAWD,EAAAA,QAAQ,KACpB,SAAAtE,EAAiBsD,CAAW,EACjC,EACAiB,EAAAA,IAAC,OAAA,CAAK,UAAWD,EAAAA,QAAQ,OAAQ,SAAA,IAAC,QACjC,OAAA,CAAK,UAAWA,EAAAA,QAAQ,KACpB,SAAAtE,EAAiBqC,CAAQ,CAAA,CAC9B,CAAA,CAAA,CACJ,CAAA,EACJ,EAEAgC,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAAA,QAAQ,MACpB,SAAA,CAAAD,EAAAA,KAAC,WAAA,CAAS,UAAWC,EAAAA,QAAQ,OACzB,SAAA,CAAAC,EAAAA,IAAC,SAAA,CAAO,UAAWD,EAAAA,QAAQ,OAAQ,QAASnB,EACxC,SAAAoB,EAAAA,IAACV,GAAA,CAAiB,UAAWS,EAAAA,QAAQ,IAAA,CAAM,EAC/C,EACAC,EAAAA,IAAC,QAAA,CACG,KAAK,QACL,KAAK,SACL,IAAK,EACL,IAAK,EACL,KAAM,IACN,MAAOrB,EAAQ,EAAIF,EACnB,SAAUC,EACV,UAAWuB,EACPM,EAAAA,QAAkB,MAClBR,UAAQ,KAAA,CACZ,CAAA,CACJ,EACJ,EACCpD,GACGqD,EAAAA,IAAC,SAAA,CAAO,UAAWD,EAAAA,QAAQ,OAAQ,QAASN,GACxC,SAAAO,EAAAA,IAACQ,GAAAA,qBAAA,CAAqB,UAAWT,EAAAA,QAAQ,KAAM,EACnD,EAEHlD,GACGmD,EAAAA,IAAC,SAAA,CAAO,UAAWD,EAAAA,QAAQ,OAAQ,QAASxB,EACxC,SAAAyB,EAAAA,IAACS,kBAAA,CAAe,UAAWV,EAAAA,QAAQ,KAAM,CAAA,CAC7C,CAAA,CAAA,CAER,CAAA,CAAA,CACJ,CAAA,CAAA,CACJ,CAAA,EAER,CAER,CACJ,EAEAhE,EAAM,YAAc"}