Skip to content
Open
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
Binary file added src/assets/images/arrow-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/components/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ReactNode, useCallback, useState } from 'react'
import { StyleProp, StyleSheet, TouchableOpacity, View, ViewStyle } from 'react-native'
import { Keyboard, StyleProp, StyleSheet, TouchableOpacity, View, ViewStyle } from 'react-native'
import { Text } from 'rn-base-component'
import DateTimePickerModal from 'react-native-modal-datetime-picker'
import { colors, fonts, fontSizes, metrics } from '../themes'
Expand Down Expand Up @@ -46,6 +46,7 @@ export const DatePicker: React.FC<IDatePickerProps> = ({
}, [children, placeholder, value])

const handleShowDatePicker = useCallback(() => {
Keyboard.dismiss()
setDatePickerVisible(true)
}, [])

Expand Down
110 changes: 110 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react'
import {
Image,
ImageSourcePropType,
ImageStyle,
StyleProp,
StyleSheet,
TextStyle,
TouchableOpacity,
View,
ViewStyle,
} from 'react-native'
import { Images, metrics } from '../themes'
import { ThemedText } from './ThemedText'
import { Row } from './Row'
import { router } from 'expo-router'

export interface IHeaderProp {
title?: string
leftStyle?: StyleProp<ViewStyle>
centerStyle?: StyleProp<ViewStyle>
rightStyle?: StyleProp<ViewStyle>
onGoBack?: () => void
hasBackButton?: boolean
leftView?: React.ReactNode
centerView?: React.ReactNode
rightView?: React.ReactNode
containerStyle?: StyleProp<ViewStyle>
headerIcon?: ImageSourcePropType
titleStyle?: StyleProp<TextStyle>
headerIconStyle?: StyleProp<ImageStyle>
backButtonStyle?: StyleProp<ViewStyle>
}

export const Header: React.FC<IHeaderProp> = ({
hasBackButton = true,
title,
leftStyle,
backButtonStyle,
centerStyle,
onGoBack,
leftView,
centerView,
rightView,
containerStyle,
headerIcon = Images.arrowLeft,
titleStyle,
headerIconStyle,
rightStyle,
}) => (
<Row style={[styles.headerContainer, containerStyle]}>
{hasBackButton && (
<TouchableOpacity
style={[styles.backButton, backButtonStyle]}
onPress={() => {
if (onGoBack) {
onGoBack()
} else {
router.back()
}
}}>
<Image source={headerIcon} style={[styles.backIcon, headerIconStyle]} />
</TouchableOpacity>
)}
{leftView && <View style={[styles.componentView, leftStyle]}>{leftView}</View>}

{!!title && (
<ThemedText type="label" numberOfLines={1} style={[styles.titleText, titleStyle]}>
{title}
</ThemedText>
)}
{centerView && <View style={[styles.componentView, centerStyle]}>{rightView}</View>}
{rightView && <View style={[styles.componentView, rightStyle]}>{rightView}</View>}
</Row>
)

const styles = StyleSheet.create({
headerContainer: {
alignItems: 'center',
alignSelf: 'stretch',
gap: metrics.xs,
padding: metrics.small,
},
actionsSection: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'stretch',
gap: metrics.small,
},
backButton: {
alignItems: 'center',
padding: metrics.xxs,
},
backIcon: {
width: metrics.medium,
height: metrics.medium,
aspectRatio: 1,
},
componentView: {
alignItems: 'center',
},
titleSection: {
flexDirection: 'column',
alignSelf: 'stretch',
gap: 4,
},
titleText: {
textAlign: 'center',
},
})
9 changes: 5 additions & 4 deletions src/components/Row.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { ReactElement } from 'react'
import React, { PropsWithChildren } from 'react'
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native'

interface IRowProps {
children: ReactElement
interface IRowProps extends PropsWithChildren {
style?: StyleProp<ViewStyle>
}

export const Row = ({ style, children }: IRowProps) => <View style={[styles.row, style]}>{children}</View>
export const Row: React.FC<IRowProps> = ({ style, children }) => (
<View style={[styles.row, style]}>{children}</View>
)

const styles = StyleSheet.create({
row: {
Expand Down
59 changes: 51 additions & 8 deletions src/components/ScreenContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,61 @@
import React, { PropsWithChildren } from 'react'
import { StyleSheet, View, ViewStyle, StyleProp } from 'react-native'

interface IRowProps extends PropsWithChildren {
import {
KeyboardAvoidingView,
KeyboardAvoidingViewProps,
StyleProp,
StyleSheet,
View,
ViewStyle,
} from 'react-native'
import { colors, isIOS, metrics } from '../themes'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { Header, IHeaderProp } from './Header'
interface IScreenContainerProps extends IHeaderProp {
containerStyle?: StyleProp<ViewStyle>
style?: StyleProp<ViewStyle>
full?: boolean
title?: string
noPaddingBottom?: boolean
showHeader?: boolean
keyboardAvoidingBehavior?: KeyboardAvoidingViewProps['behavior']
}

export const ScreenContainer = ({ children, style, ...rest }: IRowProps) => (
<View style={[styles.container, style]} {...rest}>
{children}
</View>
)
export const ScreenContainer = ({
full = false,
containerStyle,
children,
style,
title,
noPaddingBottom = false,
showHeader = false,
keyboardAvoidingBehavior,
...rest
}: PropsWithChildren<IScreenContainerProps>) => {
const insets = useSafeAreaInsets()
const shouldShowHeader = !!title || showHeader
return (
<View
style={[
styles.container,
!full && { paddingTop: insets.top, paddingBottom: noPaddingBottom ? metrics.zero : insets.bottom },
containerStyle,
]}>
{shouldShowHeader && <Header title={title} {...rest} />}
<KeyboardAvoidingView
behavior={keyboardAvoidingBehavior ?? (isIOS ? 'padding' : undefined)}
style={[styles.flex, style]}>
{children}
</KeyboardAvoidingView>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.backgroundPrimary,
},
flex: {
flex: 1,
},
})
3 changes: 2 additions & 1 deletion src/components/Selection.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useMemo, useRef, useState } from 'react'
import { FlatList, StyleSheet, TouchableOpacity, View } from 'react-native'
import { FlatList, Keyboard, StyleSheet, TouchableOpacity, View } from 'react-native'
import { Text, TextInput } from 'rn-base-component'
import { BottomSheet, BottomSheetMethods } from './BottomSheet'
import { colors, fonts, fontSizes, metrics } from '@/themes'
Expand Down Expand Up @@ -69,6 +69,7 @@ export const Selection = <T extends object>({
}, [children, data, getTitle, placeholder, getValue, value])

const handleOpen = useCallback(() => {
Keyboard.dismiss()
ref.current?.open()
setSearchText('')
}, [])
Expand Down
72 changes: 58 additions & 14 deletions src/components/ThemedText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ import React from 'react'
import { Text, type TextProps, StyleSheet } from 'react-native'

import { useThemeColor } from '@/hooks/useThemeColor'
import { fontSizes, fontWeights, metrics } from '@/themes'
import { colors, fonts, fontSizes, lineHeights } from '@/themes'

export type ThemedTextProps = TextProps & {
lightColor?: string
darkColor?: string
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'
type?:
| 'span'
| 'spanMedium'
| 'small'
| 'smallMedium'
| 'body'
| 'bodyMedium'
| 'title'
| 'subtitle'
| 'link'
| 'label'
}

export const ThemedText: React.FC<ThemedTextProps> = ({
style,
lightColor,
darkColor,
type = 'default',
type = 'body',
...rest
}) => {
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text')
Expand All @@ -23,11 +33,16 @@ export const ThemedText: React.FC<ThemedTextProps> = ({
<Text
style={[
{ color },
type === 'default' ? styles.default : undefined,
type === 'span' ? styles.span : undefined,
type === 'spanMedium' ? styles.spanMedium : undefined,
type === 'small' ? styles.small : undefined,
type === 'smallMedium' ? styles.smallMedium : undefined,
type === 'body' ? styles.body : undefined,
type === 'bodyMedium' ? styles.bodyMedium : undefined,
type === 'title' ? styles.title : undefined,
type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined,
type === 'subtitle' ? styles.subtitle : undefined,
type === 'link' ? styles.link : undefined,
type === 'label' ? styles.label : undefined,
style,
]}
{...rest}
Expand All @@ -36,26 +51,55 @@ export const ThemedText: React.FC<ThemedTextProps> = ({
}

const styles = StyleSheet.create({
default: {
span: {
fontSize: fontSizes.span,
fontFamily: fonts.regular,
lineHeight: lineHeights.span,
},
spanMedium: {
fontSize: fontSizes.span,
fontFamily: fonts.medium,
lineHeight: lineHeights.span,
},
small: {
fontSize: fontSizes.small,
fontFamily: fonts.regular,
lineHeight: lineHeights.small,
},
smallMedium: {
fontSize: fontSizes.small,
fontFamily: fonts.medium,
lineHeight: lineHeights.small,
},
body: {
fontSize: fontSizes.body,
lineHeight: metrics.large,
fontFamily: fonts.regular,
lineHeight: lineHeights.body,
},
defaultSemiBold: {
bodyMedium: {
fontSize: fontSizes.body,
lineHeight: metrics.large,
fontWeight: fontWeights.semiBold,
fontFamily: fonts.medium,
lineHeight: lineHeights.body,
},
title: {
fontSize: fontSizes.title,
fontWeight: fontWeights.bold,
lineHeight: metrics.xxl,
fontFamily: fonts.bold,
lineHeight: lineHeights.title,
},
subtitle: {
fontSize: fontSizes.large,
fontWeight: fontWeights.bold,
fontFamily: fonts.bold,
lineHeight: lineHeights.large,
},
link: {
lineHeight: metrics.xxl,
fontSize: fontSizes.body,
color: colors.info,
fontFamily: fonts.regular,
lineHeight: lineHeights.body,
},
label: {
fontSize: fontSizes.label,
fontFamily: fonts.medium,
lineHeight: lineHeights.label,
},
})
Loading