expo-popcore-app/components/SearchBar.tsx

185 lines
4.9 KiB
TypeScript

import { useRef, useEffect } from 'react'
import {
View,
Text,
StyleSheet,
TextInput,
Pressable,
} from 'react-native'
import { useTranslation } from 'react-i18next'
import { LeftArrowIcon, CloseIcon } from '@/components/icon'
interface SearchBarProps {
searchText: string
onSearchTextChange: (text: string) => void
onSearch: (text: string) => void
onBack: () => void
placeholder?: string
autoFocus?: boolean
inputRef?: React.RefObject<TextInput | null>
showBackButton?: boolean
showSearchButton?: boolean
readOnly?: boolean
onInputPress?: () => void
onClearPress?: () => void
marginBottom?: number
}
export default function SearchBar({
searchText,
onSearchTextChange,
onSearch,
onBack,
placeholder,
autoFocus = false,
inputRef: externalInputRef,
showBackButton = true,
showSearchButton = true,
readOnly = false,
onInputPress,
onClearPress,
marginBottom = 20,
}: SearchBarProps) {
const { t } = useTranslation()
const internalInputRef = useRef<TextInput>(null)
const inputRef = externalInputRef || internalInputRef
const defaultPlaceholder = placeholder || t('searchBar.placeholder')
useEffect(() => {
if (autoFocus) {
const timer = setTimeout(() => {
inputRef.current?.focus()
}, 100)
return () => clearTimeout(timer)
}
}, [autoFocus, inputRef])
const handleClear = () => {
if (onClearPress) {
onClearPress()
} else {
onSearchTextChange('')
}
}
const inputContainer = (
<>
<TextInput
ref={inputRef}
style={styles.searchInput}
value={searchText}
onChangeText={readOnly ? undefined : onSearchTextChange}
placeholder={defaultPlaceholder}
placeholderTextColor="#ABABAB"
underlineColorAndroid="transparent"
selectionColor="#F5F5F5"
autoCorrect={false}
autoCapitalize="none"
editable={!readOnly}
pointerEvents={readOnly ? 'none' : 'auto'}
onSubmitEditing={() => {
if (searchText.trim()) {
onSearch(searchText.trim())
}
}}
/>
{searchText.length > 0 && (
<Pressable
onPress={(e) => {
if (readOnly && onInputPress) {
e.stopPropagation()
}
handleClear()
}}
style={styles.clearButton}
>
<CloseIcon />
</Pressable>
)}
</>
)
return (
<View style={[styles.topBar, { marginBottom }]}>
{showBackButton && (
<Pressable onPress={onBack}>
<LeftArrowIcon />
</Pressable>
)}
{readOnly && onInputPress ? (
<Pressable
style={styles.searchInputContainer}
onPress={onInputPress}
>
{inputContainer}
</Pressable>
) : (
<View style={styles.searchInputContainer}>
{inputContainer}
</View>
)}
{showSearchButton && (
<Pressable
style={styles.searchButton}
onPress={() => {
if (searchText.trim()) {
onSearch(searchText.trim())
}
}}
>
<Text style={styles.searchButtonText}>{t('searchBar.button')}</Text>
</Pressable>
)}
</View>
)
}
const styles = StyleSheet.create({
topBar: {
height: 44,
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 12,
marginTop: 8,
marginBottom: 20,
},
searchInputContainer: {
flex: 1,
marginLeft: 4,
marginRight: 12,
position: 'relative',
height: 40,
},
searchInput: {
flex: 1,
color: '#F5F5F5',
fontSize: 14,
height: 40,
paddingVertical: 8,
paddingLeft: 12,
paddingRight: 36,
borderRadius: 100,
backgroundColor: '#16181B',
},
clearButton: {
position: 'absolute',
right: 8,
top: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
padding: 4,
},
searchButton: {
paddingHorizontal: 0,
paddingVertical: 8,
},
searchButtonText: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '400',
},
})