Core/src/Components/Steps/Steps.tsx

110 lines
2.5 KiB
TypeScript
Raw Normal View History

import React, {useEffect} from "react";
import {
GlobalStateProvider,
useGlobalStateReducers, useGlobalStateValue,
} from "../../GlobalState";
import {usePreviousValue} from "../../Utils";
import {StepKeyType, stepsGlobalState, useCurrentStepKey, useStepsNavigator} from "./StepsContext";
/**
* Main Steps component.
*/
export function Steps({children}: React.PropsWithChildren<{}>)
{
return (
<GlobalStateProvider globalState={stepsGlobalState}>
<div className={"steps"}>
<StepsNavigatorComponent />
<div>
{children}
</div>
</div>
</GlobalStateProvider>
);
}
/**
* Steps navigator component.
*/
export function StepsNavigatorComponent()
{
// Get the steps navigator functions.
const stepsNavigator = useStepsNavigator();
// Get the current steps state.
const stepsState = useGlobalStateValue(stepsGlobalState);
// Get the current step.
const currentStep = useCurrentStepKey();
return (
<nav className={"steps"}>
<ul>
{ // Showing a button for each step.
stepsState.steps.map((step, index) => (
// Rendering the current step button.
<li key={step.key} className={currentStep == step.key ? "active" : undefined}>
<button type={"button"} onClick={() => {
stepsNavigator.set(step.key);
}}>
{step.title ?? (index + 1)}
</button>
</li>
))
}
</ul>
</nav>
);
}
/**
* Component of a step.
*/
export function Step({stepKey, stepTitle, children}: React.PropsWithChildren<{
/**
* The current step unique key.
*/
stepKey: StepKeyType;
/**
* The step title, to show in the navigator.
*/
stepTitle?: React.ReactNode;
}>)
{
// Get the global state reducers class.
const stepsGlobalStateReducers = useGlobalStateReducers(stepsGlobalState);
// Get the previous step key.
const previousStepKey = usePreviousValue(stepKey);
useEffect(() => {
// Remove the previous step key, if there is one.
if (previousStepKey) stepsGlobalStateReducers.removeStep(previousStepKey);
// Register the current step key.
stepsGlobalStateReducers.registerStep(stepKey, stepTitle);
// Remove the step key when component is removed.
return () => stepsGlobalStateReducers.removeStep(stepKey);
}, [stepsGlobalStateReducers, previousStepKey, stepTitle]);
// Get the current step key.
const currentStep = useCurrentStepKey();
if (currentStep != stepKey)
// If this step is not the current one, rendering nothing.
return undefined;
// Rendering the current step.
return (
<section className={"step"}>
{children}
</section>
);
}