a2b58852e7
Squashed commit of the following: commit 9d9c46ced116079add8ae1beaed854b38962d608 Author: Paul Frazee <pfrazee@gmail.com> Date: Tue Jan 23 14:12:32 2024 -0800 Fix reference error on the web build commit 1981621c5b6f2b63b3e3875b68721161487d7df0 Merge:cda4fe4a0d9b6954Author: Paul Frazee <pfrazee@gmail.com> Date: Tue Jan 23 12:43:51 2024 -0800 Merge branch 'feat/selectable-text' of https://github.com/haileyok/social-app into haileyok-feat/selectable-text commit0d9b695447Merge:3c381f94f1a7a571Author: Hailey <153161762+haileyok@users.noreply.github.com> Date: Fri Jan 19 16:42:13 2024 -0800 Merge branch 'main' into feat/selectable-text commit3c381f9470Merge:f9510156fb596e7fAuthor: Hailey <153161762+haileyok@users.noreply.github.com> Date: Thu Jan 18 23:48:10 2024 -0800 Merge branch 'main' into feat/selectable-text commitf951015637Author: Hailey <me@haileyok.com> Date: Thu Jan 18 23:46:25 2024 -0800 update readme commitaa9b8b06edAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 23:37:49 2024 -0800 calculate line height commit9fe479630cAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 23:19:31 2024 -0800 improve height calculation, render on prop changes commit209caffa7dAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 22:53:08 2024 -0800 presses commit384c8ec3a8Author: Hailey <me@haileyok.com> Date: Thu Jan 18 21:57:56 2024 -0800 line break mode commitadfcf05fe4Author: Hailey <me@haileyok.com> Date: Thu Jan 18 21:50:21 2024 -0800 onTextLayout event commite9ba104e6fAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 21:34:35 2024 -0800 better naming commite335f5ab7fAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 21:31:38 2024 -0800 remove android commit9e197934baAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 21:28:28 2024 -0800 remove expo module commit99882c7e39Author: Hailey <me@haileyok.com> Date: Thu Jan 18 21:27:43 2024 -0800 handle presses commit18f818649eAuthor: Hailey <me@haileyok.com> Date: Thu Jan 18 21:14:38 2024 -0800 make use of rctshadowview commit7134e1106eAuthor: Hailey <me@haileyok.com> Date: Wed Jan 17 20:38:39 2024 -0800 stop unnecessary layouts, resize container before setting text commit340b84f053Author: Hailey <me@haileyok.com> Date: Wed Jan 17 11:17:36 2024 -0800 handle prop changes for both children and root views commitd906fe4fcfAuthor: Hailey <me@haileyok.com> Date: Tue Jan 16 18:42:22 2024 -0800 handle onpress better commitb6b0964168Author: Hailey <me@haileyok.com> Date: Tue Jan 16 16:57:31 2024 -0800 resolve animation issue, animate alt text expansion commitdaedd1f671Author: Hailey <me@haileyok.com> Date: Tue Jan 16 15:47:24 2024 -0800 move getChildren to didMoveToWindow commit87d44e4b57Author: Hailey <me@haileyok.com> Date: Mon Jan 15 18:48:36 2024 -0800 simplify getPressed commitd92584bad7Author: Hailey <me@haileyok.com> Date: Mon Jan 15 17:56:43 2024 -0800 just more cleanup commitd39f7a937dAuthor: Hailey <me@haileyok.com> Date: Mon Jan 15 17:03:19 2024 -0800 remove unnecessary property for gesture recognizer commita35513a1d2Author: Hailey <me@haileyok.com> Date: Mon Jan 15 16:55:36 2024 -0800 remove debug line commit788956aa01Author: Hailey <me@haileyok.com> Date: Mon Jan 15 16:33:44 2024 -0800 typo commita3ba6e7825Author: Hailey <me@haileyok.com> Date: Mon Jan 15 13:42:25 2024 -0800 make alt text selectable commite5472a13daAuthor: Hailey <me@haileyok.com> Date: Mon Jan 15 05:27:15 2024 -0800 re-render on numberOfLines change commit9f5b7602c1Author: Hailey <me@haileyok.com> Date: Mon Jan 15 04:57:35 2024 -0800 more implementations commitaa96bba066Author: Hailey <me@haileyok.com> Date: Mon Jan 15 03:12:43 2024 -0800 merge main in what are you doing there? go away fix recognizer to clear selected text on tap remove jank/hacks update readme remove android stuff (?) don't remove clipped subview on android for selection enable selection of alt text add numberOfLines properly apply container styles handle both selection and expand press events in alt text far better implementation revert link changes revert lightbox changes for now fix file name commitec8c05f3f0Merge:2435a25212a0ceeeAuthor: Hailey <me@haileyok.com> Date: Fri Jan 12 23:41:10 2024 -0800 Merge branch 'main' into feat/selectable-text # Conflicts: # src/view/com/util/Link.tsx commit2435a25257Author: Hailey <me@haileyok.com> Date: Fri Jan 12 23:30:13 2024 -0800 cleanup commitfdf75927f6Author: Hailey <me@haileyok.com> Date: Fri Jan 12 23:25:23 2024 -0800 remove debug commit36d8cd82efAuthor: Hailey <me@haileyok.com> Date: Fri Jan 12 23:25:17 2024 -0800 reset text selection on text update commitb8f7bc23c2Author: Hailey <me@haileyok.com> Date: Fri Jan 12 23:24:43 2024 -0800 use textkit 1 commit5216464458Author: Hailey <me@haileyok.com> Date: Fri Jan 12 22:50:15 2024 -0800 properly handle link press events commit2802902c69Author: Hailey <me@haileyok.com> Date: Fri Jan 12 22:49:47 2024 -0800 modify Link so that we can create the TextLink press handler outside commit860610e63aAuthor: Hailey <me@haileyok.com> Date: Fri Jan 12 19:17:51 2024 -0800 always make sure we use the latest styles commit7f05d0141bAuthor: Hailey <me@haileyok.com> Date: Fri Jan 12 16:57:08 2024 -0800 update readme with tech info commitb8318446a3Author: Hailey <me@haileyok.com> Date: Fri Jan 12 16:34:35 2024 -0800 remove all uitextview padding commit0f0b6aa131Author: Hailey <me@haileyok.com> Date: Fri Jan 12 16:34:28 2024 -0800 cleanup imports commitc9f0064836Author: Hailey <me@haileyok.com> Date: Fri Jan 12 16:18:08 2024 -0800 update interface commit7dcac644baAuthor: Hailey <me@haileyok.com> Date: Fri Jan 12 16:13:49 2024 -0800 remove useless struct commit5174744213Author: Hailey <me@haileyok.com> Date: Fri Jan 12 16:13:34 2024 -0800 adjust deps commitce8b9ed62bAuthor: Hailey <me@haileyok.com> Date: Thu Jan 11 22:15:50 2024 -0800 add readme, update info commit33c6e3b15cAuthor: Hailey <me@haileyok.com> Date: Thu Jan 11 22:04:53 2024 -0800 remove unnecessary android/web stuff commitfbca531bdfAuthor: Hailey <me@haileyok.com> Date: Thu Jan 11 22:02:30 2024 -0800 simplify cast of string.index to int before i forget commit648552eafbAuthor: Hailey <me@haileyok.com> Date: Thu Jan 11 02:01:20 2024 -0800 wip commitc6d2e54923Author: Hailey <me@haileyok.com> Date: Thu Jan 11 00:38:47 2024 -0800 selectable text experiment
148 lines
4.8 KiB
Swift
148 lines
4.8 KiB
Swift
class RNUITextViewShadow: RCTShadowView {
|
|
// Props
|
|
@objc var numberOfLines: Int = 0 {
|
|
didSet {
|
|
if !YGNodeIsDirty(self.yogaNode) {
|
|
self.setAttributedText()
|
|
}
|
|
}
|
|
}
|
|
@objc var allowsFontScaling: Bool = true
|
|
|
|
var attributedText: NSAttributedString = NSAttributedString()
|
|
var frameSize: CGSize = CGSize()
|
|
|
|
var lineHeight: CGFloat = 0
|
|
|
|
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<RNUITextViewShadow>.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: RNUITextViewChildShadow.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? RNUITextViewChildShadow else {
|
|
return
|
|
}
|
|
let scaledFontSize = self.allowsFontScaling ?
|
|
UIFontMetrics.default.scaledValue(for: child.fontSize) : child.fontSize
|
|
let font = UIFont.systemFont(ofSize: scaledFontSize, weight: child.getFontWeight())
|
|
|
|
// Set some generic attributes that don't need ranges
|
|
let attributes: [NSAttributedString.Key:Any] = [
|
|
.font: font,
|
|
.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()
|
|
if child.lineHeight != 0.0 {
|
|
paragraphStyle.minimumLineHeight = child.lineHeight
|
|
paragraphStyle.maximumLineHeight = child.lineHeight
|
|
string.addAttribute(
|
|
NSAttributedString.Key.paragraphStyle,
|
|
value: paragraphStyle,
|
|
range: NSMakeRange(0, string.length)
|
|
)
|
|
|
|
// Store that height
|
|
self.lineHeight = child.lineHeight
|
|
} else {
|
|
self.lineHeight = font.lineHeight
|
|
}
|
|
|
|
finalAttributedString.append(string)
|
|
}
|
|
|
|
self.attributedText = finalAttributedString
|
|
self.dirtyLayout()
|
|
}
|
|
|
|
// Create a YGSize based on the max width
|
|
func getNeededSize(maxWidth: Float) -> YGSize {
|
|
// Create the max size and figure out the size of the entire text
|
|
let maxSize = CGSize(width: CGFloat(maxWidth), height: CGFloat(MAXFLOAT))
|
|
let textSize = self.attributedText.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, context: nil)
|
|
|
|
// Figure out how many total lines there are
|
|
let totalLines = Int(ceil(textSize.height / self.lineHeight))
|
|
|
|
// Default to the text size
|
|
var neededSize: CGSize = textSize.size
|
|
|
|
// If the total lines > max number, return size with the max
|
|
if self.numberOfLines != 0, totalLines > self.numberOfLines {
|
|
neededSize = CGSize(width: CGFloat(maxWidth), height: CGFloat(CGFloat(self.numberOfLines) * self.lineHeight))
|
|
}
|
|
|
|
self.frameSize = neededSize
|
|
return YGSize(width: Float(neededSize.width), height: Float(neededSize.height))
|
|
}
|
|
}
|