π File detail
components/Spinner/useShimmerAnimation.ts
π§© .tsπ 32 linesπΎ 1,236 bytesπ text
β Back to All Filesπ― Use case
This file lives under βcomponents/β, which covers shared React UI pieces. On the API surface it exposes useShimmerAnimation β mainly functions, hooks, or classes. Dependencies touch React UI. It composes internal code from ink and types (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import { useMemo } from 'react' import { stringWidth } from '../../ink/stringWidth.js' import { type DOMElement, useAnimationFrame } from '../../ink.js' import type { SpinnerMode } from './types.js'
π€ Exports (heuristic)
useShimmerAnimation
π External import roots
Package roots from from "β¦" (relative paths omitted).
react
π₯οΈ Source preview
import { useMemo } from 'react'
import { stringWidth } from '../../ink/stringWidth.js'
import { type DOMElement, useAnimationFrame } from '../../ink.js'
import type { SpinnerMode } from './types.js'
export function useShimmerAnimation(
mode: SpinnerMode,
message: string,
isStalled: boolean,
): [ref: (element: DOMElement | null) => void, glimmerIndex: number] {
const glimmerSpeed = mode === 'requesting' ? 50 : 200
// Pass null when stalled to unsubscribe from the clock β otherwise the
// setInterval keeps firing at 20fps even when the shimmer isn't visible.
// Notably, if the caller never attaches `ref` (e.g. conditional JSX),
// useTerminalViewport stays at its initial isVisible:true and the
// viewport-pause never kicks in, so this is the only stop mechanism.
const [ref, time] = useAnimationFrame(isStalled ? null : glimmerSpeed)
const messageWidth = useMemo(() => stringWidth(message), [message])
if (isStalled) {
return [ref, -100]
}
const cyclePosition = Math.floor(time / glimmerSpeed)
const cycleLength = messageWidth + 20
if (mode === 'requesting') {
return [ref, (cyclePosition % cycleLength) - 10]
}
return [ref, messageWidth + 10 - (cyclePosition % cycleLength)]
}