Skip to content

feat: add removeInvalidMentionContent prop - #858

Open
JaydeepAgravat wants to merge 2 commits into
software-mansion:mainfrom
JaydeepAgravat:feat/remove-invalid-mention-content
Open

JaydeepAgravat wants to merge 2 commits into
software-mansion:mainfrom
JaydeepAgravat:feat/remove-invalid-mention-content

Conversation

@JaydeepAgravat

@JaydeepAgravat JaydeepAgravat commented Nov 8, 2026 •

Copy link
Copy Markdown

Summary

Closes #855.

Adds a removeInvalidMentionContent prop. When it's true, any change to the text of an inserted mention (typing inside it, deleting part of it, autocorrect) removes the whole mention. When it's false (the default), nothing changes: the text stays and is no longer a mention.

iOS and web already have a check for "this mention's text no longer matches", and the prop changes what happens there. Android gets a small one next to its existing stale-span handling:

  • iOS: MentionStyle.handleExistingMentions deletes the text instead of removing the attribute. Text typed inside a mention doesn't get the mention attribute, so it splits the mention into two runs with the same params; those are deleted together with the typed text in between.
  • Android: ParametrizedStyles.afterTextChanged checks the mention spans and deletes a span whose text no longer matches. I didn't branch inside detectActiveMention, because it only looks at the word around the cursor and misses mentions whose text has no indicator.
  • Web: removeMentionMarksIfSpansResized deletes the range instead of removing the mark.

On all three: the space after the mention stays, the cursor ends up where the mention started, and edits right before or after a mention don't count. One iOS-only case: a mention loaded from HTML whose text attribute doesn't match its content is removed on load. That's the same check that already strips such mentions on iOS today; Android and web don't check on load.

Two choices you may want differently:

  1. The character typed inside the mention is removed along with it. Keeping it would mean telling the typed text apart from the mention's text on iOS and Android.
  2. The space after the mention is kept. On iOS setMention reuses a space that's already there, so the space can't always be counted as part of the mention.

Test Plan

Example app (Dev Screen, removeInvalidMentionContent button) or /test-mentions on web:

  1. Type @J and pick a user.
  2. Put the cursor inside the name and type a character: the whole mention goes away, and the HTML has no <mention>.
  3. Backspace inside the name: same.
  4. Type right after the name: the mention stays.
  5. With the toggle off, everything behaves as on main.

Automated:

  • Jest: removeMentionMarksIfSpansResized.test.ts covers both modes, editing at the edge, and two mentions changed in one edit.
  • Playwright: 4 cases in mentions.spec.ts (default behaviour, typing inside, backspace inside, typing right after).

I checked steps 1–5 by hand on the iOS simulator (iPhone 17 Pro, iOS 26.5), the Android emulator (Pixel 5, Gboard) and Chrome.

I put the toggle on the Dev Screen rather than the Test Screen so the Test Screen's Maestro screenshots don't change.

Screenshots / Videos

iOS

ios.mp4

Android

android.mp4

Web

web.webm

Compatibility

OS Implemented
iOS ✅
Android ✅
Web ✅

Checklist

  • E2E tests are passing
  • Required E2E tests have been added (if applicable)

Web E2E pass locally in Chrome, except mention renders correctly, which is a screenshot test that needs the Docker browser. I couldn't run the Maestro/Argent mobile E2E.

When true, changing the text of an inserted mention (typing inside it,
deleting part of it, autocorrect) removes the whole mention instead of
leaving plain text. Defaults to false, so the current behaviour is
unchanged.

Closes software-mansion#855
@JaydeepAgravat
JaydeepAgravat marked this pull request as ready for review November 8, 2026 07:01
Copilot AI balanced review requested due to automatic review settings November 8, 2026 07:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Active issues include an Android crash when deleting across two mentions and incomplete mention-content removal on web and iOS, including during initial mount.

4 open issues
What changed in this PR

Adds the opt-in removeInvalidMentionContent prop to address #855, allowing edited mentions to be removed entirely rather than converted to plain text across iOS, Android, and web.

Changes:

  • Exposes the prop through public types, native bindings, and web configuration, defaulting to false.
  • Adds platform-specific deletion handling for invalid mentions.
  • Documents the behavior and adds example toggles, web unit tests, and browser tests.
File Description
src/​web/​pmPlugins/​MentionPlugin/​types.ts Adds the removal-mode option getter.
src/​web/​pmPlugins/​MentionPlugin/​removeMentionMarksIfSpansResized.ts Adds deletion of resized mention ranges.
src/​web/​pmPlugins/​MentionPlugin/​index.ts Passes the removal option into cleanup.
src/​web/​EnrichedTextInput.tsx Connects the prop to the mention plugin.
src/​web/​__tests__/​removeMentionMarksIfSpansResized.test.ts Tests cleanup modes and edit boundaries.
src/​types.ts Defines and documents the public prop.
src/​spec/​EnrichedTextInputNativeComponent.ts Adds the native component prop.
src/​native/​EnrichedTextInput.tsx Forwards the prop to native implementations.
ios/​styles/​MentionStyle.mm Deletes invalid mention content in removal mode.
ios/​EnrichedTextInputView.mm Applies the prop to iOS configuration.
ios/​config/​EnrichedConfig.mm Stores, copies, and exposes the setting.
ios/​config/​EnrichedConfig.h Declares configuration accessors.
docs/​docs/​rich-text-formatting/​mentions.mdx Explains mention-editing behavior.
docs/​docs/​api-reference/​enriched-text-input.md Documents the prop and platform support.
apps/​example/​src/​screens/​DevScreen.tsx Adds a native example toggle.
apps/​example-web/​src/​testScreens/​TestMentions.tsx Adds a web test-screen toggle.
android/​src/​main/​java/​com/​swmansion/​enriched/​textinput/​styles/​ParametrizedStyles.kt Detects and deletes invalid mention spans.
android/​src/​main/​java/​com/​swmansion/​enriched/​textinput/​EnrichedTextInputViewManager.kt Exposes the Android prop setter.
.playwright/​tests/​mentions.spec.ts Tests default behavior, deletion, and boundary typing.

Review effort: Balanced

Comment thread ios/EnrichedTextInputView.mm Resolved
Comment thread ios/styles/MentionStyle.mm Resolved
- Android: skip mention spans the nested watcher pass already removed,
  which crashed when a deletion touched two mentions
- iOS: apply the prop before defaultValue, and check the text of
  mentions that end up touching each other
- web: also compare the mention text, so same-length edits count

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Typing or autocorrecting inside a mention strips it to plain text

2 participants