1 | import { __rest } from "tslib";
|
2 | import * as React from 'react';
|
3 | import { KEY_CODES } from '../../helpers/constants';
|
4 | import { css } from '@patternfly/react-styles';
|
5 | import styles from '@patternfly/react-styles/css/components/Wizard/wizard';
|
6 | import { Modal, ModalVariant } from '../Modal';
|
7 | import { WizardFooterInternal } from './WizardFooterInternal';
|
8 | import { WizardToggle } from './WizardToggle';
|
9 | import { WizardNav } from './WizardNav';
|
10 | import { WizardNavItem } from './WizardNavItem';
|
11 | import { WizardContextProvider } from './WizardContext';
|
12 | import { WizardHeader } from './WizardHeader';
|
13 | export class Wizard extends React.Component {
|
14 | constructor(props) {
|
15 | super(props);
|
16 | this.handleKeyClicks = (event) => {
|
17 | if (event.keyCode === KEY_CODES.ESCAPE_KEY) {
|
18 | if (this.state.isNavOpen) {
|
19 | this.setState({ isNavOpen: !this.state.isNavOpen });
|
20 | }
|
21 | else if (this.props.isOpen) {
|
22 | this.props.onClose();
|
23 | }
|
24 | }
|
25 | };
|
26 | this.onNext = () => {
|
27 | const { onNext, onClose, onSave } = this.props;
|
28 | const { currentStep } = this.state;
|
29 | const flattenedSteps = this.getFlattenedSteps();
|
30 | const maxSteps = flattenedSteps.length;
|
31 | if (currentStep >= maxSteps) {
|
32 |
|
33 | if (onSave) {
|
34 | return onSave();
|
35 | }
|
36 | return onClose();
|
37 | }
|
38 | else {
|
39 | const newStep = currentStep + 1;
|
40 | this.setState({
|
41 | currentStep: newStep
|
42 | });
|
43 | const { id: prevId, name: prevName } = flattenedSteps[currentStep - 1];
|
44 | const { id, name } = flattenedSteps[newStep - 1];
|
45 | return onNext && onNext({ id, name }, { prevId, prevName });
|
46 | }
|
47 | };
|
48 | this.onBack = () => {
|
49 | const { onBack } = this.props;
|
50 | const { currentStep } = this.state;
|
51 | const flattenedSteps = this.getFlattenedSteps();
|
52 | if (flattenedSteps.length < currentStep) {
|
53 |
|
54 | const adjustedStep = flattenedSteps.length;
|
55 | this.setState({
|
56 | currentStep: adjustedStep
|
57 | });
|
58 | }
|
59 | else {
|
60 | const newStep = currentStep - 1 <= 0 ? 0 : currentStep - 1;
|
61 | this.setState({
|
62 | currentStep: newStep
|
63 | });
|
64 | const { id: prevId, name: prevName } = flattenedSteps[newStep];
|
65 | const { id, name } = flattenedSteps[newStep - 1];
|
66 | return onBack && onBack({ id, name }, { prevId, prevName });
|
67 | }
|
68 | };
|
69 | this.goToStep = (step) => {
|
70 | const { onGoToStep } = this.props;
|
71 | const { currentStep } = this.state;
|
72 | const flattenedSteps = this.getFlattenedSteps();
|
73 | const maxSteps = flattenedSteps.length;
|
74 | if (step < 1) {
|
75 | step = 1;
|
76 | }
|
77 | else if (step > maxSteps) {
|
78 | step = maxSteps;
|
79 | }
|
80 | this.setState({ currentStep: step, isNavOpen: false });
|
81 | const { id: prevId, name: prevName } = flattenedSteps[currentStep - 1];
|
82 | const { id, name } = flattenedSteps[step - 1];
|
83 | return onGoToStep && onGoToStep({ id, name }, { prevId, prevName });
|
84 | };
|
85 | this.goToStepById = (stepId) => {
|
86 | const flattenedSteps = this.getFlattenedSteps();
|
87 | let step;
|
88 | for (let i = 0; i < flattenedSteps.length; i++) {
|
89 | if (flattenedSteps[i].id === stepId) {
|
90 | step = i + 1;
|
91 | break;
|
92 | }
|
93 | }
|
94 | if (step) {
|
95 | this.setState({ currentStep: step });
|
96 | }
|
97 | };
|
98 | this.goToStepByName = (stepName) => {
|
99 | const flattenedSteps = this.getFlattenedSteps();
|
100 | let step;
|
101 | for (let i = 0; i < flattenedSteps.length; i++) {
|
102 | if (flattenedSteps[i].name === stepName) {
|
103 | step = i + 1;
|
104 | break;
|
105 | }
|
106 | }
|
107 | if (step) {
|
108 | this.setState({ currentStep: step });
|
109 | }
|
110 | };
|
111 | this.getFlattenedSteps = () => {
|
112 | const { steps } = this.props;
|
113 | const flattenedSteps = [];
|
114 | for (const step of steps) {
|
115 | if (step.steps) {
|
116 | for (const childStep of step.steps) {
|
117 | flattenedSteps.push(childStep);
|
118 | }
|
119 | }
|
120 | else {
|
121 | flattenedSteps.push(step);
|
122 | }
|
123 | }
|
124 | return flattenedSteps;
|
125 | };
|
126 | this.getFlattenedStepsIndex = (flattenedSteps, stepName) => {
|
127 | for (let i = 0; i < flattenedSteps.length; i++) {
|
128 | if (flattenedSteps[i].name === stepName) {
|
129 | return i + 1;
|
130 | }
|
131 | }
|
132 | return 0;
|
133 | };
|
134 | this.initSteps = (steps) => {
|
135 |
|
136 | for (let i = 0; i < steps.length; i++) {
|
137 | if (steps[i].steps) {
|
138 | for (let j = 0; j < steps[i].steps.length; j++) {
|
139 | steps[i].steps[j] = Object.assign({ canJumpTo: true }, steps[i].steps[j]);
|
140 | }
|
141 | }
|
142 | steps[i] = Object.assign({ canJumpTo: true }, steps[i]);
|
143 | }
|
144 | return steps;
|
145 | };
|
146 | this.getElement = (appendTo) => {
|
147 | if (typeof appendTo === 'function') {
|
148 | return appendTo();
|
149 | }
|
150 | return appendTo || document.body;
|
151 | };
|
152 | const newId = Wizard.currentId++;
|
153 | this.titleId = props.titleId || `pf-wizard-title-${newId}`;
|
154 | this.descriptionId = props.descriptionId || `pf-wizard-description-${newId}`;
|
155 | this.state = {
|
156 | currentStep: this.props.startAtStep && Number.isInteger(this.props.startAtStep) ? this.props.startAtStep : 1,
|
157 | isNavOpen: false
|
158 | };
|
159 | }
|
160 | componentDidMount() {
|
161 | const target = typeof document !== 'undefined' ? document.body : null;
|
162 | if (target) {
|
163 | target.addEventListener('keydown', this.handleKeyClicks, false);
|
164 | }
|
165 | }
|
166 | componentWillUnmount() {
|
167 | const target = (typeof document !== 'undefined' && document.body) || null;
|
168 | if (target) {
|
169 | target.removeEventListener('keydown', this.handleKeyClicks, false);
|
170 | }
|
171 | }
|
172 | render() {
|
173 | const _a = this.props, {
|
174 |
|
175 | width, height, title, description, descriptionComponent, onClose, onSave, onBack, onNext, onGoToStep, className, steps, startAtStep, nextButtonText = 'Next', backButtonText = 'Back', cancelButtonText = 'Cancel', hideClose, closeButtonAriaLabel = 'Close', navAriaLabel, navAriaLabelledBy, mainAriaLabel, mainAriaLabelledBy, hasNoBodyPadding, footer, appendTo, isOpen, titleId, descriptionId, isNavExpandable } = _a, rest = __rest(_a, ["width", "height", "title", "description", "descriptionComponent", "onClose", "onSave", "onBack", "onNext", "onGoToStep", "className", "steps", "startAtStep", "nextButtonText", "backButtonText", "cancelButtonText", "hideClose", "closeButtonAriaLabel", "navAriaLabel", "navAriaLabelledBy", "mainAriaLabel", "mainAriaLabelledBy", "hasNoBodyPadding", "footer", "appendTo", "isOpen", "titleId", "descriptionId", "isNavExpandable"])
|
176 |
|
177 | ;
|
178 | const { currentStep } = this.state;
|
179 | const flattenedSteps = this.getFlattenedSteps();
|
180 | const adjustedStep = flattenedSteps.length < currentStep ? flattenedSteps.length : currentStep;
|
181 | const activeStep = flattenedSteps[adjustedStep - 1];
|
182 | const computedSteps = this.initSteps(steps);
|
183 | const firstStep = activeStep === flattenedSteps[0];
|
184 | const isValid = activeStep && activeStep.enableNext !== undefined ? activeStep.enableNext : true;
|
185 | const nav = (isWizardNavOpen) => {
|
186 | const wizNavAProps = {
|
187 | isOpen: isWizardNavOpen,
|
188 | 'aria-label': navAriaLabel,
|
189 | 'aria-labelledby': (title || navAriaLabelledBy) && (navAriaLabelledBy || this.titleId)
|
190 | };
|
191 | return (React.createElement(WizardNav, Object.assign({}, wizNavAProps), computedSteps.map((step, index) => {
|
192 | if (step.isFinishedStep) {
|
193 |
|
194 | return;
|
195 | }
|
196 | let enabled;
|
197 | let navItemStep;
|
198 | if (step.steps) {
|
199 | let hasActiveChild = false;
|
200 | let canJumpToParent = false;
|
201 | for (const subStep of step.steps) {
|
202 | if (activeStep.name === subStep.name) {
|
203 |
|
204 | hasActiveChild = true;
|
205 | }
|
206 | if (subStep.canJumpTo) {
|
207 | canJumpToParent = true;
|
208 | }
|
209 | }
|
210 | navItemStep = this.getFlattenedStepsIndex(flattenedSteps, step.steps[0].name);
|
211 | return (React.createElement(WizardNavItem, { key: index, id: step.id, content: step.name, isExpandable: isNavExpandable, isCurrent: hasActiveChild, isDisabled: !canJumpToParent, step: navItemStep, onNavItemClick: this.goToStep },
|
212 | React.createElement(WizardNav, Object.assign({}, wizNavAProps, { returnList: true }), step.steps.map((childStep, indexChild) => {
|
213 | if (childStep.isFinishedStep) {
|
214 |
|
215 | return;
|
216 | }
|
217 | navItemStep = this.getFlattenedStepsIndex(flattenedSteps, childStep.name);
|
218 | enabled = childStep.canJumpTo;
|
219 | return (React.createElement(WizardNavItem, { key: `child_${indexChild}`, id: childStep.id, content: childStep.name, isCurrent: activeStep.name === childStep.name, isDisabled: !enabled, step: navItemStep, onNavItemClick: this.goToStep }));
|
220 | }))));
|
221 | }
|
222 | navItemStep = this.getFlattenedStepsIndex(flattenedSteps, step.name);
|
223 | enabled = step.canJumpTo;
|
224 | return (React.createElement(WizardNavItem, Object.assign({}, step.stepNavItemProps, { key: index, id: step.id, content: step.name, isCurrent: activeStep.name === step.name, isDisabled: !enabled, step: navItemStep, onNavItemClick: this.goToStep })));
|
225 | })));
|
226 | };
|
227 | const context = {
|
228 | goToStepById: this.goToStepById,
|
229 | goToStepByName: this.goToStepByName,
|
230 | onNext: this.onNext,
|
231 | onBack: this.onBack,
|
232 | onClose,
|
233 | activeStep
|
234 | };
|
235 | const divStyles = Object.assign(Object.assign({}, (height ? { height } : {})), (width ? { width } : {}));
|
236 | const wizard = (React.createElement(WizardContextProvider, { value: context },
|
237 | React.createElement("div", Object.assign({}, rest, { className: css(styles.wizard, activeStep && activeStep.isFinishedStep && 'pf-m-finished', className), style: Object.keys(divStyles).length ? divStyles : undefined }),
|
238 | title && (React.createElement(WizardHeader, { titleId: this.titleId, descriptionId: this.descriptionId, onClose: onClose, title: title, description: description, descriptionComponent: descriptionComponent, closeButtonAriaLabel: closeButtonAriaLabel, hideClose: hideClose })),
|
239 | React.createElement(WizardToggle, { mainAriaLabel: mainAriaLabel, isInPage: isOpen === undefined, mainAriaLabelledBy: (title || mainAriaLabelledBy) && (mainAriaLabelledBy || this.titleId), isNavOpen: this.state.isNavOpen, onNavToggle: isNavOpen => this.setState({ isNavOpen }), nav: nav, steps: steps, activeStep: activeStep, hasNoBodyPadding: hasNoBodyPadding }, footer || (React.createElement(WizardFooterInternal, { onNext: this.onNext, onBack: this.onBack, onClose: onClose, isValid: isValid, firstStep: firstStep, activeStep: activeStep, nextButtonText: (activeStep && activeStep.nextButtonText) || nextButtonText, backButtonText: backButtonText, cancelButtonText: cancelButtonText }))))));
|
240 | if (isOpen !== undefined) {
|
241 | return (React.createElement(Modal, { width: width !== null ? width : undefined, isOpen: isOpen, variant: ModalVariant.large, "aria-labelledby": this.titleId, "aria-describedby": this.descriptionId, showClose: false, hasNoBodyWrapper: true }, wizard));
|
242 | }
|
243 | return wizard;
|
244 | }
|
245 | }
|
246 | Wizard.displayName = 'Wizard';
|
247 | Wizard.currentId = 0;
|
248 | Wizard.defaultProps = {
|
249 | title: null,
|
250 | description: '',
|
251 | descriptionComponent: 'p',
|
252 | className: '',
|
253 | startAtStep: 1,
|
254 | nextButtonText: 'Next',
|
255 | backButtonText: 'Back',
|
256 | cancelButtonText: 'Cancel',
|
257 | hideClose: false,
|
258 | closeButtonAriaLabel: 'Close',
|
259 | navAriaLabel: null,
|
260 | navAriaLabelledBy: null,
|
261 | mainAriaLabel: null,
|
262 | mainAriaLabelledBy: null,
|
263 | hasNoBodyPadding: false,
|
264 | onBack: null,
|
265 | onNext: null,
|
266 | onGoToStep: null,
|
267 | width: null,
|
268 | height: null,
|
269 | footer: null,
|
270 | onClose: () => undefined,
|
271 | appendTo: null,
|
272 | isOpen: undefined,
|
273 | isNavExpandable: false
|
274 | };
|
275 |
|
\ | No newline at end of file |