Commit a035363
Fix: [iOS][Fabric] Correctly mark inline attachments as clipped when in truncated text range (#55518)
Summary:
### Title
[iOS] Inline attachments in truncated Text still visible (Fabric)
---
### Description
On iOS with the New Architecture (Fabric), inline attachments in a `<Text>` that lie beyond the `numberOfLines` limit are still being rendered instead of being clipped.
As a result, the attachment that should be clipped appears just above its wrapper. See screenshots below.
---
### MANDATORY Reproducer
https://snack.expo.dev/kamildelekta/truncatedtextattachmentvisiblebug
---
### Screenshots of issue
Only `maxLines` changes between these two screenshots. You can check it yourself in the expo snack above.
| Text | Truncated Text |
| --------- | ------- |
|<img width="250" height="1027" alt="maxLines4" src="https://github.com/user-attachments/assets/bc93a03a-7819-4ec6-84ab-dea2bd7cbe6c" /> | <img width="250" height="1029" alt="maxLines3" src="https://github.com/user-attachments/assets/25eee68d-ef10-40d2-a657-b9dc9e158c1b" /> |
### React Native Version
```
"react-native": "0.83.0"
```
---
### Affected Platforms
only IOS New Arch
---
Pull Request resolved: #55518
Test Plan:
**Visible cases**
Tested multiple layouts where the attachment is in range; the attachment is shown and laid out correctly.
**Clipped cases**
Tested both clipping paths: (1) attachment after the last visible line → `isOutsideVisibleRange`; (2) attachment in the truncated "..." range → `isInTruncatedRange`. In both cases the attachment is correctly clipped.
**Context**
Before this change we only had `isInTruncatedRange`. Handling for `isOutsideVisibleRange` was added. The example below shows that these two clipping cases are mutually exclusive; in the app, both cases correctly clip the attachments.
Testing code:
```
<View style={{ flex: 1, justifyContent: 'center', padding: 16, alignItems: 'stretch' }}>
<Text style={{ fontSize: 20, fontWeight: 'bold', marginBottom: 8, color: '#333' }}>
Correctly clipped
</Text>
{/* Case 1: isOutsideVisibleRange: 1, isInTruncatedRange: 0 */}
<Text numberOfLines={3} style={{ fontSize: 18, borderWidth: 1, marginBottom: 16, textAlign: 'justify' }}>
Line 1{'\n'}Line 2{'\n'}Line 3{'\n'}
<View style={{ width: 20, height: 20, backgroundColor: 'red' }} />
</Text>
{/* Case 2: isOutsideVisibleRange: 0, isInTruncatedRange: 1 */}
<Text numberOfLines={1} style={{ fontSize: 18, width: 200, borderWidth: 1, marginBottom: 8 }}>
Long text that truncates with ellipsis
<View style={{ width: 20, height: 20, backgroundColor: 'blue' }} />
</Text>
<Text style={{ fontSize: 20, fontWeight: 'bold', marginTop: 16, marginBottom: 8, color: '#333' }}>
Visible
</Text>
<Text style={{ fontSize: 12, color: '#666', marginBottom: 4, marginTop: 8 }}>First char</Text>
<Text numberOfLines={2} style={{ fontSize: 18, borderWidth: 1, marginBottom: 16, textAlign: 'justify' }}>
<View style={{ width: 20, height: 20, backgroundColor: 'green' }} />
text after attachment
</Text>
<Text style={{ fontSize: 12, color: '#666', marginBottom: 4 }}>Middle of line</Text>
<Text numberOfLines={3} style={{ fontSize: 18, borderWidth: 1, marginBottom: 16, textAlign: 'justify' }}>
Line 1{'\n'}Line 2 with
<View style={{ width: 20, height: 20, backgroundColor: 'green' }} />
{'\n'}Line 3
</Text>
<Text style={{ fontSize: 12, color: '#666', marginBottom: 4 }}>End of line 1</Text>
<Text numberOfLines={3} style={{ fontSize: 18, borderWidth: 1, marginBottom: 16, textAlign: 'justify' }}>
Line 1
<View style={{ width: 20, height: 20, backgroundColor: 'orange' }} />
{'\n'}Line 2{'\n'}Line 3
</Text>
<Text style={{ fontSize: 12, color: '#666', marginBottom: 4 }}>Short text, end</Text>
<Text style={{ fontSize: 18, borderWidth: 1, marginBottom: 16, textAlign: 'justify' }}>
Short text
<View style={{ width: 20, height: 20, backgroundColor: 'orange' }} />
</Text>
<Text style={{ fontSize: 12, color: '#666', marginBottom: 4 }}>Only attachment on line</Text>
<Text numberOfLines={2} style={{ fontSize: 18, borderWidth: 1, textAlign: 'justify' }}>
<View style={{ width: 20, height: 20, backgroundColor: 'purple' }} />
{'\n'}Second line
</Text>
</View>
```
and here some examples:
| oldArch | newArch | newArch fixed
| --------- | ------- | ------- |
|<img width="250" height="2622" alt="oldArch" src="https://github.com/user-attachments/assets/aaffac4c-f3da-43ff-9560-7eb6e5258eb3" /> | <img width="250" height="2622" alt="newArch" src="https://github.com/user-attachments/assets/8905bb4e-8431-4f4d-ae46-770705520a61" /> | <img width="250" height="2622" alt="newArchFixed" src="https://github.com/user-attachments/assets/f786178e-438d-4a90-8ccf-9802181b5d8c" />|
---
## Changelog:
[iOS] [Fixed] - Inline attachments after the last visible line in truncated text are now correctly marked as clipped.
---
### Output of `npx react-native-community/cli info`
```
System:
OS: macOS 26.2
CPU: (12) arm64 Apple M4 Pro
Memory: 982.39 MB / 48.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.14.0
path: /nix/store/04fc23dsflkxl4s9p6lkigia1hq3vjp2-nodejs-22.14.0/bin/node
Yarn:
version: 1.22.19
path: /Users/kamil/.nix-profile/bin/yarn
npm:
version: 10.9.2
path: /nix/store/04fc23dsflkxl4s9p6lkigia1hq3vjp2-nodejs-22.14.0/bin/npm
Watchman:
version: 2024.03.11.00
path: /Users/kamil/.nix-profile/bin/watchman
Managers:
CocoaPods:
version: 1.15.2
path: /Users/kamil/.nix-profile/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.2
- iOS 26.2
- macOS 26.2
- tvOS 26.2
- visionOS 26.2
- watchOS 26.2
Android SDK: Not Found
IDEs:
Android Studio: Not Found
Xcode:
version: 26.2/17C52
path: /usr/bin/xcodebuild
Languages:
Java: Not Found
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"react-native-community/cli":
installed: 20.0.0
wanted: 20.0.0
react:
installed: 19.2.0
wanted: 19.2.0
react-native:
installed: 0.83.0
wanted: 0.83.0
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
info React Native v0.83.2 is now available (your project is running on v0.83.0).
```
---
Reviewed By: NickGerleman
Differential Revision: D92991293
Pulled By: CalixTang
fbshipit-source-id: ebd097c4311a18e0f628fe5dd3eec353582ce4231 parent 4ef7ac3 commit a035363
1 file changed
Lines changed: 11 additions & 1 deletion
File tree
- packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager
Lines changed: 11 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
391 | 391 | | |
392 | 392 | | |
393 | 393 | | |
| 394 | + | |
| 395 | + | |
394 | 396 | | |
395 | 397 | | |
396 | 398 | | |
| |||
406 | 408 | | |
407 | 409 | | |
408 | 410 | | |
409 | | - | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
410 | 420 | | |
411 | 421 | | |
412 | 422 | | |
| |||
0 commit comments