diff --git a/modules/react-native-ui-text-view/android/build.gradle b/modules/react-native-ui-text-view/android/build.gradle
new file mode 100644
index 0000000000..beb57dba92
--- /dev/null
+++ b/modules/react-native-ui-text-view/android/build.gradle
@@ -0,0 +1,94 @@
+buildscript {
+ // Buildscript is evaluated before everything else so we can't use getExtOrDefault
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["UiTextView_kotlinVersion"]
+
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "com.android.tools.build:gradle:7.2.1"
+ // noinspection DifferentKotlinGradleVersion
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+def isNewArchitectureEnabled() {
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
+}
+
+apply plugin: "com.android.library"
+apply plugin: "kotlin-android"
+
+if (isNewArchitectureEnabled()) {
+ apply plugin: "com.facebook.react"
+}
+
+def getExtOrDefault(name) {
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["UiTextView_" + name]
+}
+
+def getExtOrIntegerDefault(name) {
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["UiTextView_" + name]).toInteger()
+}
+
+def supportsNamespace() {
+ def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
+ def major = parsed[0].toInteger()
+ def minor = parsed[1].toInteger()
+
+ // Namespace support was added in 7.3.0
+ return (major == 7 && minor >= 3) || major >= 8
+}
+
+android {
+ if (supportsNamespace()) {
+ namespace "com.uitextview"
+
+ sourceSets {
+ main {
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
+ }
+ }
+ }
+
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
+
+ defaultConfig {
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
+
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+
+ lintOptions {
+ disable "GradleCompatible"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+repositories {
+ mavenCentral()
+ google()
+}
+
+def kotlin_version = getExtOrDefault("kotlinVersion")
+
+dependencies {
+ // For < 0.71, this will be from the local maven repo
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
+ //noinspection GradleDynamicVersion
+ implementation "com.facebook.react:react-native:+"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+}
+
diff --git a/modules/react-native-ui-text-view/android/gradle.properties b/modules/react-native-ui-text-view/android/gradle.properties
new file mode 100644
index 0000000000..f60fa36f9a
--- /dev/null
+++ b/modules/react-native-ui-text-view/android/gradle.properties
@@ -0,0 +1,5 @@
+UiTextView_kotlinVersion=1.7.0
+UiTextView_minSdkVersion=21
+UiTextView_targetSdkVersion=31
+UiTextView_compileSdkVersion=31
+UiTextView_ndkversion=21.4.7075529
diff --git a/modules/react-native-ui-text-view/android/src/main/AndroidManifest.xml b/modules/react-native-ui-text-view/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..5fc0734b47
--- /dev/null
+++ b/modules/react-native-ui-text-view/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/modules/react-native-ui-text-view/android/src/main/AndroidManifestNew.xml b/modules/react-native-ui-text-view/android/src/main/AndroidManifestNew.xml
new file mode 100644
index 0000000000..a2f47b6057
--- /dev/null
+++ b/modules/react-native-ui-text-view/android/src/main/AndroidManifestNew.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewPackage.kt b/modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewPackage.kt
new file mode 100644
index 0000000000..58eb101f2f
--- /dev/null
+++ b/modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewPackage.kt
@@ -0,0 +1,17 @@
+package com.uitextview
+
+import com.facebook.react.ReactPackage
+import com.facebook.react.bridge.NativeModule
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.ViewManager
+
+
+class UiTextViewPackage : ReactPackage {
+ override fun createNativeModules(reactContext: ReactApplicationContext): List {
+ return emptyList()
+ }
+
+ override fun createViewManagers(reactContext: ReactApplicationContext): List> {
+ return listOf(UiTextViewViewManager())
+ }
+}
diff --git a/modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewViewManager.kt b/modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewViewManager.kt
new file mode 100644
index 0000000000..f7202fd1b1
--- /dev/null
+++ b/modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewViewManager.kt
@@ -0,0 +1,20 @@
+package com.uitextview
+
+import android.graphics.Color
+import android.view.View
+import com.facebook.react.uimanager.SimpleViewManager
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+
+class UiTextViewViewManager : SimpleViewManager() {
+ override fun getName() = "UiTextViewView"
+
+ override fun createViewInstance(reactContext: ThemedReactContext): View {
+ return View(reactContext)
+ }
+
+ @ReactProp(name = "color")
+ fun setColor(view: View, color: String) {
+ view.setBackgroundColor(Color.parseColor(color))
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/FontStyle.swift b/modules/react-native-ui-text-view/ios/FontStyle.swift
new file mode 100644
index 0000000000..32ae4b8373
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/FontStyle.swift
@@ -0,0 +1,47 @@
+enum FontWeight: String {
+ case bold
+ case normal
+ case one = "100"
+ case two = "200"
+ case three = "300"
+ case four = "400"
+ case five = "500"
+ case six = "600"
+ case seven = "700"
+ case eight = "800"
+ case nine = "900"
+
+ func toFontWeight() -> UIFont.Weight {
+ switch self {
+ case .bold:
+ return .bold
+ case .normal:
+ return .regular
+ case .one:
+ return .ultraLight
+ case .two:
+ return .ultraLight
+ case .three:
+ return .light
+ case .four:
+ return .regular
+ case .five:
+ return .medium
+ case .six:
+ return .semibold
+ case .seven:
+ return .semibold
+ case .eight:
+ return .bold
+ case .nine:
+ return .heavy
+ }
+ }
+}
+
+enum TextDecorationLine: String {
+ case underline
+ case lineThrough = "line-through"
+ case underlineLineThrough = "underline line-through"
+ case normal
+}
diff --git a/modules/react-native-ui-text-view/ios/RNUITextView.swift b/modules/react-native-ui-text-view/ios/RNUITextView.swift
new file mode 100644
index 0000000000..10c283de5e
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/RNUITextView.swift
@@ -0,0 +1,63 @@
+class RNUITextView: UIView {
+ var textView: UITextView
+
+ @objc var numberOfLines: Int = 0 {
+ didSet {
+ print(numberOfLines)
+ textView.textContainer.maximumNumberOfLines = numberOfLines
+ }
+ }
+
+ override init(frame: CGRect) {
+ self.textView = UITextView()
+
+ // Disable scrolling
+ textView.isScrollEnabled = false
+ // Remove all the padding
+ textView.textContainerInset = .zero
+ textView.textContainer.lineFragmentPadding = 0
+
+ // Remove other properties
+ textView.isEditable = false
+ textView.backgroundColor = .clear
+
+ // Init
+ super.init(frame: frame)
+
+ // Add the view
+ addSubview(textView)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // Resolves some animation issues
+ override func reactSetFrame(_ frame: CGRect) {
+ UIView.performWithoutAnimation {
+ super.reactSetFrame(frame)
+ }
+ }
+
+ override func didUpdateReactSubviews() {
+ // Do nothing
+ }
+
+ func setText(string: NSAttributedString, size: CGSize, numberOfLines: Int) -> Void {
+ self.textView.frame.size = size
+ self.textView.textContainer.maximumNumberOfLines = numberOfLines
+ self.textView.attributedText = string
+ }
+
+ @IBAction func callOnPress(_ sender: UITapGestureRecognizer) -> Void {
+ // If we find a child, then call onPress
+// if let child = getPressed(sender) {
+// if textView.selectedTextRange == nil {
+// child.onTextPress()
+// } else {
+// // Clear the selected text range if we are not pressing on a link
+// textView.selectedTextRange = nil
+// }
+// }
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/RNUITextViewChild.swift b/modules/react-native-ui-text-view/ios/RNUITextViewChild.swift
new file mode 100644
index 0000000000..615ff283c0
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/RNUITextViewChild.swift
@@ -0,0 +1,21 @@
+class RNUITextViewChild: UIView {
+ @objc var text: String = "" {
+ didSet {
+ print(text)
+ let superview = self.superview as? RNUITextView
+ }
+ }
+ @objc var textStyle: TextStyle? {
+ didSet {
+ print(textStyle)
+ }
+ }
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/RNUITextViewChildShadowView.swift b/modules/react-native-ui-text-view/ios/RNUITextViewChildShadowView.swift
new file mode 100644
index 0000000000..e0630c6ebd
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/RNUITextViewChildShadowView.swift
@@ -0,0 +1,46 @@
+// We want all of our props to be available in the child's shadow view so we
+// can create the attributed text before mount and calculate the needed size
+// for the view.
+class RNUITextViewChildShadowView: RCTShadowView {
+ @objc var text: String = ""
+ @objc var color: UIColor = .black
+ @objc var fontSize: CGFloat = 16.0
+ @objc var fontStyle: String = "normal"
+ @objc var fontWeight: String = "normal"
+ @objc var letterSpacing: CGFloat = 0.0
+ @objc var lineHeight: CGFloat = 0.0
+ @objc var pointerEvents: NSString?
+
+ override func isYogaLeafNode() -> Bool {
+ return true
+ }
+
+ func getFontWeight() -> UIFont.Weight {
+ switch self.fontWeight {
+ case "bold":
+ return .bold
+ case "normal":
+ return .regular
+ case "100":
+ return .ultraLight
+ case "200":
+ return .ultraLight
+ case "300":
+ return .light
+ case "400":
+ return .regular
+ case "500":
+ return .medium
+ case "600":
+ return .semibold
+ case "700":
+ return .semibold
+ case "800":
+ return .bold
+ case "900":
+ return .heavy
+ default:
+ return .regular
+ }
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/RNUITextViewShadowView.swift b/modules/react-native-ui-text-view/ios/RNUITextViewShadowView.swift
new file mode 100644
index 0000000000..b76bd86760
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/RNUITextViewShadowView.swift
@@ -0,0 +1,153 @@
+class RNUITextViewShadowView: RCTShadowView {
+ // Props
+ @objc var numberOfLines: Int = 0
+ @objc var ellipsizeMode: Int = 0
+ @objc var allowsFontScaling: Bool = true
+
+ var attributedText: NSAttributedString = NSAttributedString()
+ var frameSize: CGSize = CGSize()
+
+ var bridge: RCTBridge
+
+ init(bridge: RCTBridge) {
+ self.bridge = bridge
+ super.init()
+
+ // We need to set a custom measure func here to calculate the height correctly
+ YGNodeSetMeasureFunc(self.yogaNode) { node, width, widthMode, height, heightMode in
+ // Get the shadowview and determine the needed size to set
+ let shadowView = Unmanaged.fromOpaque(YGNodeGetContext(node)).takeUnretainedValue()
+ return shadowView.getNeededSize(maxWidth: width)
+ }
+
+ // Subscribe to ynamic type size changes
+ NotificationCenter.default.addObserver(
+ self,
+ selector: #selector(preferredContentSizeChanged(_:)),
+ name: UIContentSizeCategory.didChangeNotification,
+ object: nil
+ )
+ }
+
+ @objc func preferredContentSizeChanged(_ notification: Notification) {
+ self.setAttributedText()
+ }
+
+ // Tell yoga not to use flexbox
+ override func isYogaLeafNode() -> Bool {
+ return true
+ }
+
+ // We only need to insert text children
+ override func insertReactSubview(_ subview: RCTShadowView!, at atIndex: Int) {
+ if subview.isKind(of: RNUITextViewChildShadowView.self) {
+ super.insertReactSubview(subview, at: atIndex)
+ }
+ }
+
+ // Whenever the subvies update, set the text
+ override func didUpdateReactSubviews() {
+ self.setAttributedText()
+ }
+
+ // Whenever we layout, update the UI
+ override func layoutSubviews(with layoutContext: RCTLayoutContext) {
+ // Don't do anything if the layout is dirty
+ if(YGNodeIsDirty(self.yogaNode)) {
+ return
+ }
+
+ // Update the text
+ self.bridge.uiManager.addUIBlock { uiManager, viewRegistry in
+ guard let textView = viewRegistry?[self.reactTag] as? RNUITextView else {
+ return
+ }
+ textView.setText(string: self.attributedText, size: self.frameSize, numberOfLines: self.numberOfLines)
+ }
+ }
+
+ override func dirtyLayout() {
+ super.dirtyLayout()
+ YGNodeMarkDirty(self.yogaNode)
+ }
+
+ // Update the attributed text whenever changes are made to the subviews.
+ func setAttributedText() -> Void {
+ // Create an attributed string to store each of the segments
+ let finalAttributedString = NSMutableAttributedString()
+
+ self.reactSubviews().forEach { child in
+ guard let child = child as? RNUITextViewChildShadowView else {
+ return
+ }
+ let scaledFontSize = self.allowsFontScaling ?
+ UIFontMetrics.default.scaledValue(for: child.fontSize) : child.fontSize
+
+ // Set some generic attributes that don't need ranges
+ let attributes: [NSAttributedString.Key:Any] = [
+ .font: UIFont.systemFont(
+ ofSize: scaledFontSize,
+ weight: child.getFontWeight()
+ ),
+ .foregroundColor: child.color,
+ ]
+
+ // Create the attributed string with the generic attributes
+ let string = NSMutableAttributedString(string: child.text, attributes: attributes)
+
+ // Set the paragraph style attributes if necessary
+ let paragraphStyle = NSMutableParagraphStyle()
+ paragraphStyle.minimumLineHeight = child.lineHeight
+ paragraphStyle.maximumLineHeight = child.lineHeight
+ string.addAttribute(
+ NSAttributedString.Key.paragraphStyle,
+ value: paragraphStyle,
+ range: NSMakeRange(0, string.length)
+ )
+
+// if let textDecorationLine = child.textDecorationLine {
+// if textDecorationLine == .underline || textDecorationLine == .underlineLineThrough {
+// string.addAttribute(
+// NSAttributedString.Key.underlineStyle,
+// value: NSUnderlineStyle.single.rawValue,
+// range: NSMakeRange(0, string.length)
+// )
+// }
+//
+// if textDecorationLine == .lineThrough || textDecorationLine == .underlineLineThrough {
+// string.addAttribute(
+// NSAttributedString.Key.strikethroughStyle,
+// value: NSUnderlineStyle.single.rawValue,
+// range: NSMakeRange(0, string.length)
+// )
+// }
+// }
+
+ finalAttributedString.append(string)
+ }
+
+ self.attributedText = finalAttributedString
+ }
+
+ // Create a YGSize based on the max width
+ func getNeededSize(maxWidth: Float) -> YGSize {
+
+ // Create a temporary textview
+ let textView = UITextView()
+ textView.attributedText = self.attributedText
+ textView.textContainer.lineFragmentPadding = 0
+ textView.textContainer.maximumNumberOfLines = self.numberOfLines
+ textView.textContainerInset = .zero
+ textView.isScrollEnabled = false
+
+ // Get the max size for sizeThatFits
+ let maxSize = CGSize(width: CGFloat(maxWidth), height: CGFloat(MAXFLOAT))
+
+ // Get the max height
+ let height = textView.sizeThatFits(maxSize).height
+
+ // Save the frame size and return the YGSize
+ self.frameSize = CGSize(width: CGFloat(maxWidth), height: height)
+ return YGSize(width: Float(maxWidth), height: Float(height))
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/TextStyle.swift b/modules/react-native-ui-text-view/ios/TextStyle.swift
new file mode 100644
index 0000000000..57894b182a
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/TextStyle.swift
@@ -0,0 +1,43 @@
+@objcMembers class TextStyle: NSObject {
+ var color: String? = "black"
+ var fontSize: CGFloat? = 16.0
+ var fontStyle: String? = "normal"
+ var fontWeight: String?
+ var letterSpacing: Float?
+ var textAlign: String? = "auto"
+ var lineHeight: Float?
+ var textDecorationLine: String?
+ var flex: Int?
+ var pointerEvents: String?
+
+ func parseFontWeight() -> UIFont.Weight {
+ switch self.fontWeight {
+ case "bold":
+ return .bold
+ case "normal":
+ return .regular
+ case "100":
+ return .ultraLight
+ case "200":
+ return .ultraLight
+ case "300":
+ return .light
+ case "400":
+ return .regular
+ case "500":
+ return .medium
+ case "600":
+ return .semibold
+ case "700":
+ return .semibold
+ case "800":
+ return .bold
+ case "900":
+ return .heavy
+ case nil:
+ return .regular
+ case .some(_):
+ return .regular
+ }
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/TextUtils.swift b/modules/react-native-ui-text-view/ios/TextUtils.swift
new file mode 100644
index 0000000000..ef69ce5906
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/TextUtils.swift
@@ -0,0 +1,188 @@
+public class TextUtils {
+ public static func hexToUIColor(hex: String?) -> UIColor {
+ guard let hex else {
+ return UIColor.black
+ }
+
+ let r, g, b, a: CGFloat
+
+ if hex.hasPrefix("#") {
+ let start = hex.index(hex.startIndex, offsetBy: 1)
+ let hexColor = String(hex[start...])
+
+ if hexColor.count == 8 {
+ let scanner = Scanner(string: hexColor)
+ var hexNumber: UInt64 = 0
+
+ if scanner.scanHexInt64(&hexNumber) {
+ r = CGFloat((hexNumber & 0xff000000) >> 24) / 255
+ g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
+ b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
+ a = CGFloat(hexNumber & 0x000000ff) / 255
+
+ return UIColor(red: r, green: g, blue: b, alpha: a)
+ }
+ } else if hexColor.count == 6 {
+ let scanner = Scanner(string: hexColor)
+ var hexNumber: UInt64 = 0
+
+ if scanner.scanHexInt64(&hexNumber) {
+ r = CGFloat((hexNumber & 0xff0000) >> 16) / 255
+ g = CGFloat((hexNumber & 0x00ff00) >> 8) / 255
+ b = CGFloat(hexNumber & 0x0000ff) / 255
+
+ return UIColor(red: r, green: g, blue: b, alpha: 1.0)
+ }
+ }
+ }
+
+ return UIColor.black
+ }
+}
+
+// https://github.com/WorldDownTown/CSS3ColorsSwift/blob/master/CSS3ColorsSwift/CSS3ColorsSwift.swift
+
+//
+// CSS3Colors.swift
+// CSS3Colors
+//
+// Created by Keisuke Shoji on 2016/11/07.
+// Copyright © 2016年 Keisuke Shoji. All rights reserved.
+//
+
+import UIKit
+
+public extension UIColor {
+
+ class var whiteSmoke: UIColor { return #colorLiteral(red: 0.9607843137, green: 0.9607843137, blue: 0.9607843137, alpha: 1) } // F5F5F5
+ class var ghostWhite: UIColor { return #colorLiteral(red: 0.9725490196, green: 0.9725490196, blue: 1.0000000000, alpha: 1) } // F8F8FF
+ class var aliceBlue: UIColor { return #colorLiteral(red: 0.9411764706, green: 0.9725490196, blue: 1.0000000000, alpha: 1) } // F0F8FF
+ class var lavender: UIColor { return #colorLiteral(red: 0.9019607843, green: 0.9019607843, blue: 0.9803921569, alpha: 1) } // E6E6FA
+ class var azure: UIColor { return #colorLiteral(red: 0.9411764706, green: 1.0000000000, blue: 1.0000000000, alpha: 1) } // F0FFFF
+ class var lightCyan: UIColor { return #colorLiteral(red: 0.8784313725, green: 1.0000000000, blue: 1.0000000000, alpha: 1) } // E0FFFF
+ class var mintCream: UIColor { return #colorLiteral(red: 0.9607843137, green: 1.0000000000, blue: 0.9803921569, alpha: 1) } // F5FFFA
+ class var honeyDew: UIColor { return #colorLiteral(red: 0.9411764706, green: 1.0000000000, blue: 0.9411764706, alpha: 1) } // F0FFF0
+ class var ivory: UIColor { return #colorLiteral(red: 1.0000000000, green: 1.0000000000, blue: 0.9411764706, alpha: 1) } // FFFFF0
+ class var beige: UIColor { return #colorLiteral(red: 0.9607843137, green: 0.9607843137, blue: 0.8627450980, alpha: 1) } // F5F5DC
+ class var lightYellow: UIColor { return #colorLiteral(red: 1.0000000000, green: 1.0000000000, blue: 0.8784313725, alpha: 1) } // FFFFE0
+ class var lightGoldenRodYellow: UIColor { return #colorLiteral(red: 0.9803921569, green: 0.9803921569, blue: 0.8235294118, alpha: 1) } // FAFAD2
+ class var lemonChiffon: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9803921569, blue: 0.8039215686, alpha: 1) } // FFFACD
+ class var floralWhite: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9803921569, blue: 0.9411764706, alpha: 1) } // FFFAF0
+ class var oldLace: UIColor { return #colorLiteral(red: 0.9921568627, green: 0.9607843137, blue: 0.9019607843, alpha: 1) } // FDF5E6
+ class var cornSilk: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9725490196, blue: 0.8627450980, alpha: 1) } // FFF8DC
+ class var papayaWhip: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9372549020, blue: 0.8352941176, alpha: 1) } // FFEFD5
+ class var blanchedAlmond: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9215686275, blue: 0.8039215686, alpha: 1) } // FFEBCD
+ class var bisque: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.8941176471, blue: 0.7686274510, alpha: 1) } // FFE4C4
+ class var snow: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9803921569, blue: 0.9803921569, alpha: 1) } // FFFAFA
+ class var linen: UIColor { return #colorLiteral(red: 0.9803921569, green: 0.9411764706, blue: 0.9019607843, alpha: 1) } // FAF0E6
+ class var antiqueWhite: UIColor { return #colorLiteral(red: 0.9803921569, green: 0.9215686275, blue: 0.8431372549, alpha: 1) } // FAEBD7
+ class var seaShell: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9607843137, blue: 0.9333333333, alpha: 1) } // FFF5EE
+ class var lavenderBlush: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.9411764706, blue: 0.9607843137, alpha: 1) } // FFF0F5
+ class var mistyRose: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.8941176471, blue: 0.8823529412, alpha: 1) } // FFE4E1
+ class var gainsboro: UIColor { return #colorLiteral(red: 0.8627450980, green: 0.8627450980, blue: 0.8627450980, alpha: 1) } // DCDCDC
+ class var lightGrayCSS3: UIColor { return #colorLiteral(red: 0.8274509804, green: 0.8274509804, blue: 0.8274509804, alpha: 1) } // D3D3D3
+ class var lightSteelBlue: UIColor { return #colorLiteral(red: 0.6901960784, green: 0.7686274510, blue: 0.8705882353, alpha: 1) } // B0C4DE
+ class var lightBlue: UIColor { return #colorLiteral(red: 0.6784313725, green: 0.8470588235, blue: 0.9019607843, alpha: 1) } // ADD8E6
+ class var lightSkyBlue: UIColor { return #colorLiteral(red: 0.5294117647, green: 0.8078431373, blue: 0.9803921569, alpha: 1) } // 87CEFA
+ class var powderBlue: UIColor { return #colorLiteral(red: 0.6901960784, green: 0.8784313725, blue: 0.9019607843, alpha: 1) } // B0E0E6
+ class var paleTurquoise: UIColor { return #colorLiteral(red: 0.6862745098, green: 0.9333333333, blue: 0.9333333333, alpha: 1) } // AFEEEE
+ class var skyBlue: UIColor { return #colorLiteral(red: 0.5294117647, green: 0.8078431373, blue: 0.9215686275, alpha: 1) } // 87CEEB
+ class var mediumAquamarine: UIColor { return #colorLiteral(red: 0.4000000000, green: 0.8039215686, blue: 0.6666666667, alpha: 1) } // 66CDAA
+ class var aquamarine: UIColor { return #colorLiteral(red: 0.4980392157, green: 1.0000000000, blue: 0.8313725490, alpha: 1) } // 7FFFD4
+ class var paleGreen: UIColor { return #colorLiteral(red: 0.5960784314, green: 0.9843137255, blue: 0.5960784314, alpha: 1) } // 98FB98
+ class var lightGreen: UIColor { return #colorLiteral(red: 0.5647058824, green: 0.9333333333, blue: 0.5647058824, alpha: 1) } // 90EE90
+ class var khaki: UIColor { return #colorLiteral(red: 0.9411764706, green: 0.9019607843, blue: 0.5490196078, alpha: 1) } // F0E68C
+ class var paleGoldenRod: UIColor { return #colorLiteral(red: 0.9333333333, green: 0.9098039216, blue: 0.6666666667, alpha: 1) } // EEE8AA
+ class var moccasin: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.8941176471, blue: 0.7098039216, alpha: 1) } // FFE4B5
+ class var navajoWhite: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.8705882353, blue: 0.6784313725, alpha: 1) } // FFDEAD
+ class var peachPuff: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.8549019608, blue: 0.7254901961, alpha: 1) } // FFDAB9
+ class var wheat: UIColor { return #colorLiteral(red: 0.9607843137, green: 0.8705882353, blue: 0.7019607843, alpha: 1) } // F5DEB3
+ class var pink: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.7529411765, blue: 0.7960784314, alpha: 1) } // FFC0CB
+ class var lightPink: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.7137254902, blue: 0.7568627451, alpha: 1) } // FFB6C1
+ class var thistle: UIColor { return #colorLiteral(red: 0.8470588235, green: 0.7490196078, blue: 0.8470588235, alpha: 1) } // D8BFD8
+ class var plum: UIColor { return #colorLiteral(red: 0.8666666667, green: 0.6274509804, blue: 0.8666666667, alpha: 1) } // DDA0DD
+ class var silver: UIColor { return #colorLiteral(red: 0.7529411765, green: 0.7529411765, blue: 0.7529411765, alpha: 1) } // C0C0C0
+ class var darkGrayCSS3: UIColor { return #colorLiteral(red: 0.6627450980, green: 0.6627450980, blue: 0.6627450980, alpha: 1) } // A9A9A9
+ class var lightSlateGray: UIColor { return #colorLiteral(red: 0.4666666667, green: 0.5333333333, blue: 0.6000000000, alpha: 1) } // 778899
+ class var slateGray: UIColor { return #colorLiteral(red: 0.4392156863, green: 0.5019607843, blue: 0.5647058824, alpha: 1) } // 708090
+ class var slateBlue: UIColor { return #colorLiteral(red: 0.4156862745, green: 0.3529411765, blue: 0.8039215686, alpha: 1) } // 6A5ACD
+ class var steelBlue: UIColor { return #colorLiteral(red: 0.2745098039, green: 0.5098039216, blue: 0.7058823529, alpha: 1) } // 4682B4
+ class var mediumSlateBlue: UIColor { return #colorLiteral(red: 0.4823529412, green: 0.4078431373, blue: 0.9333333333, alpha: 1) } // 7B68EE
+ class var royalBlue: UIColor { return #colorLiteral(red: 0.2549019608, green: 0.4117647059, blue: 0.8823529412, alpha: 1) } // 4169E1
+ class var dodgerBlue: UIColor { return #colorLiteral(red: 0.1176470588, green: 0.5647058824, blue: 1.0000000000, alpha: 1) } // 1E90FF
+ class var cornflowerBlue: UIColor { return #colorLiteral(red: 0.3921568627, green: 0.5843137255, blue: 0.9294117647, alpha: 1) } // 6495ED
+ class var deepSkyBlue: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.7490196078, blue: 1.0000000000, alpha: 1) } // 00BFFF
+ class var aqua: UIColor { return #colorLiteral(red: 0.0000000000, green: 1.0000000000, blue: 1.0000000000, alpha: 1) } // 00FFFF
+ class var turquoise: UIColor { return #colorLiteral(red: 0.2509803922, green: 0.8784313725, blue: 0.8156862745, alpha: 1) } // 40E0D0
+ class var mediumTurquoise: UIColor { return #colorLiteral(red: 0.2823529412, green: 0.8196078431, blue: 0.8000000000, alpha: 1) } // 48D1CC
+ class var darkTurquoise: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.8078431373, blue: 0.8196078431, alpha: 1) } // 00CED1
+ class var lightSeaGreen: UIColor { return #colorLiteral(red: 0.1254901961, green: 0.6980392157, blue: 0.6666666667, alpha: 1) } // 20B2AA
+ class var mediumSpringGreen: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.9803921569, blue: 0.6039215686, alpha: 1) } // 00FA9A
+ class var springGreen: UIColor { return #colorLiteral(red: 0.0000000000, green: 1.0000000000, blue: 0.4980392157, alpha: 1) } // 00FF7F
+ class var lime: UIColor { return #colorLiteral(red: 0.0000000000, green: 1.0000000000, blue: 0.0000000000, alpha: 1) } // 00FF00
+ class var limeGreen: UIColor { return #colorLiteral(red: 0.1960784314, green: 0.8039215686, blue: 0.1960784314, alpha: 1) } // 32CD32
+ class var yellowGreen: UIColor { return #colorLiteral(red: 0.6039215686, green: 0.8039215686, blue: 0.1960784314, alpha: 1) } // 9ACD32
+ class var lawnGreen: UIColor { return #colorLiteral(red: 0.4862745098, green: 0.9882352941, blue: 0.0000000000, alpha: 1) } // 7CFC00
+ class var chartreuse: UIColor { return #colorLiteral(red: 0.4980392157, green: 1.0000000000, blue: 0.0000000000, alpha: 1) } // 7FFF00
+ class var greenYellow: UIColor { return #colorLiteral(red: 0.6784313725, green: 1.0000000000, blue: 0.1843137255, alpha: 1) } // ADFF2F
+ class var gold: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.8431372549, blue: 0.0000000000, alpha: 1) } // FFD700
+ class var orangeCSS3: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.6470588235, blue: 0.0000000000, alpha: 1) } // FFA500
+ class var darkOrange: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.5490196078, blue: 0.0000000000, alpha: 1) } // FF8C00
+ class var goldenRod: UIColor { return #colorLiteral(red: 0.8549019608, green: 0.6470588235, blue: 0.1254901961, alpha: 1) } // DAA520
+ class var burlyWood: UIColor { return #colorLiteral(red: 0.8705882353, green: 0.7215686275, blue: 0.5294117647, alpha: 1) } // DEB887
+ class var tan: UIColor { return #colorLiteral(red: 0.8235294118, green: 0.7058823529, blue: 0.5490196078, alpha: 1) } // D2B48C
+ class var sandyBrown: UIColor { return #colorLiteral(red: 0.9568627451, green: 0.6431372549, blue: 0.3764705882, alpha: 1) } // F4A460
+ class var darkSalmon: UIColor { return #colorLiteral(red: 0.9137254902, green: 0.5882352941, blue: 0.4784313725, alpha: 1) } // E9967A
+ class var lightCoral: UIColor { return #colorLiteral(red: 0.9411764706, green: 0.5019607843, blue: 0.5019607843, alpha: 1) } // F08080
+ class var salmon: UIColor { return #colorLiteral(red: 0.9803921569, green: 0.5019607843, blue: 0.4470588235, alpha: 1) } // FA8072
+ class var lightSalmon: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.6274509804, blue: 0.4784313725, alpha: 1) } // FFA07A
+ class var coral: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.4980392157, blue: 0.3137254902, alpha: 1) } // FF7F50
+ class var tomato: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.3882352941, blue: 0.2784313725, alpha: 1) } // FF6347
+ class var orangeRed: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.2705882353, blue: 0.0000000000, alpha: 1) } // FF4500
+ class var deepPink: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.0784313725, blue: 0.5764705882, alpha: 1) } // FF1493
+ class var hotPink: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.4117647059, blue: 0.7058823529, alpha: 1) } // FF69B4
+ class var paleVioletRed: UIColor { return #colorLiteral(red: 0.8470588235, green: 0.4392156863, blue: 0.5764705882, alpha: 1) } // D87093
+ class var violet: UIColor { return #colorLiteral(red: 0.9333333333, green: 0.5098039216, blue: 0.9333333333, alpha: 1) } // EE82EE
+ class var orchid: UIColor { return #colorLiteral(red: 0.8549019608, green: 0.4392156863, blue: 0.8392156863, alpha: 1) } // DA70D6
+ class var fuchsia: UIColor { return #colorLiteral(red: 1.0000000000, green: 0.0000000000, blue: 1.0000000000, alpha: 1) } // FF00FF
+ class var mediumOrchid: UIColor { return #colorLiteral(red: 0.7294117647, green: 0.3333333333, blue: 0.8274509804, alpha: 1) } // BA55D3
+ class var darkOrchid: UIColor { return #colorLiteral(red: 0.6000000000, green: 0.1960784314, blue: 0.8000000000, alpha: 1) } // 9932CC
+ class var darkViolet: UIColor { return #colorLiteral(red: 0.5803921569, green: 0.0000000000, blue: 0.8274509804, alpha: 1) } // 9400D3
+ class var blueViolet: UIColor { return #colorLiteral(red: 0.5411764706, green: 0.1686274510, blue: 0.8862745098, alpha: 1) } // 8A2BE2
+ class var mediumPurple: UIColor { return #colorLiteral(red: 0.5764705882, green: 0.4392156863, blue: 0.8470588235, alpha: 1) } // 9370D8
+ class var mediumBlue: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.0000000000, blue: 0.8039215686, alpha: 1) } // 0000CD
+ class var darkCyan: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.5450980392, blue: 0.5450980392, alpha: 1) } // 008B8B
+ class var cadetBlue: UIColor { return #colorLiteral(red: 0.3725490196, green: 0.6196078431, blue: 0.6274509804, alpha: 1) } // 5F9EA0
+ class var darkSeaGreen: UIColor { return #colorLiteral(red: 0.5607843137, green: 0.7372549020, blue: 0.5607843137, alpha: 1) } // 8FBC8F
+ class var mediumSeaGreen: UIColor { return #colorLiteral(red: 0.2352941176, green: 0.7019607843, blue: 0.4431372549, alpha: 1) } // 3CB371
+ class var teal: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.5019607843, blue: 0.5019607843, alpha: 1) } // 008080
+ class var forestGreen: UIColor { return #colorLiteral(red: 0.1333333333, green: 0.5450980392, blue: 0.1333333333, alpha: 1) } // 228B22
+ class var seaGreen: UIColor { return #colorLiteral(red: 0.1803921569, green: 0.5450980392, blue: 0.3411764706, alpha: 1) } // 2E8B57
+ class var darkKhaki: UIColor { return #colorLiteral(red: 0.7411764706, green: 0.7176470588, blue: 0.4196078431, alpha: 1) } // BDB76B
+ class var peru: UIColor { return #colorLiteral(red: 0.8039215686, green: 0.5215686275, blue: 0.2470588235, alpha: 1) } // CD853F
+ class var crimson: UIColor { return #colorLiteral(red: 0.8627450980, green: 0.0784313725, blue: 0.2352941176, alpha: 1) } // DC143C
+ class var indianRed: UIColor { return #colorLiteral(red: 0.8039215686, green: 0.3607843137, blue: 0.3607843137, alpha: 1) } // CD5C5C
+ class var rosyBrown: UIColor { return #colorLiteral(red: 0.7372549020, green: 0.5607843137, blue: 0.5607843137, alpha: 1) } // BC8F8F
+ class var mediumVioletRed: UIColor { return #colorLiteral(red: 0.7803921569, green: 0.0823529412, blue: 0.5215686275, alpha: 1) } // C71585
+ class var dimGray: UIColor { return #colorLiteral(red: 0.4117647059, green: 0.4117647059, blue: 0.4117647059, alpha: 1) } // 696969
+ class var midnightBlue: UIColor { return #colorLiteral(red: 0.0980392157, green: 0.0980392157, blue: 0.4392156863, alpha: 1) } // 191970
+ class var darkSlateBlue: UIColor { return #colorLiteral(red: 0.2823529412, green: 0.2392156863, blue: 0.5450980392, alpha: 1) } // 483D8B
+ class var darkBlue: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.0000000000, blue: 0.5450980392, alpha: 1) } // 00008B
+ class var navy: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.0000000000, blue: 0.5019607843, alpha: 1) } // 000080
+ class var darkSlateGray: UIColor { return #colorLiteral(red: 0.1843137255, green: 0.3098039216, blue: 0.3098039216, alpha: 1) } // 2F4F4F
+ class var greenCSS3: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.5019607843, blue: 0.0000000000, alpha: 1) } // 008000
+ class var darkGreen: UIColor { return #colorLiteral(red: 0.0000000000, green: 0.3921568627, blue: 0.0000000000, alpha: 1) } // 006400
+ class var darkOliveGreen: UIColor { return #colorLiteral(red: 0.3333333333, green: 0.4196078431, blue: 0.1843137255, alpha: 1) } // 556B2F
+ class var oliveDrab: UIColor { return #colorLiteral(red: 0.4196078431, green: 0.5568627451, blue: 0.1372549020, alpha: 1) } // 6B8E23
+ class var olive: UIColor { return #colorLiteral(red: 0.5019607843, green: 0.5019607843, blue: 0.0000000000, alpha: 1) } // 808000
+ class var darkGoldenRod: UIColor { return #colorLiteral(red: 0.7215686275, green: 0.5254901961, blue: 0.0431372549, alpha: 1) } // B8860B
+ class var chocolate: UIColor { return #colorLiteral(red: 0.8235294118, green: 0.4117647059, blue: 0.1176470588, alpha: 1) } // D2691E
+ class var sienna: UIColor { return #colorLiteral(red: 0.6274509804, green: 0.3215686275, blue: 0.1764705882, alpha: 1) } // A0522D
+ class var saddleBrown: UIColor { return #colorLiteral(red: 0.5450980392, green: 0.2705882353, blue: 0.0745098039, alpha: 1) } // 8B4513
+ class var fireBrick: UIColor { return #colorLiteral(red: 0.6980392157, green: 0.1333333333, blue: 0.1333333333, alpha: 1) } // B22222
+ class var brownCSS3: UIColor { return #colorLiteral(red: 0.6470588235, green: 0.1647058824, blue: 0.1647058824, alpha: 1) } // A52A2A
+ class var maroon: UIColor { return #colorLiteral(red: 0.5019607843, green: 0.0000000000, blue: 0.0000000000, alpha: 1) } // 800000
+ class var darkRed: UIColor { return #colorLiteral(red: 0.5450980392, green: 0.0000000000, blue: 0.0000000000, alpha: 1) } // 8B0000
+ class var darkMagenta: UIColor { return #colorLiteral(red: 0.5450980392, green: 0.0000000000, blue: 0.5450980392, alpha: 1) } // 8B008B
+ class var indigo: UIColor { return #colorLiteral(red: 0.2941176471, green: 0.0000000000, blue: 0.5098039216, alpha: 1) } // 4B0082
+}
diff --git a/modules/react-native-ui-text-view/ios/UITextViewManager.swift b/modules/react-native-ui-text-view/ios/UITextViewManager.swift
new file mode 100644
index 0000000000..80692a7e8c
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/UITextViewManager.swift
@@ -0,0 +1,32 @@
+@objc(RNUITextViewManager)
+class RNUITextViewManager: RCTViewManager {
+ var textStorage = NSTextStorage()
+
+ override func view() -> (RNUITextView) {
+ return RNUITextView()
+ }
+
+ @objc override static func requiresMainQueueSetup() -> Bool {
+ return true
+ }
+
+ override func shadowView() -> RCTShadowView {
+ // Pass the bridge to the shadow view
+ return RNUITextViewShadowView(bridge: self.bridge)
+ }
+}
+
+@objc(RNUITextViewChildManager)
+class RNUITextViewChildManager: RCTViewManager {
+ override func view() -> (RNUITextViewChild) {
+ return RNUITextViewChild()
+ }
+
+ @objc override static func requiresMainQueueSetup() -> Bool {
+ return true
+ }
+
+ override func shadowView() -> RCTShadowView {
+ return RNUITextViewChildShadowView()
+ }
+}
diff --git a/modules/react-native-ui-text-view/ios/UiTextView-Bridging-Header.h b/modules/react-native-ui-text-view/ios/UiTextView-Bridging-Header.h
new file mode 100644
index 0000000000..e669b47eb2
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/UiTextView-Bridging-Header.h
@@ -0,0 +1,3 @@
+#import
+#import
+#import
diff --git a/modules/react-native-ui-text-view/ios/UiTextViewViewManager.m b/modules/react-native-ui-text-view/ios/UiTextViewViewManager.m
new file mode 100644
index 0000000000..984131f44b
--- /dev/null
+++ b/modules/react-native-ui-text-view/ios/UiTextViewViewManager.m
@@ -0,0 +1,27 @@
+#import
+
+@interface RCT_EXTERN_MODULE(RNUITextViewManager, RCTViewManager)
+RCT_REMAP_SHADOW_PROPERTY(numberOfLines, numberOfLines, NSInteger)
+RCT_REMAP_SHADOW_PROPERTY(ellipsizeMode, ellipsizeMode, NSString)
+RCT_REMAP_SHADOW_PROPERTY(allowsFontScaling, allowsFontScaling, BOOL)
+
+//RCT_REMAP_SHADOW_PROPERTY(numberOfLines, numberOfLines, NSInteger)
+//RCT_REMAP_SHADOW_PROPERTY(ellipsizeMode, ellipsizeMode, NSLineBreakMode)
+//RCT_REMAP_SHADOW_PROPERTY(adjustsFontSizeToFit, adjustsFontSizeToFit, BOOL)
+
+//RCT_EXPORT_SHADOW_PROPERTY(onTextLayout, RCTDirectEventBlock)
+//
+//RCT_EXPORT_VIEW_PROPERTY(selectable, BOOL)
+
+@end
+
+@interface RCT_EXTERN_MODULE(RNUITextViewChildManager, RCTViewManager)
+RCT_REMAP_SHADOW_PROPERTY(text, text, NSString)
+RCT_REMAP_SHADOW_PROPERTY(color, color, UIColor)
+RCT_REMAP_SHADOW_PROPERTY(fontSize, fontSize, CGFloat)
+RCT_REMAP_SHADOW_PROPERTY(fontStyle, fontStyle, NSString)
+RCT_REMAP_SHADOW_PROPERTY(fontWeight, fontWeight, NSString)
+RCT_REMAP_SHADOW_PROPERTY(letterSpacing, letterSpacing, CGFloat)
+RCT_REMAP_SHADOW_PROPERTY(lineHeight, lineHeight, CGFloat)
+RCT_REMAP_SHADOW_PROPERTY(pointerEvents, pointerEvents, NSString)
+@end
diff --git a/modules/react-native-ui-text-view/package.json b/modules/react-native-ui-text-view/package.json
new file mode 100644
index 0000000000..a21bdf7055
--- /dev/null
+++ b/modules/react-native-ui-text-view/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "react-native-ui-text-view",
+ "version": "0.0.0",
+ "description": "UITextView in React Native on iOS",
+ "main": "src/index",
+ "author": " <> ()",
+ "license": "UNLICENSED",
+ "homepage": "#readme"
+}
diff --git a/modules/react-native-ui-text-view/react-native-ui-text-view.podspec b/modules/react-native-ui-text-view/react-native-ui-text-view.podspec
new file mode 100644
index 0000000000..1e0dee93f8
--- /dev/null
+++ b/modules/react-native-ui-text-view/react-native-ui-text-view.podspec
@@ -0,0 +1,42 @@
+require "json"
+
+package = JSON.parse(File.read(File.join(__dir__, "package.json")))
+folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
+
+Pod::Spec.new do |s|
+ s.name = "react-native-ui-text-view"
+ s.version = package["version"]
+ s.summary = package["description"]
+ s.homepage = package["homepage"]
+ s.license = package["license"]
+ s.authors = package["author"]
+
+ s.platforms = { :ios => "11.0" }
+ s.source = { :git => ".git", :tag => "#{s.version}" }
+
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
+
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
+ if respond_to?(:install_modules_dependencies, true)
+ install_modules_dependencies(s)
+ else
+ s.dependency "React-Core"
+
+ # Don't install the dependencies when we run `pod install` in the old architecture.
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
+ s.pod_target_xcconfig = {
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
+ }
+ s.dependency "React-RCTFabric"
+ s.dependency "React-Codegen"
+ s.dependency "RCT-Folly"
+ s.dependency "RCTRequired"
+ s.dependency "RCTTypeSafety"
+ s.dependency "ReactCommon/turbomodule/core"
+ end
+ end
+end
diff --git a/modules/react-native-ui-text-view/src/UITextView.tsx b/modules/react-native-ui-text-view/src/UITextView.tsx
new file mode 100644
index 0000000000..ea6926b371
--- /dev/null
+++ b/modules/react-native-ui-text-view/src/UITextView.tsx
@@ -0,0 +1,72 @@
+import React from 'react'
+import {StyleSheet, TextProps, ViewStyle} from 'react-native'
+import {RNUITextView, RNUITextViewChild} from './index'
+
+const TextAncestorContext = React.createContext<[boolean, ViewStyle]>([
+ false,
+ StyleSheet.create({}),
+])
+const useTextAncestorContext = () => React.useContext(TextAncestorContext)
+
+const textDefaults: TextProps = {
+ allowFontScaling: true,
+ selectable: true,
+}
+
+export function UITextView({style, children, onPress, ...rest}: TextProps) {
+ const [isAncestor, rootStyle] = useTextAncestorContext()
+
+ // Flatten the styles, and apply the root styles when needed
+ const flattenedStyle = React.useMemo(
+ () => StyleSheet.flatten([rootStyle, style]),
+ [rootStyle, style],
+ )
+
+ if (!isAncestor) {
+ return (
+
+
+ {React.Children.toArray(children).map((c, index) => {
+ if (React.isValidElement(c)) {
+ return c
+ } else if (typeof c === 'string') {
+ return (
+
+ )
+ }
+ })}
+
+
+ )
+ } else {
+ return (
+ <>
+ {React.Children.toArray(children).map((c, index) => {
+ if (React.isValidElement(c)) {
+ return c
+ } else if (typeof c === 'string') {
+ return (
+
+ )
+ }
+ })}
+ >
+ )
+ }
+}
diff --git a/modules/react-native-ui-text-view/src/index.tsx b/modules/react-native-ui-text-view/src/index.tsx
new file mode 100644
index 0000000000..ada5c4d955
--- /dev/null
+++ b/modules/react-native-ui-text-view/src/index.tsx
@@ -0,0 +1,40 @@
+import {
+ requireNativeComponent,
+ UIManager,
+ Platform,
+ type ViewStyle,
+ TextProps,
+} from 'react-native'
+
+const LINKING_ERROR =
+ `The package 'react-native-ui-text-view' doesn't seem to be linked. Make sure: \n\n` +
+ Platform.select({ios: "- You have run 'pod install'\n", default: ''}) +
+ '- You rebuilt the app after installing the package\n' +
+ '- You are not using Expo Go\n'
+
+export interface RNUITextViewProps extends TextProps {
+ children: React.ReactNode
+ style: ViewStyle[]
+}
+
+export interface RNUITextViewChildProps extends TextProps {
+ text: string
+ onTextPress?: (...args: any[]) => void
+ onTextLongPress?: (...args: any[]) => void
+}
+
+export const RNUITextView =
+ UIManager.getViewManagerConfig('RNUITextView') != null
+ ? requireNativeComponent('RNUITextView')
+ : () => {
+ throw new Error(LINKING_ERROR)
+ }
+
+export const RNUITextViewChild =
+ UIManager.getViewManagerConfig('RNUITextViewChild') != null
+ ? requireNativeComponent('RNUITextViewChild')
+ : () => {
+ throw new Error(LINKING_ERROR)
+ }
+
+export * from './UITextView'
diff --git a/package.json b/package.json
index 71410feabf..7b4bd6aefa 100644
--- a/package.json
+++ b/package.json
@@ -173,7 +173,8 @@
"tlds": "^1.234.0",
"use-deep-compare": "^1.1.0",
"zeego": "^1.6.2",
- "zod": "^3.20.2"
+ "zod": "^3.20.2",
+ "react-native-ui-text-view": "link:./modules/react-native-ui-text-view"
},
"devDependencies": {
"@atproto/dev-env": "^0.2.19",
diff --git a/src/view/com/util/text/Text.tsx b/src/view/com/util/text/Text.tsx
index f20e2a7df9..ccb51bfca6 100644
--- a/src/view/com/util/text/Text.tsx
+++ b/src/view/com/util/text/Text.tsx
@@ -3,7 +3,7 @@ import {Text as RNText, TextProps} from 'react-native'
import {s, lh} from 'lib/styles'
import {useTheme, TypographyVariant} from 'lib/ThemeContext'
import {isIOS} from 'platform/detection'
-import {UITextView} from '../../../../../modules/expo-selectable-text'
+import {UITextView} from 'react-native-ui-text-view'
export type CustomTextProps = TextProps & {
type?: TypographyVariant
diff --git a/yarn.lock b/yarn.lock
index 760e0b331a..95f3d4f3d9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18333,6 +18333,10 @@ react-native-svg@14.1.0:
css-select "^5.1.0"
css-tree "^1.1.3"
+"react-native-ui-text-view@link:./modules/react-native-ui-text-view":
+ version "0.0.0"
+ uid ""
+
react-native-url-polyfill@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/react-native-url-polyfill/-/react-native-url-polyfill-1.3.0.tgz#c1763de0f2a8c22cc3e959b654c8790622b6ef6a"