fix(app): keep the chat readable with the keyboard open on iOS 26+ (#8918)

iOS 26 adds a scroll edge effect, a blur at each edge of every scroll view,
and places it in the scroll view's own coordinates without applying
transforms. The keyboard lifts the chat with a translateY, so on iPhones the
blur lands over the readable conversation and stays until the next scroll.
The app draws its own header fade, so the app's ScrollView component class,
which backs every React Native ScrollView, hides all four edge effects.

Co-authored-by: David Greenspan <155814+dgreensp@users.noreply.github.com>
(cherry picked from commit 4281372bee)
This commit is contained in:
Mohamed Boudra
2026-11-06 15:28:38 +01:00
parent e896c05b09
commit 5bbbd368ef
3 changed files with 54 additions and 1 deletions
@@ -1 +1 @@
{ "platforms": ["android"], "android": { "modules": [] } }
{ "platforms": ["android", "ios"], "android": { "modules": [] }, "ios": { "modules": [] } }
@@ -0,0 +1,16 @@
Pod::Spec.new do |s|
s.name = 'PaseoScroll'
s.version = '0.1.0'
s.summary = 'Scroll view corrections for Paseo'
s.description = 'Scroll view corrections for Paseo'
s.license = 'Apache-2.0'
s.author = 'Paseo'
s.homepage = 'https://paseo.sh'
s.platforms = { :ios => '15.1' }
s.source = { :path => '.' }
s.static_framework = true
s.source_files = "**/*.{h,mm}"
install_modules_dependencies(s)
end
@@ -0,0 +1,37 @@
#import <React/RCTComponentViewFactory.h>
#import <React/RCTScrollViewComponentView.h>
@interface PaseoScrollViewComponentView : RCTScrollViewComponentView
@end
@implementation PaseoScrollViewComponentView
// Register before the first Fabric surface creates a ScrollView.
+ (void)load
{
[[RCTComponentViewFactory currentComponentViewFactory] registerComponentViewClass:self];
}
// iOS 26 blurs a scroll view's edges and places the blur in the scroll view's own coordinates,
// ignoring transforms. The keyboard lifts the chat with a translateY, so on iPhones the blur lands
// over the readable chat and stays until the next scroll (#7883). React Native hides it for
// inverted lists for the same reason (https://github.com/react/react-native/pull/58684). The app
// draws its own header fade, so every edge is hidden; hiding only top and bottom leaves the side
// effects, which also cover a transformed list on device.
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
#if defined(__IPHONE_26_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_26_0
if (@available(iOS 26.0, *)) {
UIScrollView *scrollView = self.scrollView;
scrollView.topEdgeEffect.hidden = YES;
scrollView.bottomEdgeEffect.hidden = YES;
scrollView.leftEdgeEffect.hidden = YES;
scrollView.rightEdgeEffect.hidden = YES;
}
#endif
}
return self;
}
@end