Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Pressable, Text, ActivityIndicator } from 'react-native';

/**
* Button 컴포넌트
*
* **기능**
* - 클릭 이벤트(onPress) 처리
* - disabled 상태 지원
* - loading 상태 지원 (로딩 중에는 클릭 불가 및 ActivityIndicator 표시)
* - children이 문자열/숫자일 경우 Text로 감싸서 표시, 그 외 React 요소는 그대로 렌더링
*
* @example
* <Button onPress={() => console.log('클릭!')}>클릭</Button>
* <Button onPress={handleSave} disabled={isSaving}>저장</Button>
* <Button onPress={handleLoad} loading={true}>로딩 중</Button>
* <Button onPress={handleCustom}><Icon name="star" /></Button>
*
* @param onPress 클릭 이벤트 함수
* @param disabled 버튼 비활성화 여부
* @param loading 로딩 상태 여부
* @param children 버튼 내부 텍스트/숫자 또는 React 노드
*/
export const Button = ({ onPress, disabled, loading, children }: any) => {
return (
<Pressable onPress={onPress} disabled={disabled || loading}>
{loading ? (
<ActivityIndicator />
) : typeof children === 'string' || typeof children === 'number' ? (
<Text>{children}</Text>
) : (
children
)}
</Pressable>
);
};
30 changes: 30 additions & 0 deletions src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { View, Text, Pressable } from 'react-native';

/**
* Dropdown 컴포넌트
*
* 기능:
* - 옵션 리스트를 렌더링
* - 옵션 선택 시 onSelect 콜백 호출
*
* @param {Object} props
* @param {Array<string>} props.options - 드롭다운에 표시할 옵션 배열
* @param {(item: string) => void} props.onSelect - 옵션 선택 시 호출되는 함수
*
* @example
* <Dropdown
* options={['Option 1', 'Option 2', 'Option 3']}
* onSelect={(item) => console.log(item)}
* />
*/
export const Dropdown = ({ options, onSelect }: any) => {
return (
<View>
{options.map((item: any, idx: number) => (
<Pressable key={idx} onPress={() => onSelect(item)}>
<Text>{item}</Text>
</Pressable>
))}
</View>
);
};
32 changes: 32 additions & 0 deletions src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { TextInput, View, Text } from 'react-native';
import { useFormContext } from '../../contexts/FormContext';

/**
* Input 컴포넌트
*
* 기능:
* - useFormContext를 통해 form 상태와 validation 연동
* - 입력값 변경 시 handleChange 호출
* - 에러 메시지 표시
*
* @param {Object} props
* @param {string} props.name - form state에서 연결할 필드 이름
* @param {string} [props.placeholder] - 입력창 placeholder
*
* @example
* <Input name="email" placeholder="이메일 입력" />
*/
export const Input = ({ name, placeholder }: any) => {
const { values, errors, handleChange } = useFormContext();

return (
<View>
<TextInput
value={values[name]}
onChangeText={(text) => handleChange(name, text)}
placeholder={placeholder}
/>
{errors[name] && <Text>{errors[name]}</Text>}
</View>
);
};
26 changes: 26 additions & 0 deletions src/components/Loading/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { View, ActivityIndicator } from 'react-native';

interface LoadingProps {
visible: boolean;
size?: 'small' | 'large';
color?: string;
}

/**
* Loading 컴포넌트
* - visible: boolean으로 표시 여부 결정
* - size, color props로 커스터마이징 가능
*
* @example
* <Loading visible={true} />
*/
export const Loading: React.FC<LoadingProps> = ({ visible, size = 'large', color = '#007AFF' }) => {
if (!visible) return null;

return (
<View>
<ActivityIndicator size={size} color={color} />
</View>
);
};
33 changes: 33 additions & 0 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Modal as RNModal, View, TouchableWithoutFeedback } from 'react-native';

/**
* Modal 컴포넌트
*
* 기능:
* - isOpen prop으로 열림/닫힘 제어
* - onClose로 모달 닫기 처리
* - 터치 외부 영역 클릭 시 모달 닫기
*
* @param {ModalProps} props - 모달 컴포넌트 props
* @param {boolean} props.isOpen - 모달 열림 여부
* @param {() => void} props.onClose - 모달 닫기 함수
* @param {React.ReactNode} props.children - 모달 내용
*
* @example
* <Modal isOpen={true} onClose={() => setOpen(false)}>
* <Text>모달 내용</Text>
* </Modal>
*/
export const Modal = ({ isOpen, onClose, children }: any) => {
return (
<RNModal visible={isOpen} transparent onRequestClose={onClose}>
<TouchableWithoutFeedback onPress={onClose}>
<View style={{ flex: 1 }}>
<TouchableWithoutFeedback>
<View>{children}</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</RNModal>
);
};
27 changes: 27 additions & 0 deletions src/components/Skeleton/Skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { View, StyleSheet, ViewStyle } from 'react-native';

interface SkeletonProps {
width?: number | string;
height?: number | string;
}

/**
* Skeleton 컴포넌트
* - 로딩 화면용 박스 UI
* - width, height props로 재사용 가능
*
* @example
* <Skeleton width={100} height={20} />
* <Skeleton width={'80%'} height={15} />
*/
export const Skeleton: React.FC<SkeletonProps> = ({ width = '100%', height = 20 }) => {
return <View style={[styles.skeleton, { width, height } as ViewStyle]} />;
};

const styles = StyleSheet.create({
skeleton: {
backgroundColor: '#E0E0E0',
borderRadius: 8,
},
});
1 change: 0 additions & 1 deletion src/components/common/Button.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/common/Input.tsx

This file was deleted.

Loading