fix(core): derive effective mute state for volume UI components (#753)

This commit is contained in:
rahim
2026-03-05 23:10:25 -08:00
committed by GitHub
parent dce16ae5fd
commit 14bcdc833f
6 changed files with 43 additions and 29 deletions
@@ -114,25 +114,27 @@ describe('volumeFeature', () => {
});
describe('toggleMuted', () => {
it('toggles mute from false to true', async () => {
const video = createMockVideo({ muted: false });
it('mutes when unmuted with volume > 0', async () => {
const video = createMockVideo({ muted: false, volume: 0.8 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
const result = await store.toggleMuted();
expect(video.muted).toBe(true);
expect(video.volume).toBe(0.8);
expect(result).toBe(true);
});
it('toggles mute from true to false', async () => {
const video = createMockVideo({ muted: true });
it('unmutes when muted with volume > 0', async () => {
const video = createMockVideo({ muted: true, volume: 0.6 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
const result = await store.toggleMuted();
expect(video.muted).toBe(false);
expect(video.volume).toBe(0.6);
expect(result).toBe(false);
});
@@ -147,26 +149,16 @@ describe('volumeFeature', () => {
expect(video.volume).toBe(0.25);
});
it('preserves volume when unmuting with volume > 0', async () => {
const video = createMockVideo({ muted: true, volume: 0.6 });
it('unmutes and restores volume when volume is 0 and not muted', async () => {
const video = createMockVideo({ muted: false, volume: 0 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.toggleMuted();
const result = await store.toggleMuted();
expect(video.muted).toBe(false);
expect(video.volume).toBe(0.6);
});
it('does not change volume when muting', async () => {
const video = createMockVideo({ muted: false, volume: 0.8 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.toggleMuted();
expect(video.muted).toBe(true);
expect(video.volume).toBe(0.8);
expect(video.volume).toBe(0.25);
expect(result).toBe(false);
});
});
});
@@ -28,12 +28,14 @@ export const volumeFeature = definePlayerFeature({
toggleMuted() {
const { media } = target();
const willUnmute = media.muted;
media.muted = !media.muted;
const effectivelyMuted = media.muted || media.volume === 0;
// Restore a sensible volume when unmuting at zero.
if (willUnmute && media.volume === 0) {
media.volume = UNMUTE_VOLUME;
if (effectivelyMuted) {
media.muted = false;
// Restore a sensible volume when unmuting at zero.
if (media.volume === 0) media.volume = UNMUTE_VOLUME;
} else {
media.muted = true;
}
return media.muted;