Skip to content

Commit ae0af36

Browse files
committed
Revert hook edits unlrelated to the scroll feature
Part 2
1 parent e9af061 commit ae0af36

File tree

1 file changed

+19
-89
lines changed

1 file changed

+19
-89
lines changed

special-pages/pages/new-tab/app/protections/utils/useAnimatedCount.js

Lines changed: 19 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,10 @@ import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
22
import { animateCount } from './animateCount.js';
33

44
/**
5-
* Custom hook to animate a count value with visibility-aware and
6-
* viewport-aware animation
7-
*
8-
* IMPORTANT: In webview contexts (especially macOS), the NTP webview stays
9-
* alive and processes updates in the background even when not visible. This
10-
* hook tracks the "last seen" value when the element becomes invisible and
11-
* animates from that value to the new target when it becomes visible again.
12-
*
13-
* Detection methods (in order of reliability):
14-
* 1. Native visibility notification via messaging (e.g., 'ntp_becameVisible'
15-
* subscription) - MOST RELIABLE (Not yet implemented - see @todo below)
16-
* 2. IntersectionObserver (element enters/exits webview viewport) - CURRENTLY USED
17-
* 3. document.visibilityState (page visibility API) - CURRENTLY USED (may not
18-
* work if webview stays alive)
19-
*
5+
* Custom hook to animate a count value with visibility-aware and viewport-aware animation
206
* @param {number} targetValue - The target value to animate to
21-
* @param {import('preact').RefObject<HTMLElement>} [elementRef] - Optional ref
22-
* to element for viewport detection
7+
* @param {import('preact').RefObject<HTMLElement>} [elementRef] - Optional ref to element for viewport detection
238
* @returns {number} The current animated value
24-
*
25-
* @todo IDEAL SOLUTION: Native code should send a message (e.g.,
26-
* 'ntp_becameVisible') when the NTP webview becomes visible to the user. This
27-
* would be more reliable than JavaScript-only detection. We could subscribe to
28-
* this message and trigger animation when received.
299
*/
3010
export function useAnimatedCount(targetValue, elementRef) {
3111
// Initialize to 0 so first render triggers percentage-based animation from spec
@@ -41,13 +21,9 @@ export function useAnimatedCount(targetValue, elementRef) {
4121
// Track if we've animated at least once (to prevent re-animation on re-entry)
4222
const hasAnimatedRef = useRef(false);
4323

44-
// Track the last value that was displayed when the page was visible
45-
// This allows us to animate from the last seen value when returning to NTP
24+
// Track the last value that was displayed when element exited viewport
4625
const lastSeenValueRef = useRef(/** @type {number | null} */ (null));
47-
48-
// Track whether we were visible the last time we checked
49-
// Used to detect transitions from hidden -> visible
50-
const wasVisibleRef = useRef(false);
26+
const wasInViewportRef = useRef(false);
5127

5228
// Memoize the update callback to avoid recreating it on every render
5329
const updateAnimatedCount = useCallback(
@@ -60,16 +36,11 @@ export function useAnimatedCount(targetValue, elementRef) {
6036
[],
6137
);
6238

63-
// Track previous viewport state for IntersectionObserver callback
64-
const wasInViewportRef = useRef(false);
65-
6639
// Setup IntersectionObserver for viewport detection
6740
useEffect(() => {
6841
// If no elementRef provided, element is always considered "in viewport"
6942
if (!elementRef || !elementRef.current) {
7043
setIsInViewport(true);
71-
wasInViewportRef.current = true;
72-
7344
return;
7445
}
7546

@@ -79,11 +50,8 @@ export function useAnimatedCount(targetValue, elementRef) {
7950
const wasInViewport = wasInViewportRef.current;
8051
const isNowInViewport = entry.isIntersecting;
8152

82-
// When element exits viewport, save current displayed value as "last seen"
83-
// This is the value the user last saw, and we'll animate from this when returning
53+
// When element exits viewport, save current displayed value
8454
if (wasInViewport && !isNowInViewport) {
85-
// Save the value that was displayed when element became invisible
86-
// This handles the case where user navigates away while NTP is visible
8755
lastSeenValueRef.current = animatedValueRef.current;
8856
}
8957

@@ -110,78 +78,40 @@ export function useAnimatedCount(targetValue, elementRef) {
11078
useEffect(() => {
11179
let cancelAnimation = () => {};
11280

113-
const isCurrentlyVisible = document.visibilityState === 'visible' && isInViewport;
114-
const wasVisible = wasVisibleRef.current;
115-
const becameVisible = isCurrentlyVisible && !wasVisible;
116-
// We're returning to NTP if we became visible AND we have a last seen value
117-
// This means the element was visible before, became invisible, and is now visible again
118-
const isReturningToNTP = becameVisible && lastSeenValueRef.current !== null;
119-
120-
// Update visibility tracking
121-
wasVisibleRef.current = isCurrentlyVisible;
81+
const shouldAnimate = document.visibilityState === 'visible' && isInViewport;
12282

123-
if (isCurrentlyVisible) {
83+
if (shouldAnimate) {
12484
// Determine starting value for animation
12585
let startValue = animatedValueRef.current;
12686

127-
// If we're returning to NTP and the target value has changed, animate from last seen value
128-
if (isReturningToNTP && lastSeenValueRef.current !== null && lastSeenValueRef.current !== targetValue) {
87+
// If we have a last seen value, animate from that
88+
if (lastSeenValueRef.current !== null && lastSeenValueRef.current !== targetValue) {
12989
startValue = lastSeenValueRef.current;
130-
// Reset animation state to allow re-animation
131-
hasAnimatedRef.current = false;
90+
lastSeenValueRef.current = null; // Clear after use
13291
}
13392

13493
// Animate from start value to target
13594
cancelAnimation = animateCount(targetValue, updateAnimatedCount, undefined, startValue);
13695
hasAnimatedRef.current = true;
137-
138-
// After animation starts, update last seen to target (will be updated as animation progresses)
139-
// This ensures next time we hide, we save the correct final value
140-
} else {
141-
// Page is not visible
142-
if (wasVisible) {
143-
// We just became hidden - save the current displayed value as last seen
144-
// This is the value the user last saw, and we'll animate from this when returning
145-
lastSeenValueRef.current = animatedValueRef.current;
146-
}
147-
148-
if (hasAnimatedRef.current) {
149-
// If we've already animated once and conditions aren't met, just snap to value
150-
// This handles the case where value changes while element is out of viewport
151-
setAnimatedValue(targetValue);
152-
animatedValueRef.current = targetValue;
153-
}
154-
// else: conditions not met and haven't animated yet, do nothing (wait for viewport entry)
96+
} else if (hasAnimatedRef.current) {
97+
// If we've already animated once and conditions aren't met, just snap to value
98+
// This handles the case where value changes while element is out of viewport
99+
setAnimatedValue(targetValue);
100+
animatedValueRef.current = targetValue;
155101
}
102+
// else: conditions not met and haven't animated yet, do nothing (wait for viewport entry)
156103

157104
// Listen for visibility changes
158105
const handleVisibilityChange = () => {
159-
const isNowVisible = document.visibilityState === 'visible' && isInViewport;
160-
const wasVisibleBefore = wasVisibleRef.current;
161-
const becameVisibleNow = isNowVisible && !wasVisibleBefore;
162-
const isReturningToNTPNow = becameVisibleNow && lastSeenValueRef.current !== null;
163-
164-
wasVisibleRef.current = isNowVisible;
165-
166-
if (isNowVisible) {
167-
// Determine starting value
168-
let startValue = animatedValueRef.current;
169-
170-
// If returning to NTP and value changed, animate from last seen
171-
if (isReturningToNTPNow && lastSeenValueRef.current !== null && lastSeenValueRef.current !== targetValue) {
172-
startValue = lastSeenValueRef.current;
173-
hasAnimatedRef.current = false;
174-
}
175-
106+
if (document.visibilityState === 'visible' && isInViewport) {
176107
// Page became visible and element is in viewport - start animation
177108
cancelAnimation();
178-
cancelAnimation = animateCount(targetValue, updateAnimatedCount, undefined, startValue);
109+
cancelAnimation = animateCount(targetValue, updateAnimatedCount, undefined, animatedValueRef.current);
179110
hasAnimatedRef.current = true;
180111
} else if (document.visibilityState === 'hidden') {
181-
// Page became hidden - save current value and cancel animation
112+
// Page became hidden - cancel animation and snap to final value
182113
cancelAnimation();
183114
if (hasAnimatedRef.current) {
184-
lastSeenValueRef.current = animatedValueRef.current;
185115
setAnimatedValue(targetValue);
186116
animatedValueRef.current = targetValue;
187117
}

0 commit comments

Comments
 (0)