diff --git a/README.md b/README.md
index 08a3db0..08b13ea 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,7 @@ React.render(, container);
| notFoundContent | Set mentions content when not match | ReactNode | 'Not Found' |
| placement | Set popup placement | 'top' \| 'bottom' | 'bottom' |
| prefix | Set trigger prefix keyword | string \| string[] | '@' |
+| suffix | Set suffix string when option is selected | string | '' |
| rows | Set row count | number | 1 |
| split | Set split string before and after selected mention | string | ' ' |
| validateSearch | Customize trigger search logic | (text: string, props: MentionsProps) => void | - |
diff --git a/examples/suffix.js b/examples/suffix.js
new file mode 100644
index 0000000..da778fc
--- /dev/null
+++ b/examples/suffix.js
@@ -0,0 +1,44 @@
+/* eslint no-console: 0 */
+
+import React from 'react';
+import Mentions from '../src';
+import '../assets/index.less';
+
+const { Option } = Mentions;
+
+class Demo extends React.Component {
+ onSelect = (option, prefix) => {
+ console.log('Select:', prefix, '-', option.value);
+ };
+
+ onFocus = () => {
+ console.log('onFocus');
+ };
+
+ onBlur = () => {
+ console.log('onBlur');
+ };
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default Demo;
diff --git a/src/Mentions.tsx b/src/Mentions.tsx
index 5a9f451..d8e6288 100644
--- a/src/Mentions.tsx
+++ b/src/Mentions.tsx
@@ -34,6 +34,7 @@ export interface MentionsProps extends BaseTextareaAttrs {
transitionName?: string;
placement?: Placement;
prefix?: string | string[];
+ suffix?: string;
prefixCls?: string;
value?: string;
filterOption?: false | typeof defaultFilterOption;
@@ -240,13 +241,14 @@ class Mentions extends React.Component {
public selectOption = (option: OptionProps) => {
const { value, measureLocation, measurePrefix } = this.state;
- const { split, onSelect } = this.props;
+ const { split, suffix = '', onSelect } = this.props;
const { value: mentionValue = '' } = option;
const { text, selectionLocation } = replaceWithMeasure(value, {
measureLocation,
targetText: mentionValue,
prefix: measurePrefix,
+ suffix,
selectionStart: this.textarea!.selectionStart,
split: split!,
});
diff --git a/src/util.ts b/src/util.ts
index fb39b50..1c92838 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -54,6 +54,7 @@ export function getLastMeasureIndex(text: string, prefix: string | string[] = ''
interface MeasureConfig {
measureLocation: number;
prefix: string;
+ suffix: string;
targetText: string;
selectionStart: number;
split: string;
@@ -91,7 +92,7 @@ function reduceText(text: string, targetText: string, split: string) {
* => little @light test
*/
export function replaceWithMeasure(text: string, measureConfig: MeasureConfig) {
- const { measureLocation, prefix, targetText, selectionStart, split } = measureConfig;
+ const { measureLocation, prefix, suffix, targetText, selectionStart, split } = measureConfig;
// Before text will append one space if have other text
let beforeMeasureText = text.slice(0, measureLocation);
@@ -112,8 +113,7 @@ export function replaceWithMeasure(text: string, measureConfig: MeasureConfig) {
restText = restText.slice(split.length);
}
- const connectedStartText = `${beforeMeasureText}${prefix}${targetText}${split}`;
-
+ const connectedStartText = `${beforeMeasureText}${prefix}${targetText}${suffix}${split}`;
return {
text: `${connectedStartText}${restText}`,
selectionLocation: connectedStartText.length,
diff --git a/tests/FullProcess.spec.jsx b/tests/FullProcess.spec.jsx
index 292fc8f..a9f331b 100644
--- a/tests/FullProcess.spec.jsx
+++ b/tests/FullProcess.spec.jsx
@@ -31,6 +31,8 @@ describe('Full Process', () => {
]);
simulateInput(wrapper, '@a');
+ wrapper.find('textarea').instance().selectionStart = 2;
+ wrapper.find('textarea').simulate('keyUp', {});
expect(wrapper.find('DropdownMenu').props().options).toMatchObject([
{ value: 'bamboo' },
{ value: 'cat' },
@@ -110,4 +112,27 @@ describe('Full Process', () => {
expect(wrapper.state().measuring).toBe(false);
});
+
+ it('add suffix after target if suffix exists', () => {
+ const onChange = jest.fn();
+ const onKeyDown = jest.fn();
+ const wrapper = createMentions({
+ prefix: '{',
+ suffix: '}',
+ split: ' ',
+ onChange,
+ onKeyDown,
+ });
+
+ simulateInput(wrapper, '{');
+ wrapper.find('textarea').instance().selectionStart = 1;
+ expect(wrapper.state().measuring).toBe(true);
+
+ wrapper.find('textarea').simulate('keyDown', {
+ which: KeyCode.ENTER,
+ });
+
+ expect(wrapper.state().measuring).toBe(false);
+ expect(onChange).toBeCalledWith('{bamboo} ');
+ });
});
diff --git a/tests/shared/input.js b/tests/shared/input.js
index 8676c11..745f412 100644
--- a/tests/shared/input.js
+++ b/tests/shared/input.js
@@ -5,6 +5,10 @@ export function simulateInput(wrapper, text = '', keyEvent) {
const myKeyEvent = keyEvent || {
which: lastChar.charCodeAt(0),
key: lastChar,
+ target: {
+ value: text,
+ selectionStart: text.length,
+ },
};
wrapper.find('textarea').simulate('keyDown', myKeyEvent);