Merge pull request #2966 from npny/npny/autocomplete-arrow-keys

Allow arrow keys navigation in autocomplete list
This commit is contained in:
Bruno Windels 2019-06-13 15:38:36 +00:00 committed by GitHub
commit 48f5cf1523
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 60 deletions

View file

@ -171,26 +171,13 @@ export default class Autocomplete extends React.Component {
} }
// called from MessageComposerInput // called from MessageComposerInput
onUpArrow(): ?Completion { moveSelection(delta): ?Completion {
const completionCount = this.countCompletions(); const completionCount = this.countCompletions();
// completionCount + 1, since 0 means composer is selected if (completionCount === 0) return; // there are no items to move the selection through
const selectionOffset = (completionCount + 1 + this.state.selectionOffset - 1)
% (completionCount + 1);
if (!completionCount) {
return null;
}
this.setSelection(selectionOffset);
}
// called from MessageComposerInput // Note: selectionOffset 0 represents the unsubstituted text, while 1 means first pill selected
onDownArrow(): ?Completion { const index = (this.state.selectionOffset + delta + completionCount + 1) % (completionCount + 1);
const completionCount = this.countCompletions(); this.setSelection(index);
// completionCount + 1, since 0 means composer is selected
const selectionOffset = (this.state.selectionOffset + 1) % (completionCount + 1);
if (!completionCount) {
return null;
}
this.setSelection(selectionOffset);
} }
onEscape(e): boolean { onEscape(e): boolean {

View file

@ -673,6 +673,31 @@ export default class MessageComposerInput extends React.Component {
onKeyDown = (ev: KeyboardEvent, change: Change, editor: Editor) => { onKeyDown = (ev: KeyboardEvent, change: Change, editor: Editor) => {
this.suppressAutoComplete = false; this.suppressAutoComplete = false;
this.direction = '';
// Navigate autocomplete list with arrow keys
if (this.autocomplete.countCompletions() > 0) {
if (!(ev.ctrlKey || ev.shiftKey || ev.altKey || ev.metaKey)) {
switch (ev.keyCode) {
case KeyCode.LEFT:
this.autocomplete.moveSelection(-1);
ev.preventDefault();
return true;
case KeyCode.RIGHT:
this.autocomplete.moveSelection(+1);
ev.preventDefault();
return true;
case KeyCode.UP:
this.autocomplete.moveSelection(-1);
ev.preventDefault();
return true;
case KeyCode.DOWN:
this.autocomplete.moveSelection(+1);
ev.preventDefault();
return true;
}
}
}
// skip void nodes - see // skip void nodes - see
// https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095 // https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095
@ -680,8 +705,6 @@ export default class MessageComposerInput extends React.Component {
this.direction = 'Previous'; this.direction = 'Previous';
} else if (ev.keyCode === KeyCode.RIGHT) { } else if (ev.keyCode === KeyCode.RIGHT) {
this.direction = 'Next'; this.direction = 'Next';
} else {
this.direction = '';
} }
switch (ev.keyCode) { switch (ev.keyCode) {
@ -1175,12 +1198,9 @@ export default class MessageComposerInput extends React.Component {
}; };
onVerticalArrow = (e, up) => { onVerticalArrow = (e, up) => {
if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) { if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) return;
return;
}
// Select history only if we are not currently auto-completing // Select history
if (this.autocomplete.state.completionList.length === 0) {
const selection = this.state.editorState.selection; const selection = this.state.editorState.selection;
// selection must be collapsed // selection must be collapsed
@ -1201,10 +1221,6 @@ export default class MessageComposerInput extends React.Component {
}); });
} }
} }
} else {
this.moveAutocompleteSelection(up);
e.preventDefault();
}
}; };
onTab = async (e) => { onTab = async (e) => {
@ -1212,23 +1228,19 @@ export default class MessageComposerInput extends React.Component {
someCompletions: null, someCompletions: null,
}); });
e.preventDefault(); e.preventDefault();
if (this.autocomplete.state.completionList.length === 0) { if (this.autocomplete.countCompletions() === 0) {
// Force completions to show for the text currently entered // Force completions to show for the text currently entered
const completionCount = await this.autocomplete.forceComplete(); const completionCount = await this.autocomplete.forceComplete();
this.setState({ this.setState({
someCompletions: completionCount > 0, someCompletions: completionCount > 0,
}); });
// Select the first item by moving "down" // Select the first item by moving "down"
await this.moveAutocompleteSelection(false); await this.autocomplete.moveSelection(+1);
} else { } else {
await this.moveAutocompleteSelection(e.shiftKey); await this.autocomplete.moveSelection(e.shiftKey ? -1 : +1);
} }
}; };
moveAutocompleteSelection = (up) => {
up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow();
};
onEscape = async (e) => { onEscape = async (e) => {
e.preventDefault(); e.preventDefault();
if (this.autocomplete) { if (this.autocomplete) {

View file

@ -43,17 +43,13 @@ export default class AutocompleteWrapperModel {
async onTab(e) { async onTab(e) {
const acComponent = this._getAutocompleterComponent(); const acComponent = this._getAutocompleterComponent();
if (acComponent.state.completionList.length === 0) { if (acComponent.countCompletions() === 0) {
// Force completions to show for the text currently entered // Force completions to show for the text currently entered
await acComponent.forceComplete(); await acComponent.forceComplete();
// Select the first item by moving "down" // Select the first item by moving "down"
await acComponent.onDownArrow(); await acComponent.moveSelection(+1);
} else { } else {
if (e.shiftKey) { await acComponent.moveSelection(e.shiftKey ? -1 : +1);
await acComponent.onUpArrow();
} else {
await acComponent.onDownArrow();
}
} }
this._updateCallback({ this._updateCallback({
close: true, close: true,
@ -61,11 +57,11 @@ export default class AutocompleteWrapperModel {
} }
onUpArrow() { onUpArrow() {
this._getAutocompleterComponent().onUpArrow(); this._getAutocompleterComponent().moveSelection(-1);
} }
onDownArrow() { onDownArrow() {
this._getAutocompleterComponent().onDownArrow(); this._getAutocompleterComponent().moveSelection(+1);
} }
onPartUpdate(part, offset) { onPartUpdate(part, offset) {