From c1b05b6a7956b344ff55bc666605e04070872c29 Mon Sep 17 00:00:00 2001 From: Carlos Lalimarmo Date: Sun, 25 Oct 2015 23:16:02 -0400 Subject: [PATCH 1/2] Optionally propagate keydown events so that we can leverage default keydown behaviors provided by the browser, such as tabbing to the next input. The default behavior was the previous behavior, so that this is not a breaking change. --- README.md | 7 +++++++ src/typeahead/index.js | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1e4b842f..e2f33bee 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,13 @@ Default: true If false, the default classNames are removed from the typeahead. +#### props.propagateKeyDownEvents + +Type: `boolean` +Default: false + +If true, allows keyDown events to propagate. This is useful if you want the `tab` key to focus the next element, for example. + #### props.customListComponent Type: `React Component` diff --git a/src/typeahead/index.js b/src/typeahead/index.js index c13d2dd0..2ffb672d 100644 --- a/src/typeahead/index.js +++ b/src/typeahead/index.js @@ -51,6 +51,7 @@ var Typeahead = React.createClass({ React.PropTypes.func ]), defaultClassNames: React.PropTypes.bool, + propagateKeyDownEvents: React.PropTypes.bool, customListComponent: React.PropTypes.oneOfType([ React.PropTypes.element, React.PropTypes.func @@ -75,6 +76,7 @@ var Typeahead = React.createClass({ onBlur: function(event) {}, filterOption: null, defaultClassNames: true, + propagateKeyDownEvents: false, customListComponent: TypeaheadSelector }; }, @@ -279,8 +281,10 @@ var Typeahead = React.createClass({ } else { return this.props.onKeyDown(event); } - // Don't propagate the keystroke back to the DOM/browser - event.preventDefault(); + // By default, don't propagate the keystroke back to the DOM/browser + if (!this.props.propagateKeyDownEvents) { + event.preventDefault(); + } }, componentWillReceiveProps: function(nextProps) { From fd2ce4ddc756f335c5bee47a1787161dee2d3d04 Mon Sep 17 00:00:00 2001 From: Carlos Lalimarmo Date: Sun, 15 Nov 2015 15:13:00 -0500 Subject: [PATCH 2/2] Allow Tokenizer to also propagate keydown events To make this useful for the tokenizer, we also take steps to keep the focus on the tokenizer input, unless the input is empty. We reuse the logic that determines whether "backspace" should clear a token, or do it's default behavior. --- src/tokenizer/index.js | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/tokenizer/index.js b/src/tokenizer/index.js index c931688a..68a98d2e 100644 --- a/src/tokenizer/index.js +++ b/src/tokenizer/index.js @@ -49,7 +49,8 @@ var TypeaheadTokenizer = React.createClass({ React.PropTypes.func ]), maxVisible: React.PropTypes.number, - defaultClassNames: React.PropTypes.bool + defaultClassNames: React.PropTypes.bool, + propagateKeyDownEvents: React.PropTypes.bool }, getInitialState: function() { @@ -78,6 +79,7 @@ var TypeaheadTokenizer = React.createClass({ onBlur: function(event) {}, onTokenAdd: function() {}, onTokenRemove: function() {} + propagateKeyDownEvents: false, }; }, @@ -126,6 +128,10 @@ var TypeaheadTokenizer = React.createClass({ if (event.keyCode === KeyEvent.DOM_VK_BACK_SPACE) { return this._handleBackspace(event); } + // or tabs + if (event.keyCode === KeyEvent.DOM_VK_TAB) { + this._handleTab(event); + } this.props.onKeyDown(event); }, @@ -135,17 +141,29 @@ var TypeaheadTokenizer = React.createClass({ return; } - // Remove token ONLY when bksp pressed at beginning of line - // without a selection - var entry = this.refs.typeahead.refs.entry; - if (entry.selectionStart == entry.selectionEnd && - entry.selectionStart == 0) { + if (this._inputIsEmpty()) { this._removeTokenForValue( this.state.selected[this.state.selected.length - 1]); event.preventDefault(); } }, + _handleTab: function(event) { + // Intercept tab to prevent focusing on next element, unless + // nothing is selected and the input is empty + var entry = this.refs.typeahead.refs.entry; + if (!this._inputIsEmpty()) { + event.preventDefault(); + } + }, + + _inputIsEmpty: function() { + // beginning of line, without a selection + var entry = this.refs.typeahead.refs.entry; + return entry.selectionStart == entry.selectionEnd && + entry.selectionStart == 0; + }, + _removeTokenForValue: function(value) { var index = this.state.selected.indexOf(value); if (index == -1) { @@ -195,7 +213,8 @@ var TypeaheadTokenizer = React.createClass({ onBlur={this.props.onBlur} displayOption={this.props.displayOption} defaultClassNames={this.props.defaultClassNames} - filterOption={this.props.filterOption} /> + filterOption={this.props.filterOption} + propagateKeyDownEvents={this.props.propagateKeyDownEvents} /> ); }