From 326e0eec92e24ee75592b62786a553bac1077664 Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 19 Mar 2015 14:32:30 -0700 Subject: [PATCH] [TextInput] returnKeyType, enablesReturnKeyAutomatically, secureTextEntry more keyboardTypes This diff completes adding support for the following UITextField properties: returnKeyType: what the return key on the keyboard says enablesReturnKeyAutomatically: the return key is disabled iff there is no text entered. This too could be implemented in React but it feels better in UIKit right now because it is handled synchronously. secureTextEntry: obscure passwords keyboardType: added all the keyboard types, they are useful in different scenarios There were varying degrees of support for these properties so it looks like this diff continues some unfinished work. I also updated the keyboardType enum to use native constants instead of strings like the other properties here. Added examples to the UIExplorer. --- Examples/UIExplorer/TextInputExample.js | 83 +++++++++++++++++++ .../Components/TextInput/TextInput.ios.js | 62 +++++++++++++- React/Base/RCTConvert.h | 1 + React/Base/RCTConvert.m | 25 +++++- React/Modules/RCTUIManager.m | 26 ++++++ React/Views/RCTTextField.m | 1 - React/Views/RCTTextFieldManager.m | 3 + 7 files changed, 198 insertions(+), 3 deletions(-) diff --git a/Examples/UIExplorer/TextInputExample.js b/Examples/UIExplorer/TextInputExample.js index a52284b85ec11f..4e54c38b827a54 100644 --- a/Examples/UIExplorer/TextInputExample.js +++ b/Examples/UIExplorer/TextInputExample.js @@ -174,6 +174,89 @@ exports.examples = [ ); } }, + { + title: 'Keyboard types', + render: function() { + var keyboardTypes = [ + 'default', + 'ascii-capable', + 'numbers-and-punctuation', + 'url', + 'number-pad', + 'phone-pad', + 'name-phone-pad', + 'email-address', + 'decimal-pad', + 'twitter', + 'web-search', + 'numeric', + ]; + var examples = keyboardTypes.map((type) => { + return ( + + + + ); + }); + return {examples}; + } + }, + { + title: 'Return key types', + render: function() { + var returnKeyTypes = [ + 'default', + 'go', + 'google', + 'join', + 'next', + 'route', + 'search', + 'send', + 'yahoo', + 'done', + 'emergency-call', + ]; + var examples = returnKeyTypes.map((type) => { + return ( + + + + ); + }); + return {examples}; + } + }, + { + title: 'Enable return key automatically', + render: function() { + return ( + + + + + + ); + } + }, + { + title: 'Secure text entry', + render: function() { + return ( + + + + + + ); + } + }, { title: 'Event handling', render: function(): ReactElement { return }, diff --git a/Libraries/Components/TextInput/TextInput.ios.js b/Libraries/Components/TextInput/TextInput.ios.js index 02fec4d5a3a700..e73debbb0ee8b6 100644 --- a/Libraries/Components/TextInput/TextInput.ios.js +++ b/Libraries/Components/TextInput/TextInput.ios.js @@ -33,6 +33,8 @@ var merge = require('merge'); var autoCapitalizeConsts = RCTUIManager.UIText.AutocapitalizationType; var clearButtonModeConsts = RCTUIManager.UITextField.clearButtonMode; +var keyboardTypeConsts = RCTUIManager.UIKeyboardType; +var returnKeyTypeConsts = RCTUIManager.UIReturnKeyType; var RCTTextViewAttributes = merge(ReactIOSViewAttributes.UIView, { autoCorrect: true, @@ -44,6 +46,9 @@ var RCTTextViewAttributes = merge(ReactIOSViewAttributes.UIView, { fontStyle: true, fontWeight: true, keyboardType: true, + returnKeyType: true, + enablesReturnKeyAutomatically: true, + secureTextEntry: true, mostRecentEventCounter: true, placeholder: true, placeholderTextColor: true, @@ -66,6 +71,10 @@ var notMultiline = { onSubmitEditing: true, }; +var crossPlatformKeyboardTypeMap = { + 'numeric': 'decimal-pad', +}; + type DefaultProps = { bufferDelay: number; }; @@ -138,8 +147,47 @@ var TextInput = React.createClass({ */ keyboardType: PropTypes.oneOf([ 'default', + // iOS + 'ascii-capable', + 'numbers-and-punctuation', + 'url', + 'number-pad', + 'phone-pad', + 'name-phone-pad', + 'email-address', + 'decimal-pad', + 'twitter', + 'web-search', + // Cross-platform 'numeric', ]), + /** + * Determines how the return key should look. + */ + returnKeyType: PropTypes.oneOf([ + 'default', + 'go', + 'google', + 'join', + 'next', + 'route', + 'search', + 'send', + 'yahoo', + 'done', + 'emergency-call', + ]), + /** + * If true, the keyboard disables the return key when there is no text and + * automatically enables it when there is text. Default value is false. + */ + enablesReturnKeyAutomatically: PropTypes.bool, + + /** + * If true, the text input obscures the text entered so that sensitive text + * like passwords stay secure. Default value is false. + */ + secureTextEntry: PropTypes.bool, /** * If true, the text input can be multiple lines. Default value is false. */ @@ -317,6 +365,11 @@ var TextInput = React.createClass({ var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize]; var clearButtonMode = clearButtonModeConsts[this.props.clearButtonMode]; + var keyboardType = keyboardTypeConsts[ + crossPlatformKeyboardTypeMap[this.props.keyboardType] || + this.props.keyboardType + ]; + var returnKeyType = returnKeyTypeConsts[this.props.returnKeyType]; if (!this.props.multiline) { for (var propKey in onlyMultiline) { @@ -331,7 +384,10 @@ var TextInput = React.createClass({ ref="input" style={[styles.input, this.props.style]} enabled={this.props.editable} - keyboardType={this.props.keyboardType} + keyboardType={keyboardType} + returnKeyType={returnKeyType} + enablesReturnKeyAutomatically={this.props.enablesReturnKeyAutomatically} + secureTextEntry={this.props.secureTextEntry} onFocus={this._onFocus} onBlur={this._onBlur} onChange={this._onChange} @@ -373,6 +429,10 @@ var TextInput = React.createClass({ children={children} mostRecentEventCounter={this.state.mostRecentEventCounter} editable={this.props.editable} + keyboardType={keyboardType} + returnKeyType={returnKeyType} + enablesReturnKeyAutomatically={this.props.enablesReturnKeyAutomatically} + secureTextEntry={this.props.secureTextEntry} onFocus={this._onFocus} onBlur={this._onBlur} onChange={this._onChange} diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index c8d6ecadab5501..0f2ecf68ed0dc9 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -51,6 +51,7 @@ + (UITextFieldViewMode)UITextFieldViewMode:(id)json; + (UIScrollViewKeyboardDismissMode)UIScrollViewKeyboardDismissMode:(id)json; + (UIKeyboardType)UIKeyboardType:(id)json; ++ (UIReturnKeyType)UIReturnKeyType:(id)json; + (UIViewContentMode)UIViewContentMode:(id)json; + (UIBarStyle)UIBarStyle:(id)json; diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 9bf7104c996b0d..36de37f21c50c2 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -116,10 +116,33 @@ + (NSURLRequest *)NSURLRequest:(id)json }), UIScrollViewKeyboardDismissModeNone, integerValue) RCT_ENUM_CONVERTER(UIKeyboardType, (@{ - @"numeric": @(UIKeyboardTypeDecimalPad), @"default": @(UIKeyboardTypeDefault), + @"ascii-capable": @(UIKeyboardTypeASCIICapable), + @"numbers-and-punctuation": @(UIKeyboardTypeNumbersAndPunctuation), + @"url": @(UIKeyboardTypeURL), + @"number-pad": @(UIKeyboardTypeNumberPad), + @"phone-pad": @(UIKeyboardTypePhonePad), + @"name-phone-pad": @(UIKeyboardTypeNamePhonePad), + @"email-address": @(UIKeyboardTypeEmailAddress), + @"decimal-pad": @(UIKeyboardTypeDecimalPad), + @"twitter": @(UIKeyboardTypeTwitter), + @"web-search": @(UIKeyboardTypeWebSearch), }), UIKeyboardTypeDefault, integerValue) +RCT_ENUM_CONVERTER(UIReturnKeyType, (@{ + @"default": @(UIReturnKeyDefault), + @"go": @(UIReturnKeyGo), + @"google": @(UIReturnKeyGoogle), + @"join": @(UIReturnKeyJoin), + @"next": @(UIReturnKeyNext), + @"route": @(UIReturnKeyRoute), + @"search": @(UIReturnKeySearch), + @"send": @(UIReturnKeySend), + @"yahoo": @(UIReturnKeyYahoo), + @"done": @(UIReturnKeyDone), + @"emergency-call": @(UIReturnKeyEmergencyCall), +}), UIReturnKeyDefault, integerValue) + RCT_ENUM_CONVERTER(UIViewContentMode, (@{ @"scale-to-fill": @(UIViewContentModeScaleToFill), @"scale-aspect-fit": @(UIViewContentModeScaleAspectFit), diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index a0e7285c6b0dfb..ae6e54d69404c0 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1291,6 +1291,32 @@ - (NSDictionary *)constantsToExport @"always": @(UITextFieldViewModeAlways), }, }, + @"UIKeyboardType": @{ + @"default": @(UIKeyboardTypeDefault), + @"ascii-capable": @(UIKeyboardTypeASCIICapable), + @"numbers-and-punctuation": @(UIKeyboardTypeNumbersAndPunctuation), + @"url": @(UIKeyboardTypeURL), + @"number-pad": @(UIKeyboardTypeNumberPad), + @"phone-pad": @(UIKeyboardTypePhonePad), + @"name-phone-pad": @(UIKeyboardTypeNamePhonePad), + @"decimal-pad": @(UIKeyboardTypeDecimalPad), + @"email-address": @(UIKeyboardTypeEmailAddress), + @"twitter": @(UIKeyboardTypeTwitter), + @"web-search": @(UIKeyboardTypeWebSearch), + }, + @"UIReturnKeyType": @{ + @"default": @(UIReturnKeyDefault), + @"go": @(UIReturnKeyGo), + @"google": @(UIReturnKeyGoogle), + @"join": @(UIReturnKeyJoin), + @"next": @(UIReturnKeyNext), + @"route": @(UIReturnKeyRoute), + @"search": @(UIReturnKeySearch), + @"send": @(UIReturnKeySend), + @"yahoo": @(UIReturnKeyYahoo), + @"done": @(UIReturnKeyDone), + @"emergency-call": @(UIReturnKeyEmergencyCall), + }, @"UIView": @{ @"ContentMode": @{ @"ScaleToFill": @(UIViewContentModeScaleToFill), diff --git a/React/Views/RCTTextField.m b/React/Views/RCTTextField.m index 1ccf17d7f5f658..953c3421cd6118 100644 --- a/React/Views/RCTTextField.m +++ b/React/Views/RCTTextField.m @@ -31,7 +31,6 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher [self addTarget:self action:@selector(_textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd]; [self addTarget:self action:@selector(_textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit]; _reactSubviews = [[NSMutableArray alloc] init]; - self.returnKeyType = UIReturnKeyDone; } return self; } diff --git a/React/Views/RCTTextFieldManager.m b/React/Views/RCTTextFieldManager.m index 087dc5b26421d2..ddf6d6f924f9e9 100644 --- a/React/Views/RCTTextFieldManager.m +++ b/React/Views/RCTTextFieldManager.m @@ -29,6 +29,9 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(text, NSString) RCT_EXPORT_VIEW_PROPERTY(clearButtonMode, UITextFieldViewMode) RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType) +RCT_EXPORT_VIEW_PROPERTY(returnKeyType, UIReturnKeyType) +RCT_EXPORT_VIEW_PROPERTY(enablesReturnKeyAutomatically, BOOL) +RCT_EXPORT_VIEW_PROPERTY(secureTextEntry, BOOL) RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor) RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType, UITextAutocapitalizationType) RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextField)