import { useEffect, useRef } from 'react'; import type { SeekbarStyle } from '../store/authStoreTypes'; import { makeAnimState, makeHeights } from '../utils/waveformSeekHelpers'; import { drawSeekbar } from '../utils/waveformSeekRenderers'; interface Props { style: SeekbarStyle; label: string; selected: boolean; onClick: () => void; } /** Animated preview tile for Settings — drives drawSeekbar via a rAF loop and * parks itself when the window/tab is hidden. */ export function SeekbarPreview({ style, label, selected, onClick }: Props) { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; let heights: Float32Array | null = null; if (style === 'truewave' || style === 'pseudowave') { heights = makeHeights('seekbar-preview-demo'); } const animState = makeAnimState(); let t = 0; let rafId: number | null = null; let pollId: number | null = null; const stop = () => { if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; } if (pollId !== null) { window.clearTimeout(pollId); pollId = null; } }; const tick = () => { if (document.hidden || window.__psyHidden) { pollId = window.setTimeout(() => { pollId = null; tick(); }, 400); return; } t += 0.016; animState.time = t; const progress = 0.15 + 0.65 * (0.5 + 0.5 * Math.sin(t)); const buffered = Math.min(1, progress + 0.18); drawSeekbar(canvas, style, heights, progress, buffered, animState); rafId = requestAnimationFrame(tick); }; tick(); return () => stop(); }, [style]); return ( ); }