react-mention-input 1.1.4 → 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 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: {messageText: string, messageHTML: string}) => void` | Callback function triggered on sending a message, providing both plain text and HTML. |
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
@@ -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
  }
@@ -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
- // Regular expression for mentions
16
- var mentionRegex = /@([^\s]+(?: [^\s]+)?)(?=\s|$)/g;
17
- // First, highlight mentions
18
- var highlightedText = text.replace(mentionRegex, '<span class="mention-highlight">@$1</span>');
19
- // Then, highlight links
20
- highlightedText = highlightedText.replace(linkRegex, '<a href="$1" target="_blank" rel="noopener noreferrer" class="link-highlight">$1</a>');
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>&nbsp;");
24
+ });
25
+ });
21
26
  return highlightedText;
22
27
  };
23
28
  var restoreCaretPosition = function (node, caretOffset) {
@@ -122,33 +127,53 @@ 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
- var newValue = plainText.substring(0, mentionIndex + 1) + user.name + plainText.substring(caretOffset);
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 &nbsp;
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
  };
168
+ var handleKeyDown = function (event) {
169
+ if (event.key === "Enter" && !event.shiftKey) {
170
+ event.preventDefault(); // Prevent newline in content-editable
171
+ handleSendMessage(); // Trigger the same function as the Send button
172
+ }
173
+ };
149
174
  return (React.createElement("div", { className: "mention-container ".concat(containerClassName || "") },
150
175
  React.createElement("div", { className: "mention-input-container ".concat(inputContainerClassName || "") },
151
- React.createElement("div", { ref: inputRef, contentEditable: true, suppressContentEditableWarning: true, className: "mention-input ".concat(inputClassName || ""), onInput: handleInputChange }),
176
+ React.createElement("div", { ref: inputRef, contentEditable: true, suppressContentEditableWarning: true, className: "mention-input ".concat(inputClassName || ""), onInput: handleInputChange, onKeyDown: handleKeyDown }),
152
177
  React.createElement("button", { onClick: handleSendMessage, className: "send-button ".concat(sendBtnClassName || "") }, sendButtonIcon || "➤")),
153
178
  renderSuggestions()));
154
179
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-mention-input",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -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
- // Regular expression for mentions
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>&nbsp;`;
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 &nbsp;
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,14 +245,23 @@ 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
  };
231
257
 
258
+ const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
259
+ if (event.key === "Enter" && !event.shiftKey) {
260
+ event.preventDefault(); // Prevent newline in content-editable
261
+ handleSendMessage(); // Trigger the same function as the Send button
262
+ }
263
+ };
264
+
232
265
 
233
266
 
234
267
  return (
@@ -240,6 +273,7 @@ const MentionInput: React.FC<MentionInputProps> = ({
240
273
  suppressContentEditableWarning
241
274
  className={`mention-input ${inputClassName || ""}`}
242
275
  onInput={handleInputChange}
276
+ onKeyDown={handleKeyDown} // Add keydown listener
243
277
  ></div>
244
278
  <button
245
279
  onClick={handleSendMessage}