2017-11-17 14:38:54 +08:00
|
|
|
import * as React from 'react';
|
2016-07-20 18:56:44 +08:00
|
|
|
import RcMention, { Nav, toString, toEditorState, getMentions } from 'rc-editor-mention';
|
2016-09-28 16:55:14 +08:00
|
|
|
import classNames from 'classnames';
|
2017-01-26 12:09:26 +08:00
|
|
|
import shallowequal from 'shallowequal';
|
2016-11-14 13:20:00 +08:00
|
|
|
import Icon from '../icon';
|
2016-07-04 10:31:27 +08:00
|
|
|
|
2017-09-25 21:12:43 +08:00
|
|
|
export type MentionPlacement = 'top' | 'bottom';
|
|
|
|
|
2016-07-04 10:31:27 +08:00
|
|
|
export interface MentionProps {
|
2017-05-26 09:16:53 +08:00
|
|
|
prefixCls?: string;
|
2017-03-06 15:48:03 +08:00
|
|
|
suggestionStyle?: React.CSSProperties;
|
2016-07-04 10:31:27 +08:00
|
|
|
suggestions?: Array<any>;
|
2018-07-21 07:42:29 +08:00
|
|
|
onSearchChange?: (value: string, trigger: string) => any;
|
|
|
|
onChange?: (contentState: any) => any;
|
2016-07-04 10:31:27 +08:00
|
|
|
notFoundContent?: any;
|
2018-07-21 07:42:29 +08:00
|
|
|
loading?: boolean;
|
2017-03-06 15:48:03 +08:00
|
|
|
style?: React.CSSProperties;
|
2016-09-19 10:17:07 +08:00
|
|
|
defaultValue?: any;
|
|
|
|
value?: any;
|
2016-07-18 17:58:55 +08:00
|
|
|
className?: string;
|
2018-07-21 07:42:29 +08:00
|
|
|
multiLines?: boolean;
|
|
|
|
prefix?: string | string[];
|
2016-09-30 11:26:27 +08:00
|
|
|
placeholder?: string;
|
2017-03-28 13:20:05 +08:00
|
|
|
getSuggestionContainer?: (triggerNode: Element) => HTMLElement;
|
2017-11-21 19:03:21 +08:00
|
|
|
onFocus?: React.FocusEventHandler<HTMLElement>;
|
|
|
|
onBlur?: React.FocusEventHandler<HTMLElement>;
|
2018-07-21 07:42:29 +08:00
|
|
|
onSelect?: (suggestion: string, data?: any) => any;
|
2017-05-05 14:53:46 +08:00
|
|
|
readOnly?: boolean;
|
|
|
|
disabled?: boolean;
|
2017-09-25 21:12:43 +08:00
|
|
|
placement?: MentionPlacement;
|
2016-07-04 10:31:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface MentionState {
|
|
|
|
suggestions?: Array<any>;
|
|
|
|
focus?: Boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default class Mention extends React.Component<MentionProps, MentionState> {
|
2016-07-20 18:56:44 +08:00
|
|
|
static getMentions = getMentions;
|
2016-07-04 10:31:27 +08:00
|
|
|
static defaultProps = {
|
|
|
|
prefixCls: 'ant-mention',
|
|
|
|
notFoundContent: '无匹配结果,轻敲空格完成输入',
|
|
|
|
loading: false,
|
|
|
|
multiLines: false,
|
2017-09-25 21:12:43 +08:00
|
|
|
placement: 'bottom',
|
2016-07-04 10:31:27 +08:00
|
|
|
};
|
2017-05-05 14:53:46 +08:00
|
|
|
static Nav = Nav;
|
|
|
|
static toString = toString;
|
|
|
|
static toContentState = toEditorState;
|
2017-06-28 16:02:38 +08:00
|
|
|
private mentionEle: any;
|
2017-11-21 19:03:21 +08:00
|
|
|
constructor(props: MentionProps) {
|
2016-07-04 10:31:27 +08:00
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
suggestions: props.suggestions,
|
|
|
|
focus: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-05-25 16:54:15 +08:00
|
|
|
componentWillReceiveProps(nextProps: MentionProps) {
|
|
|
|
const { suggestions } = nextProps;
|
2017-01-26 12:09:26 +08:00
|
|
|
if (!shallowequal(suggestions, this.props.suggestions)) {
|
|
|
|
this.setState({
|
|
|
|
suggestions,
|
|
|
|
});
|
|
|
|
}
|
2016-07-04 10:31:27 +08:00
|
|
|
}
|
|
|
|
|
2017-11-21 19:03:21 +08:00
|
|
|
onSearchChange = (value: string, prefix: string) => {
|
2016-07-04 10:31:27 +08:00
|
|
|
if (this.props.onSearchChange) {
|
2017-02-13 15:50:38 +08:00
|
|
|
return this.props.onSearchChange(value, prefix);
|
2016-07-04 10:31:27 +08:00
|
|
|
}
|
|
|
|
return this.defaultSearchChange(value);
|
|
|
|
}
|
|
|
|
|
2017-11-21 19:03:21 +08:00
|
|
|
onChange = (editorState: any) => {
|
2016-07-04 10:31:27 +08:00
|
|
|
if (this.props.onChange) {
|
2016-07-19 12:31:03 +08:00
|
|
|
this.props.onChange(editorState);
|
2016-07-04 10:31:27 +08:00
|
|
|
}
|
|
|
|
}
|
2016-07-18 17:58:55 +08:00
|
|
|
|
2018-11-27 23:21:45 +08:00
|
|
|
defaultSearchChange(value: string): void {
|
2016-07-04 10:31:27 +08:00
|
|
|
const searchValue = value.toLowerCase();
|
2016-10-24 12:04:26 +08:00
|
|
|
const filteredSuggestions = (this.props.suggestions || []).filter(
|
2017-09-23 12:51:59 +08:00
|
|
|
suggestion => {
|
|
|
|
if (suggestion.type && suggestion.type === Nav) {
|
|
|
|
return suggestion.props.value ?
|
|
|
|
suggestion.props.value.toLowerCase().indexOf(searchValue) !== -1
|
|
|
|
: true;
|
|
|
|
}
|
|
|
|
return suggestion.toLowerCase().indexOf(searchValue) !== -1;
|
|
|
|
},
|
2016-07-04 10:31:27 +08:00
|
|
|
);
|
|
|
|
this.setState({
|
|
|
|
suggestions: filteredSuggestions,
|
|
|
|
});
|
|
|
|
}
|
2017-01-26 12:09:26 +08:00
|
|
|
|
2017-11-21 19:03:21 +08:00
|
|
|
onFocus = (ev: React.FocusEvent<HTMLElement>) => {
|
2016-12-09 13:03:09 +08:00
|
|
|
this.setState({
|
|
|
|
focus: true,
|
|
|
|
});
|
|
|
|
if (this.props.onFocus) {
|
|
|
|
this.props.onFocus(ev);
|
|
|
|
}
|
|
|
|
}
|
2017-11-21 19:03:21 +08:00
|
|
|
onBlur = (ev: React.FocusEvent<HTMLElement>) => {
|
2016-12-09 13:03:09 +08:00
|
|
|
this.setState({
|
|
|
|
focus: false,
|
|
|
|
});
|
|
|
|
if (this.props.onBlur) {
|
|
|
|
this.props.onBlur(ev);
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 16:02:38 +08:00
|
|
|
focus = () => {
|
2018-03-06 20:59:03 +08:00
|
|
|
this.mentionEle._editor.focusEditor();
|
2017-06-28 16:02:38 +08:00
|
|
|
}
|
2017-11-21 19:03:21 +08:00
|
|
|
mentionRef = (ele: any) => {
|
2017-06-28 16:02:38 +08:00
|
|
|
this.mentionEle = ele;
|
|
|
|
}
|
2016-07-04 10:31:27 +08:00
|
|
|
render() {
|
2017-09-25 21:12:43 +08:00
|
|
|
const { className = '', prefixCls, loading, placement } = this.props;
|
2016-07-04 10:31:27 +08:00
|
|
|
const { suggestions, focus } = this.state;
|
2016-11-30 10:20:23 +08:00
|
|
|
const cls = classNames(className, {
|
2016-11-14 12:21:58 +08:00
|
|
|
[`${prefixCls}-active`]: focus,
|
2017-09-25 21:12:43 +08:00
|
|
|
[`${prefixCls}-placement-top`]: placement === 'top',
|
2016-07-04 10:31:27 +08:00
|
|
|
});
|
|
|
|
|
2016-11-14 12:21:58 +08:00
|
|
|
const notFoundContent = loading
|
|
|
|
? <Icon type="loading" />
|
|
|
|
: this.props.notFoundContent;
|
2016-07-18 17:58:55 +08:00
|
|
|
|
2016-11-14 12:21:58 +08:00
|
|
|
return (
|
|
|
|
<RcMention
|
2016-07-04 10:31:27 +08:00
|
|
|
{...this.props}
|
|
|
|
className={cls}
|
2017-06-28 16:02:38 +08:00
|
|
|
ref={this.mentionRef}
|
2016-11-14 12:21:58 +08:00
|
|
|
onSearchChange={this.onSearchChange}
|
|
|
|
onChange={this.onChange}
|
2016-12-09 13:03:09 +08:00
|
|
|
onFocus={this.onFocus}
|
|
|
|
onBlur={this.onBlur}
|
2016-07-18 17:58:55 +08:00
|
|
|
suggestions={suggestions}
|
2016-07-04 10:31:27 +08:00
|
|
|
notFoundContent={notFoundContent}
|
2016-11-14 12:21:58 +08:00
|
|
|
/>
|
|
|
|
);
|
2016-07-04 10:31:27 +08:00
|
|
|
}
|
|
|
|
}
|