diff --git a/packages/react-core/src/components/Wizard/examples/Wizard.md b/packages/react-core/src/components/Wizard/examples/Wizard.md
index 027987b3e34..377c4969894 100644
--- a/packages/react-core/src/components/Wizard/examples/Wizard.md
+++ b/packages/react-core/src/components/Wizard/examples/Wizard.md
@@ -133,8 +133,10 @@ class IncrementallyEnabledStepsWizard extends React.Component {
stepIdReached: 1
};
this.onNext = ({ id }) => {
+ const [, orderIndex] = id.split('-');
+
this.setState({
- stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
+ stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached
});
};
this.closeWizard = () => {
@@ -146,27 +148,27 @@ class IncrementallyEnabledStepsWizard extends React.Component {
const { stepIdReached } = this.state;
const steps = [
- { id: 'incrementally-enabled-1', name: 'First step', component:
Step 1 content
},
+ { id: 'incrementallyEnabled-1', name: 'First step', component: Step 1 content
},
{
- id: 'incrementally-enabled-2',
+ id: 'incrementallyEnabled-2',
name: 'Second step',
component: Step 2 content
,
canJumpTo: stepIdReached >= 2
},
{
- id: 'incrementally-enabled-3',
+ id: 'incrementallyEnabled-3',
name: 'Third step',
component: Step 3 content
,
canJumpTo: stepIdReached >= 3
},
{
- id: 'incrementally-enabled-4',
+ id: 'incrementallyEnabled-4',
name: 'Fourth step',
component: Step 4 content
,
canJumpTo: stepIdReached >= 4
},
{
- id: 'incrementally-enabled-5',
+ id: 'incrementallyEnabled-5',
name: 'Review',
component: Review step content
,
nextButtonText: 'Finish',
@@ -311,8 +313,10 @@ class ValidationWizard extends React.Component {
this.onNext = ({ id, name }, { prevId, prevName }) => {
console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
+ const [, orderIndex] = id.split('-');
+
this.setState({
- stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
+ stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached
});
this.areAllStepsValid();
};
@@ -812,10 +816,10 @@ class GetCurrentStepWizard extends React.Component {
step: 1
};
this.onCurrentStepChanged = ({ id }) => {
- this.setState({
- step: id
- });
- }
+ this.setState({
+ step: id
+ });
+ };
this.closeWizard = () => {
console.log('close wizard');
};
diff --git a/packages/react-core/src/next/components/Wizard/Wizard.tsx b/packages/react-core/src/next/components/Wizard/Wizard.tsx
index 8034ab498bb..337ec12b536 100644
--- a/packages/react-core/src/next/components/Wizard/Wizard.tsx
+++ b/packages/react-core/src/next/components/Wizard/Wizard.tsx
@@ -42,8 +42,6 @@ export interface WizardProps extends React.HTMLProps {
height?: number | string;
/** Disables navigation items that haven't been visited. Defaults to false */
isStepVisitRequired?: boolean;
- /** Flag to unmount inactive steps instead of hiding. Defaults to true */
- hasUnmountedSteps?: boolean;
/** Callback function when a step in the navigation is clicked */
onNavByIndex?: WizardNavStepFunction;
/** Callback function after next button is clicked */
@@ -66,7 +64,6 @@ export const Wizard = ({
nav,
startIndex = 1,
isStepVisitRequired = false,
- hasUnmountedSteps = true,
onNavByIndex,
onNext,
onBack,
@@ -74,42 +71,37 @@ export const Wizard = ({
onClose,
...wrapperProps
}: WizardProps) => {
- const [currentStepIndex, setCurrentStepIndex] = React.useState(startIndex);
+ const [activeStepIndex, setActiveStepIndex] = React.useState(startIndex);
const initialSteps = buildSteps(children);
const goToNextStep = (steps: WizardControlStep[] = initialSteps) => {
- const newStepIndex =
- steps.findIndex((step, index) => index + 1 > currentStepIndex && !step.isHidden && !isWizardParentStep(step)) + 1;
+ const newStepIndex = steps.find(step => step.index > activeStepIndex && !step.isHidden && !isWizardParentStep(step))
+ ?.index;
- if (currentStepIndex >= steps.length || !newStepIndex) {
+ if (activeStepIndex >= steps.length || !newStepIndex) {
return onSave ? onSave() : onClose?.();
}
- const currStep = isWizardParentStep(steps[currentStepIndex])
- ? steps[currentStepIndex + 1]
- : steps[currentStepIndex];
- const prevStep = steps[currentStepIndex - 1];
-
- setCurrentStepIndex(newStepIndex);
+ const currStep = isWizardParentStep(steps[activeStepIndex]) ? steps[activeStepIndex + 1] : steps[activeStepIndex];
+ const prevStep = steps[activeStepIndex - 1];
- return onNext?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
+ setActiveStepIndex(newStepIndex);
+ return onNext?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
};
const goToPrevStep = (steps: WizardControlStep[] = initialSteps) => {
const newStepIndex =
findLastIndex(
steps,
- (step: WizardControlStep, index: number) =>
- index + 1 < currentStepIndex && !step.isHidden && !isWizardParentStep(step)
+ (step: WizardControlStep) => step.index < activeStepIndex && !step.isHidden && !isWizardParentStep(step)
) + 1;
- const currStep = isWizardParentStep(steps[currentStepIndex - 2])
- ? steps[currentStepIndex - 3]
- : steps[currentStepIndex - 2];
- const prevStep = steps[currentStepIndex - 1];
-
- setCurrentStepIndex(newStepIndex);
+ const currStep = isWizardParentStep(steps[activeStepIndex - 2])
+ ? steps[activeStepIndex - 3]
+ : steps[activeStepIndex - 2];
+ const prevStep = steps[activeStepIndex - 1];
- return onBack?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
+ setActiveStepIndex(newStepIndex);
+ return onBack?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
};
const goToStepByIndex = (steps: WizardControlStep[] = initialSteps, index: number) => {
@@ -120,46 +112,40 @@ export const Wizard = ({
index = 1;
} else if (index > lastStepIndex) {
index = lastStepIndex;
- } else if (steps[index - 1].isHidden) {
- // eslint-disable-next-line no-console
- console.error('Wizard: Unable to navigate to hidden step.');
}
const currStep = steps[index - 1];
- const prevStep = steps[currentStepIndex - 1];
- setCurrentStepIndex(index);
+ const prevStep = steps[activeStepIndex - 1];
- return onNavByIndex?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
+ setActiveStepIndex(index);
+ return onNavByIndex?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
};
const goToStepById = (steps: WizardControlStep[] = initialSteps, id: number | string) => {
- const stepIndex = steps.findIndex(step => step.id === id) + 1;
+ const step = steps.find(step => step.id === id);
+ const stepIndex = step?.index;
+ const lastStepIndex = steps.length + 1;
- if (stepIndex > 0 && stepIndex < steps.length + 1 && !steps[stepIndex].isHidden) {
- setCurrentStepIndex(stepIndex);
- } else {
- // eslint-disable-next-line no-console
- console.error(`Wizard: Unable to navigate to step with id: ${id}.`);
+ if (stepIndex > 0 && stepIndex < lastStepIndex && !step.isHidden) {
+ setActiveStepIndex(stepIndex);
}
};
const goToStepByName = (steps: WizardControlStep[] = initialSteps, name: string) => {
- const stepIndex = initialSteps.findIndex(step => step.name === name) + 1;
+ const step = steps.find(step => step.name === name);
+ const stepIndex = step?.index;
+ const lastStepIndex = steps.length + 1;
- if (stepIndex > 0 && stepIndex < steps.length + 1 && !steps[stepIndex].isHidden) {
- setCurrentStepIndex(stepIndex);
- } else {
- // eslint-disable-next-line no-console
- console.error(`Wizard: Unable to navigate to step with name: ${name}.`);
+ if (stepIndex > 0 && stepIndex < lastStepIndex && !step.isHidden) {
+ setActiveStepIndex(stepIndex);
}
};
return (
{header}
-
+
);
};
-const WizardInternal = ({
- nav,
- hasUnmountedSteps,
- isStepVisitRequired
-}: Pick) => {
- const { currentStep, steps, footer, goToStepByIndex } = useWizardContext();
+const WizardInternal = ({ nav, isStepVisitRequired }: Pick) => {
+ const { activeStep, steps, footer, goToStepByIndex } = useWizardContext();
const [isNavExpanded, setIsNavExpanded] = React.useState(false);
const wizardNav = React.useMemo(() => {
if (isCustomWizardNav(nav)) {
- return typeof nav === 'function' ? nav(isNavExpanded, steps, currentStep, goToStepByIndex) : nav;
+ return typeof nav === 'function' ? nav(isNavExpanded, steps, activeStep, goToStepByIndex) : nav;
}
return ;
- }, [currentStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
+ }, [activeStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
return (
setIsNavExpanded(prevIsExpanded => !prevIsExpanded)}
- hasUnmountedSteps={hasUnmountedSteps}
/>
);
};
diff --git a/packages/react-core/src/next/components/Wizard/WizardBody.tsx b/packages/react-core/src/next/components/Wizard/WizardBody.tsx
index 872851d1c46..ab0362bb02b 100644
--- a/packages/react-core/src/next/components/Wizard/WizardBody.tsx
+++ b/packages/react-core/src/next/components/Wizard/WizardBody.tsx
@@ -10,7 +10,7 @@ import { css } from '@patternfly/react-styles';
export interface WizardBodyProps {
children: React.ReactNode | React.ReactNode[];
/** Set to true to remove the default body padding */
- hasNoBodyPadding?: boolean;
+ hasNoPadding?: boolean;
/** An aria-label to use for the wrapper element */
'aria-label'?: string;
/** Sets the aria-labelledby attribute for the wrapper element */
@@ -21,13 +21,13 @@ export interface WizardBodyProps {
export const WizardBody = ({
children,
- hasNoBodyPadding = false,
+ hasNoPadding = false,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
component: WrapperComponent = 'div'
}: WizardBodyProps) => (
- {children}
+ {children}
);
diff --git a/packages/react-core/src/next/components/Wizard/WizardContext.tsx b/packages/react-core/src/next/components/Wizard/WizardContext.tsx
index 8e9c25de173..c3f7cd88dc5 100644
--- a/packages/react-core/src/next/components/Wizard/WizardContext.tsx
+++ b/packages/react-core/src/next/components/Wizard/WizardContext.tsx
@@ -1,16 +1,14 @@
import React from 'react';
-import { isCustomWizardFooter, isWizardParentStep, WizardControlStep, WizardFooterType } from './types';
-import { getCurrentStep } from './utils';
+import { isCustomWizardFooter, WizardControlStep, WizardFooterType } from './types';
+import { getActiveStep } from './utils';
import { WizardFooter, WizardFooterProps } from './WizardFooter';
export interface WizardContextProps {
/** List of steps */
steps: WizardControlStep[];
/** Current step */
- currentStep: WizardControlStep;
- /** Current step index */
- currentStepIndex: number;
+ activeStep: WizardControlStep;
/** Footer element */
footer: React.ReactElement;
/** Navigate to the next step */
@@ -31,17 +29,14 @@ export interface WizardContextProps {
getStep: (stepId: number | string) => WizardControlStep;
/** Set step by ID */
setStep: (step: Pick & Partial) => void;
- /** Toggle step visibility by ID */
- toggleStep: (stepId: number | string, isHidden: boolean) => void;
}
export const WizardContext = React.createContext({} as WizardContextProps);
export interface WizardContextProviderProps {
steps: WizardControlStep[];
- currentStepIndex: number;
+ activeStepIndex: number;
footer: WizardFooterType;
- isStepVisitRequired: boolean;
children: React.ReactElement;
onNext(steps: WizardControlStep[]): void;
onBack(steps: WizardControlStep[]): void;
@@ -54,8 +49,7 @@ export interface WizardContextProviderProps {
export const WizardContextProvider: React.FunctionComponent = ({
steps: initialSteps,
footer: initialFooter,
- currentStepIndex,
- isStepVisitRequired,
+ activeStepIndex,
children,
onNext,
onBack,
@@ -64,43 +58,58 @@ export const WizardContextProvider: React.FunctionComponent {
- const [steps, setSteps] = React.useState(initialSteps);
+ const [currentSteps, setCurrentSteps] = React.useState(initialSteps);
const [currentFooter, setCurrentFooter] = React.useState(
typeof initialFooter !== 'function' ? initialFooter : undefined
);
- const currentStep = getCurrentStep(steps, currentStepIndex);
+
+ // Combined initial and current state steps
+ const steps = React.useMemo(
+ () =>
+ currentSteps.map((currentStepProps, index) => {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { isVisited, ...initialStepProps } = initialSteps[index];
+
+ return {
+ ...currentStepProps,
+ ...initialStepProps
+ };
+ }),
+ [initialSteps, currentSteps]
+ );
+ const activeStep = getActiveStep(steps, activeStepIndex);
const goToNextStep = React.useCallback(() => onNext(steps), [onNext, steps]);
const goToPrevStep = React.useCallback(() => onBack(steps), [onBack, steps]);
const footer = React.useMemo(() => {
- const wizardFooter = currentFooter || initialFooter;
+ const wizardFooter = activeStep?.footer || currentFooter || initialFooter;
if (isCustomWizardFooter(wizardFooter)) {
const customFooter = wizardFooter;
return typeof customFooter === 'function'
- ? customFooter(currentStep, goToNextStep, goToPrevStep, onClose)
+ ? customFooter(activeStep, goToNextStep, goToPrevStep, onClose)
: customFooter;
}
return (
);
- }, [currentFooter, initialFooter, currentStep, goToNextStep, goToPrevStep, onClose, steps]);
+ }, [currentFooter, initialFooter, activeStep, goToNextStep, goToPrevStep, onClose, steps]);
const getStep = React.useCallback((stepId: string | number) => steps.find(step => step.id === stepId), [steps]);
const setStep = React.useCallback(
(step: Pick & Partial) =>
- setSteps(prevSteps =>
+ setCurrentSteps(prevSteps =>
prevSteps.map(prevStep => {
if (prevStep.id === step.id) {
return { ...prevStep, ...step };
@@ -112,56 +121,15 @@ export const WizardContextProvider: React.FunctionComponent
- setSteps(prevSteps => {
- let stepToHide: WizardControlStep;
-
- return prevSteps.map(prevStep => {
- if (prevStep.id === stepId) {
- // Don't hide the currently active step or its parent (if a sub-step).
- if (
- isHidden &&
- (currentStep.id === prevStep.id ||
- (isWizardParentStep(prevStep) && prevStep.subStepIds.includes(currentStep.id)))
- ) {
- // eslint-disable-next-line no-console
- console.error('Wizard: Unable to hide the current step or its parent.');
- return prevStep;
- }
-
- stepToHide = { ...prevStep, isHidden };
- return stepToHide;
- }
-
- // When isStepVisitRequired is enabled, if the step was previously hidden and not visited yet,
- // when it is shown, all steps beyond it should be disabled to ensure it is visited.
- if (
- isStepVisitRequired &&
- stepToHide?.isHidden === false &&
- !stepToHide?.isVisited &&
- prevSteps.indexOf(stepToHide) < prevSteps.indexOf(prevStep)
- ) {
- return { ...prevStep, isVisited: false };
- }
-
- return prevStep;
- });
- }),
- [currentStep.id, isStepVisitRequired]
- );
-
return (
WizardNavStepFunction | void;
/** Back button callback */
@@ -43,9 +43,9 @@ export const WizardFooterWrapper = ({ children }: WizardFooterWrapperProps) => (
);
-export const WizardFooter = ({ currentStep, ...internalProps }: WizardFooterProps) => {
- const currentStepFooter = !isCustomWizardFooter(currentStep.footer) && currentStep.footer;
- return ;
+export const WizardFooter = ({ activeStep, ...internalProps }: WizardFooterProps) => {
+ const activeStepFooter = !isCustomWizardFooter(activeStep.footer) && activeStep.footer;
+ return ;
};
const InternalWizardFooter = ({
@@ -59,7 +59,7 @@ const InternalWizardFooter = ({
nextButtonText = 'Next',
backButtonText = 'Back',
cancelButtonText = 'Cancel'
-}: Omit) => (
+}: Omit) => (