mirror of
https://github.com/element-hq/element-web
synced 2024-11-28 12:28:50 +03:00
Merge pull request #2966 from npny/npny/autocomplete-arrow-keys
Allow arrow keys navigation in autocomplete list
This commit is contained in:
commit
48f5cf1523
3 changed files with 55 additions and 60 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue