@skodaflow/web-library 8.4.0 → 8.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/cjs/components/carousel/Autoplay.js.map +1 -1
  2. package/cjs/components/carousel/Carousel.js +1 -1
  3. package/cjs/components/carousel/Carousel.js.map +1 -1
  4. package/cjs/components/carousel/Navigation.js +1 -1
  5. package/cjs/components/carousel/Navigation.js.map +1 -1
  6. package/cjs/components/carousel/Pagination.js +1 -1
  7. package/cjs/components/carousel/Pagination.js.map +1 -1
  8. package/cjs/components/header/Header.js +1 -1
  9. package/cjs/components/header/Header.js.map +1 -1
  10. package/cjs/components/header/HeaderNavigationHero.js +1 -1
  11. package/cjs/components/header/HeaderNavigationHero.js.map +1 -1
  12. package/cjs/components/header/HeaderNavigationMenu.js +1 -1
  13. package/cjs/components/header/HeaderNavigationMenu.js.map +1 -1
  14. package/cjs/components/hotspotCard/HotspotCard.js +1 -1
  15. package/cjs/components/hotspotCard/HotspotCard.js.map +1 -1
  16. package/cjs/components/icon/stroke/EmissionLabelIcon.js.map +1 -1
  17. package/cjs/components/image/Image.d.ts +38 -14
  18. package/cjs/components/image/Image.js +1 -1
  19. package/cjs/components/image/Image.js.map +1 -1
  20. package/cjs/components/index.d.ts +1 -0
  21. package/cjs/components/label/Label.js.map +1 -1
  22. package/cjs/components/overlay/Overlay.js +1 -1
  23. package/cjs/components/overlay/Overlay.js.map +1 -1
  24. package/cjs/components/video/Video.d.ts +9 -8
  25. package/cjs/components/video/Video.js +1 -1
  26. package/cjs/components/video/Video.js.map +1 -1
  27. package/cjs/components/video/index.d.ts +5 -1
  28. package/cjs/components/video/useVideoFullscreen.d.ts +13 -0
  29. package/cjs/components/video/useVideoFullscreen.js +2 -0
  30. package/cjs/components/video/useVideoFullscreen.js.map +1 -0
  31. package/cjs/components/video/useVideoPlayPause.d.ts +13 -0
  32. package/cjs/components/video/useVideoPlayPause.js +2 -0
  33. package/cjs/components/video/useVideoPlayPause.js.map +1 -0
  34. package/cjs/components/video/useVideoReady.d.ts +6 -0
  35. package/cjs/components/video/useVideoReady.js +2 -0
  36. package/cjs/components/video/useVideoReady.js.map +1 -0
  37. package/cjs/components/video/useVideoSoundControls.d.ts +17 -0
  38. package/cjs/components/video/useVideoSoundControls.js +2 -0
  39. package/cjs/components/video/useVideoSoundControls.js.map +1 -0
  40. package/cjs/components/video/useVideoTime.d.ts +22 -0
  41. package/cjs/components/video/useVideoTime.js +2 -0
  42. package/cjs/components/video/useVideoTime.js.map +1 -0
  43. package/cjs/components/videoPlayer/VideoPlayer.d.ts +125 -0
  44. package/cjs/components/videoPlayer/VideoPlayer.js +2 -0
  45. package/cjs/components/videoPlayer/VideoPlayer.js.map +1 -0
  46. package/cjs/components/videoPlayer/VideoPlayerFullscreenButton.d.ts +31 -0
  47. package/cjs/components/videoPlayer/VideoPlayerFullscreenButton.js +2 -0
  48. package/cjs/components/videoPlayer/VideoPlayerFullscreenButton.js.map +1 -0
  49. package/cjs/components/videoPlayer/VideoPlayerIconButton.d.ts +16 -0
  50. package/cjs/components/videoPlayer/VideoPlayerIconButton.js +2 -0
  51. package/cjs/components/videoPlayer/VideoPlayerIconButton.js.map +1 -0
  52. package/cjs/components/videoPlayer/VideoPlayerPlayPauseButton.d.ts +31 -0
  53. package/cjs/components/videoPlayer/VideoPlayerPlayPauseButton.js +2 -0
  54. package/cjs/components/videoPlayer/VideoPlayerPlayPauseButton.js.map +1 -0
  55. package/cjs/components/videoPlayer/VideoPlayerSkipButton.d.ts +23 -0
  56. package/cjs/components/videoPlayer/VideoPlayerSkipButton.js +2 -0
  57. package/cjs/components/videoPlayer/VideoPlayerSkipButton.js.map +1 -0
  58. package/cjs/components/videoPlayer/VideoPlayerSlider.d.ts +12 -0
  59. package/cjs/components/videoPlayer/VideoPlayerSlider.js +2 -0
  60. package/cjs/components/videoPlayer/VideoPlayerSlider.js.map +1 -0
  61. package/cjs/components/videoPlayer/VideoPlayerSoundButton.d.ts +31 -0
  62. package/cjs/components/videoPlayer/VideoPlayerSoundButton.js +2 -0
  63. package/cjs/components/videoPlayer/VideoPlayerSoundButton.js.map +1 -0
  64. package/cjs/components/videoPlayer/VideoPlayerTime.d.ts +17 -0
  65. package/cjs/components/videoPlayer/VideoPlayerTime.js +2 -0
  66. package/cjs/components/videoPlayer/VideoPlayerTime.js.map +1 -0
  67. package/cjs/components/videoPlayer/formatVideoTime.d.ts +5 -0
  68. package/cjs/components/videoPlayer/formatVideoTime.js +2 -0
  69. package/cjs/components/videoPlayer/formatVideoTime.js.map +1 -0
  70. package/cjs/components/videoPlayer/index.d.ts +10 -0
  71. package/cjs/components/videoPlayer/useVideoPlayerVisibility.d.ts +24 -0
  72. package/cjs/components/videoPlayer/useVideoPlayerVisibility.js +2 -0
  73. package/cjs/components/videoPlayer/useVideoPlayerVisibility.js.map +1 -0
  74. package/cjs/index.js +1 -1
  75. package/cjs/materialui/accordion/AccordionSummaryExpandWrapper.d.ts +5 -1
  76. package/cjs/materialui/accordion/AccordionSummaryExpandWrapper.js +1 -1
  77. package/cjs/materialui/accordion/AccordionSummaryExpandWrapper.js.map +1 -1
  78. package/cjs/materialui/alert/alertTitle.theme.js.map +1 -1
  79. package/cjs/materialui/card/Card.js.map +1 -1
  80. package/cjs/materialui/card/card.theme.js +1 -1
  81. package/cjs/materialui/card/card.theme.js.map +1 -1
  82. package/cjs/materialui/divider/divider.theme.js +1 -1
  83. package/cjs/materialui/divider/divider.theme.js.map +1 -1
  84. package/cjs/materialui/skeleton/skeleton.theme.js +1 -1
  85. package/cjs/materialui/skeleton/skeleton.theme.js.map +1 -1
  86. package/cjs/materialui/slider/slider.theme.js +1 -1
  87. package/cjs/materialui/slider/slider.theme.js.map +1 -1
  88. package/cjs/materialui/table/tablePagination.theme.js.map +1 -1
  89. package/cjs/materialui/tabs/Tab.d.ts +1 -0
  90. package/cjs/materialui/tabs/Tab.js +1 -1
  91. package/cjs/materialui/tabs/Tab.js.map +1 -1
  92. package/cjs/materialui/tabs/TabsScrollButton.d.ts +3 -1
  93. package/cjs/materialui/tabs/TabsScrollButton.js +1 -1
  94. package/cjs/materialui/tabs/TabsScrollButton.js.map +1 -1
  95. package/cjs/materialui/textfield/FormControl.js +1 -1
  96. package/cjs/materialui/textfield/FormControl.js.map +1 -1
  97. package/cjs/materialui/textfield/FormHelperText.js +1 -1
  98. package/cjs/materialui/textfield/FormHelperText.js.map +1 -1
  99. package/cjs/materialui/theme/sxConfig.js.map +1 -1
  100. package/cjs/materialui/theme/theme.extensions.d.ts +29 -0
  101. package/cjs/node_modules/swiper/modules/a11y.js +2 -0
  102. package/cjs/node_modules/swiper/modules/a11y.js.map +1 -0
  103. package/cjs/node_modules/swiper/modules/autoplay.js +1 -1
  104. package/cjs/node_modules/swiper/modules/autoplay.js.map +1 -1
  105. package/cjs/node_modules/swiper/modules/effect-fade.js +1 -1
  106. package/cjs/node_modules/swiper/modules/effect-fade.js.map +1 -1
  107. package/cjs/node_modules/swiper/modules/keyboard.js +1 -1
  108. package/cjs/node_modules/swiper/modules/keyboard.js.map +1 -1
  109. package/cjs/node_modules/swiper/modules/parallax.js +1 -1
  110. package/cjs/node_modules/swiper/modules/parallax.js.map +1 -1
  111. package/cjs/node_modules/swiper/shared/classes-to-selector.js +2 -0
  112. package/cjs/node_modules/swiper/shared/classes-to-selector.js.map +1 -0
  113. package/cjs/node_modules/swiper/shared/effect-init.js +1 -1
  114. package/cjs/node_modules/swiper/shared/effect-init.js.map +1 -1
  115. package/cjs/node_modules/swiper/shared/effect-target.js +1 -1
  116. package/cjs/node_modules/swiper/shared/effect-target.js.map +1 -1
  117. package/cjs/node_modules/swiper/shared/effect-virtual-transition-end.js +1 -1
  118. package/cjs/node_modules/swiper/shared/effect-virtual-transition-end.js.map +1 -1
  119. package/cjs/node_modules/swiper/shared/swiper-core.js +1 -1
  120. package/cjs/node_modules/swiper/shared/swiper-core.js.map +1 -1
  121. package/cjs/node_modules/swiper/shared/update-on-virtual-data.js +1 -1
  122. package/cjs/node_modules/swiper/shared/update-on-virtual-data.js.map +1 -1
  123. package/cjs/node_modules/swiper/shared/update-swiper.js +1 -1
  124. package/cjs/node_modules/swiper/shared/update-swiper.js.map +1 -1
  125. package/cjs/node_modules/swiper/shared/utils.js +1 -1
  126. package/cjs/node_modules/swiper/shared/utils.js.map +1 -1
  127. package/cjs/node_modules/swiper/swiper-react.js +1 -1
  128. package/cjs/node_modules/swiper/swiper-react.js.map +1 -1
  129. package/cjs/package.json +1 -0
  130. package/components/carousel/Autoplay.js.map +1 -1
  131. package/components/carousel/Carousel.js +1 -1
  132. package/components/carousel/Carousel.js.map +1 -1
  133. package/components/carousel/Navigation.js +1 -1
  134. package/components/carousel/Navigation.js.map +1 -1
  135. package/components/carousel/Pagination.js +1 -1
  136. package/components/carousel/Pagination.js.map +1 -1
  137. package/components/header/Header.js +1 -1
  138. package/components/header/Header.js.map +1 -1
  139. package/components/header/HeaderNavigationHero.js +1 -1
  140. package/components/header/HeaderNavigationHero.js.map +1 -1
  141. package/components/header/HeaderNavigationMenu.js +1 -1
  142. package/components/header/HeaderNavigationMenu.js.map +1 -1
  143. package/components/hotspotCard/HotspotCard.js +1 -1
  144. package/components/hotspotCard/HotspotCard.js.map +1 -1
  145. package/components/icon/stroke/EmissionLabelIcon.js.map +1 -1
  146. package/components/image/Image.d.ts +38 -14
  147. package/components/image/Image.js +1 -1
  148. package/components/image/Image.js.map +1 -1
  149. package/components/index.d.ts +1 -0
  150. package/components/label/Label.js.map +1 -1
  151. package/components/overlay/Overlay.js +1 -1
  152. package/components/overlay/Overlay.js.map +1 -1
  153. package/components/video/Video.d.ts +9 -8
  154. package/components/video/Video.js +1 -1
  155. package/components/video/Video.js.map +1 -1
  156. package/components/video/index.d.ts +5 -1
  157. package/components/video/useVideoFullscreen.d.ts +13 -0
  158. package/components/video/useVideoFullscreen.js +2 -0
  159. package/components/video/useVideoFullscreen.js.map +1 -0
  160. package/components/video/useVideoPlayPause.d.ts +13 -0
  161. package/components/video/useVideoPlayPause.js +2 -0
  162. package/components/video/useVideoPlayPause.js.map +1 -0
  163. package/components/video/useVideoReady.d.ts +6 -0
  164. package/components/video/useVideoReady.js +2 -0
  165. package/components/video/useVideoReady.js.map +1 -0
  166. package/components/video/useVideoSoundControls.d.ts +17 -0
  167. package/components/video/useVideoSoundControls.js +2 -0
  168. package/components/video/useVideoSoundControls.js.map +1 -0
  169. package/components/video/useVideoTime.d.ts +22 -0
  170. package/components/video/useVideoTime.js +2 -0
  171. package/components/video/useVideoTime.js.map +1 -0
  172. package/components/videoPlayer/VideoPlayer.d.ts +125 -0
  173. package/components/videoPlayer/VideoPlayer.js +2 -0
  174. package/components/videoPlayer/VideoPlayer.js.map +1 -0
  175. package/components/videoPlayer/VideoPlayerFullscreenButton.d.ts +31 -0
  176. package/components/videoPlayer/VideoPlayerFullscreenButton.js +2 -0
  177. package/components/videoPlayer/VideoPlayerFullscreenButton.js.map +1 -0
  178. package/components/videoPlayer/VideoPlayerIconButton.d.ts +16 -0
  179. package/components/videoPlayer/VideoPlayerIconButton.js +2 -0
  180. package/components/videoPlayer/VideoPlayerIconButton.js.map +1 -0
  181. package/components/videoPlayer/VideoPlayerPlayPauseButton.d.ts +31 -0
  182. package/components/videoPlayer/VideoPlayerPlayPauseButton.js +2 -0
  183. package/components/videoPlayer/VideoPlayerPlayPauseButton.js.map +1 -0
  184. package/components/videoPlayer/VideoPlayerSkipButton.d.ts +23 -0
  185. package/components/videoPlayer/VideoPlayerSkipButton.js +2 -0
  186. package/components/videoPlayer/VideoPlayerSkipButton.js.map +1 -0
  187. package/components/videoPlayer/VideoPlayerSlider.d.ts +12 -0
  188. package/components/videoPlayer/VideoPlayerSlider.js +2 -0
  189. package/components/videoPlayer/VideoPlayerSlider.js.map +1 -0
  190. package/components/videoPlayer/VideoPlayerSoundButton.d.ts +31 -0
  191. package/components/videoPlayer/VideoPlayerSoundButton.js +2 -0
  192. package/components/videoPlayer/VideoPlayerSoundButton.js.map +1 -0
  193. package/components/videoPlayer/VideoPlayerTime.d.ts +17 -0
  194. package/components/videoPlayer/VideoPlayerTime.js +2 -0
  195. package/components/videoPlayer/VideoPlayerTime.js.map +1 -0
  196. package/components/videoPlayer/formatVideoTime.d.ts +5 -0
  197. package/components/videoPlayer/formatVideoTime.js +2 -0
  198. package/components/videoPlayer/formatVideoTime.js.map +1 -0
  199. package/components/videoPlayer/index.d.ts +10 -0
  200. package/components/videoPlayer/useVideoPlayerVisibility.d.ts +24 -0
  201. package/components/videoPlayer/useVideoPlayerVisibility.js +2 -0
  202. package/components/videoPlayer/useVideoPlayerVisibility.js.map +1 -0
  203. package/index.js +1 -1
  204. package/materialui/accordion/AccordionSummaryExpandWrapper.d.ts +5 -1
  205. package/materialui/accordion/AccordionSummaryExpandWrapper.js +1 -1
  206. package/materialui/accordion/AccordionSummaryExpandWrapper.js.map +1 -1
  207. package/materialui/alert/alertTitle.theme.js.map +1 -1
  208. package/materialui/card/Card.js.map +1 -1
  209. package/materialui/card/card.theme.js +1 -1
  210. package/materialui/card/card.theme.js.map +1 -1
  211. package/materialui/divider/divider.theme.js +1 -1
  212. package/materialui/divider/divider.theme.js.map +1 -1
  213. package/materialui/skeleton/skeleton.theme.js +1 -1
  214. package/materialui/skeleton/skeleton.theme.js.map +1 -1
  215. package/materialui/slider/slider.theme.js +1 -1
  216. package/materialui/slider/slider.theme.js.map +1 -1
  217. package/materialui/table/tablePagination.theme.js.map +1 -1
  218. package/materialui/tabs/Tab.d.ts +1 -0
  219. package/materialui/tabs/Tab.js +1 -1
  220. package/materialui/tabs/Tab.js.map +1 -1
  221. package/materialui/tabs/TabsScrollButton.d.ts +3 -1
  222. package/materialui/tabs/TabsScrollButton.js +1 -1
  223. package/materialui/tabs/TabsScrollButton.js.map +1 -1
  224. package/materialui/textfield/FormControl.js +1 -1
  225. package/materialui/textfield/FormControl.js.map +1 -1
  226. package/materialui/textfield/FormHelperText.js +1 -1
  227. package/materialui/textfield/FormHelperText.js.map +1 -1
  228. package/materialui/theme/sxConfig.js.map +1 -1
  229. package/materialui/theme/theme.extensions.d.ts +29 -0
  230. package/package.json +1 -1
  231. package/cjs/components/video/hooks.d.ts +0 -43
  232. package/cjs/components/video/hooks.js +0 -2
  233. package/cjs/components/video/hooks.js.map +0 -1
  234. package/cjs/node_modules/swiper/shared/ssr-window.esm.js +0 -2
  235. package/cjs/node_modules/swiper/shared/ssr-window.esm.js.map +0 -1
  236. package/components/video/hooks.d.ts +0 -43
  237. package/components/video/hooks.js +0 -2
  238. package/components/video/hooks.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Video.js","sources":["../../../src/components/video/Video.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { Box, BoxProps } from '@mui/material';\nimport { FileMissingIcon } from '@/src/components/icon/stroke/FileMissingIcon';\nimport { sxOverride } from '@/src/utils/sxOverride';\n\nexport interface VideoProps extends BoxProps<'video'> {\n /** The URL of the video to embed. */\n src?: string;\n /** video type property, @default \"video/mp4\" */\n type?: string;\n /** The message (or component) to display if the video cannot be loaded, @default <Icon name=\"file-missing\" /> centered inside the Box */\n noVidErrorMessage?: React.ReactNode;\n /** Custom source Box props. */\n sourceProps?: BoxProps<'source'>;\n /** Image to be shown while the video is downloading or until the user hits the play button. */\n poster?: string;\n /** Video element autoPlay, @default true */\n autoPlay?: boolean;\n /** Video element muted, @default true */\n muted?: boolean;\n /** Video element native browser controls, @default false */\n controls?: boolean;\n /** Video element loop, @default false */\n loop?: boolean;\n}\n\n/**\n * The Video component is a customizable video player built with React and Material-UI.\n * It extends the Box component from Material-UI and provides various props to control video playback and appearance.\n * If children are provided, they are rendered inside the video element as source elements.\n * If no children are provided, a default source element is used based on the src prop.\n * @param videoRef - A reference to the video element.\n */\nexport const Video: React.FC<VideoProps> = forwardRef(\n (\n {\n src,\n type = 'video/mp4',\n noVidErrorMessage,\n sourceProps,\n poster,\n sx,\n autoPlay = true,\n muted = true,\n controls = false,\n loop = false,\n children,\n ...rest\n },\n ref,\n ) => {\n return (\n <Box\n component=\"video\"\n data-testid=\"Video\"\n poster={poster}\n ref={ref}\n autoPlay={autoPlay}\n muted={muted}\n controls={controls}\n loop={loop}\n sx={sxOverride(\n {\n display: 'block',\n maxWidth: '100%',\n },\n sx,\n )}\n {...rest}\n >\n {children ?? <Box component=\"source\" src={src} type={type} {...sourceProps} />}\n {noVidErrorMessage ?? (\n <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}>\n <FileMissingIcon />\n </Box>\n )}\n </Box>\n );\n },\n);\n"],"names":["Video","forwardRef","src","type","noVidErrorMessage","sourceProps","poster","sx","autoPlay","muted","controls","loop","children","rest","ref","_jsxs","Box","component","sxOverride","display","maxWidth","_jsx","justifyContent","alignItems","width","height","FileMissingIcon"],"mappings":"qQAiCaA,EAA8BC,EACzC,EAEIC,MACAC,OAAO,YACPC,oBACAC,cACAC,SACAC,KACAC,YAAW,EACXC,SAAQ,EACRC,YAAW,EACXC,QAAO,EACPC,cACGC,GAELC,IAGEC,EAACC,EAAG,CACFC,UAAU,QAAO,cACL,QACZX,OAAQA,EACRQ,IAAKA,EACLN,SAAUA,EACVC,MAAOA,EACPC,SAAUA,EACVC,KAAMA,EACNJ,GAAIW,EACF,CACEC,QAAS,QACTC,SAAU,QAEZb,MAEEM,EAAID,SAAA,CAEPA,GAAYS,EAACL,EAAG,CAACC,UAAU,SAASf,IAAKA,EAAKC,KAAMA,KAAUE,IAC9DD,GACCiB,EAACL,EAAG,CAACT,GAAI,CAAEY,QAAS,OAAQG,eAAgB,SAAUC,WAAY,SAAUC,MAAO,OAAQC,OAAQ,QAAQb,SACzGS,EAACK,EAAe"}
1
+ {"version":3,"file":"Video.js","sources":["../../../src/components/video/Video.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { Box, BoxProps } from '@mui/material';\nimport { FileMissingIcon } from '@/src/components/icon/stroke/FileMissingIcon';\nimport { sxOverride } from '@/src/utils/sxOverride';\n\nexport interface VideoProps extends BoxProps<'video'> {\n /** The URL of the video to embed. */\n src?: string;\n /** video type property, @default \"video/mp4\" */\n type?: string;\n /**\n * Content shown when the video fails to load\n * @default <FileMissingIcon /> centered inside the Box\n */\n errorFallback?: React.ReactNode;\n /**\n * @deprecated Use `errorFallback` instead\n */\n noVidErrorMessage?: React.ReactNode;\n /** Custom source Box props. */\n sourceProps?: BoxProps<'source'>;\n /** Video element autoPlay, @default true */\n autoPlay?: boolean;\n /** Video element muted, @default true */\n muted?: boolean;\n /** Video element native browser controls, @default false */\n controls?: boolean;\n /** Video element loop, @default false */\n loop?: boolean;\n}\n\n/**\n * Video player wrapping the native <video> element, rendering a fallback when the source fails to load\n */\nexport const Video: React.FC<VideoProps> = forwardRef(\n (\n {\n src,\n type = 'video/mp4',\n errorFallback,\n noVidErrorMessage,\n sourceProps,\n sx,\n autoPlay = true,\n muted = true,\n controls = false,\n loop = false,\n children,\n ...rest\n },\n ref,\n ) => {\n return (\n <Box\n component=\"video\"\n data-testid=\"Video\"\n ref={ref}\n autoPlay={autoPlay}\n muted={muted}\n controls={controls}\n loop={loop}\n sx={sxOverride(\n {\n display: 'block',\n maxWidth: '100%',\n // fill the container fullscreened by useVideoFullscreen, otherwise the video keeps its intrinsic size\n // leading * keeps stylis from prefixing the bare pseudo-class with the own class\n '*:fullscreen > &': {\n width: '100%',\n height: '100%',\n objectFit: 'contain',\n },\n },\n sx,\n )}\n {...rest}\n >\n {children ?? <Box component=\"source\" src={src} type={type} {...sourceProps} />}\n {errorFallback ?? noVidErrorMessage ?? (\n <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}>\n <FileMissingIcon />\n </Box>\n )}\n </Box>\n );\n },\n);\n"],"names":["Video","forwardRef","src","type","errorFallback","noVidErrorMessage","sourceProps","sx","autoPlay","muted","controls","loop","children","rest","ref","_jsxs","Box","component","sxOverride","display","maxWidth","width","height","objectFit","_jsx","justifyContent","alignItems","FileMissingIcon"],"mappings":"qQAkCaA,EAA8BC,EACzC,EAEIC,MACAC,OAAO,YACPC,gBACAC,oBACAC,cACAC,KACAC,YAAW,EACXC,SAAQ,EACRC,YAAW,EACXC,QAAO,EACPC,cACGC,GAELC,IAGEC,EAACC,EAAG,CACFC,UAAU,QAAO,cACL,QACZH,IAAKA,EACLN,SAAUA,EACVC,MAAOA,EACPC,SAAUA,EACVC,KAAMA,EACNJ,GAAIW,EACF,CACEC,QAAS,QACTC,SAAU,OAGV,mBAAoB,CAClBC,MAAO,OACPC,OAAQ,OACRC,UAAW,YAGfhB,MAEEM,EAAID,SAAA,CAEPA,GAAYY,EAACR,EAAG,CAACC,UAAU,SAASf,IAAKA,EAAKC,KAAMA,KAAUG,IAC9DF,GAAiBC,GAChBmB,EAACR,EAAG,CAACT,GAAI,CAAEY,QAAS,OAAQM,eAAgB,SAAUC,WAAY,SAAUL,MAAO,OAAQC,OAAQ,QAAQV,SACzGY,EAACG,EAAe"}
@@ -1,2 +1,6 @@
1
1
  export * from './Video';
2
- export * from './hooks';
2
+ export * from './useVideoFullscreen';
3
+ export * from './useVideoPlayPause';
4
+ export * from './useVideoReady';
5
+ export * from './useVideoSoundControls';
6
+ export * from './useVideoTime';
@@ -0,0 +1,13 @@
1
+ import { type RefObject } from 'react';
2
+ interface VideoFullscreen {
3
+ /** Whether the container is currently in fullscreen mode */
4
+ isFullscreen: boolean;
5
+ /** Toggles fullscreen on/off */
6
+ handleFullscreenToggle: () => void;
7
+ }
8
+ /**
9
+ * Manages fullscreen state for a container element
10
+ * @param containerRef - A reference to the element to display in fullscreen.
11
+ */
12
+ export declare const useVideoFullscreen: (containerRef: RefObject<HTMLElement>) => VideoFullscreen;
13
+ export {};
@@ -0,0 +1,2 @@
1
+ import{useState as e,useEffect as n,useCallback as t}from"react";const r=()=>{const e=document;return document.fullscreenElement??e.webkitFullscreenElement??null},l=e=>e instanceof HTMLVideoElement?e:e?.querySelector("video")??null,c=c=>{const[u,s]=e(!1);n(()=>{const e=l(c.current),n=()=>s(r()===c.current),t=()=>s(!0),u=()=>s(!1);return document.addEventListener("fullscreenchange",n),document.addEventListener("webkitfullscreenchange",n),e?.addEventListener("webkitbeginfullscreen",t),e?.addEventListener("webkitendfullscreen",u),()=>{document.removeEventListener("fullscreenchange",n),document.removeEventListener("webkitfullscreenchange",n),e?.removeEventListener("webkitbeginfullscreen",t),e?.removeEventListener("webkitendfullscreen",u)}},[c]);return{isFullscreen:u,handleFullscreenToggle:t(()=>{const e=c?.current;if(e)if(r()===e){const e=document;document.exitFullscreen?document.exitFullscreen().catch(()=>{}):e.webkitExitFullscreen?.()}else e.requestFullscreen?e.requestFullscreen().catch(()=>{}):e.webkitRequestFullscreen?e.webkitRequestFullscreen():l(e)?.webkitEnterFullscreen?.()},[c])}};export{c as useVideoFullscreen};
2
+ //# sourceMappingURL=useVideoFullscreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVideoFullscreen.js","sources":["../../../src/components/video/useVideoFullscreen.ts"],"sourcesContent":["import { useCallback, useEffect, useState, type RefObject } from 'react';\n\ninterface VideoFullscreen {\n /** Whether the container is currently in fullscreen mode */\n isFullscreen: boolean;\n /** Toggles fullscreen on/off */\n handleFullscreenToggle: () => void;\n}\n\n/** Prefixed Fullscreen API of Safari before 16.4 */\ninterface WebkitDocument extends Document {\n webkitFullscreenElement?: Element | null;\n webkitExitFullscreen?: () => void;\n}\n\n/** Prefixed Fullscreen API of Safari before 16.4 */\ninterface WebkitElement extends HTMLElement {\n webkitRequestFullscreen?: () => void;\n}\n\n/** Native video fullscreen of iPhone Safari, which has no Fullscreen API on other elements */\ninterface WebkitVideoElement extends HTMLVideoElement {\n webkitEnterFullscreen?: () => void;\n}\n\n/**\n * Returns the element currently in fullscreen, including the prefixed Safari API\n */\nconst getFullscreenElement = (): Element | null => {\n const webkitDocument: WebkitDocument = document;\n return document.fullscreenElement ?? webkitDocument.webkitFullscreenElement ?? null;\n};\n\n/**\n * Returns the video inside the container, or the container itself when it is the video\n */\nconst getVideo = (container: HTMLElement | null): WebkitVideoElement | null =>\n container instanceof HTMLVideoElement ? container : (container?.querySelector('video') ?? null);\n\n/**\n * Manages fullscreen state for a container element\n * @param containerRef - A reference to the element to display in fullscreen.\n */\nexport const useVideoFullscreen = (containerRef: RefObject<HTMLElement>): VideoFullscreen => {\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n useEffect(() => {\n const video = getVideo(containerRef.current);\n const handleFullscreenChange = () => setIsFullscreen(getFullscreenElement() === containerRef.current);\n const handleVideoFullscreenEnter = () => setIsFullscreen(true);\n const handleVideoFullscreenExit = () => setIsFullscreen(false);\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n document.addEventListener('webkitfullscreenchange', handleFullscreenChange);\n video?.addEventListener('webkitbeginfullscreen', handleVideoFullscreenEnter);\n video?.addEventListener('webkitendfullscreen', handleVideoFullscreenExit);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);\n video?.removeEventListener('webkitbeginfullscreen', handleVideoFullscreenEnter);\n video?.removeEventListener('webkitendfullscreen', handleVideoFullscreenExit);\n };\n }, [containerRef]);\n\n const handleFullscreenToggle = useCallback(() => {\n const container: WebkitElement | null = containerRef?.current;\n if (!container) {\n return;\n }\n\n if (getFullscreenElement() === container) {\n const webkitDocument: WebkitDocument = document;\n if (document.exitFullscreen) {\n document.exitFullscreen().catch(() => {});\n } else {\n webkitDocument.webkitExitFullscreen?.();\n }\n } else if (container.requestFullscreen) {\n container.requestFullscreen().catch(() => {});\n } else if (container.webkitRequestFullscreen) {\n container.webkitRequestFullscreen();\n } else {\n // iPhone Safari shows the video in its native player, the custom controls are not visible there\n getVideo(container)?.webkitEnterFullscreen?.();\n }\n }, [containerRef]);\n\n return {\n isFullscreen,\n handleFullscreenToggle,\n };\n};\n"],"names":["getFullscreenElement","webkitDocument","document","fullscreenElement","webkitFullscreenElement","getVideo","container","HTMLVideoElement","querySelector","useVideoFullscreen","containerRef","isFullscreen","setIsFullscreen","useState","useEffect","video","current","handleFullscreenChange","handleVideoFullscreenEnter","handleVideoFullscreenExit","addEventListener","removeEventListener","handleFullscreenToggle","useCallback","exitFullscreen","catch","webkitExitFullscreen","requestFullscreen","webkitRequestFullscreen","webkitEnterFullscreen"],"mappings":"iEA4BA,MAAMA,EAAuB,KAC3B,MAAMC,EAAiCC,SACvC,OAAOA,SAASC,mBAAqBF,EAAeG,yBAA2B,MAM3EC,EAAYC,GAChBA,aAAqBC,iBAAmBD,EAAaA,GAAWE,cAAc,UAAY,KAM/EC,EAAsBC,IACjC,MAAOC,EAAcC,GAAmBC,GAAS,GAEjDC,EAAU,KACR,MAAMC,EAAQV,EAASK,EAAaM,SAC9BC,EAAyB,IAAML,EAAgBZ,MAA2BU,EAAaM,SACvFE,EAA6B,IAAMN,GAAgB,GACnDO,EAA4B,IAAMP,GAAgB,GAOxD,OALAV,SAASkB,iBAAiB,mBAAoBH,GAC9Cf,SAASkB,iBAAiB,yBAA0BH,GACpDF,GAAOK,iBAAiB,wBAAyBF,GACjDH,GAAOK,iBAAiB,sBAAuBD,GAExC,KACLjB,SAASmB,oBAAoB,mBAAoBJ,GACjDf,SAASmB,oBAAoB,yBAA0BJ,GACvDF,GAAOM,oBAAoB,wBAAyBH,GACpDH,GAAOM,oBAAoB,sBAAuBF,KAEnD,CAACT,IAyBJ,MAAO,CACLC,eACAW,uBAzB6BC,EAAY,KACzC,MAAMjB,EAAkCI,GAAcM,QACtD,GAAKV,EAIL,GAAIN,MAA2BM,EAAW,CACxC,MAAML,EAAiCC,SACnCA,SAASsB,eACXtB,SAASsB,iBAAiBC,MAAM,QAEhCxB,EAAeyB,wBAEnB,MAAWpB,EAAUqB,kBACnBrB,EAAUqB,oBAAoBF,MAAM,QAC3BnB,EAAUsB,wBACnBtB,EAAUsB,0BAGVvB,EAASC,IAAYuB,2BAEtB,CAACnB"}
@@ -0,0 +1,13 @@
1
+ import { type RefObject } from 'react';
2
+ interface PlayPause {
3
+ /** Whether the video is currently playing */
4
+ isPlaying: boolean;
5
+ /** Toggles play/pause */
6
+ handlePlayPause: () => void;
7
+ }
8
+ /**
9
+ * Manages play/pause state for a video element
10
+ * @param videoRef - A reference to the video element.
11
+ */
12
+ export declare const useVideoPlayPause: (videoRef: RefObject<HTMLVideoElement>) => PlayPause;
13
+ export {};
@@ -0,0 +1,2 @@
1
+ import{useState as e,useEffect as t,useCallback as r}from"react";const n=n=>{const[a,s]=e(!n.current?.paused);t(()=>{const e=n?.current;e&&void 0===a&&s(!e?.paused);const t=()=>{(!e.autoplay||!e.ended)&&s(!0)},r=()=>s(!1);if(e)return e.addEventListener("pause",r),s(!e.paused),e.addEventListener("play",t),()=>{e.removeEventListener("play",t),e.removeEventListener("pause",r)}},[n]);const u=r(()=>{n?.current&&(a?n.current.pause():n.current.play().catch(()=>{}),s(e=>!e))},[a,n]);return{isPlaying:a,handlePlayPause:u}};export{n as useVideoPlayPause};
2
+ //# sourceMappingURL=useVideoPlayPause.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVideoPlayPause.js","sources":["../../../src/components/video/useVideoPlayPause.ts"],"sourcesContent":["import { useCallback, useEffect, useState, type RefObject } from 'react';\n\ninterface PlayPause {\n /** Whether the video is currently playing */\n isPlaying: boolean;\n /** Toggles play/pause */\n handlePlayPause: () => void;\n}\n\n/**\n * Manages play/pause state for a video element\n * @param videoRef - A reference to the video element.\n */\nexport const useVideoPlayPause = (videoRef: RefObject<HTMLVideoElement>): PlayPause => {\n const [isPlaying, setIsPlaying] = useState(!videoRef.current?.paused);\n\n useEffect(() => {\n const video = videoRef?.current;\n\n if (video && isPlaying === undefined) {\n setIsPlaying(!video?.paused);\n }\n\n const handlePlay = () => {\n // prevent playing state when autoplay triggers play event on re-entering viewport after video ended\n !(video.autoplay && video.ended) && setIsPlaying(true);\n };\n const handlePause = () => setIsPlaying(false);\n\n if (video) {\n video.addEventListener('pause', handlePause);\n\n // Set initial state (not enough without event listeners due to autoPlay and paused race conditions)\n setIsPlaying(!video.paused);\n\n video.addEventListener('play', handlePlay);\n\n return () => {\n video.removeEventListener('play', handlePlay);\n video.removeEventListener('pause', handlePause);\n };\n }\n }, [videoRef]);\n\n const handlePlayPause = useCallback(() => {\n if (videoRef?.current) {\n if (isPlaying) {\n videoRef.current.pause();\n } else {\n videoRef.current.play().catch(() => {});\n }\n setIsPlaying((prevIsPlaying) => !prevIsPlaying);\n }\n }, [isPlaying, videoRef]);\n\n return {\n isPlaying,\n handlePlayPause,\n };\n};\n"],"names":["useVideoPlayPause","videoRef","isPlaying","setIsPlaying","useState","current","paused","useEffect","video","undefined","handlePlay","autoplay","ended","handlePause","addEventListener","removeEventListener","handlePlayPause","useCallback","pause","play","catch","prevIsPlaying"],"mappings":"iEAaO,MAAMA,EAAqBC,IAChC,MAAOC,EAAWC,GAAgBC,GAAUH,EAASI,SAASC,QAE9DC,EAAU,KACR,MAAMC,EAAQP,GAAUI,QAEpBG,QAAuBC,IAAdP,GACXC,GAAcK,GAAOF,QAGvB,MAAMI,EAAa,OAEfF,EAAMG,WAAYH,EAAMI,QAAUT,GAAa,IAE7CU,EAAc,IAAMV,GAAa,GAEvC,GAAIK,EAQF,OAPAA,EAAMM,iBAAiB,QAASD,GAGhCV,GAAcK,EAAMF,QAEpBE,EAAMM,iBAAiB,OAAQJ,GAExB,KACLF,EAAMO,oBAAoB,OAAQL,GAClCF,EAAMO,oBAAoB,QAASF,KAGtC,CAACZ,IAEJ,MAAMe,EAAkBC,EAAY,KAC9BhB,GAAUI,UACRH,EACFD,EAASI,QAAQa,QAEjBjB,EAASI,QAAQc,OAAOC,MAAM,QAEhCjB,EAAckB,IAAmBA,KAElC,CAACnB,EAAWD,IAEf,MAAO,CACLC,YACAc"}
@@ -0,0 +1,6 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Reports whether the video has loaded its metadata without an error, false while loading or after a failure
4
+ * @param videoRef - A reference to the video element.
5
+ */
6
+ export declare const useVideoReady: (videoRef: RefObject<HTMLVideoElement>) => boolean;
@@ -0,0 +1,2 @@
1
+ import{useState as e,useEffect as t}from"react";const r=r=>{const[n,d]=e(!1);return t(()=>{const e=r?.current;if(!e)return;const t=()=>d(e.readyState>=HTMLMediaElement.HAVE_METADATA&&!e.error);return t(),e.addEventListener("loadedmetadata",t),e.addEventListener("emptied",t),e.addEventListener("error",t),()=>{e.removeEventListener("loadedmetadata",t),e.removeEventListener("emptied",t),e.removeEventListener("error",t)}},[r]),n};export{r as useVideoReady};
2
+ //# sourceMappingURL=useVideoReady.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVideoReady.js","sources":["../../../src/components/video/useVideoReady.ts"],"sourcesContent":["import { useEffect, useState, type RefObject } from 'react';\n\n/**\n * Reports whether the video has loaded its metadata without an error, false while loading or after a failure\n * @param videoRef - A reference to the video element.\n */\nexport const useVideoReady = (videoRef: RefObject<HTMLVideoElement>): boolean => {\n // not ready on the server and before the first check, so the controls never flash over a broken video\n const [ready, setReady] = useState(false);\n\n useEffect(() => {\n const video = videoRef?.current;\n if (!video) {\n return;\n }\n // a failed <source> keeps readyState at HAVE_NOTHING, a failed src or a network error sets video.error\n const update = () => setReady(video.readyState >= HTMLMediaElement.HAVE_METADATA && !video.error);\n\n // the video may have loaded before hydration\n update();\n video.addEventListener('loadedmetadata', update);\n video.addEventListener('emptied', update);\n video.addEventListener('error', update);\n\n return () => {\n video.removeEventListener('loadedmetadata', update);\n video.removeEventListener('emptied', update);\n video.removeEventListener('error', update);\n };\n }, [videoRef]);\n\n return ready;\n};\n"],"names":["useVideoReady","videoRef","ready","setReady","useState","useEffect","video","current","update","readyState","HTMLMediaElement","HAVE_METADATA","error","addEventListener","removeEventListener"],"mappings":"gDAMO,MAAMA,EAAiBC,IAE5B,MAAOC,EAAOC,GAAYC,GAAS,GAuBnC,OArBAC,EAAU,KACR,MAAMC,EAAQL,GAAUM,QACxB,IAAKD,EACH,OAGF,MAAME,EAAS,IAAML,EAASG,EAAMG,YAAcC,iBAAiBC,gBAAkBL,EAAMM,OAQ3F,OALAJ,IACAF,EAAMO,iBAAiB,iBAAkBL,GACzCF,EAAMO,iBAAiB,UAAWL,GAClCF,EAAMO,iBAAiB,QAASL,GAEzB,KACLF,EAAMQ,oBAAoB,iBAAkBN,GAC5CF,EAAMQ,oBAAoB,UAAWN,GACrCF,EAAMQ,oBAAoB,QAASN,KAEpC,CAACP,IAEGC"}
@@ -0,0 +1,17 @@
1
+ import { type RefObject } from 'react';
2
+ interface SoundControls {
3
+ /** Whether the video is muted */
4
+ isMuted: boolean;
5
+ /** Toggles mute on/off */
6
+ handleMuteToggle: () => void;
7
+ /** Current volume level, 0 to 1 */
8
+ volume: number;
9
+ /** Sets the volume level */
10
+ handleVolumeChange: (newVolume: number) => void;
11
+ }
12
+ /**
13
+ * Manages mute and volume for a video element
14
+ * @param videoRef - A reference to the video element.
15
+ */
16
+ export declare const useVideoSoundControls: (videoRef: RefObject<HTMLVideoElement>) => SoundControls;
17
+ export {};
@@ -0,0 +1,2 @@
1
+ import{useState as e,useEffect as t,useCallback as r}from"react";const u=u=>{const[n,o]=e(u.current?.muted),[c,m]=e(1);t(()=>{const e=u?.current;e&&(void 0===n&&o(e?.muted),u.current.muted=n,u.current.volume=c)},[n,c,u]);const d=r(()=>{o(e=>!e)},[]),l=r(e=>{m(e)},[]);return{isMuted:n,handleMuteToggle:d,volume:c,handleVolumeChange:l}};export{u as useVideoSoundControls};
2
+ //# sourceMappingURL=useVideoSoundControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVideoSoundControls.js","sources":["../../../src/components/video/useVideoSoundControls.ts"],"sourcesContent":["import { useCallback, useEffect, useState, type RefObject } from 'react';\n\ninterface SoundControls {\n /** Whether the video is muted */\n isMuted: boolean;\n /** Toggles mute on/off */\n handleMuteToggle: () => void;\n /** Current volume level, 0 to 1 */\n volume: number;\n /** Sets the volume level */\n handleVolumeChange: (newVolume: number) => void;\n}\n\n/**\n * Manages mute and volume for a video element\n * @param videoRef - A reference to the video element.\n */\nexport const useVideoSoundControls = (videoRef: RefObject<HTMLVideoElement>): SoundControls => {\n const [isMuted, setIsMuted] = useState(videoRef.current?.muted);\n const [volume, setVolume] = useState(1);\n\n useEffect(() => {\n const video = videoRef?.current;\n if (video) {\n if (isMuted === undefined) {\n setIsMuted(video?.muted);\n }\n\n videoRef.current.muted = isMuted;\n videoRef.current.volume = volume;\n }\n }, [isMuted, volume, videoRef]);\n\n const handleMuteToggle = useCallback(() => {\n setIsMuted((prevMuted) => !prevMuted);\n }, []);\n\n const handleVolumeChange = useCallback((newVolume: number) => {\n setVolume(newVolume);\n }, []);\n\n return {\n isMuted,\n handleMuteToggle,\n volume,\n handleVolumeChange,\n };\n};\n"],"names":["useVideoSoundControls","videoRef","isMuted","setIsMuted","useState","current","muted","volume","setVolume","useEffect","video","undefined","handleMuteToggle","useCallback","prevMuted","handleVolumeChange","newVolume"],"mappings":"iEAiBO,MAAMA,EAAyBC,IACpC,MAAOC,EAASC,GAAcC,EAASH,EAASI,SAASC,QAClDC,EAAQC,GAAaJ,EAAS,GAErCK,EAAU,KACR,MAAMC,EAAQT,GAAUI,QACpBK,SACcC,IAAZT,GACFC,EAAWO,GAAOJ,OAGpBL,EAASI,QAAQC,MAAQJ,EACzBD,EAASI,QAAQE,OAASA,IAE3B,CAACL,EAASK,EAAQN,IAErB,MAAMW,EAAmBC,EAAY,KACnCV,EAAYW,IAAeA,IAC1B,IAEGC,EAAqBF,EAAaG,IACtCR,EAAUQ,IACT,IAEH,MAAO,CACLd,UACAU,mBACAL,SACAQ"}
@@ -0,0 +1,22 @@
1
+ import { type RefObject } from 'react';
2
+ export interface VideoTimeOptions {
3
+ /**
4
+ * Updates the current time every animation frame while playing, instead of the ~250ms `timeupdate` interval
5
+ */
6
+ smooth?: boolean;
7
+ }
8
+ interface VideoTime {
9
+ /** Current playback time, in seconds */
10
+ currentTime: number;
11
+ /** Total video duration, in seconds */
12
+ duration: number;
13
+ /** Seeks to a specific time */
14
+ handleSeek: (newTime: number) => void;
15
+ }
16
+ /**
17
+ * Synchronizes playback time and duration with component state
18
+ * @param videoRef - A reference to the video element.
19
+ * @param options - Additional options.
20
+ */
21
+ export declare const useVideoTime: (videoRef: RefObject<HTMLVideoElement>, { smooth }?: VideoTimeOptions) => VideoTime;
22
+ export {};
@@ -0,0 +1,2 @@
1
+ import{useState as e,useCallback as t,useEffect as r}from"react";const n=(n,{smooth:a}={})=>{const[i,u]=e(0),[o,c]=e(n.current?.duration),m=t(()=>{n.current&&u(n.current.currentTime)},[n]),d=t(e=>{n.current&&(n.current.currentTime=e),u(e)},[n]),s=t(()=>{n.current?.duration&&c(n.current.duration)},[n]);return r(()=>{const e=n?.current;if(e)return e.addEventListener("loadedmetadata",s),e.addEventListener("timeupdate",m),()=>{e.removeEventListener("loadedmetadata",s),e.removeEventListener("timeupdate",m)}},[s,m,n]),r(()=>{const e=n?.current;if(!a||!e)return;let t;const r=()=>{u(e.currentTime),t=requestAnimationFrame(r)},i=()=>{cancelAnimationFrame(t),t=requestAnimationFrame(r)},o=()=>cancelAnimationFrame(t);return e.paused||i(),e.addEventListener("play",i),e.addEventListener("pause",o),()=>{o(),e.removeEventListener("play",i),e.removeEventListener("pause",o)}},[a,n]),{currentTime:i,duration:o,handleSeek:d}};export{n as useVideoTime};
2
+ //# sourceMappingURL=useVideoTime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVideoTime.js","sources":["../../../src/components/video/useVideoTime.ts"],"sourcesContent":["import { useCallback, useEffect, useState, type RefObject } from 'react';\n\nexport interface VideoTimeOptions {\n /**\n * Updates the current time every animation frame while playing, instead of the ~250ms `timeupdate` interval\n */\n smooth?: boolean;\n}\n\ninterface VideoTime {\n /** Current playback time, in seconds */\n currentTime: number;\n /** Total video duration, in seconds */\n duration: number;\n /** Seeks to a specific time */\n handleSeek: (newTime: number) => void;\n}\n\n/**\n * Synchronizes playback time and duration with component state\n * @param videoRef - A reference to the video element.\n * @param options - Additional options.\n */\nexport const useVideoTime = (videoRef: RefObject<HTMLVideoElement>, { smooth }: VideoTimeOptions = {}): VideoTime => {\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(videoRef.current?.duration);\n\n const handleTimeUpdate = useCallback(() => {\n if (videoRef.current) {\n setCurrentTime(videoRef.current.currentTime);\n }\n }, [videoRef]);\n\n const handleSeek = useCallback(\n (newTime: number) => {\n if (videoRef.current) {\n videoRef.current.currentTime = newTime;\n }\n setCurrentTime(newTime);\n },\n [videoRef],\n );\n\n const handleLoadedMetadata = useCallback(() => {\n if (videoRef.current?.duration) {\n setDuration(videoRef.current.duration);\n }\n }, [videoRef]);\n\n useEffect(() => {\n const video = videoRef?.current;\n if (video) {\n video.addEventListener('loadedmetadata', handleLoadedMetadata);\n video.addEventListener('timeupdate', handleTimeUpdate);\n\n return () => {\n video.removeEventListener('loadedmetadata', handleLoadedMetadata);\n video.removeEventListener('timeupdate', handleTimeUpdate);\n };\n }\n }, [handleLoadedMetadata, handleTimeUpdate, videoRef]);\n\n useEffect(() => {\n const video = videoRef?.current;\n if (!smooth || !video) {\n return;\n }\n let frame: number;\n const update = () => {\n setCurrentTime(video.currentTime);\n frame = requestAnimationFrame(update);\n };\n const start = () => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(update);\n };\n const stop = () => cancelAnimationFrame(frame);\n\n if (!video.paused) {\n start();\n }\n video.addEventListener('play', start);\n video.addEventListener('pause', stop);\n\n return () => {\n stop();\n video.removeEventListener('play', start);\n video.removeEventListener('pause', stop);\n };\n }, [smooth, videoRef]);\n\n return {\n currentTime,\n duration,\n handleSeek,\n };\n};\n"],"names":["useVideoTime","videoRef","smooth","currentTime","setCurrentTime","useState","duration","setDuration","current","handleTimeUpdate","useCallback","handleSeek","newTime","handleLoadedMetadata","useEffect","video","addEventListener","removeEventListener","frame","update","requestAnimationFrame","start","cancelAnimationFrame","stop","paused"],"mappings":"iEAuBO,MAAMA,EAAe,CAACC,GAAyCC,UAA6B,CAAA,KACjG,MAAOC,EAAaC,GAAkBC,EAAS,IACxCC,EAAUC,GAAeF,EAASJ,EAASO,SAASF,UAErDG,EAAmBC,EAAY,KAC/BT,EAASO,SACXJ,EAAeH,EAASO,QAAQL,cAEjC,CAACF,IAEEU,EAAaD,EAChBE,IACKX,EAASO,UACXP,EAASO,QAAQL,YAAcS,GAEjCR,EAAeQ,IAEjB,CAACX,IAGGY,EAAuBH,EAAY,KACnCT,EAASO,SAASF,UACpBC,EAAYN,EAASO,QAAQF,WAE9B,CAACL,IA4CJ,OA1CAa,EAAU,KACR,MAAMC,EAAQd,GAAUO,QACxB,GAAIO,EAIF,OAHAA,EAAMC,iBAAiB,iBAAkBH,GACzCE,EAAMC,iBAAiB,aAAcP,GAE9B,KACLM,EAAME,oBAAoB,iBAAkBJ,GAC5CE,EAAME,oBAAoB,aAAcR,KAG3C,CAACI,EAAsBJ,EAAkBR,IAE5Ca,EAAU,KACR,MAAMC,EAAQd,GAAUO,QACxB,IAAKN,IAAWa,EACd,OAEF,IAAIG,EACJ,MAAMC,EAAS,KACbf,EAAeW,EAAMZ,aACrBe,EAAQE,sBAAsBD,IAE1BE,EAAQ,KACZC,qBAAqBJ,GACrBA,EAAQE,sBAAsBD,IAE1BI,EAAO,IAAMD,qBAAqBJ,GAQxC,OANKH,EAAMS,QACTH,IAEFN,EAAMC,iBAAiB,OAAQK,GAC/BN,EAAMC,iBAAiB,QAASO,GAEzB,KACLA,IACAR,EAAME,oBAAoB,OAAQI,GAClCN,EAAME,oBAAoB,QAASM,KAEpC,CAACrB,EAAQD,IAEL,CACLE,cACAG,WACAK"}
@@ -0,0 +1,125 @@
1
+ import React, { ElementType, type ReactNode } from 'react';
2
+ import { BoxProps } from '@mui/material';
3
+ import { OverlayProps } from '../overlay/Overlay';
4
+ import { VideoPlayerPlayPauseButtonProps } from './VideoPlayerPlayPauseButton';
5
+ import { VideoPlayerSkipButtonProps } from './VideoPlayerSkipButton';
6
+ import { VideoPlayerSoundButtonProps } from './VideoPlayerSoundButton';
7
+ import { VideoPlayerFullscreenButtonProps } from './VideoPlayerFullscreenButton';
8
+ import { VideoPlayerSliderProps } from './VideoPlayerSlider';
9
+ import { VideoPlayerTimeProps } from './VideoPlayerTime';
10
+ export interface VideoPlayerProps extends BoxProps<ElementType> {
11
+ /**
12
+ * Video component to be controlled
13
+ */
14
+ children: ReactNode;
15
+ /**
16
+ * Inactivity in ms after which the controls hide while the video is playing
17
+ * @default 3000
18
+ */
19
+ hideDelay?: number;
20
+ /**
21
+ * Inactivity in ms after which the controls hide while the video is playing in fullscreen
22
+ * @default 1000
23
+ */
24
+ fullscreenHideDelay?: number;
25
+ /**
26
+ * Keeps the controls always visible
27
+ */
28
+ disableAutoHide?: boolean;
29
+ /**
30
+ * Callback of the skip-previous button, the button is hidden when not provided
31
+ */
32
+ onSkipPrevious?: () => void;
33
+ /**
34
+ * Callback of the skip-next button, the button is hidden when not provided
35
+ */
36
+ onSkipNext?: () => void;
37
+ /**
38
+ * Hides the sound button
39
+ */
40
+ disableSound?: boolean;
41
+ /**
42
+ * Hides the play/pause button
43
+ */
44
+ disablePlayPause?: boolean;
45
+ /**
46
+ * Hides the current time and duration
47
+ */
48
+ disableTime?: boolean;
49
+ /**
50
+ * Hides the seek slider
51
+ */
52
+ disableSlider?: boolean;
53
+ /**
54
+ * Hides the fullscreen button and disables fullscreen on double click
55
+ */
56
+ disableFullscreen?: boolean;
57
+ /**
58
+ * ReactNode that renders custom buttons between the playback and sound buttons. If multiple buttons are needed, wrap them in React.Fragment
59
+ */
60
+ startButtons?: ReactNode;
61
+ /**
62
+ * ReactNode that renders custom buttons before the fullscreen button. If multiple buttons are needed, wrap them in React.Fragment
63
+ */
64
+ endButtons?: ReactNode;
65
+ /**
66
+ * Properties passed to the Overlay component
67
+ */
68
+ overlayProps?: Omit<OverlayProps, 'overlayContent' | 'wrapperProps' | 'children'>;
69
+ /**
70
+ * Properties passed to the VideoPlayerPlayPauseButton component
71
+ */
72
+ playPauseButtonProps?: Omit<VideoPlayerPlayPauseButtonProps, 'videoRef'>;
73
+ /**
74
+ * Properties passed to the skip-previous VideoPlayerSkipButton component
75
+ */
76
+ skipPreviousButtonProps?: Omit<VideoPlayerSkipButtonProps, 'direction'>;
77
+ /**
78
+ * Properties passed to the skip-next VideoPlayerSkipButton component
79
+ */
80
+ skipNextButtonProps?: Omit<VideoPlayerSkipButtonProps, 'direction'>;
81
+ /**
82
+ * Properties passed to the VideoPlayerSoundButton component
83
+ */
84
+ soundButtonProps?: Omit<VideoPlayerSoundButtonProps, 'videoRef'>;
85
+ /**
86
+ * Properties passed to the VideoPlayerFullscreenButton component
87
+ */
88
+ fullscreenButtonProps?: Omit<VideoPlayerFullscreenButtonProps, 'containerRef'>;
89
+ /**
90
+ * Properties passed to the VideoPlayerSlider component
91
+ */
92
+ sliderProps?: Omit<VideoPlayerSliderProps, 'videoRef'>;
93
+ /**
94
+ * Properties passed to the VideoPlayerTime component
95
+ */
96
+ timeProps?: Omit<VideoPlayerTimeProps, 'videoRef'>;
97
+ /**
98
+ * Properties applied to the wrapper of playback buttons centered over the video on mobile
99
+ */
100
+ centerWrapperProps?: BoxProps<ElementType>;
101
+ /**
102
+ * Properties applied to the bar at the bottom, wrapping the slider and the toolbar
103
+ */
104
+ barProps?: BoxProps<ElementType>;
105
+ /**
106
+ * Properties applied to the toolbar below the slider
107
+ */
108
+ toolbarProps?: BoxProps<ElementType>;
109
+ /**
110
+ * Properties applied to the wrapper of playback buttons in the toolbar on desktop
111
+ */
112
+ playbackWrapperProps?: BoxProps<ElementType>;
113
+ /**
114
+ * Properties applied to the wrapper of buttons at the start of the toolbar
115
+ */
116
+ startButtonsWrapperProps?: BoxProps<ElementType>;
117
+ /**
118
+ * Properties applied to the wrapper of buttons at the end of the toolbar, filling its free space
119
+ */
120
+ endButtonsWrapperProps?: BoxProps<ElementType>;
121
+ }
122
+ /**
123
+ * Video player controls with play/pause, sound, seek and fullscreen buttons over the Video component
124
+ */
125
+ export declare const VideoPlayer: React.FC<VideoPlayerProps>;
@@ -0,0 +1,2 @@
1
+ import{jsxs as e,jsx as t,Fragment as o}from"react/jsx-runtime";import{forwardRef as i,useRef as r,useCallback as n}from"react";import{useForkRef as s,Box as a}from"@mui/material";import{sxOverride as l}from"../../utils/sxOverride/sxOverride.js";import{Overlay as d}from"../overlay/Overlay.js";import{VideoPlayerPlayPauseButton as p}from"./VideoPlayerPlayPauseButton.js";import{VideoPlayerSkipButton as u}from"./VideoPlayerSkipButton.js";import{VideoPlayerSoundButton as c}from"./VideoPlayerSoundButton.js";import{VideoPlayerFullscreenButton as m}from"./VideoPlayerFullscreenButton.js";import{VideoPlayerSlider as y}from"./VideoPlayerSlider.js";import{VideoPlayerTime as P}from"./VideoPlayerTime.js";import{useVideoPlayerVisibility as f}from"./useVideoPlayerVisibility.js";import{useVideoReady as x}from"../video/useVideoReady.js";import{useVideoFullscreen as b}from"../video/useVideoFullscreen.js";import{ControlsPlayFilledIcon as v}from"../icon/filled/ControlsPlayFilledIcon.js";import{ControlsPauseFilledIcon as V}from"../icon/filled/ControlsPauseFilledIcon.js";const h=i(({children:i,hideDelay:h=3e3,fullscreenHideDelay:k=1e3,disableAutoHide:j,onSkipPrevious:C,onSkipNext:g,disableSound:B,disablePlayPause:S,disableTime:D,disableSlider:I,disableFullscreen:F,startButtons:R,endButtons:E,overlayProps:T,playPauseButtonProps:w,skipPreviousButtonProps:z,skipNextButtonProps:W,soundButtonProps:L,fullscreenButtonProps:O,sliderProps:A,timeProps:H,centerWrapperProps:K,barProps:M,toolbarProps:N,playbackWrapperProps:q,startButtonsWrapperProps:G,endButtonsWrapperProps:J,onClick:Q,onDoubleClick:U,onPointerMove:X,onPointerDown:Y,onPointerLeave:Z,onKeyDown:$,sx:_,...ee},te)=>{const oe=r(null),ie=r(null),re=n(e=>{oe.current=e,ie.current=e?.querySelector("video")??null},[]),ne=s(re,te),{isFullscreen:se,handleFullscreenToggle:ae}=b(oe),{visible:le,handleActivity:de,handleLeave:pe}=f(ie,{hideDelay:se?k:h,disabled:j}),ue=x(ie),ce=({target:e,currentTarget:t})=>e===ie.current||e instanceof Element&&e.parentElement===t,me=r(!1),{sx:ye,...Pe}=T??{},{sx:fe,...xe}=K??{},{sx:be,...ve}=M??{},{sx:Ve,...he}=N??{},{sx:ke,...je}=q??{},{sx:Ce,...ge}=G??{},{sx:Be,...Se}=J??{},{sx:De,...Ie}=H??{},Fe=i=>e(o,{children:[C&&t(u,{direction:"previous",size:"medium",...z,onClick:e=>{z?.onClick?.(e),C()}}),!S&&t(p,{videoRef:ie,size:"medium",...i&&{PlayIconComponent:v,PauseIconComponent:V},...w}),g&&t(u,{direction:"next",size:"medium",...W,onClick:e=>{W?.onClick?.(e),g()}})]});return e(d,{"data-testid":"VideoPlayer.overlay","data-visible":le,overlayContent:i,wrapperProps:{ref:ne,"data-testid":"VideoPlayer",sx:l({...!le&&{cursor:"none"}},_),onClick:e=>{Q?.(e);const t=ie.current;t&&ue&&ce(e)&&!me.current&&(t.paused?t.play().catch(()=>{}):t.pause())},onDoubleClick:e=>{U?.(e),!F&&ue&&ce(e)&&ae()},onPointerMove:e=>{X?.(e),de()},onPointerDown:e=>{Y?.(e),me.current="touch"===e.pointerType&&!le,de()},onKeyDown:e=>{$?.(e),de()},onPointerLeave:e=>{Z?.(e),"mouse"===e.pointerType&&pe()},...ee},sx:l({transition:"opacity 0.3s ease-out",backgroundRepeat:"no-repeat",backgroundPosition:"bottom",backgroundSize:{xs:"100% 100%",md:"100% 136px"},...!le&&{opacity:"0",pointerEvents:"none","&:has(:focus-visible)":{opacity:"1",pointerEvents:"auto"}},...!ue&&{display:"none"}},ye),...Pe,children:[t(a,{"data-testid":"VideoPlayer.center",sx:l({position:"absolute",inset:"0",display:{xs:"flex",md:"none"},alignItems:"center",justifyContent:"center",gap:2,'&:has(+ * :is([data-testid="VideoPlayerSeekSlider"], [data-testid="VideoPlayer.start"] > :not([data-testid="VideoPlayer.playback"]), [data-testid="VideoPlayer.end"] > *))':{mb:4,"@media (orientation: portrait)":{"*:fullscreen &":{mb:0}}},pointerEvents:"none","& > *":{pointerEvents:"auto"}},fe),...xe,children:Fe(!0)}),e(a,{"data-testid":"VideoPlayer.bar",sx:l({position:"absolute",insetInline:"0",bottom:"0",display:"flex",flexDirection:"column",alignItems:"stretch",justifyContent:"flex-start",px:{xs:2,md:3},pb:{xs:.5,md:1}},be),...ve,children:[!I&&t(y,{videoRef:ie,...A}),e(a,{"data-testid":"VideoPlayer.toolbar",sx:l({display:"flex",alignItems:"center",justifyContent:"flex-start",gap:{xs:.5,md:1}},Ve),...he,children:[e(a,{"data-testid":"VideoPlayer.start",sx:l({display:"flex",alignItems:"center",justifyContent:"flex-start",gap:"inherit"},Ce),...ge,children:[t(a,{"data-testid":"VideoPlayer.playback",sx:l({display:{xs:"none",md:"contents"}},ke),...je,children:Fe(!1)}),R,!B&&t(c,{videoRef:ie,...L}),!D&&t(P,{videoRef:ie,sx:l({order:{xs:"-1",md:"0"}},De),...Ie})]}),e(a,{"data-testid":"VideoPlayer.end",sx:l({flex:"1",display:"flex",alignItems:"center",justifyContent:"flex-end",gap:"inherit"},Be),...Se,children:[E,!F&&t(m,{containerRef:oe,...O})]})]})]})]})});export{h as VideoPlayer};
2
+ //# sourceMappingURL=VideoPlayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoPlayer.js","sources":["../../../src/components/videoPlayer/VideoPlayer.tsx"],"sourcesContent":["import React, {\n ElementType,\n forwardRef,\n type KeyboardEvent,\n type MouseEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n useCallback,\n useRef,\n} from 'react';\nimport { Box, BoxProps, useForkRef } from '@mui/material';\nimport { sxOverride } from '@/src/utils/sxOverride';\nimport { Overlay, OverlayProps } from '@/src/components/overlay/Overlay';\nimport { VideoPlayerPlayPauseButton, VideoPlayerPlayPauseButtonProps } from './VideoPlayerPlayPauseButton';\nimport { VideoPlayerSkipButton, VideoPlayerSkipButtonProps } from './VideoPlayerSkipButton';\nimport { VideoPlayerSoundButton, VideoPlayerSoundButtonProps } from './VideoPlayerSoundButton';\nimport { VideoPlayerFullscreenButton, VideoPlayerFullscreenButtonProps } from './VideoPlayerFullscreenButton';\nimport { VideoPlayerSlider, VideoPlayerSliderProps } from './VideoPlayerSlider';\nimport { VideoPlayerTime, VideoPlayerTimeProps } from './VideoPlayerTime';\nimport { useVideoPlayerVisibility } from './useVideoPlayerVisibility';\nimport { useVideoReady } from '@/src/components/video/useVideoReady';\nimport { useVideoFullscreen } from '@/src/components/video/useVideoFullscreen';\nimport { ControlsPlayFilledIcon } from '@/src/components/icon/filled/ControlsPlayFilledIcon';\nimport { ControlsPauseFilledIcon } from '@/src/components/icon/filled/ControlsPauseFilledIcon';\n\nexport interface VideoPlayerProps extends BoxProps<ElementType> {\n /**\n * Video component to be controlled\n */\n children: ReactNode;\n /**\n * Inactivity in ms after which the controls hide while the video is playing\n * @default 3000\n */\n hideDelay?: number;\n /**\n * Inactivity in ms after which the controls hide while the video is playing in fullscreen\n * @default 1000\n */\n fullscreenHideDelay?: number;\n /**\n * Keeps the controls always visible\n */\n disableAutoHide?: boolean;\n /**\n * Callback of the skip-previous button, the button is hidden when not provided\n */\n onSkipPrevious?: () => void;\n /**\n * Callback of the skip-next button, the button is hidden when not provided\n */\n onSkipNext?: () => void;\n /**\n * Hides the sound button\n */\n disableSound?: boolean;\n /**\n * Hides the play/pause button\n */\n disablePlayPause?: boolean;\n /**\n * Hides the current time and duration\n */\n disableTime?: boolean;\n /**\n * Hides the seek slider\n */\n disableSlider?: boolean;\n /**\n * Hides the fullscreen button and disables fullscreen on double click\n */\n disableFullscreen?: boolean;\n /**\n * ReactNode that renders custom buttons between the playback and sound buttons. If multiple buttons are needed, wrap them in React.Fragment\n */\n startButtons?: ReactNode;\n /**\n * ReactNode that renders custom buttons before the fullscreen button. If multiple buttons are needed, wrap them in React.Fragment\n */\n endButtons?: ReactNode;\n /**\n * Properties passed to the Overlay component\n */\n overlayProps?: Omit<OverlayProps, 'overlayContent' | 'wrapperProps' | 'children'>;\n /**\n * Properties passed to the VideoPlayerPlayPauseButton component\n */\n playPauseButtonProps?: Omit<VideoPlayerPlayPauseButtonProps, 'videoRef'>;\n /**\n * Properties passed to the skip-previous VideoPlayerSkipButton component\n */\n skipPreviousButtonProps?: Omit<VideoPlayerSkipButtonProps, 'direction'>;\n /**\n * Properties passed to the skip-next VideoPlayerSkipButton component\n */\n skipNextButtonProps?: Omit<VideoPlayerSkipButtonProps, 'direction'>;\n /**\n * Properties passed to the VideoPlayerSoundButton component\n */\n soundButtonProps?: Omit<VideoPlayerSoundButtonProps, 'videoRef'>;\n /**\n * Properties passed to the VideoPlayerFullscreenButton component\n */\n fullscreenButtonProps?: Omit<VideoPlayerFullscreenButtonProps, 'containerRef'>;\n /**\n * Properties passed to the VideoPlayerSlider component\n */\n sliderProps?: Omit<VideoPlayerSliderProps, 'videoRef'>;\n /**\n * Properties passed to the VideoPlayerTime component\n */\n timeProps?: Omit<VideoPlayerTimeProps, 'videoRef'>;\n /**\n * Properties applied to the wrapper of playback buttons centered over the video on mobile\n */\n centerWrapperProps?: BoxProps<ElementType>;\n /**\n * Properties applied to the bar at the bottom, wrapping the slider and the toolbar\n */\n barProps?: BoxProps<ElementType>;\n /**\n * Properties applied to the toolbar below the slider\n */\n toolbarProps?: BoxProps<ElementType>;\n /**\n * Properties applied to the wrapper of playback buttons in the toolbar on desktop\n */\n playbackWrapperProps?: BoxProps<ElementType>;\n /**\n * Properties applied to the wrapper of buttons at the start of the toolbar\n */\n startButtonsWrapperProps?: BoxProps<ElementType>;\n /**\n * Properties applied to the wrapper of buttons at the end of the toolbar, filling its free space\n */\n endButtonsWrapperProps?: BoxProps<ElementType>;\n}\n\n/**\n * Video player controls with play/pause, sound, seek and fullscreen buttons over the Video component\n */\nexport const VideoPlayer: React.FC<VideoPlayerProps> = forwardRef(\n (\n {\n children,\n // common inactivity before players hide their controls\n hideDelay = 3000,\n // shorter in fullscreen, where the controls cover the whole screen\n fullscreenHideDelay = 1000,\n disableAutoHide,\n onSkipPrevious,\n onSkipNext,\n disableSound,\n disablePlayPause,\n disableTime,\n disableSlider,\n disableFullscreen,\n startButtons,\n endButtons,\n overlayProps,\n playPauseButtonProps,\n skipPreviousButtonProps,\n skipNextButtonProps,\n soundButtonProps,\n fullscreenButtonProps,\n sliderProps,\n timeProps,\n centerWrapperProps,\n barProps,\n toolbarProps,\n playbackWrapperProps,\n startButtonsWrapperProps,\n endButtonsWrapperProps,\n onClick,\n onDoubleClick,\n onPointerMove,\n onPointerDown,\n onPointerLeave,\n onKeyDown,\n sx,\n ...rest\n },\n ref,\n ) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const videoRef = useRef<HTMLVideoElement | null>(null);\n\n // refs attach before any effect runs, so the parts subscribe to the video passed as children\n const handleContainerRef = useCallback((node: HTMLDivElement | null) => {\n containerRef.current = node;\n videoRef.current = node?.querySelector('video') ?? null;\n }, []);\n const handleRef = useForkRef(handleContainerRef, ref);\n\n const { isFullscreen, handleFullscreenToggle } = useVideoFullscreen(containerRef);\n\n const { visible, handleActivity, handleLeave } = useVideoPlayerVisibility(videoRef, {\n hideDelay: isFullscreen ? fullscreenHideDelay : hideDelay,\n disabled: disableAutoHide,\n });\n\n const ready = useVideoReady(videoRef);\n\n // only the video or the overlay above it react to clicks, not the controls\n const isVideoArea = ({ target, currentTarget }: MouseEvent<HTMLDivElement>) =>\n target === videoRef.current || (target instanceof Element && target.parentElement === currentTarget);\n\n // a touch tap on hidden controls only shows them, pointerdown already shows them before the click arrives\n const revealTapRef = useRef(false);\n\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n onClick?.(event);\n const video = videoRef.current;\n if (!video || !ready || !isVideoArea(event) || revealTapRef.current) {\n return;\n }\n if (video.paused) {\n video.play().catch(() => {});\n } else {\n video.pause();\n }\n };\n\n const { sx: overlaySx, ...restOverlay } = overlayProps ?? {};\n const { sx: centerWrapperSx, ...restCenterWrapper } = centerWrapperProps ?? {};\n const { sx: barSx, ...restBar } = barProps ?? {};\n const { sx: toolbarSx, ...restToolbar } = toolbarProps ?? {};\n const { sx: playbackWrapperSx, ...restPlaybackWrapper } = playbackWrapperProps ?? {};\n const { sx: startButtonsWrapperSx, ...restStartButtonsWrapper } = startButtonsWrapperProps ?? {};\n const { sx: endButtonsWrapperSx, ...restEndButtonsWrapper } = endButtonsWrapperProps ?? {};\n const { sx: timeSx, ...restTime } = timeProps ?? {};\n\n // playback buttons keep the medium size on mobile, where they are centered over the video\n const renderPlaybackButtons = (centered: boolean) => (\n <>\n {onSkipPrevious && (\n <VideoPlayerSkipButton\n direction=\"previous\"\n size=\"medium\"\n {...skipPreviousButtonProps}\n onClick={(event: MouseEvent<HTMLButtonElement>) => {\n skipPreviousButtonProps?.onClick?.(event);\n onSkipPrevious();\n }}\n />\n )}\n {!disablePlayPause && (\n <VideoPlayerPlayPauseButton\n videoRef={videoRef}\n size=\"medium\"\n // the centered button over the video on mobile has filled icons\n {...(centered && {\n PlayIconComponent: ControlsPlayFilledIcon,\n PauseIconComponent: ControlsPauseFilledIcon,\n })}\n {...playPauseButtonProps}\n />\n )}\n {onSkipNext && (\n <VideoPlayerSkipButton\n direction=\"next\"\n size=\"medium\"\n {...skipNextButtonProps}\n onClick={(event: MouseEvent<HTMLButtonElement>) => {\n skipNextButtonProps?.onClick?.(event);\n onSkipNext();\n }}\n />\n )}\n </>\n );\n\n return (\n <Overlay\n data-testid=\"VideoPlayer.overlay\"\n data-visible={visible}\n overlayContent={children}\n wrapperProps={{\n ref: handleRef,\n 'data-testid': 'VideoPlayer',\n sx: sxOverride(\n {\n ...(!visible && {\n cursor: 'none',\n }),\n },\n sx,\n ),\n onClick: handleClick,\n onDoubleClick: (event: MouseEvent<HTMLDivElement>) => {\n onDoubleClick?.(event);\n if (!disableFullscreen && ready && isVideoArea(event)) {\n handleFullscreenToggle();\n }\n },\n onPointerMove: (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerMove?.(event);\n handleActivity();\n },\n onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n revealTapRef.current = event.pointerType === 'touch' && !visible;\n handleActivity();\n },\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n handleActivity();\n },\n onPointerLeave: (event: ReactPointerEvent<HTMLDivElement>) => {\n onPointerLeave?.(event);\n // touch fires pointerleave right after each tap, only a mouse can actually leave\n if (event.pointerType === 'mouse') {\n handleLeave();\n }\n },\n ...rest,\n }}\n sx={sxOverride(\n {\n transition: 'opacity 0.3s ease-out',\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'bottom',\n // twice the height of the bar (68px) on desktop, mobile keeps it over the whole video for centered buttons\n backgroundSize: { xs: '100% 100%', md: '100% 136px' },\n ...(!visible && {\n opacity: '0',\n // pointer reaches the video, any activity over it shows the controls again\n pointerEvents: 'none',\n // keyboard focus keeps the controls shown, focus after a mouse click is not visible\n '&:has(:focus-visible)': {\n opacity: '1',\n pointerEvents: 'auto',\n },\n }),\n // no controls over a loading or broken video, display none also keeps them out of keyboard focus\n ...(!ready && {\n display: 'none',\n }),\n },\n overlaySx,\n )}\n {...restOverlay}\n >\n <Box\n data-testid=\"VideoPlayer.center\"\n sx={sxOverride(\n {\n // on mobile playback buttons are centered over the video\n position: 'absolute',\n inset: '0',\n display: { xs: 'flex', md: 'none' },\n alignItems: 'center',\n justifyContent: 'center',\n gap: 2,\n // lifted above the bar only when it shows the slider or a toolbar item, the hidden playback wrapper does not count\n '&:has(+ * :is([data-testid=\"VideoPlayerSeekSlider\"], [data-testid=\"VideoPlayer.start\"] > :not([data-testid=\"VideoPlayer.playback\"]), [data-testid=\"VideoPlayer.end\"] > *))':\n {\n mb: 4,\n // portrait fullscreen letterboxes the video, the bar sits below it and nothing overlaps,\n // the fullscreen player is the viewport, so the media query matches its own orientation\n '@media (orientation: portrait)': {\n '*:fullscreen &': {\n mb: 0,\n },\n },\n },\n // keep the video clickable around the buttons\n pointerEvents: 'none',\n '& > *': {\n pointerEvents: 'auto',\n },\n },\n centerWrapperSx,\n )}\n {...restCenterWrapper}\n >\n {renderPlaybackButtons(true)}\n </Box>\n <Box\n data-testid=\"VideoPlayer.bar\"\n sx={sxOverride(\n {\n position: 'absolute',\n insetInline: '0',\n bottom: '0',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'stretch',\n justifyContent: 'flex-start',\n px: { xs: 2, md: 3 },\n // the slider has its own space above the track\n pb: { xs: 0.5, md: 1 },\n },\n barSx,\n )}\n {...restBar}\n >\n {!disableSlider && <VideoPlayerSlider videoRef={videoRef} {...sliderProps} />}\n <Box\n data-testid=\"VideoPlayer.toolbar\"\n sx={sxOverride(\n {\n // no padding, the toolbar collapses on mobile when nothing but centered playback buttons is in it\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-start',\n gap: { xs: 0.5, md: 1 },\n },\n toolbarSx,\n )}\n {...restToolbar}\n >\n <Box\n data-testid=\"VideoPlayer.start\"\n sx={sxOverride(\n { display: 'flex', alignItems: 'center', justifyContent: 'flex-start', gap: 'inherit' },\n startButtonsWrapperSx,\n )}\n {...restStartButtonsWrapper}\n >\n <Box\n data-testid=\"VideoPlayer.playback\"\n sx={sxOverride({ display: { xs: 'none', md: 'contents' } }, playbackWrapperSx)}\n {...restPlaybackWrapper}\n >\n {renderPlaybackButtons(false)}\n </Box>\n {startButtons}\n {!disableSound && <VideoPlayerSoundButton videoRef={videoRef} {...soundButtonProps} />}\n {!disableTime && (\n <VideoPlayerTime\n videoRef={videoRef}\n sx={sxOverride(\n {\n // on mobile the time comes first, before the start and sound buttons\n order: { xs: '-1', md: '0' },\n },\n timeSx,\n )}\n {...restTime}\n />\n )}\n </Box>\n <Box\n data-testid=\"VideoPlayer.end\"\n sx={sxOverride(\n {\n // pushes the end buttons to the right side, while also wrapping them\n flex: '1',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n gap: 'inherit',\n },\n endButtonsWrapperSx,\n )}\n {...restEndButtonsWrapper}\n >\n {endButtons}\n {!disableFullscreen && (\n <VideoPlayerFullscreenButton containerRef={containerRef} {...fullscreenButtonProps} />\n )}\n </Box>\n </Box>\n </Box>\n </Overlay>\n );\n },\n);\n"],"names":["VideoPlayer","forwardRef","children","hideDelay","fullscreenHideDelay","disableAutoHide","onSkipPrevious","onSkipNext","disableSound","disablePlayPause","disableTime","disableSlider","disableFullscreen","startButtons","endButtons","overlayProps","playPauseButtonProps","skipPreviousButtonProps","skipNextButtonProps","soundButtonProps","fullscreenButtonProps","sliderProps","timeProps","centerWrapperProps","barProps","toolbarProps","playbackWrapperProps","startButtonsWrapperProps","endButtonsWrapperProps","onClick","onDoubleClick","onPointerMove","onPointerDown","onPointerLeave","onKeyDown","sx","rest","ref","containerRef","useRef","videoRef","handleContainerRef","useCallback","node","current","querySelector","handleRef","useForkRef","isFullscreen","handleFullscreenToggle","useVideoFullscreen","visible","handleActivity","handleLeave","useVideoPlayerVisibility","disabled","ready","useVideoReady","isVideoArea","target","currentTarget","Element","parentElement","revealTapRef","overlaySx","restOverlay","centerWrapperSx","restCenterWrapper","barSx","restBar","toolbarSx","restToolbar","playbackWrapperSx","restPlaybackWrapper","startButtonsWrapperSx","restStartButtonsWrapper","endButtonsWrapperSx","restEndButtonsWrapper","timeSx","restTime","renderPlaybackButtons","centered","_jsxs","_Fragment","_jsx","VideoPlayerSkipButton","direction","size","event","VideoPlayerPlayPauseButton","PlayIconComponent","ControlsPlayFilledIcon","PauseIconComponent","ControlsPauseFilledIcon","Overlay","overlayContent","wrapperProps","sxOverride","cursor","video","paused","play","catch","pause","pointerType","transition","backgroundRepeat","backgroundPosition","backgroundSize","xs","md","opacity","pointerEvents","display","Box","position","inset","alignItems","justifyContent","gap","mb","insetInline","bottom","flexDirection","px","pb","VideoPlayerSlider","VideoPlayerSoundButton","VideoPlayerTime","order","flex","VideoPlayerFullscreenButton"],"mappings":"+iCA6IaA,EAA0CC,EACrD,EAEIC,WAEAC,YAAY,IAEZC,sBAAsB,IACtBC,kBACAC,iBACAC,aACAC,eACAC,mBACAC,cACAC,gBACAC,oBACAC,eACAC,aACAC,eACAC,uBACAC,0BACAC,sBACAC,mBACAC,wBACAC,cACAC,YACAC,qBACAC,WACAC,eACAC,uBACAC,2BACAC,yBACAC,UACAC,gBACAC,gBACAC,gBACAC,iBACAC,YACAC,QACGC,IAELC,MAEA,MAAMC,GAAeC,EAA8B,MAC7CC,GAAWD,EAAgC,MAG3CE,GAAqBC,EAAaC,IACtCL,GAAaM,QAAUD,EACvBH,GAASI,QAAUD,GAAME,cAAc,UAAY,MAClD,IACGC,GAAYC,EAAWN,GAAoBJ,KAE3CW,aAAEA,GAAYC,uBAAEA,IAA2BC,EAAmBZ,KAE9Da,QAAEA,GAAOC,eAAEA,GAAcC,YAAEA,IAAgBC,EAAyBd,GAAU,CAClFrC,UAAW6C,GAAe5C,EAAsBD,EAChDoD,SAAUlD,IAGNmD,GAAQC,EAAcjB,IAGtBkB,GAAc,EAAGC,SAAQC,mBAC7BD,IAAWnB,GAASI,SAAYe,aAAkBE,SAAWF,EAAOG,gBAAkBF,EAGlFG,GAAexB,GAAO,IAepBJ,GAAI6B,MAAcC,IAAgBlD,GAAgB,CAAA,GAClDoB,GAAI+B,MAAoBC,IAAsB5C,GAAsB,CAAA,GACpEY,GAAIiC,MAAUC,IAAY7C,GAAY,CAAA,GACtCW,GAAImC,MAAcC,IAAgB9C,GAAgB,CAAA,GAClDU,GAAIqC,MAAsBC,IAAwB/C,GAAwB,CAAA,GAC1ES,GAAIuC,MAA0BC,IAA4BhD,GAA4B,CAAA,GACtFQ,GAAIyC,MAAwBC,IAA0BjD,GAA0B,CAAA,GAChFO,GAAI2C,MAAWC,IAAazD,GAAa,CAAA,EAG3C0D,GAAyBC,GAC7BC,EAAAC,EAAA,CAAAjF,SAAA,CACGI,GACC8E,EAACC,EAAqB,CACpBC,UAAU,WACVC,KAAK,YACDtE,EACJY,QAAU2D,IACRvE,GAAyBY,UAAU2D,GACnClF,QAIJG,GACA2E,EAACK,EAA0B,CACzBjD,SAAUA,GACV+C,KAAK,YAEAN,GAAY,CACfS,kBAAmBC,EACnBC,mBAAoBC,MAElB7E,IAGPT,GACC6E,EAACC,EAAqB,CACpBC,UAAU,OACVC,KAAK,YACDrE,EACJW,QAAU2D,IACRtE,GAAqBW,UAAU2D,GAC/BjF,UAOV,OACE2E,EAACY,EAAO,CAAA,cACM,sBAAqB,eACnB3C,GACd4C,eAAgB7F,EAChB8F,aAAc,CACZ3D,IAAKS,GACL,cAAe,cACfX,GAAI8D,EACF,KACO9C,IAAW,CACd+C,OAAQ,SAGZ/D,GAEFN,QA9Ee2D,IACnB3D,IAAU2D,GACV,MAAMW,EAAQ3D,GAASI,QAClBuD,GAAU3C,IAAUE,GAAY8B,KAAUzB,GAAanB,UAGxDuD,EAAMC,OACRD,EAAME,OAAOC,MAAM,QAEnBH,EAAMI,UAsEJzE,cAAgB0D,IACd1D,IAAgB0D,IACX5E,GAAqB4C,IAASE,GAAY8B,IAC7CvC,MAGJlB,cAAgByD,IACdzD,IAAgByD,GAChBpC,MAEFpB,cAAgBwD,IACdxD,IAAgBwD,GAChBzB,GAAanB,QAAgC,UAAtB4C,EAAMgB,cAA4BrD,GACzDC,MAEFlB,UAAYsD,IACVtD,IAAYsD,GACZpC,MAEFnB,eAAiBuD,IACfvD,IAAiBuD,GAES,UAAtBA,EAAMgB,aACRnD,SAGDjB,IAELD,GAAI8D,EACF,CACEQ,WAAY,wBACZC,iBAAkB,YAClBC,mBAAoB,SAEpBC,eAAgB,CAAEC,GAAI,YAAaC,GAAI,kBAClC3D,IAAW,CACd4D,QAAS,IAETC,cAAe,OAEf,wBAAyB,CACvBD,QAAS,IACTC,cAAe,aAIdxD,IAAS,CACZyD,QAAS,SAGbjD,OAEEC,GAAW/D,SAAA,CAEfkF,EAAC8B,EAAG,CAAA,cACU,qBACZ/E,GAAI8D,EACF,CAEEkB,SAAU,WACVC,MAAO,IACPH,QAAS,CAAEJ,GAAI,OAAQC,GAAI,QAC3BO,WAAY,SACZC,eAAgB,SAChBC,IAAK,EAEL,6KACE,CACEC,GAAI,EAGJ,iCAAkC,CAChC,iBAAkB,CAChBA,GAAI,KAKZR,cAAe,OACf,QAAS,CACPA,cAAe,SAGnB9C,OAEEC,GAAiBjE,SAEpB8E,IAAsB,KAEzBE,EAACgC,EAAG,CAAA,cACU,kBACZ/E,GAAI8D,EACF,CACEkB,SAAU,WACVM,YAAa,IACbC,OAAQ,IACRT,QAAS,OACTU,cAAe,SACfN,WAAY,UACZC,eAAgB,aAChBM,GAAI,CAAEf,GAAI,EAAGC,GAAI,GAEjBe,GAAI,CAAEhB,GAAI,GAAKC,GAAI,IAErB1C,OAEEC,GAAOnE,SAAA,EAETS,GAAiByE,EAAC0C,EAAiB,CAACtF,SAAUA,MAAcnB,IAC9D6D,EAACgC,EAAG,CAAA,cACU,sBACZ/E,GAAI8D,EACF,CAEEgB,QAAS,OACTI,WAAY,SACZC,eAAgB,aAChBC,IAAK,CAAEV,GAAI,GAAKC,GAAI,IAEtBxC,OAEEC,aAEJW,EAACgC,EAAG,CAAA,cACU,oBACZ/E,GAAI8D,EACF,CAAEgB,QAAS,OAAQI,WAAY,SAAUC,eAAgB,aAAcC,IAAK,WAC5E7C,OAEEC,GAAuBzE,SAAA,CAE3BkF,EAAC8B,EAAG,CAAA,cACU,uBACZ/E,GAAI8D,EAAW,CAAEgB,QAAS,CAAEJ,GAAI,OAAQC,GAAI,aAAgBtC,OACxDC,GAAmBvE,SAEtB8E,IAAsB,KAExBnE,GACCL,GAAgB4E,EAAC2C,EAAsB,CAACvF,SAAUA,MAAcrB,KAChET,GACA0E,EAAC4C,GACCxF,SAAUA,GACVL,GAAI8D,EACF,CAEEgC,MAAO,CAAEpB,GAAI,KAAMC,GAAI,MAEzBhC,OAEEC,QAIVG,EAACgC,iBACa,kBACZ/E,GAAI8D,EACF,CAEEiC,KAAM,IACNjB,QAAS,OACTI,WAAY,SACZC,eAAgB,WAChBC,IAAK,WAEP3C,OAEEC,GAAqB3E,SAAA,CAExBY,GACCF,GACAwE,EAAC+C,GAA4B7F,aAAcA,MAAkBlB"}
@@ -0,0 +1,31 @@
1
+ import React, { ComponentType, type RefObject } from 'react';
2
+ import { SvgIconProps } from '@mui/material';
3
+ import { VideoPlayerIconButtonProps } from './VideoPlayerIconButton';
4
+ export interface VideoPlayerFullscreenButtonProps extends Omit<VideoPlayerIconButtonProps, 'title'> {
5
+ /**
6
+ * Ref to the element shown in fullscreen
7
+ */
8
+ containerRef: RefObject<HTMLElement>;
9
+ /**
10
+ * Custom component for the icon shown while not fullscreen
11
+ */
12
+ EnterIconComponent?: ComponentType<SvgIconProps>;
13
+ /**
14
+ * Custom component for the icon shown while fullscreen
15
+ */
16
+ ExitIconComponent?: ComponentType<SvgIconProps>;
17
+ /**
18
+ * Tooltip and aria-label while not fullscreen
19
+ * @default Enter fullscreen
20
+ */
21
+ enterTitle?: string;
22
+ /**
23
+ * Tooltip and aria-label while fullscreen
24
+ * @default Exit fullscreen
25
+ */
26
+ exitTitle?: string;
27
+ }
28
+ /**
29
+ * Button that toggles fullscreen of the container
30
+ */
31
+ export declare const VideoPlayerFullscreenButton: React.FC<VideoPlayerFullscreenButtonProps>;
@@ -0,0 +1,2 @@
1
+ import{jsx as e}from"react/jsx-runtime";import{forwardRef as r}from"react";import{FullscreenEnterIcon as o}from"../icon/stroke/FullscreenEnterIcon.js";import{FullscreenExitIcon as t}from"../icon/stroke/FullscreenExitIcon.js";import{useVideoFullscreen as n}from"../video/useVideoFullscreen.js";import{VideoPlayerIconButton as l}from"./VideoPlayerIconButton.js";const i=r(({containerRef:r,EnterIconComponent:i,ExitIconComponent:c,enterTitle:s="Enter fullscreen",exitTitle:m="Exit fullscreen",onClick:u,...a},d)=>{const{isFullscreen:f,handleFullscreenToggle:p}=n(r);return e(l,{ref:d,"data-testid":"VideoPlayerFullscreen",title:f?m:s,onClick:e=>{u?.(e),p()},...a,children:e(f?c??t:i??o,{"data-testid":f?"VideoPlayerFullscreenExitIcon":"VideoPlayerFullscreenEnterIcon"})})});export{i as VideoPlayerFullscreenButton};
2
+ //# sourceMappingURL=VideoPlayerFullscreenButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoPlayerFullscreenButton.js","sources":["../../../src/components/videoPlayer/VideoPlayerFullscreenButton.tsx"],"sourcesContent":["import React, { ComponentType, forwardRef, type MouseEvent, type RefObject } from 'react';\nimport { SvgIconProps } from '@mui/material';\nimport { FullscreenEnterIcon } from '@/src/components/icon/stroke/FullscreenEnterIcon';\nimport { FullscreenExitIcon } from '@/src/components/icon/stroke/FullscreenExitIcon';\nimport { useVideoFullscreen } from '@/src/components/video/useVideoFullscreen';\nimport { VideoPlayerIconButton, VideoPlayerIconButtonProps } from './VideoPlayerIconButton';\n\nexport interface VideoPlayerFullscreenButtonProps extends Omit<VideoPlayerIconButtonProps, 'title'> {\n /**\n * Ref to the element shown in fullscreen\n */\n containerRef: RefObject<HTMLElement>;\n /**\n * Custom component for the icon shown while not fullscreen\n */\n EnterIconComponent?: ComponentType<SvgIconProps>;\n /**\n * Custom component for the icon shown while fullscreen\n */\n ExitIconComponent?: ComponentType<SvgIconProps>;\n /**\n * Tooltip and aria-label while not fullscreen\n * @default Enter fullscreen\n */\n enterTitle?: string;\n /**\n * Tooltip and aria-label while fullscreen\n * @default Exit fullscreen\n */\n exitTitle?: string;\n}\n\n/**\n * Button that toggles fullscreen of the container\n */\nexport const VideoPlayerFullscreenButton: React.FC<VideoPlayerFullscreenButtonProps> = forwardRef(\n (\n {\n containerRef,\n EnterIconComponent,\n ExitIconComponent,\n enterTitle = 'Enter fullscreen',\n exitTitle = 'Exit fullscreen',\n onClick,\n ...rest\n },\n ref,\n ) => {\n const { isFullscreen, handleFullscreenToggle } = useVideoFullscreen(containerRef);\n const Icon = isFullscreen ? (ExitIconComponent ?? FullscreenExitIcon) : (EnterIconComponent ?? FullscreenEnterIcon);\n\n return (\n <VideoPlayerIconButton\n ref={ref}\n data-testid=\"VideoPlayerFullscreen\"\n title={isFullscreen ? exitTitle : enterTitle}\n onClick={(event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n handleFullscreenToggle();\n }}\n {...rest}\n >\n <Icon data-testid={isFullscreen ? 'VideoPlayerFullscreenExitIcon' : 'VideoPlayerFullscreenEnterIcon'} />\n </VideoPlayerIconButton>\n );\n },\n);\n"],"names":["VideoPlayerFullscreenButton","forwardRef","containerRef","EnterIconComponent","ExitIconComponent","enterTitle","exitTitle","onClick","rest","ref","isFullscreen","handleFullscreenToggle","useVideoFullscreen","_jsx","VideoPlayerIconButton","title","event","children","FullscreenExitIcon","FullscreenEnterIcon"],"mappings":"wWAmCO,MAAMA,EAA0EC,EACrF,EAEIC,eACAC,qBACAC,oBACAC,aAAa,mBACbC,YAAY,kBACZC,aACGC,GAELC,KAEA,MAAMC,aAAEA,EAAYC,uBAAEA,GAA2BC,EAAmBV,GAGpE,OACEW,EAACC,EAAqB,CACpBL,IAAKA,EAAG,cACI,wBACZM,MAAOL,EAAeJ,EAAYD,EAClCE,QAAUS,IACRT,IAAUS,GACVL,QAEEH,EAAIS,SAERJ,EAbSH,EAAgBN,GAAqBc,EAAuBf,GAAsBgB,EAatF,CAAA,cAAcT,EAAe,gCAAkC"}
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { IconButtonProps } from '@mui/material';
3
+ export interface VideoPlayerIconButtonProps extends IconButtonProps {
4
+ /**
5
+ * Text shown in the tooltip and used as aria-label
6
+ */
7
+ title: string;
8
+ /**
9
+ * Fixed size on all screens, small on mobile and medium on desktop when not set
10
+ */
11
+ size?: IconButtonProps['size'];
12
+ }
13
+ /**
14
+ * IconButton with a tooltip, base of the VideoPlayer buttons
15
+ */
16
+ export declare const VideoPlayerIconButton: React.FC<VideoPlayerIconButtonProps>;
@@ -0,0 +1,2 @@
1
+ import{jsx as o}from"react/jsx-runtime";import{forwardRef as t}from"react";import{Tooltip as e,IconButton as i}from"@mui/material";import{sxOverride as r}from"../../utils/sxOverride/sxOverride.js";const m=t(({title:t,size:m,sx:p,...s},a)=>o(e,{title:t,placement:"top","data-tooltip-mode":"dark",slotProps:{popper:{modifiers:[{name:"offset",options:{offset:[0,2]}}]}},children:o(i,{ref:a,color:"white",size:m??"medium","aria-label":t,sx:m?p:r(o=>({[o.breakpoints.down("md")]:{width:"32px",height:"32px","& .MuiSvgIcon-root":{fontSize:"17px"}}}),p),...s})}));export{m as VideoPlayerIconButton};
2
+ //# sourceMappingURL=VideoPlayerIconButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoPlayerIconButton.js","sources":["../../../src/components/videoPlayer/VideoPlayerIconButton.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { IconButton, IconButtonProps, Tooltip } from '@mui/material';\nimport { sxOverride } from '@/src/utils/sxOverride';\n\nexport interface VideoPlayerIconButtonProps extends IconButtonProps {\n /**\n * Text shown in the tooltip and used as aria-label\n */\n title: string;\n /**\n * Fixed size on all screens, small on mobile and medium on desktop when not set\n */\n size?: IconButtonProps['size'];\n}\n\n/**\n * IconButton with a tooltip, base of the VideoPlayer buttons\n */\nexport const VideoPlayerIconButton: React.FC<VideoPlayerIconButtonProps> = forwardRef(\n ({ title, size, sx, ...rest }, ref) => (\n <Tooltip\n title={title}\n placement=\"top\"\n // dark mode tooltip is white, keeps it white over the video regardless of the theme\n data-tooltip-mode=\"dark\"\n // tooltip closer to the button than the default offset\n slotProps={{ popper: { modifiers: [{ name: 'offset', options: { offset: [0, 2] } }] } }}\n >\n <IconButton\n ref={ref}\n color=\"white\"\n size={size ?? 'medium'}\n aria-label={title}\n sx={\n size\n ? sx\n : sxOverride(\n (theme) => ({\n // sizes of size=\"small\" on mobile, a media query instead of the prop keeps it right on the server\n [theme.breakpoints.down('md')]: {\n width: '32px',\n height: '32px',\n '& .MuiSvgIcon-root': {\n fontSize: '17px',\n },\n },\n }),\n sx,\n )\n }\n {...rest}\n />\n </Tooltip>\n ),\n);\n"],"names":["VideoPlayerIconButton","forwardRef","title","size","sx","rest","ref","_jsx","Tooltip","placement","slotProps","popper","modifiers","name","options","offset","IconButton","color","sxOverride","theme","breakpoints","down","width","height","fontSize"],"mappings":"qMAkBO,MAAMA,EAA8DC,EACzE,EAAGC,QAAOC,OAAMC,QAAOC,GAAQC,IAC7BC,EAACC,EAAO,CACNN,MAAOA,EACPO,UAAU,0BAEQ,OAElBC,UAAW,CAAEC,OAAQ,CAAEC,UAAW,CAAC,CAAEC,KAAM,SAAUC,QAAS,CAAEC,OAAQ,CAAC,EAAG,iBAE5ER,EAACS,GACCV,IAAKA,EACLW,MAAM,QACNd,KAAMA,GAAQ,sBACFD,EACZE,GACED,EACIC,EACAc,EACGC,IAAK,CAEJ,CAACA,EAAMC,YAAYC,KAAK,OAAQ,CAC9BC,MAAO,OACPC,OAAQ,OACR,qBAAsB,CACpBC,SAAU,WAIhBpB,MAGJC"}
@@ -0,0 +1,31 @@
1
+ import React, { ComponentType, type RefObject } from 'react';
2
+ import { SvgIconProps } from '@mui/material';
3
+ import { VideoPlayerIconButtonProps } from './VideoPlayerIconButton';
4
+ export interface VideoPlayerPlayPauseButtonProps extends Omit<VideoPlayerIconButtonProps, 'title'> {
5
+ /**
6
+ * Ref to the controlled <video> element
7
+ */
8
+ videoRef: RefObject<HTMLVideoElement>;
9
+ /**
10
+ * Custom component for the icon shown while the video is paused
11
+ */
12
+ PlayIconComponent?: ComponentType<SvgIconProps>;
13
+ /**
14
+ * Custom component for the icon shown while the video is playing
15
+ */
16
+ PauseIconComponent?: ComponentType<SvgIconProps>;
17
+ /**
18
+ * Tooltip and aria-label while the video is paused
19
+ * @default Play video
20
+ */
21
+ playTitle?: string;
22
+ /**
23
+ * Tooltip and aria-label while the video is playing
24
+ * @default Pause video
25
+ */
26
+ pauseTitle?: string;
27
+ }
28
+ /**
29
+ * Button that toggles play/pause of the video
30
+ */
31
+ export declare const VideoPlayerPlayPauseButton: React.FC<VideoPlayerPlayPauseButtonProps>;
@@ -0,0 +1,2 @@
1
+ import{jsx as o}from"react/jsx-runtime";import{forwardRef as e}from"react";import{sxOverride as t}from"../../utils/sxOverride/sxOverride.js";import{ControlsPlayIcon as i}from"../icon/stroke/ControlsPlayIcon.js";import{ControlsPauseIcon as r}from"../icon/stroke/ControlsPauseIcon.js";import{useVideoPlayPause as s}from"../video/useVideoPlayPause.js";import{VideoPlayerIconButton as a}from"./VideoPlayerIconButton.js";const n=e(({videoRef:e,PlayIconComponent:n,PauseIconComponent:l,playTitle:d="Play video",pauseTitle:P="Pause video",onClick:m,sx:c,...p},u)=>{const{isPlaying:y,handlePlayPause:f}=s(e),x=y?l??r:n??i;return o(a,{ref:u,"data-testid":"VideoPlayerPlayPause",title:y?P:d,onClick:o=>{m?.(o),f()},sx:t(o=>({[o.breakpoints.down("md")]:{width:"52px",height:"52px","& .MuiSvgIcon-root":{fontSize:"32px"}}}),c),...p,children:o(x,{"data-testid":y?"VideoPlayerPauseIcon":"VideoPlayerPlayIcon"})})});export{n as VideoPlayerPlayPauseButton};
2
+ //# sourceMappingURL=VideoPlayerPlayPauseButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoPlayerPlayPauseButton.js","sources":["../../../src/components/videoPlayer/VideoPlayerPlayPauseButton.tsx"],"sourcesContent":["import React, { ComponentType, forwardRef, type MouseEvent, type RefObject } from 'react';\nimport { SvgIconProps } from '@mui/material';\nimport { sxOverride } from '@/src/utils/sxOverride';\nimport { ControlsPlayIcon } from '@/src/components/icon/stroke/ControlsPlayIcon';\nimport { ControlsPauseIcon } from '@/src/components/icon/stroke/ControlsPauseIcon';\nimport { useVideoPlayPause } from '@/src/components/video/useVideoPlayPause';\nimport { VideoPlayerIconButton, VideoPlayerIconButtonProps } from './VideoPlayerIconButton';\n\nexport interface VideoPlayerPlayPauseButtonProps extends Omit<VideoPlayerIconButtonProps, 'title'> {\n /**\n * Ref to the controlled <video> element\n */\n videoRef: RefObject<HTMLVideoElement>;\n /**\n * Custom component for the icon shown while the video is paused\n */\n PlayIconComponent?: ComponentType<SvgIconProps>;\n /**\n * Custom component for the icon shown while the video is playing\n */\n PauseIconComponent?: ComponentType<SvgIconProps>;\n /**\n * Tooltip and aria-label while the video is paused\n * @default Play video\n */\n playTitle?: string;\n /**\n * Tooltip and aria-label while the video is playing\n * @default Pause video\n */\n pauseTitle?: string;\n}\n\n/**\n * Button that toggles play/pause of the video\n */\nexport const VideoPlayerPlayPauseButton: React.FC<VideoPlayerPlayPauseButtonProps> = forwardRef(\n (\n {\n videoRef,\n PlayIconComponent,\n PauseIconComponent,\n playTitle = 'Play video',\n pauseTitle = 'Pause video',\n onClick,\n sx,\n ...rest\n },\n ref,\n ) => {\n const { isPlaying, handlePlayPause } = useVideoPlayPause(videoRef);\n const Icon = isPlaying ? (PauseIconComponent ?? ControlsPauseIcon) : (PlayIconComponent ?? ControlsPlayIcon);\n\n return (\n <VideoPlayerIconButton\n ref={ref}\n data-testid=\"VideoPlayerPlayPause\"\n title={isPlaying ? pauseTitle : playTitle}\n onClick={(event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n handlePlayPause();\n }}\n sx={sxOverride(\n (theme) => ({\n // larger button on mobile, where it is centered over the video\n [theme.breakpoints.down('md')]: {\n width: '52px',\n height: '52px',\n '& .MuiSvgIcon-root': {\n fontSize: '32px',\n },\n },\n }),\n sx,\n )}\n {...rest}\n >\n <Icon data-testid={isPlaying ? 'VideoPlayerPauseIcon' : 'VideoPlayerPlayIcon'} />\n </VideoPlayerIconButton>\n );\n },\n);\n"],"names":["VideoPlayerPlayPauseButton","forwardRef","videoRef","PlayIconComponent","PauseIconComponent","playTitle","pauseTitle","onClick","sx","rest","ref","isPlaying","handlePlayPause","useVideoPlayPause","Icon","ControlsPauseIcon","ControlsPlayIcon","_jsx","VideoPlayerIconButton","title","event","sxOverride","theme","breakpoints","down","width","height","fontSize","children"],"mappings":"gaAoCO,MAAMA,EAAwEC,EACnF,EAEIC,WACAC,oBACAC,qBACAC,YAAY,aACZC,aAAa,cACbC,UACAC,QACGC,GAELC,KAEA,MAAMC,UAAEA,EAASC,gBAAEA,GAAoBC,EAAkBX,GACnDY,EAAOH,EAAaP,GAAsBW,EAAsBZ,GAAqBa,EAE3F,OACEC,EAACC,EAAqB,CACpBR,IAAKA,EAAG,cACI,uBACZS,MAAOR,EAAYL,EAAaD,EAChCE,QAAUa,IACRb,IAAUa,GACVR,KAEFJ,GAAIa,EACDC,IAAK,CAEJ,CAACA,EAAMC,YAAYC,KAAK,OAAQ,CAC9BC,MAAO,OACPC,OAAQ,OACR,qBAAsB,CACpBC,SAAU,WAIhBnB,MAEEC,EAAImB,SAERX,EAACH,EAAI,CAAA,cAAcH,EAAY,uBAAyB"}
@@ -0,0 +1,23 @@
1
+ import React, { ComponentType } from 'react';
2
+ import { SvgIconProps } from '@mui/material';
3
+ import { VideoPlayerIconButtonProps } from './VideoPlayerIconButton';
4
+ export interface VideoPlayerSkipButtonProps extends Omit<VideoPlayerIconButtonProps, 'title'> {
5
+ /**
6
+ * Tooltip and aria-label of the button
7
+ * @default Previous video or Next video based on direction
8
+ */
9
+ title?: string;
10
+ /**
11
+ * Direction of the skip
12
+ * @default next
13
+ */
14
+ direction?: 'previous' | 'next';
15
+ /**
16
+ * Custom component to be used for the icon
17
+ */
18
+ IconComponent?: ComponentType<SvgIconProps>;
19
+ }
20
+ /**
21
+ * Button that skips to the previous or next video
22
+ */
23
+ export declare const VideoPlayerSkipButton: React.FC<VideoPlayerSkipButtonProps>;
@@ -0,0 +1,2 @@
1
+ import{jsx as o}from"react/jsx-runtime";import{forwardRef as e}from"react";import{ControlsSkipPreviousIcon as t}from"../icon/stroke/ControlsSkipPreviousIcon.js";import{ControlsSkipNextIcon as i}from"../icon/stroke/ControlsSkipNextIcon.js";import{VideoPlayerIconButton as r}from"./VideoPlayerIconButton.js";const n=e(({direction:e="next",IconComponent:n,title:s,...c},p)=>{const d="previous"===e;return o(r,{ref:p,"data-testid":d?"VideoPlayerSkipPrevious":"VideoPlayerSkipNext",title:s??(d?"Previous video":"Next video"),...c,children:o(n??(d?t:i),{"data-testid":d?"VideoPlayerSkipPreviousIcon":"VideoPlayerSkipNextIcon"})})});export{n as VideoPlayerSkipButton};
2
+ //# sourceMappingURL=VideoPlayerSkipButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoPlayerSkipButton.js","sources":["../../../src/components/videoPlayer/VideoPlayerSkipButton.tsx"],"sourcesContent":["import React, { ComponentType, forwardRef } from 'react';\nimport { SvgIconProps } from '@mui/material';\nimport { ControlsSkipPreviousIcon } from '@/src/components/icon/stroke/ControlsSkipPreviousIcon';\nimport { ControlsSkipNextIcon } from '@/src/components/icon/stroke/ControlsSkipNextIcon';\nimport { VideoPlayerIconButton, VideoPlayerIconButtonProps } from './VideoPlayerIconButton';\n\nexport interface VideoPlayerSkipButtonProps extends Omit<VideoPlayerIconButtonProps, 'title'> {\n /**\n * Tooltip and aria-label of the button\n * @default Previous video or Next video based on direction\n */\n title?: string;\n /**\n * Direction of the skip\n * @default next\n */\n direction?: 'previous' | 'next';\n /**\n * Custom component to be used for the icon\n */\n IconComponent?: ComponentType<SvgIconProps>;\n}\n\n/**\n * Button that skips to the previous or next video\n */\nexport const VideoPlayerSkipButton: React.FC<VideoPlayerSkipButtonProps> = forwardRef(\n ({ direction = 'next', IconComponent, title, ...rest }, ref) => {\n const isPrevious = direction === 'previous';\n const Icon = IconComponent ?? (isPrevious ? ControlsSkipPreviousIcon : ControlsSkipNextIcon);\n\n return (\n <VideoPlayerIconButton\n ref={ref}\n data-testid={isPrevious ? 'VideoPlayerSkipPrevious' : 'VideoPlayerSkipNext'}\n title={title ?? (isPrevious ? 'Previous video' : 'Next video')}\n {...rest}\n >\n <Icon data-testid={isPrevious ? 'VideoPlayerSkipPreviousIcon' : 'VideoPlayerSkipNextIcon'} />\n </VideoPlayerIconButton>\n );\n },\n);\n"],"names":["VideoPlayerSkipButton","forwardRef","direction","IconComponent","title","rest","ref","isPrevious","_jsx","VideoPlayerIconButton","children","ControlsSkipPreviousIcon","ControlsSkipNextIcon"],"mappings":"wTA0BaA,EAA8DC,EACzE,EAAGC,YAAY,OAAQC,gBAAeC,WAAUC,GAAQC,KACtD,MAAMC,EAA2B,aAAdL,EAGnB,OACEM,EAACC,EAAqB,CACpBH,IAAKA,EAAG,cACKC,EAAa,0BAA4B,sBACtDH,MAAOA,IAAUG,EAAa,iBAAmB,iBAC7CF,EAAIK,SAERF,EATSL,IAAkBI,EAAaI,EAA2BC,GAS9D,CAAA,cAAcL,EAAa,8BAAgC"}
@@ -0,0 +1,12 @@
1
+ import React, { type RefObject } from 'react';
2
+ import { SliderProps } from '@mui/material';
3
+ export interface VideoPlayerSliderProps extends SliderProps {
4
+ /**
5
+ * Ref to the controlled <video> element
6
+ */
7
+ videoRef: RefObject<HTMLVideoElement>;
8
+ }
9
+ /**
10
+ * Seek slider showing the playback progress of the video
11
+ */
12
+ export declare const VideoPlayerSlider: React.FC<VideoPlayerSliderProps>;
@@ -0,0 +1,2 @@
1
+ import{jsx as e}from"react/jsx-runtime";import{forwardRef as r}from"react";import{Slider as o}from"@mui/material";import{sxOverride as i}from"../../utils/sxOverride/sxOverride.js";import{useVideoTime as a}from"../video/useVideoTime.js";import{useVideoPlayPause as t}from"../video/useVideoPlayPause.js";import{formatVideoTime as d}from"./formatVideoTime.js";const m=r(({videoRef:r,onChange:m,onKeyDown:n,sx:s,...l},u)=>{const{currentTime:p,duration:x,handleSeek:f}=a(r,{smooth:!0}),{handlePlayPause:h}=t(r);return e(o,{ref:u,"data-testid":"VideoPlayerSeekSlider",value:p,min:0,max:x||0,valueLabelDisplay:"off",onChange:(e,r,o)=>{m?.(e,r,o),f(r)},"aria-label":"Seek video",getAriaValueText:e=>d(e,x),onKeyDown:e=>{n?.(e)," "===e.key&&(e.preventDefault(),h())},sx:i({height:"4px",py:"6px","@media (pointer: coarse)":{py:"6px"},"& .MuiSlider-rail":{color:"common.white",borderRadius:"16px"},"& .MuiSlider-track":{color:"brand.secondary",borderRadius:"16px",transition:"none"},"& .MuiSlider-thumb":{width:"16px",height:"16px",borderRadius:"50%"}},s),...l})});export{m as VideoPlayerSlider};
2
+ //# sourceMappingURL=VideoPlayerSlider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoPlayerSlider.js","sources":["../../../src/components/videoPlayer/VideoPlayerSlider.tsx"],"sourcesContent":["import React, { forwardRef, type KeyboardEvent, type RefObject } from 'react';\nimport { Slider, SliderProps } from '@mui/material';\nimport { sxOverride } from '@/src/utils/sxOverride';\nimport { useVideoTime } from '@/src/components/video/useVideoTime';\nimport { useVideoPlayPause } from '@/src/components/video/useVideoPlayPause';\nimport { formatVideoTime } from './formatVideoTime';\n\nexport interface VideoPlayerSliderProps extends SliderProps {\n /**\n * Ref to the controlled <video> element\n */\n videoRef: RefObject<HTMLVideoElement>;\n}\n\n/**\n * Seek slider showing the playback progress of the video\n */\nexport const VideoPlayerSlider: React.FC<VideoPlayerSliderProps> = forwardRef(\n ({ videoRef, onChange, onKeyDown, sx, ...rest }, ref) => {\n const { currentTime, duration, handleSeek } = useVideoTime(videoRef, { smooth: true });\n const { handlePlayPause } = useVideoPlayPause(videoRef);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLSpanElement>) => {\n onKeyDown?.(event);\n // space toggles playback like on the play button, keyboard users don't have to leave the slider\n if (event.key === ' ') {\n event.preventDefault();\n handlePlayPause();\n }\n };\n\n return (\n <Slider\n ref={ref}\n data-testid=\"VideoPlayerSeekSlider\"\n value={currentTime}\n min={0}\n max={duration || 0}\n valueLabelDisplay=\"off\"\n onChange={(event, newValue: number, activeThumb) => {\n onChange?.(event, newValue, activeThumb);\n handleSeek(newValue);\n }}\n aria-label=\"Seek video\"\n getAriaValueText={(value) => formatVideoTime(value, duration)}\n onKeyDown={handleKeyDown}\n sx={sxOverride(\n {\n height: '4px',\n // symmetric padding keeps the track centered and serves as its hitbox,\n // Figma sits the track directly on the toolbar, the space keeps icon buttons focus ring from overlapping the slider\n py: '6px',\n // the theme sets its padding again for touch devices, the plain py would lose to it there\n '@media (pointer: coarse)': {\n py: '6px',\n },\n '& .MuiSlider-rail': {\n color: 'common.white',\n borderRadius: '16px',\n },\n '& .MuiSlider-track': {\n color: 'brand.secondary',\n borderRadius: '16px',\n // updated every frame, the default width transition would only make it lag behind\n transition: 'none',\n },\n '& .MuiSlider-thumb': {\n width: '16px',\n height: '16px',\n borderRadius: '50%',\n },\n },\n sx,\n )}\n {...rest}\n />\n );\n },\n);\n"],"names":["VideoPlayerSlider","forwardRef","videoRef","onChange","onKeyDown","sx","rest","ref","currentTime","duration","handleSeek","useVideoTime","smooth","handlePlayPause","useVideoPlayPause","_jsx","Slider","value","min","max","valueLabelDisplay","event","newValue","activeThumb","getAriaValueText","formatVideoTime","key","preventDefault","sxOverride","height","py","color","borderRadius","transition","width"],"mappings":"2WAiBaA,EAAsDC,EACjE,EAAGC,WAAUC,WAAUC,YAAWC,QAAOC,GAAQC,KAC/C,MAAMC,YAAEA,EAAWC,SAAEA,EAAQC,WAAEA,GAAeC,EAAaT,EAAU,CAAEU,QAAQ,KACzEC,gBAAEA,GAAoBC,EAAkBZ,GAW9C,OACEa,EAACC,EAAM,CACLT,IAAKA,EAAG,cACI,wBACZU,MAAOT,EACPU,IAAK,EACLC,IAAKV,GAAY,EACjBW,kBAAkB,MAClBjB,SAAU,CAACkB,EAAOC,EAAkBC,KAClCpB,IAAWkB,EAAOC,EAAUC,GAC5Bb,EAAWY,IACZ,aACU,aACXE,iBAAmBP,GAAUQ,EAAgBR,EAAOR,GACpDL,UAvBmBiB,IACrBjB,IAAYiB,GAEM,MAAdA,EAAMK,MACRL,EAAMM,iBACNd,MAmBAR,GAAIuB,EACF,CACEC,OAAQ,MAGRC,GAAI,MAEJ,2BAA4B,CAC1BA,GAAI,OAEN,oBAAqB,CACnBC,MAAO,eACPC,aAAc,QAEhB,qBAAsB,CACpBD,MAAO,kBACPC,aAAc,OAEdC,WAAY,QAEd,qBAAsB,CACpBC,MAAO,OACPL,OAAQ,OACRG,aAAc,QAGlB3B,MAEEC"}