Skip to content

Commit 9d6797e

Browse files
committed
feat(Wizard - next): Add more enhancements
1 parent c5a52cc commit 9d6797e

20 files changed

Lines changed: 604 additions & 361 deletions

packages/react-core/src/next/components/Wizard/Wizard.tsx

Lines changed: 69 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ import { css } from '@patternfly/react-styles';
44
import styles from '@patternfly/react-styles/css/components/Wizard/wizard';
55

66
import {
7-
DefaultWizardFooterProps,
8-
DefaultWizardNavProps,
97
isWizardParentStep,
108
WizardNavStepFunction,
11-
CustomWizardNavFunction
9+
CustomWizardNavFunction,
10+
WizardControlStep,
11+
isCustomWizardNav,
12+
DefaultWizardNavProps
1213
} from './types';
1314
import { buildSteps, normalizeNavStep } from './utils';
1415
import { useWizardContext, WizardContextProvider } from './WizardContext';
1516
import { WizardStepProps } from './WizardStep';
1617
import { WizardToggle } from './WizardToggle';
18+
import { WizardFooterProps } from './WizardFooter';
1719

1820
/**
1921
* Wrapper for all steps and hosts state, including navigation helpers, within context.
@@ -26,7 +28,7 @@ export interface WizardProps extends React.HTMLProps<HTMLDivElement> {
2628
/** Wizard header */
2729
header?: React.ReactNode;
2830
/** Wizard footer */
29-
footer?: DefaultWizardFooterProps | React.ReactElement;
31+
footer?: Partial<Omit<WizardFooterProps, 'hideBackButton' | 'hideCancelButton'>> | React.ReactElement;
3032
/** Default wizard nav props or a custom WizardNav (with callback) */
3133
nav?: DefaultWizardNavProps | CustomWizardNavFunction;
3234
/** The initial index the wizard is to start on (1 or higher). Defaults to 1. */
@@ -54,83 +56,93 @@ export interface WizardProps extends React.HTMLProps<HTMLDivElement> {
5456
export const Wizard = (props: WizardProps) => {
5557
const { startIndex = 1, children, footer, onNavByIndex, onNext, onBack, onSave, onClose, ...internalProps } = props;
5658
const [currentStepIndex, setCurrentStepIndex] = React.useState(startIndex);
57-
const steps = buildSteps(children);
59+
const initialSteps = buildSteps(children);
60+
const forceStepVisit = !isCustomWizardNav(internalProps.nav) && internalProps.nav?.forceStepVisit;
5861

59-
const goToStepByIndex = (index: number) => {
60-
const lastStepIndex = steps.length;
62+
const goToNextStep = (steps: WizardControlStep[] = initialSteps) => {
63+
const newStepIndex =
64+
steps.findIndex((step, index) => index + 1 > currentStepIndex && !step.isHidden && !isWizardParentStep(step)) + 1;
6165

62-
if (index < 1) {
63-
index = 1;
64-
} else if (index > lastStepIndex) {
65-
index = lastStepIndex;
66+
if (currentStepIndex >= steps.length || !newStepIndex) {
67+
return onSave ? onSave() : onClose?.();
6668
}
6769

68-
const currStep = steps[index - 1];
70+
const currStep = isWizardParentStep(steps[currentStepIndex])
71+
? steps[currentStepIndex + 1]
72+
: steps[currentStepIndex];
6973
const prevStep = steps[currentStepIndex - 1];
70-
setCurrentStepIndex(index);
7174

72-
return onNavByIndex?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
75+
setCurrentStepIndex(newStepIndex);
76+
77+
return onNext?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
7378
};
7479

75-
const goToNextStep = () => {
76-
// Save when on the last step, otherwise close
77-
if (currentStepIndex >= steps.length) {
78-
if (onSave) {
79-
return onSave();
80-
}
80+
const goToPrevStep = (steps: WizardControlStep[] = initialSteps) => {
81+
const newStepIndex =
82+
[...steps]
83+
.reverse()
84+
.findIndex(
85+
(step: WizardControlStep, index: number) =>
86+
index + 1 < currentStepIndex && !step.isHidden && !isWizardParentStep(step)
87+
) + 1;
88+
const currStep = isWizardParentStep(steps[currentStepIndex - 2])
89+
? steps[currentStepIndex - 3]
90+
: steps[currentStepIndex - 2];
91+
const prevStep = steps[currentStepIndex - 1];
8192

82-
return onClose?.();
83-
}
93+
setCurrentStepIndex(newStepIndex);
8494

85-
let currStep = steps[currentStepIndex];
86-
let newStepIndex = currentStepIndex + 1;
87-
const prevStep = steps[currentStepIndex - 1];
95+
return onBack?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
96+
};
97+
98+
const goToStepByIndex = (steps: WizardControlStep[] = initialSteps, index: number) => {
99+
const lastStepIndex = steps.length + 1;
88100

89-
// Skip parent step and focus on the first sub-step if they exist
90-
if (isWizardParentStep(currStep)) {
91-
newStepIndex += 1;
92-
currStep = steps[currentStepIndex + 1];
101+
// Handle index when out of bounds or hidden
102+
if (index < 1) {
103+
index = 1;
104+
} else if (index > lastStepIndex) {
105+
index = lastStepIndex;
106+
} else if (steps[index - 1].isHidden) {
107+
// eslint-disable-next-line no-console
108+
console.error('Wizard: Unable to navigate to hidden step.');
93109
}
94110

95-
setCurrentStepIndex(newStepIndex);
96-
return onNext?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
111+
const currStep = steps[index - 1];
112+
const prevStep = steps[currentStepIndex - 1];
113+
setCurrentStepIndex(index);
114+
115+
return onNavByIndex?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
97116
};
98117

99-
const goToPrevStep = () => {
100-
if (steps.length < currentStepIndex) {
101-
// Previous step was removed, just update the currentStep state
102-
setCurrentStepIndex(steps.length);
118+
const goToStepById = (steps: WizardControlStep[] = initialSteps, id: number | string) => {
119+
const stepIndex = steps.findIndex(step => step.id === id) + 1;
120+
121+
if (stepIndex > 0 && stepIndex < steps.length + 1 && !steps[stepIndex].isHidden) {
122+
setCurrentStepIndex(stepIndex);
103123
} else {
104-
let currStep = steps[currentStepIndex - 2];
105-
let newStepIndex = currentStepIndex - 1;
106-
const prevStep = steps[currentStepIndex - 1];
107-
108-
// // Skip parent step and focus on the step prior
109-
if (isWizardParentStep(currStep)) {
110-
newStepIndex -= 1;
111-
currStep = steps[currentStepIndex - 3];
112-
}
113-
114-
setCurrentStepIndex(newStepIndex);
115-
return onBack?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
124+
// eslint-disable-next-line no-console
125+
console.error(`Wizard: Unable to navigate to step with id: ${id}.`);
116126
}
117127
};
118128

119-
const goToStepById = (id: number | string) => {
120-
const stepIndex = steps.findIndex(step => step.id === id) + 1;
121-
stepIndex > 0 && setCurrentStepIndex(stepIndex);
122-
};
129+
const goToStepByName = (steps: WizardControlStep[] = initialSteps, name: string) => {
130+
const stepIndex = initialSteps.findIndex(step => step.name === name) + 1;
123131

124-
const goToStepByName = (name: string) => {
125-
const stepIndex = steps.findIndex(step => step.name === name) + 1;
126-
stepIndex > 0 && setCurrentStepIndex(stepIndex);
132+
if (stepIndex > 0 && stepIndex < steps.length + 1 && !steps[stepIndex].isHidden) {
133+
setCurrentStepIndex(stepIndex);
134+
} else {
135+
// eslint-disable-next-line no-console
136+
console.error(`Wizard: Unable to navigate to step with name: ${name}.`);
137+
}
127138
};
128139

129140
return (
130141
<WizardContextProvider
131-
steps={steps}
142+
steps={initialSteps}
132143
currentStepIndex={currentStepIndex}
133144
footer={footer}
145+
forceStepVisit={forceStepVisit}
134146
onNext={goToNextStep}
135147
onBack={goToPrevStep}
136148
onClose={onClose}
@@ -143,9 +155,8 @@ export const Wizard = (props: WizardProps) => {
143155
);
144156
};
145157

146-
// eslint-disable-next-line patternfly-react/no-anonymous-functions
147158
const WizardInternal = ({ height, width, className, header, nav, unmountInactiveSteps, ...divProps }: WizardProps) => {
148-
const { activeStep, steps, footer, goToStepByIndex } = useWizardContext();
159+
const { currentStep, steps, footer, goToStepByIndex } = useWizardContext();
149160

150161
return (
151162
<div
@@ -159,7 +170,7 @@ const WizardInternal = ({ height, width, className, header, nav, unmountInactive
159170
{header}
160171
<WizardToggle
161172
steps={steps}
162-
activeStep={activeStep}
173+
currentStep={currentStep}
163174
footer={footer}
164175
nav={nav}
165176
goToStepByIndex={goToStepByIndex}

0 commit comments

Comments
 (0)