diff --git a/README.md b/README.md index 4aa6c34..84bde97 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,22 @@ const App = () => { }; ``` +## Passing a value + +```tsx +import React, { useState } from 'react'; +import AuthCode from 'react-auth-code-input'; + +const App = () => { + const [result, setResult] = useState(''); + const handleOnChange = (res: string) => { + setResult(res); + }; + + return ; +}; +``` + ## SMS Autofill This component supports autofill from SMS's received, tested on Safari and Chrome in iOS. @@ -137,6 +153,11 @@ This component supports autofill from SMS's received, tested on Safari and Chrom ### 3.2.1 +- Block tab if current code position is not filled +- Added possibility to pass a value prop + +### 3.2.1 + - Fix allowing non-numeric characters being introduced in numeric mode on Safari and Firefox. ### 3.2.0 diff --git a/dist/index.js b/dist/index.js index f75d74a..7fb9af0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -23,6 +23,17 @@ var propsMap = { max: '9' } }; +var valueValidation = { + alpha: function alpha(value) { + return /^[a-zA-Z]*$/.test(value); + }, + alphanumeric: function alphanumeric(value) { + return /^[a-zA-Z0-9]*$/.test(value); + }, + numeric: function numeric(value) { + return /^[0-9]*$/.test(value); + } +}; var AuthCode = React.forwardRef(function (_ref, ref) { var _ref$allowedCharacter = _ref.allowedCharacters, allowedCharacters = _ref$allowedCharacter === void 0 ? 'alphanumeric' : _ref$allowedCharacter, @@ -37,7 +48,9 @@ var AuthCode = React.forwardRef(function (_ref, ref) { _ref$length = _ref.length, length = _ref$length === void 0 ? 6 : _ref$length, placeholder = _ref.placeholder, - onChange = _ref.onChange; + onChange = _ref.onChange, + value = _ref.value; + var values = value ? value.split('') : []; if (isNaN(length) || length < 1) { throw new Error('Length should be a number and greater than 0'); @@ -49,6 +62,14 @@ var AuthCode = React.forwardRef(function (_ref, ref) { throw new Error('Invalid value for allowedCharacters. Use alpha, numeric, or alphanumeric'); } + if (value && value.length > length) { + throw new Error('Value length should not be greater than length'); + } + + if (value && !valueValidation[allowedCharacters](value)) { + throw new Error("Value should only contain " + allowedCharacters + " characters"); + } + var inputsRef = React.useRef([]); var inputProps = propsMap[allowedCharacters]; React.useImperativeHandle(ref, function () { @@ -126,6 +147,10 @@ var AuthCode = React.forwardRef(function (_ref, ref) { sendResult(); } + + if (key === 'Tab' && target.value === '') { + e.preventDefault(); + } }; var handleOnFocus = function handleOnFocus(e) { @@ -175,7 +200,8 @@ var AuthCode = React.forwardRef(function (_ref, ref) { autoComplete: i === 0 ? 'one-time-code' : 'off', "aria-label": ariaLabel ? ariaLabel + ". Character " + (i + 1) + "." : "Character " + (i + 1) + ".", disabled: disabled, - placeholder: placeholder + placeholder: placeholder, + defaultValue: values[i] || '' }))); }; diff --git a/dist/index.js.map b/dist/index.js.map index c55ecd6..1d6009b 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import React, {\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef\n} from 'react';\n\nconst allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric'] as const;\n\nexport type AuthCodeProps = {\n allowedCharacters?: typeof allowedCharactersValues[number];\n ariaLabel?: string;\n autoFocus?: boolean;\n containerClassName?: string;\n disabled?: boolean;\n inputClassName?: string;\n isPassword?: boolean;\n length?: number;\n placeholder?: string;\n onChange: (res: string) => void;\n};\n\ntype InputMode = 'text' | 'numeric';\n\ntype InputType = 'text' | 'tel' | 'password';\n\ntype InputProps = {\n type: InputType;\n inputMode: InputMode;\n pattern: string;\n min?: string;\n max?: string;\n};\n\nexport type AuthCodeRef = {\n focus: () => void;\n clear: () => void;\n};\n\nconst propsMap: { [key: string]: InputProps } = {\n alpha: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z]{1}'\n },\n\n alphanumeric: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z0-9]{1}'\n },\n\n numeric: {\n type: 'tel',\n inputMode: 'numeric',\n pattern: '[0-9]{1}',\n min: '0',\n max: '9'\n }\n};\n\nconst AuthCode = forwardRef(\n (\n {\n allowedCharacters = 'alphanumeric',\n ariaLabel,\n autoFocus = true,\n containerClassName,\n disabled,\n inputClassName,\n isPassword = false,\n length = 6,\n placeholder,\n onChange\n },\n ref\n ) => {\n if (isNaN(length) || length < 1) {\n throw new Error('Length should be a number and greater than 0');\n }\n\n if (!allowedCharactersValues.some((value) => value === allowedCharacters)) {\n throw new Error(\n 'Invalid value for allowedCharacters. Use alpha, numeric, or alphanumeric'\n );\n }\n\n const inputsRef = useRef>([]);\n const inputProps = propsMap[allowedCharacters];\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n if (inputsRef.current) {\n inputsRef.current[0].focus();\n }\n },\n clear: () => {\n if (inputsRef.current) {\n for (let i = 0; i < inputsRef.current.length; i++) {\n inputsRef.current[i].value = '';\n }\n inputsRef.current[0].focus();\n }\n sendResult();\n }\n }));\n\n useEffect(() => {\n if (autoFocus) {\n inputsRef.current[0].focus();\n }\n }, []);\n\n const sendResult = () => {\n const res = inputsRef.current.map((input) => input.value).join('');\n onChange && onChange(res);\n };\n\n const handleOnChange = (e: React.ChangeEvent) => {\n const {\n target: { value, nextElementSibling }\n } = e;\n if (value.length > 1) {\n e.target.value = value.charAt(0);\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n if (value.match(inputProps.pattern)) {\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n e.target.value = '';\n }\n }\n sendResult();\n };\n\n const handleOnKeyDown = (e: React.KeyboardEvent) => {\n const { key } = e;\n const target = e.target as HTMLInputElement;\n if (key === 'Backspace') {\n if (target.value === '') {\n if (target.previousElementSibling !== null) {\n const t = target.previousElementSibling as HTMLInputElement;\n t.value = '';\n t.focus();\n e.preventDefault();\n }\n } else {\n target.value = '';\n }\n sendResult();\n }\n };\n\n const handleOnFocus = (e: React.FocusEvent) => {\n e.target.select();\n };\n\n const handleOnPaste = (e: React.ClipboardEvent) => {\n const pastedValue = e.clipboardData.getData('Text');\n\n let currentInput = 0;\n\n for (let i = 0; i < pastedValue.length; i++) {\n const pastedCharacter = pastedValue.charAt(i);\n const currentValue = inputsRef.current[currentInput].value;\n if (pastedCharacter.match(inputProps.pattern)) {\n if (!currentValue) {\n inputsRef.current[currentInput].value = pastedCharacter;\n if (inputsRef.current[currentInput].nextElementSibling !== null) {\n (inputsRef.current[currentInput]\n .nextElementSibling as HTMLInputElement).focus();\n currentInput++;\n }\n }\n }\n }\n sendResult();\n\n e.preventDefault();\n };\n\n const inputs = [];\n for (let i = 0; i < length; i++) {\n inputs.push(\n {\n inputsRef.current[i] = el;\n }}\n maxLength={1}\n className={inputClassName}\n autoComplete={i === 0 ? 'one-time-code' : 'off'}\n aria-label={\n ariaLabel\n ? `${ariaLabel}. Character ${i + 1}.`\n : `Character ${i + 1}.`\n }\n disabled={disabled}\n placeholder={placeholder}\n />\n );\n }\n\n return
{inputs}
;\n }\n);\n\nexport default AuthCode;\n"],"names":["allowedCharactersValues","propsMap","alpha","type","inputMode","pattern","alphanumeric","numeric","min","max","AuthCode","forwardRef","ref","allowedCharacters","ariaLabel","autoFocus","containerClassName","disabled","inputClassName","isPassword","length","placeholder","onChange","isNaN","Error","some","value","inputsRef","useRef","inputProps","useImperativeHandle","focus","current","clear","i","sendResult","useEffect","res","map","input","join","handleOnChange","e","target","nextElementSibling","charAt","match","handleOnKeyDown","key","previousElementSibling","t","preventDefault","handleOnFocus","select","handleOnPaste","pastedValue","clipboardData","getData","currentInput","pastedCharacter","currentValue","inputs","push","React","onKeyDown","onFocus","onPaste","el","maxLength","className","autoComplete"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef\n} from 'react';\n\nconst allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric'] as const;\n\nexport type AuthCodeProps = {\n allowedCharacters?: typeof allowedCharactersValues[number];\n ariaLabel?: string;\n autoFocus?: boolean;\n containerClassName?: string;\n disabled?: boolean;\n inputClassName?: string;\n isPassword?: boolean;\n length?: number;\n placeholder?: string;\n onChange: (res: string) => void;\n value?: string;\n};\n\ntype InputMode = 'text' | 'numeric';\n\ntype InputType = 'text' | 'tel' | 'password';\n\ntype InputProps = {\n type: InputType;\n inputMode: InputMode;\n pattern: string;\n min?: string;\n max?: string;\n};\n\nexport type AuthCodeRef = {\n focus: () => void;\n clear: () => void;\n};\n\nconst propsMap: { [key: string]: InputProps } = {\n alpha: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z]{1}'\n },\n\n alphanumeric: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z0-9]{1}'\n },\n\n numeric: {\n type: 'tel',\n inputMode: 'numeric',\n pattern: '[0-9]{1}',\n min: '0',\n max: '9'\n }\n};\n\nconst valueValidation = {\n alpha: (value: string) => /^[a-zA-Z]*$/.test(value),\n alphanumeric: (value: string) => /^[a-zA-Z0-9]*$/.test(value),\n numeric: (value: string) => /^[0-9]*$/.test(value)\n};\n\nconst AuthCode = forwardRef(\n (\n {\n allowedCharacters = 'alphanumeric',\n ariaLabel,\n autoFocus = true,\n containerClassName,\n disabled,\n inputClassName,\n isPassword = false,\n length = 6,\n placeholder,\n onChange,\n value\n },\n ref\n ) => {\n const values = value ? value.split('') : [];\n\n if (isNaN(length) || length < 1) {\n throw new Error('Length should be a number and greater than 0');\n }\n\n if (!allowedCharactersValues.some((value) => value === allowedCharacters)) {\n throw new Error(\n 'Invalid value for allowedCharacters. Use alpha, numeric, or alphanumeric'\n );\n }\n\n if (value && value.length > length) {\n throw new Error('Value length should not be greater than length');\n }\n\n if (value && !valueValidation[allowedCharacters](value)) {\n throw new Error(\n `Value should only contain ${allowedCharacters} characters`\n );\n }\n\n const inputsRef = useRef>([]);\n const inputProps = propsMap[allowedCharacters];\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n if (inputsRef.current) {\n inputsRef.current[0].focus();\n }\n },\n clear: () => {\n if (inputsRef.current) {\n for (let i = 0; i < inputsRef.current.length; i++) {\n inputsRef.current[i].value = '';\n }\n inputsRef.current[0].focus();\n }\n sendResult();\n }\n }));\n\n useEffect(() => {\n if (autoFocus) {\n inputsRef.current[0].focus();\n }\n }, []);\n\n const sendResult = () => {\n const res = inputsRef.current.map((input) => input.value).join('');\n onChange && onChange(res);\n };\n\n const handleOnChange = (e: React.ChangeEvent) => {\n const {\n target: { value, nextElementSibling }\n } = e;\n if (value.length > 1) {\n e.target.value = value.charAt(0);\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n if (value.match(inputProps.pattern)) {\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n e.target.value = '';\n }\n }\n sendResult();\n };\n\n const handleOnKeyDown = (e: React.KeyboardEvent) => {\n const { key } = e;\n const target = e.target as HTMLInputElement;\n if (key === 'Backspace') {\n if (target.value === '') {\n if (target.previousElementSibling !== null) {\n const t = target.previousElementSibling as HTMLInputElement;\n t.value = '';\n t.focus();\n e.preventDefault();\n }\n } else {\n target.value = '';\n }\n sendResult();\n }\n\n if (key === 'Tab' && target.value === '') {\n e.preventDefault();\n }\n };\n\n const handleOnFocus = (e: React.FocusEvent) => {\n e.target.select();\n };\n\n const handleOnPaste = (e: React.ClipboardEvent) => {\n const pastedValue = e.clipboardData.getData('Text');\n\n let currentInput = 0;\n\n for (let i = 0; i < pastedValue.length; i++) {\n const pastedCharacter = pastedValue.charAt(i);\n const currentValue = inputsRef.current[currentInput].value;\n if (pastedCharacter.match(inputProps.pattern)) {\n if (!currentValue) {\n inputsRef.current[currentInput].value = pastedCharacter;\n if (inputsRef.current[currentInput].nextElementSibling !== null) {\n (inputsRef.current[currentInput]\n .nextElementSibling as HTMLInputElement).focus();\n currentInput++;\n }\n }\n }\n }\n sendResult();\n\n e.preventDefault();\n };\n\n const inputs = [];\n for (let i = 0; i < length; i++) {\n inputs.push(\n {\n inputsRef.current[i] = el;\n }}\n maxLength={1}\n className={inputClassName}\n autoComplete={i === 0 ? 'one-time-code' : 'off'}\n aria-label={\n ariaLabel\n ? `${ariaLabel}. Character ${i + 1}.`\n : `Character ${i + 1}.`\n }\n disabled={disabled}\n placeholder={placeholder}\n defaultValue={values[i] || ''}\n />\n );\n }\n\n return
{inputs}
;\n }\n);\n\nexport default AuthCode;\n"],"names":["allowedCharactersValues","propsMap","alpha","type","inputMode","pattern","alphanumeric","numeric","min","max","valueValidation","value","test","AuthCode","forwardRef","ref","allowedCharacters","ariaLabel","autoFocus","containerClassName","disabled","inputClassName","isPassword","length","placeholder","onChange","values","split","isNaN","Error","some","inputsRef","useRef","inputProps","useImperativeHandle","focus","current","clear","i","sendResult","useEffect","res","map","input","join","handleOnChange","e","target","nextElementSibling","charAt","match","handleOnKeyDown","key","previousElementSibling","t","preventDefault","handleOnFocus","select","handleOnPaste","pastedValue","clipboardData","getData","currentInput","pastedCharacter","currentValue","inputs","push","React","onKeyDown","onFocus","onPaste","el","maxLength","className","autoComplete","defaultValue"],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.modern.js b/dist/index.modern.js index 34f10f7..38c01b3 100644 --- a/dist/index.modern.js +++ b/dist/index.modern.js @@ -1,7 +1,7 @@ import React, { forwardRef, useRef, useImperativeHandle, useEffect } from 'react'; -var allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric']; -var propsMap = { +const allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric']; +const propsMap = { alpha: { type: 'text', inputMode: 'text', @@ -20,71 +20,80 @@ var propsMap = { max: '9' } }; -var AuthCode = forwardRef(function (_ref, ref) { - var _ref$allowedCharacter = _ref.allowedCharacters, - allowedCharacters = _ref$allowedCharacter === void 0 ? 'alphanumeric' : _ref$allowedCharacter, - ariaLabel = _ref.ariaLabel, - _ref$autoFocus = _ref.autoFocus, - autoFocus = _ref$autoFocus === void 0 ? true : _ref$autoFocus, - containerClassName = _ref.containerClassName, - disabled = _ref.disabled, - inputClassName = _ref.inputClassName, - _ref$isPassword = _ref.isPassword, - isPassword = _ref$isPassword === void 0 ? false : _ref$isPassword, - _ref$length = _ref.length, - length = _ref$length === void 0 ? 6 : _ref$length, - placeholder = _ref.placeholder, - onChange = _ref.onChange; - - if (isNaN(length) || length < 1) { +const valueValidation = { + alpha: value => /^[a-zA-Z]*$/.test(value), + alphanumeric: value => /^[a-zA-Z0-9]*$/.test(value), + numeric: value => /^[0-9]*$/.test(value) +}; +const AuthCode = forwardRef(({ + allowedCharacters: _allowedCharacters = 'alphanumeric', + ariaLabel, + autoFocus: _autoFocus = true, + containerClassName, + disabled, + inputClassName, + isPassword: _isPassword = false, + length: _length = 6, + placeholder, + onChange, + value +}, ref) => { + const values = value ? value.split('') : []; + + if (isNaN(_length) || _length < 1) { throw new Error('Length should be a number and greater than 0'); } - if (!allowedCharactersValues.some(function (value) { - return value === allowedCharacters; - })) { + if (!allowedCharactersValues.some(value => value === _allowedCharacters)) { throw new Error('Invalid value for allowedCharacters. Use alpha, numeric, or alphanumeric'); } - var inputsRef = useRef([]); - var inputProps = propsMap[allowedCharacters]; - useImperativeHandle(ref, function () { - return { - focus: function focus() { - if (inputsRef.current) { - inputsRef.current[0].focus(); - } - }, - clear: function clear() { - if (inputsRef.current) { - for (var i = 0; i < inputsRef.current.length; i++) { - inputsRef.current[i].value = ''; - } + if (value && value.length > _length) { + throw new Error('Value length should not be greater than length'); + } + + if (value && !valueValidation[_allowedCharacters](value)) { + throw new Error(`Value should only contain ${_allowedCharacters} characters`); + } - inputsRef.current[0].focus(); + const inputsRef = useRef([]); + const inputProps = propsMap[_allowedCharacters]; + useImperativeHandle(ref, () => ({ + focus: () => { + if (inputsRef.current) { + inputsRef.current[0].focus(); + } + }, + clear: () => { + if (inputsRef.current) { + for (let i = 0; i < inputsRef.current.length; i++) { + inputsRef.current[i].value = ''; } - sendResult(); + inputsRef.current[0].focus(); } - }; - }); - useEffect(function () { - if (autoFocus) { + + sendResult(); + } + })); + useEffect(() => { + if (_autoFocus) { inputsRef.current[0].focus(); } }, []); - var sendResult = function sendResult() { - var res = inputsRef.current.map(function (input) { - return input.value; - }).join(''); + const sendResult = () => { + const res = inputsRef.current.map(input => input.value).join(''); onChange && onChange(res); }; - var handleOnChange = function handleOnChange(e) { - var _e$target = e.target, - value = _e$target.value, - nextElementSibling = _e$target.nextElementSibling; + const handleOnChange = e => { + const { + target: { + value, + nextElementSibling + } + } = e; if (value.length > 1) { e.target.value = value.charAt(0); @@ -105,14 +114,16 @@ var AuthCode = forwardRef(function (_ref, ref) { sendResult(); }; - var handleOnKeyDown = function handleOnKeyDown(e) { - var key = e.key; - var target = e.target; + const handleOnKeyDown = e => { + const { + key + } = e; + const target = e.target; if (key === 'Backspace') { if (target.value === '') { if (target.previousElementSibling !== null) { - var t = target.previousElementSibling; + const t = target.previousElementSibling; t.value = ''; t.focus(); e.preventDefault(); @@ -123,19 +134,23 @@ var AuthCode = forwardRef(function (_ref, ref) { sendResult(); } + + if (key === 'Tab' && target.value === '') { + e.preventDefault(); + } }; - var handleOnFocus = function handleOnFocus(e) { + const handleOnFocus = e => { e.target.select(); }; - var handleOnPaste = function handleOnPaste(e) { - var pastedValue = e.clipboardData.getData('Text'); - var currentInput = 0; + const handleOnPaste = e => { + const pastedValue = e.clipboardData.getData('Text'); + let currentInput = 0; - for (var i = 0; i < pastedValue.length; i++) { - var pastedCharacter = pastedValue.charAt(i); - var currentValue = inputsRef.current[currentInput].value; + for (let i = 0; i < pastedValue.length; i++) { + const pastedCharacter = pastedValue.charAt(i); + const currentValue = inputsRef.current[currentInput].value; if (pastedCharacter.match(inputProps.pattern)) { if (!currentValue) { @@ -153,9 +168,9 @@ var AuthCode = forwardRef(function (_ref, ref) { e.preventDefault(); }; - var inputs = []; + const inputs = []; - var _loop = function _loop(i) { + for (let i = 0; i < _length; i++) { inputs.push(React.createElement("input", Object.assign({ key: i, onChange: handleOnChange, @@ -163,21 +178,18 @@ var AuthCode = forwardRef(function (_ref, ref) { onFocus: handleOnFocus, onPaste: handleOnPaste }, inputProps, { - type: isPassword ? 'password' : inputProps.type, - ref: function ref(el) { + type: _isPassword ? 'password' : inputProps.type, + ref: el => { inputsRef.current[i] = el; }, maxLength: 1, className: inputClassName, autoComplete: i === 0 ? 'one-time-code' : 'off', - "aria-label": ariaLabel ? ariaLabel + ". Character " + (i + 1) + "." : "Character " + (i + 1) + ".", + "aria-label": ariaLabel ? `${ariaLabel}. Character ${i + 1}.` : `Character ${i + 1}.`, disabled: disabled, - placeholder: placeholder + placeholder: placeholder, + defaultValue: values[i] || '' }))); - }; - - for (var i = 0; i < length; i++) { - _loop(i); } return React.createElement("div", { diff --git a/dist/index.modern.js.map b/dist/index.modern.js.map index 9e457ca..be3e5b2 100644 --- a/dist/index.modern.js.map +++ b/dist/index.modern.js.map @@ -1 +1 @@ -{"version":3,"file":"index.modern.js","sources":["../src/index.tsx"],"sourcesContent":["import React, {\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef\n} from 'react';\n\nconst allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric'] as const;\n\nexport type AuthCodeProps = {\n allowedCharacters?: typeof allowedCharactersValues[number];\n ariaLabel?: string;\n autoFocus?: boolean;\n containerClassName?: string;\n disabled?: boolean;\n inputClassName?: string;\n isPassword?: boolean;\n length?: number;\n placeholder?: string;\n onChange: (res: string) => void;\n};\n\ntype InputMode = 'text' | 'numeric';\n\ntype InputType = 'text' | 'tel' | 'password';\n\ntype InputProps = {\n type: InputType;\n inputMode: InputMode;\n pattern: string;\n min?: string;\n max?: string;\n};\n\nexport type AuthCodeRef = {\n focus: () => void;\n clear: () => void;\n};\n\nconst propsMap: { [key: string]: InputProps } = {\n alpha: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z]{1}'\n },\n\n alphanumeric: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z0-9]{1}'\n },\n\n numeric: {\n type: 'tel',\n inputMode: 'numeric',\n pattern: '[0-9]{1}',\n min: '0',\n max: '9'\n }\n};\n\nconst AuthCode = forwardRef(\n (\n {\n allowedCharacters = 'alphanumeric',\n ariaLabel,\n autoFocus = true,\n containerClassName,\n disabled,\n inputClassName,\n isPassword = false,\n length = 6,\n placeholder,\n onChange\n },\n ref\n ) => {\n if (isNaN(length) || length < 1) {\n throw new Error('Length should be a number and greater than 0');\n }\n\n if (!allowedCharactersValues.some((value) => value === allowedCharacters)) {\n throw new Error(\n 'Invalid value for allowedCharacters. Use alpha, numeric, or alphanumeric'\n );\n }\n\n const inputsRef = useRef>([]);\n const inputProps = propsMap[allowedCharacters];\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n if (inputsRef.current) {\n inputsRef.current[0].focus();\n }\n },\n clear: () => {\n if (inputsRef.current) {\n for (let i = 0; i < inputsRef.current.length; i++) {\n inputsRef.current[i].value = '';\n }\n inputsRef.current[0].focus();\n }\n sendResult();\n }\n }));\n\n useEffect(() => {\n if (autoFocus) {\n inputsRef.current[0].focus();\n }\n }, []);\n\n const sendResult = () => {\n const res = inputsRef.current.map((input) => input.value).join('');\n onChange && onChange(res);\n };\n\n const handleOnChange = (e: React.ChangeEvent) => {\n const {\n target: { value, nextElementSibling }\n } = e;\n if (value.length > 1) {\n e.target.value = value.charAt(0);\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n if (value.match(inputProps.pattern)) {\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n e.target.value = '';\n }\n }\n sendResult();\n };\n\n const handleOnKeyDown = (e: React.KeyboardEvent) => {\n const { key } = e;\n const target = e.target as HTMLInputElement;\n if (key === 'Backspace') {\n if (target.value === '') {\n if (target.previousElementSibling !== null) {\n const t = target.previousElementSibling as HTMLInputElement;\n t.value = '';\n t.focus();\n e.preventDefault();\n }\n } else {\n target.value = '';\n }\n sendResult();\n }\n };\n\n const handleOnFocus = (e: React.FocusEvent) => {\n e.target.select();\n };\n\n const handleOnPaste = (e: React.ClipboardEvent) => {\n const pastedValue = e.clipboardData.getData('Text');\n\n let currentInput = 0;\n\n for (let i = 0; i < pastedValue.length; i++) {\n const pastedCharacter = pastedValue.charAt(i);\n const currentValue = inputsRef.current[currentInput].value;\n if (pastedCharacter.match(inputProps.pattern)) {\n if (!currentValue) {\n inputsRef.current[currentInput].value = pastedCharacter;\n if (inputsRef.current[currentInput].nextElementSibling !== null) {\n (inputsRef.current[currentInput]\n .nextElementSibling as HTMLInputElement).focus();\n currentInput++;\n }\n }\n }\n }\n sendResult();\n\n e.preventDefault();\n };\n\n const inputs = [];\n for (let i = 0; i < length; i++) {\n inputs.push(\n {\n inputsRef.current[i] = el;\n }}\n maxLength={1}\n className={inputClassName}\n autoComplete={i === 0 ? 'one-time-code' : 'off'}\n aria-label={\n ariaLabel\n ? `${ariaLabel}. Character ${i + 1}.`\n : `Character ${i + 1}.`\n }\n disabled={disabled}\n placeholder={placeholder}\n />\n );\n }\n\n return
{inputs}
;\n }\n);\n\nexport default AuthCode;\n"],"names":["allowedCharactersValues","propsMap","alpha","type","inputMode","pattern","alphanumeric","numeric","min","max","AuthCode","forwardRef","ref","allowedCharacters","ariaLabel","autoFocus","containerClassName","disabled","inputClassName","isPassword","length","placeholder","onChange","isNaN","Error","some","value","inputsRef","useRef","inputProps","useImperativeHandle","focus","current","clear","i","sendResult","useEffect","res","map","input","join","handleOnChange","e","target","nextElementSibling","charAt","match","handleOnKeyDown","key","previousElementSibling","t","preventDefault","handleOnFocus","select","handleOnPaste","pastedValue","clipboardData","getData","currentInput","pastedCharacter","currentValue","inputs","push","React","onKeyDown","onFocus","onPaste","el","maxLength","className","autoComplete"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.modern.js","sources":["../src/index.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef\n} from 'react';\n\nconst allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric'] as const;\n\nexport type AuthCodeProps = {\n allowedCharacters?: typeof allowedCharactersValues[number];\n ariaLabel?: string;\n autoFocus?: boolean;\n containerClassName?: string;\n disabled?: boolean;\n inputClassName?: string;\n isPassword?: boolean;\n length?: number;\n placeholder?: string;\n onChange: (res: string) => void;\n value?: string;\n};\n\ntype InputMode = 'text' | 'numeric';\n\ntype InputType = 'text' | 'tel' | 'password';\n\ntype InputProps = {\n type: InputType;\n inputMode: InputMode;\n pattern: string;\n min?: string;\n max?: string;\n};\n\nexport type AuthCodeRef = {\n focus: () => void;\n clear: () => void;\n};\n\nconst propsMap: { [key: string]: InputProps } = {\n alpha: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z]{1}'\n },\n\n alphanumeric: {\n type: 'text',\n inputMode: 'text',\n pattern: '[a-zA-Z0-9]{1}'\n },\n\n numeric: {\n type: 'tel',\n inputMode: 'numeric',\n pattern: '[0-9]{1}',\n min: '0',\n max: '9'\n }\n};\n\nconst valueValidation = {\n alpha: (value: string) => /^[a-zA-Z]*$/.test(value),\n alphanumeric: (value: string) => /^[a-zA-Z0-9]*$/.test(value),\n numeric: (value: string) => /^[0-9]*$/.test(value)\n};\n\nconst AuthCode = forwardRef(\n (\n {\n allowedCharacters = 'alphanumeric',\n ariaLabel,\n autoFocus = true,\n containerClassName,\n disabled,\n inputClassName,\n isPassword = false,\n length = 6,\n placeholder,\n onChange,\n value\n },\n ref\n ) => {\n const values = value ? value.split('') : [];\n\n if (isNaN(length) || length < 1) {\n throw new Error('Length should be a number and greater than 0');\n }\n\n if (!allowedCharactersValues.some((value) => value === allowedCharacters)) {\n throw new Error(\n 'Invalid value for allowedCharacters. Use alpha, numeric, or alphanumeric'\n );\n }\n\n if (value && value.length > length) {\n throw new Error('Value length should not be greater than length');\n }\n\n if (value && !valueValidation[allowedCharacters](value)) {\n throw new Error(\n `Value should only contain ${allowedCharacters} characters`\n );\n }\n\n const inputsRef = useRef>([]);\n const inputProps = propsMap[allowedCharacters];\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n if (inputsRef.current) {\n inputsRef.current[0].focus();\n }\n },\n clear: () => {\n if (inputsRef.current) {\n for (let i = 0; i < inputsRef.current.length; i++) {\n inputsRef.current[i].value = '';\n }\n inputsRef.current[0].focus();\n }\n sendResult();\n }\n }));\n\n useEffect(() => {\n if (autoFocus) {\n inputsRef.current[0].focus();\n }\n }, []);\n\n const sendResult = () => {\n const res = inputsRef.current.map((input) => input.value).join('');\n onChange && onChange(res);\n };\n\n const handleOnChange = (e: React.ChangeEvent) => {\n const {\n target: { value, nextElementSibling }\n } = e;\n if (value.length > 1) {\n e.target.value = value.charAt(0);\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n if (value.match(inputProps.pattern)) {\n if (nextElementSibling !== null) {\n (nextElementSibling as HTMLInputElement).focus();\n }\n } else {\n e.target.value = '';\n }\n }\n sendResult();\n };\n\n const handleOnKeyDown = (e: React.KeyboardEvent) => {\n const { key } = e;\n const target = e.target as HTMLInputElement;\n if (key === 'Backspace') {\n if (target.value === '') {\n if (target.previousElementSibling !== null) {\n const t = target.previousElementSibling as HTMLInputElement;\n t.value = '';\n t.focus();\n e.preventDefault();\n }\n } else {\n target.value = '';\n }\n sendResult();\n }\n\n if (key === 'Tab' && target.value === '') {\n e.preventDefault();\n }\n };\n\n const handleOnFocus = (e: React.FocusEvent) => {\n e.target.select();\n };\n\n const handleOnPaste = (e: React.ClipboardEvent) => {\n const pastedValue = e.clipboardData.getData('Text');\n\n let currentInput = 0;\n\n for (let i = 0; i < pastedValue.length; i++) {\n const pastedCharacter = pastedValue.charAt(i);\n const currentValue = inputsRef.current[currentInput].value;\n if (pastedCharacter.match(inputProps.pattern)) {\n if (!currentValue) {\n inputsRef.current[currentInput].value = pastedCharacter;\n if (inputsRef.current[currentInput].nextElementSibling !== null) {\n (inputsRef.current[currentInput]\n .nextElementSibling as HTMLInputElement).focus();\n currentInput++;\n }\n }\n }\n }\n sendResult();\n\n e.preventDefault();\n };\n\n const inputs = [];\n for (let i = 0; i < length; i++) {\n inputs.push(\n {\n inputsRef.current[i] = el;\n }}\n maxLength={1}\n className={inputClassName}\n autoComplete={i === 0 ? 'one-time-code' : 'off'}\n aria-label={\n ariaLabel\n ? `${ariaLabel}. Character ${i + 1}.`\n : `Character ${i + 1}.`\n }\n disabled={disabled}\n placeholder={placeholder}\n defaultValue={values[i] || ''}\n />\n );\n }\n\n return
{inputs}
;\n }\n);\n\nexport default AuthCode;\n"],"names":["allowedCharactersValues","propsMap","alpha","type","inputMode","pattern","alphanumeric","numeric","min","max","valueValidation","value","test","AuthCode","forwardRef","allowedCharacters","ariaLabel","autoFocus","containerClassName","disabled","inputClassName","isPassword","length","placeholder","onChange","ref","values","split","isNaN","Error","some","inputsRef","useRef","inputProps","useImperativeHandle","focus","current","clear","i","sendResult","useEffect","res","map","input","join","handleOnChange","e","target","nextElementSibling","charAt","match","handleOnKeyDown","key","previousElementSibling","t","preventDefault","handleOnFocus","select","handleOnPaste","pastedValue","clipboardData","getData","currentInput","pastedCharacter","currentValue","inputs","push","React","onKeyDown","onFocus","onPaste","el","maxLength","className","autoComplete","defaultValue"],"mappings":"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"} \ No newline at end of file diff --git a/example/src/App.tsx b/example/src/App.tsx index 6a8b712..cc35fd1 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,6 +1,6 @@ import React, { useRef, useState } from 'react'; -import AuthCode, { AuthCodeRef, AuthCodeProps } from 'react-auth-code-input'; +import AuthCode, { AuthCodeProps, AuthCodeRef } from 'react-auth-code-input'; import './index.css'; const allowedCharactersMap = [ @@ -63,10 +63,10 @@ const App = () => {

-

+

Two-Factor
Authentication -

+ {

Code: {result}

-
+
{ />
-
+ +
{ />
+ +
+
{allowedCharactersMap.map((aC) => ( -
+
* { margin-right: 8px; } + +a { + color: #0071e3; + text-decoration: none; + padding: 0.5rem; +} + +a:hover { + text-decoration: underline; +} + +a:focus { + box-shadow: 0 0 0 3px rgb(131 192 253 / 50%); +} + .container { padding: 16px; } @@ -31,15 +54,21 @@ body { text-align: center; margin-right: 12px; text-transform: uppercase; - color: #494949; + color: #e1e1e6; font-family: SF Pro Text, SF Pro Icons, Helvetica Neue, Helvetica, Arial, sans-serif; - border: 1px solid #d6d6d6; + border: 1px solid #202024; border-radius: 4px; - background: #fff; + background: #202024; background-clip: padding-box; } +.input:disabled { + background: #29292e; + color: #e1e1e6; + cursor: not-allowed; +} + .input:focus { appearance: none; outline: 0; @@ -47,6 +76,7 @@ body { } button { + cursor: pointer; appearance: none; background: #0071e3; border-radius: 980px; @@ -60,6 +90,7 @@ button { p { font-size: 17px; line-height: 1.47059; + margin: 0.5rem; } .props { @@ -76,3 +107,15 @@ p { .allowed-characters { text-align: left; } + +.props-input-container { + display: flex; + align-items: center; + gap: 0.25rem; +} + +.allowed-characters { + display: flex; + flex-direction: column; + gap: 0.25rem; +} diff --git a/package.json b/package.json index 02cdea8..e60e2b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-auth-code-input", - "version": "3.2.1", + "version": "3.2.2", "description": "One-time password (OTP) React input component, uncontrolled, zero dependencies, fully tested.", "author": "drac94", "license": "MIT", diff --git a/src/index.tsx b/src/index.tsx index 8b92566..53615ef 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,8 +1,8 @@ import React, { - useRef, + forwardRef, useEffect, useImperativeHandle, - forwardRef + useRef } from 'react'; const allowedCharactersValues = ['alpha', 'numeric', 'alphanumeric'] as const; @@ -18,6 +18,7 @@ export type AuthCodeProps = { length?: number; placeholder?: string; onChange: (res: string) => void; + value?: string; }; type InputMode = 'text' | 'numeric'; @@ -59,6 +60,12 @@ const propsMap: { [key: string]: InputProps } = { } }; +const valueValidation = { + alpha: (value: string) => /^[a-zA-Z]*$/.test(value), + alphanumeric: (value: string) => /^[a-zA-Z0-9]*$/.test(value), + numeric: (value: string) => /^[0-9]*$/.test(value) +}; + const AuthCode = forwardRef( ( { @@ -71,10 +78,13 @@ const AuthCode = forwardRef( isPassword = false, length = 6, placeholder, - onChange + onChange, + value }, ref ) => { + const values = value ? value.split('') : []; + if (isNaN(length) || length < 1) { throw new Error('Length should be a number and greater than 0'); } @@ -85,6 +95,16 @@ const AuthCode = forwardRef( ); } + if (value && value.length > length) { + throw new Error('Value length should not be greater than length'); + } + + if (value && !valueValidation[allowedCharacters](value)) { + throw new Error( + `Value should only contain ${allowedCharacters} characters` + ); + } + const inputsRef = useRef>([]); const inputProps = propsMap[allowedCharacters]; @@ -153,6 +173,10 @@ const AuthCode = forwardRef( } sendResult(); } + + if (key === 'Tab' && target.value === '') { + e.preventDefault(); + } }; const handleOnFocus = (e: React.FocusEvent) => { @@ -207,6 +231,7 @@ const AuthCode = forwardRef( } disabled={disabled} placeholder={placeholder} + defaultValue={values[i] || ''} /> ); }