diff --git a/packages/react-native-web/src/exports/TextInput/__tests__/index-test.js b/packages/react-native-web/src/exports/TextInput/__tests__/index-test.js
index 8baa9c6be3..6651b739da 100644
--- a/packages/react-native-web/src/exports/TextInput/__tests__/index-test.js
+++ b/packages/react-native-web/src/exports/TextInput/__tests__/index-test.js
@@ -160,6 +160,62 @@ describe('components/TextInput', () => {
});
});
+ describe('prop "inputMode"', () => {
+ test('value "decimal"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('decimal');
+ });
+
+ test('value "email"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('email');
+ expect(input.type).toEqual('email');
+ });
+
+ test('default value', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('none');
+ expect(input.type).toEqual('text');
+ });
+
+ test('value "numeric"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('numeric');
+ });
+
+ test('value "search"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('search');
+ expect(input.type).toEqual('search');
+ });
+
+ test('value "tel"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('tel');
+ expect(input.type).toEqual('tel');
+ });
+
+ test('value "text"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('text');
+ expect(input.type).toEqual('text');
+ });
+
+ test('value "url"', () => {
+ const { container } = render();
+ const input = findInput(container);
+ expect(input.inputMode).toEqual('url');
+ expect(input.type).toEqual('url');
+ });
+ });
+
describe('prop "keyboardType"', () => {
test('default value', () => {
const { container } = render();
diff --git a/packages/react-native-web/src/exports/TextInput/index.js b/packages/react-native-web/src/exports/TextInput/index.js
index 1a0cf24d06..eaebb34460 100644
--- a/packages/react-native-web/src/exports/TextInput/index.js
+++ b/packages/react-native-web/src/exports/TextInput/index.js
@@ -23,6 +23,7 @@ import useResponderEvents from '../../modules/useResponderEvents';
import { getLocaleDirection, useLocaleContext } from '../../modules/useLocale';
import StyleSheet from '../StyleSheet';
import TextInputState from '../../modules/TextInputState';
+import { warnOnce } from '../../modules/warnOnce';
/**
* Determines whether a 'selection' prop differs from a node's existing
@@ -101,6 +102,8 @@ const TextInput: React.AbstractComponent<
clearTextOnFocus,
dir,
editable = true,
+ enterKeyHint,
+ inputMode,
keyboardType = 'default',
multiline = false,
numberOfLines = 1,
@@ -130,7 +133,9 @@ const TextInput: React.AbstractComponent<
onStartShouldSetResponderCapture,
onSubmitEditing,
placeholderTextColor,
+ readOnly,
returnKeyType,
+ rows,
secureTextEntry = false,
selection,
selectTextOnFocus,
@@ -138,31 +143,47 @@ const TextInput: React.AbstractComponent<
} = props;
let type;
- let inputMode;
+ let _inputMode;
- switch (keyboardType) {
- case 'email-address':
+ if (inputMode != null) {
+ _inputMode = inputMode;
+ if (inputMode === 'email') {
type = 'email';
- break;
- case 'number-pad':
- case 'numeric':
- inputMode = 'numeric';
- break;
- case 'decimal-pad':
- inputMode = 'decimal';
- break;
- case 'phone-pad':
+ } else if (inputMode === 'tel') {
type = 'tel';
- break;
- case 'search':
- case 'web-search':
+ } else if (inputMode === 'search') {
type = 'search';
- break;
- case 'url':
+ } else if (inputMode === 'url') {
type = 'url';
- break;
- default:
+ } else {
type = 'text';
+ }
+ } else if (keyboardType != null) {
+ warnOnce('keyboardType', 'keyboardType is deprecated. Use inputMode.');
+ switch (keyboardType) {
+ case 'email-address':
+ type = 'email';
+ break;
+ case 'number-pad':
+ case 'numeric':
+ _inputMode = 'numeric';
+ break;
+ case 'decimal-pad':
+ _inputMode = 'decimal';
+ break;
+ case 'phone-pad':
+ type = 'tel';
+ break;
+ case 'search':
+ case 'web-search':
+ type = 'search';
+ break;
+ case 'url':
+ type = 'url';
+ break;
+ default:
+ type = 'text';
+ }
}
if (secureTextEntry) {
@@ -355,15 +376,31 @@ const TextInput: React.AbstractComponent<
supportedProps.autoCorrect = autoCorrect ? 'on' : 'off';
// 'auto' by default allows browsers to infer writing direction
supportedProps.dir = dir !== undefined ? dir : 'auto';
- supportedProps.enterKeyHint = returnKeyType;
- supportedProps.inputMode = inputMode;
+ if (returnKeyType != null) {
+ warnOnce('returnKeyType', 'returnKeyType is deprecated. Use enterKeyHint.');
+ }
+ supportedProps.enterKeyHint = enterKeyHint || returnKeyType;
+ supportedProps.inputMode = _inputMode;
supportedProps.onBlur = handleBlur;
supportedProps.onChange = handleChange;
supportedProps.onFocus = handleFocus;
supportedProps.onKeyDown = handleKeyDown;
supportedProps.onSelect = handleSelectionChange;
- supportedProps.readOnly = !editable;
- supportedProps.rows = multiline ? numberOfLines : undefined;
+ if (editable != null) {
+ warnOnce('editable', 'editable is deprecated. Use readOnly.');
+ }
+ supportedProps.readOnly = readOnly || !editable;
+ if (numberOfLines != null) {
+ warnOnce(
+ 'numberOfLines',
+ 'TextInput numberOfLines is deprecated. Use rows.'
+ );
+ }
+ supportedProps.rows = multiline
+ ? rows != null
+ ? rows
+ : numberOfLines
+ : undefined;
supportedProps.spellCheck = spellCheck != null ? spellCheck : autoCorrect;
supportedProps.style = [
{ '--placeholderTextColor': placeholderTextColor },
diff --git a/packages/react-native-web/src/exports/TextInput/types.js b/packages/react-native-web/src/exports/TextInput/types.js
index a835b9650b..a842a355d5 100644
--- a/packages/react-native-web/src/exports/TextInput/types.js
+++ b/packages/react-native-web/src/exports/TextInput/types.js
@@ -29,21 +29,26 @@ export type TextInputProps = {
defaultValue?: ?string,
dir?: ?('auto' | 'ltr' | 'rtl'),
disabled?: ?boolean,
- editable?: ?boolean,
+ enterKeyHint?:
+ | 'enter'
+ | 'done'
+ | 'go'
+ | 'next'
+ | 'previous'
+ | 'search'
+ | 'send',
inputAccessoryViewID?: ?string,
- keyboardType?:
- | 'default'
- | 'email-address'
- | 'number-pad'
- | 'numbers-and-punctuation'
+ inputMode?:
+ | 'decimal'
+ | 'email'
+ | 'none'
| 'numeric'
- | 'phone-pad'
| 'search'
- | 'url'
- | 'web-search',
+ | 'tel'
+ | 'text'
+ | 'url',
maxLength?: ?number,
multiline?: ?boolean,
- numberOfLines?: ?number,
onChange?: (e: any) => void,
onChangeText?: (e: string) => void,
onContentSizeChange?: (e: any) => void,
@@ -54,14 +59,8 @@ export type TextInputProps = {
onSubmitEditing?: (e: any) => void,
placeholder?: ?string,
placeholderTextColor?: ?ColorValue,
- returnKeyType?:
- | 'enter'
- | 'done'
- | 'go'
- | 'next'
- | 'previous'
- | 'search'
- | 'send',
+ readOnly?: ?boolean,
+ rows?: ?number,
secureTextEntry?: ?boolean,
selectTextOnFocus?: ?boolean,
selection?: {|
@@ -71,5 +70,26 @@ export type TextInputProps = {
selectionColor?: ?ColorValue,
spellCheck?: ?boolean,
style?: ?GenericStyleProp,
- value?: ?string
+ value?: ?string,
+ // deprecated
+ editable?: ?boolean,
+ keyboardType?:
+ | 'default'
+ | 'email-address'
+ | 'number-pad'
+ | 'numbers-and-punctuation'
+ | 'numeric'
+ | 'phone-pad'
+ | 'search'
+ | 'url'
+ | 'web-search',
+ numberOfLines?: ?number,
+ returnKeyType?:
+ | 'enter'
+ | 'done'
+ | 'go'
+ | 'next'
+ | 'previous'
+ | 'search'
+ | 'send'
};