react-input-pin-code
Version:
Pin input built with React component and styled-components
144 lines (133 loc) • 10.2 kB
JavaScript
import { jsx } from 'react/jsx-runtime';
import { useRef, useMemo, useEffect } from 'react';
import cx from 'clsx';
import { SIZE_LARGE, SIZE_MEDIUM, SIZE_SMALL, SIZE_EXTRA_SMALL, INPUT_KEY_BACKSPACE } from '../constants/index.js';
import { validateToPattern } from '../utils/string/index.js';
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = "input.styles-module_inputWrapper__USKTA {\n margin-right: 0.375rem;\n outline: transparent solid 2px;\n outline-offset: 2px;\n text-align: center;\n border-radius: 0.375rem;\n border-width: 1px;\n border-style: solid;\n border-color: var(--ripc-input-border-color);\n background-color: inherit;\n box-sizing: border-box;\n}\ninput.styles-module_inputWrapper__USKTA.styles-module_isExtraSmall__oAc-h {\n width: 1.5rem;\n height: 1.5rem;\n font-size: 0.75rem;\n}\ninput.styles-module_inputWrapper__USKTA.styles-module_isSmall__6FtvA {\n width: 2rem;\n height: 2rem;\n font-size: 0.875rem;\n}\ninput.styles-module_inputWrapper__USKTA.styles-module_isMedium__6rur1 {\n width: 2.5rem;\n height: 2.5rem;\n font-size: 1rem;\n}\ninput.styles-module_inputWrapper__USKTA.styles-module_isLarge__oSLPp {\n width: 3rem;\n height: 3rem;\n font-size: 1.125rem;\n}\ninput.styles-module_inputWrapper__USKTA:focus {\n border-color: var(--ripc-focus-input-border-color);\n box-shadow: var(--ripc-focus-input-border-color) 0px 0px 0px 1px;\n}\ninput.styles-module_inputWrapper__USKTA:last-child {\n margin-right: 0;\n}\ninput.styles-module_inputWrapper__USKTA.styles-module_hasCompleted__GpQi5.styles-module_showState__InvUY:valid {\n border-color: var(--ripc-valid-input-border-color);\n box-shadow: var(--ripc-valid-input-border-color) 0px 0px 0px 1px;\n background-color: var(--ripc-valid-input-background-color);\n}\ninput.styles-module_inputWrapper__USKTA.styles-module_showState__InvUY:invalid {\n border-color: var(--ripc-error-input-border-color);\n box-shadow: var(--ripc-error-input-border-color) 0px 0px 0px 1px;\n background-color: var(--ripc-error-input-background-color);\n}\ninput.styles-module_inputWrapper__USKTA:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlcy5tb2R1bGUuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLHNCQUFzQjtFQUN0Qiw4QkFBOEI7RUFDOUIsbUJBQW1CO0VBQ25CLGtCQUFrQjtFQUNsQix1QkFBdUI7RUFDdkIsaUJBQWlCO0VBQ2pCLG1CQUFtQjtFQUNuQiw0Q0FBNEM7RUFDNUMseUJBQXlCO0VBQ3pCLHNCQUFzQjtBQUN4QjtBQUNBO0VBQ0UsYUFBYTtFQUNiLGNBQWM7RUFDZCxrQkFBa0I7QUFDcEI7QUFDQTtFQUNFLFdBQVc7RUFDWCxZQUFZO0VBQ1osbUJBQW1CO0FBQ3JCO0FBQ0E7RUFDRSxhQUFhO0VBQ2IsY0FBYztFQUNkLGVBQWU7QUFDakI7QUFDQTtFQUNFLFdBQVc7RUFDWCxZQUFZO0VBQ1osbUJBQW1CO0FBQ3JCO0FBQ0E7RUFDRSxrREFBa0Q7RUFDbEQsZ0VBQWdFO0FBQ2xFO0FBQ0E7RUFDRSxlQUFlO0FBQ2pCO0FBQ0E7RUFDRSxrREFBa0Q7RUFDbEQsZ0VBQWdFO0VBQ2hFLDBEQUEwRDtBQUM1RDtBQUNBO0VBQ0Usa0RBQWtEO0VBQ2xELGdFQUFnRTtFQUNoRSwwREFBMEQ7QUFDNUQ7QUFDQTtFQUNFLFlBQVk7RUFDWixtQkFBbUI7QUFDckIiLCJmaWxlIjoic3R5bGVzLm1vZHVsZS5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiaW5wdXQuaW5wdXRXcmFwcGVyIHtcbiAgbWFyZ2luLXJpZ2h0OiAwLjM3NXJlbTtcbiAgb3V0bGluZTogdHJhbnNwYXJlbnQgc29saWQgMnB4O1xuICBvdXRsaW5lLW9mZnNldDogMnB4O1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG4gIGJvcmRlci1yYWRpdXM6IDAuMzc1cmVtO1xuICBib3JkZXItd2lkdGg6IDFweDtcbiAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcbiAgYm9yZGVyLWNvbG9yOiB2YXIoLS1yaXBjLWlucHV0LWJvcmRlci1jb2xvcik7XG4gIGJhY2tncm91bmQtY29sb3I6IGluaGVyaXQ7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG59XG5pbnB1dC5pbnB1dFdyYXBwZXIuaXNFeHRyYVNtYWxsIHtcbiAgd2lkdGg6IDEuNXJlbTtcbiAgaGVpZ2h0OiAxLjVyZW07XG4gIGZvbnQtc2l6ZTogMC43NXJlbTtcbn1cbmlucHV0LmlucHV0V3JhcHBlci5pc1NtYWxsIHtcbiAgd2lkdGg6IDJyZW07XG4gIGhlaWdodDogMnJlbTtcbiAgZm9udC1zaXplOiAwLjg3NXJlbTtcbn1cbmlucHV0LmlucHV0V3JhcHBlci5pc01lZGl1bSB7XG4gIHdpZHRoOiAyLjVyZW07XG4gIGhlaWdodDogMi41cmVtO1xuICBmb250LXNpemU6IDFyZW07XG59XG5pbnB1dC5pbnB1dFdyYXBwZXIuaXNMYXJnZSB7XG4gIHdpZHRoOiAzcmVtO1xuICBoZWlnaHQ6IDNyZW07XG4gIGZvbnQtc2l6ZTogMS4xMjVyZW07XG59XG5pbnB1dC5pbnB1dFdyYXBwZXI6Zm9jdXMge1xuICBib3JkZXItY29sb3I6IHZhcigtLXJpcGMtZm9jdXMtaW5wdXQtYm9yZGVyLWNvbG9yKTtcbiAgYm94LXNoYWRvdzogdmFyKC0tcmlwYy1mb2N1cy1pbnB1dC1ib3JkZXItY29sb3IpIDBweCAwcHggMHB4IDFweDtcbn1cbmlucHV0LmlucHV0V3JhcHBlcjpsYXN0LWNoaWxkIHtcbiAgbWFyZ2luLXJpZ2h0OiAwO1xufVxuaW5wdXQuaW5wdXRXcmFwcGVyLmhhc0NvbXBsZXRlZC5zaG93U3RhdGU6dmFsaWQge1xuICBib3JkZXItY29sb3I6IHZhcigtLXJpcGMtdmFsaWQtaW5wdXQtYm9yZGVyLWNvbG9yKTtcbiAgYm94LXNoYWRvdzogdmFyKC0tcmlwYy12YWxpZC1pbnB1dC1ib3JkZXItY29sb3IpIDBweCAwcHggMHB4IDFweDtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tcmlwYy12YWxpZC1pbnB1dC1iYWNrZ3JvdW5kLWNvbG9yKTtcbn1cbmlucHV0LmlucHV0V3JhcHBlci5zaG93U3RhdGU6aW52YWxpZCB7XG4gIGJvcmRlci1jb2xvcjogdmFyKC0tcmlwYy1lcnJvci1pbnB1dC1ib3JkZXItY29sb3IpO1xuICBib3gtc2hhZG93OiB2YXIoLS1yaXBjLWVycm9yLWlucHV0LWJvcmRlci1jb2xvcikgMHB4IDBweCAwcHggMXB4O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1yaXBjLWVycm9yLWlucHV0LWJhY2tncm91bmQtY29sb3IpO1xufVxuaW5wdXQuaW5wdXRXcmFwcGVyOmRpc2FibGVkIHtcbiAgb3BhY2l0eTogMC41O1xuICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xufSJdfQ== */";
var styles = {"inputWrapper":"styles-module_inputWrapper__USKTA","isExtraSmall":"styles-module_isExtraSmall__oAc-h","isSmall":"styles-module_isSmall__6FtvA","isMedium":"styles-module_isMedium__6rur1","isLarge":"styles-module_isLarge__oSLPp","hasCompleted":"styles-module_hasCompleted__GpQi5","showState":"styles-module_showState__InvUY"};
styleInject(css_248z);
const normalizeNewValue = (currentValue, eventValue) => {
if (!currentValue) {
return eventValue.split('');
}
if (eventValue.length > 2) {
return eventValue.split('');
}
if (eventValue === '') {
return [];
}
if (currentValue[0] === eventValue[0]) {
return [eventValue[1]];
}
return [eventValue[0]];
};
const sizeConfigMap = {
[SIZE_EXTRA_SMALL]: {
className: 'isExSmall',
},
[SIZE_SMALL]: {
className: 'isSmall',
},
[SIZE_MEDIUM]: {
className: 'isMedium',
},
[SIZE_LARGE]: {
className: 'isLarge',
},
};
const PinInputField = ({ index, value, values, completed, type = 'number', mask, size = SIZE_MEDIUM, validate, format, showState = true, autoFocus = false, autoTab = true, 'aria-describedby': ariaDescribedby, 'aria-label': ariaLabel = 'Please enter pin code', 'aria-labelledby': ariaLabelledby, autoComplete = 'off', disabled, inputMode, id, name, placeholder = 'o', required, inputClassName, inputStyle = {}, onChange, onBlur, onFocus, onKeyDown, }) => {
const inputRef = useRef(null);
const handleInputChange = (e) => {
const currentValue = values[index];
const eventValue = e.target.value;
const newValues = [...values];
const rawValue = normalizeNewValue(currentValue, eventValue).slice(0, newValues.length - index);
const regex = type === 'number' ? /(^$)|(\d+)/ : /.*/;
const shouldFireChange = rawValue.every((val) => regex.test(val));
if (!onChange) {
return;
}
// apply formatter to transform
const newValue = format ? rawValue.map((val) => format(val)) : rawValue;
if (newValue.length) {
newValue.forEach((val, idx) => (newValues[index + idx] = val));
}
else {
newValues[index] = '';
}
if (!shouldFireChange) {
return;
}
onChange(newValue, index, newValues);
// auto-tab to the specified pin input
let inputEl = inputRef.current;
for (let i = 0; i < newValue.length; i++) {
if (inputEl) {
inputEl = inputEl.nextElementSibling;
}
}
if (newValue && autoTab && inputEl instanceof HTMLInputElement) {
inputEl.focus();
}
};
const handleKeyDown = (e) => {
if (inputRef.current
&& e.key === INPUT_KEY_BACKSPACE
&& autoTab
&& values[index] === ''
&& index > 0) {
const prevInput = inputRef.current.previousElementSibling;
if (prevInput instanceof HTMLInputElement) {
prevInput.focus();
}
}
if (onKeyDown) {
onKeyDown(e);
}
};
const handleInputFocus = (e) => {
e.target.placeholder = '';
if (onFocus) {
onFocus(e);
}
};
const handleInputBlur = (e) => {
e.target.placeholder = placeholder;
if (onBlur) {
onBlur(e);
}
};
const pattern = useMemo(() => validateToPattern(validate), [validate]);
// auto-focus on mount
useEffect(() => {
if (inputRef.current && autoFocus && index === 0) {
inputRef.current.focus();
}
}, [autoFocus, index]);
const { [size]: { className: sizeClassName, }, } = sizeConfigMap;
return (jsx("input", { ref: inputRef, type: mask ? 'password' : 'text', "aria-describedby": ariaDescribedby, "aria-disabled": disabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "aria-required": required, autoComplete: autoComplete, disabled: disabled, name: name, id: id && `${id}-${index}`, className: cx(styles.inputWrapper, styles[sizeClassName], completed && styles.hasCompleted, showState && styles.showState, inputClassName), inputMode: inputMode || (type === 'number' ? 'numeric' : 'text'), required: required, placeholder: placeholder, pattern: pattern, value: value, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, onBlur: handleInputBlur, style: inputStyle, "data-index": index }));
};
export { PinInputField as P, styleInject as s };
//# sourceMappingURL=component-B3MV4PJV.js.map