Skip to content

Commit 6a06296

Browse files
authored
fix(vidstack): handle zero-offset thumbnail sprites (#1825)
1 parent 923e7c7 commit 6a06296

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { createComponent, provideContext, root, tick } from 'maverick.js';
2+
3+
import { mediaContext } from '../../../core/api/media-context';
4+
import { mediaState } from '../../../core/api/player-state';
5+
import { Thumbnail } from './thumbnail';
6+
import type { ThumbnailImageInit } from './thumbnail-loader';
7+
8+
function setupThumbnail(src: ThumbnailImageInit[], time: number) {
9+
let dispose!: () => void;
10+
11+
const $state = mediaState.create();
12+
$state.canLoad.set(true);
13+
$state.providedDuration.set(120);
14+
15+
const rootEl = document.createElement('div'),
16+
img = document.createElement('img');
17+
18+
Object.defineProperties(img, {
19+
naturalWidth: { value: 1800 },
20+
naturalHeight: { value: 1012.5 },
21+
});
22+
23+
const thumbnail = root((stop) => {
24+
dispose = stop;
25+
provideContext(mediaContext, { $state } as any);
26+
27+
const instance = createComponent(Thumbnail, {
28+
props: { src, time },
29+
}) as any;
30+
31+
instance.$$.setup();
32+
instance.$state.img.set(img);
33+
instance.$$.attach(rootEl);
34+
instance.$$.connect();
35+
36+
return instance;
37+
}) as any;
38+
39+
tick();
40+
img.dispatchEvent(new Event('load'));
41+
tick();
42+
43+
return {
44+
dispose,
45+
img,
46+
rootEl,
47+
thumbnail,
48+
};
49+
}
50+
51+
describe(Thumbnail.name, function () {
52+
it('keeps crop styles when switching to a later sprite at a zero offset', function () {
53+
const thumbnails: ThumbnailImageInit[] = [
54+
{
55+
url: 'https://cdn.example.com/seek/_0.jpg',
56+
startTime: 68.497,
57+
width: 300,
58+
height: 168.75,
59+
coords: { x: 1500, y: 843.75 },
60+
},
61+
{
62+
url: 'https://cdn.example.com/seek/_1.jpg',
63+
startTime: 70.454,
64+
width: 300,
65+
height: 168.75,
66+
coords: { x: 0, y: 0 },
67+
},
68+
];
69+
70+
const { dispose, img, rootEl, thumbnail } = setupThumbnail(thumbnails, 68.497);
71+
72+
try {
73+
expect(thumbnail.$state.src()).to.equal('https://cdn.example.com/seek/_0.jpg');
74+
expect(img.style.transform).to.equal('translate(-1500px, -843.75px)');
75+
76+
thumbnail.$props.time.set(70.454);
77+
tick();
78+
79+
expect(thumbnail.$state.src()).to.equal('https://cdn.example.com/seek/_1.jpg');
80+
expect(thumbnail.$state.activeThumbnail()?.coords).to.deep.equal({ x: 0, y: 0 });
81+
expect(rootEl.style.getPropertyValue('--thumbnail-width')).to.equal('300px');
82+
expect(rootEl.style.getPropertyValue('--thumbnail-height')).to.equal('168.75px');
83+
expect(img.style.transform).to.equal('translate(-0px, -0px)');
84+
} finally {
85+
dispose();
86+
}
87+
});
88+
});

packages/vidstack/src/components/ui/thumbnails/thumbnail.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ export class Thumbnail extends Component<ThumbnailProps, ThumbnailState> {
149149
activeImage = images[activeIndex];
150150
}
151151

152-
activeThumbnail.set(activeImage);
153152
src.set(activeImage?.url.href || '');
153+
activeThumbnail.set(activeImage);
154154
}
155155

156156
#resize() {

0 commit comments

Comments
 (0)