Skip to content

Commit d0cffca

Browse files
committed
feat: text field component introduction
1 parent 7e6e009 commit d0cffca

23 files changed

Lines changed: 2000 additions & 2 deletions

docs/docusaurus.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ const config = {
170170
TextInputAffix: 'TextInput/Adornment/TextInputAffix',
171171
TextInputIcon: 'TextInput/Adornment/TextInputIcon',
172172
},
173+
TextField: 'TextField/TextField',
173174
ToggleButton: {
174175
ToggleButton: 'ToggleButton/ToggleButton',
175176
ToggleButtonGroup: 'ToggleButton/ToggleButtonGroup',
@@ -206,6 +207,8 @@ const config = {
206207
}
207208

208209
const customUrls = {
210+
TextField: 'src/components/TextField/TextField.tsx',
211+
TextInput: 'src/components/TextInput/TextInput.tsx',
209212
TextInputAffix:
210213
'src/components/TextInput/Adornment/TextInputAffix.tsx',
211214
TextInputIcon:

docs/src/components/PropTable.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,23 @@ const typeDefinitions = {
1111
'https://github.com/callstack/react-native-paper/blob/main/src/components/Icon.tsx#L16',
1212
ThemeProp:
1313
'https://callstack.github.io/react-native-paper/docs/guides/theming#theme-properties',
14+
'ComponentType<TextFieldAccessoryProps>':
15+
'https://github.com/callstack/react-native-paper/blob/main/src/components/TextField/TextField.tsx#L21',
1416
AccessibilityState:
1517
'https://reactnative.dev/docs/accessibility#accessibilitystate',
1618
'StyleProp<ViewStyle>': 'https://reactnative.dev/docs/view-style-props',
1719
'StyleProp<TextStyle>': 'https://reactnative.dev/docs/text-style-props',
20+
TextProps: 'https://reactnative.dev/docs/text#props',
1821
};
1922

2023
const renderBadge = (annotation: string) => {
2124
const [annotType, ...annotLabel] = annotation.split(' ');
2225

2326
// eslint-disable-next-line prettier/prettier
24-
return `<span class="badge badge-${annotType.replace('@', '')} ">${annotLabel.join(' ')}</span>`;
27+
return `<span class="badge badge-${annotType.replace(
28+
'@',
29+
''
30+
)} ">${annotLabel.join(' ')}</span>`;
2531
};
2632

2733
export default function PropTable({
@@ -56,7 +62,9 @@ export default function PropTable({
5662
if (line.includes('@')) {
5763
const annotIndex = line.indexOf('@');
5864
// eslint-disable-next-line prettier/prettier
59-
return `${line.substr(0, annotIndex)} ${renderBadge(line.substr(annotIndex))}`;
65+
return `${line.substr(0, annotIndex)} ${renderBadge(
66+
line.substr(annotIndex)
67+
)}`;
6068
} else {
6169
return line;
6270
}

docs/src/data/screenshots.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ const screenshots = {
146146
'iOS (disabled)': 'screenshots/switch-disabled.ios.png',
147147
},
148148
Text: 'screenshots/typography.png',
149+
TextField: {
150+
filled: 'screenshots/text-field-filled.png',
151+
outlined: 'screenshots/text-field-outlined.png',
152+
},
149153
TextInput: {
150154
'flat (focused)': 'screenshots/textinput-flat.focused.png',
151155
'flat (disabled)': 'screenshots/textinput-flat.disabled.png',
39.1 KB
Loading
24.6 KB
Loading

example/src/ExampleList.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import SwitchExample from './Examples/SwitchExample';
4343
import TeamDetails from './Examples/TeamDetails';
4444
import TeamsList from './Examples/TeamsList';
4545
import TextExample from './Examples/TextExample';
46+
import TextFieldExample from './Examples/TextFieldExample';
4647
import TextInputExample from './Examples/TextInputExample';
4748
import ThemeExample from './Examples/ThemeExample';
4849
import ThemingWithReactNavigation from './Examples/ThemingWithReactNavigation';
@@ -89,6 +90,7 @@ export const mainExamples: Record<
8990
surface: SurfaceExample,
9091
switch: SwitchExample,
9192
text: TextExample,
93+
textField: TextFieldExample,
9294
textInput: TextInputExample,
9395
toggleButton: ToggleButtonExample,
9496
tooltipExample: TooltipExample,
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import * as React from 'react';
2+
import { Pressable, StyleSheet, View } from 'react-native';
3+
4+
import {
5+
Icon,
6+
List,
7+
TextField,
8+
type TextFieldAccessoryProps,
9+
} from 'react-native-paper';
10+
11+
import { useExampleTheme } from '../hooks/useExampleTheme';
12+
import ScreenWrapper from '../ScreenWrapper';
13+
14+
const TextFieldExample = () => {
15+
const { colors } = useExampleTheme();
16+
const iconMuted = colors.onSurfaceVariant;
17+
const [searchQuery, setSearchQuery] = React.useState('');
18+
const [email, setEmail] = React.useState('');
19+
const [filledPassword, setFilledPassword] = React.useState('');
20+
const [filledNotes, setFilledNotes] = React.useState('');
21+
const [outlinedSearchQuery, setOutlinedSearchQuery] = React.useState('');
22+
const [outlinedText, setOutlinedText] = React.useState('');
23+
const [outlinedPassword, setOutlinedPassword] = React.useState('');
24+
const [outlinedNotes, setOutlinedNotes] = React.useState('');
25+
const [errorField, setErrorField] = React.useState('invalid@');
26+
27+
const ClearFilledSearchAccessory = ({
28+
style,
29+
editable,
30+
}: TextFieldAccessoryProps) => {
31+
return (
32+
<Pressable
33+
style={style}
34+
disabled={!editable}
35+
onPress={() => setSearchQuery('')}
36+
accessibilityRole="button"
37+
accessibilityLabel="Clear text"
38+
>
39+
<Icon source="close" size={24} color={iconMuted} />
40+
</Pressable>
41+
);
42+
};
43+
44+
const ClearOutlinedSearchAccessory = ({
45+
style,
46+
editable,
47+
}: TextFieldAccessoryProps) => {
48+
return (
49+
<Pressable
50+
style={style}
51+
disabled={!editable}
52+
onPress={() => setOutlinedSearchQuery('')}
53+
accessibilityRole="button"
54+
accessibilityLabel="Clear text"
55+
>
56+
<Icon source="close" size={24} color={iconMuted} />
57+
</Pressable>
58+
);
59+
};
60+
61+
const SearchLeadingAccessory = ({ style }: TextFieldAccessoryProps) => {
62+
return (
63+
<View style={style}>
64+
<Icon source="magnify" size={24} color={iconMuted} />
65+
</View>
66+
);
67+
};
68+
69+
return (
70+
<ScreenWrapper contentContainerStyle={styles.container}>
71+
<List.Section title="Filled" style={styles.section}>
72+
<TextField
73+
variant="filled"
74+
label="With accessories"
75+
value={searchQuery}
76+
onChangeText={setSearchQuery}
77+
LeftAccessory={SearchLeadingAccessory}
78+
RightAccessory={ClearFilledSearchAccessory}
79+
pressableStyle={styles.field}
80+
/>
81+
<TextField
82+
variant="filled"
83+
label="Without accessories"
84+
value={email}
85+
onChangeText={setEmail}
86+
keyboardType="email-address"
87+
autoCapitalize="none"
88+
autoCorrect={false}
89+
pressableStyle={styles.field}
90+
/>
91+
<TextField
92+
variant="filled"
93+
label="Email (error)"
94+
helper="Enter a valid email address."
95+
placeholder="name@example.com"
96+
status="error"
97+
value={errorField}
98+
onChangeText={setErrorField}
99+
keyboardType="email-address"
100+
autoCapitalize="none"
101+
pressableStyle={styles.field}
102+
/>
103+
<TextField
104+
variant="filled"
105+
label="Account (disabled)"
106+
helper="Contact support to make changes."
107+
value="read-only@example.com"
108+
editable={false}
109+
pressableStyle={styles.field}
110+
/>
111+
<TextField
112+
variant="filled"
113+
label="Notes (multiline)"
114+
helper="Optional details for your request."
115+
placeholder="Add a note…"
116+
value={filledNotes}
117+
onChangeText={setFilledNotes}
118+
multiline
119+
pressableStyle={styles.field}
120+
/>
121+
<TextField
122+
variant="filled"
123+
label="Password"
124+
helper="At least 8 characters."
125+
placeholder="••••••••"
126+
value={filledPassword}
127+
onChangeText={setFilledPassword}
128+
secureTextEntry
129+
textContentType="password"
130+
pressableStyle={styles.field}
131+
/>
132+
</List.Section>
133+
134+
<List.Section title="Outlined" style={styles.section}>
135+
<TextField
136+
variant="outlined"
137+
label="With accessories"
138+
value={outlinedSearchQuery}
139+
onChangeText={setOutlinedSearchQuery}
140+
LeftAccessory={SearchLeadingAccessory}
141+
RightAccessory={ClearOutlinedSearchAccessory}
142+
pressableStyle={styles.field}
143+
/>
144+
<TextField
145+
variant="outlined"
146+
label="Without accessories"
147+
value={outlinedText}
148+
onChangeText={setOutlinedText}
149+
pressableStyle={styles.field}
150+
/>
151+
<TextField
152+
variant="outlined"
153+
label="Email (error)"
154+
helper="Enter a valid email address."
155+
placeholder="name@example.com"
156+
status="error"
157+
value={errorField}
158+
onChangeText={setErrorField}
159+
keyboardType="email-address"
160+
autoCapitalize="none"
161+
pressableStyle={styles.field}
162+
/>
163+
<TextField
164+
variant="outlined"
165+
label="Disabled via status"
166+
helper="This field cannot be edited."
167+
value="Disabled"
168+
status="disabled"
169+
pressableStyle={styles.field}
170+
/>
171+
<TextField
172+
variant="outlined"
173+
label="Notes (multiline)"
174+
helper="Optional details for your request."
175+
placeholder="Add a note…"
176+
value={outlinedNotes}
177+
onChangeText={setOutlinedNotes}
178+
multiline
179+
pressableStyle={styles.field}
180+
/>
181+
<TextField
182+
variant="outlined"
183+
label="Password"
184+
helper="At least 8 characters."
185+
placeholder="••••••••"
186+
value={outlinedPassword}
187+
onChangeText={setOutlinedPassword}
188+
secureTextEntry
189+
textContentType="password"
190+
pressableStyle={styles.field}
191+
/>
192+
</List.Section>
193+
</ScreenWrapper>
194+
);
195+
};
196+
197+
TextFieldExample.title = 'TextField';
198+
199+
const styles = StyleSheet.create({
200+
container: {
201+
paddingHorizontal: 16,
202+
paddingVertical: 8,
203+
},
204+
field: {},
205+
section: {
206+
gap: 16,
207+
},
208+
});
209+
210+
export default TextFieldExample;

0 commit comments

Comments
 (0)