@patternfly/react-core 4.255.0 → 4.255.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/esm/components/Alert/AlertIcon.js +1 -1
  3. package/dist/esm/components/Alert/AlertIcon.js.map +1 -1
  4. package/dist/esm/next/components/Wizard/Wizard.d.ts +1 -3
  5. package/dist/esm/next/components/Wizard/Wizard.d.ts.map +1 -1
  6. package/dist/esm/next/components/Wizard/Wizard.js +36 -45
  7. package/dist/esm/next/components/Wizard/Wizard.js.map +1 -1
  8. package/dist/esm/next/components/Wizard/WizardBody.d.ts +2 -2
  9. package/dist/esm/next/components/Wizard/WizardBody.d.ts.map +1 -1
  10. package/dist/esm/next/components/Wizard/WizardBody.js +2 -2
  11. package/dist/esm/next/components/Wizard/WizardBody.js.map +1 -1
  12. package/dist/esm/next/components/Wizard/WizardContext.d.ts +2 -7
  13. package/dist/esm/next/components/Wizard/WizardContext.d.ts.map +1 -1
  14. package/dist/esm/next/components/Wizard/WizardContext.js +18 -39
  15. package/dist/esm/next/components/Wizard/WizardContext.js.map +1 -1
  16. package/dist/esm/next/components/Wizard/WizardFooter.d.ts +3 -3
  17. package/dist/esm/next/components/Wizard/WizardFooter.d.ts.map +1 -1
  18. package/dist/esm/next/components/Wizard/WizardFooter.js +3 -3
  19. package/dist/esm/next/components/Wizard/WizardFooter.js.map +1 -1
  20. package/dist/esm/next/components/Wizard/WizardNavInternal.d.ts.map +1 -1
  21. package/dist/esm/next/components/Wizard/WizardNavInternal.js +12 -12
  22. package/dist/esm/next/components/Wizard/WizardNavInternal.js.map +1 -1
  23. package/dist/esm/next/components/Wizard/WizardStep.d.ts +1 -3
  24. package/dist/esm/next/components/Wizard/WizardStep.d.ts.map +1 -1
  25. package/dist/esm/next/components/Wizard/WizardStep.js +10 -18
  26. package/dist/esm/next/components/Wizard/WizardStep.js.map +1 -1
  27. package/dist/esm/next/components/Wizard/WizardToggle.d.ts +2 -4
  28. package/dist/esm/next/components/Wizard/WizardToggle.d.ts.map +1 -1
  29. package/dist/esm/next/components/Wizard/WizardToggle.js +19 -16
  30. package/dist/esm/next/components/Wizard/WizardToggle.js.map +1 -1
  31. package/dist/esm/next/components/Wizard/hooks/useWizardFooter.js +3 -3
  32. package/dist/esm/next/components/Wizard/hooks/useWizardFooter.js.map +1 -1
  33. package/dist/esm/next/components/Wizard/types.d.ts +5 -3
  34. package/dist/esm/next/components/Wizard/types.d.ts.map +1 -1
  35. package/dist/esm/next/components/Wizard/types.js.map +1 -1
  36. package/dist/esm/next/components/Wizard/utils.d.ts +3 -3
  37. package/dist/esm/next/components/Wizard/utils.d.ts.map +1 -1
  38. package/dist/esm/next/components/Wizard/utils.js +14 -11
  39. package/dist/esm/next/components/Wizard/utils.js.map +1 -1
  40. package/dist/js/components/Alert/AlertIcon.js +1 -1
  41. package/dist/js/components/Alert/AlertIcon.js.map +1 -1
  42. package/dist/js/next/components/Wizard/Wizard.d.ts +1 -3
  43. package/dist/js/next/components/Wizard/Wizard.d.ts.map +1 -1
  44. package/dist/js/next/components/Wizard/Wizard.js +36 -45
  45. package/dist/js/next/components/Wizard/Wizard.js.map +1 -1
  46. package/dist/js/next/components/Wizard/WizardBody.d.ts +2 -2
  47. package/dist/js/next/components/Wizard/WizardBody.d.ts.map +1 -1
  48. package/dist/js/next/components/Wizard/WizardBody.js +2 -2
  49. package/dist/js/next/components/Wizard/WizardBody.js.map +1 -1
  50. package/dist/js/next/components/Wizard/WizardContext.d.ts +2 -7
  51. package/dist/js/next/components/Wizard/WizardContext.d.ts.map +1 -1
  52. package/dist/js/next/components/Wizard/WizardContext.js +15 -37
  53. package/dist/js/next/components/Wizard/WizardContext.js.map +1 -1
  54. package/dist/js/next/components/Wizard/WizardFooter.d.ts +3 -3
  55. package/dist/js/next/components/Wizard/WizardFooter.d.ts.map +1 -1
  56. package/dist/js/next/components/Wizard/WizardFooter.js +3 -3
  57. package/dist/js/next/components/Wizard/WizardFooter.js.map +1 -1
  58. package/dist/js/next/components/Wizard/WizardNavInternal.d.ts.map +1 -1
  59. package/dist/js/next/components/Wizard/WizardNavInternal.js +12 -12
  60. package/dist/js/next/components/Wizard/WizardNavInternal.js.map +1 -1
  61. package/dist/js/next/components/Wizard/WizardStep.d.ts +1 -3
  62. package/dist/js/next/components/Wizard/WizardStep.d.ts.map +1 -1
  63. package/dist/js/next/components/Wizard/WizardStep.js +9 -18
  64. package/dist/js/next/components/Wizard/WizardStep.js.map +1 -1
  65. package/dist/js/next/components/Wizard/WizardToggle.d.ts +2 -4
  66. package/dist/js/next/components/Wizard/WizardToggle.d.ts.map +1 -1
  67. package/dist/js/next/components/Wizard/WizardToggle.js +18 -16
  68. package/dist/js/next/components/Wizard/WizardToggle.js.map +1 -1
  69. package/dist/js/next/components/Wizard/hooks/useWizardFooter.js +3 -3
  70. package/dist/js/next/components/Wizard/hooks/useWizardFooter.js.map +1 -1
  71. package/dist/js/next/components/Wizard/types.d.ts +5 -3
  72. package/dist/js/next/components/Wizard/types.d.ts.map +1 -1
  73. package/dist/js/next/components/Wizard/types.js.map +1 -1
  74. package/dist/js/next/components/Wizard/utils.d.ts +3 -3
  75. package/dist/js/next/components/Wizard/utils.d.ts.map +1 -1
  76. package/dist/js/next/components/Wizard/utils.js +16 -13
  77. package/dist/js/next/components/Wizard/utils.js.map +1 -1
  78. package/dist/umd/react-core.min.css +812 -812
  79. package/dist/umd/react-core.min.js +1 -1
  80. package/package.json +2 -2
  81. package/src/components/Alert/AlertIcon.tsx +2 -2
  82. package/src/components/Button/__tests__/Button.test.tsx +16 -7
  83. package/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +36 -0
  84. package/src/components/Button/examples/ButtonProgress.tsx +15 -2
  85. package/src/components/Wizard/examples/Wizard.md +11 -7
  86. package/src/next/components/Wizard/Wizard.tsx +35 -54
  87. package/src/next/components/Wizard/WizardBody.tsx +3 -3
  88. package/src/next/components/Wizard/WizardContext.tsx +29 -61
  89. package/src/next/components/Wizard/WizardFooter.tsx +6 -6
  90. package/src/next/components/Wizard/WizardNavInternal.tsx +18 -17
  91. package/src/next/components/Wizard/WizardStep.tsx +19 -30
  92. package/src/next/components/Wizard/WizardToggle.tsx +22 -24
  93. package/src/next/components/Wizard/__tests__/Wizard.test.tsx +1 -21
  94. package/src/next/components/Wizard/__tests__/WizardBody.test.tsx +2 -2
  95. package/src/next/components/Wizard/__tests__/WizardFooter.test.tsx +5 -5
  96. package/src/next/components/Wizard/__tests__/WizardStep.test.tsx +22 -76
  97. package/src/next/components/Wizard/__tests__/WizardToggle.test.tsx +7 -11
  98. package/src/next/components/Wizard/__tests__/utils.test.tsx +3 -3
  99. package/src/next/components/Wizard/examples/Wizard.md +4 -4
  100. package/src/next/components/Wizard/examples/WizardCustomNav.tsx +4 -4
  101. package/src/next/components/Wizard/examples/WizardKitchenSink.tsx +74 -85
  102. package/src/next/components/Wizard/hooks/__tests__/useWizardFooter.test.tsx +4 -4
  103. package/src/next/components/Wizard/hooks/useWizardFooter.tsx +3 -3
  104. package/src/next/components/Wizard/types.tsx +5 -3
  105. package/src/next/components/Wizard/utils.ts +35 -25
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/react-core",
3
- "version": "4.255.0",
3
+ "version": "4.255.2",
4
4
  "description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
5
5
  "main": "dist/js/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -70,5 +70,5 @@
70
70
  "react": "^16.8 || ^17 || ^18",
71
71
  "react-dom": "^16.8 || ^17 || ^18"
72
72
  },
73
- "gitHead": "d37ff721bbea043cbb5c51b95829f8143d37c80c"
73
+ "gitHead": "16b0f452e3031ba81eda21a873e961bc6aab51fd"
74
74
  }
@@ -26,9 +26,9 @@ export interface AlertIconProps extends React.HTMLProps<HTMLDivElement> {
26
26
 
27
27
  export const AlertIcon = ({ variant, customIcon, className = '', ...props }: AlertIconProps) => {
28
28
  const Icon = variantIcons[variant];
29
- return (
29
+ return Icon ? (
30
30
  <div {...props} className={css(styles.alertIcon, className)}>
31
31
  {customIcon || <Icon />}
32
32
  </div>
33
- );
33
+ ) : null;
34
34
  };
@@ -103,6 +103,22 @@ describe('Button', () => {
103
103
  expect(asFragment()).toMatchSnapshot();
104
104
  });
105
105
 
106
+ test('isLoading inline link', () => {
107
+ const { asFragment } = render(
108
+ <Button variant="link" isInline isLoading aria-label="Loading" spinnerAriaValueText="Loading">
109
+ Loading Button
110
+ </Button>
111
+ );
112
+ expect(asFragment()).toMatchSnapshot();
113
+ });
114
+
115
+ test('isLoading icon only', () => {
116
+ const { asFragment } = render(
117
+ <Button variant="plain" isLoading aria-label="Upload" spinnerAriaValueText="Loading" icon={<div>ICON</div>} />
118
+ );
119
+ expect(asFragment()).toMatchSnapshot();
120
+ });
121
+
106
122
  test('allows passing in a string as the component', () => {
107
123
  const component = 'a';
108
124
  render(<Button component={component}>anchor button</Button>);
@@ -130,11 +146,4 @@ describe('Button', () => {
130
146
  render(<Button tabIndex={0}>TabIndex 0 Button</Button>);
131
147
  expect(screen.getByRole('button')).toHaveAttribute('tabindex', '0');
132
148
  });
133
-
134
- test('isLoading icon only', () => {
135
- const { asFragment } = render(
136
- <Button variant="plain" isLoading aria-label="Upload" spinnerAriaValueText="Loading" icon={<div>ICON</div>} />
137
- );
138
- expect(asFragment()).toMatchSnapshot();
139
- });
140
149
  });
@@ -240,6 +240,42 @@ exports[`Button isLoading icon only 1`] = `
240
240
  </DocumentFragment>
241
241
  `;
242
242
 
243
+ exports[`Button isLoading inline link 1`] = `
244
+ <DocumentFragment>
245
+ <button
246
+ aria-disabled="false"
247
+ aria-label="Loading"
248
+ class="pf-c-button pf-m-link pf-m-inline pf-m-progress pf-m-in-progress"
249
+ data-ouia-component-id="OUIA-Generated-Button-link-5"
250
+ data-ouia-component-type="PF4/Button"
251
+ data-ouia-safe="true"
252
+ type="button"
253
+ >
254
+ <span
255
+ class="pf-c-button__progress"
256
+ >
257
+ <span
258
+ aria-label="Contents"
259
+ aria-valuetext="Loading"
260
+ class="pf-c-spinner pf-m-md"
261
+ role="progressbar"
262
+ >
263
+ <span
264
+ class="pf-c-spinner__clipper"
265
+ />
266
+ <span
267
+ class="pf-c-spinner__lead-ball"
268
+ />
269
+ <span
270
+ class="pf-c-spinner__tail-ball"
271
+ />
272
+ </span>
273
+ </span>
274
+ Loading Button
275
+ </button>
276
+ </DocumentFragment>
277
+ `;
278
+
243
279
  exports[`Button isSmall 1`] = `
244
280
  <DocumentFragment>
245
281
  <button
@@ -12,6 +12,7 @@ interface LoadingPropsType {
12
12
  export const ButtonProgress: React.FunctionComponent = () => {
13
13
  const [isPrimaryLoading, setIsPrimaryLoading] = React.useState<boolean>(true);
14
14
  const [isSecondaryLoading, setIsSecondaryLoading] = React.useState<boolean>(true);
15
+ const [isInlineLoading, setIsInlineLoading] = React.useState<boolean>(true);
15
16
  const [isUploading, setIsUploading] = React.useState<boolean>(false);
16
17
 
17
18
  const primaryLoadingProps = {} as LoadingPropsType;
@@ -24,6 +25,11 @@ export const ButtonProgress: React.FunctionComponent = () => {
24
25
  secondaryLoadingProps.spinnerAriaLabel = 'Content being loaded';
25
26
  secondaryLoadingProps.isLoading = isSecondaryLoading;
26
27
 
28
+ const inlineLoadingProps = {} as LoadingPropsType;
29
+ inlineLoadingProps.spinnerAriaValueText = 'Loading';
30
+ inlineLoadingProps.spinnerAriaLabel = 'Content being loaded';
31
+ inlineLoadingProps.isLoading = isInlineLoading;
32
+
27
33
  const uploadingProps = {} as LoadingPropsType;
28
34
  uploadingProps.spinnerAriaValueText = 'Loading';
29
35
  uploadingProps.spinnerAriaLabel = 'Uploading data';
@@ -37,18 +43,25 @@ export const ButtonProgress: React.FunctionComponent = () => {
37
43
  onClick={() => setIsPrimaryLoading(!isPrimaryLoading)}
38
44
  {...primaryLoadingProps}
39
45
  >
40
- {isPrimaryLoading ? 'Pause loading logs' : 'Resume loading logs'}
46
+ {isPrimaryLoading ? 'Click to stop loading' : 'Click to start loading'}
41
47
  </Button>{' '}
42
48
  <Button variant="secondary" onClick={() => setIsSecondaryLoading(!isSecondaryLoading)} {...secondaryLoadingProps}>
43
49
  {isSecondaryLoading ? 'Click to stop loading' : 'Click to start loading'}
44
50
  </Button>{' '}
51
+ <br />
52
+ <br />
45
53
  <Button
46
54
  variant="plain"
47
55
  {...(!isUploading && { 'aria-label': 'Upload' })}
48
56
  onClick={() => setIsUploading(!isUploading)}
49
57
  icon={<UploadIcon />}
50
58
  {...uploadingProps}
51
- />
59
+ />{' '}
60
+ <br />
61
+ <br />
62
+ <Button variant="link" isInline onClick={() => setIsInlineLoading(!isInlineLoading)} {...inlineLoadingProps}>
63
+ {isInlineLoading ? 'Pause loading logs' : 'Resume loading logs'}
64
+ </Button>{' '}
52
65
  </React.Fragment>
53
66
  );
54
67
  };
@@ -134,8 +134,10 @@ class IncrementallyEnabledStepsWizard extends React.Component {
134
134
  stepIdReached: 1
135
135
  };
136
136
  this.onNext = ({ id }) => {
137
+ const [, orderIndex] = id.split('-');
138
+
137
139
  this.setState({
138
- stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
140
+ stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached
139
141
  });
140
142
  };
141
143
  this.closeWizard = () => {
@@ -147,27 +149,27 @@ class IncrementallyEnabledStepsWizard extends React.Component {
147
149
  const { stepIdReached } = this.state;
148
150
 
149
151
  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> },
151
153
  {
152
- id: 'incrementally-enabled-2',
154
+ id: 'incrementallyEnabled-2',
153
155
  name: 'Second step',
154
156
  component: <p>Step 2 content</p>,
155
157
  canJumpTo: stepIdReached >= 2
156
158
  },
157
159
  {
158
- id: 'incrementally-enabled-3',
160
+ id: 'incrementallyEnabled-3',
159
161
  name: 'Third step',
160
162
  component: <p>Step 3 content</p>,
161
163
  canJumpTo: stepIdReached >= 3
162
164
  },
163
165
  {
164
- id: 'incrementally-enabled-4',
166
+ id: 'incrementallyEnabled-4',
165
167
  name: 'Fourth step',
166
168
  component: <p>Step 4 content</p>,
167
169
  canJumpTo: stepIdReached >= 4
168
170
  },
169
171
  {
170
- id: 'incrementally-enabled-5',
172
+ id: 'incrementallyEnabled-5',
171
173
  name: 'Review',
172
174
  component: <p>Review step content</p>,
173
175
  nextButtonText: 'Finish',
@@ -312,8 +314,10 @@ class ValidationWizard extends React.Component {
312
314
 
313
315
  this.onNext = ({ id, name }, { prevId, prevName }) => {
314
316
  console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
317
+ const [, orderIndex] = id.split('-');
318
+
315
319
  this.setState({
316
- stepIdReached: this.state.stepIdReached < id ? id : this.state.stepIdReached
320
+ stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached
317
321
  });
318
322
  this.areAllStepsValid();
319
323
  };
@@ -42,8 +42,6 @@ export interface WizardProps extends React.HTMLProps<HTMLDivElement> {
42
42
  height?: number | string;
43
43
  /** Disables navigation items that haven't been visited. Defaults to false */
44
44
  isStepVisitRequired?: boolean;
45
- /** Flag to unmount inactive steps instead of hiding. Defaults to true */
46
- hasUnmountedSteps?: boolean;
47
45
  /** Callback function when a step in the navigation is clicked */
48
46
  onNavByIndex?: WizardNavStepFunction;
49
47
  /** Callback function after next button is clicked */
@@ -66,7 +64,6 @@ export const Wizard = ({
66
64
  nav,
67
65
  startIndex = 1,
68
66
  isStepVisitRequired = false,
69
- hasUnmountedSteps = true,
70
67
  onNavByIndex,
71
68
  onNext,
72
69
  onBack,
@@ -74,42 +71,37 @@ export const Wizard = ({
74
71
  onClose,
75
72
  ...wrapperProps
76
73
  }: WizardProps) => {
77
- const [currentStepIndex, setCurrentStepIndex] = React.useState(startIndex);
74
+ const [activeStepIndex, setActiveStepIndex] = React.useState(startIndex);
78
75
  const initialSteps = buildSteps(children);
79
76
 
80
77
  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;
83
80
 
84
- if (currentStepIndex >= steps.length || !newStepIndex) {
81
+ if (activeStepIndex >= steps.length || !newStepIndex) {
85
82
  return onSave ? onSave() : onClose?.();
86
83
  }
87
84
 
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];
94
87
 
95
- return onNext?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
88
+ setActiveStepIndex(newStepIndex);
89
+ return onNext?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
96
90
  };
97
91
 
98
92
  const goToPrevStep = (steps: WizardControlStep[] = initialSteps) => {
99
93
  const newStepIndex =
100
94
  findLastIndex(
101
95
  steps,
102
- (step: WizardControlStep, index: number) =>
103
- index + 1 < currentStepIndex && !step.isHidden && !isWizardParentStep(step)
96
+ (step: WizardControlStep) => step.index < activeStepIndex && !step.isHidden && !isWizardParentStep(step)
104
97
  ) + 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];
111
102
 
112
- return onBack?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
103
+ setActiveStepIndex(newStepIndex);
104
+ return onBack?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
113
105
  };
114
106
 
115
107
  const goToStepByIndex = (steps: WizardControlStep[] = initialSteps, index: number) => {
@@ -120,46 +112,40 @@ export const Wizard = ({
120
112
  index = 1;
121
113
  } else if (index > lastStepIndex) {
122
114
  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.');
126
115
  }
127
116
 
128
117
  const currStep = steps[index - 1];
129
- const prevStep = steps[currentStepIndex - 1];
130
- setCurrentStepIndex(index);
118
+ const prevStep = steps[activeStepIndex - 1];
131
119
 
132
- return onNavByIndex?.(normalizeNavStep(currStep, steps), normalizeNavStep(prevStep, steps));
120
+ setActiveStepIndex(index);
121
+ return onNavByIndex?.(normalizeNavStep(currStep), normalizeNavStep(prevStep));
133
122
  };
134
123
 
135
124
  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;
137
128
 
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);
143
131
  }
144
132
  };
145
133
 
146
134
  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;
148
138
 
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);
154
141
  }
155
142
  };
156
143
 
157
144
  return (
158
145
  <WizardContextProvider
159
146
  steps={initialSteps}
160
- currentStepIndex={currentStepIndex}
147
+ activeStepIndex={activeStepIndex}
161
148
  footer={footer}
162
- isStepVisitRequired={isStepVisitRequired}
163
149
  onNext={goToNextStep}
164
150
  onBack={goToPrevStep}
165
151
  onClose={onClose}
@@ -176,37 +162,32 @@ export const Wizard = ({
176
162
  {...wrapperProps}
177
163
  >
178
164
  {header}
179
- <WizardInternal nav={nav} hasUnmountedSteps={hasUnmountedSteps} isStepVisitRequired={isStepVisitRequired} />
165
+ <WizardInternal nav={nav} isStepVisitRequired={isStepVisitRequired} />
180
166
  </div>
181
167
  </WizardContextProvider>
182
168
  );
183
169
  };
184
170
 
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();
191
173
  const [isNavExpanded, setIsNavExpanded] = React.useState(false);
192
174
 
193
175
  const wizardNav = React.useMemo(() => {
194
176
  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;
196
178
  }
197
179
 
198
180
  return <WizardNavInternal nav={nav} isNavExpanded={isNavExpanded} isStepVisitRequired={isStepVisitRequired} />;
199
- }, [currentStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
181
+ }, [activeStep, isStepVisitRequired, goToStepByIndex, isNavExpanded, nav, steps]);
200
182
 
201
183
  return (
202
184
  <WizardToggle
203
185
  nav={wizardNav}
204
186
  footer={footer}
205
187
  steps={steps}
206
- currentStep={currentStep}
188
+ activeStep={activeStep}
207
189
  isNavExpanded={isNavExpanded}
208
190
  toggleNavExpanded={() => setIsNavExpanded(prevIsExpanded => !prevIsExpanded)}
209
- hasUnmountedSteps={hasUnmountedSteps}
210
191
  />
211
192
  );
212
193
  };
@@ -10,7 +10,7 @@ import { css } from '@patternfly/react-styles';
10
10
  export interface WizardBodyProps {
11
11
  children: React.ReactNode | React.ReactNode[];
12
12
  /** Set to true to remove the default body padding */
13
- hasNoBodyPadding?: boolean;
13
+ hasNoPadding?: boolean;
14
14
  /** An aria-label to use for the wrapper element */
15
15
  'aria-label'?: string;
16
16
  /** Sets the aria-labelledby attribute for the wrapper element */
@@ -21,13 +21,13 @@ export interface WizardBodyProps {
21
21
 
22
22
  export const WizardBody = ({
23
23
  children,
24
- hasNoBodyPadding = false,
24
+ hasNoPadding = false,
25
25
  'aria-label': ariaLabel,
26
26
  'aria-labelledby': ariaLabelledBy,
27
27
  component: WrapperComponent = 'div'
28
28
  }: WizardBodyProps) => (
29
29
  <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>
31
31
  </WrapperComponent>
32
32
  );
33
33
 
@@ -1,16 +1,14 @@
1
1
  import React from 'react';
2
2
 
3
- import { isCustomWizardFooter, isWizardParentStep, WizardControlStep, WizardFooterType } from './types';
4
- import { getCurrentStep } from './utils';
3
+ import { isCustomWizardFooter, WizardControlStep, WizardFooterType } from './types';
4
+ import { getActiveStep } from './utils';
5
5
  import { WizardFooter, WizardFooterProps } from './WizardFooter';
6
6
 
7
7
  export interface WizardContextProps {
8
8
  /** List of steps */
9
9
  steps: WizardControlStep[];
10
10
  /** Current step */
11
- currentStep: WizardControlStep;
12
- /** Current step index */
13
- currentStepIndex: number;
11
+ activeStep: WizardControlStep;
14
12
  /** Footer element */
15
13
  footer: React.ReactElement;
16
14
  /** Navigate to the next step */
@@ -31,17 +29,14 @@ export interface WizardContextProps {
31
29
  getStep: (stepId: number | string) => WizardControlStep;
32
30
  /** Set step by ID */
33
31
  setStep: (step: Pick<WizardControlStep, 'id'> & Partial<WizardControlStep>) => void;
34
- /** Toggle step visibility by ID */
35
- toggleStep: (stepId: number | string, isHidden: boolean) => void;
36
32
  }
37
33
 
38
34
  export const WizardContext = React.createContext({} as WizardContextProps);
39
35
 
40
36
  export interface WizardContextProviderProps {
41
37
  steps: WizardControlStep[];
42
- currentStepIndex: number;
38
+ activeStepIndex: number;
43
39
  footer: WizardFooterType;
44
- isStepVisitRequired: boolean;
45
40
  children: React.ReactElement;
46
41
  onNext(steps: WizardControlStep[]): void;
47
42
  onBack(steps: WizardControlStep[]): void;
@@ -54,8 +49,7 @@ export interface WizardContextProviderProps {
54
49
  export const WizardContextProvider: React.FunctionComponent<WizardContextProviderProps> = ({
55
50
  steps: initialSteps,
56
51
  footer: initialFooter,
57
- currentStepIndex,
58
- isStepVisitRequired,
52
+ activeStepIndex,
59
53
  children,
60
54
  onNext,
61
55
  onBack,
@@ -64,43 +58,58 @@ export const WizardContextProvider: React.FunctionComponent<WizardContextProvide
64
58
  goToStepByName,
65
59
  goToStepByIndex
66
60
  }) => {
67
- const [steps, setSteps] = React.useState(initialSteps);
61
+ const [currentSteps, setCurrentSteps] = React.useState(initialSteps);
68
62
  const [currentFooter, setCurrentFooter] = React.useState(
69
63
  typeof initialFooter !== 'function' ? initialFooter : undefined
70
64
  );
71
- const currentStep = getCurrentStep(steps, currentStepIndex);
65
+
66
+ // Combined initial and current state steps
67
+ const steps = React.useMemo(
68
+ () =>
69
+ currentSteps.map((currentStepProps, index) => {
70
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
71
+ const { isVisited, ...initialStepProps } = initialSteps[index];
72
+
73
+ return {
74
+ ...currentStepProps,
75
+ ...initialStepProps
76
+ };
77
+ }),
78
+ [initialSteps, currentSteps]
79
+ );
80
+ const activeStep = getActiveStep(steps, activeStepIndex);
72
81
 
73
82
  const goToNextStep = React.useCallback(() => onNext(steps), [onNext, steps]);
74
83
  const goToPrevStep = React.useCallback(() => onBack(steps), [onBack, steps]);
75
84
 
76
85
  const footer = React.useMemo(() => {
77
- const wizardFooter = currentFooter || initialFooter;
86
+ const wizardFooter = activeStep?.footer || currentFooter || initialFooter;
78
87
 
79
88
  if (isCustomWizardFooter(wizardFooter)) {
80
89
  const customFooter = wizardFooter;
81
90
 
82
91
  return typeof customFooter === 'function'
83
- ? customFooter(currentStep, goToNextStep, goToPrevStep, onClose)
92
+ ? customFooter(activeStep, goToNextStep, goToPrevStep, onClose)
84
93
  : customFooter;
85
94
  }
86
95
 
87
96
  return (
88
97
  <WizardFooter
89
- currentStep={currentStep}
98
+ activeStep={activeStep}
90
99
  onNext={goToNextStep}
91
100
  onBack={goToPrevStep}
92
101
  onClose={onClose}
93
- isBackDisabled={currentStep?.id === steps[0]?.id}
102
+ isBackDisabled={activeStep?.id === steps[0]?.id}
94
103
  {...wizardFooter}
95
104
  />
96
105
  );
97
- }, [currentFooter, initialFooter, currentStep, goToNextStep, goToPrevStep, onClose, steps]);
106
+ }, [currentFooter, initialFooter, activeStep, goToNextStep, goToPrevStep, onClose, steps]);
98
107
 
99
108
  const getStep = React.useCallback((stepId: string | number) => steps.find(step => step.id === stepId), [steps]);
100
109
 
101
110
  const setStep = React.useCallback(
102
111
  (step: Pick<WizardControlStep, 'id'> & Partial<WizardControlStep>) =>
103
- setSteps(prevSteps =>
112
+ setCurrentSteps(prevSteps =>
104
113
  prevSteps.map(prevStep => {
105
114
  if (prevStep.id === step.id) {
106
115
  return { ...prevStep, ...step };
@@ -112,56 +121,15 @@ export const WizardContextProvider: React.FunctionComponent<WizardContextProvide
112
121
  []
113
122
  );
114
123
 
115
- const toggleStep = React.useCallback(
116
- (stepId: string | number, isHidden: boolean) =>
117
- setSteps(prevSteps => {
118
- let stepToHide: WizardControlStep;
119
-
120
- return prevSteps.map(prevStep => {
121
- if (prevStep.id === stepId) {
122
- // Don't hide the currently active step or its parent (if a sub-step).
123
- if (
124
- isHidden &&
125
- (currentStep.id === prevStep.id ||
126
- (isWizardParentStep(prevStep) && prevStep.subStepIds.includes(currentStep.id)))
127
- ) {
128
- // eslint-disable-next-line no-console
129
- console.error('Wizard: Unable to hide the current step or its parent.');
130
- return prevStep;
131
- }
132
-
133
- stepToHide = { ...prevStep, isHidden };
134
- return stepToHide;
135
- }
136
-
137
- // When isStepVisitRequired is enabled, if the step was previously hidden and not visited yet,
138
- // when it is shown, all steps beyond it should be disabled to ensure it is visited.
139
- if (
140
- isStepVisitRequired &&
141
- stepToHide?.isHidden === false &&
142
- !stepToHide?.isVisited &&
143
- prevSteps.indexOf(stepToHide) < prevSteps.indexOf(prevStep)
144
- ) {
145
- return { ...prevStep, isVisited: false };
146
- }
147
-
148
- return prevStep;
149
- });
150
- }),
151
- [currentStep.id, isStepVisitRequired]
152
- );
153
-
154
124
  return (
155
125
  <WizardContext.Provider
156
126
  value={{
157
127
  steps,
158
- currentStep,
159
- currentStepIndex,
128
+ activeStep,
160
129
  footer,
161
130
  onClose,
162
131
  getStep,
163
132
  setStep,
164
- toggleStep,
165
133
  setFooter: setCurrentFooter,
166
134
  onNext: goToNextStep,
167
135
  onBack: goToPrevStep,
@@ -11,8 +11,8 @@ import { isCustomWizardFooter, WizardControlStep, WizardNavStepFunction } from '
11
11
  */
12
12
 
13
13
  export interface WizardFooterProps {
14
- /** The current step */
15
- currentStep: WizardControlStep;
14
+ /** The active step */
15
+ activeStep: WizardControlStep;
16
16
  /** Next button callback */
17
17
  onNext: () => WizardNavStepFunction | void;
18
18
  /** Back button callback */
@@ -43,9 +43,9 @@ export const WizardFooterWrapper = ({ children }: WizardFooterWrapperProps) => (
43
43
  <footer className={css(styles.wizardFooter)}>{children}</footer>
44
44
  );
45
45
 
46
- export const WizardFooter = ({ currentStep, ...internalProps }: WizardFooterProps) => {
47
- const currentStepFooter = !isCustomWizardFooter(currentStep.footer) && currentStep.footer;
48
- return <InternalWizardFooter {...internalProps} {...currentStepFooter} />;
46
+ export const WizardFooter = ({ activeStep, ...internalProps }: WizardFooterProps) => {
47
+ const activeStepFooter = !isCustomWizardFooter(activeStep.footer) && activeStep.footer;
48
+ return <InternalWizardFooter {...internalProps} {...activeStepFooter} />;
49
49
  };
50
50
 
51
51
  const InternalWizardFooter = ({
@@ -59,7 +59,7 @@ const InternalWizardFooter = ({
59
59
  nextButtonText = 'Next',
60
60
  backButtonText = 'Back',
61
61
  cancelButtonText = 'Cancel'
62
- }: Omit<WizardFooterProps, 'currentStep'>) => (
62
+ }: Omit<WizardFooterProps, 'activeStep'>) => (
63
63
  <WizardFooterWrapper>
64
64
  <Button variant={ButtonVariant.primary} type="submit" onClick={onNext} isDisabled={isNextDisabled}>
65
65
  {nextButtonText}