- The most fundamental component for building UI, `View` is a
+ * The most fundamental component for building UI, `View` is a
* container that supports layout with flexbox, style, some touch handling, and
* accessibility controls, and is designed to be nested inside other views and
* to have 0 to many children of any type. `View` maps directly to the native
@@ -21,11 +26,13 @@ var ViewStylePropTypes = require('ViewStylePropTypes');
* `UIView`, ``, `android.view`, etc. This example creates a `View` that
* wraps two colored boxes and custom component in a row with padding.
*
- *
- *
- *
- *
- *
+ * ```
+ *
+ *
+ *
+ *
+ *
+ * ```
*
* By default, `View`s have a primary flex direction of 'column', so children
* will stack up vertically by default. `View`s also expand to fill the parent
@@ -39,20 +46,8 @@ var ViewStylePropTypes = require('ViewStylePropTypes');
* `View`s are designed to be used with `StyleSheet`s for clarity and
* performance, although inline styles are also supported. It is common for
* `StyleSheet`s to be combined dynamically. See `StyleSheet.js` for more info.
- *
- * Check out `ViewExample.js`, `LayoutExample.js`, and other apps for more code
- * examples.
*/
-
-var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
-
-var stylePropType = StyleSheetPropType(ViewStylePropTypes);
-
var View = React.createClass({
- statics: {
- stylePropType,
- },
-
mixins: [NativeMethodsMixin],
/**
@@ -141,12 +136,12 @@ var RKView = createReactIOSNativeComponentClass({
validAttributes: ReactIOSViewAttributes.RKView,
uiViewClassName: 'RCTView',
});
+RKView.propTypes = View.propTypes;
var ViewToExport = RKView;
if (__DEV__) {
ViewToExport = View;
}
-ViewToExport.stylePropType = stylePropType;
module.exports = ViewToExport;
diff --git a/Libraries/GeoLocation/GeoLocation.js b/Libraries/GeoLocation/Geolocation.ios.js
similarity index 65%
rename from Libraries/GeoLocation/GeoLocation.js
rename to Libraries/GeoLocation/Geolocation.ios.js
index 9a7f792c4..1b5719212 100644
--- a/Libraries/GeoLocation/GeoLocation.js
+++ b/Libraries/GeoLocation/Geolocation.ios.js
@@ -1,12 +1,12 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
- * @providesModule GeoLocation
+ * @providesModule Geolocation
*/
'use strict';
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
-var RCTLocationObserver = require('NativeModules').RKLocationObserver;
+var RCTLocationObserver = require('NativeModulesDeprecated').RKLocationObserver;
var invariant = require('invariant');
var logError = require('logError');
@@ -16,13 +16,6 @@ var subscriptions = [];
var updatesEnabled = false;
-var ensureObserving = function() {
- if (!updatesEnabled) {
- RCTLocationObserver.startObserving();
- updatesEnabled = true;
- }
-};
-
/**
* /!\ ATTENTION /!\
* You need to add NSLocationWhenInUseUsageDescription key
@@ -30,43 +23,51 @@ var ensureObserving = function() {
* to *fail silently*!
* \!/ \!/
*
- * GeoLocation follows the MDN specification:
+ * Geolocation follows the MDN specification:
* https://developer.mozilla.org/en-US/docs/Web/API/Geolocation
*/
-class GeoLocation {
- static getCurrentPosition(geo_success, geo_error, geo_options) {
+var Geolocation = {
+
+ getCurrentPosition: function(geo_success, geo_error, geo_options) {
invariant(
typeof geo_success === 'function',
'Must provide a valid geo_success callback.'
);
- if (geo_options) {
- warning('geo_options are not yet supported.');
- }
- ensureObserving();
RCTLocationObserver.getCurrentPosition(
geo_success,
- geo_error || logError
+ geo_error || logError,
+ geo_options || {}
);
- }
- static watchPosition(callback) {
- ensureObserving();
+ },
+
+ watchPosition: function(success, error, options) {
+ if (!updatesEnabled) {
+ RCTLocationObserver.startObserving(options || {});
+ updatesEnabled = true;
+ }
var watchID = subscriptions.length;
- subscriptions.push(
+ subscriptions.push([
RCTDeviceEventEmitter.addListener(
- 'geoLocationDidChange',
- callback
- )
- );
+ 'geolocationDidChange',
+ success
+ ),
+ error ? RCTDeviceEventEmitter.addListener(
+ 'geolocationError',
+ error
+ ) : null,
+ ]);
return watchID;
- }
- static clearWatch(watchID) {
+ },
+
+ clearWatch: function(watchID) {
var sub = subscriptions[watchID];
if (!sub) {
// Silently exit when the watchID is invalid or already cleared
// This is consistent with timers
return;
}
- sub.remove();
+ sub[0].remove();
+ sub[1] && sub[1].remove();
subscriptions[watchID] = undefined;
var noWatchers = true;
for (var ii = 0; ii < subscriptions.length; ii++) {
@@ -75,10 +76,11 @@ class GeoLocation {
}
}
if (noWatchers) {
- GeoLocation.stopObserving();
+ Geolocation.stopObserving();
}
- }
- static stopObserving() {
+ },
+
+ stopObserving: function() {
if (updatesEnabled) {
RCTLocationObserver.stopObserving();
updatesEnabled = false;
@@ -89,10 +91,8 @@ class GeoLocation {
}
}
subscriptions = [];
- } else {
- warning('Tried to stop observing when not observing.');
}
}
}
-module.exports = GeoLocation;
+module.exports = Geolocation;
diff --git a/Libraries/GeoLocation/RCTGeolocation.xcodeproj/project.pbxproj b/Libraries/GeoLocation/RCTGeolocation.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..94f9c3f91
--- /dev/null
+++ b/Libraries/GeoLocation/RCTGeolocation.xcodeproj/project.pbxproj
@@ -0,0 +1,256 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 134814061AA4E45400B7C361 /* RCTLocationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 134814051AA4E45400B7C361 /* RCTLocationObserver.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 58B511D91A9E6C8500147676 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "include/$(PRODUCT_NAME)";
+ dstSubfolderSpec = 16;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 134814041AA4E45400B7C361 /* RCTLocationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLocationObserver.h; sourceTree = ""; };
+ 134814051AA4E45400B7C361 /* RCTLocationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLocationObserver.m; sourceTree = ""; };
+ 134814201AA4EA6300B7C361 /* libRCTGeolocation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTGeolocation.a; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 58B511D81A9E6C8500147676 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 134814211AA4EA7D00B7C361 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 134814201AA4EA6300B7C361 /* libRCTGeolocation.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 58B511D21A9E6C8500147676 = {
+ isa = PBXGroup;
+ children = (
+ 134814041AA4E45400B7C361 /* RCTLocationObserver.h */,
+ 134814051AA4E45400B7C361 /* RCTLocationObserver.m */,
+ 134814211AA4EA7D00B7C361 /* Products */,
+ );
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 58B511DA1A9E6C8500147676 /* RCTGeolocation */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTGeolocation" */;
+ buildPhases = (
+ 58B511D71A9E6C8500147676 /* Sources */,
+ 58B511D81A9E6C8500147676 /* Frameworks */,
+ 58B511D91A9E6C8500147676 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = RCTGeolocation;
+ productName = RCTDataManager;
+ productReference = 134814201AA4EA6300B7C361 /* libRCTGeolocation.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 58B511D31A9E6C8500147676 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = Facebook;
+ TargetAttributes = {
+ 58B511DA1A9E6C8500147676 = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ };
+ };
+ buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTGeolocation" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 58B511D21A9E6C8500147676;
+ productRefGroup = 58B511D21A9E6C8500147676;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 58B511DA1A9E6C8500147676 /* RCTGeolocation */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 58B511D71A9E6C8500147676 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 134814061AA4E45400B7C361 /* RCTLocationObserver.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 58B511ED1A9E6C8500147676 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 58B511EE1A9E6C8500147676 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 58B511F01A9E6C8500147676 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../../ReactKit/**",
+ );
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "/Users/nicklockwood/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/ReactKit/build/Debug-iphoneos",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = RCTGeolocation;
+ SKIP_INSTALL = YES;
+ };
+ name = Debug;
+ };
+ 58B511F11A9E6C8500147676 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../../ReactKit/**",
+ );
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "/Users/nicklockwood/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/ReactKit/build/Debug-iphoneos",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = RCTGeolocation;
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTGeolocation" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 58B511ED1A9E6C8500147676 /* Debug */,
+ 58B511EE1A9E6C8500147676 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTGeolocation" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 58B511F01A9E6C8500147676 /* Debug */,
+ 58B511F11A9E6C8500147676 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 58B511D31A9E6C8500147676 /* Project object */;
+}
diff --git a/ReactKit/Modules/RCTLocationObserver.h b/Libraries/GeoLocation/RCTLocationObserver.h
similarity index 100%
rename from ReactKit/Modules/RCTLocationObserver.h
rename to Libraries/GeoLocation/RCTLocationObserver.h
diff --git a/Libraries/GeoLocation/RCTLocationObserver.m b/Libraries/GeoLocation/RCTLocationObserver.m
new file mode 100644
index 000000000..019653640
--- /dev/null
+++ b/Libraries/GeoLocation/RCTLocationObserver.m
@@ -0,0 +1,319 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTLocationObserver.h"
+
+#import
+#import
+#import
+
+#import "RCTAssert.h"
+#import "RCTBridge.h"
+#import "RCTConvert.h"
+#import "RCTEventDispatcher.h"
+#import "RCTLog.h"
+
+typedef NS_ENUM(NSInteger, RCTPositionErrorCode) {
+ RCTPositionErrorDenied = 1,
+ RCTPositionErrorUnavailable,
+ RCTPositionErrorTimeout,
+};
+
+#define RCT_DEFAULT_LOCATION_ACCURACY kCLLocationAccuracyHundredMeters
+
+typedef struct {
+ NSTimeInterval timeout;
+ NSTimeInterval maximumAge;
+ CLLocationAccuracy accuracy;
+} RCTLocationOptions;
+
+static RCTLocationOptions RCTLocationOptionsWithJSON(id json)
+{
+ NSDictionary *options = [RCTConvert NSDictionary:json];
+ return (RCTLocationOptions){
+ .timeout = [RCTConvert NSTimeInterval:options[@"timeout"]] ?: INFINITY,
+ .maximumAge = [RCTConvert NSTimeInterval:options[@"maximumAge"]] ?: INFINITY,
+ .accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY
+ };
+}
+
+static NSDictionary *RCTPositionError(RCTPositionErrorCode code, NSString *msg /* nil for default */)
+{
+ if (!msg) {
+ switch (code) {
+ case RCTPositionErrorDenied:
+ msg = @"User denied access to location services.";
+ break;
+ case RCTPositionErrorUnavailable:
+ msg = @"Unable to retrieve location.";
+ break;
+ case RCTPositionErrorTimeout:
+ msg = @"The location request timed out.";
+ break;
+ }
+ }
+
+ return @{
+ @"code": @(code),
+ @"message": msg,
+ @"PERMISSION_DENIED": @(RCTPositionErrorDenied),
+ @"POSITION_UNAVAILABLE": @(RCTPositionErrorUnavailable),
+ @"TIMEOUT": @(RCTPositionErrorTimeout)
+ };
+}
+
+@interface RCTLocationRequest : NSObject
+
+@property (nonatomic, copy) RCTResponseSenderBlock successBlock;
+@property (nonatomic, copy) RCTResponseSenderBlock errorBlock;
+@property (nonatomic, assign) RCTLocationOptions options;
+@property (nonatomic, strong) NSTimer *timeoutTimer;
+
+@end
+
+@implementation RCTLocationRequest
+
+- (void)dealloc
+{
+ [_timeoutTimer invalidate];
+}
+
+@end
+
+@interface RCTLocationObserver ()
+
+@end
+
+@implementation RCTLocationObserver
+{
+ CLLocationManager *_locationManager;
+ NSDictionary *_lastLocationEvent;
+ NSMutableArray *_pendingRequests;
+ BOOL _observingLocation;
+ RCTLocationOptions _observerOptions;
+}
+
+@synthesize bridge = _bridge;
+
+#pragma mark - Lifecycle
+
+- (instancetype)init
+{
+ if ((self = [super init])) {
+
+ _locationManager = [[CLLocationManager alloc] init];
+ _locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
+ _locationManager.delegate = self;
+
+ _pendingRequests = [[NSMutableArray alloc] init];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [_locationManager stopUpdatingLocation];
+}
+
+#pragma mark - Private API
+
+- (void)beginLocationUpdates
+{
+ // Request location access permission
+ if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
+ [_locationManager requestWhenInUseAuthorization];
+ }
+
+ // Start observing location
+ [_locationManager startUpdatingLocation];
+}
+
+#pragma mark - Timeout handler
+
+- (void)timeout:(NSTimer *)timer
+{
+ RCTLocationRequest *request = timer.userInfo;
+ NSString *message = [NSString stringWithFormat: @"Unable to fetch location within %zds.", (NSInteger)(timer.timeInterval * 1000.0)];
+ request.errorBlock(@[RCTPositionError(RCTPositionErrorTimeout, message)]);
+ [_pendingRequests removeObject:request];
+
+ // Stop updating if no pending requests
+ if (_pendingRequests.count == 0 && !_observingLocation) {
+ [_locationManager stopUpdatingLocation];
+ }
+}
+
+#pragma mark - Public API
+
+- (void)startObserving:(NSDictionary *)optionsJSON
+{
+ RCT_EXPORT();
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ // Select best options
+ _observerOptions = RCTLocationOptionsWithJSON(optionsJSON);
+ for (RCTLocationRequest *request in _pendingRequests) {
+ _observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
+ }
+
+ _locationManager.desiredAccuracy = _observerOptions.accuracy;
+ [self beginLocationUpdates];
+ _observingLocation = YES;
+
+ });
+}
+
+- (void)stopObserving
+{
+ RCT_EXPORT();
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ // Stop observing
+ _observingLocation = NO;
+
+ // Stop updating if no pending requests
+ if (_pendingRequests.count == 0) {
+ [_locationManager stopUpdatingLocation];
+ }
+
+ });
+}
+
+- (void)getCurrentPosition:(RCTResponseSenderBlock)successBlock
+ withErrorCallback:(RCTResponseSenderBlock)errorBlock
+ options:(NSDictionary *)optionsJSON
+{
+ RCT_EXPORT();
+
+ if (!successBlock) {
+ RCTLogError(@"%@.getCurrentPosition called with nil success parameter.", [self class]);
+ return;
+ }
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ if (![CLLocationManager locationServicesEnabled]) {
+ if (errorBlock) {
+ errorBlock(@[
+ RCTPositionError(RCTPositionErrorUnavailable, @"Location services disabled.")
+ ]);
+ return;
+ }
+ }
+
+ if (![CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
+ if (errorBlock) {
+ errorBlock(@[
+ RCTPositionError(RCTPositionErrorDenied, nil)
+ ]);
+ return;
+ }
+ }
+
+ // Get options
+ RCTLocationOptions options = RCTLocationOptionsWithJSON(optionsJSON);
+
+ // Check if previous recorded location exists and is good enough
+ if (_lastLocationEvent &&
+ CFAbsoluteTimeGetCurrent() - [RCTConvert NSTimeInterval:_lastLocationEvent[@"timestamp"]] < options.maximumAge &&
+ [_lastLocationEvent[@"coords"][@"accuracy"] doubleValue] >= options.accuracy) {
+
+ // Call success block with most recent known location
+ successBlock(@[_lastLocationEvent]);
+ return;
+ }
+
+ // Create request
+ RCTLocationRequest *request = [[RCTLocationRequest alloc] init];
+ request.successBlock = successBlock;
+ request.errorBlock = errorBlock ?: ^(NSArray *args){};
+ request.options = options;
+ request.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:options.timeout
+ target:self
+ selector:@selector(timeout:)
+ userInfo:request
+ repeats:NO];
+ [_pendingRequests addObject:request];
+
+ // Configure location manager and begin updating location
+ _locationManager.desiredAccuracy = MIN(_locationManager.desiredAccuracy, options.accuracy);
+ [self beginLocationUpdates];
+
+ });
+}
+
+#pragma mark - CLLocationManagerDelegate
+
+- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
+{
+ // Create event
+ CLLocation *location = [locations lastObject];
+ _lastLocationEvent = @{
+ @"coords": @{
+ @"latitude": @(location.coordinate.latitude),
+ @"longitude": @(location.coordinate.longitude),
+ @"altitude": @(location.altitude),
+ @"accuracy": @(location.horizontalAccuracy),
+ @"altitudeAccuracy": @(location.verticalAccuracy),
+ @"heading": @(location.course),
+ @"speed": @(location.speed),
+ },
+ @"timestamp": @(CFAbsoluteTimeGetCurrent() * 1000.0) // in ms
+ };
+
+ // Send event
+ if (_observingLocation) {
+ [_bridge.eventDispatcher sendDeviceEventWithName:@"geolocationDidChange"
+ body:_lastLocationEvent];
+ }
+
+ // Fire all queued callbacks
+ for (RCTLocationRequest *request in _pendingRequests) {
+ request.successBlock(@[_lastLocationEvent]);
+ }
+ [_pendingRequests removeAllObjects];
+
+ // Stop updating if not not observing
+ if (!_observingLocation) {
+ [_locationManager stopUpdatingLocation];
+ }
+
+ // Reset location accuracy
+ _locationManager.desiredAccuracy = RCT_DEFAULT_LOCATION_ACCURACY;
+}
+
+- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
+{
+ // Check error type
+ NSDictionary *jsError = nil;
+ switch (error.code) {
+ case kCLErrorDenied:
+ jsError = RCTPositionError(RCTPositionErrorDenied, nil);
+ break;
+ case kCLErrorNetwork:
+ jsError = RCTPositionError(RCTPositionErrorUnavailable, @"Unable to retrieve location due to a network failure");
+ break;
+ case kCLErrorLocationUnknown:
+ default:
+ jsError = RCTPositionError(RCTPositionErrorUnavailable, nil);
+ break;
+ }
+
+ // Send event
+ if (_observingLocation) {
+ [_bridge.eventDispatcher sendDeviceEventWithName:@"geolocationError"
+ body:jsError];
+ }
+
+ // Fire all queued error callbacks
+ for (RCTLocationRequest *request in _pendingRequests) {
+ request.errorBlock(@[jsError]);
+ }
+ [_pendingRequests removeAllObjects];
+
+ // Reset location accuracy
+ _locationManager.desiredAccuracy = RCT_DEFAULT_LOCATION_ACCURACY;
+}
+
+@end
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 5926cb144..f8ab583a9 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -10,7 +10,6 @@ var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModulesDeprecated = require('NativeModulesDeprecated');
var PropTypes = require('ReactPropTypes');
var ImageResizeMode = require('ImageResizeMode');
-var ImageSourcePropType = require('ImageSourcePropType');
var ImageStylePropTypes = require('ImageStylePropTypes');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
@@ -25,31 +24,40 @@ var merge = require('merge');
var warning = require('warning');
/**
- * - A react component for displaying different types of images,
+ * A react component for displaying different types of images,
* including network images, static resources, temporary local images, and
- * images from local disk, such as the camera roll. Example usage:
+ * images from local disk, such as the camera roll.
*
- * renderImages: function() {
- * return (
- *
- *
- *
- *
- * );
- * },
+ * Example usage:
*
- * More example code in ImageExample.js
+ * ```
+ * renderImages: function() {
+ * return (
+ *
+ *
+ *
+ *
+ * );
+ * },
+ * ```
*/
var Image = React.createClass({
propTypes: {
- source: ImageSourcePropType,
+ source: PropTypes.shape({
+ /**
+ * A string representing the resource identifier for the image, which
+ * could be an http address, a local file path, or the name of a static image
+ * resource (which should be wrapped in the `ix` function).
+ */
+ uri: PropTypes.string,
+ }).isRequired,
/**
* accessible - Whether this element should be revealed as an accessible
* element.
@@ -78,7 +86,6 @@ var Image = React.createClass({
statics: {
resizeMode: ImageResizeMode,
- sourcePropType: ImageSourcePropType,
},
mixins: [NativeMethodsMixin],
diff --git a/Libraries/Image/ImageSourcePropType.js b/Libraries/Image/ImageSourcePropType.js
deleted file mode 100644
index 84eaf6629..000000000
--- a/Libraries/Image/ImageSourcePropType.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @providesModule ImageSourcePropType
- * @flow
- */
-'use strict';
-
-var { PropTypes } = require('React');
-
-var ImageSourcePropType = PropTypes.shape({
- /**
- * uri - A string representing the resource identifier for the image, which
- * could be an http address, a local file path, or the name of a static image
- * resource (which should be wrapped in the `ix` function).
- */
- uri: PropTypes.string.isRequired,
- /**
- * width/height - Used to store the size of the image itself, but unused by
- * the component - use normal style layout properties to define the
- * size of the frame.
- */
- width: PropTypes.number,
- height: PropTypes.number,
-});
-
-module.exports = ImageSourcePropType;
diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 3c507129b..422447d46 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -140,7 +140,7 @@ function setupXHR() {
function setupGeolocation() {
GLOBAL.navigator = GLOBAL.navigator || {};
- GLOBAL.navigator.geolocation = require('GeoLocation');
+ GLOBAL.navigator.geolocation = require('Geolocation');
}
setupDocumentShim();
diff --git a/Libraries/ReactIOS/nativePropType.js b/Libraries/ReactIOS/nativePropType.js
deleted file mode 100644
index d61c7f191..000000000
--- a/Libraries/ReactIOS/nativePropType.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @providesModule nativePropType
- */
-'use strict'
-
-/**
- * A simple wrapper for prop types to mark them as native, which will allow them
- * to be passed over the bridge to be applied to the native component if
- * processed by `validAttributesFromPropTypes`.
- */
-function nativePropType(propType) {
- propType.isNative = true;
- return propType;
-}
-
-module.exports = nativePropType;
diff --git a/Libraries/StyleSheet/ArrayOfPropType.js b/Libraries/StyleSheet/ArrayOfPropType.js
deleted file mode 100644
index 89d224d8b..000000000
--- a/Libraries/StyleSheet/ArrayOfPropType.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @providesModule ArrayOfPropType
- */
-'use strict'
-
-var ReactPropTypes = require('ReactPropTypes');
-
-var deepDiffer = require('deepDiffer');
-
-var ArrayOfPropType = (type, differ) => {
- var checker = ReactPropTypes.arrayOf(type);
- checker.differ = differ ? differ : deepDiffer;
- return checker;
-};
-
-module.exports = ArrayOfPropType;
diff --git a/Libraries/StyleSheet/EdgeInsetsPropType.js b/Libraries/StyleSheet/EdgeInsetsPropType.js
index dcf38de79..a57abcaf8 100644
--- a/Libraries/StyleSheet/EdgeInsetsPropType.js
+++ b/Libraries/StyleSheet/EdgeInsetsPropType.js
@@ -17,6 +17,4 @@ var EdgeInsetsPropType = createStrictShapeTypeChecker({
right: PropTypes.number,
});
-EdgeInsetsPropType.differ = insetsDiffer;
-
module.exports = EdgeInsetsPropType;
diff --git a/Libraries/StyleSheet/PointPropType.js b/Libraries/StyleSheet/PointPropType.js
index b281b96e0..c409bd660 100644
--- a/Libraries/StyleSheet/PointPropType.js
+++ b/Libraries/StyleSheet/PointPropType.js
@@ -15,6 +15,4 @@ var PointPropType = createStrictShapeTypeChecker({
y: PropTypes.number,
});
-PointPropType.differ = pointsDiffer;
-
module.exports = PointPropType;
diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js
index 71e022d9b..6171ecbde 100644
--- a/Libraries/Text/Text.js
+++ b/Libraries/Text/Text.js
@@ -28,46 +28,42 @@ var viewConfig = {
};
/**
- * - A react component for displaying text which supports nesting,
+ * A react component for displaying text which supports nesting,
* styling, and touch handling. In the following example, the nested title and
* body text will inherit the `fontFamily` from `styles.baseText`, but the title
* provides its own additional styles. The title and body will stack on top of
* each other on account of the literal newlines:
*
- * renderText: function() {
- * return (
- *
- *
- * {this.state.titleText + '\n\n'}
- *
- *
- * {this.state.bodyText}
- *
+ * ```
+ * renderText: function() {
+ * return (
+ *
+ *
+ * {this.state.titleText + '\n\n'}
*
- * );
+ *
+ * {this.state.bodyText}
+ *
+ *
+ * );
+ * },
+ * ...
+ * var styles = StyleSheet.create({
+ * baseText: {
+ * fontFamily: 'Cochin',
* },
- * ...
- * var styles = StyleSheet.create({
- * baseText: {
- * fontFamily: 'Cochin',
- * },
- * titleText: {
- * fontSize: 20,
- * fontWeight: 'bold',
- * },
- * };
- *
- * More example code in `TextExample.ios.js`
+ * titleText: {
+ * fontSize: 20,
+ * fontWeight: 'bold',
+ * },
+ * };
+ * ```
*/
var Text = React.createClass({
mixins: [Touchable.Mixin, NativeMethodsMixin],
- statics: {
- stylePropType: stylePropType,
- },
-
propTypes: {
/**
* Used to truncate the text with an elipsis after computing the text
diff --git a/Libraries/Utilities/validAttributesFromPropTypes.js b/Libraries/Utilities/validAttributesFromPropTypes.js
deleted file mode 100644
index d08d17cfa..000000000
--- a/Libraries/Utilities/validAttributesFromPropTypes.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @providesModule validAttributesFromPropTypes
- */
-'use strict'
-
-function validAttributesFromPropTypes(propTypes) {
- var validAttributes = {};
- for (var key in propTypes) {
- var propType = propTypes[key];
- if (propType && propType.isNative) {
- var diff = propType.differ;
- validAttributes[key] = diff ? {diff} : true;
- }
- }
- return validAttributes;
-}
-
-module.exports = validAttributesFromPropTypes;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 78c93960b..7f7edaf72 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -8,6 +8,7 @@
var ReactNative = {
...require('React'),
AppRegistry: require('AppRegistry'),
+ DatePickerIOS: require('DatePickerIOS'),
ExpandingText: require('ExpandingText'),
Image: require('Image'),
LayoutAnimation: require('LayoutAnimation'),
@@ -17,8 +18,10 @@ var ReactNative = {
PixelRatio: require('PixelRatio'),
ScrollView: require('ScrollView'),
ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
+ Slider: require('Slider'),
StatusBarIOS: require('StatusBarIOS'),
StyleSheet: require('StyleSheet'),
+ SwitchIOS: require('SwitchIOS'),
Text: require('Text'),
TextInput: require('TextInput'),
TimerMixin: require('TimerMixin'),
diff --git a/ReactKit/Base/RCTConvert.h b/ReactKit/Base/RCTConvert.h
index a5aa59fe6..16cd6967b 100644
--- a/ReactKit/Base/RCTConvert.h
+++ b/ReactKit/Base/RCTConvert.h
@@ -19,6 +19,8 @@
+ (float)float:(id)json;
+ (int)int:(id)json;
++ (NSArray *)NSArray:(id)json;
++ (NSDictionary *)NSDictionary:(id)json;
+ (NSString *)NSString:(id)json;
+ (NSNumber *)NSNumber:(id)json;
+ (NSInteger)NSInteger:(id)json;
diff --git a/ReactKit/Base/RCTConvert.m b/ReactKit/Base/RCTConvert.m
index bec60ff6c..760f8284d 100644
--- a/ReactKit/Base/RCTConvert.m
+++ b/ReactKit/Base/RCTConvert.m
@@ -99,6 +99,8 @@ RCT_CONVERTER(double, double, doubleValue)
RCT_CONVERTER(float, float, floatValue)
RCT_CONVERTER(int, int, intValue)
+RCT_CONVERTER_CUSTOM(NSArray *, NSArray, [NSArray arrayWithArray:json])
+RCT_CONVERTER_CUSTOM(NSDictionary *, NSDictionary, [NSDictionary dictionaryWithDictionary:json])
RCT_CONVERTER(NSString *, NSString, description)
RCT_CONVERTER_CUSTOM(NSNumber *, NSNumber, @([json doubleValue]))
RCT_CONVERTER(NSInteger, NSInteger, integerValue)
diff --git a/ReactKit/Modules/RCTLocationObserver.m b/ReactKit/Modules/RCTLocationObserver.m
deleted file mode 100644
index fd9c7ac07..000000000
--- a/ReactKit/Modules/RCTLocationObserver.m
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#import "RCTLocationObserver.h"
-
-#import
-#import
-
-#import "RCTAssert.h"
-#import "RCTBridge.h"
-#import "RCTEventDispatcher.h"
-#import "RCTLog.h"
-
-// TODO (#5906496): Shouldn't these be configurable?
-const CLLocationAccuracy RCTLocationAccuracy = 500.0; // meters
-
-@interface RCTPendingLocationRequest : NSObject
-
-@property (nonatomic, copy) RCTResponseSenderBlock successBlock;
-@property (nonatomic, copy) RCTResponseSenderBlock errorBlock;
-
-@end
-
-@implementation RCTPendingLocationRequest @end
-
-@interface RCTLocationObserver ()
-
-@end
-
-@implementation RCTLocationObserver
-{
- CLLocationManager *_locationManager;
- NSDictionary *_lastLocationEvent;
- NSMutableDictionary *_pendingRequests;
-}
-
-@synthesize bridge = _bridge;
-
-#pragma mark - Lifecycle
-
-- (instancetype)init
-{
- if ((self = [super init])) {
- _pendingRequests = [[NSMutableDictionary alloc] init];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [_locationManager stopUpdatingLocation];
-}
-
-#pragma mark - Public API
-
-- (void)startObserving
-{
- RCT_EXPORT();
-
- dispatch_async(dispatch_get_main_queue(), ^{
-
- // Create the location manager if this object does not
- // already have one, and it must be created and accessed
- // on the main thread
- if (nil == _locationManager) {
- _locationManager = [[CLLocationManager alloc] init];
- }
-
- _locationManager.delegate = self;
- _locationManager.desiredAccuracy = RCTLocationAccuracy;
-
- // Set a movement threshold for new events.
- _locationManager.distanceFilter = RCTLocationAccuracy; // meters
-
- if([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
- [_locationManager requestWhenInUseAuthorization];
- }
-
- [_locationManager startUpdatingLocation];
-
- });
-}
-
-- (void)stopObserving
-{
- RCT_EXPORT();
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [_locationManager stopUpdatingLocation];
- _lastLocationEvent = nil;
- });
-}
-
-#pragma mark - CLLocationManagerDelegate
-
-- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
-{
- CLLocation *loc = [locations lastObject];
- NSDictionary *event = @{
- @"coords": @{
- @"latitude": @(loc.coordinate.latitude),
- @"longitude": @(loc.coordinate.longitude),
- @"altitude": @(loc.altitude),
- @"accuracy": @(RCTLocationAccuracy),
- @"altitudeAccuracy": @(RCTLocationAccuracy),
- @"heading": @(loc.course),
- @"speed": @(loc.speed),
- },
- @"timestamp": @(CACurrentMediaTime())
- };
- [_bridge.eventDispatcher sendDeviceEventWithName:@"geoLocationDidChange" body:event];
- NSArray *pendingRequestsCopy;
-
- // TODO (#5906496): is this locking neccessary? If so, use something better than @synchronize
- @synchronized(self) {
-
- pendingRequestsCopy = [_pendingRequests allValues];
- [_pendingRequests removeAllObjects];
-
- _lastLocationEvent = event;
- }
-
- for (RCTPendingLocationRequest *request in pendingRequestsCopy) {
- if (request.successBlock) {
- request.successBlock(@[event]);
- }
- }
-}
-
-- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
-{
- NSArray *pendingRequestsCopy;
-
- // TODO (#5906496): is this locking neccessary? If so, use something better than @synchronize
- @synchronized(self) {
- pendingRequestsCopy = [_pendingRequests allValues];
- [_pendingRequests removeAllObjects];
- }
-
- NSString *errorMsg = @"User denied location service or location service not available.";
- for (RCTPendingLocationRequest *request in pendingRequestsCopy) {
- if (request.errorBlock) {
- request.errorBlock(@[errorMsg]);
- }
- }
-}
-
-- (void)getCurrentPosition:(RCTResponseSenderBlock)geoSuccess withErrorCallback:(RCTResponseSenderBlock)geoError
-{
- RCT_EXPORT();
-
- NSDictionary *lastLocationCopy;
- // TODO (#5906496): is this locking neccessary? If so, use something better than @synchronize
- @synchronized(self) {
- if (![CLLocationManager locationServicesEnabled] || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
- if (geoError) {
- NSString *errorMsg = @"User denied location service or location service not available.";
- geoError(@[errorMsg]);
- return;
- }
- }
-
- // If a request for the current position comes in before the OS has informed us, we wait for the first
- // OS event and then call our callbacks. This obviates the need for handling of the otherwise
- // common failure case of requesting the geolocation until it succeeds, assuming we would have
- // instead returned an error if it wasn't yet available.
- if (!_lastLocationEvent) {
- NSInteger requestID = [_pendingRequests count];
- RCTPendingLocationRequest *request = [[RCTPendingLocationRequest alloc] init];
- request.successBlock = geoSuccess;
- request.errorBlock = geoError;
- _pendingRequests[@(requestID)] = request;
- return;
- } else {
- lastLocationCopy = [_lastLocationEvent copy];
- }
- }
- if (geoSuccess) {
- geoSuccess(@[lastLocationCopy]);
- }
-}
-
-@end
diff --git a/ReactKit/Modules/RCTUIManager.m b/ReactKit/Modules/RCTUIManager.m
index 47b2e6c84..a22f24540 100644
--- a/ReactKit/Modules/RCTUIManager.m
+++ b/ReactKit/Modules/RCTUIManager.m
@@ -74,8 +74,9 @@ UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimationType t
_property = [RCTConvert NSString:config[@"property"]];
// TODO: this should be provided in ms, not seconds
- _duration = [RCTConvert NSTimeInterval:config[@"duration"]] ?: duration;
- _delay = [RCTConvert NSTimeInterval:config[@"delay"]];
+ // (this will require changing all call sites to ms as well)
+ _duration = [RCTConvert NSTimeInterval:config[@"duration"]] * 1000.0 ?: duration;
+ _delay = [RCTConvert NSTimeInterval:config[@"delay"]] * 1000.0;
_animationType = [RCTConvert RCTAnimationType:config[@"type"]];
if (_animationType == RCTAnimationTypeSpring) {
_springDamping = [RCTConvert CGFloat:config[@"springDamping"]];
@@ -135,7 +136,8 @@ UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimationType t
if ((self = [super init])) {
// TODO: this should be provided in ms, not seconds
- NSTimeInterval duration = [RCTConvert NSTimeInterval:config[@"duration"]];
+ // (this will require changing all call sites to ms as well)
+ NSTimeInterval duration = [RCTConvert NSTimeInterval:config[@"duration"]] * 1000.0;
_createAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"create"]];
_updateAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"update"]];
diff --git a/ReactKit/ReactKit.xcodeproj/project.pbxproj b/ReactKit/ReactKit.xcodeproj/project.pbxproj
index 899d865b4..48cac5ded 100644
--- a/ReactKit/ReactKit.xcodeproj/project.pbxproj
+++ b/ReactKit/ReactKit.xcodeproj/project.pbxproj
@@ -34,7 +34,10 @@
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
13E067591A70F44B002CDEE1 /* UIView+ReactKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */; };
- 5F5F0D991A9E456B001279FA /* RCTLocationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */; };
+ 58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; };
+ 14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; };
+ 14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; };
+ 14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; };
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 830BA4541A8E3BDA00D53203 /* RCTCache.m */; };
832348161A77A5AA00B55238 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FC71A68125100A75B9A /* Layout.c */; };
@@ -123,8 +126,14 @@
13E067531A70F44B002CDEE1 /* UIView+ReactKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ReactKit.h"; sourceTree = ""; };
13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ReactKit.m"; sourceTree = ""; };
13EFFCCF1A98E6FE002607DC /* RCTJSMethodRegistrar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSMethodRegistrar.h; sourceTree = ""; };
- 5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLocationObserver.h; sourceTree = ""; };
- 5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLocationObserver.m; sourceTree = ""; };
+ 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDatePickerManager.m; sourceTree = ""; };
+ 58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDatePickerManager.h; sourceTree = ""; };
+ 14F362071AABD06A001CE568 /* RCTSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitch.h; sourceTree = ""; };
+ 14F362081AABD06A001CE568 /* RCTSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitch.m; sourceTree = ""; };
+ 14F362091AABD06A001CE568 /* RCTSwitchManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitchManager.h; sourceTree = ""; };
+ 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitchManager.m; sourceTree = ""; };
+ 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSliderManager.h; sourceTree = ""; };
+ 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSliderManager.m; sourceTree = ""; };
830213F31A654E0800B993E6 /* RCTBridgeModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeModule.h; sourceTree = ""; };
830A229C1A66C68A008503DA /* RCTRootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootView.h; sourceTree = ""; };
830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = ""; };
@@ -187,8 +196,6 @@
13B07FE01A69315300A75B9A /* Modules */ = {
isa = PBXGroup;
children = (
- 5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */,
- 5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */,
13B07FE71A69327A00A75B9A /* RCTAlertManager.h */,
13B07FE81A69327A00A75B9A /* RCTAlertManager.m */,
13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */,
@@ -206,7 +213,15 @@
13B07FF31A6947C200A75B9A /* Views */ = {
isa = PBXGroup;
children = (
+ 14F362071AABD06A001CE568 /* RCTSwitch.h */,
+ 14F362081AABD06A001CE568 /* RCTSwitch.m */,
+ 14F362091AABD06A001CE568 /* RCTSwitchManager.h */,
+ 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */,
+ 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */,
+ 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */,
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */,
+ 58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */,
+ 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */,
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */,
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */,
@@ -393,14 +408,16 @@
13B0801E1A69489C00A75B9A /* RCTTextField.m in Sources */,
13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */,
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
- 5F5F0D991A9E456B001279FA /* RCTLocationObserver.m in Sources */,
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */,
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */,
83CBBA5A1A601E9000E9B192 /* RCTRedBox.m in Sources */,
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */,
832348161A77A5AA00B55238 /* Layout.c in Sources */,
+ 14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */,
+ 14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
13B080201A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m in Sources */,
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */,
+ 58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */,
13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
@@ -409,6 +426,7 @@
13B0801F1A69489C00A75B9A /* RCTTextFieldManager.m in Sources */,
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */,
13E067591A70F44B002CDEE1 /* UIView+ReactKit.m in Sources */,
+ 14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */,
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
diff --git a/ReactKit/Views/RCTDatePickerManager.h b/ReactKit/Views/RCTDatePickerManager.h
new file mode 100644
index 000000000..65459b80c
--- /dev/null
+++ b/ReactKit/Views/RCTDatePickerManager.h
@@ -0,0 +1,7 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTViewManager.h"
+
+@interface RCTDatePickerManager : RCTViewManager
+
+@end
diff --git a/ReactKit/Views/RCTDatePickerManager.m b/ReactKit/Views/RCTDatePickerManager.m
new file mode 100644
index 000000000..39010214e
--- /dev/null
+++ b/ReactKit/Views/RCTDatePickerManager.m
@@ -0,0 +1,51 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTDatePickerManager.h"
+
+#import "RCTBridge.h"
+#import "RCTConvert.h"
+#import "RCTEventDispatcher.h"
+#import "UIView+ReactKit.h"
+
+@implementation RCTDatePickerManager
+
+- (UIView *)view
+{
+ UIDatePicker *picker = [[UIDatePicker alloc] init];
+ [picker addTarget:self
+ action:@selector(onChange:)
+ forControlEvents:UIControlEventValueChanged];
+ return picker;
+}
+
+RCT_EXPORT_VIEW_PROPERTY(date)
+RCT_EXPORT_VIEW_PROPERTY(minimumDate)
+RCT_EXPORT_VIEW_PROPERTY(maximumDate)
+RCT_EXPORT_VIEW_PROPERTY(minuteInterval)
+RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode)
+RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone)
+
+- (void)onChange:(UIDatePicker *)sender
+{
+ NSDictionary *event = @{
+ @"target": sender.reactTag,
+ @"timestamp": @([sender.date timeIntervalSince1970] * 1000.0)
+ };
+ [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
+}
+
+- (NSDictionary *)constantsToExport
+{
+ UIDatePicker *dp = [[UIDatePicker alloc] init];
+ return @{
+ @"ComponentHeight": @(CGRectGetHeight(dp.frame)),
+ @"ComponentWidth": @(CGRectGetWidth(dp.frame)),
+ @"DatePickerModes": @{
+ @"time": @(UIDatePickerModeTime),
+ @"date": @(UIDatePickerModeDate),
+ @"datetime": @(UIDatePickerModeDateAndTime),
+ }
+ };
+}
+
+@end
diff --git a/ReactKit/Views/RCTShadowView.h b/ReactKit/Views/RCTShadowView.h
index 9a09bad4f..f869ca614 100644
--- a/ReactKit/Views/RCTShadowView.h
+++ b/ReactKit/Views/RCTShadowView.h
@@ -32,8 +32,8 @@ typedef void (^RCTApplierBlock)(RCTSparseArray *);
@property (nonatomic, weak, readonly) RCTShadowView *superview;
@property (nonatomic, assign, readonly) css_node_t *cssNode;
@property (nonatomic, copy) NSString *moduleName;
-@property (nonatomic, assign) BOOL isBGColorExplicitlySet; // Used to propogate to children
-@property (nonatomic, strong) UIColor *backgroundColor; // Used to propogate to children
+@property (nonatomic, assign) BOOL isBGColorExplicitlySet; // Used to propagate to children
+@property (nonatomic, strong) UIColor *backgroundColor; // Used to propagate to children
@property (nonatomic, assign) RCTUpdateLifecycle layoutLifecycle;
/**
diff --git a/ReactKit/Views/RCTSliderManager.h b/ReactKit/Views/RCTSliderManager.h
new file mode 100644
index 000000000..1088ec569
--- /dev/null
+++ b/ReactKit/Views/RCTSliderManager.h
@@ -0,0 +1,7 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTViewManager.h"
+
+@interface RCTSliderManager : RCTViewManager
+
+@end
diff --git a/ReactKit/Views/RCTSliderManager.m b/ReactKit/Views/RCTSliderManager.m
new file mode 100644
index 000000000..8561c0a97
--- /dev/null
+++ b/ReactKit/Views/RCTSliderManager.m
@@ -0,0 +1,43 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTSliderManager.h"
+
+#import "RCTBridge.h"
+#import "RCTEventDispatcher.h"
+#import "UIView+ReactKit.h"
+
+@implementation RCTSliderManager
+
+- (UIView *)view
+{
+ UISlider *slider = [[UISlider alloc] init];
+ [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
+ [slider addTarget:self action:@selector(sliderTouchEnd:) forControlEvents:UIControlEventTouchUpInside];
+ return slider;
+}
+
+- (void)sliderValueChanged:(UISlider *)sender
+{
+ NSDictionary *event = @{
+ @"target": sender.reactTag,
+ @"value": @(sender.value),
+ @"continuous": @YES,
+ };
+
+ [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
+}
+
+- (void)sliderTouchEnd:(UISlider *)sender
+{
+ NSDictionary *event = @{
+ @"target": sender.reactTag,
+ @"value": @(sender.value),
+ @"continuous": @NO,
+ };
+
+ [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
+}
+
+RCT_EXPORT_VIEW_PROPERTY(value);
+
+@end
diff --git a/ReactKit/Views/RCTSwitch.h b/ReactKit/Views/RCTSwitch.h
new file mode 100644
index 000000000..7866eb866
--- /dev/null
+++ b/ReactKit/Views/RCTSwitch.h
@@ -0,0 +1,10 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+
+#import
+
+@interface RCTSwitch : UISwitch
+
+@property (nonatomic, assign) BOOL wasOn;
+
+@end
diff --git a/ReactKit/Views/RCTSwitch.m b/ReactKit/Views/RCTSwitch.m
new file mode 100644
index 000000000..70233fede
--- /dev/null
+++ b/ReactKit/Views/RCTSwitch.m
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTSwitch.h"
+
+#import "RCTEventDispatcher.h"
+#import "UIView+ReactKit.h"
+
+@implementation RCTSwitch
+
+- (void)setOn:(BOOL)on animated:(BOOL)animated {
+ _wasOn = on;
+ [super setOn:on animated:animated];
+}
+
+@end
diff --git a/ReactKit/Views/RCTSwitchManager.h b/ReactKit/Views/RCTSwitchManager.h
new file mode 100644
index 000000000..f6833d106
--- /dev/null
+++ b/ReactKit/Views/RCTSwitchManager.h
@@ -0,0 +1,7 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTViewManager.h"
+
+@interface RCTSwitchManager : RCTViewManager
+
+@end
diff --git a/ReactKit/Views/RCTSwitchManager.m b/ReactKit/Views/RCTSwitchManager.m
new file mode 100644
index 000000000..61eab8199
--- /dev/null
+++ b/ReactKit/Views/RCTSwitchManager.m
@@ -0,0 +1,39 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTSwitchManager.h"
+
+#import "RCTBridge.h"
+#import "RCTEventDispatcher.h"
+#import "RCTSwitch.h"
+#import "UIView+ReactKit.h"
+
+@implementation RCTSwitchManager
+
+- (UIView *)view
+{
+ RCTSwitch *switcher = [[RCTSwitch alloc] init];
+ [switcher addTarget:self
+ action:@selector(onChange:)
+ forControlEvents:UIControlEventValueChanged];
+ return switcher;
+}
+
+- (void)onChange:(RCTSwitch *)sender
+{
+ if (sender.wasOn != sender.on) {
+ [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:@{
+ @"target": sender.reactTag,
+ @"value": @(sender.on)
+ }];
+
+ sender.wasOn = sender.on;
+ }
+}
+
+RCT_EXPORT_VIEW_PROPERTY(onTintColor);
+RCT_EXPORT_VIEW_PROPERTY(tintColor);
+RCT_EXPORT_VIEW_PROPERTY(thumbTintColor);
+RCT_EXPORT_VIEW_PROPERTY(on);
+RCT_EXPORT_VIEW_PROPERTY(enabled);
+
+@end
diff --git a/ReactKit/Views/RCTViewNodeProtocol.h b/ReactKit/Views/RCTViewNodeProtocol.h
index 0e3e08099..71422b2c8 100644
--- a/ReactKit/Views/RCTViewNodeProtocol.h
+++ b/ReactKit/Views/RCTViewNodeProtocol.h
@@ -1,7 +1,6 @@
// Copyright 2004-present Facebook. All Rights Reserved.
/**
-
* Logical node in a tree of application components. Both `ShadowView`s and
* `UIView+ReactKit`s conform to this. Allows us to write utilities that
* reason about trees generally.