From 0ff02999ff1ac70a0d3e2a429af8923d7c01d228 Mon Sep 17 00:00:00 2001 From: cburbank Date: Mon, 2 Jan 2017 21:20:41 -0500 Subject: [PATCH] feat(input): Allow custom input element Allow passing custom input component as child of PlacesAutocomplete. --- README.md | 25 +++++++++++++++++++++++++ src/PlacesAutocomplete.js | 37 +++++++++++++++++++++++++++---------- src/tests/index.spec.js | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f50776f5..e23b3c11 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,31 @@ export default SimpleForm ### Props for `PlacesAutocomplete` +#### children +Type: `Element` +Required: `false` + +You can add autocomplete functionality to an existing input element by wrapping it in ``. +The wrapper will pass `onChange`, `onKeyDown`, and `value` props down to the child component. + +```js +// custom input element example +import MyCustomInput from 'my-custom-input' + +... + +render() { + return ( + + + + ) +} +``` + #### value Type: `String`, Required: `true` diff --git a/src/PlacesAutocomplete.js b/src/PlacesAutocomplete.js index 9b2d2195..22565276 100644 --- a/src/PlacesAutocomplete.js +++ b/src/PlacesAutocomplete.js @@ -202,24 +202,40 @@ class PlacesAutocomplete extends React.Component { ) } + renderCustomInput() { + const { children, value } = this.props + return React.cloneElement(children, { + onChange: this.handleInputChange, + onKeyDown: this.handleInputKeyDown, + value + }) + } + + renderDefaultInput() { + const { classNames, placeholder, styles, value } = this.props + return ( + + ) + } + // TODO: remove `classNames.container` in the next version release. render() { - const { classNames, placeholder, styles, value } = this.props + const { classNames, children, styles } = this.props return (
{this.renderLabel()} - + {children ? this.renderCustomInput() : this.renderDefaultInput()} {this.renderOverlay()} {this.renderAutocomplete()}
@@ -228,6 +244,7 @@ class PlacesAutocomplete extends React.Component { } PlacesAutocomplete.propTypes = { + children: React.PropTypes.element, value: React.PropTypes.string.isRequired, onChange: React.PropTypes.func.isRequired, onSelect: React.PropTypes.func, diff --git a/src/tests/index.spec.js b/src/tests/index.spec.js index 973dfe59..18fc64fd 100644 --- a/src/tests/index.spec.js +++ b/src/tests/index.spec.js @@ -193,6 +193,39 @@ describe('AutocompletionRequest options', () => { }) }) +describe('custom input component', () => { + it('renders a custom input component passed as a child', () => { + const wrapper = shallow( {}}> {}}/>) + expect(wrapper.find('.test-input')).to.have.length(1) + }) + + it('adds the correct props to the child component', () => { + const wrapper = shallow( {}}>) + expect(wrapper.find('.test-input').props().onChange).to.be.defined + expect(wrapper.find('.test-input').props().onKeyDown).to.be.defined + expect(wrapper.find('.test-input').props().value).to.be.defined + }) + + it('correctly sets the value prop of the custom input component', () => { + const wrapper = shallow( {}}> {}}/>) + expect(wrapper.find('.test-input').props().value).to.equal('LA') + }) + + it('executes the onChange callback when the custom input is changed', () => { + const spy = sinon.spy() + const wrapper = shallow() + wrapper.find('.test-input').simulate('change', { target: { value: null } }) + expect(spy.calledOnce).to.equal(true) + }) + + it('executes handleInputKeyDown when a keyDown event happens on the custom input', () => { + const spy = sinon.spy(PlacesAutocomplete.prototype, 'handleInputKeyDown') + const wrapper = shallow( {}}>) + wrapper.find('.test-input').simulate('keyDown', { keyCode: null }) + expect(spy.calledOnce).to.equal(true) + }) +}) + // TODO: test geocodeByAddress function describe('geocodeByAddress', () => { it('should be true', () => {