From c8b87779a6f61d19f2cef5c186c101f7479d0e99 Mon Sep 17 00:00:00 2001 From: GusttavoCastilho Date: Mon, 23 Jun 2025 22:33:56 -0300 Subject: [PATCH] feat: add clear (X) button and onClear handler --- .../__tests__/AutocompleteInput.spec.tsx | 24 ++++++++++ .../react-native-autocomplete-input/index.tsx | 44 +++++++++++++++++-- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/packages/react-native-autocomplete-input/__tests__/AutocompleteInput.spec.tsx b/packages/react-native-autocomplete-input/__tests__/AutocompleteInput.spec.tsx index 2eefeff..10cb02f 100644 --- a/packages/react-native-autocomplete-input/__tests__/AutocompleteInput.spec.tsx +++ b/packages/react-native-autocomplete-input/__tests__/AutocompleteInput.spec.tsx @@ -146,4 +146,28 @@ describe('', () => { await userEvent.type(input, ' New Hope'); expect(input).toHaveDisplayValue('A New Hope'); }); + + it('should render clear button when value is not empty', () => { + render( {}} />); + + const clearButton = screen.getByLabelText('Clear text'); + expect(clearButton).toBeOnTheScreen(); + }); + + it('should not render clear button when value is empty', () => { + render(); + + const clearButton = screen.queryByLabelText('Clear text'); + expect(clearButton).not.toBeOnTheScreen(); + }); + + it('should call onClear when clear button is pressed', async () => { + const onClear = jest.fn(); + render(); + + const clearButton = screen.getByLabelText('Clear text'); + + await userEvent.press(clearButton); + expect(onClear).toHaveBeenCalled(); + }); }); diff --git a/packages/react-native-autocomplete-input/index.tsx b/packages/react-native-autocomplete-input/index.tsx index df85e5b..4114231 100644 --- a/packages/react-native-autocomplete-input/index.tsx +++ b/packages/react-native-autocomplete-input/index.tsx @@ -6,7 +6,7 @@ import type { ViewStyle, ListRenderItemInfo, } from 'react-native'; -import { FlatList, Platform, StyleSheet, Text, TextInput, View } from 'react-native'; +import { FlatList, Platform, StyleSheet, Text, TextInput, View, TouchableOpacity } from 'react-native'; export type AutocompleteInputProps = TextInputProps & { containerStyle?: StyleProp; @@ -18,6 +18,7 @@ export type AutocompleteInputProps = TextInputProps & { renderTextInput?: React.FC; flatListProps?: Partial, 'data'>>; data: readonly Item[]; + onClear?: () => void; }; function defaultKeyExtractor(_: unknown, index: number): string { @@ -44,6 +45,8 @@ export const AutocompleteInput = React.forwardRef(function AutocompleteInputComp renderTextInput: customRenderTextInput = (props) => , flatListProps, style, + onClear, + value, ...textInputProps } = props; @@ -60,13 +63,30 @@ export const AutocompleteInput = React.forwardRef(function AutocompleteInputComp } function renderTextInput(): React.ReactNode { - const renderProps = { + const renderProps: TextInputProps = { ...textInputProps, style: [styles.input, style], ...(ref && { ref }), }; + if (typeof value !== 'undefined') { + renderProps.value = value; + } - return customRenderTextInput(renderProps); + return ( + + {customRenderTextInput(renderProps)} + {onClear && value && value.length > 0 && ( + + × + + )} + + ); } const showResults = data.length > 0; @@ -145,6 +165,24 @@ const styles = StyleSheet.create({ ios: iosStyles, default: iosStyles, }), + inputRow: { + flexDirection: 'row', + alignItems: 'center', + position: 'relative', + }, + clearButton: { + position: 'absolute', + right: 0, + height: '100%', + justifyContent: 'center', + alignItems: 'center', + paddingHorizontal: 10, + zIndex: 2, + }, + clearButtonText: { + fontSize: 18, + color: '#888', + }, }); export default AutocompleteInput;