Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions src/Mentions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ const InternalMentions = forwardRef<MentionsRef, InternalMentionsProps>(
* 1. Selection is out of range
* 2. Contains `space`
* 3. ESC or select one
* 4. The measured prefix is removed from the text
*/
const onInternalKeyUp: React.KeyboardEventHandler<
HTMLTextAreaElement
Expand Down Expand Up @@ -480,29 +481,47 @@ const InternalMentions = forwardRef<MentionsRef, InternalMentionsProps>(
const validateMeasure: boolean = validateSearch(nextMeasureText, split);
const matchOption = !!getOptions(nextMeasureText).length;

if (validateMeasure) {
// adding AltGraph also fort azert keyboard
if (
key === nextMeasurePrefix ||
key === 'Shift' ||
which === KeyCode.ALT ||
key === 'AltGraph' ||
mergedMeasuring ||
(nextMeasureText !== mergedMeasureText && matchOption)
) {
startMeasure(nextMeasureText, nextMeasurePrefix, measureIndex);
}
} else if (mergedMeasuring) {
// Stop if measureText is invalidate
// adding AltGraph also fort azert keyboard
const isTypingPrefix =
key === nextMeasurePrefix ||
key === 'Shift' ||
which === KeyCode.ALT ||
key === 'AltGraph';

// The measured prefix may be removed from the text (e.g. user deletes
// the `@` char just typed). Stop measuring instead of re-anchor to a
// previous prefix in the text which user is not typing at.
const measurePrefixExist =
isTypingPrefix ||
!mergedMeasuring ||
selectionStartText.slice(
mergedMeasureLocation,
mergedMeasureLocation + mergedMeasurePrefix.length,
) === mergedMeasurePrefix;

if (!measurePrefixExist) {
stopMeasure();
}
} else {
if (validateMeasure) {
if (
isTypingPrefix ||
mergedMeasuring ||
(nextMeasureText !== mergedMeasureText && matchOption)
) {
startMeasure(nextMeasureText, nextMeasurePrefix, measureIndex);
}
} else if (mergedMeasuring) {
// Stop if measureText is invalidate
stopMeasure();
}

/**
* We will trigger `onSearch` to developer since they may use for async update.
* If met `space` means user finished searching.
*/
if (onSearch && validateMeasure) {
onSearch(nextMeasureText, nextMeasurePrefix);
/**
* We will trigger `onSearch` to developer since they may use for async update.
* If met `space` means user finished searching.
*/
if (onSearch && validateMeasure) {
onSearch(nextMeasureText, nextMeasurePrefix);
}
}
} else if (mergedMeasuring) {
stopMeasure();
Expand Down
27 changes: 27 additions & 0 deletions tests/FullProcess.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,33 @@ describe('Full Process', () => {
expectMeasuring(container, false);
});

it('stop measure if remove prefix and previous prefix exists', () => {
const { container } = createMentions({ defaultValue: '@zz' });

// Type `@` again which will start measure
simulateInput(container, '@zz@');
expectMeasuring(container);

// Remove the measured `@`, measure should stop instead of
// re-anchor to the previous `@` in the text
const textarea = container.querySelector('textarea');
fireEvent.keyDown(textarea, {
keyCode: KeyCode.BACKSPACE,
which: KeyCode.BACKSPACE,
key: 'Backspace',
});
fireEvent.change(textarea, {
target: { value: '@zz', selectionStart: '@zz'.length },
});
fireEvent.keyUp(textarea, {
keyCode: KeyCode.BACKSPACE,
which: KeyCode.BACKSPACE,
key: 'Backspace',
});

expectMeasuring(container, false);
});

it('should not call onPressEnter when measuring', () => {
const onPressEnter = jest.fn();
const { container } = createMentions({ onPressEnter });
Expand Down