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' };