85 lines
2.0 KiB
TypeScript
85 lines
2.0 KiB
TypeScript
import { Search, X } from 'lucide-react-native';
|
|
import {
|
|
forwardRef,
|
|
useEffect,
|
|
useImperativeHandle,
|
|
useRef,
|
|
type ReactNode,
|
|
} from 'react';
|
|
import { Pressable, StyleSheet, TextInput } from 'react-native';
|
|
|
|
import { colors } from '@/theme/colors';
|
|
|
|
import Input, { type InputProps } from './Input';
|
|
|
|
export type SearchInputProps = Omit<InputProps, 'left' | 'right'> & {
|
|
onDebouncedChange?: (value: string) => void;
|
|
debounceMs?: number;
|
|
};
|
|
|
|
const SearchInput = forwardRef<TextInput, SearchInputProps>(function SearchInput(
|
|
{ onDebouncedChange, debounceMs = 300, value, onChangeText, ...props },
|
|
ref,
|
|
) {
|
|
const inputRef = useRef<TextInput>(null);
|
|
const valueAsString = typeof value === 'string' ? value : '';
|
|
|
|
useImperativeHandle(ref, () => inputRef.current as TextInput);
|
|
|
|
useEffect(() => {
|
|
if (!onDebouncedChange) {
|
|
return;
|
|
}
|
|
|
|
const timer = setTimeout(() => {
|
|
onDebouncedChange(valueAsString);
|
|
}, debounceMs);
|
|
|
|
return () => {
|
|
clearTimeout(timer);
|
|
};
|
|
}, [debounceMs, onDebouncedChange, valueAsString]);
|
|
|
|
const clearButton: ReactNode =
|
|
valueAsString.length > 0 ? (
|
|
<Pressable
|
|
onPress={() => {
|
|
onChangeText?.('');
|
|
inputRef.current?.clear();
|
|
inputRef.current?.focus();
|
|
}}
|
|
style={styles.clearButton}
|
|
hitSlop={8}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Vider la recherche"
|
|
>
|
|
<X color={colors.textSecondary} size={20} />
|
|
</Pressable>
|
|
) : null;
|
|
|
|
return (
|
|
<Input
|
|
ref={inputRef}
|
|
value={value}
|
|
onChangeText={onChangeText}
|
|
left={<Search color={colors.textSecondary} size={20} />}
|
|
right={clearButton}
|
|
returnKeyType="search"
|
|
autoCorrect={false}
|
|
clearButtonMode="never"
|
|
{...props}
|
|
/>
|
|
);
|
|
});
|
|
|
|
const styles = StyleSheet.create({
|
|
clearButton: {
|
|
width: 44,
|
|
height: 44,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
});
|
|
|
|
export default SearchInput;
|