UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

179 lines (175 loc) 11 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 CFormControlWrapper = require('../form/CFormControlWrapper.js'); var utils = require('./utils.js'); var getNextActiveElement = require('../../utils/getNextActiveElement.js'); var isRTL = require('../../utils/isRTL.js'); const COneTimePassword = React.forwardRef((_a, ref) => { var { ariaLabel = (index, total) => `Digit ${index + 1} of ${total}`, autoSubmit = false, children, className, defaultValue, disabled = false, feedback, feedbackInvalid, feedbackValid, floatingClassName, floatingLabel, id, invalid, label, linear = true, masked = false, name, onChange, onComplete, placeholder, readOnly = false, required = false, size, text, tooltipFeedback, type = 'number', valid, value } = _a, rest = tslib_es6.__rest(_a, ["ariaLabel", "autoSubmit", "children", "className", "defaultValue", "disabled", "feedback", "feedbackInvalid", "feedbackValid", "floatingClassName", "floatingLabel", "id", "invalid", "label", "linear", "masked", "name", "onChange", "onComplete", "placeholder", "readOnly", "required", "size", "text", "tooltipFeedback", "type", "valid", "value"]); const inputRefs = React.useRef([]); const hiddenInputRef = React.useRef(null); // Count valid OTP input children const inputCount = React.useMemo(() => { return React.Children.count(children); }, [children]); const [inputValues, setInputValues] = React.useState(() => { var _a; const initialValue = String((_a = value !== null && value !== void 0 ? value : defaultValue) !== null && _a !== void 0 ? _a : ''); return Array.from({ length: inputCount }, (_, i) => initialValue[i] || ''); }); // Update input values when value prop changes (controlled mode) React.useEffect(() => { if (value !== undefined) { const valueString = String(value); setInputValues(Array.from({ length: inputCount }, (_, i) => valueString[i] || '')); } }, [value, inputCount]); // Update hidden input and trigger events const updateValue = React.useCallback((newValues) => { var _a; const newValue = newValues.join(''); if (hiddenInputRef.current) { hiddenInputRef.current.value = newValue; } onChange === null || onChange === void 0 ? void 0 : onChange(newValue); if (newValue.length === inputCount) { onComplete === null || onComplete === void 0 ? void 0 : onComplete(newValue); if (autoSubmit) { const form = (_a = hiddenInputRef.current) === null || _a === void 0 ? void 0 : _a.closest('form'); if (form && typeof form.requestSubmit === 'function') { form.requestSubmit(); } } } }, [autoSubmit, onChange, onComplete, inputCount]); const handleInputChange = React.useCallback((index, event) => { const inputValue = event.target.value; if (inputValue.length === 1 && !utils.isValidInput(inputValue, type)) { return; } const newValues = [...inputValues]; newValues[index] = inputValue.length === 1 ? inputValue : ''; setInputValues(newValues); updateValue(newValues); if (inputValue.length === 1) { const nextInput = getNextActiveElement.default(inputRefs.current, event.target, true, false); nextInput === null || nextInput === void 0 ? void 0 : nextInput.focus(); } }, [inputValues, type, updateValue]); const handleInputFocus = React.useCallback((event) => { const { target } = event; if (target.value) { setTimeout(() => { target.select(); }, 0); return; } if (linear) { const firstEmptyInput = inputRefs.current.find((input) => !(input === null || input === void 0 ? void 0 : input.value)); if (firstEmptyInput && firstEmptyInput !== target) { firstEmptyInput.focus(); } } }, [linear]); const handleKeyDown = React.useCallback((event) => { const { key, target } = event; if (key === 'Backspace' && target.value === '') { const newValues = [...inputValues]; const prevInput = getNextActiveElement.default(inputRefs.current, target, false, false); if (prevInput) { const prevIndex = inputRefs.current.indexOf(prevInput); if (prevIndex !== -1) { newValues[prevIndex] = ''; setInputValues(newValues); updateValue(newValues); prevInput.focus(); } } return; } if (key === 'ArrowRight') { if (linear && target.value === '') { return; } const shouldMoveNext = !isRTL.default(target); const nextInput = getNextActiveElement.default(inputRefs.current, target, shouldMoveNext, false); nextInput === null || nextInput === void 0 ? void 0 : nextInput.focus(); return; } if (key === 'ArrowLeft') { const shouldMoveNext = isRTL.default(target); const prevInput = getNextActiveElement.default(inputRefs.current, target, shouldMoveNext, false); prevInput === null || prevInput === void 0 ? void 0 : prevInput.focus(); } }, [inputValues, linear, updateValue]); const handlePaste = React.useCallback((index, event) => { var _a, _b; event.preventDefault(); const pastedData = event.clipboardData.getData('text'); const validChars = utils.extractValidChars(pastedData, type); if (!validChars) return; const newValues = [...inputValues]; const startIndex = index; for (let i = 0; i < validChars.length && startIndex + i < inputCount; i++) { newValues[startIndex + i] = validChars[i]; } setInputValues(newValues); updateValue(newValues); // Focus the next empty input or the last filled input const nextEmptyIndex = startIndex + validChars.length; if (nextEmptyIndex < inputCount) { (_a = inputRefs.current[nextEmptyIndex]) === null || _a === void 0 ? void 0 : _a.focus(); } else { (_b = inputRefs.current.at(-1)) === null || _b === void 0 ? void 0 : _b.focus(); } }, [inputValues, type, updateValue, inputCount]); let inputIndex = 0; return (React.createElement(CFormControlWrapper.CFormControlWrapper, { describedby: rest['aria-describedby'], feedback: feedback, feedbackInvalid: feedbackInvalid, feedbackValid: feedbackValid, floatingClassName: floatingClassName, floatingLabel: floatingLabel, id: id, invalid: invalid, label: label, text: text, tooltipFeedback: tooltipFeedback, valid: valid }, React.createElement("div", Object.assign({ className: index.default('form-otp', { [`form-otp-${size}`]: size, }, className), role: "group", ref: ref }, rest), React.Children.map(children, (child, index$1) => { var _a; if (!React.isValidElement(child) || ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) !== 'COneTimePasswordInput') { return child; } const inputChild = child; const currentInputIndex = inputIndex++; return React.cloneElement(inputChild, Object.assign(Object.assign({}, inputChild.props), { type: masked ? 'password' : 'text', className: index.default({ 'is-invalid': invalid, 'is-valid': valid, }, inputChild.props.className), id: inputChild.props.id || (id ? `${id}-${currentInputIndex}` : undefined), name: inputChild.props.name || (name ? `${name}-${currentInputIndex}` : undefined), placeholder: inputChild.props.placeholder || (placeholder && placeholder.length > 1 ? placeholder[currentInputIndex] : placeholder), value: inputValues[currentInputIndex] || '', tabIndex: currentInputIndex === 0 ? 0 : inputValues[currentInputIndex - 1] ? 0 : -1, disabled: disabled || inputChild.props.disabled, readOnly: readOnly || inputChild.props.readOnly, required: required || inputChild.props.required, 'aria-label': inputChild.props['aria-label'] || ariaLabel(currentInputIndex, inputCount), inputMode: type === 'number' ? 'numeric' : 'text', pattern: type === 'number' ? '[0-9]*' : '.*', onInput: (event) => { var _a, _b; handleInputChange(currentInputIndex, event); (_b = (_a = inputChild.props).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, event); }, onFocus: (event) => { var _a, _b; handleInputFocus(event); (_b = (_a = inputChild.props).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, event); }, onKeyDown: (event) => { var _a, _b; handleKeyDown(event); (_b = (_a = inputChild.props).onKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, event); }, onPaste: (event) => { var _a, _b; handlePaste(index$1, event); (_b = (_a = inputChild.props).onPaste) === null || _b === void 0 ? void 0 : _b.call(_a, event); }, ref: (el) => { inputRefs.current[currentInputIndex] = el; } })); }), React.createElement("input", { type: "hidden", id: id, name: name, value: inputValues.join(''), disabled: disabled, ref: hiddenInputRef })))); }); COneTimePassword.propTypes = Object.assign({ ariaLabel: PropTypes.func, autoSubmit: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), disabled: PropTypes.bool, id: PropTypes.string, linear: PropTypes.bool, masked: PropTypes.bool, name: PropTypes.string, onChange: PropTypes.func, onComplete: PropTypes.func, placeholder: PropTypes.string, readOnly: PropTypes.bool, required: PropTypes.bool, size: PropTypes.oneOf(['sm', 'lg']), type: PropTypes.oneOf(['number', 'text']), value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) }, CFormControlWrapper.CFormControlWrapper.propTypes); COneTimePassword.displayName = 'COneTimePassword'; exports.COneTimePassword = COneTimePassword; //# sourceMappingURL=COneTimePassword.js.map