diff --git a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js index 994b6ce7..42bd77ff 100644 --- a/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js +++ b/src/components/LocationAutocompleteInput/LocationAutocompleteInput.js @@ -17,7 +17,7 @@ const DIRECTION_DOWN = 'down'; // Renders the autocompletion prediction results in a list const LocationPredictionsList = props => { - const { predictions, highlightedIndex, onSelectItem } = props; + const { predictions, highlightedIndex, onSelectStart, onSelectEnd } = props; if (predictions.length === 0) { return null; } @@ -30,7 +30,10 @@ const LocationPredictionsList = props => {
  • onSelectItem(index)} + onTouchStart={onSelectStart} + onMouseDown={onSelectStart} + onTouchEnd={() => onSelectEnd(index)} + onMouseUp={() => onSelectEnd(index)} > {prediction.description}
  • @@ -58,7 +61,8 @@ LocationPredictionsList.propTypes = { }) ).isRequired, highlightedIndex: number, - onSelectItem: func.isRequired, + onSelectStart: func.isRequired, + onSelectEnd: func.isRequired, }; // Get the current value with defaults from the given @@ -91,7 +95,7 @@ class LocationAutocompleteInput extends Component { this.state = { inputHasFocus: false, - predictionsHaveHover: false, + selectionInProgress: false, highlightedIndex: -1, // -1 means no highlight }; @@ -100,6 +104,10 @@ class LocationAutocompleteInput extends Component { this.selectItemIfNoneSelected = this.selectItemIfNoneSelected.bind(this); this.onKeyDown = this.onKeyDown.bind(this); this.onChange = this.onChange.bind(this); + this.handleOnBlur = this.handleOnBlur.bind(this); + this.handlePredictionsSelectStart = this.handlePredictionsSelectStart.bind(this); + this.handlePredictionsSelectEnd = this.handlePredictionsSelectEnd.bind(this); + this.finalizeSelection = this.finalizeSelection.bind(this); // Debounce the method to avoid calling the API too many times // when the user is typing fast. @@ -268,9 +276,31 @@ class LocationAutocompleteInput extends Component { }); }); } + + finalizeSelection() { + this.setState({ inputHasFocus: false, highlightedIndex: -1 }); + this.props.input.onBlur(currentValue(this.props)); + } + + handleOnBlur() { + if (!this.state.selectionInProgress) { + this.finalizeSelection(); + } + } + + handlePredictionsSelectStart() { + this.setState({selectionInProgress: true}) + } + + handlePredictionsSelectEnd(index) { + this.setState({selectionInProgress: false}); + this.selectItem(index); + this.finalizeSelection(); + } + render() { const { autoFocus, className, placeholder, input } = this.props; - const { name, onFocus, onBlur } = input; + const { name, onFocus } = input; const { search, predictions } = currentValue(this.props); const handleOnFocus = e => { @@ -278,21 +308,12 @@ class LocationAutocompleteInput extends Component { onFocus(e); }; - const handleOnBlur = () => { - this.setState({ inputHasFocus: false, highlightedIndex: -1 }); - onBlur(currentValue(this.props)); - }; - // Only render predictions when the input has focus. For // development and easier workflow with the browser devtools, you // might want to hardcode this to `true`. Otherwise the dropdown // list will disappear. // - // We also have to check if the predictions have hover to avoid a - // click triggering a blur event that hides the predictions before - // the click event is sent, resulting in a click to whatever is - // rendered below the predictions. - const renderPredictions = this.state.inputHasFocus || this.state.predictionsHaveHover; + const renderPredictions = this.state.inputHasFocus; return (
    @@ -305,21 +326,17 @@ class LocationAutocompleteInput extends Component { name={name} value={search} onFocus={handleOnFocus} - onBlur={handleOnBlur} + onBlur={this.handleOnBlur} onChange={this.onChange} onKeyDown={this.onKeyDown} /> {renderPredictions - ?
    this.setState({ predictionsHaveHover: true })} - onMouseLeave={() => this.setState({ predictionsHaveHover: false })} - > - -
    + ? : null}
    );