diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js new file mode 100644 index 000000000..7c1cc7547 --- /dev/null +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Keyboard + * @flow + */ +'use strict'; + +const NativeEventEmitter = require('NativeEventEmitter'); + +module.exports = new NativeEventEmitter('KeyboardObserver'); diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 62fe76837..0169dd303 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -13,7 +13,7 @@ var Dimensions = require('Dimensions'); var Platform = require('Platform'); -var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); +var Keyboard = require('Keyboard'); var ReactNative = require('ReactNative'); var Subscribable = require('Subscribable'); var TextInputState = require('TextInputState'); @@ -476,10 +476,10 @@ var ScrollResponderMixin = { componentWillMount: function() { this.keyboardWillOpenTo = null; this.additionalScrollOffset = 0; - this.addListenerOn(RCTDeviceEventEmitter, 'keyboardWillShow', this.scrollResponderKeyboardWillShow); - this.addListenerOn(RCTDeviceEventEmitter, 'keyboardWillHide', this.scrollResponderKeyboardWillHide); - this.addListenerOn(RCTDeviceEventEmitter, 'keyboardDidShow', this.scrollResponderKeyboardDidShow); - this.addListenerOn(RCTDeviceEventEmitter, 'keyboardDidHide', this.scrollResponderKeyboardDidHide); + this.addListenerOn(Keyboard, 'keyboardWillShow', this.scrollResponderKeyboardWillShow); + this.addListenerOn(Keyboard, 'keyboardWillHide', this.scrollResponderKeyboardWillHide); + this.addListenerOn(Keyboard, 'keyboardDidShow', this.scrollResponderKeyboardDidShow); + this.addListenerOn(Keyboard, 'keyboardDidHide', this.scrollResponderKeyboardDidHide); }, /** diff --git a/Libraries/Components/StatusBar/StatusBarIOS.android.js b/Libraries/Components/StatusBar/StatusBarIOS.android.js index d4ffd63f0..2be8f34ea 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.android.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.android.js @@ -11,4 +11,6 @@ */ 'use strict'; -module.exports = null; +const NativeEventEmitter = require('NativeEventEmitter'); + +module.exports = new NativeEventEmitter('StatusBarManager'); diff --git a/Libraries/Components/StatusBar/StatusBarIOS.ios.js b/Libraries/Components/StatusBar/StatusBarIOS.ios.js index a4c0357b0..9c2176c44 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.ios.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.ios.js @@ -11,6 +11,7 @@ */ 'use strict'; +const NativeEventEmitter = require('NativeEventEmitter'); const StatusBar = require('StatusBar'); import type {StatusBarStyle, StatusBarAnimation} from 'StatusBar'; @@ -18,17 +19,17 @@ import type {StatusBarStyle, StatusBarAnimation} from 'StatusBar'; /** * Deprecated. Use `StatusBar` instead. */ -const StatusBarIOS = { +class StatusBarIOS extends NativeEventEmitter { setStyle(style: StatusBarStyle, animated?: boolean) { console.warn('`StatusBarIOS.setStyle` is deprecated. Use `StatusBar.setBarStyle` instead.'); StatusBar.setBarStyle(style, animated); - }, + } setHidden(hidden: boolean, animation?: StatusBarAnimation) { console.warn('`StatusBarIOS.setHidden` is deprecated. Use `StatusBar.setHidden` instead.'); StatusBar.setHidden(hidden, animation); - }, + } setNetworkActivityIndicatorVisible(visible: boolean) { console.warn( @@ -36,7 +37,7 @@ const StatusBarIOS = { 'Use `StatusBar.setNetworkActivityIndicatorVisible` instead.' ); StatusBar.setNetworkActivityIndicatorVisible(visible); - }, + } }; -module.exports = StatusBarIOS; +module.exports = new StatusBarIOS('StatusBarManager'); diff --git a/Libraries/Device/NativeEventEmitter.js b/Libraries/Device/NativeEventEmitter.js new file mode 100644 index 000000000..78ee98c8e --- /dev/null +++ b/Libraries/Device/NativeEventEmitter.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule NativeEventEmitter + * @flow + */ +'use strict'; + +const NativeModules = require('NativeModules'); +const Platform = require('Platform'); +const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); +const invariant = require('fbjs/lib/invariant'); + +import type EmitterSubscription from 'EmitterSubscription'; + +/** + * Abstract base class for implementing event-emitting modules. This implements + * a subset of the standard EventEmitter node module API. + */ +class NativeEventEmitter { + + _listenerCount: number; + _nativeModule: Object; + + constructor(nativeModuleName: string) { + if (Platform.OS === 'ios') { + this._listenerCount = 0; + this._nativeModule = NativeModules[nativeModuleName]; + invariant(this._nativeModule, + 'Native module `' + nativeModuleName + '` not found.'); + } + } + + addListener(eventType: string, listener: any, context: ?Object): EmitterSubscription { + if (Platform.OS === 'ios') { + this._listenerCount++; + this._nativeModule.addListener(eventType); + } + return RCTDeviceEventEmitter.nativeAddListener(eventType, listener, context); + } + + once(eventType: string, listener: any, context: ?Object): EmitterSubscription { + return this.addListener(eventType, () => { + this.removeCurrentListener(); + listener.apply(context, arguments); + }); + } + + removeAllListeners(eventType: string) { + invariant(eventType, 'eventType argument is required.'); + if (Platform.OS === 'ios') { + var count = RCTDeviceEventEmitter.listeners(eventType).length; + this._nativeModule.removeListeners(count); + } + RCTDeviceEventEmitter.removeAllListeners(eventType); + } + + removeCurrentListener() { + if (Platform.OS === 'ios') { + this._listenerCount--; + this._nativeModule.removeListeners(1); + } + RCTDeviceEventEmitter.removeCurrentListener(); + } +} + +module.exports = NativeEventEmitter; diff --git a/Libraries/Device/RCTDeviceEventEmitter.js b/Libraries/Device/RCTDeviceEventEmitter.js index 41e4d408f..4aeb55afc 100644 --- a/Libraries/Device/RCTDeviceEventEmitter.js +++ b/Libraries/Device/RCTDeviceEventEmitter.js @@ -11,10 +11,36 @@ */ 'use strict'; -var EventEmitter = require('EventEmitter'); -var BatchedBridge = require('BatchedBridge'); +const EventEmitter = require('EventEmitter'); +const BatchedBridge = require('BatchedBridge'); +const NativeModules = require('NativeModules'); -var RCTDeviceEventEmitter = new EventEmitter(); +import type EmitterSubscription from 'EmitterSubscription'; + +/** + * Deprecated - subclass NativeEventEmitter to create granular event modules instead of + * routing all event observation through RCTDeviceEventEmitter. + */ +class RCTDeviceEventEmitter extends EventEmitter { + + addListener(eventType: string, listener: any, context: ?Object): EmitterSubscription { + if (eventType.lastIndexOf('statusBar', 0) === 0) { + console.warn('statusBar events should be registered via the StatusBarIOS module'); + return require('StatusBarIOS').addListener(eventType, listener, context); + } + if (eventType.lastIndexOf('keyboard', 0) === 0) { + console.warn('keyboard events should be registered via the Keyboard module'); + return require('Keyboard').addListener(eventType, listener, context); + } + return super.addListener(eventType, listener, context); + } + + nativeAddListener(eventType: string, listener: any, context: ?Object): EmitterSubscription { + return super.addListener(eventType, listener, context); + } +} + +RCTDeviceEventEmitter = new RCTDeviceEventEmitter(); BatchedBridge.registerCallableModule( 'RCTDeviceEventEmitter', diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index f2d6e6ccb..fc07a8711 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -257,7 +257,8 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); { if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) { - if (![moduleClasses containsObject:cls]) { + if (![moduleClasses containsObject:cls] && + ![cls respondsToSelector:@selector(moduleName)]) { RCTLogWarn(@"Class %@ was not exported. Did you forget to use " "RCT_EXPORT_MODULE()?", cls); } diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m index bf8bea10e..f9afb5963 100644 --- a/React/Base/RCTModuleData.m +++ b/React/Base/RCTModuleData.m @@ -220,25 +220,29 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init); } unsigned int methodCount; - Method *methods = class_copyMethodList(object_getClass(_moduleClass), &methodCount); + Class cls = _moduleClass; + while (cls && cls != [NSObject class] && cls != [NSProxy class]) { + Method *methods = class_copyMethodList(object_getClass(cls), &methodCount); - for (unsigned int i = 0; i < methodCount; i++) { - Method method = methods[i]; - SEL selector = method_getName(method); - if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) { - IMP imp = method_getImplementation(method); - NSArray *entries = - ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector); - id moduleMethod = - [[RCTModuleMethod alloc] initWithMethodSignature:entries[1] - JSMethodName:entries[0] - moduleClass:_moduleClass]; + for (unsigned int i = 0; i < methodCount; i++) { + Method method = methods[i]; + SEL selector = method_getName(method); + if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) { + IMP imp = method_getImplementation(method); + NSArray *entries = + ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector); + id moduleMethod = + [[RCTModuleMethod alloc] initWithMethodSignature:entries[1] + JSMethodName:entries[0] + moduleClass:_moduleClass]; - [moduleMethods addObject:moduleMethod]; + [moduleMethods addObject:moduleMethod]; + } } - } - free(methods); + free(methods); + cls = class_getSuperclass(cls); + } _methods = [moduleMethods copy]; } diff --git a/React/Modules/RCTEventEmitter.h b/React/Modules/RCTEventEmitter.h new file mode 100644 index 000000000..260c1d750 --- /dev/null +++ b/React/Modules/RCTEventEmitter.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBridge.h" + +/** + * RCTEventEmitter is an abstract base class to be used for modules that emit + * events to be observed by JS. + */ +@interface RCTEventEmitter : NSObject + +@property (nonatomic, weak) RCTBridge *bridge; + +/** + * Override this method to return an array of supported event names. Attempting + * to observe or send an event that isn't included in this list will result in + * an error. + */ +- (NSArray *)supportedEvents; + +/** + * Send an event that does not relate to a specific view, e.g. a navigation + * or data update notification. + */ +- (void)sendEventWithName:(NSString *)name body:(id)body; + +/** + * These methods will be called when the first observer is added and when the + * last observer is removed (or when dealloc is called), respectively. These + * should be overridden in your subclass in order to start/stop sending events. + */ +- (void)startObserving; +- (void)stopObserving; + +@end diff --git a/React/Modules/RCTEventEmitter.m b/React/Modules/RCTEventEmitter.m new file mode 100644 index 000000000..d0a2cf720 --- /dev/null +++ b/React/Modules/RCTEventEmitter.m @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTEventEmitter.h" +#import "RCTAssert.h" +#import "RCTLog.h" + +@implementation RCTEventEmitter +{ + NSInteger _listenerCount; +} + ++ (NSString *)moduleName +{ + return @""; +} + +- (NSArray *)supportedEvents +{ + return nil; +} + +- (void)sendEventWithName:(NSString *)eventName body:(id)body +{ + RCTAssert(self.bridge != nil, @"bridge is not set."); + + if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) { + RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]); + } + [self.bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit" + args:body ? @[eventName, body] : @[eventName]]; +} + +- (void)startObserving +{ + // Does nothing +} + +- (void)stopObserving +{ + // Does nothing +} + +- (void)dealloc +{ + if (_listenerCount > 0) { + [self stopObserving]; + } +} + +RCT_EXPORT_METHOD(addListener:(NSString *)eventName) +{ + if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) { + RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]); + } + if (_listenerCount == 0) { + [self startObserving]; + } + _listenerCount++; +} + +RCT_EXPORT_METHOD(removeListeners:(NSInteger)count) +{ + RCTAssert(count <= _listenerCount, @"Attempted to remove more listeners than added"); + if (count == _listenerCount) { + [self stopObserving]; + } + _listenerCount -= count; +} + +@end diff --git a/React/Base/RCTKeyboardObserver.h b/React/Modules/RCTKeyboardObserver.h similarity index 72% rename from React/Base/RCTKeyboardObserver.h rename to React/Modules/RCTKeyboardObserver.h index 8fad021f3..89bba8999 100644 --- a/React/Base/RCTKeyboardObserver.h +++ b/React/Modules/RCTKeyboardObserver.h @@ -7,10 +7,8 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import "RCTEventEmitter.h" -#import "RCTBridgeModule.h" - -@interface RCTKeyboardObserver : NSObject +@interface RCTKeyboardObserver : RCTEventEmitter @end diff --git a/React/Base/RCTKeyboardObserver.m b/React/Modules/RCTKeyboardObserver.m similarity index 88% rename from React/Base/RCTKeyboardObserver.m rename to React/Modules/RCTKeyboardObserver.m index a849c3d5a..d87570b63 100644 --- a/React/Base/RCTKeyboardObserver.m +++ b/React/Modules/RCTKeyboardObserver.m @@ -15,21 +15,10 @@ static NSDictionary *RCTParseKeyboardNotification(NSNotification *notification); @implementation RCTKeyboardObserver -@synthesize bridge = _bridge; - RCT_EXPORT_MODULE() -- (instancetype)init +- (void)startObserving { - // We're only overriding this to ensure the module gets created at startup - // TODO (t11106126): Remove once we have more declarative control over module setup. - return [super init]; -} - -- (void)setBridge:(RCTBridge *)bridge -{ - _bridge = bridge; - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; #define ADD_KEYBOARD_HANDLER(NAME, SELECTOR) \ @@ -46,7 +35,17 @@ RCT_EXPORT_MODULE() } -- (void)dealloc +- (NSArray *)supportedEvents +{ + return @[@"keyboardWillShow", + @"keyboardDidShow", + @"keyboardWillHide", + @"keyboardDidHide", + @"keyboardWillChangeFrame", + @"keyboardDidChangeFrame"]; +} + +- (void)stopObserving { [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -54,8 +53,7 @@ RCT_EXPORT_MODULE() #define IMPLEMENT_KEYBOARD_HANDLER(EVENT) \ - (void)EVENT:(NSNotification *)notification \ { \ - [_bridge.eventDispatcher \ - sendDeviceEventWithName:@#EVENT \ + [self sendEventWithName:@#EVENT \ body:RCTParseKeyboardNotification(notification)]; \ } diff --git a/React/Modules/RCTStatusBarManager.h b/React/Modules/RCTStatusBarManager.h index aee9b8642..1e6328991 100644 --- a/React/Modules/RCTStatusBarManager.h +++ b/React/Modules/RCTStatusBarManager.h @@ -9,7 +9,7 @@ #import -#import "RCTBridgeModule.h" +#import "RCTEventEmitter.h" #import "RCTConvert.h" @interface RCTConvert (UIStatusBar) @@ -19,6 +19,6 @@ @end -@interface RCTStatusBarManager : NSObject +@interface RCTStatusBarManager : RCTEventEmitter @end diff --git a/React/Modules/RCTStatusBarManager.m b/React/Modules/RCTStatusBarManager.m index 5171c5aa9..9036469a4 100644 --- a/React/Modules/RCTStatusBarManager.m +++ b/React/Modules/RCTStatusBarManager.m @@ -44,28 +44,20 @@ static BOOL RCTViewControllerBasedStatusBarAppearance() RCT_EXPORT_MODULE() -@synthesize bridge = _bridge; - -- (instancetype)init +- (NSArray *)supportedEvents { - // We're only overriding this to ensure the module gets created at startup - // TODO (t11106126): Remove once we have more declarative control over module setup. - return [super init]; + return @[@"statusBarFrameDidChange", + @"statusBarFrameWillChange"]; } -- (void)setBridge:(RCTBridge *)bridge +- (void)startObserving { - _bridge = bridge; - - // TODO: if we add an explicit "startObserving" method, we can take this out - // of the application startup path - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(applicationDidChangeStatusBarFrame:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil]; [nc addObserver:self selector:@selector(applicationWillChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil]; } -- (void)dealloc +- (void)stopObserving { [[NSNotificationCenter defaultCenter] removeObserver:self]; } @@ -86,7 +78,7 @@ RCT_EXPORT_MODULE() @"height": @(frame.size.height), }, }; - [_bridge.eventDispatcher sendDeviceEventWithName:eventName body:event]; + [self sendEventWithName:eventName body:event]; } - (void)applicationDidChangeStatusBarFrame:(NSNotification *)notification diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index c166c6de6..53c851f42 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -46,6 +46,8 @@ 13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156041AB1A2840079392D /* RCTWebViewManager.m */; }; 13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */; }; 13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D033621C1837FE0021DC29 /* RCTClipboard.m */; }; + 13D9FEEB1CDCCECF00158BD7 /* RCTEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */; }; + 13D9FEEE1CDCD93000158BD7 /* RCTKeyboardObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D9FEED1CDCD93000158BD7 /* RCTKeyboardObserver.m */; }; 13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067491A70F434002CDEE1 /* RCTUIManager.m */; }; 13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */; }; 13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; }; @@ -82,7 +84,6 @@ 830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; }; 832348161A77A5AA00B55238 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FC71A68125100A75B9A /* Layout.c */; }; 83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83392EB21B6634E10013B15F /* RCTModalHostViewController.m */; }; - 8385CF351B8B77CD00C6273E /* RCTKeyboardObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF341B8B77CD00C6273E /* RCTKeyboardObserver.m */; }; 83A1FE8C1B62640A00BE0E65 /* RCTModalHostView.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A1FE8B1B62640A00BE0E65 /* RCTModalHostView.m */; }; 83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */; }; 83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA4B1A601E3B00E9B192 /* RCTAssert.m */; }; @@ -201,6 +202,10 @@ 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBorderDrawing.m; sourceTree = ""; }; 13D033611C1837FE0021DC29 /* RCTClipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTClipboard.h; sourceTree = ""; }; 13D033621C1837FE0021DC29 /* RCTClipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTClipboard.m; sourceTree = ""; }; + 13D9FEE91CDCCECF00158BD7 /* RCTEventEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTEventEmitter.h; sourceTree = ""; }; + 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventEmitter.m; sourceTree = ""; }; + 13D9FEEC1CDCD93000158BD7 /* RCTKeyboardObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyboardObserver.h; sourceTree = ""; }; + 13D9FEED1CDCD93000158BD7 /* RCTKeyboardObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyboardObserver.m; sourceTree = ""; }; 13E067481A70F434002CDEE1 /* RCTUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIManager.h; sourceTree = ""; }; 13E067491A70F434002CDEE1 /* RCTUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManager.m; sourceTree = ""; }; 13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowView.h; sourceTree = ""; }; @@ -273,8 +278,6 @@ 830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = ""; }; 83392EB11B6634E10013B15F /* RCTModalHostViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModalHostViewController.h; sourceTree = ""; }; 83392EB21B6634E10013B15F /* RCTModalHostViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModalHostViewController.m; sourceTree = ""; }; - 8385CF331B8B77CD00C6273E /* RCTKeyboardObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyboardObserver.h; sourceTree = ""; }; - 8385CF341B8B77CD00C6273E /* RCTKeyboardObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyboardObserver.m; sourceTree = ""; }; 83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModalHostView.h; sourceTree = ""; }; 83A1FE8B1B62640A00BE0E65 /* RCTModalHostView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModalHostView.m; sourceTree = ""; }; 83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModalHostViewManager.h; sourceTree = ""; }; @@ -335,6 +338,8 @@ 13B07FE01A69315300A75B9A /* Modules */ = { isa = PBXGroup; children = ( + 13D9FEE91CDCCECF00158BD7 /* RCTEventEmitter.h */, + 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */, E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */, E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */, 13B07FE71A69327A00A75B9A /* RCTAlertManager.h */, @@ -357,6 +362,8 @@ 000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */, 13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */, 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */, + 13D9FEEC1CDCD93000158BD7 /* RCTKeyboardObserver.h */, + 13D9FEED1CDCD93000158BD7 /* RCTKeyboardObserver.m */, 13B07FED1A69327A00A75B9A /* RCTTiming.h */, 13B07FEE1A69327A00A75B9A /* RCTTiming.m */, 13E067481A70F434002CDEE1 /* RCTUIManager.h */, @@ -545,8 +552,6 @@ 83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */, 14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */, 14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */, - 8385CF331B8B77CD00C6273E /* RCTKeyboardObserver.h */, - 8385CF341B8B77CD00C6273E /* RCTKeyboardObserver.m */, 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */, 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */, 83CBBA4D1A601E3B00E9B192 /* RCTLog.h */, @@ -685,7 +690,6 @@ 13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */, 83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */, 13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */, - 8385CF351B8B77CD00C6273E /* RCTKeyboardObserver.m in Sources */, 58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */, 832348161A77A5AA00B55238 /* Layout.c in Sources */, 13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */, @@ -698,6 +702,7 @@ 13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */, 58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */, 1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */, + 13D9FEEB1CDCCECF00158BD7 /* RCTEventEmitter.m in Sources */, 14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */, 1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */, 13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */, @@ -723,6 +728,7 @@ 13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */, 13E067571A70F44B002CDEE1 /* RCTView.m in Sources */, 13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */, + 13D9FEEE1CDCD93000158BD7 /* RCTKeyboardObserver.m in Sources */, 13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */, 137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */, 13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,