'use client'; import { forwardRef, useState, HTMLAttributes } from 'react'; import styles from './phase-container.module.css'; export interface Phase { /** Unique phase identifier */ id: string; /** Phase content */ content: React.ReactNode; /** Whether this phase can be skipped */ skippable?: boolean; /** Minimum duration (ms) before showing next button */ minDuration?: number; } export interface PhaseContainerProps extends HTMLAttributes { /** Array of phases */ phases: Phase[]; /** Current phase index (controlled) */ currentPhase?: number; /** Callback when phase changes */ onPhaseChange?: (index: number, phase: Phase) => void; /** Show progress indicator */ showProgress?: boolean; /** Progress position */ progressPosition?: 'top' | 'bottom' | 'left' | 'right'; /** Show phase counter */ showCounter?: boolean; /** Counter label */ counterLabel?: string; /** Transition animation */ transition?: 'fade' | 'slide' | 'scale' | 'blur' | 'glitch' | 'none'; /** Transition duration in ms */ transitionDuration?: number; /** Allow skipping phases */ allowSkip?: boolean; /** Skip button label */ skipLabel?: string; /** Show back button */ showBack?: boolean; /** Back button label */ backLabel?: string; } export const PhaseContainer = forwardRef( ( { phases, currentPhase: controlledIndex, onPhaseChange, showProgress = true, progressPosition = 'bottom', showCounter = true, counterLabel = 'PHASE', transition = 'fade', transitionDuration = 500, allowSkip = true, skipLabel = 'Skip →', showBack = true, backLabel = '← Back', className, children, ...props }, ref ) => { const [internalIndex, setInternalIndex] = useState(0); const [transitioning, setTransitioning] = useState(false); const currentIndex = controlledIndex !== undefined ? controlledIndex : internalIndex; const currentPhase = phases[currentIndex]; const isFirst = currentIndex === 0; const isLast = currentIndex === phases.length - 1; const goToPhase = (index: number) => { if (transitioning || index < 0 || index >= phases.length) return; const phase = phases[index]; setTransitioning(true); setTimeout(() => { if (controlledIndex === undefined) { setInternalIndex(index); } onPhaseChange?.(index, phase); setTransitioning(false); }, transitionDuration); }; const goNext = () => { if (!isLast) { goToPhase(currentIndex + 1); } }; const goBack = () => { if (!isFirst) { goToPhase(currentIndex - 1); } }; return (
{/* Progress Bar */} {showProgress && (
{showCounter && ( {counterLabel} {currentIndex + 1}/{phases.length} )}
)} {/* Phase Content */}
{currentPhase?.content}
{/* Navigation */}
); } ); PhaseContainer.displayName = 'PhaseContainer'; export default PhaseContainer;