-
Notifications
You must be signed in to change notification settings - Fork 0
/
use-native-mask.ts
106 lines (95 loc) · 2.28 KB
/
use-native-mask.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import React from 'react';
import type { MaskGenerator } from '../types/mask-generator';
import { useRefMask } from './use-ref-mask';
interface NativeSelection {
start: number;
end: number;
}
interface NativeSelectionWrapper {
selection: NativeSelection;
}
interface TextInputProps {
setNativeProps: (props: NativeSelectionWrapper) => void;
}
export const useNativeMask = <T extends TextInputProps>({
maskGenerator,
value,
onChange,
keepMask,
waitToUpdateCursor,
ref: outerRef,
}: {
maskGenerator?: MaskGenerator;
value?: string;
onChange?: (value: string) => void;
keepMask?: boolean;
waitToUpdateCursor?: boolean;
ref?: React.ForwardedRef<T>;
}) => {
const selectionRef = React.useRef({ start: 0, end: 0 });
const onSelectionChange = React.useCallback(
(event: { nativeEvent: NativeSelectionWrapper }) => {
const selection = event.nativeEvent.selection;
selectionRef.current = selection;
},
[],
);
const getCursorPosition = React.useCallback(() => {
const cursorPosition = selectionRef.current?.start ?? 0;
return cursorPosition;
}, []);
const setCursorPosition = React.useCallback(
(
cursorPosition: number,
el:
| { setNativeProps: (props: NativeSelectionWrapper) => void }
| undefined,
) => {
if (el?.setNativeProps) {
const selection = { start: cursorPosition, end: cursorPosition };
selectionRef.current = selection;
if (waitToUpdateCursor) {
setTimeout(() => {
selectionRef.current = selection;
el.setNativeProps({
selection,
});
}, 20);
} else {
el.setNativeProps({
selection,
});
}
}
},
[waitToUpdateCursor],
);
const { displayValue, setDisplayValue, ref } = useRefMask({
value,
maskGenerator,
getCursorPosition,
setCursorPosition,
onChange,
keepMask,
ref: outerRef,
});
const onChangeText = React.useCallback(
(text: string) => {
const position =
(selectionRef.current?.start ?? 0) +
(text?.length ?? 0) -
(displayValue?.length ?? 0);
const selection = { start: position, end: position };
selectionRef.current = selection;
ref.current?.setNativeProps({ selection });
return setDisplayValue(text);
},
[setDisplayValue, ref, displayValue],
);
return {
value: displayValue,
onChangeText,
onSelectionChange,
ref,
};
};