Files
bsky-social-app/patches/react-native@0.86.0.patch
T
2026-08-17 11:46:06 +02:00

210 lines
9.9 KiB
Diff

diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
index c593d9ee2155a826352ebca34845aa5792b2eec3..3c26cd737f21116ff0aa48190e97e6c0649b5fac 100644
--- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
+++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
@@ -101,6 +101,20 @@ - (void)setContentOffset:(CGPoint)contentOffset
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
}
+- (void)setCenterContent:(BOOL)centerContent
+{
+ if (_centerContent != centerContent) {
+ _centerContent = centerContent;
+ [self centerContentIfNeeded];
+ }
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+ [super setContentSize:contentSize];
+ [self centerContentIfNeeded];
+}
+
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h
index 914a2494a57923fbf185644b7e2bb8aca8848e56..0deac55f22350f5e8377d8963fb1c2434bf6abfd 100644
--- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h
+++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h
@@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface RCTPullToRefreshViewComponentView : RCTViewComponentView <RCTCustomPullToRefreshViewProtocol>
+- (void)beginRefreshingProgrammatically;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
index 1494fd225aff1fa0429e917404d6b4ca5fc961c5..d0cce700090245444f8ce51e517d5ceca09526f6 100644
--- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
+++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
@@ -380,7 +380,15 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
MAP_SCROLL_VIEW_PROP(zoomScale);
- if (oldScrollViewProps.contentInset != newScrollViewProps.contentInset) {
+ // When disabling centerContent, reset inset to prop value
+ // (enabling is handled automatically by the setCenterContent: setter)
+ if (oldScrollViewProps.centerContent && !newScrollViewProps.centerContent) {
+ _scrollView.contentInset = RCTUIEdgeInsetsFromEdgeInsets(newScrollViewProps.contentInset);
+ }
+
+ // Only apply contentInset from props if centerContent is disabled
+ // When centerContent is enabled, the inset is calculated by centerContentIfNeeded
+ if (oldScrollViewProps.contentInset != newScrollViewProps.contentInset && !newScrollViewProps.centerContent) {
_scrollView.contentInset = RCTUIEdgeInsetsFromEdgeInsets(newScrollViewProps.contentInset);
}
@@ -507,7 +515,7 @@ - (UIView *)betterHitTest:(CGPoint)point withEvent:(UIEvent *)event
}
}
- return isPointInside ? self : nil;
+ return isPointInside ? _scrollView : nil;
}
/*
@@ -1133,6 +1133,11 @@ - (RCTVirtualViewContainerState *)virtualViewContainerState
return _virtualViewContainerState;
}
++ (BOOL)shouldBeRecycled
+{
+ return NO;
+}
+
@end
Class<RCTComponentViewProtocol> RCTScrollViewCls(void)
diff --git a/React/Views/RefreshControl/RCTRefreshControl.h b/React/Views/RefreshControl/RCTRefreshControl.h
index e9b330fa7c29c42653a3b0191d0f8a1b13b2d3de..5fbb2e05cadfc06fd7a18bf52b81bc399e92f3ca 100644
--- a/React/Views/RefreshControl/RCTRefreshControl.h
+++ b/React/Views/RefreshControl/RCTRefreshControl.h
@@ -15,5 +15,6 @@
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
@property (nonatomic, weak) UIScrollView *scrollView;
+@property (nonatomic, copy) UIColor *customTintColor;
@end
diff --git a/React/Views/RefreshControl/RCTRefreshControl.m b/React/Views/RefreshControl/RCTRefreshControl.m
index 53bfd04703502d5b8e932c47a528bb03cd79d330..e2e0c9f4e5d1a3a3b178a7ec69aa63e3039b6dec 100644
--- a/React/Views/RefreshControl/RCTRefreshControl.m
+++ b/React/Views/RefreshControl/RCTRefreshControl.m
@@ -23,6 +23,7 @@ @implementation RCTRefreshControl {
UIColor *_titleColor;
CGFloat _progressViewOffset;
BOOL _hasMovedToWindow;
+ UIColor *_customTintColor;
}
- (instancetype)init
@@ -58,6 +59,12 @@ - (void)layoutSubviews
_isInitialRender = false;
}
+- (void)didMoveToSuperview
+{
+ [super didMoveToSuperview];
+ [self setTintColor:_customTintColor];
+}
+
- (void)didMoveToWindow
{
[super didMoveToWindow];
@@ -221,4 +228,16 @@ - (void)refreshControlValueChanged
}
}
+// Fix for https://github.com/facebook/react-native/issues/43388
+// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor
+// is set before the refresh control gets added to the scrollview. We'll call this
+// function whenever the superview changes. We'll also call it if the value of customTintColor
+// changes.
+- (void)setTintColor:(UIColor *)tintColor
+{
+ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) {
+ [super setTintColor:tintColor];
+ }
+}
+
@end
diff --git a/React/Views/RefreshControl/RCTRefreshControlManager.m b/React/Views/RefreshControl/RCTRefreshControlManager.m
index 40aaf9c51ebda9fedb1d1db2e9aacec84b4c39c8..1c60164b69762997b3369b46609a07768a06bad3 100644
--- a/React/Views/RefreshControl/RCTRefreshControlManager.m
+++ b/React/Views/RefreshControl/RCTRefreshControlManager.m
@@ -22,11 +22,12 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat)
+RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor)
+
RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing)
{
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt
index 89b666dcf0258df0702c812600b685463128294c..2b1c3971f0c31a0d7a592b90170e4cc53a8a69dd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt
@@ -431,6 +431,13 @@ public open class ReactViewGroup public constructor(context: Context?) :
inSubviewClippingLoop = true
var clippedSoFar = 0
for (i in 0..<allChildrenCount) {
+ // Reentrant child removal during this loop can compact allChildren and leave a null at
+ // an index below allChildrenCount. A null entry means the view is already detached, so
+ // treat it as clipped instead of crashing.
+ if (childArray[i] == null) {
+ clippedSoFar++
+ continue
+ }
try {
updateSubviewClipStatus(clippingRect, i, clippedSoFar, excludedViewsSet)
} catch (ex: IndexOutOfBoundsException) {
@@ -466,7 +473,9 @@ public open class ReactViewGroup public constructor(context: Context?) :
) {
assertOnUiThread()
- val child = checkNotNull(allChildren?.get(idx))
+ // allChildren can be mutated reentrantly while a clipping pass is running, so a stale
+ // index can point at a null slot. Skip it instead of crashing.
+ val child = allChildren?.get(idx) ?: return
val intersects = clippingRect.intersects(child.left, child.top, child.right, child.bottom)
var needUpdateClippingRecursive = false
diff --git a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm
index 9b04cad..b2b2762 100644
--- a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm
+++ b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm
@@ -361,7 +361,7 @@ UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties)
font = [UIFont fontWithName:fontProperties.family size:effectiveFontSize];
if (font != nullptr) {
fontNames = [UIFont fontNamesForFamilyName:font.familyName];
- fontWeight = (fontWeight != 0.0) ?: RCTGetFontWeight(font);
+ fontWeight = (fontWeight != 0.0) ? fontWeight : RCTGetFontWeight(font);
} else {
// Failback to system font.
font = RCTDefaultFontWithFontProperties(fontProperties);
diff --git a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
index ac55304..d99c8f4 100644
--- a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
+++ b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
@@ -389,8 +389,9 @@ - (TextMeasurement)_measureTextStorage:(NSTextStorage *)textStorage
size.height = enumeratedLinesHeight;
}
- size = (CGSize){ceil(size.width * layoutContext.pointScaleFactor) / layoutContext.pointScaleFactor,
- ceil(size.height * layoutContext.pointScaleFactor) / layoutContext.pointScaleFactor};
+ CGFloat epsilon = 0.001;
+ size = (CGSize){ceil((size.width + epsilon) * layoutContext.pointScaleFactor) / layoutContext.pointScaleFactor,
+ ceil((size.height + epsilon) * layoutContext.pointScaleFactor) / layoutContext.pointScaleFactor};
NSRange visibleGlyphRange = [layoutManager glyphRangeForTextContainer:textContainer];