This repository has been archived on 2026-08-11. You can view files and clone it, but cannot push or open issues or pull requests.
Gishen-Mob/components/ui/SearchField.tsx
kirukib 7310a349c5 Add Gishen mobile app with complete demo shopping and care flows.
Ship Expo Router screens, seeded stores, and polished UX so auth, shop, checkout, prescriptions, loyalty, family, and account processes work end-to-end offline.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-07 01:21:32 +03:00

120 lines
3.0 KiB
TypeScript

import { useState, type ReactNode } from "react";
import { Ionicons } from "@expo/vector-icons";
import {
Pressable,
TextInput,
View,
type TextInputProps,
} from "react-native";
import { Text } from "@/components/ui/Text";
import { colors, fonts, radii } from "@/lib/theme";
type Props = TextInputProps & {
onClear?: () => void;
/** Renders as a button instead of an input (home screen → search screen). */
readOnlyPress?: () => void;
trailing?: ReactNode;
};
export function SearchField({
value,
onClear,
readOnlyPress,
trailing,
placeholder = "Search medicine, brand or symptom",
...rest
}: Props) {
const [focused, setFocused] = useState(false);
const body = (
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: 10,
backgroundColor: colors.surface,
borderRadius: radii.pill,
borderWidth: 1.5,
borderColor: focused ? colors.brand : colors.line,
paddingLeft: 16,
paddingRight: trailing ? 6 : 16,
height: 52,
}}
>
<Ionicons name="search" size={18} color={focused ? colors.brandText : colors.subtle} />
{readOnlyPress ? (
<Text variant="body" color={colors.subtle} style={{ flex: 1 }} numberOfLines={1}>
{value || placeholder}
</Text>
) : (
<TextInput
value={value}
placeholder={placeholder}
placeholderTextColor={colors.subtle}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
returnKeyType="search"
style={{
flex: 1,
fontFamily: fonts.regular,
fontSize: 14,
color: colors.ink,
paddingVertical: 0,
}}
{...rest}
/>
)}
{value && onClear && !readOnlyPress ? (
<Pressable onPress={onClear} hitSlop={8}>
<Ionicons name="close-circle" size={18} color={colors.subtle} />
</Pressable>
) : null}
{trailing}
</View>
);
if (readOnlyPress) {
return (
<Pressable onPress={readOnlyPress} style={({ pressed }) => ({ opacity: pressed ? 0.9 : 1 })}>
{body}
</Pressable>
);
}
return body;
}
/** Lime pill action that sits inside the search field (scan entry point). */
export function SearchAction({
icon,
label,
onPress,
}: {
icon: keyof typeof Ionicons.glyphMap;
label?: string;
onPress?: () => void;
}) {
return (
<Pressable
onPress={onPress}
style={({ pressed }) => ({
flexDirection: "row",
alignItems: "center",
gap: 6,
backgroundColor: colors.brand,
borderRadius: radii.pill,
paddingHorizontal: label ? 14 : 10,
height: 40,
opacity: pressed ? 0.85 : 1,
})}
>
<Ionicons name={icon} size={16} color={colors.ink} />
{label ? (
<Text variant="label" color={colors.ink}>
{label}
</Text>
) : null}
</Pressable>
);
}