@videojs/html 10.0.0 → 10.0.1
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/define/media/dash-video.js +1 -1
- package/dist/default/define/media/hls-video.js +1 -1
- package/dist/default/define/media/hlsjs-video.js +1 -1
- package/dist/default/define/media/native-hls-video.js +1 -1
- package/dist/default/extensions/mux-data/extension.js +1 -1
- package/dist/default/ui/thumbnail/element.js +2 -2
- package/dist/default/version.js +1 -1
- package/dist/dev/define/audio/compat-skin2.js.map +1 -1
- package/dist/dev/define/audio/neutral-skin2.js.map +1 -1
- package/dist/dev/define/audio/skin2.js.map +1 -1
- package/dist/dev/define/live-audio/compat-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/skin2.js.map +1 -1
- package/dist/dev/define/live-video/neutral-skin2.js.map +1 -1
- package/dist/dev/define/live-video/skin2.js.map +1 -1
- package/dist/dev/define/media/dash-video.d.ts +1 -1
- package/dist/dev/define/media/dash-video.js +1 -1
- package/dist/dev/define/media/dash-video.js.map +1 -1
- package/dist/dev/define/media/hls-video.d.ts +1 -1
- package/dist/dev/define/media/hls-video.js +1 -1
- package/dist/dev/define/media/hls-video.js.map +1 -1
- package/dist/dev/define/media/hlsjs-video.d.ts +1 -1
- package/dist/dev/define/media/hlsjs-video.js +1 -1
- package/dist/dev/define/media/hlsjs-video.js.map +1 -1
- package/dist/dev/define/media/native-hls-video.d.ts +1 -1
- package/dist/dev/define/media/native-hls-video.js +1 -1
- package/dist/dev/define/media/native-hls-video.js.map +1 -1
- package/dist/dev/define/video/compat-skin2.js.map +1 -1
- package/dist/dev/define/video/skin2.js.map +1 -1
- package/dist/dev/extensions/mux-data/extension.d.ts +1 -1
- package/dist/dev/extensions/mux-data/extension.js +1 -1
- package/dist/dev/extensions/mux-data/extension.js.map +1 -1
- package/dist/dev/ui/thumbnail/element.js +2 -2
- package/dist/dev/ui/thumbnail/element.js.map +1 -1
- package/dist/dev/version.js +1 -1
- package/docs/README.md +1 -1
- package/docs/guides/architecture.md +3 -3
- package/docs/guides/autoplay.md +3 -3
- package/docs/guides/captions.md +5 -5
- package/docs/guides/casting.md +5 -5
- package/docs/guides/cdn.md +11 -11
- package/docs/guides/customize-skins.md +2 -2
- package/docs/guides/features.md +1 -1
- package/docs/guides/fullscreen.md +1 -1
- package/docs/guides/installation-cdn.md +2 -2
- package/docs/guides/installation-shadcn.md +4 -4
- package/docs/guides/installation-svelte.md +2 -2
- package/docs/guides/installation-vue.md +2 -2
- package/docs/guides/installation.md +2 -2
- package/docs/guides/internationalization.md +5 -5
- package/docs/guides/live-streams.md +3 -3
- package/docs/guides/llms.txt +4 -3
- package/docs/guides/media-sources.md +2 -2
- package/docs/guides/migrate-from-media-chrome.md +4 -4
- package/docs/guides/migrate-from-mux-player.md +7 -7
- package/docs/guides/migrate-from-plyr.md +8 -8
- package/docs/guides/migrate-from-video-js-8.md +9 -9
- package/docs/guides/migrate-from-vidstack.md +9 -9
- package/docs/guides/migrate.md +17 -0
- package/docs/guides/mux-data.md +1 -1
- package/docs/guides/playback-errors.md +4 -4
- package/docs/guides/presets.md +13 -13
- package/docs/guides/quality.md +3 -3
- package/docs/guides/self-hosting.md +6 -6
- package/docs/guides/skins.md +5 -5
- package/docs/guides/thumbnails.md +2 -2
- package/docs/guides/user-preferences.md +2 -2
- package/docs/llms.txt +4 -3
- package/docs/reference/api/feature-fullscreen.md +2 -2
- package/docs/reference/api/feature-metadata.md +2 -2
- package/docs/reference/api/feature-source.md +1 -1
- package/docs/reference/api/feature-text-tracks.md +2 -2
- package/docs/reference/api/llms.txt +1 -1
- package/docs/reference/api/media-capabilities.md +1 -1
- package/docs/reference/api/player-store.md +3 -3
- package/docs/reference/api/preset-audio.md +2 -2
- package/docs/reference/api/preset-background.md +3 -3
- package/docs/reference/api/preset-live-audio.md +3 -3
- package/docs/reference/api/preset-live-video.md +3 -3
- package/docs/reference/api/preset-video.md +2 -2
- package/docs/reference/api/resolve-adapter-type.md +2 -2
- package/docs/reference/api/vjs8-legacy-options.md +1 -1
- package/docs/reference/components/audio-compat-skin.md +33 -3
- package/docs/reference/components/audio-neutral-skin.md +34 -4
- package/docs/reference/components/audio-skin.md +34 -4
- package/docs/reference/components/audio.md +1 -1
- package/docs/reference/components/background-video-skin.md +36 -4
- package/docs/reference/components/background-video.md +1 -1
- package/docs/reference/components/cast-button.md +1 -1
- package/docs/reference/components/cloudflare-video.md +1 -1
- package/docs/reference/components/dash-video.md +1 -1
- package/docs/reference/components/google-cast.md +1 -1
- package/docs/reference/components/hls-audio.md +1 -1
- package/docs/reference/components/hls-background-video.md +1 -1
- package/docs/reference/components/hls-video.md +1 -1
- package/docs/reference/components/hlsjs-video.md +1 -1
- package/docs/reference/components/live-audio-compat-skin.md +35 -4
- package/docs/reference/components/live-audio-neutral-skin.md +36 -5
- package/docs/reference/components/live-audio-skin.md +36 -5
- package/docs/reference/components/live-video-compat-skin.md +36 -4
- package/docs/reference/components/live-video-neutral-skin.md +37 -5
- package/docs/reference/components/live-video-skin.md +37 -5
- package/docs/reference/components/llms.txt +1 -1
- package/docs/reference/components/mux-audio.md +2 -2
- package/docs/reference/components/mux-background-video.md +1 -1
- package/docs/reference/components/mux-data.md +1 -1
- package/docs/reference/components/mux-video.md +2 -2
- package/docs/reference/components/native-hls-video.md +1 -1
- package/docs/reference/components/player-container.md +1 -1
- package/docs/reference/components/player.md +4 -4
- package/docs/reference/components/shaka-video.md +1 -1
- package/docs/reference/components/spotify-audio.md +1 -1
- package/docs/reference/components/thumbnail.md +5 -5
- package/docs/reference/components/tiktok-video.md +1 -1
- package/docs/reference/components/twitch-video.md +1 -1
- package/docs/reference/components/video-compat-skin.md +36 -3
- package/docs/reference/components/video-neutral-skin.md +37 -4
- package/docs/reference/components/video-skin.md +37 -4
- package/docs/reference/components/video.md +1 -1
- package/docs/reference/components/vimeo-video.md +1 -1
- package/docs/reference/components/wistia-video.md +1 -1
- package/docs/reference/components/youtube-video.md +1 -1
- package/package.json +38 -40
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/thumbnail/element.ts"],"sourcesContent":["import {\n mapCuesToThumbnails,\n ThumbnailCore,\n ThumbnailDataAttrs,\n type ThumbnailImage,\n type ThumbnailResizeResult,\n type ThumbnailImageProps,\n type ThumbnailProps,\n} from '@videojs/core';\nimport type { ThumbnailApi } from '@videojs/core/dom';\nimport { applyElementProps, applyStateDataAttrs, createThumbnail, selectTextTrack } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport type { MediaTextTrackState } from '@videojs/media';\nimport { findComposedElement, isHTMLImageElement, listen } from '@videojs/utils/dom';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\n\nconst SHADOW_CSS = `\\\n:host {\n display: inline-block;\n overflow: hidden;\n}\nimg,\n::slotted(img) {\n display: block;\n}`;\n\n/**\n * Image attributes the element fills in from its own properties. Ones already on an image when it is adopted are the\n * author's and are left alone, so an `<img slot=\"thumbnail\" loading=\"lazy\">` keeps its settings inside a skin.\n */\nconst IMAGE_ATTRIBUTES = ['crossorigin', 'loading', 'fetchpriority'] as const;\n\ntype ImageAttribute = (typeof IMAGE_ATTRIBUTES)[number];\n\n/** The image the element draws when none is supplied, reachable from outside as `::part(image)`. */\nfunction createFallbackImage(): HTMLImageElement {\n const img = document.createElement('img');\n\n img.alt = '';\n img.setAttribute('part', 'image');\n img.setAttribute('aria-hidden', 'true');\n img.setAttribute('decoding', 'async');\n\n return img;\n}\n\n/**\n * `<media-thumbnail>` — resolves and sizes a time-based thumbnail into an image.\n *\n * The element owns `src` and `srcset` on the active image. Left empty, it draws an image of its own in its shadow root.\n * Supply an `<img>` child instead — `<media-thumbnail time=\"12\"><img alt=\"\"></media-thumbnail>` — to compose overlays\n * or loading indicators beside the image the element controls. Any `crossorigin`, `loading`, or `fetchpriority` the\n * child already carries wins over the element's own; the rest are filled in. Inside a skin, an `<img slot=\"thumbnail\">`\n * of yours replaces the one the skin carries.\n */\nexport class ThumbnailElement extends UIElement {\n static readonly tagName = 'media-thumbnail';\n\n static override properties = {\n time: { type: Number },\n crossOrigin: { type: String, attribute: 'crossorigin' },\n loading: { type: String },\n fetchPriority: { type: String, attribute: 'fetchpriority' },\n } satisfies PropertyDeclarationMap<Exclude<keyof (ThumbnailProps & ThumbnailImageProps), 'thumbnails'>>;\n\n time = 0;\n crossOrigin: (ThumbnailProps & ThumbnailImageProps)['crossOrigin'];\n loading: (ThumbnailProps & ThumbnailImageProps)['loading'];\n fetchPriority: (ThumbnailProps & ThumbnailImageProps)['fetchPriority'];\n\n readonly #core = new ThumbnailCore();\n readonly #shadow = this.attachShadow({ mode: 'open' });\n readonly #fallback = createFallbackImage();\n readonly #children = new MutationObserver(() => this.requestUpdate());\n // An image assigned through a forwarding slot lives outside this subtree, so its\n // attributes are watched on the image itself.\n readonly #imageAttributes = new MutationObserver(() => this.requestUpdate());\n readonly #textTracks = new PlayerController(this, playerContext, selectTextTrack);\n\n #slots: AbortController | null = null;\n #img: HTMLImageElement | null = null;\n /** Attributes `#img` already carried when adopted, which the author owns. */\n #authored = new Set<ImageAttribute>();\n #thumbnails: ThumbnailImage[] = [];\n #externalThumbnails: ThumbnailImage[] | undefined;\n #lastTextTrack: MediaTextTrackState | undefined;\n #api: ThumbnailApi | null = null;\n\n constructor() {\n super();\n\n const style = document.createElement('style');\n\n style.textContent = SHADOW_CSS;\n this.#shadow.append(style, document.createElement('slot'), this.#fallback);\n }\n\n /**\n * Set thumbnail images directly, bypassing the automatic `<track>` detection. When set, this takes priority over the\n * text track path.\n */\n get thumbnails(): ThumbnailImage[] | undefined {\n return this.#externalThumbnails;\n }\n\n set thumbnails(value: ThumbnailImage[] | undefined) {\n this.#externalThumbnails = value;\n this.requestUpdate();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#api = createThumbnail({\n getContainer: () => this,\n getImg: () => this.#img,\n onStateChange: () => this.requestUpdate(),\n });\n this.#children.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['src', 'srcset'],\n });\n\n // Nodes assigned to a forwarding slot are not children of this subtree, so an image slotted\n // in later never shows up as a mutation. The slot announces it with `slotchange` instead.\n this.#slots = new AbortController();\n listen(this, 'slotchange', () => this.requestUpdate(), { signal: this.#slots.signal });\n\n // Disconnecting let go of the image, and reconnecting alone schedules no update,\n // so a moved element adopts its image and reapplies the source here.\n this.requestUpdate();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n this.#adopt(null);\n this.#children.disconnect();\n this.#slots?.abort();\n this.#slots = null;\n this.#api?.destroy();\n this.#api = null;\n }\n\n override destroyCallback(): void {\n this.#api?.destroy();\n super.destroyCallback();\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n const textTrack = this.#textTracks.value;\n\n // Resolve thumbnails: external prop takes priority over auto <track> path.\n if (this.#externalThumbnails) {\n this.#thumbnails = this.#externalThumbnails;\n } else if (textTrack !== this.#lastTextTrack) {\n this.#lastTextTrack = textTrack;\n const thumbnailsTrack = textTrack?.thumbnailsTrack;\n\n this.#thumbnails =\n thumbnailsTrack && thumbnailsTrack.cues.length > 0\n ? mapCuesToThumbnails(thumbnailsTrack.cues, thumbnailsTrack.src ?? undefined)\n : [];\n }\n\n const thumbnail = this.#core.findActiveThumbnail(this.#thumbnails, this.time);\n const img = findComposedElement(this, isHTMLImageElement) ?? this.#fallback;\n\n this.#adopt(img);\n this.#applyImageAttributes(img, textTrack);\n\n // Track src changes via the thumbnail API.\n this.#api?.updateSrc(thumbnail?.url);\n this.#applySource(thumbnail?.url);\n this.#api?.connect();\n\n if (!thumbnail) {\n this.#resetStyles();\n\n const state = this.#core.getState(false, false, undefined);\n\n applyElementProps(this, this.#core.getAttrs(state));\n applyStateDataAttrs(this, state, ThumbnailDataAttrs);\n return;\n }\n\n const api = this.#api;\n const state = this.#core.getState(api?.loading ?? false, api?.error ?? false, thumbnail);\n\n applyElementProps(this, this.#core.getAttrs(state));\n applyStateDataAttrs(this, state, ThumbnailDataAttrs);\n\n if (api?.naturalWidth && api.naturalHeight) {\n const constraints = api.readConstraints();\n const result = this.#core.resize(thumbnail, api.naturalWidth, api.naturalHeight, constraints);\n\n if (result) {\n this.#applyResize(result);\n }\n }\n }\n\n /**\n * Leaving `crossOrigin` unset means \"follow the media element\", so thumbnails keep working on a CORS-enabled player\n * without a skin having to thread an attribute through. Only the `<track>` path inherits: `thumbnails` set directly\n * may point at a host that has nothing to do with the media element.\n */\n #inheritedCrossOrigin(\n textTrack: MediaTextTrackState | undefined\n ): (ThumbnailProps & ThumbnailImageProps)['crossOrigin'] {\n return this.#externalThumbnails ? undefined : textTrack?.thumbnailsTrack?.crossOrigin;\n }\n\n /** Sync image attributes from element properties, leaving the ones the author put on the image alone. */\n #applyImageAttributes(img: HTMLImageElement, textTrack: MediaTextTrackState | undefined): void {\n const props: Partial<Record<ImageAttribute, string | undefined>> = {\n crossorigin: this.#core.resolveCrossOrigin(this.crossOrigin, this.#inheritedCrossOrigin(textTrack)),\n loading: this.loading,\n fetchpriority: this.fetchPriority,\n };\n\n for (const name of this.#authored) delete props[name];\n\n applyElementProps(img, props);\n }\n\n #applyResize(result: ThumbnailResizeResult): void {\n this.style.width = `${result.containerWidth}px`;\n this.style.height = `${result.containerHeight}px`;\n\n const imgStyle = this.#img?.style;\n if (!imgStyle) return;\n\n imgStyle.width = `${result.imageWidth}px`;\n imgStyle.height = `${result.imageHeight}px`;\n imgStyle.maxWidth = 'none';\n imgStyle.transform =\n result.offsetX || result.offsetY ? `translate(-${result.offsetX}px, -${result.offsetY}px)` : '';\n }\n\n #resetStyles(): void {\n this.style.width = '';\n this.style.height = '';\n\n const imgStyle = this.#img?.style;\n if (!imgStyle) return;\n\n imgStyle.width = '';\n imgStyle.height = '';\n imgStyle.maxWidth = '';\n imgStyle.transform = '';\n }\n\n #adopt(next: HTMLImageElement | null): void {\n if (next === this.#img) return;\n\n const previous = this.#img;\n\n if (previous) {\n this.#api?.disconnectImg(previous);\n this.#resetStyles();\n previous.removeAttribute('src');\n previous.removeAttribute('srcset');\n\n for (const name of IMAGE_ATTRIBUTES) {\n if (!this.#authored.has(name)) previous.removeAttribute(name);\n }\n }\n\n // Ownership is settled once, when an image becomes active: after the first\n // sync the attributes we set would themselves look authored.\n this.#img = next;\n this.#authored = new Set(next ? IMAGE_ATTRIBUTES.filter((name) => next.hasAttribute(name)) : []);\n this.#imageAttributes.disconnect();\n\n if (next && next !== this.#fallback) {\n this.#imageAttributes.observe(next, { attributes: true, attributeFilter: ['src', 'srcset'] });\n }\n\n // The fallback only occupies the shadow root while it is the active image,\n // so a supplied image never sits beside a hidden one.\n if (next === this.#fallback) this.#shadow.append(this.#fallback);\n else if (next) this.#fallback.remove();\n\n // Reset the request even when the next image will receive the same URL. A\n // replacement image is a new download with its own lifecycle.\n this.#api?.updateSrc(undefined);\n }\n\n #applySource(src: string | undefined): void {\n const img = this.#img;\n if (!img) return;\n\n // A srcset candidate wins over src, so the root has to clear both parts of\n // the source contract before applying the selected thumbnail URL.\n img.removeAttribute('srcset');\n\n if (!src) img.removeAttribute('src');\n else if (img.getAttribute('src') !== src) img.setAttribute('src', src);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/thumbnail/element.ts"],"sourcesContent":["import {\n mapCuesToThumbnails,\n ThumbnailCore,\n ThumbnailDataAttrs,\n type ThumbnailImage,\n type ThumbnailResizeResult,\n type ThumbnailImageProps,\n type ThumbnailProps,\n} from '@videojs/core';\nimport type { ThumbnailApi } from '@videojs/core/dom';\nimport { applyElementProps, applyStateDataAttrs, createThumbnail, selectTextTrack } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport type { MediaTextTrackState } from '@videojs/media';\nimport { findComposedElement, isHTMLImageElement, listen } from '@videojs/utils/dom';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\n\nconst SHADOW_CSS = `\\\n:host {\n display: inline-block;\n overflow: hidden;\n}\nimg,\n::slotted(img) {\n display: block;\n}`;\n\n/**\n * Image attributes the element fills in from its own properties. Ones already on an image when it is adopted are the\n * author's and are left alone, so an `<img slot=\"thumbnail\" loading=\"lazy\">` keeps its settings inside a skin.\n */\nconst IMAGE_ATTRIBUTES = ['crossorigin', 'loading', 'fetchpriority'] as const;\n\ntype ImageAttribute = (typeof IMAGE_ATTRIBUTES)[number];\n\n/** The image the element draws when none is supplied, reachable from outside as `::part(image)`. */\nfunction createFallbackImage(): HTMLImageElement {\n const img = document.createElement('img');\n\n img.alt = '';\n img.setAttribute('part', 'image');\n img.setAttribute('aria-hidden', 'true');\n img.setAttribute('decoding', 'async');\n\n return img;\n}\n\n/**\n * `<media-thumbnail>` — resolves and sizes a time-based thumbnail into an image.\n *\n * The element owns `src` and `srcset` on the active image. Left empty, it draws an image of its own in its shadow root.\n * Supply an `<img>` child instead — `<media-thumbnail time=\"12\"><img alt=\"\"></media-thumbnail>` — to compose overlays\n * or loading indicators beside the image the element controls. Any `crossorigin`, `loading`, or `fetchpriority` the\n * child already carries wins over the element's own; the rest are filled in. Inside a skin, an `<img slot=\"thumbnail\">`\n * of yours replaces the one the skin carries.\n */\nexport class ThumbnailElement extends UIElement {\n static readonly tagName = 'media-thumbnail';\n\n static override properties = {\n time: { type: Number },\n crossOrigin: { type: String, attribute: 'crossorigin' },\n loading: { type: String },\n fetchPriority: { type: String, attribute: 'fetchpriority' },\n } satisfies PropertyDeclarationMap<Exclude<keyof (ThumbnailProps & ThumbnailImageProps), 'thumbnails'>>;\n\n time = 0;\n crossOrigin: (ThumbnailProps & ThumbnailImageProps)['crossOrigin'];\n loading: (ThumbnailProps & ThumbnailImageProps)['loading'];\n fetchPriority: (ThumbnailProps & ThumbnailImageProps)['fetchPriority'];\n\n readonly #core = new ThumbnailCore();\n readonly #shadow = this.attachShadow({ mode: 'open' });\n readonly #fallback = createFallbackImage();\n readonly #children = new MutationObserver(() => this.requestUpdate());\n // An image assigned through a forwarding slot lives outside this subtree, so its\n // attributes are watched on the image itself.\n readonly #imageAttributes = new MutationObserver(() => this.requestUpdate());\n readonly #textTracks = new PlayerController(this, playerContext, selectTextTrack);\n\n #slots: AbortController | null = null;\n #img: HTMLImageElement | null = null;\n /** Attributes `#img` already carried when adopted, which the author owns. */\n #authored = new Set<ImageAttribute>();\n #thumbnails: ThumbnailImage[] = [];\n #externalThumbnails: ThumbnailImage[] | undefined;\n #lastTextTrack: MediaTextTrackState | undefined;\n #api: ThumbnailApi | null = null;\n\n constructor() {\n super();\n\n const style = document.createElement('style');\n\n style.textContent = SHADOW_CSS;\n this.#shadow.append(style, document.createElement('slot'), this.#fallback);\n }\n\n /**\n * Set thumbnail images directly, bypassing the automatic `<track>` detection. When set, this takes priority over the\n * text track path.\n */\n get thumbnails(): ThumbnailImage[] | undefined {\n return this.#externalThumbnails;\n }\n\n set thumbnails(value: ThumbnailImage[] | undefined) {\n this.#externalThumbnails = value;\n this.requestUpdate();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#api = createThumbnail({\n getContainer: () => this,\n getImg: () => this.#img,\n onStateChange: () => this.requestUpdate(),\n });\n this.#children.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['src', 'srcset'],\n });\n\n // Nodes assigned to a forwarding slot are not children of this subtree, so an image slotted\n // in later never shows up as a mutation. The slot announces it with `slotchange` instead.\n this.#slots = new AbortController();\n listen(this, 'slotchange', () => this.requestUpdate(), { signal: this.#slots.signal });\n\n // Disconnecting let go of the image, and reconnecting alone schedules no update,\n // so a moved element adopts its image and reapplies the source here.\n this.requestUpdate();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n this.#adopt(null);\n this.#children.disconnect();\n this.#slots?.abort();\n this.#slots = null;\n this.#api?.destroy();\n this.#api = null;\n }\n\n override destroyCallback(): void {\n this.#api?.destroy();\n super.destroyCallback();\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n const textTrack = this.#textTracks.value;\n\n // Resolve thumbnails: external prop takes priority over auto <track> path.\n if (this.#externalThumbnails) {\n this.#thumbnails = this.#externalThumbnails;\n } else if (textTrack !== this.#lastTextTrack) {\n this.#lastTextTrack = textTrack;\n const thumbnailsTrack = textTrack?.thumbnailsTrack;\n\n this.#thumbnails =\n thumbnailsTrack && thumbnailsTrack.cues.length > 0\n ? mapCuesToThumbnails(thumbnailsTrack.cues, thumbnailsTrack.src ?? undefined)\n : [];\n }\n\n const thumbnail = this.#core.findActiveThumbnail(this.#thumbnails, this.time);\n const img = findComposedElement(this, isHTMLImageElement) ?? this.#fallback;\n\n this.#adopt(img);\n this.#applyImageAttributes(img, textTrack);\n\n // Track src changes via the thumbnail API.\n this.#api?.updateSrc(thumbnail?.url);\n this.#applySource(thumbnail?.url);\n this.#api?.connect();\n\n if (!thumbnail) {\n this.#resetStyles();\n\n const state = this.#core.getState(false, false, undefined);\n\n applyElementProps(this, this.#core.getAttrs(state));\n applyStateDataAttrs(this, state, ThumbnailDataAttrs);\n return;\n }\n\n const api = this.#api;\n const state = this.#core.getState(api?.loading ?? false, api?.error ?? false, thumbnail);\n\n applyElementProps(this, this.#core.getAttrs(state));\n applyStateDataAttrs(this, state, ThumbnailDataAttrs);\n\n if (api?.naturalWidth && api.naturalHeight) {\n const constraints = api.readConstraints();\n const result = this.#core.resize(thumbnail, api.naturalWidth, api.naturalHeight, constraints);\n\n if (result) {\n this.#applyResize(result);\n }\n }\n }\n\n /**\n * Leaving `crossOrigin` unset means \"follow the media component\", so thumbnails keep working on a CORS-enabled player\n * without a skin having to thread an attribute through. Only the `<track>` path inherits: `thumbnails` set directly\n * may point at a host that has nothing to do with the media component.\n */\n #inheritedCrossOrigin(\n textTrack: MediaTextTrackState | undefined\n ): (ThumbnailProps & ThumbnailImageProps)['crossOrigin'] {\n return this.#externalThumbnails ? undefined : textTrack?.thumbnailsTrack?.crossOrigin;\n }\n\n /** Sync image attributes from element properties, leaving the ones the author put on the image alone. */\n #applyImageAttributes(img: HTMLImageElement, textTrack: MediaTextTrackState | undefined): void {\n const props: Partial<Record<ImageAttribute, string | undefined>> = {\n crossorigin: this.#core.resolveCrossOrigin(this.crossOrigin, this.#inheritedCrossOrigin(textTrack)),\n loading: this.loading,\n fetchpriority: this.fetchPriority,\n };\n\n for (const name of this.#authored) delete props[name];\n\n applyElementProps(img, props);\n }\n\n #applyResize(result: ThumbnailResizeResult): void {\n this.style.width = `${result.containerWidth}px`;\n this.style.height = `${result.containerHeight}px`;\n\n const imgStyle = this.#img?.style;\n if (!imgStyle) return;\n\n imgStyle.width = `${result.imageWidth}px`;\n imgStyle.height = `${result.imageHeight}px`;\n imgStyle.maxWidth = 'none';\n imgStyle.transform =\n result.offsetX || result.offsetY ? `translate(-${result.offsetX}px, -${result.offsetY}px)` : '';\n }\n\n #resetStyles(): void {\n this.style.width = '';\n this.style.height = '';\n\n const imgStyle = this.#img?.style;\n if (!imgStyle) return;\n\n imgStyle.width = '';\n imgStyle.height = '';\n imgStyle.maxWidth = '';\n imgStyle.transform = '';\n }\n\n #adopt(next: HTMLImageElement | null): void {\n if (next === this.#img) return;\n\n const previous = this.#img;\n\n if (previous) {\n this.#api?.disconnectImg(previous);\n this.#resetStyles();\n previous.removeAttribute('src');\n previous.removeAttribute('srcset');\n\n for (const name of IMAGE_ATTRIBUTES) {\n if (!this.#authored.has(name)) previous.removeAttribute(name);\n }\n }\n\n // Ownership is settled once, when an image becomes active: after the first\n // sync the attributes we set would themselves look authored.\n this.#img = next;\n this.#authored = new Set(next ? IMAGE_ATTRIBUTES.filter((name) => next.hasAttribute(name)) : []);\n this.#imageAttributes.disconnect();\n\n if (next && next !== this.#fallback) {\n this.#imageAttributes.observe(next, { attributes: true, attributeFilter: ['src', 'srcset'] });\n }\n\n // The fallback only occupies the shadow root while it is the active image,\n // so a supplied image never sits beside a hidden one.\n if (next === this.#fallback) this.#shadow.append(this.#fallback);\n else if (next) this.#fallback.remove();\n\n // Reset the request even when the next image will receive the same URL. A\n // replacement image is a new download with its own lifecycle.\n this.#api?.updateSrc(undefined);\n }\n\n #applySource(src: string | undefined): void {\n const img = this.#img;\n if (!img) return;\n\n // A srcset candidate wins over src, so the root has to clear both parts of\n // the source contract before applying the selected thumbnail URL.\n img.removeAttribute('srcset');\n\n if (!src) img.removeAttribute('src');\n else if (img.getAttribute('src') !== src) img.setAttribute('src', src);\n }\n}\n"],"mappings":"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"}
|
package/dist/dev/version.js
CHANGED
package/docs/README.md
CHANGED
|
@@ -70,7 +70,7 @@ Media components are the components that actually display your media. They’re
|
|
|
70
70
|
|
|
71
71
|
Media components can be format specific (HLS, DASH), service specific (YouTube, Vimeo, Mux), or use case specific (background video).
|
|
72
72
|
|
|
73
|
-
Media
|
|
73
|
+
Media components are discovered automatically. Plain `<video>` and `<audio>` elements are found via a `querySelector`. Media components like `<hlsjs-video>` register themselves after you import their registration entry point.
|
|
74
74
|
|
|
75
75
|
```html
|
|
76
76
|
<video-player>
|
|
@@ -104,7 +104,7 @@ An extension can provide behavior that a UI component controls: `<google-cast>`
|
|
|
104
104
|
|
|
105
105
|
The default presets are `@videojs/html/video` and `@videojs/html/audio`, covering the baseline set of controls you’d expect from the HTML `<video>` and `<audio>` tags.
|
|
106
106
|
|
|
107
|
-
Beyond the defaults, presets target more specific use cases. The `/background` preset combines a media
|
|
107
|
+
Beyond the defaults, presets target more specific use cases. The `/background` preset combines a media component with autoplay, mute, and loop built in, a skin with no controls, and only the features needed to power it.
|
|
108
108
|
|
|
109
109
|
You can use it from the `@videojs/html/background/*` registration entry points.
|
|
110
110
|
|
|
@@ -117,4 +117,4 @@ You can use it from the `@videojs/html/background/*` registration entry points.
|
|
|
117
117
|
- [Installation](./installation.md): Install Video.js packages and build an accessible, customizable video player with composable controls
|
|
118
118
|
- [Features](./features.md): The state and actions each feature adds to the player
|
|
119
119
|
- [Skins](./skins.md): Packaged player designs that include both UI components and their styles.
|
|
120
|
-
- [Presets](./presets.md): Pre-packaged player configurations that bundle state management, skins, and media
|
|
120
|
+
- [Presets](./presets.md): Pre-packaged player configurations that bundle state management, skins, and media components for specific use cases.
|
package/docs/guides/autoplay.md
CHANGED
|
@@ -6,7 +6,7 @@ For the best chance of autoplay succeeding, start playback muted and enable inli
|
|
|
6
6
|
|
|
7
7
|
## Recommended approach
|
|
8
8
|
|
|
9
|
-
Set autoplay, muted, and inline playback on the media
|
|
9
|
+
Set autoplay, muted, and inline playback on the media component, and keep a manual play control available for when autoplay is blocked.
|
|
10
10
|
|
|
11
11
|
**index.html**
|
|
12
12
|
|
|
@@ -112,7 +112,7 @@ These components default to muted, looping playback without player controls. Pro
|
|
|
112
112
|
|
|
113
113
|
Do not rely on unmuted autoplay for a user’s first visit. Start playback from an explicit user action instead.
|
|
114
114
|
|
|
115
|
-
Call `play()` on the media
|
|
115
|
+
Call `play()` on the media component from a click handler:
|
|
116
116
|
|
|
117
117
|
```html
|
|
118
118
|
<video-player>
|
|
@@ -148,7 +148,7 @@ If autoplay is blocked, the player stays paused and the Play button remains in i
|
|
|
148
148
|
|
|
149
149
|
### The video opens fullscreen on iPhone
|
|
150
150
|
|
|
151
|
-
Enable inline playback with the `playsinline` attribute on the media
|
|
151
|
+
Enable inline playback with the `playsinline` attribute on the media component.
|
|
152
152
|
|
|
153
153
|
### The video starts without sound
|
|
154
154
|
|
package/docs/guides/captions.md
CHANGED
|
@@ -8,7 +8,7 @@ Show captions and subtitles, and let users turn them on and pick a language.
|
|
|
8
8
|
|
|
9
9
|
## Recommended approach
|
|
10
10
|
|
|
11
|
-
Add WebVTT tracks as `<track>` children of the media
|
|
11
|
+
Add WebVTT tracks as `<track>` children of the media component, and give users a [`<media-captions-button>`](../reference/components/captions-button.md) to toggle them.
|
|
12
12
|
|
|
13
13
|
The `<track>` loads `/docs/demos/text-tracks/captions.vtt`, shown in the `captions.vtt` tab. Host a WebVTT file for your video and point `src` at its URL.
|
|
14
14
|
|
|
@@ -93,7 +93,7 @@ Toggle captions on and off with a single click.
|
|
|
93
93
|
|
|
94
94
|
## How it works
|
|
95
95
|
|
|
96
|
-
The [text track feature](../reference/api/feature-text-tracks.md) mirrors the media
|
|
96
|
+
The [text track feature](../reference/api/feature-text-tracks.md) mirrors the media component’s `textTracks` into player state:
|
|
97
97
|
|
|
98
98
|
- `textTrackList` holds every track with its `id`, `kind`, `label`, `language`, and `mode`.
|
|
99
99
|
- `subtitlesShowing` is `true` when any caption or subtitle track is showing.
|
|
@@ -108,7 +108,7 @@ The browser renders the cues. Style them with the `::cue` pseudo-element.
|
|
|
108
108
|
|
|
109
109
|
- Captions availability is `'unavailable'` until the media has at least one caption or subtitle track; caption controls render nothing in that case.
|
|
110
110
|
- Cues load asynchronously. A track appears in `textTrackList` before its cues are parsed, so cue-driven UI fills in when the track finishes loading.
|
|
111
|
-
- Cross-origin track files require CORS: serve the VTT with CORS headers and set `crossorigin` on the media
|
|
111
|
+
- Cross-origin track files require CORS: serve the VTT with CORS headers and set `crossorigin` on the media component.
|
|
112
112
|
- Track selection UIs identify tracks by `label` and `language`; give every track both.
|
|
113
113
|
- `default` on a `<track>` marks it as the preferred initial track. The browser’s caption preferences can select another track.
|
|
114
114
|
|
|
@@ -155,7 +155,7 @@ Confirm that:
|
|
|
155
155
|
|
|
156
156
|
### Captions work locally but not in production
|
|
157
157
|
|
|
158
|
-
The track file is served from another origin without CORS headers. Serve it with `Access-Control-Allow-Origin` and set `crossorigin` on the media
|
|
158
|
+
The track file is served from another origin without CORS headers. Serve it with `Access-Control-Allow-Origin` and set `crossorigin` on the media component.
|
|
159
159
|
|
|
160
160
|
### The captions menu is empty
|
|
161
161
|
|
|
@@ -176,5 +176,5 @@ The radio group hides when there are no caption or subtitle tracks, but the exam
|
|
|
176
176
|
### Guides
|
|
177
177
|
|
|
178
178
|
- [Show timeline thumbnail previews](./thumbnails.md): Preview frames along the timeline while the user scrubs, powered by a storyboard track.
|
|
179
|
-
- [Media sources](./media-sources.md): Set what a media
|
|
179
|
+
- [Media sources](./media-sources.md): Set what a media component plays and how its engine plays it with the structured source property
|
|
180
180
|
- [Accessibility](./accessibility.md): How Video.js approaches accessibility, and what you should consider if you're deeply customizing your player
|
package/docs/guides/casting.md
CHANGED
|
@@ -116,7 +116,7 @@ import '@videojs/html/ui/airplay-button';
|
|
|
116
116
|
import '@videojs/html/ui/cast-button';
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
The demo pairs the media
|
|
119
|
+
The demo pairs the media component with the `<google-cast>` extension. Without that extension, `<media-cast-button>` drives the browser’s native Remote Playback API instead, which does not provide Video.js receiver or load-request configuration.
|
|
120
120
|
|
|
121
121
|
## How it works
|
|
122
122
|
|
|
@@ -130,7 +130,7 @@ AirPlay uses WebKit’s presentation APIs. Google Cast uses a sender and receive
|
|
|
130
130
|
|
|
131
131
|
While connected, playback actions — play, pause, seek, volume — proxy to the remote device, and player state keeps reflecting the remote session. Local playback is suspended.
|
|
132
132
|
|
|
133
|
-
Control playback and read its state through the player while casting: use the built-in controls or the [store actions and state](../reference/api/player-store.md) on the player element’s `store`. Don’t call methods on the media
|
|
133
|
+
Control playback and read its state through the player while casting: use the built-in controls or the [store actions and state](../reference/api/player-store.md) on the player element’s `store`. Don’t call methods on the media component or listen for its events to drive or track a session.
|
|
134
134
|
|
|
135
135
|
For a custom control, call `promptRemotePlayback()` directly from the click handler and catch its promise. It rejects when no remote route exists or the browser refuses the request. A canceled Google Cast picker can also resolve without connecting, so show success only when `remotePlaybackState` is `'connected'`. The built-in buttons handle the request for you.
|
|
136
136
|
|
|
@@ -142,7 +142,7 @@ The Google Cast SDK loads only when the player includes the `<google-cast>` exte
|
|
|
142
142
|
- Google Cast works only in Chromium-based browsers; elsewhere its route reports `'unsupported'`.
|
|
143
143
|
- AirPlay works only in Safari; availability requires an AirPlay device reachable on the network.
|
|
144
144
|
- The remote device fetches the source and its text tracks on its own. Localhost, VPN-only, expired, or cross-origin URLs without the necessary CORS headers will fail on the receiver even if they play in the browser.
|
|
145
|
-
- Set the `disableremoteplayback` attribute on the media
|
|
145
|
+
- Set the `disableremoteplayback` attribute on the media component to opt out entirely.
|
|
146
146
|
|
|
147
147
|
## Common variations
|
|
148
148
|
|
|
@@ -172,7 +172,7 @@ The receiver cannot fetch the media. Confirm the source URL is reachable from th
|
|
|
172
172
|
|
|
173
173
|
### Custom UI shows local playback while casting
|
|
174
174
|
|
|
175
|
-
The code reads or controls the media
|
|
175
|
+
The code reads or controls the media component directly. Read playback state from the player store and call its actions instead; only the player reflects the remote session.
|
|
176
176
|
|
|
177
177
|
### The UI freezes on “connecting”
|
|
178
178
|
|
|
@@ -193,4 +193,4 @@ For Google Cast, track the `promptRemotePlayback()` promise separately from `rem
|
|
|
193
193
|
|
|
194
194
|
### Guides
|
|
195
195
|
|
|
196
|
-
- [Media sources](./media-sources.md): Set what a media
|
|
196
|
+
- [Media sources](./media-sources.md): Set what a media component plays and how its engine plays it with the structured source property
|
package/docs/guides/cdn.md
CHANGED
|
@@ -27,7 +27,7 @@ Each installation [preset](./presets.md) ships its bundles at the package root:
|
|
|
27
27
|
| `video-compat.js` | `<video-player>`, `<video-compat-skin>`, and the UI elements the compat skin composes |
|
|
28
28
|
| `video-player.js` | `<video-player>` alone, for markup without a packaged skin |
|
|
29
29
|
|
|
30
|
-
The other presets follow the same pattern. Background video is the exception: one bundle, `background.js`, registers the player, the skin, and the `<background-video>` media
|
|
30
|
+
The other presets follow the same pattern. Background video is the exception: one bundle, `background.js`, registers the player, the skin, and the `<background-video>` media component.
|
|
31
31
|
|
|
32
32
|
A skin bundle registers every UI element its skin is built from. Any element the skin does not compose is its own bundle under `ui/`.
|
|
33
33
|
|
|
@@ -36,19 +36,19 @@ A skin bundle registers every UI element its skin is built from. Any element the
|
|
|
36
36
|
Each [UI element](./ui-components.md) is its own bundle under `ui/`, for markup that a skin bundle does not already cover: a player-only bundle, [skin source](./customize-skins.md#style-skin-source) that adds a component the packaged skin lacks, or a [dialog](../reference/components/dialog.md) your page opens beside a packaged skin.
|
|
37
37
|
|
|
38
38
|
```html
|
|
39
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
40
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
39
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video-player.js"></script>
|
|
40
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/ui/play-button.js"></script>
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Each path mirrors its npm subpath: `ui/play-button.js` registers the element that `@videojs/html/ui/play-button` does. Compound components list one bundle per part in their reference page’s Import section, and all of the bundles share chunks with the player.
|
|
44
44
|
|
|
45
45
|
## Media bundles
|
|
46
46
|
|
|
47
|
-
The default presets play through the browser’s own `<video>` and `<audio>`. Every other [media
|
|
47
|
+
The default presets play through the browser’s own `<video>` and `<audio>`. Every other [media component](./media-sources.md) is its own bundle under `media/`, loaded beside the player bundle:
|
|
48
48
|
|
|
49
49
|
```html
|
|
50
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
51
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
50
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
51
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/media/hlsjs-video.js"></script>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
Each path mirrors its npm subpath. Elements with more than one playback engine keep the extra flavors in a directory named for the element, such as `media/mux-video/spf.js`. Load one flavor per page: every flavor claims the same tag name, and the first registration wins.
|
|
@@ -58,9 +58,9 @@ Each path mirrors its npm subpath. Elements with more than one playback engine k
|
|
|
58
58
|
Each [extension](./architecture.md) is its own bundle under `extensions/`, loaded beside the player and media bundles:
|
|
59
59
|
|
|
60
60
|
```html
|
|
61
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
62
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
63
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
61
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
62
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/media/mux-video.js"></script>
|
|
63
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/extensions/mux-data.js"></script>
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
As with media, each path mirrors its npm subpath: `extensions/mux-data.js` registers the element that `@videojs/html/extensions/mux-data` does.
|
|
@@ -70,8 +70,8 @@ As with media, each path mirrors its npm subpath: `extensions/mux-data.js` regis
|
|
|
70
70
|
English ships inside the skin bundles. Each other locale is a bundle under `locales/` that registers its translations on import. Load it before the player script to avoid a flash of English:
|
|
71
71
|
|
|
72
72
|
```html
|
|
73
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
74
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
73
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/locales/es.js"></script>
|
|
74
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
One bundle exists per locale pack, plus bare-language aliases such as `pt`. For custom strings, see [Internationalize the player](./internationalization.md).
|
|
@@ -38,7 +38,7 @@ If you omit `--media-accent-text-color`, the skins choose a contrasting text col
|
|
|
38
38
|
|
|
39
39
|
The skins use [`Inter`](https://rsms.me/inter/) when your page loads it and fall back to the system UI font. Video.js does not load the webfont for you. Set `--media-font-family` to use another font.
|
|
40
40
|
|
|
41
|
-
The media
|
|
41
|
+
The media component and poster share `--media-object-fit` and `--media-object-position`, so a `cover` poster stays aligned with `cover` video. See [Add a poster and loading placeholder](./poster.md).
|
|
42
42
|
|
|
43
43
|
### Set the color scheme
|
|
44
44
|
|
|
@@ -96,7 +96,7 @@ The Shadcn installation guide handles project setup, lets you choose the skin an
|
|
|
96
96
|
|
|
97
97
|
### Use the installed skin
|
|
98
98
|
|
|
99
|
-
The skin directory contains `skin.html`, `skin.ts`, and `skin.css`. Keep importing the player and media from `@videojs/html`. Import the installed `skin.ts` once, then paste the markup from `skin.html` inside your player around the media
|
|
99
|
+
The skin directory contains `skin.html`, `skin.ts`, and `skin.css`. Keep importing the player and media from `@videojs/html`. Import the installed `skin.ts` once, then paste the markup from `skin.html` inside your player around the media component.
|
|
100
100
|
|
|
101
101
|
### Edit the installed files
|
|
102
102
|
|
package/docs/guides/features.md
CHANGED
|
@@ -24,7 +24,7 @@ For example, if you import `<video-player>` from the `/video` path, you will hav
|
|
|
24
24
|
</video-player>
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Feature bundles are usually paired with specific skins and media
|
|
27
|
+
Feature bundles are usually paired with specific skins and media components in a **preset**. To learn more about this, and the available presets, you’ll want to check out the presets guide.
|
|
28
28
|
|
|
29
29
|
- [Learn more about presets](./presets.md)
|
|
30
30
|
|
|
@@ -77,7 +77,7 @@ import '@videojs/html/ui/fullscreen-button';
|
|
|
77
77
|
The [fullscreen feature](../reference/api/feature-fullscreen.md) tracks fullscreen state and provides the actions:
|
|
78
78
|
|
|
79
79
|
- `isFullscreen` is `true` while the player is fullscreen, from any path — your button, native controls, or the platform presentation.
|
|
80
|
-
- `fullscreenAvailability` is `'available'`, `'unavailable'`, or `'unsupported'`. It starts as `'unavailable'`, then settles to `'available'` or `'unsupported'` when the feature attaches to a media
|
|
80
|
+
- `fullscreenAvailability` is `'available'`, `'unavailable'`, or `'unsupported'`. It starts as `'unavailable'`, then settles to `'available'` or `'unsupported'` when the feature attaches to a media component.
|
|
81
81
|
- `requestFullscreen()` and `exitFullscreen()` change the presentation. When the Fullscreen API is available, requests target the player container. Otherwise they fall back to the media element’s native presentation.
|
|
82
82
|
|
|
83
83
|
Fullscreen and picture-in-picture are exclusive: requesting fullscreen exits an active picture-in-picture presentation first.
|
|
@@ -89,7 +89,7 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
89
89
|
## Reproduce or change these instructions
|
|
90
90
|
|
|
91
91
|
```sh
|
|
92
|
-
npx @videojs/cli@10.0.
|
|
92
|
+
npx @videojs/cli@10.0.1 agents init --method cdn --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --template none
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
## Load Video.js
|
|
@@ -101,7 +101,7 @@ Add these module scripts to the page head. Module scripts are deferred, so they
|
|
|
101
101
|
_Merge this into the page `<head>`._
|
|
102
102
|
|
|
103
103
|
```html
|
|
104
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
104
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
## Add your player
|
|
@@ -94,7 +94,7 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
94
94
|
## Reproduce or change these instructions
|
|
95
95
|
|
|
96
96
|
```sh
|
|
97
|
-
npx @videojs/cli@10.0.
|
|
97
|
+
npx @videojs/cli@10.0.1 agents init --method shadcn --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite --styling css
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
## Configure app aliases
|
|
@@ -214,7 +214,7 @@ pnpm dlx shadcn@latest registry add @videojs=https://shadcn.videojs.org/r/html/{
|
|
|
214
214
|
|
|
215
215
|
## Add the skin source
|
|
216
216
|
|
|
217
|
-
Make sure the working tree is clean or checkpointed so every added or replaced file is reviewable; ask before committing. The add command overwrites an existing Video.js skin so catalog and theme changes fully apply. Review and remove obsolete Video.js style files left by a previous catalog. The later media step restores the selected media
|
|
217
|
+
Make sure the working tree is clean or checkpointed so every added or replaced file is reviewable; ask before committing. The add command overwrites an existing Video.js skin so catalog and theme changes fully apply. Review and remove obsolete Video.js style files left by a previous catalog. The later media step restores the selected media component after an overwrite.
|
|
218
218
|
|
|
219
219
|
```bash
|
|
220
220
|
pnpm dlx shadcn@latest add @videojs/video --overwrite --yes
|
|
@@ -222,11 +222,11 @@ pnpm dlx shadcn@latest add @videojs/video --overwrite --yes
|
|
|
222
222
|
|
|
223
223
|
## Add your player
|
|
224
224
|
|
|
225
|
-
Use the aliases.components value from components.json when it differs from the generated @/components path: the skin file then lives under the directory that alias maps to instead of src/components, and the skin import uses that alias. Replace the <!-- Add a compatible media
|
|
225
|
+
Use the aliases.components value from components.json when it differs from the generated @/components path: the skin file then lives under the directory that alias maps to instead of src/components, and the skin import uses that alias. Replace the <!-- Add a compatible media component here. --> placeholder in src/components/videojs/video/skin.html with the media snippet below. Size the video on the skin's root media-container by replacing its opening <media-container with the snippet below. Then replace the <!-- Paste the contents of src/components/videojs/video/skin.html here. --> comment in the page with the complete updated skin markup. Merge the example into the existing Vite route or component that should render the player, and preserve unrelated content.
|
|
226
226
|
|
|
227
227
|
### `src/components/videojs/video/skin.html`
|
|
228
228
|
|
|
229
|
-
_Replace `<!-- Add a compatible media
|
|
229
|
+
_Replace `<!-- Add a compatible media component here. -->` with this block._
|
|
230
230
|
|
|
231
231
|
```html
|
|
232
232
|
<video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" playsinline></video>
|
|
@@ -90,13 +90,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
90
90
|
## Reproduce or change these instructions
|
|
91
91
|
|
|
92
92
|
```sh
|
|
93
|
-
npx @videojs/cli@10.0.
|
|
93
|
+
npx @videojs/cli@10.0.1 agents init --method packaged --framework svelte --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
## Install the packages
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
pnpm add @videojs/html@10.0.
|
|
99
|
+
pnpm add @videojs/html@10.0.1
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## Add your player
|
|
@@ -90,13 +90,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
90
90
|
## Reproduce or change these instructions
|
|
91
91
|
|
|
92
92
|
```sh
|
|
93
|
-
npx @videojs/cli@10.0.
|
|
93
|
+
npx @videojs/cli@10.0.1 agents init --method packaged --framework vue --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
## Install the packages
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
pnpm add @videojs/html@10.0.
|
|
99
|
+
pnpm add @videojs/html@10.0.1
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## Register custom elements
|
|
@@ -92,13 +92,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
92
92
|
## Reproduce or change these instructions
|
|
93
93
|
|
|
94
94
|
```sh
|
|
95
|
-
npx @videojs/cli@10.0.
|
|
95
|
+
npx @videojs/cli@10.0.1 agents init --method packaged --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
## Install the packages
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
pnpm add @videojs/html@10.0.
|
|
101
|
+
pnpm add @videojs/html@10.0.1
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
## Add your player
|
|
@@ -199,8 +199,8 @@ import '@videojs/html/i18n/locales/ja/register';
|
|
|
199
199
|
CDN locale modules call `registerI18n` on import. Pin every URL to the same version:
|
|
200
200
|
|
|
201
201
|
```html
|
|
202
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
203
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
202
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/locales/es.js"></script>
|
|
203
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
Use the same pinned version for your locale pack, `i18n.js`, and player script. Copies loaded in the same window share a registry; matching versions keeps their translation keys and APIs compatible. Import the full locale pack before partial overrides, and register before the player loads to translate the first render:
|
|
@@ -208,15 +208,15 @@ Use the same pinned version for your locale pack, `i18n.js`, and player script.
|
|
|
208
208
|
**my-locale.js**
|
|
209
209
|
|
|
210
210
|
```js
|
|
211
|
-
import 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
212
|
-
import { registerI18n } from 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
211
|
+
import 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/locales/es.js';
|
|
212
|
+
import { registerI18n } from 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/i18n.js';
|
|
213
213
|
|
|
214
214
|
registerI18n('es', { buttons: { play: 'Reproducir', pause: 'Pausa' } });
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
```html
|
|
218
218
|
<script type="module" src="/my-locale.js"></script>
|
|
219
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
219
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
### Switch locale at runtime
|
|
@@ -16,7 +16,7 @@ pnpm add @videojs/html @videojs/hlsjs-video
|
|
|
16
16
|
|
|
17
17
|
## Recommended approach
|
|
18
18
|
|
|
19
|
-
Use the live feature bundle with a streaming media
|
|
19
|
+
Use the live feature bundle with a streaming media component, and give users a `<media-live-button>`: it shows whether playback is at the live edge and seeks back to it when activated.
|
|
20
20
|
|
|
21
21
|
```html
|
|
22
22
|
<live-video-player>
|
|
@@ -119,7 +119,7 @@ Render live or on-demand controls from `streamType` when one player handles both
|
|
|
119
119
|
|
|
120
120
|
### The live badge never activates
|
|
121
121
|
|
|
122
|
-
`<media-live-button>` reads `targetLiveWindow`, `currentTime`, and `seekable`. Confirm that `targetLiveWindow` is `0` or `Infinity` and that `seekable` has a finite end. Use a live-capable media
|
|
122
|
+
`<media-live-button>` reads `targetLiveWindow`, `currentTime`, and `seekable`. Confirm that `targetLiveWindow` is `0` or `Infinity` and that `seekable` has a finite end. Use a live-capable media component such as [`<hlsjs-video>`](../reference/components/hlsjs-video.md). The live button does not need `streamTypeFeature`; add it only when your own UI reads `streamType`.
|
|
123
123
|
|
|
124
124
|
### Playback keeps falling behind the edge
|
|
125
125
|
|
|
@@ -145,4 +145,4 @@ Compare the slider’s range with `seekable`. The built-in slider always starts
|
|
|
145
145
|
|
|
146
146
|
### Guides
|
|
147
147
|
|
|
148
|
-
- [Media sources](./media-sources.md): Set what a media
|
|
148
|
+
- [Media sources](./media-sources.md): Set what a media component plays and how its engine plays it with the structured source property
|
package/docs/guides/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Video.js v10 — HTML Guides
|
|
2
2
|
|
|
3
|
-
> Installation, migration, concepts, playback guides, customization, and tooling for Video.js. Bundled with `@videojs/html` v10.0.
|
|
3
|
+
> Installation, migration, concepts, playback guides, customization, and tooling for Video.js. Bundled with `@videojs/html` v10.0.1. Links are relative paths to files in this directory.
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -43,10 +43,10 @@ Understanding-oriented pages that explain how and why things work. Read these to
|
|
|
43
43
|
|
|
44
44
|
- [Features](./features.md): The state and actions each feature adds to the player
|
|
45
45
|
- [Skins](./skins.md): Packaged player designs that include both UI components and their styles.
|
|
46
|
-
- [Presets](./presets.md): Pre-packaged player configurations that bundle state management, skins, and media
|
|
46
|
+
- [Presets](./presets.md): Pre-packaged player configurations that bundle state management, skins, and media components for specific use cases.
|
|
47
47
|
- [UI components](./ui-components.md): How Video.js UI components use focused elements, data attributes for state, and compound composition.
|
|
48
48
|
- [Accessibility](./accessibility.md): How Video.js approaches accessibility, and what you should consider if you're deeply customizing your player
|
|
49
|
-
- [Media sources](./media-sources.md): Set what a media
|
|
49
|
+
- [Media sources](./media-sources.md): Set what a media component plays and how its engine plays it with the structured source property
|
|
50
50
|
|
|
51
51
|
## Playback
|
|
52
52
|
|
|
@@ -73,6 +73,7 @@ Guides for one player capability each: the recommended setup, how it works, brow
|
|
|
73
73
|
|
|
74
74
|
Guides for moving an existing player integration to Video.js v10, one per player you might be coming from.
|
|
75
75
|
|
|
76
|
+
- [Migrate to Video.js v10](./migrate.md): Understand how Video.js v10 differs from the players it brings together, and choose the migration guide for the player you use today.
|
|
76
77
|
- [Migrate from Video.js 8](./migrate-from-video-js-8.md): Move a Video.js 8 integration to v10, mapping the options object, techs, plugins, and player API onto composed components
|
|
77
78
|
- [Migrate from Mux Player](./migrate-from-mux-player.md): Move a Mux Player embed to Video.js v10 using a player, media component, skin, and analytics extension
|
|
78
79
|
- [Migrate from Plyr](./migrate-from-plyr.md): Move an existing Plyr integration to Video.js v10, mapping Plyr options and its instance API onto components and player state
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Media sources
|
|
2
2
|
|
|
3
|
-
Set what a media
|
|
3
|
+
Set what a media component plays and how its engine plays it with the structured source property
|
|
4
4
|
|
|
5
|
-
Every media
|
|
5
|
+
Every media component takes a `src`. Elements that drive a playback engine also take `source`, a structured object that carries the URL alongside everything else about that source:
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
8
|
const video = document.querySelector('hlsjs-video');
|
|
@@ -46,14 +46,14 @@ Before loading Video.js HTML, remove every Media Chrome import and CDN script fr
|
|
|
46
46
|
For a page without a bundler, load the CDN video preset. It registers the player, the UI elements and icons used in the controller example below, and the `<media-i18n>` element:
|
|
47
47
|
|
|
48
48
|
```html
|
|
49
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
49
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Some elements in the mapping table below need separate bundles. If you use any of these elements, also load its bundle:
|
|
53
53
|
|
|
54
|
-
- `media-seek-button`: `https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
55
|
-
- `media-playback-rate-button`: `https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
56
|
-
- `media-thumbnail`: `https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
54
|
+
- `media-seek-button`: `https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/ui/seek-button.js`
|
|
55
|
+
- `media-playback-rate-button`: `https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/ui/playback-rate-button.js`
|
|
56
|
+
- `media-thumbnail`: `https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/ui/thumbnail.js`
|
|
57
57
|
|
|
58
58
|
Load each with `<script type="module" src="…"></script>`. See [CDN](./cdn.md) for individual component bundles.
|
|
59
59
|
|
|
@@ -43,7 +43,7 @@ Make a migration checklist before changing your embed:
|
|
|
43
43
|
|
|
44
44
|
- **List the Mux Player attributes or React props you set.** Compare them with the mapping tables below.
|
|
45
45
|
- **Grep your codebase for `mux-player` selectors.** After the swap, CSS rules and `querySelector` calls that reach into the element stop matching, with no error. Look for patterns such as `mux-player::part(…)`, `mux-player [role="slider"]`, and `player.shadowRoot`. Restyle the UI with the skin’s custom properties or rebuild it with Video.js components.
|
|
46
|
-
- **Find your event listeners and imperative calls** (`play()`, `currentTime`, `addChapters`). Media APIs move to the media
|
|
46
|
+
- **Find your event listeners and imperative calls** (`play()`, `currentTime`, `addChapters`). Media APIs move to the media component; the rest is mapped under [Drive playback](#drive-playback).
|
|
47
47
|
- **Note your theme and CSS variables.** Compare your Mux Player theme with the two Video.js skins, and map its CSS variables.
|
|
48
48
|
- **Check [Known gaps](#known-gaps)** for features your app needs.
|
|
49
49
|
- **Check your catalog for MPEG-TS, raw ADTS AAC, AES-128, low-latency HLS, or DVR streams.** Check whether the SPF engine supports these requirements. If you use DRM, verify playback with whichever engine you choose. See [Which Mux media should you use?](#which-mux-media-should-you-use).
|
|
@@ -68,9 +68,9 @@ The examples keep a playback ID, analytics metadata, and a poster from two secon
|
|
|
68
68
|
From the CDN, load the video [preset](./presets.md), the Mux media, and analytics:
|
|
69
69
|
|
|
70
70
|
```html
|
|
71
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
72
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
73
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
71
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/video.js"></script>
|
|
72
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/media/mux-video.js"></script>
|
|
73
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/extensions/mux-data.js"></script>
|
|
74
74
|
|
|
75
75
|
<video-player content-title="Test VOD">
|
|
76
76
|
<video-skin style="aspect-ratio: 16 / 9">
|
|
@@ -421,8 +421,8 @@ Mux Player switches to live controls automatically. In Video.js, choose the live
|
|
|
421
421
|
Register the live preset and Mux media. From the CDN:
|
|
422
422
|
|
|
423
423
|
```html
|
|
424
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
425
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
424
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/live-video.js"></script>
|
|
425
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/media/mux-video.js"></script>
|
|
426
426
|
|
|
427
427
|
<live-video-player>
|
|
428
428
|
<live-video-skin>
|
|
@@ -452,7 +452,7 @@ Use [`createPlayer`](../reference/api/html-create-player.md) to build a player e
|
|
|
452
452
|
The live skin already includes a live button. If you build your own controls, use that same component and style it to match your app. It keeps track of whether playback is live and returns viewers to the newest available point in the stream.
|
|
453
453
|
|
|
454
454
|
```html
|
|
455
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.
|
|
455
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/ui/live-button.js"></script>
|
|
456
456
|
|
|
457
457
|
<media-live-button class="station-live-button">On air</media-live-button>
|
|
458
458
|
```
|