106 lines
2.6 KiB
TypeScript
106 lines
2.6 KiB
TypeScript
import type { icons } from 'lucide-react-native'
|
|
import type { ReactElement, ReactNode } from 'react'
|
|
import type { ViewStyle } from 'react-native'
|
|
import { Children, cloneElement, isValidElement } from 'react'
|
|
import { Text, TouchableOpacity, View } from 'react-native'
|
|
import LucideIcon from './LucideIcon'
|
|
|
|
/* ================= Cell ================= */
|
|
export interface CellProps {
|
|
left?: ReactNode
|
|
right?: ReactNode
|
|
|
|
title?: string
|
|
leftIcon?: keyof typeof icons
|
|
rightIcon?: keyof typeof icons
|
|
rightText?: string
|
|
|
|
isLink?: boolean
|
|
className?: string
|
|
style?: ViewStyle
|
|
|
|
showDivider?: boolean // 由 CellGroup 注入
|
|
|
|
onPress?: () => void
|
|
}
|
|
|
|
export function Cell({
|
|
left,
|
|
right,
|
|
title,
|
|
leftIcon,
|
|
rightIcon = 'ChevronRight',
|
|
rightText,
|
|
isLink = false,
|
|
className,
|
|
style,
|
|
showDivider = false,
|
|
onPress,
|
|
}: CellProps) {
|
|
return (
|
|
<View>
|
|
<TouchableOpacity
|
|
activeOpacity={isLink ? 0.5 : 1}
|
|
className={`flex flex-row items-center justify-between px-4 py-3 ${className}`}
|
|
style={style}
|
|
onPress={onPress}
|
|
>
|
|
{left || (
|
|
<View className="flex flex-row items-center space-x-2">
|
|
{leftIcon && <LucideIcon icon={leftIcon} size={18} />}
|
|
{title && <Text className="text-base text-gray-900 ml-2">{title}</Text>}
|
|
</View>
|
|
)}
|
|
|
|
{right || (
|
|
<View className="flex flex-row items-center ">
|
|
{rightText && <Text className="text-gray-500 text-base mr-2">{rightText}</Text>}
|
|
{isLink && rightIcon && (
|
|
<LucideIcon icon={rightIcon} size={16} color="#9ca3af" />
|
|
)}
|
|
</View>
|
|
)}
|
|
</TouchableOpacity>
|
|
|
|
{showDivider && (
|
|
<View
|
|
className="bg-gray-100"
|
|
style={{ marginLeft: 16, marginRight: 16, height: 1 }}
|
|
/>
|
|
)}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
/* ================= CellGroup ================= */
|
|
export interface CellGroupProps {
|
|
className?: string
|
|
style?: ViewStyle
|
|
children?: ReactNode
|
|
showDivider?: boolean // 整组是否显示下划线
|
|
}
|
|
|
|
export function CellGroup({
|
|
className,
|
|
style,
|
|
children,
|
|
showDivider = true,
|
|
}: CellGroupProps) {
|
|
const elements = Children.toArray(children)
|
|
|
|
return (
|
|
<View className={`bg-white ${className}`} style={style}>
|
|
{elements.map((child, index) => {
|
|
if (!isValidElement<CellProps>(child))
|
|
return child
|
|
|
|
const isLast = index === elements.length - 1
|
|
|
|
return cloneElement<CellProps>(child as ReactElement<CellProps>, {
|
|
showDivider: showDivider && !isLast,
|
|
})
|
|
})}
|
|
</View>
|
|
)
|
|
}
|