Skip to content

Commit dfbb2ae

Browse files
committed
fix: textinput handlefocus and styles
1 parent f7f3532 commit dfbb2ae

File tree

19 files changed

+1228
-215
lines changed

19 files changed

+1228
-215
lines changed

.cursor/rules/testing-guidelines.mdc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ alwaysApply: true
2626
```typescript
2727
import React from 'react'
2828
import {render, fireEvent} from '@testing-library/react-native'
29-
import {Button} from '../components/Button'
29+
import {ButtonPrimary} from '../components/Button'
3030
import {BaseProvider} from '../core/BaseProvider'
3131

3232
const renderWithProvider = (component: React.ReactElement) => {
@@ -55,9 +55,9 @@ describe('Button Component', () => {
5555

5656
it('applies correct styles for variants', () => {
5757
const {getByTestId} = renderWithProvider(
58-
<Button variant="primary" testID="primary-button">Primary</Button>
58+
<ButtonPrimary testID="primary-button">Primary</ButtonPrimary>
5959
)
60-
60+
6161
const button = getByTestId('primary-button')
6262
// Test styling expectations
6363
})

example/app/_layout.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
import { Stack } from 'expo-router'
1+
import { ScreenProps, Stack } from 'expo-router'
22
import { StatusBar } from 'expo-status-bar'
33
import 'react-native-reanimated'
44

55
import React from 'react'
66
import { BaseProvider } from 'rn-base-component'
77

8+
const baseHeaderOptions: ScreenProps['options']
9+
= {
10+
headerShown: true,
11+
headerBackTitle: 'Back',
12+
headerStyle: {
13+
backgroundColor: '#f8f9fa',
14+
},
15+
headerTintColor: '#1a1a1a',
16+
headerTitleStyle: {
17+
fontWeight: 'bold',
18+
fontSize: 18,
19+
},
20+
}
821

922
export default function RootLayout() {
23+
1024
return (
1125
<BaseProvider>
1226
<Stack>
@@ -20,16 +34,14 @@ export default function RootLayout() {
2034
name="code-input"
2135
options={{
2236
title: 'CodeInput Component',
23-
headerShown: true,
24-
headerBackTitle: 'Back',
25-
headerStyle: {
26-
backgroundColor: '#f8f9fa',
27-
},
28-
headerTintColor: '#1a1a1a',
29-
headerTitleStyle: {
30-
fontWeight: 'bold',
31-
fontSize: 18,
32-
},
37+
...baseHeaderOptions,
38+
}}
39+
/>
40+
<Stack.Screen
41+
name="text-input"
42+
options={{
43+
title: 'TextInput Component',
44+
...baseHeaderOptions,
3345
}}
3446
/>
3547
</Stack>

example/app/text-input.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React from 'react'
2+
import { TextInputDemo } from '@/components/TextInputDemo'
3+
4+
const TextInputDemoScreen = () => {
5+
return <TextInputDemo />
6+
}
7+
8+
export default TextInputDemoScreen
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React, { useState } from 'react'
2+
import { Text, View } from 'react-native'
3+
import { TextInput } from 'rn-base-component'
4+
import { demoStyles } from './styles'
5+
6+
export const BasicExamples = () => {
7+
const [name, setName] = useState('')
8+
const [email, setEmail] = useState('')
9+
const [phone, setPhone] = useState('')
10+
11+
return (
12+
<View style={demoStyles.section}>
13+
<Text style={demoStyles.sectionTitle}>📝 Basic Examples</Text>
14+
15+
<View style={demoStyles.example}>
16+
<Text style={demoStyles.exampleTitle}>Default TextInput</Text>
17+
<TextInput
18+
label="Full Name"
19+
placeholder="Enter your full name"
20+
value={name}
21+
onChangeText={setName}
22+
/>
23+
</View>
24+
25+
<View style={demoStyles.example}>
26+
<Text style={demoStyles.exampleTitle}>Required Field with Label</Text>
27+
<TextInput
28+
label="Email Address"
29+
placeholder="Enter your email"
30+
value={email}
31+
onChangeText={setEmail}
32+
isRequire
33+
keyboardType="email-address"
34+
autoCapitalize="none"
35+
/>
36+
</View>
37+
38+
<View style={demoStyles.example}>
39+
<Text style={demoStyles.exampleTitle}>With Placeholder and Keyboard Type</Text>
40+
<TextInput
41+
label="Phone Number"
42+
placeholder="(123) 456-7890"
43+
value={phone}
44+
onChangeText={setPhone}
45+
keyboardType="phone-pad"
46+
/>
47+
</View>
48+
49+
<View style={demoStyles.example}>
50+
<Text style={demoStyles.exampleTitle}>Password Input</Text>
51+
<TextInput
52+
label="Password"
53+
placeholder="Enter your password"
54+
secureTextEntry
55+
isRequire
56+
/>
57+
</View>
58+
</View>
59+
)
60+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import React from 'react'
2+
import { Text, View } from 'react-native'
3+
import { TextInput } from 'rn-base-component'
4+
import { demoStyles } from './styles'
5+
6+
export const DisabledState = () => {
7+
return (
8+
<View style={demoStyles.section}>
9+
<Text style={demoStyles.sectionTitle}>🚫 Disabled States</Text>
10+
<Text style={demoStyles.sectionDescription}>
11+
TextInput in disabled state for read-only scenarios
12+
</Text>
13+
14+
<View style={demoStyles.example}>
15+
<Text style={demoStyles.exampleTitle}>Disabled Default Input</Text>
16+
<TextInput
17+
label="Disabled Field"
18+
placeholder="This input is disabled"
19+
editable={false}
20+
value="This field is read-only"
21+
/>
22+
</View>
23+
24+
<View style={demoStyles.example}>
25+
<Text style={demoStyles.exampleTitle}>Disabled Outlined Input</Text>
26+
<TextInput.Outlined
27+
label="Read-only Email"
28+
placeholder="user@example.com"
29+
editable={false}
30+
value="user@example.com"
31+
/>
32+
</View>
33+
34+
<View style={demoStyles.example}>
35+
<Text style={demoStyles.exampleTitle}>Disabled Flat Input</Text>
36+
<TextInput.Flat
37+
label="Read-only Name"
38+
placeholder="John Doe"
39+
editable={false}
40+
value="John Doe"
41+
/>
42+
</View>
43+
44+
<View style={demoStyles.example}>
45+
<Text style={demoStyles.exampleTitle}>Disabled with Required Indicator</Text>
46+
<TextInput
47+
label="Required but Disabled"
48+
placeholder="This is required but disabled"
49+
isRequire
50+
editable={false}
51+
value="Pre-filled value"
52+
/>
53+
</View>
54+
55+
<View style={demoStyles.example}>
56+
<Text style={demoStyles.exampleTitle}>Disabled with Icons</Text>
57+
<TextInput
58+
label="Contact Info"
59+
placeholder="Contact information"
60+
editable={false}
61+
value="+1 (555) 123-4567"
62+
leftComponent={
63+
<View style={{ paddingHorizontal: 8 }}>
64+
<Text style={{ fontSize: 16 }}>📞</Text>
65+
</View>
66+
}
67+
rightComponent={
68+
<View style={{ paddingHorizontal: 8 }}>
69+
<Text style={{ fontSize: 16 }}></Text>
70+
</View>
71+
}
72+
/>
73+
</View>
74+
75+
<View style={demoStyles.example}>
76+
<Text style={demoStyles.exampleTitle}>Disabled Multiline Input</Text>
77+
<TextInput
78+
label="Read-only Description"
79+
placeholder="Description"
80+
editable={false}
81+
multiline
82+
numberOfLines={3}
83+
value="This is a multi-line read-only text field that contains some example content to demonstrate how disabled multiline inputs appear in the interface."
84+
/>
85+
</View>
86+
87+
<View style={demoStyles.example}>
88+
<Text style={demoStyles.exampleTitle}>Comparison: Enabled vs Disabled</Text>
89+
<View style={{ gap: 12 }}>
90+
<TextInput
91+
label="Enabled Input"
92+
placeholder="You can type here"
93+
value=""
94+
/>
95+
96+
<TextInput
97+
label="Disabled Input"
98+
placeholder="You cannot type here"
99+
editable={false}
100+
value="Disabled content"
101+
/>
102+
</View>
103+
</View>
104+
</View>
105+
)
106+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import React, { useState } from 'react'
2+
import { Text, TouchableOpacity, View } from 'react-native'
3+
import { TextInput } from 'rn-base-component'
4+
import { demoStyles } from './styles'
5+
6+
export const IconsAndComponents = () => {
7+
const [searchText, setSearchText] = useState('')
8+
const [phoneNumber, setPhoneNumber] = useState('')
9+
const [isPasswordVisible, setIsPasswordVisible] = useState(false)
10+
11+
const SearchIcon = () => (
12+
<View style={{ paddingHorizontal: 8 }}>
13+
<Text style={{ fontSize: 16 }}>🔍</Text>
14+
</View>
15+
)
16+
17+
const PhoneIcon = () => (
18+
<View style={{ paddingHorizontal: 8 }}>
19+
<Text style={{ fontSize: 16 }}>📞</Text>
20+
</View>
21+
)
22+
23+
const EyeIcon = ({ visible }: { visible: boolean }) => (
24+
<TouchableOpacity
25+
onPress={() => setIsPasswordVisible(!visible)}
26+
style={{ paddingHorizontal: 8 }}
27+
>
28+
<Text style={{ fontSize: 16 }}>{visible ? '👁️' : '🙈'}</Text>
29+
</TouchableOpacity>
30+
)
31+
32+
const ClearButton = ({ onClear }: { onClear: () => void }) => (
33+
<TouchableOpacity onPress={onClear} style={{ paddingHorizontal: 8 }}>
34+
<Text style={{ fontSize: 16 }}></Text>
35+
</TouchableOpacity>
36+
)
37+
38+
const UnitLabel = ({ unit }: { unit: string }) => (
39+
<View style={{ paddingHorizontal: 8, backgroundColor: '#f0f0f0', borderRadius: 4, paddingVertical: 2 }}>
40+
<Text style={{ fontSize: 12, color: '#666' }}>{unit}</Text>
41+
</View>
42+
)
43+
44+
return (
45+
<View style={demoStyles.section}>
46+
<Text style={demoStyles.sectionTitle}>🎨 Icons and Components</Text>
47+
<Text style={demoStyles.sectionDescription}>
48+
TextInput with left and right components for enhanced UX
49+
</Text>
50+
51+
<View style={demoStyles.example}>
52+
<Text style={demoStyles.exampleTitle}>Search Input with Icon</Text>
53+
<TextInput
54+
label="Search"
55+
placeholder="Search for something..."
56+
value={searchText}
57+
onChangeText={setSearchText}
58+
leftComponent={<SearchIcon />}
59+
rightComponent={
60+
searchText ? <ClearButton onClear={() => setSearchText('')} /> : undefined
61+
}
62+
/>
63+
</View>
64+
65+
<View style={demoStyles.example}>
66+
<Text style={demoStyles.exampleTitle}>Phone Number Input</Text>
67+
<TextInput
68+
label="Phone Number"
69+
placeholder="(123) 456-7890"
70+
value={phoneNumber}
71+
onChangeText={setPhoneNumber}
72+
keyboardType="phone-pad"
73+
leftComponent={<PhoneIcon />}
74+
/>
75+
</View>
76+
77+
<View style={demoStyles.example}>
78+
<Text style={demoStyles.exampleTitle}>Password with Visibility Toggle</Text>
79+
<TextInput
80+
label="Password"
81+
placeholder="Enter your password"
82+
secureTextEntry={!isPasswordVisible}
83+
rightComponent={<EyeIcon visible={isPasswordVisible} />}
84+
/>
85+
</View>
86+
87+
<View style={demoStyles.example}>
88+
<Text style={demoStyles.exampleTitle}>Weight Input with Unit</Text>
89+
<TextInput
90+
label="Weight"
91+
placeholder="Enter weight"
92+
keyboardType="numeric"
93+
rightComponent={<UnitLabel unit="kg" />}
94+
/>
95+
</View>
96+
97+
<View style={demoStyles.example}>
98+
<Text style={demoStyles.exampleTitle}>Price Input with Currency</Text>
99+
<TextInput
100+
label="Price"
101+
placeholder="0.00"
102+
keyboardType="numeric"
103+
leftComponent={<UnitLabel unit="$" />}
104+
/>
105+
</View>
106+
107+
<View style={demoStyles.example}>
108+
<Text style={demoStyles.exampleTitle}>Complex Example - Email with Actions</Text>
109+
<TextInput
110+
label="Email Address"
111+
placeholder="your@email.com"
112+
keyboardType="email-address"
113+
autoCapitalize="none"
114+
leftComponent={
115+
<View style={{ paddingHorizontal: 8 }}>
116+
<Text style={{ fontSize: 16 }}>✉️</Text>
117+
</View>
118+
}
119+
rightComponent={
120+
<View style={{ flexDirection: 'row' }}>
121+
<TouchableOpacity style={{ paddingHorizontal: 8 }}>
122+
<Text style={{ fontSize: 16 }}>📎</Text>
123+
</TouchableOpacity>
124+
<TouchableOpacity style={{ paddingHorizontal: 8 }}>
125+
<Text style={{ fontSize: 16 }}>⚙️</Text>
126+
</TouchableOpacity>
127+
</View>
128+
}
129+
/>
130+
</View>
131+
</View>
132+
)
133+
}

0 commit comments

Comments
 (0)