Download packages/cli/src/ui/hooks/useAnimatedScrollbar.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 3.66 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/hooks/useAnimatedScrollbar.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/src/ui/hooks/useAnimatedScrollbar.ts
-
curl -L -o useAnimatedScrollbar.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/hooks/useAnimatedScrollbar.ts
3.66 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { useState, useLayoutEffect, useRef, useCallback } from 'react'; | |
| import { theme } from '../semantic-colors.js'; | |
| import { interpolateColor } from '../themes/color-utils.js'; | |
| import { debugState } from '../debug.js'; | |
| export function useAnimatedScrollbar( | |
| isFocused: boolean, | |
| scrollBy: (delta: number) => void, | |
| ) { | |
| const [scrollbarColor, setScrollbarColor] = useState(theme.ui.dark); | |
| const colorRef = useRef(scrollbarColor); | |
| colorRef.current = scrollbarColor; | |
| const animationFrame = useRef<NodeJS.Timeout | null>(null); | |
| const timeout = useRef<NodeJS.Timeout | null>(null); | |
| const isAnimatingRef = useRef(false); | |
| const cleanup = useCallback(() => { | |
| if (isAnimatingRef.current) { | |
| debugState.debugNumAnimatedComponents--; | |
| isAnimatingRef.current = false; | |
| } | |
| if (animationFrame.current) { | |
| clearInterval(animationFrame.current); | |
| animationFrame.current = null; | |
| } | |
| if (timeout.current) { | |
| clearTimeout(timeout.current); | |
| timeout.current = null; | |
| } | |
| }, []); | |
| const flashScrollbar = useCallback(() => { | |
| cleanup(); | |
| debugState.debugNumAnimatedComponents++; | |
| isAnimatingRef.current = true; | |
| const isTest = | |
| typeof process !== 'undefined' && process.env['NODE_ENV'] === 'test'; | |
| const fadeInDuration = isTest ? 0 : 200; | |
| const visibleDuration = isTest ? 0 : 1000; | |
| const fadeOutDuration = isTest ? 0 : 300; | |
| const focusedColor = theme.text.secondary; | |
| const unfocusedColor = theme.ui.dark; | |
| const startColor = colorRef.current; | |
| if (!focusedColor || !unfocusedColor) { | |
| return; | |
| } | |
| if (isTest) { | |
| setScrollbarColor(unfocusedColor); | |
| cleanup(); | |
| return; | |
| } | |
| // Phase 1: Fade In | |
| let start = Date.now(); | |
| const animateFadeIn = () => { | |
| if (!isAnimatingRef.current) return; | |
| const elapsed = Date.now() - start; | |
| const progress = Math.max(0, Math.min(elapsed / fadeInDuration, 1)); | |
| setScrollbarColor(interpolateColor(startColor, focusedColor, progress)); | |
| if (progress === 1) { | |
| if (animationFrame.current) { | |
| clearInterval(animationFrame.current); | |
| animationFrame.current = null; | |
| } | |
| // Phase 2: Wait | |
| timeout.current = setTimeout(() => { | |
| // Phase 3: Fade Out | |
| start = Date.now(); | |
| const animateFadeOut = () => { | |
| if (!isAnimatingRef.current) return; | |
| const elapsed = Date.now() - start; | |
| const progress = Math.max( | |
| 0, | |
| Math.min(elapsed / fadeOutDuration, 1), | |
| ); | |
| setScrollbarColor( | |
| interpolateColor(focusedColor, unfocusedColor, progress), | |
| ); | |
| if (progress === 1) { | |
| cleanup(); | |
| } | |
| }; | |
| animationFrame.current = setInterval(animateFadeOut, 33); | |
| }, visibleDuration); | |
| } | |
| }; | |
| animationFrame.current = setInterval(animateFadeIn, 33); | |
| }, [cleanup]); | |
| const wasFocused = useRef(isFocused); | |
| useLayoutEffect(() => { | |
| if (isFocused && !wasFocused.current) { | |
| flashScrollbar(); | |
| } else if (!isFocused && wasFocused.current) { | |
| cleanup(); | |
| setScrollbarColor(theme.ui.dark); | |
| } | |
| wasFocused.current = isFocused; | |
| return cleanup; | |
| }, [isFocused, flashScrollbar, cleanup]); | |
| const scrollByWithAnimation = useCallback( | |
| (delta: number) => { | |
| scrollBy(delta); | |
| flashScrollbar(); | |
| }, | |
| [scrollBy, flashScrollbar], | |
| ); | |
| return { scrollbarColor, flashScrollbar, scrollByWithAnimation }; | |
| } | |