import React, { useState, forwardRef } from 'react';
import { ReturnKeyTypeOptions, TextInput } from 'react-native';
import styled from 'styled-components/native';
import { themeType } from '../theme';
interface styledPropsType {
theme: themeType;
isFocused: boolean;
}
const Container = styled.View`
flex-direction: column;
width: 100%;
margin: 10px 0;
`;
const Label = styled.Text<styledPropsType>`
color: ${({ theme, isFocused }) =>
isFocused ? theme.text : theme.inputLabel};
font-size: 14px;
font-weight: 600;
margin-bottom: 6px;
`;
const StyledInput = styled.TextInput.attrs<styledPropsType>(({ theme }) => ({
placeholderTextColor: theme.inputPlaceholder,
}))<styledPropsType>`
width: 100%;
background-color: ${({ theme }) => theme.inputBackground};
color: ${({ theme }) => theme.text};
padding: 20px 10px;
font-size: 16px;
border: 1px solid
${({ theme, isFocused }) => (isFocused ? theme.text : theme.inputBorder)};
border-radius: 4px;
`;
interface props {
label?: string;
value?: string;
onChangeText?: (text: string) => void;
onSubmitEditing?: () => void;
onBlur?: () => {};
placeholder?: string;
returnKeyType?: ReturnKeyTypeOptions;
maxLength?: number;
textContentType?: string;
isPassword?: boolean;
}
const Input = forwardRef(
(
{
label,
value,
onChangeText,
onSubmitEditing,
onBlur,
placeholder,
returnKeyType,
maxLength,
isPassword,
}: props,
ref?: React.Ref<TextInput>,
) => {
const [isFocused, SetIsFocused] = useState(false);
return (
<Container>
<Label isFocused={isFocused}>{label}</Label>
<StyledInput
ref={ref}
value={value}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
onBlur={() => {
SetIsFocused(false);
onBlur;
}}
placeholder={placeholder}
returnKeyType={returnKeyType}
maxLength={maxLength}
autoCapitalize="none" // 첫글자 대문자 방지
autoCorrect={false} // 자동 고침 방지
isFocused={isFocused}
onFocus={() => SetIsFocused(true)}
secureTextEntry={isPassword} // 비밀번호 ** 표시용
/>
</Container>
);
},
);
export default Input;
https://github.com/APSL/react-native-keyboard-aware-scroll-view
// src/screens/Signup.tsx
import React, { useState, useRef } from 'react';
import styled from 'styled-components/native';
import { themeType } from '../theme';
import { Button, Image, Input } from '../components';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { TextInput } from 'react-native';
// ⭐️⭐️⭐️⭐️
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
const Conatiner = styled.View<styledPropsType>`
flex: 1;
justify-content: center;
align-items: center;
background-color: ${({ theme }) => theme.background};
padding: 50px 20px;
/* padding-top: ${({ insets }) => insets.top}px;
padding-bottom: ${({ insets }) => insets.bottom}px; */
/* padding-left: ${({ insets }) => insets.left}px;
padding-right: ${({ insets }) => insets.right}px; */
`;
interface styledPropsType {
insets: {
bottom: number;
left: number;
right: number;
top: number;
};
theme: themeType;
}
const Signup = () => {
const insets = useSafeAreaInsets();
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [passwordConfirm, setPasswordConfirm] = useState('');
const refEmail = useRef<TextInput | null>(null);
const refPassword = useRef<TextInput | null>(null);
const refPasswordConfirm = useRef<TextInput | null>(null);
const _handleSingupBtnPress = () => {
console.log('signup');
};
return (
// ⭐️⭐️⭐️⭐️
<KeyboardAwareScrollView extraScrollHeight={20} enableOnAndroid={true}>
<Conatiner insets={insets}>
<Image />
<Input
label="Name"
value={name}
placeholder="Name"
onChangeText={setName}
returnKeyType="next"
maxLength={20}
textContentType="none"
onSubmitEditing={() => refEmail.current?.focus()}
/>
<Input
ref={refEmail}
label="Email"
value={email}
placeholder="Email"
onChangeText={setEmail}
returnKeyType="next"
maxLength={20}
textContentType="none"
onSubmitEditing={() => refPassword.current?.focus()}
/>
<Input
ref={refPassword}
label="Password"
value={password}
placeholder="Password"
onChangeText={setPassword}
returnKeyType="next"
maxLength={20}
textContentType="none"
isPassword={true}
onSubmitEditing={() => refPasswordConfirm.current?.focus()}
/>
<Input
ref={refPasswordConfirm}
label="Password Confirm"
value={passwordConfirm}
placeholder="Password"
onChangeText={setPasswordConfirm}
returnKeyType="done"
maxLength={20}
textContentType="none"
isPassword={true}
onSubmitEditing={_handleSingupBtnPress}
/>
<Button title="Sign up" onPress={_handleSingupBtnPress} />
</Conatiner>
</KeyboardAwareScrollView>
);
};
export default Signup;
// src/screens/Signin
import React, { useContext, useState, useRef } from 'react';
import styled from 'styled-components/native';
import { ThemeContext } from 'styled-components';
import { themeType } from '../theme';
import { Button, Image, Input } from '../components';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StackNavigationProp } from '@react-navigation/stack';
import { AuthStackParamList } from '../navigations/Auth';
import { TextInput } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
const Conatiner = styled.View<styledPropsType>`
flex: 1;
justify-content: center;
align-items: center;
background-color: ${({ theme }) => theme.background};
padding: 0 20px;
padding-top: ${({ insets }) => insets.top}px;
padding-bottom: ${({ insets }) => insets.bottom}px;
/* padding-left: ${({ insets }) => insets.left}px;
padding-right: ${({ insets }) => insets.right}px; */
`;
interface styledPropsType {
insets: {
bottom: number;
left: number;
right: number;
top: number;
};
theme: themeType;
}
type SigninScreenNavPropsType = StackNavigationProp<
AuthStackParamList,
'Signin'
>;
type Props = {
navigation: SigninScreenNavPropsType;
};
const LOGO =
'https://firebasestorage.googleapis.com/v0/b/react-native-chat-app-d8603.appspot.com/o/logo.png?alt=media';
const Signin = ({ navigation }: Props) => {
const insets = useSafeAreaInsets();
const theme = useContext(ThemeContext);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const refPassword = useRef<TextInput | null>(null);
const _handleSinginBtnPress = () => {
console.log('signin');
};
return (
// ⭐️⭐️⭐️⭐️
<KeyboardAwareScrollView
extraScrollHeight={20}
contentContainerStyle={{ flex: 1 }}
>
<Conatiner insets={insets}>
<Image url={LOGO} />
<Input
label="Email"
value={email}
placeholder="Email"
onChangeText={setEmail}
returnKeyType="next"
maxLength={20}
textContentType="none"
onSubmitEditing={() => refPassword.current?.focus()}
/>
<Input
ref={refPassword}
label="Password"
value={password}
placeholder="Email"
onChangeText={setPassword}
returnKeyType="done"
maxLength={20}
isPassword={true}
onSubmitEditing={_handleSinginBtnPress}
/>
<Button title="Sign in" onPress={_handleSinginBtnPress} />
<Button
title="Sign up with email"
onPress={() => {
navigation.navigate('Signup');
}}
containerStyle={{ marginTop: 0, backgroundColor: 'transparent' }}
textStyle={{ color: theme.btnTitleLink, fontSize: 18 }}
/>
</Conatiner>
</KeyboardAwareScrollView>
);
};
export default Signin;