@videojs/react 10.0.0-beta.29 → 10.0.0-beta.30
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.
- package/dist/default/index.js +2 -1
- package/dist/default/media/shaka-video/index.js +2 -0
- package/dist/default/media/shaka-video/media.js +21 -0
- package/dist/default/media/shaka-video/media.js.map +1 -0
- package/dist/default/presets/audio/minimal-skin.css +1 -3
- package/dist/default/presets/audio/skin.css +1 -3
- package/dist/default/presets/live-audio/minimal-skin.css +1 -3
- package/dist/default/presets/live-audio/skin.css +1 -3
- package/dist/default/presets/live-video/minimal-skin.css +2 -31
- package/dist/default/presets/live-video/minimal-skin.js +2 -6
- package/dist/default/presets/live-video/minimal-skin.js.map +1 -1
- package/dist/default/presets/live-video/minimal-skin.tailwind.js +2 -6
- package/dist/default/presets/live-video/minimal-skin.tailwind.js.map +1 -1
- package/dist/default/presets/live-video/skin.css +2 -33
- package/dist/default/presets/live-video/skin.js +2 -6
- package/dist/default/presets/live-video/skin.js.map +1 -1
- package/dist/default/presets/live-video/skin.tailwind.js +2 -6
- package/dist/default/presets/live-video/skin.tailwind.js.map +1 -1
- package/dist/default/presets/video/minimal-skin.css +2 -31
- package/dist/default/presets/video/minimal-skin.js +2 -6
- package/dist/default/presets/video/minimal-skin.js.map +1 -1
- package/dist/default/presets/video/minimal-skin.tailwind.js +2 -6
- package/dist/default/presets/video/minimal-skin.tailwind.js.map +1 -1
- package/dist/default/presets/video/skin.css +2 -33
- package/dist/default/presets/video/skin.js +2 -6
- package/dist/default/presets/video/skin.js.map +1 -1
- package/dist/default/presets/video/skin.tailwind.js +2 -6
- package/dist/default/presets/video/skin.tailwind.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/button.js +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/button.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/menu.js +2 -2
- package/dist/default/skins/dist/default/default/tailwind/components/menu.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/components/poster.js +1 -7
- package/dist/default/skins/dist/default/default/tailwind/components/poster.js.map +1 -1
- package/dist/default/skins/dist/default/default/tailwind/video.tailwind.js +1 -10
- package/dist/default/skins/dist/default/default/tailwind/video.tailwind.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/button.js +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/button.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/menu.js +2 -2
- package/dist/default/skins/dist/default/minimal/tailwind/components/menu.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/components/poster.js +1 -7
- package/dist/default/skins/dist/default/minimal/tailwind/components/poster.js.map +1 -1
- package/dist/default/skins/dist/default/minimal/tailwind/video.tailwind.js +1 -10
- package/dist/default/skins/dist/default/minimal/tailwind/video.tailwind.js.map +1 -1
- package/dist/default/ui/thumbnail/thumbnail.js +18 -1
- package/dist/default/ui/thumbnail/thumbnail.js.map +1 -1
- package/dist/default/ui/title/index.js +2 -0
- package/dist/default/ui/title/title.js +44 -0
- package/dist/default/ui/title/title.js.map +1 -0
- package/dist/dev/index.d.ts +3 -2
- package/dist/dev/index.js +2 -1
- package/dist/dev/media/shaka-video/index.d.ts +2 -0
- package/dist/dev/media/shaka-video/index.js +2 -0
- package/dist/dev/media/shaka-video/media.d.ts +13 -0
- package/dist/dev/media/shaka-video/media.d.ts.map +1 -0
- package/dist/dev/media/shaka-video/media.js +21 -0
- package/dist/dev/media/shaka-video/media.js.map +1 -0
- package/dist/dev/presets/audio/minimal-skin.css +1 -3
- package/dist/dev/presets/audio/skin.css +1 -3
- package/dist/dev/presets/live-audio/minimal-skin.css +1 -3
- package/dist/dev/presets/live-audio/skin.css +1 -3
- package/dist/dev/presets/live-video/minimal-skin.css +2 -31
- package/dist/dev/presets/live-video/minimal-skin.js +2 -6
- package/dist/dev/presets/live-video/minimal-skin.js.map +1 -1
- package/dist/dev/presets/live-video/minimal-skin.tailwind.js +2 -6
- package/dist/dev/presets/live-video/minimal-skin.tailwind.js.map +1 -1
- package/dist/dev/presets/live-video/skin.css +2 -33
- package/dist/dev/presets/live-video/skin.js +2 -6
- package/dist/dev/presets/live-video/skin.js.map +1 -1
- package/dist/dev/presets/live-video/skin.tailwind.js +2 -6
- package/dist/dev/presets/live-video/skin.tailwind.js.map +1 -1
- package/dist/dev/presets/types.d.ts +0 -2
- package/dist/dev/presets/types.d.ts.map +1 -1
- package/dist/dev/presets/video/minimal-skin.css +2 -31
- package/dist/dev/presets/video/minimal-skin.js +2 -6
- package/dist/dev/presets/video/minimal-skin.js.map +1 -1
- package/dist/dev/presets/video/minimal-skin.tailwind.js +2 -6
- package/dist/dev/presets/video/minimal-skin.tailwind.js.map +1 -1
- package/dist/dev/presets/video/skin.css +2 -33
- package/dist/dev/presets/video/skin.js +2 -6
- package/dist/dev/presets/video/skin.js.map +1 -1
- package/dist/dev/presets/video/skin.tailwind.js +2 -6
- package/dist/dev/presets/video/skin.tailwind.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/button.js +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/button.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/menu.js +2 -2
- package/dist/dev/skins/dist/default/default/tailwind/components/menu.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/components/poster.js +1 -7
- package/dist/dev/skins/dist/default/default/tailwind/components/poster.js.map +1 -1
- package/dist/dev/skins/dist/default/default/tailwind/video.tailwind.js +1 -10
- package/dist/dev/skins/dist/default/default/tailwind/video.tailwind.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/button.js +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/button.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/menu.js +2 -2
- package/dist/dev/skins/dist/default/minimal/tailwind/components/menu.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/components/poster.js +1 -7
- package/dist/dev/skins/dist/default/minimal/tailwind/components/poster.js.map +1 -1
- package/dist/dev/skins/dist/default/minimal/tailwind/video.tailwind.js +1 -10
- package/dist/dev/skins/dist/default/minimal/tailwind/video.tailwind.js.map +1 -1
- package/dist/dev/ui/thumbnail/thumbnail.d.ts.map +1 -1
- package/dist/dev/ui/thumbnail/thumbnail.js +18 -1
- package/dist/dev/ui/thumbnail/thumbnail.js.map +1 -1
- package/dist/dev/ui/title/index.d.ts +2 -0
- package/dist/dev/ui/title/index.js +2 -0
- package/dist/dev/ui/title/title.d.ts +27 -0
- package/dist/dev/ui/title/title.d.ts.map +1 -0
- package/dist/dev/ui/title/title.js +47 -0
- package/dist/dev/ui/title/title.js.map +1 -0
- package/docs/README.md +1 -1
- package/docs/concepts/presets.md +4 -4
- package/docs/concepts/skins.md +8 -48
- package/docs/how-to/add-a-poster-placeholder.md +133 -0
- package/docs/how-to/customize-skins.md +10 -92
- package/docs/how-to/migrate-from-mux-player.md +14 -8
- package/docs/llms.txt +3 -0
- package/docs/reference/feature-fullscreen.md +9 -8
- package/docs/reference/feature-metadata.md +129 -0
- package/docs/reference/feature-orientation-lock.md +94 -8
- package/docs/reference/feature-text-tracks.md +10 -0
- package/docs/reference/menu.md +0 -1
- package/docs/reference/thumbnail.md +4 -0
- package/docs/reference/title.md +208 -0
- package/package.json +8 -8
|
@@ -34,20 +34,11 @@ const container = (isShadowDOM) => cn(container$1, "group/skin", "bg-black overf
|
|
|
34
34
|
"[&_video::-webkit-media-text-track-container]:scale-98",
|
|
35
35
|
"[&_video::-webkit-media-text-track-container]:z-1",
|
|
36
36
|
"[&_video::-webkit-media-text-track-container]:font-[inherit]"
|
|
37
|
-
] : [], !isShadowDOM ? [
|
|
38
|
-
"before:absolute before:inset-0 before:pointer-events-none",
|
|
39
|
-
"before:[background-image:var(--media-poster-placeholder,none)]",
|
|
40
|
-
"before:bg-no-repeat",
|
|
41
|
-
"before:[background-position:var(--media-object-position,center)]",
|
|
42
|
-
"before:[background-size:var(--media-object-fit,contain)]",
|
|
43
|
-
"before:opacity-0 before:[filter:blur(var(--media-poster-placeholder-blur,20px))]",
|
|
44
|
-
"before:transition-opacity before:duration-250",
|
|
45
|
-
"has-[img[data-visible]:not([data-loaded])]:before:opacity-100"
|
|
46
37
|
] : [], "[&:fullscreen]:[--container-border-radius:0]", {
|
|
47
38
|
"[&:fullscreen_video]:object-contain": !isShadowDOM,
|
|
48
39
|
"[&:fullscreen_::slotted(video)]:object-contain": isShadowDOM
|
|
49
40
|
});
|
|
50
|
-
const controls = cn(controls$1, "absolute bottom-1 inset-x-1", "[--base-side-offset:5] [--base-boundary-offset:1]", "[--volume-mask:linear-gradient(to_right,transparent_10%,black_25%,black_100%)]", "gap-x-2 flex-wrap rounded-[--spacing(3)] group/controls", "text-white z-20", "peer-data-open/error:hidden", "ease-(--controls-transition-timing-function)", "duration-[calc(var(--controls-transition-duration)/2)]", "not-data-visible:duration-(--controls-transition-duration)", "pointer-fine:
|
|
41
|
+
const controls = cn(controls$1, "absolute bottom-1 inset-x-1", "[--base-side-offset:5] [--base-boundary-offset:1]", "[--volume-mask:linear-gradient(to_right,transparent_10%,black_25%,black_100%)]", "gap-x-2 flex-wrap rounded-[--spacing(3)] group/controls", "text-white z-20", "peer-data-open/error:hidden", "ease-(--controls-transition-timing-function)", "duration-[calc(var(--controls-transition-duration)/2)]", "not-data-visible:duration-(--controls-transition-duration)", "pointer-fine:transition-[translate,filter,opacity]", "pointer-coarse:transition-[translate,opacity]", "not-data-visible:opacity-0 not-data-visible:pointer-events-none", "motion-safe:not-data-visible:translate-y-full", "pointer-fine:motion-safe:not-data-visible:blur-sm", "@2xl/media-root:flex-nowrap @2xl/media-root:[--controls-padding:2] @2xl/media-root:[--base-side-offset:2]");
|
|
51
42
|
const volumeMaskTarget = cn("[mask-image:var(--volume-mask-image,none)]", "[mask-repeat:no-repeat]", "[mask-position:var(--volume-mask-position,100%_0)]", "[mask-size:var(--volume-mask-size,200%_100%)]", "[transition:mask-position_50ms_ease-out]");
|
|
52
43
|
const buttonGroupStart = cn(buttonGroup, "flex-1 @2xl/media-root:flex-none");
|
|
53
44
|
const buttonGroupEnd = cn(buttonGroup, volumeMaskTarget, "flex-1 justify-end @2xl/media-root:flex-none", "group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-image:var(--volume-mask)]", "group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-position:0_0]", "group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-size:400%_100%]");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.tailwind.js","names":[],"sources":["../../../../../../../../skins/dist/default/minimal/tailwind/video.tailwind.js"],"sourcesContent":["import { container as container$1 } from \"./components/container.js\";\nimport { controls as controls$1 } from \"./components/controls.js\";\nimport { error as error$1 } from \"./components/error.js\";\nimport { popup as popup$1 } from \"./components/popup.js\";\nimport { slider as slider$1 } from \"./components/slider.js\";\nimport { iconState } from \"../../shared/tailwind/icon-state.js\";\nimport { badge } from \"./components/badge.js\";\nimport { bufferingIndicator } from \"./components/buffering.js\";\nimport { button } from \"./components/button.js\";\nimport { buttonGroup } from \"./components/button-group.js\";\nimport { icon, iconContainer, iconFlipped, iconHidden } from \"./components/icon.js\";\nimport { menu as menu$1 } from \"./components/menu.js\";\nimport { playbackRate } from \"./components/playback-rate.js\";\nimport { seek } from \"./components/seek.js\";\nimport { time as time$1 } from \"./components/time.js\";\nimport { thumbnail as thumbnail$1 } from \"./components/thumbnail.js\";\nimport { inputIndicatorOverlay } from \"./components/input-indicator-overlay.js\";\nimport { overlay } from \"./components/overlay.js\";\nimport { poster } from \"./components/poster.js\";\nimport { seekIndicator } from \"./components/seek-indicator.js\";\nimport { statusIndicator } from \"./components/status-indicator.js\";\nimport { volumeIndicator } from \"./components/volume-indicator.js\";\nimport { cn } from \"@videojs/utils/style\";\n//#region src/minimal/tailwind/video.tailwind.ts\nconst container = (isShadowDOM) => cn(container$1, \"group/skin\", \"bg-black overflow-clip\", \"after:absolute after:pointer-events-none after:rounded-[inherit] after:z-10\", \"[&:fullscreen]:after:hidden\", \"after:inset-0 after:ring-1 after:ring-inset after:ring-(color:--border-color)\", {\n\t\"[&_::slotted(video)]:block [&_::slotted(video)]:w-full [&_::slotted(video)]:h-full [&_::slotted(video)]:rounded-(--container-border-radius) [&_::slotted(video)]:[object-fit:var(--media-object-fit,cover)] [&_::slotted(video)]:[object-position:var(--media-object-position,center)]\": isShadowDOM,\n\t\"[&_video]:block [&_video]:w-full [&_video]:h-full [&_video]:rounded-[inherit] [&_video]:[object-fit:var(--media-object-fit,contain)] [&_video]:[object-position:var(--media-object-position,center)]\": !isShadowDOM\n}, \"[--default-accent-color:oklch(1_0_0)]\", \"[--border-color:light-dark(oklch(0_0_0/0.15),oklch(1_0_0/0.15))]\", \"[--focus-ring-color:light-dark(oklch(0_0_0),oklch(1_0_0))]\", \"**:[--focus-ring-color:oklch(1_0_0)]\", \"[--container-border-radius:var(--media-border-radius,0.75rem)]\", \"[--media-video-border-radius:var(--container-border-radius)]\", \"[--controls-background-color:transparent]\", \"[--controls-transition-duration:100ms]\", \"[--controls-transition-timing-function:ease-out]\", \"[--error-dialog-transition-duration:150ms]\", \"[--error-dialog-transition-delay:100ms]\", \"[--error-dialog-transition-timing-function:ease-out]\", \"[--popup-transition-duration:100ms]\", \"[--popup-transition-timing-function:ease-out]\", \"[--popover-backdrop-filter:blur(16px)_saturate(1.5)]\", \"[--popover-background-color:oklch(0_0_0/0.5)]\", \"[--popover-border-color:oklch(1_0_0/0.1)]\", \"[--tooltip-backdrop-filter:var(--popover-backdrop-filter)]\", \"[--tooltip-background-color:var(--popover-background-color)]\", \"[--tooltip-border-color:var(--popover-border-color)]\", \"[--tooltip-text-color:currentColor]\", \"min-[1280px]:[&:fullscreen]:[--scale:1.25]\", \"min-[1536px]:[&:fullscreen]:[--scale:1.5]\", \"min-[1920px]:[&:fullscreen]:[--scale:1.75]\", \"motion-reduce:[--error-dialog-transition-duration:50ms]\", \"motion-reduce:[--error-dialog-transition-delay:0ms]\", \"motion-reduce:[--popup-transition-duration:0ms]\", \"[@media(prefers-reduced-transparency:reduce)]:[--controls-background-color:oklch(0_0_0)]\", \"contrast-more:[--controls-background-color:oklch(0_0_0)]\", \"[@media(prefers-reduced-transparency:reduce)]:[--tooltip-background-color:oklch(0_0_0)]\", \"contrast-more:[--tooltip-background-color:oklch(0_0_0)]\", \"pointer-fine:has-[[data-controls]:not([data-visible])]:[--controls-transition-duration:300ms]\", \"pointer-coarse:has-[[data-controls]:not([data-visible])]:[--controls-transition-duration:150ms]\", \"motion-reduce:has-[[data-controls]:not([data-visible])]:[--controls-transition-duration:50ms]\", \"[--media-caption-track-y:--spacing(-2)]\", \"[--media-caption-track-delay:25ms]\", \"[--media-caption-track-duration:var(--controls-transition-duration)]\", \"has-[[data-controls][data-visible]]:[--media-caption-track-y:--spacing(-18)]\", \"@2xl/media-root:has-[[data-controls][data-visible]]:*:[--media-caption-track-y:--spacing(-12)]\", !isShadowDOM ? [\n\t\"[&_video::-webkit-media-text-track-container]:transition-[translate]\",\n\t\"[&_video::-webkit-media-text-track-container]:duration-(--media-caption-track-duration)\",\n\t\"[&_video::-webkit-media-text-track-container]:ease-out\",\n\t\"[&_video::-webkit-media-text-track-container]:delay-(--media-caption-track-delay)\",\n\t\"[&_video::-webkit-media-text-track-container]:translate-y-(--media-caption-track-y)\",\n\t\"[&_video::-webkit-media-text-track-container]:scale-98\",\n\t\"[&_video::-webkit-media-text-track-container]:z-1\",\n\t\"[&_video::-webkit-media-text-track-container]:font-[inherit]\"\n] : [], !isShadowDOM ? [\n\t\"before:absolute before:inset-0 before:pointer-events-none\",\n\t\"before:[background-image:var(--media-poster-placeholder,none)]\",\n\t\"before:bg-no-repeat\",\n\t\"before:[background-position:var(--media-object-position,center)]\",\n\t\"before:[background-size:var(--media-object-fit,contain)]\",\n\t\"before:opacity-0 before:[filter:blur(var(--media-poster-placeholder-blur,20px))]\",\n\t\"before:transition-opacity before:duration-250\",\n\t\"has-[img[data-visible]:not([data-loaded])]:before:opacity-100\"\n] : [], \"[&:fullscreen]:[--container-border-radius:0]\", {\n\t\"[&:fullscreen_video]:object-contain\": !isShadowDOM,\n\t\"[&:fullscreen_::slotted(video)]:object-contain\": isShadowDOM\n});\nconst controls = cn(controls$1, \"absolute bottom-1 inset-x-1\", \"[--base-side-offset:5] [--base-boundary-offset:1]\", \"[--volume-mask:linear-gradient(to_right,transparent_10%,black_25%,black_100%)]\", \"gap-x-2 flex-wrap rounded-[--spacing(3)] group/controls\", \"text-white z-20\", \"peer-data-open/error:hidden\", \"ease-(--controls-transition-timing-function)\", \"duration-[calc(var(--controls-transition-duration)/2)]\", \"not-data-visible:duration-(--controls-transition-duration)\", \"pointer-fine:will-change-[translate,filter,opacity]\", \"pointer-fine:transition-[translate,filter,opacity]\", \"pointer-coarse:will-change-[translate,opacity]\", \"pointer-coarse:transition-[translate,opacity]\", \"not-data-visible:opacity-0 not-data-visible:pointer-events-none\", \"motion-safe:not-data-visible:translate-y-full\", \"pointer-fine:motion-safe:not-data-visible:blur-sm\", \"@2xl/media-root:flex-nowrap @2xl/media-root:[--controls-padding:2] @2xl/media-root:[--base-side-offset:2]\");\nconst volumeMaskTarget = cn(\"[mask-image:var(--volume-mask-image,none)]\", \"[mask-repeat:no-repeat]\", \"[mask-position:var(--volume-mask-position,100%_0)]\", \"[mask-size:var(--volume-mask-size,200%_100%)]\", \"[transition:mask-position_50ms_ease-out]\");\nconst buttonGroupStart = cn(buttonGroup, \"flex-1 @2xl/media-root:flex-none\");\nconst buttonGroupEnd = cn(buttonGroup, volumeMaskTarget, \"flex-1 justify-end @2xl/media-root:flex-none\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-image:var(--volume-mask)]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-position:0_0]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-size:400%_100%]\");\nconst spacer = \"grow\";\nconst time = {\n\t...time$1,\n\tcontrols: cn(time$1.controls, volumeMaskTarget, \"[--slider-height:--spacing(5)] grow-0 shrink-0 basis-full order-[-1] px-1.5\", \"@2xl/media-root:[--slider-height:--spacing(8)] @2xl/media-root:grow @2xl/media-root:shrink @2xl/media-root:basis-0 @2xl/media-root:order-[unset]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@2xl/media-root:[--volume-mask-image:var(--volume-mask)]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@2xl/media-root:[--volume-mask-position:0_0]\")\n};\nconst error = {\n\t...error$1,\n\troot: cn(error$1.root, \"pointer-events-none outline-none\"),\n\tdialog: cn(error$1.dialog, \"pointer-events-auto w-full max-w-64 p-4 rounded-none\"),\n\tcontent: cn(error$1.content, \"p-0 py-1.5\"),\n\ttitle: \"text-(length:--font-size-medium)\"\n};\nconst thumbnail = thumbnail$1;\nconst slider = {\n\t...slider$1,\n\ttrack: cn(slider$1.track, \"ring-1 ring-black/5\"),\n\tpreview: cn(slider$1.preview, \"[--preview-end-inset:calc(100cqi-100%)]\", \"[--preview-left:clamp(calc(var(--max-size)/2),var(--media-slider-pointer),calc(100%-var(--max-size)/2+var(--preview-end-inset)))]\", \"@2xl/media-root:[--preview-left:var(--media-slider-pointer)]\")\n};\nconst popup = {\n\t...popup$1,\n\tvolume: cn(popup$1.popover, \"p-0 bg-transparent\", \"@max-2xl/media-root:[--media-popover-side-offset:--spacing(3)]\")\n};\nconst menu = {\n\t...menu$1,\n\troot: menu$1.root,\n\tsettings: menu$1.settings\n};\n//#endregion\nexport { badge, bufferingIndicator, button, buttonGroup, buttonGroupEnd, buttonGroupStart, container, controls, error, icon, iconContainer, iconFlipped, iconHidden, iconState, inputIndicatorOverlay, menu, overlay, playbackRate, popup, poster, seek, seekIndicator, slider, spacer, statusIndicator, thumbnail, time, volumeIndicator };\n\n//# sourceMappingURL=video.tailwind.js.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,aAAa,gBAAgB,GAAG,aAAa,cAAc,0BAA0B,+EAA+E,+BAA+B,iFAAiF;CACzR,0RAA0R;CAC1R,wMAAwM,CAAC;AAC1M,GAAG,yCAAyC,oEAAoE,8DAA8D,wCAAwC,kEAAkE,gEAAgE,6CAA6C,0CAA0C,oDAAoD,8CAA8C,2CAA2C,wDAAwD,uCAAuC,iDAAiD,wDAAwD,iDAAiD,6CAA6C,8DAA8D,gEAAgE,wDAAwD,uCAAuC,8CAA8C,6CAA6C,8CAA8C,2DAA2D,uDAAuD,mDAAmD,4FAA4F,4DAA4D,2FAA2F,2DAA2D,iGAAiG,mGAAmG,iGAAiG,2CAA2C,sCAAsC,wEAAwE,gFAAgF,kGAAkG,CAAC,cAAc;CACzxE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,IAAI,CAAC,GAAG,CAAC,cAAc;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,IAAI,CAAC,GAAG,gDAAgD;CACvD,uCAAuC,CAAC;CACxC,kDAAkD;AACnD,CAAC;AACD,MAAM,WAAW,GAAG,YAAY,+BAA+B,qDAAqD,kFAAkF,2DAA2D,mBAAmB,+BAA+B,gDAAgD,0DAA0D,8DAA8D,uDAAuD,sDAAsD,kDAAkD,iDAAiD,mEAAmE,iDAAiD,qDAAqD,2GAA2G;AAC/7B,MAAM,mBAAmB,GAAG,8CAA8C,2BAA2B,sDAAsD,iDAAiD,0CAA0C;AACtP,MAAM,mBAAmB,GAAG,aAAa,kCAAkC;AAC3E,MAAM,iBAAiB,GAAG,aAAa,kBAAkB,gDAAgD,6HAA6H,iHAAiH,iHAAiH;AACxc,MAAM,SAAS;AACf,MAAM,OAAO;CACZ,GAAG;CACH,UAAU,GAAG,OAAO,UAAU,kBAAkB,+EAA+E,oJAAoJ,yHAAyH,2GAA2G;AACxf;AACA,MAAM,QAAQ;CACb,GAAG;CACH,MAAM,GAAG,QAAQ,MAAM,kCAAkC;CACzD,QAAQ,GAAG,QAAQ,QAAQ,sDAAsD;CACjF,SAAS,GAAG,QAAQ,SAAS,YAAY;CACzC,OAAO;AACR;AACA,MAAM,YAAY;AAClB,MAAM,SAAS;CACd,GAAG;CACH,OAAO,GAAG,SAAS,OAAO,qBAAqB;CAC/C,SAAS,GAAG,SAAS,SAAS,2CAA2C,qIAAqI,8DAA8D;AAC7Q;AACA,MAAM,QAAQ;CACb,GAAG;CACH,QAAQ,GAAG,QAAQ,SAAS,sBAAsB,gEAAgE;AACnH;AACA,MAAM,OAAO;CACZ,GAAG;CACH,MAAM,OAAO;CACb,UAAU,OAAO;AAClB"}
|
|
1
|
+
{"version":3,"file":"video.tailwind.js","names":[],"sources":["../../../../../../../../skins/dist/default/minimal/tailwind/video.tailwind.js"],"sourcesContent":["import { container as container$1 } from \"./components/container.js\";\nimport { controls as controls$1 } from \"./components/controls.js\";\nimport { error as error$1 } from \"./components/error.js\";\nimport { popup as popup$1 } from \"./components/popup.js\";\nimport { slider as slider$1 } from \"./components/slider.js\";\nimport { iconState } from \"../../shared/tailwind/icon-state.js\";\nimport { badge } from \"./components/badge.js\";\nimport { bufferingIndicator } from \"./components/buffering.js\";\nimport { button } from \"./components/button.js\";\nimport { buttonGroup } from \"./components/button-group.js\";\nimport { icon, iconContainer, iconFlipped, iconHidden } from \"./components/icon.js\";\nimport { menu as menu$1 } from \"./components/menu.js\";\nimport { playbackRate } from \"./components/playback-rate.js\";\nimport { seek } from \"./components/seek.js\";\nimport { time as time$1 } from \"./components/time.js\";\nimport { thumbnail as thumbnail$1 } from \"./components/thumbnail.js\";\nimport { inputIndicatorOverlay } from \"./components/input-indicator-overlay.js\";\nimport { overlay } from \"./components/overlay.js\";\nimport { poster } from \"./components/poster.js\";\nimport { seekIndicator } from \"./components/seek-indicator.js\";\nimport { statusIndicator } from \"./components/status-indicator.js\";\nimport { volumeIndicator } from \"./components/volume-indicator.js\";\nimport { cn } from \"@videojs/utils/style\";\n//#region src/minimal/tailwind/video.tailwind.ts\nconst container = (isShadowDOM) => cn(container$1, \"group/skin\", \"bg-black overflow-clip\", \"after:absolute after:pointer-events-none after:rounded-[inherit] after:z-10\", \"[&:fullscreen]:after:hidden\", \"after:inset-0 after:ring-1 after:ring-inset after:ring-(color:--border-color)\", {\n\t\"[&_::slotted(video)]:block [&_::slotted(video)]:w-full [&_::slotted(video)]:h-full [&_::slotted(video)]:rounded-(--container-border-radius) [&_::slotted(video)]:[object-fit:var(--media-object-fit,cover)] [&_::slotted(video)]:[object-position:var(--media-object-position,center)]\": isShadowDOM,\n\t\"[&_video]:block [&_video]:w-full [&_video]:h-full [&_video]:rounded-[inherit] [&_video]:[object-fit:var(--media-object-fit,contain)] [&_video]:[object-position:var(--media-object-position,center)]\": !isShadowDOM\n}, \"[--default-accent-color:oklch(1_0_0)]\", \"[--border-color:light-dark(oklch(0_0_0/0.15),oklch(1_0_0/0.15))]\", \"[--focus-ring-color:light-dark(oklch(0_0_0),oklch(1_0_0))]\", \"**:[--focus-ring-color:oklch(1_0_0)]\", \"[--container-border-radius:var(--media-border-radius,0.75rem)]\", \"[--media-video-border-radius:var(--container-border-radius)]\", \"[--controls-background-color:transparent]\", \"[--controls-transition-duration:100ms]\", \"[--controls-transition-timing-function:ease-out]\", \"[--error-dialog-transition-duration:150ms]\", \"[--error-dialog-transition-delay:100ms]\", \"[--error-dialog-transition-timing-function:ease-out]\", \"[--popup-transition-duration:100ms]\", \"[--popup-transition-timing-function:ease-out]\", \"[--popover-backdrop-filter:blur(16px)_saturate(1.5)]\", \"[--popover-background-color:oklch(0_0_0/0.5)]\", \"[--popover-border-color:oklch(1_0_0/0.1)]\", \"[--tooltip-backdrop-filter:var(--popover-backdrop-filter)]\", \"[--tooltip-background-color:var(--popover-background-color)]\", \"[--tooltip-border-color:var(--popover-border-color)]\", \"[--tooltip-text-color:currentColor]\", \"min-[1280px]:[&:fullscreen]:[--scale:1.25]\", \"min-[1536px]:[&:fullscreen]:[--scale:1.5]\", \"min-[1920px]:[&:fullscreen]:[--scale:1.75]\", \"motion-reduce:[--error-dialog-transition-duration:50ms]\", \"motion-reduce:[--error-dialog-transition-delay:0ms]\", \"motion-reduce:[--popup-transition-duration:0ms]\", \"[@media(prefers-reduced-transparency:reduce)]:[--controls-background-color:oklch(0_0_0)]\", \"contrast-more:[--controls-background-color:oklch(0_0_0)]\", \"[@media(prefers-reduced-transparency:reduce)]:[--tooltip-background-color:oklch(0_0_0)]\", \"contrast-more:[--tooltip-background-color:oklch(0_0_0)]\", \"pointer-fine:has-[[data-controls]:not([data-visible])]:[--controls-transition-duration:300ms]\", \"pointer-coarse:has-[[data-controls]:not([data-visible])]:[--controls-transition-duration:150ms]\", \"motion-reduce:has-[[data-controls]:not([data-visible])]:[--controls-transition-duration:50ms]\", \"[--media-caption-track-y:--spacing(-2)]\", \"[--media-caption-track-delay:25ms]\", \"[--media-caption-track-duration:var(--controls-transition-duration)]\", \"has-[[data-controls][data-visible]]:[--media-caption-track-y:--spacing(-18)]\", \"@2xl/media-root:has-[[data-controls][data-visible]]:*:[--media-caption-track-y:--spacing(-12)]\", !isShadowDOM ? [\n\t\"[&_video::-webkit-media-text-track-container]:transition-[translate]\",\n\t\"[&_video::-webkit-media-text-track-container]:duration-(--media-caption-track-duration)\",\n\t\"[&_video::-webkit-media-text-track-container]:ease-out\",\n\t\"[&_video::-webkit-media-text-track-container]:delay-(--media-caption-track-delay)\",\n\t\"[&_video::-webkit-media-text-track-container]:translate-y-(--media-caption-track-y)\",\n\t\"[&_video::-webkit-media-text-track-container]:scale-98\",\n\t\"[&_video::-webkit-media-text-track-container]:z-1\",\n\t\"[&_video::-webkit-media-text-track-container]:font-[inherit]\"\n] : [], \"[&:fullscreen]:[--container-border-radius:0]\", {\n\t\"[&:fullscreen_video]:object-contain\": !isShadowDOM,\n\t\"[&:fullscreen_::slotted(video)]:object-contain\": isShadowDOM\n});\nconst controls = cn(controls$1, \"absolute bottom-1 inset-x-1\", \"[--base-side-offset:5] [--base-boundary-offset:1]\", \"[--volume-mask:linear-gradient(to_right,transparent_10%,black_25%,black_100%)]\", \"gap-x-2 flex-wrap rounded-[--spacing(3)] group/controls\", \"text-white z-20\", \"peer-data-open/error:hidden\", \"ease-(--controls-transition-timing-function)\", \"duration-[calc(var(--controls-transition-duration)/2)]\", \"not-data-visible:duration-(--controls-transition-duration)\", \"pointer-fine:transition-[translate,filter,opacity]\", \"pointer-coarse:transition-[translate,opacity]\", \"not-data-visible:opacity-0 not-data-visible:pointer-events-none\", \"motion-safe:not-data-visible:translate-y-full\", \"pointer-fine:motion-safe:not-data-visible:blur-sm\", \"@2xl/media-root:flex-nowrap @2xl/media-root:[--controls-padding:2] @2xl/media-root:[--base-side-offset:2]\");\nconst volumeMaskTarget = cn(\"[mask-image:var(--volume-mask-image,none)]\", \"[mask-repeat:no-repeat]\", \"[mask-position:var(--volume-mask-position,100%_0)]\", \"[mask-size:var(--volume-mask-size,200%_100%)]\", \"[transition:mask-position_50ms_ease-out]\");\nconst buttonGroupStart = cn(buttonGroup, \"flex-1 @2xl/media-root:flex-none\");\nconst buttonGroupEnd = cn(buttonGroup, volumeMaskTarget, \"flex-1 justify-end @2xl/media-root:flex-none\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-image:var(--volume-mask)]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-position:0_0]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@max-2xl/media-root:[--volume-mask-size:400%_100%]\");\nconst spacer = \"grow\";\nconst time = {\n\t...time$1,\n\tcontrols: cn(time$1.controls, volumeMaskTarget, \"[--slider-height:--spacing(5)] grow-0 shrink-0 basis-full order-[-1] px-1.5\", \"@2xl/media-root:[--slider-height:--spacing(8)] @2xl/media-root:grow @2xl/media-root:shrink @2xl/media-root:basis-0 @2xl/media-root:order-[unset]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@2xl/media-root:[--volume-mask-image:var(--volume-mask)]\", \"group-has-[[data-volume-level][aria-expanded=true]]/controls:@2xl/media-root:[--volume-mask-position:0_0]\")\n};\nconst error = {\n\t...error$1,\n\troot: cn(error$1.root, \"pointer-events-none outline-none\"),\n\tdialog: cn(error$1.dialog, \"pointer-events-auto w-full max-w-64 p-4 rounded-none\"),\n\tcontent: cn(error$1.content, \"p-0 py-1.5\"),\n\ttitle: \"text-(length:--font-size-medium)\"\n};\nconst thumbnail = thumbnail$1;\nconst slider = {\n\t...slider$1,\n\ttrack: cn(slider$1.track, \"ring-1 ring-black/5\"),\n\tpreview: cn(slider$1.preview, \"[--preview-end-inset:calc(100cqi-100%)]\", \"[--preview-left:clamp(calc(var(--max-size)/2),var(--media-slider-pointer),calc(100%-var(--max-size)/2+var(--preview-end-inset)))]\", \"@2xl/media-root:[--preview-left:var(--media-slider-pointer)]\")\n};\nconst popup = {\n\t...popup$1,\n\tvolume: cn(popup$1.popover, \"p-0 bg-transparent\", \"@max-2xl/media-root:[--media-popover-side-offset:--spacing(3)]\")\n};\nconst menu = {\n\t...menu$1,\n\troot: menu$1.root,\n\tsettings: menu$1.settings\n};\n//#endregion\nexport { badge, bufferingIndicator, button, buttonGroup, buttonGroupEnd, buttonGroupStart, container, controls, error, icon, iconContainer, iconFlipped, iconHidden, iconState, inputIndicatorOverlay, menu, overlay, playbackRate, popup, poster, seek, seekIndicator, slider, spacer, statusIndicator, thumbnail, time, volumeIndicator };\n\n//# sourceMappingURL=video.tailwind.js.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAM,aAAa,gBAAgB,GAAG,aAAa,cAAc,0BAA0B,+EAA+E,+BAA+B,iFAAiF;CACzR,0RAA0R;CAC1R,wMAAwM,CAAC;AAC1M,GAAG,yCAAyC,oEAAoE,8DAA8D,wCAAwC,kEAAkE,gEAAgE,6CAA6C,0CAA0C,oDAAoD,8CAA8C,2CAA2C,wDAAwD,uCAAuC,iDAAiD,wDAAwD,iDAAiD,6CAA6C,8DAA8D,gEAAgE,wDAAwD,uCAAuC,8CAA8C,6CAA6C,8CAA8C,2DAA2D,uDAAuD,mDAAmD,4FAA4F,4DAA4D,2FAA2F,2DAA2D,iGAAiG,mGAAmG,iGAAiG,2CAA2C,sCAAsC,wEAAwE,gFAAgF,kGAAkG,CAAC,cAAc;CACzxE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,IAAI,CAAC,GAAG,gDAAgD;CACvD,uCAAuC,CAAC;CACxC,kDAAkD;AACnD,CAAC;AACD,MAAM,WAAW,GAAG,YAAY,+BAA+B,qDAAqD,kFAAkF,2DAA2D,mBAAmB,+BAA+B,gDAAgD,0DAA0D,8DAA8D,sDAAsD,iDAAiD,mEAAmE,iDAAiD,qDAAqD,2GAA2G;AACt1B,MAAM,mBAAmB,GAAG,8CAA8C,2BAA2B,sDAAsD,iDAAiD,0CAA0C;AACtP,MAAM,mBAAmB,GAAG,aAAa,kCAAkC;AAC3E,MAAM,iBAAiB,GAAG,aAAa,kBAAkB,gDAAgD,6HAA6H,iHAAiH,iHAAiH;AACxc,MAAM,SAAS;AACf,MAAM,OAAO;CACZ,GAAG;CACH,UAAU,GAAG,OAAO,UAAU,kBAAkB,+EAA+E,oJAAoJ,yHAAyH,2GAA2G;AACxf;AACA,MAAM,QAAQ;CACb,GAAG;CACH,MAAM,GAAG,QAAQ,MAAM,kCAAkC;CACzD,QAAQ,GAAG,QAAQ,QAAQ,sDAAsD;CACjF,SAAS,GAAG,QAAQ,SAAS,YAAY;CACzC,OAAO;AACR;AACA,MAAM,YAAY;AAClB,MAAM,SAAS;CACd,GAAG;CACH,OAAO,GAAG,SAAS,OAAO,qBAAqB;CAC/C,SAAS,GAAG,SAAS,SAAS,2CAA2C,qIAAqI,8DAA8D;AAC7Q;AACA,MAAM,QAAQ;CACb,GAAG;CACH,QAAQ,GAAG,QAAQ,SAAS,sBAAsB,gEAAgE;AACnH;AACA,MAAM,OAAO;CACZ,GAAG;CACH,MAAM,OAAO;CACb,UAAU,OAAO;AAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thumbnail.d.ts","names":[],"sources":["../../../../src/ui/thumbnail/thumbnail.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"thumbnail.d.ts","names":[],"sources":["../../../../src/ui/thumbnail/thumbnail.tsx"],"mappings":";;;UAkBiB,uBAAuB,wBAAwB,cAAc,QAAQ,cAAc;;EAElG,aAAa;;cAwBF,2BAAS,0BAAA,KAAA,yCAAA,cAAA;kBAwGL;OACH,QAAQ;OACR,QAAQ,cAAc"}
|
|
@@ -4,8 +4,24 @@ import { renderElement } from "../../utils/use-render.js";
|
|
|
4
4
|
import { createThumbnail, selectTextTrack } from "@videojs/core/dom";
|
|
5
5
|
import { forwardRef, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { isNull, isUndefined } from "@videojs/utils/predicate";
|
|
7
8
|
import { ThumbnailCore, ThumbnailDataAttrs, mapCuesToThumbnails } from "@videojs/core";
|
|
8
9
|
//#region src/ui/thumbnail/thumbnail.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Leaving `crossOrigin` unset means "follow the media element", so thumbnails
|
|
12
|
+
* keep working on a CORS-enabled player without a skin having to thread a prop
|
|
13
|
+
* through. `null` opts out and fetches the sprites no-CORS. `''` is passed
|
|
14
|
+
* straight through, since the CORS-settings attribute reads it as Anonymous.
|
|
15
|
+
*
|
|
16
|
+
* Only the `<track>` path inherits: `thumbnails` passed directly may point at a
|
|
17
|
+
* host that has nothing to do with the media element.
|
|
18
|
+
*/
|
|
19
|
+
function resolveCrossOrigin(explicit, external, inherited) {
|
|
20
|
+
if (isNull(explicit)) return void 0;
|
|
21
|
+
if (!isUndefined(explicit)) return explicit;
|
|
22
|
+
if (external?.length) return void 0;
|
|
23
|
+
return inherited ?? void 0;
|
|
24
|
+
}
|
|
9
25
|
const Thumbnail = forwardRef(function Thumbnail(componentProps, forwardedRef) {
|
|
10
26
|
const { render, className, style, time = 0, thumbnails: externalThumbnails, crossOrigin, loading, fetchPriority, ...elementProps } = componentProps;
|
|
11
27
|
const [core] = useState(() => new ThumbnailCore());
|
|
@@ -28,6 +44,7 @@ const Thumbnail = forwardRef(function Thumbnail(componentProps, forwardedRef) {
|
|
|
28
44
|
thumbnails,
|
|
29
45
|
time
|
|
30
46
|
]);
|
|
47
|
+
const resolvedCrossOrigin = resolveCrossOrigin(crossOrigin, externalThumbnails, textTrack?.thumbnailTrackCrossOrigin);
|
|
31
48
|
handle.updateSrc(thumbnail?.url);
|
|
32
49
|
const state = core.getState(handle.loading, handle.error, thumbnail);
|
|
33
50
|
let containerStyle = { overflow: "hidden" };
|
|
@@ -67,7 +84,7 @@ const Thumbnail = forwardRef(function Thumbnail(componentProps, forwardedRef) {
|
|
|
67
84
|
"aria-hidden": "true",
|
|
68
85
|
decoding: "async",
|
|
69
86
|
src: thumbnail?.url,
|
|
70
|
-
crossOrigin:
|
|
87
|
+
crossOrigin: resolvedCrossOrigin,
|
|
71
88
|
loading,
|
|
72
89
|
style: imgStyle,
|
|
73
90
|
fetchPriority
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thumbnail.js","names":[],"sources":["../../../../src/ui/thumbnail/thumbnail.tsx"],"sourcesContent":["import {\n mapCuesToThumbnails,\n ThumbnailCore,\n ThumbnailDataAttrs,\n type ThumbnailFetchPriority,\n type ThumbnailImage,\n} from '@videojs/core';\nimport { createThumbnail, selectTextTrack } from '@videojs/core/dom';\nimport type { CSSProperties } from 'react';\nimport { forwardRef, useMemo, useRef, useState } from 'react';\n\nimport { useOptionalPlayer } from '../../player/context';\nimport type { UIComponentProps } from '../../utils/types';\nimport { useDestroy } from '../../utils/use-destroy';\nimport { renderElement } from '../../utils/use-render';\n\nexport interface ThumbnailProps extends UIComponentProps<'div', ThumbnailCore.State>, ThumbnailCore.Props {\n /** Pre-parsed thumbnail images — bypasses the automatic `<track>` detection. */\n thumbnails?: ThumbnailImage[] | undefined;\n}\n\nexport const Thumbnail = forwardRef<HTMLDivElement, ThumbnailProps>(function Thumbnail(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n time = 0,\n thumbnails: externalThumbnails,\n crossOrigin,\n loading,\n fetchPriority,\n ...elementProps\n } = componentProps;\n\n const [core] = useState(() => new ThumbnailCore());\n const divRef = useRef<HTMLDivElement>(null);\n const imgRef = useRef<HTMLImageElement>(null);\n const textTrack = useOptionalPlayer(selectTextTrack);\n\n // Force re-render when the handle's state changes (img load/error, resize).\n const [, setRenderToken] = useState(0);\n\n const [handle] = useState(() =>\n createThumbnail({\n getContainer: () => divRef.current,\n getImg: () => imgRef.current,\n onStateChange: () => setRenderToken((n) => n + 1),\n })\n );\n\n useDestroy(handle, () => handle.connect());\n\n // Resolve thumbnails: external prop takes priority over auto <track> path.\n const thumbnails = useMemo(() => {\n if (externalThumbnails && externalThumbnails.length > 0) return externalThumbnails;\n return textTrack && textTrack.thumbnailCues.length > 0\n ? mapCuesToThumbnails(textTrack.thumbnailCues, textTrack.thumbnailTrackSrc ?? undefined)\n : [];\n }, [externalThumbnails, textTrack]);\n\n const thumbnail = useMemo(() => core.findActiveThumbnail(thumbnails, time), [core, thumbnails, time]);\n\n // Track src changes via the handle.\n handle.updateSrc(thumbnail?.url);\n\n const state = core.getState(handle.loading, handle.error, thumbnail);\n\n // Compute styles declaratively from resize result.\n let containerStyle: CSSProperties = { overflow: 'hidden' };\n let imgStyle: CSSProperties | undefined;\n\n if (thumbnail && handle.naturalWidth && handle.naturalHeight) {\n const constraints = handle.readConstraints();\n const result = core.resize(thumbnail, handle.naturalWidth, handle.naturalHeight, constraints);\n\n if (result) {\n containerStyle = {\n overflow: 'hidden',\n width: result.containerWidth,\n height: result.containerHeight,\n };\n imgStyle = {\n width: result.imageWidth,\n height: result.imageHeight,\n maxWidth: 'none',\n transform:\n result.offsetX || result.offsetY ? `translate(-${result.offsetX}px, -${result.offsetY}px)` : undefined,\n };\n }\n }\n\n return renderElement(\n 'div',\n { render, className, style },\n {\n state,\n stateAttrMap: ThumbnailDataAttrs,\n ref: [forwardedRef, divRef],\n props: [\n core.getAttrs(state),\n { style: containerStyle },\n elementProps,\n {\n children: (\n <img\n ref={imgRef}\n alt=\"\"\n aria-hidden=\"true\"\n decoding=\"async\"\n src={thumbnail?.url}\n crossOrigin={
|
|
1
|
+
{"version":3,"file":"thumbnail.js","names":[],"sources":["../../../../src/ui/thumbnail/thumbnail.tsx"],"sourcesContent":["import {\n mapCuesToThumbnails,\n ThumbnailCore,\n ThumbnailDataAttrs,\n type ThumbnailFetchPriority,\n type ThumbnailImage,\n} from '@videojs/core';\nimport { createThumbnail, selectTextTrack } from '@videojs/core/dom';\nimport type { MediaTextTrackState } from '@videojs/media';\nimport { isNull, isUndefined } from '@videojs/utils/predicate';\nimport type { CSSProperties } from 'react';\nimport { forwardRef, useMemo, useRef, useState } from 'react';\n\nimport { useOptionalPlayer } from '../../player/context';\nimport type { UIComponentProps } from '../../utils/types';\nimport { useDestroy } from '../../utils/use-destroy';\nimport { renderElement } from '../../utils/use-render';\n\nexport interface ThumbnailProps extends UIComponentProps<'div', ThumbnailCore.State>, ThumbnailCore.Props {\n /** Pre-parsed thumbnail images — bypasses the automatic `<track>` detection. */\n thumbnails?: ThumbnailImage[] | undefined;\n}\n\n/**\n * Leaving `crossOrigin` unset means \"follow the media element\", so thumbnails\n * keep working on a CORS-enabled player without a skin having to thread a prop\n * through. `null` opts out and fetches the sprites no-CORS. `''` is passed\n * straight through, since the CORS-settings attribute reads it as Anonymous.\n *\n * Only the `<track>` path inherits: `thumbnails` passed directly may point at a\n * host that has nothing to do with the media element.\n */\nfunction resolveCrossOrigin(\n explicit: ThumbnailCore.Props['crossOrigin'],\n external: ThumbnailImage[] | undefined,\n inherited: MediaTextTrackState['thumbnailTrackCrossOrigin'] | undefined\n) {\n if (isNull(explicit)) return undefined;\n if (!isUndefined(explicit)) return explicit;\n if (external?.length) return undefined;\n\n return inherited ?? undefined;\n}\n\nexport const Thumbnail = forwardRef<HTMLDivElement, ThumbnailProps>(function Thumbnail(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n time = 0,\n thumbnails: externalThumbnails,\n crossOrigin,\n loading,\n fetchPriority,\n ...elementProps\n } = componentProps;\n\n const [core] = useState(() => new ThumbnailCore());\n const divRef = useRef<HTMLDivElement>(null);\n const imgRef = useRef<HTMLImageElement>(null);\n const textTrack = useOptionalPlayer(selectTextTrack);\n\n // Force re-render when the handle's state changes (img load/error, resize).\n const [, setRenderToken] = useState(0);\n\n const [handle] = useState(() =>\n createThumbnail({\n getContainer: () => divRef.current,\n getImg: () => imgRef.current,\n onStateChange: () => setRenderToken((n) => n + 1),\n })\n );\n\n useDestroy(handle, () => handle.connect());\n\n // Resolve thumbnails: external prop takes priority over auto <track> path.\n const thumbnails = useMemo(() => {\n if (externalThumbnails && externalThumbnails.length > 0) return externalThumbnails;\n return textTrack && textTrack.thumbnailCues.length > 0\n ? mapCuesToThumbnails(textTrack.thumbnailCues, textTrack.thumbnailTrackSrc ?? undefined)\n : [];\n }, [externalThumbnails, textTrack]);\n\n const thumbnail = useMemo(() => core.findActiveThumbnail(thumbnails, time), [core, thumbnails, time]);\n\n const resolvedCrossOrigin = resolveCrossOrigin(crossOrigin, externalThumbnails, textTrack?.thumbnailTrackCrossOrigin);\n\n // Track src changes via the handle.\n handle.updateSrc(thumbnail?.url);\n\n const state = core.getState(handle.loading, handle.error, thumbnail);\n\n // Compute styles declaratively from resize result.\n let containerStyle: CSSProperties = { overflow: 'hidden' };\n let imgStyle: CSSProperties | undefined;\n\n if (thumbnail && handle.naturalWidth && handle.naturalHeight) {\n const constraints = handle.readConstraints();\n const result = core.resize(thumbnail, handle.naturalWidth, handle.naturalHeight, constraints);\n\n if (result) {\n containerStyle = {\n overflow: 'hidden',\n width: result.containerWidth,\n height: result.containerHeight,\n };\n imgStyle = {\n width: result.imageWidth,\n height: result.imageHeight,\n maxWidth: 'none',\n transform:\n result.offsetX || result.offsetY ? `translate(-${result.offsetX}px, -${result.offsetY}px)` : undefined,\n };\n }\n }\n\n return renderElement(\n 'div',\n { render, className, style },\n {\n state,\n stateAttrMap: ThumbnailDataAttrs,\n ref: [forwardedRef, divRef],\n props: [\n core.getAttrs(state),\n { style: containerStyle },\n elementProps,\n {\n children: (\n <img\n ref={imgRef}\n alt=\"\"\n aria-hidden=\"true\"\n decoding=\"async\"\n src={thumbnail?.url}\n crossOrigin={resolvedCrossOrigin}\n loading={loading}\n style={imgStyle}\n // React's types omit `| undefined` from fetchPriority — cast to satisfy exactOptionalPropertyTypes.\n fetchPriority={fetchPriority as ThumbnailFetchPriority}\n />\n ),\n },\n ],\n }\n );\n});\n\nexport namespace Thumbnail {\n export type Props = ThumbnailProps;\n export type State = ThumbnailCore.State;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgCA,SAAS,mBACP,UACA,UACA,WACA;CACA,IAAI,OAAO,QAAQ,GAAG,OAAO,KAAA;CAC7B,IAAI,CAAC,YAAY,QAAQ,GAAG,OAAO;CACnC,IAAI,UAAU,QAAQ,OAAO,KAAA;CAE7B,OAAO,aAAa,KAAA;AACtB;AAEA,MAAa,YAAY,WAA2C,SAAS,UAAU,gBAAgB,cAAc;CACnH,MAAM,EACJ,QACA,WACA,OACA,OAAO,GACP,YAAY,oBACZ,aACA,SACA,eACA,GAAG,iBACD;CAEJ,MAAM,CAAC,QAAQ,eAAe,IAAI,cAAc,CAAC;CACjD,MAAM,SAAS,OAAuB,IAAI;CAC1C,MAAM,SAAS,OAAyB,IAAI;CAC5C,MAAM,YAAY,kBAAkB,eAAe;CAGnD,MAAM,GAAG,kBAAkB,SAAS,CAAC;CAErC,MAAM,CAAC,UAAU,eACf,gBAAgB;EACd,oBAAoB,OAAO;EAC3B,cAAc,OAAO;EACrB,qBAAqB,gBAAgB,MAAM,IAAI,CAAC;CAClD,CAAC,CACH;CAEA,WAAW,cAAc,OAAO,QAAQ,CAAC;CAGzC,MAAM,aAAa,cAAc;EAC/B,IAAI,sBAAsB,mBAAmB,SAAS,GAAG,OAAO;EAChE,OAAO,aAAa,UAAU,cAAc,SAAS,IACjD,oBAAoB,UAAU,eAAe,UAAU,qBAAqB,KAAA,CAAS,IACrF,CAAC;CACP,GAAG,CAAC,oBAAoB,SAAS,CAAC;CAElC,MAAM,YAAY,cAAc,KAAK,oBAAoB,YAAY,IAAI,GAAG;EAAC;EAAM;EAAY;CAAI,CAAC;CAEpG,MAAM,sBAAsB,mBAAmB,aAAa,oBAAoB,WAAW,yBAAyB;CAGpH,OAAO,UAAU,WAAW,GAAG;CAE/B,MAAM,QAAQ,KAAK,SAAS,OAAO,SAAS,OAAO,OAAO,SAAS;CAGnE,IAAI,iBAAgC,EAAE,UAAU,SAAS;CACzD,IAAI;CAEJ,IAAI,aAAa,OAAO,gBAAgB,OAAO,eAAe;EAC5D,MAAM,cAAc,OAAO,gBAAgB;EAC3C,MAAM,SAAS,KAAK,OAAO,WAAW,OAAO,cAAc,OAAO,eAAe,WAAW;EAE5F,IAAI,QAAQ;GACV,iBAAiB;IACf,UAAU;IACV,OAAO,OAAO;IACd,QAAQ,OAAO;GACjB;GACA,WAAW;IACT,OAAO,OAAO;IACd,QAAQ,OAAO;IACf,UAAU;IACV,WACE,OAAO,WAAW,OAAO,UAAU,cAAc,OAAO,QAAQ,OAAO,OAAO,QAAQ,OAAO,KAAA;GACjG;EACF;CACF;CAEA,OAAO,cACL,OACA;EAAE;EAAQ;EAAW;CAAM,GAC3B;EACE;EACA,cAAc;EACd,KAAK,CAAC,cAAc,MAAM;EAC1B,OAAO;GACL,KAAK,SAAS,KAAK;GACnB,EAAE,OAAO,eAAe;GACxB;GACA,EACE,UACE,oBAAC,OAAD;IACE,KAAK;IACL,KAAI;IACJ,eAAY;IACZ,UAAS;IACT,KAAK,WAAW;IAChB,aAAa;IACJ;IACT,OAAO;IAEQ;GAChB,CAAA,EAEL;EACF;CACF,CACF;AACF,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { UIComponentProps } from "../../utils/types.js";
|
|
2
|
+
import { TitleCore } from "@videojs/core";
|
|
3
|
+
//#region src/ui/title/title.d.ts
|
|
4
|
+
interface TitleProps extends Omit<UIComponentProps<'span', TitleCore.State>, 'children'> {}
|
|
5
|
+
/**
|
|
6
|
+
* Displays the resolved content title.
|
|
7
|
+
*
|
|
8
|
+
* The component owns its text content. Set the title through the player's
|
|
9
|
+
* `title` prop rather than by passing children.
|
|
10
|
+
*
|
|
11
|
+
* Renders nothing when no title resolves.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <Title />
|
|
16
|
+
*
|
|
17
|
+
* <Title className="title" />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare const Title: import("react").ForwardRefExoticComponent<Omit<TitleProps, "ref"> & import("react").RefAttributes<HTMLSpanElement>>;
|
|
21
|
+
declare namespace Title {
|
|
22
|
+
type Props = TitleProps;
|
|
23
|
+
type State = TitleCore.State;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { Title, TitleProps };
|
|
27
|
+
//# sourceMappingURL=title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.d.ts","names":[],"sources":["../../../../src/ui/title/title.tsx"],"mappings":";;;UAWiB,mBAAmB,KAAK,yBAAyB,UAAU;;;;;;;;;;;;;;;;cAiB/D,uBAAK,0BAAA,KAAA,qCAAA,cAAA;kBA+BD;OACH,QAAQ;OACR,QAAQ,UAAU"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { usePlayer } from "../../player/context.js";
|
|
3
|
+
import { renderElement } from "../../utils/use-render.js";
|
|
4
|
+
import { logMissingFeature, selectMetadata } from "@videojs/core/dom";
|
|
5
|
+
import { forwardRef, useState } from "react";
|
|
6
|
+
import { TitleCore, TitleDataAttrs } from "@videojs/core";
|
|
7
|
+
//#region src/ui/title/title.tsx
|
|
8
|
+
/**
|
|
9
|
+
* Displays the resolved content title.
|
|
10
|
+
*
|
|
11
|
+
* The component owns its text content. Set the title through the player's
|
|
12
|
+
* `title` prop rather than by passing children.
|
|
13
|
+
*
|
|
14
|
+
* Renders nothing when no title resolves.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <Title />
|
|
19
|
+
*
|
|
20
|
+
* <Title className="title" />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
const Title = forwardRef(function Title(componentProps, forwardedRef) {
|
|
24
|
+
const { render, className, style, ...elementProps } = componentProps;
|
|
25
|
+
const metadata = usePlayer(selectMetadata);
|
|
26
|
+
const [core] = useState(() => new TitleCore());
|
|
27
|
+
if (!metadata) {
|
|
28
|
+
logMissingFeature("Title", "metadata");
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const state = core.getState(metadata);
|
|
32
|
+
if (state.hidden) return null;
|
|
33
|
+
return renderElement("span", {
|
|
34
|
+
render,
|
|
35
|
+
className,
|
|
36
|
+
style
|
|
37
|
+
}, {
|
|
38
|
+
state,
|
|
39
|
+
stateAttrMap: TitleDataAttrs,
|
|
40
|
+
ref: [forwardedRef],
|
|
41
|
+
props: [{ children: state.title }, elementProps]
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
export { Title };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.js","names":[],"sources":["../../../../src/ui/title/title.tsx"],"sourcesContent":["'use client';\n\nimport { TitleCore, TitleDataAttrs } from '@videojs/core';\nimport { logMissingFeature, selectMetadata } from '@videojs/core/dom';\nimport type { ForwardedRef } from 'react';\nimport { forwardRef, useState } from 'react';\n\nimport { usePlayer } from '../../player/context';\nimport type { UIComponentProps } from '../../utils/types';\nimport { renderElement } from '../../utils/use-render';\n\nexport interface TitleProps extends Omit<UIComponentProps<'span', TitleCore.State>, 'children'> {}\n\n/**\n * Displays the resolved content title.\n *\n * The component owns its text content. Set the title through the player's\n * `title` prop rather than by passing children.\n *\n * Renders nothing when no title resolves.\n *\n * @example\n * ```tsx\n * <Title />\n *\n * <Title className=\"title\" />\n * ```\n */\nexport const Title = forwardRef(function Title(\n componentProps: TitleProps,\n forwardedRef: ForwardedRef<HTMLSpanElement>\n) {\n const { render, className, style, ...elementProps } = componentProps;\n\n const metadata = usePlayer(selectMetadata);\n\n const [core] = useState(() => new TitleCore());\n\n if (!metadata) {\n if (__DEV__) logMissingFeature('Title', 'metadata');\n return null;\n }\n\n const state = core.getState(metadata);\n\n if (state.hidden) return null;\n\n return renderElement(\n 'span',\n { render, className, style },\n {\n state,\n stateAttrMap: TitleDataAttrs,\n ref: [forwardedRef],\n props: [{ children: state.title }, elementProps],\n }\n );\n});\n\nexport namespace Title {\n export type Props = TitleProps;\n export type State = TitleCore.State;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,QAAQ,WAAW,SAAS,MACvC,gBACA,cACA;CACA,MAAM,EAAE,QAAQ,WAAW,OAAO,GAAG,iBAAiB;CAEtD,MAAM,WAAW,UAAU,cAAc;CAEzC,MAAM,CAAC,QAAQ,eAAe,IAAI,UAAU,CAAC;CAE7C,IAAI,CAAC,UAAU;EACA,kBAAkB,SAAS,UAAU;EAClD,OAAO;CACT;CAEA,MAAM,QAAQ,KAAK,SAAS,QAAQ;CAEpC,IAAI,MAAM,QAAQ,OAAO;CAEzB,OAAO,cACL,QACA;EAAE;EAAQ;EAAW;CAAM,GAC3B;EACE;EACA,cAAc;EACd,KAAK,CAAC,YAAY;EAClB,OAAO,CAAC,EAAE,UAAU,MAAM,MAAM,GAAG,YAAY;CACjD,CACF;AACF,CAAC"}
|
package/docs/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @videojs/react documentation
|
|
2
2
|
|
|
3
|
-
Bundled markdown documentation for `@videojs/react` v10.0.0-beta.
|
|
3
|
+
Bundled markdown documentation for `@videojs/react` v10.0.0-beta.30.
|
|
4
4
|
|
|
5
5
|
Start at [`./llms.txt`](./llms.txt) — it's the structured index of every page in this directory.
|
|
6
6
|
|
package/docs/concepts/presets.md
CHANGED
|
@@ -44,7 +44,7 @@ Feature bundle
|
|
|
44
44
|
|
|
45
45
|
Features
|
|
46
46
|
|
|
47
|
-
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [quality](../reference/feature-quality.md), [audioTrack](../reference/feature-audio-track.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), metadata
|
|
47
|
+
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [quality](../reference/feature-quality.md), [audioTrack](../reference/feature-audio-track.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), [metadata](../reference/feature-metadata.md)
|
|
48
48
|
|
|
49
49
|
Skins
|
|
50
50
|
|
|
@@ -72,7 +72,7 @@ Feature bundle
|
|
|
72
72
|
|
|
73
73
|
Features
|
|
74
74
|
|
|
75
|
-
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), metadata
|
|
75
|
+
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), [metadata](../reference/feature-metadata.md)
|
|
76
76
|
|
|
77
77
|
Skins
|
|
78
78
|
|
|
@@ -124,7 +124,7 @@ Feature bundle
|
|
|
124
124
|
|
|
125
125
|
Features
|
|
126
126
|
|
|
127
|
-
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), metadata
|
|
127
|
+
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), [metadata](../reference/feature-metadata.md)
|
|
128
128
|
|
|
129
129
|
Skins
|
|
130
130
|
|
|
@@ -152,7 +152,7 @@ Feature bundle
|
|
|
152
152
|
|
|
153
153
|
Features
|
|
154
154
|
|
|
155
|
-
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), metadata
|
|
155
|
+
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), [metadata](../reference/feature-metadata.md)
|
|
156
156
|
|
|
157
157
|
Skins
|
|
158
158
|
|
package/docs/concepts/skins.md
CHANGED
|
@@ -354,7 +354,6 @@ export interface VideoPlayerProps {
|
|
|
354
354
|
style?: CSSProperties;
|
|
355
355
|
className?: string;
|
|
356
356
|
renderPoster?: Poster.Props['render'];
|
|
357
|
-
placeholder?: string | undefined;
|
|
358
357
|
}
|
|
359
358
|
|
|
360
359
|
/**
|
|
@@ -366,18 +365,10 @@ export interface VideoPlayerProps {
|
|
|
366
365
|
* />
|
|
367
366
|
* ```
|
|
368
367
|
*/
|
|
369
|
-
export function VideoPlayer({ src, poster, className, renderPoster,
|
|
370
|
-
const containerStyle = placeholder
|
|
371
|
-
? ({ '--media-poster-placeholder': `url(${placeholder})`, ...style } as CSSProperties)
|
|
372
|
-
: style;
|
|
373
|
-
|
|
368
|
+
export function VideoPlayer({ src, poster, className, renderPoster, style, ...rest }: VideoPlayerProps): ReactNode {
|
|
374
369
|
return (
|
|
375
370
|
<Player poster={poster}>
|
|
376
|
-
<Container
|
|
377
|
-
className={`media-default-skin media-default-skin--video ${className ?? ''}`}
|
|
378
|
-
style={containerStyle}
|
|
379
|
-
{...rest}
|
|
380
|
-
>
|
|
371
|
+
<Container className={`media-default-skin media-default-skin--video ${className ?? ''}`} style={style} {...rest}>
|
|
381
372
|
<Video src={src} playsInline />
|
|
382
373
|
|
|
383
374
|
<Poster render={renderPoster} />
|
|
@@ -1066,7 +1057,7 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
1066
1057
|
@media (prefers-reduced-motion: reduce) {
|
|
1067
1058
|
.media-default-skin .media-button {
|
|
1068
1059
|
scale: 1;
|
|
1069
|
-
transition-property: background-color, color
|
|
1060
|
+
transition-property: background-color, color;
|
|
1070
1061
|
will-change: auto;
|
|
1071
1062
|
}
|
|
1072
1063
|
}
|
|
@@ -1111,8 +1102,7 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
1111
1102
|
transition: opacity 0.25s;
|
|
1112
1103
|
}
|
|
1113
1104
|
.media-default-skin media-poster:not([data-visible]),
|
|
1114
|
-
.media-default-skin > img:not([data-visible])
|
|
1115
|
-
.media-default-skin > img[data-visible]:not([data-loaded]) {
|
|
1105
|
+
.media-default-skin > img:not([data-visible]) {
|
|
1116
1106
|
opacity: 0;
|
|
1117
1107
|
}
|
|
1118
1108
|
.media-default-skin media-poster ::slotted(img),
|
|
@@ -1131,30 +1121,6 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
1131
1121
|
border-radius: inherit;
|
|
1132
1122
|
}
|
|
1133
1123
|
|
|
1134
|
-
/* Blurred placeholder: HTML path targets media-poster::before, React path targets the skin container::before */
|
|
1135
|
-
.media-default-skin media-poster::before,
|
|
1136
|
-
.media-default-skin::before {
|
|
1137
|
-
position: absolute;
|
|
1138
|
-
inset: 0;
|
|
1139
|
-
pointer-events: none;
|
|
1140
|
-
content: "";
|
|
1141
|
-
background-image: var(--media-poster-placeholder, none);
|
|
1142
|
-
background-repeat: no-repeat;
|
|
1143
|
-
background-position: var(--media-object-position, center);
|
|
1144
|
-
background-size: var(--media-object-fit, contain);
|
|
1145
|
-
filter: blur(var(--media-poster-placeholder-blur, 20px));
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
/* React path: hidden by default, transitions in while poster loads */
|
|
1149
|
-
.media-default-skin::before {
|
|
1150
|
-
opacity: 0;
|
|
1151
|
-
transition: opacity 0.25s;
|
|
1152
|
-
}
|
|
1153
|
-
/* Show placeholder while the poster is visible but not yet loaded */
|
|
1154
|
-
.media-default-skin:has(img[data-visible]:not([data-loaded]))::before {
|
|
1155
|
-
opacity: 1;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
1124
|
.media-default-skin:fullscreen media-poster ::slotted(img),
|
|
1159
1125
|
.media-default-skin:fullscreen media-poster img,
|
|
1160
1126
|
.media-default-skin:fullscreen > img {
|
|
@@ -1759,7 +1725,6 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
1759
1725
|
transition-timing-function: ease-out;
|
|
1760
1726
|
transition-duration: var(--menu-transition-duration);
|
|
1761
1727
|
transition-property: translate, filter;
|
|
1762
|
-
will-change: translate, filter;
|
|
1763
1728
|
|
|
1764
1729
|
&:where([data-starting-style], [data-ending-style]) {
|
|
1765
1730
|
overflow: hidden;
|
|
@@ -1943,7 +1908,6 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
1943
1908
|
transition:
|
|
1944
1909
|
translate var(--menu-transition-duration) ease-out,
|
|
1945
1910
|
filter var(--menu-transition-duration) ease-out;
|
|
1946
|
-
will-change: translate, filter;
|
|
1947
1911
|
}
|
|
1948
1912
|
|
|
1949
1913
|
&[data-submenu-expanded="true"] > :not([data-submenu]) {
|
|
@@ -2497,12 +2461,10 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
2497
2461
|
|
|
2498
2462
|
@media (pointer: fine) {
|
|
2499
2463
|
transition-property: filter, opacity, scale, translate;
|
|
2500
|
-
will-change: filter, opacity, scale, translate;
|
|
2501
2464
|
}
|
|
2502
2465
|
|
|
2503
2466
|
@media (pointer: coarse) {
|
|
2504
2467
|
transition-property: opacity, scale, translate;
|
|
2505
|
-
will-change: opacity, scale, translate;
|
|
2506
2468
|
}
|
|
2507
2469
|
}
|
|
2508
2470
|
|
|
@@ -2587,12 +2549,10 @@ export const { Player } = createPlayer({ features: videoFeatures });
|
|
|
2587
2549
|
|
|
2588
2550
|
@media (pointer: fine) {
|
|
2589
2551
|
transition-property: filter, opacity, scale, translate;
|
|
2590
|
-
will-change: filter, opacity, scale, translate;
|
|
2591
2552
|
}
|
|
2592
2553
|
|
|
2593
2554
|
@media (pointer: coarse) {
|
|
2594
2555
|
transition-property: opacity, scale, translate;
|
|
2595
|
-
will-change: opacity, scale, translate;
|
|
2596
2556
|
}
|
|
2597
2557
|
|
|
2598
2558
|
@container media-root (width > 42rem) {
|
|
@@ -2641,7 +2601,7 @@ Feature bundle
|
|
|
2641
2601
|
|
|
2642
2602
|
Features
|
|
2643
2603
|
|
|
2644
|
-
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [quality](../reference/feature-quality.md), [audioTrack](../reference/feature-audio-track.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), metadata
|
|
2604
|
+
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [quality](../reference/feature-quality.md), [audioTrack](../reference/feature-audio-track.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), [metadata](../reference/feature-metadata.md)
|
|
2645
2605
|
|
|
2646
2606
|
Skins
|
|
2647
2607
|
|
|
@@ -2669,7 +2629,7 @@ Feature bundle
|
|
|
2669
2629
|
|
|
2670
2630
|
Features
|
|
2671
2631
|
|
|
2672
|
-
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), metadata
|
|
2632
|
+
[playback](../reference/feature-playback.md), [playbackRate](../reference/feature-playback-rate.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), [metadata](../reference/feature-metadata.md)
|
|
2673
2633
|
|
|
2674
2634
|
Skins
|
|
2675
2635
|
|
|
@@ -2721,7 +2681,7 @@ Feature bundle
|
|
|
2721
2681
|
|
|
2722
2682
|
Features
|
|
2723
2683
|
|
|
2724
|
-
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), metadata
|
|
2684
|
+
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), [metadata](../reference/feature-metadata.md)
|
|
2725
2685
|
|
|
2726
2686
|
Skins
|
|
2727
2687
|
|
|
@@ -2749,7 +2709,7 @@ Feature bundle
|
|
|
2749
2709
|
|
|
2750
2710
|
Features
|
|
2751
2711
|
|
|
2752
|
-
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), metadata
|
|
2712
|
+
[playback](../reference/feature-playback.md), [volume](../reference/feature-volume.md), [time](../reference/feature-time.md), [source](../reference/feature-source.md), [buffer](../reference/feature-buffer.md), [fullscreen](../reference/feature-fullscreen.md), [pip](../reference/feature-pip.md), [remotePlayback](../reference/feature-remote-playback.md), [controls](../reference/feature-controls.md), [textTrack](../reference/feature-text-tracks.md), [error](../reference/feature-error.md), [live](../reference/feature-live.md), [metadata](../reference/feature-metadata.md)
|
|
2753
2713
|
|
|
2754
2714
|
Skins
|
|
2755
2715
|
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Add a poster placeholder
|
|
2
|
+
|
|
3
|
+
Show a lightweight placeholder while the poster image loads
|
|
4
|
+
|
|
5
|
+
To show something while your video’s poster loads, customize the image drawn by the skin or the [Poster](../reference/poster.md) component.
|
|
6
|
+
|
|
7
|
+
The examples keep the placeholder aligned with the poster position. Change `contain` to `cover` if your poster fills its container.
|
|
8
|
+
|
|
9
|
+
[
|
|
10
|
+
|
|
11
|
+
Set your own poster
|
|
12
|
+
|
|
13
|
+
Configure your own poster URL
|
|
14
|
+
|
|
15
|
+
](../reference/poster.md)
|
|
16
|
+
|
|
17
|
+
## Use a framework image component
|
|
18
|
+
|
|
19
|
+
Many frameworks have image components that render both an image and a placeholder while it loads. Pass one to `renderPoster`; it receives `src` from Video.js when the media provides a poster.
|
|
20
|
+
|
|
21
|
+
tsx
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
import NextImage from 'next/image';
|
|
25
|
+
import type { ComponentProps } from 'react';
|
|
26
|
+
import { MuxVideo } from '@videojs/react/media/mux-video';
|
|
27
|
+
import { VideoPlayer, VideoSkin } from '@videojs/react/video';
|
|
28
|
+
|
|
29
|
+
export function MyPlayer() {
|
|
30
|
+
return (
|
|
31
|
+
<VideoPlayer>
|
|
32
|
+
<VideoSkin
|
|
33
|
+
renderPoster={({ src, ...props }: ComponentProps<'img'>) =>
|
|
34
|
+
src ? (
|
|
35
|
+
<NextImage
|
|
36
|
+
{...props}
|
|
37
|
+
src={src}
|
|
38
|
+
alt=""
|
|
39
|
+
fill
|
|
40
|
+
placeholder="blur"
|
|
41
|
+
blurDataURL="data:image/webp;base64,…"
|
|
42
|
+
/>
|
|
43
|
+
) : null
|
|
44
|
+
}
|
|
45
|
+
>
|
|
46
|
+
<MuxVideo
|
|
47
|
+
source={{ playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM' }}
|
|
48
|
+
playsInline
|
|
49
|
+
/>
|
|
50
|
+
</VideoSkin>
|
|
51
|
+
</VideoPlayer>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Next.js generates blur data for static imports. Because this poster URL arrives at runtime, pass `blurDataURL` yourself.
|
|
57
|
+
|
|
58
|
+
## Use a plain image
|
|
59
|
+
|
|
60
|
+
A background image on the poster works well for a lightweight placeholder:
|
|
61
|
+
|
|
62
|
+
tsx
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
import { MuxVideo } from '@videojs/react/media/mux-video';
|
|
66
|
+
import { VideoPlayer, VideoSkin } from '@videojs/react/video';
|
|
67
|
+
|
|
68
|
+
export function MyPlayer() {
|
|
69
|
+
return (
|
|
70
|
+
<VideoPlayer>
|
|
71
|
+
<VideoSkin
|
|
72
|
+
renderPoster={(props) => (
|
|
73
|
+
<img
|
|
74
|
+
{...props}
|
|
75
|
+
style={{
|
|
76
|
+
...props.style,
|
|
77
|
+
background:
|
|
78
|
+
"url('data:image/webp;base64,…') var(--media-object-position, center) / contain no-repeat",
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
>
|
|
83
|
+
<MuxVideo
|
|
84
|
+
source={{ playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM' }}
|
|
85
|
+
playsInline
|
|
86
|
+
/>
|
|
87
|
+
</VideoSkin>
|
|
88
|
+
</VideoPlayer>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Use the Poster component
|
|
94
|
+
|
|
95
|
+
If you built your own UI, use the same `render` prop directly on `Poster`:
|
|
96
|
+
|
|
97
|
+
tsx
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
import { Container, Poster } from '@videojs/react';
|
|
101
|
+
import { MuxVideo } from '@videojs/react/media/mux-video';
|
|
102
|
+
import { VideoPlayer } from '@videojs/react/video';
|
|
103
|
+
|
|
104
|
+
export function MyPlayer() {
|
|
105
|
+
return (
|
|
106
|
+
<VideoPlayer>
|
|
107
|
+
<Container style={{ position: 'relative', aspectRatio: '16 / 9' }}>
|
|
108
|
+
<MuxVideo
|
|
109
|
+
source={{ playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM' }}
|
|
110
|
+
playsInline
|
|
111
|
+
/>
|
|
112
|
+
<Poster
|
|
113
|
+
render={(props) => (
|
|
114
|
+
<img
|
|
115
|
+
{...props}
|
|
116
|
+
style={{
|
|
117
|
+
...props.style,
|
|
118
|
+
position: 'absolute',
|
|
119
|
+
inset: 0,
|
|
120
|
+
width: '100%',
|
|
121
|
+
height: '100%',
|
|
122
|
+
background:
|
|
123
|
+
"url('data:image/webp;base64,…') var(--media-object-position, center) / contain no-repeat",
|
|
124
|
+
objectFit: 'contain',
|
|
125
|
+
}}
|
|
126
|
+
/>
|
|
127
|
+
)}
|
|
128
|
+
/>
|
|
129
|
+
</Container>
|
|
130
|
+
</VideoPlayer>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|