๐ - Plugins, that set value into input don't call onInput in React
aktanoff opened this issue ยท 8 comments
Which package(s) are the source of the bug?
@maskito/kit
Playground Link
Description
Leading zero plugin and others doesn't work on blur, it sets the value, but this change don't fire in React's syntheticevent handler onInput
, and value in state and value in input become different.
By little research i found out that it's because bubbles
sets to false by default, and react don't handle events like this.
I've made a little example of how this works without maskito (just with react and dispatchEvent)
https://codesandbox.io/p/sandbox/pensive-shamir?file=%2Fsrc%2FApp.tsx%3A47%2C40
You can click here on buttons and it will dispatch events with and without bubbles parameter.
And example of how this works with maskito
https://stackblitz.com/edit/stackblitz-starters-chezz9?description=React%20%20%20TypeScript%20starter%20project&file=src%2FApp.tsx&title=React%20Starter
- Open link
- Type '000123'
- Blur input somehow
Expected:
Value above input is '123'
Actual:
Value above input is '000 123'
To fix you can just add bubbles: true
in plugins dispatchEvents
For example here https://github.com/taiga-family/maskito/blob/main/projects/kit/src/lib/masks/number/plugins/leading-zeroes-validation.plugin.ts#L35C29-L35C29
Maskito version
1.9.0
Which browsers have you used?
- Chrome
- Firefox
- Safari
- Edge
Which operating systems have you used?
- macOS
- Windows
- Linux
- iOS
- Android
@aktanoff
Thanks for your research!
I think we can create utility maskitoUpdateValue
(@maskito/kit
)
export function maskitoUpdateValue(
element: HTMLInputElement | HTMLTextAreaElement,
value: string,
): void {
element.value = value;
element.dispatchEvent(
new Event(
'input',
/**
* Good explanation why we need it
*/
{bubbles: true},
),
);
}
And use it everywhere inside all plugins.
@aktanoff Do you want to contribute to our project ?
maskitoUpdateValue
or maskitoSetElementValue
? ๐ค
UPDATE: i think that the second option is better
What do you think ?
@nsbarsukov,
thanks for answer!
yeah, i can contribute, but did i got it right?
we need to write the utility, export it outside of the package, and replace with it all dispatchEvents
calls in @maskito/kit
plugins?
we need to write the utility, export it outside of the package, and replace with it all dispatchEvents calls in @maskito/kit plugins?
@aktanoff yep, all's right)
I will really appreciate if you also add a simple unit test for react package (inside this folder) for this case. But it is optional, if you will have enough time for it.
I forgot that @maskito/core
also contains a single built-in plugin maskitoInitialCalibrationPlugin
with the same behaviour:
maskito/projects/core/src/lib/utils/initial-calibration-plugin.ts
Lines 11 to 12 in 2d807c3
Let's put utility maskitoSetElementValue
inside @maskito/core
package.
maskitoUpdateValue
ormaskitoSetElementValue
? ๐คUPDATE: i think that the second option is better
What do you think ?
I like maskitoUpdateValue
better, since it does not just set value but updates everybody through event. And also it is shorter, 4 words seem too long to me :)
I like
maskitoUpdateValue
better, since it does not just set value but updates everybody through event. And also it is shorter, 4 words seem too long to me :)
I agree that maskitoSetElementValue
is too long.
However, maskitoUpdateValue
is not enough descriptive โ it is not obvious that it updates native element value (and not internal Maskito
's value or something else).
I have one more proposal โ maskitoUpdateElement
:
import {ElementState} from '../types';
export function maskitoUpdateElement(
element: HTMLInputElement | HTMLTextAreaElement,
valueOrElementState: ElementState | string,
): void {
if (typeof valueOrElementState === 'string') {
element.value = valueOrElementState;
} else {
const [from, to] = valueOrElementState.selection;
element.value = valueOrElementState.value;
element.setSelectionRange?.(from, to);
}
element.dispatchEvent(
new Event(
'input',
/**
* Good explanation why we need it
*/
{bubbles: true},
),
);
}
For example, we can use it here:
maskito/projects/core/src/lib/utils/initial-calibration-plugin.ts
Lines 11 to 13 in 39228de
maskitoUpdateElement(element, {
value: maskitoTransform(element.value, customOptions || options),
selection: [from, to],
});
@waterplea @aktanoff what do you think about it ?
maskitoUpdateElement
+1