import { useCallback, useEffect, useRef, useState } from 'react'; import { GuidedTourPlayer } from './GuidedTourPlayer'; import type { GuidedTour, GuidedTourSinks, GuidedTourSnapshot, } from './guidedTour'; export interface UseGuidedTourPlayerResult { player: GuidedTourPlayer; snapshot: GuidedTourSnapshot; play: () => void; pause: () => void; resume: () => void; restart: (autoPlay?: boolean) => void; next: () => void; previous: () => void; seekStep: (stepIndex: number) => void; setReducedMotion: (enabled: boolean) => void; } export function useGuidedTourPlayer( tour: GuidedTour | null | undefined, sinks: GuidedTourSinks, ): UseGuidedTourPlayerResult { const playerRef = useRef(null); if (!playerRef.current) { playerRef.current = new GuidedTourPlayer(tour, sinks); } const player = playerRef.current; const [snapshot, setSnapshot] = useState(() => player.getSnapshot()); useEffect(() => player.subscribe(setSnapshot), [player]); useEffect(() => { player.setTour(tour ?? null); }, [player, tour]); useEffect(() => { player.setSinks(sinks); }, [player, sinks]); useEffect(() => { if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return undefined; const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); const syncReducedMotion = () => player.setReducedMotion(mediaQuery.matches); syncReducedMotion(); if (typeof mediaQuery.addEventListener === 'function') { mediaQuery.addEventListener('change', syncReducedMotion); return () => mediaQuery.removeEventListener('change', syncReducedMotion); } mediaQuery.addListener(syncReducedMotion); return () => mediaQuery.removeListener(syncReducedMotion); }, [player]); useEffect( () => () => { player.dispose(); }, [player], ); return { player, snapshot, play: useCallback(() => player.play(), [player]), pause: useCallback(() => player.pause(), [player]), resume: useCallback(() => player.resume(), [player]), restart: useCallback((autoPlay = false) => player.restart(autoPlay), [player]), next: useCallback(() => player.next(), [player]), previous: useCallback(() => player.previous(), [player]), seekStep: useCallback((stepIndex: number) => player.seekStep(stepIndex), [player]), setReducedMotion: useCallback((enabled: boolean) => player.setReducedMotion(enabled), [player]), }; }