UNPKG

kwikid-components-react

Version:

KwikID's Component Library in React

241 lines (234 loc) 9.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _kwikidToolkit = require("kwikid-toolkit"); var _react = _interopRequireWildcard(require("react")); var _Messages = _interopRequireDefault(require("../../messages/Messages")); var _InputOtp = require("./InputOtp.definition"); var _InputOtp2 = require("./InputOtp.style"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } // Constants for magic numbers moved to the top of the file const DEFAULT_OTP_LENGTH = 6; // Default OTP length const BASE_36 = 36; // For the random string conversion const RANDOM_STRING_START = 2; // Starting index for the random string const RANDOM_STRING_LENGTH = 9; // Length of the random ID suffix const KwikUIInputOtp = _ref => { let { customStyles = { wrapper: {}, container: {}, label: {}, input: {} }, disabled = false, id = "input_otp", label = undefined, otpLength = DEFAULT_OTP_LENGTH, messages = [], placeholder = undefined, required = true, shape = _InputOtp.IKwikUIInputOtpShape.CURVED, size = _InputOtp.IKwikUIInputOtpSize.M, updateOn = _InputOtp.IKwikUIInputOtpUpdateOn.CHANGE, value = undefined, onInput = undefined, onInputValidate = undefined, isInputCopyDisabled = false, isInputPasteDisabled = false, onInputCopyDisabled = undefined, onInputPasteDisabled = undefined, mode = _InputOtp.IKwikUIInputOtpMode.MULTIPLE } = _ref; // Create a unique ID prefix for this component instance const instanceIdPrefix = _react.default.useMemo(() => "".concat(id, "-").concat(Math.random().toString(BASE_36).substr(RANDOM_STRING_START, RANDOM_STRING_LENGTH)), [id]); const [valid, setValid] = _react.default.useState(undefined); const [inputFocused, setInputFocused] = _react.default.useState(undefined); const [otpValues, setOtpValues] = _react.default.useState(Array(otpLength || DEFAULT_OTP_LENGTH).fill("")); const [finalOtpValue, setFinalOtpValue] = _react.default.useState(value); // Create a ref for the container element to scope our DOM queries const containerRef = _react.default.useRef(null); // Define handleOnInput at the top to avoid "used before defined" error const handleOnInput = newValue => { if (onInputValidate) { const validation = onInputValidate(id, newValue); setValid(validation === null || validation === void 0 ? void 0 : validation.isValid); } else { setValid(true); } // Use Number.isNaN instead of isNaN to fix linter error if (Number.isNaN(Number(newValue))) { newValue = ""; } if (onInput && !disabled) { onInput(id, newValue); } }; (0, _react.useEffect)(() => { if (value) { const updatedValue = value.split(""); setOtpValues(updatedValue); } else { setOtpValues(new Array(otpLength || DEFAULT_OTP_LENGTH).fill("")); } }, [otpLength]); (0, _react.useEffect)(() => { if (mode === "multiple" && (value === null || value === void 0 ? void 0 : value.length) === otpLength) { const updatedValue = value.split(""); if (updatedValue.length) { setOtpValues(updatedValue); } } else { setFinalOtpValue(value); } }, []); (0, _react.useEffect)(() => { const updatedValue = (finalOtpValue === null || finalOtpValue === void 0 ? void 0 : finalOtpValue.split("")) || []; if (updatedValue.length !== otpLength) { while (updatedValue.length !== otpLength) { updatedValue.push(""); } } setOtpValues(updatedValue); }, [mode]); const handleSingleChange = e => { if (/^\d*$/.test(e.target.value)) { setFinalOtpValue(e.target.value); handleOnInput(e.target.value); } }; const handleChange = (e, index) => { if (/^\d*$/.test(e.target.value)) { const newOtpValues = [...otpValues]; newOtpValues[index] = e.target.value; setOtpValues(newOtpValues); const newValue = newOtpValues.join(""); setFinalOtpValue(newValue); handleOnInput(newValue); if (e.target.value && index < otpLength - 1) { if (containerRef.current) { const nextField = containerRef.current.querySelector("#".concat(instanceIdPrefix, "-box-").concat(index + 1)); if (nextField) { nextField.focus(); } } } } }; const handleOnKeyDown = (e, index) => { if (e.key === "Backspace" && otpValues[index] === "") { if (index > 0) { if (containerRef.current) { const prevField = containerRef.current.querySelector("#".concat(instanceIdPrefix, "-box-").concat(index - 1)); if (prevField) { prevField.focus(); } } } } }; const handleOnInputCopy = e => { if (isInputCopyDisabled) { e.preventDefault(); if (onInputCopyDisabled) { onInputCopyDisabled(); } } }; const handleOnInputPaste = e => { if (isInputPasteDisabled) { e.preventDefault(); if (onInputPasteDisabled) { onInputPasteDisabled(); } } }; const handleOnClick = (_e, _index) => { // Find the first empty input in this OTP component and focus it if (containerRef.current && mode === "multiple") { // Find the index of the first empty value const firstEmptyIndex = otpValues.findIndex(value => value === ""); // Only proceed if there's an empty input and we're not at the end if (firstEmptyIndex !== -1) { // Find the input element for this index within this component instance const firstEmptyInput = containerRef.current.querySelector("#".concat(instanceIdPrefix, "-box-").concat(firstEmptyIndex)); // Focus the first empty input if found if (firstEmptyInput) { firstEmptyInput.focus(); } } } }; return /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpWrapper, { style: customStyles.wrapper }, label && mode === "multiple" && /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpOutsideLabel, { size: size, disabled: disabled, style: customStyles.label }, label, required && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "\xA0*")), /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpContainer, { ref: containerRef, size: size, shape: shape, disabled: disabled, className: "\n input input-number\n ".concat(valid === false ? "input-error" : "", "\n ").concat(valid !== false && inputFocused ? "input-focused" : "", "\n "), style: customStyles.container }, mode === "multiple" ? /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpBoxesContainer, null, otpValues.map((value, index) => /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpBox, { key: index, size: size, shape: shape, disabled: disabled, style: customStyles.input }, /*#__PURE__*/_react.default.createElement("input", { disabled: disabled, id: "".concat(instanceIdPrefix, "-box-").concat(index), type: "text", maxLength: 1, value: value, placeholder: placeholder ? placeholder.substring(0, 1) : "", onChange: e => handleChange(e, index), onFocus: () => setInputFocused(true), onBlur: () => { if (updateOn === "blur") { handleOnInput(otpValues.join("")); } setInputFocused(false); }, onKeyDown: e => handleOnKeyDown(e, index), onCopy: handleOnInputCopy, onPaste: handleOnInputPaste, onClick: e => handleOnClick(e, index), style: customStyles.input })))) : /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpSingleContainer, { shape: shape, size: size, disabled: disabled }, label && /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpLabel, { size: size, disabled: disabled, style: customStyles.label }, label, required && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "\xA0*")), /*#__PURE__*/_react.default.createElement("input", { disabled: disabled, id: id, type: "text", maxLength: otpLength, value: finalOtpValue, placeholder: placeholder, onChange: handleSingleChange, onFocus: () => setInputFocused(true), onBlur: e => { if (updateOn === "blur") { handleOnInput(e.target.value); } setInputFocused(false); }, onCopy: handleOnInputCopy, onPaste: handleOnInputPaste, style: customStyles.input }))), (0, _kwikidToolkit.isNotEmptyValue)(messages) && /*#__PURE__*/_react.default.createElement(_InputOtp2.KwikUIStyleInputOtpMessagesContainer, null, /*#__PURE__*/_react.default.createElement(_Messages.default, { messages: messages, size: size }))); }; var _default = exports.default = KwikUIInputOtp;