make use of rctshadowview

This commit is contained in:
Hailey
2024-01-18 21:14:38 -08:00
parent 7134e1106e
commit 18f818649e
23 changed files with 934 additions and 2 deletions
@@ -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"
}
@@ -0,0 +1,5 @@
UiTextView_kotlinVersion=1.7.0
UiTextView_minSdkVersion=21
UiTextView_targetSdkVersion=31
UiTextView_compileSdkVersion=31
UiTextView_ndkversion=21.4.7075529
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.uitextview">
</manifest>
@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
@@ -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<NativeModule> {
return emptyList()
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return listOf(UiTextViewViewManager())
}
}
@@ -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<View>() {
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))
}
}
@@ -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
}
@@ -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
// }
// }
}
}
@@ -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")
}
}
@@ -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
}
}
}
@@ -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<RNUITextViewShadowView>.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))
}
}
@@ -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
}
}
}
@@ -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
}
@@ -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()
}
}
@@ -0,0 +1,3 @@
#import <React/RCTViewManager.h>
#import <React/RCTBridge.h>
#import <React/RCTBridge+Private.h>
@@ -0,0 +1,27 @@
#import <React/RCTViewManager.h>
@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
@@ -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"
}
@@ -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
@@ -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 (
<TextAncestorContext.Provider value={[true, flattenedStyle]}>
<RNUITextView
{...textDefaults}
{...rest}
ellipsizeMode={rest.ellipsizeMode ?? rest.lineBreakMode ?? 'tail'}
style={[{flex: 1}, flattenedStyle]}>
{React.Children.toArray(children).map((c, index) => {
if (React.isValidElement(c)) {
return c
} else if (typeof c === 'string') {
return (
<RNUITextViewChild
key={index}
style={flattenedStyle}
text={c}
onTextPress={onPress}
{...rest}
/>
)
}
})}
</RNUITextView>
</TextAncestorContext.Provider>
)
} else {
return (
<>
{React.Children.toArray(children).map((c, index) => {
if (React.isValidElement(c)) {
return c
} else if (typeof c === 'string') {
return (
<RNUITextViewChild
key={index}
style={flattenedStyle}
text={c}
onTextPress={onPress}
{...rest}
/>
)
}
})}
</>
)
}
}
@@ -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<RNUITextViewProps>('RNUITextView')
: () => {
throw new Error(LINKING_ERROR)
}
export const RNUITextViewChild =
UIManager.getViewManagerConfig('RNUITextViewChild') != null
? requireNativeComponent<RNUITextViewChildProps>('RNUITextViewChild')
: () => {
throw new Error(LINKING_ERROR)
}
export * from './UITextView'
+2 -1
View File
@@ -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",
+1 -1
View File
@@ -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
+4
View File
@@ -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"