ant-design/components/mention/index.tsx

164 lines
4.4 KiB
TypeScript
Raw Normal View History

import * as React from 'react';
import RcMention, { Nav, toString, toEditorState, getMentions } from 'rc-editor-mention';
2018-11-21 22:38:27 +08:00
import { polyfill } from 'react-lifecycles-compat';
import classNames from 'classnames';
2016-11-14 13:20:00 +08:00
import Icon from '../icon';
import warning from '../_util/warning';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export type MentionPlacement = 'top' | 'bottom';
type SuggestionItme = React.ReactElement<{ value?: string }> | string;
2016-07-04 10:31:27 +08:00
export interface MentionProps {
prefixCls?: string;
suggestionStyle?: React.CSSProperties;
defaultSuggestions?: Array<SuggestionItme>;
2019-06-24 11:29:58 +08:00
suggestions?: Array<React.ReactElement<any>>;
onSearchChange?: (value: string, trigger: string) => any;
onChange?: (contentState: any) => void;
notFoundContent?: any;
2018-07-21 07:42:29 +08:00
loading?: boolean;
style?: React.CSSProperties;
2019-06-24 11:29:58 +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[];
placeholder?: string;
getSuggestionContainer?: (triggerNode: Element) => HTMLElement;
2017-11-21 19:03:21 +08:00
onFocus?: React.FocusEventHandler<HTMLElement>;
onBlur?: React.FocusEventHandler<HTMLElement>;
2019-06-24 11:29:58 +08:00
onSelect?: (suggestion: string, data?: any) => void;
readOnly?: boolean;
disabled?: boolean;
placement?: MentionPlacement;
2016-07-04 10:31:27 +08:00
}
export interface MentionState {
2019-06-24 11:29:58 +08:00
filteredSuggestions?: Array<any>;
2016-07-04 10:31:27 +08:00
focus?: Boolean;
}
2018-11-21 22:38:27 +08:00
class Mention extends React.Component<MentionProps, MentionState> {
static getMentions = getMentions;
2016-07-04 10:31:27 +08:00
static defaultProps = {
notFoundContent: 'No matches found',
2016-07-04 10:31:27 +08:00
loading: false,
multiLines: false,
placement: 'bottom' as MentionPlacement,
2016-07-04 10:31:27 +08:00
};
static Nav = Nav;
static toString = toString;
static toContentState = toEditorState;
2018-11-21 22:38:27 +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 = {
2018-12-18 18:32:21 +08:00
filteredSuggestions: props.defaultSuggestions,
2016-07-04 10:31:27 +08:00
focus: false,
};
warning(
false,
'Mention',
'Mention component is deprecated. Please use Mentions component instead.',
);
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) {
return this.props.onSearchChange(value, prefix);
2016-07-04 10:31:27 +08:00
}
return this.defaultSearchChange(value);
2018-12-07 20:02:01 +08:00
};
2016-07-04 10:31:27 +08:00
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
}
2018-12-07 20:02:01 +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();
2018-12-18 18:32:21 +08:00
const filteredSuggestions = (this.props.defaultSuggestions || []).filter(suggestion => {
if (typeof suggestion === 'string') {
return suggestion.toLowerCase().indexOf(searchValue) !== -1;
} else if (suggestion.type && suggestion.type === Nav) {
2018-12-07 20:02:01 +08:00
return suggestion.props.value
? suggestion.props.value.toLowerCase().indexOf(searchValue) !== -1
: true;
}
});
2016-07-04 10:31:27 +08:00
this.setState({
2018-12-18 18:32:21 +08:00
filteredSuggestions,
2016-07-04 10:31:27 +08:00
});
}
2017-11-21 19:03:21 +08:00
onFocus = (ev: React.FocusEvent<HTMLElement>) => {
this.setState({
focus: true,
});
if (this.props.onFocus) {
this.props.onFocus(ev);
}
2018-12-07 20:02:01 +08:00
};
2018-12-16 22:41:04 +08:00
2017-11-21 19:03:21 +08:00
onBlur = (ev: React.FocusEvent<HTMLElement>) => {
this.setState({
focus: false,
});
if (this.props.onBlur) {
this.props.onBlur(ev);
}
2018-12-07 20:02:01 +08:00
};
2018-12-16 22:41:04 +08:00
focus = () => {
2018-03-06 20:59:03 +08:00
this.mentionEle._editor.focusEditor();
2018-12-07 20:02:01 +08:00
};
2018-12-16 22:41:04 +08:00
2017-11-21 19:03:21 +08:00
mentionRef = (ele: any) => {
this.mentionEle = ele;
2018-12-07 20:02:01 +08:00
};
renderMention = ({ getPrefixCls }: ConfigConsumerProps) => {
2018-12-18 18:32:21 +08:00
const {
prefixCls: customizePrefixCls,
className = '',
loading,
placement,
suggestions,
} = this.props;
const { filteredSuggestions, focus } = this.state;
const prefixCls = getPrefixCls('mention', customizePrefixCls);
const cls = classNames(className, {
2016-11-14 12:21:58 +08:00
[`${prefixCls}-active`]: focus,
[`${prefixCls}-placement-top`]: placement === 'top',
2016-07-04 10:31:27 +08:00
});
2018-12-07 20:02:01 +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}
prefixCls={prefixCls}
2016-07-04 10:31:27 +08:00
className={cls}
ref={this.mentionRef}
2016-11-14 12:21:58 +08:00
onSearchChange={this.onSearchChange}
onChange={this.onChange}
onFocus={this.onFocus}
onBlur={this.onBlur}
2018-12-18 18:32:21 +08:00
suggestions={suggestions || filteredSuggestions}
2016-07-04 10:31:27 +08:00
notFoundContent={notFoundContent}
2016-11-14 12:21:58 +08:00
/>
);
2018-12-07 20:02:01 +08:00
};
render() {
2018-12-07 20:02:01 +08:00
return <ConfigConsumer>{this.renderMention}</ConfigConsumer>;
}
2016-07-04 10:31:27 +08:00
}
2018-11-21 22:38:27 +08:00
2018-12-01 23:06:05 +08:00
polyfill(Mention);
export default Mention;