Skip to content

Commit

Permalink
Keep entered text when pressing Escape.
Browse files Browse the repository at this point in the history
  • Loading branch information
afercia committed Jul 25, 2018
1 parent 2242484 commit c6feb24
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 12 deletions.
30 changes: 21 additions & 9 deletions packages/components/src/form-token-field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const initialState = {
isExpanded: false,
selectedSuggestionIndex: -1,
selectedSuggestionScroll: false,
showSuggestions: false,
};

class FormTokenField extends Component {
Expand Down Expand Up @@ -133,7 +134,7 @@ class FormTokenField extends Component {
}
break;
case ESCAPE:
preventDefault = this.handleEscapeKey();
preventDefault = this.handleEscapeKey( event );
event.stopPropagation();
break;
default:
Expand Down Expand Up @@ -193,6 +194,9 @@ class FormTokenField extends Component {
const separator = this.props.tokenizeOnSpace ? /[ ,\t]+/ : /[,\t]+/;
const items = text.split( separator );
const tokenValue = last( items ) || '';
const inputHasMinimumChars = tokenValue.trim().length > 1;
const matchingSuggestions = this.getMatchingSuggestions( tokenValue );
const hasVisibleSuggestions = inputHasMinimumChars && !! matchingSuggestions.length;

if ( items.length > 1 ) {
this.addNewTokens( items.slice( 0, -1 ) );
Expand All @@ -203,15 +207,16 @@ class FormTokenField extends Component {
selectedSuggestionIndex: -1,
selectedSuggestionScroll: false,
isExpanded: false,
showSuggestions: false,
} );

this.props.onInputChange( tokenValue );

const inputHasMinimumChars = tokenValue.trim().length > 1;
if ( inputHasMinimumChars ) {
const matchingSuggestions = this.getMatchingSuggestions( tokenValue );

this.setState( { isExpanded: !! matchingSuggestions.length } );
this.setState( {
isExpanded: hasVisibleSuggestions,
showSuggestions: hasVisibleSuggestions,
} );

if ( !! matchingSuggestions.length ) {
this.props.debouncedSpeak( sprintf( _n(
Expand Down Expand Up @@ -289,8 +294,14 @@ class FormTokenField extends Component {
return true; // preventDefault
}

handleEscapeKey() {
this.setState( initialState );
handleEscapeKey( event ) {
this.setState( {
incompleteTokenValue: event.target.value,
isExpanded: false,
selectedSuggestionIndex: -1,
selectedSuggestionScroll: false,
showSuggestions: false,
} );
return true; // preventDefault
}

Expand Down Expand Up @@ -379,6 +390,8 @@ class FormTokenField extends Component {
incompleteTokenValue: '',
selectedSuggestionIndex: -1,
selectedSuggestionScroll: false,
isExpanded: false,
showSuggestions: false,
} );

if ( this.state.isActive ) {
Expand Down Expand Up @@ -527,6 +540,7 @@ class FormTokenField extends Component {
instanceId,
className,
} = this.props;
const { showSuggestions } = this.state;
const classes = classnames( className, 'components-form-token-field', {
'is-active': this.state.isActive,
'is-disabled': disabled,
Expand All @@ -537,8 +551,6 @@ class FormTokenField extends Component {
tabIndex: '-1',
};
const matchingSuggestions = this.getMatchingSuggestions();
const inputHasMinimumChars = this.state.incompleteTokenValue.trim().length > 1;
const showSuggestions = inputHasMinimumChars && !! matchingSuggestions.length;

if ( ! disabled ) {
tokenFieldProps = Object.assign( {}, tokenFieldProps, {
Expand Down
24 changes: 22 additions & 2 deletions packages/components/src/form-token-field/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,16 @@ describe( 'FormTokenField', function() {

describe( 'displaying tokens', function() {
it( 'should render default tokens', function() {
wrapper.setState( {
showSuggestions: true,
} );
expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
} );

it( 'should display tokens with escaped special characters properly', function() {
wrapper.setState( {
tokens: fixtures.specialTokens.textEscaped,
showSuggestions: true,
} );
expect( getTokensHTML() ).toEqual( fixtures.specialTokens.htmlEscaped );
} );
Expand All @@ -137,13 +141,17 @@ describe( 'FormTokenField', function() {
// through unescaped to the HTML.
wrapper.setState( {
tokens: fixtures.specialTokens.textUnescaped,
showSuggestions: true,
} );
expect( getTokensHTML() ).toEqual( fixtures.specialTokens.htmlUnescaped );
} );
} );

describe( 'suggestions', function() {
it( 'should not render suggestions unless we type at least two characters', function() {
wrapper.setState( {
showSuggestions: true,
} );
expect( getSuggestionsText() ).toEqual( [] );
setText( 'th' );
expect( getSuggestionsText() ).toEqual( fixtures.matchingSuggestions.th );
Expand All @@ -157,40 +165,52 @@ describe( 'FormTokenField', function() {
} );

it( 'suggestions that begin with match are boosted', function() {
wrapper.setState( {
showSuggestions: true,
} );
setText( 'so' );
expect( getSuggestionsText() ).toEqual( fixtures.matchingSuggestions.so );
} );

it( 'should match against the unescaped values of suggestions with special characters', function() {
setText( '& S' );
wrapper.setState( {
tokenSuggestions: fixtures.specialSuggestions.textUnescaped,
showSuggestions: true,
} );
setText( '& S' );
expect( getSuggestionsText() ).toEqual( fixtures.specialSuggestions.matchAmpersandUnescaped );
} );

it( 'should match against the unescaped values of suggestions with special characters (including spaces)', function() {
setText( 's &' );
wrapper.setState( {
tokenSuggestions: fixtures.specialSuggestions.textUnescaped,
showSuggestions: true,
} );
setText( 's &' );
expect( getSuggestionsText() ).toEqual( fixtures.specialSuggestions.matchAmpersandSequence );
} );

it( 'should not match against the escaped values of suggestions with special characters', function() {
setText( 'amp' );
wrapper.setState( {
tokenSuggestions: fixtures.specialSuggestions.textUnescaped,
showSuggestions: true,
} );
expect( getSuggestionsText() ).toEqual( fixtures.specialSuggestions.matchAmpersandEscaped );
} );

it( 'should match suggestions even with trailing spaces', function() {
wrapper.setState( {
showSuggestions: true,
} );
setText( ' at ' );
expect( getSuggestionsText() ).toEqual( fixtures.matchingSuggestions.at );
} );

it( 'should manage the selected suggestion based on both keyboard and mouse events', function() {
wrapper.setState( {
showSuggestions: true,
} );
setText( 'th' );
expect( getSuggestionsText() ).toEqual( fixtures.matchingSuggestions.th );
expect( getSelectedSuggestion() ).toBe( null );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ class TokenFieldWrapper extends Component {
this.state = {
tokenSuggestions: suggestions,
tokens: Object.freeze( [ 'foo', 'bar' ] ),
showSuggestions: false,
};
this.onTokensChange = this.onTokensChange.bind( this );
}

render() {
return (
<TokenField
suggestions={ this.state.tokenSuggestions }
suggestions={ this.state.showSuggestions ? this.state.tokenSuggestions : null }
value={ this.state.tokens }
displayTransform={ unescapeAndFormatSpaces }
onChange={ this.onTokensChange }
Expand Down

0 comments on commit c6feb24

Please sign in to comment.