Skip to content

Commit 88197c3

Browse files
fix: preserve spaces in rawText when no mask is set (#317)
1 parent 9e72787 commit 88197c3

File tree

2 files changed

+92
-23
lines changed

2 files changed

+92
-23
lines changed

src/components/MaskedTextInput.test.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,39 @@ describe('<MaskedTextInput />', () => {
1414
expect(container).toMatchSnapshot();
1515
})
1616

17+
test('should preserve spaces in rawText when no mask is provided', async () => {
18+
const onChangeTextMock = jest.fn();
19+
const container = render(
20+
<MaskedTextInput
21+
onChangeText={onChangeTextMock}
22+
testID="masked-text-input"
23+
/>
24+
);
25+
26+
fireEvent.changeText(container.getByTestId('masked-text-input'), 'test test')
27+
28+
await waitFor(() => {
29+
expect(onChangeTextMock).toHaveBeenCalledWith('test test', 'test test')
30+
})
31+
})
32+
33+
test('should remove spaces in rawText when mask is provided', async () => {
34+
const onChangeTextMock = jest.fn();
35+
const container = render(
36+
<MaskedTextInput
37+
mask="AAA-999"
38+
onChangeText={onChangeTextMock}
39+
testID="masked-text-input"
40+
/>
41+
);
42+
43+
fireEvent.changeText(container.getByTestId('masked-text-input'), 'ABC 123')
44+
45+
await waitFor(() => {
46+
expect(onChangeTextMock).toHaveBeenCalledWith('ABC-123', 'ABC123')
47+
})
48+
})
49+
1750
test('should renders correctly with custom mask', () => {
1851
const container = render(
1952
<MaskedTextInput mask="AAA-999" onChangeText={mockedOnChangeText} />,

src/components/MaskedTextInput.tsx

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,38 +52,62 @@ export const MaskedTextInputComponent: ForwardRefRenderFunction<
5252
},
5353
style
5454
]
55+
56+
const isMasked = () => pattern || type === 'currency'
57+
5558
const getMaskedValue = (value: string) =>
5659
mask(value, pattern, type, options, autoCapitalize)
60+
5761
const getUnMaskedValue = (value: string) =>
5862
unMask(value, type as 'custom' | 'currency')
5963

64+
const updateStatesWithMasking = (inputValue: string) => {
65+
const newUnMaskedValue = getUnMaskedValue(inputValue)
66+
const newMaskedValue = getMaskedValue(newUnMaskedValue)
67+
68+
setMaskedValue(newMaskedValue)
69+
setUnmaskedValue(newUnMaskedValue)
70+
setRawValue(inputValue)
71+
}
72+
73+
const updateStatesWithoutMasking = (inputValue: string) => {
74+
setMaskedValue(inputValue)
75+
setUnmaskedValue(inputValue)
76+
setRawValue(inputValue)
77+
}
78+
79+
const clearAllStates = () => {
80+
setMaskedValue('')
81+
setUnmaskedValue('')
82+
setRawValue('')
83+
}
84+
6085
const defaultValueCustom = defaultValue || ''
6186
const defaultValueCurrency = defaultValue || '0'
87+
const initialRawValue = value
6288

63-
const initialRawValue = value;
89+
const initialMaskedValue = isMasked()
90+
? getMaskedValue(type === 'currency' ? defaultValueCurrency : defaultValueCustom)
91+
: (value || defaultValueCustom)
6492

65-
const initialMaskedValue = getMaskedValue(
66-
type === 'currency' ? defaultValueCurrency : defaultValueCustom
67-
)
68-
69-
const initialUnMaskedValue = getUnMaskedValue(
70-
type === 'currency' ? defaultValueCurrency : defaultValueCustom
71-
)
93+
const initialUnMaskedValue = isMasked()
94+
? getUnMaskedValue(type === 'currency' ? defaultValueCurrency : defaultValueCustom)
95+
: (value || defaultValueCustom)
7296

7397
const [maskedValue, setMaskedValue] = useState(initialMaskedValue)
7498
const [unMaskedValue, setUnmaskedValue] = useState(initialUnMaskedValue)
75-
const [rawValue, setRawValue] = useState(initialRawValue);
99+
const [rawValue, setRawValue] = useState(initialRawValue)
76100
const [isInitialRender, setIsInitialRender] = useState(true)
77101

78-
const actualValue = pattern || type === "currency" ? maskedValue : rawValue;
102+
const actualValue = isMasked() ? maskedValue : rawValue
79103

80-
function onChange(value: string) {
81-
const newUnMaskedValue = unMask(value, type as 'custom' | 'currency')
82-
const newMaskedValue = mask(newUnMaskedValue, pattern, type, options)
83104

84-
setMaskedValue(newMaskedValue)
85-
setUnmaskedValue(newUnMaskedValue)
86-
setRawValue(value);
105+
const handleChange = (inputValue: string) => {
106+
if (isMasked()) {
107+
updateStatesWithMasking(inputValue)
108+
} else {
109+
updateStatesWithoutMasking(inputValue)
110+
}
87111
}
88112

89113
useEffect(() => {
@@ -92,23 +116,35 @@ export const MaskedTextInputComponent: ForwardRefRenderFunction<
92116
return
93117
}
94118

95-
onChangeText(maskedValue, unMaskedValue)
96-
}, [maskedValue, unMaskedValue])
119+
if (isMasked()) {
120+
onChangeText(maskedValue, unMaskedValue)
121+
} else {
122+
onChangeText(rawValue || '', rawValue || '')
123+
}
124+
}, [maskedValue, unMaskedValue, rawValue])
97125

98126
useEffect(() => {
99127
if (value) {
100-
setMaskedValue(getMaskedValue(value))
101-
setUnmaskedValue(getUnMaskedValue(value))
128+
if (isMasked()) {
129+
setMaskedValue(getMaskedValue(value))
130+
setUnmaskedValue(getUnMaskedValue(value))
131+
} else {
132+
updateStatesWithoutMasking(value)
133+
}
102134
} else {
103-
setMaskedValue(initialMaskedValue)
104-
setUnmaskedValue(initialUnMaskedValue)
135+
if (isMasked()) {
136+
setMaskedValue(initialMaskedValue)
137+
setUnmaskedValue(initialUnMaskedValue)
138+
} else {
139+
clearAllStates()
140+
}
105141
}
106142
}, [value])
107143

108144
return (
109145
<>
110146
<TextInput
111-
onChangeText={(value) => onChange(value)}
147+
onChangeText={handleChange}
112148
ref={ref}
113149
maxLength={pattern.length || undefined}
114150
autoCapitalize={autoCapitalize}

0 commit comments

Comments
 (0)