Skip to content

Commit 17af1ff

Browse files
authored
next(Wizard): Allow for WizardStep to better control state from props entry-point, include index (#8218)
* next(Wizard): Allow for WizardStep to better control state from props entrypoint, include index * address feedback * fix a couple existing wizard demos, update naming of combined steps in 'next' wizard context * disable Back/Cancel for async Next step in Kitchen sink example
1 parent bb273c8 commit 17af1ff

21 files changed

+312
-448
lines changed

packages/react-core/src/components/Wizard/examples/Wizard.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ class IncrementallyEnabledStepsWizard extends React.Component {
134134
stepIdReached: 1
135135
};
136136
this.onNext = ({ id }) => {
137+
const [, orderIndex] = id.split('-');
138+
137139
this.setState({
138-
stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
140+
stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached
139141
});
140142
};
141143
this.closeWizard = () => {
@@ -147,27 +149,27 @@ class IncrementallyEnabledStepsWizard extends React.Component {
147149
const { stepIdReached } = this.state;
148150

149151
const steps = [
150-
{ id: 'incrementally-enabled-1', name: 'First step', component: <p>Step 1 content</p> },
152+
{ id: 'incrementallyEnabled-1', name: 'First step', component: <p>Step 1 content</p> },
151153
{
152-
id: 'incrementally-enabled-2',
154+
id: 'incrementallyEnabled-2',
153155
name: 'Second step',
154156
component: <p>Step 2 content</p>,
155157
canJumpTo: stepIdReached >= 2
156158
},
157159
{
158-
id: 'incrementally-enabled-3',
160+
id: 'incrementallyEnabled-3',
159161
name: 'Third step',
160162
component: <p>Step 3 content</p>,
161163
canJumpTo: stepIdReached >= 3
162164
},
163165
{
164-
id: 'incrementally-enabled-4',
166+
id: 'incrementallyEnabled-4',
165167
name: 'Fourth step',
166168
component: <p>Step 4 content</p>,
167169
canJumpTo: stepIdReached >= 4
168170
},
169171
{
170-
id: 'incrementally-enabled-5',
172+
id: 'incrementallyEnabled-5',
171173
name: 'Review',
172174
component: <p>Review step content</p>,
173175
nextButtonText: 'Finish',
@@ -312,8 +314,10 @@ class ValidationWizard extends React.Component {
312314

313315
this.onNext = ({ id, name }, { prevId, prevName }) => {
314316
console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
317+
const [, orderIndex] = id.split('-');
318+
315319
this.setState({
316-
stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
320+
stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached
317321
});
318322
this.areAllStepsValid();
319323
};

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

Lines changed: 35 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ export interface WizardProps extends React.HTMLProps<HTMLDivElement> {
4242
height?: number | string;
4343
/** Disables navigation items that haven't been visited. Defaults to false */
4444
isStepVisitRequired?: boolean;
45-
/** Flag to unmount inactive steps instead of hiding. Defaults to true */
46-
hasUnmountedSteps?: boolean;
4745
/** Callback function when a step in the navigation is clicked */
4846
onNavByIndex?: WizardNavStepFunction;
4947
/** Callback function after next button is clicked */
@@ -66,50 +64,44 @@ export const Wizard = ({
6664
nav,
6765
startIndex = 1,
6866
isStepVisitRequired = false,
69-
hasUnmountedSteps = true,
7067
onNavByIndex,
7168
onNext,
7269
onBack,
7370
onSave,
7471
onClose,
7572
...wrapperProps
7673
}: WizardProps) => {
77-
const [currentStepIndex, setCurrentStepIndex] = React.useState(startIndex);
74+
const [activeStepIndex, setActiveStepIndex] = React.useState(startIndex);
7875
const initialSteps = buildSteps(children);
7976

8077
const goToNextStep = (steps: WizardControlStep[] = initialSteps) => {
81-
const newStepIndex =
82-
steps.findIndex((step, index) => index + 1 > currentStepIndex && !step.isHidden && !isWizardParentStep(step)) + 1;
78+
const newStepIndex = steps.find(step => step.index > activeStepIndex && !step.isHidden && !isWizardParentStep(step))
79+
?.index;
8380

84-
if (currentStepIndex >= steps.length || !newStepIndex) {
81+
if (activeStepIndex >= steps.length || !newStepIndex) {
8582
return onSave ? onSave() : onClose?.();
8683
}
8784

88-
const currStep = isWizardParentStep(steps[currentStepIndex])
89-
? steps[currentStepIndex + 1]
90-
: steps[currentStepIndex];
91-
const prevStep = steps[currentStepIndex - 1];
92-
93-
setCurrentStepIndex(newStepIndex);
85+
const currStep = isWizardParentStep(steps[activeStepIndex]) ? steps[activeStepIndex + 1] : steps[activeStepIndex];
86+
const prevStep = steps[activeStepIndex - 1];
9487

95-
return onNext?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
88+
setActiveStepIndex(newStepIndex);
89+
return onNext?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
9690
};
9791

9892
const goToPrevStep = (steps: WizardControlStep[] = initialSteps) => {
9993
const newStepIndex =
10094
findLastIndex(
10195
steps,
102-
(step: WizardControlStep, index: number) =>
103-
index + 1 < currentStepIndex && !step.isHidden && !isWizardParentStep(step)
96+
(step: WizardControlStep) => step.index < activeStepIndex && !step.isHidden && !isWizardParentStep(step)
10497
) + 1;
105-
const currStep = isWizardParentStep(steps[currentStepIndex - 2])
106-
? steps[currentStepIndex - 3]
107-
: steps[currentStepIndex - 2];
108-
const prevStep = steps[currentStepIndex - 1];
109-
110-
setCurrentStepIndex(newStepIndex);
98+
const currStep = isWizardParentStep(steps[activeStepIndex - 2])
99+
? steps[activeStepIndex - 3]
100+
: steps[activeStepIndex - 2];
101+
const prevStep = steps[activeStepIndex - 1];
111102

112-
return onBack?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
103+
setActiveStepIndex(newStepIndex);
104+
return onBack?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
113105
};
114106

115107
const goToStepByIndex = (steps: WizardControlStep[] = initialSteps, index: number) => {
@@ -120,46 +112,40 @@ export const Wizard = ({
120112
index = 1;
121113
} else if (index > lastStepIndex) {
122114
index = lastStepIndex;
123-
} else if (steps[index - 1].isHidden) {
124-
// eslint-disable-next-line no-console
125-
console.error('Wizard: Unable to navigate to hidden step.');
126115
}
127116

128117
const currStep = steps[index - 1];
129-
const prevStep = steps[currentStepIndex - 1];
130-
setCurrentStepIndex(index);
118+
const prevStep = steps[activeStepIndex - 1];
131119

132-
return onNavByIndex?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
120+
setActiveStepIndex(index);
121+
return onNavByIndex?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
133122
};
134123

135124
const goToStepById = (steps: WizardControlStep[] = initialSteps, id: number | string) => {
136-
const stepIndex = steps.findIndex(step => step.id === id) + 1;
125+
const step = steps.find(step => step.id === id);
126+
const stepIndex = step?.index;
127+
const lastStepIndex = steps.length + 1;
137128

138-
if (stepIndex > 0 && stepIndex < steps.length + 1 && !steps[stepIndex].isHidden) {
139-
setCurrentStepIndex(stepIndex);
140-
} else {
141-
// eslint-disable-next-line no-console
142-
console.error(`Wizard: Unable to navigate to step with id: ${id}.`);
129+
if (stepIndex > 0 && stepIndex < lastStepIndex && !step.isHidden) {
130+
setActiveStepIndex(stepIndex);
143131
}
144132
};
145133

146134
const goToStepByName = (steps: WizardControlStep[] = initialSteps, name: string) => {
147-
const stepIndex = initialSteps.findIndex(step => step.name === name) + 1;
135+
const step = steps.find(step => step.name === name);
136+
const stepIndex = step?.index;
137+
const lastStepIndex = steps.length + 1;
148138

149-
if (stepIndex > 0 && stepIndex < steps.length + 1 && !steps[stepIndex].isHidden) {
150-
setCurrentStepIndex(stepIndex);
151-
} else {
152-
// eslint-disable-next-line no-console
153-
console.error(`Wizard: Unable to navigate to step with name: ${name}.`);
139+
if (stepIndex > 0 && stepIndex < lastStepIndex && !step.isHidden) {
140+
setActiveStepIndex(stepIndex);
154141
}
155142
};
156143

157144
return (
158145
<WizardContextProvider
159146
steps={initialSteps}
160-
currentStepIndex={currentStepIndex}
147+
activeStepIndex={activeStepIndex}
161148
footer={footer}
162-
isStepVisitRequired={isStepVisitRequired}
163149
onNext={goToNextStep}
164150
onBack={goToPrevStep}
165151
onClose={onClose}
@@ -176,37 +162,32 @@ export const Wizard = ({
176162
{...wrapperProps}
177163
>
178164
{header}
179-
<WizardInternal nav={nav} hasUnmountedSteps={hasUnmountedSteps} isStepVisitRequired={isStepVisitRequired} />
165+
<WizardInternal nav={nav} isStepVisitRequired={isStepVisitRequired} />
180166
</div>
181167
</WizardContextProvider>
182168
);
183169
};
184170

185-
const WizardInternal = ({
186-
nav,
187-
hasUnmountedSteps,
188-
isStepVisitRequired
189-
}: Pick<WizardProps, 'nav' | 'hasUnmountedSteps' | 'isStepVisitRequired'>) => {
190-
const { currentStep, steps, footer, goToStepByIndex } = useWizardContext();
171+
const WizardInternal = ({ nav, isStepVisitRequired }: Pick<WizardProps, 'nav' | 'isStepVisitRequired'>) => {
172+
const { activeStep, steps, footer, goToStepByIndex } = useWizardContext();
191173
const [isNavExpanded, setIsNavExpanded] = React.useState(false);
192174

193175
const wizardNav = React.useMemo(() => {
194176
if (isCustomWizardNav(nav)) {
195-
return typeof nav === 'function' ? nav(isNavExpanded, steps, currentStep, goToStepByIndex) : nav;
177+
return typeof nav === 'function' ? nav(isNavExpanded, steps, activeStep, goToStepByIndex) : nav;
196178
}
197179

198180
return <WizardNavInternal nav={nav} isNavExpanded={isNavExpanded} isStepVisitRequired={isStepVisitRequired} />;
199-
}, [currentStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
181+
}, [activeStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
200182

201183
return (
202184
<WizardToggle
203185
nav={wizardNav}
204186
footer={footer}
205187
steps={steps}
206-
currentStep={currentStep}
188+
activeStep={activeStep}
207189
isNavExpanded={isNavExpanded}
208190
toggleNavExpanded={() => setIsNavExpanded(prevIsExpanded => !prevIsExpanded)}
209-
hasUnmountedSteps={hasUnmountedSteps}
210191
/>
211192
);
212193
};

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { css } from '@patternfly/react-styles';
1010
export interface WizardBodyProps {
1111
children: React.ReactNode | React.ReactNode[];
1212
/** Set to true to remove the default body padding */
13-
hasNoBodyPadding?: boolean;
13+
hasNoPadding?: boolean;
1414
/** An aria-label to use for the wrapper element */
1515
'aria-label'?: string;
1616
/** Sets the aria-labelledby attribute for the wrapper element */
@@ -21,13 +21,13 @@ export interface WizardBodyProps {
2121

2222
export const WizardBody = ({
2323
children,
24-
hasNoBodyPadding = false,
24+
hasNoPadding = false,
2525
'aria-label': ariaLabel,
2626
'aria-labelledby': ariaLabelledBy,
2727
component: WrapperComponent = 'div'
2828
}: WizardBodyProps) => (
2929
<WrapperComponent aria-label={ariaLabel} aria-labelledby={ariaLabelledBy} className={css(styles.wizardMain)}>
30-
<div className={css(styles.wizardMainBody, hasNoBodyPadding && styles.modifiers.noPadding)}>{children}</div>
30+
<div className={css(styles.wizardMainBody, hasNoPadding && styles.modifiers.noPadding)}>{children}</div>
3131
</WrapperComponent>
3232
);
3333

0 commit comments

Comments
 (0)