Skip to content

Add TextEffect component and registry for custom text span effects#56720

Open
andrewdacenko wants to merge 2 commits intofacebook:mainfrom
andrewdacenko:export-D98812222
Open

Add TextEffect component and registry for custom text span effects#56720
andrewdacenko wants to merge 2 commits intofacebook:mainfrom
andrewdacenko:export-D98812222

Conversation

@andrewdacenko
Copy link
Copy Markdown
Contributor

Summary:
Introduces a generic TextEffect system that lets apps register custom text
span effects without modifying React Native core. This can serve for use cases like react-native-live-markdown, or product specific effects.

The implementation is pretty dumb right now. It's just a marker, where we can add some JSON serializable data, to be serialized during Spannable creation on JS side MapBuffer.

JS API:

import requireNativeTextEffect from 'react-native/Libraries/Text/requireNativeTextEffect';
const Spoiler = requireNativeTextEffect<{}>('RCTSpoiler');

<Text>Normal <Spoiler>hidden text</Spoiler></Text>

Android registration (via FabricUIManager):

val fabricUIManager = UIManagerHelper.getUIManager(
    context, UIManagerType.FABRIC) as? FabricUIManager
fabricUIManager?.textEffectRegistry?.register("RCTSpoiler") { props ->
    MyCustomSpan()
}

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D98812222

…acebook#56709)

Summary:

Changelog: [Internal]

Introduces `TouchableSpan`, an interface for spans that receive full
`MotionEvent` touch events from `PreparedLayoutTextView`. Unlike
`ClickableSpan` which only provides an `onClick` callback with no
position information, `TouchableSpan` receives the full `MotionEvent`,
enabling position-aware interactions such as dismiss animations
originating from the tap point.

Reviewed By: Abbondanzo

Differential Revision: D97417356
Summary:
Introduces a generic TextEffect system that lets apps register custom text
span effects without modifying React Native core. This can serve for use cases like `react-native-live-markdown`, or product specific effects.

The implementation is pretty dumb right now. It's just a marker, where we can add some JSON serializable data, to be serialized during Spannable creation on JS side MapBuffer. 

**JS API:**
```js
import requireNativeTextEffect from 'react-native/Libraries/Text/requireNativeTextEffect';
const Spoiler = requireNativeTextEffect<{}>('RCTSpoiler');

<Text>Normal <Spoiler>hidden text</Spoiler></Text>
```

**Android registration** (via FabricUIManager):
```kotlin
val fabricUIManager = UIManagerHelper.getUIManager(
    context, UIManagerType.FABRIC) as? FabricUIManager
fabricUIManager?.textEffectRegistry?.register("RCTSpoiler") { props ->
    MyCustomSpan()
}
```

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D98812222
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 7, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented May 7, 2026

@andrewdacenko has exported this pull request. If you are a Meta employee, you can view the originating Diff in D98812222.

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant