@talend/react-components
Version:
Set of react components.
234 lines (227 loc) • 8.32 kB
JavaScript
import { Fragment, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { ErrorState, StackVertical, Stepper as CoralStepper } from '@talend/design-system';
import Icon from '../Icon';
import CircularProgress from '../CircularProgress';
import { getTheme } from '../theme';
import theme from './Stepper.component.module.scss';
import { DEFAULT_TRANSITION_DURATION, StepperTransition } from './StepperTransition.component';
import I18N_DOMAIN_COMPONENTS from '../constants';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const getClass = getTheme(theme);
const SHOW_COMPLETED_TRANSITION_TIMER = 1000;
const TRANSITION_STATE = {
STEPS: 'STEPS',
TRANSITION: 'TRANSITION',
CHILD: 'CHILD'
};
const LOADING_STEP_STATUSES = {
ABORTED: 'aborted',
PENDING: 'pending',
LOADING: 'loading',
SUCCESS: 'success',
FAILURE: 'failure'
};
/**
* This function tells if there is an error in the steps
* @param {array} steps array of steps
*/
const isErrorInSteps = steps => steps.some(step => step.status === LOADING_STEP_STATUSES.FAILURE);
const getStepInError = steps => steps.find(step => step.status === LOADING_STEP_STATUSES.FAILURE);
/**
* This function tells if all the steps are successful
* @param {array} steps array of steps
*/
const isAllSuccessful = steps => steps.every(step => step.status === LOADING_STEP_STATUSES.SUCCESS);
/**
* This function tells if the loading is done, by an error, a success ot not started
* @param {array} steps array of steps
*/
const isStepsLoading = steps => steps.length !== 0 && !isAllSuccessful(steps) && !isErrorInSteps(steps);
/**
* This function returns a label for some status
* @param {string} status the current step status
*/
function getStatusText(t, status) {
switch (status) {
case LOADING_STEP_STATUSES.ABORTED:
return t('ABORTED', {
defaultValue: ' (Aborted)'
});
case LOADING_STEP_STATUSES.PENDING:
return t('PENDING', {
defaultValue: ' (Pending)'
});
default:
return null;
}
}
/**
* This function returns an icon that represent the current step
* @param {string} status the current step status
*/
function getIconByStatus(status) {
const iconCLass = getClass(`stepper-icon-${status}`, 'stepper-icon');
switch (status) {
case LOADING_STEP_STATUSES.SUCCESS:
return /*#__PURE__*/_jsx(Icon, {
name: "talend-check",
className: iconCLass
});
case LOADING_STEP_STATUSES.ABORTED:
return /*#__PURE__*/_jsx(Icon, {
name: "talend-cross",
className: iconCLass
});
case LOADING_STEP_STATUSES.PENDING:
return /*#__PURE__*/_jsx("span", {
className: iconCLass,
children: "-"
});
case LOADING_STEP_STATUSES.FAILURE:
return /*#__PURE__*/_jsx(Icon, {
name: "talend-warning",
className: iconCLass
});
case LOADING_STEP_STATUSES.LOADING:
return /*#__PURE__*/_jsx(CircularProgress, {
className: iconCLass
});
default:
return null;
}
}
function changeTransitionState(newTransitionState, setTransitionState, timer = 0) {
if (timer === 0) {
setTransitionState(newTransitionState);
} else {
setTimeout(() => {
setTransitionState(newTransitionState);
}, timer);
}
}
/**
* This function returns a rendered step
* @param {object} step the current loading step
* @param {number} index the index for the key
*/
function showStep(t, step, index, steps) {
const cssStep = getClass('stepper-step', `stepper-step-${step.status}`);
const a11y = {};
if ([LOADING_STEP_STATUSES.LOADING, LOADING_STEP_STATUSES.FAILURE].includes(step.status) || index === steps.length - 1 && step.status === LOADING_STEP_STATUSES.SUCCESS) {
a11y['aria-current'] = true;
}
return /*#__PURE__*/_jsxs("li", {
className: cssStep,
...a11y,
children: [/*#__PURE__*/_jsxs("div", {
className: getClass('stepper-step-infos'),
children: [getIconByStatus(step.status), step.label, getStatusText(t, step.status)]
}), step.message && /*#__PURE__*/_jsxs("div", {
className: getClass('stepper-step-message'),
children: [/*#__PURE__*/_jsx("span", {
className: getClass('stepper-step-message-label'),
children: step.message.label
}), step.message.description && /*#__PURE__*/_jsx("p", {
children: step.message.description
})]
})]
}, `step-${index}`);
}
/**
* This function generates a set transition state function
* @param {string} transition the transition state to set
* @param {number} timer the timer to set the transition
*/
function transition(transitionState, timer = 0) {
return setTransitionState => changeTransitionState(transitionState, setTransitionState, timer);
}
const transitionLoadingToEmpty = transition(TRANSITION_STATE.TRANSITION, SHOW_COMPLETED_TRANSITION_TIMER);
const transitionEmptyToChildren = transition(TRANSITION_STATE.CHILD, SHOW_COMPLETED_TRANSITION_TIMER + DEFAULT_TRANSITION_DURATION);
const transitionChildrenToEmpty = transition(TRANSITION_STATE.TRANSITION);
const transitionEmptyToLoading = transition(TRANSITION_STATE.STEPS, DEFAULT_TRANSITION_DURATION);
function Stepper({
steps,
title,
renderActions,
children
}) {
const {
t
} = useTranslation(I18N_DOMAIN_COMPONENTS);
const errorStep = getStepInError(steps);
const [transitionState, setTransitionState] = useState(isStepsLoading(steps) || !children ? TRANSITION_STATE.STEPS : TRANSITION_STATE.CHILD);
useEffect(() => {
const allSuccessful = isAllSuccessful(steps);
if (children && allSuccessful && (transitionState === TRANSITION_STATE.STEPS || transitionState === TRANSITION_STATE.TRANSITION)) {
transitionLoadingToEmpty(setTransitionState);
transitionEmptyToChildren(setTransitionState);
} else if (!allSuccessful && transitionState === TRANSITION_STATE.CHILD) {
transitionChildrenToEmpty(setTransitionState);
transitionEmptyToLoading(setTransitionState);
}
}, [steps]);
if (!!errorStep) {
var _errorStep$message;
return /*#__PURE__*/_jsx("div", {
className: getClass('loading-content-steps', 'error'),
children: /*#__PURE__*/_jsxs(StackVertical, {
gap: 0,
align: "center",
justify: "center",
children: [/*#__PURE__*/_jsx(ErrorState, {
title: errorStep.label,
description: (_errorStep$message = errorStep.message) === null || _errorStep$message === void 0 ? void 0 : _errorStep$message.label
}), renderActions && renderActions(!!errorStep) ? /*#__PURE__*/_jsx("div", {
children: renderActions(!!errorStep)
}) : null]
})
});
}
return /*#__PURE__*/_jsxs(Fragment, {
children: [/*#__PURE__*/_jsx(StepperTransition, {
active: transitionState === TRANSITION_STATE.CHILD,
children: children
}), /*#__PURE__*/_jsx(StepperTransition, {
active: transitionState === TRANSITION_STATE.STEPS,
children: /*#__PURE__*/_jsx("div", {
className: getClass('stepper'),
children: /*#__PURE__*/_jsxs("div", {
className: getClass('loading-content-steps'),
children: [title && /*#__PURE__*/_jsx("h2", {
children: title
}), /*#__PURE__*/_jsx("ol", {
className: getClass('stepper-steps'),
children: steps.map((step, index, array) => showStep(t, step, index, array))
})]
})
})
})]
});
}
Stepper.displayName = 'Stepper';
Stepper.defaultProps = {
steps: []
};
Stepper.propTypes = {
title: PropTypes.string,
renderActions: PropTypes.func,
children: PropTypes.element,
steps: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string,
status: PropTypes.oneOf(Object.values(LOADING_STEP_STATUSES)),
message: PropTypes.shape({
label: PropTypes.string,
description: PropTypes.string
})
}))
};
Stepper.SHOW_COMPLETED_TRANSITION_TIMER = SHOW_COMPLETED_TRANSITION_TIMER;
Stepper.LOADING_STEP_STATUSES = LOADING_STEP_STATUSES;
Stepper.isStepsLoading = isStepsLoading;
Stepper.isAllSuccessful = isAllSuccessful;
Stepper.isErrorInSteps = isErrorInSteps;
Stepper.Form = CoralStepper;
export default Stepper;
//# sourceMappingURL=Stepper.component.js.map