diff options
Diffstat (limited to 'apps/mobile/components/ui/SearchInput/SearchInput.tsx')
| -rw-r--r-- | apps/mobile/components/ui/SearchInput/SearchInput.tsx | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/apps/mobile/components/ui/SearchInput/SearchInput.tsx b/apps/mobile/components/ui/SearchInput/SearchInput.tsx new file mode 100644 index 00000000..7e816ab6 --- /dev/null +++ b/apps/mobile/components/ui/SearchInput/SearchInput.tsx @@ -0,0 +1,114 @@ +import * as React from "react"; +import { Pressable, TextInput, View } from "react-native"; +import Animated, { FadeIn, FadeOut } from "react-native-reanimated"; +import { TailwindResolver } from "@/components/TailwindResolver"; +import { Button } from "@/components/ui/Button"; +import { useColorScheme } from "@/lib/useColorScheme"; +import { cn } from "@/lib/utils"; +import { useAugmentedRef, useControllableState } from "@rn-primitives/hooks"; +import { Icon } from "@roninoss/icons"; + +import type { SearchInputProps } from "./types"; + +const SearchInput = React.forwardRef< + React.ElementRef<typeof TextInput>, + SearchInputProps +>( + ( + { + value: valueProp, + onChangeText: onChangeTextProp, + placeholder = "Search...", + containerClassName, + iconContainerClassName, + className, + onCancel, + ...props + }, + ref, + ) => { + const { colors } = useColorScheme(); + const inputRef = useAugmentedRef({ ref, methods: { focus, blur, clear } }); + const [value = "", onChangeText] = useControllableState({ + prop: valueProp, + defaultProp: valueProp ?? "", + onChange: onChangeTextProp, + }); + + function focus() { + inputRef.current?.focus(); + } + + function blur() { + inputRef.current?.blur(); + } + + function clear() { + onCancel?.(); + onChangeText(""); + } + + return ( + <Button + variant="plain" + className={cn( + "android:gap-0 android:h-14 flex-row items-center rounded-full bg-card px-2", + containerClassName, + )} + onPress={focus} + > + <View + className={cn("p-2", iconContainerClassName)} + pointerEvents="none" + > + <TailwindResolver + className="text-muted" + comp={(styles) => ( + <Icon + color={styles?.color?.toString()} + name="magnify" + size={24} + /> + )} + /> + </View> + + <View className="flex-1" pointerEvents="none"> + <TextInput + ref={inputRef} + placeholder={placeholder} + className={cn( + "flex-1 rounded-r-full p-2 text-[17px] text-foreground placeholder:text-muted", + className, + )} + placeholderTextColor={colors.foreground} + value={value} + onChangeText={onChangeText} + role="searchbox" + {...props} + /> + </View> + {!!value && ( + <Animated.View entering={FadeIn} exiting={FadeOut.duration(150)}> + <Pressable className="p-2" onPress={clear}> + <TailwindResolver + className="text-muted" + comp={(styles) => ( + <Icon + name="close" + size={24} + color={styles?.color?.toString()} + /> + )} + /> + </Pressable> + </Animated.View> + )} + </Button> + ); + }, +); + +SearchInput.displayName = "SearchInput"; + +export { SearchInput }; |
