@m3-moretv/react-code-input
Version:
Typescript implementation of some code/pin-code input
127 lines (126 loc) • 5.51 kB
JavaScript
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importStar(require("react"));
const classnames_1 = __importDefault(require("classnames"));
const utils_1 = require("./utils");
const BACKSPACE_KEY = 8;
const LEFT_ARROW_KEY = 37;
const UP_ARROW_KEY = 38;
const RIGHT_ARROW_KEY = 39;
const DOWN_ARROW_KEY = 40;
const E_KEY = 69;
const DOT_KEY = 190;
const COMMA_KEY = 188;
var Types;
(function (Types) {
Types["text"] = "text";
Types["number"] = "number";
})(Types = exports.Types || (exports.Types = {}));
const CodeInput = ({ fields, value, name, onChange, onBlur, onFocus = utils_1.defaultOnFocus, autoFocus, type = Types.text, disabled, isValid = true, className, inputClassName, invalidInputClassName }) => {
const [inputsValues, setInputsValues] = react_1.useState(utils_1.fillEmptyArray(fields).map((element, i) => value.split('')[i] || element));
const [inputsKeys, setInputsKeys] = react_1.useState(utils_1.fillEmptyArray(fields).map((element, i) => utils_1.uuid()));
const inputsRefs = inputsValues.map(() => react_1.useRef({}));
const handleChange = (event) => {
const target = event.target;
const value = target.value;
if (value === '') {
return;
}
const currInputIndex = Number(target.dataset.id);
const nextInputIndex = currInputIndex + 1;
let nextTarget = inputsRefs[nextInputIndex];
const copiedInputsValues = inputsValues.slice();
/** throwing focus on next input when the new value is equal
to previous cause onChange doesn't fire in this case */
if (value.length > 1) {
value.split('').forEach((chart, i) => {
if (currInputIndex + i < copiedInputsValues.length) {
copiedInputsValues[currInputIndex + i] = chart;
/**Set focus on last input with value after ctrl + v */
nextTarget = inputsRefs[currInputIndex + i];
}
});
}
else {
copiedInputsValues[currInputIndex] = value;
}
if (nextTarget) {
utils_1.moveToNewTarget(nextTarget);
}
setInputsValues(copiedInputsValues);
if (onChange) {
const fullValue = copiedInputsValues.join('');
onChange(fullValue);
}
};
const handleKeyDown = (event) => {
const target = event.currentTarget;
const currInputIndex = Number(target.dataset.id);
const nextInput = inputsRefs[currInputIndex + 1];
const prevInput = inputsRefs[currInputIndex - 1];
const currInput = inputsRefs[currInputIndex];
switch (event.keyCode) {
case BACKSPACE_KEY:
const copiedInputsValues = inputsValues.slice();
copiedInputsValues[currInputIndex] = '';
//to completely update input; helpfull on adroid when comma not beeing registered
const newKeys = inputsKeys.slice();
newKeys[currInputIndex] = utils_1.uuid();
setInputsValues(copiedInputsValues);
setInputsKeys(newKeys);
if (prevInput) {
utils_1.moveToNewTarget(prevInput);
}
else {
utils_1.updateFocus(currInput);
}
if (onChange) {
const fullValue = copiedInputsValues.join('');
onChange(fullValue);
}
break;
case LEFT_ARROW_KEY:
event.preventDefault();
if (prevInput) {
utils_1.moveToNewTarget(prevInput);
}
break;
case RIGHT_ARROW_KEY:
event.preventDefault();
if (nextInput) {
utils_1.moveToNewTarget(nextInput);
}
break;
case UP_ARROW_KEY:
event.preventDefault();
break;
case DOWN_ARROW_KEY:
event.preventDefault();
break;
case E_KEY:
case DOT_KEY:
case COMMA_KEY:
if (type === Types.number) {
event.preventDefault();
break;
}
default:
break;
}
};
const inputClasses = classnames_1.default(inputClassName, invalidInputClassName && { [invalidInputClassName]: !isValid });
return (react_1.default.createElement("div", { className: className }, inputsValues.map((value, i) => {
return (react_1.default.createElement("input", { ref: inputsRefs[i], id: utils_1.uuid(), name: name, "data-id": i, autoFocus: autoFocus && i === 0, value: value, key: inputsKeys[i], type: type, disabled: disabled, className: inputClasses, onBlur: onBlur, onChange: handleChange, onKeyDown: handleKeyDown, onFocus: onFocus, pattern: type === Types.number ? '[0-9]*' : undefined }));
})));
};
exports.default = CodeInput;