[fix] TextInput onKeyPress and onSubmitEditing events

onKeyPress forwards the synthetic keydown event.
onSubmitEditing is only called if IME composition is not in progress.

Fix #1332
This commit is contained in:
Nicolas Gallagher
2020-05-27 13:53:48 -07:00
parent 52f903229e
commit 0901be6e5c
2 changed files with 52 additions and 39 deletions
@@ -42,6 +42,7 @@ function createKeyboardEvent(
ctrlKey = false,
isComposing = false,
key = '',
keyCode = 0,
metaKey = false,
preventDefault = () => {},
shiftKey = false
@@ -52,6 +53,7 @@ function createKeyboardEvent(
ctrlKey,
isComposing,
key,
keyCode,
metaKey,
preventDefault,
shiftKey
@@ -271,14 +273,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: 'ArrowLeft',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -293,14 +295,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: 'Backspace',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -315,14 +317,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: 'Enter',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -337,14 +339,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: 'Escape',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -359,14 +361,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: ' ',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -381,14 +383,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: 'Tab',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -403,14 +405,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: false,
ctrlKey: false,
key: 'a',
metaKey: false,
shiftKey: false,
target: expect.anything()
}
})
})
);
});
@@ -433,14 +435,14 @@ describe('components/TextInput', () => {
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
nativeEvent: expect.objectContaining({
altKey: true,
ctrlKey: true,
key: ' ',
metaKey: true,
shiftKey: true,
target: expect.anything()
}
})
})
);
});
@@ -500,6 +502,17 @@ describe('components/TextInput', () => {
}
});
test('single-line input while composing', () => {
const onSubmitEditing = jest.fn();
const { container } = render(
<TextInput defaultValue="12345" onSubmitEditing={onSubmitEditing} />
);
const input = findInput(container);
input.dispatchEvent(keydown({ key: 'Enter', isComposing: true, keyCode: 13 }));
input.dispatchEvent(keydown({ key: 'Enter', isComposing: false, keyCode: 229 }));
expect(onSubmitEditing).not.toHaveBeenCalled();
});
test('multi-line input', () => {
const onSubmitEditing = jest.fn();
const { container } = render(
@@ -567,17 +580,15 @@ describe('components/TextInput', () => {
test('set cursor location', () => {
const cursorLocation = { start: 3, end: 3 };
const { container: defaultContainer } = render(<TextInput defaultValue="12345" />);
const { container: customContainer } = render(
<TextInput defaultValue="12345" selection={cursorLocation} />
);
const inputDefaultSelection = findInput(defaultContainer);
const inputCustomSelection = findInput(customContainer);
// default selection is 0
expect(inputDefaultSelection.selectionStart).toEqual(0);
expect(inputDefaultSelection.selectionEnd).toEqual(0);
const { container: customContainer } = render(
<TextInput defaultValue="12345" selection={cursorLocation} />
);
const inputCustomSelection = findInput(customContainer);
// custom selection sets cursor at custom position
expect(inputCustomSelection.selectionStart).toEqual(cursorLocation.start);
expect(inputCustomSelection.selectionEnd).toEqual(cursorLocation.end);
+19 -17
View File
@@ -104,6 +104,12 @@ const forwardPropsList = {
const pickProps = props => pick(props, forwardPropsList);
// If an Input Method Editor is processing key input, the 'keyCode' is 229.
// https://www.w3.org/TR/uievents/#determine-keydown-keyup-keyCode
function isEventComposing(nativeEvent) {
return nativeEvent.isComposing || nativeEvent.keyCode === 229;
}
const TextInput = forwardRef<TextInputProps, *>((props, forwardedRef) => {
const {
autoCapitalize = 'sentences',
@@ -267,31 +273,27 @@ const TextInput = forwardRef<TextInputProps, *>((props, forwardedRef) => {
const blurOnSubmitDefault = !multiline;
const shouldBlurOnSubmit = blurOnSubmit == null ? blurOnSubmitDefault : blurOnSubmit;
if (onKeyPress) {
const keyValue = e.key;
const nativeEvent = e.nativeEvent;
const isComposing = isEventComposing(nativeEvent);
if (keyValue) {
e.nativeEvent = {
altKey: e.altKey,
ctrlKey: e.ctrlKey,
key: keyValue,
metaKey: e.metaKey,
shiftKey: e.shiftKey,
target: e.target
};
onKeyPress(e);
}
if (onKeyPress) {
onKeyPress(e);
}
if (!e.isDefaultPrevented() && e.key === 'Enter' && !e.shiftKey) {
if (
e.key === 'Enter' &&
!e.shiftKey &&
// Do not call submit if composition is occuring.
!isComposing &&
!e.isDefaultPrevented()
) {
if ((blurOnSubmit || !multiline) && onSubmitEditing) {
// prevent "Enter" from inserting a newline
// prevent "Enter" from inserting a newline or submitting a form
e.preventDefault();
e.nativeEvent = { target: e.target, text: e.target.value };
nativeEvent.text = e.target.value;
onSubmitEditing(e);
}
if (shouldBlurOnSubmit && hostRef.current != null) {
// $FlowFixMe
hostRef.current.blur();
}
}