import React, { useState } from 'react';
import {
View,
ScrollView,
Pressable,
ActivityIndicator,
ViewStyle,
PressableProps,
} from 'react-native';
import { Text } from '../Text';
import { Icon } from '../Icon';
export type SelectOption = {
id: string;
label: string;
subtitle?: string;
icon?: string;
description?: string;
};
export type SelectProps = {
/** Options to display */
options: SelectOption[];
/** Currently selected option ID */
selectedId: string | null;
/** Callback when option is selected */
onSelect: (option: SelectOption) => void;
/** Show loading state */
loading?: boolean;
/** Error message */
error?: string | null;
/** Retry callback for error state */
onRetry?: () => void;
/** Disable selection */
disabled?: boolean;
/** Minimum width for each option */
minWidth?: number;
/** Title above options */
title?: string;
/** Background color for unselected options */
backgroundColor?: string;
/** Border color for unselected options */
borderColor?: string;
/** Background color for selected option */
selectedBackgroundColor?: string;
/** Border color for selected option */
selectedBorderColor?: string;
/** Text color for unselected options */
textColor?: string;
/** Text color for selected option */
selectedTextColor?: string;
/** Additional styles */
style?: ViewStyle;
};
export function Select({
options,
selectedId,
onSelect,
loading = false,
error = null,
onRetry,
disabled = false,
minWidth = 160,
title,
backgroundColor = '#FFFFFF',
borderColor = '#E5E7EB',
selectedBackgroundColor = '#3B82F6',
selectedBorderColor = '#3B82F6',
textColor = '#111827',
selectedTextColor = '#FFFFFF',
style,
}: SelectProps) {
const [showInfo, setShowInfo] = useState(false);
// Loading state
if (loading) {
return (
Loading...
);
}
// Error state
if (error || options.length === 0) {
return (
{error || 'No options available'}
{onRetry && (
Retry
)}
);
}
// Find selected option for description
const selectedOption = options.find((opt) => opt.id === selectedId);
// Check if any option has subtitle or description
const hasDetails = options.some((opt) => opt.subtitle || opt.description);
// Success state - show options
return (
{/* Header with Title and Info Icon */}
{(title || hasDetails) && (
{title && (
{title}
)}
{hasDetails && (
setShowInfo(!showInfo)}
style={{
flexDirection: 'row',
alignItems: 'center',
padding: 4,
}}
>
{showInfo ? 'Hide Info' : 'Info'}
)}
)}
{options.map((option) => {
const isSelected = selectedId === option.id;
return (
!disabled && onSelect(option)}
disabled={disabled}
style={({ pressed }) => ({
backgroundColor: isSelected ? selectedBackgroundColor : backgroundColor,
borderWidth: 2,
borderColor: isSelected ? selectedBorderColor : borderColor,
borderRadius: 12,
padding: 16,
marginHorizontal: 4,
minWidth: minWidth,
opacity: disabled ? 0.5 : pressed ? 0.7 : 1,
alignItems: 'center',
})}
>
{option.icon && {option.icon}}
{option.label}
{showInfo && option.subtitle && (
{option.subtitle}
)}
);
})}
{showInfo && selectedOption?.description && (
{selectedOption.description}
)}
);
}