Closed tonyspb closed 1 year ago
@tonyspb That's a case that I considered, although it's not so simple to fix.
The first point is that the mask algoritm receives a value and applies a mask to it, so if you had:
+63(900) 000-00-00
Considering the mask generator as:
const maskGenerator: MaskGenerator = {
generateMask: () => '+63(9NN) NNN-NN-NN',
rules: new Map([['N', /\d/]]),
};
If with the cursor at the start of the input field you write 1
, it changes to:
1+63(900) 000-00-00
The mask tries to use the character as a static mask char if it's the same, otherwise it will place it at the 1st dynamic position it finds, if it satisfies the rule, or discard it otherwise.
So in steps it will become:
// pending: 1+63(900) 000-00-00
+ // pending: 1+63(900) 000-00-00
+6 // pending: 1+63(900) 000-00-00
+63 // pending: 1+63(900) 000-00-00
+63( // pending: 1+63(900) 000-00-00
+63(9 // pending: 1+63(900) 000-00-00
+63(91 // pending: +63(900) 000-00-00
+63(91 // pending: 63(900) 000-00-00
+63(916 // pending: 3(900) 000-00-00
+63(916) // pending: 3(900) 000-00-00
+63(916) // pending: 3(900) 000-00-00
+63(916) 3 // pending: (900) 000-00-00
+63(916) 3 // pending: 900) 000-00-00
+63(916) 39 // pending: 00) 000-00-00
+63(916) 390 // pending: 0) 000-00-00
+63(916) 390- // pending: 0) 000-00-00
+63(916) 390-0 // pending: ) 000-00-00
+63(916) 390-0 // pending: 000-00-00
+63(916) 390-0 // pending: 000-00-00
+63(916) 390-00 // pending: 00-00-00
+63(916) 390-00- // pending: 00-00-00
+63(916) 390-00-0 // pending: 0-00-00
+63(916) 390-00-00 // pending: -00-00
(discards -00-00 due to overflow)
You can see that the mask algoritm does not know that you entered 1
, nor does it know that the chars after 1
were previous static mask chars.
It actually isn't the responsibility of the algorithm that applies the mask to know that (although the algorithm that defines the cursor position may need to know). Actually, the mask algorithm itself can be applied isolately, outside an input, as:
import { mask } from 'react-hook-mask';
const value = '12345678901';
const Component = () => (
<div>
<div>Value: {value}</div>
<div>Masked: {mask(value, maskGenerator)}</div>
</div>
);
You can see in the example above that the mask function only knows the value in which apply the mask, and the mask generator, not how the value was before or new input chars (if there's any, or anything of the sort).
This doesn't mean that nothing should be done in the example you posted, but if something is done, it should be before the mask algorithm is called.
One easy way to solve it is to set the cursor after the static chars when the input is focused, or it changes position, although it might need some boilerplate, and could not be a good user experience.
Another possibility is to verify if the chars after the cursor position, before the changes were applies, are equal to the starting static chars. This will not work if you type a digit in the middle of the static chars, tough. For example, +613(900) 000-00-00
has +6
before and 3(9
after, and to determine that these chars were previous static chars might not be easy.
One thing that is known before applying the mask is the cursor position, for example: +61|3(900) 000-00-00
(the cursor represented by |
). I can take the starting static chars in the mask +63(9
and test if it's equal to the next chars after the cursor, which isn't, and then remove the 1st char (+
), verify if this is the 1st char of the new value (it is) and test the remaining static chars 63(9
, which does not satisfies, then the next char (6
), verify that it's the 2nd char in the new value, and test the remaining static chars 3(9
and so on and on until it there's no remaining char (in which case it does not do anything).
In the case above, it would determine that the new value starts with +6
and that after the cursor there is 3)9
, so it will discard 3)9
of the new value, changing +613(900) 000-00-00
to +6100) 000-00-00
and correctly becoming +63(910) 000-00-00
after the mask is applied.
This will also work in your case: 1+63(900) 000-00-00
becomes 100) 000-00-00
and after the mask is applied becomes +63(910) 000-00-00
.
It will also work with pasted chars, for example, if instead of just typing 1
, you paste 147
in the middle of the static chars: +61473(900) 000-00-00
becomes +614700) 000-00-00
and then +63(914) 700-00-00
.
This won't work when the static chars are in the middle of the mask, tough, as opposed to your example in which they are in the beginning (but these cases should be rare, and might not be needed). For example, the mask NNN-123-NNN
would still behave as of today, but I don't think it will be a problem.
The above logic should work, but I need to implement it and see if it really woks. Probably, the changes should be done in the function:
I can't say exactly when I will implement it, I'm open to PRs.
thanks for detailed reply I will try to implement something
Ok, I should give it a try in a week or two to see if I can solve it.
@tonyspb I released a new version (1.1.16) that should have this issue fixed. I will close the issue, but feel free to give any feedback here, or reopen this issue if it was not solved.
thanks, works fine 👍🏻
btw, there is no need in react-scripts@^5.0.1 peer deps
@tonyspb I removed the peer dependency, but I don't see the need of a new version just for that. When I release a newer version, it will not have the peer dependency anymore (there's no ETA for that though).
inserting a digit between static mask digits causes inserting all static mask digits after the inserted one
set all
0
's to have value as +639000000000insert
1
as first digit before static mask and we get value as +639163900000