diff --git a/.gitignore b/.gitignore index ed8c09532e8c3d..4b88986b3a2213 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ !**/*.xcworkspacedata !**/*.xcsettings !**/*.xcscheme +Examples/UIExplorer/.idea/ +React/.idea/ build/ *.pbxuser !default.pbxuser diff --git a/Examples/UIExplorer/TextInputExample.js b/Examples/UIExplorer/TextInputExample.js index e0ae1b46517070..5d1aec899beac2 100644 --- a/Examples/UIExplorer/TextInputExample.js +++ b/Examples/UIExplorer/TextInputExample.js @@ -57,6 +57,7 @@ var TextEventsExample = React.createClass({ this.updateText('onFocus')} onBlur={() => this.updateText('onBlur')} diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme b/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme index b231b77ee84fc9..5c546b64ca80aa 100644 --- a/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme +++ b/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme @@ -1,17 +1,10 @@ - + + buildForRunning = "YES"> - - - - - - - - - - - - - - - - - + buildConfiguration = "Debug"> + - - - - - - - - - - - - diff --git a/Examples/UIExplorer/UIExplorer/AppDelegate.m b/Examples/UIExplorer/UIExplorer/AppDelegate.m index 84734f12f9d642..5a44bbb0b487e8 100644 --- a/Examples/UIExplorer/UIExplorer/AppDelegate.m +++ b/Examples/UIExplorer/UIExplorer/AppDelegate.m @@ -31,7 +31,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // // To run on device, change `localhost` to the IP address of your computer, and make sure your computer and // iOS device are on the same Wi-Fi network. - jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.includeRequire.runModule.bundle?dev=true"]; + jsCodeLocation = [NSURL URLWithString:@"http://bimawa.local:8081/Examples/UIExplorer/UIExplorerApp.includeRequire.runModule.bundle?dev=true"]; // OPTION 2 // Load from pre-bundled file on disk. To re-generate the static bundle, run diff --git a/Examples/UIExplorer/UIExplorerList.js b/Examples/UIExplorer/UIExplorerList.js index 308249572da166..9806e95200003a 100644 --- a/Examples/UIExplorer/UIExplorerList.js +++ b/Examples/UIExplorer/UIExplorerList.js @@ -126,6 +126,7 @@ class UIExplorerList extends React.Component { clearButtonMode="always" onChangeText={this._search.bind(this)} placeholder="Search..." + placeholderTextColor="red" style={styles.searchTextInput} /> diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index fb5f99949fbdcd..5d0da86df67ff9 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -442,6 +442,7 @@ var TextInput = React.createClass({ onSubmitEditing={this.props.onSubmitEditing} onSelectionChangeShouldSetResponder={() => true} placeholder={this.props.placeholder} + placeholderTextColor={this.props.placeholderTextColor} text={this.state.bufferedValue} autoCapitalize={autoCapitalize} autoCorrect={this.props.autoCorrect} diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index b6a350dcd4964e..16ff233ea486d4 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -729,14 +729,12 @@ static BOOL RCTCallPropertySetter(NSString *key, SEL setter, id value, id view, } static void RCTSetViewProps(NSDictionary *props, UIView *view, - UIView *defaultView, RCTViewManager *manager) -{ - [props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { - - SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forView:withDefaultView:", key]); - RCTCallPropertySetter(key, setter, obj, view, defaultView, manager); + UIView *defaultView, RCTViewManager *manager) { + [props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forView:withDefaultView:", key]); + RCTCallPropertySetter(key, setter, obj, view, defaultView, manager); - }]; + }]; } static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView, diff --git a/React/Views/RCTTextField.h b/React/Views/RCTTextField.h index bd1be9c187bd39..b7517a5e2a8875 100644 --- a/React/Views/RCTTextField.h +++ b/React/Views/RCTTextField.h @@ -13,10 +13,11 @@ @interface RCTTextField : UITextField -@property (nonatomic, assign) BOOL caretHidden; -@property (nonatomic, assign) BOOL autoCorrect; -@property (nonatomic, assign) BOOL selectTextOnFocus; -@property (nonatomic, assign) UIEdgeInsets contentInset; +@property(nonatomic, assign) BOOL caretHidden; +@property(nonatomic, assign) BOOL autoCorrect; +@property(nonatomic, assign) BOOL selectTextOnFocus; +@property(nonatomic, assign) UIEdgeInsets contentInset; +@property(nonatomic, strong) UIColor *placeholderTextColor; - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; diff --git a/React/Views/RCTTextField.m b/React/Views/RCTTextField.m index 35eb84d9653dde..119fa3a8c43822 100644 --- a/React/Views/RCTTextField.m +++ b/React/Views/RCTTextField.m @@ -9,90 +9,102 @@ #import "RCTTextField.h" -#import "RCTConvert.h" #import "RCTEventDispatcher.h" -#import "RCTUtils.h" #import "UIView+React.h" -@implementation RCTTextField -{ - RCTEventDispatcher *_eventDispatcher; - NSMutableArray *_reactSubviews; - BOOL _jsRequestingFirstResponder; +@implementation RCTTextField { + RCTEventDispatcher *_eventDispatcher; + NSMutableArray *_reactSubviews; + BOOL _jsRequestingFirstResponder; } -- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher -{ - if ((self = [super initWithFrame:CGRectZero])) { +- (void)_setupPlaceholder { + NSAttributedString *placeholderAttributedString = nil; + if (self.placeholder && self.placeholder.length > 0) { + if (self.placeholderTextColor) { + placeholderAttributedString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName : self.placeholderTextColor}]; + } + } - _eventDispatcher = eventDispatcher; - [self addTarget:self action:@selector(_textFieldDidChange) forControlEvents:UIControlEventEditingChanged]; - [self addTarget:self action:@selector(_textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin]; - [self addTarget:self action:@selector(_textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd]; - [self addTarget:self action:@selector(_textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit]; - _reactSubviews = [[NSMutableArray alloc] init]; - } - return self; + if (placeholderAttributedString) + self.attributedPlaceholder = placeholderAttributedString; + +} + +- (void)setPlaceholderTextColor:(UIColor *)placeholderTextColor { + _placeholderTextColor = placeholderTextColor; + [self _setupPlaceholder]; +} + +- (void)setPlaceholder:(NSString *)placeholder { + [super setPlaceholder:[placeholder mutableCopy]]; + [self _setupPlaceholder]; +} + +- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher { + if ((self = [super initWithFrame:CGRectZero])) { + + _eventDispatcher = eventDispatcher; + [self addTarget:self action:@selector(_textFieldDidChange) forControlEvents:UIControlEventEditingChanged]; + [self addTarget:self action:@selector(_textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin]; + [self addTarget:self action:@selector(_textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd]; + [self addTarget:self action:@selector(_textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit]; + _reactSubviews = [[NSMutableArray alloc] init]; + } + return self; } -- (void)setText:(NSString *)text -{ - if (![text isEqualToString:self.text]) { - [super setText:text]; - } +- (void)setText:(NSString *)text { + if (![text isEqualToString:self.text]) { + [super setText:text]; + } } -- (NSArray *)reactSubviews -{ - // TODO: do we support subviews of textfield in React? - // In any case, we should have a better approach than manually - // maintaining array in each view subclass like this - return _reactSubviews; +- (NSArray *)reactSubviews { + // TODO: do we support subviews of textfield in React? + // In any case, we should have a better approach than manually + // maintaining array in each view subclass like this + return _reactSubviews; } -- (void)removeReactSubview:(UIView *)subview -{ - // TODO: this is a bit broken - if the TextField inserts any of - // its own views below or between React's, the indices won't match - [_reactSubviews removeObject:subview]; - [subview removeFromSuperview]; +- (void)removeReactSubview:(UIView *)subview { + // TODO: this is a bit broken - if the TextField inserts any of + // its own views below or between React's, the indices won't match + [_reactSubviews removeObject:subview]; + [subview removeFromSuperview]; } -- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex -{ - // TODO: this is a bit broken - if the TextField inserts any of - // its own views below or between React's, the indices won't match - [_reactSubviews insertObject:view atIndex:atIndex]; - [super insertSubview:view atIndex:atIndex]; +- (void)insertReactSubview:(UIView *)view + atIndex: + (NSInteger)atIndex { + // TODO: this is a bit broken - if the TextField inserts any of + // its own views below or between React's, the indices won't match + [_reactSubviews insertObject:view atIndex:atIndex]; + [super insertSubview:view atIndex:atIndex]; } -- (CGRect)caretRectForPosition:(UITextPosition *)position -{ - if (_caretHidden) { - return CGRectZero; - } - return [super caretRectForPosition:position]; +- (CGRect)caretRectForPosition:(UITextPosition *)position { + if (_caretHidden) { + return CGRectZero; + } + return [super caretRectForPosition:position]; } -- (CGRect)textRectForBounds:(CGRect)bounds -{ - CGRect rect = [super textRectForBounds:bounds]; - return UIEdgeInsetsInsetRect(rect, _contentInset); +- (CGRect)textRectForBounds:(CGRect)bounds { + CGRect rect = [super textRectForBounds:bounds]; + return UIEdgeInsetsInsetRect(rect, _contentInset); } -- (CGRect)editingRectForBounds:(CGRect)bounds -{ - return [self textRectForBounds:bounds]; +- (CGRect)editingRectForBounds:(CGRect)bounds { + return [self textRectForBounds:bounds]; } -- (void)setAutoCorrect:(BOOL)autoCorrect -{ - self.autocorrectionType = (autoCorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo); +- (void)setAutoCorrect:(BOOL)autoCorrect { + self.autocorrectionType = (autoCorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo); } -- (BOOL)autoCorrect -{ - return self.autocorrectionType == UITextAutocorrectionTypeYes; +- (BOOL)autoCorrect { + return self.autocorrectionType == UITextAutocorrectionTypeYes; } #define RCT_TEXT_EVENT_HANDLER(delegateMethod, eventName) \ @@ -104,46 +116,43 @@ - (void)delegateMethod \ } RCT_TEXT_EVENT_HANDLER(_textFieldDidChange, RCTTextEventTypeChange) + RCT_TEXT_EVENT_HANDLER(_textFieldEndEditing, RCTTextEventTypeEnd) + RCT_TEXT_EVENT_HANDLER(_textFieldSubmitEditing, RCTTextEventTypeSubmit) -- (void)_textFieldBeginEditing -{ - if (_selectTextOnFocus) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self selectAll:nil]; - }); - } - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus - reactTag:self.reactTag - text:self.text]; +- (void)_textFieldBeginEditing { + if (_selectTextOnFocus) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self selectAll:nil]; + }); + } + [_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus + reactTag:self.reactTag + text:self.text]; } // TODO: we should support shouldChangeTextInRect (see UITextFieldDelegate) -- (BOOL)becomeFirstResponder -{ - _jsRequestingFirstResponder = YES; - BOOL result = [super becomeFirstResponder]; - _jsRequestingFirstResponder = NO; - return result; +- (BOOL)becomeFirstResponder { + _jsRequestingFirstResponder = YES; + BOOL result = [super becomeFirstResponder]; + _jsRequestingFirstResponder = NO; + return result; } -- (BOOL)resignFirstResponder -{ - BOOL result = [super resignFirstResponder]; - if (result) - { - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur - reactTag:self.reactTag - text:self.text]; - } - return result; +- (BOOL)resignFirstResponder { + BOOL result = [super resignFirstResponder]; + if (result) { + [_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur + reactTag:self.reactTag + text:self.text]; + } + return result; } -- (BOOL)canBecomeFirstResponder -{ - return _jsRequestingFirstResponder; +- (BOOL)canBecomeFirstResponder { + return _jsRequestingFirstResponder; } @end diff --git a/React/Views/RCTTextFieldManager.h b/React/Views/RCTTextFieldManager.h index beea00fe668e0b..039ba2444106ba 100644 --- a/React/Views/RCTTextFieldManager.h +++ b/React/Views/RCTTextFieldManager.h @@ -1,15 +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. - */ +* 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 "RCTViewManager.h" @interface RCTTextFieldManager : RCTViewManager + @end diff --git a/React/Views/RCTTextFieldManager.m b/React/Views/RCTTextFieldManager.m index 6e78d86a3b1c39..e34433655d71cf 100644 --- a/React/Views/RCTTextFieldManager.m +++ b/React/Views/RCTTextFieldManager.m @@ -1,16 +1,15 @@ /** - * 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. - */ +* 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 "RCTTextFieldManager.h" #import "RCTBridge.h" -#import "RCTConvert.h" #import "RCTShadowView.h" #import "RCTSparseArray.h" #import "RCTTextField.h" @@ -28,6 +27,7 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL) RCT_EXPORT_VIEW_PROPERTY(enabled, BOOL) RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString) +RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(text, NSString) RCT_EXPORT_VIEW_PROPERTY(clearButtonMode, UITextFieldViewMode) RCT_REMAP_VIEW_PROPERTY(clearTextOnFocus, clearsOnBeginEditing, BOOL)