Skip to content

Commit 7c2cf7e

Browse files
authored
Merge pull request #5785 from YadavAkhileshh/fix/replace-deprecated-mediaquery-listener
frontend: themes: Replace deprecated MediaQueryList listener methods
2 parents fc4889b + 22df39f commit 7c2cf7e

2 files changed

Lines changed: 44 additions & 7 deletions

File tree

frontend/src/lib/themes.test.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,11 @@ describe('themes.ts', () => {
132132

133133
it('should return light when system prefers light', () => {
134134
Object.defineProperty(window, 'matchMedia', {
135-
value: vi
136-
.fn()
137-
.mockReturnValue({ matches: false, addListener: vi.fn(), removeListener: vi.fn() }),
135+
value: vi.fn().mockReturnValue({
136+
matches: false,
137+
addEventListener: vi.fn(),
138+
removeEventListener: vi.fn(),
139+
}),
138140
writable: true,
139141
configurable: true,
140142
});
@@ -144,9 +146,11 @@ describe('themes.ts', () => {
144146

145147
it('should return dark when system prefers dark', () => {
146148
Object.defineProperty(window, 'matchMedia', {
147-
value: vi
148-
.fn()
149-
.mockReturnValue({ matches: true, addListener: vi.fn(), removeListener: vi.fn() }),
149+
value: vi.fn().mockReturnValue({
150+
matches: true,
151+
addEventListener: vi.fn(),
152+
removeEventListener: vi.fn(),
153+
}),
150154
writable: true,
151155
configurable: true,
152156
});
@@ -155,6 +159,27 @@ describe('themes.ts', () => {
155159
});
156160

157161
it('should register and clean up the media query listener', () => {
162+
const addEventListener = vi.fn();
163+
const removeEventListener = vi.fn();
164+
Object.defineProperty(window, 'matchMedia', {
165+
value: vi.fn().mockReturnValue({ matches: false, addEventListener, removeEventListener }),
166+
writable: true,
167+
configurable: true,
168+
});
169+
const { unmount } = renderHook(() => usePrefersColorScheme());
170+
171+
expect(addEventListener).toHaveBeenCalledTimes(1);
172+
expect(addEventListener).toHaveBeenCalledWith('change', expect.any(Function));
173+
174+
const handler = addEventListener.mock.calls[0][1];
175+
176+
unmount();
177+
178+
expect(removeEventListener).toHaveBeenCalledTimes(1);
179+
expect(removeEventListener).toHaveBeenCalledWith('change', handler);
180+
});
181+
182+
it('should register and clean up the media query listener using fallback methods when addEventListener is not defined', () => {
158183
const addListener = vi.fn();
159184
const removeListener = vi.fn();
160185
Object.defineProperty(window, 'matchMedia', {
@@ -163,9 +188,16 @@ describe('themes.ts', () => {
163188
configurable: true,
164189
});
165190
const { unmount } = renderHook(() => usePrefersColorScheme());
191+
166192
expect(addListener).toHaveBeenCalledTimes(1);
193+
expect(addListener).toHaveBeenCalledWith(expect.any(Function));
194+
195+
const handler = addListener.mock.calls[0][0];
196+
167197
unmount();
198+
168199
expect(removeListener).toHaveBeenCalledTimes(1);
200+
expect(removeListener).toHaveBeenCalledWith(handler);
169201
});
170202
});
171203

frontend/src/lib/themes.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,12 @@ export function usePrefersColorScheme() {
579579

580580
React.useEffect(() => {
581581
if (!mql) return;
582-
const handler = (x: MediaQueryListEvent | MediaQueryList) => setValue(x.matches);
582+
const handler = (x: MediaQueryListEvent) => setValue(x.matches);
583+
if (typeof mql.addEventListener === 'function') {
584+
mql.addEventListener('change', handler);
585+
return () => mql.removeEventListener('change', handler);
586+
}
587+
// Legacy fallback (e.g. older Safari/WebViews)
583588
mql.addListener(handler);
584589
return () => mql.removeListener(handler);
585590
// eslint-disable-next-line react-hooks/exhaustive-deps

0 commit comments

Comments
 (0)