Skip to content

Commit bbcc919

Browse files
authored
fix(mention): allow mention trigger in middle of text (#166)
Fixes #88 - Improved text detection logic to check if text after cursor is separated or part of existing mention - Fixed mention insertion to properly update existing mentions' positions when inserting in middle of text - Mentions now trigger correctly regardless of position within input
1 parent 48fc0ba commit bbcc919

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

packages/mention/src/mention-input.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,23 @@ const MentionInput = React.forwardRef<InputElement, MentionInputProps>(
204204
const isImmediatelyAfterTrigger =
205205
currentPosition === lastTriggerIndex + 1;
206206

207-
// Check if there's any text after the cursor position
208-
const textAfterCursor = value.slice(currentPosition).trim();
209-
const hasCompletedText =
210-
textAfterCursor.length > 0 && !textAfterCursor.startsWith(" ");
211-
if (hasCompletedText) {
207+
const textAfterCursor = value.slice(currentPosition);
208+
const firstCharAfterCursor = textAfterCursor[0];
209+
const isTextAfterCursorSeparated =
210+
!firstCharAfterCursor ||
211+
firstCharAfterCursor === " " ||
212+
firstCharAfterCursor === "\n" ||
213+
firstCharAfterCursor === context.trigger;
214+
const isTextAfterCursorPartOfMention = context.mentions.some(
215+
(mention) =>
216+
currentPosition >= mention.start && currentPosition < mention.end,
217+
);
218+
const hasInterferingText =
219+
textAfterCursor.length > 0 &&
220+
!isTextAfterCursorSeparated &&
221+
!isTextAfterCursorPartOfMention;
222+
223+
if (hasInterferingText) {
212224
if (context.open) {
213225
context.onOpenChange(false);
214226
context.onHighlightedItemChange(null);

packages/mention/src/mention-root.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,18 +294,31 @@ const MentionRoot = React.forwardRef<RootElement, MentionRootProps>(
294294
?.label ?? payloadValue;
295295
const mentionText = `${trigger}${mentionLabel}`;
296296
const beforeTrigger = input.value.slice(0, triggerIndex);
297-
const afterSearchText = input.value.slice(
298-
input.selectionStart ?? triggerIndex,
299-
);
297+
const insertionPoint = input.selectionStart ?? triggerIndex;
298+
const afterSearchText = input.value.slice(insertionPoint);
300299
const newValue = `${beforeTrigger}${mentionText} ${afterSearchText}`;
301300

301+
const insertionLength = mentionText.length + 1;
302+
302303
const newMention: Mention = {
303304
value: payloadValue,
304305
start: triggerIndex,
305306
end: triggerIndex + mentionText.length,
306307
};
307308

308-
setMentions((prev) => [...prev, newMention]);
309+
setMentions((prev) => {
310+
const updatedMentions = prev.map((mention) => {
311+
if (mention.start >= insertionPoint) {
312+
return {
313+
...mention,
314+
start: mention.start + insertionLength,
315+
end: mention.end + insertionLength,
316+
};
317+
}
318+
return mention;
319+
});
320+
return [...updatedMentions, newMention];
321+
});
309322

310323
input.value = newValue;
311324
setInputValue(newValue);

0 commit comments

Comments
 (0)