Skip to content

Commit ea8b388

Browse files
Merge pull request Expensify#89705 from QichenZhu/fix/57556-v2
Follow up improvements for inline code blocks on iOS
2 parents c1c7c3d + 59c2eca commit ea8b388

2 files changed

Lines changed: 162 additions & 0 deletions

File tree

patches/react-native/details.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,10 @@
264264
- Reason: Fixes an Android-specific issue (reproducible on certain Samsung models) where `onPress` events do not trigger for `Pressable` components when used inside a `Tooltip`. The root cause is that in the new architecture, `Pressability.measure()` reads stale layout information from the shadow tree instead of the actual native view hierarchy. This patch introduces a new `measureAsyncOnUI` method that measures the view asynchronously using the native layout hierarchy on the UI thread, bypassing stale shadow tree data.
265265
- Upstream PR/issue: [facebook/react-native#51835](https://github.com/facebook/react-native/pull/51835)
266266
- E/App issue: [#59953](https://github.com/Expensify/App/issues/59953)
267+
268+
### [react-native+0.83.1+036+rounded-inline-code-background.patch](react-native+0.83.1+036+rounded-inline-code-background.patch)
269+
270+
- Reason: Draws inline code block background with rounded corners on iOS when `borderTopLeftRadius` is set.
271+
- Upstream PR/issue: 🛑
272+
- E/App issue: https://github.com/Expensify/App/issues/57556
273+
- PR introducing patch: https://github.com/Expensify/App/pull/79815
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
diff --git a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp
2+
index 9cf89bf..845f6c1 100644
3+
--- a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp
4+
+++ b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp
5+
@@ -25,6 +25,9 @@ void TextAttributes::apply(TextAttributes textAttributes) {
6+
backgroundColor = textAttributes.backgroundColor
7+
? textAttributes.backgroundColor
8+
: backgroundColor;
9+
+ borderTopLeftRadius = !std::isnan(textAttributes.borderTopLeftRadius)
10+
+ ? textAttributes.borderTopLeftRadius
11+
+ : borderTopLeftRadius;
12+
opacity =
13+
!std::isnan(textAttributes.opacity) ? textAttributes.opacity : opacity;
14+
15+
@@ -171,6 +174,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const {
16+
floatEquality(fontSizeMultiplier, rhs.fontSizeMultiplier) &&
17+
floatEquality(letterSpacing, rhs.letterSpacing) &&
18+
floatEquality(lineHeight, rhs.lineHeight) &&
19+
+ floatEquality(borderTopLeftRadius, rhs.borderTopLeftRadius) &&
20+
floatEquality(textShadowRadius, rhs.textShadowRadius);
21+
}
22+
23+
diff --git a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h
24+
index b664524..dce4e3b 100644
25+
--- a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h
26+
+++ b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h
27+
@@ -41,6 +41,7 @@ class TextAttributes : public DebugStringConvertible {
28+
// Color
29+
SharedColor foregroundColor{};
30+
SharedColor backgroundColor{};
31+
+ Float borderTopLeftRadius{std::numeric_limits<Float>::quiet_NaN()};
32+
Float opacity{std::numeric_limits<Float>::quiet_NaN()};
33+
34+
// Font
35+
@@ -112,6 +113,7 @@ struct hash<facebook::react::TextAttributes> {
36+
return facebook::react::hash_combine(
37+
textAttributes.foregroundColor,
38+
textAttributes.backgroundColor,
39+
+ textAttributes.borderTopLeftRadius,
40+
textAttributes.opacity,
41+
textAttributes.fontFamily,
42+
textAttributes.fontSize,
43+
diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp b/node_modules/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp
44+
index f20cd3c..8a9cedc 100644
45+
--- a/node_modules/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp
46+
+++ b/node_modules/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp
47+
@@ -222,6 +222,12 @@ static TextAttributes convertRawProp(
48+
"backgroundColor",
49+
sourceTextAttributes.backgroundColor,
50+
defaultTextAttributes.backgroundColor);
51+
+ textAttributes.borderTopLeftRadius = convertRawProp(
52+
+ context,
53+
+ rawProps,
54+
+ "borderTopLeftRadius",
55+
+ sourceTextAttributes.borderTopLeftRadius,
56+
+ defaultTextAttributes.borderTopLeftRadius);
57+
58+
return textAttributes;
59+
}
60+
@@ -334,6 +340,8 @@ void BaseTextProps::setProp(
61+
defaults, value, textAttributes, opacity, "opacity");
62+
REBUILD_FIELD_SWITCH_CASE(
63+
defaults, value, textAttributes, backgroundColor, "backgroundColor");
64+
+ REBUILD_FIELD_SWITCH_CASE(
65+
+ defaults, value, textAttributes, borderTopLeftRadius, "borderTopLeftRadius");
66+
}
67+
}
68+
69+
diff --git a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h
70+
index dac572b..87cc9f0 100644
71+
--- a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h
72+
+++ b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h
73+
@@ -18,6 +18,7 @@ NSString *const RCTAttributedStringEventEmitterKey = @"EventEmitter";
74+
75+
// String representation of either `role` or `accessibilityRole`
76+
NSString *const RCTTextAttributesAccessibilityRoleAttributeName = @"AccessibilityRole";
77+
+NSString *const RCTTextBackgroundBorderRadiusAttributeName = @"TextBackgroundBorderRadius";
78+
79+
/*
80+
* Creates `NSTextAttributes` from given `facebook::react::TextAttributes`
81+
diff --git a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm
82+
index 520a24c..452a0fe 100644
83+
--- a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm
84+
+++ b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm
85+
@@ -179,7 +179,12 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex
86+
}
87+
88+
if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) {
89+
- attributes[NSBackgroundColorAttributeName] = RCTEffectiveBackgroundColorFromTextAttributes(textAttributes);
90+
+ UIColor *bgColor = RCTEffectiveBackgroundColorFromTextAttributes(textAttributes) ?: [UIColor clearColor];
91+
+ if (!isnan(textAttributes.borderTopLeftRadius) && textAttributes.borderTopLeftRadius > 0) {
92+
+ attributes[RCTTextBackgroundBorderRadiusAttributeName] = @[@(textAttributes.borderTopLeftRadius), bgColor];
93+
+ } else {
94+
+ attributes[NSBackgroundColorAttributeName] = bgColor;
95+
+ }
96+
}
97+
98+
// Kerning
99+
diff --git a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
100+
index ef50487..df9290f 100644
101+
--- a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
102+
+++ b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
103+
@@ -17,6 +17,8 @@
104+
105+
using namespace facebook::react;
106+
107+
+static const CGFloat inlineCodeBackgroundTopInset = 3;
108+
+
109+
@implementation RCTTextLayoutManager {
110+
SimpleThreadSafeCache<AttributedString, std::shared_ptr<void>, 256> _cache;
111+
}
112+
@@ -86,6 +88,43 @@ - (void)drawAttributedString:(AttributedString)attributedString
113+
114+
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
115+
116+
+ NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
117+
+ [textStorage enumerateAttribute:RCTTextBackgroundBorderRadiusAttributeName
118+
+ inRange:characterRange
119+
+ options:0
120+
+ usingBlock:^(NSArray *value, NSRange range, BOOL *stop) {
121+
+ if (!value) {
122+
+ return;
123+
+ }
124+
+ CGFloat radius = [value[0] floatValue];
125+
+ UIColor *color = value[1];
126+
+ NSRange rangeGlyphRange = [layoutManager glyphRangeForCharacterRange:range actualCharacterRange:NULL];
127+
+ NSMutableArray<NSValue *> *rects = [NSMutableArray array];
128+
+ [layoutManager enumerateEnclosingRectsForGlyphRange:rangeGlyphRange
129+
+ withinSelectedGlyphRange:rangeGlyphRange
130+
+ inTextContainer:textContainer
131+
+ usingBlock:^(CGRect enclosingRect, BOOL *anotherStop) {
132+
+ [rects addObject:[NSValue valueWithCGRect:enclosingRect]];
133+
+ }];
134+
+ NSUInteger count = rects.count;
135+
+ for (NSUInteger i = 0; i < count; i++) {
136+
+ CGRect rect = UIEdgeInsetsInsetRect(
137+
+ CGRectOffset([rects[i] CGRectValue], frame.origin.x, frame.origin.y),
138+
+ UIEdgeInsetsMake(inlineCodeBackgroundTopInset, 0, 0, 0));
139+
+ UIRectCorner corners = 0;
140+
+ if (count == 1) {
141+
+ corners = UIRectCornerAllCorners;
142+
+ } else if (i == 0) {
143+
+ corners = UIRectCornerTopLeft | UIRectCornerBottomLeft;
144+
+ } else if (i == count - 1) {
145+
+ corners = UIRectCornerTopRight | UIRectCornerBottomRight;
146+
+ }
147+
+ UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];
148+
+ [color setFill];
149+
+ [path fill];
150+
+ }
151+
+ }];
152+
+
153+
[self processTruncatedAttributedText:textStorage textContainer:textContainer layoutManager:layoutManager];
154+
155+
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:frame.origin];

0 commit comments

Comments
 (0)