Skip to content

Commit 2f709e4

Browse files
authored
feat: [#1724] Add support for "prefers-reduced-motion" (#1725)
1 parent efd734b commit 2f709e4

File tree

5 files changed

+56
-4
lines changed

5 files changed

+56
-4
lines changed

packages/happy-dom/src/browser/DefaultBrowserSettings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default <IBrowserSettings>{
3838
},
3939
device: {
4040
prefersColorScheme: 'light',
41+
prefersReducedMotion: 'no-preference',
4142
mediaType: 'screen'
4243
},
4344
debug: {

packages/happy-dom/src/browser/types/IBrowserSettings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export default interface IBrowserSettings {
109109
*/
110110
device: {
111111
prefersColorScheme: string;
112+
prefersReducedMotion: string;
112113
mediaType: string;
113114
};
114115

packages/happy-dom/src/browser/types/IOptionalBrowserSettings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export default interface IOptionalBrowserSettings {
103103
*/
104104
device?: {
105105
prefersColorScheme?: string;
106+
prefersReducedMotion?: string;
106107
mediaType?: string;
107108
};
108109

packages/happy-dom/src/match-media/MediaQueryItem.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ export default class MediaQueryItem {
199199
* @returns "true" if the rule matches.
200200
*/
201201
private matchesRule(rule: IMediaQueryRule): boolean {
202+
const settings = new WindowBrowserContext(this.window).getSettings();
203+
204+
if (!settings) {
205+
return false;
206+
}
207+
202208
if (!rule.value) {
203209
switch (rule.name) {
204210
case 'min-width':
@@ -218,6 +224,8 @@ export default class MediaQueryItem {
218224
case 'max-aspect-ratio':
219225
case 'aspect-ratio':
220226
return true;
227+
case 'prefers-reduced-motion':
228+
return settings.device.prefersReducedMotion === 'reduce';
221229
}
222230
return false;
223231
}
@@ -246,10 +254,9 @@ export default class MediaQueryItem {
246254
? this.window.innerWidth > this.window.innerHeight
247255
: this.window.innerWidth < this.window.innerHeight;
248256
case 'prefers-color-scheme':
249-
return (
250-
rule.value ===
251-
new WindowBrowserContext(this.window).getSettings().device.prefersColorScheme
252-
);
257+
return rule.value === settings.device.prefersColorScheme;
258+
case 'prefers-reduced-motion':
259+
return rule.value === settings.device.prefersReducedMotion;
253260
case 'any-hover':
254261
case 'hover':
255262
if (rule.value === 'none') {

packages/happy-dom/test/match-media/MediaQueryList.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ describe('MediaQueryList', () => {
2121
expect(
2222
new MediaQueryList({ window: window, media: 'NOT all AND (prefers-COLOR-scheme)' }).media
2323
).toBe('not all and (prefers-color-scheme)');
24+
expect(
25+
new MediaQueryList({ window: window, media: 'NOT all AND (prefers-REDUCED-motion)' }).media
26+
).toBe('not all and (prefers-reduced-motion)');
2427
expect(new MediaQueryList({ window: window, media: 'all and (hover: none' }).media).toBe(
2528
'all and (hover: none)'
2629
);
@@ -46,6 +49,15 @@ describe('MediaQueryList', () => {
4649
expect(new MediaQueryList({ window: window, media: '(prefers-color-scheme)' }).media).toBe(
4750
'(prefers-color-scheme)'
4851
);
52+
expect(new MediaQueryList({ window: window, media: 'prefers-reduced-motion' }).media).toBe(
53+
''
54+
);
55+
expect(new MediaQueryList({ window: window, media: '(prefers-reduced-motion' }).media).toBe(
56+
'not all'
57+
);
58+
expect(new MediaQueryList({ window: window, media: '(prefers-reduced-motion)' }).media).toBe(
59+
'(prefers-reduced-motion)'
60+
);
4961
});
5062
});
5163

@@ -268,6 +280,36 @@ describe('MediaQueryList', () => {
268280
).toBe(false);
269281
});
270282

283+
it('Handles "prefers-reduced-motion".', () => {
284+
expect(
285+
new MediaQueryList({ window: window, media: '(prefers-reduced-motion)' }).matches
286+
).toBe(false);
287+
expect(
288+
new MediaQueryList({ window: window, media: '(prefers-reduced-motion: reduce)' }).matches
289+
).toBe(false);
290+
expect(
291+
new MediaQueryList({ window: window, media: '(prefers-reduced-motion: no-preference)' })
292+
.matches
293+
).toBe(true);
294+
295+
window = new Window({
296+
width: 1024,
297+
height: 768,
298+
settings: { device: { prefersReducedMotion: 'reduce' } }
299+
});
300+
301+
expect(
302+
new MediaQueryList({ window: window, media: '(prefers-reduced-motion)' }).matches
303+
).toBe(true);
304+
expect(
305+
new MediaQueryList({ window: window, media: '(prefers-reduced-motion: reduce)' }).matches
306+
).toBe(true);
307+
expect(
308+
new MediaQueryList({ window: window, media: '(prefers-reduced-motion: no-preference)' })
309+
.matches
310+
).toBe(false);
311+
});
312+
271313
it('Handles "hover".', () => {
272314
expect(new MediaQueryList({ window: window, media: '(hover)' }).matches).toBe(true);
273315
expect(new MediaQueryList({ window: window, media: '(hover: invalid)' }).matches).toBe(false);

0 commit comments

Comments
 (0)