UNPKG

@carbon/ibm-security

Version:

Carbon for Cloud & Cognitive IBM Security UI components

454 lines (453 loc) 18 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/inherits"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; var _excluded = ["labels", "focusTrap", "title", "subTitle", "className", "navLabel"]; import _regeneratorRuntime from "@babel/runtime/regenerator"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /** * @file Wizard. * @copyright IBM Security 2019 - 2021 */ import classnames from 'classnames'; import PropTypes from 'prop-types'; import React, { Children, Component } from 'react'; import { getComponentNamespace } from '../../globals/namespace'; import * as defaultLabels from '../../globals/nls'; import { isClient, isNode } from '../../globals/utils/capabilities'; import Nav from '../Nav'; import { ProgressIndicator, ProgressStep } from '../ProgressIndicator'; import NavItem from '../Nav/NavItem'; import { Tearsheet } from '../Tearsheet'; import WizardStep from './WizardStep'; var namespace = getComponentNamespace('wizard'); var Wizard = /*#__PURE__*/function (_Component) { function Wizard() { var _this; _classCallCheck(this, Wizard); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Wizard, [].concat(args)); _defineProperty(_this, "state", { steps: _this.steps, componentState: _this.props.initState, stepInitState: _this.props.initState, currentStep: 0, isOpen: true, loading: false, controlledOpen: _this.props.isOpen != null, deleteIsLoading: false }); _defineProperty(_this, "setNextState", /*#__PURE__*/function () { var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(cb) { var changes, isLastStep; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _this.setState({ loading: true }); _context.prev = 1; _context.next = 4; return _this.currentStep.next(_this.state.componentState); case 4: changes = _context.sent; isLastStep = _this.isLastStep(); _this.setState(function (_ref2) { var currentStep = _ref2.currentStep, componentState = _ref2.componentState; return { currentStep: currentStep + (isLastStep ? 0 : 1), componentState: _objectSpread(_objectSpread(_objectSpread({}, componentState), changes), {}, { error: undefined }), loading: false, valid: undefined }; }, function () { _this.setState(function (_ref3) { var componentState = _ref3.componentState; return { stepInitState: componentState }; }); if (isLastStep) { if (cb) { cb(); } _this.props.onClose(_this.state.componentState); _this.setState({ isOpen: false }); } }); _context.next = 12; break; case 9: _context.prev = 9; _context.t0 = _context["catch"](1); _this.setState(function (_ref4) { var componentState = _ref4.componentState; return { loading: false, componentState: _objectSpread(_objectSpread({}, componentState), {}, { error: _context.t0 }) }; }); case 12: case "end": return _context.stop(); } }, _callee, null, [[1, 9]]); })); return function (_x) { return _ref.apply(this, arguments); }; }()); _defineProperty(_this, "setComponentState", function (changes, cb) { if (typeof changes === 'function') { _this.setState(function (_ref5) { var componentState = _ref5.componentState; var newComponentState = _objectSpread(_objectSpread({}, componentState), changes(componentState)); return { componentState: newComponentState, valid: _this.currentStep.validate(newComponentState) }; }, cb); } else { var newComponentState = _objectSpread(_objectSpread({}, _this.state.componentState), changes); _this.setState({ componentState: newComponentState, valid: _this.currentStep.validate(newComponentState) }, cb); } }); _defineProperty(_this, "isLastStep", function () { return _this.state.currentStep === _this.steps.length - 1; }); /** * Keeps the state in sync with the current props. * @param {Props} nextProps The current props passed to the component. * @returns {Record<object, any>} The updated state for the component. * @static */ _defineProperty(_this, "secondaryAction", function () { _this.setState(function (_ref6) { var componentState = _ref6.componentState, currentStep = _ref6.currentStep, steps = _ref6.steps; var previousStep = currentStep - 1; return { currentStep: previousStep, valid: steps[previousStep].validate(componentState) }; }); }); _defineProperty(_this, "closeAction", function () { _this.props.onClose(_this.state.componentState); if (!_this.state.controlledOpen) { _this.setState({ isOpen: false }); } }); _defineProperty(_this, "deleteAction", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: _this.setState({ deleteIsLoading: true }); _context2.prev = 1; _context2.next = 4; return _this.props.onDelete(_this.state.componentState); case 4: _this.setState(function (_ref8) { var controlledOpen = _ref8.controlledOpen; return { deleteIsLoading: false, isOpen: !controlledOpen }; }); _context2.next = 11; break; case 7: _context2.prev = 7; _context2.t0 = _context2["catch"](1); _this.setState({ deleteIsLoading: false, deleteButtonText: 'Failed' }); setTimeout(function () { return _this.setState({ deleteButtonText: undefined }); }, 5000); case 11: case "end": return _context2.stop(); } }, _callee2, null, [[1, 7]]); }))); _defineProperty(_this, "handleItemSelect", function (event) { var id = event.target.id; _this.setState(function (_ref9) { var componentState = _ref9.componentState, steps = _ref9.steps; return { currentStep: Number(id), valid: steps[id].validate(componentState) }; }); }); _defineProperty(_this, "renderSidebar", function () { var _this$state = _this.state, currentStep = _this$state.currentStep, valid = _this$state.valid; return !_this.sequentialMode ? /*#__PURE__*/React.createElement(Nav, { label: _this.props.navLabel }, _this.steps.map(function (_ref10, index) { var title = _ref10.title; return /*#__PURE__*/React.createElement(NavItem, { key: title, id: String(index), className: "".concat(namespace, "__navItem"), current: String(currentStep), disabled: !valid, handleItemSelect: _this.handleItemSelect, link: false }, title); })) : /*#__PURE__*/React.createElement(ProgressIndicator, { currentIndex: currentStep, vertical: true }, _this.steps.map(function (_ref11, index) { var title = _ref11.title; return /*#__PURE__*/React.createElement(ProgressStep, { key: title, disabled: index > currentStep, label: title }); })); }); return _this; } _inherits(Wizard, _Component); return _createClass(Wizard, [{ key: "editMode", get: function get() { return this.props.onDelete !== Wizard.defaultProps.onDelete; } }, { key: "sequentialMode", get: function get() { if (typeof this.props.isSequential !== 'undefined') { return this.props.isSequential; } return !this.editMode; } }, { key: "currentStep", get: function get() { if (this.state.steps[this.state.currentStep]) { return _objectSpread(_objectSpread({}, WizardStep.defaultProps), this.state.steps[this.state.currentStep]); } return undefined; } }, { key: "steps", get: function get() { if (Children.count(this.props.children)) { return Children.map(this.props.children, WizardStep.getPropsFromElement).filter(function (props) { return props != null; }); } else if (Array.isArray(this.props.steps)) { return this.props.steps; } return []; } }, { key: "isValid", get: function get() { if (this.state.valid == null) { var valid = this.currentStep.validate(this.state.componentState); this.setState({ valid: valid }); return valid; } return this.state.valid; } }, { key: "render", value: /** * Renders the component. */ function render() { var _this2 = this; var _this$props = this.props, labels = _this$props.labels, focusTrap = _this$props.focusTrap, title = _this$props.title, subTitle = _this$props.subTitle, className = _this$props.className, _ = _this$props.navLabel, other = _objectWithoutProperties(_this$props, _excluded); var componentLabels = _objectSpread(_objectSpread({}, defaultLabels.labels), labels); var _this$state$isOpen = this.state.isOpen, isOpen = _this$state$isOpen === void 0 ? true : _this$state$isOpen; if (!this.currentStep) { return null; } var buttons = { primary: { onClick: function onClick() { return _this2.setNextState(); }, isDisabled: !this.isValid || this.state.loading }, secondary: this.state.currentStep === 0 ? { onClick: this.closeAction, isDisabled: true } : { onClick: function onClick() { return _this2.setState(function (_ref12) { var componentState = _ref12.componentState, currentStep = _ref12.currentStep, steps = _ref12.steps; var previousStep = currentStep - 1; return { currentStep: previousStep, valid: steps[previousStep].validate(componentState) }; }); }, isDisabled: false }, cancelSetup: { onClick: this.closeAction, isDisabled: false, secondaryText: componentLabels.WIZARD_TERTIARY_SECONDARY_TEXT }, // Wizard should not have a close button in the top right. close: { isDisabled: true }, delete: this.editMode ? { onClick: this.deleteAction, isDisabled: this.state.deleteIsLoading } : undefined }; var buttonLabels = { TEARSHEET_PRIMARY_BUTTON: this.isLastStep() ? componentLabels.WIZARD_FINISH_BUTTON : componentLabels.WIZARD_NEXT_BUTTON, TEARSHEET_SECONDARY_BUTTON: this.state.currentStep === 0 ? componentLabels.WIZARD_CANCEL_BUTTON : componentLabels.WIZARD_BACK_BUTTON, TEARSHEET_DELETE_BUTTON: this.editMode ? this.state.deleteButtonText || componentLabels.WIZARD_TEARSHEET_DELETE_BUTTON : undefined, TEARSHEET_TERTIARY_BUTTON: componentLabels.WIZARD_TERTIARY_BUTTON }; var renderMain = function renderMain() { return _this2.currentStep.renderMain(_this2.state.componentState, _this2.setComponentState); }; return /*#__PURE__*/React.createElement(Tearsheet, _extends({ focusTrap: focusTrap, sidebarTitle: title, sidebarSubtitle: subTitle, mainTitle: this.currentStep.title, renderSidebar: this.renderSidebar, renderMain: renderMain, rootNode: this.props.rootNode, primaryButton: buttons.primary, secondaryButton: buttons.secondary, tertiaryButton: buttons.cancelSetup, closeButton: buttons.close, deleteButton: buttons.delete, isOpen: isOpen, labels: _objectSpread(_objectSpread({}, componentLabels), defaultLabels.filterFalsey(buttonLabels)), loading: this.state.loading, loadingMessage: this.props.loadingMessage, className: classnames(namespace, className) }, other)); } }], [{ key: "getDerivedStateFromProps", value: function getDerivedStateFromProps(props, state) { var nextState = state; if (state.controlledOpen && props.isOpen && !state.isOpen) { nextState = _objectSpread(_objectSpread({}, nextState), {}, { currentStep: 0, componentState: props.initState }); } nextState = _objectSpread(_objectSpread({}, nextState), {}, { isOpen: state.controlledOpen ? props.isOpen : state.isOpen }); return nextState; } }]); }(Component); Wizard.propTypes = { /** @type {...React.Element(WizardStep)} Provide one element of the WizardStep component for each step of your wizard (see the WizardStep docs). */ children: PropTypes.node, /** Optional class name for the wrapper node. */ className: PropTypes.string, /** @type {boolean} Focus trap. */ focusTrap: PropTypes.bool, /** @type {object} The initial state object of the wizard * (useful to prefill some values in your forms). */ initState: PropTypes.instanceOf(Object), /** @type {boolean} The open state. * Leave this property undefined, to give control over the open state to the Wizard component. * When defined at component creation time, the open state is controlled only by this property. */ isOpen: PropTypes.bool, /** @type {boolean} Defines whether the wizard is sequential or not. */ isSequential: PropTypes.bool, /** @type {object} The labels to be used with the wizard * (useful to override default labels) */ labels: defaultLabels.propType, /** @type {string} The message to be displayed during loading. */ loadingMessage: PropTypes.string, /** Provide an accessible label that describes the Wizard sidebar navigation. */ navLabel: PropTypes.string, /** @type {function(wizardState: Object): any} This is called whenever the wizard closes (or wants to close) */ onClose: PropTypes.func, /** @type {function(wizardState: Object): Promise} onDelete handler, enables edit mode */ onDelete: PropTypes.func, /** @type {DOM Node} Target to render the wizard. */ rootNode: isNode() ? PropTypes.instanceOf(Node) : PropTypes.any, /** @type {Array<object>} An object list of step props. __(deprecated)__ */ steps: PropTypes.arrayOf(PropTypes.shape(WizardStep.propTypes)), /** @type {string} The subtitle of the Wizard. */ subTitle: PropTypes.string, /** @type {string} The title of the Wizard. */ title: PropTypes.string.isRequired }; Wizard.defaultProps = { className: '', focusTrap: true, rootNode: isClient() ? document.body : undefined, subTitle: '', isOpen: undefined, initState: {}, onClose: function onClose() {}, steps: [], children: undefined, onDelete: function onDelete() { return Promise.resolve(); }, isSequential: undefined, labels: {}, navLabel: 'Steps navigation' }; export default Wizard;