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

prabhuignoto / react-chrono / #99

08 Dec 2025 06:00PM UTC coverage: 64.754% (-25.9%) from 90.669%
#99

push

prabhuignoto
Update test command in coveralls workflow to align with Bun's command structure

2231 of 2661 branches covered (83.84%)

Branch coverage included in aggregate %.

14146 of 22630 relevant lines covered (62.51%)

15.0 hits per line

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

72.66
/src/components/effects/useSlideshow.ts
1
import { RefObject, useCallback, useEffect, useRef, useState } from 'react';
1✔
2

3
type SlideshowHookReturn = {
4
  paused: boolean;
5
  remainInterval: number;
6
  setStartWidth: (width: number) => void;
7
  setupTimer: (interval: number) => void;
8
  startWidth: number;
9
  tryPause: () => void;
10
  tryResume: () => void;
11
};
12

13
/**
14
 * Custom hook to manage slideshow functionality with pause/resume capabilities
15
 * Uses requestAnimationFrame for smoother animation performance
16
 * @param ref - Reference to the HTML element containing the slideshow
17
 * @param active - Whether the current slide is active
18
 * @param slideShowActive - Whether the slideshow functionality is enabled
19
 * @param slideItemDuration - Duration in milliseconds for each slide
20
 * @param id - Unique identifier for the current slide
21
 * @param onElapsed - Callback function triggered when slide duration elapses
22
 * @returns Object containing slideshow control functions and state
23
 */
24
const useSlideshow = (
1✔
25
  ref: RefObject<HTMLElement>,
101✔
26
  active: boolean,
101✔
27
  slideShowActive: boolean,
101✔
28
  slideItemDuration: number,
101✔
29
  id: string,
101✔
30
  onElapsed?: (id: string) => void,
101✔
31
): SlideshowHookReturn => {
101✔
32
  const startTime = useRef<number | null>(null);
101✔
33
  const timerRef = useRef<number>(0);
101✔
34
  const rafRef = useRef<number>(0);
101✔
35
  const [startWidth, setStartWidth] = useState<number>(0);
101✔
36
  const [paused, setPaused] = useState<boolean>(false);
101✔
37
  const slideShowElapsed = useRef<number>(0);
101✔
38
  const [remainInterval, setRemainInterval] = useState<number>(0);
101✔
39
  const isRunning = useRef<boolean>(false);
101✔
40

41
  /**
42
   * Cleans up timers and animation frames
43
   */
44
  const cleanupTimer = useCallback(() => {
101✔
45
    // Clear timeout if exists
46
    if (timerRef.current) {
266!
47
      window.clearTimeout(timerRef.current);
×
48
      timerRef.current = 0;
×
49
    }
×
50

51
    // Cancel animation frame if exists
52
    if (rafRef.current) {
266✔
53
      window.cancelAnimationFrame(rafRef.current);
3✔
54
      rafRef.current = 0;
3✔
55
    }
3✔
56

57
    isRunning.current = false;
266✔
58
  }, []);
101✔
59

60
  /**
61
   * Handles timer completion
62
   */
63
  const handleTimerComplete = useCallback(() => {
101✔
64
    cleanupTimer();
×
65
    setPaused(true);
×
66
    setStartWidth(0);
×
67
    setRemainInterval(slideItemDuration);
×
68
    if (id && onElapsed) {
×
69
      onElapsed(id);
×
70
    }
×
71
  }, [id, onElapsed, slideItemDuration, cleanupTimer]);
101✔
72

73
  /**
74
   * Sets up a new timer for the slideshow using requestAnimationFrame for smoother animations
75
   * @param interval - Duration in milliseconds for the timer
76
   */
77
  const setupTimer = useCallback(
101✔
78
    (interval: number) => {
101✔
79
      if (!slideItemDuration || interval <= 0 || !active || !slideShowActive) {
3!
80
        return;
×
81
      }
×
82

83
      cleanupTimer();
3✔
84
      setRemainInterval(interval);
3✔
85
      startTime.current = performance.now();
3✔
86
      setPaused(false);
3✔
87
      isRunning.current = true;
3✔
88

89
      // For very short durations, use setTimeout as fallback
90
      if (interval < 50) {
3!
91
        timerRef.current = window.setTimeout(() => {
×
92
          handleTimerComplete();
×
93
        }, interval);
×
94
        return;
×
95
      }
×
96

97
      // Use requestAnimationFrame for smoother animation
98
      const endTime = startTime.current + interval;
3✔
99

100
      const animationStep = (timestamp: number) => {
3✔
101
        if (!isRunning.current) return;
×
102

103
        if (timestamp >= endTime) {
×
104
          handleTimerComplete();
×
105
          return;
×
106
        }
×
107

108
        // Continue animation loop
109
        rafRef.current = window.requestAnimationFrame(animationStep);
×
110
      };
×
111

112
      rafRef.current = window.requestAnimationFrame(animationStep);
3✔
113
    },
3✔
114
    [
101✔
115
      slideItemDuration,
101✔
116
      active,
101✔
117
      slideShowActive,
101✔
118
      cleanupTimer,
101✔
119
      handleTimerComplete,
101✔
120
    ],
101✔
121
  );
101✔
122

123
  /**
124
   * Pauses the current slideshow if conditions are met
125
   */
126
  const tryPause = useCallback(() => {
101✔
127
    if (!active || !slideShowActive) {
1!
128
      return;
×
129
    }
×
130

131
    cleanupTimer();
1✔
132
    setPaused(true);
1✔
133

134
    if (startTime.current !== null) {
1✔
135
      const elapsed = performance.now() - startTime.current;
1✔
136
      slideShowElapsed.current = elapsed;
1✔
137
    }
1✔
138

139
    if (ref.current) {
1✔
140
      setStartWidth(ref.current.clientWidth);
1✔
141
    }
1✔
142
  }, [active, slideShowActive, cleanupTimer]);
101✔
143

144
  /**
145
   * Resumes the slideshow if conditions are met
146
   */
147
  const tryResume = useCallback(() => {
101✔
148
    if (!active || !slideShowActive || !slideItemDuration) {
×
149
      return;
×
150
    }
×
151

152
    const remainingInterval = slideItemDuration - slideShowElapsed.current;
×
153
    if (remainingInterval > 0) {
×
154
      setPaused(false);
×
155
      setupTimer(remainingInterval);
×
156
    }
×
157
  }, [active, slideShowActive, slideItemDuration, setupTimer]);
101✔
158

159
  // Auto-start timer when slideshow becomes active
160
  useEffect(() => {
101✔
161
    if (slideShowActive && active && slideItemDuration > 0) {
69✔
162
      setupTimer(slideItemDuration);
3✔
163
    } else if (!slideShowActive) {
69✔
164
      cleanupTimer();
66✔
165
    }
66✔
166
    return cleanupTimer;
69✔
167
  }, [slideShowActive, active, slideItemDuration, setupTimer, cleanupTimer]);
101✔
168

169
  // Cleanup effect when active state changes
170
  useEffect(() => {
101✔
171
    if (!active) {
69✔
172
      cleanupTimer();
58✔
173
    }
58✔
174
    return () => {
69✔
175
      // Cleanup when component unmounts or dependencies change
176
      cleanupTimer();
69✔
177
    };
69✔
178
  }, [active, cleanupTimer]);
101✔
179

180
  return {
101✔
181
    paused,
101✔
182
    remainInterval,
101✔
183
    setStartWidth,
101✔
184
    setupTimer,
101✔
185
    startWidth,
101✔
186
    tryPause,
101✔
187
    tryResume,
101✔
188
  };
101✔
189
};
101✔
190

191
export { useSlideshow };
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

© 2026 Coveralls, Inc