fictoan-react 0.41.1 → 0.41.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/dist/cjs/components/PinInputField/PinInputField.d.ts +3 -3
- package/dist/cjs/components/PinInputField/PinInputField.js +1 -1
- package/dist/cjs/components/PinInputField/PinInputField.js.map +1 -1
- package/dist/es/components/PinInputField/PinInputField.d.ts +3 -3
- package/dist/es/components/PinInputField/PinInputField.js +2 -2
- package/dist/es/components/PinInputField/PinInputField.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,12 +2,12 @@ import React from "react";
|
|
|
2
2
|
import { CommonAndHTMLProps } from "../Element/constants";
|
|
3
3
|
declare type PinInputFieldCustomProps = {
|
|
4
4
|
numberOfFields: number;
|
|
5
|
-
|
|
5
|
+
onChange?: (value: string) => void;
|
|
6
6
|
type?: "alphanumeric" | "number";
|
|
7
7
|
mask?: boolean;
|
|
8
8
|
otp?: boolean;
|
|
9
9
|
};
|
|
10
10
|
export declare type PinInputFieldElementType = HTMLDivElement;
|
|
11
|
-
export declare type
|
|
12
|
-
export declare const PinInputField: React.ForwardRefExoticComponent<PinInputFieldCustomProps & React.RefAttributes<HTMLDivElement>>;
|
|
11
|
+
export declare type PinInputFieldProps = Omit<CommonAndHTMLProps<PinInputFieldElementType>, keyof PinInputFieldCustomProps> & PinInputFieldCustomProps;
|
|
12
|
+
export declare const PinInputField: React.ForwardRefExoticComponent<Omit<CommonAndHTMLProps<HTMLDivElement>, keyof PinInputFieldCustomProps> & PinInputFieldCustomProps & React.RefAttributes<HTMLDivElement>>;
|
|
13
13
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../../external/Element.js"),r=require("../Form/InputField/InputField.js"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../../external/Element.js"),r=require("../Form/InputField/InputField.js"),n=require("./PinInputField.styled.js");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}require("../Form/BaseInputComponent/BaseInputComponent.js"),require("../Form/InputLabel/InputLabel.js"),require("../Form/FormItem/FormItem.js"),require("../Form/FormItem/FormItem.styled.js"),require("styled-components"),require("../Form/InputField/InputField.styled.js"),require("../Form/Select/Select.styled.js"),require("../Form/TextArea/TextArea.styled.js");var u=/*#__PURE__*/l(e);function a(e,t){return("alphanumeric"===t?/^[a-zA-Z0-9]+$/i:/^[0-9]+$/).test(e)}const o=u.default.forwardRef((({numberOfFields:l,onChange:o,type:s="number",mask:i=!1,otp:c=!1},m)=>{const[d,p]=e.useState([]),[f,F]=e.useState([]),[y,v]=e.useState(!0),[g,h]=e.useState(0),I=e.useCallback((e=>{var t;const r=d[e];null===(t=null==r?void 0:r.current)||void 0===t||t.focus()}),[d]);e.useEffect((()=>{p((t=>Array(l).fill(0).map(((r,n)=>{var l;const u=t[n]||e.createRef();return 0===n&&(null===(l=u.current)||void 0===l||l.focus()),u}))))}),[l]);const j=e.useCallback((e=>{if(!y)return;const t=e+1<l?e+1:null;t&&I(t)}),[I,l,y]),b=e.useCallback(((e,t)=>{const r=[...f];r[t]=e,F(r),o(r.join(""));""!==e&&r.length===l&&r.every((e=>null!=e&&""!==e))||j(t)}),[j,l,o,f]),q=e.useCallback(((e,t)=>{let r=t;return(null==e?void 0:e.length)>0&&(e[0]===t.charAt(0)?r=t.charAt(1):e[0]===t.charAt(1)&&(r=t.charAt(0))),r}),[]),k=()=>{h(-1)};return u.default.createElement(t.Element,{as:n.PinInputStyled,ref:m},[...Array(l)].map(((e,t)=>u.default.createElement(r.InputField,{key:t,className:"pin-input-field",ref:d[t],type:i?"password":"number"===s?"tel":"text",inputMode:"number"===s?"numeric":"text",onChange:e=>((e,t)=>{const r=e.currentTarget.value,n=f[t],u=q(n,r);if(""!==u)if(r.length>1&&t<l-1){if(a(r,s)){const e=r.split("").filter(((e,t)=>t<l));F(e),I(t+e.length<l?t+e.length:l-1),null==o||o(e.join(""))}}else a(u,s)&&b(u,t),v(!0);else b("",t)})(e,t),onKeyDown:e=>((e,t)=>{var r;if("Backspace"===e.key)if(""===e.target.value){if(t>0){const e=t-1;b("",e),I(e),v(!0)}}else v(!1);else"Escape"===e.key?(null===(r=d[t].current)||void 0===r||r.blur(),k()):"ArrowRight"===e.key?t<l-1&&I(t+1):"ArrowLeft"===e.key&&t>0&&I(t-1)})(e,t),onFocus:e=>((e,t)=>{h(t),setTimeout((()=>{e.target.setSelectionRange(e.target.value.length,e.target.value.length)}),0)})(e,t),onBlur:k,placeholder:g!==t?"⦁":void 0,autoComplete:c?"one-time-code":"off",value:f[t]||"",autoFocus:0===t}))))}));exports.PinInputField=o;
|
|
2
2
|
//# sourceMappingURL=PinInputField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinInputField.js","sources":["../../../../src/components/PinInputField/PinInputField.tsx"],"sourcesContent":["import React, { createRef, useCallback, useEffect, useState } from \"react\";\n\nimport { Element } from \"../Element/Element\";\nimport { CommonAndHTMLProps } from \"../Element/constants\";\nimport { InputField } from \"../Form/InputField/InputField\";\n\nimport { PinInputStyled } from \"./PinInputField.styled\";\n\n// prettier-ignore\ntype PinInputFieldCustomProps = {\n numberOfFields : number;\n onComplete ? : (value: string) => void;\n type ? : \"alphanumeric\" | \"number\";\n mask ? : boolean;\n otp ? : boolean;\n};\n\nexport type PinInputFieldElementType = HTMLDivElement;\nexport type RowProps = Omit<CommonAndHTMLProps<PinInputFieldElementType>, keyof PinInputFieldCustomProps> &\n PinInputFieldCustomProps;\n\nfunction validate(value: string, type: \"alphanumeric\" | \"number\") {\n const NUMERIC_REGEX = /^[0-9]+$/;\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i;\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX;\n return regex.test(value);\n}\n\nexport const PinInputField = React.forwardRef(\n (\n { numberOfFields: length, onComplete, type = \"number\", mask = false, otp = false }: PinInputFieldCustomProps,\n ref: React.Ref<PinInputFieldElementType>\n ) => {\n const [inputRefs, setInputRefs] = useState<React.RefObject<HTMLInputElement>[]>([]);\n const [values, setValues] = useState<string[]>([]);\n const [moveFocus, setMoveFocus] = useState<boolean>(true);\n const [focusedIndex, setFocusedIndex] = useState<number>(0);\n\n const focus = useCallback(\n (index: number) => {\n const ref = inputRefs[index];\n ref?.current?.focus();\n },\n [inputRefs]\n );\n\n useEffect(() => {\n setInputRefs((inputRefs) => {\n const refs = Array(length)\n .fill(0)\n .map((_, i) => {\n const ref = inputRefs[i] || createRef();\n if (i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length]);\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus) return;\n const next = index + 1 < length ? index + 1 : null;\n if (next) {\n focus(next);\n }\n },\n [focus, length, moveFocus]\n );\n\n const setValue = useCallback(\n (value: string, index: number) => {\n const nextValues = [...values];\n nextValues[index] = value;\n setValues(nextValues);\n\n const isComplete =\n value !== \"\" &&\n nextValues.length === length &&\n nextValues.every((inputValue) => inputValue != null && inputValue !== \"\");\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"));\n } else {\n focusNext(index);\n }\n },\n [focusNext, length, onComplete, values]\n );\n\n const getNextValue = useCallback((value: string, eventValue: string) => {\n let nextValue = eventValue;\n if (value?.length > 0) {\n if (value[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1);\n } else if (value[0] === eventValue.charAt(1)) {\n nextValue = eventValue.charAt(0);\n }\n }\n return nextValue;\n }, []);\n\n const handleInputChange = (event: React.FormEvent<HTMLInputElement>, i: number) => {\n const eventValue = event.currentTarget.value;\n const currentValue = values[i];\n const nextValue = getNextValue(currentValue, eventValue);\n\n if (nextValue === \"\") {\n setValue(\"\", i);\n return;\n }\n\n if (eventValue.length > 1 && i < length - 1) {\n if (validate(eventValue, type)) {\n const nextValue = eventValue.split(\"\").filter((_, index) => index < length);\n setValues(nextValue);\n focus(i + nextValue.length < length ? i + nextValue.length : length - 1);\n if (nextValue.length === length) {\n onComplete?.(nextValue.join(\"\"));\n }\n }\n } else {\n if (validate(nextValue, type)) {\n setValue(nextValue, i);\n }\n setMoveFocus(true);\n }\n };\n\n const onKeyDown = (event: React.KeyboardEvent, i: number) => {\n if (event.key === \"Backspace\") {\n if ((event.target as HTMLInputElement).value === \"\") {\n if (i > 0) {\n const newIndex = i - 1;\n setValue(\"\", newIndex);\n focus(newIndex);\n setMoveFocus(true);\n }\n } else {\n setMoveFocus(false);\n }\n } else if (event.key === \"Escape\") {\n inputRefs[i].current?.blur();\n onBlur();\n } else if (event.key === \"ArrowRight\") {\n if (i < length - 1) {\n focus(i + 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n if (i > 0) {\n focus(i - 1);\n }\n }\n };\n\n const onFocus = (e: React.FocusEvent<HTMLInputElement>, i: number) => {\n setFocusedIndex(i);\n setTimeout(() => {\n // https://github.com/facebook/react/issues/6483\n e.target.setSelectionRange(e.target.value.length, e.target.value.length);\n }, 0);\n };\n\n const onBlur = () => {\n setFocusedIndex(-1);\n };\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} ref={ref}>\n {[...Array(length)].map((_, i) => (\n <InputField\n key={i}\n className=\"pin-input-field\"\n ref={inputRefs[i]}\n type={mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\"}\n inputMode={type === \"number\" ? \"numeric\" : \"text\"}\n onChange={(e) => handleInputChange(e, i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n onFocus={(e) => onFocus(e, i)}\n onBlur={onBlur}\n placeholder={focusedIndex !== i ? `\\u2981` : undefined}\n autoComplete={otp ? \"one-time-code\" : \"off\"}\n value={values[i] || \"\"}\n autoFocus={i === 0}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onComplete","mask","otp","ref","inputRefs","setInputRefs","useState","values","setValues","moveFocus","setMoveFocus","focusedIndex","setFocusedIndex","focus","useCallback","index","current","useEffect","Array","fill","map","_","i","createRef","focusNext","next","setValue","nextValues","every","inputValue","join","getNextValue","eventValue","nextValue","charAt","onBlur","Element","as","PinInputStyled","InputField","key","className","inputMode","onChange","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","autoFocus"],"mappings":"gqBAqBA,SAASA,EAASC,EAAeC,UAGN,iBAATA,EADc,kBADN,YAGTC,KAAKF,SAGTG,EAAgBC,UAAMC,YAC/B,EACMC,eAAgBC,EAAQC,WAAAA,EAAYP,KAAAA,EAAO,SAAUQ,KAAAA,GAAO,EAAOC,IAAAA,GAAM,GAC3EC,WAEOC,EAAWC,GAAgBC,WAA8C,KACzEC,EAAQC,GAAaF,WAAmB,KACxCG,EAAWC,GAAgBJ,YAAkB,IAC7CK,EAAcC,GAAmBN,WAAiB,GAEnDO,EAAQC,eACTC,gBACSZ,EAAMC,EAAUW,aACtBZ,MAAAA,SAAAA,EAAKa,wBAASH,UAElB,CAACT,IAGLa,aAAU,KACNZ,GAAcD,GACGc,MAAMnB,GACdoB,KAAK,GACLC,KAAI,CAACC,EAAGC,iBACCnB,EAAMC,EAAUkB,IAAMC,qBAClB,IAAND,cACAnB,EAAIa,wBAASH,SAEVV,SAIpB,CAACJ,UAEEyB,EAAYV,eACbC,QACQN,EAAW,aACVgB,EAAOV,EAAQ,EAAIhB,EAASgB,EAAQ,EAAI,KAC1CU,GACAZ,EAAMY,KAGd,CAACZ,EAAOd,EAAQU,IAGdiB,EAAWZ,eACb,CAACtB,EAAeuB,WACNY,EAAa,IAAIpB,GACvBoB,EAAWZ,GAASvB,EACpBgB,EAAUmB,GAGI,KAAVnC,GACAmC,EAAW5B,SAAWA,GACtB4B,EAAWC,OAAOC,GAA6B,MAAdA,GAAqC,KAAfA,IAGvD7B,MAAAA,GAAAA,EAAa2B,EAAWG,KAAK,KAE7BN,EAAUT,KAGlB,CAACS,EAAWzB,EAAQC,EAAYO,IAG9BwB,EAAejB,eAAY,CAACtB,EAAewC,SACzCC,EAAYD,SACZxC,MAAAA,SAAAA,EAAOO,QAAS,IACZP,EAAM,KAAOwC,EAAWE,OAAO,GAC/BD,EAAYD,EAAWE,OAAO,GACvB1C,EAAM,KAAOwC,EAAWE,OAAO,KACtCD,EAAYD,EAAWE,OAAO,KAG/BD,IACR,IA+DGE,EAAS,KACXvB,GAAiB,WAIjBhB,wBAACwC,WAAkCC,GAAIC,iBAAgBnC,IAAKA,GACvD,IAAIe,MAAMnB,IAASqB,KAAI,CAACC,EAAGC,IACxB1B,wBAAC2C,cACGC,IAAKlB,EACLmB,UAAU,kBACVtC,IAAKC,EAAUkB,GACf7B,KAAMQ,EAAO,WAAsB,WAATR,EAAoB,MAAQ,OACtDiD,UAAoB,WAATjD,EAAoB,UAAY,OAC3CkD,SAAWC,GA1ED,EAACC,EAA0CvB,WAC3DU,EAAaa,EAAMC,cAActD,MACjCuD,EAAexC,EAAOe,GACtBW,EAAYF,EAAagB,EAAcf,MAE3B,KAAdC,KAKAD,EAAWjC,OAAS,GAAKuB,EAAIvB,EAAS,MAClCR,EAASyC,EAAYvC,GAAO,OACtBwC,EAAYD,EAAWgB,MAAM,IAAIC,QAAO,CAAC5B,EAAGN,IAAUA,EAAQhB,IACpES,EAAUyB,GACVpB,EAAMS,EAAIW,EAAUlC,OAASA,EAASuB,EAAIW,EAAUlC,OAASA,EAAS,GAClEkC,EAAUlC,SAAWA,IACrBC,MAAAA,GAAAA,EAAaiC,EAAUH,KAAK,YAIhCvC,EAAS0C,EAAWxC,IACpBiC,EAASO,EAAWX,GAExBZ,GAAa,QAjBbgB,EAAS,GAAIJ,IAoEY4B,CAAkBN,EAAGtB,GACtC6B,UAAYP,GAhDV,EAACC,EAA4BvB,cACzB,cAAduB,EAAML,OAC2C,KAA5CK,EAAMO,OAA4B5D,UAC/B8B,EAAI,EAAG,OACD+B,EAAW/B,EAAI,EACrBI,EAAS,GAAI2B,GACbxC,EAAMwC,GACN3C,GAAa,SAGjBA,GAAa,OAEI,WAAdmC,EAAML,eACbpC,EAAUkB,GAAGN,wBAASsC,OACtBnB,KACqB,eAAdU,EAAML,IACTlB,EAAIvB,EAAS,GACbc,EAAMS,EAAI,GAEO,cAAduB,EAAML,KACTlB,EAAI,GACJT,EAAMS,EAAI,IA2BY6B,CAAUP,EAAGtB,GAC/BiC,QAAUX,GAvBV,EAACA,EAAuCtB,KACpDV,EAAgBU,GAChBkC,YAAW,KAEPZ,EAAEQ,OAAOK,kBAAkBb,EAAEQ,OAAO5D,MAAMO,OAAQ6C,EAAEQ,OAAO5D,MAAMO,UAClE,IAkByBwD,CAAQX,EAAGtB,GAC3Ba,OAAQA,EACRuB,YAAa/C,IAAiBW,WAAeqC,EAC7CC,aAAc1D,EAAM,gBAAkB,MACtCV,MAAOe,EAAOe,IAAM,GACpBuC,UAAiB,IAANvC"}
|
|
1
|
+
{"version":3,"file":"PinInputField.js","sources":["../../../../src/components/PinInputField/PinInputField.tsx"],"sourcesContent":["import React, { createRef, useCallback, useEffect, useState } from \"react\";\n\nimport { Element } from \"../Element/Element\";\nimport { CommonAndHTMLProps } from \"../Element/constants\";\nimport { InputField } from \"../Form/InputField/InputField\";\n\nimport { PinInputStyled } from \"./PinInputField.styled\";\n\n// prettier-ignore\ntype PinInputFieldCustomProps = {\n numberOfFields : number;\n onChange ? : (value: string) => void;\n type ? : \"alphanumeric\" | \"number\";\n mask ? : boolean;\n otp ? : boolean;\n};\n\nexport type PinInputFieldElementType = HTMLDivElement;\nexport type PinInputFieldProps = Omit<CommonAndHTMLProps<PinInputFieldElementType>, keyof PinInputFieldCustomProps> &\n PinInputFieldCustomProps;\n\nfunction validate(value: string, type: \"alphanumeric\" | \"number\") {\n const NUMERIC_REGEX = /^[0-9]+$/;\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i;\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX;\n return regex.test(value);\n}\n\nexport const PinInputField = React.forwardRef(\n (\n { numberOfFields: length, onChange, type = \"number\", mask = false, otp = false }: PinInputFieldProps,\n ref: React.Ref<PinInputFieldElementType>\n ) => {\n const [inputRefs, setInputRefs] = useState<React.RefObject<HTMLInputElement>[]>([]);\n const [values, setValues] = useState<string[]>([]);\n const [moveFocus, setMoveFocus] = useState<boolean>(true);\n const [focusedIndex, setFocusedIndex] = useState<number>(0);\n\n const focus = useCallback(\n (index: number) => {\n const ref = inputRefs[index];\n ref?.current?.focus();\n },\n [inputRefs]\n );\n\n useEffect(() => {\n setInputRefs((inputRefs) => {\n const refs = Array(length)\n .fill(0)\n .map((_, i) => {\n const ref = inputRefs[i] || createRef();\n if (i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length]);\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus) return;\n const next = index + 1 < length ? index + 1 : null;\n if (next) {\n focus(next);\n }\n },\n [focus, length, moveFocus]\n );\n\n const setValue = useCallback(\n (value: string, index: number) => {\n const nextValues = [...values];\n nextValues[index] = value;\n setValues(nextValues);\n onChange(nextValues.join(\"\"));\n\n const isComplete =\n value !== \"\" &&\n nextValues.length === length &&\n nextValues.every((inputValue) => inputValue != null && inputValue !== \"\");\n\n if (!isComplete) {\n focusNext(index);\n }\n },\n [focusNext, length, onChange, values]\n );\n\n const getNextValue = useCallback((value: string, eventValue: string) => {\n let nextValue = eventValue;\n if (value?.length > 0) {\n if (value[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1);\n } else if (value[0] === eventValue.charAt(1)) {\n nextValue = eventValue.charAt(0);\n }\n }\n return nextValue;\n }, []);\n\n const handleInputChange = (event: React.FormEvent<HTMLInputElement>, i: number) => {\n const eventValue = event.currentTarget.value;\n const currentValue = values[i];\n const nextValue = getNextValue(currentValue, eventValue);\n\n if (nextValue === \"\") {\n setValue(\"\", i);\n return;\n }\n\n if (eventValue.length > 1 && i < length - 1) {\n if (validate(eventValue, type)) {\n const nextValue = eventValue.split(\"\").filter((_, index) => index < length);\n setValues(nextValue);\n focus(i + nextValue.length < length ? i + nextValue.length : length - 1);\n onChange?.(nextValue.join(\"\"));\n }\n } else {\n if (validate(nextValue, type)) {\n setValue(nextValue, i);\n }\n setMoveFocus(true);\n }\n };\n\n const onKeyDown = (event: React.KeyboardEvent, i: number) => {\n if (event.key === \"Backspace\") {\n if ((event.target as HTMLInputElement).value === \"\") {\n if (i > 0) {\n const newIndex = i - 1;\n setValue(\"\", newIndex);\n focus(newIndex);\n setMoveFocus(true);\n }\n } else {\n setMoveFocus(false);\n }\n } else if (event.key === \"Escape\") {\n inputRefs[i].current?.blur();\n onBlur();\n } else if (event.key === \"ArrowRight\") {\n if (i < length - 1) {\n focus(i + 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n if (i > 0) {\n focus(i - 1);\n }\n }\n };\n\n const onFocus = (e: React.FocusEvent<HTMLInputElement>, i: number) => {\n setFocusedIndex(i);\n setTimeout(() => {\n // https://github.com/facebook/react/issues/6483\n e.target.setSelectionRange(e.target.value.length, e.target.value.length);\n }, 0);\n };\n\n const onBlur = () => {\n setFocusedIndex(-1);\n };\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} ref={ref}>\n {[...Array(length)].map((_, i) => (\n <InputField\n key={i}\n className=\"pin-input-field\"\n ref={inputRefs[i]}\n type={mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\"}\n inputMode={type === \"number\" ? \"numeric\" : \"text\"}\n onChange={(e) => handleInputChange(e, i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n onFocus={(e) => onFocus(e, i)}\n onBlur={onBlur}\n placeholder={focusedIndex !== i ? `\\u2981` : undefined}\n autoComplete={otp ? \"one-time-code\" : \"off\"}\n value={values[i] || \"\"}\n autoFocus={i === 0}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onChange","mask","otp","ref","inputRefs","setInputRefs","useState","values","setValues","moveFocus","setMoveFocus","focusedIndex","setFocusedIndex","focus","useCallback","index","current","useEffect","Array","fill","map","_","i","createRef","focusNext","next","setValue","nextValues","join","every","inputValue","getNextValue","eventValue","nextValue","charAt","onBlur","Element","as","PinInputStyled","InputField","key","className","inputMode","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","autoFocus"],"mappings":"gqBAqBA,SAASA,EAASC,EAAeC,UAGN,iBAATA,EADc,kBADN,YAGTC,KAAKF,SAGTG,EAAgBC,UAAMC,YAC/B,EACMC,eAAgBC,EAAQC,SAAAA,EAAUP,KAAAA,EAAO,SAAUQ,KAAAA,GAAO,EAAOC,IAAAA,GAAM,GACzEC,WAEOC,EAAWC,GAAgBC,WAA8C,KACzEC,EAAQC,GAAaF,WAAmB,KACxCG,EAAWC,GAAgBJ,YAAkB,IAC7CK,EAAcC,GAAmBN,WAAiB,GAEnDO,EAAQC,eACTC,gBACSZ,EAAMC,EAAUW,aACtBZ,MAAAA,SAAAA,EAAKa,wBAASH,UAElB,CAACT,IAGLa,aAAU,KACNZ,GAAcD,GACGc,MAAMnB,GACdoB,KAAK,GACLC,KAAI,CAACC,EAAGC,iBACCnB,EAAMC,EAAUkB,IAAMC,qBAClB,IAAND,cACAnB,EAAIa,wBAASH,SAEVV,SAIpB,CAACJ,UAEEyB,EAAYV,eACbC,QACQN,EAAW,aACVgB,EAAOV,EAAQ,EAAIhB,EAASgB,EAAQ,EAAI,KAC1CU,GACAZ,EAAMY,KAGd,CAACZ,EAAOd,EAAQU,IAGdiB,EAAWZ,eACb,CAACtB,EAAeuB,WACNY,EAAa,IAAIpB,GACvBoB,EAAWZ,GAASvB,EACpBgB,EAAUmB,GACV3B,EAAS2B,EAAWC,KAAK,KAGX,KAAVpC,GACAmC,EAAW5B,SAAWA,GACtB4B,EAAWE,OAAOC,GAA6B,MAAdA,GAAqC,KAAfA,KAGvDN,EAAUT,KAGlB,CAACS,EAAWzB,EAAQC,EAAUO,IAG5BwB,EAAejB,eAAY,CAACtB,EAAewC,SACzCC,EAAYD,SACZxC,MAAAA,SAAAA,EAAOO,QAAS,IACZP,EAAM,KAAOwC,EAAWE,OAAO,GAC/BD,EAAYD,EAAWE,OAAO,GACvB1C,EAAM,KAAOwC,EAAWE,OAAO,KACtCD,EAAYD,EAAWE,OAAO,KAG/BD,IACR,IA6DGE,EAAS,KACXvB,GAAiB,WAIjBhB,wBAACwC,WAAkCC,GAAIC,iBAAgBnC,IAAKA,GACvD,IAAIe,MAAMnB,IAASqB,KAAI,CAACC,EAAGC,IACxB1B,wBAAC2C,cACGC,IAAKlB,EACLmB,UAAU,kBACVtC,IAAKC,EAAUkB,GACf7B,KAAMQ,EAAO,WAAsB,WAATR,EAAoB,MAAQ,OACtDiD,UAAoB,WAATjD,EAAoB,UAAY,OAC3CO,SAAW2C,GAxED,EAACC,EAA0CtB,WAC3DU,EAAaY,EAAMC,cAAcrD,MACjCsD,EAAevC,EAAOe,GACtBW,EAAYF,EAAae,EAAcd,MAE3B,KAAdC,KAKAD,EAAWjC,OAAS,GAAKuB,EAAIvB,EAAS,MAClCR,EAASyC,EAAYvC,GAAO,OACtBwC,EAAYD,EAAWe,MAAM,IAAIC,QAAO,CAAC3B,EAAGN,IAAUA,EAAQhB,IACpES,EAAUyB,GACVpB,EAAMS,EAAIW,EAAUlC,OAASA,EAASuB,EAAIW,EAAUlC,OAASA,EAAS,GACtEC,MAAAA,GAAAA,EAAWiC,EAAUL,KAAK,WAG1BrC,EAAS0C,EAAWxC,IACpBiC,EAASO,EAAWX,GAExBZ,GAAa,QAfbgB,EAAS,GAAIJ,IAkEY2B,CAAkBN,EAAGrB,GACtC4B,UAAYP,GAhDV,EAACC,EAA4BtB,cACzB,cAAdsB,EAAMJ,OAC2C,KAA5CI,EAAMO,OAA4B3D,UAC/B8B,EAAI,EAAG,OACD8B,EAAW9B,EAAI,EACrBI,EAAS,GAAI0B,GACbvC,EAAMuC,GACN1C,GAAa,SAGjBA,GAAa,OAEI,WAAdkC,EAAMJ,eACbpC,EAAUkB,GAAGN,wBAASqC,OACtBlB,KACqB,eAAdS,EAAMJ,IACTlB,EAAIvB,EAAS,GACbc,EAAMS,EAAI,GAEO,cAAdsB,EAAMJ,KACTlB,EAAI,GACJT,EAAMS,EAAI,IA2BY4B,CAAUP,EAAGrB,GAC/BgC,QAAUX,GAvBV,EAACA,EAAuCrB,KACpDV,EAAgBU,GAChBiC,YAAW,KAEPZ,EAAEQ,OAAOK,kBAAkBb,EAAEQ,OAAO3D,MAAMO,OAAQ4C,EAAEQ,OAAO3D,MAAMO,UAClE,IAkByBuD,CAAQX,EAAGrB,GAC3Ba,OAAQA,EACRsB,YAAa9C,IAAiBW,WAAeoC,EAC7CC,aAAczD,EAAM,gBAAkB,MACtCV,MAAOe,EAAOe,IAAM,GACpBsC,UAAiB,IAANtC"}
|
|
@@ -2,12 +2,12 @@ import React from "react";
|
|
|
2
2
|
import { CommonAndHTMLProps } from "../Element/constants";
|
|
3
3
|
declare type PinInputFieldCustomProps = {
|
|
4
4
|
numberOfFields: number;
|
|
5
|
-
|
|
5
|
+
onChange?: (value: string) => void;
|
|
6
6
|
type?: "alphanumeric" | "number";
|
|
7
7
|
mask?: boolean;
|
|
8
8
|
otp?: boolean;
|
|
9
9
|
};
|
|
10
10
|
export declare type PinInputFieldElementType = HTMLDivElement;
|
|
11
|
-
export declare type
|
|
12
|
-
export declare const PinInputField: React.ForwardRefExoticComponent<PinInputFieldCustomProps & React.RefAttributes<HTMLDivElement>>;
|
|
11
|
+
export declare type PinInputFieldProps = Omit<CommonAndHTMLProps<PinInputFieldElementType>, keyof PinInputFieldCustomProps> & PinInputFieldCustomProps;
|
|
12
|
+
export declare const PinInputField: React.ForwardRefExoticComponent<Omit<CommonAndHTMLProps<HTMLDivElement>, keyof PinInputFieldCustomProps> & PinInputFieldCustomProps & React.RefAttributes<HTMLDivElement>>;
|
|
13
13
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import e,{useState as t,useCallback as r,useEffect as o,createRef as n}from"react";import{E as l}from"../../external/Element.js";import{InputField as m}from"../Form/InputField/InputField.js";import{PinInputStyled as s}from"./PinInputField.styled.js";import"../Form/BaseInputComponent/BaseInputComponent.js";import"../Form/InputLabel/InputLabel.js";import"../Form/FormItem/FormItem.js";import"../Form/FormItem/FormItem.styled.js";import"styled-components";import"../Form/InputField/InputField.styled.js";import"../Form/Select/Select.styled.js";import"../Form/TextArea/TextArea.styled.js";function
|
|
2
|
-
return e.createElement(l,{as:s,ref:d},[...Array(
|
|
1
|
+
import e,{useState as t,useCallback as r,useEffect as o,createRef as n}from"react";import{E as l}from"../../external/Element.js";import{InputField as m}from"../Form/InputField/InputField.js";import{PinInputStyled as s}from"./PinInputField.styled.js";import"../Form/BaseInputComponent/BaseInputComponent.js";import"../Form/InputLabel/InputLabel.js";import"../Form/FormItem/FormItem.js";import"../Form/FormItem/FormItem.styled.js";import"styled-components";import"../Form/InputField/InputField.styled.js";import"../Form/Select/Select.styled.js";import"../Form/TextArea/TextArea.styled.js";function a(e,t){return("alphanumeric"===t?/^[a-zA-Z0-9]+$/i:/^[0-9]+$/).test(e)}const i=/*#__PURE__*/e.forwardRef((({numberOfFields:i,onChange:u,type:p="number",mask:c=!1,otp:f=!1},d)=>{const[F,y]=t([]),[g,h]=t([]),[v,I]=t(!0),[j,A]=t(0),b=r((e=>{var t;const r=F[e];null===(t=null==r?void 0:r.current)||void 0===t||t.focus()}),[F]);o((()=>{y((e=>Array(i).fill(0).map(((t,r)=>{var o;const l=e[r]||/*#__PURE__*/n();return 0===r&&(null===(o=l.current)||void 0===o||o.focus()),l}))))}),[i]);const k=r((e=>{if(!v)return;const t=e+1<i?e+1:null;t&&b(t)}),[b,i,v]),x=r(((e,t)=>{const r=[...g];r[t]=e,h(r),u(r.join(""));""!==e&&r.length===i&&r.every((e=>null!=e&&""!==e))||k(t)}),[k,i,u,g]),w=r(((e,t)=>{let r=t;return(null==e?void 0:e.length)>0&&(e[0]===t.charAt(0)?r=t.charAt(1):e[0]===t.charAt(1)&&(r=t.charAt(0))),r}),[]),C=()=>{A(-1)};/*#__PURE__*/
|
|
2
|
+
return e.createElement(l,{as:s,ref:d},[...Array(i)].map(((t,r)=>/*#__PURE__*/e.createElement(m,{key:r,className:"pin-input-field",ref:F[r],type:c?"password":"number"===p?"tel":"text",inputMode:"number"===p?"numeric":"text",onChange:e=>((e,t)=>{const r=e.currentTarget.value,o=g[t],n=w(o,r);if(""!==n)if(r.length>1&&t<i-1){if(a(r,p)){const e=r.split("").filter(((e,t)=>t<i));h(e),b(t+e.length<i?t+e.length:i-1),null==u||u(e.join(""))}}else a(n,p)&&x(n,t),I(!0);else x("",t)})(e,r),onKeyDown:e=>((e,t)=>{var r;if("Backspace"===e.key)if(""===e.target.value){if(t>0){const e=t-1;x("",e),b(e),I(!0)}}else I(!1);else"Escape"===e.key?(null===(r=F[t].current)||void 0===r||r.blur(),C()):"ArrowRight"===e.key?t<i-1&&b(t+1):"ArrowLeft"===e.key&&t>0&&b(t-1)})(e,r),onFocus:e=>((e,t)=>{A(t),setTimeout((()=>{e.target.setSelectionRange(e.target.value.length,e.target.value.length)}),0)})(e,r),onBlur:C,placeholder:j!==r?"⦁":void 0,autoComplete:f?"one-time-code":"off",value:g[r]||"",autoFocus:0===r}))))}));export{i as PinInputField};
|
|
3
3
|
//# sourceMappingURL=PinInputField.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinInputField.js","sources":["../../../../src/components/PinInputField/PinInputField.tsx"],"sourcesContent":["import React, { createRef, useCallback, useEffect, useState } from \"react\";\n\nimport { Element } from \"../Element/Element\";\nimport { CommonAndHTMLProps } from \"../Element/constants\";\nimport { InputField } from \"../Form/InputField/InputField\";\n\nimport { PinInputStyled } from \"./PinInputField.styled\";\n\n// prettier-ignore\ntype PinInputFieldCustomProps = {\n numberOfFields : number;\n onComplete ? : (value: string) => void;\n type ? : \"alphanumeric\" | \"number\";\n mask ? : boolean;\n otp ? : boolean;\n};\n\nexport type PinInputFieldElementType = HTMLDivElement;\nexport type RowProps = Omit<CommonAndHTMLProps<PinInputFieldElementType>, keyof PinInputFieldCustomProps> &\n PinInputFieldCustomProps;\n\nfunction validate(value: string, type: \"alphanumeric\" | \"number\") {\n const NUMERIC_REGEX = /^[0-9]+$/;\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i;\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX;\n return regex.test(value);\n}\n\nexport const PinInputField = React.forwardRef(\n (\n { numberOfFields: length, onComplete, type = \"number\", mask = false, otp = false }: PinInputFieldCustomProps,\n ref: React.Ref<PinInputFieldElementType>\n ) => {\n const [inputRefs, setInputRefs] = useState<React.RefObject<HTMLInputElement>[]>([]);\n const [values, setValues] = useState<string[]>([]);\n const [moveFocus, setMoveFocus] = useState<boolean>(true);\n const [focusedIndex, setFocusedIndex] = useState<number>(0);\n\n const focus = useCallback(\n (index: number) => {\n const ref = inputRefs[index];\n ref?.current?.focus();\n },\n [inputRefs]\n );\n\n useEffect(() => {\n setInputRefs((inputRefs) => {\n const refs = Array(length)\n .fill(0)\n .map((_, i) => {\n const ref = inputRefs[i] || createRef();\n if (i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length]);\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus) return;\n const next = index + 1 < length ? index + 1 : null;\n if (next) {\n focus(next);\n }\n },\n [focus, length, moveFocus]\n );\n\n const setValue = useCallback(\n (value: string, index: number) => {\n const nextValues = [...values];\n nextValues[index] = value;\n setValues(nextValues);\n\n const isComplete =\n value !== \"\" &&\n nextValues.length === length &&\n nextValues.every((inputValue) => inputValue != null && inputValue !== \"\");\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"));\n } else {\n focusNext(index);\n }\n },\n [focusNext, length, onComplete, values]\n );\n\n const getNextValue = useCallback((value: string, eventValue: string) => {\n let nextValue = eventValue;\n if (value?.length > 0) {\n if (value[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1);\n } else if (value[0] === eventValue.charAt(1)) {\n nextValue = eventValue.charAt(0);\n }\n }\n return nextValue;\n }, []);\n\n const handleInputChange = (event: React.FormEvent<HTMLInputElement>, i: number) => {\n const eventValue = event.currentTarget.value;\n const currentValue = values[i];\n const nextValue = getNextValue(currentValue, eventValue);\n\n if (nextValue === \"\") {\n setValue(\"\", i);\n return;\n }\n\n if (eventValue.length > 1 && i < length - 1) {\n if (validate(eventValue, type)) {\n const nextValue = eventValue.split(\"\").filter((_, index) => index < length);\n setValues(nextValue);\n focus(i + nextValue.length < length ? i + nextValue.length : length - 1);\n if (nextValue.length === length) {\n onComplete?.(nextValue.join(\"\"));\n }\n }\n } else {\n if (validate(nextValue, type)) {\n setValue(nextValue, i);\n }\n setMoveFocus(true);\n }\n };\n\n const onKeyDown = (event: React.KeyboardEvent, i: number) => {\n if (event.key === \"Backspace\") {\n if ((event.target as HTMLInputElement).value === \"\") {\n if (i > 0) {\n const newIndex = i - 1;\n setValue(\"\", newIndex);\n focus(newIndex);\n setMoveFocus(true);\n }\n } else {\n setMoveFocus(false);\n }\n } else if (event.key === \"Escape\") {\n inputRefs[i].current?.blur();\n onBlur();\n } else if (event.key === \"ArrowRight\") {\n if (i < length - 1) {\n focus(i + 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n if (i > 0) {\n focus(i - 1);\n }\n }\n };\n\n const onFocus = (e: React.FocusEvent<HTMLInputElement>, i: number) => {\n setFocusedIndex(i);\n setTimeout(() => {\n // https://github.com/facebook/react/issues/6483\n e.target.setSelectionRange(e.target.value.length, e.target.value.length);\n }, 0);\n };\n\n const onBlur = () => {\n setFocusedIndex(-1);\n };\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} ref={ref}>\n {[...Array(length)].map((_, i) => (\n <InputField\n key={i}\n className=\"pin-input-field\"\n ref={inputRefs[i]}\n type={mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\"}\n inputMode={type === \"number\" ? \"numeric\" : \"text\"}\n onChange={(e) => handleInputChange(e, i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n onFocus={(e) => onFocus(e, i)}\n onBlur={onBlur}\n placeholder={focusedIndex !== i ? `\\u2981` : undefined}\n autoComplete={otp ? \"one-time-code\" : \"off\"}\n value={values[i] || \"\"}\n autoFocus={i === 0}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onComplete","mask","otp","ref","inputRefs","setInputRefs","useState","values","setValues","moveFocus","setMoveFocus","focusedIndex","setFocusedIndex","focus","useCallback","index","current","useEffect","Array","fill","map","_","i","createRef","focusNext","next","setValue","nextValues","every","inputValue","join","getNextValue","eventValue","nextValue","charAt","onBlur","Element","as","PinInputStyled","InputField","key","className","inputMode","onChange","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","autoFocus"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PinInputField.js","sources":["../../../../src/components/PinInputField/PinInputField.tsx"],"sourcesContent":["import React, { createRef, useCallback, useEffect, useState } from \"react\";\n\nimport { Element } from \"../Element/Element\";\nimport { CommonAndHTMLProps } from \"../Element/constants\";\nimport { InputField } from \"../Form/InputField/InputField\";\n\nimport { PinInputStyled } from \"./PinInputField.styled\";\n\n// prettier-ignore\ntype PinInputFieldCustomProps = {\n numberOfFields : number;\n onChange ? : (value: string) => void;\n type ? : \"alphanumeric\" | \"number\";\n mask ? : boolean;\n otp ? : boolean;\n};\n\nexport type PinInputFieldElementType = HTMLDivElement;\nexport type PinInputFieldProps = Omit<CommonAndHTMLProps<PinInputFieldElementType>, keyof PinInputFieldCustomProps> &\n PinInputFieldCustomProps;\n\nfunction validate(value: string, type: \"alphanumeric\" | \"number\") {\n const NUMERIC_REGEX = /^[0-9]+$/;\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i;\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX;\n return regex.test(value);\n}\n\nexport const PinInputField = React.forwardRef(\n (\n { numberOfFields: length, onChange, type = \"number\", mask = false, otp = false }: PinInputFieldProps,\n ref: React.Ref<PinInputFieldElementType>\n ) => {\n const [inputRefs, setInputRefs] = useState<React.RefObject<HTMLInputElement>[]>([]);\n const [values, setValues] = useState<string[]>([]);\n const [moveFocus, setMoveFocus] = useState<boolean>(true);\n const [focusedIndex, setFocusedIndex] = useState<number>(0);\n\n const focus = useCallback(\n (index: number) => {\n const ref = inputRefs[index];\n ref?.current?.focus();\n },\n [inputRefs]\n );\n\n useEffect(() => {\n setInputRefs((inputRefs) => {\n const refs = Array(length)\n .fill(0)\n .map((_, i) => {\n const ref = inputRefs[i] || createRef();\n if (i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length]);\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus) return;\n const next = index + 1 < length ? index + 1 : null;\n if (next) {\n focus(next);\n }\n },\n [focus, length, moveFocus]\n );\n\n const setValue = useCallback(\n (value: string, index: number) => {\n const nextValues = [...values];\n nextValues[index] = value;\n setValues(nextValues);\n onChange(nextValues.join(\"\"));\n\n const isComplete =\n value !== \"\" &&\n nextValues.length === length &&\n nextValues.every((inputValue) => inputValue != null && inputValue !== \"\");\n\n if (!isComplete) {\n focusNext(index);\n }\n },\n [focusNext, length, onChange, values]\n );\n\n const getNextValue = useCallback((value: string, eventValue: string) => {\n let nextValue = eventValue;\n if (value?.length > 0) {\n if (value[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1);\n } else if (value[0] === eventValue.charAt(1)) {\n nextValue = eventValue.charAt(0);\n }\n }\n return nextValue;\n }, []);\n\n const handleInputChange = (event: React.FormEvent<HTMLInputElement>, i: number) => {\n const eventValue = event.currentTarget.value;\n const currentValue = values[i];\n const nextValue = getNextValue(currentValue, eventValue);\n\n if (nextValue === \"\") {\n setValue(\"\", i);\n return;\n }\n\n if (eventValue.length > 1 && i < length - 1) {\n if (validate(eventValue, type)) {\n const nextValue = eventValue.split(\"\").filter((_, index) => index < length);\n setValues(nextValue);\n focus(i + nextValue.length < length ? i + nextValue.length : length - 1);\n onChange?.(nextValue.join(\"\"));\n }\n } else {\n if (validate(nextValue, type)) {\n setValue(nextValue, i);\n }\n setMoveFocus(true);\n }\n };\n\n const onKeyDown = (event: React.KeyboardEvent, i: number) => {\n if (event.key === \"Backspace\") {\n if ((event.target as HTMLInputElement).value === \"\") {\n if (i > 0) {\n const newIndex = i - 1;\n setValue(\"\", newIndex);\n focus(newIndex);\n setMoveFocus(true);\n }\n } else {\n setMoveFocus(false);\n }\n } else if (event.key === \"Escape\") {\n inputRefs[i].current?.blur();\n onBlur();\n } else if (event.key === \"ArrowRight\") {\n if (i < length - 1) {\n focus(i + 1);\n }\n } else if (event.key === \"ArrowLeft\") {\n if (i > 0) {\n focus(i - 1);\n }\n }\n };\n\n const onFocus = (e: React.FocusEvent<HTMLInputElement>, i: number) => {\n setFocusedIndex(i);\n setTimeout(() => {\n // https://github.com/facebook/react/issues/6483\n e.target.setSelectionRange(e.target.value.length, e.target.value.length);\n }, 0);\n };\n\n const onBlur = () => {\n setFocusedIndex(-1);\n };\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} ref={ref}>\n {[...Array(length)].map((_, i) => (\n <InputField\n key={i}\n className=\"pin-input-field\"\n ref={inputRefs[i]}\n type={mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\"}\n inputMode={type === \"number\" ? \"numeric\" : \"text\"}\n onChange={(e) => handleInputChange(e, i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n onFocus={(e) => onFocus(e, i)}\n onBlur={onBlur}\n placeholder={focusedIndex !== i ? `\\u2981` : undefined}\n autoComplete={otp ? \"one-time-code\" : \"off\"}\n value={values[i] || \"\"}\n autoFocus={i === 0}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onChange","mask","otp","ref","inputRefs","setInputRefs","useState","values","setValues","moveFocus","setMoveFocus","focusedIndex","setFocusedIndex","focus","useCallback","index","current","useEffect","Array","fill","map","_","i","createRef","focusNext","next","setValue","nextValues","join","every","inputValue","getNextValue","eventValue","nextValue","charAt","onBlur","Element","as","PinInputStyled","InputField","key","className","inputMode","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","autoFocus"],"mappings":"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"}
|