• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prabhuignoto / react-chrono / #92

18 Jun 2025 10:08AM UTC coverage: 90.727% (+0.9%) from 89.791%
#92

push

web-flow
Minor cleanup and expanding test coverage (#548)

* refactor: rename project to React Chrono UI and update related files

* fix: update tsconfig to reference the correct entry file for React Chrono UI

* feat: enhance styles with vendor prefixes and improve cross-browser support

* Add tests for useNewScrollPosition hook and TimelineHorizontal component

- Implement comprehensive tests for the useNewScrollPosition hook covering horizontal, vertical, and edge cases.
- Create a new test file for the TimelineHorizontal component, ensuring it renders correctly and handles various props and states.
- Update snapshots for timeline control and vertical components to reflect recent changes in class names.
- Modify vitest configuration to include all test files in the src directory.

* refactor: simplify transform handling in timeline styles

* refactor: clean up test imports and remove unused styles in timeline components

1783 of 2112 branches covered (84.42%)

Branch coverage included in aggregate %.

670 of 674 new or added lines in 12 files covered. (99.41%)

400 existing lines in 29 files now uncovered.

10564 of 11497 relevant lines covered (91.88%)

10.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.42
/src/components/effects/useMatchMedia.ts
1
import { useCallback, useEffect, useRef, useState } from 'react';
1✔
2
import { useDebouncedCallback } from 'use-debounce';
1✔
3
import {
1✔
4
  createMediaQuery,
5
  addMediaListeners,
6
  removeMediaListeners,
7
} from '../../utils/mediaQueryUtils';
8

9
/**
10
 * Configuration options for the useMatchMedia hook
11
 */
12
interface MatchMediaOptions {
13
  /** Callback function to execute when media query matches */
14
  onMatch?: () => void;
15
  /** Whether the hook is enabled */
16
  enabled?: boolean;
17
  /** Debounce delay in milliseconds */
18
  debounceDelay?: number;
19
}
20

21
/**
22
 * Custom hook that tracks if a media query matches and executes a callback on matches
23
 *
24
 * @param query - The media query string to match against
25
 * @param options - Configuration options
26
 * @returns Boolean indicating if the media query currently matches
27
 *
28
 * @example
29
 * ```tsx
30
 * const isMobile = useMatchMedia('(max-width: 768px)', {
31
 *   onMatch: () => console.log('Mobile view detected'),
32
 *   debounceDelay: 200
33
 * });
34
 * ```
35
 */
36
export const useMatchMedia = (
1✔
37
  query: string,
23✔
38
  { onMatch, enabled = true, debounceDelay = 100 }: MatchMediaOptions = {},
23✔
39
): boolean => {
23✔
40
  const [matches, setMatches] = useState<boolean>(false);
23✔
41
  const mediaQuery = useRef<MediaQueryList | null>(null);
23✔
42
  const isCleanedUp = useRef<boolean>(false);
23✔
43

44
  // Stable callback references to prevent unnecessary effect re-runs
45
  const handleMediaChange = useCallback(
23✔
46
    (event: MediaQueryListEvent | MediaQueryList) => {
23✔
47
      if (isCleanedUp.current) return;
9!
48
      setMatches(event.matches);
9✔
49
    },
9✔
50
    [],
23✔
51
  );
23✔
52

53
  const handleResize = useDebouncedCallback(
23✔
54
    () => {
23✔
55
      if (!mediaQuery.current || isCleanedUp.current) return;
1!
56

57
      const currentMatches = mediaQuery.current.matches;
1✔
58
      setMatches(currentMatches);
1✔
59
    },
1✔
60
    debounceDelay,
23✔
61
    { maxWait: 1000 },
23✔
62
  );
23✔
63

64
  // Setup media query listener
65
  useEffect(() => {
23✔
66
    if (!enabled || typeof window === 'undefined') {
14✔
67
      return;
1✔
68
    }
1✔
69

70
    isCleanedUp.current = false;
13✔
71

72
    // Cleanup previous mediaQuery if it exists
73
    if (mediaQuery.current) {
14!
UNCOV
74
      removeMediaListeners(mediaQuery.current, handleMediaChange, handleResize);
×
UNCOV
75
    }
✔
76

77
    mediaQuery.current = createMediaQuery(query);
13✔
78
    const currentMedia = mediaQuery.current;
13✔
79

80
    if (!currentMedia) {
14✔
81
      return;
5✔
82
    }
5✔
83

84
    // Initial check
85
    handleMediaChange(currentMedia);
8✔
86

87
    // Add event listeners
88
    addMediaListeners(currentMedia, handleMediaChange, handleResize);
8✔
89

90
    // Cleanup
91
    return () => {
8✔
92
      isCleanedUp.current = true;
8✔
93
      if (currentMedia) {
8✔
94
        removeMediaListeners(currentMedia, handleMediaChange, handleResize);
8✔
95
      }
8✔
96
      handleResize.cancel(); // Cancel any pending debounced calls
8✔
97
      mediaQuery.current = null; // Clear the ref
8✔
98
    };
8✔
99
  }, [query, enabled, handleMediaChange, handleResize]); // Removed createMediaQuery dependency to avoid infinite loops
23✔
100

101
  // Execute callback when matches changes - use ref to avoid stale closure
102
  const onMatchRef = useRef(onMatch);
23✔
103
  onMatchRef.current = onMatch;
23✔
104

105
  useEffect(() => {
23✔
106
    if (matches && onMatchRef.current) {
21✔
107
      onMatchRef.current();
1✔
108
    }
1✔
109
  }, [matches]);
23✔
110

111
  return matches;
23✔
112
};
23✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc