@patternfly/react-core 4.267.4 → 4.267.5
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 +8 -0
- package/package.json +2 -2
- package/src/components/Wizard/examples/Wizard.md +14 -691
- package/src/components/Wizard/examples/WizardAnchorsForNavItems.tsx +42 -0
- package/src/components/Wizard/examples/WizardBasic.tsx +14 -0
- package/src/components/Wizard/examples/WizardBasicWithDisabledSteps.tsx +14 -0
- package/src/components/Wizard/examples/WizardEnabledOnFormValidation.tsx +139 -0
- package/src/components/Wizard/examples/WizardExpandableSteps.tsx +34 -0
- package/src/components/Wizard/examples/WizardFinished.tsx +90 -0
- package/src/components/Wizard/examples/WizardGetCurrentStep.tsx +33 -0
- package/src/components/Wizard/examples/WizardInModal.tsx +32 -0
- package/src/components/Wizard/examples/WizardIncrementallyEnabledSteps.tsx +61 -0
- package/src/components/Wizard/examples/WizardValidateOnButtonPress.tsx +204 -0
- package/src/components/Wizard/examples/WizardWithDrawer.tsx +126 -0
- package/src/components/Wizard/examples/FinishedStep.js +0 -70
- package/src/components/Wizard/examples/SampleForm.js +0 -59
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button, Wizard } from '@patternfly/react-core';
|
|
3
|
+
import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon';
|
|
4
|
+
import SlackHashIcon from '@patternfly/react-icons/dist/esm/icons/slack-hash-icon';
|
|
5
|
+
|
|
6
|
+
export const WizardWithNavAnchors: React.FunctionComponent = () => {
|
|
7
|
+
const steps = [
|
|
8
|
+
{
|
|
9
|
+
name: (
|
|
10
|
+
<div>
|
|
11
|
+
<ExternalLinkAltIcon /> PF3
|
|
12
|
+
</div>
|
|
13
|
+
),
|
|
14
|
+
component: <p>Step 1: Read about PF3</p>,
|
|
15
|
+
stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v3/', target: '_blank' }
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: (
|
|
19
|
+
<div>
|
|
20
|
+
<ExternalLinkAltIcon /> PF4
|
|
21
|
+
</div>
|
|
22
|
+
),
|
|
23
|
+
component: <p>Step 2: Read about PF4</p>,
|
|
24
|
+
stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v4/', target: '_blank' }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: (
|
|
28
|
+
<div>
|
|
29
|
+
<SlackHashIcon /> Join us on slack
|
|
30
|
+
</div>
|
|
31
|
+
),
|
|
32
|
+
component: (
|
|
33
|
+
<Button variant="link" component="a" target="_blank" href="https://patternfly.slack.com/">
|
|
34
|
+
Join the conversation
|
|
35
|
+
</Button>
|
|
36
|
+
),
|
|
37
|
+
stepNavItemProps: { navItemComponent: 'a', href: 'https://patternfly.slack.com/', target: '_blank' }
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
const title = 'Anchor link wizard example';
|
|
41
|
+
return <Wizard navAriaLabel={`${title} steps`} mainAriaLabel={`${title} content`} steps={steps} height={400} />;
|
|
42
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Wizard } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const WizardBasic: React.FunctionComponent = () => {
|
|
5
|
+
const steps = [
|
|
6
|
+
{ name: 'First step', component: <p>Step 1 content</p> },
|
|
7
|
+
{ name: 'Second step', component: <p>Step 2 content</p> },
|
|
8
|
+
{ name: 'Third step', component: <p>Step 3 content</p> },
|
|
9
|
+
{ name: 'Fourth step', component: <p>Step 4 content</p> },
|
|
10
|
+
{ name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
|
|
11
|
+
];
|
|
12
|
+
const title = 'Basic wizard example';
|
|
13
|
+
return <Wizard navAriaLabel={`${title} steps`} mainAriaLabel={`${title} content`} steps={steps} height={400} />;
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Wizard } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const WizardBasicWithDisabledSteps: React.FunctionComponent = () => {
|
|
5
|
+
const steps = [
|
|
6
|
+
{ name: 'First step', component: <p>Step 1 content</p> },
|
|
7
|
+
{ name: 'Second step', component: <p>Step 2 content</p>, isDisabled: true },
|
|
8
|
+
{ name: 'Third step', component: <p>Step 3 content</p> },
|
|
9
|
+
{ name: 'Fourth step', component: <p>Step 4 content</p>, isDisabled: true },
|
|
10
|
+
{ name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
|
|
11
|
+
];
|
|
12
|
+
const title = 'Basic wizard with disabled steps example';
|
|
13
|
+
return <Wizard navAriaLabel={`${title} steps`} mainAriaLabel={`${title} content`} steps={steps} height={400} />;
|
|
14
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Form, FormGroup, TextInput, Wizard, WizardStep } from '@patternfly/react-core';
|
|
3
|
+
interface PrevStepInfo {
|
|
4
|
+
prevId?: string | number;
|
|
5
|
+
prevName: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface sampleFormProps {
|
|
9
|
+
formValue: string;
|
|
10
|
+
isFormValid: boolean;
|
|
11
|
+
onChange?: (isValid: boolean, value: string) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const SampleForm: React.FunctionComponent<sampleFormProps> = (props: sampleFormProps) => {
|
|
15
|
+
const [value, setValue] = React.useState(props.formValue);
|
|
16
|
+
const [isValid, setIsValid] = React.useState(props.isFormValid);
|
|
17
|
+
|
|
18
|
+
const handleTextInputChange = (value: string) => {
|
|
19
|
+
const valid = /^\d+$/.test(value);
|
|
20
|
+
setValue(value);
|
|
21
|
+
setIsValid(valid);
|
|
22
|
+
props.onChange && props.onChange(valid, value);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const validated = isValid ? 'default' : 'error';
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Form>
|
|
29
|
+
<FormGroup
|
|
30
|
+
label="Age:"
|
|
31
|
+
type="number"
|
|
32
|
+
helperText="Write your age in numbers."
|
|
33
|
+
helperTextInvalid="Age has to be a number"
|
|
34
|
+
fieldId="age"
|
|
35
|
+
validated={validated}
|
|
36
|
+
>
|
|
37
|
+
<TextInput
|
|
38
|
+
validated={validated}
|
|
39
|
+
value={value}
|
|
40
|
+
id="age-input"
|
|
41
|
+
aria-describedby="age-helper"
|
|
42
|
+
onChange={handleTextInputChange}
|
|
43
|
+
/>
|
|
44
|
+
</FormGroup>
|
|
45
|
+
</Form>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const WizardFormValidation: React.FunctionComponent = () => {
|
|
50
|
+
const [isFormValid, setIsFormValid] = React.useState(false);
|
|
51
|
+
const [formValue, setFormValue] = React.useState('Thirty');
|
|
52
|
+
const [allStepsValid, setAllStepsValid] = React.useState(false);
|
|
53
|
+
const [stepIdReached, setStepIdReached] = React.useState(1);
|
|
54
|
+
|
|
55
|
+
React.useEffect(() => {
|
|
56
|
+
setAllStepsValid(isFormValid);
|
|
57
|
+
}, [isFormValid, stepIdReached]);
|
|
58
|
+
|
|
59
|
+
const closeWizard = () => {
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.log('close wizard');
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const onFormChange = (isValid: boolean, value: string) => {
|
|
65
|
+
setIsFormValid(isValid);
|
|
66
|
+
setFormValue(value);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const areAllStepsValid = () => {
|
|
70
|
+
setAllStepsValid(isFormValid);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const onNext = ({ id, name }: WizardStep, { prevId, prevName }: PrevStepInfo) => {
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
|
|
76
|
+
if (id) {
|
|
77
|
+
if (typeof id === 'string') {
|
|
78
|
+
const [, orderIndex] = id.split('-');
|
|
79
|
+
id = parseInt(orderIndex);
|
|
80
|
+
}
|
|
81
|
+
setStepIdReached(stepIdReached < id ? id : stepIdReached);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const onBack = ({ id, name }: WizardStep, { prevId, prevName }: PrevStepInfo) => {
|
|
86
|
+
// eslint-disable-next-line no-console
|
|
87
|
+
console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
|
|
88
|
+
areAllStepsValid();
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const onGoToStep = ({ id, name }: WizardStep, { prevId, prevName }: PrevStepInfo) => {
|
|
92
|
+
// eslint-disable-next-line no-console
|
|
93
|
+
console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const steps = [
|
|
97
|
+
{ id: 'validated-1', name: 'Information', component: <p>Step 1 content</p> },
|
|
98
|
+
{
|
|
99
|
+
name: 'Configuration',
|
|
100
|
+
steps: [
|
|
101
|
+
{
|
|
102
|
+
id: 'validated-2',
|
|
103
|
+
name: 'Substep A with validation',
|
|
104
|
+
component: <SampleForm formValue={formValue} isFormValid={isFormValid} onChange={onFormChange} />,
|
|
105
|
+
enableNext: isFormValid,
|
|
106
|
+
canJumpTo: stepIdReached >= 2
|
|
107
|
+
},
|
|
108
|
+
{ id: 'validated-3', name: 'Substep B', component: <p>Substep B</p>, canJumpTo: stepIdReached >= 3 }
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'validated-4',
|
|
113
|
+
name: 'Additional',
|
|
114
|
+
component: <p>Step 3 content</p>,
|
|
115
|
+
enableNext: allStepsValid,
|
|
116
|
+
canJumpTo: stepIdReached >= 4
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'validated-5',
|
|
120
|
+
name: 'Review',
|
|
121
|
+
component: <p>Step 4 content</p>,
|
|
122
|
+
nextButtonText: 'Finish',
|
|
123
|
+
canJumpTo: stepIdReached >= 5
|
|
124
|
+
}
|
|
125
|
+
];
|
|
126
|
+
const title = 'Wizard enabled on form validation example';
|
|
127
|
+
return (
|
|
128
|
+
<Wizard
|
|
129
|
+
navAriaLabel={`${title} steps`}
|
|
130
|
+
mainAriaLabel={`${title} content`}
|
|
131
|
+
onClose={closeWizard}
|
|
132
|
+
steps={steps}
|
|
133
|
+
onNext={onNext}
|
|
134
|
+
onBack={onBack}
|
|
135
|
+
onGoToStep={onGoToStep}
|
|
136
|
+
height={400}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Wizard } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const WizardExpandableSteps: React.FunctionComponent = () => {
|
|
5
|
+
const steps = [
|
|
6
|
+
{
|
|
7
|
+
name: 'First step',
|
|
8
|
+
steps: [
|
|
9
|
+
{ name: 'Substep A', component: <p>Substep A content</p> },
|
|
10
|
+
{ name: 'Substep B', component: <p>Substep B content</p> }
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{ name: 'Second step', component: <p>Step 2 content</p> },
|
|
14
|
+
{
|
|
15
|
+
name: 'Third step',
|
|
16
|
+
steps: [
|
|
17
|
+
{ name: 'Substep C', component: <p>Substep C content</p> },
|
|
18
|
+
{ name: 'Substep D', component: <p>Substep D content</p> }
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{ name: 'Fourth step', component: <p>Step 4 content</p> },
|
|
22
|
+
{ name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
|
|
23
|
+
];
|
|
24
|
+
const title = 'Expandable wizard example';
|
|
25
|
+
return (
|
|
26
|
+
<Wizard
|
|
27
|
+
navAriaLabel={`${title} steps`}
|
|
28
|
+
mainAriaLabel={`${title} content`}
|
|
29
|
+
steps={steps}
|
|
30
|
+
height={400}
|
|
31
|
+
isNavExpandable
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
EmptyState,
|
|
4
|
+
EmptyStateIcon,
|
|
5
|
+
EmptyStateBody,
|
|
6
|
+
EmptyStateSecondaryActions,
|
|
7
|
+
Title,
|
|
8
|
+
Progress,
|
|
9
|
+
Button,
|
|
10
|
+
Wizard
|
|
11
|
+
} from '@patternfly/react-core';
|
|
12
|
+
// eslint-disable-next-line patternfly-react/import-tokens-icons
|
|
13
|
+
import { CogsIcon } from '@patternfly/react-icons';
|
|
14
|
+
|
|
15
|
+
interface finishedProps {
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const FinishedStep: React.FunctionComponent<finishedProps> = (props: finishedProps) => {
|
|
20
|
+
const [percent, setPercent] = React.useState(0);
|
|
21
|
+
|
|
22
|
+
const tick = () => {
|
|
23
|
+
setPercent(prevPercent => {
|
|
24
|
+
if (prevPercent < 100) {
|
|
25
|
+
return prevPercent + 20;
|
|
26
|
+
} else {
|
|
27
|
+
return prevPercent;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
const interval = setInterval(() => tick(), 1000);
|
|
34
|
+
|
|
35
|
+
if (percent >= 100) {
|
|
36
|
+
clearInterval(interval);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return () => clearInterval(interval);
|
|
40
|
+
}, [percent]);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="pf-l-bullseye">
|
|
44
|
+
<EmptyState variant="large">
|
|
45
|
+
<EmptyStateIcon icon={CogsIcon} />
|
|
46
|
+
<Title headingLevel="h4" size="lg">
|
|
47
|
+
{percent === 100 ? 'Validation complete' : 'Validating credentials'}
|
|
48
|
+
</Title>
|
|
49
|
+
<EmptyStateBody>
|
|
50
|
+
<Progress value={percent} measureLocation="outside" aria-label="validation-progress" />
|
|
51
|
+
</EmptyStateBody>
|
|
52
|
+
<EmptyStateBody>
|
|
53
|
+
Description can be used to further elaborate on the validation step, or give the user a better idea of how
|
|
54
|
+
long the process will take.
|
|
55
|
+
</EmptyStateBody>
|
|
56
|
+
<EmptyStateSecondaryActions>
|
|
57
|
+
<Button isDisabled={percent !== 100} onClick={props.onClose}>
|
|
58
|
+
Log to console
|
|
59
|
+
</Button>
|
|
60
|
+
</EmptyStateSecondaryActions>
|
|
61
|
+
</EmptyState>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const WizardFinished: React.FunctionComponent = () => {
|
|
67
|
+
const closeWizard = () => {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.log('close wizard');
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const steps = [
|
|
73
|
+
{ name: 'First step', component: <p>Step 1 content</p> },
|
|
74
|
+
{ name: 'Second step', component: <p>Step 2 content</p> },
|
|
75
|
+
{ name: 'Third step', component: <p>Step 3 content</p> },
|
|
76
|
+
{ name: 'Fourth step', component: <p>Step 4 content</p> },
|
|
77
|
+
{ name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' },
|
|
78
|
+
{ name: 'Finish', component: <FinishedStep onClose={closeWizard} />, isFinishedStep: true }
|
|
79
|
+
];
|
|
80
|
+
const title = 'Finished wizard example';
|
|
81
|
+
return (
|
|
82
|
+
<Wizard
|
|
83
|
+
navAriaLabel={`${title} steps`}
|
|
84
|
+
mainAriaLabel={`${title} content`}
|
|
85
|
+
onClose={closeWizard}
|
|
86
|
+
steps={steps}
|
|
87
|
+
height={400}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Wizard, WizardStep } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const WizardGetCurrentStep: React.FunctionComponent = () => {
|
|
5
|
+
const onCurrentStepChanged = ({ id }: WizardStep) => {
|
|
6
|
+
// eslint-disable-next-line no-console
|
|
7
|
+
console.log(id);
|
|
8
|
+
};
|
|
9
|
+
const closeWizard = () => {
|
|
10
|
+
// eslint-disable-next-line no-console
|
|
11
|
+
console.log('close wizard');
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const steps = [
|
|
15
|
+
{ id: 1, name: 'First step', component: <p>Step 1 content</p> },
|
|
16
|
+
{ id: 2, name: 'Second step', component: <p>Step 2 content</p> },
|
|
17
|
+
{ id: 3, name: 'Third step', component: <p>Step 3 content</p> },
|
|
18
|
+
{ id: 4, name: 'Fourth step', component: <p>Step 4 content</p> },
|
|
19
|
+
{ id: 5, name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
|
|
20
|
+
];
|
|
21
|
+
const title = 'Get current step wizard example';
|
|
22
|
+
return (
|
|
23
|
+
<Wizard
|
|
24
|
+
navAriaLabel={`${title} steps`}
|
|
25
|
+
mainAriaLabel={`${title} content`}
|
|
26
|
+
onClose={closeWizard}
|
|
27
|
+
description="Simple Wizard Description"
|
|
28
|
+
steps={steps}
|
|
29
|
+
height={400}
|
|
30
|
+
onCurrentStepChanged={onCurrentStepChanged}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button, Wizard } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const WizardInModal: React.FunctionComponent = () => {
|
|
5
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
6
|
+
const handleModalToggle = () => {
|
|
7
|
+
setIsOpen(!isOpen);
|
|
8
|
+
};
|
|
9
|
+
const steps = [
|
|
10
|
+
{ name: 'First step', component: <p>Step 1 content</p> },
|
|
11
|
+
{ name: 'Second step', component: <p>Step 2 content</p> },
|
|
12
|
+
{ name: 'Third step', component: <p>Step 3 content</p> },
|
|
13
|
+
{ name: 'Fourth step', component: <p>Step 4 content</p> },
|
|
14
|
+
{ name: 'Review', component: <p>Review step content</p>, nextButtonText: 'Finish' }
|
|
15
|
+
];
|
|
16
|
+
const title = 'Wizard in modal example';
|
|
17
|
+
return (
|
|
18
|
+
<React.Fragment>
|
|
19
|
+
<Button variant="primary" onClick={handleModalToggle}>
|
|
20
|
+
Show Modal
|
|
21
|
+
</Button>
|
|
22
|
+
<Wizard
|
|
23
|
+
title={title}
|
|
24
|
+
description="Simple Wizard Description"
|
|
25
|
+
descriptionComponent="div"
|
|
26
|
+
steps={steps}
|
|
27
|
+
onClose={handleModalToggle}
|
|
28
|
+
isOpen={isOpen}
|
|
29
|
+
/>
|
|
30
|
+
</React.Fragment>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Wizard, WizardStep } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const WizardIncrementallyEnabledSteps: React.FunctionComponent = () => {
|
|
5
|
+
const [stepIdReached, setStepIdReached] = React.useState(1);
|
|
6
|
+
|
|
7
|
+
const onNext = ({ id }: WizardStep) => {
|
|
8
|
+
if (id) {
|
|
9
|
+
if (typeof id === 'string') {
|
|
10
|
+
const [, orderIndex] = id.split('-');
|
|
11
|
+
id = parseInt(orderIndex);
|
|
12
|
+
}
|
|
13
|
+
setStepIdReached(stepIdReached < id ? id : stepIdReached);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const closeWizard = () => {
|
|
18
|
+
// eslint-disable-next-line no-console
|
|
19
|
+
console.log('close wizard');
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const steps = [
|
|
23
|
+
{ id: 'incrementallyEnabled-1', name: 'First step', component: <p>Step 1 content</p> },
|
|
24
|
+
{
|
|
25
|
+
id: 'incrementallyEnabled-2',
|
|
26
|
+
name: 'Second step',
|
|
27
|
+
component: <p>Step 2 content</p>,
|
|
28
|
+
canJumpTo: stepIdReached >= 2
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'incrementallyEnabled-3',
|
|
32
|
+
name: 'Third step',
|
|
33
|
+
component: <p>Step 3 content</p>,
|
|
34
|
+
canJumpTo: stepIdReached >= 3
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'incrementallyEnabled-4',
|
|
38
|
+
name: 'Fourth step',
|
|
39
|
+
component: <p>Step 4 content</p>,
|
|
40
|
+
canJumpTo: stepIdReached >= 4
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'incrementallyEnabled-5',
|
|
44
|
+
name: 'Review',
|
|
45
|
+
component: <p>Review step content</p>,
|
|
46
|
+
nextButtonText: 'Finish',
|
|
47
|
+
canJumpTo: stepIdReached >= 5
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
const title = 'Incrementally enabled wizard example';
|
|
51
|
+
return (
|
|
52
|
+
<Wizard
|
|
53
|
+
navAriaLabel={`${title} steps`}
|
|
54
|
+
mainAriaLabel={`${title} content`}
|
|
55
|
+
onClose={closeWizard}
|
|
56
|
+
steps={steps}
|
|
57
|
+
onNext={onNext}
|
|
58
|
+
height={400}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
EmptyState,
|
|
4
|
+
EmptyStateIcon,
|
|
5
|
+
EmptyStateBody,
|
|
6
|
+
EmptyStateSecondaryActions,
|
|
7
|
+
Title,
|
|
8
|
+
Form,
|
|
9
|
+
FormGroup,
|
|
10
|
+
TextInput,
|
|
11
|
+
Progress,
|
|
12
|
+
Button,
|
|
13
|
+
Wizard,
|
|
14
|
+
WizardFooter,
|
|
15
|
+
WizardContextConsumer,
|
|
16
|
+
Alert
|
|
17
|
+
} from '@patternfly/react-core';
|
|
18
|
+
// eslint-disable-next-line patternfly-react/import-tokens-icons
|
|
19
|
+
import { CogsIcon } from '@patternfly/react-icons';
|
|
20
|
+
|
|
21
|
+
interface finishedProps {
|
|
22
|
+
onClose: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const FinishedStep: React.FunctionComponent<finishedProps> = (props: finishedProps) => {
|
|
26
|
+
const [percent, setPercent] = React.useState(0);
|
|
27
|
+
|
|
28
|
+
const tick = () => {
|
|
29
|
+
setPercent(prevPercent => {
|
|
30
|
+
if (prevPercent < 100) {
|
|
31
|
+
return prevPercent + 20;
|
|
32
|
+
} else {
|
|
33
|
+
return prevPercent;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
const interval = setInterval(() => tick(), 1000);
|
|
40
|
+
|
|
41
|
+
if (percent >= 100) {
|
|
42
|
+
clearInterval(interval);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return () => clearInterval(interval);
|
|
46
|
+
}, [percent]);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className="pf-l-bullseye">
|
|
50
|
+
<EmptyState variant="large">
|
|
51
|
+
<EmptyStateIcon icon={CogsIcon} />
|
|
52
|
+
<Title headingLevel="h4" size="lg">
|
|
53
|
+
{percent === 100 ? 'Validation complete' : 'Validating credentials'}
|
|
54
|
+
</Title>
|
|
55
|
+
<EmptyStateBody>
|
|
56
|
+
<Progress value={percent} measureLocation="outside" aria-label="validation-progress" />
|
|
57
|
+
</EmptyStateBody>
|
|
58
|
+
<EmptyStateBody>
|
|
59
|
+
Description can be used to further elaborate on the validation step, or give the user a better idea of how
|
|
60
|
+
long the process will take.
|
|
61
|
+
</EmptyStateBody>
|
|
62
|
+
<EmptyStateSecondaryActions>
|
|
63
|
+
<Button isDisabled={percent !== 100} onClick={props.onClose}>
|
|
64
|
+
Log to console
|
|
65
|
+
</Button>
|
|
66
|
+
</EmptyStateSecondaryActions>
|
|
67
|
+
</EmptyState>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
interface sampleFormProps {
|
|
73
|
+
formValue: string;
|
|
74
|
+
isFormValid: boolean;
|
|
75
|
+
onChange?: (isValid: boolean, value: string) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const SampleForm: React.FunctionComponent<sampleFormProps> = (props: sampleFormProps) => {
|
|
79
|
+
const [value, setValue] = React.useState(props.formValue);
|
|
80
|
+
const [isValid, setIsValid] = React.useState(props.isFormValid);
|
|
81
|
+
|
|
82
|
+
const handleTextInputChange = (value: string) => {
|
|
83
|
+
const valid = /^\d+$/.test(value);
|
|
84
|
+
setValue(value);
|
|
85
|
+
setIsValid(valid);
|
|
86
|
+
props.onChange && props.onChange(valid, value);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const validated = isValid ? 'default' : 'error';
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Form>
|
|
93
|
+
<FormGroup
|
|
94
|
+
label="Age:"
|
|
95
|
+
type="number"
|
|
96
|
+
helperText="Write your age in numbers."
|
|
97
|
+
helperTextInvalid="Age has to be a number"
|
|
98
|
+
fieldId="age"
|
|
99
|
+
validated={validated}
|
|
100
|
+
>
|
|
101
|
+
<TextInput
|
|
102
|
+
validated={validated}
|
|
103
|
+
value={value}
|
|
104
|
+
id="age"
|
|
105
|
+
aria-describedby="age-helper"
|
|
106
|
+
onChange={handleTextInputChange}
|
|
107
|
+
/>
|
|
108
|
+
</FormGroup>
|
|
109
|
+
</Form>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const WizardValidateButtonPress: React.FunctionComponent = () => {
|
|
114
|
+
const [isFormValid, setIsFormValid] = React.useState(false);
|
|
115
|
+
const [formValue, setFormValue] = React.useState('Validating on button press');
|
|
116
|
+
const [stepsValid, setStepsValid] = React.useState(0);
|
|
117
|
+
const [errorText, setErrorText] = React.useState(false);
|
|
118
|
+
|
|
119
|
+
const closeWizard = () => {
|
|
120
|
+
// eslint-disable-next-line no-console
|
|
121
|
+
console.log('close wizard');
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const onFormChange = (isValid: boolean, value: string) => {
|
|
125
|
+
setIsFormValid(isValid);
|
|
126
|
+
setFormValue(value);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const validateLastStep: (onNext: () => void) => void = onNext => {
|
|
130
|
+
if (stepsValid !== 1 && !isFormValid) {
|
|
131
|
+
setErrorText(true);
|
|
132
|
+
} else {
|
|
133
|
+
setStepsValid(1);
|
|
134
|
+
setErrorText(false);
|
|
135
|
+
onNext();
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const steps = [
|
|
140
|
+
{ name: 'First step', component: <p>Step 1 content</p> },
|
|
141
|
+
{ name: 'Second step', component: <p>Step 2 content</p> },
|
|
142
|
+
{
|
|
143
|
+
name: 'Final Step',
|
|
144
|
+
component: (
|
|
145
|
+
<>
|
|
146
|
+
{errorText && (
|
|
147
|
+
<div style={{ padding: '15px 0' }}>
|
|
148
|
+
<Alert variant="warning" title="Validation failed, please try again" />
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
151
|
+
<SampleForm formValue={formValue} isFormValid={stepsValid !== 1} onChange={onFormChange} />
|
|
152
|
+
</>
|
|
153
|
+
)
|
|
154
|
+
},
|
|
155
|
+
{ name: 'Finish', component: <FinishedStep onClose={closeWizard} />, isFinishedStep: true }
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
const CustomFooter = (
|
|
159
|
+
<WizardFooter>
|
|
160
|
+
<WizardContextConsumer>
|
|
161
|
+
{({ activeStep, goToStepByName, onNext, onBack, onClose }) => {
|
|
162
|
+
if (activeStep.name !== 'Final Step') {
|
|
163
|
+
return (
|
|
164
|
+
<>
|
|
165
|
+
<Button variant="primary" type="submit" onClick={onNext}>
|
|
166
|
+
Forward
|
|
167
|
+
</Button>
|
|
168
|
+
<Button
|
|
169
|
+
variant="secondary"
|
|
170
|
+
onClick={onBack}
|
|
171
|
+
className={activeStep.name === 'First step' ? 'pf-m-disabled' : ''}
|
|
172
|
+
>
|
|
173
|
+
Backward
|
|
174
|
+
</Button>
|
|
175
|
+
<Button variant="link" onClick={onClose}>
|
|
176
|
+
Cancel
|
|
177
|
+
</Button>
|
|
178
|
+
</>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
// Final step buttons
|
|
182
|
+
return (
|
|
183
|
+
<>
|
|
184
|
+
<Button onClick={() => validateLastStep(onNext)}>Validate</Button>
|
|
185
|
+
<Button onClick={() => goToStepByName('First step')}>Go to Beginning</Button>
|
|
186
|
+
</>
|
|
187
|
+
);
|
|
188
|
+
}}
|
|
189
|
+
</WizardContextConsumer>
|
|
190
|
+
</WizardFooter>
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const title = 'Validate on button press wizard example';
|
|
194
|
+
return (
|
|
195
|
+
<Wizard
|
|
196
|
+
navAriaLabel={`${title} steps`}
|
|
197
|
+
mainAriaLabel={`${title} content`}
|
|
198
|
+
onClose={closeWizard}
|
|
199
|
+
footer={CustomFooter}
|
|
200
|
+
steps={steps}
|
|
201
|
+
height={400}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
};
|