@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.
- package/CHANGELOG.md +19 -0
- package/dist/esm/components/Alert/AlertIcon.js +1 -1
- package/dist/esm/components/Alert/AlertIcon.js.map +1 -1
- package/dist/esm/next/components/Wizard/Wizard.d.ts +1 -3
- package/dist/esm/next/components/Wizard/Wizard.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/Wizard.js +36 -45
- package/dist/esm/next/components/Wizard/Wizard.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardBody.d.ts +2 -2
- package/dist/esm/next/components/Wizard/WizardBody.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardBody.js +2 -2
- package/dist/esm/next/components/Wizard/WizardBody.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardContext.d.ts +2 -7
- package/dist/esm/next/components/Wizard/WizardContext.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardContext.js +18 -39
- package/dist/esm/next/components/Wizard/WizardContext.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardFooter.d.ts +3 -3
- package/dist/esm/next/components/Wizard/WizardFooter.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardFooter.js +3 -3
- package/dist/esm/next/components/Wizard/WizardFooter.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardNavInternal.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardNavInternal.js +12 -12
- package/dist/esm/next/components/Wizard/WizardNavInternal.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardStep.d.ts +1 -3
- package/dist/esm/next/components/Wizard/WizardStep.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardStep.js +10 -18
- package/dist/esm/next/components/Wizard/WizardStep.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardToggle.d.ts +2 -4
- package/dist/esm/next/components/Wizard/WizardToggle.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardToggle.js +19 -16
- package/dist/esm/next/components/Wizard/WizardToggle.js.map +1 -1
- package/dist/esm/next/components/Wizard/hooks/useWizardFooter.js +3 -3
- package/dist/esm/next/components/Wizard/hooks/useWizardFooter.js.map +1 -1
- package/dist/esm/next/components/Wizard/types.d.ts +5 -3
- package/dist/esm/next/components/Wizard/types.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/types.js.map +1 -1
- package/dist/esm/next/components/Wizard/utils.d.ts +3 -3
- package/dist/esm/next/components/Wizard/utils.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/utils.js +14 -11
- package/dist/esm/next/components/Wizard/utils.js.map +1 -1
- package/dist/js/components/Alert/AlertIcon.js +1 -1
- package/dist/js/components/Alert/AlertIcon.js.map +1 -1
- package/dist/js/next/components/Wizard/Wizard.d.ts +1 -3
- package/dist/js/next/components/Wizard/Wizard.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/Wizard.js +36 -45
- package/dist/js/next/components/Wizard/Wizard.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardBody.d.ts +2 -2
- package/dist/js/next/components/Wizard/WizardBody.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardBody.js +2 -2
- package/dist/js/next/components/Wizard/WizardBody.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardContext.d.ts +2 -7
- package/dist/js/next/components/Wizard/WizardContext.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardContext.js +15 -37
- package/dist/js/next/components/Wizard/WizardContext.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardFooter.d.ts +3 -3
- package/dist/js/next/components/Wizard/WizardFooter.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardFooter.js +3 -3
- package/dist/js/next/components/Wizard/WizardFooter.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardNavInternal.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardNavInternal.js +12 -12
- package/dist/js/next/components/Wizard/WizardNavInternal.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardStep.d.ts +1 -3
- package/dist/js/next/components/Wizard/WizardStep.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardStep.js +9 -18
- package/dist/js/next/components/Wizard/WizardStep.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardToggle.d.ts +2 -4
- package/dist/js/next/components/Wizard/WizardToggle.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardToggle.js +18 -16
- package/dist/js/next/components/Wizard/WizardToggle.js.map +1 -1
- package/dist/js/next/components/Wizard/hooks/useWizardFooter.js +3 -3
- package/dist/js/next/components/Wizard/hooks/useWizardFooter.js.map +1 -1
- package/dist/js/next/components/Wizard/types.d.ts +5 -3
- package/dist/js/next/components/Wizard/types.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/types.js.map +1 -1
- package/dist/js/next/components/Wizard/utils.d.ts +3 -3
- package/dist/js/next/components/Wizard/utils.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/utils.js +16 -13
- package/dist/js/next/components/Wizard/utils.js.map +1 -1
- package/dist/umd/react-core.min.css +812 -812
- package/dist/umd/react-core.min.js +1 -1
- package/package.json +2 -2
- package/src/components/Alert/AlertIcon.tsx +2 -2
- package/src/components/Button/__tests__/Button.test.tsx +16 -7
- package/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +36 -0
- package/src/components/Button/examples/ButtonProgress.tsx +15 -2
- package/src/components/Wizard/examples/Wizard.md +11 -7
- package/src/next/components/Wizard/Wizard.tsx +35 -54
- package/src/next/components/Wizard/WizardBody.tsx +3 -3
- package/src/next/components/Wizard/WizardContext.tsx +29 -61
- package/src/next/components/Wizard/WizardFooter.tsx +6 -6
- package/src/next/components/Wizard/WizardNavInternal.tsx +18 -17
- package/src/next/components/Wizard/WizardStep.tsx +19 -30
- package/src/next/components/Wizard/WizardToggle.tsx +22 -24
- package/src/next/components/Wizard/__tests__/Wizard.test.tsx +1 -21
- package/src/next/components/Wizard/__tests__/WizardBody.test.tsx +2 -2
- package/src/next/components/Wizard/__tests__/WizardFooter.test.tsx +5 -5
- package/src/next/components/Wizard/__tests__/WizardStep.test.tsx +22 -76
- package/src/next/components/Wizard/__tests__/WizardToggle.test.tsx +7 -11
- package/src/next/components/Wizard/__tests__/utils.test.tsx +3 -3
- package/src/next/components/Wizard/examples/Wizard.md +4 -4
- package/src/next/components/Wizard/examples/WizardCustomNav.tsx +4 -4
- package/src/next/components/Wizard/examples/WizardKitchenSink.tsx +74 -85
- package/src/next/components/Wizard/hooks/__tests__/useWizardFooter.test.tsx +4 -4
- package/src/next/components/Wizard/hooks/useWizardFooter.tsx +3 -3
- package/src/next/components/Wizard/types.tsx +5 -3
- 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.
|
|
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": "
|
|
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 ? '
|
|
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 <
|
|
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: '
|
|
152
|
+
{ id: 'incrementallyEnabled-1', name: 'First step', component: <p>Step 1 content</p> },
|
|
151
153
|
{
|
|
152
|
-
id: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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 <
|
|
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 [
|
|
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
|
-
|
|
78
|
+
const newStepIndex = steps.find(step => step.index > activeStepIndex && !step.isHidden && !isWizardParentStep(step))
|
|
79
|
+
?.index;
|
|
83
80
|
|
|
84
|
-
if (
|
|
81
|
+
if (activeStepIndex >= steps.length || !newStepIndex) {
|
|
85
82
|
return onSave ? onSave() : onClose?.();
|
|
86
83
|
}
|
|
87
84
|
|
|
88
|
-
const currStep = isWizardParentStep(steps[
|
|
89
|
-
|
|
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
|
-
|
|
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
|
|
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[
|
|
106
|
-
? steps[
|
|
107
|
-
: steps[
|
|
108
|
-
const prevStep = steps[
|
|
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
|
-
|
|
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[
|
|
130
|
-
setCurrentStepIndex(index);
|
|
118
|
+
const prevStep = steps[activeStepIndex - 1];
|
|
131
119
|
|
|
132
|
-
|
|
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
|
|
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 <
|
|
139
|
-
|
|
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
|
|
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 <
|
|
150
|
-
|
|
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
|
-
|
|
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}
|
|
165
|
+
<WizardInternal nav={nav} isStepVisitRequired={isStepVisitRequired} />
|
|
180
166
|
</div>
|
|
181
167
|
</WizardContextProvider>
|
|
182
168
|
);
|
|
183
169
|
};
|
|
184
170
|
|
|
185
|
-
const WizardInternal = ({
|
|
186
|
-
|
|
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,
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
4
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 [
|
|
61
|
+
const [currentSteps, setCurrentSteps] = React.useState(initialSteps);
|
|
68
62
|
const [currentFooter, setCurrentFooter] = React.useState(
|
|
69
63
|
typeof initialFooter !== 'function' ? initialFooter : undefined
|
|
70
64
|
);
|
|
71
|
-
|
|
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(
|
|
92
|
+
? customFooter(activeStep, goToNextStep, goToPrevStep, onClose)
|
|
84
93
|
: customFooter;
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
return (
|
|
88
97
|
<WizardFooter
|
|
89
|
-
|
|
98
|
+
activeStep={activeStep}
|
|
90
99
|
onNext={goToNextStep}
|
|
91
100
|
onBack={goToPrevStep}
|
|
92
101
|
onClose={onClose}
|
|
93
|
-
isBackDisabled={
|
|
102
|
+
isBackDisabled={activeStep?.id === steps[0]?.id}
|
|
94
103
|
{...wizardFooter}
|
|
95
104
|
/>
|
|
96
105
|
);
|
|
97
|
-
}, [currentFooter, initialFooter,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
15
|
-
|
|
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 = ({
|
|
47
|
-
const
|
|
48
|
-
return <InternalWizardFooter {...internalProps} {...
|
|
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, '
|
|
62
|
+
}: Omit<WizardFooterProps, 'activeStep'>) => (
|
|
63
63
|
<WizardFooterWrapper>
|
|
64
64
|
<Button variant={ButtonVariant.primary} type="submit" onClick={onNext} isDisabled={isNextDisabled}>
|
|
65
65
|
{nextButtonText}
|