diff --git a/src/autocomplete/AutocompleteProvider.js b/src/autocomplete/AutocompleteProvider.js
index 41d5d035d1..e3332d014e 100644
--- a/src/autocomplete/AutocompleteProvider.js
+++ b/src/autocomplete/AutocompleteProvider.js
@@ -1,4 +1,5 @@
import Q from 'q';
+import React from 'react';
export default class AutocompleteProvider {
constructor(commandRegex?: RegExp, fuseOpts?: any) {
@@ -51,4 +52,12 @@ export default class AutocompleteProvider {
getName(): string {
return 'Default Provider';
}
+
+ renderCompletions(completions: [React.Component]): ?React.Component {
+ return (
+
before rendering but I think this is the better way to do it.
+ */
+
+export class TextualCompletion extends React.Component {
+ render() {
+ const {
+ title,
+ subtitle,
+ description,
+ className,
+ ...restProps,
+ } = this.props;
+ return (
+
+ {title}
+ {subtitle}
+ {description}
+
+ );
+ }
}
+TextualCompletion.propTypes = {
+ title: React.PropTypes.string,
+ subtitle: React.PropTypes.string,
+ description: React.PropTypes.string,
+ className: React.PropTypes.string,
+};
+
+export class PillCompletion extends React.Component {
+ render() {
+ const {
+ title,
+ subtitle,
+ description,
+ initialComponent,
+ className,
+ ...restProps,
+ } = this.props;
+ return (
+
+ {initialComponent}
+ {title}
+ {subtitle}
+ {description}
+
+ );
+ }
+}
+PillCompletion.propTypes = {
+ title: React.PropTypes.string,
+ subtitle: React.PropTypes.string,
+ description: React.PropTypes.string,
+ initialComponent: React.PropTypes.element,
+ className: React.PropTypes.string,
+};
diff --git a/src/autocomplete/DuckDuckGoProvider.js b/src/autocomplete/DuckDuckGoProvider.js
index 1746ce0aaa..c74ffa0473 100644
--- a/src/autocomplete/DuckDuckGoProvider.js
+++ b/src/autocomplete/DuckDuckGoProvider.js
@@ -78,7 +78,7 @@ export default class DuckDuckGoProvider extends AutocompleteProvider {
}
getName() {
- return 'Results from DuckDuckGo';
+ return '🔍 Results from DuckDuckGo';
}
static getInstance(): DuckDuckGoProvider {
diff --git a/src/autocomplete/EmojiProvider.js b/src/autocomplete/EmojiProvider.js
index 37a50ee8d8..8763d90749 100644
--- a/src/autocomplete/EmojiProvider.js
+++ b/src/autocomplete/EmojiProvider.js
@@ -3,6 +3,8 @@ import AutocompleteProvider from './AutocompleteProvider';
import Q from 'q';
import {emojioneList, shortnameToImage, shortnameToUnicode} from 'emojione';
import Fuse from 'fuse.js';
+import sdk from '../index';
+import {PillCompletion} from './Components';
const EMOJI_REGEX = /:\w*:?/g;
const EMOJI_SHORTNAMES = Object.keys(emojioneList);
@@ -16,28 +18,28 @@ export default class EmojiProvider extends AutocompleteProvider {
}
getCompletions(query: string, selection: {start: number, end: number}) {
+ const EmojiText = sdk.getComponent('views.elements.EmojiText');
+
let completions = [];
let {command, range} = this.getCurrentCommand(query, selection);
if (command) {
completions = this.fuse.search(command[0]).map(result => {
- let shortname = EMOJI_SHORTNAMES[result];
- let imageHTML = shortnameToImage(shortname);
+ const shortname = EMOJI_SHORTNAMES[result];
+ const unicode = shortnameToUnicode(shortname);
return {
- completion: shortnameToUnicode(shortname),
+ completion: unicode,
component: (
-
- {shortname}
-
+
{unicode}} />
),
range,
};
- }).slice(0, 4);
+ }).slice(0, 8);
}
return Q.when(completions);
}
getName() {
- return 'Emoji';
+ return '😃 Emoji';
}
static getInstance() {
@@ -45,4 +47,10 @@ export default class EmojiProvider extends AutocompleteProvider {
instance = new EmojiProvider();
return instance;
}
+
+ renderCompletions(completions: [React.Component]): ?React.Component {
+ return React.cloneElement(super.renderCompletions(completions), {
+ className: 'mx_Autocomplete_Completion_container_pill',
+ });
+ }
}
diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js
index b34fdeb59a..f27d450266 100644
--- a/src/autocomplete/RoomProvider.js
+++ b/src/autocomplete/RoomProvider.js
@@ -3,8 +3,9 @@ import AutocompleteProvider from './AutocompleteProvider';
import Q from 'q';
import MatrixClientPeg from '../MatrixClientPeg';
import Fuse from 'fuse.js';
-import {TextualCompletion} from './Components';
+import {PillCompletion} from './Components';
import {getDisplayAliasForRoom} from '../MatrixTools';
+import sdk from '../index';
const ROOM_REGEX = /(?=#)([^\s]*)/g;
@@ -21,6 +22,8 @@ export default class RoomProvider extends AutocompleteProvider {
}
getCompletions(query: string, selection: {start: number, end: number}) {
+ const RoomAvatar = sdk.getComponent('views.avatars.RoomAvatar');
+
let client = MatrixClientPeg.get();
let completions = [];
const {command, range} = this.getCurrentCommand(query, selection);
@@ -39,7 +42,7 @@ export default class RoomProvider extends AutocompleteProvider {
return {
completion: displayAlias,
component: (
-
+ } title={room.name} description={displayAlias} />
),
range,
};
@@ -49,7 +52,7 @@ export default class RoomProvider extends AutocompleteProvider {
}
getName() {
- return 'Rooms';
+ return '💬 Rooms';
}
static getInstance() {
@@ -59,4 +62,10 @@ export default class RoomProvider extends AutocompleteProvider {
return instance;
}
+
+ renderCompletions(completions: [React.Component]): ?React.Component {
+ return React.cloneElement(super.renderCompletions(completions), {
+ className: 'mx_Autocomplete_Completion_container_pill',
+ });
+ }
}
diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js
index 8828f8cb70..e772d62b23 100644
--- a/src/autocomplete/UserProvider.js
+++ b/src/autocomplete/UserProvider.js
@@ -2,7 +2,8 @@ import React from 'react';
import AutocompleteProvider from './AutocompleteProvider';
import Q from 'q';
import Fuse from 'fuse.js';
-import {TextualCompletion} from './Components';
+import {PillCompletion} from './Components';
+import sdk from '../index';
const USER_REGEX = /@[^\s]*/g;
@@ -20,6 +21,8 @@ export default class UserProvider extends AutocompleteProvider {
}
getCompletions(query: string, selection: {start: number, end: number}) {
+ const MemberAvatar = sdk.getComponent('views.avatars.MemberAvatar');
+
let completions = [];
let {command, range} = this.getCurrentCommand(query, selection);
if (command) {
@@ -29,7 +32,8 @@ export default class UserProvider extends AutocompleteProvider {
return {
completion: user.userId,
component: (
- }
title={displayName}
description={user.userId} />
),
@@ -41,7 +45,7 @@ export default class UserProvider extends AutocompleteProvider {
}
getName() {
- return 'Users';
+ return '👥 Users';
}
setUserList(users) {
@@ -54,4 +58,10 @@ export default class UserProvider extends AutocompleteProvider {
}
return instance;
}
+
+ renderCompletions(completions: [React.Component]): ?React.Component {
+ return React.cloneElement(super.renderCompletions(completions), {
+ className: 'mx_Autocomplete_Completion_container_pill',
+ });
+ }
}
diff --git a/src/components/views/rooms/Autocomplete.js b/src/components/views/rooms/Autocomplete.js
index 32e568e2ba..1f62ce852c 100644
--- a/src/components/views/rooms/Autocomplete.js
+++ b/src/components/views/rooms/Autocomplete.js
@@ -1,7 +1,8 @@
import React from 'react';
-import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
+import ReactDOM from 'react-dom';
import classNames from 'classnames';
import flatMap from 'lodash/flatMap';
+import sdk from '../../../index';
import {getCompletions} from '../../../autocomplete/Autocompleter';
@@ -100,11 +101,26 @@ export default class Autocomplete extends React.Component {
this.setState({selectionOffset});
}
+ componentDidUpdate() {
+ // this is the selected completion, so scroll it into view if needed
+ const selectedCompletion = this.refs[`completion${this.state.selectionOffset}`];
+ if (selectedCompletion && this.container) {
+ const {offsetTop} = ReactDOM.findDOMNode(selectedCompletion);
+ if (offsetTop > this.container.scrollTop + this.container.offsetHeight ||
+ offsetTop < this.container.scrollTop) {
+ this.container.scrollTop = offsetTop - this.container.offsetTop;
+ }
+ }
+ }
+
render() {
+ const EmojiText = sdk.getComponent('views.elements.EmojiText');
+
let position = 0;
let renderedCompletions = this.state.completions.map((completionResult, i) => {
let completions = completionResult.completions.map((completion, i) => {
- let className = classNames('mx_Autocomplete_Completion', {
+
+ const className = classNames('mx_Autocomplete_Completion', {
'selected': position === this.state.selectionOffset,
});
let componentPosition = position;
@@ -116,40 +132,27 @@ export default class Autocomplete extends React.Component {
this.onConfirm();
};
- return (
-
- {completion.component}
-
- );
+ return React.cloneElement(completion.component, {
+ key: i,
+ ref: `completion${i}`,
+ className,
+ onMouseOver,
+ onClick,
+ });
});
return completions.length > 0 ? (
- {completionResult.provider.getName()}
-
- {completions}
-
+ {completionResult.provider.getName()}
+ {completionResult.provider.renderCompletions(completions)}
) : null;
});
return (
-
-
- {renderedCompletions}
-
+
this.container = e}>
+ {renderedCompletions}
);
}