Skip to content

Commit

Permalink
Add onKeyDown to TextField and TextArea
Browse files Browse the repository at this point in the history
  • Loading branch information
jennyscript committed Aug 7, 2018
1 parent 983c75d commit fe93cab
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
### Minor

* Internal: Turn on sketchy-number flow lint rules as an error (#293)
* TextArea: Add an onKeyDown prop
* TextField: Add an onKeyDown prop

### Patch

Expand Down
4 changes: 4 additions & 0 deletions docs/src/TextArea.doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ card(
name: 'onFocus',
type: '({ event: SyntheticFocusEvent<>, value: string }) => void',
},
{
name: 'onKeyDown',
type: '({ event: SyntheticKeyboardEvent<>, value: string }) => void',
},
{
name: 'placeholder',
type: 'string',
Expand Down
4 changes: 4 additions & 0 deletions docs/src/TextField.doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ card(
name: 'onFocus',
type: '({ event: SyntheticFocusEvent<>, value: string }) => void',
},
{
name: 'onKeyDown',
type: '({ event: SyntheticKeyboardEvent<>, value: string }) => void',
},
{
name: 'placeholder',
type: 'string',
Expand Down
12 changes: 12 additions & 0 deletions packages/gestalt/src/TextArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Props = {|
onBlur?: ({ event: SyntheticFocusEvent<>, value: string }) => void,
onChange: ({ event: SyntheticInputEvent<>, value: string }) => void,
onFocus?: ({ event: SyntheticFocusEvent<>, value: string }) => void,
onKeyDown?: ({ event: SyntheticKeyboardEvent<>, value: string }) => void,
placeholder?: string,
rows?: number /* default: 3 */,
value?: string,
Expand All @@ -40,6 +41,7 @@ export default class TextArea extends React.Component<Props, State> {
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
onKeyDown: PropTypes.func,
placeholder: PropTypes.string,
rows: PropTypes.number,
value: PropTypes.string,
Expand Down Expand Up @@ -105,6 +107,15 @@ export default class TextArea extends React.Component<Props, State> {
}
};

handleKeyDown = (event: SyntheticKeyboardEvent<>) => {
if (event.target instanceof HTMLTextAreaElement && this.props.onKeyDown) {
this.props.onKeyDown({
event,
value: event.target.value,
});
}
};

textarea: ?HTMLElement;

render() {
Expand Down Expand Up @@ -140,6 +151,7 @@ export default class TextArea extends React.Component<Props, State> {
onBlur={this.handleBlur}
onChange={this.handleChange}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}
placeholder={placeholder}
ref={c => {
this.textarea = c;
Expand Down
56 changes: 56 additions & 0 deletions packages/gestalt/src/TextArea.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import TextArea from './TextArea.js';
import Flyout from './Flyout.js';

describe('TextArea', () => {
beforeAll(() => {
// Mock this out for the instanceof checks in event handlers
global.HTMLTextAreaElement = Object;
});
it('Renders a Flyout if an error message is passed in', () => {
const wrapper = shallow(
<TextArea errorMessage="test" id="test" onChange={jest.fn()} />
Expand Down Expand Up @@ -81,4 +85,56 @@ describe('TextArea', () => {
});
expect(tree.find(Flyout)).toHaveLength(1);
});

it('handles blur events', () => {
const mockBlur = jest.fn();
const tree = shallow(
<TextArea id="test" onBlur={mockBlur} onChange={jest.fn()} />
);
tree.find('textarea').simulate('blur', { target: { value: 'fake value' } });
expect(mockBlur).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});

it('handles change events', () => {
const mockChange = jest.fn();
const tree = shallow(<TextArea id="test" onChange={mockChange} />);
tree
.find('textarea')
.simulate('change', { target: { value: 'fake value' } });
expect(mockChange).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});

it('handles focus events', () => {
const mockFocus = jest.fn();
const tree = shallow(
<TextArea id="test" onChange={jest.fn()} onFocus={mockFocus} />
);
tree
.find('textarea')
.simulate('focus', { target: { value: 'fake value' } });
expect(mockFocus).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});

it('handles key down events', () => {
const mockKeyDown = jest.fn();
const tree = shallow(
<TextArea id="test" onChange={jest.fn()} onKeyDown={mockKeyDown} />
);
tree
.find('textarea')
.simulate('keyDown', { target: { value: 'fake value' } });
expect(mockKeyDown).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});
});
12 changes: 12 additions & 0 deletions packages/gestalt/src/TextField.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Props = {|
onBlur?: ({ event: SyntheticFocusEvent<>, value: string }) => void,
onChange: ({ event: SyntheticInputEvent<>, value: string }) => void,
onFocus?: ({ event: SyntheticFocusEvent<>, value: string }) => void,
onKeyDown?: ({ event: SyntheticKeyboardEvent<>, value: string }) => void,
placeholder?: string,
type?: 'date' | 'email' | 'number' | 'password' | 'text' | 'url',
value?: string,
Expand All @@ -47,6 +48,7 @@ export default class TextField extends React.Component<Props, State> {
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
onKeyDown: PropTypes.func,
placeholder: PropTypes.string,
type: PropTypes.oneOf([
'date',
Expand Down Expand Up @@ -115,6 +117,15 @@ export default class TextField extends React.Component<Props, State> {
}
};

handleKeyDown = (event: SyntheticKeyboardEvent<>) => {
if (event.target instanceof HTMLInputElement && this.props.onKeyDown) {
this.props.onKeyDown({
event,
value: event.target.value,
});
}
};

textfield: ?HTMLElement;

render() {
Expand Down Expand Up @@ -156,6 +167,7 @@ export default class TextField extends React.Component<Props, State> {
onBlur={this.handleBlur}
onChange={this.handleChange}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}
pattern={pattern}
placeholder={placeholder}
ref={c => {
Expand Down
50 changes: 50 additions & 0 deletions packages/gestalt/src/TextField.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import TextField from './TextField.js';
import Flyout from './Flyout.js';

describe('TextField', () => {
beforeAll(() => {
// Mock this out for the instanceof checks in event handlers
global.HTMLInputElement = Object;
});
it('Renders a Flyout if an error message is passed in', () => {
const wrapper = shallow(
<TextField errorMessage="test" id="test" onChange={jest.fn()} />
Expand Down Expand Up @@ -114,4 +118,50 @@ describe('TextField', () => {
).html();
expect(tree).toMatchSnapshot();
});

it('handles blur events', () => {
const mockBlur = jest.fn();
const tree = shallow(
<TextField id="test" onBlur={mockBlur} onChange={jest.fn()} />
);
tree.find('input').simulate('blur', { target: { value: 'fake value' } });
expect(mockBlur).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});

it('handles change events', () => {
const mockChange = jest.fn();
const tree = shallow(<TextField id="test" onChange={mockChange} />);
tree.find('input').simulate('change', { target: { value: 'fake value' } });
expect(mockChange).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});

it('handles focus events', () => {
const mockFocus = jest.fn();
const tree = shallow(
<TextField id="test" onChange={jest.fn()} onFocus={mockFocus} />
);
tree.find('input').simulate('focus', { target: { value: 'fake value' } });
expect(mockFocus).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});

it('handles key down events', () => {
const mockKeyDown = jest.fn();
const tree = shallow(
<TextField id="test" onChange={jest.fn()} onKeyDown={mockKeyDown} />
);
tree.find('input').simulate('keyDown', { target: { value: 'fake value' } });
expect(mockKeyDown).toHaveBeenCalledWith({
event: { target: { value: 'fake value' } },
value: 'fake value',
});
});
});
2 changes: 2 additions & 0 deletions packages/gestalt/src/__snapshots__/TextArea.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ exports[`TextArea TextArea normal 1`] = `
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
rows={3}
/>
</span>
Expand All @@ -31,6 +32,7 @@ exports[`TextArea TextArea with rows 1`] = `
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
rows={5}
/>
</span>
Expand Down
1 change: 1 addition & 0 deletions packages/gestalt/src/__snapshots__/TextField.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ exports[`TextField TextField normal 1`] = `
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
type="text"
/>
</span>
Expand Down

0 comments on commit fe93cab

Please sign in to comment.