react-mention-input 1.1.3 → 1.1.5
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/dist/MentionInput.css +9 -0
- package/dist/MentionInput.js +19 -5
- package/package.json +1 -1
- package/src/MentionInput.css +9 -0
- package/src/MentionInput.tsx +37 -13
package/dist/MentionInput.css
CHANGED
package/dist/MentionInput.js
CHANGED
|
@@ -9,8 +9,16 @@ var MentionInput = function (_a) {
|
|
|
9
9
|
var inputRef = useRef(null);
|
|
10
10
|
var suggestionListRef = useRef(null);
|
|
11
11
|
var caretOffsetRef = useRef(0);
|
|
12
|
-
var
|
|
13
|
-
|
|
12
|
+
var highlightMentionsAndLinks = function (text) {
|
|
13
|
+
// Regular expression for detecting links
|
|
14
|
+
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>');
|
|
21
|
+
return highlightedText;
|
|
14
22
|
};
|
|
15
23
|
var restoreCaretPosition = function (node, caretOffset) {
|
|
16
24
|
var range = document.createRange();
|
|
@@ -70,7 +78,7 @@ var MentionInput = function (_a) {
|
|
|
70
78
|
setShowSuggestions(false);
|
|
71
79
|
}
|
|
72
80
|
var previousHTML = inputRef.current.innerHTML;
|
|
73
|
-
var htmlWithHighlights =
|
|
81
|
+
var htmlWithHighlights = highlightMentionsAndLinks(plainText); // Updated function
|
|
74
82
|
if (previousHTML !== htmlWithHighlights) {
|
|
75
83
|
inputRef.current.innerHTML = htmlWithHighlights;
|
|
76
84
|
}
|
|
@@ -120,7 +128,7 @@ var MentionInput = function (_a) {
|
|
|
120
128
|
var newValue = plainText.substring(0, mentionIndex + 1) + user.name + plainText.substring(caretOffset);
|
|
121
129
|
setInputValue(newValue);
|
|
122
130
|
inputRef.current.innerText = newValue;
|
|
123
|
-
var htmlWithHighlights =
|
|
131
|
+
var htmlWithHighlights = highlightMentionsAndLinks(newValue);
|
|
124
132
|
inputRef.current.innerHTML = htmlWithHighlights;
|
|
125
133
|
setShowSuggestions(false);
|
|
126
134
|
var mentionEnd = mentionIndex + user.name.length + 1;
|
|
@@ -138,9 +146,15 @@ var MentionInput = function (_a) {
|
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
148
|
};
|
|
149
|
+
var handleKeyDown = function (event) {
|
|
150
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
151
|
+
event.preventDefault(); // Prevent newline in content-editable
|
|
152
|
+
handleSendMessage(); // Trigger the same function as the Send button
|
|
153
|
+
}
|
|
154
|
+
};
|
|
141
155
|
return (React.createElement("div", { className: "mention-container ".concat(containerClassName || "") },
|
|
142
156
|
React.createElement("div", { className: "mention-input-container ".concat(inputContainerClassName || "") },
|
|
143
|
-
React.createElement("div", { ref: inputRef, contentEditable: true, suppressContentEditableWarning: true, className: "mention-input ".concat(inputClassName || ""), onInput: handleInputChange }),
|
|
157
|
+
React.createElement("div", { ref: inputRef, contentEditable: true, suppressContentEditableWarning: true, className: "mention-input ".concat(inputClassName || ""), onInput: handleInputChange, onKeyDown: handleKeyDown }),
|
|
144
158
|
React.createElement("button", { onClick: handleSendMessage, className: "send-button ".concat(sendBtnClassName || "") }, sendButtonIcon || "➤")),
|
|
145
159
|
renderSuggestions()));
|
|
146
160
|
};
|
package/package.json
CHANGED
package/src/MentionInput.css
CHANGED
package/src/MentionInput.tsx
CHANGED
|
@@ -42,11 +42,26 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
42
42
|
const suggestionListRef = useRef<HTMLUListElement>(null);
|
|
43
43
|
const caretOffsetRef = useRef<number>(0);
|
|
44
44
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const highlightMentionsAndLinks = (text: string): string => {
|
|
46
|
+
// Regular expression for detecting links
|
|
47
|
+
const linkRegex = /(https?:\/\/[^\s]+)/g;
|
|
48
|
+
|
|
49
|
+
// Regular expression for mentions
|
|
50
|
+
const mentionRegex = /@([^\s]+(?: [^\s]+)?)(?=\s|$)/g;
|
|
51
|
+
|
|
52
|
+
// First, highlight mentions
|
|
53
|
+
let highlightedText = text.replace(
|
|
54
|
+
mentionRegex,
|
|
48
55
|
'<span class="mention-highlight">@$1</span>'
|
|
49
56
|
);
|
|
57
|
+
|
|
58
|
+
// Then, highlight links
|
|
59
|
+
highlightedText = highlightedText.replace(
|
|
60
|
+
linkRegex,
|
|
61
|
+
'<a href="$1" target="_blank" rel="noopener noreferrer" class="link-highlight">$1</a>'
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return highlightedText;
|
|
50
65
|
};
|
|
51
66
|
|
|
52
67
|
const restoreCaretPosition = (node: HTMLElement, caretOffset: number) => {
|
|
@@ -82,10 +97,10 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
82
97
|
|
|
83
98
|
const handleInputChange = () => {
|
|
84
99
|
if (!inputRef.current) return;
|
|
85
|
-
|
|
100
|
+
|
|
86
101
|
const selection = window.getSelection();
|
|
87
102
|
const range = selection?.getRangeAt(0);
|
|
88
|
-
|
|
103
|
+
|
|
89
104
|
let newCaretOffset = 0;
|
|
90
105
|
if (range && inputRef.current.contains(range.startContainer)) {
|
|
91
106
|
const preCaretRange = range.cloneRange();
|
|
@@ -93,31 +108,32 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
93
108
|
preCaretRange.setEnd(range.startContainer, range.startOffset);
|
|
94
109
|
newCaretOffset = preCaretRange.toString().length;
|
|
95
110
|
}
|
|
96
|
-
|
|
111
|
+
|
|
97
112
|
caretOffsetRef.current = newCaretOffset;
|
|
98
|
-
|
|
113
|
+
|
|
99
114
|
const plainText = inputRef.current.innerText;
|
|
100
115
|
setInputValue(plainText);
|
|
101
|
-
|
|
116
|
+
|
|
102
117
|
const mentionMatch = plainText.slice(0, newCaretOffset).match(/@(\S*)$/);
|
|
103
118
|
if (mentionMatch) {
|
|
104
119
|
const query = mentionMatch[1].toLowerCase();
|
|
105
120
|
const filteredUsers = query === "" ? users : users.filter((user) => user.name.toLowerCase().startsWith(query));
|
|
106
|
-
|
|
121
|
+
|
|
107
122
|
setSuggestions(filteredUsers);
|
|
108
123
|
setShowSuggestions(filteredUsers.length > 0);
|
|
109
124
|
} else {
|
|
110
125
|
setShowSuggestions(false);
|
|
111
126
|
}
|
|
112
|
-
|
|
127
|
+
|
|
113
128
|
const previousHTML = inputRef.current.innerHTML;
|
|
114
|
-
const htmlWithHighlights =
|
|
129
|
+
const htmlWithHighlights = highlightMentionsAndLinks(plainText); // Updated function
|
|
115
130
|
if (previousHTML !== htmlWithHighlights) {
|
|
116
131
|
inputRef.current.innerHTML = htmlWithHighlights;
|
|
117
132
|
}
|
|
118
|
-
|
|
133
|
+
|
|
119
134
|
restoreCaretPosition(inputRef.current, newCaretOffset);
|
|
120
135
|
};
|
|
136
|
+
|
|
121
137
|
|
|
122
138
|
const renderSuggestions = () => {
|
|
123
139
|
if (!showSuggestions || !inputRef.current) return null;
|
|
@@ -190,7 +206,7 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
190
206
|
setInputValue(newValue);
|
|
191
207
|
inputRef.current.innerText = newValue;
|
|
192
208
|
|
|
193
|
-
const htmlWithHighlights =
|
|
209
|
+
const htmlWithHighlights = highlightMentionsAndLinks(newValue);
|
|
194
210
|
inputRef.current.innerHTML = htmlWithHighlights;
|
|
195
211
|
|
|
196
212
|
setShowSuggestions(false);
|
|
@@ -213,6 +229,13 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
213
229
|
}
|
|
214
230
|
};
|
|
215
231
|
|
|
232
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
233
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
234
|
+
event.preventDefault(); // Prevent newline in content-editable
|
|
235
|
+
handleSendMessage(); // Trigger the same function as the Send button
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
216
239
|
|
|
217
240
|
|
|
218
241
|
return (
|
|
@@ -224,6 +247,7 @@ const MentionInput: React.FC<MentionInputProps> = ({
|
|
|
224
247
|
suppressContentEditableWarning
|
|
225
248
|
className={`mention-input ${inputClassName || ""}`}
|
|
226
249
|
onInput={handleInputChange}
|
|
250
|
+
onKeyDown={handleKeyDown} // Add keydown listener
|
|
227
251
|
></div>
|
|
228
252
|
<button
|
|
229
253
|
onClick={handleSendMessage}
|