react-mention-input 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/MentionInput.d.ts +5 -0
- package/dist/MentionInput.js +28 -9
- package/package.json +1 -1
- package/src/MentionInput.tsx +48 -22
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ A customizable input component with @mention functionality.
|
|
|
37
37
|
| `suggestionListClassName` | `string` | Custom class name for the suggestion list. |
|
|
38
38
|
| `suggestionItemClassName` | `string` | Custom class name for each suggestion item. |
|
|
39
39
|
| `sendButtonIcon` | `ReactNode` | Custom icon for the send button (MUI icon or image path). |
|
|
40
|
-
| `onSendMessage` | `(obj:
|
|
40
|
+
| `onSendMessage` | `(obj:{messageText: string, messageHTML: string,userSelectListWithIds:{ id: number; name: string }[],userSelectListName:string[]}) => void` | Callback function triggered on sending a message, providing both plain text, HTML and userName. |
|
|
41
41
|
| `suggestionPosition` | `'top' | 'bottom' | 'left' | 'right'` | Position of the suggestion dropdown relative to the input. Default is `bottom`. |
|
|
42
42
|
|
|
43
43
|
#### Example Usage
|
package/dist/MentionInput.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ interface MentionInputProps {
|
|
|
17
17
|
onSendMessage?: (obj: {
|
|
18
18
|
messageText: string;
|
|
19
19
|
messageHTML: string;
|
|
20
|
+
userSelectListWithIds: {
|
|
21
|
+
id: number;
|
|
22
|
+
name: string;
|
|
23
|
+
}[];
|
|
24
|
+
userSelectListName: string[];
|
|
20
25
|
}) => void;
|
|
21
26
|
suggestionPosition?: 'top' | 'bottom' | 'left' | 'right';
|
|
22
27
|
}
|
package/dist/MentionInput.js
CHANGED
|
@@ -9,15 +9,20 @@ var MentionInput = function (_a) {
|
|
|
9
9
|
var inputRef = useRef(null);
|
|
10
10
|
var suggestionListRef = useRef(null);
|
|
11
11
|
var caretOffsetRef = useRef(0);
|
|
12
|
+
var userSelectListRef = useRef([]); // Only unique names
|
|
13
|
+
var userSelectListWithIdsRef = useRef([]); // Unique IDs with names
|
|
12
14
|
var highlightMentionsAndLinks = function (text) {
|
|
13
15
|
// Regular expression for detecting links
|
|
14
16
|
var linkRegex = /(https?:\/\/[^\s]+)/g;
|
|
15
|
-
//
|
|
16
|
-
var
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
// Highlight links
|
|
18
|
+
var highlightedText = text.replace(linkRegex, '<a href="$1" target="_blank" rel="noopener noreferrer" class="link-highlight">$1</a>');
|
|
19
|
+
// Highlight mentions manually based on `userSelectListRef`
|
|
20
|
+
userSelectListRef === null || userSelectListRef === void 0 ? void 0 : userSelectListRef.current.forEach(function (userName) {
|
|
21
|
+
var mentionPattern = new RegExp("@".concat(userName, "(\\s|$)"), "g");
|
|
22
|
+
highlightedText = highlightedText.replace(mentionPattern, function (match, trailingSpace) {
|
|
23
|
+
return "<span class=\"mention-highlight\">".concat(match.trim(), "</span> ");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
21
26
|
return highlightedText;
|
|
22
27
|
};
|
|
23
28
|
var restoreCaretPosition = function (node, caretOffset) {
|
|
@@ -122,27 +127,41 @@ var MentionInput = function (_a) {
|
|
|
122
127
|
var plainText = inputValue;
|
|
123
128
|
var caretOffset = caretOffsetRef.current;
|
|
124
129
|
var mentionMatch = plainText.slice(0, caretOffset).match(/@(\S*)$/);
|
|
130
|
+
if (!userSelectListRef.current.includes(user.name)) {
|
|
131
|
+
userSelectListRef.current.push(user.name);
|
|
132
|
+
}
|
|
133
|
+
// Check if the ID is already stored
|
|
134
|
+
var isIdExists = userSelectListWithIdsRef.current.some(function (item) { return item.id === user.id; });
|
|
135
|
+
if (!isIdExists) {
|
|
136
|
+
userSelectListWithIdsRef.current.push(user);
|
|
137
|
+
}
|
|
125
138
|
if (!mentionMatch)
|
|
126
139
|
return;
|
|
127
140
|
var mentionIndex = plainText.slice(0, caretOffset).lastIndexOf("@");
|
|
128
|
-
|
|
141
|
+
// Append space after the mention
|
|
142
|
+
var newValue = plainText.substring(0, mentionIndex + 1) + user.name + " " + plainText.substring(caretOffset);
|
|
129
143
|
setInputValue(newValue);
|
|
130
144
|
inputRef.current.innerText = newValue;
|
|
145
|
+
// Highlight mentions and links with
|
|
131
146
|
var htmlWithHighlights = highlightMentionsAndLinks(newValue);
|
|
147
|
+
// Set highlighted content
|
|
132
148
|
inputRef.current.innerHTML = htmlWithHighlights;
|
|
133
149
|
setShowSuggestions(false);
|
|
150
|
+
// Adjust caret position after adding the mention and space
|
|
134
151
|
var mentionEnd = mentionIndex + user.name.length + 1;
|
|
135
|
-
restoreCaretPosition(inputRef.current, mentionEnd);
|
|
152
|
+
restoreCaretPosition(inputRef.current, mentionEnd + 1); // +1 for the space
|
|
136
153
|
};
|
|
137
154
|
var handleSendMessage = function () {
|
|
138
155
|
if (inputRef.current) {
|
|
139
156
|
var messageText = inputRef.current.innerText.trim(); // Plain text
|
|
140
157
|
var messageHTML = inputRef.current.innerHTML.trim(); // HTML with <span> highlighting
|
|
141
158
|
if (messageText && onSendMessage) {
|
|
142
|
-
onSendMessage({ messageText: messageText, messageHTML: messageHTML }); // Pass both plain text and HTML
|
|
159
|
+
onSendMessage({ messageText: messageText, messageHTML: messageHTML, userSelectListWithIds: userSelectListWithIdsRef.current, userSelectListName: userSelectListRef.current }); // Pass both plain text and HTML
|
|
143
160
|
setInputValue(""); // Clear state
|
|
144
161
|
setShowSuggestions(false); // Hide suggestions
|
|
145
162
|
inputRef.current.innerText = ""; // Clear input field
|
|
163
|
+
userSelectListRef.current = [];
|
|
164
|
+
userSelectListWithIdsRef.current = [];
|
|
146
165
|
}
|
|
147
166
|
}
|
|
148
167
|
};
|
package/package.json
CHANGED
package/src/MentionInput.tsx
CHANGED
|
@@ -17,7 +17,7 @@ interface MentionInputProps {
|
|
|
17
17
|
suggestionListClassName?: string;
|
|
18
18
|
suggestionItemClassName?: string;
|
|
19
19
|
sendButtonIcon?: ReactNode; // Button icon (MUI icon or image path)
|
|
20
|
-
onSendMessage?: (obj:{messageText: string, messageHTML: string}) => void;
|
|
20
|
+
onSendMessage?: (obj:{messageText: string, messageHTML: string,userSelectListWithIds:{ id: number; name: string }[],userSelectListName:string[]}) => void;
|
|
21
21
|
suggestionPosition?: 'top' | 'bottom' | 'left' | 'right'; // New prop for tooltip position
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -37,32 +37,39 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
37
37
|
const [inputValue, setInputValue] = useState<string>(""); // Plain text
|
|
38
38
|
const [suggestions, setSuggestions] = useState<User[]>([]);
|
|
39
39
|
const [showSuggestions, setShowSuggestions] = useState<boolean>(false);
|
|
40
|
+
|
|
41
|
+
|
|
40
42
|
|
|
41
43
|
const inputRef = useRef<HTMLDivElement>(null);
|
|
42
44
|
const suggestionListRef = useRef<HTMLUListElement>(null);
|
|
43
45
|
const caretOffsetRef = useRef<number>(0);
|
|
46
|
+
const userSelectListRef = useRef<string[]>([]); // Only unique names
|
|
47
|
+
const userSelectListWithIdsRef = useRef<{ id: number; name: string }[]>([]); // Unique IDs with names
|
|
44
48
|
|
|
45
49
|
const highlightMentionsAndLinks = (text: string): string => {
|
|
46
50
|
// Regular expression for detecting links
|
|
47
51
|
const linkRegex = /(https?:\/\/[^\s]+)/g;
|
|
48
52
|
|
|
49
|
-
//
|
|
50
|
-
const mentionRegex = /@([^\s]+(?: [^\s]+)?)(?=\s|$)/g;
|
|
51
|
-
|
|
52
|
-
// First, highlight mentions
|
|
53
|
+
// Highlight links
|
|
53
54
|
let highlightedText = text.replace(
|
|
54
|
-
mentionRegex,
|
|
55
|
-
'<span class="mention-highlight">@$1</span>'
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
// Then, highlight links
|
|
59
|
-
highlightedText = highlightedText.replace(
|
|
60
55
|
linkRegex,
|
|
61
56
|
'<a href="$1" target="_blank" rel="noopener noreferrer" class="link-highlight">$1</a>'
|
|
62
57
|
);
|
|
63
58
|
|
|
59
|
+
// Highlight mentions manually based on `userSelectListRef`
|
|
60
|
+
userSelectListRef?.current.forEach((userName) => {
|
|
61
|
+
const mentionPattern = new RegExp(`@${userName}(\\s|$)`, "g");
|
|
62
|
+
highlightedText = highlightedText.replace(
|
|
63
|
+
mentionPattern,
|
|
64
|
+
(match, trailingSpace) => {
|
|
65
|
+
return `<span class="mention-highlight">${match.trim()}</span> `;
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
64
70
|
return highlightedText;
|
|
65
71
|
};
|
|
72
|
+
|
|
66
73
|
|
|
67
74
|
const restoreCaretPosition = (node: HTMLElement, caretOffset: number) => {
|
|
68
75
|
const range = document.createRange();
|
|
@@ -191,28 +198,45 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
191
198
|
|
|
192
199
|
const handleSuggestionClick = (user: User) => {
|
|
193
200
|
if (!inputRef.current) return;
|
|
194
|
-
|
|
201
|
+
|
|
195
202
|
const plainText = inputValue;
|
|
196
203
|
const caretOffset = caretOffsetRef.current;
|
|
197
204
|
const mentionMatch = plainText.slice(0, caretOffset).match(/@(\S*)$/);
|
|
198
|
-
|
|
205
|
+
|
|
206
|
+
if (!userSelectListRef.current.includes(user.name)) {
|
|
207
|
+
userSelectListRef.current.push(user.name);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Check if the ID is already stored
|
|
211
|
+
const isIdExists = userSelectListWithIdsRef.current.some(
|
|
212
|
+
(item) => item.id === user.id
|
|
213
|
+
);
|
|
214
|
+
if (!isIdExists) {
|
|
215
|
+
userSelectListWithIdsRef.current.push(user);
|
|
216
|
+
}
|
|
217
|
+
|
|
199
218
|
if (!mentionMatch) return;
|
|
200
|
-
|
|
219
|
+
|
|
201
220
|
const mentionIndex = plainText.slice(0, caretOffset).lastIndexOf("@");
|
|
202
|
-
|
|
221
|
+
|
|
222
|
+
// Append space after the mention
|
|
203
223
|
const newValue =
|
|
204
|
-
plainText.substring(0, mentionIndex + 1) + user.name + plainText.substring(caretOffset);
|
|
205
|
-
|
|
224
|
+
plainText.substring(0, mentionIndex + 1) + user.name + " " + plainText.substring(caretOffset);
|
|
225
|
+
|
|
206
226
|
setInputValue(newValue);
|
|
207
227
|
inputRef.current.innerText = newValue;
|
|
208
|
-
|
|
228
|
+
|
|
229
|
+
// Highlight mentions and links with
|
|
209
230
|
const htmlWithHighlights = highlightMentionsAndLinks(newValue);
|
|
231
|
+
|
|
232
|
+
// Set highlighted content
|
|
210
233
|
inputRef.current.innerHTML = htmlWithHighlights;
|
|
211
|
-
|
|
234
|
+
|
|
212
235
|
setShowSuggestions(false);
|
|
213
|
-
|
|
236
|
+
|
|
237
|
+
// Adjust caret position after adding the mention and space
|
|
214
238
|
const mentionEnd = mentionIndex + user.name.length + 1;
|
|
215
|
-
restoreCaretPosition(inputRef.current, mentionEnd);
|
|
239
|
+
restoreCaretPosition(inputRef.current, mentionEnd + 1); // +1 for the space
|
|
216
240
|
};
|
|
217
241
|
|
|
218
242
|
const handleSendMessage = () => {
|
|
@@ -221,10 +245,12 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
221
245
|
const messageHTML = inputRef.current.innerHTML.trim(); // HTML with <span> highlighting
|
|
222
246
|
|
|
223
247
|
if (messageText && onSendMessage) {
|
|
224
|
-
onSendMessage({messageText, messageHTML}); // Pass both plain text and HTML
|
|
248
|
+
onSendMessage({messageText, messageHTML,userSelectListWithIds:userSelectListWithIdsRef.current,userSelectListName:userSelectListRef.current }); // Pass both plain text and HTML
|
|
225
249
|
setInputValue(""); // Clear state
|
|
226
250
|
setShowSuggestions(false); // Hide suggestions
|
|
227
251
|
inputRef.current.innerText = ""; // Clear input field
|
|
252
|
+
userSelectListRef.current = []
|
|
253
|
+
userSelectListWithIdsRef.current = []
|
|
228
254
|
}
|
|
229
255
|
}
|
|
230
256
|
};
|