mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: The `maxFontSizeMultiplier` prop for `Text` and `TextInput` was not handled in Fabric / New Architecture as documented in https://github.com/facebook/react-native/issues/47499. bypass-github-export-checks ## Changelog: [GENERAL] [FIXED] - Fix `maxFontSizeMultiplier` prop on `Text` and `TextInput` components in Fabric / New Architecture Pull Request resolved: https://github.com/facebook/react-native/pull/47614 Test Plan: I have not added any automated tests for this change but try to do so if requested. I have however added examples to RN Tester for both the Text and TextInput components, as well as compared the behaviour with Paper / Old Architecture. Both on version 0.76. Noticed now I didn't do exactly the same steps in both videos, oops! Be aware that reapplying changes made in the Settings are currently half-broken on the new architecture, thus I'm restarting the app on Android and iOS. But this issue is unrelated to my changes. I've tested on main branch and it has the same issue. Here are comparison videos between Paper and Fabric on iOS *after* I've made my fix. ### Text | Paper | Fabric | | ------------- | ------------- | | <video src="https://github.com/user-attachments/assets/f4fd009f-aa6d-41ab-92fa-8dcf1e351ba1" /> | <video src="https://github.com/user-attachments/assets/fda42cc6-34c2-42a7-a6e2-028e7c866075" /> | ### TextInput | Paper | Fabric | | ------------- | ------------- | | <video src="https://github.com/user-attachments/assets/59b59f7b-25d2-4b5b-a8e2-d2054cc6390b" /> | <video src="https://github.com/user-attachments/assets/72068566-8f2a-4463-874c-45a6f5b63b0d" /> | Reviewed By: Abbondanzo Differential Revision: D65953019 Pulled By: cipolleschi fbshipit-source-id: 90c3c7e236229e9ad9bd346941fafe4af8a9d9fc
1031 lines
29 KiB
JavaScript
1031 lines
29 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
* @flow
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
import type {
|
|
RNTesterModule,
|
|
RNTesterModuleExample,
|
|
} from '../../types/RNTesterTypes';
|
|
import type {KeyboardType} from 'react-native/Libraries/Components/TextInput/TextInput';
|
|
|
|
import RNTesterText from '../../components/RNTesterText';
|
|
import ExampleTextInput from './ExampleTextInput';
|
|
import TextInputSharedExamples from './TextInputSharedExamples';
|
|
import React from 'react';
|
|
import {
|
|
Alert,
|
|
Button,
|
|
InputAccessoryView,
|
|
StyleSheet,
|
|
Switch,
|
|
Text,
|
|
TextInput,
|
|
View,
|
|
} from 'react-native';
|
|
|
|
class WithLabel extends React.Component<$FlowFixMeProps> {
|
|
render(): React.Node {
|
|
return (
|
|
<View style={styles.labelContainer}>
|
|
<View style={styles.label}>
|
|
<RNTesterText>{this.props.label}</RNTesterText>
|
|
</View>
|
|
{this.props.children}
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
class TextInputAccessoryViewChangeTextExample extends React.Component<
|
|
{...},
|
|
{text: string},
|
|
> {
|
|
constructor(props: void | {...}) {
|
|
// $FlowFixMe[incompatible-call]
|
|
super(props);
|
|
this.state = {text: 'Placeholder Text'};
|
|
}
|
|
|
|
render(): React.Node {
|
|
const inputAccessoryViewID = 'inputAccessoryView1';
|
|
return (
|
|
<View>
|
|
<RNTesterText>
|
|
Set InputAccessoryView with ID & reset text:
|
|
</RNTesterText>
|
|
<ExampleTextInput
|
|
inputAccessoryViewID={inputAccessoryViewID}
|
|
onChangeText={text => this.setState({text})}
|
|
value={this.state.text}
|
|
/>
|
|
<InputAccessoryView nativeID={inputAccessoryViewID}>
|
|
<View style={{backgroundColor: 'white'}}>
|
|
<Button
|
|
onPress={() => this.setState({text: 'Placeholder Text'})}
|
|
title="Reset Text"
|
|
/>
|
|
</View>
|
|
</InputAccessoryView>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
class TextInputAccessoryViewChangeKeyboardExample extends React.Component<
|
|
{...},
|
|
{keyboardType: string, text: string},
|
|
> {
|
|
constructor(props: void | {...}) {
|
|
// $FlowFixMe[incompatible-call]
|
|
super(props);
|
|
this.state = {text: '', keyboardType: 'default'};
|
|
}
|
|
|
|
_switchKeyboard = () => {
|
|
this.setState({
|
|
keyboardType:
|
|
this.state.keyboardType === 'default' ? 'number-pad' : 'default',
|
|
});
|
|
};
|
|
|
|
render(): React.Node {
|
|
const inputAccessoryViewID = 'inputAccessoryView2';
|
|
return (
|
|
<View>
|
|
<RNTesterText>
|
|
Set InputAccessoryView with ID & switch keyboard:
|
|
</RNTesterText>
|
|
{/* $FlowFixMe[incompatible-use] */}
|
|
<ExampleTextInput
|
|
inputAccessoryViewID={inputAccessoryViewID}
|
|
onChangeText={text => this.setState({text})}
|
|
value={this.state.text}
|
|
// $FlowFixMe[incompatible-type]
|
|
keyboardType={this.state.keyboardType}
|
|
returnKeyType="done"
|
|
/>
|
|
<InputAccessoryView nativeID={inputAccessoryViewID}>
|
|
<View style={{backgroundColor: 'white'}}>
|
|
<Button onPress={this._switchKeyboard} title="Switch Keyboard" />
|
|
</View>
|
|
</InputAccessoryView>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
class TextInputAccessoryViewDefaultDoneButtonExample extends React.Component<
|
|
$ReadOnly<{|
|
|
keyboardType: KeyboardType,
|
|
|}>,
|
|
{text: string},
|
|
> {
|
|
constructor(props: void | $ReadOnly<{keyboardType: KeyboardType}>) {
|
|
// $FlowFixMe[incompatible-call]
|
|
super(props);
|
|
this.state = {text: ''};
|
|
}
|
|
|
|
render(): React.Node {
|
|
return (
|
|
<ExampleTextInput
|
|
onChangeText={text => this.setState({text})}
|
|
value={this.state.text}
|
|
keyboardType={this.props.keyboardType}
|
|
returnKeyType="done"
|
|
/>
|
|
);
|
|
}
|
|
}
|
|
|
|
class RewriteExampleKana extends React.Component<$FlowFixMeProps, any> {
|
|
constructor(props: any | void) {
|
|
super(props);
|
|
this.state = {text: ''};
|
|
}
|
|
render(): React.Node {
|
|
return (
|
|
<View style={styles.rewriteContainer}>
|
|
<ExampleTextInput
|
|
multiline={false}
|
|
onChangeText={text => {
|
|
this.setState({text: text.replace(/ひ/g, '日')});
|
|
}}
|
|
value={this.state.text}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
class SecureEntryExample extends React.Component<$FlowFixMeProps, any> {
|
|
constructor(props: any | void) {
|
|
super(props);
|
|
this.state = {
|
|
text: '',
|
|
password: '',
|
|
isSecureTextEntry: true,
|
|
};
|
|
}
|
|
render(): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
secureTextEntry={true}
|
|
defaultValue="abc"
|
|
onChangeText={text => this.setState({text})}
|
|
value={this.state.text}
|
|
/>
|
|
<RNTesterText>Current text is: {this.state.text}</RNTesterText>
|
|
<View
|
|
style={{
|
|
flex: 1,
|
|
flexDirection: 'row',
|
|
}}>
|
|
<ExampleTextInput
|
|
defaultValue="cde"
|
|
onChangeText={text => this.setState({password: text})}
|
|
secureTextEntry={this.state.isSecureTextEntry}
|
|
value={this.state.password}
|
|
/>
|
|
<Switch
|
|
onValueChange={value => {
|
|
this.setState({isSecureTextEntry: value});
|
|
}}
|
|
style={{marginLeft: 4}}
|
|
value={this.state.isSecureTextEntry}
|
|
/>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
const TextInputWithFocusButton = () => {
|
|
const inputToFocusRef = React.useRef<React.ElementRef<
|
|
typeof TextInput,
|
|
> | null>(null);
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
ref={inputToFocusRef}
|
|
placeholder="height increases with content"
|
|
defaultValue="React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native."
|
|
multiline={true}
|
|
enablesReturnKeyAutomatically={true}
|
|
returnKeyType="go"
|
|
style={[styles.multiline, styles.multilineExpandable]}
|
|
/>
|
|
<Button
|
|
title="Focus"
|
|
onPress={() => {
|
|
inputToFocusRef.current?.focus();
|
|
}}
|
|
/>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
function KeyboardShortcutsExample() {
|
|
return (
|
|
<View>
|
|
<Text
|
|
style={{
|
|
marginBottom: 4,
|
|
}}>
|
|
Single line:
|
|
</Text>
|
|
|
|
<ExampleTextInput
|
|
style={{
|
|
marginBottom: 4,
|
|
}}
|
|
placeholder="Default"
|
|
/>
|
|
|
|
<ExampleTextInput
|
|
style={{
|
|
marginBottom: 4,
|
|
}}
|
|
placeholder="Disable keyboard shortcuts"
|
|
disableKeyboardShortcuts
|
|
/>
|
|
|
|
<ExampleTextInput
|
|
style={{
|
|
marginBottom: 4,
|
|
}}
|
|
placeholder="Hidden keyboard with suggestions"
|
|
showSoftInputOnFocus={false}
|
|
/>
|
|
|
|
<ExampleTextInput
|
|
style={{
|
|
marginBottom: 4,
|
|
}}
|
|
placeholder="Hidden keyboard without suggestions"
|
|
disableKeyboardShortcuts
|
|
autoCorrect={false}
|
|
spellCheck={false}
|
|
showSoftInputOnFocus={false}
|
|
/>
|
|
|
|
<Text
|
|
style={{
|
|
marginBottom: 4,
|
|
}}>
|
|
Multiline:
|
|
</Text>
|
|
|
|
<ExampleTextInput
|
|
style={styles.multiline}
|
|
multiline
|
|
placeholder="default"
|
|
/>
|
|
|
|
<ExampleTextInput
|
|
style={styles.multiline}
|
|
multiline
|
|
placeholder="Disable keyboard shortcuts"
|
|
disableKeyboardShortcuts
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
multiline: {
|
|
height: 50,
|
|
marginBottom: 4,
|
|
},
|
|
multilinePlaceholderStyles: {
|
|
letterSpacing: 10,
|
|
lineHeight: 20,
|
|
textAlign: 'center',
|
|
},
|
|
multilineExpandable: {
|
|
height: 'auto',
|
|
maxHeight: 100,
|
|
},
|
|
multilineWithFontStyles: {
|
|
color: 'blue',
|
|
fontWeight: 'bold',
|
|
fontSize: 18,
|
|
fontFamily: 'Cochin',
|
|
height: 60,
|
|
},
|
|
singlelinePlaceholderStyles: {
|
|
letterSpacing: 10,
|
|
textAlign: 'center',
|
|
},
|
|
labelContainer: {
|
|
flexDirection: 'row',
|
|
marginVertical: 2,
|
|
},
|
|
label: {
|
|
width: 115,
|
|
alignItems: 'flex-end',
|
|
marginRight: 10,
|
|
paddingTop: 2,
|
|
},
|
|
rewriteContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
remainder: {
|
|
textAlign: 'right',
|
|
width: 24,
|
|
},
|
|
});
|
|
|
|
const textInputExamples: Array<RNTesterModuleExample> = [
|
|
...TextInputSharedExamples,
|
|
{
|
|
title: 'Live Re-Write (ひ -> 日)',
|
|
render: function (): React.Node {
|
|
return <RewriteExampleKana />;
|
|
},
|
|
},
|
|
{
|
|
title: 'Keyboard Input Accessory View',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<TextInputAccessoryViewChangeTextExample />
|
|
<TextInputAccessoryViewChangeKeyboardExample />
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: "Default Input Accessory View with returnKeyType = 'done'",
|
|
render: function (): React.Node {
|
|
const keyboardTypesWithDoneButton = [
|
|
'number-pad',
|
|
'phone-pad',
|
|
'decimal-pad',
|
|
'ascii-capable-number-pad',
|
|
];
|
|
const examples = keyboardTypesWithDoneButton.map(type => {
|
|
return (
|
|
<WithLabel key={'keyboardType: ' + type} label={type}>
|
|
<TextInputAccessoryViewDefaultDoneButtonExample
|
|
key={type}
|
|
keyboardType={type}
|
|
/>
|
|
</WithLabel>
|
|
);
|
|
});
|
|
return <View>{examples}</View>;
|
|
},
|
|
},
|
|
{
|
|
title: 'Custom Input Accessory View Button Label',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="Localized Label">
|
|
<ExampleTextInput
|
|
keyboardType="number-pad"
|
|
inputAccessoryViewButtonLabel="Presiona aquí para terminar"
|
|
/>
|
|
</WithLabel>
|
|
<WithLabel label="Custom Label">
|
|
<ExampleTextInput
|
|
keyboardType="ascii-capable-number-pad"
|
|
inputAccessoryViewButtonLabel="Press here to finish"
|
|
/>
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Nested content and `value` property',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="singleline">
|
|
<ExampleTextInput value="(value property)">
|
|
(first raw text node)
|
|
<Text style={{color: 'red'}}>(internal raw text node)</Text>
|
|
(last raw text node)
|
|
</ExampleTextInput>
|
|
</WithLabel>
|
|
<WithLabel label="multiline">
|
|
<ExampleTextInput multiline={true} value="(value property)">
|
|
(first raw text node)
|
|
<Text style={{color: 'red'}}>(internal raw text node)</Text>
|
|
(last raw text node)
|
|
</ExampleTextInput>
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Keyboard appearance',
|
|
render: function (): React.Node {
|
|
const keyboardAppearance = ['default', 'light', 'dark'];
|
|
const examples = keyboardAppearance.map(type => {
|
|
return (
|
|
<WithLabel key={type} label={type}>
|
|
<ExampleTextInput keyboardAppearance={type} />
|
|
</WithLabel>
|
|
);
|
|
});
|
|
return <View>{examples}</View>;
|
|
},
|
|
},
|
|
{
|
|
title: 'Return key types',
|
|
render: function (): React.Node {
|
|
const returnKeyTypes = [
|
|
'default',
|
|
'go',
|
|
'google',
|
|
'join',
|
|
'next',
|
|
'route',
|
|
'search',
|
|
'send',
|
|
'yahoo',
|
|
'done',
|
|
'emergency-call',
|
|
];
|
|
const examples = returnKeyTypes.map(type => {
|
|
return (
|
|
<WithLabel key={type} label={type}>
|
|
<ExampleTextInput returnKeyType={type} />
|
|
</WithLabel>
|
|
);
|
|
});
|
|
return <View>{examples}</View>;
|
|
},
|
|
},
|
|
{
|
|
title: 'Enable return key automatically',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="true">
|
|
<ExampleTextInput enablesReturnKeyAutomatically={true} />
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Secure text entry',
|
|
render: function (): React.Node {
|
|
return <SecureEntryExample />;
|
|
},
|
|
},
|
|
{
|
|
title: 'Colored input text',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput style={{color: 'blue'}} defaultValue="Blue" />
|
|
<ExampleTextInput style={{color: 'green'}} defaultValue="Green" />
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Colored highlight/cursor for text input',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
selectionColor={'green'}
|
|
defaultValue="Highlight me"
|
|
/>
|
|
<ExampleTextInput
|
|
selectionColor={'rgba(86, 76, 205, 1)'}
|
|
defaultValue="Highlight me"
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Clear button mode',
|
|
render: function (): React.Node {
|
|
const clearButtonModes = [
|
|
'never',
|
|
'while-editing',
|
|
'unless-editing',
|
|
'always',
|
|
];
|
|
const examples = clearButtonModes.map(mode => {
|
|
return (
|
|
<WithLabel key={mode} label={mode}>
|
|
<ExampleTextInput clearButtonMode={mode} defaultValue={mode} />
|
|
</WithLabel>
|
|
);
|
|
});
|
|
return <View>{examples}</View>;
|
|
},
|
|
},
|
|
{
|
|
title: 'Clear and select',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="clearTextOnFocus">
|
|
<ExampleTextInput
|
|
placeholder="text is cleared on focus"
|
|
defaultValue="text is cleared on focus"
|
|
clearTextOnFocus={true}
|
|
/>
|
|
</WithLabel>
|
|
<WithLabel label="selectTextOnFocus">
|
|
<ExampleTextInput
|
|
placeholder="text is selected on focus"
|
|
defaultValue="text is selected on focus"
|
|
selectTextOnFocus={true}
|
|
/>
|
|
</WithLabel>
|
|
<WithLabel label="clearTextOnFocus (multiline)">
|
|
<ExampleTextInput
|
|
placeholder="text is cleared on focus"
|
|
defaultValue="text is cleared on focus"
|
|
clearTextOnFocus={true}
|
|
multiline={true}
|
|
/>
|
|
</WithLabel>
|
|
<WithLabel label="selectTextOnFocus (multiline)">
|
|
<ExampleTextInput
|
|
placeholder="text is selected on focus"
|
|
defaultValue="text is selected on focus"
|
|
selectTextOnFocus={true}
|
|
multiline={true}
|
|
/>
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Multiline blur on submit',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
style={styles.multiline}
|
|
placeholder="blurOnSubmit = true"
|
|
returnKeyType="next"
|
|
blurOnSubmit={true}
|
|
multiline={true}
|
|
onSubmitEditing={event =>
|
|
Alert.alert('Alert', event.nativeEvent.text)
|
|
}
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Multiline',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
placeholder="multiline text input"
|
|
multiline={true}
|
|
style={styles.multiline}
|
|
/>
|
|
<ExampleTextInput
|
|
placeholder="multiline text input with font styles and placeholder"
|
|
multiline={true}
|
|
clearTextOnFocus={true}
|
|
autoCorrect={true}
|
|
autoCapitalize="words"
|
|
placeholderTextColor="red"
|
|
keyboardType="url"
|
|
style={[styles.multiline, styles.multilineWithFontStyles]}
|
|
/>
|
|
<ExampleTextInput
|
|
placeholder="multiline text input with max length"
|
|
maxLength={5}
|
|
multiline={true}
|
|
style={styles.multiline}
|
|
/>
|
|
<ExampleTextInput
|
|
placeholder="uneditable multiline text input"
|
|
editable={false}
|
|
multiline={true}
|
|
style={styles.multiline}
|
|
/>
|
|
<ExampleTextInput
|
|
defaultValue="uneditable multiline text input with phone number detection: 88888888."
|
|
editable={false}
|
|
multiline={true}
|
|
style={styles.multiline}
|
|
dataDetectorTypes="phoneNumber"
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Editable and Read only',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
placeholder="editable text input using editable prop"
|
|
editable
|
|
/>
|
|
<ExampleTextInput
|
|
placeholder="uneditable text input using editable prop"
|
|
editable={false}
|
|
/>
|
|
<ExampleTextInput
|
|
placeholder="editable text input using readOnly prop"
|
|
readOnly={false}
|
|
/>
|
|
<ExampleTextInput
|
|
placeholder="uneditable text input using readOnly prop"
|
|
readOnly
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'TextInput Intrinsic Size',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<RNTesterText>Singleline TextInput</RNTesterText>
|
|
<View style={{height: 80}}>
|
|
<ExampleTextInput
|
|
style={{
|
|
position: 'absolute',
|
|
fontSize: 16,
|
|
backgroundColor: '#eeeeee',
|
|
borderColor: '#666666',
|
|
borderWidth: 5,
|
|
borderTopWidth: 20,
|
|
borderRadius: 10,
|
|
borderBottomRightRadius: 20,
|
|
padding: 10,
|
|
paddingTop: 20,
|
|
}}
|
|
testID="singleline_textinput"
|
|
placeholder="Placeholder defines intrinsic size"
|
|
/>
|
|
</View>
|
|
<RNTesterText>Multiline TextInput</RNTesterText>
|
|
<View style={{height: 80}}>
|
|
<ExampleTextInput
|
|
style={{
|
|
position: 'absolute',
|
|
fontSize: 16,
|
|
backgroundColor: '#eeeeee',
|
|
borderColor: '#666666',
|
|
borderWidth: 5,
|
|
borderTopWidth: 20,
|
|
borderRadius: 10,
|
|
borderBottomRightRadius: 20,
|
|
padding: 10,
|
|
paddingTop: 20,
|
|
maxHeight: 100,
|
|
}}
|
|
testID="multiline_textinput"
|
|
multiline={true}
|
|
placeholder="Placeholder defines intrinsic size"
|
|
/>
|
|
</View>
|
|
<RNTesterText>Multiline TextInput with flex</RNTesterText>
|
|
<View>
|
|
<ExampleTextInput
|
|
style={{
|
|
fontSize: 16,
|
|
backgroundColor: '#eeeeee',
|
|
borderColor: '#666666',
|
|
borderWidth: 5,
|
|
borderTopWidth: 20,
|
|
borderRadius: 10,
|
|
borderBottomRightRadius: 20,
|
|
padding: 10,
|
|
paddingTop: 20,
|
|
}}
|
|
testID="multiline_textinput_with_flex"
|
|
multiline={true}
|
|
placeholder="Placeholder defines intrinsic size"
|
|
/>
|
|
</View>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'allowFontScaling attribute',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<Text>
|
|
By default, text will respect Text Size accessibility setting on
|
|
iOS. It means that all font sizes will be increased or decreased
|
|
depending on the value of Text Size setting in{' '}
|
|
<Text style={{fontWeight: 'bold'}}>
|
|
Settings.app - Display & Brightness - Text Size
|
|
</Text>
|
|
</Text>
|
|
<ExampleTextInput
|
|
placeholder="allowFontScaling = false"
|
|
allowFontScaling={false}
|
|
/>
|
|
<ExampleTextInput
|
|
style={{marginTop: 10}}
|
|
placeholder="allowFontScaling = false"
|
|
allowFontScaling={true}
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'maxFontSizeMultiplier attribute',
|
|
name: 'maxFontSizeMultiplier',
|
|
render(): React.Node {
|
|
return (
|
|
<View testID={'max-font-size-multiplier'}>
|
|
<Text>
|
|
When allowFontScaling is enabled, you can use the
|
|
maxFontSizeMultiplier prop to set an upper limit on how much the
|
|
font size will be scaled.
|
|
</Text>
|
|
<ExampleTextInput
|
|
allowFontScaling={true}
|
|
maxFontSizeMultiplier={1}
|
|
placeholder="This text will not scale up (max 1x)"
|
|
style={{marginTop: 10}}
|
|
testID={'non-scalable-text-input'}
|
|
/>
|
|
<ExampleTextInput
|
|
allowFontScaling={true}
|
|
maxFontSizeMultiplier={1.5}
|
|
placeholder="This text will scale up (max 1.5x)"
|
|
style={{marginTop: 10}}
|
|
testID={'scalable-text-input'}
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Auto-expanding',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<ExampleTextInput
|
|
placeholder="height increases with content"
|
|
defaultValue="React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native."
|
|
multiline={true}
|
|
enablesReturnKeyAutomatically={true}
|
|
returnKeyType="go"
|
|
style={[styles.multiline, styles.multilineExpandable]}
|
|
/>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'TextInput maxLength',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="maxLength: 5">
|
|
<ExampleTextInput maxLength={5} />
|
|
</WithLabel>
|
|
<WithLabel label="maxLength: 5 with placeholder">
|
|
<ExampleTextInput maxLength={5} placeholder="ZIP code entry" />
|
|
</WithLabel>
|
|
<WithLabel label="maxLength: 5 with default value already set">
|
|
<ExampleTextInput maxLength={5} defaultValue="94025" />
|
|
</WithLabel>
|
|
<WithLabel label="maxLength: 5 with very long default value already set">
|
|
<ExampleTextInput maxLength={5} defaultValue="9402512345" />
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Text Auto Complete',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="country">
|
|
<ExampleTextInput autoComplete="country" />
|
|
</WithLabel>
|
|
<WithLabel label="one-time-code">
|
|
<ExampleTextInput autoComplete="one-time-code" />
|
|
</WithLabel>
|
|
<WithLabel label="birthdate-full">
|
|
<ExampleTextInput autoComplete="birthdate-full" />
|
|
</WithLabel>
|
|
<WithLabel label="cc-name">
|
|
<ExampleTextInput autoComplete="cc-name" />
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Text Content Type',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="emailAddress">
|
|
<ExampleTextInput textContentType="emailAddress" />
|
|
</WithLabel>
|
|
<WithLabel label="name">
|
|
<ExampleTextInput textContentType="name" />
|
|
</WithLabel>
|
|
<WithLabel label="postalCode, when autoComplete set">
|
|
<ExampleTextInput
|
|
textContentType="postalCode"
|
|
autoComplete="email"
|
|
/>
|
|
</WithLabel>
|
|
<WithLabel label="creditCardExpiration">
|
|
<ExampleTextInput textContentType="creditCardExpiration" />
|
|
</WithLabel>
|
|
<WithLabel label="birthdate">
|
|
<ExampleTextInput textContentType="birthdate" />
|
|
</WithLabel>
|
|
<WithLabel label="dateTime">
|
|
<ExampleTextInput textContentType="dateTime" />
|
|
</WithLabel>
|
|
<WithLabel label="flightNumber">
|
|
<ExampleTextInput textContentType="flightNumber" />
|
|
</WithLabel>
|
|
<WithLabel label="shipmentTrackingNumber">
|
|
<ExampleTextInput textContentType="shipmentTrackingNumber" />
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'TextInput Placeholder Styles',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="letterSpacing: 10 lineHeight: 20 textAlign: 'center'">
|
|
<ExampleTextInput
|
|
placeholder="multiline text input"
|
|
multiline={true}
|
|
style={[styles.multiline, styles.multilinePlaceholderStyles]}
|
|
/>
|
|
</WithLabel>
|
|
<WithLabel label="letterSpacing: 10 textAlign: 'center'">
|
|
<ExampleTextInput
|
|
placeholder="singleline"
|
|
style={styles.singlelinePlaceholderStyles}
|
|
/>
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Line Break Strategy',
|
|
render: function (): React.Node {
|
|
const lineBreakStrategy = ['none', 'standard', 'hangul-word', 'push-out'];
|
|
const textByCode = {
|
|
en: 'lineBreakStrategy lineBreakStrategy lineBreakStrategy lineBreakStrategy',
|
|
ko: '한글개행한글개행 한글개행한글개행 한글개행한글개행 한글개행한글개행 한글개행한글개행 한글개행한글개행',
|
|
ja: 'かいぎょう かいぎょう かいぎょう かいぎょう かいぎょう かいぎょう',
|
|
cn: '改行 改行 改行 改行 改行 改行 改行 改行 改行 改行 改行 改行',
|
|
};
|
|
return (
|
|
<View>
|
|
{lineBreakStrategy.map(strategy => {
|
|
return (
|
|
<View key={strategy} style={{marginBottom: 12}}>
|
|
<Text
|
|
style={{
|
|
backgroundColor: 'lightgrey',
|
|
}}>{`Strategy: ${strategy}`}</Text>
|
|
{Object.keys(textByCode).map(code => {
|
|
return (
|
|
<View key={code}>
|
|
<RNTesterText
|
|
style={{
|
|
fontWeight: 'bold',
|
|
}}>{`[${code}]`}</RNTesterText>
|
|
<ExampleTextInput
|
|
multiline
|
|
lineBreakStrategyIOS={strategy}
|
|
defaultValue={textByCode[code]}
|
|
/>
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'iOS autoformatting behaviors',
|
|
render: function (): React.Node {
|
|
return (
|
|
<View>
|
|
<WithLabel label="smartInsertDelete: true | undefined">
|
|
<ExampleTextInput defaultValue="CopyAndPaste" />
|
|
</WithLabel>
|
|
<WithLabel label="smartInsertDelete: false">
|
|
<ExampleTextInput
|
|
smartInsertDelete={false}
|
|
defaultValue="CopyAndPaste"
|
|
/>
|
|
</WithLabel>
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: 'Auto scroll cursor into view when focusing',
|
|
render: function (): React.Node {
|
|
return <TextInputWithFocusButton />;
|
|
},
|
|
},
|
|
{
|
|
title: 'Keyboard shortcuts',
|
|
render: function (): React.Node {
|
|
return <KeyboardShortcutsExample />;
|
|
},
|
|
},
|
|
{
|
|
title: 'Line Break Mode',
|
|
render: function (): React.Node {
|
|
const lineBreakMode = [
|
|
'wordWrapping',
|
|
'char',
|
|
'clip',
|
|
'head',
|
|
'middle',
|
|
'tail',
|
|
];
|
|
const textByCode = {
|
|
en: 'verylongtext-dummydummydummydummydummydummydummydummydummydummydummydummy',
|
|
ko: '한글개행한글개행-한글개행한글개행한글개행한글개행한글개행한글개행한글개행한글개행한글개행한글개행',
|
|
};
|
|
return (
|
|
<View>
|
|
{lineBreakMode.map(strategy => {
|
|
return (
|
|
<View key={strategy} style={{marginBottom: 12}}>
|
|
<Text
|
|
style={{
|
|
backgroundColor: 'lightgrey',
|
|
}}>{`Mode: ${strategy}`}</Text>
|
|
{Object.keys(textByCode).map(code => {
|
|
return (
|
|
<View key={code}>
|
|
<RNTesterText
|
|
style={{
|
|
fontWeight: 'bold',
|
|
}}>{`[${code}]`}</RNTesterText>
|
|
<ExampleTextInput
|
|
lineBreakModeIOS={strategy}
|
|
defaultValue={textByCode[code]}
|
|
/>
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
},
|
|
},
|
|
];
|
|
|
|
module.exports = ({
|
|
displayName: (undefined: ?string),
|
|
title: 'TextInput',
|
|
documentationURL: 'https://reactnative.dev/docs/TextInput',
|
|
category: 'Basic',
|
|
description: 'Single and multi-line text inputs.',
|
|
examples: textInputExamples,
|
|
}: RNTesterModule);
|