- 移除未使用的YAML锚点定义 - 替换commands字段中的锚点引用为实际值 - 移除有问题的通知步骤 - 修复测试文件中的问题 - 添加新的测试用例和配置文件
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { useReducedMotion } from '@/hooks/use-reduced-motion';
|
||||
|
||||
describe('useReducedMotion', () => {
|
||||
const originalMatchMedia = window.matchMedia;
|
||||
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
matches: query === '(prefers-reduced-motion: reduce)',
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.matchMedia = originalMatchMedia;
|
||||
});
|
||||
|
||||
it('should return false when user prefers motion', () => {
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when user prefers reduced motion', () => {
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
matches: query === '(prefers-reduced-motion: reduce)',
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('should update when preference changes', () => {
|
||||
const listeners: Array<(event: MediaQueryListEvent) => void> = [];
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
addEventListener: jest.fn((event, listener) => {
|
||||
if (event === 'change') {
|
||||
listeners.push(listener);
|
||||
}
|
||||
}),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
act(() => {
|
||||
listeners.forEach(listener => {
|
||||
listener({ matches: true } as MediaQueryListEvent);
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function useReducedMotion() {
|
||||
const [shouldReduceMotion, setShouldReduceMotion] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
setShouldReduceMotion(mediaQuery.matches);
|
||||
|
||||
const handleChange = (event: MediaQueryListEvent) => {
|
||||
setShouldReduceMotion(event.matches);
|
||||
};
|
||||
|
||||
mediaQuery.addEventListener('change', handleChange);
|
||||
|
||||
return () => {
|
||||
mediaQuery.removeEventListener('change', handleChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return shouldReduceMotion;
|
||||
}
|
||||
|
||||
export function getAnimationConfig(
|
||||
shouldReduceMotion: boolean,
|
||||
normalConfig: { duration?: number; delay?: number; ease?: any },
|
||||
reducedConfig?: { duration?: number; delay?: number; ease?: any }
|
||||
) {
|
||||
if (shouldReduceMotion) {
|
||||
return {
|
||||
duration: reducedConfig?.duration ?? 0,
|
||||
delay: reducedConfig?.delay ?? 0,
|
||||
ease: reducedConfig?.ease ?? 'linear',
|
||||
};
|
||||
}
|
||||
return normalConfig;
|
||||
}
|
||||
|
||||
export function getAnimationVariants(
|
||||
shouldReduceMotion: boolean,
|
||||
normalVariants: any
|
||||
) {
|
||||
if (shouldReduceMotion) {
|
||||
return {
|
||||
initial: {},
|
||||
animate: {},
|
||||
exit: {},
|
||||
};
|
||||
}
|
||||
return normalVariants;
|
||||
}
|
||||
Reference in New Issue
Block a user