@videojs/react 10.0.0-beta.14 → 10.0.0-beta.16

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 (119) hide show
  1. package/dist/default/index.js +4 -1
  2. package/dist/default/media/dash-video/index.js +3 -2
  3. package/dist/default/media/dash-video/index.js.map +1 -1
  4. package/dist/default/media/hls-video/index.js +3 -2
  5. package/dist/default/media/hls-video/index.js.map +1 -1
  6. package/dist/default/media/mux-audio/index.js +20 -0
  7. package/dist/default/media/mux-audio/index.js.map +1 -0
  8. package/dist/default/media/mux-video/index.js +3 -2
  9. package/dist/default/media/mux-video/index.js.map +1 -1
  10. package/dist/default/media/native-hls-video/index.js +3 -2
  11. package/dist/default/media/native-hls-video/index.js.map +1 -1
  12. package/dist/default/media/simple-hls-video/index.js +3 -2
  13. package/dist/default/media/simple-hls-video/index.js.map +1 -1
  14. package/dist/default/player/context.js +9 -1
  15. package/dist/default/player/context.js.map +1 -1
  16. package/dist/default/presets/audio/minimal-skin.css +23 -0
  17. package/dist/default/presets/audio/skin.css +23 -0
  18. package/dist/default/presets/audio/skin.js +65 -0
  19. package/dist/default/presets/audio/skin.js.map +1 -1
  20. package/dist/default/presets/video/minimal-skin.css +23 -0
  21. package/dist/default/presets/video/skin.css +23 -0
  22. package/dist/default/presets/video/skin.js +78 -1
  23. package/dist/default/presets/video/skin.js.map +1 -1
  24. package/dist/default/ui/captions-button/captions-button.js +2 -1
  25. package/dist/default/ui/captions-button/captions-button.js.map +1 -1
  26. package/dist/default/ui/create-media-button.js +7 -2
  27. package/dist/default/ui/create-media-button.js.map +1 -1
  28. package/dist/default/ui/fullscreen-button/fullscreen-button.js +2 -1
  29. package/dist/default/ui/fullscreen-button/fullscreen-button.js.map +1 -1
  30. package/dist/default/ui/hooks/use-slider.js +1 -1
  31. package/dist/default/ui/hooks/use-slider.js.map +1 -1
  32. package/dist/default/ui/hotkey/media-hotkey.js +41 -0
  33. package/dist/default/ui/hotkey/media-hotkey.js.map +1 -0
  34. package/dist/default/ui/hotkey/use-aria-key-shortcuts.js +16 -0
  35. package/dist/default/ui/hotkey/use-aria-key-shortcuts.js.map +1 -0
  36. package/dist/default/ui/hotkey/use-hotkey.js +32 -0
  37. package/dist/default/ui/hotkey/use-hotkey.js.map +1 -0
  38. package/dist/default/ui/mute-button/mute-button.js +2 -1
  39. package/dist/default/ui/mute-button/mute-button.js.map +1 -1
  40. package/dist/default/ui/pip-button/pip-button.js +2 -1
  41. package/dist/default/ui/pip-button/pip-button.js.map +1 -1
  42. package/dist/default/ui/play-button/play-button.js +2 -1
  43. package/dist/default/ui/play-button/play-button.js.map +1 -1
  44. package/dist/default/ui/time-slider/time-slider-root.js +2 -2
  45. package/dist/default/ui/time-slider/time-slider-root.js.map +1 -1
  46. package/dist/dev/index.d.ts +4 -1
  47. package/dist/dev/index.js +4 -1
  48. package/dist/dev/media/dash-video/index.d.ts +4 -1
  49. package/dist/dev/media/dash-video/index.d.ts.map +1 -1
  50. package/dist/dev/media/dash-video/index.js +3 -2
  51. package/dist/dev/media/dash-video/index.js.map +1 -1
  52. package/dist/dev/media/hls-video/index.d.ts +4 -1
  53. package/dist/dev/media/hls-video/index.d.ts.map +1 -1
  54. package/dist/dev/media/hls-video/index.js +3 -2
  55. package/dist/dev/media/hls-video/index.js.map +1 -1
  56. package/dist/dev/media/mux-audio/index.d.ts +13 -0
  57. package/dist/dev/media/mux-audio/index.d.ts.map +1 -0
  58. package/dist/dev/media/mux-audio/index.js +20 -0
  59. package/dist/dev/media/mux-audio/index.js.map +1 -0
  60. package/dist/dev/media/mux-video/index.d.ts +5 -2
  61. package/dist/dev/media/mux-video/index.d.ts.map +1 -1
  62. package/dist/dev/media/mux-video/index.js +3 -2
  63. package/dist/dev/media/mux-video/index.js.map +1 -1
  64. package/dist/dev/media/native-hls-video/index.d.ts +4 -1
  65. package/dist/dev/media/native-hls-video/index.d.ts.map +1 -1
  66. package/dist/dev/media/native-hls-video/index.js +3 -2
  67. package/dist/dev/media/native-hls-video/index.js.map +1 -1
  68. package/dist/dev/media/simple-hls-video/index.d.ts +4 -1
  69. package/dist/dev/media/simple-hls-video/index.d.ts.map +1 -1
  70. package/dist/dev/media/simple-hls-video/index.js +3 -2
  71. package/dist/dev/media/simple-hls-video/index.js.map +1 -1
  72. package/dist/dev/player/context.d.ts.map +1 -1
  73. package/dist/dev/player/context.js +9 -1
  74. package/dist/dev/player/context.js.map +1 -1
  75. package/dist/dev/presets/audio/minimal-skin.css +23 -0
  76. package/dist/dev/presets/audio/skin.css +23 -0
  77. package/dist/dev/presets/audio/skin.d.ts.map +1 -1
  78. package/dist/dev/presets/audio/skin.js +65 -0
  79. package/dist/dev/presets/audio/skin.js.map +1 -1
  80. package/dist/dev/presets/video/minimal-skin.css +23 -0
  81. package/dist/dev/presets/video/skin.css +23 -0
  82. package/dist/dev/presets/video/skin.d.ts.map +1 -1
  83. package/dist/dev/presets/video/skin.js +78 -1
  84. package/dist/dev/presets/video/skin.js.map +1 -1
  85. package/dist/dev/ui/captions-button/captions-button.d.ts.map +1 -1
  86. package/dist/dev/ui/captions-button/captions-button.js +2 -1
  87. package/dist/dev/ui/captions-button/captions-button.js.map +1 -1
  88. package/dist/dev/ui/create-media-button.js +7 -2
  89. package/dist/dev/ui/create-media-button.js.map +1 -1
  90. package/dist/dev/ui/fullscreen-button/fullscreen-button.d.ts.map +1 -1
  91. package/dist/dev/ui/fullscreen-button/fullscreen-button.js +2 -1
  92. package/dist/dev/ui/fullscreen-button/fullscreen-button.js.map +1 -1
  93. package/dist/dev/ui/hooks/use-slider.d.ts +1 -1
  94. package/dist/dev/ui/hooks/use-slider.js +1 -1
  95. package/dist/dev/ui/hooks/use-slider.js.map +1 -1
  96. package/dist/dev/ui/hotkey/media-hotkey.d.ts +21 -0
  97. package/dist/dev/ui/hotkey/media-hotkey.d.ts.map +1 -0
  98. package/dist/dev/ui/hotkey/media-hotkey.js +41 -0
  99. package/dist/dev/ui/hotkey/media-hotkey.js.map +1 -0
  100. package/dist/dev/ui/hotkey/use-aria-key-shortcuts.d.ts +5 -0
  101. package/dist/dev/ui/hotkey/use-aria-key-shortcuts.d.ts.map +1 -0
  102. package/dist/dev/ui/hotkey/use-aria-key-shortcuts.js +16 -0
  103. package/dist/dev/ui/hotkey/use-aria-key-shortcuts.js.map +1 -0
  104. package/dist/dev/ui/hotkey/use-hotkey.d.ts +12 -0
  105. package/dist/dev/ui/hotkey/use-hotkey.d.ts.map +1 -0
  106. package/dist/dev/ui/hotkey/use-hotkey.js +32 -0
  107. package/dist/dev/ui/hotkey/use-hotkey.js.map +1 -0
  108. package/dist/dev/ui/mute-button/mute-button.d.ts.map +1 -1
  109. package/dist/dev/ui/mute-button/mute-button.js +2 -1
  110. package/dist/dev/ui/mute-button/mute-button.js.map +1 -1
  111. package/dist/dev/ui/pip-button/pip-button.d.ts.map +1 -1
  112. package/dist/dev/ui/pip-button/pip-button.js +2 -1
  113. package/dist/dev/ui/pip-button/pip-button.js.map +1 -1
  114. package/dist/dev/ui/play-button/play-button.d.ts.map +1 -1
  115. package/dist/dev/ui/play-button/play-button.js +2 -1
  116. package/dist/dev/ui/play-button/play-button.js.map +1 -1
  117. package/dist/dev/ui/time-slider/time-slider-root.js +2 -2
  118. package/dist/dev/ui/time-slider/time-slider-root.js.map +1 -1
  119. package/package.json +11 -11
@@ -34,6 +34,12 @@
34
34
  height: 100%;
35
35
  width: 100%;
36
36
  border-radius: var(--media-border-radius, 0.75rem);
37
+ outline: 2px solid transparent;
38
+ outline-offset: 2px;
39
+
40
+ &:focus-visible {
41
+ outline-color: currentColor;
42
+ }
37
43
  font-family:
38
44
  Inter Variable,
39
45
  Inter,
@@ -607,6 +613,23 @@
607
613
  }
608
614
  }
609
615
 
616
+ /* Dragging — thumb and fill follow the pointer position */
617
+ .media-minimal-skin .media-slider[data-dragging] .media-slider__thumb[data-orientation="horizontal"] {
618
+ left: var(--media-slider-pointer);
619
+ }
620
+
621
+ .media-minimal-skin .media-slider[data-dragging] .media-slider__thumb[data-orientation="vertical"] {
622
+ top: calc(100% - var(--media-slider-pointer));
623
+ }
624
+
625
+ .media-minimal-skin .media-slider[data-dragging] .media-slider__fill[data-orientation="horizontal"] {
626
+ width: var(--media-slider-pointer);
627
+ }
628
+
629
+ .media-minimal-skin .media-slider[data-dragging] .media-slider__fill[data-orientation="vertical"] {
630
+ height: var(--media-slider-pointer);
631
+ }
632
+
610
633
  /* ==========================================================================
611
634
  Popups & Animations
612
635
  ========================================================================== */
@@ -34,6 +34,12 @@
34
34
  height: 100%;
35
35
  width: 100%;
36
36
  border-radius: var(--media-border-radius, 2rem);
37
+ outline: 2px solid transparent;
38
+ outline-offset: 2px;
39
+
40
+ &:focus-visible {
41
+ outline-color: currentColor;
42
+ }
37
43
  font-family:
38
44
  Inter Variable,
39
45
  Inter,
@@ -633,6 +639,23 @@
633
639
  }
634
640
  }
635
641
 
642
+ /* Dragging — thumb and fill follow the pointer position */
643
+ .media-default-skin .media-slider[data-dragging] .media-slider__thumb[data-orientation="horizontal"] {
644
+ left: var(--media-slider-pointer);
645
+ }
646
+
647
+ .media-default-skin .media-slider[data-dragging] .media-slider__thumb[data-orientation="vertical"] {
648
+ top: calc(100% - var(--media-slider-pointer));
649
+ }
650
+
651
+ .media-default-skin .media-slider[data-dragging] .media-slider__fill[data-orientation="horizontal"] {
652
+ width: var(--media-slider-pointer);
653
+ }
654
+
655
+ .media-default-skin .media-slider[data-dragging] .media-slider__fill[data-orientation="vertical"] {
656
+ height: var(--media-slider-pointer);
657
+ }
658
+
636
659
  /* ==========================================================================
637
660
  Popups & Tooltips
638
661
  ========================================================================== */
@@ -1 +1 @@
1
- {"version":3,"file":"skin.d.ts","names":[],"sources":["../../../../src/presets/video/skin.tsx"],"mappings":";;;;KA0CY,cAAA,GAAiB,kBAAA;AAAA,iBAyCb,SAAA,CAAU,KAAA,EAAO,cAAA,GAAiB,SAAA"}
1
+ {"version":3,"file":"skin.d.ts","names":[],"sources":["../../../../src/presets/video/skin.tsx"],"mappings":";;;;KA2CY,cAAA,GAAiB,kBAAA;AAAA,iBAyCb,SAAA,CAAU,KAAA,EAAO,cAAA,GAAiB,SAAA"}
@@ -9,6 +9,7 @@ import { ControlsRoot } from "../../ui/controls/controls-root.js";
9
9
  import { ErrorDialogDescription } from "../../ui/error-dialog/error-dialog-description.js";
10
10
  import { ErrorDialogRoot } from "../../ui/error-dialog/error-dialog-root.js";
11
11
  import { FullscreenButton } from "../../ui/fullscreen-button/fullscreen-button.js";
12
+ import { MediaHotkey } from "../../ui/hotkey/media-hotkey.js";
12
13
  import { MuteButton } from "../../ui/mute-button/mute-button.js";
13
14
  import { PiPButton } from "../../ui/pip-button/pip-button.js";
14
15
  import { PlayButton } from "../../ui/play-button/play-button.js";
@@ -268,7 +269,83 @@ function VideoSkin(props) {
268
269
  })
269
270
  ] })
270
271
  }),
271
- /* @__PURE__ */ jsx("div", { className: "media-overlay" })
272
+ /* @__PURE__ */ jsx("div", { className: "media-overlay" }),
273
+ /* @__PURE__ */ jsx(MediaHotkey, {
274
+ keys: "Space",
275
+ action: "togglePaused"
276
+ }),
277
+ /* @__PURE__ */ jsx(MediaHotkey, {
278
+ keys: "k",
279
+ action: "togglePaused"
280
+ }),
281
+ /* @__PURE__ */ jsx(MediaHotkey, {
282
+ keys: "m",
283
+ action: "toggleMuted"
284
+ }),
285
+ /* @__PURE__ */ jsx(MediaHotkey, {
286
+ keys: "f",
287
+ action: "toggleFullscreen"
288
+ }),
289
+ /* @__PURE__ */ jsx(MediaHotkey, {
290
+ keys: "c",
291
+ action: "toggleSubtitles"
292
+ }),
293
+ /* @__PURE__ */ jsx(MediaHotkey, {
294
+ keys: "i",
295
+ action: "togglePiP"
296
+ }),
297
+ /* @__PURE__ */ jsx(MediaHotkey, {
298
+ keys: "ArrowRight",
299
+ action: "seekStep",
300
+ value: 5
301
+ }),
302
+ /* @__PURE__ */ jsx(MediaHotkey, {
303
+ keys: "ArrowLeft",
304
+ action: "seekStep",
305
+ value: -5
306
+ }),
307
+ /* @__PURE__ */ jsx(MediaHotkey, {
308
+ keys: "l",
309
+ action: "seekStep",
310
+ value: 10
311
+ }),
312
+ /* @__PURE__ */ jsx(MediaHotkey, {
313
+ keys: "j",
314
+ action: "seekStep",
315
+ value: -10
316
+ }),
317
+ /* @__PURE__ */ jsx(MediaHotkey, {
318
+ keys: "ArrowUp",
319
+ action: "volumeStep",
320
+ value: .05
321
+ }),
322
+ /* @__PURE__ */ jsx(MediaHotkey, {
323
+ keys: "ArrowDown",
324
+ action: "volumeStep",
325
+ value: -.05
326
+ }),
327
+ /* @__PURE__ */ jsx(MediaHotkey, {
328
+ keys: "0-9",
329
+ action: "seekToPercent"
330
+ }),
331
+ /* @__PURE__ */ jsx(MediaHotkey, {
332
+ keys: "Home",
333
+ action: "seekToPercent",
334
+ value: 0
335
+ }),
336
+ /* @__PURE__ */ jsx(MediaHotkey, {
337
+ keys: "End",
338
+ action: "seekToPercent",
339
+ value: 100
340
+ }),
341
+ /* @__PURE__ */ jsx(MediaHotkey, {
342
+ keys: ">",
343
+ action: "speedUp"
344
+ }),
345
+ /* @__PURE__ */ jsx(MediaHotkey, {
346
+ keys: "<",
347
+ action: "speedDown"
348
+ })
272
349
  ]
273
350
  });
274
351
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skin.js","names":["Popover.Root","Popover.Trigger","Popover.Popup","VolumeSlider.Root","VolumeSlider.Track","VolumeSlider.Fill","VolumeSlider.Thumb","ErrorDialog.Root","ErrorDialog.Popup","ErrorDialog.Title","ErrorDialog.Description","ErrorDialog.Close","Controls.Root","Tooltip.Provider","Tooltip.Root","Tooltip.Trigger","Tooltip.Popup","Time.Value","TimeSlider.Root","TimeSlider.Track","TimeSlider.Fill","TimeSlider.Buffer","TimeSlider.Thumb","Slider.Thumbnail","TimeSlider.Value"],"sources":["../../../../src/presets/video/skin.tsx"],"sourcesContent":["import {\n CaptionsOffIcon,\n CaptionsOnIcon,\n FullscreenEnterIcon,\n FullscreenExitIcon,\n PauseIcon,\n PipEnterIcon,\n PipExitIcon,\n PlayIcon,\n RestartIcon,\n SeekIcon,\n SpinnerIcon,\n VolumeHighIcon,\n VolumeLowIcon,\n VolumeOffIcon,\n} from '@videojs/icons/react';\nimport { isString } from '@videojs/utils/predicate';\nimport { cn } from '@videojs/utils/style';\nimport { type ComponentProps, forwardRef, type ReactNode } from 'react';\nimport { Container, usePlayer } from '@/player/context';\nimport { BufferingIndicator } from '@/ui/buffering-indicator';\nimport { CaptionsButton } from '@/ui/captions-button';\nimport { Controls } from '@/ui/controls';\nimport { ErrorDialog } from '@/ui/error-dialog';\nimport { FullscreenButton } from '@/ui/fullscreen-button';\nimport { MuteButton } from '@/ui/mute-button';\nimport { PiPButton } from '@/ui/pip-button';\nimport { PlayButton } from '@/ui/play-button';\nimport { PlaybackRateButton } from '@/ui/playback-rate-button';\nimport { Popover } from '@/ui/popover';\nimport { Poster } from '@/ui/poster';\nimport { SeekButton } from '@/ui/seek-button';\nimport { Slider } from '@/ui/slider';\nimport { Time } from '@/ui/time';\nimport { TimeSlider } from '@/ui/time-slider';\nimport { Tooltip } from '@/ui/tooltip';\nimport { VolumeSlider } from '@/ui/volume-slider';\nimport { isRenderProp } from '@/utils/use-render';\nimport type { BaseVideoSkinProps } from '../types';\n\nconst SEEK_TIME = 10;\n\nexport type VideoSkinProps = BaseVideoSkinProps;\n\nconst Button = forwardRef<HTMLButtonElement, ComponentProps<'button'>>(function Button({ className, ...props }, ref) {\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn('media-button media-button--subtle media-button--icon', className)}\n {...props}\n />\n );\n});\n\nfunction VolumePopover(): ReactNode {\n const volumeUnsupported = usePlayer((s) => s.volumeAvailability === 'unsupported');\n\n const muteButton = (\n <MuteButton className=\"media-button--mute\" render={<Button />}>\n <VolumeOffIcon className=\"media-icon media-icon--volume-off\" />\n <VolumeLowIcon className=\"media-icon media-icon--volume-low\" />\n <VolumeHighIcon className=\"media-icon media-icon--volume-high\" />\n </MuteButton>\n );\n\n if (volumeUnsupported) return muteButton;\n\n return (\n <Popover.Root openOnHover delay={200} closeDelay={100} side=\"top\">\n <Popover.Trigger render={muteButton} />\n <Popover.Popup className=\"media-surface media-popover media-popover--volume\">\n <VolumeSlider.Root className=\"media-slider\" orientation=\"vertical\" thumbAlignment=\"edge\">\n <VolumeSlider.Track className=\"media-slider__track\">\n <VolumeSlider.Fill className=\"media-slider__fill\" />\n </VolumeSlider.Track>\n <VolumeSlider.Thumb className=\"media-slider__thumb media-slider__thumb--persistent\" />\n </VolumeSlider.Root>\n </Popover.Popup>\n </Popover.Root>\n );\n}\n\nexport function VideoSkin(props: VideoSkinProps): ReactNode {\n const { children, className, poster, ...rest } = props;\n\n return (\n <Container className={cn('media-default-skin media-default-skin--video', className)} {...rest}>\n {children}\n\n {poster && (\n <Poster src={isString(poster) ? poster : undefined} render={isRenderProp(poster) ? poster : undefined} />\n )}\n\n <BufferingIndicator\n render={(props) => (\n <div {...props} className=\"media-buffering-indicator\">\n <div className=\"media-surface\">\n <SpinnerIcon className=\"media-icon\" />\n </div>\n </div>\n )}\n />\n\n <ErrorDialog.Root>\n <ErrorDialog.Popup className=\"media-error\">\n <div className=\"media-error__dialog media-surface\">\n <div className=\"media-error__content\">\n <ErrorDialog.Title className=\"media-error__title\">Something went wrong.</ErrorDialog.Title>\n <ErrorDialog.Description className=\"media-error__description\" />\n </div>\n <div className=\"media-error__actions\">\n <ErrorDialog.Close className=\"media-button media-button--primary\">OK</ErrorDialog.Close>\n </div>\n </div>\n </ErrorDialog.Popup>\n </ErrorDialog.Root>\n\n <Controls.Root className=\"media-surface media-controls\">\n <Tooltip.Provider>\n <div className=\"media-button-group\">\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <PlayButton className=\"media-button--play\" render={<Button />}>\n <RestartIcon className=\"media-icon media-icon--restart\" />\n <PlayIcon className=\"media-icon media-icon--play\" />\n <PauseIcon className=\"media-icon media-icon--pause\" />\n </PlayButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <SeekButton seconds={-SEEK_TIME} className=\"media-button--seek\" render={<Button />}>\n <span className=\"media-icon__container\">\n <SeekIcon className=\"media-icon media-icon--seek media-icon--flipped\" />\n <span className=\"media-icon__label\">{SEEK_TIME}</span>\n </span>\n </SeekButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\">Seek backward {SEEK_TIME} seconds</Tooltip.Popup>\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <SeekButton seconds={SEEK_TIME} className=\"media-button--seek\" render={<Button />}>\n <span className=\"media-icon__container\">\n <SeekIcon className=\"media-icon media-icon--seek\" />\n <span className=\"media-icon__label\">{SEEK_TIME}</span>\n </span>\n </SeekButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\">Seek forward {SEEK_TIME} seconds</Tooltip.Popup>\n </Tooltip.Root>\n </div>\n\n <div className=\"media-time-controls\">\n <Time.Value type=\"current\" className=\"media-time\" />\n <TimeSlider.Root className=\"media-slider\">\n <TimeSlider.Track className=\"media-slider__track\">\n <TimeSlider.Fill className=\"media-slider__fill\" />\n <TimeSlider.Buffer className=\"media-slider__buffer\" />\n </TimeSlider.Track>\n <TimeSlider.Thumb className=\"media-slider__thumb\" />\n\n <div className=\"media-surface media-preview media-slider__preview\">\n <Slider.Thumbnail className=\"media-preview__thumbnail\" />\n <TimeSlider.Value type=\"pointer\" className=\"media-time media-preview__time\" />\n <SpinnerIcon className=\"media-preview__spinner media-icon\" />\n </div>\n </TimeSlider.Root>\n <Time.Value type=\"duration\" className=\"media-time\" />\n </div>\n\n <div className=\"media-button-group\">\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={<PlaybackRateButton className=\"media-button--playback-rate\" render={<Button />} />}\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\">Toggle playback rate</Tooltip.Popup>\n </Tooltip.Root>\n\n <VolumePopover />\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <CaptionsButton className=\"media-button--captions\" render={<Button />}>\n <CaptionsOffIcon className=\"media-icon media-icon--captions-off\" />\n <CaptionsOnIcon className=\"media-icon media-icon--captions-on\" />\n </CaptionsButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <PiPButton className=\"media-button--pip\" render={<Button />}>\n <PipEnterIcon className=\"media-icon media-icon--pip-enter\" />\n <PipExitIcon className=\"media-icon media-icon--pip-exit\" />\n </PiPButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <FullscreenButton className=\"media-button--fullscreen\" render={<Button />}>\n <FullscreenEnterIcon className=\"media-icon media-icon--fullscreen-enter\" />\n <FullscreenExitIcon className=\"media-icon media-icon--fullscreen-exit\" />\n </FullscreenButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n </div>\n </Tooltip.Provider>\n </Controls.Root>\n\n <div className=\"media-overlay\" />\n </Container>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skin.js","names":["Popover.Root","Popover.Trigger","Popover.Popup","VolumeSlider.Root","VolumeSlider.Track","VolumeSlider.Fill","VolumeSlider.Thumb","ErrorDialog.Root","ErrorDialog.Popup","ErrorDialog.Title","ErrorDialog.Description","ErrorDialog.Close","Controls.Root","Tooltip.Provider","Tooltip.Root","Tooltip.Trigger","Tooltip.Popup","Time.Value","TimeSlider.Root","TimeSlider.Track","TimeSlider.Fill","TimeSlider.Buffer","TimeSlider.Thumb","Slider.Thumbnail","TimeSlider.Value"],"sources":["../../../../src/presets/video/skin.tsx"],"sourcesContent":["import {\n CaptionsOffIcon,\n CaptionsOnIcon,\n FullscreenEnterIcon,\n FullscreenExitIcon,\n PauseIcon,\n PipEnterIcon,\n PipExitIcon,\n PlayIcon,\n RestartIcon,\n SeekIcon,\n SpinnerIcon,\n VolumeHighIcon,\n VolumeLowIcon,\n VolumeOffIcon,\n} from '@videojs/icons/react';\nimport { isString } from '@videojs/utils/predicate';\nimport { cn } from '@videojs/utils/style';\nimport { type ComponentProps, forwardRef, type ReactNode } from 'react';\nimport { Container, usePlayer } from '@/player/context';\nimport { BufferingIndicator } from '@/ui/buffering-indicator';\nimport { CaptionsButton } from '@/ui/captions-button';\nimport { Controls } from '@/ui/controls';\nimport { ErrorDialog } from '@/ui/error-dialog';\nimport { FullscreenButton } from '@/ui/fullscreen-button';\nimport { MediaHotkey } from '@/ui/hotkey/media-hotkey';\nimport { MuteButton } from '@/ui/mute-button';\nimport { PiPButton } from '@/ui/pip-button';\nimport { PlayButton } from '@/ui/play-button';\nimport { PlaybackRateButton } from '@/ui/playback-rate-button';\nimport { Popover } from '@/ui/popover';\nimport { Poster } from '@/ui/poster';\nimport { SeekButton } from '@/ui/seek-button';\nimport { Slider } from '@/ui/slider';\nimport { Time } from '@/ui/time';\nimport { TimeSlider } from '@/ui/time-slider';\nimport { Tooltip } from '@/ui/tooltip';\nimport { VolumeSlider } from '@/ui/volume-slider';\nimport { isRenderProp } from '@/utils/use-render';\nimport type { BaseVideoSkinProps } from '../types';\n\nconst SEEK_TIME = 10;\n\nexport type VideoSkinProps = BaseVideoSkinProps;\n\nconst Button = forwardRef<HTMLButtonElement, ComponentProps<'button'>>(function Button({ className, ...props }, ref) {\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn('media-button media-button--subtle media-button--icon', className)}\n {...props}\n />\n );\n});\n\nfunction VolumePopover(): ReactNode {\n const volumeUnsupported = usePlayer((s) => s.volumeAvailability === 'unsupported');\n\n const muteButton = (\n <MuteButton className=\"media-button--mute\" render={<Button />}>\n <VolumeOffIcon className=\"media-icon media-icon--volume-off\" />\n <VolumeLowIcon className=\"media-icon media-icon--volume-low\" />\n <VolumeHighIcon className=\"media-icon media-icon--volume-high\" />\n </MuteButton>\n );\n\n if (volumeUnsupported) return muteButton;\n\n return (\n <Popover.Root openOnHover delay={200} closeDelay={100} side=\"top\">\n <Popover.Trigger render={muteButton} />\n <Popover.Popup className=\"media-surface media-popover media-popover--volume\">\n <VolumeSlider.Root className=\"media-slider\" orientation=\"vertical\" thumbAlignment=\"edge\">\n <VolumeSlider.Track className=\"media-slider__track\">\n <VolumeSlider.Fill className=\"media-slider__fill\" />\n </VolumeSlider.Track>\n <VolumeSlider.Thumb className=\"media-slider__thumb media-slider__thumb--persistent\" />\n </VolumeSlider.Root>\n </Popover.Popup>\n </Popover.Root>\n );\n}\n\nexport function VideoSkin(props: VideoSkinProps): ReactNode {\n const { children, className, poster, ...rest } = props;\n\n return (\n <Container className={cn('media-default-skin media-default-skin--video', className)} {...rest}>\n {children}\n\n {poster && (\n <Poster src={isString(poster) ? poster : undefined} render={isRenderProp(poster) ? poster : undefined} />\n )}\n\n <BufferingIndicator\n render={(props) => (\n <div {...props} className=\"media-buffering-indicator\">\n <div className=\"media-surface\">\n <SpinnerIcon className=\"media-icon\" />\n </div>\n </div>\n )}\n />\n\n <ErrorDialog.Root>\n <ErrorDialog.Popup className=\"media-error\">\n <div className=\"media-error__dialog media-surface\">\n <div className=\"media-error__content\">\n <ErrorDialog.Title className=\"media-error__title\">Something went wrong.</ErrorDialog.Title>\n <ErrorDialog.Description className=\"media-error__description\" />\n </div>\n <div className=\"media-error__actions\">\n <ErrorDialog.Close className=\"media-button media-button--primary\">OK</ErrorDialog.Close>\n </div>\n </div>\n </ErrorDialog.Popup>\n </ErrorDialog.Root>\n\n <Controls.Root className=\"media-surface media-controls\">\n <Tooltip.Provider>\n <div className=\"media-button-group\">\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <PlayButton className=\"media-button--play\" render={<Button />}>\n <RestartIcon className=\"media-icon media-icon--restart\" />\n <PlayIcon className=\"media-icon media-icon--play\" />\n <PauseIcon className=\"media-icon media-icon--pause\" />\n </PlayButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <SeekButton seconds={-SEEK_TIME} className=\"media-button--seek\" render={<Button />}>\n <span className=\"media-icon__container\">\n <SeekIcon className=\"media-icon media-icon--seek media-icon--flipped\" />\n <span className=\"media-icon__label\">{SEEK_TIME}</span>\n </span>\n </SeekButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\">Seek backward {SEEK_TIME} seconds</Tooltip.Popup>\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <SeekButton seconds={SEEK_TIME} className=\"media-button--seek\" render={<Button />}>\n <span className=\"media-icon__container\">\n <SeekIcon className=\"media-icon media-icon--seek\" />\n <span className=\"media-icon__label\">{SEEK_TIME}</span>\n </span>\n </SeekButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\">Seek forward {SEEK_TIME} seconds</Tooltip.Popup>\n </Tooltip.Root>\n </div>\n\n <div className=\"media-time-controls\">\n <Time.Value type=\"current\" className=\"media-time\" />\n <TimeSlider.Root className=\"media-slider\">\n <TimeSlider.Track className=\"media-slider__track\">\n <TimeSlider.Fill className=\"media-slider__fill\" />\n <TimeSlider.Buffer className=\"media-slider__buffer\" />\n </TimeSlider.Track>\n <TimeSlider.Thumb className=\"media-slider__thumb\" />\n\n <div className=\"media-surface media-preview media-slider__preview\">\n <Slider.Thumbnail className=\"media-preview__thumbnail\" />\n <TimeSlider.Value type=\"pointer\" className=\"media-time media-preview__time\" />\n <SpinnerIcon className=\"media-preview__spinner media-icon\" />\n </div>\n </TimeSlider.Root>\n <Time.Value type=\"duration\" className=\"media-time\" />\n </div>\n\n <div className=\"media-button-group\">\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={<PlaybackRateButton className=\"media-button--playback-rate\" render={<Button />} />}\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\">Toggle playback rate</Tooltip.Popup>\n </Tooltip.Root>\n\n <VolumePopover />\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <CaptionsButton className=\"media-button--captions\" render={<Button />}>\n <CaptionsOffIcon className=\"media-icon media-icon--captions-off\" />\n <CaptionsOnIcon className=\"media-icon media-icon--captions-on\" />\n </CaptionsButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <PiPButton className=\"media-button--pip\" render={<Button />}>\n <PipEnterIcon className=\"media-icon media-icon--pip-enter\" />\n <PipExitIcon className=\"media-icon media-icon--pip-exit\" />\n </PiPButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n\n <Tooltip.Root side=\"top\">\n <Tooltip.Trigger\n render={\n <FullscreenButton className=\"media-button--fullscreen\" render={<Button />}>\n <FullscreenEnterIcon className=\"media-icon media-icon--fullscreen-enter\" />\n <FullscreenExitIcon className=\"media-icon media-icon--fullscreen-exit\" />\n </FullscreenButton>\n }\n />\n <Tooltip.Popup className=\"media-surface media-tooltip\" />\n </Tooltip.Root>\n </div>\n </Tooltip.Provider>\n </Controls.Root>\n\n <div className=\"media-overlay\" />\n\n {/* Hotkeys */}\n <MediaHotkey keys=\"Space\" action=\"togglePaused\" />\n <MediaHotkey keys=\"k\" action=\"togglePaused\" />\n <MediaHotkey keys=\"m\" action=\"toggleMuted\" />\n <MediaHotkey keys=\"f\" action=\"toggleFullscreen\" />\n <MediaHotkey keys=\"c\" action=\"toggleSubtitles\" />\n <MediaHotkey keys=\"i\" action=\"togglePiP\" />\n <MediaHotkey keys=\"ArrowRight\" action=\"seekStep\" value={5} />\n <MediaHotkey keys=\"ArrowLeft\" action=\"seekStep\" value={-5} />\n <MediaHotkey keys=\"l\" action=\"seekStep\" value={10} />\n <MediaHotkey keys=\"j\" action=\"seekStep\" value={-10} />\n <MediaHotkey keys=\"ArrowUp\" action=\"volumeStep\" value={0.05} />\n <MediaHotkey keys=\"ArrowDown\" action=\"volumeStep\" value={-0.05} />\n <MediaHotkey keys=\"0-9\" action=\"seekToPercent\" />\n <MediaHotkey keys=\"Home\" action=\"seekToPercent\" value={0} />\n <MediaHotkey keys=\"End\" action=\"seekToPercent\" value={100} />\n <MediaHotkey keys=\">\" action=\"speedUp\" />\n <MediaHotkey keys=\"<\" action=\"speedDown\" />\n </Container>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,MAAM,YAAY;AAIlB,MAAM,SAAS,WAAwD,SAAS,OAAO,EAAE,WAAW,GAAG,SAAS,KAAK;AACnH,QACE,oBAAC,UAAD;EACO;EACL,MAAK;EACL,WAAW,GAAG,wDAAwD,UAAU;EAChF,GAAI;EACJ,CAAA;EAEJ;AAEF,SAAS,gBAA2B;CAClC,MAAM,oBAAoB,WAAW,MAAM,EAAE,uBAAuB,cAAc;CAElF,MAAM,aACJ,qBAAC,YAAD;EAAY,WAAU;EAAqB,QAAQ,oBAAC,QAAD,EAAU,CAAA;YAA7D;GACE,oBAAC,eAAD,EAAe,WAAU,qCAAsC,CAAA;GAC/D,oBAAC,eAAD,EAAe,WAAU,qCAAsC,CAAA;GAC/D,oBAAC,gBAAD,EAAgB,WAAU,sCAAuC,CAAA;GACtD;;AAGf,KAAI,kBAAmB,QAAO;AAE9B,QACE,qBAACA,aAAD;EAAc,aAAA;EAAY,OAAO;EAAK,YAAY;EAAK,MAAK;YAA5D,CACE,oBAACC,gBAAD,EAAiB,QAAQ,YAAc,CAAA,EACvC,oBAACC,cAAD;GAAe,WAAU;aACvB,qBAACC,kBAAD;IAAmB,WAAU;IAAe,aAAY;IAAW,gBAAe;cAAlF,CACE,oBAACC,aAAD;KAAoB,WAAU;eAC5B,oBAACC,YAAD,EAAmB,WAAU,sBAAuB,CAAA;KACjC,CAAA,EACrB,oBAACC,aAAD,EAAoB,WAAU,uDAAwD,CAAA,CACpE;;GACN,CAAA,CACH;;;AAInB,SAAgB,UAAU,OAAkC;CAC1D,MAAM,EAAE,UAAU,WAAW,QAAQ,GAAG,SAAS;AAEjD,QACE,qBAAC,WAAD;EAAW,WAAW,GAAG,gDAAgD,UAAU;EAAE,GAAI;YAAzF;GACG;GAEA,UACC,oBAAC,QAAD;IAAQ,KAAK,SAAS,OAAO,GAAG,SAAS,KAAA;IAAW,QAAQ,aAAa,OAAO,GAAG,SAAS,KAAA;IAAa,CAAA;GAG3G,oBAAC,oBAAD,EACE,SAAS,UACP,oBAAC,OAAD;IAAK,GAAI;IAAO,WAAU;cACxB,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,aAAD,EAAa,WAAU,cAAe,CAAA;KAClC,CAAA;IACF,CAAA,EAER,CAAA;GAEF,oBAACC,iBAAD,EAAA,UACE,oBAACC,kBAAD;IAAmB,WAAU;cAC3B,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAACC,kBAAD;OAAmB,WAAU;iBAAqB;OAAyC,CAAA,EAC3F,oBAACC,wBAAD,EAAyB,WAAU,4BAA6B,CAAA,CAC5D;SACN,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAACC,kBAAD;OAAmB,WAAU;iBAAqC;OAAsB,CAAA;MACpF,CAAA,CACF;;IACY,CAAA,EACH,CAAA;GAEnB,oBAACC,cAAD;IAAe,WAAU;cACvB,qBAACC,iBAAD,EAAA,UAAA;KACE,qBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,qBAACC,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QACE,qBAAC,YAAD;SAAY,WAAU;SAAqB,QAAQ,oBAAC,QAAD,EAAU,CAAA;mBAA7D;UACE,oBAAC,aAAD,EAAa,WAAU,kCAAmC,CAAA;UAC1D,oBAAC,UAAD,EAAU,WAAU,+BAAgC,CAAA;UACpD,oBAAC,WAAD,EAAW,WAAU,gCAAiC,CAAA;UAC3C;YAEf,CAAA,EACF,oBAACC,cAAD,EAAe,WAAU,+BAAgC,CAAA,CAC5C;;OAEf,qBAACF,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QACE,oBAAC,YAAD;SAAY,SAAS,CAAC;SAAW,WAAU;SAAqB,QAAQ,oBAAC,QAAD,EAAU,CAAA;mBAChF,qBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,oBAAC,UAAD,EAAU,WAAU,mDAAoD,CAAA,EACxE,oBAAC,QAAD;WAAM,WAAU;qBAAqB;WAAiB,CAAA,CACjD;;SACI,CAAA,EAEf,CAAA,EACF,qBAACC,cAAD;SAAe,WAAU;mBAAzB;UAAuD;UAAe;UAAU;UAAwB;WAC3F;;OAEf,qBAACF,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QACE,oBAAC,YAAD;SAAY,SAAS;SAAW,WAAU;SAAqB,QAAQ,oBAAC,QAAD,EAAU,CAAA;mBAC/E,qBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,oBAAC,UAAD,EAAU,WAAU,+BAAgC,CAAA,EACpD,oBAAC,QAAD;WAAM,WAAU;qBAAqB;WAAiB,CAAA,CACjD;;SACI,CAAA,EAEf,CAAA,EACF,qBAACC,cAAD;SAAe,WAAU;mBAAzB;UAAuD;UAAc;UAAU;UAAwB;WAC1F;;OACX;;KAEN,qBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,oBAACC,OAAD;QAAY,MAAK;QAAU,WAAU;QAAe,CAAA;OACpD,qBAACC,gBAAD;QAAiB,WAAU;kBAA3B;SACE,qBAACC,aAAD;UAAkB,WAAU;oBAA5B,CACE,oBAACC,YAAD,EAAiB,WAAU,sBAAuB,CAAA,EAClD,oBAACC,cAAD,EAAmB,WAAU,wBAAyB,CAAA,CACrC;;SACnB,oBAACC,aAAD,EAAkB,WAAU,uBAAwB,CAAA;SAEpD,qBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,oBAACC,iBAAD,EAAkB,WAAU,4BAA6B,CAAA;WACzD,oBAACC,aAAD;YAAkB,MAAK;YAAU,WAAU;YAAmC,CAAA;WAC9E,oBAAC,aAAD,EAAa,WAAU,qCAAsC,CAAA;WACzD;;SACU;;OAClB,oBAACP,OAAD;QAAY,MAAK;QAAW,WAAU;QAAe,CAAA;OACjD;;KAEN,qBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,qBAACH,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QAAQ,oBAAC,oBAAD;SAAoB,WAAU;SAA8B,QAAQ,oBAAC,QAAD,EAAU,CAAA;SAAI,CAAA,EAC1F,CAAA,EACF,oBAACC,cAAD;SAAe,WAAU;mBAA8B;SAAoC,CAAA,CAC9E;;OAEf,oBAAC,eAAD,EAAiB,CAAA;OAEjB,qBAACF,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QACE,qBAAC,gBAAD;SAAgB,WAAU;SAAyB,QAAQ,oBAAC,QAAD,EAAU,CAAA;mBAArE,CACE,oBAAC,iBAAD,EAAiB,WAAU,uCAAwC,CAAA,EACnE,oBAAC,gBAAD,EAAgB,WAAU,sCAAuC,CAAA,CAClD;YAEnB,CAAA,EACF,oBAACC,cAAD,EAAe,WAAU,+BAAgC,CAAA,CAC5C;;OAEf,qBAACF,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QACE,qBAAC,WAAD;SAAW,WAAU;SAAoB,QAAQ,oBAAC,QAAD,EAAU,CAAA;mBAA3D,CACE,oBAAC,cAAD,EAAc,WAAU,oCAAqC,CAAA,EAC7D,oBAAC,aAAD,EAAa,WAAU,mCAAoC,CAAA,CACjD;YAEd,CAAA,EACF,oBAACC,cAAD,EAAe,WAAU,+BAAgC,CAAA,CAC5C;;OAEf,qBAACF,aAAD;QAAc,MAAK;kBAAnB,CACE,oBAACC,gBAAD,EACE,QACE,qBAAC,kBAAD;SAAkB,WAAU;SAA2B,QAAQ,oBAAC,QAAD,EAAU,CAAA;mBAAzE,CACE,oBAAC,qBAAD,EAAqB,WAAU,2CAA4C,CAAA,EAC3E,oBAAC,oBAAD,EAAoB,WAAU,0CAA2C,CAAA,CACxD;YAErB,CAAA,EACF,oBAACC,cAAD,EAAe,WAAU,+BAAgC,CAAA,CAC5C;;OACX;;KACW,EAAA,CAAA;IACL,CAAA;GAEhB,oBAAC,OAAD,EAAK,WAAU,iBAAkB,CAAA;GAGjC,oBAAC,aAAD;IAAa,MAAK;IAAQ,QAAO;IAAiB,CAAA;GAClD,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAiB,CAAA;GAC9C,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAgB,CAAA;GAC7C,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAqB,CAAA;GAClD,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAoB,CAAA;GACjD,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAc,CAAA;GAC3C,oBAAC,aAAD;IAAa,MAAK;IAAa,QAAO;IAAW,OAAO;IAAK,CAAA;GAC7D,oBAAC,aAAD;IAAa,MAAK;IAAY,QAAO;IAAW,OAAO;IAAM,CAAA;GAC7D,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAW,OAAO;IAAM,CAAA;GACrD,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAW,OAAO;IAAO,CAAA;GACtD,oBAAC,aAAD;IAAa,MAAK;IAAU,QAAO;IAAa,OAAO;IAAQ,CAAA;GAC/D,oBAAC,aAAD;IAAa,MAAK;IAAY,QAAO;IAAa,OAAO;IAAS,CAAA;GAClE,oBAAC,aAAD;IAAa,MAAK;IAAM,QAAO;IAAkB,CAAA;GACjD,oBAAC,aAAD;IAAa,MAAK;IAAO,QAAO;IAAgB,OAAO;IAAK,CAAA;GAC5D,oBAAC,aAAD;IAAa,MAAK;IAAM,QAAO;IAAgB,OAAO;IAAO,CAAA;GAC7D,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAY,CAAA;GACzC,oBAAC,aAAD;IAAa,MAAK;IAAI,QAAO;IAAc,CAAA;GACjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"captions-button.d.ts","names":[],"sources":["../../../../src/ui/captions-button/captions-button.tsx"],"mappings":";;;;;UAQiB,mBAAA,SACP,gBAAA,WAA2B,kBAAA,CAAmB,KAAA,GACpD,kBAAA,CAAmB,KAAA;;cAGV,cAAA,EAAc,KAAA,CAAA,yBAAA,CAAA,mBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA;AAAA,kBAQV,cAAA;EAAA,KACH,KAAA,GAAQ,mBAAA;EAAA,KACR,KAAA,GAAQ,kBAAA,CAAmB,KAAA;AAAA"}
1
+ {"version":3,"file":"captions-button.d.ts","names":[],"sources":["../../../../src/ui/captions-button/captions-button.tsx"],"mappings":";;;;;UAQiB,mBAAA,SACP,gBAAA,WAA2B,kBAAA,CAAmB,KAAA,GACpD,kBAAA,CAAmB,KAAA;;cAGV,cAAA,EAAc,KAAA,CAAA,yBAAA,CAAA,mBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA;AAAA,kBASV,cAAA;EAAA,KACH,KAAA,GAAQ,mBAAA;EAAA,KACR,KAAA,GAAQ,kBAAA,CAAmB,KAAA;AAAA"}
@@ -9,7 +9,8 @@ const CaptionsButton = createMediaButton({
9
9
  core: CaptionsButtonCore,
10
10
  stateAttrMap: CaptionsButtonDataAttrs,
11
11
  selector: selectTextTrack,
12
- action: (core, state) => core.toggle(state)
12
+ action: (core, state) => core.toggle(state),
13
+ hotkeyAction: "toggleSubtitles"
13
14
  });
14
15
  //#endregion
15
16
  export { CaptionsButton };
@@ -1 +1 @@
1
- {"version":3,"file":"captions-button.js","names":[],"sources":["../../../../src/ui/captions-button/captions-button.tsx"],"sourcesContent":["'use client';\n\nimport { CaptionsButtonCore, CaptionsButtonDataAttrs } from '@videojs/core';\nimport { selectTextTrack } from '@videojs/core/dom';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { createMediaButton } from '../create-media-button';\n\nexport interface CaptionsButtonProps\n extends UIComponentProps<'button', CaptionsButtonCore.State>,\n CaptionsButtonCore.Props {}\n\n/** A button that toggles captions. */\nexport const CaptionsButton = createMediaButton<CaptionsButtonCore, CaptionsButtonProps>({\n displayName: 'CaptionsButton',\n core: CaptionsButtonCore,\n stateAttrMap: CaptionsButtonDataAttrs,\n selector: selectTextTrack,\n action: (core, state) => core.toggle(state),\n});\n\nexport namespace CaptionsButton {\n export type Props = CaptionsButtonProps;\n export type State = CaptionsButtonCore.State;\n}\n"],"mappings":";;;;;;AAaA,MAAa,iBAAiB,kBAA2D;CACvF,aAAa;CACb,MAAM;CACN,cAAc;CACd,UAAU;CACV,SAAS,MAAM,UAAU,KAAK,OAAO,MAAM;CAC5C,CAAC"}
1
+ {"version":3,"file":"captions-button.js","names":[],"sources":["../../../../src/ui/captions-button/captions-button.tsx"],"sourcesContent":["'use client';\n\nimport { CaptionsButtonCore, CaptionsButtonDataAttrs } from '@videojs/core';\nimport { selectTextTrack } from '@videojs/core/dom';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { createMediaButton } from '../create-media-button';\n\nexport interface CaptionsButtonProps\n extends UIComponentProps<'button', CaptionsButtonCore.State>,\n CaptionsButtonCore.Props {}\n\n/** A button that toggles captions. */\nexport const CaptionsButton = createMediaButton<CaptionsButtonCore, CaptionsButtonProps>({\n displayName: 'CaptionsButton',\n core: CaptionsButtonCore,\n stateAttrMap: CaptionsButtonDataAttrs,\n selector: selectTextTrack,\n action: (core, state) => core.toggle(state),\n hotkeyAction: 'toggleSubtitles',\n});\n\nexport namespace CaptionsButton {\n export type Props = CaptionsButtonProps;\n export type State = CaptionsButtonCore.State;\n}\n"],"mappings":";;;;;;AAaA,MAAa,iBAAiB,kBAA2D;CACvF,aAAa;CACb,MAAM;CACN,cAAc;CACd,UAAU;CACV,SAAS,MAAM,UAAU,KAAK,OAAO,MAAM;CAC3C,cAAc;CACf,CAAC"}
@@ -2,13 +2,14 @@
2
2
  import { usePlayer } from "../player/context.js";
3
3
  import { renderElement } from "../utils/use-render.js";
4
4
  import { useButton } from "./hooks/use-button.js";
5
+ import { useAriaKeyShortcuts } from "./hotkey/use-aria-key-shortcuts.js";
5
6
  import { useOptionalTooltipContext } from "./tooltip/context.js";
6
7
  import { logMissingFeature } from "@videojs/core/dom";
7
8
  import { forwardRef, useLayoutEffect, useState } from "react";
8
9
  //#region src/ui/create-media-button.tsx
9
10
  /** Creates a media button React component from a core class and config. */
10
11
  function createMediaButton(config) {
11
- const { displayName, core: CoreClass, stateAttrMap, selector, action } = config;
12
+ const { displayName, core: CoreClass, stateAttrMap, selector, action, hotkeyAction } = config;
12
13
  const corePropKeys = new Set(Object.keys(CoreClass.defaultProps));
13
14
  const Component = forwardRef(function MediaButton(componentProps, forwardedRef) {
14
15
  const { render, className, style, ...rest } = componentProps;
@@ -18,6 +19,7 @@ function createMediaButton(config) {
18
19
  else elementProps[key] = rest[key];
19
20
  const tooltipCtx = useOptionalTooltipContext();
20
21
  const feature = usePlayer(selector);
22
+ const shortcuts = useAriaKeyShortcuts(hotkeyAction);
21
23
  const [core] = useState(() => new CoreClass());
22
24
  core.setProps(coreProps);
23
25
  const { getButtonProps, buttonRef } = useButton({
@@ -37,7 +39,10 @@ function createMediaButton(config) {
37
39
  logMissingFeature(displayName, selector.displayName ?? displayName);
38
40
  return null;
39
41
  }
40
- const attrs = core.getAttrs(state);
42
+ const attrs = {
43
+ ...core.getAttrs(state),
44
+ "aria-keyshortcuts": shortcuts
45
+ };
41
46
  return renderElement("button", {
42
47
  render,
43
48
  className,
@@ -1 +1 @@
1
- {"version":3,"file":"create-media-button.js","names":[],"sources":["../../../src/ui/create-media-button.tsx"],"sourcesContent":["'use client';\n\nimport type { InferComponentState, InferMediaState, MediaButtonComponent, StateAttrMap } from '@videojs/core';\nimport { logMissingFeature } from '@videojs/core/dom';\nimport type { Selector } from '@videojs/store';\nimport type { ForwardedRef, ForwardRefExoticComponent, RefAttributes } from 'react';\nimport { forwardRef, useLayoutEffect, useState } from 'react';\n\nimport { usePlayer } from '../player/context';\nimport type { renderElement as renderElementFn } from '../utils/use-render';\nimport { renderElement } from '../utils/use-render';\nimport { useButton } from './hooks/use-button';\nimport { useOptionalTooltipContext } from './tooltip/context';\n\ninterface MediaButtonConfig<Core extends Required<MediaButtonComponent>> {\n displayName: string;\n core: { new (): Core; defaultProps: Record<string, unknown> };\n stateAttrMap: StateAttrMap<InferComponentState<Core>>;\n selector: Selector<object, InferMediaState<Core> | undefined>;\n action: (core: Core, state: InferMediaState<Core>) => void;\n}\n\n/** Creates a media button React component from a core class and config. */\nexport function createMediaButton<Core extends Required<MediaButtonComponent>, Props extends object>(\n config: MediaButtonConfig<Core>\n): ForwardRefExoticComponent<Props & RefAttributes<HTMLButtonElement>> {\n const { displayName, core: CoreClass, stateAttrMap, selector, action } = config;\n\n // Props that exist in the core's defaultProps are routed to setProps; the rest go to the DOM element.\n const corePropKeys = new Set(Object.keys(CoreClass.defaultProps));\n\n const Component = forwardRef(function MediaButton(\n componentProps: Record<string, unknown>,\n forwardedRef: ForwardedRef<HTMLButtonElement>\n ) {\n const { render, className, style, ...rest } = componentProps;\n\n const coreProps: Record<string, unknown> = {};\n const elementProps: Record<string, unknown> = {};\n\n for (const key of Object.keys(rest)) {\n if (corePropKeys.has(key)) {\n coreProps[key] = rest[key];\n } else {\n elementProps[key] = rest[key];\n }\n }\n\n const tooltipCtx = useOptionalTooltipContext();\n const feature = usePlayer(selector);\n\n const [core] = useState(() => new CoreClass());\n core.setProps(coreProps);\n\n const { getButtonProps, buttonRef } = useButton({\n displayName,\n onActivate: () => action(core, feature!),\n isDisabled: () => !!coreProps.disabled || !feature,\n });\n\n // Derive state and label before the hooks boundary so the\n // useLayoutEffect below (called unconditionally) can reference them.\n type State = InferComponentState<Core>;\n if (feature) core.setMedia(feature);\n const state = feature ? (core.getState() as State) : null;\n const label = state ? core.getLabel(state) : undefined;\n\n // Forward label to tooltip popup content when inside a Tooltip.Root.\n useLayoutEffect(() => {\n if (!tooltipCtx) return;\n tooltipCtx.setContent(label);\n return () => tooltipCtx.setContent(undefined);\n }, [tooltipCtx, label]);\n\n if (!feature || !state) {\n if (__DEV__) logMissingFeature(displayName, selector.displayName ?? displayName);\n return null;\n }\n\n const attrs = core.getAttrs(state);\n\n return renderElement(\n 'button',\n { render, className, style } as renderElementFn.ComponentProps<InferComponentState<Core>>,\n {\n state,\n stateAttrMap,\n ref: [forwardedRef, buttonRef],\n props: [attrs, elementProps, getButtonProps()],\n }\n );\n });\n\n Component.displayName = displayName;\n\n return Component as unknown as ForwardRefExoticComponent<Props & RefAttributes<HTMLButtonElement>>;\n}\n"],"mappings":";;;;;;;;;AAuBA,SAAgB,kBACd,QACqE;CACrE,MAAM,EAAE,aAAa,MAAM,WAAW,cAAc,UAAU,WAAW;CAGzE,MAAM,eAAe,IAAI,IAAI,OAAO,KAAK,UAAU,aAAa,CAAC;CAEjE,MAAM,YAAY,WAAW,SAAS,YACpC,gBACA,cACA;EACA,MAAM,EAAE,QAAQ,WAAW,OAAO,GAAG,SAAS;EAE9C,MAAM,YAAqC,EAAE;EAC7C,MAAM,eAAwC,EAAE;AAEhD,OAAK,MAAM,OAAO,OAAO,KAAK,KAAK,CACjC,KAAI,aAAa,IAAI,IAAI,CACvB,WAAU,OAAO,KAAK;MAEtB,cAAa,OAAO,KAAK;EAI7B,MAAM,aAAa,2BAA2B;EAC9C,MAAM,UAAU,UAAU,SAAS;EAEnC,MAAM,CAAC,QAAQ,eAAe,IAAI,WAAW,CAAC;AAC9C,OAAK,SAAS,UAAU;EAExB,MAAM,EAAE,gBAAgB,cAAc,UAAU;GAC9C;GACA,kBAAkB,OAAO,MAAM,QAAS;GACxC,kBAAkB,CAAC,CAAC,UAAU,YAAY,CAAC;GAC5C,CAAC;AAKF,MAAI,QAAS,MAAK,SAAS,QAAQ;EACnC,MAAM,QAAQ,UAAW,KAAK,UAAU,GAAa;EACrD,MAAM,QAAQ,QAAQ,KAAK,SAAS,MAAM,GAAG,KAAA;AAG7C,wBAAsB;AACpB,OAAI,CAAC,WAAY;AACjB,cAAW,WAAW,MAAM;AAC5B,gBAAa,WAAW,WAAW,KAAA,EAAU;KAC5C,CAAC,YAAY,MAAM,CAAC;AAEvB,MAAI,CAAC,WAAW,CAAC,OAAO;AACT,qBAAkB,aAAa,SAAS,eAAe,YAAY;AAChF,UAAO;;EAGT,MAAM,QAAQ,KAAK,SAAS,MAAM;AAElC,SAAO,cACL,UACA;GAAE;GAAQ;GAAW;GAAO,EAC5B;GACE;GACA;GACA,KAAK,CAAC,cAAc,UAAU;GAC9B,OAAO;IAAC;IAAO;IAAc,gBAAgB;IAAC;GAC/C,CACF;GACD;AAEF,WAAU,cAAc;AAExB,QAAO"}
1
+ {"version":3,"file":"create-media-button.js","names":[],"sources":["../../../src/ui/create-media-button.tsx"],"sourcesContent":["'use client';\n\nimport type { InferComponentState, InferMediaState, MediaButtonComponent, StateAttrMap } from '@videojs/core';\nimport { logMissingFeature } from '@videojs/core/dom';\nimport type { Selector } from '@videojs/store';\nimport type { ForwardedRef, ForwardRefExoticComponent, RefAttributes } from 'react';\nimport { forwardRef, useLayoutEffect, useState } from 'react';\n\nimport { usePlayer } from '../player/context';\nimport type { renderElement as renderElementFn } from '../utils/use-render';\nimport { renderElement } from '../utils/use-render';\nimport { useButton } from './hooks/use-button';\nimport { useAriaKeyShortcuts } from './hotkey/use-aria-key-shortcuts';\nimport { useOptionalTooltipContext } from './tooltip/context';\n\ninterface MediaButtonConfig<Core extends Required<MediaButtonComponent>> {\n displayName: string;\n core: { new (): Core; defaultProps: Record<string, unknown> };\n stateAttrMap: StateAttrMap<InferComponentState<Core>>;\n selector: Selector<object, InferMediaState<Core> | undefined>;\n action: (core: Core, state: InferMediaState<Core>) => void;\n hotkeyAction?: string;\n}\n\n/** Creates a media button React component from a core class and config. */\nexport function createMediaButton<Core extends Required<MediaButtonComponent>, Props extends object>(\n config: MediaButtonConfig<Core>\n): ForwardRefExoticComponent<Props & RefAttributes<HTMLButtonElement>> {\n const { displayName, core: CoreClass, stateAttrMap, selector, action, hotkeyAction } = config;\n\n // Props that exist in the core's defaultProps are routed to setProps; the rest go to the DOM element.\n const corePropKeys = new Set(Object.keys(CoreClass.defaultProps));\n\n const Component = forwardRef(function MediaButton(\n componentProps: Record<string, unknown>,\n forwardedRef: ForwardedRef<HTMLButtonElement>\n ) {\n const { render, className, style, ...rest } = componentProps;\n\n const coreProps: Record<string, unknown> = {};\n const elementProps: Record<string, unknown> = {};\n\n for (const key of Object.keys(rest)) {\n if (corePropKeys.has(key)) {\n coreProps[key] = rest[key];\n } else {\n elementProps[key] = rest[key];\n }\n }\n\n const tooltipCtx = useOptionalTooltipContext();\n const feature = usePlayer(selector);\n const shortcuts = useAriaKeyShortcuts(hotkeyAction);\n\n const [core] = useState(() => new CoreClass());\n core.setProps(coreProps);\n\n const { getButtonProps, buttonRef } = useButton({\n displayName,\n onActivate: () => action(core, feature!),\n isDisabled: () => !!coreProps.disabled || !feature,\n });\n\n // Derive state and label before the hooks boundary so the\n // useLayoutEffect below (called unconditionally) can reference them.\n type State = InferComponentState<Core>;\n if (feature) core.setMedia(feature);\n const state = feature ? (core.getState() as State) : null;\n const label = state ? core.getLabel(state) : undefined;\n\n // Forward label to tooltip popup content when inside a Tooltip.Root.\n useLayoutEffect(() => {\n if (!tooltipCtx) return;\n tooltipCtx.setContent(label);\n return () => tooltipCtx.setContent(undefined);\n }, [tooltipCtx, label]);\n\n if (!feature || !state) {\n if (__DEV__) logMissingFeature(displayName, selector.displayName ?? displayName);\n return null;\n }\n\n const attrs = { ...core.getAttrs(state), 'aria-keyshortcuts': shortcuts };\n\n return renderElement(\n 'button',\n { render, className, style } as renderElementFn.ComponentProps<InferComponentState<Core>>,\n {\n state,\n stateAttrMap,\n ref: [forwardedRef, buttonRef],\n props: [attrs, elementProps, getButtonProps()],\n }\n );\n });\n\n Component.displayName = displayName;\n\n return Component as unknown as ForwardRefExoticComponent<Props & RefAttributes<HTMLButtonElement>>;\n}\n"],"mappings":";;;;;;;;;;AAyBA,SAAgB,kBACd,QACqE;CACrE,MAAM,EAAE,aAAa,MAAM,WAAW,cAAc,UAAU,QAAQ,iBAAiB;CAGvF,MAAM,eAAe,IAAI,IAAI,OAAO,KAAK,UAAU,aAAa,CAAC;CAEjE,MAAM,YAAY,WAAW,SAAS,YACpC,gBACA,cACA;EACA,MAAM,EAAE,QAAQ,WAAW,OAAO,GAAG,SAAS;EAE9C,MAAM,YAAqC,EAAE;EAC7C,MAAM,eAAwC,EAAE;AAEhD,OAAK,MAAM,OAAO,OAAO,KAAK,KAAK,CACjC,KAAI,aAAa,IAAI,IAAI,CACvB,WAAU,OAAO,KAAK;MAEtB,cAAa,OAAO,KAAK;EAI7B,MAAM,aAAa,2BAA2B;EAC9C,MAAM,UAAU,UAAU,SAAS;EACnC,MAAM,YAAY,oBAAoB,aAAa;EAEnD,MAAM,CAAC,QAAQ,eAAe,IAAI,WAAW,CAAC;AAC9C,OAAK,SAAS,UAAU;EAExB,MAAM,EAAE,gBAAgB,cAAc,UAAU;GAC9C;GACA,kBAAkB,OAAO,MAAM,QAAS;GACxC,kBAAkB,CAAC,CAAC,UAAU,YAAY,CAAC;GAC5C,CAAC;AAKF,MAAI,QAAS,MAAK,SAAS,QAAQ;EACnC,MAAM,QAAQ,UAAW,KAAK,UAAU,GAAa;EACrD,MAAM,QAAQ,QAAQ,KAAK,SAAS,MAAM,GAAG,KAAA;AAG7C,wBAAsB;AACpB,OAAI,CAAC,WAAY;AACjB,cAAW,WAAW,MAAM;AAC5B,gBAAa,WAAW,WAAW,KAAA,EAAU;KAC5C,CAAC,YAAY,MAAM,CAAC;AAEvB,MAAI,CAAC,WAAW,CAAC,OAAO;AACT,qBAAkB,aAAa,SAAS,eAAe,YAAY;AAChF,UAAO;;EAGT,MAAM,QAAQ;GAAE,GAAG,KAAK,SAAS,MAAM;GAAE,qBAAqB;GAAW;AAEzE,SAAO,cACL,UACA;GAAE;GAAQ;GAAW;GAAO,EAC5B;GACE;GACA;GACA,KAAK,CAAC,cAAc,UAAU;GAC9B,OAAO;IAAC;IAAO;IAAc,gBAAgB;IAAC;GAC/C,CACF;GACD;AAEF,WAAU,cAAc;AAExB,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"fullscreen-button.d.ts","names":[],"sources":["../../../../src/ui/fullscreen-button/fullscreen-button.tsx"],"mappings":";;;;;UAQiB,qBAAA,SACP,gBAAA,WAA2B,oBAAA,CAAqB,KAAA,GACtD,oBAAA,CAAqB,KAAA;;cAGZ,gBAAA,EAAgB,KAAA,CAAA,yBAAA,CAAA,qBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA;AAAA,kBAQZ,gBAAA;EAAA,KACH,KAAA,GAAQ,qBAAA;EAAA,KACR,KAAA,GAAQ,oBAAA,CAAqB,KAAA;AAAA"}
1
+ {"version":3,"file":"fullscreen-button.d.ts","names":[],"sources":["../../../../src/ui/fullscreen-button/fullscreen-button.tsx"],"mappings":";;;;;UAQiB,qBAAA,SACP,gBAAA,WAA2B,oBAAA,CAAqB,KAAA,GACtD,oBAAA,CAAqB,KAAA;;cAGZ,gBAAA,EAAgB,KAAA,CAAA,yBAAA,CAAA,qBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA;AAAA,kBASZ,gBAAA;EAAA,KACH,KAAA,GAAQ,qBAAA;EAAA,KACR,KAAA,GAAQ,oBAAA,CAAqB,KAAA;AAAA"}
@@ -9,7 +9,8 @@ const FullscreenButton = createMediaButton({
9
9
  core: FullscreenButtonCore,
10
10
  stateAttrMap: FullscreenButtonDataAttrs,
11
11
  selector: selectFullscreen,
12
- action: (core, state) => core.toggle(state)
12
+ action: (core, state) => core.toggle(state),
13
+ hotkeyAction: "toggleFullscreen"
13
14
  });
14
15
  //#endregion
15
16
  export { FullscreenButton };
@@ -1 +1 @@
1
- {"version":3,"file":"fullscreen-button.js","names":[],"sources":["../../../../src/ui/fullscreen-button/fullscreen-button.tsx"],"sourcesContent":["'use client';\n\nimport { FullscreenButtonCore, FullscreenButtonDataAttrs } from '@videojs/core';\nimport { selectFullscreen } from '@videojs/core/dom';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { createMediaButton } from '../create-media-button';\n\nexport interface FullscreenButtonProps\n extends UIComponentProps<'button', FullscreenButtonCore.State>,\n FullscreenButtonCore.Props {}\n\n/** A button that toggles fullscreen. */\nexport const FullscreenButton = createMediaButton<FullscreenButtonCore, FullscreenButtonProps>({\n displayName: 'FullscreenButton',\n core: FullscreenButtonCore,\n stateAttrMap: FullscreenButtonDataAttrs,\n selector: selectFullscreen,\n action: (core, state) => core.toggle(state),\n});\n\nexport namespace FullscreenButton {\n export type Props = FullscreenButtonProps;\n export type State = FullscreenButtonCore.State;\n}\n"],"mappings":";;;;;;AAaA,MAAa,mBAAmB,kBAA+D;CAC7F,aAAa;CACb,MAAM;CACN,cAAc;CACd,UAAU;CACV,SAAS,MAAM,UAAU,KAAK,OAAO,MAAM;CAC5C,CAAC"}
1
+ {"version":3,"file":"fullscreen-button.js","names":[],"sources":["../../../../src/ui/fullscreen-button/fullscreen-button.tsx"],"sourcesContent":["'use client';\n\nimport { FullscreenButtonCore, FullscreenButtonDataAttrs } from '@videojs/core';\nimport { selectFullscreen } from '@videojs/core/dom';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { createMediaButton } from '../create-media-button';\n\nexport interface FullscreenButtonProps\n extends UIComponentProps<'button', FullscreenButtonCore.State>,\n FullscreenButtonCore.Props {}\n\n/** A button that toggles fullscreen. */\nexport const FullscreenButton = createMediaButton<FullscreenButtonCore, FullscreenButtonProps>({\n displayName: 'FullscreenButton',\n core: FullscreenButtonCore,\n stateAttrMap: FullscreenButtonDataAttrs,\n selector: selectFullscreen,\n action: (core, state) => core.toggle(state),\n hotkeyAction: 'toggleFullscreen',\n});\n\nexport namespace FullscreenButton {\n export type Props = FullscreenButtonProps;\n export type State = FullscreenButtonCore.State;\n}\n"],"mappings":";;;;;;AAaA,MAAa,mBAAmB,kBAA+D;CAC7F,aAAa;CACb,MAAM;CACN,cAAc;CACd,UAAU;CACV,SAAS,MAAM,UAAU,KAAK,OAAO,MAAM;CAC3C,cAAc;CACf,CAAC"}
@@ -2,7 +2,7 @@ import { SliderInput, SliderState } from "@videojs/core";
2
2
  import { SliderOptions, SliderRootProps, SliderRootStyle, SliderThumbProps } from "@videojs/core/dom";
3
3
 
4
4
  //#region src/ui/hooks/use-slider.d.ts
5
- interface UseSliderOptions<State extends SliderState = SliderState> extends Pick<SliderOptions, 'getPercent' | 'getStepPercent' | 'getLargeStepPercent' | 'commitThrottle' | 'onValueChange' | 'onValueCommit' | 'onDragStart' | 'onDragEnd'> {
5
+ interface UseSliderOptions<State extends SliderState = SliderState> extends Pick<SliderOptions, 'getPercent' | 'getStepPercent' | 'getLargeStepPercent' | 'changeThrottle' | 'onValueChange' | 'onValueCommit' | 'onDragStart' | 'onDragEnd'> {
6
6
  computeState: (input: SliderInput) => State;
7
7
  orientation?: 'horizontal' | 'vertical' | undefined;
8
8
  disabled?: boolean | undefined;
@@ -29,7 +29,7 @@ function useSlider(options) {
29
29
  getPercent: () => optionsRef.current.getPercent(),
30
30
  getStepPercent: () => optionsRef.current.getStepPercent(),
31
31
  getLargeStepPercent: () => optionsRef.current.getLargeStepPercent(),
32
- commitThrottle: optionsRef.current.commitThrottle,
32
+ changeThrottle: optionsRef.current.changeThrottle,
33
33
  adjustPercent: optionsRef.current.adjustPercent,
34
34
  onValueChange: (percent) => optionsRef.current.onValueChange?.(percent),
35
35
  onValueCommit: (percent) => optionsRef.current.onValueCommit?.(percent),
@@ -1 +1 @@
1
- {"version":3,"file":"use-slider.js","names":[],"sources":["../../../../src/ui/hooks/use-slider.ts"],"sourcesContent":["'use client';\n\nimport type { SliderInput, SliderState } from '@videojs/core';\nimport {\n createSlider,\n type SliderApi,\n type SliderOptions,\n type SliderRootProps,\n type SliderRootStyle,\n type SliderThumbProps,\n} from '@videojs/core/dom';\nimport { useSnapshot } from '@videojs/store/react';\nimport { isRTL } from '@videojs/utils/dom';\nimport { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport { useDestroy } from '../../utils/use-destroy';\nimport { useForceRender } from '../../utils/use-force-render';\nimport { useLatestRef } from '../../utils/use-latest-ref';\n\nexport interface UseSliderOptions<State extends SliderState = SliderState>\n extends Pick<\n SliderOptions,\n | 'getPercent'\n | 'getStepPercent'\n | 'getLargeStepPercent'\n | 'commitThrottle'\n | 'onValueChange'\n | 'onValueCommit'\n | 'onDragStart'\n | 'onDragEnd'\n > {\n computeState: (input: SliderInput) => State;\n orientation?: 'horizontal' | 'vertical' | undefined;\n disabled?: boolean | undefined;\n /** Adjust a raw 0–100 percent for thumb alignment. Called for fill and pointer percents. */\n adjustPercent?: ((rawPercent: number, thumbSize: number, trackSize: number) => number) | undefined;\n /** Compute CSS variable map from the (possibly alignment-adjusted) state. */\n getCSSVars: (state: State) => Record<string, string>;\n}\n\nexport interface UseSliderReturnValue<State extends SliderState = SliderState> {\n state: State;\n cssVars: Record<string, string>;\n rootRef: React.RefCallback<HTMLElement>;\n thumbRef: React.RefCallback<HTMLElement>;\n rootProps: SliderRootProps;\n rootStyle: SliderRootStyle;\n thumbProps: SliderThumbProps;\n}\n\n/**\n * Manages slider input lifecycle for React.\n *\n * Wraps `createSlider()` from `@videojs/core/dom` and subscribes to its\n * input state via `useSnapshot`. Returns split props for the root\n * (pointer events) and thumb (keyboard/focus) elements.\n */\nexport function useSlider<State extends SliderState = SliderState>(\n options: UseSliderOptions<State>\n): UseSliderReturnValue<State> {\n const optionsRef = useLatestRef(options);\n\n const rootElementRef = useRef<HTMLElement | null>(null);\n const thumbElementRef = useRef<HTMLElement | null>(null);\n const forceRender = useForceRender();\n\n // Lazy-init the slider handle. Stable across re-renders.\n const [slider] = useState<SliderApi>(() => {\n const stableOptions: SliderOptions = {\n getElement: () => rootElementRef.current!,\n getThumbElement: () => thumbElementRef.current,\n getOrientation: () => optionsRef.current.orientation ?? 'horizontal',\n isRTL: () => (rootElementRef.current ? isRTL(rootElementRef.current) : false),\n isDisabled: () => optionsRef.current.disabled ?? false,\n getPercent: () => optionsRef.current.getPercent(),\n getStepPercent: () => optionsRef.current.getStepPercent(),\n getLargeStepPercent: () => optionsRef.current.getLargeStepPercent(),\n commitThrottle: optionsRef.current.commitThrottle,\n adjustPercent: optionsRef.current.adjustPercent,\n onValueChange: (percent) => optionsRef.current.onValueChange?.(percent),\n onValueCommit: (percent) => optionsRef.current.onValueCommit?.(percent),\n onDragStart: () => optionsRef.current.onDragStart?.(),\n onDragEnd: () => optionsRef.current.onDragEnd?.(),\n };\n\n return createSlider(stableOptions);\n });\n\n useDestroy(slider);\n\n // Subscribe to slider input state.\n const input = useSnapshot(slider.input);\n\n // Compute derived state from input + caller-provided projection.\n const state = options.computeState(input);\n\n // Force a synchronous re-render after mount so edge thumb alignment\n // can read DOM measurements from the now-populated element refs.\n useLayoutEffect(() => {\n if (state.thumbAlignment === 'edge' && rootElementRef.current && thumbElementRef.current) {\n forceRender();\n }\n }, [state.thumbAlignment]);\n\n // Adjust CSS var percents for edge thumb alignment using live DOM measurements.\n const cssVars = options.getCSSVars(slider.adjustForAlignment(state));\n\n // Ref callbacks for root and thumb elements.\n const rootRef = useCallback((element: HTMLElement | null) => {\n rootElementRef.current = element;\n }, []);\n\n const thumbRef = useCallback((element: HTMLElement | null) => {\n thumbElementRef.current = element;\n }, []);\n\n return {\n state,\n cssVars,\n rootRef,\n thumbRef,\n rootProps: slider.rootProps,\n rootStyle: slider.rootStyle,\n thumbProps: slider.thumbProps,\n };\n}\n\nexport namespace useSlider {\n export type Options = UseSliderOptions;\n export type ReturnValue = UseSliderReturnValue;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwDA,SAAgB,UACd,SAC6B;CAC7B,MAAM,aAAa,aAAa,QAAQ;CAExC,MAAM,iBAAiB,OAA2B,KAAK;CACvD,MAAM,kBAAkB,OAA2B,KAAK;CACxD,MAAM,cAAc,gBAAgB;CAGpC,MAAM,CAAC,UAAU,eAA0B;AAkBzC,SAAO,aAjB8B;GACnC,kBAAkB,eAAe;GACjC,uBAAuB,gBAAgB;GACvC,sBAAsB,WAAW,QAAQ,eAAe;GACxD,aAAc,eAAe,UAAU,MAAM,eAAe,QAAQ,GAAG;GACvE,kBAAkB,WAAW,QAAQ,YAAY;GACjD,kBAAkB,WAAW,QAAQ,YAAY;GACjD,sBAAsB,WAAW,QAAQ,gBAAgB;GACzD,2BAA2B,WAAW,QAAQ,qBAAqB;GACnE,gBAAgB,WAAW,QAAQ;GACnC,eAAe,WAAW,QAAQ;GAClC,gBAAgB,YAAY,WAAW,QAAQ,gBAAgB,QAAQ;GACvE,gBAAgB,YAAY,WAAW,QAAQ,gBAAgB,QAAQ;GACvE,mBAAmB,WAAW,QAAQ,eAAe;GACrD,iBAAiB,WAAW,QAAQ,aAAa;GAClD,CAEiC;GAClC;AAEF,YAAW,OAAO;CAGlB,MAAM,QAAQ,YAAY,OAAO,MAAM;CAGvC,MAAM,QAAQ,QAAQ,aAAa,MAAM;AAIzC,uBAAsB;AACpB,MAAI,MAAM,mBAAmB,UAAU,eAAe,WAAW,gBAAgB,QAC/E,cAAa;IAEd,CAAC,MAAM,eAAe,CAAC;AAc1B,QAAO;EACL;EACA,SAbc,QAAQ,WAAW,OAAO,mBAAmB,MAAM,CAAC;EAclE,SAXc,aAAa,YAAgC;AAC3D,kBAAe,UAAU;KACxB,EAAE,CAAC;EAUJ,UARe,aAAa,YAAgC;AAC5D,mBAAgB,UAAU;KACzB,EAAE,CAAC;EAOJ,WAAW,OAAO;EAClB,WAAW,OAAO;EAClB,YAAY,OAAO;EACpB"}
1
+ {"version":3,"file":"use-slider.js","names":[],"sources":["../../../../src/ui/hooks/use-slider.ts"],"sourcesContent":["'use client';\n\nimport type { SliderInput, SliderState } from '@videojs/core';\nimport {\n createSlider,\n type SliderApi,\n type SliderOptions,\n type SliderRootProps,\n type SliderRootStyle,\n type SliderThumbProps,\n} from '@videojs/core/dom';\nimport { useSnapshot } from '@videojs/store/react';\nimport { isRTL } from '@videojs/utils/dom';\nimport { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport { useDestroy } from '../../utils/use-destroy';\nimport { useForceRender } from '../../utils/use-force-render';\nimport { useLatestRef } from '../../utils/use-latest-ref';\n\nexport interface UseSliderOptions<State extends SliderState = SliderState>\n extends Pick<\n SliderOptions,\n | 'getPercent'\n | 'getStepPercent'\n | 'getLargeStepPercent'\n | 'changeThrottle'\n | 'onValueChange'\n | 'onValueCommit'\n | 'onDragStart'\n | 'onDragEnd'\n > {\n computeState: (input: SliderInput) => State;\n orientation?: 'horizontal' | 'vertical' | undefined;\n disabled?: boolean | undefined;\n /** Adjust a raw 0–100 percent for thumb alignment. Called for fill and pointer percents. */\n adjustPercent?: ((rawPercent: number, thumbSize: number, trackSize: number) => number) | undefined;\n /** Compute CSS variable map from the (possibly alignment-adjusted) state. */\n getCSSVars: (state: State) => Record<string, string>;\n}\n\nexport interface UseSliderReturnValue<State extends SliderState = SliderState> {\n state: State;\n cssVars: Record<string, string>;\n rootRef: React.RefCallback<HTMLElement>;\n thumbRef: React.RefCallback<HTMLElement>;\n rootProps: SliderRootProps;\n rootStyle: SliderRootStyle;\n thumbProps: SliderThumbProps;\n}\n\n/**\n * Manages slider input lifecycle for React.\n *\n * Wraps `createSlider()` from `@videojs/core/dom` and subscribes to its\n * input state via `useSnapshot`. Returns split props for the root\n * (pointer events) and thumb (keyboard/focus) elements.\n */\nexport function useSlider<State extends SliderState = SliderState>(\n options: UseSliderOptions<State>\n): UseSliderReturnValue<State> {\n const optionsRef = useLatestRef(options);\n\n const rootElementRef = useRef<HTMLElement | null>(null);\n const thumbElementRef = useRef<HTMLElement | null>(null);\n const forceRender = useForceRender();\n\n // Lazy-init the slider handle. Stable across re-renders.\n const [slider] = useState<SliderApi>(() => {\n const stableOptions: SliderOptions = {\n getElement: () => rootElementRef.current!,\n getThumbElement: () => thumbElementRef.current,\n getOrientation: () => optionsRef.current.orientation ?? 'horizontal',\n isRTL: () => (rootElementRef.current ? isRTL(rootElementRef.current) : false),\n isDisabled: () => optionsRef.current.disabled ?? false,\n getPercent: () => optionsRef.current.getPercent(),\n getStepPercent: () => optionsRef.current.getStepPercent(),\n getLargeStepPercent: () => optionsRef.current.getLargeStepPercent(),\n changeThrottle: optionsRef.current.changeThrottle,\n adjustPercent: optionsRef.current.adjustPercent,\n onValueChange: (percent) => optionsRef.current.onValueChange?.(percent),\n onValueCommit: (percent) => optionsRef.current.onValueCommit?.(percent),\n onDragStart: () => optionsRef.current.onDragStart?.(),\n onDragEnd: () => optionsRef.current.onDragEnd?.(),\n };\n\n return createSlider(stableOptions);\n });\n\n useDestroy(slider);\n\n // Subscribe to slider input state.\n const input = useSnapshot(slider.input);\n\n // Compute derived state from input + caller-provided projection.\n const state = options.computeState(input);\n\n // Force a synchronous re-render after mount so edge thumb alignment\n // can read DOM measurements from the now-populated element refs.\n useLayoutEffect(() => {\n if (state.thumbAlignment === 'edge' && rootElementRef.current && thumbElementRef.current) {\n forceRender();\n }\n }, [state.thumbAlignment]);\n\n // Adjust CSS var percents for edge thumb alignment using live DOM measurements.\n const cssVars = options.getCSSVars(slider.adjustForAlignment(state));\n\n // Ref callbacks for root and thumb elements.\n const rootRef = useCallback((element: HTMLElement | null) => {\n rootElementRef.current = element;\n }, []);\n\n const thumbRef = useCallback((element: HTMLElement | null) => {\n thumbElementRef.current = element;\n }, []);\n\n return {\n state,\n cssVars,\n rootRef,\n thumbRef,\n rootProps: slider.rootProps,\n rootStyle: slider.rootStyle,\n thumbProps: slider.thumbProps,\n };\n}\n\nexport namespace useSlider {\n export type Options = UseSliderOptions;\n export type ReturnValue = UseSliderReturnValue;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwDA,SAAgB,UACd,SAC6B;CAC7B,MAAM,aAAa,aAAa,QAAQ;CAExC,MAAM,iBAAiB,OAA2B,KAAK;CACvD,MAAM,kBAAkB,OAA2B,KAAK;CACxD,MAAM,cAAc,gBAAgB;CAGpC,MAAM,CAAC,UAAU,eAA0B;AAkBzC,SAAO,aAjB8B;GACnC,kBAAkB,eAAe;GACjC,uBAAuB,gBAAgB;GACvC,sBAAsB,WAAW,QAAQ,eAAe;GACxD,aAAc,eAAe,UAAU,MAAM,eAAe,QAAQ,GAAG;GACvE,kBAAkB,WAAW,QAAQ,YAAY;GACjD,kBAAkB,WAAW,QAAQ,YAAY;GACjD,sBAAsB,WAAW,QAAQ,gBAAgB;GACzD,2BAA2B,WAAW,QAAQ,qBAAqB;GACnE,gBAAgB,WAAW,QAAQ;GACnC,eAAe,WAAW,QAAQ;GAClC,gBAAgB,YAAY,WAAW,QAAQ,gBAAgB,QAAQ;GACvE,gBAAgB,YAAY,WAAW,QAAQ,gBAAgB,QAAQ;GACvE,mBAAmB,WAAW,QAAQ,eAAe;GACrD,iBAAiB,WAAW,QAAQ,aAAa;GAClD,CAEiC;GAClC;AAEF,YAAW,OAAO;CAGlB,MAAM,QAAQ,YAAY,OAAO,MAAM;CAGvC,MAAM,QAAQ,QAAQ,aAAa,MAAM;AAIzC,uBAAsB;AACpB,MAAI,MAAM,mBAAmB,UAAU,eAAe,WAAW,gBAAgB,QAC/E,cAAa;IAEd,CAAC,MAAM,eAAe,CAAC;AAc1B,QAAO;EACL;EACA,SAbc,QAAQ,WAAW,OAAO,mBAAmB,MAAM,CAAC;EAclE,SAXc,aAAa,YAAgC;AAC3D,kBAAe,UAAU;KACxB,EAAE,CAAC;EAUJ,UARe,aAAa,YAAgC;AAC5D,mBAAgB,UAAU;KACzB,EAAE,CAAC;EAOJ,WAAW,OAAO;EAClB,WAAW,OAAO;EAClB,YAAY,OAAO;EACpB"}
@@ -0,0 +1,21 @@
1
+ import { HotkeyActionName } from "@videojs/core/dom";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/ui/hotkey/media-hotkey.d.ts
5
+ interface MediaHotkeyProps {
6
+ keys: string;
7
+ action: HotkeyActionName | (string & {});
8
+ value?: number;
9
+ disabled?: boolean;
10
+ target?: 'player' | 'document';
11
+ }
12
+ declare function MediaHotkey({
13
+ keys,
14
+ action,
15
+ value,
16
+ disabled,
17
+ target
18
+ }: MediaHotkeyProps): ReactNode;
19
+ //#endregion
20
+ export { MediaHotkey, MediaHotkeyProps };
21
+ //# sourceMappingURL=media-hotkey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-hotkey.d.ts","names":[],"sources":["../../../../src/ui/hotkey/media-hotkey.tsx"],"mappings":";;;;UAciB,gBAAA;EACf,IAAA;EACA,MAAA,EAAQ,gBAAA;EACR,KAAA;EACA,QAAA;EACA,MAAA;AAAA;AAAA,iBAGc,WAAA,CAAA;EAAc,IAAA;EAAM,MAAA;EAAQ,KAAA;EAAO,QAAA;EAAU;AAAA,GAAU,gBAAA,GAAmB,SAAA"}
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { useContainer, usePlayer } from "../../player/context.js";
3
+ import { createHotkey, isHotkeyToggleAction, resolveHotkeyAction } from "@videojs/core/dom";
4
+ import { useEffect } from "react";
5
+ //#region src/ui/hotkey/media-hotkey.tsx
6
+ function MediaHotkey({ keys, action, value, disabled, target }) {
7
+ const store = usePlayer();
8
+ const container = useContainer();
9
+ useEffect(() => {
10
+ if (!container || !keys || !action || disabled) return;
11
+ const resolver = resolveHotkeyAction(action);
12
+ if (!resolver) return;
13
+ return createHotkey(container, {
14
+ keys,
15
+ action,
16
+ target,
17
+ disabled,
18
+ repeatable: !isHotkeyToggleAction(action),
19
+ onActivate: (_event, key) => {
20
+ resolver({
21
+ store,
22
+ key,
23
+ value
24
+ });
25
+ }
26
+ });
27
+ }, [
28
+ container,
29
+ store,
30
+ keys,
31
+ action,
32
+ value,
33
+ disabled,
34
+ target
35
+ ]);
36
+ return null;
37
+ }
38
+ //#endregion
39
+ export { MediaHotkey };
40
+
41
+ //# sourceMappingURL=media-hotkey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-hotkey.js","names":[],"sources":["../../../../src/ui/hotkey/media-hotkey.tsx"],"sourcesContent":["'use client';\n\nimport {\n type AnyPlayerStore,\n createHotkey,\n type HotkeyActionName,\n isHotkeyToggleAction,\n resolveHotkeyAction,\n} from '@videojs/core/dom';\nimport type { ReactNode } from 'react';\nimport { useEffect } from 'react';\n\nimport { useContainer, usePlayer } from '../../player/context';\n\nexport interface MediaHotkeyProps {\n keys: string;\n action: HotkeyActionName | (string & {});\n value?: number;\n disabled?: boolean;\n target?: 'player' | 'document';\n}\n\nexport function MediaHotkey({ keys, action, value, disabled, target }: MediaHotkeyProps): ReactNode {\n const store = usePlayer() as AnyPlayerStore;\n const container = useContainer();\n\n useEffect(() => {\n if (!container || !keys || !action || disabled) return;\n\n const resolver = resolveHotkeyAction(action);\n if (!resolver) return;\n\n return createHotkey(container, {\n keys,\n action,\n target,\n disabled,\n repeatable: !isHotkeyToggleAction(action),\n onActivate: (_event, key) => {\n resolver({ store, key, value });\n },\n });\n }, [container, store, keys, action, value, disabled, target]);\n\n return null;\n}\n"],"mappings":";;;;;AAsBA,SAAgB,YAAY,EAAE,MAAM,QAAQ,OAAO,UAAU,UAAuC;CAClG,MAAM,QAAQ,WAAW;CACzB,MAAM,YAAY,cAAc;AAEhC,iBAAgB;AACd,MAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,SAAU;EAEhD,MAAM,WAAW,oBAAoB,OAAO;AAC5C,MAAI,CAAC,SAAU;AAEf,SAAO,aAAa,WAAW;GAC7B;GACA;GACA;GACA;GACA,YAAY,CAAC,qBAAqB,OAAO;GACzC,aAAa,QAAQ,QAAQ;AAC3B,aAAS;KAAE;KAAO;KAAK;KAAO,CAAC;;GAElC,CAAC;IACD;EAAC;EAAW;EAAO;EAAM;EAAQ;EAAO;EAAU;EAAO,CAAC;AAE7D,QAAO"}
@@ -0,0 +1,5 @@
1
+ //#region src/ui/hotkey/use-aria-key-shortcuts.d.ts
2
+ declare function useAriaKeyShortcuts(action: string | undefined): string | undefined;
3
+ //#endregion
4
+ export { useAriaKeyShortcuts };
5
+ //# sourceMappingURL=use-aria-key-shortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-aria-key-shortcuts.d.ts","names":[],"sources":["../../../../src/ui/hotkey/use-aria-key-shortcuts.ts"],"mappings":";iBAOgB,mBAAA,CAAoB,MAAA"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { useContainer } from "../../player/context.js";
3
+ import { findHotkeyCoordinator } from "@videojs/core/dom";
4
+ import { useMemo } from "react";
5
+ //#region src/ui/hotkey/use-aria-key-shortcuts.ts
6
+ function useAriaKeyShortcuts(action) {
7
+ const container = useContainer();
8
+ return useMemo(() => {
9
+ if (!container || !action) return void 0;
10
+ return findHotkeyCoordinator(container)?.getAriaKeys(action);
11
+ }, [container, action]);
12
+ }
13
+ //#endregion
14
+ export { useAriaKeyShortcuts };
15
+
16
+ //# sourceMappingURL=use-aria-key-shortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-aria-key-shortcuts.js","names":[],"sources":["../../../../src/ui/hotkey/use-aria-key-shortcuts.ts"],"sourcesContent":["'use client';\n\nimport { findHotkeyCoordinator } from '@videojs/core/dom';\nimport { useMemo } from 'react';\n\nimport { useContainer } from '../../player/context';\n\nexport function useAriaKeyShortcuts(action: string | undefined): string | undefined {\n const container = useContainer();\n return useMemo(() => {\n if (!container || !action) return undefined;\n return findHotkeyCoordinator(container)?.getAriaKeys(action);\n }, [container, action]);\n}\n"],"mappings":";;;;;AAOA,SAAgB,oBAAoB,QAAgD;CAClF,MAAM,YAAY,cAAc;AAChC,QAAO,cAAc;AACnB,MAAI,CAAC,aAAa,CAAC,OAAQ,QAAO,KAAA;AAClC,SAAO,sBAAsB,UAAU,EAAE,YAAY,OAAO;IAC3D,CAAC,WAAW,OAAO,CAAC"}
@@ -0,0 +1,12 @@
1
+ //#region src/ui/hotkey/use-hotkey.d.ts
2
+ interface UseHotkeyOptions {
3
+ keys: string;
4
+ onActivate: (event: KeyboardEvent, key: string) => void;
5
+ target?: 'player' | 'document';
6
+ repeatable?: boolean;
7
+ disabled?: boolean;
8
+ }
9
+ declare function useHotkey(options: UseHotkeyOptions): void;
10
+ //#endregion
11
+ export { UseHotkeyOptions, useHotkey };
12
+ //# sourceMappingURL=use-hotkey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hotkey.d.ts","names":[],"sources":["../../../../src/ui/hotkey/use-hotkey.ts"],"mappings":";UAQiB,gBAAA;EACf,IAAA;EACA,UAAA,GAAa,KAAA,EAAO,aAAA,EAAe,GAAA;EACnC,MAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,iBAGc,SAAA,CAAU,OAAA,EAAS,gBAAA"}
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { useContainer } from "../../player/context.js";
3
+ import { useLatestRef } from "../../utils/use-latest-ref.js";
4
+ import { createHotkey } from "@videojs/core/dom";
5
+ import { useEffect } from "react";
6
+ //#region src/ui/hotkey/use-hotkey.ts
7
+ function useHotkey(options) {
8
+ const { keys, target = "player", repeatable = true, disabled = false } = options;
9
+ const container = useContainer();
10
+ const onActivateRef = useLatestRef(options.onActivate);
11
+ useEffect(() => {
12
+ if (!container || !keys || disabled) return;
13
+ return createHotkey(container, {
14
+ keys,
15
+ target,
16
+ repeatable,
17
+ disabled,
18
+ onActivate: (event, key) => onActivateRef.current(event, key)
19
+ });
20
+ }, [
21
+ container,
22
+ keys,
23
+ target,
24
+ repeatable,
25
+ disabled,
26
+ onActivateRef
27
+ ]);
28
+ }
29
+ //#endregion
30
+ export { useHotkey };
31
+
32
+ //# sourceMappingURL=use-hotkey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hotkey.js","names":[],"sources":["../../../../src/ui/hotkey/use-hotkey.ts"],"sourcesContent":["'use client';\n\nimport { createHotkey } from '@videojs/core/dom';\nimport { useEffect } from 'react';\n\nimport { useContainer } from '../../player/context';\nimport { useLatestRef } from '../../utils/use-latest-ref';\n\nexport interface UseHotkeyOptions {\n keys: string;\n onActivate: (event: KeyboardEvent, key: string) => void;\n target?: 'player' | 'document';\n repeatable?: boolean;\n disabled?: boolean;\n}\n\nexport function useHotkey(options: UseHotkeyOptions): void {\n const { keys, target = 'player', repeatable = true, disabled = false } = options;\n const container = useContainer();\n const onActivateRef = useLatestRef(options.onActivate);\n\n useEffect(() => {\n if (!container || !keys || disabled) return;\n\n return createHotkey(container, {\n keys,\n target,\n repeatable,\n disabled,\n onActivate: (event, key) => onActivateRef.current(event, key),\n });\n }, [container, keys, target, repeatable, disabled, onActivateRef]);\n}\n"],"mappings":";;;;;;AAgBA,SAAgB,UAAU,SAAiC;CACzD,MAAM,EAAE,MAAM,SAAS,UAAU,aAAa,MAAM,WAAW,UAAU;CACzE,MAAM,YAAY,cAAc;CAChC,MAAM,gBAAgB,aAAa,QAAQ,WAAW;AAEtD,iBAAgB;AACd,MAAI,CAAC,aAAa,CAAC,QAAQ,SAAU;AAErC,SAAO,aAAa,WAAW;GAC7B;GACA;GACA;GACA;GACA,aAAa,OAAO,QAAQ,cAAc,QAAQ,OAAO,IAAI;GAC9D,CAAC;IACD;EAAC;EAAW;EAAM;EAAQ;EAAY;EAAU;EAAc,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"mute-button.d.ts","names":[],"sources":["../../../../src/ui/mute-button/mute-button.tsx"],"mappings":";;;;;UAQiB,eAAA,SAAwB,gBAAA,WAA2B,cAAA,CAAe,KAAA,GAAQ,cAAA,CAAe,KAAA;;cAG7F,UAAA,EAAU,KAAA,CAAA,yBAAA,CAAA,eAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA;AAAA,kBAQN,UAAA;EAAA,KACH,KAAA,GAAQ,eAAA;EAAA,KACR,KAAA,GAAQ,cAAA,CAAe,KAAA;AAAA"}
1
+ {"version":3,"file":"mute-button.d.ts","names":[],"sources":["../../../../src/ui/mute-button/mute-button.tsx"],"mappings":";;;;;UAQiB,eAAA,SAAwB,gBAAA,WAA2B,cAAA,CAAe,KAAA,GAAQ,cAAA,CAAe,KAAA;;cAG7F,UAAA,EAAU,KAAA,CAAA,yBAAA,CAAA,eAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA;AAAA,kBASN,UAAA;EAAA,KACH,KAAA,GAAQ,eAAA;EAAA,KACR,KAAA,GAAQ,cAAA,CAAe,KAAA;AAAA"}
@@ -9,7 +9,8 @@ const MuteButton = createMediaButton({
9
9
  core: MuteButtonCore,
10
10
  stateAttrMap: MuteButtonDataAttrs,
11
11
  selector: selectVolume,
12
- action: (core, state) => core.toggle(state)
12
+ action: (core, state) => core.toggle(state),
13
+ hotkeyAction: "toggleMuted"
13
14
  });
14
15
  //#endregion
15
16
  export { MuteButton };
@@ -1 +1 @@
1
- {"version":3,"file":"mute-button.js","names":[],"sources":["../../../../src/ui/mute-button/mute-button.tsx"],"sourcesContent":["'use client';\n\nimport { MuteButtonCore, MuteButtonDataAttrs } from '@videojs/core';\nimport { selectVolume } from '@videojs/core/dom';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { createMediaButton } from '../create-media-button';\n\nexport interface MuteButtonProps extends UIComponentProps<'button', MuteButtonCore.State>, MuteButtonCore.Props {}\n\n/** A button that toggles mute state. */\nexport const MuteButton = createMediaButton<MuteButtonCore, MuteButtonProps>({\n displayName: 'MuteButton',\n core: MuteButtonCore,\n stateAttrMap: MuteButtonDataAttrs,\n selector: selectVolume,\n action: (core, state) => core.toggle(state),\n});\n\nexport namespace MuteButton {\n export type Props = MuteButtonProps;\n export type State = MuteButtonCore.State;\n}\n"],"mappings":";;;;;;AAWA,MAAa,aAAa,kBAAmD;CAC3E,aAAa;CACb,MAAM;CACN,cAAc;CACd,UAAU;CACV,SAAS,MAAM,UAAU,KAAK,OAAO,MAAM;CAC5C,CAAC"}
1
+ {"version":3,"file":"mute-button.js","names":[],"sources":["../../../../src/ui/mute-button/mute-button.tsx"],"sourcesContent":["'use client';\n\nimport { MuteButtonCore, MuteButtonDataAttrs } from '@videojs/core';\nimport { selectVolume } from '@videojs/core/dom';\n\nimport type { UIComponentProps } from '../../utils/types';\nimport { createMediaButton } from '../create-media-button';\n\nexport interface MuteButtonProps extends UIComponentProps<'button', MuteButtonCore.State>, MuteButtonCore.Props {}\n\n/** A button that toggles mute state. */\nexport const MuteButton = createMediaButton<MuteButtonCore, MuteButtonProps>({\n displayName: 'MuteButton',\n core: MuteButtonCore,\n stateAttrMap: MuteButtonDataAttrs,\n selector: selectVolume,\n action: (core, state) => core.toggle(state),\n hotkeyAction: 'toggleMuted',\n});\n\nexport namespace MuteButton {\n export type Props = MuteButtonProps;\n export type State = MuteButtonCore.State;\n}\n"],"mappings":";;;;;;AAWA,MAAa,aAAa,kBAAmD;CAC3E,aAAa;CACb,MAAM;CACN,cAAc;CACd,UAAU;CACV,SAAS,MAAM,UAAU,KAAK,OAAO,MAAM;CAC3C,cAAc;CACf,CAAC"}