UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

202 lines (198 loc) 10.7 kB
'use strict'; var tslib_es6 = require('../../node_modules/tslib/tslib.es6.js'); var React = require('react'); var PropTypes = require('prop-types'); var index = require('../../_virtual/index.js'); var CCollapse = require('../collapse/CCollapse.js'); var getNextActiveElement = require('../../utils/getNextActiveElement.js'); var CStepper = React.forwardRef(function (_a, ref) { var controlledActiveStepIndex = _a.activeStepIndex, className = _a.className, _b = _a.defaultActiveStepIndex, defaultActiveStepIndex = _b === void 0 ? 0 : _b, _c = _a.layout, layout = _c === void 0 ? 'horizontal' : _c, _d = _a.linear, linear = _d === void 0 ? true : _d, onFinish = _a.onFinish, onReset = _a.onReset, onStepChange = _a.onStepChange, onStepValidationComplete = _a.onStepValidationComplete, _e = _a.steps, steps = _e === void 0 ? [] : _e, _f = _a.stepButtonLayout, stepButtonLayout = _f === void 0 ? 'horizontal' : _f, _g = _a.validation, validation = _g === void 0 ? true : _g, rest = tslib_es6.__rest(_a, ["activeStepIndex", "className", "defaultActiveStepIndex", "layout", "linear", "onFinish", "onReset", "onStepChange", "onStepValidationComplete", "steps", "stepButtonLayout", "validation"]); var stepperRef = React.useRef(null); var stepsRef = React.useRef(null); var stepButtonRefs = React.useRef([]); var uniqueId = React.useId(); var isControlled = controlledActiveStepIndex !== undefined; var _h = React.useState(isControlled ? controlledActiveStepIndex : defaultActiveStepIndex), internalActiveStepIndex = _h[0], setInternalActiveStepIndex = _h[1]; var _j = React.useState(false), isFinished = _j[0], setIsFinished = _j[1]; var activeStepIndex = isControlled ? controlledActiveStepIndex : internalActiveStepIndex; // Sync state if controlled prop changes React.useEffect(function () { if (isControlled) { setInternalActiveStepIndex(controlledActiveStepIndex); } }, [controlledActiveStepIndex, isControlled]); // Ensure stepButtonRefs array has the correct size React.useEffect(function () { stepButtonRefs.current = stepButtonRefs.current.slice(0, steps.length); }, [steps.length]); var isStepValid = React.useCallback(function (index) { var _a; if (!validation) { return true; } var currentStepData = steps[index]; var form = (_a = currentStepData === null || currentStepData === void 0 ? void 0 : currentStepData.formRef) === null || _a === void 0 ? void 0 : _a.current; if (form) { var isValid = form.checkValidity(); onStepValidationComplete === null || onStepValidationComplete === void 0 ? void 0 : onStepValidationComplete({ stepNumber: index + 1, isValid: isValid, }); if (form && !isValid) { form.reportValidity(); return false; } } return true; }, [steps, validation]); var setActiveStep = React.useCallback(function (index, bypassValidation) { if (bypassValidation === void 0) { bypassValidation = false; } if (index < 0 || index >= steps.length || index === activeStepIndex) { return; } // Validate current step before moving forward if (!bypassValidation && index > activeStepIndex && !isStepValid(activeStepIndex)) { return; } if (!isControlled) { setInternalActiveStepIndex(index); } onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(index + 1); }, [steps.length, activeStepIndex, isStepValid, isControlled, onStepChange]); var handleStepClick = function (index) { if (linear) { setActiveStep(index, index <= activeStepIndex); return; } setActiveStep(index, true); }; var handleNext = function () { if (activeStepIndex < steps.length - 1) { setActiveStep(activeStepIndex + 1); } else { handleFinish(); // Attempt finish if already on last step } }; var handlePrev = function () { if (activeStepIndex > 0) { setActiveStep(activeStepIndex - 1, true); // Bypass validation when going back } }; var handleFinish = function () { if (activeStepIndex === steps.length - 1 && isStepValid(activeStepIndex)) { setIsFinished(true); onFinish === null || onFinish === void 0 ? void 0 : onFinish(); } }; var handleReset = function () { var _a; if (validation) { steps.forEach(function (step) { var _a, _b; return (_b = (_a = step.formRef) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.reset(); }); } if (!isControlled) { setInternalActiveStepIndex(defaultActiveStepIndex); } setIsFinished(false); onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(defaultActiveStepIndex); onReset === null || onReset === void 0 ? void 0 : onReset(); (_a = stepButtonRefs.current[defaultActiveStepIndex]) === null || _a === void 0 ? void 0 : _a.focus(); }; var handleKeyDown = function (event) { var target = event.target; var currentButton = target.closest('button.stepper-step-button'); if (!currentButton || !stepsRef.current) { return; } var buttons = tslib_es6.__spreadArray([], stepsRef.current.querySelectorAll('button.stepper-step-button'), true); var nextElement = null; switch (event.key) { case 'ArrowRight': case 'ArrowDown': { nextElement = getNextActiveElement.default(buttons, currentButton, true, false); break; } case 'ArrowLeft': case 'ArrowUp': { nextElement = getNextActiveElement.default(buttons, currentButton, false, false); break; } case 'Home': { nextElement = buttons[0]; break; } case 'End': { nextElement = buttons.at(-1); break; } default: { return; } } if (nextElement) { event.preventDefault(); nextElement.focus(); } }; // Expose methods via ref React.useImperativeHandle(ref, function () { return ({ next: handleNext, prev: handlePrev, finish: handleFinish, reset: handleReset, }); }); var isVertical = layout === 'vertical'; return (React.createElement("div", tslib_es6.__assign({ className: index.default('stepper', { 'stepper-vertical': isVertical, }, className), ref: stepperRef }, rest), React.createElement("ol", { className: "stepper-steps", "aria-orientation": isVertical ? 'vertical' : 'horizontal', ref: stepsRef, onKeyDown: handleKeyDown, role: "tablist" }, steps.map(function (step, index$1) { var _a; var isActive = !isFinished && index$1 === activeStepIndex; var isComplete = isFinished || index$1 < activeStepIndex; var isDisabled = isFinished || (linear && index$1 > activeStepIndex + 1); var stepId = "stepper-".concat(rest.id || uniqueId, "-step-").concat(index$1); var panelId = "stepper-".concat(rest.id || uniqueId, "-panel-").concat(index$1); return (React.createElement("li", { key: index$1, className: index.default('stepper-step', stepButtonLayout), role: "presentation" }, React.createElement("button", tslib_es6.__assign({ type: "button", className: index.default('stepper-step-button', { active: isActive, complete: isComplete, }), disabled: isDisabled, id: stepId, role: "tab", onClick: function () { return handleStepClick(index$1); }, ref: function (el) { return (stepButtonRefs.current[index$1] = el); }, "aria-selected": isActive }, (step.content && { 'aria-controls': panelId, }), { tabIndex: isActive ? 0 : -1 }), React.createElement("span", { className: "stepper-step-indicator" }, isComplete ? (React.createElement("span", { className: "stepper-step-indicator-icon" })) : (React.createElement("span", { className: "stepper-step-indicator-text" }, (_a = step.indicator) !== null && _a !== void 0 ? _a : index$1 + 1))), React.createElement("span", { className: "stepper-step-label" }, step.label)), index$1 < steps.length - 1 && React.createElement("div", { className: "stepper-step-connector" }), step.content && isVertical && (React.createElement(CCollapse.CCollapse, { className: "stepper-step-content", id: panelId, role: "tabpanel", visible: isActive, "aria-hidden": !isActive, "aria-labelledby": stepId, "aria-live": "polite" }, step.content)))); })), !isVertical && steps.some(function (step) { return step.content !== undefined && step.content !== null; }) && (React.createElement("div", { className: "stepper-content" }, steps.map(function (step, index$1) { var isActive = !isFinished && index$1 === activeStepIndex; var stepId = "stepper-".concat(rest.id || uniqueId, "-step-").concat(index$1); var panelId = "stepper-".concat(rest.id || uniqueId, "-panel-").concat(index$1); return (React.createElement("div", { key: index$1, className: index.default('stepper-pane', { show: isActive, active: isActive, }), id: panelId, role: "tabpanel", "aria-hidden": !isActive, "aria-labelledby": stepId, "aria-live": "polite" }, step.content)); }))))); }); CStepper.displayName = 'CStepper'; CStepper.propTypes = { activeStepIndex: PropTypes.number, className: PropTypes.string, defaultActiveStepIndex: PropTypes.number, layout: PropTypes.oneOf(['horizontal', 'vertical']), linear: PropTypes.bool, onFinish: PropTypes.func, onReset: PropTypes.func, onStepChange: PropTypes.func, onStepValidationComplete: PropTypes.func, steps: PropTypes.arrayOf(PropTypes.shape({ label: PropTypes.node.isRequired, content: PropTypes.node, formRef: PropTypes.object, // Check for object shape might be better }).isRequired).isRequired, stepButtonLayout: PropTypes.oneOf(['horizontal', 'vertical']), validation: PropTypes.bool, }; exports.CStepper = CStepper; //# sourceMappingURL=CStepper.js.map