@videojs/html 10.0.0-rc.5 → 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/README.md +0 -2
- 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-video/compat-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/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 -6
- package/docs/guides/installation-shadcn.md +4 -8
- package/docs/guides/installation-svelte.md +2 -6
- package/docs/guides/installation-vue.md +2 -6
- package/docs/guides/installation.md +2 -6
- package/docs/guides/internationalization.md +5 -5
- package/docs/guides/live-streams.md +3 -3
- package/docs/guides/llms.txt +5 -4
- 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/guides/v10-roadmap.md +19 -54
- package/docs/llms.txt +5 -4
- 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.
|
|
@@ -4,10 +4,6 @@ Load Video.js from jsDelivr and build an HTML video player without installing Vi
|
|
|
4
4
|
|
|
5
5
|
Video.js can run directly from browser-ready files on jsDelivr. This HTML-only path does not install Video.js packages: choose a player, load its scripts, and add the generated custom-element markup to your page.
|
|
6
6
|
|
|
7
|
-
> **Note: Release Candidate**
|
|
8
|
-
>
|
|
9
|
-
> Video.js v10 is a *release candidate*. We feel the API is stable and ready to build with. With your [feedback](https://github.com/videojs/v10/issues), a few documentation updates, and any final fixes, we look forward to shipping 10.0.0 soon. [Read the Release Candidate blog post](https://videojs.org/blog/videojs-v10-release-candidate).
|
|
10
|
-
|
|
11
7
|
> **Tip: Coming from another player?**
|
|
12
8
|
>
|
|
13
9
|
> Follow the migration guide for [Video.js 8](./migrate-from-video-js-8.md), [Mux Player](./migrate-from-mux-player.md), [Plyr](./migrate-from-plyr.md), [Media Chrome](./migrate-from-media-chrome.md), or [Vidstack](./migrate-from-vidstack.md). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
|
|
@@ -93,7 +89,7 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
93
89
|
## Reproduce or change these instructions
|
|
94
90
|
|
|
95
91
|
```sh
|
|
96
|
-
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
|
|
97
93
|
```
|
|
98
94
|
|
|
99
95
|
## Load Video.js
|
|
@@ -105,7 +101,7 @@ Add these module scripts to the page head. Module scripts are deferred, so they
|
|
|
105
101
|
_Merge this into the page `<head>`._
|
|
106
102
|
|
|
107
103
|
```html
|
|
108
|
-
<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>
|
|
109
105
|
```
|
|
110
106
|
|
|
111
107
|
## Add your player
|
|
@@ -4,10 +4,6 @@ Add editable React or HTML skin source with the Shadcn registry
|
|
|
4
4
|
|
|
5
5
|
Use Shadcn to add a Video.js skin's components, layout, styles, and interactions as React or HTML custom-element source. The CLI copies the files into your app so you can review and change them like any other source code.
|
|
6
6
|
|
|
7
|
-
> **Note: Release Candidate**
|
|
8
|
-
>
|
|
9
|
-
> Video.js v10 is a *release candidate*. We feel the API is stable and ready to build with. With your [feedback](https://github.com/videojs/v10/issues), a few documentation updates, and any final fixes, we look forward to shipping 10.0.0 soon. [Read the Release Candidate blog post](https://videojs.org/blog/videojs-v10-release-candidate).
|
|
10
|
-
|
|
11
7
|
> **Tip: Coming from another player?**
|
|
12
8
|
>
|
|
13
9
|
> Follow the HTML migration guide for [Video.js 8](./migrate-from-video-js-8.md), [Mux Player](./migrate-from-mux-player.md), [Plyr](./migrate-from-plyr.md), [Media Chrome](./migrate-from-media-chrome.md), or [Vidstack](./migrate-from-vidstack.md). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
|
|
@@ -98,7 +94,7 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
98
94
|
## Reproduce or change these instructions
|
|
99
95
|
|
|
100
96
|
```sh
|
|
101
|
-
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
|
|
102
98
|
```
|
|
103
99
|
|
|
104
100
|
## Configure app aliases
|
|
@@ -218,7 +214,7 @@ pnpm dlx shadcn@latest registry add @videojs=https://shadcn.videojs.org/r/html/{
|
|
|
218
214
|
|
|
219
215
|
## Add the skin source
|
|
220
216
|
|
|
221
|
-
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.
|
|
222
218
|
|
|
223
219
|
```bash
|
|
224
220
|
pnpm dlx shadcn@latest add @videojs/video --overwrite --yes
|
|
@@ -226,11 +222,11 @@ pnpm dlx shadcn@latest add @videojs/video --overwrite --yes
|
|
|
226
222
|
|
|
227
223
|
## Add your player
|
|
228
224
|
|
|
229
|
-
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.
|
|
230
226
|
|
|
231
227
|
### `src/components/videojs/video/skin.html`
|
|
232
228
|
|
|
233
|
-
_Replace `<!-- Add a compatible media
|
|
229
|
+
_Replace `<!-- Add a compatible media component here. -->` with this block._
|
|
234
230
|
|
|
235
231
|
```html
|
|
236
232
|
<video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" playsinline></video>
|
|
@@ -4,10 +4,6 @@ Install Video.js in Svelte or SvelteKit and build a video player with HTML custo
|
|
|
4
4
|
|
|
5
5
|
Svelte apps built with Vite, Astro, or SvelteKit use Video.js HTML custom elements directly in their markup. These lightweight, framework-free components build accessible, customizable players with small bundles, advanced features, and consistent behavior across browsers.
|
|
6
6
|
|
|
7
|
-
> **Note: Release Candidate**
|
|
8
|
-
>
|
|
9
|
-
> Video.js v10 is a *release candidate*. We feel the API is stable and ready to build with. With your [feedback](https://github.com/videojs/v10/issues), a few documentation updates, and any final fixes, we look forward to shipping 10.0.0 soon. [Read the Release Candidate blog post](https://videojs.org/blog/videojs-v10-release-candidate).
|
|
10
|
-
|
|
11
7
|
> **Tip: Coming from another player?**
|
|
12
8
|
>
|
|
13
9
|
> Follow the migration guide for [Video.js 8](./migrate-from-video-js-8.md), [Mux Player](./migrate-from-mux-player.md), [Plyr](./migrate-from-plyr.md), [Media Chrome](./migrate-from-media-chrome.md), or [Vidstack](./migrate-from-vidstack.md). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
|
|
@@ -94,13 +90,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
94
90
|
## Reproduce or change these instructions
|
|
95
91
|
|
|
96
92
|
```sh
|
|
97
|
-
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
|
|
98
94
|
```
|
|
99
95
|
|
|
100
96
|
## Install the packages
|
|
101
97
|
|
|
102
98
|
```bash
|
|
103
|
-
pnpm add @videojs/html@10.0.
|
|
99
|
+
pnpm add @videojs/html@10.0.1
|
|
104
100
|
```
|
|
105
101
|
|
|
106
102
|
## Add your player
|
|
@@ -4,10 +4,6 @@ Install Video.js in Vue or Nuxt and build a video player with HTML custom elemen
|
|
|
4
4
|
|
|
5
5
|
Vue apps built with Vite, Astro, or Nuxt use Video.js HTML custom elements directly in their templates. These lightweight, framework-free components build accessible, customizable players with small bundles, advanced features, and consistent behavior across browsers.
|
|
6
6
|
|
|
7
|
-
> **Note: Release Candidate**
|
|
8
|
-
>
|
|
9
|
-
> Video.js v10 is a *release candidate*. We feel the API is stable and ready to build with. With your [feedback](https://github.com/videojs/v10/issues), a few documentation updates, and any final fixes, we look forward to shipping 10.0.0 soon. [Read the Release Candidate blog post](https://videojs.org/blog/videojs-v10-release-candidate).
|
|
10
|
-
|
|
11
7
|
> **Tip: Coming from another player?**
|
|
12
8
|
>
|
|
13
9
|
> Follow the migration guide for [Video.js 8](./migrate-from-video-js-8.md), [Mux Player](./migrate-from-mux-player.md), [Plyr](./migrate-from-plyr.md), [Media Chrome](./migrate-from-media-chrome.md), or [Vidstack](./migrate-from-vidstack.md). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
|
|
@@ -94,13 +90,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
94
90
|
## Reproduce or change these instructions
|
|
95
91
|
|
|
96
92
|
```sh
|
|
97
|
-
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
|
|
98
94
|
```
|
|
99
95
|
|
|
100
96
|
## Install the packages
|
|
101
97
|
|
|
102
98
|
```bash
|
|
103
|
-
pnpm add @videojs/html@10.0.
|
|
99
|
+
pnpm add @videojs/html@10.0.1
|
|
104
100
|
```
|
|
105
101
|
|
|
106
102
|
## Register custom elements
|
|
@@ -4,10 +4,6 @@ Install Video.js with HTML custom elements and build an accessible, customizable
|
|
|
4
4
|
|
|
5
5
|
Video.js is an **HTML video player built on custom elements**: lightweight, framework-free components for building accessible, customizable players with minimal bundle sizes, advanced features, and consistency across browsers.
|
|
6
6
|
|
|
7
|
-
> **Note: Release Candidate**
|
|
8
|
-
>
|
|
9
|
-
> Video.js v10 is a *release candidate*. We feel the API is stable and ready to build with. With your [feedback](https://github.com/videojs/v10/issues), a few documentation updates, and any final fixes, we look forward to shipping 10.0.0 soon. [Read the Release Candidate blog post](https://videojs.org/blog/videojs-v10-release-candidate).
|
|
10
|
-
|
|
11
7
|
> **Tip: Coming from another player?**
|
|
12
8
|
>
|
|
13
9
|
> Follow the migration guide for [Video.js 8](./migrate-from-video-js-8.md), [Mux Player](./migrate-from-mux-player.md), [Plyr](./migrate-from-plyr.md), [Media Chrome](./migrate-from-media-chrome.md), or [Vidstack](./migrate-from-vidstack.md). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
|
|
@@ -96,13 +92,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
96
92
|
## Reproduce or change these instructions
|
|
97
93
|
|
|
98
94
|
```sh
|
|
99
|
-
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
|
|
100
96
|
```
|
|
101
97
|
|
|
102
98
|
## Install the packages
|
|
103
99
|
|
|
104
100
|
```bash
|
|
105
|
-
pnpm add @videojs/html@10.0.
|
|
101
|
+
pnpm add @videojs/html@10.0.1
|
|
106
102
|
```
|
|
107
103
|
|
|
108
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
|
|
|
@@ -17,7 +17,7 @@ Install Video.js, customize a skin, understand its main pieces, check browser an
|
|
|
17
17
|
- [Why Video.js?](./why-videojs.md): The open-source video player for React and HTML. Lightweight, accessible components built for performance and streaming.
|
|
18
18
|
- [Browser support](./browser-support.md): Browsers and rendering environments supported by Video.js 10, and how the packaged skins reach them
|
|
19
19
|
- [Build with AI](./build-with-ai.md): Install the Video.js skill and give AI coding agents version-matched docs for building and migrating players
|
|
20
|
-
- [v10 Roadmap](./v10-roadmap.md):
|
|
20
|
+
- [v10 Roadmap](./v10-roadmap.md): Where Video.js v10 stands, what comes after 10.0, and the support plan for Video.js 8
|
|
21
21
|
- [Contribute to Video.js](https://github.com/videojs/v10/blob/main/CONTRIBUTING.md)
|
|
22
22
|
|
|
23
23
|
## Frameworks
|
|
@@ -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');
|