Skip to content

Commit 2e3f981

Browse files
authored
fix(ios): selection reset (#42)
* fix(ios): collapse NitroText selection on outside taps * refactor: streamline TextAncestorContext initialization in NitroText component
1 parent be972e5 commit 2e3f981

4 files changed

Lines changed: 48 additions & 9 deletions

File tree

cpp/NitroTextShadowNode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//
22
// NitroTextShadowNode.cpp
3-
// Moved implementations from header into translation unit
3+
//
44
//
55

66
#include "NitroTextShadowNode.hpp"

example/App.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ export default function App() {
7878
paragraph.
7979
</NitroText>
8080
</View>
81+
82+
{/* Rich Text Formatting using RN Text */}
8183
<View style={styles.section}>
82-
<Text style={styles.sectionTitle}>Rich Text Formatting</Text>
84+
<Text style={styles.sectionTitle}>Rich Text Formatting(RN Text)</Text>
8385
<Text style={styles.richText}>
8486
Welcome to the world of <Text style={styles.bold}>bold text</Text>,{' '}
8587
<Text style={styles.italic}>beautiful italics</Text>, and{' '}
@@ -112,8 +114,9 @@ export default function App() {
112114
</NitroText>
113115
</View>
114116

117+
{/* Layout Measurement using RN Text */}
115118
<View style={styles.section}>
116-
<Text style={styles.sectionTitle}>Layout Measurement</Text>
119+
<Text style={styles.sectionTitle}>Layout Measurement(RN Text)</Text>
117120
<Text style={styles.measuredText} onLayout={handleLayout}>
118121
This text demonstrates layout measurement capabilities. The component
119122
can measure its dimensions and report back to JavaScript.

ios/NitroTextView.swift

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ final class NitroTextView: UITextView {
118118
var index = glyphRange.location
119119
while index < NSMaxRange(glyphRange) {
120120
var lineGlyphRange = NSRange(location: 0, length: 0)
121-
let usedRect = lm.lineFragmentUsedRect(forGlyphAt: index, effectiveRange: &lineGlyphRange)
121+
let usedRect = lm.lineFragmentUsedRect(
122+
forGlyphAt: index, effectiveRange: &lineGlyphRange)
122123
let charRange = lm.characterRange(forGlyphRange: lineGlyphRange, actualGlyphRange: nil)
123124

124125
let substring = fullText.substring(with: charRange)
@@ -128,7 +129,9 @@ final class NitroTextView: UITextView {
128129
var desc: CGFloat = -(font?.descender ?? 0)
129130
var cap: CGFloat = font?.capHeight ?? 0
130131
var xh: CGFloat = font?.xHeight ?? 0
131-
if let attrsFont = storage?.attribute(.font, at: charRange.location, effectiveRange: nil) as? UIFont {
132+
if let attrsFont = storage?.attribute(
133+
.font, at: charRange.location, effectiveRange: nil) as? UIFont
134+
{
132135
asc = attrsFont.ascender
133136
desc = -(attrsFont.descender)
134137
cap = attrsFont.capHeight
@@ -160,8 +163,33 @@ final class NitroTextView: UITextView {
160163
}
161164

162165
@objc private func handleTap(_ recognizer: UITapGestureRecognizer) {
163-
if recognizer.state == .ended {
164-
nitroTextDelegate?.onNitroTextPress()
165-
}
166+
guard recognizer.state == .ended else { return }
167+
clearSelectionIfNeeded(at: recognizer.location(in: self))
168+
nitroTextDelegate?.onNitroTextPress()
166169
}
170+
167171
}
172+
173+
private extension NitroTextView {
174+
func selectionLength(_ range: UITextRange) -> Int {
175+
offset(from: range.start, to: range.end)
176+
}
177+
178+
func isPoint(_ point: CGPoint, insideSelection range: UITextRange) -> Bool {
179+
for selectionRect in selectionRects(for: range) {
180+
let rect = selectionRect.rect
181+
if rect.isNull || rect.isEmpty { continue }
182+
if rect.contains(point) { return true }
183+
}
184+
return false
185+
}
186+
187+
func clearSelectionIfNeeded(at point: CGPoint) {
188+
guard let currentSelection = selectedTextRange,
189+
selectionLength(currentSelection) > 0
190+
else { return }
191+
if !isPoint(point, insideSelection: currentSelection) {
192+
selectedTextRange = nil
193+
}
194+
}
195+
}

src/nitro-text.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,16 @@ type NitroTextPropsWithEvents = Pick<
2929
> &
3030
Omit<TextProps, 'onTextLayout'>
3131

32+
let TextAncestorContext = unstable_TextAncestorContext
33+
if (
34+
Platform.constants.reactNativeVersion.major > 0 ||
35+
(Platform.constants.reactNativeVersion.major === 0 &&
36+
Platform.constants.reactNativeVersion.minor >= 81)
37+
) {
38+
TextAncestorContext = require('react-native/Libraries/Text/TextAncestor')
39+
}
3240
export const NitroText = (props: NitroTextPropsWithEvents) => {
33-
const isInsideRNText = React.useContext(unstable_TextAncestorContext)
41+
const isInsideRNText = React.useContext(TextAncestorContext)
3442
const {
3543
children,
3644
style,

0 commit comments

Comments
 (0)