Initial commit: expo-popcore-app
This commit is contained in:
184
components/SearchBar.tsx
Normal file
184
components/SearchBar.tsx
Normal file
@@ -0,0 +1,184 @@
|
||||
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',
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user