[fix] TextInput: call on onKeyPress for Tab and Cmd+Enter

Add support for more key combinations that only fire 'keydown' React DOM
events. And allow users to call 'preventDefault', etc., on the event.

Fix #567
Close #582
This commit is contained in:
Nicolas Gallagher
2017-07-30 19:56:59 -07:00
parent 08ee7c83bb
commit 134114de83
2 changed files with 155 additions and 83 deletions
+126 -66
View File
@@ -109,105 +109,165 @@ describe('components/TextInput', () => {
expect(input.prop('rows')).toEqual(3);
});
test('prop "onBlur"', done => {
test('prop "onBlur"', () => {
const onBlur = jest.fn();
const input = findNativeInput(mount(<TextInput onBlur={onBlur} />));
input.simulate('blur');
function onBlur(e) {
expect(e).toBeTruthy();
done();
}
expect(onBlur).toHaveBeenCalledTimes(1);
});
test('prop "onChange"', done => {
test('prop "onChange"', () => {
const onChange = jest.fn();
const input = findNativeInput(mount(<TextInput onChange={onChange} />));
input.simulate('change');
function onChange(e) {
expect(e).toBeTruthy();
done();
}
expect(onChange).toHaveBeenCalledTimes(1);
});
test('prop "onChangeText"', done => {
test('prop "onChangeText"', () => {
const onChangeText = jest.fn();
const newText = 'newText';
const input = findNativeInput(mount(<TextInput onChangeText={onChangeText} />));
input.simulate('change', { target: { value: newText } });
function onChangeText(text) {
expect(text).toEqual(newText);
done();
}
expect(onChangeText).toHaveBeenCalledTimes(1);
expect(onChangeText).toBeCalledWith(newText);
});
test('prop "onFocus"', done => {
test('prop "onFocus"', () => {
const onFocus = jest.fn();
const input = findNativeInput(mount(<TextInput onFocus={onFocus} />));
input.simulate('focus');
function onFocus(e) {
expect(e).toBeTruthy();
done();
}
expect(onFocus).toHaveBeenCalledTimes(1);
});
describe('prop "onKeyPress"', () => {
test('enter key', done => {
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', { which: 13 });
function onKeyPress(e) {
expect(e.nativeEvent.key).toEqual('Enter');
done();
}
});
test('space key', done => {
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', { which: 32 });
function onKeyPress(e) {
expect(e.nativeEvent.key).toEqual(' ');
done();
}
});
test('backspace key', done => {
test('backspace key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyDown', { which: 8 });
function onKeyPress(e) {
expect(e.nativeEvent.key).toEqual('Backspace');
done();
}
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: undefined,
ctrlKey: undefined,
key: 'Backspace',
metaKey: undefined,
shiftKey: undefined,
target: expect.anything()
}
})
);
});
test('text key', done => {
test('tab key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyDown', { which: 9 });
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: undefined,
ctrlKey: undefined,
key: 'Tab',
metaKey: undefined,
shiftKey: undefined,
target: expect.anything()
}
})
);
});
test('enter key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', { which: 13 });
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: undefined,
ctrlKey: undefined,
key: 'Enter',
metaKey: undefined,
shiftKey: undefined,
target: expect.anything()
}
})
);
});
test('space key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', { which: 32 });
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: undefined,
ctrlKey: undefined,
key: ' ',
metaKey: undefined,
shiftKey: undefined,
target: expect.anything()
}
})
);
});
test('text key', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', { which: 97 });
function onKeyPress(e) {
expect(e.nativeEvent.key).toEqual('a');
done();
}
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: undefined,
ctrlKey: undefined,
key: 'a',
metaKey: undefined,
shiftKey: undefined,
target: expect.anything()
}
})
);
});
test('target element is included', done => {
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress');
function onKeyPress(e) {
expect(e.nativeEvent.target).toBeDefined();
done();
}
});
test('modifier keys are included', done => {
test('modifier keys are included', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyPress', {
altKey: true,
ctrlKey: true,
metaKey: true,
shiftKey: true,
which: 97
which: 32
});
function onKeyPress(e) {
expect(e.nativeEvent.altKey).toEqual(true);
expect(e.nativeEvent.ctrlKey).toEqual(true);
expect(e.nativeEvent.metaKey).toEqual(true);
expect(e.nativeEvent.shiftKey).toEqual(true);
done();
}
expect(onKeyPress).toHaveBeenCalledTimes(1);
expect(onKeyPress).toBeCalledWith(
expect.objectContaining({
nativeEvent: {
altKey: true,
ctrlKey: true,
key: ' ',
metaKey: true,
shiftKey: true,
target: expect.anything()
}
})
);
});
test('meta key + Enter calls "onKeyPress"', () => {
const onKeyPress = jest.fn();
const input = findNativeInput(mount(<TextInput onKeyPress={onKeyPress} />));
input.simulate('keyDown', {
metaKey: true,
which: 13
});
expect(onKeyPress).toHaveBeenCalledTimes(1);
});
});
+29 -17
View File
@@ -301,9 +301,9 @@ class TextInput extends Component {
};
_handleKeyDown = e => {
const { onKeyPress } = this.props;
if (onKeyPress && e.which === 8) {
onKeyPress({ nativeEvent: { key: 'Backspace' } });
// Backspace, Tab, and Cmd+Enter only fire 'keydown' DOM events
if (e.which === 8 || e.which === 9 || (e.which === 13 && e.metaKey)) {
this._handleKeyPress(e);
}
};
@@ -314,23 +314,35 @@ class TextInput extends Component {
if (onKeyPress) {
let keyValue;
// enter
if (e.which === 13) {
keyValue = 'Enter';
} else if (e.which === 32) {
// space
keyValue = ' ';
} else {
// we trim to only care about the keys that has a textual representation
if (e.shiftKey) {
keyValue = String.fromCharCode(e.which).trim();
} else {
keyValue = String.fromCharCode(e.which).toLowerCase().trim();
switch (e.which) {
// backspace
case 8:
keyValue = 'Backspace';
break;
// tab
case 9:
keyValue = 'Tab';
break;
// enter
case 13:
keyValue = 'Enter';
break;
// spacebar
case 32:
keyValue = ' ';
break;
default: {
// we trim to only care about the keys that has a textual representation
if (e.shiftKey) {
keyValue = String.fromCharCode(e.which).trim();
} else {
keyValue = String.fromCharCode(e.which).toLowerCase().trim();
}
}
}
if (keyValue) {
const nativeEvent = {
e.nativeEvent = {
altKey: e.altKey,
ctrlKey: e.ctrlKey,
key: keyValue,
@@ -338,7 +350,7 @@ class TextInput extends Component {
shiftKey: e.shiftKey,
target: e.target
};
onKeyPress({ nativeEvent });
onKeyPress(e);
}
}