Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions packages/react-core/src/components/Wizard/examples/Wizard.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand All @@ -146,27 +148,27 @@ class IncrementallyEnabledStepsWizard extends React.Component {
const { stepIdReached } = this.state;

const steps = [
{ id: 'incrementally-enabled-1', name: 'First step', component: <p>Step 1 content</p> },
{ id: 'incrementallyEnabled-1', name: 'First step', component: <p>Step 1 content</p> },
{
id: 'incrementally-enabled-2',
id: 'incrementallyEnabled-2',
name: 'Second step',
component: <p>Step 2 content</p>,
canJumpTo: stepIdReached >= 2
},
{
id: 'incrementally-enabled-3',
id: 'incrementallyEnabled-3',
name: 'Third step',
component: <p>Step 3 content</p>,
canJumpTo: stepIdReached >= 3
},
{
id: 'incrementally-enabled-4',
id: 'incrementallyEnabled-4',
name: 'Fourth step',
component: <p>Step 4 content</p>,
canJumpTo: stepIdReached >= 4
},
{
id: 'incrementally-enabled-5',
id: 'incrementallyEnabled-5',
name: 'Review',
component: <p>Review step content</p>,
nextButtonText: 'Finish',
Expand Down Expand Up @@ -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();
};
Expand Down Expand Up @@ -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');
};
Expand Down
89 changes: 35 additions & 54 deletions packages/react-core/src/next/components/Wizard/Wizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ export interface WizardProps extends React.HTMLProps<HTMLDivElement> {
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 */
Expand All @@ -66,50 +64,44 @@ export const Wizard = ({
nav,
startIndex = 1,
isStepVisitRequired = false,
hasUnmountedSteps = true,
onNavByIndex,
onNext,
onBack,
onSave,
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) => {
Expand All @@ -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 (
<WizardContextProvider
steps={initialSteps}
currentStepIndex={currentStepIndex}
activeStepIndex={activeStepIndex}
footer={footer}
isStepVisitRequired={isStepVisitRequired}
onNext={goToNextStep}
onBack={goToPrevStep}
onClose={onClose}
Expand All @@ -176,37 +162,32 @@ export const Wizard = ({
{...wrapperProps}
>
{header}
<WizardInternal nav={nav} hasUnmountedSteps={hasUnmountedSteps} isStepVisitRequired={isStepVisitRequired} />
<WizardInternal nav={nav} isStepVisitRequired={isStepVisitRequired} />
</div>
</WizardContextProvider>
);
};

const WizardInternal = ({
nav,
hasUnmountedSteps,
isStepVisitRequired
}: Pick<WizardProps, 'nav' | 'hasUnmountedSteps' | 'isStepVisitRequired'>) => {
const { currentStep, steps, footer, goToStepByIndex } = useWizardContext();
const WizardInternal = ({ nav, isStepVisitRequired }: Pick<WizardProps, 'nav' | 'isStepVisitRequired'>) => {
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 <WizardNavInternal nav={nav} isNavExpanded={isNavExpanded} isStepVisitRequired={isStepVisitRequired} />;
}, [currentStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
}, [activeStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);

return (
<WizardToggle
nav={wizardNav}
footer={footer}
steps={steps}
currentStep={currentStep}
activeStep={activeStep}
isNavExpanded={isNavExpanded}
toggleNavExpanded={() => setIsNavExpanded(prevIsExpanded => !prevIsExpanded)}
hasUnmountedSteps={hasUnmountedSteps}
/>
);
};
Expand Down
6 changes: 3 additions & 3 deletions packages/react-core/src/next/components/Wizard/WizardBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

/** An aria-label to use for the wrapper element */
'aria-label'?: string;
/** Sets the aria-labelledby attribute for the wrapper element */
Expand All @@ -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) => (
<WrapperComponent aria-label={ariaLabel} aria-labelledby={ariaLabelledBy} className={css(styles.wizardMain)}>
<div className={css(styles.wizardMainBody, hasNoBodyPadding && styles.modifiers.noPadding)}>{children}</div>
<div className={css(styles.wizardMainBody, hasNoPadding && styles.modifiers.noPadding)}>{children}</div>
</WrapperComponent>
);

Expand Down
Loading