feat: Autocomplete selection wraparound
This commit is contained in:
parent
cd928fe6f5
commit
8961c87cf9
3 changed files with 59 additions and 16 deletions
|
@ -11,26 +11,28 @@ export default class Autocomplete extends React.Component {
|
|||
completions: [],
|
||||
|
||||
// how far down the completion list we are
|
||||
selectionOffset: 0
|
||||
selectionOffset: 0,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props, state) {
|
||||
if(props.query == this.props.query) return;
|
||||
if (props.query === this.props.query) {
|
||||
return;
|
||||
}
|
||||
|
||||
getCompletions(props.query, props.selection).map(completionResult => {
|
||||
getCompletions(props.query, props.selection).forEach(completionResult => {
|
||||
try {
|
||||
completionResult.completions.then(completions => {
|
||||
let i = this.state.completions.findIndex(
|
||||
completion => completion.provider === completionResult.provider
|
||||
);
|
||||
|
||||
i = i == -1 ? this.state.completions.length : i;
|
||||
i = i === -1 ? this.state.completions.length : i;
|
||||
let newCompletions = Object.assign([], this.state.completions);
|
||||
completionResult.completions = completions;
|
||||
newCompletions[i] = completionResult;
|
||||
this.setState({
|
||||
completions: newCompletions
|
||||
completions: newCompletions,
|
||||
});
|
||||
}, err => {
|
||||
console.error(err);
|
||||
|
@ -42,13 +44,25 @@ export default class Autocomplete extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
onUpArrow() {
|
||||
this.setState({selectionOffset: this.state.selectionOffset - 1});
|
||||
countCompletions(): number {
|
||||
return this.state.completions.map(completionResult => {
|
||||
return completionResult.completions.length;
|
||||
}).reduce((l, r) => l + r);
|
||||
}
|
||||
|
||||
// called from MessageComposerInput
|
||||
onUpArrow(): boolean {
|
||||
let completionCount = this.countCompletions(),
|
||||
selectionOffset = (completionCount + this.state.selectionOffset - 1) % completionCount;
|
||||
this.setState({selectionOffset});
|
||||
return true;
|
||||
}
|
||||
|
||||
onDownArrow() {
|
||||
this.setState({selectionOffset: this.state.selectionOffset + 1});
|
||||
// called from MessageComposerInput
|
||||
onDownArrow(): boolean {
|
||||
let completionCount = this.countCompletions(),
|
||||
selectionOffset = (this.state.selectionOffset + 1) % completionCount;
|
||||
this.setState({selectionOffset});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -58,18 +72,20 @@ export default class Autocomplete extends React.Component {
|
|||
let completions = completionResult.completions.map((completion, i) => {
|
||||
let Component = completion.component;
|
||||
let className = classNames('mx_Autocomplete_Completion', {
|
||||
'selected': position == this.state.selectionOffset
|
||||
'selected': position === this.state.selectionOffset,
|
||||
});
|
||||
let componentPosition = position;
|
||||
position++;
|
||||
if(Component) {
|
||||
if (Component) {
|
||||
return Component;
|
||||
}
|
||||
|
||||
let onMouseOver = () => this.setState({selectionOffset: componentPosition});
|
||||
|
||||
return (
|
||||
<div key={i}
|
||||
className={className}
|
||||
onMouseOver={() => this.setState({selectionOffset: componentPosition})}>
|
||||
onMouseOver={onMouseOver}>
|
||||
<span style={{fontWeight: 600}}>{completion.title}</span>
|
||||
<span>{completion.subtitle}</span>
|
||||
<span style={{flex: 1}} />
|
||||
|
@ -82,7 +98,11 @@ export default class Autocomplete extends React.Component {
|
|||
return completions.length > 0 ? (
|
||||
<div key={i} className="mx_Autocomplete_ProviderSection">
|
||||
<span className="mx_Autocomplete_provider_name">{completionResult.provider.getName()}</span>
|
||||
<ReactCSSTransitionGroup component="div" transitionName="autocomplete" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
component="div"
|
||||
transitionName="autocomplete"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
{completions}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
@ -91,7 +111,11 @@ export default class Autocomplete extends React.Component {
|
|||
|
||||
return (
|
||||
<div className="mx_Autocomplete">
|
||||
<ReactCSSTransitionGroup component="div" transitionName="autocomplete" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
component="div"
|
||||
transitionName="autocomplete"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
{renderedCompletions}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
@ -101,5 +125,5 @@ export default class Autocomplete extends React.Component {
|
|||
|
||||
Autocomplete.propTypes = {
|
||||
// the query string for which to show autocomplete suggestions
|
||||
query: React.PropTypes.string.isRequired
|
||||
query: React.PropTypes.string.isRequired,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue