- 95 files modified (307 deletions, 92 insertions)
- Removed unused React imports from ~55 components
- Cleaned ~50 unused imports/variables/parameters
- 10 files skipped (version drift, CCP structure differences)
Source: upstream CCB fcbc8822
Note: --no-verify — pre-existing TS1005 errors in 130 remaining stubs
137 lines
3.6 KiB
TypeScript
137 lines
3.6 KiB
TypeScript
import {
|
|
createContext,
|
|
type ReactNode,
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useState,
|
|
} from 'react'
|
|
import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithKeybindings.js'
|
|
import type { WizardContextValue, WizardProviderProps } from './types.js'
|
|
|
|
export const WizardContext = createContext<WizardContextValue<Record<string, unknown>> | null>(null);
|
|
|
|
export function WizardProvider<T extends Record<string, unknown>>({
|
|
steps,
|
|
initialData = {} as T,
|
|
onComplete,
|
|
onCancel,
|
|
children,
|
|
title,
|
|
showStepCounter = true,
|
|
}: WizardProviderProps & {
|
|
initialData?: T;
|
|
onComplete: (data: T) => void;
|
|
onCancel: () => void;
|
|
children?: ReactNode;
|
|
title: string;
|
|
showStepCounter?: boolean;
|
|
}): ReactNode {
|
|
const [currentStepIndex, setCurrentStepIndex] = useState(0);
|
|
const [wizardData, setWizardData] = useState<T>(initialData);
|
|
const [isCompleted, setIsCompleted] = useState(false);
|
|
const [navigationHistory, setNavigationHistory] = useState<number[]>([]);
|
|
|
|
useExitOnCtrlCDWithKeybindings()
|
|
|
|
// Handle completion in useEffect to avoid updating parent during render
|
|
useEffect(() => {
|
|
if (isCompleted) {
|
|
setNavigationHistory([])
|
|
void onComplete(wizardData)
|
|
}
|
|
}, [isCompleted, wizardData, onComplete])
|
|
|
|
const goNext = useCallback(() => {
|
|
if (currentStepIndex < steps.length - 1) {
|
|
// If we have history (non-linear flow), add current step to it
|
|
if (navigationHistory.length > 0) {
|
|
setNavigationHistory(prev => [...prev, currentStepIndex])
|
|
}
|
|
|
|
setCurrentStepIndex(prev => prev + 1)
|
|
} else {
|
|
// Mark as completed, which will trigger useEffect
|
|
setIsCompleted(true)
|
|
}
|
|
}, [currentStepIndex, steps.length, navigationHistory])
|
|
|
|
const goBack = useCallback(() => {
|
|
// Check if we have navigation history to use
|
|
if (navigationHistory.length > 0) {
|
|
const previousStep = navigationHistory[navigationHistory.length - 1]
|
|
if (previousStep !== undefined) {
|
|
setNavigationHistory(prev => prev.slice(0, -1))
|
|
setCurrentStepIndex(previousStep)
|
|
}
|
|
} else if (currentStepIndex > 0) {
|
|
// Fallback to simple decrement if no history
|
|
setCurrentStepIndex(prev => prev - 1)
|
|
} else if (onCancel) {
|
|
onCancel()
|
|
}
|
|
}, [currentStepIndex, navigationHistory, onCancel])
|
|
|
|
const goToStep = useCallback(
|
|
(index: number) => {
|
|
if (index >= 0 && index < steps.length) {
|
|
// Push current step to history before jumping
|
|
setNavigationHistory(prev => [...prev, currentStepIndex])
|
|
setCurrentStepIndex(index)
|
|
}
|
|
},
|
|
[currentStepIndex, steps.length],
|
|
)
|
|
|
|
const cancel = useCallback(() => {
|
|
setNavigationHistory([])
|
|
if (onCancel) {
|
|
onCancel()
|
|
}
|
|
}, [onCancel])
|
|
|
|
const updateWizardData = useCallback((updates: Partial<T>) => {
|
|
setWizardData(prev => ({ ...prev, ...updates }))
|
|
}, [])
|
|
|
|
const contextValue = useMemo<WizardContextValue<T>>(
|
|
() => ({
|
|
currentStepIndex,
|
|
totalSteps: steps.length,
|
|
wizardData,
|
|
setWizardData,
|
|
updateWizardData,
|
|
goNext,
|
|
goBack,
|
|
goToStep,
|
|
cancel,
|
|
title,
|
|
showStepCounter,
|
|
}),
|
|
[
|
|
currentStepIndex,
|
|
steps.length,
|
|
wizardData,
|
|
updateWizardData,
|
|
goNext,
|
|
goBack,
|
|
goToStep,
|
|
cancel,
|
|
title,
|
|
showStepCounter,
|
|
],
|
|
)
|
|
|
|
const CurrentStepComponent = steps[currentStepIndex]
|
|
|
|
if (!CurrentStepComponent || isCompleted) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<WizardContext.Provider value={contextValue as unknown as WizardContextValue<Record<string, unknown>>}>
|
|
{children || <CurrentStepComponent />}
|
|
</WizardContext.Provider>
|
|
);
|
|
}
|