From 3b90fd6e3877f154e68ba4112b38295365b57b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 24 Apr 2026 16:08:09 +0200 Subject: [PATCH 01/10] feat(ios): RCTViewControllerAppearanceListener --- .../RCTDefaultReactNativeFactoryDelegate.mm | 3 +- .../Modal/RCTFabricModalHostViewController.h | 4 +- .../React/Views/RCTModalHostViewController.h | 4 +- .../React/Views/RCTViewController.h | 42 +++++++ .../React/Views/RCTViewController.m | 105 ++++++++++++++++++ .../React/Views/RCTWrapperViewController.h | 4 +- .../ios-prebuild/templates/React-umbrella.h | 1 + 7 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 packages/react-native/React/Views/RCTViewController.h create mode 100644 packages/react-native/React/Views/RCTViewController.m diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm index 725c37baf52b..9ef4f13a88ad 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm @@ -7,6 +7,7 @@ #import "RCTDefaultReactNativeFactoryDelegate.h" #import +#import #import "RCTAppSetupUtils.h" #import "RCTDependencyProvider.h" #if USE_THIRD_PARTY_JSC != 1 @@ -28,7 +29,7 @@ - (NSURL *_Nullable)sourceURLForBridge:(nonnull RCTBridge *)bridge - (UIViewController *)createRootViewController { - return [UIViewController new]; + return [RCTViewController new]; } - (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h index 149a9788e2c1..059b415d0162 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h @@ -5,13 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import @protocol RCTFabricModalHostViewControllerDelegate - (void)boundsDidChange:(CGRect)newBounds; @end -@interface RCTFabricModalHostViewController : UIViewController +@interface RCTFabricModalHostViewController : RCTViewController @property (nonatomic, weak) id delegate; diff --git a/packages/react-native/React/Views/RCTModalHostViewController.h b/packages/react-native/React/Views/RCTModalHostViewController.h index 80b075045e5f..dd8f0474a69d 100644 --- a/packages/react-native/React/Views/RCTModalHostViewController.h +++ b/packages/react-native/React/Views/RCTModalHostViewController.h @@ -5,12 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import #ifndef RCT_REMOVE_LEGACY_ARCH __attribute__((deprecated("This API will be removed along with the legacy architecture."))) -@interface RCTModalHostViewController : UIViewController +@interface RCTModalHostViewController : RCTViewController @property (nonatomic, copy) void (^boundsDidChangeBlock)(CGRect newBounds); diff --git a/packages/react-native/React/Views/RCTViewController.h b/packages/react-native/React/Views/RCTViewController.h new file mode 100644 index 000000000000..8cd4d6a9f69f --- /dev/null +++ b/packages/react-native/React/Views/RCTViewController.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol RCTViewControllerAppearanceListener + +@optional +- (void)reactViewControllerDidAppear:(UIViewController *)viewController animated:(BOOL)animated; +- (void)reactViewControllerDidDisappear:(UIViewController *)viewController animated:(BOOL)animated; + +@end + +@interface UIViewController (RCTViewControllerAppearance) + +@property (nonatomic, assign, readonly) BOOL reactViewControllerIsVisible; + +- (void)reactAddViewControllerAppearanceListener:(id)listener; +- (void)reactRemoveViewControllerAppearanceListener:(id)listener; + +/** + * Call from `viewDidAppear:` / `viewDidDisappear:` in UIViewController subclasses + * that cannot inherit from RCTViewController. + */ +- (void)reactNotifyViewControllerDidAppear:(BOOL)animated; +- (void)reactNotifyViewControllerDidDisappear:(BOOL)animated; + +@end + +/** + * UIViewController subclass that forwards appearance events to registered listeners. + */ +@interface RCTViewController : UIViewController +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Views/RCTViewController.m b/packages/react-native/React/Views/RCTViewController.m new file mode 100644 index 000000000000..753bc10b1866 --- /dev/null +++ b/packages/react-native/React/Views/RCTViewController.m @@ -0,0 +1,105 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTViewController.h" + +#import + +@interface RCTViewControllerAppearanceState : NSObject + +@property (nonatomic, strong, readonly) NSHashTable> *listeners; +@property (nonatomic, assign) BOOL visible; + +@end + +@implementation RCTViewControllerAppearanceState + +- (instancetype)init +{ + if (self = [super init]) { + _listeners = [NSHashTable weakObjectsHashTable]; + } + return self; +} + +@end + +@implementation UIViewController (RCTViewControllerAppearance) + +- (RCTViewControllerAppearanceState *)reactViewControllerAppearanceState +{ + RCTViewControllerAppearanceState *state = + objc_getAssociatedObject(self, @selector(reactViewControllerAppearanceState)); + if (!state) { + state = [RCTViewControllerAppearanceState new]; + objc_setAssociatedObject( + self, @selector(reactViewControllerAppearanceState), state, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + return state; +} + +- (BOOL)reactViewControllerIsVisible +{ + return [self reactViewControllerAppearanceState].visible; +} + +- (void)reactAddViewControllerAppearanceListener:(id)listener +{ + RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; + [state.listeners addObject:listener]; + + if (state.visible && [listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { + [listener reactViewControllerDidAppear:self animated:NO]; + } +} + +- (void)reactRemoveViewControllerAppearanceListener:(id)listener +{ + [[self reactViewControllerAppearanceState].listeners removeObject:listener]; +} + +- (void)reactNotifyViewControllerDidAppear:(BOOL)animated +{ + RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; + state.visible = YES; + + for (id listener in state.listeners.allObjects) { + if ([listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { + [listener reactViewControllerDidAppear:self animated:animated]; + } + } +} + +- (void)reactNotifyViewControllerDidDisappear:(BOOL)animated +{ + RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; + state.visible = NO; + + for (id listener in state.listeners.allObjects) { + if ([listener respondsToSelector:@selector(reactViewControllerDidDisappear:animated:)]) { + [listener reactViewControllerDidDisappear:self animated:animated]; + } + } +} + +@end + +@implementation RCTViewController + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [self reactNotifyViewControllerDidAppear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + [self reactNotifyViewControllerDidDisappear:animated]; +} + +@end diff --git a/packages/react-native/React/Views/RCTWrapperViewController.h b/packages/react-native/React/Views/RCTWrapperViewController.h index b8277587684b..08100afb0d58 100644 --- a/packages/react-native/React/Views/RCTWrapperViewController.h +++ b/packages/react-native/React/Views/RCTWrapperViewController.h @@ -5,11 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import @class RCTWrapperViewController; -@interface RCTWrapperViewController : UIViewController +@interface RCTWrapperViewController : RCTViewController - (instancetype)initWithContentView:(UIView *)contentView NS_DESIGNATED_INITIALIZER; diff --git a/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h b/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h index bcd298fd26f5..8b0b0fc1e707 100644 --- a/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h +++ b/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h @@ -274,6 +274,7 @@ #import #import #import +#import #import #import #import From 6d271eb6a8671efb9e1972046c513db13699ae24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 24 Apr 2026 16:28:33 +0200 Subject: [PATCH 02/10] simplify --- .../React/Views/RCTViewController.m | 53 +++++++------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/packages/react-native/React/Views/RCTViewController.m b/packages/react-native/React/Views/RCTViewController.m index 753bc10b1866..adeec052ee72 100644 --- a/packages/react-native/React/Views/RCTViewController.m +++ b/packages/react-native/React/Views/RCTViewController.m @@ -9,65 +9,51 @@ #import -@interface RCTViewControllerAppearanceState : NSObject - -@property (nonatomic, strong, readonly) NSHashTable> *listeners; -@property (nonatomic, assign) BOOL visible; - -@end - -@implementation RCTViewControllerAppearanceState - -- (instancetype)init +static void RCTSetViewControllerIsVisible(UIViewController *viewController, BOOL isVisible) { - if (self = [super init]) { - _listeners = [NSHashTable weakObjectsHashTable]; - } - return self; + objc_setAssociatedObject( + viewController, @selector(reactViewControllerIsVisible), @(isVisible), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -@end - @implementation UIViewController (RCTViewControllerAppearance) -- (RCTViewControllerAppearanceState *)reactViewControllerAppearanceState +- (NSHashTable> *)reactViewControllerAppearanceListeners { - RCTViewControllerAppearanceState *state = - objc_getAssociatedObject(self, @selector(reactViewControllerAppearanceState)); - if (!state) { - state = [RCTViewControllerAppearanceState new]; + NSHashTable> *listeners = + objc_getAssociatedObject(self, @selector(reactViewControllerAppearanceListeners)); + if (!listeners) { + listeners = [NSHashTable weakObjectsHashTable]; objc_setAssociatedObject( - self, @selector(reactViewControllerAppearanceState), state, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self, @selector(reactViewControllerAppearanceListeners), listeners, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - return state; + return listeners; } - (BOOL)reactViewControllerIsVisible { - return [self reactViewControllerAppearanceState].visible; + return [objc_getAssociatedObject(self, @selector(reactViewControllerIsVisible)) boolValue]; } - (void)reactAddViewControllerAppearanceListener:(id)listener { - RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; - [state.listeners addObject:listener]; + [[self reactViewControllerAppearanceListeners] addObject:listener]; - if (state.visible && [listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { + if (self.reactViewControllerIsVisible && + [listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { [listener reactViewControllerDidAppear:self animated:NO]; } } - (void)reactRemoveViewControllerAppearanceListener:(id)listener { - [[self reactViewControllerAppearanceState].listeners removeObject:listener]; + [[self reactViewControllerAppearanceListeners] removeObject:listener]; } - (void)reactNotifyViewControllerDidAppear:(BOOL)animated { - RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; - state.visible = YES; + RCTSetViewControllerIsVisible(self, YES); - for (id listener in state.listeners.allObjects) { + for (id listener in [self reactViewControllerAppearanceListeners].allObjects) { if ([listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { [listener reactViewControllerDidAppear:self animated:animated]; } @@ -76,10 +62,9 @@ - (void)reactNotifyViewControllerDidAppear:(BOOL)animated - (void)reactNotifyViewControllerDidDisappear:(BOOL)animated { - RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; - state.visible = NO; + RCTSetViewControllerIsVisible(self, NO); - for (id listener in state.listeners.allObjects) { + for (id listener in [self reactViewControllerAppearanceListeners].allObjects) { if ([listener respondsToSelector:@selector(reactViewControllerDidDisappear:animated:)]) { [listener reactViewControllerDidDisappear:self animated:animated]; } From f42594f69335c5c7d3f2f490b03d56350b63a837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 24 Apr 2026 16:59:14 +0200 Subject: [PATCH 03/10] fix API mismatches --- .../api-snapshots/ReactAppleDebugCxx.api | 22 ++++++++++++++++--- .../api-snapshots/ReactAppleReleaseCxx.api | 22 ++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index f2c8329be9a1..3ca77e5a2ac3 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -325,6 +325,14 @@ category UIView(React) { public virtual void removeReactSubview:(UIView* subview); } +category UIViewController(RCTViewControllerAppearance) { + public @property (assign, readonly) BOOL reactViewControllerIsVisible; + public virtual void reactAddViewControllerAppearanceListener:(id listener); + public virtual void reactNotifyViewControllerDidAppear:(BOOL animated); + public virtual void reactNotifyViewControllerDidDisappear:(BOOL animated); + public virtual void reactRemoveViewControllerAppearanceListener:(id listener); +} + class ObjCTimerRegistry : public facebook::react::PlatformTimerRegistry { public ObjCTimerRegistry(); public RCTTiming* _Null_unspecified timing; @@ -1156,7 +1164,7 @@ interface RCTExceptionsManager : public NSObject { public virtual void reportSoftException:stack:exceptionId:(_Nullable NSString* message, _Nullable NSArray* stack, double exceptionId); } -interface RCTFabricModalHostViewController : public UIViewController { +interface RCTFabricModalHostViewController : public RCTViewController { public @property (assign) UIInterfaceOrientationMask supportedInterfaceOrientations; public @property (weak) id delegate; } @@ -1517,7 +1525,7 @@ interface RCTModalHostViewComponentView : public RCTViewComponentView { public @property (weak) RCTBridge* bridge; public CGFloat RCTJSONParseOnlyNumber(id json); @@ -2530,7 +2541,7 @@ interface RCTWrapperView : public UIView { public virtual instancetype initWithBridge:(RCTBridge* bridge); } -interface RCTWrapperViewController : public UIViewController { +interface RCTWrapperViewController : public RCTViewController { public virtual instancetype initWithContentView:(UIView* contentView); } @@ -3493,6 +3504,11 @@ protocol RCTValueAnimatedNodeObserver : public NSObject { public virtual void animatedNode:didUpdateValue:(RCTValueAnimatedNode* node, CGFloat value); } +protocol RCTViewControllerAppearanceListener : public NSObject { + public virtual void reactViewControllerDidAppear:animated:(UIViewController* viewController, BOOL animated); + public virtual void reactViewControllerDidDisappear:animated:(UIViewController* viewController, BOOL animated); +} + protocol RCTVirtualViewContainerProtocol { public virtual RCTVirtualViewContainerState* virtualViewContainerState(); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index b7e4ab668f81..4a90f9ef5f13 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -325,6 +325,14 @@ category UIView(React) { public virtual void removeReactSubview:(UIView* subview); } +category UIViewController(RCTViewControllerAppearance) { + public @property (assign, readonly) BOOL reactViewControllerIsVisible; + public virtual void reactAddViewControllerAppearanceListener:(id listener); + public virtual void reactNotifyViewControllerDidAppear:(BOOL animated); + public virtual void reactNotifyViewControllerDidDisappear:(BOOL animated); + public virtual void reactRemoveViewControllerAppearanceListener:(id listener); +} + class ObjCTimerRegistry : public facebook::react::PlatformTimerRegistry { public ObjCTimerRegistry(); public RCTTiming* _Null_unspecified timing; @@ -1156,7 +1164,7 @@ interface RCTExceptionsManager : public NSObject { public virtual void reportSoftException:stack:exceptionId:(_Nullable NSString* message, _Nullable NSArray* stack, double exceptionId); } -interface RCTFabricModalHostViewController : public UIViewController { +interface RCTFabricModalHostViewController : public RCTViewController { public @property (assign) UIInterfaceOrientationMask supportedInterfaceOrientations; public @property (weak) id delegate; } @@ -1517,7 +1525,7 @@ interface RCTModalHostViewComponentView : public RCTViewComponentView { public @property (weak) RCTBridge* bridge; public CGFloat RCTJSONParseOnlyNumber(id json); @@ -2530,7 +2541,7 @@ interface RCTWrapperView : public UIView { public virtual instancetype initWithBridge:(RCTBridge* bridge); } -interface RCTWrapperViewController : public UIViewController { +interface RCTWrapperViewController : public RCTViewController { public virtual instancetype initWithContentView:(UIView* contentView); } @@ -3493,6 +3504,11 @@ protocol RCTValueAnimatedNodeObserver : public NSObject { public virtual void animatedNode:didUpdateValue:(RCTValueAnimatedNode* node, CGFloat value); } +protocol RCTViewControllerAppearanceListener : public NSObject { + public virtual void reactViewControllerDidAppear:animated:(UIViewController* viewController, BOOL animated); + public virtual void reactViewControllerDidDisappear:animated:(UIViewController* viewController, BOOL animated); +} + protocol RCTVirtualViewContainerProtocol { public virtual RCTVirtualViewContainerState* virtualViewContainerState(); } From 94ad872301af6c61ac076bc601297f3f045ea6ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 24 Apr 2026 17:03:45 +0200 Subject: [PATCH 04/10] remove RCTViewController --- .../RCTDefaultReactNativeFactoryDelegate.mm | 3 +- .../Modal/RCTFabricModalHostViewController.h | 4 +- .../React/Views/RCTModalHostViewController.h | 4 +- .../React/Views/RCTViewController.m | 90 ------------------- .../React/Views/RCTWrapperViewController.h | 4 +- ...wController.h => UIViewController+React.h} | 10 +-- .../React/Views/UIViewController+React.m | 89 ++++++++++++++++++ .../ios-prebuild/templates/React-umbrella.h | 2 +- 8 files changed, 99 insertions(+), 107 deletions(-) delete mode 100644 packages/react-native/React/Views/RCTViewController.m rename packages/react-native/React/Views/{RCTViewController.h => UIViewController+React.h} (80%) create mode 100644 packages/react-native/React/Views/UIViewController+React.m diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm index 9ef4f13a88ad..725c37baf52b 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm @@ -7,7 +7,6 @@ #import "RCTDefaultReactNativeFactoryDelegate.h" #import -#import #import "RCTAppSetupUtils.h" #import "RCTDependencyProvider.h" #if USE_THIRD_PARTY_JSC != 1 @@ -29,7 +28,7 @@ - (NSURL *_Nullable)sourceURLForBridge:(nonnull RCTBridge *)bridge - (UIViewController *)createRootViewController { - return [RCTViewController new]; + return [UIViewController new]; } - (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h index 059b415d0162..149a9788e2c1 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTFabricModalHostViewController.h @@ -5,13 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import @protocol RCTFabricModalHostViewControllerDelegate - (void)boundsDidChange:(CGRect)newBounds; @end -@interface RCTFabricModalHostViewController : RCTViewController +@interface RCTFabricModalHostViewController : UIViewController @property (nonatomic, weak) id delegate; diff --git a/packages/react-native/React/Views/RCTModalHostViewController.h b/packages/react-native/React/Views/RCTModalHostViewController.h index dd8f0474a69d..80b075045e5f 100644 --- a/packages/react-native/React/Views/RCTModalHostViewController.h +++ b/packages/react-native/React/Views/RCTModalHostViewController.h @@ -5,12 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import #ifndef RCT_REMOVE_LEGACY_ARCH __attribute__((deprecated("This API will be removed along with the legacy architecture."))) -@interface RCTModalHostViewController : RCTViewController +@interface RCTModalHostViewController : UIViewController @property (nonatomic, copy) void (^boundsDidChangeBlock)(CGRect newBounds); diff --git a/packages/react-native/React/Views/RCTViewController.m b/packages/react-native/React/Views/RCTViewController.m deleted file mode 100644 index adeec052ee72..000000000000 --- a/packages/react-native/React/Views/RCTViewController.m +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import "RCTViewController.h" - -#import - -static void RCTSetViewControllerIsVisible(UIViewController *viewController, BOOL isVisible) -{ - objc_setAssociatedObject( - viewController, @selector(reactViewControllerIsVisible), @(isVisible), OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -@implementation UIViewController (RCTViewControllerAppearance) - -- (NSHashTable> *)reactViewControllerAppearanceListeners -{ - NSHashTable> *listeners = - objc_getAssociatedObject(self, @selector(reactViewControllerAppearanceListeners)); - if (!listeners) { - listeners = [NSHashTable weakObjectsHashTable]; - objc_setAssociatedObject( - self, @selector(reactViewControllerAppearanceListeners), listeners, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - } - return listeners; -} - -- (BOOL)reactViewControllerIsVisible -{ - return [objc_getAssociatedObject(self, @selector(reactViewControllerIsVisible)) boolValue]; -} - -- (void)reactAddViewControllerAppearanceListener:(id)listener -{ - [[self reactViewControllerAppearanceListeners] addObject:listener]; - - if (self.reactViewControllerIsVisible && - [listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { - [listener reactViewControllerDidAppear:self animated:NO]; - } -} - -- (void)reactRemoveViewControllerAppearanceListener:(id)listener -{ - [[self reactViewControllerAppearanceListeners] removeObject:listener]; -} - -- (void)reactNotifyViewControllerDidAppear:(BOOL)animated -{ - RCTSetViewControllerIsVisible(self, YES); - - for (id listener in [self reactViewControllerAppearanceListeners].allObjects) { - if ([listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { - [listener reactViewControllerDidAppear:self animated:animated]; - } - } -} - -- (void)reactNotifyViewControllerDidDisappear:(BOOL)animated -{ - RCTSetViewControllerIsVisible(self, NO); - - for (id listener in [self reactViewControllerAppearanceListeners].allObjects) { - if ([listener respondsToSelector:@selector(reactViewControllerDidDisappear:animated:)]) { - [listener reactViewControllerDidDisappear:self animated:animated]; - } - } -} - -@end - -@implementation RCTViewController - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - [self reactNotifyViewControllerDidAppear:animated]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - [self reactNotifyViewControllerDidDisappear:animated]; -} - -@end diff --git a/packages/react-native/React/Views/RCTWrapperViewController.h b/packages/react-native/React/Views/RCTWrapperViewController.h index 08100afb0d58..b8277587684b 100644 --- a/packages/react-native/React/Views/RCTWrapperViewController.h +++ b/packages/react-native/React/Views/RCTWrapperViewController.h @@ -5,11 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import @class RCTWrapperViewController; -@interface RCTWrapperViewController : RCTViewController +@interface RCTWrapperViewController : UIViewController - (instancetype)initWithContentView:(UIView *)contentView NS_DESIGNATED_INITIALIZER; diff --git a/packages/react-native/React/Views/RCTViewController.h b/packages/react-native/React/Views/UIViewController+React.h similarity index 80% rename from packages/react-native/React/Views/RCTViewController.h rename to packages/react-native/React/Views/UIViewController+React.h index 8cd4d6a9f69f..f765467a0223 100644 --- a/packages/react-native/React/Views/RCTViewController.h +++ b/packages/react-native/React/Views/UIViewController+React.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface UIViewController (RCTViewControllerAppearance) +@interface UIViewController (React) @property (nonatomic, assign, readonly) BOOL reactViewControllerIsVisible; @@ -26,17 +26,11 @@ NS_ASSUME_NONNULL_BEGIN /** * Call from `viewDidAppear:` / `viewDidDisappear:` in UIViewController subclasses - * that cannot inherit from RCTViewController. + * that want to notify registered React Native appearance listeners. */ - (void)reactNotifyViewControllerDidAppear:(BOOL)animated; - (void)reactNotifyViewControllerDidDisappear:(BOOL)animated; @end -/** - * UIViewController subclass that forwards appearance events to registered listeners. - */ -@interface RCTViewController : UIViewController -@end - NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Views/UIViewController+React.m b/packages/react-native/React/Views/UIViewController+React.m new file mode 100644 index 000000000000..df18a0904051 --- /dev/null +++ b/packages/react-native/React/Views/UIViewController+React.m @@ -0,0 +1,89 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "UIViewController+React.h" + +#import + +@interface RCTViewControllerAppearanceState : NSObject + +@property (nonatomic, strong, readonly) NSHashTable> *listeners; +@property (nonatomic, assign) BOOL visible; + +@end + +@implementation RCTViewControllerAppearanceState + +- (instancetype)init +{ + if (self = [super init]) { + _listeners = [NSHashTable weakObjectsHashTable]; + } + return self; +} + +@end + +@implementation UIViewController (React) + +- (RCTViewControllerAppearanceState *)reactViewControllerAppearanceState +{ + RCTViewControllerAppearanceState *state = + objc_getAssociatedObject(self, @selector(reactViewControllerAppearanceState)); + if (!state) { + state = [RCTViewControllerAppearanceState new]; + objc_setAssociatedObject( + self, @selector(reactViewControllerAppearanceState), state, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + return state; +} + +- (BOOL)reactViewControllerIsVisible +{ + return [self reactViewControllerAppearanceState].visible; +} + +- (void)reactAddViewControllerAppearanceListener:(id)listener +{ + RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; + [state.listeners addObject:listener]; + + if (state.visible && [listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { + [listener reactViewControllerDidAppear:self animated:NO]; + } +} + +- (void)reactRemoveViewControllerAppearanceListener:(id)listener +{ + [[self reactViewControllerAppearanceState].listeners removeObject:listener]; +} + +- (void)reactNotifyViewControllerDidAppear:(BOOL)animated +{ + RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; + state.visible = YES; + + for (id listener in state.listeners.allObjects) { + if ([listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) { + [listener reactViewControllerDidAppear:self animated:animated]; + } + } +} + +- (void)reactNotifyViewControllerDidDisappear:(BOOL)animated +{ + RCTViewControllerAppearanceState *state = [self reactViewControllerAppearanceState]; + state.visible = NO; + + for (id listener in state.listeners.allObjects) { + if ([listener respondsToSelector:@selector(reactViewControllerDidDisappear:animated:)]) { + [listener reactViewControllerDidDisappear:self animated:animated]; + } + } +} + +@end diff --git a/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h b/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h index 8b0b0fc1e707..19898532a7b6 100644 --- a/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h +++ b/packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h @@ -274,7 +274,6 @@ #import #import #import -#import #import #import #import @@ -284,6 +283,7 @@ #import #import #import +#import FOUNDATION_EXPORT double ReactVersionNumber; FOUNDATION_EXPORT const unsigned char ReactVersionString[]; From 3c03d8e7ad36fc8d062616535452e53642ab954c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 24 Apr 2026 17:10:25 +0200 Subject: [PATCH 05/10] fix API mismatches --- scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api | 11 ++++------- .../cxx-api/api-snapshots/ReactAppleReleaseCxx.api | 11 ++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 3ca77e5a2ac3..a6d24b8d3c46 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -325,7 +325,7 @@ category UIView(React) { public virtual void removeReactSubview:(UIView* subview); } -category UIViewController(RCTViewControllerAppearance) { +category UIViewController(React) { public @property (assign, readonly) BOOL reactViewControllerIsVisible; public virtual void reactAddViewControllerAppearanceListener:(id listener); public virtual void reactNotifyViewControllerDidAppear:(BOOL animated); @@ -1164,7 +1164,7 @@ interface RCTExceptionsManager : public NSObject { public virtual void reportSoftException:stack:exceptionId:(_Nullable NSString* message, _Nullable NSArray* stack, double exceptionId); } -interface RCTFabricModalHostViewController : public RCTViewController { +interface RCTFabricModalHostViewController : public UIViewController { public @property (assign) UIInterfaceOrientationMask supportedInterfaceOrientations; public @property (weak) id delegate; } @@ -1525,7 +1525,7 @@ interface RCTModalHostViewComponentView : public RCTViewComponentView { public @property (weak) RCTBridge* bridge; public CGFloat RCTJSONParseOnlyNumber(id json); @@ -2541,7 +2538,7 @@ interface RCTWrapperView : public UIView { public virtual instancetype initWithBridge:(RCTBridge* bridge); } -interface RCTWrapperViewController : public RCTViewController { +interface RCTWrapperViewController : public UIViewController { public virtual instancetype initWithContentView:(UIView* contentView); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 4a90f9ef5f13..5a12845514e5 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -325,7 +325,7 @@ category UIView(React) { public virtual void removeReactSubview:(UIView* subview); } -category UIViewController(RCTViewControllerAppearance) { +category UIViewController(React) { public @property (assign, readonly) BOOL reactViewControllerIsVisible; public virtual void reactAddViewControllerAppearanceListener:(id listener); public virtual void reactNotifyViewControllerDidAppear:(BOOL animated); @@ -1164,7 +1164,7 @@ interface RCTExceptionsManager : public NSObject { public virtual void reportSoftException:stack:exceptionId:(_Nullable NSString* message, _Nullable NSArray* stack, double exceptionId); } -interface RCTFabricModalHostViewController : public RCTViewController { +interface RCTFabricModalHostViewController : public UIViewController { public @property (assign) UIInterfaceOrientationMask supportedInterfaceOrientations; public @property (weak) id delegate; } @@ -1525,7 +1525,7 @@ interface RCTModalHostViewComponentView : public RCTViewComponentView { public @property (weak) RCTBridge* bridge; public CGFloat RCTJSONParseOnlyNumber(id json); @@ -2541,7 +2538,7 @@ interface RCTWrapperView : public UIView { public virtual instancetype initWithBridge:(RCTBridge* bridge); } -interface RCTWrapperViewController : public RCTViewController { +interface RCTWrapperViewController : public UIViewController { public virtual instancetype initWithContentView:(UIView* contentView); } From 4099a1596995bcedd45d7fd3a73f0670030008bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 27 Apr 2026 11:04:52 +0200 Subject: [PATCH 06/10] change(ios): make root VC notify on viewDidAppear/-Disappear --- .../RCTDefaultReactNativeFactoryDelegate.mm | 3 +- .../React/Views/RCTViewController.h | 17 +++++++++++ .../React/Views/RCTViewController.m | 29 +++++++++++++++++++ .../React/Views/RCTWrapperViewController.h | 4 +-- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 packages/react-native/React/Views/RCTViewController.h create mode 100644 packages/react-native/React/Views/RCTViewController.m diff --git a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm index 725c37baf52b..9ef4f13a88ad 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm @@ -7,6 +7,7 @@ #import "RCTDefaultReactNativeFactoryDelegate.h" #import +#import #import "RCTAppSetupUtils.h" #import "RCTDependencyProvider.h" #if USE_THIRD_PARTY_JSC != 1 @@ -28,7 +29,7 @@ - (NSURL *_Nullable)sourceURLForBridge:(nonnull RCTBridge *)bridge - (UIViewController *)createRootViewController { - return [UIViewController new]; + return [RCTViewController new]; } - (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions diff --git a/packages/react-native/React/Views/RCTViewController.h b/packages/react-native/React/Views/RCTViewController.h new file mode 100644 index 000000000000..020630862dec --- /dev/null +++ b/packages/react-native/React/Views/RCTViewController.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Views/RCTViewController.m b/packages/react-native/React/Views/RCTViewController.m new file mode 100644 index 000000000000..c9d111b3e17a --- /dev/null +++ b/packages/react-native/React/Views/RCTViewController.m @@ -0,0 +1,29 @@ +// +// RCTViewController.m +// React-Core +// +// Created by Hanno Goedecke on 27.04.26. +// + +#import "RCTViewController.h" +#import + +@interface RCTViewController () + +@end + +@implementation RCTViewController + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [self reactNotifyViewControllerDidAppear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + [self reactNotifyViewControllerDidDisappear:animated]; +} + +@end diff --git a/packages/react-native/React/Views/RCTWrapperViewController.h b/packages/react-native/React/Views/RCTWrapperViewController.h index b8277587684b..08100afb0d58 100644 --- a/packages/react-native/React/Views/RCTWrapperViewController.h +++ b/packages/react-native/React/Views/RCTWrapperViewController.h @@ -5,11 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import @class RCTWrapperViewController; -@interface RCTWrapperViewController : UIViewController +@interface RCTWrapperViewController : RCTViewController - (instancetype)initWithContentView:(UIView *)contentView NS_DESIGNATED_INITIALIZER; From 6e9fa53e8e450fec40196c3b8989e2d82538a63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 27 Apr 2026 12:47:03 +0200 Subject: [PATCH 07/10] APi mismatches --- scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api | 5 ++++- scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index a6d24b8d3c46..e8d381b3a7ca 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -2475,6 +2475,9 @@ interface RCTViewComponentView : public UIView { public @property (weak) RCTBridge* bridge; public CGFloat RCTJSONParseOnlyNumber(id json); @@ -2538,7 +2541,7 @@ interface RCTWrapperView : public UIView { public virtual instancetype initWithBridge:(RCTBridge* bridge); } -interface RCTWrapperViewController : public UIViewController { +interface RCTWrapperViewController : public RCTViewController { public virtual instancetype initWithContentView:(UIView* contentView); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 5a12845514e5..ac156f189fdc 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -2475,6 +2475,9 @@ interface RCTViewComponentView : public UIView { public @property (weak) RCTBridge* bridge; public CGFloat RCTJSONParseOnlyNumber(id json); @@ -2538,7 +2541,7 @@ interface RCTWrapperView : public UIView { public virtual instancetype initWithBridge:(RCTBridge* bridge); } -interface RCTWrapperViewController : public UIViewController { +interface RCTWrapperViewController : public RCTViewController { public virtual instancetype initWithContentView:(UIView* contentView); } From 813e5fe57acdac8fbc6bd0f41948c4e6d6b9f660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 27 Apr 2026 11:19:47 +0200 Subject: [PATCH 08/10] WIP: view controller switch to viewDidAppear --- .../TextInput/RCTTextInputComponentView.mm | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index c0e56acd2a0f..bc0f88703db0 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -17,6 +17,8 @@ #import #import #import +#import +#import #import "RCTConversions.h" #import "RCTTextInputNativeCommands.h" @@ -32,6 +34,7 @@ @interface RCTTextInputComponentView () < RCTBackedTextInputDelegate, + RCTViewControllerAppearanceListener, RCTTextInputViewProtocol #if !TARGET_OS_TV , @@ -70,6 +73,8 @@ @implementation RCTTextInputComponentView { */ BOOL _comingFromJS; BOOL _didMoveToWindow; + BOOL _didAutoFocus; + __weak UIViewController *_viewController; /* * Newly initialized default typing attributes contain a no-op NSParagraphStyle and NSShadow. These cause inequality @@ -95,6 +100,7 @@ - (instancetype)initWithFrame:(CGRect)frame _ignoreNextTextInputCall = NO; _comingFromJS = NO; _didMoveToWindow = NO; + _didAutoFocus = NO; _originalTypingAttributes = [_backedTextInputView.typingAttributes copy]; _previousContentSize = CGSizeZero; @@ -121,12 +127,11 @@ - (void)didMoveToWindow { [super didMoveToWindow]; + [_viewController reactRemoveViewControllerAppearanceListener:self]; + _viewController = self.window ? [self reactViewController] : nil; + [_viewController reactAddViewControllerAppearanceListener:self]; + if (self.window && !_didMoveToWindow) { - const auto &props = static_cast(*_props); - if (props.autoFocus) { - [_backedTextInputView becomeFirstResponder]; - [self scrollCursorIntoView]; - } _didMoveToWindow = YES; [self initializeReturnKeyType]; } @@ -384,12 +389,27 @@ - (void)prepareForRecycle _lastStringStateWasUpdatedWith = nil; _ignoreNextTextInputCall = NO; _didMoveToWindow = NO; + _didAutoFocus = NO; + [_viewController reactRemoveViewControllerAppearanceListener:self]; + _viewController = nil; _backedTextInputView.inputAccessoryViewID = nil; _backedTextInputView.inputAccessoryView = nil; _hasInputAccessoryView = false; [_backedTextInputView resignFirstResponder]; } +#pragma mark - RCTViewControllerAppearanceListener + +- (void)reactViewControllerDidAppear:(UIViewController *)viewController animated:(BOOL)animated +{ + const auto &props = static_cast(*_props); + if (props.autoFocus && !_didAutoFocus) { + _didAutoFocus = YES; + [_backedTextInputView becomeFirstResponder]; + [self scrollCursorIntoView]; + } +} + #pragma mark - RCTBackedTextInputDelegate - (BOOL)textInputShouldBeginEditing From 601729c37f59a9878edc2b36924d99fdb4308d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 27 Apr 2026 11:28:54 +0200 Subject: [PATCH 09/10] Add enableIOSExperimentalAutoFocusImplementation feature falg --- .../featureflags/ReactNativeFeatureFlags.kt | 8 +- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 +- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 +- ...agsOverrides_RNOSS_Experimental_Android.kt | 4 +- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +- .../featureflags/ReactNativeFeatureFlags.h | 7 +- .../ReactNativeFeatureFlagsAccessor.cpp | 150 ++++++++++-------- .../ReactNativeFeatureFlagsAccessor.h | 6 +- .../ReactNativeFeatureFlagsDefaults.h | 6 +- .../ReactNativeFeatureFlagsDynamicProvider.h | 11 +- ...tiveFeatureFlagsOverridesOSSExperimental.h | 6 +- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 +- .../NativeReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlags.config.js | 10 ++ .../featureflags/ReactNativeFeatureFlags.js | 7 +- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 22 files changed, 209 insertions(+), 87 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index 5a9736feef95..382061a5b911 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<1e2cf81bf4354a7e3d9d09384d813cfc>> */ /** @@ -186,6 +186,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableFontScaleChangesUpdatingLayout(): Boolean = accessor.enableFontScaleChangesUpdatingLayout() + /** + * Fixes #56595 by moving the autoFocus from didMoveToWindow to viewDidAppear + */ + @JvmStatic + public fun enableIOSExperimentalAutoFocusImplementation(): Boolean = accessor.enableIOSExperimentalAutoFocusImplementation() + /** * Applies base offset for each line of text separately on iOS. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index 31e7ff51beb2..9937b497fd28 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<8dd2a1c47c059810961eb66b13b18dc1>> */ /** @@ -46,6 +46,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var enableFabricLogsCache: Boolean? = null private var enableFabricRendererCache: Boolean? = null private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null + private var enableIOSExperimentalAutoFocusImplementationCache: Boolean? = null private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null private var enableIOSViewClipToPaddingBoxCache: Boolean? = null private var enableImagePrefetchingAndroidCache: Boolean? = null @@ -346,6 +347,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableIOSExperimentalAutoFocusImplementation(): Boolean { + var cached = enableIOSExperimentalAutoFocusImplementationCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableIOSExperimentalAutoFocusImplementation() + enableIOSExperimentalAutoFocusImplementationCache = cached + } + return cached + } + override fun enableIOSTextBaselineOffsetPerLine(): Boolean { var cached = enableIOSTextBaselineOffsetPerLineCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 345b7649dfde..681a654f85cb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<62d1f0fcdf8e3165480da12575d62826>> + * @generated SignedSource<> */ /** @@ -80,6 +80,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableFontScaleChangesUpdatingLayout(): Boolean + @DoNotStrip @JvmStatic public external fun enableIOSExperimentalAutoFocusImplementation(): Boolean + @DoNotStrip @JvmStatic public external fun enableIOSTextBaselineOffsetPerLine(): Boolean @DoNotStrip @JvmStatic public external fun enableIOSViewClipToPaddingBox(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index e9d57e7423b3..3b24f9b18796 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<84ac5b80585f9185c879c81822718d86>> + * @generated SignedSource<<27361d399f26a6f7462a82f9fbfd5d48>> */ /** @@ -75,6 +75,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableFontScaleChangesUpdatingLayout(): Boolean = true + override fun enableIOSExperimentalAutoFocusImplementation(): Boolean = false + override fun enableIOSTextBaselineOffsetPerLine(): Boolean = false override fun enableIOSViewClipToPaddingBox(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index d076ea34d2ff..ae4992cbb293 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<3574e23fe8f846e408964af26cf0dd4c>> + * @generated SignedSource<> */ /** @@ -50,6 +50,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var enableFabricLogsCache: Boolean? = null private var enableFabricRendererCache: Boolean? = null private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null + private var enableIOSExperimentalAutoFocusImplementationCache: Boolean? = null private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null private var enableIOSViewClipToPaddingBoxCache: Boolean? = null private var enableImagePrefetchingAndroidCache: Boolean? = null @@ -376,6 +377,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun enableIOSExperimentalAutoFocusImplementation(): Boolean { + var cached = enableIOSExperimentalAutoFocusImplementationCache + if (cached == null) { + cached = currentProvider.enableIOSExperimentalAutoFocusImplementation() + accessedFeatureFlags.add("enableIOSExperimentalAutoFocusImplementation") + enableIOSExperimentalAutoFocusImplementationCache = cached + } + return cached + } + override fun enableIOSTextBaselineOffsetPerLine(): Boolean { var cached = enableIOSTextBaselineOffsetPerLineCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt index c806054c45fc..3bad62e6b8b1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<187ac62197545fbce9d537527b4aed3b>> + * @generated SignedSource<> */ /** @@ -27,6 +27,8 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android : override fun enableAccessibilityOrder(): Boolean = true + override fun enableIOSExperimentalAutoFocusImplementation(): Boolean = true + override fun enableSwiftUIBasedFilters(): Boolean = true override fun preventShadowTreeCommitExhaustion(): Boolean = true diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 6edb264c3c99..1bb0103414b5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<9222fd90d191a91893e2c58770d83259>> + * @generated SignedSource<> */ /** @@ -75,6 +75,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableFontScaleChangesUpdatingLayout(): Boolean + @DoNotStrip public fun enableIOSExperimentalAutoFocusImplementation(): Boolean + @DoNotStrip public fun enableIOSTextBaselineOffsetPerLine(): Boolean @DoNotStrip public fun enableIOSViewClipToPaddingBox(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 365b7f6392a0..777f34dcbee7 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -195,6 +195,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool enableIOSExperimentalAutoFocusImplementation() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableIOSExperimentalAutoFocusImplementation"); + return method(javaProvider_); + } + bool enableIOSTextBaselineOffsetPerLine() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableIOSTextBaselineOffsetPerLine"); @@ -719,6 +725,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableFontScaleChangesUpdatingLayout( return ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout(); } +bool JReactNativeFeatureFlagsCxxInterop::enableIOSExperimentalAutoFocusImplementation( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableIOSExperimentalAutoFocusImplementation(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableIOSTextBaselineOffsetPerLine( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine(); @@ -1153,6 +1164,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableFontScaleChangesUpdatingLayout", JReactNativeFeatureFlagsCxxInterop::enableFontScaleChangesUpdatingLayout), + makeNativeMethod( + "enableIOSExperimentalAutoFocusImplementation", + JReactNativeFeatureFlagsCxxInterop::enableIOSExperimentalAutoFocusImplementation), makeNativeMethod( "enableIOSTextBaselineOffsetPerLine", JReactNativeFeatureFlagsCxxInterop::enableIOSTextBaselineOffsetPerLine), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index 27d515ea5167..0c1b2830c9d6 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<773741594e911047dac28904e9fc9544>> + * @generated SignedSource<<0d42119f721e3240e5d140b865547e18>> */ /** @@ -108,6 +108,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableFontScaleChangesUpdatingLayout( facebook::jni::alias_ref); + static bool enableIOSExperimentalAutoFocusImplementation( + facebook::jni::alias_ref); + static bool enableIOSTextBaselineOffsetPerLine( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 071660787b0b..2d35115ccdce 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<6a15a6444767342acf4da0c0c8aa6208>> + * @generated SignedSource<<11c0b22fb3739bdbb269084214263fe3>> */ /** @@ -130,6 +130,10 @@ bool ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout() { return getAccessor().enableFontScaleChangesUpdatingLayout(); } +bool ReactNativeFeatureFlags::enableIOSExperimentalAutoFocusImplementation() { + return getAccessor().enableIOSExperimentalAutoFocusImplementation(); +} + bool ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine() { return getAccessor().enableIOSTextBaselineOffsetPerLine(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index dab48f3e43cc..37994150284d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<62d1840f9a39eaceaa800542b7351a41>> + * @generated SignedSource<<48115b5bbcdf8122a252d6c6c16e9c81>> */ /** @@ -169,6 +169,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableFontScaleChangesUpdatingLayout(); + /** + * Fixes #56595 by moving the autoFocus from didMoveToWindow to viewDidAppear + */ + RN_EXPORT static bool enableIOSExperimentalAutoFocusImplementation(); + /** * Applies base offset for each line of text separately on iOS. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index d4f6761af0e7..e99a424a8d53 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -497,6 +497,24 @@ bool ReactNativeFeatureFlagsAccessor::enableFontScaleChangesUpdatingLayout() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableIOSExperimentalAutoFocusImplementation() { + auto flagValue = enableIOSExperimentalAutoFocusImplementation_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(26, "enableIOSExperimentalAutoFocusImplementation"); + + flagValue = currentProvider_->enableIOSExperimentalAutoFocusImplementation(); + enableIOSExperimentalAutoFocusImplementation_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableIOSTextBaselineOffsetPerLine() { auto flagValue = enableIOSTextBaselineOffsetPerLine_.load(); @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSTextBaselineOffsetPerLine() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "enableIOSTextBaselineOffsetPerLine"); + markFlagAsAccessed(27, "enableIOSTextBaselineOffsetPerLine"); flagValue = currentProvider_->enableIOSTextBaselineOffsetPerLine(); enableIOSTextBaselineOffsetPerLine_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(28, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImagePrefetchingAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "enableImagePrefetchingAndroid"); + markFlagAsAccessed(29, "enableImagePrefetchingAndroid"); flagValue = currentProvider_->enableImagePrefetchingAndroid(); enableImagePrefetchingAndroid_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImagePrefetchingJNIBatchingAndroid() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "enableImagePrefetchingJNIBatchingAndroid"); + markFlagAsAccessed(30, "enableImagePrefetchingJNIBatchingAndroid"); flagValue = currentProvider_->enableImagePrefetchingJNIBatchingAndroid(); enableImagePrefetchingJNIBatchingAndroid_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImagePrefetchingOnUiThreadAndroid() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "enableImagePrefetchingOnUiThreadAndroid"); + markFlagAsAccessed(31, "enableImagePrefetchingOnUiThreadAndroid"); flagValue = currentProvider_->enableImagePrefetchingOnUiThreadAndroid(); enableImagePrefetchingOnUiThreadAndroid_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImmediateUpdateModeForContentOffsetC // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "enableImmediateUpdateModeForContentOffsetChanges"); + markFlagAsAccessed(32, "enableImmediateUpdateModeForContentOffsetChanges"); flagValue = currentProvider_->enableImmediateUpdateModeForContentOffsetChanges(); enableImmediateUpdateModeForContentOffsetChanges_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImperativeFocus() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "enableImperativeFocus"); + markFlagAsAccessed(33, "enableImperativeFocus"); flagValue = currentProvider_->enableImperativeFocus(); enableImperativeFocus_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::enableInteropViewManagerClassLookUpOptimiz // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "enableInteropViewManagerClassLookUpOptimizationIOS"); + markFlagAsAccessed(34, "enableInteropViewManagerClassLookUpOptimizationIOS"); flagValue = currentProvider_->enableInteropViewManagerClassLookUpOptimizationIOS(); enableInteropViewManagerClassLookUpOptimizationIOS_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIntersectionObserverByDefault() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "enableIntersectionObserverByDefault"); + markFlagAsAccessed(35, "enableIntersectionObserverByDefault"); flagValue = currentProvider_->enableIntersectionObserverByDefault(); enableIntersectionObserverByDefault_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::enableKeyEvents() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "enableKeyEvents"); + markFlagAsAccessed(36, "enableKeyEvents"); flagValue = currentProvider_->enableKeyEvents(); enableKeyEvents_ = flagValue; @@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(36, "enableLayoutAnimationsOnAndroid"); + markFlagAsAccessed(37, "enableLayoutAnimationsOnAndroid"); flagValue = currentProvider_->enableLayoutAnimationsOnAndroid(); enableLayoutAnimationsOnAndroid_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(38, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMainQueueCoordinatorOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "enableMainQueueCoordinatorOnIOS"); + markFlagAsAccessed(39, "enableMainQueueCoordinatorOnIOS"); flagValue = currentProvider_->enableMainQueueCoordinatorOnIOS(); enableMainQueueCoordinatorOnIOS_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::enableModuleArgumentNSNullConversionIOS() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "enableModuleArgumentNSNullConversionIOS"); + markFlagAsAccessed(40, "enableModuleArgumentNSNullConversionIOS"); flagValue = currentProvider_->enableModuleArgumentNSNullConversionIOS(); enableModuleArgumentNSNullConversionIOS_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMutationObserverByDefault() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "enableMutationObserverByDefault"); + markFlagAsAccessed(41, "enableMutationObserverByDefault"); flagValue = currentProvider_->enableMutationObserverByDefault(); enableMutationObserverByDefault_ = flagValue; @@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(41, "enableNativeCSSParsing"); + markFlagAsAccessed(42, "enableNativeCSSParsing"); flagValue = currentProvider_->enableNativeCSSParsing(); enableNativeCSSParsing_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeViewPropTransformations() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "enableNativeViewPropTransformations"); + markFlagAsAccessed(43, "enableNativeViewPropTransformations"); flagValue = currentProvider_->enableNativeViewPropTransformations(); enableNativeViewPropTransformations_ = flagValue; @@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNetworkEventReporting() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(43, "enableNetworkEventReporting"); + markFlagAsAccessed(44, "enableNetworkEventReporting"); flagValue = currentProvider_->enableNetworkEventReporting(); enableNetworkEventReporting_ = flagValue; @@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreparedTextLayout() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(44, "enablePreparedTextLayout"); + markFlagAsAccessed(45, "enablePreparedTextLayout"); flagValue = currentProvider_->enablePreparedTextLayout(); enablePreparedTextLayout_ = flagValue; @@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(45, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(46, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSwiftUIBasedFilters() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(46, "enableSwiftUIBasedFilters"); + markFlagAsAccessed(47, "enableSwiftUIBasedFilters"); flagValue = currentProvider_->enableSwiftUIBasedFilters(); enableSwiftUIBasedFilters_ = flagValue; @@ -884,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(47, "enableViewCulling"); + markFlagAsAccessed(48, "enableViewCulling"); flagValue = currentProvider_->enableViewCulling(); enableViewCulling_ = flagValue; @@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(48, "enableViewRecycling"); + markFlagAsAccessed(49, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -920,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForImage() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(49, "enableViewRecyclingForImage"); + markFlagAsAccessed(50, "enableViewRecyclingForImage"); flagValue = currentProvider_->enableViewRecyclingForImage(); enableViewRecyclingForImage_ = flagValue; @@ -938,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForScrollView() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(50, "enableViewRecyclingForScrollView"); + markFlagAsAccessed(51, "enableViewRecyclingForScrollView"); flagValue = currentProvider_->enableViewRecyclingForScrollView(); enableViewRecyclingForScrollView_ = flagValue; @@ -956,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(51, "enableViewRecyclingForText"); + markFlagAsAccessed(52, "enableViewRecyclingForText"); flagValue = currentProvider_->enableViewRecyclingForText(); enableViewRecyclingForText_ = flagValue; @@ -974,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(52, "enableViewRecyclingForView"); + markFlagAsAccessed(53, "enableViewRecyclingForView"); flagValue = currentProvider_->enableViewRecyclingForView(); enableViewRecyclingForView_ = flagValue; @@ -992,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewContainerStateExperimenta // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(53, "enableVirtualViewContainerStateExperimental"); + markFlagAsAccessed(54, "enableVirtualViewContainerStateExperimental"); flagValue = currentProvider_->enableVirtualViewContainerStateExperimental(); enableVirtualViewContainerStateExperimental_ = flagValue; @@ -1010,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewDebugFeatures() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(54, "enableVirtualViewDebugFeatures"); + markFlagAsAccessed(55, "enableVirtualViewDebugFeatures"); flagValue = currentProvider_->enableVirtualViewDebugFeatures(); enableVirtualViewDebugFeatures_ = flagValue; @@ -1028,7 +1046,7 @@ bool ReactNativeFeatureFlagsAccessor::fixDifferentiatorParentTagForUnflattenCase // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(55, "fixDifferentiatorParentTagForUnflattenCase"); + markFlagAsAccessed(56, "fixDifferentiatorParentTagForUnflattenCase"); flagValue = currentProvider_->fixDifferentiatorParentTagForUnflattenCase(); fixDifferentiatorParentTagForUnflattenCase_ = flagValue; @@ -1046,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::fixFindShadowNodeByTagRaceCondition() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(56, "fixFindShadowNodeByTagRaceCondition"); + markFlagAsAccessed(57, "fixFindShadowNodeByTagRaceCondition"); flagValue = currentProvider_->fixFindShadowNodeByTagRaceCondition(); fixFindShadowNodeByTagRaceCondition_ = flagValue; @@ -1064,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(57, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(58, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -1082,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::fixYogaFlexBasisFitContentInMainAxis() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(58, "fixYogaFlexBasisFitContentInMainAxis"); + markFlagAsAccessed(59, "fixYogaFlexBasisFitContentInMainAxis"); flagValue = currentProvider_->fixYogaFlexBasisFitContentInMainAxis(); fixYogaFlexBasisFitContentInMainAxis_ = flagValue; @@ -1100,7 +1118,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxAssertSingleHostState() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(59, "fuseboxAssertSingleHostState"); + markFlagAsAccessed(60, "fuseboxAssertSingleHostState"); flagValue = currentProvider_->fuseboxAssertSingleHostState(); fuseboxAssertSingleHostState_ = flagValue; @@ -1118,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(60, "fuseboxEnabledRelease"); + markFlagAsAccessed(61, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -1136,7 +1154,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxFrameRecordingEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(61, "fuseboxFrameRecordingEnabled"); + markFlagAsAccessed(62, "fuseboxFrameRecordingEnabled"); flagValue = currentProvider_->fuseboxFrameRecordingEnabled(); fuseboxFrameRecordingEnabled_ = flagValue; @@ -1154,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(62, "fuseboxNetworkInspectionEnabled"); + markFlagAsAccessed(63, "fuseboxNetworkInspectionEnabled"); flagValue = currentProvider_->fuseboxNetworkInspectionEnabled(); fuseboxNetworkInspectionEnabled_ = flagValue; @@ -1172,7 +1190,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxScreenshotCaptureEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(63, "fuseboxScreenshotCaptureEnabled"); + markFlagAsAccessed(64, "fuseboxScreenshotCaptureEnabled"); flagValue = currentProvider_->fuseboxScreenshotCaptureEnabled(); fuseboxScreenshotCaptureEnabled_ = flagValue; @@ -1190,7 +1208,7 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(64, "hideOffscreenVirtualViewsOnIOS"); + markFlagAsAccessed(65, "hideOffscreenVirtualViewsOnIOS"); flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS(); hideOffscreenVirtualViewsOnIOS_ = flagValue; @@ -1208,7 +1226,7 @@ bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(65, "overrideBySynchronousMountPropsAtMountingAndroid"); + markFlagAsAccessed(66, "overrideBySynchronousMountPropsAtMountingAndroid"); flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid(); overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue; @@ -1226,7 +1244,7 @@ bool ReactNativeFeatureFlagsAccessor::perfIssuesEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(66, "perfIssuesEnabled"); + markFlagAsAccessed(67, "perfIssuesEnabled"); flagValue = currentProvider_->perfIssuesEnabled(); perfIssuesEnabled_ = flagValue; @@ -1244,7 +1262,7 @@ bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(67, "perfMonitorV2Enabled"); + markFlagAsAccessed(68, "perfMonitorV2Enabled"); flagValue = currentProvider_->perfMonitorV2Enabled(); perfMonitorV2Enabled_ = flagValue; @@ -1262,7 +1280,7 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(68, "preparedTextCacheSize"); + markFlagAsAccessed(69, "preparedTextCacheSize"); flagValue = currentProvider_->preparedTextCacheSize(); preparedTextCacheSize_ = flagValue; @@ -1280,7 +1298,7 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(69, "preventShadowTreeCommitExhaustion"); + markFlagAsAccessed(70, "preventShadowTreeCommitExhaustion"); flagValue = currentProvider_->preventShadowTreeCommitExhaustion(); preventShadowTreeCommitExhaustion_ = flagValue; @@ -1298,7 +1316,7 @@ bool ReactNativeFeatureFlagsAccessor::redBoxV2Android() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(70, "redBoxV2Android"); + markFlagAsAccessed(71, "redBoxV2Android"); flagValue = currentProvider_->redBoxV2Android(); redBoxV2Android_ = flagValue; @@ -1316,7 +1334,7 @@ bool ReactNativeFeatureFlagsAccessor::redBoxV2IOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(71, "redBoxV2IOS"); + markFlagAsAccessed(72, "redBoxV2IOS"); flagValue = currentProvider_->redBoxV2IOS(); redBoxV2IOS_ = flagValue; @@ -1334,7 +1352,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(72, "shouldPressibilityUseW3CPointerEventsForHover"); + markFlagAsAccessed(73, "shouldPressibilityUseW3CPointerEventsForHover"); flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover(); shouldPressibilityUseW3CPointerEventsForHover_ = flagValue; @@ -1352,7 +1370,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldTriggerResponderTransferOnScrollAndr // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(73, "shouldTriggerResponderTransferOnScrollAndroid"); + markFlagAsAccessed(74, "shouldTriggerResponderTransferOnScrollAndroid"); flagValue = currentProvider_->shouldTriggerResponderTransferOnScrollAndroid(); shouldTriggerResponderTransferOnScrollAndroid_ = flagValue; @@ -1370,7 +1388,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(74, "skipActivityIdentityAssertionOnHostPause"); + markFlagAsAccessed(75, "skipActivityIdentityAssertionOnHostPause"); flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause(); skipActivityIdentityAssertionOnHostPause_ = flagValue; @@ -1388,7 +1406,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(75, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(76, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -1406,7 +1424,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(76, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(77, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -1424,7 +1442,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommitT // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(77, "updateRuntimeShadowNodeReferencesOnCommitThread"); + markFlagAsAccessed(78, "updateRuntimeShadowNodeReferencesOnCommitThread"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommitThread(); updateRuntimeShadowNodeReferencesOnCommitThread_ = flagValue; @@ -1442,7 +1460,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(78, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(79, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -1460,7 +1478,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(79, "useFabricInterop"); + markFlagAsAccessed(80, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -1478,7 +1496,7 @@ bool ReactNativeFeatureFlagsAccessor::useLISAlgorithmInDifferentiator() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(80, "useLISAlgorithmInDifferentiator"); + markFlagAsAccessed(81, "useLISAlgorithmInDifferentiator"); flagValue = currentProvider_->useLISAlgorithmInDifferentiator(); useLISAlgorithmInDifferentiator_ = flagValue; @@ -1496,7 +1514,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(81, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(82, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -1514,7 +1532,7 @@ bool ReactNativeFeatureFlagsAccessor::useNestedScrollViewAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(82, "useNestedScrollViewAndroid"); + markFlagAsAccessed(83, "useNestedScrollViewAndroid"); flagValue = currentProvider_->useNestedScrollViewAndroid(); useNestedScrollViewAndroid_ = flagValue; @@ -1532,7 +1550,7 @@ bool ReactNativeFeatureFlagsAccessor::useSharedAnimatedBackend() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(83, "useSharedAnimatedBackend"); + markFlagAsAccessed(84, "useSharedAnimatedBackend"); flagValue = currentProvider_->useSharedAnimatedBackend(); useSharedAnimatedBackend_ = flagValue; @@ -1550,7 +1568,7 @@ bool ReactNativeFeatureFlagsAccessor::useTraitHiddenOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(84, "useTraitHiddenOnAndroid"); + markFlagAsAccessed(85, "useTraitHiddenOnAndroid"); flagValue = currentProvider_->useTraitHiddenOnAndroid(); useTraitHiddenOnAndroid_ = flagValue; @@ -1568,7 +1586,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(85, "useTurboModuleInterop"); + markFlagAsAccessed(86, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1586,7 +1604,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(86, "useTurboModules"); + markFlagAsAccessed(87, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; @@ -1604,7 +1622,7 @@ bool ReactNativeFeatureFlagsAccessor::useUnorderedMapInDifferentiator() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(87, "useUnorderedMapInDifferentiator"); + markFlagAsAccessed(88, "useUnorderedMapInDifferentiator"); flagValue = currentProvider_->useUnorderedMapInDifferentiator(); useUnorderedMapInDifferentiator_ = flagValue; @@ -1622,7 +1640,7 @@ double ReactNativeFeatureFlagsAccessor::viewCullingOutsetRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(88, "viewCullingOutsetRatio"); + markFlagAsAccessed(89, "viewCullingOutsetRatio"); flagValue = currentProvider_->viewCullingOutsetRatio(); viewCullingOutsetRatio_ = flagValue; @@ -1640,7 +1658,7 @@ bool ReactNativeFeatureFlagsAccessor::viewTransitionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(89, "viewTransitionEnabled"); + markFlagAsAccessed(90, "viewTransitionEnabled"); flagValue = currentProvider_->viewTransitionEnabled(); viewTransitionEnabled_ = flagValue; @@ -1658,7 +1676,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(90, "virtualViewPrerenderRatio"); + markFlagAsAccessed(91, "virtualViewPrerenderRatio"); flagValue = currentProvider_->virtualViewPrerenderRatio(); virtualViewPrerenderRatio_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 9529d8a54065..7a36e0e31351 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<11a1936e637ed40b79a1aedd02932e7b>> + * @generated SignedSource<<2cc8cebd572ffe79f7ffc7e312d7eb13>> */ /** @@ -58,6 +58,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableFabricLogs(); bool enableFabricRenderer(); bool enableFontScaleChangesUpdatingLayout(); + bool enableIOSExperimentalAutoFocusImplementation(); bool enableIOSTextBaselineOffsetPerLine(); bool enableIOSViewClipToPaddingBox(); bool enableImagePrefetchingAndroid(); @@ -134,7 +135,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 91> accessedFeatureFlags_; + std::array, 92> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> cdpInteractionMetricsEnabled_; @@ -162,6 +163,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableFabricLogs_; std::atomic> enableFabricRenderer_; std::atomic> enableFontScaleChangesUpdatingLayout_; + std::atomic> enableIOSExperimentalAutoFocusImplementation_; std::atomic> enableIOSTextBaselineOffsetPerLine_; std::atomic> enableIOSViewClipToPaddingBox_; std::atomic> enableImagePrefetchingAndroid_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index e37c310a2b4b..d59c43015fb3 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<6aa42056b9acfeb38e3ea612b6421a15>> + * @generated SignedSource<<9409d4088a4d1b7b454af0df9816fc58>> */ /** @@ -131,6 +131,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return true; } + bool enableIOSExperimentalAutoFocusImplementation() override { + return false; + } + bool enableIOSTextBaselineOffsetPerLine() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 5269d2c64c88..3e20b2284f13 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2a4b0d699f7e7e701defd972cd79b116>> + * @generated SignedSource<<27db9899bab6acfdc4e674d4ca4a0f0a>> */ /** @@ -279,6 +279,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::enableFontScaleChangesUpdatingLayout(); } + bool enableIOSExperimentalAutoFocusImplementation() override { + auto value = values_["enableIOSExperimentalAutoFocusImplementation"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::enableIOSExperimentalAutoFocusImplementation(); + } + bool enableIOSTextBaselineOffsetPerLine() override { auto value = values_["enableIOSTextBaselineOffsetPerLine"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h index e84785c6fd2c..45d1c43d2888 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsOverridesOSSExperimental.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<577f69448b914525ff64e851c6019c1f>> */ /** @@ -35,6 +35,10 @@ class ReactNativeFeatureFlagsOverridesOSSExperimental : public ReactNativeFeatur return true; } + bool enableIOSExperimentalAutoFocusImplementation() override { + return true; + } + bool enableSwiftUIBasedFilters() override { return true; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 9eef5b56f5e9..e7c3f6117091 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -51,6 +51,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableFabricLogs() = 0; virtual bool enableFabricRenderer() = 0; virtual bool enableFontScaleChangesUpdatingLayout() = 0; + virtual bool enableIOSExperimentalAutoFocusImplementation() = 0; virtual bool enableIOSTextBaselineOffsetPerLine() = 0; virtual bool enableIOSViewClipToPaddingBox() = 0; virtual bool enableImagePrefetchingAndroid() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 5451b8c68cff..0925211f9346 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<4b821513e808ca071104f413e15c2fd9>> + * @generated SignedSource<> */ /** @@ -174,6 +174,11 @@ bool NativeReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout( return ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout(); } +bool NativeReactNativeFeatureFlags::enableIOSExperimentalAutoFocusImplementation( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableIOSExperimentalAutoFocusImplementation(); +} + bool NativeReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 844e1602154d..7c0f6dd50e2f 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<55da460bc2f8c915552eeae11f0b2e3e>> + * @generated SignedSource<> */ /** @@ -88,6 +88,8 @@ class NativeReactNativeFeatureFlags bool enableFontScaleChangesUpdatingLayout(jsi::Runtime& runtime); + bool enableIOSExperimentalAutoFocusImplementation(jsi::Runtime& runtime); + bool enableIOSTextBaselineOffsetPerLine(jsi::Runtime& runtime); bool enableIOSViewClipToPaddingBox(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 9c4788f67899..bc1bca520c90 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -325,6 +325,16 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + enableIOSExperimentalAutoFocusImplementation: { + defaultValue: false, + metadata: { + dateAdded: '2025-11-19', + description: 'Fixes #56595 by moving the autoFocus from didMoveToWindow to viewDidAppear', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'experimental', + }, enableIOSTextBaselineOffsetPerLine: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 0ab8c557bff4..4cfc3db58878 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1d648095164f22868bbdf3500668bb14>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -73,6 +73,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ enableFabricLogs: Getter, enableFabricRenderer: Getter, enableFontScaleChangesUpdatingLayout: Getter, + enableIOSExperimentalAutoFocusImplementation: Getter, enableIOSTextBaselineOffsetPerLine: Getter, enableIOSViewClipToPaddingBox: Getter, enableImagePrefetchingAndroid: Getter, @@ -308,6 +309,10 @@ export const enableFabricRenderer: Getter = createNativeFlagGetter('ena * Enables font scale changes updating layout for measurable nodes. */ export const enableFontScaleChangesUpdatingLayout: Getter = createNativeFlagGetter('enableFontScaleChangesUpdatingLayout', true); +/** + * Fixes #56595 by moving the autoFocus from didMoveToWindow to viewDidAppear + */ +export const enableIOSExperimentalAutoFocusImplementation: Getter = createNativeFlagGetter('enableIOSExperimentalAutoFocusImplementation', false); /** * Applies base offset for each line of text separately on iOS. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index a268a1c5144a..92a4cb8c56cf 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<5dea8e41a09f4ed658ce248121a2e981>> + * @generated SignedSource<<5974eabb1fcb69b9ebf76c144e7d63e7>> * @flow strict * @noformat */ @@ -51,6 +51,7 @@ export interface Spec extends TurboModule { +enableFabricLogs?: () => boolean; +enableFabricRenderer?: () => boolean; +enableFontScaleChangesUpdatingLayout?: () => boolean; + +enableIOSExperimentalAutoFocusImplementation?: () => boolean; +enableIOSTextBaselineOffsetPerLine?: () => boolean; +enableIOSViewClipToPaddingBox?: () => boolean; +enableImagePrefetchingAndroid?: () => boolean; From e84548ffba633e1cb63ff1736c5a9b15e9d5acdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 27 Apr 2026 11:52:11 +0200 Subject: [PATCH 10/10] hide behind feature flag --- .../TextInput/RCTTextInputComponentView.mm | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index bc0f88703db0..cf783ed512aa 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -127,12 +127,18 @@ - (void)didMoveToWindow { [super didMoveToWindow]; - [_viewController reactRemoveViewControllerAppearanceListener:self]; - _viewController = self.window ? [self reactViewController] : nil; - [_viewController reactAddViewControllerAppearanceListener:self]; + bool enableNewAutoFocusImpl = ReactNativeFeatureFlags::enableIOSExperimentalAutoFocusImplementation(); + if (enableNewAutoFocusImpl) { + [_viewController reactRemoveViewControllerAppearanceListener:self]; + _viewController = self.window ? [self reactViewController] : nil; + [_viewController reactAddViewControllerAppearanceListener:self]; + } if (self.window && !_didMoveToWindow) { _didMoveToWindow = YES; + if (!enableNewAutoFocusImpl) { + [self tryAutoFocus]; + } [self initializeReturnKeyType]; } @@ -398,9 +404,9 @@ - (void)prepareForRecycle [_backedTextInputView resignFirstResponder]; } -#pragma mark - RCTViewControllerAppearanceListener +#pragma mark - Auto focus / RCTViewControllerAppearanceListener -- (void)reactViewControllerDidAppear:(UIViewController *)viewController animated:(BOOL)animated +- (void)tryAutoFocus { const auto &props = static_cast(*_props); if (props.autoFocus && !_didAutoFocus) { @@ -410,6 +416,11 @@ - (void)reactViewControllerDidAppear:(UIViewController *)viewController animated } } +- (void)reactViewControllerDidAppear:(UIViewController *)viewController animated:(BOOL)animated +{ + [self tryAutoFocus]; +} + #pragma mark - RCTBackedTextInputDelegate - (BOOL)textInputShouldBeginEditing