fictoan-react 0.45.1 → 0.45.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 +1 -1
- 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 +1 -1
- package/dist/es/components/PinInputField/PinInputField.js +1 -1
- package/dist/es/components/PinInputField/PinInputField.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
### 0.45.2
|
|
4
|
+
- Fix prop name for disable copy/paste to pasteFromClipboard which takes either enabled or disabled as parameters for `PinInput Field`
|
|
5
|
+
|
|
3
6
|
### 0.45.1
|
|
4
7
|
- Export props types for all components
|
|
5
8
|
- Fix excess margin issue for `Tabs` labels
|
|
@@ -7,7 +7,7 @@ declare type PinInputFieldCustomProps = {
|
|
|
7
7
|
mask?: boolean;
|
|
8
8
|
otp?: boolean;
|
|
9
9
|
autoFocus?: boolean;
|
|
10
|
-
|
|
10
|
+
pasteFromClipboard?: "enabled" | "disabled";
|
|
11
11
|
spacing?: SpacingTypes;
|
|
12
12
|
};
|
|
13
13
|
export declare type PinInputFieldElementType = HTMLDivElement;
|
|
@@ -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"),l=require("./PinInputField.styled.js");function n(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"),require("../../external/theme.js"),require("../../external/DefaultColours.js");var u=/*#__PURE__*/n(e);function a(e,t){return("alphanumeric"===t?/^[a-zA-Z0-9]+$/i:/^[0-9]+$/).test(e)}const s=u.default.forwardRef((({numberOfFields:n,onChange:s,type:o="number",mask:i=!1,otp:c=!1,autoFocus:p=!1,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../../external/Element.js"),r=require("../Form/InputField/InputField.js"),l=require("./PinInputField.styled.js");function n(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"),require("../../external/theme.js"),require("../../external/DefaultColours.js");var u=/*#__PURE__*/n(e);function a(e,t){return("alphanumeric"===t?/^[a-zA-Z0-9]+$/i:/^[0-9]+$/).test(e)}const s=u.default.forwardRef((({numberOfFields:n,onChange:s,type:o="number",mask:i=!1,otp:c=!1,autoFocus:p=!1,pasteFromClipboard:d="enabled",spacing:m="small"},f)=>{const[F,y]=e.useState([]),[v,g]=e.useState([]),[h,b]=e.useState(!0),[j,I]=e.useState(-1),q=e.useCallback((e=>{var t;const r=F[e];null===(t=null==r?void 0:r.current)||void 0===t||t.focus()}),[F]);e.useEffect((()=>{y((t=>Array(n).fill(0).map(((r,l)=>{var n;const u=t[l]||e.createRef();return p&&0===l&&(null===(n=u.current)||void 0===n||n.focus()),u}))))}),[n,p]);const C=e.useCallback((e=>{if(!h)return;const t=e+1<n?e+1:null;t&&q(t)}),[q,n,h]),k=e.useCallback(((e,t)=>{const r=[...v];r[t]=e,g(r),null==s||s(r.join(""));""!==e&&r.length===n&&r.every((e=>null!=e&&""!==e))||C(t)}),[C,n,s,v]),A=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}),[]),x=()=>{I(-1)};let S=[];return m&&S.push(`spacing-${m}`),u.default.createElement(t.Element,{as:l.PinInputStyled,classNames:S,ref:f},[...Array(n)].map(((e,t)=>u.default.createElement(r.InputField,{key:t,className:"pin-input-field",ref:F[t],type:i?"password":"number"===o?"tel":"text",inputMode:"number"===o?"numeric":"text",onChange:e=>((e,t)=>{const r=e.currentTarget.value,l=v[t],u=A(l,r);if(""!==u)if(r.length>1&&t<n-1){if(a(r,o)){const e=r.split("").filter(((e,t)=>t<n));g(e),q(t+e.length<n?t+e.length:n-1),null==s||s(e.join(""))}}else a(u,o)&&k(u,t),b(!0);else k("",t)})(e,t),onKeyDown:e=>((e,t)=>{var r;if("Backspace"===e.key)if(""===e.target.value){if(t>0){const e=t-1;k("",e),q(e),b(!0)}}else b(!1);else"Escape"===e.key?(null===(r=F[t].current)||void 0===r||r.blur(),x()):"ArrowRight"===e.key?t<n-1&&q(t+1):"ArrowLeft"===e.key&&t>0&&q(t-1)})(e,t),onFocus:e=>((e,t)=>{I(t),setTimeout((()=>{e.target.setSelectionRange(e.target.value.length,e.target.value.length)}),0)})(e,t),onBlur:x,placeholder:j!==t?"⦁":void 0,autoComplete:c?"one-time-code":"off",value:v[t]||"",autoFocus:p&&0===t,onCopy:e=>"disabled"===d&&e.preventDefault(),onPaste:e=>"disabled"===d&&e.preventDefault()}))))}));exports.PinInputField=s;
|
|
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, SpacingTypes } 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 autoFocus ? : boolean;\n disableCopyPaste ? : boolean;\n spacing ? : SpacingTypes;\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 {\n numberOfFields: length,\n onChange,\n type = \"number\",\n mask = false,\n otp = false,\n autoFocus = false,\n disableCopyPaste = false,\n spacing = \"small\",\n }: 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>(-1);\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 (autoFocus && i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length, autoFocus]);\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 let classNames = [];\n\n if (spacing) {\n classNames.push(`spacing-${spacing}`);\n }\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} classNames={classNames} 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={autoFocus && i === 0}\n onCopy={e=> disableCopyPaste && e.preventDefault()}\n onPaste={e=> disableCopyPaste && e.preventDefault()}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onChange","mask","otp","autoFocus","disableCopyPaste","spacing","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","classNames","push","Element","as","PinInputStyled","InputField","key","className","inputMode","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","onCopy","preventDefault","onPaste"],"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, SpacingTypes } 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 autoFocus ? : boolean;\n pasteFromClipboard ? : \"enabled\" | \"disabled\";\n spacing ? : SpacingTypes;\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 {\n numberOfFields: length,\n onChange,\n type = \"number\",\n mask = false,\n otp = false,\n autoFocus = false,\n pasteFromClipboard = \"enabled\",\n spacing = \"small\",\n }: 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>(-1);\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 (autoFocus && i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length, autoFocus]);\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 let classNames = [];\n\n if (spacing) {\n classNames.push(`spacing-${spacing}`);\n }\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} classNames={classNames} 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={autoFocus && i === 0}\n onCopy={e=> pasteFromClipboard === \"disabled\" && e.preventDefault()}\n onPaste={e=> pasteFromClipboard === \"disabled\" && e.preventDefault()}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onChange","mask","otp","autoFocus","pasteFromClipboard","spacing","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","classNames","push","Element","as","PinInputStyled","InputField","key","className","inputMode","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","onCopy","preventDefault","onPaste"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ declare type PinInputFieldCustomProps = {
|
|
|
7
7
|
mask?: boolean;
|
|
8
8
|
otp?: boolean;
|
|
9
9
|
autoFocus?: boolean;
|
|
10
|
-
|
|
10
|
+
pasteFromClipboard?: "enabled" | "disabled";
|
|
11
11
|
spacing?: SpacingTypes;
|
|
12
12
|
};
|
|
13
13
|
export declare type PinInputFieldElementType = HTMLDivElement;
|
|
@@ -1,2 +1,2 @@
|
|
|
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
|
|
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 a}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";import"../../external/theme.js";import"../../external/DefaultColours.js";function m(e,t){return("alphanumeric"===t?/^[a-zA-Z0-9]+$/i:/^[0-9]+$/).test(e)}const u=/*#__PURE__*/e.forwardRef((({numberOfFields:u,onChange:i,type:p="number",mask:c=!1,otp:d=!1,autoFocus:f=!1,pasteFromClipboard:F="enabled",spacing:g="small"},h)=>{const[y,v]=t([]),[j,I]=t([]),[b,A]=t(!0),[x,C]=t(-1),k=r((e=>{var t;const r=y[e];null===(t=null==r?void 0:r.current)||void 0===t||t.focus()}),[y]);o((()=>{v((e=>Array(u).fill(0).map(((t,r)=>{var o;const l=e[r]||/*#__PURE__*/n();return f&&0===r&&(null===(o=l.current)||void 0===o||o.focus()),l}))))}),[u,f]);const w=r((e=>{if(!b)return;const t=e+1<u?e+1:null;t&&k(t)}),[k,u,b]),E=r(((e,t)=>{const r=[...j];r[t]=e,I(r),null==i||i(r.join(""));""!==e&&r.length===u&&r.every((e=>null!=e&&""!==e))||w(t)}),[w,u,i,j]),B=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}),[]),D=()=>{C(-1)};let T=[];return g&&T.push(`spacing-${g}`),/*#__PURE__*/e.createElement(l,{as:s,classNames:T,ref:h},[...Array(u)].map(((t,r)=>/*#__PURE__*/e.createElement(a,{key:r,className:"pin-input-field",ref:y[r],type:c?"password":"number"===p?"tel":"text",inputMode:"number"===p?"numeric":"text",onChange:e=>((e,t)=>{const r=e.currentTarget.value,o=j[t],n=B(o,r);if(""!==n)if(r.length>1&&t<u-1){if(m(r,p)){const e=r.split("").filter(((e,t)=>t<u));I(e),k(t+e.length<u?t+e.length:u-1),null==i||i(e.join(""))}}else m(n,p)&&E(n,t),A(!0);else E("",t)})(e,r),onKeyDown:e=>((e,t)=>{var r;if("Backspace"===e.key)if(""===e.target.value){if(t>0){const e=t-1;E("",e),k(e),A(!0)}}else A(!1);else"Escape"===e.key?(null===(r=y[t].current)||void 0===r||r.blur(),D()):"ArrowRight"===e.key?t<u-1&&k(t+1):"ArrowLeft"===e.key&&t>0&&k(t-1)})(e,r),onFocus:e=>((e,t)=>{C(t),setTimeout((()=>{e.target.setSelectionRange(e.target.value.length,e.target.value.length)}),0)})(e,r),onBlur:D,placeholder:x!==r?"⦁":void 0,autoComplete:d?"one-time-code":"off",value:j[r]||"",autoFocus:f&&0===r,onCopy:e=>"disabled"===F&&e.preventDefault(),onPaste:e=>"disabled"===F&&e.preventDefault()}))))}));export{u as PinInputField};
|
|
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, SpacingTypes } 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 autoFocus ? : boolean;\n disableCopyPaste ? : boolean;\n spacing ? : SpacingTypes;\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 {\n numberOfFields: length,\n onChange,\n type = \"number\",\n mask = false,\n otp = false,\n autoFocus = false,\n disableCopyPaste = false,\n spacing = \"small\",\n }: 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>(-1);\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 (autoFocus && i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length, autoFocus]);\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 let classNames = [];\n\n if (spacing) {\n classNames.push(`spacing-${spacing}`);\n }\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} classNames={classNames} 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={autoFocus && i === 0}\n onCopy={e=> disableCopyPaste && e.preventDefault()}\n onPaste={e=> disableCopyPaste && e.preventDefault()}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onChange","mask","otp","autoFocus","disableCopyPaste","spacing","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","classNames","push","Element","as","PinInputStyled","InputField","key","className","inputMode","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","onCopy","preventDefault","onPaste"],"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, SpacingTypes } 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 autoFocus ? : boolean;\n pasteFromClipboard ? : \"enabled\" | \"disabled\";\n spacing ? : SpacingTypes;\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 {\n numberOfFields: length,\n onChange,\n type = \"number\",\n mask = false,\n otp = false,\n autoFocus = false,\n pasteFromClipboard = \"enabled\",\n spacing = \"small\",\n }: 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>(-1);\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 (autoFocus && i === 0) {\n ref.current?.focus();\n }\n return ref;\n });\n return refs;\n });\n }, [length, autoFocus]);\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 let classNames = [];\n\n if (spacing) {\n classNames.push(`spacing-${spacing}`);\n }\n\n return (\n <Element<PinInputFieldElementType> as={PinInputStyled} classNames={classNames} 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={autoFocus && i === 0}\n onCopy={e=> pasteFromClipboard === \"disabled\" && e.preventDefault()}\n onPaste={e=> pasteFromClipboard === \"disabled\" && e.preventDefault()}\n />\n ))}\n </Element>\n );\n }\n);\n"],"names":["validate","value","type","test","PinInputField","React","forwardRef","numberOfFields","length","onChange","mask","otp","autoFocus","pasteFromClipboard","spacing","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","classNames","push","Element","as","PinInputStyled","InputField","key","className","inputMode","e","event","currentTarget","currentValue","split","filter","handleInputChange","onKeyDown","target","newIndex","blur","onFocus","setTimeout","setSelectionRange","placeholder","undefined","autoComplete","onCopy","preventDefault","onPaste"],"mappings":"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"}
|