Skip to content

Commit 4a1e036

Browse files
authored
fix(vidstack): reapply caption styles on remount (#1817)
1 parent 77b740f commit 4a1e036

2 files changed

Lines changed: 64 additions & 7 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { vi } from 'vitest';
2+
3+
let player: { el: HTMLElement };
4+
5+
describe('font vars', function () {
6+
beforeEach(function () {
7+
vi.resetModules();
8+
vi.doMock('../api/media-context', () => ({
9+
useMediaContext: () => ({ player }),
10+
}));
11+
12+
localStorage.clear();
13+
});
14+
15+
afterEach(function () {
16+
vi.doUnmock('../api/media-context');
17+
});
18+
19+
it('applies stored font vars to players added after the watcher is initialized', async function () {
20+
localStorage.setItem('vds-player:font-family', 'capitals');
21+
localStorage.setItem('vds-player:text-bg', '#ff0000');
22+
localStorage.setItem('vds-player:text-bg-opacity', '50%');
23+
24+
const [{ createScope, scoped }, { updateFontCssVars }] = await Promise.all([
25+
import('maverick.js'),
26+
import('./font-vars'),
27+
]);
28+
29+
player = { el: document.createElement('media-player') };
30+
scoped(() => updateFontCssVars(), createScope());
31+
32+
player = { el: document.createElement('media-player') };
33+
scoped(() => updateFontCssVars(), createScope());
34+
35+
expect(player.el.style.getPropertyValue('--media-user-text-bg').replace(/\s+/g, ' ')).to.equal(
36+
'rgb(255 0 0 / var(--media-user-text-bg-opacity, 1))',
37+
);
38+
expect(player.el.style.getPropertyValue('--media-user-text-bg-opacity')).to.equal('0.5');
39+
expect(player.el.style.getPropertyValue('--media-user-font-variant')).to.equal('small-caps');
40+
});
41+
});

packages/vidstack/src/core/font/font-vars.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,22 @@ export function updateFontCssVars() {
1414

1515
const { player } = useMediaContext();
1616
players.add(player);
17+
applyFontCssVars(player);
1718
onDispose(() => players.delete(player));
1819

1920
if (!isWatchingVars) {
2021
scoped(() => {
2122
for (const type of keysOf(FONT_SIGNALS)) {
2223
const $value = FONT_SIGNALS[type],
2324
defaultValue = FONT_DEFAULTS[type],
24-
varName = `--media-user-${camelToKebabCase(type)}`,
2525
storageKey = `vds-player:${camelToKebabCase(type)}`;
2626

2727
effect(() => {
2828
const value = $value(),
29-
isDefaultVarValue = value === defaultValue,
30-
varValue = !isDefaultVarValue ? getCssVarValue(player, type, value) : null;
29+
isDefaultVarValue = value === defaultValue;
3130

3231
for (const player of players) {
33-
player.el?.style.setProperty(varName, varValue);
32+
setFontCssVar(player, type, value);
3433
}
3534

3635
if (isDefaultVarValue) {
@@ -46,11 +45,28 @@ export function updateFontCssVars() {
4645
}
4746
}
4847

49-
function getCssVarValue(player: MediaPlayer, type: FontSignal, value: string) {
48+
function applyFontCssVars(player: MediaPlayer) {
49+
for (const type of keysOf(FONT_SIGNALS)) {
50+
setFontCssVar(player, type, FONT_SIGNALS[type]());
51+
}
52+
}
53+
54+
function setFontCssVar(player: MediaPlayer, type: FontSignal, value: string) {
55+
const defaultValue = FONT_DEFAULTS[type],
56+
varName = `--media-user-${camelToKebabCase(type)}`,
57+
varValue = value !== defaultValue ? getCssVarValue(type, value) : null;
58+
59+
if (type === 'fontFamily') {
60+
const fontVariant = value === 'capitals' ? 'small-caps' : null;
61+
player.el?.style.setProperty('--media-user-font-variant', fontVariant);
62+
}
63+
64+
player.el?.style.setProperty(varName, varValue);
65+
}
66+
67+
function getCssVarValue(type: FontSignal, value: string) {
5068
switch (type) {
5169
case 'fontFamily':
52-
const fontVariant = value === 'capitals' ? 'small-caps' : '';
53-
player.el?.style.setProperty('--media-user-font-variant', fontVariant);
5470
return getFontFamilyCSSVarValue(value);
5571
case 'fontSize':
5672
case 'textOpacity':

0 commit comments

Comments
 (0)