1
- import { ChangeEvent , useCallback , useMemo , useRef , useState } from "react" ;
1
+ import { ChangeEvent , KeyboardEvent , useCallback , useMemo , useRef , useState } from "react" ;
2
2
3
3
import { PhoneNumber , usePhoneOptions } from "./types" ;
4
4
@@ -74,6 +74,43 @@ export const parsePhoneNumber = (formattedNumber: string, countriesList: typeof
74
74
return { countryCode, areaCode, phoneNumber, isoCode} ;
75
75
}
76
76
77
+ export const useMask = ( pattern : string ) => {
78
+ const backRef = useRef < boolean > ( false ) ;
79
+
80
+ const clean = useCallback ( ( input : any ) => {
81
+ return cleanInput ( input , pattern . replaceAll ( / \d / g, "." ) ) ;
82
+ } , [ pattern ] )
83
+
84
+ const first = useMemo ( ( ) => {
85
+ return [ ...pattern ] . findIndex ( c => slots . has ( c ) ) ;
86
+ } , [ pattern ] )
87
+
88
+ const prev = useMemo ( ( j = 0 ) => {
89
+ return Array . from ( pattern . replaceAll ( / \d / g, "." ) , ( c , i ) => {
90
+ return slots . has ( c ) ? j = i + 1 : j ;
91
+ } ) ;
92
+ } , [ pattern ] )
93
+
94
+ const onKeyDown = useCallback ( ( event : KeyboardEvent < HTMLInputElement > ) => {
95
+ backRef . current = event . key === "Backspace" ;
96
+ } , [ ] )
97
+
98
+ const onInput = useCallback ( ( { target} : ChangeEvent < HTMLInputElement > ) => {
99
+ const [ i , j ] = [ target . selectionStart , target . selectionEnd ] . map ( ( i : any ) => {
100
+ i = clean ( target . value . slice ( 0 , i ) ) . findIndex ( c => slots . has ( c ) ) ;
101
+ return i < 0 ? prev [ prev . length - 1 ] : backRef . current ? prev [ i - 1 ] || first : i ;
102
+ } ) ;
103
+ target . value = getFormattedNumber ( target . value , pattern ) ;
104
+ target . setSelectionRange ( i , j ) ;
105
+ backRef . current = false ;
106
+ } , [ clean , first , pattern , prev ] )
107
+
108
+ return {
109
+ onInput,
110
+ onKeyDown,
111
+ }
112
+ }
113
+
77
114
export const usePhone = ( {
78
115
query = "" ,
79
116
country = "" ,
@@ -87,7 +124,6 @@ export const usePhone = ({
87
124
const defaultMetadata = getMetadata ( defaultValue ) || countries . find ( ( [ iso ] ) => iso === country ) ;
88
125
const defaultValueState = defaultValue || countries . find ( ( [ iso ] ) => iso === defaultMetadata ?. [ 0 ] ) ?. [ 2 ] as string ;
89
126
90
- const backRef = useRef < boolean > ( false ) ;
91
127
const [ value , setValue ] = useState < string > ( defaultValueState ) ;
92
128
93
129
const countriesOnly = useMemo ( ( ) => {
@@ -121,35 +157,9 @@ export const usePhone = ({
121
157
return metadata ?. [ 3 ] || defaultMetadata ?. [ 3 ] || "" ;
122
158
} , [ defaultMetadata , metadata ] )
123
159
124
- const clean = useCallback ( ( input : any ) => {
125
- return cleanInput ( input , pattern . replaceAll ( / \d / g, "." ) ) ;
126
- } , [ pattern ] )
127
-
128
- const first = useMemo ( ( ) => {
129
- return [ ...pattern ] . findIndex ( c => slots . has ( c ) ) ;
130
- } , [ pattern ] )
131
-
132
- const prev = useMemo ( ( j = 0 ) => {
133
- return Array . from ( pattern . replaceAll ( / \d / g, "." ) , ( c , i ) => {
134
- return slots . has ( c ) ? j = i + 1 : j ;
135
- } ) ;
136
- } , [ pattern ] )
137
-
138
- const format = useCallback ( ( { target} : ChangeEvent < HTMLInputElement > ) => {
139
- const [ i , j ] = [ target . selectionStart , target . selectionEnd ] . map ( ( i : any ) => {
140
- i = clean ( target . value . slice ( 0 , i ) ) . findIndex ( c => slots . has ( c ) ) ;
141
- return i < 0 ? prev [ prev . length - 1 ] : backRef . current ? prev [ i - 1 ] || first : i ;
142
- } ) ;
143
- target . value = getFormattedNumber ( target . value , pattern ) ;
144
- target . setSelectionRange ( i , j ) ;
145
- backRef . current = false ;
146
- setValue ( target . value ) ;
147
- } , [ clean , first , pattern , prev ] )
148
-
149
160
return {
150
- clean,
151
161
value,
152
- format ,
162
+ pattern ,
153
163
metadata,
154
164
setValue,
155
165
countriesList,
0 commit comments