From 5bbbd368efbe1a1e8bcea8e49855b51265656767 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 6 Nov 2026 15:14:23 +0700 Subject: [PATCH] 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 4281372bee42e22356f684031d2bba42bfe90562) --- .../paseo-scroll/expo-module.config.json | 2 +- .../paseo-scroll/ios/PaseoScroll.podspec | 16 ++++++++ .../ios/PaseoScrollViewComponentView.mm | 37 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 packages/app/modules/paseo-scroll/ios/PaseoScroll.podspec create mode 100644 packages/app/modules/paseo-scroll/ios/PaseoScrollViewComponentView.mm diff --git a/packages/app/modules/paseo-scroll/expo-module.config.json b/packages/app/modules/paseo-scroll/expo-module.config.json index ba00434407..47b7ac97b7 100644 --- a/packages/app/modules/paseo-scroll/expo-module.config.json +++ b/packages/app/modules/paseo-scroll/expo-module.config.json @@ -1 +1 @@ -{ "platforms": ["android"], "android": { "modules": [] } } +{ "platforms": ["android", "ios"], "android": { "modules": [] }, "ios": { "modules": [] } } diff --git a/packages/app/modules/paseo-scroll/ios/PaseoScroll.podspec b/packages/app/modules/paseo-scroll/ios/PaseoScroll.podspec new file mode 100644 index 0000000000..8ddbfd47b2 --- /dev/null +++ b/packages/app/modules/paseo-scroll/ios/PaseoScroll.podspec @@ -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 diff --git a/packages/app/modules/paseo-scroll/ios/PaseoScrollViewComponentView.mm b/packages/app/modules/paseo-scroll/ios/PaseoScrollViewComponentView.mm new file mode 100644 index 0000000000..6766280058 --- /dev/null +++ b/packages/app/modules/paseo-scroll/ios/PaseoScrollViewComponentView.mm @@ -0,0 +1,37 @@ +#import +#import + +@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