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.js b/Libraries/Components/TextInput/TextInput.js index a44d61adf73bc7..0b30fd7a572741 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -32,6 +32,8 @@ var invariant = require('invariant'); var merge = require('merge'); var autoCapitalizeConsts = RCTUIManager.UIText.AutocapitalizationType; +var keyboardTypeConsts = RCTUIManager.UIKeyboardType; +var returnKeyTypeConsts = RCTUIManager.UIReturnKeyType; var RCTTextViewAttributes = merge(ReactIOSViewAttributes.UIView, { autoCorrect: true, @@ -43,6 +45,9 @@ var RCTTextViewAttributes = merge(ReactIOSViewAttributes.UIView, { fontStyle: true, fontWeight: true, keyboardType: true, + returnKeyType: true, + enablesReturnKeyAutomatically: true, + secureTextEntry: true, mostRecentEventCounter: true, placeholder: true, placeholderTextColor: true, @@ -82,6 +87,10 @@ var AndroidTextInput = createReactIOSNativeComponentClass({ uiViewClassName: 'AndroidTextInput', }); +var crossPlatformKeyboardTypeMap = { + 'numeric': 'decimal-pad', +}; + type DefaultProps = { bufferDelay: number; }; @@ -154,8 +163,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. */ @@ -351,6 +399,12 @@ var TextInput = React.createClass({ var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize]; var clearButtonMode = RCTUIManager.UITextField.clearButtonMode[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) { if (this.props[propKey]) { @@ -364,7 +418,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} @@ -406,6 +463,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 45058d524d64fc..666ce013e744ff 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -52,6 +52,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 cd8008fbf95246..9aea12727b394f 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -144,10 +144,33 @@ + (NSDate *)NSDate:(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 6ac370a4928499..d460ea68db279d 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1301,6 +1301,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 5fb0960058691f..0911e069ff8eac 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 7385b49ad164da..041474643dbdcd 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)