Repository navigation
Release 2.6.0: pause button, reduced motion, lazy loading, HLS and style.css - #49
Merged
Merged
Conversation
A component of an earlier test kept its listeners on window and document, so it reacted to the events of the next test. The helpers add fakes for IntersectionObserver, matchMedia and the page visibility, which jsdom does not have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
Before, the element was only reachable through the internal player.$refs.video. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
You pass the Hls class of hls.js with the new hls prop, and hlsConfig for its options. If the browser supports hls.js, hls.js plays .m3u8 sources. Otherwise the browser plays them itself, as before. The package does not import hls.js, so the bundle stays without it. hls.js removes all <source> elements when it detaches. The component renders its <source> again only after hls.js stopped. A fatal hls.js error keeps the poster and emits error with a CustomEvent, whose detail holds the error data of hls.js. hls.js is a dev dependency for the type tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
All four options are off by default, so the component behaves as before. - pauseButton renders a native button before the content, first in the tab order (WCAG 2.2.2 Pause, Stop, Hide). Its label changes between pauseLabel and playLabel, and the pause-button slot replaces the icon. A pause with the button stays when the window switches to another source. - respectReducedMotion shows only the poster when the user prefers reduced motion, and the video does not load. The play button or play() loads and plays it. A change of the setting pauses a playing video. - pauseWhenHidden pauses the video while it is off screen or the page is in the background, and plays it again when it is visible. A video that the user paused stays paused. - lazy loads the video when the section comes within 200px of the viewport. play() on a video that waits loads it first. Its promise resolves when the video plays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
With keepLargerSource, a smaller window keeps a video that already loads, so the browser does not download the smaller one too. A larger window still switches to the larger video. Off by default. The new tests also cover a source with an empty src: the component loads no video for that window width and shows only the poster. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The build also writes the CSS of the component to dist/style.css, and the package exports it as vue-responsive-video-background-player/style.css. With server-side rendering, the page can link it, so the server HTML has its styles before the JavaScript runs. With a strict Content Security Policy that blocks injected <style> elements, the styles still apply. The JavaScript still injects the CSS, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The styles of the button are inside :where(), so they have no specificity. A plain .videobg-pause-button rule in your CSS now wins, whatever the order of the style sheets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The README gets sections for the pause button and accessibility, for less loading and less work, for HLS streams with hls.js, for the CSS file and for the slots. The Nuxt section shows the CSS file in nuxt.config.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The browser test showed a square button on the demo page: Bootstrap 4
sets button { border-radius: 0 }, and that rule beat the :where()
rules, which have no specificity. Tailwind also sets the background of
[type='button'] to transparent. The styles of the button now use
button.videobg-pause-button in a style block without scope. That beats
the resets, and a selector with two classes still overrides it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The hero gets the pause button, respectReducedMotion, pauseWhenHidden and keepLargerSource, and posters for the desktop and tablet videos. Without a poster, reduced motion showed an empty section. A second section below plays an HLS stream (1 MB, encoded with ffmpeg from accessories-hero-desktop.mp4) with hls.js and lazy loading, and lists its events. The demo loads hls.js 1.7.3 from jsDelivr, so the demo bundle stays without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
TypeScript 6 and 7 check side-effect imports by default, so import 'vue-responsive-video-background-player/style.css' failed with TS2882 in a project without its own *.css declaration. The build now writes dist/style.css.d.ts, and the export points to it with the types condition. Bundlers and Node.js still get dist/style.css. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
An independent review by Codex (gpt-6-astra, high) found seven problems. - pause() and stop() before the video was ready did not stick: autoplay started the video when it was ready, also after play() on a lazy video. play(), pause() and stop() now tell the background what you want, for the current video. After a switch to another source, the autoplay of that source decides again, as before. The pause button keeps its choice across switches. The background itself uses the new internal startVideo() and pauseVideo(). - After a fatal hls.js error or a video that failed to load, the play button showed "pause" and did nothing. play() and the button now load the video again. - A play() that waited for the video stayed pending when the window switched to a source with only a poster, or to another video. It resolves now. - A fatal hls.js error inside loadSource() got lost, because the instance was not active yet. The instance is active before loadSource() now. - play() of the player did not count as the choice of the user, so turning on reduced motion paused a video that play() started. - Back from a poster-only source within one second, hls.js started twice. The pending load() now handles the new source. - Turning lazy off did not load the video. The tests for all seven fail on the code before this commit. The fake of hls.js now removes the <source> elements like hls.js with ManagedMediaSource, and a reduced motion test flushes between changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
A short review by Codex (gpt-6-astra, medium) of the previous fixes found four minor problems. - The old play() of a failed stream ended the wait of a newer play() too early, when the new load interrupted it. Only the current play request ends the wait now. - reloadAfterFailure() left a pending load() active, so hls.js started twice. It cancels the pending load() now, and hides the video. - A choice through the player stayed when the window switched to another video while lazy loading still held the source back. The choice now follows the selected source, not the loaded one. - The test for play() before readiness passed also without the fix, because the media mock resolved play() at once. It now models a pending play() that the pause at readiness interrupts. The new tests fail on the code before this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The second short review by Codex (gpt-6-astra, medium) found a major problem in the guard from the previous commit: when the browser blocked playback, the catch branch hid the video, which made its own play request obsolete. Then the guard never ended the wait, and a play() on a lazy or reduced-motion video stayed pending forever. This was the last review round, so the guard goes back to the line that the first short review checked. The small problem that the guard fixed is open again: the old play() of a failed stream can end the wait of a newer play() too early. Its test is now it.fails. New tests check that a waiting play() resolves when the browser blocks playback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
jsdom 30 needs Node.js ^22.22.2, ^24.15.0 or >=26. .nvmrc names 24.21.0, and CI tests Node.js 22, 24 and 26. The release workflow already uses the newest Node.js 24. The published files do not change. TypeScript stays on 5.9 for the development tools. vue-tsc 3.3.12, the newest version, stops with ERR_PACKAGE_PATH_NOT_EXPORTED for typescript/lib/tsc, because TypeScript 7 no longer ships the JavaScript API of the compiler. The type tests of this repository pass with TypeScript 7, and the types of the package are tested with TypeScript 5.9, 6.0 and 7.0. ESLint stays on 9 until eslint-config-avidofood 5 supports ESLint 10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
The old play() of a failed stream ended the wait of a newer play() too early: the new load interrupted the old play() of the browser, and its promise chain resolved all waiting plays. Now only the current play request ends the wait. The first try of this guard in 661e39d also left the wait open when the browser blocked playback, because hide() in the catch branch made the request obsolete. Now the catch branch ends the wait before hide(). The test of the open problem is it() again, and the two tests for a blocked play() stay green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
eslint-config-avidofood 5 needs ESLint 10 and uses eslint-plugin-import-x. The rule names stay import/..., and eslint.config.mjs does not change. The lint result is the same as before: no errors and no warnings in 27 files, with the same 342 active rules. ESLint 10 needs Node.js ^20.19, ^22.13 or >=24, which the development tools already need for jsdom 30. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Feature release 2.6.0. All new options are off by default. Without them, the component works as in 2.5.1.
Related issues: #44 (HLS), #14 (keep the larger video), #30 (video element), #3 (play and pause). Please close them after the release, not with this merge.
New options
pauseButton,pauseLabel,playLabel, slotpause-buttonaria-pressed. A pause with the button stays across source switches and acrosspauseWhenHidden.respectReducedMotionplayer.play()starts it. A live change of the setting pauses a playing video.pauseWhenHiddenplay(). A video that the user paused stays paused.lazykeepLargerSourcehls,hlsConfigHlsclass of hls.js (#44). Where hls.js is supported, it plays.m3u8sources. Elsewhere, the browser plays them, as before. The package never imports hls.js.player.video<video>element (#30).vue-responsive-video-background-player/style.cssplay()on a video that waits (lazy, reduced motion) or that failed loads it first. The play button also loads a failed video again.Fixed
pause()andstop()before the video is ready keep it paused. Before, autoplay started it at readiness.play()before the video is ready plays it at readiness, also withautoplayset to false. Before, the video stayed paused.Development tools
.nvmrcnames 24.21.0. CI tests Node.js 22, 24 and 26.ERR_PACKAGE_PATH_NOT_EXPORTEDfortypescript/lib/tsc, because TypeScript 7 no longer ships the JavaScript API of the compiler. The types of the package are tested with TypeScript 5.9, 6.0 and 7.0.Checks
dist/imports onlyvue, without?.,??orprocess. ESM 19.3 kB (gzip 5.7 kB, before 3.4 kB).style.css, and a client mount in jsdom.@arethetypeswrong/cli: no problems for the main entry.publint: no errors and no warnings.keepLargerSourcelazywith real hls.js over MSE, including the loopstyle.css, hydrationReview
An independent review by Codex (gpt-6-astra) checked the work before this pull request:
play().Demo
The hero shows the pause button, reduced motion,
pauseWhenHiddenandkeepLargerSource. A second section plays an HLS stream with hls.js from jsDelivr. The stream has 1 MB, and ffmpeg encoded it from an existing demo video. The section loads it only near the viewport.Release after the merge
release.yml, environmentnpm-publish).2.6.0onmasterand push the tag. The Release workflow publishes.🤖 Generated with Claude Code
https://claude.ai/code/session_017WCUweANBn9U6qXMZNf9w4