@patternfly/react-core 4.249.0 → 4.250.0
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 +17 -0
- package/dist/esm/next/components/Select/Select.d.ts +28 -0
- package/dist/esm/next/components/Select/Select.d.ts.map +1 -0
- package/dist/esm/next/components/Select/Select.js +62 -0
- package/dist/esm/next/components/Select/Select.js.map +1 -0
- package/dist/esm/next/components/Select/SelectGroup.d.ts +12 -0
- package/dist/esm/next/components/Select/SelectGroup.d.ts.map +1 -0
- package/dist/esm/next/components/Select/SelectGroup.js +10 -0
- package/dist/esm/next/components/Select/SelectGroup.js.map +1 -0
- package/dist/esm/next/components/Select/SelectList.d.ts +10 -0
- package/dist/esm/next/components/Select/SelectList.d.ts.map +1 -0
- package/dist/esm/next/components/Select/SelectList.js +10 -0
- package/dist/esm/next/components/Select/SelectList.js.map +1 -0
- package/dist/esm/next/components/Select/SelectOption.d.ts +20 -0
- package/dist/esm/next/components/Select/SelectOption.d.ts.map +1 -0
- package/dist/esm/next/components/Select/SelectOption.js +10 -0
- package/dist/esm/next/components/Select/SelectOption.js.map +1 -0
- package/dist/esm/next/components/Select/index.d.ts +5 -0
- package/dist/esm/next/components/Select/index.d.ts.map +1 -0
- package/dist/esm/next/components/Select/index.js +5 -0
- package/dist/esm/next/components/Select/index.js.map +1 -0
- package/dist/esm/next/components/Wizard/Wizard.d.ts +9 -7
- package/dist/esm/next/components/Wizard/Wizard.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/Wizard.js +62 -48
- 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 +1 -1
- package/dist/esm/next/components/Wizard/WizardBody.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardContext.d.ts +21 -20
- package/dist/esm/next/components/Wizard/WizardContext.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardContext.js +63 -32
- package/dist/esm/next/components/Wizard/WizardContext.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardFooter.d.ts +20 -6
- package/dist/esm/next/components/Wizard/WizardFooter.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardFooter.js +13 -4
- package/dist/esm/next/components/Wizard/WizardFooter.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardHeader.d.ts +1 -1
- package/dist/esm/next/components/Wizard/WizardHeader.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardHeader.js +2 -2
- package/dist/esm/next/components/Wizard/WizardHeader.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardNav.d.ts +5 -5
- package/dist/esm/next/components/Wizard/WizardNav.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardNav.js +3 -4
- package/dist/esm/next/components/Wizard/WizardNav.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardNavInternal.d.ts +14 -0
- package/dist/esm/next/components/Wizard/WizardNavInternal.d.ts.map +1 -0
- package/dist/esm/next/components/Wizard/WizardNavInternal.js +49 -0
- package/dist/esm/next/components/Wizard/WizardNavInternal.js.map +1 -0
- package/dist/esm/next/components/Wizard/WizardNavItem.d.ts +12 -8
- package/dist/esm/next/components/Wizard/WizardNavItem.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardNavItem.js +23 -12
- package/dist/esm/next/components/Wizard/WizardNavItem.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardStep.d.ts +22 -6
- package/dist/esm/next/components/Wizard/WizardStep.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardStep.js +20 -1
- package/dist/esm/next/components/Wizard/WizardStep.js.map +1 -1
- package/dist/esm/next/components/Wizard/WizardToggle.d.ts +9 -15
- package/dist/esm/next/components/Wizard/WizardToggle.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/WizardToggle.js +15 -50
- package/dist/esm/next/components/Wizard/WizardToggle.js.map +1 -1
- package/dist/esm/next/components/Wizard/hooks/useWizardFooter.d.ts +2 -2
- package/dist/esm/next/components/Wizard/hooks/useWizardFooter.d.ts.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 +37 -46
- package/dist/esm/next/components/Wizard/types.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/types.js +10 -2
- package/dist/esm/next/components/Wizard/types.js.map +1 -1
- package/dist/esm/next/components/Wizard/utils.d.ts +4 -5
- package/dist/esm/next/components/Wizard/utils.d.ts.map +1 -1
- package/dist/esm/next/components/Wizard/utils.js +20 -13
- package/dist/esm/next/components/Wizard/utils.js.map +1 -1
- package/dist/esm/next/components/index.d.ts +2 -1
- package/dist/esm/next/components/index.d.ts.map +1 -1
- package/dist/esm/next/components/index.js +2 -1
- package/dist/esm/next/components/index.js.map +1 -1
- package/dist/js/next/components/Select/Select.d.ts +28 -0
- package/dist/js/next/components/Select/Select.d.ts.map +1 -0
- package/dist/js/next/components/Select/Select.js +65 -0
- package/dist/js/next/components/Select/Select.js.map +1 -0
- package/dist/js/next/components/Select/SelectGroup.d.ts +12 -0
- package/dist/js/next/components/Select/SelectGroup.d.ts.map +1 -0
- package/dist/js/next/components/Select/SelectGroup.js +14 -0
- package/dist/js/next/components/Select/SelectGroup.js.map +1 -0
- package/dist/js/next/components/Select/SelectList.d.ts +10 -0
- package/dist/js/next/components/Select/SelectList.d.ts.map +1 -0
- package/dist/js/next/components/Select/SelectList.js +14 -0
- package/dist/js/next/components/Select/SelectList.js.map +1 -0
- package/dist/js/next/components/Select/SelectOption.d.ts +20 -0
- package/dist/js/next/components/Select/SelectOption.d.ts.map +1 -0
- package/dist/js/next/components/Select/SelectOption.js +14 -0
- package/dist/js/next/components/Select/SelectOption.js.map +1 -0
- package/dist/js/next/components/Select/index.d.ts +5 -0
- package/dist/js/next/components/Select/index.d.ts.map +1 -0
- package/dist/js/next/components/Select/index.js +8 -0
- package/dist/js/next/components/Select/index.js.map +1 -0
- package/dist/js/next/components/Wizard/Wizard.d.ts +9 -7
- package/dist/js/next/components/Wizard/Wizard.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/Wizard.js +59 -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 +1 -1
- package/dist/js/next/components/Wizard/WizardBody.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardContext.d.ts +21 -20
- package/dist/js/next/components/Wizard/WizardContext.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardContext.js +61 -30
- package/dist/js/next/components/Wizard/WizardContext.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardFooter.d.ts +20 -6
- package/dist/js/next/components/Wizard/WizardFooter.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardFooter.js +15 -6
- package/dist/js/next/components/Wizard/WizardFooter.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardHeader.d.ts +1 -1
- package/dist/js/next/components/Wizard/WizardHeader.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardHeader.js +2 -2
- package/dist/js/next/components/Wizard/WizardHeader.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardNav.d.ts +5 -5
- package/dist/js/next/components/Wizard/WizardNav.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardNav.js +3 -4
- package/dist/js/next/components/Wizard/WizardNav.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardNavInternal.d.ts +14 -0
- package/dist/js/next/components/Wizard/WizardNavInternal.d.ts.map +1 -0
- package/dist/js/next/components/Wizard/WizardNavInternal.js +54 -0
- package/dist/js/next/components/Wizard/WizardNavInternal.js.map +1 -0
- package/dist/js/next/components/Wizard/WizardNavItem.d.ts +12 -8
- package/dist/js/next/components/Wizard/WizardNavItem.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardNavItem.js +23 -12
- package/dist/js/next/components/Wizard/WizardNavItem.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardStep.d.ts +22 -6
- package/dist/js/next/components/Wizard/WizardStep.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardStep.js +20 -1
- package/dist/js/next/components/Wizard/WizardStep.js.map +1 -1
- package/dist/js/next/components/Wizard/WizardToggle.d.ts +9 -15
- package/dist/js/next/components/Wizard/WizardToggle.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/WizardToggle.js +15 -51
- package/dist/js/next/components/Wizard/WizardToggle.js.map +1 -1
- package/dist/js/next/components/Wizard/hooks/useWizardFooter.d.ts +2 -2
- package/dist/js/next/components/Wizard/hooks/useWizardFooter.d.ts.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 +37 -46
- package/dist/js/next/components/Wizard/types.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/types.js +12 -3
- package/dist/js/next/components/Wizard/types.js.map +1 -1
- package/dist/js/next/components/Wizard/utils.d.ts +4 -5
- package/dist/js/next/components/Wizard/utils.d.ts.map +1 -1
- package/dist/js/next/components/Wizard/utils.js +24 -15
- package/dist/js/next/components/Wizard/utils.js.map +1 -1
- package/dist/js/next/components/index.d.ts +2 -1
- package/dist/js/next/components/index.d.ts.map +1 -1
- package/dist/js/next/components/index.js +2 -1
- package/dist/js/next/components/index.js.map +1 -1
- package/dist/umd/react-core.min.css +940 -940
- package/package.json +2 -2
- package/src/next/components/Select/Select.tsx +129 -0
- package/src/next/components/Select/SelectGroup.tsx +24 -0
- package/src/next/components/Select/SelectList.tsx +21 -0
- package/src/next/components/Select/SelectOption.tsx +31 -0
- package/src/next/components/Select/examples/Select.md +37 -0
- package/src/next/components/Select/examples/SelectBasic.tsx +54 -0
- package/src/next/components/Select/examples/SelectCheckbox.tsx +67 -0
- package/src/next/components/Select/examples/SelectGrouped.tsx +63 -0
- package/src/next/components/Select/examples/SelectMultiTypeahead.tsx +195 -0
- package/src/next/components/Select/examples/SelectTypeahead.tsx +191 -0
- package/src/next/components/Select/index.ts +4 -0
- package/src/next/components/Wizard/Wizard.tsx +107 -64
- package/src/next/components/Wizard/WizardBody.tsx +4 -4
- package/src/next/components/Wizard/WizardContext.tsx +117 -65
- package/src/next/components/Wizard/WizardFooter.tsx +39 -17
- package/src/next/components/Wizard/WizardHeader.tsx +6 -3
- package/src/next/components/Wizard/WizardNav.tsx +9 -10
- package/src/next/components/Wizard/WizardNavInternal.tsx +137 -0
- package/src/next/components/Wizard/WizardNavItem.tsx +47 -20
- package/src/next/components/Wizard/WizardStep.tsx +52 -7
- package/src/next/components/Wizard/WizardToggle.tsx +24 -142
- package/src/next/components/Wizard/__tests__/Wizard.test.tsx +10 -13
- package/src/next/components/Wizard/__tests__/WizardBody.test.tsx +3 -3
- package/src/next/components/Wizard/__tests__/WizardFooter.test.tsx +11 -14
- package/src/next/components/Wizard/__tests__/WizardStep.test.tsx +100 -0
- package/src/next/components/Wizard/__tests__/WizardToggle.test.tsx +4 -4
- package/src/next/components/Wizard/examples/Wizard.md +40 -15
- package/src/next/components/Wizard/examples/WizardBasic.tsx +2 -2
- package/src/next/components/Wizard/examples/WizardCustomNav.tsx +4 -4
- package/src/next/components/Wizard/examples/WizardKitchenSink.tsx +126 -60
- package/src/next/components/Wizard/hooks/__tests__/useWizardFooter.test.tsx +23 -34
- package/src/next/components/Wizard/hooks/useWizardFooter.tsx +5 -5
- package/src/next/components/Wizard/types.tsx +59 -53
- package/src/next/components/Wizard/utils.ts +25 -16
- package/src/next/components/index.ts +2 -1
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import { DefaultWizardFooterProps, isCustomWizardFooter, WizardControlStep } from './types';
|
|
7
|
-
import { getActiveStep } from './utils';
|
|
8
|
-
import { WizardFooter } from './WizardFooter';
|
|
3
|
+
import { isCustomWizardFooter, isWizardParentStep, WizardControlStep, WizardFooterType } from './types';
|
|
4
|
+
import { getCurrentStep } from './utils';
|
|
5
|
+
import { WizardFooter, WizardFooterProps } from './WizardFooter';
|
|
9
6
|
|
|
10
7
|
export interface WizardContextProps {
|
|
11
8
|
/** List of steps */
|
|
12
9
|
steps: WizardControlStep[];
|
|
13
|
-
/**
|
|
14
|
-
|
|
10
|
+
/** Current step */
|
|
11
|
+
currentStep: WizardControlStep;
|
|
12
|
+
/** Current step index */
|
|
13
|
+
currentStepIndex: number;
|
|
15
14
|
/** Footer element */
|
|
16
15
|
footer: React.ReactElement;
|
|
17
16
|
/** Navigate to the next step */
|
|
@@ -27,38 +26,36 @@ export interface WizardContextProps {
|
|
|
27
26
|
/** Navigate to step by index */
|
|
28
27
|
goToStepByIndex: (index: number) => void;
|
|
29
28
|
/** Update the footer with any react element */
|
|
30
|
-
setFooter: (footer:
|
|
29
|
+
setFooter: (footer: React.ReactElement | Partial<WizardFooterProps>) => void;
|
|
30
|
+
/** Get step by ID */
|
|
31
|
+
getStep: (stepId: number | string) => WizardControlStep;
|
|
32
|
+
/** Set step by ID */
|
|
33
|
+
setStep: (step: Pick<WizardControlStep, 'id'> & Partial<WizardControlStep>) => void;
|
|
34
|
+
/** Toggle step visibility by ID */
|
|
35
|
+
toggleStep: (stepId: number | string, isHidden: boolean) => void;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
export const WizardContext = React.createContext({} as WizardContextProps);
|
|
34
39
|
|
|
35
|
-
interface WizardContextRenderProps {
|
|
36
|
-
steps: WizardControlStep[];
|
|
37
|
-
activeStep: WizardControlStep;
|
|
38
|
-
footer: React.ReactElement;
|
|
39
|
-
onNext(): void;
|
|
40
|
-
onBack(): void;
|
|
41
|
-
onClose(): void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
40
|
export interface WizardContextProviderProps {
|
|
45
41
|
steps: WizardControlStep[];
|
|
46
42
|
currentStepIndex: number;
|
|
47
|
-
footer:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
footer: WizardFooterType;
|
|
44
|
+
isStepVisitRequired: boolean;
|
|
45
|
+
children: React.ReactElement;
|
|
46
|
+
onNext(steps: WizardControlStep[]): void;
|
|
47
|
+
onBack(steps: WizardControlStep[]): void;
|
|
51
48
|
onClose(): void;
|
|
52
|
-
goToStepById(id: number | string): void;
|
|
53
|
-
goToStepByName(name: string): void;
|
|
54
|
-
goToStepByIndex(index: number): void;
|
|
49
|
+
goToStepById(steps: WizardControlStep[], id: number | string): void;
|
|
50
|
+
goToStepByName(steps: WizardControlStep[], name: string): void;
|
|
51
|
+
goToStepByIndex(steps: WizardControlStep[], index: number): void;
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
// eslint-disable-next-line patternfly-react/no-anonymous-functions
|
|
58
54
|
export const WizardContextProvider: React.FunctionComponent<WizardContextProviderProps> = ({
|
|
59
55
|
steps: initialSteps,
|
|
60
56
|
footer: initialFooter,
|
|
61
57
|
currentStepIndex,
|
|
58
|
+
isStepVisitRequired,
|
|
62
59
|
children,
|
|
63
60
|
onNext,
|
|
64
61
|
onBack,
|
|
@@ -68,61 +65,116 @@ export const WizardContextProvider: React.FunctionComponent<WizardContextProvide
|
|
|
68
65
|
goToStepByIndex
|
|
69
66
|
}) => {
|
|
70
67
|
const [steps, setSteps] = React.useState(initialSteps);
|
|
71
|
-
const [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const wizardFooter = React.useMemo(
|
|
75
|
-
() =>
|
|
76
|
-
isCustomWizardFooter(footer) ? (
|
|
77
|
-
<div className={css(styles.wizardFooter)}>{footer}</div>
|
|
78
|
-
) : (
|
|
79
|
-
<WizardFooter
|
|
80
|
-
activeStep={activeStep}
|
|
81
|
-
onNext={onNext}
|
|
82
|
-
onBack={onBack}
|
|
83
|
-
onClose={onClose}
|
|
84
|
-
disableBackButton={activeStep?.id === steps[0]?.id}
|
|
85
|
-
{...footer}
|
|
86
|
-
/>
|
|
87
|
-
),
|
|
88
|
-
[activeStep, footer, onBack, onClose, onNext, steps]
|
|
68
|
+
const [currentFooter, setCurrentFooter] = React.useState(
|
|
69
|
+
typeof initialFooter !== 'function' ? initialFooter : undefined
|
|
89
70
|
);
|
|
71
|
+
const currentStep = getCurrentStep(steps, currentStepIndex);
|
|
72
|
+
|
|
73
|
+
const goToNextStep = React.useCallback(() => onNext(steps), [onNext, steps]);
|
|
74
|
+
const goToPrevStep = React.useCallback(() => onBack(steps), [onBack, steps]);
|
|
75
|
+
|
|
76
|
+
const footer = React.useMemo(() => {
|
|
77
|
+
const wizardFooter = currentFooter || initialFooter;
|
|
78
|
+
|
|
79
|
+
if (isCustomWizardFooter(wizardFooter)) {
|
|
80
|
+
const customFooter = wizardFooter;
|
|
81
|
+
|
|
82
|
+
return typeof customFooter === 'function'
|
|
83
|
+
? customFooter(currentStep, goToNextStep, goToPrevStep, onClose)
|
|
84
|
+
: customFooter;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<WizardFooter
|
|
89
|
+
currentStep={currentStep}
|
|
90
|
+
onNext={goToNextStep}
|
|
91
|
+
onBack={goToPrevStep}
|
|
92
|
+
onClose={onClose}
|
|
93
|
+
isBackDisabled={currentStep?.id === steps[0]?.id}
|
|
94
|
+
{...wizardFooter}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}, [currentFooter, initialFooter, currentStep, goToNextStep, goToPrevStep, onClose, steps]);
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
const getStep = React.useCallback((stepId: string | number) => steps.find(step => step.id === stepId), [steps]);
|
|
100
|
+
|
|
101
|
+
const setStep = React.useCallback(
|
|
102
|
+
(step: Pick<WizardControlStep, 'id'> & Partial<WizardControlStep>) =>
|
|
94
103
|
setSteps(prevSteps =>
|
|
95
|
-
prevSteps.map(
|
|
96
|
-
if (
|
|
97
|
-
return { ...
|
|
104
|
+
prevSteps.map(prevStep => {
|
|
105
|
+
if (prevStep.id === step.id) {
|
|
106
|
+
return { ...prevStep, ...step };
|
|
98
107
|
}
|
|
99
108
|
|
|
100
|
-
return
|
|
109
|
+
return prevStep;
|
|
101
110
|
})
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
),
|
|
112
|
+
[]
|
|
113
|
+
);
|
|
114
|
+
|
|
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
|
+
);
|
|
105
153
|
|
|
106
154
|
return (
|
|
107
155
|
<WizardContext.Provider
|
|
108
156
|
value={{
|
|
109
157
|
steps,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
onBack,
|
|
158
|
+
currentStep,
|
|
159
|
+
currentStepIndex,
|
|
160
|
+
footer,
|
|
114
161
|
onClose,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
setFooter
|
|
162
|
+
getStep,
|
|
163
|
+
setStep,
|
|
164
|
+
toggleStep,
|
|
165
|
+
setFooter: setCurrentFooter,
|
|
166
|
+
onNext: goToNextStep,
|
|
167
|
+
onBack: goToPrevStep,
|
|
168
|
+
goToStepById: React.useCallback(id => goToStepById(steps, id), [goToStepById, steps]),
|
|
169
|
+
goToStepByName: React.useCallback(name => goToStepByName(steps, name), [goToStepByName, steps]),
|
|
170
|
+
goToStepByIndex: React.useCallback(index => goToStepByIndex(steps, index), [goToStepByIndex, steps])
|
|
119
171
|
}}
|
|
120
172
|
>
|
|
121
|
-
{
|
|
122
|
-
? children({ activeStep, steps, footer: wizardFooter, onNext, onBack, onClose })
|
|
123
|
-
: children}
|
|
173
|
+
{children}
|
|
124
174
|
</WizardContext.Provider>
|
|
125
175
|
);
|
|
126
176
|
};
|
|
127
177
|
|
|
178
|
+
WizardContextProvider.displayName = 'WizardContextProvider';
|
|
179
|
+
|
|
128
180
|
export const useWizardContext = () => React.useContext(WizardContext);
|
|
@@ -4,60 +4,82 @@ import { css } from '@patternfly/react-styles';
|
|
|
4
4
|
import styles from '@patternfly/react-styles/css/components/Wizard/wizard';
|
|
5
5
|
|
|
6
6
|
import { Button, ButtonVariant } from '../../../components/Button';
|
|
7
|
-
import { WizardControlStep, WizardNavStepFunction } from './types';
|
|
7
|
+
import { isCustomWizardFooter, WizardControlStep, WizardNavStepFunction } from './types';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Hosts the standard structure of a footer with ties to the active step so that text for buttons can vary from step to step.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
export interface WizardFooterProps {
|
|
14
|
-
/** The
|
|
15
|
-
|
|
14
|
+
/** The current step */
|
|
15
|
+
currentStep: WizardControlStep;
|
|
16
16
|
/** Next button callback */
|
|
17
17
|
onNext: () => WizardNavStepFunction | void;
|
|
18
18
|
/** Back button callback */
|
|
19
19
|
onBack: () => WizardNavStepFunction | void;
|
|
20
20
|
/** Cancel link callback */
|
|
21
21
|
onClose: () => void;
|
|
22
|
-
/** Custom text for the Next button. The
|
|
22
|
+
/** Custom text for the Next button. The current step's nextButtonText takes precedence. */
|
|
23
23
|
nextButtonText?: React.ReactNode;
|
|
24
24
|
/** Custom text for the Back button */
|
|
25
25
|
backButtonText?: React.ReactNode;
|
|
26
26
|
/** Custom text for the Cancel link */
|
|
27
27
|
cancelButtonText?: React.ReactNode;
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/** Flag to disable the next button */
|
|
29
|
+
isNextDisabled?: boolean;
|
|
30
|
+
/** Flag to disable the back button */
|
|
31
|
+
isBackDisabled?: boolean;
|
|
32
|
+
/** True to hide the Back button */
|
|
33
|
+
isBackHidden?: boolean;
|
|
34
|
+
/** True to hide the Cancel button */
|
|
35
|
+
isCancelHidden?: boolean;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
interface WizardFooterWrapperProps {
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const WizardFooterWrapper = ({ children }: WizardFooterWrapperProps) => (
|
|
43
|
+
<footer className={css(styles.wizardFooter)}>{children}</footer>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export const WizardFooter = ({ currentStep, ...internalProps }: WizardFooterProps) => {
|
|
47
|
+
const currentStepFooter = !isCustomWizardFooter(currentStep.footer) && currentStep.footer;
|
|
48
|
+
return <InternalWizardFooter {...internalProps} {...currentStepFooter} />;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const InternalWizardFooter = ({
|
|
33
52
|
onNext,
|
|
34
53
|
onBack,
|
|
35
54
|
onClose,
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
isNextDisabled,
|
|
56
|
+
isBackDisabled,
|
|
57
|
+
isBackHidden,
|
|
58
|
+
isCancelHidden,
|
|
38
59
|
nextButtonText = 'Next',
|
|
39
60
|
backButtonText = 'Back',
|
|
40
61
|
cancelButtonText = 'Cancel'
|
|
41
|
-
}: WizardFooterProps) => (
|
|
42
|
-
<
|
|
43
|
-
<Button variant={ButtonVariant.primary} type="submit" onClick={onNext} isDisabled={
|
|
44
|
-
{
|
|
62
|
+
}: Omit<WizardFooterProps, 'currentStep'>) => (
|
|
63
|
+
<WizardFooterWrapper>
|
|
64
|
+
<Button variant={ButtonVariant.primary} type="submit" onClick={onNext} isDisabled={isNextDisabled}>
|
|
65
|
+
{nextButtonText}
|
|
45
66
|
</Button>
|
|
46
67
|
|
|
47
|
-
{!
|
|
48
|
-
<Button variant={ButtonVariant.secondary} onClick={onBack} isDisabled={
|
|
68
|
+
{!isBackHidden && (
|
|
69
|
+
<Button variant={ButtonVariant.secondary} onClick={onBack} isDisabled={isBackDisabled}>
|
|
49
70
|
{backButtonText}
|
|
50
71
|
</Button>
|
|
51
72
|
)}
|
|
52
73
|
|
|
53
|
-
{!
|
|
74
|
+
{!isCancelHidden && (
|
|
54
75
|
<div className={styles.wizardFooterCancel}>
|
|
55
76
|
<Button variant={ButtonVariant.link} onClick={onClose}>
|
|
56
77
|
{cancelButtonText}
|
|
57
78
|
</Button>
|
|
58
79
|
</div>
|
|
59
80
|
)}
|
|
60
|
-
</
|
|
81
|
+
</WizardFooterWrapper>
|
|
61
82
|
);
|
|
62
83
|
|
|
84
|
+
WizardFooterWrapper.displayName = 'WizardFooterWrapper';
|
|
63
85
|
WizardFooter.displayName = 'WizardFooter';
|
|
@@ -15,7 +15,7 @@ export interface WizardHeaderProps {
|
|
|
15
15
|
/** Component type of the description */
|
|
16
16
|
descriptionComponent?: 'div' | 'p';
|
|
17
17
|
/** Flag indicating whether the close button should be in the header */
|
|
18
|
-
|
|
18
|
+
isCloseHidden?: boolean;
|
|
19
19
|
/** Aria-label applied to the X (Close) button */
|
|
20
20
|
closeButtonAriaLabel?: string;
|
|
21
21
|
/** id for the title */
|
|
@@ -28,21 +28,23 @@ export const WizardHeader: React.FunctionComponent<WizardHeaderProps> = ({
|
|
|
28
28
|
onClose = () => undefined,
|
|
29
29
|
title,
|
|
30
30
|
description,
|
|
31
|
-
|
|
31
|
+
isCloseHidden,
|
|
32
32
|
closeButtonAriaLabel,
|
|
33
33
|
titleId,
|
|
34
34
|
descriptionComponent: Component = 'p',
|
|
35
35
|
descriptionId
|
|
36
36
|
}: WizardHeaderProps) => (
|
|
37
37
|
<div className={css(styles.wizardHeader)}>
|
|
38
|
-
{!
|
|
38
|
+
{!isCloseHidden && (
|
|
39
39
|
<Button variant="plain" className={css(styles.wizardClose)} aria-label={closeButtonAriaLabel} onClick={onClose}>
|
|
40
40
|
<TimesIcon aria-hidden="true" />
|
|
41
41
|
</Button>
|
|
42
42
|
)}
|
|
43
|
+
|
|
43
44
|
<Title headingLevel="h2" size="3xl" className={css(styles.wizardTitle)} aria-label={title} id={titleId}>
|
|
44
45
|
{title || <> </>}
|
|
45
46
|
</Title>
|
|
47
|
+
|
|
46
48
|
{description && (
|
|
47
49
|
<Component className={css(styles.wizardDescription)} id={descriptionId}>
|
|
48
50
|
{description}
|
|
@@ -50,4 +52,5 @@ export const WizardHeader: React.FunctionComponent<WizardHeaderProps> = ({
|
|
|
50
52
|
)}
|
|
51
53
|
</div>
|
|
52
54
|
);
|
|
55
|
+
|
|
53
56
|
WizardHeader.displayName = 'WizardHeader';
|
|
@@ -5,14 +5,14 @@ import { css } from '@patternfly/react-styles';
|
|
|
5
5
|
export interface WizardNavProps {
|
|
6
6
|
/** children should be WizardNavItem components */
|
|
7
7
|
children?: any;
|
|
8
|
-
/** Aria-label applied to the
|
|
8
|
+
/** Aria-label applied to the navigation element */
|
|
9
9
|
'aria-label'?: string;
|
|
10
|
-
/** Sets the aria-labelledby attribute on the
|
|
10
|
+
/** Sets the aria-labelledby attribute on the navigation element */
|
|
11
11
|
'aria-labelledby'?: string;
|
|
12
|
-
/** Whether the
|
|
12
|
+
/** Whether the navigation is expanded */
|
|
13
13
|
isExpanded?: boolean;
|
|
14
|
-
/** True to return the inner list without the wrapping
|
|
15
|
-
|
|
14
|
+
/** True to return the inner list without the wrapping navigation element */
|
|
15
|
+
isInnerList?: boolean;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export const WizardNav: React.FunctionComponent<WizardNavProps> = ({
|
|
@@ -20,12 +20,10 @@ export const WizardNav: React.FunctionComponent<WizardNavProps> = ({
|
|
|
20
20
|
'aria-label': ariaLabel,
|
|
21
21
|
'aria-labelledby': ariaLabelledBy,
|
|
22
22
|
isExpanded = false,
|
|
23
|
-
|
|
23
|
+
isInnerList = false
|
|
24
24
|
}: WizardNavProps) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (returnList) {
|
|
28
|
-
return innerList;
|
|
25
|
+
if (isInnerList) {
|
|
26
|
+
return <ol className={css(styles.wizardNavList)}>{children}</ol>;
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
return (
|
|
@@ -38,4 +36,5 @@ export const WizardNav: React.FunctionComponent<WizardNavProps> = ({
|
|
|
38
36
|
</nav>
|
|
39
37
|
);
|
|
40
38
|
};
|
|
39
|
+
|
|
41
40
|
WizardNav.displayName = 'WizardNav';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { isCustomWizardNavItem, isWizardBasicStep, isWizardParentStep } from './types';
|
|
4
|
+
import { WizardProps } from './Wizard';
|
|
5
|
+
import { useWizardContext } from './WizardContext';
|
|
6
|
+
import { WizardNav, WizardNavProps } from './WizardNav';
|
|
7
|
+
import { WizardNavItem } from './WizardNavItem';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hosts deafult wizard navigation logic by utilizing the wizard's context and WizardNav/WizardNavItem.
|
|
11
|
+
* This component is not exposed to consumers.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface WizardNavInternalProps extends Pick<WizardProps, 'isStepVisitRequired'> {
|
|
15
|
+
nav: Partial<WizardNavProps>;
|
|
16
|
+
isNavExpanded: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const WizardNavInternal = ({ nav, isStepVisitRequired, isNavExpanded }: WizardNavInternalProps) => {
|
|
20
|
+
const { currentStep, steps, goToStepByIndex } = useWizardContext();
|
|
21
|
+
|
|
22
|
+
const wizardNavProps: WizardNavProps = {
|
|
23
|
+
isExpanded: isNavExpanded,
|
|
24
|
+
'aria-label': nav?.['aria-label'] || 'Wizard steps',
|
|
25
|
+
...(nav?.['aria-labelledby'] && {
|
|
26
|
+
'aria-labelledby': nav['aria-labelledby']
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<WizardNav {...wizardNavProps}>
|
|
32
|
+
{steps.map((step, index) => {
|
|
33
|
+
const stepIndex = index + 1;
|
|
34
|
+
const customStepNavItem = isCustomWizardNavItem(step.navItem) && (
|
|
35
|
+
<React.Fragment key={step.id}>
|
|
36
|
+
{typeof step.navItem === 'function'
|
|
37
|
+
? step.navItem(step, currentStep, steps, goToStepByIndex)
|
|
38
|
+
: step.navItem}
|
|
39
|
+
</React.Fragment>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (isWizardParentStep(step) && !step.isHidden) {
|
|
43
|
+
let firstSubStepIndex;
|
|
44
|
+
let hasActiveChild = false;
|
|
45
|
+
|
|
46
|
+
const subNavItems = step.subStepIds?.map((subStepId, subStepIndex) => {
|
|
47
|
+
const subStep = steps.find(step => step.id === subStepId);
|
|
48
|
+
const subStepOrderIndex = steps.indexOf(subStep) + 1;
|
|
49
|
+
const customSubStepNavItem = isCustomWizardNavItem(subStep.navItem) && (
|
|
50
|
+
<React.Fragment key={subStep.id}>
|
|
51
|
+
{typeof subStep.navItem === 'function'
|
|
52
|
+
? subStep.navItem(subStep, currentStep, steps, goToStepByIndex)
|
|
53
|
+
: subStep.navItem}
|
|
54
|
+
</React.Fragment>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Don't render the sub-step navigation item if the hidden property is enabled
|
|
58
|
+
if (subStep.isHidden) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Store the first sub-step index so that when its parent is clicked, the first sub-step is focused
|
|
63
|
+
if (subStepIndex === 0) {
|
|
64
|
+
firstSubStepIndex = subStepOrderIndex;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// When a sub-step is active, use this flag to set the parent step as active (isCurrent)
|
|
68
|
+
if (currentStep?.id === subStep.id) {
|
|
69
|
+
hasActiveChild = true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
customSubStepNavItem || (
|
|
74
|
+
<WizardNavItem
|
|
75
|
+
key={subStep.id}
|
|
76
|
+
id={subStep.id}
|
|
77
|
+
content={subStep.name}
|
|
78
|
+
isCurrent={currentStep?.id === subStep.id}
|
|
79
|
+
isDisabled={subStep.isDisabled || (isStepVisitRequired && !subStep.isVisited)}
|
|
80
|
+
isVisited={subStep.isVisited}
|
|
81
|
+
stepIndex={subStepOrderIndex}
|
|
82
|
+
onNavItemClick={goToStepByIndex}
|
|
83
|
+
status={subStep.status}
|
|
84
|
+
{...subStep.navItem}
|
|
85
|
+
/>
|
|
86
|
+
)
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
const hasEnabledChildren = React.Children.toArray(subNavItems).some(
|
|
90
|
+
child => React.isValidElement(child) && !child.props.isDisabled
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
customStepNavItem || (
|
|
95
|
+
<WizardNavItem
|
|
96
|
+
key={step.id}
|
|
97
|
+
id={step.id}
|
|
98
|
+
content={step.name}
|
|
99
|
+
isExpandable={true}
|
|
100
|
+
isCurrent={hasActiveChild}
|
|
101
|
+
isDisabled={!hasEnabledChildren}
|
|
102
|
+
isVisited={step.isVisited}
|
|
103
|
+
stepIndex={firstSubStepIndex}
|
|
104
|
+
onNavItemClick={goToStepByIndex}
|
|
105
|
+
status={step.status}
|
|
106
|
+
{...step.navItem}
|
|
107
|
+
>
|
|
108
|
+
<WizardNav {...wizardNavProps} isInnerList>
|
|
109
|
+
{subNavItems}
|
|
110
|
+
</WizardNav>
|
|
111
|
+
</WizardNavItem>
|
|
112
|
+
)
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (isWizardBasicStep(step) && !step.isHidden) {
|
|
117
|
+
return (
|
|
118
|
+
customStepNavItem || (
|
|
119
|
+
<WizardNavItem
|
|
120
|
+
key={step.id}
|
|
121
|
+
id={step.id}
|
|
122
|
+
content={step.name}
|
|
123
|
+
isCurrent={currentStep?.id === step.id}
|
|
124
|
+
isDisabled={step.isDisabled || (isStepVisitRequired && !step.isVisited)}
|
|
125
|
+
isVisited={step.isVisited}
|
|
126
|
+
stepIndex={stepIndex}
|
|
127
|
+
onNavItemClick={goToStepByIndex}
|
|
128
|
+
status={step.status}
|
|
129
|
+
{...step.navItem}
|
|
130
|
+
/>
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
})}
|
|
135
|
+
</WizardNav>
|
|
136
|
+
);
|
|
137
|
+
};
|