From 18f818649efcd1e18c810aaf4ea1a4cb93ddd111 Mon Sep 17 00:00:00 2001 From: Hailey Date: Thu, 18 Jan 2024 21:14:38 -0800 Subject: [PATCH] make use of rctshadowview --- .../android/build.gradle | 94 +++++++++ .../android/gradle.properties | 5 + .../android/src/main/AndroidManifest.xml | 3 + .../android/src/main/AndroidManifestNew.xml | 2 + .../java/com/uitextview/UiTextViewPackage.kt | 17 ++ .../com/uitextview/UiTextViewViewManager.kt | 20 ++ .../ios/FontStyle.swift | 47 +++++ .../ios/RNUITextView.swift | 63 ++++++ .../ios/RNUITextViewChild.swift | 21 ++ .../ios/RNUITextViewChildShadowView.swift | 46 +++++ .../ios/RNUITextViewShadowView.swift | 153 ++++++++++++++ .../ios/TextStyle.swift | 43 ++++ .../ios/TextUtils.swift | 188 ++++++++++++++++++ .../ios/UITextViewManager.swift | 32 +++ .../ios/UiTextView-Bridging-Header.h | 3 + .../ios/UiTextViewViewManager.m | 27 +++ .../react-native-ui-text-view/package.json | 9 + .../react-native-ui-text-view.podspec | 42 ++++ .../src/UITextView.tsx | 72 +++++++ .../react-native-ui-text-view/src/index.tsx | 40 ++++ package.json | 3 +- src/view/com/util/text/Text.tsx | 2 +- yarn.lock | 4 + 23 files changed, 934 insertions(+), 2 deletions(-) create mode 100644 modules/react-native-ui-text-view/android/build.gradle create mode 100644 modules/react-native-ui-text-view/android/gradle.properties create mode 100644 modules/react-native-ui-text-view/android/src/main/AndroidManifest.xml create mode 100644 modules/react-native-ui-text-view/android/src/main/AndroidManifestNew.xml create mode 100644 modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewPackage.kt create mode 100644 modules/react-native-ui-text-view/android/src/main/java/com/uitextview/UiTextViewViewManager.kt create mode 100644 modules/react-native-ui-text-view/ios/FontStyle.swift create mode 100644 modules/react-native-ui-text-view/ios/RNUITextView.swift create mode 100644 modules/react-native-ui-text-view/ios/RNUITextViewChild.swift create mode 100644 modules/react-native-ui-text-view/ios/RNUITextViewChildShadowView.swift create mode 100644 modules/react-native-ui-text-view/ios/RNUITextViewShadowView.swift create mode 100644 modules/react-native-ui-text-view/ios/TextStyle.swift create mode 100644 modules/react-native-ui-text-view/ios/TextUtils.swift create mode 100644 modules/react-native-ui-text-view/ios/UITextViewManager.swift create mode 100644 modules/react-native-ui-text-view/ios/UiTextView-Bridging-Header.h create mode 100644 modules/react-native-ui-text-view/ios/UiTextViewViewManager.m create mode 100644 modules/react-native-ui-text-view/package.json create mode 100644 modules/react-native-ui-text-view/react-native-ui-text-view.podspec create mode 100644 modules/react-native-ui-text-view/src/UITextView.tsx create mode 100644 modules/react-native-ui-text-view/src/index.tsx 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"